summaryrefslogtreecommitdiff
path: root/util-linux/mount.c
diff options
context:
space:
mode:
authorRob Landley2005-08-10 20:35:54 +0000
committerRob Landley2005-08-10 20:35:54 +0000
commit6a6798b8e47c71888945ec5cb55c703db19b956c (patch)
tree9179ec8c6dc4e402cdc4a86cf6af119745de2f40 /util-linux/mount.c
parent0b62158475ecbfce16fb857042ec7f402d7594ec (diff)
downloadbusybox-6a6798b8e47c71888945ec5cb55c703db19b956c.zip
busybox-6a6798b8e47c71888945ec5cb55c703db19b956c.tar.gz
Major rewrite of mount, umount, losetup. Untangled lots of code, shrunk
things down a bit, fixed a number of funky corner cases, added support for several new features (things like mount --move, mount --bind, lazy unounts, automatic detection of loop mounts, and so on). Probably broke several other things, but it's fixable. (Bang on it, tell me what doesn't work for you...) Note: you no longer need to say "-o loop". It does that for you when necessary. Still need to add "user mount" support, which involves making mount suid. Not too hard to do under the new infrastructure, just haven't done it yet... The previous code had the following notes, that belong in the version control comments: - * 3/21/1999 Charles P. Wright <cpwright@cpwright.com> - * searches through fstab when -a is passed - * will try mounting stuff with all fses when passed -t auto - * - * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab. - * - * 1999-10-07 Erik Andersen <andersen@codepoet.org>. - * Rewrite of a lot of code. Removed mtab usage (I plan on - * putting it back as a compile-time option some time), - * major adjustments to option parsing, and some serious - * dieting all around. - * - * 1999-11-06 mtab support is back - andersee - * - * 2000-01-12 Ben Collins <bcollins@debian.org>, Borrowed utils-linux's - * mount to add loop support. - * - * 2000-04-30 Dave Cinege <dcinege@psychosis.com> - * Rewrote fstab while loop and lower mount section. Can now do - * single mounts from fstab. Can override fstab options for single - * mount. Common mount_one call for single mounts and 'all'. Fixed - * mtab updating and stale entries. Removed 'remount' default. - *
Diffstat (limited to 'util-linux/mount.c')
-rw-r--r--util-linux/mount.c681
1 files changed, 292 insertions, 389 deletions
diff --git a/util-linux/mount.c b/util-linux/mount.c
index b059d70..924d79d 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
+ * Copyright (C) 2005 by Rob Landley <rob@landley.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,29 +20,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- * 3/21/1999 Charles P. Wright <cpwright@cpwright.com>
- * searches through fstab when -a is passed
- * will try mounting stuff with all fses when passed -t auto
- *
- * 1999-04-17 Dave Cinege...Rewrote -t auto. Fixed ro mtab.
- *
- * 1999-10-07 Erik Andersen <andersen@codepoet.org>.
- * Rewrite of a lot of code. Removed mtab usage (I plan on
- * putting it back as a compile-time option some time),
- * major adjustments to option parsing, and some serious
- * dieting all around.
- *
- * 1999-11-06 mtab support is back - andersee
- *
- * 2000-01-12 Ben Collins <bcollins@debian.org>, Borrowed utils-linux's
- * mount to add loop support.
- *
- * 2000-04-30 Dave Cinege <dcinege@psychosis.com>
- * Rewrote fstab while loop and lower mount section. Can now do
- * single mounts from fstab. Can override fstab options for single
- * mount. Common mount_one call for single mounts and 'all'. Fixed
- * mtab updating and stale entries. Removed 'remount' default.
- *
*/
#include <limits.h>
@@ -52,351 +30,131 @@
#include <stdio.h>
#include <mntent.h>
#include <ctype.h>
+#include <sys/mount.h>
+#include <fcntl.h> // for CONFIG_FEATURE_MOUNT_LOOP
+#include <sys/ioctl.h> // for CONFIG_FEATURE_MOUNT_LOOP
#include "busybox.h"
-#ifdef CONFIG_NFSMOUNT
-#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
+/* This is just a warning of a common mistake. Possibly this should be a
+ * uclibc faq entry rather than in busybox... */
+#if ENABLE_NFSMOUNT && defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
#error "You need to build uClibc with UCLIBC_HAS_RPC for busybox mount with NFS support to compile."
#endif
-#endif
-
-enum {
- MS_MGC_VAL = 0xc0ed0000, /* Magic number indicatng "new" flags */
- MS_RDONLY = 1, /* Mount read-only */
- MS_NOSUID = 2, /* Ignore suid and sgid bits */
- MS_NODEV = 4, /* Disallow access to device special files */
- MS_NOEXEC = 8, /* Disallow program execution */
- MS_SYNCHRONOUS = 16, /* Writes are synced at once */
- MS_REMOUNT = 32, /* Alter flags of a mounted FS */
- MS_MANDLOCK = 64, /* Allow mandatory locks on an FS */
- S_QUOTA = 128, /* Quota initialized for file/directory/symlink */
- S_APPEND = 256, /* Append-only file */
- S_IMMUTABLE = 512, /* Immutable file */
- MS_NOATIME = 1024, /* Do not update access times. */
- MS_NODIRATIME = 2048, /* Do not update directory access times */
- MS_BIND = 4096, /* Use the new linux 2.4.x "mount --bind" feature */
- MS_MOVE = 8192, /* Use the new linux 2.4.x "mount --move" feature */
-};
-
-#if defined CONFIG_FEATURE_MOUNT_LOOP
-#include <fcntl.h>
-#include <sys/ioctl.h>
-static int use_loop = FALSE;
+// These two aren't always defined in old headers
+#ifndef MS_BIND
+#define MS_BIND 4096
+#endif
+#ifndef MS_MOVE
+#define MS_MOVE 8192
#endif
-extern int mount(__const char *__special_file, __const char *__dir,
- __const char *__fstype, unsigned long int __rwflag,
- __const void *__data);
-extern int umount(__const char *__special_file);
-extern int umount2(__const char *__special_file, int __flags);
-
-extern int sysfs(int option, unsigned int fs_index, char *buf);
+/* Consume standard mount options (from -o options or --options).
+ * Set appropriate flags and collect unrecognized ones as a comma separated
+ * string to pass to kernel */
-struct mount_options {
+struct {
const char *name;
- unsigned long and;
- unsigned long or;
+ long flags;
+} static const mount_options[] = {
+ {"loop", 0},
+ {"defaults", 0},
+ {"noauto", 0},
+ {"ro", MS_RDONLY},
+ {"rw", ~MS_RDONLY},
+ {"nosuid", MS_NOSUID},
+ {"suid", ~MS_NOSUID},
+ {"dev", ~MS_NODEV},
+ {"nodev", MS_NODEV},
+ {"exec", ~MS_NOEXEC},
+ {"noexec", MS_NOEXEC},
+ {"sync", MS_SYNCHRONOUS},
+ {"async", ~MS_SYNCHRONOUS},
+ {"remount", MS_REMOUNT},
+ {"atime", MS_NOATIME},
+ {"noatime", MS_NOATIME},
+ {"diratime", MS_NODIRATIME},
+ {"nodiratime", MS_NODIRATIME},
+ {"bind", MS_BIND},
+ {"move", MS_MOVE}
};
-static const struct mount_options mount_options[] = {
- {"async", ~MS_SYNCHRONOUS, 0},
- {"atime", ~0, ~MS_NOATIME},
- {"defaults", ~0, 0},
- {"noauto", ~0, 0},
- {"dev", ~MS_NODEV, 0},
- {"diratime", ~0, ~MS_NODIRATIME},
- {"exec", ~MS_NOEXEC, 0},
- {"noatime", ~0, MS_NOATIME},
- {"nodev", ~0, MS_NODEV},
- {"nodiratime", ~0, MS_NODIRATIME},
- {"noexec", ~0, MS_NOEXEC},
- {"nosuid", ~0, MS_NOSUID},
- {"remount", ~0, MS_REMOUNT},
- {"ro", ~0, MS_RDONLY},
- {"rw", ~MS_RDONLY, 0},
- {"suid", ~MS_NOSUID, 0},
- {"sync", ~0, MS_SYNCHRONOUS},
- {"bind", ~0, MS_BIND},
- {"move", ~0, MS_MOVE},
- {0, 0, 0}
-};
-
-static int
-do_mount(char *specialfile, char *dir, char *filesystemtype, long flags,
- void *string_flags, int useMtab, int fakeIt, char *mtab_opts,
- int mount_all)
-{
- int status = 0;
-
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- char *lofile = NULL;
-#endif
-
- if (!fakeIt) {
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- if (use_loop == TRUE) {
- int loro = flags & MS_RDONLY;
-
- lofile = specialfile;
-
- specialfile = find_unused_loop_device();
- if (specialfile == NULL) {
- bb_error_msg_and_die("Could not find a spare loop device");
- }
- if (set_loop(specialfile, lofile, 0, &loro)) {
- bb_error_msg_and_die("Could not setup loop device");
- }
- if (!(flags & MS_RDONLY) && loro) { /* loop is ro, but wanted rw */
- bb_error_msg("WARNING: loop device is read-only");
- flags |= MS_RDONLY;
- }
- }
-#endif
- status = mount(specialfile, dir, filesystemtype, flags, string_flags);
- if (status < 0 && errno == EROFS) {
- bb_error_msg("%s is write-protected, mounting read-only",
- specialfile);
- status = mount(specialfile, dir, filesystemtype, flags |=
- MS_RDONLY, string_flags);
- }
- /* Don't whine about already mounted filesystems when mounting all. */
- if (status < 0 && errno == EBUSY && mount_all) {
- return TRUE;
- }
- }
-
-
- /* If the mount was sucessful, do anything needed, then return TRUE */
- if (status == 0 || fakeIt == TRUE) {
-
-#if defined CONFIG_FEATURE_MTAB_SUPPORT
- if (useMtab) {
- erase_mtab(specialfile); /* Clean any stale entries */
- write_mtab(specialfile, dir, filesystemtype, flags, mtab_opts);
- }
-#endif
- return (TRUE);
- }
-
- /* Bummer. mount failed. Clean up */
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- if (lofile != NULL) {
- del_loop(specialfile);
- }
-#endif
-
- if (errno == EPERM) {
- bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
- }
-
- return (FALSE);
-}
-
-
-static void paste_str(char **s1, const char *s2)
-{
- *s1 = xrealloc(*s1, strlen(*s1) + strlen(s2) + 1);
- strcat(*s1, s2);
-}
-
-/* Seperate standard mount options from the nonstandard string options */
+/* Uses the mount_options list above */
static void parse_mount_options(char *options, int *flags, char **strflags)
{
- while (options) {
- int gotone = FALSE;
+ // Loop through options
+ for(;;) {
+ int i;
char *comma = strchr(options, ',');
- const struct mount_options *f = mount_options;
- if (comma) {
- *comma = '\0';
- }
-
- while (f->name != 0) {
- if (strcasecmp(f->name, options) == 0) {
+ if(comma) *comma = 0;
- *flags &= f->and;
- *flags |= f->or;
- gotone = TRUE;
+ // Find this option in mount_options
+ for(i = 0; i < (sizeof(mount_options) / sizeof(*mount_options)); i++) {
+ if(!strcasecmp(mount_options[i].name, options)) {
+ long fl = mount_options[i].flags;
+ if(fl < 0) *flags &= fl;
+ else *flags |= fl;
break;
}
- f++;
- }
-#if defined CONFIG_FEATURE_MOUNT_LOOP
- if (!strcasecmp("loop", options)) { /* loop device support */
- use_loop = TRUE;
- gotone = TRUE;
}
-#endif
- if (!gotone) {
- if (**strflags) {
- /* have previous parsed options */
- paste_str(strflags, ",");
- }
- paste_str(strflags, options);
+ // Unrecognized mount option?
+ if(i == sizeof(mount_options)) {
+ // Add it to strflags, to pass on to kernel
+ i = *strflags ? strlen(*strflags) : 0;
+ *strflags = xrealloc(*strflags, i+strlen(options)+2);
+ // Comma separated if it's not the first one
+ if(i) (*strflags)[i] = ',';
+ strcpy((*strflags)+i, options);
}
- if (comma) {
+ // Advance to next option, or finish
+ if(comma) {
*comma = ',';
options = ++comma;
- } else {
- break;
- }
+ } else break;
}
}
-static int mount_one(char *blockDevice, char *directory, char *filesystemType,
- unsigned long flags, char *string_flags, int useMtab,
- int fakeIt, char *mtab_opts, int whineOnErrors,
- int mount_all)
-{
- int status = 0;
- if (strcmp(filesystemType, "auto") == 0) {
- char buf[255];
- FILE *f;
- int read_proc = 0;
-
- f = fopen("/etc/filesystems", "r");
-
- if (f) {
- while (fgets(buf, sizeof(buf), f)) {
- if (*buf == '*') {
- read_proc = 1;
- } else if (*buf == '#') {
- continue;
- } else {
- filesystemType = buf;
-
- /* Add NULL termination to each line */
- while (*filesystemType && !isspace(*filesystemType)) {
- filesystemType++;
- }
- *filesystemType = '\0';
-
- filesystemType = buf;
-
- if (bb_strlen(filesystemType)) {
- status = do_mount(blockDevice, directory, filesystemType,
- flags | MS_MGC_VAL, string_flags,
- useMtab, fakeIt, mtab_opts, mount_all);
- if (status) {
- break;
- }
- }
-
- }
- }
- fclose(f);
- } else {
- read_proc = 1;
- }
-
- if (read_proc && !status) {
-
- f = bb_xfopen("/proc/filesystems", "r");
+/* This does the work */
- while (fgets(buf, sizeof(buf), f) != NULL) {
- filesystemType = buf;
- if (*filesystemType == '\t') { /* Not a nodev filesystem */
-
- /* Add NULL termination to each line */
- while (*filesystemType && *filesystemType != '\n') {
- filesystemType++;
- }
- *filesystemType = '\0';
-
- filesystemType = buf;
- filesystemType++; /* hop past tab */
-
- status = do_mount(blockDevice, directory, filesystemType,
- flags | MS_MGC_VAL, string_flags, useMtab,
- fakeIt, mtab_opts, mount_all);
- if (status) {
- break;
- }
- }
- }
- fclose(f);
- }
- } else {
- status = do_mount(blockDevice, directory, filesystemType,
- flags | MS_MGC_VAL, string_flags, useMtab, fakeIt,
- mtab_opts, mount_all);
- }
-
- if (!status) {
- if (whineOnErrors) {
- bb_perror_msg("Mounting %s on %s failed", blockDevice, directory);
- }
- return (FALSE);
- }
- return (TRUE);
-}
-
-static void show_mounts(char *onlytype)
+extern int mount_main(int argc, char **argv)
{
- FILE *mountTable = setmntent(bb_path_mtab_file, "r");
-
- if (mountTable) {
- struct mntent *m;
+ char *string_flags = 0, *fsType = 0, *blockDevice = 0, *directory = 0,
+ *loopFile = 0, *buf = 0,
+ *files[] = {"/etc/filesystems", "/proc/filesystems", 0};
+ int i, opt, all = FALSE, fakeIt = FALSE, allowWrite = FALSE,
+ rc = EXIT_FAILURE, useMtab = ENABLE_FEATURE_MTAB_SUPPORT;
+ int flags=0xc0ed0000; // Needed for linux 2.2, ignored by 2.4 and 2.6.
+ FILE *file = 0,*f = 0;
+ char path[PATH_MAX*2];
+ struct mntent m;
+ struct stat statbuf;
- while ((m = getmntent(mountTable)) != 0) {
- char *blockDevice = m->mnt_fsname;
+ /* parse long options, like --bind and --move. Note that -o option
+ * and --option are synonymous. Yes, this means --remount,rw works. */
- if (strcmp(blockDevice, "rootfs") == 0) {
- continue;
- } else if (strcmp(blockDevice, "/dev/root") == 0) {
- blockDevice = find_real_root_device_name();
- }
- if (!onlytype || (strcmp(m->mnt_type, onlytype) == 0)) {
- printf("%s on %s type %s (%s)\n", blockDevice, m->mnt_dir,
- m->mnt_type, m->mnt_opts);
- }
-#ifdef CONFIG_FEATURE_CLEAN_UP
- if (blockDevice != m->mnt_fsname) {
- free(blockDevice);
- }
-#endif
- }
- endmntent(mountTable);
- } else {
- bb_perror_msg_and_die(bb_path_mtab_file);
+ for(i = opt = 0; i < argc; i++) {
+ if(argv[i][0] == '-' && argv[i][1] == '-')
+ parse_mount_options(argv[i]+2, &flags, &string_flags);
+ else argv[opt++] = argv[i];
}
- exit(EXIT_SUCCESS);
-}
+ argc = opt;
-extern int mount_main(int argc, char **argv)
-{
- struct stat statbuf;
- char *string_flags = bb_xstrdup("");
- char *extra_opts;
- int flags = 0;
- char *filesystemType = "auto";
- int got_filesystemType = 0;
- char *device = xmalloc(PATH_MAX);
- char *directory = xmalloc(PATH_MAX);
- struct mntent *m = NULL;
- int all = FALSE;
- int fakeIt = FALSE;
- int useMtab = TRUE;
- int rc = EXIT_FAILURE;
- FILE *f = 0;
- int opt;
-
- /* Parse options */
- while ((opt = getopt(argc, argv, "o:rt:wafnv")) > 0) {
+ // Parse remaining options
+
+ while((opt = getopt(argc, argv, "o:t:rwafnv")) > 0) {
switch (opt) {
case 'o':
parse_mount_options(optarg, &flags, &string_flags);
break;
+ case 't':
+ fsType = optarg;
+ break;
case 'r':
flags |= MS_RDONLY;
break;
- case 't':
- filesystemType = optarg;
- got_filesystemType = 1;
- break;
case 'w':
- flags &= ~MS_RDONLY;
+ allowWrite=TRUE;
break;
case 'a':
all = TRUE;
@@ -405,93 +163,238 @@ extern int mount_main(int argc, char **argv)
fakeIt = TRUE;
break;
case 'n':
-#ifdef CONFIG_FEATURE_MTAB_SUPPORT
useMtab = FALSE;
-#endif
break;
case 'v':
- break; /* ignore -v */
+ break; // ignore -v
+ default:
+ bb_show_usage();
}
}
- if (!all && (optind == argc)) {
- show_mounts(got_filesystemType ? filesystemType : NULL);
- }
+ // If we have no arguments, show currently mounted filesystems
- if (optind < argc) {
- /* if device is a filename get its real path */
- if (stat(argv[optind], &statbuf) == 0) {
- char *tmp = bb_simplify_path(argv[optind]);
+ if(!all && (optind == argc)) {
+ FILE *mountTable = setmntent(bb_path_mtab_file, "r");
- safe_strncpy(device, tmp, PATH_MAX);
- } else {
- safe_strncpy(device, argv[optind], PATH_MAX);
+ if(!mountTable) bb_perror_msg_and_die(bb_path_mtab_file);
+
+ while (getmntent_r(mountTable,&m,path,sizeof(path))) {
+ blockDevice = m.mnt_fsname;
+
+ // Clean up display a little bit regarding root devie
+ if(!strcmp(blockDevice, "rootfs")) continue;
+ if(!strcmp(blockDevice, "/dev/root"))
+ blockDevice = find_block_device("/");
+
+ if(!fsType || !strcmp(m.mnt_type, fsType))
+ printf("%s on %s type %s (%s)\n", blockDevice, m.mnt_dir,
+ m.mnt_type, m.mnt_opts);
+ if(ENABLE_FEATURE_CLEAN_UP && blockDevice != m.mnt_fsname)
+ free(blockDevice);
}
+ endmntent(mountTable);
+ return EXIT_SUCCESS;
}
- if (optind + 1 < argc)
- directory = bb_simplify_path(argv[optind + 1]);
+ /* The next argument is what to mount. if there's an argument after that
+ * it's where to mount it. If we're not mounting all, and we have both
+ * of these arguments, jump straight to the actual mount. */
+
+ statbuf.st_mode=0;
+ if(optind < argc)
+ blockDevice = !stat(argv[optind], &statbuf) ?
+ bb_simplify_path(argv[optind]) :
+ (ENABLE_FEATURE_CLEAN_UP ? strdup(argv[optind]) : argv[optind]);
+ if(optind+1 < argc) directory = bb_simplify_path(argv[optind+1]);
+
+ // If we don't have to loop through fstab, skip ahead a bit.
+
+ if(!all && optind+1!=argc) goto singlemount;
+
+ // Loop through /etc/fstab entries to look up this entry.
- if (all || optind + 1 == argc) {
- f = setmntent("/etc/fstab", "r");
+ if(!(file=setmntent("/etc/fstab","r")))
+ bb_perror_msg_and_die("\nCannot read /etc/fstab");
+ for(;;) {
- if (f == NULL)
- bb_perror_msg_and_die("\nCannot read /etc/fstab");
+ // Get next fstab entry
- while ((m = getmntent(f)) != NULL) {
- if (!all && (optind + 1 == argc)
- && ((strcmp(device, m->mnt_fsname) != 0)
- && (strcmp(device, m->mnt_dir) != 0))) {
+ if(!getmntent_r(file,&m,path,sizeof(path))) {
+ if(!all)
+ bb_perror_msg("Can't find %s in /etc/fstab\n", blockDevice);
+ break;
+ }
+
+ // If we're mounting all and all doesn't mount this one, skip it.
+
+ if(all) {
+ if(strstr(m.mnt_opts,"noauto") || strstr(m.mnt_type,"swap"))
continue;
+ flags=0;
+
+ /* If we're mounting 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 */
+
+ } else if(strcmp(blockDevice,m.mnt_fsname) &&
+ strcmp(argv[optind],m.mnt_fsname) &&
+ strcmp(blockDevice,m.mnt_dir) &&
+ strcmp(argv[optind],m.mnt_dir)) continue;
+
+ /* Parse flags from /etc/fstab (unless this is a single mount
+ * overriding fstab -- note the "all" test above zeroed the flags,
+ * to prevent flags from previous entries affecting this one, so
+ * the only way we could get here with nonzero flags is a single
+ * mount). */
+
+ if(!flags) {
+ if(ENABLE_FEATURE_CLEAN_UP) free(string_flags);
+ string_flags=NULL;
+ parse_mount_options(m.mnt_opts, &flags, &string_flags);
+ }
+
+ /* Fill out remaining fields with info from mtab */
+
+ if(ENABLE_FEATURE_CLEAN_UP) {
+ free(blockDevice);
+ blockDevice=strdup(m.mnt_fsname);
+ free(directory);
+ directory=strdup(m.mnt_type);
+ } else {
+ blockDevice=m.mnt_fsname;
+ directory=m.mnt_dir;
+ }
+ fsType=m.mnt_type;
+
+ /* Ok, we're ready to actually mount a specific source on a specific
+ * directory now. */
+
+singlemount:
+
+ // If they said -w, override fstab
+
+ if(allowWrite) flags&=~MS_RDONLY;
+
+ // Might this be an NFS filesystem?
+
+ if(ENABLE_NFSMOUNT && (!fsType || !strcmp(fsType,"nfs")) &&
+ strchr(blockDevice, ':') != NULL)
+ {
+ if(nfsmount(blockDevice, directory, &flags, &string_flags, 1))
+ bb_perror_msg("nfsmount failed");
+ else {
+ rc=EXIT_SUCCESS;
+ fsType="nfs";
}
+ } else {
+
+ // Do we need to allocate a loopback device?
- if (all && ( /* If we're mounting 'all' */
- (strstr(m->mnt_opts, "noauto")) || /* and the file system isn't noauto, */
- (strstr(m->mnt_type, "swap")))) /* and isn't swap, then mount it */
+ if(ENABLE_FEATURE_MOUNT_LOOP && !fakeIt && S_ISREG(statbuf.st_mode))
{
- continue;
+ loopFile = blockDevice;
+ blockDevice = 0;
+ switch(set_loop(&blockDevice, loopFile, 0)) {
+ case 0:
+ case 1:
+ break;
+ default:
+ bb_error_msg_and_die(
+ errno == EPERM || errno == EACCES ?
+ bb_msg_perm_denied_are_you_root :
+ "Couldn't setup loop device");
+ break;
+ }
}
- if (all || flags == 0) { /* Allow single mount to override fstab flags */
- flags = 0;
- string_flags[0] = 0;
- parse_mount_options(m->mnt_opts, &flags, &string_flags);
- }
+ /* If we know the fstype (or don't need to), jump straight
+ * to the actual mount. */
- strcpy(device, m->mnt_fsname);
- strcpy(directory, m->mnt_dir);
- filesystemType = bb_xstrdup(m->mnt_type);
- singlemount:
- extra_opts = string_flags;
- rc = EXIT_SUCCESS;
-#ifdef CONFIG_NFSMOUNT
- if (strchr(device, ':') != NULL) {
- filesystemType = "nfs";
- if (nfsmount
- (device, directory, &flags, &extra_opts, &string_flags,
- 1)) {
- bb_perror_msg("nfsmount failed");
- rc = EXIT_FAILURE;
+ if(fsType || (flags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
+ goto mount_it_now;
+ }
+
+ // Loop through filesystem types until mount succeeds or we run out
+
+ for(i = 0; files[i] && rc; i++) {
+ f = fopen(files[i], "r");
+ if(!f) continue;
+ // Get next block device backed filesystem
+ for(buf = 0; (buf = fsType = bb_get_chomped_line_from_file(f));
+ free(buf))
+ {
+ // Skip funky entries in /proc
+ if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue;
+
+ while(isspace(*fsType)) fsType++;
+ if(*buf=='#' || *buf=='*') continue;
+ if(!*fsType) continue;
+mount_it_now:
+ // Okay, try to mount
+
+ if (!fakeIt) {
+ for(;;) {
+ rc = mount(blockDevice, directory, fsType, flags, string_flags);
+ if(!rc || (flags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
+ break;
+ bb_error_msg("%s is write-protected, mounting read-only", blockDevice);
+ flags|=MS_RDONLY;
+ }
}
+ if(!rc) break;
}
-#endif
- if (!mount_one
- (device, directory, filesystemType, flags, string_flags,
- useMtab, fakeIt, extra_opts, TRUE, all)) {
- rc = EXIT_FAILURE;
+ if(f) fclose(f);
+ if(!f || !rc) break;
+ }
+
+ /* If the mount was sucessful, and we're maintaining an old-style
+ * mtab file by hand, add new entry to it now. */
+ if((!rc || fakeIt) && useMtab) {
+ FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
+
+ if(!mountTable) bb_perror_msg(bb_path_mtab_file);
+ else {
+ // Remove trailing / (if any) from directory we mounted on
+ int length=strlen(directory);
+ if(length>1 && directory[length-1] == '/')
+ directory[length-1]=0;
+
+ // Fill out structure (should be ok to re-use existing one).
+ m.mnt_fsname=blockDevice;
+ m.mnt_dir=directory;
+ m.mnt_type=fsType ? : "--bind";
+ m.mnt_opts=string_flags ? :
+ ((flags & MS_RDONLY) ? "ro" : "rw");
+ m.mnt_freq = 0;
+ m.mnt_passno = 0;
+
+ // Write and close
+ addmntent(mountTable, &m);
+ endmntent(mountTable);
}
- if (!all) {
- break;
+ } else {
+ // Mount failed. Clean up
+ if(loopFile) {
+ del_loop(blockDevice);
+ if(ENABLE_FEATURE_CLEAN_UP) free(loopFile);
}
+ // Don't whine about already mounted fs when mounting all.
+ if(rc<0 && errno == EBUSY && all) rc=0;
+ else if (errno == EPERM)
+ bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
}
- if (f) {
- endmntent(f);
+ // We couldn't free this earlier becase fsType could be in buf.
+ if(ENABLE_FEATURE_CLEAN_UP) {
+ free(buf);
+ free(blockDevice);
+ free(directory);
}
- if (!all && f && m == NULL) {
- fprintf(stderr, "Can't find %s in /etc/fstab\n", device);
- }
- return rc;
+ if(!all) break;
}
- goto singlemount;
+ if(file) endmntent(file);
+ if(rc) bb_perror_msg("Mounting %s on %s failed", blockDevice, directory);
+
+ return rc ? : EXIT_FAILURE;
}