xref: /openbsd-src/sbin/fsck/fsck.c (revision bc5a8259a456844c67e446bf6bd66575acc64837)
1*bc5a8259Sbeck /*	$OpenBSD: fsck.c,v 1.41 2021/07/12 15:09:18 beck Exp $	*/
287304b87Stholo /*	$NetBSD: fsck.c,v 1.7 1996/10/03 20:06:30 christos Exp $	*/
387304b87Stholo 
487304b87Stholo /*
587304b87Stholo  * Copyright (c) 1996 Christos Zoulas. All rights reserved.
687304b87Stholo  * Copyright (c) 1980, 1989, 1993, 1994
787304b87Stholo  *	The Regents of the University of California.  All rights reserved.
887304b87Stholo  *
987304b87Stholo  * Redistribution and use in source and binary forms, with or without
1087304b87Stholo  * modification, are permitted provided that the following conditions
1187304b87Stholo  * are met:
1287304b87Stholo  * 1. Redistributions of source code must retain the above copyright
1387304b87Stholo  *    notice, this list of conditions and the following disclaimer.
1487304b87Stholo  * 2. Redistributions in binary form must reproduce the above copyright
1587304b87Stholo  *    notice, this list of conditions and the following disclaimer in the
1687304b87Stholo  *    documentation and/or other materials provided with the distribution.
171ef0d710Smillert  * 3. Neither the name of the University nor the names of its contributors
1887304b87Stholo  *    may be used to endorse or promote products derived from this software
1987304b87Stholo  *    without specific prior written permission.
2087304b87Stholo  *
2187304b87Stholo  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2287304b87Stholo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2387304b87Stholo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2487304b87Stholo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2587304b87Stholo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2687304b87Stholo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2787304b87Stholo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2887304b87Stholo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2987304b87Stholo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3087304b87Stholo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3187304b87Stholo  * SUCH DAMAGE.
3287304b87Stholo  *
3387304b87Stholo  * From: @(#)mount.c	8.19 (Berkeley) 4/19/94
3487304b87Stholo  * From: NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp
3587304b87Stholo  *
3687304b87Stholo  */
3787304b87Stholo 
38b9fc9a72Sderaadt #include <sys/types.h>
3987304b87Stholo #include <sys/mount.h>
4087304b87Stholo #include <sys/queue.h>
4164717ec7Smillert #include <sys/resource.h>
42c9112980Sderaadt #include <sys/stat.h>
4387304b87Stholo #include <sys/wait.h>
4487304b87Stholo 
4587304b87Stholo #include <err.h>
4687304b87Stholo #include <errno.h>
4787304b87Stholo #include <fstab.h>
4887304b87Stholo #include <signal.h>
4987304b87Stholo #include <stdio.h>
5087304b87Stholo #include <stdlib.h>
5187304b87Stholo #include <string.h>
5287304b87Stholo #include <unistd.h>
53b9fc9a72Sderaadt #include <limits.h>
545a93b9deSderaadt #include <util.h>
5587304b87Stholo 
5687304b87Stholo #include "pathnames.h"
5787304b87Stholo #include "fsutil.h"
5887304b87Stholo 
5987304b87Stholo static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST;
602babb8b2Sclaudio static enum { NONET_FILTER, NET_FILTER } filter = NONET_FILTER;
6187304b87Stholo 
TAILQ_HEAD(fstypelist,entry)6287304b87Stholo TAILQ_HEAD(fstypelist, entry) opthead, selhead;
6387304b87Stholo 
6487304b87Stholo struct entry {
6587304b87Stholo 	char *type;
6687304b87Stholo 	char *options;
6787304b87Stholo 	TAILQ_ENTRY(entry) entries;
6887304b87Stholo };
6987304b87Stholo 
702babb8b2Sclaudio static int maxrun;
712babb8b2Sclaudio static char *options;
722babb8b2Sclaudio static int flags;
7387304b87Stholo 
74c72b5b24Smillert int main(int, char *[]);
7587304b87Stholo 
76f3c3a9c6Smillert static int checkfs(const char *, const char *, const char *, void *, pid_t *);
77c72b5b24Smillert static int selected(const char *);
78c72b5b24Smillert static void addoption(char *);
79c72b5b24Smillert static const char *getoptions(const char *);
80c72b5b24Smillert static void addentry(struct fstypelist *, const char *, const char *);
81c72b5b24Smillert static void maketypelist(char *);
82c72b5b24Smillert static char *catopt(char *, const char *, int);
83c72b5b24Smillert static void mangle(char *, int *, const char ***, int *);
84c72b5b24Smillert static void usage(void);
85c72b5b24Smillert static void *isok(struct fstab *);
862babb8b2Sclaudio static int hasopt(const char *, const char *);
8787304b87Stholo 
8887304b87Stholo 
8987304b87Stholo int
main(int argc,char * argv[])90bc52e260Sderaadt main(int argc, char *argv[])
9187304b87Stholo {
92a47b6461Sderaadt 	const char *errstr;
9387304b87Stholo 	struct fstab *fs;
9487304b87Stholo 	int i, rval = 0;
9587304b87Stholo 	char *vfstype = NULL;
9687e5b1dbSmillert 	char *p, globopt[3];
9764717ec7Smillert 	struct rlimit rl;
9864717ec7Smillert 
9964717ec7Smillert 	/* Increase our data size to the max */
10064717ec7Smillert 	if (getrlimit(RLIMIT_DATA, &rl) == 0) {
1013b47bd06Smillert 		if (geteuid() == 0)
1023b47bd06Smillert 			rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
1033b47bd06Smillert 		else
10464717ec7Smillert 			rl.rlim_cur = rl.rlim_max;
105df69c215Sderaadt 		if (setrlimit(RLIMIT_DATA, &rl) == -1)
10666c75fc7Smillert 			warn("Can't set resource limit to max data size");
10764717ec7Smillert 	} else
10864717ec7Smillert 		warn("Can't get resource limit for data size");
10987304b87Stholo 
110c9112980Sderaadt 	checkroot();
111c9112980Sderaadt 
112c9112980Sderaadt 	if (unveil("/dev", "rw") == -1)
113*bc5a8259Sbeck 		err(1, "unveil /dev");
114c9112980Sderaadt 	if (unveil(_PATH_FSTAB, "r") == -1)
115*bc5a8259Sbeck 		err(1, "unveil %s", _PATH_FSTAB);
116c9112980Sderaadt 	if (unveil("/sbin", "x") == -1)
117*bc5a8259Sbeck 		err(1, "unveil /sbin");
118e384f6efSderaadt 	if (pledge("stdio rpath wpath disklabel proc exec", NULL) == -1)
119e384f6efSderaadt 		err(1, "pledge");
120e384f6efSderaadt 
12187304b87Stholo 	globopt[0] = '-';
12287304b87Stholo 	globopt[2] = '\0';
12387304b87Stholo 
12487304b87Stholo 	TAILQ_INIT(&selhead);
12587304b87Stholo 	TAILQ_INIT(&opthead);
12687304b87Stholo 
1272babb8b2Sclaudio 	while ((i = getopt(argc, argv, "b:dfl:nNpT:t:vy")) != -1)
12887304b87Stholo 		switch (i) {
12987304b87Stholo 		case 'd':
13087304b87Stholo 			flags |= CHECK_DEBUG;
13187304b87Stholo 			break;
13287304b87Stholo 
13387304b87Stholo 		case 'v':
13487304b87Stholo 			flags |= CHECK_VERBOSE;
13587304b87Stholo 			break;
13687304b87Stholo 
13787304b87Stholo 		case 'p':
13887304b87Stholo 			flags |= CHECK_PREEN;
13987304b87Stholo 			/*FALLTHROUGH*/
14087304b87Stholo 		case 'n':
14187304b87Stholo 		case 'f':
14287304b87Stholo 		case 'y':
14387304b87Stholo 			globopt[1] = i;
14487304b87Stholo 			options = catopt(options, globopt, 1);
14587304b87Stholo 			break;
14687304b87Stholo 
14787e5b1dbSmillert 		case 'b':
14887e5b1dbSmillert 			if (asprintf(&p, "-b %s", optarg) == -1)
14987e5b1dbSmillert 				err(1, "malloc failed");
15087e5b1dbSmillert 			options = catopt(options, p, 1);
15187e5b1dbSmillert 			free(p);
15287e5b1dbSmillert 			break;
15387e5b1dbSmillert 
15487304b87Stholo 		case 'l':
155a47b6461Sderaadt 			maxrun = strtonum(optarg, 0, INT_MAX, &errstr);
156a47b6461Sderaadt 			if (errstr)
157a47b6461Sderaadt 				errx(1, "-l %s: %s", optarg, errstr);
158a47b6461Sderaadt 
15987304b87Stholo 			break;
16087304b87Stholo 
16187304b87Stholo 		case 'T':
16287304b87Stholo 			if (*optarg)
16387304b87Stholo 				addoption(optarg);
16487304b87Stholo 			break;
16587304b87Stholo 
16687304b87Stholo 		case 't':
16774c87c28Sotto 			if (!TAILQ_EMPTY(&selhead))
16887304b87Stholo 				errx(1, "only one -t option may be specified.");
16987304b87Stholo 
17087304b87Stholo 			maketypelist(optarg);
17187304b87Stholo 			vfstype = optarg;
17287304b87Stholo 			break;
17387304b87Stholo 
1742babb8b2Sclaudio 		case 'N':
1752babb8b2Sclaudio 			filter = NET_FILTER;
1762babb8b2Sclaudio 			break;
1772babb8b2Sclaudio 
17887304b87Stholo 		case '?':
17987304b87Stholo 		default:
18087304b87Stholo 			usage();
18187304b87Stholo 			/* NOTREACHED */
18287304b87Stholo 		}
18387304b87Stholo 
18487304b87Stholo 	argc -= optind;
18587304b87Stholo 	argv += optind;
18687304b87Stholo 
18787304b87Stholo 	if (argc == 0)
18887304b87Stholo 		return checkfstab(flags, maxrun, isok, checkfs);
18987304b87Stholo 
19087304b87Stholo #define	BADTYPE(type)							\
19187304b87Stholo 	(strcmp(type, FSTAB_RO) &&					\
19287304b87Stholo 	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
19387304b87Stholo 
19487304b87Stholo 
19587304b87Stholo 	for (; argc--; argv++) {
19687304b87Stholo 		char *spec, *type;
19787304b87Stholo 
19897e25138Sjsing 		if ((strncmp(*argv, "/dev/", 5) == 0 || isduid(*argv, 0)) &&
19957bc3e67Sdownsj 		    (type = readlabelfs(*argv, 0))) {
2005a93b9deSderaadt 			spec = *argv;
2015a93b9deSderaadt 		} else if ((fs = getfsfile(*argv)) == NULL &&
20287304b87Stholo 		    (fs = getfsspec(*argv)) == NULL) {
20387304b87Stholo 			if (vfstype == NULL)
20487304b87Stholo 				errx(1,
20587304b87Stholo 				    "%s: unknown special file or file system.",
20687304b87Stholo 				    *argv);
20787304b87Stholo 			spec = *argv;
20887304b87Stholo 			type = vfstype;
2095a93b9deSderaadt 		} else {
21087304b87Stholo 			spec = fs->fs_spec;
21187304b87Stholo 			type = fs->fs_vfstype;
21287304b87Stholo 			if (BADTYPE(fs->fs_type))
21387304b87Stholo 				errx(1, "%s has unknown file system type.",
21487304b87Stholo 				    *argv);
21587304b87Stholo 		}
21687304b87Stholo 
21787304b87Stholo 		rval |= checkfs(type, blockcheck(spec), *argv, NULL, NULL);
21887304b87Stholo 	}
21987304b87Stholo 
22087304b87Stholo 	return rval;
22187304b87Stholo }
22287304b87Stholo 
22387304b87Stholo 
22487304b87Stholo static void *
isok(struct fstab * fs)225bc52e260Sderaadt isok(struct fstab *fs)
22687304b87Stholo {
22787304b87Stholo 	if (fs->fs_passno == 0)
22887304b87Stholo 		return NULL;
22987304b87Stholo 
23087304b87Stholo 	if (BADTYPE(fs->fs_type))
23187304b87Stholo 		return NULL;
23287304b87Stholo 
2332babb8b2Sclaudio 	switch (filter) {
2342babb8b2Sclaudio 	case NET_FILTER:
2352babb8b2Sclaudio 		if (!hasopt(fs->fs_mntops, "net"))
2362babb8b2Sclaudio 			return NULL;
2372babb8b2Sclaudio 		break;
2382babb8b2Sclaudio 	case NONET_FILTER:
2392babb8b2Sclaudio 		if (hasopt(fs->fs_mntops, "net"))
2402babb8b2Sclaudio 			return NULL;
2412babb8b2Sclaudio 		break;
2422babb8b2Sclaudio 	}
24387304b87Stholo 	if (!selected(fs->fs_vfstype))
24487304b87Stholo 		return NULL;
24587304b87Stholo 
24687304b87Stholo 	return fs;
24787304b87Stholo }
24887304b87Stholo 
24987304b87Stholo 
25087304b87Stholo static int
checkfs(const char * vfstype,const char * spec,const char * mntpt,void * auxarg,pid_t * pidp)251bc52e260Sderaadt checkfs(const char *vfstype, const char *spec, const char *mntpt, void *auxarg,
252bc52e260Sderaadt     pid_t *pidp)
25387304b87Stholo {
25487304b87Stholo 	/* List of directories containing fsck_xxx subcommands. */
25587304b87Stholo 	static const char *edirs[] = {
25687304b87Stholo 		_PATH_SBIN,
25787304b87Stholo 		_PATH_USRSBIN,
25887304b87Stholo 		NULL
25987304b87Stholo 	};
26087304b87Stholo 	const char **argv, **edir;
26187304b87Stholo 	pid_t pid;
26287304b87Stholo 	int argc, i, status, maxargc;
263b9fc9a72Sderaadt 	char *optbuf = NULL, fsname[PATH_MAX], execname[PATH_MAX];
26487304b87Stholo 	const char *extra = getoptions(vfstype);
26587304b87Stholo 
26687304b87Stholo 	if (strcmp(vfstype, "ufs") == 0)
26787304b87Stholo 		vfstype = MOUNT_UFS;
26887304b87Stholo 
26987304b87Stholo 	maxargc = 100;
2706d0985b9Sderaadt 	argv = ereallocarray(NULL, maxargc, sizeof(char *));
27187304b87Stholo 
27287304b87Stholo 	argc = 0;
27333486055Sderaadt 	(void)snprintf(fsname, sizeof(fsname), "fsck_%s", vfstype);
27433486055Sderaadt 	argv[argc++] = fsname;
27587304b87Stholo 
27687304b87Stholo 	if (options) {
27787304b87Stholo 		if (extra != NULL)
27887304b87Stholo 			optbuf = catopt(options, extra, 0);
27987304b87Stholo 		else
28087304b87Stholo 			optbuf = estrdup(options);
28187304b87Stholo 	}
28287304b87Stholo 	else if (extra)
28387304b87Stholo 		optbuf = estrdup(extra);
28487304b87Stholo 
28587304b87Stholo 	if (optbuf)
28687304b87Stholo 		mangle(optbuf, &argc, &argv, &maxargc);
28787304b87Stholo 
28887304b87Stholo 	argv[argc++] = spec;
28987304b87Stholo 	argv[argc] = NULL;
29087304b87Stholo 
29187304b87Stholo 	if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) {
29233486055Sderaadt 		(void)printf("start %s %swait %s", mntpt,
29333486055Sderaadt 			pidp ? "no" : "", fsname);
29487304b87Stholo 		for (i = 1; i < argc; i++)
29587304b87Stholo 			(void)printf(" %s", argv[i]);
29687304b87Stholo 		(void)printf("\n");
29787304b87Stholo 	}
29887304b87Stholo 
29933486055Sderaadt 	switch (pid = fork()) {
30087304b87Stholo 	case -1:				/* Error. */
301d138bb61Sderaadt 		warn("fork");
30287304b87Stholo 		free(optbuf);
30318c2ce40Sdhill 		free(argv);
30487304b87Stholo 		return (1);
30587304b87Stholo 
30687304b87Stholo 	case 0:					/* Child. */
30787304b87Stholo 		if (flags & CHECK_DEBUG)
30887304b87Stholo 			_exit(0);
30987304b87Stholo 
31087304b87Stholo 		/* Go find an executable. */
31187304b87Stholo 		edir = edirs;
31287304b87Stholo 		do {
31387304b87Stholo 			(void)snprintf(execname,
31487304b87Stholo 			    sizeof(execname), "%s/fsck_%s", *edir, vfstype);
31587304b87Stholo 			execv(execname, (char * const *)argv);
316a4df0321Sderaadt 			if (errno != ENOENT) {
31787304b87Stholo 				if (spec)
31887304b87Stholo 					warn("exec %s for %s", execname, spec);
31987304b87Stholo 				else
32087304b87Stholo 					warn("exec %s", execname);
321a4df0321Sderaadt 			}
32287304b87Stholo 		} while (*++edir != NULL);
32387304b87Stholo 
324a4df0321Sderaadt 		if (errno == ENOENT) {
32587304b87Stholo 			if (spec)
32687304b87Stholo 				warn("exec %s for %s", execname, spec);
32787304b87Stholo 			else
32887304b87Stholo 				warn("exec %s", execname);
329a4df0321Sderaadt 		}
33087304b87Stholo 		exit(1);
33187304b87Stholo 		/* NOTREACHED */
33287304b87Stholo 
33387304b87Stholo 	default:				/* Parent. */
33487304b87Stholo 		free(optbuf);
33518c2ce40Sdhill 		free(argv);
33687304b87Stholo 
33787304b87Stholo 		if (pidp) {
33887304b87Stholo 			*pidp = pid;
33987304b87Stholo 			return 0;
34087304b87Stholo 		}
34187304b87Stholo 
342df69c215Sderaadt 		if (waitpid(pid, &status, 0) == -1) {
34387304b87Stholo 			warn("waitpid");
34487304b87Stholo 			return (1);
34587304b87Stholo 		}
34687304b87Stholo 
34787304b87Stholo 		if (WIFEXITED(status)) {
34887304b87Stholo 			if (WEXITSTATUS(status) != 0)
34987304b87Stholo 				return (WEXITSTATUS(status));
35087304b87Stholo 		}
35187304b87Stholo 		else if (WIFSIGNALED(status)) {
35287304b87Stholo 			warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
35387304b87Stholo 			return (1);
35487304b87Stholo 		}
35587304b87Stholo 		break;
35687304b87Stholo 	}
35787304b87Stholo 
35887304b87Stholo 	return (0);
35987304b87Stholo }
36087304b87Stholo 
36187304b87Stholo 
36287304b87Stholo static int
selected(const char * type)363bc52e260Sderaadt selected(const char *type)
36487304b87Stholo {
36587304b87Stholo 	struct entry *e;
36687304b87Stholo 
36787304b87Stholo 	/* If no type specified, it's always selected. */
368441476a3Sotto 	TAILQ_FOREACH(e, &selhead, entries)
36987304b87Stholo 		if (!strncmp(e->type, type, MFSNAMELEN))
37087304b87Stholo 			return which == IN_LIST ? 1 : 0;
37187304b87Stholo 
37287304b87Stholo 	return which == IN_LIST ? 0 : 1;
37387304b87Stholo }
37487304b87Stholo 
37587304b87Stholo 
37687304b87Stholo static const char *
getoptions(const char * type)377bc52e260Sderaadt getoptions(const char *type)
37887304b87Stholo {
37987304b87Stholo 	struct entry *e;
38087304b87Stholo 
381441476a3Sotto 	TAILQ_FOREACH(e, &opthead, entries)
38287304b87Stholo 		if (!strncmp(e->type, type, MFSNAMELEN))
38387304b87Stholo 			return e->options;
38487304b87Stholo 	return "";
38587304b87Stholo }
38687304b87Stholo 
38787304b87Stholo 
38887304b87Stholo static void
addoption(char * optstr)389bc52e260Sderaadt addoption(char *optstr)
39087304b87Stholo {
39187304b87Stholo 	char *newoptions;
39287304b87Stholo 	struct entry *e;
39387304b87Stholo 
39487304b87Stholo 	if ((newoptions = strchr(optstr, ':')) == NULL)
39587304b87Stholo 		errx(1, "Invalid option string");
39687304b87Stholo 
39787304b87Stholo 	*newoptions++ = '\0';
39887304b87Stholo 
399441476a3Sotto 	TAILQ_FOREACH(e, &opthead, entries)
40087304b87Stholo 		if (!strncmp(e->type, optstr, MFSNAMELEN)) {
40187304b87Stholo 			e->options = catopt(e->options, newoptions, 1);
40287304b87Stholo 			return;
40387304b87Stholo 		}
40487304b87Stholo 	addentry(&opthead, optstr, newoptions);
40587304b87Stholo }
40687304b87Stholo 
40787304b87Stholo 
40887304b87Stholo static void
addentry(struct fstypelist * list,const char * type,const char * opts)409bc52e260Sderaadt addentry(struct fstypelist *list, const char *type, const char *opts)
41087304b87Stholo {
41187304b87Stholo 	struct entry *e;
41287304b87Stholo 
41387304b87Stholo 	e = emalloc(sizeof(struct entry));
41487304b87Stholo 	e->type = estrdup(type);
41587304b87Stholo 	e->options = estrdup(opts);
41687304b87Stholo 	TAILQ_INSERT_TAIL(list, e, entries);
41787304b87Stholo }
41887304b87Stholo 
41987304b87Stholo 
42087304b87Stholo static void
maketypelist(char * fslist)421bc52e260Sderaadt maketypelist(char *fslist)
42287304b87Stholo {
42387304b87Stholo 	char *ptr;
42487304b87Stholo 
42587304b87Stholo 	if ((fslist == NULL) || (fslist[0] == '\0'))
42687304b87Stholo 		errx(1, "empty type list");
42787304b87Stholo 
42887304b87Stholo 	if (fslist[0] == 'n' && fslist[1] == 'o') {
42987304b87Stholo 		fslist += 2;
43087304b87Stholo 		which = NOT_IN_LIST;
43187304b87Stholo 	}
43287304b87Stholo 	else
43387304b87Stholo 		which = IN_LIST;
43487304b87Stholo 
43587304b87Stholo 	while ((ptr = strsep(&fslist, ",")) != NULL)
43687304b87Stholo 		addentry(&selhead, ptr, "");
43787304b87Stholo 
43887304b87Stholo }
43987304b87Stholo 
44087304b87Stholo 
44187304b87Stholo static char *
catopt(char * s0,const char * s1,int fr)442bc52e260Sderaadt catopt(char *s0, const char *s1, int fr)
44387304b87Stholo {
44487304b87Stholo 	char *cp;
44587304b87Stholo 
44687304b87Stholo 	if (s0 && *s0) {
447e966780fSderaadt 		if (asprintf(&cp, "%s,%s", s0, s1) == -1)
448e966780fSderaadt 			err(1, "malloc failed");
449e966780fSderaadt 	} else
45087304b87Stholo 		cp = estrdup(s1);
45187304b87Stholo 
45234c2ea26Sderaadt 	if (fr)
45387304b87Stholo 		free(s0);
45487304b87Stholo 	return (cp);
45587304b87Stholo }
45687304b87Stholo 
45787304b87Stholo 
45887304b87Stholo static void
mangle(char * opts,int * argcp,const char *** argvp,int * maxargcp)459bc52e260Sderaadt mangle(char *opts, int *argcp, const char ***argvp, int *maxargcp)
46087304b87Stholo {
46187304b87Stholo 	char *p, *s;
46287304b87Stholo 	int argc = *argcp, maxargc = *maxargcp;
46387304b87Stholo 	const char **argv = *argvp;
46487304b87Stholo 
46587304b87Stholo 	for (s = opts; (p = strsep(&s, ",")) != NULL;) {
46687304b87Stholo 		/* always leave space for one more argument and the NULL */
46787304b87Stholo 		if (argc >= maxargc - 3) {
4684b05fed4Sderaadt 			int newmaxargc = maxargc + 50;
4694b05fed4Sderaadt 
470119ae1adSderaadt 			argv = ereallocarray(argv, newmaxargc, sizeof(char *));
471f76c2b66Sotto 			maxargc = newmaxargc;
47287304b87Stholo 		}
473a4df0321Sderaadt 		if (*p != '\0') {
47487304b87Stholo 			if (*p == '-') {
47587304b87Stholo 				argv[argc++] = p;
47687304b87Stholo 				p = strchr(p, '=');
47787304b87Stholo 				if (p) {
47887304b87Stholo 					*p = '\0';
47987304b87Stholo 					argv[argc++] = p+1;
48087304b87Stholo 				}
48187304b87Stholo 			}
48287304b87Stholo 			else {
48387304b87Stholo 				argv[argc++] = "-o";
48487304b87Stholo 				argv[argc++] = p;
48587304b87Stholo 			}
48687304b87Stholo 		}
487a4df0321Sderaadt 	}
48887304b87Stholo 
48987304b87Stholo 	*argcp = argc;
49087304b87Stholo 	*argvp = argv;
49187304b87Stholo 	*maxargcp = maxargc;
49287304b87Stholo }
49387304b87Stholo 
4942babb8b2Sclaudio static int
hasopt(const char * mntopts,const char * option)4952babb8b2Sclaudio hasopt(const char *mntopts, const char *option)
4962babb8b2Sclaudio {
4972babb8b2Sclaudio 	int found;
4982babb8b2Sclaudio 	char *opt, *optbuf;
4992babb8b2Sclaudio 
5002babb8b2Sclaudio 	if (mntopts == NULL)
5012babb8b2Sclaudio 		return (0);
5022babb8b2Sclaudio 	optbuf = strdup(mntopts);
5032babb8b2Sclaudio 	found = 0;
5042babb8b2Sclaudio 	for (opt = optbuf; !found && opt != NULL; strsep(&opt, ","))
5052babb8b2Sclaudio 		found = !strncmp(opt, option, strlen(option));
5062babb8b2Sclaudio 	free(optbuf);
5072babb8b2Sclaudio 	return (found);
5082babb8b2Sclaudio }
5092babb8b2Sclaudio 
51087304b87Stholo 
51187304b87Stholo static void
usage(void)512bc52e260Sderaadt usage(void)
51387304b87Stholo {
51487304b87Stholo 	extern char *__progname;
51587304b87Stholo 
516b28a0cb5Ssobrado 	fprintf(stderr, "usage: %s "
5170e3c8cccSjmc 	    "[-dfNnpvy] [-b block#] [-l maxparallel] [-T fstype:fsoptions]\n"
518b28a0cb5Ssobrado 	    "            [-t fstype] [special | node ...]\n", __progname);
51987304b87Stholo 	exit(1);
52087304b87Stholo }
521