aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/helper.c7
-rw-r--r--lib/mount.c104
-rw-r--r--lib/mount_util.c171
-rw-r--r--lib/mount_util.h15
-rw-r--r--util/.cvsignore1
-rw-r--r--util/Makefile.am2
-rw-r--r--util/fusermount.c130
9 files changed, 257 insertions, 186 deletions
diff --git a/ChangeLog b/ChangeLog
index c113245..b5f83b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2007-04-25 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Improve mounting support in libfuse:
+ - check non-empty mountpoint
+ - only fall back to fusermount when necessary
+
+2007-04-23 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Don't chdir to "/" in foreground mode, it causes more trouble
+ than it's worth
+
2007-04-18 Miklos Szeredi <miklos@szeredi.hu>
* Replace utils/mount.fuse "sh" script with a "C" program
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 40f7014..0247d11 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -8,7 +8,7 @@ lib_LTLIBRARIES = libfuse.la libulockmgr.la
if BSD
mount_source = mount_bsd.c
else
-mount_source = mount.c
+mount_source = mount.c mount_util.c mount_util.h
endif
if ICONV
diff --git a/lib/helper.c b/lib/helper.c
index a1e9eb0..e6bfc4d 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -180,13 +180,6 @@ int fuse_daemonize(int foreground)
perror("fuse: failed to daemonize program\n");
return -1;
}
- } else {
- /* Ensure consistant behavior across debug and normal modes */
- res = chdir("/");
- if (res == -1) {
- perror("fuse: failed to change working directory to /\n");
- return -1;
- }
}
return 0;
}
diff --git a/lib/mount.c b/lib/mount.c
index 5232737..3ca5e7e 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -10,6 +10,7 @@
#include "fuse_i.h"
#include "fuse_opt.h"
#include "fuse_common_compat.h"
+#include "mount_util.h"
#include <stdio.h>
#include <stdlib.h>
@@ -52,7 +53,6 @@ struct mount_opts {
int flags;
int nonempty;
int blkdev;
- int large_read;
char *fsname;
char *mtab_opts;
char *fusermount_opts;
@@ -67,13 +67,12 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_MOUNT_OPT("nonempty", nonempty),
FUSE_MOUNT_OPT("blkdev", blkdev),
FUSE_MOUNT_OPT("fsname=%s", fsname),
- FUSE_MOUNT_OPT("large_read", large_read),
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
- FUSE_OPT_KEY("large_read", KEY_FUSERMOUNT_OPT),
+ FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
@@ -356,34 +355,6 @@ int fuse_mount_compat22(const char *mountpoint, const char *opts)
return rv;
}
-static int add_mount(const char *fsname, const char *mnt, const char *type,
- const char *opts)
-{
- int res;
- int status;
-
- res = fork();
- if (res == -1) {
- perror("fork");
- return -1;
- }
- if (res == 0) {
- setuid(geteuid());
- execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
- fsname, mnt, NULL);
- perror("execl /bin/mount");
- exit(1);
- }
- res = waitpid(res, &status, 0);
- if (res == -1) {
- perror("waitpid");
- return -1;
- }
- if (status != 0)
- return -1;
-
- return 0;
-}
static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
const char *mnt_opts)
@@ -395,20 +366,29 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
int fd;
int res;
- /* For now silently fall back to fusermount if something doesn't work */
-
- /* FIXME: check non-empty mountpoint*/
-
- if (mo->large_read)
- return -1;
-
res = lstat(mnt, &stbuf);
- if (res == -1)
+ if (res == -1) {
+ fprintf(stderr ,"fuse: failed to access mountpoint %s: %s\n",
+ mnt, strerror(errno));
return -1;
+ }
+
+ if (!mo->nonempty) {
+ res = fuse_mnt_check_empty("fuse", mnt, stbuf.st_mode, stbuf.st_size);
+ if (res == -1)
+ return -1;
+ }
fd = open(devname, O_RDWR);
- if (fd == -1)
+ if (fd == -1) {
+ if (errno == ENODEV || errno == ENOENT)
+ fprintf(stderr,
+ "fuse: device not found, try 'modprobe fuse' first\n");
+ else
+ fprintf(stderr, "fuse: failed to open %s: %s\n", devname,
+ strerror(errno));
return -1;
+ }
if (mo->fsname)
devname = mo->fsname;
@@ -416,24 +396,42 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd,
stbuf.st_mode & S_IFMT, getuid(), getgid());
- if (fuse_opt_add_opt(&mo->kernel_opts, tmp) == -1) {
- close(fd);
- return -1;
- }
+ res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
+ if (res == -1)
+ goto out_close;
+
res = mount(devname, mnt, type, mo->flags, mo->kernel_opts);
if (res == -1) {
- close(fd);
- return -1;
+ /*
+ * Maybe kernel doesn't support unprivileged mounts, in this
+ * case try falling back to fusermount
+ */
+ if (errno == EPERM)
+ res = -2;
+ else
+ perror("fuse: mount failed");
+ goto out_close;
}
+
if (geteuid() == 0) {
- res = add_mount(devname, mnt, type, mnt_opts);
- if (res == -1) {
- umount2(mnt, 2); /* lazy umount */
- close(fd);
- return -1;
- }
+ char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
+ res = -1;
+ if (!newmnt)
+ goto out_umount;
+
+ res = fuse_mnt_add_mount("fuse", devname, newmnt, type, mnt_opts);
+ free(newmnt);
+ if (res == -1)
+ goto out_umount;
}
+
return fd;
+
+ out_umount:
+ umount2(mnt, 2); /* lazy umount */
+ out_close:
+ close(fd);
+ return res;
}
static int get_mnt_flag_opts(char **mnt_optsp, int flags)
@@ -481,7 +479,7 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
goto out;
res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
- if (res == -1) {
+ if (res == -2) {
if (mo.fusermount_opts &&
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
goto out;
diff --git a/lib/mount_util.c b/lib/mount_util.c
new file mode 100644
index 0000000..852e264
--- /dev/null
+++ b/lib/mount_util.c
@@ -0,0 +1,171 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU LGPL.
+ See the file COPYING.LIB.
+*/
+
+#include "mount_util.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+int fuse_mnt_add_mount(const char *progname, const char *fsname,
+ const char *mnt, const char *type, const char *opts)
+{
+ int res;
+ int status;
+
+ res = fork();
+ if (res == -1) {
+ fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
+ return -1;
+ }
+ if (res == 0) {
+ char templ[] = "/tmp/fusermountXXXXXX";
+ char *tmp;
+
+ setuid(geteuid());
+
+ /*
+ * hide in a directory, where mount isn't able to resolve
+ * fsname as a valid path
+ */
+ tmp = mkdtemp(templ);
+ if (!tmp) {
+ fprintf(stderr, "%s: failed to create temporary directory\n",
+ progname);
+ exit(1);
+ }
+ if (mkdir(tmp, 0) == -1) {
+ fprintf(stderr, "%s: failed to mkdir %s: %s\n", progname, tmp,
+ strerror(errno));
+ exit(1);
+ }
+ if (chdir(tmp)) {
+ fprintf(stderr, "%s: failed to chdir to %s: %s\n",
+ progname, tmp, strerror(errno));
+ exit(1);
+ }
+ rmdir(tmp);
+ execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
+ fsname, mnt, NULL);
+ fprintf(stderr, "%s: failed to execute /bin/mount: %s\n", progname,
+ strerror(errno));
+ exit(1);
+ }
+ res = waitpid(res, &status, 0);
+ if (res == -1) {
+ fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
+ return -1;
+ }
+ if (status != 0)
+ return -1;
+
+ return 0;
+}
+
+char *fuse_mnt_resolve_path(const char *progname, const char *orig)
+{
+ char buf[PATH_MAX];
+ char *copy;
+ char *dst;
+ char *end;
+ char *lastcomp;
+ const char *toresolv;
+
+ if (!orig[0]) {
+ fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
+ return NULL;
+ }
+
+ copy = strdup(orig);
+ if (copy == NULL) {
+ fprintf(stderr, "%s: failed to allocate memory\n", progname);
+ return NULL;
+ }
+
+ toresolv = copy;
+ lastcomp = NULL;
+ for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
+ if (end[0] != '/') {
+ char *tmp;
+ end[1] = '\0';
+ tmp = strrchr(copy, '/');
+ if (tmp == NULL) {
+ lastcomp = copy;
+ toresolv = ".";
+ } else {
+ lastcomp = tmp + 1;
+ if (tmp == copy)
+ toresolv = "/";
+ }
+ if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
+ lastcomp = NULL;
+ toresolv = copy;
+ }
+ else if (tmp)
+ tmp[0] = '\0';
+ }
+ if (realpath(toresolv, buf) == NULL) {
+ fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
+ strerror(errno));
+ free(copy);
+ return NULL;
+ }
+ if (lastcomp == NULL)
+ dst = strdup(buf);
+ else {
+ dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
+ if (dst) {
+ unsigned buflen = strlen(buf);
+ if (buflen && buf[buflen-1] == '/')
+ sprintf(dst, "%s%s", buf, lastcomp);
+ else
+ sprintf(dst, "%s/%s", buf, lastcomp);
+ }
+ }
+ free(copy);
+ if (dst == NULL)
+ fprintf(stderr, "%s: failed to allocate memory\n", progname);
+ return dst;
+}
+
+int fuse_mnt_check_empty(const char *progname, const char *mnt,
+ mode_t rootmode, off_t rootsize)
+{
+ int isempty = 1;
+
+ if (S_ISDIR(rootmode)) {
+ struct dirent *ent;
+ DIR *dp = opendir(mnt);
+ if (dp == NULL) {
+ fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n",
+ progname, strerror(errno));
+ return -1;
+ }
+ while ((ent = readdir(dp)) != NULL) {
+ if (strcmp(ent->d_name, ".") != 0 &&
+ strcmp(ent->d_name, "..") != 0) {
+ isempty = 0;
+ break;
+ }
+ }
+ closedir(dp);
+ } else if (rootsize)
+ isempty = 0;
+
+ if (!isempty) {
+ fprintf(stderr, "%s: mountpoint is not empty\n", progname);
+ fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
+ return -1;
+ }
+ return 0;
+}
diff --git a/lib/mount_util.h b/lib/mount_util.h
new file mode 100644
index 0000000..d341df7
--- /dev/null
+++ b/lib/mount_util.h
@@ -0,0 +1,15 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU LGPL.
+ See the file COPYING.LIB.
+*/
+
+#include <sys/types.h>
+
+int fuse_mnt_add_mount(const char *progname, const char *fsname,
+ const char *mnt, const char *type, const char *opts);
+char *fuse_mnt_resolve_path(const char *progname, const char *orig);
+int fuse_mnt_check_empty(const char *progname, const char *mnt,
+ mode_t rootmode, off_t rootsize);
diff --git a/util/.cvsignore b/util/.cvsignore
index d7a4699..85b4a71 100644
--- a/util/.cvsignore
+++ b/util/.cvsignore
@@ -5,3 +5,4 @@ Makefile
fusermount
ulockmgr_server
fuse_ioslave
+mount.fuse
diff --git a/util/Makefile.am b/util/Makefile.am
index 56046c0..cc3e355 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -5,6 +5,8 @@ bin_PROGRAMS = fusermount ulockmgr_server
noinst_PROGRAMS = mount.fuse
fusermount_SOURCES = fusermount.c
+fusermount_LDADD = ../lib/mount_util.o
+fusermount_CPPFLAGS = -I../lib
mount_fuse_SOURCES = mount.fuse.c
ulockmgr_server_SOURCES = ulockmgr_server.c
diff --git a/util/fusermount.c b/util/fusermount.c
index 70903a0..fc68f3d 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -9,6 +9,7 @@
#include <config.h>
+#include "mount_util.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -19,7 +20,6 @@
#include <fcntl.h>
#include <pwd.h>
#include <mntent.h>
-#include <dirent.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mount.h>
@@ -106,30 +106,7 @@ static int do_unmount(const char *mnt, int quiet, int lazy)
static int add_mount(const char *fsname, const char *mnt, const char *type,
const char *opts)
{
- int res;
- int status;
-
- res = fork();
- if (res == -1) {
- perror("fork");
- return -1;
- }
- if (res == 0) {
- setuid(geteuid());
- execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
- fsname, mnt, NULL);
- perror("execl /bin/mount");
- exit(1);
- }
- res = waitpid(res, &status, 0);
- if (res == -1) {
- perror("waitpid");
- return -1;
- }
- if (status != 0)
- return -1;
-
- return 0;
+ return fuse_mnt_add_mount(progname, fsname, mnt, type, opts);
}
static int unmount_fuse(const char *mnt, int quiet, int lazy)
@@ -397,38 +374,6 @@ static int opt_eq(const char *s, unsigned len, const char *opt)
return 0;
}
-static int check_mountpoint_empty(const char *mnt, mode_t rootmode,
- off_t rootsize)
-{
- int isempty = 1;
-
- if (S_ISDIR(rootmode)) {
- struct dirent *ent;
- DIR *dp = opendir(mnt);
- if (dp == NULL) {
- fprintf(stderr, "%s: failed to open mountpoint for reading: %s\n",
- progname, strerror(errno));
- return -1;
- }
- while ((ent = readdir(dp)) != NULL) {
- if (strcmp(ent->d_name, ".") != 0 &&
- strcmp(ent->d_name, "..") != 0) {
- isempty = 0;
- break;
- }
- }
- closedir(dp);
- } else if (rootsize)
- isempty = 0;
-
- if (!isempty) {
- fprintf(stderr, "%s: mountpoint is not empty\n", progname);
- fprintf(stderr, "%s: if you are sure this is safe, use the 'nonempty' mount option\n", progname);
- return -1;
- }
- return 0;
-}
-
static int has_fuseblk(void)
{
char buf[256];
@@ -545,7 +490,8 @@ static int do_mount(const char *mnt, const char **type, mode_t rootmode,
}
}
- if (check_empty && check_mountpoint_empty(mnt, rootmode, rootsize) == -1)
+ if (check_empty &&
+ fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1)
goto err;
if (blkdev)
@@ -811,72 +757,6 @@ static int mount_fuse(const char *mnt, const char *opts)
return fd;
}
-static char *resolve_path(const char *orig)
-{
- char buf[PATH_MAX];
- char *copy;
- char *dst;
- char *end;
- char *lastcomp;
- const char *toresolv;
-
- if (!orig[0]) {
- fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname, orig);
- return NULL;
- }
-
- copy = strdup(orig);
- if (copy == NULL) {
- fprintf(stderr, "%s: failed to allocate memory\n", progname);
- return NULL;
- }
-
- toresolv = copy;
- lastcomp = NULL;
- for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
- if (end[0] != '/') {
- char *tmp;
- end[1] = '\0';
- tmp = strrchr(copy, '/');
- if (tmp == NULL) {
- lastcomp = copy;
- toresolv = ".";
- } else {
- lastcomp = tmp + 1;
- if (tmp == copy)
- toresolv = "/";
- }
- if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
- lastcomp = NULL;
- toresolv = copy;
- }
- else if (tmp)
- tmp[0] = '\0';
- }
- if (realpath(toresolv, buf) == NULL) {
- fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
- strerror(errno));
- free(copy);
- return NULL;
- }
- if (lastcomp == NULL)
- dst = strdup(buf);
- else {
- dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
- if (dst) {
- unsigned buflen = strlen(buf);
- if (buflen && buf[buflen-1] == '/')
- sprintf(dst, "%s%s", buf, lastcomp);
- else
- sprintf(dst, "%s/%s", buf, lastcomp);
- }
- }
- free(copy);
- if (dst == NULL)
- fprintf(stderr, "%s: failed to allocate memory\n", progname);
- return dst;
-}
-
static int send_fd(int sock_fd, int fd)
{
int retval;
@@ -1006,7 +886,7 @@ int main(int argc, char *argv[])
origmnt = argv[optind];
drop_privs();
- mnt = resolve_path(origmnt);
+ mnt = fuse_mnt_resolve_path(progname, origmnt);
restore_privs();
if (mnt == NULL)
exit(1);