Annotation of 43BSDReno/sbin/fsck/utilities.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980, 1986 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted provided
                      6:  * that: (1) source distributions retain this entire copyright notice and
                      7:  * comment, and (2) distributions including binaries display the following
                      8:  * acknowledgement:  ``This product includes software developed by the
                      9:  * University of California, Berkeley and its contributors'' in the
                     10:  * documentation or other materials provided with the distribution and in
                     11:  * all advertising materials mentioning features or use of this software.
                     12:  * Neither the name of the University nor the names of its contributors may
                     13:  * be used to endorse or promote products derived from this software without
                     14:  * specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: static char sccsid[] = "@(#)utilities.c        5.29 (Berkeley) 7/27/90";
                     22: #endif /* not lint */
                     23: 
                     24: #include <sys/param.h>
                     25: #include <ufs/dinode.h>
                     26: #include <ufs/fs.h>
                     27: #include <ufs/dir.h>
                     28: #include <stdio.h>
                     29: #include <stdlib.h>
                     30: #include <string.h>
                     31: #include <ctype.h>
                     32: #include "fsck.h"
                     33: 
                     34: long   diskreads, totalreads;  /* Disk cache statistics */
                     35: long   lseek();
                     36: 
                     37: ftypeok(dp)
                     38:        struct dinode *dp;
                     39: {
                     40:        switch (dp->di_mode & IFMT) {
                     41: 
                     42:        case IFDIR:
                     43:        case IFREG:
                     44:        case IFBLK:
                     45:        case IFCHR:
                     46:        case IFLNK:
                     47:        case IFSOCK:
                     48:        case IFIFO:
                     49:                return (1);
                     50: 
                     51:        default:
                     52:                if (debug)
                     53:                        printf("bad file type 0%o\n", dp->di_mode);
                     54:                return (0);
                     55:        }
                     56: }
                     57: 
                     58: reply(question)
                     59:        char *question;
                     60: {
                     61:        int persevere;
                     62:        char c;
                     63: 
                     64:        if (preen)
                     65:                pfatal("INTERNAL ERROR: GOT TO reply()");
                     66:        persevere = !strcmp(question, "CONTINUE");
                     67:        printf("\n");
                     68:        if (!persevere && (nflag || fswritefd < 0)) {
                     69:                printf("%s? no\n\n", question);
                     70:                return (0);
                     71:        }
                     72:        if (yflag || (persevere && nflag)) {
                     73:                printf("%s? yes\n\n", question);
                     74:                return (1);
                     75:        }
                     76:        do      {
                     77:                printf("%s? [yn] ", question);
                     78:                (void) fflush(stdout);
                     79:                c = getc(stdin);
                     80:                while (c != '\n' && getc(stdin) != '\n')
                     81:                        if (feof(stdin))
                     82:                                return (0);
                     83:        } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
                     84:        printf("\n");
                     85:        if (c == 'y' || c == 'Y')
                     86:                return (1);
                     87:        return (0);
                     88: }
                     89: 
                     90: /*
                     91:  * Malloc buffers and set up cache.
                     92:  */
                     93: bufinit()
                     94: {
                     95:        register struct bufarea *bp;
                     96:        long bufcnt, i;
                     97:        char *bufp;
                     98: 
                     99:        pbp = pdirbp = (struct bufarea *)0;
                    100:        bufp = malloc((unsigned int)sblock.fs_bsize);
                    101:        if (bufp == 0)
                    102:                errexit("cannot allocate buffer pool\n");
                    103:        cgblk.b_un.b_buf = bufp;
                    104:        initbarea(&cgblk);
                    105:        bufhead.b_next = bufhead.b_prev = &bufhead;
                    106:        bufcnt = MAXBUFSPACE / sblock.fs_bsize;
                    107:        if (bufcnt < MINBUFS)
                    108:                bufcnt = MINBUFS;
                    109:        for (i = 0; i < bufcnt; i++) {
                    110:                bp = (struct bufarea *)malloc(sizeof(struct bufarea));
                    111:                bufp = malloc((unsigned int)sblock.fs_bsize);
                    112:                if (bp == NULL || bufp == NULL) {
                    113:                        if (i >= MINBUFS)
                    114:                                break;
                    115:                        errexit("cannot allocate buffer pool\n");
                    116:                }
                    117:                bp->b_un.b_buf = bufp;
                    118:                bp->b_prev = &bufhead;
                    119:                bp->b_next = bufhead.b_next;
                    120:                bufhead.b_next->b_prev = bp;
                    121:                bufhead.b_next = bp;
                    122:                initbarea(bp);
                    123:        }
                    124:        bufhead.b_size = i;     /* save number of buffers */
                    125: }
                    126: 
                    127: /*
                    128:  * Manage a cache of directory blocks.
                    129:  */
                    130: struct bufarea *
                    131: getdatablk(blkno, size)
                    132:        daddr_t blkno;
                    133:        long size;
                    134: {
                    135:        register struct bufarea *bp;
                    136: 
                    137:        for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
                    138:                if (bp->b_bno == fsbtodb(&sblock, blkno))
                    139:                        goto foundit;
                    140:        for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
                    141:                if ((bp->b_flags & B_INUSE) == 0)
                    142:                        break;
                    143:        if (bp == &bufhead)
                    144:                errexit("deadlocked buffer pool\n");
                    145:        getblk(bp, blkno, size);
                    146:        /* fall through */
                    147: foundit:
                    148:        totalreads++;
                    149:        bp->b_prev->b_next = bp->b_next;
                    150:        bp->b_next->b_prev = bp->b_prev;
                    151:        bp->b_prev = &bufhead;
                    152:        bp->b_next = bufhead.b_next;
                    153:        bufhead.b_next->b_prev = bp;
                    154:        bufhead.b_next = bp;
                    155:        bp->b_flags |= B_INUSE;
                    156:        return (bp);
                    157: }
                    158: 
                    159: void
                    160: getblk(bp, blk, size)
                    161:        register struct bufarea *bp;
                    162:        daddr_t blk;
                    163:        long size;
                    164: {
                    165:        daddr_t dblk;
                    166: 
                    167:        dblk = fsbtodb(&sblock, blk);
                    168:        if (bp->b_bno != dblk) {
                    169:                flush(fswritefd, bp);
                    170:                diskreads++;
                    171:                bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
                    172:                bp->b_bno = dblk;
                    173:                bp->b_size = size;
                    174:        }
                    175: }
                    176: 
                    177: flush(fd, bp)
                    178:        int fd;
                    179:        register struct bufarea *bp;
                    180: {
                    181:        register int i, j;
                    182: 
                    183:        if (!bp->b_dirty)
                    184:                return;
                    185:        if (bp->b_errs != 0)
                    186:                pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
                    187:                    (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
                    188:                    bp->b_bno);
                    189:        bp->b_dirty = 0;
                    190:        bp->b_errs = 0;
                    191:        bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
                    192:        if (bp != &sblk)
                    193:                return;
                    194:        for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
                    195:                bwrite(fswritefd, (char *)sblock.fs_csp[j],
                    196:                    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
                    197:                    sblock.fs_cssize - i < sblock.fs_bsize ?
                    198:                    sblock.fs_cssize - i : sblock.fs_bsize);
                    199:        }
                    200: }
                    201: 
                    202: rwerror(mesg, blk)
                    203:        char *mesg;
                    204:        daddr_t blk;
                    205: {
                    206: 
                    207:        if (preen == 0)
                    208:                printf("\n");
                    209:        pfatal("CANNOT %s: BLK %ld", mesg, blk);
                    210:        if (reply("CONTINUE") == 0)
                    211:                errexit("Program terminated\n");
                    212: }
                    213: 
                    214: ckfini()
                    215: {
                    216:        register struct bufarea *bp, *nbp;
                    217:        int cnt = 0;
                    218: 
                    219:        flush(fswritefd, &sblk);
                    220:        if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
                    221:            !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
                    222:                sblk.b_bno = SBOFF / dev_bsize;
                    223:                sbdirty();
                    224:                flush(fswritefd, &sblk);
                    225:        }
                    226:        flush(fswritefd, &cgblk);
                    227:        free(cgblk.b_un.b_buf);
                    228:        for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) {
                    229:                cnt++;
                    230:                flush(fswritefd, bp);
                    231:                nbp = bp->b_prev;
                    232:                free(bp->b_un.b_buf);
                    233:                free((char *)bp);
                    234:        }
                    235:        if (bufhead.b_size != cnt)
                    236:                errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
                    237:        pbp = pdirbp = (struct bufarea *)0;
                    238:        if (debug)
                    239:                printf("cache missed %ld of %ld (%d%%)\n", diskreads,
                    240:                    totalreads, (int)(diskreads * 100 / totalreads));
                    241:        (void)close(fsreadfd);
                    242:        (void)close(fswritefd);
                    243: }
                    244: 
                    245: bread(fd, buf, blk, size)
                    246:        int fd;
                    247:        char *buf;
                    248:        daddr_t blk;
                    249:        long size;
                    250: {
                    251:        char *cp;
                    252:        int i, errs;
                    253: 
                    254:        if (lseek(fd, blk * dev_bsize, 0) < 0)
                    255:                rwerror("SEEK", blk);
                    256:        else if (read(fd, buf, (int)size) == size)
                    257:                return (0);
                    258:        rwerror("READ", blk);
                    259:        if (lseek(fd, blk * dev_bsize, 0) < 0)
                    260:                rwerror("SEEK", blk);
                    261:        errs = 0;
                    262:        bzero(buf, (size_t)size);
                    263:        printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
                    264:        for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
                    265:                if (read(fd, cp, (int)secsize) != secsize) {
                    266:                        (void)lseek(fd, blk * dev_bsize + i + secsize, 0);
                    267:                        if (secsize != dev_bsize && dev_bsize != 1)
                    268:                                printf(" %ld (%ld),",
                    269:                                    (blk * dev_bsize + i) / secsize,
                    270:                                    blk + i / dev_bsize);
                    271:                        else
                    272:                                printf(" %ld,", blk + i / dev_bsize);
                    273:                        errs++;
                    274:                }
                    275:        }
                    276:        printf("\n");
                    277:        return (errs);
                    278: }
                    279: 
                    280: bwrite(fd, buf, blk, size)
                    281:        int fd;
                    282:        char *buf;
                    283:        daddr_t blk;
                    284:        long size;
                    285: {
                    286:        int i;
                    287:        char *cp;
                    288: 
                    289:        if (fd < 0)
                    290:                return;
                    291:        if (lseek(fd, blk * dev_bsize, 0) < 0)
                    292:                rwerror("SEEK", blk);
                    293:        else if (write(fd, buf, (int)size) == size) {
                    294:                fsmodified = 1;
                    295:                return;
                    296:        }
                    297:        rwerror("WRITE", blk);
                    298:        if (lseek(fd, blk * dev_bsize, 0) < 0)
                    299:                rwerror("SEEK", blk);
                    300:        printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
                    301:        for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
                    302:                if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
                    303:                        (void)lseek(fd, blk * dev_bsize + i + dev_bsize, 0);
                    304:                        printf(" %ld,", blk + i / dev_bsize);
                    305:                }
                    306:        printf("\n");
                    307:        return;
                    308: }
                    309: 
                    310: /*
                    311:  * allocate a data block with the specified number of fragments
                    312:  */
                    313: allocblk(frags)
                    314:        long frags;
                    315: {
                    316:        register int i, j, k;
                    317: 
                    318:        if (frags <= 0 || frags > sblock.fs_frag)
                    319:                return (0);
                    320:        for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
                    321:                for (j = 0; j <= sblock.fs_frag - frags; j++) {
                    322:                        if (testbmap(i + j))
                    323:                                continue;
                    324:                        for (k = 1; k < frags; k++)
                    325:                                if (testbmap(i + j + k))
                    326:                                        break;
                    327:                        if (k < frags) {
                    328:                                j += k;
                    329:                                continue;
                    330:                        }
                    331:                        for (k = 0; k < frags; k++)
                    332:                                setbmap(i + j + k);
                    333:                        n_blks += frags;
                    334:                        return (i + j);
                    335:                }
                    336:        }
                    337:        return (0);
                    338: }
                    339: 
                    340: /*
                    341:  * Free a previously allocated block
                    342:  */
                    343: freeblk(blkno, frags)
                    344:        daddr_t blkno;
                    345:        long frags;
                    346: {
                    347:        struct inodesc idesc;
                    348: 
                    349:        idesc.id_blkno = blkno;
                    350:        idesc.id_numfrags = frags;
                    351:        (void)pass4check(&idesc);
                    352: }
                    353: 
                    354: /*
                    355:  * Find a pathname
                    356:  */
                    357: getpathname(namebuf, curdir, ino)
                    358:        char *namebuf;
                    359:        ino_t curdir, ino;
                    360: {
                    361:        int len;
                    362:        register char *cp;
                    363:        struct inodesc idesc;
                    364:        static int busy = 0;
                    365:        extern int findname();
                    366: 
                    367:        if (busy ||
                    368:            (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
                    369:                (void)strcpy(namebuf, "?");
                    370:                return;
                    371:        }
                    372:        busy = 1;
                    373:        bzero((char *)&idesc, sizeof(struct inodesc));
                    374:        idesc.id_type = DATA;
                    375:        idesc.id_fix = IGNORE;
                    376:        cp = &namebuf[MAXPATHLEN - 1];
                    377:        *cp = '\0';
                    378:        if (curdir != ino) {
                    379:                idesc.id_parent = curdir;
                    380:                goto namelookup;
                    381:        }
                    382:        while (ino != ROOTINO) {
                    383:                idesc.id_number = ino;
                    384:                idesc.id_func = findino;
                    385:                idesc.id_name = "..";
                    386:                if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
                    387:                        break;
                    388:        namelookup:
                    389:                idesc.id_number = idesc.id_parent;
                    390:                idesc.id_parent = ino;
                    391:                idesc.id_func = findname;
                    392:                idesc.id_name = namebuf;
                    393:                if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
                    394:                        break;
                    395:                len = strlen(namebuf);
                    396:                cp -= len;
                    397:                if (cp < &namebuf[MAXNAMLEN])
                    398:                        break;
                    399:                bcopy(namebuf, cp, (size_t)len);
                    400:                *--cp = '/';
                    401:                ino = idesc.id_number;
                    402:        }
                    403:        busy = 0;
                    404:        if (ino != ROOTINO) {
                    405:                (void)strcpy(namebuf, "?");
                    406:                return;
                    407:        }
                    408:        bcopy(cp, namebuf, (size_t)(&namebuf[MAXPATHLEN] - cp));
                    409: }
                    410: 
                    411: void
                    412: catch()
                    413: {
                    414:        ckfini();
                    415:        exit(12);
                    416: }
                    417: 
                    418: /*
                    419:  * When preening, allow a single quit to signal
                    420:  * a special exit after filesystem checks complete
                    421:  * so that reboot sequence may be interrupted.
                    422:  */
                    423: void
                    424: catchquit()
                    425: {
                    426:        extern returntosingle;
                    427: 
                    428:        printf("returning to single-user after filesystem check\n");
                    429:        returntosingle = 1;
                    430:        (void)signal(SIGQUIT, SIG_DFL);
                    431: }
                    432: 
                    433: /*
                    434:  * Ignore a single quit signal; wait and flush just in case.
                    435:  * Used by child processes in preen.
                    436:  */
                    437: void
                    438: voidquit()
                    439: {
                    440: 
                    441:        sleep(1);
                    442:        (void)signal(SIGQUIT, SIG_IGN);
                    443:        (void)signal(SIGQUIT, SIG_DFL);
                    444: }
                    445: 
                    446: /*
                    447:  * determine whether an inode should be fixed.
                    448:  */
                    449: dofix(idesc, msg)
                    450:        register struct inodesc *idesc;
                    451:        char *msg;
                    452: {
                    453: 
                    454:        switch (idesc->id_fix) {
                    455: 
                    456:        case DONTKNOW:
                    457:                if (idesc->id_type == DATA)
                    458:                        direrror(idesc->id_number, msg);
                    459:                else
                    460:                        pwarn(msg);
                    461:                if (preen) {
                    462:                        printf(" (SALVAGED)\n");
                    463:                        idesc->id_fix = FIX;
                    464:                        return (ALTERED);
                    465:                }
                    466:                if (reply("SALVAGE") == 0) {
                    467:                        idesc->id_fix = NOFIX;
                    468:                        return (0);
                    469:                }
                    470:                idesc->id_fix = FIX;
                    471:                return (ALTERED);
                    472: 
                    473:        case FIX:
                    474:                return (ALTERED);
                    475: 
                    476:        case NOFIX:
                    477:        case IGNORE:
                    478:                return (0);
                    479: 
                    480:        default:
                    481:                errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
                    482:        }
                    483:        /* NOTREACHED */
                    484: }
                    485: 
                    486: /* VARARGS1 */
                    487: errexit(s1, s2, s3, s4)
                    488:        char *s1;
                    489: {
                    490:        printf(s1, s2, s3, s4);
                    491:        exit(8);
                    492: }
                    493: 
                    494: /*
                    495:  * An unexpected inconsistency occured.
                    496:  * Die if preening, otherwise just print message and continue.
                    497:  */
                    498: /* VARARGS1 */
                    499: pfatal(s, a1, a2, a3)
                    500:        char *s;
                    501: {
                    502: 
                    503:        if (preen) {
                    504:                printf("%s: ", devname);
                    505:                printf(s, a1, a2, a3);
                    506:                printf("\n");
                    507:                printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
                    508:                        devname);
                    509:                exit(8);
                    510:        }
                    511:        printf(s, a1, a2, a3);
                    512: }
                    513: 
                    514: /*
                    515:  * Pwarn just prints a message when not preening,
                    516:  * or a warning (preceded by filename) when preening.
                    517:  */
                    518: /* VARARGS1 */
                    519: pwarn(s, a1, a2, a3, a4, a5, a6)
                    520:        char *s;
                    521: {
                    522: 
                    523:        if (preen)
                    524:                printf("%s: ", devname);
                    525:        printf(s, a1, a2, a3, a4, a5, a6);
                    526: }
                    527: 
                    528: #ifndef lint
                    529: /*
                    530:  * Stub for routines from kernel.
                    531:  */
                    532: panic(s)
                    533:        char *s;
                    534: {
                    535: 
                    536:        pfatal("INTERNAL INCONSISTENCY:");
                    537:        errexit(s);
                    538: }
                    539: #endif

unix.superglobalmegacorp.com

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