]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blobdiff - misc/mke2fs.c
Merge branch 'maint' into next
[thirdparty/e2fsprogs.git] / misc / mke2fs.c
index e49ad04d51402e96442d643794a5d9f58cb2b431..0718d4cf8c8160b6b531473a8c76db8c47f0fb13 100644 (file)
  * 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 <stdio.h>
 #include <string.h>
 #include <strings.h>
-#include <fcntl.h>
 #include <ctype.h>
 #include <time.h>
 #ifdef __linux__
@@ -45,25 +44,22 @@ extern int optind;
 #include <errno.h>
 #endif
 #include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <libgen.h>
 #include <limits.h>
 #include <blkid/blkid.h>
 
 #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 "plausible.h"
 #include "profile.h"
 #include "prof_err.h"
 #include "../version.h"
-#include "nls-enable.h"
 #include "quota/quotaio.h"
 #include "mke2fs.h"
+#include "create_inode.h"
+#include "nls-enable.h"
 
 #define STRIDE_LENGTH 8
 
@@ -113,23 +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 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);
 }
@@ -339,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;
@@ -402,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)
@@ -416,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)
@@ -599,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:
@@ -706,6 +733,23 @@ skip_details:
        printf("\n\n");
 }
 
+/*
+ * 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.
@@ -1033,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|
@@ -1045,7 +1091,7 @@ static __u32 ok_features[3] = {
 #ifdef CONFIG_QUOTA
                EXT4_FEATURE_RO_COMPAT_QUOTA|
 #endif
-               0
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 
@@ -1174,15 +1220,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)
@@ -1512,7 +1554,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);
@@ -1555,6 +1597,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;
@@ -1711,6 +1767,9 @@ profile_error:
                case 'U':
                        fs_uuid = optarg;
                        break;
+               case 'd':
+                       root_dir = optarg;
+                       break;
                case 'v':
                        verbose = 1;
                        break;
@@ -1718,6 +1777,9 @@ profile_error:
                        /* Print version number and exit */
                        show_version_only++;
                        break;
+               case 'z':
+                       undo_file = optarg;
+                       break;
                default:
                        usage();
                }
@@ -1896,10 +1958,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);
@@ -2040,7 +2132,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 */
@@ -2126,6 +2219,14 @@ profile_error:
                        blocksize, sys_page_size);
        }
 
+       /* 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.
@@ -2173,6 +2274,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)) {
@@ -2198,7 +2306,8 @@ profile_error:
                                  "See https://ext4.wiki.kernel.org/"
                                  "index.php/Bigalloc 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) &&
@@ -2257,6 +2366,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;
@@ -2326,7 +2449,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;
@@ -2374,6 +2498,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
@@ -2407,10 +2546,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)
@@ -2428,6 +2571,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;
@@ -2534,6 +2678,38 @@ 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;
@@ -2567,7 +2743,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);
@@ -2596,6 +2772,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) ||
@@ -2633,6 +2838,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;
 
@@ -2653,6 +2859,7 @@ int main (int argc, char *argv[])
                }
        } else
                uuid_generate(fs->super->s_uuid);
+       ext2fs_init_csum_seed(fs);
 
        /*
         * Initialize the directory index variables
@@ -2729,6 +2936,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);
 
@@ -2738,6 +2958,7 @@ int main (int argc, char *argv[])
        if (fs->super->s_feature_incompat &
            EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
                create_journal_dev(fs);
+               printf("\n");
                exit(ext2fs_close_free(&fs) ? 1 : 0);
        }
 
@@ -2784,8 +3005,7 @@ int main (int argc, char *argv[])
                 * 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);
                }
@@ -2923,6 +3143,20 @@ no_journal:
        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 "