]>
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 | ||
b969b1b8 MA |
28 | #define _XOPEN_SOURCE /* for inclusion of strptime() */ |
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> |
3839e657 | 45 | |
54c637d4 | 46 | #include "ext2fs/ext2_fs.h" |
3839e657 TT |
47 | #include "ext2fs/ext2fs.h" |
48 | #include "et/com_err.h" | |
1e3472c5 | 49 | #include "uuid/uuid.h" |
3839e657 | 50 | #include "e2p/e2p.h" |
dc2ec525 | 51 | #include "jfs_user.h" |
63985320 | 52 | #include "util.h" |
ed1b33e8 | 53 | #include "blkid/blkid.h" |
3839e657 TT |
54 | |
55 | #include "../version.h" | |
d9c56d3c | 56 | #include "nls-enable.h" |
3839e657 TT |
57 | |
58 | const char * program_name = "tune2fs"; | |
63985320 | 59 | char * device_name; |
c8c071a0 | 60 | char * new_label, *new_last_mounted, *new_UUID; |
4d0f2283 | 61 | static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag; |
d4de4aa9 TT |
62 | static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag; |
63 | static time_t last_check_time; | |
83238153 | 64 | static int print_label; |
63985320 TT |
65 | static int max_mount_count, mount_count, mount_flags; |
66 | static unsigned long interval, reserved_ratio, reserved_blocks; | |
67 | static unsigned long resgid, resuid; | |
68 | static unsigned short errors; | |
83238153 TT |
69 | static int open_flag; |
70 | static char *features_cmd; | |
a0c3fd5e | 71 | static char *mntopts_cmd; |
3839e657 | 72 | |
63985320 TT |
73 | int journal_size, journal_flags; |
74 | char *journal_device; | |
75 | ||
76 | static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n"); | |
1e3472c5 | 77 | |
3e699064 TT |
78 | void do_findfs(int argc, char **argv); |
79 | ||
818180cd | 80 | static void usage(void) |
3839e657 | 81 | { |
b21e38a0 TT |
82 | fprintf(stderr, |
83 | _("Usage: %s [-c max-mounts-count] [-e errors-behavior] " | |
84 | "[-g group]\n" | |
a0c3fd5e TT |
85 | "\t[-i interval[d|m|w]] [-j] [-J journal-options]\n" |
86 | "\t[-l] [-s sparse-flag] [-m reserved-blocks-percent]\n" | |
87 | "\t[-o [^]mount-options[,...]] [-r reserved-blocks-count]\n" | |
88 | "\t[-u user] [-C mount-count] [-L volume-label] " | |
89 | "[-M last-mounted-dir]\n" | |
d4de4aa9 TT |
90 | "\t[-O [^]feature[,...]] [-T last-check-time] [-U UUID]" |
91 | " device\n"), program_name); | |
3839e657 TT |
92 | exit (1); |
93 | } | |
94 | ||
896938d5 | 95 | static __u32 ok_features[3] = { |
843049c4 TT |
96 | EXT3_FEATURE_COMPAT_HAS_JOURNAL | |
97 | EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */ | |
896938d5 TT |
98 | EXT2_FEATURE_INCOMPAT_FILETYPE, /* Incompat */ |
99 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER /* R/O compat */ | |
100 | }; | |
101 | ||
dc2ec525 TT |
102 | /* |
103 | * Remove an external journal from the filesystem | |
104 | */ | |
105 | static void remove_journal_device(ext2_filsys fs) | |
106 | { | |
4ea7bd04 | 107 | char *journal_path; |
dc2ec525 TT |
108 | ext2_filsys jfs; |
109 | char buf[1024]; | |
110 | journal_superblock_t *jsb; | |
111 | int i, nr_users; | |
112 | errcode_t retval; | |
4d0f2283 | 113 | int commit_remove_journal = 0; |
2a29f135 | 114 | io_manager io_ptr; |
4d0f2283 TT |
115 | |
116 | if (f_flag) | |
117 | commit_remove_journal = 1; /* force removal even if error */ | |
dc2ec525 | 118 | |
2d15576d | 119 | uuid_unparse(fs->super->s_journal_uuid, buf); |
ed1b33e8 | 120 | journal_path = blkid_get_devname(NULL, "UUID", buf); |
2d15576d | 121 | |
4ea7bd04 TT |
122 | if (!journal_path) { |
123 | journal_path = | |
2d15576d | 124 | ext2fs_find_block_device(fs->super->s_journal_dev); |
4ea7bd04 | 125 | if (!journal_path) |
2d15576d AD |
126 | return; |
127 | } | |
dc2ec525 | 128 | |
2a29f135 TT |
129 | #ifdef CONFIG_TESTIO_DEBUG |
130 | io_ptr = test_io_manager; | |
131 | test_io_backing_manager = unix_io_manager; | |
132 | #else | |
133 | io_ptr = unix_io_manager; | |
134 | #endif | |
4ea7bd04 | 135 | retval = ext2fs_open(journal_path, EXT2_FLAG_RW| |
dc2ec525 | 136 | EXT2_FLAG_JOURNAL_DEV_OK, 0, |
2a29f135 | 137 | fs->blocksize, io_ptr, &jfs); |
dc2ec525 TT |
138 | if (retval) { |
139 | com_err(program_name, retval, | |
140 | _("while trying to open external journal")); | |
4d0f2283 | 141 | goto no_valid_journal; |
dc2ec525 TT |
142 | } |
143 | if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { | |
7141b54b | 144 | fprintf(stderr, _("%s is not a journal device.\n"), |
4ea7bd04 | 145 | journal_path); |
4d0f2283 | 146 | goto no_valid_journal; |
dc2ec525 TT |
147 | } |
148 | ||
149 | /* Get the journal superblock */ | |
150 | if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) { | |
151 | com_err(program_name, retval, | |
152 | _("while reading journal superblock")); | |
4d0f2283 | 153 | goto no_valid_journal; |
dc2ec525 TT |
154 | } |
155 | ||
156 | jsb = (journal_superblock_t *) buf; | |
157 | if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || | |
158 | (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) { | |
54434927 | 159 | fputs(_("Journal superblock not found!\n"), stderr); |
4d0f2283 | 160 | goto no_valid_journal; |
dc2ec525 TT |
161 | } |
162 | ||
163 | /* Find the filesystem UUID */ | |
164 | nr_users = ntohl(jsb->s_nr_users); | |
165 | for (i=0; i < nr_users; i++) { | |
166 | if (memcmp(fs->super->s_uuid, | |
167 | &jsb->s_users[i*16], 16) == 0) | |
168 | break; | |
169 | } | |
170 | if (i >= nr_users) { | |
54434927 TT |
171 | fputs(_("Filesystem's UUID not found on journal device.\n"), |
172 | stderr); | |
4d0f2283 TT |
173 | commit_remove_journal = 1; |
174 | goto no_valid_journal; | |
dc2ec525 TT |
175 | } |
176 | nr_users--; | |
177 | for (i=0; i < nr_users; i++) | |
178 | memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16); | |
179 | jsb->s_nr_users = htonl(nr_users); | |
180 | ||
181 | /* Write back the journal superblock */ | |
182 | if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) { | |
183 | com_err(program_name, retval, | |
184 | "while writing journal superblock."); | |
4d0f2283 | 185 | goto no_valid_journal; |
dc2ec525 TT |
186 | } |
187 | ||
4d0f2283 TT |
188 | commit_remove_journal = 1; |
189 | ||
190 | no_valid_journal: | |
191 | if (commit_remove_journal == 0) { | |
54434927 | 192 | fputs(_("Journal NOT removed\n"), stderr); |
4d0f2283 TT |
193 | exit(1); |
194 | } | |
dc2ec525 | 195 | fs->super->s_journal_dev = 0; |
ed1b33e8 | 196 | uuid_clear(fs->super->s_journal_uuid); |
dc2ec525 | 197 | ext2fs_mark_super_dirty(fs); |
54434927 | 198 | fputs(_("Journal removed\n"), stdout); |
4ea7bd04 | 199 | free(journal_path); |
dc2ec525 TT |
200 | } |
201 | ||
194686bb TT |
202 | /* Helper function for remove_journal_inode */ |
203 | static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr, | |
54434927 TT |
204 | int blockcnt EXT2FS_ATTR((unused)), |
205 | void *private EXT2FS_ATTR((unused))) | |
194686bb TT |
206 | { |
207 | blk_t block; | |
208 | int group; | |
209 | ||
210 | block = *blocknr; | |
211 | ext2fs_unmark_block_bitmap(fs->block_map,block); | |
212 | group = ext2fs_group_of_blk(fs, block); | |
213 | fs->group_desc[group].bg_free_blocks_count++; | |
214 | fs->super->s_free_blocks_count++; | |
215 | return 0; | |
216 | } | |
217 | ||
218 | /* | |
219 | * Remove the journal inode from the filesystem | |
220 | */ | |
221 | static void remove_journal_inode(ext2_filsys fs) | |
222 | { | |
223 | struct ext2_inode inode; | |
224 | errcode_t retval; | |
225 | ino_t ino = fs->super->s_journal_inum; | |
194686bb TT |
226 | |
227 | retval = ext2fs_read_inode(fs, ino, &inode); | |
228 | if (retval) { | |
229 | com_err(program_name, retval, | |
230 | _("while reading journal inode")); | |
231 | exit(1); | |
232 | } | |
233 | if (ino == EXT2_JOURNAL_INO) { | |
234 | retval = ext2fs_read_bitmaps(fs); | |
235 | if (retval) { | |
236 | com_err(program_name, retval, | |
237 | _("while reading bitmaps")); | |
238 | exit(1); | |
239 | } | |
240 | retval = ext2fs_block_iterate(fs, ino, 0, NULL, | |
241 | release_blocks_proc, NULL); | |
242 | if (retval) { | |
243 | com_err(program_name, retval, | |
244 | _("while clearing journal inode")); | |
245 | exit(1); | |
246 | } | |
247 | memset(&inode, 0, sizeof(inode)); | |
248 | ext2fs_mark_bb_dirty(fs); | |
194686bb TT |
249 | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; |
250 | } else | |
251 | inode.i_flags &= ~EXT2_IMMUTABLE_FL; | |
252 | retval = ext2fs_write_inode(fs, ino, &inode); | |
253 | if (retval) { | |
254 | com_err(program_name, retval, | |
255 | _("while writing journal inode")); | |
256 | exit(1); | |
257 | } | |
258 | fs->super->s_journal_inum = 0; | |
259 | ext2fs_mark_super_dirty(fs); | |
260 | } | |
dc2ec525 | 261 | |
a0c3fd5e TT |
262 | /* |
263 | * Update the default mount options | |
264 | */ | |
265 | static void update_mntopts(ext2_filsys fs, char *mntopts) | |
266 | { | |
267 | struct ext2_super_block *sb= fs->super; | |
268 | ||
269 | if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) { | |
270 | fprintf(stderr, _("Invalid mount option set: %s\n"), | |
271 | mntopts); | |
272 | exit(1); | |
273 | } | |
274 | ext2fs_mark_super_dirty(fs); | |
275 | } | |
276 | ||
63985320 TT |
277 | /* |
278 | * Update the feature set as provided by the user. | |
279 | */ | |
c8c071a0 | 280 | static void update_feature_set(ext2_filsys fs, char *features) |
63985320 TT |
281 | { |
282 | int sparse, old_sparse, filetype, old_filetype; | |
843049c4 | 283 | int journal, old_journal, dxdir, old_dxdir; |
63985320 | 284 | struct ext2_super_block *sb= fs->super; |
63985320 TT |
285 | |
286 | old_sparse = sb->s_feature_ro_compat & | |
287 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | |
288 | old_filetype = sb->s_feature_incompat & | |
289 | EXT2_FEATURE_INCOMPAT_FILETYPE; | |
290 | old_journal = sb->s_feature_compat & | |
291 | EXT3_FEATURE_COMPAT_HAS_JOURNAL; | |
843049c4 TT |
292 | old_dxdir = sb->s_feature_compat & |
293 | EXT2_FEATURE_COMPAT_DIR_INDEX; | |
c8c071a0 | 294 | if (e2p_edit_feature(features, &sb->s_feature_compat, |
63985320 TT |
295 | ok_features)) { |
296 | fprintf(stderr, _("Invalid filesystem option set: %s\n"), | |
c8c071a0 | 297 | features); |
63985320 TT |
298 | exit(1); |
299 | } | |
300 | sparse = sb->s_feature_ro_compat & | |
301 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | |
302 | filetype = sb->s_feature_incompat & | |
303 | EXT2_FEATURE_INCOMPAT_FILETYPE; | |
304 | journal = sb->s_feature_compat & | |
305 | EXT3_FEATURE_COMPAT_HAS_JOURNAL; | |
843049c4 TT |
306 | dxdir = sb->s_feature_compat & |
307 | EXT2_FEATURE_COMPAT_DIR_INDEX; | |
63985320 TT |
308 | if (old_journal && !journal) { |
309 | if ((mount_flags & EXT2_MF_MOUNTED) && | |
310 | !(mount_flags & EXT2_MF_READONLY)) { | |
54434927 TT |
311 | fputs(_("The has_journal flag may only be " |
312 | "cleared when the filesystem is\n" | |
313 | "unmounted or mounted " | |
314 | "read-only.\n"), stderr); | |
63985320 TT |
315 | exit(1); |
316 | } | |
317 | if (sb->s_feature_incompat & | |
318 | EXT3_FEATURE_INCOMPAT_RECOVER) { | |
54434927 TT |
319 | fputs(_("The needs_recovery flag is set. " |
320 | "Please run e2fsck before clearing\n" | |
321 | "the has_journal flag.\n"), stderr); | |
63985320 TT |
322 | exit(1); |
323 | } | |
63985320 | 324 | if (sb->s_journal_inum) { |
194686bb | 325 | remove_journal_inode(fs); |
63985320 | 326 | } |
de49f015 | 327 | if (sb->s_journal_dev) { |
dc2ec525 | 328 | remove_journal_device(fs); |
de49f015 | 329 | } |
63985320 TT |
330 | } |
331 | if (journal && !old_journal) { | |
332 | /* | |
333 | * If adding a journal flag, let the create journal | |
334 | * code below handle creating setting the flag and | |
335 | * creating the journal. We supply a default size if | |
336 | * necessary. | |
337 | */ | |
dc2ec525 TT |
338 | if (!journal_size) |
339 | journal_size = -1; | |
08dd830d | 340 | sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; |
63985320 | 341 | } |
843049c4 TT |
342 | if (dxdir && !old_dxdir) { |
343 | if (!sb->s_def_hash_version) | |
344 | sb->s_def_hash_version = EXT2_HASH_TEA; | |
345 | if (uuid_is_null((unsigned char *) sb->s_hash_seed)) | |
346 | uuid_generate((unsigned char *) sb->s_hash_seed); | |
347 | } | |
dc2ec525 | 348 | |
63985320 TT |
349 | if (sb->s_rev_level == EXT2_GOOD_OLD_REV && |
350 | (sb->s_feature_compat || sb->s_feature_ro_compat || | |
351 | sb->s_feature_incompat)) | |
352 | ext2fs_update_dynamic_rev(fs); | |
353 | if ((sparse != old_sparse) || | |
194686bb | 354 | (filetype != old_filetype)) { |
63985320 TT |
355 | sb->s_state &= ~EXT2_VALID_FS; |
356 | printf("\n%s\n", _(please_fsck)); | |
357 | } | |
358 | ext2fs_mark_super_dirty(fs); | |
359 | } | |
360 | ||
361 | /* | |
362 | * Add a journal to the filesystem. | |
363 | */ | |
364 | static void add_journal(ext2_filsys fs) | |
365 | { | |
366 | unsigned long journal_blocks; | |
367 | errcode_t retval; | |
16ed5b3a | 368 | ext2_filsys jfs; |
2a29f135 | 369 | io_manager io_ptr; |
63985320 TT |
370 | |
371 | if (fs->super->s_feature_compat & | |
372 | EXT3_FEATURE_COMPAT_HAS_JOURNAL) { | |
54434927 | 373 | fputs(_("The filesystem already has a journal.\n"), stderr); |
2d15576d | 374 | goto err; |
63985320 | 375 | } |
63985320 TT |
376 | if (journal_device) { |
377 | check_plausibility(journal_device); | |
378 | check_mount(journal_device, 0, _("journal")); | |
2a29f135 TT |
379 | #ifdef CONFIG_TESTIO_DEBUG |
380 | io_ptr = test_io_manager; | |
381 | test_io_backing_manager = unix_io_manager; | |
382 | #else | |
383 | io_ptr = unix_io_manager; | |
384 | #endif | |
16ed5b3a TT |
385 | retval = ext2fs_open(journal_device, EXT2_FLAG_RW| |
386 | EXT2_FLAG_JOURNAL_DEV_OK, 0, | |
2a29f135 | 387 | fs->blocksize, io_ptr, &jfs); |
16ed5b3a TT |
388 | if (retval) { |
389 | com_err(program_name, retval, | |
1d08d9bf | 390 | _("\n\twhile trying to open journal on %s\n"), |
16ed5b3a | 391 | journal_device); |
2d15576d | 392 | goto err; |
16ed5b3a | 393 | } |
63985320 TT |
394 | printf(_("Creating journal on device %s: "), |
395 | journal_device); | |
4055ef73 | 396 | fflush(stdout); |
2d15576d | 397 | |
16ed5b3a | 398 | retval = ext2fs_add_journal_device(fs, jfs); |
2d15576d | 399 | ext2fs_close(jfs); |
63985320 TT |
400 | if (retval) { |
401 | com_err (program_name, retval, | |
8d641749 | 402 | _("while adding filesystem to journal on %s"), |
63985320 | 403 | journal_device); |
2d15576d | 404 | goto err; |
63985320 | 405 | } |
54434927 | 406 | fputs(_("done\n"), stdout); |
63985320 | 407 | } else if (journal_size) { |
54434927 | 408 | fputs(_("Creating journal inode: "), stdout); |
63985320 | 409 | fflush(stdout); |
2537b6d0 TT |
410 | journal_blocks = figure_journal_size(journal_size, fs); |
411 | ||
63985320 TT |
412 | retval = ext2fs_add_journal_inode(fs, journal_blocks, |
413 | journal_flags); | |
414 | if (retval) { | |
7141b54b | 415 | fprintf(stderr, "\n"); |
63985320 | 416 | com_err(program_name, retval, |
1d08d9bf | 417 | _("\n\twhile trying to create journal file")); |
63985320 | 418 | exit(1); |
1d08d9bf | 419 | } else |
54434927 | 420 | fputs(_("done\n"), stdout); |
63985320 TT |
421 | /* |
422 | * If the filesystem wasn't mounted, we need to force | |
423 | * the block group descriptors out. | |
424 | */ | |
425 | if ((mount_flags & EXT2_MF_MOUNTED) == 0) | |
426 | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; | |
427 | } | |
66cf2f60 | 428 | print_check_message(fs); |
2d15576d AD |
429 | return; |
430 | ||
431 | err: | |
432 | if (journal_device) | |
433 | free(journal_device); | |
434 | exit(1); | |
63985320 TT |
435 | } |
436 | ||
83238153 | 437 | |
c8c071a0 | 438 | static void parse_e2label_options(int argc, char ** argv) |
83238153 TT |
439 | { |
440 | if ((argc < 2) || (argc > 3)) { | |
54434927 | 441 | fputs(_("Usage: e2label device [newlabel]\n"), stderr); |
83238153 TT |
442 | exit(1); |
443 | } | |
332f2c23 | 444 | device_name = blkid_get_devname(NULL, argv[1], NULL); |
817e49e3 TT |
445 | if (!device_name) { |
446 | com_err("e2label", 0, _("Unable to resolve '%s'"), | |
447 | argv[1]); | |
448 | exit(1); | |
449 | } | |
83238153 | 450 | if (argc == 3) { |
2d15576d | 451 | open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK; |
83238153 TT |
452 | L_flag = 1; |
453 | new_label = argv[2]; | |
454 | } else | |
455 | print_label++; | |
456 | } | |
457 | ||
d4de4aa9 TT |
458 | static time_t parse_time(char *str) |
459 | { | |
460 | struct tm ts; | |
461 | ||
462 | if (strcmp(str, "now") == 0) { | |
463 | return (time(0)); | |
464 | } | |
465 | memset(&ts, 0, sizeof(ts)); | |
bc7c14e0 | 466 | #ifdef HAVE_STRPTIME |
d4de4aa9 | 467 | strptime(optarg, "%Y%m%d%H%M%S", &ts); |
bc7c14e0 TT |
468 | #else |
469 | sscanf(optarg, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon, | |
470 | &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec); | |
471 | ts.tm_year -= 1900; | |
472 | ts.tm_mon -= 1; | |
473 | if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 || | |
474 | ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 || | |
475 | ts.tm_min > 59 || ts.tm_sec > 61) | |
476 | ts.tm_mday = 0; | |
477 | #endif | |
d4de4aa9 TT |
478 | if (ts.tm_mday == 0) { |
479 | com_err(program_name, 0, | |
480 | _("Couldn't parse date/time specifier: %s"), | |
481 | str); | |
482 | usage(); | |
483 | } | |
484 | return (mktime(&ts)); | |
485 | } | |
83238153 | 486 | |
c8c071a0 | 487 | static void parse_tune2fs_options(int argc, char **argv) |
3839e657 | 488 | { |
519149fb | 489 | int c; |
3839e657 | 490 | char * tmp; |
f3db3566 TT |
491 | struct group * gr; |
492 | struct passwd * pw; | |
3839e657 | 493 | |
0f8973fb | 494 | printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); |
a0c3fd5e | 495 | while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:J:L:M:O:T:U:")) != EOF) |
3839e657 TT |
496 | switch (c) |
497 | { | |
498 | case 'c': | |
45d9e2ff | 499 | max_mount_count = strtol (optarg, &tmp, 0); |
818180cd | 500 | if (*tmp || max_mount_count > 16000) { |
3839e657 | 501 | com_err (program_name, 0, |
d9c56d3c | 502 | _("bad mounts count - %s"), |
3839e657 | 503 | optarg); |
818180cd | 504 | usage(); |
3839e657 | 505 | } |
ce57f14f TT |
506 | if (max_mount_count == 0) |
507 | max_mount_count = -1; | |
3839e657 | 508 | c_flag = 1; |
1e3472c5 TT |
509 | open_flag = EXT2_FLAG_RW; |
510 | break; | |
511 | case 'C': | |
512 | mount_count = strtoul (optarg, &tmp, 0); | |
818180cd | 513 | if (*tmp || mount_count > 16000) { |
1e3472c5 | 514 | com_err (program_name, 0, |
d9c56d3c | 515 | _("bad mounts count - %s"), |
1e3472c5 | 516 | optarg); |
818180cd | 517 | usage(); |
1e3472c5 TT |
518 | } |
519 | C_flag = 1; | |
520 | open_flag = EXT2_FLAG_RW; | |
3839e657 TT |
521 | break; |
522 | case 'e': | |
523 | if (strcmp (optarg, "continue") == 0) | |
524 | errors = EXT2_ERRORS_CONTINUE; | |
525 | else if (strcmp (optarg, "remount-ro") == 0) | |
526 | errors = EXT2_ERRORS_RO; | |
527 | else if (strcmp (optarg, "panic") == 0) | |
528 | errors = EXT2_ERRORS_PANIC; | |
818180cd | 529 | else { |
3839e657 | 530 | com_err (program_name, 0, |
d9c56d3c | 531 | _("bad error behavior - %s"), |
3839e657 | 532 | optarg); |
818180cd | 533 | usage(); |
3839e657 TT |
534 | } |
535 | e_flag = 1; | |
1e3472c5 | 536 | open_flag = EXT2_FLAG_RW; |
3839e657 | 537 | break; |
4d0f2283 TT |
538 | case 'f': /* Force */ |
539 | f_flag = 1; | |
540 | break; | |
f3db3566 TT |
541 | case 'g': |
542 | resgid = strtoul (optarg, &tmp, 0); | |
818180cd | 543 | if (*tmp) { |
f3db3566 TT |
544 | gr = getgrnam (optarg); |
545 | if (gr == NULL) | |
546 | tmp = optarg; | |
a418d3ad | 547 | else { |
f3db3566 | 548 | resgid = gr->gr_gid; |
a418d3ad TT |
549 | *tmp =0; |
550 | } | |
f3db3566 | 551 | } |
818180cd | 552 | if (*tmp) { |
f3db3566 | 553 | com_err (program_name, 0, |
d9c56d3c | 554 | _("bad gid/group name - %s"), |
f3db3566 | 555 | optarg); |
818180cd | 556 | usage(); |
f3db3566 TT |
557 | } |
558 | g_flag = 1; | |
1e3472c5 | 559 | open_flag = EXT2_FLAG_RW; |
f3db3566 | 560 | break; |
3839e657 TT |
561 | case 'i': |
562 | interval = strtoul (optarg, &tmp, 0); | |
1e3472c5 TT |
563 | switch (*tmp) { |
564 | case 's': | |
565 | tmp++; | |
566 | break; | |
567 | case '\0': | |
568 | case 'd': | |
569 | case 'D': /* days */ | |
570 | interval *= 86400; | |
571 | if (*tmp != '\0') | |
f3db3566 | 572 | tmp++; |
1e3472c5 TT |
573 | break; |
574 | case 'm': | |
575 | case 'M': /* months! */ | |
576 | interval *= 86400 * 30; | |
577 | tmp++; | |
578 | break; | |
579 | case 'w': | |
580 | case 'W': /* weeks */ | |
581 | interval *= 86400 * 7; | |
582 | tmp++; | |
583 | break; | |
3839e657 | 584 | } |
818180cd | 585 | if (*tmp || interval > (365 * 86400)) { |
3839e657 | 586 | com_err (program_name, 0, |
d9c56d3c | 587 | _("bad interval - %s"), optarg); |
818180cd | 588 | usage(); |
3839e657 TT |
589 | } |
590 | i_flag = 1; | |
1e3472c5 | 591 | open_flag = EXT2_FLAG_RW; |
3839e657 | 592 | break; |
63985320 | 593 | case 'j': |
dc2ec525 TT |
594 | if (!journal_size) |
595 | journal_size = -1; | |
4d0f2283 | 596 | open_flag = EXT2_FLAG_RW; |
dc2ec525 TT |
597 | break; |
598 | case 'J': | |
599 | parse_journal_opts(optarg); | |
63985320 TT |
600 | open_flag = EXT2_FLAG_RW; |
601 | break; | |
08dd830d TT |
602 | case 'l': |
603 | l_flag = 1; | |
604 | break; | |
1e3472c5 TT |
605 | case 'L': |
606 | new_label = optarg; | |
607 | L_flag = 1; | |
2d15576d AD |
608 | open_flag = EXT2_FLAG_RW | |
609 | EXT2_FLAG_JOURNAL_DEV_OK; | |
1e3472c5 | 610 | break; |
3839e657 TT |
611 | case 'm': |
612 | reserved_ratio = strtoul (optarg, &tmp, 0); | |
818180cd | 613 | if (*tmp || reserved_ratio > 50) { |
3839e657 | 614 | com_err (program_name, 0, |
d9c56d3c | 615 | _("bad reserved block ratio - %s"), |
3839e657 | 616 | optarg); |
818180cd | 617 | usage(); |
3839e657 TT |
618 | } |
619 | m_flag = 1; | |
1e3472c5 TT |
620 | open_flag = EXT2_FLAG_RW; |
621 | break; | |
622 | case 'M': | |
623 | new_last_mounted = optarg; | |
624 | M_flag = 1; | |
625 | open_flag = EXT2_FLAG_RW; | |
3839e657 | 626 | break; |
a0c3fd5e TT |
627 | case 'o': |
628 | if (mntopts_cmd) { | |
629 | com_err (program_name, 0, | |
630 | _("-o may only be specified once")); | |
631 | usage(); | |
632 | } | |
633 | mntopts_cmd = optarg; | |
634 | open_flag = EXT2_FLAG_RW; | |
635 | break; | |
636 | ||
896938d5 | 637 | case 'O': |
d258668d TT |
638 | if (features_cmd) { |
639 | com_err (program_name, 0, | |
640 | _("-O may only be specified once")); | |
641 | usage(); | |
642 | } | |
896938d5 TT |
643 | features_cmd = optarg; |
644 | open_flag = EXT2_FLAG_RW; | |
645 | break; | |
f3db3566 TT |
646 | case 'r': |
647 | reserved_blocks = strtoul (optarg, &tmp, 0); | |
818180cd | 648 | if (*tmp) { |
f3db3566 | 649 | com_err (program_name, 0, |
d9c56d3c | 650 | _("bad reserved blocks count - %s"), |
f3db3566 | 651 | optarg); |
818180cd | 652 | usage(); |
f3db3566 TT |
653 | } |
654 | r_flag = 1; | |
1e3472c5 | 655 | open_flag = EXT2_FLAG_RW; |
f3db3566 | 656 | break; |
521e3685 TT |
657 | case 's': |
658 | s_flag = atoi(optarg); | |
659 | open_flag = EXT2_FLAG_RW; | |
660 | break; | |
d4de4aa9 TT |
661 | case 'T': |
662 | T_flag = 1; | |
663 | last_check_time = parse_time(optarg); | |
664 | open_flag = EXT2_FLAG_RW; | |
665 | break; | |
f3db3566 TT |
666 | case 'u': |
667 | resuid = strtoul (optarg, &tmp, 0); | |
818180cd | 668 | if (*tmp) { |
f3db3566 TT |
669 | pw = getpwnam (optarg); |
670 | if (pw == NULL) | |
671 | tmp = optarg; | |
a418d3ad | 672 | else { |
f3db3566 | 673 | resuid = pw->pw_uid; |
a418d3ad TT |
674 | *tmp = 0; |
675 | } | |
f3db3566 | 676 | } |
818180cd | 677 | if (*tmp) { |
f3db3566 | 678 | com_err (program_name, 0, |
d9c56d3c | 679 | _("bad uid/user name - %s"), |
f3db3566 | 680 | optarg); |
818180cd | 681 | usage(); |
f3db3566 TT |
682 | } |
683 | u_flag = 1; | |
1e3472c5 TT |
684 | open_flag = EXT2_FLAG_RW; |
685 | break; | |
686 | case 'U': | |
687 | new_UUID = optarg; | |
688 | U_flag = 1; | |
2d15576d AD |
689 | open_flag = EXT2_FLAG_RW | |
690 | EXT2_FLAG_JOURNAL_DEV_OK; | |
f3db3566 | 691 | break; |
3839e657 | 692 | default: |
818180cd | 693 | usage(); |
3839e657 TT |
694 | } |
695 | if (optind < argc - 1 || optind == argc) | |
818180cd | 696 | usage(); |
1e3472c5 TT |
697 | if (!open_flag && !l_flag) |
698 | usage(); | |
332f2c23 | 699 | device_name = blkid_get_devname(NULL, argv[optind], NULL); |
817e49e3 TT |
700 | if (!device_name) { |
701 | com_err("tune2fs", 0, _("Unable to resolve '%s'"), | |
702 | argv[optind]); | |
703 | exit(1); | |
704 | } | |
118d7dac TT |
705 | } |
706 | ||
3e699064 | 707 | void do_findfs(int argc, char **argv) |
118d7dac TT |
708 | { |
709 | char *dev; | |
83238153 | 710 | |
118d7dac TT |
711 | if ((argc != 2) || |
712 | (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) { | |
713 | fprintf(stderr, "Usage: findfs LABEL=<label>|UUID=<uuid>\n"); | |
714 | exit(2); | |
715 | } | |
ed1b33e8 | 716 | dev = blkid_get_devname(NULL, argv[1], NULL); |
118d7dac | 717 | if (!dev) { |
817e49e3 | 718 | com_err("findfs", 0, _("Unable to resolve '%s'"), |
118d7dac TT |
719 | argv[1]); |
720 | exit(1); | |
721 | } | |
722 | puts(dev); | |
723 | exit(0); | |
724 | } | |
83238153 TT |
725 | |
726 | ||
727 | int main (int argc, char ** argv) | |
728 | { | |
729 | errcode_t retval; | |
730 | ext2_filsys fs; | |
731 | struct ext2_super_block *sb; | |
2a29f135 | 732 | io_manager io_ptr; |
83238153 TT |
733 | |
734 | #ifdef ENABLE_NLS | |
735 | setlocale(LC_MESSAGES, ""); | |
14308a53 | 736 | setlocale(LC_CTYPE, ""); |
83238153 TT |
737 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); |
738 | textdomain(NLS_CAT_NAME); | |
739 | #endif | |
740 | if (argc && *argv) | |
741 | program_name = *argv; | |
742 | initialize_ext2_error_table(); | |
743 | ||
118d7dac TT |
744 | if (strcmp(get_progname(argv[0]), "findfs") == 0) |
745 | do_findfs(argc, argv); | |
83238153 TT |
746 | if (strcmp(get_progname(argv[0]), "e2label") == 0) |
747 | parse_e2label_options(argc, argv); | |
748 | else | |
749 | parse_tune2fs_options(argc, argv); | |
750 | ||
2a29f135 TT |
751 | #ifdef CONFIG_TESTIO_DEBUG |
752 | io_ptr = test_io_manager; | |
753 | test_io_backing_manager = unix_io_manager; | |
754 | #else | |
755 | io_ptr = unix_io_manager; | |
756 | #endif | |
757 | retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs); | |
818180cd | 758 | if (retval) { |
d9c56d3c | 759 | com_err (program_name, retval, _("while trying to open %s"), |
3839e657 | 760 | device_name); |
7141b54b TT |
761 | fprintf(stderr, |
762 | _("Couldn't find valid filesystem superblock.\n")); | |
3839e657 TT |
763 | exit(1); |
764 | } | |
83238153 TT |
765 | sb = fs->super; |
766 | if (print_label) { | |
767 | /* For e2label emulation */ | |
c8c071a0 TT |
768 | printf("%.*s\n", (int) sizeof(sb->s_volume_name), |
769 | sb->s_volume_name); | |
83238153 TT |
770 | exit(0); |
771 | } | |
b21e38a0 TT |
772 | retval = ext2fs_check_if_mounted(device_name, &mount_flags); |
773 | if (retval) { | |
774 | com_err("ext2fs_check_if_mount", retval, | |
775 | _("while determining whether %s is mounted."), | |
776 | device_name); | |
4055ef73 | 777 | exit(1); |
b21e38a0 | 778 | } |
63985320 TT |
779 | /* Normally we only need to write out the superblock */ |
780 | fs->flags |= EXT2_FLAG_SUPER_ONLY; | |
3839e657 | 781 | |
1e3472c5 | 782 | if (c_flag) { |
b21e38a0 | 783 | sb->s_max_mnt_count = max_mount_count; |
3839e657 | 784 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 785 | printf (_("Setting maximal mount count to %d\n"), |
1e3472c5 | 786 | max_mount_count); |
3839e657 | 787 | } |
1e3472c5 | 788 | if (C_flag) { |
b21e38a0 | 789 | sb->s_mnt_count = mount_count; |
1e3472c5 | 790 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 791 | printf (_("Setting current mount count to %d\n"), mount_count); |
1e3472c5 TT |
792 | } |
793 | if (e_flag) { | |
b21e38a0 | 794 | sb->s_errors = errors; |
3839e657 | 795 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 796 | printf (_("Setting error behavior to %d\n"), errors); |
3839e657 | 797 | } |
b21e38a0 TT |
798 | if (g_flag) { |
799 | sb->s_def_resgid = resgid; | |
f3db3566 | 800 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 801 | printf (_("Setting reserved blocks gid to %lu\n"), resgid); |
f3db3566 | 802 | } |
818180cd | 803 | if (i_flag) { |
b21e38a0 | 804 | sb->s_checkinterval = interval; |
3839e657 | 805 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 806 | printf (_("Setting interval between check %lu seconds\n"), interval); |
3839e657 | 807 | } |
818180cd | 808 | if (m_flag) { |
b21e38a0 | 809 | sb->s_r_blocks_count = (sb->s_blocks_count / 100) |
3839e657 TT |
810 | * reserved_ratio; |
811 | ext2fs_mark_super_dirty(fs); | |
d9c56d3c | 812 | printf (_("Setting reserved blocks percentage to %lu (%u blocks)\n"), |
b21e38a0 | 813 | reserved_ratio, sb->s_r_blocks_count); |
3839e657 | 814 | } |
818180cd | 815 | if (r_flag) { |
b21e38a0 | 816 | if (reserved_blocks >= sb->s_blocks_count) { |
f3db3566 | 817 | com_err (program_name, 0, |
54434927 | 818 | _("reserved blocks count is too big (%lu)"), |
f3db3566 TT |
819 | reserved_blocks); |
820 | exit (1); | |
821 | } | |
b21e38a0 | 822 | sb->s_r_blocks_count = reserved_blocks; |
f3db3566 | 823 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 824 | printf (_("Setting reserved blocks count to %lu\n"), |
f3db3566 TT |
825 | reserved_blocks); |
826 | } | |
521e3685 | 827 | if (s_flag == 1) { |
521e3685 TT |
828 | if (sb->s_feature_ro_compat & |
829 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) | |
54434927 TT |
830 | fputs(_("\nThe filesystem already has sparse " |
831 | "superblocks.\n"), stderr); | |
521e3685 TT |
832 | else { |
833 | sb->s_feature_ro_compat |= | |
834 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | |
b21e38a0 | 835 | sb->s_state &= ~EXT2_VALID_FS; |
521e3685 | 836 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 837 | printf(_("\nSparse superblock flag set. %s"), |
a4fa100c | 838 | _(please_fsck)); |
521e3685 | 839 | } |
521e3685 TT |
840 | } |
841 | if (s_flag == 0) { | |
521e3685 TT |
842 | if (!(sb->s_feature_ro_compat & |
843 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) | |
54434927 TT |
844 | fputs(_("\nThe filesystem already has sparse " |
845 | "superblocks disabled.\n"), stderr); | |
521e3685 TT |
846 | else { |
847 | sb->s_feature_ro_compat &= | |
848 | ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | |
b21e38a0 | 849 | sb->s_state &= ~EXT2_VALID_FS; |
521e3685 TT |
850 | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; |
851 | ext2fs_mark_super_dirty(fs); | |
d9c56d3c | 852 | printf(_("\nSparse superblock flag cleared. %s"), |
a4fa100c | 853 | _(please_fsck)); |
521e3685 | 854 | } |
521e3685 | 855 | } |
d4de4aa9 TT |
856 | if (T_flag) { |
857 | sb->s_lastcheck = last_check_time; | |
858 | ext2fs_mark_super_dirty(fs); | |
859 | printf(_("Setting time filesystem last checked to %s\n"), | |
860 | ctime(&last_check_time)); | |
861 | } | |
b21e38a0 TT |
862 | if (u_flag) { |
863 | sb->s_def_resuid = resuid; | |
f3db3566 | 864 | ext2fs_mark_super_dirty(fs); |
d9c56d3c | 865 | printf (_("Setting reserved blocks uid to %lu\n"), resuid); |
f3db3566 | 866 | } |
1e3472c5 | 867 | if (L_flag) { |
a789d840 | 868 | if (strlen(new_label) > sizeof(sb->s_volume_name)) |
54434927 TT |
869 | fputs(_("Warning: label too long, truncating.\n"), |
870 | stderr); | |
1e3472c5 TT |
871 | memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name)); |
872 | strncpy(sb->s_volume_name, new_label, | |
873 | sizeof(sb->s_volume_name)); | |
874 | ext2fs_mark_super_dirty(fs); | |
875 | } | |
876 | if (M_flag) { | |
877 | memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); | |
878 | strncpy(sb->s_last_mounted, new_last_mounted, | |
879 | sizeof(sb->s_last_mounted)); | |
880 | ext2fs_mark_super_dirty(fs); | |
881 | } | |
a0c3fd5e TT |
882 | if (mntopts_cmd) |
883 | update_mntopts(fs, mntopts_cmd); | |
63985320 TT |
884 | if (features_cmd) |
885 | update_feature_set(fs, features_cmd); | |
dc2ec525 | 886 | if (journal_size || journal_device) |
63985320 TT |
887 | add_journal(fs); |
888 | ||
1e3472c5 | 889 | if (U_flag) { |
4d0f2283 TT |
890 | if ((strcasecmp(new_UUID, "null") == 0) || |
891 | (strcasecmp(new_UUID, "clear") == 0)) { | |
1e3472c5 | 892 | uuid_clear(sb->s_uuid); |
63985320 TT |
893 | } else if (strcasecmp(new_UUID, "time") == 0) { |
894 | uuid_generate_time(sb->s_uuid); | |
1e3472c5 TT |
895 | } else if (strcasecmp(new_UUID, "random") == 0) { |
896 | uuid_generate(sb->s_uuid); | |
897 | } else if (uuid_parse(new_UUID, sb->s_uuid)) { | |
d9c56d3c | 898 | com_err(program_name, 0, _("Invalid UUID format\n")); |
1e3472c5 TT |
899 | exit(1); |
900 | } | |
901 | ext2fs_mark_super_dirty(fs); | |
902 | } | |
903 | ||
3839e657 | 904 | if (l_flag) |
b21e38a0 | 905 | list_super (sb); |
c007bc06 | 906 | return (ext2fs_close (fs) ? 1 : 0); |
3839e657 | 907 | } |