summaryrefslogtreecommitdiffhomepage
path: root/util-linux
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-09-15 15:12:00 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-09-15 15:12:00 +0000
commit30a64cdc95eaa435c00a9aeccdc1b8f9da727875 (patch)
tree1f8fd2a5aa7b863be39d32d371d0f34fbb470b01 /util-linux
parent215c61d3c2830113479ce008d9c1d7e3978ad9c1 (diff)
mount: reorder things, fix NFS-less mount.
Diffstat (limited to 'util-linux')
-rw-r--r--util-linux/mount.c740
1 files changed, 360 insertions, 380 deletions
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 4660b27ef..5219842ef 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -25,6 +25,16 @@
#include "busybox.h"
#include <mntent.h>
+/* Needed for nfs support only... */
+#include <syslog.h>
+#include <sys/utsname.h>
+#undef TRUE
+#undef FALSE
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_clnt.h>
+
+
// Not real flags, but we want to be able to check for this.
#define MOUNT_NOAUTO (1<<29)
#define MOUNT_SWAP (1<<30)
@@ -86,7 +96,7 @@ struct {
{"remount", MS_REMOUNT}, // action flag
};
-static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts);
+
/* Append mount options to string */
static void append_mount_options(char **oldopts, char *newopts)
@@ -272,349 +282,6 @@ static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
return rc;
}
-// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
-// type detection. Returns 0 for success, nonzero for failure.
-
-static int singlemount(struct mntent *mp, int ignore_busy)
-{
- int rc = -1, vfsflags;
- char *loopFile = 0, *filteropts = 0;
- llist_t *fl = 0;
- struct stat st;
-
- vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
-
- // Treat fstype "auto" as unspecified.
-
- if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0;
-
- // Might this be an CIFS filesystem?
-
- if(ENABLE_FEATURE_MOUNT_CIFS &&
- (!mp->mnt_type || !strcmp(mp->mnt_type,"cifs")) &&
- (mp->mnt_fsname[0]==mp->mnt_fsname[1] && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\')))
- {
- struct hostent *he;
- char ip[32], *s;
-
- rc = 1;
- // Replace '/' with '\' and verify that unc points to "//server/share".
-
- for (s = mp->mnt_fsname; *s; ++s)
- if (*s == '/') *s = '\\';
-
- // get server IP
-
- s = strrchr(mp->mnt_fsname, '\\');
- if (s == mp->mnt_fsname+1) goto report_error;
- *s = 0;
- he = gethostbyname(mp->mnt_fsname+2);
- *s = '\\';
- if (!he) goto report_error;
-
- // Insert ip=... option into string flags. (NOTE: Add IPv6 support.)
-
- sprintf(ip, "ip=%d.%d.%d.%d", he->h_addr[0], he->h_addr[1],
- he->h_addr[2], he->h_addr[3]);
- parse_mount_options(ip, &filteropts);
-
- // compose new unc '\\server-ip\share'
-
- s = xasprintf("\\\\%s%s",ip+3,strchr(mp->mnt_fsname+2,'\\'));
- if (ENABLE_FEATURE_CLEAN_UP) free(mp->mnt_fsname);
- mp->mnt_fsname = s;
-
- // lock is required
- vfsflags |= MS_MANDLOCK;
-
- mp->mnt_type = "cifs";
- rc = mount_it_now(mp, vfsflags, filteropts);
- goto report_error;
- }
-
- // Might this be an NFS filesystem?
-
- if (ENABLE_FEATURE_MOUNT_NFS &&
- (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&
- strchr(mp->mnt_fsname, ':') != NULL)
- {
- rc = nfsmount(mp, vfsflags, filteropts);
- goto report_error;
- }
-
- // Look at the file. (Not found isn't a failure for remount, or for
- // a synthetic filesystem like proc or sysfs.)
-
- if (!lstat(mp->mnt_fsname, &st) && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
- {
- // Do we need to allocate a loopback device for it?
-
- if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
- loopFile = bb_simplify_path(mp->mnt_fsname);
- mp->mnt_fsname = 0;
- switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) {
- case 0:
- case 1:
- break;
- default:
- bb_error_msg( errno == EPERM || errno == EACCES
- ? bb_msg_perm_denied_are_you_root
- : "cannot setup loop device");
- return errno;
- }
-
- // Autodetect bind mounts
-
- } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
- vfsflags |= MS_BIND;
- }
-
- /* If we know the fstype (or don't need to), jump straight
- * to the actual mount. */
-
- if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
- rc = mount_it_now(mp, vfsflags, filteropts);
-
- // Loop through filesystem types until mount succeeds or we run out
-
- else {
-
- /* Initialize list of block backed filesystems. This has to be
- * done here so that during "mount -a", mounts after /proc shows up
- * can autodetect. */
-
- if (!fslist) {
- fslist = get_block_backed_filesystems();
- if (ENABLE_FEATURE_CLEAN_UP && fslist)
- atexit(delete_block_backed_filesystems);
- }
-
- for (fl = fslist; fl; fl = fl->link) {
- mp->mnt_type = fl->data;
-
- if (!(rc = mount_it_now(mp,vfsflags, filteropts))) break;
-
- mp->mnt_type = 0;
- }
- }
-
- // If mount failed, clean up loop file (if any).
-
- if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
- del_loop(mp->mnt_fsname);
- if (ENABLE_FEATURE_CLEAN_UP) {
- free(loopFile);
- free(mp->mnt_fsname);
- }
- }
-
-report_error:
- if (ENABLE_FEATURE_CLEAN_UP) free(filteropts);
-
- if (rc && errno == EBUSY && ignore_busy) rc = 0;
- if (rc < 0)
- /* perror here sometimes says "mounting ... on ... failed: Success" */
- bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
-
- return rc;
-}
-
-// Parse options, if necessary parse fstab/mtab, and call singlemount for
-// each directory to be mounted.
-
-int mount_main(int argc, char **argv)
-{
- char *cmdopts = xstrdup(""), *fstabname, *fstype=0, *storage_path=0;
- FILE *fstab;
- int i, opt, all = FALSE, rc = 0;
- struct mntent mtpair[2], *mtcur = mtpair;
-
- /* parse long options, like --bind and --move. Note that -o option
- * and --option are synonymous. Yes, this means --remount,rw works. */
-
- for (i = opt = 0; i < argc; i++) {
- if (argv[i][0] == '-' && argv[i][1] == '-') {
- append_mount_options(&cmdopts,argv[i]+2);
- } else argv[opt++] = argv[i];
- }
- argc = opt;
-
- // Parse remaining options
-
- while ((opt = getopt(argc, argv, "o:t:rwavnf")) > 0) {
- switch (opt) {
- case 'o':
- append_mount_options(&cmdopts, optarg);
- break;
- case 't':
- fstype = optarg;
- break;
- case 'r':
- append_mount_options(&cmdopts, "ro");
- break;
- case 'w':
- append_mount_options(&cmdopts, "rw");
- break;
- case 'a':
- all = TRUE;
- break;
- case 'n':
- USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;)
- break;
- case 'f':
- USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;)
- break;
- case 'v':
- break; // ignore -v
- default:
- bb_show_usage();
- }
- }
-
- // Three or more non-option arguments? Die with a usage message.
-
- if (optind-argc>2) bb_show_usage();
-
- // If we have no arguments, show currently mounted filesystems
-
- if (optind == argc) {
- if (!all) {
- FILE *mountTable = setmntent(bb_path_mtab_file, "r");
-
- if(!mountTable) bb_error_msg_and_die("no %s",bb_path_mtab_file);
-
- while (getmntent_r(mountTable,mtpair,bb_common_bufsiz1,
- sizeof(bb_common_bufsiz1)))
- {
- // Don't show rootfs.
- if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
-
- if (!fstype || !strcmp(mtpair->mnt_type, fstype))
- printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
- mtpair->mnt_dir, mtpair->mnt_type,
- mtpair->mnt_opts);
- }
- if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);
- return EXIT_SUCCESS;
- }
- } else storage_path = bb_simplify_path(argv[optind]);
-
- // When we have two arguments, the second is the directory and we can
- // skip looking at fstab entirely. We can always abspath() the directory
- // argument when we get it.
-
- if (optind+2 == argc) {
- mtpair->mnt_fsname = argv[optind];
- mtpair->mnt_dir = argv[optind+1];
- mtpair->mnt_type = fstype;
- mtpair->mnt_opts = cmdopts;
- rc = singlemount(mtpair, 0);
- goto clean_up;
- }
-
- // If we have a shared subtree flag, don't worry about fstab or mtab.
- i = parse_mount_options(cmdopts,0);
- if (ENABLE_FEATURE_MOUNT_FLAGS &&
- (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE )))
- {
- rc = mount("", argv[optind], "", i, "");
- if (rc) bb_perror_msg_and_die("%s", argv[optind]);
- goto clean_up;
- }
-
- // Open either fstab or mtab
-
- if (parse_mount_options(cmdopts,0) & MS_REMOUNT)
- fstabname = bb_path_mtab_file;
- else fstabname="/etc/fstab";
-
- if (!(fstab=setmntent(fstabname,"r")))
- bb_perror_msg_and_die("cannot read %s",fstabname);
-
- // Loop through entries until we find what we're looking for.
-
- memset(mtpair,0,sizeof(mtpair));
- for (;;) {
- struct mntent *mtnext = mtpair + (mtcur==mtpair ? 1 : 0);
-
- // Get next fstab entry
-
- if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1
- + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0),
- sizeof(bb_common_bufsiz1)/2))
- {
- // Were we looking for something specific?
-
- if (optind != argc) {
-
- // If we didn't find anything, complain.
-
- if (!mtnext->mnt_fsname)
- bb_error_msg_and_die("can't find %s in %s",
- argv[optind], fstabname);
-
- // Mount the last thing we found.
-
- mtcur = mtnext;
- mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
- append_mount_options(&(mtcur->mnt_opts),cmdopts);
- rc = singlemount(mtcur, 0);
- free(mtcur->mnt_opts);
- }
- goto clean_up;
- }
-
- /* If we're trying to mount something specific and this isn't it,
- * skip it. Note we must match both the exact text in fstab (ala
- * "proc") or a full path from root */
-
- if (optind != argc) {
-
- // Is this what we're looking for?
-
- if(strcmp(argv[optind],mtcur->mnt_fsname) &&
- strcmp(storage_path,mtcur->mnt_fsname) &&
- strcmp(argv[optind],mtcur->mnt_dir) &&
- strcmp(storage_path,mtcur->mnt_dir)) continue;
-
- // Remember this entry. Something later may have overmounted
- // it, and we want the _last_ match.
-
- mtcur = mtnext;
-
- // If we're mounting all.
-
- } else {
-
- // Do we need to match a filesystem type?
- if (fstype && strcmp(mtcur->mnt_type,fstype)) continue;
-
- // Skip noauto and swap anyway.
-
- if (parse_mount_options(mtcur->mnt_opts,0)
- & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
-
- // Mount this thing.
-
- if (singlemount(mtcur, 1)) {
- /* Count number of failed mounts */
- rc++;
- }
- }
- }
- if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);
-
-clean_up:
-
- if (ENABLE_FEATURE_CLEAN_UP) {
- free(storage_path);
- free(cmdopts);
- }
-
- return rc;
-}
-
-
#if ENABLE_FEATURE_MOUNT_NFS
/*
@@ -639,17 +306,9 @@ clean_up:
* plus NFSv3 stuff.
*/
-#include <syslog.h>
-#include <sys/utsname.h>
-#undef TRUE
-#undef FALSE
-#include <rpc/rpc.h>
-#include <rpc/pmap_prot.h>
-#include <rpc/pmap_clnt.h>
-
/* This is just a warning of a common mistake. Possibly this should be a
* uclibc faq entry rather than in busybox... */
-#if ENABLE_FEATURE_MOUNT_NFS && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
+#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
#endif
@@ -1314,25 +973,6 @@ static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)
if (!data.timeo)
data.timeo = tcp ? 70 : 7;
-#ifdef NFS_MOUNT_DEBUG
- printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
- data.rsize, data.wsize, data.timeo, data.retrans);
- printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
- data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
- printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
- port, bg, retry, data.flags);
- printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
- mountprog, mountvers, nfsprog, nfsvers);
- printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
- (data.flags & NFS_MOUNT_SOFT) != 0,
- (data.flags & NFS_MOUNT_INTR) != 0,
- (data.flags & NFS_MOUNT_POSIX) != 0,
- (data.flags & NFS_MOUNT_NOCTO) != 0,
- (data.flags & NFS_MOUNT_NOAC) != 0);
- printf("tcp = %d\n",
- (data.flags & NFS_MOUNT_TCP) != 0);
-#endif
-
data.version = nfs_mount_version;
if (vfsflags & MS_REMOUNT)
@@ -1559,14 +1199,7 @@ prepare_kernel_data:
tcp ? IPPROTO_TCP : IPPROTO_UDP);
if (port == 0)
port = NFS_PORT;
-#ifdef NFS_MOUNT_DEBUG
- else
- printf("used portmapper to find NFS port\n");
-#endif
}
-#ifdef NFS_MOUNT_DEBUG
- printf("using port %d for nfs daemon\n", port);
-#endif
server_addr.sin_port = htons(port);
/* prepare data structure for kernel */
@@ -1625,4 +1258,351 @@ ret:
return retval;
}
-#endif /* ENABLE_FEATURE_MOUNT_NFS */
+#else /* !ENABLE_FEATURE_MOUNT_NFS */
+
+/* Never called. Call should be optimized out. */
+int nfsmount(struct mntent *mp, int vfsflags, char *filteropts);
+
+#endif /* !ENABLE_FEATURE_MOUNT_NFS */
+
+// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
+// type detection. Returns 0 for success, nonzero for failure.
+
+static int singlemount(struct mntent *mp, int ignore_busy)
+{
+ int rc = -1, vfsflags;
+ char *loopFile = 0, *filteropts = 0;
+ llist_t *fl = 0;
+ struct stat st;
+
+ vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
+
+ // Treat fstype "auto" as unspecified.
+
+ if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0;
+
+ // Might this be an CIFS filesystem?
+
+ if(ENABLE_FEATURE_MOUNT_CIFS &&
+ (!mp->mnt_type || !strcmp(mp->mnt_type,"cifs")) &&
+ (mp->mnt_fsname[0]==mp->mnt_fsname[1] && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\')))
+ {
+ struct hostent *he;
+ char ip[32], *s;
+
+ rc = 1;
+ // Replace '/' with '\' and verify that unc points to "//server/share".
+
+ for (s = mp->mnt_fsname; *s; ++s)
+ if (*s == '/') *s = '\\';
+
+ // get server IP
+
+ s = strrchr(mp->mnt_fsname, '\\');
+ if (s == mp->mnt_fsname+1) goto report_error;
+ *s = 0;
+ he = gethostbyname(mp->mnt_fsname+2);
+ *s = '\\';
+ if (!he) goto report_error;
+
+ // Insert ip=... option into string flags. (NOTE: Add IPv6 support.)
+
+ sprintf(ip, "ip=%d.%d.%d.%d", he->h_addr[0], he->h_addr[1],
+ he->h_addr[2], he->h_addr[3]);
+ parse_mount_options(ip, &filteropts);
+
+ // compose new unc '\\server-ip\share'
+
+ s = xasprintf("\\\\%s%s",ip+3,strchr(mp->mnt_fsname+2,'\\'));
+ if (ENABLE_FEATURE_CLEAN_UP) free(mp->mnt_fsname);
+ mp->mnt_fsname = s;
+
+ // lock is required
+ vfsflags |= MS_MANDLOCK;
+
+ mp->mnt_type = "cifs";
+ rc = mount_it_now(mp, vfsflags, filteropts);
+ goto report_error;
+ }
+
+ // Might this be an NFS filesystem?
+
+ if (ENABLE_FEATURE_MOUNT_NFS &&
+ (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&
+ strchr(mp->mnt_fsname, ':') != NULL)
+ {
+ rc = nfsmount(mp, vfsflags, filteropts);
+ goto report_error;
+ }
+
+ // Look at the file. (Not found isn't a failure for remount, or for
+ // a synthetic filesystem like proc or sysfs.)
+
+ if (!lstat(mp->mnt_fsname, &st) && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
+ {
+ // Do we need to allocate a loopback device for it?
+
+ if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
+ loopFile = bb_simplify_path(mp->mnt_fsname);
+ mp->mnt_fsname = 0;
+ switch(set_loop(&(mp->mnt_fsname), loopFile, 0)) {
+ case 0:
+ case 1:
+ break;
+ default:
+ bb_error_msg( errno == EPERM || errno == EACCES
+ ? bb_msg_perm_denied_are_you_root
+ : "cannot setup loop device");
+ return errno;
+ }
+
+ // Autodetect bind mounts
+
+ } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
+ vfsflags |= MS_BIND;
+ }
+
+ /* If we know the fstype (or don't need to), jump straight
+ * to the actual mount. */
+
+ if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
+ rc = mount_it_now(mp, vfsflags, filteropts);
+
+ // Loop through filesystem types until mount succeeds or we run out
+
+ else {
+
+ /* Initialize list of block backed filesystems. This has to be
+ * done here so that during "mount -a", mounts after /proc shows up
+ * can autodetect. */
+
+ if (!fslist) {
+ fslist = get_block_backed_filesystems();
+ if (ENABLE_FEATURE_CLEAN_UP && fslist)
+ atexit(delete_block_backed_filesystems);
+ }
+
+ for (fl = fslist; fl; fl = fl->link) {
+ mp->mnt_type = fl->data;
+
+ if (!(rc = mount_it_now(mp,vfsflags, filteropts))) break;
+
+ mp->mnt_type = 0;
+ }
+ }
+
+ // If mount failed, clean up loop file (if any).
+
+ if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
+ del_loop(mp->mnt_fsname);
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(loopFile);
+ free(mp->mnt_fsname);
+ }
+ }
+
+report_error:
+ if (ENABLE_FEATURE_CLEAN_UP) free(filteropts);
+
+ if (rc && errno == EBUSY && ignore_busy) rc = 0;
+ if (rc < 0)
+ /* perror here sometimes says "mounting ... on ... failed: Success" */
+ bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
+
+ return rc;
+}
+
+// Parse options, if necessary parse fstab/mtab, and call singlemount for
+// each directory to be mounted.
+
+int mount_main(int argc, char **argv)
+{
+ char *cmdopts = xstrdup(""), *fstabname, *fstype=0, *storage_path=0;
+ FILE *fstab;
+ int i, opt, all = FALSE, rc = 0;
+ struct mntent mtpair[2], *mtcur = mtpair;
+
+ /* parse long options, like --bind and --move. Note that -o option
+ * and --option are synonymous. Yes, this means --remount,rw works. */
+
+ for (i = opt = 0; i < argc; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == '-') {
+ append_mount_options(&cmdopts,argv[i]+2);
+ } else argv[opt++] = argv[i];
+ }
+ argc = opt;
+
+ // Parse remaining options
+
+ while ((opt = getopt(argc, argv, "o:t:rwavnf")) > 0) {
+ switch (opt) {
+ case 'o':
+ append_mount_options(&cmdopts, optarg);
+ break;
+ case 't':
+ fstype = optarg;
+ break;
+ case 'r':
+ append_mount_options(&cmdopts, "ro");
+ break;
+ case 'w':
+ append_mount_options(&cmdopts, "rw");
+ break;
+ case 'a':
+ all = TRUE;
+ break;
+ case 'n':
+ USE_FEATURE_MTAB_SUPPORT(useMtab = FALSE;)
+ break;
+ case 'f':
+ USE_FEATURE_MTAB_SUPPORT(fakeIt = FALSE;)
+ break;
+ case 'v':
+ break; // ignore -v
+ default:
+ bb_show_usage();
+ }
+ }
+
+ // Three or more non-option arguments? Die with a usage message.
+
+ if (optind-argc>2) bb_show_usage();
+
+ // If we have no arguments, show currently mounted filesystems
+
+ if (optind == argc) {
+ if (!all) {
+ FILE *mountTable = setmntent(bb_path_mtab_file, "r");
+
+ if(!mountTable) bb_error_msg_and_die("no %s",bb_path_mtab_file);
+
+ while (getmntent_r(mountTable,mtpair,bb_common_bufsiz1,
+ sizeof(bb_common_bufsiz1)))
+ {
+ // Don't show rootfs.
+ if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
+
+ if (!fstype || !strcmp(mtpair->mnt_type, fstype))
+ printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
+ mtpair->mnt_dir, mtpair->mnt_type,
+ mtpair->mnt_opts);
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);
+ return EXIT_SUCCESS;
+ }
+ } else storage_path = bb_simplify_path(argv[optind]);
+
+ // When we have two arguments, the second is the directory and we can
+ // skip looking at fstab entirely. We can always abspath() the directory
+ // argument when we get it.
+
+ if (optind+2 == argc) {
+ mtpair->mnt_fsname = argv[optind];
+ mtpair->mnt_dir = argv[optind+1];
+ mtpair->mnt_type = fstype;
+ mtpair->mnt_opts = cmdopts;
+ rc = singlemount(mtpair, 0);
+ goto clean_up;
+ }
+
+ // If we have a shared subtree flag, don't worry about fstab or mtab.
+ i = parse_mount_options(cmdopts,0);
+ if (ENABLE_FEATURE_MOUNT_FLAGS &&
+ (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE )))
+ {
+ rc = mount("", argv[optind], "", i, "");
+ if (rc) bb_perror_msg_and_die("%s", argv[optind]);
+ goto clean_up;
+ }
+
+ // Open either fstab or mtab
+
+ if (parse_mount_options(cmdopts,0) & MS_REMOUNT)
+ fstabname = bb_path_mtab_file;
+ else fstabname="/etc/fstab";
+
+ if (!(fstab=setmntent(fstabname,"r")))
+ bb_perror_msg_and_die("cannot read %s",fstabname);
+
+ // Loop through entries until we find what we're looking for.
+
+ memset(mtpair,0,sizeof(mtpair));
+ for (;;) {
+ struct mntent *mtnext = mtpair + (mtcur==mtpair ? 1 : 0);
+
+ // Get next fstab entry
+
+ if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1
+ + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0),
+ sizeof(bb_common_bufsiz1)/2))
+ {
+ // Were we looking for something specific?
+
+ if (optind != argc) {
+
+ // If we didn't find anything, complain.
+
+ if (!mtnext->mnt_fsname)
+ bb_error_msg_and_die("can't find %s in %s",
+ argv[optind], fstabname);
+
+ // Mount the last thing we found.
+
+ mtcur = mtnext;
+ mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
+ append_mount_options(&(mtcur->mnt_opts),cmdopts);
+ rc = singlemount(mtcur, 0);
+ free(mtcur->mnt_opts);
+ }
+ goto clean_up;
+ }
+
+ /* If we're trying to mount something specific and this isn't it,
+ * skip it. Note we must match both the exact text in fstab (ala
+ * "proc") or a full path from root */
+
+ if (optind != argc) {
+
+ // Is this what we're looking for?
+
+ if(strcmp(argv[optind],mtcur->mnt_fsname) &&
+ strcmp(storage_path,mtcur->mnt_fsname) &&
+ strcmp(argv[optind],mtcur->mnt_dir) &&
+ strcmp(storage_path,mtcur->mnt_dir)) continue;
+
+ // Remember this entry. Something later may have overmounted
+ // it, and we want the _last_ match.
+
+ mtcur = mtnext;
+
+ // If we're mounting all.
+
+ } else {
+
+ // Do we need to match a filesystem type?
+ if (fstype && strcmp(mtcur->mnt_type,fstype)) continue;
+
+ // Skip noauto and swap anyway.
+
+ if (parse_mount_options(mtcur->mnt_opts,0)
+ & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
+
+ // Mount this thing.
+
+ if (singlemount(mtcur, 1)) {
+ /* Count number of failed mounts */
+ rc++;
+ }
+ }
+ }
+ if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);
+
+clean_up:
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ free(storage_path);
+ free(cmdopts);
+ }
+
+ return rc;
+}