# -*- coding: utf-8 -*- ''' # DESCRIPTION: # Entropy Object Oriented Interface Copyright (C) 2007-2009 Fabio Erculiani 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ''' from __future__ import with_statement import subprocess import shutil from entropy.client.interfaces.client import Client from entropy.const import * from entropy.exceptions import * from entropy.output import * from entropy.i18n import _ class Trigger: import entropy.tools as entropyTools def __init__(self, EquoInstance, phase, pkgdata, package_action = None): if not isinstance(EquoInstance,Client): mytxt = _("A valid Entropy Instance is needed") raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,)) self.Entropy = EquoInstance self.clientLog = self.Entropy.clientLog self.validPhases = ("preinstall","postinstall","preremove","postremove") self.pkgdata = pkgdata self.prepared = False self.triggers = set() self.gentoo_compat = etpConst['gentoo-compat'] self.package_action = package_action ''' @ description: Gentoo toolchain variables ''' self.MODULEDB_DIR="/var/lib/module-rebuild/" self.INITSERVICES_DIR="/var/lib/init.d/" ''' portage stuff ''' if self.gentoo_compat: try: Spm = self.Entropy.Spm() self.Spm = Spm except Exception, e: self.entropyTools.print_traceback() mytxt = darkred("%s, %s: %s, %s !") % ( _("Portage interface can't be loaded"), _("Error"), e, _("please fix"), ) self.Entropy.updateProgress( mytxt, importance = 0, header = bold(" !!! ") ) self.gentoo_compat = False self.phase = phase # validate phase self.phaseValidation() def phaseValidation(self): if self.phase not in self.validPhases: mytxt = "%s: %s" % (_("Valid phases"),self.validPhases,) raise InvalidData("InvalidData: %s" % (mytxt,)) def prepare(self): func = getattr(self,self.phase) self.triggers = func() self.prepared = True return len(self.triggers) > 0 def run(self): for trigger in self.triggers: fname = 'trigger_%s' % (trigger,) if not hasattr(self,fname): continue getattr(self,fname)() def kill(self): self.prepared = False del self.triggers[:] def postinstall(self): functions = [] # Gentoo hook if self.gentoo_compat: functions.append('ebuild_postinstall') # equo purge cache if self.pkgdata['category']+"/"+self.pkgdata['name'] == "sys-apps/entropy": functions.append("purgecache") # binutils configuration if self.pkgdata['category']+"/"+self.pkgdata['name'] == "sys-devel/binutils": functions.append("binutilsswitch") # opengl configuration if (self.pkgdata['category'] == "x11-drivers") and \ (self.pkgdata['name'].startswith("nvidia-") or \ self.pkgdata['name'].startswith("ati-")): if "ebuild_postinstall" in functions: # disabling gentoo postinstall since we reimplemented it functions.remove("ebuild_postinstall") functions.append("openglsetup") # load linker paths ldpaths = self.Entropy.entropyTools.collect_linker_paths() for x in self.pkgdata['content']: if (x.startswith("/etc/conf.d") or \ x.startswith("/etc/init.d")) and \ ("conftouch" not in functions): functions.append('conftouch') if x.startswith('/lib/modules/') and ("kernelmod" not in functions): if "ebuild_postinstall" in functions: # disabling gentoo postinstall since we reimplemented it functions.remove("ebuild_postinstall") functions.append('kernelmod') if x.startswith('/boot/kernel-') and ("addbootablekernel" not in functions): functions.append('addbootablekernel') if x.startswith('/usr/src/') and ("createkernelsym" not in functions): functions.append('createkernelsym') if x.startswith('/etc/env.d/') and ("env_update" not in functions): functions.append('env_update') if (os.path.dirname(x) in ldpaths) and ("run_ldconfig" not in functions): if x.find(".so") > -1: functions.append('run_ldconfig') if self.pkgdata['trigger']: functions.append('call_ext_postinstall') del ldpaths return functions def preinstall(self): functions = [] # Gentoo hook if self.gentoo_compat: functions.append('ebuild_preinstall') for x in self.pkgdata['content']: if x.startswith("/etc/init.d/") and ("initinform" not in functions): functions.append('initinform') if x.startswith("/boot") and ("mountboot" not in functions): functions.append('mountboot') if self.pkgdata['trigger']: functions.append('call_ext_preinstall') return functions def postremove(self): functions = [] # load linker paths ldpaths = self.Entropy.entropyTools.collect_linker_paths() for x in self.pkgdata['removecontent']: if x.startswith('/boot/kernel-') and ("removebootablekernel" not in functions): functions.append('removebootablekernel') if x.startswith('/etc/init.d/') and ("initdisable" not in functions): functions.append('initdisable') if x.endswith('.py') and ("cleanpy" not in functions): functions.append('cleanpy') if x.startswith('/etc/env.d/') and ("env_update" not in functions): functions.append('env_update') if (os.path.dirname(x) in ldpaths) and ("run_ldconfig" not in functions): if x.find(".so") > -1: functions.append('run_ldconfig') if self.pkgdata['trigger']: functions.append('call_ext_postremove') del ldpaths return functions def preremove(self): functions = [] # Gentoo hook if self.gentoo_compat: functions.append('ebuild_preremove') functions.append('ebuild_postremove') # doing here because we need /var/db/pkg stuff in place and also because doesn't make any difference # opengl configuration if (self.pkgdata['category'] == "x11-drivers") and \ (self.pkgdata['name'].startswith("nvidia-") or \ self.pkgdata['name'].startswith("ati-")): if "ebuild_preremove" in functions: functions.remove("ebuild_preremove") if "ebuild_postremove" in functions: # disabling gentoo postinstall since we reimplemented it functions.remove("ebuild_postremove") if self.package_action in ("remove",): functions.append("openglsetup_xorg") for x in self.pkgdata['removecontent']: if x.startswith("/boot"): functions.append('mountboot') break if self.pkgdata['trigger']: functions.append('call_ext_preremove') return functions ''' Real triggers ''' def trigger_call_ext_preinstall(self): return self.trigger_call_ext_generic() def trigger_call_ext_postinstall(self): return self.trigger_call_ext_generic() def trigger_call_ext_preremove(self): return self.trigger_call_ext_generic() def trigger_call_ext_postremove(self): return self.trigger_call_ext_generic() def trigger_call_ext_generic(self): try: return self.do_trigger_call_ext_generic() except Exception, e: mykey = self.pkgdata['category']+"/"+self.pkgdata['name'] tb = self.entropyTools.get_traceback() self.Entropy.updateProgress(tb, importance = 0, type = "error") self.Entropy.clientLog.write(tb) self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] ATTENTION Cannot run External trigger for "+mykey+"!! "+str(Exception)+": "+str(e) ) mytxt = "%s: %s %s. %s." % ( bold(_("QA")), brown(_("Cannot run External trigger for")), bold(mykey), brown(_("Please report it")), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return 0 class EntropyShSandbox: def __env_setup(self, stage, pkgdata): # mandatory variables category = pkgdata.get('category') if isinstance(category,unicode): category = category.encode('utf-8') pn = pkgdata.get('name') if isinstance(pn,unicode): pn = pn.encode('utf-8') pv = pkgdata.get('version') if isinstance(pv,unicode): pv = pv.encode('utf-8') pr = self.entropyTools.dep_get_portage_revision(pv) pvr = pv if pr == "r0": pvr += "-%s" % (pr,) pet = pkgdata.get('versiontag') if isinstance(pet,unicode): pet = pet.encode('utf-8') per = pkgdata.get('revision') if isinstance(per,unicode): per = per.encode('utf-8') etp_branch = pgkdata.get('branch') if isinstance(etp_branch,unicode): etp_branch = etp_branch.encode('utf-8') slot = pgkdata.get('slot') if isinstance(slot,unicode): slot = slot.encode('utf-8') pkgatom = pkgdata.get('atom') pkgkey = self.entropyTools.dep_getkey(pkgatom) pvrte = pkgatom[len(pkgkey)+1:] if isinstance(pvrte,unicode): pvrte = pvrte.encode('utf-8') etpapi = pkgdata.get('etpapi') if isinstance(etpapi,unicode): etpapi = etpapi.encode('utf-8') p = pkgatom if isinstance(p,unicode): p = p.encode('utf-8') chost, cflags, cxxflags = pkgdata.get('chost'), pkgdata.get('cflags'), pkgdata.get('cxxflags') chost = pkgdata.get('etpapi') if isinstance(chost,unicode): chost = chost.encode('utf-8') cflags = pkgdata.get('etpapi') if isinstance(cflags,unicode): cflags = cflags.encode('utf-8') cxxflags = pkgdata.get('etpapi') if isinstance(cxxflags,unicode): cxxflags = cxxflags.encode('utf-8') # Not mandatory variables eclasses = ' '.join(pkgdata.get('eclasses',[])) if isinstance(eclasses,unicode): eclasses = eclasses.encode('utf-8') unpackdir = pkgdata.get('unpackdir','') if isinstance(unpackdir,unicode): unpackdir = unpackdir.encode('utf-8') imagedir = pkgdata.get('imagedir','') if isinstance(imagedir,unicode): imagedir = imagedir.encode('utf-8') sb_dirs = [unpackdir,imagedir] sb_write = ':'.join(sb_dirs) myenv = { "ETP_API": etpSys['api'], "ETP_LOG": self.Entropy.clientLog.get_fpath(), "ETP_STAGE": stage, # entropy trigger stage "ETP_PHASE": self.__get_sh_stage(), # entropy trigger phase "ETP_BRANCH": etp_branch, "CATEGORY": category, # package category "PN": pn, # package name "PV": pv, # package version "PR": pr, # package revision (portage) "PVR": pvr, # package version+revision "PVRTE": pvrte, # package version+revision+entropy tag+entropy rev "PER": per, # package entropy revision "PET": pet, # package entropy tag "SLOT": slot, # package slot "PAPI": etpapi, # package entropy api "P": p, # complete package atom "WORKDIR": unpackdir, # temporary package workdir "B": unpackdir, # unpacked binary package directory? "D": imagedir, # package unpack destination (before merging to live) "ENTROPY_TMPDIR": etpConst['packagestmpdir'], # entropy temporary directory "CFLAGS": cflags, # compile flags "CXXFLAGS": cxxflags, # compile flags "CHOST": chost, # *nix CHOST "PORTAGE_ECLASSES": eclasses, # portage eclasses, " " separated "ROOT": etpConst['systemroot'], "SANDBOX_WRITE": sb_write, } sysenv = os.environ.copy() sysenv.update(myenv) return sysenv def __get_sh_stage(self, stage): mydict = { "preinstall": "pkg_preinst", "postinstall": "pkg_postinst", "preremove": "pkg_prerm", "postremove": "pkg_postrm", } return mydict.get(stage) def run(self, stage, pkgdata, trigger_file): env = self.__env_setup(stage, pkgdata) p = subprocess.Popen([trigger_file, stage], stdout = sys.stdout, stderr = sys.stderr, env = env ) rc = p.wait() if os.path.isfile(trigger_file): os.remove(trigger_file) return rc class EntropyPySandbox: def run(self, stage, pkgdata, trigger_file): my_ext_status = 1 if os.path.isfile(trigger_file): execfile(trigger_file) if os.path.isfile(trigger_file): os.remove(trigger_file) return my_ext_status def do_trigger_call_ext_generic(self): # if mute, supress portage output if etpUi['mute']: oldsystderr = sys.stderr oldsysstdout = sys.stdout stdfile = open("/dev/null","w") sys.stdout = stdfile sys.stderr = stdfile tg_pfx = "%s/trigger-" % (etpConst['entropyunpackdir'],) while 1: triggerfile = "%s%s" % (tg_pfx,self.Entropy.entropyTools.get_random_number(),) if not os.path.isfile(triggerfile): break triggerdir = os.path.dirname(triggerfile) if not os.path.isdir(triggerdir): os.makedirs(triggerdir) f = open(triggerfile,"w") chunk = 1024 start = 0 while 1: buf = self.pkgdata['trigger'][start:] if not buf: break f.write(buf) start += chunk f.flush() f.close() # if mute, restore old stdout/stderr if etpUi['mute']: sys.stderr = oldsystderr sys.stdout = oldsysstdout stdfile.close() f = open(triggerfile,"r") interpreter = f.readline().strip() f.close() entropy_sh = etpConst['trigger_sh_interpreter'] if interpreter == "#!%s" % (entropy_sh,): os.chmod(triggerfile,0775) my = self.EntropyShSandbox() else: my = self.EntropyPySandbox() return my.run(self.phase, self.pkgdata, triggerfile) def trigger_purgecache(self): self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Purging Entropy cache..." ) mytxt = "%s: %s." % (_("Please remember"),_("It is always better to leave Entropy updates isolated"),) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) mytxt = "%s ..." % (_("Purging Entropy cache"),) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) self.Entropy.purge_cache(False) def trigger_conftouch(self): self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Updating {conf.d,init.d} mtime..." ) mytxt = "%s ..." % (_("Updating {conf.d,init.d} mtime"),) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) for item in self.pkgdata['content']: if not (item.startswith("/etc/conf.d") or item.startswith("/etc/conf.d")): continue if not os.path.isfile(item): continue if not os.access(item,os.W_OK): continue try: f = open(item,"abw") f.flush() f.close() except (OSError,IOError,): pass def trigger_binutilsswitch(self): self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Configuring Binutils Profile..." ) mytxt = "%s ..." % (_("Configuring Binutils Profile"),) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) # get binutils profile pkgsplit = self.Entropy.entropyTools.catpkgsplit( self.pkgdata['category'] + "/" + self.pkgdata['name'] + "-" + self.pkgdata['version'] ) profile = self.pkgdata['chost']+"-"+pkgsplit[2] self.trigger_set_binutils_profile(profile) def trigger_kernelmod(self): if self.pkgdata['category'] != "sys-kernel": self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Updating moduledb..." ) mytxt = "%s ..." % (_("Updating moduledb"),) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) item = 'a:1:'+self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version'] self.trigger_update_moduledb(item) mytxt = "%s ..." % (_("Running depmod"),) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) # get kernel modules dir name name = '' for item in self.pkgdata['content']: item = etpConst['systemroot']+item if item.startswith(etpConst['systemroot']+"/lib/modules/"): name = item[len(etpConst['systemroot']):] name = name.split("/")[3] break if name: self.trigger_run_depmod(name) def trigger_initdisable(self): for item in self.pkgdata['removecontent']: item = etpConst['systemroot']+item if item.startswith(etpConst['systemroot']+"/etc/init.d/") and os.path.isfile(item): myroot = "/" if etpConst['systemroot']: myroot = etpConst['systemroot']+"/" runlevels_dir = etpConst['systemroot']+"/etc/runlevels" runlevels = [] if os.path.isdir(runlevels_dir) and os.access(runlevels_dir,os.R_OK): runlevels = [x for x in os.listdir(runlevels_dir) \ if os.path.isdir(os.path.join(runlevels_dir,x)) \ and os.path.isfile(os.path.join(runlevels_dir,x,os.path.basename(item))) ] for runlevel in runlevels: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Removing boot service: %s, runlevel: %s" % (os.path.basename(item),runlevel,) ) mytxt = "%s: %s : %s" % (brown(_("Removing boot service")),os.path.basename(item),runlevel,) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) cmd = 'ROOT="%s" rc-update del %s %s' % (myroot, os.path.basename(item), runlevel) subprocess.call(cmd, shell = True) def trigger_initinform(self): for item in self.pkgdata['content']: item = etpConst['systemroot']+item if item.startswith(etpConst['systemroot']+"/etc/init.d/") and not os.path.isfile(etpConst['systemroot']+item): self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] A new service will be installed: %s" % (item,) ) mytxt = "%s: %s" % (brown(_("A new service will be installed")),item,) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) def trigger_openglsetup(self): opengl = "xorg-x11" if self.pkgdata['name'] == "nvidia-drivers": opengl = "nvidia" elif self.pkgdata['name'] == "ati-drivers": opengl = "ati" # is there eselect ? eselect = subprocess.call("eselect opengl &> /dev/null", shell = True) if eselect == 0: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Reconfiguring OpenGL to %s ..." % (opengl,) ) mytxt = "%s ..." % (brown(_("Reconfiguring OpenGL")),) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) quietstring = '' if etpUi['quiet']: quietstring = " &>/dev/null" if etpConst['systemroot']: subprocess.call('echo "eselect opengl set --use-old %s" | chroot %s %s' % (opengl,etpConst['systemroot'],quietstring,), shell = True) else: subprocess.call('eselect opengl set --use-old %s %s' % (opengl,quietstring,), shell = True) else: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Eselect NOT found, cannot run OpenGL trigger" ) mytxt = "%s !" % (brown(_("Eselect NOT found, cannot run OpenGL trigger")),) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ##") ) def trigger_openglsetup_xorg(self): eselect = subprocess.call("eselect opengl &> /dev/null", shell = True) if eselect == 0: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Reconfiguring OpenGL to fallback xorg-x11 ..." ) mytxt = "%s ..." % (brown(_("Reconfiguring OpenGL")),) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) quietstring = '' if etpUi['quiet']: quietstring = " &>/dev/null" if etpConst['systemroot']: subprocess.call('echo "eselect opengl set xorg-x11" | chroot %s %s' % (etpConst['systemroot'],quietstring,), shell = True) else: subprocess.call('eselect opengl set xorg-x11 %s' % (quietstring,), shell = True) else: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Eselect NOT found, cannot run OpenGL trigger" ) mytxt = "%s !" % (brown(_("Eselect NOT found, cannot run OpenGL trigger")),) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ##") ) # FIXME: this only supports grub (no lilo support) def trigger_addbootablekernel(self): boot_mount = False if os.path.ismount("/boot"): boot_mount = True kernels = [x for x in self.pkgdata['content'] if x.startswith("/boot/kernel-")] if boot_mount: kernels = [x[len("/boot"):] for x in kernels] for kernel in kernels: mykernel = kernel.split('/kernel-')[1] initramfs = "/boot/initramfs-"+mykernel if initramfs not in self.pkgdata['content']: initramfs = '' elif boot_mount: initramfs = initramfs[len("/boot"):] # configure GRUB self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Configuring GRUB bootloader. Adding the new kernel..." ) mytxt = "%s. %s ..." % ( _("Configuring GRUB bootloader"), _("Adding the new kernel"), ) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) self.trigger_configure_boot_grub(kernel, initramfs) # FIXME: this only supports grub (no lilo support) def trigger_removebootablekernel(self): kernels = [x for x in self.pkgdata['content'] if \ x.startswith("/boot/kernel-")] for kernel in kernels: initramfs = "/boot/initramfs-"+kernel[13:] if initramfs not in self.pkgdata['content']: initramfs = '' # configure GRUB self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Configuring GRUB bootloader. Removing the selected kernel..." ) mytxt = "%s. %s ..." % ( _("Configuring GRUB bootloader"), _("Removing the selected kernel"), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) self.trigger_remove_boot_grub(kernel,initramfs) def trigger_mountboot(self): # is in fstab? if etpConst['systemroot']: return if os.path.isfile("/etc/fstab"): f = open("/etc/fstab","r") fstab = f.readlines() fstab = self.Entropy.entropyTools.list_to_utf8(fstab) f.close() for line in fstab: fsline = line.split() if len(fsline) > 1: if fsline[1] == "/boot": if not os.path.ismount("/boot"): # trigger mount /boot rc = subprocess.call("mount /boot &> /dev/null", shell = True) if rc == 0: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] Mounted /boot successfully" ) self.Entropy.updateProgress( brown(_("Mounted /boot successfully")), importance = 0, header = red(" ## ") ) elif rc != 8192: # already mounted self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] Cannot mount /boot automatically !!" ) self.Entropy.updateProgress( brown(_("Cannot mount /boot automatically !!")), importance = 0, header = red(" ## ") ) break def trigger_cleanpy(self): pyfiles = [x for x in self.pkgdata['content'] if x.endswith(".py")] for item in pyfiles: item = etpConst['systemroot']+item if os.path.isfile(item+"o"): try: os.remove(item+"o") except OSError: pass if os.path.isfile(item+"c"): try: os.remove(item+"c") except OSError: pass def trigger_createkernelsym(self): for item in self.pkgdata['content']: item = etpConst['systemroot']+item if item.startswith(etpConst['systemroot']+"/usr/src/"): # extract directory try: todir = item[len(etpConst['systemroot']):] todir = todir.split("/")[3] except: continue if os.path.isdir(etpConst['systemroot']+"/usr/src/"+todir): # link to /usr/src/linux self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Creating kernel symlink "+etpConst['systemroot']+"/usr/src/linux for /usr/src/"+todir ) mytxt = "%s %s %s %s" % ( _("Creating kernel symlink"), etpConst['systemroot']+"/usr/src/linux", _("for"), "/usr/src/"+todir, ) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) if os.path.isfile(etpConst['systemroot']+"/usr/src/linux") or \ os.path.islink(etpConst['systemroot']+"/usr/src/linux"): os.remove(etpConst['systemroot']+"/usr/src/linux") if os.path.isdir(etpConst['systemroot']+"/usr/src/linux"): mydir = etpConst['systemroot']+"/usr/src/linux."+str(self.Entropy.entropyTools.get_random_number()) while os.path.isdir(mydir): mydir = etpConst['systemroot']+"/usr/src/linux."+str(self.Entropy.entropyTools.get_random_number()) shutil.move(etpConst['systemroot']+"/usr/src/linux",mydir) try: os.symlink(todir,etpConst['systemroot']+"/usr/src/linux") except OSError: # not important in the end pass break def trigger_run_ldconfig(self): if not etpConst['systemroot']: myroot = "/" else: myroot = etpConst['systemroot']+"/" self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Running ldconfig" ) mytxt = "%s %s" % (_("Regenerating"),"/etc/ld.so.cache",) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) subprocess.call("ldconfig -r %s &> /dev/null" % (myroot,), shell = True) def trigger_env_update(self): self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] Running env-update" ) if os.access(etpConst['systemroot']+"/usr/sbin/env-update",os.X_OK): mytxt = "%s ..." % (_("Updating environment"),) self.Entropy.updateProgress( brown(mytxt), importance = 0, header = red(" ## ") ) if etpConst['systemroot']: subprocess.call("echo 'env-update --no-ldconfig' | chroot %s &> /dev/null" % (etpConst['systemroot'],), shell = True) else: subprocess.call('env-update --no-ldconfig &> /dev/null', shell = True) def trigger_ebuild_postinstall(self): stdfile = open("/dev/null","w") oldstderr = sys.stderr oldstdout = sys.stdout sys.stderr = stdfile myebuild = [self.pkgdata['xpakdir']+"/"+x for x in os.listdir(self.pkgdata['xpakdir']) if x.endswith(etpConst['spm']['source_build_ext'])] if myebuild: myebuild = myebuild[0] portage_atom = self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version'] self.Entropy.updateProgress( brown("Ebuild: pkg_postinst()"), importance = 0, header = red(" ## ") ) try: if not os.path.isfile(self.pkgdata['unpackdir']+"/portage/"+portage_atom+"/temp/environment"): # if environment is not yet created, we need to run pkg_setup() sys.stdout = stdfile rc = self.Spm.spm_doebuild( myebuild, mydo = "setup", tree = "bintree", cpv = portage_atom, portage_tmpdir = self.pkgdata['unpackdir'], licenses = self.pkgdata['accept_license'] ) if rc == 1: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] ATTENTION Cannot properly run Gentoo postinstall (pkg_setup())" " trigger for "+str(portage_atom)+". Something bad happened." ) sys.stdout = oldstdout rc = self.Spm.spm_doebuild( myebuild, mydo = "postinst", tree = "bintree", cpv = portage_atom, portage_tmpdir = self.pkgdata['unpackdir'], licenses = self.pkgdata['accept_license'] ) if rc == 1: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] ATTENTION Cannot properly run Gentoo postinstall (pkg_postinst()) trigger for " + \ str(portage_atom) + ". Something bad happened." ) except Exception, e: sys.stdout = oldstdout self.entropyTools.print_traceback() self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[POST] ATTENTION Cannot run Portage trigger for "+portage_atom+"!! "+str(Exception)+": "+str(e) ) mytxt = "%s: %s %s. %s. %s: %s" % ( bold(_("QA")), brown(_("Cannot run Portage trigger for")), bold(str(portage_atom)), brown(_("Please report it")), bold(_("Attach this")), darkred(etpConst['spmlogfile']), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) sys.stderr = oldstderr sys.stdout = oldstdout stdfile.close() return 0 def trigger_ebuild_preinstall(self): stdfile = open("/dev/null","w") oldstderr = sys.stderr oldstdout = sys.stdout sys.stderr = stdfile myebuild = [self.pkgdata['xpakdir']+"/"+x for x in os.listdir(self.pkgdata['xpakdir']) if x.endswith(etpConst['spm']['source_build_ext'])] if myebuild: myebuild = myebuild[0] portage_atom = self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version'] self.Entropy.updateProgress( brown(" Ebuild: pkg_preinst()"), importance = 0, header = red(" ##") ) try: sys.stdout = stdfile rc = self.Spm.spm_doebuild( myebuild, mydo = "setup", tree = "bintree", cpv = portage_atom, portage_tmpdir = self.pkgdata['unpackdir'], licenses = self.pkgdata['accept_license'] ) # create mysettings["T"]+"/environment" if rc == 1: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] ATTENTION Cannot properly run Portage preinstall (pkg_setup()) trigger for " + \ str(portage_atom) + ". Something bad happened." ) sys.stdout = oldstdout rc = self.Spm.spm_doebuild( myebuild, mydo = "preinst", tree = "bintree", cpv = portage_atom, portage_tmpdir = self.pkgdata['unpackdir'], licenses = self.pkgdata['accept_license'] ) if rc == 1: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] ATTENTION Cannot properly run Gentoo preinstall (pkg_preinst()) trigger for " + \ str(portage_atom)+". Something bad happened." ) except Exception, e: sys.stdout = oldstdout self.entropyTools.print_traceback() self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] ATTENTION Cannot run Gentoo preinst trigger for "+portage_atom+"!! "+str(Exception)+": "+str(e) ) mytxt = "%s: %s %s. %s. %s: %s" % ( bold(_("QA")), brown(_("Cannot run Portage trigger for")), bold(str(portage_atom)), brown(_("Please report it")), bold(_("Attach this")), darkred(etpConst['spmlogfile']), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) sys.stderr = oldstderr sys.stdout = oldstdout stdfile.close() return 0 def trigger_ebuild_preremove(self): stdfile = open("/dev/null","w") oldstderr = sys.stderr sys.stderr = stdfile portage_atom = self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version'] try: myebuild = self.Spm.get_vdb_path()+portage_atom+"/"+self.pkgdata['name']+"-"+self.pkgdata['version']+etpConst['spm']['source_build_ext'] except: myebuild = '' self.myebuild_moved = None if os.path.isfile(myebuild): try: myebuild = self._setup_remove_ebuild_environment(myebuild, portage_atom) except EOFError, e: sys.stderr = oldstderr stdfile.close() # stuff on system is broken, ignore it self.Entropy.updateProgress( darkred("!!! Ebuild: pkg_prerm() failed, EOFError: ")+str(e)+darkred(" - ignoring"), importance = 1, type = "warning", header = red(" ## ") ) return 0 except ImportError, e: sys.stderr = oldstderr stdfile.close() # stuff on system is broken, ignore it self.Entropy.updateProgress( darkred("!!! Ebuild: pkg_prerm() failed, ImportError: ")+str(e)+darkred(" - ignoring"), importance = 1, type = "warning", header = red(" ## ") ) return 0 if os.path.isfile(myebuild): self.Entropy.updateProgress( brown(" Ebuild: pkg_prerm()"), importance = 0, header = red(" ##") ) try: rc = self.Spm.spm_doebuild( myebuild, mydo = "prerm", tree = "bintree", cpv = portage_atom, portage_tmpdir = etpConst['entropyunpackdir'] + "/" + portage_atom ) if rc == 1: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] ATTENTION Cannot properly run Portage trigger for " + \ str(portage_atom)+". Something bad happened." ) except Exception, e: sys.stderr = oldstderr stdfile.close() self.entropyTools.print_traceback() self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] ATTENTION Cannot run Portage preremove trigger for "+portage_atom+"!! "+str(Exception)+": "+str(e) ) mytxt = "%s: %s %s. %s. %s: %s" % ( bold(_("QA")), brown(_("Cannot run Portage trigger for")), bold(str(portage_atom)), brown(_("Please report it")), bold(_("Attach this")), darkred(etpConst['spmlogfile']), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return 0 sys.stderr = oldstderr stdfile.close() self._remove_overlayed_ebuild() return 0 def trigger_ebuild_postremove(self): stdfile = open("/dev/null","w") oldstderr = sys.stderr sys.stderr = stdfile portage_atom = self.pkgdata['category']+"/"+self.pkgdata['name']+"-"+self.pkgdata['version'] try: myebuild = self.Spm.get_vdb_path()+portage_atom+"/"+self.pkgdata['name']+"-"+self.pkgdata['version']+etpConst['spm']['source_build_ext'] except: myebuild = '' self.myebuild_moved = None if os.path.isfile(myebuild): try: myebuild = self._setup_remove_ebuild_environment(myebuild, portage_atom) except EOFError, e: sys.stderr = oldstderr stdfile.close() # stuff on system is broken, ignore it self.Entropy.updateProgress( darkred("!!! Ebuild: pkg_postrm() failed, EOFError: ")+str(e)+darkred(" - ignoring"), importance = 1, type = "warning", header = red(" ## ") ) return 0 except ImportError, e: sys.stderr = oldstderr stdfile.close() # stuff on system is broken, ignore it self.Entropy.updateProgress( darkred("!!! Ebuild: pkg_postrm() failed, ImportError: ")+str(e)+darkred(" - ignoring"), importance = 1, type = "warning", header = red(" ## ") ) return 0 if os.path.isfile(myebuild): self.Entropy.updateProgress( brown(" Ebuild: pkg_postrm()"), importance = 0, header = red(" ##") ) try: rc = self.Spm.spm_doebuild( myebuild, mydo = "postrm", tree = "bintree", cpv = portage_atom, portage_tmpdir = etpConst['entropyunpackdir']+"/"+portage_atom ) if rc == 1: self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] ATTENTION Cannot properly run Gentoo postremove trigger for " + \ str(portage_atom)+". Something bad happened." ) except Exception, e: sys.stderr = oldstderr stdfile.close() self.entropyTools.print_traceback() self.Entropy.clientLog.log( ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, "[PRE] ATTENTION Cannot run Gentoo postremove trigger for " + \ portage_atom+"!! "+str(Exception)+": "+str(e) ) mytxt = "%s: %s %s. %s. %s: %s" % ( bold(_("QA")), brown(_("Cannot run Portage trigger for")), bold(str(portage_atom)), brown(_("Please report it")), bold(_("Attach this")), darkred(etpConst['spmlogfile']), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return 0 sys.stderr = oldstderr stdfile.close() self._remove_overlayed_ebuild() return 0 def _setup_remove_ebuild_environment(self, myebuild, portage_atom): ebuild_dir = os.path.dirname(myebuild) ebuild_file = os.path.basename(myebuild) # copy the whole directory in a safe place dest_dir = os.path.join(etpConst['entropyunpackdir'],"vardb/"+portage_atom) if os.path.exists(dest_dir): if os.path.isdir(dest_dir): shutil.rmtree(dest_dir,True) elif os.path.isfile(dest_dir) or os.path.islink(dest_dir): os.remove(dest_dir) os.makedirs(dest_dir) items = os.listdir(ebuild_dir) for item in items: myfrom = os.path.join(ebuild_dir,item) myto = os.path.join(dest_dir,item) shutil.copy2(myfrom,myto) newmyebuild = os.path.join(dest_dir,ebuild_file) if os.path.isfile(newmyebuild): myebuild = newmyebuild self.myebuild_moved = myebuild self._ebuild_env_setup_hook(myebuild) return myebuild def _ebuild_env_setup_hook(self, myebuild): ebuild_path = os.path.dirname(myebuild) if not etpConst['systemroot']: myroot = "/" else: myroot = etpConst['systemroot']+"/" # we need to fix ROOT= if it's set inside environment bz2envfile = os.path.join(ebuild_path,"environment.bz2") if os.path.isfile(bz2envfile) and os.path.isdir(myroot): import bz2 envfile = self.Entropy.entropyTools.unpack_bzip2(bz2envfile) bzf = bz2.BZ2File(bz2envfile,"w") f = open(envfile,"r") line = f.readline() while line: if line.startswith("ROOT="): line = "ROOT=%s\n" % (myroot,) bzf.write(line) line = f.readline() f.close() bzf.close() os.remove(envfile) def _remove_overlayed_ebuild(self): if not self.myebuild_moved: return if os.path.isfile(self.myebuild_moved): mydir = os.path.dirname(self.myebuild_moved) shutil.rmtree(mydir,True) mydir = os.path.dirname(mydir) content = os.listdir(mydir) while not content: os.rmdir(mydir) mydir = os.path.dirname(mydir) content = os.listdir(mydir) ''' Internal ones ''' ''' @description: set chosen gcc profile @output: returns int() as exit status ''' def trigger_set_gcc_profile(self, profile): if os.access(etpConst['systemroot']+'/usr/bin/gcc-config',os.X_OK): redirect = "" if etpUi['quiet']: redirect = " &> /dev/null" if etpConst['systemroot']: subprocess.call("echo '/usr/bin/gcc-config %s' | chroot %s %s" % ( profile, etpConst['systemroot'], redirect,), shell = True) else: subprocess.call('/usr/bin/gcc-config %s %s' % ( profile, redirect,), shell = True) return 0 ''' @description: set chosen binutils profile @output: returns int() as exit status ''' def trigger_set_binutils_profile(self, profile): if os.access(etpConst['systemroot']+'/usr/bin/binutils-config',os.X_OK): redirect = "" if etpUi['quiet']: redirect = " &> /dev/null" if etpConst['systemroot']: subprocess.call("echo '/usr/bin/binutils-config %s' | chroot %s %s" % (profile,etpConst['systemroot'],redirect,), shell = True) else: subprocess.call('/usr/bin/binutils-config %s %s' % (profile,redirect,), shell = True) return 0 ''' @description: updates moduledb @output: returns int() as exit status ''' def trigger_update_moduledb(self, item): if os.access(etpConst['systemroot']+'/usr/sbin/module-rebuild',os.X_OK): if os.path.isfile(etpConst['systemroot']+self.MODULEDB_DIR+'moduledb'): f = open(etpConst['systemroot']+self.MODULEDB_DIR+'moduledb',"r") moduledb = f.readlines() moduledb = self.Entropy.entropyTools.list_to_utf8(moduledb) f.close() avail = [x for x in moduledb if x.strip() == item] if (not avail): f = open(etpConst['systemroot']+self.MODULEDB_DIR+'moduledb',"aw") f.write(item+"\n") f.flush() f.close() return 0 ''' @description: insert kernel object into kernel modules db @output: returns int() as exit status ''' def trigger_run_depmod(self, name): if os.access('/sbin/depmod',os.X_OK): if not etpConst['systemroot']: myroot = "/" else: myroot = etpConst['systemroot']+"/" subprocess.call('/sbin/depmod -a -b %s -r %s &> /dev/null' % ( myroot, name,), shell = True) return 0 def __get_entropy_kernel_grub_line(self, kernel): sys_name = self.Entropy.SystemSettings['system']['name'] return "title=%s (%s)\n" % (sys_name, os.path.basename(kernel),) ''' @description: append kernel entry to grub.conf @output: returns int() as exit status ''' def trigger_configure_boot_grub(self, kernel, initramfs): if not os.path.isdir(etpConst['systemroot']+"/boot/grub"): os.makedirs(etpConst['systemroot']+"/boot/grub") if os.path.isfile(etpConst['systemroot']+"/boot/grub/grub.conf"): # open in append grub = open(etpConst['systemroot']+"/boot/grub/grub.conf","aw") shutil.copy2(etpConst['systemroot']+"/boot/grub/grub.conf", etpConst['systemroot']+"/boot/grub/grub.conf.old.add") # get boot dev boot_dev = self.trigger_get_grub_boot_dev() # test if entry has been already added grubtest = open(etpConst['systemroot']+"/boot/grub/grub.conf","r") content = grubtest.readlines() content = [unicode(x,'raw_unicode_escape') for x in content] for line in content: if line.find(self.__get_entropy_kernel_grub_line(kernel)) != -1: grubtest.close() return # also check if we have the same kernel listed if (line.find("kernel") != 1) and \ (line.find(os.path.basename(kernel)) != -1) and not \ line.strip().startswith("#"): grubtest.close() return else: # create boot_dev = "(hd0,0)" grub = open(etpConst['systemroot']+"/boot/grub/grub.conf","w") # write header - guess (hd0,0)... since it is weird # having a running system without a bootloader, at least, grub. grub.write("default=0\ntimeout=10\n") grub.write(self.__get_entropy_kernel_grub_line(kernel)) grub.write("\troot "+boot_dev+"\n") grub.write("\tkernel "+kernel+"\n") if initramfs: grub.write("\tinitrd "+initramfs+"\n") grub.write("\tsavedefault\n") grub.write("\n") grub.flush() grub.close() def trigger_remove_boot_grub(self, kernel,initramfs): if os.path.isdir(etpConst['systemroot']+"/boot/grub") and \ os.path.isfile(etpConst['systemroot']+"/boot/grub/grub.conf"): shutil.copy2(etpConst['systemroot']+"/boot/grub/grub.conf", etpConst['systemroot']+"/boot/grub/grub.conf.old.remove") f = open(etpConst['systemroot']+"/boot/grub/grub.conf","r") grub_conf = f.readlines() f.close() content = [unicode(x,'raw_unicode_escape') for x in grub_conf] try: kernel, initramfs = (unicode(kernel,'raw_unicode_escape'), unicode(initramfs,'raw_unicode_escape'),) except TypeError: pass new_conf = [] skip = False for line in content: kernel_grub_line = self.__get_entropy_kernel_grub_line(kernel) if (line.find(kernel_grub_line) != -1): skip = True continue if line.strip().startswith("title"): skip = False if not skip or line.strip().startswith("#"): new_conf.append(line) f = open(etpConst['systemroot']+"/boot/grub/grub.conf","w") for line in new_conf: try: f.write(line) except UnicodeEncodeError: f.write(line.encode('utf-8')) f.flush() f.close() def trigger_get_grub_boot_dev(self): if etpConst['systemroot']: return "(hd0,0)" import re df_avail = subprocess.call("which df &> /dev/null", shell = True) if df_avail != 0: mytxt = "%s: %s! %s. %s (hd0,0)." % ( bold(_("QA")), brown(_("Cannot find df")), brown(_("Cannot properly configure the kernel")), brown(_("Defaulting to")), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return "(hd0,0)" grub_avail = subprocess.call("which grub &> /dev/null", shell = True) if grub_avail != 0: mytxt = "%s: %s! %s. %s (hd0,0)." % ( bold(_("QA")), brown(_("Cannot find grub")), brown(_("Cannot properly configure the kernel")), brown(_("Defaulting to")), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return "(hd0,0)" from entropy.tools import getstatusoutput gboot = getstatusoutput("df /boot")[1].split("\n")[-1].split()[0] if gboot.startswith("/dev/"): # it's ok - handle /dev/md if gboot.startswith("/dev/md"): md = os.path.basename(gboot) if not md.startswith("md"): md = "md"+md f = open("/proc/mdstat","r") mdstat = f.readlines() mdstat = [x for x in mdstat if x.startswith(md)] f.close() if mdstat: mdstat = mdstat[0].strip().split() mddevs = [] for x in mdstat: if x.startswith("sd"): mddevs.append(x[:-3]) mddevs = sorted(mddevs) if mddevs: gboot = "/dev/"+mddevs[0] else: gboot = "/dev/sda1" else: gboot = "/dev/sda1" # get disk match = re.subn("[0-9]","",gboot) gdisk = match[0] if gdisk == '': mytxt = "%s: %s %s %s. %s! %s (hd0,0)." % ( bold(_("QA")), brown(_("cannot match device")), brown(str(gboot)), brown(_("with a grub one")), # 'cannot match device /dev/foo with a grub one' brown(_("Cannot properly configure the kernel")), brown(_("Defaulting to")), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return "(hd0,0)" match = re.subn("[a-z/]","",gboot) try: gpartnum = str(int(match[0])-1) except ValueError: mytxt = "%s: %s: %s. %s. %s (hd0,0)." % ( bold(_("QA")), brown(_("grub translation not supported for")), brown(str(gboot)), brown(_("Cannot properly configure grub.conf")), brown(_("Defaulting to")), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return "(hd0,0)" # now match with grub device_map = etpConst['packagestmpdir']+"/grub.map" if os.path.isfile(device_map): os.remove(device_map) # generate device.map subprocess.call('echo "quit" | grub --device-map="%s" --no-floppy --batch &> /dev/null' % (device_map,), shell = True) if os.path.isfile(device_map): f = open(device_map,"r") device_map_file = f.readlines() f.close() grub_dev = [x for x in device_map_file if (x.find(gdisk) != -1)] if grub_dev: grub_disk = grub_dev[0].strip().split()[0] grub_dev = grub_disk[:-1]+","+gpartnum+")" return grub_dev else: mytxt = "%s: %s. %s! %s (hd0,0)." % ( bold(_("QA")), brown(_("cannot match grub device with a Linux one")), brown(_("Cannot properly configure the kernel")), brown(_("Defaulting to")), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return "(hd0,0)" else: mytxt = "%s: %s. %s! %s (hd0,0)." % ( bold(_("QA")), brown(_("cannot find generated device.map")), brown(_("Cannot properly configure the kernel")), brown(_("Defaulting to")), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return "(hd0,0)" else: mytxt = "%s: %s. %s! %s (hd0,0)." % ( bold(_("QA")), brown(_("cannot run df /boot")), brown(_("Cannot properly configure the kernel")), brown(_("Defaulting to")), ) self.Entropy.updateProgress( mytxt, importance = 0, header = red(" ## ") ) return "(hd0,0)"