|
|
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.