|
|
1.1 ! root 1: /* ! 2: * ncheck -- map an I-number into a pathname. ! 3: * Also, look for special and setuid files. ! 4: */ ! 5: ! 6: #include <stdio.h> ! 7: #include <sys/filsys.h> ! 8: #include <sys/fblk.h> ! 9: #include <sys/dir.h> ! 10: #include <sys/ino.h> ! 11: #include <canon.h> ! 12: ! 13: #define NHASH 101 /* Prime provides a reasonable distribution */ ! 14: #define NSBRK 512 /* Bytes to add each time out */ ! 15: #define NFNAME 400 /* Longest filename generated */ ! 16: #define NBPC 8 /* Bits per char (for bitmap) */ ! 17: #define IBLK 12 /* I-node read blocking factor */ ! 18: #define NINUM 20 /* Maximum number of i-numbers to look for */ ! 19: #define ESEEN 0200 /* Seen bit for ENTRY */ ! 20: #define unpack() l3tol(addrs, ip->di_addr, NADDR) ! 21: ! 22: /* Functions to test for directory or setuid/special i-numbers */ ! 23: #define test(bm,i) (bm[(i)/NBPC] & 1<<((i)%NBPC)) ! 24: #define mark(bm,i) (bm[(i)/NBPC] |= 1<<((i)%NBPC)) ! 25: ! 26: /* ! 27: * Tables used by imap. ! 28: * This effectively implements ! 29: * the access polynomial for the indirect ! 30: * blocks. ! 31: */ ! 32: #undef NI ! 33: #define NI 1 ! 34: #define NII 1 ! 35: #define NIII 1 ! 36: static daddr_t ranges[] = { ! 37: ND, ! 38: ND + (daddr_t)NI*NBN, ! 39: ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN, ! 40: ND + (daddr_t)NI*NBN + (daddr_t)NII*NBN*NBN + (daddr_t)NIII*NBN*NBN*NBN, ! 41: }; ! 42: ! 43: static char offsets[] = { ! 44: 0, ! 45: ND, ! 46: ND+NI, ! 47: ND+NI+NII, ! 48: }; ! 49: ! 50: static daddr_t coeff[] = { ! 51: 1, (daddr_t)NBN, (daddr_t)NBN*NBN, (daddr_t)NBN*NBN*NBN ! 52: }; ! 53: ! 54: /* ! 55: * Default filesystem names ! 56: * to check. ! 57: */ ! 58: char *defnames[] = { ! 59: "/dev/rrm00", ! 60: NULL ! 61: }; ! 62: ! 63: char tmi[] = "ncheck: too many i-numbers given\n"; ! 64: char irderr[] = "ncheck: inode read error -- pass %d\n"; ! 65: ! 66: /* ! 67: * An entry for each directory ! 68: * name in the system containing ! 69: * the current i-number and the ! 70: * parent and the name. ! 71: */ ! 72: typedef struct ENTRY { ! 73: struct ENTRY *e_next; ! 74: ino_t e_pino; /* Parent i-number */ ! 75: ino_t e_cino; /* Current i-number */ ! 76: char e_name[]; /* Name */ ! 77: } ENTRY; ! 78: ! 79: ENTRY *entries[NHASH]; /* Hashed entries */ ! 80: ! 81: char *dbmap; /* Directory I-node bit-map */ ! 82: char *sbmap; /* Special + setuid i-node bitmap */ ! 83: ! 84: int ninumber; ! 85: ino_t inums[NINUM]; ! 86: char superb[BSIZE]; ! 87: char ibuf[BSIZE*IBLK]; ! 88: char dbuf[BSIZE]; ! 89: char namebuf[NFNAME]; ! 90: ! 91: int aflag; /* All (print "." and ".." names) flag */ ! 92: int sflag; /* Special and setuid files */ ! 93: int uflag; /* Print unreferenced structure */ ! 94: int exstat; /* Exit status */ ! 95: int fsfd; /* File system file descriptor */ ! 96: daddr_t fsize = SUPERI+1; /* Allow read of super-block */ ! 97: ino_t isize; ! 98: ino_t maxino; ! 99: ! 100: daddr_t imap(); ! 101: char *malloc(); ! 102: ! 103: main(argc, argv) ! 104: char *argv[]; ! 105: { ! 106: ! 107: while (argc>1 && *argv[1]=='-') { ! 108: switch (argv[1][1]) { ! 109: case 'a': ! 110: aflag = 1; ! 111: break; ! 112: ! 113: case 'i': ! 114: for (;;) { ! 115: if (ninumber >= NINUM) { ! 116: fprintf(stderr, tmi); ! 117: exstat = 1; ! 118: break; ! 119: } ! 120: if ((inums[ninumber] = atoi(argv[2])) == 0) ! 121: break; ! 122: argv++; ! 123: argc--; ! 124: ninumber++; ! 125: } ! 126: break; ! 127: ! 128: case 's': ! 129: sflag = 1; ! 130: break; ! 131: ! 132: case 'u': /* Unimplemented search for orphan structure */ ! 133: uflag = 1; ! 134: break; ! 135: ! 136: default: ! 137: usage(); ! 138: } ! 139: argc--; ! 140: argv++; ! 141: } ! 142: if (argc > 1) ! 143: allcheck(argv+1); else ! 144: allcheck(defnames); ! 145: exit(exstat); ! 146: } ! 147: ! 148: /* ! 149: * Check the given list of filesystems ! 150: */ ! 151: allcheck(fsl) ! 152: register char **fsl; ! 153: { ! 154: while (*fsl != NULL) ! 155: ncheck(*fsl++); ! 156: } ! 157: ! 158: /* ! 159: * Do `ncheck' for each filesystem. ! 160: */ ! 161: ncheck(fsname) ! 162: char *fsname; ! 163: { ! 164: register struct filsys *sbp; ! 165: register unsigned nb; ! 166: ! 167: if ((fsfd = open(fsname, 0)) < 0) { ! 168: fprintf(stderr, "%s: cannot open\n", fsname); ! 169: exstat = 1; ! 170: return; ! 171: } ! 172: printf( "%s:\n", fsname); ! 173: sync(); ! 174: bread((daddr_t)SUPERI, superb); ! 175: sbp = superb; ! 176: ! 177: canshort(sbp->s_isize); ! 178: candaddr(sbp->s_fsize); ! 179: ! 180: fsize = sbp->s_fsize; ! 181: isize = sbp->s_isize; ! 182: if (isize<INODEI+1 || isize>=fsize) ! 183: cerr("Ridiculous fsize/isize"); ! 184: maxino = (isize-INODEI) * INOPB; ! 185: nb = (maxino+NBPC)/NBPC; ! 186: if ((dbmap = malloc(nb)) == NULL) ! 187: cerr("Out of memory for directory bit map"); ! 188: bclear(dbmap, nb); ! 189: if (sflag) { ! 190: if ((sbmap = malloc(nb)) == NULL) ! 191: cerr("Out of memory for special/setuid bit map"); ! 192: bclear(sbmap, nb); ! 193: } ! 194: pass1(); ! 195: pass2(); ! 196: pass3(); ! 197: mfree(); ! 198: close(fsfd); ! 199: } ! 200: ! 201: /* ! 202: * Pass one consists of running down each ! 203: * I-node and marking those that are directories. ! 204: * This is used to tell which directory entries are ! 205: * to be saved in the hash chains in pass 2. ! 206: */ ! 207: pass1() ! 208: { ! 209: register struct dinode *ip; ! 210: register ino_t inum; ! 211: register int i; ! 212: register unsigned imax; ! 213: fsize_t seek; ! 214: ! 215: inum = 1; ! 216: seek = INODEI*BSIZE; ! 217: for (i=maxino; i>0; i -= IBLK*INOPB) { ! 218: lseek(fsfd, seek, 0); ! 219: imax = i>IBLK*INOPB ? IBLK*INOPB : i; ! 220: imax *= sizeof (struct dinode); ! 221: seek += imax; ! 222: if (read(fsfd, ibuf, imax) != imax) { ! 223: fprintf(stderr, irderr, 1); ! 224: exstat = 1; ! 225: return; ! 226: } ! 227: for (ip = ibuf; ip < &ibuf[imax]; ip++) { ! 228: canshort(ip->di_mode); ! 229: canshort(ip->di_nlink); ! 230: if ((ip->di_mode & IFMT) == IFDIR) ! 231: mark(dbmap, inum); ! 232: if (sflag && ip->di_mode&(ISUID|ISGID|IFBLK|IFCHR)) ! 233: mark(sbmap, inum); ! 234: inum++; ! 235: } ! 236: } ! 237: } ! 238: ! 239: /* ! 240: * Pass two scans the i-list looking for ! 241: * all directories. For each directory ! 242: * entry in each of these found, it ! 243: * saves each name and i-number pair which ! 244: * is itself a directory (as determined ! 245: * by the bitmap computed in pass1). ! 246: */ ! 247: pass2() ! 248: { ! 249: register struct dinode *ip; ! 250: register ino_t inum; ! 251: register int i; ! 252: register unsigned imax; ! 253: fsize_t seek; ! 254: ! 255: inum = 1; ! 256: seek = INODEI*BSIZE; ! 257: for (i=maxino; i>0; i -= IBLK*INOPB) { ! 258: lseek(fsfd, seek, 0); ! 259: imax = i>IBLK*INOPB ? IBLK*INOPB : i; ! 260: imax *= sizeof (struct dinode); ! 261: seek += imax; ! 262: if (read(fsfd, ibuf, imax) != imax) { ! 263: fprintf(stderr, irderr, 2); ! 264: exstat = 1; ! 265: return; ! 266: } ! 267: for (ip = ibuf; ip < &ibuf[imax]; ip++) { ! 268: canshort(ip->di_mode); ! 269: canshort(ip->di_nlink); ! 270: cansize(ip->di_size); ! 271: if ((ip->di_mode & IFMT) == IFDIR) ! 272: finddirs(ip, inum); ! 273: inum++; ! 274: } ! 275: } ! 276: } ! 277: ! 278: /* ! 279: * Pass 3 uses the hashed table prodeuced ! 280: * during pass1 and pass2 to generate ! 281: * the output information that was ! 282: * requested by the command line. ! 283: */ ! 284: pass3() ! 285: { ! 286: register struct dinode *ip; ! 287: register ino_t inum; ! 288: register int i; ! 289: register unsigned imax; ! 290: fsize_t seek; ! 291: ! 292: inum = 1; ! 293: seek = INODEI*BSIZE; ! 294: if (!sflag && (ninumber==0 || iarg(ROOTIN))) ! 295: printf( "%u\t/.\n", ROOTIN); ! 296: for (i=maxino; i>0; i -= IBLK*INOPB) { ! 297: lseek(fsfd, seek, 0); ! 298: imax = i>IBLK*INOPB ? IBLK*INOPB : i; ! 299: imax *= sizeof (struct dinode); ! 300: seek += imax; ! 301: if (read(fsfd, ibuf, imax) != imax) { ! 302: fprintf(stderr, irderr, 3); ! 303: exstat = 1; ! 304: return; ! 305: } ! 306: for (ip = ibuf; ip < &ibuf[imax]; ip++) { ! 307: canshort(ip->di_mode); ! 308: canshort(ip->di_nlink); ! 309: cansize(ip->di_size); ! 310: if ((ip->di_mode & IFMT) == IFDIR) ! 311: printdir(ip, inum); ! 312: inum++; ! 313: } ! 314: } ! 315: } ! 316: ! 317: /* ! 318: * Find all entries in this directory i-node ! 319: * that are themselves directories. ! 320: */ ! 321: finddirs(ip, inum) ! 322: register struct dinode *ip; ! 323: register ino_t inum; ! 324: { ! 325: fsize_t size; ! 326: daddr_t pb, bn; ! 327: ! 328: size = ip->di_size; ! 329: bn = 0; ! 330: while (size >= sizeof(struct direct)) { ! 331: register struct direct *dp; ! 332: ! 333: if ((pb = imap(ip, bn++)) == 0) ! 334: break; ! 335: bread(pb, dbuf); ! 336: for (dp=dbuf; dp < &dbuf[BSIZE]; dp++) { ! 337: canino( dp->d_ino); ! 338: if (dp->d_ino) { ! 339: if (dp->d_ino > maxino) ! 340: dirline(inum, dp, "bad"); ! 341: else if (test(dbmap, dp->d_ino)) ! 342: direnter(dp, inum); ! 343: } ! 344: size -= sizeof( struct direct); ! 345: if (size == 0) ! 346: break; ! 347: } ! 348: } ! 349: } ! 350: ! 351: /* ! 352: * Print all of the names found ! 353: * in this directory. ! 354: */ ! 355: printdir(ip, ino) ! 356: register struct dinode *ip; ! 357: register ino_t ino; ! 358: { ! 359: fsize_t size; ! 360: daddr_t pb, bn; ! 361: ! 362: size = ip->di_size; ! 363: bn = 0; ! 364: while (size >= sizeof(struct direct)) { ! 365: register struct direct *dp; ! 366: ! 367: if ((pb = imap(ip, bn++)) == 0) ! 368: break; ! 369: bread(pb, dbuf); ! 370: for (dp=dbuf; dp < &dbuf[BSIZE]; dp++) { ! 371: canino( dp->d_ino); ! 372: if (dp->d_ino) { ! 373: if (dp->d_ino > maxino) ! 374: continue; ! 375: if (sflag && !test(sbmap, dp->d_ino)) ! 376: continue; ! 377: if (ninumber!=0 && !iarg(dp->d_ino)) ! 378: continue; ! 379: outname(dp, ino); ! 380: } ! 381: size -= sizeof( struct direct); ! 382: if (size == 0) ! 383: break; ! 384: } ! 385: } ! 386: } ! 387: ! 388: /* ! 389: * Print out the actual name by ! 390: * traversing the structures ! 391: * for a directory entry. ! 392: */ ! 393: outname(dp, ino) ! 394: register struct direct *dp; ! 395: ino_t ino; ! 396: { ! 397: register char *np; ! 398: ! 399: np = dp->d_name; ! 400: if (!aflag && *np++=='.') ! 401: if ((*np=='.' && np[1]=='\0') || *np=='\0') ! 402: return; ! 403: np = &namebuf[NFNAME]; ! 404: *--np = '\0'; ! 405: if (!aflag && test(dbmap, dp->d_ino)) { ! 406: *--np = '.'; ! 407: *--np = '/'; ! 408: } ! 409: { ! 410: register char *cp; ! 411: ! 412: for (cp = dp->d_name; cp < &dp->d_name[DIRSIZ]; cp++) ! 413: if (*cp == '\0') ! 414: break; ! 415: while (cp > dp->d_name) ! 416: *--np = *--cp; ! 417: *--np = '/'; ! 418: } ! 419: outpart(np, ino, dp->d_ino); ! 420: } ! 421: ! 422: /* ! 423: * Put out each name part. ! 424: * Either get to the root ! 425: * or find no parent. ! 426: * `ep' is the pointer running ! 427: * backwards in the namebuf. ! 428: */ ! 429: outpart(np, ino, oino) ! 430: register char *np; ! 431: ino_t ino; ! 432: ino_t oino; ! 433: { ! 434: register ENTRY *ep; ! 435: register char *cp; ! 436: register int found = 0; ! 437: register char *snp; ! 438: ! 439: if (ino != ROOTIN) { ! 440: for (ep = entries[ino%NHASH]; ep != NULL; ep = ep->e_next) ! 441: if (ep->e_cino == ino) { ! 442: if (ep->e_name[0] & ESEEN) { ! 443: *--np = '.'; ! 444: *--np = '.'; ! 445: *--np = '.'; ! 446: return; ! 447: } ! 448: snp = np; ! 449: cp = &ep->e_name[strlen(ep->e_name)]; ! 450: while (cp > ep->e_name) ! 451: *--np = *--cp; ! 452: *--np = '/'; ! 453: ep->e_name[0] |= ESEEN; ! 454: found = 1; ! 455: if (np > namebuf+DIRSIZ) ! 456: outpart(np, ep->e_pino, oino); ! 457: ep->e_name[0] &= ~ESEEN; ! 458: np = snp; ! 459: } ! 460: if (!found) { ! 461: *--np = '?'; ! 462: *--np = '?'; ! 463: } ! 464: } ! 465: if (!found || ino==ROOTIN) ! 466: printf( "%u\t%s\n", oino, np); ! 467: } ! 468: ! 469: /* ! 470: * Enter a directory entry and the current ! 471: * i-number into the chained hash table ! 472: * for use by pass 3. ! 473: */ ! 474: direnter(dp, ino) ! 475: register struct direct *dp; ! 476: ino_t ino; ! 477: { ! 478: register ENTRY *ep; ! 479: register char *cp; ! 480: register int n; ! 481: ! 482: cp = dp->d_name; ! 483: if (*cp++ == '.') ! 484: if ((*cp=='.' && cp[1]=='\0') || *cp=='\0') ! 485: return; ! 486: for (cp = dp->d_name; *cp != '\0'; cp++) ! 487: if (cp >= &dp->d_name[DIRSIZ]) ! 488: break; ! 489: n = cp - dp->d_name; ! 490: if ((ep = (ENTRY *)malloc(n+sizeof(char)+sizeof(ENTRY))) == NULL) ! 491: cerr("Out of memory for directory entries"); ! 492: ep->e_pino = ino; ! 493: ep->e_cino = dp->d_ino; ! 494: strncpy(ep->e_name, dp->d_name, n); ! 495: ep->e_name[n] = '\0'; ! 496: /* ! 497: * Compute hash and store in entries table. ! 498: */ ! 499: n = ep->e_cino%NHASH; ! 500: ep->e_next = entries[n]; ! 501: entries[n] = ep; ! 502: } ! 503: ! 504: /* ! 505: * Return true if the argument ! 506: * i-node is the one of the `-i' ! 507: * arguments. ! 508: */ ! 509: iarg(ino) ! 510: register ino_t ino; ! 511: { ! 512: register int i; ! 513: ! 514: for (i=0; i<ninumber; i++) ! 515: if (inums[i] == ino) ! 516: return (1); ! 517: return (0); ! 518: } ! 519: ! 520: /* ! 521: * Print out a line for a directory ! 522: * that is found in the search (e.g. ! 523: * bad or argument directories). ! 524: */ ! 525: dirline(ino, dp, str) ! 526: ino_t ino; ! 527: register struct direct *dp; ! 528: char *str; ! 529: { ! 530: printf("%u %s: %u/%-*.*s\n", dp->d_ino, str, ino, ! 531: DIRSIZ, DIRSIZ, dp->d_name); ! 532: } ! 533: ! 534: /* ! 535: * For a given inode (`ip'), ! 536: * map a logical block number (`bn') ! 537: * onto a physical disc block number. ! 538: */ ! 539: daddr_t ! 540: imap(ip, lb) ! 541: register struct dinode *ip; ! 542: daddr_t lb; ! 543: { ! 544: register il; ! 545: daddr_t bpos, pb; ! 546: register daddr_t *bp; ! 547: register daddr_t addrs[NADDR]; ! 548: ! 549: unpack(); ! 550: for (il=0; il<4; il++) ! 551: if (lb < ranges[il]) { ! 552: if (il != 0) ! 553: lb -= ranges[il-1]; ! 554: bpos = lb/coeff[il]; ! 555: lb %= coeff[il]; ! 556: bp = &addrs[(int)bpos + offsets[il]]; ! 557: if ((pb = *bp) != 0) { ! 558: /* ! 559: * Map through indirect ! 560: * blocks here. ! 561: */ ! 562: while (il-- > 0) { ! 563: bread(pb, dbuf); ! 564: bpos = lb/coeff[il]; ! 565: lb %= coeff[il]; ! 566: bp = (daddr_t *)dbuf + bpos; ! 567: if ((pb = *bp) == 0) ! 568: break; ! 569: pb = *bp; ! 570: candaddr( pb); ! 571: } ! 572: } ! 573: return (pb); ! 574: } ! 575: return (0); ! 576: } ! 577: ! 578: /* ! 579: * Read the specified block number ! 580: * into `buf'. ! 581: */ ! 582: bread(bn, buf) ! 583: daddr_t bn; ! 584: char *buf; ! 585: { ! 586: if (bn >= fsize) { ! 587: badblock(bn); ! 588: bclear(buf, BSIZE); ! 589: return; ! 590: } ! 591: lseek(fsfd, (fsize_t)BSIZE * bn, 0); ! 592: if (read(fsfd, buf, BSIZE) != BSIZE) { ! 593: fprintf(stderr, "ncheck: Read error %ld\n", (long)bn); ! 594: exstat = 1; ! 595: bclear(buf, BSIZE); ! 596: } ! 597: } ! 598: ! 599: /* ! 600: * Clear a block of memory ! 601: * pointed to by `bp' for size ! 602: * `nb' bytes. ! 603: */ ! 604: bclear(bp, nb) ! 605: register char *bp; ! 606: register unsigned nb; ! 607: { ! 608: if (nb) ! 609: do { ! 610: *bp++ = 0; ! 611: } while (--nb); ! 612: } ! 613: ! 614: /* ! 615: * free scratch memory ! 616: * Space used to check a filesystem is freed. This includes bitmaps ! 617: * and directory entries. ! 618: */ ! 619: mfree( ) ! 620: { ! 621: register ENTRY *ep, ! 622: **epp; ! 623: ! 624: for (epp=entries; epp<&entries[NHASH]; ) { ! 625: for (ep= *epp; ep; ep=ep->e_next) ! 626: free( (char *)ep); ! 627: *epp++ = NULL; ! 628: } ! 629: free( dbmap); ! 630: if (sbmap) ! 631: free( sbmap); ! 632: } ! 633: ! 634: /* ! 635: * Error routines ! 636: */ ! 637: badblock(bn) ! 638: daddr_t bn; ! 639: { ! 640: fprintf(stderr, "ncheck: bad block #%ld\n", (long)bn); ! 641: exstat = 1; ! 642: } ! 643: ! 644: /* ! 645: * Unrecoverable errors ! 646: */ ! 647: cerr(x) ! 648: { ! 649: fprintf(stderr, "ncheck: %r\n", &x); ! 650: exit(1); ! 651: } ! 652: ! 653: usage() ! 654: { ! 655: fprintf(stderr, "Usage: ncheck [-a] [-s] [-i ino ...] [filesystem ...]"); ! 656: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.