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 #define _XOPEN_SOURCE 600 /* for inclusion of sa_handler in Solaris */ 13 14 #include <stdio.h> 15 #ifdef HAVE_STDLIB_H 16 #include <stdlib.h> 17 #endif 18 #include <string.h> 19 #include <fcntl.h> 20 #include <ctype.h> 21 #include <time.h> 22 #ifdef HAVE_SIGNAL_H 23 #include <signal.h> 24 #endif 25 #ifdef HAVE_GETOPT_H 26 #include <getopt.h> 27 #else 28 extern char *optarg; 29 extern int optind; 30 #endif 31 #include <unistd.h> 32 #ifdef HAVE_ERRNO_H 33 #include <errno.h> 34 #endif 35 #ifdef HAVE_MNTENT_H 36 #include <mntent.h> 37 #endif 38 #ifdef HAVE_SYS_IOCTL_H 39 #include <sys/ioctl.h> 40 #endif 41 #ifdef HAVE_MALLOC_H 42 #include <malloc.h> 43 #endif 44 #ifdef HAVE_SYS_TYPES_H 45 #include <sys/types.h> 46 #endif 47 #ifdef HAVE_DIRENT_H 48 #include <dirent.h> 49 #endif 50 51 #include "e2p/e2p.h" 52 #include "et/com_err.h" 53 #include "e2p/e2p.h" 54 #include "e2fsck.h" 55 #include "problem.h" 56 #include "../version.h" 57 58 /* Command line options */ 59 static int cflag; /* check disk */ 60 static int show_version_only; 61 static int verbose; 62 63 static int replace_bad_blocks; 64 static int keep_bad_blocks; 65 static char *bad_blocks_file; 66 67 e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ 68 69 #ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jfs-debug */ 70 int journal_enable_debug = -1; 71 #endif 72 73 #ifndef ROOT_SYSCONFDIR 74 #define ROOT_SYSCONFDIR "/etc/" 75 #endif 76 77 static void usage(e2fsck_t ctx) 78 { 79 fprintf(stderr, 80 _("Usage: %s [-panyrcdfvtDFV] [-b superblock] [-B blocksize]\n" 81 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" 82 "\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n" 83 "\t\t[-E extended-options] device\n"), 84 ctx->program_name); 85 86 fprintf(stderr, _("\nEmergency help:\n" 87 " -p Automatic repair (no questions)\n" 88 " -n Make no changes to the filesystem\n" 89 " -y Assume \"yes\" to all questions\n" 90 " -c Check for bad blocks and add them to the badblock list\n" 91 " -f Force checking even if filesystem is marked clean\n")); 92 fprintf(stderr, _("" 93 " -v Be verbose\n" 94 " -b superblock Use alternative superblock\n" 95 " -B blocksize Force blocksize when looking for superblock\n" 96 " -j external_journal Set location of the external journal\n" 97 " -l bad_blocks_file Add to badblocks list\n" 98 " -L bad_blocks_file Set badblocks list\n" 99 )); 100 101 exit(FSCK_USAGE); 102 } 103 104 static void show_stats(e2fsck_t ctx) 105 { 106 ext2_filsys fs = ctx->fs; 107 ext2_ino_t inodes, inodes_used; 108 blk_t blocks, blocks_used; 109 int dir_links; 110 int num_files, num_links; 111 int frag_percent_file, frag_percent_dir, frag_percent_total; 112 int i, j; 113 114 dir_links = 2 * ctx->fs_directory_count - 1; 115 num_files = ctx->fs_total_count - dir_links; 116 num_links = ctx->fs_links_count - dir_links; 117 inodes = fs->super->s_inodes_count; 118 inodes_used = (fs->super->s_inodes_count - 119 fs->super->s_free_inodes_count); 120 blocks = fs->super->s_blocks_count; 121 blocks_used = (fs->super->s_blocks_count - 122 fs->super->s_free_blocks_count); 123 124 frag_percent_file = (10000 * ctx->fs_fragmented) / inodes_used; 125 frag_percent_file = (frag_percent_file + 5) / 10; 126 127 frag_percent_dir = (10000 * ctx->fs_fragmented_dir) / inodes_used; 128 frag_percent_dir = (frag_percent_dir + 5) / 10; 129 130 frag_percent_total = ((10000 * (ctx->fs_fragmented + 131 ctx->fs_fragmented_dir)) 132 / inodes_used); 133 frag_percent_total = (frag_percent_total + 5) / 10; 134 135 if (!verbose) { 136 printf(_("%s: %u/%u files (%0d.%d%% non-contiguous), %u/%u blocks\n"), 137 ctx->device_name, inodes_used, inodes, 138 frag_percent_total / 10, frag_percent_total % 10, 139 blocks_used, blocks); 140 return; 141 } 142 printf (P_("\n%8u inode used (%2.2f%%)\n", "\n%8u inodes used (%2.2f%%)\n", 143 inodes_used), inodes_used, 100.0 * inodes_used / inodes); 144 printf (P_("%8u non-contiguous file (%0d.%d%%)\n", 145 "%8u non-contiguous files (%0d.%d%%)\n", 146 ctx->fs_fragmented), 147 ctx->fs_fragmented, frag_percent_file / 10, 148 frag_percent_file % 10); 149 printf (P_("%8u non-contiguous directory (%0d.%d%%)\n", 150 "%8u non-contiguous directories (%0d.%d%%)\n", 151 ctx->fs_fragmented_dir), 152 ctx->fs_fragmented_dir, frag_percent_dir / 10, 153 frag_percent_dir % 10); 154 printf (_(" # of inodes with ind/dind/tind blocks: %u/%u/%u\n"), 155 ctx->fs_ind_count, ctx->fs_dind_count, ctx->fs_tind_count); 156 157 for (j=MAX_EXTENT_DEPTH_COUNT-1; j >=0; j--) 158 if (ctx->extent_depth_count[j]) 159 break; 160 if (++j) { 161 printf (_(" Extent depth histogram: ")); 162 for (i=0; i < j; i++) { 163 if (i) 164 fputc('/', stdout); 165 printf("%u", ctx->extent_depth_count[i]); 166 } 167 fputc('\n', stdout); 168 } 169 170 printf (P_("%8u block used (%2.2f%%)\n", "%8u blocks used (%2.2f%%)\n", 171 blocks_used), blocks_used, 100.0 * blocks_used / blocks); 172 printf (P_("%8u bad block\n", "%8u bad blocks\n", 173 ctx->fs_badblocks_count), ctx->fs_badblocks_count); 174 printf (P_("%8u large file\n", "%8u large files\n", 175 ctx->large_files), ctx->large_files); 176 printf (P_("\n%8u regular file\n", "\n%8u regular files\n", 177 ctx->fs_regular_count), ctx->fs_regular_count); 178 printf (P_("%8u directory\n", "%8u directories\n", 179 ctx->fs_directory_count), ctx->fs_directory_count); 180 printf (P_("%8u character device file\n", 181 "%8u character device files\n", ctx->fs_chardev_count), 182 ctx->fs_chardev_count); 183 printf (P_("%8u block device file\n", "%8u block device files\n", 184 ctx->fs_blockdev_count), ctx->fs_blockdev_count); 185 printf (P_("%8u fifo\n", "%8u fifos\n", ctx->fs_fifo_count), 186 ctx->fs_fifo_count); 187 printf (P_("%8u link\n", "%8u links\n", 188 ctx->fs_links_count - dir_links), 189 ctx->fs_links_count - dir_links); 190 printf (P_("%8u symbolic link", "%8u symbolic links", 191 ctx->fs_symlinks_count), ctx->fs_symlinks_count); 192 printf (P_(" (%u fast symbolic link)\n", " (%u fast symbolic links)\n", 193 ctx->fs_fast_symlinks_count), ctx->fs_fast_symlinks_count); 194 printf (P_("%8u socket\n", "%8u sockets\n", ctx->fs_sockets_count), 195 ctx->fs_sockets_count); 196 printf ("--------\n"); 197 printf (P_("%8u file\n", "%8u files\n", 198 ctx->fs_total_count - dir_links), 199 ctx->fs_total_count - dir_links); 200 } 201 202 static void check_mount(e2fsck_t ctx) 203 { 204 errcode_t retval; 205 int cont; 206 207 retval = ext2fs_check_if_mounted(ctx->filesystem_name, 208 &ctx->mount_flags); 209 if (retval) { 210 com_err("ext2fs_check_if_mount", retval, 211 _("while determining whether %s is mounted."), 212 ctx->filesystem_name); 213 return; 214 } 215 216 /* 217 * If the filesystem isn't mounted, or it's the root 218 * filesystem and it's mounted read-only, and we're not doing 219 * a read/write check, then everything's fine. 220 */ 221 if ((!(ctx->mount_flags & EXT2_MF_MOUNTED)) || 222 ((ctx->mount_flags & EXT2_MF_ISROOT) && 223 (ctx->mount_flags & EXT2_MF_READONLY) && 224 !(ctx->options & E2F_OPT_WRITECHECK))) 225 return; 226 227 if ((ctx->options & E2F_OPT_READONLY) && 228 !(ctx->options & E2F_OPT_WRITECHECK)) { 229 printf(_("Warning! %s is mounted.\n"), ctx->filesystem_name); 230 return; 231 } 232 233 printf(_("%s is mounted. "), ctx->filesystem_name); 234 if (!ctx->interactive) 235 fatal_error(ctx, _("Cannot continue, aborting.\n\n")); 236 printf(_("\n\n\007\007\007\007WARNING!!! " 237 "The filesystem is mounted. If you continue you ***WILL***\n" 238 "cause ***SEVERE*** filesystem damage.\007\007\007\n\n")); 239 cont = ask_yn(_("Do you really want to continue"), -1); 240 if (!cont) { 241 printf (_("check aborted.\n")); 242 exit (0); 243 } 244 return; 245 } 246 247 static int is_on_batt(void) 248 { 249 FILE *f; 250 DIR *d; 251 char tmp[80], tmp2[80], fname[80]; 252 unsigned int acflag; 253 struct dirent* de; 254 255 f = fopen("/proc/apm", "r"); 256 if (f) { 257 if (fscanf(f, "%s %s %s %x", tmp, tmp, tmp, &acflag) != 4) 258 acflag = 1; 259 fclose(f); 260 return (acflag != 1); 261 } 262 d = opendir("/proc/acpi/ac_adapter"); 263 if (d) { 264 while ((de=readdir(d)) != NULL) { 265 if (!strncmp(".", de->d_name, 1)) 266 continue; 267 snprintf(fname, 80, "/proc/acpi/ac_adapter/%s/state", 268 de->d_name); 269 f = fopen(fname, "r"); 270 if (!f) 271 continue; 272 if (fscanf(f, "%s %s", tmp2, tmp) != 2) 273 tmp[0] = 0; 274 fclose(f); 275 if (strncmp(tmp, "off-line", 8) == 0) { 276 closedir(d); 277 return 1; 278 } 279 } 280 closedir(d); 281 } 282 return 0; 283 } 284 285 /* 286 * This routine checks to see if a filesystem can be skipped; if so, 287 * it will exit with E2FSCK_OK. Under some conditions it will print a 288 * message explaining why a check is being forced. 289 */ 290 static void check_if_skip(e2fsck_t ctx) 291 { 292 ext2_filsys fs = ctx->fs; 293 const char *reason = NULL; 294 unsigned int reason_arg = 0; 295 long next_check; 296 int batt = is_on_batt(); 297 int defer_check_on_battery; 298 time_t lastcheck; 299 300 profile_get_boolean(ctx->profile, "options", 301 "defer_check_on_battery", 0, 1, 302 &defer_check_on_battery); 303 if (!defer_check_on_battery) 304 batt = 0; 305 306 if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file || cflag) 307 return; 308 309 lastcheck = fs->super->s_lastcheck; 310 if (lastcheck > ctx->now) 311 lastcheck -= ctx->time_fudge; 312 if ((fs->super->s_state & EXT2_ERROR_FS) || 313 !ext2fs_test_valid(fs)) 314 reason = _(" contains a file system with errors"); 315 else if ((fs->super->s_state & EXT2_VALID_FS) == 0) 316 reason = _(" was not cleanly unmounted"); 317 else if (check_backup_super_block(ctx)) 318 reason = _(" primary superblock features different from backup"); 319 else if ((fs->super->s_max_mnt_count > 0) && 320 (fs->super->s_mnt_count >= 321 (unsigned) fs->super->s_max_mnt_count)) { 322 reason = _(" has been mounted %u times without being checked"); 323 reason_arg = fs->super->s_mnt_count; 324 if (batt && (fs->super->s_mnt_count < 325 (unsigned) fs->super->s_max_mnt_count*2)) 326 reason = 0; 327 } else if (fs->super->s_checkinterval && (ctx->now < lastcheck)) { 328 reason = _(" has filesystem last checked time in the future"); 329 if (batt) 330 reason = 0; 331 } else if (fs->super->s_checkinterval && 332 ((ctx->now - lastcheck) >= 333 ((time_t) fs->super->s_checkinterval))) { 334 reason = _(" has gone %u days without being checked"); 335 reason_arg = (ctx->now - fs->super->s_lastcheck)/(3600*24); 336 if (batt && ((ctx->now - fs->super->s_lastcheck) < 337 fs->super->s_checkinterval*2)) 338 reason = 0; 339 } 340 if (reason) { 341 fputs(ctx->device_name, stdout); 342 printf(reason, reason_arg); 343 fputs(_(", check forced.\n"), stdout); 344 return; 345 } 346 printf(_("%s: clean, %u/%u files, %u/%u blocks"), ctx->device_name, 347 fs->super->s_inodes_count - fs->super->s_free_inodes_count, 348 fs->super->s_inodes_count, 349 fs->super->s_blocks_count - fs->super->s_free_blocks_count, 350 fs->super->s_blocks_count); 351 next_check = 100000; 352 if (fs->super->s_max_mnt_count > 0) { 353 next_check = fs->super->s_max_mnt_count - fs->super->s_mnt_count; 354 if (next_check <= 0) 355 next_check = 1; 356 } 357 if (fs->super->s_checkinterval && 358 ((ctx->now - fs->super->s_lastcheck) >= fs->super->s_checkinterval)) 359 next_check = 1; 360 if (next_check <= 5) { 361 if (next_check == 1) { 362 if (batt) 363 fputs(_(" (check deferred; on battery)"), 364 stdout); 365 else 366 fputs(_(" (check after next mount)"), stdout); 367 } else 368 printf(_(" (check in %ld mounts)"), next_check); 369 } 370 fputc('\n', stdout); 371 ext2fs_close(fs); 372 ctx->fs = NULL; 373 e2fsck_free_context(ctx); 374 exit(FSCK_OK); 375 } 376 377 /* 378 * For completion notice 379 */ 380 struct percent_tbl { 381 int max_pass; 382 int table[32]; 383 }; 384 struct percent_tbl e2fsck_tbl = { 385 5, { 0, 70, 90, 92, 95, 100 } 386 }; 387 static char bar[128], spaces[128]; 388 389 static float calc_percent(struct percent_tbl *tbl, int pass, int curr, 390 int max) 391 { 392 float percent; 393 394 if (pass <= 0) 395 return 0.0; 396 if (pass > tbl->max_pass || max == 0) 397 return 100.0; 398 percent = ((float) curr) / ((float) max); 399 return ((percent * (tbl->table[pass] - tbl->table[pass-1])) 400 + tbl->table[pass-1]); 401 } 402 403 extern void e2fsck_clear_progbar(e2fsck_t ctx) 404 { 405 if (!(ctx->flags & E2F_FLAG_PROG_BAR)) 406 return; 407 408 printf("%s%s\r%s", ctx->start_meta, spaces + (sizeof(spaces) - 80), 409 ctx->stop_meta); 410 fflush(stdout); 411 ctx->flags &= ~E2F_FLAG_PROG_BAR; 412 } 413 414 int e2fsck_simple_progress(e2fsck_t ctx, const char *label, float percent, 415 unsigned int dpynum) 416 { 417 static const char spinner[] = "\\|/-"; 418 int i; 419 unsigned int tick; 420 struct timeval tv; 421 int dpywidth; 422 int fixed_percent; 423 424 if (ctx->flags & E2F_FLAG_PROG_SUPPRESS) 425 return 0; 426 427 /* 428 * Calculate the new progress position. If the 429 * percentage hasn't changed, then we skip out right 430 * away. 431 */ 432 fixed_percent = (int) ((10 * percent) + 0.5); 433 if (ctx->progress_last_percent == fixed_percent) 434 return 0; 435 ctx->progress_last_percent = fixed_percent; 436 437 /* 438 * If we've already updated the spinner once within 439 * the last 1/8th of a second, no point doing it 440 * again. 441 */ 442 gettimeofday(&tv, NULL); 443 tick = (tv.tv_sec << 3) + (tv.tv_usec / (1000000 / 8)); 444 if ((tick == ctx->progress_last_time) && 445 (fixed_percent != 0) && (fixed_percent != 1000)) 446 return 0; 447 ctx->progress_last_time = tick; 448 449 /* 450 * Advance the spinner, and note that the progress bar 451 * will be on the screen 452 */ 453 ctx->progress_pos = (ctx->progress_pos+1) & 3; 454 ctx->flags |= E2F_FLAG_PROG_BAR; 455 456 dpywidth = 66 - strlen(label); 457 dpywidth = 8 * (dpywidth / 8); 458 if (dpynum) 459 dpywidth -= 8; 460 461 i = ((percent * dpywidth) + 50) / 100; 462 printf("%s%s: |%s%s", ctx->start_meta, label, 463 bar + (sizeof(bar) - (i+1)), 464 spaces + (sizeof(spaces) - (dpywidth - i + 1))); 465 if (fixed_percent == 1000) 466 fputc('|', stdout); 467 else 468 fputc(spinner[ctx->progress_pos & 3], stdout); 469 printf(" %4.1f%% ", percent); 470 if (dpynum) 471 printf("%u\r", dpynum); 472 else 473 fputs(" \r", stdout); 474 fputs(ctx->stop_meta, stdout); 475 476 if (fixed_percent == 1000) 477 e2fsck_clear_progbar(ctx); 478 fflush(stdout); 479 480 return 0; 481 } 482 483 static int e2fsck_update_progress(e2fsck_t ctx, int pass, 484 unsigned long cur, unsigned long max) 485 { 486 char buf[1024]; 487 float percent; 488 489 if (pass == 0) 490 return 0; 491 492 if (ctx->progress_fd) { 493 snprintf(buf, sizeof(buf), "%d %lu %lu %s\n", 494 pass, cur, max, ctx->device_name); 495 write_all(ctx->progress_fd, buf, strlen(buf)); 496 } else { 497 percent = calc_percent(&e2fsck_tbl, pass, cur, max); 498 e2fsck_simple_progress(ctx, ctx->device_name, 499 percent, 0); 500 } 501 return 0; 502 } 503 504 #define PATH_SET "PATH=/sbin" 505 506 static void reserve_stdio_fds(void) 507 { 508 int fd; 509 510 while (1) { 511 fd = open("/dev/null", O_RDWR); 512 if (fd > 2) 513 break; 514 if (fd < 0) { 515 fprintf(stderr, _("ERROR: Couldn't open " 516 "/dev/null (%s)\n"), 517 strerror(errno)); 518 break; 519 } 520 } 521 close(fd); 522 } 523 524 #ifdef HAVE_SIGNAL_H 525 static void signal_progress_on(int sig EXT2FS_ATTR((unused))) 526 { 527 e2fsck_t ctx = e2fsck_global_ctx; 528 529 if (!ctx) 530 return; 531 532 ctx->progress = e2fsck_update_progress; 533 } 534 535 static void signal_progress_off(int sig EXT2FS_ATTR((unused))) 536 { 537 e2fsck_t ctx = e2fsck_global_ctx; 538 539 if (!ctx) 540 return; 541 542 e2fsck_clear_progbar(ctx); 543 ctx->progress = 0; 544 } 545 546 static void signal_cancel(int sig EXT2FS_ATTR((unused))) 547 { 548 e2fsck_t ctx = e2fsck_global_ctx; 549 550 if (!ctx) 551 exit(FSCK_CANCELED); 552 553 ctx->flags |= E2F_FLAG_CANCEL; 554 } 555 #endif 556 557 static void parse_extended_opts(e2fsck_t ctx, const char *opts) 558 { 559 char *buf, *token, *next, *p, *arg; 560 int ea_ver; 561 int extended_usage = 0; 562 563 buf = string_copy(ctx, opts, 0); 564 for (token = buf; token && *token; token = next) { 565 p = strchr(token, ','); 566 next = 0; 567 if (p) { 568 *p = 0; 569 next = p+1; 570 } 571 arg = strchr(token, '='); 572 if (arg) { 573 *arg = 0; 574 arg++; 575 } 576 if (strcmp(token, "ea_ver") == 0) { 577 if (!arg) { 578 extended_usage++; 579 continue; 580 } 581 ea_ver = strtoul(arg, &p, 0); 582 if (*p || 583 ((ea_ver != 1) && (ea_ver != 2))) { 584 fprintf(stderr, 585 _("Invalid EA version.\n")); 586 extended_usage++; 587 continue; 588 } 589 ctx->ext_attr_ver = ea_ver; 590 } else if (strcmp(token, "fragcheck") == 0) { 591 ctx->options |= E2F_OPT_FRAGCHECK; 592 continue; 593 } else { 594 fprintf(stderr, _("Unknown extended option: %s\n"), 595 token); 596 extended_usage++; 597 } 598 } 599 free(buf); 600 601 if (extended_usage) { 602 fputs(("\nExtended options are separated by commas, " 603 "and may take an argument which\n" 604 "is set off by an equals ('=') sign. " 605 "Valid extended options are:\n"), stderr); 606 fputs(("\tea_ver=<ea_version (1 or 2)>\n"), stderr); 607 fputs(("\tfragcheck\n"), stderr); 608 fputc('\n', stderr); 609 exit(1); 610 } 611 } 612 613 static void syntax_err_report(const char *filename, long err, int line_num) 614 { 615 fprintf(stderr, 616 _("Syntax error in e2fsck config file (%s, line #%d)\n\t%s\n"), 617 filename, line_num, error_message(err)); 618 exit(FSCK_ERROR); 619 } 620 621 static const char *config_fn[] = { ROOT_SYSCONFDIR "/e2fsck.conf", 0 }; 622 623 static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) 624 { 625 int flush = 0; 626 int c, fd; 627 #ifdef MTRACE 628 extern void *mallwatch; 629 #endif 630 e2fsck_t ctx; 631 errcode_t retval; 632 #ifdef HAVE_SIGNAL_H 633 struct sigaction sa; 634 #endif 635 char *extended_opts = 0; 636 char *cp; 637 int res; /* result of sscanf */ 638 #ifdef CONFIG_JBD_DEBUG 639 char *jbd_debug; 640 #endif 641 642 retval = e2fsck_allocate_context(&ctx); 643 if (retval) 644 return retval; 645 646 *ret_ctx = ctx; 647 648 setvbuf(stdout, NULL, _IONBF, BUFSIZ); 649 setvbuf(stderr, NULL, _IONBF, BUFSIZ); 650 if (isatty(0) && isatty(1)) { 651 ctx->interactive = 1; 652 } else { 653 ctx->start_meta[0] = '\001'; 654 ctx->stop_meta[0] = '\002'; 655 } 656 memset(bar, '=', sizeof(bar)-1); 657 memset(spaces, ' ', sizeof(spaces)-1); 658 add_error_table(&et_ext2_error_table); 659 add_error_table(&et_prof_error_table); 660 blkid_get_cache(&ctx->blkid, NULL); 661 662 if (argc && *argv) 663 ctx->program_name = *argv; 664 else 665 ctx->program_name = "e2fsck"; 666 while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF) 667 switch (c) { 668 case 'C': 669 ctx->progress = e2fsck_update_progress; 670 res = sscanf(optarg, "%d", &ctx->progress_fd); 671 if (res != 1) 672 goto sscanf_err; 673 674 if (ctx->progress_fd < 0) { 675 ctx->progress = 0; 676 ctx->progress_fd = ctx->progress_fd * -1; 677 } 678 if (!ctx->progress_fd) 679 break; 680 /* Validate the file descriptor to avoid disasters */ 681 fd = dup(ctx->progress_fd); 682 if (fd < 0) { 683 fprintf(stderr, 684 _("Error validating file descriptor %d: %s\n"), 685 ctx->progress_fd, 686 error_message(errno)); 687 fatal_error(ctx, 688 _("Invalid completion information file descriptor")); 689 } else 690 close(fd); 691 break; 692 case 'D': 693 ctx->options |= E2F_OPT_COMPRESS_DIRS; 694 break; 695 case 'E': 696 extended_opts = optarg; 697 break; 698 case 'p': 699 case 'a': 700 if (ctx->options & (E2F_OPT_YES|E2F_OPT_NO)) { 701 conflict_opt: 702 fatal_error(ctx, 703 _("Only one of the options -p/-a, -n or -y may be specified.")); 704 } 705 ctx->options |= E2F_OPT_PREEN; 706 break; 707 case 'n': 708 if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN)) 709 goto conflict_opt; 710 ctx->options |= E2F_OPT_NO; 711 break; 712 case 'y': 713 if (ctx->options & (E2F_OPT_PREEN|E2F_OPT_NO)) 714 goto conflict_opt; 715 ctx->options |= E2F_OPT_YES; 716 break; 717 case 't': 718 #ifdef RESOURCE_TRACK 719 if (ctx->options & E2F_OPT_TIME) 720 ctx->options |= E2F_OPT_TIME2; 721 else 722 ctx->options |= E2F_OPT_TIME; 723 #else 724 fprintf(stderr, _("The -t option is not " 725 "supported on this version of e2fsck.\n")); 726 #endif 727 break; 728 case 'c': 729 if (cflag++) 730 ctx->options |= E2F_OPT_WRITECHECK; 731 ctx->options |= E2F_OPT_CHECKBLOCKS; 732 break; 733 case 'r': 734 /* What we do by default, anyway! */ 735 break; 736 case 'b': 737 res = sscanf(optarg, "%u", &ctx->use_superblock); 738 if (res != 1) 739 goto sscanf_err; 740 ctx->flags |= E2F_FLAG_SB_SPECIFIED; 741 break; 742 case 'B': 743 ctx->blocksize = atoi(optarg); 744 break; 745 case 'I': 746 res = sscanf(optarg, "%d", &ctx->inode_buffer_blocks); 747 if (res != 1) 748 goto sscanf_err; 749 break; 750 case 'j': 751 ctx->journal_name = string_copy(ctx, optarg, 0); 752 break; 753 case 'P': 754 res = sscanf(optarg, "%d", &ctx->process_inode_size); 755 if (res != 1) 756 goto sscanf_err; 757 break; 758 case 'L': 759 replace_bad_blocks++; 760 case 'l': 761 bad_blocks_file = string_copy(ctx, optarg, 0); 762 break; 763 case 'd': 764 ctx->options |= E2F_OPT_DEBUG; 765 break; 766 case 'f': 767 ctx->options |= E2F_OPT_FORCE; 768 break; 769 case 'F': 770 flush = 1; 771 break; 772 case 'v': 773 verbose = 1; 774 break; 775 case 'V': 776 show_version_only = 1; 777 break; 778 #ifdef MTRACE 779 case 'M': 780 mallwatch = (void *) strtol(optarg, NULL, 0); 781 break; 782 #endif 783 case 'N': 784 ctx->device_name = string_copy(ctx, optarg, 0); 785 break; 786 case 'k': 787 keep_bad_blocks++; 788 break; 789 default: 790 usage(ctx); 791 } 792 if (show_version_only) 793 return 0; 794 if (optind != argc - 1) 795 usage(ctx); 796 if ((ctx->options & E2F_OPT_NO) && 797 (ctx->options & E2F_OPT_COMPRESS_DIRS)) { 798 com_err(ctx->program_name, 0, 799 _("The -n and -D options are incompatible.")); 800 fatal_error(ctx, 0); 801 } 802 if ((ctx->options & E2F_OPT_NO) && cflag) { 803 com_err(ctx->program_name, 0, 804 _("The -n and -c options are incompatible.")); 805 fatal_error(ctx, 0); 806 } 807 if ((ctx->options & E2F_OPT_NO) && bad_blocks_file) { 808 com_err(ctx->program_name, 0, 809 _("The -n and -l/-L options are incompatible.")); 810 fatal_error(ctx, 0); 811 } 812 if (ctx->options & E2F_OPT_NO) 813 ctx->options |= E2F_OPT_READONLY; 814 815 ctx->io_options = strchr(argv[optind], '?'); 816 if (ctx->io_options) 817 *ctx->io_options++ = 0; 818 ctx->filesystem_name = blkid_get_devname(ctx->blkid, argv[optind], 0); 819 if (!ctx->filesystem_name) { 820 com_err(ctx->program_name, 0, _("Unable to resolve '%s'"), 821 argv[optind]); 822 fatal_error(ctx, 0); 823 } 824 if (extended_opts) 825 parse_extended_opts(ctx, extended_opts); 826 827 if ((cp = getenv("E2FSCK_CONFIG")) != NULL) 828 config_fn[0] = cp; 829 profile_set_syntax_err_cb(syntax_err_report); 830 profile_init(config_fn, &ctx->profile); 831 832 if (flush) { 833 fd = open(ctx->filesystem_name, O_RDONLY, 0); 834 if (fd < 0) { 835 com_err("open", errno, 836 _("while opening %s for flushing"), 837 ctx->filesystem_name); 838 fatal_error(ctx, 0); 839 } 840 if ((retval = ext2fs_sync_device(fd, 1))) { 841 com_err("ext2fs_sync_device", retval, 842 _("while trying to flush %s"), 843 ctx->filesystem_name); 844 fatal_error(ctx, 0); 845 } 846 close(fd); 847 } 848 if (cflag && bad_blocks_file) { 849 fprintf(stderr, _("The -c and the -l/-L options may " 850 "not be both used at the same time.\n")); 851 exit(FSCK_USAGE); 852 } 853 #ifdef HAVE_SIGNAL_H 854 /* 855 * Set up signal action 856 */ 857 memset(&sa, 0, sizeof(struct sigaction)); 858 sa.sa_handler = signal_cancel; 859 sigaction(SIGINT, &sa, 0); 860 sigaction(SIGTERM, &sa, 0); 861 #ifdef SA_RESTART 862 sa.sa_flags = SA_RESTART; 863 #endif 864 e2fsck_global_ctx = ctx; 865 sa.sa_handler = signal_progress_on; 866 sigaction(SIGUSR1, &sa, 0); 867 sa.sa_handler = signal_progress_off; 868 sigaction(SIGUSR2, &sa, 0); 869 #endif 870 871 /* Update our PATH to include /sbin if we need to run badblocks */ 872 if (cflag) { 873 char *oldpath = getenv("PATH"); 874 char *newpath; 875 int len = sizeof(PATH_SET) + 1; 876 877 if (oldpath) 878 len += strlen(oldpath); 879 880 newpath = malloc(len); 881 if (!newpath) 882 fatal_error(ctx, "Couldn't malloc() newpath"); 883 strcpy(newpath, PATH_SET); 884 885 if (oldpath) { 886 strcat(newpath, ":"); 887 strcat(newpath, oldpath); 888 } 889 putenv(newpath); 890 } 891 #ifdef CONFIG_JBD_DEBUG 892 jbd_debug = getenv("E2FSCK_JBD_DEBUG"); 893 if (jbd_debug) { 894 res = sscanf(jbd_debug, "%d", &journal_enable_debug); 895 if (res != 1) { 896 fprintf(stderr, 897 _("E2FSCK_JBD_DEBUG \"%s\" not an integer\n\n"), 898 jbd_debug); 899 exit (1); 900 } 901 } 902 #endif 903 return 0; 904 905 sscanf_err: 906 fprintf(stderr, _("\nInvalid non-numeric argument to -%c (\"%s\")\n\n"), 907 c, optarg); 908 exit (1); 909 } 910 911 static errcode_t try_open_fs(e2fsck_t ctx, int flags, io_manager io_ptr, 912 ext2_filsys *ret_fs) 913 { 914 errcode_t retval; 915 916 *ret_fs = NULL; 917 if (ctx->superblock && ctx->blocksize) { 918 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, 919 flags, ctx->superblock, ctx->blocksize, 920 io_ptr, ret_fs); 921 } else if (ctx->superblock) { 922 int blocksize; 923 for (blocksize = EXT2_MIN_BLOCK_SIZE; 924 blocksize <= EXT2_MAX_BLOCK_SIZE; blocksize *= 2) { 925 if (*ret_fs) { 926 ext2fs_free(*ret_fs); 927 *ret_fs = NULL; 928 } 929 retval = ext2fs_open2(ctx->filesystem_name, 930 ctx->io_options, flags, 931 ctx->superblock, blocksize, 932 io_ptr, ret_fs); 933 if (!retval) 934 break; 935 } 936 } else 937 retval = ext2fs_open2(ctx->filesystem_name, ctx->io_options, 938 flags, 0, 0, io_ptr, ret_fs); 939 return retval; 940 } 941 942 943 static const char *my_ver_string = E2FSPROGS_VERSION; 944 static const char *my_ver_date = E2FSPROGS_DATE; 945 946 int main (int argc, char *argv[]) 947 { 948 errcode_t retval = 0, retval2 = 0, orig_retval = 0; 949 int exit_value = FSCK_OK; 950 ext2_filsys fs = 0; 951 io_manager io_ptr; 952 struct ext2_super_block *sb; 953 const char *lib_ver_date; 954 int my_ver, lib_ver; 955 e2fsck_t ctx; 956 blk_t orig_superblock; 957 struct problem_context pctx; 958 int flags, run_result; 959 int journal_size; 960 int sysval, sys_page_size = 4096; 961 __u32 features[3]; 962 char *cp; 963 964 clear_problem_context(&pctx); 965 #ifdef MTRACE 966 mtrace(); 967 #endif 968 #ifdef MCHECK 969 mcheck(0); 970 #endif 971 #ifdef ENABLE_NLS 972 setlocale(LC_MESSAGES, ""); 973 setlocale(LC_CTYPE, ""); 974 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 975 textdomain(NLS_CAT_NAME); 976 #endif 977 my_ver = ext2fs_parse_version_string(my_ver_string); 978 lib_ver = ext2fs_get_library_version(0, &lib_ver_date); 979 if (my_ver > lib_ver) { 980 fprintf( stderr, _("Error: ext2fs library version " 981 "out of date!\n")); 982 show_version_only++; 983 } 984 985 retval = PRS(argc, argv, &ctx); 986 if (retval) { 987 com_err("e2fsck", retval, 988 _("while trying to initialize program")); 989 exit(FSCK_ERROR); 990 } 991 reserve_stdio_fds(); 992 993 init_resource_track(&ctx->global_rtrack, NULL); 994 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) 995 fprintf(stderr, "e2fsck %s (%s)\n", my_ver_string, 996 my_ver_date); 997 998 if (show_version_only) { 999 fprintf(stderr, _("\tUsing %s, %s\n"), 1000 error_message(EXT2_ET_BASE), lib_ver_date); 1001 exit(FSCK_OK); 1002 } 1003 1004 check_mount(ctx); 1005 1006 if (!(ctx->options & E2F_OPT_PREEN) && 1007 !(ctx->options & E2F_OPT_NO) && 1008 !(ctx->options & E2F_OPT_YES)) { 1009 if (!ctx->interactive) 1010 fatal_error(ctx, 1011 _("need terminal for interactive repairs")); 1012 } 1013 ctx->superblock = ctx->use_superblock; 1014 restart: 1015 #ifdef CONFIG_TESTIO_DEBUG 1016 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { 1017 io_ptr = test_io_manager; 1018 test_io_backing_manager = unix_io_manager; 1019 } else 1020 #endif 1021 io_ptr = unix_io_manager; 1022 flags = EXT2_FLAG_NOFREE_ON_ERROR; 1023 if ((ctx->options & E2F_OPT_READONLY) == 0) 1024 flags |= EXT2_FLAG_RW; 1025 if ((ctx->mount_flags & EXT2_MF_MOUNTED) == 0) 1026 flags |= EXT2_FLAG_EXCLUSIVE; 1027 1028 retval = try_open_fs(ctx, flags, io_ptr, &fs); 1029 1030 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && 1031 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) && 1032 ((retval == EXT2_ET_BAD_MAGIC) || 1033 (retval == EXT2_ET_CORRUPT_SUPERBLOCK) || 1034 ((retval == 0) && (retval2 = ext2fs_check_desc(fs))))) { 1035 if (retval2 == ENOMEM) { 1036 retval = retval2; 1037 goto failure; 1038 } 1039 if (fs->flags & EXT2_FLAG_NOFREE_ON_ERROR) { 1040 ext2fs_free(fs); 1041 fs = NULL; 1042 } 1043 if (!fs || (fs->group_desc_count > 1)) { 1044 printf(_("%s: %s trying backup blocks...\n"), 1045 ctx->program_name, 1046 retval ? _("Superblock invalid,") : 1047 _("Group descriptors look bad...")); 1048 orig_superblock = ctx->superblock; 1049 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr); 1050 if (fs) 1051 ext2fs_close(fs); 1052 orig_retval = retval; 1053 retval = try_open_fs(ctx, flags, io_ptr, &fs); 1054 if ((orig_retval == 0) && retval != 0) { 1055 com_err(ctx->program_name, retval, 1056 "when using the backup blocks"); 1057 printf(_("%s: going back to original " 1058 "superblock\n"), ctx->program_name); 1059 ctx->superblock = orig_superblock; 1060 retval = try_open_fs(ctx, flags, io_ptr, &fs); 1061 } 1062 } 1063 } 1064 if (((retval == EXT2_ET_UNSUPP_FEATURE) || 1065 (retval == EXT2_ET_RO_UNSUPP_FEATURE)) && 1066 fs && fs->super) { 1067 sb = fs->super; 1068 features[0] = (sb->s_feature_compat & 1069 ~EXT2_LIB_FEATURE_COMPAT_SUPP); 1070 features[1] = (sb->s_feature_incompat & 1071 ~EXT2_LIB_FEATURE_INCOMPAT_SUPP); 1072 features[2] = (sb->s_feature_ro_compat & 1073 ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP); 1074 if (features[0] || features[1] || features[2]) 1075 goto print_unsupp_features; 1076 } 1077 failure: 1078 if (retval) { 1079 if (orig_retval) 1080 retval = orig_retval; 1081 com_err(ctx->program_name, retval, _("while trying to open %s"), 1082 ctx->filesystem_name); 1083 if (retval == EXT2_ET_REV_TOO_HIGH) { 1084 printf(_("The filesystem revision is apparently " 1085 "too high for this version of e2fsck.\n" 1086 "(Or the filesystem superblock " 1087 "is corrupt)\n\n")); 1088 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); 1089 } else if (retval == EXT2_ET_SHORT_READ) 1090 printf(_("Could this be a zero-length partition?\n")); 1091 else if ((retval == EPERM) || (retval == EACCES)) 1092 printf(_("You must have %s access to the " 1093 "filesystem or be root\n"), 1094 (ctx->options & E2F_OPT_READONLY) ? 1095 "r/o" : "r/w"); 1096 else if (retval == ENXIO) 1097 printf(_("Possibly non-existent or swap device?\n")); 1098 else if (retval == EBUSY) 1099 printf(_("Filesystem mounted or opened exclusively " 1100 "by another program?\n")); 1101 #ifdef EROFS 1102 else if (retval == EROFS) 1103 printf(_("Disk write-protected; use the -n option " 1104 "to do a read-only\n" 1105 "check of the device.\n")); 1106 #endif 1107 else 1108 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); 1109 fatal_error(ctx, 0); 1110 } 1111 /* 1112 * We only update the master superblock because (a) paranoia; 1113 * we don't want to corrupt the backup superblocks, and (b) we 1114 * don't need to update the mount count and last checked 1115 * fields in the backup superblock (the kernel doesn't update 1116 * the backup superblocks anyway). With newer versions of the 1117 * library this flag is set by ext2fs_open2(), but we set this 1118 * here just to be sure. (No, we don't support e2fsck running 1119 * with some other libext2fs than the one that it was shipped 1120 * with, but just in case....) 1121 */ 1122 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; 1123 1124 if (!(ctx->flags & E2F_FLAG_GOT_DEVSIZE)) { 1125 __u32 blocksize = EXT2_BLOCK_SIZE(fs->super); 1126 int need_restart = 0; 1127 1128 pctx.errcode = ext2fs_get_device_size2(ctx->filesystem_name, 1129 blocksize, 1130 &ctx->num_blocks); 1131 /* 1132 * The floppy driver refuses to allow anyone else to 1133 * open the device if has been opened with O_EXCL; 1134 * this is unlike other block device drivers in Linux. 1135 * To handle this, we close the filesystem and then 1136 * reopen the filesystem after we get the device size. 1137 */ 1138 if (pctx.errcode == EBUSY) { 1139 ext2fs_close(fs); 1140 need_restart++; 1141 pctx.errcode = 1142 ext2fs_get_device_size2(ctx->filesystem_name, 1143 blocksize, 1144 &ctx->num_blocks); 1145 } 1146 if (pctx.errcode == EXT2_ET_UNIMPLEMENTED) 1147 ctx->num_blocks = 0; 1148 else if (pctx.errcode) { 1149 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx); 1150 ctx->flags |= E2F_FLAG_ABORT; 1151 fatal_error(ctx, 0); 1152 } 1153 ctx->flags |= E2F_FLAG_GOT_DEVSIZE; 1154 if (need_restart) 1155 goto restart; 1156 } 1157 1158 ctx->fs = fs; 1159 fs->priv_data = ctx; 1160 fs->now = ctx->now; 1161 sb = fs->super; 1162 if (sb->s_rev_level > E2FSCK_CURRENT_REV) { 1163 com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH, 1164 _("while trying to open %s"), 1165 ctx->filesystem_name); 1166 get_newer: 1167 fatal_error(ctx, _("Get a newer version of e2fsck!")); 1168 } 1169 1170 /* 1171 * Set the device name, which is used whenever we print error 1172 * or informational messages to the user. 1173 */ 1174 if (ctx->device_name == 0 && 1175 (sb->s_volume_name[0] != 0)) { 1176 ctx->device_name = string_copy(ctx, sb->s_volume_name, 1177 sizeof(sb->s_volume_name)); 1178 } 1179 if (ctx->device_name == 0) 1180 ctx->device_name = string_copy(ctx, ctx->filesystem_name, 0); 1181 for (cp = ctx->device_name; *cp; cp++) 1182 if (isspace(*cp) || *cp == ':') 1183 *cp = '_'; 1184 1185 ehandler_init(fs->io); 1186 1187 if ((ctx->mount_flags & EXT2_MF_MOUNTED) && 1188 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) 1189 goto skip_journal; 1190 1191 /* 1192 * Make sure the ext3 superblock fields are consistent. 1193 */ 1194 retval = e2fsck_check_ext3_journal(ctx); 1195 if (retval) { 1196 com_err(ctx->program_name, retval, 1197 _("while checking ext3 journal for %s"), 1198 ctx->device_name); 1199 fatal_error(ctx, 0); 1200 } 1201 1202 /* 1203 * Check to see if we need to do ext3-style recovery. If so, 1204 * do it, and then restart the fsck. 1205 */ 1206 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { 1207 if (ctx->options & E2F_OPT_READONLY) { 1208 printf(_("Warning: skipping journal recovery " 1209 "because doing a read-only filesystem " 1210 "check.\n")); 1211 io_channel_flush(ctx->fs->io); 1212 } else { 1213 if (ctx->flags & E2F_FLAG_RESTARTED) { 1214 /* 1215 * Whoops, we attempted to run the 1216 * journal twice. This should never 1217 * happen, unless the hardware or 1218 * device driver is being bogus. 1219 */ 1220 com_err(ctx->program_name, 0, 1221 _("unable to set superblock flags on %s\n"), ctx->device_name); 1222 fatal_error(ctx, 0); 1223 } 1224 retval = e2fsck_run_ext3_journal(ctx); 1225 if (retval) { 1226 com_err(ctx->program_name, retval, 1227 _("while recovering ext3 journal of %s"), 1228 ctx->device_name); 1229 fatal_error(ctx, 0); 1230 } 1231 ext2fs_close(ctx->fs); 1232 ctx->fs = 0; 1233 ctx->flags |= E2F_FLAG_RESTARTED; 1234 goto restart; 1235 } 1236 } 1237 1238 skip_journal: 1239 /* 1240 * Check for compatibility with the feature sets. We need to 1241 * be more stringent than ext2fs_open(). 1242 */ 1243 features[0] = sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP; 1244 features[1] = sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP; 1245 features[2] = (sb->s_feature_ro_compat & 1246 ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP); 1247 print_unsupp_features: 1248 if (features[0] || features[1] || features[2]) { 1249 int i, j; 1250 __u32 *mask = features, m; 1251 1252 fprintf(stderr, _("%s has unsupported feature(s):"), 1253 ctx->filesystem_name); 1254 1255 for (i=0; i <3; i++,mask++) { 1256 for (j=0,m=1; j < 32; j++, m<<=1) { 1257 if (*mask & m) 1258 fprintf(stderr, " %s", 1259 e2p_feature2string(i, m)); 1260 } 1261 } 1262 putc('\n', stderr); 1263 goto get_newer; 1264 } 1265 #ifdef ENABLE_COMPRESSION 1266 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) 1267 com_err(ctx->program_name, 0, 1268 _("Warning: compression support is experimental.\n")); 1269 #endif 1270 #ifndef ENABLE_HTREE 1271 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) { 1272 com_err(ctx->program_name, 0, 1273 _("E2fsck not compiled with HTREE support,\n\t" 1274 "but filesystem %s has HTREE directories.\n"), 1275 ctx->device_name); 1276 goto get_newer; 1277 } 1278 #endif 1279 1280 /* 1281 * If the user specified a specific superblock, presumably the 1282 * master superblock has been trashed. So we mark the 1283 * superblock as dirty, so it can be written out. 1284 */ 1285 if (ctx->superblock && 1286 !(ctx->options & E2F_OPT_READONLY)) 1287 ext2fs_mark_super_dirty(fs); 1288 1289 /* 1290 * Calculate the number of filesystem blocks per pagesize. If 1291 * fs->blocksize > page_size, set the number of blocks per 1292 * pagesize to 1 to avoid division by zero errors. 1293 */ 1294 #ifdef _SC_PAGESIZE 1295 sysval = sysconf(_SC_PAGESIZE); 1296 if (sysval > 0) 1297 sys_page_size = sysval; 1298 #endif /* _SC_PAGESIZE */ 1299 ctx->blocks_per_page = sys_page_size / fs->blocksize; 1300 if (ctx->blocks_per_page == 0) 1301 ctx->blocks_per_page = 1; 1302 1303 if (ctx->superblock) 1304 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0); 1305 ext2fs_mark_valid(fs); 1306 check_super_block(ctx); 1307 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 1308 fatal_error(ctx, 0); 1309 check_if_skip(ctx); 1310 check_resize_inode(ctx); 1311 if (bad_blocks_file) 1312 read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks); 1313 else if (cflag) 1314 read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */ 1315 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 1316 fatal_error(ctx, 0); 1317 1318 /* 1319 * Mark the system as valid, 'til proven otherwise 1320 */ 1321 ext2fs_mark_valid(fs); 1322 1323 retval = ext2fs_read_bb_inode(fs, &fs->badblocks); 1324 if (retval) { 1325 com_err(ctx->program_name, retval, 1326 _("while reading bad blocks inode")); 1327 preenhalt(ctx); 1328 printf(_("This doesn't bode well," 1329 " but we'll try to go on...\n")); 1330 } 1331 1332 /* 1333 * Save the journal size in megabytes. 1334 * Try and use the journal size from the backup else let e2fsck 1335 * find the default journal size. 1336 */ 1337 if (sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) 1338 journal_size = sb->s_jnl_blocks[16] >> 20; 1339 else 1340 journal_size = -1; 1341 1342 run_result = e2fsck_run(ctx); 1343 e2fsck_clear_progbar(ctx); 1344 1345 if (ctx->flags & E2F_FLAG_JOURNAL_INODE) { 1346 if (fix_problem(ctx, PR_6_RECREATE_JOURNAL, &pctx)) { 1347 if (journal_size < 1024) 1348 journal_size = ext2fs_default_journal_size(fs->super->s_blocks_count); 1349 if (journal_size < 0) { 1350 fs->super->s_feature_compat &= 1351 ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; 1352 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 1353 com_err(ctx->program_name, 0, 1354 _("Couldn't determine journal size")); 1355 goto no_journal; 1356 } 1357 printf(_("Creating journal (%d blocks): "), 1358 journal_size); 1359 fflush(stdout); 1360 retval = ext2fs_add_journal_inode(fs, 1361 journal_size, 0); 1362 if (retval) { 1363 com_err("Error ", retval, 1364 _("\n\twhile trying to create journal")); 1365 goto no_journal; 1366 } 1367 printf(_(" Done.\n")); 1368 printf(_("\n*** journal has been re-created - " 1369 "filesystem is now ext3 again ***\n")); 1370 } 1371 } 1372 no_journal: 1373 1374 if (run_result == E2F_FLAG_RESTART) { 1375 printf(_("Restarting e2fsck from the beginning...\n")); 1376 retval = e2fsck_reset_context(ctx); 1377 if (retval) { 1378 com_err(ctx->program_name, retval, 1379 _("while resetting context")); 1380 fatal_error(ctx, 0); 1381 } 1382 ext2fs_close(fs); 1383 goto restart; 1384 } 1385 if (run_result & E2F_FLAG_CANCEL) { 1386 printf(_("%s: e2fsck canceled.\n"), ctx->device_name ? 1387 ctx->device_name : ctx->filesystem_name); 1388 exit_value |= FSCK_CANCELED; 1389 } 1390 if (run_result & E2F_FLAG_ABORT) 1391 fatal_error(ctx, _("aborted")); 1392 if (check_backup_super_block(ctx)) { 1393 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 1394 ext2fs_mark_super_dirty(fs); 1395 } 1396 1397 #ifdef MTRACE 1398 mtrace_print("Cleanup"); 1399 #endif 1400 if (ext2fs_test_changed(fs)) { 1401 exit_value |= FSCK_NONDESTRUCT; 1402 if (!(ctx->options & E2F_OPT_PREEN)) 1403 printf(_("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n"), 1404 ctx->device_name); 1405 if (ctx->mount_flags & EXT2_MF_ISROOT) { 1406 printf(_("%s: ***** REBOOT LINUX *****\n"), 1407 ctx->device_name); 1408 exit_value |= FSCK_REBOOT; 1409 } 1410 } 1411 if (!ext2fs_test_valid(fs) || 1412 ((exit_value & FSCK_CANCELED) && 1413 (sb->s_state & EXT2_ERROR_FS))) { 1414 printf(_("\n%s: ********** WARNING: Filesystem still has " 1415 "errors **********\n\n"), ctx->device_name); 1416 exit_value |= FSCK_UNCORRECTED; 1417 exit_value &= ~FSCK_NONDESTRUCT; 1418 } 1419 if (exit_value & FSCK_CANCELED) { 1420 int allow_cancellation; 1421 1422 profile_get_boolean(ctx->profile, "options", 1423 "allow_cancellation", 0, 0, 1424 &allow_cancellation); 1425 exit_value &= ~FSCK_NONDESTRUCT; 1426 if (allow_cancellation && ext2fs_test_valid(fs) && 1427 (sb->s_state & EXT2_VALID_FS) && 1428 !(sb->s_state & EXT2_ERROR_FS)) 1429 exit_value = 0; 1430 } else { 1431 show_stats(ctx); 1432 if (!(ctx->options & E2F_OPT_READONLY)) { 1433 if (ext2fs_test_valid(fs)) { 1434 if (!(sb->s_state & EXT2_VALID_FS)) 1435 exit_value |= FSCK_NONDESTRUCT; 1436 sb->s_state = EXT2_VALID_FS; 1437 } else 1438 sb->s_state &= ~EXT2_VALID_FS; 1439 sb->s_mnt_count = 0; 1440 sb->s_lastcheck = ctx->now; 1441 ext2fs_mark_super_dirty(fs); 1442 } 1443 } 1444 1445 if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM && 1446 !(ctx->options & E2F_OPT_READONLY)) { 1447 retval = ext2fs_set_gdt_csum(ctx->fs); 1448 if (retval) { 1449 com_err(ctx->program_name, retval, 1450 _("while setting block group checksum info")); 1451 fatal_error(ctx, 0); 1452 } 1453 } 1454 1455 e2fsck_write_bitmaps(ctx); 1456 io_channel_flush(ctx->fs->io); 1457 print_resource_track(ctx, NULL, &ctx->global_rtrack, ctx->fs->io); 1458 1459 ext2fs_close(fs); 1460 ctx->fs = NULL; 1461 free(ctx->journal_name); 1462 1463 e2fsck_free_context(ctx); 1464 remove_error_table(&et_ext2_error_table); 1465 remove_error_table(&et_prof_error_table); 1466 return exit_value; 1467 } 1468