plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

verifyarena.c (5993B)


      1 #include "stdinc.h"
      2 #include "dat.h"
      3 #include "fns.h"
      4 
      5 static int	verbose;
      6 static int	fd;
      7 static uchar	*data;
      8 static int	blocksize;
      9 static int	sleepms;
     10 static vlong offset0;
     11 
     12 void
     13 usage(void)
     14 {
     15 	fprint(2, "usage: verifyarena [-b blocksize] [-s ms] [-v] [arenapart [name...]]\n");
     16 	threadexitsall(0);
     17 }
     18 
     19 static int
     20 preadblock(uchar *buf, int n, vlong off)
     21 {
     22 	int nr, m;
     23 
     24 	for(nr = 0; nr < n; nr += m){
     25 		m = n - nr;
     26 		m = pread(fd, &buf[nr], m, offset0+off+nr);
     27 		if(m <= 0){
     28 			if(m == 0)
     29 				werrstr("early eof");
     30 			return -1;
     31 		}
     32 	}
     33 	return 0;
     34 }
     35 
     36 static int
     37 readblock(uchar *buf, int n)
     38 {
     39 	int nr, m;
     40 
     41 	for(nr = 0; nr < n; nr += m){
     42 		m = n - nr;
     43 		m = read(fd, &buf[nr], m);
     44 		if(m <= 0){
     45 			if(m == 0)
     46 				werrstr("early eof");
     47 			return -1;
     48 		}
     49 	}
     50 	return 0;
     51 }
     52 
     53 static void
     54 verifyarena(char *name, vlong len)
     55 {
     56 	Arena arena;
     57 	ArenaHead head;
     58 	DigestState s;
     59 	u64int n, e;
     60 	u32int bs;
     61 	u8int score[VtScoreSize];
     62 
     63 	if(verbose)
     64 		fprint(2, "%T verify %s\n", name);
     65 
     66 	memset(&arena, 0, sizeof arena);
     67 	memset(&s, 0, sizeof s);
     68 
     69 	/*
     70 	 * read a little bit, which will include the header
     71 	 */
     72 	if(readblock(data, HeadSize) < 0){
     73 		fprint(2, "%T %s: reading header: %r\n", name);
     74 		return;
     75 	}
     76 	sha1(data, HeadSize, nil, &s);
     77 	if(unpackarenahead(&head, data) < 0){
     78 		fprint(2, "%T %s: corrupt arena header: %r\n", name);
     79 		return;
     80 	}
     81 	if(head.version != ArenaVersion4 && head.version != ArenaVersion5)
     82 		fprint(2, "%T %s: warning: unknown arena version %d\n", name, head.version);
     83 	if(len != 0 && len != head.size)
     84 		fprint(2, "%T %s: warning: unexpected length %lld != %lld\n", name, head.size, len);
     85 	if(strcmp(name, "<stdin>") != 0 && strcmp(head.name, name) != 0)
     86 		fprint(2, "%T %s: warning: unexpected name %s\n", name, head.name);
     87 
     88 	/*
     89 	 * now we know how much to read
     90 	 * read everything but the last block, which is special
     91 	 */
     92 	e = head.size - head.blocksize;
     93 	bs = blocksize;
     94 	for(n = HeadSize; n < e; n += bs){
     95 		if(n + bs > e)
     96 			bs = e - n;
     97 		if(readblock(data, bs) < 0){
     98 			fprint(2, "%T %s: read data: %r\n", name);
     99 			return;
    100 		}
    101 		sha1(data, bs, nil, &s);
    102 		if(sleepms)
    103 			sleep(sleepms);
    104 	}
    105 
    106 	/*
    107 	 * read the last block update the sum.
    108 	 * the sum is calculated assuming the slot for the sum is zero.
    109 	 */
    110 	bs = head.blocksize;
    111 	if(readblock(data, bs) < 0){
    112 		fprint(2, "%T %s: read last block: %r\n", name);
    113 		return;
    114 	}
    115 	sha1(data, bs-VtScoreSize, nil, &s);
    116 	sha1(zeroscore, VtScoreSize, nil, &s);
    117 	sha1(nil, 0, score, &s);
    118 
    119 	/*
    120 	 * validity check on the trailer
    121 	 */
    122 	arena.blocksize = head.blocksize;
    123 	if(unpackarena(&arena, data) < 0){
    124 		fprint(2, "%T %s: corrupt arena trailer: %r\n", name);
    125 		return;
    126 	}
    127 	scorecp(arena.score, &data[arena.blocksize - VtScoreSize]);
    128 
    129 	if(namecmp(arena.name, head.name) != 0){
    130 		fprint(2, "%T %s: wrong name in trailer: %s vs. %s\n",
    131 			name, head.name, arena.name);
    132 		return;
    133 	}
    134 	if(arena.version != head.version){
    135 		fprint(2, "%T %s: wrong version in trailer: %d vs. %d\n",
    136 			name, head.version, arena.version);
    137 		return;
    138 	}
    139 	arena.size = head.size - 2 * head.blocksize;
    140 
    141 	/*
    142 	 * check for no checksum or the same
    143 	 */
    144 	if(scorecmp(score, arena.score) == 0) {
    145 		if(verbose)
    146 			fprint(2, "%T %s: verified score\n", name);
    147 	} else if(scorecmp(zeroscore, arena.score) == 0) {
    148 		if(verbose || arena.diskstats.used > 0)
    149 			fprint(2, "%T %s: unsealed %,lld bytes\n", name, arena.diskstats.used);
    150 	} else{
    151 		fprint(2, "%T %s: mismatch checksum - found=%V calculated=%V\n",
    152 			name, arena.score, score);
    153 		return;
    154 	}
    155 	if(verbose > 1)
    156 		printarena(2, &arena);
    157 }
    158 
    159 static int
    160 shouldcheck(char *name, char **s, int n)
    161 {
    162 	int i;
    163 
    164 	if(n == 0)
    165 		return 1;
    166 
    167 	for(i=0; i<n; i++){
    168 		if(s[i] && strcmp(name, s[i]) == 0){
    169 			s[i] = nil;
    170 			return 1;
    171 		}
    172 	}
    173 	return 0;
    174 }
    175 
    176 void
    177 threadmain(int argc, char *argv[])
    178 {
    179 	int i, nline;
    180 	char *p, *q, *table, *f[10], line[256];
    181 	vlong start, stop;
    182 	ArenaPart ap;
    183 	Part *part;
    184 
    185 	needzeroscore();
    186 	ventifmtinstall();
    187 	blocksize = MaxIoSize;
    188 	ARGBEGIN{
    189 	case 'b':
    190 		blocksize = unittoull(EARGF(usage()));
    191 		break;
    192 	case 's':
    193 		sleepms = atoi(EARGF(usage()));
    194 		break;
    195 	case 'v':
    196 		verbose++;
    197 		break;
    198 	default:
    199 		usage();
    200 		break;
    201 	}ARGEND
    202 
    203 	data = vtmalloc(MaxIo + blocksize);
    204 	if((uintptr)data % MaxIo)
    205 		data += MaxIo - (uintptr)data%MaxIo;
    206 
    207 	if(argc == 0){
    208 		fd = 0;
    209 		verifyarena("<stdin>", 0);
    210 		threadexitsall(nil);
    211 	}
    212 
    213 	if((part = initpart(argv[0], OREAD)) == nil)
    214 		sysfatal("open partition %s: %r", argv[0]);
    215 	fd = part->fd;
    216 	offset0 = part->offset;
    217 
    218 	if(preadblock(data, 8192, PartBlank) < 0)
    219 		sysfatal("read arena part header: %r");
    220 	if(unpackarenapart(&ap, data) < 0)
    221 		sysfatal("corrupted arena part header: %r");
    222 	if(verbose)
    223 		fprint(2, "%T # arena part version=%d blocksize=%d arenabase=%d\n",
    224 			ap.version, ap.blocksize, ap.arenabase);
    225 	ap.tabbase = (PartBlank+HeadSize+ap.blocksize-1)&~(ap.blocksize-1);
    226 	ap.tabsize = ap.arenabase - ap.tabbase;
    227 	table = malloc(ap.tabsize+1);
    228 	if(preadblock((uchar*)table, ap.tabsize, ap.tabbase) < 0)
    229 		sysfatal("reading arena part directory: %r");
    230 	table[ap.tabsize] = 0;
    231 
    232 	nline = atoi(table);
    233 	p = strchr(table, '\n');
    234 	if(p)
    235 		p++;
    236 	for(i=0; i<nline; i++){
    237 		if(p == nil){
    238 			fprint(2, "%T warning: unexpected arena table end\n");
    239 			break;
    240 		}
    241 		q = strchr(p, '\n');
    242 		if(q)
    243 			*q++ = 0;
    244 		if(strlen(p) >= sizeof line){
    245 			fprint(2, "%T warning: long arena table line: %s\n", p);
    246 			p = q;
    247 			continue;
    248 		}
    249 		strcpy(line, p);
    250 		memset(f, 0, sizeof f);
    251 		if(tokenize(line, f, nelem(f)) < 3){
    252 			fprint(2, "%T warning: bad arena table line: %s\n", p);
    253 			p = q;
    254 			continue;
    255 		}
    256 		p = q;
    257 		if(shouldcheck(f[0], argv+1, argc-1)){
    258 			start = strtoull(f[1], 0, 0);
    259 			stop = strtoull(f[2], 0, 0);
    260 			if(stop <= start){
    261 				fprint(2, "%T %s: bad start,stop %lld,%lld\n", f[0], stop, start);
    262 				continue;
    263 			}
    264 			if(seek(fd, offset0+start, 0) < 0)
    265 				fprint(2, "%T %s: seek to start: %r\n", f[0]);
    266 			verifyarena(f[0], stop - start);
    267 		}
    268 	}
    269 	for(i=1; i<argc; i++)
    270 		if(argv[i] != 0)
    271 			fprint(2, "%T %s: did not find arena\n", argv[i]);
    272 
    273 	threadexitsall(nil);
    274 }