Tryag File Manager
Home
-
Turbo Force
Current Path :
/
proc
/
self
/
root
/
usr
/
bin
/
Upload File :
New :
File
Dir
//proc/self/root/usr/bin/package-cleanup
#!/usr/bin/python # # (C) 2005 Gijs Hollestelle, released under the GPL # # 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 Library 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. # # # Note: For yum 2.2.X with X <= 1 and yum 2.3.X with X <= 2 --problems # will report problems with unversioned provides fulfilling versioned # requires import yum import os import sys import rpm import re from rpmUtils import miscutils, transaction from optparse import OptionParser from yum.packages import YumInstalledPackage from yum import Errors from yum.misc import getCacheDir def initYum(opts): my = yum.YumBase() my.doConfigSetup(opts.conffile,init_plugins=False) if opts.orphans: # make it work as non root user. if my.conf.uid != 0: cachedir = getCacheDir() if cachedir is None: my.logger.error("Error: Could not make cachedir, exiting") sys.exit(50) my.repos.setCacheDir(cachedir) # Turn of cache my.conf.cache = 0 my.doRepoSetup() else: # Disable all enabled repositories for repo in my.repos.listEnabled(): my.repos.disableRepo(repo.id) my.doTsSetup() my.doSackSetup() my.doRpmDBSetup() my.localPackages = [] return my def getLocalRequires(my): """Get a list of all requirements in the local rpmdb""" pkgs = {} for po in my.rpmdb.returnPackages(): tup = po.pkgtup header= po.hdr requires = zip( header[rpm.RPMTAG_REQUIRENAME], header[rpm.RPMTAG_REQUIREFLAGS], header[rpm.RPMTAG_REQUIREVERSION], ) pkgs[tup] = requires return pkgs def buildProviderList(my, pkgs, reportProblems): """Resolve all dependencies in pkgs and build a dictionary of packages that provide something for a package other than itself""" errors = False providers = {} # To speed depsolving, don't recheck deps that have # already been checked provsomething = {} for (pkg,reqs) in pkgs.items(): for (req,flags,ver) in reqs: if ver == '': ver = None rflags = flags & 15 if req.startswith('rpmlib'): continue # ignore rpmlib deps if not providers.has_key((req,rflags,ver)): resolve_sack = my.rpmdb.whatProvides(req,rflags,ver) else: resolve_sack = providers[(req,rflags,ver)] if len(resolve_sack) < 1 and reportProblems: if not errors: print "Missing dependencies:" errors = True print "Package %s requires %s" % (pkg[0], miscutils.formatRequire(req,ver,rflags)) else: for rpkg in resolve_sack: # Skip packages that provide something for themselves # as these can still be leaves if rpkg != pkg: provsomething[rpkg] = 1 # Store the resolve_sack so that we can re-use it if another # package has the same requirement providers[(req,rflags,ver)] = resolve_sack if reportProblems: if errors: sys.exit(1) else: print "No problems found" sys.exit(0) return provsomething def findDupes(my): """takes a yum base object prints out a list of package duplicates. These typically happen when an update transaction is left half-completed""" # iterate rpmdb.pkglist # put each package into name.arch dicts with lists as the po # look for any keys with a > 1 length list of pos where the name # of the package is not kernel and/or does not provide a kernel-module pkgdict = {} refined = {} dupes = [] for (n,a,e,v,r) in my.rpmdb.simplePkgList(): if not pkgdict.has_key((n,a)): pkgdict[(n,a)] = [] pkgdict[(n,a)].append((e,v,r)) for (n,a) in pkgdict.keys(): if len(pkgdict[(n,a)]) > 1: refined[(n,a)] = pkgdict[(n,a)] del pkgdict return refined def printDupes(my): """print out the dupe listing""" dupedict = findDupes(my) dupes = [] for (n,a) in dupedict.keys(): for (e,v,r) in dupedict[(n,a)]: po = my.getInstalledPackageObject((n,a,e,v,r)) if po.name.startswith('kernel'): continue if po.name == 'gpg-pubkey': continue dupes.append(po) for pkg in dupes: if pkg.epoch != '0': print '%s:%s-%s-%s.%s' % (pkg.epoch, pkg.name, pkg.ver, pkg.rel, pkg.arch) else: print '%s-%s-%s.%s' % (pkg.name, pkg.ver, pkg.rel, pkg.arch) def cleanOldDupes(my, confirmed): """remove all the older duplicates""" dupedict = findDupes(my) removedupes = [] for (n,a) in dupedict.keys(): if n.startswith('kernel'): continue if n.startswith('gpg-pubkey'): continue (e,v,r) = dupedict[(n,a)][0] lowpo = my.getInstalledPackageObject((n,a,e,v,r)) for (e,v,r) in dupedict[(n,a)][1:]: po = my.getInstalledPackageObject((n,a,e,v,r)) if po.EVR < lowpo.EVR: lowpo = po removedupes.append(lowpo) if len(removedupes) == 0: print "No dupes to clean" sys.exit(0) print "I will remove the following old duplicate packages:" for po in removedupes: print "%s" % po if not confirmed: if not userconfirm(): sys.exit(0) for po in removedupes: my.remove(po) # Now perform the action transaction my.populateTs() my.ts.check() my.ts.order() my.ts.run(progress,'') def _shouldShowLeaf(my, pkg, leaf_regex, exclude_devel, exclude_bin): """ Determine if the given pkg should be displayed as a leaf or not. Return True if the pkg should be shown, False if not. """ if pkg[0] == 'gpg-pubkey': return False pos = my.rpmdb.searchNevra(name=pkg[0], epoch=str(pkg[2]), ver=pkg[3], rel=pkg[4], arch=pkg[1]) # This should give us an exact match assert len(pos) == 1 po = pos[0] name = po.name if exclude_devel and name.endswith('devel'): return False if exclude_bin: for file_name in po.filelist: if file_name.find('bin') != -1: return False if leaf_regex.match(name): return True return False def listLeaves(my, all, leaf_regex, exclude_devel, exclude_bin): """return a packagtuple of any installed packages that are not required by any other package on the system""" ts = transaction.initReadOnlyTransaction() leaves = ts.returnLeafNodes() for pkg in leaves: name=pkg[0] if all or _shouldShowLeaf(my, pkg, leaf_regex, exclude_devel, exclude_bin): print "%s-%s-%s.%s" % (pkg[0],pkg[3],pkg[4],pkg[1]) def listOrphans(my): installed = my.rpmdb.simplePkgList() for pkgtup in installed: (n,a,e,v,r) = pkgtup if n == "gpg-pubkey": continue try: po = my.getPackageObject(pkgtup) except Errors.DepError: print "%s-%s-%s.%s" % (n, v, r, a) def getKernels(my): """return a list of all installed kernels, sorted newest to oldest""" kernlist = [] for po in my.rpmdb.searchProvides(name='kernel'): kernlist.append(po.pkgtup) kernlist.sort(sortPackages) kernlist.reverse() return kernlist # List all kernel devel packages that either belong to kernel versions that # are no longer installed or to kernel version that are in the removelist def getOldKernelDevel(my,kernels,removelist): devellist = [] for po in my.rpmdb.searchProvides(name='kernel-devel'): # For all kernel-devel packages see if there is a matching kernel # in kernels but not in removelist tup = po.pkgtup keep = False for kernel in kernels: if kernel in removelist: continue (kname,karch,kepoch,kver,krel) = kernel (dname,darch,depoch,dver,drel) = tup if (karch,kepoch,kver,krel) == (darch,depoch,dver,drel): keep = True if not keep: devellist.append(tup) return devellist def sortPackages(pkg1,pkg2): """sort pkgtuples by evr""" return miscutils.compareEVR((pkg1[2:]),(pkg2[2:])) def progress(what, bytes, total, h, user): pass #if what == rpm.RPMCALLBACK_UNINST_STOP: # print "Removing: %s" % h def userconfirm(): """gets a yes or no from the user, defaults to No""" while True: choice = raw_input('Is this ok [y/N]: ') choice = choice.lower() if len(choice) == 0 or choice[0] in ['y', 'n']: break if len(choice) == 0 or choice[0] != 'y': return False else: return True def removeKernels(my, count, confirmed, keepdevel): """Remove old kernels, keep at most count kernels (and always keep the running kernel""" count = int(count) if count < 1: print "Error should keep at least 1 kernel!" sys.exit(100) kernels = getKernels(my) runningkernel = os.uname()[2] # Vanilla kernels dont have a release, only a version if '-' in runningkernel: (kver,krel) = runningkernel.split('-') if krel.split('.')[-1] == os.uname()[-1]: krel = ".".join(krel.split('.')[:-1]) else: kver = runningkernel krel = "" # This is roughly what we want, but when there are multiple packages # we want to keep N of each. # remove = kernels[count:] kern_name_map = {} for kern in kernels: kname = kern[0] if kname not in kern_name_map: kern_name_map[kname] = [] kern_name_map[kname].append(kern) remove = [] for kern in kern_name_map.values(): remove.extend(kern[count:]) toremove = [] # Remove running kernel from remove list for kernel in remove: (n,a,e,v,r) = kernel if (v == kver and r == krel): print "Not removing kernel %s-%s because it is the running kernel" % (kver,krel) else: toremove.append(kernel) if len(kernels) == 0: print "No kernels to remove." sys.exit(0) if len(kernels) - len(toremove) < 1: print "Error all kernel rpms are set to be removed" sys.exit(100) # Now extend the list with all kernel-devel pacakges that either # have no matching kernel installed or belong to a kernel that is to # be removed if not keepdevel: toremove.extend(getOldKernelDevel(my,kernels,toremove)) if len(toremove) < 1: print "No kernel related packages to remove" return print "I will remove the following %s kernel related packages:" % len(toremove) for kernel in toremove: (n,a,e,v,r) = kernel print "%s-%s-%s" % (n,v,r) if not confirmed: if not userconfirm(): sys.exit(0) for kernel in toremove: po = my.rpmdb.searchPkgTuple(kernel)[0] my.tsInfo.addErase(po) # Now perform the action transaction my.populateTs() my.ts.check() my.ts.order() my.ts.run(progress,'') # Returns True if exactly one value in the list evaluates to True def exactlyOne(l): return len(filter(None, l)) == 1 # Parse command line options def parseArgs(): parser = OptionParser() parser.add_option("--problems", default=False, dest="problems", action="store_true", help='List dependency problems in the local RPM database') # Leaf listing options parser.add_option("--leaves", default=False, dest="leaves",action="store_true", help='List leaf nodes in the local RPM database') parser.add_option("--all", default=False, dest="all",action="store_true", help='When listing leaf nodes also list leaf nodes that do not match leaf-regex') parser.add_option("--leaf-regex", default="(^(compat-)?lib.+|.*libs?[\d-]*$)", help='A package name that matches this regular expression (case insensitively) is a leaf') parser.add_option("--exclude-devel", default=False, action="store_true", help='When listing leaf nodes do not list development packages') parser.add_option("--exclude-bin", default=False, action="store_true", help='When listing leaf nodes do not list packages with files in bin dirs') parser.add_option("--orphans", default=False, dest="orphans",action="store_true", help='List installed packages which are not available from currenly configured repositories.') parser.add_option("-q", "--quiet", default=False, dest="quiet",action="store_true", help='Print out nothing unecessary') parser.add_option("-y", default=False, dest="confirmed",action="store_true", help='Agree to anything asked') parser.add_option("-d", "--dupes", default=False, dest="dupes", action="store_true", help='Scan for duplicates in your rpmdb') parser.add_option("--cleandupes", default=False, dest="cleandupes", action="store_true", help='Scan for duplicates in your rpmdb and cleans out the older versions') parser.add_option("--oldkernels", default=False, dest="kernels",action="store_true", help="Remove old kernel and kernel-devel packages") parser.add_option("--count",default=2,dest="kernelcount",action="store", help="Number of kernel packages to keep on the system (default 2)") parser.add_option("--keepdevel",default=False,dest="keepdevel",action="store_true", help="Do not remove kernel-devel packages when removing kernels") parser.add_option("-c", dest="conffile", action="store", default='/etc/yum.conf', help="config file location") (opts, args) = parser.parse_args() if not exactlyOne((opts.problems,opts.leaves,opts.kernels,opts.orphans, opts.dupes, opts.cleandupes)): parser.print_help() print "Please specify either --problems, --leaves, --orphans or --oldkernels" sys.exit(0) return (opts, args) def main(): (opts, args) = parseArgs() if not opts.quiet: print "Setting up yum" my = initYum(opts) if (opts.kernels): if os.geteuid() != 0: print "Error: Cannot remove kernels as a user, must be root" sys.exit(1) removeKernels(my, opts.kernelcount, opts.confirmed, opts.keepdevel) sys.exit(0) if (opts.leaves): listLeaves(my, opts.all, re.compile(opts.leaf_regex, re.IGNORECASE), opts.exclude_devel, opts.exclude_bin) sys.exit(0) if (opts.orphans): listOrphans(my) sys.exit(0) if opts.dupes: printDupes(my) sys.exit(0) if opts.cleandupes: if os.geteuid() != 0: print "Error: Cannot remove packages as a user, must be root" sys.exit(1) cleanOldDupes(my, opts.confirmed) sys.exit(0) if not opts.quiet: print "Reading local RPM database" pkgs = getLocalRequires(my) if not opts.quiet: print "Processing all local requires" provsomething = buildProviderList(my,pkgs,opts.problems) if __name__ == '__main__': main()