OSDN Git Service

installer: modified a lot..
[karesansui/karesansui.git] / installer / installer / utils.py
index 82beccd..1a6dc75 100644 (file)
@@ -1,9 +1,9 @@
-#/usr/bin/env python
+#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #
 # This file is part of Karesansui.
 #
-# Copyright (C) 2009 HDE, Inc.
+# Copyright (C) 2009-2010 HDE, Inc.
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -22,6 +22,11 @@ import pwd
 import grp
 import fcntl
 import random
+import glob
+
+if __name__ == '__main__':
+    search_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+    if (search_path in sys.path) is False: sys.path.insert(0, search_path)
 
 from installer.const import *
 
@@ -29,6 +34,179 @@ global logfile
 env = os._Environ(os.environ)
 logfile = env.get("LOGFILE")
 
+def preprint_r(var,indent=2,depth=None,return_var=False):
+    import pprint
+
+    pp = pprint.PrettyPrinter(indent=indent,depth=depth)
+    if return_var is True:
+        return pp.pformat(var)
+    else:
+        pp.pprint(var)
+        return True
+
+def dotsplit(val):
+    """<comment-ja>
+    ドット(.)区切りで文字列分割する。ドット(.)は)
+    </comment-ja>
+    <comment-en>
+    TODO: English Comment
+    </comment-en>
+    """
+    rf = val.rfind('.')
+    if rf == -1:
+        return val, ''
+    else:
+        return val[:rf], val[rf+1:]
+
+def toplist(val):
+    """<comment-ja>
+    リスト型に変換する。
+    </comment-ja>
+    <comment-en>
+    TODO: English Comment
+    </comment-en>
+    """
+    if type(val) is list:
+        return val
+    else:
+        return [val,]
+        
+def comma_split(s):
+    """<comment-ja>
+    カンマ(,)単位で文字列分割しリスト型に変換する。
+    </comment-ja>
+    <comment-en>
+    TODO: English Comment
+    </comment-en>
+    """
+    ret = []
+    for y in [x.strip() for x in s.split(',') if x]:
+        ret.append(y)
+    return ret
+
+def uniq_sort(array):
+    """<comment-ja>
+    配列の要素をソートし重複した要素を取り除く
+    @param array: 配列
+    @return: 配列
+    @rtype: list
+    </comment-ja>
+    <comment-en>
+    run a unique sort and return an array of sorted
+
+    @param array: list
+    @return: list
+    </comment-en>
+    """
+    array = sorted(array)
+    array = [_x for _x, _y in zip(array, array[1:] + [None]) if _x != _y]
+    return array
+
+def dict_ksort(dt):
+    """<comment-ja>
+    辞書配列をキーを元にソートし重複する
+
+    @param dt: 辞書
+    @type dt: dict
+    @return: ソート後の辞書配列
+    @rtype: dict
+    </comment-ja>
+    <comment-en>
+    run a key sort in dict
+    </comment-en>
+    """
+    new_dict = {}
+    for k,v in sorted(dt.iteritems(), lambda x,y : cmp(x[0], y[0])):
+        new_dict[k] = v
+    return new_dict
+
+def dec2hex(num):
+    """<comment-ja>
+    整数値を16進数の文字列に変換する
+    @param num: 整数値
+    @return: 16進数の文字列
+    @rtype: str
+    </comment-ja>
+    <comment-en>
+    TODO: English Comment
+    </comment-en>
+    """
+    return "%X" % num
+
+def dec2oct(num):
+    """<comment-ja>
+    整数値を8進数の文字列に変換する
+    @param num:整数値
+    @return: 8進数の文字列
+    @rtype: str
+    </comment-ja>
+    <comment-en>
+    TODO: English Comment
+    </comment-en>
+    """
+    return "%o" % num
+
+def hex2dec(s):
+    """<comment-ja>
+    16進数の文字列を整数値に変換する
+    @param string:16進数の文字列
+    @return int16
+    @rtype: int
+    </comment-ja>
+    <comment-en>
+    TODO: English Comment
+    </comment-en>
+    """
+    return int(s, 16)
+
+def oct2dec(string):
+    """<comment-ja>
+    8進数の文字列を整数値に変換する
+    @param string:8進数の文字列
+    @rtype: integer
+    </comment-ja>
+    <comment-en>
+    TODO: English Comment
+    </comment-en>
+    """
+    return int(string, 8)
+
+def next_number(min,max,exclude_numbers):
+    """
+    <comment-ja>
+    指定範囲内における除外対象整数以外の次の整数を取得する
+    
+    @param min: 範囲中の最小の整数
+    @param max: 範囲中の最大の整数
+    @param exclude_numbers: 除外対象整数を要素にもつ配列
+    @return: 整数
+    @rtype: int
+    </comment-ja>
+    <comment-en>
+    @param min: Minimum interger in specified range
+    @param max: Maximum interger in specified range
+    @param exclude_numbers: array that has the element of exclusive interger
+    @return: Interger
+    </comment-en>
+    """
+    for _x in range(min,max):
+      if not _x in exclude_numbers:
+        return _x
+
+def is_uuid(uuid=None):
+    """<comment-ja>
+    KaresansuiのUUIDフォーマットに対応しているか。
+    </comment-ja>
+    <comment-en>
+    TODO: English Comment
+    </comment-en>
+    """
+    uuid_regex = re.compile(r"""^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$""")
+    if uuid != None and uuid_regex.match(uuid):
+        return True
+
+    return False
+
 def generate_uuid():
     """
     <comment-ja>
@@ -84,19 +262,35 @@ def detect_encoding(string,encoding_list=None):
 
     return None
 
-def execute_command(command_args):
+def execute_command(command_args,user=None,env=None):
     global logfile
     ret = -1
     res = []
+    curdir = os.getcwd()
+
+    if user is None:
+        homedir = pwd.getpwuid(os.getuid())[5]
+    else:
+        try:
+            int(user)
+            homedir = pwd.getpwuid(int(user))[5]
+        except:
+            try:
+                homedir = pwd.getpwnam(user)[5]
+            except:
+                homedir = pwd.getpwuid(os.getuid())[5]
 
     subproc_args = { 'stdin': subprocess.PIPE,
                      'stdout': subprocess.PIPE,
                      'stderr': subprocess.STDOUT,
 #                     'shell': True,
-                     'cwd': os.getcwd(),
+                     'cwd': homedir,
                      'close_fds': True,
                    }
 
+    if env is not None:
+        subproc_args['env'] = env
+
     if logfile is None:
         logfile = "/dev/null"
     logf = open(logfile, "a")
@@ -112,7 +306,7 @@ def execute_command(command_args):
     (stdouterr, stdin) = (pp.stdout, pp.stdin)
     while True:
         line = stdouterr.readline()
-        logf.write(line)
+        ##logf.write(line)
         if not line:
             break
         line = line.rstrip()
@@ -122,6 +316,45 @@ def execute_command(command_args):
     logf.close()
     return [ret,res]
 
+def copy_file(src_file,dest_file):
+    """
+    <comment-ja>
+    ファイルをコピーする
+
+    @param src_file: コピー元ファイル名
+    @param dest_file: コピー先ファイル名
+    @return: コピー先ファイル名
+    </comment-ja>
+    <comment-en>
+    Copy file
+
+    @param src_file: Path to the source file
+    @param dest_file: The destination path
+    @return: The destination path
+    </comment-en>
+    """
+    #import shutil
+    #ret = shutil.copy2(src_file, dest_file)
+    ret = False
+    if os.path.exists(src_file):
+        try:
+            if dest_file[0] != "/":
+                dest_path = "%s/%s" % (os.getcwd(),os.path.dirname(dest_file),)
+            else:
+                dest_path = os.path.dirname(dest_file)
+            if not os.path.exists(dest_path):
+                os.makedirs(dest_path)
+
+            (ret, res) = execute_command(["cp",src_file,dest_file])
+            if ret == 0:
+                ret = True
+        except:
+            return False
+    else:
+        return False
+
+    return ret
+
 def is_int(val):
     try:
         ret = int(val)
@@ -301,7 +534,7 @@ def r_chmod(path,perm):
 
     return True
 
-def sh_config_read(filename):
+def sh_config_read(filename,separator='='):
     ret = {}
     try:
         fp = open(filename,"r")
@@ -310,8 +543,18 @@ def sh_config_read(filename):
             line = line.strip()
             if len(line) <= 0 or line[0] == "#":
                 continue
-            key, value = line.split('=',1)
-            ret[key] = value
+            try:
+                key, value = line.split(separator,1)
+                try:
+                    ret[key]
+                    if type(ret[key]) is not list:
+                        old = ret[key]
+                        ret[key] = [old]
+                    ret[key].append(value)
+                except:
+                    ret[key] = value
+            except:
+                pass
         fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
         fp.close()
     except:
@@ -319,7 +562,7 @@ def sh_config_read(filename):
 
     return ret
 
-def sh_config_write(filename,opts):
+def sh_config_write(filename,opts,separator='='):
     ret = True
 
     res = {}
@@ -334,10 +577,16 @@ def sh_config_write(filename,opts):
         fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
         for k,v in res.iteritems():
             if type(v) == str and k[0:2] != "__" and k[0:4] != "pass":
-                fp.write("%s=%s\n" % (k, v,))
+                fp.write("%s%s%s\n" % (k, separator, v,))
+            if type(v) == list:
+                for v2 in v:
+                    fp.write("%s%s%s\n" % (k, separator, v2,))
         fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
         fp.close()
-    except:
+    except TypeError, e:
+        pass
+    except IOError, e:
+        raise "%s" % e
         ret = False
 
     return ret
@@ -355,14 +604,14 @@ def run_chkconfig(name,flag=None):
     return ret
 
 def run_service(name,flag=None):
-    ret = False
-
     if flag is None:
         (ret,res) = execute_command([COMMAND_SERVICE,name,"status"])
     else:
         (ret,res) = execute_command([COMMAND_SERVICE,name,flag])
     if ret == 0:
         ret = True
+    else:
+        ret = False
 
     return ret
 
@@ -442,6 +691,25 @@ def is_installed(name,rpmlib=None):
     rpmlib.__del__
     return ret
 
+def is_updatable(fullpath, rpmlib=None):
+    if rpmlib is None:
+        from installer.rpmlib import RpmLib
+        rpmlib = RpmLib()
+
+    if os.path.isfile(fullpath) is False:
+        return False
+    try:
+        try:
+            ret = rpmlib.compareVersion(fullpath)
+            if ret < 0:
+                return True
+            else:
+                return False
+        except:
+            return False
+    finally:
+        rpmlib.__del__
+
 def get_distrubution(rpmlib=None):
     ret = ('unknown',None)
 
@@ -472,3 +740,861 @@ def get_distrubution(rpmlib=None):
             pass
     rpmlib.__del__
     return ret
+
+def findFile(dir, pattern):
+    fullPattern = os.path.join(dir,pattern)
+    return glob.glob(fullPattern)
+
+def findFileRecursive(topdir=None, pattern="*.*", nest=False, verbose=False):
+    allFilenames = list()
+    # current dir
+    if verbose:
+        print "*** %s" %topdir
+    if topdir is None: topdir = os.getcwd()
+    filenames = findFile(topdir, pattern)
+    if verbose:
+        for filename in [os.path.basename(d) for d in filenames]:
+            print "   %s" %filename
+    allFilenames.extend(filenames)
+    # possible sub dirs
+    names = [os.path.join(topdir, dir) for dir in os.listdir(topdir)]
+    dirs = [n for n in names if os.path.isdir(n)]
+    if verbose:
+        print "--> %s" % [os.path.basename(d) for d in dirs]
+    if len(dirs) > 0:
+        for dir in dirs:
+            filenames = findFileRecursive(dir, pattern, nest, verbose)
+            if nest:
+                allFilenames.append(filenames)
+            else:
+                allFilenames.extend(filenames)
+    # final result
+    return allFilenames
+
+def available_kernel_modules():
+    ret = []
+    modules_dir = "/lib/modules/%s" % os.uname()[2]
+    if os.path.isdir(modules_dir) is True:
+        for k in findFileRecursive(modules_dir,"*.ko"):
+            ret.append(os.path.basename(k)[0:-3])
+        for k in findFileRecursive(modules_dir,"*.o"):
+            ret.append(os.path.basename(k)[0:-2])
+    ret = sorted(ret)
+    ret = [p for p, q in zip(ret, ret[1:] + [None]) if p != q]
+    return ret
+
+def loaded_kernel_modules():
+    proc_modules = "/proc/modules"
+    if os.path.isfile(proc_modules) is False:
+        return None
+
+    ret = []
+    fp = open(proc_modules, "r")
+    try:
+        for line in fp.readlines():
+            if len(line.strip()) > 0:
+                val = line.split(" ")
+                ret.append(val[0])
+        fp.close()
+    except:
+        return None
+
+    return ret
+
+def is_loaded_kernel_module(module=None):
+    return module in loaded_kernel_modules()
+
+def loaded_kernel_module_dependencies(module=None):
+    if not module in loaded_kernel_modules():
+        return None
+
+    proc_modules = "/proc/modules"
+    if os.path.isfile(proc_modules) is False:
+        return None
+
+    ret = []
+    fp = open(proc_modules, "r")
+    try:
+        for line in fp.readlines():
+            if len(line.strip()) > 0:
+                val = line.split(" ")
+                if val[0] == module and val[3] != "-":
+                    ret = val[3].split(",")
+                    ret.pop()
+        fp.close()
+    except:
+        return None
+
+    return ret
+
+def load_kernel_module(module=None):
+    if is_loaded_kernel_module(module):
+        return False
+    if module in available_kernel_modules():
+        command_args = ["/sbin/modprobe",module]
+        ret = execute_command(command_args)
+        if is_loaded_kernel_module(module) is False:
+            return False
+    else:
+        return False
+    return True
+
+def unload_kernel_module(module=None,force=False):
+    if is_loaded_kernel_module(module) is False:
+        return False
+    else:
+        if force is True:
+            for k in loaded_kernel_module_dependencies(module):
+                unload_kernel_module(k,force)
+        command_args = ["/sbin/rmmod",module]
+        ret = execute_command(command_args)
+        if is_loaded_kernel_module(module):
+            return False
+    return True
+
+def available_virt_mechs():
+    """<comment-ja>
+    </comment-ja>
+    <comment-en>
+    get list of usable virtualization mechanisms
+    </comment-en>
+    """
+    ret = []
+    if os.access("/proc/xen", os.R_OK):
+        ret.append("XEN")
+    if is_loaded_kernel_module("kvm"):
+        ret.append("KVM")
+
+    return sorted(ret)
+
+def array_replace(array, pattern=None, replace=None, mode="og"):
+
+    if type(array) != list:
+        return array
+
+    regex_mode = 0
+    once_match_only = False
+    search_cnt = 1
+
+    cnt = 0
+    while cnt < len(mode):
+        if mode[cnt] == 'o':
+            once_match_only = True
+        if mode[cnt] == 'g':
+            search_cnt = 0
+        if mode[cnt] == 'i':
+            regex_mode = re.IGNORECASE
+
+        cnt += 1
+
+    if type(pattern) is str and type(replace) is str:
+        pattern = [pattern]
+        replace = [replace]
+
+    if type(pattern) is list and type(replace) is list and len(pattern) == len(replace):
+        new_array = []
+        for k in array:
+            cnt = 0
+            #print k,
+            #print " => ",
+            while cnt < len(pattern):
+                p = re.compile("%s" % pattern[cnt],regex_mode)
+                if p.search(k):
+                    k = p.sub(replace[cnt], k, search_cnt) 
+                    if once_match_only is True:
+                        break
+                cnt += 1
+            #print k
+            new_array.append(k)
+
+        return new_array
+    else:
+        return array
+
+def file_contents_replace(filename, new_filename, pattern=None, replace=None, mode="og"):
+
+    lines = []
+    try:
+        fp = open(filename,"r")
+        fcntl.lockf(fp.fileno(), fcntl.LOCK_SH)
+        for line in fp.readlines():
+            lines.append(line)
+        fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+        fp.close()
+    except:
+        return False
+
+    if len(lines) > 0:
+        lines = array_replace(lines,pattern,replace,mode)
+        try:
+            fp = open(new_filename,"w")
+            fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+            for line in lines:
+                fp.write(line)
+            fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+            fp.close()
+        except:
+            return False
+
+    return True
+
+def append_random_entropy(count=3000):
+    if os.uname()[4] != "x86_64":
+        try:
+            from installer.extensions.random_entropy import appendEntropy
+        except:
+            from extensions.random_entropy import appendEntropy
+    else:
+        try:
+            from installer.extensions.x86_64.random_entropy import appendEntropy
+        except:
+            from extensions.x86_64.random_entropy import appendEntropy
+
+    return appendEntropy(count)
+
+import threading
+class Append_Random_Entropy_Child_t(threading.Thread):
+    def __init__(self):
+        threading.Thread.__init__(self)
+    def run(self):
+        import time
+        time.sleep(3)
+        append_random_entropy(3000)
+
+def execute_certtool(opts,outfile="/dev/stdout"):
+    retval = True
+
+    outdir = os.path.dirname(outfile)
+    if os.path.exists(outdir) is False:
+        os.makedirs(outdir)
+
+    child_t = Append_Random_Entropy_Child_t()
+    child_t.start()
+
+    command_args = opts
+    command_args.insert(0,COMMAND_CERTTOOL)
+    (ret,res) = execute_command(command_args)
+
+    child_t.join()
+
+    if ret == 0:
+        try:
+            fp = open(outfile,"w")
+            fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+            for line in res:
+                fp.write(line+"\n")
+            fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+            fp.close()
+        except:
+            retval = False
+    else:
+        retval = False
+
+    return retval
+
+def generate_privkey(outfile="/dev/stdout"):
+    opts = [ "--generate-privkey" ]
+    execute_certtool(opts,outfile)
+    return os.path.exists(outfile)
+
+def generate_ca_info(outfile,opts):
+    retval = True
+
+    outdir = os.path.dirname(outfile)
+    if os.path.exists(outdir) is False:
+        os.makedirs(outdir)
+
+    try:
+        fp = open(outfile,"w")
+        fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+        fp.write("""
+cn = %s
+ca
+cert_signing_key
+""" % (opts["cn"],));
+        fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+        fp.close()
+    except:
+        retval = False
+
+    return retval
+
+def generate_ca_cert(outfile,privkey,info):
+    opts = [ "--generate-self-signed",
+             "--load-privkey",
+             privkey,
+             "--template",
+             info,
+           ]
+    execute_certtool(opts,outfile)
+    return os.path.exists(outfile)
+
+def generate_server_info(outfile,opts):
+    retval = True
+
+    outdir = os.path.dirname(outfile)
+    if os.path.exists(outdir) is False:
+        os.makedirs(outdir)
+
+    try:
+        fp = open(outfile,"w")
+        fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+        fp.write("""
+organization = %s
+cn = %s
+tls_www_server
+encryption_key
+signing_key
+""" % (opts["organization"], opts["cn"],));
+        fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+        fp.close()
+    except:
+        retval = False
+
+    return retval
+
+def generate_cert(outfile,privkey,info,ca_cert,ca_privkey):
+    opts = [ "--generate-certificate",
+             "--load-privkey",
+             privkey,
+             "--load-ca-certificate",
+             ca_cert,
+             "--load-ca-privkey",
+             ca_privkey,
+             "--template",
+             info,
+           ]
+    execute_certtool(opts,outfile)
+    return os.path.exists(outfile)
+
+def generate_client_info(outfile,opts):
+    retval = True
+
+    outdir = os.path.dirname(outfile)
+    if os.path.exists(outdir) is False:
+        os.makedirs(outdir)
+
+    try:
+        fp = open(outfile,"w")
+        fcntl.lockf(fp.fileno(), fcntl.LOCK_EX)
+        fp.write("""
+country = %s
+state = %s
+locality = %s
+organization = %s
+cn = %s
+tls_www_client
+encryption_key
+signing_key
+""" % (opts["country"],opts["state"],opts["locality"],opts["organization"],opts["cn"],));
+        fcntl.lockf(fp.fileno(), fcntl.LOCK_UN)
+        fp.close()
+    except:
+        retval = False
+
+    return retval
+
+def generate_ssl_certificates(opts):
+
+    # Setting up a Certificate Authority (CA)
+    generate_privkey(PKI_CA_PRIVATE_KEY)
+    generate_ca_info(PKI_CA_INFO,opts)
+    if os.path.exists(PKI_CA_PRIVATE_KEY) and os.path.exists(PKI_CA_INFO):
+        generate_ca_cert(PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY,PKI_CA_INFO)
+
+    # Issuing server certificates
+    generate_privkey(PKI_SERVER_PRIVATE_KEY)
+    generate_server_info(PKI_SERVER_INFO,opts)
+    if os.path.exists(PKI_CA_SELFSIGNED_CRT) and os.path.exists(PKI_SERVER_PRIVATE_KEY) and os.path.exists(PKI_SERVER_INFO):
+        generate_cert(PKI_SERVER_CRT,PKI_SERVER_PRIVATE_KEY,PKI_SERVER_INFO,PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY)
+
+    # Issuing client certificates
+    generate_privkey(PKI_CLIENT_PRIVATE_KEY)
+    generate_client_info(PKI_CLIENT_INFO,opts)
+    if os.path.exists(PKI_CA_SELFSIGNED_CRT) and os.path.exists(PKI_CLIENT_PRIVATE_KEY) and os.path.exists(PKI_CLIENT_INFO):
+        generate_cert(PKI_CLIENT_CRT,PKI_CLIENT_PRIVATE_KEY,PKI_CLIENT_INFO,PKI_CA_SELFSIGNED_CRT,PKI_CA_PRIVATE_KEY)
+
+def get_proc_meminfo(path="/proc/meminfo"):
+    if os.path.isfile(path) is False:
+        return None
+
+    fp = open(path, "r")
+    try:
+        ret = {}
+        for line in fp.readlines():
+            val = line.split(":")
+            key = re.sub(r'[\t\n]', '', val[0].strip())
+            value = re.sub(r'[\t\n]', '', val[1]).strip()
+            invalue = value.split(" ")
+            if len(invalue) > 1:
+                ret[key] = (invalue[0], invalue[1])
+            else:
+                ret[key] = (invalue[0])
+
+        return ret
+    except:
+        return None
+
+def get_proc_cpuinfo(path="/proc/cpuinfo"):
+    if os.path.isfile(path) is False:
+        return None
+
+    fp = open(path, "r")
+    try:
+        ret = {}
+        i = 0
+        ret[i] = {}
+        for line in fp.readlines():
+            if len(line.strip()) <= 0:
+                i += 1
+                ret[i] = {}
+            else:
+                val = line.split(":")
+                key = re.sub(r'[\t\n]', '', val[0].strip())
+                value = re.sub(r'[\t\n]', '', val[1]).strip()
+                ret[i][key] = value
+
+        if len(ret[len(ret)-1]) <= 0:
+            ret.pop(len(ret)-1)
+
+        return ret
+        
+    except:
+        return None
+
+def get_ifconfig_info(name=None):
+    """
+    <comment-ja>
+    ネットワークデバイス情報を取得する
+
+    @param name: 取得したいデバイス名(省略時は全デバイス情報が指定されたとみなす) 「regex:^eth」のようにプレフィックスにregex:を付けると正規表現にマッチしたデバイス名の情報を全て取得できる。
+    @return:    デバイス情報が格納されたdict配列
+                配列の内容例
+                {'eth0': {   'bcast': '172.16.0.255',
+                             'device': 'eth0',
+                             'hwaddr': '00:1D:09:D7:30:4B',
+                             'ipaddr': '172.16.0.10',
+                             'ipv6addr': 'fe80::21d:9ff:fed7:304b/64',
+                             'link': 'Ethernet',
+                             'mask': '255.255.255.0',
+                             'metric': '1',
+                             'mtu': '1500',
+                             'running': True,
+                             'scope': 'Link',
+                             'up': True,
+                             'use_bcast': 'BROADCAST',
+                             'use_mcast': 'MULTICAST'}}
+
+    </comment-ja>
+    <comment-en>
+    Get computer's network interface information
+
+    @param name: network device name
+    @return: a dict with: ipaddr, hwaddr, bcast, mask etc...
+    @rtype: dict
+    </comment-en>
+    """
+    from installer.networkaddress import NetworkAddress
+
+    info = {}
+
+    command_args = [COMMAND_IFCONFIG,'-a']
+
+    old_lang = os.environ['LANG']
+    os.environ['LANG'] = 'C'
+    (ret,res) = execute_command(command_args)
+    os.environ['LANG'] = old_lang
+
+    if ret != 0:
+        return info
+
+    device_regex = re.compile(r"""^(?P<device>[\S\:]+)\s+Link encap:(?P<link>(\S+ ?\S+))(\s+HWaddr (?P<hwaddr>[0-9a-fA-F:]+))?""")
+    ipv4_regex = re.compile(r"""^\s+inet addr:\s*(?P<ipaddr>[0-9\.]+)(\s+Bcast:(?P<bcast>[0-9\.]+))?\s+Mask:(?P<mask>[0-9\.]+)""")
+    ipv6_regex = re.compile(r"""^\s+inet6 addr:\s*(?P<ipv6addr>[0-9a-fA-F\:\/]+)\s+Scope:(?P<scope>\S+)""")
+    status_regex = re.compile(r"""^\s+((?P<up>UP)\s+)?((?P<use_bcast>(BROADCAST|LOOPBACK))\s+)?((?P<running>RUNNING)\s+)?((?P<use_mcast>(MULTICAST|NOARP))\s+)?MTU:(?P<mtu>[0-9]+)\s+Metric:(?P<metric>[0-9]+)""")
+
+    _info = {}
+    for aline in res:
+        if aline.strip() == "":
+
+            cidr = None
+            netlen = None
+
+            if ipaddr is not None and mask is not None:
+                netaddr = NetworkAddress("%s/%s" % (ipaddr,mask,))
+                cidr = netaddr.get('cidr')
+                netlen = netaddr.get('netlen')
+
+            _info[device] = {
+                           "device":device,
+                           "link":link,
+                           "hwaddr":hwaddr,
+                           "ipaddr":ipaddr,
+                           "bcast":bcast,
+                           "mask":mask,
+                           "ipv6addr":ipv6addr,
+                           "scope":scope,
+                           "up":up,
+                           "running":running,
+                           "use_bcast":use_bcast,
+                           "use_mcast":use_mcast,
+                           "mtu":mtu,
+                           "metric":metric,
+                           "cidr":cidr,
+                           "netlen":netlen,
+                           }
+        m = device_regex.match(aline)
+        if m:
+            device = m.group('device')
+            link = m.group('link')
+            hwaddr = m.group('hwaddr')
+            ipaddr = None
+            bcast = None
+            mask = None
+            ipv6addr = None
+            scope = None
+            up = False
+            running = False
+            use_bcast = None
+            use_mcast = None
+            mtu = None
+            metric = None
+
+        m = ipv4_regex.match(aline)
+        if m:
+            ipaddr = m.group('ipaddr')
+            bcast = m.group('bcast')
+            mask = m.group('mask')
+
+        m = ipv6_regex.match(aline)
+        if m:
+            ipv6addr = m.group('ipv6addr')
+            scope = m.group('scope')
+
+        m = status_regex.match(aline)
+        if m:
+            if m.group('up') == 'UP':
+                up = True
+            use_bcast = m.group('use_bcast')
+            if m.group('running') == 'RUNNING':
+                running = True
+            use_mcast = m.group('use_mcast')
+            mtu = m.group('mtu')
+            metric = m.group('metric')
+
+    all_info = dict_ksort(_info)
+    #import pprint
+    #pp = pprint.PrettyPrinter(indent=4)
+    #pp.pprint(all_info)
+
+    if name == None:
+        return all_info
+
+    regex_regex = re.compile(r"""^regex:(?P<regex>.*)""")
+    m = regex_regex.match(name)
+
+    for dev,value in all_info.iteritems():
+        if m == None:
+            if dev == name:
+                info[dev] = value
+                return info
+        else:
+            regex = m.group('regex')
+            query_regex = re.compile(r""+regex+"")
+            n = query_regex.search(dev)
+            if n != None:
+                info[dev] = value
+    return info
+
+def read_ifcfg_config(device):
+    retval = {}
+
+    sysconf_dir         = "/etc/sysconfig"
+    network_sysconf_dir = sysconf_dir + "/network-scripts"
+    config_prefix       = "ifcfg-"
+
+    ifcfg_config = "%s/%s%s" % (network_sysconf_dir,config_prefix,device,)
+    if os.path.exists(ifcfg_config):
+        retval = sh_config_read(ifcfg_config)
+    return retval
+
+def write_ifcfg_config(device,params):
+    retval = True
+
+    sysconf_dir         = "/etc/sysconfig"
+    network_sysconf_dir = sysconf_dir + "/network-scripts"
+    config_prefix       = "ifcfg-"
+    bak_dir             = network_sysconf_dir + "/ksssave"
+
+    ifcfg_config = "%s/%s%s" % (network_sysconf_dir,config_prefix,device,)
+    try:
+        # save original file.
+        if os.path.exists(ifcfg_config):
+            if not os.path.exists(bak_dir):
+                os.makedirs(bak_dir)
+            copy_file(ifcfg_config, 
+                      "%s/%s%s.%s" % (bak_dir,config_prefix,device,time.strftime("%Y%m%d%H%M%S",time.localtime())))
+
+        retval = sh_config_write(ifcfg_config,params)
+    except:
+        retval = False
+    return retval
+
+def get_primary_netdev_name():
+    ret = False
+    for k,v in get_ifconfig_info().iteritems():
+        try:
+            if v["hwaddr"] is not None and v["hwaddr"] != "00:00:00:00:00:00":
+                ret = k
+        except:
+            pass
+    return ret
+
+def switch_xen_like_bridging(phydev="peth0"):
+    retval = False
+
+    old_phydev_params = read_ifcfg_config(phydev)
+    try:
+        old_phydev_params["DEVICE"]
+        return retval
+    except:
+        pass
+
+    primary = get_primary_netdev_name()
+    if primary is not False and primary != phydev:
+        phydev_params = {}
+        br_params = {}
+
+        params = read_ifcfg_config(primary)
+        infos = get_ifconfig_info(primary)[primary]
+        try:
+            params["DEVICE"]
+            phydev_params["DEVICE"] = phydev
+            phydev_params["ONBOOT"] = "yes"
+            phydev_params["BRIDGE"] = primary
+            try:
+                phydev_params["HWADDR"] = params["HWADDR"]
+            except:
+                phydev_params["HWADDR"] = infos["hwaddr"]
+
+            br_params = params
+            br_params["DEVICE"]    = primary
+            br_params["TYPE"]      = "Bridge"
+            del br_params["HWADDR"]
+        except:
+            try:
+                phydev_params["DEVICE"] = phydev
+                phydev_params["ONBOOT"] = "yes"
+                phydev_params["BRIDGE"] = primary
+                phydev_params["HWADDR"] = infos["hwaddr"]
+
+                br_params["DEVICE"]    = primary
+                br_params["BOOTPROTO"] = "static"
+                br_params["IPADDR"]    = infos["ipaddr"]
+                br_params["NETMASK"]   = infos["mask"]
+                br_params["BROADCAST"] = infos["bcast"]
+                br_params["TYPE"]      = "Bridge"
+            except:
+                pass
+
+        if len(phydev_params) > 0 and len(br_params) > 0:
+            try:
+                write_ifcfg_config(phydev, phydev_params)
+                write_ifcfg_config(primary,br_params)
+                new_phydev_params = read_ifcfg_config(phydev)
+                new_br_params     = read_ifcfg_config(primary)
+                if len(new_phydev_params) > 0 and len(new_br_params) > 0:
+                    retval = True
+            except:
+                pass
+
+    return retval
+
+def is_iso9660_filesystem_format(file):
+
+    retval = False
+
+    magic  = "CD001"
+    extra_magic = "EL TORITO SPECIFICATION" # bootable
+    offset       = 32769
+    label_offset = 32808
+    extra_offset = 34823
+
+    if not os.path.exists(file) or os.stat(file).st_size < offset+len(magic):
+        return retval
+
+    try:
+        regex = re.compile(r"""\S""")
+        f = open(file,"rb")
+        f.seek(offset)
+        header = f.read(len(magic))
+
+        if header != magic:
+            return retval
+
+        label = ""
+        step = 0
+        for cnt in xrange(label_offset, label_offset + 100):
+            f.seek(cnt)
+            char = f.read(1)
+            #print cnt,  
+            #print "%x" % ord(char)
+            if ord(char) == 0 or char == '\0':
+                step = step + 1
+                if step == 2:
+                    break
+            #elif regex.match(char):
+            else:
+                label += char
+
+        label = label.strip()
+
+        f.seek(extra_offset)
+        data = f.read(len(extra_magic))
+        if data == extra_magic:
+            label += "(bootable)"
+
+        f.close()
+
+        retval = label
+    except:
+        pass
+
+    return retval
+
+def is_windows_bootable_iso(file):
+    retval = False
+    regexes = {
+      "Windows XP Home"                  :"WXH(CCP|FPP|OEM|VOL|OCCP)_[A-Z]{2}",
+      "Windows XP Professional"          :"WXP(CCP|FPP|OEM|VOL|OCCP)_[A-Z]{2}",
+      "Windows XP Home (SP1)"            :"XRMH(CCP|FPP|OEM|VOL|OCCP)_[A-Z]{2}",
+      "Windows XP Professional (SP1)"    :"XRMP(CCP|FPP|OEM|VOL|OCCP)_[A-Z]{2}",
+      "Windows XP Home (SP1a)"           :"X1AH(CCP|FPP|OEM|VOL|OCCP)_[A-Z]{2}",
+      "Windows XP Professional (SP1a)"   :"X1AP(CCP|FPP|OEM|VOL|OCCP)_[A-Z]{2}",
+      "Windows XP Home (SP2)"            :"VRMH(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Professional (SP2)"    :"VRMP(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Home (SP2b)"           :"VX2H(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Professional (SP2b)"   :"VX2P(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Home (SP3)"            :"GRTMH(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Home K (SP3)"          :"GRTMHK(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Home KN (SP3)"         :"GRTMHKN(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Professional (SP3)"    :"GRTMP(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Professional K (SP3)"  :"GRTMPK(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP Professional KN (SP3)" :"GRTMPKN(CCP|FPP|OEM|VOL)_[A-Z]{2}",
+      "Windows XP from Dell"             :"XP2_(PER|PRO)_ENG",
+      "Windows 7 Professional"           :"WIN_7_PROFESSIONAL",
+      "Windows 7"                        :"WIN7",
+     }
+    label = is_iso9660_filesystem_format(file)
+    if label is not False:
+        for k,v in regexes.iteritems():
+            regex_str = "%s.*\(bootable\)" % v
+            regex = re.compile(regex_str)
+            if regex.search(label):
+                retval = k
+                break
+    return retval
+
+def is_linux_bootable_iso(file):
+    retval = False
+    regexes = {
+      "Asianux"               :"Asianux",
+      "MIRACLE LINUX \\1.\\2" :"MLSE([0-9])([0-9])",
+      "Turbolinux"            :"Turbolinux",
+      "Fedora Core \\1"       :"^FC/([0-9\.]*)",
+      "CentOS \\2"            :"CentOS( \-_)([0-9].[0-9])",
+      "Red Hat Enterprise Linux \\2 \\3":"RHEL(/|\-)([0-9\.\-U]) (i386|x86_64)",
+      "Red Hat Linux/\\1"     :"Red Hat Linux/(.+)",
+      "openSUSE-\\1.\\2"      :"^SU(1[0-3])([0-9])0.00",
+      "Debian \\1"            :"^Debian (.+)",
+      "Buildix"               :"^Buildix",
+      "Ubuntu \\1"            :"^Ubuntu ([0-9].+)",
+      "Ubuntu Server \\1"     :"^Ubuntu-Server (.+)",
+     }
+    label = is_iso9660_filesystem_format(file)
+    if label is not False:
+        for k,v in regexes.iteritems():
+            regex_str = "%s.*\(bootable\)" % v
+            regex = re.compile(regex_str)
+            if regex.search(label):
+                retval = re.sub(r"""%s\(bootable\)""" % v,k,label).strip()
+                break
+    return retval
+
+def get_xml_parse(file):
+    from xml.dom import minidom
+
+    if os.path.exists(file):
+        document = minidom.parse(file)
+    else:
+        document = minidom.parseString(file)
+
+    return document
+
+def get_xml_xpath(document, expression):
+    """
+    <comment-ja>
+    XPathロケーションパスを評価する
+
+    @param document: xml.dom.minidom.Document
+    @param expression: 実行する XPath 式
+    @return: 与えられた XPath 式 にマッチするすべてのノードを含む ノード一覧
+    </comment-ja>
+    <comment-en>
+    Evaluates the XPath Location Path in the given string
+
+    @param file: Path to XML file
+    @param expression: The XPath expression to execute
+    @return: Returns node list containing all nodes matching the given XPath expression
+    </comment-en>
+    """
+    from xml import xpath
+
+    result = None
+    for i in xpath.Evaluate(expression, document.documentElement):
+        result = i.nodeValue
+
+    return result
+
+def get_nums_xml_xpath(document, expression):
+    """
+    <comment-ja>
+    XPathロケーションパスを評価する
+
+    @param file: XMLファイルパス、または、XMLデータそのもの
+    @param expression: 実行する XPath 式
+    @return: 与えられた XPath 式 にマッチするすべてのノードを含む ノード数
+    </comment-ja>
+    <comment-en>
+    Evaluates the XPath Location Path in the given string
+
+    @param file: Path to XML file
+    @param expression: The XPath expression to execute
+    @return: Returns the number of node containing all nodes matching the given XPath expression
+    </comment-en>
+    """
+    from xml import xpath
+
+    result = None
+    return xpath.Evaluate('count(%s)' % expression, document.documentElement)
+
+def write_ini_samevalue(param, src_filename, dst_filename):
+    retval = False
+
+    if not os.path.exists(src_filename) or not os.path.exists(dst_filename):
+        return retval
+
+    src_opts = sh_config_read(src_filename)
+    try:
+        src_opts[param]
+        dst_opts = sh_config_read(dst_filename)
+        dst_opts[param] = src_opts[param]
+        retval = sh_config_write(dst_filename,dst_opts)
+    except:
+        retval = False
+
+    return retval
+
+if __name__ == '__main__':
+    sys.exit()