Example #1
0
HRESULT
PALAPI
CoCreateGuid(OUT GUID * pguid)
{
#if HAVE_BSD_UUID_H
    uuid_t uuid;
    uint32_t status;
    uuid_create(&uuid, &status);
    if (status != uuid_s_ok)
    {
        ASSERT("Unexpected uuid_create failure (status=%u)\n", status);
        PROCAbort();
    }

    // Encode the uuid with little endian.
    uuid_enc_le(pguid, &uuid);
#elif HAVE_LIBUUID_H
    uuid_generate_random(*(uuid_t*)pguid);

    // Change the byte order of the Data1, 2 and 3, since the uuid_generate_random
    // generates them with big endian while GUIDS need to have them in little endian.
    pguid->Data1 = SWAP32(pguid->Data1);
    pguid->Data2 = SWAP16(pguid->Data2);
    pguid->Data3 = SWAP16(pguid->Data3);
#else
    #error Don't know how to generate UUID on this platform
#endif
    return 0;
}
Example #2
0
static int
smbios_type1_initializer(struct smbios_structure *template_entry,
    const char **template_strings, char *curaddr, char **endaddr,
    uint16_t *n, uint16_t *size)
{
	struct smbios_table_type1 *type1;

	smbios_generic_initializer(template_entry, template_strings,
	    curaddr, endaddr, n, size);
	type1 = (struct smbios_table_type1 *)curaddr;

	if (guest_uuid_str != NULL) {
		uuid_t		uuid;
		uint32_t	status;

		uuid_from_string(guest_uuid_str, &uuid, &status);
		if (status != uuid_s_ok)
			return (-1);

		uuid_enc_le(&type1->uuid, &uuid);
	} else {
		MD5_CTX		mdctx;
		u_char		digest[16];
		char		hostname[MAXHOSTNAMELEN];

		/*
		 * Universally unique and yet reproducible are an
		 * oxymoron, however reproducible is desirable in
		 * this case.
		 */
		if (gethostname(hostname, sizeof(hostname)))
			return (-1);

		MD5Init(&mdctx);
		MD5Update(&mdctx, vmname, strlen(vmname));
		MD5Update(&mdctx, hostname, sizeof(hostname));
		MD5Final(digest, &mdctx);

		/*
		 * Set the variant and version number.
		 */
		digest[6] &= 0x0F;
		digest[6] |= 0x30;	/* version 3 */
		digest[8] &= 0x3F;
		digest[8] |= 0x80;

		memcpy(&type1->uuid, digest, sizeof (digest));
	}

	return (0);
}
Example #3
0
static void
rem(gd_t gd)
{
	uuid_t uuid;
	map_t m;
	struct gpt_hdr *hdr;
	struct gpt_ent *ent;
	unsigned int i;

	if ((hdr = gpt_gethdr(gd)) == NULL)
		return;

	/* Remove all matching entries in the map. */
	for (m = map_first(gd); m != NULL; m = m->map_next) {
		if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
			continue;
		if (entry > 0 && entry != m->map_index)
			continue;
		if (block > 0 && block != m->map_start)
			continue;
		if (size > 0 && size != m->map_size)
			continue;

		i = m->map_index - 1;

		hdr = gd->gpt->map_data;
		ent = (void*)((char*)gd->tbl->map_data + i *
		    le32toh(hdr->hdr_entsz));
		uuid_dec_le(&ent->ent_type, &uuid);
		if (!uuid_is_nil(&type, NULL) &&
		    !uuid_equal(&type, &uuid, NULL))
			continue;

		/* Remove the primary entry by clearing the partition type. */
		uuid_create_nil(&uuid, NULL);
		uuid_enc_le(&ent->ent_type, &uuid);

		hdr->hdr_crc_table = htole32(crc32(gd->tbl->map_data,
		    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
		hdr->hdr_crc_self = 0;
		hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));

		gpt_write(gd, gd->gpt);
		gpt_write(gd, gd->tbl);

		hdr = gd->tpg->map_data;
		ent = (void*)((char*)gd->lbt->map_data + i *
		    le32toh(hdr->hdr_entsz));

		/* Remove the secondary entry. */
		uuid_enc_le(&ent->ent_type, &uuid);

		hdr->hdr_crc_table = htole32(crc32(gd->lbt->map_data,
		    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
		hdr->hdr_crc_self = 0;
		hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));

		gpt_write(gd, gd->lbt);
		gpt_write(gd, gd->tpg);

		gpt_status(gd, m->map_index, "removed");
	}
}
Example #4
0
void
mke2fs(const char *fsys, int fi, int fo)
{
	struct timeval tv;
	int64_t minfssize;
	uint bcount, fbcount, ficount;
	uint blocks_gd, blocks_per_cg, inodes_per_cg, iblocks_per_cg;
	uint minblocks_per_cg, blocks_lastcg;
	uint ncg, cylno, sboff;
	uuid_t uuid;
	uint32_t uustat;
	int i, len, col, delta, fld_width, max_cols;
	struct winsize winsize;

	gettimeofday(&tv, NULL);
	fsi = fi;
	fso = fo;

	/*
	 * collect and verify the block and fragment sizes
	 */
	if (!powerof2(bsize)) {
		errx(EXIT_FAILURE,
		    "block size must be a power of 2, not %u\n",
		    bsize);
	}
	if (!powerof2(fsize)) {
		errx(EXIT_FAILURE,
		    "fragment size must be a power of 2, not %u\n",
		    fsize);
	}
	if (fsize < sectorsize) {
		errx(EXIT_FAILURE,
		    "fragment size %u is too small, minimum is %u\n",
		    fsize, sectorsize);
	}
	if (bsize < MINBSIZE) {
		errx(EXIT_FAILURE,
		    "block size %u is too small, minimum is %u\n",
		    bsize, MINBSIZE);
	}
	if (bsize > EXT2_MAXBSIZE) {
		errx(EXIT_FAILURE,
		    "block size %u is too large, maximum is %u\n",
		    bsize, MAXBSIZE);
	}
	if (bsize != fsize) {
		/*
		 * There is no fragment support on current ext2fs (yet?),
		 * but some kernel code refers fsize or fpg as bsize or bpg
		 * and Linux seems to set the same values to them.
		 */
		errx(EXIT_FAILURE,
		    "block size (%u) can't be different from "
		    "fragment size (%u)\n",
		    bsize, fsize);
	}

	/* variable inodesize is REV1 feature */
	if (Oflag == 0 && inodesize != EXT2_REV0_DINODE_SIZE) {
		errx(EXIT_FAILURE, "GOOD_OLD_REV file system format"
		    " doesn't support %d byte inode\n", inodesize);
	}

	sblock.e2fs.e2fs_log_bsize = ilog2(bsize) - LOG_MINBSIZE;
	/* Umm, why not e2fs_log_fsize? */
	sblock.e2fs.e2fs_fsize = ilog2(fsize) - LOG_MINBSIZE;

	sblock.e2fs_bsize = bsize;
	sblock.e2fs_bshift = sblock.e2fs.e2fs_log_bsize + LOG_MINBSIZE;
	sblock.e2fs_qbmask = sblock.e2fs_bsize - 1;
	sblock.e2fs_bmask = ~sblock.e2fs_qbmask;
	sblock.e2fs_fsbtodb = ilog2(sblock.e2fs_bsize) - ilog2(sectorsize);
	sblock.e2fs_ipb = sblock.e2fs_bsize / inodesize;

	/*
	 * Ext2fs preserves BBSIZE (1024 bytes) space at the top for
	 * bootloader (though it is not enough at all for our bootloader).
	 * If bsize == BBSIZE we have to preserve one block.
	 * If bsize > BBSIZE, the first block already contains BBSIZE space
	 * before superblock because superblock is allocated at SBOFF and
	 * bsize is a power of two (i.e. 2048 bytes or more).
	 */
	sblock.e2fs.e2fs_first_dblock = (sblock.e2fs_bsize > BBSIZE) ? 0 : 1;
	minfssize = fsbtodb(&sblock,
	    sblock.e2fs.e2fs_first_dblock +
	    NBLOCK_SUPERBLOCK +
	    1 /* at least one group descriptor */ +
	    NBLOCK_BLOCK_BITMAP	+
	    NBLOCK_INODE_BITMAP +
	    1 /* at least one inode table block */ +
	    1 /* at least one data block for rootdir */ +
	    1 /* at least one data block for data */
	    );			/* XXX and more? */

	if (fssize < minfssize)
		errx(EXIT_FAILURE, "Filesystem size %" PRId64
		    " < minimum size of %" PRId64 "\n", fssize, minfssize);

	bcount = dbtofsb(&sblock, fssize);

	/*
	 * While many people claim that ext2fs is a (bad) clone of ufs/ffs,
	 * it isn't actual ffs so maybe we should call it "block group"
	 * as their native name rather than ffs derived "cylinder group."
	 * But we'll use the latter here since other kernel sources use it.
	 * (I also agree "cylinder" based allocation is obsolete though)
	 */

	/* maybe "simple is the best" */
	blocks_per_cg = sblock.e2fs_bsize * NBBY;

	ncg = howmany(bcount - sblock.e2fs.e2fs_first_dblock, blocks_per_cg);
	blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize);

	/* check range of inode number */
	if (num_inodes < EXT2_FIRSTINO)
		num_inodes = EXT2_FIRSTINO;	/* needs reserved inodes + 1 */
	if (num_inodes > UINT16_MAX * ncg)
		num_inodes = UINT16_MAX * ncg;	/* ext2bgd_nifree is uint16_t */

	inodes_per_cg = num_inodes / ncg;
	iblocks_per_cg = howmany(inodesize * inodes_per_cg, bsize);

	/* Check that the last cylinder group has enough space for inodes */
	minblocks_per_cg =
	    NBLOCK_BLOCK_BITMAP +
	    NBLOCK_INODE_BITMAP +
	    iblocks_per_cg +
	    1;	/* at least one data block */
	if (Oflag == 0 || cg_has_sb(ncg - 1) != 0)
		minblocks_per_cg += NBLOCK_SUPERBLOCK + blocks_gd;

	blocks_lastcg = bcount - sblock.e2fs.e2fs_first_dblock -
	    blocks_per_cg * (ncg - 1);
	if (blocks_lastcg < minblocks_per_cg) {
		/*
		 * Since we make all the cylinder groups the same size, the
		 * last will only be small if there are more than one
		 * cylinder groups. If the last one is too small to store
		 * filesystem data, just kill it.
		 *
		 * XXX: Does fsck_ext2fs(8) properly handle this case?
		 */
		bcount -= blocks_lastcg;
		ncg--;
		blocks_lastcg = blocks_per_cg;
		blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize);
		inodes_per_cg = num_inodes / ncg;
	}
	/* roundup inodes_per_cg to make it use whole inode table blocks */
	inodes_per_cg = roundup(inodes_per_cg, sblock.e2fs_ipb);
	num_inodes = inodes_per_cg * ncg;
	iblocks_per_cg = inodes_per_cg / sblock.e2fs_ipb;

	/* XXX: probably we should check these adjusted values again */

	sblock.e2fs.e2fs_bcount = bcount;
	sblock.e2fs.e2fs_icount = num_inodes;

	sblock.e2fs_ncg = ncg;
	sblock.e2fs_ngdb = blocks_gd;
	sblock.e2fs_itpg = iblocks_per_cg;

	sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * minfree / 100;
	/* e2fs_fbcount will be accounted later */
	/* e2fs_ficount will be accounted later */

	sblock.e2fs.e2fs_bpg = blocks_per_cg;
	sblock.e2fs.e2fs_fpg = blocks_per_cg;

	sblock.e2fs.e2fs_ipg = inodes_per_cg;

	sblock.e2fs.e2fs_mtime = 0;
	sblock.e2fs.e2fs_wtime = tv.tv_sec;
	sblock.e2fs.e2fs_mnt_count = 0;
	/* XXX: should add some entropy to avoid checking all fs at once? */
	sblock.e2fs.e2fs_max_mnt_count = EXT2_DEF_MAX_MNT_COUNT;

	sblock.e2fs.e2fs_magic = E2FS_MAGIC;
	sblock.e2fs.e2fs_state = E2FS_ISCLEAN;
	sblock.e2fs.e2fs_beh = E2FS_BEH_DEFAULT;
	sblock.e2fs.e2fs_minrev = 0;
	sblock.e2fs.e2fs_lastfsck = tv.tv_sec;
	sblock.e2fs.e2fs_fsckintv = EXT2_DEF_FSCKINTV;

	/*
	 * Maybe we can use E2FS_OS_FREEBSD here and it would be more proper,
	 * but the purpose of this newfs_ext2fs(8) command is to provide
	 * a filesystem which can be recognized by firmware on some
	 * Linux based appliances that can load bootstrap files only from
	 * (their native) ext2fs, and anyway we will (and should) try to
	 * act like them as much as possible.
	 *
	 * Anyway, I hope that all newer such boxes will keep their support
	 * for the "GOOD_OLD_REV" ext2fs.
	 */
	sblock.e2fs.e2fs_creator = E2FS_OS_LINUX;

	if (Oflag == 0) {
		sblock.e2fs.e2fs_rev = E2FS_REV0;
		sblock.e2fs.e2fs_features_compat   = 0;
		sblock.e2fs.e2fs_features_incompat = 0;
		sblock.e2fs.e2fs_features_rocompat = 0;
	} else {
		sblock.e2fs.e2fs_rev = E2FS_REV1;
		/*
		 * e2fsprogs say "REV1" is "dynamic" so
		 * it isn't quite a version and maybe it means
		 * "extended from REV0 so check compat features."
		 *
		 * XXX: We don't have any native tool to activate
		 *      the EXT2F_COMPAT_RESIZE feature and
		 *      fsck_ext2fs(8) might not fix structures for it.
		 */
		sblock.e2fs.e2fs_features_compat   = EXT2F_COMPAT_RESIZE;
		sblock.e2fs.e2fs_features_incompat = EXT2F_INCOMPAT_FTYPE;
		sblock.e2fs.e2fs_features_rocompat =
		    EXT2F_ROCOMPAT_SPARSESUPER | EXT2F_ROCOMPAT_LARGEFILE;
	}

	sblock.e2fs.e2fs_ruid = geteuid();
	sblock.e2fs.e2fs_rgid = getegid();

	sblock.e2fs.e2fs_first_ino = EXT2_FIRSTINO;
	sblock.e2fs.e2fs_inode_size = inodesize;

	/* e2fs_block_group_nr is set on writing superblock to each group */

	uuid_create(&uuid, &uustat);
	if (uustat != uuid_s_ok)
		errx(EXIT_FAILURE, "Failed to generate uuid\n");
	uuid_enc_le(sblock.e2fs.e2fs_uuid, &uuid);
	if (volname != NULL) {
		if (strlen(volname) > sizeof(sblock.e2fs.e2fs_vname))
			errx(EXIT_FAILURE, "Volume name is too long");
		strlcpy(sblock.e2fs.e2fs_vname, volname,
		    sizeof(sblock.e2fs.e2fs_vname));
	}

	sblock.e2fs.e2fs_fsmnt[0] = '\0';
	sblock.e2fs_fsmnt[0] = '\0';

	sblock.e2fs.e2fs_algo = 0;		/* XXX unsupported? */
	sblock.e2fs.e2fs_prealloc = 0;		/* XXX unsupported? */
	sblock.e2fs.e2fs_dir_prealloc = 0;	/* XXX unsupported? */

	/* calculate blocks for reserved group descriptors for resize */
	sblock.e2fs.e2fs_reserved_ngdb = 0;
	if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
	    (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0) {
		uint64_t target_blocks;
		uint target_ncg, target_ngdb, reserved_ngdb;

		/* reserve descriptors for size as 1024 times as current */
		target_blocks =
		    (sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock)
		    * 1024ULL;
		/* number of blocks must be in uint32_t */
		if (target_blocks > UINT32_MAX)
			target_blocks = UINT32_MAX;
		target_ncg = howmany(target_blocks, sblock.e2fs.e2fs_bpg);
		target_ngdb = howmany(sizeof(struct ext2_gd) * target_ncg,
		    sblock.e2fs_bsize);
		/*
		 * Reserved group descriptor blocks are preserved as
		 * the second level double indirect reference blocks in
		 * the EXT2_RESIZEINO inode, so the maximum number of
		 * the blocks is NINDIR(fs).
		 * (see also descriptions in init_resizeino() function)
		 *
		 * We check a number including current e2fs_ngdb here
		 * because they will be moved into reserved gdb on
		 * possible future size shrink, though e2fsprogs don't
		 * seem to care about it.
		 */
		if (target_ngdb > NINDIR(&sblock))
			target_ngdb = NINDIR(&sblock);

		reserved_ngdb = target_ngdb - sblock.e2fs_ngdb;

		/* make sure reserved_ngdb fits in the last cg */
		if (reserved_ngdb >= blocks_lastcg - cgoverhead(ncg - 1))
			reserved_ngdb = blocks_lastcg - cgoverhead(ncg - 1);
		if (reserved_ngdb == 0) {
			/* if no space for reserved gdb, disable the feature */
			sblock.e2fs.e2fs_features_compat &=
			    ~EXT2F_COMPAT_RESIZE;
		}
		sblock.e2fs.e2fs_reserved_ngdb = reserved_ngdb;
	}

	/*
	 * Initialize group descriptors
	 */
	gd = malloc(sblock.e2fs_ngdb * bsize);
	if (gd == NULL)
		errx(EXIT_FAILURE, "Can't allocate descriptors buffer");
	memset(gd, 0, sblock.e2fs_ngdb * bsize);

	fbcount = 0;
	ficount = 0;
	for (cylno = 0; cylno < ncg; cylno++) {
		uint boffset;

		boffset = cgbase(&sblock, cylno);
		if (sblock.e2fs.e2fs_rev == E2FS_REV0 ||
		    (sblock.e2fs.e2fs_features_rocompat &
		     EXT2F_ROCOMPAT_SPARSESUPER) == 0 ||
		    cg_has_sb(cylno)) {
			boffset += NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb;
			if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
			    (sblock.e2fs.e2fs_features_compat &
			     EXT2F_COMPAT_RESIZE) != 0)
				boffset += sblock.e2fs.e2fs_reserved_ngdb;
		}
		gd[cylno].ext2bgd_b_bitmap = boffset;
		boffset += NBLOCK_BLOCK_BITMAP;
		gd[cylno].ext2bgd_i_bitmap = boffset;
		boffset += NBLOCK_INODE_BITMAP;
		gd[cylno].ext2bgd_i_tables = boffset;
		if (cylno == (ncg - 1))
			gd[cylno].ext2bgd_nbfree =
			    blocks_lastcg - cgoverhead(cylno);
		else
			gd[cylno].ext2bgd_nbfree =
			    sblock.e2fs.e2fs_bpg - cgoverhead(cylno);
		fbcount += gd[cylno].ext2bgd_nbfree;
		gd[cylno].ext2bgd_nifree = sblock.e2fs.e2fs_ipg;
		if (cylno == 0) {
			/* take reserved inodes off nifree */
			gd[cylno].ext2bgd_nifree -= EXT2_RESERVED_INODES;
		}
		ficount += gd[cylno].ext2bgd_nifree;
		gd[cylno].ext2bgd_ndirs = 0;
	}
	sblock.e2fs.e2fs_fbcount = fbcount;
	sblock.e2fs.e2fs_ficount = ficount;

	/*
	 * Dump out summary information about file system.
	 */
	if (verbosity > 0) {
		printf("%s: %u.%1uMB (%" PRId64 " sectors) "
		    "block size %u, fragment size %u\n",
		    fsys,
		    (uint)(((uint64_t)bcount * bsize) / (1024 * 1024)),
		    (uint)((uint64_t)bcount * bsize -
		    rounddown((uint64_t)bcount * bsize, 1024 * 1024))
		    / 1024 / 100,
		    fssize, bsize, fsize);
		printf("\tusing %u block groups of %u.0MB, %u blks, "
		    "%u inodes.\n",
		    ncg, bsize * sblock.e2fs.e2fs_bpg / (1024 * 1024),
		    sblock.e2fs.e2fs_bpg, sblock.e2fs.e2fs_ipg);
	}

	/*
	 * allocate space for superblock and group descriptors
	 */
	iobufsize = (NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb) * sblock.e2fs_bsize;
	iobuf = mmap(0, iobufsize, PROT_READ|PROT_WRITE,
	    MAP_ANON|MAP_PRIVATE, -1, 0);
	if (iobuf == NULL)
		errx(EXIT_FAILURE, "Cannot allocate I/O buffer\n");
	memset(iobuf, 0, iobufsize);

	/*
	 * We now start writing to the filesystem
	 */

	if (!Nflag) {
		static const uint pbsize[] = { 1024, 2048, 4096, 0 };
		uint pblock, epblock;
		/*
		 * Validate the given file system size.
		 * Verify that its last block can actually be accessed.
		 * Convert to file system fragment sized units.
		 */
		if (fssize <= 0)
			errx(EXIT_FAILURE, "Preposterous size %" PRId64 "\n",
			    fssize);
		wtfs(fssize - 1, sectorsize, iobuf);

		/*
		 * Ensure there is nothing that looks like a filesystem
		 * superblock anywhere other than where ours will be.
		 * If fsck_ext2fs finds the wrong one all hell breaks loose!
		 *
		 * XXX: needs to check how fsck_ext2fs programs even
		 *      on other OSes determine alternate superblocks
		 */
		for (i = 0; pbsize[i] != 0; i++) {
			epblock = (uint64_t)bcount * bsize / pbsize[i];
			for (pblock = ((pbsize[i] == SBSIZE) ? 1 : 0);
			    pblock < epblock;
			    pblock += pbsize[i] * NBBY /* bpg */)
				zap_old_sblock((daddr_t)pblock *
				    pbsize[i] / sectorsize);
		}
	}

	if (verbosity >= 3)
		printf("super-block backups (for fsck_ext2fs -b #) at:\n");
	/* If we are printing more than one line of numbers, line up columns */
	fld_width = verbosity < 4 ? 1 : snprintf(NULL, 0, "%" PRIu64,
	    (uint64_t)cgbase(&sblock, ncg - 1));
	/* Get terminal width */
	if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0)
		max_cols = winsize.ws_col;
	else
		max_cols = 80;
	if (Nflag && verbosity == 3)
		/* Leave space to add " ..." after one row of numbers */
		max_cols -= 4;
#define BASE 0x10000	/* For some fixed-point maths */
	col = 0;
	delta = verbosity > 2 ? 0 : max_cols * BASE / ncg;
	for (cylno = 0; cylno < ncg; cylno++) {
		fflush(stdout);
		initcg(cylno);
		if (verbosity < 2)
			continue;
		/* the first one is a master, not backup */
		if (cylno == 0)
			continue;
		/* skip if this cylinder doesn't have a backup */
		if (sblock.e2fs.e2fs_rev > E2FS_REV0 &&
		    (sblock.e2fs.e2fs_features_rocompat &
		     EXT2F_ROCOMPAT_SPARSESUPER) != 0 &&
		    cg_has_sb(cylno) == 0)
			continue;

		if (delta > 0) {
			if (Nflag)
				/* No point doing dots for -N */
				break;
			/* Print dots scaled to end near RH margin */
			for (col += delta; col > BASE; col -= BASE)
				printf(".");
			continue;
		}
		/* Print superblock numbers */
		len = printf(" %*" PRIu64 "," + !col, fld_width,
		    (uint64_t)cgbase(&sblock, cylno));
		col += len;
		if (col + len < max_cols)
			/* Next number fits */
			continue;
		/* Next number won't fit, need a newline */
		if (verbosity <= 3) {
			/* Print dots for subsequent cylinder groups */
			delta = sblock.e2fs_ncg - cylno - 1;
			if (delta != 0) {
				if (Nflag) {
					printf(" ...");
					break;
				}
				delta = max_cols * BASE / delta;
			}
		}
		col = 0;
		printf("\n");
	}
#undef BASE
	if (col > 0)
		printf("\n");
	if (Nflag)
		return;

	/*
	 * Now construct the initial file system,
	 */
	if (fsinit(&tv) == 0)
		errx(EXIT_FAILURE, "Error making filesystem");
	/*
	 * Write out the superblock and group descriptors
	 */
	sblock.e2fs.e2fs_block_group_nr = 0;
	sboff = 0;
	if (cgbase(&sblock, 0) == 0) {
		/*
		 * If the first block contains the boot block sectors,
		 * (i.e. in case of sblock.e2fs.e2fs_bsize > BBSIZE)
		 * we have to preserve data in it.
		 */
		sboff = SBOFF;
	}
	e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff));
	e2fs_cgsave(gd, (struct ext2_gd *)(iobuf + sblock.e2fs_bsize),
	   sizeof(struct ext2_gd) * sblock.e2fs_ncg);
	wtfs(fsbtodb(&sblock, cgbase(&sblock, 0)) + sboff / sectorsize,
	    iobufsize - sboff, iobuf + sboff);

	munmap(iobuf, iobufsize);
}