diff options
Diffstat (limited to 'e2fsprogs/e2fsck.c')
-rw-r--r-- | e2fsprogs/e2fsck.c | 1179 |
1 files changed, 1179 insertions, 0 deletions
diff --git a/e2fsprogs/e2fsck.c b/e2fsprogs/e2fsck.c new file mode 100644 index 000000000..f1adc8549 --- /dev/null +++ b/e2fsprogs/e2fsck.c | |||
@@ -0,0 +1,1179 @@ | |||
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 | #include <stdlib.h> | ||
14 | #include <string.h> | ||
15 | #include <fcntl.h> | ||
16 | #include <ctype.h> | ||
17 | #include <time.h> | ||
18 | #ifdef HAVE_SIGNAL_H | ||
19 | #include <signal.h> | ||
20 | #endif | ||
21 | #ifdef HAVE_GETOPT_H | ||
22 | #include <getopt.h> | ||
23 | #else | ||
24 | extern char *optarg; | ||
25 | extern int optind; | ||
26 | #endif | ||
27 | #include <unistd.h> | ||
28 | #ifdef HAVE_ERRNO_H | ||
29 | #include <errno.h> | ||
30 | #endif | ||
31 | #ifdef HAVE_MNTENT_H | ||
32 | #include <mntent.h> | ||
33 | #endif | ||
34 | #ifdef HAVE_SYS_IOCTL_H | ||
35 | #include <sys/ioctl.h> | ||
36 | #endif | ||
37 | #ifdef HAVE_MALLOC_H | ||
38 | #include <malloc.h> | ||
39 | #endif | ||
40 | #ifdef HAVE_SYS_TYPES_H | ||
41 | #include <sys/types.h> | ||
42 | #endif | ||
43 | #ifdef HAVE_DIRENT_H | ||
44 | #include <dirent.h> | ||
45 | #endif | ||
46 | |||
47 | #include "e2fsbb.h" | ||
48 | #include "et/com_err.h" | ||
49 | #include "e2fsck/e2fsck.h" | ||
50 | #include "e2fsck/problem.h" | ||
51 | //#include "../version.h" | ||
52 | |||
53 | /* Command line options */ | ||
54 | static int swapfs; | ||
55 | #ifdef ENABLE_SWAPFS | ||
56 | static int normalize_swapfs; | ||
57 | #endif | ||
58 | static int cflag; /* check disk */ | ||
59 | static int show_version_only; | ||
60 | static int verbose; | ||
61 | |||
62 | static int replace_bad_blocks; | ||
63 | static int keep_bad_blocks; | ||
64 | static char *bad_blocks_file; | ||
65 | |||
66 | e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ | ||
67 | |||
68 | #ifdef __CONFIG_JBD_DEBUG__E2FS /* Enabled by configure --enable-jfs-debug */ | ||
69 | int journal_enable_debug = -1; | ||
70 | #endif | ||
71 | |||
72 | #if 0 | ||
73 | static void usage(e2fsck_t ctx) | ||
74 | { | ||
75 | fprintf(stderr, | ||
76 | _("Usage: %s [-panyrcdfvstDFSV] [-b superblock] [-B blocksize]\n" | ||
77 | "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" | ||
78 | "\t\t[-l|-L bad_blocks_file] [-C fd] [-j ext-journal]\n" | ||
79 | "\t\t[-E extended-options] device\n"), | ||
80 | ctx->program_name); | ||
81 | |||
82 | fprintf(stderr, _("\nEmergency help:\n" | ||
83 | " -p Automatic repair (no questions)\n" | ||
84 | " -n Make no changes to the filesystem\n" | ||
85 | " -y Assume \"yes\" to all questions\n" | ||
86 | " -c Check for bad blocks and add them to the badblock list\n" | ||
87 | " -f Force checking even if filesystem is marked clean\n")); | ||
88 | fprintf(stderr, _("" | ||
89 | " -v Be verbose\n" | ||
90 | " -b superblock Use alternative superblock\n" | ||
91 | " -B blocksize Force blocksize when looking for superblock\n" | ||
92 | " -j external-journal Set location of the external journal\n" | ||
93 | " -l bad_blocks_file Add to badblocks list\n" | ||
94 | " -L bad_blocks_file Set badblocks list\n" | ||
95 | )); | ||
96 | |||
97 | exit(FSCK_USAGE); | ||
98 | } | ||
99 | #endif | ||
100 | |||
101 | static void show_stats(e2fsck_t ctx) | ||
102 | { | ||
103 | ext2_filsys fs = ctx->fs; | ||
104 | int inodes, inodes_used, blocks, blocks_used; | ||
105 | int dir_links; | ||
106 | int num_files, num_links; | ||
107 | int frag_percent; | ||
108 | |||
109 | dir_links = 2 * ctx->fs_directory_count - 1; | ||
110 | num_files = ctx->fs_total_count - dir_links; | ||
111 | num_links = ctx->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); | ||
118 | |||
119 | frag_percent = (10000 * ctx->fs_fragmented) / inodes_used; | ||
120 | frag_percent = (frag_percent + 5) / 10; | ||
121 | |||
122 | if (!verbose) { | ||
123 | printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n", | ||
124 | ctx->device_name, inodes_used, inodes, | ||
125 | frag_percent / 10, frag_percent % 10, | ||
126 | blocks_used, blocks); | ||
127 | return; | ||
128 | } | ||
129 | printf (P_("\n%8d inode used (%d%%)\n", "\n%8d inodes used (%d%%)\n", | ||
130 | inodes_used), inodes_used, 100 * inodes_used / inodes); | ||
131 | printf (P_("%8d non-contiguous inode (%0d.%d%%)\n", | ||
132 | "%8d non-contiguous inodes (%0d.%d%%)\n", | ||
133 | ctx->fs_fragmented), | ||
134 | ctx->fs_fragmented, frag_percent / 10, frag_percent % 10); | ||
135 | printf (_(" # of inodes with ind/dind/tind blocks: %d/%d/%d\n"), | ||
136 | ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count); | ||
137 | printf (P_("%8d block used (%d%%)\n", "%8d blocks used (%d%%)\n", | ||
138 | blocks_used), | ||
139 | blocks_used, (int) ((long long) 100 * blocks_used / blocks)); | ||
140 | printf (P_("%8d bad block\n", "%8d bad blocks\n", | ||
141 | ctx->fs_badblocks_count), ctx->fs_badblocks_count); | ||
142 | printf (P_("%8d large file\n", "%8d large files\n", | ||
143 | ctx->large_files), ctx->large_files); | ||
144 | printf (P_("\n%8d regular file\n", "\n%8d regular files\n", | ||
145 | ctx->fs_regular_count), ctx->fs_regular_count); | ||
146 | printf (P_("%8d directory\n", "%8d directories\n", | ||
147 | ctx->fs_directory_count), ctx->fs_directory_count); | ||
148 | printf (P_("%8d character device file\n", | ||
149 | "%8d character device files\n", ctx->fs_chardev_count), | ||
150 | ctx->fs_chardev_count); | ||
151 | printf (P_("%8d block device file\n", "%8d block device files\n", | ||
152 | ctx->fs_blockdev_count), ctx->fs_blockdev_count); | ||
153 | printf (P_("%8d fifo\n", "%8d fifos\n", ctx->fs_fifo_count), | ||
154 | ctx->fs_fifo_count); | ||
155 | printf (P_("%8d link\n", "%8d links\n", | ||
156 | ctx->fs_links_count - dir_links), | ||
157 | ctx->fs_links_count - dir_links); | ||
158 | printf (P_("%8d symbolic link", "%8d symbolic links", | ||
159 | ctx->fs_symlinks_count), ctx->fs_symlinks_count); | ||
160 | printf (P_(" (%d fast symbolic link)\n", " (%d fast symbolic links)\n", | ||
161 | ctx->fs_fast_symlinks_count), ctx->fs_fast_symlinks_count); | ||
162 | printf (P_("%8d socket\n", "%8d sockets\n", ctx->fs_sockets_count), | ||
163 | ctx->fs_sockets_count); | ||
164 | printf ("--------\n"); | ||
165 | printf (P_("%8d file\n", "%8d files\n", | ||
166 | ctx->fs_total_count - dir_links), | ||
167 | ctx->fs_total_count - dir_links); | ||
168 | } | ||
169 | |||
170 | static void check_mount(e2fsck_t ctx) | ||
171 | { | ||
172 | errcode_t retval; | ||
173 | int cont; | ||
174 | |||
175 | retval = ext2fs_check_if_mounted(ctx->filesystem_name, | ||
176 | &ctx->mount_flags); | ||
177 | if (retval) { | ||
178 | com_err("ext2fs_check_if_mount", retval, | ||
179 | _("while determining whether %s is mounted."), | ||
180 | ctx->filesystem_name); | ||
181 | return; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * If the filesystem isn't mounted, or it's the root filesystem | ||
186 | * and it's mounted read-only, then everything's fine. | ||
187 | */ | ||
188 | if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) || | ||
189 | ((ctx->mount_flags & EXT2_MF_ISROOT) && | ||
190 | (ctx->mount_flags & EXT2_MF_READONLY))) | ||
191 | return; | ||
192 | |||
193 | if (ctx->options & E2F_OPT_READONLY) { | ||
194 | printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name); | ||
195 | return; | ||
196 | } | ||
197 | |||
198 | printf(_("%s is mounted. "), ctx->filesystem_name); | ||
199 | if (!ctx->interactive) | ||
200 | fatal_error(ctx, _("Cannot continue, aborting.\n\n")); | ||
201 | printf(_("\n\n\007\007\007\007WARNING!!! " | ||
202 | "Running e2fsck on a mounted filesystem may cause\n" | ||
203 | "SEVERE filesystem damage.\007\007\007\n\n")); | ||
204 | cont = ask_yn(_("Do you really want to continue"), -1); | ||
205 | if (!cont) { | ||
206 | printf (_("check aborted.\n")); | ||
207 | exit (0); | ||
208 | } | ||
209 | return; | ||
210 | } | ||
211 | |||
212 | static int is_on_batt(void) | ||
213 | { | ||
214 | FILE *f; | ||
215 | DIR *d; | ||
216 | char tmp[80], tmp2[80], fname[80]; | ||
217 | unsigned int acflag; | ||
218 | struct dirent* de; | ||
219 | |||
220 | f = fopen("/proc/apm", "r"); | ||
221 | if (f) { | ||
222 | if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4) | ||
223 | acflag = 1; | ||
224 | fclose(f); | ||
225 | return (acflag != 1); | ||
226 | } | ||
227 | d = opendir("/proc/acpi/ac_adapter"); | ||
228 | if (d) { | ||
229 | while ((de=readdir(d)) != NULL) { | ||
230 | if (!strncmp(".", de->d_name, 1)) | ||
231 | continue; | ||
232 | snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state", | ||
233 | de->d_name); | ||
234 | f = fopen(fname, "r"); | ||
235 | if (!f) | ||
236 | continue; | ||
237 | if (fscanf(f, "%s %s", tmp2, tmp) != 2) | ||
238 | tmp[0] = 0; | ||
239 | fclose(f); | ||
240 | if (strncmp(tmp, "off-line", 8) == 0) { | ||
241 | closedir(d); | ||
242 | return 1; | ||
243 | } | ||
244 | } | ||
245 | closedir(d); | ||
246 | } | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * This routine checks to see if a filesystem can be skipped; if so, | ||
252 | * it will exit with E2FSCK_OK. Under some conditions it will print a | ||
253 | * message explaining why a check is being forced. | ||
254 | */ | ||
255 | static void check_if_skip(e2fsck_t ctx) | ||
256 | { | ||
257 | ext2_filsys fs = ctx->fs; | ||
258 | const char *reason = NULL; | ||
259 | unsigned int reason_arg = 0; | ||
260 | long next_check; | ||
261 | int batt = is_on_batt(); | ||
262 | time_t now = time(0); | ||
263 | |||
264 | if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file || | ||
265 | cflag || swapfs) | ||
266 | return; | ||
267 | |||
268 | if ((fs->super->s_state & EXT2_ERROR_FS) || | ||
269 | !ext2fs_test_valid(fs)) | ||
270 | reason = _(" contains a file system with errors"); | ||
271 | else if ((fs->super->s_state & EXT2_VALID_FS) == 0) | ||
272 | reason = _(" was not cleanly unmounted"); | ||
273 | else if ((fs->super->s_max_mnt_count > 0) && | ||
274 | (fs->super->s_mnt_count >= | ||
275 | (unsigned) fs->super->s_max_mnt_count)) { | ||
276 | reason = _(" has been mounted %u times without being checked"); | ||
277 | reason_arg = fs->super->s_mnt_count; | ||
278 | if (batt && (fs->super->s_mnt_count < | ||
279 | (unsigned) fs->super->s_max_mnt_count*2)) | ||
280 | reason = 0; | ||
281 | } else if (fs->super->s_checkinterval && | ||
282 | ((now - fs->super->s_lastcheck) >= | ||
283 | fs->super->s_checkinterval)) { | ||
284 | reason = _(" has gone %u days without being checked"); | ||
285 | reason_arg = (now - fs->super->s_lastcheck)/(3600*24); | ||
286 | if (batt && ((now - fs->super->s_lastcheck) < | ||
287 | fs->super->s_checkinterval*2)) | ||
288 | reason = 0; | ||
289 | } | ||
290 | if (reason) { | ||
291 | fputs(ctx->device_name, stdout); | ||
292 | printf(reason, reason_arg); | ||
293 | fputs(_(", check forced.\n"), stdout); | ||
294 | return; | ||
295 | } | ||
296 | printf(_("%s: clean, %d/%d files, %d/%d blocks"), ctx->device_name, | ||
297 | fs->super->s_inodes_count - fs->super->s_free_inodes_count, | ||
298 | fs->super->s_inodes_count, | ||
299 | fs->super->s_blocks_count - fs->super->s_free_blocks_count, | ||
300 | fs->super->s_blocks_count); | ||
301 | next_check = 100000; | ||
302 | if (fs->super->s_max_mnt_count > 0) { | ||
303 | next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count; | ||
304 | if (next_check <= 0) | ||
305 | next_check = 1; | ||
306 | } | ||
307 | if (fs->super->s_checkinterval && | ||
308 | ((now - fs->super->s_lastcheck) >= fs->super->s_checkinterval)) | ||
309 | next_check = 1; | ||
310 | if (next_check <= 5) { | ||
311 | if (next_check == 1) | ||
312 | fputs(_(" (check after next mount)"), stdout); | ||
313 | else | ||
314 | printf(_(" (check in %ld mounts)"), next_check); | ||
315 | } | ||
316 | fputc('\n', stdout); | ||
317 | ext2fs_close(fs); | ||
318 | ctx->fs = NULL; | ||
319 | e2fsck_free_context(ctx); | ||
320 | exit(FSCK_OK); | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * For completion notice | ||
325 | */ | ||
326 | struct percent_tbl { | ||
327 | int max_pass; | ||
328 | int table[32]; | ||
329 | }; | ||
330 | struct percent_tbl e2fsck_tbl = { | ||
331 | 5, { 0, 70, 90, 92, 95, 100 } | ||
332 | }; | ||
333 | static char bar[128], spaces[128]; | ||
334 | |||
335 | static float calc_percent(struct percent_tbl *tbl, int pass, int curr, | ||
336 | int max) | ||
337 | { | ||
338 | float percent; | ||
339 | |||
340 | if (pass <= 0) | ||
341 | return 0.0; | ||
342 | if (pass > tbl->max_pass || max == 0) | ||
343 | return 100.0; | ||
344 | percent = ((float) curr) / ((float) max); | ||
345 | return ((percent * (tbl->table[pass] - tbl->table[pass-1])) | ||
346 | + tbl->table[pass-1]); | ||
347 | } | ||
348 | |||
349 | extern void e2fsck_clear_progbar(e2fsck_t ctx) | ||
350 | { | ||
351 | if (!(ctx->flags & E2F_FLAG_PROG_BAR)) | ||
352 | return; | ||
353 | |||
354 | printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80), | ||
355 | ctx->stop_meta); | ||
356 | fflush(stdout); | ||
357 | ctx->flags &= ~E2F_FLAG_PROG_BAR; | ||
358 | } | ||
359 | |||
360 | int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent, | ||
361 | unsigned int dpynum) | ||
362 | { | ||
363 | static const char spinner[] = "\\|/-"; | ||
364 | int i; | ||
365 | unsigned int tick; | ||
366 | struct timeval tv; | ||
367 | int dpywidth; | ||
368 | int fixed_percent; | ||
369 | |||
370 | if (ctx->flags & E2F_FLAG_PROG_SUPPRESS) | ||
371 | return 0; | ||
372 | |||
373 | /* | ||
374 | * Calculate the new progress position. If the | ||
375 | * percentage hasn't changed, then we skip out right | ||
376 | * away. | ||
377 | */ | ||
378 | fixed_percent = (int) ((10 * percent) + 0.5); | ||
379 | if (ctx->progress_last_percent == fixed_percent) | ||
380 | return 0; | ||
381 | ctx->progress_last_percent = fixed_percent; | ||
382 | |||
383 | /* | ||
384 | * If we've already updated the spinner once within | ||
385 | * the last 1/8th of a second, no point doing it | ||
386 | * again. | ||
387 | */ | ||
388 | gettimeofday(&tv, NULL); | ||
389 | tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8)); | ||
390 | if ((tick == ctx->progress_last_time) && | ||
391 | (fixed_percent != 0) && (fixed_percent != 1000)) | ||
392 | return 0; | ||
393 | ctx->progress_last_time = tick; | ||
394 | |||
395 | /* | ||
396 | * Advance the spinner, and note that the progress bar | ||
397 | * will be on the screen | ||
398 | */ | ||
399 | ctx->progress_pos = (ctx->progress_pos+1) & 3; | ||
400 | ctx->flags |= E2F_FLAG_PROG_BAR; | ||
401 | |||
402 | dpywidth = 66 - strlen(label); | ||
403 | dpywidth = 8 * (dpywidth / 8); | ||
404 | if (dpynum) | ||
405 | dpywidth -= 8; | ||
406 | |||
407 | i = ((percent * dpywidth) + 50) / 100; | ||
408 | printf("%s%s: |%s%s", ctx->start_meta, label, | ||
409 | bar + (sizeof(bar) - (i+1)), | ||
410 | spaces + (sizeof(spaces) - (dpywidth - i + 1))); | ||
411 | if (fixed_percent == 1000) | ||
412 | fputc('|', stdout); | ||
413 | else | ||
414 | fputc(spinner[ctx->progress_pos & 3], stdout); | ||
415 | printf(" %4.1f%% ", percent); | ||
416 | if (dpynum) | ||
417 | printf("%u\r", dpynum); | ||
418 | else | ||
419 | fputs(" \r", stdout); | ||
420 | fputs(ctx->stop_meta, stdout); | ||
421 | |||
422 | if (fixed_percent == 1000) | ||
423 | e2fsck_clear_progbar(ctx); | ||
424 | fflush(stdout); | ||
425 | |||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static int e2fsck_update_progress(e2fsck_t ctx, int pass, | ||
430 | unsigned long cur, unsigned long max) | ||
431 | { | ||
432 | char buf[80]; | ||
433 | float percent; | ||
434 | |||
435 | if (pass == 0) | ||
436 | return 0; | ||
437 | |||
438 | if (ctx->progress_fd) { | ||
439 | sprintf(buf, "%d %lu %lu\n", pass, cur, max); | ||
440 | write(ctx->progress_fd, buf, strlen(buf)); | ||
441 | } else { | ||
442 | percent = calc_percent(&e2fsck_tbl, pass, cur, max); | ||
443 | e2fsck_simple_progress(ctx, ctx->device_name, | ||
444 | percent, 0); | ||
445 | } | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | #define PATH_SET "PATH=/sbin" | ||
450 | |||
451 | static void reserve_stdio_fds(void) | ||
452 | { | ||
453 | int fd; | ||
454 | |||
455 | while (1) { | ||
456 | fd = open("/dev/null", O_RDWR); | ||
457 | if (fd > 2) | ||
458 | break; | ||
459 | if (fd < 0) { | ||
460 | fprintf(stderr, _("ERROR: Couldn't open " | ||
461 | "/dev/null (%s)\n"), | ||
462 | strerror(errno)); | ||
463 | break; | ||
464 | } | ||
465 | } | ||
466 | close(fd); | ||
467 | } | ||
468 | |||
469 | #ifdef HAVE_SIGNAL_H | ||
470 | static void signal_progress_on(int sig EXT2FS_ATTR((unused))) | ||
471 | { | ||
472 | e2fsck_t ctx = e2fsck_global_ctx; | ||
473 | |||
474 | if (!ctx) | ||
475 | return; | ||
476 | |||
477 | ctx->progress = e2fsck_update_progress; | ||
478 | ctx->progress_fd = 0; | ||
479 | } | ||
480 | |||
481 | static void signal_progress_off(int sig EXT2FS_ATTR((unused))) | ||
482 | { | ||
483 | e2fsck_t ctx = e2fsck_global_ctx; | ||
484 | |||
485 | if (!ctx) | ||
486 | return; | ||
487 | |||
488 | e2fsck_clear_progbar(ctx); | ||
489 | ctx->progress = 0; | ||
490 | } | ||
491 | |||
492 | static void signal_cancel(int sig EXT2FS_ATTR((unused))) | ||
493 | { | ||
494 | e2fsck_t ctx = e2fsck_global_ctx; | ||
495 | |||
496 | if (!ctx) | ||
497 | exit(FSCK_CANCELED); | ||
498 | |||
499 | ctx->flags |= E2F_FLAG_CANCEL; | ||
500 | } | ||
501 | #endif | ||
502 | |||
503 | static void parse_extended_opts(e2fsck_t ctx, const char *opts) | ||
504 | { | ||
505 | char *buf, *token, *next, *p, *arg; | ||
506 | int ea_ver; | ||
507 | int extended_usage = 0; | ||
508 | |||
509 | buf = string_copy(ctx, opts, 0); | ||
510 | for (token = buf; token && *token; token = next) { | ||
511 | p = strchr(token, ','); | ||
512 | next = 0; | ||
513 | if (p) { | ||
514 | *p = 0; | ||
515 | next = p+1; | ||
516 | } | ||
517 | arg = strchr(token, '='); | ||
518 | if (arg) { | ||
519 | *arg = 0; | ||
520 | arg++; | ||
521 | } | ||
522 | if (strcmp(token, "ea_ver") == 0) { | ||
523 | if (!arg) { | ||
524 | extended_usage++; | ||
525 | continue; | ||
526 | } | ||
527 | ea_ver = strtoul(arg, &p, 0); | ||
528 | if (*p || | ||
529 | ((ea_ver != 1) && (ea_ver != 2))) { | ||
530 | fprintf(stderr, | ||
531 | _("Invalid EA version.\n")); | ||
532 | extended_usage++; | ||
533 | continue; | ||
534 | } | ||
535 | ctx->ext_attr_ver = ea_ver; | ||
536 | } else | ||
537 | extended_usage++; | ||
538 | } | ||
539 | if (extended_usage) { | ||
540 | fprintf(stderr, _("Extended options are separated by commas, " | ||
541 | "and may take an argument which\n" | ||
542 | "is set off by an equals ('=') sign. " | ||
543 | "Valid raid options are:\n" | ||
544 | "\tea_ver=<ea_version (1 or 2)\n\n")); | ||
545 | exit(1); | ||
546 | } | ||
547 | } | ||
548 | |||
549 | |||
550 | static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) | ||
551 | { | ||
552 | int flush = 0; | ||
553 | int c, fd; | ||
554 | #ifdef MTRACE | ||
555 | extern void *mallwatch; | ||
556 | #endif | ||
557 | e2fsck_t ctx; | ||
558 | errcode_t retval; | ||
559 | #ifdef HAVE_SIGNAL_H | ||
560 | struct sigaction sa; | ||
561 | #endif | ||
562 | char *extended_opts = 0; | ||
563 | |||
564 | retval = e2fsck_allocate_context(&ctx); | ||
565 | if (retval) | ||
566 | return retval; | ||
567 | |||
568 | *ret_ctx = ctx; | ||
569 | |||
570 | setvbuf(stdout, NULL, _IONBF, BUFSIZ); | ||
571 | setvbuf(stderr, NULL, _IONBF, BUFSIZ); | ||
572 | if (isatty(0) && isatty(1)) { | ||
573 | ctx->interactive = 1; | ||
574 | } else { | ||
575 | ctx->start_meta[0] = '\001'; | ||
576 | ctx->stop_meta[0] = '\002'; | ||
577 | } | ||
578 | memset(bar, '=', sizeof(bar)-1); | ||
579 | memset(spaces, ' ', sizeof(spaces)-1); | ||
580 | blkid_get_cache(&ctx->blkid, NULL); | ||
581 | |||
582 | if (argc && *argv) | ||
583 | ctx->program_name = *argv; | ||
584 | else | ||
585 | ctx->program_name = "e2fsck"; | ||
586 | while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF) | ||
587 | switch (c) { | ||
588 | case 'C': | ||
589 | ctx->progress = e2fsck_update_progress; | ||
590 | ctx->progress_fd = atoi(optarg); | ||
591 | if (!ctx->progress_fd) | ||
592 | break; | ||
593 | /* Validate the file descriptor to avoid disasters */ | ||
594 | fd = dup(ctx->progress_fd); | ||
595 | if (fd < 0) { | ||
596 | fprintf(stderr, | ||
597 | _("Error validating file descriptor %d: %s\n"), | ||
598 | ctx->progress_fd, | ||
599 | error_message(errno)); | ||
600 | fatal_error(ctx, | ||
601 | _("Invalid completion information file descriptor")); | ||
602 | } else | ||
603 | close(fd); | ||
604 | break; | ||
605 | case 'D': | ||
606 | ctx->options |= E2F_OPT_COMPRESS_DIRS; | ||
607 | break; | ||
608 | case 'E': | ||
609 | extended_opts = optarg; | ||
610 | break; | ||
611 | case 'p': | ||
612 | case 'a': | ||
613 | if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) { | ||
614 | conflict_opt: | ||
615 | fatal_error(ctx, | ||
616 | _("Only one the options -p/-a, -n or -y may be specified.")); | ||
617 | } | ||
618 | ctx->options |= E2F_OPT_PREEN; | ||
619 | break; | ||
620 | case 'n': | ||
621 | if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN)) | ||
622 | goto conflict_opt; | ||
623 | ctx->options |= E2F_OPT_NO; | ||
624 | break; | ||
625 | case 'y': | ||
626 | if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO)) | ||
627 | goto conflict_opt; | ||
628 | ctx->options |= E2F_OPT_YES; | ||
629 | break; | ||
630 | case 't': | ||
631 | #ifdef RESOURCE_TRACK | ||
632 | if (ctx->options & E2F_OPT_TIME) | ||
633 | ctx->options |= E2F_OPT_TIME2; | ||
634 | else | ||
635 | ctx->options |= E2F_OPT_TIME; | ||
636 | #else | ||
637 | fprintf(stderr, _("The -t option is not " | ||
638 | "supported on this version of e2fsck.\n")); | ||
639 | #endif | ||
640 | break; | ||
641 | case 'c': | ||
642 | if (cflag++) | ||
643 | ctx->options |= E2F_OPT_WRITECHECK; | ||
644 | ctx->options |= E2F_OPT_CHECKBLOCKS; | ||
645 | break; | ||
646 | case 'r': | ||
647 | /* What we do by default, anyway! */ | ||
648 | break; | ||
649 | case 'b': | ||
650 | ctx->use_superblock = atoi(optarg); | ||
651 | ctx->flags |= E2F_FLAG_SB_SPECIFIED; | ||
652 | break; | ||
653 | case 'B': | ||
654 | ctx->blocksize = atoi(optarg); | ||
655 | break; | ||
656 | case 'I': | ||
657 | ctx->inode_buffer_blocks = atoi(optarg); | ||
658 | break; | ||
659 | case 'j': | ||
660 | ctx->journal_name = string_copy(ctx, optarg, 0); | ||
661 | break; | ||
662 | case 'P': | ||
663 | ctx->process_inode_size = atoi(optarg); | ||
664 | break; | ||
665 | case 'L': | ||
666 | replace_bad_blocks++; | ||
667 | case 'l': | ||
668 | bad_blocks_file = string_copy(ctx, optarg, 0); | ||
669 | break; | ||
670 | case 'd': | ||
671 | ctx->options |= E2F_OPT_DEBUG; | ||
672 | break; | ||
673 | case 'f': | ||
674 | ctx->options |= E2F_OPT_FORCE; | ||
675 | break; | ||
676 | case 'F': | ||
677 | flush = 1; | ||
678 | break; | ||
679 | case 'v': | ||
680 | verbose = 1; | ||
681 | break; | ||
682 | case 'V': | ||
683 | show_version_only = 1; | ||
684 | break; | ||
685 | #ifdef MTRACE | ||
686 | case 'M': | ||
687 | mallwatch = (void *) strtol(optarg, NULL, 0); | ||
688 | break; | ||
689 | #endif | ||
690 | case 'N': | ||
691 | ctx->device_name = optarg; | ||
692 | break; | ||
693 | #ifdef ENABLE_SWAPFS | ||
694 | case 's': | ||
695 | normalize_swapfs = 1; | ||
696 | case 'S': | ||
697 | swapfs = 1; | ||
698 | break; | ||
699 | #else | ||
700 | case 's': | ||
701 | case 'S': | ||
702 | fprintf(stderr, _("Byte-swapping filesystems " | ||
703 | "not compiled in this version " | ||
704 | "of e2fsck\n")); | ||
705 | exit(1); | ||
706 | #endif | ||
707 | case 'k': | ||
708 | keep_bad_blocks++; | ||
709 | break; | ||
710 | default: | ||
711 | usage(); | ||
712 | } | ||
713 | if (show_version_only) | ||
714 | return 0; | ||
715 | if (optind != argc - 1) | ||
716 | usage(); | ||
717 | if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file && | ||
718 | !cflag && !swapfs && !(ctx->options & E2F_OPT_COMPRESS_DIRS)) | ||
719 | ctx->options |= E2F_OPT_READONLY; | ||
720 | ctx->io_options = strchr(argv[optind], '?'); | ||
721 | if (ctx->io_options) | ||
722 | *ctx->io_options++ = 0; | ||
723 | ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0); | ||
724 | if (!ctx->filesystem_name) { | ||
725 | com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), | ||
726 | argv[optind]); | ||
727 | fatal_error(ctx, 0); | ||
728 | } | ||
729 | if (extended_opts) | ||
730 | parse_extended_opts(ctx, extended_opts); | ||
731 | |||
732 | if (flush) { | ||
733 | fd = open(ctx->filesystem_name, O_RDONLY, 0); | ||
734 | if (fd < 0) { | ||
735 | com_err("open", errno, | ||
736 | _("while opening %s for flushing"), | ||
737 | ctx->filesystem_name); | ||
738 | fatal_error(ctx, 0); | ||
739 | } | ||
740 | if ((retval = ext2fs_sync_device(fd, 1))) { | ||
741 | com_err("ext2fs_sync_device", retval, | ||
742 | _("while trying to flush %s"), | ||
743 | ctx->filesystem_name); | ||
744 | fatal_error(ctx, 0); | ||
745 | } | ||
746 | close(fd); | ||
747 | } | ||
748 | #ifdef ENABLE_SWAPFS | ||
749 | if (swapfs) { | ||
750 | if (cflag || bad_blocks_file) { | ||
751 | fprintf(stderr, _("Incompatible options not " | ||
752 | "allowed when byte-swapping.\n")); | ||
753 | exit(FSCK_USAGE); | ||
754 | } | ||
755 | } | ||
756 | #endif | ||
757 | if (cflag && bad_blocks_file) { | ||
758 | fprintf(stderr, _("The -c and the -l/-L options may " | ||
759 | "not be both used at the same time.\n")); | ||
760 | exit(FSCK_USAGE); | ||
761 | } | ||
762 | #ifdef HAVE_SIGNAL_H | ||
763 | /* | ||
764 | * Set up signal action | ||
765 | */ | ||
766 | memset(&sa, 0, sizeof(struct sigaction)); | ||
767 | sa.sa_handler = signal_cancel; | ||
768 | sigaction(SIGINT, &sa, 0); | ||
769 | sigaction(SIGTERM, &sa, 0); | ||
770 | #ifdef SA_RESTART | ||
771 | sa.sa_flags = SA_RESTART; | ||
772 | #endif | ||
773 | e2fsck_global_ctx = ctx; | ||
774 | sa.sa_handler = signal_progress_on; | ||
775 | sigaction(SIGUSR1, &sa, 0); | ||
776 | sa.sa_handler = signal_progress_off; | ||
777 | sigaction(SIGUSR2, &sa, 0); | ||
778 | #endif | ||
779 | |||
780 | /* Update our PATH to include /sbin if we need to run badblocks */ | ||
781 | if (cflag) { | ||
782 | char *oldpath = getenv("PATH"); | ||
783 | if (oldpath) { | ||
784 | char *newpath; | ||
785 | |||
786 | newpath = (char *) malloc(sizeof (PATH_SET) + 1 + | ||
787 | strlen (oldpath)); | ||
788 | if (!newpath) | ||
789 | fatal_error(ctx, "Couldn't malloc() newpath"); | ||
790 | strcpy (newpath, PATH_SET); | ||
791 | strcat (newpath, ":"); | ||
792 | strcat (newpath, oldpath); | ||
793 | putenv (newpath); | ||
794 | } else | ||
795 | putenv (PATH_SET); | ||
796 | } | ||
797 | #ifdef __CONFIG_JBD_DEBUG__E2FS | ||
798 | if (getenv("E2FSCK_JBD_DEBUG")) | ||
799 | journal_enable_debug = atoi(getenv("E2FSCK_JBD_DEBUG")); | ||
800 | #endif | ||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | static const char *my_ver_string = E2FSPROGS_VERSION; | ||
805 | static const char *my_ver_date = E2FSPROGS_DATE; | ||
806 | |||
807 | int e2fsck_main (int argc, char *argv[]) | ||
808 | { | ||
809 | errcode_t retval = 0; | ||
810 | int exit_value = FSCK_OK; | ||
811 | ext2_filsys fs = 0; | ||
812 | io_manager io_ptr; | ||
813 | struct ext2_super_block *sb; | ||
814 | const char *lib_ver_date; | ||
815 | int my_ver, lib_ver; | ||
816 | e2fsck_t ctx; | ||
817 | struct problem_context pctx; | ||
818 | int flags, run_result; | ||
819 | |||
820 | clear_problem_context(&pctx); | ||
821 | #ifdef MTRACE | ||
822 | mtrace(); | ||
823 | #endif | ||
824 | #ifdef MCHECK | ||
825 | mcheck(0); | ||
826 | #endif | ||
827 | #ifdef ENABLE_NLS | ||
828 | setlocale(LC_MESSAGES, ""); | ||
829 | setlocale(LC_CTYPE, ""); | ||
830 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); | ||
831 | textdomain(NLS_CAT_NAME); | ||
832 | #endif | ||
833 | my_ver = ext2fs_parse_version_string(my_ver_string); | ||
834 | lib_ver = ext2fs_get_library_version(0, &lib_ver_date); | ||
835 | if (my_ver > lib_ver) { | ||
836 | fprintf( stderr, _("Error: ext2fs library version " | ||
837 | "out of date!\n")); | ||
838 | show_version_only++; | ||
839 | } | ||
840 | |||
841 | retval = PRS(argc, argv, &ctx); | ||
842 | if (retval) { | ||
843 | com_err("e2fsck", retval, | ||
844 | _("while trying to initialize program")); | ||
845 | exit(FSCK_ERROR); | ||
846 | } | ||
847 | reserve_stdio_fds(); | ||
848 | |||
849 | #ifdef RESOURCE_TRACK | ||
850 | init_resource_track(&ctx->global_rtrack); | ||
851 | #endif | ||
852 | |||
853 | if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) | ||
854 | fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string, | ||
855 | my_ver_date); | ||
856 | |||
857 | if (show_version_only) { | ||
858 | fprintf(stderr, _("\tUsing %s, %s\n"), | ||
859 | error_message(EXT2_ET_BASE), lib_ver_date); | ||
860 | exit(FSCK_OK); | ||
861 | } | ||
862 | |||
863 | check_mount(ctx); | ||
864 | |||
865 | if (!(ctx->options & E2F_OPT_PREEN) && | ||
866 | !(ctx->options & E2F_OPT_NO) && | ||
867 | !(ctx->options & E2F_OPT_YES)) { | ||
868 | if (!ctx->interactive) | ||
869 | fatal_error(ctx, | ||
870 | _("need terminal for interactive repairs")); | ||
871 | } | ||
872 | ctx->superblock = ctx->use_superblock; | ||
873 | restart: | ||
874 | #ifdef CONFIG_TESTIO_DEBUG | ||
875 | io_ptr = test_io_manager; | ||
876 | test_io_backing_manager = unix_io_manager; | ||
877 | #else | ||
878 | io_ptr = unix_io_manager; | ||
879 | #endif | ||
880 | flags = 0; | ||
881 | if ((ctx->options & E2F_OPT_READONLY) == 0) | ||
882 | flags |= EXT2_FLAG_RW; | ||
883 | |||
884 | if (ctx->superblock && ctx->blocksize) { | ||
885 | retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, | ||
886 | flags, ctx->superblock, ctx->blocksize, | ||
887 | io_ptr, &fs); | ||
888 | } else if (ctx->superblock) { | ||
889 | int blocksize; | ||
890 | for (blocksize = EXT2_MIN_BLOCK_SIZE; | ||
891 | blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { | ||
892 | retval = ext2fs_open2(ctx->filesystem_name, | ||
893 | ctx->io_options, flags, | ||
894 | ctx->superblock, blocksize, | ||
895 | io_ptr, &fs); | ||
896 | if (!retval) | ||
897 | break; | ||
898 | } | ||
899 | } else | ||
900 | retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, | ||
901 | flags, 0, 0, io_ptr, &fs); | ||
902 | if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && | ||
903 | !(ctx->flags & E2F_FLAG_SB_SPECIFIED) && | ||
904 | ((retval == EXT2_ET_BAD_MAGIC) || | ||
905 | ((retval == 0) && ext2fs_check_desc(fs)))) { | ||
906 | if (!fs || (fs->group_desc_count > 1)) { | ||
907 | printf(_("%s trying backup blocks...\n"), | ||
908 | retval ? _("Couldn't find ext2 superblock,") : | ||
909 | _("Group descriptors look bad...")); | ||
910 | get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr); | ||
911 | if (fs) | ||
912 | ext2fs_close(fs); | ||
913 | goto restart; | ||
914 | } | ||
915 | } | ||
916 | if (retval) { | ||
917 | com_err(ctx->program_name, retval, _("while trying to open %s"), | ||
918 | ctx->filesystem_name); | ||
919 | if (retval == EXT2_ET_REV_TOO_HIGH) { | ||
920 | printf(_("The filesystem revision is apparently " | ||
921 | "too high for this version of e2fsck.\n" | ||
922 | "(Or the filesystem superblock " | ||
923 | "is corrupt)\n\n")); | ||
924 | fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); | ||
925 | } else if (retval == EXT2_ET_SHORT_READ) | ||
926 | printf(_("Could this be a zero-length partition?\n")); | ||
927 | else if ((retval == EPERM) || (retval == EACCES)) | ||
928 | printf(_("You must have %s access to the " | ||
929 | "filesystem or be root\n"), | ||
930 | (ctx->options & E2F_OPT_READONLY) ? | ||
931 | "r/o" : "r/w"); | ||
932 | else if (retval == ENXIO) | ||
933 | printf(_("Possibly non-existent or swap device?\n")); | ||
934 | #ifdef EROFS | ||
935 | else if (retval == EROFS) | ||
936 | printf(_("Disk write-protected; use the -n option " | ||
937 | "to do a read-only\n" | ||
938 | "check of the device.\n")); | ||
939 | #endif | ||
940 | else | ||
941 | fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); | ||
942 | fatal_error(ctx, 0); | ||
943 | } | ||
944 | ctx->fs = fs; | ||
945 | fs->priv_data = ctx; | ||
946 | sb = fs->super; | ||
947 | if (sb->s_rev_level > E2FSCK_CURRENT_REV) { | ||
948 | com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH, | ||
949 | _("while trying to open %s"), | ||
950 | ctx->filesystem_name); | ||
951 | get_newer: | ||
952 | fatal_error(ctx, _("Get a newer version of e2fsck!")); | ||
953 | } | ||
954 | |||
955 | /* | ||
956 | * Set the device name, which is used whenever we print error | ||
957 | * or informational messages to the user. | ||
958 | */ | ||
959 | if (ctx->device_name == 0 && | ||
960 | (sb->s_volume_name[0] != 0)) { | ||
961 | ctx->device_name = string_copy(ctx, sb->s_volume_name, | ||
962 | sizeof(sb->s_volume_name)); | ||
963 | } | ||
964 | if (ctx->device_name == 0) | ||
965 | ctx->device_name = ctx->filesystem_name; | ||
966 | |||
967 | /* | ||
968 | * Make sure the ext3 superblock fields are consistent. | ||
969 | */ | ||
970 | retval = e2fsck_check_ext3_journal(ctx); | ||
971 | if (retval) { | ||
972 | com_err(ctx->program_name, retval, | ||
973 | _("while checking ext3 journal for %s"), | ||
974 | ctx->device_name); | ||
975 | fatal_error(ctx, 0); | ||
976 | } | ||
977 | |||
978 | /* | ||
979 | * Check to see if we need to do ext3-style recovery. If so, | ||
980 | * do it, and then restart the fsck. | ||
981 | */ | ||
982 | if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { | ||
983 | if (ctx->options & E2F_OPT_READONLY) { | ||
984 | printf(_("Warning: skipping journal recovery " | ||
985 | "because doing a read-only filesystem " | ||
986 | "check.\n")); | ||
987 | io_channel_flush(ctx->fs->io); | ||
988 | } else { | ||
989 | if (ctx->flags & E2F_FLAG_RESTARTED) { | ||
990 | /* | ||
991 | * Whoops, we attempted to run the | ||
992 | * journal twice. This should never | ||
993 | * happen, unless the hardware or | ||
994 | * device driver is being bogus. | ||
995 | */ | ||
996 | com_err(ctx->program_name, 0, | ||
997 | _("unable to set superblock flags on %s\n"), ctx->device_name); | ||
998 | fatal_error(ctx, 0); | ||
999 | } | ||
1000 | retval = e2fsck_run_ext3_journal(ctx); | ||
1001 | if (retval) { | ||
1002 | com_err(ctx->program_name, retval, | ||
1003 | _("while recovering ext3 journal of %s"), | ||
1004 | ctx->device_name); | ||
1005 | fatal_error(ctx, 0); | ||
1006 | } | ||
1007 | ext2fs_close(ctx->fs); | ||
1008 | ctx->fs = 0; | ||
1009 | ctx->flags |= E2F_FLAG_RESTARTED; | ||
1010 | goto restart; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | /* | ||
1015 | * Check for compatibility with the feature sets. We need to | ||
1016 | * be more stringent than ext2fs_open(). | ||
1017 | */ | ||
1018 | if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) || | ||
1019 | (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) { | ||
1020 | com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE, | ||
1021 | "(%s)", ctx->device_name); | ||
1022 | goto get_newer; | ||
1023 | } | ||
1024 | if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { | ||
1025 | com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE, | ||
1026 | "(%s)", ctx->device_name); | ||
1027 | goto get_newer; | ||
1028 | } | ||
1029 | #ifdef ENABLE_COMPRESSION | ||
1030 | if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) | ||
1031 | com_err(ctx->program_name, 0, | ||
1032 | _("Warning: compression support is experimental.\n")); | ||
1033 | #endif | ||
1034 | #ifndef ENABLE_HTREE | ||
1035 | if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) { | ||
1036 | com_err(ctx->program_name, 0, | ||
1037 | _("E2fsck not compiled with HTREE support,\n\t" | ||
1038 | "but filesystem %s has HTREE directories.\n"), | ||
1039 | ctx->device_name); | ||
1040 | goto get_newer; | ||
1041 | } | ||
1042 | #endif | ||
1043 | |||
1044 | /* | ||
1045 | * If the user specified a specific superblock, presumably the | ||
1046 | * master superblock has been trashed. So we mark the | ||
1047 | * superblock as dirty, so it can be written out. | ||
1048 | */ | ||
1049 | if (ctx->superblock && | ||
1050 | !(ctx->options & E2F_OPT_READONLY)) | ||
1051 | ext2fs_mark_super_dirty(fs); | ||
1052 | |||
1053 | /* | ||
1054 | * We only update the master superblock because (a) paranoia; | ||
1055 | * we don't want to corrupt the backup superblocks, and (b) we | ||
1056 | * don't need to update the mount count and last checked | ||
1057 | * fields in the backup superblock (the kernel doesn't | ||
1058 | * update the backup superblocks anyway). | ||
1059 | */ | ||
1060 | fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; | ||
1061 | |||
1062 | ehandler_init(fs->io); | ||
1063 | |||
1064 | if (ctx->superblock) | ||
1065 | set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0); | ||
1066 | ext2fs_mark_valid(fs); | ||
1067 | check_super_block(ctx); | ||
1068 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) | ||
1069 | fatal_error(ctx, 0); | ||
1070 | check_if_skip(ctx); | ||
1071 | if (bad_blocks_file) | ||
1072 | read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks); | ||
1073 | else if (cflag) | ||
1074 | read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */ | ||
1075 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) | ||
1076 | fatal_error(ctx, 0); | ||
1077 | #ifdef ENABLE_SWAPFS | ||
1078 | if (normalize_swapfs) { | ||
1079 | if ((fs->flags & EXT2_FLAG_SWAP_BYTES) == | ||
1080 | ext2fs_native_flag()) { | ||
1081 | fprintf(stderr, _("%s: Filesystem byte order " | ||
1082 | "already normalized.\n"), ctx->device_name); | ||
1083 | fatal_error(ctx, 0); | ||
1084 | } | ||
1085 | } | ||
1086 | if (swapfs) { | ||
1087 | swap_filesys(ctx); | ||
1088 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) | ||
1089 | fatal_error(ctx, 0); | ||
1090 | } | ||
1091 | #endif | ||
1092 | |||
1093 | /* | ||
1094 | * Mark the system as valid, 'til proven otherwise | ||
1095 | */ | ||
1096 | ext2fs_mark_valid(fs); | ||
1097 | |||
1098 | retval = ext2fs_read_bb_inode(fs, &fs->badblocks); | ||
1099 | if (retval) { | ||
1100 | com_err(ctx->program_name, retval, | ||
1101 | _("while reading bad blocks inode")); | ||
1102 | preenhalt(ctx); | ||
1103 | printf(_("This doesn't bode well," | ||
1104 | " but we'll try to go on...\n")); | ||
1105 | } | ||
1106 | |||
1107 | run_result = e2fsck_run(ctx); | ||
1108 | e2fsck_clear_progbar(ctx); | ||
1109 | if (run_result == E2F_FLAG_RESTART) { | ||
1110 | printf(_("Restarting e2fsck from the beginning...\n")); | ||
1111 | retval = e2fsck_reset_context(ctx); | ||
1112 | if (retval) { | ||
1113 | com_err(ctx->program_name, retval, | ||
1114 | _("while resetting context")); | ||
1115 | fatal_error(ctx, 0); | ||
1116 | } | ||
1117 | ext2fs_close(fs); | ||
1118 | goto restart; | ||
1119 | } | ||
1120 | if (run_result & E2F_FLAG_CANCEL) { | ||
1121 | printf(_("%s: e2fsck canceled.\n"), ctx->device_name ? | ||
1122 | ctx->device_name : ctx->filesystem_name); | ||
1123 | exit_value |= FSCK_CANCELED; | ||
1124 | } | ||
1125 | if (run_result & E2F_FLAG_ABORT) | ||
1126 | fatal_error(ctx, _("aborted")); | ||
1127 | |||
1128 | #ifdef MTRACE | ||
1129 | mtrace_print("Cleanup"); | ||
1130 | #endif | ||
1131 | if (ext2fs_test_changed(fs)) { | ||
1132 | exit_value |= FSCK_NONDESTRUCT; | ||
1133 | if (!(ctx->options & E2F_OPT_PREEN)) | ||
1134 | printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"), | ||
1135 | ctx->device_name); | ||
1136 | if (ctx->mount_flags & EXT2_MF_ISROOT) { | ||
1137 | printf(_("%s: ***** REBOOT LINUX *****\n"), | ||
1138 | ctx->device_name); | ||
1139 | exit_value |= FSCK_REBOOT; | ||
1140 | } | ||
1141 | } | ||
1142 | if (!ext2fs_test_valid(fs)) { | ||
1143 | printf(_("\n%s: ********** WARNING: Filesystem still has " | ||
1144 | "errors **********\n\n"), ctx->device_name); | ||
1145 | exit_value |= FSCK_UNCORRECTED; | ||
1146 | exit_value &= ~FSCK_NONDESTRUCT; | ||
1147 | } | ||
1148 | if (exit_value & FSCK_CANCELED) | ||
1149 | exit_value &= ~FSCK_NONDESTRUCT; | ||
1150 | else { | ||
1151 | show_stats(ctx); | ||
1152 | if (!(ctx->options & E2F_OPT_READONLY)) { | ||
1153 | if (ext2fs_test_valid(fs)) { | ||
1154 | if (!(sb->s_state & EXT2_VALID_FS)) | ||
1155 | exit_value |= FSCK_NONDESTRUCT; | ||
1156 | sb->s_state = EXT2_VALID_FS; | ||
1157 | } else | ||
1158 | sb->s_state &= ~EXT2_VALID_FS; | ||
1159 | sb->s_mnt_count = 0; | ||
1160 | sb->s_lastcheck = time(NULL); | ||
1161 | ext2fs_mark_super_dirty(fs); | ||
1162 | } | ||
1163 | } | ||
1164 | |||
1165 | e2fsck_write_bitmaps(ctx); | ||
1166 | |||
1167 | ext2fs_close(fs); | ||
1168 | ctx->fs = NULL; | ||
1169 | free(ctx->filesystem_name); | ||
1170 | free(ctx->journal_name); | ||
1171 | e2fsck_free_context(ctx); | ||
1172 | |||
1173 | #ifdef RESOURCE_TRACK | ||
1174 | if (ctx->options & E2F_OPT_TIME) | ||
1175 | print_resource_track(NULL, &ctx->global_rtrack); | ||
1176 | #endif | ||
1177 | |||
1178 | return exit_value; | ||
1179 | } | ||