]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - misc/tune2fs.c
e2fsck: Fix leaks in error paths
[thirdparty/e2fsprogs.git] / misc / tune2fs.c
CommitLineData
3839e657 1/*
4d0f2283 2 * tune2fs.c - Change the file system parameters on an ext2 file system
3839e657
TT
3 *
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 *
4d0f2283 8 * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
19c78dc0
TT
9 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the GNU Public
12 * License.
13 * %End-Header%
3839e657
TT
14 */
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
ebabf2ad 28#define _XOPEN_SOURCE 600 /* for inclusion of strptime() */
b969b1b8 29#define _BSD_SOURCE /* for inclusion of strcasecmp() */
3839e657 30#include <fcntl.h>
f3db3566 31#include <grp.h>
a418d3ad 32#ifdef HAVE_GETOPT_H
3839e657 33#include <getopt.h>
373b8337
TT
34#else
35extern char *optarg;
36extern int optind;
a418d3ad 37#endif
f3db3566 38#include <pwd.h>
3839e657 39#include <stdio.h>
f38cf3cb 40#ifdef HAVE_STDLIB_H
3839e657 41#include <stdlib.h>
f38cf3cb 42#endif
3839e657
TT
43#include <string.h>
44#include <time.h>
45#include <unistd.h>
f3db3566 46#include <sys/types.h>
64d588cf 47#include <libgen.h>
36585791 48#include <limits.h>
3839e657 49
54c637d4 50#include "ext2fs/ext2_fs.h"
3839e657
TT
51#include "ext2fs/ext2fs.h"
52#include "et/com_err.h"
1e3472c5 53#include "uuid/uuid.h"
3839e657 54#include "e2p/e2p.h"
dc2ec525 55#include "jfs_user.h"
63985320 56#include "util.h"
ed1b33e8 57#include "blkid/blkid.h"
771e8db9 58#include "quota/mkquota.h"
3839e657
TT
59
60#include "../version.h"
d9c56d3c 61#include "nls-enable.h"
3839e657 62
771e8db9
AK
63#define QOPT_ENABLE (1)
64#define QOPT_DISABLE (-1)
65
66extern int ask_yn(const char *string, int def);
67
ec43da2f
TT
68const char *program_name = "tune2fs";
69char *device_name;
70char *new_label, *new_last_mounted, *new_UUID;
71char *io_options;
4d0f2283 72static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
771e8db9 73static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
64d588cf 74static int I_flag;
d4de4aa9 75static time_t last_check_time;
83238153 76static int print_label;
63985320 77static int max_mount_count, mount_count, mount_flags;
4efbac6f
VAH
78static unsigned long interval;
79static blk64_t reserved_blocks;
ce911145 80static double reserved_ratio;
63985320
TT
81static unsigned long resgid, resuid;
82static unsigned short errors;
83238153
TT
83static int open_flag;
84static char *features_cmd;
a0c3fd5e 85static char *mntopts_cmd;
0c17cb25
TT
86static int stride, stripe_width;
87static int stride_set, stripe_width_set;
6cb27404 88static char *extended_cmd;
721b367a 89static unsigned long new_inode_size;
9a976ac7 90static char *ext_mount_opts;
771e8db9 91static int usrquota, grpquota;
3839e657 92
63985320
TT
93int journal_size, journal_flags;
94char *journal_device;
95
64d588cf
AK
96static struct list_head blk_move_list;
97
98struct blk_move {
99 struct list_head list;
7117f8d6
VAH
100 blk64_t old_loc;
101 blk64_t new_loc;
64d588cf
AK
102};
103
104
63985320 105static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
1e3472c5 106
14b596d4 107#ifdef CONFIG_BUILD_FINDFS
3e699064 108void do_findfs(int argc, char **argv);
14b596d4 109#endif
3e699064 110
818180cd 111static void usage(void)
3839e657 112{
b21e38a0 113 fprintf(stderr,
bb145b01 114 _("Usage: %s [-c max_mounts_count] [-e errors_behavior] "
b21e38a0 115 "[-g group]\n"
ff662d5d
TT
116 "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n"
117 "\t[-m reserved_blocks_percent] "
118 "[-o [^]mount_options[,...]] \n"
119 "\t[-r reserved_blocks_count] [-u user] [-C mount_count] "
120 "[-L volume_label]\n"
6cb27404
TT
121 "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n"
122 "\t[-E extended-option[,...]] [-T last_check_time] "
64d588cf 123 "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name);
ec43da2f 124 exit(1);
3839e657
TT
125}
126
896938d5 127static __u32 ok_features[3] = {
558df544 128 /* Compat */
843049c4 129 EXT3_FEATURE_COMPAT_HAS_JOURNAL |
558df544
TT
130 EXT2_FEATURE_COMPAT_DIR_INDEX,
131 /* Incompat */
a49670e6
TT
132 EXT2_FEATURE_INCOMPAT_FILETYPE |
133 EXT3_FEATURE_INCOMPAT_EXTENTS |
c2d4300b 134 EXT4_FEATURE_INCOMPAT_FLEX_BG,
558df544
TT
135 /* R/O compat */
136 EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
2be8fe43
TT
137 EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
138 EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
139 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
4e988cb4 140 EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
771e8db9
AK
141 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
142 EXT4_FEATURE_RO_COMPAT_QUOTA
896938d5
TT
143};
144
7c4a2ef5 145static __u32 clear_ok_features[3] = {
558df544 146 /* Compat */
7c4a2ef5 147 EXT3_FEATURE_COMPAT_HAS_JOURNAL |
037914e2 148 EXT2_FEATURE_COMPAT_RESIZE_INODE |
558df544
TT
149 EXT2_FEATURE_COMPAT_DIR_INDEX,
150 /* Incompat */
a49670e6
TT
151 EXT2_FEATURE_INCOMPAT_FILETYPE |
152 EXT4_FEATURE_INCOMPAT_FLEX_BG,
558df544 153 /* R/O compat */
4e988cb4 154 EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
2be8fe43
TT
155 EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
156 EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
157 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
771e8db9
AK
158 EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
159 EXT4_FEATURE_RO_COMPAT_QUOTA
896938d5
TT
160};
161
dc2ec525
TT
162/*
163 * Remove an external journal from the filesystem
164 */
165static void remove_journal_device(ext2_filsys fs)
166{
4ea7bd04 167 char *journal_path;
dc2ec525
TT
168 ext2_filsys jfs;
169 char buf[1024];
170 journal_superblock_t *jsb;
171 int i, nr_users;
172 errcode_t retval;
4d0f2283 173 int commit_remove_journal = 0;
2a29f135 174 io_manager io_ptr;
4d0f2283
TT
175
176 if (f_flag)
177 commit_remove_journal = 1; /* force removal even if error */
dc2ec525 178
2d15576d 179 uuid_unparse(fs->super->s_journal_uuid, buf);
ed1b33e8 180 journal_path = blkid_get_devname(NULL, "UUID", buf);
2d15576d 181
4ea7bd04
TT
182 if (!journal_path) {
183 journal_path =
2d15576d 184 ext2fs_find_block_device(fs->super->s_journal_dev);
4ea7bd04 185 if (!journal_path)
2d15576d
AD
186 return;
187 }
dc2ec525 188
2a29f135 189#ifdef CONFIG_TESTIO_DEBUG
f38cf3cb
TT
190 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
191 io_ptr = test_io_manager;
192 test_io_backing_manager = unix_io_manager;
193 } else
2a29f135 194#endif
f38cf3cb 195 io_ptr = unix_io_manager;
4ea7bd04 196 retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
dc2ec525 197 EXT2_FLAG_JOURNAL_DEV_OK, 0,
2a29f135 198 fs->blocksize, io_ptr, &jfs);
dc2ec525
TT
199 if (retval) {
200 com_err(program_name, retval,
201 _("while trying to open external journal"));
4d0f2283 202 goto no_valid_journal;
dc2ec525
TT
203 }
204 if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
7141b54b 205 fprintf(stderr, _("%s is not a journal device.\n"),
4ea7bd04 206 journal_path);
4d0f2283 207 goto no_valid_journal;
dc2ec525
TT
208 }
209
210 /* Get the journal superblock */
24a117ab 211 if ((retval = io_channel_read_blk64(jfs->io, 1, -1024, buf))) {
dc2ec525
TT
212 com_err(program_name, retval,
213 _("while reading journal superblock"));
4d0f2283 214 goto no_valid_journal;
dc2ec525
TT
215 }
216
217 jsb = (journal_superblock_t *) buf;
218 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
219 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
54434927 220 fputs(_("Journal superblock not found!\n"), stderr);
4d0f2283 221 goto no_valid_journal;
dc2ec525
TT
222 }
223
224 /* Find the filesystem UUID */
225 nr_users = ntohl(jsb->s_nr_users);
ec43da2f 226 for (i = 0; i < nr_users; i++) {
dc2ec525
TT
227 if (memcmp(fs->super->s_uuid,
228 &jsb->s_users[i*16], 16) == 0)
229 break;
230 }
231 if (i >= nr_users) {
efc6f628 232 fputs(_("Filesystem's UUID not found on journal device.\n"),
54434927 233 stderr);
4d0f2283
TT
234 commit_remove_journal = 1;
235 goto no_valid_journal;
dc2ec525
TT
236 }
237 nr_users--;
ec43da2f 238 for (i = 0; i < nr_users; i++)
dc2ec525
TT
239 memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16);
240 jsb->s_nr_users = htonl(nr_users);
241
242 /* Write back the journal superblock */
24a117ab 243 if ((retval = io_channel_write_blk64(jfs->io, 1, -1024, buf))) {
dc2ec525
TT
244 com_err(program_name, retval,
245 "while writing journal superblock.");
4d0f2283 246 goto no_valid_journal;
dc2ec525
TT
247 }
248
4d0f2283
TT
249 commit_remove_journal = 1;
250
251no_valid_journal:
252 if (commit_remove_journal == 0) {
54434927 253 fputs(_("Journal NOT removed\n"), stderr);
4d0f2283
TT
254 exit(1);
255 }
dc2ec525 256 fs->super->s_journal_dev = 0;
ed1b33e8 257 uuid_clear(fs->super->s_journal_uuid);
dc2ec525 258 ext2fs_mark_super_dirty(fs);
54434927 259 fputs(_("Journal removed\n"), stdout);
4ea7bd04 260 free(journal_path);
dc2ec525
TT
261}
262
194686bb 263/* Helper function for remove_journal_inode */
7117f8d6
VAH
264static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
265 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
266 blk64_t ref_block EXT2FS_ATTR((unused)),
267 int ref_offset EXT2FS_ATTR((unused)),
54434927 268 void *private EXT2FS_ATTR((unused)))
194686bb 269{
7117f8d6 270 blk64_t block;
194686bb
TT
271 int group;
272
273 block = *blocknr;
3c041a51 274 ext2fs_unmark_block_bitmap2(fs->block_map, block);
6493f8e8 275 group = ext2fs_group_of_blk2(fs, block);
d7cca6b0 276 ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) + 1);
4e988cb4 277 ext2fs_group_desc_csum_set(fs, group);
fe75afbf 278 ext2fs_free_blocks_count_add(fs->super, EXT2FS_CLUSTER_RATIO(fs));
194686bb
TT
279 return 0;
280}
281
282/*
283 * Remove the journal inode from the filesystem
284 */
285static void remove_journal_inode(ext2_filsys fs)
286{
287 struct ext2_inode inode;
288 errcode_t retval;
289 ino_t ino = fs->super->s_journal_inum;
efc6f628 290
194686bb
TT
291 retval = ext2fs_read_inode(fs, ino, &inode);
292 if (retval) {
293 com_err(program_name, retval,
294 _("while reading journal inode"));
295 exit(1);
296 }
297 if (ino == EXT2_JOURNAL_INO) {
298 retval = ext2fs_read_bitmaps(fs);
299 if (retval) {
300 com_err(program_name, retval,
301 _("while reading bitmaps"));
302 exit(1);
303 }
7117f8d6
VAH
304 retval = ext2fs_block_iterate3(fs, ino,
305 BLOCK_FLAG_READ_ONLY, NULL,
306 release_blocks_proc, NULL);
194686bb
TT
307 if (retval) {
308 com_err(program_name, retval,
309 _("while clearing journal inode"));
310 exit(1);
311 }
312 memset(&inode, 0, sizeof(inode));
313 ext2fs_mark_bb_dirty(fs);
194686bb
TT
314 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
315 } else
316 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
317 retval = ext2fs_write_inode(fs, ino, &inode);
318 if (retval) {
319 com_err(program_name, retval,
320 _("while writing journal inode"));
321 exit(1);
322 }
323 fs->super->s_journal_inum = 0;
324 ext2fs_mark_super_dirty(fs);
325}
dc2ec525 326
a0c3fd5e
TT
327/*
328 * Update the default mount options
329 */
330static void update_mntopts(ext2_filsys fs, char *mntopts)
331{
ec43da2f 332 struct ext2_super_block *sb = fs->super;
a0c3fd5e
TT
333
334 if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) {
335 fprintf(stderr, _("Invalid mount option set: %s\n"),
336 mntopts);
337 exit(1);
338 }
339 ext2fs_mark_super_dirty(fs);
340}
341
079ad63d
TT
342static void request_fsck_afterwards(ext2_filsys fs)
343{
344 static int requested = 0;
345
346 if (requested++)
347 return;
348 fs->super->s_state &= ~EXT2_VALID_FS;
349 printf("\n%s\n", _(please_fsck));
350 if (mount_flags & EXT2_MF_READONLY)
351 printf(_("(and reboot afterwards!)\n"));
352}
353
63985320
TT
354/*
355 * Update the feature set as provided by the user.
356 */
c8c071a0 357static void update_feature_set(ext2_filsys fs, char *features)
63985320 358{
ec43da2f 359 struct ext2_super_block *sb = fs->super;
079ad63d 360 struct ext2_group_desc *gd;
885bf6b8 361 __u32 old_features[3];
079ad63d 362 int i, type_err;
7c4a2ef5 363 unsigned int mask_err;
2eb3b20e 364
885bf6b8
TT
365#define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \
366 ((&sb->s_feature_compat)[(type)] & (mask)))
367#define FEATURE_OFF(type, mask) ((old_features[(type)] & (mask)) && \
368 !((&sb->s_feature_compat)[(type)] & (mask)))
369#define FEATURE_CHANGED(type, mask) ((mask) & \
370 (old_features[(type)] ^ (&sb->s_feature_compat)[(type)]))
371
372 old_features[E2P_FEATURE_COMPAT] = sb->s_feature_compat;
373 old_features[E2P_FEATURE_INCOMPAT] = sb->s_feature_incompat;
374 old_features[E2P_FEATURE_RO_INCOMPAT] = sb->s_feature_ro_compat;
375
7c4a2ef5
TT
376 if (e2p_edit_feature2(features, &sb->s_feature_compat,
377 ok_features, clear_ok_features,
378 &type_err, &mask_err)) {
379 if (!mask_err)
380 fprintf(stderr,
381 _("Invalid filesystem option set: %s\n"),
382 features);
383 else if (type_err & E2P_FEATURE_NEGATE_FLAG)
384 fprintf(stderr, _("Clearing filesystem feature '%s' "
385 "not supported.\n"),
386 e2p_feature2string(type_err &
387 E2P_FEATURE_TYPE_MASK,
388 mask_err));
389 else
390 fprintf(stderr, _("Setting filesystem feature '%s' "
391 "not supported.\n"),
392 e2p_feature2string(type_err, mask_err));
63985320
TT
393 exit(1);
394 }
885bf6b8
TT
395
396 if (FEATURE_OFF(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
63985320
TT
397 if ((mount_flags & EXT2_MF_MOUNTED) &&
398 !(mount_flags & EXT2_MF_READONLY)) {
2be8fe43 399 fputs(_("The has_journal feature may only be "
54434927
TT
400 "cleared when the filesystem is\n"
401 "unmounted or mounted "
402 "read-only.\n"), stderr);
63985320
TT
403 exit(1);
404 }
405 if (sb->s_feature_incompat &
406 EXT3_FEATURE_INCOMPAT_RECOVER) {
54434927
TT
407 fputs(_("The needs_recovery flag is set. "
408 "Please run e2fsck before clearing\n"
409 "the has_journal flag.\n"), stderr);
63985320
TT
410 exit(1);
411 }
63985320 412 if (sb->s_journal_inum) {
194686bb 413 remove_journal_inode(fs);
63985320 414 }
de49f015 415 if (sb->s_journal_dev) {
dc2ec525 416 remove_journal_device(fs);
de49f015 417 }
63985320 418 }
885bf6b8
TT
419
420 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
63985320
TT
421 /*
422 * If adding a journal flag, let the create journal
7a0516a3
BS
423 * code below handle setting the flag and creating the
424 * journal. We supply a default size if necessary.
63985320 425 */
dc2ec525
TT
426 if (!journal_size)
427 journal_size = -1;
08dd830d 428 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
63985320 429 }
885bf6b8
TT
430
431 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) {
843049c4 432 if (!sb->s_def_hash_version)
d1070d91 433 sb->s_def_hash_version = EXT2_HASH_HALF_MD4;
843049c4
TT
434 if (uuid_is_null((unsigned char *) sb->s_hash_seed))
435 uuid_generate((unsigned char *) sb->s_hash_seed);
436 }
dc2ec525 437
a49670e6 438 if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
c2d4300b
JS
439 if (ext2fs_check_desc(fs)) {
440 fputs(_("Clearing the flex_bg flag would "
441 "cause the the filesystem to be\n"
442 "inconsistent.\n"), stderr);
443 exit(1);
444 }
445 }
dc2ec525 446
2be8fe43
TT
447 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
448 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
449 if ((mount_flags & EXT2_MF_MOUNTED) &&
450 !(mount_flags & EXT2_MF_READONLY)) {
451 fputs(_("The huge_file feature may only be "
452 "cleared when the filesystem is\n"
453 "unmounted or mounted "
454 "read-only.\n"), stderr);
455 exit(1);
456 }
457 }
458
079ad63d
TT
459 if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
460 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
7117f8d6
VAH
461 for (i = 0; i < fs->group_desc_count; i++) {
462 gd = ext2fs_group_desc(fs, fs->group_desc, i);
079ad63d
TT
463 gd->bg_itable_unused = 0;
464 gd->bg_flags = EXT2_BG_INODE_ZEROED;
465 ext2fs_group_desc_csum_set(fs, i);
466 }
467 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
468 }
469
470 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
471 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
7117f8d6
VAH
472 for (i = 0; i < fs->group_desc_count; i++) {
473 gd = ext2fs_group_desc(fs, fs->group_desc, i);
079ad63d
TT
474 if ((gd->bg_flags & EXT2_BG_INODE_ZEROED) == 0) {
475 /*
476 * XXX what we really should do is zap
477 * uninitialized inode tables instead.
478 */
479 request_fsck_afterwards(fs);
480 break;
481 }
482 gd->bg_itable_unused = 0;
483 gd->bg_flags = 0;
484 gd->bg_checksum = 0;
485 }
486 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
487 }
488
771e8db9
AK
489 if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
490 EXT4_FEATURE_RO_COMPAT_QUOTA)) {
491 /*
492 * Set the Q_flag here and handle the quota options in the code
493 * below.
494 */
495 if (!Q_flag) {
496 Q_flag = 1;
497 /* Enable both user quota and group quota by default */
498 usrquota = QOPT_ENABLE;
499 grpquota = QOPT_ENABLE;
500 }
501 sb->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA;
502 }
503
504 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
505 EXT4_FEATURE_RO_COMPAT_QUOTA)) {
506 /*
507 * Set the Q_flag here and handle the quota options in the code
508 * below.
509 */
510 if (Q_flag)
511 fputs(_("\nWarning: '^quota' option overrides '-Q'"
512 "arguments.\n"), stderr);
513 Q_flag = 1;
514 /* Disable both user quota and group quota by default */
515 usrquota = QOPT_DISABLE;
516 grpquota = QOPT_DISABLE;
517 }
518
63985320
TT
519 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
520 (sb->s_feature_compat || sb->s_feature_ro_compat ||
521 sb->s_feature_incompat))
522 ext2fs_update_dynamic_rev(fs);
885bf6b8
TT
523
524 if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT,
525 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
2be8fe43
TT
526 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
527 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
885bf6b8 528 FEATURE_CHANGED(E2P_FEATURE_INCOMPAT,
037914e2
TT
529 EXT2_FEATURE_INCOMPAT_FILETYPE) ||
530 FEATURE_CHANGED(E2P_FEATURE_COMPAT,
558df544
TT
531 EXT2_FEATURE_COMPAT_RESIZE_INODE) ||
532 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
079ad63d
TT
533 EXT2_FEATURE_RO_COMPAT_LARGE_FILE))
534 request_fsck_afterwards(fs);
885bf6b8
TT
535
536 if ((old_features[E2P_FEATURE_COMPAT] != sb->s_feature_compat) ||
537 (old_features[E2P_FEATURE_INCOMPAT] != sb->s_feature_incompat) ||
538 (old_features[E2P_FEATURE_RO_INCOMPAT] != sb->s_feature_ro_compat))
2eb3b20e 539 ext2fs_mark_super_dirty(fs);
63985320
TT
540}
541
542/*
543 * Add a journal to the filesystem.
544 */
545static void add_journal(ext2_filsys fs)
546{
547 unsigned long journal_blocks;
548 errcode_t retval;
16ed5b3a 549 ext2_filsys jfs;
2a29f135 550 io_manager io_ptr;
63985320
TT
551
552 if (fs->super->s_feature_compat &
553 EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
54434927 554 fputs(_("The filesystem already has a journal.\n"), stderr);
2d15576d 555 goto err;
63985320 556 }
63985320
TT
557 if (journal_device) {
558 check_plausibility(journal_device);
559 check_mount(journal_device, 0, _("journal"));
2a29f135 560#ifdef CONFIG_TESTIO_DEBUG
f38cf3cb
TT
561 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
562 io_ptr = test_io_manager;
563 test_io_backing_manager = unix_io_manager;
564 } else
2a29f135 565#endif
f38cf3cb 566 io_ptr = unix_io_manager;
16ed5b3a
TT
567 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
568 EXT2_FLAG_JOURNAL_DEV_OK, 0,
2a29f135 569 fs->blocksize, io_ptr, &jfs);
16ed5b3a
TT
570 if (retval) {
571 com_err(program_name, retval,
1d08d9bf 572 _("\n\twhile trying to open journal on %s\n"),
16ed5b3a 573 journal_device);
2d15576d 574 goto err;
16ed5b3a 575 }
63985320
TT
576 printf(_("Creating journal on device %s: "),
577 journal_device);
4055ef73 578 fflush(stdout);
2d15576d 579
16ed5b3a 580 retval = ext2fs_add_journal_device(fs, jfs);
2d15576d 581 ext2fs_close(jfs);
63985320 582 if (retval) {
ec43da2f
TT
583 com_err(program_name, retval,
584 _("while adding filesystem to journal on %s"),
585 journal_device);
2d15576d 586 goto err;
63985320 587 }
54434927 588 fputs(_("done\n"), stdout);
63985320 589 } else if (journal_size) {
54434927 590 fputs(_("Creating journal inode: "), stdout);
63985320 591 fflush(stdout);
2537b6d0
TT
592 journal_blocks = figure_journal_size(journal_size, fs);
593
63985320
TT
594 retval = ext2fs_add_journal_inode(fs, journal_blocks,
595 journal_flags);
596 if (retval) {
7141b54b 597 fprintf(stderr, "\n");
63985320 598 com_err(program_name, retval,
1d08d9bf 599 _("\n\twhile trying to create journal file"));
63985320 600 exit(1);
1d08d9bf 601 } else
54434927 602 fputs(_("done\n"), stdout);
63985320
TT
603 /*
604 * If the filesystem wasn't mounted, we need to force
605 * the block group descriptors out.
606 */
607 if ((mount_flags & EXT2_MF_MOUNTED) == 0)
608 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
609 }
faa2dcda
LC
610 print_check_message(fs->super->s_max_mnt_count,
611 fs->super->s_checkinterval);
2d15576d
AD
612 return;
613
614err:
45e338f5 615 free(journal_device);
2d15576d 616 exit(1);
63985320
TT
617}
618
771e8db9
AK
619void handle_quota_options(ext2_filsys fs)
620{
621 quota_ctx_t qctx;
622 errcode_t retval;
623 ext2_ino_t qf_ino;
624
625 if (!usrquota && !grpquota)
626 /* Nothing to do. */
627 return;
628
629 init_quota_context(&qctx, fs, -1);
630
631 if (usrquota == QOPT_ENABLE && !fs->super->s_usr_quota_inum) {
632 if ((qf_ino = quota_file_exists(fs, USRQUOTA, QFMT_VFS_V1)) > 0)
633 set_sb_quota_inum(fs, qf_ino, USRQUOTA);
634 else
635 write_quota_inode(qctx, USRQUOTA);
636 } else if (usrquota == QOPT_DISABLE) {
637 remove_quota_inode(fs, USRQUOTA);
638 }
639
640 if (grpquota == QOPT_ENABLE && !fs->super->s_grp_quota_inum) {
641 if ((qf_ino = quota_file_exists(fs, GRPQUOTA, QFMT_VFS_V1)) > 0)
642 set_sb_quota_inum(fs, qf_ino, GRPQUOTA);
643 else
644 write_quota_inode(qctx, GRPQUOTA);
645 } else if (grpquota == QOPT_DISABLE) {
646 remove_quota_inode(fs, GRPQUOTA);
647 }
648
649 release_quota_context(&qctx);
650
651 if ((usrquota == QOPT_ENABLE) || (grpquota == QOPT_ENABLE)) {
652 fs->super->s_feature_ro_compat |= EXT4_FEATURE_RO_COMPAT_QUOTA;
653 ext2fs_mark_super_dirty(fs);
654 } else if ((usrquota == QOPT_DISABLE) && (grpquota == QOPT_DISABLE)) {
655 fs->super->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA;
656 ext2fs_mark_super_dirty(fs);
657 }
658
659 return;
660}
661
662void parse_quota_opts(const char *opts)
663{
664 char *buf, *token, *next, *p, *arg;
665 int len;
666
667 len = strlen(opts);
668 buf = malloc(len+1);
669 if (!buf) {
670 fputs(_("Couldn't allocate memory to parse quota "
671 "options!\n"), stderr);
672 exit(1);
673 }
674 strcpy(buf, opts);
675 for (token = buf; token && *token; token = next) {
676 p = strchr(token, ',');
677 next = 0;
678 if (p) {
679 *p = 0;
680 next = p+1;
681 }
682
683 if (strcmp(token, "usrquota") == 0) {
684 usrquota = QOPT_ENABLE;
685 } else if (strcmp(token, "^usrquota") == 0) {
686 usrquota = QOPT_DISABLE;
687 } else if (strcmp(token, "grpquota") == 0) {
688 grpquota = QOPT_ENABLE;
689 } else if (strcmp(token, "^grpquota") == 0) {
690 grpquota = QOPT_DISABLE;
691 } else {
692 fputs(_("\nBad quota options specified.\n\n"
693 "Following valid quota options are available "
694 "(pass by separating with comma):\n"
695 "\t[^]usrquota\n"
696 "\t[^]grpquota\n"
697 "\n\n"), stderr);
698 free(buf);
699 exit(1);
700 }
701 }
702 free(buf);
703}
704
705
83238153 706
c8c071a0 707static void parse_e2label_options(int argc, char ** argv)
83238153
TT
708{
709 if ((argc < 2) || (argc > 3)) {
54434927 710 fputs(_("Usage: e2label device [newlabel]\n"), stderr);
83238153
TT
711 exit(1);
712 }
2e8ca9a2
TT
713 io_options = strchr(argv[1], '?');
714 if (io_options)
715 *io_options++ = 0;
332f2c23 716 device_name = blkid_get_devname(NULL, argv[1], NULL);
817e49e3 717 if (!device_name) {
efc6f628 718 com_err("e2label", 0, _("Unable to resolve '%s'"),
817e49e3
TT
719 argv[1]);
720 exit(1);
721 }
2be8fe43 722 open_flag = EXT2_FLAG_JOURNAL_DEV_OK;
83238153 723 if (argc == 3) {
0ddfd9a5 724 open_flag |= EXT2_FLAG_RW;
83238153
TT
725 L_flag = 1;
726 new_label = argv[2];
efc6f628 727 } else
83238153
TT
728 print_label++;
729}
730
d4de4aa9
TT
731static time_t parse_time(char *str)
732{
733 struct tm ts;
734
735 if (strcmp(str, "now") == 0) {
736 return (time(0));
737 }
738 memset(&ts, 0, sizeof(ts));
bc7c14e0 739#ifdef HAVE_STRPTIME
690e693c 740 strptime(str, "%Y%m%d%H%M%S", &ts);
bc7c14e0 741#else
690e693c 742 sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
bc7c14e0
TT
743 &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
744 ts.tm_year -= 1900;
745 ts.tm_mon -= 1;
746 if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
747 ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
748 ts.tm_min > 59 || ts.tm_sec > 61)
749 ts.tm_mday = 0;
750#endif
d4de4aa9
TT
751 if (ts.tm_mday == 0) {
752 com_err(program_name, 0,
753 _("Couldn't parse date/time specifier: %s"),
754 str);
755 usage();
756 }
a2ff0f31 757 ts.tm_isdst = -1;
d4de4aa9
TT
758 return (mktime(&ts));
759}
83238153 760
c8c071a0 761static void parse_tune2fs_options(int argc, char **argv)
3839e657 762{
519149fb 763 int c;
ec43da2f
TT
764 char *tmp;
765 struct group *gr;
766 struct passwd *pw;
3839e657 767
2be8fe43 768 open_flag = 0;
0ddfd9a5 769
0f8973fb 770 printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
771e8db9 771 while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:Q:T:U:")) != EOF)
ec43da2f
TT
772 switch (c) {
773 case 'c':
774 max_mount_count = strtol(optarg, &tmp, 0);
775 if (*tmp || max_mount_count > 16000) {
776 com_err(program_name, 0,
777 _("bad mounts count - %s"),
778 optarg);
779 usage();
780 }
781 if (max_mount_count == 0)
782 max_mount_count = -1;
783 c_flag = 1;
784 open_flag = EXT2_FLAG_RW;
785 break;
786 case 'C':
787 mount_count = strtoul(optarg, &tmp, 0);
788 if (*tmp || mount_count > 16000) {
789 com_err(program_name, 0,
790 _("bad mounts count - %s"),
791 optarg);
792 usage();
793 }
794 C_flag = 1;
795 open_flag = EXT2_FLAG_RW;
796 break;
797 case 'e':
798 if (strcmp(optarg, "continue") == 0)
799 errors = EXT2_ERRORS_CONTINUE;
800 else if (strcmp(optarg, "remount-ro") == 0)
801 errors = EXT2_ERRORS_RO;
802 else if (strcmp(optarg, "panic") == 0)
803 errors = EXT2_ERRORS_PANIC;
804 else {
805 com_err(program_name, 0,
806 _("bad error behavior - %s"),
807 optarg);
808 usage();
809 }
810 e_flag = 1;
811 open_flag = EXT2_FLAG_RW;
812 break;
813 case 'E':
814 extended_cmd = optarg;
815 open_flag |= EXT2_FLAG_RW;
816 break;
817 case 'f': /* Force */
818 f_flag = 1;
819 break;
820 case 'g':
821 resgid = strtoul(optarg, &tmp, 0);
822 if (*tmp) {
823 gr = getgrnam(optarg);
824 if (gr == NULL)
825 tmp = optarg;
818180cd 826 else {
ec43da2f
TT
827 resgid = gr->gr_gid;
828 *tmp = 0;
f3db3566 829 }
ec43da2f
TT
830 }
831 if (*tmp) {
832 com_err(program_name, 0,
833 _("bad gid/group name - %s"),
834 optarg);
835 usage();
836 }
837 g_flag = 1;
838 open_flag = EXT2_FLAG_RW;
839 break;
840 case 'i':
841 interval = strtoul(optarg, &tmp, 0);
842 switch (*tmp) {
843 case 's':
844 tmp++;
f3db3566 845 break;
ec43da2f
TT
846 case '\0':
847 case 'd':
848 case 'D': /* days */
849 interval *= 86400;
850 if (*tmp != '\0')
1e3472c5 851 tmp++;
1e3472c5 852 break;
3839e657 853 case 'm':
ec43da2f
TT
854 case 'M': /* months! */
855 interval *= 86400 * 30;
856 tmp++;
3839e657 857 break;
ec43da2f
TT
858 case 'w':
859 case 'W': /* weeks */
860 interval *= 86400 * 7;
861 tmp++;
a0c3fd5e 862 break;
ec43da2f
TT
863 }
864 if (*tmp) {
865 com_err(program_name, 0,
866 _("bad interval - %s"), optarg);
867 usage();
868 }
869 i_flag = 1;
870 open_flag = EXT2_FLAG_RW;
871 break;
872 case 'j':
873 if (!journal_size)
874 journal_size = -1;
875 open_flag = EXT2_FLAG_RW;
876 break;
877 case 'J':
878 parse_journal_opts(optarg);
879 open_flag = EXT2_FLAG_RW;
880 break;
881 case 'l':
882 l_flag = 1;
883 break;
884 case 'L':
885 new_label = optarg;
886 L_flag = 1;
887 open_flag |= EXT2_FLAG_RW |
888 EXT2_FLAG_JOURNAL_DEV_OK;
889 break;
890 case 'm':
891 reserved_ratio = strtod(optarg, &tmp);
8d822455
TT
892 if (*tmp || reserved_ratio > 50 ||
893 reserved_ratio < 0) {
ec43da2f
TT
894 com_err(program_name, 0,
895 _("bad reserved block ratio - %s"),
896 optarg);
897 usage();
898 }
899 m_flag = 1;
900 open_flag = EXT2_FLAG_RW;
901 break;
902 case 'M':
903 new_last_mounted = optarg;
904 M_flag = 1;
905 open_flag = EXT2_FLAG_RW;
906 break;
907 case 'o':
908 if (mntopts_cmd) {
909 com_err(program_name, 0,
910 _("-o may only be specified once"));
911 usage();
912 }
913 mntopts_cmd = optarg;
914 open_flag = EXT2_FLAG_RW;
915 break;
916
917 case 'O':
918 if (features_cmd) {
919 com_err(program_name, 0,
920 _("-O may only be specified once"));
921 usage();
922 }
923 features_cmd = optarg;
924 open_flag = EXT2_FLAG_RW;
925 break;
771e8db9
AK
926 case 'Q':
927 Q_flag = 1;
928 parse_quota_opts(optarg);
929 open_flag = EXT2_FLAG_RW;
930 break;
ec43da2f
TT
931 case 'r':
932 reserved_blocks = strtoul(optarg, &tmp, 0);
933 if (*tmp) {
934 com_err(program_name, 0,
935 _("bad reserved blocks count - %s"),
936 optarg);
937 usage();
938 }
939 r_flag = 1;
940 open_flag = EXT2_FLAG_RW;
941 break;
942 case 's': /* Deprecated */
943 s_flag = atoi(optarg);
944 open_flag = EXT2_FLAG_RW;
945 break;
946 case 'T':
947 T_flag = 1;
948 last_check_time = parse_time(optarg);
949 open_flag = EXT2_FLAG_RW;
950 break;
951 case 'u':
952 resuid = strtoul(optarg, &tmp, 0);
818180cd 953 if (*tmp) {
ec43da2f 954 pw = getpwnam(optarg);
f3db3566
TT
955 if (pw == NULL)
956 tmp = optarg;
a418d3ad 957 else {
f3db3566 958 resuid = pw->pw_uid;
a418d3ad
TT
959 *tmp = 0;
960 }
f3db3566 961 }
818180cd 962 if (*tmp) {
ec43da2f
TT
963 com_err(program_name, 0,
964 _("bad uid/user name - %s"),
965 optarg);
818180cd 966 usage();
f3db3566
TT
967 }
968 u_flag = 1;
1e3472c5
TT
969 open_flag = EXT2_FLAG_RW;
970 break;
ec43da2f
TT
971 case 'U':
972 new_UUID = optarg;
973 U_flag = 1;
974 open_flag = EXT2_FLAG_RW |
975 EXT2_FLAG_JOURNAL_DEV_OK;
976 break;
977 case 'I':
978 new_inode_size = strtoul(optarg, &tmp, 0);
979 if (*tmp) {
980 com_err(program_name, 0,
981 _("bad inode size - %s"),
982 optarg);
818180cd 983 usage();
ec43da2f
TT
984 }
985 if (!((new_inode_size &
986 (new_inode_size - 1)) == 0)) {
987 com_err(program_name, 0,
988 _("Inode size must be a "
989 "power of two- %s"),
990 optarg);
991 usage();
992 }
993 open_flag = EXT2_FLAG_RW;
994 I_flag = 1;
995 break;
996 default:
997 usage();
3839e657
TT
998 }
999 if (optind < argc - 1 || optind == argc)
818180cd 1000 usage();
1e3472c5
TT
1001 if (!open_flag && !l_flag)
1002 usage();
2e8ca9a2
TT
1003 io_options = strchr(argv[optind], '?');
1004 if (io_options)
1005 *io_options++ = 0;
332f2c23 1006 device_name = blkid_get_devname(NULL, argv[optind], NULL);
817e49e3 1007 if (!device_name) {
efc6f628 1008 com_err("tune2fs", 0, _("Unable to resolve '%s'"),
817e49e3
TT
1009 argv[optind]);
1010 exit(1);
1011 }
118d7dac
TT
1012}
1013
14b596d4 1014#ifdef CONFIG_BUILD_FINDFS
3e699064 1015void do_findfs(int argc, char **argv)
118d7dac
TT
1016{
1017 char *dev;
83238153 1018
118d7dac
TT
1019 if ((argc != 2) ||
1020 (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) {
1021 fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n");
1022 exit(2);
1023 }
ed1b33e8 1024 dev = blkid_get_devname(NULL, argv[1], NULL);
118d7dac 1025 if (!dev) {
efc6f628 1026 com_err("findfs", 0, _("Unable to resolve '%s'"),
118d7dac
TT
1027 argv[1]);
1028 exit(1);
1029 }
1030 puts(dev);
1031 exit(0);
1032}
14b596d4 1033#endif
83238153 1034
6cb27404
TT
1035static void parse_extended_opts(ext2_filsys fs, const char *opts)
1036{
1037 char *buf, *token, *next, *p, *arg;
10ff68d4 1038 int len, hash_alg;
6cb27404
TT
1039 int r_usage = 0;
1040
1041 len = strlen(opts);
1042 buf = malloc(len+1);
1043 if (!buf) {
1044 fprintf(stderr,
1045 _("Couldn't allocate memory to parse options!\n"));
1046 exit(1);
1047 }
1048 strcpy(buf, opts);
1049 for (token = buf; token && *token; token = next) {
1050 p = strchr(token, ',');
1051 next = 0;
1052 if (p) {
1053 *p = 0;
1054 next = p+1;
1055 }
1056 arg = strchr(token, '=');
1057 if (arg) {
1058 *arg = 0;
1059 arg++;
1060 }
1061 if (!strcmp(token, "test_fs")) {
1062 fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
1063 printf("Setting test filesystem flag\n");
1064 ext2fs_mark_super_dirty(fs);
1065 } else if (!strcmp(token, "^test_fs")) {
1066 fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS;
1067 printf("Clearing test filesystem flag\n");
1068 ext2fs_mark_super_dirty(fs);
0c17cb25
TT
1069 } else if (strcmp(token, "stride") == 0) {
1070 if (!arg) {
1071 r_usage++;
1072 continue;
1073 }
1074 stride = strtoul(arg, &p, 0);
035f32ab 1075 if (*p) {
0c17cb25
TT
1076 fprintf(stderr,
1077 _("Invalid RAID stride: %s\n"),
1078 arg);
1079 r_usage++;
1080 continue;
1081 }
1082 stride_set = 1;
1083 } else if (strcmp(token, "stripe-width") == 0 ||
1084 strcmp(token, "stripe_width") == 0) {
1085 if (!arg) {
1086 r_usage++;
1087 continue;
1088 }
1089 stripe_width = strtoul(arg, &p, 0);
035f32ab 1090 if (*p) {
0c17cb25
TT
1091 fprintf(stderr,
1092 _("Invalid RAID stripe-width: %s\n"),
1093 arg);
1094 r_usage++;
1095 continue;
1096 }
1097 stripe_width_set = 1;
10ff68d4
TT
1098 } else if (strcmp(token, "hash_alg") == 0 ||
1099 strcmp(token, "hash-alg") == 0) {
1100 if (!arg) {
1101 r_usage++;
1102 continue;
1103 }
1104 hash_alg = e2p_string2hash(arg);
1105 if (hash_alg < 0) {
ec43da2f 1106 fprintf(stderr,
10ff68d4
TT
1107 _("Invalid hash algorithm: %s\n"),
1108 arg);
1109 r_usage++;
1110 continue;
1111 }
1112 fs->super->s_def_hash_version = hash_alg;
1113 printf(_("Setting default hash algorithm "
ec43da2f 1114 "to %s (%d)\n"),
10ff68d4
TT
1115 arg, hash_alg);
1116 ext2fs_mark_super_dirty(fs);
9a976ac7 1117 } else if (!strcmp(token, "mount_opts")) {
9345f026
TT
1118 if (!arg) {
1119 r_usage++;
1120 continue;
1121 }
1122 if (strlen(arg) >= sizeof(fs->super->s_mount_opts)) {
1123 fprintf(stderr,
1124 "Extended mount options too long\n");
1125 continue;
1126 }
9a976ac7 1127 ext_mount_opts = strdup(arg);
efc6f628 1128 } else
6cb27404
TT
1129 r_usage++;
1130 }
1131 if (r_usage) {
1132 fprintf(stderr, _("\nBad options specified.\n\n"
1133 "Extended options are separated by commas, "
1134 "and may take an argument which\n"
1135 "\tis set off by an equals ('=') sign.\n\n"
1136 "Valid extended options are:\n"
9a976ac7
TT
1137 "\thash_alg=<hash algorithm>\n"
1138 "\tmount_opts=<extended default mount options>\n"
0c17cb25 1139 "\tstride=<RAID per-disk chunk size in blocks>\n"
10ff68d4 1140 "\tstripe_width=<RAID stride*data disks in blocks>\n"
6cb27404
TT
1141 "\ttest_fs\n"
1142 "\t^test_fs\n"));
1143 free(buf);
1144 exit(1);
1145 }
1146 free(buf);
efc6f628 1147}
6cb27404 1148
31f1815f 1149/*
a9e5177b
AK
1150 * Fill in the block bitmap bmap with the information regarding the
1151 * blocks to be moved
31f1815f
TT
1152 */
1153static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
a9e5177b 1154 ext2fs_block_bitmap bmap)
64d588cf
AK
1155{
1156 dgrp_t i;
154a5d75
AK
1157 int retval;
1158 ext2_badblocks_list bb_list = 0;
7117f8d6
VAH
1159 blk64_t j, needed_blocks = 0;
1160 blk64_t start_blk, end_blk;
64d588cf 1161
154a5d75
AK
1162 retval = ext2fs_read_bb_inode(fs, &bb_list);
1163 if (retval)
1164 return retval;
1165
64d588cf 1166 for (i = 0; i < fs->group_desc_count; i++) {
d7cca6b0 1167 start_blk = ext2fs_inode_table_loc(fs, i) +
64d588cf
AK
1168 fs->inode_blocks_per_group;
1169
d7cca6b0 1170 end_blk = ext2fs_inode_table_loc(fs, i) +
64d588cf
AK
1171 new_ino_blks_per_grp;
1172
1173 for (j = start_blk; j < end_blk; j++) {
3c041a51 1174 if (ext2fs_test_block_bitmap2(fs->block_map, j)) {
154a5d75
AK
1175 /*
1176 * IF the block is a bad block we fail
64d588cf 1177 */
154a5d75
AK
1178 if (ext2fs_badblocks_list_test(bb_list, j)) {
1179 ext2fs_badblocks_list_free(bb_list);
1180 return ENOSPC;
1181 }
1182
3c041a51 1183 ext2fs_mark_block_bitmap2(bmap, j);
64d588cf
AK
1184 } else {
1185 /*
1186 * We are going to use this block for
1187 * inode table. So mark them used.
1188 */
3c041a51 1189 ext2fs_mark_block_bitmap2(fs->block_map, j);
64d588cf
AK
1190 }
1191 }
a9e5177b 1192 needed_blocks += end_blk - start_blk;
64d588cf
AK
1193 }
1194
154a5d75 1195 ext2fs_badblocks_list_free(bb_list);
4efbac6f 1196 if (needed_blocks > ext2fs_free_blocks_count(fs->super))
64d588cf 1197 return ENOSPC;
64d588cf
AK
1198
1199 return 0;
1200}
1201
91fac979
AK
1202static int ext2fs_is_meta_block(ext2_filsys fs, blk_t blk)
1203{
1204 dgrp_t group;
1205 group = ext2fs_group_of_blk(fs, blk);
d7cca6b0 1206 if (ext2fs_block_bitmap_loc(fs, group) == blk)
91fac979 1207 return 1;
d7cca6b0 1208 if (ext2fs_inode_bitmap_loc(fs, group) == blk)
91fac979
AK
1209 return 1;
1210 return 0;
1211}
1212
1213static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk_t blk)
1214{
1215 blk_t start_blk, end_blk;
1216 start_blk = fs->super->s_first_data_block +
1217 EXT2_BLOCKS_PER_GROUP(fs->super) * group;
1218 /*
1219 * We cannot get new block beyond end_blk for for the last block group
1220 * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group
1221 */
1222 end_blk = start_blk + EXT2_BLOCKS_PER_GROUP(fs->super);
1223 if (blk >= start_blk && blk <= end_blk)
1224 return 1;
1225 return 0;
1226}
1227
a9e5177b 1228static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
64d588cf 1229{
91fac979 1230
64d588cf 1231 char *buf;
cf5301d7 1232 dgrp_t group = 0;
64d588cf 1233 errcode_t retval;
91fac979 1234 int meta_data = 0;
7117f8d6 1235 blk64_t blk, new_blk, goal;
64d588cf
AK
1236 struct blk_move *bmv;
1237
64d588cf
AK
1238 retval = ext2fs_get_mem(fs->blocksize, &buf);
1239 if (retval)
1240 return retval;
1241
27c6de45 1242 for (new_blk = blk = fs->super->s_first_data_block;
4efbac6f 1243 blk < ext2fs_blocks_count(fs->super); blk++) {
3c041a51 1244 if (!ext2fs_test_block_bitmap2(bmap, blk))
64d588cf
AK
1245 continue;
1246
91fac979
AK
1247 if (ext2fs_is_meta_block(fs, blk)) {
1248 /*
1249 * If the block is mapping a fs meta data block
1250 * like group desc/block bitmap/inode bitmap. We
1251 * should find a block in the same group and fix
1252 * the respective fs metadata pointers. Otherwise
1253 * fail
1254 */
1255 group = ext2fs_group_of_blk(fs, blk);
b49f78fe 1256 goal = ext2fs_group_first_block2(fs, group);
91fac979
AK
1257 meta_data = 1;
1258
1259 } else {
1260 goal = new_blk;
1261 }
7117f8d6 1262 retval = ext2fs_new_block2(fs, goal, NULL, &new_blk);
64d588cf
AK
1263 if (retval)
1264 goto err_out;
1265
91fac979
AK
1266 /* new fs meta data block should be in the same group */
1267 if (meta_data && !ext2fs_is_block_in_group(fs, group, new_blk)) {
1268 retval = ENOSPC;
1269 goto err_out;
1270 }
1271
64d588cf 1272 /* Mark this block as allocated */
3c041a51 1273 ext2fs_mark_block_bitmap2(fs->block_map, new_blk);
64d588cf
AK
1274
1275 /* Add it to block move list */
1276 retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv);
1277 if (retval)
1278 goto err_out;
1279
1280 bmv->old_loc = blk;
1281 bmv->new_loc = new_blk;
1282
1283 list_add(&(bmv->list), &blk_move_list);
1284
24a117ab 1285 retval = io_channel_read_blk64(fs->io, blk, 1, buf);
64d588cf
AK
1286 if (retval)
1287 goto err_out;
1288
24a117ab 1289 retval = io_channel_write_blk64(fs->io, new_blk, 1, buf);
64d588cf
AK
1290 if (retval)
1291 goto err_out;
1292 }
1293
1294err_out:
1295 ext2fs_free_mem(&buf);
1296 return retval;
1297}
1298
7117f8d6 1299static blk64_t translate_block(blk64_t blk)
64d588cf
AK
1300{
1301 struct list_head *entry;
1302 struct blk_move *bmv;
1303
1304 list_for_each(entry, &blk_move_list) {
64d588cf
AK
1305 bmv = list_entry(entry, struct blk_move, list);
1306 if (bmv->old_loc == blk)
1307 return bmv->new_loc;
1308 }
1309
1310 return 0;
1311}
1312
721b367a 1313static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)),
7117f8d6 1314 blk64_t *block_nr,
721b367a 1315 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
7117f8d6 1316 blk64_t ref_block EXT2FS_ATTR((unused)),
64d588cf 1317 int ref_offset EXT2FS_ATTR((unused)),
27c6de45 1318 void *priv_data)
64d588cf
AK
1319{
1320 int ret = 0;
7117f8d6 1321 blk64_t new_blk;
27c6de45 1322 ext2fs_block_bitmap bmap = (ext2fs_block_bitmap) priv_data;
64d588cf 1323
3c041a51 1324 if (!ext2fs_test_block_bitmap2(bmap, *block_nr))
27c6de45 1325 return 0;
ec43da2f 1326 new_blk = translate_block(*block_nr);
64d588cf
AK
1327 if (new_blk) {
1328 *block_nr = new_blk;
1329 /*
1330 * This will force the ext2fs_write_inode in the iterator
1331 */
1332 ret |= BLOCK_CHANGED;
1333 }
1334
1335 return ret;
1336}
1337
27c6de45 1338static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
64d588cf
AK
1339{
1340 errcode_t retval = 0;
1341 ext2_ino_t ino;
7117f8d6 1342 blk64_t blk;
64d588cf
AK
1343 char *block_buf = 0;
1344 struct ext2_inode inode;
1345 ext2_inode_scan scan = NULL;
1346
1347 retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
1348 if (retval)
1349 return retval;
1350
1351 retval = ext2fs_open_inode_scan(fs, 0, &scan);
1352 if (retval)
1353 goto err_out;
1354
1355 while (1) {
64d588cf
AK
1356 retval = ext2fs_get_next_inode(scan, &ino, &inode);
1357 if (retval)
1358 goto err_out;
1359
1360 if (!ino)
1361 break;
1362
1363 if (inode.i_links_count == 0)
1364 continue; /* inode not in use */
1365
1366 /* FIXME!!
1367 * If we end up modifying the journal inode
1368 * the sb->s_jnl_blocks will differ. But a
1369 * subsequent e2fsck fixes that.
1370 * Do we need to fix this ??
1371 */
1372
a63745e8
VAH
1373 if (ext2fs_file_acl_block(&inode) &&
1374 ext2fs_test_block_bitmap2(bmap,
1375 ext2fs_file_acl_block(&inode))) {
1376 blk = translate_block(ext2fs_file_acl_block(&inode));
64d588cf
AK
1377 if (!blk)
1378 continue;
1379
a63745e8 1380 ext2fs_file_acl_block_set(&inode, blk);
64d588cf
AK
1381
1382 /*
1383 * Write the inode to disk so that inode table
1384 * resizing can work
1385 */
1386 retval = ext2fs_write_inode(fs, ino, &inode);
1387 if (retval)
1388 goto err_out;
1389 }
1390
1391 if (!ext2fs_inode_has_valid_blocks(&inode))
1392 continue;
1393
7117f8d6 1394 retval = ext2fs_block_iterate3(fs, ino, 0, block_buf,
27c6de45 1395 process_block, bmap);
64d588cf
AK
1396 if (retval)
1397 goto err_out;
1398
1399 }
1400
1401err_out:
1402 ext2fs_free_mem(&block_buf);
1403
1404 return retval;
31f1815f
TT
1405}
1406
91fac979
AK
1407/*
1408 * We need to scan for inode and block bitmaps that may need to be
1409 * moved. This can take place if the filesystem was formatted for
1410 * RAID arrays using the mke2fs's extended option "stride".
1411 */
1412static int group_desc_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
1413{
1414 dgrp_t i;
1415 blk_t blk, new_blk;
1416
1417 for (i = 0; i < fs->group_desc_count; i++) {
d7cca6b0 1418 blk = ext2fs_block_bitmap_loc(fs, i);
3c041a51 1419 if (ext2fs_test_block_bitmap2(bmap, blk)) {
91fac979
AK
1420 new_blk = translate_block(blk);
1421 if (!new_blk)
1422 continue;
d7cca6b0 1423 ext2fs_block_bitmap_loc_set(fs, i, new_blk);
91fac979
AK
1424 }
1425
d7cca6b0 1426 blk = ext2fs_inode_bitmap_loc(fs, i);
3c041a51 1427 if (ext2fs_test_block_bitmap2(bmap, blk)) {
91fac979
AK
1428 new_blk = translate_block(blk);
1429 if (!new_blk)
1430 continue;
d7cca6b0 1431 ext2fs_inode_bitmap_loc_set(fs, i, new_blk);
91fac979
AK
1432 }
1433 }
1434 return 0;
1435}
1436
721b367a 1437static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size)
64d588cf
AK
1438{
1439 dgrp_t i;
7117f8d6 1440 blk64_t blk;
64d588cf 1441 errcode_t retval;
721b367a
TT
1442 int new_ino_blks_per_grp;
1443 unsigned int j;
64d588cf
AK
1444 char *old_itable = NULL, *new_itable = NULL;
1445 char *tmp_old_itable = NULL, *tmp_new_itable = NULL;
721b367a 1446 unsigned long old_ino_size;
64d588cf
AK
1447 int old_itable_size, new_itable_size;
1448
1449 old_itable_size = fs->inode_blocks_per_group * fs->blocksize;
721b367a 1450 old_ino_size = EXT2_INODE_SIZE(fs->super);
64d588cf
AK
1451
1452 new_ino_blks_per_grp = ext2fs_div_ceil(
1453 EXT2_INODES_PER_GROUP(fs->super) *
721b367a 1454 new_ino_size,
64d588cf
AK
1455 fs->blocksize);
1456
1457 new_itable_size = new_ino_blks_per_grp * fs->blocksize;
1458
1459 retval = ext2fs_get_mem(old_itable_size, &old_itable);
1460 if (retval)
1461 return retval;
1462
1463 retval = ext2fs_get_mem(new_itable_size, &new_itable);
1464 if (retval)
1465 goto err_out;
1466
1467 tmp_old_itable = old_itable;
1468 tmp_new_itable = new_itable;
1469
1470 for (i = 0; i < fs->group_desc_count; i++) {
d7cca6b0 1471 blk = ext2fs_inode_table_loc(fs, i);
24a117ab 1472 retval = io_channel_read_blk64(fs->io, blk,
64d588cf
AK
1473 fs->inode_blocks_per_group, old_itable);
1474 if (retval)
1475 goto err_out;
1476
1477 for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) {
721b367a 1478 memcpy(new_itable, old_itable, old_ino_size);
64d588cf 1479
721b367a
TT
1480 memset(new_itable+old_ino_size, 0,
1481 new_ino_size - old_ino_size);
64d588cf 1482
721b367a
TT
1483 new_itable += new_ino_size;
1484 old_itable += old_ino_size;
64d588cf
AK
1485 }
1486
1487 /* reset the pointer */
1488 old_itable = tmp_old_itable;
1489 new_itable = tmp_new_itable;
1490
24a117ab 1491 retval = io_channel_write_blk64(fs->io, blk,
64d588cf
AK
1492 new_ino_blks_per_grp, new_itable);
1493 if (retval)
1494 goto err_out;
1495 }
1496
1497 /* Update the meta data */
1498 fs->inode_blocks_per_group = new_ino_blks_per_grp;
721b367a 1499 fs->super->s_inode_size = new_ino_size;
64d588cf
AK
1500
1501err_out:
1502 if (old_itable)
1503 ext2fs_free_mem(&old_itable);
1504
1505 if (new_itable)
1506 ext2fs_free_mem(&new_itable);
1507
1508 return retval;
64d588cf
AK
1509}
1510
1511static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1512{
7117f8d6 1513 blk64_t blk;
64d588cf
AK
1514 ext2_ino_t ino;
1515 unsigned int group = 0;
1516 unsigned int count = 0;
1517 int total_free = 0;
1518 int group_free = 0;
1519
1520 /*
1521 * First calculate the block statistics
1522 */
1523 for (blk = fs->super->s_first_data_block;
4efbac6f 1524 blk < ext2fs_blocks_count(fs->super); blk++) {
3c041a51 1525 if (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk)) {
64d588cf
AK
1526 group_free++;
1527 total_free++;
1528 }
1529 count++;
1530 if ((count == fs->super->s_blocks_per_group) ||
4efbac6f 1531 (blk == ext2fs_blocks_count(fs->super)-1)) {
d7cca6b0
VAH
1532 ext2fs_bg_free_blocks_count_set(fs, group++,
1533 group_free);
64d588cf
AK
1534 count = 0;
1535 group_free = 0;
1536 }
1537 }
fe75afbf 1538 total_free = EXT2FS_C2B(fs, total_free);
4efbac6f 1539 ext2fs_free_blocks_count_set(fs->super, total_free);
64d588cf
AK
1540
1541 /*
1542 * Next, calculate the inode statistics
1543 */
1544 group_free = 0;
1545 total_free = 0;
1546 count = 0;
1547 group = 0;
1548
1549 /* Protect loop from wrap-around if s_inodes_count maxed */
1550 for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
3c041a51 1551 if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
64d588cf
AK
1552 group_free++;
1553 total_free++;
1554 }
1555 count++;
1556 if ((count == fs->super->s_inodes_per_group) ||
1557 (ino == fs->super->s_inodes_count)) {
d7cca6b0
VAH
1558 ext2fs_bg_free_inodes_count_set(fs, group++,
1559 group_free);
64d588cf
AK
1560 count = 0;
1561 group_free = 0;
1562 }
1563 }
1564 fs->super->s_free_inodes_count = total_free;
1565 ext2fs_mark_super_dirty(fs);
1566 return 0;
1567}
1568
1569#define list_for_each_safe(pos, pnext, head) \
1570 for (pos = (head)->next, pnext = pos->next; pos != (head); \
1571 pos = pnext, pnext = pos->next)
1572
721b367a 1573static void free_blk_move_list(void)
64d588cf
AK
1574{
1575 struct list_head *entry, *tmp;
1576 struct blk_move *bmv;
1577
1578 list_for_each_safe(entry, tmp, &blk_move_list) {
64d588cf
AK
1579 bmv = list_entry(entry, struct blk_move, list);
1580 list_del(entry);
1581 ext2fs_free_mem(&bmv);
1582 }
31f1815f 1583 return;
64d588cf 1584}
721b367a
TT
1585
1586static int resize_inode(ext2_filsys fs, unsigned long new_size)
64d588cf
AK
1587{
1588 errcode_t retval;
1589 int new_ino_blks_per_grp;
a9e5177b 1590 ext2fs_block_bitmap bmap;
64d588cf 1591
64d588cf
AK
1592 ext2fs_read_inode_bitmap(fs);
1593 ext2fs_read_block_bitmap(fs);
1594 INIT_LIST_HEAD(&blk_move_list);
1595
1596
1597 new_ino_blks_per_grp = ext2fs_div_ceil(
1598 EXT2_INODES_PER_GROUP(fs->super)*
721b367a 1599 new_size,
64d588cf
AK
1600 fs->blocksize);
1601
1602 /* We may change the file system.
1603 * Mark the file system as invalid so that
1604 * the user is prompted to run fsck.
1605 */
1606 fs->super->s_state &= ~EXT2_VALID_FS;
1607
1608 retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
1609 &bmap);
a9e5177b
AK
1610 if (retval) {
1611 fputs(_("Failed to allocate block bitmap when "
1612 "increasing inode size\n"), stderr);
31f1815f 1613 return retval;
a9e5177b
AK
1614 }
1615 retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap);
1616 if (retval) {
1617 fputs(_("Not enough space to increase inode size \n"), stderr);
64d588cf 1618 goto err_out;
a9e5177b
AK
1619 }
1620 retval = move_block(fs, bmap);
1621 if (retval) {
1622 fputs(_("Failed to relocate blocks during inode resize \n"),
1623 stderr);
64d588cf 1624 goto err_out;
a9e5177b 1625 }
27c6de45 1626 retval = inode_scan_and_fix(fs, bmap);
64d588cf 1627 if (retval)
a9e5177b 1628 goto err_out_undo;
31f1815f 1629
91fac979
AK
1630 retval = group_desc_scan_and_fix(fs, bmap);
1631 if (retval)
1632 goto err_out_undo;
1633
721b367a 1634 retval = expand_inode_table(fs, new_size);
64d588cf 1635 if (retval)
a9e5177b 1636 goto err_out_undo;
64d588cf
AK
1637
1638 ext2fs_calculate_summary_stats(fs);
1639
1640 fs->super->s_state |= EXT2_VALID_FS;
1641 /* mark super block and block bitmap as dirty */
1642 ext2fs_mark_super_dirty(fs);
1643 ext2fs_mark_bb_dirty(fs);
1644
1645err_out:
1646 free_blk_move_list();
1647 ext2fs_free_block_bitmap(bmap);
1648
1649 return retval;
a9e5177b
AK
1650
1651err_out_undo:
1652 free_blk_move_list();
1653 ext2fs_free_block_bitmap(bmap);
1654 fputs(_("Error in resizing the inode size.\n"
1655 "Run e2undo to undo the "
1656 "file system changes. \n"), stderr);
1657
1658 return retval;
64d588cf
AK
1659}
1660
1661static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
1662{
1663 errcode_t retval = 0;
721b367a 1664 const char *tdb_dir;
f203bbdb 1665 char *tdb_file;
721b367a 1666 char *dev_name, *tmp_name;
64d588cf
AK
1667
1668#if 0 /* FIXME!! */
1669 /*
1670 * Configuration via a conf file would be
1671 * nice
1672 */
1673 profile_get_string(profile, "scratch_files",
1674 "directory", 0, 0,
1675 &tdb_dir);
1676#endif
1677 tmp_name = strdup(name);
f203bbdb
TT
1678 if (!tmp_name) {
1679 alloc_fn_fail:
1680 com_err(program_name, ENOMEM,
1681 _("Couldn't allocate memory for tdb filename\n"));
1682 return ENOMEM;
1683 }
721b367a 1684 dev_name = basename(tmp_name);
64d588cf
AK
1685
1686 tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
1687 if (!tdb_dir)
ec43da2f 1688 tdb_dir = "/var/lib/e2fsprogs";
64d588cf
AK
1689
1690 if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
1691 access(tdb_dir, W_OK))
1692 return 0;
1693
f203bbdb
TT
1694 tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1);
1695 if (!tdb_file)
1696 goto alloc_fn_fail;
721b367a 1697 sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name);
64d588cf
AK
1698
1699 if (!access(tdb_file, F_OK)) {
1700 if (unlink(tdb_file) < 0) {
1701 retval = errno;
1702 com_err(program_name, retval,
1703 _("while trying to delete %s"),
1704 tdb_file);
f203bbdb 1705 free(tdb_file);
64d588cf
AK
1706 return retval;
1707 }
1708 }
1709
1710 set_undo_io_backing_manager(*io_ptr);
1711 *io_ptr = undo_io_manager;
1712 set_undo_io_backup_file(tdb_file);
5bf81bae 1713 printf(_("To undo the tune2fs operation please run "
577b5c43 1714 "the command\n e2undo %s %s\n\n"),
64d588cf 1715 tdb_file, name);
f203bbdb 1716 free(tdb_file);
64d588cf
AK
1717 free(tmp_name);
1718 return retval;
1719}
83238153 1720
ec43da2f 1721int main(int argc, char **argv)
83238153
TT
1722{
1723 errcode_t retval;
1724 ext2_filsys fs;
1725 struct ext2_super_block *sb;
d887f88d 1726 io_manager io_ptr, io_ptr_orig = NULL;
83238153
TT
1727
1728#ifdef ENABLE_NLS
1729 setlocale(LC_MESSAGES, "");
14308a53 1730 setlocale(LC_CTYPE, "");
83238153
TT
1731 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1732 textdomain(NLS_CAT_NAME);
1733#endif
1734 if (argc && *argv)
1735 program_name = *argv;
a6d8302b 1736 add_error_table(&et_ext2_error_table);
83238153 1737
14b596d4 1738#ifdef CONFIG_BUILD_FINDFS
118d7dac
TT
1739 if (strcmp(get_progname(argv[0]), "findfs") == 0)
1740 do_findfs(argc, argv);
14b596d4 1741#endif
83238153
TT
1742 if (strcmp(get_progname(argv[0]), "e2label") == 0)
1743 parse_e2label_options(argc, argv);
1744 else
1745 parse_tune2fs_options(argc, argv);
efc6f628 1746
2a29f135 1747#ifdef CONFIG_TESTIO_DEBUG
f38cf3cb
TT
1748 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_DEBUG")) {
1749 io_ptr = test_io_manager;
1750 test_io_backing_manager = unix_io_manager;
1751 } else
2a29f135 1752#endif
f38cf3cb 1753 io_ptr = unix_io_manager;
64d588cf 1754
d887f88d 1755retry_open:
efc6f628 1756 retval = ext2fs_open2(device_name, io_options, open_flag,
2e8ca9a2 1757 0, 0, io_ptr, &fs);
ec43da2f
TT
1758 if (retval) {
1759 com_err(program_name, retval,
1760 _("while trying to open %s"),
1761 device_name);
7141b54b
TT
1762 fprintf(stderr,
1763 _("Couldn't find valid filesystem superblock.\n"));
3839e657
TT
1764 exit(1);
1765 }
d887f88d
TT
1766
1767 if (I_flag && !io_ptr_orig) {
1768 /*
1769 * Check the inode size is right so we can issue an
1770 * error message and bail before setting up the tdb
1771 * file.
1772 */
1773 if (new_inode_size == EXT2_INODE_SIZE(fs->super)) {
9266fc7a 1774 fprintf(stderr, _("The inode size is already %lu\n"),
d887f88d
TT
1775 new_inode_size);
1776 exit(1);
1777 }
1778 if (new_inode_size < EXT2_INODE_SIZE(fs->super)) {
1779 fprintf(stderr, _("Shrinking the inode size is "
1780 "not supported\n"));
1781 exit(1);
1782 }
1783
1784 /*
1785 * If inode resize is requested use the
1786 * Undo I/O manager
1787 */
1788 io_ptr_orig = io_ptr;
1789 retval = tune2fs_setup_tdb(device_name, &io_ptr);
1790 if (retval)
1791 exit(1);
1792 if (io_ptr != io_ptr_orig) {
1793 ext2fs_close(fs);
1794 goto retry_open;
1795 }
1796 }
1797
83238153 1798 sb = fs->super;
058ad1c7 1799 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
2be8fe43 1800
83238153
TT
1801 if (print_label) {
1802 /* For e2label emulation */
c8c071a0
TT
1803 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
1804 sb->s_volume_name);
a6d8302b 1805 remove_error_table(&et_ext2_error_table);
83238153
TT
1806 exit(0);
1807 }
2be8fe43 1808
d06863f0
TT
1809 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
1810 if (retval) {
1811 com_err("ext2fs_check_if_mount", retval,
1812 _("while determining whether %s is mounted."),
1813 device_name);
1814 exit(1);
b21e38a0 1815 }
63985320
TT
1816 /* Normally we only need to write out the superblock */
1817 fs->flags |= EXT2_FLAG_SUPER_ONLY;
3839e657 1818
1e3472c5 1819 if (c_flag) {
b21e38a0 1820 sb->s_max_mnt_count = max_mount_count;
3839e657 1821 ext2fs_mark_super_dirty(fs);
ec43da2f
TT
1822 printf(_("Setting maximal mount count to %d\n"),
1823 max_mount_count);
3839e657 1824 }
1e3472c5 1825 if (C_flag) {
b21e38a0 1826 sb->s_mnt_count = mount_count;
1e3472c5 1827 ext2fs_mark_super_dirty(fs);
ec43da2f 1828 printf(_("Setting current mount count to %d\n"), mount_count);
1e3472c5
TT
1829 }
1830 if (e_flag) {
b21e38a0 1831 sb->s_errors = errors;
3839e657 1832 ext2fs_mark_super_dirty(fs);
ec43da2f 1833 printf(_("Setting error behavior to %d\n"), errors);
3839e657 1834 }
b21e38a0
TT
1835 if (g_flag) {
1836 sb->s_def_resgid = resgid;
f3db3566 1837 ext2fs_mark_super_dirty(fs);
ec43da2f 1838 printf(_("Setting reserved blocks gid to %lu\n"), resgid);
f3db3566 1839 }
818180cd 1840 if (i_flag) {
2972b163
KM
1841 if (interval >= (1ULL << 32)) {
1842 com_err(program_name, 0,
1843 _("interval between checks is too big (%lu)"),
1844 interval);
1845 exit(1);
1846 }
b21e38a0 1847 sb->s_checkinterval = interval;
3839e657 1848 ext2fs_mark_super_dirty(fs);
ec43da2f
TT
1849 printf(_("Setting interval between checks to %lu seconds\n"),
1850 interval);
3839e657 1851 }
818180cd 1852 if (m_flag) {
4efbac6f
VAH
1853 ext2fs_r_blocks_count_set(sb, reserved_ratio *
1854 ext2fs_blocks_count(sb) / 100.0);
3839e657 1855 ext2fs_mark_super_dirty(fs);
4efbac6f
VAH
1856 printf (_("Setting reserved blocks percentage to %g%% (%llu blocks)\n"),
1857 reserved_ratio, ext2fs_r_blocks_count(sb));
3839e657 1858 }
818180cd 1859 if (r_flag) {
3977a4ff 1860 if (reserved_blocks > ext2fs_blocks_count(sb)/2) {
ec43da2f 1861 com_err(program_name, 0,
4efbac6f 1862 _("reserved blocks count is too big (%llu)"),
ec43da2f
TT
1863 reserved_blocks);
1864 exit(1);
f3db3566 1865 }
4efbac6f 1866 ext2fs_r_blocks_count_set(sb, reserved_blocks);
f3db3566 1867 ext2fs_mark_super_dirty(fs);
4efbac6f 1868 printf(_("Setting reserved blocks count to %llu\n"),
ec43da2f 1869 reserved_blocks);
f3db3566 1870 }
521e3685 1871 if (s_flag == 1) {
521e3685
TT
1872 if (sb->s_feature_ro_compat &
1873 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
54434927
TT
1874 fputs(_("\nThe filesystem already has sparse "
1875 "superblocks.\n"), stderr);
521e3685
TT
1876 else {
1877 sb->s_feature_ro_compat |=
1878 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
b21e38a0 1879 sb->s_state &= ~EXT2_VALID_FS;
521e3685 1880 ext2fs_mark_super_dirty(fs);
d9c56d3c 1881 printf(_("\nSparse superblock flag set. %s"),
a4fa100c 1882 _(please_fsck));
521e3685 1883 }
521e3685
TT
1884 }
1885 if (s_flag == 0) {
ff662d5d
TT
1886 fputs(_("\nClearing the sparse superflag not supported.\n"),
1887 stderr);
1888 exit(1);
521e3685 1889 }
d4de4aa9
TT
1890 if (T_flag) {
1891 sb->s_lastcheck = last_check_time;
1892 ext2fs_mark_super_dirty(fs);
1893 printf(_("Setting time filesystem last checked to %s\n"),
1894 ctime(&last_check_time));
1895 }
b21e38a0
TT
1896 if (u_flag) {
1897 sb->s_def_resuid = resuid;
f3db3566 1898 ext2fs_mark_super_dirty(fs);
ec43da2f 1899 printf(_("Setting reserved blocks uid to %lu\n"), resuid);
f3db3566 1900 }
1e3472c5 1901 if (L_flag) {
a789d840 1902 if (strlen(new_label) > sizeof(sb->s_volume_name))
efc6f628 1903 fputs(_("Warning: label too long, truncating.\n"),
54434927 1904 stderr);
1e3472c5
TT
1905 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
1906 strncpy(sb->s_volume_name, new_label,
1907 sizeof(sb->s_volume_name));
1908 ext2fs_mark_super_dirty(fs);
1909 }
1910 if (M_flag) {
1911 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
1912 strncpy(sb->s_last_mounted, new_last_mounted,
1913 sizeof(sb->s_last_mounted));
1914 ext2fs_mark_super_dirty(fs);
1915 }
a0c3fd5e
TT
1916 if (mntopts_cmd)
1917 update_mntopts(fs, mntopts_cmd);
63985320
TT
1918 if (features_cmd)
1919 update_feature_set(fs, features_cmd);
6cb27404
TT
1920 if (extended_cmd)
1921 parse_extended_opts(fs, extended_cmd);
dc2ec525 1922 if (journal_size || journal_device)
63985320 1923 add_journal(fs);
efc6f628 1924
771e8db9
AK
1925 if (Q_flag) {
1926 if (mount_flags & EXT2_MF_MOUNTED) {
1927 fputs(_("The quota feature may only be changed when "
1928 "the filesystem is unmounted.\n"), stderr);
1929 exit(1);
1930 }
1931 handle_quota_options(fs);
1932 }
1933
1e3472c5 1934 if (U_flag) {
9d4a4dc2
TT
1935 int set_csum = 0;
1936 dgrp_t i;
1937
1938 if (sb->s_feature_ro_compat &
1939 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
ec43da2f 1940 /*
9d4a4dc2
TT
1941 * Determine if the block group checksums are
1942 * correct so we know whether or not to set
1943 * them later on.
1944 */
1945 for (i = 0; i < fs->group_desc_count; i++)
1946 if (!ext2fs_group_desc_csum_verify(fs, i))
1947 break;
1948 if (i >= fs->group_desc_count)
1949 set_csum = 1;
1950 }
4d0f2283
TT
1951 if ((strcasecmp(new_UUID, "null") == 0) ||
1952 (strcasecmp(new_UUID, "clear") == 0)) {
1e3472c5 1953 uuid_clear(sb->s_uuid);
63985320
TT
1954 } else if (strcasecmp(new_UUID, "time") == 0) {
1955 uuid_generate_time(sb->s_uuid);
1e3472c5
TT
1956 } else if (strcasecmp(new_UUID, "random") == 0) {
1957 uuid_generate(sb->s_uuid);
1958 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
d9c56d3c 1959 com_err(program_name, 0, _("Invalid UUID format\n"));
1e3472c5
TT
1960 exit(1);
1961 }
9d4a4dc2
TT
1962 if (set_csum) {
1963 for (i = 0; i < fs->group_desc_count; i++)
1964 ext2fs_group_desc_csum_set(fs, i);
1965 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
1966 }
1e3472c5
TT
1967 ext2fs_mark_super_dirty(fs);
1968 }
64d588cf
AK
1969 if (I_flag) {
1970 if (mount_flags & EXT2_MF_MOUNTED) {
1971 fputs(_("The inode size may only be "
1972 "changed when the filesystem is "
1973 "unmounted.\n"), stderr);
1974 exit(1);
1975 }
5bf81bae
TT
1976 if (fs->super->s_feature_incompat &
1977 EXT4_FEATURE_INCOMPAT_FLEX_BG) {
ec43da2f
TT
1978 fputs(_("Changing the inode size not supported for "
1979 "filesystems with the flex_bg\n"
1980 "feature enabled.\n"),
5bf81bae
TT
1981 stderr);
1982 exit(1);
1983 }
64d588cf
AK
1984 /*
1985 * We want to update group descriptor also
1986 * with the new free inode count
1987 */
1988 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
a9e5177b 1989 if (resize_inode(fs, new_inode_size) == 0) {
ec43da2f 1990 printf(_("Setting inode size %lu\n"),
64d588cf
AK
1991 new_inode_size);
1992 }
1993 }
1e3472c5 1994
3839e657 1995 if (l_flag)
ec43da2f 1996 list_super(sb);
0c17cb25
TT
1997 if (stride_set) {
1998 sb->s_raid_stride = stride;
1999 ext2fs_mark_super_dirty(fs);
2000 printf(_("Setting stride size to %d\n"), stride);
2001 }
2002 if (stripe_width_set) {
2003 sb->s_raid_stripe_width = stripe_width;
2004 ext2fs_mark_super_dirty(fs);
2005 printf(_("Setting stripe width to %d\n"), stripe_width);
2006 }
9a976ac7
TT
2007 if (ext_mount_opts) {
2008 strncpy(fs->super->s_mount_opts, ext_mount_opts,
2009 sizeof(fs->super->s_mount_opts));
2010 fs->super->s_mount_opts[sizeof(fs->super->s_mount_opts)-1] = 0;
2011 ext2fs_mark_super_dirty(fs);
2012 printf(_("Setting extended default mount options to '%s'\n"),
2013 ext_mount_opts);
2014 free(ext_mount_opts);
2015 }
1acde2b2 2016 free(device_name);
a6d8302b 2017 remove_error_table(&et_ext2_error_table);
ec43da2f 2018 return (ext2fs_close(fs) ? 1 : 0);
3839e657 2019}