fsutil.c revision 86514
148104Syokota/*
248104Syokota * Copyright (c) 1980, 1986, 1993
348104Syokota *	The Regents of the University of California.  All rights reserved.
448104Syokota *
548104Syokota * Redistribution and use in source and binary forms, with or without
648104Syokota * modification, are permitted provided that the following conditions
748104Syokota * are met:
848104Syokota * 1. Redistributions of source code must retain the above copyright
948104Syokota *    notice, this list of conditions and the following disclaimer.
1048104Syokota * 2. Redistributions in binary form must reproduce the above copyright
1148104Syokota *    notice, this list of conditions and the following disclaimer in the
1248104Syokota *    documentation and/or other materials provided with the distribution.
1348104Syokota * 3. All advertising materials mentioning features or use of this software
1448104Syokota *    must display the following acknowledgement:
1548104Syokota *	This product includes software developed by the University of
1648104Syokota *	California, Berkeley and its contributors.
1748104Syokota * 4. Neither the name of the University nor the names of its contributors
1848104Syokota *    may be used to endorse or promote products derived from this software
1948104Syokota *    without specific prior written permission.
2048104Syokota *
2148104Syokota * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2248104Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2348104Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2448104Syokota * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2548104Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2648104Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27119420Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28119420Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29119420Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3048104Syokota * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3148104Syokota * SUCH DAMAGE.
3248104Syokota */
3348104Syokota
3448104Syokota#ifndef lint
3576166Smarkm#if 0
3676166Smarkmstatic const char sccsid[] = "@(#)utilities.c	8.6 (Berkeley) 5/19/95";
37114216Skan#endif
3876166Smarkmstatic const char rcsid[] =
3976166Smarkm  "$FreeBSD: head/sbin/fsck_ffs/fsutil.c 86514 2001-11-17 23:48:21Z iedowse $";
4076166Smarkm#endif /* not lint */
4176166Smarkm
4248104Syokota#include <sys/param.h>
4365690Smarkm#include <sys/types.h>
4476166Smarkm#include <sys/sysctl.h>
4548104Syokota#include <sys/stat.h>
4648104Syokota
4748104Syokota#include <ufs/ufs/dinode.h>
4848104Syokota#include <ufs/ufs/dir.h>
4953011Syokota#include <ufs/ffs/fs.h>
5053011Syokota
5153011Syokota#include <err.h>
5253011Syokota#include <errno.h>
5353011Syokota#include <string.h>
5453011Syokota#include <ctype.h>
5553011Syokota#include <fstab.h>
5653011Syokota#include <stdio.h>
5748104Syokota#include <stdlib.h>
5848104Syokota#include <unistd.h>
5948104Syokota
6048104Syokota#include "fsck.h"
6148104Syokota
6248104Syokotalong	diskreads, totalreads;	/* Disk cache statistics */
6348104Syokota
6448104Syokotaint
6548104Syokotaftypeok(dp)
6648104Syokota	struct dinode *dp;
6748104Syokota{
6848104Syokota	switch (dp->di_mode & IFMT) {
6948104Syokota
7048104Syokota	case IFDIR:
7148104Syokota	case IFREG:
7248104Syokota	case IFBLK:
7348104Syokota	case IFCHR:
7448104Syokota	case IFLNK:
7548104Syokota	case IFSOCK:
7656043Syokota	case IFIFO:
7756043Syokota		return (1);
7848104Syokota
79115595Sjmallett	default:
8048104Syokota		if (debug)
8148104Syokota			printf("bad file type 0%o\n", dp->di_mode);
82115595Sjmallett		return (0);
8348104Syokota	}
8448104Syokota}
8548104Syokota
8648104Syokotaint
8748104Syokotareply(question)
8848104Syokota	char *question;
8948104Syokota{
9048104Syokota	int persevere;
9148104Syokota	char c;
9248104Syokota
9348104Syokota	if (preen)
9448104Syokota		pfatal("INTERNAL ERROR: GOT TO reply()");
9548104Syokota	persevere = !strcmp(question, "CONTINUE");
9648104Syokota	printf("\n");
9748104Syokota	if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) {
9848104Syokota		printf("%s? no\n\n", question);
9948104Syokota		resolved = 0;
10048104Syokota		return (0);
10148104Syokota	}
10248104Syokota	if (yflag || (persevere && nflag)) {
10348104Syokota		printf("%s? yes\n\n", question);
10448104Syokota		return (1);
10548104Syokota	}
10648104Syokota	do	{
10748104Syokota		printf("%s? [yn] ", question);
10848104Syokota		(void) fflush(stdout);
10948104Syokota		c = getc(stdin);
11048104Syokota		while (c != '\n' && getc(stdin) != '\n') {
11148104Syokota			if (feof(stdin)) {
112111119Simp				resolved = 0;
11348104Syokota				return (0);
11448104Syokota			}
11548104Syokota		}
11648104Syokota	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
11748104Syokota	printf("\n");
11848104Syokota	if (c == 'y' || c == 'Y')
11948104Syokota		return (1);
120197539Sed	resolved = 0;
121197539Sed	return (0);
122197539Sed}
123197539Sed
124197539Sed/*
125197539Sed * Look up state information for an inode.
126197539Sed */
127197539Sedstruct inostat *
128197539Sedinoinfo(inum)
129197539Sed	ino_t inum;
130197539Sed{
131197539Sed	static struct inostat unallocated = { USTATE, 0, 0 };
132197539Sed	struct inostatlist *ilp;
133197539Sed	int iloff;
134197539Sed
135197539Sed	if (inum > maxino)
136197539Sed		errx(EEXIT, "inoinfo: inumber %d out of range", inum);
137197539Sed	ilp = &inostathead[inum / sblock.fs_ipg];
138197539Sed	iloff = inum % sblock.fs_ipg;
139197539Sed	if (iloff >= ilp->il_numalloced)
140197539Sed		return (&unallocated);
141197539Sed	return (&ilp->il_stat[iloff]);
142197539Sed}
143197539Sed
144197539Sed/*
145197539Sed * Malloc buffers and set up cache.
146197539Sed */
147197539Sedvoid
148197539Sedbufinit()
149197539Sed{
150197539Sed	register struct bufarea *bp;
151197539Sed	long bufcnt, i;
152197539Sed	char *bufp;
153197539Sed
154197539Sed	pbp = pdirbp = (struct bufarea *)0;
155197539Sed	bufp = malloc((unsigned int)sblock.fs_bsize);
156197539Sed	if (bufp == 0)
157197539Sed		errx(EEXIT, "cannot allocate buffer pool");
158197539Sed	cgblk.b_un.b_buf = bufp;
159197539Sed	initbarea(&cgblk);
160197539Sed	bufhead.b_next = bufhead.b_prev = &bufhead;
161197539Sed	bufcnt = MAXBUFSPACE / sblock.fs_bsize;
16248104Syokota	if (bufcnt < MINBUFS)
16348104Syokota		bufcnt = MINBUFS;
16448104Syokota	for (i = 0; i < bufcnt; i++) {
16548104Syokota		bp = (struct bufarea *)malloc(sizeof(struct bufarea));
16648104Syokota		bufp = malloc((unsigned int)sblock.fs_bsize);
16748104Syokota		if (bp == NULL || bufp == NULL) {
16848104Syokota			if (i >= MINBUFS)
16958872Syokota				break;
17058872Syokota			errx(EEXIT, "cannot allocate buffer pool");
171149640Srodrigc		}
17256528Syokota		bp->b_un.b_buf = bufp;
17356528Syokota		bp->b_prev = &bufhead;
17456528Syokota		bp->b_next = bufhead.b_next;
175119388Sjake		bufhead.b_next->b_prev = bp;
176119388Sjake		bufhead.b_next = bp;
17758872Syokota		initbarea(bp);
17848104Syokota	}
17948104Syokota	bufhead.b_size = i;	/* save number of buffers */
18048104Syokota}
18148104Syokota
18248104Syokota/*
18348104Syokota * Manage a cache of directory blocks.
18448104Syokota */
185119388Sjakestruct bufarea *
186119388Sjakegetdatablk(blkno, size)
18748104Syokota	ufs_daddr_t blkno;
18848104Syokota	long size;
18948104Syokota{
19048104Syokota	register struct bufarea *bp;
19148104Syokota
19248104Syokota	for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
19348104Syokota		if (bp->b_bno == fsbtodb(&sblock, blkno))
19448104Syokota			goto foundit;
19548104Syokota	for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
196119388Sjake		if ((bp->b_flags & B_INUSE) == 0)
197119388Sjake			break;
19848104Syokota	if (bp == &bufhead)
19948104Syokota		errx(EEXIT, "deadlocked buffer pool");
20048104Syokota	getblk(bp, blkno, size);
20148104Syokota	/* fall through */
202149855Srodrigcfoundit:
203149855Srodrigc	totalreads++;
20448104Syokota	bp->b_prev->b_next = bp->b_next;
20548104Syokota	bp->b_next->b_prev = bp->b_prev;
20648104Syokota	bp->b_prev = &bufhead;
207119388Sjake	bp->b_next = bufhead.b_next;
20848104Syokota	bufhead.b_next->b_prev = bp;
20948104Syokota	bufhead.b_next = bp;
21048104Syokota	bp->b_flags |= B_INUSE;
21148104Syokota	return (bp);
21248104Syokota}
21348104Syokota
21448104Syokotavoid
21548104Syokotagetblk(bp, blk, size)
21648104Syokota	register struct bufarea *bp;
21748104Syokota	ufs_daddr_t blk;
21848104Syokota	long size;
21948104Syokota{
22048104Syokota	ufs_daddr_t dblk;
22148104Syokota
22248104Syokota	dblk = fsbtodb(&sblock, blk);
223162285Sscottl	if (bp->b_bno != dblk) {
22448104Syokota		flush(fswritefd, bp);
22548104Syokota		diskreads++;
22658872Syokota		bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
22758872Syokota		bp->b_bno = dblk;
22858872Syokota		bp->b_size = size;
229162285Sscottl	}
23048104Syokota}
23148104Syokota
23248104Syokotavoid
23348104Syokotaflush(fd, bp)
23448104Syokota	int fd;
23548104Syokota	register struct bufarea *bp;
23648104Syokota{
23748104Syokota	register int i, j;
23848104Syokota
23948104Syokota	if (!bp->b_dirty)
24048104Syokota		return;
241162285Sscottl	bp->b_dirty = 0;
24248104Syokota	if (fswritefd < 0) {
243119388Sjake		pfatal("WRITING IN READ_ONLY MODE.\n");
244119388Sjake		return;
24548104Syokota	}
24648104Syokota	if (bp->b_errs != 0)
24748104Syokota		pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
24848104Syokota		    (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
24948104Syokota		    bp->b_bno);
25048104Syokota	bp->b_errs = 0;
25148104Syokota	bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
25248104Syokota	if (bp != &sblk)
25348104Syokota		return;
25448104Syokota	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
25548104Syokota		bwrite(fswritefd, (char *)sblock.fs_csp + i,
25648104Syokota		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
25748104Syokota		    sblock.fs_cssize - i < sblock.fs_bsize ?
25848104Syokota		    sblock.fs_cssize - i : sblock.fs_bsize);
25948104Syokota	}
26048104Syokota}
26158872Syokota
262162285Sscottlvoid
26348104Syokotarwerror(mesg, blk)
26448104Syokota	char *mesg;
26548104Syokota	ufs_daddr_t blk;
26648104Syokota{
26748104Syokota
26848104Syokota	if (bkgrdcheck)
26948104Syokota		exit(EEXIT);
27048104Syokota	if (preen == 0)
27148104Syokota		printf("\n");
27248104Syokota	pfatal("CANNOT %s: %ld", mesg, (long)blk);
27348104Syokota	if (reply("CONTINUE") == 0)
27448104Syokota		exit(EEXIT);
27548104Syokota}
27648104Syokota
27748104Syokotavoid
27848104Syokotackfini(markclean)
27948104Syokota	int markclean;
28048104Syokota{
28148104Syokota	register struct bufarea *bp, *nbp;
28248104Syokota	int ofsmodified, cnt = 0;
28348104Syokota
28448104Syokota	if (bkgrdflag) {
28548104Syokota		unlink(snapname);
28648104Syokota		if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) {
28748104Syokota			cmd.value = FS_UNCLEAN;
28848104Syokota			cmd.size = markclean ? -1 : 1;
28948104Syokota			if (sysctlbyname("vfs.ffs.setflags", 0, 0,
29048104Syokota			    &cmd, sizeof cmd) == -1)
29148104Syokota				rwerror("SET FILESYSTEM FLAGS", FS_UNCLEAN);
29248104Syokota			if (!preen) {
29348104Syokota				printf("\n***** FILE SYSTEM MARKED %s *****\n",
29448104Syokota				    markclean ? "CLEAN" : "DIRTY");
29548104Syokota				if (!markclean)
29648104Syokota					rerun = 1;
29748104Syokota			}
29848104Syokota		} else if (!preen && !markclean) {
29948104Syokota			printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
30048104Syokota			rerun = 1;
30148104Syokota		}
30251404Syokota	}
30348104Syokota	if (fswritefd < 0) {
30448104Syokota		(void)close(fsreadfd);
30548104Syokota		return;
30648104Syokota	}
30751404Syokota	flush(fswritefd, &sblk);
30851404Syokota	if (havesb && sblk.b_bno != SBOFF / dev_bsize && cursnapshot == 0 &&
30948104Syokota	    !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
31051404Syokota		sblk.b_bno = SBOFF / dev_bsize;
31148104Syokota		sbdirty();
31248104Syokota		flush(fswritefd, &sblk);
31348104Syokota	}
31448104Syokota	flush(fswritefd, &cgblk);
31548104Syokota	free(cgblk.b_un.b_buf);
31648104Syokota	for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
31751404Syokota		cnt++;
31848104Syokota		flush(fswritefd, bp);
31948104Syokota		nbp = bp->b_prev;
32048104Syokota		free(bp->b_un.b_buf);
32151404Syokota		free((char *)bp);
32251404Syokota	}
32348104Syokota	if (bufhead.b_size != cnt)
32451404Syokota		errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt);
32551404Syokota	pbp = pdirbp = (struct bufarea *)0;
32651404Syokota	if (cursnapshot == 0 && sblock.fs_clean != markclean) {
32748104Syokota		if ((sblock.fs_clean = markclean) != 0)
32848104Syokota			sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK);
32948104Syokota		sbdirty();
33048104Syokota		ofsmodified = fsmodified;
33152813Sarchie		flush(fswritefd, &sblk);
33248104Syokota		fsmodified = ofsmodified;
33383791Ssobomax		if (!preen) {
33483791Ssobomax			printf("\n***** FILE SYSTEM MARKED %s *****\n",
33583791Ssobomax			    markclean ? "CLEAN" : "DIRTY");
33683791Ssobomax			if (!markclean)
33783791Ssobomax				rerun = 1;
33883791Ssobomax		}
33983791Ssobomax	} else if (!preen && !markclean) {
34083791Ssobomax		printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
34183791Ssobomax		rerun = 1;
34283791Ssobomax	}
34383791Ssobomax	if (debug && totalreads > 0)
34483791Ssobomax		printf("cache missed %ld of %ld (%d%%)\n", diskreads,
34548104Syokota		    totalreads, (int)(diskreads * 100 / totalreads));
34648104Syokota	(void)close(fsreadfd);
34748104Syokota	(void)close(fswritefd);
34848104Syokota}
34948104Syokota
35048104Syokotaint
35148104Syokotabread(fd, buf, blk, size)
35248104Syokota	int fd;
35348104Syokota	char *buf;
35452813Sarchie	ufs_daddr_t blk;
35548104Syokota	long size;
35648104Syokota{
35748104Syokota	char *cp;
35848104Syokota	int i, errs;
35948104Syokota	off_t offset;
36048104Syokota
36148104Syokota	offset = blk;
36248104Syokota	offset *= dev_bsize;
36348104Syokota	if (lseek(fd, offset, 0) < 0)
36448104Syokota		rwerror("SEEK BLK", blk);
36548104Syokota	else if (read(fd, buf, (int)size) == size)
36648104Syokota		return (0);
36748104Syokota	rwerror("READ BLK", blk);
36848104Syokota	if (lseek(fd, offset, 0) < 0)
36948104Syokota		rwerror("SEEK BLK", blk);
37052813Sarchie	errs = 0;
37148104Syokota	memset(buf, 0, (size_t)size);
37248104Syokota	printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
37348104Syokota	for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
37448104Syokota		if (read(fd, cp, (int)secsize) != secsize) {
37548104Syokota			(void)lseek(fd, offset + i + secsize, 0);
37648104Syokota			if (secsize != dev_bsize && dev_bsize != 1)
37783791Ssobomax				printf(" %ld (%ld),",
37883791Ssobomax				    (blk * dev_bsize + i) / secsize,
37983791Ssobomax				    blk + i / dev_bsize);
38083791Ssobomax			else
38183791Ssobomax				printf(" %ld,", blk + i / dev_bsize);
38283791Ssobomax			errs++;
38383791Ssobomax		}
38483791Ssobomax	}
38583791Ssobomax	printf("\n");
38683791Ssobomax	if (errs)
38783791Ssobomax		resolved = 0;
38883791Ssobomax	return (errs);
38983791Ssobomax}
39083791Ssobomax
39183791Ssobomaxvoid
39283791Ssobomaxbwrite(fd, buf, blk, size)
39383791Ssobomax	int fd;
39483791Ssobomax	char *buf;
39583791Ssobomax	ufs_daddr_t blk;
39683791Ssobomax	long size;
39783791Ssobomax{
39883791Ssobomax	int i;
39983791Ssobomax	char *cp;
40083791Ssobomax	off_t offset;
40183791Ssobomax
40283791Ssobomax	if (fd < 0)
40383791Ssobomax		return;
40483791Ssobomax	offset = blk;
40583791Ssobomax	offset *= dev_bsize;
40683791Ssobomax	if (lseek(fd, offset, 0) < 0)
40783791Ssobomax		rwerror("SEEK BLK", blk);
40883791Ssobomax	else if (write(fd, buf, (int)size) == size) {
40983791Ssobomax		fsmodified = 1;
41083791Ssobomax		return;
41183791Ssobomax	}
41283791Ssobomax	resolved = 0;
41383791Ssobomax	rwerror("WRITE BLK", blk);
41483791Ssobomax	if (lseek(fd, offset, 0) < 0)
41583791Ssobomax		rwerror("SEEK BLK", blk);
41683791Ssobomax	printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
41783791Ssobomax	for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
41883791Ssobomax		if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
41983791Ssobomax			(void)lseek(fd, offset + i + dev_bsize, 0);
42083791Ssobomax			printf(" %ld,", blk + i / dev_bsize);
42183791Ssobomax		}
42283791Ssobomax	printf("\n");
42383791Ssobomax	return;
42483791Ssobomax}
42583791Ssobomax
42683791Ssobomax/*
42783791Ssobomax * allocate a data block with the specified number of fragments
42883791Ssobomax */
42983791Ssobomaxufs_daddr_t
43083791Ssobomaxallocblk(frags)
43183791Ssobomax	long frags;
43283791Ssobomax{
43383791Ssobomax	int i, j, k, cg, baseblk;
43483791Ssobomax	struct cg *cgp = &cgrp;
43583791Ssobomax
43683791Ssobomax	if (frags <= 0 || frags > sblock.fs_frag)
43748104Syokota		return (0);
43848104Syokota	for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
43948104Syokota		for (j = 0; j <= sblock.fs_frag - frags; j++) {
44048104Syokota			if (testbmap(i + j))
44148104Syokota				continue;
44248104Syokota			for (k = 1; k < frags; k++)
44348104Syokota				if (testbmap(i + j + k))
44448104Syokota					break;
44548104Syokota			if (k < frags) {
44648104Syokota				j += k;
44748104Syokota				continue;
44848104Syokota			}
44948104Syokota			cg = dtog(&sblock, i + j);
45048104Syokota			getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
45148104Syokota			if (!cg_chkmagic(cgp))
45248104Syokota				pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
45348104Syokota			baseblk = dtogd(&sblock, i + j);
45448104Syokota			for (k = 0; k < frags; k++) {
45548104Syokota				setbmap(i + j + k);
45648104Syokota				clrbit(cg_blksfree(cgp), baseblk + k);
45748104Syokota			}
45848104Syokota			n_blks += frags;
45983791Ssobomax			if (frags == sblock.fs_frag)
46048104Syokota				cgp->cg_cs.cs_nbfree--;
46148104Syokota			else
46252813Sarchie				cgp->cg_cs.cs_nffree -= frags;
46348104Syokota			cgdirty();
46448104Syokota			return (i + j);
46548104Syokota		}
46648104Syokota	}
46783791Ssobomax	return (0);
46848104Syokota}
46948104Syokota
47048104Syokota/*
47148104Syokota * Free a previously allocated block
47248104Syokota */
47383791Ssobomaxvoid
47448104Syokotafreeblk(blkno, frags)
47548104Syokota	ufs_daddr_t blkno;
47648104Syokota	long frags;
47748104Syokota{
47848104Syokota	struct inodesc idesc;
47948104Syokota
48048104Syokota	idesc.id_blkno = blkno;
48148104Syokota	idesc.id_numfrags = frags;
48283791Ssobomax	(void)pass4check(&idesc);
48348104Syokota}
48448104Syokota
48548104Syokota/*
48648104Syokota * Find a pathname
48748104Syokota */
48848104Syokotavoid
489169983Sdelphijgetpathname(namebuf, curdir, ino)
490169983Sdelphij	char *namebuf;
49148104Syokota	ino_t curdir, ino;
49283791Ssobomax{
49348104Syokota	int len;
49448104Syokota	register char *cp;
49548104Syokota	struct inodesc idesc;
49648104Syokota	static int busy = 0;
49748104Syokota
49848104Syokota	if (curdir == ino && ino == ROOTINO) {
49948104Syokota		(void)strcpy(namebuf, "/");
50048104Syokota		return;
50148104Syokota	}
50248104Syokota	if (busy ||
50348104Syokota	    (inoinfo(curdir)->ino_state != DSTATE &&
50448104Syokota	     inoinfo(curdir)->ino_state != DFOUND)) {
50548104Syokota		(void)strcpy(namebuf, "?");
50648104Syokota		return;
50748104Syokota	}
50848104Syokota	busy = 1;
50948104Syokota	memset(&idesc, 0, sizeof(struct inodesc));
51083791Ssobomax	idesc.id_type = DATA;
51183791Ssobomax	idesc.id_fix = IGNORE;
51248104Syokota	cp = &namebuf[MAXPATHLEN - 1];
51348104Syokota	*cp = '\0';
51448104Syokota	if (curdir != ino) {
51548104Syokota		idesc.id_parent = curdir;
51648104Syokota		goto namelookup;
51748104Syokota	}
51848104Syokota	while (ino != ROOTINO) {
51948104Syokota		idesc.id_number = ino;
52048104Syokota		idesc.id_func = findino;
52148104Syokota		idesc.id_name = "..";
52248104Syokota		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
52348104Syokota			break;
52448104Syokota	namelookup:
52548104Syokota		idesc.id_number = idesc.id_parent;
52648104Syokota		idesc.id_parent = ino;
52748104Syokota		idesc.id_func = findname;
52848104Syokota		idesc.id_name = namebuf;
52948104Syokota		if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
53048104Syokota			break;
53148104Syokota		len = strlen(namebuf);
53248104Syokota		cp -= len;
53348104Syokota		memmove(cp, namebuf, (size_t)len);
53488926Ssobomax		*--cp = '/';
53548104Syokota		if (cp < &namebuf[MAXNAMLEN])
53648104Syokota			break;
53748104Syokota		ino = idesc.id_number;
53848104Syokota	}
53983791Ssobomax	busy = 0;
54083791Ssobomax	if (ino != ROOTINO)
54148104Syokota		*--cp = '?';
54248104Syokota	memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
54348104Syokota}
54448104Syokota
54548104Syokotavoid
54683791Ssobomaxcatch(sig)
54748104Syokota	int sig;
54848104Syokota{
54948104Syokota	if (!doinglevel2)
55083791Ssobomax		ckfini(0);
55148104Syokota	exit(12);
55248104Syokota}
55348104Syokota
55448104Syokota/*
55548104Syokota * When preening, allow a single quit to signal
55683791Ssobomax * a special exit after filesystem checks complete
55748104Syokota * so that reboot sequence may be interrupted.
55848104Syokota */
55948104Syokotavoid
56048104Syokotacatchquit(sig)
56148104Syokota	int sig;
56248104Syokota{
56348104Syokota	printf("returning to single-user after filesystem check\n");
56483791Ssobomax	returntosingle = 1;
56548104Syokota	(void)signal(SIGQUIT, SIG_DFL);
56648104Syokota}
56748104Syokota
56848104Syokota/*
56948104Syokota * determine whether an inode should be fixed.
57083791Ssobomax */
57148104Syokotaint
57248104Syokotadofix(idesc, msg)
57348104Syokota	register struct inodesc *idesc;
57448104Syokota	char *msg;
57548104Syokota{
57648104Syokota
57783791Ssobomax	switch (idesc->id_fix) {
57888926Ssobomax
57988926Ssobomax	case DONTKNOW:
58088926Ssobomax		if (idesc->id_type == DATA)
58148104Syokota			direrror(idesc->id_number, msg);
58248104Syokota		else
58348104Syokota			pwarn("%s", msg);
58448104Syokota		if (preen) {
58548104Syokota			printf(" (SALVAGED)\n");
58648104Syokota			idesc->id_fix = FIX;
58748104Syokota			return (ALTERED);
58886894Ssobomax		}
58983791Ssobomax		if (reply("SALVAGE") == 0) {
59048104Syokota			idesc->id_fix = NOFIX;
59148104Syokota			return (0);
59283791Ssobomax		}
59383791Ssobomax		idesc->id_fix = FIX;
59486894Ssobomax		return (ALTERED);
59586894Ssobomax
59686894Ssobomax	case FIX:
59748104Syokota		return (ALTERED);
59848104Syokota
59948104Syokota	case NOFIX:
60048104Syokota	case IGNORE:
60148104Syokota		return (0);
60248104Syokota
60348104Syokota	default:
60448104Syokota		errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix);
60548104Syokota	}
60648104Syokota	/* NOTREACHED */
60748104Syokota	return (0);
60848104Syokota}
60948104Syokota
61048104Syokota#if __STDC__
61148104Syokota#include <stdarg.h>
61248104Syokota#else
61348104Syokota#include <varargs.h>
61448104Syokota#endif
61548104Syokota
61648104Syokota/*
61748104Syokota * An unexpected inconsistency occured.
61848104Syokota * Die if preening or filesystem is running with soft dependency protocol,
61948104Syokota * otherwise just print message and continue.
62048104Syokota */
62148104Syokotavoid
62248104Syokota#if __STDC__
62348104Syokotapfatal(const char *fmt, ...)
62448104Syokota#else
62548104Syokotapfatal(fmt, va_alist)
62648104Syokota	char *fmt;
62748104Syokota	va_dcl
62848104Syokota#endif
62948104Syokota{
63048104Syokota	va_list ap;
63148104Syokota#if __STDC__
63248104Syokota	va_start(ap, fmt);
63348104Syokota#else
63448104Syokota	va_start(ap);
63548104Syokota#endif
63648104Syokota	if (!preen) {
63748104Syokota		(void)vfprintf(stdout, fmt, ap);
63848104Syokota		va_end(ap);
63948104Syokota		if (usedsoftdep)
64048104Syokota			(void)fprintf(stdout,
64174118Sache			    "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n");
64274118Sache		/*
64348104Syokota		 * Force foreground fsck to clean up inconsistency.
64474125Sache		 */
64548104Syokota		if (bkgrdflag) {
64648104Syokota			cmd.value = FS_NEEDSFSCK;
64748104Syokota			cmd.size = 1;
64848104Syokota			if (sysctlbyname("vfs.ffs.setflags", 0, 0,
64948104Syokota			    &cmd, sizeof cmd) == -1)
650181905Sed				pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n");
65148104Syokota			fprintf(stdout, "CANNOT RUN IN BACKGROUND\n");
65256043Syokota			ckfini(0);
65356043Syokota			exit(EEXIT);
65456043Syokota		}
65548104Syokota		return;
65675893Sjhb	}
65748104Syokota	if (cdevname == NULL)
65856043Syokota		cdevname = "fsck";
65948104Syokota	(void)fprintf(stdout, "%s: ", cdevname);
660181905Sed	(void)vfprintf(stdout, fmt, ap);
66148104Syokota	(void)fprintf(stdout,
66248104Syokota	    "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n",
66348104Syokota	    cdevname, usedsoftdep ? " SOFT UPDATE " : " ");
66448104Syokota	/*
66548104Syokota	 * Force foreground fsck to clean up inconsistency.
66648104Syokota	 */
66756043Syokota	if (bkgrdflag) {
66865690Smarkm		cmd.value = FS_NEEDSFSCK;
66965690Smarkm		cmd.size = 1;
67065690Smarkm		if (sysctlbyname("vfs.ffs.setflags", 0, 0,
67148104Syokota		    &cmd, sizeof cmd) == -1)
67248104Syokota			pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n");
67348104Syokota	}
67448104Syokota	ckfini(0);
67548104Syokota	exit(EEXIT);
67648104Syokota}
67748104Syokota
67848104Syokota/*
67948104Syokota * Pwarn just prints a message when not preening or running soft dependency
68048104Syokota * protocol, or a warning (preceded by filename) when preening.
68148104Syokota */
68248104Syokotavoid
68348104Syokota#if __STDC__
68448104Syokotapwarn(const char *fmt, ...)
68548104Syokota#else
68648104Syokotapwarn(fmt, va_alist)
68748104Syokota	char *fmt;
68848104Syokota	va_dcl
68948104Syokota#endif
69048104Syokota{
69148104Syokota	va_list ap;
69248104Syokota#if __STDC__
69348104Syokota	va_start(ap, fmt);
69448104Syokota#else
69548104Syokota	va_start(ap);
69678951Syokota#endif
69748104Syokota	if (preen)
69848104Syokota		(void)fprintf(stdout, "%s: ", cdevname);
69948104Syokota	(void)vfprintf(stdout, fmt, ap);
70048104Syokota	va_end(ap);
70148104Syokota}
70248104Syokota
70348104Syokota/*
70448104Syokota * Stub for routines from kernel.
70548104Syokota */
70648104Syokotavoid
70748104Syokota#if __STDC__
70883366Sjulianpanic(const char *fmt, ...)
70983366Sjulian#else
71048104Syokotapanic(fmt, va_alist)
71148104Syokota	char *fmt;
71248104Syokota	va_dcl
71348104Syokota#endif
71448104Syokota{
71548104Syokota	va_list ap;
71648104Syokota#if __STDC__
71748104Syokota	va_start(ap, fmt);
71848104Syokota#else
71948104Syokota	va_start(ap);
72048104Syokota#endif
72148104Syokota	pfatal("INTERNAL INCONSISTENCY:");
72258872Syokota	(void)vfprintf(stdout, fmt, ap);
72358872Syokota	va_end(ap);
72448104Syokota	exit(EEXIT);
72548104Syokota}
726146736Sdelphij