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