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