blob: 0ec0c66ac141b0b9f838d499d9dc49ae453217ef [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
Theodore Ts'o54c637d2001-05-14 11:45:38 +000044#include "ext2fs/ext2_fs.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000045#include "ext2fs/ext2fs.h"
46#include "et/com_err.h"
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000047#include "uuid/uuid.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000048#include "e2p/e2p.h"
Theodore Ts'odc2ec522001-01-18 01:51:15 +000049#include "jfs_user.h"
Theodore Ts'o63985322001-01-03 17:02:13 +000050#include "util.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000051
52#include "../version.h"
Theodore Ts'od9c56d32000-02-08 00:47:55 +000053#include "nls-enable.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000054
55const char * program_name = "tune2fs";
Theodore Ts'o63985322001-01-03 17:02:13 +000056char * device_name;
Theodore Ts'oc8c071a2001-01-11 16:08:23 +000057char * new_label, *new_last_mounted, *new_UUID;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +000058static 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 +000059static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag;
Theodore Ts'o83238152001-01-09 00:16:26 +000060static int print_label;
Theodore Ts'o63985322001-01-03 17:02:13 +000061static int max_mount_count, mount_count, mount_flags;
62static unsigned long interval, reserved_ratio, reserved_blocks;
63static unsigned long resgid, resuid;
64static unsigned short errors;
Theodore Ts'o83238152001-01-09 00:16:26 +000065static int open_flag;
66static char *features_cmd;
Theodore Ts'o3839e651997-04-26 13:21:57 +000067
Theodore Ts'o63985322001-01-03 17:02:13 +000068int journal_size, journal_flags;
69char *journal_device;
70
71static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000072
Theodore Ts'o818180c1998-06-27 05:11:14 +000073static void usage(void)
Theodore Ts'o3839e651997-04-26 13:21:57 +000074{
Theodore Ts'ob21e38a2001-01-01 15:26:58 +000075 fprintf(stderr,
76 _("Usage: %s [-c max-mounts-count] [-e errors-behavior] "
77 "[-g group]\n"
Theodore Ts'odc2ec522001-01-18 01:51:15 +000078 "\t[-i interval[d|m|w]] [-j] [-J journal-options]\n"
Theodore Ts'o63985322001-01-03 17:02:13 +000079 "\t[-l] [-s sparse-flag] [-m reserved-blocks-percent]\n"
Theodore Ts'ob21e38a2001-01-01 15:26:58 +000080 "\t[-r reserved-blocks-count] [-u user] [-C mount-count]\n"
81 "\t[-L volume-label] [-M last-mounted-dir] [-U UUID]\n"
82 "\t[-O [^]feature[,...]] device\n"), program_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +000083 exit (1);
84}
85
Theodore Ts'o896938d1999-10-23 01:04:50 +000086static __u32 ok_features[3] = {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +000087 EXT3_FEATURE_COMPAT_HAS_JOURNAL, /* Compat */
Theodore Ts'o896938d1999-10-23 01:04:50 +000088 EXT2_FEATURE_INCOMPAT_FILETYPE, /* Incompat */
89 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */
90};
91
Theodore Ts'o63985322001-01-03 17:02:13 +000092/*
Theodore Ts'odc2ec522001-01-18 01:51:15 +000093 * Remove an external journal from the filesystem
94 */
95static void remove_journal_device(ext2_filsys fs)
96{
97 char *journal_device;
98 ext2_filsys jfs;
99 char buf[1024];
100 journal_superblock_t *jsb;
101 int i, nr_users;
102 errcode_t retval;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000103 int commit_remove_journal = 0;
104
105 if (f_flag)
106 commit_remove_journal = 1; /* force removal even if error */
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000107
108 journal_device = ext2fs_find_block_device(fs->super->s_journal_dev);
109 if (!journal_device)
110 return;
111
112 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
113 EXT2_FLAG_JOURNAL_DEV_OK, 0,
114 fs->blocksize, unix_io_manager, &jfs);
115 if (retval) {
116 com_err(program_name, retval,
117 _("while trying to open external journal"));
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000118 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000119 }
120 if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
121 fprintf(stderr, "%s is not a journal device.\n",
122 journal_device);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000123 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000124 }
125
126 /* Get the journal superblock */
127 if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) {
128 com_err(program_name, retval,
129 _("while reading journal superblock"));
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000130 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000131 }
132
133 jsb = (journal_superblock_t *) buf;
134 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
135 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
136 fprintf(stderr, _("Journal superblock not found!\n"));
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000137 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000138 }
139
140 /* Find the filesystem UUID */
141 nr_users = ntohl(jsb->s_nr_users);
142 for (i=0; i < nr_users; i++) {
143 if (memcmp(fs->super->s_uuid,
144 &jsb->s_users[i*16], 16) == 0)
145 break;
146 }
147 if (i >= nr_users) {
148 fprintf(stderr, "Filesystem's UUID not found on journal device.\n");
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000149 commit_remove_journal = 1;
150 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000151 }
152 nr_users--;
153 for (i=0; i < nr_users; i++)
154 memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16);
155 jsb->s_nr_users = htonl(nr_users);
156
157 /* Write back the journal superblock */
158 if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) {
159 com_err(program_name, retval,
160 "while writing journal superblock.");
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000161 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000162 }
163
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000164 commit_remove_journal = 1;
165
166no_valid_journal:
167 if (commit_remove_journal == 0) {
168 printf(_("Journal NOT removed\n"));
169 exit(1);
170 }
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000171 fs->super->s_journal_dev = 0;
172 memset(fs->super->s_journal_uuid, 0,
173 sizeof(fs->super->s_journal_uuid));
174 ext2fs_mark_super_dirty(fs);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000175 printf(_("Journal removed\n"));
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000176}
177
Theodore Ts'o194686b2001-07-31 12:03:23 -0400178/* Helper function for remove_journal_inode */
179static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
180 int blockcnt, void *private)
181{
182 blk_t block;
183 int group;
184
185 block = *blocknr;
186 ext2fs_unmark_block_bitmap(fs->block_map,block);
187 group = ext2fs_group_of_blk(fs, block);
188 fs->group_desc[group].bg_free_blocks_count++;
189 fs->super->s_free_blocks_count++;
190 return 0;
191}
192
193/*
194 * Remove the journal inode from the filesystem
195 */
196static void remove_journal_inode(ext2_filsys fs)
197{
198 struct ext2_inode inode;
199 errcode_t retval;
200 ino_t ino = fs->super->s_journal_inum;
201 int group;
202
203 retval = ext2fs_read_inode(fs, ino, &inode);
204 if (retval) {
205 com_err(program_name, retval,
206 _("while reading journal inode"));
207 exit(1);
208 }
209 if (ino == EXT2_JOURNAL_INO) {
210 retval = ext2fs_read_bitmaps(fs);
211 if (retval) {
212 com_err(program_name, retval,
213 _("while reading bitmaps"));
214 exit(1);
215 }
216 retval = ext2fs_block_iterate(fs, ino, 0, NULL,
217 release_blocks_proc, NULL);
218 if (retval) {
219 com_err(program_name, retval,
220 _("while clearing journal inode"));
221 exit(1);
222 }
223 memset(&inode, 0, sizeof(inode));
224 ext2fs_mark_bb_dirty(fs);
225 group = ext2fs_group_of_ino(fs, ino);
226 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
227 } else
228 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
229 retval = ext2fs_write_inode(fs, ino, &inode);
230 if (retval) {
231 com_err(program_name, retval,
232 _("while writing journal inode"));
233 exit(1);
234 }
235 fs->super->s_journal_inum = 0;
236 ext2fs_mark_super_dirty(fs);
237}
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000238
239/*
Theodore Ts'o63985322001-01-03 17:02:13 +0000240 * Update the feature set as provided by the user.
241 */
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000242static void update_feature_set(ext2_filsys fs, char *features)
Theodore Ts'o63985322001-01-03 17:02:13 +0000243{
244 int sparse, old_sparse, filetype, old_filetype;
245 int journal, old_journal;
246 struct ext2_inode inode;
247 struct ext2_super_block *sb= fs->super;
248 errcode_t retval;
249
250 old_sparse = sb->s_feature_ro_compat &
251 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
252 old_filetype = sb->s_feature_incompat &
253 EXT2_FEATURE_INCOMPAT_FILETYPE;
254 old_journal = sb->s_feature_compat &
255 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000256 if (e2p_edit_feature(features, &sb->s_feature_compat,
Theodore Ts'o63985322001-01-03 17:02:13 +0000257 ok_features)) {
258 fprintf(stderr, _("Invalid filesystem option set: %s\n"),
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000259 features);
Theodore Ts'o63985322001-01-03 17:02:13 +0000260 exit(1);
261 }
262 sparse = sb->s_feature_ro_compat &
263 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
264 filetype = sb->s_feature_incompat &
265 EXT2_FEATURE_INCOMPAT_FILETYPE;
266 journal = sb->s_feature_compat &
267 EXT3_FEATURE_COMPAT_HAS_JOURNAL;
268 if (old_journal && !journal) {
269 if ((mount_flags & EXT2_MF_MOUNTED) &&
270 !(mount_flags & EXT2_MF_READONLY)) {
271 fprintf(stderr,
Theodore Ts'o8d641742001-05-14 04:12:27 +0000272 _("The has_journal flag may only be "
Theodore Ts'o63985322001-01-03 17:02:13 +0000273 "cleared when the filesystem is\n"
274 "unmounted or mounted "
275 "read-only.\n"));
276 exit(1);
277 }
278 if (sb->s_feature_incompat &
279 EXT3_FEATURE_INCOMPAT_RECOVER) {
280 fprintf(stderr,
Theodore Ts'o8d641742001-05-14 04:12:27 +0000281 _("The needs_recovery flag is set. "
Theodore Ts'o63985322001-01-03 17:02:13 +0000282 "Please run e2fsck before clearing\n"
Theodore Ts'oe549d0a2001-05-25 16:38:48 +0000283 "the has_journal flag.\n"));
Theodore Ts'o63985322001-01-03 17:02:13 +0000284 exit(1);
285 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000286 if (sb->s_journal_inum) {
Theodore Ts'o194686b2001-07-31 12:03:23 -0400287 remove_journal_inode(fs);
Theodore Ts'o63985322001-01-03 17:02:13 +0000288 }
Theodore Ts'ode49f012001-07-30 16:31:30 -0400289 if (sb->s_journal_dev) {
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000290 remove_journal_device(fs);
Theodore Ts'ode49f012001-07-30 16:31:30 -0400291 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000292 }
293 if (journal && !old_journal) {
294 /*
295 * If adding a journal flag, let the create journal
296 * code below handle creating setting the flag and
297 * creating the journal. We supply a default size if
298 * necessary.
299 */
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000300 if (!journal_size)
301 journal_size = -1;
Theodore Ts'o08dd8302001-01-14 16:25:58 +0000302 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
Theodore Ts'o63985322001-01-03 17:02:13 +0000303 }
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000304
Theodore Ts'o63985322001-01-03 17:02:13 +0000305 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
306 (sb->s_feature_compat || sb->s_feature_ro_compat ||
307 sb->s_feature_incompat))
308 ext2fs_update_dynamic_rev(fs);
309 if ((sparse != old_sparse) ||
Theodore Ts'o194686b2001-07-31 12:03:23 -0400310 (filetype != old_filetype)) {
Theodore Ts'o63985322001-01-03 17:02:13 +0000311 sb->s_state &= ~EXT2_VALID_FS;
312 printf("\n%s\n", _(please_fsck));
313 }
314 ext2fs_mark_super_dirty(fs);
315}
316
317/*
318 * Add a journal to the filesystem.
319 */
320static void add_journal(ext2_filsys fs)
321{
322 unsigned long journal_blocks;
323 errcode_t retval;
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000324 ext2_filsys jfs;
Theodore Ts'o63985322001-01-03 17:02:13 +0000325
326 if (fs->super->s_feature_compat &
327 EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
328 fprintf(stderr, _("The filesystem already has a journal.\n"));
329 exit(1);
330 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000331 if (journal_device) {
332 check_plausibility(journal_device);
333 check_mount(journal_device, 0, _("journal"));
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000334 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
335 EXT2_FLAG_JOURNAL_DEV_OK, 0,
336 fs->blocksize, unix_io_manager, &jfs);
337 if (retval) {
338 com_err(program_name, retval,
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000339 _("\n\twhile trying to open journal on %s\n"),
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000340 journal_device);
341 exit(1);
342 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000343 printf(_("Creating journal on device %s: "),
344 journal_device);
Theodore Ts'o4055ef72001-01-14 16:11:14 +0000345 fflush(stdout);
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000346
347 retval = ext2fs_add_journal_device(fs, jfs);
Theodore Ts'o63985322001-01-03 17:02:13 +0000348 if (retval) {
349 com_err (program_name, retval,
Theodore Ts'o8d641742001-05-14 04:12:27 +0000350 _("while adding filesystem to journal on %s"),
Theodore Ts'o63985322001-01-03 17:02:13 +0000351 journal_device);
352 exit(1);
353 }
354 printf(_("done\n"));
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000355 ext2fs_close(jfs);
Theodore Ts'o63985322001-01-03 17:02:13 +0000356 } else if (journal_size) {
Theodore Ts'o63985322001-01-03 17:02:13 +0000357 printf(_("Creating journal inode: "));
358 fflush(stdout);
Theodore Ts'o2537b6d2001-03-26 20:07:13 +0000359 journal_blocks = figure_journal_size(journal_size, fs);
360
Theodore Ts'o63985322001-01-03 17:02:13 +0000361 retval = ext2fs_add_journal_inode(fs, journal_blocks,
362 journal_flags);
363 if (retval) {
364 printf("\n");
365 com_err(program_name, retval,
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000366 _("\n\twhile trying to create journal file"));
Theodore Ts'o63985322001-01-03 17:02:13 +0000367 exit(1);
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000368 } else
369 printf(_("done\n"));
Theodore Ts'o63985322001-01-03 17:02:13 +0000370 /*
371 * If the filesystem wasn't mounted, we need to force
372 * the block group descriptors out.
373 */
374 if ((mount_flags & EXT2_MF_MOUNTED) == 0)
375 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
376 }
Theodore Ts'o66cf2f62001-06-14 06:42:44 +0000377 print_check_message(fs);
Theodore Ts'o63985322001-01-03 17:02:13 +0000378}
379
Theodore Ts'o83238152001-01-09 00:16:26 +0000380/*
381 * Given argv[0], return the program name.
382 */
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000383static char *get_progname(char *argv_zero)
Theodore Ts'o83238152001-01-09 00:16:26 +0000384{
385 char *cp;
386
387 cp = strrchr(argv_zero, '/');
388 if (!cp )
389 return argv_zero;
390 else
391 return cp+1;
392}
Theodore Ts'o63985322001-01-03 17:02:13 +0000393
Theodore Ts'o896938d1999-10-23 01:04:50 +0000394
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000395static void parse_e2label_options(int argc, char ** argv)
Theodore Ts'o83238152001-01-09 00:16:26 +0000396{
397 if ((argc < 2) || (argc > 3)) {
398 fprintf(stderr, _("Usage: e2label device [newlabel]\n"));
399 exit(1);
400 }
401 device_name = argv[1];
402 if (argc == 3) {
403 open_flag = EXT2_FLAG_RW;
404 L_flag = 1;
405 new_label = argv[2];
406 } else
407 print_label++;
408}
409
410
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000411static void parse_tune2fs_options(int argc, char **argv)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000412{
Theodore Ts'o519149f1997-10-25 03:49:49 +0000413 int c;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000414 char * tmp;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000415 struct group * gr;
416 struct passwd * pw;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000417
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000418 fprintf (stderr, _("tune2fs %s, %s for EXT2 FS %s, %s\n"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000419 E2FSPROGS_VERSION, E2FSPROGS_DATE,
420 EXT2FS_VERSION, EXT2FS_DATE);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000421 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 +0000422 switch (c)
423 {
424 case 'c':
Theodore Ts'o45d9e2f2000-07-07 03:12:54 +0000425 max_mount_count = strtol (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000426 if (*tmp || max_mount_count > 16000) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000427 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000428 _("bad mounts count - %s"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000429 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000430 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000431 }
Theodore Ts'oce57f142001-04-26 04:25:39 +0000432 if (max_mount_count == 0)
433 max_mount_count = -1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000434 c_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000435 open_flag = EXT2_FLAG_RW;
436 break;
437 case 'C':
438 mount_count = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000439 if (*tmp || mount_count > 16000) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000440 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000441 _("bad mounts count - %s"),
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000442 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000443 usage();
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000444 }
445 C_flag = 1;
446 open_flag = EXT2_FLAG_RW;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000447 break;
448 case 'e':
449 if (strcmp (optarg, "continue") == 0)
450 errors = EXT2_ERRORS_CONTINUE;
451 else if (strcmp (optarg, "remount-ro") == 0)
452 errors = EXT2_ERRORS_RO;
453 else if (strcmp (optarg, "panic") == 0)
454 errors = EXT2_ERRORS_PANIC;
Theodore Ts'o818180c1998-06-27 05:11:14 +0000455 else {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000456 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000457 _("bad error behavior - %s"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000458 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000459 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000460 }
461 e_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000462 open_flag = EXT2_FLAG_RW;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000463 break;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000464 case 'f': /* Force */
465 f_flag = 1;
466 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000467 case 'g':
468 resgid = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000469 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000470 gr = getgrnam (optarg);
471 if (gr == NULL)
472 tmp = optarg;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000473 else {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000474 resgid = gr->gr_gid;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000475 *tmp =0;
476 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000477 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000478 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000479 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000480 _("bad gid/group name - %s"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000481 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000482 usage();
Theodore Ts'of3db3561997-04-26 13:34:30 +0000483 }
484 g_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000485 open_flag = EXT2_FLAG_RW;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000486 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000487 case 'i':
488 interval = strtoul (optarg, &tmp, 0);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000489 switch (*tmp) {
490 case 's':
491 tmp++;
492 break;
493 case '\0':
494 case 'd':
495 case 'D': /* days */
496 interval *= 86400;
497 if (*tmp != '\0')
Theodore Ts'o3839e651997-04-26 13:21:57 +0000498 tmp++;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000499 break;
500 case 'm':
501 case 'M': /* months! */
502 interval *= 86400 * 30;
503 tmp++;
504 break;
505 case 'w':
506 case 'W': /* weeks */
507 interval *= 86400 * 7;
508 tmp++;
509 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000510 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000511 if (*tmp || interval > (365 * 86400)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000512 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000513 _("bad interval - %s"), optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000514 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000515 }
516 i_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000517 open_flag = EXT2_FLAG_RW;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000518 break;
Theodore Ts'o63985322001-01-03 17:02:13 +0000519 case 'j':
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000520 if (!journal_size)
521 journal_size = -1;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000522 open_flag = EXT2_FLAG_RW;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000523 break;
524 case 'J':
525 parse_journal_opts(optarg);
Theodore Ts'o63985322001-01-03 17:02:13 +0000526 open_flag = EXT2_FLAG_RW;
527 break;
Theodore Ts'o08dd8302001-01-14 16:25:58 +0000528 case 'l':
529 l_flag = 1;
530 break;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000531 case 'L':
532 new_label = optarg;
533 L_flag = 1;
534 open_flag = EXT2_FLAG_RW;
535 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000536 case 'm':
537 reserved_ratio = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000538 if (*tmp || reserved_ratio > 50) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000539 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000540 _("bad reserved block ratio - %s"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000541 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000542 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000543 }
544 m_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000545 open_flag = EXT2_FLAG_RW;
546 break;
547 case 'M':
548 new_last_mounted = optarg;
549 M_flag = 1;
550 open_flag = EXT2_FLAG_RW;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000551 break;
Theodore Ts'o896938d1999-10-23 01:04:50 +0000552 case 'O':
553 features_cmd = optarg;
554 open_flag = EXT2_FLAG_RW;
555 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000556 case 'r':
557 reserved_blocks = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000558 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000559 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000560 _("bad reserved blocks count - %s"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000561 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000562 usage();
Theodore Ts'of3db3561997-04-26 13:34:30 +0000563 }
564 r_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000565 open_flag = EXT2_FLAG_RW;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000566 break;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000567 case 's':
568 s_flag = atoi(optarg);
569 open_flag = EXT2_FLAG_RW;
570 break;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000571 case 'u':
572 resuid = strtoul (optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000573 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000574 pw = getpwnam (optarg);
575 if (pw == NULL)
576 tmp = optarg;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000577 else {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000578 resuid = pw->pw_uid;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +0000579 *tmp = 0;
580 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000581 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000582 if (*tmp) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000583 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000584 _("bad uid/user name - %s"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000585 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000586 usage();
Theodore Ts'of3db3561997-04-26 13:34:30 +0000587 }
588 u_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000589 open_flag = EXT2_FLAG_RW;
590 break;
591 case 'U':
592 new_UUID = optarg;
593 U_flag = 1;
594 open_flag = EXT2_FLAG_RW;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000595 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000596 default:
Theodore Ts'o818180c1998-06-27 05:11:14 +0000597 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000598 }
599 if (optind < argc - 1 || optind == argc)
Theodore Ts'o818180c1998-06-27 05:11:14 +0000600 usage();
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000601 if (!open_flag && !l_flag)
602 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +0000603 device_name = argv[optind];
Theodore Ts'o83238152001-01-09 00:16:26 +0000604}
605
606
607
608int main (int argc, char ** argv)
609{
610 errcode_t retval;
611 ext2_filsys fs;
612 struct ext2_super_block *sb;
613
614#ifdef ENABLE_NLS
615 setlocale(LC_MESSAGES, "");
616 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
617 textdomain(NLS_CAT_NAME);
618#endif
619 if (argc && *argv)
620 program_name = *argv;
621 initialize_ext2_error_table();
622
623 if (strcmp(get_progname(argv[0]), "e2label") == 0)
624 parse_e2label_options(argc, argv);
625 else
626 parse_tune2fs_options(argc, argv);
627
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000628 retval = ext2fs_open (device_name, open_flag, 0, 0,
629 unix_io_manager, &fs);
Theodore Ts'o818180c1998-06-27 05:11:14 +0000630 if (retval) {
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000631 com_err (program_name, retval, _("while trying to open %s"),
Theodore Ts'o3839e651997-04-26 13:21:57 +0000632 device_name);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000633 printf(_("Couldn't find valid filesystem superblock.\n"));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000634 exit(1);
635 }
Theodore Ts'o83238152001-01-09 00:16:26 +0000636 sb = fs->super;
637 if (print_label) {
638 /* For e2label emulation */
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000639 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
640 sb->s_volume_name);
Theodore Ts'o83238152001-01-09 00:16:26 +0000641 exit(0);
642 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000643 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
644 if (retval) {
645 com_err("ext2fs_check_if_mount", retval,
646 _("while determining whether %s is mounted."),
647 device_name);
Theodore Ts'o4055ef72001-01-14 16:11:14 +0000648 exit(1);
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000649 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000650 /* Normally we only need to write out the superblock */
651 fs->flags |= EXT2_FLAG_SUPER_ONLY;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000652
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000653 if (c_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000654 sb->s_max_mnt_count = max_mount_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000655 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000656 printf (_("Setting maximal mount count to %d\n"),
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000657 max_mount_count);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000658 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000659 if (C_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000660 sb->s_mnt_count = mount_count;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000661 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000662 printf (_("Setting current mount count to %d\n"), mount_count);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000663 }
664 if (e_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000665 sb->s_errors = errors;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000666 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000667 printf (_("Setting error behavior to %d\n"), errors);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000668 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000669 if (g_flag) {
670 sb->s_def_resgid = resgid;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000671 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000672 printf (_("Setting reserved blocks gid to %lu\n"), resgid);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000673 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000674 if (i_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000675 sb->s_checkinterval = interval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000676 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000677 printf (_("Setting interval between check %lu seconds\n"), interval);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000678 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000679 if (m_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000680 sb->s_r_blocks_count = (sb->s_blocks_count / 100)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000681 * reserved_ratio;
682 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000683 printf (_("Setting reserved blocks percentage to %lu (%u blocks)\n"),
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000684 reserved_ratio, sb->s_r_blocks_count);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000685 }
Theodore Ts'o818180c1998-06-27 05:11:14 +0000686 if (r_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000687 if (reserved_blocks >= sb->s_blocks_count) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000688 com_err (program_name, 0,
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000689 _("reserved blocks count is too big (%ul)"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000690 reserved_blocks);
691 exit (1);
692 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000693 sb->s_r_blocks_count = reserved_blocks;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000694 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000695 printf (_("Setting reserved blocks count to %lu\n"),
Theodore Ts'of3db3561997-04-26 13:34:30 +0000696 reserved_blocks);
697 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000698 if (s_flag == 1) {
Theodore Ts'o521e3681997-04-29 17:48:10 +0000699 if (sb->s_feature_ro_compat &
700 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000701 fprintf(stderr, _("\nThe filesystem already"
Theodore Ts'oe1a0a3e2000-02-11 05:00:19 +0000702 " has sparse superblocks.\n"));
Theodore Ts'o521e3681997-04-29 17:48:10 +0000703 else {
704 sb->s_feature_ro_compat |=
705 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000706 sb->s_state &= ~EXT2_VALID_FS;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000707 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000708 printf(_("\nSparse superblock flag set. %s"),
Theodore Ts'oa4fa1002000-02-08 21:35:41 +0000709 _(please_fsck));
Theodore Ts'o521e3681997-04-29 17:48:10 +0000710 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000711 }
712 if (s_flag == 0) {
Theodore Ts'o521e3681997-04-29 17:48:10 +0000713 if (!(sb->s_feature_ro_compat &
714 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000715 fprintf(stderr, _("\nThe filesystem already"
Theodore Ts'oe1a0a3e2000-02-11 05:00:19 +0000716 " has sparse superblocks disabled.\n"));
Theodore Ts'o521e3681997-04-29 17:48:10 +0000717 else {
718 sb->s_feature_ro_compat &=
719 ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000720 sb->s_state &= ~EXT2_VALID_FS;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000721 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
722 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000723 printf(_("\nSparse superblock flag cleared. %s"),
Theodore Ts'oa4fa1002000-02-08 21:35:41 +0000724 _(please_fsck));
Theodore Ts'o521e3681997-04-29 17:48:10 +0000725 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000726 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000727 if (u_flag) {
728 sb->s_def_resuid = resuid;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000729 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000730 printf (_("Setting reserved blocks uid to %lu\n"), resuid);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000731 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000732 if (L_flag) {
Theodore Ts'oa789d841998-03-30 01:20:55 +0000733 if (strlen(new_label) > sizeof(sb->s_volume_name))
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000734 fprintf(stderr, _("Warning: label too "
735 "long, truncating.\n"));
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000736 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
737 strncpy(sb->s_volume_name, new_label,
738 sizeof(sb->s_volume_name));
739 ext2fs_mark_super_dirty(fs);
740 }
741 if (M_flag) {
742 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
743 strncpy(sb->s_last_mounted, new_last_mounted,
744 sizeof(sb->s_last_mounted));
745 ext2fs_mark_super_dirty(fs);
746 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000747 if (features_cmd)
748 update_feature_set(fs, features_cmd);
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000749 if (journal_size || journal_device)
Theodore Ts'o63985322001-01-03 17:02:13 +0000750 add_journal(fs);
751
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000752 if (U_flag) {
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000753 if ((strcasecmp(new_UUID, "null") == 0) ||
754 (strcasecmp(new_UUID, "clear") == 0)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000755 uuid_clear(sb->s_uuid);
Theodore Ts'o63985322001-01-03 17:02:13 +0000756 } else if (strcasecmp(new_UUID, "time") == 0) {
757 uuid_generate_time(sb->s_uuid);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000758 } else if (strcasecmp(new_UUID, "random") == 0) {
759 uuid_generate(sb->s_uuid);
760 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000761 com_err(program_name, 0, _("Invalid UUID format\n"));
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000762 exit(1);
763 }
764 ext2fs_mark_super_dirty(fs);
765 }
766
Theodore Ts'o3839e651997-04-26 13:21:57 +0000767 if (l_flag)
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000768 list_super (sb);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000769 ext2fs_close (fs);
770 exit (0);
771}