Home | History | Annotate | Line # | Download | only in fsck
fsck.c revision 1.9
      1 /*	$NetBSD: fsck.c,v 1.9 1996/12/07 19:09:11 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1996 Christos Zoulas. All rights reserved.
      5  * Copyright (c) 1980, 1989, 1993, 1994
      6  *	The Regents of the University of California.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  *
     36  * From: @(#)mount.c	8.19 (Berkeley) 4/19/94
     37  * From: NetBSD: mount.c,v 1.24 1995/11/18 03:34:29 cgd Exp
     38  *
     39  */
     40 
     41 static char rcsid[] = "$NetBSD: fsck.c,v 1.9 1996/12/07 19:09:11 christos Exp $";
     42 
     43 #include <sys/param.h>
     44 #include <sys/mount.h>
     45 #include <sys/queue.h>
     46 #include <sys/wait.h>
     47 #define DKTYPENAMES
     48 #include <sys/disklabel.h>
     49 #include <sys/ioctl.h>
     50 
     51 #include <err.h>
     52 #include <errno.h>
     53 #include <fstab.h>
     54 #include <fcntl.h>
     55 #include <signal.h>
     56 #include <stdio.h>
     57 #include <stdlib.h>
     58 #include <string.h>
     59 #include <unistd.h>
     60 
     61 #include "pathnames.h"
     62 #include "fsutil.h"
     63 
     64 static enum { IN_LIST, NOT_IN_LIST } which = NOT_IN_LIST;
     65 
     66 TAILQ_HEAD(fstypelist, entry) opthead, selhead;
     67 
     68 struct entry {
     69 	char *type;
     70 	char *options;
     71 	TAILQ_ENTRY(entry) entries;
     72 };
     73 
     74 static int maxrun = 0;
     75 static char *options = NULL;
     76 static int flags = 0;
     77 
     78 int main __P((int, char *[]));
     79 
     80 static int checkfs __P((const char *, const char *, const char *, void *,
     81     pid_t *));
     82 static int selected __P((const char *));
     83 static void addoption __P((char *));
     84 static const char *getoptions __P((const char *));
     85 static void addentry __P((struct fstypelist *, const char *, const char *));
     86 static void maketypelist __P((char *));
     87 static char *catopt __P((char *, const char *, int));
     88 static void mangle __P((char *, int *, const char ***, int *));
     89 static char *getfslab __P((const char *));
     90 static void usage __P((void));
     91 static void *isok __P((struct fstab *));
     92 
     93 int
     94 main(argc, argv)
     95 	int argc;
     96 	char *argv[];
     97 {
     98 	struct fstab *fs;
     99 	int i, rval = 0;
    100 	char *vfstype = NULL;
    101 	char globopt[3];
    102 
    103 	globopt[0] = '-';
    104 	globopt[2] = '\0';
    105 
    106 	TAILQ_INIT(&selhead);
    107 	TAILQ_INIT(&opthead);
    108 
    109 	while ((i = getopt(argc, argv, "dvpfnyl:t:T:")) != -1)
    110 		switch (i) {
    111 		case 'd':
    112 			flags |= CHECK_DEBUG;
    113 			break;
    114 
    115 		case 'v':
    116 			flags |= CHECK_VERBOSE;
    117 			break;
    118 
    119 		case 'p':
    120 			flags |= CHECK_PREEN;
    121 			/*FALLTHROUGH*/
    122 		case 'n':
    123 		case 'f':
    124 		case 'y':
    125 			globopt[1] = i;
    126 			options = catopt(options, globopt, 1);
    127 			break;
    128 
    129 		case 'l':
    130 			maxrun = atoi(optarg);
    131 			break;
    132 
    133 		case 'T':
    134 			if (*optarg)
    135 				addoption(optarg);
    136 			break;
    137 
    138 		case 't':
    139 			if (selhead.tqh_first != NULL)
    140 				errx(1, "only one -t option may be specified.");
    141 
    142 			maketypelist(optarg);
    143 			vfstype = optarg;
    144 			break;
    145 
    146 		case '?':
    147 		default:
    148 			usage();
    149 			/* NOTREACHED */
    150 		}
    151 
    152 	argc -= optind;
    153 	argv += optind;
    154 
    155 	if (argc == 0)
    156 		return checkfstab(flags, maxrun, isok, checkfs);
    157 
    158 #define	BADTYPE(type)							\
    159 	(strcmp(type, FSTAB_RO) &&					\
    160 	    strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
    161 
    162 
    163 	for (; argc--; argv++) {
    164 		char *spec, *type;
    165 
    166 		if ((fs = getfsfile(*argv)) == NULL &&
    167 		    (fs = getfsspec(*argv)) == NULL) {
    168 			if (vfstype == NULL)
    169 				vfstype = getfslab(*argv);
    170 			spec = *argv;
    171 			type = vfstype;
    172 		}
    173 		else {
    174 			spec = fs->fs_spec;
    175 			type = fs->fs_vfstype;
    176 			if (BADTYPE(fs->fs_type))
    177 				errx(1, "%s has unknown file system type.",
    178 				    *argv);
    179 		}
    180 
    181 		rval |= checkfs(type, blockcheck(spec), *argv, NULL, NULL);
    182 	}
    183 
    184 	return rval;
    185 }
    186 
    187 
    188 static void *
    189 isok(fs)
    190 	struct fstab *fs;
    191 {
    192 	if (fs->fs_passno == 0)
    193 		return NULL;
    194 
    195 	if (BADTYPE(fs->fs_type))
    196 		return NULL;
    197 
    198 	if (!selected(fs->fs_vfstype))
    199 		return NULL;
    200 
    201 	return fs;
    202 }
    203 
    204 
    205 static int
    206 checkfs(vfstype, spec, mntpt, auxarg, pidp)
    207 	const char *vfstype, *spec, *mntpt;
    208 	void *auxarg;
    209 	pid_t *pidp;
    210 {
    211 	/* List of directories containing fsck_xxx subcommands. */
    212 	static const char *edirs[] = {
    213 		_PATH_SBIN,
    214 		_PATH_USRSBIN,
    215 		NULL
    216 	};
    217 	char execbase[MAXPATHLEN];
    218 	const char **argv, **edir;
    219 	pid_t pid;
    220 	int argc = 1, i, status, maxargc;
    221 	char *optbuf = NULL, execname[MAXPATHLEN + 1];
    222 	const char *extra = getoptions(vfstype);
    223 
    224 
    225 #ifdef __GNUC__
    226 	/* Avoid vfork clobbering */
    227 	(void) &optbuf;
    228 	(void) &vfstype;
    229 #endif
    230 
    231 	if (strcmp(vfstype, "ufs") == 0)
    232 		vfstype = MOUNT_UFS;
    233 
    234 	maxargc = 100;
    235 	argv = emalloc(sizeof(char *) * maxargc);
    236 
    237 	/* construct basename of executable and argv[0] simultaneously */
    238 	(void) snprintf(execbase, sizeof(execbase), "fsck_%s", vfstype);
    239 	argv[0] = vfstype;
    240 
    241 	if (options) {
    242 		if (extra != NULL)
    243 			optbuf = catopt(options, extra, 0);
    244 		else
    245 			optbuf = estrdup(options);
    246 	}
    247 	else if (extra)
    248 		optbuf = estrdup(extra);
    249 
    250 	if (optbuf)
    251 		mangle(optbuf, &argc, &argv, &maxargc);
    252 
    253 	argv[argc++] = spec;
    254 	argv[argc] = NULL;
    255 
    256 	if (flags & (CHECK_DEBUG|CHECK_VERBOSE)) {
    257 		(void)printf("start %s %swait", mntpt,
    258 			pidp ? "no" : "");
    259 		for (i = 0; i < argc; i++)
    260 			(void)printf(" %s", argv[i]);
    261 		(void)printf("\n");
    262 	}
    263 
    264 	switch (pid = vfork()) {
    265 	case -1:				/* Error. */
    266 		warn("vfork");
    267 		if (optbuf)
    268 			free(optbuf);
    269 		return (1);
    270 
    271 	case 0:					/* Child. */
    272 		if (flags & CHECK_DEBUG)
    273 			_exit(0);
    274 
    275 		/* Go find an executable. */
    276 		edir = edirs;
    277 		do {
    278 			(void)snprintf(execname,
    279 			    sizeof(execname), "%s/%s", *edir, execbase);
    280 			execv(execname, (char * const *)argv);
    281 			if (errno != ENOENT)
    282 				if (spec)
    283 					warn("exec %s for %s", execname, spec);
    284 				else
    285 					warn("exec %s", execname);
    286 		} while (*++edir != NULL);
    287 
    288 		if (errno == ENOENT)
    289 			if (spec)
    290 				warn("exec %s for %s", execname, spec);
    291 			else
    292 				warn("exec %s", execname);
    293 		_exit(1);
    294 		/* NOTREACHED */
    295 
    296 	default:				/* Parent. */
    297 		if (optbuf)
    298 			free(optbuf);
    299 
    300 		if (pidp) {
    301 			*pidp = pid;
    302 			return 0;
    303 		}
    304 
    305 		if (waitpid(pid, &status, 0) < 0) {
    306 			warn("waitpid");
    307 			return (1);
    308 		}
    309 
    310 		if (WIFEXITED(status)) {
    311 			if (WEXITSTATUS(status) != 0)
    312 				return (WEXITSTATUS(status));
    313 		}
    314 		else if (WIFSIGNALED(status)) {
    315 			warnx("%s: %s", spec, strsignal(WTERMSIG(status)));
    316 			return (1);
    317 		}
    318 		break;
    319 	}
    320 
    321 	return (0);
    322 }
    323 
    324 
    325 static int
    326 selected(type)
    327 	const char *type;
    328 {
    329 	struct entry *e;
    330 
    331 	/* If no type specified, it's always selected. */
    332 	for (e = selhead.tqh_first; e != NULL; e = e->entries.tqe_next)
    333 		if (!strncmp(e->type, type, MFSNAMELEN))
    334 			return which == IN_LIST ? 1 : 0;
    335 
    336 	return which == IN_LIST ? 0 : 1;
    337 }
    338 
    339 
    340 static const char *
    341 getoptions(type)
    342 	const char *type;
    343 {
    344 	struct entry *e;
    345 
    346 	for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
    347 		if (!strncmp(e->type, type, MFSNAMELEN))
    348 			return e->options;
    349 	return "";
    350 }
    351 
    352 
    353 static void
    354 addoption(optstr)
    355 	char *optstr;
    356 {
    357 	char *newoptions;
    358 	struct entry *e;
    359 
    360 	if ((newoptions = strchr(optstr, ':')) == NULL)
    361 		errx(1, "Invalid option string");
    362 
    363 	*newoptions++ = '\0';
    364 
    365 	for (e = opthead.tqh_first; e != NULL; e = e->entries.tqe_next)
    366 		if (!strncmp(e->type, optstr, MFSNAMELEN)) {
    367 			e->options = catopt(e->options, newoptions, 1);
    368 			return;
    369 		}
    370 	addentry(&opthead, optstr, newoptions);
    371 }
    372 
    373 
    374 static void
    375 addentry(list, type, opts)
    376 	struct fstypelist *list;
    377 	const char *type;
    378 	const char *opts;
    379 {
    380 	struct entry *e;
    381 
    382 	e = emalloc(sizeof(struct entry));
    383 	e->type = estrdup(type);
    384 	e->options = estrdup(opts);
    385 	TAILQ_INSERT_TAIL(list, e, entries);
    386 }
    387 
    388 
    389 static void
    390 maketypelist(fslist)
    391 	char *fslist;
    392 {
    393 	char *ptr;
    394 
    395 	if ((fslist == NULL) || (fslist[0] == '\0'))
    396 		errx(1, "empty type list");
    397 
    398 	if (fslist[0] == 'n' && fslist[1] == 'o') {
    399 		fslist += 2;
    400 		which = NOT_IN_LIST;
    401 	}
    402 	else
    403 		which = IN_LIST;
    404 
    405 	while ((ptr = strsep(&fslist, ",")) != NULL)
    406 		addentry(&selhead, ptr, "");
    407 
    408 }
    409 
    410 
    411 static char *
    412 catopt(s0, s1, fr)
    413 	char *s0;
    414 	const char *s1;
    415 	int fr;
    416 {
    417 	size_t i;
    418 	char *cp;
    419 
    420 	if (s0 && *s0) {
    421 		i = strlen(s0) + strlen(s1) + 1 + 1;
    422 		cp = emalloc(i);
    423 		(void)snprintf(cp, i, "%s,%s", s0, s1);
    424 	}
    425 	else
    426 		cp = estrdup(s1);
    427 
    428 	if (s0 && fr)
    429 		free(s0);
    430 	return (cp);
    431 }
    432 
    433 
    434 static void
    435 mangle(opts, argcp, argvp, maxargcp)
    436 	char *opts;
    437 	int *argcp;
    438 	const char ***argvp;
    439 	int *maxargcp;
    440 {
    441 	char *p, *s;
    442 	int argc = *argcp, maxargc = *maxargcp;
    443 	const char **argv = *argvp;
    444 
    445 	argc = *argcp;
    446 	maxargc = *maxargcp;
    447 
    448 	for (s = opts; (p = strsep(&s, ",")) != NULL;) {
    449 		/* always leave space for one more argument and the NULL */
    450 		if (argc >= maxargc - 3) {
    451 			maxargc += 50;
    452 			argv = erealloc(argv, maxargc * sizeof(char *));
    453 		}
    454 		if (*p != '\0')
    455 			if (*p == '-') {
    456 				argv[argc++] = p;
    457 				p = strchr(p, '=');
    458 				if (p) {
    459 					*p = '\0';
    460 					argv[argc++] = p+1;
    461 				}
    462 			}
    463 			else {
    464 				argv[argc++] = "-o";
    465 				argv[argc++] = p;
    466 			}
    467 	}
    468 
    469 	*argcp = argc;
    470 	*argvp = argv;
    471 	*maxargcp = maxargc;
    472 }
    473 
    474 
    475 /* Maybe this belongs to <sys/disklabel.h> */
    476 static char *fscknames[] = {
    477 	NULL,
    478 	NULL,
    479 	NULL,
    480 	NULL,
    481 	NULL,
    482 	NULL,
    483 	NULL,
    484 	"ffs",
    485 	"msdos",
    486 	NULL,
    487 	NULL,
    488 	NULL,
    489 	NULL,
    490 	NULL,
    491 	NULL,
    492 	NULL,
    493 	NULL,
    494 	NULL
    495 };
    496 
    497 
    498 static char *
    499 getfslab(str)
    500 	const char *str;
    501 {
    502 	struct disklabel dl;
    503 	int fd;
    504 	char p, *vfstype;
    505 	u_char t;
    506 
    507 	/* deduce the filesystem type from the disk label */
    508 	if ((fd = open(str, O_RDONLY)) == -1)
    509 		err(1, "cannot open `%s'", str);
    510 
    511 	if (ioctl(fd, DIOCGDINFO, &dl) == -1)
    512 		err(1, "cannot get disklabel for `%s'", str);
    513 
    514 	(void) close(fd);
    515 
    516 	p = str[strlen(str) - 1];
    517 
    518 	if ((p - 'a') >= dl.d_npartitions)
    519 		errx(1, "partition `%s' is not defined on disk", str);
    520 
    521 	if ((t = dl.d_partitions[p - 'a'].p_fstype) >= DKMAXTYPES)
    522 		errx(1, "partition `%s' is not of a legal vfstype",
    523 		    p, str);
    524 
    525 	if ((vfstype = fscknames[t]) == NULL)
    526 		errx(1, "vfstype `%s' on partition `%s' is not supported",
    527 		    fstypenames[t], str);
    528 
    529 	return vfstype;
    530 }
    531 
    532 
    533 
    534 static void
    535 usage()
    536 {
    537 	extern char *__progname;
    538 	static const char common[] =
    539 	    "[-dpvlyn] [-T fstype:fsoptions] [-t fstype]";
    540 
    541 	(void)fprintf(stderr, "Usage: %s %s [special|node]...\n",
    542 	    __progname, common);
    543 	exit(1);
    544 }
    545