Annotation of coherent/d/bin/check/ncheck.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.