plan9port

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

reseal.c (6512B)


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