1/* vi: set sw=4 ts=4: */ 2/* 3 * fsck --- A generic, parallelizing front-end for the fsck program. 4 * It will automatically try to run fsck programs in parallel if the 5 * devices are on separate spindles. It is based on the same ideas as 6 * the generic front end for fsck by David Engel and Fred van Kempen, 7 * but it has been completely rewritten from scratch to support 8 * parallel execution. 9 * 10 * Written by Theodore Ts'o, <tytso@mit.edu> 11 * 12 * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994: 13 * o Changed -t fstype to behave like with mount when -A (all file 14 * systems) or -M (like mount) is specified. 15 * o fsck looks if it can find the fsck.type program to decide 16 * if it should ignore the fs type. This way more fsck programs 17 * can be added without changing this front-end. 18 * o -R flag skip root file system. 19 * 20 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 21 * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o. 22 * 23 * %Begin-Header% 24 * This file may be redistributed under the terms of the GNU Public 25 * License. 26 * %End-Header% 27 */ 28 29 30#include "libbb.h" 31 32#define EXIT_OK 0 33#define EXIT_NONDESTRUCT 1 34#define EXIT_DESTRUCT 2 35#define EXIT_UNCORRECTED 4 36#define EXIT_ERROR 8 37#define EXIT_USAGE 16 38#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */ 39 40/* 41 * Internal structure for mount table entries. 42 */ 43 44struct fs_info { 45 struct fs_info *next; 46 char *device; 47 char *mountpt; 48 char *type; 49 char *opts; 50 int freq; 51 int passno; 52 int flags; 53}; 54 55#define FLAG_DONE 1 56#define FLAG_PROGRESS 2 57/* 58 * Structure to allow exit codes to be stored 59 */ 60struct fsck_instance { 61 struct fsck_instance *next; 62 int pid; 63 int flags; 64 int exit_status; 65 time_t start_time; 66 char *prog; 67 char *type; 68 char *device; 69 char *base_device; /* /dev/hda for /dev/hdaN etc */ 70}; 71 72static const char ignored_types[] ALIGN1 = 73 "ignore\0" 74 "iso9660\0" 75 "nfs\0" 76 "proc\0" 77 "sw\0" 78 "swap\0" 79 "tmpfs\0" 80 "devpts\0"; 81 82 83#define BASE_MD "/dev/md" 84 85static char **devices; 86static char **args; 87static int num_devices; 88static int num_args; 89static int verbose; 90 91#define FS_TYPE_FLAG_NORMAL 0 92#define FS_TYPE_FLAG_OPT 1 93#define FS_TYPE_FLAG_NEGOPT 2 94static char **fs_type_list; 95static uint8_t *fs_type_flag; 96static smallint fs_type_negated; 97 98static volatile smallint cancel_requested; 99static smallint doall; 100static smallint noexecute; 101static smallint serialize; 102static smallint skip_root; 103/* static smallint like_mount; */ 104static smallint notitle; 105static smallint parallel_root; 106static smallint force_all_parallel; 107 108/* "progress indicator" code is somewhat buggy and ext[23] specific. 109 * We should be filesystem agnostic. IOW: there should be a well-defined 110 * API for fsck.something, NOT ad-hoc hacks in generic fsck. */ 111#define DO_PROGRESS_INDICATOR 0 112#if DO_PROGRESS_INDICATOR 113static smallint progress; 114static int progress_fd; 115#endif 116 117static int num_running; 118static int max_running; 119static char *fstype; 120static struct fs_info *filesys_info; 121static struct fs_info *filesys_last; 122static struct fsck_instance *instance_list; 123 124/* 125 * Return the "base device" given a particular device; this is used to 126 * assure that we only fsck one partition on a particular drive at any 127 * one time. Otherwise, the disk heads will be seeking all over the 128 * place. If the base device cannot be determined, return NULL. 129 * 130 * The base_device() function returns an allocated string which must 131 * be freed. 132 */ 133#if ENABLE_FEATURE_DEVFS 134/* 135 * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3 136 * pathames. 137 */ 138static const char *const devfs_hier[] = { 139 "host", "bus", "target", "lun", NULL 140}; 141#endif 142 143static char *base_device(const char *device) 144{ 145 char *str, *cp; 146#if ENABLE_FEATURE_DEVFS 147 const char *const *hier; 148 const char *disk; 149 int len; 150#endif 151 cp = str = xstrdup(device); 152 153 /* Skip over /dev/; if it's not present, give up. */ 154 if (strncmp(cp, "/dev/", 5) != 0) 155 goto errout; 156 cp += 5; 157 158 /* 159 * For md devices, we treat them all as if they were all 160 * on one disk, since we don't know how to parallelize them. 161 */ 162 if (cp[0] == 'm' && cp[1] == 'd') { 163 cp[2] = 0; 164 return str; 165 } 166 167 /* Handle DAC 960 devices */ 168 if (strncmp(cp, "rd/", 3) == 0) { 169 cp += 3; 170 if (cp[0] != 'c' || !isdigit(cp[1]) 171 || cp[2] != 'd' || !isdigit(cp[3])) 172 goto errout; 173 cp[4] = 0; 174 return str; 175 } 176 177 /* Now let's handle /dev/hd* and /dev/sd* devices.... */ 178 if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') { 179 cp += 2; 180 /* If there's a single number after /dev/hd, skip it */ 181 if (isdigit(*cp)) 182 cp++; 183 /* What follows must be an alpha char, or give up */ 184 if (!isalpha(*cp)) 185 goto errout; 186 cp[1] = 0; 187 return str; 188 } 189 190#if ENABLE_FEATURE_DEVFS 191 /* Now let's handle devfs (ugh) names */ 192 len = 0; 193 if (strncmp(cp, "ide/", 4) == 0) 194 len = 4; 195 if (strncmp(cp, "scsi/", 5) == 0) 196 len = 5; 197 if (len) { 198 cp += len; 199 /* 200 * Now we proceed down the expected devfs hierarchy. 201 * i.e., .../host1/bus2/target3/lun4/... 202 * If we don't find the expected token, followed by 203 * some number of digits at each level, abort. 204 */ 205 for (hier = devfs_hier; *hier; hier++) { 206 len = strlen(*hier); 207 if (strncmp(cp, *hier, len) != 0) 208 goto errout; 209 cp += len; 210 while (*cp != '/' && *cp != 0) { 211 if (!isdigit(*cp)) 212 goto errout; 213 cp++; 214 } 215 cp++; 216 } 217 cp[-1] = 0; 218 return str; 219 } 220 221 /* Now handle devfs /dev/disc or /dev/disk names */ 222 disk = 0; 223 if (strncmp(cp, "discs/", 6) == 0) 224 disk = "disc"; 225 else if (strncmp(cp, "disks/", 6) == 0) 226 disk = "disk"; 227 if (disk) { 228 cp += 6; 229 if (strncmp(cp, disk, 4) != 0) 230 goto errout; 231 cp += 4; 232 while (*cp != '/' && *cp != 0) { 233 if (!isdigit(*cp)) 234 goto errout; 235 cp++; 236 } 237 *cp = 0; 238 return str; 239 } 240#endif 241 errout: 242 free(str); 243 return NULL; 244} 245 246static void free_instance(struct fsck_instance *p) 247{ 248 free(p->prog); 249 free(p->device); 250 free(p->base_device); 251 free(p); 252} 253 254static struct fs_info *create_fs_device(const char *device, const char *mntpnt, 255 const char *type, const char *opts, 256 int freq, int passno) 257{ 258 struct fs_info *fs; 259 260 fs = xzalloc(sizeof(*fs)); 261 fs->device = xstrdup(device); 262 fs->mountpt = xstrdup(mntpnt); 263 fs->type = xstrdup(type); 264 fs->opts = xstrdup(opts ? opts : ""); 265 fs->freq = freq; 266 fs->passno = passno; 267 /*fs->flags = 0; */ 268 /*fs->next = NULL; */ 269 270 if (!filesys_info) 271 filesys_info = fs; 272 else 273 filesys_last->next = fs; 274 filesys_last = fs; 275 276 return fs; 277} 278 279static void strip_line(char *line) 280{ 281 char *p = line + strlen(line) - 1; 282 283 while (*line) { 284 if (*p != '\n' && *p != '\r') 285 break; 286 *p-- = '\0'; 287 } 288} 289 290static char *parse_word(char **buf) 291{ 292 char *word, *next; 293 294 word = *buf; 295 if (*word == '\0') 296 return NULL; 297 298 word = skip_whitespace(word); 299 next = skip_non_whitespace(word); 300 if (*next) 301 *next++ = '\0'; 302 *buf = next; 303 return word; 304} 305 306static void parse_escape(char *word) 307{ 308 char *q, c; 309 const char *p; 310 311 if (!word) 312 return; 313 314 for (p = q = word; *p; q++) { 315 c = *p++; 316 if (c != '\\') { 317 *q = c; 318 } else { 319 *q = bb_process_escape_sequence(&p); 320 } 321 } 322 *q = '\0'; 323} 324 325static int parse_fstab_line(char *line, struct fs_info **ret_fs) 326{ 327 char *device, *mntpnt, *type, *opts, *freq, *passno, *cp; 328 struct fs_info *fs; 329 330 *ret_fs = 0; 331 strip_line(line); 332 cp = strchr(line, '#'); 333 if (cp) 334 *cp = '\0'; /* Ignore everything after the comment char */ 335 cp = line; 336 337 device = parse_word(&cp); 338 if (!device) return 0; /* Allow blank lines */ 339 mntpnt = parse_word(&cp); 340 type = parse_word(&cp); 341 opts = parse_word(&cp); 342 freq = parse_word(&cp); 343 passno = parse_word(&cp); 344 345 if (!mntpnt || !type) 346 return -1; 347 348 parse_escape(device); 349 parse_escape(mntpnt); 350 parse_escape(type); 351 parse_escape(opts); 352 parse_escape(freq); 353 parse_escape(passno); 354 355 if (strchr(type, ',')) 356 type = NULL; 357 358 fs = create_fs_device(device, mntpnt, type ? type : "auto", opts, 359 freq ? atoi(freq) : -1, 360 passno ? atoi(passno) : -1); 361 *ret_fs = fs; 362 return 0; 363} 364 365/* Load the filesystem database from /etc/fstab */ 366static void load_fs_info(const char *filename) 367{ 368 FILE *f; 369 int lineno = 0; 370 int old_fstab = 1; 371 struct fs_info *fs; 372 373 f = fopen_or_warn(filename, "r"); 374 if (f == NULL) { 375 return; 376 } 377 while (1) { 378 int r; 379 char *buf = xmalloc_getline(f); 380 if (!buf) break; 381 r = parse_fstab_line(buf, &fs); 382 free(buf); 383 lineno++; 384 if (r < 0) { 385 bb_error_msg("WARNING: bad format " 386 "on line %d of %s", lineno, filename); 387 continue; 388 } 389 if (!fs) 390 continue; 391 if (fs->passno < 0) 392 fs->passno = 0; 393 else 394 old_fstab = 0; 395 } 396 fclose(f); 397 398 if (old_fstab) { 399 fputs("\007" 400"WARNING: Your /etc/fstab does not contain the fsck passno field.\n" 401"I will kludge around things for you, but you should fix\n" 402"your /etc/fstab file as soon as you can.\n\n", stderr); 403 for (fs = filesys_info; fs; fs = fs->next) { 404 fs->passno = 1; 405 } 406 } 407} 408 409/* Lookup filesys in /etc/fstab and return the corresponding entry. */ 410static struct fs_info *lookup(char *filesys) 411{ 412 struct fs_info *fs; 413 414 for (fs = filesys_info; fs; fs = fs->next) { 415 if (strcmp(filesys, fs->device) == 0 416 || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0) 417 ) 418 break; 419 } 420 421 return fs; 422} 423 424#if DO_PROGRESS_INDICATOR 425static int progress_active(void) 426{ 427 struct fsck_instance *inst; 428 429 for (inst = instance_list; inst; inst = inst->next) { 430 if (inst->flags & FLAG_DONE) 431 continue; 432 if (inst->flags & FLAG_PROGRESS) 433 return 1; 434 } 435 return 0; 436} 437#endif 438 439 440/* 441 * Send a signal to all outstanding fsck child processes 442 */ 443static void kill_all_if_cancel_requested(void) 444{ 445 static smallint kill_sent; 446 447 struct fsck_instance *inst; 448 449 if (!cancel_requested || kill_sent) 450 return; 451 452 for (inst = instance_list; inst; inst = inst->next) { 453 if (inst->flags & FLAG_DONE) 454 continue; 455 kill(inst->pid, SIGTERM); 456 } 457 kill_sent = 1; 458} 459 460/* 461 * Wait for one child process to exit; when it does, unlink it from 462 * the list of executing child processes, and return it. 463 */ 464static struct fsck_instance *wait_one(int flags) 465{ 466 int status; 467 int sig; 468 struct fsck_instance *inst, *prev; 469 pid_t pid; 470 471 if (!instance_list) 472 return NULL; 473 474 if (noexecute) { 475 inst = instance_list; 476 prev = NULL; 477#ifdef RANDOM_DEBUG 478 while (inst->next && (random() & 1)) { 479 prev = inst; 480 inst = inst->next; 481 } 482#endif 483 inst->exit_status = 0; 484 goto ret_inst; 485 } 486 487 inst = prev = NULL; /* for gcc */ 488 do { 489 pid = waitpid(-1, &status, flags); 490 kill_all_if_cancel_requested(); 491 if (pid == 0 && (flags & WNOHANG)) 492 return NULL; 493 if (pid < 0) { 494 if (errno == EINTR || errno == EAGAIN) 495 continue; 496 if (errno == ECHILD) { 497 bb_error_msg("wait: no more child process?!?"); 498 return NULL; 499 } 500 bb_perror_msg("wait"); 501 continue; 502 } 503 prev = NULL; 504 inst = instance_list; 505 while (inst) { 506 if (inst->pid == pid) 507 break; 508 prev = inst; 509 inst = inst->next; 510 } 511 } while (!inst); 512 513 if (WIFEXITED(status)) 514 status = WEXITSTATUS(status); 515 else if (WIFSIGNALED(status)) { 516 sig = WTERMSIG(status); 517 status = EXIT_UNCORRECTED; 518 if (sig != SIGINT) { 519 printf("Warning... %s %s exited " 520 "with signal %d\n", 521 inst->prog, inst->device, sig); 522 status = EXIT_ERROR; 523 } 524 } else { 525 printf("%s %s: status is %x, should never happen\n", 526 inst->prog, inst->device, status); 527 status = EXIT_ERROR; 528 } 529 inst->exit_status = status; 530 531#if DO_PROGRESS_INDICATOR 532 if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) { 533 struct fsck_instance *inst2; 534 for (inst2 = instance_list; inst2; inst2 = inst2->next) { 535 if (inst2->flags & FLAG_DONE) 536 continue; 537 if (strcmp(inst2->type, "ext2") != 0 538 && strcmp(inst2->type, "ext3") != 0 539 ) { 540 continue; 541 } 542 /* ext[23], we will send USR1 543 * (request to start displaying progress bar) 544 * 545 * If we've just started the fsck, wait a tiny 546 * bit before sending the kill, to give it 547 * time to set up the signal handler 548 */ 549 if (inst2->start_time >= time(NULL) - 1) 550 sleep(1); 551 kill(inst2->pid, SIGUSR1); 552 inst2->flags |= FLAG_PROGRESS; 553 break; 554 } 555 } 556#endif 557 558 ret_inst: 559 if (prev) 560 prev->next = inst->next; 561 else 562 instance_list = inst->next; 563 if (verbose > 1) 564 printf("Finished with %s (exit status %d)\n", 565 inst->device, inst->exit_status); 566 num_running--; 567 return inst; 568} 569 570#define FLAG_WAIT_ALL 0 571#define FLAG_WAIT_ATLEAST_ONE 1 572/* 573 * Wait until all executing child processes have exited; return the 574 * logical OR of all of their exit code values. 575 */ 576static int wait_many(int flags) 577{ 578 struct fsck_instance *inst; 579 int global_status = 0; 580 int wait_flags = 0; 581 582 while ((inst = wait_one(wait_flags))) { 583 global_status |= inst->exit_status; 584 free_instance(inst); 585#ifdef RANDOM_DEBUG 586 if (noexecute && (flags & WNOHANG) && !(random() % 3)) 587 break; 588#endif 589 if (flags & FLAG_WAIT_ATLEAST_ONE) 590 wait_flags = WNOHANG; 591 } 592 return global_status; 593} 594 595/* 596 * Execute a particular fsck program, and link it into the list of 597 * child processes we are waiting for. 598 */ 599static void execute(const char *type, const char *device, const char *mntpt, 600 int interactive) 601{ 602 char *argv[num_args + 4]; /* see count below: */ 603 int argc; 604 int i; 605 struct fsck_instance *inst; 606 pid_t pid; 607 608 inst = xzalloc(sizeof(*inst)); 609 610 argv[0] = xasprintf("fsck.%s", type); /* 1 */ 611 for (i = 0; i < num_args; i++) 612 argv[i+1] = args[i]; /* num_args */ 613 argc = num_args + 1; 614 615#if DO_PROGRESS_INDICATOR 616 if (progress && !progress_active()) { 617 if (strcmp(type, "ext2") == 0 618 || strcmp(type, "ext3") == 0 619 ) { 620 argv[argc++] = xasprintf("-C%d", progress_fd); /* 1 */ 621 inst->flags |= FLAG_PROGRESS; 622 } 623 } 624#endif 625 626 argv[argc++] = xstrdup(device); /* 1 */ 627 argv[argc] = NULL; /* 1 */ 628 629 if (verbose || noexecute) { 630 printf("[%s (%d) -- %s]", argv[0], num_running, 631 mntpt ? mntpt : device); 632 for (i = 0; i < argc; i++) 633 printf(" %s", argv[i]); 634 puts(""); 635 } 636 637 /* Fork and execute the correct program. */ 638 pid = -1; 639 if (!noexecute) { 640 pid = spawn(argv); 641 if (pid < 0) 642 bb_perror_msg("%s", argv[0]); 643 } 644 645 for (i = num_args+1; i < argc; i++) 646 free(argv[i]); 647 648 inst->pid = pid; 649 inst->prog = argv[0]; 650 inst->type = xstrdup(type); 651 inst->device = xstrdup(device); 652 inst->base_device = base_device(device); 653 inst->start_time = time(NULL); 654 655 /* Add to the list of running fsck's. 656 * (was adding to the end, but adding to the front is simpler...) */ 657 inst->next = instance_list; 658 instance_list = inst; 659} 660 661/* 662 * Run the fsck program on a particular device 663 * 664 * If the type is specified using -t, and it isn't prefixed with "no" 665 * (as in "noext2") and only one filesystem type is specified, then 666 * use that type regardless of what is specified in /etc/fstab. 667 * 668 * If the type isn't specified by the user, then use either the type 669 * specified in /etc/fstab, or "auto". 670 */ 671static void fsck_device(struct fs_info *fs, int interactive) 672{ 673 const char *type; 674 675 if (strcmp(fs->type, "auto") != 0) { 676 type = fs->type; 677 if (verbose > 2) 678 bb_info_msg("using filesystem type '%s' %s", 679 type, "from fstab"); 680 } else if (fstype 681 && (fstype[0] != 'n' || fstype[1] != 'o') /* != "no" */ 682 && strncmp(fstype, "opts=", 5) != 0 683 && strncmp(fstype, "loop", 4) != 0 684 && !strchr(fstype, ',') 685 ) { 686 type = fstype; 687 if (verbose > 2) 688 bb_info_msg("using filesystem type '%s' %s", 689 type, "from -t"); 690 } else { 691 type = "auto"; 692 if (verbose > 2) 693 bb_info_msg("using filesystem type '%s' %s", 694 type, "(default)"); 695 } 696 697 num_running++; 698 execute(type, fs->device, fs->mountpt, interactive); 699} 700 701/* 702 * Returns TRUE if a partition on the same disk is already being 703 * checked. 704 */ 705static int device_already_active(char *device) 706{ 707 struct fsck_instance *inst; 708 char *base; 709 710 if (force_all_parallel) 711 return 0; 712 713#ifdef BASE_MD 714 /* Don't check a soft raid disk with any other disk */ 715 if (instance_list 716 && (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) 717 || !strncmp(device, BASE_MD, sizeof(BASE_MD)-1)) 718 ) { 719 return 1; 720 } 721#endif 722 723 base = base_device(device); 724 /* 725 * If we don't know the base device, assume that the device is 726 * already active if there are any fsck instances running. 727 */ 728 if (!base) 729 return (instance_list != NULL); 730 731 for (inst = instance_list; inst; inst = inst->next) { 732 if (!inst->base_device || !strcmp(base, inst->base_device)) { 733 free(base); 734 return 1; 735 } 736 } 737 738 free(base); 739 return 0; 740} 741 742/* 743 * This function returns true if a particular option appears in a 744 * comma-delimited options list 745 */ 746static int opt_in_list(char *opt, char *optlist) 747{ 748 char *s; 749 int len; 750 751 if (!optlist) 752 return 0; 753 754 len = strlen(opt); 755 s = optlist - 1; 756 while (1) { 757 s = strstr(s + 1, opt); 758 if (!s) 759 return 0; 760 if (s != optlist && s[-1] != ',') 761 continue; 762 if (s[len] != '\0' && s[len] != ',') 763 continue; 764 return 1; 765 } 766} 767 768/* See if the filesystem matches the criteria given by the -t option */ 769static int fs_match(struct fs_info *fs) 770{ 771 int n, ret, checked_type; 772 char *cp; 773 774 if (!fs_type_list) 775 return 1; 776 777 ret = 0; 778 checked_type = 0; 779 n = 0; 780 while (1) { 781 cp = fs_type_list[n]; 782 if (!cp) 783 break; 784 switch (fs_type_flag[n]) { 785 case FS_TYPE_FLAG_NORMAL: 786 checked_type++; 787 if (strcmp(cp, fs->type) == 0) 788 ret = 1; 789 break; 790 case FS_TYPE_FLAG_NEGOPT: 791 if (opt_in_list(cp, fs->opts)) 792 return 0; 793 break; 794 case FS_TYPE_FLAG_OPT: 795 if (!opt_in_list(cp, fs->opts)) 796 return 0; 797 break; 798 } 799 n++; 800 } 801 if (checked_type == 0) 802 return 1; 803 804 return (fs_type_negated ? !ret : ret); 805} 806 807/* Check if we should ignore this filesystem. */ 808static int ignore(struct fs_info *fs) 809{ 810 /* 811 * If the pass number is 0, ignore it. 812 */ 813 if (fs->passno == 0) 814 return 1; 815 816 /* 817 * If a specific fstype is specified, and it doesn't match, 818 * ignore it. 819 */ 820 if (!fs_match(fs)) 821 return 1; 822 823 /* Are we ignoring this type? */ 824 if (index_in_strings(ignored_types, fs->type) >= 0) 825 return 1; 826 827 /* We can and want to check this file system type. */ 828 return 0; 829} 830 831/* Check all file systems, using the /etc/fstab table. */ 832static int check_all(void) 833{ 834 struct fs_info *fs; 835 int status = EXIT_OK; 836 smallint not_done_yet; 837 smallint pass_done; 838 int passno; 839 840 if (verbose) 841 puts("Checking all filesystems"); 842 843 /* 844 * Do an initial scan over the filesystem; mark filesystems 845 * which should be ignored as done, and resolve any "auto" 846 * filesystem types (done as a side-effect of calling ignore()). 847 */ 848 for (fs = filesys_info; fs; fs = fs->next) { 849 if (ignore(fs)) 850 fs->flags |= FLAG_DONE; 851 } 852 853 /* 854 * Find and check the root filesystem. 855 */ 856 if (!parallel_root) { 857 for (fs = filesys_info; fs; fs = fs->next) { 858 if (LONE_CHAR(fs->mountpt, '/')) 859 break; 860 } 861 if (fs) { 862 if (!skip_root && !ignore(fs)) { 863 fsck_device(fs, 1); 864 status |= wait_many(FLAG_WAIT_ALL); 865 if (status > EXIT_NONDESTRUCT) 866 return status; 867 } 868 fs->flags |= FLAG_DONE; 869 } 870 } 871 /* 872 * This is for the bone-headed user who enters the root 873 * filesystem twice. Skip root will skip all root entries. 874 */ 875 if (skip_root) 876 for (fs = filesys_info; fs; fs = fs->next) 877 if (LONE_CHAR(fs->mountpt, '/')) 878 fs->flags |= FLAG_DONE; 879 880 not_done_yet = 1; 881 passno = 1; 882 while (not_done_yet) { 883 not_done_yet = 0; 884 pass_done = 1; 885 886 for (fs = filesys_info; fs; fs = fs->next) { 887 if (cancel_requested) 888 break; 889 if (fs->flags & FLAG_DONE) 890 continue; 891 /* 892 * If the filesystem's pass number is higher 893 * than the current pass number, then we don't 894 * do it yet. 895 */ 896 if (fs->passno > passno) { 897 not_done_yet = 1; 898 continue; 899 } 900 /* 901 * If a filesystem on a particular device has 902 * already been spawned, then we need to defer 903 * this to another pass. 904 */ 905 if (device_already_active(fs->device)) { 906 pass_done = 0; 907 continue; 908 } 909 /* 910 * Spawn off the fsck process 911 */ 912 fsck_device(fs, serialize); 913 fs->flags |= FLAG_DONE; 914 915 /* 916 * Only do one filesystem at a time, or if we 917 * have a limit on the number of fsck's extant 918 * at one time, apply that limit. 919 */ 920 if (serialize 921 || (max_running && (num_running >= max_running)) 922 ) { 923 pass_done = 0; 924 break; 925 } 926 } 927 if (cancel_requested) 928 break; 929 if (verbose > 1) 930 printf("--waiting-- (pass %d)\n", passno); 931 status |= wait_many(pass_done ? FLAG_WAIT_ALL : 932 FLAG_WAIT_ATLEAST_ONE); 933 if (pass_done) { 934 if (verbose > 1) 935 puts("----------------------------------"); 936 passno++; 937 } else 938 not_done_yet = 1; 939 } 940 kill_all_if_cancel_requested(); 941 status |= wait_many(FLAG_WAIT_ATLEAST_ONE); 942 return status; 943} 944 945/* 946 * Deal with the fsck -t argument. 947 * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"! 948 * Why here we require "-t novfat,nonfs" ?? 949 */ 950static void compile_fs_type(char *fs_type) 951{ 952 char *s; 953 int num = 2; 954 smallint negate; 955 956 if (fs_type) { 957 s = fs_type; 958 while ((s = strchr(s, ','))) { 959 num++; 960 s++; 961 } 962 } 963 964 fs_type_list = xzalloc(num * sizeof(fs_type_list[0])); 965 fs_type_flag = xzalloc(num * sizeof(fs_type_flag[0])); 966 fs_type_negated = -1; /* not yet known is it negated or not */ 967 968 if (!fs_type) 969 return; 970 971 num = 0; 972 s = fs_type; 973 while (1) { 974 char *comma; 975 976 negate = 0; 977 if (s[0] == 'n' && s[1] == 'o') { /* "no.." */ 978 s += 2; 979 negate = 1; 980 } else if (s[0] == '!') { 981 s++; 982 negate = 1; 983 } 984 985 if (strcmp(s, "loop") == 0) 986 /* loop is really short-hand for opts=loop */ 987 goto loop_special_case; 988 if (strncmp(s, "opts=", 5) == 0) { 989 s += 5; 990 loop_special_case: 991 fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT; 992 } else { 993 if (fs_type_negated == -1) 994 fs_type_negated = negate; 995 if (fs_type_negated != negate) 996 bb_error_msg_and_die( 997"either all or none of the filesystem types passed to -t must be prefixed " 998"with 'no' or '!'"); 999 } 1000 comma = strchr(s, ','); 1001 fs_type_list[num++] = comma ? xstrndup(s, comma-s) : xstrdup(s); 1002 if (!comma) 1003 break; 1004 s = comma + 1; 1005 } 1006} 1007 1008static void parse_args(int argc, char **argv) 1009{ 1010 int i, j; 1011 char *arg, *tmp; 1012 char *options = NULL; 1013 int optpos = 0; 1014 int opts_for_fsck = 0; 1015 1016 /* in bss, so already zeroed 1017 num_devices = 0; 1018 num_args = 0; 1019 instance_list = NULL; 1020 */ 1021 1022/* TODO: getopt32 */ 1023 for (i = 1; i < argc; i++) { 1024 arg = argv[i]; 1025 1026 if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) { 1027 devices = xrealloc(devices, (num_devices+1) * sizeof(devices[0])); 1028 devices[num_devices++] = xstrdup(arg); 1029 continue; 1030 } 1031 1032 if (arg[0] != '-' || opts_for_fsck) { 1033 args = xrealloc(args, (num_args+1) * sizeof(args[0])); 1034 args[num_args++] = xstrdup(arg); 1035 continue; 1036 } 1037 1038 for (j = 1; arg[j]; j++) { 1039 if (opts_for_fsck) { 1040 optpos++; 1041 /* one extra for '\0' */ 1042 options = xrealloc(options, optpos + 2); 1043 options[optpos] = arg[j]; 1044 continue; 1045 } 1046 switch (arg[j]) { 1047 case 'A': 1048 doall = 1; 1049 break; 1050#if DO_PROGRESS_INDICATOR 1051 case 'C': 1052 progress = 1; 1053 if (arg[++j]) { /* -Cn */ 1054 progress_fd = xatoi_u(&arg[j]); 1055 goto next_arg; 1056 } 1057 /* -C n */ 1058 progress_fd = xatoi_u(argv[++i]); 1059 goto next_arg; 1060#endif 1061 case 'V': 1062 verbose++; 1063 break; 1064 case 'N': 1065 noexecute = 1; 1066 break; 1067 case 'R': 1068 skip_root = 1; 1069 break; 1070 case 'T': 1071 notitle = 1; 1072 break; 1073/* case 'M': 1074 like_mount = 1; 1075 break; */ 1076 case 'P': 1077 parallel_root = 1; 1078 break; 1079 case 's': 1080 serialize = 1; 1081 break; 1082 case 't': 1083 if (fstype) 1084 bb_show_usage(); 1085 if (arg[++j]) 1086 tmp = &arg[j]; 1087 else if (++i < argc) 1088 tmp = argv[i]; 1089 else 1090 bb_show_usage(); 1091 fstype = xstrdup(tmp); 1092 compile_fs_type(fstype); 1093 goto next_arg; 1094 case '-': 1095 opts_for_fsck++; 1096 break; 1097 case '?': 1098 bb_show_usage(); 1099 break; 1100 default: 1101 optpos++; 1102 /* one extra for '\0' */ 1103 options = xrealloc(options, optpos + 2); 1104 options[optpos] = arg[j]; 1105 break; 1106 } 1107 } 1108 next_arg: 1109 if (optpos) { 1110 options[0] = '-'; 1111 options[optpos + 1] = '\0'; 1112 args = xrealloc(args, (num_args+1) * sizeof(args[0])); 1113 args[num_args++] = options; 1114 optpos = 0; 1115 options = NULL; 1116 } 1117 } 1118 if (getenv("FSCK_FORCE_ALL_PARALLEL")) 1119 force_all_parallel = 1; 1120 tmp = getenv("FSCK_MAX_INST"); 1121 if (tmp) 1122 max_running = xatoi(tmp); 1123} 1124 1125static void signal_cancel(int sig ATTRIBUTE_UNUSED) 1126{ 1127 cancel_requested = 1; 1128} 1129 1130int fsck_main(int argc, char **argv); 1131int fsck_main(int argc, char **argv) 1132{ 1133 int i, status = 0; 1134 int interactive; 1135 const char *fstab; 1136 struct fs_info *fs; 1137 struct sigaction sa; 1138 1139 memset(&sa, 0, sizeof(sa)); 1140 sa.sa_handler = signal_cancel; 1141 sigaction(SIGINT, &sa, 0); 1142 sigaction(SIGTERM, &sa, 0); 1143 1144 setbuf(stdout, NULL); 1145 1146 parse_args(argc, argv); 1147 1148 if (!notitle) 1149 puts("fsck (busybox "BB_VER", "BB_BT")"); 1150 1151 /* Even plain "fsck /dev/hda1" needs fstab to get fs type, 1152 * so we are scanning it anyway */ 1153 fstab = getenv("FSTAB_FILE"); 1154 if (!fstab) 1155 fstab = "/etc/fstab"; 1156 load_fs_info(fstab); 1157 1158 interactive = (num_devices == 1) | serialize; 1159 1160 /* If -A was specified ("check all"), do that! */ 1161 if (doall) 1162 return check_all(); 1163 1164 if (num_devices == 0) { 1165 serialize = 1; 1166 interactive = 1; 1167 return check_all(); 1168 } 1169 1170 for (i = 0; i < num_devices; i++) { 1171 if (cancel_requested) { 1172 kill_all_if_cancel_requested(); 1173 break; 1174 } 1175 1176 fs = lookup(devices[i]); 1177 if (!fs) 1178 fs = create_fs_device(devices[i], 0, "auto", 0, -1, -1); 1179 fsck_device(fs, interactive); 1180 1181 if (serialize 1182 || (max_running && (num_running >= max_running)) 1183 ) { 1184 struct fsck_instance *inst; 1185 1186 inst = wait_one(0); 1187 if (inst) { 1188 status |= inst->exit_status; 1189 free_instance(inst); 1190 } 1191 if (verbose > 1) 1192 puts("----------------------------------"); 1193 } 1194 } 1195 status |= wait_many(FLAG_WAIT_ALL); 1196 return status; 1197} 1198