summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sbin/fsck/fsck.863
-rw-r--r--sbin/fsck/fsck.c113
-rw-r--r--sbin/fsck/fsutil.c45
-rw-r--r--sbin/fsck/fsutil.h13
-rw-r--r--sbin/fsck/preen.c34
5 files changed, 219 insertions, 49 deletions
diff --git a/sbin/fsck/fsck.8 b/sbin/fsck/fsck.8
index 54dc36d..04cd4b6 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 a4d241a..09d1804 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;
{
- if (fs->fs_passno == 0)
- return NULL;
+ int i;
+ if (fs->fs_passno == 0)
+ 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 f83c936..a7a89aa 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 <errno.h>
#include <fstab.h>
#include <err.h>
+#include <paths.h>
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/stat.h>
+#include <sys/mount.h>
#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 a4eca07..19f85fd 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 3313272..ac15385 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)
OpenPOWER on IntegriCloud