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