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*38337Smckusick static char sccsid[] = "@(#)utilities.c 5.14 (Berkeley) 06/26/89"; 922055Sdist #endif not lint 1016269Smckusick 1116269Smckusick #include <stdio.h> 1216269Smckusick #include <ctype.h> 1316269Smckusick #include <sys/param.h> 14*38337Smckusick #include <sys/time.h> 15*38337Smckusick #include <sys/vnode.h> 16*38337Smckusick #include <ufs/inode.h> 17*38337Smckusick #include <ufs/fs.h> 18*38337Smckusick #include <ufs/dir.h> 1916269Smckusick #include "fsck.h" 2016269Smckusick 2134225Smckusick long diskreads, totalreads; /* Disk cache statistics */ 2216269Smckusick long lseek(); 2316269Smckusick 2416269Smckusick ftypeok(dp) 2516269Smckusick 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 4416269Smckusick reply(s) 4516269Smckusick char *s; 4616269Smckusick { 4716269Smckusick char line[80]; 4830609Skarels int cont = (strcmp(s, "CONTINUE") == 0); 4916269Smckusick 5016269Smckusick if (preen) 5116269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 5216269Smckusick printf("\n%s? ", s); 5330609Skarels if (!cont && (nflag || dfile.wfdes < 0)) { 5416269Smckusick printf(" no\n\n"); 5516269Smckusick return (0); 5616269Smckusick } 5730609Skarels if (yflag || (cont && nflag)) { 5816269Smckusick printf(" yes\n\n"); 5916269Smckusick return (1); 6016269Smckusick } 6116269Smckusick if (getline(stdin, line, sizeof(line)) == EOF) 6216269Smckusick errexit("\n"); 6316269Smckusick printf("\n"); 6416269Smckusick if (line[0] == 'y' || line[0] == 'Y') 6516269Smckusick return (1); 6616269Smckusick else 6716269Smckusick return (0); 6816269Smckusick } 6916269Smckusick 7016269Smckusick getline(fp, loc, maxlen) 7116269Smckusick FILE *fp; 7216269Smckusick char *loc; 7316269Smckusick { 7416269Smckusick register n; 7516269Smckusick register char *p, *lastloc; 7616269Smckusick 7716269Smckusick p = loc; 7816269Smckusick lastloc = &p[maxlen-1]; 7916269Smckusick while ((n = getc(fp)) != '\n') { 8016269Smckusick if (n == EOF) 8116269Smckusick return (EOF); 8216269Smckusick if (!isspace(n) && p < lastloc) 8316269Smckusick *p++ = n; 8416269Smckusick } 8516269Smckusick *p = 0; 8616269Smckusick return (p - loc); 8716269Smckusick } 8816269Smckusick 8934225Smckusick /* 9034225Smckusick * Malloc buffers and set up cache. 9134225Smckusick */ 9234225Smckusick bufinit() 9334225Smckusick { 9434225Smckusick register BUFAREA *bp; 9534225Smckusick long bufcnt, i; 9634225Smckusick char *bufp; 9734225Smckusick 9834225Smckusick bufp = (char *)malloc(sblock.fs_bsize); 9934225Smckusick if (bufp == 0) 10034225Smckusick errexit("cannot allocate buffer pool\n"); 10134225Smckusick cgblk.b_un.b_buf = bufp; 10234225Smckusick initbarea(&cgblk); 10334225Smckusick bufhead.b_next = bufhead.b_prev = &bufhead; 10434225Smckusick bufcnt = MAXBUFSPACE / sblock.fs_bsize; 10534225Smckusick if (bufcnt < MINBUFS) 10634225Smckusick bufcnt = MINBUFS; 10734225Smckusick for (i = 0; i < bufcnt; i++) { 10834225Smckusick bp = (BUFAREA *)malloc(sizeof(BUFAREA)); 10934225Smckusick bufp = (char *)malloc(sblock.fs_bsize); 11034225Smckusick if (bp == 0 || bufp == 0) { 11134225Smckusick if (i >= MINBUFS) 11234225Smckusick break; 11334225Smckusick errexit("cannot allocate buffer pool\n"); 11434225Smckusick } 11534225Smckusick bp->b_un.b_buf = bufp; 11634225Smckusick bp->b_prev = &bufhead; 11734225Smckusick bp->b_next = bufhead.b_next; 11834225Smckusick bufhead.b_next->b_prev = bp; 11934225Smckusick bufhead.b_next = bp; 12034225Smckusick initbarea(bp); 12134225Smckusick } 12234482Smckusick bufhead.b_size = i; /* save number of buffers */ 12334225Smckusick } 12434225Smckusick 12534225Smckusick /* 12634225Smckusick * Manage a cache of directory blocks. 12734225Smckusick */ 12816269Smckusick BUFAREA * 12934225Smckusick getdatablk(blkno, size) 13034225Smckusick daddr_t blkno; 13134225Smckusick long size; 13234225Smckusick { 13334225Smckusick register BUFAREA *bp; 13434225Smckusick 13534225Smckusick for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 13634671Smckusick if (bp->b_bno == fsbtodb(&sblock, blkno)) 13734225Smckusick goto foundit; 13834225Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 13934225Smckusick if ((bp->b_flags & B_INUSE) == 0) 14034225Smckusick break; 14134225Smckusick if (bp == &bufhead) 14234225Smckusick errexit("deadlocked buffer pool\n"); 14334225Smckusick getblk(bp, blkno, size); 14434225Smckusick /* fall through */ 14534225Smckusick foundit: 14634225Smckusick totalreads++; 14734225Smckusick bp->b_prev->b_next = bp->b_next; 14834225Smckusick bp->b_next->b_prev = bp->b_prev; 14934225Smckusick bp->b_prev = &bufhead; 15034225Smckusick bp->b_next = bufhead.b_next; 15134225Smckusick bufhead.b_next->b_prev = bp; 15234225Smckusick bufhead.b_next = bp; 15334225Smckusick bp->b_flags |= B_INUSE; 15434225Smckusick return (bp); 15534225Smckusick } 15634225Smckusick 15734225Smckusick BUFAREA * 15816269Smckusick getblk(bp, blk, size) 15916269Smckusick register BUFAREA *bp; 16016269Smckusick daddr_t blk; 16116269Smckusick long size; 16216269Smckusick { 16316269Smckusick register struct filecntl *fcp; 16416269Smckusick daddr_t dblk; 16516269Smckusick 16616269Smckusick fcp = &dfile; 16734671Smckusick dblk = fsbtodb(&sblock, blk); 16834671Smckusick if (bp->b_bno == dblk) 16916269Smckusick return (bp); 17016269Smckusick flush(fcp, bp); 17134225Smckusick diskreads++; 17234671Smckusick bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size); 17334671Smckusick bp->b_bno = dblk; 17421540Smckusick bp->b_size = size; 17521540Smckusick return (bp); 17616269Smckusick } 17716269Smckusick 17816269Smckusick flush(fcp, bp) 17916269Smckusick struct filecntl *fcp; 18016269Smckusick register BUFAREA *bp; 18116269Smckusick { 18217931Smckusick register int i, j; 18316269Smckusick 18417931Smckusick if (!bp->b_dirty) 18517931Smckusick return; 18621540Smckusick if (bp->b_errs != 0) 18730609Skarels pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 18830609Skarels (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 18930609Skarels bp->b_bno); 19016269Smckusick bp->b_dirty = 0; 19121540Smckusick bp->b_errs = 0; 19221758Smckusick bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 19317931Smckusick if (bp != &sblk) 19417931Smckusick return; 19517931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 19621758Smckusick bwrite(&dfile, (char *)sblock.fs_csp[j], 19717931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 19817931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 19917931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 20017931Smckusick } 20116269Smckusick } 20216269Smckusick 20316269Smckusick rwerr(s, blk) 20416269Smckusick char *s; 20516269Smckusick daddr_t blk; 20616269Smckusick { 20716269Smckusick 20816269Smckusick if (preen == 0) 20916269Smckusick printf("\n"); 21016269Smckusick pfatal("CANNOT %s: BLK %ld", s, blk); 21116269Smckusick if (reply("CONTINUE") == 0) 21216269Smckusick errexit("Program terminated\n"); 21316269Smckusick } 21416269Smckusick 21516269Smckusick ckfini() 21616269Smckusick { 21734225Smckusick register BUFAREA *bp; 21834482Smckusick int cnt = 0; 21916269Smckusick 22016269Smckusick flush(&dfile, &sblk); 22130859Skarels if (havesb && sblk.b_bno != SBOFF / dev_bsize && 22230518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 22330556Smckusick sblk.b_bno = SBOFF / dev_bsize; 22416269Smckusick sbdirty(); 22516269Smckusick flush(&dfile, &sblk); 22616269Smckusick } 22718002Smckusick flush(&dfile, &cgblk); 22834482Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) { 22934482Smckusick cnt++; 23034225Smckusick flush(&dfile, bp); 23134482Smckusick } 23234482Smckusick if (bufhead.b_size != cnt) 23334482Smckusick errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 23434225Smckusick if (debug) 23534482Smckusick printf("cache missed %d of %d (%d%%)\n", diskreads, 23634482Smckusick totalreads, diskreads * 100 / totalreads); 23716269Smckusick (void)close(dfile.rfdes); 23816269Smckusick (void)close(dfile.wfdes); 23916269Smckusick } 24016269Smckusick 24116269Smckusick bread(fcp, buf, blk, size) 24216269Smckusick register struct filecntl *fcp; 24316269Smckusick char *buf; 24416269Smckusick daddr_t blk; 24516269Smckusick long size; 24616269Smckusick { 24721540Smckusick char *cp; 24821540Smckusick int i, errs; 24921540Smckusick 25030557Smckusick if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) 25116269Smckusick rwerr("SEEK", blk); 25216269Smckusick else if (read(fcp->rfdes, buf, (int)size) == size) 25321540Smckusick return (0); 25416269Smckusick rwerr("READ", blk); 25530557Smckusick if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) 25621540Smckusick rwerr("SEEK", blk); 25721540Smckusick errs = 0; 25830463Smckusick bzero(buf, size); 25930609Skarels printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 26030609Skarels for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 26130609Skarels if (read(fcp->rfdes, cp, secsize) < 0) { 26230609Skarels lseek(fcp->rfdes, blk * dev_bsize + i + secsize, 0); 26330859Skarels if (secsize != dev_bsize && dev_bsize != 1) 26430609Skarels printf(" %d (%d),", 26530609Skarels (blk * dev_bsize + i) / secsize, 26630609Skarels blk + i / dev_bsize); 26730609Skarels else 26830609Skarels printf(" %d,", blk + i / dev_bsize); 26921540Smckusick errs++; 27021540Smckusick } 27121540Smckusick } 27221758Smckusick printf("\n"); 27321540Smckusick return (errs); 27416269Smckusick } 27516269Smckusick 27616269Smckusick bwrite(fcp, buf, blk, size) 27716269Smckusick register struct filecntl *fcp; 27816269Smckusick char *buf; 27916269Smckusick daddr_t blk; 28016269Smckusick long size; 28116269Smckusick { 28221758Smckusick int i; 28321758Smckusick char *cp; 28416269Smckusick 28516269Smckusick if (fcp->wfdes < 0) 28621758Smckusick return; 28730557Smckusick if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) 28816269Smckusick rwerr("SEEK", blk); 28916269Smckusick else if (write(fcp->wfdes, buf, (int)size) == size) { 29016269Smckusick fcp->mod = 1; 29121758Smckusick return; 29216269Smckusick } 29316269Smckusick rwerr("WRITE", blk); 29430557Smckusick if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) 29521758Smckusick rwerr("SEEK", blk); 29630609Skarels printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 29730518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 29830518Smckusick if (write(fcp->wfdes, cp, dev_bsize) < 0) { 29930557Smckusick lseek(fcp->rfdes, blk * dev_bsize + i + dev_bsize, 0); 30030518Smckusick printf(" %d,", blk + i / dev_bsize); 30130395Smckusick } 30221758Smckusick printf("\n"); 30321758Smckusick return; 30416269Smckusick } 30516269Smckusick 30617944Smckusick /* 30717944Smckusick * allocate a data block with the specified number of fragments 30817944Smckusick */ 30917944Smckusick allocblk(frags) 31017944Smckusick int frags; 31117944Smckusick { 31217944Smckusick register int i, j, k; 31317944Smckusick 31417944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 31517944Smckusick return (0); 31617944Smckusick for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { 31717944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 31817944Smckusick if (getbmap(i + j)) 31917944Smckusick continue; 32017944Smckusick for (k = 1; k < frags; k++) 32117944Smckusick if (getbmap(i + j + k)) 32217944Smckusick break; 32317944Smckusick if (k < frags) { 32417944Smckusick j += k; 32517944Smckusick continue; 32617944Smckusick } 32717944Smckusick for (k = 0; k < frags; k++) 32817944Smckusick setbmap(i + j + k); 32917944Smckusick n_blks += frags; 33017944Smckusick return (i + j); 33117944Smckusick } 33217944Smckusick } 33317944Smckusick return (0); 33417944Smckusick } 33517944Smckusick 33617944Smckusick /* 33717944Smckusick * Free a previously allocated block 33817944Smckusick */ 33917944Smckusick freeblk(blkno, frags) 34017944Smckusick daddr_t blkno; 34117944Smckusick int frags; 34217944Smckusick { 34317944Smckusick struct inodesc idesc; 34417944Smckusick 34517944Smckusick idesc.id_blkno = blkno; 34617944Smckusick idesc.id_numfrags = frags; 34717944Smckusick pass4check(&idesc); 34817944Smckusick } 34917944Smckusick 35017991Smckusick /* 35117991Smckusick * Find a pathname 35217991Smckusick */ 35317991Smckusick getpathname(namebuf, curdir, ino) 35417991Smckusick char *namebuf; 35517991Smckusick ino_t curdir, ino; 35617991Smckusick { 35717991Smckusick int len; 35817991Smckusick register char *cp; 35917991Smckusick struct inodesc idesc; 36017991Smckusick extern int findname(); 36117991Smckusick 36217991Smckusick if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 36317991Smckusick strcpy(namebuf, "?"); 36417991Smckusick return; 36517991Smckusick } 36617991Smckusick bzero(&idesc, sizeof(struct inodesc)); 36717991Smckusick idesc.id_type = DATA; 36817991Smckusick cp = &namebuf[BUFSIZ - 1]; 36930354Smckusick *cp = '\0'; 37017991Smckusick if (curdir != ino) { 37117991Smckusick idesc.id_parent = curdir; 37217991Smckusick goto namelookup; 37317991Smckusick } 37417991Smckusick while (ino != ROOTINO) { 37517991Smckusick idesc.id_number = ino; 37617991Smckusick idesc.id_func = findino; 37717991Smckusick idesc.id_name = ".."; 37830354Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 37917991Smckusick break; 38017991Smckusick namelookup: 38117991Smckusick idesc.id_number = idesc.id_parent; 38217991Smckusick idesc.id_parent = ino; 38317991Smckusick idesc.id_func = findname; 38417991Smckusick idesc.id_name = namebuf; 38530354Smckusick if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 38617991Smckusick break; 38717991Smckusick len = strlen(namebuf); 38817991Smckusick cp -= len; 38917991Smckusick if (cp < &namebuf[MAXNAMLEN]) 39017991Smckusick break; 39117991Smckusick bcopy(namebuf, cp, len); 39217991Smckusick *--cp = '/'; 39317991Smckusick ino = idesc.id_number; 39417991Smckusick } 39517991Smckusick if (ino != ROOTINO) { 39617991Smckusick strcpy(namebuf, "?"); 39717991Smckusick return; 39817991Smckusick } 39917991Smckusick bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 40017991Smckusick } 40117991Smckusick 40216269Smckusick catch() 40316269Smckusick { 40416269Smckusick 40516269Smckusick ckfini(); 40616269Smckusick exit(12); 40716269Smckusick } 40816269Smckusick 40916269Smckusick /* 41024680Skarels * When preening, allow a single quit to signal 41124680Skarels * a special exit after filesystem checks complete 41224680Skarels * so that reboot sequence may be interrupted. 41324680Skarels */ 41424680Skarels catchquit() 41524680Skarels { 41624680Skarels extern returntosingle; 41724680Skarels 41824680Skarels printf("returning to single-user after filesystem check\n"); 41924680Skarels returntosingle = 1; 42024680Skarels (void)signal(SIGQUIT, SIG_DFL); 42124680Skarels } 42224680Skarels 42324680Skarels /* 42424680Skarels * Ignore a single quit signal; wait and flush just in case. 42524680Skarels * Used by child processes in preen. 42624680Skarels */ 42724680Skarels voidquit() 42824680Skarels { 42924680Skarels 43024680Skarels sleep(1); 43124680Skarels (void)signal(SIGQUIT, SIG_IGN); 43224680Skarels (void)signal(SIGQUIT, SIG_DFL); 43324680Skarels } 43424680Skarels 43524680Skarels /* 43616269Smckusick * determine whether an inode should be fixed. 43716269Smckusick */ 43817931Smckusick dofix(idesc, msg) 43916269Smckusick register struct inodesc *idesc; 44017931Smckusick char *msg; 44116269Smckusick { 44216269Smckusick 44316269Smckusick switch (idesc->id_fix) { 44416269Smckusick 44516269Smckusick case DONTKNOW: 44617931Smckusick if (idesc->id_type == DATA) 44717931Smckusick direrr(idesc->id_number, msg); 44817931Smckusick else 44917931Smckusick pwarn(msg); 45017931Smckusick if (preen) { 45117931Smckusick printf(" (SALVAGED)\n"); 45217931Smckusick idesc->id_fix = FIX; 45317931Smckusick return (ALTERED); 45417931Smckusick } 45516269Smckusick if (reply("SALVAGE") == 0) { 45616269Smckusick idesc->id_fix = NOFIX; 45716269Smckusick return (0); 45816269Smckusick } 45916269Smckusick idesc->id_fix = FIX; 46016269Smckusick return (ALTERED); 46116269Smckusick 46216269Smckusick case FIX: 46316269Smckusick return (ALTERED); 46416269Smckusick 46516269Smckusick case NOFIX: 46616269Smckusick return (0); 46716269Smckusick 46816269Smckusick default: 46916269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 47016269Smckusick } 47116269Smckusick /* NOTREACHED */ 47216269Smckusick } 47316269Smckusick 47416269Smckusick /* VARARGS1 */ 47517931Smckusick errexit(s1, s2, s3, s4) 47616269Smckusick char *s1; 47716269Smckusick { 47816269Smckusick printf(s1, s2, s3, s4); 47916269Smckusick exit(8); 48016269Smckusick } 48116269Smckusick 48216269Smckusick /* 48316269Smckusick * An inconsistency occured which shouldn't during normal operations. 48416269Smckusick * Die if preening, otherwise just printf. 48516269Smckusick */ 48616269Smckusick /* VARARGS1 */ 48716269Smckusick pfatal(s, a1, a2, a3) 48816269Smckusick char *s; 48916269Smckusick { 49016269Smckusick 49116269Smckusick if (preen) { 49216269Smckusick printf("%s: ", devname); 49316269Smckusick printf(s, a1, a2, a3); 49416269Smckusick printf("\n"); 49517931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 49617931Smckusick devname); 49717931Smckusick exit(8); 49816269Smckusick } 49916269Smckusick printf(s, a1, a2, a3); 50016269Smckusick } 50116269Smckusick 50216269Smckusick /* 50316269Smckusick * Pwarn is like printf when not preening, 50416269Smckusick * or a warning (preceded by filename) when preening. 50516269Smckusick */ 50616269Smckusick /* VARARGS1 */ 50716269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 50816269Smckusick char *s; 50916269Smckusick { 51016269Smckusick 51116269Smckusick if (preen) 51216269Smckusick printf("%s: ", devname); 51316269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 51416269Smckusick } 51516269Smckusick 51616269Smckusick #ifndef lint 51716269Smckusick /* 51816269Smckusick * Stub for routines from kernel. 51916269Smckusick */ 52016269Smckusick panic(s) 52116269Smckusick char *s; 52216269Smckusick { 52316269Smckusick 52417931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 52517931Smckusick errexit(s); 52616269Smckusick } 52716269Smckusick #endif 528