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*30518Smckusick static char sccsid[] = "@(#)utilities.c 5.6 (Berkeley) 02/18/87"; 922055Sdist #endif not lint 1016269Smckusick 1116269Smckusick #include <stdio.h> 1216269Smckusick #include <ctype.h> 1316269Smckusick #include <sys/param.h> 1416269Smckusick #include <sys/inode.h> 1516269Smckusick #include <sys/fs.h> 1617991Smckusick #include <sys/dir.h> 1716269Smckusick #include "fsck.h" 1816269Smckusick 1916269Smckusick long lseek(); 2016269Smckusick 2116269Smckusick ftypeok(dp) 2216269Smckusick DINODE *dp; 2316269Smckusick { 2416269Smckusick switch (dp->di_mode & IFMT) { 2516269Smckusick 2616269Smckusick case IFDIR: 2716269Smckusick case IFREG: 2816269Smckusick case IFBLK: 2916269Smckusick case IFCHR: 3016269Smckusick case IFLNK: 3116269Smckusick case IFSOCK: 3216269Smckusick return (1); 3316269Smckusick 3416269Smckusick default: 3516269Smckusick if (debug) 3616269Smckusick printf("bad file type 0%o\n", dp->di_mode); 3716269Smckusick return (0); 3816269Smckusick } 3916269Smckusick } 4016269Smckusick 4116269Smckusick reply(s) 4216269Smckusick char *s; 4316269Smckusick { 4416269Smckusick char line[80]; 4516269Smckusick 4616269Smckusick if (preen) 4716269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 4816269Smckusick printf("\n%s? ", s); 4916269Smckusick if (nflag || dfile.wfdes < 0) { 5016269Smckusick printf(" no\n\n"); 5116269Smckusick return (0); 5216269Smckusick } 5316269Smckusick if (yflag) { 5416269Smckusick printf(" yes\n\n"); 5516269Smckusick return (1); 5616269Smckusick } 5716269Smckusick if (getline(stdin, line, sizeof(line)) == EOF) 5816269Smckusick errexit("\n"); 5916269Smckusick printf("\n"); 6016269Smckusick if (line[0] == 'y' || line[0] == 'Y') 6116269Smckusick return (1); 6216269Smckusick else 6316269Smckusick return (0); 6416269Smckusick } 6516269Smckusick 6616269Smckusick getline(fp, loc, maxlen) 6716269Smckusick FILE *fp; 6816269Smckusick char *loc; 6916269Smckusick { 7016269Smckusick register n; 7116269Smckusick register char *p, *lastloc; 7216269Smckusick 7316269Smckusick p = loc; 7416269Smckusick lastloc = &p[maxlen-1]; 7516269Smckusick while ((n = getc(fp)) != '\n') { 7616269Smckusick if (n == EOF) 7716269Smckusick return (EOF); 7816269Smckusick if (!isspace(n) && p < lastloc) 7916269Smckusick *p++ = n; 8016269Smckusick } 8116269Smckusick *p = 0; 8216269Smckusick return (p - loc); 8316269Smckusick } 8416269Smckusick 8516269Smckusick BUFAREA * 8616269Smckusick getblk(bp, blk, size) 8716269Smckusick register BUFAREA *bp; 8816269Smckusick daddr_t blk; 8916269Smckusick long size; 9016269Smckusick { 9116269Smckusick register struct filecntl *fcp; 9216269Smckusick daddr_t dblk; 9316269Smckusick 9416269Smckusick fcp = &dfile; 9516269Smckusick dblk = fsbtodb(&sblock, blk); 9616269Smckusick if (bp->b_bno == dblk) 9716269Smckusick return (bp); 9816269Smckusick flush(fcp, bp); 9921540Smckusick bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size); 10021540Smckusick bp->b_bno = dblk; 10121540Smckusick bp->b_size = size; 10221540Smckusick return (bp); 10316269Smckusick } 10416269Smckusick 10516269Smckusick flush(fcp, bp) 10616269Smckusick struct filecntl *fcp; 10716269Smckusick register BUFAREA *bp; 10816269Smckusick { 10917931Smckusick register int i, j; 11016269Smckusick 11117931Smckusick if (!bp->b_dirty) 11217931Smckusick return; 11321540Smckusick if (bp->b_errs != 0) 11421540Smckusick pfatal("WRITING ZERO'ED BLOCK %d TO DISK\n", bp->b_bno); 11516269Smckusick bp->b_dirty = 0; 11621540Smckusick bp->b_errs = 0; 11721758Smckusick bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 11817931Smckusick if (bp != &sblk) 11917931Smckusick return; 12017931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 12121758Smckusick bwrite(&dfile, (char *)sblock.fs_csp[j], 12217931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 12317931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 12417931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 12517931Smckusick } 12616269Smckusick } 12716269Smckusick 12816269Smckusick rwerr(s, blk) 12916269Smckusick char *s; 13016269Smckusick daddr_t blk; 13116269Smckusick { 13216269Smckusick 13316269Smckusick if (preen == 0) 13416269Smckusick printf("\n"); 13516269Smckusick pfatal("CANNOT %s: BLK %ld", s, blk); 13616269Smckusick if (reply("CONTINUE") == 0) 13716269Smckusick errexit("Program terminated\n"); 13816269Smckusick } 13916269Smckusick 14016269Smckusick ckfini() 14116269Smckusick { 14216269Smckusick 14316269Smckusick flush(&dfile, &fileblk); 14416269Smckusick flush(&dfile, &sblk); 145*30518Smckusick if (sblk.b_bno != SBLOCK * DEV_BSIZE / dev_bsize && 146*30518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 147*30518Smckusick sblk.b_bno = SBLOCK * DEV_BSIZE / dev_bsize; 14816269Smckusick sbdirty(); 14916269Smckusick flush(&dfile, &sblk); 15016269Smckusick } 15116269Smckusick flush(&dfile, &inoblk); 15218002Smckusick flush(&dfile, &cgblk); 15316269Smckusick (void)close(dfile.rfdes); 15416269Smckusick (void)close(dfile.wfdes); 15516269Smckusick } 15616269Smckusick 15716269Smckusick bread(fcp, buf, blk, size) 15816269Smckusick register struct filecntl *fcp; 15916269Smckusick char *buf; 16016269Smckusick daddr_t blk; 16116269Smckusick long size; 16216269Smckusick { 16321540Smckusick char *cp; 16421540Smckusick int i, errs; 16521540Smckusick 16616269Smckusick if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) 16716269Smckusick rwerr("SEEK", blk); 16816269Smckusick else if (read(fcp->rfdes, buf, (int)size) == size) 16921540Smckusick return (0); 17016269Smckusick rwerr("READ", blk); 17121540Smckusick if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0) 17221540Smckusick rwerr("SEEK", blk); 17321540Smckusick errs = 0; 17430463Smckusick bzero(buf, size); 17521758Smckusick pfatal("THE FOLLOWING SECTORS COULD NOT BE READ:"); 176*30518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) { 177*30518Smckusick if (read(fcp->rfdes, cp, dev_bsize) < 0) { 178*30518Smckusick lseek(fcp->rfdes, (long)dbtob(blk) + i + dev_bsize, 0); 179*30518Smckusick printf(" %d,", blk + i / dev_bsize); 18021540Smckusick errs++; 18121540Smckusick } 18221540Smckusick } 18321758Smckusick printf("\n"); 18421540Smckusick return (errs); 18516269Smckusick } 18616269Smckusick 18716269Smckusick bwrite(fcp, buf, blk, size) 18816269Smckusick register struct filecntl *fcp; 18916269Smckusick char *buf; 19016269Smckusick daddr_t blk; 19116269Smckusick long size; 19216269Smckusick { 19321758Smckusick int i; 19421758Smckusick char *cp; 19516269Smckusick 19616269Smckusick if (fcp->wfdes < 0) 19721758Smckusick return; 19816269Smckusick if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) 19916269Smckusick rwerr("SEEK", blk); 20016269Smckusick else if (write(fcp->wfdes, buf, (int)size) == size) { 20116269Smckusick fcp->mod = 1; 20221758Smckusick return; 20316269Smckusick } 20416269Smckusick rwerr("WRITE", blk); 20521758Smckusick if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0) 20621758Smckusick rwerr("SEEK", blk); 20721758Smckusick pfatal("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 208*30518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 209*30518Smckusick if (write(fcp->wfdes, cp, dev_bsize) < 0) { 210*30518Smckusick lseek(fcp->rfdes, (long)dbtob(blk) + i + dev_bsize, 0); 211*30518Smckusick printf(" %d,", blk + i / dev_bsize); 21230395Smckusick } 21321758Smckusick printf("\n"); 21421758Smckusick return; 21516269Smckusick } 21616269Smckusick 21717944Smckusick /* 21817944Smckusick * allocate a data block with the specified number of fragments 21917944Smckusick */ 22017944Smckusick allocblk(frags) 22117944Smckusick int frags; 22217944Smckusick { 22317944Smckusick register int i, j, k; 22417944Smckusick 22517944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 22617944Smckusick return (0); 22717944Smckusick for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { 22817944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 22917944Smckusick if (getbmap(i + j)) 23017944Smckusick continue; 23117944Smckusick for (k = 1; k < frags; k++) 23217944Smckusick if (getbmap(i + j + k)) 23317944Smckusick break; 23417944Smckusick if (k < frags) { 23517944Smckusick j += k; 23617944Smckusick continue; 23717944Smckusick } 23817944Smckusick for (k = 0; k < frags; k++) 23917944Smckusick setbmap(i + j + k); 24017944Smckusick n_blks += frags; 24117944Smckusick return (i + j); 24217944Smckusick } 24317944Smckusick } 24417944Smckusick return (0); 24517944Smckusick } 24617944Smckusick 24717944Smckusick /* 24817944Smckusick * Free a previously allocated block 24917944Smckusick */ 25017944Smckusick freeblk(blkno, frags) 25117944Smckusick daddr_t blkno; 25217944Smckusick int frags; 25317944Smckusick { 25417944Smckusick struct inodesc idesc; 25517944Smckusick 25617944Smckusick idesc.id_blkno = blkno; 25717944Smckusick idesc.id_numfrags = frags; 25817944Smckusick pass4check(&idesc); 25917944Smckusick } 26017944Smckusick 26117991Smckusick /* 26217991Smckusick * Find a pathname 26317991Smckusick */ 26417991Smckusick getpathname(namebuf, curdir, ino) 26517991Smckusick char *namebuf; 26617991Smckusick ino_t curdir, ino; 26717991Smckusick { 26817991Smckusick int len; 26917991Smckusick register char *cp; 27017991Smckusick struct inodesc idesc; 27117991Smckusick extern int findname(); 27217991Smckusick 27317991Smckusick if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 27417991Smckusick strcpy(namebuf, "?"); 27517991Smckusick return; 27617991Smckusick } 27717991Smckusick bzero(&idesc, sizeof(struct inodesc)); 27817991Smckusick idesc.id_type = DATA; 27917991Smckusick cp = &namebuf[BUFSIZ - 1]; 28030354Smckusick *cp = '\0'; 28117991Smckusick if (curdir != ino) { 28217991Smckusick idesc.id_parent = curdir; 28317991Smckusick goto namelookup; 28417991Smckusick } 28517991Smckusick while (ino != ROOTINO) { 28617991Smckusick idesc.id_number = ino; 28717991Smckusick idesc.id_func = findino; 28817991Smckusick idesc.id_name = ".."; 28930354Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 29017991Smckusick break; 29117991Smckusick namelookup: 29217991Smckusick idesc.id_number = idesc.id_parent; 29317991Smckusick idesc.id_parent = ino; 29417991Smckusick idesc.id_func = findname; 29517991Smckusick idesc.id_name = namebuf; 29630354Smckusick if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 29717991Smckusick break; 29817991Smckusick len = strlen(namebuf); 29917991Smckusick cp -= len; 30017991Smckusick if (cp < &namebuf[MAXNAMLEN]) 30117991Smckusick break; 30217991Smckusick bcopy(namebuf, cp, len); 30317991Smckusick *--cp = '/'; 30417991Smckusick ino = idesc.id_number; 30517991Smckusick } 30617991Smckusick if (ino != ROOTINO) { 30717991Smckusick strcpy(namebuf, "?"); 30817991Smckusick return; 30917991Smckusick } 31017991Smckusick bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 31117991Smckusick } 31217991Smckusick 31316269Smckusick catch() 31416269Smckusick { 31516269Smckusick 31616269Smckusick ckfini(); 31716269Smckusick exit(12); 31816269Smckusick } 31916269Smckusick 32016269Smckusick /* 32124680Skarels * When preening, allow a single quit to signal 32224680Skarels * a special exit after filesystem checks complete 32324680Skarels * so that reboot sequence may be interrupted. 32424680Skarels */ 32524680Skarels catchquit() 32624680Skarels { 32724680Skarels extern returntosingle; 32824680Skarels 32924680Skarels printf("returning to single-user after filesystem check\n"); 33024680Skarels returntosingle = 1; 33124680Skarels (void)signal(SIGQUIT, SIG_DFL); 33224680Skarels } 33324680Skarels 33424680Skarels /* 33524680Skarels * Ignore a single quit signal; wait and flush just in case. 33624680Skarels * Used by child processes in preen. 33724680Skarels */ 33824680Skarels voidquit() 33924680Skarels { 34024680Skarels 34124680Skarels sleep(1); 34224680Skarels (void)signal(SIGQUIT, SIG_IGN); 34324680Skarels (void)signal(SIGQUIT, SIG_DFL); 34424680Skarels } 34524680Skarels 34624680Skarels /* 34716269Smckusick * determine whether an inode should be fixed. 34816269Smckusick */ 34917931Smckusick dofix(idesc, msg) 35016269Smckusick register struct inodesc *idesc; 35117931Smckusick char *msg; 35216269Smckusick { 35316269Smckusick 35416269Smckusick switch (idesc->id_fix) { 35516269Smckusick 35616269Smckusick case DONTKNOW: 35717931Smckusick if (idesc->id_type == DATA) 35817931Smckusick direrr(idesc->id_number, msg); 35917931Smckusick else 36017931Smckusick pwarn(msg); 36117931Smckusick if (preen) { 36217931Smckusick printf(" (SALVAGED)\n"); 36317931Smckusick idesc->id_fix = FIX; 36417931Smckusick return (ALTERED); 36517931Smckusick } 36616269Smckusick if (reply("SALVAGE") == 0) { 36716269Smckusick idesc->id_fix = NOFIX; 36816269Smckusick return (0); 36916269Smckusick } 37016269Smckusick idesc->id_fix = FIX; 37116269Smckusick return (ALTERED); 37216269Smckusick 37316269Smckusick case FIX: 37416269Smckusick return (ALTERED); 37516269Smckusick 37616269Smckusick case NOFIX: 37716269Smckusick return (0); 37816269Smckusick 37916269Smckusick default: 38016269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 38116269Smckusick } 38216269Smckusick /* NOTREACHED */ 38316269Smckusick } 38416269Smckusick 38516269Smckusick /* VARARGS1 */ 38617931Smckusick errexit(s1, s2, s3, s4) 38716269Smckusick char *s1; 38816269Smckusick { 38916269Smckusick printf(s1, s2, s3, s4); 39016269Smckusick exit(8); 39116269Smckusick } 39216269Smckusick 39316269Smckusick /* 39416269Smckusick * An inconsistency occured which shouldn't during normal operations. 39516269Smckusick * Die if preening, otherwise just printf. 39616269Smckusick */ 39716269Smckusick /* VARARGS1 */ 39816269Smckusick pfatal(s, a1, a2, a3) 39916269Smckusick char *s; 40016269Smckusick { 40116269Smckusick 40216269Smckusick if (preen) { 40316269Smckusick printf("%s: ", devname); 40416269Smckusick printf(s, a1, a2, a3); 40516269Smckusick printf("\n"); 40617931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 40717931Smckusick devname); 40817931Smckusick exit(8); 40916269Smckusick } 41016269Smckusick printf(s, a1, a2, a3); 41116269Smckusick } 41216269Smckusick 41316269Smckusick /* 41416269Smckusick * Pwarn is like printf when not preening, 41516269Smckusick * or a warning (preceded by filename) when preening. 41616269Smckusick */ 41716269Smckusick /* VARARGS1 */ 41816269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 41916269Smckusick char *s; 42016269Smckusick { 42116269Smckusick 42216269Smckusick if (preen) 42316269Smckusick printf("%s: ", devname); 42416269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 42516269Smckusick } 42616269Smckusick 42716269Smckusick #ifndef lint 42816269Smckusick /* 42916269Smckusick * Stub for routines from kernel. 43016269Smckusick */ 43116269Smckusick panic(s) 43216269Smckusick char *s; 43316269Smckusick { 43416269Smckusick 43517931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 43617931Smckusick errexit(s); 43716269Smckusick } 43816269Smckusick #endif 439