| #!/usr/bin/python |
| # Copyright 1999-2006 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| # $Id$ |
| |
| import os,sys,re |
| sys.path = ["/usr/lib/portage/pym"]+sys.path |
| |
| from stat import * |
| from output import * |
| from portage import lockfile,unlockfile,VDB_PATH,root |
| |
| |
| mylog = open("/var/log/emerge_fix-db.log", "a") |
| def writemsg(msg): |
| if msg[-1] != '\n': |
| msg += "\n" |
| sys.stderr.write(msg) |
| sys.stderr.flush() |
| mylog.write(msg) |
| mylog.flush() |
| |
| def fix_global_counter(value): |
| myf = open("/var/cache/edb/counter") |
| newvalue = value+1000 |
| myf.write(str(newvalue)) |
| myf.flush() |
| myf.close() |
| return newvalue |
| |
| bad = {} |
| counters = {} |
| times = {} |
| |
| try: |
| real_counter = long(open("/var/cache/edb/counter").read()) |
| except SystemExit, e: |
| raise # This needs to be propogated |
| except: |
| writemsg("ERROR: Real counter is invalid.\n") |
| real_counter = 0 |
| |
| vardbdir = root+VDB_PATH+"/" |
| for cat in os.listdir(vardbdir): |
| catdir = vardbdir+cat+"/" |
| if not os.path.isdir(catdir): |
| writemsg("Invalid file: '%s'\n" % catdir[:-1]) |
| continue |
| for pkg in os.listdir(catdir): |
| pkgdir = catdir+pkg+"/" |
| catpkg = cat+"/"+pkg |
| |
| if not os.path.isdir(catdir): |
| writemsg("Invalid file: '%s'\n" % pkgdir) |
| continue |
| |
| bad[catpkg] = [] |
| |
| pkgdirlist = os.listdir(pkgdir) |
| if not pkgdirlist: |
| writemsg("ERROR: Package directory is empty for '%s'\n" % catpkg) |
| writemsg(" Deleting this directory. Remerge if you want it back.\n") |
| os.rmdir(pkgdir) |
| del bad[catpkg] |
| continue |
| |
| if "CONTENTS" not in pkgdirlist: |
| bad[catpkg] += ["CONTENTS is missing"] |
| times[catpkg] = -1 |
| writemsg("ERROR: Contents file is missing from the package directory.\n") |
| writemsg(" '%s' is corrupt and should be deleted.\n" % catpkg) |
| else: |
| times[catpkg] = None |
| for line in open(pkgdir+"CONTENTS").readlines(): |
| mysplit = line.split() |
| if mysplit[0] == "obj": |
| try: |
| times[catpkg] = long(mysplit[-1]) |
| except SystemExit, e: |
| raise # This needs to be propogated |
| except: |
| times[catpkg] = -1 |
| bad[catpkg] += ["CONTENTS is corrupt"] |
| writemsg("ERROR: Corrupt CONTENTS file in '%s'\n" % catpkg) |
| writemsg(" This package should be deleted.\n") |
| break |
| if times[catpkg] == None: |
| times[catpkg] = os.stat(pkgdir+"CONTENTS")[ST_MTIME] |
| |
| if "COUNTER" not in pkgdirlist: |
| bad[catpkg] += ["COUNTER is missing"] |
| writemsg("ERROR: COUNTER file missing from '%s'.\n" % catpkg) |
| counters[catpkg] = -1 |
| else: |
| try: |
| counters[catpkg] = long(open(pkgdir+"COUNTER").read().strip()) |
| if counters[catpkg] > real_counter: |
| writemsg("ERROR: Global counter is lower than the '%s' COUNTER." % catpkg) |
| real_counter = fix_global_counter(counters[catpkg]) |
| except SystemExit, e: |
| raise # This needs to be propogated |
| except: |
| bad[catpkg] += ["COUNTER is corrupt"] |
| counters[catpkg] = -1 |
| |
| if "SLOT" not in pkgdirlist: |
| writemsg("ERROR: SLOT file missing from '%s'.\n" % catpkg) |
| writemsg(" RE-MERGE this exact package version or unmerge and remerge.\n") |
| bad[catpkg] += ["SLOT is missing"] |
| else: |
| myslot = open(pkgdir+"SLOT").read() |
| if myslot and myslot[-1]=="\n": |
| #writemsg("WARN: SLOT file has a newline. '%s'\n" % catpkg) |
| myslot = myslot[:-1] |
| if not myslot: |
| bad[catpkg] += ["SLOT is empty"] |
| writemsg("ERROR: SLOT file is empty for '%s'.\n" % catpkg) |
| writemsg(" RE-MERGE this exact package version or unmerge and remerge it.\n") |
| elif re.search("[^-a-zA-Z0-9\._]", myslot): |
| bad[catpkg] += ["SLOT is corrupt"] |
| writemsg("ERROR: SLOT file is corrupt for '%s'.\n" % catpkg) |
| writemsg(" RE-MERGE this exact package version or unmerge and remerge it.\n") |
| elif myslot.strip() != myslot: |
| writemsg("WARN: SLOT file has invalid characters. '%s'\n" % catpkg) |
| bad[catpkg] += ["SLOT is invalid"] |
| |
| if not bad[catpkg]: |
| del bad[catpkg] |
| |
| |
| actions = {} |
| writemsg("\n\n") |
| for catpkg in bad.keys(): |
| bad[catpkg].sort() |
| |
| mystr = "" |
| for x in bad[catpkg]: |
| mystr += " "+str(x)+"\n" |
| |
| if bad[catpkg] == ["CONTENTS is missing", "SLOT is missing"]: |
| writemsg("%s: (possibly injected)\n%s\n" % (green(catpkg), mystr)) |
| actions[catpkg] = ["ignore"] |
| elif bad[catpkg] == ["SLOT is empty"]: |
| writemsg("%s: (old package) []\n%s\n" % (yellow(catpkg), mystr)) |
| actions[catpkg] = ["remerge"] |
| else: |
| writemsg("%s: (damaged/invalid) []\n%s\n" % (red(catpkg), mystr)) |
| actions[catpkg] = ["merge exact"] |
| |
| if (len(sys.argv) > 1) and (sys.argv[1] == "--fix"): |
| writemsg("These are only directions, at the moment.") |
| for catpkg in actions.keys(): |
| action = actions[catpkg] |
| writemsg("We will now '%s' '%s'..." % (action, catpkg)) |
| #if action == |
| else: |
| #writemsg("Run with '--fix' to attempt automatic correction.") |
| pass |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |