Whamcloud - gitweb
tune2fs: Don't allow the -I option if the flex_bg feature is enabled
[tools/e2fsprogs.git] / misc / tune2fs.c
index 8eb7451..14529e3 100644 (file)
@@ -25,7 +25,7 @@
  * 94/03/06    - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de)
  */
 
-#define _XOPEN_SOURCE 500 /* for inclusion of strptime() */
+#define _XOPEN_SOURCE 600 /* for inclusion of strptime() */
 #define _BSD_SOURCE /* for inclusion of strcasecmp() */
 #include <fcntl.h>
 #include <grp.h>
@@ -37,7 +37,9 @@ extern int optind;
 #endif
 #include <pwd.h>
 #include <stdio.h>
+#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
@@ -172,11 +174,12 @@ static void remove_journal_device(ext2_filsys fs)
        }
 
 #ifdef CONFIG_TESTIO_DEBUG
-       io_ptr = test_io_manager;
-       test_io_backing_manager = unix_io_manager;
-#else
-       io_ptr = unix_io_manager;
+       if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
+               io_ptr = test_io_manager;
+               test_io_backing_manager = unix_io_manager;
+       } else
 #endif
+               io_ptr = unix_io_manager;
        retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
                             EXT2_FLAG_JOURNAL_DEV_OK, 0,
                             fs->blocksize, io_ptr, &jfs);
@@ -213,7 +216,7 @@ static void remove_journal_device(ext2_filsys fs)
                        break;
        }
        if (i >= nr_users) {
-               fputs(_("Filesystem's UUID not found on journal device.\n"), 
+               fputs(_("Filesystem's UUID not found on journal device.\n"),
                      stderr);
                commit_remove_journal = 1;
                goto no_valid_journal;
@@ -246,7 +249,7 @@ no_valid_journal:
 
 /* Helper function for remove_journal_inode */
 static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
-                              int blockcnt EXT2FS_ATTR((unused)), 
+                              int blockcnt EXT2FS_ATTR((unused)),
                               void *private EXT2FS_ATTR((unused)))
 {
        blk_t   block;
@@ -269,7 +272,7 @@ static void remove_journal_inode(ext2_filsys fs)
        struct ext2_inode       inode;
        errcode_t               retval;
        ino_t                   ino = fs->super->s_journal_inum;
-       
+
        retval = ext2fs_read_inode(fs, ino,  &inode);
        if (retval) {
                com_err(program_name, retval,
@@ -389,9 +392,8 @@ static void update_feature_set(ext2_filsys fs, char *features)
        if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
                /*
                 * If adding a journal flag, let the create journal
-                * code below handle creating setting the flag and
-                * creating the journal.  We supply a default size if
-                * necessary.
+                * code below handle setting the flag and creating the
+                * journal.  We supply a default size if necessary.
                 */
                if (!journal_size)
                        journal_size = -1;
@@ -400,7 +402,7 @@ static void update_feature_set(ext2_filsys fs, char *features)
 
        if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) {
                if (!sb->s_def_hash_version)
-                       sb->s_def_hash_version = EXT2_HASH_TEA;
+                       sb->s_def_hash_version = EXT2_HASH_HALF_MD4;
                if (uuid_is_null((unsigned char *) sb->s_hash_seed))
                        uuid_generate((unsigned char *) sb->s_hash_seed);
        }
@@ -474,11 +476,12 @@ static void add_journal(ext2_filsys fs)
                check_plausibility(journal_device);
                check_mount(journal_device, 0, _("journal"));
 #ifdef CONFIG_TESTIO_DEBUG
-               io_ptr = test_io_manager;
-               test_io_backing_manager = unix_io_manager;
-#else
-               io_ptr = unix_io_manager;
+               if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
+                       io_ptr = test_io_manager;
+                       test_io_backing_manager = unix_io_manager;
+               } else
 #endif
+                       io_ptr = unix_io_manager;
                retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
                                     EXT2_FLAG_JOURNAL_DEV_OK, 0,
                                     fs->blocksize, io_ptr, &jfs);
@@ -543,7 +546,7 @@ static void parse_e2label_options(int argc, char ** argv)
                *io_options++ = 0;
        device_name = blkid_get_devname(NULL, argv[1], NULL);
        if (!device_name) {
-               com_err("e2label", 0, _("Unable to resolve '%s'"), 
+               com_err("e2label", 0, _("Unable to resolve '%s'"),
                        argv[1]);
                exit(1);
        }
@@ -552,7 +555,7 @@ static void parse_e2label_options(int argc, char ** argv)
                open_flag |= EXT2_FLAG_RW;
                L_flag = 1;
                new_label = argv[2];
-       } else 
+       } else
                print_label++;
 }
 
@@ -741,7 +744,7 @@ static void parse_tune2fs_options(int argc, char **argv)
                                mntopts_cmd = optarg;
                                open_flag = EXT2_FLAG_RW;
                                break;
-                               
+
                        case 'O':
                                if (features_cmd) {
                                        com_err (program_name, 0,
@@ -828,7 +831,7 @@ static void parse_tune2fs_options(int argc, char **argv)
                *io_options++ = 0;
        device_name = blkid_get_devname(NULL, argv[optind], NULL);
        if (!device_name) {
-               com_err("tune2fs", 0, _("Unable to resolve '%s'"), 
+               com_err("tune2fs", 0, _("Unable to resolve '%s'"),
                        argv[optind]);
                exit(1);
        }
@@ -845,7 +848,7 @@ void do_findfs(int argc, char **argv)
        }
        dev = blkid_get_devname(NULL, argv[1], NULL);
        if (!dev) {
-               com_err("findfs", 0, _("Unable to resolve '%s'"), 
+               com_err("findfs", 0, _("Unable to resolve '%s'"),
                        argv[1]);
                exit(1);
        }
@@ -856,7 +859,7 @@ void do_findfs(int argc, char **argv)
 static void parse_extended_opts(ext2_filsys fs, const char *opts)
 {
        char    *buf, *token, *next, *p, *arg;
-       int     len;
+       int     len, hash_alg;
        int     r_usage = 0;
 
        len = strlen(opts);
@@ -916,7 +919,26 @@ static void parse_extended_opts(ext2_filsys fs, const char *opts)
                                continue;
                        }
                        stripe_width_set = 1;
-               } else 
+               } else if (strcmp(token, "hash_alg") == 0 ||
+                          strcmp(token, "hash-alg") == 0) {
+                       if (!arg) {
+                               r_usage++;
+                               continue;
+                       }
+                       hash_alg = e2p_string2hash(arg);
+                       if (hash_alg < 0) {
+                               fprintf(stderr, 
+                                       _("Invalid hash algorithm: %s\n"),
+                                       arg);
+                               r_usage++;
+                               continue;
+                       }
+                       fs->super->s_def_hash_version = hash_alg;
+                       printf(_("Setting default hash algorithm "
+                                "to %s (%d)\n"), 
+                              arg, hash_alg);
+                       ext2fs_mark_super_dirty(fs);
+               } else
                        r_usage++;
        }
        if (r_usage) {
@@ -926,14 +948,15 @@ static void parse_extended_opts(ext2_filsys fs, const char *opts)
                        "\tis set off by an equals ('=') sign.\n\n"
                        "Valid extended options are:\n"
                        "\tstride=<RAID per-disk chunk size in blocks>\n"
-                       "\tstripe-width=<RAID stride*data disks in blocks>\n"
+                       "\tstripe_width=<RAID stride*data disks in blocks>\n"
+                       "\thash_alg=<hash algorithm>\n"
                        "\ttest_fs\n"
                        "\t^test_fs\n"));
                free(buf);
                exit(1);
        }
        free(buf);
-}      
+}
 
 static int get_move_bitmap(ext2_filsys fs, int new_ino_blks_per_grp,
                                        ext2fs_block_bitmap bmap)
@@ -988,13 +1011,13 @@ static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
        if (retval)
                return retval;
 
-       for (blk = fs->super->s_first_data_block;
-                       blk < fs->super->s_blocks_count; blk++) {
+       for (new_blk = blk = fs->super->s_first_data_block;
+            blk < fs->super->s_blocks_count; blk++) {
 
                if (!ext2fs_test_block_bitmap(bmap, blk))
                        continue;
 
-               retval = ext2fs_new_block(fs, blk, NULL, &new_blk);
+               retval = ext2fs_new_block(fs, new_blk, NULL, &new_blk);
                if (retval)
                        goto err_out;
 
@@ -1045,12 +1068,14 @@ static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)),
                         e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
                         blk_t ref_block EXT2FS_ATTR((unused)),
                         int ref_offset EXT2FS_ATTR((unused)),
-                        void *priv_data EXT2FS_ATTR((unused)))
+                        void *priv_data)
 {
        int ret = 0;
        blk_t new_blk;
+       ext2fs_block_bitmap bmap = (ext2fs_block_bitmap) priv_data;
 
-
+       if (!ext2fs_test_block_bitmap(bmap, *block_nr))
+               return 0;
        new_blk = transalate_block(*block_nr);
        if (new_blk) {
                *block_nr = new_blk;
@@ -1063,7 +1088,7 @@ static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)),
        return ret;
 }
 
-static int inode_scan_and_fix(ext2_filsys fs)
+static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
 {
        errcode_t retval = 0;
        ext2_ino_t ino;
@@ -1099,8 +1124,8 @@ static int inode_scan_and_fix(ext2_filsys fs)
                 * Do we need to fix this ??
                 */
 
-               if (inode.i_file_acl) {
-
+               if (inode.i_file_acl &&
+                   ext2fs_test_block_bitmap(bmap, inode.i_file_acl)) {
                        blk = transalate_block(inode.i_file_acl);
                        if (!blk)
                                continue;
@@ -1119,9 +1144,8 @@ static int inode_scan_and_fix(ext2_filsys fs)
                if (!ext2fs_inode_has_valid_blocks(&inode))
                        continue;
 
-               retval = ext2fs_block_iterate2(fs, ino, 0,
-                                               block_buf, process_block,
-                                               0);
+               retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
+                                              process_block, bmap);
                if (retval)
                        goto err_out;
 
@@ -1292,11 +1316,6 @@ static int resize_inode(ext2_filsys fs, unsigned long new_size)
        int new_ino_blks_per_grp;
        ext2fs_block_bitmap bmap;
 
-       if (new_size <= EXT2_INODE_SIZE(fs->super)) {
-               fprintf(stderr, _("New inode size too small\n"));
-               return EXT2_ET_INVALID_ARGUMENT;
-       }
-
        ext2fs_read_inode_bitmap(fs);
        ext2fs_read_block_bitmap(fs);
        INIT_LIST_HEAD(&blk_move_list);
@@ -1326,7 +1345,7 @@ static int resize_inode(ext2_filsys fs, unsigned long new_size)
        if (retval)
                goto err_out;
 
-       retval = inode_scan_and_fix(fs);
+       retval = inode_scan_and_fix(fs, bmap);
        if (retval)
                goto err_out;
 
@@ -1390,8 +1409,8 @@ static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
        set_undo_io_backing_manager(*io_ptr);
        *io_ptr = undo_io_manager;
        set_undo_io_backup_file(tdb_file);
-       printf(_("To undo the tune2fs operations please run "
-                "the command\n    undoe2fs %s %s\n\n"),
+       printf(_("To undo the tune2fs operation please run "
+                "the command\n    e2undo %s %s\n\n"),
                 tdb_file, name);
        free(tmp_name);
        return retval;
@@ -1402,7 +1421,7 @@ int main (int argc, char ** argv)
        errcode_t retval;
        ext2_filsys fs;
        struct ext2_super_block *sb;
-       io_manager io_ptr;
+       io_manager io_ptr, io_ptr_orig = NULL;
 
 #ifdef ENABLE_NLS
        setlocale(LC_MESSAGES, "");
@@ -1420,33 +1439,57 @@ int main (int argc, char ** argv)
                parse_e2label_options(argc, argv);
        else
                parse_tune2fs_options(argc, argv);
-       
+
 #ifdef CONFIG_TESTIO_DEBUG
-       io_ptr = test_io_manager;
-       test_io_backing_manager = unix_io_manager;
-#else
-       io_ptr = unix_io_manager;
+       if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_DEBUG")) {
+               io_ptr = test_io_manager;
+               test_io_backing_manager = unix_io_manager;
+       } else
 #endif
+               io_ptr = unix_io_manager;
+
+retry_open:
+       retval = ext2fs_open2(device_name, io_options, open_flag,
+                             0, 0, io_ptr, &fs);
+        if (retval) {
+               com_err (program_name, retval, _("while trying to open %s"),
+                        device_name);
+               fprintf(stderr,
+                       _("Couldn't find valid filesystem superblock.\n"));
+               exit(1);
+       }
+
+       if (I_flag && !io_ptr_orig) {
+               /*
+                * Check the inode size is right so we can issue an
+                * error message and bail before setting up the tdb
+                * file.
+                */
+               if (new_inode_size == EXT2_INODE_SIZE(fs->super)) {
+                       fprintf(stderr, _("The inode size is already %d\n"),
+                               new_inode_size);
+                       exit(1);
+               }
+               if (new_inode_size < EXT2_INODE_SIZE(fs->super)) {
+                       fprintf(stderr, _("Shrinking the inode size is "
+                                         "not supported\n"));
+                       exit(1);
+               }
 
-       if (I_flag) {
                /*
                 * If inode resize is requested use the
                 * Undo I/O manager
                 */
+               io_ptr_orig = io_ptr;
                retval = tune2fs_setup_tdb(device_name, &io_ptr);
                if (retval)
                        exit(1);
+               if (io_ptr != io_ptr_orig) {
+                       ext2fs_close(fs);
+                       goto retry_open;
+               }
        }
 
-       retval = ext2fs_open2(device_name, io_options, open_flag, 
-                             0, 0, io_ptr, &fs);
-        if (retval) {
-               com_err (program_name, retval, _("while trying to open %s"),
-                        device_name);
-               fprintf(stderr,
-                       _("Couldn't find valid filesystem superblock.\n"));
-               exit(1);
-       }
        sb = fs->super;
        fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
 
@@ -1545,7 +1588,7 @@ int main (int argc, char ** argv)
        }
        if (L_flag) {
                if (strlen(new_label) > sizeof(sb->s_volume_name))
-                       fputs(_("Warning: label too long, truncating.\n"), 
+                       fputs(_("Warning: label too long, truncating.\n"),
                              stderr);
                memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
                strncpy(sb->s_volume_name, new_label,
@@ -1566,8 +1609,24 @@ int main (int argc, char ** argv)
                parse_extended_opts(fs, extended_cmd);
        if (journal_size || journal_device)
                add_journal(fs);
-       
+
        if (U_flag) {
+               int set_csum = 0;
+               dgrp_t i;
+
+               if (sb->s_feature_ro_compat &
+                   EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+                       /* 
+                        * Determine if the block group checksums are
+                        * correct so we know whether or not to set
+                        * them later on.
+                        */
+                       for (i = 0; i < fs->group_desc_count; i++)
+                               if (!ext2fs_group_desc_csum_verify(fs, i))
+                                       break;
+                       if (i >= fs->group_desc_count)
+                               set_csum = 1;
+               }
                if ((strcasecmp(new_UUID, "null") == 0) ||
                    (strcasecmp(new_UUID, "clear") == 0)) {
                        uuid_clear(sb->s_uuid);
@@ -1579,6 +1638,11 @@ int main (int argc, char ** argv)
                        com_err(program_name, 0, _("Invalid UUID format\n"));
                        exit(1);
                }
+               if (set_csum) {
+                       for (i = 0; i < fs->group_desc_count; i++)
+                               ext2fs_group_desc_csum_set(fs, i);
+                       fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+               }
                ext2fs_mark_super_dirty(fs);
        }
        if (I_flag) {
@@ -1588,6 +1652,13 @@ int main (int argc, char ** argv)
                                "unmounted.\n"), stderr);
                        exit(1);
                }
+               if (fs->super->s_feature_incompat &
+                   EXT4_FEATURE_INCOMPAT_FLEX_BG) {
+                       fputs(_("Changing the inode size not supported for filesystems "
+                               "with the flex_bg\nfeature enabled.\n"),
+                             stderr);
+                       exit(1);
+               }
                /*
                 * We want to update group descriptor also
                 * with the new free inode count
@@ -1595,7 +1666,7 @@ int main (int argc, char ** argv)
                fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
                if (resize_inode(fs, new_inode_size)) {
                        fputs(_("Error in resizing the inode size.\n"
-                               "Run undoe2fs to undo the "
+                               "Run e2undo to undo the "
                                "file system changes. \n"), stderr);
                } else {
                        printf (_("Setting inode size %lu\n"),