]>
Commit | Line | Data |
---|---|---|
1b6bf175 TT |
1 | /* |
2 | * unix.c - The unix-specific code for e2fsck | |
3 | * | |
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% | |
10 | */ | |
11 | ||
12 | #include <stdio.h> | |
13 | #ifdef HAVE_STDLIB_H | |
14 | #include <stdlib.h> | |
15 | #endif | |
16 | #include <string.h> | |
17 | #include <fcntl.h> | |
18 | #include <ctype.h> | |
19 | #include <termios.h> | |
20 | #include <time.h> | |
21 | #ifdef HAVE_GETOPT_H | |
22 | #include <getopt.h> | |
23 | #endif | |
24 | #include <unistd.h> | |
25 | #ifdef HAVE_ERRNO_H | |
26 | #include <errno.h> | |
27 | #endif | |
28 | #ifdef HAVE_MNTENT_H | |
29 | #include <mntent.h> | |
30 | #endif | |
31 | #include <sys/ioctl.h> | |
32 | #include <malloc.h> | |
33 | ||
34 | #include "et/com_err.h" | |
35 | #include "e2fsck.h" | |
36 | #include "problem.h" | |
37 | #include "../version.h" | |
38 | ||
39 | extern int isatty(int); | |
40 | ||
41 | /* Command line options */ | |
42 | static int blocksize = 0; | |
43 | static int swapfs = 0; | |
44 | static int normalize_swapfs = 0; | |
45 | static int cflag = 0; /* check disk */ | |
46 | static int show_version_only = 0; | |
47 | static int force = 0; | |
48 | static int verbose = 0; | |
49 | ||
50 | static int replace_bad_blocks = 0; | |
51 | static char *bad_blocks_file = 0; | |
52 | ||
53 | static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0}; | |
54 | ||
55 | static int root_filesystem = 0; | |
56 | static int read_only_root = 0; | |
57 | ||
58 | int restart_e2fsck = 0; | |
59 | ||
60 | static void usage(e2fsck_t ctx) | |
61 | { | |
62 | fprintf(stderr, | |
63 | "Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n" | |
64 | "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" | |
65 | "\t\t[-l|-L bad_blocks_file] device\n", ctx->program_name); | |
66 | exit(FSCK_USAGE); | |
67 | } | |
68 | ||
69 | static void show_stats(e2fsck_t ctx) | |
70 | { | |
71 | ext2_filsys fs = ctx->fs; | |
72 | int inodes, inodes_used, blocks, blocks_used; | |
73 | int dir_links; | |
74 | int num_files, num_links; | |
75 | int frag_percent; | |
76 | ||
77 | dir_links = 2 * ctx->fs_directory_count - 1; | |
78 | num_files = ctx->fs_total_count - dir_links; | |
79 | num_links = ctx->fs_links_count - dir_links; | |
80 | inodes = fs->super->s_inodes_count; | |
81 | inodes_used = (fs->super->s_inodes_count - | |
82 | fs->super->s_free_inodes_count); | |
83 | blocks = fs->super->s_blocks_count; | |
84 | blocks_used = (fs->super->s_blocks_count - | |
85 | fs->super->s_free_blocks_count); | |
86 | ||
87 | frag_percent = (10000 * ctx->fs_fragmented) / inodes_used; | |
88 | frag_percent = (frag_percent + 5) / 10; | |
89 | ||
90 | if (!verbose) { | |
91 | printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n", | |
92 | ctx->device_name, inodes_used, inodes, | |
93 | frag_percent / 10, frag_percent % 10, | |
94 | blocks_used, blocks); | |
95 | return; | |
96 | } | |
97 | printf ("\n%8d inode%s used (%d%%)\n", inodes_used, | |
98 | (inodes_used != 1) ? "s" : "", | |
99 | 100 * inodes_used / inodes); | |
100 | printf ("%8d non-contiguous inodes (%0d.%d%%)\n", | |
101 | ctx->fs_fragmented, frag_percent / 10, frag_percent % 10); | |
102 | printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n", | |
103 | ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count); | |
104 | printf ("%8d block%s used (%d%%)\n" | |
105 | "%8d bad block%s\n", blocks_used, | |
106 | (blocks_used != 1) ? "s" : "", | |
107 | 100 * blocks_used / blocks, ctx->fs_badblocks_count, | |
108 | ctx->fs_badblocks_count != 1 ? "s" : ""); | |
109 | printf ("\n%8d regular file%s\n" | |
110 | "%8d director%s\n" | |
111 | "%8d character device file%s\n" | |
112 | "%8d block device file%s\n" | |
113 | "%8d fifo%s\n" | |
114 | "%8d link%s\n" | |
115 | "%8d symbolic link%s (%d fast symbolic link%s)\n" | |
116 | "%8d socket%s\n" | |
117 | "--------\n" | |
118 | "%8d file%s\n", | |
119 | ctx->fs_regular_count, | |
120 | (ctx->fs_regular_count != 1) ? "s" : "", | |
121 | ctx->fs_directory_count, | |
122 | (ctx->fs_directory_count != 1) ? "ies" : "y", | |
123 | ctx->fs_chardev_count, | |
124 | (ctx->fs_chardev_count != 1) ? "s" : "", | |
125 | ctx->fs_blockdev_count, | |
126 | (ctx->fs_blockdev_count != 1) ? "s" : "", | |
127 | ctx->fs_fifo_count, | |
128 | (ctx->fs_fifo_count != 1) ? "s" : "", | |
129 | ctx->fs_links_count - dir_links, | |
130 | ((ctx->fs_links_count - dir_links) != 1) ? "s" : "", | |
131 | ctx->fs_symlinks_count, | |
132 | (ctx->fs_symlinks_count != 1) ? "s" : "", | |
133 | ctx->fs_fast_symlinks_count, | |
134 | (ctx->fs_fast_symlinks_count != 1) ? "s" : "", | |
135 | ctx->fs_sockets_count, (ctx->fs_sockets_count != 1) ? "s" : "", | |
136 | ctx->fs_total_count - dir_links, | |
137 | ((ctx->fs_total_count - dir_links) != 1) ? "s" : ""); | |
138 | } | |
139 | ||
140 | static void check_mount(e2fsck_t ctx) | |
141 | { | |
142 | errcode_t retval; | |
143 | int mount_flags, cont, fd; | |
144 | ||
145 | retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags); | |
146 | if (retval) { | |
147 | com_err("ext2fs_check_if_mount", retval, | |
148 | "while determining whether %s is mounted.", | |
149 | ctx->filesystem_name); | |
150 | return; | |
151 | } | |
152 | if (!(mount_flags & EXT2_MF_MOUNTED)) | |
153 | return; | |
154 | ||
155 | #if (defined(__linux__) && defined(HAVE_MNTENT_H)) | |
156 | /* | |
157 | * If the root is mounted read-only, then /etc/mtab is | |
158 | * probably not correct; so we won't issue a warning based on | |
159 | * it. | |
160 | */ | |
161 | fd = open(MOUNTED, O_RDWR); | |
162 | if (fd < 0) { | |
163 | if (errno == EROFS) | |
164 | return; | |
165 | } else | |
166 | close(fd); | |
167 | #endif | |
168 | ||
169 | if (ctx->options & E2F_OPT_READONLY) { | |
170 | printf("Warning! %s is mounted.\n", ctx->device_name); | |
171 | return; | |
172 | } | |
173 | ||
174 | printf("%s is mounted.\n\n", ctx->device_name); | |
175 | printf("\a\a\a\aWARNING!!! Running e2fsck on a mounted filesystem " | |
176 | "may cause\nSEVERE filesystem damage.\a\a\a\n\n"); | |
177 | if (isatty (0) && isatty (1)) | |
178 | cont = ask_yn("Do you really want to continue", -1); | |
179 | else | |
180 | cont = 0; | |
181 | if (!cont) { | |
182 | printf ("check aborted.\n"); | |
183 | exit (0); | |
184 | } | |
185 | return; | |
186 | } | |
187 | ||
188 | static void sync_disks(NOARGS) | |
189 | { | |
190 | sync(); | |
191 | sync(); | |
192 | sleep(1); | |
193 | sync(); | |
194 | } | |
195 | ||
196 | /* | |
197 | * This routine checks to see if a filesystem can be skipped; if so, | |
198 | * it will exit with E2FSCK_OK. Under some conditions it will print a | |
199 | * message explaining why a check is being forced. | |
200 | */ | |
201 | static void check_if_skip(e2fsck_t ctx) | |
202 | { | |
203 | ext2_filsys fs = ctx->fs; | |
204 | const char *reason = NULL; | |
205 | ||
206 | if (force || bad_blocks_file || cflag || swapfs) | |
207 | return; | |
208 | ||
209 | if (fs->super->s_state & EXT2_ERROR_FS) | |
210 | reason = "contains a file system with errors"; | |
211 | else if (fs->super->s_mnt_count >= | |
212 | (unsigned) fs->super->s_max_mnt_count) | |
213 | reason = "has reached maximal mount count"; | |
214 | else if (fs->super->s_checkinterval && | |
215 | time(0) >= (fs->super->s_lastcheck + | |
216 | fs->super->s_checkinterval)) | |
217 | reason = "has gone too long without being checked"; | |
218 | else if ((fs->super->s_state & EXT2_VALID_FS) == 0) | |
219 | reason = "was not cleanly unmounted"; | |
220 | if (reason) { | |
221 | printf("%s %s, check forced.\n", ctx->device_name, reason); | |
222 | return; | |
223 | } | |
224 | printf("%s: clean, %d/%d files, %d/%d blocks\n", ctx->device_name, | |
225 | fs->super->s_inodes_count - fs->super->s_free_inodes_count, | |
226 | fs->super->s_inodes_count, | |
227 | fs->super->s_blocks_count - fs->super->s_free_blocks_count, | |
228 | fs->super->s_blocks_count); | |
229 | ext2fs_close(fs); | |
230 | exit(FSCK_OK); | |
231 | } | |
232 | ||
233 | ||
234 | #define PATH_SET "PATH=/sbin" | |
235 | ||
236 | static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) | |
237 | { | |
238 | int flush = 0; | |
239 | char c; | |
240 | #ifdef MTRACE | |
241 | extern void *mallwatch; | |
242 | #endif | |
243 | char *oldpath = getenv("PATH"); | |
244 | e2fsck_t ctx; | |
245 | errcode_t retval; | |
246 | ||
247 | retval = e2fsck_allocate_context(&ctx); | |
248 | if (retval) | |
249 | return retval; | |
250 | ||
251 | *ret_ctx = ctx; | |
252 | ||
253 | /* Update our PATH to include /sbin */ | |
254 | if (oldpath) { | |
255 | char *newpath; | |
256 | ||
257 | newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath)); | |
258 | if (!newpath) | |
259 | fatal_error("Couldn't malloc() newpath"); | |
260 | strcpy (newpath, PATH_SET); | |
261 | strcat (newpath, ":"); | |
262 | strcat (newpath, oldpath); | |
263 | putenv (newpath); | |
264 | } else | |
265 | putenv (PATH_SET); | |
266 | ||
267 | setbuf(stdout, NULL); | |
268 | setbuf(stderr, NULL); | |
269 | initialize_ext2_error_table(); | |
270 | ||
271 | if (argc && *argv) | |
272 | ctx->program_name = *argv; | |
273 | else | |
274 | ctx->program_name = "e2fsck"; | |
275 | while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF) | |
276 | switch (c) { | |
277 | case 'p': | |
278 | case 'a': | |
279 | ctx->options |= E2F_OPT_PREEN; | |
280 | ctx->options &= ~(E2F_OPT_YES|E2F_OPT_NO); | |
281 | break; | |
282 | case 'n': | |
283 | ctx->options |= E2F_OPT_NO; | |
284 | ctx->options &= ~(E2F_OPT_YES|E2F_OPT_PREEN); | |
285 | break; | |
286 | case 'y': | |
287 | ctx->options |= E2F_OPT_YES; | |
288 | ctx->options &= ~(E2F_OPT_PREEN|E2F_OPT_NO); | |
289 | break; | |
290 | case 't': | |
291 | if (ctx->options & E2F_OPT_TIME) | |
292 | ctx->options |= E2F_OPT_TIME2; | |
293 | else | |
294 | ctx->options |= E2F_OPT_TIME; | |
295 | break; | |
296 | case 'c': | |
297 | cflag++; | |
298 | ctx->options |= E2F_OPT_CHECKBLOCKS; | |
299 | break; | |
300 | case 'r': | |
301 | /* What we do by default, anyway! */ | |
302 | break; | |
303 | case 'b': | |
304 | ctx->use_superblock = atoi(optarg); | |
305 | break; | |
306 | case 'B': | |
307 | blocksize = atoi(optarg); | |
308 | break; | |
309 | case 'I': | |
310 | ctx->inode_buffer_blocks = atoi(optarg); | |
311 | break; | |
312 | case 'P': | |
313 | ctx->process_inode_size = atoi(optarg); | |
314 | break; | |
315 | case 'L': | |
316 | replace_bad_blocks++; | |
317 | case 'l': | |
318 | bad_blocks_file = malloc(strlen(optarg)+1); | |
319 | if (!bad_blocks_file) | |
320 | fatal_error("Couldn't malloc bad_blocks_file"); | |
321 | strcpy(bad_blocks_file, optarg); | |
322 | break; | |
323 | case 'd': | |
324 | ctx->options |= E2F_OPT_DEBUG; | |
325 | break; | |
326 | case 'f': | |
327 | force = 1; | |
328 | break; | |
329 | case 'F': | |
330 | #ifdef BLKFLSBUF | |
331 | flush = 1; | |
332 | #else | |
333 | fatal_error ("-F not supported"); | |
334 | #endif | |
335 | break; | |
336 | case 'v': | |
337 | verbose = 1; | |
338 | break; | |
339 | case 'V': | |
340 | show_version_only = 1; | |
341 | break; | |
342 | #ifdef MTRACE | |
343 | case 'M': | |
344 | mallwatch = (void *) strtol(optarg, NULL, 0); | |
345 | break; | |
346 | #endif | |
347 | case 'N': | |
348 | ctx->device_name = optarg; | |
349 | break; | |
350 | case 's': | |
351 | normalize_swapfs = 1; | |
352 | case 'S': | |
353 | swapfs = 1; | |
354 | break; | |
355 | default: | |
356 | usage(ctx); | |
357 | } | |
358 | if (show_version_only) | |
359 | return 0; | |
360 | if (optind != argc - 1) | |
361 | usage(ctx); | |
362 | if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file && | |
363 | !cflag && !swapfs) | |
364 | ctx->options |= E2F_OPT_READONLY; | |
365 | ctx->filesystem_name = argv[optind]; | |
366 | if (ctx->device_name == 0) | |
367 | ctx->device_name = ctx->filesystem_name; | |
368 | if (flush) { | |
369 | #ifdef BLKFLSBUF | |
370 | int fd = open(ctx->filesystem_name, O_RDONLY, 0); | |
371 | ||
372 | if (fd < 0) { | |
373 | com_err("open", errno, "while opening %s for flushing", | |
374 | ctx->filesystem_name); | |
375 | exit(FSCK_ERROR); | |
376 | } | |
377 | if (ioctl(fd, BLKFLSBUF, 0) < 0) { | |
378 | com_err("BLKFLSBUF", errno, "while trying to flush %s", | |
379 | ctx->filesystem_name); | |
380 | exit(FSCK_ERROR); | |
381 | } | |
382 | close(fd); | |
383 | #else | |
384 | fatal_error ("BLKFLSBUF not supported"); | |
385 | #endif /* BLKFLSBUF */ | |
386 | } | |
387 | if (swapfs) { | |
388 | if (cflag || bad_blocks_file) { | |
389 | fprintf(stderr, "Incompatible options not " | |
390 | "allowed when byte-swapping.\n"); | |
391 | fatal_error(0); | |
392 | } | |
393 | } | |
394 | return 0; | |
395 | } | |
396 | ||
397 | static const char *my_ver_string = E2FSPROGS_VERSION; | |
398 | static const char *my_ver_date = E2FSPROGS_DATE; | |
399 | ||
400 | int main (int argc, char *argv[]) | |
401 | { | |
402 | errcode_t retval = 0; | |
403 | int exit_value = FSCK_OK; | |
404 | int i; | |
405 | ext2_filsys fs = 0; | |
406 | io_manager io_ptr; | |
407 | struct ext2fs_sb *s; | |
408 | const char *lib_ver_date; | |
409 | int my_ver, lib_ver; | |
410 | e2fsck_t ctx; | |
411 | struct problem_context pctx; | |
412 | int flags; | |
413 | ||
414 | clear_problem_context(&pctx); | |
415 | #ifdef MTRACE | |
416 | mtrace(); | |
417 | #endif | |
418 | #ifdef MCHECK | |
419 | mcheck(0); | |
420 | #endif | |
421 | my_ver = ext2fs_parse_version_string(my_ver_string); | |
422 | lib_ver = ext2fs_get_library_version(0, &lib_ver_date); | |
423 | if (my_ver > lib_ver) { | |
424 | fprintf( stderr, "Error: ext2fs library version " | |
425 | "out of date!\n"); | |
426 | show_version_only++; | |
427 | } | |
428 | ||
429 | retval = PRS(argc, argv, &ctx); | |
430 | if (retval) { | |
431 | com_err("e2fsck", retval, | |
432 | "while trying to initialize program"); | |
433 | exit(1); | |
434 | } | |
435 | ||
436 | init_resource_track(&ctx->global_rtrack); | |
437 | ||
438 | if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) | |
439 | fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n", | |
440 | my_ver_string, my_ver_date, EXT2FS_VERSION, | |
441 | EXT2FS_DATE); | |
442 | ||
443 | if (show_version_only) { | |
444 | fprintf(stderr, "\tUsing %s, %s\n", | |
445 | error_message(EXT2_ET_BASE), lib_ver_date); | |
446 | exit(0); | |
447 | } | |
448 | ||
449 | check_mount(ctx); | |
450 | ||
451 | if (!(ctx->options & E2F_OPT_PREEN) && | |
452 | !(ctx->options & E2F_OPT_NO) && | |
453 | !(ctx->options & E2F_OPT_YES)) { | |
454 | if (!isatty (0) || !isatty (1)) | |
455 | die ("need terminal for interactive repairs"); | |
456 | } | |
457 | ctx->superblock = ctx->use_superblock; | |
458 | restart: | |
459 | #if 1 | |
460 | io_ptr = unix_io_manager; | |
461 | #else | |
462 | io_ptr = test_io_manager; | |
463 | test_io_backing_manager = unix_io_manager; | |
464 | #endif | |
465 | sync_disks(); | |
466 | flags = (ctx->options & E2F_OPT_READONLY) ? 0 : EXT2_FLAG_RW; | |
467 | if (ctx->superblock && blocksize) { | |
468 | retval = ext2fs_open(ctx->filesystem_name, flags, | |
469 | ctx->superblock, blocksize, io_ptr, &fs); | |
470 | } else if (ctx->superblock) { | |
471 | for (i=0; possible_block_sizes[i]; i++) { | |
472 | retval = ext2fs_open(ctx->filesystem_name, flags, | |
473 | ctx->superblock, | |
474 | possible_block_sizes[i], | |
475 | io_ptr, &fs); | |
476 | if (!retval) | |
477 | break; | |
478 | } | |
479 | } else | |
480 | retval = ext2fs_open(ctx->filesystem_name, flags, | |
481 | 0, 0, io_ptr, &fs); | |
482 | if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && | |
483 | ((retval == EXT2_ET_BAD_MAGIC) || | |
484 | ((retval == 0) && ext2fs_check_desc(fs)))) { | |
485 | if (!fs || (fs->group_desc_count > 1)) { | |
486 | printf("%s trying backup blocks...\n", | |
487 | retval ? "Couldn't find ext2 superblock," : | |
488 | "Group descriptors look bad..."); | |
489 | ctx->superblock = get_backup_sb(fs); | |
490 | if (fs) | |
491 | ext2fs_close(fs); | |
492 | goto restart; | |
493 | } | |
494 | } | |
495 | if (retval) { | |
496 | com_err(ctx->program_name, retval, "while trying to open %s", | |
497 | ctx->filesystem_name); | |
498 | if (retval == EXT2_ET_REV_TOO_HIGH) | |
499 | printf ("Get a newer version of e2fsck!\n"); | |
500 | else if (retval == EXT2_ET_SHORT_READ) | |
501 | printf ("Could this be a zero-length partition?\n"); | |
502 | else if ((retval == EPERM) || (retval == EACCES)) | |
503 | printf("You must have %s access to the " | |
504 | "filesystem or be root\n", | |
505 | (ctx->options & E2F_OPT_READONLY) ? | |
506 | "r/o" : "r/w"); | |
507 | else if (retval == ENXIO) | |
508 | printf("Possibly non-existent or swap device?\n"); | |
509 | else | |
510 | fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); | |
511 | fatal_error(0); | |
512 | } | |
513 | ctx->fs = fs; | |
514 | fs->private = ctx; | |
515 | #ifdef EXT2_CURRENT_REV | |
516 | if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) { | |
517 | com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH, | |
518 | "while trying to open %s", | |
519 | ctx->filesystem_name); | |
520 | goto get_newer; | |
521 | } | |
522 | #endif | |
523 | /* | |
524 | * Check for compatibility with the feature sets. We need to | |
525 | * be more stringent than ext2fs_open(). | |
526 | */ | |
527 | s = (struct ext2fs_sb *) fs->super; | |
528 | if ((s->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) || | |
529 | (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) { | |
530 | com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE, | |
531 | "(%s)", ctx->filesystem_name); | |
532 | get_newer: | |
533 | printf ("Get a newer version of e2fsck!\n"); | |
534 | fatal_error(0); | |
535 | } | |
536 | if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { | |
537 | com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE, | |
538 | "(%s)", ctx->filesystem_name); | |
539 | goto get_newer; | |
540 | } | |
541 | ||
542 | /* | |
543 | * If the user specified a specific superblock, presumably the | |
544 | * master superblock has been trashed. So we mark the | |
545 | * superblock as dirty, so it can be written out. | |
546 | */ | |
547 | if (ctx->superblock && | |
548 | !(ctx->options & E2F_OPT_READONLY)) | |
549 | ext2fs_mark_super_dirty(fs); | |
550 | ||
551 | /* | |
552 | * Don't overwrite the backup superblock and block | |
553 | * descriptors, until we're sure the filesystem is OK.... | |
554 | */ | |
555 | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; | |
556 | ||
557 | ehandler_init(fs->io); | |
558 | ||
559 | if (ctx->superblock) | |
560 | set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0); | |
561 | check_super_block(ctx); | |
562 | check_if_skip(ctx); | |
563 | if (bad_blocks_file) | |
564 | read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks); | |
565 | else if (cflag) | |
566 | test_disk(ctx); | |
567 | ||
568 | if (normalize_swapfs) { | |
569 | if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == | |
570 | ext2fs_native_flag()) { | |
571 | fprintf(stderr, "%s: Filesystem byte order " | |
572 | "already normalized.\n", ctx->device_name); | |
573 | fatal_error(0); | |
574 | } | |
575 | } | |
576 | if (swapfs) | |
577 | swap_filesys(ctx); | |
578 | ||
579 | /* | |
580 | * Mark the system as valid, 'til proven otherwise | |
581 | */ | |
582 | ext2fs_mark_valid(fs); | |
583 | ||
584 | retval = ext2fs_read_bb_inode(fs, &fs->badblocks); | |
585 | if (retval) { | |
586 | com_err(ctx->program_name, retval, | |
587 | "while reading bad blocks inode"); | |
588 | preenhalt(ctx); | |
589 | printf("This doesn't bode well, but we'll try to go on...\n"); | |
590 | } | |
591 | ||
592 | pass1(ctx); | |
593 | if (restart_e2fsck) { | |
594 | ext2fs_close(fs); | |
595 | printf("Restarting e2fsck from the beginning...\n"); | |
596 | restart_e2fsck = 0; | |
597 | retval = e2fsck_reset_context(ctx); | |
598 | if (retval) { | |
599 | com_err(ctx->program_name, retval, | |
600 | "while resetting context"); | |
601 | exit(1); | |
602 | } | |
603 | goto restart; | |
604 | } | |
605 | pass2(ctx); | |
606 | pass3(ctx); | |
607 | pass4(ctx); | |
608 | pass5(ctx); | |
609 | ||
610 | #ifdef MTRACE | |
611 | mtrace_print("Cleanup"); | |
612 | #endif | |
613 | if (ext2fs_test_changed(fs)) { | |
614 | exit_value = FSCK_NONDESTRUCT; | |
615 | if (!(ctx->options & E2F_OPT_PREEN)) | |
616 | printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n", | |
617 | ctx->device_name); | |
618 | if (root_filesystem && !read_only_root) { | |
619 | printf("%s: ***** REBOOT LINUX *****\n", | |
620 | ctx->device_name); | |
621 | exit_value = FSCK_REBOOT; | |
622 | } | |
623 | } | |
624 | if (ext2fs_test_valid(fs)) | |
625 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; | |
626 | else | |
627 | exit_value = FSCK_UNCORRECTED; | |
628 | if (!(ctx->options & E2F_OPT_READONLY)) { | |
629 | if (ext2fs_test_valid(fs)) { | |
630 | if (!(fs->super->s_state & EXT2_VALID_FS)) | |
631 | exit_value = FSCK_NONDESTRUCT; | |
632 | fs->super->s_state = EXT2_VALID_FS; | |
633 | } else | |
634 | fs->super->s_state &= ~EXT2_VALID_FS; | |
635 | fs->super->s_mnt_count = 0; | |
636 | fs->super->s_lastcheck = time(NULL); | |
637 | ext2fs_mark_super_dirty(fs); | |
638 | } | |
639 | show_stats(ctx); | |
640 | ||
641 | write_bitmaps(ctx); | |
642 | ext2fs_close(fs); | |
643 | sync_disks(); | |
644 | ||
645 | if (ctx->options & E2F_OPT_TIME) | |
646 | print_resource_track(NULL, &ctx->global_rtrack); | |
647 | ||
648 | e2fsck_free_context(ctx); | |
649 | ||
650 | return exit_value; | |
651 | } |