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 source tree.
  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        strcpy_and_process_escape_sequences(word, word);
 353}
 354
 355static void free_instance(struct fsck_instance *i)
 356{
 357        if (i->prog)
 358                free(i->prog);
 359        if (i->device)
 360                free(i->device);
 361        if (i->base_device)
 362                free(i->base_device);
 363        free(i);
 364}
 365
 366static struct fs_info *create_fs_device(const char *device, const char *mntpnt,
 367                                        const char *type, const char *opts,
 368                                        int freq, int passno)
 369{
 370        struct fs_info *fs;
 371
 372        fs = xmalloc(sizeof(struct fs_info));
 373
 374        fs->device = string_copy(device);
 375        fs->mountpt = string_copy(mntpnt);
 376        fs->type = string_copy(type);
 377        fs->opts = string_copy(opts ? opts : "");
 378        fs->freq = freq;
 379        fs->passno = passno;
 380        fs->flags = 0;
 381        fs->next = NULL;
 382
 383        if (!filesys_info)
 384                filesys_info = fs;
 385        else
 386                filesys_last->next = fs;
 387        filesys_last = fs;
 388
 389        return fs;
 390}
 391
 392
 393
 394static int parse_fstab_line(char *line, struct fs_info **ret_fs)
 395{
 396        char    *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
 397        struct fs_info *fs;
 398
 399        *ret_fs = 0;
 400        strip_line(line);
 401        if ((cp = strchr(line, '#')))
 402                *cp = 0;        /* Ignore everything after the comment char */
 403        cp = line;
 404
 405        device = parse_word(&cp);
 406        mntpnt = parse_word(&cp);
 407        type = parse_word(&cp);
 408        opts = parse_word(&cp);
 409        freq = parse_word(&cp);
 410        passno = parse_word(&cp);
 411
 412        if (!device)
 413                return 0;       /* Allow blank lines */
 414
 415        if (!mntpnt || !type)
 416                return -1;
 417
 418        parse_escape(device);
 419        parse_escape(mntpnt);
 420        parse_escape(type);
 421        parse_escape(opts);
 422        parse_escape(freq);
 423        parse_escape(passno);
 424
 425        dev = blkid_get_devname(cache, device, NULL);
 426        if (dev)
 427                device = dev;
 428
 429        if (strchr(type, ','))
 430                type = 0;
 431
 432        fs = create_fs_device(device, mntpnt, type ? type : "auto", opts,
 433                              freq ? atoi(freq) : -1,
 434                              passno ? atoi(passno) : -1);
 435        if (dev)
 436                free(dev);
 437
 438        if (!fs)
 439                return -1;
 440        *ret_fs = fs;
 441        return 0;
 442}
 443
 444static void interpret_type(struct fs_info *fs)
 445{
 446        char    *t;
 447
 448        if (strcmp(fs->type, "auto") != 0)
 449                return;
 450        t = blkid_get_tag_value(cache, "TYPE", fs->device);
 451        if (t) {
 452                free(fs->type);
 453                fs->type = t;
 454        }
 455}
 456
 457/*
 458 * Load the filesystem database from /etc/fstab
 459 */
 460static void load_fs_info(const char *filename)
 461{
 462        FILE    *f;
 463        char    buf[1024];
 464        int     lineno = 0;
 465        int     old_fstab = 1;
 466        struct fs_info *fs;
 467
 468        if ((f = fopen_or_warn(filename, "r")) == NULL) {
 469                return;
 470        }
 471        while (!feof(f)) {
 472                lineno++;
 473                if (!fgets(buf, sizeof(buf), f))
 474                        break;
 475                buf[sizeof(buf)-1] = 0;
 476                if (parse_fstab_line(buf, &fs) < 0) {
 477                        bb_error_msg("WARNING: bad format "
 478                                "on line %d of %s\n", lineno, filename);
 479                        continue;
 480                }
 481                if (!fs)
 482                        continue;
 483                if (fs->passno < 0)
 484                        fs->passno = 0;
 485                else
 486                        old_fstab = 0;
 487        }
 488
 489        fclose(f);
 490
 491        if (old_fstab) {
 492                fputs("\007\007\007"
 493                "WARNING: Your /etc/fstab does not contain the fsck passno\n"
 494                "       field.  I will kludge around things for you, but you\n"
 495                "       should fix your /etc/fstab file as soon as you can.\n\n", stderr);
 496
 497                for (fs = filesys_info; fs; fs = fs->next) {
 498                        fs->passno = 1;
 499                }
 500        }
 501}
 502
 503/* Lookup filesys in /etc/fstab and return the corresponding entry. */
 504static struct fs_info *lookup(char *filesys)
 505{
 506        struct fs_info *fs;
 507
 508        /* No filesys name given. */
 509        if (filesys == NULL)
 510                return NULL;
 511
 512        for (fs = filesys_info; fs; fs = fs->next) {
 513                if (!strcmp(filesys, fs->device) ||
 514                    (fs->mountpt && !strcmp(filesys, fs->mountpt)))
 515                        break;
 516        }
 517
 518        return fs;
 519}
 520
 521/* Find fsck program for a given fs type. */
 522static char *find_fsck(char *type)
 523{
 524        char *s;
 525        const char *tpl;
 526        char *p = string_copy(fsck_path);
 527        struct stat st;
 528
 529        /* Are we looking for a program or just a type? */
 530        tpl = (strncmp(type, "fsck.", 5) ? "%s/fsck.%s" : "%s/%s");
 531
 532        for (s = strtok(p, ":"); s; s = strtok(NULL, ":")) {
 533                s = xasprintf(tpl, s, type);
 534                if (stat(s, &st) == 0) break;
 535                free(s);
 536        }
 537        free(p);
 538        return s;
 539}
 540
 541static int progress_active(void)
 542{
 543        struct fsck_instance *inst;
 544
 545        for (inst = instance_list; inst; inst = inst->next) {
 546                if (inst->flags & FLAG_DONE)
 547                        continue;
 548                if (inst->flags & FLAG_PROGRESS)
 549                        return 1;
 550        }
 551        return 0;
 552}
 553
 554/*
 555 * Execute a particular fsck program, and link it into the list of
 556 * child processes we are waiting for.
 557 */
 558static int execute(const char *type, const char *device, const char *mntpt,
 559                   int interactive)
 560{
 561        char *s, *argv[80];
 562        char *prog;
 563        int  argc, i;
 564        struct fsck_instance *inst, *p;
 565        pid_t   pid;
 566
 567        inst = xzalloc(sizeof(struct fsck_instance));
 568
 569        prog = xasprintf("fsck.%s", type);
 570        argv[0] = prog;
 571        argc = 1;
 572
 573        for (i=0; i <num_args; i++)
 574                argv[argc++] = string_copy(args[i]);
 575
 576        if (progress && !progress_active()) {
 577                if ((strcmp(type, "ext2") == 0) ||
 578                    (strcmp(type, "ext3") == 0)) {
 579                        char tmp[80];
 580                        snprintf(tmp, 80, "-C%d", progress_fd);
 581                        argv[argc++] = string_copy(tmp);
 582                        inst->flags |= FLAG_PROGRESS;
 583                }
 584        }
 585
 586        argv[argc++] = string_copy(device);
 587        argv[argc] = 0;
 588
 589        s = find_fsck(prog);
 590        if (s == NULL) {
 591                bb_error_msg("%s: not found", prog);
 592                return ENOENT;
 593        }
 594
 595        if (verbose || noexecute) {
 596                printf("[%s (%d) -- %s] ", s, num_running,
 597                       mntpt ? mntpt : device);
 598                for (i=0; i < argc; i++)
 599                        printf("%s ", argv[i]);
 600                bb_putchar('\n');
 601        }
 602
 603        /* Fork and execute the correct program. */
 604        if (noexecute)
 605                pid = -1;
 606        else if ((pid = fork()) < 0) {
 607                perror("vfork"+1);
 608                return errno;
 609        } else if (pid == 0) {
 610                if (!interactive)
 611                        close(0);
 612                (void) execv(s, argv);
 613                bb_simple_perror_msg_and_die(argv[0]);
 614        }
 615
 616        for (i = 1; i < argc; i++)
 617                free(argv[i]);
 618
 619        free(s);
 620        inst->pid = pid;
 621        inst->prog = prog;
 622        inst->type = string_copy(type);
 623        inst->device = string_copy(device);
 624        inst->base_device = base_device(device);
 625        inst->start_time = time(0);
 626        inst->next = NULL;
 627
 628        /*
 629         * Find the end of the list, so we add the instance on at the end.
 630         */
 631        for (p = instance_list; p && p->next; p = p->next);
 632
 633        if (p)
 634                p->next = inst;
 635        else
 636                instance_list = inst;
 637
 638        return 0;
 639}
 640
 641/*
 642 * Send a signal to all outstanding fsck child processes
 643 */
 644static int kill_all(int signum)
 645{
 646        struct fsck_instance *inst;
 647        int     n = 0;
 648
 649        for (inst = instance_list; inst; inst = inst->next) {
 650                if (inst->flags & FLAG_DONE)
 651                        continue;
 652                kill(inst->pid, signum);
 653                n++;
 654        }
 655        return n;
 656}
 657
 658/*
 659 * Wait for one child process to exit; when it does, unlink it from
 660 * the list of executing child processes, and return it.
 661 */
 662static struct fsck_instance *wait_one(int flags)
 663{
 664        int     status;
 665        int     sig;
 666        struct fsck_instance *inst, *inst2, *prev;
 667        pid_t   pid;
 668
 669        if (!instance_list)
 670                return NULL;
 671
 672        if (noexecute) {
 673                inst = instance_list;
 674                prev = 0;
 675#ifdef RANDOM_DEBUG
 676                while (inst->next && (random() & 1)) {
 677                        prev = inst;
 678                        inst = inst->next;
 679                }
 680#endif
 681                inst->exit_status = 0;
 682                goto ret_inst;
 683        }
 684
 685        /*
 686         * gcc -Wall fails saving throw against stupidity
 687         * (inst and prev are thought to be uninitialized variables)
 688         */
 689        inst = prev = NULL;
 690
 691        do {
 692                pid = waitpid(-1, &status, flags);
 693                if (cancel_requested && !kill_sent) {
 694                        kill_all(SIGTERM);
 695                        kill_sent++;
 696                }
 697                if ((pid == 0) && (flags & WNOHANG))
 698                        return NULL;
 699                if (pid < 0) {
 700                        if ((errno == EINTR) || (errno == EAGAIN))
 701                                continue;
 702                        if (errno == ECHILD) {
 703                                bb_error_msg("wait: no more child process?!?");
 704                                return NULL;
 705                        }
 706                        perror("wait");
 707                        continue;
 708                }
 709                for (prev = 0, inst = instance_list;
 710                     inst;
 711                     prev = inst, inst = inst->next) {
 712                        if (inst->pid == pid)
 713                                break;
 714                }
 715        } while (!inst);
 716
 717        if (WIFEXITED(status))
 718                status = WEXITSTATUS(status);
 719        else if (WIFSIGNALED(status)) {
 720                sig = WTERMSIG(status);
 721                if (sig == SIGINT) {
 722                        status = EXIT_UNCORRECTED;
 723                } else {
 724                        printf("Warning... %s for device %s exited "
 725                               "with signal %d.\n",
 726                               inst->prog, inst->device, sig);
 727                        status = EXIT_ERROR;
 728                }
 729        } else {
 730                printf("%s %s: status is %x, should never happen.\n",
 731                       inst->prog, inst->device, status);
 732                status = EXIT_ERROR;
 733        }
 734        inst->exit_status = status;
 735        if (progress && (inst->flags & FLAG_PROGRESS) &&
 736            !progress_active()) {
 737                for (inst2 = instance_list; inst2; inst2 = inst2->next) {
 738                        if (inst2->flags & FLAG_DONE)
 739                                continue;
 740                        if (strcmp(inst2->type, "ext2") &&
 741                            strcmp(inst2->type, "ext3"))
 742                                continue;
 743                        /*
 744                         * If we've just started the fsck, wait a tiny
 745                         * bit before sending the kill, to give it
 746                         * time to set up the signal handler
 747                         */
 748                        if (inst2->start_time < time(0)+2) {
 749                                if (fork() == 0) {
 750                                        sleep(1);
 751                                        kill(inst2->pid, SIGUSR1);
 752                                        exit(0);
 753                                }
 754                        } else
 755                                kill(inst2->pid, SIGUSR1);
 756                        inst2->flags |= FLAG_PROGRESS;
 757                        break;
 758                }
 759        }
 760ret_inst:
 761        if (prev)
 762                prev->next = inst->next;
 763        else
 764                instance_list = inst->next;
 765        if (verbose > 1)
 766                printf("Finished with %s (exit status %d)\n",
 767                       inst->device, inst->exit_status);
 768        num_running--;
 769        return inst;
 770}
 771
 772#define FLAG_WAIT_ALL           0
 773#define FLAG_WAIT_ATLEAST_ONE   1
 774/*
 775 * Wait until all executing child processes have exited; return the
 776 * logical OR of all of their exit code values.
 777 */
 778static int wait_many(int flags)
 779{
 780        struct fsck_instance *inst;
 781        int     global_status = 0;
 782        int     wait_flags = 0;
 783
 784        while ((inst = wait_one(wait_flags))) {
 785                global_status |= inst->exit_status;
 786                free_instance(inst);
 787#ifdef RANDOM_DEBUG
 788                if (noexecute && (flags & WNOHANG) && !(random() % 3))
 789                        break;
 790#endif
 791                if (flags & FLAG_WAIT_ATLEAST_ONE)
 792                        wait_flags = WNOHANG;
 793        }
 794        return global_status;
 795}
 796
 797/*
 798 * Run the fsck program on a particular device
 799 *
 800 * If the type is specified using -t, and it isn't prefixed with "no"
 801 * (as in "noext2") and only one filesystem type is specified, then
 802 * use that type regardless of what is specified in /etc/fstab.
 803 *
 804 * If the type isn't specified by the user, then use either the type
 805 * specified in /etc/fstab, or DEFAULT_FSTYPE.
 806 */
 807static void fsck_device(struct fs_info *fs, int interactive)
 808{
 809        const char *type;
 810        int retval;
 811
 812        interpret_type(fs);
 813
 814        if (strcmp(fs->type, "auto") != 0)
 815                type = fs->type;
 816        else if (fstype && strncmp(fstype, "no", 2) &&
 817            strncmp(fstype, "opts=", 5) && strncmp(fstype, "loop", 4) &&
 818            !strchr(fstype, ','))
 819                type = fstype;
 820        else
 821                type = DEFAULT_FSTYPE;
 822
 823        num_running++;
 824        retval = execute(type, fs->device, fs->mountpt, interactive);
 825        if (retval) {
 826                bb_error_msg("error %d while executing fsck.%s for %s",
 827                                                retval, type, fs->device);
 828                num_running--;
 829        }
 830}
 831
 832
 833/*
 834 * Deal with the fsck -t argument.
 835 */
 836struct fs_type_compile {
 837        char **list;
 838        int *type;
 839        int  negate;
 840} fs_type_compiled;
 841
 842#define FS_TYPE_NORMAL  0
 843#define FS_TYPE_OPT     1
 844#define FS_TYPE_NEGOPT  2
 845
 846static const char fs_type_syntax_error[] =
 847"Either all or none of the filesystem types passed to -t must be prefixed\n"
 848   "with 'no' or '!'.";
 849
 850static void compile_fs_type(char *fs_type, struct fs_type_compile *cmp)
 851{
 852        char    *cp, *list, *s;
 853        int     num = 2;
 854        int     negate, first_negate = 1;
 855
 856        if (fs_type) {
 857                for (cp=fs_type; *cp; cp++) {
 858                        if (*cp == ',')
 859                                num++;
 860                }
 861        }
 862
 863        cmp->list = xzalloc(num * sizeof(char *));
 864        cmp->type = xzalloc(num * sizeof(int));
 865        cmp->negate = 0;
 866
 867        if (!fs_type)
 868                return;
 869
 870        list = string_copy(fs_type);
 871        num = 0;
 872        s = strtok(list, ",");
 873        while (s) {
 874                negate = 0;
 875                if (strncmp(s, "no", 2) == 0) {
 876                        s += 2;
 877                        negate = 1;
 878                } else if (*s == '!') {
 879                        s++;
 880                        negate = 1;
 881                }
 882                if (strcmp(s, "loop") == 0)
 883                        /* loop is really short-hand for opts=loop */
 884                        goto loop_special_case;
 885                else if (strncmp(s, "opts=", 5) == 0) {
 886                        s += 5;
 887                loop_special_case:
 888                        cmp->type[num] = negate ? FS_TYPE_NEGOPT : FS_TYPE_OPT;
 889                } else {
 890                        if (first_negate) {
 891                                cmp->negate = negate;
 892                                first_negate = 0;
 893                        }
 894                        if ((negate && !cmp->negate) ||
 895                            (!negate && cmp->negate)) {
 896                                bb_error_msg_and_die("%s", fs_type_syntax_error);
 897                        }
 898                }
 899                cmp->list[num++] = string_copy(s);
 900                s = strtok(NULL, ",");
 901        }
 902        free(list);
 903}
 904
 905/*
 906 * This function returns true if a particular option appears in a
 907 * comma-delimited options list
 908 */
 909static int opt_in_list(char *opt, char *optlist)
 910{
 911        char    *list, *s;
 912
 913        if (!optlist)
 914                return 0;
 915        list = string_copy(optlist);
 916
 917        s = strtok(list, ",");
 918        while (s) {
 919                if (strcmp(s, opt) == 0) {
 920                        free(list);
 921                        return 1;
 922                }
 923                s = strtok(NULL, ",");
 924        }
 925        free(list);
 926        return 0;
 927}
 928
 929/* See if the filesystem matches the criteria given by the -t option */
 930static int fs_match(struct fs_info *fs, struct fs_type_compile *cmp)
 931{
 932        int n, ret = 0, checked_type = 0;
 933        char *cp;
 934
 935        if (cmp->list == 0 || cmp->list[0] == 0)
 936                return 1;
 937
 938        for (n=0; (cp = cmp->list[n]); n++) {
 939                switch (cmp->type[n]) {
 940                case FS_TYPE_NORMAL:
 941                        checked_type++;
 942                        if (strcmp(cp, fs->type) == 0) {
 943                                ret = 1;
 944                        }
 945                        break;
 946                case FS_TYPE_NEGOPT:
 947                        if (opt_in_list(cp, fs->opts))
 948                                return 0;
 949                        break;
 950                case FS_TYPE_OPT:
 951                        if (!opt_in_list(cp, fs->opts))
 952                                return 0;
 953                        break;
 954                }
 955        }
 956        if (checked_type == 0)
 957                return 1;
 958        return (cmp->negate ? !ret : ret);
 959}
 960
 961/* Check if we should ignore this filesystem. */
 962static int ignore(struct fs_info *fs)
 963{
 964        int wanted;
 965        char *s;
 966
 967        /*
 968         * If the pass number is 0, ignore it.
 969         */
 970        if (fs->passno == 0)
 971                return 1;
 972
 973        interpret_type(fs);
 974
 975        /*
 976         * If a specific fstype is specified, and it doesn't match,
 977         * ignore it.
 978         */
 979        if (!fs_match(fs, &fs_type_compiled)) return 1;
 980
 981        /* Are we ignoring this type? */
 982        if (index_in_str_array(ignored_types, fs->type) >= 0)
 983                return 1;
 984
 985        /* Do we really really want to check this fs? */
 986        wanted = index_in_str_array(really_wanted, fs->type) >= 0;
 987
 988        /* See if the <fsck.fs> program is available. */
 989        s = find_fsck(fs->type);
 990        if (s == NULL) {
 991                if (wanted)
 992                        bb_error_msg("can't check %s: fsck.%s not found",
 993                                fs->device, fs->type);
 994                return 1;
 995        }
 996        free(s);
 997
 998        /* We can and want to check this file system type. */
 999        return 0;
1000}
1001
1002/*
1003 * Returns TRUE if a partition on the same disk is already being
1004 * checked.
1005 */
1006static int device_already_active(char *device)
1007{
1008        struct fsck_instance *inst;
1009        char *base;
1010
1011        if (force_all_parallel)
1012                return 0;
1013
1014#ifdef BASE_MD
1015        /* Don't check a soft raid disk with any other disk */
1016        if (instance_list &&
1017            (!strncmp(instance_list->device, BASE_MD, sizeof(BASE_MD)-1) ||
1018             !strncmp(device, BASE_MD, sizeof(BASE_MD)-1)))
1019                return 1;
1020#endif
1021
1022        base = base_device(device);
1023        /*
1024         * If we don't know the base device, assume that the device is
1025         * already active if there are any fsck instances running.
1026         */
1027        if (!base)
1028                return (instance_list != 0);
1029        for (inst = instance_list; inst; inst = inst->next) {
1030                if (!inst->base_device || !strcmp(base, inst->base_device)) {
1031                        free(base);
1032                        return 1;
1033                }
1034        }
1035        free(base);
1036        return 0;
1037}
1038
1039/* Check all file systems, using the /etc/fstab table. */
1040static int check_all(void)
1041{
1042        struct fs_info *fs = NULL;
1043        int status = EXIT_OK;
1044        int not_done_yet = 1;
1045        int passno = 1;
1046        int pass_done;
1047
1048        if (verbose)
1049                fputs("Checking all file systems.\n", stdout);
1050
1051        /*
1052         * Do an initial scan over the filesystem; mark filesystems
1053         * which should be ignored as done, and resolve any "auto"
1054         * filesystem types (done as a side-effect of calling ignore()).
1055         */
1056        for (fs = filesys_info; fs; fs = fs->next) {
1057                if (ignore(fs))
1058                        fs->flags |= FLAG_DONE;
1059        }
1060
1061        /*
1062         * Find and check the root filesystem.
1063         */
1064        if (!parallel_root) {
1065                for (fs = filesys_info; fs; fs = fs->next) {
1066                        if (LONE_CHAR(fs->mountpt, '/'))
1067                                break;
1068                }
1069                if (fs) {
1070                        if (!skip_root && !ignore(fs)) {
1071                                fsck_device(fs, 1);
1072                                status |= wait_many(FLAG_WAIT_ALL);
1073                                if (status > EXIT_NONDESTRUCT)
1074                                        return status;
1075                        }
1076                        fs->flags |= FLAG_DONE;
1077                }
1078        }
1079        /*
1080         * This is for the bone-headed user who enters the root
1081         * filesystem twice.  Skip root will skep all root entries.
1082         */
1083        if (skip_root)
1084                for (fs = filesys_info; fs; fs = fs->next)
1085                        if (LONE_CHAR(fs->mountpt, '/'))
1086                                fs->flags |= FLAG_DONE;
1087
1088        while (not_done_yet) {
1089                not_done_yet = 0;
1090                pass_done = 1;
1091
1092                for (fs = filesys_info; fs; fs = fs->next) {
1093                        if (cancel_requested)
1094                                break;
1095                        if (fs->flags & FLAG_DONE)
1096                                continue;
1097                        /*
1098                         * If the filesystem's pass number is higher
1099                         * than the current pass number, then we don't
1100                         * do it yet.
1101                         */
1102                        if (fs->passno > passno) {
1103                                not_done_yet++;
1104                                continue;
1105                        }
1106                        /*
1107                         * If a filesystem on a particular device has
1108                         * already been spawned, then we need to defer
1109                         * this to another pass.
1110                         */
1111                        if (device_already_active(fs->device)) {
1112                                pass_done = 0;
1113                                continue;
1114                        }
1115                        /*
1116                         * Spawn off the fsck process
1117                         */
1118                        fsck_device(fs, serialize);
1119                        fs->flags |= FLAG_DONE;
1120
1121                        /*
1122                         * Only do one filesystem at a time, or if we
1123                         * have a limit on the number of fsck's extant
1124                         * at one time, apply that limit.
1125                         */
1126                        if (serialize ||
1127                            (max_running && (num_running >= max_running))) {
1128                                pass_done = 0;
1129                                break;
1130                        }
1131                }
1132                if (cancel_requested)
1133                        break;
1134                if (verbose > 1)
1135                        printf("--waiting-- (pass %d)\n", passno);
1136                status |= wait_many(pass_done ? FLAG_WAIT_ALL :
1137                                    FLAG_WAIT_ATLEAST_ONE);
1138                if (pass_done) {
1139                        if (verbose > 1)
1140                                printf("----------------------------------\n");
1141                        passno++;
1142                } else
1143                        not_done_yet++;
1144        }
1145        if (cancel_requested && !kill_sent) {
1146                kill_all(SIGTERM);
1147                kill_sent++;
1148        }
1149        status |= wait_many(FLAG_WAIT_ATLEAST_ONE);
1150        return status;
1151}
1152
1153static void signal_cancel(int sig FSCK_ATTR((unused)))
1154{
1155        cancel_requested++;
1156}
1157
1158static void PRS(int argc, char **argv)
1159{
1160        int     i, j;
1161        char    *arg, *dev, *tmp = NULL;
1162        char    options[128];
1163        int     opt = 0;
1164        int     opts_for_fsck = 0;
1165        struct sigaction        sa;
1166
1167        /*
1168         * Set up signal action
1169         */
1170        memset(&sa, 0, sizeof(struct sigaction));
1171        sa.sa_handler = signal_cancel;
1172        sigaction(SIGINT, &sa, 0);
1173        sigaction(SIGTERM, &sa, 0);
1174
1175        num_devices = 0;
1176        num_args = 0;
1177        instance_list = 0;
1178
1179        for (i=1; i < argc; i++) {
1180                arg = argv[i];
1181                if (!arg)
1182                        continue;
1183                if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) {
1184                        if (num_devices >= MAX_DEVICES) {
1185                                bb_error_msg_and_die("too many devices");
1186                        }
1187                        dev = blkid_get_devname(cache, arg, NULL);
1188                        if (!dev && strchr(arg, '=')) {
1189                                /*
1190                                 * Check to see if we failed because
1191                                 * /proc/partitions isn't found.
1192                                 */
1193                                if (access("/proc/partitions", R_OK) < 0) {
1194                                        bb_perror_msg_and_die("can't open /proc/partitions "
1195                                                        "(is /proc mounted?)");
1196                                }
1197                                /*
1198                                 * Check to see if this is because
1199                                 * we're not running as root
1200                                 */
1201                                if (geteuid())
1202                                        bb_error_msg_and_die(
1203                "must be root to scan for matching filesystems: %s\n", arg);
1204                                else
1205                                        bb_error_msg_and_die(
1206                "can't find matching filesystem: %s", arg);
1207                        }
1208                        devices[num_devices++] = dev ? dev : string_copy(arg);
1209                        continue;
1210                }
1211                if (arg[0] != '-' || opts_for_fsck) {
1212                        if (num_args >= MAX_ARGS) {
1213                                bb_error_msg_and_die("too many arguments");
1214                        }
1215                        args[num_args++] = string_copy(arg);
1216                        continue;
1217                }
1218                for (j=1; arg[j]; j++) {
1219                        if (opts_for_fsck) {
1220                                options[++opt] = arg[j];
1221                                continue;
1222                        }
1223                        switch (arg[j]) {
1224                        case 'A':
1225                                doall++;
1226                                break;
1227                        case 'C':
1228                                progress++;
1229                                if (arg[j+1]) {
1230                                        progress_fd = string_to_int(arg+j+1);
1231                                        if (progress_fd < 0)
1232                                                progress_fd = 0;
1233                                        else
1234                                                goto next_arg;
1235                                } else if ((i+1) < argc
1236                                 && argv[i+1][0] != '-') {
1237                                        progress_fd = string_to_int(argv[i]);
1238                                        if (progress_fd < 0)
1239                                                progress_fd = 0;
1240                                        else {
1241                                                goto next_arg;
1242                                                i++;
1243                                        }
1244                                }
1245                                break;
1246                        case 'V':
1247                                verbose++;
1248                                break;
1249                        case 'N':
1250                                noexecute++;
1251                                break;
1252                        case 'R':
1253                                skip_root++;
1254                                break;
1255                        case 'T':
1256                                notitle++;
1257                                break;
1258                        case 'M':
1259                                like_mount++;
1260                                break;
1261                        case 'P':
1262                                parallel_root++;
1263                                break;
1264                        case 's':
1265                                serialize++;
1266                                break;
1267                        case 't':
1268                                tmp = 0;
1269                                if (fstype)
1270                                        bb_show_usage();
1271                                if (arg[j+1])
1272                                        tmp = arg+j+1;
1273                                else if ((i+1) < argc)
1274                                        tmp = argv[++i];
1275                                else
1276                                        bb_show_usage();
1277                                fstype = string_copy(tmp);
1278                                compile_fs_type(fstype, &fs_type_compiled);
1279                                goto next_arg;
1280                        case '-':
1281                                opts_for_fsck++;
1282                                break;
1283                        case '?':
1284                                bb_show_usage();
1285                                break;
1286                        default:
1287                                options[++opt] = arg[j];
1288                                break;
1289                        }
1290                }
1291        next_arg:
1292                if (opt) {
1293                        options[0] = '-';
1294                        options[++opt] = '\0';
1295                        if (num_args >= MAX_ARGS) {
1296                                bb_error_msg("too many arguments");
1297                        }
1298                        args[num_args++] = string_copy(options);
1299                        opt = 0;
1300                }
1301        }
1302        if (getenv("FSCK_FORCE_ALL_PARALLEL"))
1303                force_all_parallel++;
1304        if ((tmp = getenv("FSCK_MAX_INST")))
1305            max_running = atoi(tmp);
1306}
1307
1308int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1309int fsck_main(int argc, char **argv)
1310{
1311        int i, status = 0;
1312        int interactive = 0;
1313        const char *fstab;
1314        struct fs_info *fs;
1315
1316        setvbuf(stdout, NULL, _IONBF, BUFSIZ);
1317        setvbuf(stderr, NULL, _IONBF, BUFSIZ);
1318
1319        blkid_get_cache(&cache, NULL);
1320        PRS(argc, argv);
1321
1322        if (!notitle)
1323                printf("fsck %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE);
1324
1325        fstab = getenv("FSTAB_FILE");
1326        if (!fstab)
1327                fstab = _PATH_MNTTAB;
1328        load_fs_info(fstab);
1329
1330        fsck_path = e2fs_set_sbin_path();
1331
1332        if ((num_devices == 1) || (serialize))
1333                interactive = 1;
1334
1335        /* If -A was specified ("check all"), do that! */
1336        if (doall)
1337                return check_all();
1338
1339        if (num_devices == 0) {
1340                serialize++;
1341                interactive++;
1342                return check_all();
1343        }
1344        for (i = 0; i < num_devices; i++) {
1345                if (cancel_requested) {
1346                        if (!kill_sent) {
1347                                kill_all(SIGTERM);
1348                                kill_sent++;
1349                        }
1350                        break;
1351                }
1352                fs = lookup(devices[i]);
1353                if (!fs) {
1354                        fs = create_fs_device(devices[i], 0, "auto",
1355                                              0, -1, -1);
1356                        if (!fs)
1357                                continue;
1358                }
1359                fsck_device(fs, interactive);
1360                if (serialize ||
1361                    (max_running && (num_running >= max_running))) {
1362                        struct fsck_instance *inst;
1363
1364                        inst = wait_one(0);
1365                        if (inst) {
1366                                status |= inst->exit_status;
1367                                free_instance(inst);
1368                        }
1369                        if (verbose > 1)
1370                                printf("----------------------------------\n");
1371                }
1372        }
1373        status |= wait_many(FLAG_WAIT_ALL);
1374        blkid_put_cache(cache);
1375        return status;
1376}
1377