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