utilities.c revision 66861
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1980, 1986, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3541477Sjulian#if 0 3623675Speterstatic const char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; 3741477Sjulian#endif 3841477Sjulianstatic const char rcsid[] = 3950476Speter "$FreeBSD: head/sbin/fsck_ffs/utilities.c 66861 2000-10-09 08:26:35Z adrian $"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 4366861Sadrian#include <sys/types.h> 4466861Sadrian#include <sys/stat.h> 4523675Speter 461558Srgrimes#include <ufs/ufs/dinode.h> 471558Srgrimes#include <ufs/ufs/dir.h> 481558Srgrimes#include <ufs/ffs/fs.h> 4923799Sbde 5023675Speter#include <err.h> 5166861Sadrian#include <errno.h> 5223799Sbde#include <string.h> 5366861Sadrian#include <ctype.h> 5466861Sadrian#include <fstab.h> 5566861Sadrian#include <stdio.h> 5666861Sadrian#include <stdlib.h> 5766861Sadrian#include <unistd.h> 5823675Speter 591558Srgrimes#include "fsck.h" 601558Srgrimes 611558Srgrimeslong diskreads, totalreads; /* Disk cache statistics */ 621558Srgrimes 6323675Speterstatic void rwerror __P((char *mesg, ufs_daddr_t blk)); 647585Sbde 657585Sbdeint 661558Srgrimesftypeok(dp) 671558Srgrimes struct dinode *dp; 681558Srgrimes{ 691558Srgrimes switch (dp->di_mode & IFMT) { 701558Srgrimes 711558Srgrimes case IFDIR: 721558Srgrimes case IFREG: 731558Srgrimes case IFBLK: 741558Srgrimes case IFCHR: 751558Srgrimes case IFLNK: 761558Srgrimes case IFSOCK: 771558Srgrimes case IFIFO: 781558Srgrimes return (1); 791558Srgrimes 801558Srgrimes default: 811558Srgrimes if (debug) 821558Srgrimes printf("bad file type 0%o\n", dp->di_mode); 831558Srgrimes return (0); 841558Srgrimes } 851558Srgrimes} 861558Srgrimes 877585Sbdeint 881558Srgrimesreply(question) 891558Srgrimes char *question; 901558Srgrimes{ 911558Srgrimes int persevere; 921558Srgrimes char c; 931558Srgrimes 941558Srgrimes if (preen) 951558Srgrimes pfatal("INTERNAL ERROR: GOT TO reply()"); 961558Srgrimes persevere = !strcmp(question, "CONTINUE"); 971558Srgrimes printf("\n"); 981558Srgrimes if (!persevere && (nflag || fswritefd < 0)) { 991558Srgrimes printf("%s? no\n\n", question); 10034266Sjulian resolved = 0; 1011558Srgrimes return (0); 1021558Srgrimes } 1031558Srgrimes if (yflag || (persevere && nflag)) { 1041558Srgrimes printf("%s? yes\n\n", question); 1051558Srgrimes return (1); 1061558Srgrimes } 1071558Srgrimes do { 1081558Srgrimes printf("%s? [yn] ", question); 1091558Srgrimes (void) fflush(stdout); 1101558Srgrimes c = getc(stdin); 11134266Sjulian while (c != '\n' && getc(stdin) != '\n') { 11234266Sjulian if (feof(stdin)) { 11334266Sjulian resolved = 0; 1141558Srgrimes return (0); 11534266Sjulian } 11634266Sjulian } 1171558Srgrimes } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); 1181558Srgrimes printf("\n"); 1191558Srgrimes if (c == 'y' || c == 'Y') 1201558Srgrimes return (1); 12134266Sjulian resolved = 0; 1221558Srgrimes return (0); 1231558Srgrimes} 1241558Srgrimes 1251558Srgrimes/* 12641474Sjulian * Look up state information for an inode. 12741474Sjulian */ 12841474Sjulianstruct inostat * 12941474Sjulianinoinfo(inum) 13041474Sjulian ino_t inum; 13141474Sjulian{ 13241474Sjulian static struct inostat unallocated = { USTATE, 0, 0 }; 13341474Sjulian struct inostatlist *ilp; 13441474Sjulian int iloff; 13541474Sjulian 13641474Sjulian if (inum > maxino) 13741474Sjulian errx(EEXIT, "inoinfo: inumber %d out of range", inum); 13841474Sjulian ilp = &inostathead[inum / sblock.fs_ipg]; 13941474Sjulian iloff = inum % sblock.fs_ipg; 14041474Sjulian if (iloff >= ilp->il_numalloced) 14141474Sjulian return (&unallocated); 14241474Sjulian return (&ilp->il_stat[iloff]); 14341474Sjulian} 14441474Sjulian 14541474Sjulian/* 1461558Srgrimes * Malloc buffers and set up cache. 1471558Srgrimes */ 1487585Sbdevoid 1491558Srgrimesbufinit() 1501558Srgrimes{ 1511558Srgrimes register struct bufarea *bp; 1521558Srgrimes long bufcnt, i; 1531558Srgrimes char *bufp; 1541558Srgrimes 1551558Srgrimes pbp = pdirbp = (struct bufarea *)0; 1561558Srgrimes bufp = malloc((unsigned int)sblock.fs_bsize); 1571558Srgrimes if (bufp == 0) 15823675Speter errx(EEXIT, "cannot allocate buffer pool"); 1591558Srgrimes cgblk.b_un.b_buf = bufp; 1601558Srgrimes initbarea(&cgblk); 1611558Srgrimes bufhead.b_next = bufhead.b_prev = &bufhead; 1621558Srgrimes bufcnt = MAXBUFSPACE / sblock.fs_bsize; 1631558Srgrimes if (bufcnt < MINBUFS) 1641558Srgrimes bufcnt = MINBUFS; 1651558Srgrimes for (i = 0; i < bufcnt; i++) { 1661558Srgrimes bp = (struct bufarea *)malloc(sizeof(struct bufarea)); 1671558Srgrimes bufp = malloc((unsigned int)sblock.fs_bsize); 1681558Srgrimes if (bp == NULL || bufp == NULL) { 1691558Srgrimes if (i >= MINBUFS) 1701558Srgrimes break; 17123675Speter errx(EEXIT, "cannot allocate buffer pool"); 1721558Srgrimes } 1731558Srgrimes bp->b_un.b_buf = bufp; 1741558Srgrimes bp->b_prev = &bufhead; 1751558Srgrimes bp->b_next = bufhead.b_next; 1761558Srgrimes bufhead.b_next->b_prev = bp; 1771558Srgrimes bufhead.b_next = bp; 1781558Srgrimes initbarea(bp); 1791558Srgrimes } 1801558Srgrimes bufhead.b_size = i; /* save number of buffers */ 1811558Srgrimes} 1821558Srgrimes 1831558Srgrimes/* 1841558Srgrimes * Manage a cache of directory blocks. 1851558Srgrimes */ 1861558Srgrimesstruct bufarea * 1871558Srgrimesgetdatablk(blkno, size) 18823675Speter ufs_daddr_t blkno; 1891558Srgrimes long size; 1901558Srgrimes{ 1911558Srgrimes register struct bufarea *bp; 1921558Srgrimes 1931558Srgrimes for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) 1941558Srgrimes if (bp->b_bno == fsbtodb(&sblock, blkno)) 1951558Srgrimes goto foundit; 1961558Srgrimes for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) 1971558Srgrimes if ((bp->b_flags & B_INUSE) == 0) 1981558Srgrimes break; 1991558Srgrimes if (bp == &bufhead) 20023675Speter errx(EEXIT, "deadlocked buffer pool"); 2011558Srgrimes getblk(bp, blkno, size); 2021558Srgrimes /* fall through */ 2031558Srgrimesfoundit: 2041558Srgrimes totalreads++; 2051558Srgrimes bp->b_prev->b_next = bp->b_next; 2061558Srgrimes bp->b_next->b_prev = bp->b_prev; 2071558Srgrimes bp->b_prev = &bufhead; 2081558Srgrimes bp->b_next = bufhead.b_next; 2091558Srgrimes bufhead.b_next->b_prev = bp; 2101558Srgrimes bufhead.b_next = bp; 2111558Srgrimes bp->b_flags |= B_INUSE; 2121558Srgrimes return (bp); 2131558Srgrimes} 2141558Srgrimes 2151558Srgrimesvoid 2161558Srgrimesgetblk(bp, blk, size) 2171558Srgrimes register struct bufarea *bp; 21823675Speter ufs_daddr_t blk; 2191558Srgrimes long size; 2201558Srgrimes{ 22123675Speter ufs_daddr_t dblk; 2221558Srgrimes 2231558Srgrimes dblk = fsbtodb(&sblock, blk); 2241558Srgrimes if (bp->b_bno != dblk) { 2251558Srgrimes flush(fswritefd, bp); 2261558Srgrimes diskreads++; 2271558Srgrimes bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); 2281558Srgrimes bp->b_bno = dblk; 2291558Srgrimes bp->b_size = size; 2301558Srgrimes } 2311558Srgrimes} 2321558Srgrimes 2337585Sbdevoid 2341558Srgrimesflush(fd, bp) 2351558Srgrimes int fd; 2361558Srgrimes register struct bufarea *bp; 2371558Srgrimes{ 2381558Srgrimes register int i, j; 2391558Srgrimes 2401558Srgrimes if (!bp->b_dirty) 2411558Srgrimes return; 2421558Srgrimes if (bp->b_errs != 0) 2431558Srgrimes pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n", 2441558Srgrimes (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", 2451558Srgrimes bp->b_bno); 2461558Srgrimes bp->b_dirty = 0; 2471558Srgrimes bp->b_errs = 0; 2481558Srgrimes bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); 2491558Srgrimes if (bp != &sblk) 2501558Srgrimes return; 2511558Srgrimes for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { 2521558Srgrimes bwrite(fswritefd, (char *)sblock.fs_csp[j], 2531558Srgrimes fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), 2541558Srgrimes sblock.fs_cssize - i < sblock.fs_bsize ? 2551558Srgrimes sblock.fs_cssize - i : sblock.fs_bsize); 2561558Srgrimes } 2571558Srgrimes} 2581558Srgrimes 25923675Speterstatic void 2601558Srgrimesrwerror(mesg, blk) 2611558Srgrimes char *mesg; 26223675Speter ufs_daddr_t blk; 2631558Srgrimes{ 2641558Srgrimes 2651558Srgrimes if (preen == 0) 2661558Srgrimes printf("\n"); 2671558Srgrimes pfatal("CANNOT %s: BLK %ld", mesg, blk); 2681558Srgrimes if (reply("CONTINUE") == 0) 26923675Speter exit(EEXIT); 2701558Srgrimes} 2711558Srgrimes 2727585Sbdevoid 27323675Speterckfini(markclean) 27423675Speter int markclean; 2751558Srgrimes{ 2761558Srgrimes register struct bufarea *bp, *nbp; 27723675Speter int ofsmodified, cnt = 0; 2781558Srgrimes 2791558Srgrimes if (fswritefd < 0) { 2801558Srgrimes (void)close(fsreadfd); 2811558Srgrimes return; 2821558Srgrimes } 2831558Srgrimes flush(fswritefd, &sblk); 2841558Srgrimes if (havesb && sblk.b_bno != SBOFF / dev_bsize && 2851558Srgrimes !preen && reply("UPDATE STANDARD SUPERBLOCK")) { 2861558Srgrimes sblk.b_bno = SBOFF / dev_bsize; 2871558Srgrimes sbdirty(); 2881558Srgrimes flush(fswritefd, &sblk); 2891558Srgrimes } 2901558Srgrimes flush(fswritefd, &cgblk); 2911558Srgrimes free(cgblk.b_un.b_buf); 2921558Srgrimes for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { 2931558Srgrimes cnt++; 2941558Srgrimes flush(fswritefd, bp); 2951558Srgrimes nbp = bp->b_prev; 2961558Srgrimes free(bp->b_un.b_buf); 2971558Srgrimes free((char *)bp); 2981558Srgrimes } 2991558Srgrimes if (bufhead.b_size != cnt) 30041477Sjulian errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt); 3011558Srgrimes pbp = pdirbp = (struct bufarea *)0; 30241474Sjulian if (sblock.fs_clean != markclean) { 30341474Sjulian sblock.fs_clean = markclean; 30423675Speter sbdirty(); 30523675Speter ofsmodified = fsmodified; 30623675Speter flush(fswritefd, &sblk); 30723675Speter fsmodified = ofsmodified; 30841474Sjulian if (!preen) { 30941474Sjulian printf("\n***** FILE SYSTEM MARKED %s *****\n", 31041474Sjulian markclean ? "CLEAN" : "DIRTY"); 31141474Sjulian if (!markclean) 31241474Sjulian rerun = 1; 31341474Sjulian } 31441474Sjulian } else if (!preen && !markclean) { 31541474Sjulian printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); 31641474Sjulian rerun = 1; 31723675Speter } 3181558Srgrimes if (debug) 3191558Srgrimes printf("cache missed %ld of %ld (%d%%)\n", diskreads, 3201558Srgrimes totalreads, (int)(diskreads * 100 / totalreads)); 3211558Srgrimes (void)close(fsreadfd); 3221558Srgrimes (void)close(fswritefd); 3231558Srgrimes} 3241558Srgrimes 3257585Sbdeint 3261558Srgrimesbread(fd, buf, blk, size) 3271558Srgrimes int fd; 3281558Srgrimes char *buf; 32923675Speter ufs_daddr_t blk; 3301558Srgrimes long size; 3311558Srgrimes{ 3321558Srgrimes char *cp; 3331558Srgrimes int i, errs; 3341558Srgrimes off_t offset; 3351558Srgrimes 3361558Srgrimes offset = blk; 3371558Srgrimes offset *= dev_bsize; 3381558Srgrimes if (lseek(fd, offset, 0) < 0) 3391558Srgrimes rwerror("SEEK", blk); 3401558Srgrimes else if (read(fd, buf, (int)size) == size) 3411558Srgrimes return (0); 3421558Srgrimes rwerror("READ", blk); 3431558Srgrimes if (lseek(fd, offset, 0) < 0) 3441558Srgrimes rwerror("SEEK", blk); 3451558Srgrimes errs = 0; 34623675Speter memset(buf, 0, (size_t)size); 3471558Srgrimes printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); 3481558Srgrimes for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { 3491558Srgrimes if (read(fd, cp, (int)secsize) != secsize) { 3501558Srgrimes (void)lseek(fd, offset + i + secsize, 0); 3511558Srgrimes if (secsize != dev_bsize && dev_bsize != 1) 3521558Srgrimes printf(" %ld (%ld),", 3531558Srgrimes (blk * dev_bsize + i) / secsize, 3541558Srgrimes blk + i / dev_bsize); 3551558Srgrimes else 3561558Srgrimes printf(" %ld,", blk + i / dev_bsize); 3571558Srgrimes errs++; 3581558Srgrimes } 3591558Srgrimes } 3601558Srgrimes printf("\n"); 36141474Sjulian if (errs) 36241474Sjulian resolved = 0; 3631558Srgrimes return (errs); 3641558Srgrimes} 3651558Srgrimes 3667585Sbdevoid 3671558Srgrimesbwrite(fd, buf, blk, size) 3681558Srgrimes int fd; 3691558Srgrimes char *buf; 37023675Speter ufs_daddr_t blk; 3711558Srgrimes long size; 3721558Srgrimes{ 3731558Srgrimes int i; 3741558Srgrimes char *cp; 3751558Srgrimes off_t offset; 3761558Srgrimes 3771558Srgrimes if (fd < 0) 3781558Srgrimes return; 3791558Srgrimes offset = blk; 3801558Srgrimes offset *= dev_bsize; 3811558Srgrimes if (lseek(fd, offset, 0) < 0) 3821558Srgrimes rwerror("SEEK", blk); 3831558Srgrimes else if (write(fd, buf, (int)size) == size) { 3841558Srgrimes fsmodified = 1; 3851558Srgrimes return; 3861558Srgrimes } 38741474Sjulian resolved = 0; 3881558Srgrimes rwerror("WRITE", blk); 3891558Srgrimes if (lseek(fd, offset, 0) < 0) 3901558Srgrimes rwerror("SEEK", blk); 3911558Srgrimes printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); 3921558Srgrimes for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) 3931558Srgrimes if (write(fd, cp, (int)dev_bsize) != dev_bsize) { 3941558Srgrimes (void)lseek(fd, offset + i + dev_bsize, 0); 3951558Srgrimes printf(" %ld,", blk + i / dev_bsize); 3961558Srgrimes } 3971558Srgrimes printf("\n"); 3981558Srgrimes return; 3991558Srgrimes} 4001558Srgrimes 4011558Srgrimes/* 4021558Srgrimes * allocate a data block with the specified number of fragments 4031558Srgrimes */ 40423675Speterufs_daddr_t 4051558Srgrimesallocblk(frags) 4061558Srgrimes long frags; 4071558Srgrimes{ 40834266Sjulian int i, j, k, cg, baseblk; 40934266Sjulian struct cg *cgp = &cgrp; 4101558Srgrimes 4111558Srgrimes if (frags <= 0 || frags > sblock.fs_frag) 4121558Srgrimes return (0); 4131558Srgrimes for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) { 4141558Srgrimes for (j = 0; j <= sblock.fs_frag - frags; j++) { 4151558Srgrimes if (testbmap(i + j)) 4161558Srgrimes continue; 4171558Srgrimes for (k = 1; k < frags; k++) 4181558Srgrimes if (testbmap(i + j + k)) 4191558Srgrimes break; 4201558Srgrimes if (k < frags) { 4211558Srgrimes j += k; 4221558Srgrimes continue; 4231558Srgrimes } 42434266Sjulian cg = dtog(&sblock, i + j); 42534266Sjulian getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 42634266Sjulian if (!cg_chkmagic(cgp)) 42734266Sjulian pfatal("CG %d: BAD MAGIC NUMBER\n", cg); 42834266Sjulian baseblk = dtogd(&sblock, i + j); 42934266Sjulian for (k = 0; k < frags; k++) { 4301558Srgrimes setbmap(i + j + k); 43134266Sjulian clrbit(cg_blksfree(cgp), baseblk + k); 43234266Sjulian } 4331558Srgrimes n_blks += frags; 43434266Sjulian if (frags == sblock.fs_frag) 43534266Sjulian cgp->cg_cs.cs_nbfree--; 43634266Sjulian else 43734266Sjulian cgp->cg_cs.cs_nffree -= frags; 43834266Sjulian cgdirty(); 4391558Srgrimes return (i + j); 4401558Srgrimes } 4411558Srgrimes } 4421558Srgrimes return (0); 4431558Srgrimes} 4441558Srgrimes 4451558Srgrimes/* 4461558Srgrimes * Free a previously allocated block 4471558Srgrimes */ 4487585Sbdevoid 4491558Srgrimesfreeblk(blkno, frags) 45023675Speter ufs_daddr_t blkno; 4511558Srgrimes long frags; 4521558Srgrimes{ 4531558Srgrimes struct inodesc idesc; 4541558Srgrimes 4551558Srgrimes idesc.id_blkno = blkno; 4561558Srgrimes idesc.id_numfrags = frags; 4571558Srgrimes (void)pass4check(&idesc); 4581558Srgrimes} 4591558Srgrimes 4601558Srgrimes/* 4611558Srgrimes * Find a pathname 4621558Srgrimes */ 4637585Sbdevoid 4641558Srgrimesgetpathname(namebuf, curdir, ino) 4651558Srgrimes char *namebuf; 4661558Srgrimes ino_t curdir, ino; 4671558Srgrimes{ 4681558Srgrimes int len; 4691558Srgrimes register char *cp; 4701558Srgrimes struct inodesc idesc; 4711558Srgrimes static int busy = 0; 4721558Srgrimes 4731558Srgrimes if (curdir == ino && ino == ROOTINO) { 4741558Srgrimes (void)strcpy(namebuf, "/"); 4751558Srgrimes return; 4761558Srgrimes } 4771558Srgrimes if (busy || 47841474Sjulian (inoinfo(curdir)->ino_state != DSTATE && 47941474Sjulian inoinfo(curdir)->ino_state != DFOUND)) { 4801558Srgrimes (void)strcpy(namebuf, "?"); 4811558Srgrimes return; 4821558Srgrimes } 4831558Srgrimes busy = 1; 48423675Speter memset(&idesc, 0, sizeof(struct inodesc)); 4851558Srgrimes idesc.id_type = DATA; 4861558Srgrimes idesc.id_fix = IGNORE; 4871558Srgrimes cp = &namebuf[MAXPATHLEN - 1]; 4881558Srgrimes *cp = '\0'; 4891558Srgrimes if (curdir != ino) { 4901558Srgrimes idesc.id_parent = curdir; 4911558Srgrimes goto namelookup; 4921558Srgrimes } 4931558Srgrimes while (ino != ROOTINO) { 4941558Srgrimes idesc.id_number = ino; 4951558Srgrimes idesc.id_func = findino; 4961558Srgrimes idesc.id_name = ".."; 4971558Srgrimes if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) 4981558Srgrimes break; 4991558Srgrimes namelookup: 5001558Srgrimes idesc.id_number = idesc.id_parent; 5011558Srgrimes idesc.id_parent = ino; 5021558Srgrimes idesc.id_func = findname; 5031558Srgrimes idesc.id_name = namebuf; 5041558Srgrimes if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) 5051558Srgrimes break; 5061558Srgrimes len = strlen(namebuf); 5071558Srgrimes cp -= len; 50823675Speter memmove(cp, namebuf, (size_t)len); 5091558Srgrimes *--cp = '/'; 5101558Srgrimes if (cp < &namebuf[MAXNAMLEN]) 5111558Srgrimes break; 5121558Srgrimes ino = idesc.id_number; 5131558Srgrimes } 5141558Srgrimes busy = 0; 5151558Srgrimes if (ino != ROOTINO) 5161558Srgrimes *--cp = '?'; 51723675Speter memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); 5181558Srgrimes} 5191558Srgrimes 5201558Srgrimesvoid 52123675Spetercatch(sig) 52223675Speter int sig; 5231558Srgrimes{ 5241558Srgrimes if (!doinglevel2) 52523675Speter ckfini(0); 5261558Srgrimes exit(12); 5271558Srgrimes} 5281558Srgrimes 5291558Srgrimes/* 5301558Srgrimes * When preening, allow a single quit to signal 5311558Srgrimes * a special exit after filesystem checks complete 5321558Srgrimes * so that reboot sequence may be interrupted. 5331558Srgrimes */ 5341558Srgrimesvoid 53523675Spetercatchquit(sig) 53623675Speter int sig; 5371558Srgrimes{ 5381558Srgrimes printf("returning to single-user after filesystem check\n"); 5391558Srgrimes returntosingle = 1; 5401558Srgrimes (void)signal(SIGQUIT, SIG_DFL); 5411558Srgrimes} 5421558Srgrimes 5431558Srgrimes/* 5441558Srgrimes * Ignore a single quit signal; wait and flush just in case. 5451558Srgrimes * Used by child processes in preen. 5461558Srgrimes */ 5471558Srgrimesvoid 54823675Spetervoidquit(sig) 54923675Speter int sig; 5501558Srgrimes{ 5511558Srgrimes 5521558Srgrimes sleep(1); 5531558Srgrimes (void)signal(SIGQUIT, SIG_IGN); 5541558Srgrimes (void)signal(SIGQUIT, SIG_DFL); 5551558Srgrimes} 5561558Srgrimes 5571558Srgrimes/* 5581558Srgrimes * determine whether an inode should be fixed. 5591558Srgrimes */ 5607585Sbdeint 5611558Srgrimesdofix(idesc, msg) 5621558Srgrimes register struct inodesc *idesc; 5631558Srgrimes char *msg; 5641558Srgrimes{ 5651558Srgrimes 5661558Srgrimes switch (idesc->id_fix) { 5671558Srgrimes 5681558Srgrimes case DONTKNOW: 5691558Srgrimes if (idesc->id_type == DATA) 5701558Srgrimes direrror(idesc->id_number, msg); 5711558Srgrimes else 57266861Sadrian pwarn(msg); 5731558Srgrimes if (preen) { 5741558Srgrimes printf(" (SALVAGED)\n"); 5751558Srgrimes idesc->id_fix = FIX; 5761558Srgrimes return (ALTERED); 5771558Srgrimes } 5781558Srgrimes if (reply("SALVAGE") == 0) { 5791558Srgrimes idesc->id_fix = NOFIX; 5801558Srgrimes return (0); 5811558Srgrimes } 5821558Srgrimes idesc->id_fix = FIX; 5831558Srgrimes return (ALTERED); 5841558Srgrimes 5851558Srgrimes case FIX: 5861558Srgrimes return (ALTERED); 5871558Srgrimes 5881558Srgrimes case NOFIX: 5891558Srgrimes case IGNORE: 5901558Srgrimes return (0); 5911558Srgrimes 5921558Srgrimes default: 59323675Speter errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix); 5941558Srgrimes } 5951558Srgrimes /* NOTREACHED */ 59623675Speter return (0); 5971558Srgrimes} 5981558Srgrimes 59923675Speter#if __STDC__ 60023675Speter#include <stdarg.h> 60123675Speter#else 60223675Speter#include <varargs.h> 60323675Speter#endif 6041558Srgrimes 6051558Srgrimes/* 6061558Srgrimes * An unexpected inconsistency occured. 60734266Sjulian * Die if preening or filesystem is running with soft dependency protocol, 60834266Sjulian * otherwise just print message and continue. 6091558Srgrimes */ 6107585Sbdevoid 61123675Speter#if __STDC__ 61223675Speterpfatal(const char *fmt, ...) 61323675Speter#else 61423675Speterpfatal(fmt, va_alist) 61523675Speter char *fmt; 61623675Speter va_dcl 61723675Speter#endif 6181558Srgrimes{ 6197585Sbde va_list ap; 62023675Speter#if __STDC__ 62123675Speter va_start(ap, fmt); 62223675Speter#else 62323675Speter va_start(ap); 62423675Speter#endif 62523675Speter if (!preen) { 62623675Speter (void)vfprintf(stderr, fmt, ap); 62723675Speter va_end(ap); 62834266Sjulian if (usedsoftdep) 62934266Sjulian (void)fprintf(stderr, 63041474Sjulian "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n"); 63123675Speter return; 6321558Srgrimes } 63341474Sjulian if (cdevname == NULL) 63441474Sjulian cdevname = "fsck"; 63523675Speter (void)fprintf(stderr, "%s: ", cdevname); 63623675Speter (void)vfprintf(stderr, fmt, ap); 63723675Speter (void)fprintf(stderr, 63834266Sjulian "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n", 63941474Sjulian cdevname, usedsoftdep ? " SOFT UPDATE " : " "); 64034266Sjulian ckfini(0); 64123675Speter exit(EEXIT); 6421558Srgrimes} 6431558Srgrimes 6441558Srgrimes/* 64534266Sjulian * Pwarn just prints a message when not preening or running soft dependency 64634266Sjulian * protocol, or a warning (preceded by filename) when preening. 6471558Srgrimes */ 6487585Sbdevoid 64923675Speter#if __STDC__ 65023675Speterpwarn(const char *fmt, ...) 65123675Speter#else 65223675Speterpwarn(fmt, va_alist) 65323675Speter char *fmt; 65423675Speter va_dcl 65523675Speter#endif 6561558Srgrimes{ 6577585Sbde va_list ap; 65823675Speter#if __STDC__ 65923675Speter va_start(ap, fmt); 66023675Speter#else 66123675Speter va_start(ap); 66223675Speter#endif 6631558Srgrimes if (preen) 66423675Speter (void)fprintf(stderr, "%s: ", cdevname); 66523675Speter (void)vfprintf(stderr, fmt, ap); 6667585Sbde va_end(ap); 6671558Srgrimes} 6681558Srgrimes 6691558Srgrimes/* 6701558Srgrimes * Stub for routines from kernel. 6711558Srgrimes */ 67218286Sbdevoid 67323675Speter#if __STDC__ 6747585Sbdepanic(const char *fmt, ...) 6757585Sbde#else 6767585Sbdepanic(fmt, va_alist) 6777585Sbde char *fmt; 67823675Speter va_dcl 6797585Sbde#endif 6801558Srgrimes{ 68123675Speter va_list ap; 68223675Speter#if __STDC__ 68323675Speter va_start(ap, fmt); 68423675Speter#else 68523675Speter va_start(ap); 68623675Speter#endif 6871558Srgrimes pfatal("INTERNAL INCONSISTENCY:"); 68823675Speter (void)vfprintf(stderr, fmt, ap); 68923675Speter va_end(ap); 69023675Speter exit(EEXIT); 6911558Srgrimes} 69266861Sadrian 69366861Sadrianchar * 69466861Sadrianblockcheck(origname) 69566861Sadrian char *origname; 69666861Sadrian{ 69766861Sadrian struct stat stslash, stblock, stchar; 69866861Sadrian char *newname, *raw; 69966861Sadrian struct fstab *fsinfo; 70066861Sadrian int retried = 0, len; 70166861Sadrian 70266861Sadrian newname = origname; 70366861Sadrianretry: 70466861Sadrian if (stat(newname, &stblock) < 0) { 70566861Sadrian printf("Can't stat %s: %s\n", newname, strerror(errno)); 70666861Sadrian return (origname); 70766861Sadrian } 70866861Sadrian switch(stblock.st_mode & S_IFMT) { 70966861Sadrian case S_IFCHR: 71066861Sadrian case S_IFBLK: 71166861Sadrian return(newname); 71266861Sadrian case S_IFDIR: 71366861Sadrian if (retried) 71466861Sadrian break; 71566861Sadrian 71666861Sadrian len = strlen(origname) - 1; 71766861Sadrian if (len > 0 && origname[len] == '/') 71866861Sadrian /* remove trailing slash */ 71966861Sadrian origname[len] = '\0'; 72066861Sadrian if ((fsinfo = getfsfile(origname)) == NULL) { 72166861Sadrian printf("Can't resolve %s to character special device", 72266861Sadrian origname); 72366861Sadrian return (0); 72466861Sadrian } 72566861Sadrian newname = fsinfo->fs_spec; 72666861Sadrian retried++; 72766861Sadrian goto retry; 72866861Sadrian } 72966861Sadrian /* 73066861Sadrian * Not a block or character device, just return name and 73166861Sadrian * let the user decide whether to use it. 73266861Sadrian */ 73366861Sadrian return (origname); 73466861Sadrian} 735