]>
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() */ |
b969b1b8 | 29 | #define _BSD_SOURCE /* for inclusion of strcasecmp() */ |
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 TT |
39 | #include <stdio.h> |
40 | #include <stdlib.h> | |
41 | #include <string.h> | |
42 | #include <time.h> | |
43 | #include <unistd.h> | |
f3db3566 | 44 | #include <sys/types.h> |
64d588cf | 45 | #include <libgen.h> |
36585791 | 46 | #include <limits.h> |
3839e657 | 47 | |
54c637d4 | 48 | #include "ext2fs/ext2_fs.h" |
3839e657 TT |
49 | #include "ext2fs/ext2fs.h" |
50 | #include "et/com_err.h" | |
1e3472c5 | 51 | #include "uuid/uuid.h" |
3839e657 | 52 | #include "e2p/e2p.h" |
dc2ec525 | 53 | #include "jfs_user.h" |
63985320 | 54 | #include "util.h" |
ed1b33e8 | 55 | #include "blkid/blkid.h" |
3839e657 TT |
56 | |
57 | #include "../version.h" | |
d9c56d3c | 58 | #include "nls-enable.h" |
3839e657 TT |
59 | |
60 | const char * program_name = "tune2fs"; | |
63985320 | 61 | char * device_name; |
c8c071a0 | 62 | char * new_label, *new_last_mounted, *new_UUID; |
2e8ca9a2 | 63 | char * io_options; |
4d0f2283 | 64 | static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag; |
d4de4aa9 | 65 | static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag; |
64d588cf | 66 | static int I_flag; |
d4de4aa9 | 67 | static time_t last_check_time; |
83238153 | 68 | static int print_label; |
63985320 | 69 | static int max_mount_count, mount_count, mount_flags; |
ce911145 AD |
70 | static unsigned long interval, reserved_blocks; |
71 | static double reserved_ratio; | |
63985320 TT |
72 | static unsigned long resgid, resuid; |
73 | static unsigned short errors; | |
83238153 TT |
74 | static int open_flag; |
75 | static char *features_cmd; | |
a0c3fd5e | 76 | static char *mntopts_cmd; |
0c17cb25 TT |
77 | static int stride, stripe_width; |
78 | static int stride_set, stripe_width_set; | |
6cb27404 | 79 | static char *extended_cmd; |
721b367a | 80 | static unsigned long new_inode_size; |
3839e657 | 81 | |
63985320 TT |
82 | int journal_size, journal_flags; |
83 | char *journal_device; | |
84 | ||
64d588cf AK |
85 | static struct list_head blk_move_list; |
86 | ||
87 | struct blk_move { | |
88 | struct list_head list; | |
89 | blk_t old_loc; | |
90 | blk_t new_loc; | |
91 | }; | |
92 | ||
93 | ||
63985320 | 94 | static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n"); |
1e3472c5 | 95 | |
3e699064 TT |
96 | void do_findfs(int argc, char **argv); |
97 | ||
818180cd | 98 | static void usage(void) |
3839e657 | 99 | { |
b21e38a0 | 100 | fprintf(stderr, |
bb145b01 | 101 | _("Usage: %s [-c max_mounts_count] [-e errors_behavior] " |
b21e38a0 | 102 | "[-g group]\n" |
ff662d5d TT |
103 | "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n" |
104 | "\t[-m reserved_blocks_percent] " | |
105 | "[-o [^]mount_options[,...]] \n" | |
106 | "\t[-r reserved_blocks_count] [-u user] [-C mount_count] " | |
107 | "[-L volume_label]\n" | |
6cb27404 TT |
108 | "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n" |
109 | "\t[-E extended-option[,...]] [-T last_check_time] " | |
64d588cf | 110 | "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name); |
3839e657 TT |
111 | exit (1); |
112 | } | |
113 | ||
896938d5 | 114 | static __u32 ok_features[3] = { |
558df544 | 115 | /* Compat */ |
843049c4 | 116 | EXT3_FEATURE_COMPAT_HAS_JOURNAL | |
558df544 TT |
117 | EXT2_FEATURE_COMPAT_DIR_INDEX, |
118 | /* Incompat */ | |
a49670e6 TT |
119 | EXT2_FEATURE_INCOMPAT_FILETYPE | |
120 | EXT3_FEATURE_INCOMPAT_EXTENTS | | |
c2d4300b | 121 | EXT4_FEATURE_INCOMPAT_FLEX_BG, |
558df544 TT |
122 | /* R/O compat */ |
123 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE | | |
2be8fe43 TT |
124 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE| |
125 | EXT4_FEATURE_RO_COMPAT_DIR_NLINK| | |
126 | EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| | |
4e988cb4 | 127 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM | |
558df544 | 128 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
896938d5 TT |
129 | }; |
130 | ||
7c4a2ef5 | 131 | static __u32 clear_ok_features[3] = { |
558df544 | 132 | /* Compat */ |
7c4a2ef5 | 133 | EXT3_FEATURE_COMPAT_HAS_JOURNAL | |
037914e2 | 134 | EXT2_FEATURE_COMPAT_RESIZE_INODE | |
558df544 TT |
135 | EXT2_FEATURE_COMPAT_DIR_INDEX, |
136 | /* Incompat */ | |
a49670e6 TT |
137 | EXT2_FEATURE_INCOMPAT_FILETYPE | |
138 | EXT4_FEATURE_INCOMPAT_FLEX_BG, | |
558df544 | 139 | /* R/O compat */ |
4e988cb4 | 140 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE | |
2be8fe43 TT |
141 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE| |
142 | EXT4_FEATURE_RO_COMPAT_DIR_NLINK| | |
143 | EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| | |
4e988cb4 | 144 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
896938d5 TT |
145 | }; |
146 | ||
dc2ec525 TT |
147 | /* |
148 | * Remove an external journal from the filesystem | |
149 | */ | |
150 | static void remove_journal_device(ext2_filsys fs) | |
151 | { | |
4ea7bd04 | 152 | char *journal_path; |
dc2ec525 TT |
153 | ext2_filsys jfs; |
154 | char buf[1024]; | |
155 | journal_superblock_t *jsb; | |
156 | int i, nr_users; | |
157 | errcode_t retval; | |
4d0f2283 | 158 | int commit_remove_journal = 0; |
2a29f135 | 159 | io_manager io_ptr; |
4d0f2283 TT |
160 | |
161 | if (f_flag) | |
162 | commit_remove_journal = 1; /* force removal even if error */ | |
dc2ec525 | 163 | |
2d15576d | 164 | uuid_unparse(fs->super->s_journal_uuid, buf); |
ed1b33e8 | 165 | journal_path = blkid_get_devname(NULL, "UUID", buf); |
2d15576d | 166 | |
4ea7bd04 TT |
167 | if (!journal_path) { |
168 | journal_path = | |
2d15576d | 169 | ext2fs_find_block_device(fs->super->s_journal_dev); |
4ea7bd04 | 170 | if (!journal_path) |
2d15576d AD |
171 | return; |
172 | } | |
dc2ec525 | 173 | |
2a29f135 TT |
174 | #ifdef CONFIG_TESTIO_DEBUG |
175 | io_ptr = test_io_manager; | |
176 | test_io_backing_manager = unix_io_manager; | |
177 | #else | |
178 | io_ptr = unix_io_manager; | |
179 | #endif | |
4ea7bd04 | 180 | retval = ext2fs_open(journal_path, EXT2_FLAG_RW| |
dc2ec525 | 181 | EXT2_FLAG_JOURNAL_DEV_OK, 0, |
2a29f135 | 182 | fs->blocksize, io_ptr, &jfs); |
dc2ec525 TT |
183 | if (retval) { |
184 | com_err(program_name, retval, | |
185 | _("while trying to open external journal")); | |
4d0f2283 | 186 | goto no_valid_journal; |
dc2ec525 TT |
187 | } |
188 | if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { | |
7141b54b | 189 | fprintf(stderr, _("%s is not a journal device.\n"), |
4ea7bd04 | 190 | journal_path); |
4d0f2283 | 191 | goto no_valid_journal; |
dc2ec525 TT |
192 | } |
193 | ||
194 | /* Get the journal superblock */ | |
195 | if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) { | |
196 | com_err(program_name, retval, | |
197 | _("while reading journal superblock")); | |
4d0f2283 | 198 | goto no_valid_journal; |
dc2ec525 TT |
199 | } |
200 | ||
201 | jsb = (journal_superblock_t *) buf; | |
202 | if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || | |
203 | (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) { | |
54434927 | 204 | fputs(_("Journal superblock not found!\n"), stderr); |
4d0f2283 | 205 | goto no_valid_journal; |
dc2ec525 TT |
206 | } |
207 | ||
208 | /* Find the filesystem UUID */ | |
209 | nr_users = ntohl(jsb->s_nr_users); | |
210 | for (i=0; i < nr_users; i++) { | |
211 | if (memcmp(fs->super->s_uuid, | |
212 | &jsb->s_users[i*16], 16) == 0) | |
213 | break; | |
214 | } | |
215 | if (i >= nr_users) { | |
efc6f628 | 216 | fputs(_("Filesystem's UUID not found on journal device.\n"), |
54434927 | 217 | stderr); |
4d0f2283 TT |
218 | commit_remove_journal = 1; |
219 | goto no_valid_journal; | |
dc2ec525 TT |
220 | } |
221 | nr_users--; | |
222 | for (i=0; i < nr_users; i++) | |
223 | memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16); | |
224 | jsb->s_nr_users = htonl(nr_users); | |
225 | ||
226 | /* Write back the journal superblock */ | |
227 | if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) { | |
228 | com_err(program_name, retval, | |
229 | "while writing journal superblock."); | |
4d0f2283 | 230 | goto no_valid_journal; |
dc2ec525 TT |
231 | } |
232 | ||
4d0f2283 TT |
233 | commit_remove_journal = 1; |
234 | ||
235 | no_valid_journal: | |
236 | if (commit_remove_journal == 0) { | |
54434927 | 237 | fputs(_("Journal NOT removed\n"), stderr); |
4d0f2283 TT |
238 | exit(1); |
239 | } | |
dc2ec525 | 240 | fs->super->s_journal_dev = 0; |
ed1b33e8 | 241 | uuid_clear(fs->super->s_journal_uuid); |
dc2ec525 | 242 | ext2fs_mark_super_dirty(fs); |
54434927 | 243 | fputs(_("Journal removed\n"), stdout); |
4ea7bd04 | 244 | free(journal_path); |
dc2ec525 TT |
245 | } |
246 | ||
194686bb TT |
247 | /* Helper function for remove_journal_inode */ |
248 | static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr, | |
efc6f628 | 249 | int blockcnt EXT2FS_ATTR((unused)), |
54434927 | 250 | void *private EXT2FS_ATTR((unused))) |
194686bb TT |
251 | { |
252 | blk_t block; | |
253 | int group; | |
254 | ||
255 | block = *blocknr; | |
256 | ext2fs_unmark_block_bitmap(fs->block_map,block); | |
257 | group = ext2fs_group_of_blk(fs, block); | |
258 | fs->group_desc[group].bg_free_blocks_count++; | |
4e988cb4 | 259 | ext2fs_group_desc_csum_set(fs, group); |
194686bb TT |
260 | fs->super->s_free_blocks_count++; |
261 | return 0; | |
262 | } | |
263 | ||
264 | /* | |
265 | * Remove the journal inode from the filesystem | |
266 | */ | |
267 | static void remove_journal_inode(ext2_filsys fs) | |
268 | { | |
269 | struct ext2_inode inode; | |
270 | errcode_t retval; | |
271 | ino_t ino = fs->super->s_journal_inum; | |
efc6f628 | 272 | |
194686bb TT |
273 | retval = ext2fs_read_inode(fs, ino, &inode); |
274 | if (retval) { | |
275 | com_err(program_name, retval, | |
276 | _("while reading journal inode")); | |
277 | exit(1); | |
278 | } | |
279 | if (ino == EXT2_JOURNAL_INO) { | |
280 | retval = ext2fs_read_bitmaps(fs); | |
281 | if (retval) { | |
282 | com_err(program_name, retval, | |
283 | _("while reading bitmaps")); | |
284 | exit(1); | |
285 | } | |
43323be9 TT |
286 | retval = ext2fs_block_iterate(fs, ino, |
287 | BLOCK_FLAG_READ_ONLY, NULL, | |
194686bb TT |
288 | release_blocks_proc, NULL); |
289 | if (retval) { | |
290 | com_err(program_name, retval, | |
291 | _("while clearing journal inode")); | |
292 | exit(1); | |
293 | } | |
294 | memset(&inode, 0, sizeof(inode)); | |
295 | ext2fs_mark_bb_dirty(fs); | |
194686bb TT |
296 | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; |
297 | } else | |
298 | inode.i_flags &= ~EXT2_IMMUTABLE_FL; | |
299 | retval = ext2fs_write_inode(fs, ino, &inode); | |
300 | if (retval) { | |
301 | com_err(program_name, retval, | |
302 | _("while writing journal inode")); | |
303 | exit(1); | |
304 | } | |
305 | fs->super->s_journal_inum = 0; | |
306 | ext2fs_mark_super_dirty(fs); | |
307 | } | |
dc2ec525 | 308 | |
a0c3fd5e TT |
309 | /* |
310 | * Update the default mount options | |
311 | */ | |
312 | static void update_mntopts(ext2_filsys fs, char *mntopts) | |
313 | { | |
314 | struct ext2_super_block *sb= fs->super; | |
315 | ||
316 | if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) { | |
317 | fprintf(stderr, _("Invalid mount option set: %s\n"), | |
318 | mntopts); | |
319 | exit(1); | |
320 | } | |
321 | ext2fs_mark_super_dirty(fs); | |
322 | } | |
323 | ||
63985320 TT |
324 | /* |
325 | * Update the feature set as provided by the user. | |
326 | */ | |
c8c071a0 | 327 | static void update_feature_set(ext2_filsys fs, char *features) |
63985320 | 328 | { |
63985320 | 329 | struct ext2_super_block *sb= fs->super; |
885bf6b8 | 330 | __u32 old_features[3]; |
7c4a2ef5 TT |
331 | int type_err; |
332 | unsigned int mask_err; | |
2eb3b20e | 333 | |
885bf6b8 TT |
334 | #define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \ |
335 | ((&sb->s_feature_compat)[(type)] & (mask))) | |
336 | #define FEATURE_OFF(type, mask) ((old_features[(type)] & (mask)) && \ | |
337 | !((&sb->s_feature_compat)[(type)] & (mask))) | |
338 | #define FEATURE_CHANGED(type, mask) ((mask) & \ | |
339 | (old_features[(type)] ^ (&sb->s_feature_compat)[(type)])) | |
340 | ||
341 | old_features[E2P_FEATURE_COMPAT] = sb->s_feature_compat; | |
342 | old_features[E2P_FEATURE_INCOMPAT] = sb->s_feature_incompat; | |
343 | old_features[E2P_FEATURE_RO_INCOMPAT] = sb->s_feature_ro_compat; | |
344 | ||
7c4a2ef5 TT |
345 | if (e2p_edit_feature2(features, &sb->s_feature_compat, |
346 | ok_features, clear_ok_features, | |
347 | &type_err, &mask_err)) { | |
348 | if (!mask_err) | |
349 | fprintf(stderr, | |
350 | _("Invalid filesystem option set: %s\n"), | |
351 | features); | |
352 | else if (type_err & E2P_FEATURE_NEGATE_FLAG) | |
353 | fprintf(stderr, _("Clearing filesystem feature '%s' " | |
354 | "not supported.\n"), | |
355 | e2p_feature2string(type_err & | |
356 | E2P_FEATURE_TYPE_MASK, | |
357 | mask_err)); | |
358 | else | |
359 | fprintf(stderr, _("Setting filesystem feature '%s' " | |
360 | "not supported.\n"), | |
361 | e2p_feature2string(type_err, mask_err)); | |
63985320 TT |
362 | exit(1); |
363 | } | |
885bf6b8 TT |
364 | |
365 | if (FEATURE_OFF(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { | |
63985320 TT |
366 | if ((mount_flags & EXT2_MF_MOUNTED) && |
367 | !(mount_flags & EXT2_MF_READONLY)) { | |
2be8fe43 | 368 | fputs(_("The has_journal feature may only be " |
54434927 TT |
369 | "cleared when the filesystem is\n" |
370 | "unmounted or mounted " | |
371 | "read-only.\n"), stderr); | |
63985320 TT |
372 | exit(1); |
373 | } | |
374 | if (sb->s_feature_incompat & | |
375 | EXT3_FEATURE_INCOMPAT_RECOVER) { | |
54434927 TT |
376 | fputs(_("The needs_recovery flag is set. " |
377 | "Please run e2fsck before clearing\n" | |
378 | "the has_journal flag.\n"), stderr); | |
63985320 TT |
379 | exit(1); |
380 | } | |
63985320 | 381 | if (sb->s_journal_inum) { |
194686bb | 382 | remove_journal_inode(fs); |
63985320 | 383 | } |
de49f015 | 384 | if (sb->s_journal_dev) { |
dc2ec525 | 385 | remove_journal_device(fs); |
de49f015 | 386 | } |
63985320 | 387 | } |
885bf6b8 TT |
388 | |
389 | if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { | |
63985320 TT |
390 | /* |
391 | * If adding a journal flag, let the create journal | |
7a0516a3 BS |
392 | * code below handle setting the flag and creating the |
393 | * journal. We supply a default size if necessary. | |
63985320 | 394 | */ |
dc2ec525 TT |
395 | if (!journal_size) |
396 | journal_size = -1; | |
08dd830d | 397 | sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
63985320 | 398 | } |
885bf6b8 TT |
399 | |
400 | if (FEATURE_ON(E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX)) { | |
843049c4 | 401 | if (!sb->s_def_hash_version) |
d1070d91 | 402 | sb->s_def_hash_version = EXT2_HASH_HALF_MD4; |
843049c4 TT |
403 | if (uuid_is_null((unsigned char *) sb->s_hash_seed)) |
404 | uuid_generate((unsigned char *) sb->s_hash_seed); | |
405 | } | |
dc2ec525 | 406 | |
a49670e6 | 407 | if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { |
c2d4300b JS |
408 | if (ext2fs_check_desc(fs)) { |
409 | fputs(_("Clearing the flex_bg flag would " | |
410 | "cause the the filesystem to be\n" | |
411 | "inconsistent.\n"), stderr); | |
412 | exit(1); | |
413 | } | |
414 | } | |
dc2ec525 | 415 | |
2be8fe43 TT |
416 | if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, |
417 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { | |
418 | if ((mount_flags & EXT2_MF_MOUNTED) && | |
419 | !(mount_flags & EXT2_MF_READONLY)) { | |
420 | fputs(_("The huge_file feature may only be " | |
421 | "cleared when the filesystem is\n" | |
422 | "unmounted or mounted " | |
423 | "read-only.\n"), stderr); | |
424 | exit(1); | |
425 | } | |
426 | } | |
427 | ||
63985320 TT |
428 | if (sb->s_rev_level == EXT2_GOOD_OLD_REV && |
429 | (sb->s_feature_compat || sb->s_feature_ro_compat || | |
430 | sb->s_feature_incompat)) | |
431 | ext2fs_update_dynamic_rev(fs); | |
885bf6b8 TT |
432 | |
433 | if (FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT, | |
434 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) || | |
4e988cb4 JS |
435 | FEATURE_CHANGED(E2P_FEATURE_RO_INCOMPAT, |
436 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM) || | |
2be8fe43 TT |
437 | FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, |
438 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || | |
885bf6b8 | 439 | FEATURE_CHANGED(E2P_FEATURE_INCOMPAT, |
037914e2 TT |
440 | EXT2_FEATURE_INCOMPAT_FILETYPE) || |
441 | FEATURE_CHANGED(E2P_FEATURE_COMPAT, | |
558df544 TT |
442 | EXT2_FEATURE_COMPAT_RESIZE_INODE) || |
443 | FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT, | |
444 | EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) { | |
63985320 TT |
445 | sb->s_state &= ~EXT2_VALID_FS; |
446 | printf("\n%s\n", _(please_fsck)); | |
2be8fe43 TT |
447 | if (mount_flags & EXT2_MF_READONLY) |
448 | printf(_("(and reboot afterwards!)\n")); | |
63985320 | 449 | } |
885bf6b8 TT |
450 | |
451 | if ((old_features[E2P_FEATURE_COMPAT] != sb->s_feature_compat) || | |
452 | (old_features[E2P_FEATURE_INCOMPAT] != sb->s_feature_incompat) || | |
453 | (old_features[E2P_FEATURE_RO_INCOMPAT] != sb->s_feature_ro_compat)) | |
2eb3b20e | 454 | ext2fs_mark_super_dirty(fs); |
63985320 TT |
455 | } |
456 | ||
457 | /* | |
458 | * Add a journal to the filesystem. | |
459 | */ | |
460 | static void add_journal(ext2_filsys fs) | |
461 | { | |
462 | unsigned long journal_blocks; | |
463 | errcode_t retval; | |
16ed5b3a | 464 | ext2_filsys jfs; |
2a29f135 | 465 | io_manager io_ptr; |
63985320 TT |
466 | |
467 | if (fs->super->s_feature_compat & | |
468 | EXT3_FEATURE_COMPAT_HAS_JOURNAL) { | |
54434927 | 469 | fputs(_("The filesystem already has a journal.\n"), stderr); |
2d15576d | 470 | goto err; |
63985320 | 471 | } |
63985320 TT |
472 | if (journal_device) { |
473 | check_plausibility(journal_device); | |
474 | check_mount(journal_device, 0, _("journal")); | |
2a29f135 TT |
475 | #ifdef CONFIG_TESTIO_DEBUG |
476 | io_ptr = test_io_manager; | |
477 | test_io_backing_manager = unix_io_manager; | |
478 | #else | |
479 | io_ptr = unix_io_manager; | |
480 | #endif | |
16ed5b3a TT |
481 | retval = ext2fs_open(journal_device, EXT2_FLAG_RW| |
482 | EXT2_FLAG_JOURNAL_DEV_OK, 0, | |
2a29f135 | 483 | fs->blocksize, io_ptr, &jfs); |
16ed5b3a TT |
484 | if (retval) { |
485 | com_err(program_name, retval, | |
1d08d9bf | 486 | _("\n\twhile trying to open journal on %s\n"), |
16ed5b3a | 487 | journal_device); |
2d15576d | 488 | goto err; |
16ed5b3a | 489 | } |
63985320 TT |
490 | printf(_("Creating journal on device %s: "), |
491 | journal_device); | |
4055ef73 | 492 | fflush(stdout); |
2d15576d | 493 | |
16ed5b3a | 494 | retval = ext2fs_add_journal_device(fs, jfs); |
2d15576d | 495 | ext2fs_close(jfs); |
63985320 TT |
496 | if (retval) { |
497 | com_err (program_name, retval, | |
8d641749 | 498 | _("while adding filesystem to journal on %s"), |
63985320 | 499 | journal_device); |
2d15576d | 500 | goto err; |
63985320 | 501 | } |
54434927 | 502 | fputs(_("done\n"), stdout); |
63985320 | 503 | } else if (journal_size) { |
54434927 | 504 | fputs(_("Creating journal inode: "), stdout); |
63985320 | 505 | fflush(stdout); |
2537b6d0 TT |
506 | journal_blocks = figure_journal_size(journal_size, fs); |
507 | ||
63985320 TT |
508 | retval = ext2fs_add_journal_inode(fs, journal_blocks, |
509 | journal_flags); | |
510 | if (retval) { | |
7141b54b | 511 | fprintf(stderr, "\n"); |
63985320 | 512 | com_err(program_name, retval, |
1d08d9bf | 513 | _("\n\twhile trying to create journal file")); |
63985320 | 514 | exit(1); |
1d08d9bf | 515 | } else |
54434927 | 516 | fputs(_("done\n"), stdout); |
63985320 TT |
517 | /* |
518 | * If the filesystem wasn't mounted, we need to force | |
519 | * the block group descriptors out. | |
520 | */ | |
521 | if ((mount_flags & EXT2_MF_MOUNTED) == 0) | |
522 | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; | |
523 | } | |
66cf2f60 | 524 | print_check_message(fs); |
2d15576d AD |
525 | return; |
526 | ||
527 | err: | |
528 | if (journal_device) | |
529 | free(journal_device); | |
530 | exit(1); | |
63985320 TT |
531 | } |
532 | ||
83238153 | 533 | |
c8c071a0 | 534 | static void parse_e2label_options(int argc, char ** argv) |
83238153 TT |
535 | { |
536 | if ((argc < 2) || (argc > 3)) { | |
54434927 | 537 | fputs(_("Usage: e2label device [newlabel]\n"), stderr); |
83238153 TT |
538 | exit(1); |
539 | } | |
2e8ca9a2 TT |
540 | io_options = strchr(argv[1], '?'); |
541 | if (io_options) | |
542 | *io_options++ = 0; | |
332f2c23 | 543 | device_name = blkid_get_devname(NULL, argv[1], NULL); |
817e49e3 | 544 | if (!device_name) { |
efc6f628 | 545 | com_err("e2label", 0, _("Unable to resolve '%s'"), |
817e49e3 TT |
546 | argv[1]); |
547 | exit(1); | |
548 | } | |
2be8fe43 | 549 | open_flag = EXT2_FLAG_JOURNAL_DEV_OK; |
83238153 | 550 | if (argc == 3) { |
0ddfd9a5 | 551 | open_flag |= EXT2_FLAG_RW; |
83238153 TT |
552 | L_flag = 1; |
553 | new_label = argv[2]; | |
efc6f628 | 554 | } else |
83238153 TT |
555 | print_label++; |
556 | } | |
557 | ||
d4de4aa9 TT |
558 | static time_t parse_time(char *str) |
559 | { | |
560 | struct tm ts; | |
561 | ||
562 | if (strcmp(str, "now") == 0) { | |
563 | return (time(0)); | |
564 | } | |
565 | memset(&ts, 0, sizeof(ts)); | |
bc7c14e0 | 566 | #ifdef HAVE_STRPTIME |
690e693c | 567 | strptime(str, "%Y%m%d%H%M%S", &ts); |
bc7c14e0 | 568 | #else |
690e693c | 569 | sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon, |
bc7c14e0 TT |
570 | &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec); |
571 | ts.tm_year -= 1900; | |
572 | ts.tm_mon -= 1; | |
573 | if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 || | |
574 | ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 || | |
575 | ts.tm_min > 59 || ts.tm_sec > 61) | |
576 | ts.tm_mday = 0; | |
577 | #endif | |
d4de4aa9 TT |
578 | if (ts.tm_mday == 0) { |
579 | com_err(program_name, 0, | |
580 | _("Couldn't parse date/time specifier: %s"), | |
581 | str); | |
582 | usage(); | |
583 | } | |
a2ff0f31 | 584 | ts.tm_isdst = -1; |
d4de4aa9 TT |
585 | return (mktime(&ts)); |
586 | } | |
83238153 | 587 | |
c8c071a0 | 588 | static void parse_tune2fs_options(int argc, char **argv) |
3839e657 | 589 | { |
519149fb | 590 | int c; |
3839e657 | 591 | char * tmp; |
f3db3566 TT |
592 | struct group * gr; |
593 | struct passwd * pw; | |
3839e657 | 594 | |
2be8fe43 | 595 | open_flag = 0; |
0ddfd9a5 | 596 | |
0f8973fb | 597 | printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); |
64d588cf | 598 | while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:")) != EOF) |
3839e657 TT |
599 | switch (c) |
600 | { | |
601 | case 'c': | |
45d9e2ff | 602 | max_mount_count = strtol (optarg, &tmp, 0); |
818180cd | 603 | if (*tmp || max_mount_count > 16000) { |
3839e657 | 604 | com_err (program_name, 0, |
d9c56d3c | 605 | _("bad mounts count - %s"), |
3839e657 | 606 | optarg); |
818180cd | 607 | usage(); |
3839e657 | 608 | } |
ce57f14f TT |
609 | if (max_mount_count == 0) |
610 | max_mount_count = -1; | |
3839e657 | 611 | c_flag = 1; |
1e3472c5 TT |
612 | open_flag = EXT2_FLAG_RW; |
613 | break; | |
614 | case 'C': | |
615 | mount_count = strtoul (optarg, &tmp, 0); | |
818180cd | 616 | if (*tmp || mount_count > 16000) { |
1e3472c5 | 617 | com_err (program_name, 0, |
d9c56d3c | 618 | _("bad mounts count - %s"), |
1e3472c5 | 619 | optarg); |
818180cd | 620 | usage(); |
1e3472c5 TT |
621 | } |
622 | C_flag = 1; | |
623 | open_flag = EXT2_FLAG_RW; | |
3839e657 TT |
624 | break; |
625 | case 'e': | |
626 | if (strcmp (optarg, "continue") == 0) | |
627 | errors = EXT2_ERRORS_CONTINUE; | |
628 | else if (strcmp (optarg, "remount-ro") == 0) | |
629 | errors = EXT2_ERRORS_RO; | |
630 | else if (strcmp (optarg, "panic") == 0) | |
631 | errors = EXT2_ERRORS_PANIC; | |
818180cd | 632 | else { |
3839e657 | 633 | com_err (program_name, 0, |
d9c56d3c | 634 | _("bad error behavior - %s"), |
3839e657 | 635 | optarg); |
818180cd | 636 | usage(); |
3839e657 TT |
637 | } |
638 | e_flag = 1; | |
1e3472c5 | 639 | open_flag = EXT2_FLAG_RW; |
3839e657 | 640 | break; |
6cb27404 TT |
641 | case 'E': |
642 | extended_cmd = optarg; | |
0ddfd9a5 | 643 | open_flag |= EXT2_FLAG_RW; |
6cb27404 | 644 | break; |
4d0f2283 TT |
645 | case 'f': /* Force */ |
646 | f_flag = 1; | |
647 | break; | |
f3db3566 TT |
648 | case 'g': |
649 | resgid = strtoul (optarg, &tmp, 0); | |
818180cd | 650 | if (*tmp) { |
f3db3566 TT |
651 | gr = getgrnam (optarg); |
652 | if (gr == NULL) | |
653 | tmp = optarg; | |
a418d3ad | 654 | else { |
f3db3566 | 655 | resgid = gr->gr_gid; |
a418d3ad TT |
656 | *tmp =0; |
657 | } | |
f3db3566 | 658 | } |
818180cd | 659 | if (*tmp) { |
f3db3566 | 660 | com_err (program_name, 0, |
d9c56d3c | 661 | _("bad gid/group name - %s"), |
f3db3566 | 662 | optarg); |
818180cd | 663 | usage(); |
f3db3566 TT |
664 | } |
665 | g_flag = 1; | |
1e3472c5 | 666 | open_flag = EXT2_FLAG_RW; |
f3db3566 | 667 | break; |
3839e657 TT |
668 | case 'i': |
669 | interval = strtoul (optarg, &tmp, 0); | |
1e3472c5 TT |
670 | switch (*tmp) { |
671 | case 's': | |
672 | tmp++; | |
673 | break; | |
674 | case '\0': | |
675 | case 'd': | |
676 | case 'D': /* days */ | |
677 | interval *= 86400; | |
678 | if (*tmp != '\0') | |
f3db3566 | 679 | tmp++; |
1e3472c5 TT |
680 | break; |
681 | case 'm': | |
682 | case 'M': /* months! */ | |
683 | interval *= 86400 * 30; | |
684 | tmp++; | |
685 | break; | |
686 | case 'w': | |
687 | case 'W': /* weeks */ | |
688 | interval *= 86400 * 7; | |
689 | tmp++; | |
690 | break; | |
3839e657 | 691 | } |
f51d0eff | 692 | if (*tmp) { |
3839e657 | 693 | com_err (program_name, 0, |
d9c56d3c | 694 | _("bad interval - %s"), optarg); |
818180cd | 695 | usage(); |
3839e657 TT |
696 | } |
697 | i_flag = 1; | |
1e3472c5 | 698 | open_flag = EXT2_FLAG_RW; |
3839e657 | 699 | break; |
63985320 | 700 | case 'j': |
dc2ec525 TT |
701 | if (!journal_size) |
702 | journal_size = -1; | |
4d0f2283 | 703 | open_flag = EXT2_FLAG_RW; |
dc2ec525 TT |
704 | break; |
705 | case 'J': | |
706 | parse_journal_opts(optarg); | |
63985320 TT |
707 | open_flag = EXT2_FLAG_RW; |
708 | break; | |
08dd830d TT |
709 | case 'l': |
710 | l_flag = 1; | |
711 | break; | |
1e3472c5 TT |
712 | case 'L': |
713 | new_label = optarg; | |
714 | L_flag = 1; | |
0ddfd9a5 | 715 | open_flag |= EXT2_FLAG_RW | |
2d15576d | 716 | EXT2_FLAG_JOURNAL_DEV_OK; |
1e3472c5 | 717 | break; |
3839e657 | 718 | case 'm': |
ce911145 | 719 | reserved_ratio = strtod(optarg, &tmp); |
818180cd | 720 | if (*tmp || reserved_ratio > 50) { |
3839e657 | 721 | com_err (program_name, 0, |
d9c56d3c | 722 | _("bad reserved block ratio - %s"), |
3839e657 | 723 | optarg); |
818180cd | 724 | usage(); |
3839e657 TT |
725 | } |
726 | m_flag = 1; | |
1e3472c5 TT |
727 | open_flag = EXT2_FLAG_RW; |
728 | break; | |
729 | case 'M': | |
730 | new_last_mounted = optarg; | |
731 | M_flag = 1; | |
732 | open_flag = EXT2_FLAG_RW; | |
3839e657 | 733 | break; |
a0c3fd5e TT |
734 | case 'o': |
735 | if (mntopts_cmd) { | |
736 | com_err (program_name, 0, | |
737 | _("-o may only be specified once")); | |
738 | usage(); | |
739 | } | |
740 | mntopts_cmd = optarg; | |
741 | open_flag = EXT2_FLAG_RW; | |
742 | break; | |
efc6f628 | 743 | |
896938d5 | 744 | case 'O': |
d258668d TT |
745 | if (features_cmd) { |
746 | com_err (program_name, 0, | |
747 | _("-O may only be specified once")); | |
748 | usage(); | |
749 | } | |
896938d5 TT |
750 | features_cmd = optarg; |
751 | open_flag = EXT2_FLAG_RW; | |
752 | break; | |
f3db3566 TT |
753 | case 'r': |
754 | reserved_blocks = strtoul (optarg, &tmp, 0); | |
818180cd | 755 | if (*tmp) { |
f3db3566 | 756 | com_err (program_name, 0, |
d9c56d3c | 757 | _("bad reserved blocks count - %s"), |
f3db3566 | 758 | optarg); |
818180cd | 759 | usage(); |
f3db3566 TT |
760 | } |
761 | r_flag = 1; | |
1e3472c5 | 762 | open_flag = EXT2_FLAG_RW; |
f3db3566 | 763 | break; |
ff662d5d | 764 | case 's': /* Deprecated */ |
521e3685 TT |
765 | s_flag = atoi(optarg); |
766 | open_flag = EXT2_FLAG_RW; | |
767 | break; | |
d4de4aa9 TT |
768 | case 'T': |
769 | T_flag = 1; | |
770 | last_check_time = parse_time(optarg); | |
771 | open_flag = EXT2_FLAG_RW; | |
772 | break; | |
f3db3566 TT |
773 | case 'u': |
774 | resuid = strtoul (optarg, &tmp, 0); | |
818180cd | 775 | if (*tmp) { |
f3db3566 TT |
776 | pw = getpwnam (optarg); |
777 | if (pw == NULL) | |
778 | tmp = optarg; | |
a418d3ad | 779 | else { |
f3db3566 | 780 | resuid = pw->pw_uid; |
a418d3ad TT |
781 | *tmp = 0; |
782 | } | |
f3db3566 | 783 | } |
818180cd | 784 | if (*tmp) { |
f3db3566 | 785 | com_err (program_name, 0, |
d9c56d3c | 786 | _("bad uid/user name - %s"), |
f3db3566 | 787 | optarg); |
818180cd | 788 | usage(); |
f3db3566 TT |
789 | } |
790 | u_flag = 1; | |
1e3472c5 TT |
791 | open_flag = EXT2_FLAG_RW; |
792 | break; | |
793 | case 'U': | |
794 | new_UUID = optarg; | |
795 | U_flag = 1; | |
2d15576d AD |
796 | open_flag = EXT2_FLAG_RW | |
797 | EXT2_FLAG_JOURNAL_DEV_OK; | |
f3db3566 | 798 | break; |
64d588cf AK |
799 | case 'I': |
800 | new_inode_size = strtoul (optarg, &tmp, 0); | |
801 | if (*tmp) { | |
802 | com_err (program_name, 0, | |
803 | _("bad inode size - %s"), | |
804 | optarg); | |
805 | usage(); | |
806 | } | |
807 | if (!((new_inode_size & | |
808 | (new_inode_size - 1)) == 0)) { | |
809 | com_err (program_name, 0, | |
810 | _("Inode size must be a " | |
811 | "power of two- %s"), | |
812 | optarg); | |
813 | usage(); | |
814 | } | |
815 | open_flag = EXT2_FLAG_RW; | |
816 | I_flag = 1; | |
817 | break; | |
3839e657 | 818 | default: |
818180cd | 819 | usage(); |
3839e657 TT |
820 | } |
821 | if (optind < argc - 1 || optind == argc) | |
818180cd | 822 | usage(); |
1e3472c5 TT |
823 | if (!open_flag && !l_flag) |
824 | usage(); | |
2e8ca9a2 TT |
825 | io_options = strchr(argv[optind], '?'); |
826 | if (io_options) | |
827 | *io_options++ = 0; | |
332f2c23 | 828 | device_name = blkid_get_devname(NULL, argv[optind], NULL); |
817e49e3 | 829 | if (!device_name) { |
efc6f628 | 830 | com_err("tune2fs", 0, _("Unable to resolve '%s'"), |
817e49e3 TT |
831 | argv[optind]); |
832 | exit(1); | |
833 | } | |
118d7dac TT |
834 | } |
835 | ||
3e699064 | 836 | void do_findfs(int argc, char **argv) |
118d7dac TT |
837 | { |
838 | char *dev; | |
83238153 | 839 | |
118d7dac TT |
840 | if ((argc != 2) || |
841 | (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) { | |
842 | fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n"); | |
843 | exit(2); | |
844 | } | |
ed1b33e8 | 845 | dev = blkid_get_devname(NULL, argv[1], NULL); |
118d7dac | 846 | if (!dev) { |
efc6f628 | 847 | com_err("findfs", 0, _("Unable to resolve '%s'"), |
118d7dac TT |
848 | argv[1]); |
849 | exit(1); | |
850 | } | |
851 | puts(dev); | |
852 | exit(0); | |
853 | } | |
83238153 | 854 | |
6cb27404 TT |
855 | static void parse_extended_opts(ext2_filsys fs, const char *opts) |
856 | { | |
857 | char *buf, *token, *next, *p, *arg; | |
858 | int len; | |
859 | int r_usage = 0; | |
860 | ||
861 | len = strlen(opts); | |
862 | buf = malloc(len+1); | |
863 | if (!buf) { | |
864 | fprintf(stderr, | |
865 | _("Couldn't allocate memory to parse options!\n")); | |
866 | exit(1); | |
867 | } | |
868 | strcpy(buf, opts); | |
869 | for (token = buf; token && *token; token = next) { | |
870 | p = strchr(token, ','); | |
871 | next = 0; | |
872 | if (p) { | |
873 | *p = 0; | |
874 | next = p+1; | |
875 | } | |
876 | arg = strchr(token, '='); | |
877 | if (arg) { | |
878 | *arg = 0; | |
879 | arg++; | |
880 | } | |
881 | if (!strcmp(token, "test_fs")) { | |
882 | fs->super->s_flags |= EXT2_FLAGS_TEST_FILESYS; | |
883 | printf("Setting test filesystem flag\n"); | |
884 | ext2fs_mark_super_dirty(fs); | |
885 | } else if (!strcmp(token, "^test_fs")) { | |
886 | fs->super->s_flags &= ~EXT2_FLAGS_TEST_FILESYS; | |
887 | printf("Clearing test filesystem flag\n"); | |
888 | ext2fs_mark_super_dirty(fs); | |
0c17cb25 TT |
889 | } else if (strcmp(token, "stride") == 0) { |
890 | if (!arg) { | |
891 | r_usage++; | |
892 | continue; | |
893 | } | |
894 | stride = strtoul(arg, &p, 0); | |
895 | if (*p || (stride == 0)) { | |
896 | fprintf(stderr, | |
897 | _("Invalid RAID stride: %s\n"), | |
898 | arg); | |
899 | r_usage++; | |
900 | continue; | |
901 | } | |
902 | stride_set = 1; | |
903 | } else if (strcmp(token, "stripe-width") == 0 || | |
904 | strcmp(token, "stripe_width") == 0) { | |
905 | if (!arg) { | |
906 | r_usage++; | |
907 | continue; | |
908 | } | |
909 | stripe_width = strtoul(arg, &p, 0); | |
910 | if (*p || (stripe_width == 0)) { | |
911 | fprintf(stderr, | |
912 | _("Invalid RAID stripe-width: %s\n"), | |
913 | arg); | |
914 | r_usage++; | |
915 | continue; | |
916 | } | |
917 | stripe_width_set = 1; | |
efc6f628 | 918 | } else |
6cb27404 TT |
919 | r_usage++; |
920 | } | |
921 | if (r_usage) { | |
922 | fprintf(stderr, _("\nBad options specified.\n\n" | |
923 | "Extended options are separated by commas, " | |
924 | "and may take an argument which\n" | |
925 | "\tis set off by an equals ('=') sign.\n\n" | |
926 | "Valid extended options are:\n" | |
0c17cb25 TT |
927 | "\tstride=<RAID per-disk chunk size in blocks>\n" |
928 | "\tstripe-width=<RAID stride*data disks in blocks>\n" | |
6cb27404 TT |
929 | "\ttest_fs\n" |
930 | "\t^test_fs\n")); | |
931 | free(buf); | |
932 | exit(1); | |
933 | } | |
934 | free(buf); | |
efc6f628 | 935 | } |
6cb27404 | 936 | |
64d588cf AK |
937 | static int get_move_bitmap(ext2_filsys fs, int new_ino_blks_per_grp, |
938 | ext2fs_block_bitmap bmap) | |
939 | { | |
940 | dgrp_t i; | |
941 | blk_t j, needed_blocks = 0; | |
942 | blk_t start_blk, end_blk; | |
943 | ||
944 | for (i = 0; i < fs->group_desc_count; i++) { | |
945 | ||
946 | start_blk = fs->group_desc[i].bg_inode_table + | |
947 | fs->inode_blocks_per_group; | |
948 | ||
949 | end_blk = fs->group_desc[i].bg_inode_table + | |
950 | new_ino_blks_per_grp; | |
951 | ||
952 | for (j = start_blk; j < end_blk; j++) { | |
953 | ||
954 | if (ext2fs_test_block_bitmap(fs->block_map, j)) { | |
955 | /* FIXME!! | |
956 | * What happens if the block is marked | |
957 | * as a bad block | |
958 | */ | |
959 | ext2fs_mark_block_bitmap(bmap, j); | |
960 | needed_blocks++; | |
961 | } else { | |
962 | /* | |
963 | * We are going to use this block for | |
964 | * inode table. So mark them used. | |
965 | */ | |
966 | ext2fs_mark_block_bitmap(fs->block_map, j); | |
967 | } | |
968 | } | |
969 | } | |
970 | ||
971 | if (needed_blocks > fs->super->s_free_blocks_count ) { | |
972 | return ENOSPC; | |
973 | } | |
974 | ||
975 | return 0; | |
976 | } | |
977 | ||
978 | static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap) | |
979 | { | |
980 | char *buf; | |
981 | errcode_t retval; | |
982 | blk_t blk, new_blk; | |
983 | struct blk_move *bmv; | |
984 | ||
985 | ||
986 | retval = ext2fs_get_mem(fs->blocksize, &buf); | |
987 | if (retval) | |
988 | return retval; | |
989 | ||
990 | for (blk = fs->super->s_first_data_block; | |
991 | blk < fs->super->s_blocks_count; blk++) { | |
992 | ||
993 | if (!ext2fs_test_block_bitmap(bmap, blk)) | |
994 | continue; | |
995 | ||
996 | retval = ext2fs_new_block(fs, blk, NULL, &new_blk); | |
997 | if (retval) | |
998 | goto err_out; | |
999 | ||
1000 | /* Mark this block as allocated */ | |
1001 | ext2fs_mark_block_bitmap(fs->block_map, new_blk); | |
1002 | ||
1003 | /* Add it to block move list */ | |
1004 | retval = ext2fs_get_mem(sizeof(struct blk_move), &bmv); | |
1005 | if (retval) | |
1006 | goto err_out; | |
1007 | ||
1008 | bmv->old_loc = blk; | |
1009 | bmv->new_loc = new_blk; | |
1010 | ||
1011 | list_add(&(bmv->list), &blk_move_list); | |
1012 | ||
1013 | retval = io_channel_read_blk(fs->io, blk, 1, buf); | |
1014 | if (retval) | |
1015 | goto err_out; | |
1016 | ||
1017 | retval = io_channel_write_blk(fs->io, new_blk, 1, buf); | |
1018 | if (retval) | |
1019 | goto err_out; | |
1020 | } | |
1021 | ||
1022 | err_out: | |
1023 | ext2fs_free_mem(&buf); | |
1024 | return retval; | |
1025 | } | |
1026 | ||
1027 | static blk_t transalate_block(blk_t blk) | |
1028 | { | |
1029 | struct list_head *entry; | |
1030 | struct blk_move *bmv; | |
1031 | ||
1032 | list_for_each(entry, &blk_move_list) { | |
1033 | ||
1034 | bmv = list_entry(entry, struct blk_move, list); | |
1035 | if (bmv->old_loc == blk) | |
1036 | return bmv->new_loc; | |
1037 | } | |
1038 | ||
1039 | return 0; | |
1040 | } | |
1041 | ||
721b367a TT |
1042 | static int process_block(ext2_filsys fs EXT2FS_ATTR((unused)), |
1043 | blk_t *block_nr, | |
1044 | e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), | |
64d588cf AK |
1045 | blk_t ref_block EXT2FS_ATTR((unused)), |
1046 | int ref_offset EXT2FS_ATTR((unused)), | |
1047 | void *priv_data EXT2FS_ATTR((unused))) | |
1048 | { | |
1049 | int ret = 0; | |
1050 | blk_t new_blk; | |
1051 | ||
1052 | ||
1053 | new_blk = transalate_block(*block_nr); | |
1054 | if (new_blk) { | |
1055 | *block_nr = new_blk; | |
1056 | /* | |
1057 | * This will force the ext2fs_write_inode in the iterator | |
1058 | */ | |
1059 | ret |= BLOCK_CHANGED; | |
1060 | } | |
1061 | ||
1062 | return ret; | |
1063 | } | |
1064 | ||
1065 | static int inode_scan_and_fix(ext2_filsys fs) | |
1066 | { | |
1067 | errcode_t retval = 0; | |
1068 | ext2_ino_t ino; | |
1069 | blk_t blk; | |
1070 | char *block_buf = 0; | |
1071 | struct ext2_inode inode; | |
1072 | ext2_inode_scan scan = NULL; | |
1073 | ||
1074 | retval = ext2fs_get_mem(fs->blocksize * 3, &block_buf); | |
1075 | if (retval) | |
1076 | return retval; | |
1077 | ||
1078 | retval = ext2fs_open_inode_scan(fs, 0, &scan); | |
1079 | if (retval) | |
1080 | goto err_out; | |
1081 | ||
1082 | while (1) { | |
1083 | ||
1084 | retval = ext2fs_get_next_inode(scan, &ino, &inode); | |
1085 | if (retval) | |
1086 | goto err_out; | |
1087 | ||
1088 | if (!ino) | |
1089 | break; | |
1090 | ||
1091 | if (inode.i_links_count == 0) | |
1092 | continue; /* inode not in use */ | |
1093 | ||
1094 | /* FIXME!! | |
1095 | * If we end up modifying the journal inode | |
1096 | * the sb->s_jnl_blocks will differ. But a | |
1097 | * subsequent e2fsck fixes that. | |
1098 | * Do we need to fix this ?? | |
1099 | */ | |
1100 | ||
1101 | if (inode.i_file_acl) { | |
1102 | ||
1103 | blk = transalate_block(inode.i_file_acl); | |
1104 | if (!blk) | |
1105 | continue; | |
1106 | ||
1107 | inode.i_file_acl = blk; | |
1108 | ||
1109 | /* | |
1110 | * Write the inode to disk so that inode table | |
1111 | * resizing can work | |
1112 | */ | |
1113 | retval = ext2fs_write_inode(fs, ino, &inode); | |
1114 | if (retval) | |
1115 | goto err_out; | |
1116 | } | |
1117 | ||
1118 | if (!ext2fs_inode_has_valid_blocks(&inode)) | |
1119 | continue; | |
1120 | ||
1121 | retval = ext2fs_block_iterate2(fs, ino, 0, | |
1122 | block_buf, process_block, | |
1123 | 0); | |
1124 | if (retval) | |
1125 | goto err_out; | |
1126 | ||
1127 | } | |
1128 | ||
1129 | err_out: | |
1130 | ext2fs_free_mem(&block_buf); | |
1131 | ||
1132 | return retval; | |
1133 | ||
1134 | } | |
1135 | ||
721b367a | 1136 | static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size) |
64d588cf AK |
1137 | { |
1138 | dgrp_t i; | |
1139 | blk_t blk; | |
1140 | errcode_t retval; | |
721b367a TT |
1141 | int new_ino_blks_per_grp; |
1142 | unsigned int j; | |
64d588cf AK |
1143 | char *old_itable = NULL, *new_itable = NULL; |
1144 | char *tmp_old_itable = NULL, *tmp_new_itable = NULL; | |
721b367a | 1145 | unsigned long old_ino_size; |
64d588cf AK |
1146 | int old_itable_size, new_itable_size; |
1147 | ||
1148 | old_itable_size = fs->inode_blocks_per_group * fs->blocksize; | |
721b367a | 1149 | old_ino_size = EXT2_INODE_SIZE(fs->super); |
64d588cf AK |
1150 | |
1151 | new_ino_blks_per_grp = ext2fs_div_ceil( | |
1152 | EXT2_INODES_PER_GROUP(fs->super) * | |
721b367a | 1153 | new_ino_size, |
64d588cf AK |
1154 | fs->blocksize); |
1155 | ||
1156 | new_itable_size = new_ino_blks_per_grp * fs->blocksize; | |
1157 | ||
1158 | retval = ext2fs_get_mem(old_itable_size, &old_itable); | |
1159 | if (retval) | |
1160 | return retval; | |
1161 | ||
1162 | retval = ext2fs_get_mem(new_itable_size, &new_itable); | |
1163 | if (retval) | |
1164 | goto err_out; | |
1165 | ||
1166 | tmp_old_itable = old_itable; | |
1167 | tmp_new_itable = new_itable; | |
1168 | ||
1169 | for (i = 0; i < fs->group_desc_count; i++) { | |
1170 | ||
1171 | blk = fs->group_desc[i].bg_inode_table; | |
1172 | retval = io_channel_read_blk(fs->io, blk, | |
1173 | fs->inode_blocks_per_group, old_itable); | |
1174 | if (retval) | |
1175 | goto err_out; | |
1176 | ||
1177 | for (j = 0; j < EXT2_INODES_PER_GROUP(fs->super); j++) { | |
1178 | ||
721b367a | 1179 | memcpy(new_itable, old_itable, old_ino_size); |
64d588cf | 1180 | |
721b367a TT |
1181 | memset(new_itable+old_ino_size, 0, |
1182 | new_ino_size - old_ino_size); | |
64d588cf | 1183 | |
721b367a TT |
1184 | new_itable += new_ino_size; |
1185 | old_itable += old_ino_size; | |
64d588cf AK |
1186 | } |
1187 | ||
1188 | /* reset the pointer */ | |
1189 | old_itable = tmp_old_itable; | |
1190 | new_itable = tmp_new_itable; | |
1191 | ||
1192 | retval = io_channel_write_blk(fs->io, blk, | |
1193 | new_ino_blks_per_grp, new_itable); | |
1194 | if (retval) | |
1195 | goto err_out; | |
1196 | } | |
1197 | ||
1198 | /* Update the meta data */ | |
1199 | fs->inode_blocks_per_group = new_ino_blks_per_grp; | |
721b367a | 1200 | fs->super->s_inode_size = new_ino_size; |
64d588cf AK |
1201 | |
1202 | err_out: | |
1203 | if (old_itable) | |
1204 | ext2fs_free_mem(&old_itable); | |
1205 | ||
1206 | if (new_itable) | |
1207 | ext2fs_free_mem(&new_itable); | |
1208 | ||
1209 | return retval; | |
64d588cf AK |
1210 | } |
1211 | ||
1212 | static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs) | |
1213 | { | |
1214 | blk_t blk; | |
1215 | ext2_ino_t ino; | |
1216 | unsigned int group = 0; | |
1217 | unsigned int count = 0; | |
1218 | int total_free = 0; | |
1219 | int group_free = 0; | |
1220 | ||
1221 | /* | |
1222 | * First calculate the block statistics | |
1223 | */ | |
1224 | for (blk = fs->super->s_first_data_block; | |
1225 | blk < fs->super->s_blocks_count; blk++) { | |
1226 | if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) { | |
1227 | group_free++; | |
1228 | total_free++; | |
1229 | } | |
1230 | count++; | |
1231 | if ((count == fs->super->s_blocks_per_group) || | |
1232 | (blk == fs->super->s_blocks_count-1)) { | |
1233 | fs->group_desc[group++].bg_free_blocks_count = | |
1234 | group_free; | |
1235 | count = 0; | |
1236 | group_free = 0; | |
1237 | } | |
1238 | } | |
1239 | fs->super->s_free_blocks_count = total_free; | |
1240 | ||
1241 | /* | |
1242 | * Next, calculate the inode statistics | |
1243 | */ | |
1244 | group_free = 0; | |
1245 | total_free = 0; | |
1246 | count = 0; | |
1247 | group = 0; | |
1248 | ||
1249 | /* Protect loop from wrap-around if s_inodes_count maxed */ | |
1250 | for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) { | |
1251 | if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) { | |
1252 | group_free++; | |
1253 | total_free++; | |
1254 | } | |
1255 | count++; | |
1256 | if ((count == fs->super->s_inodes_per_group) || | |
1257 | (ino == fs->super->s_inodes_count)) { | |
1258 | fs->group_desc[group++].bg_free_inodes_count = | |
1259 | group_free; | |
1260 | count = 0; | |
1261 | group_free = 0; | |
1262 | } | |
1263 | } | |
1264 | fs->super->s_free_inodes_count = total_free; | |
1265 | ext2fs_mark_super_dirty(fs); | |
1266 | return 0; | |
1267 | } | |
1268 | ||
1269 | #define list_for_each_safe(pos, pnext, head) \ | |
1270 | for (pos = (head)->next, pnext = pos->next; pos != (head); \ | |
1271 | pos = pnext, pnext = pos->next) | |
1272 | ||
721b367a | 1273 | static void free_blk_move_list(void) |
64d588cf AK |
1274 | { |
1275 | struct list_head *entry, *tmp; | |
1276 | struct blk_move *bmv; | |
1277 | ||
1278 | list_for_each_safe(entry, tmp, &blk_move_list) { | |
1279 | ||
1280 | bmv = list_entry(entry, struct blk_move, list); | |
1281 | list_del(entry); | |
1282 | ext2fs_free_mem(&bmv); | |
1283 | } | |
1284 | ||
1285 | return ; | |
1286 | } | |
721b367a TT |
1287 | |
1288 | static int resize_inode(ext2_filsys fs, unsigned long new_size) | |
64d588cf AK |
1289 | { |
1290 | errcode_t retval; | |
1291 | int new_ino_blks_per_grp; | |
1292 | ext2fs_block_bitmap bmap; | |
1293 | ||
64d588cf AK |
1294 | ext2fs_read_inode_bitmap(fs); |
1295 | ext2fs_read_block_bitmap(fs); | |
1296 | INIT_LIST_HEAD(&blk_move_list); | |
1297 | ||
1298 | ||
1299 | new_ino_blks_per_grp = ext2fs_div_ceil( | |
1300 | EXT2_INODES_PER_GROUP(fs->super)* | |
721b367a | 1301 | new_size, |
64d588cf AK |
1302 | fs->blocksize); |
1303 | ||
1304 | /* We may change the file system. | |
1305 | * Mark the file system as invalid so that | |
1306 | * the user is prompted to run fsck. | |
1307 | */ | |
1308 | fs->super->s_state &= ~EXT2_VALID_FS; | |
1309 | ||
1310 | retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"), | |
1311 | &bmap); | |
1312 | if (retval) | |
1313 | return retval; | |
1314 | ||
1315 | retval = get_move_bitmap(fs, new_ino_blks_per_grp, bmap); | |
1316 | if (retval) | |
1317 | goto err_out; | |
1318 | ||
1319 | retval = move_block(fs, bmap); | |
1320 | if (retval) | |
1321 | goto err_out; | |
1322 | ||
1323 | retval = inode_scan_and_fix(fs); | |
1324 | if (retval) | |
1325 | goto err_out; | |
1326 | ||
721b367a | 1327 | retval = expand_inode_table(fs, new_size); |
64d588cf AK |
1328 | if (retval) |
1329 | goto err_out; | |
1330 | ||
1331 | ext2fs_calculate_summary_stats(fs); | |
1332 | ||
1333 | fs->super->s_state |= EXT2_VALID_FS; | |
1334 | /* mark super block and block bitmap as dirty */ | |
1335 | ext2fs_mark_super_dirty(fs); | |
1336 | ext2fs_mark_bb_dirty(fs); | |
1337 | ||
1338 | err_out: | |
1339 | free_blk_move_list(); | |
1340 | ext2fs_free_block_bitmap(bmap); | |
1341 | ||
1342 | return retval; | |
1343 | } | |
1344 | ||
1345 | static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr) | |
1346 | { | |
1347 | errcode_t retval = 0; | |
721b367a TT |
1348 | const char *tdb_dir; |
1349 | char tdb_file[PATH_MAX]; | |
1350 | char *dev_name, *tmp_name; | |
64d588cf AK |
1351 | |
1352 | #if 0 /* FIXME!! */ | |
1353 | /* | |
1354 | * Configuration via a conf file would be | |
1355 | * nice | |
1356 | */ | |
1357 | profile_get_string(profile, "scratch_files", | |
1358 | "directory", 0, 0, | |
1359 | &tdb_dir); | |
1360 | #endif | |
1361 | tmp_name = strdup(name); | |
721b367a | 1362 | dev_name = basename(tmp_name); |
64d588cf AK |
1363 | |
1364 | tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); | |
1365 | if (!tdb_dir) | |
1366 | tdb_dir="/var/lib/e2fsprogs"; | |
1367 | ||
1368 | if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || | |
1369 | access(tdb_dir, W_OK)) | |
1370 | return 0; | |
1371 | ||
721b367a | 1372 | sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name); |
64d588cf AK |
1373 | |
1374 | if (!access(tdb_file, F_OK)) { | |
1375 | if (unlink(tdb_file) < 0) { | |
1376 | retval = errno; | |
1377 | com_err(program_name, retval, | |
1378 | _("while trying to delete %s"), | |
1379 | tdb_file); | |
1380 | return retval; | |
1381 | } | |
1382 | } | |
1383 | ||
1384 | set_undo_io_backing_manager(*io_ptr); | |
1385 | *io_ptr = undo_io_manager; | |
1386 | set_undo_io_backup_file(tdb_file); | |
1387 | printf(_("To undo the tune2fs operations please run " | |
577b5c43 | 1388 | "the command\n e2undo %s %s\n\n"), |
64d588cf | 1389 | tdb_file, name); |
64d588cf AK |
1390 | free(tmp_name); |
1391 | return retval; | |
1392 | } | |
83238153 TT |
1393 | |
1394 | int main (int argc, char ** argv) | |
1395 | { | |
1396 | errcode_t retval; | |
1397 | ext2_filsys fs; | |
1398 | struct ext2_super_block *sb; | |
d887f88d | 1399 | io_manager io_ptr, io_ptr_orig = NULL; |
83238153 TT |
1400 | |
1401 | #ifdef ENABLE_NLS | |
1402 | setlocale(LC_MESSAGES, ""); | |
14308a53 | 1403 | setlocale(LC_CTYPE, ""); |
83238153 TT |
1404 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); |
1405 | textdomain(NLS_CAT_NAME); | |
1406 | #endif | |
1407 | if (argc && *argv) | |
1408 | program_name = *argv; | |
a6d8302b | 1409 | add_error_table(&et_ext2_error_table); |
83238153 | 1410 | |
118d7dac TT |
1411 | if (strcmp(get_progname(argv[0]), "findfs") == 0) |
1412 | do_findfs(argc, argv); | |
83238153 TT |
1413 | if (strcmp(get_progname(argv[0]), "e2label") == 0) |
1414 | parse_e2label_options(argc, argv); | |
1415 | else | |
1416 | parse_tune2fs_options(argc, argv); | |
efc6f628 | 1417 | |
2a29f135 TT |
1418 | #ifdef CONFIG_TESTIO_DEBUG |
1419 | io_ptr = test_io_manager; | |
1420 | test_io_backing_manager = unix_io_manager; | |
1421 | #else | |
1422 | io_ptr = unix_io_manager; | |
1423 | #endif | |
64d588cf | 1424 | |
d887f88d | 1425 | retry_open: |
efc6f628 | 1426 | retval = ext2fs_open2(device_name, io_options, open_flag, |
2e8ca9a2 | 1427 | 0, 0, io_ptr, &fs); |
818180cd | 1428 | if (retval) { |
d9c56d3c | 1429 | com_err (program_name, retval, _("while trying to open %s"), |
3839e657 | 1430 | device_name); |
7141b54b TT |
1431 | fprintf(stderr, |
1432 | _("Couldn't find valid filesystem superblock.\n")); | |
3839e657 TT |
1433 | exit(1); |
1434 | } | |
d887f88d TT |
1435 | |
1436 | if (I_flag && !io_ptr_orig) { | |
1437 | /* | |
1438 | * Check the inode size is right so we can issue an | |
1439 | * error message and bail before setting up the tdb | |
1440 | * file. | |
1441 | */ | |
1442 | if (new_inode_size == EXT2_INODE_SIZE(fs->super)) { | |
1443 | fprintf(stderr, _("The inode size is already %d\n"), | |
1444 | new_inode_size); | |
1445 | exit(1); | |
1446 | } | |
1447 | if (new_inode_size < EXT2_INODE_SIZE(fs->super)) { | |
1448 | fprintf(stderr, _("Shrinking the inode size is " | |
1449 | "not supported\n")); | |
1450 | exit(1); | |
1451 | } | |
1452 | ||
1453 | /* | |
1454 | * If inode resize is requested use the | |
1455 | * Undo I/O manager | |
1456 | */ | |
1457 | io_ptr_orig = io_ptr; | |
1458 | retval = tune2fs_setup_tdb(device_name, &io_ptr); | |
1459 | if (retval) | |
1460 | exit(1); | |
1461 | if (io_ptr != io_ptr_orig) { | |
1462 | ext2fs_close(fs); | |
1463 | goto retry_open; | |
1464 | } | |
1465 | } | |
1466 | ||
83238153 | 1467 | sb = fs->super; |
058ad1c7 | 1468 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
2be8fe43 | 1469 | |
83238153 TT |
1470 | if (print_label) { |
1471 | /* For e2label emulation */ | |
c8c071a0 TT |
1472 | printf("%.*s\n", (int) sizeof(sb->s_volume_name), |
1473 | sb->s_volume_name); | |
a6d8302b | 1474 | remove_error_table(&et_ext2_error_table); |
83238153 TT |
1475 | exit(0); |
1476 | } | |
2be8fe43 | 1477 | |
d06863f0 TT |
1478 | retval = ext2fs_check_if_mounted(device_name, &mount_flags); |
1479 | if (retval) { | |
1480 | com_err("ext2fs_check_if_mount", retval, | |
1481 | _("while determining whether %s is mounted."), | |
1482 | device_name); | |
1483 | exit(1); | |
b21e38a0 | 1484 | } |
63985320 TT |
1485 | /* Normally we only need to write out the superblock */ |
1486 | fs->flags |= EXT2_FLAG_SUPER_ONLY; | |
3839e657 | 1487 | |
1e3472c5 | 1488 | if (c_flag) { |
b21e38a0 | 1489 | sb->s_max_mnt_count = max_mount_count; |
3839e657 | 1490 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 1491 | printf (_("Setting maximal mount count to %d\n"), |
1e3472c5 | 1492 | max_mount_count); |
3839e657 | 1493 | } |
1e3472c5 | 1494 | if (C_flag) { |
b21e38a0 | 1495 | sb->s_mnt_count = mount_count; |
1e3472c5 | 1496 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 1497 | printf (_("Setting current mount count to %d\n"), mount_count); |
1e3472c5 TT |
1498 | } |
1499 | if (e_flag) { | |
b21e38a0 | 1500 | sb->s_errors = errors; |
3839e657 | 1501 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 1502 | printf (_("Setting error behavior to %d\n"), errors); |
3839e657 | 1503 | } |
b21e38a0 TT |
1504 | if (g_flag) { |
1505 | sb->s_def_resgid = resgid; | |
f3db3566 | 1506 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 1507 | printf (_("Setting reserved blocks gid to %lu\n"), resgid); |
f3db3566 | 1508 | } |
818180cd | 1509 | if (i_flag) { |
b21e38a0 | 1510 | sb->s_checkinterval = interval; |
3839e657 | 1511 | ext2fs_mark_super_dirty(fs); |
f35fd3d5 | 1512 | printf (_("Setting interval between checks to %lu seconds\n"), interval); |
3839e657 | 1513 | } |
818180cd | 1514 | if (m_flag) { |
9ff8ece5 TT |
1515 | sb->s_r_blocks_count = (unsigned int) (reserved_ratio * |
1516 | sb->s_blocks_count / 100.0); | |
3839e657 | 1517 | ext2fs_mark_super_dirty(fs); |
ce911145 | 1518 | printf (_("Setting reserved blocks percentage to %g%% (%u blocks)\n"), |
b21e38a0 | 1519 | reserved_ratio, sb->s_r_blocks_count); |
3839e657 | 1520 | } |
818180cd | 1521 | if (r_flag) { |
22ba4c1d | 1522 | if (reserved_blocks >= sb->s_blocks_count/2) { |
f3db3566 | 1523 | com_err (program_name, 0, |
54434927 | 1524 | _("reserved blocks count is too big (%lu)"), |
f3db3566 TT |
1525 | reserved_blocks); |
1526 | exit (1); | |
1527 | } | |
b21e38a0 | 1528 | sb->s_r_blocks_count = reserved_blocks; |
f3db3566 | 1529 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 1530 | printf (_("Setting reserved blocks count to %lu\n"), |
f3db3566 TT |
1531 | reserved_blocks); |
1532 | } | |
521e3685 | 1533 | if (s_flag == 1) { |
521e3685 TT |
1534 | if (sb->s_feature_ro_compat & |
1535 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) | |
54434927 TT |
1536 | fputs(_("\nThe filesystem already has sparse " |
1537 | "superblocks.\n"), stderr); | |
521e3685 TT |
1538 | else { |
1539 | sb->s_feature_ro_compat |= | |
1540 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | |
b21e38a0 | 1541 | sb->s_state &= ~EXT2_VALID_FS; |
521e3685 | 1542 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 1543 | printf(_("\nSparse superblock flag set. %s"), |
a4fa100c | 1544 | _(please_fsck)); |
521e3685 | 1545 | } |
521e3685 TT |
1546 | } |
1547 | if (s_flag == 0) { | |
ff662d5d TT |
1548 | fputs(_("\nClearing the sparse superflag not supported.\n"), |
1549 | stderr); | |
1550 | exit(1); | |
521e3685 | 1551 | } |
d4de4aa9 TT |
1552 | if (T_flag) { |
1553 | sb->s_lastcheck = last_check_time; | |
1554 | ext2fs_mark_super_dirty(fs); | |
1555 | printf(_("Setting time filesystem last checked to %s\n"), | |
1556 | ctime(&last_check_time)); | |
1557 | } | |
b21e38a0 TT |
1558 | if (u_flag) { |
1559 | sb->s_def_resuid = resuid; | |
f3db3566 | 1560 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 1561 | printf (_("Setting reserved blocks uid to %lu\n"), resuid); |
f3db3566 | 1562 | } |
1e3472c5 | 1563 | if (L_flag) { |
a789d840 | 1564 | if (strlen(new_label) > sizeof(sb->s_volume_name)) |
efc6f628 | 1565 | fputs(_("Warning: label too long, truncating.\n"), |
54434927 | 1566 | stderr); |
1e3472c5 TT |
1567 | memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name)); |
1568 | strncpy(sb->s_volume_name, new_label, | |
1569 | sizeof(sb->s_volume_name)); | |
1570 | ext2fs_mark_super_dirty(fs); | |
1571 | } | |
1572 | if (M_flag) { | |
1573 | memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); | |
1574 | strncpy(sb->s_last_mounted, new_last_mounted, | |
1575 | sizeof(sb->s_last_mounted)); | |
1576 | ext2fs_mark_super_dirty(fs); | |
1577 | } | |
a0c3fd5e TT |
1578 | if (mntopts_cmd) |
1579 | update_mntopts(fs, mntopts_cmd); | |
63985320 TT |
1580 | if (features_cmd) |
1581 | update_feature_set(fs, features_cmd); | |
6cb27404 TT |
1582 | if (extended_cmd) |
1583 | parse_extended_opts(fs, extended_cmd); | |
dc2ec525 | 1584 | if (journal_size || journal_device) |
63985320 | 1585 | add_journal(fs); |
efc6f628 | 1586 | |
1e3472c5 | 1587 | if (U_flag) { |
4d0f2283 TT |
1588 | if ((strcasecmp(new_UUID, "null") == 0) || |
1589 | (strcasecmp(new_UUID, "clear") == 0)) { | |
1e3472c5 | 1590 | uuid_clear(sb->s_uuid); |
63985320 TT |
1591 | } else if (strcasecmp(new_UUID, "time") == 0) { |
1592 | uuid_generate_time(sb->s_uuid); | |
1e3472c5 TT |
1593 | } else if (strcasecmp(new_UUID, "random") == 0) { |
1594 | uuid_generate(sb->s_uuid); | |
1595 | } else if (uuid_parse(new_UUID, sb->s_uuid)) { | |
d9c56d3c | 1596 | com_err(program_name, 0, _("Invalid UUID format\n")); |
1e3472c5 TT |
1597 | exit(1); |
1598 | } | |
1599 | ext2fs_mark_super_dirty(fs); | |
1600 | } | |
64d588cf AK |
1601 | if (I_flag) { |
1602 | if (mount_flags & EXT2_MF_MOUNTED) { | |
1603 | fputs(_("The inode size may only be " | |
1604 | "changed when the filesystem is " | |
1605 | "unmounted.\n"), stderr); | |
1606 | exit(1); | |
1607 | } | |
1608 | /* | |
1609 | * We want to update group descriptor also | |
1610 | * with the new free inode count | |
1611 | */ | |
1612 | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; | |
1613 | if (resize_inode(fs, new_inode_size)) { | |
1614 | fputs(_("Error in resizing the inode size.\n" | |
577b5c43 | 1615 | "Run e2undo to undo the " |
64d588cf AK |
1616 | "file system changes. \n"), stderr); |
1617 | } else { | |
721b367a | 1618 | printf (_("Setting inode size %lu\n"), |
64d588cf AK |
1619 | new_inode_size); |
1620 | } | |
1621 | } | |
1e3472c5 | 1622 | |
3839e657 | 1623 | if (l_flag) |
b21e38a0 | 1624 | list_super (sb); |
0c17cb25 TT |
1625 | if (stride_set) { |
1626 | sb->s_raid_stride = stride; | |
1627 | ext2fs_mark_super_dirty(fs); | |
1628 | printf(_("Setting stride size to %d\n"), stride); | |
1629 | } | |
1630 | if (stripe_width_set) { | |
1631 | sb->s_raid_stripe_width = stripe_width; | |
1632 | ext2fs_mark_super_dirty(fs); | |
1633 | printf(_("Setting stripe width to %d\n"), stripe_width); | |
1634 | } | |
a6d8302b | 1635 | remove_error_table(&et_ext2_error_table); |
c007bc06 | 1636 | return (ext2fs_close (fs) ? 1 : 0); |
3839e657 | 1637 | } |