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