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