* 94/03/06 - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de)
*/
+#define _XOPEN_SOURCE 500 /* for inclusion of strptime() */
+#define _BSD_SOURCE /* for inclusion of strcasecmp() */
#include <fcntl.h>
#include <grp.h>
#ifdef HAVE_GETOPT_H
#include "../version.h"
#include "nls-enable.h"
+/*
+ * Tune2fs supports these features in addition to the standard features.
+ */
+#define EXT2_TUNE2FS_INCOMPAT (EXT3_FEATURE_INCOMPAT_EXTENTS)
+#define EXT2_TUNE2FS_RO_COMPAT (EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)
+
+
const char * program_name = "tune2fs";
char * device_name;
char * new_label, *new_last_mounted, *new_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, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
static time_t last_check_time;
static int print_label;
static int max_mount_count, mount_count, mount_flags;
-static unsigned long interval, reserved_ratio, reserved_blocks;
+static unsigned long interval, reserved_blocks;
+static double reserved_ratio;
static unsigned long resgid, resuid;
static unsigned short errors;
static int open_flag;
static char *features_cmd;
static char *mntopts_cmd;
+static char *extended_cmd;
int journal_size, journal_flags;
char *journal_device;
static void usage(void)
{
fprintf(stderr,
- _("Usage: %s [-c max-mounts-count] [-e errors-behavior] "
+ _("Usage: %s [-c max_mounts_count] [-e errors_behavior] "
"[-g group]\n"
- "\t[-i interval[d|m|w]] [-j] [-J journal-options]\n"
- "\t[-l] [-s sparse-flag] [-m reserved-blocks-percent]\n"
- "\t[-o [^]mount-options[,...]] [-r reserved-blocks-count]\n"
- "\t[-u user] [-C mount-count] [-L volume-label] "
- "[-M last-mounted-dir]\n"
- "\t[-O [^]feature[,...]] [-T last-check-time] [-U UUID]"
- " device\n"), program_name);
+ "\t[-i interval[d|m|w]] [-j] [-J journal_options]\n"
+ "\t[-l] [-s sparse_flag] [-m reserved_blocks_percent]\n"
+ "\t[-o [^]mount_options[,...]] [-r reserved_blocks_count]\n"
+ "\t[-u user] [-C mount_count] [-L volume_label]\n"
+ "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n"
+ "\t[-E extended-option[,...]] [-T last_check_time] "
+ "[-U UUID] device\n"), program_name);
exit (1);
}
int sparse, old_sparse, filetype, old_filetype;
int journal, old_journal, dxdir, old_dxdir;
struct ext2_super_block *sb= fs->super;
+ __u32 old_compat, old_incompat, old_ro_compat;
+
+ old_compat = sb->s_feature_compat;
+ old_ro_compat = sb->s_feature_ro_compat;
+ old_incompat = sb->s_feature_incompat;
old_sparse = sb->s_feature_ro_compat &
EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
sb->s_state &= ~EXT2_VALID_FS;
printf("\n%s\n", _(please_fsck));
}
- ext2fs_mark_super_dirty(fs);
+ if ((old_compat != sb->s_feature_compat) ||
+ (old_ro_compat != sb->s_feature_ro_compat) ||
+ (old_incompat != sb->s_feature_incompat))
+ ext2fs_mark_super_dirty(fs);
}
/*
fputs(_("Usage: e2label device [newlabel]\n"), stderr);
exit(1);
}
+ io_options = strchr(argv[1], '?');
+ if (io_options)
+ *io_options++ = 0;
device_name = blkid_get_devname(NULL, argv[1], NULL);
if (!device_name) {
com_err("e2label", 0, _("Unable to resolve '%s'"),
argv[1]);
exit(1);
}
+ open_flag = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_JOURNAL_DEV_OK;
if (argc == 3) {
- open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK;
+ open_flag |= EXT2_FLAG_RW;
L_flag = 1;
new_label = argv[2];
} else
}
memset(&ts, 0, sizeof(ts));
#ifdef HAVE_STRPTIME
- strptime(optarg, "%Y%m%d%H%M%S", &ts);
+ strptime(str, "%Y%m%d%H%M%S", &ts);
#else
- sscanf(optarg, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
+ sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
&ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
ts.tm_year -= 1900;
ts.tm_mon -= 1;
struct group * gr;
struct passwd * pw;
+ open_flag = EXT2_FLAG_SOFTSUPP_FEATURES;
+
printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
- while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:J:L:M:O:T:U:")) != EOF)
+ while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:J:L:M:O:T:U:")) != EOF)
switch (c)
{
case 'c':
e_flag = 1;
open_flag = EXT2_FLAG_RW;
break;
+ case 'E':
+ extended_cmd = optarg;
+ open_flag |= EXT2_FLAG_RW;
+ break;
case 'f': /* Force */
f_flag = 1;
break;
tmp++;
break;
}
- if (*tmp || interval > (365 * 86400)) {
+ if (*tmp) {
com_err (program_name, 0,
_("bad interval - %s"), optarg);
usage();
case 'L':
new_label = optarg;
L_flag = 1;
- open_flag = EXT2_FLAG_RW |
+ open_flag |= EXT2_FLAG_RW |
EXT2_FLAG_JOURNAL_DEV_OK;
break;
case 'm':
- reserved_ratio = strtoul (optarg, &tmp, 0);
+ reserved_ratio = strtod(optarg, &tmp);
if (*tmp || reserved_ratio > 50) {
com_err (program_name, 0,
_("bad reserved block ratio - %s"),
usage();
if (!open_flag && !l_flag)
usage();
+ io_options = strchr(argv[optind], '?');
+ if (io_options)
+ *io_options++ = 0;
device_name = blkid_get_devname(NULL, argv[optind], NULL);
if (!device_name) {
com_err("tune2fs", 0, _("Unable to resolve '%s'"),
exit(0);
}
+/*
+ * Note! If any extended options are incompatible with the
+ * intersection of the SOFTSUPP features and those features explicitly
+ * enabled for tune2fs, there needs to be an explicit test for them
+ * here.
+ */
+static void parse_extended_opts(ext2_filsys fs, const char *opts)
+{
+ char *buf, *token, *next, *p, *arg;
+ int len;
+ int r_usage = 0;
+
+ len = strlen(opts);
+ buf = malloc(len+1);
+ if (!buf) {
+ fprintf(stderr,
+ _("Couldn't allocate memory to parse options!\n"));
+ exit(1);
+ }
+ strcpy(buf, opts);
+ for (token = buf; token && *token; token = next) {
+ p = strchr(token, ',');
+ next = 0;
+ if (p) {
+ *p = 0;
+ next = p+1;
+ }
+ arg = strchr(token, '=');
+ if (arg) {
+ *arg = 0;
+ arg++;
+ }
+ if (!strcmp(token, "test_fs")) {
+ fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
+ printf("Setting test filesystem flag\n");
+ ext2fs_mark_super_dirty(fs);
+ } else if (!strcmp(token, "^test_fs")) {
+ fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS;
+ printf("Clearing test filesystem flag\n");
+ ext2fs_mark_super_dirty(fs);
+ } else
+ r_usage++;
+ }
+ if (r_usage) {
+ fprintf(stderr, _("\nBad options specified.\n\n"
+ "Extended options are separated by commas, "
+ "and may take an argument which\n"
+ "\tis set off by an equals ('=') sign.\n\n"
+ "Valid extended options are:\n"
+ "\ttest_fs\n"
+ "\t^test_fs\n"));
+ free(buf);
+ exit(1);
+ }
+ free(buf);
+}
+
int main (int argc, char ** argv)
{
#endif
if (argc && *argv)
program_name = *argv;
- initialize_ext2_error_table();
+ add_error_table(&et_ext2_error_table);
if (strcmp(get_progname(argv[0]), "findfs") == 0)
do_findfs(argc, argv);
#else
io_ptr = unix_io_manager;
#endif
- retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs);
+ 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);
exit(1);
}
sb = fs->super;
+ fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
+ if ((sb->s_feature_incompat & !EXT2_TUNE2FS_INCOMPAT) ||
+ (sb->s_feature_ro_compat & !EXT2_TUNE2FS_RO_COMPAT)) {
+ fprintf(stderr,
+ _("Filesystem %s has unsupported features enabled.\n"),
+ device_name);
+ exit(1);
+ }
if (print_label) {
/* For e2label emulation */
printf("%.*s\n", (int) sizeof(sb->s_volume_name),
sb->s_volume_name);
+ remove_error_table(&et_ext2_error_table);
exit(0);
}
retval = ext2fs_check_if_mounted(device_name, &mount_flags);
if (i_flag) {
sb->s_checkinterval = interval;
ext2fs_mark_super_dirty(fs);
- printf (_("Setting interval between check %lu seconds\n"), interval);
+ printf (_("Setting interval between checks to %lu seconds\n"), interval);
}
if (m_flag) {
- sb->s_r_blocks_count = (sb->s_blocks_count / 100)
- * reserved_ratio;
+ sb->s_r_blocks_count = e2p_percent(reserved_ratio,
+ sb->s_blocks_count);
ext2fs_mark_super_dirty(fs);
- printf (_("Setting reserved blocks percentage to %lu (%u blocks)\n"),
+ printf (_("Setting reserved blocks percentage to %g%% (%u blocks)\n"),
reserved_ratio, sb->s_r_blocks_count);
}
if (r_flag) {
- if (reserved_blocks >= sb->s_blocks_count) {
+ if (reserved_blocks >= sb->s_blocks_count/2) {
com_err (program_name, 0,
_("reserved blocks count is too big (%lu)"),
reserved_blocks);
update_mntopts(fs, mntopts_cmd);
if (features_cmd)
update_feature_set(fs, features_cmd);
+ if (extended_cmd)
+ parse_extended_opts(fs, extended_cmd);
if (journal_size || journal_device)
add_journal(fs);
if (l_flag)
list_super (sb);
+ remove_error_table(&et_ext2_error_table);
return (ext2fs_close (fs) ? 1 : 0);
}