• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "config.h"
30 #include <fcntl.h>
31 #include <grp.h>
32 #ifdef HAVE_GETOPT_H
33 #include <getopt.h>
34 #else
35 extern char *optarg;
36 extern int optind;
37 #endif
38 #include <pwd.h>
39 #include <stdio.h>
40 #ifdef HAVE_STDLIB_H
41 #include <stdlib.h>
42 #endif
43 #ifdef HAVE_STRINGS_H
44 #include <strings.h>	/* for strcasecmp() */
45 #else
46 #define _BSD_SOURCE	/* for inclusion of strcasecmp() via <string.h> */
47 #define _DEFAULT_SOURCE	  /* since glibc 2.20 _BSD_SOURCE is deprecated */
48 #endif
49 #include <string.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include <sys/types.h>
53 #include <libgen.h>
54 #include <limits.h>
55 
56 #include "ext2fs/ext2_fs.h"
57 #include "ext2fs/ext2fs.h"
58 #include "ext2fs/kernel-jbd.h"
59 #include "et/com_err.h"
60 #include "support/plausible.h"
61 #include "support/quotaio.h"
62 #include "uuid/uuid.h"
63 #include "e2p/e2p.h"
64 #include "util.h"
65 #include "blkid/blkid.h"
66 
67 #include "../version.h"
68 #include "support/nls-enable.h"
69 
70 #define QOPT_ENABLE	(1)
71 #define QOPT_DISABLE	(-1)
72 
73 extern int ask_yn(const char *string, int def);
74 
75 const char *program_name = "tune2fs";
76 char *device_name;
77 char *new_label, *new_last_mounted, *new_UUID;
78 char *io_options;
79 static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
80 static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
81 static int I_flag;
82 static int clear_mmp;
83 static time_t last_check_time;
84 static int print_label;
85 static int max_mount_count, mount_count, mount_flags;
86 static unsigned long interval;
87 static blk64_t reserved_blocks;
88 static double reserved_ratio;
89 static unsigned long resgid, resuid;
90 static unsigned short errors;
91 static int open_flag;
92 static char *features_cmd;
93 static char *mntopts_cmd;
94 static int stride, stripe_width;
95 static int stride_set, stripe_width_set;
96 static char *extended_cmd;
97 static unsigned long new_inode_size;
98 static char *ext_mount_opts;
99 static int quota_enable[MAXQUOTAS];
100 static int rewrite_checksums;
101 static int feature_64bit;
102 static int fsck_requested;
103 static char *undo_file;
104 int enabling_casefold;
105 
106 int journal_size, journal_flags;
107 char *journal_device;
108 static blk64_t journal_location = ~0LL;
109 
110 static struct list_head blk_move_list;
111 
112 struct blk_move {
113 	struct list_head list;
114 	blk64_t old_loc;
115 	blk64_t new_loc;
116 };
117 
118 errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs);
119 
120 static const char *fsck_explain = N_("\nThis operation requires a freshly checked filesystem.\n");
121 
122 static const char *please_fsck = N_("Please run e2fsck -f on the filesystem.\n");
123 static const char *please_dir_fsck =
124 		N_("Please run e2fsck -fD on the filesystem.\n");
125 
126 #ifdef CONFIG_BUILD_FINDFS
127 void do_findfs(int argc, char **argv);
128 #endif
129 
130 #ifdef CONFIG_JBD_DEBUG		/* Enabled by configure --enable-jbd-debug */
131 int journal_enable_debug = -1;
132 #endif
133 
usage(void)134 static void usage(void)
135 {
136 	fprintf(stderr,
137 		_("Usage: %s [-c max_mounts_count] [-e errors_behavior] [-f] "
138 		  "[-g group]\n"
139 		  "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n"
140 		  "\t[-m reserved_blocks_percent] [-o [^]mount_options[,...]]\n"
141 		  "\t[-r reserved_blocks_count] [-u user] [-C mount_count]\n"
142 		  "\t[-L volume_label] [-M last_mounted_dir]\n"
143 		  "\t[-O [^]feature[,...]] [-Q quota_options]\n"
144 		  "\t[-E extended-option[,...]] [-T last_check_time] "
145 		  "[-U UUID]\n\t[-I new_inode_size] [-z undo_file] device\n"),
146 		program_name);
147 	exit(1);
148 }
149 
150 static __u32 ok_features[3] = {
151 	/* Compat */
152 	EXT3_FEATURE_COMPAT_HAS_JOURNAL |
153 		EXT2_FEATURE_COMPAT_DIR_INDEX |
154 		EXT4_FEATURE_COMPAT_STABLE_INODES,
155 	/* Incompat */
156 	EXT2_FEATURE_INCOMPAT_FILETYPE |
157 		EXT3_FEATURE_INCOMPAT_EXTENTS |
158 		EXT4_FEATURE_INCOMPAT_FLEX_BG |
159 		EXT4_FEATURE_INCOMPAT_EA_INODE|
160 		EXT4_FEATURE_INCOMPAT_MMP |
161 		EXT4_FEATURE_INCOMPAT_64BIT |
162 		EXT4_FEATURE_INCOMPAT_ENCRYPT |
163 		EXT4_FEATURE_INCOMPAT_CSUM_SEED |
164 		EXT4_FEATURE_INCOMPAT_LARGEDIR |
165 		EXT4_FEATURE_INCOMPAT_CASEFOLD,
166 	/* R/O compat */
167 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
168 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
169 		EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
170 		EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
171 		EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
172 		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
173 		EXT4_FEATURE_RO_COMPAT_QUOTA |
174 		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM |
175 		EXT4_FEATURE_RO_COMPAT_READONLY |
176 		EXT4_FEATURE_RO_COMPAT_PROJECT |
177 		EXT4_FEATURE_RO_COMPAT_VERITY
178 };
179 
180 static __u32 clear_ok_features[3] = {
181 	/* Compat */
182 	EXT3_FEATURE_COMPAT_HAS_JOURNAL |
183 		EXT2_FEATURE_COMPAT_RESIZE_INODE |
184 		EXT2_FEATURE_COMPAT_DIR_INDEX |
185 		EXT4_FEATURE_COMPAT_STABLE_INODES,
186 	/* Incompat */
187 	EXT2_FEATURE_INCOMPAT_FILETYPE |
188 		EXT4_FEATURE_INCOMPAT_FLEX_BG |
189 		EXT4_FEATURE_INCOMPAT_MMP |
190 		EXT4_FEATURE_INCOMPAT_64BIT |
191 		EXT4_FEATURE_INCOMPAT_CSUM_SEED,
192 	/* R/O compat */
193 	EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
194 		EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
195 		EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
196 		EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
197 		EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
198 		EXT4_FEATURE_RO_COMPAT_QUOTA |
199 		EXT4_FEATURE_RO_COMPAT_PROJECT |
200 		EXT4_FEATURE_RO_COMPAT_METADATA_CSUM |
201 		EXT4_FEATURE_RO_COMPAT_READONLY
202 };
203 
204 /**
205  * Try to get journal super block if any
206  */
get_journal_sb(ext2_filsys jfs,char buf[SUPERBLOCK_SIZE])207 static int get_journal_sb(ext2_filsys jfs, char buf[SUPERBLOCK_SIZE])
208 {
209 	int retval;
210 	journal_superblock_t *jsb;
211 
212 	if (!ext2fs_has_feature_journal_dev(jfs->super)) {
213 		return EXT2_ET_UNSUPP_FEATURE;
214 	}
215 
216 	/* Get the journal superblock */
217 	if ((retval = io_channel_read_blk64(jfs->io,
218 	    ext2fs_journal_sb_start(jfs->blocksize), -SUPERBLOCK_SIZE, buf))) {
219 		com_err(program_name, retval, "%s",
220 		_("while reading journal superblock"));
221 		return retval;
222 	}
223 
224 	jsb = (journal_superblock_t *) buf;
225 	if ((jsb->s_header.h_magic != (unsigned)ntohl(JFS_MAGIC_NUMBER)) ||
226 	    (jsb->s_header.h_blocktype != (unsigned)ntohl(JFS_SUPERBLOCK_V2))) {
227 		fputs(_("Journal superblock not found!\n"), stderr);
228 		return EXT2_ET_BAD_MAGIC;
229 	}
230 
231 	return 0;
232 }
233 
journal_user(__u8 uuid[UUID_SIZE],__u8 s_users[JFS_USERS_SIZE],int nr_users)234 static __u8 *journal_user(__u8 uuid[UUID_SIZE], __u8 s_users[JFS_USERS_SIZE],
235 			  int nr_users)
236 {
237 	int i;
238 	for (i = 0; i < nr_users; i++) {
239 		if (memcmp(uuid, &s_users[i * UUID_SIZE], UUID_SIZE) == 0)
240 			return &s_users[i * UUID_SIZE];
241 	}
242 
243 	return NULL;
244 }
245 
246 /*
247  * Remove an external journal from the filesystem
248  */
remove_journal_device(ext2_filsys fs)249 static int remove_journal_device(ext2_filsys fs)
250 {
251 	char		*journal_path;
252 	ext2_filsys	jfs;
253 	char		buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8)));
254 	journal_superblock_t	*jsb;
255 	int		i, nr_users;
256 	errcode_t	retval;
257 	int		commit_remove_journal = 0;
258 	io_manager	io_ptr;
259 
260 	if (f_flag)
261 		commit_remove_journal = 1; /* force removal even if error */
262 
263 	uuid_unparse(fs->super->s_journal_uuid, buf);
264 	journal_path = blkid_get_devname(NULL, "UUID", buf);
265 
266 	if (!journal_path) {
267 		journal_path =
268 			ext2fs_find_block_device(fs->super->s_journal_dev);
269 		if (!journal_path)
270 			goto no_valid_journal;
271 	}
272 
273 #ifdef CONFIG_TESTIO_DEBUG
274 	if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
275 		io_ptr = test_io_manager;
276 		test_io_backing_manager = unix_io_manager;
277 	} else
278 #endif
279 		io_ptr = unix_io_manager;
280 	retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
281 			     EXT2_FLAG_JOURNAL_DEV_OK, 0,
282 			     fs->blocksize, io_ptr, &jfs);
283 	if (retval) {
284 		com_err(program_name, retval, "%s",
285 			_("while trying to open external journal"));
286 		goto no_valid_journal;
287 	}
288 
289 	if ((retval = get_journal_sb(jfs, buf))) {
290 		if (retval == EXT2_ET_UNSUPP_FEATURE)
291 			fprintf(stderr, _("%s is not a journal device.\n"),
292 				journal_path);
293 		goto no_valid_journal;
294 	}
295 
296 	jsb = (journal_superblock_t *) buf;
297 	/* Find the filesystem UUID */
298 	nr_users = ntohl(jsb->s_nr_users);
299 	if (nr_users > JFS_USERS_MAX) {
300 		fprintf(stderr, _("Journal superblock is corrupted, nr_users\n"
301 				 "is too high (%d).\n"), nr_users);
302 		commit_remove_journal = 1;
303 		goto no_valid_journal;
304 	}
305 
306 	if (!journal_user(fs->super->s_uuid, jsb->s_users, nr_users)) {
307 		fputs(_("Filesystem's UUID not found on journal device.\n"),
308 		      stderr);
309 		commit_remove_journal = 1;
310 		goto no_valid_journal;
311 	}
312 	nr_users--;
313 	for (i = 0; i < nr_users; i++)
314 		memcpy(&jsb->s_users[i * 16], &jsb->s_users[(i + 1) * 16], 16);
315 	jsb->s_nr_users = htonl(nr_users);
316 
317 	/* Write back the journal superblock */
318 	retval = io_channel_write_blk64(jfs->io,
319 					ext2fs_journal_sb_start(fs->blocksize),
320 					-SUPERBLOCK_SIZE, buf);
321 	if (retval) {
322 		com_err(program_name, retval,
323 			"while writing journal superblock.");
324 		goto no_valid_journal;
325 	}
326 
327 	commit_remove_journal = 1;
328 
329 no_valid_journal:
330 	if (commit_remove_journal == 0) {
331 		fputs(_("Cannot locate journal device. It was NOT removed\n"
332 			"Use -f option to remove missing journal device.\n"),
333 		      stderr);
334 		return 1;
335 	}
336 	fs->super->s_journal_dev = 0;
337 	memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks));
338 	uuid_clear(fs->super->s_journal_uuid);
339 	ext2fs_mark_super_dirty(fs);
340 	fputs(_("Journal removed\n"), stdout);
341 	free(journal_path);
342 
343 	return 0;
344 }
345 
346 /* Helper function for remove_journal_inode */
release_blocks_proc(ext2_filsys fs,blk64_t * blocknr,e2_blkcnt_t blockcnt EXT2FS_ATTR ((unused)),blk64_t ref_block EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * private EXT2FS_ATTR ((unused)))347 static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
348 			       e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
349 			       blk64_t ref_block EXT2FS_ATTR((unused)),
350 			       int ref_offset EXT2FS_ATTR((unused)),
351 			       void *private EXT2FS_ATTR((unused)))
352 {
353 	blk64_t	block;
354 	int	group;
355 
356 	block = *blocknr;
357 	ext2fs_unmark_block_bitmap2(fs->block_map, block);
358 	group = ext2fs_group_of_blk2(fs, block);
359 	ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) + 1);
360 	ext2fs_group_desc_csum_set(fs, group);
361 	ext2fs_free_blocks_count_add(fs->super, EXT2FS_CLUSTER_RATIO(fs));
362 	return 0;
363 }
364 
365 /*
366  * Remove the journal inode from the filesystem
367  */
remove_journal_inode(ext2_filsys fs)368 static errcode_t remove_journal_inode(ext2_filsys fs)
369 {
370 	struct ext2_inode	inode;
371 	errcode_t		retval;
372 	ino_t			ino = fs->super->s_journal_inum;
373 
374 	retval = ext2fs_read_inode(fs, ino,  &inode);
375 	if (retval) {
376 		com_err(program_name, retval, "%s",
377 			_("while reading journal inode"));
378 		return retval;
379 	}
380 	if (ino == EXT2_JOURNAL_INO) {
381 		retval = ext2fs_read_bitmaps(fs);
382 		if (retval) {
383 			com_err(program_name, retval, "%s",
384 				_("while reading bitmaps"));
385 			return retval;
386 		}
387 		retval = ext2fs_block_iterate3(fs, ino,
388 					       BLOCK_FLAG_READ_ONLY, NULL,
389 					       release_blocks_proc, NULL);
390 		if (retval) {
391 			com_err(program_name, retval, "%s",
392 				_("while clearing journal inode"));
393 			return retval;
394 		}
395 		memset(&inode, 0, sizeof(inode));
396 		ext2fs_mark_bb_dirty(fs);
397 		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
398 	} else
399 		inode.i_flags &= ~EXT2_IMMUTABLE_FL;
400 	retval = ext2fs_write_inode(fs, ino, &inode);
401 	if (retval) {
402 		com_err(program_name, retval, "%s",
403 			_("while writing journal inode"));
404 		return retval;
405 	}
406 	fs->super->s_journal_inum = 0;
407 	memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks));
408 	ext2fs_mark_super_dirty(fs);
409 
410 	return 0;
411 }
412 
413 /*
414  * Update the default mount options
415  */
update_mntopts(ext2_filsys fs,char * mntopts)416 static int update_mntopts(ext2_filsys fs, char *mntopts)
417 {
418 	struct ext2_super_block *sb = fs->super;
419 
420 	if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) {
421 		fprintf(stderr, _("Invalid mount option set: %s\n"),
422 			mntopts);
423 		return 1;
424 	}
425 	ext2fs_mark_super_dirty(fs);
426 
427 	return 0;
428 }
429 
check_fsck_needed(ext2_filsys fs,const char * prompt)430 static void check_fsck_needed(ext2_filsys fs, const char *prompt)
431 {
432 	/* Refuse to modify anything but a freshly checked valid filesystem. */
433 	if (!(fs->super->s_state & EXT2_VALID_FS) ||
434 	    (fs->super->s_state & EXT2_ERROR_FS) ||
435 	    (fs->super->s_lastcheck < fs->super->s_mtime)) {
436 		puts(_(fsck_explain));
437 		puts(_(please_fsck));
438 		if (mount_flags & EXT2_MF_READONLY)
439 			printf("%s", _("(and reboot afterwards!)\n"));
440 		exit(1);
441 	}
442 
443 	/* Give the admin a few seconds to bail out of a dangerous op. */
444 	if (!getenv("TUNE2FS_FORCE_PROMPT") && (!isatty(0) || !isatty(1)))
445 		return;
446 
447 	puts(prompt);
448 	proceed_question(5);
449 }
450 
request_dir_fsck_afterwards(ext2_filsys fs)451 static void request_dir_fsck_afterwards(ext2_filsys fs)
452 {
453 	static int requested;
454 
455 	if (requested++)
456 		return;
457 	fsck_requested++;
458 	fs->super->s_state &= ~EXT2_VALID_FS;
459 	puts(_(fsck_explain));
460 	puts(_(please_dir_fsck));
461 	if (mount_flags & EXT2_MF_READONLY)
462 		printf("%s", _("(and reboot afterwards!)\n"));
463 }
464 
request_fsck_afterwards(ext2_filsys fs)465 static void request_fsck_afterwards(ext2_filsys fs)
466 {
467 	static int requested = 0;
468 
469 	if (requested++)
470 		return;
471 	fsck_requested++;
472 	fs->super->s_state &= ~EXT2_VALID_FS;
473 	printf("\n%s\n", _(please_fsck));
474 	if (mount_flags & EXT2_MF_READONLY)
475 		printf("%s", _("(and reboot afterwards!)\n"));
476 }
477 
convert_64bit(ext2_filsys fs,int direction)478 static void convert_64bit(ext2_filsys fs, int direction)
479 {
480 	/*
481 	 * Is resize2fs going to demand a fsck run? Might as well tell the
482 	 * user now.
483 	 */
484 	if (!fsck_requested &&
485 	    ((fs->super->s_state & EXT2_ERROR_FS) ||
486 	     !(fs->super->s_state & EXT2_VALID_FS) ||
487 	     fs->super->s_lastcheck < fs->super->s_mtime))
488 		request_fsck_afterwards(fs);
489 	if (fsck_requested)
490 		fprintf(stderr, _("After running e2fsck, please run `resize2fs %s %s"),
491 			direction > 0 ? "-b" : "-s", fs->device_name);
492 	else
493 		fprintf(stderr, _("Please run `resize2fs %s %s"),
494 			direction > 0 ? "-b" : "-s", fs->device_name);
495 
496 	if (undo_file)
497 		fprintf(stderr, _(" -z \"%s\""), undo_file);
498 	if (direction > 0)
499 		fprintf(stderr, _("' to enable 64-bit mode.\n"));
500 	else
501 		fprintf(stderr, _("' to disable 64-bit mode.\n"));
502 }
503 
504 /*
505  * Rewrite directory blocks with checksums
506  */
507 struct rewrite_dir_context {
508 	char *buf;
509 	errcode_t errcode;
510 	ext2_ino_t dir;
511 	int is_htree;
512 };
513 
rewrite_dir_block(ext2_filsys fs,blk64_t * blocknr,e2_blkcnt_t blockcnt EXT2FS_ATTR ((unused)),blk64_t ref_block EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv_data)514 static int rewrite_dir_block(ext2_filsys fs,
515 			     blk64_t	*blocknr,
516 			     e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
517 			     blk64_t	ref_block EXT2FS_ATTR((unused)),
518 			     int	ref_offset EXT2FS_ATTR((unused)),
519 			     void	*priv_data)
520 {
521 	struct ext2_dx_countlimit *dcl = NULL;
522 	struct rewrite_dir_context *ctx = priv_data;
523 	int dcl_offset, changed = 0;
524 
525 	ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
526 					      ctx->dir);
527 	if (ctx->errcode)
528 		return BLOCK_ABORT;
529 
530 	/* if htree node... */
531 	if (ctx->is_htree)
532 		ext2fs_get_dx_countlimit(fs, (struct ext2_dir_entry *)ctx->buf,
533 					 &dcl, &dcl_offset);
534 	if (dcl) {
535 		if (!ext2fs_has_feature_metadata_csum(fs->super)) {
536 			/* Ensure limit is the max size */
537 			int max_entries = (fs->blocksize - dcl_offset) /
538 					  sizeof(struct ext2_dx_entry);
539 			if (ext2fs_le16_to_cpu(dcl->limit) != max_entries) {
540 				changed = 1;
541 				dcl->limit = ext2fs_cpu_to_le16(max_entries);
542 			}
543 		} else {
544 			/* If htree block is full then rebuild the dir */
545 			if (ext2fs_le16_to_cpu(dcl->count) ==
546 			    ext2fs_le16_to_cpu(dcl->limit)) {
547 				request_dir_fsck_afterwards(fs);
548 				return 0;
549 			}
550 			/*
551 			 * Ensure dcl->limit is small enough to leave room for
552 			 * the checksum tail.
553 			 */
554 			int max_entries = (fs->blocksize - (dcl_offset +
555 						sizeof(struct ext2_dx_tail))) /
556 					  sizeof(struct ext2_dx_entry);
557 			if (ext2fs_le16_to_cpu(dcl->limit) != max_entries)
558 				dcl->limit = ext2fs_cpu_to_le16(max_entries);
559 			/* Always rewrite checksum */
560 			changed = 1;
561 		}
562 	} else {
563 		unsigned int rec_len, name_size;
564 		char *top = ctx->buf + fs->blocksize;
565 		struct ext2_dir_entry *de = (struct ext2_dir_entry *)ctx->buf;
566 		struct ext2_dir_entry *last_de = NULL, *penultimate_de = NULL;
567 
568 		/* Find last and penultimate dirent */
569 		while ((char *)de < top) {
570 			penultimate_de = last_de;
571 			last_de = de;
572 			ctx->errcode = ext2fs_get_rec_len(fs, de, &rec_len);
573 			if (!ctx->errcode && !rec_len)
574 				ctx->errcode = EXT2_ET_DIR_CORRUPTED;
575 			if (ctx->errcode)
576 				return BLOCK_ABORT;
577 			de = (struct ext2_dir_entry *)(((char *)de) + rec_len);
578 		}
579 		ctx->errcode = ext2fs_get_rec_len(fs, last_de, &rec_len);
580 		if (ctx->errcode)
581 			return BLOCK_ABORT;
582 		name_size = ext2fs_dirent_name_len(last_de);
583 
584 		if (!ext2fs_has_feature_metadata_csum(fs->super)) {
585 			if (!penultimate_de)
586 				return 0;
587 			if (last_de->inode ||
588 			    name_size ||
589 			    rec_len != sizeof(struct ext2_dir_entry_tail))
590 				return 0;
591 			/*
592 			 * The last dirent is unused and the right length to
593 			 * have stored a checksum.  Erase it.
594 			 */
595 			ctx->errcode = ext2fs_get_rec_len(fs, penultimate_de,
596 							  &rec_len);
597 			if (!rec_len)
598 				ctx->errcode = EXT2_ET_DIR_CORRUPTED;
599 			if (ctx->errcode)
600 				return BLOCK_ABORT;
601 			ext2fs_set_rec_len(fs, rec_len +
602 					sizeof(struct ext2_dir_entry_tail),
603 					penultimate_de);
604 			changed = 1;
605 		} else {
606 			unsigned csum_size = sizeof(struct ext2_dir_entry_tail);
607 			struct ext2_dir_entry_tail *t;
608 
609 			/*
610 			 * If the last dirent looks like the tail, just update
611 			 * the checksum.
612 			 */
613 			if (!last_de->inode &&
614 			    rec_len == csum_size) {
615 				t = (struct ext2_dir_entry_tail *)last_de;
616 				t->det_reserved_name_len =
617 						EXT2_DIR_NAME_LEN_CSUM;
618 				changed = 1;
619 				goto out;
620 			}
621 			if (name_size & 3)
622 				name_size = (name_size & ~3) + 4;
623 			/* If there's not enough space for the tail, e2fsck */
624 			if (rec_len <= (8 + name_size + csum_size)) {
625 				request_dir_fsck_afterwards(fs);
626 				return 0;
627 			}
628 			/* Shorten that last de and insert the tail */
629 			ext2fs_set_rec_len(fs, rec_len - csum_size, last_de);
630 			t = EXT2_DIRENT_TAIL(ctx->buf, fs->blocksize);
631 			ext2fs_initialize_dirent_tail(fs, t);
632 
633 			/* Always update checksum */
634 			changed = 1;
635 		}
636 	}
637 
638 out:
639 	if (!changed)
640 		return 0;
641 
642 	ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr, ctx->buf,
643 					       0, ctx->dir);
644 	if (ctx->errcode)
645 		return BLOCK_ABORT;
646 
647 	return 0;
648 }
649 
rewrite_directory(ext2_filsys fs,ext2_ino_t dir,struct ext2_inode * inode)650 static errcode_t rewrite_directory(ext2_filsys fs, ext2_ino_t dir,
651 				   struct ext2_inode *inode)
652 {
653 	errcode_t	retval;
654 	struct rewrite_dir_context ctx;
655 
656 	retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
657 	if (retval)
658 		return retval;
659 
660 	ctx.is_htree = (inode->i_flags & EXT2_INDEX_FL);
661 	ctx.dir = dir;
662 	ctx.errcode = 0;
663 	retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY |
664 						BLOCK_FLAG_DATA_ONLY,
665 				       0, rewrite_dir_block, &ctx);
666 
667 	ext2fs_free_mem(&ctx.buf);
668 	if (retval)
669 		return retval;
670 
671 	return ctx.errcode;
672 }
673 
674 /*
675  * Context information that does not change across rewrite_one_inode()
676  * invocations.
677  */
678 struct rewrite_context {
679 	ext2_filsys fs;
680 	struct ext2_inode *zero_inode;
681 	char *ea_buf;
682 	int inode_size;
683 };
684 
685 #define fatal_err(code, args...)		\
686 	do {					\
687 		com_err(__func__, code, args);	\
688 		exit(1);			\
689 	} while (0);
690 
update_ea_inode_hash(struct rewrite_context * ctx,ext2_ino_t ino,struct ext2_inode * inode)691 static void update_ea_inode_hash(struct rewrite_context *ctx, ext2_ino_t ino,
692 				 struct ext2_inode *inode)
693 {
694 	errcode_t retval;
695 	ext2_file_t file;
696 	__u32 hash;
697 
698 	retval = ext2fs_file_open(ctx->fs, ino, 0, &file);
699 	if (retval)
700 		fatal_err(retval, "open ea_inode");
701 	retval = ext2fs_file_read(file, ctx->ea_buf, inode->i_size,
702 				  NULL);
703 	if (retval)
704 		fatal_err(retval, "read ea_inode");
705 	retval = ext2fs_file_close(file);
706 	if (retval)
707 		fatal_err(retval, "close ea_inode");
708 
709 	hash = ext2fs_crc32c_le(ctx->fs->csum_seed,
710 				(unsigned char *) ctx->ea_buf, inode->i_size);
711 	ext2fs_set_ea_inode_hash(inode, hash);
712 }
713 
update_xattr_entry_hashes(ext2_filsys fs,struct ext2_ext_attr_entry * entry,struct ext2_ext_attr_entry * end)714 static int update_xattr_entry_hashes(ext2_filsys fs,
715 				     struct ext2_ext_attr_entry *entry,
716 				     struct ext2_ext_attr_entry *end)
717 {
718 	int modified = 0;
719 	errcode_t retval;
720 
721 	while (entry < end && !EXT2_EXT_IS_LAST_ENTRY(entry)) {
722 		if (entry->e_value_inum) {
723 			retval = ext2fs_ext_attr_hash_entry2(fs, entry, NULL,
724 							     &entry->e_hash);
725 			if (retval)
726 				fatal_err(retval, "hash ea_inode entry");
727 			modified = 1;
728 		}
729 		entry = EXT2_EXT_ATTR_NEXT(entry);
730 	}
731 	return modified;
732 }
733 
update_inline_xattr_hashes(struct rewrite_context * ctx,struct ext2_inode_large * inode)734 static void update_inline_xattr_hashes(struct rewrite_context *ctx,
735 				       struct ext2_inode_large *inode)
736 {
737 	struct ext2_ext_attr_entry *start, *end;
738 	__u32 *ea_magic;
739 
740 	if (inode->i_extra_isize == 0)
741 		return;
742 
743 	if (inode->i_extra_isize & 3 ||
744 	    inode->i_extra_isize > ctx->inode_size - EXT2_GOOD_OLD_INODE_SIZE)
745 		fatal_err(EXT2_ET_INODE_CORRUPTED, "bad i_extra_isize")
746 
747 	ea_magic = (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
748 				inode->i_extra_isize);
749 	if (*ea_magic != EXT2_EXT_ATTR_MAGIC)
750 		return;
751 
752 	start = (struct ext2_ext_attr_entry *)(ea_magic + 1);
753 	end = (struct ext2_ext_attr_entry *)((char *)inode + ctx->inode_size);
754 
755 	update_xattr_entry_hashes(ctx->fs, start, end);
756 }
757 
update_block_xattr_hashes(struct rewrite_context * ctx,char * block_buf)758 static void update_block_xattr_hashes(struct rewrite_context *ctx,
759 				      char *block_buf)
760 {
761 	struct ext2_ext_attr_header *header;
762 	struct ext2_ext_attr_entry *start, *end;
763 
764 	header = (struct ext2_ext_attr_header *)block_buf;
765 	if (header->h_magic != EXT2_EXT_ATTR_MAGIC)
766 		return;
767 
768 	start = (struct ext2_ext_attr_entry *)(header+1);
769 	end = (struct ext2_ext_attr_entry *)(block_buf + ctx->fs->blocksize);
770 
771 	if (update_xattr_entry_hashes(ctx->fs, start, end))
772 		ext2fs_ext_attr_block_rehash(header, end);
773 }
774 
rewrite_one_inode(struct rewrite_context * ctx,ext2_ino_t ino,struct ext2_inode * inode)775 static void rewrite_one_inode(struct rewrite_context *ctx, ext2_ino_t ino,
776 			      struct ext2_inode *inode)
777 {
778 	blk64_t file_acl_block;
779 	errcode_t retval;
780 
781 	if (!ext2fs_test_inode_bitmap2(ctx->fs->inode_map, ino)) {
782 		if (!memcmp(inode, ctx->zero_inode, ctx->inode_size))
783 			return;
784 		memset(inode, 0, ctx->inode_size);
785 	}
786 
787 	if (inode->i_flags & EXT4_EA_INODE_FL)
788 		update_ea_inode_hash(ctx, ino, inode);
789 
790 	if (ctx->inode_size != EXT2_GOOD_OLD_INODE_SIZE)
791 		update_inline_xattr_hashes(ctx,
792 					   (struct ext2_inode_large *)inode);
793 
794 	retval = ext2fs_write_inode_full(ctx->fs, ino, inode, ctx->inode_size);
795 	if (retval)
796 		fatal_err(retval, "while writing inode");
797 
798 	retval = ext2fs_fix_extents_checksums(ctx->fs, ino, inode);
799 	if (retval)
800 		fatal_err(retval, "while rewriting extents");
801 
802 	if (LINUX_S_ISDIR(inode->i_mode) &&
803 	    ext2fs_inode_has_valid_blocks2(ctx->fs, inode)) {
804 		retval = rewrite_directory(ctx->fs, ino, inode);
805 		if (retval)
806 			fatal_err(retval, "while rewriting directories");
807 	}
808 
809 	file_acl_block = ext2fs_file_acl_block(ctx->fs, inode);
810 	if (!file_acl_block)
811 		return;
812 
813 	retval = ext2fs_read_ext_attr3(ctx->fs, file_acl_block, ctx->ea_buf,
814 				       ino);
815 	if (retval)
816 		fatal_err(retval, "while rewriting extended attribute");
817 
818 	update_block_xattr_hashes(ctx, ctx->ea_buf);
819 	retval = ext2fs_write_ext_attr3(ctx->fs, file_acl_block, ctx->ea_buf,
820 					ino);
821 	if (retval)
822 		fatal_err(retval, "while rewriting extended attribute");
823 }
824 
825 /*
826  * Forcibly set checksums in all inodes.
827  */
rewrite_inodes(ext2_filsys fs)828 static void rewrite_inodes(ext2_filsys fs)
829 {
830 	ext2_inode_scan	scan;
831 	errcode_t	retval;
832 	ext2_ino_t	ino;
833 	struct ext2_inode *inode;
834 	int pass;
835 	struct rewrite_context ctx = {
836 		.fs = fs,
837 		.inode_size = EXT2_INODE_SIZE(fs->super),
838 	};
839 
840 	if (fs->super->s_creator_os == EXT2_OS_HURD)
841 		return;
842 
843 	retval = ext2fs_get_mem(ctx.inode_size, &inode);
844 	if (retval)
845 		fatal_err(retval, "while allocating memory");
846 
847 	retval = ext2fs_get_memzero(ctx.inode_size, &ctx.zero_inode);
848 	if (retval)
849 		fatal_err(retval, "while allocating memory");
850 
851 	retval = ext2fs_get_mem(64 * 1024, &ctx.ea_buf);
852 	if (retval)
853 		fatal_err(retval, "while allocating memory");
854 
855 	/*
856 	 * Extended attribute inodes have a lookup hash that needs to be
857 	 * recalculated with the new csum_seed. Other inodes referencing xattr
858 	 * inodes need this value to be up to date. That's why we do two passes:
859 	 *
860 	 * pass 1: update xattr inodes to update their lookup hash as well as
861 	 *         other checksums.
862 	 *
863 	 * pass 2: go over other inodes to update their checksums.
864 	 */
865 	if (ext2fs_has_feature_ea_inode(fs->super))
866 		pass = 1;
867 	else
868 		pass = 2;
869 	for (;pass <= 2; pass++) {
870 		retval = ext2fs_open_inode_scan(fs, 0, &scan);
871 		if (retval)
872 			fatal_err(retval, "while opening inode scan");
873 
874 		do {
875 			retval = ext2fs_get_next_inode_full(scan, &ino, inode,
876 							    ctx.inode_size);
877 			if (retval)
878 				fatal_err(retval, "while getting next inode");
879 			if (!ino)
880 				break;
881 
882 			if (((pass == 1) &&
883 			     (inode->i_flags & EXT4_EA_INODE_FL)) ||
884 			    ((pass == 2) &&
885 			     !(inode->i_flags & EXT4_EA_INODE_FL)))
886 				rewrite_one_inode(&ctx, ino, inode);
887 		} while (ino);
888 
889 		ext2fs_close_inode_scan(scan);
890 	}
891 
892 	ext2fs_free_mem(&ctx.zero_inode);
893 	ext2fs_free_mem(&ctx.ea_buf);
894 	ext2fs_free_mem(&inode);
895 }
896 
rewrite_metadata_checksums(ext2_filsys fs)897 static void rewrite_metadata_checksums(ext2_filsys fs)
898 {
899 	errcode_t retval;
900 	dgrp_t i;
901 
902 	fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
903 	ext2fs_init_csum_seed(fs);
904 	for (i = 0; i < fs->group_desc_count; i++)
905 		ext2fs_group_desc_csum_set(fs, i);
906 	retval = ext2fs_read_bitmaps(fs);
907 	if (retval)
908 		fatal_err(retval, "while reading bitmaps");
909 	rewrite_inodes(fs);
910 	ext2fs_mark_ib_dirty(fs);
911 	ext2fs_mark_bb_dirty(fs);
912 	ext2fs_mmp_update2(fs, 1);
913 	fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
914 	fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
915 	if (ext2fs_has_feature_metadata_csum(fs->super))
916 		fs->super->s_checksum_type = EXT2_CRC32C_CHKSUM;
917 	else
918 		fs->super->s_checksum_type = 0;
919 	ext2fs_mark_super_dirty(fs);
920 }
921 
enable_uninit_bg(ext2_filsys fs)922 static void enable_uninit_bg(ext2_filsys fs)
923 {
924 	struct ext2_group_desc *gd;
925 	dgrp_t i;
926 
927 	for (i = 0; i < fs->group_desc_count; i++) {
928 		gd = ext2fs_group_desc(fs, fs->group_desc, i);
929 		gd->bg_itable_unused = 0;
930 		gd->bg_flags = EXT2_BG_INODE_ZEROED;
931 		ext2fs_group_desc_csum_set(fs, i);
932 	}
933 	fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
934 }
935 
zero_empty_inodes(ext2_filsys fs)936 static errcode_t zero_empty_inodes(ext2_filsys fs)
937 {
938 	int length = EXT2_INODE_SIZE(fs->super);
939 	struct ext2_inode *inode = NULL;
940 	ext2_inode_scan	scan;
941 	errcode_t	retval;
942 	ext2_ino_t	ino;
943 
944 	retval = ext2fs_open_inode_scan(fs, 0, &scan);
945 	if (retval)
946 		goto out;
947 
948 	retval = ext2fs_get_mem(length, &inode);
949 	if (retval)
950 		goto out;
951 
952 	do {
953 		retval = ext2fs_get_next_inode_full(scan, &ino, inode, length);
954 		if (retval)
955 			goto out;
956 		if (!ino)
957 			break;
958 		if (!ext2fs_test_inode_bitmap2(fs->inode_map, ino)) {
959 			memset(inode, 0, length);
960 			retval = ext2fs_write_inode_full(fs, ino, inode,
961 							 length);
962 			if (retval)
963 				goto out;
964 		}
965 	} while (1);
966 
967 out:
968 	ext2fs_free_mem(&inode);
969 	ext2fs_close_inode_scan(scan);
970 	return retval;
971 }
972 
disable_uninit_bg(ext2_filsys fs,__u32 csum_feature_flag)973 static errcode_t disable_uninit_bg(ext2_filsys fs, __u32 csum_feature_flag)
974 {
975 	struct ext2_group_desc *gd;
976 	dgrp_t i;
977 	errcode_t retval;
978 	blk64_t b, c, d;
979 
980 	/* Load bitmaps to ensure that the uninit ones get written out */
981 	fs->super->s_feature_ro_compat |= csum_feature_flag;
982 	retval = ext2fs_read_bitmaps(fs);
983 	fs->super->s_feature_ro_compat &= ~csum_feature_flag;
984 	if (retval) {
985 		com_err("disable_uninit_bg", retval,
986 			"while reading bitmaps");
987 		request_fsck_afterwards(fs);
988 		return retval;
989 	}
990 	ext2fs_mark_ib_dirty(fs);
991 	ext2fs_mark_bb_dirty(fs);
992 
993 	/* If we're only turning off uninit_bg, zero the inodes */
994 	if (csum_feature_flag == EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
995 		retval = zero_empty_inodes(fs);
996 		if (retval) {
997 			com_err("disable_uninit_bg", retval,
998 				"while zeroing unused inodes");
999 			request_fsck_afterwards(fs);
1000 			return retval;
1001 		}
1002 	}
1003 
1004 	/* The bbitmap is zeroed; we must mark group metadata blocks in use */
1005 	for (i = 0; i < fs->group_desc_count; i++) {
1006 		b = ext2fs_block_bitmap_loc(fs, i);
1007 		ext2fs_mark_block_bitmap2(fs->block_map, b);
1008 		b = ext2fs_inode_bitmap_loc(fs, i);
1009 		ext2fs_mark_block_bitmap2(fs->block_map, b);
1010 
1011 		retval = ext2fs_super_and_bgd_loc2(fs, i, &b, &c, &d, NULL);
1012 		if (retval == 0 && b)
1013 			ext2fs_mark_block_bitmap2(fs->block_map, b);
1014 		if (retval == 0 && c)
1015 			ext2fs_mark_block_bitmap2(fs->block_map, c);
1016 		if (retval == 0 && d)
1017 			ext2fs_mark_block_bitmap2(fs->block_map, d);
1018 		if (retval) {
1019 			com_err("disable_uninit_bg", retval,
1020 				"while initializing block bitmaps");
1021 			request_fsck_afterwards(fs);
1022 		}
1023 
1024 		gd = ext2fs_group_desc(fs, fs->group_desc, i);
1025 		gd->bg_itable_unused = 0;
1026 		gd->bg_flags = 0;
1027 		ext2fs_group_desc_csum_set(fs, i);
1028 	}
1029 	fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
1030 	ext2fs_mark_super_dirty(fs);
1031 
1032 	return 0;
1033 }
1034 
1035 static void
try_confirm_csum_seed_support(void)1036 try_confirm_csum_seed_support(void)
1037 {
1038 	if (access("/sys/fs/ext4/features/metadata_csum_seed", R_OK))
1039 		fputs(_("WARNING: Could not confirm kernel support for "
1040 			"metadata_csum_seed.\n  This requires Linux >= "
1041 			"v4.4.\n"), stderr);
1042 }
1043 
1044 /*
1045  * Update the feature set as provided by the user.
1046  */
update_feature_set(ext2_filsys fs,char * features)1047 static int update_feature_set(ext2_filsys fs, char *features)
1048 {
1049 	struct ext2_super_block *sb = fs->super;
1050 	__u32		old_features[3];
1051 	int		type_err;
1052 	unsigned int	mask_err;
1053 	errcode_t	err;
1054 	enum quota_type qtype;
1055 
1056 #define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \
1057 				((&sb->s_feature_compat)[(type)] & (mask)))
1058 #define FEATURE_OFF(type, mask) ((old_features[(type)] & (mask)) && \
1059 				 !((&sb->s_feature_compat)[(type)] & (mask)))
1060 #define FEATURE_CHANGED(type, mask) ((mask) & \
1061 		     (old_features[(type)] ^ (&sb->s_feature_compat)[(type)]))
1062 
1063 	old_features[E2P_FEATURE_COMPAT] = sb->s_feature_compat;
1064 	old_features[E2P_FEATURE_INCOMPAT] = sb->s_feature_incompat;
1065 	old_features[E2P_FEATURE_RO_INCOMPAT] = sb->s_feature_ro_compat;
1066 
1067 	if (e2p_edit_feature2(features, &sb->s_feature_compat,
1068 			      ok_features, clear_ok_features,
1069 			      &type_err, &mask_err)) {
1070 		if (!mask_err)
1071 			fprintf(stderr,
1072 				_("Invalid filesystem option set: %s\n"),
1073 				features);
1074 		else if (type_err & E2P_FEATURE_NEGATE_FLAG)
1075 			fprintf(stderr, _("Clearing filesystem feature '%s' "
1076 					  "not supported.\n"),
1077 				e2p_feature2string(type_err &
1078 						   E2P_FEATURE_TYPE_MASK,
1079 						   mask_err));
1080 		else
1081 			fprintf(stderr, _("Setting filesystem feature '%s' "
1082 					  "not supported.\n"),
1083 				e2p_feature2string(type_err, mask_err));
1084 		return 1;
1085 	}
1086 
1087 	if (FEATURE_OFF(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
1088 		if ((mount_flags & EXT2_MF_MOUNTED) &&
1089 		    !(mount_flags & EXT2_MF_READONLY)) {
1090 			fputs(_("The has_journal feature may only be "
1091 				"cleared when the filesystem is\n"
1092 				"unmounted or mounted "
1093 				"read-only.\n"), stderr);
1094 			return 1;
1095 		}
1096 		if (ext2fs_has_feature_journal_needs_recovery(sb) &&
1097 		    f_flag < 2) {
1098 			fputs(_("The needs_recovery flag is set.  "
1099 				"Please run e2fsck before clearing\n"
1100 				"the has_journal flag.\n"), stderr);
1101 			return 1;
1102 		}
1103 		if (sb->s_journal_inum) {
1104 			if (remove_journal_inode(fs))
1105 				return 1;
1106 		}
1107 		if (sb->s_journal_dev) {
1108 			if (remove_journal_device(fs))
1109 				return 1;
1110 		}
1111 	}
1112 
1113 	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
1114 		EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
1115 		if (ext2fs_has_feature_meta_bg(sb)) {
1116 			fputs(_("Setting filesystem feature 'sparse_super' "
1117 				"not supported\nfor filesystems with "
1118 				"the meta_bg feature enabled.\n"),
1119 				stderr);
1120 			return 1;
1121 		}
1122 	}
1123 
1124 	if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) {
1125 		int error;
1126 
1127 		if ((mount_flags & EXT2_MF_MOUNTED) ||
1128 		    (mount_flags & EXT2_MF_READONLY)) {
1129 			fputs(_("The multiple mount protection feature can't\n"
1130 				"be set if the filesystem is mounted or\n"
1131 				"read-only.\n"), stderr);
1132 			return 1;
1133 		}
1134 
1135 		error = ext2fs_mmp_init(fs);
1136 		if (error) {
1137 			fputs(_("\nError while enabling multiple mount "
1138 				"protection feature."), stderr);
1139 			return 1;
1140 		}
1141 
1142 		/*
1143 		 * We want to update group desc with the new free blocks count
1144 		 */
1145 		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
1146 
1147 		printf(_("Multiple mount protection has been enabled "
1148 			 "with update interval %ds.\n"),
1149 		       sb->s_mmp_update_interval);
1150 	}
1151 
1152 	if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) {
1153 		int error;
1154 
1155 		if (mount_flags & EXT2_MF_READONLY) {
1156 			fputs(_("The multiple mount protection feature cannot\n"
1157 				"be disabled if the filesystem is readonly.\n"),
1158 				stderr);
1159 			return 1;
1160 		}
1161 
1162 		error = ext2fs_read_bitmaps(fs);
1163 		if (error) {
1164 			fputs(_("Error while reading bitmaps\n"), stderr);
1165 			return 1;
1166 		}
1167 
1168 		error = ext2fs_mmp_read(fs, sb->s_mmp_block, NULL);
1169 		if (error) {
1170 			struct mmp_struct *mmp_cmp = fs->mmp_cmp;
1171 
1172 			if (error == EXT2_ET_MMP_MAGIC_INVALID)
1173 				printf(_("Magic number in MMP block does not "
1174 					 "match. expected: %x, actual: %x\n"),
1175 					 EXT4_MMP_MAGIC, mmp_cmp->mmp_magic);
1176 			else
1177 				com_err(program_name, error, "%s",
1178 					_("while reading MMP block."));
1179 			goto mmp_error;
1180 		}
1181 
1182 		/* We need to force out the group descriptors as well */
1183 		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
1184 		ext2fs_block_alloc_stats2(fs, sb->s_mmp_block, -1);
1185 mmp_error:
1186 		sb->s_mmp_block = 0;
1187 		sb->s_mmp_update_interval = 0;
1188 	}
1189 
1190 	if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
1191 		/*
1192 		 * If adding a journal flag, let the create journal
1193 		 * code below handle setting the flag and creating the
1194 		 * journal.  We supply a default size if necessary.
1195 		 */
1196 		if (!journal_size)
1197 			journal_size = -1;
1198 		ext2fs_clear_feature_journal(sb);
1199 	}
1200 
1201 	if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) {
1202 		if (!sb->s_def_hash_version)
1203 			sb->s_def_hash_version = EXT2_HASH_HALF_MD4;
1204 		if (uuid_is_null((unsigned char *) sb->s_hash_seed))
1205 			uuid_generate((unsigned char *) sb->s_hash_seed);
1206 	}
1207 
1208 	if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
1209 		if (ext2fs_check_desc(fs)) {
1210 			fputs(_("Clearing the flex_bg flag would "
1211 				"cause the the filesystem to be\n"
1212 				"inconsistent.\n"), stderr);
1213 			return 1;
1214 		}
1215 	}
1216 
1217 	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
1218 			    EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
1219 		if ((mount_flags & EXT2_MF_MOUNTED) &&
1220 		    !(mount_flags & EXT2_MF_READONLY)) {
1221 			fputs(_("The huge_file feature may only be "
1222 				"cleared when the filesystem is\n"
1223 				"unmounted or mounted "
1224 				"read-only.\n"), stderr);
1225 			return 1;
1226 		}
1227 	}
1228 
1229 	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
1230 		       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
1231 		check_fsck_needed(fs,
1232 			_("Enabling checksums could take some time."));
1233 		if (mount_flags & EXT2_MF_MOUNTED) {
1234 			fputs(_("Cannot enable metadata_csum on a mounted "
1235 				"filesystem!\n"), stderr);
1236 			exit(1);
1237 		}
1238 		if (!ext2fs_has_feature_extents(fs->super))
1239 			printf("%s",
1240 			       _("Extents are not enabled.  The file extent "
1241 				 "tree can be checksummed, whereas block maps "
1242 				 "cannot.  Not enabling extents reduces the "
1243 				 "coverage of metadata checksumming.  "
1244 				 "Re-run with -O extent to rectify.\n"));
1245 		if (!ext2fs_has_feature_64bit(fs->super))
1246 			printf("%s",
1247 			       _("64-bit filesystem support is not enabled.  "
1248 				 "The larger fields afforded by this feature "
1249 				 "enable full-strength checksumming.  "
1250 				 "Run resize2fs -b to rectify.\n"));
1251 		rewrite_checksums = 1;
1252 		/* metadata_csum supersedes uninit_bg */
1253 		ext2fs_clear_feature_gdt_csum(fs->super);
1254 
1255 		/* if uninit_bg was previously off, rewrite group desc */
1256 		if (!(old_features[E2P_FEATURE_RO_INCOMPAT] &
1257 		      EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
1258 			enable_uninit_bg(fs);
1259 
1260 		/*
1261 		 * Since metadata_csum supersedes uninit_bg, pretend like
1262 		 * uninit_bg has been off all along.
1263 		 */
1264 		old_features[E2P_FEATURE_RO_INCOMPAT] &=
1265 			~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
1266 	}
1267 
1268 	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
1269 			EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
1270 		__u32	test_features[3];
1271 
1272 		check_fsck_needed(fs,
1273 			_("Disabling checksums could take some time."));
1274 		if (mount_flags & EXT2_MF_MOUNTED) {
1275 			fputs(_("Cannot disable metadata_csum on a mounted "
1276 				"filesystem!\n"), stderr);
1277 			exit(1);
1278 		}
1279 		rewrite_checksums = 1;
1280 
1281 		/* Enable uninit_bg unless the user expressly turned it off */
1282 		memcpy(test_features, old_features, sizeof(test_features));
1283 		test_features[E2P_FEATURE_RO_INCOMPAT] |=
1284 						EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
1285 		e2p_edit_feature2(features, test_features, ok_features,
1286 				  clear_ok_features, NULL, NULL);
1287 		if (test_features[E2P_FEATURE_RO_INCOMPAT] &
1288 						EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
1289 			ext2fs_set_feature_gdt_csum(fs->super);
1290 
1291 		/*
1292 		 * If we're turning off metadata_csum and not turning on
1293 		 * uninit_bg, rewrite group desc.
1294 		 */
1295 		if (!ext2fs_has_feature_gdt_csum(fs->super)) {
1296 			err = disable_uninit_bg(fs,
1297 					EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
1298 			if (err)
1299 				return 1;
1300 		} else
1301 			/*
1302 			 * metadata_csum previously provided uninit_bg, so if
1303 			 * we're also setting the uninit_bg feature bit,
1304 			 * pretend like it was previously enabled.  Checksums
1305 			 * will be rewritten with crc16 later.
1306 			 */
1307 			old_features[E2P_FEATURE_RO_INCOMPAT] |=
1308 				EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
1309 		fs->super->s_checksum_seed = 0;
1310 		ext2fs_clear_feature_csum_seed(fs->super);
1311 	}
1312 
1313 	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
1314 		       EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
1315 		/* Do not enable uninit_bg when metadata_csum enabled */
1316 		if (ext2fs_has_feature_metadata_csum(fs->super))
1317 			ext2fs_clear_feature_gdt_csum(fs->super);
1318 		else
1319 			enable_uninit_bg(fs);
1320 	}
1321 
1322 	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
1323 			EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
1324 		err = disable_uninit_bg(fs,
1325 				EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
1326 		if (err)
1327 			return 1;
1328 	}
1329 
1330 	/*
1331 	 * We don't actually toggle 64bit; resize2fs does that.  But this
1332 	 * must come after the metadata_csum feature_on so that it won't
1333 	 * complain about the lack of 64bit.
1334 	 */
1335 	if (FEATURE_ON(E2P_FEATURE_INCOMPAT,
1336 		       EXT4_FEATURE_INCOMPAT_64BIT)) {
1337 		if (mount_flags & EXT2_MF_MOUNTED) {
1338 			fprintf(stderr, _("Cannot enable 64-bit mode "
1339 					  "while mounted!\n"));
1340 			exit(1);
1341 		}
1342 		ext2fs_clear_feature_64bit(sb);
1343 		feature_64bit = 1;
1344 	}
1345 	if (FEATURE_OFF(E2P_FEATURE_INCOMPAT,
1346 			EXT4_FEATURE_INCOMPAT_64BIT)) {
1347 		if (mount_flags & EXT2_MF_MOUNTED) {
1348 			fprintf(stderr, _("Cannot disable 64-bit mode "
1349 					  "while mounted!\n"));
1350 			exit(1);
1351 		}
1352 		ext2fs_set_feature_64bit(sb);
1353 		feature_64bit = -1;
1354 	}
1355 
1356 	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
1357 				EXT4_FEATURE_RO_COMPAT_QUOTA)) {
1358 		/*
1359 		 * Set the Q_flag here and handle the quota options in the code
1360 		 * below.
1361 		 */
1362 		if (!Q_flag) {
1363 			Q_flag = 1;
1364 			/* Enable usr/grp quota by default */
1365 			for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
1366 				if (qtype != PRJQUOTA)
1367 					quota_enable[qtype] = QOPT_ENABLE;
1368 				else
1369 					quota_enable[qtype] = QOPT_DISABLE;
1370 			}
1371 		}
1372 		ext2fs_clear_feature_quota(sb);
1373 	}
1374 
1375 	if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
1376 		       EXT4_FEATURE_RO_COMPAT_PROJECT)) {
1377 		if (fs->super->s_inode_size == EXT2_GOOD_OLD_INODE_SIZE) {
1378 			fprintf(stderr, _("Cannot enable project feature; "
1379 					  "inode size too small.\n"));
1380 			exit(1);
1381 		}
1382 		Q_flag = 1;
1383 		quota_enable[PRJQUOTA] = QOPT_ENABLE;
1384 	}
1385 
1386 	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
1387 			EXT4_FEATURE_RO_COMPAT_PROJECT)) {
1388 		Q_flag = 1;
1389 		quota_enable[PRJQUOTA] = QOPT_DISABLE;
1390 	}
1391 
1392 	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
1393 				EXT4_FEATURE_RO_COMPAT_QUOTA)) {
1394 		/*
1395 		 * Set the Q_flag here and handle the quota options in the code
1396 		 * below.
1397 		 */
1398 		if (Q_flag)
1399 			fputs(_("\nWarning: '^quota' option overrides '-Q'"
1400 				"arguments.\n"), stderr);
1401 		Q_flag = 1;
1402 		/* Disable all quota by default */
1403 		for (qtype = 0; qtype < MAXQUOTAS; qtype++)
1404 			quota_enable[qtype] = QOPT_DISABLE;
1405 	}
1406 
1407 	if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT)) {
1408 		fs->super->s_encrypt_algos[0] =
1409 			EXT4_ENCRYPTION_MODE_AES_256_XTS;
1410 		fs->super->s_encrypt_algos[1] =
1411 			EXT4_ENCRYPTION_MODE_AES_256_CTS;
1412 	}
1413 
1414 	if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_CASEFOLD)) {
1415 		if (mount_flags & EXT2_MF_MOUNTED) {
1416 			fputs(_("The casefold feature may only be enabled when "
1417 				"the filesystem is unmounted.\n"), stderr);
1418 			return 1;
1419 		}
1420 		fs->super->s_encoding = EXT4_ENC_UTF8_12_1;
1421 		fs->super->s_encoding_flags = e2p_get_encoding_flags(EXT4_ENC_UTF8_12_1);
1422 		enabling_casefold = 1;
1423 	}
1424 
1425 	if (FEATURE_ON(E2P_FEATURE_INCOMPAT,
1426 		EXT4_FEATURE_INCOMPAT_CSUM_SEED)) {
1427 		if (!ext2fs_has_feature_metadata_csum(sb)) {
1428 			fputs(_("Setting feature 'metadata_csum_seed' "
1429 				"is only supported\non filesystems with "
1430 				"the metadata_csum feature enabled.\n"),
1431 				stderr);
1432 			return 1;
1433 		}
1434 		try_confirm_csum_seed_support();
1435 		fs->super->s_checksum_seed = fs->csum_seed;
1436 	}
1437 
1438 	if (FEATURE_OFF(E2P_FEATURE_INCOMPAT,
1439 		EXT4_FEATURE_INCOMPAT_CSUM_SEED)) {
1440 		__le32 uuid_seed;
1441 
1442 		uuid_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid,
1443 					sizeof(fs->super->s_uuid));
1444 		if (fs->super->s_checksum_seed != uuid_seed) {
1445 			if (mount_flags & (EXT2_MF_BUSY|EXT2_MF_MOUNTED)) {
1446 				fputs(_("UUID has changed since enabling "
1447 		"metadata_csum.  Filesystem must be unmounted "
1448 		"\nto safely rewrite all metadata to match the new UUID.\n"),
1449 				      stderr);
1450 				return 1;
1451 			}
1452 			check_fsck_needed(fs, _("Recalculating checksums "
1453 						"could take some time."));
1454 			rewrite_checksums = 1;
1455 		}
1456 	}
1457 
1458 	if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
1459 	    (sb->s_feature_compat || sb->s_feature_ro_compat ||
1460 	     sb->s_feature_incompat))
1461 		ext2fs_update_dynamic_rev(fs);
1462 
1463 	if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT,
1464 			    EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
1465 	    FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
1466 			EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
1467 	    FEATURE_CHANGED(E2P_FEATURE_INCOMPAT,
1468 			    EXT2_FEATURE_INCOMPAT_FILETYPE) ||
1469 	    FEATURE_CHANGED(E2P_FEATURE_COMPAT,
1470 			    EXT2_FEATURE_COMPAT_RESIZE_INODE) ||
1471 	    FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
1472 			EXT2_FEATURE_RO_COMPAT_LARGE_FILE))
1473 		request_fsck_afterwards(fs);
1474 
1475 	if ((old_features[E2P_FEATURE_COMPAT] != sb->s_feature_compat) ||
1476 	    (old_features[E2P_FEATURE_INCOMPAT] != sb->s_feature_incompat) ||
1477 	    (old_features[E2P_FEATURE_RO_INCOMPAT] != sb->s_feature_ro_compat))
1478 		ext2fs_mark_super_dirty(fs);
1479 
1480 	return 0;
1481 }
1482 
1483 /*
1484  * Add a journal to the filesystem.
1485  */
add_journal(ext2_filsys fs)1486 static int add_journal(ext2_filsys fs)
1487 {
1488 	unsigned long journal_blocks;
1489 	errcode_t	retval;
1490 	ext2_filsys	jfs;
1491 	io_manager	io_ptr;
1492 
1493 	if (ext2fs_has_feature_journal(fs->super)) {
1494 		fputs(_("The filesystem already has a journal.\n"), stderr);
1495 		goto err;
1496 	}
1497 	if (journal_device) {
1498 		if (!check_plausibility(journal_device, CHECK_BLOCK_DEV,
1499 					NULL))
1500 			proceed_question(-1);
1501 		check_mount(journal_device, 0, _("journal"));
1502 #ifdef CONFIG_TESTIO_DEBUG
1503 		if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
1504 			io_ptr = test_io_manager;
1505 			test_io_backing_manager = unix_io_manager;
1506 		} else
1507 #endif
1508 			io_ptr = unix_io_manager;
1509 		retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
1510 				     EXT2_FLAG_JOURNAL_DEV_OK, 0,
1511 				     fs->blocksize, io_ptr, &jfs);
1512 		if (retval) {
1513 			com_err(program_name, retval,
1514 				_("\n\twhile trying to open journal on %s\n"),
1515 				journal_device);
1516 			goto err;
1517 		}
1518 		printf(_("Creating journal on device %s: "),
1519 		       journal_device);
1520 		fflush(stdout);
1521 
1522 		retval = ext2fs_add_journal_device(fs, jfs);
1523 		ext2fs_close_free(&jfs);
1524 		if (retval) {
1525 			com_err(program_name, retval,
1526 				_("while adding filesystem to journal on %s"),
1527 				journal_device);
1528 			goto err;
1529 		}
1530 		fputs(_("done\n"), stdout);
1531 	} else if (journal_size) {
1532 		fputs(_("Creating journal inode: "), stdout);
1533 		fflush(stdout);
1534 		journal_blocks = figure_journal_size(journal_size, fs);
1535 
1536 		if (journal_location_string)
1537 			journal_location =
1538 				parse_num_blocks2(journal_location_string,
1539 						  fs->super->s_log_block_size);
1540 		retval = ext2fs_add_journal_inode2(fs, journal_blocks,
1541 						   journal_location,
1542 						   journal_flags);
1543 		if (retval) {
1544 			fprintf(stderr, "\n");
1545 			com_err(program_name, retval, "%s",
1546 				_("\n\twhile trying to create journal file"));
1547 			return retval;
1548 		} else
1549 			fputs(_("done\n"), stdout);
1550 		/*
1551 		 * If the filesystem wasn't mounted, we need to force
1552 		 * the block group descriptors out.
1553 		 */
1554 		if ((mount_flags & EXT2_MF_MOUNTED) == 0)
1555 			fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
1556 	}
1557 	print_check_message(fs->super->s_max_mnt_count,
1558 			    fs->super->s_checkinterval);
1559 	return 0;
1560 
1561 err:
1562 	free(journal_device);
1563 	return 1;
1564 }
1565 
handle_quota_options(ext2_filsys fs)1566 static void handle_quota_options(ext2_filsys fs)
1567 {
1568 	errcode_t retval;
1569 	quota_ctx_t qctx;
1570 	ext2_ino_t qf_ino;
1571 	enum quota_type qtype;
1572 	unsigned int qtype_bits = 0;
1573 	int need_dirty = 0;
1574 
1575 	for (qtype = 0 ; qtype < MAXQUOTAS; qtype++)
1576 		if (quota_enable[qtype] != 0)
1577 			break;
1578 	if (qtype == MAXQUOTAS)
1579 		/* Nothing to do. */
1580 		return;
1581 
1582 	if (quota_enable[PRJQUOTA] == QOPT_ENABLE &&
1583 	    fs->super->s_inode_size == EXT2_GOOD_OLD_INODE_SIZE) {
1584 		fprintf(stderr, _("Cannot enable project quota; "
1585 				  "inode size too small.\n"));
1586 		exit(1);
1587 	}
1588 
1589 	for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
1590 		if (quota_enable[qtype] == QOPT_ENABLE)
1591 			qtype_bits |= 1 << qtype;
1592 	}
1593 
1594 	retval = quota_init_context(&qctx, fs, qtype_bits);
1595 	if (retval) {
1596 		com_err(program_name, retval,
1597 			_("while initializing quota context in support library"));
1598 		exit(1);
1599 	}
1600 
1601 	if (qtype_bits)
1602 		quota_compute_usage(qctx);
1603 
1604 	for (qtype = 0 ; qtype < MAXQUOTAS; qtype++) {
1605 		if (quota_enable[qtype] == QOPT_ENABLE &&
1606 		    *quota_sb_inump(fs->super, qtype) == 0) {
1607 			if ((qf_ino = quota_file_exists(fs, qtype)) > 0) {
1608 				retval = quota_update_limits(qctx, qf_ino,
1609 							     qtype);
1610 				if (retval) {
1611 					com_err(program_name, retval,
1612 						_("while updating quota limits (%d)"),
1613 						qtype);
1614 					exit(1);
1615 				}
1616 			}
1617 			retval = quota_write_inode(qctx, 1 << qtype);
1618 			if (retval) {
1619 				com_err(program_name, retval,
1620 					_("while writing quota file (%d)"),
1621 					qtype);
1622 				exit(1);
1623 			}
1624 			/* Enable Quota feature if one of quota enabled */
1625 			if (!ext2fs_has_feature_quota(fs->super)) {
1626 				ext2fs_set_feature_quota(fs->super);
1627 				need_dirty = 1;
1628 			}
1629 			if (qtype == PRJQUOTA &&
1630 			    !ext2fs_has_feature_project(fs->super)) {
1631 				ext2fs_set_feature_project(fs->super);
1632 				need_dirty = 1;
1633 			}
1634 		} else if (quota_enable[qtype] == QOPT_DISABLE) {
1635 			retval = quota_remove_inode(fs, qtype);
1636 			if (retval) {
1637 				com_err(program_name, retval,
1638 					_("while removing quota file (%d)"),
1639 					qtype);
1640 				exit(1);
1641 			}
1642 			if (qtype == PRJQUOTA) {
1643 				ext2fs_clear_feature_project(fs->super);
1644 				need_dirty = 1;
1645 			}
1646 		}
1647 	}
1648 
1649 	quota_release_context(&qctx);
1650 	/* Clear Quota feature if all quota types disabled. */
1651 	if (!qtype_bits) {
1652 		for (qtype = 0 ; qtype < MAXQUOTAS; qtype++)
1653 			if (*quota_sb_inump(fs->super, qtype))
1654 				break;
1655 		if (qtype == MAXQUOTAS) {
1656 			ext2fs_clear_feature_quota(fs->super);
1657 			need_dirty = 1;
1658 		}
1659 
1660 	}
1661 	if (need_dirty)
1662 		ext2fs_mark_super_dirty(fs);
1663 	return;
1664 }
1665 
option_handle_function(char * token)1666 static int option_handle_function(char *token)
1667 {
1668 	if (strncmp(token, "usr", 3) == 0) {
1669 		quota_enable[USRQUOTA] = QOPT_ENABLE;
1670 	} else if (strncmp(token, "^usr", 4) == 0) {
1671 		quota_enable[USRQUOTA] = QOPT_DISABLE;
1672 	} else if (strncmp(token, "grp", 3) == 0) {
1673 		quota_enable[GRPQUOTA] = QOPT_ENABLE;
1674 	} else if (strncmp(token, "^grp", 4) == 0) {
1675 		quota_enable[GRPQUOTA] = QOPT_DISABLE;
1676 	} else if (strncmp(token, "prj", 3) == 0) {
1677 		quota_enable[PRJQUOTA] = QOPT_ENABLE;
1678 	} else if (strncmp(token, "^prj", 4) == 0) {
1679 		quota_enable[PRJQUOTA] = QOPT_DISABLE;
1680 	} else {
1681 		fputs(_("\nBad quota options specified.\n\n"
1682 			"Following valid quota options are available "
1683 			"(pass by separating with comma):\n"
1684 			"\t[^]usr[quota]\n"
1685 			"\t[^]grp[quota]\n"
1686 			"\t[^]prj[quota]\n"
1687 			"\n\n"), stderr);
1688 		return 1;
1689 	}
1690 	return 0;
1691 }
1692 
parse_e2label_options(int argc,char ** argv)1693 static void parse_e2label_options(int argc, char ** argv)
1694 {
1695 	if ((argc < 2) || (argc > 3)) {
1696 		fputs(_("Usage: e2label device [newlabel]\n"), stderr);
1697 		exit(1);
1698 	}
1699 	io_options = strchr(argv[1], '?');
1700 	if (io_options)
1701 		*io_options++ = 0;
1702 	device_name = blkid_get_devname(NULL, argv[1], NULL);
1703 	if (!device_name) {
1704 		com_err("e2label", 0, _("Unable to resolve '%s'"),
1705 			argv[1]);
1706 		exit(1);
1707 	}
1708 	open_flag = EXT2_FLAG_JOURNAL_DEV_OK;
1709 	if (argc == 3) {
1710 		open_flag |= EXT2_FLAG_RW;
1711 		L_flag = 1;
1712 		new_label = argv[2];
1713 	} else
1714 		print_label++;
1715 }
1716 
parse_time(char * str)1717 static time_t parse_time(char *str)
1718 {
1719 	struct	tm	ts;
1720 
1721 	if (strcmp(str, "now") == 0) {
1722 		return (time(0));
1723 	}
1724 	memset(&ts, 0, sizeof(ts));
1725 #ifdef HAVE_STRPTIME
1726 	strptime(str, "%Y%m%d%H%M%S", &ts);
1727 #else
1728 	sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
1729 	       &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
1730 	ts.tm_year -= 1900;
1731 	ts.tm_mon -= 1;
1732 	if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
1733 	    ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
1734 	    ts.tm_min > 59 || ts.tm_sec > 61)
1735 		ts.tm_mday = 0;
1736 #endif
1737 	if (ts.tm_mday == 0) {
1738 		com_err(program_name, 0,
1739 			_("Couldn't parse date/time specifier: %s"),
1740 			str);
1741 		usage();
1742 	}
1743 	ts.tm_isdst = -1;
1744 	return (mktime(&ts));
1745 }
1746 
parse_tune2fs_options(int argc,char ** argv)1747 static void parse_tune2fs_options(int argc, char **argv)
1748 {
1749 	int c;
1750 	char *tmp;
1751 	struct group *gr;
1752 	struct passwd *pw;
1753 	int ret;
1754 	char optstring[100] = "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:z:Q:";
1755 
1756 	open_flag = 0;
1757 	printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
1758 	while ((c = getopt(argc, argv, optstring)) != EOF)
1759 		switch (c) {
1760 		case 'c':
1761 			max_mount_count = strtol(optarg, &tmp, 0);
1762 			if (*tmp || max_mount_count > 16000) {
1763 				com_err(program_name, 0,
1764 					_("bad mounts count - %s"),
1765 					optarg);
1766 				usage();
1767 			}
1768 			if (max_mount_count == 0)
1769 				max_mount_count = -1;
1770 			c_flag = 1;
1771 			open_flag = EXT2_FLAG_RW;
1772 			break;
1773 		case 'C':
1774 			mount_count = strtoul(optarg, &tmp, 0);
1775 			if (*tmp || mount_count > 16000) {
1776 				com_err(program_name, 0,
1777 					_("bad mounts count - %s"),
1778 					optarg);
1779 				usage();
1780 			}
1781 			C_flag = 1;
1782 			open_flag = EXT2_FLAG_RW;
1783 			break;
1784 		case 'e':
1785 			if (strcmp(optarg, "continue") == 0)
1786 				errors = EXT2_ERRORS_CONTINUE;
1787 			else if (strcmp(optarg, "remount-ro") == 0)
1788 				errors = EXT2_ERRORS_RO;
1789 			else if (strcmp(optarg, "panic") == 0)
1790 				errors = EXT2_ERRORS_PANIC;
1791 			else {
1792 				com_err(program_name, 0,
1793 					_("bad error behavior - %s"),
1794 					optarg);
1795 				usage();
1796 			}
1797 			e_flag = 1;
1798 			open_flag = EXT2_FLAG_RW;
1799 			break;
1800 		case 'E':
1801 			extended_cmd = optarg;
1802 			open_flag |= EXT2_FLAG_RW;
1803 			break;
1804 		case 'f': /* Force */
1805 			f_flag++;
1806 			break;
1807 		case 'g':
1808 			resgid = strtoul(optarg, &tmp, 0);
1809 			if (*tmp) {
1810 				gr = getgrnam(optarg);
1811 				if (gr == NULL)
1812 					tmp = optarg;
1813 				else {
1814 					resgid = gr->gr_gid;
1815 					*tmp = 0;
1816 				}
1817 			}
1818 			if (*tmp) {
1819 				com_err(program_name, 0,
1820 					_("bad gid/group name - %s"),
1821 					optarg);
1822 				usage();
1823 			}
1824 			g_flag = 1;
1825 			open_flag = EXT2_FLAG_RW;
1826 			break;
1827 		case 'i':
1828 			interval = strtoul(optarg, &tmp, 0);
1829 			switch (*tmp) {
1830 			case 's':
1831 				tmp++;
1832 				break;
1833 			case '\0':
1834 			case 'd':
1835 			case 'D': /* days */
1836 				interval *= 86400;
1837 				if (*tmp != '\0')
1838 					tmp++;
1839 				break;
1840 			case 'm':
1841 			case 'M': /* months! */
1842 				interval *= 86400 * 30;
1843 				tmp++;
1844 				break;
1845 			case 'w':
1846 			case 'W': /* weeks */
1847 				interval *= 86400 * 7;
1848 				tmp++;
1849 				break;
1850 			}
1851 			if (*tmp) {
1852 				com_err(program_name, 0,
1853 					_("bad interval - %s"), optarg);
1854 				usage();
1855 			}
1856 			i_flag = 1;
1857 			open_flag = EXT2_FLAG_RW;
1858 			break;
1859 		case 'j':
1860 			if (!journal_size)
1861 				journal_size = -1;
1862 			open_flag = EXT2_FLAG_RW;
1863 			break;
1864 		case 'J':
1865 			parse_journal_opts(optarg);
1866 			open_flag = EXT2_FLAG_RW;
1867 			break;
1868 		case 'l':
1869 			l_flag = 1;
1870 			break;
1871 		case 'L':
1872 			new_label = optarg;
1873 			L_flag = 1;
1874 			open_flag |= EXT2_FLAG_RW |
1875 				EXT2_FLAG_JOURNAL_DEV_OK;
1876 			break;
1877 		case 'm':
1878 			reserved_ratio = strtod(optarg, &tmp);
1879 			if (*tmp || reserved_ratio > 50 ||
1880 			    reserved_ratio < 0) {
1881 				com_err(program_name, 0,
1882 					_("bad reserved block ratio - %s"),
1883 					optarg);
1884 				usage();
1885 			}
1886 			m_flag = 1;
1887 			open_flag = EXT2_FLAG_RW;
1888 			break;
1889 		case 'M':
1890 			new_last_mounted = optarg;
1891 			M_flag = 1;
1892 			open_flag = EXT2_FLAG_RW;
1893 			break;
1894 		case 'o':
1895 			if (mntopts_cmd) {
1896 				com_err(program_name, 0, "%s",
1897 					_("-o may only be specified once"));
1898 				usage();
1899 			}
1900 			mntopts_cmd = optarg;
1901 			open_flag = EXT2_FLAG_RW;
1902 			break;
1903 		case 'O':
1904 			if (features_cmd) {
1905 				com_err(program_name, 0, "%s",
1906 					_("-O may only be specified once"));
1907 				usage();
1908 			}
1909 			features_cmd = optarg;
1910 			open_flag = EXT2_FLAG_RW;
1911 			break;
1912 		case 'Q':
1913 			Q_flag = 1;
1914 			ret = parse_quota_opts(optarg, option_handle_function);
1915 			if (ret)
1916 				exit(1);
1917 			open_flag = EXT2_FLAG_RW;
1918 			break;
1919 		case 'r':
1920 			reserved_blocks = strtoul(optarg, &tmp, 0);
1921 			if (*tmp) {
1922 				com_err(program_name, 0,
1923 					_("bad reserved blocks count - %s"),
1924 					optarg);
1925 				usage();
1926 			}
1927 			r_flag = 1;
1928 			open_flag = EXT2_FLAG_RW;
1929 			break;
1930 		case 's': /* Deprecated */
1931 			s_flag = atoi(optarg);
1932 			open_flag = EXT2_FLAG_RW;
1933 			break;
1934 		case 'T':
1935 			T_flag = 1;
1936 			last_check_time = parse_time(optarg);
1937 			open_flag = EXT2_FLAG_RW;
1938 			break;
1939 		case 'u':
1940 				resuid = strtoul(optarg, &tmp, 0);
1941 				if (*tmp) {
1942 					pw = getpwnam(optarg);
1943 					if (pw == NULL)
1944 						tmp = optarg;
1945 					else {
1946 						resuid = pw->pw_uid;
1947 						*tmp = 0;
1948 					}
1949 				}
1950 				if (*tmp) {
1951 					com_err(program_name, 0,
1952 						_("bad uid/user name - %s"),
1953 						optarg);
1954 					usage();
1955 				}
1956 				u_flag = 1;
1957 				open_flag = EXT2_FLAG_RW;
1958 				break;
1959 		case 'U':
1960 			new_UUID = optarg;
1961 			U_flag = 1;
1962 			open_flag = EXT2_FLAG_RW |
1963 				EXT2_FLAG_JOURNAL_DEV_OK;
1964 			break;
1965 		case 'I':
1966 			new_inode_size = strtoul(optarg, &tmp, 0);
1967 			if (*tmp) {
1968 				com_err(program_name, 0,
1969 					_("bad inode size - %s"),
1970 					optarg);
1971 				usage();
1972 			}
1973 			if (!((new_inode_size &
1974 			       (new_inode_size - 1)) == 0)) {
1975 				com_err(program_name, 0,
1976 					_("Inode size must be a "
1977 					  "power of two- %s"),
1978 					optarg);
1979 				usage();
1980 			}
1981 			open_flag = EXT2_FLAG_RW;
1982 			I_flag = 1;
1983 			break;
1984 		case 'z':
1985 			undo_file = optarg;
1986 			break;
1987 		default:
1988 			usage();
1989 		}
1990 	if (optind < argc - 1 || optind == argc)
1991 		usage();
1992 	if (!open_flag && !l_flag)
1993 		usage();
1994 	io_options = strchr(argv[optind], '?');
1995 	if (io_options)
1996 		*io_options++ = 0;
1997 	device_name = blkid_get_devname(NULL, argv[optind], NULL);
1998 	if (!device_name) {
1999 		com_err(program_name, 0, _("Unable to resolve '%s'"),
2000 			argv[optind]);
2001 		exit(1);
2002 	}
2003 }
2004 
2005 #ifdef CONFIG_BUILD_FINDFS
do_findfs(int argc,char ** argv)2006 void do_findfs(int argc, char **argv)
2007 {
2008 	char	*dev;
2009 
2010 	if ((argc != 2) ||
2011 	    (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) {
2012 		fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n");
2013 		exit(2);
2014 	}
2015 	dev = blkid_get_devname(NULL, argv[1], NULL);
2016 	if (!dev) {
2017 		com_err("findfs", 0, _("Unable to resolve '%s'"),
2018 			argv[1]);
2019 		exit(1);
2020 	}
2021 	puts(dev);
2022 	exit(0);
2023 }
2024 #endif
2025 
parse_extended_opts(ext2_filsys fs,const char * opts)2026 static int parse_extended_opts(ext2_filsys fs, const char *opts)
2027 {
2028 	struct ext2_super_block *sb = fs->super;
2029 	char	*buf, *token, *next, *p, *arg;
2030 	int	len, hash_alg;
2031 	int	r_usage = 0;
2032 	int encoding = 0;
2033 	char	*encoding_flags = NULL;
2034 
2035 	len = strlen(opts);
2036 	buf = malloc(len+1);
2037 	if (!buf) {
2038 		fprintf(stderr, "%s",
2039 			_("Couldn't allocate memory to parse options!\n"));
2040 		return 1;
2041 	}
2042 	strcpy(buf, opts);
2043 	for (token = buf; token && *token; token = next) {
2044 		p = strchr(token, ',');
2045 		next = 0;
2046 		if (p) {
2047 			*p = 0;
2048 			next = p+1;
2049 		}
2050 		arg = strchr(token, '=');
2051 		if (arg) {
2052 			*arg = 0;
2053 			arg++;
2054 		}
2055 		if (strcmp(token, "clear-mmp") == 0 ||
2056 		    strcmp(token, "clear_mmp") == 0) {
2057 			clear_mmp = 1;
2058 		} else if (strcmp(token, "mmp_update_interval") == 0) {
2059 			unsigned long intv;
2060 			if (!arg) {
2061 				r_usage++;
2062 				continue;
2063 			}
2064 			intv = strtoul(arg, &p, 0);
2065 			if (*p) {
2066 				fprintf(stderr,
2067 					_("Invalid mmp_update_interval: %s\n"),
2068 					arg);
2069 				r_usage++;
2070 				continue;
2071 			}
2072 			if (intv == 0) {
2073 				intv = EXT4_MMP_UPDATE_INTERVAL;
2074 			} else if (intv > EXT4_MMP_MAX_UPDATE_INTERVAL) {
2075 				fprintf(stderr,
2076 					_("mmp_update_interval too big: %lu\n"),
2077 					intv);
2078 				r_usage++;
2079 				continue;
2080 			}
2081 			printf(P_("Setting multiple mount protection update "
2082 				  "interval to %lu second\n",
2083 				  "Setting multiple mount protection update "
2084 				  "interval to %lu seconds\n", intv),
2085 			       intv);
2086 			sb->s_mmp_update_interval = intv;
2087 			ext2fs_mark_super_dirty(fs);
2088 		} else if (!strcmp(token, "force_fsck")) {
2089 			sb->s_state |= EXT2_ERROR_FS;
2090 			printf(_("Setting filesystem error flag to force fsck.\n"));
2091 			ext2fs_mark_super_dirty(fs);
2092 		} else if (!strcmp(token, "test_fs")) {
2093 			sb->s_flags |= EXT2_FLAGS_TEST_FILESYS;
2094 			printf("Setting test filesystem flag\n");
2095 			ext2fs_mark_super_dirty(fs);
2096 		} else if (!strcmp(token, "^test_fs")) {
2097 			sb->s_flags &= ~EXT2_FLAGS_TEST_FILESYS;
2098 			printf("Clearing test filesystem flag\n");
2099 			ext2fs_mark_super_dirty(fs);
2100 		} else if (strcmp(token, "stride") == 0) {
2101 			if (!arg) {
2102 				r_usage++;
2103 				continue;
2104 			}
2105 			stride = strtoul(arg, &p, 0);
2106 			if (*p) {
2107 				fprintf(stderr,
2108 					_("Invalid RAID stride: %s\n"),
2109 					arg);
2110 				r_usage++;
2111 				continue;
2112 			}
2113 			stride_set = 1;
2114 		} else if (strcmp(token, "stripe-width") == 0 ||
2115 			   strcmp(token, "stripe_width") == 0) {
2116 			if (!arg) {
2117 				r_usage++;
2118 				continue;
2119 			}
2120 			stripe_width = strtoul(arg, &p, 0);
2121 			if (*p) {
2122 				fprintf(stderr,
2123 					_("Invalid RAID stripe-width: %s\n"),
2124 					arg);
2125 				r_usage++;
2126 				continue;
2127 			}
2128 			stripe_width_set = 1;
2129 		} else if (strcmp(token, "hash_alg") == 0 ||
2130 			   strcmp(token, "hash-alg") == 0) {
2131 			if (!arg) {
2132 				r_usage++;
2133 				continue;
2134 			}
2135 			hash_alg = e2p_string2hash(arg);
2136 			if (hash_alg < 0) {
2137 				fprintf(stderr,
2138 					_("Invalid hash algorithm: %s\n"),
2139 					arg);
2140 				r_usage++;
2141 				continue;
2142 			}
2143 			sb->s_def_hash_version = hash_alg;
2144 			printf(_("Setting default hash algorithm "
2145 				 "to %s (%d)\n"),
2146 			       arg, hash_alg);
2147 			ext2fs_mark_super_dirty(fs);
2148 		} else if (!strcmp(token, "mount_opts")) {
2149 			if (!arg) {
2150 				r_usage++;
2151 				continue;
2152 			}
2153 			if (strlen(arg) >= sizeof(fs->super->s_mount_opts)) {
2154 				fprintf(stderr,
2155 					"Extended mount options too long\n");
2156 				continue;
2157 			}
2158 			ext_mount_opts = strdup(arg);
2159 		} else if (!strcmp(token, "encoding")) {
2160 			if (!arg) {
2161 				r_usage++;
2162 				continue;
2163 			}
2164 			if (mount_flags & EXT2_MF_MOUNTED) {
2165 				fputs(_("The casefold feature may only be enabled when "
2166 					"the filesystem is unmounted.\n"), stderr);
2167 				r_usage++;
2168 				continue;
2169 			}
2170 			if (ext2fs_has_feature_casefold(sb) && !enabling_casefold) {
2171 				fprintf(stderr, _("Cannot alter existing encoding\n"));
2172 				r_usage++;
2173 				continue;
2174 			}
2175 			encoding = e2p_str2encoding(arg);
2176 			if (encoding < 0) {
2177 				fprintf(stderr, _("Invalid encoding: %s\n"), arg);
2178 				r_usage++;
2179 				continue;
2180 			}
2181 			enabling_casefold = 1;
2182 			sb->s_encoding = encoding;
2183 			printf(_("Setting encoding to '%s'\n"), arg);
2184 			sb->s_encoding_flags =
2185 				e2p_get_encoding_flags(sb->s_encoding);
2186 		} else if (!strcmp(token, "encoding_flags")) {
2187 			if (!arg) {
2188 				r_usage++;
2189 				continue;
2190 			}
2191 			encoding_flags = arg;
2192 		} else
2193 			r_usage++;
2194 	}
2195 
2196 	if (encoding > 0 && !r_usage) {
2197 		sb->s_encoding_flags =
2198 			e2p_get_encoding_flags(sb->s_encoding);
2199 
2200 		if (encoding_flags &&
2201 		    e2p_str2encoding_flags(sb->s_encoding, encoding_flags,
2202 					   &sb->s_encoding_flags)) {
2203 			fprintf(stderr, _("error: Invalid encoding flag: %s\n"),
2204 					encoding_flags);
2205 			r_usage++;
2206 		} else if (encoding_flags)
2207 			printf(_("Setting encoding_flags to '%s'\n"),
2208 				 encoding_flags);
2209 		ext2fs_set_feature_casefold(sb);
2210 		ext2fs_mark_super_dirty(fs);
2211 	} else if (encoding_flags && !r_usage) {
2212 		fprintf(stderr, _("error: An encoding must be explicitly "
2213 				  "specified when passing encoding-flags\n"));
2214 		r_usage++;
2215 	}
2216 	if (r_usage) {
2217 		fprintf(stderr, "%s", _("\nBad options specified.\n\n"
2218 			"Extended options are separated by commas, "
2219 			"and may take an argument which\n"
2220 			"\tis set off by an equals ('=') sign.\n\n"
2221 			"Valid extended options are:\n"
2222 			"\tclear_mmp\n"
2223 			"\thash_alg=<hash algorithm>\n"
2224 			"\tmount_opts=<extended default mount options>\n"
2225 			"\tmmp_update_interval=<mmp update interval in seconds>\n"
2226 			"\tstride=<RAID per-disk chunk size in blocks>\n"
2227 			"\tstripe_width=<RAID stride*data disks in blocks>\n"
2228 			"\tforce_fsck\n"
2229 			"\ttest_fs\n"
2230 			"\t^test_fs\n"
2231 			"\tencoding=<encoding>\n"
2232 			"\tencoding_flags=<flags>\n"));
2233 		free(buf);
2234 		return 1;
2235 	}
2236 	free(buf);
2237 
2238 	return 0;
2239 }
2240 
2241 /*
2242  * Fill in the block bitmap bmap with the information regarding the
2243  * blocks to be moved
2244  */
get_move_bitmaps(ext2_filsys fs,int new_ino_blks_per_grp,ext2fs_block_bitmap bmap)2245 static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
2246 			    ext2fs_block_bitmap bmap)
2247 {
2248 	dgrp_t i;
2249 	int retval;
2250 	ext2_badblocks_list bb_list = 0;
2251 	blk64_t j, needed_blocks = 0;
2252 	blk64_t start_blk, end_blk;
2253 
2254 	retval = ext2fs_read_bb_inode(fs, &bb_list);
2255 	if (retval)
2256 		return retval;
2257 
2258 	for (i = 0; i < fs->group_desc_count; i++) {
2259 		start_blk = ext2fs_inode_table_loc(fs, i) +
2260 					fs->inode_blocks_per_group;
2261 
2262 		end_blk = ext2fs_inode_table_loc(fs, i) +
2263 					new_ino_blks_per_grp;
2264 
2265 		for (j = start_blk; j < end_blk; j++) {
2266 			if (ext2fs_test_block_bitmap2(fs->block_map, j)) {
2267 				/*
2268 				 * IF the block is a bad block we fail
2269 				 */
2270 				if (ext2fs_badblocks_list_test(bb_list, j)) {
2271 					ext2fs_badblocks_list_free(bb_list);
2272 					return ENOSPC;
2273 				}
2274 
2275 				ext2fs_mark_block_bitmap2(bmap, j);
2276 			} else {
2277 				/*
2278 				 * We are going to use this block for
2279 				 * inode table. So mark them used.
2280 				 */
2281 				ext2fs_mark_block_bitmap2(fs->block_map, j);
2282 			}
2283 		}
2284 		needed_blocks += end_blk - start_blk;
2285 	}
2286 
2287 	ext2fs_badblocks_list_free(bb_list);
2288 	if (needed_blocks > ext2fs_free_blocks_count(fs->super))
2289 		return ENOSPC;
2290 
2291 	return 0;
2292 }
2293 
ext2fs_is_meta_block(ext2_filsys fs,blk64_t blk)2294 static int ext2fs_is_meta_block(ext2_filsys fs, blk64_t blk)
2295 {
2296 	dgrp_t group;
2297 	group = ext2fs_group_of_blk2(fs, blk);
2298 	if (ext2fs_block_bitmap_loc(fs, group) == blk)
2299 		return 1;
2300 	if (ext2fs_inode_bitmap_loc(fs, group) == blk)
2301 		return 1;
2302 	return 0;
2303 }
2304 
ext2fs_is_block_in_group(ext2_filsys fs,dgrp_t group,blk64_t blk)2305 static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk64_t blk)
2306 {
2307 	blk64_t start_blk, end_blk;
2308 	start_blk = fs->super->s_first_data_block +
2309 			EXT2_GROUPS_TO_BLOCKS(fs->super, group);
2310 	/*
2311 	 * We cannot get new block beyond end_blk for for the last block group
2312 	 * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group
2313 	 */
2314 	end_blk   = start_blk + EXT2_BLOCKS_PER_GROUP(fs->super);
2315 	if (blk >= start_blk && blk <= end_blk)
2316 		return 1;
2317 	return 0;
2318 }
2319 
move_block(ext2_filsys fs,ext2fs_block_bitmap bmap)2320 static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
2321 {
2322 
2323 	char *buf;
2324 	dgrp_t group = 0;
2325 	errcode_t retval;
2326 	int meta_data = 0;
2327 	blk64_t blk, new_blk, goal;
2328 	struct blk_move *bmv;
2329 
2330 	retval = ext2fs_get_mem(fs->blocksize, &buf);
2331 	if (retval)
2332 		return retval;
2333 
2334 	for (new_blk = blk = fs->super->s_first_data_block;
2335 	     blk < ext2fs_blocks_count(fs->super); blk++) {
2336 		if (!ext2fs_test_block_bitmap2(bmap, blk))
2337 			continue;
2338 
2339 		if (ext2fs_is_meta_block(fs, blk)) {
2340 			/*
2341 			 * If the block is mapping a fs meta data block
2342 			 * like group desc/block bitmap/inode bitmap. We
2343 			 * should find a block in the same group and fix
2344 			 * the respective fs metadata pointers. Otherwise
2345 			 * fail
2346 			 */
2347 			group = ext2fs_group_of_blk2(fs, blk);
2348 			goal = ext2fs_group_first_block2(fs, group);
2349 			meta_data = 1;
2350 
2351 		} else {
2352 			goal = new_blk;
2353 		}
2354 		retval = ext2fs_new_block2(fs, goal, NULL, &new_blk);
2355 		if (retval)
2356 			goto err_out;
2357 
2358 		/* new fs meta data block should be in the same group */
2359 		if (meta_data && !ext2fs_is_block_in_group(fs, group, new_blk)) {
2360 			retval = ENOSPC;
2361 			goto err_out;
2362 		}
2363 
2364 		/* Mark this block as allocated */
2365 		ext2fs_mark_block_bitmap2(fs->block_map, new_blk);
2366 
2367 		/* Add it to block move list */
2368 		retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv);
2369 		if (retval)
2370 			goto err_out;
2371 
2372 		bmv->old_loc = blk;
2373 		bmv->new_loc = new_blk;
2374 
2375 		list_add(&(bmv->list), &blk_move_list);
2376 
2377 		retval = io_channel_read_blk64(fs->io, blk, 1, buf);
2378 		if (retval)
2379 			goto err_out;
2380 
2381 		retval = io_channel_write_blk64(fs->io, new_blk, 1, buf);
2382 		if (retval)
2383 			goto err_out;
2384 	}
2385 
2386 err_out:
2387 	ext2fs_free_mem(&buf);
2388 	return retval;
2389 }
2390 
translate_block(blk64_t blk)2391 static blk64_t translate_block(blk64_t blk)
2392 {
2393 	struct list_head *entry;
2394 	struct blk_move *bmv;
2395 
2396 	list_for_each(entry, &blk_move_list) {
2397 		bmv = list_entry(entry, struct blk_move, list);
2398 		if (bmv->old_loc == blk)
2399 			return bmv->new_loc;
2400 	}
2401 
2402 	return 0;
2403 }
2404 
process_block(ext2_filsys fs EXT2FS_ATTR ((unused)),blk64_t * block_nr,e2_blkcnt_t blockcnt EXT2FS_ATTR ((unused)),blk64_t ref_block EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv_data)2405 static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)),
2406 			 blk64_t *block_nr,
2407 			 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
2408 			 blk64_t ref_block EXT2FS_ATTR((unused)),
2409 			 int ref_offset EXT2FS_ATTR((unused)),
2410 			 void *priv_data)
2411 {
2412 	int ret = 0;
2413 	blk64_t new_blk;
2414 	ext2fs_block_bitmap bmap = (ext2fs_block_bitmap) priv_data;
2415 
2416 	if (!ext2fs_test_block_bitmap2(bmap, *block_nr))
2417 		return 0;
2418 	new_blk = translate_block(*block_nr);
2419 	if (new_blk) {
2420 		*block_nr = new_blk;
2421 		/*
2422 		 * This will force the ext2fs_write_inode in the iterator
2423 		 */
2424 		ret |= BLOCK_CHANGED;
2425 	}
2426 
2427 	return ret;
2428 }
2429 
inode_scan_and_fix(ext2_filsys fs,ext2fs_block_bitmap bmap)2430 static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
2431 {
2432 	errcode_t retval = 0;
2433 	ext2_ino_t ino;
2434 	blk64_t blk;
2435 	char *block_buf = 0;
2436 	struct ext2_inode inode;
2437 	ext2_inode_scan	scan = NULL;
2438 
2439 	retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
2440 	if (retval)
2441 		return retval;
2442 
2443 	retval = ext2fs_open_inode_scan(fs, 0, &scan);
2444 	if (retval)
2445 		goto err_out;
2446 
2447 	while (1) {
2448 		retval = ext2fs_get_next_inode(scan, &ino, &inode);
2449 		if (retval)
2450 			goto err_out;
2451 
2452 		if (!ino)
2453 			break;
2454 
2455 		if (inode.i_links_count == 0)
2456 			continue; /* inode not in use */
2457 
2458 		/* FIXME!!
2459 		 * If we end up modifying the journal inode
2460 		 * the sb->s_jnl_blocks will differ. But a
2461 		 * subsequent e2fsck fixes that.
2462 		 * Do we need to fix this ??
2463 		 */
2464 
2465 		if (ext2fs_file_acl_block(fs, &inode) &&
2466 		    ext2fs_test_block_bitmap2(bmap,
2467 					ext2fs_file_acl_block(fs, &inode))) {
2468 			blk = translate_block(ext2fs_file_acl_block(fs,
2469 								    &inode));
2470 			if (!blk)
2471 				continue;
2472 
2473 			ext2fs_file_acl_block_set(fs, &inode, blk);
2474 
2475 			/*
2476 			 * Write the inode to disk so that inode table
2477 			 * resizing can work
2478 			 */
2479 			retval = ext2fs_write_inode(fs, ino, &inode);
2480 			if (retval)
2481 				goto err_out;
2482 		}
2483 
2484 		if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
2485 			continue;
2486 
2487 		retval = ext2fs_block_iterate3(fs, ino, 0, block_buf,
2488 					       process_block, bmap);
2489 		if (retval)
2490 			goto err_out;
2491 
2492 	}
2493 
2494 err_out:
2495 	ext2fs_free_mem(&block_buf);
2496 	ext2fs_close_inode_scan(scan);
2497 
2498 	return retval;
2499 }
2500 
2501 /*
2502  * We need to scan for inode and block bitmaps that may need to be
2503  * moved.  This can take place if the filesystem was formatted for
2504  * RAID arrays using the mke2fs's extended option "stride".
2505  */
group_desc_scan_and_fix(ext2_filsys fs,ext2fs_block_bitmap bmap)2506 static int group_desc_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
2507 {
2508 	dgrp_t i;
2509 	blk64_t blk, new_blk;
2510 
2511 	for (i = 0; i < fs->group_desc_count; i++) {
2512 		blk = ext2fs_block_bitmap_loc(fs, i);
2513 		if (ext2fs_test_block_bitmap2(bmap, blk)) {
2514 			new_blk = translate_block(blk);
2515 			if (!new_blk)
2516 				continue;
2517 			ext2fs_block_bitmap_loc_set(fs, i, new_blk);
2518 		}
2519 
2520 		blk = ext2fs_inode_bitmap_loc(fs, i);
2521 		if (ext2fs_test_block_bitmap2(bmap, blk)) {
2522 			new_blk = translate_block(blk);
2523 			if (!new_blk)
2524 				continue;
2525 			ext2fs_inode_bitmap_loc_set(fs, i, new_blk);
2526 		}
2527 	}
2528 	return 0;
2529 }
2530 
expand_inode_table(ext2_filsys fs,unsigned long new_ino_size)2531 static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size)
2532 {
2533 	dgrp_t i;
2534 	blk64_t blk;
2535 	errcode_t retval;
2536 	int new_ino_blks_per_grp;
2537 	unsigned int j;
2538 	char *old_itable = NULL, *new_itable = NULL;
2539 	char *tmp_old_itable = NULL, *tmp_new_itable = NULL;
2540 	unsigned long old_ino_size;
2541 	int old_itable_size, new_itable_size;
2542 
2543 	old_itable_size = fs->inode_blocks_per_group * fs->blocksize;
2544 	old_ino_size = EXT2_INODE_SIZE(fs->super);
2545 
2546 	new_ino_blks_per_grp = ext2fs_div_ceil(
2547 					EXT2_INODES_PER_GROUP(fs->super) *
2548 					new_ino_size,
2549 					fs->blocksize);
2550 
2551 	new_itable_size = new_ino_blks_per_grp * fs->blocksize;
2552 
2553 	retval = ext2fs_get_mem(old_itable_size, &old_itable);
2554 	if (retval)
2555 		return retval;
2556 
2557 	retval = ext2fs_get_mem(new_itable_size, &new_itable);
2558 	if (retval)
2559 		goto err_out;
2560 
2561 	tmp_old_itable = old_itable;
2562 	tmp_new_itable = new_itable;
2563 
2564 	for (i = 0; i < fs->group_desc_count; i++) {
2565 		blk = ext2fs_inode_table_loc(fs, i);
2566 		retval = io_channel_read_blk64(fs->io, blk,
2567 				fs->inode_blocks_per_group, old_itable);
2568 		if (retval)
2569 			goto err_out;
2570 
2571 		for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) {
2572 			memcpy(new_itable, old_itable, old_ino_size);
2573 
2574 			memset(new_itable+old_ino_size, 0,
2575 					new_ino_size - old_ino_size);
2576 
2577 			new_itable += new_ino_size;
2578 			old_itable += old_ino_size;
2579 		}
2580 
2581 		/* reset the pointer */
2582 		old_itable = tmp_old_itable;
2583 		new_itable = tmp_new_itable;
2584 
2585 		retval = io_channel_write_blk64(fs->io, blk,
2586 					new_ino_blks_per_grp, new_itable);
2587 		if (retval)
2588 			goto err_out;
2589 	}
2590 
2591 	/* Update the meta data */
2592 	fs->inode_blocks_per_group = new_ino_blks_per_grp;
2593 	ext2fs_free_inode_cache(fs->icache);
2594 	fs->icache = 0;
2595 	fs->super->s_inode_size = new_ino_size;
2596 
2597 err_out:
2598 	if (old_itable)
2599 		ext2fs_free_mem(&old_itable);
2600 
2601 	if (new_itable)
2602 		ext2fs_free_mem(&new_itable);
2603 
2604 	return retval;
2605 }
2606 
ext2fs_calculate_summary_stats(ext2_filsys fs)2607 static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
2608 {
2609 	blk64_t		blk;
2610 	ext2_ino_t	ino;
2611 	unsigned int	group = 0;
2612 	unsigned int	count = 0;
2613 	int		total_free = 0;
2614 	int		group_free = 0;
2615 
2616 	/*
2617 	 * First calculate the block statistics
2618 	 */
2619 	for (blk = fs->super->s_first_data_block;
2620 	     blk < ext2fs_blocks_count(fs->super); blk++) {
2621 		if (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk)) {
2622 			group_free++;
2623 			total_free++;
2624 		}
2625 		count++;
2626 		if ((count == fs->super->s_blocks_per_group) ||
2627 		    (blk == ext2fs_blocks_count(fs->super)-1)) {
2628 			ext2fs_bg_free_blocks_count_set(fs, group++,
2629 							group_free);
2630 			count = 0;
2631 			group_free = 0;
2632 		}
2633 	}
2634 	total_free = EXT2FS_C2B(fs, total_free);
2635 	ext2fs_free_blocks_count_set(fs->super, total_free);
2636 
2637 	/*
2638 	 * Next, calculate the inode statistics
2639 	 */
2640 	group_free = 0;
2641 	total_free = 0;
2642 	count = 0;
2643 	group = 0;
2644 
2645 	/* Protect loop from wrap-around if s_inodes_count maxed */
2646 	for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
2647 		if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
2648 			group_free++;
2649 			total_free++;
2650 		}
2651 		count++;
2652 		if ((count == fs->super->s_inodes_per_group) ||
2653 		    (ino == fs->super->s_inodes_count)) {
2654 			ext2fs_bg_free_inodes_count_set(fs, group++,
2655 							group_free);
2656 			count = 0;
2657 			group_free = 0;
2658 		}
2659 	}
2660 	fs->super->s_free_inodes_count = total_free;
2661 	ext2fs_mark_super_dirty(fs);
2662 	return 0;
2663 }
2664 
2665 #define list_for_each_safe(pos, pnext, head) \
2666 	for (pos = (head)->next, pnext = pos->next; pos != (head); \
2667 	     pos = pnext, pnext = pos->next)
2668 
free_blk_move_list(void)2669 static void free_blk_move_list(void)
2670 {
2671 	struct list_head *entry, *tmp;
2672 	struct blk_move *bmv;
2673 
2674 	list_for_each_safe(entry, tmp, &blk_move_list) {
2675 		bmv = list_entry(entry, struct blk_move, list);
2676 		list_del(entry);
2677 		ext2fs_free_mem(&bmv);
2678 	}
2679 	return;
2680 }
2681 
resize_inode(ext2_filsys fs,unsigned long new_size)2682 static int resize_inode(ext2_filsys fs, unsigned long new_size)
2683 {
2684 	errcode_t retval;
2685 	int new_ino_blks_per_grp;
2686 	ext2fs_block_bitmap bmap;
2687 
2688 	retval = ext2fs_read_inode_bitmap(fs);
2689 	if (retval) {
2690 		fputs(_("Failed to read inode bitmap\n"), stderr);
2691 		return retval;
2692 	}
2693 	retval = ext2fs_read_block_bitmap(fs);
2694 	if (retval) {
2695 		fputs(_("Failed to read block bitmap\n"), stderr);
2696 		return retval;
2697 	}
2698 	INIT_LIST_HEAD(&blk_move_list);
2699 
2700 
2701 	new_ino_blks_per_grp = ext2fs_div_ceil(
2702 					EXT2_INODES_PER_GROUP(fs->super)*
2703 					new_size,
2704 					fs->blocksize);
2705 
2706 	/* We may change the file system.
2707 	 * Mark the file system as invalid so that
2708 	 * the user is prompted to run fsck.
2709 	 */
2710 	fs->super->s_state &= ~EXT2_VALID_FS;
2711 
2712 	retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
2713 						&bmap);
2714 	if (retval) {
2715 		fputs(_("Failed to allocate block bitmap when "
2716 				"increasing inode size\n"), stderr);
2717 		return retval;
2718 	}
2719 	retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap);
2720 	if (retval) {
2721 		fputs(_("Not enough space to increase inode size \n"), stderr);
2722 		goto err_out;
2723 	}
2724 	retval = move_block(fs, bmap);
2725 	if (retval) {
2726 		fputs(_("Failed to relocate blocks during inode resize \n"),
2727 		      stderr);
2728 		goto err_out;
2729 	}
2730 	retval = inode_scan_and_fix(fs, bmap);
2731 	if (retval)
2732 		goto err_out_undo;
2733 
2734 	retval = group_desc_scan_and_fix(fs, bmap);
2735 	if (retval)
2736 		goto err_out_undo;
2737 
2738 	retval = expand_inode_table(fs, new_size);
2739 	if (retval)
2740 		goto err_out_undo;
2741 
2742 	ext2fs_calculate_summary_stats(fs);
2743 
2744 	fs->super->s_state |= EXT2_VALID_FS;
2745 	/* mark super block and block bitmap as dirty */
2746 	ext2fs_mark_super_dirty(fs);
2747 	ext2fs_mark_bb_dirty(fs);
2748 
2749 err_out:
2750 	free_blk_move_list();
2751 	ext2fs_free_block_bitmap(bmap);
2752 
2753 	return retval;
2754 
2755 err_out_undo:
2756 	free_blk_move_list();
2757 	ext2fs_free_block_bitmap(bmap);
2758 	fputs(_("Error in resizing the inode size.\n"
2759 			"Run e2undo to undo the "
2760 			"file system changes. \n"), stderr);
2761 
2762 	return retval;
2763 }
2764 
tune2fs_setup_tdb(const char * name,io_manager * io_ptr)2765 static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
2766 {
2767 	errcode_t retval = 0;
2768 	const char *tdb_dir;
2769 	char *tdb_file = NULL;
2770 	char *dev_name, *tmp_name;
2771 
2772 	/* (re)open a specific undo file */
2773 	if (undo_file && undo_file[0] != 0) {
2774 		retval = set_undo_io_backing_manager(*io_ptr);
2775 		if (retval)
2776 			goto err;
2777 		*io_ptr = undo_io_manager;
2778 		retval = set_undo_io_backup_file(undo_file);
2779 		if (retval)
2780 			goto err;
2781 		printf(_("Overwriting existing filesystem; this can be undone "
2782 			 "using the command:\n"
2783 			 "    e2undo %s %s\n\n"),
2784 			 undo_file, name);
2785 		return retval;
2786 	}
2787 
2788 	/*
2789 	 * Configuration via a conf file would be
2790 	 * nice
2791 	 */
2792 	tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
2793 	if (!tdb_dir)
2794 		tdb_dir = "/var/lib/e2fsprogs";
2795 
2796 	if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
2797 	    access(tdb_dir, W_OK))
2798 		return 0;
2799 
2800 	tmp_name = strdup(name);
2801 	if (!tmp_name)
2802 		goto errout;
2803 	dev_name = basename(tmp_name);
2804 	tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1);
2805 	if (!tdb_file) {
2806 		free(tmp_name);
2807 		goto errout;
2808 	}
2809 	sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name);
2810 	free(tmp_name);
2811 
2812 	if ((unlink(tdb_file) < 0) && (errno != ENOENT)) {
2813 		retval = errno;
2814 		com_err(program_name, retval,
2815 			_("while trying to delete %s"), tdb_file);
2816 		goto errout;
2817 	}
2818 
2819 	retval = set_undo_io_backing_manager(*io_ptr);
2820 	if (retval)
2821 		goto errout;
2822 	*io_ptr = undo_io_manager;
2823 	retval = set_undo_io_backup_file(tdb_file);
2824 	if (retval)
2825 		goto errout;
2826 	printf(_("Overwriting existing filesystem; this can be undone "
2827 		 "using the command:\n"
2828 		 "    e2undo %s %s\n\n"),
2829 		 tdb_file, name);
2830 
2831 	free(tdb_file);
2832 	return 0;
2833 errout:
2834 	free(tdb_file);
2835 err:
2836 	com_err("tune2fs", retval, "while trying to setup undo file\n");
2837 	return retval;
2838 }
2839 
2840 static int
fs_update_journal_user(struct ext2_super_block * sb,__u8 old_uuid[UUID_SIZE])2841 fs_update_journal_user(struct ext2_super_block *sb, __u8 old_uuid[UUID_SIZE])
2842 {
2843 	int retval, nr_users, start;
2844 	journal_superblock_t *jsb;
2845 	ext2_filsys jfs;
2846 	__u8 *j_uuid;
2847 	char *journal_path;
2848 	char uuid[UUID_STR_SIZE];
2849 	char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8)));
2850 
2851 	if (!ext2fs_has_feature_journal(sb) || uuid_is_null(sb->s_journal_uuid))
2852 		return 0;
2853 
2854 	uuid_unparse(sb->s_journal_uuid, uuid);
2855 	journal_path = blkid_get_devname(NULL, "UUID", uuid);
2856 	if (!journal_path)
2857 		return 0;
2858 
2859 	retval = ext2fs_open2(journal_path, io_options,
2860 			      EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_RW,
2861 			      0, 0, unix_io_manager, &jfs);
2862 	if (retval) {
2863 		com_err(program_name, retval,
2864 			_("while trying to open %s"),
2865 			journal_path);
2866 		return retval;
2867 	}
2868 
2869 	retval = get_journal_sb(jfs, buf);
2870 	if (retval != 0) {
2871 		if (retval == EXT2_ET_UNSUPP_FEATURE)
2872 			fprintf(stderr, _("%s is not a journal device.\n"),
2873 				journal_path);
2874 		return retval;
2875 	}
2876 
2877 	jsb = (journal_superblock_t *) buf;
2878 	/* Find the filesystem UUID */
2879 	nr_users = ntohl(jsb->s_nr_users);
2880 	if (nr_users > JFS_USERS_MAX) {
2881 		fprintf(stderr, _("Journal superblock is corrupted, nr_users\n"
2882 				 "is too high (%d).\n"), nr_users);
2883 		return EXT2_ET_CORRUPT_JOURNAL_SB;
2884 	}
2885 
2886 	j_uuid = journal_user(old_uuid, jsb->s_users, nr_users);
2887 	if (j_uuid == NULL) {
2888 		fputs(_("Filesystem's UUID not found on journal device.\n"),
2889 		      stderr);
2890 		return EXT2_ET_LOAD_EXT_JOURNAL;
2891 	}
2892 
2893 	memcpy(j_uuid, sb->s_uuid, UUID_SIZE);
2894 
2895 	start = ext2fs_journal_sb_start(jfs->blocksize);
2896 	/* Write back the journal superblock */
2897 	retval = io_channel_write_blk64(jfs->io, start, -SUPERBLOCK_SIZE, buf);
2898 	if (retval != 0) {
2899 		com_err(program_name, retval,
2900 			"while writing journal superblock.");
2901 		return retval;
2902 	}
2903 
2904 	ext2fs_close(jfs);
2905 
2906 	return 0;
2907 }
2908 
2909 #ifndef BUILD_AS_LIB
main(int argc,char ** argv)2910 int main(int argc, char **argv)
2911 #else
2912 int tune2fs_main(int argc, char **argv)
2913 #endif  /* BUILD_AS_LIB */
2914 {
2915 	errcode_t retval;
2916 	ext2_filsys fs;
2917 	struct ext2_super_block *sb;
2918 	io_manager io_ptr, io_ptr_orig = NULL;
2919 	int rc = 0;
2920 	char default_undo_file[1] = { 0 };
2921 
2922 #ifdef ENABLE_NLS
2923 	setlocale(LC_MESSAGES, "");
2924 	setlocale(LC_CTYPE, "");
2925 	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
2926 	textdomain(NLS_CAT_NAME);
2927 	set_com_err_gettext(gettext);
2928 #endif
2929 	if (argc && *argv)
2930 		program_name = *argv;
2931 	add_error_table(&et_ext2_error_table);
2932 
2933 #ifdef CONFIG_BUILD_FINDFS
2934 	if (strcmp(get_progname(argv[0]), "findfs") == 0)
2935 		do_findfs(argc, argv);
2936 #endif
2937 	if (strcmp(get_progname(argv[0]), "e2label") == 0)
2938 		parse_e2label_options(argc, argv);
2939 	else
2940 		parse_tune2fs_options(argc, argv);
2941 
2942 #ifdef CONFIG_TESTIO_DEBUG
2943 	if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_DEBUG")) {
2944 		io_ptr = test_io_manager;
2945 		test_io_backing_manager = unix_io_manager;
2946 	} else
2947 #endif
2948 		io_ptr = unix_io_manager;
2949 
2950 retry_open:
2951 	if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag)
2952 		open_flag |= EXT2_FLAG_SKIP_MMP;
2953 
2954 	open_flag |= EXT2_FLAG_64BITS | EXT2_FLAG_JOURNAL_DEV_OK;
2955 
2956 	/* keep the filesystem struct around to dump MMP data */
2957 	open_flag |= EXT2_FLAG_NOFREE_ON_ERROR;
2958 
2959 	retval = ext2fs_open2(device_name, io_options, open_flag,
2960 			      0, 0, io_ptr, &fs);
2961 	if (retval) {
2962 		com_err(program_name, retval,
2963 			_("while trying to open %s"),
2964 			device_name);
2965 		if (retval == EXT2_ET_MMP_FSCK_ON ||
2966 		    retval == EXT2_ET_MMP_UNKNOWN_SEQ)
2967 			dump_mmp_msg(fs->mmp_buf,
2968 				     _("If you are sure the filesystem "
2969 				       "is not in use on any node, run:\n"
2970 				       "'tune2fs -f -E clear_mmp {device}'\n"));
2971 		else if (retval == EXT2_ET_MMP_FAILED)
2972 			dump_mmp_msg(fs->mmp_buf, NULL);
2973 		else if (retval == EXT2_ET_MMP_MAGIC_INVALID)
2974 			fprintf(stderr,
2975 				_("MMP block magic is bad. Try to fix it by "
2976 				  "running:\n'e2fsck -f %s'\n"), device_name);
2977 		else if (retval == EXT2_ET_BAD_MAGIC)
2978 			check_plausibility(device_name, CHECK_FS_EXIST, NULL);
2979 		else if (retval != EXT2_ET_MMP_FAILED)
2980 			fprintf(stderr, "%s",
2981 			     _("Couldn't find valid filesystem superblock.\n"));
2982 
2983 		ext2fs_free(fs);
2984 		exit(1);
2985 	}
2986 	if (ext2fs_has_feature_journal_dev(fs->super)) {
2987 		fprintf(stderr, "%s", _("Cannot modify a journal device.\n"));
2988 		ext2fs_free(fs);
2989 		exit(1);
2990 	}
2991 	fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
2992 
2993 	if (I_flag) {
2994 		/*
2995 		 * Check the inode size is right so we can issue an
2996 		 * error message and bail before setting up the tdb
2997 		 * file.
2998 		 */
2999 		if (new_inode_size == EXT2_INODE_SIZE(fs->super)) {
3000 			fprintf(stderr, _("The inode size is already %lu\n"),
3001 				new_inode_size);
3002 			rc = 1;
3003 			goto closefs;
3004 		}
3005 		if (new_inode_size < EXT2_INODE_SIZE(fs->super)) {
3006 			fprintf(stderr, "%s",
3007 				_("Shrinking inode size is not supported\n"));
3008 			rc = 1;
3009 			goto closefs;
3010 		}
3011 		if (new_inode_size > fs->blocksize) {
3012 			fprintf(stderr, _("Invalid inode size %lu (max %d)\n"),
3013 				new_inode_size, fs->blocksize);
3014 			rc = 1;
3015 			goto closefs;
3016 		}
3017 		check_fsck_needed(fs,
3018 			_("Resizing inodes could take some time."));
3019 		/*
3020 		 * If inode resize is requested use the
3021 		 * Undo I/O manager
3022 		 */
3023 		undo_file = default_undo_file;
3024 	}
3025 
3026 	/* Set up an undo file */
3027 	if (undo_file && io_ptr_orig == NULL) {
3028 		io_ptr_orig = io_ptr;
3029 		retval = tune2fs_setup_tdb(device_name, &io_ptr);
3030 		if (retval) {
3031 			rc = 1;
3032 			goto closefs;
3033 		}
3034 		if (io_ptr != io_ptr_orig) {
3035 			ext2fs_close_free(&fs);
3036 			goto retry_open;
3037 		}
3038 	}
3039 
3040 	sb = fs->super;
3041 	fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
3042 
3043 	if (print_label) {
3044 		/* For e2label emulation */
3045 		printf("%.*s\n", (int) sizeof(sb->s_volume_name),
3046 		       sb->s_volume_name);
3047 		remove_error_table(&et_ext2_error_table);
3048 		goto closefs;
3049 	}
3050 
3051 	retval = ext2fs_check_if_mounted(device_name, &mount_flags);
3052 	if (retval) {
3053 		com_err("ext2fs_check_if_mount", retval,
3054 			_("while determining whether %s is mounted."),
3055 			device_name);
3056 		rc = 1;
3057 		goto closefs;
3058 	}
3059 
3060 #ifdef NO_RECOVERY
3061 	/* Warn if file system needs recovery and it is opened for writing. */
3062 	if ((open_flag & EXT2_FLAG_RW) && !(mount_flags & EXT2_MF_MOUNTED) &&
3063 	    (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
3064 	    (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) {
3065 		fprintf(stderr,
3066 _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
3067   "\te2fsck -E journal_only %s\n\n"
3068   "then rerun this command.  Otherwise, any changes made may be overwritten\n"
3069   "by journal recovery.\n"), device_name);
3070 	}
3071 #else
3072 	/* Recover the journal if possible. */
3073 	if ((open_flag & EXT2_FLAG_RW) && !(mount_flags & (EXT2_MF_BUSY | EXT2_MF_MOUNTED)) &&
3074 	    ext2fs_has_feature_journal_needs_recovery(fs->super)) {
3075 		errcode_t err;
3076 
3077 		printf(_("Recovering journal.\n"));
3078 		err = ext2fs_run_ext3_journal(&fs);
3079 		if (err) {
3080 			com_err("tune2fs", err, "while recovering journal.\n");
3081 			printf(_("Please run e2fsck -fy %s.\n"), argv[1]);
3082 			if (fs)
3083 				ext2fs_close_free(&fs);
3084 			exit(1);
3085 		}
3086 		sb = fs->super;
3087 	}
3088 #endif
3089 
3090 	/* Normally we only need to write out the superblock */
3091 	fs->flags |= EXT2_FLAG_SUPER_ONLY;
3092 
3093 	if (c_flag) {
3094 		sb->s_max_mnt_count = max_mount_count;
3095 		ext2fs_mark_super_dirty(fs);
3096 		printf(_("Setting maximal mount count to %d\n"),
3097 		       max_mount_count);
3098 	}
3099 	if (C_flag) {
3100 		sb->s_mnt_count = mount_count;
3101 		ext2fs_mark_super_dirty(fs);
3102 		printf(_("Setting current mount count to %d\n"), mount_count);
3103 	}
3104 	if (e_flag) {
3105 		sb->s_errors = errors;
3106 		ext2fs_mark_super_dirty(fs);
3107 		printf(_("Setting error behavior to %d\n"), errors);
3108 	}
3109 	if (g_flag) {
3110 		sb->s_def_resgid = resgid;
3111 		ext2fs_mark_super_dirty(fs);
3112 		printf(_("Setting reserved blocks gid to %lu\n"), resgid);
3113 	}
3114 	if (i_flag) {
3115 		if ((unsigned long long)interval >= (1ULL << 32)) {
3116 			com_err(program_name, 0,
3117 				_("interval between checks is too big (%lu)"),
3118 				interval);
3119 			rc = 1;
3120 			goto closefs;
3121 		}
3122 		sb->s_checkinterval = interval;
3123 		ext2fs_mark_super_dirty(fs);
3124 		printf(_("Setting interval between checks to %lu seconds\n"),
3125 		       interval);
3126 	}
3127 	if (m_flag) {
3128 		ext2fs_r_blocks_count_set(sb, reserved_ratio *
3129 					  ext2fs_blocks_count(sb) / 100.0);
3130 		ext2fs_mark_super_dirty(fs);
3131 		printf (_("Setting reserved blocks percentage to %g%% (%llu blocks)\n"),
3132 			reserved_ratio, ext2fs_r_blocks_count(sb));
3133 	}
3134 	if (r_flag) {
3135 		if (reserved_blocks > ext2fs_blocks_count(sb)/2) {
3136 			com_err(program_name, 0,
3137 				_("reserved blocks count is too big (%llu)"),
3138 				reserved_blocks);
3139 			rc = 1;
3140 			goto closefs;
3141 		}
3142 		ext2fs_r_blocks_count_set(sb, reserved_blocks);
3143 		ext2fs_mark_super_dirty(fs);
3144 		printf(_("Setting reserved blocks count to %llu\n"),
3145 		       reserved_blocks);
3146 	}
3147 	if (s_flag == 1) {
3148 		if (ext2fs_has_feature_sparse_super(sb)) {
3149 			fputs(_("\nThe filesystem already has sparse "
3150 				"superblocks.\n"), stderr);
3151 		} else if (ext2fs_has_feature_meta_bg(sb)) {
3152 			fputs(_("\nSetting the sparse superblock flag not "
3153 				"supported\nfor filesystems with "
3154 				"the meta_bg feature enabled.\n"),
3155 				stderr);
3156 			rc = 1;
3157 			goto closefs;
3158 		} else {
3159 			ext2fs_set_feature_sparse_super(sb);
3160 			sb->s_state &= ~EXT2_VALID_FS;
3161 			ext2fs_mark_super_dirty(fs);
3162 			printf(_("\nSparse superblock flag set.  %s"),
3163 			       _(please_fsck));
3164 		}
3165 	}
3166 	if (s_flag == 0) {
3167 		fputs(_("\nClearing the sparse superblock flag not supported.\n"),
3168 		      stderr);
3169 		rc = 1;
3170 		goto closefs;
3171 	}
3172 	if (T_flag) {
3173 		sb->s_lastcheck = last_check_time;
3174 		ext2fs_mark_super_dirty(fs);
3175 		printf(_("Setting time filesystem last checked to %s\n"),
3176 		       ctime(&last_check_time));
3177 	}
3178 	if (u_flag) {
3179 		sb->s_def_resuid = resuid;
3180 		ext2fs_mark_super_dirty(fs);
3181 		printf(_("Setting reserved blocks uid to %lu\n"), resuid);
3182 	}
3183 	if (L_flag) {
3184 		if (strlen(new_label) > sizeof(sb->s_volume_name))
3185 			fputs(_("Warning: label too long, truncating.\n"),
3186 			      stderr);
3187 		memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
3188 		strncpy(sb->s_volume_name, new_label,
3189 			sizeof(sb->s_volume_name));
3190 		ext2fs_mark_super_dirty(fs);
3191 	}
3192 	if (M_flag) {
3193 		memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
3194 		strncpy(sb->s_last_mounted, new_last_mounted,
3195 			sizeof(sb->s_last_mounted));
3196 		ext2fs_mark_super_dirty(fs);
3197 	}
3198 	if (mntopts_cmd) {
3199 		rc = update_mntopts(fs, mntopts_cmd);
3200 		if (rc)
3201 			goto closefs;
3202 	}
3203 	if (features_cmd) {
3204 		rc = update_feature_set(fs, features_cmd);
3205 		if (rc)
3206 			goto closefs;
3207 	}
3208 	if (extended_cmd) {
3209 		rc = parse_extended_opts(fs, extended_cmd);
3210 		if (rc)
3211 			goto closefs;
3212 		if (clear_mmp && !f_flag) {
3213 			fputs(_("Error in using clear_mmp. "
3214 				"It must be used with -f\n"),
3215 			      stderr);
3216 			goto closefs;
3217 		}
3218 	}
3219 	if (clear_mmp) {
3220 		rc = ext2fs_mmp_clear(fs);
3221 		goto closefs;
3222 	}
3223 	if (journal_size || journal_device) {
3224 		rc = add_journal(fs);
3225 		if (rc)
3226 			goto closefs;
3227 	}
3228 
3229 	if (Q_flag) {
3230 		if (mount_flags & EXT2_MF_MOUNTED) {
3231 			fputs(_("The quota feature may only be changed when "
3232 				"the filesystem is unmounted.\n"), stderr);
3233 			rc = 1;
3234 			goto closefs;
3235 		}
3236 		handle_quota_options(fs);
3237 	}
3238 
3239 	if (U_flag) {
3240 		int set_csum = 0;
3241 		dgrp_t i;
3242 		char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8)));
3243 		__u8 old_uuid[UUID_SIZE];
3244 
3245 		if (!ext2fs_has_feature_csum_seed(fs->super) &&
3246 		    (ext2fs_has_feature_metadata_csum(fs->super) ||
3247 		     ext2fs_has_feature_ea_inode(fs->super))) {
3248 			check_fsck_needed(fs,
3249 				_("Setting the UUID on this "
3250 				  "filesystem could take some time."));
3251 			rewrite_checksums = 1;
3252 		}
3253 
3254 		if (ext2fs_has_group_desc_csum(fs)) {
3255 			/*
3256 			 * Changing the UUID on a metadata_csum FS requires
3257 			 * rewriting all metadata, which can race with a
3258 			 * mounted fs.  Don't allow that unless we're saving
3259 			 * the checksum seed.
3260 			 */
3261 			if ((mount_flags & EXT2_MF_MOUNTED) &&
3262 			    !ext2fs_has_feature_csum_seed(fs->super) &&
3263 			    ext2fs_has_feature_metadata_csum(fs->super)) {
3264 				fputs(_("The UUID may only be "
3265 					"changed when the filesystem is "
3266 					"unmounted.\n"), stderr);
3267 				fputs(_("If you only use kernels newer than "
3268 					"v4.4, run 'tune2fs -O "
3269 					"metadata_csum_seed' and re-run this "
3270 					"command.\n"), stderr);
3271 				try_confirm_csum_seed_support();
3272 				exit(1);
3273 			}
3274 
3275 			/*
3276 			 * Determine if the block group checksums are
3277 			 * correct so we know whether or not to set
3278 			 * them later on.
3279 			 */
3280 			for (i = 0; i < fs->group_desc_count; i++)
3281 				if (!ext2fs_group_desc_csum_verify(fs, i))
3282 					break;
3283 			if (i >= fs->group_desc_count)
3284 				set_csum = 1;
3285 		}
3286 
3287 		memcpy(old_uuid, sb->s_uuid, UUID_SIZE);
3288 		if ((strcasecmp(new_UUID, "null") == 0) ||
3289 		    (strcasecmp(new_UUID, "clear") == 0)) {
3290 			uuid_clear(sb->s_uuid);
3291 		} else if (strcasecmp(new_UUID, "time") == 0) {
3292 			uuid_generate_time(sb->s_uuid);
3293 		} else if (strcasecmp(new_UUID, "random") == 0) {
3294 			uuid_generate(sb->s_uuid);
3295 		} else if (uuid_parse(new_UUID, sb->s_uuid)) {
3296 			com_err(program_name, 0, "%s",
3297 				_("Invalid UUID format\n"));
3298 			rc = 1;
3299 			goto closefs;
3300 		}
3301 		ext2fs_init_csum_seed(fs);
3302 		if (set_csum) {
3303 			for (i = 0; i < fs->group_desc_count; i++)
3304 				ext2fs_group_desc_csum_set(fs, i);
3305 			fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
3306 		}
3307 
3308 		/* If this is a journal dev, we need to copy UUID into jsb */
3309 		if (!(rc = get_journal_sb(fs, buf))) {
3310 			journal_superblock_t *jsb;
3311 
3312 			jsb = (journal_superblock_t *) buf;
3313 			fputs(_("Need to update journal superblock.\n"), stdout);
3314 			memcpy(jsb->s_uuid, sb->s_uuid, sizeof(sb->s_uuid));
3315 
3316 			/* Writeback the journal superblock */
3317 			if ((rc = io_channel_write_blk64(fs->io,
3318 				ext2fs_journal_sb_start(fs->blocksize),
3319 					-SUPERBLOCK_SIZE, buf)))
3320 				goto closefs;
3321 		} else if (rc != EXT2_ET_UNSUPP_FEATURE)
3322 			goto closefs;
3323 		else {
3324 			rc = 0; /** Reset rc to avoid ext2fs_mmp_stop() */
3325 
3326 			if ((rc = fs_update_journal_user(sb, old_uuid)))
3327 				goto closefs;
3328 		}
3329 
3330 		ext2fs_mark_super_dirty(fs);
3331 	}
3332 
3333 	if (I_flag) {
3334 		if (mount_flags & EXT2_MF_MOUNTED) {
3335 			fputs(_("The inode size may only be "
3336 				"changed when the filesystem is "
3337 				"unmounted.\n"), stderr);
3338 			rc = 1;
3339 			goto closefs;
3340 		}
3341 		if (ext2fs_has_feature_flex_bg(fs->super)) {
3342 			fputs(_("Changing the inode size not supported for "
3343 				"filesystems with the flex_bg\n"
3344 				"feature enabled.\n"),
3345 			      stderr);
3346 			rc = 1;
3347 			goto closefs;
3348 		}
3349 		/*
3350 		 * We want to update group descriptor also
3351 		 * with the new free inode count
3352 		 */
3353 		if (rewrite_checksums)
3354 			fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
3355 		fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
3356 		retval = resize_inode(fs, new_inode_size);
3357 		if (rewrite_checksums)
3358 			fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
3359 		if (retval == 0) {
3360 			printf(_("Setting inode size %lu\n"),
3361 							new_inode_size);
3362 			rewrite_checksums = 1;
3363 		} else {
3364 			printf("%s", _("Failed to change inode size\n"));
3365 			rc = 1;
3366 			goto closefs;
3367 		}
3368 	}
3369 
3370 	if (rewrite_checksums)
3371 		rewrite_metadata_checksums(fs);
3372 
3373 	if (l_flag)
3374 		list_super(sb);
3375 	if (stride_set) {
3376 		sb->s_raid_stride = stride;
3377 		ext2fs_mark_super_dirty(fs);
3378 		printf(_("Setting stride size to %d\n"), stride);
3379 	}
3380 	if (stripe_width_set) {
3381 		sb->s_raid_stripe_width = stripe_width;
3382 		ext2fs_mark_super_dirty(fs);
3383 		printf(_("Setting stripe width to %d\n"), stripe_width);
3384 	}
3385 	if (ext_mount_opts) {
3386 		strncpy((char *)(fs->super->s_mount_opts), ext_mount_opts,
3387 			sizeof(fs->super->s_mount_opts));
3388 		fs->super->s_mount_opts[sizeof(fs->super->s_mount_opts)-1] = 0;
3389 		ext2fs_mark_super_dirty(fs);
3390 		printf(_("Setting extended default mount options to '%s'\n"),
3391 		       ext_mount_opts);
3392 		free(ext_mount_opts);
3393 	}
3394 
3395 	free(device_name);
3396 	remove_error_table(&et_ext2_error_table);
3397 
3398 closefs:
3399 	if (rc) {
3400 		ext2fs_mmp_stop(fs);
3401 #ifndef BUILD_AS_LIB
3402 		exit(1);
3403 #endif
3404 	}
3405 
3406 	if (feature_64bit)
3407 		convert_64bit(fs, feature_64bit);
3408 	return (ext2fs_close_free(&fs) ? 1 : 0);
3409 }
3410