X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=misc%2Fmke2fs.c;h=179a4d15b868bae83f8a55ab4c4632195d40d09e;hb=03940aac5492879ef365b07e69105a98f4dbabf9;hp=abc8bd07a61595b23b924588d18c7163f08e6e15;hpb=9aef4b695445c0bc12a79b8c0bd68efc194302e7;p=tools%2Fe2fsprogs.git diff --git a/misc/mke2fs.c b/misc/mke2fs.c index abc8bd0..179a4d1 100644 --- a/misc/mke2fs.c +++ b/misc/mke2fs.c @@ -16,18 +16,17 @@ * enforced (but it's not much fun on a character device :-). */ -#define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX in Solaris */ +#define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX */ #include "config.h" #include #include #include -#include #include #include #ifdef __linux__ #include -#include +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #endif #ifdef HAVE_GETOPT_H #include @@ -45,25 +44,22 @@ extern int optind; #include #endif #include -#include -#include #include #include #include #include "ext2fs/ext2_fs.h" #include "ext2fs/ext2fsP.h" -#include "et/com_err.h" #include "uuid/uuid.h" -#include "e2p/e2p.h" -#include "ext2fs/ext2fs.h" #include "util.h" -#include "profile.h" -#include "prof_err.h" +#include "support/nls-enable.h" +#include "support/plausible.h" +#include "support/profile.h" +#include "support/prof_err.h" #include "../version.h" -#include "nls-enable.h" -#include "quota/mkquota.h" +#include "support/quotaio.h" #include "mke2fs.h" +#include "create_inode.h" #define STRIDE_LENGTH 8 @@ -102,6 +98,8 @@ static __u32 fs_stride; static int quotatype = -1; /* Initialize both user and group quotas by default */ static __u64 offset; static blk64_t journal_location = ~0LL; +static int proceed_delay = -1; +static blk64_t dev_size; static struct ext2_super_block fs_param; static char *fs_uuid = NULL; @@ -111,24 +109,29 @@ static char *mount_dir; char *journal_device; static int sync_kludge; /* Set using the MKE2FS_SYNC env. option */ char **fs_types; +const char *root_dir; /* Copy files from the specified directory */ +static char *undo_file; static profile_t profile; static int sys_page_size = 4096; -static int linux_version_code = 0; + +static int errors_behavior = 0; static void usage(void) { fprintf(stderr, _("Usage: %s [-c|-l filename] [-b block-size] " "[-C cluster-size]\n\t[-i bytes-per-inode] [-I inode-size] " "[-J journal-options]\n" - "\t[-G flex-group-size] [-N number-of-inodes]\n" + "\t[-G flex-group-size] [-N number-of-inodes] " + "[-d root-directory]\n" "\t[-m reserved-blocks-percentage] [-o creator-os]\n" "\t[-g blocks-per-group] [-L volume-label] " "[-M last-mounted-directory]\n\t[-O feature[,...]] " "[-r fs-revision] [-E extended-option[,...]]\n" - "\t[-t fs-type] [-T usage-type ] [-U UUID] " - "[-jnqvDFKSV] device [blocks-count]\n"), + "\t[-t fs-type] [-T usage-type ] [-U UUID] [-e errors_behavior]" + "[-z undo_file]\n" + "\t[-jnqvDFKSV] device [blocks-count]\n"), program_name); exit(1); } @@ -177,7 +180,8 @@ static int parse_version_number(const char *s) return KERNEL_VERSION(major, minor, rev); } -static int is_before_linux_ver(unsigned int major, unsigned int minor) +static int is_before_linux_ver(unsigned int major, unsigned int minor, + unsigned int rev) { struct utsname ut; static int linux_version_code = -1; @@ -191,10 +195,11 @@ static int is_before_linux_ver(unsigned int major, unsigned int minor) if (linux_version_code == 0) return 0; - return linux_version_code < KERNEL_VERSION(major, minor, 0); + return linux_version_code < (int) KERNEL_VERSION(major, minor, rev); } #else -static int is_before_linux_ver(unsigned int major, unsigned int minor) +static int is_before_linux_ver(unsigned int major, unsigned int minor, + unsigned int rev) { return 0; } @@ -336,6 +341,25 @@ _("Warning: the backup superblock/group descriptors at block %u contain\n" ext2fs_badblocks_list_iterate_end(bb_iter); } +static void write_reserved_inodes(ext2_filsys fs) +{ + errcode_t retval; + ext2_ino_t ino; + struct ext2_inode *inode; + + retval = ext2fs_get_memzero(EXT2_INODE_SIZE(fs->super), &inode); + if (retval) { + com_err("inode_init", retval, _("while allocating memory")); + exit(1); + } + + for (ino = 1; ino < EXT2_FIRST_INO(fs->super); ino++) + ext2fs_write_inode_full(fs, ino, inode, + EXT2_INODE_SIZE(fs->super)); + + ext2fs_free_mem(&inode); +} + static errcode_t packed_allocate_tables(ext2_filsys fs) { errcode_t retval; @@ -366,6 +390,7 @@ static errcode_t packed_allocate_tables(ext2_filsys fs) ext2fs_block_alloc_stats_range(fs, goal, fs->inode_blocks_per_group, +1); ext2fs_inode_table_loc_set(fs, i, goal); + ext2fs_group_desc_csum_set(fs, i); } return 0; } @@ -398,12 +423,14 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed) ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_ZEROED); ext2fs_group_desc_csum_set(fs, i); } - retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num); - if (retval) { - fprintf(stderr, _("\nCould not write %d " - "blocks in inode table starting at %llu: %s\n"), - num, blk, error_message(retval)); - exit(1); + if (!itable_zeroed) { + retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num); + if (retval) { + fprintf(stderr, _("\nCould not write %d " + "blocks in inode table starting at %llu: %s\n"), + num, blk, error_message(retval)); + exit(1); + } } if (sync_kludge) { if (sync_kludge == 1) @@ -412,9 +439,14 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed) sync(); } } - ext2fs_zero_blocks2(0, 0, 0, 0, 0); ext2fs_numeric_progress_close(fs, &progress, _("done \n")); + + /* Reserved inodes must always have correct checksums */ + if (fs->super->s_creator_os == EXT2_OS_LINUX && + fs->super->s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) + write_reserved_inodes(fs); } static void create_root_dir(ext2_filsys fs) @@ -595,7 +627,6 @@ static void create_journal_dev(ext2_filsys fs) count -= c; ext2fs_numeric_progress_update(fs, &progress, blk); } - ext2fs_zero_blocks2(0, 0, 0, 0, 0); ext2fs_numeric_progress_close(fs, &progress, NULL); write_superblock: @@ -618,6 +649,14 @@ static void show_stats(ext2_filsys fs) dgrp_t i; int need, col_left; + if (!verbose) { + printf(_("Creating filesystem with %llu %dk blocks and " + "%u inodes\n"), + ext2fs_blocks_count(s), fs->blocksize >> 10, + s->s_inodes_count); + goto skip_details; + } + if (ext2fs_blocks_count(&fs_param) != ext2fs_blocks_count(s)) fprintf(stderr, _("warning: %llu blocks unused.\n\n"), ext2fs_blocks_count(&fs_param) - ext2fs_blocks_count(s)); @@ -666,11 +705,14 @@ static void show_stats(ext2_filsys fs) s->s_blocks_per_group, s->s_clusters_per_group); printf(_("%u inodes per group\n"), s->s_inodes_per_group); +skip_details: if (fs->group_desc_count == 1) { printf("\n"); return; } + if (!e2p_is_null_uuid(s->s_uuid)) + printf(_("Filesystem UUID: %s\n"), e2p_uuid2str(s->s_uuid)); printf("%s", _("Superblock backups stored on blocks: ")); group_block = s->s_first_data_block; col_left = 0; @@ -692,6 +734,23 @@ static void show_stats(ext2_filsys fs) } /* + * Returns true if making a file system for the Hurd, else 0 + */ +static int for_hurd(const char *os) +{ + if (!os) { +#ifdef __GNU__ + return 1; +#else + return 0; +#endif + } + if (isdigit(*os)) + return (atoi(os) == EXT2_OS_HURD); + return (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0); +} + +/* * Set the S_CREATOR_OS field. Return true if OS is known, * otherwise, 0. */ @@ -809,7 +868,7 @@ static void parse_extended_opts(struct ext2_super_block *param, if (*p || num_backups > 2) { fprintf(stderr, _("Invalid # of backup " - "superbocks: %s\n"), + "superblocks: %s\n"), arg); r_usage++; continue; @@ -1018,7 +1077,9 @@ static __u32 ok_features[3] = { EXT2_FEATURE_INCOMPAT_META_BG| EXT4_FEATURE_INCOMPAT_FLEX_BG| EXT4_FEATURE_INCOMPAT_MMP | - EXT4_FEATURE_INCOMPAT_64BIT, + EXT4_FEATURE_INCOMPAT_64BIT| + EXT4_FEATURE_INCOMPAT_INLINE_DATA| + EXT4_FEATURE_INCOMPAT_ENCRYPT, /* R/O compat */ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| EXT4_FEATURE_RO_COMPAT_HUGE_FILE| @@ -1027,10 +1088,8 @@ static __u32 ok_features[3] = { EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| EXT4_FEATURE_RO_COMPAT_GDT_CSUM| EXT4_FEATURE_RO_COMPAT_BIGALLOC| -#ifdef CONFIG_QUOTA EXT4_FEATURE_RO_COMPAT_QUOTA| -#endif - 0 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM }; @@ -1159,15 +1218,11 @@ static char **parse_fs_type(const char *fs_type, const char *size_type; struct str_list list; unsigned long long meg; - int is_hurd = 0; + int is_hurd = for_hurd(creator_os); if (init_list(&list)) return 0; - if (creator_os && (!strcasecmp(creator_os, "GNU") || - !strcasecmp(creator_os, "hurd"))) - is_hurd = 1; - if (fs_type) ext_type = fs_type; else if (is_hurd) @@ -1295,6 +1350,18 @@ int get_int_from_profile(char **types, const char *opt, int def_val) return ret; } +static unsigned int get_uint_from_profile(char **types, const char *opt, + unsigned int def_val) +{ + unsigned int ret; + char **cpp; + + profile_get_uint(profile, "defaults", opt, 0, def_val, &ret); + for (cpp = types; *cpp; cpp++) + profile_get_uint(profile, "fs_types", *cpp, opt, ret, &ret); + return ret; +} + static double get_double_from_profile(char **types, const char *opt, double def_val) { @@ -1327,11 +1394,11 @@ static const char *default_files[] = { "", 0 }; * device's alignment offset, if any, or a negative error. */ static int get_device_geometry(const char *file, - struct ext2_super_block *fs_param, - int psector_size) + struct ext2_super_block *param, + unsigned int psector_size) { int rc = -1; - int blocksize; + unsigned int blocksize; blkid_probe pr; blkid_topology tp; unsigned long min_io; @@ -1352,7 +1419,7 @@ static int get_device_geometry(const char *file, min_io = blkid_topology_get_minimum_io_size(tp); opt_io = blkid_topology_get_optimal_io_size(tp); - blocksize = EXT2_BLOCK_SIZE(fs_param); + blocksize = EXT2_BLOCK_SIZE(param); if ((min_io == 0) && (psector_size > blocksize)) min_io = psector_size; if ((opt_io == 0) && min_io) @@ -1362,9 +1429,9 @@ static int get_device_geometry(const char *file, /* setting stripe/stride to blocksize is pointless */ if (min_io > blocksize) - fs_param->s_raid_stride = min_io / blocksize; + param->s_raid_stride = min_io / blocksize; if (opt_io > blocksize) - fs_param->s_raid_stripe_width = opt_io / blocksize; + param->s_raid_stripe_width = opt_io / blocksize; rc = blkid_topology_get_alignment_offset(tp); out: @@ -1375,7 +1442,7 @@ out: static void PRS(int argc, char *argv[]) { - int b, c; + int b, c, flags; int cluster_size = 0; char *tmp, **cpp; int blocksize = 0; @@ -1384,14 +1451,13 @@ static void PRS(int argc, char *argv[]) unsigned long flex_bg_size = 0; double reserved_ratio = -1.0; int lsector_size = 0, psector_size = 0; - int show_version_only = 0; + int show_version_only = 0, is_device = 0; unsigned long long num_inodes = 0; /* unsigned long long to catch too-large input */ errcode_t retval; char * oldpath = getenv("PATH"); char * extended_opts = 0; char * fs_type = 0; char * usage_types = 0; - blk64_t dev_size; /* * NOTE: A few words about fs_blocks_count and blocksize: * @@ -1473,7 +1539,7 @@ profile_error: memset(&fs_param, 0, sizeof(struct ext2_super_block)); fs_param.s_rev_level = 1; /* Create revision 1 filesystems now */ - if (is_before_linux_ver(2, 2)) + if (is_before_linux_ver(2, 2, 0)) fs_param.s_rev_level = 0; if (argc && *argv) { @@ -1486,7 +1552,7 @@ profile_error: } while ((c = getopt (argc, argv, - "b:cg:i:jl:m:no:qr:s:t:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) { + "b:ce:g:i:jl:m:no:qr:s:t:d:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:Vz:")) != EOF) { switch (c) { case 'b': blocksize = parse_num_blocks2(optarg, -1); @@ -1529,6 +1595,20 @@ profile_error: case 'E': extended_opts = optarg; break; + case 'e': + if (strcmp(optarg, "continue") == 0) + errors_behavior = EXT2_ERRORS_CONTINUE; + else if (strcmp(optarg, "remount-ro") == 0) + errors_behavior = EXT2_ERRORS_RO; + else if (strcmp(optarg, "panic") == 0) + errors_behavior = EXT2_ERRORS_PANIC; + else { + com_err(program_name, 0, + _("bad error behavior - %s"), + optarg); + usage(); + } + break; case 'F': force++; break; @@ -1558,6 +1638,12 @@ profile_error: _("flex_bg size must be a power of 2")); exit(1); } + if (flex_bg_size > MAX_32_NUM) { + com_err(program_name, 0, + _("flex_bg size (%lu) must be less than" + " or equal to 2^31"), flex_bg_size); + exit(1); + } break; case 'i': inode_ratio = strtoul(optarg, &tmp, 0); @@ -1647,6 +1733,11 @@ profile_error: _("bad revision level - %s"), optarg); exit(1); } + if (r_opt > EXT2_MAX_SUPP_REV) { + com_err(program_name, EXT2_ET_REV_TOO_HIGH, + _("while trying to create revision %d"), r_opt); + exit(1); + } fs_param.s_rev_level = r_opt; break; case 's': /* deprecated */ @@ -1674,6 +1765,9 @@ profile_error: case 'U': fs_uuid = optarg; break; + case 'd': + root_dir = optarg; + break; case 'v': verbose = 1; break; @@ -1681,6 +1775,9 @@ profile_error: /* Print version number and exit */ show_version_only++; break; + case 'z': + undo_file = optarg; + break; default: usage(); } @@ -1734,7 +1831,7 @@ profile_error: printf(_("Using journal device's blocksize: %d\n"), blocksize); fs_param.s_log_block_size = int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); - ext2fs_close(jfs); + ext2fs_close_free(&jfs); } if (optind < argc) { @@ -1750,8 +1847,20 @@ profile_error: if (optind < argc) usage(); - if (!force) - check_plausibility(device_name); + profile_get_integer(profile, "options", "proceed_delay", 0, 0, + &proceed_delay); + + /* The isatty() test is so we don't break existing scripts */ + flags = CREATE_FILE; + if (isatty(0) && isatty(1)) + flags |= CHECK_FS_EXIST; + if (!quiet) + flags |= VERBOSE_CREATE; + if (fs_blocks_count == 0) + flags |= NO_SIZE; + if (!check_plausibility(device_name, flags, &is_device) && !force) + proceed_question(proceed_delay); + check_mount(device_name, force, _("filesystem")); /* Determine the size of the device (if possible) */ @@ -1793,10 +1902,10 @@ profile_error: fs_blocks_count &= ~((blk64_t) ((sys_page_size / EXT2_BLOCK_SIZE(&fs_param))-1)); } - } else if (!force && (fs_blocks_count > dev_size)) { + } else if (!force && is_device && (fs_blocks_count > dev_size)) { com_err(program_name, 0, "%s", _("Filesystem larger than apparent device size.")); - proceed_question(); + proceed_question(proceed_delay); } if (!fs_type) @@ -1824,7 +1933,7 @@ profile_error: tmp = NULL; if (fs_param.s_rev_level != EXT2_GOOD_OLD_REV) { tmp = get_string_from_profile(fs_types, "base_features", - "sparse_super,filetype,resize_inode,dir_index"); + "sparse_super,large_file,filetype,resize_inode,dir_index"); edit_feature(tmp, &fs_param.s_feature_compat); free(tmp); @@ -1847,10 +1956,40 @@ profile_error: tmp = get_string_from_profile(fs_types, "default_features", ""); } + /* Mask off features which aren't supported by the Hurd */ + if (for_hurd(creator_os)) { + fs_param.s_feature_incompat &= ~EXT2_FEATURE_INCOMPAT_FILETYPE; + fs_param.s_feature_ro_compat &= + ~(EXT4_FEATURE_RO_COMPAT_HUGE_FILE | + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); + } edit_feature(fs_features ? fs_features : tmp, &fs_param.s_feature_compat); if (tmp) free(tmp); + /* + * If the user specified features incompatible with the Hurd, complain + */ + if (for_hurd(creator_os)) { + if (fs_param.s_feature_incompat & + EXT2_FEATURE_INCOMPAT_FILETYPE) { + fprintf(stderr, "%s", _("The HURD does not support the " + "filetype feature.\n")); + exit(1); + } + if (fs_param.s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_HUGE_FILE) { + fprintf(stderr, "%s", _("The HURD does not support the " + "huge_file feature.\n")); + exit(1); + } + if (fs_param.s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) { + fprintf(stderr, "%s", _("The HURD does not support the " + "metadata_csum feature.\n")); + exit(1); + } + } /* Get the hardware sector sizes, if available */ retval = ext2fs_get_device_sectsize(device_name, &lsector_size); @@ -1882,7 +2021,7 @@ profile_error: if (use_bsize == -1) { use_bsize = sys_page_size; - if (is_before_linux_ver(2, 6) && use_bsize > 4096) + if (is_before_linux_ver(2, 6, 0) && use_bsize > 4096) use_bsize = 4096; } if (lsector_size && use_bsize < lsector_size) @@ -1991,7 +2130,8 @@ profile_error: reserved_ratio = 0; fs_param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV; fs_param.s_feature_compat = 0; - fs_param.s_feature_ro_compat = 0; + fs_param.s_feature_ro_compat &= + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; } /* Check the user's mkfs options for 64bit */ @@ -2039,7 +2179,8 @@ profile_error: } #ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY - retval = get_device_geometry(device_name, &fs_param, psector_size); + retval = get_device_geometry(device_name, &fs_param, + (unsigned int) psector_size); if (retval < 0) { fprintf(stderr, _("warning: Unable to get device geometry for %s\n"), @@ -2070,14 +2211,30 @@ profile_error: com_err(program_name, 0, _("%d-byte blocks too big for system (max %d)"), blocksize, sys_page_size); - proceed_question(); + proceed_question(proceed_delay); } fprintf(stderr, _("Warning: %d-byte blocks too big for system " "(max %d), forced to continue\n"), blocksize, sys_page_size); } - lazy_itable_init = 0; + /* Metadata checksumming wasn't totally stable before 3.18. */ + if (is_before_linux_ver(3, 18, 0) && + (fs_param.s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) + fprintf(stderr, _("Suggestion: Use Linux kernel >= 3.18 for " + "improved stability of the metadata and journal " + "checksum features.\n")); + + /* + * On newer kernels we do have lazy_itable_init support. So pick the + * right default in case ext4 module is not loaded. + */ + if (is_before_linux_ver(2, 6, 37)) + lazy_itable_init = 0; + else + lazy_itable_init = 1; + if (access("/sys/fs/ext4/features/lazy_itable_init", R_OK) == 0) lazy_itable_init = 1; @@ -2116,6 +2273,13 @@ profile_error: if (extended_opts) parse_extended_opts(&fs_param, extended_opts); + /* Don't allow user to set both metadata_csum and uninit_bg bits. */ + if ((fs_param.s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && + (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) + fs_param.s_feature_ro_compat &= + ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM; + /* Can't support bigalloc feature without extents feature */ if ((fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC) && !(fs_param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)) { @@ -2141,14 +2305,8 @@ profile_error: "See https://ext4.wiki.kernel.org/" "index.php/Bigalloc for more information\n\n")); - if (!quiet && - (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_QUOTA)) - fprintf(stderr, "%s", _("\nWarning: the quota feature is " - "still under development\n" - "See https://ext4.wiki.kernel.org/" - "index.php/Quota for more information\n\n")); - - /* Since sparse_super is the default, we would only have a problem + /* + * Since sparse_super is the default, we would only have a problem * here if it was explicitly disabled. */ if ((fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) && @@ -2181,8 +2339,8 @@ profile_error: inode_size = get_int_from_profile(fs_types, "inode_size", 0); if (!flex_bg_size && (fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG)) - flex_bg_size = get_int_from_profile(fs_types, - "flex_bg_size", 16); + flex_bg_size = get_uint_from_profile(fs_types, + "flex_bg_size", 16); if (flex_bg_size) { if (!(fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_FLEX_BG)) { @@ -2207,6 +2365,20 @@ profile_error: fs_param.s_inode_size = inode_size; } + /* + * If inode size is 128 and inline data is enabled, we need + * to notify users that inline data will never be useful. + */ + if ((fs_param.s_feature_incompat & + EXT4_FEATURE_INCOMPAT_INLINE_DATA) && + fs_param.s_inode_size == EXT2_GOOD_OLD_INODE_SIZE) { + com_err(program_name, 0, + _("%d byte inodes are too small for inline data; " + "specify larger size"), + fs_param.s_inode_size); + exit(1); + } + /* Make sure number of inodes specified will fit in 32 bits */ if (num_inodes == 0) { unsigned long long n; @@ -2276,7 +2448,8 @@ static int should_do_undo(const char *name) int csum_flag, force_undo; csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(&fs_param, - EXT4_FEATURE_RO_COMPAT_GDT_CSUM); + EXT4_FEATURE_RO_COMPAT_GDT_CSUM | + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); force_undo = get_int_from_profile(fs_types, "force_undo", 0); if (!force_undo && (!csum_flag || !lazy_itable_init)) return 0; @@ -2324,6 +2497,21 @@ static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr) char *dev_name, *tmp_name; int free_tdb_dir = 0; + /* (re)open a specific undo file */ + if (undo_file && undo_file[0] != 0) { + retval = set_undo_io_backing_manager(*io_ptr); + if (retval) + goto err; + *io_ptr = undo_io_manager; + retval = set_undo_io_backup_file(undo_file); + if (retval) + goto err; + printf(_("Overwriting existing filesystem; this can be undone " + "using the command:\n" + " e2undo %s %s\n\n"), undo_file, name); + return retval; + } + /* * Configuration via a conf file would be * nice @@ -2357,10 +2545,14 @@ static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr) if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { retval = errno; + com_err(program_name, retval, + _("while trying to delete %s"), tdb_file); goto errout; } - set_undo_io_backing_manager(*io_ptr); + retval = set_undo_io_backing_manager(*io_ptr); + if (retval) + goto errout; *io_ptr = undo_io_manager; retval = set_undo_io_backup_file(tdb_file); if (retval) @@ -2378,6 +2570,7 @@ errout: if (free_tdb_dir) free(tdb_dir); free(tdb_file); +err: com_err(program_name, retval, "%s", _("while trying to setup undo file\n")); return retval; @@ -2484,12 +2677,44 @@ static int create_quota_inodes(ext2_filsys fs) return 0; } +static errcode_t set_error_behavior(ext2_filsys fs) +{ + char *arg = NULL; + short errors = fs->super->s_errors; + + arg = get_string_from_profile(fs_types, "errors", NULL); + if (arg == NULL) + goto try_user; + + if (strcmp(arg, "continue") == 0) + errors = EXT2_ERRORS_CONTINUE; + else if (strcmp(arg, "remount-ro") == 0) + errors = EXT2_ERRORS_RO; + else if (strcmp(arg, "panic") == 0) + errors = EXT2_ERRORS_PANIC; + else { + com_err(program_name, 0, + _("bad error behavior in profile - %s"), + arg); + free(arg); + return EXT2_ET_INVALID_ARGUMENT; + } + free(arg); + +try_user: + if (errors_behavior) + errors = errors_behavior; + + fs->super->s_errors = errors; + return 0; +} + int main (int argc, char *argv[]) { errcode_t retval = 0; ext2_filsys fs; badblocks_list bb_list = 0; - unsigned int journal_blocks; + unsigned int journal_blocks = 0; unsigned int i, checkinterval; int max_mnt_count; int val, hash_alg; @@ -2517,7 +2742,7 @@ int main (int argc, char *argv[]) #endif io_ptr = unix_io_manager; - if (should_do_undo(device_name)) { + if (undo_file != NULL || should_do_undo(device_name)) { retval = mke2fs_setup_tdb(device_name, &io_ptr); if (retval) exit(1); @@ -2546,6 +2771,35 @@ int main (int argc, char *argv[]) _("while setting up superblock")); exit(1); } + fs->progress_ops = &ext2fs_numeric_progress_ops; + + /* Set the error behavior */ + retval = set_error_behavior(fs); + if (retval) + usage(); + + /* Check the user's mkfs options for metadata checksumming */ + if (!quiet && + !EXT2_HAS_INCOMPAT_FEATURE(fs->super, + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) && + EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { + if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, + EXT3_FEATURE_INCOMPAT_EXTENTS)) + printf("%s", + _("Extents are not enabled. The file extent " + "tree can be checksummed, whereas block maps " + "cannot. Not enabling extents reduces the " + "coverage of metadata checksumming. " + "Pass -O extents to rectify.\n")); + if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, + EXT4_FEATURE_INCOMPAT_64BIT)) + printf("%s", + _("64-bit filesystem support is not enabled. " + "The larger fields afforded by this feature " + "enable full-strength checksumming. " + "Pass -O 64bit to rectify.\n")); + } /* Calculate journal blocks */ if (!journal_device && ((journal_size) || @@ -2554,7 +2808,7 @@ int main (int argc, char *argv[]) journal_blocks = figure_journal_size(journal_size, fs); /* Can't undo discard ... */ - if (!noaction && discard && (io_ptr != undo_io_manager)) { + if (!noaction && discard && dev_size && (io_ptr != undo_io_manager)) { retval = mke2fs_discard_device(fs); if (!retval && io_channel_discard_zeroes_data(fs->io)) { if (verbose) @@ -2583,6 +2837,7 @@ int main (int argc, char *argv[]) (fs_param.s_feature_ro_compat & (EXT4_FEATURE_RO_COMPAT_HUGE_FILE|EXT4_FEATURE_RO_COMPAT_GDT_CSUM| EXT4_FEATURE_RO_COMPAT_DIR_NLINK| + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM| EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))) fs->super->s_kbytes_written = 1; @@ -2603,6 +2858,7 @@ int main (int argc, char *argv[]) } } else uuid_generate(fs->super->s_uuid); + ext2fs_init_csum_seed(fs); /* * Initialize the directory index variables @@ -2679,6 +2935,19 @@ int main (int argc, char *argv[]) sizeof(fs->super->s_last_mounted)); } + /* Set current default encryption algorithms for data and + * filename encryption */ + if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_ENCRYPT) { + fs->super->s_encrypt_algos[0] = + EXT4_ENCRYPTION_MODE_AES_256_XTS; + fs->super->s_encrypt_algos[1] = + EXT4_ENCRYPTION_MODE_AES_256_CTS; + } + + if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) + fs->super->s_checksum_type = EXT2_CRC32C_CHKSUM; + if (!quiet || noaction) show_stats(fs); @@ -2688,7 +2957,8 @@ int main (int argc, char *argv[]) if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { create_journal_dev(fs); - exit(ext2fs_close(fs) ? 1 : 0); + printf("\n"); + exit(ext2fs_close_free(&fs) ? 1 : 0); } if (bad_blocks_filename) @@ -2721,16 +2991,20 @@ int main (int argc, char *argv[]) } if (super_only) { + check_plausibility(device_name, CHECK_FS_EXIST, NULL); + printf(_("%s may be further corrupted by superblock rewrite\n"), + device_name); + if (!force) + proceed_question(proceed_delay); fs->super->s_state |= EXT2_ERROR_FS; fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY); - /* + /* * The command "mke2fs -S" is used to recover * corrupted file systems, so do not mark any of the * inodes as unused; we want e2fsck to consider all * inodes as potentially containing recoverable data. */ - if (fs->super->s_feature_ro_compat & - EXT4_FEATURE_RO_COMPAT_GDT_CSUM) { + if (ext2fs_has_group_desc_csum(fs)) { for (i = 0; i < fs->group_desc_count; i++) ext2fs_bg_itable_unused_set(fs, i, 0); } @@ -2782,8 +3056,9 @@ int main (int argc, char *argv[]) if (journal_device) { ext2_filsys jfs; - if (!force) - check_plausibility(journal_device); + if (!check_plausibility(journal_device, CHECK_BLOCK_DEV, + NULL) && !force) + proceed_question(proceed_delay); check_mount(journal_device, force, _("journal")); retval = ext2fs_open(journal_device, EXT2_FLAG_RW| @@ -2809,7 +3084,7 @@ int main (int argc, char *argv[]) } if (!quiet) printf("%s", _("done\n")); - ext2fs_close(jfs); + ext2fs_close_free(&jfs); free(journal_device); } else if ((journal_size) || (fs_param.s_feature_compat & @@ -2864,16 +3139,30 @@ no_journal: EXT4_FEATURE_RO_COMPAT_QUOTA)) create_quota_inodes(fs); - retval = mk_hugefiles(fs); + retval = mk_hugefiles(fs, device_name); if (retval) com_err(program_name, retval, "while creating huge files"); + /* Copy files from the specified directory */ + if (root_dir) { + if (!quiet) + printf("%s", _("Copying files into the device: ")); + + retval = populate_fs(fs, EXT2_ROOT_INO, root_dir, + EXT2_ROOT_INO); + if (retval) { + com_err(program_name, retval, "%s", + _("while populating file system")); + exit(1); + } else if (!quiet) + printf("%s", _("done\n")); + } if (!quiet) printf("%s", _("Writing superblocks and " "filesystem accounting information: ")); checkinterval = fs->super->s_checkinterval; max_mnt_count = fs->super->s_max_mnt_count; - retval = ext2fs_close(fs); + retval = ext2fs_close_free(&fs); if (retval) { fprintf(stderr, "%s", _("\nWarning, had trouble writing out superblocks."));