*** empty log message ***
authorMiklos Szeredi <miklos@szeredi.hu>
Wed, 25 Apr 2007 15:52:39 +0000 (15:52 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Wed, 25 Apr 2007 15:52:39 +0000 (15:52 +0000)
ChangeLog
lib/Makefile.am
lib/helper.c
lib/mount.c
lib/mount_util.c [new file with mode: 0644]
lib/mount_util.h [new file with mode: 0644]
util/.cvsignore
util/Makefile.am
util/fusermount.c

index c113245b608618adf0efeb6ad8c7ed8564f35c1d..b5f83b6f8c4db6026d5e36e138cdc69be890d051 100644 (file)
--- 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
index 40f70145f63353455407a4277f81751d5e77fe59..0247d1112de1e7c7a38105a103ac4aca4ecfe2a3 100644 (file)
@@ -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
index a1e9eb021eddf8bb2befe7e615a279f28d006d3e..e6bfc4d7ebaa2cedf4b83d2d3a808f80ac8ebec6 100644 (file)
@@ -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;
 }
index 5232737ec7bac2138496894002486517d79b847d..3ca5e7e6abd4ece424a1c9c12f18c9e503cb972a 100644 (file)
@@ -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 (file)
index 0000000..852e264
--- /dev/null
@@ -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 (file)
index 0000000..d341df7
--- /dev/null
@@ -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);
index d7a46992ce722c65170a0d80e9d738956b35a162..85b4a7110cb1def3dba8bf3a20b2651757357bdd 100644 (file)
@@ -5,3 +5,4 @@ Makefile
 fusermount
 ulockmgr_server
 fuse_ioslave
+mount.fuse
index 56046c0ab127f4a21e3bcece929e4fe082e1ebb9..cc3e355c26eaca95e0875949c96f29e1ce5d15c1 100644 (file)
@@ -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
index 70903a0510bbbd595e757a0992236035ff8aa607..fc68f3dfbaee1ee69a551e9064dc30c9625e49b3 100644 (file)
@@ -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);