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