diff options
-rw-r--r-- | e2fsprogs/tune2fs.c | 776 |
1 files changed, 776 insertions, 0 deletions
diff --git a/e2fsprogs/tune2fs.c b/e2fsprogs/tune2fs.c new file mode 100644 index 000000000..e4f904ea0 --- /dev/null +++ b/e2fsprogs/tune2fs.c | |||
@@ -0,0 +1,776 @@ | |||
1 | /* | ||
2 | * tune2fs.c - Change the file system parameters on an ext2 file system | ||
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 | * | ||
8 | * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. | ||
9 | * | ||
10 | * %Begin-Header% | ||
11 | * This file may be redistributed under the terms of the GNU Public | ||
12 | * License. | ||
13 | * %End-Header% | ||
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 | |||
28 | #include <fcntl.h> | ||
29 | #include <grp.h> | ||
30 | #ifdef HAVE_GETOPT_H | ||
31 | #include <getopt.h> | ||
32 | #else | ||
33 | extern char *optarg; | ||
34 | extern int optind; | ||
35 | #endif | ||
36 | #include <pwd.h> | ||
37 | #include <stdio.h> | ||
38 | #include <stdlib.h> | ||
39 | #include <string.h> | ||
40 | #include <time.h> | ||
41 | #include <unistd.h> | ||
42 | #include <sys/types.h> | ||
43 | |||
44 | #include "e2fsbb.h" | ||
45 | #include "ext2fs/ext2_fs.h" | ||
46 | #include "ext2fs/ext2fs.h" | ||
47 | #include "uuid/uuid.h" | ||
48 | #include "e2p/e2p.h" | ||
49 | #include "ext2fs/jfs_user.h" | ||
50 | #include "util.h" | ||
51 | #include "blkid/blkid.h" | ||
52 | |||
53 | static char * device_name; | ||
54 | static char * new_label, *new_last_mounted, *new_UUID; | ||
55 | static char * io_options; | ||
56 | static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag; | ||
57 | static int m_flag, M_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag; | ||
58 | static time_t last_check_time; | ||
59 | static int print_label; | ||
60 | static int max_mount_count, mount_count, mount_flags; | ||
61 | static unsigned long interval, reserved_ratio, reserved_blocks; | ||
62 | static unsigned long resgid, resuid; | ||
63 | static unsigned short errors; | ||
64 | static int open_flag; | ||
65 | static char *features_cmd; | ||
66 | static char *mntopts_cmd; | ||
67 | |||
68 | static int journal_size, journal_flags; | ||
69 | static char *journal_device; | ||
70 | |||
71 | static const char *please_fsck = "Please run e2fsck on the filesystem\n"; | ||
72 | |||
73 | static __u32 ok_features[3] = { | ||
74 | EXT3_FEATURE_COMPAT_HAS_JOURNAL | EXT2_FEATURE_COMPAT_DIR_INDEX, | ||
75 | EXT2_FEATURE_INCOMPAT_FILETYPE, | ||
76 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER | ||
77 | }; | ||
78 | |||
79 | /* | ||
80 | * Remove an external journal from the filesystem | ||
81 | */ | ||
82 | static void remove_journal_device(ext2_filsys fs) | ||
83 | { | ||
84 | char *journal_path; | ||
85 | ext2_filsys jfs; | ||
86 | char buf[1024]; | ||
87 | journal_superblock_t *jsb; | ||
88 | int i, nr_users; | ||
89 | errcode_t retval; | ||
90 | int commit_remove_journal = 0; | ||
91 | io_manager io_ptr; | ||
92 | |||
93 | if (f_flag) | ||
94 | commit_remove_journal = 1; /* force removal even if error */ | ||
95 | |||
96 | uuid_unparse(fs->super->s_journal_uuid, buf); | ||
97 | journal_path = blkid_get_devname(NULL, "UUID", buf); | ||
98 | |||
99 | if (!journal_path) { | ||
100 | journal_path = | ||
101 | ext2fs_find_block_device(fs->super->s_journal_dev); | ||
102 | if (!journal_path) | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | io_ptr = unix_io_manager; | ||
107 | retval = ext2fs_open(journal_path, EXT2_FLAG_RW| | ||
108 | EXT2_FLAG_JOURNAL_DEV_OK, 0, | ||
109 | fs->blocksize, io_ptr, &jfs); | ||
110 | if (retval) { | ||
111 | bb_error_msg("Failed to open external journal"); | ||
112 | goto no_valid_journal; | ||
113 | } | ||
114 | if (!(jfs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { | ||
115 | bb_error_msg("%s is not a journal device", journal_path); | ||
116 | goto no_valid_journal; | ||
117 | } | ||
118 | |||
119 | /* Get the journal superblock */ | ||
120 | if ((retval = io_channel_read_blk(jfs->io, 1, -1024, buf))) { | ||
121 | bb_error_msg("Failed to read journal superblock"); | ||
122 | goto no_valid_journal; | ||
123 | } | ||
124 | |||
125 | jsb = (journal_superblock_t *) buf; | ||
126 | if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || | ||
127 | (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) { | ||
128 | bb_error_msg("Journal superblock not found!"); | ||
129 | goto no_valid_journal; | ||
130 | } | ||
131 | |||
132 | /* Find the filesystem UUID */ | ||
133 | nr_users = ntohl(jsb->s_nr_users); | ||
134 | for (i=0; i < nr_users; i++) { | ||
135 | if (memcmp(fs->super->s_uuid, | ||
136 | &jsb->s_users[i*16], 16) == 0) | ||
137 | break; | ||
138 | } | ||
139 | if (i >= nr_users) { | ||
140 | bb_error_msg("Filesystem's UUID not found on journal device"); | ||
141 | commit_remove_journal = 1; | ||
142 | goto no_valid_journal; | ||
143 | } | ||
144 | nr_users--; | ||
145 | for (i=0; i < nr_users; i++) | ||
146 | memcpy(&jsb->s_users[i*16], &jsb->s_users[(i+1)*16], 16); | ||
147 | jsb->s_nr_users = htonl(nr_users); | ||
148 | |||
149 | /* Write back the journal superblock */ | ||
150 | if ((retval = io_channel_write_blk(jfs->io, 1, -1024, buf))) { | ||
151 | bb_error_msg("Failed to write journal superblock"); | ||
152 | goto no_valid_journal; | ||
153 | } | ||
154 | |||
155 | commit_remove_journal = 1; | ||
156 | |||
157 | no_valid_journal: | ||
158 | if (commit_remove_journal == 0) | ||
159 | bb_error_msg_and_die("Journal NOT removed"); | ||
160 | fs->super->s_journal_dev = 0; | ||
161 | uuid_clear(fs->super->s_journal_uuid); | ||
162 | ext2fs_mark_super_dirty(fs); | ||
163 | puts("Journal removed"); | ||
164 | free(journal_path); | ||
165 | } | ||
166 | |||
167 | /* Helper function for remove_journal_inode */ | ||
168 | static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr, | ||
169 | int blockcnt EXT2FS_ATTR((unused)), | ||
170 | void *private EXT2FS_ATTR((unused))) | ||
171 | { | ||
172 | blk_t block; | ||
173 | int group; | ||
174 | |||
175 | block = *blocknr; | ||
176 | ext2fs_unmark_block_bitmap(fs->block_map,block); | ||
177 | group = ext2fs_group_of_blk(fs, block); | ||
178 | fs->group_desc[group].bg_free_blocks_count++; | ||
179 | fs->super->s_free_blocks_count++; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * Remove the journal inode from the filesystem | ||
185 | */ | ||
186 | static void remove_journal_inode(ext2_filsys fs) | ||
187 | { | ||
188 | struct ext2_inode inode; | ||
189 | errcode_t retval; | ||
190 | ino_t ino = fs->super->s_journal_inum; | ||
191 | |||
192 | retval = ext2fs_read_inode(fs, ino, &inode); | ||
193 | if (retval) | ||
194 | bb_error_msg_and_die("Failed to read journal inode"); | ||
195 | if (ino == EXT2_JOURNAL_INO) { | ||
196 | retval = ext2fs_read_bitmaps(fs); | ||
197 | if (retval) | ||
198 | bb_error_msg_and_die("Failed to read bitmaps"); | ||
199 | retval = ext2fs_block_iterate(fs, ino, 0, NULL, | ||
200 | release_blocks_proc, NULL); | ||
201 | if (retval) | ||
202 | bb_error_msg_and_die("Failed clearing journal inode"); | ||
203 | memset(&inode, 0, sizeof(inode)); | ||
204 | ext2fs_mark_bb_dirty(fs); | ||
205 | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; | ||
206 | } else | ||
207 | inode.i_flags &= ~EXT2_IMMUTABLE_FL; | ||
208 | retval = ext2fs_write_inode(fs, ino, &inode); | ||
209 | if (retval) | ||
210 | bb_error_msg_and_die("Failed writing journal inode"); | ||
211 | fs->super->s_journal_inum = 0; | ||
212 | ext2fs_mark_super_dirty(fs); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * Update the default mount options | ||
217 | */ | ||
218 | static void update_mntopts(ext2_filsys fs, char *mntopts) | ||
219 | { | ||
220 | struct ext2_super_block *sb= fs->super; | ||
221 | |||
222 | if (e2p_edit_mntopts(mntopts, &sb->s_default_mount_opts, ~0)) | ||
223 | bb_error_msg_and_die("Invalid mount option set: %s", mntopts); | ||
224 | ext2fs_mark_super_dirty(fs); | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * Update the feature set as provided by the user. | ||
229 | */ | ||
230 | static void update_feature_set(ext2_filsys fs, char *features) | ||
231 | { | ||
232 | int sparse, old_sparse, filetype, old_filetype; | ||
233 | int journal, old_journal, dxdir, old_dxdir; | ||
234 | struct ext2_super_block *sb= fs->super; | ||
235 | __u32 old_compat, old_incompat, old_ro_compat; | ||
236 | |||
237 | old_compat = sb->s_feature_compat; | ||
238 | old_ro_compat = sb->s_feature_ro_compat; | ||
239 | old_incompat = sb->s_feature_incompat; | ||
240 | |||
241 | old_sparse = sb->s_feature_ro_compat & | ||
242 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | ||
243 | old_filetype = sb->s_feature_incompat & | ||
244 | EXT2_FEATURE_INCOMPAT_FILETYPE; | ||
245 | old_journal = sb->s_feature_compat & | ||
246 | EXT3_FEATURE_COMPAT_HAS_JOURNAL; | ||
247 | old_dxdir = sb->s_feature_compat & | ||
248 | EXT2_FEATURE_COMPAT_DIR_INDEX; | ||
249 | if (e2p_edit_feature(features, &sb->s_feature_compat, ok_features)) | ||
250 | bb_error_msg_and_die("Invalid filesystem option set: %s", features); | ||
251 | sparse = sb->s_feature_ro_compat & | ||
252 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | ||
253 | filetype = sb->s_feature_incompat & | ||
254 | EXT2_FEATURE_INCOMPAT_FILETYPE; | ||
255 | journal = sb->s_feature_compat & | ||
256 | EXT3_FEATURE_COMPAT_HAS_JOURNAL; | ||
257 | dxdir = sb->s_feature_compat & | ||
258 | EXT2_FEATURE_COMPAT_DIR_INDEX; | ||
259 | if (old_journal && !journal) { | ||
260 | if ((mount_flags & EXT2_MF_MOUNTED) && | ||
261 | !(mount_flags & EXT2_MF_READONLY)) { | ||
262 | bb_error_msg_and_die( | ||
263 | "The has_journal flag may only be " | ||
264 | "cleared when the filesystem is\n" | ||
265 | "unmounted or mounted " | ||
266 | "read-only"); | ||
267 | } | ||
268 | if (sb->s_feature_incompat & | ||
269 | EXT3_FEATURE_INCOMPAT_RECOVER) { | ||
270 | bb_error_msg_and_die( | ||
271 | "The needs_recovery flag is set. " | ||
272 | "Please run e2fsck before clearing\n" | ||
273 | "the has_journal flag."); | ||
274 | } | ||
275 | if (sb->s_journal_inum) { | ||
276 | remove_journal_inode(fs); | ||
277 | } | ||
278 | if (sb->s_journal_dev) { | ||
279 | remove_journal_device(fs); | ||
280 | } | ||
281 | } | ||
282 | if (journal && !old_journal) { | ||
283 | /* | ||
284 | * If adding a journal flag, let the create journal | ||
285 | * code below handle creating setting the flag and | ||
286 | * creating the journal. We supply a default size if | ||
287 | * necessary. | ||
288 | */ | ||
289 | if (!journal_size) | ||
290 | journal_size = -1; | ||
291 | sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; | ||
292 | } | ||
293 | if (dxdir && !old_dxdir) { | ||
294 | if (!sb->s_def_hash_version) | ||
295 | sb->s_def_hash_version = EXT2_HASH_TEA; | ||
296 | if (uuid_is_null((unsigned char *) sb->s_hash_seed)) | ||
297 | uuid_generate((unsigned char *) sb->s_hash_seed); | ||
298 | } | ||
299 | |||
300 | if (sb->s_rev_level == EXT2_GOOD_OLD_REV && | ||
301 | (sb->s_feature_compat || sb->s_feature_ro_compat || | ||
302 | sb->s_feature_incompat)) | ||
303 | ext2fs_update_dynamic_rev(fs); | ||
304 | if ((sparse != old_sparse) || | ||
305 | (filetype != old_filetype)) { | ||
306 | sb->s_state &= ~EXT2_VALID_FS; | ||
307 | printf("\n%s\n", please_fsck); | ||
308 | } | ||
309 | if ((old_compat != sb->s_feature_compat) || | ||
310 | (old_ro_compat != sb->s_feature_ro_compat) || | ||
311 | (old_incompat != sb->s_feature_incompat)) | ||
312 | ext2fs_mark_super_dirty(fs); | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * Add a journal to the filesystem. | ||
317 | */ | ||
318 | static void add_journal(ext2_filsys fs) | ||
319 | { | ||
320 | unsigned long journal_blocks; | ||
321 | errcode_t retval; | ||
322 | ext2_filsys jfs; | ||
323 | io_manager io_ptr; | ||
324 | |||
325 | if (fs->super->s_feature_compat & | ||
326 | EXT3_FEATURE_COMPAT_HAS_JOURNAL) { | ||
327 | bb_error_msg("The filesystem already has a journal"); | ||
328 | goto err; | ||
329 | } | ||
330 | if (journal_device) { | ||
331 | check_plausibility(journal_device); | ||
332 | check_mount(journal_device, 0, "journal"); | ||
333 | io_ptr = unix_io_manager; | ||
334 | retval = ext2fs_open(journal_device, EXT2_FLAG_RW| | ||
335 | EXT2_FLAG_JOURNAL_DEV_OK, 0, | ||
336 | fs->blocksize, io_ptr, &jfs); | ||
337 | if (retval) { | ||
338 | bb_error_msg("Failed to open journal on %s", journal_device); | ||
339 | goto err; | ||
340 | } | ||
341 | printf("Creating journal on device %s: ", journal_device); | ||
342 | fflush(stdout); | ||
343 | |||
344 | retval = ext2fs_add_journal_device(fs, jfs); | ||
345 | ext2fs_close(jfs); | ||
346 | if (retval) { | ||
347 | bb_error_msg("Failed to add filesystem to journal on %s", journal_device); | ||
348 | goto err; | ||
349 | } | ||
350 | puts("done"); | ||
351 | } else if (journal_size) { | ||
352 | fputs("Creating journal inode: ", stdout); | ||
353 | fflush(stdout); | ||
354 | journal_blocks = figure_journal_size(journal_size, fs); | ||
355 | |||
356 | retval = ext2fs_add_journal_inode(fs, journal_blocks, | ||
357 | journal_flags); | ||
358 | if (retval) | ||
359 | bb_error_msg_and_die("Failed to create journal file"); | ||
360 | else | ||
361 | puts("done"); | ||
362 | /* | ||
363 | * If the filesystem wasn't mounted, we need to force | ||
364 | * the block group descriptors out. | ||
365 | */ | ||
366 | if ((mount_flags & EXT2_MF_MOUNTED) == 0) | ||
367 | fs->flags &= ~EXT2_FLAG_SUPER_ONLY; | ||
368 | } | ||
369 | print_check_message(fs); | ||
370 | return; | ||
371 | |||
372 | err: | ||
373 | if (journal_device) | ||
374 | free(journal_device); | ||
375 | exit(1); | ||
376 | } | ||
377 | |||
378 | |||
379 | static void parse_e2label_options(int argc, char ** argv) | ||
380 | { | ||
381 | if ((argc < 2) || (argc > 3)) | ||
382 | bb_show_usage(); | ||
383 | io_options = strchr(argv[1], '?'); | ||
384 | if (io_options) | ||
385 | *io_options++ = 0; | ||
386 | device_name = blkid_get_devname(NULL, argv[1], NULL); | ||
387 | if (!device_name) | ||
388 | bb_error_msg_and_die("Unable to resolve '%s'", argv[1]); | ||
389 | if (argc == 3) { | ||
390 | open_flag = EXT2_FLAG_RW | EXT2_FLAG_JOURNAL_DEV_OK; | ||
391 | L_flag = 1; | ||
392 | new_label = argv[2]; | ||
393 | } else | ||
394 | print_label++; | ||
395 | } | ||
396 | |||
397 | static time_t parse_time(char *str) | ||
398 | { | ||
399 | struct tm ts; | ||
400 | |||
401 | if (strcmp(str, "now") == 0) { | ||
402 | return (time(0)); | ||
403 | } | ||
404 | memset(&ts, 0, sizeof(ts)); | ||
405 | #ifdef HAVE_STRPTIME | ||
406 | strptime(str, "%Y%m%d%H%M%S", &ts); | ||
407 | #else | ||
408 | sscanf(str, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon, | ||
409 | &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec); | ||
410 | ts.tm_year -= 1900; | ||
411 | ts.tm_mon -= 1; | ||
412 | if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 || | ||
413 | ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 || | ||
414 | ts.tm_min > 59 || ts.tm_sec > 61) | ||
415 | ts.tm_mday = 0; | ||
416 | #endif | ||
417 | if (ts.tm_mday == 0) { | ||
418 | bb_error_msg_and_die("Couldn't parse date/time specifier: %s", str); | ||
419 | } | ||
420 | return (mktime(&ts)); | ||
421 | } | ||
422 | |||
423 | static void parse_tune2fs_options(int argc, char **argv) | ||
424 | { | ||
425 | int c; | ||
426 | char * tmp; | ||
427 | struct group * gr; | ||
428 | struct passwd * pw; | ||
429 | |||
430 | printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); | ||
431 | while ((c = getopt(argc, argv, "c:e:fg:i:jlm:o:r:s:u:C:J:L:M:O:T:U:")) != EOF) | ||
432 | switch (c) | ||
433 | { | ||
434 | case 'c': | ||
435 | max_mount_count = strtol (optarg, &tmp, 0); | ||
436 | if (*tmp || max_mount_count > 16000) { | ||
437 | bb_error_msg_and_die("bad mounts count - %s", optarg); | ||
438 | } | ||
439 | if (max_mount_count == 0) | ||
440 | max_mount_count = -1; | ||
441 | c_flag = 1; | ||
442 | open_flag = EXT2_FLAG_RW; | ||
443 | break; | ||
444 | case 'C': | ||
445 | mount_count = strtoul (optarg, &tmp, 0); | ||
446 | if (*tmp || mount_count > 16000) { | ||
447 | bb_error_msg_and_die("bad mounts count - %s", optarg); | ||
448 | } | ||
449 | C_flag = 1; | ||
450 | open_flag = EXT2_FLAG_RW; | ||
451 | break; | ||
452 | case 'e': | ||
453 | if (strcmp (optarg, "continue") == 0) | ||
454 | errors = EXT2_ERRORS_CONTINUE; | ||
455 | else if (strcmp (optarg, "remount-ro") == 0) | ||
456 | errors = EXT2_ERRORS_RO; | ||
457 | else if (strcmp (optarg, "panic") == 0) | ||
458 | errors = EXT2_ERRORS_PANIC; | ||
459 | else { | ||
460 | bb_error_msg_and_die("bad error behavior - %s", optarg); | ||
461 | } | ||
462 | e_flag = 1; | ||
463 | open_flag = EXT2_FLAG_RW; | ||
464 | break; | ||
465 | case 'f': /* Force */ | ||
466 | f_flag = 1; | ||
467 | break; | ||
468 | case 'g': | ||
469 | resgid = strtoul (optarg, &tmp, 0); | ||
470 | if (*tmp) { | ||
471 | gr = getgrnam (optarg); | ||
472 | if (gr == NULL) | ||
473 | tmp = optarg; | ||
474 | else { | ||
475 | resgid = gr->gr_gid; | ||
476 | *tmp =0; | ||
477 | } | ||
478 | } | ||
479 | if (*tmp) { | ||
480 | bb_error_msg_and_die("bad gid/group name - %s", optarg); | ||
481 | } | ||
482 | g_flag = 1; | ||
483 | open_flag = EXT2_FLAG_RW; | ||
484 | break; | ||
485 | case 'i': | ||
486 | interval = strtoul (optarg, &tmp, 0); | ||
487 | switch (*tmp) { | ||
488 | case 's': | ||
489 | tmp++; | ||
490 | break; | ||
491 | case '\0': | ||
492 | case 'd': | ||
493 | case 'D': /* days */ | ||
494 | interval *= 86400; | ||
495 | if (*tmp != '\0') | ||
496 | tmp++; | ||
497 | break; | ||
498 | case 'm': | ||
499 | case 'M': /* months! */ | ||
500 | interval *= 86400 * 30; | ||
501 | tmp++; | ||
502 | break; | ||
503 | case 'w': | ||
504 | case 'W': /* weeks */ | ||
505 | interval *= 86400 * 7; | ||
506 | tmp++; | ||
507 | break; | ||
508 | } | ||
509 | if (*tmp || interval > (365 * 86400)) { | ||
510 | bb_error_msg_and_die("bad interval - %s", optarg); | ||
511 | } | ||
512 | i_flag = 1; | ||
513 | open_flag = EXT2_FLAG_RW; | ||
514 | break; | ||
515 | case 'j': | ||
516 | if (!journal_size) | ||
517 | journal_size = -1; | ||
518 | open_flag = EXT2_FLAG_RW; | ||
519 | break; | ||
520 | case 'J': | ||
521 | parse_journal_opts(&journal_device, &journal_flags, &journal_size, optarg); | ||
522 | open_flag = EXT2_FLAG_RW; | ||
523 | break; | ||
524 | case 'l': | ||
525 | l_flag = 1; | ||
526 | break; | ||
527 | case 'L': | ||
528 | new_label = optarg; | ||
529 | L_flag = 1; | ||
530 | open_flag = EXT2_FLAG_RW | | ||
531 | EXT2_FLAG_JOURNAL_DEV_OK; | ||
532 | break; | ||
533 | case 'm': | ||
534 | reserved_ratio = strtoul (optarg, &tmp, 0); | ||
535 | if (*tmp || reserved_ratio > 50) { | ||
536 | bb_error_msg_and_die("bad reserved block ratio - %s", optarg); | ||
537 | } | ||
538 | m_flag = 1; | ||
539 | open_flag = EXT2_FLAG_RW; | ||
540 | break; | ||
541 | case 'M': | ||
542 | new_last_mounted = optarg; | ||
543 | M_flag = 1; | ||
544 | open_flag = EXT2_FLAG_RW; | ||
545 | break; | ||
546 | case 'o': | ||
547 | if (mntopts_cmd) { | ||
548 | bb_error_msg_and_die("-o may only be specified once"); | ||
549 | } | ||
550 | mntopts_cmd = optarg; | ||
551 | open_flag = EXT2_FLAG_RW; | ||
552 | break; | ||
553 | |||
554 | case 'O': | ||
555 | if (features_cmd) { | ||
556 | bb_error_msg_and_die("-O may only be specified once"); | ||
557 | } | ||
558 | features_cmd = optarg; | ||
559 | open_flag = EXT2_FLAG_RW; | ||
560 | break; | ||
561 | case 'r': | ||
562 | reserved_blocks = strtoul (optarg, &tmp, 0); | ||
563 | if (*tmp) { | ||
564 | bb_error_msg_and_die("bad reserved blocks count - %s", optarg); | ||
565 | } | ||
566 | r_flag = 1; | ||
567 | open_flag = EXT2_FLAG_RW; | ||
568 | break; | ||
569 | case 's': | ||
570 | s_flag = atoi(optarg); | ||
571 | open_flag = EXT2_FLAG_RW; | ||
572 | break; | ||
573 | case 'T': | ||
574 | T_flag = 1; | ||
575 | last_check_time = parse_time(optarg); | ||
576 | open_flag = EXT2_FLAG_RW; | ||
577 | break; | ||
578 | case 'u': | ||
579 | resuid = strtoul (optarg, &tmp, 0); | ||
580 | if (*tmp) { | ||
581 | pw = getpwnam (optarg); | ||
582 | if (pw == NULL) | ||
583 | tmp = optarg; | ||
584 | else { | ||
585 | resuid = pw->pw_uid; | ||
586 | *tmp = 0; | ||
587 | } | ||
588 | } | ||
589 | if (*tmp) { | ||
590 | bb_error_msg_and_die("bad uid/user name - %s", optarg); | ||
591 | } | ||
592 | u_flag = 1; | ||
593 | open_flag = EXT2_FLAG_RW; | ||
594 | break; | ||
595 | case 'U': | ||
596 | new_UUID = optarg; | ||
597 | U_flag = 1; | ||
598 | open_flag = EXT2_FLAG_RW | | ||
599 | EXT2_FLAG_JOURNAL_DEV_OK; | ||
600 | break; | ||
601 | default: | ||
602 | bb_show_usage(); | ||
603 | } | ||
604 | if (optind < argc - 1 || optind == argc) | ||
605 | bb_show_usage(); | ||
606 | if (!open_flag && !l_flag) | ||
607 | bb_show_usage(); | ||
608 | io_options = strchr(argv[optind], '?'); | ||
609 | if (io_options) | ||
610 | *io_options++ = 0; | ||
611 | device_name = blkid_get_devname(NULL, argv[optind], NULL); | ||
612 | if (!device_name) | ||
613 | bb_error_msg_and_die("Unable to resolve '%s'", argv[optind]); | ||
614 | } | ||
615 | |||
616 | static void do_findfs(int argc, char **argv) | ||
617 | { | ||
618 | char *dev; | ||
619 | |||
620 | if ((argc != 2) || | ||
621 | (strncmp(argv[1], "LABEL=", 6) && strncmp(argv[1], "UUID=", 5))) | ||
622 | bb_show_usage(); | ||
623 | dev = blkid_get_devname(NULL, argv[1], NULL); | ||
624 | if (!dev) | ||
625 | bb_error_msg_and_die("Unable to resolve '%s'", argv[1]); | ||
626 | puts(dev); | ||
627 | exit(0); | ||
628 | } | ||
629 | |||
630 | int tune2fs_main(int argc, char **argv) | ||
631 | { | ||
632 | errcode_t retval; | ||
633 | ext2_filsys fs; | ||
634 | struct ext2_super_block *sb; | ||
635 | io_manager io_ptr; | ||
636 | char *program_name = basename(argv[0]); | ||
637 | |||
638 | if (strcmp(program_name, "findfs") == 0) | ||
639 | do_findfs(argc, argv); | ||
640 | if (strcmp(program_name, "e2label") == 0) | ||
641 | parse_e2label_options(argc, argv); | ||
642 | else | ||
643 | parse_tune2fs_options(argc, argv); | ||
644 | |||
645 | io_ptr = unix_io_manager; | ||
646 | retval = ext2fs_open2(device_name, io_options, open_flag, | ||
647 | 0, 0, io_ptr, &fs); | ||
648 | if (retval) | ||
649 | bb_error_msg_and_die("No valid superblock on %s", device_name); | ||
650 | sb = fs->super; | ||
651 | if (print_label) { | ||
652 | /* For e2label emulation */ | ||
653 | printf("%.*s\n", (int) sizeof(sb->s_volume_name), | ||
654 | sb->s_volume_name); | ||
655 | exit(0); | ||
656 | } | ||
657 | retval = ext2fs_check_if_mounted(device_name, &mount_flags); | ||
658 | if (retval) | ||
659 | bb_error_msg_and_die("Could not determine if %s is mounted", device_name); | ||
660 | /* Normally we only need to write out the superblock */ | ||
661 | fs->flags |= EXT2_FLAG_SUPER_ONLY; | ||
662 | |||
663 | if (c_flag) { | ||
664 | sb->s_max_mnt_count = max_mount_count; | ||
665 | ext2fs_mark_super_dirty(fs); | ||
666 | printf("Setting maximal mount count to %d\n", max_mount_count); | ||
667 | } | ||
668 | if (C_flag) { | ||
669 | sb->s_mnt_count = mount_count; | ||
670 | ext2fs_mark_super_dirty(fs); | ||
671 | printf("Setting current mount count to %d\n", mount_count); | ||
672 | } | ||
673 | if (e_flag) { | ||
674 | sb->s_errors = errors; | ||
675 | ext2fs_mark_super_dirty(fs); | ||
676 | printf("Setting error behavior to %d\n", errors); | ||
677 | } | ||
678 | if (g_flag) { | ||
679 | sb->s_def_resgid = resgid; | ||
680 | ext2fs_mark_super_dirty(fs); | ||
681 | printf("Setting reserved blocks gid to %lu\n", resgid); | ||
682 | } | ||
683 | if (i_flag) { | ||
684 | sb->s_checkinterval = interval; | ||
685 | ext2fs_mark_super_dirty(fs); | ||
686 | printf("Setting interval between check %lu seconds\n", interval); | ||
687 | } | ||
688 | if (m_flag) { | ||
689 | sb->s_r_blocks_count = (sb->s_blocks_count / 100) | ||
690 | * reserved_ratio; | ||
691 | ext2fs_mark_super_dirty(fs); | ||
692 | printf("Setting reserved blocks percentage to %lu (%u blocks)\n", | ||
693 | reserved_ratio, sb->s_r_blocks_count); | ||
694 | } | ||
695 | if (r_flag) { | ||
696 | if (reserved_blocks >= sb->s_blocks_count/2) | ||
697 | bb_error_msg_and_die("reserved blocks count is too big (%lu)", reserved_blocks); | ||
698 | sb->s_r_blocks_count = reserved_blocks; | ||
699 | ext2fs_mark_super_dirty(fs); | ||
700 | printf("Setting reserved blocks count to %lu\n", reserved_blocks); | ||
701 | } | ||
702 | if (s_flag == 1) { | ||
703 | if (sb->s_feature_ro_compat & | ||
704 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) | ||
705 | bb_error_msg("\nThe filesystem already has sparse superblocks\n"); | ||
706 | else { | ||
707 | sb->s_feature_ro_compat |= | ||
708 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | ||
709 | sb->s_state &= ~EXT2_VALID_FS; | ||
710 | ext2fs_mark_super_dirty(fs); | ||
711 | printf("\nSparse superblock flag set. %s", please_fsck); | ||
712 | } | ||
713 | } | ||
714 | if (s_flag == 0) { | ||
715 | if (!(sb->s_feature_ro_compat & | ||
716 | EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) | ||
717 | bb_error_msg("\nThe filesystem already has sparse superblocks disabled\n"); | ||
718 | else { | ||
719 | sb->s_feature_ro_compat &= | ||
720 | ~EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER; | ||
721 | sb->s_state &= ~EXT2_VALID_FS; | ||
722 | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; | ||
723 | ext2fs_mark_super_dirty(fs); | ||
724 | printf("\nSparse superblock flag cleared. %s", please_fsck); | ||
725 | } | ||
726 | } | ||
727 | if (T_flag) { | ||
728 | sb->s_lastcheck = last_check_time; | ||
729 | ext2fs_mark_super_dirty(fs); | ||
730 | printf("Setting time filesystem last checked to %s\n", | ||
731 | ctime(&last_check_time)); | ||
732 | } | ||
733 | if (u_flag) { | ||
734 | sb->s_def_resuid = resuid; | ||
735 | ext2fs_mark_super_dirty(fs); | ||
736 | printf("Setting reserved blocks uid to %lu\n", resuid); | ||
737 | } | ||
738 | if (L_flag) { | ||
739 | if (strlen(new_label) > sizeof(sb->s_volume_name)) | ||
740 | bb_error_msg("Warning: label too long, truncating\n"); | ||
741 | memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name)); | ||
742 | strncpy(sb->s_volume_name, new_label, | ||
743 | sizeof(sb->s_volume_name)); | ||
744 | ext2fs_mark_super_dirty(fs); | ||
745 | } | ||
746 | if (M_flag) { | ||
747 | memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted)); | ||
748 | strncpy(sb->s_last_mounted, new_last_mounted, | ||
749 | sizeof(sb->s_last_mounted)); | ||
750 | ext2fs_mark_super_dirty(fs); | ||
751 | } | ||
752 | if (mntopts_cmd) | ||
753 | update_mntopts(fs, mntopts_cmd); | ||
754 | if (features_cmd) | ||
755 | update_feature_set(fs, features_cmd); | ||
756 | if (journal_size || journal_device) | ||
757 | add_journal(fs); | ||
758 | |||
759 | if (U_flag) { | ||
760 | if ((strcasecmp(new_UUID, "null") == 0) || | ||
761 | (strcasecmp(new_UUID, "clear") == 0)) { | ||
762 | uuid_clear(sb->s_uuid); | ||
763 | } else if (strcasecmp(new_UUID, "time") == 0) { | ||
764 | uuid_generate_time(sb->s_uuid); | ||
765 | } else if (strcasecmp(new_UUID, "random") == 0) { | ||
766 | uuid_generate(sb->s_uuid); | ||
767 | } else if (uuid_parse(new_UUID, sb->s_uuid)) { | ||
768 | bb_error_msg_and_die("Invalid UUID format"); | ||
769 | } | ||
770 | ext2fs_mark_super_dirty(fs); | ||
771 | } | ||
772 | |||
773 | if (l_flag) | ||
774 | list_super (sb); | ||
775 | return (ext2fs_close (fs) ? 1 : 0); | ||
776 | } | ||