2 * mke2fs.c - Make a ext2fs filesystem.
4 * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Public
12 /* Usage: mke2fs [options] device
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 :-).
40 #include <sys/ioctl.h>
41 #include <sys/types.h>
45 #ifdef HAVE_LINUX_FS_H
48 #include <linux/ext2_fs.h>
49 #ifdef HAVE_LINUX_MAJOR_H
50 #include <linux/major.h>
53 #include "et/com_err.h"
54 #include "uuid/uuid.h"
55 #include "ext2fs/ext2fs.h"
56 #include "../version.h"
58 #define STRIDE_LENGTH 8
64 extern int isatty(int);
65 extern FILE *fpopen(const char *cmd
, const char *mode
);
67 const char * program_name
= "mke2fs";
68 const char * device_name
= NULL
;
70 /* Command line options */
76 char *bad_blocks_filename
= 0;
78 struct ext2_super_block param
;
79 char *creator_os
= NULL
;
80 char *volume_label
= NULL
;
81 char *mount_dir
= NULL
;
83 static void usage(NOARGS
)
85 fprintf(stderr
, "Usage: %s [-c|-t|-l filename] [-b block-size] "
86 "[-f fragment-size]\n\t[-i bytes-per-inode] "
87 "[-m reserved-blocks-percentage] [-qvS]\n\t"
88 "[-o creator-os] [-g blocks-per-group] [-L volume-label]\n\t"
89 "[-M last-mounted-directory] device [blocks-count]\n",
94 static int log2(int arg
)
106 static void check_plausibility(NOARGS
)
108 #ifdef HAVE_LINUX_MAJOR_H
112 val
= stat(device_name
, &s
);
115 printf("Could not stat %s --- %s\n", device_name
,
116 error_message(errno
));
118 printf("\nThe device apparently does not exist; "
119 "did yo specify it correctly?\n");
122 if(!S_ISBLK(s
.st_mode
)) {
123 printf("%s is not a block special device.\n", device_name
);
124 printf("Proceed anyway? (y,n) ");
125 if (getchar() != 'y')
129 if ((MAJOR(s
.st_rdev
) == HD_MAJOR
&& MINOR(s
.st_rdev
)%64 == 0) ||
130 (MAJOR(s
.st_rdev
) == SCSI_DISK_MAJOR
&&
131 MINOR(s
.st_rdev
)%16 == 0)) {
132 printf("%s is entire device, not just one partition!\n",
134 printf("Proceed anyway? (y,n) ");
135 if (getchar() != 'y')
142 static void check_mount(NOARGS
)
147 retval
= ext2fs_check_if_mounted(device_name
, &mount_flags
);
149 com_err("ext2fs_check_if_mount", retval
,
150 "while determining whether %s is mounted.",
154 if (!(mount_flags
& EXT2_MF_MOUNTED
))
157 fprintf(stderr
, "%s is mounted; will not make a filesystem here!\n",
163 * Helper function for read_bb_file and test_disk
165 static void invalid_block(ext2_filsys fs
, blk_t blk
)
167 printf("Bad block %u out of range; ignored.\n", blk
);
172 * Reads the bad blocks list from a file
174 static void read_bb_file(ext2_filsys fs
, badblocks_list
*bb_list
,
175 const char *bad_blocks_file
)
180 f
= fopen(bad_blocks_file
, "r");
182 com_err("read_bad_blocks_file", errno
,
183 "while trying to open %s", bad_blocks_file
);
186 retval
= ext2fs_read_bb_FILE(fs
, f
, bb_list
, invalid_block
);
189 com_err("ext2fs_read_bb_FILE", retval
,
190 "while reading in list of bad blocks from file");
196 * Runs the badblocks program to test the disk
198 static void test_disk(ext2_filsys fs
, badblocks_list
*bb_list
)
204 sprintf(buf
, "badblocks %s%s %d", quiet
? "" : "-s ",
206 fs
->super
->s_blocks_count
);
208 printf("Running command: %s\n", buf
);
211 com_err("popen", errno
,
212 "while trying run '%s'", buf
);
215 retval
= ext2fs_read_bb_FILE(fs
, f
, bb_list
, invalid_block
);
218 com_err("ext2fs_read_bb_FILE", retval
,
219 "while processing list of bad blocks from program");
224 static void handle_bad_blocks(ext2_filsys fs
, badblocks_list bb_list
)
229 badblocks_iterate bb_iter
;
239 * The primary superblock and group descriptors *must* be
240 * good; if not, abort.
242 must_be_good
= fs
->super
->s_first_data_block
+ 1 + fs
->desc_blocks
;
243 for (i
= fs
->super
->s_first_data_block
; i
<= must_be_good
; i
++) {
244 if (badblocks_list_test(bb_list
, i
)) {
245 fprintf(stderr
, "Block %d in primary superblock/group "
246 "descriptor area bad.\n", i
);
247 fprintf(stderr
, "Blocks %d through %d must be good "
248 "in order to build a filesystem.\n",
249 fs
->super
->s_first_data_block
, must_be_good
);
250 fprintf(stderr
, "Aborting....\n");
256 * See if any of the bad blocks are showing up in the backup
257 * superblocks and/or group descriptors. If so, issue a
258 * warning and adjust the block counts appropriately.
260 group_block
= fs
->super
->s_first_data_block
+
261 fs
->super
->s_blocks_per_group
;
264 for (i
= 1; i
< fs
->group_desc_count
; i
++) {
265 for (j
=0; j
< fs
->desc_blocks
+1; j
++) {
266 if (badblocks_list_test(bb_list
, group_block
+
270 "Warning: the backup superblock/group descriptors at block %d contain\n"
274 group
= ext2fs_group_of_blk(fs
, group_block
+j
);
275 fs
->group_desc
[group
].bg_free_blocks_count
++;
276 fs
->super
->s_free_blocks_count
++;
279 group_block
+= fs
->super
->s_blocks_per_group
;
283 * Mark all the bad blocks as used...
285 retval
= badblocks_list_iterate_begin(bb_list
, &bb_iter
);
287 com_err("badblocks_list_iterate_begin", retval
,
288 "while marking bad blocks as used");
291 while (badblocks_list_iterate(bb_iter
, &blk
))
292 ext2fs_mark_block_bitmap(fs
->block_map
, blk
);
293 badblocks_list_iterate_end(bb_iter
);
296 static void write_inode_tables(ext2_filsys fs
)
300 int i
, j
, num
, count
;
303 buf
= malloc(fs
->blocksize
* STRIDE_LENGTH
);
305 com_err("malloc", ENOMEM
, "while allocating zeroizing buffer");
308 memset(buf
, 0, fs
->blocksize
* STRIDE_LENGTH
);
311 printf("Writing inode tables: ");
312 for (i
= 0; i
< fs
->group_desc_count
; i
++) {
314 printf("%4d/%4ld", i
, fs
->group_desc_count
);
316 blk
= fs
->group_desc
[i
].bg_inode_table
;
317 num
= fs
->inode_blocks_per_group
;
319 for (j
=0; j
< num
; j
+= STRIDE_LENGTH
, blk
+= STRIDE_LENGTH
) {
320 if (num
-j
> STRIDE_LENGTH
)
321 count
= STRIDE_LENGTH
;
324 retval
= io_channel_write_blk(fs
->io
, blk
, count
, buf
);
326 printf("Warning: could not write %d blocks "
327 "in inode table starting at %d: %s\n",
328 count
, blk
, error_message(retval
));
331 printf("\b\b\b\b\b\b\b\b\b");
338 static void create_root_dir(ext2_filsys fs
)
341 struct ext2_inode inode
;
343 retval
= ext2fs_mkdir(fs
, EXT2_ROOT_INO
, EXT2_ROOT_INO
, 0);
345 com_err("ext2fs_mkdir", retval
, "while creating root dir");
349 retval
= ext2fs_read_inode(fs
, EXT2_ROOT_INO
, &inode
);
351 com_err("ext2fs_read_inode", retval
,
352 "while reading root inode");
355 inode
.i_uid
= getuid();
357 inode
.i_gid
= getgid();
358 retval
= ext2fs_write_inode(fs
, EXT2_ROOT_INO
, &inode
);
360 com_err("ext2fs_write_inode", retval
,
361 "while setting root inode ownership");
367 static void create_lost_and_found(ext2_filsys fs
)
371 const char *name
= "lost+found";
374 retval
= ext2fs_mkdir(fs
, EXT2_ROOT_INO
, 0, name
);
376 com_err("ext2fs_mkdir", retval
, "while creating /lost+found");
380 retval
= ext2fs_lookup(fs
, EXT2_ROOT_INO
, name
, strlen(name
), 0, &ino
);
382 com_err("ext2_lookup", retval
, "while looking up /lost+found");
386 for (i
=1; i
< EXT2_NDIR_BLOCKS
; i
++) {
387 retval
= ext2fs_expand_dir(fs
, ino
);
389 com_err("ext2fs_expand_dir", retval
,
390 "while expanding /lost+found");
396 static void create_bad_block_inode(ext2_filsys fs
, badblocks_list bb_list
)
400 ext2fs_mark_inode_bitmap(fs
->inode_map
, EXT2_BAD_INO
);
401 fs
->group_desc
[0].bg_free_inodes_count
--;
402 fs
->super
->s_free_inodes_count
--;
403 retval
= ext2fs_update_bb_inode(fs
, bb_list
);
405 com_err("ext2fs_update_bb_inode", retval
,
406 "while setting bad block inode");
412 static void reserve_inodes(ext2_filsys fs
)
417 for (i
= EXT2_ROOT_INO
+ 1; i
< EXT2_FIRST_INODE(fs
->super
); i
++) {
418 ext2fs_mark_inode_bitmap(fs
->inode_map
, i
);
419 group
= ext2fs_group_of_ino(fs
, i
);
420 fs
->group_desc
[group
].bg_free_inodes_count
--;
421 fs
->super
->s_free_inodes_count
--;
423 ext2fs_mark_ib_dirty(fs
);
427 static void zap_bootblock(ext2_filsys fs
)
434 retval
= io_channel_write_blk(fs
->io
, 0, -512, buf
);
436 printf("Warning: could not erase block 0: %s\n",
437 error_message(retval
));
442 static void show_stats(ext2_filsys fs
)
444 struct ext2fs_sb
*s
= (struct ext2fs_sb
*) fs
->super
;
449 if (param
.s_blocks_count
!= s
->s_blocks_count
)
450 printf("warning: %d blocks unused.\n\n",
451 param
.s_blocks_count
- s
->s_blocks_count
);
453 switch (fs
->super
->s_creator_os
) {
454 case EXT2_OS_LINUX
: printf ("Linux"); break;
455 case EXT2_OS_HURD
: printf ("GNU/hurd"); break;
456 case EXT2_OS_MASIX
: printf ("Masix"); break;
457 default: printf ("(unknown os)");
459 printf (" ext2 filesystem format\n");
460 memset(buf
, 0, sizeof(buf
));
461 strncpy(buf
, s
->s_volume_name
, sizeof(s
->s_volume_name
));
462 printf("Filesystem label=%s\n", buf
);
463 printf("%u inodes, %u blocks\n", s
->s_inodes_count
,
465 printf("%u blocks (%2.2f%%) reserved for the super user\n",
467 100.0 * s
->s_r_blocks_count
/ s
->s_blocks_count
);
468 printf("First data block=%u\n", s
->s_first_data_block
);
469 printf("Block size=%u (log=%u)\n", fs
->blocksize
,
470 s
->s_log_block_size
);
471 printf("Fragment size=%u (log=%u)\n", fs
->fragsize
,
473 printf("%lu block group%s\n", fs
->group_desc_count
,
474 (fs
->group_desc_count
> 1) ? "s" : "");
475 printf("%u blocks per group, %u fragments per group\n",
476 s
->s_blocks_per_group
, s
->s_frags_per_group
);
477 printf("%u inodes per group\n", s
->s_inodes_per_group
);
479 if (fs
->group_desc_count
== 1) {
484 printf("Superblock backups stored on blocks: ");
485 group_block
= s
->s_first_data_block
;
487 for (i
= 1; i
< fs
->group_desc_count
; i
++) {
488 group_block
+= s
->s_blocks_per_group
;
489 if (!ext2fs_bg_has_super(fs
, i
))
495 printf("%u", group_block
);
496 if (i
!= fs
->group_desc_count
- 1)
502 #ifndef HAVE_STRCASECMP
503 static int strcasecmp (char *s1
, char *s2
)
506 int ch1
= *s1
++, ch2
= *s2
++;
514 return *s1
? 1 : *s2
? -1 : 0;
519 * Set the S_CREATOR_OS field. Return true if OS is known,
522 static int set_os(struct ext2_super_block
*sb
, char *os
)
525 sb
->s_creator_os
= atoi (os
);
526 else if (strcasecmp(os
, "linux") == 0)
527 sb
->s_creator_os
= EXT2_OS_LINUX
;
528 else if (strcasecmp(os
, "GNU") == 0 || strcasecmp(os
, "hurd") == 0)
529 sb
->s_creator_os
= EXT2_OS_HURD
;
530 else if (strcasecmp(os
, "masix") == 0)
531 sb
->s_creator_os
= EXT2_OS_MASIX
;
537 #define PATH_SET "PATH=/sbin"
539 static void PRS(int argc
, char *argv
[])
545 int inode_ratio
= 4096;
546 int reserved_ratio
= 5;
548 int sparse_option
= -1;
549 char *oldpath
= getenv("PATH");
550 struct ext2fs_sb
*param_ext2
= (struct ext2fs_sb
*) ¶m
;
552 /* Update our PATH to include /sbin */
556 newpath
= malloc(sizeof (PATH_SET
) + 1 + strlen (oldpath
));
557 strcpy (newpath
, PATH_SET
);
558 strcat (newpath
, ":");
559 strcat (newpath
, oldpath
);
564 setbuf(stdout
, NULL
);
565 setbuf(stderr
, NULL
);
566 initialize_ext2_error_table();
567 memset(¶m
, 0, sizeof(struct ext2_super_block
));
568 #ifdef EXT2_DYNAMIC_REV
569 param
.s_rev_level
= EXT2_DYNAMIC_REV
;
572 fprintf (stderr
, "mke2fs %s, %s for EXT2 FS %s, %s\n",
573 E2FSPROGS_VERSION
, E2FSPROGS_DATE
,
574 EXT2FS_VERSION
, EXT2FS_DATE
);
576 program_name
= *argv
;
577 while ((c
= getopt (argc
, argv
,
578 "b:cf:g:i:l:m:o:qr:s:tvI:SFL:M:")) != EOF
)
581 size
= strtoul(optarg
, &tmp
, 0);
582 if (size
< 1024 || size
> 4096 || *tmp
) {
583 com_err(program_name
, 0, "bad block size - %s",
587 param
.s_log_block_size
=
588 log2(size
>> EXT2_MIN_BLOCK_LOG_SIZE
);
592 case 't': /* Check for bad blocks */
596 size
= strtoul(optarg
, &tmp
, 0);
597 if (size
< 1024 || size
> 4096 || *tmp
) {
598 com_err(program_name
, 0, "bad fragment size - %s",
602 param
.s_log_frag_size
=
603 log2(size
>> EXT2_MIN_BLOCK_LOG_SIZE
);
604 printf("Warning: fragments not supported. "
605 "Ignoring -f option\n");
608 param
.s_blocks_per_group
= strtoul(optarg
, &tmp
, 0);
610 com_err(program_name
, 0,
611 "Illegal number for blocks per group");
614 if ((param
.s_blocks_per_group
% 8) != 0) {
615 com_err(program_name
, 0,
616 "blocks per group must be multiple of 8");
621 inode_ratio
= strtoul(optarg
, &tmp
, 0);
622 if (inode_ratio
< 1024 || inode_ratio
> 256 * 1024 ||
624 com_err(program_name
, 0, "bad inode ratio - %s",
630 bad_blocks_filename
= malloc(strlen(optarg
)+1);
631 if (!bad_blocks_filename
) {
632 com_err(program_name
, ENOMEM
,
633 "in malloc for bad_blocks_filename");
636 strcpy(bad_blocks_filename
, optarg
);
639 reserved_ratio
= strtoul(optarg
, &tmp
, 0);
640 if (reserved_ratio
> 50 || *tmp
) {
641 com_err(program_name
, 0,
642 "bad reserved blocks percent - %s",
651 param
.s_rev_level
= atoi(optarg
);
654 sparse_option
= atoi(optarg
);
656 #ifdef EXT2_DYNAMIC_REV
658 param
.s_inode_size
= atoi(optarg
);
671 volume_label
= optarg
;
684 device_name
= argv
[optind
];
687 param
.s_blocks_count
= strtoul(argv
[optind
++], &tmp
, 0);
689 com_err(program_name
, 0, "bad blocks count - %s",
698 check_plausibility();
701 param
.s_log_frag_size
= param
.s_log_block_size
;
703 if (!param
.s_blocks_count
) {
704 retval
= ext2fs_get_device_size(device_name
,
705 EXT2_BLOCK_SIZE(¶m
),
706 ¶m
.s_blocks_count
);
708 com_err(program_name
, retval
,
709 "while trying to determine filesystem size");
714 if (param
.s_blocks_per_group
) {
715 if (param
.s_blocks_per_group
< 256 ||
716 param
.s_blocks_per_group
> max
|| *tmp
) {
717 com_err(program_name
, 0,
718 "blocks per group count out of range");
724 * Calculate number of inodes based on the inode ratio
726 param
.s_inodes_count
=
727 ((long long) param
.s_blocks_count
* EXT2_BLOCK_SIZE(¶m
))
731 * Calculate number of blocks to reserve
733 param
.s_r_blocks_count
= (param
.s_blocks_count
* reserved_ratio
) / 100;
736 * If we are using revision #1, use the sparse super feature
739 #ifdef EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
740 if ((sparse_option
== 1)
741 #ifdef EXT2_DYNAMIC_REV
742 || (param
.s_rev_level
>= EXT2_DYNAMIC_REV
) && (!sparse_option
)
745 param_ext2
->s_feature_ro_compat
|=
746 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
;
750 int main (int argc
, char *argv
[])
752 errcode_t retval
= 0;
754 badblocks_list bb_list
= 0;
760 * Initialize the superblock....
762 retval
= ext2fs_initialize(device_name
, 0, ¶m
,
763 unix_io_manager
, &fs
);
765 com_err(device_name
, retval
, "while setting up superblock");
770 * Generate a UUID for it...
772 s
= (struct ext2fs_sb
*) fs
->super
;
773 uuid_generate(s
->s_uuid
);
776 * Override the creator OS, if applicable
778 if (creator_os
&& !set_os(fs
->super
, creator_os
)) {
779 com_err (program_name
, 0, "unknown os - %s", creator_os
);
784 * Set the volume label...
787 memset(s
->s_volume_name
, 0, sizeof(s
->s_volume_name
));
788 strncpy(s
->s_volume_name
, volume_label
,
789 sizeof(s
->s_volume_name
));
793 * Set the last mount directory
796 memset(s
->s_last_mounted
, 0, sizeof(s
->s_last_mounted
));
797 strncpy(s
->s_last_mounted
, mount_dir
,
798 sizeof(s
->s_last_mounted
));
804 if (bad_blocks_filename
)
805 read_bb_file(fs
, &bb_list
, bad_blocks_filename
);
807 test_disk(fs
, &bb_list
);
809 handle_bad_blocks(fs
, bb_list
);
810 retval
= ext2fs_allocate_tables(fs
);
812 com_err(program_name
, retval
,
813 "while trying to allocate filesystem tables");
817 fs
->super
->s_state
|= EXT2_ERROR_FS
;
818 fs
->flags
&= ~(EXT2_FLAG_IB_DIRTY
|EXT2_FLAG_BB_DIRTY
);
820 write_inode_tables(fs
);
822 create_lost_and_found(fs
);
824 create_bad_block_inode(fs
, bb_list
);
831 printf("Writing superblocks and "
832 "filesystem accounting information: ");