verifyarena.c 5.6 KB

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