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 }