URI:
       treseal.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       treseal.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 }