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;
61 static int print_label;
62 static int max_mount_count, mount_count, mount_flags;
63 static unsigned long interval, reserved_ratio, reserved_blocks;
64 static unsigned long resgid, resuid;
65 static unsigned short errors;
67 static char *features_cmd;
69 int journal_size, journal_flags;
72 static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
74 static void usage(void)
77 _("Usage: %s [-c max-mounts-count] [-e errors-behavior] "
79 "\t[-i interval[d|m|w]] [-j] [-J journal-options]\n"
80 "\t[-l] [-s sparse-flag] [-m reserved-blocks-percent]\n"
81 "\t[-r reserved-blocks-count] [-u user] [-C mount-count]\n"
82 "\t[-L volume-label] [-M last-mounted-dir] [-U UUID]\n"
83 "\t[-O [^]feature[,...]] device\n"), program_name);
87 static __u32 ok_features[3] = {
88 EXT3_FEATURE_COMPAT_HAS_JOURNAL, /* Compat */
89 EXT2_FEATURE_INCOMPAT_FILETYPE, /* Incompat */
90 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */
94 * Remove an external journal from the filesystem
96 static void remove_journal_device(ext2_filsys fs)
101 journal_superblock_t *jsb;
104 int commit_remove_journal = 0;
107 commit_remove_journal = 1; /* force removal even if error */
109 uuid_unparse(fs->super->s_journal_uuid, buf);
110 journal_device = get_spec_by_uuid(buf);
112 if (!journal_device) {
114 ext2fs_find_block_device(fs->super->s_journal_dev);
119 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
120 EXT2_FLAG_JOURNAL_DEV_OK, 0,
121 fs->blocksize, unix_io_manager, &jfs);
123 com_err(program_name, retval,
124 _("while trying to open external journal"));
125 goto no_valid_journal;
127 if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
128 fprintf(stderr, _("%s is not a journal device.\n"),
130 goto no_valid_journal;
133 /* Get the journal superblock */
134 if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) {
135 com_err(program_name, retval,
136 _("while reading journal superblock"));
137 goto no_valid_journal;
140 jsb = (journal_superblock_t *) buf;
141 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
142 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
143 fprintf(stderr, _("Journal superblock not found!\n"));
144 goto no_valid_journal;
147 /* Find the filesystem UUID */
148 nr_users = ntohl(jsb->s_nr_users);
149 for (i=0; i < nr_users; i++) {
150 if (memcmp(fs->super->s_uuid,
151 &jsb->s_users[i*16], 16) == 0)
156 _("Filesystem's UUID not found on journal device.\n"));
157 commit_remove_journal = 1;
158 goto no_valid_journal;
161 for (i=0; i < nr_users; i++)
162 memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16);
163 jsb->s_nr_users = htonl(nr_users);
165 /* Write back the journal superblock */
166 if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) {
167 com_err(program_name, retval,
168 "while writing journal superblock.");
169 goto no_valid_journal;
172 commit_remove_journal = 1;
175 if (commit_remove_journal == 0) {
176 fprintf(stderr, _("Journal NOT removed\n"));
179 fs->super->s_journal_dev = 0;
180 memset(fs->super->s_journal_uuid, 0,
181 sizeof(fs->super->s_journal_uuid));
182 ext2fs_mark_super_dirty(fs);
183 printf(_("Journal removed\n"));
184 free(journal_device);
187 /* Helper function for remove_journal_inode */
188 static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
189 int blockcnt, void *private)
195 ext2fs_unmark_block_bitmap(fs->block_map,block);
196 group = ext2fs_group_of_blk(fs, block);
197 fs->group_desc[group].bg_free_blocks_count++;
198 fs->super->s_free_blocks_count++;
203 * Remove the journal inode from the filesystem
205 static void remove_journal_inode(ext2_filsys fs)
207 struct ext2_inode inode;
209 ino_t ino = fs->super->s_journal_inum;
212 retval = ext2fs_read_inode(fs, ino, &inode);
214 com_err(program_name, retval,
215 _("while reading journal inode"));
218 if (ino == EXT2_JOURNAL_INO) {
219 retval = ext2fs_read_bitmaps(fs);
221 com_err(program_name, retval,
222 _("while reading bitmaps"));
225 retval = ext2fs_block_iterate(fs, ino, 0, NULL,
226 release_blocks_proc, NULL);
228 com_err(program_name, retval,
229 _("while clearing journal inode"));
232 memset(&inode, 0, sizeof(inode));
233 ext2fs_mark_bb_dirty(fs);
234 group = ext2fs_group_of_ino(fs, ino);
235 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
237 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
238 retval = ext2fs_write_inode(fs, ino, &inode);
240 com_err(program_name, retval,
241 _("while writing journal inode"));
244 fs->super->s_journal_inum = 0;
245 ext2fs_mark_super_dirty(fs);
249 * Update the feature set as provided by the user.
251 static void update_feature_set(ext2_filsys fs, char *features)
253 int sparse, old_sparse, filetype, old_filetype;
254 int journal, old_journal;
255 struct ext2_inode inode;
256 struct ext2_super_block *sb= fs->super;
259 old_sparse = sb->s_feature_ro_compat &
260 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
261 old_filetype = sb->s_feature_incompat &
262 EXT2_FEATURE_INCOMPAT_FILETYPE;
263 old_journal = sb->s_feature_compat &
264 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
265 if (e2p_edit_feature(features, &sb->s_feature_compat,
267 fprintf(stderr, _("Invalid filesystem option set: %s\n"),
271 sparse = sb->s_feature_ro_compat &
272 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
273 filetype = sb->s_feature_incompat &
274 EXT2_FEATURE_INCOMPAT_FILETYPE;
275 journal = sb->s_feature_compat &
276 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
277 if (old_journal && !journal) {
278 if ((mount_flags & EXT2_MF_MOUNTED) &&
279 !(mount_flags & EXT2_MF_READONLY)) {
281 _("The has_journal flag may only be "
282 "cleared when the filesystem is\n"
283 "unmounted or mounted "
287 if (sb->s_feature_incompat &
288 EXT3_FEATURE_INCOMPAT_RECOVER) {
290 _("The needs_recovery flag is set. "
291 "Please run e2fsck before clearing\n"
292 "the has_journal flag.\n"));
295 if (sb->s_journal_inum) {
296 remove_journal_inode(fs);
298 if (sb->s_journal_dev) {
299 remove_journal_device(fs);
302 if (journal && !old_journal) {
304 * If adding a journal flag, let the create journal
305 * code below handle creating setting the flag and
306 * creating the journal. We supply a default size if
311 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
314 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
315 (sb->s_feature_compat || sb->s_feature_ro_compat ||
316 sb->s_feature_incompat))
317 ext2fs_update_dynamic_rev(fs);
318 if ((sparse != old_sparse) ||
319 (filetype != old_filetype)) {
320 sb->s_state &= ~EXT2_VALID_FS;
321 printf("\n%s\n", _(please_fsck));
323 ext2fs_mark_super_dirty(fs);
327 * Add a journal to the filesystem.
329 static void add_journal(ext2_filsys fs)
331 unsigned long journal_blocks;
335 if (fs->super->s_feature_compat &
336 EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
337 fprintf(stderr, _("The filesystem already has a journal.\n"));
340 if (journal_device) {
341 check_plausibility(journal_device);
342 check_mount(journal_device, 0, _("journal"));
343 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
344 EXT2_FLAG_JOURNAL_DEV_OK, 0,
345 fs->blocksize, unix_io_manager, &jfs);
347 com_err(program_name, retval,
348 _("\n\twhile trying to open journal on %s\n"),
352 printf(_("Creating journal on device %s: "),
356 retval = ext2fs_add_journal_device(fs, jfs);
359 com_err (program_name, retval,
360 _("while adding filesystem to journal on %s"),
365 } else if (journal_size) {
366 printf(_("Creating journal inode: "));
368 journal_blocks = figure_journal_size(journal_size, fs);
370 retval = ext2fs_add_journal_inode(fs, journal_blocks,
373 fprintf(stderr, "\n");
374 com_err(program_name, retval,
375 _("\n\twhile trying to create journal file"));
380 * If the filesystem wasn't mounted, we need to force
381 * the block group descriptors out.
383 if ((mount_flags & EXT2_MF_MOUNTED) == 0)
384 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
386 print_check_message(fs);
391 free(journal_device);
396 * Given argv[0], return the program name.
398 static char *get_progname(char *argv_zero)
402 cp = strrchr(argv_zero, '/');
410 static void parse_e2label_options(int argc, char ** argv)
412 if ((argc < 2) || (argc > 3)) {
413 fprintf(stderr, _("Usage: e2label device [newlabel]\n"));
416 device_name = argv[1];
418 open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK;
426 static void parse_tune2fs_options(int argc, char **argv)
433 printf(_("tune2fs %s, %s for EXT2 FS %s, %s\n"),
434 E2FSPROGS_VERSION, E2FSPROGS_DATE,
435 EXT2FS_VERSION, EXT2FS_DATE);
436 while ((c = getopt (argc, argv, "c:e:fg:i:jlm:r:s:u:C:J:L:M:O:U:")) != EOF)
440 max_mount_count = strtol (optarg, &tmp, 0);
441 if (*tmp || max_mount_count > 16000) {
442 com_err (program_name, 0,
443 _("bad mounts count - %s"),
447 if (max_mount_count == 0)
448 max_mount_count = -1;
450 open_flag = EXT2_FLAG_RW;
453 mount_count = strtoul (optarg, &tmp, 0);
454 if (*tmp || mount_count > 16000) {
455 com_err (program_name, 0,
456 _("bad mounts count - %s"),
461 open_flag = EXT2_FLAG_RW;
464 if (strcmp (optarg, "continue") == 0)
465 errors = EXT2_ERRORS_CONTINUE;
466 else if (strcmp (optarg, "remount-ro") == 0)
467 errors = EXT2_ERRORS_RO;
468 else if (strcmp (optarg, "panic") == 0)
469 errors = EXT2_ERRORS_PANIC;
471 com_err (program_name, 0,
472 _("bad error behavior - %s"),
477 open_flag = EXT2_FLAG_RW;
479 case 'f': /* Force */
483 resgid = strtoul (optarg, &tmp, 0);
485 gr = getgrnam (optarg);
494 com_err (program_name, 0,
495 _("bad gid/group name - %s"),
500 open_flag = EXT2_FLAG_RW;
503 interval = strtoul (optarg, &tmp, 0);
516 case 'M': /* months! */
517 interval *= 86400 * 30;
521 case 'W': /* weeks */
522 interval *= 86400 * 7;
526 if (*tmp || interval > (365 * 86400)) {
527 com_err (program_name, 0,
528 _("bad interval - %s"), optarg);
532 open_flag = EXT2_FLAG_RW;
537 open_flag = EXT2_FLAG_RW;
540 parse_journal_opts(optarg);
541 open_flag = EXT2_FLAG_RW;
549 open_flag = EXT2_FLAG_RW |
550 EXT2_FLAG_JOURNAL_DEV_OK;
553 reserved_ratio = strtoul (optarg, &tmp, 0);
554 if (*tmp || reserved_ratio > 50) {
555 com_err (program_name, 0,
556 _("bad reserved block ratio - %s"),
561 open_flag = EXT2_FLAG_RW;
564 new_last_mounted = optarg;
566 open_flag = EXT2_FLAG_RW;
570 com_err (program_name, 0,
571 _("-O may only be specified once"));
574 features_cmd = optarg;
575 open_flag = EXT2_FLAG_RW;
578 reserved_blocks = strtoul (optarg, &tmp, 0);
580 com_err (program_name, 0,
581 _("bad reserved blocks count - %s"),
586 open_flag = EXT2_FLAG_RW;
589 s_flag = atoi(optarg);
590 open_flag = EXT2_FLAG_RW;
593 resuid = strtoul (optarg, &tmp, 0);
595 pw = getpwnam (optarg);
604 com_err (program_name, 0,
605 _("bad uid/user name - %s"),
610 open_flag = EXT2_FLAG_RW;
615 open_flag = EXT2_FLAG_RW |
616 EXT2_FLAG_JOURNAL_DEV_OK;
621 if (optind < argc - 1 || optind == argc)
623 if (!open_flag && !l_flag)
625 device_name = argv[optind];
630 int main (int argc, char ** argv)
634 struct ext2_super_block *sb;
637 setlocale(LC_MESSAGES, "");
638 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
639 textdomain(NLS_CAT_NAME);
642 program_name = *argv;
643 initialize_ext2_error_table();
645 if (strcmp(get_progname(argv[0]), "e2label") == 0)
646 parse_e2label_options(argc, argv);
648 parse_tune2fs_options(argc, argv);
650 retval = ext2fs_open (device_name, open_flag, 0, 0,
651 unix_io_manager, &fs);
653 com_err (program_name, retval, _("while trying to open %s"),
656 _("Couldn't find valid filesystem superblock.\n"));
661 /* For e2label emulation */
662 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
666 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
668 com_err("ext2fs_check_if_mount", retval,
669 _("while determining whether %s is mounted."),
673 /* Normally we only need to write out the superblock */
674 fs->flags |= EXT2_FLAG_SUPER_ONLY;
677 sb->s_max_mnt_count = max_mount_count;
678 ext2fs_mark_super_dirty(fs);
679 printf (_("Setting maximal mount count to %d\n"),
683 sb->s_mnt_count = mount_count;
684 ext2fs_mark_super_dirty(fs);
685 printf (_("Setting current mount count to %d\n"), mount_count);
688 sb->s_errors = errors;
689 ext2fs_mark_super_dirty(fs);
690 printf (_("Setting error behavior to %d\n"), errors);
693 sb->s_def_resgid = resgid;
694 ext2fs_mark_super_dirty(fs);
695 printf (_("Setting reserved blocks gid to %lu\n"), resgid);
698 sb->s_checkinterval = interval;
699 ext2fs_mark_super_dirty(fs);
700 printf (_("Setting interval between check %lu seconds\n"), interval);
703 sb->s_r_blocks_count = (sb->s_blocks_count / 100)
705 ext2fs_mark_super_dirty(fs);
706 printf (_("Setting reserved blocks percentage to %lu (%u blocks)\n"),
707 reserved_ratio, sb->s_r_blocks_count);
710 if (reserved_blocks >= sb->s_blocks_count) {
711 com_err (program_name, 0,
712 _("reserved blocks count is too big (%ul)"),
716 sb->s_r_blocks_count = reserved_blocks;
717 ext2fs_mark_super_dirty(fs);
718 printf (_("Setting reserved blocks count to %lu\n"),
722 if (sb->s_feature_ro_compat &
723 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
724 fprintf(stderr, _("\nThe filesystem already"
725 " has sparse superblocks.\n"));
727 sb->s_feature_ro_compat |=
728 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
729 sb->s_state &= ~EXT2_VALID_FS;
730 ext2fs_mark_super_dirty(fs);
731 printf(_("\nSparse superblock flag set. %s"),
736 if (!(sb->s_feature_ro_compat &
737 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
738 fprintf(stderr, _("\nThe filesystem already"
739 " has sparse superblocks disabled.\n"));
741 sb->s_feature_ro_compat &=
742 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
743 sb->s_state &= ~EXT2_VALID_FS;
744 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
745 ext2fs_mark_super_dirty(fs);
746 printf(_("\nSparse superblock flag cleared. %s"),
751 sb->s_def_resuid = resuid;
752 ext2fs_mark_super_dirty(fs);
753 printf (_("Setting reserved blocks uid to %lu\n"), resuid);
756 if (strlen(new_label) > sizeof(sb->s_volume_name))
757 fprintf(stderr, _("Warning: label too "
758 "long, truncating.\n"));
759 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
760 strncpy(sb->s_volume_name, new_label,
761 sizeof(sb->s_volume_name));
762 ext2fs_mark_super_dirty(fs);
765 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
766 strncpy(sb->s_last_mounted, new_last_mounted,
767 sizeof(sb->s_last_mounted));
768 ext2fs_mark_super_dirty(fs);
771 update_feature_set(fs, features_cmd);
772 if (journal_size || journal_device)
776 if ((strcasecmp(new_UUID, "null") == 0) ||
777 (strcasecmp(new_UUID, "clear") == 0)) {
778 uuid_clear(sb->s_uuid);
779 } else if (strcasecmp(new_UUID, "time") == 0) {
780 uuid_generate_time(sb->s_uuid);
781 } else if (strcasecmp(new_UUID, "random") == 0) {
782 uuid_generate(sb->s_uuid);
783 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
784 com_err(program_name, 0, _("Invalid UUID format\n"));
787 ext2fs_mark_super_dirty(fs);