xref: /netbsd-src/sbin/fsck/fsutil.c (revision a74e29fe24406e588e4c7ad6d03168a00d009bc1)
1*a74e29feSjoerg /*	$NetBSD: fsutil.c,v 1.27 2020/04/03 19:36:32 joerg Exp $	*/
27dfca760Schristos 
37dfca760Schristos /*
47dfca760Schristos  * Copyright (c) 1990, 1993
57dfca760Schristos  *	The Regents of the University of California.  All rights reserved.
67dfca760Schristos  *
77dfca760Schristos  * Redistribution and use in source and binary forms, with or without
87dfca760Schristos  * modification, are permitted provided that the following conditions
97dfca760Schristos  * are met:
107dfca760Schristos  * 1. Redistributions of source code must retain the above copyright
117dfca760Schristos  *    notice, this list of conditions and the following disclaimer.
127dfca760Schristos  * 2. Redistributions in binary form must reproduce the above copyright
137dfca760Schristos  *    notice, this list of conditions and the following disclaimer in the
147dfca760Schristos  *    documentation and/or other materials provided with the distribution.
15bf07c871Sagc  * 3. Neither the name of the University nor the names of its contributors
167dfca760Schristos  *    may be used to endorse or promote products derived from this software
177dfca760Schristos  *    without specific prior written permission.
187dfca760Schristos  *
197dfca760Schristos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
207dfca760Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
217dfca760Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
227dfca760Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
237dfca760Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
247dfca760Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
257dfca760Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
267dfca760Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
277dfca760Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
287dfca760Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
297dfca760Schristos  * SUCH DAMAGE.
307dfca760Schristos  */
3126ba0ba0Slukem 
3226ba0ba0Slukem #include <sys/cdefs.h>
337dfca760Schristos #ifndef lint
34*a74e29feSjoerg __RCSID("$NetBSD: fsutil.c,v 1.27 2020/04/03 19:36:32 joerg Exp $");
357dfca760Schristos #endif /* not lint */
367dfca760Schristos 
3749f4cf4bSdholland /*
3849f4cf4bSdholland  * used by sbin/fsck
3949f4cf4bSdholland  * used by sbin/fsck_ext2fs
4049f4cf4bSdholland  * used by sbin/fsck_ffs
4149f4cf4bSdholland  * used by sbin/fsck_lfs
4249f4cf4bSdholland  * used by sbin/fsck_msdos
4349f4cf4bSdholland  * used by sbin/fsck_v7fs
4449f4cf4bSdholland  * used by sbin/fsdb
4549f4cf4bSdholland  * used by usr.sbin/quotacheck
4649f4cf4bSdholland  */
4749f4cf4bSdholland 
483c367dcbSlukem #include <sys/param.h>
493c367dcbSlukem 
507dfca760Schristos #include <stdio.h>
517dfca760Schristos #include <string.h>
527dfca760Schristos #include <stdlib.h>
537dfca760Schristos #include <stdarg.h>
547dfca760Schristos #include <errno.h>
557dfca760Schristos #include <fstab.h>
5623ffdf5bSchristos #include <fcntl.h>
5723ffdf5bSchristos #include <unistd.h>
587dfca760Schristos #include <err.h>
595727faddSchristos #include <util.h>
607dfca760Schristos 
617dfca760Schristos #include <sys/types.h>
627dfca760Schristos #include <sys/stat.h>
637dfca760Schristos 
647dfca760Schristos #include "fsutil.h"
65742b48d5Schristos #include "exitvalues.h"
667dfca760Schristos 
67c30abfbbSdholland volatile sig_atomic_t returntosingle;
68c30abfbbSdholland 
69*a74e29feSjoerg void (*ckfinish)(int);
70*a74e29feSjoerg 
717dfca760Schristos static const char *dev = NULL;
727dfca760Schristos static int hot = 0;
737dfca760Schristos static int preen = 0;
74*a74e29feSjoerg int quiet;			/* don't report clean filesystems */
756a6266ccSchristos #define F_ERROR	0x80000000
767dfca760Schristos 
777dfca760Schristos void
setcdevname(const char * cd,int pr)78f97f5096Slukem setcdevname(const char *cd, int pr)
797dfca760Schristos {
80f97f5096Slukem 
817dfca760Schristos 	dev = cd;
827dfca760Schristos 	preen = pr;
837dfca760Schristos }
847dfca760Schristos 
857dfca760Schristos const char *
cdevname(void)86f97f5096Slukem cdevname(void)
877dfca760Schristos {
88f97f5096Slukem 
897dfca760Schristos 	return dev;
907dfca760Schristos }
917dfca760Schristos 
927dfca760Schristos int
hotroot(void)93f97f5096Slukem hotroot(void)
947dfca760Schristos {
95f97f5096Slukem 
967dfca760Schristos 	return hot;
977dfca760Schristos }
987dfca760Schristos 
997dfca760Schristos /*VARARGS*/
1007dfca760Schristos void
errexit(const char * fmt,...)1017dfca760Schristos errexit(const char *fmt, ...)
1027dfca760Schristos {
1037dfca760Schristos 	va_list ap;
1047dfca760Schristos 
1057dfca760Schristos 	va_start(ap, fmt);
1067dfca760Schristos 	(void) vfprintf(stderr, fmt, ap);
1077dfca760Schristos 	va_end(ap);
108481ad7b0Slukem 	(void)fprintf(stderr, "\n");
109742b48d5Schristos 	exit(FSCK_EXIT_CHECK_FAILED);
1107dfca760Schristos }
1117dfca760Schristos 
11242b90091Sperseant void
vmsg(int fatal,const char * fmt,va_list ap)113f97f5096Slukem vmsg(int fatal, const char *fmt, va_list ap)
1147dfca760Schristos {
1156a6266ccSchristos 	int serr = fatal & F_ERROR;
1166a6266ccSchristos 	int serrno = errno;
1176a6266ccSchristos 	fatal &= ~F_ERROR;
118f97f5096Slukem 
1197dfca760Schristos 	if (!fatal && preen)
1207dfca760Schristos 		(void)printf("%s: ", dev);
121e69ce3e4Sdsl 	if (quiet && !preen) {
122e69ce3e4Sdsl 		(void)printf("** %s (vmsg)\n", dev);
123e69ce3e4Sdsl 		quiet = 0;
124e69ce3e4Sdsl 	}
1257dfca760Schristos 
1267dfca760Schristos 	(void) vprintf(fmt, ap);
1276a6266ccSchristos 	if (serr)
1286a6266ccSchristos 		printf(" (%s)", strerror(serrno));
1297dfca760Schristos 
1307dfca760Schristos 	if (fatal && preen)
1317dfca760Schristos 		(void) printf("\n");
1327dfca760Schristos 
1337dfca760Schristos 	if (fatal && preen) {
1347dfca760Schristos 		(void) printf(
1357dfca760Schristos 		    "%s: UNEXPECTED INCONSISTENCY; RUN %s MANUALLY.\n",
1368a986b2eScgd 		    dev, getprogname());
137742b48d5Schristos 		exit(FSCK_EXIT_CHECK_FAILED);
1387dfca760Schristos 	}
1397dfca760Schristos }
1407dfca760Schristos 
1417dfca760Schristos /*VARARGS*/
1427dfca760Schristos void
pfatal(const char * fmt,...)1437dfca760Schristos pfatal(const char *fmt, ...)
1447dfca760Schristos {
1457dfca760Schristos 	va_list ap;
1467dfca760Schristos 
1477dfca760Schristos 	va_start(ap, fmt);
1487dfca760Schristos 	vmsg(1, fmt, ap);
1497dfca760Schristos 	va_end(ap);
1507dfca760Schristos }
1517dfca760Schristos 
1527dfca760Schristos /*VARARGS*/
1537dfca760Schristos void
pwarn(const char * fmt,...)1547dfca760Schristos pwarn(const char *fmt, ...)
1557dfca760Schristos {
1567dfca760Schristos 	va_list ap;
1571b51e882Schristos 
158f97f5096Slukem 	va_start(ap, fmt);
1597dfca760Schristos 	vmsg(0, fmt, ap);
1607dfca760Schristos 	va_end(ap);
1617dfca760Schristos }
1627dfca760Schristos 
1637dfca760Schristos void
perr(const char * fmt,...)1646a6266ccSchristos perr(const char *fmt, ...)
1657dfca760Schristos {
1666a6266ccSchristos 	va_list ap;
167f97f5096Slukem 
1686a6266ccSchristos 	va_start(ap, fmt);
1696a6266ccSchristos 	vmsg(1 | F_ERROR, fmt, ap);
1706a6266ccSchristos 	va_end(ap);
1717dfca760Schristos }
1727dfca760Schristos 
1737dfca760Schristos void
panic(const char * fmt,...)1747dfca760Schristos panic(const char *fmt, ...)
1757dfca760Schristos {
1767dfca760Schristos 	va_list ap;
1777dfca760Schristos 
1787dfca760Schristos 	va_start(ap, fmt);
1797dfca760Schristos 	vmsg(1, fmt, ap);
1807dfca760Schristos 	va_end(ap);
181742b48d5Schristos 	exit(FSCK_EXIT_CHECK_FAILED);
1827dfca760Schristos }
1837dfca760Schristos 
184b93acf4aSmycroft const char *
blockcheck(const char * origname)185f97f5096Slukem blockcheck(const char *origname)
1867dfca760Schristos {
1877dfca760Schristos 	struct stat stslash, stblock, stchar;
188ba7ad727Schristos 	const char *newname, *raw, *cooked;
1897dfca760Schristos 	struct fstab *fsp;
1907dfca760Schristos 	int retried = 0;
1919fc31869Smlelstv 	ssize_t len;
192ba7ad727Schristos 	char cbuf[MAXPATHLEN];
193ca11e1e6Schristos 	static char buf[MAXPATHLEN];
1947dfca760Schristos 
1957dfca760Schristos 	hot = 0;
1967dfca760Schristos 	if (stat("/", &stslash) < 0) {
1976a6266ccSchristos 		perr("Can't stat `/'");
1987dfca760Schristos 		return (origname);
1997dfca760Schristos 	}
2009fc31869Smlelstv 	len = readlink(origname, cbuf, sizeof(cbuf)-1);
2019fc31869Smlelstv 	if (len == -1) {
2027dfca760Schristos 		newname = origname;
2039fc31869Smlelstv 	} else {
2049fc31869Smlelstv 		cbuf[len] = '\0';
2059fc31869Smlelstv 		newname = cbuf;
2069fc31869Smlelstv 	}
2077dfca760Schristos retry:
2087dfca760Schristos 	if (stat(newname, &stblock) < 0) {
2096a6266ccSchristos 		perr("Can't stat `%s'", newname);
210ba7ad727Schristos 		return origname;
2117dfca760Schristos 	}
2127dfca760Schristos 	if (S_ISBLK(stblock.st_mode)) {
2137dfca760Schristos 		if (stslash.st_dev == stblock.st_rdev)
2147dfca760Schristos 			hot++;
215ca11e1e6Schristos 		raw = getdiskrawname(buf, sizeof(buf), newname);
216ca11e1e6Schristos 		if (raw == NULL) {
217ca11e1e6Schristos 			perr("Can't convert to raw `%s'", newname);
218ca11e1e6Schristos 			return origname;
219ca11e1e6Schristos 		}
2207dfca760Schristos 		if (stat(raw, &stchar) < 0) {
2216a6266ccSchristos 			perr("Can't stat `%s'", raw);
222ba7ad727Schristos 			return origname;
2237dfca760Schristos 		}
2247dfca760Schristos 		if (S_ISCHR(stchar.st_mode)) {
225ba7ad727Schristos 			return raw;
2267dfca760Schristos 		} else {
227ba7ad727Schristos 			perr("%s is not a character device\n", raw);
228ba7ad727Schristos 			return origname;
2297dfca760Schristos 		}
2307dfca760Schristos 	} else if (S_ISCHR(stblock.st_mode) && !retried) {
231ba7ad727Schristos 		cooked = getdiskcookedname(cbuf, sizeof(cbuf), newname);
232ba7ad727Schristos 		if (cooked == NULL) {
233ca11e1e6Schristos 			perr("Can't convert to cooked `%s'", newname);
234ca11e1e6Schristos 			return origname;
235ca11e1e6Schristos 		} else
236ba7ad727Schristos 			newname = cooked;
2377dfca760Schristos 		retried++;
2387dfca760Schristos 		goto retry;
2397dfca760Schristos 	} else if ((fsp = getfsfile(newname)) != 0 && !retried) {
240ba7ad727Schristos 		newname = getfsspecname(cbuf, sizeof(cbuf), fsp->fs_spec);
2415727faddSchristos 		if (newname == NULL)
2425727faddSchristos 			perr("%s", buf);
2437dfca760Schristos 		retried++;
2447dfca760Schristos 		goto retry;
2457dfca760Schristos 	}
2467dfca760Schristos 	/*
2477dfca760Schristos 	 * Not a block or character device, just return name and
2487dfca760Schristos 	 * let the user decide whether to use it.
2497dfca760Schristos 	 */
250ba7ad727Schristos 	return origname;
2517dfca760Schristos }
252c68c36a5Schristos 
253c68c36a5Schristos const char *
print_mtime(time_t t)254c68c36a5Schristos print_mtime(time_t t)
255c68c36a5Schristos {
256c68c36a5Schristos 	static char b[128];
257c68c36a5Schristos 	char *p = ctime(&t);
258c68c36a5Schristos 	if (p != NULL)
259c68c36a5Schristos 		(void)snprintf(b, sizeof(b), "%12.12s %4.4s ", &p[4], &p[20]);
260c68c36a5Schristos 	else
261c68c36a5Schristos 		(void)snprintf(b, sizeof(b), "%lld ", (long long)t);
262c68c36a5Schristos 	return b;
263c68c36a5Schristos }
26423ffdf5bSchristos 
26523ffdf5bSchristos 
26623ffdf5bSchristos void
catch(int n)26723ffdf5bSchristos catch(int n)
26823ffdf5bSchristos {
26923ffdf5bSchristos 	if (ckfinish) (*ckfinish)(0);
27023ffdf5bSchristos 	_exit(FSCK_EXIT_SIGNALLED);
27123ffdf5bSchristos }
27223ffdf5bSchristos 
27323ffdf5bSchristos /*
27423ffdf5bSchristos  * When preening, allow a single quit to signal
27523ffdf5bSchristos  * a special exit after filesystem checks complete
27623ffdf5bSchristos  * so that reboot sequence may be interrupted.
27723ffdf5bSchristos  */
27823ffdf5bSchristos void
catchquit(int n)27923ffdf5bSchristos catchquit(int n)
28023ffdf5bSchristos {
28123ffdf5bSchristos 	static const char msg[] =
28223ffdf5bSchristos 	    "returning to single-user after filesystem check\n";
28323ffdf5bSchristos 	int serrno = errno;
28423ffdf5bSchristos 
28523ffdf5bSchristos 	(void)write(STDOUT_FILENO, msg, sizeof(msg) - 1);
28623ffdf5bSchristos 	returntosingle = 1;
28723ffdf5bSchristos 	(void)signal(SIGQUIT, SIG_DFL);
28823ffdf5bSchristos 	errno = serrno;
28923ffdf5bSchristos }
29023ffdf5bSchristos 
29123ffdf5bSchristos /*
29223ffdf5bSchristos  * Ignore a single quit signal; wait and flush just in case.
29323ffdf5bSchristos  * Used by child processes in preen.
29423ffdf5bSchristos  */
29523ffdf5bSchristos void
voidquit(int n)29623ffdf5bSchristos voidquit(int n)
29723ffdf5bSchristos {
29823ffdf5bSchristos 	int serrno = errno;
29923ffdf5bSchristos 
30023ffdf5bSchristos 	sleep(1);
30123ffdf5bSchristos 	(void)signal(SIGQUIT, SIG_IGN);
30223ffdf5bSchristos 	(void)signal(SIGQUIT, SIG_DFL);
30323ffdf5bSchristos 	errno = serrno;
30423ffdf5bSchristos }
305