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"
  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 sig;
 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_error_msg("wait: no more children");
 435                                return -1;
 436                        }
 437                        bb_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        status = WEXITSTATUS(status);
 452        if (WIFSIGNALED(status)) {
 453                sig = WTERMSIG(status);
 454                status = EXIT_UNCORRECTED;
 455                if (sig != SIGINT) {
 456                        printf("Warning: %s %s terminated "
 457                                "by signal %d\n",
 458                                inst->prog, inst->device, sig);
 459                        status = EXIT_ERROR;
 460                }
 461        }
 462
 463#if DO_PROGRESS_INDICATOR
 464        if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) {
 465                struct fsck_instance *inst2;
 466                for (inst2 = G.instance_list; inst2; inst2 = inst2->next) {
 467                        if (inst2->flags & FLAG_DONE)
 468                                continue;
 469                        if (strcmp(inst2->type, "ext2") != 0
 470                         && strcmp(inst2->type, "ext3") != 0
 471                        ) {
 472                                continue;
 473                        }
 474                        /* ext[23], we will send USR1
 475                         * (request to start displaying progress bar)
 476                         *
 477                         * If we've just started the fsck, wait a tiny
 478                         * bit before sending the kill, to give it
 479                         * time to set up the signal handler
 480                         */
 481                        if (inst2->start_time >= time(NULL) - 1)
 482                                sleep(1);
 483                        kill(inst2->pid, SIGUSR1);
 484                        inst2->flags |= FLAG_PROGRESS;
 485                        break;
 486                }
 487        }
 488#endif
 489
 490        if (prev)
 491                prev->next = inst->next;
 492        else
 493                G.instance_list = inst->next;
 494        if (G.verbose > 1)
 495                printf("Finished with %s (exit status %d)\n",
 496                        inst->device, status);
 497        G.num_running--;
 498        free_instance(inst);
 499
 500        return status;
 501}
 502
 503/*
 504 * Wait until all executing child processes have exited; return the
 505 * logical OR of all of their exit code values.
 506 */
 507#define FLAG_WAIT_ALL           0
 508#define FLAG_WAIT_ATLEAST_ONE   WNOHANG
 509static int wait_many(int flags)
 510{
 511        int exit_status;
 512        int global_status = 0;
 513        int wait_flags = 0;
 514
 515        while ((exit_status = wait_one(wait_flags)) != -1) {
 516                global_status |= exit_status;
 517                wait_flags |= flags;
 518        }
 519        return global_status;
 520}
 521
 522/*
 523 * Execute a particular fsck program, and link it into the list of
 524 * child processes we are waiting for.
 525 */
 526static void execute(const char *type, const char *device,
 527                const char *mntpt /*, int interactive */)
 528{
 529        int i;
 530        struct fsck_instance *inst;
 531        pid_t pid;
 532
 533        G.args[0] = xasprintf("fsck.%s", type);
 534
 535#if DO_PROGRESS_INDICATOR
 536        if (progress && !progress_active()) {
 537                if (strcmp(type, "ext2") == 0
 538                 || strcmp(type, "ext3") == 0
 539                ) {
 540                        G.args[XXX] = xasprintf("-C%d", progress_fd); /* 1 */
 541                        inst->flags |= FLAG_PROGRESS;
 542                }
 543        }
 544#endif
 545
 546        G.args[G.num_args - 2] = (char*)device;
 547        /* G.args[G.num_args - 1] = NULL; - already is */
 548
 549        if (G.verbose || G.noexecute) {
 550                printf("[%s (%d) -- %s]", G.args[0], G.num_running,
 551                                        mntpt ? mntpt : device);
 552                for (i = 0; G.args[i]; i++)
 553                        printf(" %s", G.args[i]);
 554                bb_putchar('\n');
 555        }
 556
 557        /* Fork and execute the correct program. */
 558        pid = -1;
 559        if (!G.noexecute) {
 560                pid = spawn(G.args);
 561                if (pid < 0)
 562                        bb_simple_perror_msg(G.args[0]);
 563        }
 564
 565#if DO_PROGRESS_INDICATOR
 566        free(G.args[XXX]);
 567#endif
 568
 569        /* No child, so don't record an instance */
 570        if (pid <= 0) {
 571                free(G.args[0]);
 572                return;
 573        }
 574
 575        inst = xzalloc(sizeof(*inst));
 576        inst->pid = pid;
 577        inst->prog = G.args[0];
 578        inst->device = xstrdup(device);
 579        inst->base_device = base_device(device);
 580#if DO_PROGRESS_INDICATOR
 581        inst->start_time = time(NULL);
 582#endif
 583
 584        /* Add to the list of running fsck's.
 585         * (was adding to the end, but adding to the front is simpler...) */
 586        inst->next = G.instance_list;
 587        G.instance_list = inst;
 588}
 589
 590/*
 591 * Run the fsck program on a particular device
 592 *
 593 * If the type is specified using -t, and it isn't prefixed with "no"
 594 * (as in "noext2") and only one filesystem type is specified, then
 595 * use that type regardless of what is specified in /etc/fstab.
 596 *
 597 * If the type isn't specified by the user, then use either the type
 598 * specified in /etc/fstab, or "auto".
 599 */
 600static void fsck_device(struct fs_info *fs /*, int interactive */)
 601{
 602        const char *type;
 603
 604        if (strcmp(fs->type, "auto") != 0) {
 605                type = fs->type;
 606                if (G.verbose > 2)
 607                        printf("using filesystem type '%s' %s\n",
 608                                        type, "from fstab");
 609        } else if (G.fstype
 610         && (G.fstype[0] != 'n' || G.fstype[1] != 'o') /* != "no" */
 611         && !is_prefixed_with(G.fstype, "opts=")
 612         && !is_prefixed_with(G.fstype, "loop")
 613         && !strchr(G.fstype, ',')
 614        ) {
 615                type = G.fstype;
 616                if (G.verbose > 2)
 617                        printf("using filesystem type '%s' %s\n",
 618                                        type, "from -t");
 619        } else {
 620                type = "auto";
 621                if (G.verbose > 2)
 622                        printf("using filesystem type '%s' %s\n",
 623                                        type, "(default)");
 624        }
 625
 626        G.num_running++;
 627        execute(type, fs->device, fs->mountpt /*, interactive */);
 628}
 629
 630/*
 631 * Returns TRUE if a partition on the same disk is already being
 632 * checked.
 633 */
 634static int device_already_active(char *device)
 635{
 636        struct fsck_instance *inst;
 637        char *base;
 638
 639        if (G.force_all_parallel)
 640                return 0;
 641
 642#ifdef BASE_MD
 643        /* Don't check a soft raid disk with any other disk */
 644        if (G.instance_list
 645         && (is_prefixed_with(G.instance_list->device, BASE_MD)
 646             || is_prefixed_with(device, BASE_MD))
 647        ) {
 648                return 1;
 649        }
 650#endif
 651
 652        base = base_device(device);
 653        /*
 654         * If we don't know the base device, assume that the device is
 655         * already active if there are any fsck instances running.
 656         */
 657        if (!base)
 658                return (G.instance_list != NULL);
 659
 660        for (inst = G.instance_list; inst; inst = inst->next) {
 661                if (!inst->base_device || !strcmp(base, inst->base_device)) {
 662                        free(base);
 663                        return 1;
 664                }
 665        }
 666
 667        free(base);
 668        return 0;
 669}
 670
 671/*
 672 * This function returns true if a particular option appears in a
 673 * comma-delimited options list
 674 */
 675static int opt_in_list(char *opt, char *optlist)
 676{
 677        char *s;
 678        int len;
 679
 680        if (!optlist)
 681                return 0;
 682
 683        len = strlen(opt);
 684        s = optlist - 1;
 685        while (1) {
 686                s = strstr(s + 1, opt);
 687                if (!s)
 688                        return 0;
 689                /* neither "opt.." nor "xxx,opt.."? */
 690                if (s != optlist && s[-1] != ',')
 691                        continue;
 692                /* neither "..opt" nor "..opt,xxx"? */
 693                if (s[len] != '\0' && s[len] != ',')
 694                        continue;
 695                return 1;
 696        }
 697}
 698
 699/* See if the filesystem matches the criteria given by the -t option */
 700static int fs_match(struct fs_info *fs)
 701{
 702        int n, ret, checked_type;
 703        char *cp;
 704
 705        if (!G.fs_type_list)
 706                return 1;
 707
 708        ret = 0;
 709        checked_type = 0;
 710        n = 0;
 711        while (1) {
 712                cp = G.fs_type_list[n];
 713                if (!cp)
 714                        break;
 715                switch (G.fs_type_flag[n]) {
 716                case FS_TYPE_FLAG_NORMAL:
 717                        checked_type++;
 718                        if (strcmp(cp, fs->type) == 0)
 719                                ret = 1;
 720                        break;
 721                case FS_TYPE_FLAG_NEGOPT:
 722                        if (opt_in_list(cp, fs->opts))
 723                                return 0;
 724                        break;
 725                case FS_TYPE_FLAG_OPT:
 726                        if (!opt_in_list(cp, fs->opts))
 727                                return 0;
 728                        break;
 729                }
 730                n++;
 731        }
 732        if (checked_type == 0)
 733                return 1;
 734
 735        return (G.fs_type_negated ? !ret : ret);
 736}
 737
 738/* Check if we should ignore this filesystem. */
 739static int ignore(struct fs_info *fs)
 740{
 741        /*
 742         * If the pass number is 0, ignore it.
 743         */
 744        if (fs->passno == 0)
 745                return 1;
 746
 747        /*
 748         * If a specific fstype is specified, and it doesn't match,
 749         * ignore it.
 750         */
 751        if (!fs_match(fs))
 752                return 1;
 753
 754        /* Are we ignoring this type? */
 755        if (index_in_strings(ignored_types, fs->type) >= 0)
 756                return 1;
 757
 758        /* We can and want to check this file system type. */
 759        return 0;
 760}
 761
 762/* Check all file systems, using the /etc/fstab table. */
 763static int check_all(void)
 764{
 765        struct fs_info *fs;
 766        int status = EXIT_OK;
 767        smallint not_done_yet;
 768        smallint pass_done;
 769        int passno;
 770
 771        if (G.verbose)
 772                puts("Checking all filesystems");
 773
 774        /*
 775         * Do an initial scan over the filesystem; mark filesystems
 776         * which should be ignored as done, and resolve any "auto"
 777         * filesystem types (done as a side-effect of calling ignore()).
 778         */
 779        for (fs = G.filesys_info; fs; fs = fs->next)
 780                if (ignore(fs))
 781                        fs->flags |= FLAG_DONE;
 782
 783        /*
 784         * Find and check the root filesystem.
 785         */
 786        if (!G.parallel_root) {
 787                for (fs = G.filesys_info; fs; fs = fs->next) {
 788                        if (LONE_CHAR(fs->mountpt, '/')) {
 789                                if (!G.skip_root && !ignore(fs)) {
 790                                        fsck_device(fs /*, 1*/);
 791                                        status |= wait_many(FLAG_WAIT_ALL);
 792                                        if (status > EXIT_NONDESTRUCT)
 793                                                return status;
 794                                }
 795                                fs->flags |= FLAG_DONE;
 796                                break;
 797                        }
 798                }
 799        }
 800        /*
 801         * This is for the bone-headed user who has root
 802         * filesystem listed twice.
 803         * "Skip root" will skip _all_ root entries.
 804         */
 805        if (G.skip_root)
 806                for (fs = G.filesys_info; fs; fs = fs->next)
 807                        if (LONE_CHAR(fs->mountpt, '/'))
 808                                fs->flags |= FLAG_DONE;
 809
 810        not_done_yet = 1;
 811        passno = 1;
 812        while (not_done_yet) {
 813                not_done_yet = 0;
 814                pass_done = 1;
 815
 816                for (fs = G.filesys_info; fs; fs = fs->next) {
 817                        if (bb_got_signal)
 818                                break;
 819                        if (fs->flags & FLAG_DONE)
 820                                continue;
 821                        /*
 822                         * If the filesystem's pass number is higher
 823                         * than the current pass number, then we didn't
 824                         * do it yet.
 825                         */
 826                        if (fs->passno > passno) {
 827                                not_done_yet = 1;
 828                                continue;
 829                        }
 830                        /*
 831                         * If a filesystem on a particular device has
 832                         * already been spawned, then we need to defer
 833                         * this to another pass.
 834                         */
 835                        if (device_already_active(fs->device)) {
 836                                pass_done = 0;
 837                                continue;
 838                        }
 839                        /*
 840                         * Spawn off the fsck process
 841                         */
 842                        fsck_device(fs /*, G.serialize*/);
 843                        fs->flags |= FLAG_DONE;
 844
 845                        /*
 846                         * Only do one filesystem at a time, or if we
 847                         * have a limit on the number of fsck's extant
 848                         * at one time, apply that limit.
 849                         */
 850                        if (G.serialize
 851                         || (G.num_running >= G.max_running)
 852                        ) {
 853                                pass_done = 0;
 854                                break;
 855                        }
 856                }
 857                if (bb_got_signal)
 858                        break;
 859                if (G.verbose > 1)
 860                        printf("--waiting-- (pass %d)\n", passno);
 861                status |= wait_many(pass_done ? FLAG_WAIT_ALL :
 862                                FLAG_WAIT_ATLEAST_ONE);
 863                if (pass_done) {
 864                        if (G.verbose > 1)
 865                                puts("----------------------------------");
 866                        passno++;
 867                } else
 868                        not_done_yet = 1;
 869        }
 870        kill_all_if_got_signal();
 871        status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
 872        return status;
 873}
 874
 875/*
 876 * Deal with the fsck -t argument.
 877 * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"!
 878 * Why here we require "-t novfat,nonfs" ??
 879 */
 880static void compile_fs_type(char *fs_type)
 881{
 882        char *s;
 883        int num = 2;
 884        smallint negate;
 885
 886        s = fs_type;
 887        while ((s = strchr(s, ','))) {
 888                num++;
 889                s++;
 890        }
 891
 892        G.fs_type_list = xzalloc(num * sizeof(G.fs_type_list[0]));
 893        G.fs_type_flag = xzalloc(num * sizeof(G.fs_type_flag[0]));
 894        G.fs_type_negated = -1; /* not yet known is it negated or not */
 895
 896        num = 0;
 897        s = fs_type;
 898        while (1) {
 899                char *comma;
 900
 901                negate = 0;
 902                if (s[0] == 'n' && s[1] == 'o') { /* "no.." */
 903                        s += 2;
 904                        negate = 1;
 905                } else if (s[0] == '!') {
 906                        s++;
 907                        negate = 1;
 908                }
 909
 910                if (strcmp(s, "loop") == 0)
 911                        /* loop is really short-hand for opts=loop */
 912                        goto loop_special_case;
 913                if (is_prefixed_with(s, "opts=")) {
 914                        s += 5;
 915 loop_special_case:
 916                        G.fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT;
 917                } else {
 918                        if (G.fs_type_negated == -1)
 919                                G.fs_type_negated = negate;
 920                        if (G.fs_type_negated != negate)
 921                                bb_error_msg_and_die(
 922"either all or none of the filesystem types passed to -t must be prefixed "
 923"with 'no' or '!'");
 924                }
 925                comma = strchrnul(s, ',');
 926                G.fs_type_list[num++] = xstrndup(s, comma-s);
 927                if (*comma == '\0')
 928                        break;
 929                s = comma + 1;
 930        }
 931}
 932
 933static char **new_args(void)
 934{
 935        G.args = xrealloc_vector(G.args, 2, G.num_args);
 936        return &G.args[G.num_args++];
 937}
 938
 939int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 940int fsck_main(int argc UNUSED_PARAM, char **argv)
 941{
 942        int i, status;
 943        /*int interactive;*/
 944        struct fs_info *fs;
 945        const char *fstab;
 946        char *tmp;
 947        char **devices;
 948        int num_devices;
 949        smallint opts_for_fsck;
 950        smallint doall;
 951        smallint notitle;
 952
 953        INIT_G();
 954
 955        /* we want wait() to be interruptible */
 956        signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
 957        signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo);
 958
 959        setbuf(stdout, NULL);
 960
 961        opts_for_fsck = doall = notitle = 0;
 962        devices = NULL;
 963        num_devices = 0;
 964        new_args(); /* G.args[0] = NULL, will be replaced by fsck.<type> */
 965        /* G.instance_list = NULL; - in bss, so already zeroed */
 966
 967        while (*++argv) {
 968                int j;
 969                int optpos;
 970                char *options;
 971                char *arg = *argv;
 972
 973                /* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */
 974                if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
 975// FIXME: must check that arg is a blkdev, or resolve
 976// "/path", "UUID=xxx" or "LABEL=xxx" into block device name
 977// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties)
 978                        devices = xrealloc_vector(devices, 2, num_devices);
 979                        devices[num_devices++] = arg;
 980                        continue;
 981                }
 982
 983                if (arg[0] != '-' || opts_for_fsck) {
 984                        *new_args() = arg;
 985                        continue;
 986                }
 987
 988                if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */
 989                        opts_for_fsck = 1;
 990                        continue;
 991                }
 992
 993                optpos = 0;
 994                options = NULL;
 995                for (j = 1; arg[j]; j++) {
 996                        switch (arg[j]) {
 997                        case 'A':
 998                                doall = 1;
 999                                break;
1000#if DO_PROGRESS_INDICATOR
1001                        case 'C':
1002                                progress = 1;
1003                                if (arg[++j]) { /* -Cn */
1004                                        progress_fd = xatoi_positive(&arg[j]);
1005                                        goto next_arg;
1006                                }
1007                                /* -C n */
1008                                if (!*++argv)
1009                                        bb_show_usage();
1010                                progress_fd = xatoi_positive(*argv);
1011                                goto next_arg;
1012#endif
1013                        case 'V':
1014                                G.verbose++;
1015                                break;
1016                        case 'N':
1017                                G.noexecute = 1;
1018                                break;
1019                        case 'R':
1020                                G.skip_root = 1;
1021                                break;
1022                        case 'T':
1023                                notitle = 1;
1024                                break;
1025/*                      case 'M':
1026                                like_mount = 1;
1027                                break; */
1028                        case 'P':
1029                                G.parallel_root = 1;
1030                                break;
1031                        case 's':
1032                                G.serialize = 1;
1033                                break;
1034                        case 't':
1035                                if (G.fstype)
1036                                        bb_show_usage();
1037                                if (arg[++j])
1038                                        tmp = &arg[j];
1039                                else if (*++argv)
1040                                        tmp = *argv;
1041                                else
1042                                        bb_show_usage();
1043                                G.fstype = xstrdup(tmp);
1044                                compile_fs_type(G.fstype);
1045                                goto next_arg;
1046                        case '?':
1047                                bb_show_usage();
1048                                break;
1049                        default:
1050                                optpos++;
1051                                /* one extra for '\0' */
1052                                options = xrealloc(options, optpos + 2);
1053                                options[optpos] = arg[j];
1054                                break;
1055                        }
1056                }
1057 next_arg:
1058                if (optpos) {
1059                        options[0] = '-';
1060                        options[optpos + 1] = '\0';
1061                        *new_args() = options;
1062                }
1063        }
1064        if (getenv("FSCK_FORCE_ALL_PARALLEL"))
1065                G.force_all_parallel = 1;
1066        tmp = getenv("FSCK_MAX_INST");
1067        G.max_running = INT_MAX;
1068        if (tmp)
1069                G.max_running = xatoi(tmp);
1070        new_args(); /* G.args[G.num_args - 2] will be replaced by <device> */
1071        new_args(); /* G.args[G.num_args - 1] is the last, NULL element */
1072
1073        if (!notitle)
1074                puts("fsck (busybox "BB_VER", "BB_BT")");
1075
1076        /* Even plain "fsck /dev/hda1" needs fstab to get fs type,
1077         * so we are scanning it anyway */
1078        fstab = getenv("FSTAB_FILE");
1079        if (!fstab)
1080                fstab = "/etc/fstab";
1081        load_fs_info(fstab);
1082
1083        /*interactive = (num_devices == 1) | G.serialize;*/
1084
1085        if (num_devices == 0)
1086                /*interactive =*/ G.serialize = doall = 1;
1087        if (doall)
1088                return check_all();
1089
1090        status = 0;
1091        for (i = 0; i < num_devices; i++) {
1092                if (bb_got_signal) {
1093                        kill_all_if_got_signal();
1094                        break;
1095                }
1096
1097                fs = lookup(devices[i]);
1098                if (!fs)
1099                        fs = create_fs_device(devices[i], "", "auto", NULL, -1);
1100                fsck_device(fs /*, interactive */);
1101
1102                if (G.serialize
1103                 || (G.num_running >= G.max_running)
1104                ) {
1105                        int exit_status = wait_one(0);
1106                        if (exit_status >= 0)
1107                                status |= exit_status;
1108                        if (G.verbose > 1)
1109                                puts("----------------------------------");
1110                }
1111        }
1112        status |= wait_many(FLAG_WAIT_ALL);
1113        return status;
1114}
1115