Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (13 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod? silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian? keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René? Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File:
1 edited

Legend:

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

    r902 r1770  
    1010 */
    1111
    12 /* todo:
    13  * bb_getopt_ulflags();
    14  */
    15 
    1612/* Design notes: There is no spec for mount.  Remind me to write one.
    1713
     
    2319*/
    2420
    25 #include "busybox.h"
    26 #include <unistd.h>
    27 #include <errno.h>
    28 #include <string.h>
     21#include "libbb.h"
    2922#include <mntent.h>
    30 #include <ctype.h>
    31 #include <fcntl.h>      // for CONFIG_FEATURE_MOUNT_LOOP
    32 #include <sys/ioctl.h>  // for CONFIG_FEATURE_MOUNT_LOOP
    33 
    34 // These two aren't always defined in old headers
    35 #ifndef MS_BIND
    36 #define MS_BIND     4096
     23
     24/* Needed for nfs support only... */
     25#include <syslog.h>
     26#include <sys/utsname.h>
     27#undef TRUE
     28#undef FALSE
     29#include <rpc/rpc.h>
     30#include <rpc/pmap_prot.h>
     31#include <rpc/pmap_clnt.h>
     32
     33
     34#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... */
     38struct mntent *getmntent_r(FILE* stream, struct mntent* result, char* buffer, int bufsize)
     39{
     40    /* *** XXX FIXME WARNING: This hack is NOT thread safe. --Sampo */
     41    struct mntent* ment = getmntent(stream);
     42    memcpy(result, ment, sizeof(struct mntent));
     43    return result;
     44}
    3745#endif
    38 #ifndef MS_MOVE
    39 #define MS_MOVE     8192
    40 #endif
    41 #ifndef MS_SILENT
    42 #define MS_SILENT   32768
    43 #endif
     46
    4447
    4548// Not real flags, but we want to be able to check for this.
    46 #define MOUNT_NOAUTO    (1<<29)
    47 #define MOUNT_SWAP      (1<<30)
     49enum {
     50    MOUNT_USERS  = (1<<28)*ENABLE_DESKTOP,
     51    MOUNT_NOAUTO = (1<<29),
     52    MOUNT_SWAP   = (1<<30),
     53};
     54// TODO: more "user" flag compatibility.
     55// "user" option (from mount manpage):
     56// Only the user that mounted a filesystem can unmount it again.
     57// If any user should be able to unmount, then use users instead of user
     58// in the fstab line.  The owner option is similar to the user option,
     59// with the restriction that the user must be the owner of the special file.
     60// This may be useful e.g. for /dev/fd if a login script makes
     61// the console user owner of this device.
     62
    4863/* Standard mount options (from -o options or --options), with corresponding
    4964 * flags */
     
    5267    const char *name;
    5368    long flags;
    54 } static const mount_options[] = {
    55     // NOP flags.
    56 
    57     {"loop", 0},
    58     {"defaults", 0},
    59     {"quiet", 0},
    60 
    61     // vfs flags
    62 
    63     {"ro", MS_RDONLY},
    64     {"rw", ~MS_RDONLY},
    65     {"nosuid", MS_NOSUID},
    66     {"suid", ~MS_NOSUID},
    67     {"dev", ~MS_NODEV},
    68     {"nodev", MS_NODEV},
    69     {"exec", ~MS_NOEXEC},
    70     {"noexec", MS_NOEXEC},
    71     {"sync", MS_SYNCHRONOUS},
    72     {"async", ~MS_SYNCHRONOUS},
    73     {"atime", ~MS_NOATIME},
    74     {"noatime", MS_NOATIME},
    75     {"diratime", ~MS_NODIRATIME},
    76     {"nodiratime", MS_NODIRATIME},
    77     {"loud", ~MS_SILENT},
    78 
    79     // action flags
    80 
    81     {"remount", MS_REMOUNT},
    82     {"bind", MS_BIND},
    83     {"move", MS_MOVE},
    84     {"noauto",MOUNT_NOAUTO},
    85     {"swap",MOUNT_SWAP}
     69} static mount_options[] = {
     70    // MS_FLAGS set a bit.  ~MS_FLAGS disable that bit.  0 flags are NOPs.
     71
     72    USE_FEATURE_MOUNT_LOOP(
     73        {"loop", 0},
     74    )
     75
     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},)
     84    )
     85
     86    USE_FEATURE_MOUNT_FLAGS(
     87        // 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},
     101
     102        // 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},
     114    )
     115
     116    // Always understood.
     117
     118    {"ro", MS_RDONLY},        // vfs flag
     119    {"rw", ~MS_RDONLY},       // vfs flag
     120    {"remount", MS_REMOUNT},  // action flag
    86121};
    87122
     123
    88124/* Append mount options to string */
    89 static void append_mount_options(char **oldopts, char *newopts)
    90 {
    91     if(*oldopts && **oldopts) {
    92         char *temp=bb_xasprintf("%s,%s",*oldopts,newopts);
    93         free(*oldopts);
    94         *oldopts=temp;
     125static void append_mount_options(char **oldopts, const char *newopts)
     126{
     127    if (*oldopts && **oldopts) {
     128        /* do not insert options which are already there */
     129        while (newopts[0]) {
     130            char *p;
     131            int len = strlen(newopts);
     132            p = strchr(newopts, ',');
     133            if (p) len = p - newopts;
     134            p = *oldopts;
     135            while (1) {
     136                if (!strncmp(p, newopts, len)
     137                 && (p[len]==',' || p[len]==0))
     138                    goto skip;
     139                p = strchr(p,',');
     140                if (!p) break;
     141                p++;
     142            }
     143            p = xasprintf("%s,%.*s", *oldopts, len, newopts);
     144            free(*oldopts);
     145            *oldopts = p;
     146skip:
     147            newopts += len;
     148            while (newopts[0] == ',') newopts++;
     149        }
    95150    } else {
    96151        if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
    97         *oldopts = bb_xstrdup(newopts);
     152        *oldopts = xstrdup(newopts);
    98153    }
    99154}
    100155
    101156/* Use the mount_options list to parse options into flags.
    102  * Return list of unrecognized options in *strflags if strflags!=NULL */
     157 * Also return list of unrecognized options if unrecognized!=NULL */
    103158static int parse_mount_options(char *options, char **unrecognized)
    104159{
     
    113168
    114169        // Find this option in mount_options
    115         for (i = 0; i < (sizeof(mount_options) / sizeof(*mount_options)); i++) {
     170        for (i = 0; i < ARRAY_SIZE(mount_options); i++) {
    116171            if (!strcasecmp(mount_options[i].name, options)) {
    117172                long fl = mount_options[i].flags;
    118                 if(fl < 0) flags &= fl;
     173                if (fl < 0) flags &= fl;
    119174                else flags |= fl;
    120175                break;
     
    122177        }
    123178        // If unrecognized not NULL, append unrecognized mount options */
    124         if (unrecognized
    125                 && i == (sizeof(mount_options) / sizeof(*mount_options)))
    126         {
     179        if (unrecognized && i == ARRAY_SIZE(mount_options)) {
    127180            // Add it to strflags, to pass on to kernel
    128181            i = *unrecognized ? strlen(*unrecognized) : 0;
     
    135188
    136189        // Advance to next option, or finish
    137         if(comma) {
     190        if (comma) {
    138191            *comma = ',';
    139192            options = ++comma;
     
    148201static llist_t *get_block_backed_filesystems(void)
    149202{
    150     char *fs, *buf,
    151          *filesystems[] = {"/etc/filesystems", "/proc/filesystems", 0};
     203    static const char filesystems[2][sizeof("/proc/filesystems")] = {
     204        "/etc/filesystems",
     205        "/proc/filesystems",
     206    };
     207    char *fs, *buf;
    152208    llist_t *list = 0;
    153209    int i;
    154210    FILE *f;
    155211
    156     for(i = 0; filesystems[i]; i++) {
    157         if(!(f = fopen(filesystems[i], "r"))) continue;
    158 
    159         for(fs = buf = 0; (fs = buf = bb_get_chomped_line_from_file(f));
    160             free(buf))
    161         {
    162             if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue;
    163 
    164             while(isspace(*fs)) fs++;
    165             if(*fs=='#' || *fs=='*') continue;
    166             if(!*fs) continue;
    167 
    168             llist_add_to_end(&list,bb_xstrdup(fs));
     212    for (i = 0; i < 2; i++) {
     213        f = fopen(filesystems[i], "r");
     214        if (!f) continue;
     215
     216        while ((buf = xmalloc_getline(f)) != 0) {
     217            if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
     218                continue;
     219            fs = skip_whitespace(buf);
     220            if (*fs=='#' || *fs=='*' || !*fs) continue;
     221
     222            llist_add_to_end(&list, xstrdup(fs));
     223            free(buf);
    169224        }
    170225        if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
     
    186241
    187242#if ENABLE_FEATURE_MTAB_SUPPORT
    188 static int useMtab;
     243static int useMtab = 1;
    189244static int fakeIt;
    190245#else
     
    194249
    195250// Perform actual mount of specific filesystem at specific location.
    196 
     251// NB: mp->xxx fields may be trashed on exit
    197252static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
    198253{
    199     int rc;
    200 
    201     if (fakeIt) { return 0; }
     254    int rc = 0;
     255
     256    if (fakeIt) goto mtab;
    202257
    203258    // Mount, with fallback to read-only if necessary.
    204259
    205     for(;;) {
     260    for (;;) {
    206261        rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
    207262                vfsflags, filteropts);
    208         if(!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
     263        if (!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
    209264            break;
    210265        bb_error_msg("%s is write-protected, mounting read-only",
     
    220275    /* If the mount was successful, and we're maintaining an old-style
    221276     * mtab file by hand, add the new entry to it now. */
    222 
    223     if(ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc) {
     277 mtab:
     278    if (ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
     279        char *fsname;
    224280        FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
    225281        int i;
    226282
    227         if(!mountTable)
    228             bb_error_msg("No %s\n",bb_path_mtab_file);
     283        if (!mountTable) {
     284            bb_error_msg("no %s",bb_path_mtab_file);
     285            goto ret;
     286        }
    229287
    230288        // Add vfs string flags
    231289
    232         for(i=0; mount_options[i].flags != MS_REMOUNT; i++)
    233             if (mount_options[i].flags > 0)
    234                 append_mount_options(&(mp->mnt_opts),
    235 // Shut up about the darn const.  It's not important.  I don't care.
    236                         (char *)mount_options[i].name);
     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);
    237293
    238294        // Remove trailing / (if any) from directory we mounted on
    239295
    240         i = strlen(mp->mnt_dir);
    241         if(i>1 && mp->mnt_dir[i-1] == '/') mp->mnt_dir[i-1] = 0;
     296        i = strlen(mp->mnt_dir) - 1;
     297        if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = 0;
     298
     299        // Convert to canonical pathnames as needed
     300
     301        mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
     302        fsname = 0;
     303        if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */
     304            mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
     305            mp->mnt_type = (char*)"bind";
     306        }
     307        mp->mnt_freq = mp->mnt_passno = 0;
    242308
    243309        // Write and close.
    244310
    245         if(!mp->mnt_type || !*mp->mnt_type) mp->mnt_type="--bind";
    246311        addmntent(mountTable, mp);
    247312        endmntent(mountTable);
    248         if (ENABLE_FEATURE_CLEAN_UP)
    249             if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0;
    250     }
    251 
     313        if (ENABLE_FEATURE_CLEAN_UP) {
     314            free(mp->mnt_dir);
     315            free(fsname);
     316        }
     317    }
     318 ret:
    252319    return rc;
    253320}
    254321
    255 
    256 // Mount one directory.  Handles NFS, loopback, autobind, and filesystem type
    257 // detection.  Returns 0 for success, nonzero for failure.
    258 
     322#if ENABLE_FEATURE_MOUNT_NFS
     323
     324/*
     325 * Linux NFS mount
     326 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
     327 *
     328 * Licensed under GPLv2, see file LICENSE in this tarball for details.
     329 *
     330 * Wed Feb  8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
     331 * numbers to be specified on the command line.
     332 *
     333 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
     334 * Omit the call to connect() for Linux version 1.3.11 or later.
     335 *
     336 * Wed Oct  1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
     337 * Implemented the "bg", "fg" and "retry" mount options for NFS.
     338 *
     339 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
     340 * - added Native Language Support
     341 *
     342 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
     343 * plus NFSv3 stuff.
     344 */
     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
     351
     352#define MOUNTPORT 635
     353#define MNTPATHLEN 1024
     354#define MNTNAMLEN 255
     355#define FHSIZE 32
     356#define FHSIZE3 64
     357
     358typedef char fhandle[FHSIZE];
     359
     360typedef struct {
     361    unsigned int fhandle3_len;
     362    char *fhandle3_val;
     363} fhandle3;
     364
     365enum mountstat3 {
     366    MNT_OK = 0,
     367    MNT3ERR_PERM = 1,
     368    MNT3ERR_NOENT = 2,
     369    MNT3ERR_IO = 5,
     370    MNT3ERR_ACCES = 13,
     371    MNT3ERR_NOTDIR = 20,
     372    MNT3ERR_INVAL = 22,
     373    MNT3ERR_NAMETOOLONG = 63,
     374    MNT3ERR_NOTSUPP = 10004,
     375    MNT3ERR_SERVERFAULT = 10006,
     376};
     377typedef enum mountstat3 mountstat3;
     378
     379struct fhstatus {
     380    unsigned int fhs_status;
     381    union {
     382        fhandle fhs_fhandle;
     383    } fhstatus_u;
     384};
     385typedef struct fhstatus fhstatus;
     386
     387struct mountres3_ok {
     388    fhandle3 fhandle;
     389    struct {
     390        unsigned int auth_flavours_len;
     391        char *auth_flavours_val;
     392    } auth_flavours;
     393};
     394typedef struct mountres3_ok mountres3_ok;
     395
     396struct mountres3 {
     397    mountstat3 fhs_status;
     398    union {
     399        mountres3_ok mountinfo;
     400    } mountres3_u;
     401};
     402typedef struct mountres3 mountres3;
     403
     404typedef char *dirpath;
     405
     406typedef char *name;
     407
     408typedef struct mountbody *mountlist;
     409
     410struct mountbody {
     411    name ml_hostname;
     412    dirpath ml_directory;
     413    mountlist ml_next;
     414};
     415typedef struct mountbody mountbody;
     416
     417typedef struct groupnode *groups;
     418
     419struct groupnode {
     420    name gr_name;
     421    groups gr_next;
     422};
     423typedef struct groupnode groupnode;
     424
     425typedef struct exportnode *exports;
     426
     427struct exportnode {
     428    dirpath ex_dir;
     429    groups ex_groups;
     430    exports ex_next;
     431};
     432typedef struct exportnode exportnode;
     433
     434struct ppathcnf {
     435    int pc_link_max;
     436    short pc_max_canon;
     437    short pc_max_input;
     438    short pc_name_max;
     439    short pc_path_max;
     440    short pc_pipe_buf;
     441    uint8_t pc_vdisable;
     442    char pc_xxx;
     443    short pc_mask[2];
     444};
     445typedef struct ppathcnf ppathcnf;
     446
     447#define MOUNTPROG 100005
     448#define MOUNTVERS 1
     449
     450#define MOUNTPROC_NULL 0
     451#define MOUNTPROC_MNT 1
     452#define MOUNTPROC_DUMP 2
     453#define MOUNTPROC_UMNT 3
     454#define MOUNTPROC_UMNTALL 4
     455#define MOUNTPROC_EXPORT 5
     456#define MOUNTPROC_EXPORTALL 6
     457
     458#define MOUNTVERS_POSIX 2
     459
     460#define MOUNTPROC_PATHCONF 7
     461
     462#define MOUNT_V3 3
     463
     464#define MOUNTPROC3_NULL 0
     465#define MOUNTPROC3_MNT 1
     466#define MOUNTPROC3_DUMP 2
     467#define MOUNTPROC3_UMNT 3
     468#define MOUNTPROC3_UMNTALL 4
     469#define MOUNTPROC3_EXPORT 5
     470
     471enum {
     472#ifndef NFS_FHSIZE
     473    NFS_FHSIZE = 32,
     474#endif
     475#ifndef NFS_PORT
     476    NFS_PORT = 2049
     477#endif
     478};
     479
     480/*
     481 * We want to be able to compile mount on old kernels in such a way
     482 * that the binary will work well on more recent kernels.
     483 * Thus, if necessary we teach nfsmount.c the structure of new fields
     484 * that will come later.
     485 *
     486 * Moreover, the new kernel includes conflict with glibc includes
     487 * so it is easiest to ignore the kernel altogether (at compile time).
     488 */
     489
     490struct nfs2_fh {
     491    char                    data[32];
     492};
     493struct nfs3_fh {
     494    unsigned short          size;
     495    unsigned char           data[64];
     496};
     497
     498struct nfs_mount_data {
     499    int     version;        /* 1 */
     500    int     fd;         /* 1 */
     501    struct nfs2_fh  old_root;       /* 1 */
     502    int     flags;          /* 1 */
     503    int     rsize;          /* 1 */
     504    int     wsize;          /* 1 */
     505    int     timeo;          /* 1 */
     506    int     retrans;        /* 1 */
     507    int     acregmin;       /* 1 */
     508    int     acregmax;       /* 1 */
     509    int     acdirmin;       /* 1 */
     510    int     acdirmax;       /* 1 */
     511    struct sockaddr_in addr;        /* 1 */
     512    char        hostname[256];      /* 1 */
     513    int     namlen;         /* 2 */
     514    unsigned int    bsize;          /* 3 */
     515    struct nfs3_fh  root;           /* 4 */
     516};
     517
     518/* bits in the flags field */
     519enum {
     520    NFS_MOUNT_SOFT = 0x0001,    /* 1 */
     521    NFS_MOUNT_INTR = 0x0002,    /* 1 */
     522    NFS_MOUNT_SECURE = 0x0004,  /* 1 */
     523    NFS_MOUNT_POSIX = 0x0008,   /* 1 */
     524    NFS_MOUNT_NOCTO = 0x0010,   /* 1 */
     525    NFS_MOUNT_NOAC = 0x0020,    /* 1 */
     526    NFS_MOUNT_TCP = 0x0040,     /* 2 */
     527    NFS_MOUNT_VER3 = 0x0080,    /* 3 */
     528    NFS_MOUNT_KERBEROS = 0x0100,    /* 3 */
     529    NFS_MOUNT_NONLM = 0x0200    /* 3 */
     530};
     531
     532
     533/*
     534 * We need to translate between nfs status return values and
     535 * the local errno values which may not be the same.
     536 *
     537 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
     538 * "after #include <errno.h> the symbol errno is reserved for any use,
     539 *  it cannot even be used as a struct tag or field name".
     540 */
     541
     542#ifndef EDQUOT
     543#define EDQUOT  ENOSPC
     544#endif
     545
     546// Convert each NFSERR_BLAH into EBLAH
     547
     548static 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}
     556};
     557
     558static char *nfs_strerror(int status)
     559{
     560    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;
     569}
     570
     571static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
     572{
     573    if (!xdr_opaque(xdrs, objp, FHSIZE))
     574         return FALSE;
     575    return TRUE;
     576}
     577
     578static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
     579{
     580    if (!xdr_u_int(xdrs, &objp->fhs_status))
     581         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    }
     590    return TRUE;
     591}
     592
     593static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
     594{
     595    if (!xdr_string(xdrs, objp, MNTPATHLEN))
     596         return FALSE;
     597    return TRUE;
     598}
     599
     600static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
     601{
     602    if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
     603         return FALSE;
     604    return TRUE;
     605}
     606
     607static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
     608{
     609    if (!xdr_fhandle3(xdrs, &objp->fhandle))
     610        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;
     615}
     616
     617static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
     618{
     619    if (!xdr_enum(xdrs, (enum_t *) objp))
     620         return FALSE;
     621    return TRUE;
     622}
     623
     624static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
     625{
     626    if (!xdr_mountstat3(xdrs, &objp->fhs_status))
     627        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    }
     636    return TRUE;
     637}
     638
     639#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
     640
     641/*
     642 * nfs_mount_version according to the sources seen at compile time.
     643 */
     644static int nfs_mount_version;
     645static int kernel_version;
     646
     647/*
     648 * Unfortunately, the kernel prints annoying console messages
     649 * in case of an unexpected nfs mount version (instead of
     650 * just returning some error).  Therefore we'll have to try
     651 * and figure out what version the kernel expects.
     652 *
     653 * Variables:
     654 *  KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
     655 *  NFS_MOUNT_VERSION: these nfsmount sources at compile time
     656 *  nfs_mount_version: version this source and running kernel can handle
     657 */
     658static void
     659find_kernel_nfs_mount_version(void)
     660{
     661    if (kernel_version)
     662        return;
     663
     664    nfs_mount_version = 4; /* default */
     665
     666    kernel_version = get_linux_version_code();
     667    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)))
     673            nfs_mount_version = 3;
     674        /* else v4 since 2.3.99pre4 */
     675    }
     676}
     677
     678static struct pmap *
     679get_mountport(struct sockaddr_in *server_addr,
     680    long unsigned prog,
     681    long unsigned version,
     682    long unsigned proto,
     683    long unsigned port)
     684{
     685    struct pmaplist *pmap;
     686    static struct pmap p = {0, 0, 0, 0};
     687
     688    server_addr->sin_port = PMAPPORT;
     689/* glibc 2.4 (still) has pmap_getmaps(struct sockaddr_in *).
     690 * I understand it like "IPv6 for this is not 100% ready" */
     691    pmap = pmap_getmaps(server_addr);
     692
     693    if (version > MAX_NFSPROT)
     694        version = MAX_NFSPROT;
     695    if (!prog)
     696        prog = MOUNTPROG;
     697    p.pm_prog = prog;
     698    p.pm_vers = version;
     699    p.pm_prot = proto;
     700    p.pm_port = port;
     701
     702    while (pmap) {
     703        if (pmap->pml_map.pm_prog != prog)
     704            goto next;
     705        if (!version && p.pm_vers > pmap->pml_map.pm_vers)
     706            goto next;
     707        if (version > 2 && pmap->pml_map.pm_vers != version)
     708            goto next;
     709        if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
     710            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))
     714            goto next;
     715        memcpy(&p, &pmap->pml_map, sizeof(p));
     716next:
     717        pmap = pmap->pml_next;
     718    }
     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
     728static int daemonize(void)
     729{
     730    int fd;
     731    int pid = fork();
     732    if (pid < 0) /* error */
     733        return -errno;
     734    if (pid > 0) /* parent */
     735        return 0;
     736    /* 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--);
     742    setsid();
     743    openlog(applet_name, LOG_PID, LOG_DAEMON);
     744    logmode = LOGMODE_SYSLOG;
     745    return 1;
     746}
     747
     748// TODO
     749static inline int we_saw_this_host_before(const char *hostname)
     750{
     751    return 0;
     752}
     753
     754/* RPC strerror analogs are terminally idiotic:
     755 * *mandatory* prefix and \n at end.
     756 * This hopefully helps. Usage:
     757 * error_msg_rpc(clnt_*error*(" ")) */
     758static void error_msg_rpc(const char *msg)
     759{
     760    int len;
     761    while (msg[0] == ' ' || msg[0] == ':') msg++;
     762    len = strlen(msg);
     763    while (len && msg[len-1] == '\n') len--;
     764    bb_error_msg("%.*s", len, msg);
     765}
     766
     767// NB: mp->xxx fields may be trashed on exit
     768static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)
     769{
     770    CLIENT *mclient;
     771    char *hostname;
     772    char *pathname;
     773    char *mounthost;
     774    struct nfs_mount_data data;
     775    char *opt;
     776    struct hostent *hp;
     777    struct sockaddr_in server_addr;
     778    struct sockaddr_in mount_server_addr;
     779    int msock, fsock;
     780    union {
     781        struct fhstatus nfsv2;
     782        struct mountres3 nfsv3;
     783    } status;
     784    int daemonized;
     785    char *s;
     786    int port;
     787    int mountport;
     788    int proto;
     789    int bg;
     790    int soft;
     791    int intr;
     792    int posix;
     793    int nocto;
     794    int noac;
     795    int nolock;
     796    int retry;
     797    int tcp;
     798    int mountprog;
     799    int mountvers;
     800    int nfsprog;
     801    int nfsvers;
     802    int retval;
     803
     804    find_kernel_nfs_mount_version();
     805
     806    daemonized = 0;
     807    mounthost = NULL;
     808    retval = ETIMEDOUT;
     809    msock = fsock = -1;
     810    mclient = NULL;
     811
     812    /* NB: hostname, mounthost, filteropts must be free()d prior to return */
     813
     814    filteropts = xstrdup(filteropts); /* going to trash it later... */
     815
     816    hostname = xstrdup(mp->mnt_fsname);
     817    /* mount_main() guarantees that ':' is there */
     818    s = strchr(hostname, ':');
     819    pathname = s + 1;
     820    *s = '\0';
     821    /* Ignore all but first hostname in replicated mounts
     822       until they can be fully supported. (mack@sgi.com) */
     823    s = strchr(hostname, ',');
     824    if (s) {
     825        *s = '\0';
     826        bb_error_msg("warning: multiple hostnames not supported");
     827    }
     828
     829    server_addr.sin_family = AF_INET;
     830    if (!inet_aton(hostname, &server_addr.sin_addr)) {
     831        hp = gethostbyname(hostname);
     832        if (hp == NULL) {
     833            bb_herror_msg("%s", hostname);
     834            goto fail;
     835        }
     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);
     842    }
     843
     844    memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
     845
     846    /* add IP address to mtab options for use when unmounting */
     847
     848    if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
     849        mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
     850    } else {
     851        char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
     852                    mp->mnt_opts[0] ? "," : "",
     853                    inet_ntoa(server_addr.sin_addr));
     854        free(mp->mnt_opts);
     855        mp->mnt_opts = tmp;
     856    }
     857
     858    /* Set default options.
     859     * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
     860     * let the kernel decide.
     861     * timeo is filled in after we know whether it'll be TCP or UDP. */
     862    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;
     871    soft = 0;
     872    intr = 0;
     873    posix = 0;
     874    nocto = 0;
     875    nolock = 0;
     876    noac = 0;
     877    retry = 10000;      /* 10000 minutes ~ 1 week */
     878    tcp = 0;
     879
     880    mountprog = MOUNTPROG;
     881    mountvers = 0;
     882    port = 0;
     883    mountport = 0;
     884    nfsprog = 100003;
     885    nfsvers = 0;
     886
     887    /* parse options */
     888    if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
     889        char *opteq = strchr(opt, '=');
     890        if (opteq) {
     891            static const char options[] ALIGN1 =
     892                /* 0 */ "rsize\0"
     893                /* 1 */ "wsize\0"
     894                /* 2 */ "timeo\0"
     895                /* 3 */ "retrans\0"
     896                /* 4 */ "acregmin\0"
     897                /* 5 */ "acregmax\0"
     898                /* 6 */ "acdirmin\0"
     899                /* 7 */ "acdirmax\0"
     900                /* 8 */ "actimeo\0"
     901                /* 9 */ "retry\0"
     902                /* 10 */ "port\0"
     903                /* 11 */ "mountport\0"
     904                /* 12 */ "mounthost\0"
     905                /* 13 */ "mountprog\0"
     906                /* 14 */ "mountvers\0"
     907                /* 15 */ "nfsprog\0"
     908                /* 16 */ "nfsvers\0"
     909                /* 17 */ "vers\0"
     910                /* 18 */ "proto\0"
     911                /* 19 */ "namlen\0"
     912                /* 20 */ "addr\0";
     913            int val = xatoi_u(opteq + 1);
     914            *opteq = '\0';
     915            switch (index_in_strings(options, opt)) {
     916            case 0: // "rsize"
     917                data.rsize = val;
     918                break;
     919            case 1: // "wsize"
     920                data.wsize = val;
     921                break;
     922            case 2: // "timeo"
     923                data.timeo = val;
     924                break;
     925            case 3: // "retrans"
     926                data.retrans = val;
     927                break;
     928            case 4: // "acregmin"
     929                data.acregmin = val;
     930                break;
     931            case 5: // "acregmax"
     932                data.acregmax = val;
     933                break;
     934            case 6: // "acdirmin"
     935                data.acdirmin = val;
     936                break;
     937            case 7: // "acdirmax"
     938                data.acdirmax = val;
     939                break;
     940            case 8: // "actimeo"
     941                data.acregmin = val;
     942                data.acregmax = val;
     943                data.acdirmin = val;
     944                data.acdirmax = val;
     945                break;
     946            case 9: // "retry"
     947                retry = val;
     948                break;
     949            case 10: // "port"
     950                port = val;
     951                break;
     952            case 11: // "mountport"
     953                mountport = val;
     954                break;
     955            case 12: // "mounthost"
     956                mounthost = xstrndup(opteq+1,
     957                        strcspn(opteq+1," \t\n\r,"));
     958                break;
     959            case 13: // "mountprog"
     960                mountprog = val;
     961                break;
     962            case 14: // "mountvers"
     963                mountvers = val;
     964                break;
     965            case 15: // "nfsprog"
     966                nfsprog = val;
     967                break;
     968            case 16: // "nfsvers"
     969            case 17: // "vers"
     970                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;
     980            case 19: // "namlen"
     981                if (nfs_mount_version >= 2)
     982                    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;
     988            default:
     989                bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
     990                goto fail;
     991            }
     992        }
     993        else {
     994            static const char options[] ALIGN1 =
     995                "bg\0"
     996                "fg\0"
     997                "soft\0"
     998                "hard\0"
     999                "intr\0"
     1000                "posix\0"
     1001                "cto\0"
     1002                "ac\0"
     1003                "tcp\0"
     1004                "udp\0"
     1005                "lock\0";
     1006            int val = 1;
     1007            if (!strncmp(opt, "no", 2)) {
     1008                val = 0;
     1009                opt += 2;
     1010            }
     1011            switch (index_in_strings(options, opt)) {
     1012            case 0: // "bg"
     1013                bg = val;
     1014                break;
     1015            case 1: // "fg"
     1016                bg = !val;
     1017                break;
     1018            case 2: // "soft"
     1019                soft = val;
     1020                break;
     1021            case 3: // "hard"
     1022                soft = !val;
     1023                break;
     1024            case 4: // "intr"
     1025                intr = val;
     1026                break;
     1027            case 5: // "posix"
     1028                posix = val;
     1029                break;
     1030            case 6: // "cto"
     1031                nocto = !val;
     1032                break;
     1033            case 7: // "ac"
     1034                noac = !val;
     1035                break;
     1036            case 8: // "tcp"
     1037                tcp = val;
     1038                break;
     1039            case 9: // "udp"
     1040                tcp = !val;
     1041                break;
     1042            case 10: // "lock"
     1043                if (nfs_mount_version >= 3)
     1044                    nolock = !val;
     1045                else
     1046                    bb_error_msg("warning: option nolock is not supported");
     1047                break;
     1048            default:
     1049                bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
     1050                goto fail;
     1051            }
     1052        }
     1053    }
     1054    proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
     1055
     1056    data.flags = (soft ? NFS_MOUNT_SOFT : 0)
     1057        | (intr ? NFS_MOUNT_INTR : 0)
     1058        | (posix ? NFS_MOUNT_POSIX : 0)
     1059        | (nocto ? NFS_MOUNT_NOCTO : 0)
     1060        | (noac ? NFS_MOUNT_NOAC : 0);
     1061    if (nfs_mount_version >= 2)
     1062        data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
     1063    if (nfs_mount_version >= 3)
     1064        data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
     1065    if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
     1066        bb_error_msg("NFSv%d not supported", nfsvers);
     1067        goto fail;
     1068    }
     1069    if (nfsvers && !mountvers)
     1070        mountvers = (nfsvers < 3) ? 1 : nfsvers;
     1071    if (nfsvers && nfsvers < mountvers) {
     1072        mountvers = nfsvers;
     1073    }
     1074
     1075    /* Adjust options if none specified */
     1076    if (!data.timeo)
     1077        data.timeo = tcp ? 70 : 7;
     1078
     1079    data.version = nfs_mount_version;
     1080
     1081    if (vfsflags & MS_REMOUNT)
     1082        goto do_mount;
     1083
     1084    /*
     1085     * If the previous mount operation on the same host was
     1086     * backgrounded, and the "bg" for this mount is also set,
     1087     * give up immediately, to avoid the initial timeout.
     1088     */
     1089    if (bg && we_saw_this_host_before(hostname)) {
     1090        daemonized = daemonize(); /* parent or error */
     1091        if (daemonized <= 0) { /* parent or error */
     1092            retval = -daemonized;
     1093            goto ret;
     1094        }
     1095    }
     1096
     1097    /* create mount daemon client */
     1098    /* See if the nfs host = mount host. */
     1099    if (mounthost) {
     1100        if (mounthost[0] >= '0' && mounthost[0] <= '9') {
     1101            mount_server_addr.sin_family = AF_INET;
     1102            mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
     1103        } else {
     1104            hp = gethostbyname(mounthost);
     1105            if (hp == NULL) {
     1106                bb_herror_msg("%s", mounthost);
     1107                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);
     1116            }
     1117        }
     1118    }
     1119
     1120    /*
     1121     * The following loop implements the mount retries. When the mount
     1122     * times out, and the "bg" option is set, we background ourself
     1123     * and continue trying.
     1124     *
     1125     * The case where the mount point is not present and the "bg"
     1126     * option is set, is treated as a timeout. This is done to
     1127     * support nested mounts.
     1128     *
     1129     * The "retry" count specified by the user is the number of
     1130     * minutes to retry before giving up.
     1131     */
     1132    {
     1133        struct timeval total_timeout;
     1134        struct timeval retry_timeout;
     1135        struct pmap* pm_mnt;
     1136        time_t t;
     1137        time_t prevt;
     1138        time_t timeout;
     1139
     1140        retry_timeout.tv_sec = 3;
     1141        retry_timeout.tv_usec = 0;
     1142        total_timeout.tv_sec = 20;
     1143        total_timeout.tv_usec = 0;
     1144        timeout = time(NULL) + 60 * retry;
     1145        prevt = 0;
     1146        t = 30;
     1147retry:
     1148        /* be careful not to use too many CPU cycles */
     1149        if (t - prevt < 30)
     1150            sleep(30);
     1151
     1152        pm_mnt = get_mountport(&mount_server_addr,
     1153                mountprog,
     1154                mountvers,
     1155                proto,
     1156                mountport);
     1157        nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
     1158
     1159        /* contact the mount daemon via TCP */
     1160        mount_server_addr.sin_port = htons(pm_mnt->pm_port);
     1161        msock = RPC_ANYSOCK;
     1162
     1163        switch (pm_mnt->pm_prot) {
     1164        case IPPROTO_UDP:
     1165            mclient = clntudp_create(&mount_server_addr,
     1166                         pm_mnt->pm_prog,
     1167                         pm_mnt->pm_vers,
     1168                         retry_timeout,
     1169                         &msock);
     1170            if (mclient)
     1171                break;
     1172            mount_server_addr.sin_port = htons(pm_mnt->pm_port);
     1173            msock = RPC_ANYSOCK;
     1174        case IPPROTO_TCP:
     1175            mclient = clnttcp_create(&mount_server_addr,
     1176                         pm_mnt->pm_prog,
     1177                         pm_mnt->pm_vers,
     1178                         &msock, 0, 0);
     1179            break;
     1180        default:
     1181            mclient = 0;
     1182        }
     1183        if (!mclient) {
     1184            if (!daemonized && prevt == 0)
     1185                error_msg_rpc(clnt_spcreateerror(" "));
     1186        } else {
     1187            enum clnt_stat clnt_stat;
     1188            /* try to mount hostname:pathname */
     1189            mclient->cl_auth = authunix_create_default();
     1190
     1191            /* make pointers in xdr_mountres3 NULL so
     1192             * that xdr_array allocates memory for us
     1193             */
     1194            memset(&status, 0, sizeof(status));
     1195
     1196            if (pm_mnt->pm_vers == 3)
     1197                clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
     1198                          (xdrproc_t) xdr_dirpath,
     1199                          (caddr_t) &pathname,
     1200                          (xdrproc_t) xdr_mountres3,
     1201                          (caddr_t) &status,
     1202                          total_timeout);
     1203            else
     1204                clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
     1205                          (xdrproc_t) xdr_dirpath,
     1206                          (caddr_t) &pathname,
     1207                          (xdrproc_t) xdr_fhstatus,
     1208                          (caddr_t) &status,
     1209                          total_timeout);
     1210
     1211            if (clnt_stat == RPC_SUCCESS)
     1212                goto prepare_kernel_data; /* we're done */
     1213            if (errno != ECONNREFUSED) {
     1214                error_msg_rpc(clnt_sperror(mclient, " "));
     1215                goto fail;  /* don't retry */
     1216            }
     1217            /* Connection refused */
     1218            if (!daemonized && prevt == 0) /* print just once */
     1219                error_msg_rpc(clnt_sperror(mclient, " "));
     1220            auth_destroy(mclient->cl_auth);
     1221            clnt_destroy(mclient);
     1222            mclient = 0;
     1223            close(msock);
     1224        }
     1225
     1226        /* Timeout. We are going to retry... maybe */
     1227
     1228        if (!bg)
     1229            goto fail;
     1230        if (!daemonized) {
     1231            daemonized = daemonize();
     1232            if (daemonized <= 0) { /* parent or error */
     1233                retval = -daemonized;
     1234                goto ret;
     1235            }
     1236        }
     1237        prevt = t;
     1238        t = time(NULL);
     1239        if (t >= timeout)
     1240            /* TODO error message */
     1241            goto fail;
     1242
     1243        goto retry;
     1244    }
     1245
     1246prepare_kernel_data:
     1247
     1248    if (nfsvers == 2) {
     1249        if (status.nfsv2.fhs_status != 0) {
     1250            bb_error_msg("%s:%s failed, reason given by server: %s",
     1251                hostname, pathname,
     1252                nfs_strerror(status.nfsv2.fhs_status));
     1253            goto fail;
     1254        }
     1255        memcpy(data.root.data,
     1256                (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
     1257                NFS_FHSIZE);
     1258        data.root.size = NFS_FHSIZE;
     1259        memcpy(data.old_root.data,
     1260                (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
     1261                NFS_FHSIZE);
     1262    } else {
     1263        fhandle3 *my_fhandle;
     1264        if (status.nfsv3.fhs_status != 0) {
     1265            bb_error_msg("%s:%s failed, reason given by server: %s",
     1266                hostname, pathname,
     1267                nfs_strerror(status.nfsv3.fhs_status));
     1268            goto fail;
     1269        }
     1270        my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
     1271        memset(data.old_root.data, 0, NFS_FHSIZE);
     1272        memset(&data.root, 0, sizeof(data.root));
     1273        data.root.size = my_fhandle->fhandle3_len;
     1274        memcpy(data.root.data,
     1275                (char *) my_fhandle->fhandle3_val,
     1276                my_fhandle->fhandle3_len);
     1277
     1278        data.flags |= NFS_MOUNT_VER3;
     1279    }
     1280
     1281    /* create nfs socket for kernel */
     1282
     1283    if (tcp) {
     1284        if (nfs_mount_version < 3) {
     1285            bb_error_msg("NFS over TCP is not supported");
     1286            goto fail;
     1287        }
     1288        fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     1289    } else
     1290        fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     1291    if (fsock < 0) {
     1292        bb_perror_msg("nfs socket");
     1293        goto fail;
     1294    }
     1295    if (bindresvport(fsock, 0) < 0) {
     1296        bb_perror_msg("nfs bindresvport");
     1297        goto fail;
     1298    }
     1299    if (port == 0) {
     1300        server_addr.sin_port = PMAPPORT;
     1301        port = pmap_getport(&server_addr, nfsprog, nfsvers,
     1302                    tcp ? IPPROTO_TCP : IPPROTO_UDP);
     1303        if (port == 0)
     1304            port = NFS_PORT;
     1305    }
     1306    server_addr.sin_port = htons(port);
     1307
     1308    /* prepare data structure for kernel */
     1309
     1310    data.fd = fsock;
     1311    memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
     1312    strncpy(data.hostname, hostname, sizeof(data.hostname));
     1313
     1314    /* clean up */
     1315
     1316    auth_destroy(mclient->cl_auth);
     1317    clnt_destroy(mclient);
     1318    close(msock);
     1319
     1320    if (bg) {
     1321        /* We must wait until mount directory is available */
     1322        struct stat statbuf;
     1323        int delay = 1;
     1324        while (stat(mp->mnt_dir, &statbuf) == -1) {
     1325            if (!daemonized) {
     1326                daemonized = daemonize();
     1327                if (daemonized <= 0) { /* parent or error */
     1328                    retval = -daemonized;
     1329                    goto ret;
     1330                }
     1331            }
     1332            sleep(delay);   /* 1, 2, 4, 8, 16, 30, ... */
     1333            delay *= 2;
     1334            if (delay > 30)
     1335                delay = 30;
     1336        }
     1337    }
     1338
     1339do_mount: /* perform actual mount */
     1340
     1341    mp->mnt_type = (char*)"nfs";
     1342    retval = mount_it_now(mp, vfsflags, (char*)&data);
     1343    goto ret;
     1344
     1345fail:   /* abort */
     1346
     1347    if (msock != -1) {
     1348        if (mclient) {
     1349            auth_destroy(mclient->cl_auth);
     1350            clnt_destroy(mclient);
     1351        }
     1352        close(msock);
     1353    }
     1354    if (fsock != -1)
     1355        close(fsock);
     1356
     1357ret:
     1358    free(hostname);
     1359    free(mounthost);
     1360    free(filteropts);
     1361    return retval;
     1362}
     1363
     1364#else /* !ENABLE_FEATURE_MOUNT_NFS */
     1365
     1366/* Never called. Call should be optimized out. */
     1367int nfsmount(struct mntent *mp, int vfsflags, char *filteropts);
     1368
     1369#endif /* !ENABLE_FEATURE_MOUNT_NFS */
     1370
     1371// Mount one directory.  Handles CIFS, NFS, loopback, autobind, and filesystem
     1372// type detection.  Returns 0 for success, nonzero for failure.
     1373// NB: mp->xxx fields may be trashed on exit
    2591374static int singlemount(struct mntent *mp, int ignore_busy)
    2601375{
     
    2681383    // Treat fstype "auto" as unspecified.
    2691384
    270     if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0;
     1385    if (mp->mnt_type && strcmp(mp->mnt_type,"auto") == 0)
     1386        mp->mnt_type = 0;
     1387
     1388    // Might this be an CIFS filesystem?
     1389
     1390    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]
     1394    ) {
     1395        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);
     1417        ip = xasprintf("ip=%s", dotted);
     1418        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
     1426        vfsflags |= MS_MANDLOCK;
     1427
     1428        mp->mnt_type = (char*)"cifs";
     1429        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        }
     1436        goto report_error;
     1437    }
    2711438
    2721439    // Might this be an NFS filesystem?
    2731440
    274     if (ENABLE_FEATURE_MOUNT_NFS &&
    275         (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&
    276         strchr(mp->mnt_fsname, ':') != NULL)
    277     {
    278         if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &filteropts, 1)) {
    279             bb_perror_msg("nfsmount failed");
    280             goto report_error;
    281         } else {
    282             // Strangely enough, nfsmount() doesn't actually mount() anything.
    283             mp->mnt_type = "nfs";
    284             rc = mount_it_now(mp, vfsflags, filteropts);
    285             if (ENABLE_FEATURE_CLEAN_UP) free(filteropts);
    286            
    287             goto report_error;
    288         }
     1441    if (ENABLE_FEATURE_MOUNT_NFS
     1442     && (!mp->mnt_type || !strcmp(mp->mnt_type, "nfs"))
     1443     && strchr(mp->mnt_fsname, ':') != NULL
     1444    ) {
     1445        rc = nfsmount(mp, vfsflags, filteropts);
     1446        goto report_error;
    2891447    }
    2901448
    2911449    // Look at the file.  (Not found isn't a failure for remount, or for
    2921450    // a synthetic filesystem like proc or sysfs.)
    293 
    294     if (stat(mp->mnt_fsname, &st));
    295     else if (!(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
     1451    // (We use stat, not lstat, in order to allow
     1452    // mount symlink_to_file_or_blkdev dir)
     1453
     1454    if (!stat(mp->mnt_fsname, &st)
     1455     && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))
     1456    ) {
    2961457        // Do we need to allocate a loopback device for it?
    2971458
    2981459        if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
    2991460            loopFile = bb_simplify_path(mp->mnt_fsname);
    300             mp->mnt_fsname = 0;
    301             switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) {
    302                 case 0:
    303                 case 1:
    304                     break;
    305                 default:
    306                     bb_error_msg( errno == EPERM || errno == EACCES
    307                         ? bb_msg_perm_denied_are_you_root
    308                         : "Couldn't setup loop device");
    309                     return errno;
     1461            mp->mnt_fsname = NULL; /* will receive malloced loop dev name */
     1462            if (set_loop(&(mp->mnt_fsname), loopFile, 0) < 0) {
     1463                if (errno == EPERM || errno == EACCES)
     1464                    bb_error_msg(bb_msg_perm_denied_are_you_root);
     1465                else
     1466                    bb_perror_msg("cannot setup loop device");
     1467                return errno;
    3101468            }
    3111469
    3121470        // Autodetect bind mounts
    3131471
    314         } else if (S_ISDIR(st.st_mode) && !mp->mnt_type) vfsflags |= MS_BIND;
     1472        } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
     1473            vfsflags |= MS_BIND;
    3151474    }
    3161475
     
    3201479    if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
    3211480        rc = mount_it_now(mp, vfsflags, filteropts);
    322 
    323     // Loop through filesystem types until mount succeeds or we run out
    324 
    3251481    else {
     1482        // Loop through filesystem types until mount succeeds
     1483        // or we run out
    3261484
    3271485        /* Initialize list of block backed filesystems.  This has to be
     
    3371495        for (fl = fslist; fl; fl = fl->link) {
    3381496            mp->mnt_type = fl->data;
    339 
    340             if (!(rc = mount_it_now(mp,vfsflags, filteropts))) break;
    341 
    342             mp->mnt_type = 0;
    343         }
    344     }
    345 
    346     if (ENABLE_FEATURE_CLEAN_UP) free(filteropts);
     1497            rc = mount_it_now(mp, vfsflags, filteropts);
     1498            if (!rc) break;
     1499        }
     1500    }
    3471501
    3481502    // If mount failed, clean up loop file (if any).
     
    3551509        }
    3561510    }
    357 report_error:
    358     if (rc && errno == EBUSY && ignore_busy) rc = 0;
     1511
     1512 report_error:
     1513    if (ENABLE_FEATURE_CLEAN_UP)
     1514        free(filteropts);
     1515
     1516    if (rc && errno == EBUSY && ignore_busy)
     1517        rc = 0;
    3591518    if (rc < 0)
    360         bb_perror_msg("Mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
     1519        bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
    3611520
    3621521    return rc;
     
    3661525// each directory to be mounted.
    3671526
     1527static const char must_be_root[] ALIGN1 = "you must be root";
     1528
     1529int mount_main(int argc, char **argv);
    3681530int mount_main(int argc, char **argv)
    3691531{
    370     char *cmdopts = bb_xstrdup(""), *fstabname, *fstype=0, *storage_path=0;
     1532    enum { OPT_ALL = 0x10 };
     1533
     1534    char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0;
     1535    char *opt_o;
     1536    const char *fstabname;
    3711537    FILE *fstab;
    372     int i, opt, all = FALSE, rc = 0;
     1538    int i, j, rc = 0;
     1539    unsigned opt;
    3731540    struct mntent mtpair[2], *mtcur = mtpair;
     1541    SKIP_DESKTOP(const int nonroot = 0;)
     1542    USE_DESKTOP( int nonroot = (getuid() != 0);)
    3741543
    3751544    /* parse long options, like --bind and --move.  Note that -o option
    3761545     * and --option are synonymous.  Yes, this means --remount,rw works. */
    3771546
    378     for (i = opt = 0; i < argc; i++) {
     1547    for (i = j = 0; i < argc; i++) {
    3791548        if (argv[i][0] == '-' && argv[i][1] == '-') {
    380             append_mount_options(&cmdopts,argv[i]+2);
    381         } else argv[opt++] = argv[i];
    382     }
    383     argc = opt;
     1549            append_mount_options(&cmdopts, argv[i]+2);
     1550        } else argv[j++] = argv[i];
     1551    }
     1552    argv[j] = 0;
     1553    argc = j;
    3841554
    3851555    // Parse remaining options
    3861556
    387     while ((opt = getopt(argc, argv, "o:t:rwavnf")) > 0) {
    388         switch (opt) {
    389             case 'o':
    390                 append_mount_options(&cmdopts, optarg);
    391                 break;
    392             case 't':
    393                 fstype = optarg;
    394                 break;
    395             case 'r':
    396                 append_mount_options(&cmdopts, "ro");
    397                 break;
    398             case 'w':
    399                 append_mount_options(&cmdopts, "rw");
    400                 break;
    401             case 'a':
    402                 all = TRUE;
    403                 break;
    404             case 'n':
    405                 USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;)
    406                 break;
    407             case 'f':
    408                 USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;)
    409                 break;
    410             case 'v':
    411                 break;      // ignore -v
    412             default:
    413                 bb_show_usage();
    414         }
    415     }
     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)
     1567    argv += optind;
     1568    argc -= optind;
    4161569
    4171570    // Three or more non-option arguments?  Die with a usage message.
    4181571
    419     if (optind-argc>2) bb_show_usage();
     1572    if (argc > 2) bb_show_usage();
    4201573
    4211574    // If we have no arguments, show currently mounted filesystems
    4221575
    423     if (optind == argc) {
    424         if (!all) {
     1576    if (!argc) {
     1577        if (!(opt & OPT_ALL)) {
    4251578            FILE *mountTable = setmntent(bb_path_mtab_file, "r");
    4261579
    427             if(!mountTable) bb_error_msg_and_die("No %s",bb_path_mtab_file);
    428 
    429             while (getmntent_r(mountTable,mtpair,bb_common_bufsiz1,
     1580            if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file);
     1581
     1582            while (getmntent_r(mountTable, mtpair, bb_common_bufsiz1,
    4301583                                sizeof(bb_common_bufsiz1)))
    4311584            {
    432                 // Don't show rootfs.
    433                 if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
     1585                // Don't show rootfs. FIXME: why??
     1586                // util-linux 2.12a happily shows rootfs...
     1587                //if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
    4341588
    4351589                if (!fstype || !strcmp(mtpair->mnt_type, fstype))
     
    4411595            return EXIT_SUCCESS;
    4421596        }
    443     }
     1597    } else storage_path = bb_simplify_path(argv[0]);
    4441598
    4451599    // When we have two arguments, the second is the directory and we can
     
    4471601    // argument when we get it.
    4481602
    449     if (optind+2 == argc) {
    450         mtpair->mnt_fsname = argv[optind];
    451         mtpair->mnt_dir = argv[optind+1];
     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];
    4521608        mtpair->mnt_type = fstype;
    4531609        mtpair->mnt_opts = cmdopts;
     
    4561612    }
    4571613
    458     // If we have at least one argument, it's the storage location
    459 
    460     if (optind < argc) storage_path = bb_simplify_path(argv[optind]);
     1614    i = parse_mount_options(cmdopts, 0);
     1615    if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
     1616        bb_error_msg_and_die(must_be_root);
     1617
     1618    // If we have a shared subtree flag, don't worry about fstab or mtab.
     1619
     1620    if (ENABLE_FEATURE_MOUNT_FLAGS
     1621     && (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE))
     1622    ) {
     1623        rc = mount("", argv[0], "", i, "");
     1624        if (rc) bb_perror_msg_and_die("%s", argv[0]);
     1625        goto clean_up;
     1626    }
    4611627
    4621628    // Open either fstab or mtab
    4631629
    464     if (parse_mount_options(cmdopts,0) & MS_REMOUNT)
    465         fstabname = (char *)bb_path_mtab_file;  // Again with the evil const.
    466     else fstabname="/etc/fstab";
    467 
    468     if (!(fstab=setmntent(fstabname,"r")))
    469         bb_perror_msg_and_die("Cannot read %s",fstabname);
     1630    fstabname = "/etc/fstab";
     1631    if (i & MS_REMOUNT) {
     1632        fstabname = bb_path_mtab_file;
     1633    }
     1634    fstab = setmntent(fstabname, "r");
     1635    if (!fstab)
     1636        bb_perror_msg_and_die("cannot read %s", fstabname);
    4701637
    4711638    // Loop through entries until we find what we're looking for.
    4721639
    473     memset(mtpair,0,sizeof(mtpair));
     1640    memset(mtpair, 0, sizeof(mtpair));
    4741641    for (;;) {
    475         struct mntent *mtnext = mtpair + (mtcur==mtpair ? 1 : 0);
     1642        struct mntent *mtnext = (mtcur==mtpair ? mtpair+1 : mtpair);
    4761643
    4771644        // Get next fstab entry
     
    4831650            // Were we looking for something specific?
    4841651
    485             if (optind != argc) {
     1652            if (argc) {
    4861653
    4871654                // If we didn't find anything, complain.
    4881655
    4891656                if (!mtnext->mnt_fsname)
    490                     bb_error_msg_and_die("Can't find %s in %s",
    491                         argv[optind], fstabname);
     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                }
    4921666
    4931667                // Mount the last thing we found.
    4941668
    495                 mtcur = mtnext;
    496                 mtcur->mnt_opts=bb_xstrdup(mtcur->mnt_opts);
    497                 append_mount_options(&(mtcur->mnt_opts),cmdopts);
     1669                mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
     1670                append_mount_options(&(mtcur->mnt_opts), cmdopts);
    4981671                rc = singlemount(mtcur, 0);
    4991672                free(mtcur->mnt_opts);
     
    5061679         * "proc") or a full path from root */
    5071680
    508         if (optind != argc) {
     1681        if (argc) {
    5091682
    5101683            // Is this what we're looking for?
    5111684
    512             if(strcmp(argv[optind],mtcur->mnt_fsname) &&
    513                strcmp(storage_path,mtcur->mnt_fsname) &&
    514                strcmp(argv[optind],mtcur->mnt_dir) &&
    515                strcmp(storage_path,mtcur->mnt_dir)) continue;
     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;
    5161689
    5171690            // Remember this entry.  Something later may have overmounted
     
    5231696
    5241697        } else {
    525 
    5261698            // Do we need to match a filesystem type?
    527             if (fstype && strcmp(mtcur->mnt_type,fstype)) continue;
     1699            if (fstype && match_fstype(mtcur, fstype)) continue;
    5281700
    5291701            // Skip noauto and swap anyway.
    5301702
    531             if (parse_mount_options(mtcur->mnt_opts,0)
     1703            if (parse_mount_options(mtcur->mnt_opts, 0)
    5321704                & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
    5331705
     1706            // No, mount -a won't mount anything,
     1707            // even user mounts, for mere humans.
     1708
     1709            if (nonroot)
     1710                bb_error_msg_and_die(must_be_root);
     1711
    5341712            // Mount this thing.
    5351713
     1714            // NFS mounts want this to be xrealloc-able
     1715            mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
    5361716            if (singlemount(mtcur, 1)) {
    5371717                /* Count number of failed mounts */
    5381718                rc++;
    5391719            }
     1720            free(mtcur->mnt_opts);
    5401721        }
    5411722    }
Note: See TracChangeset for help on using the changeset viewer.