fsck.c revision a1069118d438851e69c3dd6e38211fc4adfc7048
1/* 2 * pfsck --- A generic, parallelizing front-end for the fsck program. 3 * It will automatically try to run fsck programs in parallel if the 4 * devices are on separate spindles. It is based on the same ideas as 5 * the generic front end for fsck by David Engel and Fred van Kempen, 6 * but it has been completely rewritten from scratch to support 7 * parallel execution. 8 * 9 * Written by Theodore Ts'o, <tytso@mit.edu> 10 * 11 * Usage: fsck [-ACVRNTM] [-s] [-t fstype] [fs-options] device 12 * 13 * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994: 14 * o Changed -t fstype to behave like with mount when -A (all file 15 * systems) or -M (like mount) is specified. 16 * o fsck looks if it can find the fsck.type program to decide 17 * if it should ignore the fs type. This way more fsck programs 18 * can be added without changing this front-end. 19 * o -R flag skip root file system. 20 * 21 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 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#include <sys/types.h> 30#include <sys/wait.h> 31#include <sys/signal.h> 32#include <sys/stat.h> 33#include <limits.h> 34#include <stdio.h> 35#include <ctype.h> 36#include <string.h> 37#include <time.h> 38#if HAVE_STDLIB_H 39#include <stdlib.h> 40#endif 41#if HAVE_ERRNO_H 42#include <errno.h> 43#endif 44#if HAVE_PATHS_H 45#include <paths.h> 46#endif 47#if HAVE_UNISTD_H 48#include <unistd.h> 49#endif 50#if HAVE_ERRNO_H 51#include <errno.h> 52#endif 53#include <malloc.h> 54 55#include "../version.h" 56#include "nls-enable.h" 57#include "fsck.h" 58#include "get_device_by_label.h" 59 60#ifndef _PATH_MNTTAB 61#define _PATH_MNTTAB "/etc/fstab" 62#endif 63 64static const char *ignored_types[] = { 65 "ignore", 66 "iso9660", 67 "nfs", 68 "proc", 69 "sw", 70 "swap", 71 NULL 72}; 73 74static const char *really_wanted[] = { 75 "minix", 76 "ext2", 77 "ext3", 78 "xiafs", 79 NULL 80}; 81 82#define BASE_MD "/dev/md" 83 84/* 85 * Global variables for options 86 */ 87char *devices[MAX_DEVICES]; 88char *args[MAX_ARGS]; 89int num_devices, num_args; 90 91int verbose = 0; 92int doall = 0; 93int noexecute = 0; 94int serialize = 0; 95int skip_root = 0; 96int like_mount = 0; 97int notitle = 0; 98int parallel_root = 0; 99int progress = 0; 100int force_all_parallel = 0; 101int num_running = 0; 102int max_running = 0; 103char *progname; 104char *fstype = NULL; 105struct fs_info *filesys_info; 106struct fsck_instance *instance_list; 107const char *fsck_prefix_path = "/sbin:/sbin/fs.d:/sbin/fs:/etc/fs:/etc"; 108char *fsck_path = 0; 109static int ignore(struct fs_info *); 110 111static char *skip_over_blank(char *cp) 112{ 113 while (*cp && isspace(*cp)) 114 cp++; 115 return cp; 116} 117 118static char *skip_over_word(char *cp) 119{ 120 while (*cp && !isspace(*cp)) 121 cp++; 122 return cp; 123} 124 125static void strip_line(char *line) 126{ 127 char *p; 128 129 while (*line) { 130 p = line + strlen(line) - 1; 131 if ((*p == '\n') || (*p == '\r')) 132 *p = 0; 133 else 134 break; 135 } 136} 137 138static char *parse_word(char **buf) 139{ 140 char *word, *next; 141 142 word = *buf; 143 if (*word == 0) 144 return 0; 145 146 word = skip_over_blank(word); 147 next = skip_over_word(word); 148 if (*next) 149 *next++ = 0; 150 *buf = next; 151 return word; 152} 153 154static void free_instance(struct fsck_instance *i) 155{ 156 if (i->prog) 157 free(i->prog); 158 if (i->device) 159 free(i->device); 160 if (i->base_device) 161 free(i->base_device); 162 free(i); 163 return; 164} 165 166static int parse_fstab_line(char *line, struct fs_info **ret_fs) 167{ 168 char *device, *mntpnt, *type, *opts, *freq, *passno, *cp; 169 struct fs_info *fs; 170 171 *ret_fs = 0; 172 strip_line(line); 173 if ((cp = strchr(line, '#'))) 174 *cp = 0; /* Ignore everything after the comment char */ 175 cp = line; 176 177 device = parse_word(&cp); 178 mntpnt = parse_word(&cp); 179 type = parse_word(&cp); 180 opts = parse_word(&cp); 181 freq = parse_word(&cp); 182 passno = parse_word(&cp); 183 184 if (!device) 185 return 0; /* Allow blank lines */ 186 187 if (!mntpnt || !type) 188 return -1; 189 190 if (!(fs = malloc(sizeof(struct fs_info)))) 191 return -1; 192 193 fs->device = string_copy(device); 194 fs->mountpt = string_copy(mntpnt); 195 fs->type = string_copy(type); 196 fs->opts = string_copy(opts ? opts : ""); 197 fs->freq = freq ? atoi(freq) : -1; 198 fs->passno = passno ? atoi(passno) : -1; 199 fs->flags = 0; 200 fs->next = NULL; 201 202 *ret_fs = fs; 203 204 return 0; 205} 206 207/* 208 * Interpret the device name if necessary 209 */ 210static char *interpret_device(char *spec) 211{ 212 char *dev = interpret_spec(spec); 213 214 if (dev) 215 return dev; 216 217 /* 218 * Check to see if this was because /proc/partitions isn't 219 * found. 220 */ 221 if (access("/proc/partitions", R_OK) < 0) { 222 fprintf(stderr, "Couldn't open /proc/partitions: %s\n", 223 strerror(errno)); 224 fprintf(stderr, "Is /proc mounted?\n"); 225 exit(EXIT_ERROR); 226 } 227 /* 228 * Check to see if this is because we're not running as root 229 */ 230 if (geteuid()) 231 fprintf(stderr, 232 "Must be root to scan for matching filesystems: %s\n", 233 spec); 234 else 235 fprintf(stderr, "Couldn't find matching filesystem: %s\n", 236 spec); 237 exit(EXIT_ERROR); 238} 239 240/* 241 * Interpret filesystem auto type if necessary 242 */ 243static void interpret_type(struct fs_info *fs) 244{ 245 const char *type; 246 247 if (strcmp(fs->type, "auto") == 0) { 248 if (fs && strchr(fs->device, '=')) 249 fs->device = interpret_device(fs->device); 250 type = identify_fs(fs->device); 251 if (type) { 252 free(fs->type); 253 fs->type = string_copy(type); 254 } else 255 fprintf(stderr, _("Could not determine " 256 "filesystem type for %s\n"), 257 fs->device); 258 } 259} 260 261 262/* 263 * Load the filesystem database from /etc/fstab 264 */ 265static void load_fs_info(const char *filename) 266{ 267 FILE *f; 268 char buf[1024]; 269 int lineno = 0; 270 int old_fstab = 1; 271 struct fs_info *fs, *fs_last = NULL; 272 273 filesys_info = NULL; 274 if ((f = fopen(filename, "r")) == NULL) { 275 fprintf(stderr, _("WARNING: couldn't open %s: %s\n"), 276 filename, strerror(errno)); 277 return; 278 } 279 while (!feof(f)) { 280 lineno++; 281 if (!fgets(buf, sizeof(buf), f)) 282 break; 283 buf[sizeof(buf)-1] = 0; 284 if (parse_fstab_line(buf, &fs) < 0) { 285 fprintf(stderr, _("WARNING: bad format " 286 "on line %d of %s\n"), lineno, filename); 287 continue; 288 } 289 if (!fs) 290 continue; 291 if (!filesys_info) 292 filesys_info = fs; 293 else 294 fs_last->next = fs; 295 fs_last = fs; 296 if (fs->passno < 0) 297 fs->passno = 0; 298 else 299 old_fstab = 0; 300 } 301 302 fclose(f); 303 304 if (old_fstab) { 305 fprintf(stderr, _("\007\007\007" 306 "WARNING: Your /etc/fstab does not contain the fsck passno\n" 307 " field. I will kludge around things for you, but you\n" 308 " should fix your /etc/fstab file as soon as you can.\n\n")); 309 310 for (fs = filesys_info; fs; fs = fs->next) { 311 fs->passno = 1; 312 } 313 } 314} 315 316/* Lookup filesys in /etc/fstab and return the corresponding entry. */ 317static struct fs_info *lookup(char *filesys) 318{ 319 struct fs_info *fs; 320 int try_again = 0; 321 322 /* No filesys name given. */ 323 if (filesys == NULL) 324 return NULL; 325 326 for (fs = filesys_info; fs; fs = fs->next) { 327 if (strchr(fs->device, '=')) 328 try_again++; 329 if (!strcmp(filesys, fs->device) || 330 !strcmp(filesys, fs->mountpt)) 331 break; 332 } 333 if (fs && strchr(fs->device, '=')) 334 fs->device = interpret_device(fs->device); 335 336 if (fs || !try_again) 337 return fs; 338 339 for (fs = filesys_info; fs; fs = fs->next) { 340 fs->device = interpret_device(fs->device); 341 if (!strcmp(filesys, fs->device) || 342 !strcmp(filesys, fs->mountpt)) 343 break; 344 } 345 346 return fs; 347} 348 349/* Find fsck program for a given fs type. */ 350static char *find_fsck(char *type) 351{ 352 char *s; 353 const char *tpl; 354 static char prog[256]; 355 char *p = string_copy(fsck_path); 356 struct stat st; 357 358 /* Are we looking for a program or just a type? */ 359 tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s"); 360 361 for(s = strtok(p, ":"); s; s = strtok(NULL, ":")) { 362 sprintf(prog, tpl, s, type); 363 if (stat(prog, &st) == 0) break; 364 } 365 free(p); 366 return(s ? prog : NULL); 367} 368 369static int progress_active(NOARGS) 370{ 371 struct fsck_instance *inst; 372 373 for (inst = instance_list; inst; inst = inst->next) { 374 if (inst->flags & FLAG_DONE) 375 continue; 376 if (inst->flags & FLAG_PROGRESS) 377 return 1; 378 } 379 return 0; 380} 381 382/* 383 * Execute a particular fsck program, and link it into the list of 384 * child processes we are waiting for. 385 */ 386static int execute(const char *type, char *device, char *mntpt, 387 int interactive) 388{ 389 char *s, *argv[80], prog[80]; 390 int argc, i; 391 struct fsck_instance *inst, *p; 392 pid_t pid; 393 394 inst = malloc(sizeof(struct fsck_instance)); 395 if (!inst) 396 return ENOMEM; 397 memset(inst, 0, sizeof(struct fsck_instance)); 398 399 sprintf(prog, "fsck.%s", type); 400 argv[0] = string_copy(prog); 401 argc = 1; 402 403 for (i=0; i <num_args; i++) 404 argv[argc++] = string_copy(args[i]); 405 406 if (progress & !progress_active()) { 407 if ((strcmp(type, "ext2") == 0) || 408 (strcmp(type, "ext3") == 0)) { 409 argv[argc++] = string_copy("-C0"); 410 inst->flags |= FLAG_PROGRESS; 411 } 412 } 413 414 argv[argc++] = string_copy(device); 415 argv[argc] = 0; 416 417 s = find_fsck(prog); 418 if (s == NULL) { 419 fprintf(stderr, _("fsck: %s: not found\n"), prog); 420 return ENOENT; 421 } 422 423 if (verbose || noexecute) { 424 printf("[%s (%d) -- %s] ", s, num_running, 425 mntpt ? mntpt : device); 426 for (i=0; i < argc; i++) 427 printf("%s ", argv[i]); 428 printf("\n"); 429 } 430 431 /* Fork and execute the correct program. */ 432 if (noexecute) 433 pid = -1; 434 else if ((pid = fork()) < 0) { 435 perror("fork"); 436 return errno; 437 } else if (pid == 0) { 438 if (!interactive) 439 close(0); 440 (void) execv(s, argv); 441 perror(argv[0]); 442 exit(EXIT_ERROR); 443 } 444 445 for (i=0; i < argc; i++) 446 free(argv[i]); 447 448 inst->pid = pid; 449 inst->prog = string_copy(prog); 450 inst->type = string_copy(type); 451 inst->device = string_copy(device); 452 inst->base_device = base_device(device); 453 inst->start_time = time(0); 454 inst->next = NULL; 455 456 /* 457 * Find the end of the list, so we add the instance on at the end. 458 */ 459 for (p = instance_list; p && p->next; p = p->next); 460 461 if (p) 462 p->next = inst; 463 else 464 instance_list = inst; 465 466 return 0; 467} 468 469/* 470 * Wait for one child process to exit; when it does, unlink it from 471 * the list of executing child processes, and return it. 472 */ 473static struct fsck_instance *wait_one(int flags) 474{ 475 int status; 476 int sig; 477 struct fsck_instance *inst, *inst2, *prev; 478 pid_t pid; 479 480 if (!instance_list) 481 return NULL; 482 483 if (noexecute) { 484 inst = instance_list; 485 prev = 0; 486#ifdef RANDOM_DEBUG 487 while (inst->next && (random() & 1)) { 488 prev = inst; 489 inst = inst->next; 490 } 491#endif 492 inst->exit_status = 0; 493 goto ret_inst; 494 } 495 496 /* 497 * gcc -Wall fails saving throw against stupidity 498 * (inst and prev are thought to be uninitialized variables) 499 */ 500 inst = prev = NULL; 501 502 do { 503 pid = waitpid(-1, &status, flags); 504 if ((pid == 0) && (flags & WNOHANG)) 505 return NULL; 506 if (pid < 0) { 507 if ((errno == EINTR) || (errno == EAGAIN)) 508 continue; 509 if (errno == ECHILD) { 510 fprintf(stderr, 511 _("%s: wait: No more child process?!?\n"), 512 progname); 513 return NULL; 514 } 515 perror("wait"); 516 continue; 517 } 518 for (prev = 0, inst = instance_list; 519 inst; 520 prev = inst, inst = inst->next) { 521 if (inst->pid == pid) 522 break; 523 } 524 } while (!inst); 525 526 if (WIFEXITED(status)) 527 status = WEXITSTATUS(status); 528 else if (WIFSIGNALED(status)) { 529 sig = WTERMSIG(status); 530 if (sig == SIGINT) { 531 status = EXIT_UNCORRECTED; 532 } else { 533 printf(_("Warning... %s for device %s exited " 534 "with signal %d.\n"), 535 inst->prog, inst->device, sig); 536 status = EXIT_ERROR; 537 } 538 } else { 539 printf(_("%s %s: status is %x, should never happen.\n"), 540 inst->prog, inst->device, status); 541 status = EXIT_ERROR; 542 } 543 inst->exit_status = status; 544 if (progress && (inst->flags & FLAG_PROGRESS) && 545 !progress_active()) { 546 for (inst2 = instance_list; inst2; inst2 = inst2->next) { 547 if (inst2->flags & FLAG_DONE) 548 continue; 549 if (strcmp(inst2->type, "ext2") && 550 strcmp(inst2->type, "ext3")) 551 continue; 552 /* 553 * If we've just started the fsck, wait a tiny 554 * bit before sending the kill, to give it 555 * time to set up the signal handler 556 */ 557 if (inst2->start_time < time(0)+2) { 558 if (fork() == 0) { 559 sleep(1); 560 kill(inst2->pid, SIGUSR1); 561 exit(0); 562 } 563 } else 564 kill(inst2->pid, SIGUSR1); 565 inst2->flags |= FLAG_PROGRESS; 566 break; 567 } 568 } 569ret_inst: 570 if (prev) 571 prev->next = inst->next; 572 else 573 instance_list = inst->next; 574 if (verbose > 1) 575 printf(_("Finished with %s (exit status %d)\n"), 576 inst->device, inst->exit_status); 577 num_running--; 578 return inst; 579} 580 581/* 582 * Wait until all executing child processes have exited; return the 583 * logical OR of all of their exit code values. 584 */ 585static int wait_all(int flags) 586{ 587 struct fsck_instance *inst; 588 int global_status = 0; 589 590 while ((inst = wait_one(flags))) { 591 global_status |= inst->exit_status; 592 free_instance(inst); 593#ifdef RANDOM_DEBUG 594 if (noexecute && (flags & WNOHANG) && !(random() % 3)) 595 break; 596#endif 597 } 598 return global_status; 599} 600 601/* 602 * Run the fsck program on a particular device 603 * 604 * If the type is specified using -t, and it isn't prefixed with "no" 605 * (as in "noext2") and only one filesystem type is specified, then 606 * use that type regardless of what is specified in /etc/fstab. 607 * 608 * If the type isn't specified by the user, then use either the type 609 * specified in /etc/fstab, or DEFAULT_FSTYPE. 610 */ 611static void fsck_device(char *device, int interactive) 612{ 613 const char *type = 0; 614 struct fs_info *fsent; 615 int retval; 616 617 if (fstype && strncmp(fstype, "no", 2) && 618 strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) && 619 !strchr(fstype, ',')) 620 type = fstype; 621 622 if ((fsent = lookup(device))) { 623 device = fsent->device; 624 interpret_type(fsent); 625 if (!type) 626 type = fsent->type; 627 } 628 if (!type) 629 type = DEFAULT_FSTYPE; 630 631 num_running++; 632 retval = execute(type, device, fsent ? fsent->mountpt : 0, 633 interactive); 634 if (retval) { 635 fprintf(stderr, _("%s: Error %d while executing fsck.%s " 636 "for %s\n"), progname, retval, type, device); 637 num_running--; 638 } 639} 640 641 642/* 643 * Deal with the fsck -t argument. 644 */ 645struct fs_type_compile { 646 char **list; 647 int *type; 648 int negate; 649} fs_type_compiled; 650 651#define FS_TYPE_NORMAL 0 652#define FS_TYPE_OPT 1 653#define FS_TYPE_NEGOPT 2 654 655static const char *fs_type_syntax_error = 656N_("Either all or none of the filesystem types passed to -t must be prefixed\n" 657 "with 'no' or '!'.\n"); 658 659static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp) 660{ 661 char *cp, *list, *s; 662 int num = 2; 663 int negate, first_negate = 1; 664 665 if (fs_type) { 666 for (cp=fs_type; *cp; cp++) { 667 if (*cp == ',') 668 num++; 669 } 670 } 671 672 cmp->list = malloc(num * sizeof(char *)); 673 cmp->type = malloc(num * sizeof(int)); 674 if (!cmp->list || !cmp->type) { 675 fprintf(stderr, _("Couldn't allocate memory for " 676 "filesystem types\n")); 677 exit(EXIT_ERROR); 678 } 679 memset(cmp->list, 0, num * sizeof(char *)); 680 memset(cmp->type, 0, num * sizeof(int)); 681 cmp->negate = 0; 682 683 if (!fs_type) 684 return; 685 686 list = string_copy(fs_type); 687 num = 0; 688 s = strtok(list, ","); 689 while(s) { 690 negate = 0; 691 if (strncmp(s, "no", 2) == 0) { 692 s += 2; 693 negate = 1; 694 } else if (*s == '!') { 695 s++; 696 negate = 1; 697 } 698 if (strcmp(s, "loop") == 0) 699 /* loop is really short-hand for opts=loop */ 700 goto loop_special_case; 701 else if (strncmp(s, "opts=", 5) == 0) { 702 s += 5; 703 loop_special_case: 704 cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT; 705 } else { 706 if (first_negate) { 707 cmp->negate = negate; 708 first_negate = 0; 709 } 710 if ((negate && !cmp->negate) || 711 (!negate && cmp->negate)) { 712 fprintf(stderr, _(fs_type_syntax_error)); 713 exit(EXIT_USAGE); 714 } 715 } 716#if 0 717 printf("Adding %s to list (type %d).\n", s, cmp->type[num]); 718#endif 719 cmp->list[num++] = string_copy(s); 720 s = strtok(NULL, ","); 721 } 722 free(list); 723} 724 725/* 726 * This function returns true if a particular option appears in a 727 * comma-delimited options list 728 */ 729static int opt_in_list(char *opt, char *optlist) 730{ 731 char *list, *s; 732 733 if (!optlist) 734 return 0; 735 list = string_copy(optlist); 736 737 s = strtok(list, ","); 738 while(s) { 739 if (strcmp(s, opt) == 0) { 740 free(list); 741 return 1; 742 } 743 s = strtok(NULL, ","); 744 } 745 free(list); 746 return 0; 747} 748 749/* See if the filesystem matches the criteria given by the -t option */ 750static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp) 751{ 752 int n, ret = 0, checked_type = 0; 753 char *cp; 754 755 if (cmp->list == 0 || cmp->list[0] == 0) 756 return 1; 757 758 for (n=0; (cp = cmp->list[n]); n++) { 759 switch (cmp->type[n]) { 760 case FS_TYPE_NORMAL: 761 checked_type++; 762 if (strcmp(cp, fs->type) == 0) { 763 ret = 1; 764 } 765 break; 766 case FS_TYPE_NEGOPT: 767 if (opt_in_list(cp, fs->opts)) 768 return 0; 769 break; 770 case FS_TYPE_OPT: 771 if (!opt_in_list(cp, fs->opts)) 772 return 0; 773 break; 774 } 775 } 776 if (checked_type == 0) 777 return 1; 778 return (cmp->negate ? !ret : ret); 779} 780 781/* Check if we should ignore this filesystem. */ 782static int ignore(struct fs_info *fs) 783{ 784 const char **ip; 785 int wanted = 0; 786 787 /* 788 * If the pass number is 0, ignore it. 789 */ 790 if (fs->passno == 0) 791 return 1; 792 793 interpret_type(fs); 794 795 /* 796 * If a specific fstype is specified, and it doesn't match, 797 * ignore it. 798 */ 799 if (!fs_match(fs, &fs_type_compiled)) return 1; 800 801 /* Are we ignoring this type? */ 802 for(ip = ignored_types; *ip; ip++) 803 if (strcmp(fs->type, *ip) == 0) return 1; 804 805 /* Do we really really want to check this fs? */ 806 for(ip = really_wanted; *ip; ip++) 807 if (strcmp(fs->type, *ip) == 0) { 808 wanted = 1; 809 break; 810 } 811 812 /* See if the <fsck.fs> program is available. */ 813 if (find_fsck(fs->type) == NULL) { 814 if (wanted) 815 fprintf(stderr, _("fsck: cannot check %s: fsck.%s not found\n"), 816 fs->device, fs->type); 817 return 1; 818 } 819 820 /* We can and want to check this file system type. */ 821 return 0; 822} 823 824/* 825 * Returns TRUE if a partition on the same disk is already being 826 * checked. 827 */ 828static int device_already_active(char *device) 829{ 830 struct fsck_instance *inst; 831 char *base; 832 833 if (force_all_parallel) 834 return 0; 835 836#ifdef BASE_MD 837 /* Don't check a soft raid disk with any other disk */ 838 if (instance_list && 839 (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) || 840 !strncmp(device, BASE_MD, sizeof(BASE_MD)-1))) 841 return 1; 842#endif 843 844 base = base_device(device); 845 /* 846 * If we don't know the base device, assume that the device is 847 * already active if there are any fsck instances running. 848 */ 849 if (!base) 850 return (instance_list != 0); 851 for (inst = instance_list; inst; inst = inst->next) { 852 if (!inst->base_device || !strcmp(base, inst->base_device)) { 853 free(base); 854 return 1; 855 } 856 } 857 free(base); 858 return 0; 859} 860 861/* Check all file systems, using the /etc/fstab table. */ 862static int check_all(NOARGS) 863{ 864 struct fs_info *fs = NULL; 865 struct fsck_instance *inst; 866 int status = EXIT_OK; 867 int not_done_yet = 1; 868 int passno = 1; 869 int pass_done; 870 871 if (verbose) 872 printf(_("Checking all file systems.\n")); 873 874 /* 875 * Do an initial scan over the filesystem; mark filesystems 876 * which should be ignored as done, and resolve LABEL= and 877 * UUID= specifications to the real device. 878 */ 879 for (fs = filesys_info; fs; fs = fs->next) { 880 if (ignore(fs)) 881 fs->flags |= FLAG_DONE; 882 else 883 fs->device = interpret_device(fs->device); 884 } 885 886 /* 887 * Find and check the root filesystem. 888 */ 889 if (!parallel_root) { 890 for (fs = filesys_info; fs; fs = fs->next) { 891 if (!strcmp(fs->mountpt, "/")) 892 break; 893 } 894 if (fs) { 895 if (!skip_root && !ignore(fs)) { 896 fsck_device(fs->device, 1); 897 status |= wait_all(0); 898 if (status > EXIT_NONDESTRUCT) 899 return status; 900 } 901 fs->flags |= FLAG_DONE; 902 } 903 } 904 905 while (not_done_yet) { 906 not_done_yet = 0; 907 pass_done = 1; 908 909 for (fs = filesys_info; fs; fs = fs->next) { 910 if (fs->flags & FLAG_DONE) 911 continue; 912 /* 913 * If the filesystem's pass number is higher 914 * than the current pass number, then we don't 915 * do it yet. 916 */ 917 if (fs->passno > passno) { 918 not_done_yet++; 919 continue; 920 } 921 /* 922 * If a filesystem on a particular device has 923 * already been spawned, then we need to defer 924 * this to another pass. 925 */ 926 if (device_already_active(fs->device)) { 927 pass_done = 0; 928 continue; 929 } 930 /* 931 * Spawn off the fsck process 932 */ 933 fsck_device(fs->device, serialize); 934 fs->flags |= FLAG_DONE; 935 936 /* 937 * Only do one filesystem at a time, or if we 938 * have a limit on the number of fsck's extant 939 * at one time, apply that limit. 940 */ 941 if (serialize || 942 (max_running && (num_running >= max_running))) { 943 pass_done = 0; 944 break; 945 } 946 } 947 if (verbose > 1) 948 printf(_("--waiting-- (pass %d)\n"), passno); 949 status |= wait_all(pass_done ? 0 : WNOHANG); 950 if (pass_done) { 951 if (verbose > 1) 952 printf("----------------------------------\n"); 953 passno++; 954 } else 955 not_done_yet++; 956 } 957 status |= wait_all(0); 958 return status; 959} 960 961static void usage(NOARGS) 962{ 963 fprintf(stderr, 964 _("Usage: fsck [-ACNPRTV] [-t fstype] [fs-options] filesys\n")); 965 exit(EXIT_USAGE); 966} 967 968static void PRS(int argc, char *argv[]) 969{ 970 int i, j; 971 char *arg, *tmp; 972 char options[128]; 973 int opt = 0; 974 int opts_for_fsck = 0; 975 976 num_devices = 0; 977 num_args = 0; 978 instance_list = 0; 979 980 progname = argv[0]; 981 982 for (i=1; i < argc; i++) { 983 arg = argv[i]; 984 if (!arg) 985 continue; 986 if ((arg[0] == '/' && !opts_for_fsck) || 987 (strncmp(arg, "LABEL=", 6) == 0) || 988 (strncmp(arg, "UUID=", 5) == 0)) { 989 if (num_devices >= MAX_DEVICES) { 990 fprintf(stderr, _("%s: too many devices\n"), 991 progname); 992 exit(EXIT_ERROR); 993 } 994 devices[num_devices++] = 995 interpret_device(string_copy(arg)); 996 continue; 997 } 998 if (arg[0] != '-' || opts_for_fsck) { 999 if (num_args >= MAX_ARGS) { 1000 fprintf(stderr, _("%s: too many arguments\n"), 1001 progname); 1002 exit(EXIT_ERROR); 1003 } 1004 args[num_args++] = string_copy(arg); 1005 continue; 1006 } 1007 for (j=1; arg[j]; j++) { 1008 if (opts_for_fsck) { 1009 options[++opt] = arg[j]; 1010 continue; 1011 } 1012 switch (arg[j]) { 1013 case 'A': 1014 doall++; 1015 break; 1016 case 'C': 1017 progress++; 1018 break; 1019 case 'V': 1020 verbose++; 1021 break; 1022 case 'N': 1023 noexecute++; 1024 break; 1025 case 'R': 1026 skip_root++; 1027 break; 1028 case 'T': 1029 notitle++; 1030 break; 1031 case 'M': 1032 like_mount++; 1033 break; 1034 case 'P': 1035 parallel_root++; 1036 break; 1037 case 's': 1038 serialize++; 1039 break; 1040 case 't': 1041 if (fstype) 1042 usage(); 1043 if (arg[j+1]) 1044 tmp = arg+j+1; 1045 else if ((i+1) < argc) 1046 tmp = argv[++i]; 1047 else 1048 usage(); 1049 fstype = string_copy(tmp); 1050 compile_fs_type(fstype, &fs_type_compiled); 1051 goto next_arg; 1052 case '-': 1053 opts_for_fsck++; 1054 break; 1055 case '?': 1056 usage(); 1057 break; 1058 default: 1059 options[++opt] = arg[j]; 1060 break; 1061 } 1062 } 1063 next_arg: 1064 if (opt) { 1065 options[0] = '-'; 1066 options[++opt] = '\0'; 1067 if (num_args >= MAX_ARGS) { 1068 fprintf(stderr, 1069 _("%s: too many arguments\n"), 1070 progname); 1071 exit(EXIT_ERROR); 1072 } 1073 args[num_args++] = string_copy(options); 1074 opt = 0; 1075 } 1076 } 1077 if (getenv("FSCK_FORCE_ALL_PARALLEL")) 1078 force_all_parallel++; 1079 if ((tmp = getenv("FSCK_MAX_INST"))) 1080 max_running = atoi(tmp); 1081} 1082 1083int main(int argc, char *argv[]) 1084{ 1085 int i; 1086 int status = 0; 1087 int interactive = 0; 1088 char *oldpath = getenv("PATH"); 1089 const char *fstab; 1090 1091#ifdef ENABLE_NLS 1092 setlocale(LC_MESSAGES, ""); 1093 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 1094 textdomain(NLS_CAT_NAME); 1095#endif 1096 PRS(argc, argv); 1097 1098 if (!notitle) 1099 printf("fsck %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); 1100 1101 fstab = getenv("FSTAB_FILE"); 1102 if (!fstab) 1103 fstab = _PATH_MNTTAB; 1104 load_fs_info(fstab); 1105 1106 /* Update our search path to include uncommon directories. */ 1107 if (oldpath) { 1108 fsck_path = malloc (strlen (fsck_prefix_path) + 1 + 1109 strlen (oldpath) + 1); 1110 strcpy (fsck_path, fsck_prefix_path); 1111 strcat (fsck_path, ":"); 1112 strcat (fsck_path, oldpath); 1113 } else { 1114 fsck_path = string_copy(fsck_prefix_path); 1115 } 1116 1117 if ((num_devices == 1) || (serialize)) 1118 interactive = 1; 1119 1120 /* If -A was specified ("check all"), do that! */ 1121 if (doall) 1122 return check_all(); 1123 1124 if (num_devices == 0) { 1125 fprintf(stderr, _("\nNo devices specified to be checked!\n")); 1126 exit(EXIT_ERROR); 1127 } 1128 for (i = 0 ; i < num_devices; i++) { 1129 fsck_device(devices[i], interactive); 1130 if (serialize || (num_running >= max_running)) { 1131 struct fsck_instance *inst; 1132 1133 inst = wait_one(0); 1134 if (inst) { 1135 status |= inst->exit_status; 1136 free_instance(inst); 1137 } 1138 } 1139 } 1140 status |= wait_all(0); 1141 free(fsck_path); 1142 return status; 1143} 1144