1*0a6a1f1dSLionel Sambuc /* $NetBSD: preen.c,v 1.32 2015/06/21 04:01:40 dholland Exp $ */
24d4057d8SBen Gras
34d4057d8SBen Gras /*
44d4057d8SBen Gras * Copyright (c) 1990, 1993
54d4057d8SBen Gras * The Regents of the University of California. All rights reserved.
64d4057d8SBen Gras *
74d4057d8SBen Gras * Redistribution and use in source and binary forms, with or without
84d4057d8SBen Gras * modification, are permitted provided that the following conditions
94d4057d8SBen Gras * are met:
104d4057d8SBen Gras * 1. Redistributions of source code must retain the above copyright
114d4057d8SBen Gras * notice, this list of conditions and the following disclaimer.
124d4057d8SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
134d4057d8SBen Gras * notice, this list of conditions and the following disclaimer in the
144d4057d8SBen Gras * documentation and/or other materials provided with the distribution.
154d4057d8SBen Gras * 3. Neither the name of the University nor the names of its contributors
164d4057d8SBen Gras * may be used to endorse or promote products derived from this software
174d4057d8SBen Gras * without specific prior written permission.
184d4057d8SBen Gras *
194d4057d8SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
204d4057d8SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
214d4057d8SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
224d4057d8SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
234d4057d8SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
244d4057d8SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
254d4057d8SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
264d4057d8SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
274d4057d8SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
284d4057d8SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
294d4057d8SBen Gras * SUCH DAMAGE.
304d4057d8SBen Gras */
314d4057d8SBen Gras
324d4057d8SBen Gras #include <sys/cdefs.h>
334d4057d8SBen Gras #ifndef lint
344d4057d8SBen Gras #if 0
354d4057d8SBen Gras static char sccsid[] = "@(#)preen.c 8.5 (Berkeley) 4/28/95";
364d4057d8SBen Gras #else
37*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: preen.c,v 1.32 2015/06/21 04:01:40 dholland Exp $");
384d4057d8SBen Gras #endif
394d4057d8SBen Gras #endif /* not lint */
404d4057d8SBen Gras
41*0a6a1f1dSLionel Sambuc /*
42*0a6a1f1dSLionel Sambuc * used by sbin/fsck
43*0a6a1f1dSLionel Sambuc * used by usr.sbin/quotacheck
44*0a6a1f1dSLionel Sambuc */
45*0a6a1f1dSLionel Sambuc
464d4057d8SBen Gras #include <sys/param.h>
474d4057d8SBen Gras #include <sys/stat.h>
484d4057d8SBen Gras #include <sys/wait.h>
494d4057d8SBen Gras #include <sys/queue.h>
504d4057d8SBen Gras #include <sys/disk.h>
514d4057d8SBen Gras #include <sys/ioctl.h>
524d4057d8SBen Gras
534d4057d8SBen Gras #include <err.h>
544d4057d8SBen Gras #include <ctype.h>
554d4057d8SBen Gras #include <fstab.h>
564d4057d8SBen Gras #include <fcntl.h>
574d4057d8SBen Gras #include <string.h>
584d4057d8SBen Gras #include <stdio.h>
594d4057d8SBen Gras #include <stdlib.h>
604d4057d8SBen Gras #include <unistd.h>
614d4057d8SBen Gras #include <util.h>
624d4057d8SBen Gras
634d4057d8SBen Gras #include "fsutil.h"
644d4057d8SBen Gras #include "exitvalues.h"
654d4057d8SBen Gras
664d4057d8SBen Gras struct partentry {
674d4057d8SBen Gras TAILQ_ENTRY(partentry) p_entries;
684d4057d8SBen Gras char *p_devname; /* device name */
694d4057d8SBen Gras char *p_mntpt; /* mount point */
704d4057d8SBen Gras char *p_type; /* file system type */
714d4057d8SBen Gras void *p_auxarg; /* auxiliary argument */
724d4057d8SBen Gras };
734d4057d8SBen Gras
744d4057d8SBen Gras TAILQ_HEAD(part, partentry) badh;
754d4057d8SBen Gras
764d4057d8SBen Gras struct diskentry {
774d4057d8SBen Gras TAILQ_ENTRY(diskentry) d_entries;
784d4057d8SBen Gras char *d_name; /* disk base name */
794d4057d8SBen Gras TAILQ_HEAD(prt, partentry) d_part; /* list of partitions on disk */
804d4057d8SBen Gras int d_pid; /* 0 or pid of fsck proc */
814d4057d8SBen Gras };
824d4057d8SBen Gras
834d4057d8SBen Gras TAILQ_HEAD(diskinfo, diskentry) diskh;
844d4057d8SBen Gras
854d4057d8SBen Gras static int nrun = 0, ndisks = 0;
864d4057d8SBen Gras
874d4057d8SBen Gras static struct diskentry *finddisk(const char *);
884d4057d8SBen Gras static void addpart(const char *, const char *, const char *, void *);
894d4057d8SBen Gras static int startdisk(struct diskentry *,
904d4057d8SBen Gras int (*)(const char *, const char *, const char *, void *, pid_t *));
914d4057d8SBen Gras static void printpart(void);
924d4057d8SBen Gras
934d4057d8SBen Gras int
checkfstab(int flags,int maxrun,void * (* docheck)(struct fstab *),int (* checkit)(const char *,const char *,const char *,void *,pid_t *))944d4057d8SBen Gras checkfstab(int flags, int maxrun, void *(*docheck)(struct fstab *),
954d4057d8SBen Gras int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
964d4057d8SBen Gras {
974d4057d8SBen Gras struct fstab *fs;
984d4057d8SBen Gras struct diskentry *d, *nextdisk;
994d4057d8SBen Gras struct partentry *p;
1004d4057d8SBen Gras int ret, pid, retcode, passno, sumstatus, status;
1014d4057d8SBen Gras void *auxarg;
1024d4057d8SBen Gras const char *name;
1034d4057d8SBen Gras int error = FSCK_EXIT_OK;
1044d4057d8SBen Gras
1054d4057d8SBen Gras TAILQ_INIT(&badh);
1064d4057d8SBen Gras TAILQ_INIT(&diskh);
1074d4057d8SBen Gras
1084d4057d8SBen Gras sumstatus = FSCK_EXIT_OK;
1094d4057d8SBen Gras
1104d4057d8SBen Gras for (passno = 1; passno <= 2; passno++) {
1114d4057d8SBen Gras if (setfsent() == 0) {
1124d4057d8SBen Gras warnx("Can't open checklist file: %s", _PATH_FSTAB);
1134d4057d8SBen Gras return FSCK_EXIT_CHECK_FAILED;
1144d4057d8SBen Gras }
1154d4057d8SBen Gras while ((fs = getfsent()) != 0) {
11684d9c625SLionel Sambuc char buf[MAXPATHLEN];
11784d9c625SLionel Sambuc const char *fsspec;
1184d4057d8SBen Gras if ((auxarg = (*docheck)(fs)) == NULL)
1194d4057d8SBen Gras continue;
12084d9c625SLionel Sambuc fsspec = getfsspecname(buf, sizeof(buf), fs->fs_spec);
12184d9c625SLionel Sambuc if (fsspec == NULL) {
12284d9c625SLionel Sambuc warn("%s", buf);
12384d9c625SLionel Sambuc return FSCK_EXIT_CHECK_FAILED;
12484d9c625SLionel Sambuc }
12584d9c625SLionel Sambuc name = blockcheck(fsspec);
1264d4057d8SBen Gras if (flags & CHECK_DEBUG)
1274d4057d8SBen Gras printf("pass %d, name %s\n", passno, name);
1284d4057d8SBen Gras
1294d4057d8SBen Gras if ((flags & CHECK_PREEN) == 0 ||
1304d4057d8SBen Gras (passno == 1 && fs->fs_passno == 1)) {
1314d4057d8SBen Gras if (name == NULL) {
1324d4057d8SBen Gras if (flags & CHECK_PREEN)
1334d4057d8SBen Gras return FSCK_EXIT_CHECK_FAILED;
1344d4057d8SBen Gras else
1354d4057d8SBen Gras continue;
1364d4057d8SBen Gras }
1374d4057d8SBen Gras sumstatus = (*checkit)(fs->fs_vfstype,
1384d4057d8SBen Gras name, fs->fs_file, auxarg, NULL);
1394d4057d8SBen Gras
1404d4057d8SBen Gras if (sumstatus) {
1414d4057d8SBen Gras if ((flags & CHECK_NOFIX) == 0)
1424d4057d8SBen Gras return sumstatus;
1434d4057d8SBen Gras else if (error < sumstatus)
1444d4057d8SBen Gras error = sumstatus;
1454d4057d8SBen Gras }
1464d4057d8SBen Gras } else if (passno == 2 && fs->fs_passno > 1) {
1474d4057d8SBen Gras if (name == NULL) {
1484d4057d8SBen Gras (void) fprintf(stderr,
14984d9c625SLionel Sambuc "BAD DISK NAME %s\n", fsspec);
1504d4057d8SBen Gras sumstatus = FSCK_EXIT_CHECK_FAILED;
1514d4057d8SBen Gras continue;
1524d4057d8SBen Gras }
1534d4057d8SBen Gras addpart(fs->fs_vfstype, name, fs->fs_file,
1544d4057d8SBen Gras auxarg);
1554d4057d8SBen Gras }
1564d4057d8SBen Gras }
1574d4057d8SBen Gras if ((flags & CHECK_PREEN) == 0)
1584d4057d8SBen Gras return error;
1594d4057d8SBen Gras }
1604d4057d8SBen Gras
1614d4057d8SBen Gras if (flags & CHECK_DEBUG)
1624d4057d8SBen Gras printpart();
1634d4057d8SBen Gras
1644d4057d8SBen Gras if (flags & CHECK_PREEN) {
1654d4057d8SBen Gras if (maxrun == 0)
1664d4057d8SBen Gras maxrun = ndisks;
1674d4057d8SBen Gras if (maxrun > ndisks)
1684d4057d8SBen Gras maxrun = ndisks;
1694d4057d8SBen Gras nextdisk = TAILQ_FIRST(&diskh);
1704d4057d8SBen Gras for (passno = 0; passno < maxrun; ++passno) {
1714d4057d8SBen Gras if ((ret = startdisk(nextdisk, checkit)) != 0) {
1724d4057d8SBen Gras if ((flags & CHECK_NOFIX) == 0)
1734d4057d8SBen Gras return ret;
1744d4057d8SBen Gras else if (error < ret)
1754d4057d8SBen Gras error = ret;
1764d4057d8SBen Gras }
1774d4057d8SBen Gras nextdisk = TAILQ_NEXT(nextdisk, d_entries);
1784d4057d8SBen Gras }
1794d4057d8SBen Gras
1804d4057d8SBen Gras while ((pid = wait(&status)) != -1) {
1814d4057d8SBen Gras TAILQ_FOREACH(d, &diskh, d_entries)
1824d4057d8SBen Gras if (d->d_pid == pid)
1834d4057d8SBen Gras break;
1844d4057d8SBen Gras
1854d4057d8SBen Gras if (d == NULL) {
1864d4057d8SBen Gras warnx("Unknown pid %d", pid);
1874d4057d8SBen Gras continue;
1884d4057d8SBen Gras }
1894d4057d8SBen Gras
1904d4057d8SBen Gras
1914d4057d8SBen Gras if (WIFEXITED(status))
1924d4057d8SBen Gras retcode = WEXITSTATUS(status);
1934d4057d8SBen Gras else
1944d4057d8SBen Gras retcode = 0;
1954d4057d8SBen Gras
1964d4057d8SBen Gras p = TAILQ_FIRST(&d->d_part);
1974d4057d8SBen Gras
1984d4057d8SBen Gras if (flags & (CHECK_DEBUG|CHECK_VERBOSE))
1994d4057d8SBen Gras (void) printf("done %s: %s (%s) = 0x%x\n",
2004d4057d8SBen Gras p->p_type, p->p_devname, p->p_mntpt,
2014d4057d8SBen Gras status);
2024d4057d8SBen Gras
2034d4057d8SBen Gras if (WIFSIGNALED(status)) {
2044d4057d8SBen Gras (void) fprintf(stderr,
2054d4057d8SBen Gras "%s: %s (%s): EXITED WITH SIGNAL %d\n",
2064d4057d8SBen Gras p->p_type, p->p_devname, p->p_mntpt,
2074d4057d8SBen Gras WTERMSIG(status));
2084d4057d8SBen Gras retcode = FSCK_EXIT_SIGNALLED;
2094d4057d8SBen Gras }
2104d4057d8SBen Gras
2114d4057d8SBen Gras TAILQ_REMOVE(&d->d_part, p, p_entries);
2124d4057d8SBen Gras
2134d4057d8SBen Gras if (retcode != 0) {
2144d4057d8SBen Gras TAILQ_INSERT_TAIL(&badh, p, p_entries);
2154d4057d8SBen Gras sumstatus |= retcode;
2164d4057d8SBen Gras } else {
2174d4057d8SBen Gras free(p->p_type);
2184d4057d8SBen Gras free(p->p_devname);
2194d4057d8SBen Gras free(p);
2204d4057d8SBen Gras }
2214d4057d8SBen Gras d->d_pid = 0;
2224d4057d8SBen Gras nrun--;
2234d4057d8SBen Gras
2244d4057d8SBen Gras if (TAILQ_FIRST(&d->d_part) == NULL)
2254d4057d8SBen Gras ndisks--;
2264d4057d8SBen Gras
2274d4057d8SBen Gras if (nextdisk == NULL) {
2284d4057d8SBen Gras if (TAILQ_FIRST(&d->d_part) != NULL) {
2294d4057d8SBen Gras if ((ret = startdisk(d, checkit)) != 0)
2304d4057d8SBen Gras {
2314d4057d8SBen Gras if ((flags & CHECK_NOFIX) == 0)
2324d4057d8SBen Gras return ret;
2334d4057d8SBen Gras else if (error < ret)
2344d4057d8SBen Gras error = ret;
2354d4057d8SBen Gras }
2364d4057d8SBen Gras }
2374d4057d8SBen Gras } else if (nrun < maxrun && nrun < ndisks) {
2384d4057d8SBen Gras for ( ;; ) {
2394d4057d8SBen Gras nextdisk = TAILQ_NEXT(nextdisk,
2404d4057d8SBen Gras d_entries);
2414d4057d8SBen Gras if (nextdisk == NULL)
2424d4057d8SBen Gras nextdisk = TAILQ_FIRST(&diskh);
2434d4057d8SBen Gras if (TAILQ_FIRST(&nextdisk->d_part)
2444d4057d8SBen Gras != NULL && nextdisk->d_pid == 0)
2454d4057d8SBen Gras break;
2464d4057d8SBen Gras }
2474d4057d8SBen Gras if ((ret = startdisk(nextdisk, checkit)) != 0)
2484d4057d8SBen Gras {
2494d4057d8SBen Gras if ((flags & CHECK_NOFIX) == 0)
2504d4057d8SBen Gras return ret;
2514d4057d8SBen Gras else if (error < ret)
2524d4057d8SBen Gras error = ret;
2534d4057d8SBen Gras }
2544d4057d8SBen Gras }
2554d4057d8SBen Gras }
2564d4057d8SBen Gras }
2574d4057d8SBen Gras if (sumstatus) {
2584d4057d8SBen Gras p = TAILQ_FIRST(&badh);
2594d4057d8SBen Gras if (p == NULL)
2604d4057d8SBen Gras return sumstatus;
2614d4057d8SBen Gras
2624d4057d8SBen Gras (void) fprintf(stderr,
2634d4057d8SBen Gras "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
2644d4057d8SBen Gras TAILQ_NEXT(p, p_entries) ? "S" : "",
2654d4057d8SBen Gras "UNEXPECTED INCONSISTENCY:");
2664d4057d8SBen Gras
2674d4057d8SBen Gras TAILQ_FOREACH(p, &badh, p_entries)
2684d4057d8SBen Gras (void) fprintf(stderr,
2694d4057d8SBen Gras "%s: %s (%s)%s", p->p_type, p->p_devname,
2704d4057d8SBen Gras p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
2714d4057d8SBen Gras
2724d4057d8SBen Gras return sumstatus;
2734d4057d8SBen Gras }
2744d4057d8SBen Gras (void) endfsent();
2754d4057d8SBen Gras return error;
2764d4057d8SBen Gras }
2774d4057d8SBen Gras
2784d4057d8SBen Gras
2794d4057d8SBen Gras static struct diskentry *
finddisk(const char * name)2804d4057d8SBen Gras finddisk(const char *name)
2814d4057d8SBen Gras {
2824d4057d8SBen Gras const char *p;
2834d4057d8SBen Gras size_t len, dlen;
2844d4057d8SBen Gras struct diskentry *d;
28584d9c625SLionel Sambuc #if !defined(__minix)
2864d4057d8SBen Gras char buf[MAXPATHLEN];
2874d4057d8SBen Gras struct dkwedge_info dkw;
2884d4057d8SBen Gras int fd;
2894d4057d8SBen Gras
2904d4057d8SBen Gras if ((fd = opendisk(name, O_RDONLY, buf, sizeof(buf), 0)) != -1) {
2914d4057d8SBen Gras if (ioctl(fd, DIOCGWEDGEINFO, &dkw) != -1)
2924d4057d8SBen Gras name = dkw.dkw_parent;
2934d4057d8SBen Gras (void)close(fd);
2944d4057d8SBen Gras }
29584d9c625SLionel Sambuc #endif /* !defined(__minix) */
2964d4057d8SBen Gras
2974d4057d8SBen Gras for (dlen = len = strlen(name), p = name + len - 1; p >= name; --p)
2984d4057d8SBen Gras if (isdigit((unsigned char)*p)) {
2994d4057d8SBen Gras len = p - name + 1;
3004d4057d8SBen Gras break;
3014d4057d8SBen Gras }
3024d4057d8SBen Gras if (p < name)
3034d4057d8SBen Gras len = dlen;
3044d4057d8SBen Gras
3054d4057d8SBen Gras TAILQ_FOREACH(d, &diskh, d_entries)
3064d4057d8SBen Gras if (strncmp(d->d_name, name, len) == 0 && d->d_name[len] == 0)
3074d4057d8SBen Gras return d;
3084d4057d8SBen Gras
3094d4057d8SBen Gras d = emalloc(sizeof(*d));
3104d4057d8SBen Gras d->d_name = estrdup(name);
3114d4057d8SBen Gras d->d_name[len] = '\0';
3124d4057d8SBen Gras TAILQ_INIT(&d->d_part);
3134d4057d8SBen Gras d->d_pid = 0;
3144d4057d8SBen Gras
3154d4057d8SBen Gras TAILQ_INSERT_TAIL(&diskh, d, d_entries);
3164d4057d8SBen Gras ndisks++;
3174d4057d8SBen Gras
3184d4057d8SBen Gras return d;
3194d4057d8SBen Gras }
3204d4057d8SBen Gras
3214d4057d8SBen Gras
3224d4057d8SBen Gras static void
printpart(void)3234d4057d8SBen Gras printpart(void)
3244d4057d8SBen Gras {
3254d4057d8SBen Gras struct diskentry *d;
3264d4057d8SBen Gras struct partentry *p;
3274d4057d8SBen Gras
3284d4057d8SBen Gras TAILQ_FOREACH(d, &diskh, d_entries) {
3294d4057d8SBen Gras (void) printf("disk %s:", d->d_name);
3304d4057d8SBen Gras TAILQ_FOREACH(p, &d->d_part, p_entries)
3314d4057d8SBen Gras (void) printf(" %s", p->p_devname);
3324d4057d8SBen Gras (void) printf("\n");
3334d4057d8SBen Gras }
3344d4057d8SBen Gras }
3354d4057d8SBen Gras
3364d4057d8SBen Gras
3374d4057d8SBen Gras static void
addpart(const char * type,const char * dev,const char * mntpt,void * auxarg)3384d4057d8SBen Gras addpart(const char *type, const char *dev, const char *mntpt, void *auxarg)
3394d4057d8SBen Gras {
3404d4057d8SBen Gras struct diskentry *d = finddisk(dev);
3414d4057d8SBen Gras struct partentry *p;
3424d4057d8SBen Gras
3434d4057d8SBen Gras TAILQ_FOREACH(p, &d->d_part, p_entries)
3444d4057d8SBen Gras if (strcmp(p->p_devname, dev) == 0) {
3454d4057d8SBen Gras warnx("%s in fstab more than once!", dev);
3464d4057d8SBen Gras return;
3474d4057d8SBen Gras }
3484d4057d8SBen Gras
3494d4057d8SBen Gras p = emalloc(sizeof(*p));
3504d4057d8SBen Gras p->p_devname = estrdup(dev);
3514d4057d8SBen Gras p->p_mntpt = estrdup(mntpt);
3524d4057d8SBen Gras p->p_type = estrdup(type);
3534d4057d8SBen Gras p->p_auxarg = auxarg;
3544d4057d8SBen Gras
3554d4057d8SBen Gras TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
3564d4057d8SBen Gras }
3574d4057d8SBen Gras
3584d4057d8SBen Gras
3594d4057d8SBen Gras static int
startdisk(struct diskentry * d,int (* checkit)(const char *,const char *,const char *,void *,pid_t *))3604d4057d8SBen Gras startdisk(struct diskentry *d,
3614d4057d8SBen Gras int (*checkit)(const char *, const char *, const char *, void *, pid_t *))
3624d4057d8SBen Gras {
3634d4057d8SBen Gras struct partentry *p = TAILQ_FIRST(&d->d_part);
3644d4057d8SBen Gras int rv;
3654d4057d8SBen Gras
3664d4057d8SBen Gras while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt,
3674d4057d8SBen Gras p->p_auxarg, &d->d_pid)) != 0 && nrun > 0)
3684d4057d8SBen Gras sleep(10);
3694d4057d8SBen Gras
3704d4057d8SBen Gras if (rv == 0)
3714d4057d8SBen Gras nrun++;
3724d4057d8SBen Gras
3734d4057d8SBen Gras return rv;
3744d4057d8SBen Gras }
375