1303 files changed, 32187 insertions, 57138 deletions
diff --git a/util-linux/mount.c b/util-linux/mount.c index 16b58a0..4e4e154 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -17,8 +17,111 @@ // mount_it_now() does the actual mount. // +//config:config MOUNT +//config: bool "mount" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: All files and filesystems in Unix are arranged into one big directory +//config: tree. The 'mount' utility is used to graft a filesystem onto a +//config: particular part of the tree. A filesystem can either live on a block +//config: device, or it can be accessible over the network, as is the case with +//config: NFS filesystems. Most people using BusyBox will also want to enable +//config: the 'mount' utility. +//config: +//config:config FEATURE_MOUNT_FAKE +//config: bool "Support option -f" +//config: default y +//config: depends on MOUNT +//config: help +//config: Enable support for faking a file system mount. +//config: +//config:config FEATURE_MOUNT_VERBOSE +//config: bool "Support option -v" +//config: default y +//config: depends on MOUNT +//config: help +//config: Enable multi-level -v[vv...] verbose messages. Useful if you +//config: debug mount problems and want to see what is exactly passed +//config: to the kernel. +//config: +//config:config FEATURE_MOUNT_HELPERS +//config: bool "Support mount helpers" +//config: default n +//config: depends on MOUNT +//config: help +//config: Enable mounting of virtual file systems via external helpers. +//config: E.g. "mount obexfs#-b00.11.22.33.44.55 /mnt" will in effect call +//config: "obexfs -b00.11.22.33.44.55 /mnt" +//config: Also "mount -t sometype [-o opts] fs /mnt" will try +//config: "sometype [-o opts] fs /mnt" if simple mount syscall fails. +//config: The idea is to use such virtual filesystems in /etc/fstab. +//config: +//config:config FEATURE_MOUNT_LABEL +//config: bool "Support specifying devices by label or UUID" +//config: default y +//config: depends on MOUNT +//config: select VOLUMEID +//config: help +//config: This allows for specifying a device by label or uuid, rather than by +//config: name. This feature utilizes the same functionality as blkid/findfs. +//config: This also enables label or uuid support for swapon. +//config: +//config:config FEATURE_MOUNT_NFS +//config: bool "Support mounting NFS file systems on Linux < 2.6.23" +//config: default n +//config: depends on MOUNT +//config: select FEATURE_HAVE_RPC +//config: select FEATURE_SYSLOG +//config: help +//config: Enable mounting of NFS file systems on Linux kernels prior +//config: to version 2.6.23. Note that in this case mounting of NFS +//config: over IPv6 will not be possible. +//config: +//config: Note that this option links in RPC support from libc, +//config: which is rather large (~10 kbytes on uclibc). +//config: +//config:config FEATURE_MOUNT_CIFS +//config: bool "Support mounting CIFS/SMB file systems" +//config: default y +//config: depends on MOUNT +//config: help +//config: Enable support for samba mounts. +//config: +//config:config FEATURE_MOUNT_FLAGS +//config: depends on MOUNT +//config: bool "Support lots of -o flags in mount" +//config: default y +//config: help +//config: Without this, mount only supports ro/rw/remount. With this, it +//config: supports nosuid, suid, dev, nodev, exec, noexec, sync, async, atime, +//config: noatime, diratime, nodiratime, loud, bind, move, shared, slave, +//config: private, unbindable, rshared, rslave, rprivate, and runbindable. +//config: +//config:config FEATURE_MOUNT_FSTAB +//config: depends on MOUNT +//config: bool "Support /etc/fstab and -a" +//config: default y +//config: help +//config: Support mount all and looking for files in /etc/fstab. +//config: +//config:config FEATURE_MOUNT_OTHERTAB +//config: depends on FEATURE_MOUNT_FSTAB +//config: bool "Support -T <alt_fstab>" +//config: default y +//config: help +//config: Support mount -T (specifying an alternate fstab) + +/* On full-blown systems, requires suid for user mounts. + * But it's not unthinkable to have it available in non-suid flavor on some systems, + * for viewing mount table. + * Therefore we use BB_SUID_MAYBE instead of BB_SUID_REQUIRE: */ +//applet:IF_MOUNT(APPLET(mount, BB_DIR_BIN, IF_DESKTOP(BB_SUID_MAYBE) IF_NOT_DESKTOP(BB_SUID_DROP))) + +//kbuild:lib-$(CONFIG_MOUNT) += mount.o + //usage:#define mount_trivial_usage -//usage: "[OPTIONS] [-o OPTS] DEVICE NODE" +//usage: "[OPTIONS] [-o OPT] DEVICE NODE" //usage:#define mount_full_usage "\n\n" //usage: "Mount a filesystem. Filesystem autodetection requires /proc.\n" //usage: "\n -a Mount all filesystems in fstab" @@ -41,8 +144,11 @@ //usage: ) ////usage: "\n -s Sloppy (ignored)" //usage: "\n -r Read-only mount" -//usage: "\n -w Read-write mount (default)" +////usage: "\n -w Read-write mount (default)" //usage: "\n -t FSTYPE[,...] Filesystem type(s)" +//usage: IF_FEATURE_MOUNT_OTHERTAB( +//usage: "\n -T FILE Read FILE instead of /etc/fstab" +//usage: ) //usage: "\n -O OPT Mount only filesystems with option OPT (-a only)" //usage: "\n-o OPT:" //usage: IF_FEATURE_MOUNT_LOOP( @@ -64,7 +170,7 @@ //usage: "\n move Relocate an existing mount point" //usage: ) //usage: "\n remount Remount a mounted filesystem, changing flags" -//usage: "\n ro/rw Same as -r/-w" +//usage: "\n ro Same as -r" //usage: "\n" //usage: "\nThere are filesystem-specific -o flags." //usage: @@ -82,6 +188,8 @@ #include <mntent.h> #include <syslog.h> #include <sys/mount.h> +#include <android.h> + // Grab more as needed from util-linux's mount/mount_constants.h #ifndef MS_DIRSYNC # define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous @@ -125,6 +233,7 @@ #define BB_MS_INVERTED_VALUE (1u << 31) #include "libbb.h" +#include "common_bufsiz.h" #if ENABLE_FEATURE_MOUNT_LABEL # include "volume_id.h" #else @@ -161,13 +270,15 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result, // Not real flags, but we want to be able to check for this. enum { - MOUNT_USERS = (1 << 28) * ENABLE_DESKTOP, + MOUNT_USERS = (1 << 27) * ENABLE_DESKTOP, + MOUNT_NOFAIL = (1 << 28) * ENABLE_DESKTOP, MOUNT_NOAUTO = (1 << 29), MOUNT_SWAP = (1 << 30), + MOUNT_FAKEFLAGS = MOUNT_USERS | MOUNT_NOFAIL | MOUNT_NOAUTO | MOUNT_SWAP }; -#define OPTION_STR "o:t:rwanfvsiO:" +#define OPTION_STR "o:*t:rwanfvsiO:" IF_FEATURE_MOUNT_OTHERTAB("T:") enum { OPT_o = (1 << 0), OPT_t = (1 << 1), @@ -180,6 +291,7 @@ enum { OPT_s = (1 << 8), OPT_i = (1 << 9), OPT_O = (1 << 10), + OPT_T = (1 << 11), }; #if ENABLE_FEATURE_MTAB_SUPPORT @@ -227,6 +339,7 @@ static const int32_t mount_options[] = { /* "swap" */ MOUNT_SWAP, IF_DESKTOP(/* "user" */ MOUNT_USERS,) IF_DESKTOP(/* "users" */ MOUNT_USERS,) + IF_DESKTOP(/* "nofail" */ MOUNT_NOFAIL,) /* "_netdev" */ 0, IF_DESKTOP(/* "comment=" */ 0,) /* systemd uses this in fstab */ ) @@ -274,7 +387,7 @@ static const int32_t mount_options[] = { /* "remount" */ MS_REMOUNT // action flag }; -static const char mount_option_str[] = +static const char mount_option_str[] ALIGN1 = IF_FEATURE_MOUNT_LOOP( "loop\0" ) @@ -286,6 +399,7 @@ static const char mount_option_str[] = "swap\0" IF_DESKTOP("user\0") IF_DESKTOP("users\0") + IF_DESKTOP("nofail\0") "_netdev\0" IF_DESKTOP("comment=\0") /* systemd uses this in fstab */ ) @@ -344,7 +458,7 @@ struct globals { char getmntent_buf[1]; } FIX_ALIASING; enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_buf) }; -#define G (*(struct globals*)&bb_common_bufsiz1) +#define G (*(struct globals*)bb_common_bufsiz1) #define nfs_mount_version (G.nfs_mount_version) #if ENABLE_FEATURE_MOUNT_VERBOSE #define verbose (G.verbose ) @@ -353,7 +467,7 @@ enum { GETMNTENT_BUFSIZE = COMMON_BUFSIZE - offsetof(struct globals, getmntent_b #endif #define fslist (G.fslist ) #define getmntent_buf (G.getmntent_buf ) -#define INIT_G() do { } while (0) +#define INIT_G() do { setup_common_bufsiz(); } while (0) #if ENABLE_FEATURE_MTAB_SUPPORT /* @@ -542,7 +656,7 @@ static llist_t *get_block_backed_filesystems(void) if (!f) continue; while ((buf = xmalloc_fgetline(f)) != NULL) { - if (strncmp(buf, "nodev", 5) == 0 && isspace(buf[5])) + if (is_prefixed_with(buf, "nodev") && isspace(buf[5])) goto next; fs = skip_whitespace(buf); if (*fs == '#' || *fs == '*' || !*fs) @@ -573,6 +687,8 @@ static int mount_it_now(struct mntent *mp, unsigned long vfsflags, char *filtero { int rc = 0; + vfsflags &= ~(unsigned long)MOUNT_FAKEFLAGS; + if (FAKE_IT) { if (verbose >= 2) bb_error_msg("would do mount('%s','%s','%s',0x%08lx,'%s')", @@ -897,7 +1013,7 @@ enum { # define EDQUOT ENOSPC #endif /* Convert each NFSERR_BLAH into EBLAH */ -static const uint8_t nfs_err_stat[] = { +static const uint8_t nfs_err_stat[] ALIGN1 = { 1, 2, 5, 6, 13, 17, 19, 20, 21, 22, 27, 28, 30, 63, 66, 69, 70, 71 @@ -910,7 +1026,7 @@ typedef uint8_t nfs_err_type; #else typedef uint16_t nfs_err_type; #endif -static const nfs_err_type nfs_err_errnum[] = { +static const nfs_err_type nfs_err_errnum[] ALIGN2 = { EPERM , ENOENT , EIO , ENXIO , EACCES, EEXIST, ENODEV, ENOTDIR , EISDIR , EINVAL, EFBIG , ENOSPC, EROFS , ENAMETOOLONG, ENOTEMPTY, EDQUOT, ESTALE, EREMOTE @@ -1265,9 +1381,9 @@ static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *fi strcspn(opteq, " \t\n\r,")); continue; case 18: // "proto" - if (!strncmp(opteq, "tcp", 3)) + if (is_prefixed_with(opteq, "tcp")) tcp = 1; - else if (!strncmp(opteq, "udp", 3)) + else if (is_prefixed_with(opteq, "udp")) tcp = 0; else bb_error_msg("warning: unrecognized proto= option"); @@ -1360,7 +1476,7 @@ static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *fi "rdirplus\0" "acl\0"; int val = 1; - if (!strncmp(opt, "no", 2)) { + if (is_prefixed_with(opt, "no")) { val = 0; opt += 2; } @@ -1825,7 +1941,6 @@ static int singlemount(struct mntent *mp, int ignore_busy) int len; char c; char *hostname, *share; - char *dotted, *ip; len_and_sockaddr *lsa; // Parse mp->mnt_fsname of the form "//hostname/share[/dir1/dir2]" @@ -1865,13 +1980,26 @@ static int singlemount(struct mntent *mp, int ignore_busy) if (!lsa) goto report_error; - // Insert "ip=..." option into options - dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); - if (ENABLE_FEATURE_CLEAN_UP) free(lsa); - ip = xasprintf("ip=%s", dotted); - if (ENABLE_FEATURE_CLEAN_UP) free(dotted); - parse_mount_options(ip, &filteropts); - if (ENABLE_FEATURE_CLEAN_UP) free(ip); + // If there is no "ip=..." option yet + if (!is_prefixed_with(filteropts, ",ip="+1) + && !strstr(filteropts, ",ip=") + ) { + char *dotted, *ip; + // Insert "ip=..." option into options + dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); + if (ENABLE_FEATURE_CLEAN_UP) free(lsa); + ip = xasprintf("ip=%s", dotted); + if (ENABLE_FEATURE_CLEAN_UP) free(dotted); +// Note: IPv6 scoped addresses ("host%iface", see RFC 4007) should be +// handled by libc in getnameinfo() (inside xmalloc_sockaddr2dotted_noport()). +// Currently, glibc does not support that (has no NI_NUMERICSCOPE), +// musl apparently does. This results in "ip=numericIPv6%iface_name" +// (instead of _numeric_ iface_id) with glibc. +// This probably should be fixed in glibc, not here. +// The workaround is to manually specify correct "ip=ADDR%n" option. + parse_mount_options(ip, &filteropts); + if (ENABLE_FEATURE_CLEAN_UP) free(ip); + } mp->mnt_type = (char*)"cifs"; rc = mount_it_now(mp, vfsflags, filteropts); @@ -1880,7 +2008,7 @@ static int singlemount(struct mntent *mp, int ignore_busy) } // Might this be an NFS filesystem? - if ((!mp->mnt_type || strncmp(mp->mnt_type, "nfs", 3) == 0) + if ((!mp->mnt_type || is_prefixed_with(mp->mnt_type, "nfs")) && strchr(mp->mnt_fsname, ':') != NULL ) { if (!mp->mnt_type) @@ -1952,7 +2080,7 @@ static int singlemount(struct mntent *mp, int ignore_busy) del_loop(mp->mnt_fsname); if (ENABLE_FEATURE_CLEAN_UP) { free(loopFile); - free(mp->mnt_fsname); + /* No, "rc != 0" needs it: free(mp->mnt_fsname); */ } } @@ -1962,6 +2090,8 @@ static int singlemount(struct mntent *mp, int ignore_busy) if (errno == EBUSY && ignore_busy) return 0; + if (errno == ENOENT && (vfsflags & MOUNT_NOFAIL)) + return 0; if (rc != 0) bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); return rc; @@ -2034,7 +2164,7 @@ int mount_main(int argc UNUSED_PARAM, char **argv) char *O_optmatch = NULL; char *storage_path; llist_t *lst_o = NULL; - const char *fstabname; + const char *fstabname = "/etc/fstab"; FILE *fstab; int i, j; int rc = EXIT_SUCCESS; @@ -2059,8 +2189,9 @@ int mount_main(int argc UNUSED_PARAM, char **argv) // Parse remaining options // Max 2 params; -o is a list, -v is a counter - opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv"); + opt_complementary = "?2" IF_FEATURE_MOUNT_VERBOSE("vv"); opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch + IF_FEATURE_MOUNT_OTHERTAB(, &fstabname) IF_FEATURE_MOUNT_VERBOSE(, &verbose)); while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r @@ -2128,8 +2259,10 @@ int mount_main(int argc UNUSED_PARAM, char **argv) return rc; } + // A malicious user could overmount /usr without this. + if (ENABLE_FEATURE_MOUNT_OTHERTAB && nonroot) + fstabname = "/etc/fstab"; // Open either fstab or mtab - fstabname = "/etc/fstab"; if (cmdopt_flags & MS_REMOUNT) { // WARNING. I am not sure this matches util-linux's // behavior. It's possible util-linux does not |