xref: /freebsd/sbin/fsck_ffs/utilities.c (revision 780a5c1ec16f889d55914a09fbcde7ff7b2cfcca)
18fae3551SRodney W. Grimes /*
28fae3551SRodney W. Grimes  * Copyright (c) 1980, 1986, 1993
38fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
48fae3551SRodney W. Grimes  *
58fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
68fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
78fae3551SRodney W. Grimes  * are met:
88fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
98fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
108fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
118fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
128fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
138fae3551SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
148fae3551SRodney W. Grimes  *    must display the following acknowledgement:
158fae3551SRodney W. Grimes  *	This product includes software developed by the University of
168fae3551SRodney W. Grimes  *	California, Berkeley and its contributors.
178fae3551SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
188fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
198fae3551SRodney W. Grimes  *    without specific prior written permission.
208fae3551SRodney W. Grimes  *
218fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
228fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
258fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
268fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
278fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
288fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
298fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
308fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
318fae3551SRodney W. Grimes  * SUCH DAMAGE.
328fae3551SRodney W. Grimes  */
338fae3551SRodney W. Grimes 
348fae3551SRodney W. Grimes #ifndef lint
35780a5c1eSPeter Wemm static const char sccsid[] = "@(#)utilities.c	8.6 (Berkeley) 5/19/95";
368fae3551SRodney W. Grimes #endif /* not lint */
378fae3551SRodney W. Grimes 
388fae3551SRodney W. Grimes #include <sys/param.h>
398fae3551SRodney W. Grimes #include <sys/time.h>
40780a5c1eSPeter Wemm 
418fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h>
428fae3551SRodney W. Grimes #include <ufs/ufs/dir.h>
438fae3551SRodney W. Grimes #include <ufs/ffs/fs.h>
448fae3551SRodney W. Grimes #include <stdio.h>
458fae3551SRodney W. Grimes #include <stdlib.h>
4631f4ab50SBruce Evans #include <unistd.h>
4731f4ab50SBruce Evans #include <stdarg.h>
488fae3551SRodney W. Grimes #include <string.h>
49780a5c1eSPeter Wemm #include <ctype.h>
50780a5c1eSPeter Wemm #include <err.h>
51780a5c1eSPeter Wemm 
528fae3551SRodney W. Grimes #include "fsck.h"
538fae3551SRodney W. Grimes 
548fae3551SRodney W. Grimes long	diskreads, totalreads;	/* Disk cache statistics */
558fae3551SRodney W. Grimes 
56780a5c1eSPeter Wemm static void rwerror __P((char *mesg, ufs_daddr_t blk));
5731f4ab50SBruce Evans 
5831f4ab50SBruce Evans int
598fae3551SRodney W. Grimes ftypeok(dp)
608fae3551SRodney W. Grimes 	struct dinode *dp;
618fae3551SRodney W. Grimes {
628fae3551SRodney W. Grimes 	switch (dp->di_mode & IFMT) {
638fae3551SRodney W. Grimes 
648fae3551SRodney W. Grimes 	case IFDIR:
658fae3551SRodney W. Grimes 	case IFREG:
668fae3551SRodney W. Grimes 	case IFBLK:
678fae3551SRodney W. Grimes 	case IFCHR:
688fae3551SRodney W. Grimes 	case IFLNK:
698fae3551SRodney W. Grimes 	case IFSOCK:
708fae3551SRodney W. Grimes 	case IFIFO:
718fae3551SRodney W. Grimes 		return (1);
728fae3551SRodney W. Grimes 
738fae3551SRodney W. Grimes 	default:
748fae3551SRodney W. Grimes 		if (debug)
758fae3551SRodney W. Grimes 			printf("bad file type 0%o\n", dp->di_mode);
768fae3551SRodney W. Grimes 		return (0);
778fae3551SRodney W. Grimes 	}
788fae3551SRodney W. Grimes }
798fae3551SRodney W. Grimes 
8031f4ab50SBruce Evans int
818fae3551SRodney W. Grimes reply(question)
828fae3551SRodney W. Grimes 	char *question;
838fae3551SRodney W. Grimes {
848fae3551SRodney W. Grimes 	int persevere;
858fae3551SRodney W. Grimes 	char c;
868fae3551SRodney W. Grimes 
878fae3551SRodney W. Grimes 	if (preen)
888fae3551SRodney W. Grimes 		pfatal("INTERNAL ERROR: GOT TO reply()");
898fae3551SRodney W. Grimes 	persevere = !strcmp(question, "CONTINUE");
908fae3551SRodney W. Grimes 	printf("\n");
918fae3551SRodney W. Grimes 	if (!persevere && (nflag || fswritefd < 0)) {
928fae3551SRodney W. Grimes 		printf("%s? no\n\n", question);
938fae3551SRodney W. Grimes 		return (0);
948fae3551SRodney W. Grimes 	}
958fae3551SRodney W. Grimes 	if (yflag || (persevere && nflag)) {
968fae3551SRodney W. Grimes 		printf("%s? yes\n\n", question);
978fae3551SRodney W. Grimes 		return (1);
988fae3551SRodney W. Grimes 	}
998fae3551SRodney W. Grimes 	do	{
1008fae3551SRodney W. Grimes 		printf("%s? [yn] ", question);
1018fae3551SRodney W. Grimes 		(void) fflush(stdout);
1028fae3551SRodney W. Grimes 		c = getc(stdin);
1038fae3551SRodney W. Grimes 		while (c != '\n' && getc(stdin) != '\n')
1048fae3551SRodney W. Grimes 			if (feof(stdin))
1058fae3551SRodney W. Grimes 				return (0);
1068fae3551SRodney W. Grimes 	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
1078fae3551SRodney W. Grimes 	printf("\n");
1088fae3551SRodney W. Grimes 	if (c == 'y' || c == 'Y')
1098fae3551SRodney W. Grimes 		return (1);
1108fae3551SRodney W. Grimes 	return (0);
1118fae3551SRodney W. Grimes }
1128fae3551SRodney W. Grimes 
1138fae3551SRodney W. Grimes /*
1148fae3551SRodney W. Grimes  * Malloc buffers and set up cache.
1158fae3551SRodney W. Grimes  */
11631f4ab50SBruce Evans void
1178fae3551SRodney W. Grimes bufinit()
1188fae3551SRodney W. Grimes {
1198fae3551SRodney W. Grimes 	register struct bufarea *bp;
1208fae3551SRodney W. Grimes 	long bufcnt, i;
1218fae3551SRodney W. Grimes 	char *bufp;
1228fae3551SRodney W. Grimes 
1238fae3551SRodney W. Grimes 	pbp = pdirbp = (struct bufarea *)0;
1248fae3551SRodney W. Grimes 	bufp = malloc((unsigned int)sblock.fs_bsize);
1258fae3551SRodney W. Grimes 	if (bufp == 0)
126780a5c1eSPeter Wemm 		errx(EEXIT, "cannot allocate buffer pool");
1278fae3551SRodney W. Grimes 	cgblk.b_un.b_buf = bufp;
1288fae3551SRodney W. Grimes 	initbarea(&cgblk);
1298fae3551SRodney W. Grimes 	bufhead.b_next = bufhead.b_prev = &bufhead;
1308fae3551SRodney W. Grimes 	bufcnt = MAXBUFSPACE / sblock.fs_bsize;
1318fae3551SRodney W. Grimes 	if (bufcnt < MINBUFS)
1328fae3551SRodney W. Grimes 		bufcnt = MINBUFS;
1338fae3551SRodney W. Grimes 	for (i = 0; i < bufcnt; i++) {
1348fae3551SRodney W. Grimes 		bp = (struct bufarea *)malloc(sizeof(struct bufarea));
1358fae3551SRodney W. Grimes 		bufp = malloc((unsigned int)sblock.fs_bsize);
1368fae3551SRodney W. Grimes 		if (bp == NULL || bufp == NULL) {
1378fae3551SRodney W. Grimes 			if (i >= MINBUFS)
1388fae3551SRodney W. Grimes 				break;
139780a5c1eSPeter Wemm 			errx(EEXIT, "cannot allocate buffer pool");
1408fae3551SRodney W. Grimes 		}
1418fae3551SRodney W. Grimes 		bp->b_un.b_buf = bufp;
1428fae3551SRodney W. Grimes 		bp->b_prev = &bufhead;
1438fae3551SRodney W. Grimes 		bp->b_next = bufhead.b_next;
1448fae3551SRodney W. Grimes 		bufhead.b_next->b_prev = bp;
1458fae3551SRodney W. Grimes 		bufhead.b_next = bp;
1468fae3551SRodney W. Grimes 		initbarea(bp);
1478fae3551SRodney W. Grimes 	}
1488fae3551SRodney W. Grimes 	bufhead.b_size = i;	/* save number of buffers */
1498fae3551SRodney W. Grimes }
1508fae3551SRodney W. Grimes 
1518fae3551SRodney W. Grimes /*
1528fae3551SRodney W. Grimes  * Manage a cache of directory blocks.
1538fae3551SRodney W. Grimes  */
1548fae3551SRodney W. Grimes struct bufarea *
1558fae3551SRodney W. Grimes getdatablk(blkno, size)
156780a5c1eSPeter Wemm 	ufs_daddr_t blkno;
1578fae3551SRodney W. Grimes 	long size;
1588fae3551SRodney W. Grimes {
1598fae3551SRodney W. Grimes 	register struct bufarea *bp;
1608fae3551SRodney W. Grimes 
1618fae3551SRodney W. Grimes 	for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
1628fae3551SRodney W. Grimes 		if (bp->b_bno == fsbtodb(&sblock, blkno))
1638fae3551SRodney W. Grimes 			goto foundit;
1648fae3551SRodney W. Grimes 	for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
1658fae3551SRodney W. Grimes 		if ((bp->b_flags & B_INUSE) == 0)
1668fae3551SRodney W. Grimes 			break;
1678fae3551SRodney W. Grimes 	if (bp == &bufhead)
168780a5c1eSPeter Wemm 		errx(EEXIT, "deadlocked buffer pool");
1698fae3551SRodney W. Grimes 	getblk(bp, blkno, size);
1708fae3551SRodney W. Grimes 	/* fall through */
1718fae3551SRodney W. Grimes foundit:
1728fae3551SRodney W. Grimes 	totalreads++;
1738fae3551SRodney W. Grimes 	bp->b_prev->b_next = bp->b_next;
1748fae3551SRodney W. Grimes 	bp->b_next->b_prev = bp->b_prev;
1758fae3551SRodney W. Grimes 	bp->b_prev = &bufhead;
1768fae3551SRodney W. Grimes 	bp->b_next = bufhead.b_next;
1778fae3551SRodney W. Grimes 	bufhead.b_next->b_prev = bp;
1788fae3551SRodney W. Grimes 	bufhead.b_next = bp;
1798fae3551SRodney W. Grimes 	bp->b_flags |= B_INUSE;
1808fae3551SRodney W. Grimes 	return (bp);
1818fae3551SRodney W. Grimes }
1828fae3551SRodney W. Grimes 
1838fae3551SRodney W. Grimes void
1848fae3551SRodney W. Grimes getblk(bp, blk, size)
1858fae3551SRodney W. Grimes 	register struct bufarea *bp;
186780a5c1eSPeter Wemm 	ufs_daddr_t blk;
1878fae3551SRodney W. Grimes 	long size;
1888fae3551SRodney W. Grimes {
189780a5c1eSPeter Wemm 	ufs_daddr_t dblk;
1908fae3551SRodney W. Grimes 
1918fae3551SRodney W. Grimes 	dblk = fsbtodb(&sblock, blk);
1928fae3551SRodney W. Grimes 	if (bp->b_bno != dblk) {
1938fae3551SRodney W. Grimes 		flush(fswritefd, bp);
1948fae3551SRodney W. Grimes 		diskreads++;
1958fae3551SRodney W. Grimes 		bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
1968fae3551SRodney W. Grimes 		bp->b_bno = dblk;
1978fae3551SRodney W. Grimes 		bp->b_size = size;
1988fae3551SRodney W. Grimes 	}
1998fae3551SRodney W. Grimes }
2008fae3551SRodney W. Grimes 
20131f4ab50SBruce Evans void
2028fae3551SRodney W. Grimes flush(fd, bp)
2038fae3551SRodney W. Grimes 	int fd;
2048fae3551SRodney W. Grimes 	register struct bufarea *bp;
2058fae3551SRodney W. Grimes {
2068fae3551SRodney W. Grimes 	register int i, j;
2078fae3551SRodney W. Grimes 
2088fae3551SRodney W. Grimes 	if (!bp->b_dirty)
2098fae3551SRodney W. Grimes 		return;
2108fae3551SRodney W. Grimes 	if (bp->b_errs != 0)
2118fae3551SRodney W. Grimes 		pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
2128fae3551SRodney W. Grimes 		    (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
2138fae3551SRodney W. Grimes 		    bp->b_bno);
2148fae3551SRodney W. Grimes 	bp->b_dirty = 0;
2158fae3551SRodney W. Grimes 	bp->b_errs = 0;
2168fae3551SRodney W. Grimes 	bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
2178fae3551SRodney W. Grimes 	if (bp != &sblk)
2188fae3551SRodney W. Grimes 		return;
2198fae3551SRodney W. Grimes 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
2208fae3551SRodney W. Grimes 		bwrite(fswritefd, (char *)sblock.fs_csp[j],
2218fae3551SRodney W. Grimes 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
2228fae3551SRodney W. Grimes 		    sblock.fs_cssize - i < sblock.fs_bsize ?
2238fae3551SRodney W. Grimes 		    sblock.fs_cssize - i : sblock.fs_bsize);
2248fae3551SRodney W. Grimes 	}
2258fae3551SRodney W. Grimes }
2268fae3551SRodney W. Grimes 
227780a5c1eSPeter Wemm static void
2288fae3551SRodney W. Grimes rwerror(mesg, blk)
2298fae3551SRodney W. Grimes 	char *mesg;
230780a5c1eSPeter Wemm 	ufs_daddr_t blk;
2318fae3551SRodney W. Grimes {
2328fae3551SRodney W. Grimes 
2338fae3551SRodney W. Grimes 	if (preen == 0)
2348fae3551SRodney W. Grimes 		printf("\n");
2358fae3551SRodney W. Grimes 	pfatal("CANNOT %s: BLK %ld", mesg, blk);
2368fae3551SRodney W. Grimes 	if (reply("CONTINUE") == 0)
237780a5c1eSPeter Wemm 		exit(EEXIT);
2388fae3551SRodney W. Grimes }
2398fae3551SRodney W. Grimes 
24031f4ab50SBruce Evans void
241780a5c1eSPeter Wemm ckfini(markclean)
242780a5c1eSPeter Wemm 	int markclean;
2438fae3551SRodney W. Grimes {
2448fae3551SRodney W. Grimes 	register struct bufarea *bp, *nbp;
245780a5c1eSPeter Wemm 	int ofsmodified, cnt = 0;
2468fae3551SRodney W. Grimes 
2478fae3551SRodney W. Grimes 	if (fswritefd < 0) {
2488fae3551SRodney W. Grimes 		(void)close(fsreadfd);
2498fae3551SRodney W. Grimes 		return;
2508fae3551SRodney W. Grimes 	}
2518fae3551SRodney W. Grimes 	flush(fswritefd, &sblk);
2528fae3551SRodney W. Grimes 	if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
2538fae3551SRodney W. Grimes 	    !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
2548fae3551SRodney W. Grimes 		sblk.b_bno = SBOFF / dev_bsize;
2558fae3551SRodney W. Grimes 		sbdirty();
2568fae3551SRodney W. Grimes 		flush(fswritefd, &sblk);
2578fae3551SRodney W. Grimes 	}
2588fae3551SRodney W. Grimes 	flush(fswritefd, &cgblk);
2598fae3551SRodney W. Grimes 	free(cgblk.b_un.b_buf);
2608fae3551SRodney W. Grimes 	for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
2618fae3551SRodney W. Grimes 		cnt++;
2628fae3551SRodney W. Grimes 		flush(fswritefd, bp);
2638fae3551SRodney W. Grimes 		nbp = bp->b_prev;
2648fae3551SRodney W. Grimes 		free(bp->b_un.b_buf);
2658fae3551SRodney W. Grimes 		free((char *)bp);
2668fae3551SRodney W. Grimes 	}
2678fae3551SRodney W. Grimes 	if (bufhead.b_size != cnt)
268780a5c1eSPeter Wemm 		errx(EEXIT, "Panic: lost %d buffers", bufhead.b_size - cnt);
2698fae3551SRodney W. Grimes 	pbp = pdirbp = (struct bufarea *)0;
270780a5c1eSPeter Wemm 	if (markclean && sblock.fs_clean == 0) {
271780a5c1eSPeter Wemm 		sblock.fs_clean = 1;
272780a5c1eSPeter Wemm 		sbdirty();
273780a5c1eSPeter Wemm 		ofsmodified = fsmodified;
274780a5c1eSPeter Wemm 		flush(fswritefd, &sblk);
275780a5c1eSPeter Wemm 		fsmodified = ofsmodified;
276780a5c1eSPeter Wemm 		if (!preen)
277780a5c1eSPeter Wemm 			printf("\n***** FILE SYSTEM MARKED CLEAN *****\n");
278780a5c1eSPeter Wemm 	}
2798fae3551SRodney W. Grimes 	if (debug)
2808fae3551SRodney W. Grimes 		printf("cache missed %ld of %ld (%d%%)\n", diskreads,
2818fae3551SRodney W. Grimes 		    totalreads, (int)(diskreads * 100 / totalreads));
2828fae3551SRodney W. Grimes 	(void)close(fsreadfd);
2838fae3551SRodney W. Grimes 	(void)close(fswritefd);
2848fae3551SRodney W. Grimes }
2858fae3551SRodney W. Grimes 
28631f4ab50SBruce Evans int
2878fae3551SRodney W. Grimes bread(fd, buf, blk, size)
2888fae3551SRodney W. Grimes 	int fd;
2898fae3551SRodney W. Grimes 	char *buf;
290780a5c1eSPeter Wemm 	ufs_daddr_t blk;
2918fae3551SRodney W. Grimes 	long size;
2928fae3551SRodney W. Grimes {
2938fae3551SRodney W. Grimes 	char *cp;
2948fae3551SRodney W. Grimes 	int i, errs;
2958fae3551SRodney W. Grimes 	off_t offset;
2968fae3551SRodney W. Grimes 
2978fae3551SRodney W. Grimes 	offset = blk;
2988fae3551SRodney W. Grimes 	offset *= dev_bsize;
2998fae3551SRodney W. Grimes 	if (lseek(fd, offset, 0) < 0)
3008fae3551SRodney W. Grimes 		rwerror("SEEK", blk);
3018fae3551SRodney W. Grimes 	else if (read(fd, buf, (int)size) == size)
3028fae3551SRodney W. Grimes 		return (0);
3038fae3551SRodney W. Grimes 	rwerror("READ", blk);
3048fae3551SRodney W. Grimes 	if (lseek(fd, offset, 0) < 0)
3058fae3551SRodney W. Grimes 		rwerror("SEEK", blk);
3068fae3551SRodney W. Grimes 	errs = 0;
307780a5c1eSPeter Wemm 	memset(buf, 0, (size_t)size);
3088fae3551SRodney W. Grimes 	printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
3098fae3551SRodney W. Grimes 	for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
3108fae3551SRodney W. Grimes 		if (read(fd, cp, (int)secsize) != secsize) {
3118fae3551SRodney W. Grimes 			(void)lseek(fd, offset + i + secsize, 0);
3128fae3551SRodney W. Grimes 			if (secsize != dev_bsize && dev_bsize != 1)
3138fae3551SRodney W. Grimes 				printf(" %ld (%ld),",
3148fae3551SRodney W. Grimes 				    (blk * dev_bsize + i) / secsize,
3158fae3551SRodney W. Grimes 				    blk + i / dev_bsize);
3168fae3551SRodney W. Grimes 			else
3178fae3551SRodney W. Grimes 				printf(" %ld,", blk + i / dev_bsize);
3188fae3551SRodney W. Grimes 			errs++;
3198fae3551SRodney W. Grimes 		}
3208fae3551SRodney W. Grimes 	}
3218fae3551SRodney W. Grimes 	printf("\n");
3228fae3551SRodney W. Grimes 	return (errs);
3238fae3551SRodney W. Grimes }
3248fae3551SRodney W. Grimes 
32531f4ab50SBruce Evans void
3268fae3551SRodney W. Grimes bwrite(fd, buf, blk, size)
3278fae3551SRodney W. Grimes 	int fd;
3288fae3551SRodney W. Grimes 	char *buf;
329780a5c1eSPeter Wemm 	ufs_daddr_t blk;
3308fae3551SRodney W. Grimes 	long size;
3318fae3551SRodney W. Grimes {
3328fae3551SRodney W. Grimes 	int i;
3338fae3551SRodney W. Grimes 	char *cp;
3348fae3551SRodney W. Grimes 	off_t offset;
3358fae3551SRodney W. Grimes 
3368fae3551SRodney W. Grimes 	if (fd < 0)
3378fae3551SRodney W. Grimes 		return;
3388fae3551SRodney W. Grimes 	offset = blk;
3398fae3551SRodney W. Grimes 	offset *= dev_bsize;
3408fae3551SRodney W. Grimes 	if (lseek(fd, offset, 0) < 0)
3418fae3551SRodney W. Grimes 		rwerror("SEEK", blk);
3428fae3551SRodney W. Grimes 	else if (write(fd, buf, (int)size) == size) {
3438fae3551SRodney W. Grimes 		fsmodified = 1;
3448fae3551SRodney W. Grimes 		return;
3458fae3551SRodney W. Grimes 	}
3468fae3551SRodney W. Grimes 	rwerror("WRITE", blk);
3478fae3551SRodney W. Grimes 	if (lseek(fd, offset, 0) < 0)
3488fae3551SRodney W. Grimes 		rwerror("SEEK", blk);
3498fae3551SRodney W. Grimes 	printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
3508fae3551SRodney W. Grimes 	for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
3518fae3551SRodney W. Grimes 		if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
3528fae3551SRodney W. Grimes 			(void)lseek(fd, offset + i + dev_bsize, 0);
3538fae3551SRodney W. Grimes 			printf(" %ld,", blk + i / dev_bsize);
3548fae3551SRodney W. Grimes 		}
3558fae3551SRodney W. Grimes 	printf("\n");
3568fae3551SRodney W. Grimes 	return;
3578fae3551SRodney W. Grimes }
3588fae3551SRodney W. Grimes 
3598fae3551SRodney W. Grimes /*
3608fae3551SRodney W. Grimes  * allocate a data block with the specified number of fragments
3618fae3551SRodney W. Grimes  */
362780a5c1eSPeter Wemm ufs_daddr_t
3638fae3551SRodney W. Grimes allocblk(frags)
3648fae3551SRodney W. Grimes 	long frags;
3658fae3551SRodney W. Grimes {
3668fae3551SRodney W. Grimes 	register int i, j, k;
3678fae3551SRodney W. Grimes 
3688fae3551SRodney W. Grimes 	if (frags <= 0 || frags > sblock.fs_frag)
3698fae3551SRodney W. Grimes 		return (0);
3708fae3551SRodney W. Grimes 	for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
3718fae3551SRodney W. Grimes 		for (j = 0; j <= sblock.fs_frag - frags; j++) {
3728fae3551SRodney W. Grimes 			if (testbmap(i + j))
3738fae3551SRodney W. Grimes 				continue;
3748fae3551SRodney W. Grimes 			for (k = 1; k < frags; k++)
3758fae3551SRodney W. Grimes 				if (testbmap(i + j + k))
3768fae3551SRodney W. Grimes 					break;
3778fae3551SRodney W. Grimes 			if (k < frags) {
3788fae3551SRodney W. Grimes 				j += k;
3798fae3551SRodney W. Grimes 				continue;
3808fae3551SRodney W. Grimes 			}
3818fae3551SRodney W. Grimes 			for (k = 0; k < frags; k++)
3828fae3551SRodney W. Grimes 				setbmap(i + j + k);
3838fae3551SRodney W. Grimes 			n_blks += frags;
3848fae3551SRodney W. Grimes 			return (i + j);
3858fae3551SRodney W. Grimes 		}
3868fae3551SRodney W. Grimes 	}
3878fae3551SRodney W. Grimes 	return (0);
3888fae3551SRodney W. Grimes }
3898fae3551SRodney W. Grimes 
3908fae3551SRodney W. Grimes /*
3918fae3551SRodney W. Grimes  * Free a previously allocated block
3928fae3551SRodney W. Grimes  */
39331f4ab50SBruce Evans void
3948fae3551SRodney W. Grimes freeblk(blkno, frags)
395780a5c1eSPeter Wemm 	ufs_daddr_t blkno;
3968fae3551SRodney W. Grimes 	long frags;
3978fae3551SRodney W. Grimes {
3988fae3551SRodney W. Grimes 	struct inodesc idesc;
3998fae3551SRodney W. Grimes 
4008fae3551SRodney W. Grimes 	idesc.id_blkno = blkno;
4018fae3551SRodney W. Grimes 	idesc.id_numfrags = frags;
4028fae3551SRodney W. Grimes 	(void)pass4check(&idesc);
4038fae3551SRodney W. Grimes }
4048fae3551SRodney W. Grimes 
4058fae3551SRodney W. Grimes /*
4068fae3551SRodney W. Grimes  * Find a pathname
4078fae3551SRodney W. Grimes  */
40831f4ab50SBruce Evans void
4098fae3551SRodney W. Grimes getpathname(namebuf, curdir, ino)
4108fae3551SRodney W. Grimes 	char *namebuf;
4118fae3551SRodney W. Grimes 	ino_t curdir, ino;
4128fae3551SRodney W. Grimes {
4138fae3551SRodney W. Grimes 	int len;
4148fae3551SRodney W. Grimes 	register char *cp;
4158fae3551SRodney W. Grimes 	struct inodesc idesc;
4168fae3551SRodney W. Grimes 	static int busy = 0;
4178fae3551SRodney W. Grimes 
4188fae3551SRodney W. Grimes 	if (curdir == ino && ino == ROOTINO) {
4198fae3551SRodney W. Grimes 		(void)strcpy(namebuf, "/");
4208fae3551SRodney W. Grimes 		return;
4218fae3551SRodney W. Grimes 	}
4228fae3551SRodney W. Grimes 	if (busy ||
4238fae3551SRodney W. Grimes 	    (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
4248fae3551SRodney W. Grimes 		(void)strcpy(namebuf, "?");
4258fae3551SRodney W. Grimes 		return;
4268fae3551SRodney W. Grimes 	}
4278fae3551SRodney W. Grimes 	busy = 1;
428780a5c1eSPeter Wemm 	memset(&idesc, 0, sizeof(struct inodesc));
4298fae3551SRodney W. Grimes 	idesc.id_type = DATA;
4308fae3551SRodney W. Grimes 	idesc.id_fix = IGNORE;
4318fae3551SRodney W. Grimes 	cp = &namebuf[MAXPATHLEN - 1];
4328fae3551SRodney W. Grimes 	*cp = '\0';
4338fae3551SRodney W. Grimes 	if (curdir != ino) {
4348fae3551SRodney W. Grimes 		idesc.id_parent = curdir;
4358fae3551SRodney W. Grimes 		goto namelookup;
4368fae3551SRodney W. Grimes 	}
4378fae3551SRodney W. Grimes 	while (ino != ROOTINO) {
4388fae3551SRodney W. Grimes 		idesc.id_number = ino;
4398fae3551SRodney W. Grimes 		idesc.id_func = findino;
4408fae3551SRodney W. Grimes 		idesc.id_name = "..";
4418fae3551SRodney W. Grimes 		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
4428fae3551SRodney W. Grimes 			break;
4438fae3551SRodney W. Grimes 	namelookup:
4448fae3551SRodney W. Grimes 		idesc.id_number = idesc.id_parent;
4458fae3551SRodney W. Grimes 		idesc.id_parent = ino;
4468fae3551SRodney W. Grimes 		idesc.id_func = findname;
4478fae3551SRodney W. Grimes 		idesc.id_name = namebuf;
4488fae3551SRodney W. Grimes 		if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
4498fae3551SRodney W. Grimes 			break;
4508fae3551SRodney W. Grimes 		len = strlen(namebuf);
4518fae3551SRodney W. Grimes 		cp -= len;
452780a5c1eSPeter Wemm 		memmove(cp, namebuf, (size_t)len);
4538fae3551SRodney W. Grimes 		*--cp = '/';
4548fae3551SRodney W. Grimes 		if (cp < &namebuf[MAXNAMLEN])
4558fae3551SRodney W. Grimes 			break;
4568fae3551SRodney W. Grimes 		ino = idesc.id_number;
4578fae3551SRodney W. Grimes 	}
4588fae3551SRodney W. Grimes 	busy = 0;
4598fae3551SRodney W. Grimes 	if (ino != ROOTINO)
4608fae3551SRodney W. Grimes 		*--cp = '?';
461780a5c1eSPeter Wemm 	memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
4628fae3551SRodney W. Grimes }
4638fae3551SRodney W. Grimes 
4648fae3551SRodney W. Grimes void
465780a5c1eSPeter Wemm catch(sig)
466780a5c1eSPeter Wemm 	int sig;
4678fae3551SRodney W. Grimes {
4688fae3551SRodney W. Grimes 	if (!doinglevel2)
469780a5c1eSPeter Wemm 		ckfini(0);
4708fae3551SRodney W. Grimes 	exit(12);
4718fae3551SRodney W. Grimes }
4728fae3551SRodney W. Grimes 
4738fae3551SRodney W. Grimes /*
4748fae3551SRodney W. Grimes  * When preening, allow a single quit to signal
4758fae3551SRodney W. Grimes  * a special exit after filesystem checks complete
4768fae3551SRodney W. Grimes  * so that reboot sequence may be interrupted.
4778fae3551SRodney W. Grimes  */
4788fae3551SRodney W. Grimes void
479780a5c1eSPeter Wemm catchquit(sig)
480780a5c1eSPeter Wemm 	int sig;
4818fae3551SRodney W. Grimes {
4828fae3551SRodney W. Grimes 	printf("returning to single-user after filesystem check\n");
4838fae3551SRodney W. Grimes 	returntosingle = 1;
4848fae3551SRodney W. Grimes 	(void)signal(SIGQUIT, SIG_DFL);
4858fae3551SRodney W. Grimes }
4868fae3551SRodney W. Grimes 
4878fae3551SRodney W. Grimes /*
4888fae3551SRodney W. Grimes  * Ignore a single quit signal; wait and flush just in case.
4898fae3551SRodney W. Grimes  * Used by child processes in preen.
4908fae3551SRodney W. Grimes  */
4918fae3551SRodney W. Grimes void
492780a5c1eSPeter Wemm voidquit(sig)
493780a5c1eSPeter Wemm 	int sig;
4948fae3551SRodney W. Grimes {
4958fae3551SRodney W. Grimes 
4968fae3551SRodney W. Grimes 	sleep(1);
4978fae3551SRodney W. Grimes 	(void)signal(SIGQUIT, SIG_IGN);
4988fae3551SRodney W. Grimes 	(void)signal(SIGQUIT, SIG_DFL);
4998fae3551SRodney W. Grimes }
5008fae3551SRodney W. Grimes 
5018fae3551SRodney W. Grimes /*
5028fae3551SRodney W. Grimes  * determine whether an inode should be fixed.
5038fae3551SRodney W. Grimes  */
50431f4ab50SBruce Evans int
5058fae3551SRodney W. Grimes dofix(idesc, msg)
5068fae3551SRodney W. Grimes 	register struct inodesc *idesc;
5078fae3551SRodney W. Grimes 	char *msg;
5088fae3551SRodney W. Grimes {
5098fae3551SRodney W. Grimes 
5108fae3551SRodney W. Grimes 	switch (idesc->id_fix) {
5118fae3551SRodney W. Grimes 
5128fae3551SRodney W. Grimes 	case DONTKNOW:
5138fae3551SRodney W. Grimes 		if (idesc->id_type == DATA)
5148fae3551SRodney W. Grimes 			direrror(idesc->id_number, msg);
5158fae3551SRodney W. Grimes 		else
5168fae3551SRodney W. Grimes 			pwarn(msg);
5178fae3551SRodney W. Grimes 		if (preen) {
5188fae3551SRodney W. Grimes 			printf(" (SALVAGED)\n");
5198fae3551SRodney W. Grimes 			idesc->id_fix = FIX;
5208fae3551SRodney W. Grimes 			return (ALTERED);
5218fae3551SRodney W. Grimes 		}
5228fae3551SRodney W. Grimes 		if (reply("SALVAGE") == 0) {
5238fae3551SRodney W. Grimes 			idesc->id_fix = NOFIX;
5248fae3551SRodney W. Grimes 			return (0);
5258fae3551SRodney W. Grimes 		}
5268fae3551SRodney W. Grimes 		idesc->id_fix = FIX;
5278fae3551SRodney W. Grimes 		return (ALTERED);
5288fae3551SRodney W. Grimes 
5298fae3551SRodney W. Grimes 	case FIX:
5308fae3551SRodney W. Grimes 		return (ALTERED);
5318fae3551SRodney W. Grimes 
5328fae3551SRodney W. Grimes 	case NOFIX:
5338fae3551SRodney W. Grimes 	case IGNORE:
5348fae3551SRodney W. Grimes 		return (0);
5358fae3551SRodney W. Grimes 
5368fae3551SRodney W. Grimes 	default:
537780a5c1eSPeter Wemm 		errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix);
5388fae3551SRodney W. Grimes 	}
5398fae3551SRodney W. Grimes 	/* NOTREACHED */
540780a5c1eSPeter Wemm 	return (0);
5418fae3551SRodney W. Grimes }
5428fae3551SRodney W. Grimes 
543780a5c1eSPeter Wemm #if __STDC__
544780a5c1eSPeter Wemm #include <stdarg.h>
545780a5c1eSPeter Wemm #else
546780a5c1eSPeter Wemm #include <varargs.h>
547780a5c1eSPeter Wemm #endif
5488fae3551SRodney W. Grimes 
5498fae3551SRodney W. Grimes /*
5508fae3551SRodney W. Grimes  * An unexpected inconsistency occured.
5518fae3551SRodney W. Grimes  * Die if preening, otherwise just print message and continue.
5528fae3551SRodney W. Grimes  */
55331f4ab50SBruce Evans void
554780a5c1eSPeter Wemm #if __STDC__
555780a5c1eSPeter Wemm pfatal(const char *fmt, ...)
556780a5c1eSPeter Wemm #else
557780a5c1eSPeter Wemm pfatal(fmt, va_alist)
558780a5c1eSPeter Wemm 	char *fmt;
559780a5c1eSPeter Wemm 	va_dcl
560780a5c1eSPeter Wemm #endif
5618fae3551SRodney W. Grimes {
56231f4ab50SBruce Evans 	va_list ap;
563780a5c1eSPeter Wemm #if __STDC__
564780a5c1eSPeter Wemm 	va_start(ap, fmt);
565780a5c1eSPeter Wemm #else
566780a5c1eSPeter Wemm 	va_start(ap);
567780a5c1eSPeter Wemm #endif
568780a5c1eSPeter Wemm 	if (!preen) {
569780a5c1eSPeter Wemm 		(void)vfprintf(stderr, fmt, ap);
57031f4ab50SBruce Evans 		va_end(ap);
571780a5c1eSPeter Wemm 		return;
572780a5c1eSPeter Wemm 	}
573780a5c1eSPeter Wemm 	(void)fprintf(stderr, "%s: ", cdevname);
574780a5c1eSPeter Wemm 	(void)vfprintf(stderr, fmt, ap);
575780a5c1eSPeter Wemm 	(void)fprintf(stderr,
576780a5c1eSPeter Wemm 	    "\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
577780a5c1eSPeter Wemm 	    cdevname);
578780a5c1eSPeter Wemm 	exit(EEXIT);
5798fae3551SRodney W. Grimes }
5808fae3551SRodney W. Grimes 
5818fae3551SRodney W. Grimes /*
5828fae3551SRodney W. Grimes  * Pwarn just prints a message when not preening,
5838fae3551SRodney W. Grimes  * or a warning (preceded by filename) when preening.
5848fae3551SRodney W. Grimes  */
58531f4ab50SBruce Evans void
586780a5c1eSPeter Wemm #if __STDC__
587780a5c1eSPeter Wemm pwarn(const char *fmt, ...)
588780a5c1eSPeter Wemm #else
589780a5c1eSPeter Wemm pwarn(fmt, va_alist)
590780a5c1eSPeter Wemm 	char *fmt;
591780a5c1eSPeter Wemm 	va_dcl
592780a5c1eSPeter Wemm #endif
5938fae3551SRodney W. Grimes {
59431f4ab50SBruce Evans 	va_list ap;
595780a5c1eSPeter Wemm #if __STDC__
596780a5c1eSPeter Wemm 	va_start(ap, fmt);
597780a5c1eSPeter Wemm #else
598780a5c1eSPeter Wemm 	va_start(ap);
599780a5c1eSPeter Wemm #endif
6008fae3551SRodney W. Grimes 	if (preen)
601780a5c1eSPeter Wemm 		(void)fprintf(stderr, "%s: ", cdevname);
602780a5c1eSPeter Wemm 	(void)vfprintf(stderr, fmt, ap);
60331f4ab50SBruce Evans 	va_end(ap);
6048fae3551SRodney W. Grimes }
6058fae3551SRodney W. Grimes 
6068fae3551SRodney W. Grimes /*
6078fae3551SRodney W. Grimes  * Stub for routines from kernel.
6088fae3551SRodney W. Grimes  */
609eaa86f9dSBruce Evans void
610780a5c1eSPeter Wemm #if __STDC__
61131f4ab50SBruce Evans panic(const char *fmt, ...)
61231f4ab50SBruce Evans #else
61331f4ab50SBruce Evans panic(fmt, va_alist)
61431f4ab50SBruce Evans 	char *fmt;
615780a5c1eSPeter Wemm 	va_dcl
61631f4ab50SBruce Evans #endif
6178fae3551SRodney W. Grimes {
618780a5c1eSPeter Wemm 	va_list ap;
619780a5c1eSPeter Wemm #if __STDC__
620780a5c1eSPeter Wemm 	va_start(ap, fmt);
621780a5c1eSPeter Wemm #else
622780a5c1eSPeter Wemm 	va_start(ap);
6238fae3551SRodney W. Grimes #endif
624780a5c1eSPeter Wemm 	pfatal("INTERNAL INCONSISTENCY:");
625780a5c1eSPeter Wemm 	(void)vfprintf(stderr, fmt, ap);
626780a5c1eSPeter Wemm 	va_end(ap);
627780a5c1eSPeter Wemm 	exit(EEXIT);
628780a5c1eSPeter Wemm }
629