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