Migration (without history) of the current stable line to subversion.
[portage.git] / bin / fix-db.py
1 #!/usr/bin/python
2 # Copyright 1999-2004 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4 # $Header: /var/cvsroot/gentoo-src/portage/bin/fix-db.py,v 1.8 2004/10/11 04:01:00 jstubbs Exp $
5
6 import os,sys,re
7 sys.path = ["/usr/lib/portage/pym"]+sys.path
8
9 from stat import *
10 from output import *
11 from portage import lockfile,unlockfile,VDB_PATH,root
12
13
14 mylog = open("/var/log/emerge_fix-db.log", "a")
15 def writemsg(msg):
16         if msg[-1] != '\n':
17                 msg += "\n"
18         sys.stderr.write(msg)
19         sys.stderr.flush()
20         mylog.write(msg)
21         mylog.flush()
22
23 def fix_global_counter(value):
24         myf = open("/var/cache/edb/counter")
25         newvalue = value+1000
26         myf.write(str(newvalue))
27         myf.flush()
28         myf.close()
29         return newvalue
30
31 bad = {}
32 counters = {}
33 times = {}
34
35 try:
36         real_counter = long(open("/var/cache/edb/counter").read())
37 except SystemExit, e:
38         raise  # This needs to be propogated
39 except:
40         writemsg("ERROR: Real counter is invalid.\n")
41         real_counter = 0
42
43 vardbdir = root+VDB_PATH+"/"
44 for cat in os.listdir(vardbdir):
45         catdir = vardbdir+cat+"/"
46         if not os.path.isdir(catdir):
47                 writemsg("Invalid file: '%s'\n" % catdir[:-1])
48                 continue
49         for pkg in os.listdir(catdir):
50                 pkgdir = catdir+pkg+"/"
51                 catpkg = cat+"/"+pkg
52
53                 if not os.path.isdir(catdir):
54                         writemsg("Invalid file: '%s'\n" % pkgdir)
55                         continue
56                         
57                 bad[catpkg] = []
58                 
59                 pkgdirlist = os.listdir(pkgdir)
60                 if not pkgdirlist:
61                         writemsg("ERROR: Package directory is empty for '%s'\n" % catpkg)
62                         writemsg("       Deleting this directory. Remerge if you want it back.\n")
63                         os.rmdir(pkgdir)
64                         del bad[catpkg]
65                         continue
66                 
67                 if "CONTENTS" not in pkgdirlist:
68                         bad[catpkg] += ["CONTENTS is missing"]
69                         times[catpkg] = -1
70                         writemsg("ERROR: Contents file is missing from the package directory.\n")
71                         writemsg("       '%s' is corrupt and should be deleted.\n" % catpkg)
72                 else:
73                         times[catpkg] = None
74                         for line in open(pkgdir+"CONTENTS").readlines():
75                                 mysplit = line.split()
76                                 if mysplit[0] == "obj":
77                                         try:
78                                                 times[catpkg] = long(mysplit[-1])
79                                         except SystemExit, e:
80                                                 raise  # This needs to be propogated
81                                         except:
82                                                 times[catpkg] = -1
83                                                 bad[catpkg] += ["CONTENTS is corrupt"]
84                                                 writemsg("ERROR: Corrupt CONTENTS file in '%s'\n" % catpkg)
85                                                 writemsg("       This package should be deleted.\n")
86                                         break
87                         if times[catpkg] == None:
88                                 times[catpkg] = os.stat(pkgdir+"CONTENTS")[ST_MTIME]
89
90                 if "COUNTER" not in pkgdirlist:
91                         bad[catpkg] += ["COUNTER is missing"]
92                         writemsg("ERROR: COUNTER file missing from '%s'.\n" % catpkg)
93                         counters[catpkg] = -1
94                 else:
95                         try:
96                                 counters[catpkg] = long(open(pkgdir+"COUNTER").read().strip())
97                                 if counters[catpkg] > real_counter:
98                                         writemsg("ERROR: Global counter is lower than the '%s' COUNTER." % catpkg)
99                                         real_counter = fix_global_counter(counters[catpkg])
100                         except SystemExit, e:
101                                 raise  # This needs to be propogated
102                         except:
103                                 bad[catpkg] += ["COUNTER is corrupt"]
104                                 counters[catpkg] = -1
105
106                 if "SLOT" not in pkgdirlist:
107                         writemsg("ERROR: SLOT file missing from '%s'.\n" % catpkg)
108                         writemsg("       RE-MERGE this exact package version or unmerge and remerge.\n")
109                         bad[catpkg] += ["SLOT is missing"]
110                 else:
111                         myslot = open(pkgdir+"SLOT").read()
112                         if myslot and myslot[-1]=="\n":
113                                 #writemsg("WARN: SLOT file has a newline. '%s'\n" % catpkg)
114                                 myslot = myslot[:-1]
115                         if not myslot:
116                                 bad[catpkg] += ["SLOT is empty"]
117                                 writemsg("ERROR: SLOT file is empty for '%s'.\n" % catpkg)
118                                 writemsg("       RE-MERGE this exact package version or unmerge and remerge it.\n")
119                         elif re.search("[^-a-zA-Z0-9\._]", myslot):
120                                 bad[catpkg] += ["SLOT is corrupt"]
121                                 writemsg("ERROR: SLOT file is corrupt for '%s'.\n" % catpkg)
122                                 writemsg("       RE-MERGE this exact package version or unmerge and remerge it.\n")
123                         elif myslot.strip() != myslot:
124                                 writemsg("WARN: SLOT file has invalid characters. '%s'\n" % catpkg)
125                                 bad[catpkg] += ["SLOT is invalid"]
126
127                 if not bad[catpkg]:
128                         del bad[catpkg]
129
130
131 actions = {}
132 writemsg("\n\n")
133 for catpkg in bad.keys():
134         bad[catpkg].sort()
135
136         mystr = ""
137         for x in bad[catpkg]:
138                 mystr += "   "+str(x)+"\n"
139
140         if bad[catpkg] == ["CONTENTS is missing", "SLOT is missing"]:
141                 writemsg("%s: (possibly injected)\n%s\n" % (green(catpkg), mystr))
142                 actions[catpkg] = ["ignore"]
143         elif bad[catpkg] == ["SLOT is empty"]:
144                 writemsg("%s: (old package) []\n%s\n" % (yellow(catpkg), mystr))
145                 actions[catpkg] = ["remerge"]
146         else:
147                 writemsg("%s: (damaged/invalid) []\n%s\n" % (red(catpkg), mystr))
148                 actions[catpkg] = ["merge exact"]
149
150 if (len(sys.argv) > 1) and (sys.argv[1] == "--fix"):
151         writemsg("These are only directions, at the moment.")
152         for catpkg in actions.keys():
153                 action = actions[catpkg]
154                 writemsg("We will now '%s' '%s'..." % (action, catpkg))
155                 #if action == 
156 else:
157         #writemsg("Run with '--fix' to attempt automatic correction.")
158         pass
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175