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