mke2fs.c revision 3984b61df41c68966bdfbb2a5e5a45ef4b9a536c
1/*
2 * mke2fs.c - Make a ext2fs filesystem.
3 *
4 * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
5 * 	2003, 2004, 2005 by Theodore Ts'o.
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Public
9 * License.
10 * %End-Header%
11 */
12
13/* Usage: mke2fs [options] device
14 *
15 * The device may be a block device or a image of one, but this isn't
16 * enforced (but it's not much fun on a character device :-).
17 */
18
19#define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX in Solaris */
20
21#include <stdio.h>
22#include <string.h>
23#include <strings.h>
24#include <fcntl.h>
25#include <ctype.h>
26#include <time.h>
27#ifdef __linux__
28#include <sys/utsname.h>
29#endif
30#ifdef HAVE_GETOPT_H
31#include <getopt.h>
32#else
33extern char *optarg;
34extern int optind;
35#endif
36#ifdef HAVE_UNISTD_H
37#include <unistd.h>
38#endif
39#ifdef HAVE_STDLIB_H
40#include <stdlib.h>
41#endif
42#ifdef HAVE_ERRNO_H
43#include <errno.h>
44#endif
45#ifdef HAVE_MNTENT_H
46#include <mntent.h>
47#endif
48#include <sys/ioctl.h>
49#include <sys/types.h>
50#include <sys/stat.h>
51#include <libgen.h>
52#include <limits.h>
53#include <blkid/blkid.h>
54
55#include "ext2fs/ext2_fs.h"
56#include "et/com_err.h"
57#include "uuid/uuid.h"
58#include "e2p/e2p.h"
59#include "ext2fs/ext2fs.h"
60#include "util.h"
61#include "profile.h"
62#include "prof_err.h"
63#include "../version.h"
64#include "nls-enable.h"
65
66#define STRIDE_LENGTH 8
67
68#ifndef __sparc__
69#define ZAP_BOOTBLOCK
70#endif
71
72#ifndef ROOT_SYSCONFDIR
73#define ROOT_SYSCONFDIR "/etc"
74#endif
75
76extern int isatty(int);
77extern FILE *fpopen(const char *cmd, const char *mode);
78
79const char * program_name = "mke2fs";
80const char * device_name /* = NULL */;
81
82/* Command line options */
83int	cflag;
84int	verbose;
85int	quiet;
86int	super_only;
87int	discard = 1;
88int	force;
89int	noaction;
90int	journal_size;
91int	journal_flags;
92int	lazy_itable_init;
93char	*bad_blocks_filename;
94__u32	fs_stride;
95
96struct ext2_super_block fs_param;
97char *fs_uuid = NULL;
98char *creator_os;
99char *volume_label;
100char *mount_dir;
101char *journal_device;
102int sync_kludge;	/* Set using the MKE2FS_SYNC env. option */
103char **fs_types;
104
105profile_t	profile;
106
107int sys_page_size = 4096;
108int linux_version_code = 0;
109
110static void usage(void)
111{
112	fprintf(stderr, _("Usage: %s [-c|-l filename] [-b block-size] "
113	"[-f fragment-size]\n\t[-i bytes-per-inode] [-I inode-size] "
114	"[-J journal-options]\n"
115	"\t[-G meta group size] [-N number-of-inodes]\n"
116	"\t[-m reserved-blocks-percentage] [-o creator-os]\n"
117	"\t[-g blocks-per-group] [-L volume-label] "
118	"[-M last-mounted-directory]\n\t[-O feature[,...]] "
119	"[-r fs-revision] [-E extended-option[,...]]\n"
120	"\t[-T fs-type] [-U UUID] [-jnqvFKSV] device [blocks-count]\n"),
121		program_name);
122	exit(1);
123}
124
125static int int_log2(int arg)
126{
127	int	l = 0;
128
129	arg >>= 1;
130	while (arg) {
131		l++;
132		arg >>= 1;
133	}
134	return l;
135}
136
137static int int_log10(unsigned int arg)
138{
139	int	l;
140
141	for (l=0; arg ; l++)
142		arg = arg / 10;
143	return l;
144}
145
146static int parse_version_number(const char *s)
147{
148	int	major, minor, rev;
149	char	*endptr;
150	const char *cp = s;
151
152	if (!s)
153		return 0;
154	major = strtol(cp, &endptr, 10);
155	if (cp == endptr || *endptr != '.')
156		return 0;
157	cp = endptr + 1;
158	minor = strtol(cp, &endptr, 10);
159	if (cp == endptr || *endptr != '.')
160		return 0;
161	cp = endptr + 1;
162	rev = strtol(cp, &endptr, 10);
163	if (cp == endptr)
164		return 0;
165	return ((((major * 256) + minor) * 256) + rev);
166}
167
168/*
169 * Helper function for read_bb_file and test_disk
170 */
171static void invalid_block(ext2_filsys fs EXT2FS_ATTR((unused)), blk_t blk)
172{
173	fprintf(stderr, _("Bad block %u out of range; ignored.\n"), blk);
174	return;
175}
176
177/*
178 * Reads the bad blocks list from a file
179 */
180static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list,
181			 const char *bad_blocks_file)
182{
183	FILE		*f;
184	errcode_t	retval;
185
186	f = fopen(bad_blocks_file, "r");
187	if (!f) {
188		com_err("read_bad_blocks_file", errno,
189			_("while trying to open %s"), bad_blocks_file);
190		exit(1);
191	}
192	retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
193	fclose (f);
194	if (retval) {
195		com_err("ext2fs_read_bb_FILE", retval,
196			_("while reading in list of bad blocks from file"));
197		exit(1);
198	}
199}
200
201#ifndef NO_CHECK_BB
202/*
203 * Runs the badblocks program to test the disk
204 */
205static void test_disk(ext2_filsys fs, badblocks_list *bb_list)
206{
207	FILE		*f;
208	errcode_t	retval;
209	char		buf[1024];
210
211	sprintf(buf, "badblocks -b %d -X %s%s%s %u", fs->blocksize,
212		quiet ? "" : "-s ", (cflag > 1) ? "-w " : "",
213		fs->device_name, fs->super->s_blocks_count-1);
214	if (verbose)
215		printf(_("Running command: %s\n"), buf);
216	f = popen(buf, "r");
217	if (!f) {
218		com_err("popen", errno,
219			_("while trying to run '%s'"), buf);
220		exit(1);
221	}
222	retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
223	pclose(f);
224	if (retval) {
225		com_err("ext2fs_read_bb_FILE", retval,
226			_("while processing list of bad blocks from program"));
227		exit(1);
228	}
229}
230#endif
231
232static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
233{
234	dgrp_t			i;
235	blk_t			j;
236	unsigned 		must_be_good;
237	blk_t			blk;
238	badblocks_iterate	bb_iter;
239	errcode_t		retval;
240	blk_t			group_block;
241	int			group;
242	int			group_bad;
243
244	if (!bb_list)
245		return;
246
247	/*
248	 * The primary superblock and group descriptors *must* be
249	 * good; if not, abort.
250	 */
251	must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks;
252	for (i = fs->super->s_first_data_block; i <= must_be_good; i++) {
253		if (ext2fs_badblocks_list_test(bb_list, i)) {
254			fprintf(stderr, _("Block %d in primary "
255				"superblock/group descriptor area bad.\n"), i);
256			fprintf(stderr, _("Blocks %u through %u must be good "
257				"in order to build a filesystem.\n"),
258				fs->super->s_first_data_block, must_be_good);
259			fputs(_("Aborting....\n"), stderr);
260			exit(1);
261		}
262	}
263
264	/*
265	 * See if any of the bad blocks are showing up in the backup
266	 * superblocks and/or group descriptors.  If so, issue a
267	 * warning and adjust the block counts appropriately.
268	 */
269	group_block = fs->super->s_first_data_block +
270		fs->super->s_blocks_per_group;
271
272	for (i = 1; i < fs->group_desc_count; i++) {
273		group_bad = 0;
274		for (j=0; j < fs->desc_blocks+1; j++) {
275			if (ext2fs_badblocks_list_test(bb_list,
276						       group_block + j)) {
277				if (!group_bad)
278					fprintf(stderr,
279_("Warning: the backup superblock/group descriptors at block %u contain\n"
280"	bad blocks.\n\n"),
281						group_block);
282				group_bad++;
283				group = ext2fs_group_of_blk(fs, group_block+j);
284				fs->group_desc[group].bg_free_blocks_count++;
285				ext2fs_group_desc_csum_set(fs, group);
286				fs->super->s_free_blocks_count++;
287			}
288		}
289		group_block += fs->super->s_blocks_per_group;
290	}
291
292	/*
293	 * Mark all the bad blocks as used...
294	 */
295	retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
296	if (retval) {
297		com_err("ext2fs_badblocks_list_iterate_begin", retval,
298			_("while marking bad blocks as used"));
299		exit(1);
300	}
301	while (ext2fs_badblocks_list_iterate(bb_iter, &blk))
302		ext2fs_mark_block_bitmap(fs->block_map, blk);
303	ext2fs_badblocks_list_iterate_end(bb_iter);
304}
305
306/*
307 * These functions implement a generalized progress meter.
308 */
309struct progress_struct {
310	char		format[20];
311	char		backup[80];
312	__u32		max;
313	int		skip_progress;
314};
315
316static void progress_init(struct progress_struct *progress,
317			  const char *label,__u32 max)
318{
319	int	i;
320
321	memset(progress, 0, sizeof(struct progress_struct));
322	if (quiet)
323		return;
324
325	/*
326	 * Figure out how many digits we need
327	 */
328	i = int_log10(max);
329	sprintf(progress->format, "%%%dd/%%%dld", i, i);
330	memset(progress->backup, '\b', sizeof(progress->backup)-1);
331	progress->backup[sizeof(progress->backup)-1] = 0;
332	if ((2*i)+1 < (int) sizeof(progress->backup))
333		progress->backup[(2*i)+1] = 0;
334	progress->max = max;
335
336	progress->skip_progress = 0;
337	if (getenv("MKE2FS_SKIP_PROGRESS"))
338		progress->skip_progress++;
339
340	fputs(label, stdout);
341	fflush(stdout);
342}
343
344static void progress_update(struct progress_struct *progress, __u32 val)
345{
346	if ((progress->format[0] == 0) || progress->skip_progress)
347		return;
348	printf(progress->format, val, progress->max);
349	fputs(progress->backup, stdout);
350}
351
352static void progress_close(struct progress_struct *progress)
353{
354	if (progress->format[0] == 0)
355		return;
356	fputs(_("done                            \n"), stdout);
357}
358
359static void write_inode_tables(ext2_filsys fs, int lazy_flag)
360{
361	errcode_t	retval;
362	blk_t		blk;
363	dgrp_t		i;
364	int		num, ipb;
365	struct progress_struct progress;
366
367	if (quiet)
368		memset(&progress, 0, sizeof(progress));
369	else
370		progress_init(&progress, _("Writing inode tables: "),
371			      fs->group_desc_count);
372
373	for (i = 0; i < fs->group_desc_count; i++) {
374		progress_update(&progress, i);
375
376		blk = fs->group_desc[i].bg_inode_table;
377		num = fs->inode_blocks_per_group;
378
379		if (lazy_flag) {
380			ipb = fs->blocksize / EXT2_INODE_SIZE(fs->super);
381			num = ((((fs->super->s_inodes_per_group -
382				  fs->group_desc[i].bg_itable_unused) *
383				 EXT2_INODE_SIZE(fs->super)) +
384				EXT2_BLOCK_SIZE(fs->super) - 1) /
385			       EXT2_BLOCK_SIZE(fs->super));
386		} else {
387			/* The kernel doesn't need to zero the itable blocks */
388			fs->group_desc[i].bg_flags |= EXT2_BG_INODE_ZEROED;
389			ext2fs_group_desc_csum_set(fs, i);
390		}
391		retval = ext2fs_zero_blocks(fs, blk, num, &blk, &num);
392		if (retval) {
393			fprintf(stderr, _("\nCould not write %d "
394				  "blocks in inode table starting at %u: %s\n"),
395				num, blk, error_message(retval));
396			exit(1);
397		}
398		if (sync_kludge) {
399			if (sync_kludge == 1)
400				sync();
401			else if ((i % sync_kludge) == 0)
402				sync();
403		}
404	}
405	ext2fs_zero_blocks(0, 0, 0, 0, 0);
406	progress_close(&progress);
407}
408
409static void create_root_dir(ext2_filsys fs)
410{
411	errcode_t		retval;
412	struct ext2_inode	inode;
413	__u32			uid, gid;
414
415	retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
416	if (retval) {
417		com_err("ext2fs_mkdir", retval, _("while creating root dir"));
418		exit(1);
419	}
420	if (geteuid()) {
421		retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode);
422		if (retval) {
423			com_err("ext2fs_read_inode", retval,
424				_("while reading root inode"));
425			exit(1);
426		}
427		uid = getuid();
428		inode.i_uid = uid;
429		ext2fs_set_i_uid_high(inode, uid >> 16);
430		if (uid) {
431			gid = getgid();
432			inode.i_gid = gid;
433			ext2fs_set_i_gid_high(inode, gid >> 16);
434		}
435		retval = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode);
436		if (retval) {
437			com_err("ext2fs_write_inode", retval,
438				_("while setting root inode ownership"));
439			exit(1);
440		}
441	}
442}
443
444static void create_lost_and_found(ext2_filsys fs)
445{
446	unsigned int		lpf_size = 0;
447	errcode_t		retval;
448	ext2_ino_t		ino;
449	const char		*name = "lost+found";
450	int			i;
451
452	fs->umask = 077;
453	retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
454	if (retval) {
455		com_err("ext2fs_mkdir", retval,
456			_("while creating /lost+found"));
457		exit(1);
458	}
459
460	retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
461	if (retval) {
462		com_err("ext2_lookup", retval,
463			_("while looking up /lost+found"));
464		exit(1);
465	}
466
467	for (i=1; i < EXT2_NDIR_BLOCKS; i++) {
468		/* Ensure that lost+found is at least 2 blocks, so we always
469		 * test large empty blocks for big-block filesystems.  */
470		if ((lpf_size += fs->blocksize) >= 16*1024 &&
471		    lpf_size >= 2 * fs->blocksize)
472			break;
473		retval = ext2fs_expand_dir(fs, ino);
474		if (retval) {
475			com_err("ext2fs_expand_dir", retval,
476				_("while expanding /lost+found"));
477			exit(1);
478		}
479	}
480}
481
482static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list)
483{
484	errcode_t	retval;
485
486	ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
487	ext2fs_inode_alloc_stats2(fs, EXT2_BAD_INO, +1, 0);
488	retval = ext2fs_update_bb_inode(fs, bb_list);
489	if (retval) {
490		com_err("ext2fs_update_bb_inode", retval,
491			_("while setting bad block inode"));
492		exit(1);
493	}
494
495}
496
497static void reserve_inodes(ext2_filsys fs)
498{
499	ext2_ino_t	i;
500
501	for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++)
502		ext2fs_inode_alloc_stats2(fs, i, +1, 0);
503	ext2fs_mark_ib_dirty(fs);
504}
505
506#define BSD_DISKMAGIC   (0x82564557UL)  /* The disk magic number */
507#define BSD_MAGICDISK   (0x57455682UL)  /* The disk magic number reversed */
508#define BSD_LABEL_OFFSET        64
509
510static void zap_sector(ext2_filsys fs, int sect, int nsect)
511{
512	char *buf;
513	int retval;
514	unsigned int *magic;
515
516	buf = malloc(512*nsect);
517	if (!buf) {
518		printf(_("Out of memory erasing sectors %d-%d\n"),
519		       sect, sect + nsect - 1);
520		exit(1);
521	}
522
523	if (sect == 0) {
524		/* Check for a BSD disklabel, and don't erase it if so */
525		retval = io_channel_read_blk(fs->io, 0, -512, buf);
526		if (retval)
527			fprintf(stderr,
528				_("Warning: could not read block 0: %s\n"),
529				error_message(retval));
530		else {
531			magic = (unsigned int *) (buf + BSD_LABEL_OFFSET);
532			if ((*magic == BSD_DISKMAGIC) ||
533			    (*magic == BSD_MAGICDISK))
534				return;
535		}
536	}
537
538	memset(buf, 0, 512*nsect);
539	io_channel_set_blksize(fs->io, 512);
540	retval = io_channel_write_blk(fs->io, sect, -512*nsect, buf);
541	io_channel_set_blksize(fs->io, fs->blocksize);
542	free(buf);
543	if (retval)
544		fprintf(stderr, _("Warning: could not erase sector %d: %s\n"),
545			sect, error_message(retval));
546}
547
548static void create_journal_dev(ext2_filsys fs)
549{
550	struct progress_struct progress;
551	errcode_t		retval;
552	char			*buf;
553	blk_t			blk, err_blk;
554	int			c, count, err_count;
555
556	retval = ext2fs_create_journal_superblock(fs,
557				  fs->super->s_blocks_count, 0, &buf);
558	if (retval) {
559		com_err("create_journal_dev", retval,
560			_("while initializing journal superblock"));
561		exit(1);
562	}
563	if (quiet)
564		memset(&progress, 0, sizeof(progress));
565	else
566		progress_init(&progress, _("Zeroing journal device: "),
567			      fs->super->s_blocks_count);
568
569	blk = 0;
570	count = fs->super->s_blocks_count;
571	while (count > 0) {
572		if (count > 1024)
573			c = 1024;
574		else
575			c = count;
576		retval = ext2fs_zero_blocks(fs, blk, c, &err_blk, &err_count);
577		if (retval) {
578			com_err("create_journal_dev", retval,
579				_("while zeroing journal device "
580				  "(block %u, count %d)"),
581				err_blk, err_count);
582			exit(1);
583		}
584		blk += c;
585		count -= c;
586		progress_update(&progress, blk);
587	}
588	ext2fs_zero_blocks(0, 0, 0, 0, 0);
589
590	retval = io_channel_write_blk(fs->io,
591				      fs->super->s_first_data_block+1,
592				      1, buf);
593	if (retval) {
594		com_err("create_journal_dev", retval,
595			_("while writing journal superblock"));
596		exit(1);
597	}
598	progress_close(&progress);
599}
600
601static void show_stats(ext2_filsys fs)
602{
603	struct ext2_super_block *s = fs->super;
604	char 			buf[80];
605        char                    *os;
606	blk_t			group_block;
607	dgrp_t			i;
608	int			need, col_left;
609
610	if (fs_param.s_blocks_count != s->s_blocks_count)
611		fprintf(stderr, _("warning: %u blocks unused.\n\n"),
612		       fs_param.s_blocks_count - s->s_blocks_count);
613
614	memset(buf, 0, sizeof(buf));
615	strncpy(buf, s->s_volume_name, sizeof(s->s_volume_name));
616	printf(_("Filesystem label=%s\n"), buf);
617	fputs(_("OS type: "), stdout);
618        os = e2p_os2string(fs->super->s_creator_os);
619	fputs(os, stdout);
620	free(os);
621	printf("\n");
622	printf(_("Block size=%u (log=%u)\n"), fs->blocksize,
623		s->s_log_block_size);
624	printf(_("Fragment size=%u (log=%u)\n"), fs->fragsize,
625		s->s_log_frag_size);
626	printf(_("Stride=%u blocks, Stripe width=%u blocks\n"),
627	       s->s_raid_stride, s->s_raid_stripe_width);
628	printf(_("%u inodes, %u blocks\n"), s->s_inodes_count,
629	       s->s_blocks_count);
630	printf(_("%u blocks (%2.2f%%) reserved for the super user\n"),
631		s->s_r_blocks_count,
632	       100.0 * s->s_r_blocks_count / s->s_blocks_count);
633	printf(_("First data block=%u\n"), s->s_first_data_block);
634	if (s->s_reserved_gdt_blocks)
635		printf(_("Maximum filesystem blocks=%lu\n"),
636		       (s->s_reserved_gdt_blocks + fs->desc_blocks) *
637		       EXT2_DESC_PER_BLOCK(s) * s->s_blocks_per_group);
638	if (fs->group_desc_count > 1)
639		printf(_("%u block groups\n"), fs->group_desc_count);
640	else
641		printf(_("%u block group\n"), fs->group_desc_count);
642	printf(_("%u blocks per group, %u fragments per group\n"),
643	       s->s_blocks_per_group, s->s_frags_per_group);
644	printf(_("%u inodes per group\n"), s->s_inodes_per_group);
645
646	if (fs->group_desc_count == 1) {
647		printf("\n");
648		return;
649	}
650
651	printf(_("Superblock backups stored on blocks: "));
652	group_block = s->s_first_data_block;
653	col_left = 0;
654	for (i = 1; i < fs->group_desc_count; i++) {
655		group_block += s->s_blocks_per_group;
656		if (!ext2fs_bg_has_super(fs, i))
657			continue;
658		if (i != 1)
659			printf(", ");
660		need = int_log10(group_block) + 2;
661		if (need > col_left) {
662			printf("\n\t");
663			col_left = 72;
664		}
665		col_left -= need;
666		printf("%u", group_block);
667	}
668	printf("\n\n");
669}
670
671/*
672 * Set the S_CREATOR_OS field.  Return true if OS is known,
673 * otherwise, 0.
674 */
675static int set_os(struct ext2_super_block *sb, char *os)
676{
677	if (isdigit (*os))
678		sb->s_creator_os = atoi (os);
679	else if (strcasecmp(os, "linux") == 0)
680		sb->s_creator_os = EXT2_OS_LINUX;
681	else if (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0)
682		sb->s_creator_os = EXT2_OS_HURD;
683	else if (strcasecmp(os, "freebsd") == 0)
684		sb->s_creator_os = EXT2_OS_FREEBSD;
685	else if (strcasecmp(os, "lites") == 0)
686		sb->s_creator_os = EXT2_OS_LITES;
687	else
688		return 0;
689	return 1;
690}
691
692#define PATH_SET "PATH=/sbin"
693
694static void parse_extended_opts(struct ext2_super_block *param,
695				const char *opts)
696{
697	char	*buf, *token, *next, *p, *arg, *badopt = 0;
698	int	len;
699	int	r_usage = 0;
700
701	len = strlen(opts);
702	buf = malloc(len+1);
703	if (!buf) {
704		fprintf(stderr,
705			_("Couldn't allocate memory to parse options!\n"));
706		exit(1);
707	}
708	strcpy(buf, opts);
709	for (token = buf; token && *token; token = next) {
710		p = strchr(token, ',');
711		next = 0;
712		if (p) {
713			*p = 0;
714			next = p+1;
715		}
716		arg = strchr(token, '=');
717		if (arg) {
718			*arg = 0;
719			arg++;
720		}
721		if (strcmp(token, "stride") == 0) {
722			if (!arg) {
723				r_usage++;
724				badopt = token;
725				continue;
726			}
727			param->s_raid_stride = strtoul(arg, &p, 0);
728			if (*p || (param->s_raid_stride == 0)) {
729				fprintf(stderr,
730					_("Invalid stride parameter: %s\n"),
731					arg);
732				r_usage++;
733				continue;
734			}
735		} else if (strcmp(token, "stripe-width") == 0 ||
736			   strcmp(token, "stripe_width") == 0) {
737			if (!arg) {
738				r_usage++;
739				badopt = token;
740				continue;
741			}
742			param->s_raid_stripe_width = strtoul(arg, &p, 0);
743			if (*p || (param->s_raid_stripe_width == 0)) {
744				fprintf(stderr,
745					_("Invalid stripe-width parameter: %s\n"),
746					arg);
747				r_usage++;
748				continue;
749			}
750		} else if (!strcmp(token, "resize")) {
751			unsigned long resize, bpg, rsv_groups;
752			unsigned long group_desc_count, desc_blocks;
753			unsigned int gdpb, blocksize;
754			int rsv_gdb;
755
756			if (!arg) {
757				r_usage++;
758				badopt = token;
759				continue;
760			}
761
762			resize = parse_num_blocks(arg,
763						  param->s_log_block_size);
764
765			if (resize == 0) {
766				fprintf(stderr,
767					_("Invalid resize parameter: %s\n"),
768					arg);
769				r_usage++;
770				continue;
771			}
772			if (resize <= param->s_blocks_count) {
773				fprintf(stderr,
774					_("The resize maximum must be greater "
775					  "than the filesystem size.\n"));
776				r_usage++;
777				continue;
778			}
779
780			blocksize = EXT2_BLOCK_SIZE(param);
781			bpg = param->s_blocks_per_group;
782			if (!bpg)
783				bpg = blocksize * 8;
784			gdpb = EXT2_DESC_PER_BLOCK(param);
785			group_desc_count =
786				ext2fs_div_ceil(param->s_blocks_count, bpg);
787			desc_blocks = (group_desc_count +
788				       gdpb - 1) / gdpb;
789			rsv_groups = ext2fs_div_ceil(resize, bpg);
790			rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) -
791				desc_blocks;
792			if (rsv_gdb > (int) EXT2_ADDR_PER_BLOCK(param))
793				rsv_gdb = EXT2_ADDR_PER_BLOCK(param);
794
795			if (rsv_gdb > 0) {
796				if (param->s_rev_level == EXT2_GOOD_OLD_REV) {
797					fprintf(stderr,
798	_("On-line resizing not supported with revision 0 filesystems\n"));
799					free(buf);
800					exit(1);
801				}
802				param->s_feature_compat |=
803					EXT2_FEATURE_COMPAT_RESIZE_INODE;
804
805				param->s_reserved_gdt_blocks = rsv_gdb;
806			}
807		} else if (!strcmp(token, "test_fs")) {
808			param->s_flags |= EXT2_FLAGS_TEST_FILESYS;
809		} else if (!strcmp(token, "lazy_itable_init")) {
810			if (arg)
811				lazy_itable_init = strtoul(arg, &p, 0);
812			else
813				lazy_itable_init = 1;
814		} else {
815			r_usage++;
816			badopt = token;
817		}
818	}
819	if (r_usage) {
820		fprintf(stderr, _("\nBad option(s) specified: %s\n\n"
821			"Extended options are separated by commas, "
822			"and may take an argument which\n"
823			"\tis set off by an equals ('=') sign.\n\n"
824			"Valid extended options are:\n"
825			"\tstride=<RAID per-disk data chunk in blocks>\n"
826			"\tstripe-width=<RAID stride * data disks in blocks>\n"
827			"\tresize=<resize maximum size in blocks>\n"
828			"\tlazy_itable_init=<0 to disable, 1 to enable>\n"
829			"\ttest_fs\n\n"),
830			badopt ? badopt : "");
831		free(buf);
832		exit(1);
833	}
834	if (param->s_raid_stride &&
835	    (param->s_raid_stripe_width % param->s_raid_stride) != 0)
836		fprintf(stderr, _("\nWarning: RAID stripe-width %u not an even "
837				  "multiple of stride %u.\n\n"),
838			param->s_raid_stripe_width, param->s_raid_stride);
839
840	free(buf);
841}
842
843static __u32 ok_features[3] = {
844	/* Compat */
845	EXT3_FEATURE_COMPAT_HAS_JOURNAL |
846		EXT2_FEATURE_COMPAT_RESIZE_INODE |
847		EXT2_FEATURE_COMPAT_DIR_INDEX |
848		EXT2_FEATURE_COMPAT_EXT_ATTR,
849	/* Incompat */
850	EXT2_FEATURE_INCOMPAT_FILETYPE|
851		EXT3_FEATURE_INCOMPAT_EXTENTS|
852		EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
853		EXT2_FEATURE_INCOMPAT_META_BG|
854		EXT4_FEATURE_INCOMPAT_FLEX_BG,
855	/* R/O compat */
856	EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
857		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
858		EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
859		EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
860		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
861		EXT4_FEATURE_RO_COMPAT_GDT_CSUM
862};
863
864
865static void syntax_err_report(const char *filename, long err, int line_num)
866{
867	fprintf(stderr,
868		_("Syntax error in mke2fs config file (%s, line #%d)\n\t%s\n"),
869		filename, line_num, error_message(err));
870	exit(1);
871}
872
873static const char *config_fn[] = { ROOT_SYSCONFDIR "/mke2fs.conf", 0 };
874
875static void edit_feature(const char *str, __u32 *compat_array)
876{
877	if (!str)
878		return;
879
880	if (e2p_edit_feature(str, compat_array, ok_features)) {
881		fprintf(stderr, _("Invalid filesystem option set: %s\n"),
882			str);
883		exit(1);
884	}
885}
886
887struct str_list {
888	char **list;
889	int num;
890	int max;
891};
892
893static errcode_t init_list(struct str_list *sl)
894{
895	sl->num = 0;
896	sl->max = 0;
897	sl->list = malloc((sl->max+1) * sizeof(char *));
898	if (!sl->list)
899		return ENOMEM;
900	sl->list[0] = 0;
901	return 0;
902}
903
904static errcode_t push_string(struct str_list *sl, const char *str)
905{
906	char **new_list;
907
908	if (sl->num >= sl->max) {
909		sl->max += 2;
910		new_list = realloc(sl->list, (sl->max+1) * sizeof(char *));
911		if (!new_list)
912			return ENOMEM;
913		sl->list = new_list;
914	}
915	sl->list[sl->num] = malloc(strlen(str)+1);
916	if (sl->list[sl->num] == 0)
917		return ENOMEM;
918	strcpy(sl->list[sl->num], str);
919	sl->num++;
920	sl->list[sl->num] = 0;
921	return 0;
922}
923
924static void print_str_list(char **list)
925{
926	char **cpp;
927
928	for (cpp = list; *cpp; cpp++) {
929		printf("'%s'", *cpp);
930		if (cpp[1])
931			fputs(", ", stdout);
932	}
933	fputc('\n', stdout);
934}
935
936static char **parse_fs_type(const char *fs_type,
937			    const char *usage_types,
938			    struct ext2_super_block *fs_param,
939			    char *progname)
940{
941	const char	*ext_type = 0;
942	char		*parse_str;
943	char		*profile_type = 0;
944	char		*cp, *t;
945	const char	*size_type;
946	struct str_list	list;
947	unsigned long	meg;
948	int		is_hurd = 0;
949
950	if (init_list(&list))
951		return 0;
952
953	if (creator_os && (!strcasecmp(creator_os, "GNU") ||
954			   !strcasecmp(creator_os, "hurd")))
955		is_hurd = 1;
956
957	if (fs_type)
958		ext_type = fs_type;
959	else if (is_hurd)
960		ext_type = "ext2";
961	else if (!strcmp(program_name, "mke3fs"))
962		ext_type = "ext3";
963	else if (progname) {
964		ext_type = strrchr(progname, '/');
965		if (ext_type)
966			ext_type++;
967		else
968			ext_type = progname;
969
970		if (!strncmp(ext_type, "mkfs.", 5)) {
971			ext_type += 5;
972			if (ext_type[0] == 0)
973				ext_type = 0;
974		} else
975			ext_type = 0;
976	}
977
978	if (!ext_type) {
979		profile_get_string(profile, "defaults", "fs_type", 0,
980				   "ext2", &profile_type);
981		ext_type = profile_type;
982		if (!strcmp(ext_type, "ext2") && (journal_size != 0))
983			ext_type = "ext3";
984	}
985
986	if (!strcmp(ext_type, "ext3") || !strcmp(ext_type, "ext4") ||
987	    !strcmp(ext_type, "ext4dev")) {
988		profile_get_string(profile, "fs_types", ext_type, "features",
989				   0, &t);
990		if (!t) {
991			printf(_("\nWarning!  Your mke2fs.conf file does "
992				 "not define the %s filesystem type.\n"),
993			       ext_type);
994			printf(_("You probably need to install an updated "
995				 "mke2fs.conf file.\n\n"));
996			sleep(5);
997		}
998	}
999
1000	meg = (1024 * 1024) / EXT2_BLOCK_SIZE(fs_param);
1001	if (fs_param->s_blocks_count < 3 * meg)
1002		size_type = "floppy";
1003	else if (fs_param->s_blocks_count < 512 * meg)
1004		size_type = "small";
1005	else
1006		size_type = "default";
1007
1008	if (!usage_types)
1009		usage_types = size_type;
1010
1011	parse_str = malloc(usage_types ? strlen(usage_types)+1 : 1);
1012	if (!parse_str) {
1013		free(list.list);
1014		return 0;
1015	}
1016	if (usage_types)
1017		strcpy(parse_str, usage_types);
1018	else
1019		*parse_str = '\0';
1020
1021	if (ext_type)
1022		push_string(&list, ext_type);
1023	cp = parse_str;
1024	while (1) {
1025		t = strchr(cp, ',');
1026		if (t)
1027			*t = '\0';
1028
1029		if (*cp)
1030			push_string(&list, cp);
1031		if (t)
1032			cp = t+1;
1033		else {
1034			cp = "";
1035			break;
1036		}
1037	}
1038	free(parse_str);
1039	free(profile_type);
1040	if (is_hurd)
1041		push_string(&list, "hurd");
1042	return (list.list);
1043}
1044
1045static char *get_string_from_profile(char **fs_types, const char *opt,
1046				     const char *def_val)
1047{
1048	char *ret = 0;
1049	int i;
1050
1051	for (i=0; fs_types[i]; i++);
1052	for (i-=1; i >=0 ; i--) {
1053		profile_get_string(profile, "fs_types", fs_types[i],
1054				   opt, 0, &ret);
1055		if (ret)
1056			return ret;
1057	}
1058	profile_get_string(profile, "defaults", opt, 0, def_val, &ret);
1059	return (ret);
1060}
1061
1062static int get_int_from_profile(char **fs_types, const char *opt, int def_val)
1063{
1064	int ret;
1065	char **cpp;
1066
1067	profile_get_integer(profile, "defaults", opt, 0, def_val, &ret);
1068	for (cpp = fs_types; *cpp; cpp++)
1069		profile_get_integer(profile, "fs_types", *cpp, opt, ret, &ret);
1070	return ret;
1071}
1072
1073static int get_bool_from_profile(char **fs_types, const char *opt, int def_val)
1074{
1075	int ret;
1076	char **cpp;
1077
1078	profile_get_boolean(profile, "defaults", opt, 0, def_val, &ret);
1079	for (cpp = fs_types; *cpp; cpp++)
1080		profile_get_boolean(profile, "fs_types", *cpp, opt, ret, &ret);
1081	return ret;
1082}
1083
1084extern const char *mke2fs_default_profile;
1085static const char *default_files[] = { "<default>", 0 };
1086
1087#ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY
1088/*
1089 * Sets the geometry of a device (stripe/stride), and returns the
1090 * device's alignment offset, if any, or a negative error.
1091 */
1092static int ext2fs_get_device_geometry(const char *file,
1093				      struct ext2_super_block *fs_param)
1094{
1095	int rc = -1;
1096	int blocksize;
1097	blkid_probe pr;
1098	blkid_topology tp;
1099	unsigned long min_io;
1100	unsigned long opt_io;
1101	struct stat statbuf;
1102
1103	/* Nothing to do for a regular file */
1104	if (!stat(file, &statbuf) && S_ISREG(statbuf.st_mode))
1105		return 0;
1106
1107	pr = blkid_new_probe_from_filename(file);
1108	if (!pr)
1109		goto out;
1110
1111	tp = blkid_probe_get_topology(pr);
1112	if (!tp)
1113		goto out;
1114
1115	min_io = blkid_topology_get_minimum_io_size(tp);
1116	opt_io = blkid_topology_get_optimal_io_size(tp);
1117	blocksize = EXT2_BLOCK_SIZE(fs_param);
1118
1119	fs_param->s_raid_stride = min_io / blocksize;
1120	fs_param->s_raid_stripe_width = opt_io / blocksize;
1121
1122	rc = blkid_topology_get_alignment_offset(tp);
1123out:
1124	blkid_free_probe(pr);
1125	return rc;
1126}
1127#endif
1128
1129static void PRS(int argc, char *argv[])
1130{
1131	int		b, c;
1132	int		size;
1133	char 		*tmp, **cpp;
1134	int		blocksize = 0;
1135	int		inode_ratio = 0;
1136	int		inode_size = 0;
1137	unsigned long	flex_bg_size = 0;
1138	double		reserved_ratio = 5.0;
1139	int		sector_size = 0;
1140	int		show_version_only = 0;
1141	unsigned long long num_inodes = 0; /* unsigned long long to catch too-large input */
1142	errcode_t	retval;
1143	char *		oldpath = getenv("PATH");
1144	char *		extended_opts = 0;
1145	const char *	fs_type = 0;
1146	const char *	usage_types = 0;
1147	blk_t		dev_size;
1148#ifdef __linux__
1149	struct 		utsname ut;
1150#endif
1151	long		sysval;
1152	int		s_opt = -1, r_opt = -1;
1153	char		*fs_features = 0;
1154	int		use_bsize;
1155	char		*newpath;
1156	int		pathlen = sizeof(PATH_SET) + 1;
1157
1158	if (oldpath)
1159		pathlen += strlen(oldpath);
1160	newpath = malloc(pathlen);
1161	strcpy(newpath, PATH_SET);
1162
1163	/* Update our PATH to include /sbin  */
1164	if (oldpath) {
1165		strcat (newpath, ":");
1166		strcat (newpath, oldpath);
1167	}
1168	putenv (newpath);
1169
1170	tmp = getenv("MKE2FS_SYNC");
1171	if (tmp)
1172		sync_kludge = atoi(tmp);
1173
1174	/* Determine the system page size if possible */
1175#ifdef HAVE_SYSCONF
1176#if (!defined(_SC_PAGESIZE) && defined(_SC_PAGE_SIZE))
1177#define _SC_PAGESIZE _SC_PAGE_SIZE
1178#endif
1179#ifdef _SC_PAGESIZE
1180	sysval = sysconf(_SC_PAGESIZE);
1181	if (sysval > 0)
1182		sys_page_size = sysval;
1183#endif /* _SC_PAGESIZE */
1184#endif /* HAVE_SYSCONF */
1185
1186	if ((tmp = getenv("MKE2FS_CONFIG")) != NULL)
1187		config_fn[0] = tmp;
1188	profile_set_syntax_err_cb(syntax_err_report);
1189	retval = profile_init(config_fn, &profile);
1190	if (retval == ENOENT) {
1191		profile_init(default_files, &profile);
1192		profile_set_default(profile, mke2fs_default_profile);
1193	}
1194
1195	setbuf(stdout, NULL);
1196	setbuf(stderr, NULL);
1197	add_error_table(&et_ext2_error_table);
1198	add_error_table(&et_prof_error_table);
1199	memset(&fs_param, 0, sizeof(struct ext2_super_block));
1200	fs_param.s_rev_level = 1;  /* Create revision 1 filesystems now */
1201
1202#ifdef __linux__
1203	if (uname(&ut)) {
1204		perror("uname");
1205		exit(1);
1206	}
1207	linux_version_code = parse_version_number(ut.release);
1208	if (linux_version_code && linux_version_code < (2*65536 + 2*256))
1209		fs_param.s_rev_level = 0;
1210#endif
1211
1212	if (argc && *argv) {
1213		program_name = get_progname(*argv);
1214
1215		/* If called as mkfs.ext3, create a journal inode */
1216		if (!strcmp(program_name, "mkfs.ext3") ||
1217		    !strcmp(program_name, "mke3fs"))
1218			journal_size = -1;
1219	}
1220
1221	while ((c = getopt (argc, argv,
1222		    "b:cf:g:G:i:jl:m:no:qr:s:t:vE:FI:J:KL:M:N:O:R:ST:U:V")) != EOF) {
1223		switch (c) {
1224		case 'b':
1225			blocksize = strtol(optarg, &tmp, 0);
1226			b = (blocksize > 0) ? blocksize : -blocksize;
1227			if (b < EXT2_MIN_BLOCK_SIZE ||
1228			    b > EXT2_MAX_BLOCK_SIZE || *tmp) {
1229				com_err(program_name, 0,
1230					_("invalid block size - %s"), optarg);
1231				exit(1);
1232			}
1233			if (blocksize > 4096)
1234				fprintf(stderr, _("Warning: blocksize %d not "
1235						  "usable on most systems.\n"),
1236					blocksize);
1237			if (blocksize > 0)
1238				fs_param.s_log_block_size =
1239					int_log2(blocksize >>
1240						 EXT2_MIN_BLOCK_LOG_SIZE);
1241			break;
1242		case 'c':	/* Check for bad blocks */
1243#ifndef NO_CHECK_BB
1244			cflag++;
1245#else
1246			com_err(program_name, 0, _("check for bad blocks disabled"));
1247			exit(1);
1248#endif
1249			break;
1250		case 'f':
1251			size = strtoul(optarg, &tmp, 0);
1252			if (size < EXT2_MIN_BLOCK_SIZE ||
1253			    size > EXT2_MAX_BLOCK_SIZE || *tmp) {
1254				com_err(program_name, 0,
1255					_("invalid fragment size - %s"),
1256					optarg);
1257				exit(1);
1258			}
1259			fs_param.s_log_frag_size =
1260				int_log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
1261			fprintf(stderr, _("Warning: fragments not supported.  "
1262			       "Ignoring -f option\n"));
1263			break;
1264		case 'g':
1265			fs_param.s_blocks_per_group = strtoul(optarg, &tmp, 0);
1266			if (*tmp) {
1267				com_err(program_name, 0,
1268					_("Illegal number for blocks per group"));
1269				exit(1);
1270			}
1271			if ((fs_param.s_blocks_per_group % 8) != 0) {
1272				com_err(program_name, 0,
1273				_("blocks per group must be multiple of 8"));
1274				exit(1);
1275			}
1276			break;
1277		case 'G':
1278			flex_bg_size = strtoul(optarg, &tmp, 0);
1279			if (*tmp) {
1280				com_err(program_name, 0,
1281					_("Illegal number for flex_bg size"));
1282				exit(1);
1283			}
1284			if (flex_bg_size < 2 ||
1285			    (flex_bg_size & (flex_bg_size-1)) != 0) {
1286				com_err(program_name, 0,
1287					_("flex_bg size must be a power of 2"));
1288				exit(1);
1289			}
1290			break;
1291		case 'i':
1292			inode_ratio = strtoul(optarg, &tmp, 0);
1293			if (inode_ratio < EXT2_MIN_BLOCK_SIZE ||
1294			    inode_ratio > EXT2_MAX_BLOCK_SIZE * 1024 ||
1295			    *tmp) {
1296				com_err(program_name, 0,
1297					_("invalid inode ratio %s (min %d/max %d)"),
1298					optarg, EXT2_MIN_BLOCK_SIZE,
1299					EXT2_MAX_BLOCK_SIZE);
1300				exit(1);
1301			}
1302			break;
1303		case 'J':
1304			parse_journal_opts(optarg);
1305			break;
1306		case 'K':
1307			discard = 0;
1308			break;
1309		case 'j':
1310			if (!journal_size)
1311				journal_size = -1;
1312			break;
1313		case 'l':
1314			bad_blocks_filename = malloc(strlen(optarg)+1);
1315			if (!bad_blocks_filename) {
1316				com_err(program_name, ENOMEM,
1317					_("in malloc for bad_blocks_filename"));
1318				exit(1);
1319			}
1320			strcpy(bad_blocks_filename, optarg);
1321			break;
1322		case 'm':
1323			reserved_ratio = strtod(optarg, &tmp);
1324			if ( *tmp || reserved_ratio > 50 ||
1325			     reserved_ratio < 0) {
1326				com_err(program_name, 0,
1327					_("invalid reserved blocks percent - %s"),
1328					optarg);
1329				exit(1);
1330			}
1331			break;
1332		case 'n':
1333			noaction++;
1334			break;
1335		case 'o':
1336			creator_os = optarg;
1337			break;
1338		case 'q':
1339			quiet = 1;
1340			break;
1341		case 'r':
1342			r_opt = strtoul(optarg, &tmp, 0);
1343			if (*tmp) {
1344				com_err(program_name, 0,
1345					_("bad revision level - %s"), optarg);
1346				exit(1);
1347			}
1348			fs_param.s_rev_level = r_opt;
1349			break;
1350		case 's':	/* deprecated */
1351			s_opt = atoi(optarg);
1352			break;
1353		case 'I':
1354			inode_size = strtoul(optarg, &tmp, 0);
1355			if (*tmp) {
1356				com_err(program_name, 0,
1357					_("invalid inode size - %s"), optarg);
1358				exit(1);
1359			}
1360			break;
1361		case 'v':
1362			verbose = 1;
1363			break;
1364		case 'F':
1365			force++;
1366			break;
1367		case 'L':
1368			volume_label = optarg;
1369			break;
1370		case 'M':
1371			mount_dir = optarg;
1372			break;
1373		case 'N':
1374			num_inodes = strtoul(optarg, &tmp, 0);
1375			if (*tmp) {
1376				com_err(program_name, 0,
1377					_("bad num inodes - %s"), optarg);
1378					exit(1);
1379			}
1380			break;
1381		case 'O':
1382			fs_features = optarg;
1383			break;
1384		case 'E':
1385		case 'R':
1386			extended_opts = optarg;
1387			break;
1388		case 'S':
1389			super_only = 1;
1390			break;
1391		case 't':
1392			fs_type = optarg;
1393			break;
1394		case 'T':
1395			usage_types = optarg;
1396			break;
1397		case 'U':
1398			fs_uuid = optarg;
1399			break;
1400		case 'V':
1401			/* Print version number and exit */
1402			show_version_only++;
1403			break;
1404		default:
1405			usage();
1406		}
1407	}
1408	if ((optind == argc) && !show_version_only)
1409		usage();
1410	device_name = argv[optind++];
1411
1412	if (!quiet || show_version_only)
1413		fprintf (stderr, "mke2fs %s (%s)\n", E2FSPROGS_VERSION,
1414			 E2FSPROGS_DATE);
1415
1416	if (show_version_only) {
1417		fprintf(stderr, _("\tUsing %s\n"),
1418			error_message(EXT2_ET_BASE));
1419		exit(0);
1420	}
1421
1422	/*
1423	 * If there's no blocksize specified and there is a journal
1424	 * device, use it to figure out the blocksize
1425	 */
1426	if (blocksize <= 0 && journal_device) {
1427		ext2_filsys	jfs;
1428		io_manager	io_ptr;
1429
1430#ifdef CONFIG_TESTIO_DEBUG
1431		if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
1432			io_ptr = test_io_manager;
1433			test_io_backing_manager = unix_io_manager;
1434		} else
1435#endif
1436			io_ptr = unix_io_manager;
1437		retval = ext2fs_open(journal_device,
1438				     EXT2_FLAG_JOURNAL_DEV_OK, 0,
1439				     0, io_ptr, &jfs);
1440		if (retval) {
1441			com_err(program_name, retval,
1442				_("while trying to open journal device %s\n"),
1443				journal_device);
1444			exit(1);
1445		}
1446		if ((blocksize < 0) && (jfs->blocksize < (unsigned) (-blocksize))) {
1447			com_err(program_name, 0,
1448				_("Journal dev blocksize (%d) smaller than "
1449				  "minimum blocksize %d\n"), jfs->blocksize,
1450				-blocksize);
1451			exit(1);
1452		}
1453		blocksize = jfs->blocksize;
1454		printf(_("Using journal device's blocksize: %d\n"), blocksize);
1455		fs_param.s_log_block_size =
1456			int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
1457		ext2fs_close(jfs);
1458	}
1459
1460	if (blocksize > sys_page_size) {
1461		if (!force) {
1462			com_err(program_name, 0,
1463				_("%d-byte blocks too big for system (max %d)"),
1464				blocksize, sys_page_size);
1465			proceed_question();
1466		}
1467		fprintf(stderr, _("Warning: %d-byte blocks too big for system "
1468				  "(max %d), forced to continue\n"),
1469			blocksize, sys_page_size);
1470	}
1471	if (optind < argc) {
1472		fs_param.s_blocks_count = parse_num_blocks(argv[optind++],
1473				fs_param.s_log_block_size);
1474		if (!fs_param.s_blocks_count) {
1475			com_err(program_name, 0, _("invalid blocks count - %s"),
1476				argv[optind - 1]);
1477			exit(1);
1478		}
1479	}
1480	if (optind < argc)
1481		usage();
1482
1483	if (!force)
1484		check_plausibility(device_name);
1485	check_mount(device_name, force, _("filesystem"));
1486
1487	fs_param.s_log_frag_size = fs_param.s_log_block_size;
1488
1489	if (noaction && fs_param.s_blocks_count) {
1490		dev_size = fs_param.s_blocks_count;
1491		retval = 0;
1492	} else {
1493	retry:
1494		retval = ext2fs_get_device_size(device_name,
1495						EXT2_BLOCK_SIZE(&fs_param),
1496						&dev_size);
1497		if ((retval == EFBIG) &&
1498		    (blocksize == 0) &&
1499		    (fs_param.s_log_block_size == 0)) {
1500			fs_param.s_log_block_size = 2;
1501			blocksize = 4096;
1502			goto retry;
1503		}
1504	}
1505
1506	if (retval == EFBIG) {
1507		blk64_t	big_dev_size;
1508
1509		if (blocksize < 4096) {
1510			fs_param.s_log_block_size = 2;
1511			blocksize = 4096;
1512		}
1513		retval = ext2fs_get_device_size2(device_name,
1514				 EXT2_BLOCK_SIZE(&fs_param), &big_dev_size);
1515		if (retval)
1516			goto get_size_failure;
1517		if (big_dev_size == (1ULL << 32)) {
1518			dev_size = (blk_t) (big_dev_size - 1);
1519			goto got_size;
1520		}
1521		fprintf(stderr, _("%s: Size of device %s too big "
1522				  "to be expressed in 32 bits\n\t"
1523				  "using a blocksize of %d.\n"),
1524			program_name, device_name, EXT2_BLOCK_SIZE(&fs_param));
1525		exit(1);
1526	}
1527get_size_failure:
1528	if (retval && (retval != EXT2_ET_UNIMPLEMENTED)) {
1529		com_err(program_name, retval,
1530			_("while trying to determine filesystem size"));
1531		exit(1);
1532	}
1533got_size:
1534	if (!fs_param.s_blocks_count) {
1535		if (retval == EXT2_ET_UNIMPLEMENTED) {
1536			com_err(program_name, 0,
1537				_("Couldn't determine device size; you "
1538				"must specify\nthe size of the "
1539				"filesystem\n"));
1540			exit(1);
1541		} else {
1542			if (dev_size == 0) {
1543				com_err(program_name, 0,
1544				_("Device size reported to be zero.  "
1545				  "Invalid partition specified, or\n\t"
1546				  "partition table wasn't reread "
1547				  "after running fdisk, due to\n\t"
1548				  "a modified partition being busy "
1549				  "and in use.  You may need to reboot\n\t"
1550				  "to re-read your partition table.\n"
1551				  ));
1552				exit(1);
1553			}
1554			fs_param.s_blocks_count = dev_size;
1555			if (sys_page_size > EXT2_BLOCK_SIZE(&fs_param))
1556				fs_param.s_blocks_count &= ~((sys_page_size /
1557					   EXT2_BLOCK_SIZE(&fs_param))-1);
1558		}
1559
1560	} else if (!force && (fs_param.s_blocks_count > dev_size)) {
1561		com_err(program_name, 0,
1562			_("Filesystem larger than apparent device size."));
1563		proceed_question();
1564	}
1565
1566	fs_types = parse_fs_type(fs_type, usage_types, &fs_param, argv[0]);
1567	if (!fs_types) {
1568		fprintf(stderr, _("Failed to parse fs types list\n"));
1569		exit(1);
1570	}
1571
1572	/* Figure out what features should be enabled */
1573
1574	tmp = NULL;
1575	if (fs_param.s_rev_level != EXT2_GOOD_OLD_REV) {
1576		tmp = get_string_from_profile(fs_types, "base_features",
1577		      "sparse_super,filetype,resize_inode,dir_index");
1578		edit_feature(tmp, &fs_param.s_feature_compat);
1579		free(tmp);
1580
1581		for (cpp = fs_types; *cpp; cpp++) {
1582			tmp = NULL;
1583			profile_get_string(profile, "fs_types", *cpp,
1584					   "features", "", &tmp);
1585			if (tmp && *tmp)
1586				edit_feature(tmp, &fs_param.s_feature_compat);
1587			free(tmp);
1588		}
1589		tmp = get_string_from_profile(fs_types, "default_features",
1590					      "");
1591	}
1592	edit_feature(fs_features ? fs_features : tmp,
1593		     &fs_param.s_feature_compat);
1594	free(tmp);
1595
1596	if (fs_param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
1597		fs_types[0] = strdup("journal");
1598		fs_types[1] = 0;
1599	}
1600
1601	if (verbose) {
1602		fputs(_("fs_types for mke2fs.conf resolution: "), stdout);
1603		print_str_list(fs_types);
1604	}
1605
1606	if (r_opt == EXT2_GOOD_OLD_REV &&
1607	    (fs_param.s_feature_compat || fs_param.s_feature_incompat ||
1608	     fs_param.s_feature_ro_compat)) {
1609		fprintf(stderr, _("Filesystem features not supported "
1610				  "with revision 0 filesystems\n"));
1611		exit(1);
1612	}
1613
1614	if (s_opt > 0) {
1615		if (r_opt == EXT2_GOOD_OLD_REV) {
1616			fprintf(stderr, _("Sparse superblocks not supported "
1617				  "with revision 0 filesystems\n"));
1618			exit(1);
1619		}
1620		fs_param.s_feature_ro_compat |=
1621			EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
1622	} else if (s_opt == 0)
1623		fs_param.s_feature_ro_compat &=
1624			~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
1625
1626	if (journal_size != 0) {
1627		if (r_opt == EXT2_GOOD_OLD_REV) {
1628			fprintf(stderr, _("Journals not supported "
1629				  "with revision 0 filesystems\n"));
1630			exit(1);
1631		}
1632		fs_param.s_feature_compat |=
1633			EXT3_FEATURE_COMPAT_HAS_JOURNAL;
1634	}
1635
1636	if (fs_param.s_feature_incompat &
1637	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
1638		reserved_ratio = 0;
1639		fs_param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV;
1640		fs_param.s_feature_compat = 0;
1641		fs_param.s_feature_ro_compat = 0;
1642 	}
1643
1644	if ((fs_param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
1645	    (fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)) {
1646		fprintf(stderr, _("The resize_inode and meta_bg features "
1647				  "are not compatible.\n"
1648				  "They can not be both enabled "
1649				  "simultaneously.\n"));
1650		exit(1);
1651	}
1652
1653	/* Set first meta blockgroup via an environment variable */
1654	/* (this is mostly for debugging purposes) */
1655	if ((fs_param.s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) &&
1656	    ((tmp = getenv("MKE2FS_FIRST_META_BG"))))
1657		fs_param.s_first_meta_bg = atoi(tmp);
1658
1659	/* Get the hardware sector size, if available */
1660	retval = ext2fs_get_device_sectsize(device_name, &sector_size);
1661	if (retval) {
1662		com_err(program_name, retval,
1663			_("while trying to determine hardware sector size"));
1664		exit(1);
1665	}
1666
1667	if ((tmp = getenv("MKE2FS_DEVICE_SECTSIZE")) != NULL)
1668		sector_size = atoi(tmp);
1669
1670	if (blocksize <= 0) {
1671		use_bsize = get_int_from_profile(fs_types, "blocksize", 4096);
1672
1673		if (use_bsize == -1) {
1674			use_bsize = sys_page_size;
1675			if ((linux_version_code < (2*65536 + 6*256)) &&
1676			    (use_bsize > 4096))
1677				use_bsize = 4096;
1678		}
1679		if (sector_size && use_bsize < sector_size)
1680			use_bsize = sector_size;
1681		if ((blocksize < 0) && (use_bsize < (-blocksize)))
1682			use_bsize = -blocksize;
1683		blocksize = use_bsize;
1684		fs_param.s_blocks_count /= blocksize / 1024;
1685	}
1686
1687	if (inode_ratio == 0) {
1688		inode_ratio = get_int_from_profile(fs_types, "inode_ratio",
1689						   8192);
1690		if (inode_ratio < blocksize)
1691			inode_ratio = blocksize;
1692	}
1693
1694	fs_param.s_log_frag_size = fs_param.s_log_block_size =
1695		int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
1696
1697#ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY
1698	retval = ext2fs_get_device_geometry(device_name, &fs_param);
1699	if (retval < 0) {
1700		fprintf(stderr,
1701			_("warning: Unable to get device geometry for %s\n"),
1702			device_name);
1703	} else if (retval) {
1704		printf(_("%s alignment is offset by %lu bytes.\n"),
1705		       device_name, retval);
1706		printf(_("This may result in very poor performance, "
1707			  "(re)-partitioning suggested.\n"));
1708	}
1709#endif
1710
1711	blocksize = EXT2_BLOCK_SIZE(&fs_param);
1712
1713	lazy_itable_init = get_bool_from_profile(fs_types,
1714						 "lazy_itable_init", 0);
1715
1716	/* Get options from profile */
1717	for (cpp = fs_types; *cpp; cpp++) {
1718		tmp = NULL;
1719		profile_get_string(profile, "fs_types", *cpp, "options", "", &tmp);
1720			if (tmp && *tmp)
1721				parse_extended_opts(&fs_param, tmp);
1722			free(tmp);
1723	}
1724
1725	if (extended_opts)
1726		parse_extended_opts(&fs_param, extended_opts);
1727
1728	/* Since sparse_super is the default, we would only have a problem
1729	 * here if it was explicitly disabled.
1730	 */
1731	if ((fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
1732	    !(fs_param.s_feature_ro_compat&EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
1733		com_err(program_name, 0,
1734			_("reserved online resize blocks not supported "
1735			  "on non-sparse filesystem"));
1736		exit(1);
1737	}
1738
1739	if (fs_param.s_blocks_per_group) {
1740		if (fs_param.s_blocks_per_group < 256 ||
1741		    fs_param.s_blocks_per_group > 8 * (unsigned) blocksize) {
1742			com_err(program_name, 0,
1743				_("blocks per group count out of range"));
1744			exit(1);
1745		}
1746	}
1747
1748	if (inode_size == 0)
1749		inode_size = get_int_from_profile(fs_types, "inode_size", 0);
1750	if (!flex_bg_size && (fs_param.s_feature_incompat &
1751			      EXT4_FEATURE_INCOMPAT_FLEX_BG))
1752		flex_bg_size = get_int_from_profile(fs_types,
1753						    "flex_bg_size", 16);
1754	if (flex_bg_size) {
1755		if (!(fs_param.s_feature_incompat &
1756		      EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
1757			com_err(program_name, 0,
1758				_("Flex_bg feature not enabled, so "
1759				  "flex_bg size may not be specified"));
1760			exit(1);
1761		}
1762		fs_param.s_log_groups_per_flex = int_log2(flex_bg_size);
1763	}
1764
1765	if (inode_size && fs_param.s_rev_level >= EXT2_DYNAMIC_REV) {
1766		if (inode_size < EXT2_GOOD_OLD_INODE_SIZE ||
1767		    inode_size > EXT2_BLOCK_SIZE(&fs_param) ||
1768		    inode_size & (inode_size - 1)) {
1769			com_err(program_name, 0,
1770				_("invalid inode size %d (min %d/max %d)"),
1771				inode_size, EXT2_GOOD_OLD_INODE_SIZE,
1772				blocksize);
1773			exit(1);
1774		}
1775		fs_param.s_inode_size = inode_size;
1776	}
1777
1778	/* Make sure number of inodes specified will fit in 32 bits */
1779	if (num_inodes == 0) {
1780		unsigned long long n;
1781		n = (unsigned long long) fs_param.s_blocks_count * blocksize / inode_ratio;
1782		if (n > ~0U) {
1783			com_err(program_name, 0,
1784			    _("too many inodes (%llu), raise inode ratio?"), n);
1785			exit(1);
1786		}
1787	} else if (num_inodes > ~0U) {
1788		com_err(program_name, 0,
1789			_("too many inodes (%llu), specify < 2^32 inodes"),
1790			  num_inodes);
1791		exit(1);
1792	}
1793	/*
1794	 * Calculate number of inodes based on the inode ratio
1795	 */
1796	fs_param.s_inodes_count = num_inodes ? num_inodes :
1797		((__u64) fs_param.s_blocks_count * blocksize)
1798			/ inode_ratio;
1799
1800	if ((((long long)fs_param.s_inodes_count) *
1801	     (inode_size ? inode_size : EXT2_GOOD_OLD_INODE_SIZE)) >=
1802	    (((long long)fs_param.s_blocks_count) *
1803	     EXT2_BLOCK_SIZE(&fs_param))) {
1804		com_err(program_name, 0, _("inode_size (%u) * inodes_count "
1805					  "(%u) too big for a\n\t"
1806					  "filesystem with %lu blocks, "
1807					  "specify higher inode_ratio (-i)\n\t"
1808					  "or lower inode count (-N).\n"),
1809			inode_size ? inode_size : EXT2_GOOD_OLD_INODE_SIZE,
1810			fs_param.s_inodes_count,
1811			(unsigned long) fs_param.s_blocks_count);
1812		exit(1);
1813	}
1814
1815	/*
1816	 * Calculate number of blocks to reserve
1817	 */
1818	fs_param.s_r_blocks_count = (unsigned int) (reserved_ratio *
1819					fs_param.s_blocks_count / 100.0);
1820}
1821
1822static int should_do_undo(const char *name)
1823{
1824	errcode_t retval;
1825	io_channel channel;
1826	__u16	s_magic;
1827	struct ext2_super_block super;
1828	io_manager manager = unix_io_manager;
1829	int csum_flag, force_undo;
1830
1831	csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
1832					       EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
1833	force_undo = get_int_from_profile(fs_types, "force_undo", 0);
1834	if (!force_undo && (!csum_flag || !lazy_itable_init))
1835		return 0;
1836
1837	retval = manager->open(name, IO_FLAG_EXCLUSIVE,  &channel);
1838	if (retval) {
1839		/*
1840		 * We don't handle error cases instead we
1841		 * declare that the file system doesn't exist
1842		 * and let the rest of mke2fs take care of
1843		 * error
1844		 */
1845		retval = 0;
1846		goto open_err_out;
1847	}
1848
1849	io_channel_set_blksize(channel, SUPERBLOCK_OFFSET);
1850	retval = io_channel_read_blk(channel, 1, -SUPERBLOCK_SIZE, &super);
1851	if (retval) {
1852		retval = 0;
1853		goto err_out;
1854	}
1855
1856#if defined(WORDS_BIGENDIAN)
1857	s_magic = ext2fs_swab16(super.s_magic);
1858#else
1859	s_magic = super.s_magic;
1860#endif
1861
1862	if (s_magic == EXT2_SUPER_MAGIC)
1863		retval = 1;
1864
1865err_out:
1866	io_channel_close(channel);
1867
1868open_err_out:
1869
1870	return retval;
1871}
1872
1873static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr)
1874{
1875	errcode_t retval = 0;
1876	char *tdb_dir, *tdb_file;
1877	char *device_name, *tmp_name;
1878
1879	/*
1880	 * Configuration via a conf file would be
1881	 * nice
1882	 */
1883	tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
1884	if (!tdb_dir)
1885		profile_get_string(profile, "defaults",
1886				   "undo_dir", 0, "/var/lib/e2fsprogs",
1887				   &tdb_dir);
1888
1889	if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
1890	    access(tdb_dir, W_OK))
1891		return 0;
1892
1893	tmp_name = strdup(name);
1894	if (!tmp_name) {
1895	alloc_fn_fail:
1896		com_err(program_name, ENOMEM,
1897			_("Couldn't allocate memory for tdb filename\n"));
1898		return ENOMEM;
1899	}
1900	device_name = basename(tmp_name);
1901	tdb_file = malloc(strlen(tdb_dir) + 8 + strlen(device_name) + 7 + 1);
1902	if (!tdb_file)
1903		goto alloc_fn_fail;
1904	sprintf(tdb_file, "%s/mke2fs-%s.e2undo", tdb_dir, device_name);
1905
1906	if (!access(tdb_file, F_OK)) {
1907		if (unlink(tdb_file) < 0) {
1908			retval = errno;
1909			com_err(program_name, retval,
1910				_("while trying to delete %s"),
1911				tdb_file);
1912			free(tdb_file);
1913			return retval;
1914		}
1915	}
1916
1917	set_undo_io_backing_manager(*io_ptr);
1918	*io_ptr = undo_io_manager;
1919	set_undo_io_backup_file(tdb_file);
1920	printf(_("Overwriting existing filesystem; this can be undone "
1921		 "using the command:\n"
1922		 "    e2undo %s %s\n\n"), tdb_file, name);
1923
1924	free(tdb_file);
1925	free(tmp_name);
1926	return retval;
1927}
1928
1929#ifdef __linux__
1930
1931#ifndef BLKDISCARD
1932#define BLKDISCARD	_IO(0x12,119)
1933#endif
1934
1935static void mke2fs_discard_blocks(ext2_filsys fs)
1936{
1937	int fd;
1938	int ret;
1939	int blocksize;
1940	__u64 blocks;
1941	__uint64_t range[2];
1942
1943	blocks = fs->super->s_blocks_count;
1944	blocksize = EXT2_BLOCK_SIZE(fs->super);
1945	range[0] = 0;
1946	range[1] = blocks * blocksize;
1947
1948#ifdef HAVE_OPEN64
1949	fd = open64(fs->device_name, O_RDWR);
1950#else
1951	fd = open(fs->device_name, O_RDWR);
1952#endif
1953
1954	/*
1955	 * We don't care about whether the ioctl succeeds; it's only an
1956	 * optmization for SSDs or sparse storage.
1957	 */
1958	if (fd > 0) {
1959		ret = ioctl(fd, BLKDISCARD, &range);
1960		if (verbose) {
1961			printf(_("Calling BLKDISCARD from %llu to %llu "),
1962				range[0], range[1]);
1963			if (ret)
1964				printf(_("failed.\n"));
1965			else
1966				printf(_("succeeded.\n"));
1967		}
1968		close(fd);
1969	}
1970}
1971#else
1972#define mke2fs_discard_blocks(fs)
1973#endif
1974
1975int main (int argc, char *argv[])
1976{
1977	errcode_t	retval = 0;
1978	ext2_filsys	fs;
1979	badblocks_list	bb_list = 0;
1980	unsigned int	journal_blocks;
1981	unsigned int	i;
1982	int		val, hash_alg;
1983	io_manager	io_ptr;
1984	char		tdb_string[40];
1985	char		*hash_alg_str;
1986
1987#ifdef ENABLE_NLS
1988	setlocale(LC_MESSAGES, "");
1989	setlocale(LC_CTYPE, "");
1990	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1991	textdomain(NLS_CAT_NAME);
1992#endif
1993	PRS(argc, argv);
1994
1995#ifdef CONFIG_TESTIO_DEBUG
1996	if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
1997		io_ptr = test_io_manager;
1998		test_io_backing_manager = unix_io_manager;
1999	} else
2000#endif
2001		io_ptr = unix_io_manager;
2002
2003	if (should_do_undo(device_name)) {
2004		retval = mke2fs_setup_tdb(device_name, &io_ptr);
2005		if (retval)
2006			exit(1);
2007	}
2008
2009	/*
2010	 * Initialize the superblock....
2011	 */
2012	retval = ext2fs_initialize(device_name, EXT2_FLAG_EXCLUSIVE, &fs_param,
2013				   io_ptr, &fs);
2014	if (retval) {
2015		com_err(device_name, retval, _("while setting up superblock"));
2016		exit(1);
2017	}
2018
2019	/* Can't undo discard ... */
2020	if (discard && (io_ptr != undo_io_manager))
2021		mke2fs_discard_blocks(fs);
2022
2023	sprintf(tdb_string, "tdb_data_size=%d", fs->blocksize <= 4096 ?
2024		32768 : fs->blocksize * 8);
2025	io_channel_set_options(fs->io, tdb_string);
2026
2027	if (fs_param.s_flags & EXT2_FLAGS_TEST_FILESYS)
2028		fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
2029
2030	if ((fs_param.s_feature_incompat &
2031	     (EXT3_FEATURE_INCOMPAT_EXTENTS|EXT4_FEATURE_INCOMPAT_FLEX_BG)) ||
2032	    (fs_param.s_feature_ro_compat &
2033	     (EXT4_FEATURE_RO_COMPAT_HUGE_FILE|EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
2034	      EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
2035	      EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)))
2036		fs->super->s_kbytes_written = 1;
2037
2038	/*
2039	 * Wipe out the old on-disk superblock
2040	 */
2041	if (!noaction)
2042		zap_sector(fs, 2, 6);
2043
2044	/*
2045	 * Parse or generate a UUID for the filesystem
2046	 */
2047	if (fs_uuid) {
2048		if (uuid_parse(fs_uuid, fs->super->s_uuid) !=0) {
2049			com_err(device_name, 0, "could not parse UUID: %s\n",
2050				fs_uuid);
2051			exit(1);
2052		}
2053	} else
2054		uuid_generate(fs->super->s_uuid);
2055
2056	/*
2057	 * Initialize the directory index variables
2058	 */
2059	hash_alg_str = get_string_from_profile(fs_types, "hash_alg",
2060					       "half_md4");
2061	hash_alg = e2p_string2hash(hash_alg_str);
2062	fs->super->s_def_hash_version = (hash_alg >= 0) ? hash_alg :
2063		EXT2_HASH_HALF_MD4;
2064	uuid_generate((unsigned char *) fs->super->s_hash_seed);
2065
2066	/*
2067	 * Add "jitter" to the superblock's check interval so that we
2068	 * don't check all the filesystems at the same time.  We use a
2069	 * kludgy hack of using the UUID to derive a random jitter value.
2070	 */
2071	for (i = 0, val = 0 ; i < sizeof(fs->super->s_uuid); i++)
2072		val += fs->super->s_uuid[i];
2073	fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
2074
2075	/*
2076	 * Override the creator OS, if applicable
2077	 */
2078	if (creator_os && !set_os(fs->super, creator_os)) {
2079		com_err (program_name, 0, _("unknown os - %s"), creator_os);
2080		exit(1);
2081	}
2082
2083	/*
2084	 * For the Hurd, we will turn off filetype since it doesn't
2085	 * support it.
2086	 */
2087	if (fs->super->s_creator_os == EXT2_OS_HURD)
2088		fs->super->s_feature_incompat &=
2089			~EXT2_FEATURE_INCOMPAT_FILETYPE;
2090
2091	/*
2092	 * Set the volume label...
2093	 */
2094	if (volume_label) {
2095		memset(fs->super->s_volume_name, 0,
2096		       sizeof(fs->super->s_volume_name));
2097		strncpy(fs->super->s_volume_name, volume_label,
2098			sizeof(fs->super->s_volume_name));
2099	}
2100
2101	/*
2102	 * Set the last mount directory
2103	 */
2104	if (mount_dir) {
2105		memset(fs->super->s_last_mounted, 0,
2106		       sizeof(fs->super->s_last_mounted));
2107		strncpy(fs->super->s_last_mounted, mount_dir,
2108			sizeof(fs->super->s_last_mounted));
2109	}
2110
2111	if (!quiet || noaction)
2112		show_stats(fs);
2113
2114	if (noaction)
2115		exit(0);
2116
2117	if (fs->super->s_feature_incompat &
2118	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
2119		create_journal_dev(fs);
2120		exit(ext2fs_close(fs) ? 1 : 0);
2121	}
2122
2123	if (bad_blocks_filename)
2124		read_bb_file(fs, &bb_list, bad_blocks_filename);
2125
2126#ifndef NO_CHECK_BB
2127	if (cflag)
2128		test_disk(fs, &bb_list);
2129#endif
2130
2131	handle_bad_blocks(fs, bb_list);
2132	fs->stride = fs_stride = fs->super->s_raid_stride;
2133	retval = ext2fs_allocate_tables(fs);
2134	if (retval) {
2135		com_err(program_name, retval,
2136			_("while trying to allocate filesystem tables"));
2137		exit(1);
2138	}
2139	if (super_only) {
2140		fs->super->s_state |= EXT2_ERROR_FS;
2141		fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY);
2142	} else {
2143		/* rsv must be a power of two (64kB is MD RAID sb alignment) */
2144		unsigned int rsv = 65536 / fs->blocksize;
2145		unsigned long blocks = fs->super->s_blocks_count;
2146		unsigned long start;
2147		blk_t ret_blk;
2148
2149#ifdef ZAP_BOOTBLOCK
2150		zap_sector(fs, 0, 2);
2151#endif
2152
2153		/*
2154		 * Wipe out any old MD RAID (or other) metadata at the end
2155		 * of the device.  This will also verify that the device is
2156		 * as large as we think.  Be careful with very small devices.
2157		 */
2158		start = (blocks & ~(rsv - 1));
2159		if (start > rsv)
2160			start -= rsv;
2161		if (start > 0)
2162			retval = ext2fs_zero_blocks(fs, start, blocks - start,
2163						    &ret_blk, NULL);
2164
2165		if (retval) {
2166			com_err(program_name, retval,
2167				_("while zeroing block %u at end of filesystem"),
2168				ret_blk);
2169		}
2170		write_inode_tables(fs, lazy_itable_init);
2171		create_root_dir(fs);
2172		create_lost_and_found(fs);
2173		reserve_inodes(fs);
2174		create_bad_block_inode(fs, bb_list);
2175		if (fs->super->s_feature_compat &
2176		    EXT2_FEATURE_COMPAT_RESIZE_INODE) {
2177			retval = ext2fs_create_resize_inode(fs);
2178			if (retval) {
2179				com_err("ext2fs_create_resize_inode", retval,
2180				_("while reserving blocks for online resize"));
2181				exit(1);
2182			}
2183		}
2184	}
2185
2186	if (journal_device) {
2187		ext2_filsys	jfs;
2188
2189		if (!force)
2190			check_plausibility(journal_device);
2191		check_mount(journal_device, force, _("journal"));
2192
2193		retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
2194				     EXT2_FLAG_JOURNAL_DEV_OK, 0,
2195				     fs->blocksize, unix_io_manager, &jfs);
2196		if (retval) {
2197			com_err(program_name, retval,
2198				_("while trying to open journal device %s\n"),
2199				journal_device);
2200			exit(1);
2201		}
2202		if (!quiet) {
2203			printf(_("Adding journal to device %s: "),
2204			       journal_device);
2205			fflush(stdout);
2206		}
2207		retval = ext2fs_add_journal_device(fs, jfs);
2208		if(retval) {
2209			com_err (program_name, retval,
2210				 _("\n\twhile trying to add journal to device %s"),
2211				 journal_device);
2212			exit(1);
2213		}
2214		if (!quiet)
2215			printf(_("done\n"));
2216		ext2fs_close(jfs);
2217		free(journal_device);
2218	} else if ((journal_size) ||
2219		   (fs_param.s_feature_compat &
2220		    EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
2221		journal_blocks = figure_journal_size(journal_size, fs);
2222
2223		if (super_only) {
2224			printf(_("Skipping journal creation in super-only mode\n"));
2225			fs->super->s_journal_inum = EXT2_JOURNAL_INO;
2226			goto no_journal;
2227		}
2228
2229		if (!journal_blocks) {
2230			fs->super->s_feature_compat &=
2231				~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
2232			goto no_journal;
2233		}
2234		if (!quiet) {
2235			printf(_("Creating journal (%u blocks): "),
2236			       journal_blocks);
2237			fflush(stdout);
2238		}
2239		retval = ext2fs_add_journal_inode(fs, journal_blocks,
2240						  journal_flags);
2241		if (retval) {
2242			com_err (program_name, retval,
2243				 _("\n\twhile trying to create journal"));
2244			exit(1);
2245		}
2246		if (!quiet)
2247			printf(_("done\n"));
2248	}
2249no_journal:
2250
2251	if (!quiet)
2252		printf(_("Writing superblocks and "
2253		       "filesystem accounting information: "));
2254	retval = ext2fs_flush(fs);
2255	if (retval) {
2256		fprintf(stderr,
2257			_("\nWarning, had trouble writing out superblocks."));
2258	}
2259	if (!quiet) {
2260		printf(_("done\n\n"));
2261		if (!getenv("MKE2FS_SKIP_CHECK_MSG"))
2262			print_check_message(fs);
2263	}
2264	val = ext2fs_close(fs);
2265	remove_error_table(&et_ext2_error_table);
2266	remove_error_table(&et_prof_error_table);
2267	profile_release(profile);
2268	return (retval || val) ? 1 : 0;
2269}
2270