• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
33 extern char *optarg;
34 extern 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 
76 extern int isatty(int);
77 extern FILE *fpopen(const char *cmd, const char *mode);
78 
79 const char * program_name = "mke2fs";
80 const char * device_name /* = NULL */;
81 
82 /* Command line options */
83 int	cflag;
84 int	verbose;
85 int	quiet;
86 int	super_only;
87 int	discard = 1;
88 int	force;
89 int	noaction;
90 int	journal_size;
91 int	journal_flags;
92 int	lazy_itable_init;
93 char	*bad_blocks_filename;
94 __u32	fs_stride;
95 
96 struct ext2_super_block fs_param;
97 char *fs_uuid = NULL;
98 char *creator_os;
99 char *volume_label;
100 char *mount_dir;
101 char *journal_device;
102 int sync_kludge;	/* Set using the MKE2FS_SYNC env. option */
103 char **fs_types;
104 
105 profile_t	profile;
106 
107 int sys_page_size = 4096;
108 int linux_version_code = 0;
109 
usage(void)110 static 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 
int_log2(int arg)125 static 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 
int_log10(unsigned int arg)137 static 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 
parse_version_number(const char * s)146 static 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  */
invalid_block(ext2_filsys fs EXT2FS_ATTR ((unused)),blk_t blk)171 static 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  */
read_bb_file(ext2_filsys fs,badblocks_list * bb_list,const char * bad_blocks_file)180 static 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  */
test_disk(ext2_filsys fs,badblocks_list * bb_list)205 static 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 
handle_bad_blocks(ext2_filsys fs,badblocks_list bb_list)232 static 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  */
309 struct progress_struct {
310 	char		format[20];
311 	char		backup[80];
312 	__u32		max;
313 	int		skip_progress;
314 };
315 
progress_init(struct progress_struct * progress,const char * label,__u32 max)316 static 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 
progress_update(struct progress_struct * progress,__u32 val)344 static 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 
progress_close(struct progress_struct * progress)352 static void progress_close(struct progress_struct *progress)
353 {
354 	if (progress->format[0] == 0)
355 		return;
356 	fputs(_("done                            \n"), stdout);
357 }
358 
write_inode_tables(ext2_filsys fs,int lazy_flag)359 static 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 
create_root_dir(ext2_filsys fs)409 static 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 
create_lost_and_found(ext2_filsys fs)444 static 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 
create_bad_block_inode(ext2_filsys fs,badblocks_list bb_list)482 static 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 
reserve_inodes(ext2_filsys fs)497 static 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 
zap_sector(ext2_filsys fs,int sect,int nsect)510 static 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 
create_journal_dev(ext2_filsys fs)548 static 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 
show_stats(ext2_filsys fs)601 static 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  */
set_os(struct ext2_super_block * sb,char * os)675 static 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 
parse_extended_opts(struct ext2_super_block * param,const char * opts)694 static 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 
843 static __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 
syntax_err_report(const char * filename,long err,int line_num)865 static 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 
873 static const char *config_fn[] = { ROOT_SYSCONFDIR "/mke2fs.conf", 0 };
874 
edit_feature(const char * str,__u32 * compat_array)875 static 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 
887 struct str_list {
888 	char **list;
889 	int num;
890 	int max;
891 };
892 
init_list(struct str_list * sl)893 static 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 
push_string(struct str_list * sl,const char * str)904 static 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 
print_str_list(char ** list)924 static 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 
parse_fs_type(const char * fs_type,const char * usage_types,struct ext2_super_block * fs_param,char * progname)936 static 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 
get_string_from_profile(char ** fs_types,const char * opt,const char * def_val)1045 static 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 
get_int_from_profile(char ** fs_types,const char * opt,int def_val)1062 static 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 
get_bool_from_profile(char ** fs_types,const char * opt,int def_val)1073 static 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 
1084 extern const char *mke2fs_default_profile;
1085 static 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  */
ext2fs_get_device_geometry(const char * file,struct ext2_super_block * fs_param)1092 static 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);
1123 out:
1124 	blkid_free_probe(pr);
1125 	return rc;
1126 }
1127 #endif
1128 
PRS(int argc,char * argv[])1129 static 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 	}
1527 get_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 	}
1533 got_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 
should_do_undo(const char * name)1822 static 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 
1865 err_out:
1866 	io_channel_close(channel);
1867 
1868 open_err_out:
1869 
1870 	return retval;
1871 }
1872 
mke2fs_setup_tdb(const char * name,io_manager * io_ptr)1873 static 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 
mke2fs_discard_blocks(ext2_filsys fs)1935 static 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 
main(int argc,char * argv[])1975 int 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 	}
2249 no_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