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*30859Skarels static char sccsid[] = "@(#)utilities.c 5.10 (Berkeley) 04/07/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]; 4530609Skarels int cont = (strcmp(s, "CONTINUE") == 0); 4616269Smckusick 4716269Smckusick if (preen) 4816269Smckusick pfatal("INTERNAL ERROR: GOT TO reply()"); 4916269Smckusick printf("\n%s? ", s); 5030609Skarels if (!cont && (nflag || dfile.wfdes < 0)) { 5116269Smckusick printf(" no\n\n"); 5216269Smckusick return (0); 5316269Smckusick } 5430609Skarels if (yflag || (cont && nflag)) { 5516269Smckusick printf(" yes\n\n"); 5616269Smckusick return (1); 5716269Smckusick } 5816269Smckusick if (getline(stdin, line, sizeof(line)) == EOF) 5916269Smckusick errexit("\n"); 6016269Smckusick printf("\n"); 6116269Smckusick if (line[0] == 'y' || line[0] == 'Y') 6216269Smckusick return (1); 6316269Smckusick else 6416269Smckusick return (0); 6516269Smckusick } 6616269Smckusick 6716269Smckusick getline(fp, loc, maxlen) 6816269Smckusick FILE *fp; 6916269Smckusick char *loc; 7016269Smckusick { 7116269Smckusick register n; 7216269Smckusick register char *p, *lastloc; 7316269Smckusick 7416269Smckusick p = loc; 7516269Smckusick lastloc = &p[maxlen-1]; 7616269Smckusick while ((n = getc(fp)) != '\n') { 7716269Smckusick if (n == EOF) 7816269Smckusick return (EOF); 7916269Smckusick if (!isspace(n) && p < lastloc) 8016269Smckusick *p++ = n; 8116269Smckusick } 8216269Smckusick *p = 0; 8316269Smckusick return (p - loc); 8416269Smckusick } 8516269Smckusick 8616269Smckusick BUFAREA * 8716269Smckusick getblk(bp, blk, size) 8816269Smckusick register BUFAREA *bp; 8916269Smckusick daddr_t blk; 9016269Smckusick long size; 9116269Smckusick { 9216269Smckusick register struct filecntl *fcp; 9316269Smckusick daddr_t dblk; 9416269Smckusick 9516269Smckusick fcp = &dfile; 9616269Smckusick dblk = fsbtodb(&sblock, blk); 9716269Smckusick if (bp->b_bno == dblk) 9816269Smckusick return (bp); 9916269Smckusick flush(fcp, bp); 10021540Smckusick bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size); 10121540Smckusick bp->b_bno = dblk; 10221540Smckusick bp->b_size = size; 10321540Smckusick return (bp); 10416269Smckusick } 10516269Smckusick 10616269Smckusick flush(fcp, bp) 10716269Smckusick struct filecntl *fcp; 10816269Smckusick register BUFAREA *bp; 10916269Smckusick { 11017931Smckusick register int i, j; 11116269Smckusick 11217931Smckusick if (!bp->b_dirty) 11317931Smckusick return; 11421540Smckusick if (bp->b_errs != 0) 11530609Skarels pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 11630609Skarels (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 11730609Skarels bp->b_bno); 11816269Smckusick bp->b_dirty = 0; 11921540Smckusick bp->b_errs = 0; 12021758Smckusick bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 12117931Smckusick if (bp != &sblk) 12217931Smckusick return; 12317931Smckusick for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 12421758Smckusick bwrite(&dfile, (char *)sblock.fs_csp[j], 12517931Smckusick fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 12617931Smckusick sblock.fs_cssize - i < sblock.fs_bsize ? 12717931Smckusick sblock.fs_cssize - i : sblock.fs_bsize); 12817931Smckusick } 12916269Smckusick } 13016269Smckusick 13116269Smckusick rwerr(s, blk) 13216269Smckusick char *s; 13316269Smckusick daddr_t blk; 13416269Smckusick { 13516269Smckusick 13616269Smckusick if (preen == 0) 13716269Smckusick printf("\n"); 13816269Smckusick pfatal("CANNOT %s: BLK %ld", s, blk); 13916269Smckusick if (reply("CONTINUE") == 0) 14016269Smckusick errexit("Program terminated\n"); 14116269Smckusick } 14216269Smckusick 14316269Smckusick ckfini() 14416269Smckusick { 14516269Smckusick 14616269Smckusick flush(&dfile, &fileblk); 14716269Smckusick flush(&dfile, &sblk); 148*30859Skarels if (havesb && sblk.b_bno != SBOFF / dev_bsize && 14930518Smckusick !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 15030556Smckusick sblk.b_bno = SBOFF / dev_bsize; 15116269Smckusick sbdirty(); 15216269Smckusick flush(&dfile, &sblk); 15316269Smckusick } 15416269Smckusick flush(&dfile, &inoblk); 15518002Smckusick flush(&dfile, &cgblk); 15616269Smckusick (void)close(dfile.rfdes); 15716269Smckusick (void)close(dfile.wfdes); 15816269Smckusick } 15916269Smckusick 16016269Smckusick bread(fcp, buf, blk, size) 16116269Smckusick register struct filecntl *fcp; 16216269Smckusick char *buf; 16316269Smckusick daddr_t blk; 16416269Smckusick long size; 16516269Smckusick { 16621540Smckusick char *cp; 16721540Smckusick int i, errs; 16821540Smckusick 16930557Smckusick if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) 17016269Smckusick rwerr("SEEK", blk); 17116269Smckusick else if (read(fcp->rfdes, buf, (int)size) == size) 17221540Smckusick return (0); 17316269Smckusick rwerr("READ", blk); 17430557Smckusick if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0) 17521540Smckusick rwerr("SEEK", blk); 17621540Smckusick errs = 0; 17730463Smckusick bzero(buf, size); 17830609Skarels printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 17930609Skarels for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 18030609Skarels if (read(fcp->rfdes, cp, secsize) < 0) { 18130609Skarels lseek(fcp->rfdes, blk * dev_bsize + i + secsize, 0); 182*30859Skarels if (secsize != dev_bsize && dev_bsize != 1) 18330609Skarels printf(" %d (%d),", 18430609Skarels (blk * dev_bsize + i) / secsize, 18530609Skarels blk + i / dev_bsize); 18630609Skarels else 18730609Skarels printf(" %d,", blk + i / dev_bsize); 18821540Smckusick errs++; 18921540Smckusick } 19021540Smckusick } 19121758Smckusick printf("\n"); 19221540Smckusick return (errs); 19316269Smckusick } 19416269Smckusick 19516269Smckusick bwrite(fcp, buf, blk, size) 19616269Smckusick register struct filecntl *fcp; 19716269Smckusick char *buf; 19816269Smckusick daddr_t blk; 19916269Smckusick long size; 20016269Smckusick { 20121758Smckusick int i; 20221758Smckusick char *cp; 20316269Smckusick 20416269Smckusick if (fcp->wfdes < 0) 20521758Smckusick return; 20630557Smckusick if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) 20716269Smckusick rwerr("SEEK", blk); 20816269Smckusick else if (write(fcp->wfdes, buf, (int)size) == size) { 20916269Smckusick fcp->mod = 1; 21021758Smckusick return; 21116269Smckusick } 21216269Smckusick rwerr("WRITE", blk); 21330557Smckusick if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0) 21421758Smckusick rwerr("SEEK", blk); 21530609Skarels printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 21630518Smckusick for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 21730518Smckusick if (write(fcp->wfdes, cp, dev_bsize) < 0) { 21830557Smckusick lseek(fcp->rfdes, blk * dev_bsize + i + dev_bsize, 0); 21930518Smckusick printf(" %d,", blk + i / dev_bsize); 22030395Smckusick } 22121758Smckusick printf("\n"); 22221758Smckusick return; 22316269Smckusick } 22416269Smckusick 22517944Smckusick /* 22617944Smckusick * allocate a data block with the specified number of fragments 22717944Smckusick */ 22817944Smckusick allocblk(frags) 22917944Smckusick int frags; 23017944Smckusick { 23117944Smckusick register int i, j, k; 23217944Smckusick 23317944Smckusick if (frags <= 0 || frags > sblock.fs_frag) 23417944Smckusick return (0); 23517944Smckusick for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) { 23617944Smckusick for (j = 0; j <= sblock.fs_frag - frags; j++) { 23717944Smckusick if (getbmap(i + j)) 23817944Smckusick continue; 23917944Smckusick for (k = 1; k < frags; k++) 24017944Smckusick if (getbmap(i + j + k)) 24117944Smckusick break; 24217944Smckusick if (k < frags) { 24317944Smckusick j += k; 24417944Smckusick continue; 24517944Smckusick } 24617944Smckusick for (k = 0; k < frags; k++) 24717944Smckusick setbmap(i + j + k); 24817944Smckusick n_blks += frags; 24917944Smckusick return (i + j); 25017944Smckusick } 25117944Smckusick } 25217944Smckusick return (0); 25317944Smckusick } 25417944Smckusick 25517944Smckusick /* 25617944Smckusick * Free a previously allocated block 25717944Smckusick */ 25817944Smckusick freeblk(blkno, frags) 25917944Smckusick daddr_t blkno; 26017944Smckusick int frags; 26117944Smckusick { 26217944Smckusick struct inodesc idesc; 26317944Smckusick 26417944Smckusick idesc.id_blkno = blkno; 26517944Smckusick idesc.id_numfrags = frags; 26617944Smckusick pass4check(&idesc); 26717944Smckusick } 26817944Smckusick 26917991Smckusick /* 27017991Smckusick * Find a pathname 27117991Smckusick */ 27217991Smckusick getpathname(namebuf, curdir, ino) 27317991Smckusick char *namebuf; 27417991Smckusick ino_t curdir, ino; 27517991Smckusick { 27617991Smckusick int len; 27717991Smckusick register char *cp; 27817991Smckusick struct inodesc idesc; 27917991Smckusick extern int findname(); 28017991Smckusick 28117991Smckusick if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) { 28217991Smckusick strcpy(namebuf, "?"); 28317991Smckusick return; 28417991Smckusick } 28517991Smckusick bzero(&idesc, sizeof(struct inodesc)); 28617991Smckusick idesc.id_type = DATA; 28717991Smckusick cp = &namebuf[BUFSIZ - 1]; 28830354Smckusick *cp = '\0'; 28917991Smckusick if (curdir != ino) { 29017991Smckusick idesc.id_parent = curdir; 29117991Smckusick goto namelookup; 29217991Smckusick } 29317991Smckusick while (ino != ROOTINO) { 29417991Smckusick idesc.id_number = ino; 29517991Smckusick idesc.id_func = findino; 29617991Smckusick idesc.id_name = ".."; 29730354Smckusick if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 29817991Smckusick break; 29917991Smckusick namelookup: 30017991Smckusick idesc.id_number = idesc.id_parent; 30117991Smckusick idesc.id_parent = ino; 30217991Smckusick idesc.id_func = findname; 30317991Smckusick idesc.id_name = namebuf; 30430354Smckusick if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0) 30517991Smckusick break; 30617991Smckusick len = strlen(namebuf); 30717991Smckusick cp -= len; 30817991Smckusick if (cp < &namebuf[MAXNAMLEN]) 30917991Smckusick break; 31017991Smckusick bcopy(namebuf, cp, len); 31117991Smckusick *--cp = '/'; 31217991Smckusick ino = idesc.id_number; 31317991Smckusick } 31417991Smckusick if (ino != ROOTINO) { 31517991Smckusick strcpy(namebuf, "?"); 31617991Smckusick return; 31717991Smckusick } 31817991Smckusick bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp); 31917991Smckusick } 32017991Smckusick 32116269Smckusick catch() 32216269Smckusick { 32316269Smckusick 32416269Smckusick ckfini(); 32516269Smckusick exit(12); 32616269Smckusick } 32716269Smckusick 32816269Smckusick /* 32924680Skarels * When preening, allow a single quit to signal 33024680Skarels * a special exit after filesystem checks complete 33124680Skarels * so that reboot sequence may be interrupted. 33224680Skarels */ 33324680Skarels catchquit() 33424680Skarels { 33524680Skarels extern returntosingle; 33624680Skarels 33724680Skarels printf("returning to single-user after filesystem check\n"); 33824680Skarels returntosingle = 1; 33924680Skarels (void)signal(SIGQUIT, SIG_DFL); 34024680Skarels } 34124680Skarels 34224680Skarels /* 34324680Skarels * Ignore a single quit signal; wait and flush just in case. 34424680Skarels * Used by child processes in preen. 34524680Skarels */ 34624680Skarels voidquit() 34724680Skarels { 34824680Skarels 34924680Skarels sleep(1); 35024680Skarels (void)signal(SIGQUIT, SIG_IGN); 35124680Skarels (void)signal(SIGQUIT, SIG_DFL); 35224680Skarels } 35324680Skarels 35424680Skarels /* 35516269Smckusick * determine whether an inode should be fixed. 35616269Smckusick */ 35717931Smckusick dofix(idesc, msg) 35816269Smckusick register struct inodesc *idesc; 35917931Smckusick char *msg; 36016269Smckusick { 36116269Smckusick 36216269Smckusick switch (idesc->id_fix) { 36316269Smckusick 36416269Smckusick case DONTKNOW: 36517931Smckusick if (idesc->id_type == DATA) 36617931Smckusick direrr(idesc->id_number, msg); 36717931Smckusick else 36817931Smckusick pwarn(msg); 36917931Smckusick if (preen) { 37017931Smckusick printf(" (SALVAGED)\n"); 37117931Smckusick idesc->id_fix = FIX; 37217931Smckusick return (ALTERED); 37317931Smckusick } 37416269Smckusick if (reply("SALVAGE") == 0) { 37516269Smckusick idesc->id_fix = NOFIX; 37616269Smckusick return (0); 37716269Smckusick } 37816269Smckusick idesc->id_fix = FIX; 37916269Smckusick return (ALTERED); 38016269Smckusick 38116269Smckusick case FIX: 38216269Smckusick return (ALTERED); 38316269Smckusick 38416269Smckusick case NOFIX: 38516269Smckusick return (0); 38616269Smckusick 38716269Smckusick default: 38816269Smckusick errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix); 38916269Smckusick } 39016269Smckusick /* NOTREACHED */ 39116269Smckusick } 39216269Smckusick 39316269Smckusick /* VARARGS1 */ 39417931Smckusick errexit(s1, s2, s3, s4) 39516269Smckusick char *s1; 39616269Smckusick { 39716269Smckusick printf(s1, s2, s3, s4); 39816269Smckusick exit(8); 39916269Smckusick } 40016269Smckusick 40116269Smckusick /* 40216269Smckusick * An inconsistency occured which shouldn't during normal operations. 40316269Smckusick * Die if preening, otherwise just printf. 40416269Smckusick */ 40516269Smckusick /* VARARGS1 */ 40616269Smckusick pfatal(s, a1, a2, a3) 40716269Smckusick char *s; 40816269Smckusick { 40916269Smckusick 41016269Smckusick if (preen) { 41116269Smckusick printf("%s: ", devname); 41216269Smckusick printf(s, a1, a2, a3); 41316269Smckusick printf("\n"); 41417931Smckusick printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", 41517931Smckusick devname); 41617931Smckusick exit(8); 41716269Smckusick } 41816269Smckusick printf(s, a1, a2, a3); 41916269Smckusick } 42016269Smckusick 42116269Smckusick /* 42216269Smckusick * Pwarn is like printf when not preening, 42316269Smckusick * or a warning (preceded by filename) when preening. 42416269Smckusick */ 42516269Smckusick /* VARARGS1 */ 42616269Smckusick pwarn(s, a1, a2, a3, a4, a5, a6) 42716269Smckusick char *s; 42816269Smckusick { 42916269Smckusick 43016269Smckusick if (preen) 43116269Smckusick printf("%s: ", devname); 43216269Smckusick printf(s, a1, a2, a3, a4, a5, a6); 43316269Smckusick } 43416269Smckusick 43516269Smckusick #ifndef lint 43616269Smckusick /* 43716269Smckusick * Stub for routines from kernel. 43816269Smckusick */ 43916269Smckusick panic(s) 44016269Smckusick char *s; 44116269Smckusick { 44216269Smckusick 44317931Smckusick pfatal("INTERNAL INCONSISTENCY:"); 44417931Smckusick errexit(s); 44516269Smckusick } 44616269Smckusick #endif 447