122055Sdist /* 222055Sdist * Copyright (c) 1980 Regents of the University of California. 322055Sdist * All rights reserved. The Berkeley software License Agreement 422055Sdist * specifies the terms and conditions for redistribution. 522055Sdist */ 622055Sdist 716269Smckusick #ifndef lint 8*38377Smckusick static char sccsid[] = "@(#)utilities.c 5.16 (Berkeley) 06/30/89"; 922055Sdist #endif not lint 1016269Smckusick 1116269Smckusick #include <stdio.h> 1216269Smckusick #include <ctype.h> 1316269Smckusick #include <sys/param.h> 1438337Smckusick #include <sys/time.h> 1538337Smckusick #include <sys/vnode.h> 1638337Smckusick #include <ufs/inode.h> 1738337Smckusick #include <ufs/fs.h> 1838337Smckusick #include <ufs/dir.h> 1916269Smckusick #include "fsck.h" 2016269Smckusick 2134225Smckusick long diskreads, totalreads; /* Disk cache statistics */ 2216269Smckusick long lseek(); 23*38377Smckusick char *malloc(); 2416269Smckusick 2516269Smckusick ftypeok(dp) 2616269Smckusick 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: 3616269Smckusick return (1); 3716269Smckusick 3816269Smckusick default: 3916269Smckusick if (debug) 4016269Smckusick printf("bad file type 0%o\n", dp->di_mode); 4116269Smckusick return (0); 4216269Smckusick } 4316269Smckusick } 4416269Smckusick 4516269Smckusick reply(s) 4616269Smckusick char *s; 4716269Smckusick { 4816269Smckusick char line[80]; 4930609Skarels int cont = (strcmp(s, "CONTINUE") == 0); 5016269Smckusick 5116269Smckusick if (preen) 5216269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 5316269Smckusick printf("\n%s? ", s); 5430609Skarels if (!cont && (nflag || dfile.wfdes < 0)) { 5516269Smckusick printf(" no\n\n"); 5616269Smckusick return (0); 5716269Smckusick } 5830609Skarels if (yflag || (cont && nflag)) { 5916269Smckusick printf(" yes\n\n"); 6016269Smckusick return (1); 6116269Smckusick } 6216269Smckusick if (getline(stdin, line, sizeof(line)) == EOF) 6316269Smckusick errexit("\n"); 6416269Smckusick printf("\n"); 6516269Smckusick if (line[0] == 'y' || line[0] == 'Y') 6616269Smckusick return (1); 6716269Smckusick else 6816269Smckusick return (0); 6916269Smckusick } 7016269Smckusick 7116269Smckusick getline(fp, loc, maxlen) 7216269Smckusick FILE *fp; 7316269Smckusick char *loc; 7416269Smckusick { 7516269Smckusick register n; 7616269Smckusick register char *p, *lastloc; 7716269Smckusick 7816269Smckusick p = loc; 7916269Smckusick lastloc = &p[maxlen-1]; 8016269Smckusick while ((n = getc(fp)) != '\n') { 8116269Smckusick if (n == EOF) 8216269Smckusick return (EOF); 8316269Smckusick if (!isspace(n) && p < lastloc) 8416269Smckusick *p++ = n; 8516269Smckusick } 8616269Smckusick *p = 0; 8716269Smckusick return (p - loc); 8816269Smckusick } 8916269Smckusick 9034225Smckusick /* 9134225Smckusick * Malloc buffers and set up cache. 9234225Smckusick */ 9334225Smckusick bufinit() 9434225Smckusick { 9534225Smckusick register BUFAREA *bp; 9634225Smckusick long bufcnt, i; 9734225Smckusick char *bufp; 9834225Smckusick 99*38377Smckusick bufp = malloc(sblock.fs_bsize); 10034225Smckusick if (bufp == 0) 10134225Smckusick errexit("cannot allocate buffer pool\n"); 10234225Smckusick cgblk.b_un.b_buf = bufp; 10334225Smckusick initbarea(&cgblk); 10434225Smckusick bufhead.b_next = bufhead.b_prev = &bufhead; 10534225Smckusick bufcnt = MAXBUFSPACE / sblock.fs_bsize; 10634225Smckusick if (bufcnt < MINBUFS) 10734225Smckusick bufcnt = MINBUFS; 10834225Smckusick for (i = 0; i < bufcnt; i++) { 10934225Smckusick bp = (BUFAREA *)malloc(sizeof(BUFAREA)); 110*38377Smckusick bufp = malloc(sblock.fs_bsize); 111*38377Smckusick if (bp == NULL || bufp == NULL) { 11234225Smckusick if (i >= MINBUFS) 11334225Smckusick break; 11434225Smckusick errexit("cannot allocate buffer pool\n"); 11534225Smckusick } 11634225Smckusick bp->b_un.b_buf = bufp; 11734225Smckusick bp->b_prev = &bufhead; 11834225Smckusick bp->b_next = bufhead.b_next; 11934225Smckusick bufhead.b_next->b_prev = bp; 12034225Smckusick bufhead.b_next = bp; 12134225Smckusick initbarea(bp); 12234225Smckusick } 12334482Smckusick bufhead.b_size = i; /* save number of buffers */ 12434225Smckusick } 12534225Smckusick 12634225Smckusick /* 12734225Smckusick * Manage a cache of directory blocks. 12834225Smckusick */ 12916269Smckusick BUFAREA * 13034225Smckusick getdatablk(blkno, size) 13134225Smckusick daddr_t blkno; 13234225Smckusick long size; 13334225Smckusick { 13434225Smckusick register BUFAREA *bp; 13534225Smckusick 13634225Smckusick for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 13734671Smckusick if (bp->b_bno == fsbtodb(&sblock, blkno)) 13834225Smckusick goto foundit; 13934225Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 14034225Smckusick if ((bp->b_flags & B_INUSE) == 0) 14134225Smckusick break; 14234225Smckusick if (bp == &bufhead) 14334225Smckusick errexit("deadlocked buffer pool\n"); 14434225Smckusick getblk(bp, blkno, size); 14534225Smckusick /* fall through */ 14634225Smckusick foundit: 14734225Smckusick totalreads++; 14834225Smckusick bp->b_prev->b_next = bp->b_next; 14934225Smckusick bp->b_next->b_prev = bp->b_prev; 15034225Smckusick bp->b_prev = &bufhead; 15134225Smckusick bp->b_next = bufhead.b_next; 15234225Smckusick bufhead.b_next->b_prev = bp; 15334225Smckusick bufhead.b_next = bp; 15434225Smckusick bp->b_flags |= B_INUSE; 15534225Smckusick return (bp); 15634225Smckusick } 15734225Smckusick 15834225Smckusick BUFAREA * 15916269Smckusick getblk(bp, blk, size) 16016269Smckusick register BUFAREA *bp; 16116269Smckusick daddr_t blk; 16216269Smckusick long size; 16316269Smckusick { 16416269Smckusick register struct filecntl *fcp; 16516269Smckusick daddr_t dblk; 16616269Smckusick 16716269Smckusick fcp = &dfile; 16834671Smckusick dblk = fsbtodb(&sblock, blk); 16934671Smckusick if (bp->b_bno == dblk) 17016269Smckusick return (bp); 17116269Smckusick flush(fcp, bp); 17234225Smckusick diskreads++; 17334671Smckusick bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size); 17434671Smckusick bp->b_bno = dblk; 17521540Smckusick bp->b_size = size; 17621540Smckusick return (bp); 17716269Smckusick } 17816269Smckusick 17916269Smckusick flush(fcp, bp) 18016269Smckusick struct filecntl *fcp; 18116269Smckusick register BUFAREA *bp; 18216269Smckusick { 18317931Smckusick register int i, j; 18416269Smckusick 18517931Smckusick if (!bp->b_dirty) 18617931Smckusick return; 18721540Smckusick if (bp->b_errs != 0) 18830609Skarels pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 18930609Skarels (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 19030609Skarels bp->b_bno); 19116269Smckusick bp->b_dirty = 0; 19221540Smckusick bp->b_errs = 0; 19321758Smckusick bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 19417931Smckusick if (bp != &sblk) 19517931Smckusick return; 19617931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 19721758Smckusick bwrite(&dfile, (char *)sblock.fs_csp[j], 19817931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 19917931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 20017931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 20117931Smckusick } 20216269Smckusick } 20316269Smckusick 20416269Smckusick rwerr(s, blk) 20516269Smckusick char *s; 20616269Smckusick daddr_t blk; 20716269Smckusick { 20816269Smckusick 20916269Smckusick if (preen == 0) 21016269Smckusick printf("\n"); 21116269Smckusick pfatal("CANNOT %s: BLK %ld", s, blk); 21216269Smckusick if (reply("CONTINUE") == 0) 21316269Smckusick errexit("Program terminated\n"); 21416269Smckusick } 21516269Smckusick 21616269Smckusick ckfini() 21716269Smckusick { 21838342Smckusick register BUFAREA *bp, *nbp; 21934482Smckusick int cnt = 0; 22016269Smckusick 22116269Smckusick flush(&dfile, &sblk); 22230859Skarels if (havesb && sblk.b_bno != SBOFF / dev_bsize && 22330518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 22430556Smckusick sblk.b_bno = SBOFF / dev_bsize; 22516269Smckusick sbdirty(); 22616269Smckusick flush(&dfile, &sblk); 22716269Smckusick } 22818002Smckusick flush(&dfile, &cgblk); 22938342Smckusick free(cgblk.b_un.b_buf); 23038342Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) { 23134482Smckusick cnt++; 23234225Smckusick flush(&dfile, bp); 23338342Smckusick nbp = bp->b_prev; 23438342Smckusick free(bp->b_un.b_buf); 23538342Smckusick free((char *)bp); 23634482Smckusick } 23734482Smckusick if (bufhead.b_size != cnt) 23834482Smckusick errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 23934225Smckusick if (debug) 24034482Smckusick printf("cache missed %d of %d (%d%%)\n", diskreads, 24134482Smckusick totalreads, diskreads * 100 / totalreads); 24216269Smckusick (void)close(dfile.rfdes); 24316269Smckusick (void)close(dfile.wfdes); 24416269Smckusick } 24516269Smckusick 24616269Smckusick bread(fcp, buf, blk, size) 24716269Smckusick register struct filecntl *fcp; 24816269Smckusick char *buf; 24916269Smckusick daddr_t blk; 25016269Smckusick long size; 25116269Smckusick { 25221540Smckusick char *cp; 25321540Smckusick int i, errs; 25421540Smckusick 25530557Smckusick if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) 25616269Smckusick rwerr("SEEK", blk); 25716269Smckusick else if (read(fcp->rfdes, buf, (int)size) == size) 25821540Smckusick return (0); 25916269Smckusick rwerr("READ", blk); 26030557Smckusick if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) 26121540Smckusick rwerr("SEEK", blk); 26221540Smckusick errs = 0; 26330463Smckusick bzero(buf, size); 26430609Skarels printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 26530609Skarels for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 26630609Skarels if (read(fcp->rfdes, cp, secsize) < 0) { 26730609Skarels lseek(fcp->rfdes, blk * dev_bsize + i + secsize, 0); 26830859Skarels if (secsize != dev_bsize && dev_bsize != 1) 26930609Skarels printf(" %d (%d),", 27030609Skarels (blk * dev_bsize + i) / secsize, 27130609Skarels blk + i / dev_bsize); 27230609Skarels else 27330609Skarels printf(" %d,", blk + i / dev_bsize); 27421540Smckusick errs++; 27521540Smckusick } 27621540Smckusick } 27721758Smckusick printf("\n"); 27821540Smckusick return (errs); 27916269Smckusick } 28016269Smckusick 28116269Smckusick bwrite(fcp, buf, blk, size) 28216269Smckusick register struct filecntl *fcp; 28316269Smckusick char *buf; 28416269Smckusick daddr_t blk; 28516269Smckusick long size; 28616269Smckusick { 28721758Smckusick int i; 28821758Smckusick char *cp; 28916269Smckusick 29016269Smckusick if (fcp->wfdes < 0) 29121758Smckusick return; 29230557Smckusick if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) 29316269Smckusick rwerr("SEEK", blk); 29416269Smckusick else if (write(fcp->wfdes, buf, (int)size) == size) { 29516269Smckusick fcp->mod = 1; 29621758Smckusick return; 29716269Smckusick } 29816269Smckusick rwerr("WRITE", blk); 29930557Smckusick if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) 30021758Smckusick rwerr("SEEK", blk); 30130609Skarels printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 30230518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 30330518Smckusick if (write(fcp->wfdes, cp, dev_bsize) < 0) { 30430557Smckusick lseek(fcp->rfdes, blk * dev_bsize + i + dev_bsize, 0); 30530518Smckusick printf(" %d,", blk + i / dev_bsize); 30630395Smckusick } 30721758Smckusick printf("\n"); 30821758Smckusick return; 30916269Smckusick } 31016269Smckusick 31117944Smckusick /* 31217944Smckusick * allocate a data block with the specified number of fragments 31317944Smckusick */ 31417944Smckusick allocblk(frags) 31517944Smckusick int frags; 31617944Smckusick { 31717944Smckusick register int i, j, k; 31817944Smckusick 31917944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 32017944Smckusick return (0); 32117944Smckusick for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { 32217944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 32317944Smckusick if (getbmap(i + j)) 32417944Smckusick continue; 32517944Smckusick for (k = 1; k < frags; k++) 32617944Smckusick if (getbmap(i + j + k)) 32717944Smckusick break; 32817944Smckusick if (k < frags) { 32917944Smckusick j += k; 33017944Smckusick continue; 33117944Smckusick } 33217944Smckusick for (k = 0; k < frags; k++) 33317944Smckusick setbmap(i + j + k); 33417944Smckusick n_blks += frags; 33517944Smckusick return (i + j); 33617944Smckusick } 33717944Smckusick } 33817944Smckusick return (0); 33917944Smckusick } 34017944Smckusick 34117944Smckusick /* 34217944Smckusick * Free a previously allocated block 34317944Smckusick */ 34417944Smckusick freeblk(blkno, frags) 34517944Smckusick daddr_t blkno; 34617944Smckusick int frags; 34717944Smckusick { 34817944Smckusick struct inodesc idesc; 34917944Smckusick 35017944Smckusick idesc.id_blkno = blkno; 35117944Smckusick idesc.id_numfrags = frags; 35217944Smckusick pass4check(&idesc); 35317944Smckusick } 35417944Smckusick 35517991Smckusick /* 35617991Smckusick * Find a pathname 35717991Smckusick */ 35817991Smckusick getpathname(namebuf, curdir, ino) 35917991Smckusick char *namebuf; 36017991Smckusick ino_t curdir, ino; 36117991Smckusick { 36217991Smckusick int len; 36317991Smckusick register char *cp; 36417991Smckusick struct inodesc idesc; 36517991Smckusick extern int findname(); 36617991Smckusick 36717991Smckusick if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 36817991Smckusick strcpy(namebuf, "?"); 36917991Smckusick return; 37017991Smckusick } 37117991Smckusick bzero(&idesc, sizeof(struct inodesc)); 37217991Smckusick idesc.id_type = DATA; 37317991Smckusick cp = &namebuf[BUFSIZ - 1]; 37430354Smckusick *cp = '\0'; 37517991Smckusick if (curdir != ino) { 37617991Smckusick idesc.id_parent = curdir; 37717991Smckusick goto namelookup; 37817991Smckusick } 37917991Smckusick while (ino != ROOTINO) { 38017991Smckusick idesc.id_number = ino; 38117991Smckusick idesc.id_func = findino; 38217991Smckusick idesc.id_name = ".."; 38330354Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 38417991Smckusick break; 38517991Smckusick namelookup: 38617991Smckusick idesc.id_number = idesc.id_parent; 38717991Smckusick idesc.id_parent = ino; 38817991Smckusick idesc.id_func = findname; 38917991Smckusick idesc.id_name = namebuf; 39030354Smckusick if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 39117991Smckusick break; 39217991Smckusick len = strlen(namebuf); 39317991Smckusick cp -= len; 39417991Smckusick if (cp < &namebuf[MAXNAMLEN]) 39517991Smckusick break; 39617991Smckusick bcopy(namebuf, cp, len); 39717991Smckusick *--cp = '/'; 39817991Smckusick ino = idesc.id_number; 39917991Smckusick } 40017991Smckusick if (ino != ROOTINO) { 40117991Smckusick strcpy(namebuf, "?"); 40217991Smckusick return; 40317991Smckusick } 40417991Smckusick bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 40517991Smckusick } 40617991Smckusick 40716269Smckusick catch() 40816269Smckusick { 40916269Smckusick 41016269Smckusick ckfini(); 41116269Smckusick exit(12); 41216269Smckusick } 41316269Smckusick 41416269Smckusick /* 41524680Skarels * When preening, allow a single quit to signal 41624680Skarels * a special exit after filesystem checks complete 41724680Skarels * so that reboot sequence may be interrupted. 41824680Skarels */ 41924680Skarels catchquit() 42024680Skarels { 42124680Skarels extern returntosingle; 42224680Skarels 42324680Skarels printf("returning to single-user after filesystem check\n"); 42424680Skarels returntosingle = 1; 42524680Skarels (void)signal(SIGQUIT, SIG_DFL); 42624680Skarels } 42724680Skarels 42824680Skarels /* 42924680Skarels * Ignore a single quit signal; wait and flush just in case. 43024680Skarels * Used by child processes in preen. 43124680Skarels */ 43224680Skarels voidquit() 43324680Skarels { 43424680Skarels 43524680Skarels sleep(1); 43624680Skarels (void)signal(SIGQUIT, SIG_IGN); 43724680Skarels (void)signal(SIGQUIT, SIG_DFL); 43824680Skarels } 43924680Skarels 44024680Skarels /* 44116269Smckusick * determine whether an inode should be fixed. 44216269Smckusick */ 44317931Smckusick dofix(idesc, msg) 44416269Smckusick register struct inodesc *idesc; 44517931Smckusick char *msg; 44616269Smckusick { 44716269Smckusick 44816269Smckusick switch (idesc->id_fix) { 44916269Smckusick 45016269Smckusick case DONTKNOW: 45117931Smckusick if (idesc->id_type == DATA) 45217931Smckusick direrr(idesc->id_number, msg); 45317931Smckusick else 45417931Smckusick pwarn(msg); 45517931Smckusick if (preen) { 45617931Smckusick printf(" (SALVAGED)\n"); 45717931Smckusick idesc->id_fix = FIX; 45817931Smckusick return (ALTERED); 45917931Smckusick } 46016269Smckusick if (reply("SALVAGE") == 0) { 46116269Smckusick idesc->id_fix = NOFIX; 46216269Smckusick return (0); 46316269Smckusick } 46416269Smckusick idesc->id_fix = FIX; 46516269Smckusick return (ALTERED); 46616269Smckusick 46716269Smckusick case FIX: 46816269Smckusick return (ALTERED); 46916269Smckusick 47016269Smckusick case NOFIX: 47116269Smckusick return (0); 47216269Smckusick 47316269Smckusick default: 47416269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 47516269Smckusick } 47616269Smckusick /* NOTREACHED */ 47716269Smckusick } 47816269Smckusick 47916269Smckusick /* VARARGS1 */ 48017931Smckusick errexit(s1, s2, s3, s4) 48116269Smckusick char *s1; 48216269Smckusick { 48316269Smckusick printf(s1, s2, s3, s4); 48416269Smckusick exit(8); 48516269Smckusick } 48616269Smckusick 48716269Smckusick /* 48816269Smckusick * An inconsistency occured which shouldn't during normal operations. 48916269Smckusick * Die if preening, otherwise just printf. 49016269Smckusick */ 49116269Smckusick /* VARARGS1 */ 49216269Smckusick pfatal(s, a1, a2, a3) 49316269Smckusick char *s; 49416269Smckusick { 49516269Smckusick 49616269Smckusick if (preen) { 49716269Smckusick printf("%s: ", devname); 49816269Smckusick printf(s, a1, a2, a3); 49916269Smckusick printf("\n"); 50017931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 50117931Smckusick devname); 50217931Smckusick exit(8); 50316269Smckusick } 50416269Smckusick printf(s, a1, a2, a3); 50516269Smckusick } 50616269Smckusick 50716269Smckusick /* 50816269Smckusick * Pwarn is like printf when not preening, 50916269Smckusick * or a warning (preceded by filename) when preening. 51016269Smckusick */ 51116269Smckusick /* VARARGS1 */ 51216269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 51316269Smckusick char *s; 51416269Smckusick { 51516269Smckusick 51616269Smckusick if (preen) 51716269Smckusick printf("%s: ", devname); 51816269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 51916269Smckusick } 52016269Smckusick 52116269Smckusick #ifndef lint 52216269Smckusick /* 52316269Smckusick * Stub for routines from kernel. 52416269Smckusick */ 52516269Smckusick panic(s) 52616269Smckusick char *s; 52716269Smckusick { 52816269Smckusick 52917931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 53017931Smckusick errexit(s); 53116269Smckusick } 53216269Smckusick #endif 533