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*39973Smckusick static char sccsid[] = "@(#)utilities.c 5.19 (Berkeley) 02/01/90"; 922055Sdist #endif not lint 1016269Smckusick 1116269Smckusick #include <sys/param.h> 1239383Smckusick #include <ufs/dinode.h> 1338337Smckusick #include <ufs/fs.h> 1438337Smckusick #include <ufs/dir.h> 1539165Sbostic #include <stdio.h> 1639165Sbostic #include <ctype.h> 1716269Smckusick #include "fsck.h" 1816269Smckusick 1934225Smckusick long diskreads, totalreads; /* Disk cache statistics */ 2016269Smckusick long lseek(); 2138377Smckusick char *malloc(); 2216269Smckusick 2316269Smckusick ftypeok(dp) 24*39973Smckusick struct dinode *dp; 2516269Smckusick { 2616269Smckusick switch (dp->di_mode & IFMT) { 2716269Smckusick 2816269Smckusick case IFDIR: 2916269Smckusick case IFREG: 3016269Smckusick case IFBLK: 3116269Smckusick case IFCHR: 3216269Smckusick case IFLNK: 3316269Smckusick case IFSOCK: 3416269Smckusick return (1); 3516269Smckusick 3616269Smckusick default: 3716269Smckusick if (debug) 3816269Smckusick printf("bad file type 0%o\n", dp->di_mode); 3916269Smckusick return (0); 4016269Smckusick } 4116269Smckusick } 4216269Smckusick 43*39973Smckusick reply(mesg) 44*39973Smckusick char *mesg; 4516269Smckusick { 4616269Smckusick char line[80]; 47*39973Smckusick int cont = (strcmp(mesg, "CONTINUE") == 0); 4816269Smckusick 4916269Smckusick if (preen) 5016269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 51*39973Smckusick printf("\n%s? ", mesg); 52*39973Smckusick if (!cont && (nflag || fswritefd < 0)) { 5316269Smckusick printf(" no\n\n"); 5416269Smckusick return (0); 5516269Smckusick } 5630609Skarels if (yflag || (cont && nflag)) { 5716269Smckusick printf(" yes\n\n"); 5816269Smckusick return (1); 5916269Smckusick } 6016269Smckusick if (getline(stdin, line, sizeof(line)) == EOF) 6116269Smckusick errexit("\n"); 6216269Smckusick printf("\n"); 6316269Smckusick if (line[0] == 'y' || line[0] == 'Y') 6416269Smckusick return (1); 6516269Smckusick else 6616269Smckusick return (0); 6716269Smckusick } 6816269Smckusick 6916269Smckusick getline(fp, loc, maxlen) 7016269Smckusick FILE *fp; 7116269Smckusick char *loc; 72*39973Smckusick int maxlen; 7316269Smckusick { 74*39973Smckusick register long 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 { 94*39973Smckusick register struct bufarea *bp; 9534225Smckusick long bufcnt, i; 9634225Smckusick char *bufp; 9734225Smckusick 98*39973Smckusick bufp = malloc((unsigned int)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++) { 108*39973Smckusick bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 109*39973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 11038377Smckusick if (bp == NULL || bufp == NULL) { 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 */ 128*39973Smckusick struct bufarea * 12934225Smckusick getdatablk(blkno, size) 13034225Smckusick daddr_t blkno; 13134225Smckusick long size; 13234225Smckusick { 133*39973Smckusick register struct 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 157*39973Smckusick struct bufarea * 15816269Smckusick getblk(bp, blk, size) 159*39973Smckusick register struct bufarea *bp; 16016269Smckusick daddr_t blk; 16116269Smckusick long size; 16216269Smckusick { 16316269Smckusick daddr_t dblk; 16416269Smckusick 16534671Smckusick dblk = fsbtodb(&sblock, blk); 16634671Smckusick if (bp->b_bno == dblk) 16716269Smckusick return (bp); 168*39973Smckusick flush(fswritefd, bp); 16934225Smckusick diskreads++; 170*39973Smckusick bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 17134671Smckusick bp->b_bno = dblk; 17221540Smckusick bp->b_size = size; 17321540Smckusick return (bp); 17416269Smckusick } 17516269Smckusick 176*39973Smckusick flush(fd, bp) 177*39973Smckusick int fd; 178*39973Smckusick register struct bufarea *bp; 17916269Smckusick { 18017931Smckusick register int i, j; 18116269Smckusick 18217931Smckusick if (!bp->b_dirty) 18317931Smckusick return; 18421540Smckusick if (bp->b_errs != 0) 18530609Skarels pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 18630609Skarels (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 18730609Skarels bp->b_bno); 18816269Smckusick bp->b_dirty = 0; 18921540Smckusick bp->b_errs = 0; 190*39973Smckusick bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 19117931Smckusick if (bp != &sblk) 19217931Smckusick return; 19317931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 194*39973Smckusick bwrite(fswritefd, (char *)sblock.fs_csp[j], 19517931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 19617931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 19717931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 19817931Smckusick } 19916269Smckusick } 20016269Smckusick 201*39973Smckusick rwerror(mesg, blk) 202*39973Smckusick char *mesg; 20316269Smckusick daddr_t blk; 20416269Smckusick { 20516269Smckusick 20616269Smckusick if (preen == 0) 20716269Smckusick printf("\n"); 208*39973Smckusick pfatal("CANNOT %s: BLK %ld", mesg, blk); 20916269Smckusick if (reply("CONTINUE") == 0) 21016269Smckusick errexit("Program terminated\n"); 21116269Smckusick } 21216269Smckusick 21316269Smckusick ckfini() 21416269Smckusick { 215*39973Smckusick register struct bufarea *bp, *nbp; 21634482Smckusick int cnt = 0; 21716269Smckusick 218*39973Smckusick flush(fswritefd, &sblk); 21930859Skarels if (havesb && sblk.b_bno != SBOFF / dev_bsize && 22030518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 22130556Smckusick sblk.b_bno = SBOFF / dev_bsize; 22216269Smckusick sbdirty(); 223*39973Smckusick flush(fswritefd, &sblk); 22416269Smckusick } 225*39973Smckusick flush(fswritefd, &cgblk); 22638342Smckusick free(cgblk.b_un.b_buf); 22738342Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) { 22834482Smckusick cnt++; 229*39973Smckusick flush(fswritefd, bp); 23038342Smckusick nbp = bp->b_prev; 23138342Smckusick free(bp->b_un.b_buf); 23238342Smckusick free((char *)bp); 23334482Smckusick } 23434482Smckusick if (bufhead.b_size != cnt) 23534482Smckusick errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 23634225Smckusick if (debug) 23734482Smckusick printf("cache missed %d of %d (%d%%)\n", diskreads, 23834482Smckusick totalreads, diskreads * 100 / totalreads); 239*39973Smckusick (void)close(fsreadfd); 240*39973Smckusick (void)close(fswritefd); 24116269Smckusick } 24216269Smckusick 243*39973Smckusick bread(fd, buf, blk, size) 244*39973Smckusick int fd; 24516269Smckusick char *buf; 24616269Smckusick daddr_t blk; 24716269Smckusick long size; 24816269Smckusick { 24921540Smckusick char *cp; 25021540Smckusick int i, errs; 25121540Smckusick 252*39973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 253*39973Smckusick rwerror("SEEK", blk); 254*39973Smckusick else if (read(fd, buf, (int)size) == size) 25521540Smckusick return (0); 256*39973Smckusick rwerror("READ", blk); 257*39973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 258*39973Smckusick rwerror("SEEK", blk); 25921540Smckusick errs = 0; 260*39973Smckusick bzero(buf, (int)size); 26130609Skarels printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 26230609Skarels for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 263*39973Smckusick if (read(fd, cp, (int)secsize) < 0) { 264*39973Smckusick lseek(fd, blk * dev_bsize + i + secsize, 0); 26530859Skarels if (secsize != dev_bsize && dev_bsize != 1) 26630609Skarels printf(" %d (%d),", 26730609Skarels (blk * dev_bsize + i) / secsize, 26830609Skarels blk + i / dev_bsize); 26930609Skarels else 27030609Skarels printf(" %d,", blk + i / dev_bsize); 27121540Smckusick errs++; 27221540Smckusick } 27321540Smckusick } 27421758Smckusick printf("\n"); 27521540Smckusick return (errs); 27616269Smckusick } 27716269Smckusick 278*39973Smckusick bwrite(fd, buf, blk, size) 279*39973Smckusick int fd; 28016269Smckusick char *buf; 28116269Smckusick daddr_t blk; 28216269Smckusick long size; 28316269Smckusick { 28421758Smckusick int i; 28521758Smckusick char *cp; 28616269Smckusick 287*39973Smckusick if (fd < 0) 28821758Smckusick return; 289*39973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 290*39973Smckusick rwerror("SEEK", blk); 291*39973Smckusick else if (write(fd, buf, (int)size) == size) { 292*39973Smckusick fsmodified = 1; 29321758Smckusick return; 29416269Smckusick } 295*39973Smckusick rwerror("WRITE", blk); 296*39973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 297*39973Smckusick 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) 300*39973Smckusick if (write(fd, cp, (int)dev_bsize) < 0) { 301*39973Smckusick lseek(fd, blk * dev_bsize + i + dev_bsize, 0); 30230518Smckusick printf(" %d,", 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) 312*39973Smckusick long frags; 31317944Smckusick { 31417944Smckusick register int i, j, k; 31517944Smckusick 31617944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 31717944Smckusick return (0); 318*39973Smckusick for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 31917944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 320*39973Smckusick if (testbmap(i + j)) 32117944Smckusick continue; 32217944Smckusick for (k = 1; k < frags; k++) 323*39973Smckusick 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; 343*39973Smckusick long frags; 34417944Smckusick { 34517944Smckusick struct inodesc idesc; 34617944Smckusick 34717944Smckusick idesc.id_blkno = blkno; 34817944Smckusick idesc.id_numfrags = frags; 34917944Smckusick 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; 36217991Smckusick extern int findname(); 36317991Smckusick 36417991Smckusick if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 36517991Smckusick strcpy(namebuf, "?"); 36617991Smckusick return; 36717991Smckusick } 368*39973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 36917991Smckusick idesc.id_type = DATA; 37017991Smckusick cp = &namebuf[BUFSIZ - 1]; 37130354Smckusick *cp = '\0'; 37217991Smckusick if (curdir != ino) { 37317991Smckusick idesc.id_parent = curdir; 37417991Smckusick goto namelookup; 37517991Smckusick } 37617991Smckusick while (ino != ROOTINO) { 37717991Smckusick idesc.id_number = ino; 37817991Smckusick idesc.id_func = findino; 37917991Smckusick idesc.id_name = ".."; 38030354Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 38117991Smckusick break; 38217991Smckusick namelookup: 38317991Smckusick idesc.id_number = idesc.id_parent; 38417991Smckusick idesc.id_parent = ino; 38517991Smckusick idesc.id_func = findname; 38617991Smckusick idesc.id_name = namebuf; 38730354Smckusick if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 38817991Smckusick break; 38917991Smckusick len = strlen(namebuf); 39017991Smckusick cp -= len; 39117991Smckusick if (cp < &namebuf[MAXNAMLEN]) 39217991Smckusick break; 39317991Smckusick bcopy(namebuf, cp, len); 39417991Smckusick *--cp = '/'; 39517991Smckusick ino = idesc.id_number; 39617991Smckusick } 39717991Smckusick if (ino != ROOTINO) { 39817991Smckusick strcpy(namebuf, "?"); 39917991Smckusick return; 40017991Smckusick } 40117991Smckusick bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 40217991Smckusick } 40317991Smckusick 40439165Sbostic void 40516269Smckusick catch() 40616269Smckusick { 40716269Smckusick ckfini(); 40816269Smckusick exit(12); 40916269Smckusick } 41016269Smckusick 41116269Smckusick /* 41224680Skarels * When preening, allow a single quit to signal 41324680Skarels * a special exit after filesystem checks complete 41424680Skarels * so that reboot sequence may be interrupted. 41524680Skarels */ 41639165Sbostic void 41724680Skarels catchquit() 41824680Skarels { 41924680Skarels extern returntosingle; 42024680Skarels 42124680Skarels printf("returning to single-user after filesystem check\n"); 42224680Skarels returntosingle = 1; 42324680Skarels (void)signal(SIGQUIT, SIG_DFL); 42424680Skarels } 42524680Skarels 42624680Skarels /* 42724680Skarels * Ignore a single quit signal; wait and flush just in case. 42824680Skarels * Used by child processes in preen. 42924680Skarels */ 43039165Sbostic void 43124680Skarels voidquit() 43224680Skarels { 43324680Skarels 43424680Skarels sleep(1); 43524680Skarels (void)signal(SIGQUIT, SIG_IGN); 43624680Skarels (void)signal(SIGQUIT, SIG_DFL); 43724680Skarels } 43824680Skarels 43924680Skarels /* 44016269Smckusick * determine whether an inode should be fixed. 44116269Smckusick */ 44217931Smckusick dofix(idesc, msg) 44316269Smckusick register struct inodesc *idesc; 44417931Smckusick char *msg; 44516269Smckusick { 44616269Smckusick 44716269Smckusick switch (idesc->id_fix) { 44816269Smckusick 44916269Smckusick case DONTKNOW: 45017931Smckusick if (idesc->id_type == DATA) 451*39973Smckusick direrror(idesc->id_number, msg); 45217931Smckusick else 45317931Smckusick pwarn(msg); 45417931Smckusick if (preen) { 45517931Smckusick printf(" (SALVAGED)\n"); 45617931Smckusick idesc->id_fix = FIX; 45717931Smckusick return (ALTERED); 45817931Smckusick } 45916269Smckusick if (reply("SALVAGE") == 0) { 46016269Smckusick idesc->id_fix = NOFIX; 46116269Smckusick return (0); 46216269Smckusick } 46316269Smckusick idesc->id_fix = FIX; 46416269Smckusick return (ALTERED); 46516269Smckusick 46616269Smckusick case FIX: 46716269Smckusick return (ALTERED); 46816269Smckusick 46916269Smckusick case NOFIX: 47016269Smckusick return (0); 47116269Smckusick 47216269Smckusick default: 47316269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 47416269Smckusick } 47516269Smckusick /* NOTREACHED */ 47616269Smckusick } 47716269Smckusick 47816269Smckusick /* VARARGS1 */ 47917931Smckusick errexit(s1, s2, s3, s4) 48016269Smckusick char *s1; 48116269Smckusick { 48216269Smckusick printf(s1, s2, s3, s4); 48316269Smckusick exit(8); 48416269Smckusick } 48516269Smckusick 48616269Smckusick /* 487*39973Smckusick * An unexpected inconsistency occured. 488*39973Smckusick * Die if preening, otherwise just print message and continue. 48916269Smckusick */ 49016269Smckusick /* VARARGS1 */ 49116269Smckusick pfatal(s, a1, a2, a3) 49216269Smckusick char *s; 49316269Smckusick { 49416269Smckusick 49516269Smckusick if (preen) { 49616269Smckusick printf("%s: ", devname); 49716269Smckusick printf(s, a1, a2, a3); 49816269Smckusick printf("\n"); 49917931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 50017931Smckusick devname); 50117931Smckusick exit(8); 50216269Smckusick } 50316269Smckusick printf(s, a1, a2, a3); 50416269Smckusick } 50516269Smckusick 50616269Smckusick /* 507*39973Smckusick * Pwarn just prints a message when not preening, 50816269Smckusick * or a warning (preceded by filename) when preening. 50916269Smckusick */ 51016269Smckusick /* VARARGS1 */ 51116269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 51216269Smckusick char *s; 51316269Smckusick { 51416269Smckusick 51516269Smckusick if (preen) 51616269Smckusick printf("%s: ", devname); 51716269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 51816269Smckusick } 51916269Smckusick 52016269Smckusick #ifndef lint 52116269Smckusick /* 52216269Smckusick * Stub for routines from kernel. 52316269Smckusick */ 52416269Smckusick panic(s) 52516269Smckusick char *s; 52616269Smckusick { 52716269Smckusick 52817931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 52917931Smckusick errexit(s); 53016269Smckusick } 53116269Smckusick #endif 532