122055Sdist /* 2*61492Sbostic * Copyright (c) 1980, 1986, 1993 3*61492Sbostic * The Regents of the University of California. All rights reserved. 439976Smckusick * 542702Sbostic * %sccs.include.redist.c% 622055Sdist */ 722055Sdist 816269Smckusick #ifndef lint 9*61492Sbostic static char sccsid[] = "@(#)utilities.c 8.1 (Berkeley) 06/05/93"; 1039976Smckusick #endif /* not lint */ 1116269Smckusick 1216269Smckusick #include <sys/param.h> 1353703Smckusick #include <sys/time.h> 1451532Sbostic #include <ufs/ufs/dinode.h> 1551532Sbostic #include <ufs/ufs/dir.h> 1651532Sbostic #include <ufs/ffs/fs.h> 1739165Sbostic #include <stdio.h> 1844934Smckusick #include <stdlib.h> 1944934Smckusick #include <string.h> 2039165Sbostic #include <ctype.h> 2116269Smckusick #include "fsck.h" 2216269Smckusick 2334225Smckusick long diskreads, totalreads; /* Disk cache statistics */ 2416269Smckusick 2516269Smckusick ftypeok(dp) 2639973Smckusick struct dinode *dp; 2716269Smckusick { 2816269Smckusick switch (dp->di_mode & IFMT) { 2916269Smckusick 3016269Smckusick case IFDIR: 3116269Smckusick case IFREG: 3216269Smckusick case IFBLK: 3316269Smckusick case IFCHR: 3416269Smckusick case IFLNK: 3516269Smckusick case IFSOCK: 3642943Smckusick case IFIFO: 3716269Smckusick return (1); 3816269Smckusick 3916269Smckusick default: 4016269Smckusick if (debug) 4116269Smckusick printf("bad file type 0%o\n", dp->di_mode); 4216269Smckusick return (0); 4316269Smckusick } 4416269Smckusick } 4516269Smckusick 4639975Smckusick reply(question) 4739975Smckusick char *question; 4816269Smckusick { 4939975Smckusick int persevere; 5039975Smckusick char c; 5116269Smckusick 5216269Smckusick if (preen) 5316269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 5439975Smckusick persevere = !strcmp(question, "CONTINUE"); 5539975Smckusick printf("\n"); 5639975Smckusick if (!persevere && (nflag || fswritefd < 0)) { 5739975Smckusick printf("%s? no\n\n", question); 5816269Smckusick return (0); 5916269Smckusick } 6039975Smckusick if (yflag || (persevere && nflag)) { 6139975Smckusick printf("%s? yes\n\n", question); 6216269Smckusick return (1); 6316269Smckusick } 6439975Smckusick do { 6539975Smckusick printf("%s? [yn] ", question); 6639975Smckusick (void) fflush(stdout); 6739975Smckusick c = getc(stdin); 6839975Smckusick while (c != '\n' && getc(stdin) != '\n') 6939975Smckusick if (feof(stdin)) 7039975Smckusick return (0); 7139975Smckusick } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 7216269Smckusick printf("\n"); 7339975Smckusick if (c == 'y' || c == 'Y') 7416269Smckusick return (1); 7539975Smckusick return (0); 7616269Smckusick } 7716269Smckusick 7834225Smckusick /* 7934225Smckusick * Malloc buffers and set up cache. 8034225Smckusick */ 8134225Smckusick bufinit() 8234225Smckusick { 8339973Smckusick register struct bufarea *bp; 8434225Smckusick long bufcnt, i; 8534225Smckusick char *bufp; 8634225Smckusick 8740649Smckusick pbp = pdirbp = (struct bufarea *)0; 8839973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 8934225Smckusick if (bufp == 0) 9034225Smckusick errexit("cannot allocate buffer pool\n"); 9134225Smckusick cgblk.b_un.b_buf = bufp; 9234225Smckusick initbarea(&cgblk); 9334225Smckusick bufhead.b_next = bufhead.b_prev = &bufhead; 9434225Smckusick bufcnt = MAXBUFSPACE / sblock.fs_bsize; 9534225Smckusick if (bufcnt < MINBUFS) 9634225Smckusick bufcnt = MINBUFS; 9734225Smckusick for (i = 0; i < bufcnt; i++) { 9839973Smckusick bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 9939973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 10038377Smckusick if (bp == NULL || bufp == NULL) { 10134225Smckusick if (i >= MINBUFS) 10234225Smckusick break; 10334225Smckusick errexit("cannot allocate buffer pool\n"); 10434225Smckusick } 10534225Smckusick bp->b_un.b_buf = bufp; 10634225Smckusick bp->b_prev = &bufhead; 10734225Smckusick bp->b_next = bufhead.b_next; 10834225Smckusick bufhead.b_next->b_prev = bp; 10934225Smckusick bufhead.b_next = bp; 11034225Smckusick initbarea(bp); 11134225Smckusick } 11234482Smckusick bufhead.b_size = i; /* save number of buffers */ 11334225Smckusick } 11434225Smckusick 11534225Smckusick /* 11634225Smckusick * Manage a cache of directory blocks. 11734225Smckusick */ 11839973Smckusick struct bufarea * 11934225Smckusick getdatablk(blkno, size) 12034225Smckusick daddr_t blkno; 12134225Smckusick long size; 12234225Smckusick { 12339973Smckusick register struct bufarea *bp; 12434225Smckusick 12534225Smckusick for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 12634671Smckusick if (bp->b_bno == fsbtodb(&sblock, blkno)) 12734225Smckusick goto foundit; 12834225Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 12934225Smckusick if ((bp->b_flags & B_INUSE) == 0) 13034225Smckusick break; 13134225Smckusick if (bp == &bufhead) 13234225Smckusick errexit("deadlocked buffer pool\n"); 13334225Smckusick getblk(bp, blkno, size); 13434225Smckusick /* fall through */ 13534225Smckusick foundit: 13634225Smckusick totalreads++; 13734225Smckusick bp->b_prev->b_next = bp->b_next; 13834225Smckusick bp->b_next->b_prev = bp->b_prev; 13934225Smckusick bp->b_prev = &bufhead; 14034225Smckusick bp->b_next = bufhead.b_next; 14134225Smckusick bufhead.b_next->b_prev = bp; 14234225Smckusick bufhead.b_next = bp; 14334225Smckusick bp->b_flags |= B_INUSE; 14434225Smckusick return (bp); 14534225Smckusick } 14634225Smckusick 14744934Smckusick void 14816269Smckusick getblk(bp, blk, size) 14939973Smckusick register struct bufarea *bp; 15016269Smckusick daddr_t blk; 15116269Smckusick long size; 15216269Smckusick { 15316269Smckusick daddr_t dblk; 15416269Smckusick 15534671Smckusick dblk = fsbtodb(&sblock, blk); 15644934Smckusick if (bp->b_bno != dblk) { 15744934Smckusick flush(fswritefd, bp); 15844934Smckusick diskreads++; 15944934Smckusick bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 16044934Smckusick bp->b_bno = dblk; 16144934Smckusick bp->b_size = size; 16244934Smckusick } 16316269Smckusick } 16416269Smckusick 16539973Smckusick flush(fd, bp) 16639973Smckusick int fd; 16739973Smckusick register struct bufarea *bp; 16816269Smckusick { 16917931Smckusick register int i, j; 17016269Smckusick 17117931Smckusick if (!bp->b_dirty) 17217931Smckusick return; 17321540Smckusick if (bp->b_errs != 0) 17430609Skarels pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 17530609Skarels (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 17630609Skarels bp->b_bno); 17716269Smckusick bp->b_dirty = 0; 17821540Smckusick bp->b_errs = 0; 17939973Smckusick bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 18017931Smckusick if (bp != &sblk) 18117931Smckusick return; 18217931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 18339973Smckusick bwrite(fswritefd, (char *)sblock.fs_csp[j], 18417931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 18517931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 18617931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 18717931Smckusick } 18816269Smckusick } 18916269Smckusick 19039973Smckusick rwerror(mesg, blk) 19139973Smckusick char *mesg; 19216269Smckusick daddr_t blk; 19316269Smckusick { 19416269Smckusick 19516269Smckusick if (preen == 0) 19616269Smckusick printf("\n"); 19739973Smckusick pfatal("CANNOT %s: BLK %ld", mesg, blk); 19816269Smckusick if (reply("CONTINUE") == 0) 19916269Smckusick errexit("Program terminated\n"); 20016269Smckusick } 20116269Smckusick 20216269Smckusick ckfini() 20316269Smckusick { 20439973Smckusick register struct bufarea *bp, *nbp; 20534482Smckusick int cnt = 0; 20616269Smckusick 20756809Smckusick if (fswritefd < 0) { 20856809Smckusick (void)close(fsreadfd); 20956809Smckusick return; 21056809Smckusick } 21139973Smckusick flush(fswritefd, &sblk); 21230859Skarels if (havesb && sblk.b_bno != SBOFF / dev_bsize && 21330518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 21430556Smckusick sblk.b_bno = SBOFF / dev_bsize; 21516269Smckusick sbdirty(); 21639973Smckusick flush(fswritefd, &sblk); 21716269Smckusick } 21839973Smckusick flush(fswritefd, &cgblk); 21938342Smckusick free(cgblk.b_un.b_buf); 22056809Smckusick for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 22134482Smckusick cnt++; 22239973Smckusick flush(fswritefd, bp); 22338342Smckusick nbp = bp->b_prev; 22438342Smckusick free(bp->b_un.b_buf); 22538342Smckusick free((char *)bp); 22634482Smckusick } 22734482Smckusick if (bufhead.b_size != cnt) 22834482Smckusick errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 22940649Smckusick pbp = pdirbp = (struct bufarea *)0; 23034225Smckusick if (debug) 23144934Smckusick printf("cache missed %ld of %ld (%d%%)\n", diskreads, 23244934Smckusick totalreads, (int)(diskreads * 100 / totalreads)); 23339973Smckusick (void)close(fsreadfd); 23439973Smckusick (void)close(fswritefd); 23516269Smckusick } 23616269Smckusick 23739973Smckusick bread(fd, buf, blk, size) 23839973Smckusick int fd; 23916269Smckusick char *buf; 24016269Smckusick daddr_t blk; 24116269Smckusick long size; 24216269Smckusick { 24321540Smckusick char *cp; 24421540Smckusick int i, errs; 24560638Smckusick off_t offset; 24621540Smckusick 24760638Smckusick offset = blk; 24860638Smckusick offset *= dev_bsize; 24960638Smckusick if (lseek(fd, offset, 0) < 0) 25039973Smckusick rwerror("SEEK", blk); 25139973Smckusick else if (read(fd, buf, (int)size) == size) 25221540Smckusick return (0); 25339973Smckusick rwerror("READ", blk); 25460638Smckusick if (lseek(fd, offset, 0) < 0) 25539973Smckusick rwerror("SEEK", blk); 25621540Smckusick errs = 0; 25744934Smckusick bzero(buf, (size_t)size); 25830609Skarels printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 25930609Skarels for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 26044999Smckusick if (read(fd, cp, (int)secsize) != secsize) { 26160638Smckusick (void)lseek(fd, offset + i + secsize, 0); 26230859Skarels if (secsize != dev_bsize && dev_bsize != 1) 26344934Smckusick printf(" %ld (%ld),", 26430609Skarels (blk * dev_bsize + i) / secsize, 26530609Skarels blk + i / dev_bsize); 26630609Skarels else 26744934Smckusick printf(" %ld,", blk + i / dev_bsize); 26821540Smckusick errs++; 26921540Smckusick } 27021540Smckusick } 27121758Smckusick printf("\n"); 27221540Smckusick return (errs); 27316269Smckusick } 27416269Smckusick 27539973Smckusick bwrite(fd, buf, blk, size) 27639973Smckusick int fd; 27716269Smckusick char *buf; 27816269Smckusick daddr_t blk; 27916269Smckusick long size; 28016269Smckusick { 28121758Smckusick int i; 28221758Smckusick char *cp; 28360638Smckusick off_t offset; 28416269Smckusick 28539973Smckusick if (fd < 0) 28621758Smckusick return; 28760638Smckusick offset = blk; 28860638Smckusick offset *= dev_bsize; 28960638Smckusick if (lseek(fd, offset, 0) < 0) 29039973Smckusick rwerror("SEEK", blk); 29139973Smckusick else if (write(fd, buf, (int)size) == size) { 29239973Smckusick fsmodified = 1; 29321758Smckusick return; 29416269Smckusick } 29539973Smckusick rwerror("WRITE", blk); 29660638Smckusick if (lseek(fd, offset, 0) < 0) 29739973Smckusick rwerror("SEEK", blk); 29830609Skarels printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 29930518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 30044999Smckusick if (write(fd, cp, (int)dev_bsize) != dev_bsize) { 30160638Smckusick (void)lseek(fd, offset + i + dev_bsize, 0); 30244934Smckusick printf(" %ld,", blk + i / dev_bsize); 30330395Smckusick } 30421758Smckusick printf("\n"); 30521758Smckusick return; 30616269Smckusick } 30716269Smckusick 30817944Smckusick /* 30917944Smckusick * allocate a data block with the specified number of fragments 31017944Smckusick */ 31117944Smckusick allocblk(frags) 31239973Smckusick long frags; 31317944Smckusick { 31417944Smckusick register int i, j, k; 31517944Smckusick 31617944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 31717944Smckusick return (0); 31839973Smckusick for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 31917944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 32039973Smckusick if (testbmap(i + j)) 32117944Smckusick continue; 32217944Smckusick for (k = 1; k < frags; k++) 32339973Smckusick if (testbmap(i + j + k)) 32417944Smckusick break; 32517944Smckusick if (k < frags) { 32617944Smckusick j += k; 32717944Smckusick continue; 32817944Smckusick } 32917944Smckusick for (k = 0; k < frags; k++) 33017944Smckusick setbmap(i + j + k); 33117944Smckusick n_blks += frags; 33217944Smckusick return (i + j); 33317944Smckusick } 33417944Smckusick } 33517944Smckusick return (0); 33617944Smckusick } 33717944Smckusick 33817944Smckusick /* 33917944Smckusick * Free a previously allocated block 34017944Smckusick */ 34117944Smckusick freeblk(blkno, frags) 34217944Smckusick daddr_t blkno; 34339973Smckusick long frags; 34417944Smckusick { 34517944Smckusick struct inodesc idesc; 34617944Smckusick 34717944Smckusick idesc.id_blkno = blkno; 34817944Smckusick idesc.id_numfrags = frags; 34944934Smckusick (void)pass4check(&idesc); 35017944Smckusick } 35117944Smckusick 35217991Smckusick /* 35317991Smckusick * Find a pathname 35417991Smckusick */ 35517991Smckusick getpathname(namebuf, curdir, ino) 35617991Smckusick char *namebuf; 35717991Smckusick ino_t curdir, ino; 35817991Smckusick { 35917991Smckusick int len; 36017991Smckusick register char *cp; 36117991Smckusick struct inodesc idesc; 36244999Smckusick static int busy = 0; 36317991Smckusick extern int findname(); 36417991Smckusick 36554600Smckusick if (curdir == ino && ino == ROOTINO) { 36654600Smckusick (void)strcpy(namebuf, "/"); 36754600Smckusick return; 36854600Smckusick } 36944999Smckusick if (busy || 37044999Smckusick (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) { 37144934Smckusick (void)strcpy(namebuf, "?"); 37217991Smckusick return; 37317991Smckusick } 37444999Smckusick busy = 1; 37539973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 37617991Smckusick idesc.id_type = DATA; 37744999Smckusick idesc.id_fix = IGNORE; 37840646Smckusick cp = &namebuf[MAXPATHLEN - 1]; 37930354Smckusick *cp = '\0'; 38017991Smckusick if (curdir != ino) { 38117991Smckusick idesc.id_parent = curdir; 38217991Smckusick goto namelookup; 38317991Smckusick } 38417991Smckusick while (ino != ROOTINO) { 38517991Smckusick idesc.id_number = ino; 38617991Smckusick idesc.id_func = findino; 38717991Smckusick idesc.id_name = ".."; 38840019Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 38917991Smckusick break; 39017991Smckusick namelookup: 39117991Smckusick idesc.id_number = idesc.id_parent; 39217991Smckusick idesc.id_parent = ino; 39317991Smckusick idesc.id_func = findname; 39417991Smckusick idesc.id_name = namebuf; 39540019Smckusick if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 39617991Smckusick break; 39717991Smckusick len = strlen(namebuf); 39817991Smckusick cp -= len; 39950572Smckusick bcopy(namebuf, cp, (size_t)len); 40050572Smckusick *--cp = '/'; 40117991Smckusick if (cp < &namebuf[MAXNAMLEN]) 40217991Smckusick break; 40317991Smckusick ino = idesc.id_number; 40417991Smckusick } 40544999Smckusick busy = 0; 40650572Smckusick if (ino != ROOTINO) 40750572Smckusick *--cp = '?'; 40844934Smckusick bcopy(cp, namebuf, (size_t)(&namebuf[MAXPATHLEN] - cp)); 40917991Smckusick } 41017991Smckusick 41139165Sbostic void 41216269Smckusick catch() 41316269Smckusick { 41454600Smckusick if (!doinglevel2) 41554600Smckusick ckfini(); 41616269Smckusick exit(12); 41716269Smckusick } 41816269Smckusick 41916269Smckusick /* 42024680Skarels * When preening, allow a single quit to signal 42124680Skarels * a special exit after filesystem checks complete 42224680Skarels * so that reboot sequence may be interrupted. 42324680Skarels */ 42439165Sbostic void 42524680Skarels catchquit() 42624680Skarels { 42724680Skarels extern returntosingle; 42824680Skarels 42924680Skarels printf("returning to single-user after filesystem check\n"); 43024680Skarels returntosingle = 1; 43124680Skarels (void)signal(SIGQUIT, SIG_DFL); 43224680Skarels } 43324680Skarels 43424680Skarels /* 43524680Skarels * Ignore a single quit signal; wait and flush just in case. 43624680Skarels * Used by child processes in preen. 43724680Skarels */ 43839165Sbostic void 43924680Skarels voidquit() 44024680Skarels { 44124680Skarels 44224680Skarels sleep(1); 44324680Skarels (void)signal(SIGQUIT, SIG_IGN); 44424680Skarels (void)signal(SIGQUIT, SIG_DFL); 44524680Skarels } 44624680Skarels 44724680Skarels /* 44816269Smckusick * determine whether an inode should be fixed. 44916269Smckusick */ 45017931Smckusick dofix(idesc, msg) 45116269Smckusick register struct inodesc *idesc; 45217931Smckusick char *msg; 45316269Smckusick { 45416269Smckusick 45516269Smckusick switch (idesc->id_fix) { 45616269Smckusick 45716269Smckusick case DONTKNOW: 45817931Smckusick if (idesc->id_type == DATA) 45939973Smckusick direrror(idesc->id_number, msg); 46017931Smckusick else 46117931Smckusick pwarn(msg); 46217931Smckusick if (preen) { 46317931Smckusick printf(" (SALVAGED)\n"); 46417931Smckusick idesc->id_fix = FIX; 46517931Smckusick return (ALTERED); 46617931Smckusick } 46716269Smckusick if (reply("SALVAGE") == 0) { 46816269Smckusick idesc->id_fix = NOFIX; 46916269Smckusick return (0); 47016269Smckusick } 47116269Smckusick idesc->id_fix = FIX; 47216269Smckusick return (ALTERED); 47316269Smckusick 47416269Smckusick case FIX: 47516269Smckusick return (ALTERED); 47616269Smckusick 47716269Smckusick case NOFIX: 47844999Smckusick case IGNORE: 47916269Smckusick return (0); 48016269Smckusick 48116269Smckusick default: 48216269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 48316269Smckusick } 48416269Smckusick /* NOTREACHED */ 48516269Smckusick } 48616269Smckusick 48716269Smckusick /* VARARGS1 */ 48817931Smckusick errexit(s1, s2, s3, s4) 48916269Smckusick char *s1; 49016269Smckusick { 49116269Smckusick printf(s1, s2, s3, s4); 49216269Smckusick exit(8); 49316269Smckusick } 49416269Smckusick 49516269Smckusick /* 49639973Smckusick * An unexpected inconsistency occured. 49739973Smckusick * Die if preening, otherwise just print message and continue. 49816269Smckusick */ 49916269Smckusick /* VARARGS1 */ 50016269Smckusick pfatal(s, a1, a2, a3) 50116269Smckusick char *s; 50216269Smckusick { 50316269Smckusick 50416269Smckusick if (preen) { 50561110Sbostic printf("%s: ", cdevname); 50616269Smckusick printf(s, a1, a2, a3); 50716269Smckusick printf("\n"); 50817931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 50961110Sbostic cdevname); 51017931Smckusick exit(8); 51116269Smckusick } 51216269Smckusick printf(s, a1, a2, a3); 51316269Smckusick } 51416269Smckusick 51516269Smckusick /* 51639973Smckusick * Pwarn just prints a message when not preening, 51716269Smckusick * or a warning (preceded by filename) when preening. 51816269Smckusick */ 51916269Smckusick /* VARARGS1 */ 52016269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 52116269Smckusick char *s; 52216269Smckusick { 52316269Smckusick 52416269Smckusick if (preen) 52561110Sbostic printf("%s: ", cdevname); 52616269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 52716269Smckusick } 52816269Smckusick 52916269Smckusick #ifndef lint 53016269Smckusick /* 53116269Smckusick * Stub for routines from kernel. 53216269Smckusick */ 53316269Smckusick panic(s) 53416269Smckusick char *s; 53516269Smckusick { 53616269Smckusick 53717931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 53817931Smckusick errexit(s); 53916269Smckusick } 54016269Smckusick #endif 541