summaryrefslogtreecommitdiffstats
path: root/bin/fix-db.py
blob: 301ec80025e564edbb8bb076440bc66f3a1d4618 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#!/usr/bin/python
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id$

import os,sys,re

try:
	import portage
except ImportError:
	from os import path as osp
	sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
	import portage

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:
	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:
		action = actions[catpkg]
		writemsg("We will now '%s' '%s'..." % (action, catpkg))
		#if action == 
else:
	#writemsg("Run with '--fix' to attempt automatic correction.")
	pass