diff --git a/sbin/fsck/fsck.8 b/sbin/fsck/fsck.8 index 54dc36de7235..04cd4b602a27 100644 --- a/sbin/fsck/fsck.8 +++ b/sbin/fsck/fsck.8 @@ -37,6 +37,7 @@ .Sh SYNOPSIS .Nm .Op Fl dvplfyn +.Op Fl B | F .Op Fl l Ar maxparallel .Op Fl t Ar fstype .Op Fl T Ar fstype : Ns Ar fsoptions @@ -52,9 +53,29 @@ file or in the command line for consistency. It is normally used in the script .Pa /etc/rc during automatic reboot. -If no filesystems are specified, and ``preen'' mode is enabled ( -.Fl p -option) +Traditionally, +.Nm +is invoked before the filesystems are mounted +and all checks are done to completion at that time. +If background checking is available, +.Nm +is invoked twice. +It is first invoked at the traditional time, +before the filesystems are mounted, with the +.Fl F +flag to do checking on all the filesystems +that cannot do background checking. +It is then invoked a second time, +after the system has completed going multiuser, with the +.Fl B +flag to do checking on all the filesystems +that can do background checking. +Unlike the foreground checking, +the background checking is started asynchonously +so that other system activity can proceed +even on the filesystems that are being checked. +.Pp +If no filesystems are specified .Nm reads the table .Pa /etc/fstab @@ -99,6 +120,42 @@ Causes to assume no as the answer to all operator questions, except "CONTINUE?". .It Fl p Enter preen mode. +In preen mode, only a restricted class of innocuous +filesystem inconsistencies will be corrected. +If unexpected inconsistencies caused by hardware or +software failures are encounted, the check program +will exit with a failure. +See the manual pages for the individual check programs +for a list of the sorts of failures that they correct +when running in preen mode. +.It Fl F +Run in foreground mode. +The check program for each filesystem is invoked with the +.Fl F +flag to determine whether it wishes to run as part of +the boot up sequence, +or if it is able to do its job in background after the +system is up and running. +A non-zero exit code indicates that it wants to run in foreground +and the check program is invoked. +A zero exit code indicates that it is able to run later in background +and just a deferred message is printed. +.It Fl B +Run in background mode. +The check program for each filesystem is invoked with the +.Fl F +flag to determine whether it wishes to run as part of +the boot up sequence, +or if it is able to do its job in background after the +system is up and running. +A non-zero exit code indicates that it wanted to run in foreground +which is assumed to have been done, so the filesystem is skipped. +A zero exit code indicates that it is able to run in background +so the check program is invoked with the +.Fl B +flag to indicate that a check on the active filesystem should be done. +When running in background mode, +only one filesystem at a time will be checked. .It Fl t Ar fstype Invoke .Nm diff --git a/sbin/fsck/fsck.c b/sbin/fsck/fsck.c index a4d241a8bb59..09d1804c306f 100644 --- a/sbin/fsck/fsck.c +++ b/sbin/fsck/fsck.c @@ -78,10 +78,11 @@ struct entry { static char *options = NULL; static int flags = 0; +static int forceflag = 0; int main __P((int, char *[])); -static int checkfs __P((const char *, const char *, const char *, void *, +static int checkfs __P((const char *, const char *, const char *, char *, pid_t *)); static int selected __P((const char *)); static void addoption __P((char *)); @@ -92,7 +93,7 @@ static void catopt __P((char **, const char *)); static void mangle __P((char *, int *, const char ***, int *)); static const char *getfslab __P((const char *)); static void usage __P((void)); -static void *isok __P((struct fstab *)); +static int isok __P((struct fstab *)); int main(argc, argv) @@ -110,8 +111,14 @@ main(argc, argv) TAILQ_INIT(&selhead); TAILQ_INIT(&opthead); - while ((i = getopt(argc, argv, "dvpfnyl:t:T:")) != -1) + while ((i = getopt(argc, argv, "BdvpfFnyl:t:T:")) != -1) switch (i) { + case 'B': + if (flags & CHECK_BACKGRD) + errx(1, "Cannot specify -B and -F."); + flags |= DO_BACKGRD; + break; + case 'd': flags |= CHECK_DEBUG; break; @@ -120,16 +127,27 @@ main(argc, argv) flags |= CHECK_VERBOSE; break; + case 'F': + if (flags & DO_BACKGRD) + errx(1, "Cannot specify -B and -F."); + flags |= CHECK_BACKGRD; + break; + case 'p': flags |= CHECK_PREEN; /*FALLTHROUGH*/ case 'n': - case 'f': case 'y': globopt[1] = i; catopt(&options, globopt); break; + case 'f': + forceflag = 1; + globopt[1] = i; + catopt(&options, globopt); + break; + case 'l': warnx("Ignoring obsolete -l option\n"); break; @@ -165,8 +183,9 @@ main(argc, argv) for (; argc--; argv++) { - const char *spec, *type, *cp; - char device[MAXPATHLEN]; + const char *spec, *mntpt, *type, *cp; + char device[MAXPATHLEN]; + struct statfs *mntp; spec = *argv; cp = strrchr(spec, '/'); @@ -175,48 +194,98 @@ main(argc, argv) _PATH_DEV, spec); spec = device; } + mntp = getmntpt(spec); + if (mntp != NULL) { + spec = mntp->f_mntfromname; + mntpt = mntp->f_mntonname; + } if ((fs = getfsfile(spec)) == NULL && (fs = getfsspec(spec)) == NULL) { if (vfstype == NULL) vfstype = getfslab(spec); type = vfstype; - } - else { + devcheck(spec); + } else { spec = fs->fs_spec; type = fs->fs_vfstype; + mntpt = fs->fs_file; if (BADTYPE(fs->fs_type)) errx(1, "%s has unknown file system type.", spec); } + if ((flags & CHECK_BACKGRD) && + checkfs(type, spec, mntpt, "-F", NULL) == 0) { + printf("%s: DEFER FOR BACKGROUND CHECKING\n", *argv); + continue; + } + if ((flags & DO_BACKGRD) && forceflag == 0 && + checkfs(type, spec, mntpt, "-F", NULL) != 0) + continue; - rval |= checkfs(type, devcheck(spec), *argv, NULL, NULL); + rval |= checkfs(type, spec, mntpt, NULL, NULL); } return rval; } -static void * +static int isok(fs) struct fstab *fs; { + int i; + if (fs->fs_passno == 0) - return NULL; - + return (0); if (BADTYPE(fs->fs_type)) - return NULL; - + return (0); if (!selected(fs->fs_vfstype)) - return NULL; - - return fs; + return (0); + /* + * If the -B flag has been given, then process the needed + * background checks. Background checks cannot be run on + * filesystems that will be mounted read-only or that were + * not mounted at boot time (typically those marked `noauto'). + * If these basic tests are passed, check with the filesystem + * itself to see if it is willing to do background checking + * by invoking its check program with the -F flag. + */ + if (flags & DO_BACKGRD) { + if (!strcmp(fs->fs_type, FSTAB_RO)) + return (0); + if (getmntpt(fs->fs_spec) == NULL) + return (0); + if (checkfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, "-F", 0)) + return (0); + return (1); + } + /* + * If the -F flag has been given, then consider deferring the + * check to background. Background checks cannot be run on + * filesystems that will be mounted read-only or that will + * not be mounted at boot time (e.g., marked `noauto'). If + * these basic tests are passed, check with the filesystem + * itself to see if it is willing to defer to background + * checking by invoking its check program with the -F flag. + */ + if ((flags & CHECK_BACKGRD) == 0 || !strcmp(fs->fs_type, FSTAB_RO)) + return (1); + for (i = strlen(fs->fs_mntops) - 6; i >= 0; i--) + if (!strncmp(&fs->fs_mntops[i], "noauto", 6)) + break; + if (i >= 0) + return (1); + if (checkfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file, "-F", NULL) != 0) + return (1); + printf("%s: DEFER FOR BACKGROUND CHECKING\n", fs->fs_spec); + return (0); } static int -checkfs(pvfstype, spec, mntpt, auxarg, pidp) +checkfs(pvfstype, spec, mntpt, auxopt, pidp) const char *pvfstype, *spec, *mntpt; - void *auxarg; + char *auxopt; pid_t *pidp; { /* List of directories containing fsck_xxx subcommands. */ @@ -256,6 +325,10 @@ checkfs(pvfstype, spec, mntpt, auxarg, pidp) catopt(&optbuf, options); if (extra) catopt(&optbuf, extra); + if (auxopt) + catopt(&optbuf, auxopt); + else if (flags & DO_BACKGRD) + catopt(&optbuf, "-B"); maxargc = 64; argv = emalloc(sizeof(char *) * maxargc); @@ -285,7 +358,7 @@ checkfs(pvfstype, spec, mntpt, auxarg, pidp) return (1); case 0: /* Child. */ - if (flags & CHECK_DEBUG) + if ((flags & CHECK_DEBUG) && auxopt == NULL) _exit(0); /* Go find an executable. */ diff --git a/sbin/fsck/fsutil.c b/sbin/fsck/fsutil.c index f83c936fa489..a7a89aa4683d 100644 --- a/sbin/fsck/fsutil.c +++ b/sbin/fsck/fsutil.c @@ -51,9 +51,11 @@ __RCSID("$NetBSD: fsutil.c,v 1.7 1998/07/30 17:41:03 thorpej Exp $"); #include #include #include +#include -#include +#include #include +#include #include "fsutil.h" @@ -263,6 +265,47 @@ devcheck(origname) return (origname); } +/* + * Get the mount point information for name. + */ +struct statfs * +getmntpt(name) + const char *name; +{ + struct stat devstat, mntdevstat; + char device[sizeof(_PATH_DEV) - 1 + MNAMELEN]; + char *devname; + struct statfs *mntbuf, *statfsp; + int i, mntsize, isdev; + + if (stat(name, &devstat) != 0) + return (NULL); + if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode)) + isdev = 1; + else + isdev = 0; + mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); + for (i = 0; i < mntsize; i++) { + statfsp = &mntbuf[i]; + devname = statfsp->f_mntfromname; + if (*devname != '/') { + strcpy(device, _PATH_DEV); + strcat(device, devname); + strcpy(statfsp->f_mntfromname, device); + } + if (isdev == 0) { + if (strcmp(name, statfsp->f_mntonname)) + continue; + return (statfsp); + } + if (stat(devname, &mntdevstat) == 0 && + mntdevstat.st_rdev == devstat.st_rdev) + return (statfsp); + } + statfsp = NULL; + return (statfsp); +} + #if 0 /* * XXX this code is from NetBSD, but fails in FreeBSD because we diff --git a/sbin/fsck/fsutil.h b/sbin/fsck/fsutil.h index a4eca070082c..19f85fd946be 100644 --- a/sbin/fsck/fsutil.h +++ b/sbin/fsck/fsutil.h @@ -48,15 +48,18 @@ const char *blockcheck __P((const char *)); const char *devcheck __P((const char *)); const char *cdevname __P((void)); void setcdevname __P((const char *, int)); +struct statfs *getmntpt __P((const char *)); int hotroot __P((void)); void *emalloc __P((size_t)); void *erealloc __P((void *, size_t)); char *estrdup __P((const char *)); -#define CHECK_PREEN 1 -#define CHECK_VERBOSE 2 -#define CHECK_DEBUG 4 +#define CHECK_PREEN 0x0001 +#define CHECK_VERBOSE 0x0002 +#define CHECK_DEBUG 0x0004 +#define CHECK_BACKGRD 0x0008 +#define DO_BACKGRD 0x0010 struct fstab; -int checkfstab __P((int, void *(*)(struct fstab *), - int (*) (const char *, const char *, const char *, void *, pid_t *))); +int checkfstab __P((int, int (*)(struct fstab *), + int (*) (const char *, const char *, const char *, char *, pid_t *))); diff --git a/sbin/fsck/preen.c b/sbin/fsck/preen.c index 3313272aaec6..ac15385500e5 100644 --- a/sbin/fsck/preen.c +++ b/sbin/fsck/preen.c @@ -64,7 +64,6 @@ struct partentry { char *p_devname; /* device name */ char *p_mntpt; /* mount point */ char *p_type; /* filesystem type */ - void *p_auxarg; /* auxiliary argument */ }; TAILQ_HEAD(part, partentry) badh; @@ -81,23 +80,22 @@ TAILQ_HEAD(disk, diskentry) diskh; static int nrun = 0, ndisks = 0; static struct diskentry *finddisk __P((const char *)); -static void addpart __P((const char *, const char *, const char *, void *)); +static void addpart __P((const char *, const char *, const char *)); static int startdisk __P((struct diskentry *, - int (*)(const char *, const char *, const char *, void *, pid_t *))); + int (*)(const char *, const char *, const char *, char *, pid_t *))); static void printpart __P((void)); int checkfstab(flags, docheck, checkit) int flags; - void *(*docheck) __P((struct fstab *)); - int (*checkit) __P((const char *, const char *, const char *, void *, + int (*docheck) __P((struct fstab *)); + int (*checkit) __P((const char *, const char *, const char *, char *, pid_t *)); { struct fstab *fs; struct diskentry *d, *nextdisk; struct partentry *p; int ret, pid, retcode, passno, sumstatus, status, nextpass; - void *auxarg; const char *name; TAILQ_INIT(&badh); @@ -116,20 +114,18 @@ checkfstab(flags, docheck, checkit) return (8); } while ((fs = getfsent()) != 0) { - if ((auxarg = (*docheck)(fs)) == NULL) - continue; - name = fs->fs_spec; if (fs->fs_passno > passno && fs->fs_passno < nextpass) nextpass = fs->fs_passno; - if (passno != fs->fs_passno) + if (passno != fs->fs_passno || (*docheck)(fs) == 0) continue; if (flags & CHECK_DEBUG) printf("pass %d, name %s\n", passno, name); - if ((flags & CHECK_PREEN) == 0 || passno == 1) { + if ((flags & CHECK_PREEN) == 0 || passno == 1 || + (flags & DO_BACKGRD) != 0) { if (name == NULL) { if (flags & CHECK_PREEN) return 8; @@ -137,7 +133,7 @@ checkfstab(flags, docheck, checkit) continue; } sumstatus = (*checkit)(fs->fs_vfstype, - name, fs->fs_file, auxarg, NULL); + name, fs->fs_file, NULL, NULL); if (sumstatus) return (sumstatus); @@ -149,11 +145,11 @@ checkfstab(flags, docheck, checkit) sumstatus |= 8; continue; } - addpart(fs->fs_vfstype, name, fs->fs_file, - auxarg); + addpart(fs->fs_vfstype, name, fs->fs_file); } - if ((flags & CHECK_PREEN) == 0 || passno == 1) + if ((flags & CHECK_PREEN) == 0 || passno == 1 || + (flags & DO_BACKGRD) != 0) continue; if (flags & CHECK_DEBUG) { @@ -304,9 +300,8 @@ printpart() static void -addpart(type, devname, mntpt, auxarg) +addpart(type, devname, mntpt) const char *type, *devname, *mntpt; - void *auxarg; { struct diskentry *d = finddisk(devname); struct partentry *p; @@ -321,7 +316,6 @@ addpart(type, devname, mntpt, auxarg) p->p_devname = estrdup(devname); p->p_mntpt = estrdup(mntpt); p->p_type = estrdup(type); - p->p_auxarg = auxarg; TAILQ_INSERT_TAIL(&d->d_part, p, p_entries); } @@ -330,14 +324,14 @@ addpart(type, devname, mntpt, auxarg) static int startdisk(d, checkit) struct diskentry *d; - int (*checkit) __P((const char *, const char *, const char *, void *, + int (*checkit) __P((const char *, const char *, const char *, char *, pid_t *)); { struct partentry *p = TAILQ_FIRST(&d->d_part); int rv; while ((rv = (*checkit)(p->p_type, p->p_devname, p->p_mntpt, - p->p_auxarg, &d->d_pid)) != 0 && nrun > 0) + NULL, &d->d_pid)) != 0 && nrun > 0) sleep(10); if (rv == 0)