blob: 64a76f1e4864889ef1c0561ee3e6cda67adaf248 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
Theodore Ts'o4d0f2282001-04-23 20:58:03 +00002 * tune2fs.c - Change the file system parameters on an ext2 file system
Theodore Ts'o3839e651997-04-26 13:21:57 +00003 *
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 *
Theodore Ts'o4d0f2282001-04-23 20:58:03 +00008 * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o.
Theodore Ts'o19c78dc1997-04-29 16:17:09 +00009 *
10 * %Begin-Header%
11 * This file may be redistributed under the terms of the GNU Public
12 * License.
13 * %End-Header%
Theodore Ts'o3839e651997-04-26 13:21:57 +000014 */
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
Theodore Ts'oebabf2a2008-07-13 15:32:37 -040028#define _XOPEN_SOURCE 600 /* for inclusion of strptime() */
Theodore Ts'od1154eb2011-09-18 17:34:37 -040029#include "config.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000030#include <fcntl.h>
Theodore Ts'of3db3561997-04-26 13:34:30 +000031#include <grp.h>
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000032#ifdef HAVE_GETOPT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000033#include <getopt.h>
Theodore Ts'o373b8332000-04-03 16:22:35 +000034#else
35extern char *optarg;
36extern int optind;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +000037#endif
Theodore Ts'of3db3561997-04-26 13:34:30 +000038#include <pwd.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000039#include <stdio.h>
Theodore Ts'of38cf3c2008-09-01 11:17:29 -040040#ifdef HAVE_STDLIB_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000041#include <stdlib.h>
Theodore Ts'of38cf3c2008-09-01 11:17:29 -040042#endif
Andreas Dilger269da3b2013-12-15 23:26:25 -050043#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
Theodore Ts'o3839e651997-04-26 13:21:57 +000048#include <string.h>
49#include <time.h>
50#include <unistd.h>
Theodore Ts'of3db3561997-04-26 13:34:30 +000051#include <sys/types.h>
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +053052#include <libgen.h>
Theodore Ts'o36585792008-06-07 22:07:50 -040053#include <limits.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000054
Theodore Ts'o54c637d2001-05-14 11:45:38 +000055#include "ext2fs/ext2_fs.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000056#include "ext2fs/ext2fs.h"
57#include "et/com_err.h"
Theodore Ts'o1e3472c1997-04-29 14:53:37 +000058#include "uuid/uuid.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000059#include "e2p/e2p.h"
Theodore Ts'odc2ec522001-01-18 01:51:15 +000060#include "jfs_user.h"
Theodore Ts'o63985322001-01-03 17:02:13 +000061#include "util.h"
Theodore Ts'oed1b33e2003-03-01 19:29:01 -050062#include "blkid/blkid.h"
Aditya Kali771e8db2011-07-20 11:40:05 -070063#include "quota/mkquota.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000064
65#include "../version.h"
Theodore Ts'od9c56d32000-02-08 00:47:55 +000066#include "nls-enable.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000067
Aditya Kali771e8db2011-07-20 11:40:05 -070068#define QOPT_ENABLE (1)
69#define QOPT_DISABLE (-1)
70
71extern int ask_yn(const char *string, int def);
72
Theodore Ts'oec43da22009-01-20 02:34:39 -050073const char *program_name = "tune2fs";
74char *device_name;
75char *new_label, *new_last_mounted, *new_UUID;
76char *io_options;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +000077static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
Aditya Kali771e8db2011-07-20 11:40:05 -070078static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +053079static int I_flag;
Andreas Dilger0f5eba72011-09-24 13:48:55 -040080static int clear_mmp;
Theodore Ts'od4de4aa2001-12-26 08:58:01 -050081static time_t last_check_time;
Theodore Ts'o83238152001-01-09 00:16:26 +000082static int print_label;
Theodore Ts'o63985322001-01-03 17:02:13 +000083static int max_mount_count, mount_count, mount_flags;
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -040084static unsigned long interval;
85static blk64_t reserved_blocks;
Andreas Dilgerce911142005-07-06 11:50:08 -050086static double reserved_ratio;
Theodore Ts'o63985322001-01-03 17:02:13 +000087static unsigned long resgid, resuid;
88static unsigned short errors;
Theodore Ts'o83238152001-01-09 00:16:26 +000089static int open_flag;
90static char *features_cmd;
Theodore Ts'oa0c3fd52002-10-15 17:43:43 -040091static char *mntopts_cmd;
Theodore Ts'o0c17cb22008-02-18 22:56:25 -050092static int stride, stripe_width;
93static int stride_set, stripe_width_set;
Theodore Ts'o6cb27402008-01-26 19:06:35 -050094static char *extended_cmd;
Theodore Ts'o721b3672008-06-07 11:51:33 -040095static unsigned long new_inode_size;
Theodore Ts'o9a976ac2011-07-04 20:14:35 -040096static char *ext_mount_opts;
Aditya Kali771e8db2011-07-20 11:40:05 -070097static int usrquota, grpquota;
Theodore Ts'o3839e651997-04-26 13:21:57 +000098
Theodore Ts'o63985322001-01-03 17:02:13 +000099int journal_size, journal_flags;
100char *journal_device;
Theodore Ts'ob8182052014-01-28 12:58:56 -0500101static blk64_t journal_location = ~0LL;
Theodore Ts'o63985322001-01-03 17:02:13 +0000102
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +0530103static struct list_head blk_move_list;
104
105struct blk_move {
106 struct list_head list;
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -0400107 blk64_t old_loc;
108 blk64_t new_loc;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +0530109};
110
111
Theodore Ts'o63985322001-01-03 17:02:13 +0000112static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000113
Theodore Ts'o14b596d2009-04-22 09:18:30 -0400114#ifdef CONFIG_BUILD_FINDFS
Theodore Ts'o3e699062002-10-13 23:56:28 -0400115void do_findfs(int argc, char **argv);
Theodore Ts'o14b596d2009-04-22 09:18:30 -0400116#endif
Theodore Ts'o3e699062002-10-13 23:56:28 -0400117
Theodore Ts'o818180c1998-06-27 05:11:14 +0000118static void usage(void)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000119{
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000120 fprintf(stderr,
Theodore Ts'obb145b02005-06-20 08:35:27 -0400121 _("Usage: %s [-c max_mounts_count] [-e errors_behavior] "
Theodore Ts'ob21e38a2001-01-01 15:26:58 +0000122 "[-g group]\n"
Theodore Ts'off662d52008-02-28 21:26:01 -0500123 "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n"
124 "\t[-m reserved_blocks_percent] "
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400125 "[-o [^]mount_options[,...]] [-p mmp_update_interval]\n"
Theodore Ts'off662d52008-02-28 21:26:01 -0500126 "\t[-r reserved_blocks_count] [-u user] [-C mount_count] "
127 "[-L volume_label]\n"
Theodore Ts'o6cb27402008-01-26 19:06:35 -0500128 "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n"
Eric Sandeend82445e2013-10-14 09:03:06 -0400129#ifdef CONFIG_QUOTA
130 "\t[-Q quota_options]\n"
131#endif
Theodore Ts'o6cb27402008-01-26 19:06:35 -0500132 "\t[-E extended-option[,...]] [-T last_check_time] "
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +0530133 "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name);
Theodore Ts'oec43da22009-01-20 02:34:39 -0500134 exit(1);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000135}
136
Theodore Ts'o896938d1999-10-23 01:04:50 +0000137static __u32 ok_features[3] = {
Theodore Ts'o558df542008-02-27 15:01:19 -0500138 /* Compat */
Theodore Ts'o843049c2002-09-22 15:37:40 -0400139 EXT3_FEATURE_COMPAT_HAS_JOURNAL |
Theodore Ts'o558df542008-02-27 15:01:19 -0500140 EXT2_FEATURE_COMPAT_DIR_INDEX,
141 /* Incompat */
Theodore Ts'oa49670e2008-02-27 18:53:34 -0500142 EXT2_FEATURE_INCOMPAT_FILETYPE |
143 EXT3_FEATURE_INCOMPAT_EXTENTS |
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400144 EXT4_FEATURE_INCOMPAT_FLEX_BG |
145 EXT4_FEATURE_INCOMPAT_MMP,
Theodore Ts'o558df542008-02-27 15:01:19 -0500146 /* R/O compat */
147 EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
Theodore Ts'o2be8fe42008-07-10 10:49:59 -0400148 EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
149 EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
150 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
Jose R. Santos4e988cb2007-10-21 21:03:41 -0500151 EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
Eric Sandeen44a2cca2012-11-27 12:35:48 -0600152#ifdef CONFIG_QUOTA
Theodore Ts'o0f818652012-11-29 14:58:29 -0500153 EXT4_FEATURE_RO_COMPAT_QUOTA |
Eric Sandeen44a2cca2012-11-27 12:35:48 -0600154#endif
Theodore Ts'o0f818652012-11-29 14:58:29 -0500155 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
Theodore Ts'o896938d1999-10-23 01:04:50 +0000156};
157
Theodore Ts'o7c4a2ef2008-02-26 14:27:57 -0500158static __u32 clear_ok_features[3] = {
Theodore Ts'o558df542008-02-27 15:01:19 -0500159 /* Compat */
Theodore Ts'o7c4a2ef2008-02-26 14:27:57 -0500160 EXT3_FEATURE_COMPAT_HAS_JOURNAL |
Theodore Ts'o037914e2008-02-26 17:31:06 -0500161 EXT2_FEATURE_COMPAT_RESIZE_INODE |
Theodore Ts'o558df542008-02-27 15:01:19 -0500162 EXT2_FEATURE_COMPAT_DIR_INDEX,
163 /* Incompat */
Theodore Ts'oa49670e2008-02-27 18:53:34 -0500164 EXT2_FEATURE_INCOMPAT_FILETYPE |
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400165 EXT4_FEATURE_INCOMPAT_FLEX_BG |
166 EXT4_FEATURE_INCOMPAT_MMP,
Theodore Ts'o558df542008-02-27 15:01:19 -0500167 /* R/O compat */
Jose R. Santos4e988cb2007-10-21 21:03:41 -0500168 EXT2_FEATURE_RO_COMPAT_LARGE_FILE |
Theodore Ts'o2be8fe42008-07-10 10:49:59 -0400169 EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
170 EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
171 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
Eric Sandeen44a2cca2012-11-27 12:35:48 -0600172#ifdef CONFIG_QUOTA
Theodore Ts'o0f818652012-11-29 14:58:29 -0500173 EXT4_FEATURE_RO_COMPAT_QUOTA |
Eric Sandeen44a2cca2012-11-27 12:35:48 -0600174#endif
Theodore Ts'o0f818652012-11-29 14:58:29 -0500175 EXT4_FEATURE_RO_COMPAT_GDT_CSUM
Theodore Ts'o896938d1999-10-23 01:04:50 +0000176};
177
Theodore Ts'o63985322001-01-03 17:02:13 +0000178/*
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000179 * Remove an external journal from the filesystem
180 */
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400181static int remove_journal_device(ext2_filsys fs)
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000182{
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500183 char *journal_path;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000184 ext2_filsys jfs;
185 char buf[1024];
186 journal_superblock_t *jsb;
187 int i, nr_users;
188 errcode_t retval;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000189 int commit_remove_journal = 0;
Theodore Ts'o2a29f132003-05-05 12:08:47 -0400190 io_manager io_ptr;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000191
192 if (f_flag)
193 commit_remove_journal = 1; /* force removal even if error */
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000194
Andreas Dilger2d155762001-08-17 03:48:11 -0600195 uuid_unparse(fs->super->s_journal_uuid, buf);
Theodore Ts'oed1b33e2003-03-01 19:29:01 -0500196 journal_path = blkid_get_devname(NULL, "UUID", buf);
Andreas Dilger2d155762001-08-17 03:48:11 -0600197
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500198 if (!journal_path) {
199 journal_path =
Andreas Dilger2d155762001-08-17 03:48:11 -0600200 ext2fs_find_block_device(fs->super->s_journal_dev);
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500201 if (!journal_path)
Andreas Dilgerd90d6a72011-09-24 13:17:05 -0400202 goto no_valid_journal;
Andreas Dilger2d155762001-08-17 03:48:11 -0600203 }
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000204
Theodore Ts'o2a29f132003-05-05 12:08:47 -0400205#ifdef CONFIG_TESTIO_DEBUG
Theodore Ts'of38cf3c2008-09-01 11:17:29 -0400206 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
207 io_ptr = test_io_manager;
208 test_io_backing_manager = unix_io_manager;
209 } else
Theodore Ts'o2a29f132003-05-05 12:08:47 -0400210#endif
Theodore Ts'of38cf3c2008-09-01 11:17:29 -0400211 io_ptr = unix_io_manager;
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500212 retval = ext2fs_open(journal_path, EXT2_FLAG_RW|
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000213 EXT2_FLAG_JOURNAL_DEV_OK, 0,
Theodore Ts'o2a29f132003-05-05 12:08:47 -0400214 fs->blocksize, io_ptr, &jfs);
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000215 if (retval) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500216 com_err(program_name, retval, "%s",
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000217 _("while trying to open external journal"));
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000218 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000219 }
Andreas Dilger6747ac82011-09-24 13:25:34 -0400220 if (!(jfs->super->s_feature_incompat &
221 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
Theodore Ts'o7141b542001-08-15 19:17:37 -0400222 fprintf(stderr, _("%s is not a journal device.\n"),
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500223 journal_path);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000224 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000225 }
226
227 /* Get the journal superblock */
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -0400228 if ((retval = io_channel_read_blk64(jfs->io, 1, -1024, buf))) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500229 com_err(program_name, retval, "%s",
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000230 _("while reading journal superblock"));
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000231 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000232 }
233
234 jsb = (journal_superblock_t *) buf;
Andreas Dilger6747ac82011-09-24 13:25:34 -0400235 if ((jsb->s_header.h_magic != (unsigned)ntohl(JFS_MAGIC_NUMBER)) ||
236 (jsb->s_header.h_blocktype != (unsigned)ntohl(JFS_SUPERBLOCK_V2))) {
Theodore Ts'o54434922003-12-07 01:28:50 -0500237 fputs(_("Journal superblock not found!\n"), stderr);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000238 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000239 }
240
241 /* Find the filesystem UUID */
242 nr_users = ntohl(jsb->s_nr_users);
Theodore Ts'oec43da22009-01-20 02:34:39 -0500243 for (i = 0; i < nr_users; i++) {
Andreas Dilger6747ac82011-09-24 13:25:34 -0400244 if (memcmp(fs->super->s_uuid, &jsb->s_users[i * 16], 16) == 0)
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000245 break;
246 }
247 if (i >= nr_users) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400248 fputs(_("Filesystem's UUID not found on journal device.\n"),
Theodore Ts'o54434922003-12-07 01:28:50 -0500249 stderr);
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000250 commit_remove_journal = 1;
251 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000252 }
253 nr_users--;
Theodore Ts'oec43da22009-01-20 02:34:39 -0500254 for (i = 0; i < nr_users; i++)
Andreas Dilger6747ac82011-09-24 13:25:34 -0400255 memcpy(&jsb->s_users[i * 16], &jsb->s_users[(i + 1) * 16], 16);
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000256 jsb->s_nr_users = htonl(nr_users);
257
258 /* Write back the journal superblock */
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -0400259 if ((retval = io_channel_write_blk64(jfs->io, 1, -1024, buf))) {
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000260 com_err(program_name, retval,
261 "while writing journal superblock.");
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000262 goto no_valid_journal;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000263 }
264
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000265 commit_remove_journal = 1;
266
267no_valid_journal:
268 if (commit_remove_journal == 0) {
Andreas Dilgerd90d6a72011-09-24 13:17:05 -0400269 fputs(_("Cannot locate journal device. It was NOT removed\n"
270 "Use -f option to remove missing journal device.\n"),
271 stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400272 return 1;
Theodore Ts'o4d0f2282001-04-23 20:58:03 +0000273 }
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000274 fs->super->s_journal_dev = 0;
Theodore Ts'oed1b33e2003-03-01 19:29:01 -0500275 uuid_clear(fs->super->s_journal_uuid);
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000276 ext2fs_mark_super_dirty(fs);
Theodore Ts'o54434922003-12-07 01:28:50 -0500277 fputs(_("Journal removed\n"), stdout);
Theodore Ts'o4ea7bd02001-12-16 23:23:37 -0500278 free(journal_path);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400279
280 return 0;
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000281}
282
Theodore Ts'o194686b2001-07-31 12:03:23 -0400283/* Helper function for remove_journal_inode */
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -0400284static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
285 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
286 blk64_t ref_block EXT2FS_ATTR((unused)),
287 int ref_offset EXT2FS_ATTR((unused)),
Theodore Ts'o54434922003-12-07 01:28:50 -0500288 void *private EXT2FS_ATTR((unused)))
Theodore Ts'o194686b2001-07-31 12:03:23 -0400289{
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -0400290 blk64_t block;
Theodore Ts'o194686b2001-07-31 12:03:23 -0400291 int group;
292
293 block = *blocknr;
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -0400294 ext2fs_unmark_block_bitmap2(fs->block_map, block);
Theodore Ts'o6493f8e2009-10-25 20:50:15 -0400295 group = ext2fs_group_of_blk2(fs, block);
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400296 ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) + 1);
Jose R. Santos4e988cb2007-10-21 21:03:41 -0500297 ext2fs_group_desc_csum_set(fs, group);
Theodore Ts'ofe75afb2011-06-16 01:38:43 -0400298 ext2fs_free_blocks_count_add(fs->super, EXT2FS_CLUSTER_RATIO(fs));
Theodore Ts'o194686b2001-07-31 12:03:23 -0400299 return 0;
300}
301
302/*
303 * Remove the journal inode from the filesystem
304 */
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400305static errcode_t remove_journal_inode(ext2_filsys fs)
Theodore Ts'o194686b2001-07-31 12:03:23 -0400306{
307 struct ext2_inode inode;
308 errcode_t retval;
309 ino_t ino = fs->super->s_journal_inum;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400310
Theodore Ts'o194686b2001-07-31 12:03:23 -0400311 retval = ext2fs_read_inode(fs, ino, &inode);
312 if (retval) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500313 com_err(program_name, retval, "%s",
Theodore Ts'o194686b2001-07-31 12:03:23 -0400314 _("while reading journal inode"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400315 return retval;
Theodore Ts'o194686b2001-07-31 12:03:23 -0400316 }
317 if (ino == EXT2_JOURNAL_INO) {
318 retval = ext2fs_read_bitmaps(fs);
319 if (retval) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500320 com_err(program_name, retval, "%s",
Theodore Ts'o194686b2001-07-31 12:03:23 -0400321 _("while reading bitmaps"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400322 return retval;
Theodore Ts'o194686b2001-07-31 12:03:23 -0400323 }
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -0400324 retval = ext2fs_block_iterate3(fs, ino,
325 BLOCK_FLAG_READ_ONLY, NULL,
326 release_blocks_proc, NULL);
Theodore Ts'o194686b2001-07-31 12:03:23 -0400327 if (retval) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500328 com_err(program_name, retval, "%s",
Theodore Ts'o194686b2001-07-31 12:03:23 -0400329 _("while clearing journal inode"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400330 return retval;
Theodore Ts'o194686b2001-07-31 12:03:23 -0400331 }
332 memset(&inode, 0, sizeof(inode));
333 ext2fs_mark_bb_dirty(fs);
Theodore Ts'o194686b2001-07-31 12:03:23 -0400334 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
335 } else
336 inode.i_flags &= ~EXT2_IMMUTABLE_FL;
337 retval = ext2fs_write_inode(fs, ino, &inode);
338 if (retval) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500339 com_err(program_name, retval, "%s",
Theodore Ts'o194686b2001-07-31 12:03:23 -0400340 _("while writing journal inode"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400341 return retval;
Theodore Ts'o194686b2001-07-31 12:03:23 -0400342 }
343 fs->super->s_journal_inum = 0;
344 ext2fs_mark_super_dirty(fs);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400345
346 return 0;
Theodore Ts'o194686b2001-07-31 12:03:23 -0400347}
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000348
349/*
Theodore Ts'oa0c3fd52002-10-15 17:43:43 -0400350 * Update the default mount options
351 */
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400352static int update_mntopts(ext2_filsys fs, char *mntopts)
Theodore Ts'oa0c3fd52002-10-15 17:43:43 -0400353{
Theodore Ts'oec43da22009-01-20 02:34:39 -0500354 struct ext2_super_block *sb = fs->super;
Theodore Ts'oa0c3fd52002-10-15 17:43:43 -0400355
356 if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) {
357 fprintf(stderr, _("Invalid mount option set: %s\n"),
358 mntopts);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400359 return 1;
Theodore Ts'oa0c3fd52002-10-15 17:43:43 -0400360 }
361 ext2fs_mark_super_dirty(fs);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400362
363 return 0;
Theodore Ts'oa0c3fd52002-10-15 17:43:43 -0400364}
365
Darrick J. Wong66457fc2013-12-14 20:51:04 -0500366static int check_fsck_needed(ext2_filsys fs)
367{
368 if (fs->super->s_state & EXT2_VALID_FS)
369 return 0;
370 printf("\n%s\n", _(please_fsck));
371 if (mount_flags & EXT2_MF_READONLY)
372 printf(_("(and reboot afterwards!)\n"));
373 return 1;
374}
375
Theodore Ts'o079ad632010-05-19 12:14:39 -0400376static void request_fsck_afterwards(ext2_filsys fs)
377{
378 static int requested = 0;
379
380 if (requested++)
381 return;
382 fs->super->s_state &= ~EXT2_VALID_FS;
383 printf("\n%s\n", _(please_fsck));
384 if (mount_flags & EXT2_MF_READONLY)
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500385 printf("%s", _("(and reboot afterwards!)\n"));
Theodore Ts'o079ad632010-05-19 12:14:39 -0400386}
387
Theodore Ts'oa0c3fd52002-10-15 17:43:43 -0400388/*
Theodore Ts'o63985322001-01-03 17:02:13 +0000389 * Update the feature set as provided by the user.
390 */
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400391static int update_feature_set(ext2_filsys fs, char *features)
Theodore Ts'o63985322001-01-03 17:02:13 +0000392{
Theodore Ts'oec43da22009-01-20 02:34:39 -0500393 struct ext2_super_block *sb = fs->super;
Theodore Ts'o079ad632010-05-19 12:14:39 -0400394 struct ext2_group_desc *gd;
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500395 __u32 old_features[3];
Theodore Ts'o577c7732013-05-19 20:03:48 -0400396 dgrp_t i;
397 int type_err;
Theodore Ts'o7c4a2ef2008-02-26 14:27:57 -0500398 unsigned int mask_err;
Theodore Ts'o2eb3b202004-04-07 09:27:36 -0400399
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500400#define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \
401 ((&sb->s_feature_compat)[(type)] & (mask)))
402#define FEATURE_OFF(type, mask) ((old_features[(type)] & (mask)) && \
403 !((&sb->s_feature_compat)[(type)] & (mask)))
404#define FEATURE_CHANGED(type, mask) ((mask) & \
405 (old_features[(type)] ^ (&sb->s_feature_compat)[(type)]))
Theodore Ts'o63985322001-01-03 17:02:13 +0000406
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500407 old_features[E2P_FEATURE_COMPAT] = sb->s_feature_compat;
408 old_features[E2P_FEATURE_INCOMPAT] = sb->s_feature_incompat;
409 old_features[E2P_FEATURE_RO_INCOMPAT] = sb->s_feature_ro_compat;
410
Theodore Ts'o7c4a2ef2008-02-26 14:27:57 -0500411 if (e2p_edit_feature2(features, &sb->s_feature_compat,
412 ok_features, clear_ok_features,
413 &type_err, &mask_err)) {
414 if (!mask_err)
415 fprintf(stderr,
416 _("Invalid filesystem option set: %s\n"),
417 features);
418 else if (type_err & E2P_FEATURE_NEGATE_FLAG)
419 fprintf(stderr, _("Clearing filesystem feature '%s' "
420 "not supported.\n"),
421 e2p_feature2string(type_err &
422 E2P_FEATURE_TYPE_MASK,
423 mask_err));
424 else
425 fprintf(stderr, _("Setting filesystem feature '%s' "
426 "not supported.\n"),
427 e2p_feature2string(type_err, mask_err));
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400428 return 1;
Theodore Ts'o63985322001-01-03 17:02:13 +0000429 }
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500430
431 if (FEATURE_OFF(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
Theodore Ts'o63985322001-01-03 17:02:13 +0000432 if ((mount_flags & EXT2_MF_MOUNTED) &&
433 !(mount_flags & EXT2_MF_READONLY)) {
Theodore Ts'o2be8fe42008-07-10 10:49:59 -0400434 fputs(_("The has_journal feature may only be "
Theodore Ts'o54434922003-12-07 01:28:50 -0500435 "cleared when the filesystem is\n"
436 "unmounted or mounted "
437 "read-only.\n"), stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400438 return 1;
Theodore Ts'o63985322001-01-03 17:02:13 +0000439 }
440 if (sb->s_feature_incompat &
441 EXT3_FEATURE_INCOMPAT_RECOVER) {
Theodore Ts'o54434922003-12-07 01:28:50 -0500442 fputs(_("The needs_recovery flag is set. "
443 "Please run e2fsck before clearing\n"
444 "the has_journal flag.\n"), stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400445 return 1;
Theodore Ts'o63985322001-01-03 17:02:13 +0000446 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000447 if (sb->s_journal_inum) {
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400448 if (remove_journal_inode(fs))
449 return 1;
Theodore Ts'o63985322001-01-03 17:02:13 +0000450 }
Theodore Ts'ode49f012001-07-30 16:31:30 -0400451 if (sb->s_journal_dev) {
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400452 if (remove_journal_device(fs))
453 return 1;
Theodore Ts'ode49f012001-07-30 16:31:30 -0400454 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000455 }
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400456 if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) {
457 int error;
458
459 if ((mount_flags & EXT2_MF_MOUNTED) ||
460 (mount_flags & EXT2_MF_READONLY)) {
461 fputs(_("The multiple mount protection feature can't\n"
462 "be set if the filesystem is mounted or\n"
463 "read-only.\n"), stderr);
464 return 1;
465 }
466
467 error = ext2fs_mmp_init(fs);
468 if (error) {
469 fputs(_("\nError while enabling multiple mount "
470 "protection feature."), stderr);
471 return 1;
472 }
473
474 /*
475 * We want to update group desc with the new free blocks count
476 */
477 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
478
479 printf(_("Multiple mount protection has been enabled "
480 "with update interval %ds.\n"),
481 sb->s_mmp_update_interval);
482 }
483
484 if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_MMP)) {
485 int error;
486
487 if (mount_flags & EXT2_MF_READONLY) {
488 fputs(_("The multiple mount protection feature cannot\n"
489 "be disabled if the filesystem is readonly.\n"),
490 stderr);
491 return 1;
492 }
493
494 error = ext2fs_read_bitmaps(fs);
495 if (error) {
496 fputs(_("Error while reading bitmaps\n"), stderr);
497 return 1;
498 }
499
500 error = ext2fs_mmp_read(fs, sb->s_mmp_block, NULL);
501 if (error) {
502 struct mmp_struct *mmp_cmp = fs->mmp_cmp;
503
504 if (error == EXT2_ET_MMP_MAGIC_INVALID)
505 printf(_("Magic number in MMP block does not "
506 "match. expected: %x, actual: %x\n"),
507 EXT4_MMP_MAGIC, mmp_cmp->mmp_magic);
508 else
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500509 com_err(program_name, error, "%s",
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400510 _("while reading MMP block."));
511 goto mmp_error;
512 }
513
514 /* We need to force out the group descriptors as well */
515 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
Darrick J. Wong4dbfd792013-10-07 09:51:48 -0400516 ext2fs_block_alloc_stats2(fs, sb->s_mmp_block, -1);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400517mmp_error:
518 sb->s_mmp_block = 0;
519 sb->s_mmp_update_interval = 0;
520 }
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500521
522 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
Theodore Ts'o63985322001-01-03 17:02:13 +0000523 /*
524 * If adding a journal flag, let the create journal
Benno Schulenberg7a0516a2008-07-17 23:58:35 +0200525 * code below handle setting the flag and creating the
526 * journal. We supply a default size if necessary.
Theodore Ts'o63985322001-01-03 17:02:13 +0000527 */
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000528 if (!journal_size)
529 journal_size = -1;
Theodore Ts'o08dd8302001-01-14 16:25:58 +0000530 sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
Theodore Ts'o63985322001-01-03 17:02:13 +0000531 }
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500532
533 if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) {
Theodore Ts'o843049c2002-09-22 15:37:40 -0400534 if (!sb->s_def_hash_version)
Theodore Ts'od1070d92008-08-28 23:09:35 -0400535 sb->s_def_hash_version = EXT2_HASH_HALF_MD4;
Theodore Ts'o843049c2002-09-22 15:37:40 -0400536 if (uuid_is_null((unsigned char *) sb->s_hash_seed))
537 uuid_generate((unsigned char *) sb->s_hash_seed);
538 }
Theodore Ts'odc2ec522001-01-18 01:51:15 +0000539
Theodore Ts'oa49670e2008-02-27 18:53:34 -0500540 if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
Jose R. Santosc2d43002007-08-13 23:32:57 -0500541 if (ext2fs_check_desc(fs)) {
542 fputs(_("Clearing the flex_bg flag would "
543 "cause the the filesystem to be\n"
544 "inconsistent.\n"), stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400545 return 1;
Jose R. Santosc2d43002007-08-13 23:32:57 -0500546 }
547 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000548
Theodore Ts'o2be8fe42008-07-10 10:49:59 -0400549 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
550 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
551 if ((mount_flags & EXT2_MF_MOUNTED) &&
552 !(mount_flags & EXT2_MF_READONLY)) {
553 fputs(_("The huge_file feature may only be "
554 "cleared when the filesystem is\n"
555 "unmounted or mounted "
556 "read-only.\n"), stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400557 return 1;
Theodore Ts'o2be8fe42008-07-10 10:49:59 -0400558 }
559 }
560
Theodore Ts'o079ad632010-05-19 12:14:39 -0400561 if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
562 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -0400563 for (i = 0; i < fs->group_desc_count; i++) {
564 gd = ext2fs_group_desc(fs, fs->group_desc, i);
Theodore Ts'o079ad632010-05-19 12:14:39 -0400565 gd->bg_itable_unused = 0;
566 gd->bg_flags = EXT2_BG_INODE_ZEROED;
567 ext2fs_group_desc_csum_set(fs, i);
568 }
569 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
570 }
571
572 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
573 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -0400574 for (i = 0; i < fs->group_desc_count; i++) {
575 gd = ext2fs_group_desc(fs, fs->group_desc, i);
Theodore Ts'o079ad632010-05-19 12:14:39 -0400576 if ((gd->bg_flags & EXT2_BG_INODE_ZEROED) == 0) {
577 /*
578 * XXX what we really should do is zap
579 * uninitialized inode tables instead.
580 */
581 request_fsck_afterwards(fs);
582 break;
583 }
584 gd->bg_itable_unused = 0;
585 gd->bg_flags = 0;
586 gd->bg_checksum = 0;
587 }
588 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
589 }
590
Aditya Kali771e8db2011-07-20 11:40:05 -0700591 if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
592 EXT4_FEATURE_RO_COMPAT_QUOTA)) {
593 /*
594 * Set the Q_flag here and handle the quota options in the code
595 * below.
596 */
597 if (!Q_flag) {
598 Q_flag = 1;
599 /* Enable both user quota and group quota by default */
600 usrquota = QOPT_ENABLE;
601 grpquota = QOPT_ENABLE;
602 }
603 sb->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA;
604 }
605
606 if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
607 EXT4_FEATURE_RO_COMPAT_QUOTA)) {
608 /*
609 * Set the Q_flag here and handle the quota options in the code
610 * below.
611 */
612 if (Q_flag)
613 fputs(_("\nWarning: '^quota' option overrides '-Q'"
614 "arguments.\n"), stderr);
615 Q_flag = 1;
616 /* Disable both user quota and group quota by default */
617 usrquota = QOPT_DISABLE;
618 grpquota = QOPT_DISABLE;
619 }
620
Theodore Ts'o63985322001-01-03 17:02:13 +0000621 if (sb->s_rev_level == EXT2_GOOD_OLD_REV &&
622 (sb->s_feature_compat || sb->s_feature_ro_compat ||
623 sb->s_feature_incompat))
624 ext2fs_update_dynamic_rev(fs);
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500625
626 if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT,
627 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
Theodore Ts'o2be8fe42008-07-10 10:49:59 -0400628 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
629 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500630 FEATURE_CHANGED(E2P_FEATURE_INCOMPAT,
Theodore Ts'o037914e2008-02-26 17:31:06 -0500631 EXT2_FEATURE_INCOMPAT_FILETYPE) ||
632 FEATURE_CHANGED(E2P_FEATURE_COMPAT,
Theodore Ts'o558df542008-02-27 15:01:19 -0500633 EXT2_FEATURE_COMPAT_RESIZE_INODE) ||
634 FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
Theodore Ts'o079ad632010-05-19 12:14:39 -0400635 EXT2_FEATURE_RO_COMPAT_LARGE_FILE))
636 request_fsck_afterwards(fs);
Theodore Ts'o885bf6b2008-02-26 15:08:14 -0500637
638 if ((old_features[E2P_FEATURE_COMPAT] != sb->s_feature_compat) ||
639 (old_features[E2P_FEATURE_INCOMPAT] != sb->s_feature_incompat) ||
640 (old_features[E2P_FEATURE_RO_INCOMPAT] != sb->s_feature_ro_compat))
Theodore Ts'o2eb3b202004-04-07 09:27:36 -0400641 ext2fs_mark_super_dirty(fs);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400642
643 return 0;
Theodore Ts'o63985322001-01-03 17:02:13 +0000644}
645
646/*
647 * Add a journal to the filesystem.
648 */
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400649static int add_journal(ext2_filsys fs)
Theodore Ts'o63985322001-01-03 17:02:13 +0000650{
651 unsigned long journal_blocks;
652 errcode_t retval;
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000653 ext2_filsys jfs;
Theodore Ts'o2a29f132003-05-05 12:08:47 -0400654 io_manager io_ptr;
Theodore Ts'o63985322001-01-03 17:02:13 +0000655
656 if (fs->super->s_feature_compat &
657 EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
Theodore Ts'o54434922003-12-07 01:28:50 -0500658 fputs(_("The filesystem already has a journal.\n"), stderr);
Andreas Dilger2d155762001-08-17 03:48:11 -0600659 goto err;
Theodore Ts'o63985322001-01-03 17:02:13 +0000660 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000661 if (journal_device) {
662 check_plausibility(journal_device);
663 check_mount(journal_device, 0, _("journal"));
Theodore Ts'o2a29f132003-05-05 12:08:47 -0400664#ifdef CONFIG_TESTIO_DEBUG
Theodore Ts'of38cf3c2008-09-01 11:17:29 -0400665 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
666 io_ptr = test_io_manager;
667 test_io_backing_manager = unix_io_manager;
668 } else
Theodore Ts'o2a29f132003-05-05 12:08:47 -0400669#endif
Theodore Ts'of38cf3c2008-09-01 11:17:29 -0400670 io_ptr = unix_io_manager;
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000671 retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
672 EXT2_FLAG_JOURNAL_DEV_OK, 0,
Theodore Ts'o2a29f132003-05-05 12:08:47 -0400673 fs->blocksize, io_ptr, &jfs);
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000674 if (retval) {
675 com_err(program_name, retval,
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000676 _("\n\twhile trying to open journal on %s\n"),
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000677 journal_device);
Andreas Dilger2d155762001-08-17 03:48:11 -0600678 goto err;
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000679 }
Theodore Ts'o63985322001-01-03 17:02:13 +0000680 printf(_("Creating journal on device %s: "),
681 journal_device);
Theodore Ts'o4055ef72001-01-14 16:11:14 +0000682 fflush(stdout);
Andreas Dilger2d155762001-08-17 03:48:11 -0600683
Theodore Ts'o16ed5b32001-01-16 07:47:31 +0000684 retval = ext2fs_add_journal_device(fs, jfs);
Andreas Dilger2d155762001-08-17 03:48:11 -0600685 ext2fs_close(jfs);
Theodore Ts'o63985322001-01-03 17:02:13 +0000686 if (retval) {
Theodore Ts'oec43da22009-01-20 02:34:39 -0500687 com_err(program_name, retval,
688 _("while adding filesystem to journal on %s"),
689 journal_device);
Andreas Dilger2d155762001-08-17 03:48:11 -0600690 goto err;
Theodore Ts'o63985322001-01-03 17:02:13 +0000691 }
Theodore Ts'o54434922003-12-07 01:28:50 -0500692 fputs(_("done\n"), stdout);
Theodore Ts'o63985322001-01-03 17:02:13 +0000693 } else if (journal_size) {
Theodore Ts'o54434922003-12-07 01:28:50 -0500694 fputs(_("Creating journal inode: "), stdout);
Theodore Ts'o63985322001-01-03 17:02:13 +0000695 fflush(stdout);
Theodore Ts'o2537b6d2001-03-26 20:07:13 +0000696 journal_blocks = figure_journal_size(journal_size, fs);
697
Theodore Ts'ob8182052014-01-28 12:58:56 -0500698 if (journal_location_string)
699 journal_location =
700 parse_num_blocks2(journal_location_string,
701 fs->super->s_log_block_size);
702 retval = ext2fs_add_journal_inode2(fs, journal_blocks,
703 journal_location,
704 journal_flags);
Theodore Ts'o63985322001-01-03 17:02:13 +0000705 if (retval) {
Theodore Ts'o7141b542001-08-15 19:17:37 -0400706 fprintf(stderr, "\n");
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500707 com_err(program_name, retval, "%s",
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000708 _("\n\twhile trying to create journal file"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400709 return retval;
Theodore Ts'o1d08d9b2001-04-17 01:01:49 +0000710 } else
Theodore Ts'o54434922003-12-07 01:28:50 -0500711 fputs(_("done\n"), stdout);
Theodore Ts'o63985322001-01-03 17:02:13 +0000712 /*
713 * If the filesystem wasn't mounted, we need to force
714 * the block group descriptors out.
715 */
716 if ((mount_flags & EXT2_MF_MOUNTED) == 0)
717 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
718 }
Lukas Czernerfaa2dcd2011-09-13 22:24:11 -0400719 print_check_message(fs->super->s_max_mnt_count,
720 fs->super->s_checkinterval);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400721 return 0;
Andreas Dilger2d155762001-08-17 03:48:11 -0600722
723err:
Jim Meyering45e338f2009-02-23 18:07:50 +0100724 free(journal_device);
Andreas Dilger0f5eba72011-09-24 13:48:55 -0400725 return 1;
Theodore Ts'o63985322001-01-03 17:02:13 +0000726}
727
Theodore Ts'o577c7732013-05-19 20:03:48 -0400728static void handle_quota_options(ext2_filsys fs)
Aditya Kali771e8db2011-07-20 11:40:05 -0700729{
730 quota_ctx_t qctx;
Aditya Kali771e8db2011-07-20 11:40:05 -0700731 ext2_ino_t qf_ino;
732
733 if (!usrquota && !grpquota)
734 /* Nothing to do. */
735 return;
736
Aditya Kalia86d55d2011-11-14 10:55:54 -0500737 quota_init_context(&qctx, fs, -1);
Aditya Kali771e8db2011-07-20 11:40:05 -0700738
Aditya Kalid7c6f4e2011-11-14 10:55:54 -0500739 if (usrquota == QOPT_ENABLE || grpquota == QOPT_ENABLE)
740 quota_compute_usage(qctx);
Aditya Kali771e8db2011-07-20 11:40:05 -0700741
Niucdfaa752011-11-14 10:58:28 -0500742 if (usrquota == QOPT_ENABLE && !fs->super->s_usr_quota_inum) {
743 if ((qf_ino = quota_file_exists(fs, USRQUOTA,
Aditya Kali50277512012-07-13 15:25:06 -0700744 QFMT_VFS_V1)) > 0)
745 quota_update_limits(qctx, qf_ino, USRQUOTA);
746 quota_write_inode(qctx, USRQUOTA);
Niucdfaa752011-11-14 10:58:28 -0500747 } else if (usrquota == QOPT_DISABLE) {
Aditya Kalid7c6f4e2011-11-14 10:55:54 -0500748 quota_remove_inode(fs, USRQUOTA);
Niucdfaa752011-11-14 10:58:28 -0500749 }
Aditya Kalid7c6f4e2011-11-14 10:55:54 -0500750
Niucdfaa752011-11-14 10:58:28 -0500751 if (grpquota == QOPT_ENABLE && !fs->super->s_grp_quota_inum) {
752 if ((qf_ino = quota_file_exists(fs, GRPQUOTA,
Aditya Kali50277512012-07-13 15:25:06 -0700753 QFMT_VFS_V1)) > 0)
754 quota_update_limits(qctx, qf_ino, GRPQUOTA);
755 quota_write_inode(qctx, GRPQUOTA);
Niucdfaa752011-11-14 10:58:28 -0500756 } else if (grpquota == QOPT_DISABLE) {
Aditya Kalia86d55d2011-11-14 10:55:54 -0500757 quota_remove_inode(fs, GRPQUOTA);
Niucdfaa752011-11-14 10:58:28 -0500758 }
Aditya Kali771e8db2011-07-20 11:40:05 -0700759
Aditya Kalia86d55d2011-11-14 10:55:54 -0500760 quota_release_context(&qctx);
Aditya Kali771e8db2011-07-20 11:40:05 -0700761
762 if ((usrquota == QOPT_ENABLE) || (grpquota == QOPT_ENABLE)) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -0500763 fprintf(stderr, "%s", _("\nWarning: the quota feature is still "
Theodore Ts'oa713a7f2013-01-21 19:07:38 -0500764 "under development\n"
765 "See https://ext4.wiki.kernel.org/"
766 "index.php/Quota for more information\n\n"));
Aditya Kali771e8db2011-07-20 11:40:05 -0700767 fs->super->s_feature_ro_compat |= EXT4_FEATURE_RO_COMPAT_QUOTA;
768 ext2fs_mark_super_dirty(fs);
Aditya Kali89dd15d2012-07-13 15:25:09 -0700769 } else if (!fs->super->s_usr_quota_inum &&
770 !fs->super->s_grp_quota_inum) {
Aditya Kali771e8db2011-07-20 11:40:05 -0700771 fs->super->s_feature_ro_compat &= ~EXT4_FEATURE_RO_COMPAT_QUOTA;
772 ext2fs_mark_super_dirty(fs);
773 }
774
775 return;
776}
777
Andreas Dilger269da3b2013-12-15 23:26:25 -0500778#ifdef CONFIG_QUOTA
Theodore Ts'o577c7732013-05-19 20:03:48 -0400779static void parse_quota_opts(const char *opts)
Aditya Kali771e8db2011-07-20 11:40:05 -0700780{
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700781 char *buf, *token, *next, *p;
Aditya Kali771e8db2011-07-20 11:40:05 -0700782 int len;
783
784 len = strlen(opts);
785 buf = malloc(len+1);
786 if (!buf) {
787 fputs(_("Couldn't allocate memory to parse quota "
788 "options!\n"), stderr);
789 exit(1);
790 }
791 strcpy(buf, opts);
792 for (token = buf; token && *token; token = next) {
793 p = strchr(token, ',');
794 next = 0;
795 if (p) {
796 *p = 0;
797 next = p+1;
798 }
799
800 if (strcmp(token, "usrquota") == 0) {
801 usrquota = QOPT_ENABLE;
802 } else if (strcmp(token, "^usrquota") == 0) {
803 usrquota = QOPT_DISABLE;
804 } else if (strcmp(token, "grpquota") == 0) {
805 grpquota = QOPT_ENABLE;
806 } else if (strcmp(token, "^grpquota") == 0) {
807 grpquota = QOPT_DISABLE;
808 } else {
809 fputs(_("\nBad quota options specified.\n\n"
810 "Following valid quota options are available "
811 "(pass by separating with comma):\n"
812 "\t[^]usrquota\n"
813 "\t[^]grpquota\n"
814 "\n\n"), stderr);
815 free(buf);
816 exit(1);
817 }
818 }
819 free(buf);
820}
Andreas Dilger269da3b2013-12-15 23:26:25 -0500821#endif
Theodore Ts'o896938d1999-10-23 01:04:50 +0000822
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000823static void parse_e2label_options(int argc, char ** argv)
Theodore Ts'o83238152001-01-09 00:16:26 +0000824{
825 if ((argc < 2) || (argc > 3)) {
Theodore Ts'o54434922003-12-07 01:28:50 -0500826 fputs(_("Usage: e2label device [newlabel]\n"), stderr);
Theodore Ts'o83238152001-01-09 00:16:26 +0000827 exit(1);
828 }
Theodore Ts'o2e8ca9a2004-11-30 14:07:11 -0500829 io_options = strchr(argv[1], '?');
830 if (io_options)
831 *io_options++ = 0;
Theodore Ts'o332f2c22003-03-06 12:58:33 -0500832 device_name = blkid_get_devname(NULL, argv[1], NULL);
Theodore Ts'o817e49e2003-11-21 09:10:29 -0500833 if (!device_name) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400834 com_err("e2label", 0, _("Unable to resolve '%s'"),
Theodore Ts'o817e49e2003-11-21 09:10:29 -0500835 argv[1]);
836 exit(1);
837 }
Theodore Ts'o2be8fe42008-07-10 10:49:59 -0400838 open_flag = EXT2_FLAG_JOURNAL_DEV_OK;
Theodore Ts'o83238152001-01-09 00:16:26 +0000839 if (argc == 3) {
Theodore Ts'o0ddfd9a2008-02-09 22:22:38 -0500840 open_flag |= EXT2_FLAG_RW;
Theodore Ts'o83238152001-01-09 00:16:26 +0000841 L_flag = 1;
842 new_label = argv[2];
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400843 } else
Theodore Ts'o83238152001-01-09 00:16:26 +0000844 print_label++;
845}
846
Theodore Ts'od4de4aa2001-12-26 08:58:01 -0500847static time_t parse_time(char *str)
848{
849 struct tm ts;
850
851 if (strcmp(str, "now") == 0) {
852 return (time(0));
853 }
854 memset(&ts, 0, sizeof(ts));
Theodore Ts'obc7c14e2003-05-03 16:40:09 -0400855#ifdef HAVE_STRPTIME
Theodore Ts'o690e6932004-12-21 20:40:08 -0500856 strptime(str, "%Y%m%d%H%M%S", &ts);
Theodore Ts'obc7c14e2003-05-03 16:40:09 -0400857#else
Theodore Ts'o690e6932004-12-21 20:40:08 -0500858 sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
Theodore Ts'obc7c14e2003-05-03 16:40:09 -0400859 &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
860 ts.tm_year -= 1900;
861 ts.tm_mon -= 1;
862 if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
863 ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
864 ts.tm_min > 59 || ts.tm_sec > 61)
865 ts.tm_mday = 0;
866#endif
Theodore Ts'od4de4aa2001-12-26 08:58:01 -0500867 if (ts.tm_mday == 0) {
868 com_err(program_name, 0,
869 _("Couldn't parse date/time specifier: %s"),
870 str);
871 usage();
872 }
Theodore Ts'oa2ff0f32008-03-21 09:10:09 -0400873 ts.tm_isdst = -1;
Theodore Ts'od4de4aa2001-12-26 08:58:01 -0500874 return (mktime(&ts));
875}
Theodore Ts'o83238152001-01-09 00:16:26 +0000876
Theodore Ts'oc8c071a2001-01-11 16:08:23 +0000877static void parse_tune2fs_options(int argc, char **argv)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000878{
Theodore Ts'o519149f1997-10-25 03:49:49 +0000879 int c;
Theodore Ts'oec43da22009-01-20 02:34:39 -0500880 char *tmp;
881 struct group *gr;
882 struct passwd *pw;
Eric Sandeend82445e2013-10-14 09:03:06 -0400883 char optstring[100] = "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000884
Eric Sandeend82445e2013-10-14 09:03:06 -0400885#ifdef CONFIG_QUOTA
886 strcat(optstring, "Q:");
887#endif
Theodore Ts'o2be8fe42008-07-10 10:49:59 -0400888 open_flag = 0;
Theodore Ts'o0ddfd9a2008-02-09 22:22:38 -0500889
Theodore Ts'o0f8973f2001-08-27 12:44:23 -0400890 printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
Eric Sandeend82445e2013-10-14 09:03:06 -0400891 while ((c = getopt(argc, argv, optstring)) != EOF)
Theodore Ts'oec43da22009-01-20 02:34:39 -0500892 switch (c) {
893 case 'c':
894 max_mount_count = strtol(optarg, &tmp, 0);
895 if (*tmp || max_mount_count > 16000) {
896 com_err(program_name, 0,
897 _("bad mounts count - %s"),
898 optarg);
899 usage();
900 }
901 if (max_mount_count == 0)
902 max_mount_count = -1;
903 c_flag = 1;
904 open_flag = EXT2_FLAG_RW;
905 break;
906 case 'C':
907 mount_count = strtoul(optarg, &tmp, 0);
908 if (*tmp || mount_count > 16000) {
909 com_err(program_name, 0,
910 _("bad mounts count - %s"),
911 optarg);
912 usage();
913 }
914 C_flag = 1;
915 open_flag = EXT2_FLAG_RW;
916 break;
917 case 'e':
918 if (strcmp(optarg, "continue") == 0)
919 errors = EXT2_ERRORS_CONTINUE;
920 else if (strcmp(optarg, "remount-ro") == 0)
921 errors = EXT2_ERRORS_RO;
922 else if (strcmp(optarg, "panic") == 0)
923 errors = EXT2_ERRORS_PANIC;
924 else {
925 com_err(program_name, 0,
926 _("bad error behavior - %s"),
927 optarg);
928 usage();
929 }
930 e_flag = 1;
931 open_flag = EXT2_FLAG_RW;
932 break;
933 case 'E':
934 extended_cmd = optarg;
935 open_flag |= EXT2_FLAG_RW;
936 break;
937 case 'f': /* Force */
938 f_flag = 1;
939 break;
940 case 'g':
941 resgid = strtoul(optarg, &tmp, 0);
942 if (*tmp) {
943 gr = getgrnam(optarg);
944 if (gr == NULL)
945 tmp = optarg;
Theodore Ts'o818180c1998-06-27 05:11:14 +0000946 else {
Theodore Ts'oec43da22009-01-20 02:34:39 -0500947 resgid = gr->gr_gid;
948 *tmp = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000949 }
Theodore Ts'oec43da22009-01-20 02:34:39 -0500950 }
951 if (*tmp) {
952 com_err(program_name, 0,
953 _("bad gid/group name - %s"),
954 optarg);
955 usage();
956 }
957 g_flag = 1;
958 open_flag = EXT2_FLAG_RW;
959 break;
960 case 'i':
961 interval = strtoul(optarg, &tmp, 0);
962 switch (*tmp) {
963 case 's':
964 tmp++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000965 break;
Theodore Ts'oec43da22009-01-20 02:34:39 -0500966 case '\0':
967 case 'd':
968 case 'D': /* days */
969 interval *= 86400;
970 if (*tmp != '\0')
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000971 tmp++;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000972 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000973 case 'm':
Theodore Ts'oec43da22009-01-20 02:34:39 -0500974 case 'M': /* months! */
975 interval *= 86400 * 30;
976 tmp++;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000977 break;
Theodore Ts'oec43da22009-01-20 02:34:39 -0500978 case 'w':
979 case 'W': /* weeks */
980 interval *= 86400 * 7;
981 tmp++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000982 break;
Theodore Ts'oec43da22009-01-20 02:34:39 -0500983 }
984 if (*tmp) {
985 com_err(program_name, 0,
986 _("bad interval - %s"), optarg);
987 usage();
988 }
989 i_flag = 1;
990 open_flag = EXT2_FLAG_RW;
991 break;
992 case 'j':
993 if (!journal_size)
994 journal_size = -1;
995 open_flag = EXT2_FLAG_RW;
996 break;
997 case 'J':
998 parse_journal_opts(optarg);
999 open_flag = EXT2_FLAG_RW;
1000 break;
1001 case 'l':
1002 l_flag = 1;
1003 break;
1004 case 'L':
1005 new_label = optarg;
1006 L_flag = 1;
1007 open_flag |= EXT2_FLAG_RW |
1008 EXT2_FLAG_JOURNAL_DEV_OK;
1009 break;
1010 case 'm':
1011 reserved_ratio = strtod(optarg, &tmp);
Theodore Ts'o8d822452009-03-06 02:23:59 -05001012 if (*tmp || reserved_ratio > 50 ||
1013 reserved_ratio < 0) {
Theodore Ts'oec43da22009-01-20 02:34:39 -05001014 com_err(program_name, 0,
1015 _("bad reserved block ratio - %s"),
1016 optarg);
1017 usage();
1018 }
1019 m_flag = 1;
1020 open_flag = EXT2_FLAG_RW;
1021 break;
1022 case 'M':
1023 new_last_mounted = optarg;
1024 M_flag = 1;
1025 open_flag = EXT2_FLAG_RW;
1026 break;
1027 case 'o':
1028 if (mntopts_cmd) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -05001029 com_err(program_name, 0, "%s",
Theodore Ts'oec43da22009-01-20 02:34:39 -05001030 _("-o may only be specified once"));
1031 usage();
1032 }
1033 mntopts_cmd = optarg;
1034 open_flag = EXT2_FLAG_RW;
1035 break;
Theodore Ts'oec43da22009-01-20 02:34:39 -05001036 case 'O':
1037 if (features_cmd) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -05001038 com_err(program_name, 0, "%s",
Theodore Ts'oec43da22009-01-20 02:34:39 -05001039 _("-O may only be specified once"));
1040 usage();
1041 }
1042 features_cmd = optarg;
1043 open_flag = EXT2_FLAG_RW;
1044 break;
Eric Sandeend82445e2013-10-14 09:03:06 -04001045#ifdef CONFIG_QUOTA
Aditya Kali771e8db2011-07-20 11:40:05 -07001046 case 'Q':
1047 Q_flag = 1;
1048 parse_quota_opts(optarg);
1049 open_flag = EXT2_FLAG_RW;
1050 break;
Eric Sandeend82445e2013-10-14 09:03:06 -04001051#endif
Theodore Ts'oec43da22009-01-20 02:34:39 -05001052 case 'r':
1053 reserved_blocks = strtoul(optarg, &tmp, 0);
1054 if (*tmp) {
1055 com_err(program_name, 0,
1056 _("bad reserved blocks count - %s"),
1057 optarg);
1058 usage();
1059 }
1060 r_flag = 1;
1061 open_flag = EXT2_FLAG_RW;
1062 break;
1063 case 's': /* Deprecated */
1064 s_flag = atoi(optarg);
1065 open_flag = EXT2_FLAG_RW;
1066 break;
1067 case 'T':
1068 T_flag = 1;
1069 last_check_time = parse_time(optarg);
1070 open_flag = EXT2_FLAG_RW;
1071 break;
1072 case 'u':
1073 resuid = strtoul(optarg, &tmp, 0);
Theodore Ts'o818180c1998-06-27 05:11:14 +00001074 if (*tmp) {
Theodore Ts'oec43da22009-01-20 02:34:39 -05001075 pw = getpwnam(optarg);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001076 if (pw == NULL)
1077 tmp = optarg;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +00001078 else {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001079 resuid = pw->pw_uid;
Theodore Ts'oa418d3a1997-04-26 14:00:26 +00001080 *tmp = 0;
1081 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001082 }
Theodore Ts'o818180c1998-06-27 05:11:14 +00001083 if (*tmp) {
Theodore Ts'oec43da22009-01-20 02:34:39 -05001084 com_err(program_name, 0,
1085 _("bad uid/user name - %s"),
1086 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +00001087 usage();
Theodore Ts'of3db3561997-04-26 13:34:30 +00001088 }
1089 u_flag = 1;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001090 open_flag = EXT2_FLAG_RW;
1091 break;
Theodore Ts'oec43da22009-01-20 02:34:39 -05001092 case 'U':
1093 new_UUID = optarg;
1094 U_flag = 1;
1095 open_flag = EXT2_FLAG_RW |
1096 EXT2_FLAG_JOURNAL_DEV_OK;
1097 break;
1098 case 'I':
1099 new_inode_size = strtoul(optarg, &tmp, 0);
1100 if (*tmp) {
1101 com_err(program_name, 0,
1102 _("bad inode size - %s"),
1103 optarg);
Theodore Ts'o818180c1998-06-27 05:11:14 +00001104 usage();
Theodore Ts'oec43da22009-01-20 02:34:39 -05001105 }
1106 if (!((new_inode_size &
1107 (new_inode_size - 1)) == 0)) {
1108 com_err(program_name, 0,
1109 _("Inode size must be a "
1110 "power of two- %s"),
1111 optarg);
1112 usage();
1113 }
1114 open_flag = EXT2_FLAG_RW;
1115 I_flag = 1;
1116 break;
1117 default:
1118 usage();
Theodore Ts'o3839e651997-04-26 13:21:57 +00001119 }
1120 if (optind < argc - 1 || optind == argc)
Theodore Ts'o818180c1998-06-27 05:11:14 +00001121 usage();
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001122 if (!open_flag && !l_flag)
1123 usage();
Theodore Ts'o2e8ca9a2004-11-30 14:07:11 -05001124 io_options = strchr(argv[optind], '?');
1125 if (io_options)
1126 *io_options++ = 0;
Theodore Ts'o332f2c22003-03-06 12:58:33 -05001127 device_name = blkid_get_devname(NULL, argv[optind], NULL);
Theodore Ts'o817e49e2003-11-21 09:10:29 -05001128 if (!device_name) {
Theodore Ts'oe3507732013-01-01 13:28:27 -05001129 com_err(program_name, 0, _("Unable to resolve '%s'"),
Theodore Ts'o817e49e2003-11-21 09:10:29 -05001130 argv[optind]);
1131 exit(1);
1132 }
Theodore Ts'o118d7da2002-08-17 23:01:22 -04001133}
Theodore Ts'o83238152001-01-09 00:16:26 +00001134
Theodore Ts'o14b596d2009-04-22 09:18:30 -04001135#ifdef CONFIG_BUILD_FINDFS
Theodore Ts'o3e699062002-10-13 23:56:28 -04001136void do_findfs(int argc, char **argv)
Theodore Ts'o118d7da2002-08-17 23:01:22 -04001137{
1138 char *dev;
1139
1140 if ((argc != 2) ||
1141 (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) {
1142 fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n");
1143 exit(2);
1144 }
Theodore Ts'oed1b33e2003-03-01 19:29:01 -05001145 dev = blkid_get_devname(NULL, argv[1], NULL);
Theodore Ts'o118d7da2002-08-17 23:01:22 -04001146 if (!dev) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001147 com_err("findfs", 0, _("Unable to resolve '%s'"),
Theodore Ts'o118d7da2002-08-17 23:01:22 -04001148 argv[1]);
1149 exit(1);
1150 }
1151 puts(dev);
1152 exit(0);
1153}
Theodore Ts'o14b596d2009-04-22 09:18:30 -04001154#endif
Theodore Ts'o83238152001-01-09 00:16:26 +00001155
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001156static int parse_extended_opts(ext2_filsys fs, const char *opts)
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001157{
1158 char *buf, *token, *next, *p, *arg;
Theodore Ts'o10ff68d2008-08-29 21:21:19 -04001159 int len, hash_alg;
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001160 int r_usage = 0;
1161
1162 len = strlen(opts);
1163 buf = malloc(len+1);
1164 if (!buf) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -05001165 fprintf(stderr, "%s",
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001166 _("Couldn't allocate memory to parse options!\n"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001167 return 1;
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001168 }
1169 strcpy(buf, opts);
1170 for (token = buf; token && *token; token = next) {
1171 p = strchr(token, ',');
1172 next = 0;
1173 if (p) {
1174 *p = 0;
1175 next = p+1;
1176 }
1177 arg = strchr(token, '=');
1178 if (arg) {
1179 *arg = 0;
1180 arg++;
1181 }
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001182 if (strcmp(token, "clear-mmp") == 0 ||
1183 strcmp(token, "clear_mmp") == 0) {
1184 clear_mmp = 1;
1185 } else if (strcmp(token, "mmp_update_interval") == 0) {
Theodore Ts'o577c7732013-05-19 20:03:48 -04001186 unsigned long intv;
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001187 if (!arg) {
1188 r_usage++;
1189 continue;
1190 }
Theodore Ts'o577c7732013-05-19 20:03:48 -04001191 intv = strtoul(arg, &p, 0);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001192 if (*p) {
1193 fprintf(stderr,
1194 _("Invalid mmp_update_interval: %s\n"),
1195 arg);
1196 r_usage++;
1197 continue;
1198 }
Theodore Ts'o577c7732013-05-19 20:03:48 -04001199 if (intv == 0) {
1200 intv = EXT4_MMP_UPDATE_INTERVAL;
1201 } else if (intv > EXT4_MMP_MAX_UPDATE_INTERVAL) {
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001202 fprintf(stderr,
1203 _("mmp_update_interval too big: %lu\n"),
Theodore Ts'o577c7732013-05-19 20:03:48 -04001204 intv);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001205 r_usage++;
1206 continue;
1207 }
Theodore Ts'o3fcd8fe2011-10-09 17:08:47 -04001208 printf(P_("Setting multiple mount protection update "
1209 "interval to %lu second\n",
1210 "Setting multiple mount protection update "
Theodore Ts'o577c7732013-05-19 20:03:48 -04001211 "interval to %lu seconds\n", intv),
1212 intv);
1213 fs->super->s_mmp_update_interval = intv;
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001214 ext2fs_mark_super_dirty(fs);
1215 } else if (!strcmp(token, "test_fs")) {
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001216 fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS;
1217 printf("Setting test filesystem flag\n");
1218 ext2fs_mark_super_dirty(fs);
1219 } else if (!strcmp(token, "^test_fs")) {
1220 fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS;
1221 printf("Clearing test filesystem flag\n");
1222 ext2fs_mark_super_dirty(fs);
Theodore Ts'o0c17cb22008-02-18 22:56:25 -05001223 } else if (strcmp(token, "stride") == 0) {
1224 if (!arg) {
1225 r_usage++;
1226 continue;
1227 }
1228 stride = strtoul(arg, &p, 0);
Theodore Ts'o035f32a2011-07-04 19:37:11 -04001229 if (*p) {
Theodore Ts'o0c17cb22008-02-18 22:56:25 -05001230 fprintf(stderr,
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001231 _("Invalid RAID stride: %s\n"),
Theodore Ts'o0c17cb22008-02-18 22:56:25 -05001232 arg);
1233 r_usage++;
1234 continue;
1235 }
1236 stride_set = 1;
1237 } else if (strcmp(token, "stripe-width") == 0 ||
1238 strcmp(token, "stripe_width") == 0) {
1239 if (!arg) {
1240 r_usage++;
1241 continue;
1242 }
1243 stripe_width = strtoul(arg, &p, 0);
Theodore Ts'o035f32a2011-07-04 19:37:11 -04001244 if (*p) {
Theodore Ts'o0c17cb22008-02-18 22:56:25 -05001245 fprintf(stderr,
1246 _("Invalid RAID stripe-width: %s\n"),
1247 arg);
1248 r_usage++;
1249 continue;
1250 }
1251 stripe_width_set = 1;
Theodore Ts'o10ff68d2008-08-29 21:21:19 -04001252 } else if (strcmp(token, "hash_alg") == 0 ||
1253 strcmp(token, "hash-alg") == 0) {
1254 if (!arg) {
1255 r_usage++;
1256 continue;
1257 }
1258 hash_alg = e2p_string2hash(arg);
1259 if (hash_alg < 0) {
Theodore Ts'oec43da22009-01-20 02:34:39 -05001260 fprintf(stderr,
Theodore Ts'o10ff68d2008-08-29 21:21:19 -04001261 _("Invalid hash algorithm: %s\n"),
1262 arg);
1263 r_usage++;
1264 continue;
1265 }
1266 fs->super->s_def_hash_version = hash_alg;
1267 printf(_("Setting default hash algorithm "
Theodore Ts'oec43da22009-01-20 02:34:39 -05001268 "to %s (%d)\n"),
Theodore Ts'o10ff68d2008-08-29 21:21:19 -04001269 arg, hash_alg);
1270 ext2fs_mark_super_dirty(fs);
Theodore Ts'o9a976ac2011-07-04 20:14:35 -04001271 } else if (!strcmp(token, "mount_opts")) {
Theodore Ts'o9345f022010-09-18 19:38:22 -04001272 if (!arg) {
1273 r_usage++;
1274 continue;
1275 }
1276 if (strlen(arg) >= sizeof(fs->super->s_mount_opts)) {
1277 fprintf(stderr,
1278 "Extended mount options too long\n");
1279 continue;
1280 }
Theodore Ts'o9a976ac2011-07-04 20:14:35 -04001281 ext_mount_opts = strdup(arg);
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001282 } else
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001283 r_usage++;
1284 }
1285 if (r_usage) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -05001286 fprintf(stderr, "%s", _("\nBad options specified.\n\n"
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001287 "Extended options are separated by commas, "
1288 "and may take an argument which\n"
1289 "\tis set off by an equals ('=') sign.\n\n"
1290 "Valid extended options are:\n"
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001291 "\tclear_mmp\n"
Theodore Ts'o9a976ac2011-07-04 20:14:35 -04001292 "\thash_alg=<hash algorithm>\n"
1293 "\tmount_opts=<extended default mount options>\n"
Theodore Ts'o0c17cb22008-02-18 22:56:25 -05001294 "\tstride=<RAID per-disk chunk size in blocks>\n"
Theodore Ts'o10ff68d2008-08-29 21:21:19 -04001295 "\tstripe_width=<RAID stride*data disks in blocks>\n"
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001296 "\ttest_fs\n"
1297 "\t^test_fs\n"));
1298 free(buf);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001299 return 1;
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001300 }
1301 free(buf);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001302
1303 return 0;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001304}
Theodore Ts'o6cb27402008-01-26 19:06:35 -05001305
Theodore Ts'o31f18152009-01-20 11:49:17 -05001306/*
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301307 * Fill in the block bitmap bmap with the information regarding the
1308 * blocks to be moved
Theodore Ts'o31f18152009-01-20 11:49:17 -05001309 */
1310static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301311 ext2fs_block_bitmap bmap)
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301312{
1313 dgrp_t i;
Aneesh Kumar K.V154a5d72009-08-06 11:42:31 +05301314 int retval;
1315 ext2_badblocks_list bb_list = 0;
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001316 blk64_t j, needed_blocks = 0;
1317 blk64_t start_blk, end_blk;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301318
Aneesh Kumar K.V154a5d72009-08-06 11:42:31 +05301319 retval = ext2fs_read_bb_inode(fs, &bb_list);
1320 if (retval)
1321 return retval;
1322
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301323 for (i = 0; i < fs->group_desc_count; i++) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001324 start_blk = ext2fs_inode_table_loc(fs, i) +
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301325 fs->inode_blocks_per_group;
1326
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001327 end_blk = ext2fs_inode_table_loc(fs, i) +
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301328 new_ino_blks_per_grp;
1329
1330 for (j = start_blk; j < end_blk; j++) {
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001331 if (ext2fs_test_block_bitmap2(fs->block_map, j)) {
Aneesh Kumar K.V154a5d72009-08-06 11:42:31 +05301332 /*
1333 * IF the block is a bad block we fail
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301334 */
Aneesh Kumar K.V154a5d72009-08-06 11:42:31 +05301335 if (ext2fs_badblocks_list_test(bb_list, j)) {
1336 ext2fs_badblocks_list_free(bb_list);
1337 return ENOSPC;
1338 }
1339
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001340 ext2fs_mark_block_bitmap2(bmap, j);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301341 } else {
1342 /*
1343 * We are going to use this block for
1344 * inode table. So mark them used.
1345 */
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001346 ext2fs_mark_block_bitmap2(fs->block_map, j);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301347 }
1348 }
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301349 needed_blocks += end_blk - start_blk;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301350 }
1351
Aneesh Kumar K.V154a5d72009-08-06 11:42:31 +05301352 ext2fs_badblocks_list_free(bb_list);
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04001353 if (needed_blocks > ext2fs_free_blocks_count(fs->super))
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301354 return ENOSPC;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301355
1356 return 0;
1357}
1358
Darrick J. Wong4dbfd792013-10-07 09:51:48 -04001359static int ext2fs_is_meta_block(ext2_filsys fs, blk64_t blk)
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301360{
1361 dgrp_t group;
Darrick J. Wong4dbfd792013-10-07 09:51:48 -04001362 group = ext2fs_group_of_blk2(fs, blk);
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001363 if (ext2fs_block_bitmap_loc(fs, group) == blk)
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301364 return 1;
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001365 if (ext2fs_inode_bitmap_loc(fs, group) == blk)
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301366 return 1;
1367 return 0;
1368}
1369
Darrick J. Wong4dbfd792013-10-07 09:51:48 -04001370static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk64_t blk)
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301371{
Darrick J. Wong4dbfd792013-10-07 09:51:48 -04001372 blk64_t start_blk, end_blk;
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301373 start_blk = fs->super->s_first_data_block +
1374 EXT2_BLOCKS_PER_GROUP(fs->super) * group;
1375 /*
1376 * We cannot get new block beyond end_blk for for the last block group
1377 * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group
1378 */
1379 end_blk = start_blk + EXT2_BLOCKS_PER_GROUP(fs->super);
1380 if (blk >= start_blk && blk <= end_blk)
1381 return 1;
1382 return 0;
1383}
1384
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301385static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301386{
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301387
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301388 char *buf;
Andreas Dilgercf5301d2011-06-11 10:58:25 -04001389 dgrp_t group = 0;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301390 errcode_t retval;
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301391 int meta_data = 0;
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001392 blk64_t blk, new_blk, goal;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301393 struct blk_move *bmv;
1394
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301395 retval = ext2fs_get_mem(fs->blocksize, &buf);
1396 if (retval)
1397 return retval;
1398
Theodore Ts'o27c6de42008-11-15 00:32:39 -05001399 for (new_blk = blk = fs->super->s_first_data_block;
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04001400 blk < ext2fs_blocks_count(fs->super); blk++) {
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001401 if (!ext2fs_test_block_bitmap2(bmap, blk))
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301402 continue;
1403
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301404 if (ext2fs_is_meta_block(fs, blk)) {
1405 /*
1406 * If the block is mapping a fs meta data block
1407 * like group desc/block bitmap/inode bitmap. We
1408 * should find a block in the same group and fix
1409 * the respective fs metadata pointers. Otherwise
1410 * fail
1411 */
Darrick J. Wong4dbfd792013-10-07 09:51:48 -04001412 group = ext2fs_group_of_blk2(fs, blk);
Theodore Ts'ob49f78f2009-10-25 21:24:06 -04001413 goal = ext2fs_group_first_block2(fs, group);
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301414 meta_data = 1;
1415
1416 } else {
1417 goal = new_blk;
1418 }
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001419 retval = ext2fs_new_block2(fs, goal, NULL, &new_blk);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301420 if (retval)
1421 goto err_out;
1422
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301423 /* new fs meta data block should be in the same group */
1424 if (meta_data && !ext2fs_is_block_in_group(fs, group, new_blk)) {
1425 retval = ENOSPC;
1426 goto err_out;
1427 }
1428
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301429 /* Mark this block as allocated */
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001430 ext2fs_mark_block_bitmap2(fs->block_map, new_blk);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301431
1432 /* Add it to block move list */
1433 retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv);
1434 if (retval)
1435 goto err_out;
1436
1437 bmv->old_loc = blk;
1438 bmv->new_loc = new_blk;
1439
1440 list_add(&(bmv->list), &blk_move_list);
1441
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -04001442 retval = io_channel_read_blk64(fs->io, blk, 1, buf);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301443 if (retval)
1444 goto err_out;
1445
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -04001446 retval = io_channel_write_blk64(fs->io, new_blk, 1, buf);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301447 if (retval)
1448 goto err_out;
1449 }
1450
1451err_out:
1452 ext2fs_free_mem(&buf);
1453 return retval;
1454}
1455
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001456static blk64_t translate_block(blk64_t blk)
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301457{
1458 struct list_head *entry;
1459 struct blk_move *bmv;
1460
1461 list_for_each(entry, &blk_move_list) {
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301462 bmv = list_entry(entry, struct blk_move, list);
1463 if (bmv->old_loc == blk)
1464 return bmv->new_loc;
1465 }
1466
1467 return 0;
1468}
1469
Theodore Ts'o721b3672008-06-07 11:51:33 -04001470static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)),
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001471 blk64_t *block_nr,
Theodore Ts'o721b3672008-06-07 11:51:33 -04001472 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001473 blk64_t ref_block EXT2FS_ATTR((unused)),
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301474 int ref_offset EXT2FS_ATTR((unused)),
Theodore Ts'o27c6de42008-11-15 00:32:39 -05001475 void *priv_data)
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301476{
1477 int ret = 0;
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001478 blk64_t new_blk;
Theodore Ts'o27c6de42008-11-15 00:32:39 -05001479 ext2fs_block_bitmap bmap = (ext2fs_block_bitmap) priv_data;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301480
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001481 if (!ext2fs_test_block_bitmap2(bmap, *block_nr))
Theodore Ts'o27c6de42008-11-15 00:32:39 -05001482 return 0;
Theodore Ts'oec43da22009-01-20 02:34:39 -05001483 new_blk = translate_block(*block_nr);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301484 if (new_blk) {
1485 *block_nr = new_blk;
1486 /*
1487 * This will force the ext2fs_write_inode in the iterator
1488 */
1489 ret |= BLOCK_CHANGED;
1490 }
1491
1492 return ret;
1493}
1494
Theodore Ts'o27c6de42008-11-15 00:32:39 -05001495static int inode_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301496{
1497 errcode_t retval = 0;
1498 ext2_ino_t ino;
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001499 blk64_t blk;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301500 char *block_buf = 0;
1501 struct ext2_inode inode;
1502 ext2_inode_scan scan = NULL;
1503
1504 retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf);
1505 if (retval)
1506 return retval;
1507
1508 retval = ext2fs_open_inode_scan(fs, 0, &scan);
1509 if (retval)
1510 goto err_out;
1511
1512 while (1) {
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301513 retval = ext2fs_get_next_inode(scan, &ino, &inode);
1514 if (retval)
1515 goto err_out;
1516
1517 if (!ino)
1518 break;
1519
1520 if (inode.i_links_count == 0)
1521 continue; /* inode not in use */
1522
1523 /* FIXME!!
1524 * If we end up modifying the journal inode
1525 * the sb->s_jnl_blocks will differ. But a
1526 * subsequent e2fsck fixes that.
1527 * Do we need to fix this ??
1528 */
1529
Theodore Ts'o0c80c442011-10-16 20:29:00 -04001530 if (ext2fs_file_acl_block(fs, &inode) &&
Valerie Aurora Hensona63745e2009-09-07 22:29:45 -04001531 ext2fs_test_block_bitmap2(bmap,
Theodore Ts'o0c80c442011-10-16 20:29:00 -04001532 ext2fs_file_acl_block(fs, &inode))) {
1533 blk = translate_block(ext2fs_file_acl_block(fs,
1534 &inode));
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301535 if (!blk)
1536 continue;
1537
Theodore Ts'o0c80c442011-10-16 20:29:00 -04001538 ext2fs_file_acl_block_set(fs, &inode, blk);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301539
1540 /*
1541 * Write the inode to disk so that inode table
1542 * resizing can work
1543 */
1544 retval = ext2fs_write_inode(fs, ino, &inode);
1545 if (retval)
1546 goto err_out;
1547 }
1548
Theodore Ts'o0c80c442011-10-16 20:29:00 -04001549 if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301550 continue;
1551
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001552 retval = ext2fs_block_iterate3(fs, ino, 0, block_buf,
Theodore Ts'o27c6de42008-11-15 00:32:39 -05001553 process_block, bmap);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301554 if (retval)
1555 goto err_out;
1556
1557 }
1558
1559err_out:
1560 ext2fs_free_mem(&block_buf);
1561
1562 return retval;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301563}
1564
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301565/*
1566 * We need to scan for inode and block bitmaps that may need to be
1567 * moved. This can take place if the filesystem was formatted for
1568 * RAID arrays using the mke2fs's extended option "stride".
1569 */
1570static int group_desc_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
1571{
1572 dgrp_t i;
Darrick J. Wong4dbfd792013-10-07 09:51:48 -04001573 blk64_t blk, new_blk;
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301574
1575 for (i = 0; i < fs->group_desc_count; i++) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001576 blk = ext2fs_block_bitmap_loc(fs, i);
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001577 if (ext2fs_test_block_bitmap2(bmap, blk)) {
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301578 new_blk = translate_block(blk);
1579 if (!new_blk)
1580 continue;
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001581 ext2fs_block_bitmap_loc_set(fs, i, new_blk);
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301582 }
1583
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001584 blk = ext2fs_inode_bitmap_loc(fs, i);
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001585 if (ext2fs_test_block_bitmap2(bmap, blk)) {
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301586 new_blk = translate_block(blk);
1587 if (!new_blk)
1588 continue;
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001589 ext2fs_inode_bitmap_loc_set(fs, i, new_blk);
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301590 }
1591 }
1592 return 0;
1593}
1594
Theodore Ts'o721b3672008-06-07 11:51:33 -04001595static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size)
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301596{
1597 dgrp_t i;
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001598 blk64_t blk;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301599 errcode_t retval;
Theodore Ts'o721b3672008-06-07 11:51:33 -04001600 int new_ino_blks_per_grp;
1601 unsigned int j;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301602 char *old_itable = NULL, *new_itable = NULL;
1603 char *tmp_old_itable = NULL, *tmp_new_itable = NULL;
Theodore Ts'o721b3672008-06-07 11:51:33 -04001604 unsigned long old_ino_size;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301605 int old_itable_size, new_itable_size;
1606
1607 old_itable_size = fs->inode_blocks_per_group * fs->blocksize;
Theodore Ts'o721b3672008-06-07 11:51:33 -04001608 old_ino_size = EXT2_INODE_SIZE(fs->super);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301609
1610 new_ino_blks_per_grp = ext2fs_div_ceil(
1611 EXT2_INODES_PER_GROUP(fs->super) *
Theodore Ts'o721b3672008-06-07 11:51:33 -04001612 new_ino_size,
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301613 fs->blocksize);
1614
1615 new_itable_size = new_ino_blks_per_grp * fs->blocksize;
1616
1617 retval = ext2fs_get_mem(old_itable_size, &old_itable);
1618 if (retval)
1619 return retval;
1620
1621 retval = ext2fs_get_mem(new_itable_size, &new_itable);
1622 if (retval)
1623 goto err_out;
1624
1625 tmp_old_itable = old_itable;
1626 tmp_new_itable = new_itable;
1627
1628 for (i = 0; i < fs->group_desc_count; i++) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001629 blk = ext2fs_inode_table_loc(fs, i);
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -04001630 retval = io_channel_read_blk64(fs->io, blk,
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301631 fs->inode_blocks_per_group, old_itable);
1632 if (retval)
1633 goto err_out;
1634
1635 for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) {
Theodore Ts'o721b3672008-06-07 11:51:33 -04001636 memcpy(new_itable, old_itable, old_ino_size);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301637
Theodore Ts'o721b3672008-06-07 11:51:33 -04001638 memset(new_itable+old_ino_size, 0,
1639 new_ino_size - old_ino_size);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301640
Theodore Ts'o721b3672008-06-07 11:51:33 -04001641 new_itable += new_ino_size;
1642 old_itable += old_ino_size;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301643 }
1644
1645 /* reset the pointer */
1646 old_itable = tmp_old_itable;
1647 new_itable = tmp_new_itable;
1648
Valerie Aurora Henson24a117a2009-09-07 21:14:24 -04001649 retval = io_channel_write_blk64(fs->io, blk,
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301650 new_ino_blks_per_grp, new_itable);
1651 if (retval)
1652 goto err_out;
1653 }
1654
1655 /* Update the meta data */
1656 fs->inode_blocks_per_group = new_ino_blks_per_grp;
Theodore Ts'o721b3672008-06-07 11:51:33 -04001657 fs->super->s_inode_size = new_ino_size;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301658
1659err_out:
1660 if (old_itable)
1661 ext2fs_free_mem(&old_itable);
1662
1663 if (new_itable)
1664 ext2fs_free_mem(&new_itable);
1665
1666 return retval;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301667}
1668
1669static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
1670{
Valerie Aurora Henson7117f8d2010-06-13 16:00:00 -04001671 blk64_t blk;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301672 ext2_ino_t ino;
1673 unsigned int group = 0;
1674 unsigned int count = 0;
1675 int total_free = 0;
1676 int group_free = 0;
1677
1678 /*
1679 * First calculate the block statistics
1680 */
1681 for (blk = fs->super->s_first_data_block;
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04001682 blk < ext2fs_blocks_count(fs->super); blk++) {
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001683 if (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk)) {
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301684 group_free++;
1685 total_free++;
1686 }
1687 count++;
1688 if ((count == fs->super->s_blocks_per_group) ||
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04001689 (blk == ext2fs_blocks_count(fs->super)-1)) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001690 ext2fs_bg_free_blocks_count_set(fs, group++,
1691 group_free);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301692 count = 0;
1693 group_free = 0;
1694 }
1695 }
Theodore Ts'ofe75afb2011-06-16 01:38:43 -04001696 total_free = EXT2FS_C2B(fs, total_free);
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04001697 ext2fs_free_blocks_count_set(fs->super, total_free);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301698
1699 /*
1700 * Next, calculate the inode statistics
1701 */
1702 group_free = 0;
1703 total_free = 0;
1704 count = 0;
1705 group = 0;
1706
1707 /* Protect loop from wrap-around if s_inodes_count maxed */
1708 for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
Valerie Aurora Henson3c041a52009-08-22 21:15:30 -04001709 if (!ext2fs_fast_test_inode_bitmap2(fs->inode_map, ino)) {
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301710 group_free++;
1711 total_free++;
1712 }
1713 count++;
1714 if ((count == fs->super->s_inodes_per_group) ||
1715 (ino == fs->super->s_inodes_count)) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -04001716 ext2fs_bg_free_inodes_count_set(fs, group++,
1717 group_free);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301718 count = 0;
1719 group_free = 0;
1720 }
1721 }
1722 fs->super->s_free_inodes_count = total_free;
1723 ext2fs_mark_super_dirty(fs);
1724 return 0;
1725}
1726
1727#define list_for_each_safe(pos, pnext, head) \
1728 for (pos = (head)->next, pnext = pos->next; pos != (head); \
1729 pos = pnext, pnext = pos->next)
1730
Theodore Ts'o721b3672008-06-07 11:51:33 -04001731static void free_blk_move_list(void)
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301732{
1733 struct list_head *entry, *tmp;
1734 struct blk_move *bmv;
1735
1736 list_for_each_safe(entry, tmp, &blk_move_list) {
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301737 bmv = list_entry(entry, struct blk_move, list);
1738 list_del(entry);
1739 ext2fs_free_mem(&bmv);
1740 }
Theodore Ts'o31f18152009-01-20 11:49:17 -05001741 return;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301742}
Theodore Ts'o721b3672008-06-07 11:51:33 -04001743
1744static int resize_inode(ext2_filsys fs, unsigned long new_size)
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301745{
1746 errcode_t retval;
1747 int new_ino_blks_per_grp;
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301748 ext2fs_block_bitmap bmap;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301749
Eric Sandeenc3ecabe2011-09-16 15:49:37 -05001750 retval = ext2fs_read_inode_bitmap(fs);
1751 if (retval) {
1752 fputs(_("Failed to read inode bitmap\n"), stderr);
1753 return retval;
1754 }
1755 retval = ext2fs_read_block_bitmap(fs);
1756 if (retval) {
Theodore Ts'o3fcd8fe2011-10-09 17:08:47 -04001757 fputs(_("Failed to read block bitmap\n"), stderr);
Eric Sandeenc3ecabe2011-09-16 15:49:37 -05001758 return retval;
1759 }
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301760 INIT_LIST_HEAD(&blk_move_list);
1761
1762
1763 new_ino_blks_per_grp = ext2fs_div_ceil(
1764 EXT2_INODES_PER_GROUP(fs->super)*
Theodore Ts'o721b3672008-06-07 11:51:33 -04001765 new_size,
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301766 fs->blocksize);
1767
1768 /* We may change the file system.
1769 * Mark the file system as invalid so that
1770 * the user is prompted to run fsck.
1771 */
1772 fs->super->s_state &= ~EXT2_VALID_FS;
1773
1774 retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
1775 &bmap);
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301776 if (retval) {
1777 fputs(_("Failed to allocate block bitmap when "
1778 "increasing inode size\n"), stderr);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301779 return retval;
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301780 }
1781 retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap);
1782 if (retval) {
1783 fputs(_("Not enough space to increase inode size \n"), stderr);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301784 goto err_out;
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301785 }
1786 retval = move_block(fs, bmap);
1787 if (retval) {
1788 fputs(_("Failed to relocate blocks during inode resize \n"),
1789 stderr);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301790 goto err_out;
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301791 }
Theodore Ts'o27c6de42008-11-15 00:32:39 -05001792 retval = inode_scan_and_fix(fs, bmap);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301793 if (retval)
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301794 goto err_out_undo;
Theodore Ts'o31f18152009-01-20 11:49:17 -05001795
Aneesh Kumar K.V91fac972009-08-06 11:42:30 +05301796 retval = group_desc_scan_and_fix(fs, bmap);
1797 if (retval)
1798 goto err_out_undo;
1799
Theodore Ts'o721b3672008-06-07 11:51:33 -04001800 retval = expand_inode_table(fs, new_size);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301801 if (retval)
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301802 goto err_out_undo;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301803
1804 ext2fs_calculate_summary_stats(fs);
1805
1806 fs->super->s_state |= EXT2_VALID_FS;
1807 /* mark super block and block bitmap as dirty */
1808 ext2fs_mark_super_dirty(fs);
1809 ext2fs_mark_bb_dirty(fs);
1810
1811err_out:
1812 free_blk_move_list();
1813 ext2fs_free_block_bitmap(bmap);
1814
1815 return retval;
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05301816
1817err_out_undo:
1818 free_blk_move_list();
1819 ext2fs_free_block_bitmap(bmap);
1820 fputs(_("Error in resizing the inode size.\n"
1821 "Run e2undo to undo the "
1822 "file system changes. \n"), stderr);
1823
1824 return retval;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301825}
1826
1827static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
1828{
1829 errcode_t retval = 0;
Theodore Ts'o721b3672008-06-07 11:51:33 -04001830 const char *tdb_dir;
Theodore Ts'of203bbd2009-04-18 10:53:32 -04001831 char *tdb_file;
Theodore Ts'o721b3672008-06-07 11:51:33 -04001832 char *dev_name, *tmp_name;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301833
1834#if 0 /* FIXME!! */
1835 /*
1836 * Configuration via a conf file would be
1837 * nice
1838 */
1839 profile_get_string(profile, "scratch_files",
1840 "directory", 0, 0,
1841 &tdb_dir);
1842#endif
1843 tmp_name = strdup(name);
Theodore Ts'of203bbd2009-04-18 10:53:32 -04001844 if (!tmp_name) {
1845 alloc_fn_fail:
Andreas Dilger45ff69f2013-12-15 22:11:40 -05001846 com_err(program_name, ENOMEM, "%s",
Theodore Ts'of203bbd2009-04-18 10:53:32 -04001847 _("Couldn't allocate memory for tdb filename\n"));
1848 return ENOMEM;
1849 }
Theodore Ts'o721b3672008-06-07 11:51:33 -04001850 dev_name = basename(tmp_name);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301851
1852 tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
1853 if (!tdb_dir)
Theodore Ts'oec43da22009-01-20 02:34:39 -05001854 tdb_dir = "/var/lib/e2fsprogs";
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301855
1856 if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) ||
1857 access(tdb_dir, W_OK))
1858 return 0;
1859
Theodore Ts'of203bbd2009-04-18 10:53:32 -04001860 tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1);
1861 if (!tdb_file)
1862 goto alloc_fn_fail;
Theodore Ts'o721b3672008-06-07 11:51:33 -04001863 sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301864
Theodore Ts'o250bf9a2014-01-10 21:39:27 -05001865 if ((unlink(tdb_file) < 0) && (errno != ENOENT)) {
1866 retval = errno;
1867 com_err(program_name, retval,
1868 _("while trying to delete %s"), tdb_file);
1869 free(tdb_file);
1870 return retval;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301871 }
1872
1873 set_undo_io_backing_manager(*io_ptr);
1874 *io_ptr = undo_io_manager;
1875 set_undo_io_backup_file(tdb_file);
Theodore Ts'o5bf81ba2009-01-20 01:50:07 -05001876 printf(_("To undo the tune2fs operation please run "
Benno Schulenberg577b5c42008-07-17 23:24:09 +02001877 "the command\n e2undo %s %s\n\n"),
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301878 tdb_file, name);
Theodore Ts'of203bbd2009-04-18 10:53:32 -04001879 free(tdb_file);
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301880 free(tmp_name);
1881 return retval;
1882}
Theodore Ts'o83238152001-01-09 00:16:26 +00001883
Theodore Ts'oec43da22009-01-20 02:34:39 -05001884int main(int argc, char **argv)
Theodore Ts'o83238152001-01-09 00:16:26 +00001885{
1886 errcode_t retval;
1887 ext2_filsys fs;
1888 struct ext2_super_block *sb;
Theodore Ts'od887f882008-07-27 16:00:48 -04001889 io_manager io_ptr, io_ptr_orig = NULL;
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001890 int rc = 0;
Theodore Ts'o83238152001-01-09 00:16:26 +00001891
1892#ifdef ENABLE_NLS
1893 setlocale(LC_MESSAGES, "");
Theodore Ts'o14308a52002-03-05 03:26:52 -05001894 setlocale(LC_CTYPE, "");
Theodore Ts'o83238152001-01-09 00:16:26 +00001895 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
1896 textdomain(NLS_CAT_NAME);
Theodore Ts'o9d4507c2011-10-05 01:00:30 -04001897 set_com_err_gettext(gettext);
Theodore Ts'o83238152001-01-09 00:16:26 +00001898#endif
1899 if (argc && *argv)
1900 program_name = *argv;
Theodore Ts'oa6d83022006-12-26 03:38:07 -05001901 add_error_table(&et_ext2_error_table);
Theodore Ts'o83238152001-01-09 00:16:26 +00001902
Theodore Ts'o14b596d2009-04-22 09:18:30 -04001903#ifdef CONFIG_BUILD_FINDFS
Theodore Ts'o118d7da2002-08-17 23:01:22 -04001904 if (strcmp(get_progname(argv[0]), "findfs") == 0)
1905 do_findfs(argc, argv);
Theodore Ts'o14b596d2009-04-22 09:18:30 -04001906#endif
Theodore Ts'o83238152001-01-09 00:16:26 +00001907 if (strcmp(get_progname(argv[0]), "e2label") == 0)
1908 parse_e2label_options(argc, argv);
1909 else
1910 parse_tune2fs_options(argc, argv);
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001911
Theodore Ts'o2a29f132003-05-05 12:08:47 -04001912#ifdef CONFIG_TESTIO_DEBUG
Theodore Ts'of38cf3c2008-09-01 11:17:29 -04001913 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_DEBUG")) {
1914 io_ptr = test_io_manager;
1915 test_io_backing_manager = unix_io_manager;
1916 } else
Theodore Ts'o2a29f132003-05-05 12:08:47 -04001917#endif
Theodore Ts'of38cf3c2008-09-01 11:17:29 -04001918 io_ptr = unix_io_manager;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05301919
Theodore Ts'od887f882008-07-27 16:00:48 -04001920retry_open:
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001921 if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag)
1922 open_flag |= EXT2_FLAG_SKIP_MMP;
1923
1924 open_flag |= EXT2_FLAG_64BITS;
1925
1926 /* keep the filesystem struct around to dump MMP data */
1927 open_flag |= EXT2_FLAG_NOFREE_ON_ERROR;
1928
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001929 retval = ext2fs_open2(device_name, io_options, open_flag,
Theodore Ts'o2e8ca9a2004-11-30 14:07:11 -05001930 0, 0, io_ptr, &fs);
Theodore Ts'oec43da22009-01-20 02:34:39 -05001931 if (retval) {
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001932 com_err(program_name, retval,
1933 _("while trying to open %s"),
Theodore Ts'oec43da22009-01-20 02:34:39 -05001934 device_name);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001935 if (retval == EXT2_ET_MMP_FSCK_ON ||
1936 retval == EXT2_ET_MMP_UNKNOWN_SEQ)
1937 dump_mmp_msg(fs->mmp_buf,
1938 _("If you are sure the filesystem "
1939 "is not in use on any node, run:\n"
1940 "'tune2fs -f -E clear_mmp {device}'\n"));
1941 else if (retval == EXT2_ET_MMP_FAILED)
1942 dump_mmp_msg(fs->mmp_buf, NULL);
1943 else if (retval == EXT2_ET_MMP_MAGIC_INVALID)
1944 fprintf(stderr,
1945 _("MMP block magic is bad. Try to fix it by "
1946 "running:\n'e2fsck -f %s'\n"), device_name);
1947 else if (retval != EXT2_ET_MMP_FAILED)
Andreas Dilger45ff69f2013-12-15 22:11:40 -05001948 fprintf(stderr, "%s",
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001949 _("Couldn't find valid filesystem superblock.\n"));
1950
1951 ext2fs_free(fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001952 exit(1);
1953 }
Theodore Ts'o24dea552012-03-15 16:39:56 -04001954 fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
Theodore Ts'od887f882008-07-27 16:00:48 -04001955
1956 if (I_flag && !io_ptr_orig) {
1957 /*
1958 * Check the inode size is right so we can issue an
1959 * error message and bail before setting up the tdb
1960 * file.
1961 */
1962 if (new_inode_size == EXT2_INODE_SIZE(fs->super)) {
Theodore Ts'o9266fc72009-04-22 15:13:37 -04001963 fprintf(stderr, _("The inode size is already %lu\n"),
Theodore Ts'od887f882008-07-27 16:00:48 -04001964 new_inode_size);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001965 rc = 1;
1966 goto closefs;
Theodore Ts'od887f882008-07-27 16:00:48 -04001967 }
1968 if (new_inode_size < EXT2_INODE_SIZE(fs->super)) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -05001969 fprintf(stderr, "%s",
1970 _("Shrinking inode size is not supported\n"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001971 rc = 1;
1972 goto closefs;
Theodore Ts'od887f882008-07-27 16:00:48 -04001973 }
Akira Fujitafab0d282013-04-21 23:14:28 -04001974 if (new_inode_size > fs->blocksize) {
1975 fprintf(stderr, _("Invalid inode size %lu (max %d)\n"),
1976 new_inode_size, fs->blocksize);
1977 rc = 1;
1978 goto closefs;
1979 }
Theodore Ts'od887f882008-07-27 16:00:48 -04001980
1981 /*
1982 * If inode resize is requested use the
1983 * Undo I/O manager
1984 */
1985 io_ptr_orig = io_ptr;
1986 retval = tune2fs_setup_tdb(device_name, &io_ptr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04001987 if (retval) {
1988 rc = 1;
1989 goto closefs;
1990 }
Theodore Ts'od887f882008-07-27 16:00:48 -04001991 if (io_ptr != io_ptr_orig) {
1992 ext2fs_close(fs);
1993 goto retry_open;
1994 }
1995 }
1996
Theodore Ts'o83238152001-01-09 00:16:26 +00001997 sb = fs->super;
Theodore Ts'o058ad1c2007-06-18 18:26:50 -04001998 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
Theodore Ts'o2be8fe42008-07-10 10:49:59 -04001999
Theodore Ts'o83238152001-01-09 00:16:26 +00002000 if (print_label) {
2001 /* For e2label emulation */
Theodore Ts'oc8c071a2001-01-11 16:08:23 +00002002 printf("%.*s\n", (int) sizeof(sb->s_volume_name),
2003 sb->s_volume_name);
Theodore Ts'oa6d83022006-12-26 03:38:07 -05002004 remove_error_table(&et_ext2_error_table);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002005 goto closefs;
Theodore Ts'o83238152001-01-09 00:16:26 +00002006 }
Theodore Ts'o2be8fe42008-07-10 10:49:59 -04002007
Theodore Ts'od06863f2004-04-12 12:37:55 -04002008 retval = ext2fs_check_if_mounted(device_name, &mount_flags);
2009 if (retval) {
2010 com_err("ext2fs_check_if_mount", retval,
2011 _("while determining whether %s is mounted."),
2012 device_name);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002013 rc = 1;
2014 goto closefs;
Theodore Ts'ob21e38a2001-01-01 15:26:58 +00002015 }
Theodore Ts'o63985322001-01-03 17:02:13 +00002016 /* Normally we only need to write out the superblock */
2017 fs->flags |= EXT2_FLAG_SUPER_ONLY;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002018
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002019 if (c_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +00002020 sb->s_max_mnt_count = max_mount_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002021 ext2fs_mark_super_dirty(fs);
Theodore Ts'oec43da22009-01-20 02:34:39 -05002022 printf(_("Setting maximal mount count to %d\n"),
2023 max_mount_count);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002024 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002025 if (C_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +00002026 sb->s_mnt_count = mount_count;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002027 ext2fs_mark_super_dirty(fs);
Theodore Ts'oec43da22009-01-20 02:34:39 -05002028 printf(_("Setting current mount count to %d\n"), mount_count);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002029 }
2030 if (e_flag) {
Theodore Ts'ob21e38a2001-01-01 15:26:58 +00002031 sb->s_errors = errors;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002032 ext2fs_mark_super_dirty(fs);
Theodore Ts'oec43da22009-01-20 02:34:39 -05002033 printf(_("Setting error behavior to %d\n"), errors);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002034 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +00002035 if (g_flag) {
2036 sb->s_def_resgid = resgid;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002037 ext2fs_mark_super_dirty(fs);
Theodore Ts'oec43da22009-01-20 02:34:39 -05002038 printf(_("Setting reserved blocks gid to %lu\n"), resgid);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002039 }
Theodore Ts'o818180c1998-06-27 05:11:14 +00002040 if (i_flag) {
Kazuya Mio2972b162011-04-18 20:11:39 +00002041 if (interval >= (1ULL << 32)) {
2042 com_err(program_name, 0,
2043 _("interval between checks is too big (%lu)"),
2044 interval);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002045 rc = 1;
2046 goto closefs;
Kazuya Mio2972b162011-04-18 20:11:39 +00002047 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +00002048 sb->s_checkinterval = interval;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002049 ext2fs_mark_super_dirty(fs);
Theodore Ts'oec43da22009-01-20 02:34:39 -05002050 printf(_("Setting interval between checks to %lu seconds\n"),
2051 interval);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002052 }
Theodore Ts'o818180c1998-06-27 05:11:14 +00002053 if (m_flag) {
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04002054 ext2fs_r_blocks_count_set(sb, reserved_ratio *
2055 ext2fs_blocks_count(sb) / 100.0);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002056 ext2fs_mark_super_dirty(fs);
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04002057 printf (_("Setting reserved blocks percentage to %g%% (%llu blocks)\n"),
2058 reserved_ratio, ext2fs_r_blocks_count(sb));
Theodore Ts'o3839e651997-04-26 13:21:57 +00002059 }
Theodore Ts'o818180c1998-06-27 05:11:14 +00002060 if (r_flag) {
Theodore Ts'o3977a4f2011-05-31 20:08:58 -04002061 if (reserved_blocks > ext2fs_blocks_count(sb)/2) {
Theodore Ts'oec43da22009-01-20 02:34:39 -05002062 com_err(program_name, 0,
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04002063 _("reserved blocks count is too big (%llu)"),
Theodore Ts'oec43da22009-01-20 02:34:39 -05002064 reserved_blocks);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002065 rc = 1;
2066 goto closefs;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002067 }
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04002068 ext2fs_r_blocks_count_set(sb, reserved_blocks);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002069 ext2fs_mark_super_dirty(fs);
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -04002070 printf(_("Setting reserved blocks count to %llu\n"),
Theodore Ts'oec43da22009-01-20 02:34:39 -05002071 reserved_blocks);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002072 }
Theodore Ts'o521e3681997-04-29 17:48:10 +00002073 if (s_flag == 1) {
Theodore Ts'o521e3681997-04-29 17:48:10 +00002074 if (sb->s_feature_ro_compat &
2075 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
Theodore Ts'o54434922003-12-07 01:28:50 -05002076 fputs(_("\nThe filesystem already has sparse "
2077 "superblocks.\n"), stderr);
Theodore Ts'o521e3681997-04-29 17:48:10 +00002078 else {
2079 sb->s_feature_ro_compat |=
2080 EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER;
Theodore Ts'ob21e38a2001-01-01 15:26:58 +00002081 sb->s_state &= ~EXT2_VALID_FS;
Theodore Ts'o521e3681997-04-29 17:48:10 +00002082 ext2fs_mark_super_dirty(fs);
Theodore Ts'od9c56d32000-02-08 00:47:55 +00002083 printf(_("\nSparse superblock flag set. %s"),
Theodore Ts'oa4fa1002000-02-08 21:35:41 +00002084 _(please_fsck));
Theodore Ts'o521e3681997-04-29 17:48:10 +00002085 }
Theodore Ts'o521e3681997-04-29 17:48:10 +00002086 }
2087 if (s_flag == 0) {
Theodore Ts'off662d52008-02-28 21:26:01 -05002088 fputs(_("\nClearing the sparse superflag not supported.\n"),
2089 stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002090 rc = 1;
2091 goto closefs;
Theodore Ts'o521e3681997-04-29 17:48:10 +00002092 }
Theodore Ts'od4de4aa2001-12-26 08:58:01 -05002093 if (T_flag) {
2094 sb->s_lastcheck = last_check_time;
2095 ext2fs_mark_super_dirty(fs);
2096 printf(_("Setting time filesystem last checked to %s\n"),
2097 ctime(&last_check_time));
2098 }
Theodore Ts'ob21e38a2001-01-01 15:26:58 +00002099 if (u_flag) {
2100 sb->s_def_resuid = resuid;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002101 ext2fs_mark_super_dirty(fs);
Theodore Ts'oec43da22009-01-20 02:34:39 -05002102 printf(_("Setting reserved blocks uid to %lu\n"), resuid);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002103 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002104 if (L_flag) {
Theodore Ts'oa789d841998-03-30 01:20:55 +00002105 if (strlen(new_label) > sizeof(sb->s_volume_name))
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002106 fputs(_("Warning: label too long, truncating.\n"),
Theodore Ts'o54434922003-12-07 01:28:50 -05002107 stderr);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002108 memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
2109 strncpy(sb->s_volume_name, new_label,
2110 sizeof(sb->s_volume_name));
2111 ext2fs_mark_super_dirty(fs);
2112 }
2113 if (M_flag) {
2114 memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
2115 strncpy(sb->s_last_mounted, new_last_mounted,
2116 sizeof(sb->s_last_mounted));
2117 ext2fs_mark_super_dirty(fs);
2118 }
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002119 if (mntopts_cmd) {
2120 rc = update_mntopts(fs, mntopts_cmd);
2121 if (rc)
2122 goto closefs;
2123 }
2124 if (features_cmd) {
2125 rc = update_feature_set(fs, features_cmd);
2126 if (rc)
2127 goto closefs;
2128 }
2129 if (extended_cmd) {
2130 rc = parse_extended_opts(fs, extended_cmd);
2131 if (rc)
2132 goto closefs;
2133 if (clear_mmp && !f_flag) {
2134 fputs(_("Error in using clear_mmp. "
2135 "It must be used with -f\n"),
2136 stderr);
2137 goto closefs;
2138 }
2139 }
2140 if (clear_mmp) {
2141 rc = ext2fs_mmp_clear(fs);
2142 goto closefs;
2143 }
2144 if (journal_size || journal_device) {
2145 rc = add_journal(fs);
2146 if (rc)
2147 goto closefs;
2148 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002149
Aditya Kali771e8db2011-07-20 11:40:05 -07002150 if (Q_flag) {
2151 if (mount_flags & EXT2_MF_MOUNTED) {
2152 fputs(_("The quota feature may only be changed when "
2153 "the filesystem is unmounted.\n"), stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002154 rc = 1;
2155 goto closefs;
Aditya Kali771e8db2011-07-20 11:40:05 -07002156 }
2157 handle_quota_options(fs);
2158 }
2159
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002160 if (U_flag) {
Theodore Ts'o9d4a4dc2008-11-14 17:42:27 -05002161 int set_csum = 0;
2162 dgrp_t i;
2163
2164 if (sb->s_feature_ro_compat &
2165 EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
Theodore Ts'oec43da22009-01-20 02:34:39 -05002166 /*
Darrick J. Wong66457fc2013-12-14 20:51:04 -05002167 * Changing the UUID requires rewriting all metadata,
2168 * which can race with a mounted fs. Don't allow that.
2169 */
2170 if (mount_flags & EXT2_MF_MOUNTED) {
2171 fputs(_("The UUID may only be "
2172 "changed when the filesystem is "
2173 "unmounted.\n"), stderr);
2174 exit(1);
2175 }
2176 if (check_fsck_needed(fs))
2177 exit(1);
2178
2179 /*
Theodore Ts'o9d4a4dc2008-11-14 17:42:27 -05002180 * Determine if the block group checksums are
2181 * correct so we know whether or not to set
2182 * them later on.
2183 */
2184 for (i = 0; i < fs->group_desc_count; i++)
2185 if (!ext2fs_group_desc_csum_verify(fs, i))
2186 break;
2187 if (i >= fs->group_desc_count)
2188 set_csum = 1;
2189 }
Theodore Ts'o4d0f2282001-04-23 20:58:03 +00002190 if ((strcasecmp(new_UUID, "null") == 0) ||
2191 (strcasecmp(new_UUID, "clear") == 0)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002192 uuid_clear(sb->s_uuid);
Theodore Ts'o63985322001-01-03 17:02:13 +00002193 } else if (strcasecmp(new_UUID, "time") == 0) {
2194 uuid_generate_time(sb->s_uuid);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002195 } else if (strcasecmp(new_UUID, "random") == 0) {
2196 uuid_generate(sb->s_uuid);
2197 } else if (uuid_parse(new_UUID, sb->s_uuid)) {
Andreas Dilger45ff69f2013-12-15 22:11:40 -05002198 com_err(program_name, 0, "%s",
2199 _("Invalid UUID format\n"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002200 rc = 1;
2201 goto closefs;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002202 }
Theodore Ts'o9d4a4dc2008-11-14 17:42:27 -05002203 if (set_csum) {
2204 for (i = 0; i < fs->group_desc_count; i++)
2205 ext2fs_group_desc_csum_set(fs, i);
2206 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
2207 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002208 ext2fs_mark_super_dirty(fs);
2209 }
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05302210 if (I_flag) {
2211 if (mount_flags & EXT2_MF_MOUNTED) {
2212 fputs(_("The inode size may only be "
2213 "changed when the filesystem is "
2214 "unmounted.\n"), stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002215 rc = 1;
2216 goto closefs;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05302217 }
Theodore Ts'o5bf81ba2009-01-20 01:50:07 -05002218 if (fs->super->s_feature_incompat &
2219 EXT4_FEATURE_INCOMPAT_FLEX_BG) {
Theodore Ts'oec43da22009-01-20 02:34:39 -05002220 fputs(_("Changing the inode size not supported for "
2221 "filesystems with the flex_bg\n"
2222 "feature enabled.\n"),
Theodore Ts'o5bf81ba2009-01-20 01:50:07 -05002223 stderr);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002224 rc = 1;
2225 goto closefs;
Theodore Ts'o5bf81ba2009-01-20 01:50:07 -05002226 }
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05302227 /*
2228 * We want to update group descriptor also
2229 * with the new free inode count
2230 */
2231 fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
Aneesh Kumar K.Va9e51772009-08-06 11:42:29 +05302232 if (resize_inode(fs, new_inode_size) == 0) {
Theodore Ts'oec43da22009-01-20 02:34:39 -05002233 printf(_("Setting inode size %lu\n"),
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05302234 new_inode_size);
Eric Sandeenc3ecabe2011-09-16 15:49:37 -05002235 } else {
Andreas Dilger45ff69f2013-12-15 22:11:40 -05002236 printf("%s", _("Failed to change inode size\n"));
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002237 rc = 1;
2238 goto closefs;
Aneesh Kumar K.V64d588c2007-08-13 15:56:24 +05302239 }
2240 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002241
Theodore Ts'o3839e651997-04-26 13:21:57 +00002242 if (l_flag)
Theodore Ts'oec43da22009-01-20 02:34:39 -05002243 list_super(sb);
Theodore Ts'o0c17cb22008-02-18 22:56:25 -05002244 if (stride_set) {
2245 sb->s_raid_stride = stride;
2246 ext2fs_mark_super_dirty(fs);
2247 printf(_("Setting stride size to %d\n"), stride);
2248 }
2249 if (stripe_width_set) {
2250 sb->s_raid_stripe_width = stripe_width;
2251 ext2fs_mark_super_dirty(fs);
2252 printf(_("Setting stripe width to %d\n"), stripe_width);
2253 }
Theodore Ts'o9a976ac2011-07-04 20:14:35 -04002254 if (ext_mount_opts) {
Andreas Dilger6b56f3d2011-09-24 12:59:31 -04002255 strncpy((char *)(fs->super->s_mount_opts), ext_mount_opts,
Theodore Ts'o9a976ac2011-07-04 20:14:35 -04002256 sizeof(fs->super->s_mount_opts));
2257 fs->super->s_mount_opts[sizeof(fs->super->s_mount_opts)-1] = 0;
2258 ext2fs_mark_super_dirty(fs);
2259 printf(_("Setting extended default mount options to '%s'\n"),
2260 ext_mount_opts);
2261 free(ext_mount_opts);
2262 }
Theodore Ts'o1acde2b2009-06-15 03:53:04 -04002263 free(device_name);
Theodore Ts'oa6d83022006-12-26 03:38:07 -05002264 remove_error_table(&et_ext2_error_table);
Andreas Dilger0f5eba72011-09-24 13:48:55 -04002265
2266closefs:
2267 if (rc) {
2268 ext2fs_mmp_stop(fs);
2269 exit(1);
2270 }
2271
Theodore Ts'oec43da22009-01-20 02:34:39 -05002272 return (ext2fs_close(fs) ? 1 : 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002273}