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