xref: /openbsd-src/sbin/fsck_ext2fs/utilities.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: utilities.c,v 1.29 2023/03/08 04:43:06 guenther Exp $	*/
20190393fSart /*	$NetBSD: utilities.c,v 1.6 2001/02/04 21:19:34 christos Exp $	*/
38c424e8eSdownsj 
48c424e8eSdownsj /*
55ff4e0c8Sdownsj  * Copyright (c) 1997 Manuel Bouyer.
68c424e8eSdownsj  * Copyright (c) 1980, 1986, 1993
78c424e8eSdownsj  *	The Regents of the University of California.  All rights reserved.
88c424e8eSdownsj  *
98c424e8eSdownsj  * Redistribution and use in source and binary forms, with or without
108c424e8eSdownsj  * modification, are permitted provided that the following conditions
118c424e8eSdownsj  * are met:
128c424e8eSdownsj  * 1. Redistributions of source code must retain the above copyright
138c424e8eSdownsj  *    notice, this list of conditions and the following disclaimer.
148c424e8eSdownsj  * 2. Redistributions in binary form must reproduce the above copyright
158c424e8eSdownsj  *    notice, this list of conditions and the following disclaimer in the
168c424e8eSdownsj  *    documentation and/or other materials provided with the distribution.
171ef0d710Smillert  * 3. Neither the name of the University nor the names of its contributors
188c424e8eSdownsj  *    may be used to endorse or promote products derived from this software
198c424e8eSdownsj  *    without specific prior written permission.
208c424e8eSdownsj  *
218c424e8eSdownsj  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
228c424e8eSdownsj  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238c424e8eSdownsj  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248c424e8eSdownsj  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
258c424e8eSdownsj  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
268c424e8eSdownsj  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
278c424e8eSdownsj  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
288c424e8eSdownsj  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
298c424e8eSdownsj  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
308c424e8eSdownsj  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
318c424e8eSdownsj  * SUCH DAMAGE.
328c424e8eSdownsj  */
338c424e8eSdownsj 
34b9fc9a72Sderaadt #include <sys/param.h>	/* DEV_BSIZE isset setbit */
358c424e8eSdownsj #include <sys/time.h>
36b9fc9a72Sderaadt #include <sys/signal.h>
378c424e8eSdownsj #include <ufs/ext2fs/ext2fs_dinode.h>
388c424e8eSdownsj #include <ufs/ext2fs/ext2fs_dir.h>
398c424e8eSdownsj #include <ufs/ext2fs/ext2fs.h>
408c424e8eSdownsj #include <ufs/ufs/dinode.h> /* for IFMT & friends */
418c424e8eSdownsj #include <stdio.h>
428c424e8eSdownsj #include <stdlib.h>
438c424e8eSdownsj #include <string.h>
448c424e8eSdownsj #include <ctype.h>
458c424e8eSdownsj #include <unistd.h>
465cb46d43Sderaadt #include <errno.h>
478c424e8eSdownsj 
488c424e8eSdownsj #include "fsutil.h"
498c424e8eSdownsj #include "fsck.h"
508c424e8eSdownsj #include "extern.h"
518c424e8eSdownsj 
528c424e8eSdownsj long	diskreads, totalreads;	/* Disk cache statistics */
538c424e8eSdownsj 
54b6d2e2d5Sderaadt static void rwerror(char *, daddr32_t);
558c424e8eSdownsj 
568c424e8eSdownsj int
ftypeok(struct ext2fs_dinode * dp)578809fabbSderaadt ftypeok(struct ext2fs_dinode *dp)
588c424e8eSdownsj {
5960a51e06Spelikan 	switch (letoh16(dp->e2di_mode) & IFMT) {
608c424e8eSdownsj 
618c424e8eSdownsj 	case IFDIR:
628c424e8eSdownsj 	case IFREG:
638c424e8eSdownsj 	case IFBLK:
648c424e8eSdownsj 	case IFCHR:
658c424e8eSdownsj 	case IFLNK:
668c424e8eSdownsj 	case IFSOCK:
678c424e8eSdownsj 	case IFIFO:
688c424e8eSdownsj 		return (1);
698c424e8eSdownsj 
708c424e8eSdownsj 	default:
718c424e8eSdownsj 		if (debug)
7260a51e06Spelikan 			printf("bad file type 0%o\n", letoh16(dp->e2di_mode));
738c424e8eSdownsj 		return (0);
748c424e8eSdownsj 	}
758c424e8eSdownsj }
768c424e8eSdownsj 
778c424e8eSdownsj int
reply(char * question)788809fabbSderaadt reply(char *question)
798c424e8eSdownsj {
808c424e8eSdownsj 	int persevere;
8141770c1aSderaadt 	int c;
828c424e8eSdownsj 
838c424e8eSdownsj 	if (preen)
848c424e8eSdownsj 		pfatal("INTERNAL ERROR: GOT TO reply()");
858c424e8eSdownsj 	persevere = !strcmp(question, "CONTINUE");
868c424e8eSdownsj 	printf("\n");
878c424e8eSdownsj 	if (!persevere && (nflag || fswritefd < 0)) {
888c424e8eSdownsj 		printf("%s? no\n\n", question);
898c424e8eSdownsj 		return (0);
908c424e8eSdownsj 	}
918c424e8eSdownsj 	if (yflag || (persevere && nflag)) {
928c424e8eSdownsj 		printf("%s? yes\n\n", question);
938c424e8eSdownsj 		return (1);
948c424e8eSdownsj 	}
958c424e8eSdownsj 	do {
965cb46d43Sderaadt 		printf("%s? [Fyn?] ", question);
978c424e8eSdownsj 		(void) fflush(stdout);
988c424e8eSdownsj 		c = getc(stdin);
99daaa95b6Sderaadt 		if (c == 'F') {
100daaa95b6Sderaadt 			yflag = 1;
101daaa95b6Sderaadt 			return (1);
102daaa95b6Sderaadt 		}
1038c424e8eSdownsj 		while (c != '\n' && getc(stdin) != '\n')
1048c424e8eSdownsj 			if (feof(stdin))
1058c424e8eSdownsj 				return (0);
1068c424e8eSdownsj 	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
1078c424e8eSdownsj 	printf("\n");
1088c424e8eSdownsj 	if (c == 'y' || c == 'Y')
1098c424e8eSdownsj 		return (1);
1108c424e8eSdownsj 	return (0);
1118c424e8eSdownsj }
1128c424e8eSdownsj 
1138c424e8eSdownsj /*
1148c424e8eSdownsj  * Malloc buffers and set up cache.
1158c424e8eSdownsj  */
1168c424e8eSdownsj void
bufinit(void)1178809fabbSderaadt bufinit(void)
1188c424e8eSdownsj {
1190190393fSart 	struct bufarea *bp;
1208c424e8eSdownsj 	long bufcnt, i;
1218c424e8eSdownsj 	char *bufp;
1228c424e8eSdownsj 
12365348f21Sjasoni 	diskreads = totalreads = 0;
124c9899b11Skrw 	pbp = pdirbp = NULL;
1258c424e8eSdownsj 	bufhead.b_next = bufhead.b_prev = &bufhead;
1268c424e8eSdownsj 	bufcnt = MAXBUFSPACE / sblock.e2fs_bsize;
1278c424e8eSdownsj 	if (bufcnt < MINBUFS)
1288c424e8eSdownsj 		bufcnt = MINBUFS;
1298c424e8eSdownsj 	for (i = 0; i < bufcnt; i++) {
1305ae94ef8Sderaadt 		bp = malloc(sizeof(struct bufarea));
1318c424e8eSdownsj 		bufp = malloc((unsigned int)sblock.e2fs_bsize);
1328c424e8eSdownsj 		if (bp == NULL || bufp == NULL) {
1334435eaddSderaadt 			free(bp);
1344435eaddSderaadt 			free(bufp);
1358c424e8eSdownsj 			if (i >= MINBUFS)
1368c424e8eSdownsj 				break;
1378c424e8eSdownsj 			errexit("cannot allocate buffer pool\n");
1388c424e8eSdownsj 		}
1398c424e8eSdownsj 		bp->b_un.b_buf = bufp;
1408c424e8eSdownsj 		bp->b_prev = &bufhead;
1418c424e8eSdownsj 		bp->b_next = bufhead.b_next;
1428c424e8eSdownsj 		bufhead.b_next->b_prev = bp;
1438c424e8eSdownsj 		bufhead.b_next = bp;
1448c424e8eSdownsj 		initbarea(bp);
1458c424e8eSdownsj 	}
1468c424e8eSdownsj 	bufhead.b_size = i;	/* save number of buffers */
1478c424e8eSdownsj }
1488c424e8eSdownsj 
1498c424e8eSdownsj /*
1508c424e8eSdownsj  * Manage a cache of directory blocks.
1518c424e8eSdownsj  */
1528c424e8eSdownsj struct bufarea *
getdatablk(daddr32_t blkno,long size)153b6d2e2d5Sderaadt getdatablk(daddr32_t blkno, long size)
1548c424e8eSdownsj {
1550190393fSart 	struct bufarea *bp;
1568c424e8eSdownsj 
1578c424e8eSdownsj 	for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
1588c424e8eSdownsj 		if (bp->b_bno == fsbtodb(&sblock, blkno))
1598c424e8eSdownsj 			goto foundit;
1608c424e8eSdownsj 	for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
1618c424e8eSdownsj 		if ((bp->b_flags & B_INUSE) == 0)
1628c424e8eSdownsj 			break;
1638c424e8eSdownsj 	if (bp == &bufhead)
1648c424e8eSdownsj 		errexit("deadlocked buffer pool\n");
1658c424e8eSdownsj 	getblk(bp, blkno, size);
16665348f21Sjasoni 	diskreads++;
1678c424e8eSdownsj 	/* fall through */
1688c424e8eSdownsj foundit:
1698c424e8eSdownsj 	totalreads++;
1708c424e8eSdownsj 	bp->b_prev->b_next = bp->b_next;
1718c424e8eSdownsj 	bp->b_next->b_prev = bp->b_prev;
1728c424e8eSdownsj 	bp->b_prev = &bufhead;
1738c424e8eSdownsj 	bp->b_next = bufhead.b_next;
1748c424e8eSdownsj 	bufhead.b_next->b_prev = bp;
1758c424e8eSdownsj 	bufhead.b_next = bp;
1768c424e8eSdownsj 	bp->b_flags |= B_INUSE;
1778c424e8eSdownsj 	return (bp);
1788c424e8eSdownsj }
1798c424e8eSdownsj 
1808c424e8eSdownsj void
getblk(struct bufarea * bp,daddr32_t blk,long size)181b6d2e2d5Sderaadt getblk(struct bufarea *bp, daddr32_t blk, long size)
1828c424e8eSdownsj {
183b6d2e2d5Sderaadt 	daddr32_t dblk;
1848c424e8eSdownsj 
1858c424e8eSdownsj 	dblk = fsbtodb(&sblock, blk);
1868c424e8eSdownsj 	if (bp->b_bno != dblk) {
1878c424e8eSdownsj 		flush(fswritefd, bp);
1888c424e8eSdownsj 		diskreads++;
1898c424e8eSdownsj 		bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
1908c424e8eSdownsj 		bp->b_bno = dblk;
1918c424e8eSdownsj 		bp->b_size = size;
1928c424e8eSdownsj 	}
1938c424e8eSdownsj }
1948c424e8eSdownsj 
1958c424e8eSdownsj void
flush(int fd,struct bufarea * bp)1968809fabbSderaadt flush(int fd, struct bufarea *bp)
1978c424e8eSdownsj {
1980190393fSart 	int i;
1998c424e8eSdownsj 
2008c424e8eSdownsj 	if (!bp->b_dirty)
2018c424e8eSdownsj 		return;
2028c424e8eSdownsj 	if (bp->b_errs != 0)
2038c424e8eSdownsj 		pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
2049e7daf04Skrw 		    (bp->b_errs == bp->b_size / DEV_BSIZE) ? "" : "PARTIALLY ",
2058c424e8eSdownsj 		    bp->b_bno);
2068c424e8eSdownsj 	bp->b_dirty = 0;
2078c424e8eSdownsj 	bp->b_errs = 0;
2088c424e8eSdownsj 	bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
2098c424e8eSdownsj 	if (bp != &sblk)
2108c424e8eSdownsj 		return;
2118c424e8eSdownsj 	for (i = 0; i < sblock.e2fs_ngdb; i++) {
2128c424e8eSdownsj 		bwrite(fswritefd, (char *)
2138c424e8eSdownsj 			&sblock.e2fs_gd[i* sblock.e2fs_bsize / sizeof(struct ext2_gd)],
2148c424e8eSdownsj 		    fsbtodb(&sblock, ((sblock.e2fs_bsize>1024)?0:1)+i+1),
2158c424e8eSdownsj 		    sblock.e2fs_bsize);
2168c424e8eSdownsj 	}
2178c424e8eSdownsj }
2188c424e8eSdownsj 
2198c424e8eSdownsj static void
rwerror(char * mesg,daddr32_t blk)220b6d2e2d5Sderaadt rwerror(char *mesg, daddr32_t blk)
2218c424e8eSdownsj {
2228c424e8eSdownsj 
2238c424e8eSdownsj 	if (preen == 0)
2248c424e8eSdownsj 		printf("\n");
2258c424e8eSdownsj 	pfatal("CANNOT %s: BLK %d", mesg, blk);
2268c424e8eSdownsj 	if (reply("CONTINUE") == 0)
2278c424e8eSdownsj 		errexit("Program terminated\n");
2288c424e8eSdownsj }
2298c424e8eSdownsj 
2308c424e8eSdownsj void
ckfini(int markclean)2318809fabbSderaadt ckfini(int markclean)
2328c424e8eSdownsj {
2330190393fSart 	struct bufarea *bp, *nbp;
2348c424e8eSdownsj 	int cnt = 0;
2358c424e8eSdownsj 
2368c424e8eSdownsj 	if (fswritefd < 0) {
2378c424e8eSdownsj 		(void)close(fsreadfd);
2388c424e8eSdownsj 		return;
2398c424e8eSdownsj 	}
2408c424e8eSdownsj 	flush(fswritefd, &sblk);
2419e7daf04Skrw 	if (havesb && sblk.b_bno != SBOFF / DEV_BSIZE &&
24265348f21Sjasoni 	    !preen && reply("UPDATE STANDARD SUPERBLOCKS")) {
2439e7daf04Skrw 		sblk.b_bno = SBOFF / DEV_BSIZE;
2448c424e8eSdownsj 		sbdirty();
2458c424e8eSdownsj 		flush(fswritefd, &sblk);
24665348f21Sjasoni 		copyback_sb(&asblk);
24765348f21Sjasoni 		asblk.b_dirty = 1;
24865348f21Sjasoni 		flush(fswritefd, &asblk);
2498c424e8eSdownsj 	}
2508c424e8eSdownsj 	for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
2518c424e8eSdownsj 		cnt++;
2528c424e8eSdownsj 		flush(fswritefd, bp);
2538c424e8eSdownsj 		nbp = bp->b_prev;
2548c424e8eSdownsj 		free(bp->b_un.b_buf);
2558c424e8eSdownsj 		free((char *)bp);
2568c424e8eSdownsj 	}
2578c424e8eSdownsj 	if (bufhead.b_size != cnt)
2588c424e8eSdownsj 		errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
259c9899b11Skrw 	pbp = pdirbp = NULL;
2608c424e8eSdownsj 	if (markclean && (sblock.e2fs.e2fs_state & E2FS_ISCLEAN) == 0) {
2618c424e8eSdownsj 		/*
2628c424e8eSdownsj 		 * Mark the file system as clean, and sync the superblock.
2638c424e8eSdownsj 		 */
2648c424e8eSdownsj 		if (preen)
2658c424e8eSdownsj 			pwarn("MARKING FILE SYSTEM CLEAN\n");
2668c424e8eSdownsj 		else if (!reply("MARK FILE SYSTEM CLEAN"))
2678c424e8eSdownsj 			markclean = 0;
2688c424e8eSdownsj 		if (markclean) {
2698c424e8eSdownsj 			sblock.e2fs.e2fs_state = E2FS_ISCLEAN;
2708c424e8eSdownsj 			sbdirty();
2718c424e8eSdownsj 			flush(fswritefd, &sblk);
2728c424e8eSdownsj 		}
2738c424e8eSdownsj 	}
2748c424e8eSdownsj 	if (debug)
2758c424e8eSdownsj 		printf("cache missed %ld of %ld (%d%%)\n", diskreads,
2768c424e8eSdownsj 		    totalreads, (int)(diskreads * 100 / totalreads));
2778c424e8eSdownsj 	(void)close(fsreadfd);
2788c424e8eSdownsj 	(void)close(fswritefd);
2798c424e8eSdownsj }
2808c424e8eSdownsj 
2818c424e8eSdownsj int
bread(int fd,char * buf,daddr32_t blk,long size)282b6d2e2d5Sderaadt bread(int fd, char *buf, daddr32_t blk, long size)
2838c424e8eSdownsj {
2848c424e8eSdownsj 	char *cp;
2858c424e8eSdownsj 	int i, errs;
2868c424e8eSdownsj 	off_t offset;
2878c424e8eSdownsj 
2888c424e8eSdownsj 	offset = blk;
2899e7daf04Skrw 	offset *= DEV_BSIZE;
2901593d282Skrw 	if (pread(fd, buf, size, offset) == size)
2918c424e8eSdownsj 		return (0);
2928c424e8eSdownsj 	rwerror("READ", blk);
2938c424e8eSdownsj 	errs = 0;
2948c424e8eSdownsj 	memset(buf, 0, (size_t)size);
2958c424e8eSdownsj 	printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
2968c424e8eSdownsj 	for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
2971593d282Skrw 		if (pread(fd, cp, secsize, offset + i) != secsize) {
2989e7daf04Skrw 			if (secsize != DEV_BSIZE)
2995480ff59Skrw 				printf(" %lld (%lld),",
3005480ff59Skrw 				    (long long)(offset + i) / secsize,
3015480ff59Skrw 				    (long long)blk + i / DEV_BSIZE);
3028c424e8eSdownsj 			else
3035480ff59Skrw 				printf(" %lld,", (long long)blk +
3045480ff59Skrw 				    i / DEV_BSIZE);
3058c424e8eSdownsj 			errs++;
3068c424e8eSdownsj 		}
3078c424e8eSdownsj 	}
3088c424e8eSdownsj 	printf("\n");
3098c424e8eSdownsj 	return (errs);
3108c424e8eSdownsj }
3118c424e8eSdownsj 
3128c424e8eSdownsj void
bwrite(int fd,char * buf,daddr32_t blk,long size)313b6d2e2d5Sderaadt bwrite(int fd, char *buf, daddr32_t blk, long size)
3148c424e8eSdownsj {
3158c424e8eSdownsj 	int i;
3168c424e8eSdownsj 	char *cp;
3178c424e8eSdownsj 	off_t offset;
3188c424e8eSdownsj 
3198c424e8eSdownsj 	if (fd < 0)
3208c424e8eSdownsj 		return;
3218c424e8eSdownsj 	offset = blk;
3229e7daf04Skrw 	offset *= DEV_BSIZE;
3231593d282Skrw 	if (pwrite(fd, buf, size, offset) == size) {
3248c424e8eSdownsj 		fsmodified = 1;
3258c424e8eSdownsj 		return;
3268c424e8eSdownsj 	}
3278c424e8eSdownsj 	rwerror("WRITE", blk);
3288c424e8eSdownsj 	printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
3299e7daf04Skrw 	for (cp = buf, i = 0; i < size; i += secsize, cp += secsize)
3309e7daf04Skrw 		if (pwrite(fd, cp, secsize, offset + i) != secsize) {
3315480ff59Skrw 			if (secsize != DEV_BSIZE)
3325480ff59Skrw 				printf(" %lld (%lld),",
3335480ff59Skrw 				    (long long)(offset + i) / secsize,
3345480ff59Skrw 				    (long long)blk + i / DEV_BSIZE);
3355480ff59Skrw 			else
3365480ff59Skrw 				printf(" %lld,", (long long)blk +
3375480ff59Skrw 				    i / DEV_BSIZE);
3388c424e8eSdownsj 		}
3398c424e8eSdownsj 	printf("\n");
3408c424e8eSdownsj 	return;
3418c424e8eSdownsj }
3428c424e8eSdownsj 
3438c424e8eSdownsj /*
3448c424e8eSdownsj  * allocate a data block
3458c424e8eSdownsj  */
3468c424e8eSdownsj int
allocblk(void)3478809fabbSderaadt allocblk(void)
3488c424e8eSdownsj {
3490190393fSart 	int i;
3508c424e8eSdownsj 
3518c424e8eSdownsj 	for (i = 0; i < maxfsblock - 1; i++) {
3528c424e8eSdownsj 		if (testbmap(i))
3538c424e8eSdownsj 				continue;
3548c424e8eSdownsj 		setbmap(i);
3558c424e8eSdownsj 		n_blks ++;
3568c424e8eSdownsj 		return (i);
3578c424e8eSdownsj 	}
3588c424e8eSdownsj 	return (0);
3598c424e8eSdownsj }
3608c424e8eSdownsj 
3618c424e8eSdownsj /*
3628c424e8eSdownsj  * Free a previously allocated block
3638c424e8eSdownsj  */
3648c424e8eSdownsj void
freeblk(daddr32_t blkno)365b6d2e2d5Sderaadt freeblk(daddr32_t blkno)
3668c424e8eSdownsj {
3678c424e8eSdownsj 	struct inodesc idesc;
3688c424e8eSdownsj 
3698c424e8eSdownsj 	idesc.id_blkno = blkno;
3708c424e8eSdownsj 	idesc.id_numfrags = 1;
3718c424e8eSdownsj 	(void)pass4check(&idesc);
3728c424e8eSdownsj }
3738c424e8eSdownsj 
3748c424e8eSdownsj /*
3758c424e8eSdownsj  * Find a pathname
3768c424e8eSdownsj  */
3778c424e8eSdownsj void
getpathname(char * namebuf,size_t buflen,ino_t curdir,ino_t ino)3788809fabbSderaadt getpathname(char *namebuf, size_t buflen, ino_t curdir, ino_t ino)
3798c424e8eSdownsj {
380487a1948Stedu 	size_t len;
3810190393fSart 	char *cp;
3828c424e8eSdownsj 	struct inodesc idesc;
3838c424e8eSdownsj 	static int busy = 0;
3848c424e8eSdownsj 
3858c424e8eSdownsj 	if (curdir == ino && ino == EXT2_ROOTINO) {
386487a1948Stedu 		(void)strlcpy(namebuf, "/", buflen);
3878c424e8eSdownsj 		return;
3888c424e8eSdownsj 	}
3898c424e8eSdownsj 	if (busy ||
3908c424e8eSdownsj 	    (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
3918809fabbSderaadt 
392487a1948Stedu 		(void)strlcpy(namebuf, "?", buflen);
3938c424e8eSdownsj 		return;
3948c424e8eSdownsj 	}
3958c424e8eSdownsj 	busy = 1;
3968c424e8eSdownsj 	memset(&idesc, 0, sizeof(struct inodesc));
3978c424e8eSdownsj 	idesc.id_type = DATA;
3988c424e8eSdownsj 	idesc.id_fix = IGNORE;
399487a1948Stedu 	cp = &namebuf[buflen - 1];
4008c424e8eSdownsj 	*cp = '\0';
4018c424e8eSdownsj 	if (curdir != ino) {
4028c424e8eSdownsj 		idesc.id_parent = curdir;
4038c424e8eSdownsj 		goto namelookup;
4048c424e8eSdownsj 	}
4058c424e8eSdownsj 	while (ino != EXT2_ROOTINO) {
4068c424e8eSdownsj 		idesc.id_number = ino;
4078c424e8eSdownsj 		idesc.id_func = findino;
4088c424e8eSdownsj 		idesc.id_name = "..";
4098c424e8eSdownsj 		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
4108c424e8eSdownsj 			break;
4118c424e8eSdownsj 	namelookup:
4128c424e8eSdownsj 		idesc.id_number = idesc.id_parent;
4138c424e8eSdownsj 		idesc.id_parent = ino;
4148c424e8eSdownsj 		idesc.id_func = findname;
4158c424e8eSdownsj 		idesc.id_name = namebuf;
4168c424e8eSdownsj 		if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
4178c424e8eSdownsj 			break;
4188c424e8eSdownsj 		len = strlen(namebuf);
4198c424e8eSdownsj 		cp -= len;
4202edacca7Smillert 		memmove(cp, namebuf, len);
421487a1948Stedu 		*(--cp) = '/';
4228c424e8eSdownsj 		if (cp < &namebuf[EXT2FS_MAXNAMLEN])
4238c424e8eSdownsj 			break;
4248c424e8eSdownsj 		ino = idesc.id_number;
4258c424e8eSdownsj 	}
4268c424e8eSdownsj 	busy = 0;
4278c424e8eSdownsj 	if (ino != EXT2_ROOTINO)
428487a1948Stedu 		*(--cp) = '?';
4292edacca7Smillert 	memmove(namebuf, cp, (size_t)(&namebuf[buflen] - cp));
4308c424e8eSdownsj }
4318c424e8eSdownsj 
4328c424e8eSdownsj void
catch(int signo)4335cb46d43Sderaadt catch(int signo)
4348c424e8eSdownsj {
4355cb46d43Sderaadt 	ckfini(0);			/* XXX signal race */
4365cb46d43Sderaadt 	_exit(12);
4378c424e8eSdownsj }
4388c424e8eSdownsj 
4398c424e8eSdownsj /*
4408c424e8eSdownsj  * When preening, allow a single quit to signal
4418c424e8eSdownsj  * a special exit after filesystem checks complete
4428c424e8eSdownsj  * so that reboot sequence may be interrupted.
4438c424e8eSdownsj  */
4448c424e8eSdownsj void
catchquit(int signo)4455cb46d43Sderaadt catchquit(int signo)
4468c424e8eSdownsj {
4475cb46d43Sderaadt 	extern volatile sig_atomic_t returntosingle;
4489d5ab9dfSguenther 	static const char message[] =
4499d5ab9dfSguenther 	    "returning to single-user after filesystem check\n";
4508c424e8eSdownsj 
4519d5ab9dfSguenther 	write(STDOUT_FILENO, message, sizeof(message)-1);
4528c424e8eSdownsj 	returntosingle = 1;
4538c424e8eSdownsj 	(void)signal(SIGQUIT, SIG_DFL);
4548c424e8eSdownsj }
4558c424e8eSdownsj 
4568c424e8eSdownsj /*
4578c424e8eSdownsj  * Ignore a single quit signal; wait and flush just in case.
4588c424e8eSdownsj  * Used by child processes in preen.
4598c424e8eSdownsj  */
4608c424e8eSdownsj void
voidquit(int signo)4615cb46d43Sderaadt voidquit(int signo)
4628c424e8eSdownsj {
4635cb46d43Sderaadt 	int save_errno = errno;
4648c424e8eSdownsj 
4658c424e8eSdownsj 	sleep(1);
4668c424e8eSdownsj 	(void)signal(SIGQUIT, SIG_IGN);
4678c424e8eSdownsj 	(void)signal(SIGQUIT, SIG_DFL);
4685cb46d43Sderaadt 	errno = save_errno;
4698c424e8eSdownsj }
4708c424e8eSdownsj 
4718c424e8eSdownsj /*
4728c424e8eSdownsj  * determine whether an inode should be fixed.
4738c424e8eSdownsj  */
4748c424e8eSdownsj int
dofix(struct inodesc * idesc,char * msg)4758809fabbSderaadt dofix(struct inodesc *idesc, char *msg)
4768c424e8eSdownsj {
4778c424e8eSdownsj 
4788c424e8eSdownsj 	switch (idesc->id_fix) {
4798c424e8eSdownsj 
4808c424e8eSdownsj 	case DONTKNOW:
4818c424e8eSdownsj 		if (idesc->id_type == DATA)
4828c424e8eSdownsj 			direrror(idesc->id_number, msg);
4838c424e8eSdownsj 		else
4842cc28a79Saaron 			pwarn("%s", msg);
4858c424e8eSdownsj 		if (preen) {
4868c424e8eSdownsj 			printf(" (SALVAGED)\n");
4878c424e8eSdownsj 			idesc->id_fix = FIX;
4888c424e8eSdownsj 			return (ALTERED);
4898c424e8eSdownsj 		}
4908c424e8eSdownsj 		if (reply("SALVAGE") == 0) {
4918c424e8eSdownsj 			idesc->id_fix = NOFIX;
4928c424e8eSdownsj 			return (0);
4938c424e8eSdownsj 		}
4948c424e8eSdownsj 		idesc->id_fix = FIX;
4958c424e8eSdownsj 		return (ALTERED);
4968c424e8eSdownsj 
4978c424e8eSdownsj 	case FIX:
4988c424e8eSdownsj 		return (ALTERED);
4998c424e8eSdownsj 
5008c424e8eSdownsj 	case NOFIX:
5018c424e8eSdownsj 	case IGNORE:
5028c424e8eSdownsj 		return (0);
5038c424e8eSdownsj 
5048c424e8eSdownsj 	default:
5058c424e8eSdownsj 		errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
5068c424e8eSdownsj 	}
5078c424e8eSdownsj 	/* NOTREACHED */
5088c424e8eSdownsj }
509