xref: /minix3/sbin/fsck/fsck.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
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