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