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