aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar Miklos Szeredi <miklos@szeredi.hu>2007-04-25 15:52:39 +0000
committerGravatar Miklos Szeredi <miklos@szeredi.hu>2007-04-25 15:52:39 +0000
commit8e10b7420a10b73625eee93ea4096f4a2bc21ad5 (patch)
tree13ebf4dbdc1aa7ed56fd621ffecbd7809875079c /lib
parent0ac820ee6a02e761ad00e70b93c448de4d227877 (diff)
*** empty log message ***
Diffstat (limited to 'lib')
-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
5 files changed, 238 insertions, 61 deletions
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);