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