summaryrefslogtreecommitdiffstats
path: root/sbin/fsck_ffs
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2008-04-10 23:49:23 +0000
committerdelphij <delphij@FreeBSD.org>2008-04-10 23:49:23 +0000
commitaff41aab585ea9a4db2a88f4299e3ad8f2f12031 (patch)
treeb5f93f915b454019d2b6ae372ac45f5167ac1c67 /sbin/fsck_ffs
parentd99d951c1c77a9727f83ca99c52261cc3bc93f76 (diff)
downloadFreeBSD-src-aff41aab585ea9a4db2a88f4299e3ad8f2f12031.zip
FreeBSD-src-aff41aab585ea9a4db2a88f4299e3ad8f2f12031.tar.gz
Add a new flag, '-C' which enables a special mode that is intended for
catastrophic recovery. Currently, this mode only validates whether a cylindergroup has good signature data, and prompts the user to decide whether to clear it as a whole. This mode is useful when there is data damage on a disk and you are working on copy of the original disk, as fsck_ffs(8) tends to abnormally exit in such case, as a last resort to recover data from the disk.
Diffstat (limited to 'sbin/fsck_ffs')
-rw-r--r--sbin/fsck_ffs/fsck.h2
-rw-r--r--sbin/fsck_ffs/fsck_ffs.824
-rw-r--r--sbin/fsck_ffs/fsutil.c32
-rw-r--r--sbin/fsck_ffs/inode.c3
-rw-r--r--sbin/fsck_ffs/main.c7
5 files changed, 61 insertions, 7 deletions
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index f9b38e0..14f49d6 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -270,6 +270,7 @@ char yflag; /* assume a yes response */
int bkgrdflag; /* use a snapshot to run on an active system */
int bflag; /* location of alternate super block */
int debug; /* output debugging info */
+char catastrophicflag; /* run in catastrophic mode */
int cvtlevel; /* convert to newer file system format */
int bkgrdcheck; /* determine if background check is possible */
int bkgrdsumadj; /* whether the kernel have ability to adjust superblock summary */
@@ -335,6 +336,7 @@ void cacheino(union dinode *dp, ino_t inumber);
void catch(int);
void catchquit(int);
int changeino(ino_t dir, const char *name, ino_t newnum);
+void check_cgmagic(int cg, struct cg *cgp);
int chkrange(ufs2_daddr_t blk, int cnt);
void ckfini(int markclean);
int ckinode(union dinode *dp, struct inodesc *);
diff --git a/sbin/fsck_ffs/fsck_ffs.8 b/sbin/fsck_ffs/fsck_ffs.8
index a64c7ce..98c97f3 100644
--- a/sbin/fsck_ffs/fsck_ffs.8
+++ b/sbin/fsck_ffs/fsck_ffs.8
@@ -29,7 +29,7 @@
.\" @(#)fsck.8 8.4 (Berkeley) 5/9/95
.\" $FreeBSD$
.\"
-.Dd April 24, 2001
+.Dd April 10, 2008
.Dt FSCK_FFS 8
.Os
.Sh NAME
@@ -38,7 +38,7 @@
.Nd file system consistency check and interactive repair
.Sh SYNOPSIS
.Nm
-.Op Fl BFpfny
+.Op Fl BCFpfny
.Op Fl b Ar block
.Op Fl c Ar level
.Op Fl m Ar mode
@@ -175,6 +175,26 @@ Use the block specified immediately after the flag as
the super block for the file system.
An alternate super block is usually located at block 32 for UFS1,
and block 160 for UFS2.
+.It Fl C
+Run
+.Nm
+in 'catastrophic recovery' mode, which will enable certain aggressive
+operations that can make
+.Nm
+to survive with file systems that has very serious data damage, which
+is an useful last resort when on disk data damage is very serious
+and causes
+.Nm
+to crash otherwise. Be
+.Em very careful
+using this flag, is dangerous if there are data transmission hazards
+because a false positive cylinder group magic number mismatch could
+cause
+.Em irrevertible data loss!
+.Pp
+This option implies the
+.Fl f
+flag.
.It Fl c
Convert the file system to the specified level.
Note that the level of a file system can only be raised.
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 65f996c..7ca0c44 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -418,6 +418,35 @@ blwrite(int fd, char *buf, ufs2_daddr_t blk, long size)
}
/*
+ * Check cg's magic number. If catastrophic mode is enabled and the cg's
+ * magic number is bad, offer an option to clear the whole cg.
+ */
+void
+check_cgmagic(int cg, struct cg *cgp)
+{
+
+ if (!cg_chkmagic(cgp)) {
+ pwarn("CG %d: BAD MAGIC NUMBER\n", cg);
+ if (catastrophicflag) {
+ if (reply("CLEAR CG")) {
+ memset(cgp, 0, (size_t)sblock.fs_cgsize);
+ cgp->cg_initediblk = sblock.fs_ipg;
+ cgp->cg_old_niblk = sblock.fs_ipg;
+ cgp->cg_old_ncyl = sblock.fs_old_cpg;
+ cgp->cg_cgx = cg;
+ cgp->cg_niblk = sblock.fs_ipg;
+ cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg);
+ cgp->cg_magic = CG_MAGIC;
+ cgdirty();
+ printf("PLEASE RERUN FSCK.\n");
+ rerun = 1;
+ }
+ } else
+ printf("YOU MAY NEED TO RERUN FSCK WITH -C IF IT CRASHED.\n");
+ }
+}
+
+/*
* allocate a data block with the specified number of fragments
*/
ufs2_daddr_t
@@ -441,8 +470,7 @@ allocblk(long frags)
}
cg = dtog(&sblock, i + j);
getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
- if (!cg_chkmagic(cgp))
- pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
+ check_cgmagic(cg, cgp);
baseblk = dtogd(&sblock, i + j);
for (k = 0; k < frags; k++) {
setbmap(i + j + k);
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index b41d843..94c637e 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -617,8 +617,7 @@ allocino(ino_t request, int type)
return (0);
cg = ino_to_cg(&sblock, ino);
getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
- if (!cg_chkmagic(cgp))
- pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
+ check_cgmagic(cg, cgp);
setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
cgp->cg_cs.cs_nifree--;
switch (type & IFMT) {
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index f24d49b..7cb20a7 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -81,7 +81,8 @@ main(int argc, char *argv[])
sync();
skipclean = 1;
- while ((ch = getopt(argc, argv, "b:Bc:dfFm:npy")) != -1) {
+ catastrophicflag = 0;
+ while ((ch = getopt(argc, argv, "b:Bc:CdfFm:npy")) != -1) {
switch (ch) {
case 'b':
skipclean = 0;
@@ -105,6 +106,10 @@ main(int argc, char *argv[])
debug++;
break;
+ case 'C':
+ catastrophicflag = 1;
+ /* FALLTHROUGH */
+
case 'f':
skipclean = 0;
break;
OpenPOWER on IntegriCloud