busybox/e2fsprogs/fsck.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * fsck --- 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 source tree.
  24 */
  25
  26/* All filesystem specific hooks have been removed.
  27 * If filesystem cannot be determined, we will execute
  28 * "fsck.auto". Currently this also happens if you specify
  29 * UUID=xxx or LABEL=xxx as an object to check.
  30 * Detection code for that is also probably has to be in fsck.auto.
  31 *
  32 * In other words, this is _really_ is just a driver program which
  33 * spawns actual fsck.something for each filesystem to check.
  34 * It doesn't guess filesystem types from on-disk format.
  35 */
  36//config:config FSCK
  37//config:       bool "fsck (7.4 kb)"
  38//config:       default y
  39//config:       help
  40//config:       fsck is used to check and optionally repair one or more filesystems.
  41//config:       In actuality, fsck is simply a front-end for the various file system
  42//config:       checkers (fsck.fstype) available under Linux.
  43
  44//applet:IF_FSCK(APPLET(fsck, BB_DIR_SBIN, BB_SUID_DROP))
  45
  46//kbuild:lib-$(CONFIG_FSCK) += fsck.o
  47
  48//usage:#define fsck_trivial_usage
  49//usage:       "[-ANPRTV] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]..."
  50//usage:#define fsck_full_usage "\n\n"
  51//usage:       "Check and repair filesystems\n"
  52//usage:     "\n        -A      Walk /etc/fstab and check all filesystems"
  53//usage:     "\n        -N      Don't execute, just show what would be done"
  54//usage:     "\n        -P      With -A, check filesystems in parallel"
  55//usage:     "\n        -R      With -A, skip the root filesystem"
  56//usage:     "\n        -T      Don't show title on startup"
  57//usage:     "\n        -V      Verbose"
  58//DO_PROGRESS_INDICATOR is off:
  59////usage:     "\n      -C FD   Write status information to specified file descriptor"
  60//usage:     "\n        -t TYPE List of filesystem types to check"
  61
  62#include "libbb.h"
  63#include "common_bufsiz.h"
  64
  65/* "progress indicator" code is somewhat buggy and ext[23] specific.
  66 * We should be filesystem agnostic. IOW: there should be a well-defined
  67 * API for fsck.something, NOT ad-hoc hacks in generic fsck. */
  68#define DO_PROGRESS_INDICATOR 0
  69
  70/* fsck 1.41.4 (27-Jan-2009) manpage says:
  71 * 0   - No errors
  72 * 1   - File system errors corrected
  73 * 2   - System should be rebooted
  74 * 4   - File system errors left uncorrected
  75 * 8   - Operational error
  76 * 16  - Usage or syntax error
  77 * 32  - Fsck canceled by user request
  78 * 128 - Shared library error
  79 */
  80#define EXIT_OK          0
  81#define EXIT_NONDESTRUCT 1
  82#define EXIT_DESTRUCT    2
  83#define EXIT_UNCORRECTED 4
  84#define EXIT_ERROR       8
  85#define EXIT_USAGE       16
  86#define FSCK_CANCELED    32     /* Aborted with a signal or ^C */
  87
  88/*
  89 * Internal structure for mount table entries.
  90 */
  91struct fs_info {
  92        struct fs_info *next;
  93        char    *device;
  94        char    *mountpt;
  95        char    *type;
  96        char    *opts;
  97        int     passno;
  98        int     flags;
  99};
 100
 101#define FLAG_DONE 1
 102#define FLAG_PROGRESS 2
 103/*
 104 * Structure to allow exit codes to be stored
 105 */
 106struct fsck_instance {
 107        struct fsck_instance *next;
 108        int     pid;
 109        int     flags;
 110#if DO_PROGRESS_INDICATOR
 111        time_t  start_time;
 112#endif
 113        char    *prog;
 114        char    *device;
 115        char    *base_device; /* /dev/hda for /dev/hdaN etc */
 116};
 117
 118static const char ignored_types[] ALIGN1 =
 119        "ignore\0"
 120        "iso9660\0"
 121        "nfs\0"
 122        "proc\0"
 123        "sw\0"
 124        "swap\0"
 125        "tmpfs\0"
 126        "devpts\0";
 127
 128#if 0
 129static const char really_wanted[] ALIGN1 =
 130        "minix\0"
 131        "ext2\0"
 132        "ext3\0"
 133        "jfs\0"
 134        "reiserfs\0"
 135        "xiafs\0"
 136        "xfs\0";
 137#endif
 138
 139#define BASE_MD "/dev/md"
 140
 141struct globals {
 142        char **args;
 143        int num_args;
 144        int verbose;
 145
 146#define FS_TYPE_FLAG_NORMAL 0
 147#define FS_TYPE_FLAG_OPT    1
 148#define FS_TYPE_FLAG_NEGOPT 2
 149        char **fs_type_list;
 150        uint8_t *fs_type_flag;
 151        smallint fs_type_negated;
 152
 153        smallint noexecute;
 154        smallint serialize;
 155        smallint skip_root;
 156        /* smallint like_mount; */
 157        smallint parallel_root;
 158        smallint force_all_parallel;
 159        smallint kill_sent;
 160
 161#if DO_PROGRESS_INDICATOR
 162        smallint progress;
 163        int progress_fd;
 164#endif
 165
 166        int num_running;
 167        int max_running;
 168        char *fstype;
 169        struct fs_info *filesys_info;
 170        struct fs_info *filesys_last;
 171        struct fsck_instance *instance_list;
 172} FIX_ALIASING;
 173#define G (*(struct globals*)bb_common_bufsiz1)
 174#define INIT_G() do { \
 175        setup_common_bufsiz(); \
 176        BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \
 177} while (0)
 178
 179/*
 180 * Return the "base device" given a particular device; this is used to
 181 * assure that we only fsck one partition on a particular drive at any
 182 * one time.  Otherwise, the disk heads will be seeking all over the
 183 * place.  If the base device cannot be determined, return NULL.
 184 *
 185 * The base_device() function returns an allocated string which must
 186 * be freed.
 187 */
 188#if ENABLE_FEATURE_DEVFS
 189/*
 190 * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3
 191 * pathames.
 192 */
 193static const char *const devfs_hier[] = {
 194        "host", "bus", "target", "lun", NULL
 195};
 196#endif
 197
 198static char *base_device(const char *device)
 199{
 200        char *str, *cp;
 201#if ENABLE_FEATURE_DEVFS
 202        const char *const *hier;
 203        const char *disk;
 204        int len;
 205#endif
 206        str = xstrdup(device);
 207
 208        /* Skip over "/dev/"; if it's not present, give up */
 209        cp = skip_dev_pfx(str);
 210        if (cp == str)
 211                goto errout;
 212
 213        /*
 214         * For md devices, we treat them all as if they were all
 215         * on one disk, since we don't know how to parallelize them.
 216         */
 217        if (cp[0] == 'm' && cp[1] == 'd') {
 218                cp[2] = 0;
 219                return str;
 220        }
 221
 222        /* Handle DAC 960 devices */
 223        if (is_prefixed_with(cp, "rd/")) {
 224                cp += 3;
 225                if (cp[0] != 'c' || !isdigit(cp[1])
 226                 || cp[2] != 'd' || !isdigit(cp[3]))
 227                        goto errout;
 228                cp[4] = 0;
 229                return str;
 230        }
 231
 232        /* Now let's handle /dev/hd* and /dev/sd* devices.... */
 233        if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') {
 234                cp += 2;
 235                /* If there's a single number after /dev/hd, skip it */
 236                if (isdigit(*cp))
 237                        cp++;
 238                /* What follows must be an alpha char, or give up */
 239                if (!isalpha(*cp))
 240                        goto errout;
 241                cp[1] = 0;
 242                return str;
 243        }
 244
 245#if ENABLE_FEATURE_DEVFS
 246        /* Now let's handle devfs (ugh) names */
 247        len = 0;
 248        if (is_prefixed_with(cp, "ide/"))
 249                len = 4;
 250        if (is_prefixed_with(cp, "scsi/"))
 251                len = 5;
 252        if (len) {
 253                cp += len;
 254                /*
 255                 * Now we proceed down the expected devfs hierarchy.
 256                 * i.e., .../host1/bus2/target3/lun4/...
 257                 * If we don't find the expected token, followed by
 258                 * some number of digits at each level, abort.
 259                 */
 260                for (hier = devfs_hier; *hier; hier++) {
 261                        cp = is_prefixed_with(cp, *hier);
 262                        if (!cp)
 263                                goto errout;
 264                        while (*cp != '/' && *cp != '\0') {
 265                                if (!isdigit(*cp))
 266                                        goto errout;
 267                                cp++;
 268                        }
 269//FIXME: what if *cp = '\0' now? cp++ moves past it!!!
 270                        cp++;
 271                }
 272                cp[-1] = '\0';
 273                return str;
 274        }
 275
 276        /* Now handle devfs /dev/disc or /dev/disk names */
 277        disk = NULL;
 278        if (is_prefixed_with(cp, "discs/"))
 279                disk = "disc";
 280        else if (is_prefixed_with(cp, "disks/"))
 281                disk = "disk";
 282        if (disk) {
 283                cp += 6;
 284                cp = is_prefixed_with(cp, disk);
 285                if (!cp)
 286                        goto errout;
 287                while (*cp != '/' && *cp != '\0') {
 288                        if (!isdigit(*cp))
 289                                goto errout;
 290                        cp++;
 291                }
 292                *cp = '\0';
 293                return str;
 294        }
 295#endif
 296 errout:
 297        free(str);
 298        return NULL;
 299}
 300
 301static void free_instance(struct fsck_instance *p)
 302{
 303        free(p->prog);
 304        free(p->device);
 305        free(p->base_device);
 306        free(p);
 307}
 308
 309static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
 310                                        const char *type, const char *opts,
 311                                        int passno)
 312{
 313        struct fs_info *fs;
 314
 315        fs = xzalloc(sizeof(*fs));
 316        fs->device = xstrdup(device);
 317        fs->mountpt = xstrdup(mntpnt);
 318        if (strchr(type, ','))
 319                type = (char *)"auto";
 320        fs->type = xstrdup(type);
 321        fs->opts = xstrdup(opts ? opts : "");
 322        fs->passno = passno < 0 ? 1 : passno;
 323        /*fs->flags = 0; */
 324        /*fs->next = NULL; */
 325
 326        if (!G.filesys_info)
 327                G.filesys_info = fs;
 328        else
 329                G.filesys_last->next = fs;
 330        G.filesys_last = fs;
 331
 332        return fs;
 333}
 334
 335/* Load the filesystem database from /etc/fstab */
 336static void load_fs_info(const char *filename)
 337{
 338        FILE *fstab;
 339        struct mntent mte;
 340        char buf[1024];
 341
 342        fstab = setmntent(filename, "r");
 343        if (!fstab) {
 344                bb_perror_msg("can't read '%s'", filename);
 345                return;
 346        }
 347
 348        // Loop through entries
 349        while (getmntent_r(fstab, &mte, buf, sizeof(buf))) {
 350                //bb_error_msg("CREATE[%s][%s][%s][%s][%d]", mte.mnt_fsname, mte.mnt_dir,
 351                //      mte.mnt_type, mte.mnt_opts,
 352                //      mte.mnt_passno);
 353                create_fs_device(mte.mnt_fsname, mte.mnt_dir,
 354                        mte.mnt_type, mte.mnt_opts,
 355                        mte.mnt_passno);
 356        }
 357        endmntent(fstab);
 358}
 359
 360/* Lookup filesys in /etc/fstab and return the corresponding entry. */
 361static struct fs_info *lookup(char *filesys)
 362{
 363        struct fs_info *fs;
 364
 365        for (fs = G.filesys_info; fs; fs = fs->next) {
 366                if (strcmp(filesys, fs->device) == 0
 367                 || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0)
 368                )
 369                        break;
 370        }
 371
 372        return fs;
 373}
 374
 375#if DO_PROGRESS_INDICATOR
 376static int progress_active(void)
 377{
 378        struct fsck_instance *inst;
 379
 380        for (inst = G.instance_list; inst; inst = inst->next) {
 381                if (inst->flags & FLAG_DONE)
 382                        continue;
 383                if (inst->flags & FLAG_PROGRESS)
 384                        return 1;
 385        }
 386        return 0;
 387}
 388#endif
 389
 390
 391/*
 392 * Send a signal to all outstanding fsck child processes
 393 */
 394static void kill_all_if_got_signal(void)
 395{
 396        struct fsck_instance *inst;
 397
 398        if (!bb_got_signal || G.kill_sent)
 399                return;
 400
 401        for (inst = G.instance_list; inst; inst = inst->next) {
 402                if (inst->flags & FLAG_DONE)
 403                        continue;
 404                kill(inst->pid, SIGTERM);
 405        }
 406        G.kill_sent = 1;
 407}
 408
 409/*
 410 * Wait for one child process to exit; when it does, unlink it from
 411 * the list of executing child processes, free, and return its exit status.
 412 * If there is no exited child, return -1.
 413 */
 414static int wait_one(int flags)
 415{
 416        int status;
 417        int exitcode;
 418        struct fsck_instance *inst, *prev;
 419        pid_t pid;
 420
 421        if (!G.instance_list)
 422                return -1;
 423        /* if (G.noexecute) { already returned -1; } */
 424
 425        while (1) {
 426                pid = waitpid(-1, &status, flags);
 427                kill_all_if_got_signal();
 428                if (pid == 0) /* flags == WNOHANG and no children exited */
 429                        return -1;
 430                if (pid < 0) {
 431                        if (errno == EINTR)
 432                                continue;
 433                        if (errno == ECHILD) { /* paranoia */
 434                                bb_simple_error_msg("wait: no more children");
 435                                return -1;
 436                        }
 437                        bb_simple_perror_msg("wait");
 438                        continue;
 439                }
 440                prev = NULL;
 441                inst = G.instance_list;
 442                do {
 443                        if (inst->pid == pid)
 444                                goto child_died;
 445                        prev = inst;
 446                        inst = inst->next;
 447                } while (inst);
 448        }
 449 child_died:
 450
 451        exitcode = WEXITSTATUS(status);
 452        if (WIFSIGNALED(status)) {
 453                unsigned sig;
 454                sig = WTERMSIG(status);
 455                exitcode = EXIT_UNCORRECTED;
 456                if (sig != SIGINT) {
 457                        printf("Warning: %s %s terminated "
 458                                "by signal %u\n",
 459                                inst->prog, inst->device, sig);
 460                        exitcode = EXIT_ERROR;
 461                }
 462        }
 463
 464#if DO_PROGRESS_INDICATOR
 465        if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) {
 466                struct fsck_instance *inst2;
 467                for (inst2 = G.instance_list; inst2; inst2 = inst2->next) {
 468                        if (inst2->flags & FLAG_DONE)
 469                                continue;
 470                        if (strcmp(inst2->type, "ext2") != 0
 471                         && strcmp(inst2->type, "ext3") != 0
 472                        ) {
 473                                continue;
 474                        }
 475                        /* ext[23], we will send USR1
 476                         * (request to start displaying progress bar)
 477                         *
 478                         * If we've just started the fsck, wait a tiny
 479                         * bit before sending the kill, to give it
 480                         * time to set up the signal handler
 481                         */
 482                        if (inst2->start_time >= time(NULL) - 1)
 483                                sleep1();
 484                        kill(inst2->pid, SIGUSR1);
 485                        inst2->flags |= FLAG_PROGRESS;
 486                        break;
 487                }
 488        }
 489#endif
 490
 491        if (prev)
 492                prev->next = inst->next;
 493        else
 494                G.instance_list = inst->next;
 495        if (G.verbose > 1)
 496                printf("Finished with %s (exit status %u)\n",
 497                        inst->device, exitcode);
 498        G.num_running--;
 499        free_instance(inst);
 500
 501        return exitcode;
 502}
 503
 504/*
 505 * Wait until all executing child processes have exited; return the
 506 * logical OR of all of their exit code values.
 507 */
 508#define FLAG_WAIT_ALL           0
 509#define FLAG_WAIT_ATLEAST_ONE   WNOHANG
 510static int wait_many(int flags)
 511{
 512        int exit_status;
 513        int global_status = 0;
 514        int wait_flags = 0;
 515
 516        while ((exit_status = wait_one(wait_flags)) != -1) {
 517                global_status |= exit_status;
 518                wait_flags |= flags;
 519        }
 520        return global_status;
 521}
 522
 523/*
 524 * Execute a particular fsck program, and link it into the list of
 525 * child processes we are waiting for.
 526 */
 527static void execute(const char *type, const char *device,
 528                const char *mntpt /*, int interactive */)
 529{
 530        int i;
 531        struct fsck_instance *inst;
 532        pid_t pid;
 533
 534        G.args[0] = xasprintf("fsck.%s", type);
 535
 536#if DO_PROGRESS_INDICATOR
 537        if (progress && !progress_active()) {
 538                if (strcmp(type, "ext2") == 0
 539                 || strcmp(type, "ext3") == 0
 540                ) {
 541                        G.args[XXX] = xasprintf("-C%d", progress_fd); /* 1 */
 542                        inst->flags |= FLAG_PROGRESS;
 543                }
 544        }
 545#endif
 546
 547        G.args[G.num_args - 2] = (char*)device;
 548        /* G.args[G.num_args - 1] = NULL; - already is */
 549
 550        if (G.verbose || G.noexecute) {
 551                printf("[%s (%d) -- %s]", G.args[0], G.num_running,
 552                                        mntpt ? mntpt : device);
 553                for (i = 0; G.args[i]; i++)
 554                        printf(" %s", G.args[i]);
 555                bb_putchar('\n');
 556        }
 557
 558        /* Fork and execute the correct program. */
 559        pid = -1;
 560        if (!G.noexecute) {
 561                pid = spawn(G.args);
 562                if (pid < 0)
 563                        bb_simple_perror_msg(G.args[0]);
 564        }
 565
 566#if DO_PROGRESS_INDICATOR
 567        free(G.args[XXX]);
 568#endif
 569
 570        /* No child, so don't record an instance */
 571        if (pid <= 0) {
 572                free(G.args[0]);
 573                return;
 574        }
 575
 576        inst = xzalloc(sizeof(*inst));
 577        inst->pid = pid;
 578        inst->prog = G.args[0];
 579        inst->device = xstrdup(device);
 580        inst->base_device = base_device(device);
 581#if DO_PROGRESS_INDICATOR
 582        inst->start_time = time(NULL);
 583#endif
 584
 585        /* Add to the list of running fsck's.
 586         * (was adding to the end, but adding to the front is simpler...) */
 587        inst->next = G.instance_list;
 588        G.instance_list = inst;
 589}
 590
 591/*
 592 * Run the fsck program on a particular device
 593 *
 594 * If the type is specified using -t, and it isn't prefixed with "no"
 595 * (as in "noext2") and only one filesystem type is specified, then
 596 * use that type regardless of what is specified in /etc/fstab.
 597 *
 598 * If the type isn't specified by the user, then use either the type
 599 * specified in /etc/fstab, or "auto".
 600 */
 601static void fsck_device(struct fs_info *fs /*, int interactive */)
 602{
 603        const char *type;
 604
 605        if (strcmp(fs->type, "auto") != 0) {
 606                type = fs->type;
 607                if (G.verbose > 2)
 608                        printf("using filesystem type '%s' %s\n",
 609                                        type, "from fstab");
 610        } else if (G.fstype
 611         && (G.fstype[0] != 'n' || G.fstype[1] != 'o') /* != "no" */
 612         && !is_prefixed_with(G.fstype, "opts=")
 613         && !is_prefixed_with(G.fstype, "loop")
 614         && !strchr(G.fstype, ',')
 615        ) {
 616                type = G.fstype;
 617                if (G.verbose > 2)
 618                        printf("using filesystem type '%s' %s\n",
 619                                        type, "from -t");
 620        } else {
 621                type = "auto";
 622                if (G.verbose > 2)
 623                        printf("using filesystem type '%s' %s\n",
 624                                        type, "(default)");
 625        }
 626
 627        G.num_running++;
 628        execute(type, fs->device, fs->mountpt /*, interactive */);
 629}
 630
 631/*
 632 * Returns TRUE if a partition on the same disk is already being
 633 * checked.
 634 */
 635static int device_already_active(char *device)
 636{
 637        struct fsck_instance *inst;
 638        char *base;
 639
 640        if (G.force_all_parallel)
 641                return 0;
 642
 643#ifdef BASE_MD
 644        /* Don't check a soft raid disk with any other disk */
 645        if (G.instance_list
 646         && (is_prefixed_with(G.instance_list->device, BASE_MD)
 647             || is_prefixed_with(device, BASE_MD))
 648        ) {
 649                return 1;
 650        }
 651#endif
 652
 653        base = base_device(device);
 654        /*
 655         * If we don't know the base device, assume that the device is
 656         * already active if there are any fsck instances running.
 657         */
 658        if (!base)
 659                return (G.instance_list != NULL);
 660
 661        for (inst = G.instance_list; inst; inst = inst->next) {
 662                if (!inst->base_device || strcmp(base, inst->base_device) == 0) {
 663                        free(base);
 664                        return 1;
 665                }
 666        }
 667
 668        free(base);
 669        return 0;
 670}
 671
 672/*
 673 * This function returns true if a particular option appears in a
 674 * comma-delimited options list
 675 */
 676static int opt_in_list(char *opt, char *optlist)
 677{
 678        char *s;
 679        int len;
 680
 681        if (!optlist)
 682                return 0;
 683
 684        len = strlen(opt);
 685        s = optlist - 1;
 686        while (1) {
 687                s = strstr(s + 1, opt);
 688                if (!s)
 689                        return 0;
 690                /* neither "opt.." nor "xxx,opt.."? */
 691                if (s != optlist && s[-1] != ',')
 692                        continue;
 693                /* neither "..opt" nor "..opt,xxx"? */
 694                if (s[len] != '\0' && s[len] != ',')
 695                        continue;
 696                return 1;
 697        }
 698}
 699
 700/* See if the filesystem matches the criteria given by the -t option */
 701static int fs_match(struct fs_info *fs)
 702{
 703        int n, ret, checked_type;
 704        char *cp;
 705
 706        if (!G.fs_type_list)
 707                return 1;
 708
 709        ret = 0;
 710        checked_type = 0;
 711        n = 0;
 712        while (1) {
 713                cp = G.fs_type_list[n];
 714                if (!cp)
 715                        break;
 716                switch (G.fs_type_flag[n]) {
 717                case FS_TYPE_FLAG_NORMAL:
 718                        checked_type++;
 719                        if (strcmp(cp, fs->type) == 0)
 720                                ret = 1;
 721                        break;
 722                case FS_TYPE_FLAG_NEGOPT:
 723                        if (opt_in_list(cp, fs->opts))
 724                                return 0;
 725                        break;
 726                case FS_TYPE_FLAG_OPT:
 727                        if (!opt_in_list(cp, fs->opts))
 728                                return 0;
 729                        break;
 730                }
 731                n++;
 732        }
 733        if (checked_type == 0)
 734                return 1;
 735
 736        return (G.fs_type_negated ? !ret : ret);
 737}
 738
 739/* Check if we should ignore this filesystem. */
 740static int ignore(struct fs_info *fs)
 741{
 742        /*
 743         * If the pass number is 0, ignore it.
 744         */
 745        if (fs->passno == 0)
 746                return 1;
 747
 748        /*
 749         * If a specific fstype is specified, and it doesn't match,
 750         * ignore it.
 751         */
 752        if (!fs_match(fs))
 753                return 1;
 754
 755        /* Are we ignoring this type? */
 756        if (index_in_strings(ignored_types, fs->type) >= 0)
 757                return 1;
 758
 759        /* We can and want to check this file system type. */
 760        return 0;
 761}
 762
 763/* Check all file systems, using the /etc/fstab table. */
 764static int check_all(void)
 765{
 766        struct fs_info *fs;
 767        int status = EXIT_OK;
 768        smallint not_done_yet;
 769        smallint pass_done;
 770        int passno;
 771
 772        if (G.verbose)
 773                puts("Checking all filesystems");
 774
 775        /*
 776         * Do an initial scan over the filesystem; mark filesystems
 777         * which should be ignored as done, and resolve any "auto"
 778         * filesystem types (done as a side-effect of calling ignore()).
 779         */
 780        for (fs = G.filesys_info; fs; fs = fs->next)
 781                if (ignore(fs))
 782                        fs->flags |= FLAG_DONE;
 783
 784        /*
 785         * Find and check the root filesystem.
 786         */
 787        if (!G.parallel_root) {
 788                for (fs = G.filesys_info; fs; fs = fs->next) {
 789                        if (LONE_CHAR(fs->mountpt, '/')) {
 790                                if (!G.skip_root && !ignore(fs)) {
 791                                        fsck_device(fs /*, 1*/);
 792                                        status |= wait_many(FLAG_WAIT_ALL);
 793                                        if (status > EXIT_NONDESTRUCT)
 794                                                return status;
 795                                }
 796                                fs->flags |= FLAG_DONE;
 797                                break;
 798                        }
 799                }
 800        }
 801        /*
 802         * This is for the bone-headed user who has root
 803         * filesystem listed twice.
 804         * "Skip root" will skip _all_ root entries.
 805         */
 806        if (G.skip_root)
 807                for (fs = G.filesys_info; fs; fs = fs->next)
 808                        if (LONE_CHAR(fs->mountpt, '/'))
 809                                fs->flags |= FLAG_DONE;
 810
 811        not_done_yet = 1;
 812        passno = 1;
 813        while (not_done_yet) {
 814                not_done_yet = 0;
 815                pass_done = 1;
 816
 817                for (fs = G.filesys_info; fs; fs = fs->next) {
 818                        if (bb_got_signal)
 819                                break;
 820                        if (fs->flags & FLAG_DONE)
 821                                continue;
 822                        /*
 823                         * If the filesystem's pass number is higher
 824                         * than the current pass number, then we didn't
 825                         * do it yet.
 826                         */
 827                        if (fs->passno > passno) {
 828                                not_done_yet = 1;
 829                                continue;
 830                        }
 831                        /*
 832                         * If a filesystem on a particular device has
 833                         * already been spawned, then we need to defer
 834                         * this to another pass.
 835                         */
 836                        if (device_already_active(fs->device)) {
 837                                pass_done = 0;
 838                                continue;
 839                        }
 840                        /*
 841                         * Spawn off the fsck process
 842                         */
 843                        fsck_device(fs /*, G.serialize*/);
 844                        fs->flags |= FLAG_DONE;
 845
 846                        /*
 847                         * Only do one filesystem at a time, or if we
 848                         * have a limit on the number of fsck's extant
 849                         * at one time, apply that limit.
 850                         */
 851                        if (G.serialize
 852                         || (G.num_running >= G.max_running)
 853                        ) {
 854                                pass_done = 0;
 855                                break;
 856                        }
 857                }
 858                if (bb_got_signal)
 859                        break;
 860                if (G.verbose > 1)
 861                        printf("--waiting-- (pass %d)\n", passno);
 862                status |= wait_many(pass_done ? FLAG_WAIT_ALL :
 863                                FLAG_WAIT_ATLEAST_ONE);
 864                if (pass_done) {
 865                        if (G.verbose > 1)
 866                                puts("----------------------------------");
 867                        passno++;
 868                } else
 869                        not_done_yet = 1;
 870        }
 871        kill_all_if_got_signal();
 872        status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
 873        return status;
 874}
 875
 876/*
 877 * Deal with the fsck -t argument.
 878 * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"!
 879 * Why here we require "-t novfat,nonfs" ??
 880 */
 881static void compile_fs_type(char *fs_type)
 882{
 883        char *s;
 884        int num = 2;
 885        smallint negate;
 886
 887        s = fs_type;
 888        while ((s = strchr(s, ','))) {
 889                num++;
 890                s++;
 891        }
 892
 893        G.fs_type_list = xzalloc(num * sizeof(G.fs_type_list[0]));
 894        G.fs_type_flag = xzalloc(num * sizeof(G.fs_type_flag[0]));
 895        G.fs_type_negated = -1; /* not yet known is it negated or not */
 896
 897        num = 0;
 898        s = fs_type;
 899        while (1) {
 900                char *comma;
 901
 902                negate = 0;
 903                if (s[0] == 'n' && s[1] == 'o') { /* "no.." */
 904                        s += 2;
 905                        negate = 1;
 906                } else if (s[0] == '!') {
 907                        s++;
 908                        negate = 1;
 909                }
 910
 911                if (strcmp(s, "loop") == 0)
 912                        /* loop is really short-hand for opts=loop */
 913                        goto loop_special_case;
 914                if (is_prefixed_with(s, "opts=")) {
 915                        s += 5;
 916 loop_special_case:
 917                        G.fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT;
 918                } else {
 919                        if (G.fs_type_negated == -1)
 920                                G.fs_type_negated = negate;
 921                        if (G.fs_type_negated != negate)
 922                                bb_simple_error_msg_and_die(
 923"either all or none of the filesystem types passed to -t must be prefixed "
 924"with 'no' or '!'");
 925                }
 926                comma = strchrnul(s, ',');
 927                G.fs_type_list[num++] = xstrndup(s, comma-s);
 928                if (*comma == '\0')
 929                        break;
 930                s = comma + 1;
 931        }
 932}
 933
 934static char **new_args(void)
 935{
 936        G.args = xrealloc_vector(G.args, 2, G.num_args);
 937        return &G.args[G.num_args++];
 938}
 939
 940int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 941int fsck_main(int argc UNUSED_PARAM, char **argv)
 942{
 943        int i, status;
 944        /*int interactive;*/
 945        struct fs_info *fs;
 946        const char *fstab;
 947        char *tmp;
 948        char **devices;
 949        int num_devices;
 950        smallint opts_for_fsck;
 951        smallint doall;
 952        smallint notitle;
 953
 954        INIT_G();
 955
 956        /* we want wait() to be interruptible */
 957        signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
 958        signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo);
 959
 960        setbuf(stdout, NULL);
 961
 962        opts_for_fsck = doall = notitle = 0;
 963        devices = NULL;
 964        num_devices = 0;
 965        new_args(); /* G.args[0] = NULL, will be replaced by fsck.<type> */
 966        /* G.instance_list = NULL; - in bss, so already zeroed */
 967
 968        while (*++argv) {
 969                int j;
 970                int optpos;
 971                char *options;
 972                char *arg = *argv;
 973
 974                /* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */
 975                if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
 976// FIXME: must check that arg is a blkdev, or resolve
 977// "/path", "UUID=xxx" or "LABEL=xxx" into block device name
 978// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties)
 979                        devices = xrealloc_vector(devices, 2, num_devices);
 980                        devices[num_devices++] = arg;
 981                        continue;
 982                }
 983
 984                if (arg[0] != '-' || opts_for_fsck) {
 985                        *new_args() = arg;
 986                        continue;
 987                }
 988
 989                if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */
 990                        opts_for_fsck = 1;
 991                        continue;
 992                }
 993
 994                optpos = 0;
 995                options = NULL;
 996                for (j = 1; arg[j]; j++) {
 997                        switch (arg[j]) {
 998                        case 'A':
 999                                doall = 1;
1000                                break;
1001#if DO_PROGRESS_INDICATOR
1002                        case 'C':
1003                                progress = 1;
1004                                if (arg[++j]) { /* -Cn */
1005                                        progress_fd = xatoi_positive(&arg[j]);
1006                                        goto next_arg;
1007                                }
1008                                /* -C n */
1009                                if (!*++argv)
1010                                        bb_show_usage();
1011                                progress_fd = xatoi_positive(*argv);
1012                                goto next_arg;
1013#endif
1014                        case 'V':
1015                                G.verbose++;
1016                                break;
1017                        case 'N':
1018                                G.noexecute = 1;
1019                                break;
1020                        case 'R':
1021                                G.skip_root = 1;
1022                                break;
1023                        case 'T':
1024                                notitle = 1;
1025                                break;
1026/*                      case 'M':
1027                                like_mount = 1;
1028                                break; */
1029                        case 'P':
1030                                G.parallel_root = 1;
1031                                break;
1032                        case 's':
1033                                G.serialize = 1;
1034                                break;
1035                        case 't':
1036                                if (G.fstype)
1037                                        bb_show_usage();
1038                                if (arg[++j])
1039                                        tmp = &arg[j];
1040                                else if (*++argv)
1041                                        tmp = *argv;
1042                                else
1043                                        bb_show_usage();
1044                                G.fstype = xstrdup(tmp);
1045                                compile_fs_type(G.fstype);
1046                                goto next_arg;
1047                        case '?':
1048                                bb_show_usage();
1049                                break;
1050                        default:
1051                                optpos++;
1052                                /* one extra for '\0' */
1053                                options = xrealloc(options, optpos + 2);
1054                                options[optpos] = arg[j];
1055                                break;
1056                        }
1057                }
1058 next_arg:
1059                if (optpos) {
1060                        options[0] = '-';
1061                        options[optpos + 1] = '\0';
1062                        *new_args() = options;
1063                }
1064        }
1065        if (getenv("FSCK_FORCE_ALL_PARALLEL"))
1066                G.force_all_parallel = 1;
1067        tmp = getenv("FSCK_MAX_INST");
1068        G.max_running = INT_MAX;
1069        if (tmp)
1070                G.max_running = xatoi(tmp);
1071        new_args(); /* G.args[G.num_args - 2] will be replaced by <device> */
1072        new_args(); /* G.args[G.num_args - 1] is the last, NULL element */
1073
1074        if (!notitle)
1075                puts("fsck (busybox "BB_VER")");
1076
1077        /* Even plain "fsck /dev/hda1" needs fstab to get fs type,
1078         * so we are scanning it anyway */
1079        fstab = getenv("FSTAB_FILE");
1080        if (!fstab)
1081                fstab = "/etc/fstab";
1082        load_fs_info(fstab);
1083
1084        /*interactive = (num_devices == 1) | G.serialize;*/
1085
1086        if (num_devices == 0)
1087                /*interactive =*/ G.serialize = doall = 1;
1088        if (doall)
1089                return check_all();
1090
1091        status = 0;
1092        for (i = 0; i < num_devices; i++) {
1093                if (bb_got_signal) {
1094                        kill_all_if_got_signal();
1095                        break;
1096                }
1097
1098                fs = lookup(devices[i]);
1099                if (!fs)
1100                        fs = create_fs_device(devices[i], "", "auto", NULL, -1);
1101                fsck_device(fs /*, interactive */);
1102
1103                if (G.serialize
1104                 || (G.num_running >= G.max_running)
1105                ) {
1106                        int exit_status = wait_one(0);
1107                        if (exit_status >= 0)
1108                                status |= exit_status;
1109                        if (G.verbose > 1)
1110                                puts("----------------------------------");
1111                }
1112        }
1113        status |= wait_many(FLAG_WAIT_ALL);
1114        return status;
1115}
1116