xref: /openbsd-src/sbin/fsck/fsck.c (revision 57bc3e67b3431e45bcbf6d8889df3ad73c82ded2)
1*57bc3e67Sdownsj /*	$OpenBSD: fsck.c,v 1.5 1996/12/23 07:44:59 downsj 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.
1787304b87Stholo  * 3. All advertising materials mentioning features or use of this software
1887304b87Stholo  *    must display the following acknowledgement:
1987304b87Stholo  *	This product includes software developed by the University of
2087304b87Stholo  *	California, Berkeley and its contributors.
2187304b87Stholo  * 4. Neither the name of the University nor the names of its contributors
2287304b87Stholo  *    may be used to endorse or promote products derived from this software
2387304b87Stholo  *    without specific prior written permission.
2487304b87Stholo  *
2587304b87Stholo  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2687304b87Stholo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2787304b87Stholo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2887304b87Stholo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2987304b87Stholo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3087304b87Stholo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3187304b87Stholo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3287304b87Stholo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3387304b87Stholo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3487304b87Stholo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3587304b87Stholo  * SUCH DAMAGE.
3687304b87Stholo  *
3787304b87Stholo  * From: @(#)mount.c	8.19 (Berkeley) 4/19/94
3887304b87Stholo  * From: NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp
3987304b87Stholo  *
4087304b87Stholo  */
4187304b87Stholo 
4287304b87Stholo static char rcsid[] = "$NetBSD: fsck.c,v 1.7 1996/10/03 20:06:30 christos Exp $";
4387304b87Stholo 
4487304b87Stholo #include <sys/param.h>
4587304b87Stholo #include <sys/mount.h>
4687304b87Stholo #include <sys/queue.h>
4787304b87Stholo #include <sys/wait.h>
4887304b87Stholo 
4987304b87Stholo #include <err.h>
5087304b87Stholo #include <errno.h>
5187304b87Stholo #include <fstab.h>
5287304b87Stholo #include <signal.h>
5387304b87Stholo #include <stdio.h>
5487304b87Stholo #include <stdlib.h>
5587304b87Stholo #include <string.h>
5687304b87Stholo #include <unistd.h>
575a93b9deSderaadt #include <util.h>
5887304b87Stholo 
5987304b87Stholo #include "pathnames.h"
6087304b87Stholo #include "fsutil.h"
6187304b87Stholo 
6287304b87Stholo static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST;
6387304b87Stholo 
6487304b87Stholo TAILQ_HEAD(fstypelist, entry) opthead, selhead;
6587304b87Stholo 
6687304b87Stholo struct entry {
6787304b87Stholo 	char *type;
6887304b87Stholo 	char *options;
6987304b87Stholo 	TAILQ_ENTRY(entry) entries;
7087304b87Stholo };
7187304b87Stholo 
7287304b87Stholo static int maxrun = 0;
7387304b87Stholo static char *options = NULL;
7487304b87Stholo static int flags = 0;
7587304b87Stholo 
7687304b87Stholo int main __P((int, char *[]));
7787304b87Stholo 
7887304b87Stholo static int checkfs __P((const char *, const char *, const char *, void *,
7987304b87Stholo     pid_t *));
8087304b87Stholo static int selected __P((const char *));
8187304b87Stholo static void addoption __P((char *));
8287304b87Stholo static const char *getoptions __P((const char *));
8387304b87Stholo static void addentry __P((struct fstypelist *, const char *, const char *));
8487304b87Stholo static void maketypelist __P((char *));
8587304b87Stholo static char *catopt __P((char *, const char *, int));
8687304b87Stholo static void mangle __P((char *, int *, const char ***, int *));
8787304b87Stholo static void usage __P((void));
8887304b87Stholo static void *isok __P((struct fstab *));
8987304b87Stholo 
9087304b87Stholo 
9187304b87Stholo int
9287304b87Stholo main(argc, argv)
9387304b87Stholo 	int argc;
9487304b87Stholo 	char *argv[];
9587304b87Stholo {
9687304b87Stholo 	struct fstab *fs;
9787304b87Stholo 	int i, rval = 0;
9887304b87Stholo 	char *vfstype = NULL;
9987304b87Stholo 	char globopt[3];
10087304b87Stholo 
10187304b87Stholo 	globopt[0] = '-';
10287304b87Stholo 	globopt[2] = '\0';
10387304b87Stholo 
10487304b87Stholo 	TAILQ_INIT(&selhead);
10587304b87Stholo 	TAILQ_INIT(&opthead);
10687304b87Stholo 
10787304b87Stholo 	while ((i = getopt(argc, argv, "dvpfnyl:t:T:")) != -1)
10887304b87Stholo 		switch (i) {
10987304b87Stholo 		case 'd':
11087304b87Stholo 			flags |= CHECK_DEBUG;
11187304b87Stholo 			break;
11287304b87Stholo 
11387304b87Stholo 		case 'v':
11487304b87Stholo 			flags |= CHECK_VERBOSE;
11587304b87Stholo 			break;
11687304b87Stholo 
11787304b87Stholo 		case 'p':
11887304b87Stholo 			flags |= CHECK_PREEN;
11987304b87Stholo 			/*FALLTHROUGH*/
12087304b87Stholo 		case 'n':
12187304b87Stholo 		case 'f':
12287304b87Stholo 		case 'y':
12387304b87Stholo 			globopt[1] = i;
12487304b87Stholo 			options = catopt(options, globopt, 1);
12587304b87Stholo 			break;
12687304b87Stholo 
12787304b87Stholo 		case 'l':
12887304b87Stholo 			maxrun = atoi(optarg);
12987304b87Stholo 			break;
13087304b87Stholo 
13187304b87Stholo 		case 'T':
13287304b87Stholo 			if (*optarg)
13387304b87Stholo 				addoption(optarg);
13487304b87Stholo 			break;
13587304b87Stholo 
13687304b87Stholo 		case 't':
13787304b87Stholo 			if (selhead.tqh_first != NULL)
13887304b87Stholo 				errx(1, "only one -t option may be specified.");
13987304b87Stholo 
14087304b87Stholo 			maketypelist(optarg);
14187304b87Stholo 			vfstype = optarg;
14287304b87Stholo 			break;
14387304b87Stholo 
14487304b87Stholo 		case '?':
14587304b87Stholo 		default:
14687304b87Stholo 			usage();
14787304b87Stholo 			/* NOTREACHED */
14887304b87Stholo 		}
14987304b87Stholo 
15087304b87Stholo 	argc -= optind;
15187304b87Stholo 	argv += optind;
15287304b87Stholo 
15387304b87Stholo 	if (argc == 0)
15487304b87Stholo 		return checkfstab(flags, maxrun, isok, checkfs);
15587304b87Stholo 
15687304b87Stholo #define	BADTYPE(type)							\
15787304b87Stholo 	(strcmp(type, FSTAB_RO) &&					\
15887304b87Stholo 	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
15987304b87Stholo 
16087304b87Stholo 
16187304b87Stholo 	for (; argc--; argv++) {
16287304b87Stholo 		char *spec, *type;
16387304b87Stholo 
1645a93b9deSderaadt 		if (strncmp(*argv, "/dev/", 5) == 0 &&
165*57bc3e67Sdownsj 		    (type = readlabelfs(*argv, 0))) {
1665a93b9deSderaadt 			spec = *argv;
1675a93b9deSderaadt 		} else if ((fs = getfsfile(*argv)) == NULL &&
16887304b87Stholo 		    (fs = getfsspec(*argv)) == NULL) {
16987304b87Stholo 			if (vfstype == NULL)
17087304b87Stholo 				errx(1,
17187304b87Stholo 				    "%s: unknown special file or file system.",
17287304b87Stholo 				    *argv);
17387304b87Stholo 			spec = *argv;
17487304b87Stholo 			type = vfstype;
1755a93b9deSderaadt 		} else {
17687304b87Stholo 			spec = fs->fs_spec;
17787304b87Stholo 			type = fs->fs_vfstype;
17887304b87Stholo 			if (BADTYPE(fs->fs_type))
17987304b87Stholo 				errx(1, "%s has unknown file system type.",
18087304b87Stholo 				    *argv);
18187304b87Stholo 		}
18287304b87Stholo 
18387304b87Stholo 		rval |= checkfs(type, blockcheck(spec), *argv, NULL, NULL);
18487304b87Stholo 	}
18587304b87Stholo 
18687304b87Stholo 	return rval;
18787304b87Stholo }
18887304b87Stholo 
18987304b87Stholo 
19087304b87Stholo static void *
19187304b87Stholo isok(fs)
19287304b87Stholo 	struct fstab *fs;
19387304b87Stholo {
19487304b87Stholo 	if (fs->fs_passno == 0)
19587304b87Stholo 		return NULL;
19687304b87Stholo 
19787304b87Stholo 	if (BADTYPE(fs->fs_type))
19887304b87Stholo 		return NULL;
19987304b87Stholo 
20087304b87Stholo 	if (!selected(fs->fs_vfstype))
20187304b87Stholo 		return NULL;
20287304b87Stholo 
20387304b87Stholo 	return fs;
20487304b87Stholo }
20587304b87Stholo 
20687304b87Stholo 
20787304b87Stholo static int
20887304b87Stholo checkfs(vfstype, spec, mntpt, auxarg, pidp)
20987304b87Stholo 	const char *vfstype, *spec, *mntpt;
21087304b87Stholo 	void *auxarg;
21187304b87Stholo 	pid_t *pidp;
21287304b87Stholo {
21387304b87Stholo 	/* List of directories containing fsck_xxx subcommands. */
21487304b87Stholo 	static const char *edirs[] = {
21587304b87Stholo 		_PATH_SBIN,
21687304b87Stholo 		_PATH_USRSBIN,
21787304b87Stholo 		NULL
21887304b87Stholo 	};
21987304b87Stholo 	const char **argv, **edir;
22087304b87Stholo 	pid_t pid;
22187304b87Stholo 	int argc, i, status, maxargc;
22233486055Sderaadt 	char *optbuf = NULL, fsname[MAXPATHLEN], execname[MAXPATHLEN];
22387304b87Stholo 	const char *extra = getoptions(vfstype);
22487304b87Stholo 
22587304b87Stholo 	if (strcmp(vfstype, "ufs") == 0)
22687304b87Stholo 		vfstype = MOUNT_UFS;
22787304b87Stholo 
22887304b87Stholo 	maxargc = 100;
22987304b87Stholo 	argv = emalloc(sizeof(char *) * maxargc);
23087304b87Stholo 
23187304b87Stholo 	argc = 0;
23233486055Sderaadt 	(void)snprintf(fsname, sizeof(fsname), "fsck_%s", vfstype);
23333486055Sderaadt 	argv[argc++] = fsname;
23487304b87Stholo 
23587304b87Stholo 	if (options) {
23687304b87Stholo 		if (extra != NULL)
23787304b87Stholo 			optbuf = catopt(options, extra, 0);
23887304b87Stholo 		else
23987304b87Stholo 			optbuf = estrdup(options);
24087304b87Stholo 	}
24187304b87Stholo 	else if (extra)
24287304b87Stholo 		optbuf = estrdup(extra);
24387304b87Stholo 
24487304b87Stholo 	if (optbuf)
24587304b87Stholo 		mangle(optbuf, &argc, &argv, &maxargc);
24687304b87Stholo 
24787304b87Stholo 	argv[argc++] = spec;
24887304b87Stholo 	argv[argc] = NULL;
24987304b87Stholo 
25087304b87Stholo 	if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) {
25133486055Sderaadt 		(void)printf("start %s %swait %s", mntpt,
25233486055Sderaadt 			pidp ? "no" : "", fsname);
25387304b87Stholo 		for (i = 1; i < argc; i++)
25487304b87Stholo 			(void)printf(" %s", argv[i]);
25587304b87Stholo 		(void)printf("\n");
25687304b87Stholo 	}
25787304b87Stholo 
25833486055Sderaadt 	switch (pid = fork()) {
25987304b87Stholo 	case -1:				/* Error. */
260d138bb61Sderaadt 		warn("fork");
26187304b87Stholo 		if (optbuf)
26287304b87Stholo 			free(optbuf);
26387304b87Stholo 		return (1);
26487304b87Stholo 
26587304b87Stholo 	case 0:					/* Child. */
26687304b87Stholo 		if (flags & CHECK_DEBUG)
26787304b87Stholo 			_exit(0);
26887304b87Stholo 
26987304b87Stholo 		/* Go find an executable. */
27087304b87Stholo 		edir = edirs;
27187304b87Stholo 		do {
27287304b87Stholo 			(void)snprintf(execname,
27387304b87Stholo 			    sizeof(execname), "%s/fsck_%s", *edir, vfstype);
27487304b87Stholo 			execv(execname, (char * const *)argv);
27587304b87Stholo 			if (errno != ENOENT)
27687304b87Stholo 				if (spec)
27787304b87Stholo 					warn("exec %s for %s", execname, spec);
27887304b87Stholo 				else
27987304b87Stholo 					warn("exec %s", execname);
28087304b87Stholo 		} while (*++edir != NULL);
28187304b87Stholo 
28287304b87Stholo 		if (errno == ENOENT)
28387304b87Stholo 			if (spec)
28487304b87Stholo 				warn("exec %s for %s", execname, spec);
28587304b87Stholo 			else
28687304b87Stholo 				warn("exec %s", execname);
28787304b87Stholo 		exit(1);
28887304b87Stholo 		/* NOTREACHED */
28987304b87Stholo 
29087304b87Stholo 	default:				/* Parent. */
29187304b87Stholo 		if (optbuf)
29287304b87Stholo 			free(optbuf);
29387304b87Stholo 
29487304b87Stholo 		if (pidp) {
29587304b87Stholo 			*pidp = pid;
29687304b87Stholo 			return 0;
29787304b87Stholo 		}
29887304b87Stholo 
29987304b87Stholo 		if (waitpid(pid, &status, 0) < 0) {
30087304b87Stholo 			warn("waitpid");
30187304b87Stholo 			return (1);
30287304b87Stholo 		}
30387304b87Stholo 
30487304b87Stholo 		if (WIFEXITED(status)) {
30587304b87Stholo 			if (WEXITSTATUS(status) != 0)
30687304b87Stholo 				return (WEXITSTATUS(status));
30787304b87Stholo 		}
30887304b87Stholo 		else if (WIFSIGNALED(status)) {
30987304b87Stholo 			warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
31087304b87Stholo 			return (1);
31187304b87Stholo 		}
31287304b87Stholo 		break;
31387304b87Stholo 	}
31487304b87Stholo 
31587304b87Stholo 	return (0);
31687304b87Stholo }
31787304b87Stholo 
31887304b87Stholo 
31987304b87Stholo static int
32087304b87Stholo selected(type)
32187304b87Stholo 	const char *type;
32287304b87Stholo {
32387304b87Stholo 	struct entry *e;
32487304b87Stholo 
32587304b87Stholo 	/* If no type specified, it's always selected. */
32687304b87Stholo 	for (e = selhead.tqh_first; e != NULL; e = e->entries.tqe_next)
32787304b87Stholo 		if (!strncmp(e->type, type, MFSNAMELEN))
32887304b87Stholo 			return which == IN_LIST ? 1 : 0;
32987304b87Stholo 
33087304b87Stholo 	return which == IN_LIST ? 0 : 1;
33187304b87Stholo }
33287304b87Stholo 
33387304b87Stholo 
33487304b87Stholo static const char *
33587304b87Stholo getoptions(type)
33687304b87Stholo 	const char *type;
33787304b87Stholo {
33887304b87Stholo 	struct entry *e;
33987304b87Stholo 
34087304b87Stholo 	for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
34187304b87Stholo 		if (!strncmp(e->type, type, MFSNAMELEN))
34287304b87Stholo 			return e->options;
34387304b87Stholo 	return "";
34487304b87Stholo }
34587304b87Stholo 
34687304b87Stholo 
34787304b87Stholo static void
34887304b87Stholo addoption(optstr)
34987304b87Stholo 	char *optstr;
35087304b87Stholo {
35187304b87Stholo 	char *newoptions;
35287304b87Stholo 	struct entry *e;
35387304b87Stholo 
35487304b87Stholo 	if ((newoptions = strchr(optstr, ':')) == NULL)
35587304b87Stholo 		errx(1, "Invalid option string");
35687304b87Stholo 
35787304b87Stholo 	*newoptions++ = '\0';
35887304b87Stholo 
35987304b87Stholo 	for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
36087304b87Stholo 		if (!strncmp(e->type, optstr, MFSNAMELEN)) {
36187304b87Stholo 			e->options = catopt(e->options, newoptions, 1);
36287304b87Stholo 			return;
36387304b87Stholo 		}
36487304b87Stholo 	addentry(&opthead, optstr, newoptions);
36587304b87Stholo }
36687304b87Stholo 
36787304b87Stholo 
36887304b87Stholo static void
36987304b87Stholo addentry(list, type, opts)
37087304b87Stholo 	struct fstypelist *list;
37187304b87Stholo 	const char *type;
37287304b87Stholo 	const char *opts;
37387304b87Stholo {
37487304b87Stholo 	struct entry *e;
37587304b87Stholo 
37687304b87Stholo 	e = emalloc(sizeof(struct entry));
37787304b87Stholo 	e->type = estrdup(type);
37887304b87Stholo 	e->options = estrdup(opts);
37987304b87Stholo 	TAILQ_INSERT_TAIL(list, e, entries);
38087304b87Stholo }
38187304b87Stholo 
38287304b87Stholo 
38387304b87Stholo static void
38487304b87Stholo maketypelist(fslist)
38587304b87Stholo 	char *fslist;
38687304b87Stholo {
38787304b87Stholo 	char *ptr;
38887304b87Stholo 
38987304b87Stholo 	if ((fslist == NULL) || (fslist[0] == '\0'))
39087304b87Stholo 		errx(1, "empty type list");
39187304b87Stholo 
39287304b87Stholo 	if (fslist[0] == 'n' && fslist[1] == 'o') {
39387304b87Stholo 		fslist += 2;
39487304b87Stholo 		which = NOT_IN_LIST;
39587304b87Stholo 	}
39687304b87Stholo 	else
39787304b87Stholo 		which = IN_LIST;
39887304b87Stholo 
39987304b87Stholo 	while ((ptr = strsep(&fslist, ",")) != NULL)
40087304b87Stholo 		addentry(&selhead, ptr, "");
40187304b87Stholo 
40287304b87Stholo }
40387304b87Stholo 
40487304b87Stholo 
40587304b87Stholo static char *
40687304b87Stholo catopt(s0, s1, fr)
40787304b87Stholo 	char *s0;
40887304b87Stholo 	const char *s1;
40987304b87Stholo 	int fr;
41087304b87Stholo {
41187304b87Stholo 	size_t i;
41287304b87Stholo 	char *cp;
41387304b87Stholo 
41487304b87Stholo 	if (s0 && *s0) {
41587304b87Stholo 		i = strlen(s0) + strlen(s1) + 1 + 1;
41687304b87Stholo 		cp = emalloc(i);
41787304b87Stholo 		(void)snprintf(cp, i, "%s,%s", s0, s1);
41887304b87Stholo 	}
41987304b87Stholo 	else
42087304b87Stholo 		cp = estrdup(s1);
42187304b87Stholo 
42287304b87Stholo 	if (s0 && fr)
42387304b87Stholo 		free(s0);
42487304b87Stholo 	return (cp);
42587304b87Stholo }
42687304b87Stholo 
42787304b87Stholo 
42887304b87Stholo static void
42987304b87Stholo mangle(opts, argcp, argvp, maxargcp)
43087304b87Stholo 	char *opts;
43187304b87Stholo 	int *argcp;
43287304b87Stholo 	const char ***argvp;
43387304b87Stholo 	int *maxargcp;
43487304b87Stholo {
43587304b87Stholo 	char *p, *s;
43687304b87Stholo 	int argc = *argcp, maxargc = *maxargcp;
43787304b87Stholo 	const char **argv = *argvp;
43887304b87Stholo 
43987304b87Stholo 	argc = *argcp;
44087304b87Stholo 	maxargc = *maxargcp;
44187304b87Stholo 
44287304b87Stholo 	for (s = opts; (p = strsep(&s, ",")) != NULL;) {
44387304b87Stholo 		/* always leave space for one more argument and the NULL */
44487304b87Stholo 		if (argc >= maxargc - 3) {
44587304b87Stholo 			maxargc += 50;
44687304b87Stholo 			argv = erealloc(argv, maxargc * sizeof(char *));
44787304b87Stholo 		}
44887304b87Stholo 		if (*p != '\0')
44987304b87Stholo 			if (*p == '-') {
45087304b87Stholo 				argv[argc++] = p;
45187304b87Stholo 				p = strchr(p, '=');
45287304b87Stholo 				if (p) {
45387304b87Stholo 					*p = '\0';
45487304b87Stholo 					argv[argc++] = p+1;
45587304b87Stholo 				}
45687304b87Stholo 			}
45787304b87Stholo 			else {
45887304b87Stholo 				argv[argc++] = "-o";
45987304b87Stholo 				argv[argc++] = p;
46087304b87Stholo 			}
46187304b87Stholo 	}
46287304b87Stholo 
46387304b87Stholo 	*argcp = argc;
46487304b87Stholo 	*argvp = argv;
46587304b87Stholo 	*maxargcp = maxargc;
46687304b87Stholo }
46787304b87Stholo 
46887304b87Stholo 
46987304b87Stholo static void
47087304b87Stholo usage()
47187304b87Stholo {
47287304b87Stholo 	extern char *__progname;
47387304b87Stholo 	static const char common[] =
47487304b87Stholo 	    "[-dpvlyn] [-T fstype:fsoptions] [-t fstype]";
47587304b87Stholo 
47687304b87Stholo 	(void)fprintf(stderr, "Usage: %s %s [special|node]...\n",
47787304b87Stholo 	    __progname, common);
47887304b87Stholo 	exit(1);
47987304b87Stholo }
480