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