xref: /plan9/sys/src/cmd/venti/srv/verifyarena.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1368c31abSDavid du Colombier #include "stdinc.h"
2368c31abSDavid du Colombier #include "dat.h"
3368c31abSDavid du Colombier #include "fns.h"
4368c31abSDavid du Colombier 
5368c31abSDavid du Colombier static int	verbose;
6368c31abSDavid du Colombier static int	fd;
7368c31abSDavid du Colombier static uchar	*data;
8368c31abSDavid du Colombier static int	blocksize;
9368c31abSDavid du Colombier static int	sleepms;
10*f9e1cf08SDavid du Colombier static vlong offset0;
11368c31abSDavid du Colombier 
12368c31abSDavid du Colombier void
usage(void)13368c31abSDavid du Colombier usage(void)
14368c31abSDavid du Colombier {
15368c31abSDavid du Colombier 	fprint(2, "usage: verifyarena [-b blocksize] [-s ms] [-v] [arenapart [name...]]\n");
16368c31abSDavid du Colombier 	threadexitsall(0);
17368c31abSDavid du Colombier }
18368c31abSDavid du Colombier 
19368c31abSDavid du Colombier static int
preadblock(uchar * buf,int n,vlong off)20368c31abSDavid du Colombier preadblock(uchar *buf, int n, vlong off)
21368c31abSDavid du Colombier {
22368c31abSDavid du Colombier 	int nr, m;
23368c31abSDavid du Colombier 
24368c31abSDavid du Colombier 	for(nr = 0; nr < n; nr += m){
25368c31abSDavid du Colombier 		m = n - nr;
26*f9e1cf08SDavid du Colombier 		m = pread(fd, &buf[nr], m, offset0+off+nr);
27368c31abSDavid du Colombier 		if(m <= 0){
28368c31abSDavid du Colombier 			if(m == 0)
29368c31abSDavid du Colombier 				werrstr("early eof");
30368c31abSDavid du Colombier 			return -1;
31368c31abSDavid du Colombier 		}
32368c31abSDavid du Colombier 	}
33368c31abSDavid du Colombier 	return 0;
34368c31abSDavid du Colombier }
35368c31abSDavid du Colombier 
36368c31abSDavid du Colombier static int
readblock(uchar * buf,int n)37368c31abSDavid du Colombier readblock(uchar *buf, int n)
38368c31abSDavid du Colombier {
39368c31abSDavid du Colombier 	int nr, m;
40368c31abSDavid du Colombier 
41368c31abSDavid du Colombier 	for(nr = 0; nr < n; nr += m){
42368c31abSDavid du Colombier 		m = n - nr;
43368c31abSDavid du Colombier 		m = read(fd, &buf[nr], m);
44368c31abSDavid du Colombier 		if(m <= 0){
45368c31abSDavid du Colombier 			if(m == 0)
46368c31abSDavid du Colombier 				werrstr("early eof");
47368c31abSDavid du Colombier 			return -1;
48368c31abSDavid du Colombier 		}
49368c31abSDavid du Colombier 	}
50368c31abSDavid du Colombier 	return 0;
51368c31abSDavid du Colombier }
52368c31abSDavid du Colombier 
53368c31abSDavid du Colombier static void
verifyarena(char * name,vlong len)54368c31abSDavid du Colombier verifyarena(char *name, vlong len)
55368c31abSDavid du Colombier {
56368c31abSDavid du Colombier 	Arena arena;
57368c31abSDavid du Colombier 	ArenaHead head;
58368c31abSDavid du Colombier 	DigestState s;
59368c31abSDavid du Colombier 	u64int n, e;
60368c31abSDavid du Colombier 	u32int bs;
61368c31abSDavid du Colombier 	u8int score[VtScoreSize];
62368c31abSDavid du Colombier 
63368c31abSDavid du Colombier 	fprint(2, "%T verify %s\n", name);
64368c31abSDavid du Colombier 
65368c31abSDavid du Colombier 	memset(&arena, 0, sizeof arena);
66368c31abSDavid du Colombier 	memset(&s, 0, sizeof s);
67368c31abSDavid du Colombier 
68368c31abSDavid du Colombier 	/*
69368c31abSDavid du Colombier 	 * read a little bit, which will include the header
70368c31abSDavid du Colombier 	 */
71368c31abSDavid du Colombier 	if(readblock(data, HeadSize) < 0){
72368c31abSDavid du Colombier 		fprint(2, "%T %s: reading header: %r\n", name);
73368c31abSDavid du Colombier 		return;
74368c31abSDavid du Colombier 	}
75368c31abSDavid du Colombier 	sha1(data, HeadSize, nil, &s);
76368c31abSDavid du Colombier 	if(unpackarenahead(&head, data) < 0){
77368c31abSDavid du Colombier 		fprint(2, "%T %s: corrupt arena header: %r\n", name);
78368c31abSDavid du Colombier 		return;
79368c31abSDavid du Colombier 	}
80368c31abSDavid du Colombier 	if(head.version != ArenaVersion4 && head.version != ArenaVersion5)
81368c31abSDavid du Colombier 		fprint(2, "%T %s: warning: unknown arena version %d\n", name, head.version);
82368c31abSDavid du Colombier 	if(len != 0 && len != head.size)
83368c31abSDavid du Colombier 		fprint(2, "%T %s: warning: unexpected length %lld != %lld\n", name, head.size, len);
84368c31abSDavid du Colombier 	if(strcmp(name, "<stdin>") != 0 && strcmp(head.name, name) != 0)
85368c31abSDavid du Colombier 		fprint(2, "%T %s: warning: unexpected name %s\n", name, head.name);
86368c31abSDavid du Colombier 
87368c31abSDavid du Colombier 	/*
88368c31abSDavid du Colombier 	 * now we know how much to read
89368c31abSDavid du Colombier 	 * read everything but the last block, which is special
90368c31abSDavid du Colombier 	 */
91368c31abSDavid du Colombier 	e = head.size - head.blocksize;
92368c31abSDavid du Colombier 	bs = blocksize;
93368c31abSDavid du Colombier 	for(n = HeadSize; n < e; n += bs){
94368c31abSDavid du Colombier 		if(n + bs > e)
95368c31abSDavid du Colombier 			bs = e - n;
96368c31abSDavid du Colombier 		if(readblock(data, bs) < 0){
97368c31abSDavid du Colombier 			fprint(2, "%T %s: read data: %r\n", name);
98368c31abSDavid du Colombier 			return;
99368c31abSDavid du Colombier 		}
100368c31abSDavid du Colombier 		sha1(data, bs, nil, &s);
101368c31abSDavid du Colombier 		if(sleepms)
102368c31abSDavid du Colombier 			sleep(sleepms);
103368c31abSDavid du Colombier 	}
104368c31abSDavid du Colombier 
105368c31abSDavid du Colombier 	/*
106368c31abSDavid du Colombier 	 * read the last block update the sum.
107368c31abSDavid du Colombier 	 * the sum is calculated assuming the slot for the sum is zero.
108368c31abSDavid du Colombier 	 */
109368c31abSDavid du Colombier 	bs = head.blocksize;
110368c31abSDavid du Colombier 	if(readblock(data, bs) < 0){
111368c31abSDavid du Colombier 		fprint(2, "%T %s: read last block: %r\n", name);
112368c31abSDavid du Colombier 		return;
113368c31abSDavid du Colombier 	}
114368c31abSDavid du Colombier 	sha1(data, bs-VtScoreSize, nil, &s);
115368c31abSDavid du Colombier 	sha1(zeroscore, VtScoreSize, nil, &s);
116368c31abSDavid du Colombier 	sha1(nil, 0, score, &s);
117368c31abSDavid du Colombier 
118368c31abSDavid du Colombier 	/*
119368c31abSDavid du Colombier 	 * validity check on the trailer
120368c31abSDavid du Colombier 	 */
121368c31abSDavid du Colombier 	arena.blocksize = head.blocksize;
122368c31abSDavid du Colombier 	if(unpackarena(&arena, data) < 0){
123368c31abSDavid du Colombier 		fprint(2, "%T %s: corrupt arena trailer: %r\n", name);
124368c31abSDavid du Colombier 		return;
125368c31abSDavid du Colombier 	}
126368c31abSDavid du Colombier 	scorecp(arena.score, &data[arena.blocksize - VtScoreSize]);
127368c31abSDavid du Colombier 
128368c31abSDavid du Colombier 	if(namecmp(arena.name, head.name) != 0){
129368c31abSDavid du Colombier 		fprint(2, "%T %s: wrong name in trailer: %s vs. %s\n",
130368c31abSDavid du Colombier 			name, head.name, arena.name);
131368c31abSDavid du Colombier 		return;
132368c31abSDavid du Colombier 	}
133368c31abSDavid du Colombier 	if(arena.version != head.version){
134368c31abSDavid du Colombier 		fprint(2, "%T %s: wrong version in trailer: %d vs. %d\n",
135368c31abSDavid du Colombier 			name, head.version, arena.version);
136368c31abSDavid du Colombier 		return;
137368c31abSDavid du Colombier 	}
138368c31abSDavid du Colombier 	arena.size = head.size - 2 * head.blocksize;
139368c31abSDavid du Colombier 
140368c31abSDavid du Colombier 	/*
141368c31abSDavid du Colombier 	 * check for no checksum or the same
142368c31abSDavid du Colombier 	 */
143368c31abSDavid du Colombier 	if(scorecmp(score, arena.score) == 0)
144368c31abSDavid du Colombier 		fprint(2, "%T %s: verified score\n", name);
145368c31abSDavid du Colombier 	else if(scorecmp(zeroscore, arena.score) == 0)
146368c31abSDavid du Colombier 		fprint(2, "%T %s: unsealed\n", name);
147368c31abSDavid du Colombier 	else{
148368c31abSDavid du Colombier 		fprint(2, "%T %s: mismatch checksum - found=%V calculated=%V\n",
149368c31abSDavid du Colombier 			name, arena.score, score);
150368c31abSDavid du Colombier 		return;
151368c31abSDavid du Colombier 	}
152368c31abSDavid du Colombier 	printarena(2, &arena);
153368c31abSDavid du Colombier }
154368c31abSDavid du Colombier 
155368c31abSDavid du Colombier static int
shouldcheck(char * name,char ** s,int n)156368c31abSDavid du Colombier shouldcheck(char *name, char **s, int n)
157368c31abSDavid du Colombier {
158368c31abSDavid du Colombier 	int i;
159368c31abSDavid du Colombier 
160368c31abSDavid du Colombier 	if(n == 0)
161368c31abSDavid du Colombier 		return 1;
162368c31abSDavid du Colombier 
163368c31abSDavid du Colombier 	for(i=0; i<n; i++){
164368c31abSDavid du Colombier 		if(s[i] && strcmp(name, s[i]) == 0){
165368c31abSDavid du Colombier 			s[i] = nil;
166368c31abSDavid du Colombier 			return 1;
167368c31abSDavid du Colombier 		}
168368c31abSDavid du Colombier 	}
169368c31abSDavid du Colombier 	return 0;
170368c31abSDavid du Colombier }
171368c31abSDavid du Colombier 
172368c31abSDavid du Colombier void
threadmain(int argc,char * argv[])173368c31abSDavid du Colombier threadmain(int argc, char *argv[])
174368c31abSDavid du Colombier {
175368c31abSDavid du Colombier 	int i, nline;
176368c31abSDavid du Colombier 	char *p, *q, *table, *f[10], line[256];
177368c31abSDavid du Colombier 	vlong start, stop;
178368c31abSDavid du Colombier 	ArenaPart ap;
179*f9e1cf08SDavid du Colombier 	Part *part;
180368c31abSDavid du Colombier 
181368c31abSDavid du Colombier 	needzeroscore();
182368c31abSDavid du Colombier 	ventifmtinstall();
183368c31abSDavid du Colombier 	blocksize = MaxIoSize;
184368c31abSDavid du Colombier 	ARGBEGIN{
185368c31abSDavid du Colombier 	case 'b':
186368c31abSDavid du Colombier 		blocksize = unittoull(EARGF(usage()));
187368c31abSDavid du Colombier 		break;
188368c31abSDavid du Colombier 	case 's':
189368c31abSDavid du Colombier 		sleepms = atoi(EARGF(usage()));
190368c31abSDavid du Colombier 		break;
191368c31abSDavid du Colombier 	case 'v':
192368c31abSDavid du Colombier 		verbose++;
193368c31abSDavid du Colombier 		break;
194368c31abSDavid du Colombier 	default:
195368c31abSDavid du Colombier 		usage();
196368c31abSDavid du Colombier 		break;
197368c31abSDavid du Colombier 	}ARGEND
198368c31abSDavid du Colombier 
199368c31abSDavid du Colombier 	data = vtmalloc(blocksize);
200368c31abSDavid du Colombier 	if(argc == 0){
201368c31abSDavid du Colombier 		fd = 0;
202368c31abSDavid du Colombier 		verifyarena("<stdin>", 0);
203368c31abSDavid du Colombier 		threadexitsall(nil);
204368c31abSDavid du Colombier 	}
205368c31abSDavid du Colombier 
206*f9e1cf08SDavid du Colombier 	if((part = initpart(argv[0], OREAD)) == nil)
207*f9e1cf08SDavid du Colombier 		sysfatal("open partition %s: %r", argv[0]);
208*f9e1cf08SDavid du Colombier 	fd = part->fd;
209*f9e1cf08SDavid du Colombier 	offset0 = part->offset;
210368c31abSDavid du Colombier 
211368c31abSDavid du Colombier 	if(preadblock(data, 8192, PartBlank) < 0)
212368c31abSDavid du Colombier 		sysfatal("read arena part header: %r");
213368c31abSDavid du Colombier 	if(unpackarenapart(&ap, data) < 0)
214368c31abSDavid du Colombier 		sysfatal("corrupted arena part header: %r");
215368c31abSDavid du Colombier 	fprint(2, "%T # arena part version=%d blocksize=%d arenabase=%d\n",
216368c31abSDavid du Colombier 		ap.version, ap.blocksize, ap.arenabase);
217368c31abSDavid du Colombier 	ap.tabbase = (PartBlank+HeadSize+ap.blocksize-1)&~(ap.blocksize-1);
218368c31abSDavid du Colombier 	ap.tabsize = ap.arenabase - ap.tabbase;
219368c31abSDavid du Colombier 	table = malloc(ap.tabsize+1);
220368c31abSDavid du Colombier 	if(preadblock((uchar*)table, ap.tabsize, ap.tabbase) < 0)
221368c31abSDavid du Colombier 		sysfatal("reading arena part directory: %r");
222368c31abSDavid du Colombier 	table[ap.tabsize] = 0;
223368c31abSDavid du Colombier 
224368c31abSDavid du Colombier 	nline = atoi(table);
225368c31abSDavid du Colombier 	p = strchr(table, '\n');
226368c31abSDavid du Colombier 	if(p)
227368c31abSDavid du Colombier 		p++;
228368c31abSDavid du Colombier 	for(i=0; i<nline; i++){
229368c31abSDavid du Colombier 		if(p == nil){
230368c31abSDavid du Colombier 			fprint(2, "%T warning: unexpected arena table end\n");
231368c31abSDavid du Colombier 			break;
232368c31abSDavid du Colombier 		}
233368c31abSDavid du Colombier 		q = strchr(p, '\n');
234368c31abSDavid du Colombier 		if(q)
235368c31abSDavid du Colombier 			*q++ = 0;
236368c31abSDavid du Colombier 		if(strlen(p) >= sizeof line){
237368c31abSDavid du Colombier 			fprint(2, "%T warning: long arena table line: %s\n", p);
238368c31abSDavid du Colombier 			p = q;
239368c31abSDavid du Colombier 			continue;
240368c31abSDavid du Colombier 		}
241368c31abSDavid du Colombier 		strcpy(line, p);
242368c31abSDavid du Colombier 		memset(f, 0, sizeof f);
243368c31abSDavid du Colombier 		if(tokenize(line, f, nelem(f)) < 3){
244368c31abSDavid du Colombier 			fprint(2, "%T warning: bad arena table line: %s\n", p);
245368c31abSDavid du Colombier 			p = q;
246368c31abSDavid du Colombier 			continue;
247368c31abSDavid du Colombier 		}
248368c31abSDavid du Colombier 		p = q;
249368c31abSDavid du Colombier 		if(shouldcheck(f[0], argv+1, argc-1)){
250368c31abSDavid du Colombier 			start = strtoull(f[1], 0, 0);
251368c31abSDavid du Colombier 			stop = strtoull(f[2], 0, 0);
252368c31abSDavid du Colombier 			if(stop <= start){
253368c31abSDavid du Colombier 				fprint(2, "%T %s: bad start,stop %lld,%lld\n", f[0], stop, start);
254368c31abSDavid du Colombier 				continue;
255368c31abSDavid du Colombier 			}
256*f9e1cf08SDavid du Colombier 			if(seek(fd, offset0+start, 0) < 0)
257368c31abSDavid du Colombier 				fprint(2, "%T %s: seek to start: %r\n", f[0]);
258368c31abSDavid du Colombier 			verifyarena(f[0], stop - start);
259368c31abSDavid du Colombier 		}
260368c31abSDavid du Colombier 	}
261368c31abSDavid du Colombier 	for(i=1; i<argc; i++)
262368c31abSDavid du Colombier 		if(argv[i] != 0)
263368c31abSDavid du Colombier 			fprint(2, "%T %s: did not find arena\n", argv[i]);
264368c31abSDavid du Colombier 
265368c31abSDavid du Colombier 	threadexitsall(nil);
266368c31abSDavid du Colombier }
267