122055Sdist /* 239976Smckusick * Copyright (c) 1980, 1986 The Regents of the University of California. 339976Smckusick * All rights reserved. 439976Smckusick * 5*42702Sbostic * %sccs.include.redist.c% 622055Sdist */ 722055Sdist 816269Smckusick #ifndef lint 9*42702Sbostic static char sccsid[] = "@(#)utilities.c 5.26 (Berkeley) 06/01/90"; 1039976Smckusick #endif /* not lint */ 1116269Smckusick 1216269Smckusick #include <sys/param.h> 1339383Smckusick #include <ufs/dinode.h> 1438337Smckusick #include <ufs/fs.h> 1538337Smckusick #include <ufs/dir.h> 1639165Sbostic #include <stdio.h> 1739165Sbostic #include <ctype.h> 1816269Smckusick #include "fsck.h" 1916269Smckusick 2034225Smckusick long diskreads, totalreads; /* Disk cache statistics */ 2116269Smckusick long lseek(); 2238377Smckusick char *malloc(); 2316269Smckusick 2416269Smckusick ftypeok(dp) 2539973Smckusick struct dinode *dp; 2616269Smckusick { 2716269Smckusick switch (dp->di_mode & IFMT) { 2816269Smckusick 2916269Smckusick case IFDIR: 3016269Smckusick case IFREG: 3116269Smckusick case IFBLK: 3216269Smckusick case IFCHR: 3316269Smckusick case IFLNK: 3416269Smckusick case IFSOCK: 3516269Smckusick return (1); 3616269Smckusick 3716269Smckusick default: 3816269Smckusick if (debug) 3916269Smckusick printf("bad file type 0%o\n", dp->di_mode); 4016269Smckusick return (0); 4116269Smckusick } 4216269Smckusick } 4316269Smckusick 4439975Smckusick reply(question) 4539975Smckusick char *question; 4616269Smckusick { 4739975Smckusick int persevere; 4839975Smckusick char c; 4916269Smckusick 5016269Smckusick if (preen) 5116269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 5239975Smckusick persevere = !strcmp(question, "CONTINUE"); 5339975Smckusick printf("\n"); 5439975Smckusick if (!persevere && (nflag || fswritefd < 0)) { 5539975Smckusick printf("%s? no\n\n", question); 5616269Smckusick return (0); 5716269Smckusick } 5839975Smckusick if (yflag || (persevere && nflag)) { 5939975Smckusick printf("%s? yes\n\n", question); 6016269Smckusick return (1); 6116269Smckusick } 6239975Smckusick do { 6339975Smckusick printf("%s? [yn] ", question); 6439975Smckusick (void) fflush(stdout); 6539975Smckusick c = getc(stdin); 6639975Smckusick while (c != '\n' && getc(stdin) != '\n') 6739975Smckusick if (feof(stdin)) 6839975Smckusick return (0); 6939975Smckusick } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 7016269Smckusick printf("\n"); 7139975Smckusick if (c == 'y' || c == 'Y') 7216269Smckusick return (1); 7339975Smckusick return (0); 7416269Smckusick } 7516269Smckusick 7634225Smckusick /* 7734225Smckusick * Malloc buffers and set up cache. 7834225Smckusick */ 7934225Smckusick bufinit() 8034225Smckusick { 8139973Smckusick register struct bufarea *bp; 8234225Smckusick long bufcnt, i; 8334225Smckusick char *bufp; 8434225Smckusick 8540649Smckusick pbp = pdirbp = (struct bufarea *)0; 8639973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 8734225Smckusick if (bufp == 0) 8834225Smckusick errexit("cannot allocate buffer pool\n"); 8934225Smckusick cgblk.b_un.b_buf = bufp; 9034225Smckusick initbarea(&cgblk); 9134225Smckusick bufhead.b_next = bufhead.b_prev = &bufhead; 9234225Smckusick bufcnt = MAXBUFSPACE / sblock.fs_bsize; 9334225Smckusick if (bufcnt < MINBUFS) 9434225Smckusick bufcnt = MINBUFS; 9534225Smckusick for (i = 0; i < bufcnt; i++) { 9639973Smckusick bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 9739973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 9838377Smckusick if (bp == NULL || bufp == NULL) { 9934225Smckusick if (i >= MINBUFS) 10034225Smckusick break; 10134225Smckusick errexit("cannot allocate buffer pool\n"); 10234225Smckusick } 10334225Smckusick bp->b_un.b_buf = bufp; 10434225Smckusick bp->b_prev = &bufhead; 10534225Smckusick bp->b_next = bufhead.b_next; 10634225Smckusick bufhead.b_next->b_prev = bp; 10734225Smckusick bufhead.b_next = bp; 10834225Smckusick initbarea(bp); 10934225Smckusick } 11034482Smckusick bufhead.b_size = i; /* save number of buffers */ 11134225Smckusick } 11234225Smckusick 11334225Smckusick /* 11434225Smckusick * Manage a cache of directory blocks. 11534225Smckusick */ 11639973Smckusick struct bufarea * 11734225Smckusick getdatablk(blkno, size) 11834225Smckusick daddr_t blkno; 11934225Smckusick long size; 12034225Smckusick { 12139973Smckusick register struct bufarea *bp; 12234225Smckusick 12334225Smckusick for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 12434671Smckusick if (bp->b_bno == fsbtodb(&sblock, blkno)) 12534225Smckusick goto foundit; 12634225Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 12734225Smckusick if ((bp->b_flags & B_INUSE) == 0) 12834225Smckusick break; 12934225Smckusick if (bp == &bufhead) 13034225Smckusick errexit("deadlocked buffer pool\n"); 13134225Smckusick getblk(bp, blkno, size); 13234225Smckusick /* fall through */ 13334225Smckusick foundit: 13434225Smckusick totalreads++; 13534225Smckusick bp->b_prev->b_next = bp->b_next; 13634225Smckusick bp->b_next->b_prev = bp->b_prev; 13734225Smckusick bp->b_prev = &bufhead; 13834225Smckusick bp->b_next = bufhead.b_next; 13934225Smckusick bufhead.b_next->b_prev = bp; 14034225Smckusick bufhead.b_next = bp; 14134225Smckusick bp->b_flags |= B_INUSE; 14234225Smckusick return (bp); 14334225Smckusick } 14434225Smckusick 14539973Smckusick struct bufarea * 14616269Smckusick getblk(bp, blk, size) 14739973Smckusick register struct bufarea *bp; 14816269Smckusick daddr_t blk; 14916269Smckusick long size; 15016269Smckusick { 15116269Smckusick daddr_t dblk; 15216269Smckusick 15334671Smckusick dblk = fsbtodb(&sblock, blk); 15434671Smckusick if (bp->b_bno == dblk) 15516269Smckusick return (bp); 15639973Smckusick flush(fswritefd, bp); 15734225Smckusick diskreads++; 15839973Smckusick bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 15934671Smckusick bp->b_bno = dblk; 16021540Smckusick bp->b_size = size; 16121540Smckusick return (bp); 16216269Smckusick } 16316269Smckusick 16439973Smckusick flush(fd, bp) 16539973Smckusick int fd; 16639973Smckusick register struct bufarea *bp; 16716269Smckusick { 16817931Smckusick register int i, j; 16916269Smckusick 17017931Smckusick if (!bp->b_dirty) 17117931Smckusick return; 17221540Smckusick if (bp->b_errs != 0) 17330609Skarels pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 17430609Skarels (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 17530609Skarels bp->b_bno); 17616269Smckusick bp->b_dirty = 0; 17721540Smckusick bp->b_errs = 0; 17839973Smckusick bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 17917931Smckusick if (bp != &sblk) 18017931Smckusick return; 18117931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 18239973Smckusick bwrite(fswritefd, (char *)sblock.fs_csp[j], 18317931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 18417931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 18517931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 18617931Smckusick } 18716269Smckusick } 18816269Smckusick 18939973Smckusick rwerror(mesg, blk) 19039973Smckusick char *mesg; 19116269Smckusick daddr_t blk; 19216269Smckusick { 19316269Smckusick 19416269Smckusick if (preen == 0) 19516269Smckusick printf("\n"); 19639973Smckusick pfatal("CANNOT %s: BLK %ld", mesg, blk); 19716269Smckusick if (reply("CONTINUE") == 0) 19816269Smckusick errexit("Program terminated\n"); 19916269Smckusick } 20016269Smckusick 20116269Smckusick ckfini() 20216269Smckusick { 20339973Smckusick register struct bufarea *bp, *nbp; 20434482Smckusick int cnt = 0; 20516269Smckusick 20639973Smckusick flush(fswritefd, &sblk); 20730859Skarels if (havesb && sblk.b_bno != SBOFF / dev_bsize && 20830518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 20930556Smckusick sblk.b_bno = SBOFF / dev_bsize; 21016269Smckusick sbdirty(); 21139973Smckusick flush(fswritefd, &sblk); 21216269Smckusick } 21339973Smckusick flush(fswritefd, &cgblk); 21438342Smckusick free(cgblk.b_un.b_buf); 21538342Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) { 21634482Smckusick cnt++; 21739973Smckusick flush(fswritefd, bp); 21838342Smckusick nbp = bp->b_prev; 21938342Smckusick free(bp->b_un.b_buf); 22038342Smckusick free((char *)bp); 22134482Smckusick } 22234482Smckusick if (bufhead.b_size != cnt) 22334482Smckusick errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 22440649Smckusick pbp = pdirbp = (struct bufarea *)0; 22534225Smckusick if (debug) 22634482Smckusick printf("cache missed %d of %d (%d%%)\n", diskreads, 22734482Smckusick totalreads, diskreads * 100 / totalreads); 22839973Smckusick (void)close(fsreadfd); 22939973Smckusick (void)close(fswritefd); 23016269Smckusick } 23116269Smckusick 23239973Smckusick bread(fd, buf, blk, size) 23339973Smckusick int fd; 23416269Smckusick char *buf; 23516269Smckusick daddr_t blk; 23616269Smckusick long size; 23716269Smckusick { 23821540Smckusick char *cp; 23921540Smckusick int i, errs; 24021540Smckusick 24139973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 24239973Smckusick rwerror("SEEK", blk); 24339973Smckusick else if (read(fd, buf, (int)size) == size) 24421540Smckusick return (0); 24539973Smckusick rwerror("READ", blk); 24639973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 24739973Smckusick rwerror("SEEK", blk); 24821540Smckusick errs = 0; 24939973Smckusick bzero(buf, (int)size); 25030609Skarels printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 25130609Skarels for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 25239973Smckusick if (read(fd, cp, (int)secsize) < 0) { 25339973Smckusick lseek(fd, blk * dev_bsize + i + secsize, 0); 25430859Skarels if (secsize != dev_bsize && dev_bsize != 1) 25530609Skarels printf(" %d (%d),", 25630609Skarels (blk * dev_bsize + i) / secsize, 25730609Skarels blk + i / dev_bsize); 25830609Skarels else 25930609Skarels printf(" %d,", blk + i / dev_bsize); 26021540Smckusick errs++; 26121540Smckusick } 26221540Smckusick } 26321758Smckusick printf("\n"); 26421540Smckusick return (errs); 26516269Smckusick } 26616269Smckusick 26739973Smckusick bwrite(fd, buf, blk, size) 26839973Smckusick int fd; 26916269Smckusick char *buf; 27016269Smckusick daddr_t blk; 27116269Smckusick long size; 27216269Smckusick { 27321758Smckusick int i; 27421758Smckusick char *cp; 27516269Smckusick 27639973Smckusick if (fd < 0) 27721758Smckusick return; 27839973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 27939973Smckusick rwerror("SEEK", blk); 28039973Smckusick else if (write(fd, buf, (int)size) == size) { 28139973Smckusick fsmodified = 1; 28221758Smckusick return; 28316269Smckusick } 28439973Smckusick rwerror("WRITE", blk); 28539973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 28639973Smckusick rwerror("SEEK", blk); 28730609Skarels printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 28830518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 28939973Smckusick if (write(fd, cp, (int)dev_bsize) < 0) { 29039973Smckusick lseek(fd, blk * dev_bsize + i + dev_bsize, 0); 29130518Smckusick printf(" %d,", blk + i / dev_bsize); 29230395Smckusick } 29321758Smckusick printf("\n"); 29421758Smckusick return; 29516269Smckusick } 29616269Smckusick 29717944Smckusick /* 29817944Smckusick * allocate a data block with the specified number of fragments 29917944Smckusick */ 30017944Smckusick allocblk(frags) 30139973Smckusick long frags; 30217944Smckusick { 30317944Smckusick register int i, j, k; 30417944Smckusick 30517944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 30617944Smckusick return (0); 30739973Smckusick for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 30817944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 30939973Smckusick if (testbmap(i + j)) 31017944Smckusick continue; 31117944Smckusick for (k = 1; k < frags; k++) 31239973Smckusick if (testbmap(i + j + k)) 31317944Smckusick break; 31417944Smckusick if (k < frags) { 31517944Smckusick j += k; 31617944Smckusick continue; 31717944Smckusick } 31817944Smckusick for (k = 0; k < frags; k++) 31917944Smckusick setbmap(i + j + k); 32017944Smckusick n_blks += frags; 32117944Smckusick return (i + j); 32217944Smckusick } 32317944Smckusick } 32417944Smckusick return (0); 32517944Smckusick } 32617944Smckusick 32717944Smckusick /* 32817944Smckusick * Free a previously allocated block 32917944Smckusick */ 33017944Smckusick freeblk(blkno, frags) 33117944Smckusick daddr_t blkno; 33239973Smckusick long frags; 33317944Smckusick { 33417944Smckusick struct inodesc idesc; 33517944Smckusick 33617944Smckusick idesc.id_blkno = blkno; 33717944Smckusick idesc.id_numfrags = frags; 33817944Smckusick pass4check(&idesc); 33917944Smckusick } 34017944Smckusick 34117991Smckusick /* 34217991Smckusick * Find a pathname 34317991Smckusick */ 34417991Smckusick getpathname(namebuf, curdir, ino) 34517991Smckusick char *namebuf; 34617991Smckusick ino_t curdir, ino; 34717991Smckusick { 34817991Smckusick int len; 34917991Smckusick register char *cp; 35017991Smckusick struct inodesc idesc; 35117991Smckusick extern int findname(); 35217991Smckusick 35340019Smckusick if (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND) { 35417991Smckusick strcpy(namebuf, "?"); 35517991Smckusick return; 35617991Smckusick } 35739973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 35817991Smckusick idesc.id_type = DATA; 35940646Smckusick cp = &namebuf[MAXPATHLEN - 1]; 36030354Smckusick *cp = '\0'; 36117991Smckusick if (curdir != ino) { 36217991Smckusick idesc.id_parent = curdir; 36317991Smckusick goto namelookup; 36417991Smckusick } 36517991Smckusick while (ino != ROOTINO) { 36617991Smckusick idesc.id_number = ino; 36717991Smckusick idesc.id_func = findino; 36817991Smckusick idesc.id_name = ".."; 36940019Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 37017991Smckusick break; 37117991Smckusick namelookup: 37217991Smckusick idesc.id_number = idesc.id_parent; 37317991Smckusick idesc.id_parent = ino; 37417991Smckusick idesc.id_func = findname; 37517991Smckusick idesc.id_name = namebuf; 37640019Smckusick if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 37717991Smckusick break; 37817991Smckusick len = strlen(namebuf); 37917991Smckusick cp -= len; 38017991Smckusick if (cp < &namebuf[MAXNAMLEN]) 38117991Smckusick break; 38217991Smckusick bcopy(namebuf, cp, len); 38317991Smckusick *--cp = '/'; 38417991Smckusick ino = idesc.id_number; 38517991Smckusick } 38617991Smckusick if (ino != ROOTINO) { 38717991Smckusick strcpy(namebuf, "?"); 38817991Smckusick return; 38917991Smckusick } 39040646Smckusick bcopy(cp, namebuf, &namebuf[MAXPATHLEN] - cp); 39117991Smckusick } 39217991Smckusick 39339165Sbostic void 39416269Smckusick catch() 39516269Smckusick { 39616269Smckusick ckfini(); 39716269Smckusick exit(12); 39816269Smckusick } 39916269Smckusick 40016269Smckusick /* 40124680Skarels * When preening, allow a single quit to signal 40224680Skarels * a special exit after filesystem checks complete 40324680Skarels * so that reboot sequence may be interrupted. 40424680Skarels */ 40539165Sbostic void 40624680Skarels catchquit() 40724680Skarels { 40824680Skarels extern returntosingle; 40924680Skarels 41024680Skarels printf("returning to single-user after filesystem check\n"); 41124680Skarels returntosingle = 1; 41224680Skarels (void)signal(SIGQUIT, SIG_DFL); 41324680Skarels } 41424680Skarels 41524680Skarels /* 41624680Skarels * Ignore a single quit signal; wait and flush just in case. 41724680Skarels * Used by child processes in preen. 41824680Skarels */ 41939165Sbostic void 42024680Skarels voidquit() 42124680Skarels { 42224680Skarels 42324680Skarels sleep(1); 42424680Skarels (void)signal(SIGQUIT, SIG_IGN); 42524680Skarels (void)signal(SIGQUIT, SIG_DFL); 42624680Skarels } 42724680Skarels 42824680Skarels /* 42916269Smckusick * determine whether an inode should be fixed. 43016269Smckusick */ 43117931Smckusick dofix(idesc, msg) 43216269Smckusick register struct inodesc *idesc; 43317931Smckusick char *msg; 43416269Smckusick { 43516269Smckusick 43616269Smckusick switch (idesc->id_fix) { 43716269Smckusick 43816269Smckusick case DONTKNOW: 43917931Smckusick if (idesc->id_type == DATA) 44039973Smckusick direrror(idesc->id_number, msg); 44117931Smckusick else 44217931Smckusick pwarn(msg); 44317931Smckusick if (preen) { 44417931Smckusick printf(" (SALVAGED)\n"); 44517931Smckusick idesc->id_fix = FIX; 44617931Smckusick return (ALTERED); 44717931Smckusick } 44816269Smckusick if (reply("SALVAGE") == 0) { 44916269Smckusick idesc->id_fix = NOFIX; 45016269Smckusick return (0); 45116269Smckusick } 45216269Smckusick idesc->id_fix = FIX; 45316269Smckusick return (ALTERED); 45416269Smckusick 45516269Smckusick case FIX: 45616269Smckusick return (ALTERED); 45716269Smckusick 45816269Smckusick case NOFIX: 45916269Smckusick return (0); 46016269Smckusick 46116269Smckusick default: 46216269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 46316269Smckusick } 46416269Smckusick /* NOTREACHED */ 46516269Smckusick } 46616269Smckusick 46716269Smckusick /* VARARGS1 */ 46817931Smckusick errexit(s1, s2, s3, s4) 46916269Smckusick char *s1; 47016269Smckusick { 47116269Smckusick printf(s1, s2, s3, s4); 47216269Smckusick exit(8); 47316269Smckusick } 47416269Smckusick 47516269Smckusick /* 47639973Smckusick * An unexpected inconsistency occured. 47739973Smckusick * Die if preening, otherwise just print message and continue. 47816269Smckusick */ 47916269Smckusick /* VARARGS1 */ 48016269Smckusick pfatal(s, a1, a2, a3) 48116269Smckusick char *s; 48216269Smckusick { 48316269Smckusick 48416269Smckusick if (preen) { 48516269Smckusick printf("%s: ", devname); 48616269Smckusick printf(s, a1, a2, a3); 48716269Smckusick printf("\n"); 48817931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 48917931Smckusick devname); 49017931Smckusick exit(8); 49116269Smckusick } 49216269Smckusick printf(s, a1, a2, a3); 49316269Smckusick } 49416269Smckusick 49516269Smckusick /* 49639973Smckusick * Pwarn just prints a message when not preening, 49716269Smckusick * or a warning (preceded by filename) when preening. 49816269Smckusick */ 49916269Smckusick /* VARARGS1 */ 50016269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 50116269Smckusick char *s; 50216269Smckusick { 50316269Smckusick 50416269Smckusick if (preen) 50516269Smckusick printf("%s: ", devname); 50616269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 50716269Smckusick } 50816269Smckusick 50916269Smckusick #ifndef lint 51016269Smckusick /* 51116269Smckusick * Stub for routines from kernel. 51216269Smckusick */ 51316269Smckusick panic(s) 51416269Smckusick char *s; 51516269Smckusick { 51616269Smckusick 51717931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 51817931Smckusick errexit(s); 51916269Smckusick } 52016269Smckusick #endif 521