122055Sdist /* 239976Smckusick * Copyright (c) 1980, 1986 The Regents of the University of California. 339976Smckusick * All rights reserved. 439976Smckusick * 539976Smckusick * Redistribution and use in source and binary forms are permitted 639976Smckusick * provided that the above copyright notice and this paragraph are 739976Smckusick * duplicated in all such forms and that any documentation, 839976Smckusick * advertising materials, and other materials related to such 939976Smckusick * distribution and use acknowledge that the software was developed 1039976Smckusick * by the University of California, Berkeley. The name of the 1139976Smckusick * University may not be used to endorse or promote products derived 1239976Smckusick * from this software without specific prior written permission. 1339976Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1439976Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1539976Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1622055Sdist */ 1722055Sdist 1816269Smckusick #ifndef lint 19*40649Smckusick static char sccsid[] = "@(#)utilities.c 5.25 (Berkeley) 03/27/90"; 2039976Smckusick #endif /* not lint */ 2116269Smckusick 2216269Smckusick #include <sys/param.h> 2339383Smckusick #include <ufs/dinode.h> 2438337Smckusick #include <ufs/fs.h> 2538337Smckusick #include <ufs/dir.h> 2639165Sbostic #include <stdio.h> 2739165Sbostic #include <ctype.h> 2816269Smckusick #include "fsck.h" 2916269Smckusick 3034225Smckusick long diskreads, totalreads; /* Disk cache statistics */ 3116269Smckusick long lseek(); 3238377Smckusick char *malloc(); 3316269Smckusick 3416269Smckusick ftypeok(dp) 3539973Smckusick struct dinode *dp; 3616269Smckusick { 3716269Smckusick switch (dp->di_mode & IFMT) { 3816269Smckusick 3916269Smckusick case IFDIR: 4016269Smckusick case IFREG: 4116269Smckusick case IFBLK: 4216269Smckusick case IFCHR: 4316269Smckusick case IFLNK: 4416269Smckusick case IFSOCK: 4516269Smckusick return (1); 4616269Smckusick 4716269Smckusick default: 4816269Smckusick if (debug) 4916269Smckusick printf("bad file type 0%o\n", dp->di_mode); 5016269Smckusick return (0); 5116269Smckusick } 5216269Smckusick } 5316269Smckusick 5439975Smckusick reply(question) 5539975Smckusick char *question; 5616269Smckusick { 5739975Smckusick int persevere; 5839975Smckusick char c; 5916269Smckusick 6016269Smckusick if (preen) 6116269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 6239975Smckusick persevere = !strcmp(question, "CONTINUE"); 6339975Smckusick printf("\n"); 6439975Smckusick if (!persevere && (nflag || fswritefd < 0)) { 6539975Smckusick printf("%s? no\n\n", question); 6616269Smckusick return (0); 6716269Smckusick } 6839975Smckusick if (yflag || (persevere && nflag)) { 6939975Smckusick printf("%s? yes\n\n", question); 7016269Smckusick return (1); 7116269Smckusick } 7239975Smckusick do { 7339975Smckusick printf("%s? [yn] ", question); 7439975Smckusick (void) fflush(stdout); 7539975Smckusick c = getc(stdin); 7639975Smckusick while (c != '\n' && getc(stdin) != '\n') 7739975Smckusick if (feof(stdin)) 7839975Smckusick return (0); 7939975Smckusick } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 8016269Smckusick printf("\n"); 8139975Smckusick if (c == 'y' || c == 'Y') 8216269Smckusick return (1); 8339975Smckusick return (0); 8416269Smckusick } 8516269Smckusick 8634225Smckusick /* 8734225Smckusick * Malloc buffers and set up cache. 8834225Smckusick */ 8934225Smckusick bufinit() 9034225Smckusick { 9139973Smckusick register struct bufarea *bp; 9234225Smckusick long bufcnt, i; 9334225Smckusick char *bufp; 9434225Smckusick 95*40649Smckusick pbp = pdirbp = (struct bufarea *)0; 9639973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 9734225Smckusick if (bufp == 0) 9834225Smckusick errexit("cannot allocate buffer pool\n"); 9934225Smckusick cgblk.b_un.b_buf = bufp; 10034225Smckusick initbarea(&cgblk); 10134225Smckusick bufhead.b_next = bufhead.b_prev = &bufhead; 10234225Smckusick bufcnt = MAXBUFSPACE / sblock.fs_bsize; 10334225Smckusick if (bufcnt < MINBUFS) 10434225Smckusick bufcnt = MINBUFS; 10534225Smckusick for (i = 0; i < bufcnt; i++) { 10639973Smckusick bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 10739973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 10838377Smckusick if (bp == NULL || bufp == NULL) { 10934225Smckusick if (i >= MINBUFS) 11034225Smckusick break; 11134225Smckusick errexit("cannot allocate buffer pool\n"); 11234225Smckusick } 11334225Smckusick bp->b_un.b_buf = bufp; 11434225Smckusick bp->b_prev = &bufhead; 11534225Smckusick bp->b_next = bufhead.b_next; 11634225Smckusick bufhead.b_next->b_prev = bp; 11734225Smckusick bufhead.b_next = bp; 11834225Smckusick initbarea(bp); 11934225Smckusick } 12034482Smckusick bufhead.b_size = i; /* save number of buffers */ 12134225Smckusick } 12234225Smckusick 12334225Smckusick /* 12434225Smckusick * Manage a cache of directory blocks. 12534225Smckusick */ 12639973Smckusick struct bufarea * 12734225Smckusick getdatablk(blkno, size) 12834225Smckusick daddr_t blkno; 12934225Smckusick long size; 13034225Smckusick { 13139973Smckusick register struct bufarea *bp; 13234225Smckusick 13334225Smckusick for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 13434671Smckusick if (bp->b_bno == fsbtodb(&sblock, blkno)) 13534225Smckusick goto foundit; 13634225Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 13734225Smckusick if ((bp->b_flags & B_INUSE) == 0) 13834225Smckusick break; 13934225Smckusick if (bp == &bufhead) 14034225Smckusick errexit("deadlocked buffer pool\n"); 14134225Smckusick getblk(bp, blkno, size); 14234225Smckusick /* fall through */ 14334225Smckusick foundit: 14434225Smckusick totalreads++; 14534225Smckusick bp->b_prev->b_next = bp->b_next; 14634225Smckusick bp->b_next->b_prev = bp->b_prev; 14734225Smckusick bp->b_prev = &bufhead; 14834225Smckusick bp->b_next = bufhead.b_next; 14934225Smckusick bufhead.b_next->b_prev = bp; 15034225Smckusick bufhead.b_next = bp; 15134225Smckusick bp->b_flags |= B_INUSE; 15234225Smckusick return (bp); 15334225Smckusick } 15434225Smckusick 15539973Smckusick struct bufarea * 15616269Smckusick getblk(bp, blk, size) 15739973Smckusick register struct bufarea *bp; 15816269Smckusick daddr_t blk; 15916269Smckusick long size; 16016269Smckusick { 16116269Smckusick daddr_t dblk; 16216269Smckusick 16334671Smckusick dblk = fsbtodb(&sblock, blk); 16434671Smckusick if (bp->b_bno == dblk) 16516269Smckusick return (bp); 16639973Smckusick flush(fswritefd, bp); 16734225Smckusick diskreads++; 16839973Smckusick bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 16934671Smckusick bp->b_bno = dblk; 17021540Smckusick bp->b_size = size; 17121540Smckusick return (bp); 17216269Smckusick } 17316269Smckusick 17439973Smckusick flush(fd, bp) 17539973Smckusick int fd; 17639973Smckusick register struct bufarea *bp; 17716269Smckusick { 17817931Smckusick register int i, j; 17916269Smckusick 18017931Smckusick if (!bp->b_dirty) 18117931Smckusick return; 18221540Smckusick if (bp->b_errs != 0) 18330609Skarels pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 18430609Skarels (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 18530609Skarels bp->b_bno); 18616269Smckusick bp->b_dirty = 0; 18721540Smckusick bp->b_errs = 0; 18839973Smckusick bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 18917931Smckusick if (bp != &sblk) 19017931Smckusick return; 19117931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 19239973Smckusick bwrite(fswritefd, (char *)sblock.fs_csp[j], 19317931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 19417931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 19517931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 19617931Smckusick } 19716269Smckusick } 19816269Smckusick 19939973Smckusick rwerror(mesg, blk) 20039973Smckusick char *mesg; 20116269Smckusick daddr_t blk; 20216269Smckusick { 20316269Smckusick 20416269Smckusick if (preen == 0) 20516269Smckusick printf("\n"); 20639973Smckusick pfatal("CANNOT %s: BLK %ld", mesg, blk); 20716269Smckusick if (reply("CONTINUE") == 0) 20816269Smckusick errexit("Program terminated\n"); 20916269Smckusick } 21016269Smckusick 21116269Smckusick ckfini() 21216269Smckusick { 21339973Smckusick register struct bufarea *bp, *nbp; 21434482Smckusick int cnt = 0; 21516269Smckusick 21639973Smckusick flush(fswritefd, &sblk); 21730859Skarels if (havesb && sblk.b_bno != SBOFF / dev_bsize && 21830518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 21930556Smckusick sblk.b_bno = SBOFF / dev_bsize; 22016269Smckusick sbdirty(); 22139973Smckusick flush(fswritefd, &sblk); 22216269Smckusick } 22339973Smckusick flush(fswritefd, &cgblk); 22438342Smckusick free(cgblk.b_un.b_buf); 22538342Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) { 22634482Smckusick cnt++; 22739973Smckusick flush(fswritefd, bp); 22838342Smckusick nbp = bp->b_prev; 22938342Smckusick free(bp->b_un.b_buf); 23038342Smckusick free((char *)bp); 23134482Smckusick } 23234482Smckusick if (bufhead.b_size != cnt) 23334482Smckusick errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 234*40649Smckusick pbp = pdirbp = (struct bufarea *)0; 23534225Smckusick if (debug) 23634482Smckusick printf("cache missed %d of %d (%d%%)\n", diskreads, 23734482Smckusick totalreads, diskreads * 100 / totalreads); 23839973Smckusick (void)close(fsreadfd); 23939973Smckusick (void)close(fswritefd); 24016269Smckusick } 24116269Smckusick 24239973Smckusick bread(fd, buf, blk, size) 24339973Smckusick int fd; 24416269Smckusick char *buf; 24516269Smckusick daddr_t blk; 24616269Smckusick long size; 24716269Smckusick { 24821540Smckusick char *cp; 24921540Smckusick int i, errs; 25021540Smckusick 25139973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 25239973Smckusick rwerror("SEEK", blk); 25339973Smckusick else if (read(fd, buf, (int)size) == size) 25421540Smckusick return (0); 25539973Smckusick rwerror("READ", blk); 25639973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 25739973Smckusick rwerror("SEEK", blk); 25821540Smckusick errs = 0; 25939973Smckusick bzero(buf, (int)size); 26030609Skarels printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 26130609Skarels for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 26239973Smckusick if (read(fd, cp, (int)secsize) < 0) { 26339973Smckusick lseek(fd, blk * dev_bsize + i + secsize, 0); 26430859Skarels if (secsize != dev_bsize && dev_bsize != 1) 26530609Skarels printf(" %d (%d),", 26630609Skarels (blk * dev_bsize + i) / secsize, 26730609Skarels blk + i / dev_bsize); 26830609Skarels else 26930609Skarels printf(" %d,", blk + i / dev_bsize); 27021540Smckusick errs++; 27121540Smckusick } 27221540Smckusick } 27321758Smckusick printf("\n"); 27421540Smckusick return (errs); 27516269Smckusick } 27616269Smckusick 27739973Smckusick bwrite(fd, buf, blk, size) 27839973Smckusick int fd; 27916269Smckusick char *buf; 28016269Smckusick daddr_t blk; 28116269Smckusick long size; 28216269Smckusick { 28321758Smckusick int i; 28421758Smckusick char *cp; 28516269Smckusick 28639973Smckusick if (fd < 0) 28721758Smckusick return; 28839973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 28939973Smckusick rwerror("SEEK", blk); 29039973Smckusick else if (write(fd, buf, (int)size) == size) { 29139973Smckusick fsmodified = 1; 29221758Smckusick return; 29316269Smckusick } 29439973Smckusick rwerror("WRITE", blk); 29539973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 29639973Smckusick rwerror("SEEK", blk); 29730609Skarels printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 29830518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 29939973Smckusick if (write(fd, cp, (int)dev_bsize) < 0) { 30039973Smckusick lseek(fd, blk * dev_bsize + i + dev_bsize, 0); 30130518Smckusick printf(" %d,", blk + i / dev_bsize); 30230395Smckusick } 30321758Smckusick printf("\n"); 30421758Smckusick return; 30516269Smckusick } 30616269Smckusick 30717944Smckusick /* 30817944Smckusick * allocate a data block with the specified number of fragments 30917944Smckusick */ 31017944Smckusick allocblk(frags) 31139973Smckusick long frags; 31217944Smckusick { 31317944Smckusick register int i, j, k; 31417944Smckusick 31517944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 31617944Smckusick return (0); 31739973Smckusick for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 31817944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 31939973Smckusick if (testbmap(i + j)) 32017944Smckusick continue; 32117944Smckusick for (k = 1; k < frags; k++) 32239973Smckusick if (testbmap(i + j + k)) 32317944Smckusick break; 32417944Smckusick if (k < frags) { 32517944Smckusick j += k; 32617944Smckusick continue; 32717944Smckusick } 32817944Smckusick for (k = 0; k < frags; k++) 32917944Smckusick setbmap(i + j + k); 33017944Smckusick n_blks += frags; 33117944Smckusick return (i + j); 33217944Smckusick } 33317944Smckusick } 33417944Smckusick return (0); 33517944Smckusick } 33617944Smckusick 33717944Smckusick /* 33817944Smckusick * Free a previously allocated block 33917944Smckusick */ 34017944Smckusick freeblk(blkno, frags) 34117944Smckusick daddr_t blkno; 34239973Smckusick long frags; 34317944Smckusick { 34417944Smckusick struct inodesc idesc; 34517944Smckusick 34617944Smckusick idesc.id_blkno = blkno; 34717944Smckusick idesc.id_numfrags = frags; 34817944Smckusick pass4check(&idesc); 34917944Smckusick } 35017944Smckusick 35117991Smckusick /* 35217991Smckusick * Find a pathname 35317991Smckusick */ 35417991Smckusick getpathname(namebuf, curdir, ino) 35517991Smckusick char *namebuf; 35617991Smckusick ino_t curdir, ino; 35717991Smckusick { 35817991Smckusick int len; 35917991Smckusick register char *cp; 36017991Smckusick struct inodesc idesc; 36117991Smckusick extern int findname(); 36217991Smckusick 36340019Smckusick if (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND) { 36417991Smckusick strcpy(namebuf, "?"); 36517991Smckusick return; 36617991Smckusick } 36739973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 36817991Smckusick idesc.id_type = DATA; 36940646Smckusick cp = &namebuf[MAXPATHLEN - 1]; 37030354Smckusick *cp = '\0'; 37117991Smckusick if (curdir != ino) { 37217991Smckusick idesc.id_parent = curdir; 37317991Smckusick goto namelookup; 37417991Smckusick } 37517991Smckusick while (ino != ROOTINO) { 37617991Smckusick idesc.id_number = ino; 37717991Smckusick idesc.id_func = findino; 37817991Smckusick idesc.id_name = ".."; 37940019Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 38017991Smckusick break; 38117991Smckusick namelookup: 38217991Smckusick idesc.id_number = idesc.id_parent; 38317991Smckusick idesc.id_parent = ino; 38417991Smckusick idesc.id_func = findname; 38517991Smckusick idesc.id_name = namebuf; 38640019Smckusick if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 38717991Smckusick break; 38817991Smckusick len = strlen(namebuf); 38917991Smckusick cp -= len; 39017991Smckusick if (cp < &namebuf[MAXNAMLEN]) 39117991Smckusick break; 39217991Smckusick bcopy(namebuf, cp, len); 39317991Smckusick *--cp = '/'; 39417991Smckusick ino = idesc.id_number; 39517991Smckusick } 39617991Smckusick if (ino != ROOTINO) { 39717991Smckusick strcpy(namebuf, "?"); 39817991Smckusick return; 39917991Smckusick } 40040646Smckusick bcopy(cp, namebuf, &namebuf[MAXPATHLEN] - cp); 40117991Smckusick } 40217991Smckusick 40339165Sbostic void 40416269Smckusick catch() 40516269Smckusick { 40616269Smckusick ckfini(); 40716269Smckusick exit(12); 40816269Smckusick } 40916269Smckusick 41016269Smckusick /* 41124680Skarels * When preening, allow a single quit to signal 41224680Skarels * a special exit after filesystem checks complete 41324680Skarels * so that reboot sequence may be interrupted. 41424680Skarels */ 41539165Sbostic void 41624680Skarels catchquit() 41724680Skarels { 41824680Skarels extern returntosingle; 41924680Skarels 42024680Skarels printf("returning to single-user after filesystem check\n"); 42124680Skarels returntosingle = 1; 42224680Skarels (void)signal(SIGQUIT, SIG_DFL); 42324680Skarels } 42424680Skarels 42524680Skarels /* 42624680Skarels * Ignore a single quit signal; wait and flush just in case. 42724680Skarels * Used by child processes in preen. 42824680Skarels */ 42939165Sbostic void 43024680Skarels voidquit() 43124680Skarels { 43224680Skarels 43324680Skarels sleep(1); 43424680Skarels (void)signal(SIGQUIT, SIG_IGN); 43524680Skarels (void)signal(SIGQUIT, SIG_DFL); 43624680Skarels } 43724680Skarels 43824680Skarels /* 43916269Smckusick * determine whether an inode should be fixed. 44016269Smckusick */ 44117931Smckusick dofix(idesc, msg) 44216269Smckusick register struct inodesc *idesc; 44317931Smckusick char *msg; 44416269Smckusick { 44516269Smckusick 44616269Smckusick switch (idesc->id_fix) { 44716269Smckusick 44816269Smckusick case DONTKNOW: 44917931Smckusick if (idesc->id_type == DATA) 45039973Smckusick direrror(idesc->id_number, msg); 45117931Smckusick else 45217931Smckusick pwarn(msg); 45317931Smckusick if (preen) { 45417931Smckusick printf(" (SALVAGED)\n"); 45517931Smckusick idesc->id_fix = FIX; 45617931Smckusick return (ALTERED); 45717931Smckusick } 45816269Smckusick if (reply("SALVAGE") == 0) { 45916269Smckusick idesc->id_fix = NOFIX; 46016269Smckusick return (0); 46116269Smckusick } 46216269Smckusick idesc->id_fix = FIX; 46316269Smckusick return (ALTERED); 46416269Smckusick 46516269Smckusick case FIX: 46616269Smckusick return (ALTERED); 46716269Smckusick 46816269Smckusick case NOFIX: 46916269Smckusick return (0); 47016269Smckusick 47116269Smckusick default: 47216269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 47316269Smckusick } 47416269Smckusick /* NOTREACHED */ 47516269Smckusick } 47616269Smckusick 47716269Smckusick /* VARARGS1 */ 47817931Smckusick errexit(s1, s2, s3, s4) 47916269Smckusick char *s1; 48016269Smckusick { 48116269Smckusick printf(s1, s2, s3, s4); 48216269Smckusick exit(8); 48316269Smckusick } 48416269Smckusick 48516269Smckusick /* 48639973Smckusick * An unexpected inconsistency occured. 48739973Smckusick * Die if preening, otherwise just print message and continue. 48816269Smckusick */ 48916269Smckusick /* VARARGS1 */ 49016269Smckusick pfatal(s, a1, a2, a3) 49116269Smckusick char *s; 49216269Smckusick { 49316269Smckusick 49416269Smckusick if (preen) { 49516269Smckusick printf("%s: ", devname); 49616269Smckusick printf(s, a1, a2, a3); 49716269Smckusick printf("\n"); 49817931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 49917931Smckusick devname); 50017931Smckusick exit(8); 50116269Smckusick } 50216269Smckusick printf(s, a1, a2, a3); 50316269Smckusick } 50416269Smckusick 50516269Smckusick /* 50639973Smckusick * Pwarn just prints a message when not preening, 50716269Smckusick * or a warning (preceded by filename) when preening. 50816269Smckusick */ 50916269Smckusick /* VARARGS1 */ 51016269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 51116269Smckusick char *s; 51216269Smckusick { 51316269Smckusick 51416269Smckusick if (preen) 51516269Smckusick printf("%s: ", devname); 51616269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 51716269Smckusick } 51816269Smckusick 51916269Smckusick #ifndef lint 52016269Smckusick /* 52116269Smckusick * Stub for routines from kernel. 52216269Smckusick */ 52316269Smckusick panic(s) 52416269Smckusick char *s; 52516269Smckusick { 52616269Smckusick 52717931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 52817931Smckusick errexit(s); 52916269Smckusick } 53016269Smckusick #endif 531