Whamcloud - gitweb
e2fsck: track errors/badness found for each inode
[tools/e2fsprogs.git] / misc / mke2fs.c
index cf9c338..7ec8cc2 100644 (file)
@@ -18,6 +18,7 @@
 
 #define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX in Solaris */
 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
 #include <strings.h>
@@ -42,9 +43,6 @@ extern int optind;
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
-#ifdef HAVE_MNTENT_H
-#include <mntent.h>
-#endif
 #include <sys/ioctl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -87,6 +85,7 @@ int   verbose;
 int    quiet;
 int    super_only;
 int    discard = 1;    /* attempt to discard device before fs creation */
+int    direct_io;
 int    force;
 int    noaction;
 int    journal_size;
@@ -94,6 +93,7 @@ int   journal_flags;
 int    lazy_itable_init;
 char   *bad_blocks_filename;
 __u32  fs_stride;
+int    quotatype = -1;  /* Initialize both user and group quotas by default */
 
 struct ext2_super_block fs_param;
 char *fs_uuid = NULL;
@@ -112,14 +112,15 @@ int linux_version_code = 0;
 static void usage(void)
 {
        fprintf(stderr, _("Usage: %s [-c|-l filename] [-b block-size] "
-       "[-f fragment-size]\n\t[-i bytes-per-inode] [-I inode-size] "
+       "[-C cluster-size]\n\t[-i bytes-per-inode] [-I inode-size] "
        "[-J journal-options]\n"
-       "\t[-G meta group size] [-N number-of-inodes]\n"
+       "\t[-G flex-group-size] [-N number-of-inodes]\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] [-U UUID] [-jnqvFKSV] device [blocks-count]\n"),
+       "\t[-t fs-type] [-T usage-type ] [-U UUID] "
+       "[-jnqvDFKSV] device [blocks-count]\n"),
                program_name);
        exit(1);
 }
@@ -674,7 +675,21 @@ static void parse_extended_opts(struct ext2_super_block *param,
                        *arg = 0;
                        arg++;
                }
-               if (strcmp(token, "stride") == 0) {
+               if (strcmp(token, "mmp_update_interval") == 0) {
+                       if (!arg) {
+                               r_usage++;
+                               badopt = token;
+                               continue;
+                       }
+                       param->s_mmp_update_interval = strtoul(arg, &p, 0);
+                       if (*p) {
+                               fprintf(stderr,
+                                       _("Invalid mmp_update_interval: %s\n"),
+                                       arg);
+                               r_usage++;
+                               continue;
+                       }
+               } else if (strcmp(token, "stride") == 0) {
                        if (!arg) {
                                r_usage++;
                                badopt = token;
@@ -778,6 +793,23 @@ static void parse_extended_opts(struct ext2_super_block *param,
                        discard = 1;
                } else if (!strcmp(token, "nodiscard")) {
                        discard = 0;
+               } else if (!strcmp(token, "quotatype")) {
+                       if (!arg) {
+                               r_usage++;
+                               badopt = token;
+                               continue;
+                       }
+                       if (!strncmp(arg, "usr", 3)) {
+                               quotatype = 0;
+                       } else if (!strncmp(arg, "grp", 3)) {
+                               quotatype = 1;
+                       } else {
+                               fprintf(stderr,
+                                       _("Invalid quotatype parameter: %s\n"),
+                                       arg);
+                               r_usage++;
+                               continue;
+                       }
                } else {
                        r_usage++;
                        badopt = token;
@@ -796,7 +828,8 @@ static void parse_extended_opts(struct ext2_super_block *param,
                        "\tlazy_journal_init=<0 to disable, 1 to enable>\n"
                        "\ttest_fs\n"
                        "\tdiscard\n"
-                       "\tnodiscard\n\n"),
+                       "\tnodiscard\n"
+                       "\tquotatype=<usr OR grp>\n\n"),
                        badopt ? badopt : "");
                free(buf);
                exit(1);
@@ -822,6 +855,7 @@ static __u32 ok_features[3] = {
                EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|
                EXT2_FEATURE_INCOMPAT_META_BG|
                EXT4_FEATURE_INCOMPAT_FLEX_BG|
+               EXT4_FEATURE_INCOMPAT_MMP |
                EXT4_FEATURE_INCOMPAT_64BIT,
        /* R/O compat */
        EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
@@ -831,7 +865,10 @@ static __u32 ok_features[3] = {
                EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|
                EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
                EXT4_FEATURE_RO_COMPAT_BIGALLOC|
-               EXT4_FEATURE_RO_COMPAT_QUOTA
+#ifdef CONFIG_QUOTA
+               EXT4_FEATURE_RO_COMPAT_QUOTA|
+#endif
+               0
 };
 
 
@@ -975,6 +1012,8 @@ static char **parse_fs_type(const char *fs_type,
                ext_type = "ext2";
        else if (!strcmp(program_name, "mke3fs"))
                ext_type = "ext3";
+       else if (!strcmp(program_name, "mke4fs"))
+               ext_type = "ext4";
        else if (progname) {
                ext_type = strrchr(progname, '/');
                if (ext_type)
@@ -1029,15 +1068,12 @@ static char **parse_fs_type(const char *fs_type,
        if (!usage_types)
                usage_types = size_type;
 
-       parse_str = malloc(usage_types ? strlen(usage_types)+1 : 1);
+       parse_str = malloc(strlen(usage_types)+1);
        if (!parse_str) {
                free(list.list);
                return 0;
        }
-       if (usage_types)
-               strcpy(parse_str, usage_types);
-       else
-               *parse_str = '\0';
+       strcpy(parse_str, usage_types);
 
        if (ext_type)
                push_string(&list, ext_type);
@@ -1283,7 +1319,7 @@ profile_error:
        }
 
        while ((c = getopt (argc, argv,
-                   "b:cg:i:jl:m:no:qr:s:t:vC:E:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) {
+                   "b:cg:i:jl:m:no:qr:s:t:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) {
                switch (c) {
                case 'b':
                        blocksize = strtol(optarg, &tmp, 0);
@@ -1311,11 +1347,14 @@ profile_error:
                        if (cluster_size < EXT2_MIN_CLUSTER_SIZE ||
                            cluster_size > EXT2_MAX_CLUSTER_SIZE || *tmp) {
                                com_err(program_name, 0,
-                                       _("invalid fragment size - %s"),
+                                       _("invalid cluster size - %s"),
                                        optarg);
                                exit(1);
                        }
                        break;
+               case 'D':
+                       direct_io = 1;
+                       break;
                case 'g':
                        fs_param.s_blocks_per_group = strtoul(optarg, &tmp, 0);
                        if (*tmp) {
@@ -1448,9 +1487,19 @@ profile_error:
                        super_only = 1;
                        break;
                case 't':
+                       if (fs_type) {
+                               com_err(program_name, 0,
+                                   _("The -t option may only be used once"));
+                               exit(1);
+                       }
                        fs_type = strdup(optarg);
                        break;
                case 'T':
+                       if (usage_types) {
+                               com_err(program_name, 0,
+                                   _("The -T option may only be used once"));
+                               exit(1);
+                       }
                        usage_types = strdup(optarg);
                        break;
                case 'U':
@@ -1516,17 +1565,6 @@ profile_error:
                ext2fs_close(jfs);
        }
 
-       if (blocksize > sys_page_size) {
-               if (!force) {
-                       com_err(program_name, 0,
-                               _("%d-byte blocks too big for system (max %d)"),
-                               blocksize, sys_page_size);
-                       proceed_question();
-               }
-               fprintf(stderr, _("Warning: %d-byte blocks too big for system "
-                                 "(max %d), forced to continue\n"),
-                       blocksize, sys_page_size);
-       }
        if (optind < argc) {
                fs_blocks_count = parse_num_blocks2(argv[optind++],
                                                   fs_param.s_log_block_size);
@@ -1835,6 +1873,19 @@ profile_error:
 
        blocksize = EXT2_BLOCK_SIZE(&fs_param);
 
+       /* This check should happen beyond the last assignment to blocksize */
+       if (blocksize > sys_page_size) {
+               if (!force) {
+                       com_err(program_name, 0,
+                               _("%d-byte blocks too big for system (max %d)"),
+                               blocksize, sys_page_size);
+                       proceed_question();
+               }
+               fprintf(stderr, _("Warning: %d-byte blocks too big for system "
+                                 "(max %d), forced to continue\n"),
+                       blocksize, sys_page_size);
+       }
+
        lazy_itable_init = 0;
        if (access("/sys/fs/ext4/features/lazy_itable_init", R_OK) == 0)
                lazy_itable_init = 1;
@@ -1846,6 +1897,7 @@ profile_error:
        journal_flags |= get_bool_from_profile(fs_types,
                                               "lazy_journal_init", 0) ?
                                               EXT2_MKJOURNAL_LAZYINIT : 0;
+       journal_flags |= EXT2_MKJOURNAL_NO_MNT_CHECK;
 
        /* Get options from profile */
        for (cpp = fs_types; *cpp; cpp++) {
@@ -1919,7 +1971,7 @@ profile_error:
                                num_inodes = MAX_32_NUM;
                        else {
                                com_err(program_name, 0,
-                                       _("too many inodes (%llu), raise"
+                                       _("too many inodes (%llu), raise "
                                          "inode ratio?"), n);
                                exit(1);
                        }
@@ -2015,18 +2067,21 @@ open_err_out:
 static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr)
 {
        errcode_t retval = ENOMEM;
-       char *tdb_dir, *tdb_file = NULL;
+       char *tdb_dir = NULL, *tdb_file = NULL;
        char *device_name, *tmp_name;
+       int free_tdb_dir = 0;
 
        /*
         * Configuration via a conf file would be
         * nice
         */
        tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
-       if (!tdb_dir)
+       if (!tdb_dir) {
                profile_get_string(profile, "defaults",
                                   "undo_dir", 0, "/var/lib/e2fsprogs",
                                   &tdb_dir);
+               free_tdb_dir = 1;
+       }
 
        if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
            access(tdb_dir, W_OK))
@@ -2060,10 +2115,14 @@ static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr)
                 "using the command:\n"
                 "    e2undo %s %s\n\n"), tdb_file, name);
 
+       if (free_tdb_dir)
+               free(tdb_dir);
        free(tdb_file);
        return 0;
 
 errout:
+       if (free_tdb_dir)
+               free(tdb_dir);
        free(tdb_file);
        com_err(program_name, retval,
                _("while trying to setup undo file\n"));
@@ -2075,12 +2134,18 @@ static int mke2fs_discard_device(ext2_filsys fs)
        struct ext2fs_numeric_progress_struct progress;
        blk64_t blocks = ext2fs_blocks_count(fs->super);
        blk64_t count = DISCARD_STEP_MB;
-       blk64_t cur = 0;
+       blk64_t cur;
        int retval = 0;
 
-       retval = io_channel_discard(fs->io, 0, 0);
+       /*
+        * Let's try if discard really works on the device, so
+        * we do not print numeric progress resulting in failure
+        * afterwards.
+        */
+       retval = io_channel_discard(fs->io, 0, fs->blocksize);
        if (retval)
                return retval;
+       cur = fs->blocksize;
 
        count *= (1024 * 1024);
        count /= fs->blocksize;
@@ -2143,13 +2208,12 @@ static int create_quota_inodes(ext2_filsys fs)
 {
        quota_ctx_t qctx;
 
-       init_quota_context(&qctx, fs, -1);
-       compute_quota(qctx, -1);
-       write_quota_inode(qctx, USRQUOTA);
-       write_quota_inode(qctx, GRPQUOTA);
-       release_quota_context(&qctx);
+       quota_init_context(&qctx, fs, -1);
+       quota_compute_usage(qctx);
+       quota_write_inode(qctx, quotatype);
+       quota_release_context(&qctx);
 
-       return;
+       return 0;
 }
 
 int main (int argc, char *argv[])
@@ -2158,7 +2222,8 @@ int main (int argc, char *argv[])
        ext2_filsys     fs;
        badblocks_list  bb_list = 0;
        unsigned int    journal_blocks;
-       unsigned int    i;
+       unsigned int    i, checkinterval;
+       int             max_mnt_count;
        int             val, hash_alg;
        int             flags;
        int             old_bitmaps;
@@ -2172,6 +2237,7 @@ int main (int argc, char *argv[])
        setlocale(LC_CTYPE, "");
        bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
        textdomain(NLS_CAT_NAME);
+       set_com_err_gettext(gettext);
 #endif
        PRS(argc, argv);
 
@@ -2193,6 +2259,8 @@ int main (int argc, char *argv[])
         * Initialize the superblock....
         */
        flags = EXT2_FLAG_EXCLUSIVE;
+       if (direct_io)
+               flags |= EXT2_FLAG_DIRECT_IO;
        profile_get_boolean(profile, "options", "old_bitmaps", 0, 0,
                            &old_bitmaps);
        if (!old_bitmaps)
@@ -2291,7 +2359,8 @@ int main (int argc, char *argv[])
                for (i = 0, val = 0 ; i < sizeof(fs->super->s_uuid); i++)
                        val += fs->super->s_uuid[i];
                fs->super->s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
-       }
+       } else
+               fs->super->s_max_mnt_count = -1;
 
        /*
         * Override the creator OS, if applicable
@@ -2369,6 +2438,17 @@ int main (int argc, char *argv[])
        if (super_only) {
                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) {
+                       for (i = 0; i < fs->group_desc_count; i++)
+                               ext2fs_bg_itable_unused_set(fs, i, 0);
+               }
        } else {
                /* rsv must be a power of two (64kB is MD RAID sb alignment) */
                blk64_t rsv = 65536 / fs->blocksize;
@@ -2477,6 +2557,19 @@ int main (int argc, char *argv[])
                        printf(_("done\n"));
        }
 no_journal:
+       if (!super_only &&
+           fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) {
+               retval = ext2fs_mmp_init(fs);
+               if (retval) {
+                       fprintf(stderr, _("\nError while enabling multiple "
+                                         "mount protection feature."));
+                       exit(1);
+               }
+               if (!quiet)
+                       printf(_("Multiple mount protection is enabled "
+                                "with update interval %d seconds.\n"),
+                              fs->super->s_mmp_update_interval);
+       }
 
        if (EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
                                       EXT4_FEATURE_RO_COMPAT_BIGALLOC))
@@ -2488,22 +2581,23 @@ no_journal:
        if (!quiet)
                printf(_("Writing superblocks and "
                       "filesystem accounting information: "));
-       retval = ext2fs_flush(fs);
+       checkinterval = fs->super->s_checkinterval;
+       max_mnt_count = fs->super->s_max_mnt_count;
+       retval = ext2fs_close(fs);
        if (retval) {
                fprintf(stderr,
                        _("\nWarning, had trouble writing out superblocks."));
-       }
-       if (!quiet) {
+       } else if (!quiet) {
                printf(_("done\n\n"));
                if (!getenv("MKE2FS_SKIP_CHECK_MSG"))
-                       print_check_message(fs);
+                       print_check_message(max_mnt_count, checkinterval);
        }
-       val = ext2fs_close(fs);
+
        remove_error_table(&et_ext2_error_table);
        remove_error_table(&et_prof_error_table);
        profile_release(profile);
        for (i=0; fs_types[i]; i++)
                free(fs_types[i]);
        free(fs_types);
-       return (retval || val) ? 1 : 0;
+       return retval;
 }