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