git: efd949aaba74 - stable/13 - Have fsck_ffs(8) properly correct superblock check-hash failures.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 16 Feb 2022 01:14:38 UTC
The branch stable/13 has been updated by mckusick:
URL: https://cgit.FreeBSD.org/src/commit/?id=efd949aaba7449ae994fe5052178c2ba3efd2e7b
commit efd949aaba7449ae994fe5052178c2ba3efd2e7b
Author: Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2022-02-04 19:46:36 +0000
Commit: Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2022-02-16 01:14:22 +0000
Have fsck_ffs(8) properly correct superblock check-hash failures.
(cherry picked from commit c0bfa109b942659f609b7e2bf3ba042ec0cb3f9d)
PR: 245916
---
sbin/fsck_ffs/fsck.h | 1 +
sbin/fsck_ffs/fsutil.c | 4 +-
sbin/fsck_ffs/globs.c | 6 +-
sbin/fsck_ffs/main.c | 309 +++++++++++++++++++++++++++++++++----------------
sbin/fsck_ffs/setup.c | 182 +++++++----------------------
5 files changed, 258 insertions(+), 244 deletions(-)
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 9ecc5793e644..690a98038884 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -356,6 +356,7 @@ extern char preen; /* just fix normal inconsistencies */
extern char rerun; /* rerun fsck. Only used in non-preen mode */
extern int returntosingle; /* 1 => return to single user mode on exit */
extern char resolved; /* cleared if unresolved changes => not clean */
+extern int sbhashfailed; /* when reading superblock check hash failed */
extern char havesb; /* superblock has been read */
extern char skipclean; /* skip clean file systems if preening */
extern int fsmodified; /* 1 => write done to file system */
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index db22ee5b20cf..711c9bb63549 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -250,6 +250,7 @@ cglookup(int cg)
if (cgp == NULL) {
if (sujrecovery)
errx(EEXIT,"Ran out of memory during journal recovery");
+ flush(fswritefd, &cgblk);
getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
return (&cgblk);
}
@@ -564,7 +565,7 @@ ckfini(int markclean)
cmd.size = markclean ? -1 : 1;
if (sysctlbyname("vfs.ffs.setflags", 0, 0,
&cmd, sizeof cmd) == -1)
- rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN);
+ pwarn("CANNOT SET FILE SYSTEM DIRTY FLAG\n");
if (!preen) {
printf("\n***** FILE SYSTEM MARKED %s *****\n",
markclean ? "CLEAN" : "DIRTY");
@@ -575,6 +576,7 @@ ckfini(int markclean)
printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
rerun = 1;
}
+ bkgrdflag = 0;
}
if (debug && cachelookups > 0)
printf("cache with %d buffers missed %d of %d (%d%%)\n",
diff --git a/sbin/fsck_ffs/globs.c b/sbin/fsck_ffs/globs.c
index be4434ce38ca..09dbcc6694a2 100644
--- a/sbin/fsck_ffs/globs.c
+++ b/sbin/fsck_ffs/globs.c
@@ -96,6 +96,7 @@ char preen; /* just fix normal inconsistencies */
char rerun; /* rerun fsck. Only used in non-preen mode */
int returntosingle; /* 1 => return to single user mode on exit */
char resolved; /* cleared if unresolved changes => not clean */
+int sbhashfailed; /* when reading superblock check hash failed */
char havesb; /* superblock has been read */
char skipclean; /* skip clean file systems if preening */
int fsmodified; /* 1 => write done to file system */
@@ -155,8 +156,9 @@ fsckinit(void)
resolved = 0;
havesb = 0;
fsmodified = 0;
- fsreadfd = 0;
- fswritefd = 0;
+ sbhashfailed = 0;
+ fsreadfd = -1;
+ fswritefd = -1;
maxfsblock = 0;
maxino = 0;
lfdir = 0;
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index e78e2d206499..f7224b48a9a4 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -75,6 +75,8 @@ static int restarts;
static void usage(void) __dead2;
static intmax_t argtoimax(int flag, const char *req, const char *str, int base);
static int checkfilesys(char *filesys);
+static int setup_bkgrdchk(struct statfs *mntp, int sbrdfailed, char **filesys);
+static int openfilesys(char *dev);
static int chkdoreload(struct statfs *mntp);
static struct statfs *getmntpt(const char *);
@@ -181,6 +183,11 @@ main(int argc, char *argv[])
if (!argc)
usage();
+ if (bkgrdflag && cvtlevel > 0) {
+ pfatal("CANNOT CONVERT A SNAPSHOT\n");
+ exit(EEXIT);
+ }
+
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
(void)signal(SIGINT, catch);
if (ckclean)
@@ -237,18 +244,10 @@ checkfilesys(char *filesys)
ufs2_daddr_t n_ffree, n_bfree;
struct dups *dp;
struct statfs *mntp;
- struct stat snapdir;
- struct group *grp;
- struct iovec *iov;
- char errmsg[255];
- int ofsmodified;
- int iovlen;
intmax_t blks, files;
size_t size;
+ int sbreadfailed, ofsmodified;
- iov = NULL;
- iovlen = 0;
- errmsg[0] = '\0';
fsutilinit();
fsckinit();
@@ -272,10 +271,12 @@ checkfilesys(char *filesys)
* exit status will cause a foreground check to be run.
*/
sblock_init();
+ sbreadfailed = 0;
+ if (openfilesys(filesys) == 0 || readsb(0) == 0)
+ sbreadfailed = 1;
if (bkgrdcheck) {
- if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0)
+ if (sbreadfailed)
exit(3); /* Cannot read superblock */
- close(fsreadfd);
/* Earlier background failed or journaled */
if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ))
exit(4);
@@ -293,7 +294,7 @@ checkfilesys(char *filesys)
/*
* If file system is gjournaled, check it here.
*/
- if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0)
+ if (sbreadfailed)
exit(3); /* Cannot read superblock */
if (bkgrdflag == 0 &&
(nflag || (fswritefd = open(filesys, O_WRONLY)) < 0)) {
@@ -307,107 +308,30 @@ checkfilesys(char *filesys)
pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
exit(0);
}
- if ((sblock.fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) {
+ if ((sblock.fs_flags &
+ (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) {
bufinit();
gjournal_check(filesys);
if (chkdoreload(mntp) == 0)
exit(0);
exit(4);
} else {
- pfatal("UNEXPECTED INCONSISTENCY, CANNOT RUN "
- "FAST FSCK\n");
+ pfatal("FULL FSCK NEEDED, CANNOT RUN FAST "
+ "FSCK\n");
}
}
- close(fsreadfd);
close(fswritefd);
+ fswritefd = -1;
}
- /*
- * If we are to do a background check:
- * Get the mount point information of the file system
- * create snapshot file
- * return created snapshot file
- * if not found, clear bkgrdflag and proceed with normal fsck
- */
if (bkgrdflag) {
- /* Get the mount point information of the file system */
- if (mntp == NULL) {
- bkgrdflag = 0;
- pfatal("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n");
- } else if ((mntp->f_flags & MNT_SOFTDEP) == 0) {
- bkgrdflag = 0;
- pfatal("NOT USING SOFT UPDATES, CANNOT RUN IN "
- "BACKGROUND\n");
- } else if ((mntp->f_flags & MNT_RDONLY) != 0) {
- bkgrdflag = 0;
- pfatal("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n");
- } else if ((fsreadfd = open(filesys, O_RDONLY)) >= 0) {
- if (readsb(0) != 0) {
- if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ)) {
- bkgrdflag = 0;
- pfatal(
- "UNEXPECTED INCONSISTENCY, CANNOT RUN IN BACKGROUND\n");
- }
- if ((sblock.fs_flags & FS_UNCLEAN) == 0 &&
- skipclean && ckclean) {
- /*
- * file system is clean;
- * skip snapshot and report it clean
- */
- pwarn(
- "FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
- goto clean;
- }
- }
- close(fsreadfd);
- }
- if (bkgrdflag) {
- snprintf(snapname, sizeof snapname, "%s/.snap",
- mntp->f_mntonname);
- if (stat(snapname, &snapdir) < 0) {
- if (errno != ENOENT) {
- bkgrdflag = 0;
- pfatal(
- "CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n",
- snapname, strerror(errno));
- } else if ((grp = getgrnam("operator")) == NULL ||
- mkdir(snapname, 0770) < 0 ||
- chown(snapname, -1, grp->gr_gid) < 0 ||
- chmod(snapname, 0770) < 0) {
- bkgrdflag = 0;
- pfatal(
- "CANNOT CREATE SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n",
- snapname, strerror(errno));
- }
- } else if (!S_ISDIR(snapdir.st_mode)) {
- bkgrdflag = 0;
- pfatal(
- "%s IS NOT A DIRECTORY, CANNOT RUN IN BACKGROUND\n",
- snapname);
- }
- }
- if (bkgrdflag) {
- snprintf(snapname, sizeof snapname,
- "%s/.snap/fsck_snapshot", mntp->f_mntonname);
- build_iovec(&iov, &iovlen, "fstype", "ffs", 4);
- build_iovec(&iov, &iovlen, "from", snapname,
- (size_t)-1);
- build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname,
- (size_t)-1);
- build_iovec(&iov, &iovlen, "errmsg", errmsg,
- sizeof(errmsg));
- build_iovec(&iov, &iovlen, "update", NULL, 0);
- build_iovec(&iov, &iovlen, "snapshot", NULL, 0);
-
- while (nmount(iov, iovlen, mntp->f_flags) < 0) {
- if (errno == EEXIST && unlink(snapname) == 0)
- continue;
- bkgrdflag = 0;
- pfatal("CANNOT CREATE SNAPSHOT %s: %s %s\n",
- snapname, strerror(errno), errmsg);
- break;
- }
- if (bkgrdflag != 0)
- filesys = snapname;
+ switch (setup_bkgrdchk(mntp, sbreadfailed, &filesys)) {
+ case -1: /* filesystem clean */
+ goto clean;
+ case 0: /* cannot do background, give up */
+ exit(EEXIT);
+ case 1: /* doing background check, preen rules apply */
+ preen = 1;
+ break;
}
}
@@ -646,6 +570,187 @@ checkfilesys(char *filesys)
return (rerun ? ERERUN : 0);
}
+/*
+ * If we are to do a background check:
+ * Get the mount point information of the file system
+ * If already clean, return -1
+ * Check that kernel supports background fsck
+ * Find or create the snapshot directory
+ * Create the snapshot file
+ * Open snapshot
+ * If anything fails print reason and return 0 which exits
+ */
+static int
+setup_bkgrdchk(struct statfs *mntp, int sbreadfailed, char **filesys)
+{
+ struct stat snapdir;
+ struct group *grp;
+ struct iovec *iov;
+ char errmsg[255];
+ int iovlen;
+ long size;
+
+ /* Get the mount point information of the file system */
+ if (mntp == NULL) {
+ pwarn("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n");
+ return (0);
+ }
+ if ((mntp->f_flags & MNT_RDONLY) != 0) {
+ pwarn("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n");
+ return (0);
+ }
+ if ((mntp->f_flags & MNT_SOFTDEP) == 0) {
+ pwarn("NOT USING SOFT UPDATES, CANNOT RUN IN BACKGROUND\n");
+ return (0);
+ }
+ if (sbreadfailed) {
+ pwarn("SUPERBLOCK READ FAILED, CANNOT RUN IN BACKGROUND\n");
+ return (0);
+ }
+ if ((sblock.fs_flags & FS_NEEDSFSCK) != 0) {
+ pwarn("FULL FSCK NEEDED, CANNOT RUN IN BACKGROUND\n");
+ return (0);
+ }
+ if ((sblock.fs_flags & FS_SUJ) != 0) {
+ pwarn("JOURNALED FILESYSTEM, CANNOT RUN IN BACKGROUND\n");
+ return (0);
+ }
+ if (skipclean && ckclean &&
+ (sblock.fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK)) == 0) {
+ /*
+ * file system is clean;
+ * skip snapshot and report it clean
+ */
+ pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
+ return (-1);
+ }
+ /* Check that kernel supports background fsck */
+ size = MIBSIZE;
+ if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0||
+ sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0||
+ sysctlnametomib("vfs.ffs.setsize", setsize, &size) < 0 ||
+ sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0||
+ sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 ||
+ sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) {
+ pwarn("KERNEL LACKS BACKGROUND FSCK SUPPORT\n");
+ return (0);
+ }
+ /*
+ * When kernel lacks runtime bgfsck superblock summary
+ * adjustment functionality, it does not mean we can not
+ * continue, as old kernels will recompute the summary at
+ * mount time. However, it will be an unexpected softupdates
+ * inconsistency if it turns out that the summary is still
+ * incorrect. Set a flag so subsequent operation can know this.
+ */
+ bkgrdsumadj = 1;
+ if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 ||
+ sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 ||
+ sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 ||
+ sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 ||
+ sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters,
+ &size) < 0) {
+ bkgrdsumadj = 0;
+ pwarn("KERNEL LACKS RUNTIME SUPERBLOCK SUMMARY ADJUSTMENT "
+ "SUPPORT\n");
+ }
+ /* Find or create the snapshot directory */
+ snprintf(snapname, sizeof snapname, "%s/.snap",
+ mntp->f_mntonname);
+ if (stat(snapname, &snapdir) < 0) {
+ if (errno != ENOENT) {
+ pwarn("CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT "
+ "RUN IN BACKGROUND\n", snapname, strerror(errno));
+ return (0);
+ }
+ if ((grp = getgrnam("operator")) == NULL ||
+ mkdir(snapname, 0770) < 0 ||
+ chown(snapname, -1, grp->gr_gid) < 0 ||
+ chmod(snapname, 0770) < 0) {
+ pwarn("CANNOT CREATE SNAPSHOT DIRECTORY %s: %s, "
+ "CANNOT RUN IN BACKGROUND\n", snapname,
+ strerror(errno));
+ return (0);
+ }
+ } else if (!S_ISDIR(snapdir.st_mode)) {
+ pwarn("%s IS NOT A DIRECTORY, CANNOT RUN IN BACKGROUND\n",
+ snapname);
+ return (0);
+ }
+ /* Create the snapshot file */
+ iov = NULL;
+ iovlen = 0;
+ errmsg[0] = '\0';
+ snprintf(snapname, sizeof snapname, "%s/.snap/fsck_snapshot",
+ mntp->f_mntonname);
+ build_iovec(&iov, &iovlen, "fstype", "ffs", 4);
+ build_iovec(&iov, &iovlen, "from", snapname, (size_t)-1);
+ build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, (size_t)-1);
+ build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
+ build_iovec(&iov, &iovlen, "update", NULL, 0);
+ build_iovec(&iov, &iovlen, "snapshot", NULL, 0);
+ /* Create snapshot, removing old snapshot it it exists */
+ while (nmount(iov, iovlen, mntp->f_flags) < 0) {
+ if (errno == EEXIST && unlink(snapname) == 0)
+ continue;
+ pwarn("CANNOT CREATE SNAPSHOT %s: %s %s\n", snapname,
+ strerror(errno), errmsg);
+ return (0);
+ }
+ /* Open snapshot */
+ if (openfilesys(snapname) == 0) {
+ unlink(snapname);
+ pwarn("CANNOT OPEN SNAPSHOT %s: %s, CANNOT RUN IN "
+ "BACKGROUND\n", snapname, strerror(errno));
+ return (0);
+ }
+ free(sblock.fs_csp);
+ free(sblock.fs_si);
+ havesb = 0;
+ *filesys = snapname;
+ cmd.version = FFS_CMD_VERSION;
+ cmd.handle = fsreadfd;
+ return (1);
+}
+
+/*
+ * Open a device or file to be checked by fsck.
+ */
+static int
+openfilesys(char *dev)
+{
+ struct stat statb;
+ int saved_fsreadfd;
+
+ if (stat(dev, &statb) < 0) {
+ pfatal("CANNOT STAT %s: %s\n", dev, strerror(errno));
+ return (0);
+ }
+ if ((statb.st_mode & S_IFMT) != S_IFCHR &&
+ (statb.st_mode & S_IFMT) != S_IFBLK) {
+ if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) {
+ pfatal("BACKGROUND FSCK LACKS A SNAPSHOT\n");
+ exit(EEXIT);
+ }
+ if (bkgrdflag != 0) {
+ cursnapshot = statb.st_ino;
+ } else {
+ pfatal("%s IS NOT A DISK DEVICE\n", dev);
+ if (reply("CONTINUE") == 0)
+ return (0);
+ }
+ }
+ saved_fsreadfd = fsreadfd;
+ if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
+ fsreadfd = saved_fsreadfd;
+ pfatal("CANNOT OPEN %s: %s\n", dev, strerror(errno));
+ return (0);
+ }
+ if (saved_fsreadfd != -1)
+ close(saved_fsreadfd);
+ return (1);
+}
+
static int
chkdoreload(struct statfs *mntp)
{
diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c
index 0ae7f1bbb28f..506a027f40ac 100644
--- a/sbin/fsck_ffs/setup.c
+++ b/sbin/fsck_ffs/setup.c
@@ -76,114 +76,19 @@ static int chkrecovery(int devfd);
int
setup(char *dev)
{
- long cg, asked, i, j;
- long bmapsize;
- struct stat statb;
+ long cg, bmapsize;
struct fs proto;
- size_t size;
- havesb = 0;
- fswritefd = -1;
- cursnapshot = 0;
- if (stat(dev, &statb) < 0) {
- printf("Can't stat %s: %s\n", dev, strerror(errno));
- if (bkgrdflag) {
- unlink(snapname);
- bkgrdflag = 0;
- }
- return (0);
- }
- if ((statb.st_mode & S_IFMT) != S_IFCHR &&
- (statb.st_mode & S_IFMT) != S_IFBLK) {
- if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) {
- unlink(snapname);
- printf("background fsck lacks a snapshot\n");
- exit(EEXIT);
- }
- if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) {
- cursnapshot = statb.st_ino;
- } else {
- if (cvtlevel == 0 ||
- (statb.st_flags & SF_SNAPSHOT) == 0) {
- if (preen && bkgrdflag) {
- unlink(snapname);
- bkgrdflag = 0;
- }
- pfatal("%s is not a disk device", dev);
- if (reply("CONTINUE") == 0) {
- if (bkgrdflag) {
- unlink(snapname);
- bkgrdflag = 0;
- }
- return (0);
- }
- } else {
- if (bkgrdflag) {
- unlink(snapname);
- bkgrdflag = 0;
- }
- pfatal("cannot convert a snapshot");
- exit(EEXIT);
- }
- }
- }
- if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
- if (bkgrdflag) {
- unlink(snapname);
- bkgrdflag = 0;
- }
- printf("Can't open %s: %s\n", dev, strerror(errno));
+ /*
+ * We are expected to have an open file descriptor
+ */
+ if (fsreadfd < 0)
return (0);
- }
- if (bkgrdflag) {
- unlink(snapname);
- size = MIBSIZE;
- if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0||
- sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0||
- sysctlnametomib("vfs.ffs.setsize", setsize, &size) < 0 ||
- sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0||
- sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 ||
- sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) {
- pfatal("kernel lacks background fsck support\n");
- exit(EEXIT);
- }
- /*
- * When kernel is lack of runtime bgfsck superblock summary
- * adjustment functionality, it does not mean we can not
- * continue, as old kernels will recompute the summary at
- * mount time. However, it will be an unexpected softupdates
- * inconsistency if it turns out that the summary is still
- * incorrect. Set a flag so subsequent operation can know
- * this.
- */
- bkgrdsumadj = 1;
- if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 ||
- sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 ||
- sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 ||
- sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 ||
- sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, &size) < 0) {
- bkgrdsumadj = 0;
- pwarn("kernel lacks runtime superblock summary adjustment support");
- }
- cmd.version = FFS_CMD_VERSION;
- cmd.handle = fsreadfd;
- fswritefd = -1;
- }
- if (preen == 0)
- printf("** %s", dev);
- if (bkgrdflag == 0 &&
- (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) {
- fswritefd = -1;
- if (preen)
- pfatal("NO WRITE ACCESS");
- printf(" (NO WRITE)");
- }
- if (preen == 0)
- printf("\n");
/*
- * Read in the superblock, looking for alternates if necessary
+ * If we do not yet have a superblock, read it in looking
+ * for alternates if necessary.
*/
- if (readsb(1) == 0) {
+ if (havesb == 0 && readsb(1) == 0) {
skipclean = 0;
if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
return(0);
@@ -195,19 +100,38 @@ setup(char *dev)
break;
}
if (cg >= proto.fs_ncg) {
- printf("%s %s\n%s %s\n%s %s\n",
- "SEARCH FOR ALTERNATE SUPER-BLOCK",
- "FAILED. YOU MUST USE THE",
- "-b OPTION TO FSCK TO SPECIFY THE",
- "LOCATION OF AN ALTERNATE",
- "SUPER-BLOCK TO SUPPLY NEEDED",
- "INFORMATION; SEE fsck_ffs(8).");
+ printf("SEARCH FOR ALTERNATE SUPER-BLOCK FAILED. "
+ "YOU MUST USE THE\n-b OPTION TO FSCK TO SPECIFY "
+ "THE LOCATION OF AN ALTERNATE\nSUPER-BLOCK TO "
+ "SUPPLY NEEDED INFORMATION; SEE fsck_ffs(8).\n");
bflag = 0;
return(0);
}
pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag);
bflag = 0;
}
+ if (preen == 0)
+ printf("** %s", dev);
+ if (bkgrdflag == 0 &&
+ (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) {
+ fswritefd = -1;
+ if (preen)
+ pfatal("NO WRITE ACCESS");
+ printf(" (NO WRITE)");
+ }
+ if (preen == 0)
+ printf("\n");
+ if (sbhashfailed != 0) {
+ pwarn("SUPERBLOCK CHECK HASH FAILED");
+ if (fswritefd == -1)
+ pwarn("OPENED READONLY SO CANNOT CORRECT CHECK HASH\n");
+ else if (preen || reply("CORRECT CHECK HASH") != 0) {
+ if (preen)
+ printf(" (CORRECTED)\n");
+ sblock.fs_clean = 0;
+ sbdirty();
+ }
+ }
if (skipclean && ckclean && sblock.fs_clean) {
pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
return (-1);
@@ -247,30 +171,6 @@ setup(char *dev)
fswritefd != -1 && chkrecovery(fsreadfd) == 0 &&
reply("SAVE DATA TO FIND ALTERNATE SUPERBLOCKS") != 0)
saverecovery(fsreadfd, fswritefd);
- /*
- * read in the summary info.
- */
- asked = 0;
- sblock.fs_csp = Calloc(1, sblock.fs_cssize);
- if (sblock.fs_csp == NULL) {
- printf("cannot alloc %u bytes for cg summary info\n",
- (unsigned)sblock.fs_cssize);
- goto badsb;
- }
- for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
- size = MIN(sblock.fs_cssize - i, sblock.fs_bsize);
- readcnt[sblk.b_type]++;
- if (blread(fsreadfd, (char *)sblock.fs_csp + i,
- fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
- size) != 0 && !asked) {
- pfatal("BAD SUMMARY INFORMATION");
- if (reply("CONTINUE") == 0) {
- ckfini(0);
- exit(EEXIT);
- }
- asked++;
- }
- }
/*
* allocate and initialize the necessary maps
*/
@@ -320,13 +220,17 @@ readsb(int listerr)
int bad, ret;
struct fs *fs;
- super = bflag ? bflag * dev_bsize : STDSB_NOHASHFAIL;
+ super = bflag ? bflag * dev_bsize :
+ sbhashfailed ? STDSB_NOHASHFAIL_NOMSG : STDSB_NOMSG;
readcnt[sblk.b_type]++;
- if ((ret = sbget(fsreadfd, &fs, super)) != 0) {
+ while ((ret = sbget(fsreadfd, &fs, super)) != 0) {
switch (ret) {
- case EINVAL:
- /* Superblock check-hash failed */
- return (0);
+ case EINTEGRITY:
+ if (bflag || super == STDSB_NOHASHFAIL_NOMSG)
+ return (0);
+ super = STDSB_NOHASHFAIL_NOMSG;
+ sbhashfailed = 1;
+ continue;
case ENOENT:
if (bflag)
printf("%jd is not a file system "