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