Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/util-linux/mount.c

    r1765 r2725  
    77 * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
    88 *
    9  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    1010 */
    11 
    12 /* Design notes: There is no spec for mount.  Remind me to write one.
    13 
    14    mount_main() calls singlemount() which calls mount_it_now().
    15 
    16    mount_main() can loop through /etc/fstab for mount -a
    17    singlemount() can loop through /etc/filesystems for fstype detection.
    18    mount_it_now() does the actual mount.
    19 */
     11// Design notes: There is no spec for mount.  Remind me to write one.
     12//
     13// mount_main() calls singlemount() which calls mount_it_now().
     14//
     15// mount_main() can loop through /etc/fstab for mount -a
     16// singlemount() can loop through /etc/filesystems for fstype detection.
     17// mount_it_now() does the actual mount.
     18//
     19#include <mntent.h>
     20#include <syslog.h>
     21#include <sys/mount.h>
     22// Grab more as needed from util-linux's mount/mount_constants.h
     23#ifndef MS_DIRSYNC
     24# define MS_DIRSYNC     (1 << 7) // Directory modifications are synchronous
     25#endif
     26#ifndef MS_UNION
     27# define MS_UNION       (1 << 8)
     28#endif
     29#ifndef MS_BIND
     30# define MS_BIND        (1 << 12)
     31#endif
     32#ifndef MS_MOVE
     33# define MS_MOVE        (1 << 13)
     34#endif
     35#ifndef MS_RECURSIVE
     36# define MS_RECURSIVE   (1 << 14)
     37#endif
     38#ifndef MS_SILENT
     39# define MS_SILENT      (1 << 15)
     40#endif
     41// The shared subtree stuff, which went in around 2.6.15
     42#ifndef MS_UNBINDABLE
     43# define MS_UNBINDABLE  (1 << 17)
     44#endif
     45#ifndef MS_PRIVATE
     46# define MS_PRIVATE     (1 << 18)
     47#endif
     48#ifndef MS_SLAVE
     49# define MS_SLAVE       (1 << 19)
     50#endif
     51#ifndef MS_SHARED
     52# define MS_SHARED      (1 << 20)
     53#endif
     54#ifndef MS_RELATIME
     55# define MS_RELATIME    (1 << 21)
     56#endif
    2057
    2158#include "libbb.h"
    22 #include <mntent.h>
    23 
    24 /* Needed for nfs support only... */
    25 #include <syslog.h>
     59#if ENABLE_FEATURE_MOUNT_LABEL
     60# include "volume_id.h"
     61#else
     62# define resolve_mount_spec(fsname) ((void)0)
     63#endif
     64
     65// Needed for nfs support only
    2666#include <sys/utsname.h>
    2767#undef TRUE
    2868#undef FALSE
    29 #include <rpc/rpc.h>
    30 #include <rpc/pmap_prot.h>
    31 #include <rpc/pmap_clnt.h>
     69#if ENABLE_FEATURE_MOUNT_NFS
     70/* This is just a warning of a common mistake.  Possibly this should be a
     71 * uclibc faq entry rather than in busybox... */
     72# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
     73#  error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
     74# endif
     75# include <rpc/rpc.h>
     76# include <rpc/pmap_prot.h>
     77# include <rpc/pmap_clnt.h>
     78#endif
    3279
    3380
    3481#if defined(__dietlibc__)
    35 /* 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
    36  * dietlibc-0.30 does not have implementation of getmntent_r() */
    37 /* OTOH: why we use getmntent_r instead of getmntent? TODO... */
    38 struct mntent *getmntent_r(FILE* stream, struct mntent* result, char* buffer, int bufsize)
    39 {
    40     /* *** XXX FIXME WARNING: This hack is NOT thread safe. --Sampo */
     82// 16.12.2006, Sampo Kellomaki (sampo@iki.fi)
     83// dietlibc-0.30 does not have implementation of getmntent_r()
     84static struct mntent *getmntent_r(FILE* stream, struct mntent* result,
     85        char* buffer UNUSED_PARAM, int bufsize UNUSED_PARAM)
     86{
    4187    struct mntent* ment = getmntent(stream);
    42     memcpy(result, ment, sizeof(struct mntent));
    43     return result;
     88    return memcpy(result, ment, sizeof(*ment));
    4489}
    4590#endif
     
    4893// Not real flags, but we want to be able to check for this.
    4994enum {
    50     MOUNT_USERS  = (1<<28)*ENABLE_DESKTOP,
    51     MOUNT_NOAUTO = (1<<29),
    52     MOUNT_SWAP   = (1<<30),
     95    MOUNT_USERS  = (1 << 28) * ENABLE_DESKTOP,
     96    MOUNT_NOAUTO = (1 << 29),
     97    MOUNT_SWAP   = (1 << 30),
    5398};
     99
     100
     101#define OPTION_STR "o:t:rwanfvsiO:"
     102enum {
     103    OPT_o = (1 << 0),
     104    OPT_t = (1 << 1),
     105    OPT_r = (1 << 2),
     106    OPT_w = (1 << 3),
     107    OPT_a = (1 << 4),
     108    OPT_n = (1 << 5),
     109    OPT_f = (1 << 6),
     110    OPT_v = (1 << 7),
     111    OPT_s = (1 << 8),
     112    OPT_i = (1 << 9),
     113    OPT_O = (1 << 10),
     114};
     115
     116#if ENABLE_FEATURE_MTAB_SUPPORT
     117#define USE_MTAB (!(option_mask32 & OPT_n))
     118#else
     119#define USE_MTAB 0
     120#endif
     121
     122#if ENABLE_FEATURE_MOUNT_FAKE
     123#define FAKE_IT (option_mask32 & OPT_f)
     124#else
     125#define FAKE_IT 0
     126#endif
     127
     128#if ENABLE_FEATURE_MOUNT_HELPERS
     129#define HELPERS_ALLOWED (!(option_mask32 & OPT_i))
     130#else
     131#define HELPERS_ALLOWED 0
     132#endif
     133
     134
    54135// TODO: more "user" flag compatibility.
    55136// "user" option (from mount manpage):
     
    61142// the console user owner of this device.
    62143
    63 /* Standard mount options (from -o options or --options), with corresponding
    64  * flags */
    65 
    66 struct {
    67     const char *name;
    68     long flags;
    69 } static mount_options[] = {
     144// Standard mount options (from -o options or --options),
     145// with corresponding flags
     146static const int32_t mount_options[] = {
    70147    // MS_FLAGS set a bit.  ~MS_FLAGS disable that bit.  0 flags are NOPs.
    71148
    72     USE_FEATURE_MOUNT_LOOP(
    73         {"loop", 0},
     149    IF_FEATURE_MOUNT_LOOP(
     150        /* "loop" */ 0,
    74151    )
    75152
    76     USE_FEATURE_MOUNT_FSTAB(
    77         {"defaults", 0},
    78         /* {"quiet", 0}, - do not filter out, vfat wants to see it */
    79         {"noauto", MOUNT_NOAUTO},
    80         {"sw", MOUNT_SWAP},
    81         {"swap", MOUNT_SWAP},
    82         USE_DESKTOP({"user",  MOUNT_USERS},)
    83         USE_DESKTOP({"users", MOUNT_USERS},)
     153    IF_FEATURE_MOUNT_FSTAB(
     154        /* "defaults" */ 0,
     155        /* "quiet" 0 - do not filter out, vfat wants to see it */
     156        /* "noauto" */ MOUNT_NOAUTO,
     157        /* "sw"     */ MOUNT_SWAP,
     158        /* "swap"   */ MOUNT_SWAP,
     159        IF_DESKTOP(/* "user"  */ MOUNT_USERS,)
     160        IF_DESKTOP(/* "users" */ MOUNT_USERS,)
     161        /* "_netdev" */ 0,
    84162    )
    85163
    86     USE_FEATURE_MOUNT_FLAGS(
     164    IF_FEATURE_MOUNT_FLAGS(
    87165        // vfs flags
    88         {"nosuid", MS_NOSUID},
    89         {"suid", ~MS_NOSUID},
    90         {"dev", ~MS_NODEV},
    91         {"nodev", MS_NODEV},
    92         {"exec", ~MS_NOEXEC},
    93         {"noexec", MS_NOEXEC},
    94         {"sync", MS_SYNCHRONOUS},
    95         {"async", ~MS_SYNCHRONOUS},
    96         {"atime", ~MS_NOATIME},
    97         {"noatime", MS_NOATIME},
    98         {"diratime", ~MS_NODIRATIME},
    99         {"nodiratime", MS_NODIRATIME},
    100         {"loud", ~MS_SILENT},
     166        /* "nosuid"      */ MS_NOSUID,
     167        /* "suid"        */ ~MS_NOSUID,
     168        /* "dev"         */ ~MS_NODEV,
     169        /* "nodev"       */ MS_NODEV,
     170        /* "exec"        */ ~MS_NOEXEC,
     171        /* "noexec"      */ MS_NOEXEC,
     172        /* "sync"        */ MS_SYNCHRONOUS,
     173        /* "dirsync"     */ MS_DIRSYNC,
     174        /* "async"       */ ~MS_SYNCHRONOUS,
     175        /* "atime"       */ ~MS_NOATIME,
     176        /* "noatime"     */ MS_NOATIME,
     177        /* "diratime"    */ ~MS_NODIRATIME,
     178        /* "nodiratime"  */ MS_NODIRATIME,
     179        /* "mand"        */ MS_MANDLOCK,
     180        /* "nomand"      */ ~MS_MANDLOCK,
     181        /* "relatime"    */ MS_RELATIME,
     182        /* "norelatime"  */ ~MS_RELATIME,
     183        /* "loud"        */ ~MS_SILENT,
    101184
    102185        // action flags
    103 
    104         {"bind", MS_BIND},
    105         {"move", MS_MOVE},
    106         {"shared", MS_SHARED},
    107         {"slave", MS_SLAVE},
    108         {"private", MS_PRIVATE},
    109         {"unbindable", MS_UNBINDABLE},
    110         {"rshared", MS_SHARED|MS_RECURSIVE},
    111         {"rslave", MS_SLAVE|MS_RECURSIVE},
    112         {"rprivate", MS_SLAVE|MS_RECURSIVE},
    113         {"runbindable", MS_UNBINDABLE|MS_RECURSIVE},
     186        /* "union"       */ MS_UNION,
     187        /* "bind"        */ MS_BIND,
     188        /* "move"        */ MS_MOVE,
     189        /* "shared"      */ MS_SHARED,
     190        /* "slave"       */ MS_SLAVE,
     191        /* "private"     */ MS_PRIVATE,
     192        /* "unbindable"  */ MS_UNBINDABLE,
     193        /* "rshared"     */ MS_SHARED|MS_RECURSIVE,
     194        /* "rslave"      */ MS_SLAVE|MS_RECURSIVE,
     195        /* "rprivate"    */ MS_SLAVE|MS_RECURSIVE,
     196        /* "runbindable" */ MS_UNBINDABLE|MS_RECURSIVE,
    114197    )
    115198
    116199    // Always understood.
    117 
    118     {"ro", MS_RDONLY},        // vfs flag
    119     {"rw", ~MS_RDONLY},       // vfs flag
    120     {"remount", MS_REMOUNT},  // action flag
     200    /* "ro"      */ MS_RDONLY,  // vfs flag
     201    /* "rw"      */ ~MS_RDONLY, // vfs flag
     202    /* "remount" */ MS_REMOUNT  // action flag
    121203};
    122204
    123 
    124 /* Append mount options to string */
     205static const char mount_option_str[] =
     206    IF_FEATURE_MOUNT_LOOP(
     207        "loop\0"
     208    )
     209    IF_FEATURE_MOUNT_FSTAB(
     210        "defaults\0"
     211        // "quiet\0" - do not filter out, vfat wants to see it
     212        "noauto\0"
     213        "sw\0"
     214        "swap\0"
     215        IF_DESKTOP("user\0")
     216        IF_DESKTOP("users\0")
     217        "_netdev\0"
     218    )
     219    IF_FEATURE_MOUNT_FLAGS(
     220        // vfs flags
     221        "nosuid\0"
     222        "suid\0"
     223        "dev\0"
     224        "nodev\0"
     225        "exec\0"
     226        "noexec\0"
     227        "sync\0"
     228        "dirsync\0"
     229        "async\0"
     230        "atime\0"
     231        "noatime\0"
     232        "diratime\0"
     233        "nodiratime\0"
     234        "mand\0"
     235        "nomand\0"
     236        "relatime\0"
     237        "norelatime\0"
     238        "loud\0"
     239
     240        // action flags
     241        "union\0"
     242        "bind\0"
     243        "move\0"
     244        "shared\0"
     245        "slave\0"
     246        "private\0"
     247        "unbindable\0"
     248        "rshared\0"
     249        "rslave\0"
     250        "rprivate\0"
     251        "runbindable\0"
     252    )
     253
     254    // Always understood.
     255    "ro\0"        // vfs flag
     256    "rw\0"        // vfs flag
     257    "remount\0"   // action flag
     258;
     259
     260
     261struct globals {
     262#if ENABLE_FEATURE_MOUNT_NFS
     263    smalluint nfs_mount_version;
     264#endif
     265#if ENABLE_FEATURE_MOUNT_VERBOSE
     266    unsigned verbose;
     267#endif
     268    llist_t *fslist;
     269    char getmntent_buf[1];
     270} FIX_ALIASING;
     271enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) };
     272#define G (*(struct globals*)&bb_common_bufsiz1)
     273#define nfs_mount_version (G.nfs_mount_version)
     274#if ENABLE_FEATURE_MOUNT_VERBOSE
     275#define verbose           (G.verbose          )
     276#else
     277#define verbose           0
     278#endif
     279#define fslist            (G.fslist           )
     280#define getmntent_buf     (G.getmntent_buf    )
     281
     282
     283#if ENABLE_FEATURE_MOUNT_VERBOSE
     284static int verbose_mount(const char *source, const char *target,
     285        const char *filesystemtype,
     286        unsigned long mountflags, const void *data)
     287{
     288    int rc;
     289
     290    errno = 0;
     291    rc = mount(source, target, filesystemtype, mountflags, data);
     292    if (verbose >= 2)
     293        bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d",
     294            source, target, filesystemtype,
     295            mountflags, (char*)data, rc);
     296    return rc;
     297}
     298#else
     299#define verbose_mount(...) mount(__VA_ARGS__)
     300#endif
     301
     302// Append mount options to string
    125303static void append_mount_options(char **oldopts, const char *newopts)
    126304{
    127305    if (*oldopts && **oldopts) {
    128         /* do not insert options which are already there */
     306        // Do not insert options which are already there
    129307        while (newopts[0]) {
    130308            char *p;
     
    135313            while (1) {
    136314                if (!strncmp(p, newopts, len)
    137                  && (p[len]==',' || p[len]==0))
     315                 && (p[len] == ',' || p[len] == '\0'))
    138316                    goto skip;
    139317                p = strchr(p,',');
     
    144322            free(*oldopts);
    145323            *oldopts = p;
    146 skip:
     324 skip:
    147325            newopts += len;
    148326            while (newopts[0] == ',') newopts++;
     
    154332}
    155333
    156 /* Use the mount_options list to parse options into flags.
    157  * Also return list of unrecognized options if unrecognized!=NULL */
    158 static int parse_mount_options(char *options, char **unrecognized)
    159 {
    160     int flags = MS_SILENT;
     334// Use the mount_options list to parse options into flags.
     335// Also update list of unrecognized options if unrecognized != NULL
     336static long parse_mount_options(char *options, char **unrecognized)
     337{
     338    long flags = MS_SILENT;
    161339
    162340    // Loop through options
    163341    for (;;) {
    164         int i;
     342        unsigned i;
    165343        char *comma = strchr(options, ',');
    166 
    167         if (comma) *comma = 0;
    168 
     344        const char *option_str = mount_option_str;
     345
     346        if (comma) *comma = '\0';
     347
     348// FIXME: use hasmntopt()
    169349        // Find this option in mount_options
    170350        for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
    171             if (!strcasecmp(mount_options[i].name, options)) {
    172                 long fl = mount_options[i].flags;
    173                 if (fl < 0) flags &= fl;
    174                 else flags |= fl;
    175                 break;
     351            if (strcasecmp(option_str, options) == 0) {
     352                long fl = mount_options[i];
     353                if (fl < 0)
     354                    flags &= fl;
     355                else
     356                    flags |= fl;
     357                goto found;
    176358            }
    177         }
    178         // If unrecognized not NULL, append unrecognized mount options */
    179         if (unrecognized && i == ARRAY_SIZE(mount_options)) {
     359            option_str += strlen(option_str) + 1;
     360        }
     361        // We did not recognize this option.
     362        // If "unrecognized" is not NULL, append option there.
     363        // Note that we should not append *empty* option -
     364        // in this case we want to pass NULL, not "", to "data"
     365        // parameter of mount(2) syscall.
     366        // This is crucial for filesystems that don't accept
     367        // any arbitrary mount options, like cgroup fs:
     368        // "mount -t cgroup none /mnt"
     369        if (options[0] && unrecognized) {
    180370            // Add it to strflags, to pass on to kernel
    181             i = *unrecognized ? strlen(*unrecognized) : 0;
    182             *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);
     371            char *p = *unrecognized;
     372            unsigned len = p ? strlen(p) : 0;
     373            *unrecognized = p = xrealloc(p, len + strlen(options) + 2);
    183374
    184375            // Comma separated if it's not the first one
    185             if (i) (*unrecognized)[i++] = ',';
    186             strcpy((*unrecognized)+i, options);
    187         }
    188 
    189         // Advance to next option, or finish
    190         if (comma) {
    191             *comma = ',';
    192             options = ++comma;
    193         } else break;
     376            if (len) p[len++] = ',';
     377            strcpy(p + len, options);
     378        }
     379 found:
     380        if (!comma)
     381            break;
     382        // Advance to next option
     383        *comma = ',';
     384        options = ++comma;
    194385    }
    195386
     
    198389
    199390// Return a list of all block device backed filesystems
    200 
    201391static llist_t *get_block_backed_filesystems(void)
    202392{
     
    206396    };
    207397    char *fs, *buf;
    208     llist_t *list = 0;
     398    llist_t *list = NULL;
    209399    int i;
    210400    FILE *f;
    211401
    212402    for (i = 0; i < 2; i++) {
    213         f = fopen(filesystems[i], "r");
     403        f = fopen_for_read(filesystems[i]);
    214404        if (!f) continue;
    215405
    216         while ((buf = xmalloc_getline(f)) != 0) {
    217             if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
     406        while ((buf = xmalloc_fgetline(f)) != NULL) {
     407            if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5]))
    218408                continue;
    219409            fs = skip_whitespace(buf);
    220             if (*fs=='#' || *fs=='*' || !*fs) continue;
     410            if (*fs == '#' || *fs == '*' || !*fs)
     411                continue;
    221412
    222413            llist_add_to_end(&list, xstrdup(fs));
     
    229420}
    230421
    231 llist_t *fslist = 0;
    232 
    233422#if ENABLE_FEATURE_CLEAN_UP
    234423static void delete_block_backed_filesystems(void)
     
    240429#endif
    241430
    242 #if ENABLE_FEATURE_MTAB_SUPPORT
    243 static int useMtab = 1;
    244 static int fakeIt;
    245 #else
    246 #define useMtab 0
    247 #define fakeIt 0
    248 #endif
    249 
    250431// Perform actual mount of specific filesystem at specific location.
    251432// NB: mp->xxx fields may be trashed on exit
    252 static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
     433static int mount_it_now(struct mntent *mp, long vfsflags, char *filteropts)
    253434{
    254435    int rc = 0;
    255436
    256     if (fakeIt) goto mtab;
     437    if (FAKE_IT) {
     438        if (verbose >= 2)
     439            bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')",
     440                mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
     441                vfsflags, filteropts);
     442        goto mtab;
     443    }
    257444
    258445    // Mount, with fallback to read-only if necessary.
    259 
    260446    for (;;) {
    261         rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
     447        errno = 0;
     448        rc = verbose_mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
    262449                vfsflags, filteropts);
    263         if (!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
     450
     451        // If mount failed, try
     452        // helper program mount.<mnt_type>
     453        if (HELPERS_ALLOWED && rc && mp->mnt_type) {
     454            char *args[8];
     455            int errno_save = errno;
     456            args[0] = xasprintf("mount.%s", mp->mnt_type);
     457            rc = 1;
     458            if (FAKE_IT)
     459                args[rc++] = (char *)"-f";
     460            if (ENABLE_FEATURE_MTAB_SUPPORT && !USE_MTAB)
     461                args[rc++] = (char *)"-n";
     462            args[rc++] = mp->mnt_fsname;
     463            args[rc++] = mp->mnt_dir;
     464            if (filteropts) {
     465                args[rc++] = (char *)"-o";
     466                args[rc++] = filteropts;
     467            }
     468            args[rc] = NULL;
     469            rc = spawn_and_wait(args);
     470            free(args[0]);
     471            if (!rc)
     472                break;
     473            errno = errno_save;
     474        }
     475
     476        if (!rc || (vfsflags & MS_RDONLY) || (errno != EACCES && errno != EROFS))
    264477            break;
    265         bb_error_msg("%s is write-protected, mounting read-only",
    266                 mp->mnt_fsname);
     478        if (!(vfsflags & MS_SILENT))
     479            bb_error_msg("%s is write-protected, mounting read-only",
     480                        mp->mnt_fsname);
    267481        vfsflags |= MS_RDONLY;
    268482    }
     
    273487        bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
    274488
    275     /* If the mount was successful, and we're maintaining an old-style
    276      * mtab file by hand, add the new entry to it now. */
     489    // If the mount was successful, and we're maintaining an old-style
     490    // mtab file by hand, add the new entry to it now.
    277491 mtab:
    278     if (ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
     492    if (USE_MTAB && !rc && !(vfsflags & MS_REMOUNT)) {
    279493        char *fsname;
    280494        FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
     495        const char *option_str = mount_option_str;
    281496        int i;
    282497
    283498        if (!mountTable) {
    284             bb_error_msg("no %s",bb_path_mtab_file);
     499            bb_error_msg("no %s", bb_path_mtab_file);
    285500            goto ret;
    286501        }
     
    288503        // Add vfs string flags
    289504
    290         for (i=0; mount_options[i].flags != MS_REMOUNT; i++)
    291             if (mount_options[i].flags > 0 && (mount_options[i].flags & vfsflags))
    292                 append_mount_options(&(mp->mnt_opts), mount_options[i].name);
     505        for (i = 0; mount_options[i] != MS_REMOUNT; i++) {
     506            if (mount_options[i] > 0 && (mount_options[i] & vfsflags))
     507                append_mount_options(&(mp->mnt_opts), option_str);
     508            option_str += strlen(option_str) + 1;
     509        }
    293510
    294511        // Remove trailing / (if any) from directory we mounted on
    295512
    296513        i = strlen(mp->mnt_dir) - 1;
    297         if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = 0;
     514        if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = '\0';
    298515
    299516        // Convert to canonical pathnames as needed
     
    301518        mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
    302519        fsname = 0;
    303         if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */
     520        if (!mp->mnt_type || !*mp->mnt_type) { // bind mount
    304521            mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
    305522            mp->mnt_type = (char*)"bind";
     
    326543 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
    327544 *
    328  * Licensed under GPLv2, see file LICENSE in this tarball for details.
     545 * Licensed under GPLv2, see file LICENSE in this source tree.
    329546 *
    330547 * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
     
    337554 * Implemented the "bg", "fg" and "retry" mount options for NFS.
    338555 *
    339  * 1999-02-22 Arkadiusz Mikiewicz <misiek@misiek.eu.org>
     556 * 1999-02-22 Arkadiusz Mickiewicz <misiek@misiek.eu.org>
    340557 * - added Native Language Support
    341558 *
     
    343560 * plus NFSv3 stuff.
    344561 */
    345 
    346 /* This is just a warning of a common mistake.  Possibly this should be a
    347  * uclibc faq entry rather than in busybox... */
    348 #if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
    349 #error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
    350 #endif
    351562
    352563#define MOUNTPORT 635
     
    527738    NFS_MOUNT_VER3 = 0x0080,    /* 3 */
    528739    NFS_MOUNT_KERBEROS = 0x0100,    /* 3 */
    529     NFS_MOUNT_NONLM = 0x0200    /* 3 */
     740    NFS_MOUNT_NONLM = 0x0200,   /* 3 */
     741    NFS_MOUNT_NORDIRPLUS = 0x4000
    530742};
    531743
     
    539751 *  it cannot even be used as a struct tag or field name".
    540752 */
    541 
    542753#ifndef EDQUOT
    543 #define EDQUOT  ENOSPC
    544 #endif
    545 
    546 // Convert each NFSERR_BLAH into EBLAH
    547 
    548 static const struct {
    549     int stat;
    550     int errnum;
    551 } nfs_errtbl[] = {
    552     {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
    553     {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
    554     {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
    555     {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
     754# define EDQUOT ENOSPC
     755#endif
     756/* Convert each NFSERR_BLAH into EBLAH */
     757static const uint8_t nfs_err_stat[] = {
     758     1,  2,  5,  6, 13, 17,
     759    19, 20, 21, 22, 27, 28,
     760    30, 63, 66, 69, 70, 71
    556761};
    557 
     762#if ( \
     763    EPERM | ENOENT      | EIO      | ENXIO | EACCES| EEXIST | \
     764    ENODEV| ENOTDIR     | EISDIR   | EINVAL| EFBIG | ENOSPC | \
     765    EROFS | ENAMETOOLONG| ENOTEMPTY| EDQUOT| ESTALE| EREMOTE) < 256
     766typedef uint8_t nfs_err_type;
     767#else
     768typedef uint16_t nfs_err_type;
     769#endif
     770static const nfs_err_type nfs_err_errnum[] = {
     771    EPERM , ENOENT      , EIO      , ENXIO , EACCES, EEXIST,
     772    ENODEV, ENOTDIR     , EISDIR   , EINVAL, EFBIG , ENOSPC,
     773    EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE
     774};
    558775static char *nfs_strerror(int status)
    559776{
    560777    int i;
    561     static char buf[sizeof("unknown nfs status return value: ") + sizeof(int)*3];
    562 
    563     for (i = 0; nfs_errtbl[i].stat != -1; i++) {
    564         if (nfs_errtbl[i].stat == status)
    565             return strerror(nfs_errtbl[i].errnum);
    566     }
    567     sprintf(buf, "unknown nfs status return value: %d", status);
    568     return buf;
     778
     779    for (i = 0; i < ARRAY_SIZE(nfs_err_stat); i++) {
     780        if (nfs_err_stat[i] == status)
     781            return strerror(nfs_err_errnum[i]);
     782    }
     783    return xasprintf("unknown nfs status return value: %d", status);
    569784}
    570785
    571786static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
    572787{
    573     if (!xdr_opaque(xdrs, objp, FHSIZE))
    574          return FALSE;
    575     return TRUE;
     788    return xdr_opaque(xdrs, objp, FHSIZE);
    576789}
    577790
     
    580793    if (!xdr_u_int(xdrs, &objp->fhs_status))
    581794         return FALSE;
    582     switch (objp->fhs_status) {
    583     case 0:
    584         if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
    585              return FALSE;
    586         break;
    587     default:
    588         break;
    589     }
     795    if (objp->fhs_status == 0)
     796        return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle);
    590797    return TRUE;
    591798}
     
    593800static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
    594801{
    595     if (!xdr_string(xdrs, objp, MNTPATHLEN))
    596          return FALSE;
    597     return TRUE;
     802    return xdr_string(xdrs, objp, MNTPATHLEN);
    598803}
    599804
    600805static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
    601806{
    602     if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
    603          return FALSE;
    604     return TRUE;
     807    return xdr_bytes(xdrs, (char **)&objp->fhandle3_val,
     808               (unsigned int *) &objp->fhandle3_len,
     809               FHSIZE3);
    605810}
    606811
     
    609814    if (!xdr_fhandle3(xdrs, &objp->fhandle))
    610815        return FALSE;
    611     if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
    612                 sizeof (int), (xdrproc_t) xdr_int))
    613         return FALSE;
    614     return TRUE;
     816    return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val),
     817               &(objp->auth_flavours.auth_flavours_len),
     818               ~0,
     819               sizeof(int),
     820               (xdrproc_t) xdr_int);
    615821}
    616822
    617823static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
    618824{
    619     if (!xdr_enum(xdrs, (enum_t *) objp))
    620          return FALSE;
    621     return TRUE;
     825    return xdr_enum(xdrs, (enum_t *) objp);
    622826}
    623827
     
    626830    if (!xdr_mountstat3(xdrs, &objp->fhs_status))
    627831        return FALSE;
    628     switch (objp->fhs_status) {
    629     case MNT_OK:
    630         if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
    631              return FALSE;
    632         break;
    633     default:
    634         break;
    635     }
     832    if (objp->fhs_status == MNT_OK)
     833        return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo);
    636834    return TRUE;
    637835}
    638836
    639837#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
    640 
    641 /*
    642  * nfs_mount_version according to the sources seen at compile time.
    643  */
    644 static int nfs_mount_version;
    645 static int kernel_version;
    646838
    647839/*
     
    659851find_kernel_nfs_mount_version(void)
    660852{
    661     if (kernel_version)
     853    int kernel_version;
     854
     855    if (nfs_mount_version)
    662856        return;
    663857
     
    666860    kernel_version = get_linux_version_code();
    667861    if (kernel_version) {
    668         if (kernel_version < KERNEL_VERSION(2,1,32))
    669             nfs_mount_version = 1;
    670         else if (kernel_version < KERNEL_VERSION(2,2,18) ||
    671                 (kernel_version >= KERNEL_VERSION(2,3,0) &&
    672                  kernel_version < KERNEL_VERSION(2,3,99)))
     862        if (kernel_version < KERNEL_VERSION(2,2,18))
    673863            nfs_mount_version = 3;
    674864        /* else v4 since 2.3.99pre4 */
     
    676866}
    677867
    678 static struct pmap *
    679 get_mountport(struct sockaddr_in *server_addr,
     868static void
     869get_mountport(struct pmap *pm_mnt,
     870    struct sockaddr_in *server_addr,
    680871    long unsigned prog,
    681872    long unsigned version,
     
    684875{
    685876    struct pmaplist *pmap;
    686     static struct pmap p = {0, 0, 0, 0};
    687877
    688878    server_addr->sin_port = PMAPPORT;
     
    695885    if (!prog)
    696886        prog = MOUNTPROG;
    697     p.pm_prog = prog;
    698     p.pm_vers = version;
    699     p.pm_prot = proto;
    700     p.pm_port = port;
     887    pm_mnt->pm_prog = prog;
     888    pm_mnt->pm_vers = version;
     889    pm_mnt->pm_prot = proto;
     890    pm_mnt->pm_port = port;
    701891
    702892    while (pmap) {
    703893        if (pmap->pml_map.pm_prog != prog)
    704894            goto next;
    705         if (!version && p.pm_vers > pmap->pml_map.pm_vers)
     895        if (!version && pm_mnt->pm_vers > pmap->pml_map.pm_vers)
    706896            goto next;
    707897        if (version > 2 && pmap->pml_map.pm_vers != version)
     
    709899        if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
    710900            goto next;
    711         if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
    712             (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
    713             (port && pmap->pml_map.pm_port != port))
     901        if (pmap->pml_map.pm_vers > MAX_NFSPROT
     902         || (proto && pm_mnt->pm_prot && pmap->pml_map.pm_prot != proto)
     903         || (port && pmap->pml_map.pm_port != port)
     904        ) {
    714905            goto next;
    715         memcpy(&p, &pmap->pml_map, sizeof(p));
    716 next:
     906        }
     907        memcpy(pm_mnt, &pmap->pml_map, sizeof(*pm_mnt));
     908 next:
    717909        pmap = pmap->pml_next;
    718910    }
    719     if (!p.pm_vers)
    720         p.pm_vers = MOUNTVERS;
    721     if (!p.pm_port)
    722         p.pm_port = MOUNTPORT;
    723     if (!p.pm_prot)
    724         p.pm_prot = IPPROTO_TCP;
    725     return &p;
    726 }
    727 
     911    if (!pm_mnt->pm_vers)
     912        pm_mnt->pm_vers = MOUNTVERS;
     913    if (!pm_mnt->pm_port)
     914        pm_mnt->pm_port = MOUNTPORT;
     915    if (!pm_mnt->pm_prot)
     916        pm_mnt->pm_prot = IPPROTO_TCP;
     917}
     918
     919#if BB_MMU
    728920static int daemonize(void)
    729921{
    730     int fd;
    731922    int pid = fork();
    732923    if (pid < 0) /* error */
     
    735926        return 0;
    736927    /* child */
    737     fd = xopen(bb_dev_null, O_RDWR);
    738     dup2(fd, 0);
    739     dup2(fd, 1);
    740     dup2(fd, 2);
    741     while (fd > 2) close(fd--);
     928    close(0);
     929    xopen(bb_dev_null, O_RDWR);
     930    xdup2(0, 1);
     931    xdup2(0, 2);
    742932    setsid();
    743933    openlog(applet_name, LOG_PID, LOG_DAEMON);
     
    745935    return 1;
    746936}
    747 
    748 // TODO
    749 static inline int we_saw_this_host_before(const char *hostname)
     937#else
     938static inline int daemonize(void) { return -ENOSYS; }
     939#endif
     940
     941/* TODO */
     942static inline int we_saw_this_host_before(const char *hostname UNUSED_PARAM)
    750943{
    751944    return 0;
     
    765958}
    766959
    767 // NB: mp->xxx fields may be trashed on exit
    768 static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)
     960/* NB: mp->xxx fields may be trashed on exit */
     961static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts)
    769962{
    770963    CLIENT *mclient;
     
    772965    char *pathname;
    773966    char *mounthost;
     967    /* prior to 2.6.23, kernel took NFS options in a form of this struct
     968     * only. 2.6.23+ looks at data->version, and if it's not 1..6,
     969     * then data pointer is interpreted as a string. */
    774970    struct nfs_mount_data data;
    775971    char *opt;
     
    787983    int mountport;
    788984    int proto;
    789     int bg;
    790     int soft;
    791     int intr;
    792     int posix;
    793     int nocto;
    794     int noac;
    795     int nolock;
     985#if BB_MMU
     986    smallint bg = 0;
     987#else
     988    enum { bg = 0 };
     989#endif
    796990    int retry;
    797     int tcp;
    798991    int mountprog;
    799992    int mountvers;
     
    801994    int nfsvers;
    802995    int retval;
     996    /* these all are one-bit really. gcc 4.3.1 likes this combination: */
     997    smallint tcp;
     998    smallint soft;
     999    int intr;
     1000    int posix;
     1001    int nocto;
     1002    int noac;
     1003    int nordirplus;
     1004    int nolock;
    8031005
    8041006    find_kernel_nfs_mount_version();
     
    8341036            goto fail;
    8351037        }
    836         if (hp->h_length > sizeof(struct in_addr)) {
    837             bb_error_msg("got bad hp->h_length");
    838             hp->h_length = sizeof(struct in_addr);
    839         }
    840         memcpy(&server_addr.sin_addr,
    841                 hp->h_addr, hp->h_length);
     1038        if (hp->h_length != (int)sizeof(struct in_addr)) {
     1039            bb_error_msg_and_die("only IPv4 is supported");
     1040        }
     1041        memcpy(&server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
    8421042    }
    8431043
     
    8611061     * timeo is filled in after we know whether it'll be TCP or UDP. */
    8621062    memset(&data, 0, sizeof(data));
    863     data.retrans    = 3;
    864     data.acregmin   = 3;
    865     data.acregmax   = 60;
    866     data.acdirmin   = 30;
    867     data.acdirmax   = 60;
    868     data.namlen = NAME_MAX;
    869 
    870     bg = 0;
     1063    data.retrans  = 3;
     1064    data.acregmin = 3;
     1065    data.acregmax = 60;
     1066    data.acdirmin = 30;
     1067    data.acdirmax = 60;
     1068    data.namlen   = NAME_MAX;
     1069
    8711070    soft = 0;
    8721071    intr = 0;
     
    8751074    nolock = 0;
    8761075    noac = 0;
     1076    nordirplus = 0;
    8771077    retry = 10000;      /* 10000 minutes ~ 1 week */
    8781078    tcp = 0;
     
    8891089        char *opteq = strchr(opt, '=');
    8901090        if (opteq) {
     1091            int val, idx;
    8911092            static const char options[] ALIGN1 =
    8921093                /* 0 */ "rsize\0"
     
    9111112                /* 19 */ "namlen\0"
    9121113                /* 20 */ "addr\0";
    913             int val = xatoi_u(opteq + 1);
    914             *opteq = '\0';
    915             switch (index_in_strings(options, opt)) {
     1114
     1115            *opteq++ = '\0';
     1116            idx = index_in_strings(options, opt);
     1117            switch (idx) {
     1118            case 12: // "mounthost"
     1119                mounthost = xstrndup(opteq,
     1120                        strcspn(opteq, " \t\n\r,"));
     1121                continue;
     1122            case 18: // "proto"
     1123                if (!strncmp(opteq, "tcp", 3))
     1124                    tcp = 1;
     1125                else if (!strncmp(opteq, "udp", 3))
     1126                    tcp = 0;
     1127                else
     1128                    bb_error_msg("warning: unrecognized proto= option");
     1129                continue;
     1130            case 20: // "addr" - ignore
     1131                continue;
     1132            }
     1133
     1134            val = xatoi_positive(opteq);
     1135            switch (idx) {
    9161136            case 0: // "rsize"
    9171137                data.rsize = val;
    918                 break;
     1138                continue;
    9191139            case 1: // "wsize"
    9201140                data.wsize = val;
    921                 break;
     1141                continue;
    9221142            case 2: // "timeo"
    9231143                data.timeo = val;
    924                 break;
     1144                continue;
    9251145            case 3: // "retrans"
    9261146                data.retrans = val;
    927                 break;
     1147                continue;
    9281148            case 4: // "acregmin"
    9291149                data.acregmin = val;
    930                 break;
     1150                continue;
    9311151            case 5: // "acregmax"
    9321152                data.acregmax = val;
    933                 break;
     1153                continue;
    9341154            case 6: // "acdirmin"
    9351155                data.acdirmin = val;
    936                 break;
     1156                continue;
    9371157            case 7: // "acdirmax"
    9381158                data.acdirmax = val;
    939                 break;
     1159                continue;
    9401160            case 8: // "actimeo"
    9411161                data.acregmin = val;
     
    9431163                data.acdirmin = val;
    9441164                data.acdirmax = val;
    945                 break;
     1165                continue;
    9461166            case 9: // "retry"
    9471167                retry = val;
    948                 break;
     1168                continue;
    9491169            case 10: // "port"
    9501170                port = val;
    951                 break;
     1171                continue;
    9521172            case 11: // "mountport"
    9531173                mountport = val;
    954                 break;
    955             case 12: // "mounthost"
    956                 mounthost = xstrndup(opteq+1,
    957                         strcspn(opteq+1," \t\n\r,"));
    958                 break;
     1174                continue;
    9591175            case 13: // "mountprog"
    9601176                mountprog = val;
    961                 break;
     1177                continue;
    9621178            case 14: // "mountvers"
    9631179                mountvers = val;
    964                 break;
     1180                continue;
    9651181            case 15: // "nfsprog"
    9661182                nfsprog = val;
    967                 break;
     1183                continue;
    9681184            case 16: // "nfsvers"
    9691185            case 17: // "vers"
    9701186                nfsvers = val;
    971                 break;
    972             case 18: // "proto"
    973                 if (!strncmp(opteq+1, "tcp", 3))
    974                     tcp = 1;
    975                 else if (!strncmp(opteq+1, "udp", 3))
    976                     tcp = 0;
    977                 else
    978                     bb_error_msg("warning: unrecognized proto= option");
    979                 break;
     1187                continue;
    9801188            case 19: // "namlen"
    981                 if (nfs_mount_version >= 2)
     1189                //if (nfs_mount_version >= 2)
    9821190                    data.namlen = val;
    983                 else
    984                     bb_error_msg("warning: option namlen is not supported\n");
    985                 break;
    986             case 20: // "addr" - ignore
    987                 break;
     1191                //else
     1192                //  bb_error_msg("warning: option namlen is not supported\n");
     1193                continue;
    9881194            default:
    9891195                bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
     
    9911197            }
    9921198        }
    993         else {
     1199        else { /* not of the form opt=val */
    9941200            static const char options[] ALIGN1 =
    9951201                "bg\0"
     
    10031209                "tcp\0"
    10041210                "udp\0"
    1005                 "lock\0";
     1211                "lock\0"
     1212                "rdirplus\0";
    10061213            int val = 1;
    10071214            if (!strncmp(opt, "no", 2)) {
     
    10111218            switch (index_in_strings(options, opt)) {
    10121219            case 0: // "bg"
     1220#if BB_MMU
    10131221                bg = val;
     1222#endif
    10141223                break;
    10151224            case 1: // "fg"
     1225#if BB_MMU
    10161226                bg = !val;
     1227#endif
    10171228                break;
    10181229            case 2: // "soft"
     
    10461257                    bb_error_msg("warning: option nolock is not supported");
    10471258                break;
     1259            case 11: //rdirplus
     1260                nordirplus = !val;
     1261                break;
    10481262            default:
    10491263                bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
     
    10581272        | (posix ? NFS_MOUNT_POSIX : 0)
    10591273        | (nocto ? NFS_MOUNT_NOCTO : 0)
    1060         | (noac ? NFS_MOUNT_NOAC : 0);
     1274        | (noac ? NFS_MOUNT_NOAC : 0)
     1275        | (nordirplus ? NFS_MOUNT_NORDIRPLUS : 0);
    10611276    if (nfs_mount_version >= 2)
    10621277        data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
     
    10881303     */
    10891304    if (bg && we_saw_this_host_before(hostname)) {
    1090         daemonized = daemonize(); /* parent or error */
     1305        daemonized = daemonize();
    10911306        if (daemonized <= 0) { /* parent or error */
    10921307            retval = -daemonized;
     
    10951310    }
    10961311
    1097     /* create mount daemon client */
     1312    /* Create mount daemon client */
    10981313    /* See if the nfs host = mount host. */
    10991314    if (mounthost) {
     
    11061321                bb_herror_msg("%s", mounthost);
    11071322                goto fail;
    1108             } else {
    1109                 if (hp->h_length > sizeof(struct in_addr)) {
    1110                     bb_error_msg("got bad hp->h_length?");
    1111                     hp->h_length = sizeof(struct in_addr);
    1112                 }
    1113                 mount_server_addr.sin_family = AF_INET;
    1114                 memcpy(&mount_server_addr.sin_addr,
    1115                         hp->h_addr, hp->h_length);
    11161323            }
     1324            if (hp->h_length != (int)sizeof(struct in_addr)) {
     1325                bb_error_msg_and_die("only IPv4 is supported");
     1326            }
     1327            mount_server_addr.sin_family = AF_INET;
     1328            memcpy(&mount_server_addr.sin_addr, hp->h_addr_list[0], sizeof(struct in_addr));
    11171329        }
    11181330    }
     
    11331345        struct timeval total_timeout;
    11341346        struct timeval retry_timeout;
    1135         struct pmap* pm_mnt;
     1347        struct pmap pm_mnt;
    11361348        time_t t;
    11371349        time_t prevt;
     
    11421354        total_timeout.tv_sec = 20;
    11431355        total_timeout.tv_usec = 0;
     1356/* FIXME: use monotonic()? */
    11441357        timeout = time(NULL) + 60 * retry;
    11451358        prevt = 0;
    11461359        t = 30;
    1147 retry:
    1148         /* be careful not to use too many CPU cycles */
     1360 retry:
     1361        /* Be careful not to use too many CPU cycles */
    11491362        if (t - prevt < 30)
    11501363            sleep(30);
    11511364
    1152         pm_mnt = get_mountport(&mount_server_addr,
     1365        get_mountport(&pm_mnt, &mount_server_addr,
    11531366                mountprog,
    11541367                mountvers,
    11551368                proto,
    11561369                mountport);
    1157         nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
     1370        nfsvers = (pm_mnt.pm_vers < 2) ? 2 : pm_mnt.pm_vers;
    11581371
    11591372        /* contact the mount daemon via TCP */
    1160         mount_server_addr.sin_port = htons(pm_mnt->pm_port);
     1373        mount_server_addr.sin_port = htons(pm_mnt.pm_port);
    11611374        msock = RPC_ANYSOCK;
    11621375
    1163         switch (pm_mnt->pm_prot) {
     1376        switch (pm_mnt.pm_prot) {
    11641377        case IPPROTO_UDP:
    11651378            mclient = clntudp_create(&mount_server_addr,
    1166                          pm_mnt->pm_prog,
    1167                          pm_mnt->pm_vers,
     1379                         pm_mnt.pm_prog,
     1380                         pm_mnt.pm_vers,
    11681381                         retry_timeout,
    11691382                         &msock);
    11701383            if (mclient)
    11711384                break;
    1172             mount_server_addr.sin_port = htons(pm_mnt->pm_port);
     1385            mount_server_addr.sin_port = htons(pm_mnt.pm_port);
    11731386            msock = RPC_ANYSOCK;
    11741387        case IPPROTO_TCP:
    11751388            mclient = clnttcp_create(&mount_server_addr,
    1176                          pm_mnt->pm_prog,
    1177                          pm_mnt->pm_vers,
     1389                         pm_mnt.pm_prog,
     1390                         pm_mnt.pm_vers,
    11781391                         &msock, 0, 0);
    11791392            break;
    11801393        default:
    1181             mclient = 0;
     1394            mclient = NULL;
    11821395        }
    11831396        if (!mclient) {
     
    11861399        } else {
    11871400            enum clnt_stat clnt_stat;
    1188             /* try to mount hostname:pathname */
     1401
     1402            /* Try to mount hostname:pathname */
    11891403            mclient->cl_auth = authunix_create_default();
    11901404
    1191             /* make pointers in xdr_mountres3 NULL so
     1405            /* Make pointers in xdr_mountres3 NULL so
    11921406             * that xdr_array allocates memory for us
    11931407             */
    11941408            memset(&status, 0, sizeof(status));
    11951409
    1196             if (pm_mnt->pm_vers == 3)
     1410            if (pm_mnt.pm_vers == 3)
    11971411                clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
    11981412                          (xdrproc_t) xdr_dirpath,
     
    12201434            auth_destroy(mclient->cl_auth);
    12211435            clnt_destroy(mclient);
    1222             mclient = 0;
     1436            mclient = NULL;
    12231437            close(msock);
     1438            msock = -1;
    12241439        }
    12251440
    12261441        /* Timeout. We are going to retry... maybe */
    1227 
    12281442        if (!bg)
    12291443            goto fail;
     
    12441458    }
    12451459
    1246 prepare_kernel_data:
     1460 prepare_kernel_data:
    12471461
    12481462    if (nfsvers == 2) {
     
    12791493    }
    12801494
    1281     /* create nfs socket for kernel */
    1282 
     1495    /* Create nfs socket for kernel */
    12831496    if (tcp) {
    12841497        if (nfs_mount_version < 3) {
     
    13061519    server_addr.sin_port = htons(port);
    13071520
    1308     /* prepare data structure for kernel */
    1309 
     1521    /* Prepare data structure for kernel */
    13101522    data.fd = fsock;
    13111523    memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
    13121524    strncpy(data.hostname, hostname, sizeof(data.hostname));
    13131525
    1314     /* clean up */
    1315 
     1526    /* Clean up */
    13161527    auth_destroy(mclient->cl_auth);
    13171528    clnt_destroy(mclient);
    13181529    close(msock);
     1530    msock = -1;
    13191531
    13201532    if (bg) {
     
    13261538                daemonized = daemonize();
    13271539                if (daemonized <= 0) { /* parent or error */
     1540/* FIXME: parent doesn't close fsock - ??! */
    13281541                    retval = -daemonized;
    13291542                    goto ret;
     
    13371550    }
    13381551
    1339 do_mount: /* perform actual mount */
    1340 
     1552    /* Perform actual mount */
     1553 do_mount:
    13411554    mp->mnt_type = (char*)"nfs";
    13421555    retval = mount_it_now(mp, vfsflags, (char*)&data);
    13431556    goto ret;
    13441557
    1345 fail:   /* abort */
    1346 
    1347     if (msock != -1) {
     1558    /* Abort */
     1559 fail:
     1560    if (msock >= 0) {
    13481561        if (mclient) {
    13491562            auth_destroy(mclient->cl_auth);
     
    13521565        close(msock);
    13531566    }
    1354     if (fsock != -1)
     1567    if (fsock >= 0)
    13551568        close(fsock);
    13561569
    1357 ret:
     1570 ret:
    13581571    free(hostname);
    13591572    free(mounthost);
     
    13621575}
    13631576
    1364 #else /* !ENABLE_FEATURE_MOUNT_NFS */
    1365 
    1366 /* Never called. Call should be optimized out. */
    1367 int nfsmount(struct mntent *mp, int vfsflags, char *filteropts);
    1368 
    1369 #endif /* !ENABLE_FEATURE_MOUNT_NFS */
     1577#else // !ENABLE_FEATURE_MOUNT_NFS
     1578
     1579// Never called. Call should be optimized out.
     1580int nfsmount(struct mntent *mp, long vfsflags, char *filteropts);
     1581
     1582#endif // !ENABLE_FEATURE_MOUNT_NFS
    13701583
    13711584// Mount one directory.  Handles CIFS, NFS, loopback, autobind, and filesystem
     
    13741587static int singlemount(struct mntent *mp, int ignore_busy)
    13751588{
    1376     int rc = -1, vfsflags;
    1377     char *loopFile = 0, *filteropts = 0;
    1378     llist_t *fl = 0;
     1589    int rc = -1;
     1590    long vfsflags;
     1591    char *loopFile = NULL, *filteropts = NULL;
     1592    llist_t *fl = NULL;
    13791593    struct stat st;
    13801594
     1595    errno = 0;
     1596
    13811597    vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
    13821598
    1383     // Treat fstype "auto" as unspecified.
    1384 
    1385     if (mp->mnt_type && strcmp(mp->mnt_type,"auto") == 0)
    1386         mp->mnt_type = 0;
     1599    // Treat fstype "auto" as unspecified
     1600    if (mp->mnt_type && strcmp(mp->mnt_type, "auto") == 0)
     1601        mp->mnt_type = NULL;
     1602
     1603    // Might this be a virtual filesystem?
     1604    if (ENABLE_FEATURE_MOUNT_HELPERS && strchr(mp->mnt_fsname, '#')) {
     1605        char *args[35];
     1606        char *s;
     1607        int n;
     1608        // fsname: "cmd#arg1#arg2..."
     1609        // WARNING: allows execution of arbitrary commands!
     1610        // Try "mount 'sh#-c#sh' bogus_dir".
     1611        // It is safe ONLY because non-root
     1612        // cannot use two-argument mount command
     1613        // and using one-argument "mount 'sh#-c#sh'" doesn't work:
     1614        // "mount: can't find sh#-c#sh in /etc/fstab"
     1615        // (if /etc/fstab has it, it's ok: root sets up /etc/fstab).
     1616
     1617        s = mp->mnt_fsname;
     1618        n = 0;
     1619        args[n++] = s;
     1620        while (*s && n < 35 - 2) {
     1621            if (*s++ == '#' && *s != '#') {
     1622                s[-1] = '\0';
     1623                args[n++] = s;
     1624            }
     1625        }
     1626        args[n++] = mp->mnt_dir;
     1627        args[n] = NULL;
     1628        rc = spawn_and_wait(args);
     1629        goto report_error;
     1630    }
    13871631
    13881632    // Might this be an CIFS filesystem?
    1389 
    13901633    if (ENABLE_FEATURE_MOUNT_CIFS
    1391      && (!mp->mnt_type || strcmp(mp->mnt_type,"cifs") == 0)
    1392      && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\')
    1393      && mp->mnt_fsname[0]==mp->mnt_fsname[1]
     1634     && (!mp->mnt_type || strcmp(mp->mnt_type, "cifs") == 0)
     1635     && (mp->mnt_fsname[0] == '/' || mp->mnt_fsname[0] == '\\')
     1636     && mp->mnt_fsname[0] == mp->mnt_fsname[1]
    13941637    ) {
     1638        int len;
     1639        char c;
    13951640        len_and_sockaddr *lsa;
    1396         char *ip, *dotted;
    1397         char *s;
    1398 
    1399         rc = 1;
    1400         // Replace '/' with '\' and verify that unc points to "//server/share".
    1401 
    1402         for (s = mp->mnt_fsname; *s; ++s)
    1403             if (*s == '/') *s = '\\';
    1404 
    1405         // get server IP
    1406 
    1407         s = strrchr(mp->mnt_fsname, '\\');
    1408         if (s <= mp->mnt_fsname+1) goto report_error;
    1409         *s = '\0';
    1410         lsa = host2sockaddr(mp->mnt_fsname+2, 0);
    1411         *s = '\\';
    1412         if (!lsa) goto report_error;
    1413 
    1414         // insert ip=... option into string flags.
    1415 
    1416         dotted = xmalloc_sockaddr2dotted_noport(&lsa->sa);
     1641        char *hostname, *dotted, *ip;
     1642
     1643        hostname = mp->mnt_fsname + 2;
     1644        len = strcspn(hostname, "/\\");
     1645        if (len == 0 || hostname[len] == '\0')
     1646            goto report_error;
     1647        c = hostname[len];
     1648        hostname[len] = '\0';
     1649        lsa = host2sockaddr(hostname, 0);
     1650        hostname[len] = c;
     1651        if (!lsa)
     1652            goto report_error;
     1653
     1654        // Insert "ip=..." option into options
     1655        dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa);
     1656        if (ENABLE_FEATURE_CLEAN_UP) free(lsa);
    14171657        ip = xasprintf("ip=%s", dotted);
     1658        if (ENABLE_FEATURE_CLEAN_UP) free(dotted);
    14181659        parse_mount_options(ip, &filteropts);
    1419 
    1420         // compose new unc '\\server-ip\share'
    1421         // (s => slash after hostname)
    1422 
    1423         mp->mnt_fsname = xasprintf("\\\\%s%s", dotted, s);
    1424 
    1425         // lock is required
     1660        if (ENABLE_FEATURE_CLEAN_UP) free(ip);
     1661
     1662        // "-o mand" is required [why?]
    14261663        vfsflags |= MS_MANDLOCK;
    1427 
    14281664        mp->mnt_type = (char*)"cifs";
    14291665        rc = mount_it_now(mp, vfsflags, filteropts);
    1430         if (ENABLE_FEATURE_CLEAN_UP) {
    1431             free(mp->mnt_fsname);
    1432             free(ip);
    1433             free(dotted);
    1434             free(lsa);
    1435         }
     1666
    14361667        goto report_error;
    14371668    }
    14381669
    14391670    // Might this be an NFS filesystem?
    1440 
    14411671    if (ENABLE_FEATURE_MOUNT_NFS
    1442      && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))
     1672     && (!mp->mnt_type || strcmp(mp->mnt_type, "nfs") == 0)
    14431673     && strchr(mp->mnt_fsname, ':') != NULL
    14441674    ) {
     
    14511681    // (We use stat, not lstat, in order to allow
    14521682    // mount symlink_to_file_or_blkdev dir)
    1453 
    14541683    if (!stat(mp->mnt_fsname, &st)
    14551684     && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
    14561685    ) {
    14571686        // Do we need to allocate a loopback device for it?
    1458 
    14591687        if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
    14601688            loopFile = bb_simplify_path(mp->mnt_fsname);
    1461             mp->mnt_fsname = NULL; /* will receive malloced loop dev name */
    1462             if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {
     1689            mp->mnt_fsname = NULL; // will receive malloced loop dev name
     1690            if (set_loop(&mp->mnt_fsname, loopFile, 0) < 0) {
    14631691                if (errno == EPERM || errno == EACCES)
    14641692                    bb_error_msg(bb_msg_perm_denied_are_you_root);
    14651693                else
    1466                     bb_perror_msg("cannot setup loop device");
     1694                    bb_perror_msg("can't setup loop device");
    14671695                return errno;
    14681696            }
    14691697
    14701698        // Autodetect bind mounts
    1471 
    14721699        } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
    14731700            vfsflags |= MS_BIND;
    14741701    }
    14751702
    1476     /* If we know the fstype (or don't need to), jump straight
    1477      * to the actual mount. */
    1478 
    1479     if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
     1703    // If we know the fstype (or don't need to), jump straight
     1704    // to the actual mount.
     1705    if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
    14801706        rc = mount_it_now(mp, vfsflags, filteropts);
    1481     else {
     1707    } else {
    14821708        // Loop through filesystem types until mount succeeds
    14831709        // or we run out
    14841710
    1485         /* Initialize list of block backed filesystems.  This has to be
    1486          * done here so that during "mount -a", mounts after /proc shows up
    1487          * can autodetect. */
    1488 
     1711        // Initialize list of block backed filesystems.
     1712        // This has to be done here so that during "mount -a",
     1713        // mounts after /proc shows up can autodetect.
    14891714        if (!fslist) {
    14901715            fslist = get_block_backed_filesystems();
     
    14961721            mp->mnt_type = fl->data;
    14971722            rc = mount_it_now(mp, vfsflags, filteropts);
    1498             if (!rc) break;
     1723            if (!rc)
     1724                break;
    14991725        }
    15001726    }
    15011727
    15021728    // If mount failed, clean up loop file (if any).
    1503 
    15041729    if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
    15051730        del_loop(mp->mnt_fsname);
     
    15141739        free(filteropts);
    15151740
    1516     if (rc && errno == EBUSY && ignore_busy)
    1517         rc = 0;
    1518     if (rc < 0)
     1741    if (errno == EBUSY && ignore_busy)
     1742        return 0;
     1743    if (rc != 0)
    15191744        bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
    1520 
    15211745    return rc;
     1746}
     1747
     1748// -O support
     1749//    -O interprets a list of filter options which select whether a mount
     1750// point will be mounted: only mounts with options matching *all* filtering
     1751// options will be selected.
     1752//    By default each -O filter option must be present in the list of mount
     1753// options, but if it is prefixed by "no" then it must be absent.
     1754// For example,
     1755//  -O a,nob,c  matches  -o a,c  but fails to match  -o a,b,c
     1756//              (and also fails to match  -o a  because  -o c  is absent).
     1757//
     1758// It is different from -t in that each option is matched exactly; a leading
     1759// "no" at the beginning of one option does not negate the rest.
     1760static int match_opt(const char *fs_opt_in, const char *O_opt)
     1761{
     1762    if (!O_opt)
     1763        return 1;
     1764
     1765    while (*O_opt) {
     1766        const char *fs_opt = fs_opt_in;
     1767        int O_len;
     1768        int match;
     1769
     1770        // If option begins with "no" then treat as an inverted match:
     1771        // matching is a failure
     1772        match = 0;
     1773        if (O_opt[0] == 'n' && O_opt[1] == 'o') {
     1774            match = 1;
     1775            O_opt += 2;
     1776        }
     1777        // Isolate the current O option
     1778        O_len = strchrnul(O_opt, ',') - O_opt;
     1779        // Check for a match against existing options
     1780        while (1) {
     1781            if (strncmp(fs_opt, O_opt, O_len) == 0
     1782             && (fs_opt[O_len] == '\0' || fs_opt[O_len] == ',')
     1783            ) {
     1784                if (match)
     1785                    return 0;  // "no" prefix, but option found
     1786                match = 1;  // current O option found, go check next one
     1787                break;
     1788            }
     1789            fs_opt = strchr(fs_opt, ',');
     1790            if (!fs_opt)
     1791                break;
     1792            fs_opt++;
     1793        }
     1794        if (match == 0)
     1795            return 0;     // match wanted but not found
     1796        if (O_opt[O_len] == '\0') // end?
     1797            break;
     1798        // Step to the next O option
     1799        O_opt += O_len + 1;
     1800    }
     1801    // If we get here then everything matched
     1802    return 1;
    15221803}
    15231804
    15241805// Parse options, if necessary parse fstab/mtab, and call singlemount for
    15251806// each directory to be mounted.
    1526 
    1527 static const char must_be_root[] ALIGN1 = "you must be root";
    1528 
    1529 int mount_main(int argc, char **argv);
    1530 int mount_main(int argc, char **argv)
    1531 {
    1532     enum { OPT_ALL = 0x10 };
    1533 
    1534     char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0;
    1535     char *opt_o;
     1807int mount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     1808int mount_main(int argc UNUSED_PARAM, char **argv)
     1809{
     1810    char *cmdopts = xzalloc(1);
     1811    char *fstype = NULL;
     1812    char *O_optmatch = NULL;
     1813    char *storage_path;
     1814    llist_t *lst_o = NULL;
    15361815    const char *fstabname;
    15371816    FILE *fstab;
    1538     int i, j, rc = 0;
     1817    int i, j;
     1818    int rc = EXIT_SUCCESS;
    15391819    unsigned opt;
    15401820    struct mntent mtpair[2], *mtcur = mtpair;
    1541     SKIP_DESKTOP(const int nonroot = 0;)
    1542     USE_DESKTOP( int nonroot = (getuid() != 0);)
    1543 
    1544     /* parse long options, like --bind and --move.  Note that -o option
    1545      * and --option are synonymous.  Yes, this means --remount,rw works. */
    1546 
    1547     for (i = j = 0; i < argc; i++) {
    1548         if (argv[i][0] == '-' && argv[i][1] == '-') {
    1549             append_mount_options(&cmdopts, argv[i]+2);
    1550         } else argv[j++] = argv[i];
    1551     }
    1552     argv[j] = 0;
    1553     argc = j;
     1821    IF_NOT_DESKTOP(const int nonroot = 0;)
     1822
     1823    IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
     1824
     1825    // Parse long options, like --bind and --move.  Note that -o option
     1826    // and --option are synonymous.  Yes, this means --remount,rw works.
     1827    for (i = j = 1; argv[i]; i++) {
     1828        if (argv[i][0] == '-' && argv[i][1] == '-')
     1829            append_mount_options(&cmdopts, argv[i] + 2);
     1830        else
     1831            argv[j++] = argv[i];
     1832    }
     1833    argv[j] = NULL;
    15541834
    15551835    // Parse remaining options
    1556 
    1557     opt = getopt32(argv, "o:t:rwanfvs", &opt_o, &fstype);
    1558     if (opt & 0x1) append_mount_options(&cmdopts, opt_o); // -o
    1559     //if (opt & 0x2) // -t
    1560     if (opt & 0x4) append_mount_options(&cmdopts, "ro"); // -r
    1561     if (opt & 0x8) append_mount_options(&cmdopts, "rw"); // -w
    1562     //if (opt & 0x10) // -a
    1563     if (opt & 0x20) USE_FEATURE_MTAB_SUPPORT(useMtab = 0); // -n
    1564     if (opt & 0x40) USE_FEATURE_MTAB_SUPPORT(fakeIt = 1); // -f
    1565     //if (opt & 0x80) // -v: verbose (ignore)
    1566     //if (opt & 0x100) // -s: sloppy (ignore)
     1836    // Max 2 params; -o is a list, -v is a counter
     1837    opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
     1838    opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
     1839            IF_FEATURE_MOUNT_VERBOSE(, &verbose));
     1840    while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
     1841    if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
     1842    if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
    15671843    argv += optind;
    1568     argc -= optind;
    1569 
    1570     // Three or more non-option arguments?  Die with a usage message.
    1571 
    1572     if (argc > 2) bb_show_usage();
    15731844
    15741845    // If we have no arguments, show currently mounted filesystems
    1575 
    1576     if (!argc) {
    1577         if (!(opt & OPT_ALL)) {
     1846    if (!argv[0]) {
     1847        if (!(opt & OPT_a)) {
    15781848            FILE *mountTable = setmntent(bb_path_mtab_file, "r");
    15791849
    1580             if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file);
    1581 
    1582             while (getmntent_r(mountTable, mtpair, bb_common_bufsiz1,
    1583                                 sizeof(bb_common_bufsiz1)))
     1850            if (!mountTable)
     1851                bb_error_msg_and_die("no %s", bb_path_mtab_file);
     1852
     1853            while (getmntent_r(mountTable, &mtpair[0], getmntent_buf,
     1854                                GETMNTENT_BUFSIZE))
    15841855            {
    15851856                // Don't show rootfs. FIXME: why??
    15861857                // util-linux 2.12a happily shows rootfs...
    1587                 //if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
    1588 
    1589                 if (!fstype || !strcmp(mtpair->mnt_type, fstype))
     1858                //if (strcmp(mtpair->mnt_fsname, "rootfs") == 0) continue;
     1859
     1860                if (!fstype || strcmp(mtpair->mnt_type, fstype) == 0)
    15901861                    printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
    15911862                            mtpair->mnt_dir, mtpair->mnt_type,
    15921863                            mtpair->mnt_opts);
    15931864            }
    1594             if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);
     1865            if (ENABLE_FEATURE_CLEAN_UP)
     1866                endmntent(mountTable);
    15951867            return EXIT_SUCCESS;
    15961868        }
    1597     } else storage_path = bb_simplify_path(argv[0]);
    1598 
    1599     // When we have two arguments, the second is the directory and we can
    1600     // skip looking at fstab entirely.  We can always abspath() the directory
    1601     // argument when we get it.
    1602 
    1603     if (argc == 2) {
    1604         if (nonroot)
    1605             bb_error_msg_and_die(must_be_root);
    1606         mtpair->mnt_fsname = argv[0];
    1607         mtpair->mnt_dir = argv[1];
    1608         mtpair->mnt_type = fstype;
    1609         mtpair->mnt_opts = cmdopts;
    1610         rc = singlemount(mtpair, 0);
    1611         goto clean_up;
    1612     }
    1613 
    1614     i = parse_mount_options(cmdopts, 0);
     1869        storage_path = NULL;
     1870    } else {
     1871        // When we have two arguments, the second is the directory and we can
     1872        // skip looking at fstab entirely.  We can always abspath() the directory
     1873        // argument when we get it.
     1874        if (argv[1]) {
     1875            if (nonroot)
     1876                bb_error_msg_and_die(bb_msg_you_must_be_root);
     1877            mtpair->mnt_fsname = argv[0];
     1878            mtpair->mnt_dir = argv[1];
     1879            mtpair->mnt_type = fstype;
     1880            mtpair->mnt_opts = cmdopts;
     1881            resolve_mount_spec(&mtpair->mnt_fsname);
     1882            rc = singlemount(mtpair, /*ignore_busy:*/ 0);
     1883            return rc;
     1884        }
     1885        storage_path = bb_simplify_path(argv[0]); // malloced
     1886    }
     1887
     1888    // Past this point, we are handling either "mount -a [opts]"
     1889    // or "mount [opts] single_param"
     1890
     1891    i = parse_mount_options(cmdopts, NULL); // FIXME: should be "long", not "int"
    16151892    if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
    1616         bb_error_msg_and_die(must_be_root);
     1893        bb_error_msg_and_die(bb_msg_you_must_be_root);
    16171894
    16181895    // If we have a shared subtree flag, don't worry about fstab or mtab.
    1619 
    16201896    if (ENABLE_FEATURE_MOUNT_FLAGS
    16211897     && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
    16221898    ) {
    1623         rc = mount("", argv[0], "", i, "");
    1624         if (rc) bb_perror_msg_and_die("%s", argv[0]);
    1625         goto clean_up;
     1899        // verbose_mount(source, target, type, flags, data)
     1900        rc = verbose_mount("", argv[0], "", i, "");
     1901        if (rc)
     1902            bb_simple_perror_msg_and_die(argv[0]);
     1903        return rc;
    16261904    }
    16271905
    16281906    // Open either fstab or mtab
    1629 
    16301907    fstabname = "/etc/fstab";
    16311908    if (i & MS_REMOUNT) {
     1909        // WARNING. I am not sure this matches util-linux's
     1910        // behavior. It's possible util-linux does not
     1911        // take -o opts from mtab (takes only mount source).
    16321912        fstabname = bb_path_mtab_file;
    16331913    }
    16341914    fstab = setmntent(fstabname, "r");
    16351915    if (!fstab)
    1636         bb_perror_msg_and_die("cannot read %s", fstabname);
    1637 
    1638     // Loop through entries until we find what we're looking for.
    1639 
     1916        bb_perror_msg_and_die("can't read '%s'", fstabname);
     1917
     1918    // Loop through entries until we find what we're looking for
    16401919    memset(mtpair, 0, sizeof(mtpair));
    16411920    for (;;) {
    1642         struct mntent *mtnext = (mtcur==mtpair ? mtpair+1 : mtpair);
     1921        struct mntent *mtother = (mtcur==mtpair ? mtpair+1 : mtpair);
    16431922
    16441923        // Get next fstab entry
    1645 
    1646         if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1
    1647                     + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0),
    1648                 sizeof(bb_common_bufsiz1)/2))
    1649         {
    1650             // Were we looking for something specific?
    1651 
    1652             if (argc) {
    1653 
    1654                 // If we didn't find anything, complain.
    1655 
    1656                 if (!mtnext->mnt_fsname)
    1657                     bb_error_msg_and_die("can't find %s in %s",
    1658                         argv[0], fstabname);
    1659 
    1660                 mtcur = mtnext;
    1661                 if (nonroot) {
    1662                     // fstab must have "users" or "user"
    1663                     if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
    1664                         bb_error_msg_and_die(must_be_root);
    1665                 }
    1666 
    1667                 // Mount the last thing we found.
    1668 
    1669                 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
    1670                 append_mount_options(&(mtcur->mnt_opts), cmdopts);
    1671                 rc = singlemount(mtcur, 0);
    1672                 free(mtcur->mnt_opts);
     1924        if (!getmntent_r(fstab, mtcur, getmntent_buf
     1925                    + (mtcur==mtpair ? GETMNTENT_BUFSIZE/2 : 0),
     1926                GETMNTENT_BUFSIZE/2)
     1927        ) { // End of fstab/mtab is reached
     1928            mtcur = mtother; // the thing we found last time
     1929            break;
     1930        }
     1931
     1932        // If we're trying to mount something specific and this isn't it,
     1933        // skip it.  Note we must match the exact text in fstab (ala
     1934        // "proc") or a full path from root
     1935        if (argv[0]) {
     1936
     1937            // Is this what we're looking for?
     1938            if (strcmp(argv[0], mtcur->mnt_fsname) != 0
     1939             && strcmp(storage_path, mtcur->mnt_fsname) != 0
     1940             && strcmp(argv[0], mtcur->mnt_dir) != 0
     1941             && strcmp(storage_path, mtcur->mnt_dir) != 0
     1942            ) {
     1943                continue; // no
    16731944            }
    1674             goto clean_up;
    1675         }
    1676 
    1677         /* If we're trying to mount something specific and this isn't it,
    1678          * skip it.  Note we must match both the exact text in fstab (ala
    1679          * "proc") or a full path from root */
    1680 
    1681         if (argc) {
    1682 
    1683             // Is this what we're looking for?
    1684 
    1685             if (strcmp(argv[0], mtcur->mnt_fsname) &&
    1686                strcmp(storage_path, mtcur->mnt_fsname) &&
    1687                strcmp(argv[0], mtcur->mnt_dir) &&
    1688                strcmp(storage_path, mtcur->mnt_dir)) continue;
    1689 
    1690             // Remember this entry.  Something later may have overmounted
    1691             // it, and we want the _last_ match.
    1692 
    1693             mtcur = mtnext;
    1694 
    1695         // If we're mounting all.
    1696 
     1945
     1946            // Remember this entry.  Something later may have
     1947            // overmounted it, and we want the _last_ match.
     1948            mtcur = mtother;
     1949
     1950        // If we're mounting all
    16971951        } else {
    1698             // Do we need to match a filesystem type?
    1699             if (fstype && match_fstype(mtcur, fstype)) continue;
    1700 
    1701             // Skip noauto and swap anyway.
    1702 
    1703             if (parse_mount_options(mtcur->mnt_opts, 0)
    1704                 & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
    1705 
     1952            struct mntent *mp;
    17061953            // No, mount -a won't mount anything,
    1707             // even user mounts, for mere humans.
    1708 
     1954            // even user mounts, for mere humans
    17091955            if (nonroot)
    1710                 bb_error_msg_and_die(must_be_root);
    1711 
    1712             // Mount this thing.
     1956                bb_error_msg_and_die(bb_msg_you_must_be_root);
     1957
     1958            // Does type match? (NULL matches always)
     1959            if (!match_fstype(mtcur, fstype))
     1960                continue;
     1961
     1962            // Skip noauto and swap anyway
     1963            if ((parse_mount_options(mtcur->mnt_opts, NULL) & (MOUNT_NOAUTO | MOUNT_SWAP))
     1964            // swap is bogus "fstype", parse_mount_options can't check fstypes
     1965             || strcasecmp(mtcur->mnt_type, "swap") == 0
     1966            ) {
     1967                continue;
     1968            }
     1969
     1970            // Does (at least one) option match?
     1971            // (NULL matches always)
     1972            if (!match_opt(mtcur->mnt_opts, O_optmatch))
     1973                continue;
     1974
     1975            resolve_mount_spec(&mtcur->mnt_fsname);
    17131976
    17141977            // NFS mounts want this to be xrealloc-able
    17151978            mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
    1716             if (singlemount(mtcur, 1)) {
    1717                 /* Count number of failed mounts */
    1718                 rc++;
     1979
     1980            // If nothing is mounted on this directory...
     1981            // (otherwise repeated "mount -a" mounts everything again)
     1982            mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
     1983            // We do not check fsname match of found mount point -
     1984            // "/" may have fsname of "/dev/root" while fstab
     1985            // says "/dev/something_else".
     1986            if (mp) {
     1987                if (verbose) {
     1988                    bb_error_msg("according to %s, "
     1989                        "%s is already mounted on %s",
     1990                        bb_path_mtab_file,
     1991                        mp->mnt_fsname, mp->mnt_dir);
     1992                }
     1993            } else {
     1994                // ...mount this thing
     1995                if (singlemount(mtcur, /*ignore_busy:*/ 1)) {
     1996                    // Count number of failed mounts
     1997                    rc++;
     1998                }
    17191999            }
    17202000            free(mtcur->mnt_opts);
    17212001        }
    17222002    }
    1723     if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);
    1724 
    1725 clean_up:
    1726 
     2003
     2004    // End of fstab/mtab is reached.
     2005    // Were we looking for something specific?
     2006    if (argv[0]) { // yes
     2007        long l;
     2008
     2009        // If we didn't find anything, complain
     2010        if (!mtcur->mnt_fsname)
     2011            bb_error_msg_and_die("can't find %s in %s",
     2012                argv[0], fstabname);
     2013
     2014        // What happens when we try to "mount swap_partition"?
     2015        // (fstab containts "swap_partition swap swap defaults 0 0")
     2016        // util-linux-ng 2.13.1 does this:
     2017        // stat("/sbin/mount.swap", 0x7fff62a3a350) = -1 ENOENT (No such file or directory)
     2018        // mount("swap_partition", "swap", "swap", MS_MGC_VAL, NULL) = -1 ENOENT (No such file or directory)
     2019        // lstat("swap", 0x7fff62a3a640)           = -1 ENOENT (No such file or directory)
     2020        // write(2, "mount: mount point swap does not exist\n", 39) = 39
     2021        // exit_group(32)                          = ?
     2022#if 0
     2023        // In case we want to simply skip swap partitions:
     2024        l = parse_mount_options(mtcur->mnt_opts, NULL);
     2025        if ((l & MOUNT_SWAP)
     2026        // swap is bogus "fstype", parse_mount_options can't check fstypes
     2027         || strcasecmp(mtcur->mnt_type, "swap") == 0
     2028        ) {
     2029            goto ret;
     2030        }
     2031#endif
     2032        if (nonroot) {
     2033            // fstab must have "users" or "user"
     2034            l = parse_mount_options(mtcur->mnt_opts, NULL);
     2035            if (!(l & MOUNT_USERS))
     2036                bb_error_msg_and_die(bb_msg_you_must_be_root);
     2037        }
     2038
     2039        //util-linux-2.12 does not do this check.
     2040        //// If nothing is mounted on this directory...
     2041        //// (otherwise repeated "mount FOO" mounts FOO again)
     2042        //mp = find_mount_point(mtcur->mnt_dir, /*subdir_too:*/ 0);
     2043        //if (mp) {
     2044        //  bb_error_msg("according to %s, "
     2045        //      "%s is already mounted on %s",
     2046        //      bb_path_mtab_file,
     2047        //      mp->mnt_fsname, mp->mnt_dir);
     2048        //} else {
     2049            // ...mount the last thing we found
     2050            mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
     2051            append_mount_options(&(mtcur->mnt_opts), cmdopts);
     2052            resolve_mount_spec(&mtpair->mnt_fsname);
     2053            rc = singlemount(mtcur, /*ignore_busy:*/ 0);
     2054            if (ENABLE_FEATURE_CLEAN_UP)
     2055                free(mtcur->mnt_opts);
     2056        //}
     2057    }
     2058
     2059 //ret:
     2060    if (ENABLE_FEATURE_CLEAN_UP)
     2061        endmntent(fstab);
    17272062    if (ENABLE_FEATURE_CLEAN_UP) {
    17282063        free(storage_path);
     
    17302065    }
    17312066
     2067//TODO: exitcode should be ORed mask of (from "man mount"):
     2068// 0 success
     2069// 1 incorrect invocation or permissions
     2070// 2 system error (out of memory, cannot fork, no more loop devices)
     2071// 4 internal mount bug or missing nfs support in mount
     2072// 8 user interrupt
     2073//16 problems writing or locking /etc/mtab
     2074//32 mount failure
     2075//64 some mount succeeded
    17322076    return rc;
    17332077}
Note: See TracChangeset for help on using the changeset viewer.