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*39975Smckusick static char sccsid[] = "@(#)utilities.c 5.20 (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) 2439973Smckusick 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*39975Smckusick reply(question) 44*39975Smckusick char *question; 4516269Smckusick { 46*39975Smckusick int persevere; 47*39975Smckusick char c; 4816269Smckusick 4916269Smckusick if (preen) 5016269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 51*39975Smckusick persevere = !strcmp(question, "CONTINUE"); 52*39975Smckusick printf("\n"); 53*39975Smckusick if (!persevere && (nflag || fswritefd < 0)) { 54*39975Smckusick printf("%s? no\n\n", question); 5516269Smckusick return (0); 5616269Smckusick } 57*39975Smckusick if (yflag || (persevere && nflag)) { 58*39975Smckusick printf("%s? yes\n\n", question); 5916269Smckusick return (1); 6016269Smckusick } 61*39975Smckusick do { 62*39975Smckusick printf("%s? [yn] ", question); 63*39975Smckusick (void) fflush(stdout); 64*39975Smckusick c = getc(stdin); 65*39975Smckusick while (c != '\n' && getc(stdin) != '\n') 66*39975Smckusick if (feof(stdin)) 67*39975Smckusick return (0); 68*39975Smckusick } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 6916269Smckusick printf("\n"); 70*39975Smckusick if (c == 'y' || c == 'Y') 7116269Smckusick return (1); 72*39975Smckusick return (0); 7316269Smckusick } 7416269Smckusick 7534225Smckusick /* 7634225Smckusick * Malloc buffers and set up cache. 7734225Smckusick */ 7834225Smckusick bufinit() 7934225Smckusick { 8039973Smckusick register struct bufarea *bp; 8134225Smckusick long bufcnt, i; 8234225Smckusick char *bufp; 8334225Smckusick 8439973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 8534225Smckusick if (bufp == 0) 8634225Smckusick errexit("cannot allocate buffer pool\n"); 8734225Smckusick cgblk.b_un.b_buf = bufp; 8834225Smckusick initbarea(&cgblk); 8934225Smckusick bufhead.b_next = bufhead.b_prev = &bufhead; 9034225Smckusick bufcnt = MAXBUFSPACE / sblock.fs_bsize; 9134225Smckusick if (bufcnt < MINBUFS) 9234225Smckusick bufcnt = MINBUFS; 9334225Smckusick for (i = 0; i < bufcnt; i++) { 9439973Smckusick bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 9539973Smckusick bufp = malloc((unsigned int)sblock.fs_bsize); 9638377Smckusick if (bp == NULL || bufp == NULL) { 9734225Smckusick if (i >= MINBUFS) 9834225Smckusick break; 9934225Smckusick errexit("cannot allocate buffer pool\n"); 10034225Smckusick } 10134225Smckusick bp->b_un.b_buf = bufp; 10234225Smckusick bp->b_prev = &bufhead; 10334225Smckusick bp->b_next = bufhead.b_next; 10434225Smckusick bufhead.b_next->b_prev = bp; 10534225Smckusick bufhead.b_next = bp; 10634225Smckusick initbarea(bp); 10734225Smckusick } 10834482Smckusick bufhead.b_size = i; /* save number of buffers */ 10934225Smckusick } 11034225Smckusick 11134225Smckusick /* 11234225Smckusick * Manage a cache of directory blocks. 11334225Smckusick */ 11439973Smckusick struct bufarea * 11534225Smckusick getdatablk(blkno, size) 11634225Smckusick daddr_t blkno; 11734225Smckusick long size; 11834225Smckusick { 11939973Smckusick register struct bufarea *bp; 12034225Smckusick 12134225Smckusick for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 12234671Smckusick if (bp->b_bno == fsbtodb(&sblock, blkno)) 12334225Smckusick goto foundit; 12434225Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 12534225Smckusick if ((bp->b_flags & B_INUSE) == 0) 12634225Smckusick break; 12734225Smckusick if (bp == &bufhead) 12834225Smckusick errexit("deadlocked buffer pool\n"); 12934225Smckusick getblk(bp, blkno, size); 13034225Smckusick /* fall through */ 13134225Smckusick foundit: 13234225Smckusick totalreads++; 13334225Smckusick bp->b_prev->b_next = bp->b_next; 13434225Smckusick bp->b_next->b_prev = bp->b_prev; 13534225Smckusick bp->b_prev = &bufhead; 13634225Smckusick bp->b_next = bufhead.b_next; 13734225Smckusick bufhead.b_next->b_prev = bp; 13834225Smckusick bufhead.b_next = bp; 13934225Smckusick bp->b_flags |= B_INUSE; 14034225Smckusick return (bp); 14134225Smckusick } 14234225Smckusick 14339973Smckusick struct bufarea * 14416269Smckusick getblk(bp, blk, size) 14539973Smckusick register struct bufarea *bp; 14616269Smckusick daddr_t blk; 14716269Smckusick long size; 14816269Smckusick { 14916269Smckusick daddr_t dblk; 15016269Smckusick 15134671Smckusick dblk = fsbtodb(&sblock, blk); 15234671Smckusick if (bp->b_bno == dblk) 15316269Smckusick return (bp); 15439973Smckusick flush(fswritefd, bp); 15534225Smckusick diskreads++; 15639973Smckusick bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 15734671Smckusick bp->b_bno = dblk; 15821540Smckusick bp->b_size = size; 15921540Smckusick return (bp); 16016269Smckusick } 16116269Smckusick 16239973Smckusick flush(fd, bp) 16339973Smckusick int fd; 16439973Smckusick register struct bufarea *bp; 16516269Smckusick { 16617931Smckusick register int i, j; 16716269Smckusick 16817931Smckusick if (!bp->b_dirty) 16917931Smckusick return; 17021540Smckusick if (bp->b_errs != 0) 17130609Skarels pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 17230609Skarels (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 17330609Skarels bp->b_bno); 17416269Smckusick bp->b_dirty = 0; 17521540Smckusick bp->b_errs = 0; 17639973Smckusick bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 17717931Smckusick if (bp != &sblk) 17817931Smckusick return; 17917931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 18039973Smckusick bwrite(fswritefd, (char *)sblock.fs_csp[j], 18117931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 18217931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 18317931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 18417931Smckusick } 18516269Smckusick } 18616269Smckusick 18739973Smckusick rwerror(mesg, blk) 18839973Smckusick char *mesg; 18916269Smckusick daddr_t blk; 19016269Smckusick { 19116269Smckusick 19216269Smckusick if (preen == 0) 19316269Smckusick printf("\n"); 19439973Smckusick pfatal("CANNOT %s: BLK %ld", mesg, blk); 19516269Smckusick if (reply("CONTINUE") == 0) 19616269Smckusick errexit("Program terminated\n"); 19716269Smckusick } 19816269Smckusick 19916269Smckusick ckfini() 20016269Smckusick { 20139973Smckusick register struct bufarea *bp, *nbp; 20234482Smckusick int cnt = 0; 20316269Smckusick 20439973Smckusick flush(fswritefd, &sblk); 20530859Skarels if (havesb && sblk.b_bno != SBOFF / dev_bsize && 20630518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 20730556Smckusick sblk.b_bno = SBOFF / dev_bsize; 20816269Smckusick sbdirty(); 20939973Smckusick flush(fswritefd, &sblk); 21016269Smckusick } 21139973Smckusick flush(fswritefd, &cgblk); 21238342Smckusick free(cgblk.b_un.b_buf); 21338342Smckusick for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) { 21434482Smckusick cnt++; 21539973Smckusick flush(fswritefd, bp); 21638342Smckusick nbp = bp->b_prev; 21738342Smckusick free(bp->b_un.b_buf); 21838342Smckusick free((char *)bp); 21934482Smckusick } 22034482Smckusick if (bufhead.b_size != cnt) 22134482Smckusick errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt); 22234225Smckusick if (debug) 22334482Smckusick printf("cache missed %d of %d (%d%%)\n", diskreads, 22434482Smckusick totalreads, diskreads * 100 / totalreads); 22539973Smckusick (void)close(fsreadfd); 22639973Smckusick (void)close(fswritefd); 22716269Smckusick } 22816269Smckusick 22939973Smckusick bread(fd, buf, blk, size) 23039973Smckusick int fd; 23116269Smckusick char *buf; 23216269Smckusick daddr_t blk; 23316269Smckusick long size; 23416269Smckusick { 23521540Smckusick char *cp; 23621540Smckusick int i, errs; 23721540Smckusick 23839973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 23939973Smckusick rwerror("SEEK", blk); 24039973Smckusick else if (read(fd, buf, (int)size) == size) 24121540Smckusick return (0); 24239973Smckusick rwerror("READ", blk); 24339973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 24439973Smckusick rwerror("SEEK", blk); 24521540Smckusick errs = 0; 24639973Smckusick bzero(buf, (int)size); 24730609Skarels printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 24830609Skarels for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 24939973Smckusick if (read(fd, cp, (int)secsize) < 0) { 25039973Smckusick lseek(fd, blk * dev_bsize + i + secsize, 0); 25130859Skarels if (secsize != dev_bsize && dev_bsize != 1) 25230609Skarels printf(" %d (%d),", 25330609Skarels (blk * dev_bsize + i) / secsize, 25430609Skarels blk + i / dev_bsize); 25530609Skarels else 25630609Skarels printf(" %d,", blk + i / dev_bsize); 25721540Smckusick errs++; 25821540Smckusick } 25921540Smckusick } 26021758Smckusick printf("\n"); 26121540Smckusick return (errs); 26216269Smckusick } 26316269Smckusick 26439973Smckusick bwrite(fd, buf, blk, size) 26539973Smckusick int fd; 26616269Smckusick char *buf; 26716269Smckusick daddr_t blk; 26816269Smckusick long size; 26916269Smckusick { 27021758Smckusick int i; 27121758Smckusick char *cp; 27216269Smckusick 27339973Smckusick if (fd < 0) 27421758Smckusick return; 27539973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 27639973Smckusick rwerror("SEEK", blk); 27739973Smckusick else if (write(fd, buf, (int)size) == size) { 27839973Smckusick fsmodified = 1; 27921758Smckusick return; 28016269Smckusick } 28139973Smckusick rwerror("WRITE", blk); 28239973Smckusick if (lseek(fd, blk * dev_bsize, 0) < 0) 28339973Smckusick rwerror("SEEK", blk); 28430609Skarels printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 28530518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 28639973Smckusick if (write(fd, cp, (int)dev_bsize) < 0) { 28739973Smckusick lseek(fd, blk * dev_bsize + i + dev_bsize, 0); 28830518Smckusick printf(" %d,", blk + i / dev_bsize); 28930395Smckusick } 29021758Smckusick printf("\n"); 29121758Smckusick return; 29216269Smckusick } 29316269Smckusick 29417944Smckusick /* 29517944Smckusick * allocate a data block with the specified number of fragments 29617944Smckusick */ 29717944Smckusick allocblk(frags) 29839973Smckusick long frags; 29917944Smckusick { 30017944Smckusick register int i, j, k; 30117944Smckusick 30217944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 30317944Smckusick return (0); 30439973Smckusick for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 30517944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 30639973Smckusick if (testbmap(i + j)) 30717944Smckusick continue; 30817944Smckusick for (k = 1; k < frags; k++) 30939973Smckusick if (testbmap(i + j + k)) 31017944Smckusick break; 31117944Smckusick if (k < frags) { 31217944Smckusick j += k; 31317944Smckusick continue; 31417944Smckusick } 31517944Smckusick for (k = 0; k < frags; k++) 31617944Smckusick setbmap(i + j + k); 31717944Smckusick n_blks += frags; 31817944Smckusick return (i + j); 31917944Smckusick } 32017944Smckusick } 32117944Smckusick return (0); 32217944Smckusick } 32317944Smckusick 32417944Smckusick /* 32517944Smckusick * Free a previously allocated block 32617944Smckusick */ 32717944Smckusick freeblk(blkno, frags) 32817944Smckusick daddr_t blkno; 32939973Smckusick long frags; 33017944Smckusick { 33117944Smckusick struct inodesc idesc; 33217944Smckusick 33317944Smckusick idesc.id_blkno = blkno; 33417944Smckusick idesc.id_numfrags = frags; 33517944Smckusick pass4check(&idesc); 33617944Smckusick } 33717944Smckusick 33817991Smckusick /* 33917991Smckusick * Find a pathname 34017991Smckusick */ 34117991Smckusick getpathname(namebuf, curdir, ino) 34217991Smckusick char *namebuf; 34317991Smckusick ino_t curdir, ino; 34417991Smckusick { 34517991Smckusick int len; 34617991Smckusick register char *cp; 34717991Smckusick struct inodesc idesc; 34817991Smckusick extern int findname(); 34917991Smckusick 35017991Smckusick if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 35117991Smckusick strcpy(namebuf, "?"); 35217991Smckusick return; 35317991Smckusick } 35439973Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 35517991Smckusick idesc.id_type = DATA; 35617991Smckusick cp = &namebuf[BUFSIZ - 1]; 35730354Smckusick *cp = '\0'; 35817991Smckusick if (curdir != ino) { 35917991Smckusick idesc.id_parent = curdir; 36017991Smckusick goto namelookup; 36117991Smckusick } 36217991Smckusick while (ino != ROOTINO) { 36317991Smckusick idesc.id_number = ino; 36417991Smckusick idesc.id_func = findino; 36517991Smckusick idesc.id_name = ".."; 36630354Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 36717991Smckusick break; 36817991Smckusick namelookup: 36917991Smckusick idesc.id_number = idesc.id_parent; 37017991Smckusick idesc.id_parent = ino; 37117991Smckusick idesc.id_func = findname; 37217991Smckusick idesc.id_name = namebuf; 37330354Smckusick if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 37417991Smckusick break; 37517991Smckusick len = strlen(namebuf); 37617991Smckusick cp -= len; 37717991Smckusick if (cp < &namebuf[MAXNAMLEN]) 37817991Smckusick break; 37917991Smckusick bcopy(namebuf, cp, len); 38017991Smckusick *--cp = '/'; 38117991Smckusick ino = idesc.id_number; 38217991Smckusick } 38317991Smckusick if (ino != ROOTINO) { 38417991Smckusick strcpy(namebuf, "?"); 38517991Smckusick return; 38617991Smckusick } 38717991Smckusick bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 38817991Smckusick } 38917991Smckusick 39039165Sbostic void 39116269Smckusick catch() 39216269Smckusick { 39316269Smckusick ckfini(); 39416269Smckusick exit(12); 39516269Smckusick } 39616269Smckusick 39716269Smckusick /* 39824680Skarels * When preening, allow a single quit to signal 39924680Skarels * a special exit after filesystem checks complete 40024680Skarels * so that reboot sequence may be interrupted. 40124680Skarels */ 40239165Sbostic void 40324680Skarels catchquit() 40424680Skarels { 40524680Skarels extern returntosingle; 40624680Skarels 40724680Skarels printf("returning to single-user after filesystem check\n"); 40824680Skarels returntosingle = 1; 40924680Skarels (void)signal(SIGQUIT, SIG_DFL); 41024680Skarels } 41124680Skarels 41224680Skarels /* 41324680Skarels * Ignore a single quit signal; wait and flush just in case. 41424680Skarels * Used by child processes in preen. 41524680Skarels */ 41639165Sbostic void 41724680Skarels voidquit() 41824680Skarels { 41924680Skarels 42024680Skarels sleep(1); 42124680Skarels (void)signal(SIGQUIT, SIG_IGN); 42224680Skarels (void)signal(SIGQUIT, SIG_DFL); 42324680Skarels } 42424680Skarels 42524680Skarels /* 42616269Smckusick * determine whether an inode should be fixed. 42716269Smckusick */ 42817931Smckusick dofix(idesc, msg) 42916269Smckusick register struct inodesc *idesc; 43017931Smckusick char *msg; 43116269Smckusick { 43216269Smckusick 43316269Smckusick switch (idesc->id_fix) { 43416269Smckusick 43516269Smckusick case DONTKNOW: 43617931Smckusick if (idesc->id_type == DATA) 43739973Smckusick direrror(idesc->id_number, msg); 43817931Smckusick else 43917931Smckusick pwarn(msg); 44017931Smckusick if (preen) { 44117931Smckusick printf(" (SALVAGED)\n"); 44217931Smckusick idesc->id_fix = FIX; 44317931Smckusick return (ALTERED); 44417931Smckusick } 44516269Smckusick if (reply("SALVAGE") == 0) { 44616269Smckusick idesc->id_fix = NOFIX; 44716269Smckusick return (0); 44816269Smckusick } 44916269Smckusick idesc->id_fix = FIX; 45016269Smckusick return (ALTERED); 45116269Smckusick 45216269Smckusick case FIX: 45316269Smckusick return (ALTERED); 45416269Smckusick 45516269Smckusick case NOFIX: 45616269Smckusick return (0); 45716269Smckusick 45816269Smckusick default: 45916269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 46016269Smckusick } 46116269Smckusick /* NOTREACHED */ 46216269Smckusick } 46316269Smckusick 46416269Smckusick /* VARARGS1 */ 46517931Smckusick errexit(s1, s2, s3, s4) 46616269Smckusick char *s1; 46716269Smckusick { 46816269Smckusick printf(s1, s2, s3, s4); 46916269Smckusick exit(8); 47016269Smckusick } 47116269Smckusick 47216269Smckusick /* 47339973Smckusick * An unexpected inconsistency occured. 47439973Smckusick * Die if preening, otherwise just print message and continue. 47516269Smckusick */ 47616269Smckusick /* VARARGS1 */ 47716269Smckusick pfatal(s, a1, a2, a3) 47816269Smckusick char *s; 47916269Smckusick { 48016269Smckusick 48116269Smckusick if (preen) { 48216269Smckusick printf("%s: ", devname); 48316269Smckusick printf(s, a1, a2, a3); 48416269Smckusick printf("\n"); 48517931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 48617931Smckusick devname); 48717931Smckusick exit(8); 48816269Smckusick } 48916269Smckusick printf(s, a1, a2, a3); 49016269Smckusick } 49116269Smckusick 49216269Smckusick /* 49339973Smckusick * Pwarn just prints a message when not preening, 49416269Smckusick * or a warning (preceded by filename) when preening. 49516269Smckusick */ 49616269Smckusick /* VARARGS1 */ 49716269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 49816269Smckusick char *s; 49916269Smckusick { 50016269Smckusick 50116269Smckusick if (preen) 50216269Smckusick printf("%s: ", devname); 50316269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 50416269Smckusick } 50516269Smckusick 50616269Smckusick #ifndef lint 50716269Smckusick /* 50816269Smckusick * Stub for routines from kernel. 50916269Smckusick */ 51016269Smckusick panic(s) 51116269Smckusick char *s; 51216269Smckusick { 51316269Smckusick 51417931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 51517931Smckusick errexit(s); 51616269Smckusick } 51716269Smckusick #endif 518