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