166864Sadrian/*
266864Sadrian * Copyright (c) 1980, 1986, 1993
366864Sadrian *	The Regents of the University of California.  All rights reserved.
466864Sadrian *
566864Sadrian * Redistribution and use in source and binary forms, with or without
666864Sadrian * modification, are permitted provided that the following conditions
766864Sadrian * are met:
866864Sadrian * 1. Redistributions of source code must retain the above copyright
966864Sadrian *    notice, this list of conditions and the following disclaimer.
1066864Sadrian * 2. Redistributions in binary form must reproduce the above copyright
1166864Sadrian *    notice, this list of conditions and the following disclaimer in the
1266864Sadrian *    documentation and/or other materials provided with the distribution.
1366864Sadrian * 4. Neither the name of the University nor the names of its contributors
1466864Sadrian *    may be used to endorse or promote products derived from this software
1566864Sadrian *    without specific prior written permission.
1666864Sadrian *
1766864Sadrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1866864Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1966864Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2066864Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2166864Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2266864Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2366864Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2466864Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2566864Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2666864Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2766864Sadrian * SUCH DAMAGE.
2866864Sadrian */
2966864Sadrian
30114589Sobrien#if 0
3166864Sadrian#ifndef lint
3266864Sadrianstatic const char sccsid[] = "@(#)utilities.c	8.6 (Berkeley) 5/19/95";
33114589Sobrien#endif /* not lint */
3466864Sadrian#endif
35114589Sobrien#include <sys/cdefs.h>
36114589Sobrien__FBSDID("$FreeBSD$");
3766864Sadrian
3866864Sadrian#include <sys/param.h>
39107671Siedowse#include <sys/time.h>
4066864Sadrian#include <sys/types.h>
4186514Siedowse#include <sys/sysctl.h>
42221233Sdes#include <sys/disk.h>
4398542Smckusick#include <sys/disklabel.h>
44221233Sdes#include <sys/ioctl.h>
4566864Sadrian#include <sys/stat.h>
4666864Sadrian
4766864Sadrian#include <ufs/ufs/dinode.h>
4866864Sadrian#include <ufs/ufs/dir.h>
4966864Sadrian#include <ufs/ffs/fs.h>
5066864Sadrian
5166864Sadrian#include <err.h>
5266864Sadrian#include <errno.h>
5366864Sadrian#include <string.h>
5466864Sadrian#include <ctype.h>
5566864Sadrian#include <fstab.h>
56101037Smux#include <stdint.h>
5766864Sadrian#include <stdio.h>
5866864Sadrian#include <stdlib.h>
59249788Smckusick#include <time.h>
6066864Sadrian#include <unistd.h>
6166864Sadrian
6266864Sadrian#include "fsck.h"
6366864Sadrian
64107671Siedowsestatic void slowio_start(void);
65107671Siedowsestatic void slowio_end(void);
66249788Smckusickstatic void printIOstats(void);
67107671Siedowse
68249788Smckusickstatic long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */
69249788Smckusickstatic struct timespec startpass, finishpass;
70107671Siedowsestruct timeval slowio_starttime;
71107671Siedowseint slowio_delay_usec = 10000;	/* Initial IO delay for background fsck */
72107671Siedowseint slowio_pollcnt;
73249788Smckusickstatic struct bufarea cgblk;	/* backup buffer for cylinder group blocks */
74248628Smckusickstatic TAILQ_HEAD(buflist, bufarea) bufhead;	/* head of buffer cache list */
75248628Smckusickstatic int numbufs;				/* size of buffer cache */
76249788Smckusickstatic char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
7766864Sadrian
7866864Sadrianint
7998542Smckusickftypeok(union dinode *dp)
8066864Sadrian{
8198542Smckusick	switch (DIP(dp, di_mode) & IFMT) {
8266864Sadrian
8366864Sadrian	case IFDIR:
8466864Sadrian	case IFREG:
8566864Sadrian	case IFBLK:
8666864Sadrian	case IFCHR:
8766864Sadrian	case IFLNK:
8866864Sadrian	case IFSOCK:
8966864Sadrian	case IFIFO:
9066864Sadrian		return (1);
9166864Sadrian
9266864Sadrian	default:
9366864Sadrian		if (debug)
9498542Smckusick			printf("bad file type 0%o\n", DIP(dp, di_mode));
9566864Sadrian		return (0);
9666864Sadrian	}
9766864Sadrian}
9866864Sadrian
9966864Sadrianint
100100935Sphkreply(const char *question)
10166864Sadrian{
10266864Sadrian	int persevere;
10366864Sadrian	char c;
10466864Sadrian
10566864Sadrian	if (preen)
10666864Sadrian		pfatal("INTERNAL ERROR: GOT TO reply()");
10766864Sadrian	persevere = !strcmp(question, "CONTINUE");
10866864Sadrian	printf("\n");
10974556Smckusick	if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) {
11066864Sadrian		printf("%s? no\n\n", question);
11166864Sadrian		resolved = 0;
11266864Sadrian		return (0);
11366864Sadrian	}
11466864Sadrian	if (yflag || (persevere && nflag)) {
11566864Sadrian		printf("%s? yes\n\n", question);
11666864Sadrian		return (1);
11766864Sadrian	}
11866864Sadrian	do	{
11966864Sadrian		printf("%s? [yn] ", question);
12066864Sadrian		(void) fflush(stdout);
12166864Sadrian		c = getc(stdin);
12266864Sadrian		while (c != '\n' && getc(stdin) != '\n') {
12366864Sadrian			if (feof(stdin)) {
12466864Sadrian				resolved = 0;
12566864Sadrian				return (0);
12666864Sadrian			}
12766864Sadrian		}
12866864Sadrian	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
12966864Sadrian	printf("\n");
13066864Sadrian	if (c == 'y' || c == 'Y')
13166864Sadrian		return (1);
13266864Sadrian	resolved = 0;
13366864Sadrian	return (0);
13466864Sadrian}
13566864Sadrian
13666864Sadrian/*
13766864Sadrian * Look up state information for an inode.
13866864Sadrian */
13966864Sadrianstruct inostat *
14092839Simpinoinfo(ino_t inum)
14166864Sadrian{
14266864Sadrian	static struct inostat unallocated = { USTATE, 0, 0 };
14366864Sadrian	struct inostatlist *ilp;
14466864Sadrian	int iloff;
14566864Sadrian
14666864Sadrian	if (inum > maxino)
14766864Sadrian		errx(EEXIT, "inoinfo: inumber %d out of range", inum);
14866864Sadrian	ilp = &inostathead[inum / sblock.fs_ipg];
14966864Sadrian	iloff = inum % sblock.fs_ipg;
15066864Sadrian	if (iloff >= ilp->il_numalloced)
15166864Sadrian		return (&unallocated);
15266864Sadrian	return (&ilp->il_stat[iloff]);
15366864Sadrian}
15466864Sadrian
15566864Sadrian/*
15666864Sadrian * Malloc buffers and set up cache.
15766864Sadrian */
15866864Sadrianvoid
15992839Simpbufinit(void)
16066864Sadrian{
16192806Sobrien	struct bufarea *bp;
16266864Sadrian	long bufcnt, i;
16366864Sadrian	char *bufp;
16466864Sadrian
16566864Sadrian	pbp = pdirbp = (struct bufarea *)0;
166249788Smckusick	bufp = Malloc((unsigned int)sblock.fs_bsize);
16766864Sadrian	if (bufp == 0)
16866864Sadrian		errx(EEXIT, "cannot allocate buffer pool");
16966864Sadrian	cgblk.b_un.b_buf = bufp;
170249788Smckusick	initbarea(&cgblk, BT_CYLGRP);
171248628Smckusick	TAILQ_INIT(&bufhead);
172248628Smckusick	bufcnt = MAXBUFS;
17366864Sadrian	if (bufcnt < MINBUFS)
17466864Sadrian		bufcnt = MINBUFS;
17566864Sadrian	for (i = 0; i < bufcnt; i++) {
176249788Smckusick		bp = (struct bufarea *)Malloc(sizeof(struct bufarea));
177249788Smckusick		bufp = Malloc((unsigned int)sblock.fs_bsize);
17866864Sadrian		if (bp == NULL || bufp == NULL) {
17966864Sadrian			if (i >= MINBUFS)
18066864Sadrian				break;
18166864Sadrian			errx(EEXIT, "cannot allocate buffer pool");
18266864Sadrian		}
18366864Sadrian		bp->b_un.b_buf = bufp;
184248628Smckusick		TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
185249788Smckusick		initbarea(bp, BT_UNKNOWN);
18666864Sadrian	}
187248628Smckusick	numbufs = i;	/* save number of buffers */
188249788Smckusick	for (i = 0; i < BT_NUMBUFTYPES; i++) {
189249788Smckusick		readtime[i].tv_sec = totalreadtime[i].tv_sec = 0;
190249788Smckusick		readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0;
191249788Smckusick		readcnt[i] = totalreadcnt[i] = 0;
192249788Smckusick	}
19366864Sadrian}
19466864Sadrian
19566864Sadrian/*
196249788Smckusick * Manage cylinder group buffers.
197249788Smckusick */
198249788Smckusickstatic struct bufarea *cgbufs;	/* header for cylinder group cache */
199249788Smckusickstatic int flushtries;		/* number of tries to reclaim memory */
200249788Smckusick
201249788Smckusickstruct bufarea *
202249788Smckusickcgget(int cg)
203249788Smckusick{
204249788Smckusick	struct bufarea *cgbp;
205249788Smckusick	struct cg *cgp;
206249788Smckusick
207249788Smckusick	if (cgbufs == NULL) {
208263630Smckusick		cgbufs = calloc(sblock.fs_ncg, sizeof(struct bufarea));
209249788Smckusick		if (cgbufs == NULL)
210249788Smckusick			errx(EEXIT, "cannot allocate cylinder group buffers");
211249788Smckusick	}
212249788Smckusick	cgbp = &cgbufs[cg];
213249788Smckusick	if (cgbp->b_un.b_cg != NULL)
214249788Smckusick		return (cgbp);
215249788Smckusick	cgp = NULL;
216249788Smckusick	if (flushtries == 0)
217249788Smckusick		cgp = malloc((unsigned int)sblock.fs_cgsize);
218249788Smckusick	if (cgp == NULL) {
219249788Smckusick		getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
220249788Smckusick		return (&cgblk);
221249788Smckusick	}
222249788Smckusick	cgbp->b_un.b_cg = cgp;
223249788Smckusick	initbarea(cgbp, BT_CYLGRP);
224249788Smckusick	getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize);
225249788Smckusick	return (cgbp);
226249788Smckusick}
227249788Smckusick
228249788Smckusick/*
229249788Smckusick * Attempt to flush a cylinder group cache entry.
230249788Smckusick * Return whether the flush was successful.
231249788Smckusick */
232249788Smckusickint
233249788Smckusickflushentry(void)
234249788Smckusick{
235249788Smckusick	struct bufarea *cgbp;
236249788Smckusick
237263630Smckusick	if (flushtries == sblock.fs_ncg || cgbufs == NULL)
238263630Smckusick		return (0);
239249788Smckusick	cgbp = &cgbufs[flushtries++];
240249788Smckusick	if (cgbp->b_un.b_cg == NULL)
241249788Smckusick		return (0);
242249788Smckusick	flush(fswritefd, cgbp);
243249788Smckusick	free(cgbp->b_un.b_buf);
244249788Smckusick	cgbp->b_un.b_buf = NULL;
245249788Smckusick	return (1);
246249788Smckusick}
247249788Smckusick
248249788Smckusick/*
24966864Sadrian * Manage a cache of directory blocks.
25066864Sadrian */
25166864Sadrianstruct bufarea *
252249788Smckusickgetdatablk(ufs2_daddr_t blkno, long size, int type)
25366864Sadrian{
25492806Sobrien	struct bufarea *bp;
25566864Sadrian
256248628Smckusick	TAILQ_FOREACH(bp, &bufhead, b_list)
25766864Sadrian		if (bp->b_bno == fsbtodb(&sblock, blkno))
25866864Sadrian			goto foundit;
259248628Smckusick	TAILQ_FOREACH_REVERSE(bp, &bufhead, buflist, b_list)
26066864Sadrian		if ((bp->b_flags & B_INUSE) == 0)
26166864Sadrian			break;
262248628Smckusick	if (bp == NULL)
26366864Sadrian		errx(EEXIT, "deadlocked buffer pool");
264249788Smckusick	bp->b_type = type;
26566864Sadrian	getblk(bp, blkno, size);
26666864Sadrian	/* fall through */
26766864Sadrianfoundit:
268249788Smckusick	if (debug && bp->b_type != type)
269249788Smckusick		printf("Buffer type changed from %s to %s\n",
270249788Smckusick		    buftype[bp->b_type], buftype[type]);
271248628Smckusick	TAILQ_REMOVE(&bufhead, bp, b_list);
272248628Smckusick	TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
27366864Sadrian	bp->b_flags |= B_INUSE;
27466864Sadrian	return (bp);
27566864Sadrian}
27666864Sadrian
277249788Smckusick/*
278249788Smckusick * Timespec operations (from <sys/time.h>).
279249788Smckusick */
280249788Smckusick#define	timespecsub(vvp, uvp)						\
281249788Smckusick	do {								\
282249788Smckusick		(vvp)->tv_sec -= (uvp)->tv_sec;				\
283249788Smckusick		(vvp)->tv_nsec -= (uvp)->tv_nsec;			\
284249788Smckusick		if ((vvp)->tv_nsec < 0) {				\
285249788Smckusick			(vvp)->tv_sec--;				\
286249788Smckusick			(vvp)->tv_nsec += 1000000000;			\
287249788Smckusick		}							\
288249788Smckusick	} while (0)
289249788Smckusick#define	timespecadd(vvp, uvp)						\
290249788Smckusick	do {								\
291249788Smckusick		(vvp)->tv_sec += (uvp)->tv_sec;				\
292249788Smckusick		(vvp)->tv_nsec += (uvp)->tv_nsec;			\
293249788Smckusick		if ((vvp)->tv_nsec >= 1000000000) {			\
294249788Smckusick			(vvp)->tv_sec++;				\
295249788Smckusick			(vvp)->tv_nsec -= 1000000000;			\
296249788Smckusick		}							\
297249788Smckusick	} while (0)
298249788Smckusick
29966864Sadrianvoid
30098542Smckusickgetblk(struct bufarea *bp, ufs2_daddr_t blk, long size)
30166864Sadrian{
30298542Smckusick	ufs2_daddr_t dblk;
303249788Smckusick	struct timespec start, finish;
30466864Sadrian
30566864Sadrian	dblk = fsbtodb(&sblock, blk);
306249788Smckusick	if (bp->b_bno == dblk) {
307249788Smckusick		totalreads++;
308249788Smckusick	} else {
30966864Sadrian		flush(fswritefd, bp);
310249788Smckusick		if (debug) {
311249788Smckusick			readcnt[bp->b_type]++;
312249788Smckusick			clock_gettime(CLOCK_REALTIME_PRECISE, &start);
313249788Smckusick		}
314163845Spjd		bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size);
315249788Smckusick		if (debug) {
316249788Smckusick			clock_gettime(CLOCK_REALTIME_PRECISE, &finish);
317249788Smckusick			timespecsub(&finish, &start);
318249788Smckusick			timespecadd(&readtime[bp->b_type], &finish);
319249788Smckusick		}
32066864Sadrian		bp->b_bno = dblk;
32166864Sadrian		bp->b_size = size;
32266864Sadrian	}
32366864Sadrian}
32466864Sadrian
32566864Sadrianvoid
32692839Simpflush(int fd, struct bufarea *bp)
32766864Sadrian{
32892806Sobrien	int i, j;
32966864Sadrian
33066864Sadrian	if (!bp->b_dirty)
33166864Sadrian		return;
33274556Smckusick	bp->b_dirty = 0;
33374556Smckusick	if (fswritefd < 0) {
33474556Smckusick		pfatal("WRITING IN READ_ONLY MODE.\n");
33574556Smckusick		return;
33674556Smckusick	}
33766864Sadrian	if (bp->b_errs != 0)
338100935Sphk		pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n",
33966864Sadrian		    (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
340100935Sphk		    (long long)bp->b_bno);
34166864Sadrian	bp->b_errs = 0;
342163845Spjd	blwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
34366864Sadrian	if (bp != &sblk)
34466864Sadrian		return;
34566864Sadrian	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
346163845Spjd		blwrite(fswritefd, (char *)sblock.fs_csp + i,
34766864Sadrian		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
34866864Sadrian		    sblock.fs_cssize - i < sblock.fs_bsize ?
34966864Sadrian		    sblock.fs_cssize - i : sblock.fs_bsize);
35066864Sadrian	}
35166864Sadrian}
35266864Sadrian
35374556Smckusickvoid
354100935Sphkrwerror(const char *mesg, ufs2_daddr_t blk)
35566864Sadrian{
35666864Sadrian
35775927Smckusick	if (bkgrdcheck)
35875927Smckusick		exit(EEXIT);
35966864Sadrian	if (preen == 0)
36066864Sadrian		printf("\n");
36186514Siedowse	pfatal("CANNOT %s: %ld", mesg, (long)blk);
36266864Sadrian	if (reply("CONTINUE") == 0)
36366864Sadrian		exit(EEXIT);
36466864Sadrian}
36566864Sadrian
36666864Sadrianvoid
36792839Simpckfini(int markclean)
36866864Sadrian{
36992806Sobrien	struct bufarea *bp, *nbp;
370248628Smckusick	int ofsmodified, cnt;
37166864Sadrian
37274556Smckusick	if (bkgrdflag) {
37374556Smckusick		unlink(snapname);
37474556Smckusick		if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) {
37574556Smckusick			cmd.value = FS_UNCLEAN;
37674556Smckusick			cmd.size = markclean ? -1 : 1;
37774556Smckusick			if (sysctlbyname("vfs.ffs.setflags", 0, 0,
37874556Smckusick			    &cmd, sizeof cmd) == -1)
379118302Sru				rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN);
38074556Smckusick			if (!preen) {
38174556Smckusick				printf("\n***** FILE SYSTEM MARKED %s *****\n",
38274556Smckusick				    markclean ? "CLEAN" : "DIRTY");
38374556Smckusick				if (!markclean)
38474556Smckusick					rerun = 1;
38574556Smckusick			}
38674556Smckusick		} else if (!preen && !markclean) {
38774556Smckusick			printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
38874556Smckusick			rerun = 1;
38974556Smckusick		}
39074556Smckusick	}
391248628Smckusick	if (debug && totalreads > 0)
392248628Smckusick		printf("cache with %d buffers missed %ld of %ld (%d%%)\n",
393249788Smckusick		    numbufs, totaldiskreads, totalreads,
394249788Smckusick		    (int)(totaldiskreads * 100 / totalreads));
39566864Sadrian	if (fswritefd < 0) {
39666864Sadrian		(void)close(fsreadfd);
39766864Sadrian		return;
39866864Sadrian	}
39966864Sadrian	flush(fswritefd, &sblk);
40098542Smckusick	if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC &&
401107294Smckusick	    sblk.b_bno != sblock.fs_sblockloc / dev_bsize &&
40266864Sadrian	    !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
403107294Smckusick		sblk.b_bno = sblock.fs_sblockloc / dev_bsize;
40466864Sadrian		sbdirty();
40566864Sadrian		flush(fswritefd, &sblk);
40666864Sadrian	}
40766864Sadrian	flush(fswritefd, &cgblk);
40866864Sadrian	free(cgblk.b_un.b_buf);
409248628Smckusick	cnt = 0;
410248628Smckusick	TAILQ_FOREACH_REVERSE_SAFE(bp, &bufhead, buflist, b_list, nbp) {
411248628Smckusick		TAILQ_REMOVE(&bufhead, bp, b_list);
41266864Sadrian		cnt++;
41366864Sadrian		flush(fswritefd, bp);
41466864Sadrian		free(bp->b_un.b_buf);
41566864Sadrian		free((char *)bp);
41666864Sadrian	}
417248628Smckusick	if (numbufs != cnt)
418248628Smckusick		errx(EEXIT, "panic: lost %d buffers", numbufs - cnt);
419263630Smckusick	if (cgbufs != NULL) {
420263630Smckusick		for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
421263630Smckusick			if (cgbufs[cnt].b_un.b_cg == NULL)
422263630Smckusick				continue;
423263630Smckusick			flush(fswritefd, &cgbufs[cnt]);
424263630Smckusick			free(cgbufs[cnt].b_un.b_cg);
425263630Smckusick		}
426263630Smckusick		free(cgbufs);
427249788Smckusick	}
42866864Sadrian	pbp = pdirbp = (struct bufarea *)0;
42974556Smckusick	if (cursnapshot == 0 && sblock.fs_clean != markclean) {
430105436Smckusick		if ((sblock.fs_clean = markclean) != 0) {
43175557Smckusick			sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK);
432105436Smckusick			sblock.fs_pendingblocks = 0;
433105436Smckusick			sblock.fs_pendinginodes = 0;
434105436Smckusick		}
43566864Sadrian		sbdirty();
43666864Sadrian		ofsmodified = fsmodified;
43766864Sadrian		flush(fswritefd, &sblk);
43866864Sadrian		fsmodified = ofsmodified;
43966864Sadrian		if (!preen) {
44066864Sadrian			printf("\n***** FILE SYSTEM MARKED %s *****\n",
44166864Sadrian			    markclean ? "CLEAN" : "DIRTY");
44266864Sadrian			if (!markclean)
44366864Sadrian				rerun = 1;
44466864Sadrian		}
445188110Smckusick	} else if (!preen) {
446188110Smckusick		if (markclean) {
447188110Smckusick			printf("\n***** FILE SYSTEM IS CLEAN *****\n");
448188110Smckusick		} else {
449188110Smckusick			printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
450188110Smckusick			rerun = 1;
451188110Smckusick		}
45266864Sadrian	}
45366864Sadrian	(void)close(fsreadfd);
45466864Sadrian	(void)close(fswritefd);
45566864Sadrian}
45666864Sadrian
457249788Smckusick/*
458249788Smckusick * Print out I/O statistics.
459249788Smckusick */
460249788Smckusickvoid
461249788SmckusickIOstats(char *what)
462249788Smckusick{
463249788Smckusick	int i;
464249788Smckusick
465249788Smckusick	if (debug == 0)
466249788Smckusick		return;
467249788Smckusick	if (diskreads == 0) {
468249788Smckusick		printf("%s: no I/O\n\n", what);
469249788Smckusick		return;
470249788Smckusick	}
471249788Smckusick	if (startpass.tv_sec == 0)
472249788Smckusick		startpass = startprog;
473249788Smckusick	printf("%s: I/O statistics\n", what);
474249788Smckusick	printIOstats();
475249788Smckusick	totaldiskreads += diskreads;
476249788Smckusick	diskreads = 0;
477249788Smckusick	for (i = 0; i < BT_NUMBUFTYPES; i++) {
478249788Smckusick		timespecadd(&totalreadtime[i], &readtime[i]);
479249788Smckusick		totalreadcnt[i] += readcnt[i];
480249788Smckusick		readtime[i].tv_sec = readtime[i].tv_nsec = 0;
481249788Smckusick		readcnt[i] = 0;
482249788Smckusick	}
483249788Smckusick	clock_gettime(CLOCK_REALTIME_PRECISE, &startpass);
484249788Smckusick}
485249788Smckusick
486249788Smckusickvoid
487249788SmckusickfinalIOstats(void)
488249788Smckusick{
489249788Smckusick	int i;
490249788Smckusick
491249788Smckusick	if (debug == 0)
492249788Smckusick		return;
493249788Smckusick	printf("Final I/O statistics\n");
494249788Smckusick	totaldiskreads += diskreads;
495249788Smckusick	diskreads = totaldiskreads;
496249788Smckusick	startpass = startprog;
497249788Smckusick	for (i = 0; i < BT_NUMBUFTYPES; i++) {
498249788Smckusick		timespecadd(&totalreadtime[i], &readtime[i]);
499249788Smckusick		totalreadcnt[i] += readcnt[i];
500249788Smckusick		readtime[i] = totalreadtime[i];
501249788Smckusick		readcnt[i] = totalreadcnt[i];
502249788Smckusick	}
503249788Smckusick	printIOstats();
504249788Smckusick}
505249788Smckusick
506249788Smckusickstatic void printIOstats(void)
507249788Smckusick{
508249788Smckusick	long long msec, totalmsec;
509249788Smckusick	int i;
510249788Smckusick
511249788Smckusick	clock_gettime(CLOCK_REALTIME_PRECISE, &finishpass);
512249788Smckusick	timespecsub(&finishpass, &startpass);
513249788Smckusick	printf("Running time: %jd.%03ld sec\n",
514249788Smckusick		(intmax_t)finishpass.tv_sec, finishpass.tv_nsec / 1000000);
515249788Smckusick	printf("buffer reads by type:\n");
516249788Smckusick	for (totalmsec = 0, i = 0; i < BT_NUMBUFTYPES; i++)
517249788Smckusick		totalmsec += readtime[i].tv_sec * 1000 +
518249788Smckusick		    readtime[i].tv_nsec / 1000000;
519249788Smckusick	if (totalmsec == 0)
520249788Smckusick		totalmsec = 1;
521249788Smckusick	for (i = 0; i < BT_NUMBUFTYPES; i++) {
522249788Smckusick		if (readcnt[i] == 0)
523249788Smckusick			continue;
524249788Smckusick		msec =
525249788Smckusick		    readtime[i].tv_sec * 1000 + readtime[i].tv_nsec / 1000000;
526249788Smckusick		printf("%21s:%8ld %2ld.%ld%% %4jd.%03ld sec %2lld.%lld%%\n",
527249788Smckusick		    buftype[i], readcnt[i], readcnt[i] * 100 / diskreads,
528249788Smckusick		    (readcnt[i] * 1000 / diskreads) % 10,
529249788Smckusick		    (intmax_t)readtime[i].tv_sec, readtime[i].tv_nsec / 1000000,
530249788Smckusick		    msec * 100 / totalmsec, (msec * 1000 / totalmsec) % 10);
531249788Smckusick	}
532249788Smckusick	printf("\n");
533249788Smckusick}
534249788Smckusick
53566864Sadrianint
536163845Spjdblread(int fd, char *buf, ufs2_daddr_t blk, long size)
53766864Sadrian{
53866864Sadrian	char *cp;
53966864Sadrian	int i, errs;
54066864Sadrian	off_t offset;
54166864Sadrian
54266864Sadrian	offset = blk;
54366864Sadrian	offset *= dev_bsize;
544107671Siedowse	if (bkgrdflag)
545107671Siedowse		slowio_start();
546249788Smckusick	totalreads++;
547249788Smckusick	diskreads++;
54866864Sadrian	if (lseek(fd, offset, 0) < 0)
54974556Smckusick		rwerror("SEEK BLK", blk);
550107671Siedowse	else if (read(fd, buf, (int)size) == size) {
551107671Siedowse		if (bkgrdflag)
552107671Siedowse			slowio_end();
55366864Sadrian		return (0);
554107671Siedowse	}
55574556Smckusick	rwerror("READ BLK", blk);
55666864Sadrian	if (lseek(fd, offset, 0) < 0)
55774556Smckusick		rwerror("SEEK BLK", blk);
55866864Sadrian	errs = 0;
55966864Sadrian	memset(buf, 0, (size_t)size);
56066864Sadrian	printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
56166864Sadrian	for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
56266864Sadrian		if (read(fd, cp, (int)secsize) != secsize) {
56366864Sadrian			(void)lseek(fd, offset + i + secsize, 0);
56466864Sadrian			if (secsize != dev_bsize && dev_bsize != 1)
565101037Smux				printf(" %jd (%jd),",
566101037Smux				    (intmax_t)(blk * dev_bsize + i) / secsize,
567101037Smux				    (intmax_t)blk + i / dev_bsize);
56866864Sadrian			else
569101037Smux				printf(" %jd,", (intmax_t)blk + i / dev_bsize);
57066864Sadrian			errs++;
57166864Sadrian		}
57266864Sadrian	}
57366864Sadrian	printf("\n");
57466864Sadrian	if (errs)
57566864Sadrian		resolved = 0;
57666864Sadrian	return (errs);
57766864Sadrian}
57866864Sadrian
57966864Sadrianvoid
580163845Spjdblwrite(int fd, char *buf, ufs2_daddr_t blk, long size)
58166864Sadrian{
58266864Sadrian	int i;
58366864Sadrian	char *cp;
58466864Sadrian	off_t offset;
58566864Sadrian
58666864Sadrian	if (fd < 0)
58766864Sadrian		return;
58866864Sadrian	offset = blk;
58966864Sadrian	offset *= dev_bsize;
59066864Sadrian	if (lseek(fd, offset, 0) < 0)
59174556Smckusick		rwerror("SEEK BLK", blk);
59266864Sadrian	else if (write(fd, buf, (int)size) == size) {
59366864Sadrian		fsmodified = 1;
59466864Sadrian		return;
59566864Sadrian	}
59666864Sadrian	resolved = 0;
59774556Smckusick	rwerror("WRITE BLK", blk);
59866864Sadrian	if (lseek(fd, offset, 0) < 0)
59974556Smckusick		rwerror("SEEK BLK", blk);
60066864Sadrian	printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
60166864Sadrian	for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
60266864Sadrian		if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
60366864Sadrian			(void)lseek(fd, offset + i + dev_bsize, 0);
604101037Smux			printf(" %jd,", (intmax_t)blk + i / dev_bsize);
60566864Sadrian		}
60666864Sadrian	printf("\n");
60766864Sadrian	return;
60866864Sadrian}
60966864Sadrian
610221233Sdesvoid
611221233Sdesblerase(int fd, ufs2_daddr_t blk, long size)
612221233Sdes{
613221233Sdes	off_t ioarg[2];
614221233Sdes
615221233Sdes	if (fd < 0)
616221233Sdes		return;
617221233Sdes	ioarg[0] = blk * dev_bsize;
618221233Sdes	ioarg[1] = size;
619221233Sdes	ioctl(fd, DIOCGDELETE, ioarg);
620221233Sdes	/* we don't really care if we succeed or not */
621221233Sdes	return;
622221233Sdes}
623221233Sdes
624253155Sdesvoid
625253155Sdesblzero(int fd, ufs2_daddr_t blk, long size)
626253155Sdes{
627253155Sdes	static char *zero;
628253155Sdes	off_t offset, len;
629253155Sdes
630253155Sdes	if (fd < 0)
631253155Sdes		return;
632253155Sdes	len = ZEROBUFSIZE;
633253155Sdes	if (zero == NULL) {
634253155Sdes		zero = calloc(len, 1);
635253155Sdes		if (zero == NULL)
636253155Sdes			errx(EEXIT, "cannot allocate buffer pool");
637253155Sdes	}
638253155Sdes	offset = blk * dev_bsize;
639253155Sdes	if (lseek(fd, offset, 0) < 0)
640253155Sdes		rwerror("SEEK BLK", blk);
641253155Sdes	while (size > 0) {
642253155Sdes		if (size > len)
643253155Sdes			size = len;
644253155Sdes		else
645253155Sdes			len = size;
646253155Sdes		if (write(fd, zero, len) != len)
647253155Sdes			rwerror("WRITE BLK", blk);
648253155Sdes		blk += len / dev_bsize;
649253155Sdes		size -= len;
650253155Sdes	}
651253155Sdes}
652253155Sdes
65366864Sadrian/*
654188110Smckusick * Verify cylinder group's magic number and other parameters.  If the
655188110Smckusick * test fails, offer an option to rebuild the whole cylinder group.
656178088Sdelphij */
657188110Smckusickint
658249788Smckusickcheck_cgmagic(int cg, struct bufarea *cgbp)
659178088Sdelphij{
660249788Smckusick	struct cg *cgp = cgbp->b_un.b_cg;
661178088Sdelphij
662188110Smckusick	/*
663188110Smckusick	 * Extended cylinder group checks.
664188110Smckusick	 */
665188110Smckusick	if (cg_chkmagic(cgp) &&
666188110Smckusick	    ((sblock.fs_magic == FS_UFS1_MAGIC &&
667188110Smckusick	      cgp->cg_old_niblk == sblock.fs_ipg &&
668188110Smckusick	      cgp->cg_ndblk <= sblock.fs_fpg &&
669201700Smckusick	      cgp->cg_old_ncyl <= sblock.fs_old_cpg) ||
670188110Smckusick	     (sblock.fs_magic == FS_UFS2_MAGIC &&
671188110Smckusick	      cgp->cg_niblk == sblock.fs_ipg &&
672188110Smckusick	      cgp->cg_ndblk <= sblock.fs_fpg &&
673188110Smckusick	      cgp->cg_initediblk <= sblock.fs_ipg))) {
674188110Smckusick		return (1);
675178088Sdelphij	}
676188110Smckusick	pfatal("CYLINDER GROUP %d: BAD MAGIC NUMBER", cg);
677188110Smckusick	if (!reply("REBUILD CYLINDER GROUP")) {
678188110Smckusick		printf("YOU WILL NEED TO RERUN FSCK.\n");
679188110Smckusick		rerun = 1;
680188110Smckusick		return (1);
681188110Smckusick	}
682188110Smckusick	/*
683188110Smckusick	 * Zero out the cylinder group and then initialize critical fields.
684188110Smckusick	 * Bit maps and summaries will be recalculated by later passes.
685188110Smckusick	 */
686188110Smckusick	memset(cgp, 0, (size_t)sblock.fs_cgsize);
687188110Smckusick	cgp->cg_magic = CG_MAGIC;
688188110Smckusick	cgp->cg_cgx = cg;
689188110Smckusick	cgp->cg_niblk = sblock.fs_ipg;
690188110Smckusick	cgp->cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ?
691188110Smckusick	    sblock.fs_ipg : 2 * INOPB(&sblock);
692188110Smckusick	if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size)
693188110Smckusick		cgp->cg_ndblk = sblock.fs_fpg;
694188110Smckusick	else
695188110Smckusick		cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg);
696188110Smckusick	cgp->cg_iusedoff = &cgp->cg_space[0] - (u_char *)(&cgp->cg_firstfield);
697188110Smckusick	if (sblock.fs_magic == FS_UFS1_MAGIC) {
698188110Smckusick		cgp->cg_niblk = 0;
699188110Smckusick		cgp->cg_initediblk = 0;
700188110Smckusick		cgp->cg_old_ncyl = sblock.fs_old_cpg;
701188110Smckusick		cgp->cg_old_niblk = sblock.fs_ipg;
702188110Smckusick		cgp->cg_old_btotoff = cgp->cg_iusedoff;
703188110Smckusick		cgp->cg_old_boff = cgp->cg_old_btotoff +
704188110Smckusick		    sblock.fs_old_cpg * sizeof(int32_t);
705188110Smckusick		cgp->cg_iusedoff = cgp->cg_old_boff +
706188110Smckusick		    sblock.fs_old_cpg * sizeof(u_int16_t);
707188110Smckusick	}
708188110Smckusick	cgp->cg_freeoff = cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
709188110Smckusick	cgp->cg_nextfreeoff = cgp->cg_freeoff + howmany(sblock.fs_fpg,CHAR_BIT);
710188110Smckusick	if (sblock.fs_contigsumsize > 0) {
711188110Smckusick		cgp->cg_nclusterblks = cgp->cg_ndblk / sblock.fs_frag;
712188110Smckusick		cgp->cg_clustersumoff =
713188110Smckusick		    roundup(cgp->cg_nextfreeoff, sizeof(u_int32_t));
714188110Smckusick		cgp->cg_clustersumoff -= sizeof(u_int32_t);
715188110Smckusick		cgp->cg_clusteroff = cgp->cg_clustersumoff +
716188110Smckusick		    (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t);
717188110Smckusick		cgp->cg_nextfreeoff = cgp->cg_clusteroff +
718188110Smckusick		    howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
719188110Smckusick	}
720249788Smckusick	dirty(cgbp);
721188110Smckusick	return (0);
722178088Sdelphij}
723178088Sdelphij
724178088Sdelphij/*
72566864Sadrian * allocate a data block with the specified number of fragments
72666864Sadrian */
72798542Smckusickufs2_daddr_t
72892839Simpallocblk(long frags)
72966864Sadrian{
73066864Sadrian	int i, j, k, cg, baseblk;
731249788Smckusick	struct bufarea *cgbp;
732249788Smckusick	struct cg *cgp;
73366864Sadrian
73466864Sadrian	if (frags <= 0 || frags > sblock.fs_frag)
73566864Sadrian		return (0);
73666864Sadrian	for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
73766864Sadrian		for (j = 0; j <= sblock.fs_frag - frags; j++) {
73866864Sadrian			if (testbmap(i + j))
73966864Sadrian				continue;
74066864Sadrian			for (k = 1; k < frags; k++)
74166864Sadrian				if (testbmap(i + j + k))
74266864Sadrian					break;
74366864Sadrian			if (k < frags) {
74466864Sadrian				j += k;
74566864Sadrian				continue;
74666864Sadrian			}
74766864Sadrian			cg = dtog(&sblock, i + j);
748249788Smckusick			cgbp = cgget(cg);
749249788Smckusick			cgp = cgbp->b_un.b_cg;
750249788Smckusick			if (!check_cgmagic(cg, cgbp))
751188110Smckusick				return (0);
75266864Sadrian			baseblk = dtogd(&sblock, i + j);
75366864Sadrian			for (k = 0; k < frags; k++) {
75466864Sadrian				setbmap(i + j + k);
75566864Sadrian				clrbit(cg_blksfree(cgp), baseblk + k);
75666864Sadrian			}
75766864Sadrian			n_blks += frags;
75866864Sadrian			if (frags == sblock.fs_frag)
75966864Sadrian				cgp->cg_cs.cs_nbfree--;
76066864Sadrian			else
76166864Sadrian				cgp->cg_cs.cs_nffree -= frags;
762249788Smckusick			dirty(cgbp);
76366864Sadrian			return (i + j);
76466864Sadrian		}
76566864Sadrian	}
76666864Sadrian	return (0);
76766864Sadrian}
76866864Sadrian
76966864Sadrian/*
77066864Sadrian * Free a previously allocated block
77166864Sadrian */
77266864Sadrianvoid
77398542Smckusickfreeblk(ufs2_daddr_t blkno, long frags)
77466864Sadrian{
77566864Sadrian	struct inodesc idesc;
77666864Sadrian
77766864Sadrian	idesc.id_blkno = blkno;
77866864Sadrian	idesc.id_numfrags = frags;
77966864Sadrian	(void)pass4check(&idesc);
78066864Sadrian}
78166864Sadrian
782107671Siedowse/* Slow down IO so as to leave some disk bandwidth for other processes */
783107671Siedowsevoid
784107671Siedowseslowio_start()
785107671Siedowse{
786107671Siedowse
787129401Sscottl	/* Delay one in every 8 operations */
788107671Siedowse	slowio_pollcnt = (slowio_pollcnt + 1) & 7;
789107671Siedowse	if (slowio_pollcnt == 0) {
790107671Siedowse		gettimeofday(&slowio_starttime, NULL);
791107671Siedowse	}
792107671Siedowse}
793107671Siedowse
794107671Siedowsevoid
795107671Siedowseslowio_end()
796107671Siedowse{
797107671Siedowse	struct timeval tv;
798107671Siedowse	int delay_usec;
799107671Siedowse
800107671Siedowse	if (slowio_pollcnt != 0)
801107671Siedowse		return;
802107671Siedowse
803107671Siedowse	/* Update the slowdown interval. */
804107671Siedowse	gettimeofday(&tv, NULL);
805107671Siedowse	delay_usec = (tv.tv_sec - slowio_starttime.tv_sec) * 1000000 +
806107671Siedowse	    (tv.tv_usec - slowio_starttime.tv_usec);
807107671Siedowse	if (delay_usec < 64)
808107671Siedowse		delay_usec = 64;
809129401Sscottl	if (delay_usec > 2500000)
810129401Sscottl		delay_usec = 2500000;
811107671Siedowse	slowio_delay_usec = (slowio_delay_usec * 63 + delay_usec) >> 6;
812129401Sscottl	/* delay by 8 times the average IO delay */
813129401Sscottl	if (slowio_delay_usec > 64)
814129401Sscottl		usleep(slowio_delay_usec * 8);
815107671Siedowse}
816107671Siedowse
81766864Sadrian/*
81866864Sadrian * Find a pathname
81966864Sadrian */
82066864Sadrianvoid
82192839Simpgetpathname(char *namebuf, ino_t curdir, ino_t ino)
82266864Sadrian{
82366864Sadrian	int len;
82492806Sobrien	char *cp;
82566864Sadrian	struct inodesc idesc;
82666864Sadrian	static int busy = 0;
82766864Sadrian
82866864Sadrian	if (curdir == ino && ino == ROOTINO) {
82966864Sadrian		(void)strcpy(namebuf, "/");
83066864Sadrian		return;
83166864Sadrian	}
832136281Struckman	if (busy || !INO_IS_DVALID(curdir)) {
83366864Sadrian		(void)strcpy(namebuf, "?");
83466864Sadrian		return;
83566864Sadrian	}
83666864Sadrian	busy = 1;
83766864Sadrian	memset(&idesc, 0, sizeof(struct inodesc));
83866864Sadrian	idesc.id_type = DATA;
83966864Sadrian	idesc.id_fix = IGNORE;
84066864Sadrian	cp = &namebuf[MAXPATHLEN - 1];
84166864Sadrian	*cp = '\0';
84266864Sadrian	if (curdir != ino) {
84366864Sadrian		idesc.id_parent = curdir;
84466864Sadrian		goto namelookup;
84566864Sadrian	}
84666864Sadrian	while (ino != ROOTINO) {
84766864Sadrian		idesc.id_number = ino;
84866864Sadrian		idesc.id_func = findino;
849100935Sphk		idesc.id_name = strdup("..");
85066864Sadrian		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
85166864Sadrian			break;
85266864Sadrian	namelookup:
85366864Sadrian		idesc.id_number = idesc.id_parent;
85466864Sadrian		idesc.id_parent = ino;
85566864Sadrian		idesc.id_func = findname;
85666864Sadrian		idesc.id_name = namebuf;
85766864Sadrian		if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
85866864Sadrian			break;
85966864Sadrian		len = strlen(namebuf);
86066864Sadrian		cp -= len;
86166864Sadrian		memmove(cp, namebuf, (size_t)len);
86266864Sadrian		*--cp = '/';
86366864Sadrian		if (cp < &namebuf[MAXNAMLEN])
86466864Sadrian			break;
86566864Sadrian		ino = idesc.id_number;
86666864Sadrian	}
86766864Sadrian	busy = 0;
86866864Sadrian	if (ino != ROOTINO)
86966864Sadrian		*--cp = '?';
87066864Sadrian	memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
87166864Sadrian}
87266864Sadrian
87366864Sadrianvoid
874100935Sphkcatch(int sig __unused)
87566864Sadrian{
87696483Sphk
87796483Sphk	ckfini(0);
87866864Sadrian	exit(12);
87966864Sadrian}
88066864Sadrian
88166864Sadrian/*
88266864Sadrian * When preening, allow a single quit to signal
883102231Strhodes * a special exit after file system checks complete
88466864Sadrian * so that reboot sequence may be interrupted.
88566864Sadrian */
88666864Sadrianvoid
887100935Sphkcatchquit(int sig __unused)
88866864Sadrian{
889102231Strhodes	printf("returning to single-user after file system check\n");
89066864Sadrian	returntosingle = 1;
89166864Sadrian	(void)signal(SIGQUIT, SIG_DFL);
89266864Sadrian}
89366864Sadrian
89466864Sadrian/*
89566864Sadrian * determine whether an inode should be fixed.
89666864Sadrian */
89766864Sadrianint
898100935Sphkdofix(struct inodesc *idesc, const char *msg)
89966864Sadrian{
90066864Sadrian
90166864Sadrian	switch (idesc->id_fix) {
90266864Sadrian
90366864Sadrian	case DONTKNOW:
90466864Sadrian		if (idesc->id_type == DATA)
90566864Sadrian			direrror(idesc->id_number, msg);
90666864Sadrian		else
90781911Skris			pwarn("%s", msg);
90866864Sadrian		if (preen) {
90966864Sadrian			printf(" (SALVAGED)\n");
91066864Sadrian			idesc->id_fix = FIX;
91166864Sadrian			return (ALTERED);
91266864Sadrian		}
91366864Sadrian		if (reply("SALVAGE") == 0) {
91466864Sadrian			idesc->id_fix = NOFIX;
91566864Sadrian			return (0);
91666864Sadrian		}
91766864Sadrian		idesc->id_fix = FIX;
91866864Sadrian		return (ALTERED);
91966864Sadrian
92066864Sadrian	case FIX:
92166864Sadrian		return (ALTERED);
92266864Sadrian
92366864Sadrian	case NOFIX:
92466864Sadrian	case IGNORE:
92566864Sadrian		return (0);
92666864Sadrian
92766864Sadrian	default:
92866864Sadrian		errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix);
92966864Sadrian	}
93066864Sadrian	/* NOTREACHED */
93166864Sadrian	return (0);
93266864Sadrian}
93366864Sadrian
93466864Sadrian#include <stdarg.h>
93566864Sadrian
93666864Sadrian/*
93766864Sadrian * An unexpected inconsistency occured.
938102231Strhodes * Die if preening or file system is running with soft dependency protocol,
93966864Sadrian * otherwise just print message and continue.
94066864Sadrian */
94166864Sadrianvoid
94266864Sadrianpfatal(const char *fmt, ...)
94366864Sadrian{
94466864Sadrian	va_list ap;
94566864Sadrian	va_start(ap, fmt);
94666864Sadrian	if (!preen) {
94775927Smckusick		(void)vfprintf(stdout, fmt, ap);
94866864Sadrian		va_end(ap);
94966864Sadrian		if (usedsoftdep)
95075927Smckusick			(void)fprintf(stdout,
95166864Sadrian			    "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n");
95275557Smckusick		/*
95375557Smckusick		 * Force foreground fsck to clean up inconsistency.
95475557Smckusick		 */
95575557Smckusick		if (bkgrdflag) {
95675557Smckusick			cmd.value = FS_NEEDSFSCK;
95775557Smckusick			cmd.size = 1;
95875557Smckusick			if (sysctlbyname("vfs.ffs.setflags", 0, 0,
95975557Smckusick			    &cmd, sizeof cmd) == -1)
96075557Smckusick				pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n");
96175927Smckusick			fprintf(stdout, "CANNOT RUN IN BACKGROUND\n");
96275557Smckusick			ckfini(0);
96375557Smckusick			exit(EEXIT);
96475557Smckusick		}
96566864Sadrian		return;
96666864Sadrian	}
96766864Sadrian	if (cdevname == NULL)
968100935Sphk		cdevname = strdup("fsck");
96975927Smckusick	(void)fprintf(stdout, "%s: ", cdevname);
97075927Smckusick	(void)vfprintf(stdout, fmt, ap);
97175927Smckusick	(void)fprintf(stdout,
97266864Sadrian	    "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n",
97366864Sadrian	    cdevname, usedsoftdep ? " SOFT UPDATE " : " ");
97475557Smckusick	/*
97575557Smckusick	 * Force foreground fsck to clean up inconsistency.
97675557Smckusick	 */
97775557Smckusick	if (bkgrdflag) {
97875557Smckusick		cmd.value = FS_NEEDSFSCK;
97975557Smckusick		cmd.size = 1;
98075557Smckusick		if (sysctlbyname("vfs.ffs.setflags", 0, 0,
98175557Smckusick		    &cmd, sizeof cmd) == -1)
98275557Smckusick			pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n");
98375557Smckusick	}
98466864Sadrian	ckfini(0);
98566864Sadrian	exit(EEXIT);
98666864Sadrian}
98766864Sadrian
98866864Sadrian/*
98966864Sadrian * Pwarn just prints a message when not preening or running soft dependency
99066864Sadrian * protocol, or a warning (preceded by filename) when preening.
99166864Sadrian */
99266864Sadrianvoid
99366864Sadrianpwarn(const char *fmt, ...)
99466864Sadrian{
99566864Sadrian	va_list ap;
99666864Sadrian	va_start(ap, fmt);
99766864Sadrian	if (preen)
99875927Smckusick		(void)fprintf(stdout, "%s: ", cdevname);
99975927Smckusick	(void)vfprintf(stdout, fmt, ap);
100066864Sadrian	va_end(ap);
100166864Sadrian}
100266864Sadrian
100366864Sadrian/*
100466864Sadrian * Stub for routines from kernel.
100566864Sadrian */
100666864Sadrianvoid
100766864Sadrianpanic(const char *fmt, ...)
100866864Sadrian{
100966864Sadrian	va_list ap;
101066864Sadrian	va_start(ap, fmt);
101166864Sadrian	pfatal("INTERNAL INCONSISTENCY:");
101275927Smckusick	(void)vfprintf(stdout, fmt, ap);
101366864Sadrian	va_end(ap);
101466864Sadrian	exit(EEXIT);
101566864Sadrian}
1016