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