|
|
1.1 root 1: /*
2: * Rec'd from Lauren Weinstein, 7-16-84.
3: * Dcheck - check consistency of directory
4: * graph structure for a filesystem.
5: * and optionally repair faulty link counts.
6: */
7: #include <stdio.h>
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:
15: #define IBLK 12 /* I-node read blocking factor */
16: #define NINUM 20 /* Maximum number of i-numbers to look for */
17: #undef NI
18: #define NI 1
19: #define NII 1
20: #define NIII 1
21: #define INOORG 2
22:
23: /*
24: * A chain of these structures
25: * holds all of the defective blocks found
26: * in the bad block file. The list is sorted for
27: * easy access by those parts of the program
28: * that scan blocks.
29: */
30: struct defect
31: {
32: struct defect *d_next; /* Link to next */
33: daddr_t d_start; /* First bad block in cluster */
34: int d_length; /* Size of cluster */
35: };
36:
37: /*
38: * Tables used by imap.
39: * This effectively implements
40: * the access polynomial for the indirect
41: * blocks.
42: */
43: static daddr_t ranges[] = {
44: ND,
45: ND + (daddr_t)NI*NBN,
46: ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN,
47: ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN + (daddr_t)NIII*NBN*NBN*NBN,
48: };
49:
50: static char offsets[] = {
51: 0,
52: ND,
53: ND+NI,
54: ND+NI+NII,
55: };
56:
57: static daddr_t coeff[] = {
58: 1, (daddr_t)NBN, (daddr_t)NBN*NBN, (daddr_t)NBN*NBN*NBN
59: };
60:
61: char tmi[] = "Too many i-numbers given\n";
62: char irderr[] = "I-node read error -- pass %d\n";
63:
64: int ninumber;
65: ino_t inums[NINUM];
66: struct defect *deflist;
67: char superb[BSIZE];
68: char ibuf[BSIZE*IBLK];
69: char dbuf[BSIZE];
70:
71: int sflag; /* Repair filesystem */
72: int exstat; /* Exit status */
73: FILE *fs; /* File system i/o stream pointer */
74: daddr_t fsize = SUPERI+1; /* Allow read of super-block */
75: ino_t isize;
76: ino_t maxino;
77: unsigned nhard; /* Hard things requiring pass 3 to fix */
78: short unsigned *entries;
79:
80: daddr_t imap();
81: int imark();
82: int icompare();
83:
84: main(argc, argv)
85: char *argv[];
86: {
87:
88: while (argc>1 && *argv[1]=='-') {
89: switch (argv[1][1]) {
90: case 'i':
91: ninumber = 0;
92: while(inums[ninumber] = atoi(argv[2])) {
93: if (ninumber++ >= NINUM) {
94: fprintf(stderr, tmi);
95: exstat |= DC_MISC;
96: break;
97: }
98: argv++;
99: argc--;
100: }
101: break;
102:
103: case 's':
104: sflag = 1;
105: break;
106:
107: default:
108: usage();
109: }
110: argc--;
111: argv++;
112: }
113: if (argc > 1)
114: allcheck(argv+1);
115: else
116: usage();
117: exit(exstat);
118: }
119:
120: /*
121: * Check the given list of filesystems
122: */
123: allcheck(fsl)
124: register char **fsl;
125: {
126: while (*fsl != NULL)
127: dcheck(*fsl++);
128: }
129:
130: /*
131: * Check one filesystem
132: */
133: dcheck(fsname)
134: char *fsname;
135: {
136: register i;
137: struct filsys *sbp;
138: char *mode;
139:
140: mode = sflag ? "r+w" : "r";
141: if ((fs = fopen(fsname, mode)) == NULL) {
142: fprintf(stderr, "%s: cannot open\n", fsname);
143: exstat |= DC_MISC;
144: return;
145: }
146: printf("%s:\n", fsname);
147: if (!sflag)
148: sync();
149: bread((daddr_t)SUPERI, superb);
150: sbp = superb;
151: canshort( sbp->s_isize);
152: candaddr( sbp->s_fsize);
153: canshort( sbp->s_nfree);
154: for (i=0; i<NICFREE; ++i)
155: candaddr( sbp->s_free[i]);
156: canshort( sbp->s_ninode);
157: for (i=0; i<NICINOD; ++i)
158: canino( sbp->s_inode[i]);
159: cantime( sbp->s_time);
160: candaddr( sbp->s_tfree);
161: canino( sbp->s_tinode);
162: canshort( sbp->s_m);
163: canshort( sbp->s_n);
164: fsize = sbp->s_fsize;
165: isize = sbp->s_isize;
166: if (isize<INODEI+1 || isize>=fsize)
167: cerr("Ridiculous fsize/isize");
168: if ((entries=calloc(isize*INOPB, sizeof(short unsigned))) == NULL)
169: cerr("Not enough space");
170: finddefective();
171: maxino = (isize-INODEI) * INOPB;
172: /*
173: * The first pass runs down the
174: * graph filling in the array
175: * `entries' which is the number
176: * of names found in directories for
177: * any i-node.
178: */
179: entries[ROOTIN-1]++;
180: pass(0, imark);
181: /*
182: * In the next pass, link counts
183: * in the i-nodes are compared with
184: * those pre-computed for the graph.
185: */
186: pass(1, icompare);
187: /*
188: * This fixup pass is only
189: * required for some harder errors
190: * encountered in `-s' mode.
191: */
192: if (nhard && sflag)
193: pass(2, imark);
194: free(entries);
195: freedefective();
196: nhard = 0;
197: fclose(fs);
198: }
199:
200: /*
201: * A generalised pass over all i-nodes, calls
202: * the routine `func' for every i-node encountered.
203: * `n' is the pass number, used only in the diagnostics.
204: */
205: pass(n, func)
206: int n;
207: int (*func)();
208: {
209: register struct dinode *ip;
210: register ino_t inum;
211: daddr_t seek, limit;
212: int thischunk;
213: struct defect *cdsp;
214:
215: inum = 1;
216: seek = INOORG;
217: cdsp = deflist;
218: while (seek < isize) {
219: if (cdsp!=NULL && cdsp->d_start==seek) {
220: seek += cdsp->d_length;
221: inum += cdsp->d_length*INOPB;
222: cdsp = cdsp->d_next;
223: continue;
224: }
225: limit = seek+IBLK;
226: if (cdsp!=NULL && limit>cdsp->d_start)
227: limit = cdsp->d_start;
228: if (limit > isize)
229: limit = isize;
230: thischunk = limit-seek;
231: lseek(fileno(fs), seek*BSIZE, 0);
232: seek += thischunk;
233: thischunk *= BSIZE;
234: if (read(fileno(fs), ibuf, thischunk) != thischunk) {
235: fprintf(stderr, irderr, n);
236: exstat |= DC_HARD;
237: break;
238: }
239: ip = (struct dinode *) &ibuf[0];
240: while (ip < (struct dinode *) &ibuf[thischunk]) {
241: if (inum != BADFIN) {
242: canshort(ip->di_mode);
243: canshort(ip->di_nlink);
244: canshort(ip->di_uid);
245: canshort(ip->di_gid);
246: cansize(ip->di_size);
247: cantime(ip->di_atime);
248: cantime(ip->di_mtime);
249: cantime(ip->di_ctime);
250: if ((*func)(ip, inum, n))
251: return;
252: }
253: ++inum;
254: ++ip;
255: }
256: }
257: }
258:
259: /*
260: * Check an i-node link count (in
261: * pass 2) against the entries already
262: * found.
263: */
264: icompare(ip, inum, pn)
265: register struct dinode *ip;
266: register ino_t inum;
267: int pn;
268: {
269: register unsigned nent;
270:
271: nent = entries[inum-1];
272: entries[inum-1] = 0;
273: if (nent != ip->di_nlink
274: || (ip->di_mode!=0 && ip->di_nlink==0))
275: badnlink(ip, inum, nent);
276: return (0);
277: }
278:
279: /*
280: * Report or fix up bad link count
281: * in filesystem.
282: * `entries' is the number found.
283: */
284: badnlink(ip, ino, nent)
285: register struct dinode *ip;
286: ino_t ino;
287: int nent;
288: {
289: static int needtitle = 1;
290:
291: if (sflag == 0) {
292: if (needtitle != 0) {
293: printf(" Ino Entries Link\n");
294: needtitle = 0;
295: }
296: printf("%4u %7u %6u", ino, nent, ip->di_nlink);
297: if (ip->di_mode!=0 && ip->di_nlink==0)
298: printf(" (u)");
299: putchar('\n');
300: }
301: if (nent == 0) {
302: if (sflag) {
303: bclear((char *) ip, sizeof (*ip));
304: iwrite(ip, ino);
305: } else
306: exstat |= DC_CLRI;
307: } else if (ip->di_mode != 0) {
308: if (sflag) {
309: ip->di_nlink = nent;
310: iwrite(ip, ino);
311: } else
312: exstat |= DC_LCE;
313: } else if (ip->di_mode==0 && ip->di_nlink==0) {
314: nhard++;
315: entries[ino-1] = nent;
316: }
317: }
318:
319: /*
320: * Imark looks at all directory i-nodes
321: * and marks all of the subordinate nodes
322: * in the entries table. It also checks for
323: * argument i-numbers to list specially.
324: * Returns non-zero if we should stop
325: * i-list scanning in `pass'.
326: */
327: imark(ip, inum, pn)
328: register struct dinode *ip;
329: register ino_t inum;
330: int pn;
331: {
332: fsize_t size;
333: daddr_t pb;
334: register daddr_t bn;
335:
336: if (ip->di_mode == 0)
337: return (0);
338: if ((ip->di_mode&IFMT) != IFDIR)
339: return (0);
340: size = ip->di_size;
341: bn = 0;
342: if (pn==1 && (size % sizeof(struct direct))!=0) {
343: printf("I#%u: Directory size not mod %d\n", inum,
344: sizeof(struct direct));
345: size -= size % sizeof( struct direct);
346: }
347: while (size) {
348: register struct direct *dp;
349:
350: if ((pb = imap(ip, bn++)) == 0)
351: break;
352: bread(pb, dbuf);
353: for (dp=dbuf; dp < &dbuf[BSIZE]; dp++) {
354: canino( dp->d_ino);
355: if (dp->d_ino) {
356: if (dp->d_ino > maxino)
357: dirline(inum, dp, "bad");
358: else if (pn == 0)
359: entries[dp->d_ino-1]++;
360: else {
361: if (entries[dp->d_ino-1]) {
362: if (--entries[dp->d_ino-1] == 0)
363: nhard--;
364: bclear(dp, sizeof(*dp));
365: bwrite(pb, dbuf);
366: }
367: }
368: if (ninumber)
369: iarg(inum, dp);
370: }
371: size -= sizeof( struct direct);
372: if (size == 0)
373: break;
374: }
375: }
376: if (pn==0)
377: return (0);
378: return (nhard == 0);
379: }
380:
381: /*
382: * Iarg checks if the directory i-number is in
383: * the argument list of i-nodes, and if it is
384: * prints this out.
385: */
386: iarg(inum, dp)
387: register ino_t inum;
388: register struct direct *dp;
389: {
390: register unsigned i;
391:
392: for (i=0; i<ninumber;)
393: if (inums[i++] == dp->d_ino)
394: dirline(inum, dp, "arg");
395: }
396:
397: /*
398: * Print out a line for a directory
399: * that is found in the search (.e.g.
400: * bad or argument directories).
401: */
402: dirline(ino, dp, str)
403: ino_t ino;
404: register struct direct *dp;
405: char *str;
406: {
407: printf("%u %s: %u/%-*.*s\n", dp->d_ino, str, ino,
408: DIRSIZ, DIRSIZ, dp->d_name);
409: }
410:
411: /*
412: * This routine finds all of the
413: * defective space on the filsystem by reading
414: * the bad block file and marking all the blocks.
415: * The defective space list, used by the I-list
416: * scanner and other guys, is constructued.
417: */
418: finddefective()
419: {
420: register struct dinode *ip;
421: daddr_t pb, lb;
422:
423: lseek(fileno(fs), (long)iblockn(BADFIN)*BSIZE, 0);
424: if (read(fileno(fs), ibuf, BSIZE) != BSIZE) {
425: printf("I/O error reading bad block inode\n");
426: exstat |= IC_HARD;
427: return;
428: }
429: ip = (struct dinode *) &ibuf[0] + iblocko(BADFIN);
430: canshort(ip->di_mode);
431: if (ip->di_mode == 0)
432: return;
433: if ((ip->di_mode&IFMT) != IFREG) {
434: printf("Bad block file has bad mode\n");
435: exstat |= IC_HARD;
436: return;
437: }
438: lb = 0;
439: while ((pb=imap(ip, lb++)) != 0)
440: savedefective(pb);
441: }
442:
443: /*
444: * Free all of the nodes
445: * in the defective space list.
446: */
447: freedefective()
448: {
449: register struct defect *cdsp1, *cdsp2;
450:
451: cdsp1 = deflist;
452: deflist = NULL;
453: while (cdsp1 != NULL) {
454: cdsp2 = cdsp1->d_next;
455: free((char *) cdsp1);
456: cdsp1 = cdsp2;
457: }
458: }
459:
460: /*
461: * Add a new, defective block
462: * into the sorted defective block chain.
463: * Merge this block with the ends of
464: * any existing entries. No check is made
465: * for entries fusing; bad blocks get scooped
466: * (in general) up in order, and the bad blocks
467: * are generally sparsely placed on the disc.
468: */
469: savedefective(bn)
470: daddr_t bn;
471: {
472: register struct defect *cdsp1, *cdsp2, *cdsp3;
473:
474: cdsp1 = NULL;
475: cdsp2 = deflist;
476: while (cdsp2!=NULL && bn>cdsp2->d_start) {
477: cdsp1 = cdsp2;
478: cdsp2 = cdsp2->d_next;
479: }
480: if (cdsp1!=NULL && bn==cdsp1->d_start+cdsp1->d_length) {
481: ++cdsp1->d_length;
482: return;
483: }
484: if (cdsp2!=NULL && bn==cdsp2->d_start-1) {
485: --cdsp2->d_start;
486: ++cdsp2->d_length;
487: return;
488: }
489: if ((cdsp3=(struct defect *)malloc(sizeof(struct defect))) == NULL)
490: cerr("Out of space for bad blocks");
491: if (cdsp1 == NULL)
492: deflist = cdsp3; else
493: cdsp1->d_next = cdsp3;
494: cdsp3->d_next = cdsp2;
495: cdsp3->d_start = bn;
496: cdsp3->d_length = 1;
497: }
498:
499: /*
500: * For a given inode (`ip'),
501: * map a logical block number (`bn')
502: * onto a physical disc block number.
503: */
504: daddr_t
505: imap(ip, lb)
506: register struct dinode *ip;
507: daddr_t lb;
508: {
509: register il;
510: daddr_t bpos, pb;
511: register daddr_t *bp;
512: register daddr_t addrs[NADDR];
513:
514: l3tol(addrs, ip->di_addr, NADDR);
515: for (il=0; il<4; il++)
516: if (lb < ranges[il]) {
517: if (il != 0)
518: lb -= ranges[il-1];
519: bpos = lb/coeff[il];
520: lb %= coeff[il];
521: bp = &addrs[(int)bpos + offsets[il]];
522: if ((pb = *bp) != 0) {
523: /*
524: * Map through indirect
525: * blocks here.
526: */
527: while (il-- > 0) {
528: bread(pb, dbuf);
529: bpos = lb/coeff[il];
530: lb %= coeff[il];
531: bp = (daddr_t *)dbuf + bpos;
532: if ((pb = *bp) == 0)
533: break;
534: pb = *bp;
535: candaddr( pb);
536: }
537: }
538: return (pb);
539: }
540: return (0);
541: }
542:
543: /*
544: * Read the specified block number
545: * into `buf'.
546: */
547: bread(bn, buf)
548: daddr_t bn;
549: char *buf;
550: {
551: if (bn >= fsize) {
552: badblock(bn, "any");
553: bclear(buf, BSIZE);
554: return;
555: }
556: lseek(fileno(fs), (fsize_t)BSIZE * bn, 0);
557: if (read(fileno(fs), buf, BSIZE) != BSIZE) {
558: fprintf(stderr, "Read error %ld\n", (long)bn);
559: exstat |= DC_HARD;
560: bclear(buf, BSIZE);
561: }
562: }
563:
564: /*
565: * Write block `bn' from `buf'.
566: */
567: bwrite(bn, buf)
568: daddr_t bn;
569: char *buf;
570: {
571: if (bn >= fsize) {
572: badblock(bn, "any");
573: return;
574: }
575: lseek(fileno(fs), (fsize_t)BSIZE * bn, 0);
576: if (write(fileno(fs), buf, BSIZE) != BSIZE) {
577: fprintf(stderr, "Write error %ld\n", (long)bn);
578: exstat |= DC_HARD;
579: }
580: }
581:
582: /*
583: * Put out an i-node to disc.
584: * Used only for `-s' option.
585: */
586: iwrite(ip, ino)
587: register struct dinode *ip;
588: register ino_t ino;
589: {
590: register struct dinode *ip2;
591: daddr_t bn;
592:
593: bn = iblockn(ino);
594: bread(bn, dbuf);
595: ip2 = &((struct dinode *)dbuf)[iblocko( ino)];
596: *ip2 = *ip;
597: canshort( ip2->di_mode);
598: canshort( ip2->di_nlink);
599: canshort( ip2->di_uid);
600: canshort( ip2->di_gid);
601: cansize( ip2->di_size);
602: cantime( ip2->di_atime);
603: cantime( ip2->di_mtime);
604: cantime( ip2->di_ctime);
605: bwrite(bn, dbuf);
606: }
607:
608: /*
609: * Clear a block of memory
610: * pointed to by `bp' for size
611: * `nb' bytes.
612: */
613: bclear(bp, nb)
614: register char *bp;
615: register unsigned nb;
616: {
617: if (nb)
618: do {
619: *bp++ = 0;
620: } while (--nb);
621: }
622:
623: /*
624: * Error routines
625: */
626: badblock(bn)
627: daddr_t bn;
628: {
629: printf("Bad block #%D\n", (long)bn);
630: exstat |= DC_HARD;
631: }
632:
633: /*
634: * Unrecoverable errors
635: */
636: cerr(x)
637: {
638: printf("%r", &x);
639: putchar('\n');
640: exit(DC_MISC);
641: }
642:
643: usage()
644: {
645: cerr("Usage: dcheck [-s] [-i ino ...] filesystem ...");
646: }
647:
648: /*
649: * Block copy routine
650: */
651: bcopy(in, out, nb)
652: register char *in, *out;
653: register unsigned nb;
654: {
655: if (nb)
656: do {
657: *out++ = *in++;
658: } while (--nb);
659: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.