예제 #1
0
파일: setup.c 프로젝트: sofuture/bitrig
/*
 * Read in the super block and its summary info.
 */
static int
readsb(int listerr)
{
	daddr64_t super = 0;
	int i;

	if (bflag) {
		super = bflag;

		if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
			return (0);

		if (sblock.fs_magic != FS_UFS1_MAGIC &&
		    sblock.fs_magic != FS_UFS2_MAGIC) {
			badsb(listerr, "MAGIC NUMBER WRONG");
			return (0);
		}
	} else {
		for (i = 0; sbtry[i] != -1; i++) {
			super = sbtry[i] / dev_bsize;

			if (bread(fsreadfd, (char *)&sblock, super,
			    (long)SBSIZE) != 0)
				return (0);

			if (sblock.fs_magic != FS_UFS1_MAGIC &&
			    sblock.fs_magic != FS_UFS2_MAGIC)
				continue; /* Not a superblock */

			/*
			 * Do not look for an FFS1 file system at SBLOCK_UFS2.
			 * Doing so will find the wrong super-block for file
			 * systems with 64k block size.
			 */
			if (sblock.fs_magic == FS_UFS1_MAGIC &&
			    sbtry[i] == SBLOCK_UFS2)
				continue;

			if (sblock.fs_magic == FS_UFS2_MAGIC &&
			    sblock.fs_sblockloc != sbtry[i])
				continue; /* Not a superblock */

			break;
		}

		if (sbtry[i] == -1) {
			badsb(listerr, "MAGIC NUMBER WRONG");
			return (0);
		}
	}

	sblk.b_bno = super;
	sblk.b_size = SBSIZE;

	/*
	 * run a few consistency checks of the super block
	 */
	if (sblock.fs_ncg < 1) {
		badsb(listerr, "NCG OUT OF RANGE");
		return (0);
	}
	if (sblock.fs_cpg < 1) {
		badsb(listerr, "CPG OUT OF RANGE");
		return (0);
	}
	if (sblock.fs_magic == FS_UFS1_MAGIC) {
		if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
		    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
			badsb(listerr, "NCYL LESS THAN NCG*CPG");
			return (0);
		}
	}
	if (sblock.fs_sbsize > SBSIZE) {
		badsb(listerr, "SBSIZE PREPOSTEROUSLY LARGE");
		return (0);
	}

	if (!POWEROF2(sblock.fs_bsize) || sblock.fs_bsize < MINBSIZE ||
	    sblock.fs_bsize > MAXBSIZE) {
		badsb(listerr, "ILLEGAL BLOCK SIZE IN SUPERBLOCK");
		return (0);
	}

	if (!POWEROF2(sblock.fs_fsize) || sblock.fs_fsize > sblock.fs_bsize ||
	    sblock.fs_fsize < sblock.fs_bsize / MAXFRAG) {
		badsb(listerr, "ILLEGAL FRAGMENT SIZE IN SUPERBLOCK");
		return (0);
	}


	/*
	 * Compute block size that the filesystem is based on,
	 * according to fsbtodb, and adjust superblock block number
	 * so we can tell if this is an alternate later.
	 */
	super *= dev_bsize;
	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
	sblk.b_bno = super / dev_bsize;
	if (bflag)
		goto out;
	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
	if (asblk.b_errs)
		return (0);
	if (cmpsb(&sblock, &altsblock)) {
		if (debug) {
			long *nlp, *olp, *endlp;

			printf("superblock mismatches\n");
			nlp = (long *)&altsblock;
			olp = (long *)&sblock;
			endlp = olp + (sblock.fs_sbsize / sizeof *olp);
			for ( ; olp < endlp; olp++, nlp++) {
				if (*olp == *nlp)
					continue;
				printf("offset %d, original %ld, alternate %ld\n",
				    (int)(olp - (long *)&sblock), *olp, *nlp);
			}
		}
		badsb(listerr,
		    "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN LAST ALTERNATE");
		return (0);
	}
out:
	if (sblock.fs_magic == FS_UFS1_MAGIC) {
		sblock.fs_time = sblock.fs_ffs1_time;
		sblock.fs_size = sblock.fs_ffs1_size;
		sblock.fs_dsize = sblock.fs_ffs1_dsize;
		sblock.fs_csaddr = sblock.fs_ffs1_csaddr;
		sblock.fs_cstotal.cs_ndir = sblock.fs_ffs1_cstotal.cs_ndir;
		sblock.fs_cstotal.cs_nbfree = sblock.fs_ffs1_cstotal.cs_nbfree;
		sblock.fs_cstotal.cs_nifree = sblock.fs_ffs1_cstotal.cs_nifree;
		sblock.fs_cstotal.cs_nffree = sblock.fs_ffs1_cstotal.cs_nffree;
	}
	havesb = 1;
	return (1);
}
예제 #2
0
파일: setup.c 프로젝트: ornarium/freebsd
/*
 * Read in the super block and its summary info.
 */
int
readsb(int listerr)
{
	ufs2_daddr_t super;
	int i;

	if (bflag) {
		super = bflag;
		readcnt[sblk.b_type]++;
		if ((blread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE)))
			return (0);
		if (sblock.fs_magic == FS_BAD_MAGIC) {
			fprintf(stderr, BAD_MAGIC_MSG);
			exit(11);
		}
		if (sblock.fs_magic != FS_UFS1_MAGIC &&
		    sblock.fs_magic != FS_UFS2_MAGIC) {
			fprintf(stderr, "%d is not a file system superblock\n",
			    bflag);
			return (0);
		}
	} else {
		for (i = 0; sblock_try[i] != -1; i++) {
			super = sblock_try[i] / dev_bsize;
			readcnt[sblk.b_type]++;
			if ((blread(fsreadfd, (char *)&sblock, super,
			    (long)SBLOCKSIZE)))
				return (0);
			if (sblock.fs_magic == FS_BAD_MAGIC) {
				fprintf(stderr, BAD_MAGIC_MSG);
				exit(11);
			}
			if ((sblock.fs_magic == FS_UFS1_MAGIC ||
			     (sblock.fs_magic == FS_UFS2_MAGIC &&
			      sblock.fs_sblockloc == sblock_try[i])) &&
			    sblock.fs_ncg >= 1 &&
			    sblock.fs_bsize >= MINBSIZE &&
			    sblock.fs_sbsize >= roundup(sizeof(struct fs), dev_bsize))
				break;
		}
		if (sblock_try[i] == -1) {
			fprintf(stderr, "Cannot find file system superblock\n");
			return (0);
		}
	}
	/*
	 * Compute block size that the file system is based on,
	 * according to fsbtodb, and adjust superblock block number
	 * so we can tell if this is an alternate later.
	 */
	super *= dev_bsize;
	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
	sblk.b_bno = super / dev_bsize;
	sblk.b_size = SBLOCKSIZE;
	if (bflag)
		goto out;
	/*
	 * Compare all fields that should not differ in alternate super block.
	 * When an alternate super-block is specified this check is skipped.
	 */
	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
	if (asblk.b_errs)
		return (0);
	if (altsblock.fs_sblkno != sblock.fs_sblkno ||
	    altsblock.fs_cblkno != sblock.fs_cblkno ||
	    altsblock.fs_iblkno != sblock.fs_iblkno ||
	    altsblock.fs_dblkno != sblock.fs_dblkno ||
	    altsblock.fs_ncg != sblock.fs_ncg ||
	    altsblock.fs_bsize != sblock.fs_bsize ||
	    altsblock.fs_fsize != sblock.fs_fsize ||
	    altsblock.fs_frag != sblock.fs_frag ||
	    altsblock.fs_bmask != sblock.fs_bmask ||
	    altsblock.fs_fmask != sblock.fs_fmask ||
	    altsblock.fs_bshift != sblock.fs_bshift ||
	    altsblock.fs_fshift != sblock.fs_fshift ||
	    altsblock.fs_fragshift != sblock.fs_fragshift ||
	    altsblock.fs_fsbtodb != sblock.fs_fsbtodb ||
	    altsblock.fs_sbsize != sblock.fs_sbsize ||
	    altsblock.fs_nindir != sblock.fs_nindir ||
	    altsblock.fs_inopb != sblock.fs_inopb ||
	    altsblock.fs_cssize != sblock.fs_cssize ||
	    altsblock.fs_ipg != sblock.fs_ipg ||
	    altsblock.fs_fpg != sblock.fs_fpg ||
	    altsblock.fs_magic != sblock.fs_magic) {
		badsb(listerr,
		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
		return (0);
	}
out:
	/*
	 * If not yet done, update UFS1 superblock with new wider fields.
	 */
	if (sblock.fs_magic == FS_UFS1_MAGIC &&
	    sblock.fs_maxbsize != sblock.fs_bsize) {
		sblock.fs_maxbsize = sblock.fs_bsize;
		sblock.fs_time = sblock.fs_old_time;
		sblock.fs_size = sblock.fs_old_size;
		sblock.fs_dsize = sblock.fs_old_dsize;
		sblock.fs_csaddr = sblock.fs_old_csaddr;
		sblock.fs_cstotal.cs_ndir = sblock.fs_old_cstotal.cs_ndir;
		sblock.fs_cstotal.cs_nbfree = sblock.fs_old_cstotal.cs_nbfree;
		sblock.fs_cstotal.cs_nifree = sblock.fs_old_cstotal.cs_nifree;
		sblock.fs_cstotal.cs_nffree = sblock.fs_old_cstotal.cs_nffree;
	}
	havesb = 1;
	return (1);
}
예제 #3
0
/*
 * Read in the super block and its summary info.
 */
static int
readsb(int listerr)
{
	ufs_daddr_t super = bflag ? bflag : SBOFF / dev_bsize;

	if (bread(fsreadfd, (char *)&sblock, super, (long)SBSIZE) != 0)
		return (0);
	sblk.b_bno = super;
	sblk.b_size = SBSIZE;
	/*
	 * run a few consistency checks of the super block
	 */
	if (sblock.fs_magic != FS_MAGIC)
		{ badsb(listerr, "MAGIC NUMBER WRONG"); return (0); }
	if (sblock.fs_ncg < 1)
		{ badsb(listerr, "NCG OUT OF RANGE"); return (0); }
	if (sblock.fs_cpg < 1)
		{ badsb(listerr, "CPG OUT OF RANGE"); return (0); }
	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
	    (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
		{ badsb(listerr, "NCYL LESS THAN NCG*CPG"); return (0); }
	if (sblock.fs_sbsize > SBSIZE)
		{ badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); }
	/*
	 * Compute block size that the filesystem is based on,
	 * according to fsbtodb, and adjust superblock block number
	 * so we can tell if this is an alternate later.
	 */
	super *= dev_bsize;
	dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
	sblk.b_bno = super / dev_bsize;
	if (bflag) {
		havesb = 1;
		return (1);
	}
	/*
	 * Compare all fields that should not differ in alternate super block.
	 * When an alternate super-block is specified this check is skipped.
	 */
	getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1), sblock.fs_sbsize);
	if (asblk.b_errs)
		return (0);
	if (altsblock.fs_sblkno != sblock.fs_sblkno ||
	    altsblock.fs_cblkno != sblock.fs_cblkno ||
	    altsblock.fs_iblkno != sblock.fs_iblkno ||
	    altsblock.fs_dblkno != sblock.fs_dblkno ||
	    altsblock.fs_cgoffset != sblock.fs_cgoffset ||
	    altsblock.fs_cgmask != sblock.fs_cgmask ||
	    altsblock.fs_ncg != sblock.fs_ncg ||
	    altsblock.fs_bsize != sblock.fs_bsize ||
	    altsblock.fs_fsize != sblock.fs_fsize ||
	    altsblock.fs_frag != sblock.fs_frag ||
	    altsblock.fs_bmask != sblock.fs_bmask ||
	    altsblock.fs_fmask != sblock.fs_fmask ||
	    altsblock.fs_bshift != sblock.fs_bshift ||
	    altsblock.fs_fshift != sblock.fs_fshift ||
	    altsblock.fs_fragshift != sblock.fs_fragshift ||
	    altsblock.fs_fsbtodb != sblock.fs_fsbtodb ||
	    altsblock.fs_sbsize != sblock.fs_sbsize ||
	    altsblock.fs_nindir != sblock.fs_nindir ||
	    altsblock.fs_inopb != sblock.fs_inopb ||
	    altsblock.fs_cssize != sblock.fs_cssize ||
	    altsblock.fs_cpg != sblock.fs_cpg ||
	    altsblock.fs_ipg != sblock.fs_ipg ||
	    altsblock.fs_fpg != sblock.fs_fpg ||
	    altsblock.fs_magic != sblock.fs_magic) {
		badsb(listerr,
		"VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE");
		return (0);
	}
	havesb = 1;
	return (1);
}
예제 #4
0
파일: setup.c 프로젝트: ryo/netbsd-src
/*
 * Read in the super block and its summary info, convert to host byte order.
 */
static int
readsb(int listerr)
{
	daddr_t super = bflag ? bflag : SBOFF / dev_bsize;

	if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, (long)SBSIZE) != 0)
		return 0;
	sblk.b_bno = super;
	sblk.b_size = SBSIZE;

	/* Copy the superblock in memory */
	e2fs_sbload(sblk.b_un.b_fs, &sblock.e2fs);
	
	/*
	 * run a few consistency checks of the super block
	 */
	if (sblock.e2fs.e2fs_magic != E2FS_MAGIC) {
		badsb(listerr, "MAGIC NUMBER WRONG");
		return 0;
	}
	if (sblock.e2fs.e2fs_log_bsize > 2) {
		badsb(listerr, "BAD LOG_BSIZE");
		return 0;
	}
	if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
	    (!powerof2(sblock.e2fs.e2fs_inode_size) ||
	     sblock.e2fs.e2fs_inode_size < EXT2_REV0_DINODE_SIZE ||
	     sblock.e2fs.e2fs_inode_size >
	      (1024 << sblock.e2fs.e2fs_log_bsize))) {
		badsb(listerr, "BAD INODE_SIZE");
		return 0;
	}

	/* compute the dynamic fields of the in-memory sb */
	/* compute dynamic sb infos */
	sblock.e2fs_ncg =
	    howmany(sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock,
	    sblock.e2fs.e2fs_bpg);
	/* XXX assume hw bsize = 512 */
	sblock.e2fs_fsbtodb = sblock.e2fs.e2fs_log_bsize + 1;
	sblock.e2fs_bsize = 1024 << sblock.e2fs.e2fs_log_bsize;
	sblock.e2fs_bshift = LOG_MINBSIZE + sblock.e2fs.e2fs_log_bsize;
	sblock.e2fs_qbmask = sblock.e2fs_bsize - 1;
	sblock.e2fs_bmask = ~sblock.e2fs_qbmask;
	sblock.e2fs_ngdb = howmany(sblock.e2fs_ncg,
	    sblock.e2fs_bsize / sizeof(struct ext2_gd));
	sblock.e2fs_ipb = sblock.e2fs_bsize / EXT2_DINODE_SIZE(&sblock);
	sblock.e2fs_itpg = howmany(sblock.e2fs.e2fs_ipg, sblock.e2fs_ipb);

	/*
	 * Compute block size that the filesystem is based on,
	 * according to fsbtodb, and adjust superblock block number
	 * so we can tell if this is an alternate later.
	 */
	super *= dev_bsize;
	dev_bsize = sblock.e2fs_bsize / EXT2_FSBTODB(&sblock, 1);
	sblk.b_bno = super / dev_bsize;

	if (sblock.e2fs_ncg == 1) {
		/* no alternate superblock; assume it's okay */
		havesb = 1;
		return 1;
	}
	getblk(&asblk, 1 * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock,
		(long)SBSIZE);
	if (asblk.b_errs)
		return 0;
	if (bflag) {
		havesb = 1;
		return 1;
	}

	/*
	 * Set all possible fields that could differ, then do check
	 * of whole super block against an alternate super block.
	 * When an alternate super-block is specified this check is skipped.
	 */
	asblk.b_un.b_fs->e2fs_rbcount = sblk.b_un.b_fs->e2fs_rbcount;
	asblk.b_un.b_fs->e2fs_fbcount = sblk.b_un.b_fs->e2fs_fbcount;
	asblk.b_un.b_fs->e2fs_ficount = sblk.b_un.b_fs->e2fs_ficount;
	asblk.b_un.b_fs->e2fs_mtime = sblk.b_un.b_fs->e2fs_mtime;
	asblk.b_un.b_fs->e2fs_wtime = sblk.b_un.b_fs->e2fs_wtime;
	asblk.b_un.b_fs->e2fs_mnt_count = sblk.b_un.b_fs->e2fs_mnt_count;
	asblk.b_un.b_fs->e2fs_max_mnt_count =
	    sblk.b_un.b_fs->e2fs_max_mnt_count;
	asblk.b_un.b_fs->e2fs_state = sblk.b_un.b_fs->e2fs_state;
	asblk.b_un.b_fs->e2fs_beh = sblk.b_un.b_fs->e2fs_beh;
	asblk.b_un.b_fs->e2fs_lastfsck = sblk.b_un.b_fs->e2fs_lastfsck;
	asblk.b_un.b_fs->e2fs_fsckintv = sblk.b_un.b_fs->e2fs_fsckintv;
	asblk.b_un.b_fs->e2fs_ruid = sblk.b_un.b_fs->e2fs_ruid;
	asblk.b_un.b_fs->e2fs_rgid = sblk.b_un.b_fs->e2fs_rgid;
	asblk.b_un.b_fs->e2fs_block_group_nr =
	    sblk.b_un.b_fs->e2fs_block_group_nr;
	asblk.b_un.b_fs->e2fs_features_rocompat &= ~EXT2F_ROCOMPAT_LARGEFILE;
	asblk.b_un.b_fs->e2fs_features_rocompat |=
	    sblk.b_un.b_fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE;
	if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
	    ((sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP_FSCK) ||
	    (sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP_FSCK))) {
		if (debug) {
			printf("compat 0x%08x, incompat 0x%08x, compat_ro "
			    "0x%08x\n",
			    sblock.e2fs.e2fs_features_compat,
			    sblock.e2fs.e2fs_features_incompat,
			    sblock.e2fs.e2fs_features_rocompat);

			if ((sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP_FSCK)) {
				char buf[512];

				snprintb(buf, sizeof(buf), EXT2F_ROCOMPAT_BITS,
					sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP_FSCK);
				printf("unsupported rocompat features: %s\n", buf);
			}
			if ((sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP_FSCK)) {
				char buf[512];

				snprintb(buf, sizeof(buf), EXT2F_INCOMPAT_BITS,
					sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP_FSCK);
				printf("unsupported incompat features: %s\n", buf);
			}
		}
		badsb(listerr, "INCOMPATIBLE FEATURE BITS IN SUPER BLOCK");
		return 0;
	}
	if (memcmp(sblk.b_un.b_fs, asblk.b_un.b_fs, SBSIZE)) {
		if (debug) {
			u_int32_t *nlp, *olp, *endlp;

			printf("superblock mismatches\n");
			nlp = (u_int32_t *)asblk.b_un.b_fs;
			olp = (u_int32_t *)sblk.b_un.b_fs;
			endlp = olp + (SBSIZE / sizeof(*olp));
			for ( ; olp < endlp; olp++, nlp++) {
				if (*olp == *nlp)
					continue;
				printf("offset %ld, original %ld, "
				    "alternate %ld\n",
				    (long)(olp - (u_int32_t *)sblk.b_un.b_fs),
				    (long)fs2h32(*olp),
				    (long)fs2h32(*nlp));
			}
		}
		badsb(listerr,
		    "VALUES IN SUPER BLOCK DISAGREE WITH "
		    "THOSE IN FIRST ALTERNATE");
		return 0;
	}
	havesb = 1;
	return 1;
}
예제 #5
0
파일: setup.c 프로젝트: andreiw/polaris
static int
read_super_block(int listerr)
{
	int fd;
	caddr_t err;

	if (mount_point != NULL) {
		fd = open(mount_point, O_RDONLY);
		if (fd == -1) {
			errexit("fsck: open mount point error: %s",
			    strerror(errno));
			/* NOTREACHED */
		}
		/* get the latest super block */
		if (ioctl(fd, _FIOGETSUPERBLOCK, &sblock)) {
			errexit("fsck: ioctl _FIOGETSUPERBLOCK error: %s",
			    strerror(errno));
			/* NOTREACHED */
		}
		(void) close(fd);
	} else {
		(void) fsck_bread(fsreadfd, (caddr_t)&sblock,
			bflag != 0 ? (diskaddr_t)bflag : (diskaddr_t)SBLOCK,
			SBSIZE);
	}

	/*
	 * Don't let trash from the disk trip us up later
	 * in ungetsummaryinfo().
	 */
	sblock.fs_u.fs_csp = NULL;

	/*
	 * Rudimentary consistency checks.  Can't really call
	 * checksb() here, because there may be outstanding
	 * deltas that still need to be applied.
	 */
	if ((sblock.fs_magic != FS_MAGIC) &&
	    (sblock.fs_magic != MTB_UFS_MAGIC)) {
		err = "MAGIC NUMBER WRONG";
		goto fail;
	}
	if (sblock.fs_magic == FS_MAGIC &&
		(sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
		sblock.fs_version != UFS_VERSION_MIN)) {
		err = "UNRECOGNIZED VERSION";
		goto fail;
	}
	if (sblock.fs_magic == MTB_UFS_MAGIC &&
		(sblock.fs_version > MTB_UFS_VERSION_1 ||
		sblock.fs_version < MTB_UFS_VERSION_MIN)) {
		err = "UNRECOGNIZED VERSION";
		goto fail;
	}
	if (sblock.fs_ncg < 1) {
		err = "NCG OUT OF RANGE";
		goto fail;
	}
	if (sblock.fs_cpg < 1) {
		err = "CPG OUT OF RANGE";
		goto fail;
	}
	if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
		(sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
		err = "NCYL IS INCONSISTENT WITH NCG*CPG";
		goto fail;
	}
	if (sblock.fs_sbsize < 0 || sblock.fs_sbsize > SBSIZE) {
		err = "SIZE OUT OF RANGE";
		goto fail;
	}

	return (1);

fail:
	badsb(listerr, err);
	return (0);
}
예제 #6
0
파일: setup.c 프로젝트: andreiw/polaris
/*
 * Check the super block and its summary info.
 */
static int
checksb(int listerr)
{
	caddr_t err;

	/*
	 * When the fs check is successfully completed, the alternate super
	 * block at sblk.b_bno will be overwritten by ckfini() with the
	 * repaired super block.
	 */
	sblk.b_bno = bflag ? bflag : (SBOFF / dev_bsize);
	sblk.b_size = SBSIZE;

	/*
	 * Sanity-check some of the values we are going to use later
	 * in allocation requests.
	 */
	if (sblock.fs_cstotal.cs_ndir < 1 ||
	    sblock.fs_cstotal.cs_ndir > sblock.fs_ncg * sblock.fs_ipg) {
		if (verbose)
			(void) printf(
	    "Found %d directories, should be between 1 and %d inclusive.\n",
			    sblock.fs_cstotal.cs_ndir,
			    sblock.fs_ncg * sblock.fs_ipg);
		err = "NUMBER OF DIRECTORIES OUT OF RANGE";
		goto failedsb;
	}

	if (sblock.fs_nrpos <= 0 || sblock.fs_postbloff < 0 ||
	    sblock.fs_cpc < 0 ||
	    (sblock.fs_postbloff +
	    (sblock.fs_nrpos * sblock.fs_cpc * sizeof (short))) >
	    sblock.fs_sbsize) {
		err = "ROTATIONAL POSITION TABLE SIZE OUT OF RANGE";
		goto failedsb;
	}

	if (sblock.fs_cssize !=
	    fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum))) {
		err = "SIZE OF CYLINDER GROUP SUMMARY AREA WRONG";
		goto failedsb;
	}

	if (sblock.fs_inopb != (sblock.fs_bsize / sizeof (struct dinode))) {
		err = "INOPB NONSENSICAL RELATIVE TO BSIZE";
		goto failedsb;
	}

	if (sblock.fs_bsize > MAXBSIZE) {
		err = "BLOCK SIZE LARGER THAN MAXIMUM SUPPORTED";
		goto failedsb;
	}

	if (sblock.fs_bsize != (sblock.fs_frag * sblock.fs_fsize)) {
		err = "FRAGS PER BLOCK OR FRAG SIZE WRONG";
		goto failedsb;
	}

	if (sblock.fs_dsize >= sblock.fs_size) {
		err = "NUMBER OF DATA BLOCKS OUT OF RANGE";
		goto failedsb;
	}

#if 0
	if (sblock.fs_size >
	    (sblock.fs_nsect * sblock.fs_ntrak * sblock.fs_ncyl)) {
		err = "FILESYSTEM SIZE LARGER THAN DEVICE";
		goto failedsb;
	}
#endif

	/*
	 *  Check that the number of inodes per group isn't less than or
	 *  equal to zero.  Also makes sure it isn't more than the
	 *  maximum number mkfs enforces.
	 */
	if (sblock.fs_ipg <= 0 || sblock.fs_ipg > MAXIpG) {
		err = "INODES PER GROUP OUT OF RANGE";
		goto failedsb;
	}

	if (sblock.fs_cgsize > sblock.fs_bsize) {
		err = "CG HEADER LARGER THAN ONE BLOCK";
		goto failedsb;
	}

	/*
	 * Set all possible fields that could differ, then do check
	 * of whole super block against an alternate super block.
	 * When an alternate super-block is specified this check is skipped.
	 */
	(void) getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1),
	    (size_t)sblock.fs_sbsize);
	if (asblk.b_errs != 0) {
		brelse(&asblk);
		return (0);
	}
	if (bflag != 0) {
		/*
		 * Invalidate clean flag and state information.
		 * Note that we couldn't return until after the
		 * above getblk(), because we're going to want to
		 * update asblk when everything's done.
		 */
		sblock.fs_clean = FSACTIVE;
		sblock.fs_state = (long)sblock.fs_time;
		sblock.fs_reclaim = 0;
		sbdirty();
		havesb = 1;
		return (1);
	}
	altsblock.fs_link = sblock.fs_link;
	altsblock.fs_rolled = sblock.fs_rolled;
	altsblock.fs_time = sblock.fs_time;
	altsblock.fs_state = sblock.fs_state;
	altsblock.fs_cstotal = sblock.fs_cstotal;
	altsblock.fs_cgrotor = sblock.fs_cgrotor;
	altsblock.fs_fmod = sblock.fs_fmod;
	altsblock.fs_clean = sblock.fs_clean;
	altsblock.fs_ronly = sblock.fs_ronly;
	altsblock.fs_flags = sblock.fs_flags;
	altsblock.fs_maxcontig = sblock.fs_maxcontig;
	altsblock.fs_minfree = sblock.fs_minfree;
	altsblock.fs_optim = sblock.fs_optim;
	altsblock.fs_rotdelay = sblock.fs_rotdelay;
	altsblock.fs_maxbpg = sblock.fs_maxbpg;
	altsblock.fs_logbno = sblock.fs_logbno;
	altsblock.fs_reclaim = sblock.fs_reclaim;
	altsblock.fs_si = sblock.fs_si;
	(void) memmove((void *)altsblock.fs_fsmnt, (void *)sblock.fs_fsmnt,
	    sizeof (sblock.fs_fsmnt));
	/*
	 * The following should not have to be copied.
	 */
	(void) memmove((void *)altsblock.fs_u.fs_csp_pad,
	    (void *)sblock.fs_u.fs_csp_pad, sizeof (sblock.fs_u.fs_csp_pad));
	altsblock.fs_fsbtodb = sblock.fs_fsbtodb;
	altsblock.fs_npsect = sblock.fs_npsect;
	altsblock.fs_nrpos = sblock.fs_nrpos;
	if (memcmp((void *)&sblock, (void *)&altsblock,
	    (size_t)sblock.fs_sbsize) != 0) {
		err = "BAD VALUES IN SUPER BLOCK";
		goto failedsb;
	}
	havesb = 1;
	return (1);

failedsb:
	badsb(listerr, err);
	return (0);
}