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