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