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 *) ¶m; 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(¶m, 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(¶m), 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(¶m)) 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 ¶m_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, ¶m, 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