1*0a6a1f1dSLionel Sambuc /* $NetBSD: fsck.c,v 1.52 2014/10/25 22:00:19 mlelstv Exp $ */
24d4057d8SBen Gras
34d4057d8SBen Gras /*
44d4057d8SBen Gras * Copyright (c) 1996 Christos Zoulas. All rights reserved.
54d4057d8SBen Gras * Copyright (c) 1980, 1989, 1993, 1994
64d4057d8SBen Gras * The Regents of the University of California. All rights reserved.
74d4057d8SBen Gras *
84d4057d8SBen Gras * Redistribution and use in source and binary forms, with or without
94d4057d8SBen Gras * modification, are permitted provided that the following conditions
104d4057d8SBen Gras * are met:
114d4057d8SBen Gras * 1. Redistributions of source code must retain the above copyright
124d4057d8SBen Gras * notice, this list of conditions and the following disclaimer.
134d4057d8SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
144d4057d8SBen Gras * notice, this list of conditions and the following disclaimer in the
154d4057d8SBen Gras * documentation and/or other materials provided with the distribution.
164d4057d8SBen Gras * 3. Neither the name of the University nor the names of its contributors
174d4057d8SBen Gras * may be used to endorse or promote products derived from this software
184d4057d8SBen Gras * without specific prior written permission.
194d4057d8SBen Gras *
204d4057d8SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
214d4057d8SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224d4057d8SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234d4057d8SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
244d4057d8SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254d4057d8SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264d4057d8SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274d4057d8SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284d4057d8SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294d4057d8SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304d4057d8SBen Gras * SUCH DAMAGE.
314d4057d8SBen Gras *
324d4057d8SBen Gras * From: @(#)mount.c 8.19 (Berkeley) 4/19/94
334d4057d8SBen Gras * From: NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp
344d4057d8SBen Gras *
354d4057d8SBen Gras */
364d4057d8SBen Gras
374d4057d8SBen Gras #include <sys/cdefs.h>
384d4057d8SBen Gras #ifndef lint
39*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: fsck.c,v 1.52 2014/10/25 22:00:19 mlelstv Exp $");
404d4057d8SBen Gras #endif /* not lint */
414d4057d8SBen Gras
424d4057d8SBen Gras #include <sys/param.h>
434d4057d8SBen Gras #include <sys/mount.h>
444d4057d8SBen Gras #include <sys/queue.h>
454d4057d8SBen Gras #include <sys/wait.h>
464d4057d8SBen Gras #define FSTYPENAMES
474d4057d8SBen Gras #define FSCKNAMES
484d4057d8SBen Gras #include <sys/disk.h>
494d4057d8SBen Gras #include <sys/disklabel.h>
504d4057d8SBen Gras #include <sys/ioctl.h>
514d4057d8SBen Gras
524d4057d8SBen Gras #include <err.h>
534d4057d8SBen Gras #include <errno.h>
544d4057d8SBen Gras #include <fstab.h>
554d4057d8SBen Gras #include <fcntl.h>
564d4057d8SBen Gras #include <paths.h>
574d4057d8SBen Gras #include <signal.h>
584d4057d8SBen Gras #include <stdio.h>
594d4057d8SBen Gras #include <stdlib.h>
604d4057d8SBen Gras #include <string.h>
614d4057d8SBen Gras #include <unistd.h>
624d4057d8SBen Gras #include <util.h>
634d4057d8SBen Gras
644d4057d8SBen Gras #include "pathnames.h"
654d4057d8SBen Gras #include "fsutil.h"
664d4057d8SBen Gras #include "exitvalues.h"
674d4057d8SBen Gras
684d4057d8SBen Gras static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST;
694d4057d8SBen Gras
TAILQ_HEAD(fstypelist,entry)704d4057d8SBen Gras TAILQ_HEAD(fstypelist, entry) opthead, selhead, omhead;
714d4057d8SBen Gras
724d4057d8SBen Gras struct entry {
734d4057d8SBen Gras char *type;
744d4057d8SBen Gras char *options;
754d4057d8SBen Gras TAILQ_ENTRY(entry) entries;
764d4057d8SBen Gras };
774d4057d8SBen Gras
784d4057d8SBen Gras static int maxrun = 0;
794d4057d8SBen Gras static char *options = NULL;
804d4057d8SBen Gras static int flags = 0;
814d4057d8SBen Gras
824d4057d8SBen Gras static int checkfs(const char *, const char *, const char *, void *, pid_t *);
834d4057d8SBen Gras static int selected(const char *);
844d4057d8SBen Gras static int omitted(const char *);
854d4057d8SBen Gras static void addoption(char *);
864d4057d8SBen Gras static const char *getoptions(const char *);
874d4057d8SBen Gras static void addentry(struct fstypelist *, const char *, const char *);
884d4057d8SBen Gras static void maketypelist(char *);
894d4057d8SBen Gras static void catopt(char **, const char *);
904d4057d8SBen Gras static void mangle(char *, int *, const char ** volatile *, int *);
914d4057d8SBen Gras static const char *getfslab(const char *);
9284d9c625SLionel Sambuc __dead static void usage(void);
934d4057d8SBen Gras static void *isok(struct fstab *);
944d4057d8SBen Gras
954d4057d8SBen Gras int
main(int argc,char * argv[])964d4057d8SBen Gras main(int argc, char *argv[])
974d4057d8SBen Gras {
984d4057d8SBen Gras struct fstab *fs;
994d4057d8SBen Gras int i, rval;
1004d4057d8SBen Gras const char *vfstype = NULL;
1014d4057d8SBen Gras char globopt[3];
1024d4057d8SBen Gras int ret = FSCK_EXIT_OK;
10384d9c625SLionel Sambuc char buf[MAXPATHLEN];
1044d4057d8SBen Gras
1054d4057d8SBen Gras globopt[0] = '-';
1064d4057d8SBen Gras globopt[2] = '\0';
1074d4057d8SBen Gras
1084d4057d8SBen Gras TAILQ_INIT(&selhead);
1094d4057d8SBen Gras TAILQ_INIT(&opthead);
1104d4057d8SBen Gras TAILQ_INIT(&omhead);
1114d4057d8SBen Gras
1124d4057d8SBen Gras while ((i = getopt(argc, argv, "dfl:nPpqT:t:vx:y")) != -1) {
1134d4057d8SBen Gras switch (i) {
1144d4057d8SBen Gras case 'd':
1154d4057d8SBen Gras flags |= CHECK_DEBUG;
1164d4057d8SBen Gras continue;
1174d4057d8SBen Gras
1184d4057d8SBen Gras case 'f':
1194d4057d8SBen Gras flags |= CHECK_FORCE;
1204d4057d8SBen Gras break;
1214d4057d8SBen Gras
1224d4057d8SBen Gras case 'n':
1234d4057d8SBen Gras flags |= CHECK_NOFIX;
1244d4057d8SBen Gras break;
1254d4057d8SBen Gras
1264d4057d8SBen Gras case 'p':
1274d4057d8SBen Gras flags |= CHECK_PREEN;
1284d4057d8SBen Gras break;
1294d4057d8SBen Gras
1304d4057d8SBen Gras case 'P':
1314d4057d8SBen Gras flags |= CHECK_PROGRESS;
1324d4057d8SBen Gras break;
1334d4057d8SBen Gras
1344d4057d8SBen Gras case 'q':
1354d4057d8SBen Gras break;
1364d4057d8SBen Gras
1374d4057d8SBen Gras case 'l':
1384d4057d8SBen Gras maxrun = atoi(optarg);
1394d4057d8SBen Gras continue;
1404d4057d8SBen Gras
1414d4057d8SBen Gras case 'T':
1424d4057d8SBen Gras if (*optarg)
1434d4057d8SBen Gras addoption(optarg);
1444d4057d8SBen Gras continue;
1454d4057d8SBen Gras
1464d4057d8SBen Gras case 't':
1474d4057d8SBen Gras if (TAILQ_FIRST(&selhead) != NULL)
1484d4057d8SBen Gras errx(1, "only one -t option may be specified.");
1494d4057d8SBen Gras
1504d4057d8SBen Gras maketypelist(optarg);
1514d4057d8SBen Gras vfstype = optarg;
1524d4057d8SBen Gras continue;
1534d4057d8SBen Gras
1544d4057d8SBen Gras case 'v':
1554d4057d8SBen Gras flags |= CHECK_VERBOSE;
1564d4057d8SBen Gras continue;
1574d4057d8SBen Gras
1584d4057d8SBen Gras case 'x':
1594d4057d8SBen Gras addentry(&omhead, optarg, "");
1604d4057d8SBen Gras continue;
1614d4057d8SBen Gras
1624d4057d8SBen Gras case 'y':
1634d4057d8SBen Gras break;
1644d4057d8SBen Gras
1654d4057d8SBen Gras case '?':
1664d4057d8SBen Gras default:
1674d4057d8SBen Gras usage();
1684d4057d8SBen Gras /* NOTREACHED */
1694d4057d8SBen Gras }
1704d4057d8SBen Gras
1714d4057d8SBen Gras /* Pass option to fsck_xxxfs */
1724d4057d8SBen Gras globopt[1] = i;
1734d4057d8SBen Gras catopt(&options, globopt);
1744d4057d8SBen Gras }
1754d4057d8SBen Gras
1764d4057d8SBen Gras /* Don't do progress meters if we're debugging. */
1774d4057d8SBen Gras if (flags & CHECK_DEBUG)
1784d4057d8SBen Gras flags &= ~CHECK_PROGRESS;
1794d4057d8SBen Gras
1804d4057d8SBen Gras /*
1814d4057d8SBen Gras * If progress meters are being used, force max parallel to 1
1824d4057d8SBen Gras * so the progress meter outputs don't interfere with one another.
1834d4057d8SBen Gras */
1844d4057d8SBen Gras if (flags & CHECK_PROGRESS)
1854d4057d8SBen Gras maxrun = 1;
1864d4057d8SBen Gras
18784d9c625SLionel Sambuc #if defined(__minix)
18894715d8eSBen Gras /* parallel checking heuristic doesn't work for minix currently */
18994715d8eSBen Gras maxrun = 1;
19084d9c625SLionel Sambuc #endif /* !defined(__minix) */
1914d4057d8SBen Gras argc -= optind;
1924d4057d8SBen Gras argv += optind;
1934d4057d8SBen Gras
1944d4057d8SBen Gras if (argc == 0)
1954d4057d8SBen Gras return checkfstab(flags, maxrun, isok, checkfs);
1964d4057d8SBen Gras
1974d4057d8SBen Gras #define BADTYPE(type) \
1984d4057d8SBen Gras (strcmp(type, FSTAB_RO) && \
1994d4057d8SBen Gras strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
2004d4057d8SBen Gras
2014d4057d8SBen Gras
2024d4057d8SBen Gras for (; argc--; argv++) {
203*0a6a1f1dSLionel Sambuc const char *spec, *spec2, *mntpt, *type, *cp;
2044d4057d8SBen Gras char device[MAXPATHLEN];
2054d4057d8SBen Gras
206*0a6a1f1dSLionel Sambuc spec = mntpt = *argv;
207*0a6a1f1dSLionel Sambuc spec2 = getfsspecname(buf, sizeof(buf), spec);
208*0a6a1f1dSLionel Sambuc if (spec2 == NULL)
209*0a6a1f1dSLionel Sambuc spec2 = spec;
210*0a6a1f1dSLionel Sambuc
211*0a6a1f1dSLionel Sambuc cp = strrchr(spec2, '/');
2124d4057d8SBen Gras if (cp == 0) {
2134d4057d8SBen Gras (void)snprintf(device, sizeof(device), "%s%s",
214*0a6a1f1dSLionel Sambuc _PATH_DEV, spec2);
215*0a6a1f1dSLionel Sambuc spec2 = device;
2164d4057d8SBen Gras }
217*0a6a1f1dSLionel Sambuc
218*0a6a1f1dSLionel Sambuc fs = getfsfile(spec);
219*0a6a1f1dSLionel Sambuc if (fs == NULL)
220*0a6a1f1dSLionel Sambuc fs = getfsspec(spec);
221*0a6a1f1dSLionel Sambuc if (fs == NULL && spec != spec2) {
222*0a6a1f1dSLionel Sambuc fs = getfsspec(spec2);
223*0a6a1f1dSLionel Sambuc spec = spec2;
2244d4057d8SBen Gras }
225*0a6a1f1dSLionel Sambuc
226*0a6a1f1dSLionel Sambuc if (fs) {
22784d9c625SLionel Sambuc spec = getfsspecname(buf, sizeof(buf), fs->fs_spec);
22884d9c625SLionel Sambuc if (spec == NULL)
22984d9c625SLionel Sambuc err(FSCK_EXIT_CHECK_FAILED, "%s", buf);
2304d4057d8SBen Gras type = fs->fs_vfstype;
2314d4057d8SBen Gras if (BADTYPE(fs->fs_type))
2324d4057d8SBen Gras errx(FSCK_EXIT_CHECK_FAILED,
2334d4057d8SBen Gras "%s has unknown file system type.",
2344d4057d8SBen Gras spec);
235*0a6a1f1dSLionel Sambuc } else {
236*0a6a1f1dSLionel Sambuc if (vfstype == NULL)
237*0a6a1f1dSLionel Sambuc vfstype = getfslab(spec);
238*0a6a1f1dSLionel Sambuc type = vfstype;
2394d4057d8SBen Gras }
2404d4057d8SBen Gras
2414d4057d8SBen Gras rval = checkfs(type, blockcheck(spec), *argv, NULL, NULL);
2424d4057d8SBen Gras if (rval > ret)
2434d4057d8SBen Gras ret = rval;
2444d4057d8SBen Gras }
2454d4057d8SBen Gras
2464d4057d8SBen Gras return ret;
2474d4057d8SBen Gras }
2484d4057d8SBen Gras
2494d4057d8SBen Gras
2504d4057d8SBen Gras static void *
isok(struct fstab * fs)2514d4057d8SBen Gras isok(struct fstab *fs)
2524d4057d8SBen Gras {
2534d4057d8SBen Gras
2544d4057d8SBen Gras if (fs->fs_passno == 0)
2554d4057d8SBen Gras return NULL;
2564d4057d8SBen Gras
2574d4057d8SBen Gras if (BADTYPE(fs->fs_type))
2584d4057d8SBen Gras return NULL;
2594d4057d8SBen Gras
2604d4057d8SBen Gras if (!selected(fs->fs_vfstype))
2614d4057d8SBen Gras return NULL;
2624d4057d8SBen Gras
2634d4057d8SBen Gras if (omitted(fs->fs_file))
2644d4057d8SBen Gras return NULL;
2654d4057d8SBen Gras
2664d4057d8SBen Gras return fs;
2674d4057d8SBen Gras }
2684d4057d8SBen Gras
2694d4057d8SBen Gras
2704d4057d8SBen Gras static int
checkfs(const char * vfst,const char * spec,const char * mntpt,void * auxarg,pid_t * pidp)2714d4057d8SBen Gras checkfs(const char *vfst, const char *spec, const char *mntpt, void *auxarg,
2724d4057d8SBen Gras pid_t *pidp)
2734d4057d8SBen Gras {
2744d4057d8SBen Gras /* List of directories containing fsck_xxx subcommands. */
2754d4057d8SBen Gras static const char *edirs[] = {
2764d4057d8SBen Gras #ifdef RESCUEDIR
2774d4057d8SBen Gras RESCUEDIR,
2784d4057d8SBen Gras #endif
2794d4057d8SBen Gras _PATH_SBIN,
2804d4057d8SBen Gras _PATH_USRSBIN,
28184d9c625SLionel Sambuc #if defined(__minix)
2824d4057d8SBen Gras "/usr/pkg/sbin/",
28384d9c625SLionel Sambuc #endif /* defined(__minix) */
2844d4057d8SBen Gras NULL
2854d4057d8SBen Gras };
2864d4057d8SBen Gras const char ** volatile argv, **edir;
2874d4057d8SBen Gras const char * volatile vfstype = vfst;
2884d4057d8SBen Gras pid_t pid;
2894d4057d8SBen Gras int argc, i, status, maxargc;
2904d4057d8SBen Gras char *optb;
2914d4057d8SBen Gras char *volatile optbuf;
29284d9c625SLionel Sambuc char execname[MAXPATHLEN + 1], execbase[MAXPATHLEN];
2934d4057d8SBen Gras const char *extra = getoptions(vfstype);
2944d4057d8SBen Gras
2954d4057d8SBen Gras if (!strcmp(vfstype, "ufs"))
2964d4057d8SBen Gras vfstype = MOUNT_UFS;
2974d4057d8SBen Gras
2984d4057d8SBen Gras optb = NULL;
2994d4057d8SBen Gras if (options)
3004d4057d8SBen Gras catopt(&optb, options);
3014d4057d8SBen Gras if (extra)
3024d4057d8SBen Gras catopt(&optb, extra);
3034d4057d8SBen Gras optbuf = optb;
3044d4057d8SBen Gras
3054d4057d8SBen Gras maxargc = 64;
3064d4057d8SBen Gras argv = emalloc(sizeof(char *) * maxargc);
3074d4057d8SBen Gras
30884d9c625SLionel Sambuc (void) snprintf(execbase, sizeof(execbase), "fsck_%s", vfstype);
3094d4057d8SBen Gras argc = 0;
31084d9c625SLionel Sambuc argv[argc++] = execbase;
3114d4057d8SBen Gras if (optbuf)
3124d4057d8SBen Gras mangle(optbuf, &argc, &argv, &maxargc);
3134d4057d8SBen Gras argv[argc++] = spec;
3144d4057d8SBen Gras argv[argc] = NULL;
3154d4057d8SBen Gras
3164d4057d8SBen Gras if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) {
3174d4057d8SBen Gras (void)printf("start %s %swait", mntpt,
3184d4057d8SBen Gras pidp ? "no" : "");
3194d4057d8SBen Gras for (i = 0; i < argc; i++)
3204d4057d8SBen Gras (void)printf(" %s", argv[i]);
3214d4057d8SBen Gras (void)printf("\n");
3224d4057d8SBen Gras }
3234d4057d8SBen Gras
3244d4057d8SBen Gras switch (pid = vfork()) {
3254d4057d8SBen Gras case -1: /* Error. */
3264d4057d8SBen Gras warn("vfork");
3274d4057d8SBen Gras if (optbuf)
3284d4057d8SBen Gras free(optbuf);
3294d4057d8SBen Gras free(argv);
3304d4057d8SBen Gras return FSCK_EXIT_CHECK_FAILED;
3314d4057d8SBen Gras
3324d4057d8SBen Gras case 0: /* Child. */
3334d4057d8SBen Gras if ((flags & CHECK_FORCE) == 0) {
3344d4057d8SBen Gras struct statvfs sfs;
3354d4057d8SBen Gras
3364d4057d8SBen Gras /*
3374d4057d8SBen Gras * if mntpt is a mountpoint of a mounted file
3384d4057d8SBen Gras * system and it's mounted read-write, skip it
3394d4057d8SBen Gras * unless -f is given.
3404d4057d8SBen Gras */
3414d4057d8SBen Gras if ((statvfs(mntpt, &sfs) == 0) &&
3424d4057d8SBen Gras (strcmp(mntpt, sfs.f_mntonname) == 0) &&
3434d4057d8SBen Gras ((sfs.f_flag & MNT_RDONLY) == 0)) {
3444d4057d8SBen Gras printf(
3454d4057d8SBen Gras "%s: file system is mounted read-write on %s; not checking\n",
3464d4057d8SBen Gras spec, mntpt);
3474d4057d8SBen Gras if ((flags & CHECK_PREEN) && auxarg != NULL)
3484d4057d8SBen Gras _exit(FSCK_EXIT_OK); /* fsck -p */
3494d4057d8SBen Gras else
3504d4057d8SBen Gras _exit(FSCK_EXIT_CHECK_FAILED); /* fsck [[-p] ...] */
3514d4057d8SBen Gras }
3524d4057d8SBen Gras }
3534d4057d8SBen Gras
3544d4057d8SBen Gras if (flags & CHECK_DEBUG)
3554d4057d8SBen Gras _exit(FSCK_EXIT_OK);
3564d4057d8SBen Gras
3574d4057d8SBen Gras /* Go find an executable. */
3584d4057d8SBen Gras edir = edirs;
3594d4057d8SBen Gras do {
3604d4057d8SBen Gras (void)snprintf(execname,
36184d9c625SLionel Sambuc sizeof(execname), "%s/%s", *edir, execbase);
3624d4057d8SBen Gras execv(execname, (char * const *)__UNCONST(argv));
3634d4057d8SBen Gras if (errno != ENOENT) {
3644d4057d8SBen Gras if (spec)
3654d4057d8SBen Gras warn("exec %s for %s", execname, spec);
3664d4057d8SBen Gras else
3674d4057d8SBen Gras warn("exec %s", execname);
3684d4057d8SBen Gras }
3694d4057d8SBen Gras } while (*++edir != NULL);
3704d4057d8SBen Gras
3714d4057d8SBen Gras if (errno == ENOENT) {
3724d4057d8SBen Gras if (spec)
3734d4057d8SBen Gras warn("exec %s for %s", execname, spec);
3744d4057d8SBen Gras else
3754d4057d8SBen Gras warn("exec %s", execname);
3764d4057d8SBen Gras }
3774d4057d8SBen Gras _exit(FSCK_EXIT_CHECK_FAILED);
3784d4057d8SBen Gras /* NOTREACHED */
3794d4057d8SBen Gras
3804d4057d8SBen Gras default: /* Parent. */
3814d4057d8SBen Gras if (optbuf)
3824d4057d8SBen Gras free(optbuf);
3834d4057d8SBen Gras free(argv);
3844d4057d8SBen Gras
3854d4057d8SBen Gras if (pidp) {
3864d4057d8SBen Gras *pidp = pid;
3874d4057d8SBen Gras return FSCK_EXIT_OK;
3884d4057d8SBen Gras }
3894d4057d8SBen Gras
3904d4057d8SBen Gras if (waitpid(pid, &status, 0) < 0) {
3914d4057d8SBen Gras warn("waitpid");
3924d4057d8SBen Gras return FSCK_EXIT_CHECK_FAILED;
3934d4057d8SBen Gras }
3944d4057d8SBen Gras
3954d4057d8SBen Gras if (WIFEXITED(status)) {
3964d4057d8SBen Gras if (WEXITSTATUS(status) != 0)
3974d4057d8SBen Gras return WEXITSTATUS(status);
3984d4057d8SBen Gras }
3994d4057d8SBen Gras else if (WIFSIGNALED(status)) {
4004d4057d8SBen Gras warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
4014d4057d8SBen Gras return FSCK_EXIT_CHECK_FAILED;
4024d4057d8SBen Gras }
4034d4057d8SBen Gras break;
4044d4057d8SBen Gras }
4054d4057d8SBen Gras
4064d4057d8SBen Gras return FSCK_EXIT_OK;
4074d4057d8SBen Gras }
4084d4057d8SBen Gras
4094d4057d8SBen Gras
4104d4057d8SBen Gras static int
selected(const char * type)4114d4057d8SBen Gras selected(const char *type)
4124d4057d8SBen Gras {
4134d4057d8SBen Gras struct entry *e;
4144d4057d8SBen Gras
4154d4057d8SBen Gras /* If no type specified, it's always selected. */
4164d4057d8SBen Gras TAILQ_FOREACH(e, &selhead, entries)
4174d4057d8SBen Gras if (!strcmp(e->type, type))
4184d4057d8SBen Gras return which == IN_LIST ? 1 : 0;
4194d4057d8SBen Gras
4204d4057d8SBen Gras return which == IN_LIST ? 0 : 1;
4214d4057d8SBen Gras }
4224d4057d8SBen Gras
4234d4057d8SBen Gras
4244d4057d8SBen Gras static int
omitted(const char * mountedon)4254d4057d8SBen Gras omitted(const char *mountedon)
4264d4057d8SBen Gras {
4274d4057d8SBen Gras struct entry *e;
4284d4057d8SBen Gras
4294d4057d8SBen Gras /* If no type specified, it's always selected. */
4304d4057d8SBen Gras TAILQ_FOREACH(e, &omhead, entries)
4314d4057d8SBen Gras if (!strcmp(e->type, mountedon))
4324d4057d8SBen Gras return 1;
4334d4057d8SBen Gras
4344d4057d8SBen Gras return 0;
4354d4057d8SBen Gras }
4364d4057d8SBen Gras
4374d4057d8SBen Gras
4384d4057d8SBen Gras static const char *
getoptions(const char * type)4394d4057d8SBen Gras getoptions(const char *type)
4404d4057d8SBen Gras {
4414d4057d8SBen Gras struct entry *e;
4424d4057d8SBen Gras
4434d4057d8SBen Gras TAILQ_FOREACH(e, &opthead, entries)
4444d4057d8SBen Gras if (!strcmp(e->type, type))
4454d4057d8SBen Gras return e->options;
4464d4057d8SBen Gras return "";
4474d4057d8SBen Gras }
4484d4057d8SBen Gras
4494d4057d8SBen Gras
4504d4057d8SBen Gras static void
addoption(char * optstr)4514d4057d8SBen Gras addoption(char *optstr)
4524d4057d8SBen Gras {
4534d4057d8SBen Gras char *newoptions;
4544d4057d8SBen Gras struct entry *e;
4554d4057d8SBen Gras
4564d4057d8SBen Gras if ((newoptions = strchr(optstr, ':')) == NULL)
4574d4057d8SBen Gras errx(1, "Invalid option string");
4584d4057d8SBen Gras
4594d4057d8SBen Gras *newoptions++ = '\0';
4604d4057d8SBen Gras
4614d4057d8SBen Gras TAILQ_FOREACH(e, &opthead, entries)
4624d4057d8SBen Gras if (!strcmp(e->type, optstr)) {
4634d4057d8SBen Gras catopt(&e->options, newoptions);
4644d4057d8SBen Gras return;
4654d4057d8SBen Gras }
4664d4057d8SBen Gras addentry(&opthead, optstr, newoptions);
4674d4057d8SBen Gras }
4684d4057d8SBen Gras
4694d4057d8SBen Gras
4704d4057d8SBen Gras static void
addentry(struct fstypelist * list,const char * type,const char * opts)4714d4057d8SBen Gras addentry(struct fstypelist *list, const char *type, const char *opts)
4724d4057d8SBen Gras {
4734d4057d8SBen Gras struct entry *e;
4744d4057d8SBen Gras
4754d4057d8SBen Gras e = emalloc(sizeof(struct entry));
4764d4057d8SBen Gras e->type = estrdup(type);
4774d4057d8SBen Gras e->options = estrdup(opts);
4784d4057d8SBen Gras TAILQ_INSERT_TAIL(list, e, entries);
4794d4057d8SBen Gras }
4804d4057d8SBen Gras
4814d4057d8SBen Gras
4824d4057d8SBen Gras static void
maketypelist(char * fslist)4834d4057d8SBen Gras maketypelist(char *fslist)
4844d4057d8SBen Gras {
4854d4057d8SBen Gras char *ptr;
4864d4057d8SBen Gras
4874d4057d8SBen Gras if ((fslist == NULL) || (fslist[0] == '\0'))
4884d4057d8SBen Gras errx(1, "empty type list");
4894d4057d8SBen Gras
4904d4057d8SBen Gras if (fslist[0] == 'n' && fslist[1] == 'o') {
4914d4057d8SBen Gras fslist += 2;
4924d4057d8SBen Gras which = NOT_IN_LIST;
4934d4057d8SBen Gras }
4944d4057d8SBen Gras else
4954d4057d8SBen Gras which = IN_LIST;
4964d4057d8SBen Gras
4974d4057d8SBen Gras while ((ptr = strsep(&fslist, ",")) != NULL)
4984d4057d8SBen Gras addentry(&selhead, ptr, "");
4994d4057d8SBen Gras
5004d4057d8SBen Gras }
5014d4057d8SBen Gras
5024d4057d8SBen Gras
5034d4057d8SBen Gras static void
catopt(char ** sp,const char * o)5044d4057d8SBen Gras catopt(char **sp, const char *o)
5054d4057d8SBen Gras {
5064d4057d8SBen Gras char *s;
5074d4057d8SBen Gras size_t i, j;
5084d4057d8SBen Gras
5094d4057d8SBen Gras s = *sp;
5104d4057d8SBen Gras if (s) {
5114d4057d8SBen Gras i = strlen(s);
5124d4057d8SBen Gras j = i + 1 + strlen(o) + 1;
5134d4057d8SBen Gras s = erealloc(s, j);
5144d4057d8SBen Gras (void)snprintf(s + i, j, ",%s", o);
5154d4057d8SBen Gras } else
5164d4057d8SBen Gras s = estrdup(o);
5174d4057d8SBen Gras *sp = s;
5184d4057d8SBen Gras }
5194d4057d8SBen Gras
5204d4057d8SBen Gras
5214d4057d8SBen Gras static void
mangle(char * opts,int * argcp,const char ** volatile * argvp,int * maxargcp)5224d4057d8SBen Gras mangle(char *opts, int *argcp, const char ** volatile *argvp, int *maxargcp)
5234d4057d8SBen Gras {
5244d4057d8SBen Gras char *p, *s;
5254d4057d8SBen Gras int argc, maxargc;
5264d4057d8SBen Gras const char **argv;
5274d4057d8SBen Gras
5284d4057d8SBen Gras argc = *argcp;
5294d4057d8SBen Gras argv = *argvp;
5304d4057d8SBen Gras maxargc = *maxargcp;
5314d4057d8SBen Gras
5324d4057d8SBen Gras for (s = opts; (p = strsep(&s, ",")) != NULL;) {
5334d4057d8SBen Gras /* Always leave space for one more argument and the NULL. */
5344d4057d8SBen Gras if (argc >= maxargc - 3) {
5354d4057d8SBen Gras maxargc <<= 1;
5364d4057d8SBen Gras argv = erealloc(argv, maxargc * sizeof(char *));
5374d4057d8SBen Gras }
5384d4057d8SBen Gras if (*p != '\0') {
5394d4057d8SBen Gras if (*p == '-') {
5404d4057d8SBen Gras argv[argc++] = p;
5414d4057d8SBen Gras p = strchr(p, '=');
5424d4057d8SBen Gras if (p) {
5434d4057d8SBen Gras *p = '\0';
5444d4057d8SBen Gras argv[argc++] = p+1;
5454d4057d8SBen Gras }
5464d4057d8SBen Gras } else {
5474d4057d8SBen Gras argv[argc++] = "-o";
5484d4057d8SBen Gras argv[argc++] = p;
5494d4057d8SBen Gras }
5504d4057d8SBen Gras }
5514d4057d8SBen Gras }
5524d4057d8SBen Gras
5534d4057d8SBen Gras *argcp = argc;
5544d4057d8SBen Gras *argvp = argv;
5554d4057d8SBen Gras *maxargcp = maxargc;
5564d4057d8SBen Gras }
5574d4057d8SBen Gras
5584d4057d8SBen Gras static const char *
getfslab(const char * str)5594d4057d8SBen Gras getfslab(const char *str)
5604d4057d8SBen Gras {
56184d9c625SLionel Sambuc #if defined(__minix)
56294715d8eSBen Gras errx(1, "cannot determine vfstype under minix");
56394715d8eSBen Gras #else
5644d4057d8SBen Gras static struct dkwedge_info dkw;
5654d4057d8SBen Gras struct disklabel dl;
5664d4057d8SBen Gras int fd;
5674d4057d8SBen Gras char p;
5684d4057d8SBen Gras const char *vfstype;
5694d4057d8SBen Gras u_char t;
5704d4057d8SBen Gras
5714d4057d8SBen Gras /* deduce the file system type from the disk label */
5724d4057d8SBen Gras if ((fd = open(str, O_RDONLY)) == -1)
5734d4057d8SBen Gras err(1, "cannot open `%s'", str);
5744d4057d8SBen Gras
5754d4057d8SBen Gras /* First check to see if it's a wedge. */
5764d4057d8SBen Gras if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == 0) {
5774d4057d8SBen Gras /* Yup, this is easy. */
5784d4057d8SBen Gras (void) close(fd);
5794d4057d8SBen Gras return (dkw.dkw_ptype);
5804d4057d8SBen Gras }
5814d4057d8SBen Gras
5824d4057d8SBen Gras if (ioctl(fd, DIOCGDINFO, &dl) == -1)
5834d4057d8SBen Gras err(1, "cannot get disklabel for `%s'", str);
5844d4057d8SBen Gras
5854d4057d8SBen Gras (void) close(fd);
5864d4057d8SBen Gras
5874d4057d8SBen Gras p = str[strlen(str) - 1];
5884d4057d8SBen Gras
5894d4057d8SBen Gras if ((p - 'a') >= dl.d_npartitions)
5904d4057d8SBen Gras errx(1, "partition `%s' is not defined on disk", str);
5914d4057d8SBen Gras
5924d4057d8SBen Gras if ((t = dl.d_partitions[p - 'a'].p_fstype) >= FSMAXTYPES)
5934d4057d8SBen Gras errx(1, "partition `%s' is not of a legal vfstype",
5944d4057d8SBen Gras str);
5954d4057d8SBen Gras
5964d4057d8SBen Gras if ((vfstype = fscknames[t]) == NULL)
5974d4057d8SBen Gras errx(1, "vfstype `%s' on partition `%s' is not supported",
5984d4057d8SBen Gras fstypenames[t], str);
5994d4057d8SBen Gras
6004d4057d8SBen Gras return vfstype;
60184d9c625SLionel Sambuc #endif /* defined(__minix) */
6024d4057d8SBen Gras }
6034d4057d8SBen Gras
6044d4057d8SBen Gras
6054d4057d8SBen Gras static void
usage(void)6064d4057d8SBen Gras usage(void)
6074d4057d8SBen Gras {
6084d4057d8SBen Gras static const char common[] =
6094d4057d8SBen Gras "[-dfnPpqvy] [-x excludemount] [-l maxparallel] [-T fstype:fsoptions]\n\t\t[-t fstype]";
6104d4057d8SBen Gras
6114d4057d8SBen Gras (void)fprintf(stderr, "usage: %s %s [special|node]...\n",
6124d4057d8SBen Gras getprogname(), common);
6134d4057d8SBen Gras exit(FSCK_EXIT_USAGE);
6144d4057d8SBen Gras }
615