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