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