1*19722ca2Smlelstv /* $NetBSD: fsck.c,v 1.53 2023/01/24 08:09:37 mlelstv Exp $ */
2bf07c871Sagc
3bf07c871Sagc /*
47570f6e8Schristos * Copyright (c) 1996 Christos Zoulas. All rights reserved.
5bf07c871Sagc * Copyright (c) 1980, 1989, 1993, 1994
6bf07c871Sagc * The Regents of the University of California. All rights reserved.
7bf07c871Sagc *
8bf07c871Sagc * Redistribution and use in source and binary forms, with or without
9bf07c871Sagc * modification, are permitted provided that the following conditions
10bf07c871Sagc * are met:
11bf07c871Sagc * 1. Redistributions of source code must retain the above copyright
12bf07c871Sagc * notice, this list of conditions and the following disclaimer.
13bf07c871Sagc * 2. Redistributions in binary form must reproduce the above copyright
14bf07c871Sagc * notice, this list of conditions and the following disclaimer in the
15bf07c871Sagc * documentation and/or other materials provided with the distribution.
16bf07c871Sagc * 3. Neither the name of the University nor the names of its contributors
17bf07c871Sagc * may be used to endorse or promote products derived from this software
18bf07c871Sagc * without specific prior written permission.
19bf07c871Sagc *
20bf07c871Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21bf07c871Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22bf07c871Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23bf07c871Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24bf07c871Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25bf07c871Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26bf07c871Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27bf07c871Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28bf07c871Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29bf07c871Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30bf07c871Sagc * SUCH DAMAGE.
31bf07c871Sagc *
32bf07c871Sagc * From: @(#)mount.c 8.19 (Berkeley) 4/19/94
33bf07c871Sagc * From: NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp
34bf07c871Sagc *
35bf07c871Sagc */
3680411b33Schristos
3726ba0ba0Slukem #include <sys/cdefs.h>
3826ba0ba0Slukem #ifndef lint
39*19722ca2Smlelstv __RCSID("$NetBSD: fsck.c,v 1.53 2023/01/24 08:09:37 mlelstv Exp $");
4026ba0ba0Slukem #endif /* not lint */
4180411b33Schristos
4280411b33Schristos #include <sys/param.h>
4380411b33Schristos #include <sys/mount.h>
4480411b33Schristos #include <sys/queue.h>
4580411b33Schristos #include <sys/wait.h>
467b57bf6dSchristos #define FSTYPENAMES
477b57bf6dSchristos #define FSCKNAMES
48ef92b0deSthorpej #include <sys/disk.h>
49468b0bc4Schristos #include <sys/disklabel.h>
50468b0bc4Schristos #include <sys/ioctl.h>
5180411b33Schristos
5280411b33Schristos #include <err.h>
5380411b33Schristos #include <errno.h>
5480411b33Schristos #include <fstab.h>
55468b0bc4Schristos #include <fcntl.h>
566d094b5bSabs #include <paths.h>
5780411b33Schristos #include <signal.h>
5880411b33Schristos #include <stdio.h>
5980411b33Schristos #include <stdlib.h>
6080411b33Schristos #include <string.h>
6180411b33Schristos #include <unistd.h>
622a1607d0Schristos #include <util.h>
6380411b33Schristos
6480411b33Schristos #include "pathnames.h"
657dfca760Schristos #include "fsutil.h"
66742b48d5Schristos #include "exitvalues.h"
6780411b33Schristos
68fdf6ea6cSchristos static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST;
6980411b33Schristos
TAILQ_HEAD(fstypelist,entry)70639f5975Schristos TAILQ_HEAD(fstypelist, entry) opthead, selhead, omhead;
7180411b33Schristos
7280411b33Schristos struct entry {
7380411b33Schristos char *type;
74fdf6ea6cSchristos char *options;
7580411b33Schristos TAILQ_ENTRY(entry) entries;
7680411b33Schristos };
7780411b33Schristos
787dfca760Schristos static int maxrun = 0;
79fdf6ea6cSchristos static char *options = NULL;
807dfca760Schristos static int flags = 0;
8180411b33Schristos
82f97f5096Slukem static int checkfs(const char *, const char *, const char *, void *, pid_t *);
83f97f5096Slukem static int selected(const char *);
84639f5975Schristos static int omitted(const char *);
85f97f5096Slukem static void addoption(char *);
86f97f5096Slukem static const char *getoptions(const char *);
87f97f5096Slukem static void addentry(struct fstypelist *, const char *, const char *);
88f97f5096Slukem static void maketypelist(char *);
89f97f5096Slukem static void catopt(char **, const char *);
9056641252Schristos static void mangle(char *, int *, const char ** volatile *, int *);
91f97f5096Slukem static const char *getfslab(const char *);
926923d07cSjoerg __dead static void usage(void);
93f97f5096Slukem static void *isok(struct fstab *);
9480411b33Schristos
9580411b33Schristos int
main(int argc,char * argv[])96f97f5096Slukem main(int argc, char *argv[])
9780411b33Schristos {
9880411b33Schristos struct fstab *fs;
99742b48d5Schristos int i, rval;
10048ba78aaSmycroft const char *vfstype = NULL;
101c623b74bSchristos char globopt[3];
102742b48d5Schristos int ret = FSCK_EXIT_OK;
1035727faddSchristos char buf[MAXPATHLEN];
104c623b74bSchristos
105c623b74bSchristos globopt[0] = '-';
106c623b74bSchristos globopt[2] = '\0';
10780411b33Schristos
108fdf6ea6cSchristos TAILQ_INIT(&selhead);
109fdf6ea6cSchristos TAILQ_INIT(&opthead);
110639f5975Schristos TAILQ_INIT(&omhead);
111fdf6ea6cSchristos
112639f5975Schristos while ((i = getopt(argc, argv, "dfl:nPpqT:t:vx:y")) != -1) {
11380411b33Schristos switch (i) {
11480411b33Schristos case 'd':
1157dfca760Schristos flags |= CHECK_DEBUG;
116e69ce3e4Sdsl continue;
117e69ce3e4Sdsl
118e69ce3e4Sdsl case 'f':
119e69ce3e4Sdsl flags |= CHECK_FORCE;
12080411b33Schristos break;
12180411b33Schristos
122e69ce3e4Sdsl case 'n':
1235f101a47Schristos flags |= CHECK_NOFIX;
12480411b33Schristos break;
12580411b33Schristos
126c623b74bSchristos case 'p':
127c623b74bSchristos flags |= CHECK_PREEN;
128e69ce3e4Sdsl break;
129e69ce3e4Sdsl
130a73c2bd5Schristos case 'P':
131a73c2bd5Schristos flags |= CHECK_PROGRESS;
132a73c2bd5Schristos break;
133a73c2bd5Schristos
134e69ce3e4Sdsl case 'q':
135fdf6ea6cSchristos break;
136fdf6ea6cSchristos
137fdf6ea6cSchristos case 'l':
138fdf6ea6cSchristos maxrun = atoi(optarg);
139e69ce3e4Sdsl continue;
14080411b33Schristos
141fdf6ea6cSchristos case 'T':
14280411b33Schristos if (*optarg)
143fdf6ea6cSchristos addoption(optarg);
144e69ce3e4Sdsl continue;
14580411b33Schristos
14680411b33Schristos case 't':
147dacdbbf6Slukem if (TAILQ_FIRST(&selhead) != NULL)
14880411b33Schristos errx(1, "only one -t option may be specified.");
149fdf6ea6cSchristos
15080411b33Schristos maketypelist(optarg);
15180411b33Schristos vfstype = optarg;
152e69ce3e4Sdsl continue;
153e69ce3e4Sdsl
154e69ce3e4Sdsl case 'v':
155e69ce3e4Sdsl flags |= CHECK_VERBOSE;
156e69ce3e4Sdsl continue;
157e69ce3e4Sdsl
158639f5975Schristos case 'x':
159639f5975Schristos addentry(&omhead, optarg, "");
160626b19f8Shannken continue;
161639f5975Schristos
162e69ce3e4Sdsl case 'y':
16380411b33Schristos break;
16480411b33Schristos
16580411b33Schristos case '?':
16680411b33Schristos default:
16780411b33Schristos usage();
16880411b33Schristos /* NOTREACHED */
16980411b33Schristos }
17080411b33Schristos
171e69ce3e4Sdsl /* Pass option to fsck_xxxfs */
172e69ce3e4Sdsl globopt[1] = i;
173e69ce3e4Sdsl catopt(&options, globopt);
174e69ce3e4Sdsl }
175e69ce3e4Sdsl
176a73c2bd5Schristos /* Don't do progress meters if we're debugging. */
177a73c2bd5Schristos if (flags & CHECK_DEBUG)
178a73c2bd5Schristos flags &= ~CHECK_PROGRESS;
179a73c2bd5Schristos
180a73c2bd5Schristos /*
181a73c2bd5Schristos * If progress meters are being used, force max parallel to 1
182a73c2bd5Schristos * so the progress meter outputs don't interfere with one another.
183a73c2bd5Schristos */
184a73c2bd5Schristos if (flags & CHECK_PROGRESS)
185a73c2bd5Schristos maxrun = 1;
186a73c2bd5Schristos
18780411b33Schristos argc -= optind;
18880411b33Schristos argv += optind;
18980411b33Schristos
190fdf6ea6cSchristos if (argc == 0)
1917dfca760Schristos return checkfstab(flags, maxrun, isok, checkfs);
192fdf6ea6cSchristos
19380411b33Schristos #define BADTYPE(type) \
19480411b33Schristos (strcmp(type, FSTAB_RO) && \
19580411b33Schristos strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
19680411b33Schristos
19780411b33Schristos
19880411b33Schristos for (; argc--; argv++) {
199a62f667aSmlelstv const char *spec, *spec2, *mntpt, *type, *cp;
2006d094b5bSabs char device[MAXPATHLEN];
20180411b33Schristos
202a62f667aSmlelstv spec = mntpt = *argv;
203a62f667aSmlelstv spec2 = getfsspecname(buf, sizeof(buf), spec);
204a62f667aSmlelstv if (spec2 == NULL)
205a62f667aSmlelstv spec2 = spec;
206a62f667aSmlelstv
207a62f667aSmlelstv cp = strrchr(spec2, '/');
2086d094b5bSabs if (cp == 0) {
2096d094b5bSabs (void)snprintf(device, sizeof(device), "%s%s",
210a62f667aSmlelstv _PATH_DEV, spec2);
211a62f667aSmlelstv spec2 = device;
2126d094b5bSabs }
213a62f667aSmlelstv
214a62f667aSmlelstv fs = getfsfile(spec);
215a62f667aSmlelstv if (fs == NULL)
216a62f667aSmlelstv fs = getfsspec(spec);
217a62f667aSmlelstv if (fs == NULL && spec != spec2) {
218a62f667aSmlelstv fs = getfsspec(spec2);
219a62f667aSmlelstv spec = spec2;
22080411b33Schristos }
221a62f667aSmlelstv
222a62f667aSmlelstv if (fs) {
2235727faddSchristos spec = getfsspecname(buf, sizeof(buf), fs->fs_spec);
2245727faddSchristos if (spec == NULL)
2255727faddSchristos err(FSCK_EXIT_CHECK_FAILED, "%s", buf);
22680411b33Schristos type = fs->fs_vfstype;
22780411b33Schristos if (BADTYPE(fs->fs_type))
228742b48d5Schristos errx(FSCK_EXIT_CHECK_FAILED,
229742b48d5Schristos "%s has unknown file system type.",
2306d094b5bSabs spec);
231a62f667aSmlelstv } else {
232a62f667aSmlelstv if (vfstype == NULL)
233a62f667aSmlelstv vfstype = getfslab(spec);
234a62f667aSmlelstv type = vfstype;
23580411b33Schristos }
23680411b33Schristos
237742b48d5Schristos rval = checkfs(type, blockcheck(spec), *argv, NULL, NULL);
238742b48d5Schristos if (rval > ret)
239742b48d5Schristos ret = rval;
24080411b33Schristos }
24180411b33Schristos
242742b48d5Schristos return ret;
24380411b33Schristos }
24480411b33Schristos
245fdf6ea6cSchristos
2467dfca760Schristos static void *
isok(struct fstab * fs)247f97f5096Slukem isok(struct fstab *fs)
248fdf6ea6cSchristos {
249f97f5096Slukem
250fdf6ea6cSchristos if (fs->fs_passno == 0)
2517dfca760Schristos return NULL;
252fdf6ea6cSchristos
253fdf6ea6cSchristos if (BADTYPE(fs->fs_type))
2547dfca760Schristos return NULL;
255fdf6ea6cSchristos
256fdf6ea6cSchristos if (!selected(fs->fs_vfstype))
2577dfca760Schristos return NULL;
258fdf6ea6cSchristos
259639f5975Schristos if (omitted(fs->fs_file))
260639f5975Schristos return NULL;
261639f5975Schristos
2627dfca760Schristos return fs;
263fdf6ea6cSchristos }
264fdf6ea6cSchristos
265fdf6ea6cSchristos
266fdf6ea6cSchristos static int
checkfs(const char * vfst,const char * spec,const char * mntpt,void * auxarg,pid_t * pidp)267df99a4ddSchristos checkfs(const char *vfst, const char *spec, const char *mntpt, void *auxarg,
268f97f5096Slukem pid_t *pidp)
26980411b33Schristos {
27080411b33Schristos /* List of directories containing fsck_xxx subcommands. */
27180411b33Schristos static const char *edirs[] = {
272ea369b96Schristos #ifdef RESCUEDIR
273ea369b96Schristos RESCUEDIR,
2748f87d646Slukem #endif
27580411b33Schristos _PATH_SBIN,
27680411b33Schristos _PATH_USRSBIN,
27780411b33Schristos NULL
27880411b33Schristos };
27956641252Schristos const char ** volatile argv, **edir;
280df99a4ddSchristos const char * volatile vfstype = vfst;
28180411b33Schristos pid_t pid;
282e49dfa57Smycroft int argc, i, status, maxargc;
283df99a4ddSchristos char *optb;
284df99a4ddSchristos char *volatile optbuf;
285df99a4ddSchristos char execname[MAXPATHLEN + 1], execbase[MAXPATHLEN];
286fdf6ea6cSchristos const char *extra = getoptions(vfstype);
28780411b33Schristos
288e49dfa57Smycroft if (!strcmp(vfstype, "ufs"))
28946243af4Scgd vfstype = MOUNT_UFS;
29046243af4Scgd
291df99a4ddSchristos optb = NULL;
2923cd66a15Smycroft if (options)
293df99a4ddSchristos catopt(&optb, options);
2943cd66a15Smycroft if (extra)
295df99a4ddSchristos catopt(&optb, extra);
296df99a4ddSchristos optbuf = optb;
297fdf6ea6cSchristos
298e49dfa57Smycroft maxargc = 64;
299e49dfa57Smycroft argv = emalloc(sizeof(char *) * maxargc);
300e49dfa57Smycroft
301e49dfa57Smycroft (void) snprintf(execbase, sizeof(execbase), "fsck_%s", vfstype);
302e49dfa57Smycroft argc = 0;
303e49dfa57Smycroft argv[argc++] = execbase;
304fdf6ea6cSchristos if (optbuf)
305c623b74bSchristos mangle(optbuf, &argc, &argv, &maxargc);
30680411b33Schristos argv[argc++] = spec;
307c623b74bSchristos argv[argc] = NULL;
30880411b33Schristos
3097dfca760Schristos if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) {
310468b0bc4Schristos (void)printf("start %s %swait", mntpt,
311468b0bc4Schristos pidp ? "no" : "");
312468b0bc4Schristos for (i = 0; i < argc; i++)
31380411b33Schristos (void)printf(" %s", argv[i]);
31480411b33Schristos (void)printf("\n");
31580411b33Schristos }
31680411b33Schristos
31780411b33Schristos switch (pid = vfork()) {
31880411b33Schristos case -1: /* Error. */
31980411b33Schristos warn("vfork");
32080411b33Schristos if (optbuf)
32180411b33Schristos free(optbuf);
322635d7297Schristos free(argv);
323742b48d5Schristos return FSCK_EXIT_CHECK_FAILED;
32480411b33Schristos
32580411b33Schristos case 0: /* Child. */
326172a636bSlukem if ((flags & CHECK_FORCE) == 0) {
3276bd1d6d4Schristos struct statvfs sfs;
328172a636bSlukem
329172a636bSlukem /*
330172a636bSlukem * if mntpt is a mountpoint of a mounted file
331172a636bSlukem * system and it's mounted read-write, skip it
332172a636bSlukem * unless -f is given.
333172a636bSlukem */
3346bd1d6d4Schristos if ((statvfs(mntpt, &sfs) == 0) &&
335172a636bSlukem (strcmp(mntpt, sfs.f_mntonname) == 0) &&
3366bd1d6d4Schristos ((sfs.f_flag & MNT_RDONLY) == 0)) {
337172a636bSlukem printf(
338172a636bSlukem "%s: file system is mounted read-write on %s; not checking\n",
339172a636bSlukem spec, mntpt);
340172a636bSlukem if ((flags & CHECK_PREEN) && auxarg != NULL)
341742b48d5Schristos _exit(FSCK_EXIT_OK); /* fsck -p */
342172a636bSlukem else
343742b48d5Schristos _exit(FSCK_EXIT_CHECK_FAILED); /* fsck [[-p] ...] */
344172a636bSlukem }
345172a636bSlukem }
346172a636bSlukem
3477dfca760Schristos if (flags & CHECK_DEBUG)
348742b48d5Schristos _exit(FSCK_EXIT_OK);
349fdf6ea6cSchristos
35080411b33Schristos /* Go find an executable. */
35180411b33Schristos edir = edirs;
35280411b33Schristos do {
35380411b33Schristos (void)snprintf(execname,
354468b0bc4Schristos sizeof(execname), "%s/%s", *edir, execbase);
3552c6eadc9Schristos execv(execname, (char * const *)__UNCONST(argv));
356029a64ccSross if (errno != ENOENT) {
35780411b33Schristos if (spec)
35880411b33Schristos warn("exec %s for %s", execname, spec);
35980411b33Schristos else
36080411b33Schristos warn("exec %s", execname);
361029a64ccSross }
36280411b33Schristos } while (*++edir != NULL);
36380411b33Schristos
364029a64ccSross if (errno == ENOENT) {
36580411b33Schristos if (spec)
36680411b33Schristos warn("exec %s for %s", execname, spec);
36780411b33Schristos else
36880411b33Schristos warn("exec %s", execname);
369029a64ccSross }
370742b48d5Schristos _exit(FSCK_EXIT_CHECK_FAILED);
37180411b33Schristos /* NOTREACHED */
37280411b33Schristos
37380411b33Schristos default: /* Parent. */
37480411b33Schristos if (optbuf)
37580411b33Schristos free(optbuf);
376635d7297Schristos free(argv);
37780411b33Schristos
378fdf6ea6cSchristos if (pidp) {
379fdf6ea6cSchristos *pidp = pid;
380742b48d5Schristos return FSCK_EXIT_OK;
381fdf6ea6cSchristos }
382fdf6ea6cSchristos
38380411b33Schristos if (waitpid(pid, &status, 0) < 0) {
38480411b33Schristos warn("waitpid");
385742b48d5Schristos return FSCK_EXIT_CHECK_FAILED;
38680411b33Schristos }
38780411b33Schristos
38880411b33Schristos if (WIFEXITED(status)) {
38980411b33Schristos if (WEXITSTATUS(status) != 0)
390742b48d5Schristos return WEXITSTATUS(status);
39180411b33Schristos }
39280411b33Schristos else if (WIFSIGNALED(status)) {
39380411b33Schristos warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
394742b48d5Schristos return FSCK_EXIT_CHECK_FAILED;
39580411b33Schristos }
39680411b33Schristos break;
39780411b33Schristos }
39880411b33Schristos
399742b48d5Schristos return FSCK_EXIT_OK;
40080411b33Schristos }
40180411b33Schristos
40280411b33Schristos
40380411b33Schristos static int
selected(const char * type)404f97f5096Slukem selected(const char *type)
40580411b33Schristos {
40680411b33Schristos struct entry *e;
40780411b33Schristos
40880411b33Schristos /* If no type specified, it's always selected. */
409dacdbbf6Slukem TAILQ_FOREACH(e, &selhead, entries)
410fede0a77Schristos if (!strcmp(e->type, type))
41180411b33Schristos return which == IN_LIST ? 1 : 0;
41280411b33Schristos
41380411b33Schristos return which == IN_LIST ? 0 : 1;
41480411b33Schristos }
41580411b33Schristos
41680411b33Schristos
417639f5975Schristos static int
omitted(const char * mountedon)418639f5975Schristos omitted(const char *mountedon)
419639f5975Schristos {
420639f5975Schristos struct entry *e;
421639f5975Schristos
422639f5975Schristos /* If no type specified, it's always selected. */
423639f5975Schristos TAILQ_FOREACH(e, &omhead, entries)
424639f5975Schristos if (!strcmp(e->type, mountedon))
425639f5975Schristos return 1;
426639f5975Schristos
427639f5975Schristos return 0;
428639f5975Schristos }
429639f5975Schristos
430639f5975Schristos
431fdf6ea6cSchristos static const char *
getoptions(const char * type)432f97f5096Slukem getoptions(const char *type)
43380411b33Schristos {
43480411b33Schristos struct entry *e;
43580411b33Schristos
436dacdbbf6Slukem TAILQ_FOREACH(e, &opthead, entries)
437fede0a77Schristos if (!strcmp(e->type, type))
438fdf6ea6cSchristos return e->options;
439fdf6ea6cSchristos return "";
440fdf6ea6cSchristos }
441fdf6ea6cSchristos
442fdf6ea6cSchristos
443fdf6ea6cSchristos static void
addoption(char * optstr)444f97f5096Slukem addoption(char *optstr)
445fdf6ea6cSchristos {
446fdf6ea6cSchristos char *newoptions;
447fdf6ea6cSchristos struct entry *e;
448fdf6ea6cSchristos
449fdf6ea6cSchristos if ((newoptions = strchr(optstr, ':')) == NULL)
450fdf6ea6cSchristos errx(1, "Invalid option string");
451fdf6ea6cSchristos
452fdf6ea6cSchristos *newoptions++ = '\0';
453fdf6ea6cSchristos
454dacdbbf6Slukem TAILQ_FOREACH(e, &opthead, entries)
455fede0a77Schristos if (!strcmp(e->type, optstr)) {
4563cd66a15Smycroft catopt(&e->options, newoptions);
457fdf6ea6cSchristos return;
458fdf6ea6cSchristos }
459fdf6ea6cSchristos addentry(&opthead, optstr, newoptions);
460fdf6ea6cSchristos }
461fdf6ea6cSchristos
462fdf6ea6cSchristos
463fdf6ea6cSchristos static void
addentry(struct fstypelist * list,const char * type,const char * opts)464f97f5096Slukem addentry(struct fstypelist *list, const char *type, const char *opts)
465fdf6ea6cSchristos {
466fdf6ea6cSchristos struct entry *e;
467fdf6ea6cSchristos
46880411b33Schristos e = emalloc(sizeof(struct entry));
46980411b33Schristos e->type = estrdup(type);
470fdf6ea6cSchristos e->options = estrdup(opts);
471fdf6ea6cSchristos TAILQ_INSERT_TAIL(list, e, entries);
47280411b33Schristos }
47380411b33Schristos
47480411b33Schristos
47580411b33Schristos static void
maketypelist(char * fslist)476f97f5096Slukem maketypelist(char *fslist)
47780411b33Schristos {
47880411b33Schristos char *ptr;
47980411b33Schristos
48080411b33Schristos if ((fslist == NULL) || (fslist[0] == '\0'))
48180411b33Schristos errx(1, "empty type list");
48280411b33Schristos
48380411b33Schristos if (fslist[0] == 'n' && fslist[1] == 'o') {
48480411b33Schristos fslist += 2;
48580411b33Schristos which = NOT_IN_LIST;
48680411b33Schristos }
48780411b33Schristos else
48880411b33Schristos which = IN_LIST;
48980411b33Schristos
49080411b33Schristos while ((ptr = strsep(&fslist, ",")) != NULL)
491fdf6ea6cSchristos addentry(&selhead, ptr, "");
49280411b33Schristos
49380411b33Schristos }
49480411b33Schristos
49580411b33Schristos
4963cd66a15Smycroft static void
catopt(char ** sp,const char * o)497f97f5096Slukem catopt(char **sp, const char *o)
49880411b33Schristos {
4993cd66a15Smycroft char *s;
5003cd66a15Smycroft size_t i, j;
50180411b33Schristos
5023cd66a15Smycroft s = *sp;
5033cd66a15Smycroft if (s) {
5043cd66a15Smycroft i = strlen(s);
5053cd66a15Smycroft j = i + 1 + strlen(o) + 1;
5063cd66a15Smycroft s = erealloc(s, j);
5073cd66a15Smycroft (void)snprintf(s + i, j, ",%s", o);
508e49dfa57Smycroft } else
5093cd66a15Smycroft s = estrdup(o);
5103cd66a15Smycroft *sp = s;
51180411b33Schristos }
51280411b33Schristos
51380411b33Schristos
51480411b33Schristos static void
mangle(char * opts,int * argcp,const char ** volatile * argvp,int * maxargcp)51556641252Schristos mangle(char *opts, int *argcp, const char ** volatile *argvp, int *maxargcp)
51680411b33Schristos {
51780411b33Schristos char *p, *s;
518e49dfa57Smycroft int argc, maxargc;
519e49dfa57Smycroft const char **argv;
52080411b33Schristos
52180411b33Schristos argc = *argcp;
522e49dfa57Smycroft argv = *argvp;
523c623b74bSchristos maxargc = *maxargcp;
524c623b74bSchristos
5254475e174Slukem for (s = opts; (p = strsep(&s, ",")) != NULL;) {
526e49dfa57Smycroft /* Always leave space for one more argument and the NULL. */
527c623b74bSchristos if (argc >= maxargc - 3) {
528e49dfa57Smycroft maxargc <<= 1;
529c623b74bSchristos argv = erealloc(argv, maxargc * sizeof(char *));
530c623b74bSchristos }
531029a64ccSross if (*p != '\0') {
53280411b33Schristos if (*p == '-') {
53380411b33Schristos argv[argc++] = p;
53480411b33Schristos p = strchr(p, '=');
53580411b33Schristos if (p) {
53680411b33Schristos *p = '\0';
53780411b33Schristos argv[argc++] = p+1;
53880411b33Schristos }
539e49dfa57Smycroft } else {
54080411b33Schristos argv[argc++] = "-o";
54180411b33Schristos argv[argc++] = p;
54280411b33Schristos }
543c623b74bSchristos }
544029a64ccSross }
54580411b33Schristos
54680411b33Schristos *argcp = argc;
547c623b74bSchristos *argvp = argv;
548c623b74bSchristos *maxargcp = maxargc;
54980411b33Schristos }
55080411b33Schristos
55156641252Schristos static const char *
getfslab(const char * str)552f97f5096Slukem getfslab(const char *str)
553468b0bc4Schristos {
554ef92b0deSthorpej static struct dkwedge_info dkw;
555468b0bc4Schristos struct disklabel dl;
556468b0bc4Schristos int fd;
55748ba78aaSmycroft char p;
55848ba78aaSmycroft const char *vfstype;
559468b0bc4Schristos u_char t;
560*19722ca2Smlelstv char buf[MAXPATHLEN];
561468b0bc4Schristos
562468b0bc4Schristos /* deduce the file system type from the disk label */
563*19722ca2Smlelstv if ((fd = opendisk(str, O_RDONLY, buf, sizeof(buf), 0)) == -1)
564*19722ca2Smlelstv err(1, "cannot open `%s'", buf);
565468b0bc4Schristos
566ef92b0deSthorpej /* First check to see if it's a wedge. */
567ef92b0deSthorpej if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == 0) {
568ef92b0deSthorpej /* Yup, this is easy. */
569ef92b0deSthorpej (void) close(fd);
570ef92b0deSthorpej return (dkw.dkw_ptype);
571ef92b0deSthorpej }
572ef92b0deSthorpej
573468b0bc4Schristos if (ioctl(fd, DIOCGDINFO, &dl) == -1)
574*19722ca2Smlelstv err(1, "cannot get disklabel for `%s'", buf);
575468b0bc4Schristos
576468b0bc4Schristos (void) close(fd);
577468b0bc4Schristos
578*19722ca2Smlelstv p = buf[strlen(buf) - 1];
579468b0bc4Schristos
580468b0bc4Schristos if ((p - 'a') >= dl.d_npartitions)
581*19722ca2Smlelstv errx(1, "partition `%s' is not defined on disk", buf);
582468b0bc4Schristos
5837cdf2a0dSbouyer if ((t = dl.d_partitions[p - 'a'].p_fstype) >= FSMAXTYPES)
584468b0bc4Schristos errx(1, "partition `%s' is not of a legal vfstype",
585*19722ca2Smlelstv buf);
586468b0bc4Schristos
587468b0bc4Schristos if ((vfstype = fscknames[t]) == NULL)
588468b0bc4Schristos errx(1, "vfstype `%s' on partition `%s' is not supported",
589*19722ca2Smlelstv fstypenames[t], buf);
590468b0bc4Schristos
591468b0bc4Schristos return vfstype;
592468b0bc4Schristos }
593468b0bc4Schristos
594468b0bc4Schristos
59580411b33Schristos static void
usage(void)596f97f5096Slukem usage(void)
59780411b33Schristos {
598fdf6ea6cSchristos static const char common[] =
599639f5975Schristos "[-dfnPpqvy] [-x excludemount] [-l maxparallel] [-T fstype:fsoptions]\n\t\t[-t fstype]";
60080411b33Schristos
601b635f565Sjmmv (void)fprintf(stderr, "usage: %s %s [special|node]...\n",
6028a986b2eScgd getprogname(), common);
603742b48d5Schristos exit(FSCK_EXIT_USAGE);
60480411b33Schristos }
605