# # iutil.py - generic install utility functions # # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 # Red Hat, Inc. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Author(s): Erik Troan # import glob import os, string, stat, sys import shutil import signal import os.path import errno import subprocess import threading import re from flags import flags from constants import * import gettext _ = lambda x: gettext.ldgettext("anaconda", x) import logging log = logging.getLogger("anaconda") program_log = logging.getLogger("program") class ExecProduct(object): def __init__(self, rc, stdout, stderr): self.rc = rc self.stdout = stdout self.stderr = stderr #Python reimplementation of the shell tee process, so we can #feed the pipe output into two places at the same time class tee(threading.Thread): def __init__(self, inputdesc, outputdesc, logmethod, command): threading.Thread.__init__(self) self.inputdesc = os.fdopen(inputdesc, "r") self.outputdesc = outputdesc self.logmethod = logmethod self.running = True self.command = command def run(self): while self.running: try: data = self.inputdesc.readline() except IOError: self.logmethod("Can't read from pipe during a call to %s. " "(program terminated suddenly?)" % self.command) break if data == "": self.running = False else: self.logmethod(data.rstrip('\n')) os.write(self.outputdesc, data) def stop(self): self.running = False return self def augmentEnv(): env = os.environ.copy() env.update({"LC_ALL": "C", "ANA_INSTALL_PATH": ROOT_PATH }) return env ## Run an external program and redirect the output to a file. # @param command The command to run. # @param argv A list of arguments. # @param stdin The file descriptor to read stdin from. # @param stdout The file descriptor to redirect stdout to. # @param stderr The file descriptor to redirect stderr to. # @param root The directory to chroot to before running command. # @return The return code of command. def execWithRedirect(command, argv, stdin = None, stdout = None, stderr = None, root = '/', env_prune=[]): if flags.testing: log.info("not running command because we're testing: %s %s" % (command, " ".join(argv))) return 0 def chroot (): os.chroot(root) stdinclose = stdoutclose = stderrclose = lambda : None argv = list(argv) if isinstance(stdin, str): if os.access(stdin, os.R_OK): stdin = os.open(stdin, os.O_RDONLY) stdinclose = lambda : os.close(stdin) else: stdin = sys.stdin.fileno() elif isinstance(stdin, int): pass elif stdin is None or not isinstance(stdin, file): stdin = sys.stdin.fileno() orig_stdout = stdout if isinstance(stdout, str): stdout = os.open(stdout, os.O_RDWR|os.O_CREAT) stdoutclose = lambda : os.close(stdout) elif isinstance(stdout, int): pass elif stdout is None or not isinstance(stdout, file): stdout = sys.stdout.fileno() if isinstance(stderr, str) and isinstance(orig_stdout, str) and stderr == orig_stdout: stderr = stdout elif isinstance(stderr, str): stderr = os.open(stderr, os.O_RDWR|os.O_CREAT) stderrclose = lambda : os.close(stderr) elif isinstance(stderr, int): pass elif stderr is None or not isinstance(stderr, file): stderr = sys.stderr.fileno() program_log.info("Running... %s" % (" ".join([command] + argv),)) #prepare os pipes for feeding tee proceses pstdout, pstdin = os.pipe() perrout, perrin = os.pipe() env = augmentEnv() for var in env_prune: if env.has_key(var): del env[var] try: #prepare tee proceses proc_std = tee(pstdout, stdout, program_log.info, command) proc_err = tee(perrout, stderr, program_log.error, command) #start monitoring the outputs proc_std.start() proc_err.start() proc = subprocess.Popen([command] + argv, stdin=stdin, stdout=pstdin, stderr=perrin, preexec_fn=chroot, cwd=root, env=env) proc.wait() ret = proc.returncode #close the input ends of pipes so we get EOF in the tee processes os.close(pstdin) os.close(perrin) #wait for the output to be written and destroy them proc_std.join() del proc_std proc_err.join() del proc_err stdinclose() stdoutclose() stderrclose() except OSError as e: errstr = "Error running %s: %s" % (command, e.strerror) log.error(errstr) program_log.error(errstr) #close the input ends of pipes so we get EOF in the tee processes os.close(pstdin) os.close(perrin) proc_std.join() proc_err.join() stdinclose() stdoutclose() stderrclose() raise RuntimeError, errstr return ret ## Run an external program and capture standard out. # @param command The command to run. # @param argv A list of arguments. # @param stdin The file descriptor to read stdin from. # @param stderr The file descriptor to redirect stderr to. # @param root The directory to chroot to before running command. # @param fatal Boolean to determine if non-zero exit is fatal. # @return The output of command from stdout. def execWithCapture(command, argv, stdin = None, stderr = None, root='/', fatal = False): if flags.testing: log.info("not running command because we're testing: %s %s" % (command, " ".join(argv))) return "" def chroot(): if root is not None: os.chroot(root) def closefds (): stdinclose() stderrclose() stdinclose = stderrclose = lambda : None rc = "" argv = list(argv) if isinstance(stdin, str): if os.access(stdin, os.R_OK): stdin = os.open(stdin, os.O_RDONLY) stdinclose = lambda : os.close(stdin) else: stdin = sys.stdin.fileno() elif isinstance(stdin, int): pass elif stdin is None or not isinstance(stdin, file): stdin = sys.stdin.fileno() if isinstance(stderr, str): stderr = os.open(stderr, os.O_RDWR|os.O_CREAT) stderrclose = lambda : os.close(stderr) elif isinstance(stderr, int): pass elif stderr is None or not isinstance(stderr, file): stderr = sys.stderr.fileno() program_log.info("Running... %s" % (" ".join([command] + argv),)) try: proc = subprocess.Popen([command] + argv, stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=chroot, cwd=root, env=augmentEnv()) while True: (outStr, errStr) = proc.communicate() if outStr: map(program_log.info, outStr.splitlines()) rc += outStr if errStr: map(program_log.error, errStr.splitlines()) os.write(stderr, errStr) if proc.returncode is not None: break # if we have anything other than a clean exit, and we get the fatal # option, raise the OSError. if proc.returncode and fatal: raise RuntimeError('Error running ' + command + ': Non-zero return code: %s' % proc.returncode) except OSError as e: log.error ("Error running " + command + ": " + e.strerror) raise RuntimeError, "Error running " + command + ": " + e.strerror finally: closefds() return rc def execWithCallback(command, argv, stdin = None, stdout = None, stderr = None, echo = True, callback = None, callback_data = None, root = '/'): if flags.testing: log.info("not running command because we're testing: %s %s" % (command, " ".join(argv))) return ExecProduct(0, '', '') def chroot(): os.chroot(root) def closefds (): stdinclose() stdoutclose() stderrclose() stdinclose = stdoutclose = stderrclose = lambda : None argv = list(argv) if isinstance(stdin, str): if os.access(stdin, os.R_OK): stdin = os.open(stdin, os.O_RDONLY) stdinclose = lambda : os.close(stdin) else: stdin = sys.stdin.fileno() elif isinstance(stdin, int): pass elif stdin is None or not isinstance(stdin, file): stdin = sys.stdin.fileno() if isinstance(stdout, str): stdout = os.open(stdout, os.O_RDWR|os.O_CREAT) stdoutclose = lambda : os.close(stdout) elif isinstance(stdout, int): pass elif stdout is None or not isinstance(stdout, file): stdout = sys.stdout.fileno() if isinstance(stderr, str): stderr = os.open(stderr, os.O_RDWR|os.O_CREAT) stderrclose = lambda : os.close(stderr) elif isinstance(stderr, int): pass elif stderr is None or not isinstance(stderr, file): stderr = sys.stderr.fileno() program_log.info("Running... %s" % (" ".join([command] + argv),)) p = os.pipe() p_stderr = os.pipe() childpid = os.fork() if not childpid: os.close(p[0]) os.close(p_stderr[0]) os.dup2(p[1], 1) os.dup2(p_stderr[1], 2) os.dup2(stdin, 0) os.close(stdin) os.close(p[1]) os.close(p_stderr[1]) os.execvp(command, [command] + argv) os._exit(1) os.close(p[1]) os.close(p_stderr[1]) log_output = '' while 1: try: s = os.read(p[0], 1) except OSError as e: if e.errno != 4: map(program_log.info, log_output.splitlines()) raise IOError, e.args if echo: os.write(stdout, s) log_output += s if callback: callback(s, callback_data=callback_data) # break out early if the sub-process changes status. # no need to flush the stream if the process has exited try: (pid, status) = os.waitpid(childpid,os.WNOHANG) if pid != 0: break except OSError as e: log.critical("exception from waitpid: %s %s" %(e.errno, e.strerror)) if len(s) < 1: break map(program_log.info, log_output.splitlines()) log_errors = '' while 1: try: err = os.read(p_stderr[0], 128) except OSError as e: if e.errno != 4: map(program_log.error, log_errors.splitlines()) raise IOError, e.args break log_errors += err if len(err) < 1: break os.write(stderr, log_errors) map(program_log.error, log_errors.splitlines()) os.close(p[0]) os.close(p_stderr[0]) try: #if we didn't already get our child's exit status above, do so now. if not pid: (pid, status) = os.waitpid(childpid, 0) except OSError as e: log.critical("exception from waitpid: %s %s" %(e.errno, e.strerror)) closefds() rc = 1 if os.WIFEXITED(status): rc = os.WEXITSTATUS(status) return ExecProduct(rc, log_output , log_errors) def _pulseProgressCallback(data, callback_data=None): if callback_data: callback_data.pulse() def execWithPulseProgress(command, argv, stdin = None, stdout = None, stderr = None, echo = True, progress = None, root = '/'): return execWithCallback(command, argv, stdin=stdin, stdout=stdout, stderr=stderr, echo=echo, callback=_pulseProgressCallback, callback_data=progress, root=root) ## Run a shell. def execConsole(): try: proc = subprocess.Popen(["/bin/sh"]) proc.wait() except OSError as e: raise RuntimeError, "Error running /bin/sh: " + e.strerror def getDirSize(dir): """ Get the size of a directory and all its subdirectories. @param dir The name of the directory to find the size of. @return The size of the directory in kilobytes. """ def getSubdirSize(dir): # returns size in bytes try: mydev = os.lstat(dir)[stat.ST_DEV] except OSError as e: log.debug("failed to stat %s: %s" % (dir, e)) return 0 try: dirlist = os.listdir(dir) except OSError as e: log.debug("failed to listdir %s: %s" % (dir, e)) return 0 dsize = 0 for f in dirlist: curpath = '%s/%s' % (dir, f) try: sinfo = os.lstat(curpath) except OSError as e: log.debug("failed to stat %s/%s: %s" % (dir, f, e)) continue if stat.S_ISDIR(sinfo[stat.ST_MODE]): if os.path.ismount(curpath): continue if mydev == sinfo[stat.ST_DEV]: dsize += getSubdirSize(curpath) elif stat.S_ISREG(sinfo[stat.ST_MODE]): dsize += sinfo[stat.ST_SIZE] return dsize return getSubdirSize(dir)/1024 ## Get the amount of RAM not used by /tmp. # @return The amount of available memory in kilobytes. def memAvailable(): tram = memInstalled() ramused = getDirSize("/tmp") return tram - ramused ## Get the amount of RAM installed in the machine. # @return The amount of installed memory in kilobytes. def memInstalled(): f = open("/proc/meminfo", "r") lines = f.readlines() f.close() for l in lines: if l.startswith("MemTotal:"): fields = string.split(l) mem = fields[1] break return long(mem) ## Create a directory path. Don't fail if the directory already exists. # @param dir The directory path to create. def mkdirChain(dir): try: os.makedirs(dir, 0755) except OSError as e: try: if e.errno == errno.EEXIST and stat.S_ISDIR(os.stat(dir).st_mode): return except OSError: pass log.error("could not create directory %s: %s" % (dir, e.strerror)) ## Copy a device node. # Copies a device node by looking at the device type, major and minor device # numbers, and doing a mknod on the new device name. # # @param src The name of the source device node. # @param dest The name of the new device node to create. def copyDeviceNode(src, dest): filestat = os.lstat(src) mode = filestat[stat.ST_MODE] if stat.S_ISBLK(mode): type = stat.S_IFBLK elif stat.S_ISCHR(mode): type = stat.S_IFCHR else: # XXX should we just fallback to copying normally? raise RuntimeError, "Tried to copy %s which isn't a device node" % (src,) os.mknod(dest, mode | type, filestat.st_rdev) ## Get the SPARC machine variety type. # @return The SPARC machine type, or 0 if not SPARC. def getSparcMachine(): if not isSparc(): return 0 machine = None f = open('/proc/cpuinfo', 'r') lines = f.readlines() f.close() for line in lines: if line.find('type') != -1: machine = line.split(':')[1].strip() return machine return None ## Get the PPC machine variety type. # @return The PPC machine type, or 0 if not PPC. def getPPCMachine(): if not isPPC(): return 0 ppcMachine = None machine = None platform = None # ppc machine hash ppcType = { 'Mac' : 'PMac', 'Book' : 'PMac', 'CHRP IBM' : 'pSeries', 'Pegasos' : 'Pegasos', 'Efika' : 'Efika', 'iSeries' : 'iSeries', 'pSeries' : 'pSeries', 'PReP' : 'PReP', 'CHRP' : 'pSeries', 'Amiga' : 'APUS', 'Gemini' : 'Gemini', 'Shiner' : 'ANS', 'BRIQ' : 'BRIQ', 'Teron' : 'Teron', 'AmigaOne' : 'Teron', 'Maple' : 'pSeries', 'Cell' : 'pSeries', 'Momentum' : 'pSeries', 'PS3' : 'PS3', 'PowerNV' : 'pSeries' } f = open('/proc/cpuinfo', 'r') lines = f.readlines() f.close() for line in lines: if line.find('machine') != -1: machine = line.split(':')[1] elif line.find('platform') != -1: platform = line.split(':')[1] for part in (machine, platform): if ppcMachine is None and part is not None: for type in ppcType.items(): if part.find(type[0]) != -1: ppcMachine = type[1] if ppcMachine is None: log.warning("Unable to find PowerPC machine type") elif ppcMachine == 0: log.warning("Unknown PowerPC machine type: %s" %(ppcMachine,)) return ppcMachine ## Get the powermac machine ID. # @return The powermac machine id, or 0 if not PPC. def getPPCMacID(): machine = None if not isPPC(): return 0 if getPPCMachine() != "PMac": return 0 f = open('/proc/cpuinfo', 'r') lines = f.readlines() f.close() for line in lines: if line.find('machine') != -1: machine = line.split(':')[1] machine = machine.strip() return machine log.warning("No Power Mac machine id") return 0 ## Get the powermac generation. # @return The powermac generation, or 0 if not powermac. def getPPCMacGen(): # XXX: should NuBus be here? pmacGen = ['OldWorld', 'NewWorld', 'NuBus'] if not isPPC(): return 0 if getPPCMachine() != "PMac": return 0 f = open('/proc/cpuinfo', 'r') lines = f.readlines() f.close() gen = None for line in lines: if line.find('pmac-generation') != -1: gen = line.split(':')[1] break if gen is None: log.warning("Unable to find pmac-generation") for type in pmacGen: if gen.find(type) != -1: return type log.warning("Unknown Power Mac generation: %s" %(gen,)) return 0 ## Determine if the hardware is an iBook or PowerBook # @return 1 if so, 0 otherwise. def getPPCMacBook(): if not isPPC(): return 0 if getPPCMachine() != "PMac": return 0 f = open('/proc/cpuinfo', 'r') lines = f.readlines() f.close() for line in lines: if not string.find(string.lower(line), 'book') == -1: return 1 return 0 ## Get the ARM processor variety. # @return The ARM processor variety type, or 0 if not ARM. def getARMMachine(): if not isARM(): return 0 if flags.armPlatform: return flags.armPlatform armMachine = os.uname()[2].rpartition('.' )[2] if armMachine.startswith('arm'): return None else: return armMachine cell = None ## Determine if the hardware is the Cell platform. # @return True if so, False otherwise. def isCell(): global cell if cell is not None: return cell cell = False if not isPPC(): return cell f = open('/proc/cpuinfo', 'r') lines = f.readlines() f.close() for line in lines: if not string.find(line, 'Cell') == -1: cell = True return cell mactel = None ## Determine if the hardware is an Intel-based Apple Mac. # @return True if so, False otherwise. def isMactel(): global mactel if mactel is not None: return mactel if not isX86(): mactel = False elif not os.path.isfile(DMI_CHASSIS_VENDOR): mactel = False else: buf = open(DMI_CHASSIS_VENDOR).read() if buf.lower().find("apple") != -1: mactel = True else: mactel = False return mactel efi = None ## Determine if the hardware supports EFI. # @return True if so, False otherwise. def isEfi(): global efi if efi is not None: return efi efi = False # XXX need to make sure efivars is loaded... if os.path.exists("/sys/firmware/efi"): efi = True return efi # Architecture checking functions def isX86(bits=None): arch = os.uname()[4] # x86 platforms include: # i*86 # athlon* # x86_64 # amd* # ia32e if bits is None: if (arch.startswith('i') and arch.endswith('86')) or \ arch.startswith('athlon') or arch.startswith('amd') or \ arch == 'x86_64' or arch == 'ia32e': return True elif bits == 32: if arch.startswith('i') and arch.endswith('86'): return True elif bits == 64: if arch.startswith('athlon') or arch.startswith('amd') or \ arch == 'x86_64' or arch == 'ia32e': return True return False def isPPC(bits=None): arch = os.uname()[4] if bits is None: if arch == 'ppc' or arch == 'ppc64': return True elif bits == 32: if arch == 'ppc': return True elif bits == 64: if arch == 'ppc64': return True return False def isS390(): return os.uname()[4].startswith('s390') def isIA64(): return os.uname()[4] == 'ia64' def isAlpha(): return os.uname()[4].startswith('alpha') def isSparc(): return os.uname()[4].startswith('sparc') def isARM(): return os.uname()[4].startswith('arm') def getArch(): if isX86(bits=32): return 'i386' elif isX86(bits=64): return 'x86_64' elif isPPC(bits=32): return 'ppc' elif isPPC(bits=64): return 'ppc64' elif isAlpha(): return 'alpha' elif isSparc(): return 'sparc' elif isARM(): return 'arm' else: return os.uname()[4] def isConsoleOnVirtualTerminal(): # XXX PJFIX is there some way to ask the kernel this instead? if isS390(): return False return not flags.serial def strip_markup(text): if text.find("<") == -1: return text r = "" inTag = False for c in text: if c == ">" and inTag: inTag = False continue elif c == "<" and not inTag: inTag = True continue elif not inTag: r += c return r.encode("utf-8") def notify_kernel(path, action="change"): """ Signal the kernel that the specified device has changed. Exceptions raised: ValueError, IOError """ log.debug("notifying kernel of '%s' event on device %s" % (action, path)) path = os.path.join(path, "uevent") if not path.startswith("/sys/") or not os.access(path, os.W_OK): log.debug("sysfs path '%s' invalid" % path) raise ValueError("invalid sysfs path") f = open(path, "a") f.write("%s\n" % action) f.close() def get_sysfs_path_by_name(dev_node, class_name="block"): """ Return sysfs path for a given device. For a device node (e.g. /dev/vda2) get the respective sysfs path (e.g. /sys/class/block/vda2). This also has to work for device nodes that are in a subdirectory of /dev like '/dev/cciss/c0d0p1'. """ dev_name = os.path.basename(dev_node) if dev_node.startswith("/dev/"): dev_name = dev_node[5:].replace("/", "!") sysfs_class_dir = "/sys/class/%s" % class_name dev_path = os.path.join(sysfs_class_dir, dev_name) if os.path.exists(dev_path): return dev_path else: raise RuntimeError("get_sysfs_path_by_name: Could not find sysfs path " "for '%s' (it is not at '%s')" % (dev_node, dev_path)) def numeric_type(num): """ Verify that a value is given as a numeric data type. Return the number if the type is sensible or raise ValueError if not. """ if num is None: num = 0 elif not (isinstance(num, int) or \ isinstance(num, long) or \ isinstance(num, float)): raise ValueError("value (%s) must be either a number or None" % num) return num def reIPL(ipldev): try: rc = execWithRedirect("chreipl", ["node", "/dev/" + ipldev], stdout = "/dev/tty5", stderr = "/dev/tty5") except RuntimeError as e: rc = True log.info("Unable to set reIPL device to %s: %s", ipldev, e) if rc: devstring = None for disk in anaconda.storage.disks: if disk.name == ipldev: devstring = disk.description break if devstring is None: devstring = _("the device containing /boot") message = _("After shutdown, please perform a manual IPL from %s " "to continue installation." % devstring) log.info("reIPL configuration failed") #os.kill(os.getppid(), signal.SIGUSR1) else: message = None log.info("reIPL configuration successful") #os.kill(os.getppid(), signal.SIGUSR2) return message def resetRpmDb(): for rpmfile in glob.glob("%s/var/lib/rpm/__db.*" % ROOT_PATH): try: os.unlink(rpmfile) except OSError as e: log.debug("error %s removing file: %s" %(e,rpmfile)) def parseNfsUrl(nfsurl): options = '' host = '' path = '' if nfsurl: s = nfsurl.split(":") s.pop(0) if len(s) >= 3: (options, host, path) = s[:3] elif len(s) == 2: (host, path) = s else: host = s[0] return (options, host, path) def insert_colons(a_string): """ Insert colon between every second character. E.g. creates 'al:go:ri:th:ms' from 'algoritms'. Useful for formatting MAC addresses and wwids for output. """ suffix = a_string[-2:] if len(a_string) > 2: return insert_colons(a_string[:-2]) + ':' + suffix else: return suffix def add_po_path(module, dir): """ Looks to see what translations are under a given path and tells the gettext module to use that path as the base dir """ for d in os.listdir(dir): if not os.path.isdir("%s/%s" %(dir,d)): continue if not os.path.exists("%s/%s/LC_MESSAGES" %(dir,d)): continue for basename in os.listdir("%s/%s/LC_MESSAGES" %(dir,d)): if not basename.endswith(".mo"): continue log.info("setting %s as translation source for %s" %(dir, basename[:-3])) module.bindtextdomain(basename[:-3], dir) def setup_translations(module): if os.path.isdir(TRANSLATIONS_UPDATE_DIR): add_po_path(module, TRANSLATIONS_UPDATE_DIR) module.textdomain("anaconda") def copy_to_sysimage(source): if not os.access(source, os.R_OK): log.info("copy_to_sysimage: source '%s' does not exist." % source) return False target = ROOT_PATH + source target_dir = os.path.dirname(target) log.debug("copy_to_sysimage: '%s' -> '%s'." % (source, target)) if not os.path.isdir(target_dir): os.makedirs(target_dir) shutil.copy(source, target) return True def get_sysfs_attr(path, attr): if not attr: log.debug("get_sysfs_attr() called with attr=None") return None attribute = "/sys%s/%s" % (path, attr) attribute = os.path.realpath(attribute) if not os.path.isfile(attribute) and not os.path.islink(attribute): log.warning("%s is not a valid attribute" % (attr,)) return None return open(attribute, "r").read().strip() def find_program_in_path(prog, raise_on_error=False): for d in os.environ["PATH"].split(os.pathsep): full = os.path.join(d, prog) if os.access(full, os.X_OK): return full if raise_on_error: raise RuntimeError("Unable to locate a needed executable: '%s'" % prog) return None def fork_orphan(): """Forks an orphan. Returns 1 in the parent and 0 in the orphaned child. """ intermediate = os.fork() if not intermediate: if os.fork(): # the intermediate child dies os._exit(0) return 0 # the original process waits for the intermediate child os.waitpid(intermediate, 0) return 1 def lsmod(): """ Returns list of names of all loaded modules. """ with open("/proc/modules") as f: lines = f.readlines() return [l.split()[0] for l in lines] def _run_systemctl(command, service): """ Runs 'systemctl command service.service' @return: exit status of the systemctl """ service_name = service + ".service" ret = execWithRedirect("systemctl", [command, service_name], stdin=None, stdout="/dev/tty5", stderr="/dev/tty5") return ret def start_service(service): return _run_systemctl("start", service) def stop_service(service): return _run_systemctl("stop", service) def restart_service(service): return _run_systemctl("restart", service) def service_running(service): ret = _run_systemctl("status", service) return ret == 0 def dracut_eject(device): """ Use dracut shutdown hook to eject media after the system is shutdown. This is needed because we are running from the squashfs.img on the media so ejecting too early will crash the installer. """ if not device: return try: if not os.path.exists(DRACUT_SHUTDOWN_EJECT): f = open(DRACUT_SHUTDOWN_EJECT, "w") f.write("#!/bin/sh\n") f.write("# Created by Anaconda\n") else: f = open(DRACUT_SHUTDOWN_EJECT, "a") f.write("eject %s\n" % (device,)) f.close() os.chmod(DRACUT_SHUTDOWN_EJECT, 0755) log.info("Wrote dracut shutdown eject hook for %s" % (device,)) except Exception, e: log.error("Error writing dracut shutdown eject hook for %s: %s" % (device, e)) def get_option_value(opt_name, options): """ Return the value of a named option in the specified options string. """ for opt in options.split(","): if "=" not in opt: continue name, val = opt.split("=") if name == opt_name: return val.strip() def vtActivate(num): """ Try to switch to tty number $num. @type num: int @return: whether the switch was successful or not @rtype: bool """ try: ret = execWithRedirect("chvt", [str(num)], stdout="/dev/tty5", stderr="/dev/tty5") except OSError as oserr: ret = -1 log.error("Failed to run chvt: %s", oserr.strerror) if ret != 0: log.error("Failed to switch to tty%d", num) return ret == 0 class ProxyStringError(Exception): pass class ProxyString(object): """ Handle a proxy url """ def __init__(self, url=None, protocol="http://", host=None, port="3128", username=None, password=None): """ Initialize with either url ([protocol://][username[:password]@]host[:port]) or pass host and optionally: protocol http, https, ftp host hostname without protocol port port number (defaults to 3128) username username password password The str() of the object is the full proxy url ProxyString.url is the full url including username:password@ ProxyString.noauth_url is the url without username:password@ """ self.url = url self.protocol = protocol self.host = host self.port = str(port) self.username = username self.password = password self.proxy_auth = "" self.noauth_url = None if url: self.parse_url() elif not host: raise ProxyStringError("No host url") else: self.parse_components() def parse_url(self): """ Parse the proxy url into its component pieces """ # NOTE: If this changes, update tests/regex/proxy.py # # proxy=[protocol://][username[:password]@]host[:port][path] # groups # 1 = protocol # 2 = username:password@ # 3 = username # 4 = password # 5 = hostname # 6 = port # 7 = extra pattern = re.compile("([A-Za-z]+://)?(([A-Za-z0-9]+)(:[^:@]+)?@)?([^:/]+)(:[0-9]+)?(/.*)?") m = pattern.match(self.url) if not m: raise ProxyStringError("malformed url, cannot parse it.") # If no protocol was given default to http. if m.group(1): self.protocol = m.group(1) else: self.protocol = "http://" if m.group(3): self.username = m.group(3) if m.group(4): # Skip the leading colon self.password = m.group(4)[1:] if m.group(5): self.host = m.group(5) if m.group(6): # Skip the leading colon self.port = m.group(6)[1:] else: raise ProxyStringError("url has no host component") self.parse_components() def parse_components(self): """ Parse the components of a proxy url into url and noauth_url """ if self.username or self.password: self.proxy_auth = "%s:%s@" % (self.username or "", self.password or "") self.url = self.protocol + self.proxy_auth + self.host + ":" + self.port self.noauth_url = self.protocol + self.host + ":" + self.port @property def dict(self): """ return a dict of all the elements of the proxy string url, noauth_url, protocol, host, port, username, password """ components = ["url", "noauth_url", "protocol", "host", "port", "username", "password"] return dict([(k, getattr(self, k)) for k in components]) def __str__(self): return self.url