mke2fs.c revision f635d7f65bd002984ce9a202d491d4f187b996b2
1/*
2 * mke2fs.c - Make a ext2fs filesystem.
3 *
4 * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
10 */
11
12/* Usage: mke2fs [options] device
13 *
14 * The device may be a block device or a image of one, but this isn't
15 * enforced (but it's not much fun on a character device :-).
16 */
17
18#include <stdio.h>
19#include <string.h>
20#include <fcntl.h>
21#include <ctype.h>
22#include <termios.h>
23#include <time.h>
24#ifdef HAVE_GETOPT_H
25#include <getopt.h>
26#endif
27#ifdef HAVE_UNISTD_H
28#include <unistd.h>
29#endif
30#ifdef HAVE_STDLIB_H
31#include <stdlib.h>
32#endif
33#ifdef HAVE_ERRNO_H
34#include <errno.h>
35#endif
36#ifdef HAVE_MNTENT_H
37#include <mntent.h>
38#endif
39#include <malloc.h>
40#include <sys/ioctl.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <stdio.h>
44
45#ifdef HAVE_LINUX_FS_H
46#include <linux/fs.h>
47#endif
48#include <linux/ext2_fs.h>
49#ifdef HAVE_LINUX_MAJOR_H
50#include <linux/major.h>
51#endif
52
53#include "et/com_err.h"
54#include "uuid/uuid.h"
55#include "ext2fs/ext2fs.h"
56#include "../version.h"
57
58#define STRIDE_LENGTH 8
59
60#ifndef sparc
61#define ZAP_BOOTBLOCK
62#endif
63
64extern int isatty(int);
65extern FILE *fpopen(const char *cmd, const char *mode);
66
67const char * program_name = "mke2fs";
68const char * device_name = NULL;
69
70/* Command line options */
71int	cflag = 0;
72int	verbose = 0;
73int	quiet = 0;
74int	super_only = 0;
75int	force = 0;
76char	*bad_blocks_filename = 0;
77__u32	fs_stride = 0;
78
79struct ext2_super_block param;
80char *creator_os = NULL;
81char *volume_label = NULL;
82char *mount_dir = NULL;
83
84static void usage(NOARGS)
85{
86	fprintf(stderr, "Usage: %s [-c|-t|-l filename] [-b block-size] "
87	"[-f fragment-size]\n\t[-i bytes-per-inode] "
88	"[-m reserved-blocks-percentage] [-qvS]\n\t"
89	"[-o creator-os] [-g blocks-per-group] [-L volume-label]\n\t"
90	"[-M last-mounted-directory] [-r fs-revision] [-R raid_opts]\n\t"
91	"device [blocks-count]\n",
92		program_name);
93	exit(1);
94}
95
96static int log2(int arg)
97{
98	int	l = 0;
99
100	arg >>= 1;
101	while (arg) {
102		l++;
103		arg >>= 1;
104	}
105	return l;
106}
107
108static void check_plausibility(NOARGS)
109{
110#ifdef HAVE_LINUX_MAJOR_H
111	int val;
112	struct stat s;
113
114	val = stat(device_name, &s);
115
116	if(val == -1) {
117		printf("Could not stat %s --- %s\n", device_name,
118		       error_message(errno));
119		if (errno == ENOENT)
120			printf("\nThe device apparently does not exist; "
121			       "did yo specify it correctly?\n");
122		exit(1);
123	}
124	if(!S_ISBLK(s.st_mode)) {
125		printf("%s is not a block special device.\n", device_name);
126		printf("Proceed anyway? (y,n) ");
127		if (getchar() != 'y')
128			exit(1);
129		return;
130	}
131	if ((MAJOR(s.st_rdev) == HD_MAJOR && MINOR(s.st_rdev)%64 == 0) ||
132	    (MAJOR(s.st_rdev) == SCSI_DISK_MAJOR &&
133	     MINOR(s.st_rdev)%16 == 0)) {
134		printf("%s is entire device, not just one partition!\n",
135		       device_name);
136		printf("Proceed anyway? (y,n) ");
137		if (getchar() != 'y')
138			exit(1);
139		return;
140	}
141#endif
142}
143
144static void check_mount(NOARGS)
145{
146	errcode_t	retval;
147	int		mount_flags;
148
149	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
150	if (retval) {
151		com_err("ext2fs_check_if_mount", retval,
152			"while determining whether %s is mounted.",
153			device_name);
154		return;
155	}
156	if (!(mount_flags & EXT2_MF_MOUNTED))
157		return;
158
159	fprintf(stderr, "%s is mounted; will not make a filesystem here!\n",
160		device_name);
161	exit(1);
162}
163
164/*
165 * Helper function for read_bb_file and test_disk
166 */
167static void invalid_block(ext2_filsys fs, blk_t blk)
168{
169	printf("Bad block %u out of range; ignored.\n", blk);
170	return;
171}
172
173/*
174 * Reads the bad blocks list from a file
175 */
176static void read_bb_file(ext2_filsys fs, badblocks_list *bb_list,
177			 const char *bad_blocks_file)
178{
179	FILE		*f;
180	errcode_t	retval;
181
182	f = fopen(bad_blocks_file, "r");
183	if (!f) {
184		com_err("read_bad_blocks_file", errno,
185			"while trying to open %s", bad_blocks_file);
186		exit(1);
187	}
188	retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
189	fclose (f);
190	if (retval) {
191		com_err("ext2fs_read_bb_FILE", retval,
192			"while reading in list of bad blocks from file");
193		exit(1);
194	}
195}
196
197/*
198 * Runs the badblocks program to test the disk
199 */
200static void test_disk(ext2_filsys fs, badblocks_list *bb_list)
201{
202	FILE		*f;
203	errcode_t	retval;
204	char		buf[1024];
205
206	sprintf(buf, "badblocks -b %d %s%s %d", fs->blocksize,
207		quiet ? "" : "-s ", fs->device_name,
208		fs->super->s_blocks_count);
209	if (verbose)
210		printf("Running command: %s\n", buf);
211	f = popen(buf, "r");
212	if (!f) {
213		com_err("popen", errno,
214			"while trying run '%s'", buf);
215		exit(1);
216	}
217	retval = ext2fs_read_bb_FILE(fs, f, bb_list, invalid_block);
218	pclose(f);
219	if (retval) {
220		com_err("ext2fs_read_bb_FILE", retval,
221			"while processing list of bad blocks from program");
222		exit(1);
223	}
224}
225
226static void handle_bad_blocks(ext2_filsys fs, badblocks_list bb_list)
227{
228	int			i, j;
229	int			must_be_good;
230	blk_t			blk;
231	badblocks_iterate	bb_iter;
232	errcode_t		retval;
233	blk_t			group_block;
234	int			group;
235	int			group_bad;
236
237	if (!bb_list)
238		return;
239
240	/*
241	 * The primary superblock and group descriptors *must* be
242	 * good; if not, abort.
243	 */
244	must_be_good = fs->super->s_first_data_block + 1 + fs->desc_blocks;
245	for (i = fs->super->s_first_data_block; i <= must_be_good; i++) {
246		if (badblocks_list_test(bb_list, i)) {
247			fprintf(stderr, "Block %d in primary superblock/group "
248				"descriptor area bad.\n", i);
249			fprintf(stderr, "Blocks %d through %d must be good "
250				"in order to build a filesystem.\n",
251				fs->super->s_first_data_block, must_be_good);
252			fprintf(stderr, "Aborting....\n");
253			exit(1);
254		}
255	}
256
257	/*
258	 * See if any of the bad blocks are showing up in the backup
259	 * superblocks and/or group descriptors.  If so, issue a
260	 * warning and adjust the block counts appropriately.
261	 */
262	group_block = fs->super->s_first_data_block +
263		fs->super->s_blocks_per_group;
264	group_bad = 0;
265
266	for (i = 1; i < fs->group_desc_count; i++) {
267		for (j=0; j < fs->desc_blocks+1; j++) {
268			if (badblocks_list_test(bb_list, group_block +
269						j)) {
270				if (!group_bad)
271					fprintf(stderr,
272"Warning: the backup superblock/group descriptors at block %d contain\n"
273"	bad blocks.\n\n",
274						group_block);
275				group_bad++;
276				group = ext2fs_group_of_blk(fs, group_block+j);
277				fs->group_desc[group].bg_free_blocks_count++;
278				fs->super->s_free_blocks_count++;
279			}
280		}
281		group_block += fs->super->s_blocks_per_group;
282	}
283
284	/*
285	 * Mark all the bad blocks as used...
286	 */
287	retval = badblocks_list_iterate_begin(bb_list, &bb_iter);
288	if (retval) {
289		com_err("badblocks_list_iterate_begin", retval,
290			"while marking bad blocks as used");
291		exit(1);
292	}
293	while (badblocks_list_iterate(bb_iter, &blk))
294		ext2fs_mark_block_bitmap(fs->block_map, blk);
295	badblocks_list_iterate_end(bb_iter);
296}
297
298static void write_inode_tables(ext2_filsys fs)
299{
300	errcode_t	retval;
301	blk_t		blk;
302	int		i, j, num, count;
303	char		*buf;
304
305	buf = malloc(fs->blocksize * STRIDE_LENGTH);
306	if (!buf) {
307		com_err("malloc", ENOMEM, "while allocating zeroizing buffer");
308		exit(1);
309	}
310	memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
311
312	if (!quiet)
313		printf("Writing inode tables: ");
314	for (i = 0; i < fs->group_desc_count; i++) {
315		if (!quiet)
316			printf("%4d/%4ld", i, fs->group_desc_count);
317
318		blk = fs->group_desc[i].bg_inode_table;
319		num = fs->inode_blocks_per_group;
320
321		for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
322			if (num-j > STRIDE_LENGTH)
323				count = STRIDE_LENGTH;
324			else
325				count = num - j;
326			retval = io_channel_write_blk(fs->io, blk, count, buf);
327			if (retval)
328				printf("Warning: could not write %d blocks "
329				       "in inode table starting at %d: %s\n",
330				       count, blk, error_message(retval));
331		}
332		if (!quiet)
333			printf("\b\b\b\b\b\b\b\b\b");
334	}
335	free(buf);
336	if (!quiet)
337		printf("done     \n");
338}
339
340static void create_root_dir(ext2_filsys fs)
341{
342	errcode_t	retval;
343	struct ext2_inode	inode;
344
345	retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
346	if (retval) {
347		com_err("ext2fs_mkdir", retval, "while creating root dir");
348		exit(1);
349	}
350	if (geteuid()) {
351		retval = ext2fs_read_inode(fs, EXT2_ROOT_INO, &inode);
352		if (retval) {
353			com_err("ext2fs_read_inode", retval,
354				"while reading root inode");
355			exit(1);
356		}
357		inode.i_uid = getuid();
358		if (inode.i_uid)
359			inode.i_gid = getgid();
360		retval = ext2fs_write_inode(fs, EXT2_ROOT_INO, &inode);
361		if (retval) {
362			com_err("ext2fs_write_inode", retval,
363				"while setting root inode ownership");
364			exit(1);
365		}
366	}
367}
368
369static void create_lost_and_found(ext2_filsys fs)
370{
371	errcode_t		retval;
372	ino_t			ino;
373	const char		*name = "lost+found";
374	int			i;
375
376	retval = ext2fs_mkdir(fs, EXT2_ROOT_INO, 0, name);
377	if (retval) {
378		com_err("ext2fs_mkdir", retval, "while creating /lost+found");
379		exit(1);
380	}
381
382	retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, strlen(name), 0, &ino);
383	if (retval) {
384		com_err("ext2_lookup", retval, "while looking up /lost+found");
385		exit(1);
386	}
387
388	for (i=1; i < EXT2_NDIR_BLOCKS; i++) {
389		retval = ext2fs_expand_dir(fs, ino);
390		if (retval) {
391			com_err("ext2fs_expand_dir", retval,
392				"while expanding /lost+found");
393			exit(1);
394		}
395	}
396}
397
398static void create_bad_block_inode(ext2_filsys fs, badblocks_list bb_list)
399{
400	errcode_t	retval;
401
402	ext2fs_mark_inode_bitmap(fs->inode_map, EXT2_BAD_INO);
403	fs->group_desc[0].bg_free_inodes_count--;
404	fs->super->s_free_inodes_count--;
405	retval = ext2fs_update_bb_inode(fs, bb_list);
406	if (retval) {
407		com_err("ext2fs_update_bb_inode", retval,
408			"while setting bad block inode");
409		exit(1);
410	}
411
412}
413
414static void reserve_inodes(ext2_filsys fs)
415{
416	ino_t	i;
417	int	group;
418
419	for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->super); i++) {
420		ext2fs_mark_inode_bitmap(fs->inode_map, i);
421		group = ext2fs_group_of_ino(fs, i);
422		fs->group_desc[group].bg_free_inodes_count--;
423		fs->super->s_free_inodes_count--;
424	}
425	ext2fs_mark_ib_dirty(fs);
426}
427
428#ifdef ZAP_BOOTBLOCK
429static void zap_bootblock(ext2_filsys fs)
430{
431	char buf[512];
432	int retval;
433
434	memset(buf, 0, 512);
435
436	retval = io_channel_write_blk(fs->io, 0, -512, buf);
437	if (retval)
438		printf("Warning: could not erase block 0: %s\n",
439		       error_message(retval));
440}
441#endif
442
443
444static void show_stats(ext2_filsys fs)
445{
446	struct ext2fs_sb 	*s = (struct ext2fs_sb *) fs->super;
447	char 			buf[80];
448	blk_t			group_block;
449	int			i, col_left;
450
451	if (param.s_blocks_count != s->s_blocks_count)
452		printf("warning: %d blocks unused.\n\n",
453		       param.s_blocks_count - s->s_blocks_count);
454
455	switch (fs->super->s_creator_os) {
456	    case EXT2_OS_LINUX: printf ("Linux"); break;
457	    case EXT2_OS_HURD:  printf ("GNU/hurd");   break;
458	    case EXT2_OS_MASIX: printf ("Masix"); break;
459	    default:		printf ("(unknown os)");
460        }
461	printf (" ext2 filesystem format\n");
462	memset(buf, 0, sizeof(buf));
463	strncpy(buf, s->s_volume_name, sizeof(s->s_volume_name));
464	printf("Filesystem label=%s\n", buf);
465	printf("%u inodes, %u blocks\n", s->s_inodes_count,
466	       s->s_blocks_count);
467	printf("%u blocks (%2.2f%%) reserved for the super user\n",
468		s->s_r_blocks_count,
469	       100.0 * s->s_r_blocks_count / s->s_blocks_count);
470	printf("First data block=%u\n", s->s_first_data_block);
471	printf("Block size=%u (log=%u)\n", fs->blocksize,
472		s->s_log_block_size);
473	printf("Fragment size=%u (log=%u)\n", fs->fragsize,
474		s->s_log_frag_size);
475	printf("%lu block group%s\n", fs->group_desc_count,
476		(fs->group_desc_count > 1) ? "s" : "");
477	printf("%u blocks per group, %u fragments per group\n",
478	       s->s_blocks_per_group, s->s_frags_per_group);
479	printf("%u inodes per group\n", s->s_inodes_per_group);
480
481	if (fs->group_desc_count == 1) {
482		printf("\n");
483		return;
484	}
485
486	printf("Superblock backups stored on blocks: ");
487	group_block = s->s_first_data_block;
488	col_left = 0;
489	for (i = 1; i < fs->group_desc_count; i++) {
490		group_block += s->s_blocks_per_group;
491		if (!ext2fs_bg_has_super(fs, i))
492			continue;
493		if (!col_left--) {
494			printf("\n\t");
495			col_left = 8;
496		}
497		printf("%u", group_block);
498		if (i != fs->group_desc_count - 1)
499			printf(", ");
500	}
501	printf("\n\n");
502}
503
504#ifndef HAVE_STRCASECMP
505static int strcasecmp (char *s1, char *s2)
506{
507	while (*s1 && *s2) {
508		int ch1 = *s1++, ch2 = *s2++;
509		if (isupper (ch1))
510			ch1 = tolower (ch1);
511		if (isupper (ch2))
512			ch2 = tolower (ch2);
513		if (ch1 != ch2)
514			return ch1 - ch2;
515	}
516	return *s1 ? 1 : *s2 ? -1 : 0;
517}
518#endif
519
520/*
521 * Set the S_CREATOR_OS field.  Return true if OS is known,
522 * otherwise, 0.
523 */
524static int set_os(struct ext2_super_block *sb, char *os)
525{
526	if (isdigit (*os))
527		sb->s_creator_os = atoi (os);
528	else if (strcasecmp(os, "linux") == 0)
529		sb->s_creator_os = EXT2_OS_LINUX;
530	else if (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0)
531		sb->s_creator_os = EXT2_OS_HURD;
532	else if (strcasecmp(os, "masix") == 0)
533		sb->s_creator_os = EXT2_OS_MASIX;
534	else
535		return 0;
536	return 1;
537}
538
539#define PATH_SET "PATH=/sbin"
540
541static parse_raid_opts(const char *opts)
542{
543	char	*buf, *token, *next, *p, *arg;
544	int	len;
545	int	raid_usage = 0;
546
547	len = strlen(opts);
548	buf = malloc(len+1);
549	if (!buf) {
550		fprintf(stderr, "Couldn't allocate memory to parse "
551			"raid options!\n");
552		exit(1);
553	}
554	strcpy(buf, opts);
555	for (token = buf; token && *token; token = next) {
556		p = strchr(token, ',');
557		next = 0;
558		if (p) {
559			*p = 0;
560			next = p+1;
561		}
562		arg = strchr(token, '=');
563		if (arg) {
564			*arg = 0;
565			arg++;
566		}
567		if (strcmp(token, "stride") == 0) {
568			if (!arg) {
569				raid_usage++;
570				continue;
571			}
572			fs_stride = strtoul(arg, &p, 0);
573			if (*p || (fs_stride == 0)) {
574				fprintf(stderr, "Invalid stride parameter.\n");
575				raid_usage++;
576				continue;
577			}
578		} else
579			raid_usage++;
580	}
581	if (raid_usage) {
582		fprintf(stderr, "\nBad raid options specified.\n\n"
583			"Raid options are separated by commas, "
584			"and may take an argument which\n"
585			"\tis set off by an equals ('=') sign.\n\n"
586			"Valid raid options are:\n"
587			"\tstride=<stride length in blocks>\n\n");
588		exit(1);
589	}
590}
591
592
593
594static void PRS(int argc, char *argv[])
595{
596	char	c;
597	int	size;
598	char	* tmp;
599	blk_t	max = 8192;
600	int	inode_ratio = 4096;
601	int	reserved_ratio = 5;
602	errcode_t	retval;
603	int	sparse_option = -1;
604	char	*oldpath = getenv("PATH");
605	struct ext2fs_sb *param_ext2 = (struct ext2fs_sb *) &param;
606	char	*raid_opts = 0;
607
608	/* Update our PATH to include /sbin  */
609	if (oldpath) {
610		char *newpath;
611
612		newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
613		strcpy (newpath, PATH_SET);
614		strcat (newpath, ":");
615		strcat (newpath, oldpath);
616		putenv (newpath);
617	} else
618		putenv (PATH_SET);
619
620	setbuf(stdout, NULL);
621	setbuf(stderr, NULL);
622	initialize_ext2_error_table();
623	memset(&param, 0, sizeof(struct ext2_super_block));
624
625	fprintf (stderr, "mke2fs %s, %s for EXT2 FS %s, %s\n",
626		 E2FSPROGS_VERSION, E2FSPROGS_DATE,
627		 EXT2FS_VERSION, EXT2FS_DATE);
628	if (argc && *argv)
629		program_name = *argv;
630	while ((c = getopt (argc, argv,
631			    "b:cf:g:i:l:m:o:qr:R:s:tvI:SFL:M:")) != EOF)
632		switch (c) {
633		case 'b':
634			size = strtoul(optarg, &tmp, 0);
635			if (size < 1024 || size > 4096 || *tmp) {
636				com_err(program_name, 0, "bad block size - %s",
637					optarg);
638				exit(1);
639			}
640			param.s_log_block_size =
641				log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
642			max = size * 8;
643			break;
644		case 'c':
645		case 't':	/* Check for bad blocks */
646			cflag = 1;
647			break;
648		case 'f':
649			size = strtoul(optarg, &tmp, 0);
650			if (size < 1024 || size > 4096 || *tmp) {
651				com_err(program_name, 0, "bad fragment size - %s",
652					optarg);
653				exit(1);
654			}
655			param.s_log_frag_size =
656				log2(size >> EXT2_MIN_BLOCK_LOG_SIZE);
657			printf("Warning: fragments not supported.  "
658			       "Ignoring -f option\n");
659			break;
660		case 'g':
661			param.s_blocks_per_group = strtoul(optarg, &tmp, 0);
662			if (*tmp) {
663				com_err(program_name, 0,
664					"Illegal number for blocks per group");
665				exit(1);
666			}
667			if ((param.s_blocks_per_group % 8) != 0) {
668				com_err(program_name, 0,
669				"blocks per group must be multiple of 8");
670				exit(1);
671			}
672			break;
673		case 'i':
674			inode_ratio = strtoul(optarg, &tmp, 0);
675			if (inode_ratio < 1024 || inode_ratio > 256 * 1024 ||
676			    *tmp) {
677				com_err(program_name, 0, "bad inode ratio - %s",
678					optarg);
679				exit(1);
680			}
681			break;
682		case 'l':
683			bad_blocks_filename = malloc(strlen(optarg)+1);
684			if (!bad_blocks_filename) {
685				com_err(program_name, ENOMEM,
686					"in malloc for bad_blocks_filename");
687				exit(1);
688			}
689			strcpy(bad_blocks_filename, optarg);
690			break;
691		case 'm':
692			reserved_ratio = strtoul(optarg, &tmp, 0);
693			if (reserved_ratio > 50 || *tmp) {
694				com_err(program_name, 0,
695					"bad reserved blocks percent - %s",
696					optarg);
697				exit(1);
698			}
699			break;
700		case 'o':
701			creator_os = optarg;
702			break;
703		case 'r':
704			param.s_rev_level = atoi(optarg);
705			break;
706		case 's':
707			sparse_option = atoi(optarg);
708			break;
709#ifdef EXT2_DYNAMIC_REV
710		case 'I':
711			param.s_inode_size = atoi(optarg);
712			break;
713#endif
714		case 'v':
715			verbose = 1;
716			break;
717		case 'q':
718			quiet = 1;
719			break;
720		case 'F':
721			force = 1;
722			break;
723		case 'L':
724			volume_label = optarg;
725			break;
726		case 'M':
727			mount_dir = optarg;
728			break;
729		case 'R':
730			raid_opts = optarg;
731			break;
732		case 'S':
733			super_only = 1;
734			break;
735		default:
736			usage();
737		}
738	if (optind == argc)
739		usage();
740	device_name = argv[optind];
741	optind++;
742	if (optind < argc) {
743		param.s_blocks_count = strtoul(argv[optind++], &tmp, 0);
744		if (*tmp) {
745			com_err(program_name, 0, "bad blocks count - %s",
746				argv[optind - 1]);
747			exit(1);
748		}
749	}
750	if (optind < argc)
751		usage();
752
753	if (raid_opts)
754		parse_raid_opts(raid_opts);
755
756	if (!force)
757		check_plausibility();
758	check_mount();
759
760	param.s_log_frag_size = param.s_log_block_size;
761
762	if (!param.s_blocks_count) {
763		retval = ext2fs_get_device_size(device_name,
764						EXT2_BLOCK_SIZE(&param),
765						&param.s_blocks_count);
766		if (retval) {
767			com_err(program_name, retval,
768				"while trying to determine filesystem size");
769			exit(1);
770		}
771	}
772
773	if (param.s_blocks_per_group) {
774		if (param.s_blocks_per_group < 256 ||
775		    param.s_blocks_per_group > max || *tmp) {
776			com_err(program_name, 0,
777				"blocks per group count out of range");
778			exit(1);
779		}
780	}
781
782	/*
783	 * Calculate number of inodes based on the inode ratio
784	 */
785	param.s_inodes_count =
786		((long long) param.s_blocks_count * EXT2_BLOCK_SIZE(&param))
787			/ inode_ratio;
788
789	/*
790	 * Calculate number of blocks to reserve
791	 */
792	param.s_r_blocks_count = (param.s_blocks_count * reserved_ratio) / 100;
793
794	/*
795	 * If we are using revision #1, use the sparse super feature
796	 * by default
797	 */
798#ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
799	if ((sparse_option == 1)
800#ifdef EXT2_DYNAMIC_REV
801	    || (param.s_rev_level >= EXT2_DYNAMIC_REV) && (!sparse_option)
802#endif
803	    )
804		param_ext2->s_feature_ro_compat |=
805			EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
806#endif
807}
808
809int main (int argc, char *argv[])
810{
811	errcode_t	retval = 0;
812	ext2_filsys	fs;
813	badblocks_list	bb_list = 0;
814	struct ext2fs_sb *s;
815
816	PRS(argc, argv);
817
818	/*
819	 * Initialize the superblock....
820	 */
821	retval = ext2fs_initialize(device_name, 0, &param,
822				   unix_io_manager, &fs);
823	if (retval) {
824		com_err(device_name, retval, "while setting up superblock");
825		exit(1);
826	}
827
828	/*
829	 * Generate a UUID for it...
830	 */
831	s = (struct ext2fs_sb *) fs->super;
832	uuid_generate(s->s_uuid);
833
834	/*
835	 * Override the creator OS, if applicable
836	 */
837	if (creator_os && !set_os(fs->super, creator_os)) {
838		com_err (program_name, 0, "unknown os - %s", creator_os);
839		exit(1);
840	}
841
842	/*
843	 * Set the volume label...
844	 */
845	if (volume_label) {
846		memset(s->s_volume_name, 0, sizeof(s->s_volume_name));
847		strncpy(s->s_volume_name, volume_label,
848			sizeof(s->s_volume_name));
849	}
850
851	/*
852	 * Set the last mount directory
853	 */
854	if (mount_dir) {
855		memset(s->s_last_mounted, 0, sizeof(s->s_last_mounted));
856		strncpy(s->s_last_mounted, mount_dir,
857			sizeof(s->s_last_mounted));
858	}
859
860	if (!quiet)
861		show_stats(fs);
862
863	if (bad_blocks_filename)
864		read_bb_file(fs, &bb_list, bad_blocks_filename);
865	if (cflag)
866		test_disk(fs, &bb_list);
867
868	handle_bad_blocks(fs, bb_list);
869	fs->stride = fs_stride;
870	retval = ext2fs_allocate_tables(fs);
871	if (retval) {
872		com_err(program_name, retval,
873			"while trying to allocate filesystem tables");
874		exit(1);
875	}
876	if (super_only) {
877		fs->super->s_state |= EXT2_ERROR_FS;
878		fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY);
879	} else {
880		write_inode_tables(fs);
881		create_root_dir(fs);
882		create_lost_and_found(fs);
883		reserve_inodes(fs);
884		create_bad_block_inode(fs, bb_list);
885#ifdef ZAP_BOOTBLOCK
886		zap_bootblock(fs);
887#endif
888	}
889
890	if (!quiet)
891		printf("Writing superblocks and "
892		       "filesystem accounting information: ");
893	ext2fs_close(fs);
894	if (!quiet)
895		printf("done\n");
896	return 0;
897}
898