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