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

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

unix.superglobalmegacorp.com

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