>From 198cba8bec884bbd51901ceae45fc4384acb113c Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 8 Sep 2025 14:16:32 -0400 Subject: [PATCH 1/2] tune2fs: reorganize command-line flag handling Instead of using individual ad-hoc variables indicating whether a particular superblock value has been requested to be changed (e.g., c_flag, C_flag, et.al) use an array of booleans with indexes that are defined with more human-readable #define's (e.g., OPT_MAX_MOUNTCOUNT). There should be no behavioral changes from this code restructuring. Signed-off-by: Theodore Ts'o --- misc/tune2fs.c | 206 +++++++++++++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 92 deletions(-) diff --git a/misc/tune2fs.c b/misc/tune2fs.c index 3db57632..b4c63da4 100644 --- a/misc/tune2fs.c +++ b/misc/tune2fs.c @@ -103,13 +103,34 @@ struct fsuuid { extern int ask_yn(const char *string, int def); +#define OPT_MAX_MOUNTCOUNT 1 +#define OPT_MOUNTCOUNT 2 +#define OPT_CHECKINTERVAL 3 +#define OPT_CHECKTIME 4 +#define OPT_ERROR_BEHAVIOR 5 +#define OPT_RESUID 6 +#define OPT_RESGID 7 +#define OPT_RESERVED_BLOCKS 8 +#define OPT_RESERVED_RATIO 9 +#define OPT_INODE_SIZE 10 +#define OPT_LABEL 11 +#define OPT_UUID 12 +#define OPT_LAST_MOUNTED 13 +#define OPT_SPARSE_SUPER 14 +#define OPT_QUOTA 15 +#define OPT_JOURNAL_SIZE 16 +#define OPT_JOURNAL_OPTS 17 +#define OPT_MNTOPTS 18 +#define OPT_FEATURES 19 +#define OPT_EXTENDED_CMD 20 +#define MAX_OPTS 21 +static bool opts[MAX_OPTS]; + const char *program_name = "tune2fs"; char *device_name; char *new_label, *new_last_mounted, *requested_uuid; char *io_options; -static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag; -static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag; -static int I_flag; +static int force, do_list_super, sparse_value = -1; static int clear_mmp; static time_t last_check_time; static int print_label; @@ -237,6 +258,19 @@ static __u32 clear_ok_features[3] = { EXT4_FEATURE_RO_COMPAT_READONLY }; +/** + * Return true if there is at least one superblock change requested + */ +static bool tune_opts_requested() +{ + int i; + + for (i = 0; i < MAX_OPTS; i++) + if (opts[i]) + return true; + return false; +} + /** * Try to get journal super block if any */ @@ -293,7 +327,7 @@ static int remove_journal_device(ext2_filsys fs) int commit_remove_journal = 0; io_manager io_ptr; - if (f_flag) + if (force) commit_remove_journal = 1; /* force removal even if error */ uuid_unparse(fs->super->s_journal_uuid, buf); @@ -1204,7 +1238,7 @@ static int update_feature_set(ext2_filsys fs, char *features) return 1; } if (ext2fs_has_feature_journal_needs_recovery(sb) && - f_flag < 2) { + force < 2) { fputs(_("The needs_recovery flag is set. " "Please run e2fsck before clearing\n" "the has_journal flag.\n"), stderr); @@ -1228,7 +1262,7 @@ static int update_feature_set(ext2_filsys fs, char *features) "when the filesystem is unmounted.\n"), stderr); return 1; } - if (ext2fs_has_feature_orphan_present(sb) && f_flag < 2) { + if (ext2fs_has_feature_orphan_present(sb) && force < 2) { fputs(_("The orphan_present feature is set. Please " "run e2fsck before clearing orphan_file " "feature.\n"), @@ -1551,8 +1585,8 @@ mmp_error: * Set the Q_flag here and handle the quota options in the code * below. */ - if (!Q_flag) { - Q_flag = 1; + if (!opts[OPT_QUOTA]) { + opts[OPT_QUOTA] = 1; /* Enable usr/grp quota by default */ for (qtype = 0; qtype < MAXQUOTAS; qtype++) { if (qtype != PRJQUOTA) @@ -1571,26 +1605,26 @@ mmp_error: "inode size too small.\n")); return 1; } - Q_flag = 1; + opts[OPT_QUOTA] = true; quota_enable[PRJQUOTA] = QOPT_ENABLE; } if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_PROJECT)) { - Q_flag = 1; + opts[OPT_QUOTA] = true; quota_enable[PRJQUOTA] = QOPT_DISABLE; } if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_QUOTA)) { /* - * Set the Q_flag here and handle the quota options in the code - * below. + * Set the quota flag here and handle the quota + * options in the code below. */ - if (Q_flag) + if (opts[OPT_QUOTA]) fputs(_("\nWarning: '^quota' option overrides '-Q'" "arguments.\n"), stderr); - Q_flag = 1; + opts[OPT_QUOTA] = true; /* Disable all quota by default */ for (qtype = 0; qtype < MAXQUOTAS; qtype++) quota_enable[qtype] = QOPT_DISABLE; @@ -1940,7 +1974,7 @@ static void parse_e2label_options(int argc, char ** argv) open_flag = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SUPER_ONLY; if (argc == 3) { open_flag |= EXT2_FLAG_RW; - L_flag = 1; + opts[OPT_LABEL] = true; new_label = argv[2]; } else print_label++; @@ -1990,8 +2024,7 @@ static void parse_tune2fs_options(int argc, char **argv) while ((c = getopt(argc, argv, optstring)) != EOF) switch (c) { case 'c': - open_flag = EXT2_FLAG_RW; - c_flag = 1; + opts[OPT_MAX_MOUNTCOUNT] = true; if (strcmp(optarg, "random") == 0) { max_mount_count = 65536; break; @@ -2008,6 +2041,7 @@ static void parse_tune2fs_options(int argc, char **argv) max_mount_count = -1; break; case 'C': + opts[OPT_MOUNTCOUNT] = true; mount_count = strtoul(optarg, &tmp, 0); if (*tmp || mount_count > 16000) { com_err(program_name, 0, @@ -2015,10 +2049,9 @@ static void parse_tune2fs_options(int argc, char **argv) optarg); usage(); } - C_flag = 1; - open_flag = EXT2_FLAG_RW; break; case 'e': + opts[OPT_ERROR_BEHAVIOR] = true; if (strcmp(optarg, "continue") == 0) errors = EXT2_ERRORS_CONTINUE; else if (strcmp(optarg, "remount-ro") == 0) @@ -2031,17 +2064,16 @@ static void parse_tune2fs_options(int argc, char **argv) optarg); usage(); } - e_flag = 1; - open_flag = EXT2_FLAG_RW; break; case 'E': + opts[OPT_EXTENDED_CMD] = true; extended_cmd = optarg; - open_flag |= EXT2_FLAG_RW; break; case 'f': /* Force */ - f_flag++; + force++; break; case 'g': + opts[OPT_RESGID] = true; resgid = strtoul(optarg, &tmp, 0); if (*tmp) { gr = getgrnam(optarg); @@ -2058,10 +2090,9 @@ static void parse_tune2fs_options(int argc, char **argv) optarg); usage(); } - g_flag = 1; - open_flag = EXT2_FLAG_RW; break; case 'i': + opts[OPT_CHECKINTERVAL] = 1; interval = strtoul(optarg, &tmp, 0); switch (*tmp) { case 's': @@ -2090,28 +2121,25 @@ static void parse_tune2fs_options(int argc, char **argv) _("bad interval - %s"), optarg); usage(); } - i_flag = 1; - open_flag = EXT2_FLAG_RW; break; case 'j': + opts[OPT_JOURNAL_SIZE] = true; if (!journal_size) journal_size = -1; - open_flag = EXT2_FLAG_RW; break; case 'J': + opts[OPT_JOURNAL_OPTS] = true; parse_journal_opts(optarg); - open_flag = EXT2_FLAG_RW; break; case 'l': - l_flag = 1; + do_list_super = 1; break; case 'L': + opts[OPT_LABEL] = true; new_label = optarg; - L_flag = 1; - open_flag |= EXT2_FLAG_RW | - EXT2_FLAG_JOURNAL_DEV_OK; break; case 'm': + opts[OPT_RESERVED_RATIO] = true; reserved_ratio = strtod(optarg, &tmp); if (*tmp || reserved_ratio > 50 || reserved_ratio < 0) { @@ -2120,40 +2148,37 @@ static void parse_tune2fs_options(int argc, char **argv) optarg); usage(); } - m_flag = 1; - open_flag = EXT2_FLAG_RW; break; case 'M': + opts[OPT_LAST_MOUNTED] = true; new_last_mounted = optarg; - M_flag = 1; - open_flag = EXT2_FLAG_RW; break; case 'o': + opts[OPT_MNTOPTS] = true; if (mntopts_cmd) { com_err(program_name, 0, "%s", _("-o may only be specified once")); usage(); } mntopts_cmd = optarg; - open_flag = EXT2_FLAG_RW; break; case 'O': + opts[OPT_FEATURES] = true; if (features_cmd) { com_err(program_name, 0, "%s", _("-O may only be specified once")); usage(); } features_cmd = optarg; - open_flag = EXT2_FLAG_RW; break; case 'Q': - Q_flag = 1; + opts[OPT_QUOTA] = true; ret = parse_quota_opts(optarg, option_handle_function); if (ret) exit(1); - open_flag = EXT2_FLAG_RW; break; case 'r': + opts[OPT_RESERVED_BLOCKS] = true; reserved_blocks = strtoul(optarg, &tmp, 0); if (*tmp) { com_err(program_name, 0, @@ -2161,45 +2186,39 @@ static void parse_tune2fs_options(int argc, char **argv) optarg); usage(); } - r_flag = 1; - open_flag = EXT2_FLAG_RW; break; case 's': /* Deprecated */ - s_flag = atoi(optarg); - open_flag = EXT2_FLAG_RW; + opts[OPT_SPARSE_SUPER] = true; + sparse_value = atoi(optarg); break; case 'T': - T_flag = 1; + opts[OPT_CHECKTIME] = true; last_check_time = parse_time(optarg); - open_flag = EXT2_FLAG_RW; break; case 'u': - resuid = strtoul(optarg, &tmp, 0); - if (*tmp) { - pw = getpwnam(optarg); - if (pw == NULL) - tmp = optarg; - else { - resuid = pw->pw_uid; - *tmp = 0; - } + opts[OPT_RESUID] = true; + resuid = strtoul(optarg, &tmp, 0); + if (*tmp) { + pw = getpwnam(optarg); + if (pw == NULL) + tmp = optarg; + else { + resuid = pw->pw_uid; + *tmp = 0; } - if (*tmp) { - com_err(program_name, 0, - _("bad uid/user name - %s"), - optarg); + } + if (*tmp) { + com_err(program_name, 0, + _("bad uid/user name - %s"), optarg); usage(); - } - u_flag = 1; - open_flag = EXT2_FLAG_RW; - break; + } + break; case 'U': + opts[OPT_UUID] = true; requested_uuid = optarg; - U_flag = 1; - open_flag = EXT2_FLAG_RW | - EXT2_FLAG_JOURNAL_DEV_OK; break; case 'I': + opts[OPT_INODE_SIZE] = true; new_inode_size = strtoul(optarg, &tmp, 0); if (*tmp) { com_err(program_name, 0, @@ -2215,8 +2234,6 @@ static void parse_tune2fs_options(int argc, char **argv) optarg); usage(); } - open_flag = EXT2_FLAG_RW; - I_flag = 1; break; case 'z': undo_file = optarg; @@ -2226,8 +2243,13 @@ static void parse_tune2fs_options(int argc, char **argv) } if (optind < argc - 1 || optind == argc) usage(); - if (!open_flag && !l_flag) + if (tune_opts_requested()) { + open_flag = EXT2_FLAG_RW; + if (opts[OPT_LABEL] || opts[OPT_UUID]) + open_flag |= EXT2_FLAG_JOURNAL_DEV_OK; + } else { usage(); + } io_options = strchr(argv[optind], '?'); if (io_options) *io_options++ = 0; @@ -3221,8 +3243,8 @@ int tune2fs_main(int argc, char **argv) * Try the get/set fs label using ioctls before we even attempt * to open the file system. */ - if (L_flag || print_label) { - rc = handle_fslabel(L_flag); + if (opts[OPT_LABEL] || print_label) { + rc = handle_fslabel(opts[OPT_LABEL]); if (rc != -1) { #ifndef BUILD_AS_LIB exit(rc); @@ -3233,7 +3255,7 @@ int tune2fs_main(int argc, char **argv) } retry_open: - if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag) + if ((open_flag & EXT2_FLAG_RW) == 0 || force) open_flag |= EXT2_FLAG_SKIP_MMP; open_flag |= EXT2_FLAG_64BITS | EXT2_FLAG_THREADS | @@ -3276,7 +3298,7 @@ retry_open: } fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; - if (I_flag) { + if (opts[OPT_INODE_SIZE]) { /* * Check the inode size is right so we can issue an * error message and bail before setting up the tdb @@ -3378,7 +3400,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" /* Normally we only need to write out the superblock */ fs->flags |= EXT2_FLAG_SUPER_ONLY; - if (c_flag) { + if (opts[OPT_MAX_MOUNTCOUNT]) { if (max_mount_count == 65536) max_mount_count = EXT2_DFL_MAX_MNT_COUNT + (random() % EXT2_DFL_MAX_MNT_COUNT); @@ -3387,17 +3409,17 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" printf(_("Setting maximal mount count to %d\n"), max_mount_count); } - if (C_flag) { + if (opts[OPT_MOUNTCOUNT]) { sb->s_mnt_count = mount_count; ext2fs_mark_super_dirty(fs); printf(_("Setting current mount count to %d\n"), mount_count); } - if (e_flag) { + if (opts[OPT_ERROR_BEHAVIOR]) { sb->s_errors = errors; ext2fs_mark_super_dirty(fs); printf(_("Setting error behavior to %d\n"), errors); } - if (g_flag) { + if (opts[OPT_RESGID]) { if (sb->s_def_resgid != resgid) { sb->s_def_resgid = resgid; ext2fs_mark_super_dirty(fs); @@ -3406,7 +3428,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" printf(_("Reserved blocks gid already set to %lu\n"), resgid); } } - if (i_flag) { + if (opts[OPT_CHECKINTERVAL]) { if ((unsigned long long)interval >= (1ULL << 32)) { com_err(program_name, 0, _("interval between checks is too big (%lu)"), @@ -3419,7 +3441,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" printf(_("Setting interval between checks to %lu seconds\n"), interval); } - if (m_flag) { + if (opts[OPT_RESERVED_RATIO]) { ext2fs_r_blocks_count_set(sb, reserved_ratio * ext2fs_blocks_count(sb) / 100.0); ext2fs_mark_super_dirty(fs); @@ -3427,7 +3449,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" reserved_ratio, (unsigned long long) ext2fs_r_blocks_count(sb)); } - if (r_flag) { + if (opts[OPT_RESERVED_BLOCKS]) { if (reserved_blocks > ext2fs_blocks_count(sb)/2) { com_err(program_name, 0, _("reserved blocks count is too big (%llu)"), @@ -3440,7 +3462,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" printf(_("Setting reserved blocks count to %llu\n"), (unsigned long long) reserved_blocks); } - if (s_flag == 1) { + if (sparse_value == 1) { if (ext2fs_has_feature_sparse_super(sb)) { fputs(_("\nThe filesystem already has sparse " "superblocks.\n"), stderr); @@ -3459,24 +3481,24 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" _(please_fsck)); } } - if (s_flag == 0) { + if (sparse_value == 0) { fputs(_("\nClearing the sparse superblock flag not supported.\n"), stderr); rc = 1; goto closefs; } - if (T_flag) { + if (opts[OPT_CHECKTIME]) { ext2fs_set_tstamp(sb, s_lastcheck, last_check_time); ext2fs_mark_super_dirty(fs); printf(_("Setting time filesystem last checked to %s\n"), ctime(&last_check_time)); } - if (u_flag) { + if (opts[OPT_RESUID]) { sb->s_def_resuid = resuid; ext2fs_mark_super_dirty(fs); printf(_("Setting reserved blocks uid to %lu\n"), resuid); } - if (L_flag) { + if (opts[OPT_LABEL]) { if (strlen(new_label) > sizeof(sb->s_volume_name)) fputs(_("Warning: label too long, truncating.\n"), stderr); @@ -3485,7 +3507,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" sizeof(sb->s_volume_name)); ext2fs_mark_super_dirty(fs); } - if (M_flag) { + if (opts[OPT_LAST_MOUNTED]) { memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); strncpy((char *)sb->s_last_mounted, new_last_mounted, sizeof(sb->s_last_mounted)); @@ -3505,7 +3527,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" rc = parse_extended_opts(fs, extended_cmd); if (rc) goto closefs; - if (clear_mmp && !f_flag) { + if (clear_mmp && !force) { fputs(_("Error in using clear_mmp. " "It must be used with -f\n"), stderr); @@ -3541,7 +3563,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" } } - if (Q_flag) { + if (opts[OPT_QUOTA]) { if (mount_flags & (EXT2_MF_BUSY | EXT2_MF_MOUNTED)) { fputs(_("The quota feature may only be changed when " "the filesystem is unmounted and not in use.\n"), stderr); @@ -3553,7 +3575,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" goto closefs; } - if (U_flag) { + if (opts[OPT_UUID]) { int set_csum = 0; dgrp_t i; char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8))); @@ -3694,7 +3716,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" } } - if (I_flag) { + if (opts[OPT_INODE_SIZE]) { if (mount_flags & (EXT2_MF_BUSY | EXT2_MF_MOUNTED)) { fputs(_("The inode size may only be " "changed when the filesystem is " @@ -3740,7 +3762,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" } } - if (l_flag) + if (do_list_super) list_super(sb); if (stride_set) { sb->s_raid_stride = stride; -- 2.51.0