aboutsummaryrefslogtreecommitdiff
path: root/sbin/fsck_ffs/setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/fsck_ffs/setup.c')
-rw-r--r--sbin/fsck_ffs/setup.c559
1 files changed, 312 insertions, 247 deletions
diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c
index 0ae7f1bbb28f..f10f02d159c3 100644
--- a/sbin/fsck_ffs/setup.c
+++ b/sbin/fsck_ffs/setup.c
@@ -29,14 +29,6 @@
* SUCH DAMAGE.
*/
-#if 0
-#ifndef lint
-static const char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95";
-#endif /* not lint */
-#endif
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/disk.h>
#include <sys/stat.h>
@@ -54,19 +46,23 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <stdint.h>
#include <string.h>
-#include <libufs.h>
#include "fsck.h"
-struct inoinfo **inphead, **inpsort; /* info about all inodes */
+struct inohash *inphash; /* hash list of directory inode info */
+struct inoinfo **inpsort; /* disk order list of directory inodes */
+struct inode snaplist[FSMAXSNAP + 1]; /* list of active snapshots */
+int snapcnt; /* number of active snapshots */
+char *copybuf; /* buffer to copy snapshot blocks */
-struct bufarea asblk;
-#define altsblock (*asblk.b_un.b_fs)
+static int sbhashfailed;
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
static int calcsb(char *dev, int devfd, struct fs *fs);
static void saverecovery(int readfd, int writefd);
static int chkrecovery(int devfd);
+static int getlbnblkno(struct inodesc *);
+static int checksnapinfo(struct inode *);
/*
* Read in a superblock finding an alternate if necessary.
@@ -76,99 +72,21 @@ static int chkrecovery(int devfd);
int
setup(char *dev)
{
- long cg, asked, i, j;
- long bmapsize;
- struct stat statb;
- struct fs proto;
- size_t size;
+ long i, bmapsize;
+ struct inode ip;
- 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;
+ /*
+ * We are expected to have an open file descriptor and a superblock.
+ */
+ if (fsreadfd < 0 || havesb == 0) {
+ if (debug) {
+ if (fsreadfd < 0)
+ printf("setup: missing fsreadfd\n");
+ else
+ printf("setup: missing superblock\n");
}
- printf("Can't open %s: %s\n", dev, strerror(errno));
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 &&
@@ -180,33 +98,16 @@ setup(char *dev)
}
if (preen == 0)
printf("\n");
- /*
- * Read in the superblock, looking for alternates if necessary
- */
- if (readsb(1) == 0) {
- skipclean = 0;
- if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
- return(0);
- if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
- return (0);
- for (cg = 0; cg < proto.fs_ncg; cg++) {
- bflag = fsbtodb(&proto, cgsblock(&proto, cg));
- if (readsb(0) != 0)
- 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).");
- bflag = 0;
- return(0);
+ 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();
}
- pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag);
- bflag = 0;
}
if (skipclean && ckclean && sblock.fs_clean) {
pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
@@ -239,41 +140,14 @@ setup(char *dev)
pfatal("from before 2002 with the command ``fsck -c 2''\n");
exit(EEXIT);
}
- if ((asblk.b_flags & B_DIRTY) != 0 && !bflag) {
- memmove(&altsblock, &sblock, (size_t)sblock.fs_sbsize);
- flush(fswritefd, &asblk);
- }
if (preen == 0 && yflag == 0 && sblock.fs_magic == FS_UFS2_MAGIC &&
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
*/
+ bufinit();
bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short));
blockmap = Calloc((unsigned)bmapsize, sizeof (char));
if (blockmap == NULL) {
@@ -287,22 +161,57 @@ setup(char *dev)
(unsigned)(sizeof(struct inostatlist) * (sblock.fs_ncg)));
goto badsb;
}
- numdirs = MAX(sblock.fs_cstotal.cs_ndir, 128);
- dirhash = numdirs;
+ numdirs = sblock.fs_cstotal.cs_ndir;
+ dirhash = MAX(numdirs / 2, 1);
inplast = 0;
listmax = numdirs + 10;
inpsort = (struct inoinfo **)Calloc(listmax, sizeof(struct inoinfo *));
- inphead = (struct inoinfo **)Calloc(numdirs, sizeof(struct inoinfo *));
- if (inpsort == NULL || inphead == NULL) {
- printf("cannot alloc %ju bytes for inphead\n",
+ inphash = (struct inohash *)Calloc(dirhash, sizeof(struct inohash));
+ if (inpsort == NULL || inphash == NULL) {
+ printf("cannot alloc %ju bytes for inphash\n",
(uintmax_t)numdirs * sizeof(struct inoinfo *));
goto badsb;
}
- bufinit();
if (sblock.fs_flags & FS_DOSOFTDEP)
usedsoftdep = 1;
else
usedsoftdep = 0;
+ /*
+ * Collect any snapshot inodes so that we can allow them to
+ * claim any blocks that we free. The code for doing this is
+ * imported here and into inode.c from sys/ufs/ffs/ffs_snapshot.c.
+ */
+ for (snapcnt = 0; snapcnt < FSMAXSNAP; snapcnt++) {
+ if (sblock.fs_snapinum[snapcnt] == 0)
+ break;
+ ginode(sblock.fs_snapinum[snapcnt], &ip);
+ if ((DIP(ip.i_dp, di_mode) & IFMT) == IFREG &&
+ (DIP(ip.i_dp, di_flags) & SF_SNAPSHOT) != 0 &&
+ checksnapinfo(&ip)) {
+ if (debug)
+ printf("Load snapshot %jd\n",
+ (intmax_t)sblock.fs_snapinum[snapcnt]);
+ snaplist[snapcnt] = ip;
+ continue;
+ }
+ printf("Removing non-snapshot inode %ju from snapshot list\n",
+ (uintmax_t)sblock.fs_snapinum[snapcnt]);
+ irelse(&ip);
+ for (i = snapcnt + 1; i < FSMAXSNAP; i++) {
+ if (sblock.fs_snapinum[i] == 0)
+ break;
+ sblock.fs_snapinum[i - 1] = sblock.fs_snapinum[i];
+ }
+ sblock.fs_snapinum[i - 1] = 0;
+ snapcnt--;
+ sbdirty();
+ }
+ if (snapcnt > 0 && copybuf == NULL) {
+ copybuf = Balloc(sblock.fs_bsize);
+ if (copybuf == NULL)
+ errx(EEXIT, "cannot allocate space for snapshot "
+ "copy buffer");
+ }
return (1);
badsb:
@@ -311,37 +220,242 @@ badsb:
}
/*
+ * Check for valid snapshot information.
+ *
+ * Each snapshot has a list of blocks that have been copied. This list
+ * is consulted before checking the snapshot inode. Its purpose is to
+ * speed checking of commonly checked blocks and to avoid recursive
+ * checks of the snapshot inode. In particular, the list must contain
+ * the superblock, the superblock summary information, and all the
+ * cylinder group blocks. The list may contain other commonly checked
+ * pointers such as those of the blocks that contain the snapshot inodes.
+ * The list is sorted into block order to allow binary search lookup.
+ *
+ * The twelve direct direct block pointers of the snapshot are always
+ * copied, so we test for them first before checking the list itself
+ * (i.e., they are not in the list).
+ *
+ * The checksnapinfo() routine needs to ensure that the list contains at
+ * least the super block, its summary information, and the cylinder groups.
+ * Here we check the list first for the superblock, zero or more cylinder
+ * groups up to the location of the superblock summary information, the
+ * summary group information, and any remaining cylinder group maps that
+ * follow it. We skip over any other entries in the list.
+ */
+#define CHKBLKINLIST(chkblk) \
+ /* All UFS_NDADDR blocks are copied */ \
+ if ((chkblk) >= UFS_NDADDR) { \
+ /* Skip over blocks that are not of interest */ \
+ while (*blkp < (chkblk) && blkp < lastblkp) \
+ blkp++; \
+ /* Fail if end of list and not all blocks found */ \
+ if (blkp >= lastblkp) { \
+ pwarn("UFS%d snapshot inode %jd failed: " \
+ "improper block list length (%jd)\n", \
+ sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, \
+ (intmax_t)snapip->i_number, \
+ (intmax_t)(lastblkp - &snapblklist[0])); \
+ status = 0; \
+ } \
+ /* Fail if block we seek is missing */ \
+ else if (*blkp++ != (chkblk)) { \
+ pwarn("UFS%d snapshot inode %jd failed: " \
+ "block list (%jd) != %s (%jd)\n", \
+ sblock.fs_magic == FS_UFS1_MAGIC ? 1 : 2, \
+ (intmax_t)snapip->i_number, \
+ (intmax_t)blkp[-1], #chkblk, \
+ (intmax_t)chkblk); \
+ status = 0; \
+ } \
+ }
+
+static int
+checksnapinfo(struct inode *snapip)
+{
+ struct fs *fs;
+ struct bufarea *bp;
+ struct inodesc idesc;
+ daddr_t *snapblklist, *blkp, *lastblkp, csblkno;
+ int cg, loc, len, status;
+ ufs_lbn_t lbn;
+ size_t size;
+
+ fs = &sblock;
+ memset(&idesc, 0, sizeof(struct inodesc));
+ idesc.id_type = ADDR;
+ idesc.id_func = getlbnblkno;
+ idesc.id_number = snapip->i_number;
+ lbn = howmany(fs->fs_size, fs->fs_frag);
+ idesc.id_parent = lbn; /* sought after blkno */
+ if ((ckinode(snapip->i_dp, &idesc) & FOUND) == 0)
+ return (0);
+ size = fragroundup(fs,
+ DIP(snapip->i_dp, di_size) - lblktosize(fs, lbn));
+ bp = getdatablk(idesc.id_parent, size, BT_DATA);
+ if (bp->b_errs != 0)
+ return (0);
+ snapblklist = (daddr_t *)bp->b_un.b_buf;
+ /*
+ * snapblklist[0] is the size of the list
+ * snapblklist[1] is the first element of the list
+ *
+ * We need to be careful to bound the size of the list and verify
+ * that we have not run off the end of it if it or its size has
+ * been corrupted.
+ */
+ blkp = &snapblklist[1];
+ lastblkp = &snapblklist[MAX(0,
+ MIN(snapblklist[0] + 1, size / sizeof(daddr_t)))];
+ status = 1;
+ /* Check that the superblock is listed. */
+ CHKBLKINLIST(lblkno(fs, fs->fs_sblockloc));
+ if (status == 0)
+ goto out;
+ /*
+ * Calculate where the summary information is located.
+ * Usually it is in the first cylinder group, but growfs
+ * may move it to the first cylinder group that it adds.
+ *
+ * Check all cylinder groups up to the summary information.
+ */
+ csblkno = fragstoblks(fs, fs->fs_csaddr);
+ for (cg = 0; cg < fs->fs_ncg; cg++) {
+ if (fragstoblks(fs, cgtod(fs, cg)) > csblkno)
+ break;
+ CHKBLKINLIST(fragstoblks(fs, cgtod(fs, cg)));
+ if (status == 0)
+ goto out;
+ }
+ /* Check the summary information block(s). */
+ len = howmany(fs->fs_cssize, fs->fs_bsize);
+ for (loc = 0; loc < len; loc++) {
+ CHKBLKINLIST(csblkno + loc);
+ if (status == 0)
+ goto out;
+ }
+ /* Check the remaining cylinder groups. */
+ for (; cg < fs->fs_ncg; cg++) {
+ CHKBLKINLIST(fragstoblks(fs, cgtod(fs, cg)));
+ if (status == 0)
+ goto out;
+ }
+out:
+ brelse(bp);
+ return (status);
+}
+
+/*
+ * Return the block number associated with a specified inode lbn.
+ * Requested lbn is in id_parent. If found, block is returned in
+ * id_parent.
+ */
+static int
+getlbnblkno(struct inodesc *idesc)
+{
+
+ if (idesc->id_lbn < idesc->id_parent)
+ return (KEEPON);
+ idesc->id_parent = idesc->id_blkno;
+ return (STOP | FOUND);
+}
+
+/*
+ * Open a device or file to be checked by fsck.
+ */
+int
+openfilesys(char *dev)
+{
+ struct stat statb;
+ int saved_fsreadfd;
+
+ if (stat(dev, &statb) < 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) {
+ pwarn("BACKGROUND FSCK LACKS A SNAPSHOT\n");
+ return (0);
+ }
+ if (bkgrdflag != 0) {
+ cursnapshot = statb.st_ino;
+ } else {
+ pwarn("%s IS NOT A DISK DEVICE\n", dev);
+ if (preen || reply("CONTINUE") == 0)
+ return (0);
+ }
+ }
+ saved_fsreadfd = fsreadfd;
+ if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
+ fsreadfd = saved_fsreadfd;
+ return (0);
+ }
+ if (saved_fsreadfd != -1)
+ close(saved_fsreadfd);
+ return (1);
+}
+
+/*
* Read in the super block and its summary info.
*/
int
-readsb(int listerr)
+readsb(void)
{
- off_t super;
- int bad, ret;
struct fs *fs;
- super = bflag ? bflag * dev_bsize : STDSB_NOHASHFAIL;
+ sbhashfailed = 0;
readcnt[sblk.b_type]++;
- if ((ret = sbget(fsreadfd, &fs, super)) != 0) {
- switch (ret) {
- case EINVAL:
- /* Superblock check-hash failed */
+ /*
+ * If bflag is given, then check just that superblock.
+ */
+ if (bflag) {
+ switch (sbget(fsreadfd, &fs, bflag * dev_bsize, 0)) {
+ case 0:
+ goto goodsb;
+ case EINTEGRITY:
+ printf("Check hash failed for superblock at %jd\n",
+ bflag);
return (0);
case ENOENT:
- if (bflag)
- printf("%jd is not a file system "
- "superblock\n", super / dev_bsize);
- else
- printf("Cannot find file system "
- "superblock\n");
+ printf("%jd is not a file system superblock\n", bflag);
return (0);
case EIO:
default:
- printf("I/O error reading %jd\n",
- super / dev_bsize);
+ printf("I/O error reading %jd\n", bflag);
return (0);
}
}
+ /*
+ * Check for the standard superblock and use it if good.
+ */
+ if (sbget(fsreadfd, &fs, UFS_STDSB, UFS_NOMSG) == 0)
+ goto goodsb;
+ /*
+ * Check if the only problem is a check-hash failure.
+ */
+ skipclean = 0;
+ if (sbget(fsreadfd, &fs, UFS_STDSB, UFS_NOMSG | UFS_NOHASHFAIL) == 0) {
+ sbhashfailed = 1;
+ goto goodsb;
+ }
+ /*
+ * Do an exhaustive search for a usable superblock.
+ */
+ switch (sbsearch(fsreadfd, &fs, 0)) {
+ case 0:
+ goto goodsb;
+ case ENOENT:
+ 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");
+ return (0);
+ case EIO:
+ default:
+ printf("I/O error reading a usable superblock\n");
+ return (0);
+ }
+
+goodsb:
memcpy(&sblock, fs, fs->fs_sbsize);
free(fs);
/*
@@ -353,58 +467,6 @@ readsb(int listerr)
sblk.b_bno = sblock.fs_sblockactualloc / dev_bsize;
sblk.b_size = SBLOCKSIZE;
/*
- * Compare all fields that should not differ in alternate super block.
- * When an alternate super-block is specified this check is skipped.
- */
- if (bflag)
- goto out;
- getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
- if (asblk.b_errs)
- return (0);
- bad = 0;
-#define CHK(x, y) \
- if (altsblock.x != sblock.x) { \
- bad++; \
- if (listerr && debug) \
- printf("SUPER BLOCK VS ALTERNATE MISMATCH %s: " y " vs " y "\n", \
- #x, (intmax_t)sblock.x, (intmax_t)altsblock.x); \
- }
- CHK(fs_sblkno, "%jd");
- CHK(fs_cblkno, "%jd");
- CHK(fs_iblkno, "%jd");
- CHK(fs_dblkno, "%jd");
- CHK(fs_ncg, "%jd");
- CHK(fs_bsize, "%jd");
- CHK(fs_fsize, "%jd");
- CHK(fs_frag, "%jd");
- CHK(fs_bmask, "%#jx");
- CHK(fs_fmask, "%#jx");
- CHK(fs_bshift, "%jd");
- CHK(fs_fshift, "%jd");
- CHK(fs_fragshift, "%jd");
- CHK(fs_fsbtodb, "%jd");
- CHK(fs_sbsize, "%jd");
- CHK(fs_nindir, "%jd");
- CHK(fs_inopb, "%jd");
- CHK(fs_cssize, "%jd");
- CHK(fs_ipg, "%jd");
- CHK(fs_fpg, "%jd");
- CHK(fs_magic, "%#jx");
-#undef CHK
- if (bad) {
- if (listerr == 0)
- return (0);
- if (preen)
- printf("%s: ", cdevname);
- printf(
- "VALUES IN SUPER BLOCK LSB=%jd DISAGREE WITH THOSE IN\n"
- "LAST ALTERNATE LSB=%jd\n",
- sblk.b_bno, asblk.b_bno);
- if (reply("IGNORE ALTERNATE SUPER BLOCK") == 0)
- return (0);
- }
-out:
- /*
* If not yet done, update UFS1 superblock with new wider fields.
*/
if (sblock.fs_magic == FS_UFS1_MAGIC &&
@@ -427,14 +489,13 @@ void
sblock_init(void)
{
+ fsreadfd = -1;
fswritefd = -1;
fsmodified = 0;
lfdir = 0;
initbarea(&sblk, BT_SUPERBLK);
- initbarea(&asblk, BT_SUPERBLK);
- sblk.b_un.b_buf = Malloc(SBLOCKSIZE);
- asblk.b_un.b_buf = Malloc(SBLOCKSIZE);
- if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
+ sblk.b_un.b_buf = Balloc(SBLOCKSIZE);
+ if (sblk.b_un.b_buf == NULL)
errx(EEXIT, "cannot allocate space for superblock");
dev_bsize = secsize = DEV_BSIZE;
}
@@ -462,7 +523,7 @@ calcsb(char *dev, int devfd, struct fs *fs)
*/
if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1)
return (0);
- fsrbuf = Malloc(secsize);
+ fsrbuf = Balloc(secsize);
if (fsrbuf == NULL)
errx(EEXIT, "calcsb: cannot allocate recovery buffer");
if (blread(devfd, fsrbuf,
@@ -495,17 +556,19 @@ chkrecovery(int devfd)
{
struct fsrecovery *fsr;
char *fsrbuf;
- u_int secsize;
+ u_int secsize, rdsize;
/*
* Could not determine if backup material exists, so do not
* offer to create it.
*/
fsrbuf = NULL;
+ rdsize = sblock.fs_fsize;
if (ioctl(devfd, DIOCGSECTORSIZE, &secsize) == -1 ||
- (fsrbuf = Malloc(secsize)) == NULL ||
- blread(devfd, fsrbuf, (SBLOCK_UFS2 - secsize) / dev_bsize,
- secsize) != 0) {
+ rdsize % secsize != 0 ||
+ (fsrbuf = Balloc(rdsize)) == NULL ||
+ blread(devfd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize,
+ rdsize) != 0) {
free(fsrbuf);
return (1);
}
@@ -513,7 +576,7 @@ chkrecovery(int devfd)
* Recovery material has already been created, so do not
* need to create it again.
*/
- fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr];
+ fsr = (struct fsrecovery *)&fsrbuf[rdsize - sizeof *fsr];
if (fsr->fsr_magic == FS_UFS2_MAGIC) {
free(fsrbuf);
return (1);
@@ -526,8 +589,8 @@ chkrecovery(int devfd)
}
/*
- * Read the last sector of the boot block, replace the last
- * 20 bytes with the recovery information, then write it back.
+ * Read the last filesystem-size piece of the boot block, replace the
+ * last 20 bytes with the recovery information, then write it back.
* The recovery information only works for UFS2 filesystems.
*/
static void
@@ -535,24 +598,26 @@ saverecovery(int readfd, int writefd)
{
struct fsrecovery *fsr;
char *fsrbuf;
- u_int secsize;
+ u_int secsize, rdsize;
fsrbuf = NULL;
+ rdsize = sblock.fs_fsize;
if (sblock.fs_magic != FS_UFS2_MAGIC ||
ioctl(readfd, DIOCGSECTORSIZE, &secsize) == -1 ||
- (fsrbuf = Malloc(secsize)) == NULL ||
- blread(readfd, fsrbuf, (SBLOCK_UFS2 - secsize) / dev_bsize,
- secsize) != 0) {
+ rdsize % secsize != 0 ||
+ (fsrbuf = Balloc(rdsize)) == NULL ||
+ blread(readfd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize,
+ rdsize) != 0) {
printf("RECOVERY DATA COULD NOT BE CREATED\n");
free(fsrbuf);
return;
}
- fsr = (struct fsrecovery *)&fsrbuf[secsize - sizeof *fsr];
+ fsr = (struct fsrecovery *)&fsrbuf[rdsize - sizeof *fsr];
fsr->fsr_magic = sblock.fs_magic;
fsr->fsr_fpg = sblock.fs_fpg;
fsr->fsr_fsbtodb = sblock.fs_fsbtodb;
fsr->fsr_sblkno = sblock.fs_sblkno;
fsr->fsr_ncg = sblock.fs_ncg;
- blwrite(writefd, fsrbuf, (SBLOCK_UFS2 - secsize) / secsize, secsize);
+ blwrite(writefd, fsrbuf, (SBLOCK_UFS2 - rdsize) / dev_bsize, rdsize);
free(fsrbuf);
}