From 8e10b7420a10b73625eee93ea4096f4a2bc21ad5 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 25 Apr 2007 15:52:39 +0000 Subject: [PATCH] *** empty log message *** --- ChangeLog | 11 +++ lib/Makefile.am | 2 +- lib/helper.c | 7 -- lib/mount.c | 104 ++++++++++++++-------------- lib/mount_util.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++ lib/mount_util.h | 15 ++++ util/.cvsignore | 1 + util/Makefile.am | 2 + util/fusermount.c | 130 ++--------------------------------- 9 files changed, 257 insertions(+), 186 deletions(-) create mode 100644 lib/mount_util.c create mode 100644 lib/mount_util.h diff --git a/ChangeLog b/ChangeLog index c113245..b5f83b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2007-04-25 Miklos Szeredi + + * Improve mounting support in libfuse: + - check non-empty mountpoint + - only fall back to fusermount when necessary + +2007-04-23 Miklos Szeredi + + * Don't chdir to "/" in foreground mode, it causes more trouble + than it's worth + 2007-04-18 Miklos Szeredi * 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 #include @@ -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 + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB. +*/ + +#include "mount_util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + + This program can be distributed under the terms of the GNU LGPL. + See the file COPYING.LIB. +*/ + +#include + +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 +#include "mount_util.h" #include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -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); -- 2.30.2