]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * e2fsck.c - a consistency checker for the new extended file system. | |
3 | * | |
21c84b71 TT |
4 | * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. |
5 | * | |
6 | * %Begin-Header% | |
7 | * This file may be redistributed under the terms of the GNU Public | |
8 | * License. | |
9 | * %End-Header% | |
3839e657 TT |
10 | */ |
11 | ||
12 | /* Usage: e2fsck [-dfpnsvy] device | |
13 | * -d -- debugging this program | |
14 | * -f -- check the fs even if it is marked valid | |
15 | * -p -- "preen" the filesystem | |
16 | * -n -- open the filesystem r/o mode; never try to fix problems | |
17 | * -v -- verbose (tells how many files) | |
18 | * -y -- always answer yes to questions | |
19 | * | |
20 | * The device may be a block device or a image of one, but this isn't | |
21 | * enforced (but it's not much fun on a character device :-). | |
22 | */ | |
23 | ||
1e3472c5 TT |
24 | #include <stdio.h> |
25 | #ifdef HAVE_STDLIB_H | |
26 | #include <stdlib.h> | |
27 | #endif | |
3839e657 TT |
28 | #include <string.h> |
29 | #include <fcntl.h> | |
30 | #include <ctype.h> | |
31 | #include <termios.h> | |
32 | #include <time.h> | |
50e1e10f | 33 | #ifdef HAVE_GETOPT_H |
3839e657 | 34 | #include <getopt.h> |
50e1e10f | 35 | #endif |
3839e657 | 36 | #include <unistd.h> |
50e1e10f TT |
37 | #ifdef HAVE_ERRNO_H |
38 | #include <errno.h> | |
39 | #endif | |
40 | #ifdef HAVE_MNTENT_H | |
3839e657 | 41 | #include <mntent.h> |
50e1e10f | 42 | #endif |
3839e657 TT |
43 | #include <sys/ioctl.h> |
44 | #include <malloc.h> | |
45 | ||
46 | #include "et/com_err.h" | |
1e3472c5 | 47 | #include "uuid/uuid.h" |
3839e657 | 48 | #include "e2fsck.h" |
21c84b71 | 49 | #include "problem.h" |
3839e657 TT |
50 | #include "../version.h" |
51 | ||
52 | extern int isatty(int); | |
53 | ||
54 | const char * program_name = "e2fsck"; | |
55 | const char * device_name = NULL; | |
50e1e10f | 56 | const char * filesystem_name = NULL; |
3839e657 TT |
57 | |
58 | /* Command line options */ | |
59 | int nflag = 0; | |
60 | int yflag = 0; | |
61 | int tflag = 0; /* Do timing */ | |
62 | int cflag = 0; /* check disk */ | |
63 | int preen = 0; | |
64 | int rwflag = 1; | |
1e3472c5 TT |
65 | int swapfs = 0; |
66 | int normalize_swapfs = 0; | |
3839e657 | 67 | int inode_buffer_blocks = 0; |
21c84b71 | 68 | blk_t use_superblock; |
3839e657 TT |
69 | blk_t superblock; |
70 | int blocksize = 0; | |
71 | int verbose = 0; | |
72 | int list = 0; | |
73 | int debug = 0; | |
74 | int force = 0; | |
f3db3566 | 75 | int invalid_bitmaps = 0; |
3839e657 TT |
76 | static int show_version_only = 0; |
77 | ||
78 | static int replace_bad_blocks = 0; | |
79 | static char *bad_blocks_file = 0; | |
80 | ||
81 | static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0}; | |
82 | ||
83 | struct resource_track global_rtrack; | |
84 | ||
85 | static int root_filesystem = 0; | |
86 | static int read_only_root = 0; | |
87 | ||
f3db3566 TT |
88 | int *invalid_inode_bitmap; |
89 | int *invalid_block_bitmap; | |
90 | int *invalid_inode_table; | |
91 | int restart_e2fsck = 0; | |
92 | ||
3839e657 TT |
93 | static void usage(NOARGS) |
94 | { | |
95 | fprintf(stderr, | |
1e3472c5 | 96 | "Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n" |
f3db3566 TT |
97 | "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" |
98 | "\t\t[-l|-L bad_blocks_file] device\n", program_name); | |
3839e657 TT |
99 | exit(FSCK_USAGE); |
100 | } | |
101 | ||
102 | static void show_stats(ext2_filsys fs) | |
103 | { | |
104 | int inodes, inodes_used, blocks, blocks_used; | |
105 | int dir_links; | |
106 | int num_files, num_links; | |
7f88b043 | 107 | int frag_percent; |
3839e657 TT |
108 | |
109 | dir_links = 2 * fs_directory_count - 1; | |
110 | num_files = fs_total_count - dir_links; | |
111 | num_links = fs_links_count - dir_links; | |
112 | inodes = fs->super->s_inodes_count; | |
113 | inodes_used = (fs->super->s_inodes_count - | |
114 | fs->super->s_free_inodes_count); | |
115 | blocks = fs->super->s_blocks_count; | |
116 | blocks_used = (fs->super->s_blocks_count - | |
117 | fs->super->s_free_blocks_count); | |
7f88b043 TT |
118 | |
119 | frag_percent = (10000 * fs_fragmented) / inodes_used; | |
120 | frag_percent = (frag_percent + 5) / 10; | |
3839e657 TT |
121 | |
122 | if (!verbose) { | |
7f88b043 | 123 | printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n", |
74becf3c | 124 | device_name, inodes_used, inodes, |
7f88b043 | 125 | frag_percent / 10, frag_percent % 10, |
74becf3c | 126 | blocks_used, blocks); |
3839e657 TT |
127 | return; |
128 | } | |
50e1e10f | 129 | printf ("\n%8d inode%s used (%d%%)\n", inodes_used, |
3839e657 TT |
130 | (inodes_used != 1) ? "s" : "", |
131 | 100 * inodes_used / inodes); | |
7f88b043 TT |
132 | printf ("%8d non-contiguous inodes (%0d.%d%%)\n", |
133 | fs_fragmented, frag_percent / 10, frag_percent % 10); | |
50e1e10f TT |
134 | printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n", |
135 | fs_ind_count, fs_dind_count, fs_tind_count); | |
136 | printf ("%8d block%s used (%d%%)\n" | |
137 | "%8d bad block%s\n", blocks_used, | |
3839e657 TT |
138 | (blocks_used != 1) ? "s" : "", |
139 | 100 * blocks_used / blocks, fs_badblocks_count, | |
140 | fs_badblocks_count != 1 ? "s" : ""); | |
50e1e10f TT |
141 | printf ("\n%8d regular file%s\n" |
142 | "%8d director%s\n" | |
143 | "%8d character device file%s\n" | |
144 | "%8d block device file%s\n" | |
145 | "%8d fifo%s\n" | |
146 | "%8d link%s\n" | |
147 | "%8d symbolic link%s (%d fast symbolic link%s)\n" | |
148 | "%8d socket%s\n" | |
149 | "--------\n" | |
150 | "%8d file%s\n", | |
3839e657 TT |
151 | fs_regular_count, (fs_regular_count != 1) ? "s" : "", |
152 | fs_directory_count, (fs_directory_count != 1) ? "ies" : "y", | |
153 | fs_chardev_count, (fs_chardev_count != 1) ? "s" : "", | |
154 | fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "", | |
155 | fs_fifo_count, (fs_fifo_count != 1) ? "s" : "", | |
156 | fs_links_count - dir_links, | |
157 | ((fs_links_count - dir_links) != 1) ? "s" : "", | |
158 | fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "", | |
159 | fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "", | |
160 | fs_sockets_count, (fs_sockets_count != 1) ? "s" : "", | |
161 | fs_total_count - dir_links, | |
162 | ((fs_total_count - dir_links) != 1) ? "s" : ""); | |
163 | } | |
164 | ||
165 | static void check_mount(NOARGS) | |
166 | { | |
50e1e10f | 167 | errcode_t retval; |
297f47a1 | 168 | int mount_flags, cont, fd; |
3839e657 | 169 | |
50e1e10f TT |
170 | retval = ext2fs_check_if_mounted(filesystem_name, &mount_flags); |
171 | if (retval) { | |
172 | com_err("ext2fs_check_if_mount", retval, | |
173 | "while determining whether %s is mounted.", | |
174 | filesystem_name); | |
3839e657 | 175 | return; |
50e1e10f TT |
176 | } |
177 | if (!(mount_flags & EXT2_MF_MOUNTED)) | |
3839e657 | 178 | return; |
297f47a1 | 179 | |
74becf3c | 180 | #if (defined(__linux__) && defined(HAVE_MNTENT_H)) |
3839e657 TT |
181 | /* |
182 | * If the root is mounted read-only, then /etc/mtab is | |
183 | * probably not correct; so we won't issue a warning based on | |
184 | * it. | |
185 | */ | |
297f47a1 TT |
186 | fd = open(MOUNTED, O_RDWR); |
187 | if (fd < 0) { | |
188 | if (errno == EROFS) | |
189 | return; | |
190 | } else | |
191 | close(fd); | |
192 | #endif | |
3839e657 TT |
193 | |
194 | if (!rwflag) { | |
195 | printf("Warning! %s is mounted.\n", device_name); | |
196 | return; | |
197 | } | |
198 | ||
199 | printf ("%s is mounted. ", device_name); | |
200 | if (isatty (0) && isatty (1)) | |
201 | cont = ask_yn("Do you really want to continue", -1); | |
202 | else | |
203 | cont = 0; | |
204 | if (!cont) { | |
205 | printf ("check aborted.\n"); | |
206 | exit (0); | |
207 | } | |
208 | return; | |
209 | } | |
210 | ||
211 | static void sync_disks(NOARGS) | |
212 | { | |
213 | sync(); | |
214 | sync(); | |
215 | sleep(1); | |
216 | sync(); | |
217 | } | |
218 | ||
f3db3566 TT |
219 | #define MIN_CHECK 1 |
220 | #define MAX_CHECK 2 | |
221 | ||
1e3472c5 TT |
222 | static const char *corrupt_msg = |
223 | "\nThe superblock could not be read or does not describe a correct ext2\n" | |
224 | "filesystem. If the device is valid and it really contains an ext2\n" | |
225 | "filesystem (and not swap or ufs or something else), then the superblock\n" | |
226 | "is corrupt, and you might try running e2fsck with an alternate superblock:\n" | |
227 | " e2fsck -b 8193 <device>\n\n"; | |
f3db3566 TT |
228 | |
229 | static void check_super_value(const char *descr, unsigned long value, | |
230 | int flags, unsigned long min, unsigned long max) | |
231 | { | |
232 | if (((flags & MIN_CHECK) && (value < min)) || | |
233 | ((flags & MAX_CHECK) && (value > max))) { | |
234 | printf("Corruption found in superblock. (%s = %lu).\n", | |
235 | descr, value); | |
236 | printf(corrupt_msg); | |
237 | fatal_error(0); | |
238 | } | |
239 | } | |
240 | ||
1e3472c5 | 241 | static void relocate_hint(void) |
62c06f79 TT |
242 | { |
243 | static hint_issued = 0; | |
244 | ||
21c84b71 TT |
245 | /* |
246 | * Only issue the hint once, and only if we're using the | |
247 | * primary superblocks. | |
248 | */ | |
249 | if (hint_issued || superblock) | |
62c06f79 TT |
250 | return; |
251 | ||
252 | printf("Note: if there is several inode or block bitmap blocks\n" | |
253 | "which require relocation, or one part of the inode table\n" | |
254 | "which must be moved, you may wish to try running e2fsck\n" | |
255 | "the '-b 8193' option first. The problem may lie only with\n" | |
256 | "the primary block group descriptor, and the backup block\n" | |
257 | "group descriptor may be OK.\n\n"); | |
258 | hint_issued = 1; | |
259 | } | |
260 | ||
261 | ||
3839e657 TT |
262 | static void check_super_block(ext2_filsys fs) |
263 | { | |
264 | blk_t first_block, last_block; | |
1e3472c5 | 265 | struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super; |
f3db3566 | 266 | blk_t blocks_per_group = fs->super->s_blocks_per_group; |
3839e657 | 267 | int i; |
f3db3566 | 268 | blk_t should_be; |
50e1e10f | 269 | errcode_t retval; |
21c84b71 TT |
270 | struct problem_context pctx; |
271 | ||
272 | clear_problem_context(&pctx); | |
3839e657 | 273 | |
f3db3566 TT |
274 | /* |
275 | * Verify the super block constants... | |
276 | */ | |
277 | check_super_value("inodes_count", s->s_inodes_count, | |
278 | MIN_CHECK, 1, 0); | |
279 | check_super_value("blocks_count", s->s_blocks_count, | |
280 | MIN_CHECK, 1, 0); | |
281 | check_super_value("first_data_block", s->s_first_data_block, | |
282 | MAX_CHECK, 0, s->s_blocks_count); | |
283 | check_super_value("log_frag_size", s->s_log_frag_size, | |
284 | MAX_CHECK, 0, 2); | |
285 | check_super_value("log_block_size", s->s_log_block_size, | |
286 | MIN_CHECK | MAX_CHECK, s->s_log_frag_size, | |
287 | 2); | |
288 | check_super_value("frags_per_group", s->s_frags_per_group, | |
289 | MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s)); | |
290 | check_super_value("blocks_per_group", s->s_blocks_per_group, | |
291 | MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s)); | |
292 | check_super_value("inodes_per_group", s->s_inodes_per_group, | |
293 | MIN_CHECK, 1, 0); | |
294 | check_super_value("r_blocks_count", s->s_r_blocks_count, | |
295 | MAX_CHECK, 0, s->s_blocks_count); | |
296 | ||
50e1e10f TT |
297 | retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s), |
298 | &should_be); | |
299 | if (retval) { | |
300 | com_err("ext2fs_get_device_size", retval, | |
301 | "while trying to check physical size of filesystem"); | |
302 | fatal_error(0); | |
303 | } | |
304 | if (should_be < s->s_blocks_count) { | |
305 | printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count); | |
306 | printf("The physical size of the device is %d blocks\n", | |
307 | should_be); | |
308 | printf("Either the superblock or the partition table is likely to be corrupt!\n"); | |
309 | preenhalt(fs); | |
310 | if (ask("Abort", 1)) | |
311 | fatal_error(0); | |
312 | } | |
313 | ||
f3db3566 TT |
314 | if (s->s_log_block_size != s->s_log_frag_size) { |
315 | printf("Superblock block_size = %d, fragsize = %d.\n", | |
316 | EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s)); | |
317 | printf("This version of e2fsck does not support fragment " | |
318 | "sizes different\n" | |
319 | "from the block size.\n"); | |
320 | fatal_error(0); | |
321 | } | |
322 | ||
323 | should_be = s->s_frags_per_group / | |
324 | (s->s_log_block_size - s->s_log_frag_size + 1); | |
325 | if (s->s_blocks_per_group != should_be) { | |
50e1e10f TT |
326 | printf("Superblock blocks_per_group = %u, should " |
327 | "have been %u\n", s->s_blocks_per_group, | |
f3db3566 TT |
328 | should_be); |
329 | printf(corrupt_msg); | |
7f88b043 | 330 | fatal_error(0); |
f3db3566 TT |
331 | } |
332 | ||
333 | should_be = (s->s_log_block_size == 0) ? 1 : 0; | |
334 | if (s->s_first_data_block != should_be) { | |
50e1e10f TT |
335 | printf("Superblock first_data_block = %u, should " |
336 | "have been %u\n", s->s_first_data_block, | |
f3db3566 TT |
337 | should_be); |
338 | printf(corrupt_msg); | |
7f88b043 | 339 | fatal_error(0); |
f3db3566 TT |
340 | } |
341 | ||
342 | /* | |
343 | * Verify the group descriptors.... | |
344 | */ | |
3839e657 TT |
345 | first_block = fs->super->s_first_data_block; |
346 | last_block = first_block + blocks_per_group; | |
347 | ||
348 | for (i = 0; i < fs->group_desc_count; i++) { | |
21c84b71 TT |
349 | pctx.group = i; |
350 | ||
f3db3566 TT |
351 | if (i == fs->group_desc_count - 1) |
352 | last_block = fs->super->s_blocks_count; | |
3839e657 TT |
353 | if ((fs->group_desc[i].bg_block_bitmap < first_block) || |
354 | (fs->group_desc[i].bg_block_bitmap >= last_block)) { | |
62c06f79 | 355 | relocate_hint(); |
21c84b71 TT |
356 | pctx.blk = fs->group_desc[i].bg_block_bitmap; |
357 | if (fix_problem(fs, PR_0_BB_NOT_GROUP, &pctx)) { | |
358 | fs->group_desc[i].bg_block_bitmap = 0; | |
359 | invalid_block_bitmap[i]++; | |
360 | invalid_bitmaps++; | |
f3db3566 | 361 | } |
3839e657 TT |
362 | } |
363 | if ((fs->group_desc[i].bg_inode_bitmap < first_block) || | |
364 | (fs->group_desc[i].bg_inode_bitmap >= last_block)) { | |
62c06f79 | 365 | relocate_hint(); |
21c84b71 TT |
366 | pctx.blk = fs->group_desc[i].bg_inode_bitmap; |
367 | if (fix_problem(fs, PR_0_IB_NOT_GROUP, &pctx)) { | |
368 | fs->group_desc[i].bg_inode_bitmap = 0; | |
369 | invalid_inode_bitmap[i]++; | |
370 | invalid_bitmaps++; | |
f3db3566 | 371 | } |
3839e657 TT |
372 | } |
373 | if ((fs->group_desc[i].bg_inode_table < first_block) || | |
374 | ((fs->group_desc[i].bg_inode_table + | |
375 | fs->inode_blocks_per_group - 1) >= last_block)) { | |
62c06f79 | 376 | relocate_hint(); |
21c84b71 TT |
377 | pctx.blk = fs->group_desc[i].bg_inode_table; |
378 | if (fix_problem(fs, PR_0_ITABLE_NOT_GROUP, &pctx)) { | |
379 | fs->group_desc[i].bg_inode_table = 0; | |
380 | invalid_inode_table[i]++; | |
381 | invalid_bitmaps++; | |
f3db3566 | 382 | } |
3839e657 TT |
383 | } |
384 | first_block += fs->super->s_blocks_per_group; | |
385 | last_block += fs->super->s_blocks_per_group; | |
386 | } | |
21c84b71 TT |
387 | /* |
388 | * If we have invalid bitmaps, set the error state of the | |
389 | * filesystem. | |
390 | */ | |
391 | if (invalid_bitmaps && rwflag) { | |
392 | fs->super->s_state &= ~EXT2_VALID_FS; | |
393 | ext2fs_mark_super_dirty(fs); | |
394 | } | |
1e3472c5 TT |
395 | |
396 | /* | |
397 | * If the UUID field isn't assigned, assign it. | |
398 | */ | |
399 | if (rwflag && uuid_is_null(s->s_uuid)) { | |
400 | if (preen) | |
401 | printf("%s: Adding UUID to filesystem.\n", | |
402 | device_name); | |
403 | else | |
404 | printf("Filesystem did not have a UUID; " | |
405 | "generating one.\n\n"); | |
406 | uuid_generate(s->s_uuid); | |
407 | ext2fs_mark_super_dirty(fs); | |
408 | } | |
3839e657 TT |
409 | return; |
410 | } | |
411 | ||
412 | /* | |
413 | * This routine checks to see if a filesystem can be skipped; if so, | |
414 | * it will exit with E2FSCK_OK. Under some conditions it will print a | |
415 | * message explaining why a check is being forced. | |
416 | */ | |
417 | static void check_if_skip(ext2_filsys fs) | |
418 | { | |
419 | const char *reason = NULL; | |
420 | ||
1e3472c5 | 421 | if (force || bad_blocks_file || cflag || swapfs) |
3839e657 TT |
422 | return; |
423 | ||
424 | if (fs->super->s_state & EXT2_ERROR_FS) | |
425 | reason = "contains a file system with errors"; | |
426 | else if (fs->super->s_mnt_count >= | |
427 | (unsigned) fs->super->s_max_mnt_count) | |
428 | reason = "has reached maximal mount count"; | |
429 | else if (fs->super->s_checkinterval && | |
430 | time(0) >= (fs->super->s_lastcheck + | |
431 | fs->super->s_checkinterval)) | |
432 | reason = "has gone too long without being checked"; | |
5c576477 TT |
433 | else if ((fs->super->s_state & EXT2_VALID_FS) == 0) |
434 | reason = "was not cleanly unmounted"; | |
3839e657 TT |
435 | if (reason) { |
436 | printf("%s %s, check forced.\n", device_name, reason); | |
437 | return; | |
438 | } | |
5c576477 TT |
439 | printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name, |
440 | fs->super->s_inodes_count - fs->super->s_free_inodes_count, | |
441 | fs->super->s_inodes_count, | |
442 | fs->super->s_blocks_count - fs->super->s_free_blocks_count, | |
443 | fs->super->s_blocks_count); | |
444 | ext2fs_close(fs); | |
445 | exit(FSCK_OK); | |
3839e657 TT |
446 | } |
447 | ||
50e1e10f TT |
448 | #define PATH_SET "PATH=/sbin" |
449 | ||
3839e657 TT |
450 | static void PRS(int argc, char *argv[]) |
451 | { | |
f3db3566 TT |
452 | int flush = 0; |
453 | char c; | |
3839e657 | 454 | #ifdef MTRACE |
f3db3566 | 455 | extern void *mallwatch; |
3839e657 | 456 | #endif |
50e1e10f | 457 | char *oldpath = getenv("PATH"); |
3839e657 TT |
458 | |
459 | /* Update our PATH to include /sbin */ | |
50e1e10f TT |
460 | if (oldpath) { |
461 | char *newpath; | |
462 | ||
463 | newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath)); | |
464 | if (!newpath) | |
465 | fatal_error("Couldn't malloc() newpath"); | |
466 | strcpy (newpath, PATH_SET); | |
467 | strcat (newpath, ":"); | |
468 | strcat (newpath, oldpath); | |
469 | putenv (newpath); | |
470 | } else | |
471 | putenv (PATH_SET); | |
3839e657 TT |
472 | |
473 | setbuf(stdout, NULL); | |
474 | setbuf(stderr, NULL); | |
475 | initialize_ext2_error_table(); | |
476 | ||
477 | if (argc && *argv) | |
478 | program_name = *argv; | |
1e3472c5 | 479 | while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF) |
3839e657 TT |
480 | switch (c) { |
481 | case 'p': | |
482 | case 'a': | |
483 | preen = 1; | |
484 | yflag = nflag = 0; | |
485 | break; | |
486 | case 'n': | |
487 | nflag = 1; | |
488 | preen = yflag = 0; | |
489 | break; | |
490 | case 'y': | |
491 | yflag = 1; | |
492 | preen = nflag = 0; | |
493 | break; | |
494 | case 't': | |
495 | tflag++; | |
496 | break; | |
497 | case 'c': | |
498 | cflag++; | |
499 | break; | |
500 | case 'r': | |
501 | /* What we do by default, anyway! */ | |
502 | break; | |
503 | case 'b': | |
21c84b71 | 504 | use_superblock = atoi(optarg); |
3839e657 TT |
505 | break; |
506 | case 'B': | |
507 | blocksize = atoi(optarg); | |
508 | break; | |
509 | case 'I': | |
510 | inode_buffer_blocks = atoi(optarg); | |
511 | break; | |
512 | case 'P': | |
513 | process_inode_size = atoi(optarg); | |
514 | break; | |
515 | case 'L': | |
516 | replace_bad_blocks++; | |
517 | case 'l': | |
518 | bad_blocks_file = malloc(strlen(optarg)+1); | |
519 | if (!bad_blocks_file) | |
520 | fatal_error("Couldn't malloc bad_blocks_file"); | |
521 | strcpy(bad_blocks_file, optarg); | |
522 | break; | |
523 | case 'd': | |
524 | debug = 1; | |
525 | break; | |
526 | case 'f': | |
527 | force = 1; | |
528 | break; | |
529 | case 'F': | |
50e1e10f | 530 | #ifdef BLKFLSBUF |
3839e657 | 531 | flush = 1; |
50e1e10f TT |
532 | #else |
533 | fatal_error ("-F not supported"); | |
534 | #endif | |
3839e657 TT |
535 | break; |
536 | case 'v': | |
537 | verbose = 1; | |
538 | break; | |
539 | case 'V': | |
540 | show_version_only = 1; | |
541 | break; | |
542 | #ifdef MTRACE | |
543 | case 'M': | |
544 | mallwatch = (void *) strtol(optarg, NULL, 0); | |
545 | break; | |
546 | #endif | |
50e1e10f TT |
547 | case 'N': |
548 | device_name = optarg; | |
549 | break; | |
1e3472c5 TT |
550 | case 's': |
551 | normalize_swapfs = 1; | |
552 | case 'S': | |
553 | swapfs = 1; | |
554 | break; | |
3839e657 TT |
555 | default: |
556 | usage (); | |
557 | } | |
558 | if (show_version_only) | |
559 | return; | |
560 | if (optind != argc - 1) | |
561 | usage (); | |
1e3472c5 | 562 | if (nflag && !bad_blocks_file && !cflag && !swapfs) |
3839e657 | 563 | rwflag = 0; |
50e1e10f TT |
564 | filesystem_name = argv[optind]; |
565 | if (device_name == 0) | |
566 | device_name = filesystem_name; | |
3839e657 | 567 | if (flush) { |
50e1e10f TT |
568 | #ifdef BLKFLSBUF |
569 | int fd = open(filesystem_name, O_RDONLY, 0); | |
3839e657 TT |
570 | |
571 | if (fd < 0) { | |
572 | com_err("open", errno, "while opening %s for flushing", | |
50e1e10f | 573 | filesystem_name); |
3839e657 TT |
574 | exit(FSCK_ERROR); |
575 | } | |
576 | if (ioctl(fd, BLKFLSBUF, 0) < 0) { | |
577 | com_err("BLKFLSBUF", errno, "while trying to flush %s", | |
50e1e10f | 578 | filesystem_name); |
3839e657 TT |
579 | exit(FSCK_ERROR); |
580 | } | |
581 | close(fd); | |
50e1e10f TT |
582 | #else |
583 | fatal_error ("BLKFLSBUF not supported"); | |
584 | #endif /* BLKFLSBUF */ | |
3839e657 | 585 | } |
1e3472c5 TT |
586 | if (swapfs) { |
587 | if (cflag || bad_blocks_file) { | |
588 | fprintf(stderr, "Incompatible options not " | |
589 | "allowed when byte-swapping.\n"); | |
590 | fatal_error(0); | |
591 | } | |
592 | } | |
3839e657 TT |
593 | } |
594 | ||
595 | int main (int argc, char *argv[]) | |
596 | { | |
597 | errcode_t retval = 0; | |
598 | int exit_value = FSCK_OK; | |
599 | int i; | |
21c84b71 TT |
600 | ext2_filsys fs = 0; |
601 | io_manager io_ptr; | |
602 | struct ext2fs_sb *s; | |
3839e657 TT |
603 | |
604 | #ifdef MTRACE | |
605 | mtrace(); | |
606 | #endif | |
607 | #ifdef MCHECK | |
608 | mcheck(0); | |
609 | #endif | |
610 | ||
611 | init_resource_track(&global_rtrack); | |
612 | ||
613 | PRS(argc, argv); | |
614 | ||
21c84b71 | 615 | if (!preen || show_version_only) |
3839e657 TT |
616 | fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n", |
617 | E2FSPROGS_VERSION, E2FSPROGS_DATE, | |
618 | EXT2FS_VERSION, EXT2FS_DATE); | |
619 | ||
5c576477 TT |
620 | if (show_version_only) { |
621 | fprintf(stderr, "\tUsing %s\n", | |
622 | error_message(EXT2_ET_BASE)); | |
3839e657 | 623 | exit(0); |
5c576477 | 624 | } |
3839e657 TT |
625 | |
626 | check_mount(); | |
627 | ||
628 | if (!preen && !nflag && !yflag) { | |
629 | if (!isatty (0) || !isatty (1)) | |
630 | die ("need terminal for interactive repairs"); | |
631 | } | |
21c84b71 | 632 | superblock = use_superblock; |
f3db3566 | 633 | restart: |
21c84b71 TT |
634 | #if 1 |
635 | io_ptr = unix_io_manager; | |
636 | #else | |
637 | io_ptr = test_io_manager; | |
638 | test_io_backing_manager = unix_io_manager; | |
639 | #endif | |
3839e657 TT |
640 | sync_disks(); |
641 | if (superblock && blocksize) { | |
50e1e10f TT |
642 | retval = ext2fs_open(filesystem_name, |
643 | rwflag ? EXT2_FLAG_RW : 0, | |
21c84b71 | 644 | superblock, blocksize, io_ptr, &fs); |
3839e657 TT |
645 | } else if (superblock) { |
646 | for (i=0; possible_block_sizes[i]; i++) { | |
50e1e10f | 647 | retval = ext2fs_open(filesystem_name, |
3839e657 TT |
648 | rwflag ? EXT2_FLAG_RW : 0, |
649 | superblock, | |
650 | possible_block_sizes[i], | |
21c84b71 | 651 | io_ptr, &fs); |
3839e657 TT |
652 | if (!retval) |
653 | break; | |
654 | } | |
655 | } else | |
50e1e10f TT |
656 | retval = ext2fs_open(filesystem_name, |
657 | rwflag ? EXT2_FLAG_RW : 0, | |
21c84b71 TT |
658 | 0, 0, io_ptr, &fs); |
659 | if (!superblock && !preen && | |
660 | ((retval == EXT2_ET_BAD_MAGIC) || | |
661 | ((retval == 0) && ext2fs_check_desc(fs)))) { | |
662 | if (!fs || (fs->group_desc_count > 1)) { | |
663 | printf("%s trying backup blocks...\n", | |
664 | retval ? "Couldn't find ext2 superblock," : | |
665 | "Group descriptors look bad..."); | |
666 | superblock = 8193; | |
667 | if (fs) | |
668 | ext2fs_close(fs); | |
669 | goto restart; | |
670 | } | |
671 | } | |
3839e657 TT |
672 | if (retval) { |
673 | com_err(program_name, retval, "while trying to open %s", | |
50e1e10f | 674 | filesystem_name); |
1e3472c5 | 675 | if (retval == EXT2_ET_REV_TOO_HIGH) |
f3db3566 | 676 | printf ("Get a newer version of e2fsck!\n"); |
1e3472c5 | 677 | else if (retval == EXT2_ET_SHORT_READ) |
50e1e10f | 678 | printf ("Could this be a zero-length partition?\n"); |
1e3472c5 | 679 | else if ((retval == EPERM) || (retval == EACCES)) |
50e1e10f TT |
680 | printf("You must have %s access to the " |
681 | "filesystem or be root\n", | |
682 | rwflag ? "r/w" : "r/o"); | |
1e3472c5 | 683 | else if (retval == ENXIO) |
50e1e10f | 684 | printf("Possibly non-existent or swap device?\n"); |
1e3472c5 | 685 | else |
f3db3566 | 686 | printf(corrupt_msg); |
3839e657 TT |
687 | fatal_error(0); |
688 | } | |
f3db3566 TT |
689 | #ifdef EXT2_CURRENT_REV |
690 | if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) { | |
7f88b043 TT |
691 | com_err(program_name, EXT2_ET_REV_TOO_HIGH, |
692 | "while trying to open %s", | |
50e1e10f | 693 | filesystem_name); |
21c84b71 TT |
694 | goto get_newer; |
695 | } | |
696 | #endif | |
697 | /* | |
698 | * Check for compatibility with the feature sets. We have to | |
699 | * check because we need to be more stringent than ext2fs_open | |
700 | */ | |
701 | s = (struct ext2fs_sb *) fs->super; | |
702 | if (s->s_feature_compat || s->s_feature_incompat || | |
703 | s->s_feature_ro_compat) { | |
704 | com_err(program_name, EXT2_ET_UNSUPP_FEATURE, | |
705 | " (%s)", filesystem_name); | |
706 | get_newer: | |
f3db3566 TT |
707 | printf ("Get a newer version of e2fsck!\n"); |
708 | fatal_error(0); | |
709 | } | |
21c84b71 | 710 | |
3839e657 TT |
711 | /* |
712 | * If the user specified a specific superblock, presumably the | |
713 | * master superblock has been trashed. So we mark the | |
714 | * superblock as dirty, so it can be written out. | |
715 | */ | |
716 | if (superblock && rwflag) | |
717 | ext2fs_mark_super_dirty(fs); | |
718 | ||
5c576477 TT |
719 | /* |
720 | * Don't overwrite the backup superblock and block | |
721 | * descriptors, until we're sure the filesystem is OK.... | |
722 | */ | |
723 | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; | |
724 | ||
3839e657 TT |
725 | ehandler_init(fs->io); |
726 | ||
f3db3566 TT |
727 | invalid_inode_bitmap = allocate_memory(sizeof(int) * |
728 | fs->group_desc_count, | |
729 | "invalid_inode_bitmap"); | |
730 | invalid_block_bitmap = allocate_memory(sizeof(int) * | |
731 | fs->group_desc_count, | |
732 | "invalid_block_bitmap"); | |
733 | invalid_inode_table = allocate_memory(sizeof(int) * | |
734 | fs->group_desc_count, | |
735 | "invalid_inode_table"); | |
736 | ||
3839e657 TT |
737 | check_super_block(fs); |
738 | check_if_skip(fs); | |
739 | if (bad_blocks_file) | |
740 | read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks); | |
741 | else if (cflag) | |
742 | test_disk(fs); | |
743 | ||
1e3472c5 | 744 | if (normalize_swapfs) { |
5c576477 TT |
745 | if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == |
746 | ext2fs_native_flag()) { | |
1e3472c5 TT |
747 | fprintf(stderr, "%s: Filesystem byte order " |
748 | "already normalized.\n", device_name); | |
749 | fatal_error(0); | |
750 | } | |
751 | } | |
752 | if (swapfs) | |
753 | swap_filesys(fs); | |
754 | ||
3839e657 TT |
755 | /* |
756 | * Mark the system as valid, 'til proven otherwise | |
757 | */ | |
758 | ext2fs_mark_valid(fs); | |
1e3472c5 | 759 | |
21c84b71 TT |
760 | retval = ext2fs_read_bb_inode(fs, &fs->badblocks); |
761 | if (retval) { | |
762 | com_err(program_name, retval, | |
763 | "while reading bad blocks inode"); | |
764 | preenhalt(fs); | |
765 | printf("This doesn't bode well, but we'll try to go on...\n"); | |
766 | } | |
767 | ||
3839e657 | 768 | pass1(fs); |
50e1e10f TT |
769 | free(invalid_inode_bitmap); |
770 | free(invalid_block_bitmap); | |
771 | free(invalid_inode_table); | |
f3db3566 TT |
772 | if (restart_e2fsck) { |
773 | ext2fs_close(fs); | |
774 | printf("Restarting e2fsck from the beginning...\n"); | |
775 | restart_e2fsck = 0; | |
21c84b71 | 776 | superblock = use_superblock; |
f3db3566 TT |
777 | goto restart; |
778 | } | |
3839e657 TT |
779 | pass2(fs); |
780 | pass3(fs); | |
781 | pass4(fs); | |
782 | pass5(fs); | |
783 | ||
784 | #ifdef MTRACE | |
785 | mtrace_print("Cleanup"); | |
786 | #endif | |
787 | if (ext2fs_test_changed(fs)) { | |
788 | exit_value = FSCK_NONDESTRUCT; | |
789 | if (!preen) | |
790 | printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n", | |
791 | device_name); | |
792 | if (root_filesystem && !read_only_root) { | |
793 | printf("%s: ***** REBOOT LINUX *****\n", device_name); | |
794 | exit_value = FSCK_REBOOT; | |
795 | } | |
796 | } | |
5c576477 TT |
797 | if (ext2fs_test_valid(fs)) |
798 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; | |
799 | else | |
3839e657 TT |
800 | exit_value = FSCK_UNCORRECTED; |
801 | if (rwflag) { | |
1e3472c5 TT |
802 | if (ext2fs_test_valid(fs)) { |
803 | if (!(fs->super->s_state & EXT2_VALID_FS)) | |
804 | exit_value = FSCK_NONDESTRUCT; | |
3839e657 | 805 | fs->super->s_state = EXT2_VALID_FS; |
1e3472c5 | 806 | } else |
3839e657 TT |
807 | fs->super->s_state &= ~EXT2_VALID_FS; |
808 | fs->super->s_mnt_count = 0; | |
809 | fs->super->s_lastcheck = time(NULL); | |
810 | ext2fs_mark_super_dirty(fs); | |
811 | } | |
812 | show_stats(fs); | |
813 | ||
814 | write_bitmaps(fs); | |
815 | ext2fs_close(fs); | |
816 | sync_disks(); | |
817 | ||
818 | if (tflag) | |
819 | print_resource_track(&global_rtrack); | |
820 | ||
821 | return exit_value; | |
822 | } |