blob: 7e2be5b837943c082b8c65fa63a35da9be618d45 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
Theodore Ts'o4d0f2282001-04-23 20:58:03 +00002 * tune2fs.c - Change the file system parameters on an ext2 file system
Theodore Ts'o3839e651997-04-26 13:21:57 +00003 *
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)
7 *
Theodore Ts'o4d0f2282001-04-23 20:58:03 +00008 * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
Theodore Ts'o19c78dc1997-04-29 16:17:09 +00009 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the GNU Public
12 * License.
13 * %End-Header%
Theodore Ts'o3839e651997-04-26 13:21:57 +000014 */
15
16/*
17 * History:
18 * 93/06/01 - Creation
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)
26 */
27
28#include <fcntl.h>
Theodore Ts'of3db3561997-04-26 13:34:30 +000029#include <grp.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000030#ifdef HAVE_GETOPT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000031#include <getopt.h>
Theodore Ts'o373b8332000-04-03 16:22:35 +000032#else
33extern char *optarg;
34extern int optind;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000035#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000036#include <pwd.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000037#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <time.h>
41#include <unistd.h>
Theodore Ts'of3db3561997-04-26 13:34:30 +000042#include <sys/types.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000043
44#include <linux/ext2_fs.h>
45
46#include "ext2fs/ext2fs.h"
47#include "et/com_err.h"
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000048#include "uuid/uuid.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000049#include "e2p/e2p.h"
Theodore Ts'odc2ec522001-01-18 01:51:15 +000050#include "jfs_user.h"
Theodore Ts'o63985322001-01-03 17:02:13 +000051#include "util.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000052
53#include "../version.h"
Theodore Ts'od9c56d32000-02-08 00:47:55 +000054#include "nls-enable.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000055
56const char * program_name = "tune2fs";
Theodore Ts'o63985322001-01-03 17:02:13 +000057char * device_name;
Theodore Ts'oc8c071a2001-01-11 16:08:23 +000058char * new_label, *new_last_mounted, *new_UUID;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +000059static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
Theodore Ts'o63985322001-01-03 17:02:13 +000060static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag;
Theodore Ts'o83238152001-01-09 00:16:26 +000061static int print_label;
Theodore Ts'o63985322001-01-03 17:02:13 +000062static int max_mount_count, mount_count, mount_flags;
63static unsigned long interval, reserved_ratio, reserved_blocks;
64static unsigned long resgid, resuid;
65static unsigned short errors;
Theodore Ts'o83238152001-01-09 00:16:26 +000066static int open_flag;
67static char *features_cmd;
Theodore Ts'o3839e651997-04-26 13:21:57 +000068
Theodore Ts'o63985322001-01-03 17:02:13 +000069int journal_size, journal_flags;
70char *journal_device;
71
72static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000073
Theodore Ts'o818180c1998-06-27 05:11:14 +000074static void usage(void)
Theodore Ts'o3839e651997-04-26 13:21:57 +000075{
Theodore Ts'ob21e38a2001-01-01 15:26:58 +000076 fprintf(stderr,
77 _("Usage: %s [-c max-mounts-count] [-e errors-behavior] "
78 "[-g group]\n"
Theodore Ts'odc2ec522001-01-18 01:51:15 +000079 "\t[-i interval[d|m|w]] [-j] [-J journal-options]\n"
Theodore Ts'o63985322001-01-03 17:02:13 +000080 "\t[-l] [-s sparse-flag] [-m reserved-blocks-percent]\n"
Theodore Ts'ob21e38a2001-01-01 15:26:58 +000081 "\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);
Theodore Ts'o3839e651997-04-26 13:21:57 +000084 exit (1);
85}
86
Theodore Ts'o896938d1999-10-23 01:04:50 +000087static __u32 ok_features[3] = {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +000088 EXT3_FEATURE_COMPAT_HAS_JOURNAL, /* Compat */
Theodore Ts'o896938d1999-10-23 01:04:50 +000089 EXT2_FEATURE_INCOMPAT_FILETYPE, /* Incompat */
90 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */
91};
92
Theodore Ts'o63985322001-01-03 17:02:13 +000093/*
Theodore Ts'odc2ec522001-01-18 01:51:15 +000094 * Remove an external journal from the filesystem
95 */
96static void remove_journal_device(ext2_filsys fs)
97{
98 char *journal_device;
99 ext2_filsys jfs;
100 char buf[1024];
101 journal_superblock_t *jsb;
102 int i, nr_users;
103 errcode_t retval;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000104 int commit_remove_journal = 0;
105
106 if (f_flag)
107 commit_remove_journal = 1; /* force removal even if error */
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000108
109 journal_device = ext2fs_find_block_device(fs->super->s_journal_dev);
110 if (!journal_device)
111 return;
112
113 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
114 EXT2_FLAG_JOURNAL_DEV_OK, 0,
115 fs->blocksize, unix_io_manager, &jfs);
116 if (retval) {
117 com_err(program_name, retval,
118 _("while trying to open external journal"));
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000119 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000120 }
121 if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
122 fprintf(stderr, "%s is not a journal device.\n",
123 journal_device);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000124 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000125 }
126
127 /* Get the journal superblock */
128 if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) {
129 com_err(program_name, retval,
130 _("while reading journal superblock"));
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000131 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000132 }
133
134 jsb = (journal_superblock_t *) buf;
135 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
136 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
137 fprintf(stderr, _("Journal superblock not found!\n"));
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000138 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000139 }
140
141 /* Find the filesystem UUID */
142 nr_users = ntohl(jsb->s_nr_users);
143 for (i=0; i < nr_users; i++) {
144 if (memcmp(fs->super->s_uuid,
145 &jsb->s_users[i*16], 16) == 0)
146 break;
147 }
148 if (i >= nr_users) {
149 fprintf(stderr, "Filesystem's UUID not found on journal device.\n");
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000150 commit_remove_journal = 1;
151 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000152 }
153 nr_users--;
154 for (i=0; i < nr_users; i++)
155 memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16);
156 jsb->s_nr_users = htonl(nr_users);
157
158 /* Write back the journal superblock */
159 if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) {
160 com_err(program_name, retval,
161 "while writing journal superblock.");
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000162 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000163 }
164
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000165 commit_remove_journal = 1;
166
167no_valid_journal:
168 if (commit_remove_journal == 0) {
169 printf(_("Journal NOT removed\n"));
170 exit(1);
171 }
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000172 fs->super->s_journal_dev = 0;
173 memset(fs->super->s_journal_uuid, 0,
174 sizeof(fs->super->s_journal_uuid));
175 ext2fs_mark_super_dirty(fs);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000176 printf(_("Journal removed\n"));
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000177}
178
179
180/*
Theodore Ts'o63985322001-01-03 17:02:13 +0000181 * Update the feature set as provided by the user.
182 */
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000183static void update_feature_set(ext2_filsys fs, char *features)
Theodore Ts'o63985322001-01-03 17:02:13 +0000184{
185 int sparse, old_sparse, filetype, old_filetype;
186 int journal, old_journal;
187 struct ext2_inode inode;
188 struct ext2_super_block *sb= fs->super;
189 errcode_t retval;
190
191 old_sparse = sb->s_feature_ro_compat &
192 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
193 old_filetype = sb->s_feature_incompat &
194 EXT2_FEATURE_INCOMPAT_FILETYPE;
195 old_journal = sb->s_feature_compat &
196 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000197 if (e2p_edit_feature(features, &sb->s_feature_compat,
Theodore Ts'o63985322001-01-03 17:02:13 +0000198 ok_features)) {
199 fprintf(stderr, _("Invalid filesystem option set: %s\n"),
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000200 features);
Theodore Ts'o63985322001-01-03 17:02:13 +0000201 exit(1);
202 }
203 sparse = sb->s_feature_ro_compat &
204 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
205 filetype = sb->s_feature_incompat &
206 EXT2_FEATURE_INCOMPAT_FILETYPE;
207 journal = sb->s_feature_compat &
208 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
209 if (old_journal && !journal) {
210 if ((mount_flags & EXT2_MF_MOUNTED) &&
211 !(mount_flags & EXT2_MF_READONLY)) {
212 fprintf(stderr,
Theodore Ts'o8d641742001-05-14 04:12:27 +0000213 _("The has_journal flag may only be "
Theodore Ts'o63985322001-01-03 17:02:13 +0000214 "cleared when the filesystem is\n"
215 "unmounted or mounted "
216 "read-only.\n"));
217 exit(1);
218 }
219 if (sb->s_feature_incompat &
220 EXT3_FEATURE_INCOMPAT_RECOVER) {
221 fprintf(stderr,
Theodore Ts'o8d641742001-05-14 04:12:27 +0000222 _("The needs_recovery flag is set. "
Theodore Ts'o63985322001-01-03 17:02:13 +0000223 "Please run e2fsck before clearing\n"
224 "the HAS_JOURNAL flag.\n"));
225 exit(1);
226 }
227 /*
228 * Remove the immutable flag on the journal inode
229 */
230 if (sb->s_journal_inum) {
231 retval = ext2fs_read_inode(fs, sb->s_journal_inum,
232 &inode);
233 if (retval) {
234 com_err(program_name, retval,
235 "while reading journal inode");
236 exit(1);
237 }
238 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
239 retval = ext2fs_write_inode(fs, sb->s_journal_inum,
240 &inode);
241 if (retval) {
242 com_err(program_name, retval,
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000243 "while writing journal inode");
Theodore Ts'o63985322001-01-03 17:02:13 +0000244 exit(1);
245 }
246 }
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000247 if (sb->s_journal_dev)
248 remove_journal_device(fs);
Theodore Ts'o63985322001-01-03 17:02:13 +0000249 }
250 if (journal && !old_journal) {
251 /*
252 * If adding a journal flag, let the create journal
253 * code below handle creating setting the flag and
254 * creating the journal. We supply a default size if
255 * necessary.
256 */
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000257 if (!journal_size)
258 journal_size = -1;
Theodore Ts'o08dd8302001-01-14 16:25:58 +0000259 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
Theodore Ts'o63985322001-01-03 17:02:13 +0000260 journal = old_journal;
261 }
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000262
Theodore Ts'o63985322001-01-03 17:02:13 +0000263 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
264 (sb->s_feature_compat || sb->s_feature_ro_compat ||
265 sb->s_feature_incompat))
266 ext2fs_update_dynamic_rev(fs);
267 if ((sparse != old_sparse) ||
268 (filetype != old_filetype) ||
269 (journal != old_journal)) {
270 sb->s_state &= ~EXT2_VALID_FS;
271 printf("\n%s\n", _(please_fsck));
272 }
273 ext2fs_mark_super_dirty(fs);
274}
275
276/*
277 * Add a journal to the filesystem.
278 */
279static void add_journal(ext2_filsys fs)
280{
281 unsigned long journal_blocks;
282 errcode_t retval;
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000283 ext2_filsys jfs;
Theodore Ts'o63985322001-01-03 17:02:13 +0000284
285 if (fs->super->s_feature_compat &
286 EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
287 fprintf(stderr, _("The filesystem already has a journal.\n"));
288 exit(1);
289 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000290 if (journal_device) {
291 check_plausibility(journal_device);
292 check_mount(journal_device, 0, _("journal"));
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000293 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
294 EXT2_FLAG_JOURNAL_DEV_OK, 0,
295 fs->blocksize, unix_io_manager, &jfs);
296 if (retval) {
297 com_err(program_name, retval,
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000298 _("\n\twhile trying to open journal on %s\n"),
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000299 journal_device);
300 exit(1);
301 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000302 printf(_("Creating journal on device %s: "),
303 journal_device);
Theodore Ts'o4055ef72001-01-14 16:11:14 +0000304 fflush(stdout);
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000305
306 retval = ext2fs_add_journal_device(fs, jfs);
Theodore Ts'o63985322001-01-03 17:02:13 +0000307 if (retval) {
308 com_err (program_name, retval,
Theodore Ts'o8d641742001-05-14 04:12:27 +0000309 _("while adding filesystem to journal on %s"),
Theodore Ts'o63985322001-01-03 17:02:13 +0000310 journal_device);
311 exit(1);
312 }
313 printf(_("done\n"));
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000314 ext2fs_close(jfs);
Theodore Ts'o63985322001-01-03 17:02:13 +0000315 } else if (journal_size) {
Theodore Ts'o63985322001-01-03 17:02:13 +0000316 printf(_("Creating journal inode: "));
317 fflush(stdout);
Theodore Ts'o2537b6d2001-03-26 20:07:13 +0000318 journal_blocks = figure_journal_size(journal_size, fs);
319
Theodore Ts'o63985322001-01-03 17:02:13 +0000320 retval = ext2fs_add_journal_inode(fs, journal_blocks,
321 journal_flags);
322 if (retval) {
323 printf("\n");
324 com_err(program_name, retval,
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000325 _("\n\twhile trying to create journal file"));
Theodore Ts'o63985322001-01-03 17:02:13 +0000326 exit(1);
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000327 } else
328 printf(_("done\n"));
Theodore Ts'o63985322001-01-03 17:02:13 +0000329 /*
330 * If the filesystem wasn't mounted, we need to force
331 * the block group descriptors out.
332 */
333 if ((mount_flags & EXT2_MF_MOUNTED) == 0)
334 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
335 }
336}
337
Theodore Ts'o83238152001-01-09 00:16:26 +0000338/*
339 * Given argv[0], return the program name.
340 */
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000341static char *get_progname(char *argv_zero)
Theodore Ts'o83238152001-01-09 00:16:26 +0000342{
343 char *cp;
344
345 cp = strrchr(argv_zero, '/');
346 if (!cp )
347 return argv_zero;
348 else
349 return cp+1;
350}
Theodore Ts'o63985322001-01-03 17:02:13 +0000351
Theodore Ts'o896938d1999-10-23 01:04:50 +0000352
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000353static void parse_e2label_options(int argc, char ** argv)
Theodore Ts'o83238152001-01-09 00:16:26 +0000354{
355 if ((argc < 2) || (argc > 3)) {
356 fprintf(stderr, _("Usage: e2label device [newlabel]\n"));
357 exit(1);
358 }
359 device_name = argv[1];
360 if (argc == 3) {
361 open_flag = EXT2_FLAG_RW;
362 L_flag = 1;
363 new_label = argv[2];
364 } else
365 print_label++;
366}
367
368
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000369static void parse_tune2fs_options(int argc, char **argv)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000370{
Theodore Ts'o519149f1997-10-25 03:49:49 +0000371 int c;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000372 char * tmp;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000373 struct group * gr;
374 struct passwd * pw;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000375
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000376 fprintf (stderr, _("tune2fs %s, %s for EXT2 FS %s, %s\n"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000377 E2FSPROGS_VERSION, E2FSPROGS_DATE,
378 EXT2FS_VERSION, EXT2FS_DATE);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000379 while ((c = getopt (argc, argv, "c:e:fg:i:jlm:r:s:u:C:J:L:M:O:U:")) != EOF)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000380 switch (c)
381 {
382 case 'c':
Theodore Ts'o45d9e2f2000-07-07 03:12:54 +0000383 max_mount_count = strtol (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000384 if (*tmp || max_mount_count > 16000) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000385 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000386 _("bad mounts count - %s"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000387 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000388 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000389 }
Theodore Ts'oce57f142001-04-26 04:25:39 +0000390 if (max_mount_count == 0)
391 max_mount_count = -1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000392 c_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000393 open_flag = EXT2_FLAG_RW;
394 break;
395 case 'C':
396 mount_count = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000397 if (*tmp || mount_count > 16000) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000398 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000399 _("bad mounts count - %s"),
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000400 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000401 usage();
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000402 }
403 C_flag = 1;
404 open_flag = EXT2_FLAG_RW;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000405 break;
406 case 'e':
407 if (strcmp (optarg, "continue") == 0)
408 errors = EXT2_ERRORS_CONTINUE;
409 else if (strcmp (optarg, "remount-ro") == 0)
410 errors = EXT2_ERRORS_RO;
411 else if (strcmp (optarg, "panic") == 0)
412 errors = EXT2_ERRORS_PANIC;
Theodore Ts'o818180c1998-06-27 05:11:14 +0000413 else {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000414 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000415 _("bad error behavior - %s"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000416 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000417 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000418 }
419 e_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000420 open_flag = EXT2_FLAG_RW;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000421 break;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000422 case 'f': /* Force */
423 f_flag = 1;
424 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000425 case 'g':
426 resgid = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000427 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000428 gr = getgrnam (optarg);
429 if (gr == NULL)
430 tmp = optarg;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000431 else {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000432 resgid = gr->gr_gid;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000433 *tmp =0;
434 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000435 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000436 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000437 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000438 _("bad gid/group name - %s"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000439 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000440 usage();
Theodore Ts'of3db3561997-04-26 13:34:30 +0000441 }
442 g_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000443 open_flag = EXT2_FLAG_RW;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000444 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000445 case 'i':
446 interval = strtoul (optarg, &tmp, 0);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000447 switch (*tmp) {
448 case 's':
449 tmp++;
450 break;
451 case '\0':
452 case 'd':
453 case 'D': /* days */
454 interval *= 86400;
455 if (*tmp != '\0')
Theodore Ts'o3839e651997-04-26 13:21:57 +0000456 tmp++;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000457 break;
458 case 'm':
459 case 'M': /* months! */
460 interval *= 86400 * 30;
461 tmp++;
462 break;
463 case 'w':
464 case 'W': /* weeks */
465 interval *= 86400 * 7;
466 tmp++;
467 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000468 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000469 if (*tmp || interval > (365 * 86400)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000470 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000471 _("bad interval - %s"), optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000472 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000473 }
474 i_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000475 open_flag = EXT2_FLAG_RW;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000476 break;
Theodore Ts'o63985322001-01-03 17:02:13 +0000477 case 'j':
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000478 if (!journal_size)
479 journal_size = -1;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000480 open_flag = EXT2_FLAG_RW;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000481 break;
482 case 'J':
483 parse_journal_opts(optarg);
Theodore Ts'o63985322001-01-03 17:02:13 +0000484 open_flag = EXT2_FLAG_RW;
485 break;
Theodore Ts'o08dd8302001-01-14 16:25:58 +0000486 case 'l':
487 l_flag = 1;
488 break;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000489 case 'L':
490 new_label = optarg;
491 L_flag = 1;
492 open_flag = EXT2_FLAG_RW;
493 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000494 case 'm':
495 reserved_ratio = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000496 if (*tmp || reserved_ratio > 50) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000497 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000498 _("bad reserved block ratio - %s"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000499 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000500 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000501 }
502 m_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000503 open_flag = EXT2_FLAG_RW;
504 break;
505 case 'M':
506 new_last_mounted = optarg;
507 M_flag = 1;
508 open_flag = EXT2_FLAG_RW;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000509 break;
Theodore Ts'o896938d1999-10-23 01:04:50 +0000510 case 'O':
511 features_cmd = optarg;
512 open_flag = EXT2_FLAG_RW;
513 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000514 case 'r':
515 reserved_blocks = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000516 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000517 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000518 _("bad reserved blocks count - %s"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000519 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000520 usage();
Theodore Ts'of3db3561997-04-26 13:34:30 +0000521 }
522 r_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000523 open_flag = EXT2_FLAG_RW;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000524 break;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000525 case 's':
526 s_flag = atoi(optarg);
527 open_flag = EXT2_FLAG_RW;
528 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000529 case 'u':
530 resuid = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000531 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000532 pw = getpwnam (optarg);
533 if (pw == NULL)
534 tmp = optarg;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000535 else {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000536 resuid = pw->pw_uid;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000537 *tmp = 0;
538 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000539 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000540 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000541 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000542 _("bad uid/user name - %s"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000543 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000544 usage();
Theodore Ts'of3db3561997-04-26 13:34:30 +0000545 }
546 u_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000547 open_flag = EXT2_FLAG_RW;
548 break;
549 case 'U':
550 new_UUID = optarg;
551 U_flag = 1;
552 open_flag = EXT2_FLAG_RW;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000553 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000554 default:
Theodore Ts'o818180c1998-06-27 05:11:14 +0000555 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000556 }
557 if (optind < argc - 1 || optind == argc)
Theodore Ts'o818180c1998-06-27 05:11:14 +0000558 usage();
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000559 if (!open_flag && !l_flag)
560 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000561 device_name = argv[optind];
Theodore Ts'o83238152001-01-09 00:16:26 +0000562}
563
564
565
566int main (int argc, char ** argv)
567{
568 errcode_t retval;
569 ext2_filsys fs;
570 struct ext2_super_block *sb;
571
572#ifdef ENABLE_NLS
573 setlocale(LC_MESSAGES, "");
574 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
575 textdomain(NLS_CAT_NAME);
576#endif
577 if (argc && *argv)
578 program_name = *argv;
579 initialize_ext2_error_table();
580
581 if (strcmp(get_progname(argv[0]), "e2label") == 0)
582 parse_e2label_options(argc, argv);
583 else
584 parse_tune2fs_options(argc, argv);
585
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000586 retval = ext2fs_open (device_name, open_flag, 0, 0,
587 unix_io_manager, &fs);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000588 if (retval) {
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000589 com_err (program_name, retval, _("while trying to open %s"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000590 device_name);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000591 printf(_("Couldn't find valid filesystem superblock.\n"));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000592 exit(1);
593 }
Theodore Ts'o83238152001-01-09 00:16:26 +0000594 sb = fs->super;
595 if (print_label) {
596 /* For e2label emulation */
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000597 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
598 sb->s_volume_name);
Theodore Ts'o83238152001-01-09 00:16:26 +0000599 exit(0);
600 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000601 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
602 if (retval) {
603 com_err("ext2fs_check_if_mount", retval,
604 _("while determining whether %s is mounted."),
605 device_name);
Theodore Ts'o4055ef72001-01-14 16:11:14 +0000606 exit(1);
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000607 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000608 /* Normally we only need to write out the superblock */
609 fs->flags |= EXT2_FLAG_SUPER_ONLY;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000610
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000611 if (c_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000612 sb->s_max_mnt_count = max_mount_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000613 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000614 printf (_("Setting maximal mount count to %d\n"),
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000615 max_mount_count);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000616 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000617 if (C_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000618 sb->s_mnt_count = mount_count;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000619 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000620 printf (_("Setting current mount count to %d\n"), mount_count);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000621 }
622 if (e_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000623 sb->s_errors = errors;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000624 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000625 printf (_("Setting error behavior to %d\n"), errors);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000626 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000627 if (g_flag) {
628 sb->s_def_resgid = resgid;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000629 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000630 printf (_("Setting reserved blocks gid to %lu\n"), resgid);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000631 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000632 if (i_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000633 sb->s_checkinterval = interval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000634 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000635 printf (_("Setting interval between check %lu seconds\n"), interval);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000636 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000637 if (m_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000638 sb->s_r_blocks_count = (sb->s_blocks_count / 100)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000639 * reserved_ratio;
640 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000641 printf (_("Setting reserved blocks percentage to %lu (%u blocks)\n"),
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000642 reserved_ratio, sb->s_r_blocks_count);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000643 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000644 if (r_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000645 if (reserved_blocks >= sb->s_blocks_count) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000646 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000647 _("reserved blocks count is too big (%ul)"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000648 reserved_blocks);
649 exit (1);
650 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000651 sb->s_r_blocks_count = reserved_blocks;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000652 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000653 printf (_("Setting reserved blocks count to %lu\n"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000654 reserved_blocks);
655 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000656 if (s_flag == 1) {
Theodore Ts'o521e3681997-04-29 17:48:10 +0000657 if (sb->s_feature_ro_compat &
658 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000659 fprintf(stderr, _("\nThe filesystem already"
Theodore Ts'oe1a0a3e2000-02-11 05:00:19 +0000660 " has sparse superblocks.\n"));
Theodore Ts'o521e3681997-04-29 17:48:10 +0000661 else {
662 sb->s_feature_ro_compat |=
663 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000664 sb->s_state &= ~EXT2_VALID_FS;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000665 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000666 printf(_("\nSparse superblock flag set. %s"),
Theodore Ts'oa4fa1002000-02-08 21:35:41 +0000667 _(please_fsck));
Theodore Ts'o521e3681997-04-29 17:48:10 +0000668 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000669 }
670 if (s_flag == 0) {
Theodore Ts'o521e3681997-04-29 17:48:10 +0000671 if (!(sb->s_feature_ro_compat &
672 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000673 fprintf(stderr, _("\nThe filesystem already"
Theodore Ts'oe1a0a3e2000-02-11 05:00:19 +0000674 " has sparse superblocks disabled.\n"));
Theodore Ts'o521e3681997-04-29 17:48:10 +0000675 else {
676 sb->s_feature_ro_compat &=
677 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000678 sb->s_state &= ~EXT2_VALID_FS;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000679 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
680 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000681 printf(_("\nSparse superblock flag cleared. %s"),
Theodore Ts'oa4fa1002000-02-08 21:35:41 +0000682 _(please_fsck));
Theodore Ts'o521e3681997-04-29 17:48:10 +0000683 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000684 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000685 if (u_flag) {
686 sb->s_def_resuid = resuid;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000687 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000688 printf (_("Setting reserved blocks uid to %lu\n"), resuid);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000689 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000690 if (L_flag) {
Theodore Ts'oa789d841998-03-30 01:20:55 +0000691 if (strlen(new_label) > sizeof(sb->s_volume_name))
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000692 fprintf(stderr, _("Warning: label too "
693 "long, truncating.\n"));
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000694 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
695 strncpy(sb->s_volume_name, new_label,
696 sizeof(sb->s_volume_name));
697 ext2fs_mark_super_dirty(fs);
698 }
699 if (M_flag) {
700 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
701 strncpy(sb->s_last_mounted, new_last_mounted,
702 sizeof(sb->s_last_mounted));
703 ext2fs_mark_super_dirty(fs);
704 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000705 if (features_cmd)
706 update_feature_set(fs, features_cmd);
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000707 if (journal_size || journal_device)
Theodore Ts'o63985322001-01-03 17:02:13 +0000708 add_journal(fs);
709
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000710 if (U_flag) {
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000711 if ((strcasecmp(new_UUID, "null") == 0) ||
712 (strcasecmp(new_UUID, "clear") == 0)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000713 uuid_clear(sb->s_uuid);
Theodore Ts'o63985322001-01-03 17:02:13 +0000714 } else if (strcasecmp(new_UUID, "time") == 0) {
715 uuid_generate_time(sb->s_uuid);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000716 } else if (strcasecmp(new_UUID, "random") == 0) {
717 uuid_generate(sb->s_uuid);
718 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000719 com_err(program_name, 0, _("Invalid UUID format\n"));
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000720 exit(1);
721 }
722 ext2fs_mark_super_dirty(fs);
723 }
724
Theodore Ts'o3839e651997-04-26 13:21:57 +0000725 if (l_flag)
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000726 list_super (sb);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000727 ext2fs_close (fs);
728 exit (0);
729}