|
|
1.1 root 1: /*
2: * Icheck - check i-list consistency of
3: * filesystems and (optionally) repair
4: * filesystems.
5: */
6: #include <stdio.h>
7: extern char *calloc();
8: #include <sys/filsys.h>
9: #include <sys/fblk.h>
10: #include <sys/dir.h>
11: #include <sys/ino.h>
12: #include "check.h"
13: #include <canon.h>
14: #undef DIR
15:
16: #define ROOTINO 2 /* I-number of root */
17: #define NBLOCK 20 /* Maximum number of blocks to check */
18: #define NBPC 8 /* Bits per character */
19: #define BOOTB 0 /* Boot block # */
20: #define SUPERB 1 /* Super block */
21: #define INOORG 2 /* Inodes begin here */
22: #define IBLK 12 /* I-node read blocking factor */
23: #define BSIZE 512
24: #define ND 10 /* Number of direct block */
25: #undef NI
26: #define NI 1
27: #define NII 1
28: #define NIII 1
29: #undef NADDR
30: #define NADDR (ND+NI+NII+NIII)
31:
32: /*
33: * Flags for crawldown.
34: */
35: #define PLAIN 0
36: #define DIR 1
37: #define BAD 2
38:
39: /*
40: * A chain of these structures
41: * holds all of the defective blocks found
42: * in the bad block file. The list is sorted for
43: * easy access by those parts of the program
44: * that scan blocks.
45: */
46: struct defect
47: {
48: struct defect *d_next; /* Link to next */
49: daddr_t d_start; /* First bad block in cluster */
50: int d_length; /* Size of cluster */
51: };
52:
53: #define test(bn) (bitmap[((unsigned)bn)/NBPC] & 1<<(((unsigned)bn)%NBPC))
54: #define mark(bn) (bitmap[((unsigned)bn)/NBPC] |= 1<<(((unsigned)bn)%NBPC))
55:
56: char tmb[] = "Too many block numbers specified\n";
57:
58: int nblock;
59: daddr_t blocks[NBLOCK];
60: ino_t freei[NICFREE]; /* Free i-nodes to put into superblock */
61: ino_t *freeip;
62: struct defect *deflist;
63: char superb[BSIZE];
64: char ibuf[IBLK*BSIZE];
65: char fbuf[BSIZE];
66: char idbuf[3][BSIZE]; /* One for each indirect level */
67:
68: /*
69: * Offsets of levels of indirection
70: * into the i-node addresses.
71: */
72: char offsets[] = {
73: 0, ND, ND+NI, ND+NI+NII, ND+NI+NII+NIII,
74: };
75:
76: /*
77: * Types of indirect and direct blocks
78: * by name.
79: */
80: char *btypes[] = {
81: "direct",
82: "indirect",
83: "double indirect",
84: "triple indirect",
85: };
86:
87: int sflag; /* Repair filesystem */
88: int vflag; /* More verbose information */
89: int exstat; /* Final exit status -- bits from <check.h> */
90: FILE *fs; /* File system i/o stream pointer */
91: char *bitmap; /* Bit map for blocks */
92: daddr_t fsize = SUPERB+1; /* Allow read of super-block */
93: unsigned isize;
94:
95: /* Various counters */
96: unsigned nfiles;
97: unsigned nreg;
98: unsigned ndir;
99: unsigned nbad; /* # of bad blocks */
100: unsigned nibad; /* # of bad blocks that were in ilist */
101: unsigned nbsp;
102: unsigned ncsp;
103: unsigned nmpx;
104: unsigned npipe;
105: long nblk;
106: long nfblk[4]; /* # of direct, single, double, and triple indirects */
107: long ndirb;
108: long nfreeb;
109: long nmissing;
110: long nfdup;
111: ino_t nifree;
112:
113: long atol();
114:
115: main(argc, argv)
116: char *argv[];
117: {
118:
119: while (argc>1 && *argv[1]=='-') {
120: switch (argv[1][1]) {
121: case 'b':
122: nblock = 0;
123: while (blocks[nblock] = atol(argv[2])) {
124: if (nblock++ >= NBLOCK) {
125: fprintf(stderr, tmb);
126: exstat |= IC_MISC;
127: break;
128: }
129: argv++;
130: argc--;
131: }
132: break;
133:
134: case 's':
135: sflag = 1;
136: break;
137:
138: case 'v':
139: vflag = 1;
140: break;
141:
142:
143: default:
144: usage();
145: }
146: argc--;
147: argv++;
148: }
149: if (argc > 1)
150: allcheck(argv+1);
151: else
152: usage();
153: exit(exstat);
154: }
155:
156: /*
157: * Check the given list of filesystems
158: */
159: allcheck(fsl)
160: register char **fsl;
161: {
162: while (*fsl != NULL)
163: if (icheck(*fsl++))
164: return;
165: }
166:
167: /*
168: * Check one filesystem
169: */
170: icheck(fsname)
171: char *fsname;
172: {
173: struct filsys *sbp;
174: register struct dinode *ip;
175: register int i;
176: register ino_t inum;
177: register char *mode;
178: int thischunk;
179: daddr_t seek, limit;
180: struct defect *cdsp;
181:
182: nfiles = 0;
183: nreg = 0;
184: ndir = 0;
185: ndirb = 0;
186: npipe = 0;
187: nbsp = 0;
188: ncsp = 0;
189: nmpx = 0;
190: nblk = 0;
191: nbad = 0;
192: nibad = 0;
193: for (i=0; i<4; i++)
194: nfblk[i] = 0;
195: nmissing = 0;
196: nfdup = 0;
197: nfreeb = 0;
198: nifree = 0;
199: freeip = freei;
200: mode = sflag ? "r+w" : "r";
201: if ((fs = fopen(fsname, mode)) == NULL) {
202: fprintf(stderr, "%s: cannot open\n", fsname);
203: exstat |= IC_MISC;
204: return;
205: }
206: printf("%s:\n", fsname);
207: if (!sflag)
208: sync();
209: bread((daddr_t)SUPERB, superb);
210: sbp = superb;
211: canint(sbp->s_isize);
212: candaddr(sbp->s_fsize);
213: canshort(sbp->s_nfree);
214: for (i=0; i<NICFREE; ++i)
215: candaddr(sbp->s_free[i]);
216: canshort(sbp->s_ninode);
217: for (i=0; i<NICINOD; ++i)
218: canino(sbp->s_inode[i]);
219: cantime(sbp->s_time);
220: candaddr(sbp->s_tfree);
221: canino(sbp->s_tinode);
222: canshort(sbp->s_m);
223: canshort(sbp->s_n);
224: canlong(sbp->s_unique);
225: fsize = sbp->s_fsize;
226: isize = sbp->s_isize;
227: if (isize<INOORG+1 || isize>=fsize || fsize<INOORG+1)
228: cerr("Ridiculous fsize/isize");
229: if ((bitmap=calloc((int)((fsize+NBPC-1)/NBPC), sizeof(char))) == NULL)
230: cerr("No space for bitmap");
231: bmark((daddr_t)BOOTB, "bootstrap", 0);
232: bmark((daddr_t)SUPERB, "super block", 0);
233: finddefective();
234: nblk = isize;
235: inum = 1;
236: seek = INOORG;
237: cdsp = deflist;
238: while (seek < isize) {
239: if (cdsp!=NULL && cdsp->d_start==seek) {
240: nibad += cdsp->d_length;
241: seek += cdsp->d_length;
242: inum += cdsp->d_length*INOPB;
243: cdsp = cdsp->d_next;
244: continue;
245: }
246: limit = seek+IBLK;
247: if (cdsp!=NULL && limit>cdsp->d_start)
248: limit = cdsp->d_start;
249: if (limit > isize)
250: limit = isize;
251: thischunk = limit-seek;
252: lseek(fileno(fs), seek*BSIZE, 0);
253: for (i=0; i<thischunk; ++i)
254: bmark((daddr_t)seek++, "inodes", 0);
255: thischunk *= BSIZE;
256: if (read(fileno(fs), ibuf, thischunk) != thischunk) {
257: fprintf(stderr, "I-node read error\n");
258: exstat |= IC_HARD;
259: break;
260: }
261: ip = (struct dinode *) &ibuf[0];
262: while (ip < (struct dinode *) &ibuf[thischunk]) {
263: if (inum != BADFIN) {
264: canshort(ip->di_mode);
265: canshort(ip->di_nlink);
266: canshort(ip->di_uid);
267: canshort(ip->di_gid);
268: cansize(ip->di_size);
269: cantime(ip->di_atime);
270: cantime(ip->di_mtime);
271: cantime(ip->di_ctime);
272: ilook(ip, inum);
273: }
274: ++inum;
275: ++ip;
276: }
277: }
278: freecount();
279: free(bitmap);
280: freedefective();
281: if (nmissing != 0)
282: exstat |= IC_MISS;
283: if (nfdup != 0)
284: exstat |= IC_DUPF;
285: if (!sflag && vflag) {
286: printf("f=%u,r=%u,d=%u,b=%u,c=%u,m=%u,p=%u\n", nfiles, nreg,
287: ndir, nbsp, ncsp, nmpx, npipe);
288: printf("blks=%ld, dirb=%ld, d=%ld, i=%ld, ii=%ld, iii=%ld\n",
289: nblk, ndirb, nfblk[0], nfblk[1], nfblk[2], nfblk[3]);
290: printf("free = %ld\n", nfreeb);
291: printf("bad=%u (%u in I-list)\n", nbad, nibad);
292: }
293: if (!sflag) {
294: if (nmissing != 0)
295: printf("missing = %ld\n", nmissing);
296: if (nfdup != 0)
297: printf("%ld dups in free\n", nfdup);
298: if (sbp->s_tinode != nifree) {
299: printf("Bad ifree list\n");
300: exstat |= IC_BFB;
301: }
302: }
303: if (sflag)
304: makesuper();
305: fclose(fs);
306: return (0);
307: }
308:
309: /*
310: * Look at each inode marking used blocks
311: * and checking consistency.
312: */
313: ilook(ip, inum)
314: register struct dinode *ip;
315: ino_t inum;
316: {
317: daddr_t addrs[NADDR];
318: register i, l;
319: int flag;
320:
321: if (ip->di_mode == 0) {
322: if (freeip < &freei[NICFREE])
323: *freeip++ = inum;
324: nifree++;
325: return;
326: }
327: nfiles++;
328: flag = PLAIN;
329: switch (ip->di_mode & IFMT) {
330: case IFREG:
331: nreg++;
332: break;
333:
334: case IFDIR:
335: ndir++;
336: flag = DIR;
337: break;
338:
339: case IFBLK:
340: nbsp++;
341: return;
342:
343: case IFCHR:
344: ncsp++;
345: return;
346:
347: case IFPIPE:
348: npipe++;
349: return;
350:
351: case IFMPB:
352: case IFMPC:
353: nmpx++;
354: return;
355:
356: default:
357: printf("%u: Bad filetype %o\n", inum, ip->di_mode&IFMT);
358: return;
359: }
360: l3tol(addrs, ip->di_addr, NADDR);
361: for (i = NADDR-1; i >= 0; i--)
362: for (l=1; l<=4; l++)
363: if (i < offsets[l]) {
364: crawldown(addrs[i], l-1, flag, inum);
365: break;
366: }
367: }
368:
369: /*
370: * Crawl down through `lev' levels
371: * of indirect blocks, starting at block
372: * `bn'. The `ino' argument is the inumber that
373: * started this all off; is just gets passed
374: * to `bmark'. The `flag' tells you what kind
375: * of blocks you have at level 0 (in can be BAD,
376: * DIR or PLAIN).
377: */
378: crawldown(bn, lev, flag, ino)
379: daddr_t bn;
380: int lev;
381: ino_t ino;
382: {
383: register char *bp;
384: register char *type;
385: register int i;
386:
387: if (bn == 0)
388: return;
389: nblk++;
390: if (lev==0 && flag==DIR) {
391: type = "dir";
392: ndirb++;
393: } else if (lev==0 && flag==BAD) {
394: type = "bad";
395: nbad++;
396: } else {
397: type = btypes[lev];
398: nfblk[lev]++;
399: }
400: if (bmark(bn, type, ino))
401: return;
402: if (lev==0 && flag==BAD)
403: savedefective(bn);
404: if (lev-- > 0) {
405: bread(bn, bp = idbuf[lev]);
406: for (i=0; i<NBN; i++) {
407: bn = ((long *)bp)[i];
408: candaddr(bn);
409: crawldown(bn, lev, flag, ino);
410: }
411: }
412: }
413:
414: /*
415: * This routine finds all of the
416: * defective space on the filsystem by reading
417: * the bad block file and marking all the blocks.
418: * The defective space list, used by the I-list
419: * scanner and other guys, is constructued.
420: */
421: finddefective()
422: {
423: register struct dinode *ip;
424: register i, level;
425: daddr_t addrs[NADDR];
426:
427: ++nfiles;
428: lseek(fileno(fs), (long)iblockn(BADFIN)*BSIZE, 0);
429: if (read(fileno(fs), ibuf, BSIZE) != BSIZE) {
430: printf("I/O error reading bad block inode\n");
431: exstat |= IC_HARD;
432: return;
433: }
434: ip = (struct dinode *) &ibuf[0] + iblocko(BADFIN);
435: canshort(ip->di_mode);
436: if (ip->di_mode == 0)
437: return;
438: if ((ip->di_mode&IFMT) != IFREG) {
439: printf("Bad block file has bad mode\n");
440: exstat |= IC_HARD;
441: return;
442: }
443: l3tol(addrs, ip->di_addr, NADDR);
444: for (i=NADDR-1; i>=0; --i) {
445: for (level=1; level<=4; ++level) {
446: if (i < offsets[level]) {
447: crawldown(addrs[i], level-1, BAD, BADFIN);
448: break;
449: }
450: }
451: }
452: }
453:
454: /*
455: * Free all of the nodes
456: * in the defective space list.
457: */
458: freedefective()
459: {
460: register struct defect *cdsp1, *cdsp2;
461:
462: cdsp1 = deflist;
463: deflist = NULL;
464: while (cdsp1 != NULL) {
465: cdsp2 = cdsp1->d_next;
466: free((char *) cdsp1);
467: cdsp1 = cdsp2;
468: }
469: }
470:
471: /*
472: * Add a new, defective block
473: * into the sorted defective block chain.
474: * Merge this block with the ends of
475: * any existing entries. No check is made
476: * for entries fusing; bad blocks get scooped
477: * (in general) up in order, and the bad blocks
478: * are generally sparsely placed on the disc.
479: */
480: savedefective(bn)
481: daddr_t bn;
482: {
483: register struct defect *cdsp1, *cdsp2, *cdsp3;
484:
485: cdsp1 = NULL;
486: cdsp2 = deflist;
487: while (cdsp2!=NULL && bn>cdsp2->d_start) {
488: cdsp1 = cdsp2;
489: cdsp2 = cdsp2->d_next;
490: }
491: if (cdsp1!=NULL && bn==cdsp1->d_start+cdsp1->d_length) {
492: ++cdsp1->d_length;
493: return;
494: }
495: if (cdsp2!=NULL && bn==cdsp2->d_start-1) {
496: --cdsp2->d_start;
497: ++cdsp2->d_length;
498: return;
499: }
500: if ((cdsp3=(struct defect *)malloc(sizeof(struct defect))) == NULL)
501: cerr("Out of space for bad blocks");
502: if (cdsp1 == NULL)
503: deflist = cdsp3; else
504: cdsp1->d_next = cdsp3;
505: cdsp3->d_next = cdsp2;
506: cdsp3->d_start = bn;
507: cdsp3->d_length = 1;
508: }
509:
510: /*
511: * Look at the free count for a filesystem
512: * by chasing down the free-list.
513: */
514: freecount()
515: {
516: register char *bmp;
517: register struct fblk *fbp;
518: struct filsys *sbp;
519: register unsigned i;
520: daddr_t bn;
521: long ntfree;
522:
523: sbp = superb;
524: fbp = &sbp->s_nfree;
525: ntfree = sbp->s_tfree;
526: while ((i = fbp->df_nfree) != 0) {
527: if ((unsigned)(fbp->df_nfree) > NICFREE) {
528: badfreelist();
529: return;
530: }
531: for (i=0; i<fbp->df_nfree; i++) {
532: bn = fbp->df_free[i];
533: bmark(bn, "free", 0);
534: nfreeb++;
535: }
536: bread(fbp->df_free[0], fbuf);
537: fbp = fbuf;
538: canint(fbp->df_nfree);
539: for (i=0; i<NICFREE; ++i)
540: candaddr(fbp->df_free[i]);
541: }
542: /*
543: * Count number of blocks not in bitmap
544: */
545: i = 1;
546: for (bn=0, bmp=bitmap; bn < fsize; bn++) {
547: if (i == 1<<NBPC) {
548: i = 1;
549: bmp++;
550: }
551: if ((*bmp & i) == 0)
552: nmissing++;
553: i <<= 1;
554: }
555: if (sflag)
556: nmissing -= isize + nfreeb;
557: if (nfreeb != ntfree) {
558: if (!sflag)
559: printf("Free list/tfree counts differ\n");
560: exstat |= IC_MISS;
561: }
562: }
563:
564: /*
565: * Remake the superblock - reconstructing
566: * the free-list if sflag is set.
567: */
568: makesuper()
569: {
570: register struct filsys *sbp;
571: register ino_t *fip;
572: register i;
573: daddr_t bn;
574:
575: sbp = superb;
576: /*
577: * Remake list of free i-numbers.
578: */
579: fip = sbp->s_inode;
580: sbp->s_ninode = freeip-freei;
581: while (freeip > freei)
582: *fip++ = *--freeip;
583: while (fip < &sbp->s_inode[NICFREE])
584: *fip++ = 0;
585: sbp->s_tinode = nifree;
586: /*
587: * Free all remaining blocks
588: * and write last one as tail of free-list
589: */
590: sbp->s_nfree = 0;
591: sbp->s_tfree = 0;
592: bn = fsize;
593: for (bn=fsize-1; bn>=isize; --bn)
594: if (!test(bn))
595: bfree(bn);
596: canint(sbp->s_isize);
597: candaddr(sbp->s_fsize);
598: canshort(sbp->s_nfree);
599: for (i=0; i<NICFREE; ++i)
600: candaddr(sbp->s_free[i]);
601: canshort(sbp->s_ninode);
602: for (i=0; i<NICINOD; ++i)
603: canino(sbp->s_inode[i]);
604: cantime(sbp->s_time);
605: candaddr(sbp->s_tfree);
606: canino(sbp->s_tinode);
607: canshort(sbp->s_m);
608: canshort(sbp->s_n);
609: canlong(sbp->s_unique);
610: bwrite((daddr_t)SUPERB, sbp);
611: }
612:
613: /*
614: * Free a block and, in so doing, construct
615: * the free list chain.
616: */
617: bfree(bn)
618: daddr_t bn;
619: {
620: register struct filsys *sbp;
621: register struct fblk *fbp;
622: register i;
623:
624: sbp = superb;
625: if (sbp->s_tfree == 0) {
626: bclear(fbuf, BSIZE);
627: bwrite(bn, fbuf);
628: }
629: if (sbp->s_nfree == NICFREE) {
630: bclear(fbp = fbuf, BSIZE);
631: fbp->df_nfree = sbp->s_nfree;
632: canint(fbp->df_nfree);
633: for (i=0; i<sbp->s_nfree; ++i) {
634: fbp->df_free[i] = sbp->s_free[i];
635: candaddr(fbp->df_free[i]);
636: }
637: bwrite(bn, fbuf);
638: sbp->s_nfree = 0;
639: }
640: sbp->s_free[sbp->s_nfree++] = bn;
641: sbp->s_tfree++;
642: }
643:
644: /*
645: * Read the specified block number
646: * into `buf'.
647: */
648: bread(bn, buf)
649: daddr_t bn;
650: char *buf;
651: {
652: if (bn<0 || bn>=fsize) {
653: badblock(bn, "any", 0);
654: bclear(buf, BSIZE);
655: return;
656: }
657: lseek(fileno(fs), (fsize_t)BSIZE * bn, 0);
658: if (read(fileno(fs), buf, BSIZE) != BSIZE) {
659: fprintf(stderr, "Read error %ld\n", (long)bn);
660: exstat |= IC_HARD;
661: bclear(buf, BSIZE);
662: }
663: }
664:
665: /*
666: * Write block `bn' from `buf'.
667: */
668: bwrite(bn, buf)
669: daddr_t bn;
670: char *buf;
671: {
672: if (bn<0 || bn>=fsize) {
673: badblock(bn, "any", 0);
674: return;
675: }
676: lseek(fileno(fs), (fsize_t)BSIZE * bn, 0);
677: if (write(fileno(fs), buf, BSIZE) != BSIZE) {
678: fprintf(stderr, "Write error %ld\n", (long)bn);
679: exstat |= IC_HARD;
680: }
681: }
682:
683: /*
684: * Mark block # `bn' as
685: * seen before an check for
686: * duplicates.
687: * Bmark only marks file blocks if `sflag' is
688: * set so that the free list can be constructed
689: * again.
690: * Return 1 when something is wrong.
691: */
692: bmark(bn, type, inum)
693: daddr_t bn;
694: char *type;
695: ino_t inum;
696: {
697: register nb;
698:
699: if (bn<0 || bn>=fsize) {
700: badblock(bn, type, inum);
701: return (1);
702: }
703: if (nb = nblock) {
704: register i;
705:
706: for (i=0; i<nb; i++)
707: if (blocks[i] == bn)
708: printf("%ld arg, class=%s, inode=%u\n",
709: (long)bn, type, inum);
710: }
711: {
712: register char *bp;
713: register int mask;
714:
715: mask = 1 << ((unsigned)bn)%NBPC;
716: bp = bitmap + ((unsigned)bn)/NBPC;
717: if (*bp & mask) /* if (test(bn)) */
718: dupblock(bn, type, inum);
719: else if (!sflag || inum!=0)
720: *bp |= mask; /* mark(bn) */
721: }
722: return (0);
723: }
724:
725: /*
726: * Clear a block of memory
727: * pointed to by `bp' for size
728: * `nb' bytes.
729: */
730: bclear(bp, nb)
731: register char *bp;
732: register unsigned nb;
733: {
734: if (nb)
735: do {
736: *bp++ = 0;
737: } while (--nb);
738: }
739:
740: /*
741: * Error routines
742: */
743: badblock(bn, type, inum)
744: daddr_t bn;
745: char *type;
746: ino_t inum;
747: {
748: register int perr = 0;
749:
750: if (strcmp(type, "free") != 0) {
751: perr++;
752: exstat |= IC_HARD;
753: } else {
754: exstat |= IC_BADF;
755: if (!sflag)
756: perr++;
757: }
758: if (perr)
759: printf("%ld bad, class=%s, inode=%u\n", (long)bn, type, inum);
760: }
761:
762: dupblock(bn, type, inum)
763: daddr_t bn;
764: char *type;
765: ino_t inum;
766: {
767: if (inum != 0)
768: exstat |= IC_HARD;
769: else
770: nfdup++;
771: if (vflag || inum!=0)
772: printf("%ld dup, class=%s, inode=%u\n", (long)bn, type, inum);
773: }
774:
775: badfreelist()
776: {
777: if (!sflag) {
778: printf("Bad freelist\n");
779: exstat |= IC_BFB;
780: }
781: }
782:
783: /*
784: * Unrecoverable errors
785: */
786: cerr(x)
787: {
788: printf("%r", &x);
789: putchar('\n');
790: exit(IC_MISC);
791: }
792:
793: usage()
794: {
795: cerr("Usage: icheck [-sv] [-b bn ...] filesystem ...");
796: }
797:
798: /*
799: * Block copy routine
800: */
801: bcopy(in, out, nb)
802: register char *in, *out;
803: register unsigned nb;
804: {
805: if (nb)
806: do {
807: *out++ = *in++;
808: } while (--nb);
809: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.