2 * tune2fs.c - Change the file system parameters on an ext2 file system
4 * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr>
5 * Laboratoire MASI, Institut Blaise Pascal
6 * Universite Pierre et Marie Curie (Paris VI)
8 * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
11 * This file may be redistributed under the terms of the GNU Public
19 * 93/10/31 - Added the -c option to change the maximal mount counts
20 * 93/12/14 - Added -l flag to list contents of superblock
21 * M.J.E. Mol (marcel@duteca.et.tudelft.nl)
22 * F.W. ten Wolde (franky@duteca.et.tudelft.nl)
23 * 93/12/29 - Added the -e option to change errors behavior
24 * 94/02/27 - Ported to use the ext2fs library
25 * 94/03/06 - Added the checks interval from Uwe Ohse (uwe@tirka.gun.de)
42 #include <sys/types.h>
44 #include "ext2fs/ext2_fs.h"
45 #include "ext2fs/ext2fs.h"
46 #include "et/com_err.h"
47 #include "uuid/uuid.h"
51 #include "get_device_by_label.h"
53 #include "../version.h"
54 #include "nls-enable.h"
56 const char * program_name = "tune2fs";
58 char * new_label, *new_last_mounted, *new_UUID;
59 static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
60 static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
61 static time_t last_check_time;
62 static int print_label;
63 static int max_mount_count, mount_count, mount_flags;
64 static unsigned long interval, reserved_ratio, reserved_blocks;
65 static unsigned long resgid, resuid;
66 static unsigned short errors;
68 static char *features_cmd;
69 static char *mntopts_cmd;
71 int journal_size, journal_flags;
74 static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
76 void do_findfs(int argc, char **argv);
78 static void usage(void)
81 _("Usage: %s [-c max-mounts-count] [-e errors-behavior] "
83 "\t[-i interval[d|m|w]] [-j] [-J journal-options]\n"
84 "\t[-l] [-s sparse-flag] [-m reserved-blocks-percent]\n"
85 "\t[-o [^]mount-options[,...]] [-r reserved-blocks-count]\n"
86 "\t[-u user] [-C mount-count] [-L volume-label] "
87 "[-M last-mounted-dir]\n"
88 "\t[-O [^]feature[,...]] [-T last-check-time] [-U UUID]"
89 " device\n"), program_name);
93 static __u32 ok_features[3] = {
94 EXT3_FEATURE_COMPAT_HAS_JOURNAL |
95 EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */
96 EXT2_FEATURE_INCOMPAT_FILETYPE, /* Incompat */
97 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */
101 * Remove an external journal from the filesystem
103 static void remove_journal_device(ext2_filsys fs)
108 journal_superblock_t *jsb;
111 int commit_remove_journal = 0;
114 commit_remove_journal = 1; /* force removal even if error */
116 uuid_unparse(fs->super->s_journal_uuid, buf);
117 journal_path = get_spec_by_uuid(buf);
121 ext2fs_find_block_device(fs->super->s_journal_dev);
126 retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
127 EXT2_FLAG_JOURNAL_DEV_OK, 0,
128 fs->blocksize, unix_io_manager, &jfs);
130 com_err(program_name, retval,
131 _("while trying to open external journal"));
132 goto no_valid_journal;
134 if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
135 fprintf(stderr, _("%s is not a journal device.\n"),
137 goto no_valid_journal;
140 /* Get the journal superblock */
141 if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) {
142 com_err(program_name, retval,
143 _("while reading journal superblock"));
144 goto no_valid_journal;
147 jsb = (journal_superblock_t *) buf;
148 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
149 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
150 fprintf(stderr, _("Journal superblock not found!\n"));
151 goto no_valid_journal;
154 /* Find the filesystem UUID */
155 nr_users = ntohl(jsb->s_nr_users);
156 for (i=0; i < nr_users; i++) {
157 if (memcmp(fs->super->s_uuid,
158 &jsb->s_users[i*16], 16) == 0)
163 _("Filesystem's UUID not found on journal device.\n"));
164 commit_remove_journal = 1;
165 goto no_valid_journal;
168 for (i=0; i < nr_users; i++)
169 memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16);
170 jsb->s_nr_users = htonl(nr_users);
172 /* Write back the journal superblock */
173 if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) {
174 com_err(program_name, retval,
175 "while writing journal superblock.");
176 goto no_valid_journal;
179 commit_remove_journal = 1;
182 if (commit_remove_journal == 0) {
183 fprintf(stderr, _("Journal NOT removed\n"));
186 fs->super->s_journal_dev = 0;
187 memset(fs->super->s_journal_uuid, 0,
188 sizeof(fs->super->s_journal_uuid));
189 ext2fs_mark_super_dirty(fs);
190 printf(_("Journal removed\n"));
194 /* Helper function for remove_journal_inode */
195 static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
196 int blockcnt, void *private)
202 ext2fs_unmark_block_bitmap(fs->block_map,block);
203 group = ext2fs_group_of_blk(fs, block);
204 fs->group_desc[group].bg_free_blocks_count++;
205 fs->super->s_free_blocks_count++;
210 * Remove the journal inode from the filesystem
212 static void remove_journal_inode(ext2_filsys fs)
214 struct ext2_inode inode;
216 ino_t ino = fs->super->s_journal_inum;
218 retval = ext2fs_read_inode(fs, ino, &inode);
220 com_err(program_name, retval,
221 _("while reading journal inode"));
224 if (ino == EXT2_JOURNAL_INO) {
225 retval = ext2fs_read_bitmaps(fs);
227 com_err(program_name, retval,
228 _("while reading bitmaps"));
231 retval = ext2fs_block_iterate(fs, ino, 0, NULL,
232 release_blocks_proc, NULL);
234 com_err(program_name, retval,
235 _("while clearing journal inode"));
238 memset(&inode, 0, sizeof(inode));
239 ext2fs_mark_bb_dirty(fs);
240 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
242 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
243 retval = ext2fs_write_inode(fs, ino, &inode);
245 com_err(program_name, retval,
246 _("while writing journal inode"));
249 fs->super->s_journal_inum = 0;
250 ext2fs_mark_super_dirty(fs);
254 * Update the default mount options
256 static void update_mntopts(ext2_filsys fs, char *mntopts)
258 struct ext2_super_block *sb= fs->super;
260 if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) {
261 fprintf(stderr, _("Invalid mount option set: %s\n"),
265 ext2fs_mark_super_dirty(fs);
269 * Update the feature set as provided by the user.
271 static void update_feature_set(ext2_filsys fs, char *features)
273 int sparse, old_sparse, filetype, old_filetype;
274 int journal, old_journal, dxdir, old_dxdir;
275 struct ext2_super_block *sb= fs->super;
277 old_sparse = sb->s_feature_ro_compat &
278 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
279 old_filetype = sb->s_feature_incompat &
280 EXT2_FEATURE_INCOMPAT_FILETYPE;
281 old_journal = sb->s_feature_compat &
282 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
283 old_dxdir = sb->s_feature_compat &
284 EXT2_FEATURE_COMPAT_DIR_INDEX;
285 if (e2p_edit_feature(features, &sb->s_feature_compat,
287 fprintf(stderr, _("Invalid filesystem option set: %s\n"),
291 sparse = sb->s_feature_ro_compat &
292 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
293 filetype = sb->s_feature_incompat &
294 EXT2_FEATURE_INCOMPAT_FILETYPE;
295 journal = sb->s_feature_compat &
296 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
297 dxdir = sb->s_feature_compat &
298 EXT2_FEATURE_COMPAT_DIR_INDEX;
299 if (old_journal && !journal) {
300 if ((mount_flags & EXT2_MF_MOUNTED) &&
301 !(mount_flags & EXT2_MF_READONLY)) {
303 _("The has_journal flag may only be "
304 "cleared when the filesystem is\n"
305 "unmounted or mounted "
309 if (sb->s_feature_incompat &
310 EXT3_FEATURE_INCOMPAT_RECOVER) {
312 _("The needs_recovery flag is set. "
313 "Please run e2fsck before clearing\n"
314 "the has_journal flag.\n"));
317 if (sb->s_journal_inum) {
318 remove_journal_inode(fs);
320 if (sb->s_journal_dev) {
321 remove_journal_device(fs);
324 if (journal && !old_journal) {
326 * If adding a journal flag, let the create journal
327 * code below handle creating setting the flag and
328 * creating the journal. We supply a default size if
333 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
335 if (dxdir && !old_dxdir) {
336 if (!sb->s_def_hash_version)
337 sb->s_def_hash_version = EXT2_HASH_TEA;
338 if (uuid_is_null((unsigned char *) sb->s_hash_seed))
339 uuid_generate((unsigned char *) sb->s_hash_seed);
342 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
343 (sb->s_feature_compat || sb->s_feature_ro_compat ||
344 sb->s_feature_incompat))
345 ext2fs_update_dynamic_rev(fs);
346 if ((sparse != old_sparse) ||
347 (filetype != old_filetype)) {
348 sb->s_state &= ~EXT2_VALID_FS;
349 printf("\n%s\n", _(please_fsck));
351 ext2fs_mark_super_dirty(fs);
355 * Add a journal to the filesystem.
357 static void add_journal(ext2_filsys fs)
359 unsigned long journal_blocks;
363 if (fs->super->s_feature_compat &
364 EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
365 fprintf(stderr, _("The filesystem already has a journal.\n"));
368 if (journal_device) {
369 check_plausibility(journal_device);
370 check_mount(journal_device, 0, _("journal"));
371 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
372 EXT2_FLAG_JOURNAL_DEV_OK, 0,
373 fs->blocksize, unix_io_manager, &jfs);
375 com_err(program_name, retval,
376 _("\n\twhile trying to open journal on %s\n"),
380 printf(_("Creating journal on device %s: "),
384 retval = ext2fs_add_journal_device(fs, jfs);
387 com_err (program_name, retval,
388 _("while adding filesystem to journal on %s"),
393 } else if (journal_size) {
394 printf(_("Creating journal inode: "));
396 journal_blocks = figure_journal_size(journal_size, fs);
398 retval = ext2fs_add_journal_inode(fs, journal_blocks,
401 fprintf(stderr, "\n");
402 com_err(program_name, retval,
403 _("\n\twhile trying to create journal file"));
408 * If the filesystem wasn't mounted, we need to force
409 * the block group descriptors out.
411 if ((mount_flags & EXT2_MF_MOUNTED) == 0)
412 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
414 print_check_message(fs);
419 free(journal_device);
424 static void parse_e2label_options(int argc, char ** argv)
426 if ((argc < 2) || (argc > 3)) {
427 fprintf(stderr, _("Usage: e2label device [newlabel]\n"));
430 device_name = argv[1];
432 open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK;
439 static time_t parse_time(char *str)
443 if (strcmp(str, "now") == 0) {
446 memset(&ts, 0, sizeof(ts));
447 strptime(optarg, "%Y%m%d%H%M%S", &ts);
448 if (ts.tm_mday == 0) {
449 com_err(program_name, 0,
450 _("Couldn't parse date/time specifier: %s"),
454 return (mktime(&ts));
457 static void parse_tune2fs_options(int argc, char **argv)
464 printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
465 while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:J:L:M:O:T:U:")) != EOF)
469 max_mount_count = strtol (optarg, &tmp, 0);
470 if (*tmp || max_mount_count > 16000) {
471 com_err (program_name, 0,
472 _("bad mounts count - %s"),
476 if (max_mount_count == 0)
477 max_mount_count = -1;
479 open_flag = EXT2_FLAG_RW;
482 mount_count = strtoul (optarg, &tmp, 0);
483 if (*tmp || mount_count > 16000) {
484 com_err (program_name, 0,
485 _("bad mounts count - %s"),
490 open_flag = EXT2_FLAG_RW;
493 if (strcmp (optarg, "continue") == 0)
494 errors = EXT2_ERRORS_CONTINUE;
495 else if (strcmp (optarg, "remount-ro") == 0)
496 errors = EXT2_ERRORS_RO;
497 else if (strcmp (optarg, "panic") == 0)
498 errors = EXT2_ERRORS_PANIC;
500 com_err (program_name, 0,
501 _("bad error behavior - %s"),
506 open_flag = EXT2_FLAG_RW;
508 case 'f': /* Force */
512 resgid = strtoul (optarg, &tmp, 0);
514 gr = getgrnam (optarg);
523 com_err (program_name, 0,
524 _("bad gid/group name - %s"),
529 open_flag = EXT2_FLAG_RW;
532 interval = strtoul (optarg, &tmp, 0);
545 case 'M': /* months! */
546 interval *= 86400 * 30;
550 case 'W': /* weeks */
551 interval *= 86400 * 7;
555 if (*tmp || interval > (365 * 86400)) {
556 com_err (program_name, 0,
557 _("bad interval - %s"), optarg);
561 open_flag = EXT2_FLAG_RW;
566 open_flag = EXT2_FLAG_RW;
569 parse_journal_opts(optarg);
570 open_flag = EXT2_FLAG_RW;
578 open_flag = EXT2_FLAG_RW |
579 EXT2_FLAG_JOURNAL_DEV_OK;
582 reserved_ratio = strtoul (optarg, &tmp, 0);
583 if (*tmp || reserved_ratio > 50) {
584 com_err (program_name, 0,
585 _("bad reserved block ratio - %s"),
590 open_flag = EXT2_FLAG_RW;
593 new_last_mounted = optarg;
595 open_flag = EXT2_FLAG_RW;
599 com_err (program_name, 0,
600 _("-o may only be specified once"));
603 mntopts_cmd = optarg;
604 open_flag = EXT2_FLAG_RW;
609 com_err (program_name, 0,
610 _("-O may only be specified once"));
613 features_cmd = optarg;
614 open_flag = EXT2_FLAG_RW;
617 reserved_blocks = strtoul (optarg, &tmp, 0);
619 com_err (program_name, 0,
620 _("bad reserved blocks count - %s"),
625 open_flag = EXT2_FLAG_RW;
628 s_flag = atoi(optarg);
629 open_flag = EXT2_FLAG_RW;
633 last_check_time = parse_time(optarg);
634 open_flag = EXT2_FLAG_RW;
637 resuid = strtoul (optarg, &tmp, 0);
639 pw = getpwnam (optarg);
648 com_err (program_name, 0,
649 _("bad uid/user name - %s"),
654 open_flag = EXT2_FLAG_RW;
659 open_flag = EXT2_FLAG_RW |
660 EXT2_FLAG_JOURNAL_DEV_OK;
665 if (optind < argc - 1 || optind == argc)
667 if (!open_flag && !l_flag)
669 device_name = argv[optind];
672 void do_findfs(int argc, char **argv)
677 (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) {
678 fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n");
681 dev = interpret_spec(argv[1]);
683 fprintf(stderr, "Filesystem matching %s not found\n",
692 int main (int argc, char ** argv)
696 struct ext2_super_block *sb;
699 setlocale(LC_MESSAGES, "");
700 setlocale(LC_CTYPE, "");
701 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
702 textdomain(NLS_CAT_NAME);
705 program_name = *argv;
706 initialize_ext2_error_table();
708 if (strcmp(get_progname(argv[0]), "findfs") == 0)
709 do_findfs(argc, argv);
710 if (strcmp(get_progname(argv[0]), "e2label") == 0)
711 parse_e2label_options(argc, argv);
713 parse_tune2fs_options(argc, argv);
715 retval = ext2fs_open (device_name, open_flag, 0, 0,
716 unix_io_manager, &fs);
718 com_err (program_name, retval, _("while trying to open %s"),
721 _("Couldn't find valid filesystem superblock.\n"));
726 /* For e2label emulation */
727 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
731 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
733 com_err("ext2fs_check_if_mount", retval,
734 _("while determining whether %s is mounted."),
738 /* Normally we only need to write out the superblock */
739 fs->flags |= EXT2_FLAG_SUPER_ONLY;
742 sb->s_max_mnt_count = max_mount_count;
743 ext2fs_mark_super_dirty(fs);
744 printf (_("Setting maximal mount count to %d\n"),
748 sb->s_mnt_count = mount_count;
749 ext2fs_mark_super_dirty(fs);
750 printf (_("Setting current mount count to %d\n"), mount_count);
753 sb->s_errors = errors;
754 ext2fs_mark_super_dirty(fs);
755 printf (_("Setting error behavior to %d\n"), errors);
758 sb->s_def_resgid = resgid;
759 ext2fs_mark_super_dirty(fs);
760 printf (_("Setting reserved blocks gid to %lu\n"), resgid);
763 sb->s_checkinterval = interval;
764 ext2fs_mark_super_dirty(fs);
765 printf (_("Setting interval between check %lu seconds\n"), interval);
768 sb->s_r_blocks_count = (sb->s_blocks_count / 100)
770 ext2fs_mark_super_dirty(fs);
771 printf (_("Setting reserved blocks percentage to %lu (%u blocks)\n"),
772 reserved_ratio, sb->s_r_blocks_count);
775 if (reserved_blocks >= sb->s_blocks_count) {
776 com_err (program_name, 0,
777 _("reserved blocks count is too big (%ul)"),
781 sb->s_r_blocks_count = reserved_blocks;
782 ext2fs_mark_super_dirty(fs);
783 printf (_("Setting reserved blocks count to %lu\n"),
787 if (sb->s_feature_ro_compat &
788 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
789 fprintf(stderr, _("\nThe filesystem already"
790 " has sparse superblocks.\n"));
792 sb->s_feature_ro_compat |=
793 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
794 sb->s_state &= ~EXT2_VALID_FS;
795 ext2fs_mark_super_dirty(fs);
796 printf(_("\nSparse superblock flag set. %s"),
801 if (!(sb->s_feature_ro_compat &
802 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
803 fprintf(stderr, _("\nThe filesystem already"
804 " has sparse superblocks disabled.\n"));
806 sb->s_feature_ro_compat &=
807 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
808 sb->s_state &= ~EXT2_VALID_FS;
809 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
810 ext2fs_mark_super_dirty(fs);
811 printf(_("\nSparse superblock flag cleared. %s"),
816 sb->s_lastcheck = last_check_time;
817 ext2fs_mark_super_dirty(fs);
818 printf(_("Setting time filesystem last checked to %s\n"),
819 ctime(&last_check_time));
822 sb->s_def_resuid = resuid;
823 ext2fs_mark_super_dirty(fs);
824 printf (_("Setting reserved blocks uid to %lu\n"), resuid);
827 if (strlen(new_label) > sizeof(sb->s_volume_name))
828 fprintf(stderr, _("Warning: label too "
829 "long, truncating.\n"));
830 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
831 strncpy(sb->s_volume_name, new_label,
832 sizeof(sb->s_volume_name));
833 ext2fs_mark_super_dirty(fs);
836 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
837 strncpy(sb->s_last_mounted, new_last_mounted,
838 sizeof(sb->s_last_mounted));
839 ext2fs_mark_super_dirty(fs);
842 update_mntopts(fs, mntopts_cmd);
844 update_feature_set(fs, features_cmd);
845 if (journal_size || journal_device)
849 if ((strcasecmp(new_UUID, "null") == 0) ||
850 (strcasecmp(new_UUID, "clear") == 0)) {
851 uuid_clear(sb->s_uuid);
852 } else if (strcasecmp(new_UUID, "time") == 0) {
853 uuid_generate_time(sb->s_uuid);
854 } else if (strcasecmp(new_UUID, "random") == 0) {
855 uuid_generate(sb->s_uuid);
856 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
857 com_err(program_name, 0, _("Invalid UUID format\n"));
860 ext2fs_mark_super_dirty(fs);
865 return (ext2fs_close (fs) ? 1 : 0);