X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=misc%2Ftune2fs.c;h=1e66204e9b8ed925c7f45385a629a722f91de3db;hb=9b2d5e912b98a4a22d8daab2004ae92bd4a2d2a3;hp=adbc1a9959c196812e86e3c3e5ba57445e73195a;hpb=63985320384bf143eaac9857af424800d9867a1a;p=tools%2Fe2fsprogs.git diff --git a/misc/tune2fs.c b/misc/tune2fs.c index adbc1a9..1e66204 100644 --- a/misc/tune2fs.c +++ b/misc/tune2fs.c @@ -1,12 +1,11 @@ /* - * tune2fs.c - Change the file system parameters on - * an unmounted second extended file system + * tune2fs.c - Change the file system parameters on an ext2 file system * * Copyright (C) 1992, 1993, 1994 Remy Card * Laboratoire MASI, Institut Blaise Pascal * Universite Pierre et Marie Curie (Paris VI) * - * Copyright 1995, 1996, 1997 by Theodore Ts'o. + * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU Public @@ -26,6 +25,8 @@ * 94/03/06 - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de) */ +#define _XOPEN_SOURCE /* for inclusion of strptime() */ +#define _BSD_SOURCE /* for inclusion of strcasecmp() */ #include #include #ifdef HAVE_GETOPT_H @@ -42,61 +43,245 @@ extern int optind; #include #include -#include - +#include "ext2fs/ext2_fs.h" #include "ext2fs/ext2fs.h" #include "et/com_err.h" #include "uuid/uuid.h" #include "e2p/e2p.h" +#include "jfs_user.h" #include "util.h" +#include "blkid/blkid.h" #include "../version.h" #include "nls-enable.h" const char * program_name = "tune2fs"; char * device_name; -char * new_label, *new_last_mounted, *new_UUID, *journal_opts; -static int c_flag, C_flag, e_flag, g_flag, i_flag, l_flag, L_flag; -static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag; +char * new_label, *new_last_mounted, *new_UUID; +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 resgid, resuid; static unsigned short errors; +static int open_flag; +static char *features_cmd; +static char *mntopts_cmd; int journal_size, journal_flags; char *journal_device; static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n"); +void do_findfs(int argc, char **argv); + static void usage(void) { fprintf(stderr, _("Usage: %s [-c max-mounts-count] [-e errors-behavior] " "[-g group]\n" - "\t[-i interval[d|m|w]] [-j journal-options]\n" - "\t[-l] [-s sparse-flag] [-m reserved-blocks-percent]\n" - "\t[-r reserved-blocks-count] [-u user] [-C mount-count]\n" - "\t[-L volume-label] [-M last-mounted-dir] [-U UUID]\n" - "\t[-O [^]feature[,...]] 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] " + "[-M last-mounted-dir]\n" + "\t[-O [^]feature[,...]] [-T last-check-time] [-U UUID]" + " device\n"), program_name); exit (1); } static __u32 ok_features[3] = { - EXT3_FEATURE_COMPAT_HAS_JOURNAL, /* Compat */ + EXT3_FEATURE_COMPAT_HAS_JOURNAL | + EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */ EXT2_FEATURE_INCOMPAT_FILETYPE, /* Incompat */ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */ }; /* + * Remove an external journal from the filesystem + */ +static void remove_journal_device(ext2_filsys fs) +{ + char *journal_path; + ext2_filsys jfs; + char buf[1024]; + journal_superblock_t *jsb; + int i, nr_users; + errcode_t retval; + int commit_remove_journal = 0; + io_manager io_ptr; + + if (f_flag) + commit_remove_journal = 1; /* force removal even if error */ + + uuid_unparse(fs->super->s_journal_uuid, buf); + journal_path = blkid_get_devname(NULL, "UUID", buf); + + if (!journal_path) { + journal_path = + ext2fs_find_block_device(fs->super->s_journal_dev); + if (!journal_path) + return; + } + +#ifdef CONFIG_TESTIO_DEBUG + io_ptr = test_io_manager; + test_io_backing_manager = unix_io_manager; +#else + io_ptr = unix_io_manager; +#endif + retval = ext2fs_open(journal_path, EXT2_FLAG_RW| + EXT2_FLAG_JOURNAL_DEV_OK, 0, + fs->blocksize, io_ptr, &jfs); + if (retval) { + com_err(program_name, retval, + _("while trying to open external journal")); + goto no_valid_journal; + } + if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { + fprintf(stderr, _("%s is not a journal device.\n"), + journal_path); + goto no_valid_journal; + } + + /* Get the journal superblock */ + if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) { + com_err(program_name, retval, + _("while reading journal superblock")); + goto no_valid_journal; + } + + jsb = (journal_superblock_t *) buf; + if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || + (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) { + fputs(_("Journal superblock not found!\n"), stderr); + goto no_valid_journal; + } + + /* Find the filesystem UUID */ + nr_users = ntohl(jsb->s_nr_users); + for (i=0; i < nr_users; i++) { + if (memcmp(fs->super->s_uuid, + &jsb->s_users[i*16], 16) == 0) + break; + } + if (i >= nr_users) { + fputs(_("Filesystem's UUID not found on journal device.\n"), + stderr); + commit_remove_journal = 1; + goto no_valid_journal; + } + nr_users--; + for (i=0; i < nr_users; i++) + memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16); + jsb->s_nr_users = htonl(nr_users); + + /* Write back the journal superblock */ + if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) { + com_err(program_name, retval, + "while writing journal superblock."); + goto no_valid_journal; + } + + commit_remove_journal = 1; + +no_valid_journal: + if (commit_remove_journal == 0) { + fputs(_("Journal NOT removed\n"), stderr); + exit(1); + } + fs->super->s_journal_dev = 0; + uuid_clear(fs->super->s_journal_uuid); + ext2fs_mark_super_dirty(fs); + fputs(_("Journal removed\n"), stdout); + free(journal_path); +} + +/* Helper function for remove_journal_inode */ +static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr, + int blockcnt EXT2FS_ATTR((unused)), + void *private EXT2FS_ATTR((unused))) +{ + blk_t block; + int group; + + block = *blocknr; + ext2fs_unmark_block_bitmap(fs->block_map,block); + group = ext2fs_group_of_blk(fs, block); + fs->group_desc[group].bg_free_blocks_count++; + fs->super->s_free_blocks_count++; + return 0; +} + +/* + * Remove the journal inode from the filesystem + */ +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, + _("while reading journal inode")); + exit(1); + } + if (ino == EXT2_JOURNAL_INO) { + retval = ext2fs_read_bitmaps(fs); + if (retval) { + com_err(program_name, retval, + _("while reading bitmaps")); + exit(1); + } + retval = ext2fs_block_iterate(fs, ino, 0, NULL, + release_blocks_proc, NULL); + if (retval) { + com_err(program_name, retval, + _("while clearing journal inode")); + exit(1); + } + memset(&inode, 0, sizeof(inode)); + ext2fs_mark_bb_dirty(fs); + fs->flags &= ~EXT2_FLAG_SUPER_ONLY; + } else + inode.i_flags &= ~EXT2_IMMUTABLE_FL; + retval = ext2fs_write_inode(fs, ino, &inode); + if (retval) { + com_err(program_name, retval, + _("while writing journal inode")); + exit(1); + } + fs->super->s_journal_inum = 0; + ext2fs_mark_super_dirty(fs); +} + +/* + * Update the default mount options + */ +static void update_mntopts(ext2_filsys fs, char *mntopts) +{ + struct ext2_super_block *sb= fs->super; + + if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) { + fprintf(stderr, _("Invalid mount option set: %s\n"), + mntopts); + exit(1); + } + ext2fs_mark_super_dirty(fs); +} + +/* * Update the feature set as provided by the user. */ -static void update_feature_set(ext2_filsys fs, char *features_cmd) +static void update_feature_set(ext2_filsys fs, char *features) { int sparse, old_sparse, filetype, old_filetype; - int journal, old_journal; - struct ext2_inode inode; + int journal, old_journal, dxdir, old_dxdir; struct ext2_super_block *sb= fs->super; - errcode_t retval; old_sparse = sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; @@ -104,10 +289,12 @@ static void update_feature_set(ext2_filsys fs, char *features_cmd) EXT2_FEATURE_INCOMPAT_FILETYPE; old_journal = sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL; - if (e2p_edit_feature(features_cmd, &sb->s_feature_compat, + old_dxdir = sb->s_feature_compat & + EXT2_FEATURE_COMPAT_DIR_INDEX; + if (e2p_edit_feature(features, &sb->s_feature_compat, ok_features)) { fprintf(stderr, _("Invalid filesystem option set: %s\n"), - features_cmd); + features); exit(1); } sparse = sb->s_feature_ro_compat & @@ -116,43 +303,29 @@ static void update_feature_set(ext2_filsys fs, char *features_cmd) EXT2_FEATURE_INCOMPAT_FILETYPE; journal = sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL; + dxdir = sb->s_feature_compat & + EXT2_FEATURE_COMPAT_DIR_INDEX; if (old_journal && !journal) { if ((mount_flags & EXT2_MF_MOUNTED) && !(mount_flags & EXT2_MF_READONLY)) { - fprintf(stderr, - _("The HAS_JOURNAL flag may only be " - "cleared when the filesystem is\n" - "unmounted or mounted " - "read-only.\n")); + fputs(_("The has_journal flag may only be " + "cleared when the filesystem is\n" + "unmounted or mounted " + "read-only.\n"), stderr); exit(1); } if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { - fprintf(stderr, - _("The NEEDS_RECOVERY flag is set. " - "Please run e2fsck before clearing\n" - "the HAS_JOURNAL flag.\n")); + fputs(_("The needs_recovery flag is set. " + "Please run e2fsck before clearing\n" + "the has_journal flag.\n"), stderr); exit(1); } - /* - * Remove the immutable flag on the journal inode - */ if (sb->s_journal_inum) { - retval = ext2fs_read_inode(fs, sb->s_journal_inum, - &inode); - if (retval) { - com_err(program_name, retval, - "while reading journal inode"); - exit(1); - } - inode.i_flags &= ~EXT2_IMMUTABLE_FL; - retval = ext2fs_write_inode(fs, sb->s_journal_inum, - &inode); - if (retval) { - com_err(program_name, retval, - "while write journal inode"); - exit(1); - } + remove_journal_inode(fs); + } + if (sb->s_journal_dev) { + remove_journal_device(fs); } } if (journal && !old_journal) { @@ -162,19 +335,23 @@ static void update_feature_set(ext2_filsys fs, char *features_cmd) * creating the journal. We supply a default size if * necessary. */ - if (!journal_opts) - journal_opts = "size=16"; - sb->s_feature_compat &=~EXT3_FEATURE_COMPAT_HAS_JOURNAL; - journal = old_journal; + if (!journal_size) + journal_size = -1; + sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; } - + if (dxdir && !old_dxdir) { + if (!sb->s_def_hash_version) + sb->s_def_hash_version = EXT2_HASH_TEA; + if (uuid_is_null((unsigned char *) sb->s_hash_seed)) + uuid_generate((unsigned char *) sb->s_hash_seed); + } + if (sb->s_rev_level == EXT2_GOOD_OLD_REV && (sb->s_feature_compat || sb->s_feature_ro_compat || sb->s_feature_incompat)) ext2fs_update_dynamic_rev(fs); if ((sparse != old_sparse) || - (filetype != old_filetype) || - (journal != old_journal)) { + (filetype != old_filetype)) { sb->s_state &= ~EXT2_VALID_FS; printf("\n%s\n", _(please_fsck)); } @@ -188,44 +365,59 @@ static void add_journal(ext2_filsys fs) { unsigned long journal_blocks; errcode_t retval; + ext2_filsys jfs; + io_manager io_ptr; if (fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) { - fprintf(stderr, _("The filesystem already has a journal.\n")); - exit(1); + fputs(_("The filesystem already has a journal.\n"), stderr); + goto err; } - parse_journal_opts(journal_opts); - journal_blocks = journal_size * 1024 / (fs->blocksize / 1024); if (journal_device) { 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; +#endif + retval = ext2fs_open(journal_device, EXT2_FLAG_RW| + EXT2_FLAG_JOURNAL_DEV_OK, 0, + fs->blocksize, io_ptr, &jfs); + if (retval) { + com_err(program_name, retval, + _("\n\twhile trying to open journal on %s\n"), + journal_device); + goto err; + } printf(_("Creating journal on device %s: "), journal_device); - retval = ext2fs_add_journal_device(fs, journal_device, - journal_blocks, - journal_flags); + fflush(stdout); + + retval = ext2fs_add_journal_device(fs, jfs); + ext2fs_close(jfs); if (retval) { com_err (program_name, retval, - _("while trying to create journal on device %s"), + _("while adding filesystem to journal on %s"), journal_device); - exit(1); + goto err; } - printf(_("done\n")); + fputs(_("done\n"), stdout); } else if (journal_size) { - errcode_t retval; - int mount_flags; - - printf(_("Creating journal inode: ")); + fputs(_("Creating journal inode: "), stdout); fflush(stdout); + journal_blocks = figure_journal_size(journal_size, fs); + retval = ext2fs_add_journal_inode(fs, journal_blocks, journal_flags); if (retval) { - printf("\n"); + fprintf(stderr, "\n"); com_err(program_name, retval, - _("while trying to create journal")); + _("\n\twhile trying to create journal file")); exit(1); - } - printf(_("done\n")); + } else + fputs(_("done\n"), stdout); /* * If the filesystem wasn't mounted, we need to force * the block group descriptors out. @@ -233,34 +425,74 @@ static void add_journal(ext2_filsys fs) if ((mount_flags & EXT2_MF_MOUNTED) == 0) fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } + print_check_message(fs); + return; + +err: + if (journal_device) + free(journal_device); + exit(1); } +static void parse_e2label_options(int argc, char ** argv) +{ + if ((argc < 2) || (argc > 3)) { + fputs(_("Usage: e2label device [newlabel]\n"), stderr); + exit(1); + } + device_name = blkid_get_devname(NULL, argv[1], NULL); + if (!device_name) { + com_err("e2label", 0, _("Unable to resolve '%s'"), + argv[1]); + exit(1); + } + if (argc == 3) { + open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK; + L_flag = 1; + new_label = argv[2]; + } else + print_label++; +} -int main (int argc, char ** argv) +static time_t parse_time(char *str) +{ + struct tm ts; + + if (strcmp(str, "now") == 0) { + return (time(0)); + } + memset(&ts, 0, sizeof(ts)); +#ifdef HAVE_STRPTIME + strptime(optarg, "%Y%m%d%H%M%S", &ts); +#else + sscanf(optarg, "%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; + if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 || + ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 || + ts.tm_min > 59 || ts.tm_sec > 61) + ts.tm_mday = 0; +#endif + if (ts.tm_mday == 0) { + com_err(program_name, 0, + _("Couldn't parse date/time specifier: %s"), + str); + usage(); + } + return (mktime(&ts)); +} + +static void parse_tune2fs_options(int argc, char **argv) { int c; char * tmp; - errcode_t retval; - ext2_filsys fs; - struct ext2_super_block *sb; struct group * gr; struct passwd * pw; - int open_flag = 0; - char *features_cmd = 0; -#ifdef ENABLE_NLS - setlocale(LC_MESSAGES, ""); - bindtextdomain(NLS_CAT_NAME, LOCALEDIR); - textdomain(NLS_CAT_NAME); -#endif - fprintf (stderr, _("tune2fs %s, %s for EXT2 FS %s, %s\n"), - E2FSPROGS_VERSION, E2FSPROGS_DATE, - EXT2FS_VERSION, EXT2FS_DATE); - if (argc && *argv) - program_name = *argv; - initialize_ext2_error_table(); - while ((c = getopt (argc, argv, "c:e:g:i:j:lm:r:s:u:C:L:M:O:U:")) != EOF) + 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) switch (c) { case 'c': @@ -271,6 +503,8 @@ int main (int argc, char ** argv) optarg); usage(); } + if (max_mount_count == 0) + max_mount_count = -1; c_flag = 1; open_flag = EXT2_FLAG_RW; break; @@ -301,6 +535,9 @@ int main (int argc, char ** argv) e_flag = 1; open_flag = EXT2_FLAG_RW; break; + case 'f': /* Force */ + f_flag = 1; + break; case 'g': resgid = strtoul (optarg, &tmp, 0); if (*tmp) { @@ -353,17 +590,23 @@ int main (int argc, char ** argv) i_flag = 1; open_flag = EXT2_FLAG_RW; break; - case 'l': - l_flag = 1; - break; case 'j': - journal_opts = optarg; + if (!journal_size) + journal_size = -1; + open_flag = EXT2_FLAG_RW; + break; + case 'J': + parse_journal_opts(optarg); open_flag = EXT2_FLAG_RW; break; + case 'l': + l_flag = 1; + break; 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); @@ -381,7 +624,22 @@ int main (int argc, char ** argv) M_flag = 1; open_flag = EXT2_FLAG_RW; break; + case 'o': + if (mntopts_cmd) { + com_err (program_name, 0, + _("-o may only be specified once")); + usage(); + } + mntopts_cmd = optarg; + open_flag = EXT2_FLAG_RW; + break; + case 'O': + if (features_cmd) { + com_err (program_name, 0, + _("-O may only be specified once")); + usage(); + } features_cmd = optarg; open_flag = EXT2_FLAG_RW; break; @@ -400,6 +658,11 @@ int main (int argc, char ** argv) s_flag = atoi(optarg); open_flag = EXT2_FLAG_RW; break; + case 'T': + T_flag = 1; + last_check_time = parse_time(optarg); + open_flag = EXT2_FLAG_RW; + break; case 'u': resuid = strtoul (optarg, &tmp, 0); if (*tmp) { @@ -423,7 +686,8 @@ int main (int argc, char ** argv) case 'U': new_UUID = optarg; U_flag = 1; - open_flag = EXT2_FLAG_RW; + open_flag = EXT2_FLAG_RW | + EXT2_FLAG_JOURNAL_DEV_OK; break; default: usage(); @@ -432,23 +696,86 @@ int main (int argc, char ** argv) usage(); if (!open_flag && !l_flag) usage(); - device_name = argv[optind]; - retval = ext2fs_open (device_name, open_flag, 0, 0, - unix_io_manager, &fs); + device_name = blkid_get_devname(NULL, argv[optind], NULL); + if (!device_name) { + com_err("tune2fs", 0, _("Unable to resolve '%s'"), + argv[optind]); + exit(1); + } +} + +void do_findfs(int argc, char **argv) +{ + char *dev; + + if ((argc != 2) || + (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) { + fprintf(stderr, "Usage: findfs LABEL=