unix.c revision b24efa218794b567c27ad99db319b4bd5d696958
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 1141 clear_problem_context(&pctx); 1142 sigcatcher_setup(); 1143#ifdef MTRACE 1144 mtrace(); 1145#endif 1146#ifdef MCHECK 1147 mcheck(0); 1148#endif 1149#ifdef ENABLE_NLS 1150 setlocale(LC_MESSAGES, ""); 1151 setlocale(LC_CTYPE, ""); 1152 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 1153 textdomain(NLS_CAT_NAME); 1154 set_com_err_gettext(gettext); 1155#endif 1156 my_ver = ext2fs_parse_version_string(my_ver_string); 1157 lib_ver = ext2fs_get_library_version(0, &lib_ver_date); 1158 if (my_ver > lib_ver) { 1159 fprintf( stderr, _("Error: ext2fs library version " 1160 "out of date!\n")); 1161 show_version_only++; 1162 } 1163 1164 retval = PRS(argc, argv, &ctx); 1165 if (retval) { 1166 com_err("e2fsck", retval, 1167 _("while trying to initialize program")); 1168 exit(FSCK_ERROR); 1169 } 1170 reserve_stdio_fds(); 1171 1172 set_up_logging(ctx); 1173 if (ctx->logf) { 1174 int i; 1175 fputs("E2fsck run: ", ctx->logf); 1176 for (i = 0; i < argc; i++) { 1177 if (i) 1178 fputc(' ', ctx->logf); 1179 fputs(argv[i], ctx->logf); 1180 } 1181 fputc('\n', ctx->logf); 1182 } 1183 1184 init_resource_track(&ctx->global_rtrack, NULL); 1185 if (!(ctx->options & E2F_OPT_PREEN) || show_version_only) 1186 log_err(ctx, "e2fsck %s (%s)\n", my_ver_string, 1187 my_ver_date); 1188 1189 if (show_version_only) { 1190 log_err(ctx, _("\tUsing %s, %s\n"), 1191 error_message(EXT2_ET_BASE), lib_ver_date); 1192 exit(FSCK_OK); 1193 } 1194 1195 check_mount(ctx); 1196 1197 if (!(ctx->options & E2F_OPT_PREEN) && 1198 !(ctx->options & E2F_OPT_NO) && 1199 !(ctx->options & E2F_OPT_YES)) { 1200 if (!ctx->interactive) 1201 fatal_error(ctx, 1202 _("need terminal for interactive repairs")); 1203 } 1204 ctx->superblock = ctx->use_superblock; 1205 1206 flags = EXT2_FLAG_SKIP_MMP; 1207restart: 1208#ifdef CONFIG_TESTIO_DEBUG 1209 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { 1210 io_ptr = test_io_manager; 1211 test_io_backing_manager = unix_io_manager; 1212 } else 1213#endif 1214 io_ptr = unix_io_manager; 1215 flags |= EXT2_FLAG_NOFREE_ON_ERROR; 1216 profile_get_boolean(ctx->profile, "options", "old_bitmaps", 0, 0, 1217 &old_bitmaps); 1218 if (!old_bitmaps) 1219 flags |= EXT2_FLAG_64BITS; 1220 if ((ctx->options & E2F_OPT_READONLY) == 0) 1221 flags |= EXT2_FLAG_RW; 1222 if ((ctx->mount_flags & EXT2_MF_MOUNTED) == 0) 1223 flags |= EXT2_FLAG_EXCLUSIVE; 1224 1225 retval = try_open_fs(ctx, flags, io_ptr, &fs); 1226 1227 if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) && 1228 !(ctx->flags & E2F_FLAG_SB_SPECIFIED) && 1229 ((retval == EXT2_ET_BAD_MAGIC) || 1230 (retval == EXT2_ET_CORRUPT_SUPERBLOCK) || 1231 ((retval == 0) && (retval2 = ext2fs_check_desc(fs))))) { 1232 if (retval) { 1233 pctx.errcode = retval; 1234 fix_problem(ctx, PR_0_OPEN_FAILED, &pctx); 1235 } 1236 if (retval2) { 1237 pctx.errcode = retval2; 1238 fix_problem(ctx, PR_0_CHECK_DESC_FAILED, &pctx); 1239 } 1240 pctx.errcode = 0; 1241 if (retval2 == ENOMEM || retval2 == EXT2_ET_NO_MEMORY) { 1242 retval = retval2; 1243 goto failure; 1244 } 1245 if (fs->flags & EXT2_FLAG_NOFREE_ON_ERROR) { 1246 ext2fs_free(fs); 1247 fs = NULL; 1248 } 1249 if (!fs || (fs->group_desc_count > 1)) { 1250 log_out(ctx, _("%s: %s trying backup blocks...\n"), 1251 ctx->program_name, 1252 retval ? _("Superblock invalid,") : 1253 _("Group descriptors look bad...")); 1254 orig_superblock = ctx->superblock; 1255 get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr); 1256 if (fs) 1257 ext2fs_close(fs); 1258 orig_retval = retval; 1259 retval = try_open_fs(ctx, flags, io_ptr, &fs); 1260 if ((orig_retval == 0) && retval != 0) { 1261 if (fs) 1262 ext2fs_close(fs); 1263 log_out(ctx, _("%s: %s while using the " 1264 "backup blocks"), 1265 ctx->program_name, 1266 error_message(retval)); 1267 log_out(ctx, _("%s: going back to original " 1268 "superblock\n"), 1269 ctx->program_name); 1270 ctx->superblock = orig_superblock; 1271 retval = try_open_fs(ctx, flags, io_ptr, &fs); 1272 } 1273 } 1274 } 1275 if (((retval == EXT2_ET_UNSUPP_FEATURE) || 1276 (retval == EXT2_ET_RO_UNSUPP_FEATURE)) && 1277 fs && fs->super) { 1278 sb = fs->super; 1279 features[0] = (sb->s_feature_compat & 1280 ~EXT2_LIB_FEATURE_COMPAT_SUPP); 1281 features[1] = (sb->s_feature_incompat & 1282 ~EXT2_LIB_FEATURE_INCOMPAT_SUPP); 1283 features[2] = (sb->s_feature_ro_compat & 1284 ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP); 1285 if (features[0] || features[1] || features[2]) 1286 goto print_unsupp_features; 1287 } 1288failure: 1289 if (retval) { 1290 if (orig_retval) 1291 retval = orig_retval; 1292 com_err(ctx->program_name, retval, _("while trying to open %s"), 1293 ctx->filesystem_name); 1294 if (retval == EXT2_ET_REV_TOO_HIGH) { 1295 log_out(ctx, _("The filesystem revision is apparently " 1296 "too high for this version of e2fsck.\n" 1297 "(Or the filesystem superblock " 1298 "is corrupt)\n\n")); 1299 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); 1300 } else if (retval == EXT2_ET_SHORT_READ) 1301 log_out(ctx, _("Could this be a zero-length " 1302 "partition?\n")); 1303 else if ((retval == EPERM) || (retval == EACCES)) 1304 log_out(ctx, _("You must have %s access to the " 1305 "filesystem or be root\n"), 1306 (ctx->options & E2F_OPT_READONLY) ? 1307 "r/o" : "r/w"); 1308 else if (retval == ENXIO) 1309 log_out(ctx, _("Possibly non-existent or " 1310 "swap device?\n")); 1311 else if (retval == EBUSY) 1312 log_out(ctx, _("Filesystem mounted or opened " 1313 "exclusively by another program?\n")); 1314 else if (retval == ENOENT) 1315 log_out(ctx, _("Possibly non-existent device?\n")); 1316#ifdef EROFS 1317 else if (retval == EROFS) 1318 log_out(ctx, _("Disk write-protected; use the -n " 1319 "option to do a read-only\n" 1320 "check of the device.\n")); 1321#endif 1322 else 1323 fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); 1324 fatal_error(ctx, 0); 1325 } 1326 /* 1327 * We only update the master superblock because (a) paranoia; 1328 * we don't want to corrupt the backup superblocks, and (b) we 1329 * don't need to update the mount count and last checked 1330 * fields in the backup superblock (the kernel doesn't update 1331 * the backup superblocks anyway). With newer versions of the 1332 * library this flag is set by ext2fs_open2(), but we set this 1333 * here just to be sure. (No, we don't support e2fsck running 1334 * with some other libext2fs than the one that it was shipped 1335 * with, but just in case....) 1336 */ 1337 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; 1338 1339 if (!(ctx->flags & E2F_FLAG_GOT_DEVSIZE)) { 1340 __u32 blocksize = EXT2_BLOCK_SIZE(fs->super); 1341 int need_restart = 0; 1342 1343 pctx.errcode = ext2fs_get_device_size2(ctx->filesystem_name, 1344 blocksize, 1345 &ctx->num_blocks); 1346 /* 1347 * The floppy driver refuses to allow anyone else to 1348 * open the device if has been opened with O_EXCL; 1349 * this is unlike other block device drivers in Linux. 1350 * To handle this, we close the filesystem and then 1351 * reopen the filesystem after we get the device size. 1352 */ 1353 if (pctx.errcode == EBUSY) { 1354 ext2fs_close(fs); 1355 need_restart++; 1356 pctx.errcode = 1357 ext2fs_get_device_size2(ctx->filesystem_name, 1358 blocksize, 1359 &ctx->num_blocks); 1360 } 1361 if (pctx.errcode == EXT2_ET_UNIMPLEMENTED) 1362 ctx->num_blocks = 0; 1363 else if (pctx.errcode) { 1364 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx); 1365 ctx->flags |= E2F_FLAG_ABORT; 1366 fatal_error(ctx, 0); 1367 } 1368 ctx->flags |= E2F_FLAG_GOT_DEVSIZE; 1369 if (need_restart) 1370 goto restart; 1371 } 1372 1373 ctx->fs = fs; 1374 fs->priv_data = ctx; 1375 fs->now = ctx->now; 1376 sb = fs->super; 1377 1378 if (sb->s_rev_level > E2FSCK_CURRENT_REV) { 1379 com_err(ctx->program_name, EXT2_ET_REV_TOO_HIGH, 1380 _("while trying to open %s"), 1381 ctx->filesystem_name); 1382 get_newer: 1383 fatal_error(ctx, _("Get a newer version of e2fsck!")); 1384 } 1385 1386 /* 1387 * Set the device name, which is used whenever we print error 1388 * or informational messages to the user. 1389 */ 1390 if (ctx->device_name == 0 && 1391 (sb->s_volume_name[0] != 0)) { 1392 ctx->device_name = string_copy(ctx, sb->s_volume_name, 1393 sizeof(sb->s_volume_name)); 1394 } 1395 if (ctx->device_name == 0) 1396 ctx->device_name = string_copy(ctx, ctx->filesystem_name, 0); 1397 for (cp = ctx->device_name; *cp; cp++) 1398 if (isspace(*cp) || *cp == ':') 1399 *cp = '_'; 1400 1401 ehandler_init(fs->io); 1402 1403 if ((fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) && 1404 (flags & EXT2_FLAG_SKIP_MMP)) { 1405 if (e2fsck_check_mmp(fs, ctx)) 1406 fatal_error(ctx, 0); 1407 1408 /* 1409 * Restart in order to reopen fs but this time start mmp. 1410 */ 1411 ext2fs_close(fs); 1412 ctx->fs = NULL; 1413 flags &= ~EXT2_FLAG_SKIP_MMP; 1414 goto restart; 1415 } 1416 1417 if (ctx->logf) 1418 fprintf(ctx->logf, "Filesystem UUID: %s\n", 1419 e2p_uuid2str(sb->s_uuid)); 1420 1421 if ((ctx->mount_flags & EXT2_MF_MOUNTED) && 1422 !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) 1423 goto skip_journal; 1424 1425 /* 1426 * Make sure the ext3 superblock fields are consistent. 1427 */ 1428 retval = e2fsck_check_ext3_journal(ctx); 1429 if (retval) { 1430 com_err(ctx->program_name, retval, 1431 _("while checking ext3 journal for %s"), 1432 ctx->device_name); 1433 fatal_error(ctx, 0); 1434 } 1435 1436 /* 1437 * Check to see if we need to do ext3-style recovery. If so, 1438 * do it, and then restart the fsck. 1439 */ 1440 if (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) { 1441 if (ctx->options & E2F_OPT_READONLY) { 1442 log_out(ctx, _("Warning: skipping journal recovery " 1443 "because doing a read-only filesystem " 1444 "check.\n")); 1445 io_channel_flush(ctx->fs->io); 1446 } else { 1447 if (ctx->flags & E2F_FLAG_RESTARTED) { 1448 /* 1449 * Whoops, we attempted to run the 1450 * journal twice. This should never 1451 * happen, unless the hardware or 1452 * device driver is being bogus. 1453 */ 1454 com_err(ctx->program_name, 0, 1455 _("unable to set superblock flags on %s\n"), ctx->device_name); 1456 fatal_error(ctx, 0); 1457 } 1458 retval = e2fsck_run_ext3_journal(ctx); 1459 if (retval) { 1460 com_err(ctx->program_name, retval, 1461 _("while recovering ext3 journal of %s"), 1462 ctx->device_name); 1463 fatal_error(ctx, 0); 1464 } 1465 ext2fs_close(ctx->fs); 1466 ctx->fs = 0; 1467 ctx->flags |= E2F_FLAG_RESTARTED; 1468 goto restart; 1469 } 1470 } 1471 1472skip_journal: 1473 /* 1474 * Check for compatibility with the feature sets. We need to 1475 * be more stringent than ext2fs_open(). 1476 */ 1477 features[0] = sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP; 1478 features[1] = sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP; 1479 features[2] = (sb->s_feature_ro_compat & 1480 ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP); 1481print_unsupp_features: 1482 if (features[0] || features[1] || features[2]) { 1483 int i, j; 1484 __u32 *mask = features, m; 1485 1486 log_err(ctx, _("%s has unsupported feature(s):"), 1487 ctx->filesystem_name); 1488 1489 for (i=0; i <3; i++,mask++) { 1490 for (j=0,m=1; j < 32; j++, m<<=1) { 1491 if (*mask & m) 1492 log_err(ctx, " %s", 1493 e2p_feature2string(i, m)); 1494 } 1495 } 1496 log_err(ctx, "\n"); 1497 goto get_newer; 1498 } 1499#ifdef ENABLE_COMPRESSION 1500 if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) 1501 log_err(ctx, _("%s: warning: compression support " 1502 "is experimental.\n"), 1503 ctx->program_name); 1504#endif 1505#ifndef ENABLE_HTREE 1506 if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) { 1507 log_err(ctx, _("%s: e2fsck not compiled with HTREE support,\n\t" 1508 "but filesystem %s has HTREE directories.\n"), 1509 ctx->program_name, ctx->device_name); 1510 goto get_newer; 1511 } 1512#endif 1513 1514 /* 1515 * If the user specified a specific superblock, presumably the 1516 * master superblock has been trashed. So we mark the 1517 * superblock as dirty, so it can be written out. 1518 */ 1519 if (ctx->superblock && 1520 !(ctx->options & E2F_OPT_READONLY)) 1521 ext2fs_mark_super_dirty(fs); 1522 1523 /* 1524 * Calculate the number of filesystem blocks per pagesize. If 1525 * fs->blocksize > page_size, set the number of blocks per 1526 * pagesize to 1 to avoid division by zero errors. 1527 */ 1528#ifdef _SC_PAGESIZE 1529 sysval = sysconf(_SC_PAGESIZE); 1530 if (sysval > 0) 1531 sys_page_size = sysval; 1532#endif /* _SC_PAGESIZE */ 1533 ctx->blocks_per_page = sys_page_size / fs->blocksize; 1534 if (ctx->blocks_per_page == 0) 1535 ctx->blocks_per_page = 1; 1536 1537 if (ctx->superblock) 1538 set_latch_flags(PR_LATCH_RELOC, PRL_LATCHED, 0); 1539 ext2fs_mark_valid(fs); 1540 check_super_block(ctx); 1541 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 1542 fatal_error(ctx, 0); 1543 check_if_skip(ctx); 1544 check_resize_inode(ctx); 1545 if (bad_blocks_file) 1546 read_bad_blocks_file(ctx, bad_blocks_file, replace_bad_blocks); 1547 else if (cflag) 1548 read_bad_blocks_file(ctx, 0, !keep_bad_blocks); /* Test disk */ 1549 if (ctx->flags & E2F_FLAG_SIGNAL_MASK) 1550 fatal_error(ctx, 0); 1551 1552 /* 1553 * Mark the system as valid, 'til proven otherwise 1554 */ 1555 ext2fs_mark_valid(fs); 1556 1557 retval = ext2fs_read_bb_inode(fs, &fs->badblocks); 1558 if (retval) { 1559 log_out(ctx, _("%s: %s while reading bad blocks inode\n"), 1560 ctx->program_name, error_message(retval)); 1561 preenhalt(ctx); 1562 log_out(ctx, _("This doesn't bode well, " 1563 "but we'll try to go on...\n")); 1564 } 1565 1566 /* 1567 * Save the journal size in megabytes. 1568 * Try and use the journal size from the backup else let e2fsck 1569 * find the default journal size. 1570 */ 1571 if (sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) 1572 journal_size = (sb->s_jnl_blocks[15] << (32 - 20)) | 1573 (sb->s_jnl_blocks[16] >> 20); 1574 else 1575 journal_size = -1; 1576 1577 if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_QUOTA) { 1578 int qtype; 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 quota_write_inode(ctx->qctx, -1); 1623 quota_release_context(&ctx->qctx); 1624 } 1625 1626 if (run_result == E2F_FLAG_RESTART) { 1627 log_out(ctx, _("Restarting e2fsck from the beginning...\n")); 1628 retval = e2fsck_reset_context(ctx); 1629 if (retval) { 1630 com_err(ctx->program_name, retval, 1631 _("while resetting context")); 1632 fatal_error(ctx, 0); 1633 } 1634 ext2fs_close(fs); 1635 goto restart; 1636 } 1637 if (run_result & E2F_FLAG_CANCEL) { 1638 log_out(ctx, _("%s: e2fsck canceled.\n"), ctx->device_name ? 1639 ctx->device_name : ctx->filesystem_name); 1640 exit_value |= FSCK_CANCELED; 1641 } 1642 if (run_result & E2F_FLAG_ABORT) 1643 fatal_error(ctx, _("aborted")); 1644 if (check_backup_super_block(ctx)) { 1645 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 1646 ext2fs_mark_super_dirty(fs); 1647 } 1648 1649#ifdef MTRACE 1650 mtrace_print("Cleanup"); 1651#endif 1652 if (ext2fs_test_changed(fs)) { 1653 exit_value |= FSCK_NONDESTRUCT; 1654 if (!(ctx->options & E2F_OPT_PREEN)) 1655 log_out(ctx, _("\n%s: ***** FILE SYSTEM WAS " 1656 "MODIFIED *****\n"), 1657 ctx->device_name); 1658 if (ctx->mount_flags & EXT2_MF_ISROOT) { 1659 log_out(ctx, _("%s: ***** REBOOT LINUX *****\n"), 1660 ctx->device_name); 1661 exit_value |= FSCK_REBOOT; 1662 } 1663 } 1664 if (!ext2fs_test_valid(fs) || 1665 ((exit_value & FSCK_CANCELED) && 1666 (sb->s_state & EXT2_ERROR_FS))) { 1667 log_out(ctx, _("\n%s: ********** WARNING: Filesystem still has " 1668 "errors **********\n\n"), ctx->device_name); 1669 exit_value |= FSCK_UNCORRECTED; 1670 exit_value &= ~FSCK_NONDESTRUCT; 1671 } 1672 if (exit_value & FSCK_CANCELED) { 1673 int allow_cancellation; 1674 1675 profile_get_boolean(ctx->profile, "options", 1676 "allow_cancellation", 0, 0, 1677 &allow_cancellation); 1678 exit_value &= ~FSCK_NONDESTRUCT; 1679 if (allow_cancellation && ext2fs_test_valid(fs) && 1680 (sb->s_state & EXT2_VALID_FS) && 1681 !(sb->s_state & EXT2_ERROR_FS)) 1682 exit_value = 0; 1683 } else { 1684 show_stats(ctx); 1685 if (!(ctx->options & E2F_OPT_READONLY)) { 1686 if (ext2fs_test_valid(fs)) { 1687 if (!(sb->s_state & EXT2_VALID_FS)) 1688 exit_value |= FSCK_NONDESTRUCT; 1689 sb->s_state = EXT2_VALID_FS; 1690 } else 1691 sb->s_state &= ~EXT2_VALID_FS; 1692 sb->s_mnt_count = 0; 1693 if (!(ctx->flags & E2F_FLAG_TIME_INSANE)) 1694 sb->s_lastcheck = ctx->now; 1695 memset(((char *) sb) + EXT4_S_ERR_START, 0, 1696 EXT4_S_ERR_LEN); 1697 ext2fs_mark_super_dirty(fs); 1698 } 1699 } 1700 1701 if ((run_result & E2F_FLAG_CANCEL) == 0 && 1702 sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM && 1703 !(ctx->options & E2F_OPT_READONLY)) { 1704 retval = ext2fs_set_gdt_csum(ctx->fs); 1705 if (retval) { 1706 com_err(ctx->program_name, retval, 1707 _("while setting block group checksum info")); 1708 fatal_error(ctx, 0); 1709 } 1710 } 1711 1712 e2fsck_write_bitmaps(ctx); 1713 io_channel_flush(ctx->fs->io); 1714 print_resource_track(ctx, NULL, &ctx->global_rtrack, ctx->fs->io); 1715 1716 ext2fs_close(fs); 1717 ctx->fs = NULL; 1718 free(ctx->journal_name); 1719 1720 e2fsck_free_context(ctx); 1721 remove_error_table(&et_ext2_error_table); 1722 remove_error_table(&et_prof_error_table); 1723 return exit_value; 1724} 1725