* bb_getopt_ulflags();
*/
-/* Design notes: There is no spec for this. Remind me to write one.
+/* Design notes: There is no spec for mount. Remind me to write one.
mount_main() calls singlemount() which calls mount_it_now().
-
+
mount_main() can loop through /etc/fstab for mount -a
singlemount() can loop through /etc/filesystems for fstype detection.
mount_it_now() does the actual mount.
*/
-#include <limits.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#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"
+#include <mntent.h>
// These two aren't always defined in old headers
#ifndef MS_BIND
{"defaults", 0},
{"quiet", 0},
- // vfs flags
+ // vfs flags
{"ro", MS_RDONLY},
{"rw", ~MS_RDONLY},
{"diratime", ~MS_NODIRATIME},
{"nodiratime", MS_NODIRATIME},
{"loud", ~MS_SILENT},
-
+
// action flags
{"remount", MS_REMOUNT},
static void append_mount_options(char **oldopts, char *newopts)
{
if(*oldopts && **oldopts) {
- char *temp=bb_xasprintf("%s,%s",*oldopts,newopts);
+ char *temp=xasprintf("%s,%s",*oldopts,newopts);
free(*oldopts);
*oldopts=temp;
} else {
if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
- *oldopts = bb_xstrdup(newopts);
+ *oldopts = xstrdup(newopts);
}
}
// If unrecognized not NULL, append unrecognized mount options */
if (unrecognized
&& i == (sizeof(mount_options) / sizeof(*mount_options)))
- {
+ {
// Add it to strflags, to pass on to kernel
i = *unrecognized ? strlen(*unrecognized) : 0;
*unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);
-
+
// Comma separated if it's not the first one
if (i) (*unrecognized)[i++] = ',';
strcpy((*unrecognized)+i, options);
}
-
+
// Advance to next option, or finish
if(comma) {
*comma = ',';
options = ++comma;
} else break;
}
-
+
return flags;
}
for(i = 0; filesystems[i]; i++) {
if(!(f = fopen(filesystems[i], "r"))) continue;
-
+
for(fs = buf = 0; (fs = buf = bb_get_chomped_line_from_file(f));
free(buf))
{
if(!strncmp(buf,"nodev",5) && isspace(buf[5])) continue;
-
+
while(isspace(*fs)) fs++;
if(*fs=='#' || *fs=='*') continue;
if(!*fs) continue;
-
- list=llist_add_to_end(list,bb_xstrdup(fs));
+
+ llist_add_to_end(&list,xstrdup(fs));
}
if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
}
#if ENABLE_FEATURE_CLEAN_UP
static void delete_block_backed_filesystems(void)
{
- llist_free(fslist);
+ llist_free(fslist, free);
}
+#else
+void delete_block_backed_filesystems(void);
#endif
#if ENABLE_FEATURE_MTAB_SUPPORT
// Perform actual mount of specific filesystem at specific location.
-static int mount_it_now(struct mntent *mp, int vfsflags)
+static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
{
int rc;
- char *filteropts = 0;
-
- parse_mount_options(mp->mnt_opts, &filteropts);
if (fakeIt) { return 0; }
vfsflags |= MS_RDONLY;
}
- free(filteropts);
-
// Abort entirely if permission denied.
if (rc && errno == EPERM)
/* If the mount was successful, and we're maintaining an old-style
* mtab file by hand, add the new entry to it now. */
-
+
if(ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc) {
FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
int i;
if (ENABLE_FEATURE_CLEAN_UP)
if(strcmp(mp->mnt_type,"--bind")) mp->mnt_type = 0;
}
-
+
return rc;
}
// Mount one directory. Handles NFS, loopback, autobind, and filesystem type
// detection. Returns 0 for success, nonzero for failure.
-static int singlemount(struct mntent *mp)
+static int singlemount(struct mntent *mp, int ignore_busy)
{
- int rc = 1, vfsflags;
- char *loopFile = 0;
+ int rc = -1, vfsflags;
+ char *loopFile = 0, *filteropts = 0;
llist_t *fl = 0;
struct stat st;
- vfsflags = parse_mount_options(mp->mnt_opts, 0);
+ vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
// Treat fstype "auto" as unspecified.
(!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&
strchr(mp->mnt_fsname, ':') != NULL)
{
- char *options=0;
- parse_mount_options(mp->mnt_opts, &options);
- if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &options, 1)) {
+ if (nfsmount(mp->mnt_fsname, mp->mnt_dir, &vfsflags, &filteropts, 1)) {
bb_perror_msg("nfsmount failed");
- return 1;
+ goto report_error;
+ } else {
+ // Strangely enough, nfsmount() doesn't actually mount() anything.
+ mp->mnt_type = "nfs";
+ rc = mount_it_now(mp, vfsflags, filteropts);
+ if (ENABLE_FEATURE_CLEAN_UP) free(filteropts);
+
+ goto report_error;
}
-
- // Strangely enough, nfsmount() doesn't actually mount() anything.
-
- else return mount_it_now(mp, vfsflags);
}
- // Look at the file. (Not found isn't a failure for remount.)
+ // 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));
-
- if (!(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) {
+ else if (!(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;
* to the actual mount. */
if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
- rc = mount_it_now(mp, vfsflags);
+ rc = mount_it_now(mp, vfsflags, filteropts);
// Loop through filesystem types until mount succeeds or we run out
if (!fslist) {
fslist = get_block_backed_filesystems();
-#if ENABLE_FEATURE_CLEAN_UP
if (ENABLE_FEATURE_CLEAN_UP && fslist)
atexit(delete_block_backed_filesystems);
-#endif
}
-
+
for (fl = fslist; fl; fl = fl->link) {
mp->mnt_type = fl->data;
- if (!(rc = mount_it_now(mp,vfsflags))) break;
+ if (!(rc = mount_it_now(mp,vfsflags, filteropts))) break;
mp->mnt_type = 0;
}
}
- // Mount failed. Clean up
- if (rc && loopFile) {
+ if (ENABLE_FEATURE_CLEAN_UP) free(filteropts);
+
+ // 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) {
+ if (ENABLE_FEATURE_CLEAN_UP) {
free(loopFile);
free(mp->mnt_fsname);
}
}
+report_error:
+ if (rc && errno == EBUSY && ignore_busy) rc = 0;
+ if (rc < 0)
+ bb_perror_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 = bb_xstrdup(""), *fstabname, *fstype=0, *storage_path=0;
+ char *cmdopts = xstrdup(""), *fstabname, *fstype=0, *storage_path=0;
FILE *fstab;
- int i, opt, all = FALSE, rc = 1;
+ 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);
+ append_mount_options(&cmdopts,argv[i]+2);
} else argv[opt++] = argv[i];
}
argc = opt;
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) {
mtpair->mnt_dir = argv[optind+1];
mtpair->mnt_type = fstype;
mtpair->mnt_opts = cmdopts;
- rc = singlemount(mtpair);
+ rc = singlemount(mtpair, 0);
goto clean_up;
}
// If we have at least one argument, it's the storage location
-
+
if (optind < argc) storage_path = bb_simplify_path(argv[optind]);
-
+
// Open either fstab or mtab
if (parse_mount_options(cmdopts,0) & MS_REMOUNT)
fstabname = (char *)bb_path_mtab_file; // Again with the evil const.
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));
// Get next fstab entry
- if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1,
- sizeof(bb_common_bufsiz1)))
+ 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 (!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=bb_xstrdup(mtcur->mnt_opts);
+ mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
append_mount_options(&(mtcur->mnt_opts),cmdopts);
- rc = singlemount(mtcur);
+ rc = singlemount(mtcur, 0);
free(mtcur->mnt_opts);
}
- break;
+ goto clean_up;
}
/* If we're trying to mount something specific and this isn't it,
// 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 this thing.
- rc = singlemount(mtcur);
- if (rc) {
- // Don't whine about already mounted fs when mounting all.
- if (errno == EBUSY) rc = 0;
- else break;
+ if (singlemount(mtcur, 1)) {
+ /* Count number of failed mounts */
+ rc++;
}
}
}
if (ENABLE_FEATURE_CLEAN_UP) {
free(storage_path);
free(cmdopts);
- free(fstype);
}
-
- if(rc)
- bb_perror_msg("Mounting %s on %s failed",
- mtcur->mnt_fsname, mtcur->mnt_dir);
return rc;
}