]>
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"; | |
24fc5032 TT |
201 | else if ((fs->super->s_state & EXT2_VALID_FS) == 0) |
202 | reason = "was not cleanly unmounted"; | |
1b6bf175 TT |
203 | else if (fs->super->s_mnt_count >= |
204 | (unsigned) fs->super->s_max_mnt_count) | |
205 | reason = "has reached maximal mount count"; | |
206 | else if (fs->super->s_checkinterval && | |
207 | time(0) >= (fs->super->s_lastcheck + | |
208 | fs->super->s_checkinterval)) | |
209 | reason = "has gone too long without being checked"; | |
1b6bf175 TT |
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 | ||
efac9a1b TT |
223 | /* |
224 | * For completion notice | |
225 | */ | |
226 | static int e2fsck_update_progress(e2fsck_t ctx, int pass, | |
227 | unsigned long cur, unsigned long max) | |
228 | { | |
229 | const char spinner[] = "\\|/-"; | |
efac9a1b | 230 | char buf[80]; |
f75c28de TT |
231 | |
232 | if (pass == 0) | |
233 | return 0; | |
efac9a1b TT |
234 | |
235 | if (ctx->progress_fd) { | |
236 | sprintf(buf, "%d %lu %lu\n", pass, cur, max); | |
237 | write(ctx->progress_fd, buf, strlen(buf)); | |
238 | } else { | |
239 | ctx->progress_pos = (ctx->progress_pos+1) & 3; | |
240 | fputc(spinner[ctx->progress_pos], stdout); | |
241 | fputc('\b', stdout); | |
242 | fflush(stdout); | |
243 | } | |
244 | return 0; | |
245 | } | |
1b6bf175 TT |
246 | |
247 | #define PATH_SET "PATH=/sbin" | |
248 | ||
24fc5032 TT |
249 | static void reserve_stdio_fds(NOARGS) |
250 | { | |
251 | int fd; | |
252 | ||
253 | while (1) { | |
254 | fd = open("/dev/null", O_RDWR); | |
255 | if (fd > 2) | |
256 | break; | |
257 | } | |
258 | close(fd); | |
259 | } | |
260 | ||
1b6bf175 TT |
261 | static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) |
262 | { | |
263 | int flush = 0; | |
519149fb | 264 | int c; |
1b6bf175 TT |
265 | #ifdef MTRACE |
266 | extern void *mallwatch; | |
267 | #endif | |
268 | char *oldpath = getenv("PATH"); | |
269 | e2fsck_t ctx; | |
270 | errcode_t retval; | |
271 | ||
272 | retval = e2fsck_allocate_context(&ctx); | |
273 | if (retval) | |
274 | return retval; | |
275 | ||
276 | *ret_ctx = ctx; | |
277 | ||
278 | /* Update our PATH to include /sbin */ | |
279 | if (oldpath) { | |
280 | char *newpath; | |
281 | ||
54dc7ca2 TT |
282 | newpath = (char *) malloc(sizeof (PATH_SET) + 1 + |
283 | strlen (oldpath)); | |
1b6bf175 | 284 | if (!newpath) |
f8188fff | 285 | fatal_error(ctx, "Couldn't malloc() newpath"); |
1b6bf175 TT |
286 | strcpy (newpath, PATH_SET); |
287 | strcat (newpath, ":"); | |
288 | strcat (newpath, oldpath); | |
289 | putenv (newpath); | |
290 | } else | |
291 | putenv (PATH_SET); | |
292 | ||
293 | setbuf(stdout, NULL); | |
294 | setbuf(stderr, NULL); | |
295 | initialize_ext2_error_table(); | |
296 | ||
297 | if (argc && *argv) | |
298 | ctx->program_name = *argv; | |
299 | else | |
300 | ctx->program_name = "e2fsck"; | |
efac9a1b | 301 | while ((c = getopt (argc, argv, "panyrcC:B:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF) |
1b6bf175 | 302 | switch (c) { |
efac9a1b TT |
303 | case 'C': |
304 | ctx->progress = e2fsck_update_progress; | |
305 | ctx->progress_fd = atoi(optarg); | |
306 | break; | |
1b6bf175 TT |
307 | case 'p': |
308 | case 'a': | |
309 | ctx->options |= E2F_OPT_PREEN; | |
310 | ctx->options &= ~(E2F_OPT_YES|E2F_OPT_NO); | |
311 | break; | |
312 | case 'n': | |
313 | ctx->options |= E2F_OPT_NO; | |
314 | ctx->options &= ~(E2F_OPT_YES|E2F_OPT_PREEN); | |
315 | break; | |
316 | case 'y': | |
317 | ctx->options |= E2F_OPT_YES; | |
318 | ctx->options &= ~(E2F_OPT_PREEN|E2F_OPT_NO); | |
319 | break; | |
320 | case 't': | |
8bf191e8 | 321 | #ifdef RESOURCE_TRACK |
1b6bf175 TT |
322 | if (ctx->options & E2F_OPT_TIME) |
323 | ctx->options |= E2F_OPT_TIME2; | |
324 | else | |
325 | ctx->options |= E2F_OPT_TIME; | |
8bf191e8 TT |
326 | #else |
327 | fprintf(stderr, "The -t option is not " | |
328 | "supported on this version of e2fsck.\n"); | |
329 | #endif | |
1b6bf175 TT |
330 | break; |
331 | case 'c': | |
332 | cflag++; | |
333 | ctx->options |= E2F_OPT_CHECKBLOCKS; | |
334 | break; | |
335 | case 'r': | |
336 | /* What we do by default, anyway! */ | |
337 | break; | |
338 | case 'b': | |
339 | ctx->use_superblock = atoi(optarg); | |
340 | break; | |
341 | case 'B': | |
342 | blocksize = atoi(optarg); | |
343 | break; | |
344 | case 'I': | |
345 | ctx->inode_buffer_blocks = atoi(optarg); | |
346 | break; | |
347 | case 'P': | |
348 | ctx->process_inode_size = atoi(optarg); | |
349 | break; | |
350 | case 'L': | |
351 | replace_bad_blocks++; | |
352 | case 'l': | |
54dc7ca2 | 353 | bad_blocks_file = (char *) malloc(strlen(optarg)+1); |
1b6bf175 | 354 | if (!bad_blocks_file) |
f8188fff TT |
355 | fatal_error(ctx, |
356 | "Couldn't malloc bad_blocks_file"); | |
1b6bf175 TT |
357 | strcpy(bad_blocks_file, optarg); |
358 | break; | |
359 | case 'd': | |
360 | ctx->options |= E2F_OPT_DEBUG; | |
361 | break; | |
362 | case 'f': | |
363 | force = 1; | |
364 | break; | |
365 | case 'F': | |
366 | #ifdef BLKFLSBUF | |
367 | flush = 1; | |
368 | #else | |
f8188fff | 369 | fatal_error(ctx, "-F not supported"); |
1b6bf175 TT |
370 | #endif |
371 | break; | |
372 | case 'v': | |
373 | verbose = 1; | |
374 | break; | |
375 | case 'V': | |
376 | show_version_only = 1; | |
377 | break; | |
378 | #ifdef MTRACE | |
379 | case 'M': | |
380 | mallwatch = (void *) strtol(optarg, NULL, 0); | |
381 | break; | |
382 | #endif | |
383 | case 'N': | |
384 | ctx->device_name = optarg; | |
385 | break; | |
386 | case 's': | |
387 | normalize_swapfs = 1; | |
388 | case 'S': | |
389 | swapfs = 1; | |
390 | break; | |
391 | default: | |
392 | usage(ctx); | |
393 | } | |
394 | if (show_version_only) | |
395 | return 0; | |
396 | if (optind != argc - 1) | |
397 | usage(ctx); | |
398 | if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file && | |
399 | !cflag && !swapfs) | |
400 | ctx->options |= E2F_OPT_READONLY; | |
401 | ctx->filesystem_name = argv[optind]; | |
402 | if (ctx->device_name == 0) | |
403 | ctx->device_name = ctx->filesystem_name; | |
404 | if (flush) { | |
405 | #ifdef BLKFLSBUF | |
406 | int fd = open(ctx->filesystem_name, O_RDONLY, 0); | |
407 | ||
408 | if (fd < 0) { | |
409 | com_err("open", errno, "while opening %s for flushing", | |
410 | ctx->filesystem_name); | |
411 | exit(FSCK_ERROR); | |
412 | } | |
413 | if (ioctl(fd, BLKFLSBUF, 0) < 0) { | |
414 | com_err("BLKFLSBUF", errno, "while trying to flush %s", | |
415 | ctx->filesystem_name); | |
416 | exit(FSCK_ERROR); | |
417 | } | |
418 | close(fd); | |
419 | #else | |
f8188fff | 420 | fatal_error(ctx, "BLKFLSBUF not supported"); |
1b6bf175 TT |
421 | #endif /* BLKFLSBUF */ |
422 | } | |
423 | if (swapfs) { | |
424 | if (cflag || bad_blocks_file) { | |
425 | fprintf(stderr, "Incompatible options not " | |
426 | "allowed when byte-swapping.\n"); | |
f8188fff | 427 | exit(FSCK_ERROR); |
1b6bf175 TT |
428 | } |
429 | } | |
430 | return 0; | |
431 | } | |
432 | ||
433 | static const char *my_ver_string = E2FSPROGS_VERSION; | |
434 | static const char *my_ver_date = E2FSPROGS_DATE; | |
435 | ||
436 | int main (int argc, char *argv[]) | |
437 | { | |
438 | errcode_t retval = 0; | |
439 | int exit_value = FSCK_OK; | |
440 | int i; | |
441 | ext2_filsys fs = 0; | |
442 | io_manager io_ptr; | |
443 | struct ext2fs_sb *s; | |
444 | const char *lib_ver_date; | |
445 | int my_ver, lib_ver; | |
446 | e2fsck_t ctx; | |
447 | struct problem_context pctx; | |
08b21301 | 448 | int flags, run_result; |
1b6bf175 TT |
449 | |
450 | clear_problem_context(&pctx); | |
451 | #ifdef MTRACE | |
452 | mtrace(); | |
453 | #endif | |
454 | #ifdef MCHECK | |
455 | mcheck(0); | |
456 | #endif | |
457 | my_ver = ext2fs_parse_version_string(my_ver_string); | |
458 | lib_ver = ext2fs_get_library_version(0, &lib_ver_date); | |
459 | if (my_ver > lib_ver) { | |
460 | fprintf( stderr, "Error: ext2fs library version " | |
461 | "out of date!\n"); | |
462 | show_version_only++; | |
463 | } | |
464 | ||
465 | retval = PRS(argc, argv, &ctx); | |
466 | if (retval) { | |
467 | com_err("e2fsck", retval, | |
468 | "while trying to initialize program"); | |
469 | exit(1); | |
470 | } | |
24fc5032 TT |
471 | reserve_stdio_fds(); |
472 | ||
8bf191e8 | 473 | #ifdef RESOURCE_TRACK |
1b6bf175 | 474 | init_resource_track(&ctx->global_rtrack); |
8bf191e8 | 475 | #endif |
1b6bf175 TT |
476 | |
477 | if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) | |
478 | fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n", | |
479 | my_ver_string, my_ver_date, EXT2FS_VERSION, | |
480 | EXT2FS_DATE); | |
481 | ||
482 | if (show_version_only) { | |
483 | fprintf(stderr, "\tUsing %s, %s\n", | |
484 | error_message(EXT2_ET_BASE), lib_ver_date); | |
485 | exit(0); | |
486 | } | |
487 | ||
488 | check_mount(ctx); | |
489 | ||
490 | if (!(ctx->options & E2F_OPT_PREEN) && | |
491 | !(ctx->options & E2F_OPT_NO) && | |
492 | !(ctx->options & E2F_OPT_YES)) { | |
493 | if (!isatty (0) || !isatty (1)) | |
f8188fff TT |
494 | fatal_error(ctx, |
495 | "need terminal for interactive repairs"); | |
1b6bf175 TT |
496 | } |
497 | ctx->superblock = ctx->use_superblock; | |
498 | restart: | |
499 | #if 1 | |
500 | io_ptr = unix_io_manager; | |
501 | #else | |
502 | io_ptr = test_io_manager; | |
503 | test_io_backing_manager = unix_io_manager; | |
504 | #endif | |
1b6bf175 TT |
505 | flags = (ctx->options & E2F_OPT_READONLY) ? 0 : EXT2_FLAG_RW; |
506 | if (ctx->superblock && blocksize) { | |
507 | retval = ext2fs_open(ctx->filesystem_name, flags, | |
508 | ctx->superblock, blocksize, io_ptr, &fs); | |
509 | } else if (ctx->superblock) { | |
510 | for (i=0; possible_block_sizes[i]; i++) { | |
511 | retval = ext2fs_open(ctx->filesystem_name, flags, | |
512 | ctx->superblock, | |
513 | possible_block_sizes[i], | |
514 | io_ptr, &fs); | |
515 | if (!retval) | |
516 | break; | |
517 | } | |
518 | } else | |
519 | retval = ext2fs_open(ctx->filesystem_name, flags, | |
520 | 0, 0, io_ptr, &fs); | |
521 | if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && | |
522 | ((retval == EXT2_ET_BAD_MAGIC) || | |
523 | ((retval == 0) && ext2fs_check_desc(fs)))) { | |
524 | if (!fs || (fs->group_desc_count > 1)) { | |
525 | printf("%s trying backup blocks...\n", | |
526 | retval ? "Couldn't find ext2 superblock," : | |
527 | "Group descriptors look bad..."); | |
528 | ctx->superblock = get_backup_sb(fs); | |
529 | if (fs) | |
530 | ext2fs_close(fs); | |
531 | goto restart; | |
532 | } | |
533 | } | |
534 | if (retval) { | |
535 | com_err(ctx->program_name, retval, "while trying to open %s", | |
536 | ctx->filesystem_name); | |
24dd4028 TT |
537 | if (retval == EXT2_ET_REV_TOO_HIGH) { |
538 | printf("The filesystem revision is apparently " | |
539 | "too high for this version of e2fsck.\n" | |
540 | "(Or the filesystem superblock " | |
541 | "is corrupt)\n\n"); | |
542 | fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); | |
543 | } else if (retval == EXT2_ET_SHORT_READ) | |
544 | printf("Could this be a zero-length partition?\n"); | |
1b6bf175 TT |
545 | else if ((retval == EPERM) || (retval == EACCES)) |
546 | printf("You must have %s access to the " | |
547 | "filesystem or be root\n", | |
548 | (ctx->options & E2F_OPT_READONLY) ? | |
549 | "r/o" : "r/w"); | |
550 | else if (retval == ENXIO) | |
551 | printf("Possibly non-existent or swap device?\n"); | |
68227542 TT |
552 | #ifdef EROFS |
553 | else if (retval == EROFS) | |
554 | printf("Disk write-protected; use the -n option" | |
555 | "to do a read-only\n" | |
556 | "check of the device.\n"); | |
68227542 | 557 | #endif |
1b6bf175 TT |
558 | else |
559 | fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); | |
f8188fff | 560 | exit(FSCK_ERROR); |
1b6bf175 TT |
561 | } |
562 | ctx->fs = fs; | |
54dc7ca2 | 563 | fs->priv_data = ctx; |
1b6bf175 TT |
564 | #ifdef EXT2_CURRENT_REV |
565 | if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) { | |
566 | com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH, | |
567 | "while trying to open %s", | |
568 | ctx->filesystem_name); | |
f8188fff TT |
569 | get_newer: |
570 | fatal_error(ctx, "Get a newer version of e2fsck!"); | |
1b6bf175 TT |
571 | } |
572 | #endif | |
573 | /* | |
574 | * Check for compatibility with the feature sets. We need to | |
575 | * be more stringent than ext2fs_open(). | |
576 | */ | |
577 | s = (struct ext2fs_sb *) fs->super; | |
578 | if ((s->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) || | |
8144d679 | 579 | (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) { |
1b6bf175 TT |
580 | com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE, |
581 | "(%s)", ctx->filesystem_name); | |
f8188fff | 582 | goto get_newer; |
1b6bf175 TT |
583 | } |
584 | if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { | |
585 | com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE, | |
586 | "(%s)", ctx->filesystem_name); | |
587 | goto get_newer; | |
588 | } | |
589 | ||
590 | /* | |
591 | * If the user specified a specific superblock, presumably the | |
592 | * master superblock has been trashed. So we mark the | |
593 | * superblock as dirty, so it can be written out. | |
594 | */ | |
595 | if (ctx->superblock && | |
596 | !(ctx->options & E2F_OPT_READONLY)) | |
597 | ext2fs_mark_super_dirty(fs); | |
598 | ||
599 | /* | |
600 | * Don't overwrite the backup superblock and block | |
601 | * descriptors, until we're sure the filesystem is OK.... | |
602 | */ | |
603 | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; | |
604 | ||
605 | ehandler_init(fs->io); | |
606 | ||
607 | if (ctx->superblock) | |
608 | set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0); | |
609 | check_super_block(ctx); | |
a02ce9df | 610 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
f8188fff | 611 | exit(FSCK_ERROR); |
1b6bf175 TT |
612 | check_if_skip(ctx); |
613 | if (bad_blocks_file) | |
614 | read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks); | |
615 | else if (cflag) | |
616 | test_disk(ctx); | |
a02ce9df | 617 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
f8188fff | 618 | exit(FSCK_ERROR); |
1b6bf175 TT |
619 | |
620 | if (normalize_swapfs) { | |
621 | if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == | |
622 | ext2fs_native_flag()) { | |
623 | fprintf(stderr, "%s: Filesystem byte order " | |
624 | "already normalized.\n", ctx->device_name); | |
f8188fff | 625 | exit(FSCK_ERROR); |
1b6bf175 TT |
626 | } |
627 | } | |
f8188fff | 628 | if (swapfs) { |
1b6bf175 | 629 | swap_filesys(ctx); |
a02ce9df | 630 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
f8188fff TT |
631 | exit(FSCK_ERROR); |
632 | } | |
1b6bf175 TT |
633 | |
634 | /* | |
635 | * Mark the system as valid, 'til proven otherwise | |
636 | */ | |
637 | ext2fs_mark_valid(fs); | |
638 | ||
639 | retval = ext2fs_read_bb_inode(fs, &fs->badblocks); | |
640 | if (retval) { | |
641 | com_err(ctx->program_name, retval, | |
642 | "while reading bad blocks inode"); | |
643 | preenhalt(ctx); | |
644 | printf("This doesn't bode well, but we'll try to go on...\n"); | |
645 | } | |
08b21301 TT |
646 | |
647 | run_result = e2fsck_run(ctx); | |
648 | if (run_result == E2F_FLAG_RESTART) { | |
1b6bf175 | 649 | printf("Restarting e2fsck from the beginning...\n"); |
1b6bf175 TT |
650 | retval = e2fsck_reset_context(ctx); |
651 | if (retval) { | |
652 | com_err(ctx->program_name, retval, | |
653 | "while resetting context"); | |
654 | exit(1); | |
655 | } | |
73f17cfc | 656 | ext2fs_close(fs); |
1b6bf175 TT |
657 | goto restart; |
658 | } | |
a02ce9df | 659 | if (run_result & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
660 | exit(FSCK_ERROR); |
661 | if (run_result & E2F_FLAG_CANCEL) | |
662 | ext2fs_unmark_valid(fs); | |
1b6bf175 TT |
663 | |
664 | #ifdef MTRACE | |
665 | mtrace_print("Cleanup"); | |
666 | #endif | |
667 | if (ext2fs_test_changed(fs)) { | |
668 | exit_value = FSCK_NONDESTRUCT; | |
669 | if (!(ctx->options & E2F_OPT_PREEN)) | |
670 | printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n", | |
671 | ctx->device_name); | |
672 | if (root_filesystem && !read_only_root) { | |
673 | printf("%s: ***** REBOOT LINUX *****\n", | |
674 | ctx->device_name); | |
675 | exit_value = FSCK_REBOOT; | |
676 | } | |
677 | } | |
678 | if (ext2fs_test_valid(fs)) | |
679 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; | |
680 | else | |
681 | exit_value = FSCK_UNCORRECTED; | |
682 | if (!(ctx->options & E2F_OPT_READONLY)) { | |
683 | if (ext2fs_test_valid(fs)) { | |
684 | if (!(fs->super->s_state & EXT2_VALID_FS)) | |
685 | exit_value = FSCK_NONDESTRUCT; | |
686 | fs->super->s_state = EXT2_VALID_FS; | |
687 | } else | |
688 | fs->super->s_state &= ~EXT2_VALID_FS; | |
689 | fs->super->s_mnt_count = 0; | |
690 | fs->super->s_lastcheck = time(NULL); | |
691 | ext2fs_mark_super_dirty(fs); | |
692 | } | |
693 | show_stats(ctx); | |
694 | ||
f8188fff | 695 | e2fsck_write_bitmaps(ctx); |
1b6bf175 | 696 | |
8bf191e8 | 697 | #ifdef RESOURCE_TRACK |
1b6bf175 TT |
698 | if (ctx->options & E2F_OPT_TIME) |
699 | print_resource_track(NULL, &ctx->global_rtrack); | |
8bf191e8 | 700 | #endif |
1b6bf175 TT |
701 | |
702 | e2fsck_free_context(ctx); | |
1dde43f0 | 703 | ext2fs_close(fs); |
1b6bf175 TT |
704 | |
705 | return exit_value; | |
706 | } |