merge FreeBSD stuff
authorMiklos Szeredi <miklos@szeredi.hu>
Wed, 16 Nov 2005 13:00:24 +0000 (13:00 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Wed, 16 Nov 2005 13:00:24 +0000 (13:00 +0000)
ChangeLog
Makefile.am
configure.in
example/fusexmp.c
example/fusexmp_fh.c
kernel/fuse_kernel.h
lib/Makefile.am
lib/fuse.c
lib/fuse_lowlevel.c
lib/helper.c
lib/mount_bsd.c [new file with mode: 0644]

index 46c519a8e70a98b41578b01efe452d0460dba0e5..0c99a0d6d0472fb50eb017a841e998dc51491cc0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-11-16  Miklos Szeredi <miklos@szeredi.hu>
+
+       * Merge library part of FreeBSD port.  Patch by Csaba Henk
+
 2005-11-11  Miklos Szeredi <miklos@szeredi.hu>
 
        * Use 64bit type for file handle, so the full range supported by
index caeaed7a7faa7df5154400e16f0688453885b3b7..a0da48e1e64fe65b2218972ef8bbd87bf4394246 100644 (file)
@@ -10,7 +10,7 @@ EXTRA_DIST =                  \
        doc/how-fuse-works      \
        doc/kernel.txt
 
-pkgconfigdir = $(libdir)/pkgconfig
+pkgconfigdir = @pkgconfigdir@
 pkgconfig_DATA = fuse.pc
 
 $(pkgconfig_DATA): config.status
index 633d436cfe25015735cf3a02f8badc30b55bd020..bdd9502fa044b91714a2ed68eaa7fdadc0a4ba7c 100644 (file)
@@ -1,4 +1,5 @@
 AC_INIT(fuse, 2.5.0-pre0)
+AC_CANONICAL_TARGET
 AM_INIT_AUTOMAKE
 AM_CONFIG_HEADER(include/config.h)
 
@@ -13,6 +14,12 @@ if test -z "$mkdir_p"; then
        AC_SUBST(mkdir_p)
 fi
 
+case $target_os in
+     *linux*)  arch=linux;;
+     *bsd*)    arch=bsd;;
+     *)                arch=unknown;;
+esac
+
 if test "$ac_env_CFLAGS_set" != set; then
        CFLAGS="-Wall -W -g -O2"
 fi
@@ -29,16 +36,22 @@ AC_ARG_ENABLE(example,
 AC_ARG_ENABLE(mtab,
        [  --disable-mtab          Disable and ignore usage of /etc/mtab ])
 
+AC_ARG_WITH(pkgconfigdir,
+            [  --with-pkgconfigdir=DIR      pkgconfig file in DIR @<:@LIBDIR/pkgconfig@:>@],
+            [pkgconfigdir=$withval],
+            [pkgconfigdir='${libdir}/pkgconfig'])
+AC_SUBST(pkgconfigdir)
+
 subdirs2="include"
 
-if test "$enable_kernel_module" != "no"; then
+if test "$arch" = linux -a "$enable_kernel_module" != "no"; then
        AC_CONFIG_SUBDIRS(kernel)
 fi
 
 if test "$enable_lib" != "no"; then
        subdirs2="$subdirs2 lib";
 fi
-if test "$enable_util" != "no"; then
+if test "$arch" = linux -a "$enable_util" != "no"; then
        subdirs2="$subdirs2 util";
 fi
 if test "$enable_example" != "no"; then
@@ -47,7 +60,7 @@ fi
 if test "$enable_mtab" = "no"; then
        AC_DEFINE(IGNORE_MTAB, 1, [Don't update /etc/mtab])
 fi
-AC_CHECK_FUNCS([fork setxattr])
+AC_CHECK_FUNCS([fork setxattr fdatasync])
 AC_CHECK_MEMBERS([struct stat.st_atim])
 
 if test -z "$MOUNT_FUSE_PATH"; then
@@ -61,5 +74,8 @@ AC_SUBST(UDEV_RULES_PATH)
 
 AC_SUBST(subdirs2)
 
+AM_CONDITIONAL(LINUX, test "$arch" = linux)
+AM_CONDITIONAL(BSD, test "$arch" = bsd)
+
 AC_CONFIG_FILES([fuse.pc Makefile lib/Makefile util/Makefile example/Makefile include/Makefile])
 AC_OUTPUT
index 5a2e9a0f6d4bf5c8c06821cd8c9f60d2fb7e3e09..26b2be25c1504562e624196a4a23982695e16fde 100644 (file)
@@ -29,7 +29,7 @@ static int xmp_getattr(const char *path, struct stat *stbuf)
     int res;
 
     res = lstat(path, stbuf);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -40,7 +40,7 @@ static int xmp_access(const char *path, int mask)
     int res;
 
     res = access(path, mask);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -51,7 +51,7 @@ static int xmp_readlink(const char *path, char *buf, size_t size)
     int res;
 
     res = readlink(path, buf, size - 1);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     buf[res] = '\0';
@@ -69,10 +69,10 @@ static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
     (void) fi;
 
     dp = opendir(path);
-    if(dp == NULL)
+    if (dp == NULL)
         return -errno;
 
-    while((de = readdir(dp)) != NULL) {
+    while ((de = readdir(dp)) != NULL) {
         struct stat st;
         memset(&st, 0, sizeof(st));
         st.st_ino = de->d_ino;
@@ -89,8 +89,17 @@ static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
 {
     int res;
 
-    res = mknod(path, mode, rdev);
-    if(res == -1)
+    /* On Linux this could just be 'mknod(path, mode, rdev)' but this
+       is more portable */
+    if (S_ISREG(mode)) {
+        res = open(path, O_CREAT | O_EXCL | O_WRONLY, mode);
+        if (res >= 0)
+            res = close(res);
+    } else if (S_ISFIFO(mode))
+        res = mkfifo(path, mode);
+    else
+        res = mknod(path, mode, rdev);
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -101,7 +110,7 @@ static int xmp_mkdir(const char *path, mode_t mode)
     int res;
 
     res = mkdir(path, mode);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -112,7 +121,7 @@ static int xmp_unlink(const char *path)
     int res;
 
     res = unlink(path);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -123,7 +132,7 @@ static int xmp_rmdir(const char *path)
     int res;
 
     res = rmdir(path);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -134,7 +143,7 @@ static int xmp_symlink(const char *from, const char *to)
     int res;
 
     res = symlink(from, to);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -145,7 +154,7 @@ static int xmp_rename(const char *from, const char *to)
     int res;
 
     res = rename(from, to);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -156,7 +165,7 @@ static int xmp_link(const char *from, const char *to)
     int res;
 
     res = link(from, to);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -167,7 +176,7 @@ static int xmp_chmod(const char *path, mode_t mode)
     int res;
 
     res = chmod(path, mode);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -178,7 +187,7 @@ static int xmp_chown(const char *path, uid_t uid, gid_t gid)
     int res;
 
     res = lchown(path, uid, gid);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -189,7 +198,7 @@ static int xmp_truncate(const char *path, off_t size)
     int res;
 
     res = truncate(path, size);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -200,7 +209,7 @@ static int xmp_utime(const char *path, struct utimbuf *buf)
     int res;
 
     res = utime(path, buf);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -212,7 +221,7 @@ static int xmp_open(const char *path, struct fuse_file_info *fi)
     int res;
 
     res = open(path, fi->flags);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     close(res);
@@ -227,11 +236,11 @@ static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
 
     (void) fi;
     fd = open(path, O_RDONLY);
-    if(fd == -1)
+    if (fd == -1)
         return -errno;
 
     res = pread(fd, buf, size, offset);
-    if(res == -1)
+    if (res == -1)
         res = -errno;
 
     close(fd);
@@ -246,11 +255,11 @@ static int xmp_write(const char *path, const char *buf, size_t size,
 
     (void) fi;
     fd = open(path, O_WRONLY);
-    if(fd == -1)
+    if (fd == -1)
         return -errno;
 
     res = pwrite(fd, buf, size, offset);
-    if(res == -1)
+    if (res == -1)
         res = -errno;
 
     close(fd);
@@ -262,7 +271,7 @@ static int xmp_statfs(const char *path, struct statvfs *stbuf)
     int res;
 
     res = statvfs(path, stbuf);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -296,7 +305,7 @@ static int xmp_setxattr(const char *path, const char *name, const char *value,
                         size_t size, int flags)
 {
     int res = lsetxattr(path, name, value, size, flags);
-    if(res == -1)
+    if (res == -1)
         return -errno;
     return 0;
 }
@@ -305,7 +314,7 @@ static int xmp_getxattr(const char *path, const char *name, char *value,
                     size_t size)
 {
     int res = lgetxattr(path, name, value, size);
-    if(res == -1)
+    if (res == -1)
         return -errno;
     return res;
 }
@@ -313,7 +322,7 @@ static int xmp_getxattr(const char *path, const char *name, char *value,
 static int xmp_listxattr(const char *path, char *list, size_t size)
 {
     int res = llistxattr(path, list, size);
-    if(res == -1)
+    if (res == -1)
         return -errno;
     return res;
 }
@@ -321,7 +330,7 @@ static int xmp_listxattr(const char *path, char *list, size_t size)
 static int xmp_removexattr(const char *path, const char *name)
 {
     int res = lremovexattr(path, name);
-    if(res == -1)
+    if (res == -1)
         return -errno;
     return 0;
 }
index 491e6911943eab5e9f7fa68b49eb90ce329fbff9..787f87c3e757d003c125162179bd23f395e0c139 100644 (file)
@@ -26,7 +26,7 @@ static int xmp_getattr(const char *path, struct stat *stbuf)
     int res;
 
     res = lstat(path, stbuf);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -40,7 +40,7 @@ static int xmp_fgetattr(const char *path, struct stat *stbuf,
     (void) path;
 
     res = fstat(fi->fh, stbuf);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -51,7 +51,7 @@ static int xmp_access(const char *path, int mask)
     int res;
 
     res = access(path, mask);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -62,7 +62,7 @@ static int xmp_readlink(const char *path, char *buf, size_t size)
     int res;
 
     res = readlink(path, buf, size - 1);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     buf[res] = '\0';
@@ -97,7 +97,7 @@ static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
         memset(&st, 0, sizeof(st));
         st.st_ino = de->d_ino;
         st.st_mode = de->d_type << 12;
-        if (filler(buf, de->d_name, &st, de->d_off))
+        if (filler(buf, de->d_name, &st, telldir(dp)))
             break;
     }
 
@@ -116,8 +116,11 @@ static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
 {
     int res;
 
-    res = mknod(path, mode, rdev);
-    if(res == -1)
+    if (S_ISFIFO(mode))
+        res = mkfifo(path, mode);
+    else
+        res = mknod(path, mode, rdev);
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -128,7 +131,7 @@ static int xmp_mkdir(const char *path, mode_t mode)
     int res;
 
     res = mkdir(path, mode);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -139,7 +142,7 @@ static int xmp_unlink(const char *path)
     int res;
 
     res = unlink(path);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -150,7 +153,7 @@ static int xmp_rmdir(const char *path)
     int res;
 
     res = rmdir(path);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -161,7 +164,7 @@ static int xmp_symlink(const char *from, const char *to)
     int res;
 
     res = symlink(from, to);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -172,7 +175,7 @@ static int xmp_rename(const char *from, const char *to)
     int res;
 
     res = rename(from, to);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -183,7 +186,7 @@ static int xmp_link(const char *from, const char *to)
     int res;
 
     res = link(from, to);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -194,7 +197,7 @@ static int xmp_chmod(const char *path, mode_t mode)
     int res;
 
     res = chmod(path, mode);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -205,7 +208,7 @@ static int xmp_chown(const char *path, uid_t uid, gid_t gid)
     int res;
 
     res = lchown(path, uid, gid);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -216,7 +219,7 @@ static int xmp_truncate(const char *path, off_t size)
     int res;
 
     res = truncate(path, size);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -230,7 +233,7 @@ static int xmp_ftruncate(const char *path, off_t size,
     (void) path;
 
     res = ftruncate(fi->fh, size);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -241,7 +244,7 @@ static int xmp_utime(const char *path, struct utimbuf *buf)
     int res;
 
     res = utime(path, buf);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -252,7 +255,7 @@ static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
     int fd;
 
     fd = open(path, fi->flags, mode);
-    if(fd == -1)
+    if (fd == -1)
         return -errno;
 
     fi->fh = fd;
@@ -264,7 +267,7 @@ static int xmp_open(const char *path, struct fuse_file_info *fi)
     int fd;
 
     fd = open(path, fi->flags);
-    if(fd == -1)
+    if (fd == -1)
         return -errno;
 
     fi->fh = fd;
@@ -278,7 +281,7 @@ static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
 
     (void) path;
     res = pread(fi->fh, buf, size, offset);
-    if(res == -1)
+    if (res == -1)
         res = -errno;
 
     return res;
@@ -291,7 +294,7 @@ static int xmp_write(const char *path, const char *buf, size_t size,
 
     (void) path;
     res = pwrite(fi->fh, buf, size, offset);
-    if(res == -1)
+    if (res == -1)
         res = -errno;
 
     return res;
@@ -302,7 +305,7 @@ static int xmp_statfs(const char *path, struct statvfs *stbuf)
     int res;
 
     res = statvfs(path, stbuf);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -322,11 +325,15 @@ static int xmp_fsync(const char *path, int isdatasync,
     int res;
     (void) path;
 
+#ifndef HAVE_FDATASYNC
+    (void) isdatasync;
+#else
     if (isdatasync)
         res = fdatasync(fi->fh);
     else
+#endif
         res = fsync(fi->fh);
-    if(res == -1)
+    if (res == -1)
         return -errno;
 
     return 0;
@@ -338,7 +345,7 @@ static int xmp_setxattr(const char *path, const char *name, const char *value,
                         size_t size, int flags)
 {
     int res = lsetxattr(path, name, value, size, flags);
-    if(res == -1)
+    if (res == -1)
         return -errno;
     return 0;
 }
@@ -347,7 +354,7 @@ static int xmp_getxattr(const char *path, const char *name, char *value,
                     size_t size)
 {
     int res = lgetxattr(path, name, value, size);
-    if(res == -1)
+    if (res == -1)
         return -errno;
     return res;
 }
@@ -355,7 +362,7 @@ static int xmp_getxattr(const char *path, const char *name, char *value,
 static int xmp_listxattr(const char *path, char *list, size_t size)
 {
     int res = llistxattr(path, list, size);
-    if(res == -1)
+    if (res == -1)
         return -errno;
     return res;
 }
@@ -363,7 +370,7 @@ static int xmp_listxattr(const char *path, char *list, size_t size)
 static int xmp_removexattr(const char *path, const char *name)
 {
     int res = lremovexattr(path, name);
-    if(res == -1)
+    if (res == -1)
         return -errno;
     return 0;
 }
index 48b60fca6e6ec77d19bf93b4b8a6ce76731f94c7..492c5cc90a8852320ea2f6d6039850edca87df09 100644 (file)
 
 /* This file defines the kernel interface of FUSE */
 
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#define __u64 uint64_t
+#define __u32 uint32_t
+#define __s32 int32_t
+#else
 #include <asm/types.h>
+#endif
 
 /** Version number of this interface */
 #define FUSE_KERNEL_VERSION 7
index 8d340f9992367966bc7d22c1626c809998eb7adf..0bd952e228b9ba8c1723c94a72ee8d21ad2c947d 100644 (file)
@@ -2,6 +2,12 @@
 
 lib_LTLIBRARIES = libfuse.la
 
+if BSD
+mount_source = mount_bsd.c
+else
+mount_source = mount.c
+endif
+
 libfuse_la_SOURCES =           \
        fuse.c                  \
        fuse_i.h                \
@@ -12,7 +18,7 @@ libfuse_la_SOURCES =          \
        fuse_mt.c               \
        fuse_session.c          \
        helper.c                \
-       mount.c
+       $(mount_source)
 
 libfuse_la_LDFLAGS = -lpthread -version-number 2:5:0 \
        -Wl,--version-script,fuse_versionscript
index 5c5eb0ac69328191778967d24fef2e83d882eda7..8966fabed2015439c9bdd790febda41ca75f0918 100644 (file)
@@ -18,6 +18,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <errno.h>
 #include <assert.h>
@@ -804,7 +805,18 @@ static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
             fflush(stdout);
         }
         err = -ENOSYS;
-        if (f->op.mknod && f->op.getattr) {
+        if (S_ISREG(mode) && f->op.create && f->op.getattr) {
+            struct fuse_file_info fi;
+
+            memset(&fi, 0, sizeof(fi));
+            fi.flags = O_CREAT | O_EXCL | O_WRONLY;
+            err = f->op.create(path, mode, &fi);
+            if (!err) {
+                err = lookup_path(f, parent, name, path, &e, &fi);
+                if (f->op.release)
+                    f->op.release(path, &fi);
+            }
+        } else if (f->op.mknod && f->op.getattr) {
             err = f->op.mknod(path, mode, rdev);
             if (!err)
                 err = lookup_path(f, parent, name, path, &e, NULL);
@@ -1937,6 +1949,13 @@ static int parse_lib_opts(struct fuse *f, const char *opts, char **llopts)
         else
             free(xopts);
     }
+#ifdef __FreeBSD__
+    /*
+     * In FreeBSD, we always use these settings as inode numbers are needed to
+     * make getcwd(3) work.
+     */
+    f->flags |= FUSE_READDIR_INO;
+#endif
     return 0;
 }
 
index f2ac1216af131c75b2c5aad55d20459a3c5b4a9a..31c2789ef26a638d9bc04af6f5de1f2bce7e30b6 100644 (file)
@@ -787,7 +787,7 @@ static void fuse_ll_process(void *data, const char *buf, size_t len,
     req->ch = ch;
 
     if (!f->got_init && in->opcode != FUSE_INIT)
-        fuse_reply_err(req, EPROTO);
+        fuse_reply_err(req, EIO);
     else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
              in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
              in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
index d8a522fb6349d223e499c0159580211fbe3a68bd..79616dc245b661e5001e4e19c111a9e129e42a43 100644 (file)
@@ -381,8 +381,8 @@ void fuse_teardown(struct fuse *fuse, int fd, char *mountpoint)
     else
         fuse_instance = NULL;
 
-    fuse_destroy(fuse);
     fuse_unmount(mountpoint);
+    fuse_destroy(fuse);
     free(mountpoint);
 }
 
diff --git a/lib/mount_bsd.c b/lib/mount_bsd.c
new file mode 100644 (file)
index 0000000..0111b14
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2005 Csaba Henk <csaba.henk@creo.hu>
+
+    This program can be distributed under the terms of the GNU LGPL.
+    See the file COPYING.LIB.
+*/
+
+#include "fuse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/wait.h>
+
+#define FUSERMOUNT_PROG         "mount_fusefs"
+
+void fuse_unmount(const char *mountpoint)
+{
+    char dev[128];
+    char *ssc, *umount_cmd;
+    FILE *sf;
+    int rv;
+    char *seekscript =
+    "/usr/bin/fstat  /dev/fuse* |\n"
+    "/usr/bin/awk '{if ($3 == %d) print $10}' |\n"
+    "/usr/bin/sort |\n"
+    "/usr/bin/uniq |\n"
+    "/usr/bin/awk '{ i+=1; if(i > 1){ exit (1); }; printf; }; END{if (i==0) exit (1)}'";
+
+    asprintf(&ssc, seekscript, getpid());
+
+    errno = 0;
+    sf = popen(ssc, "r");
+    if (! sf)
+        return;
+
+    fgets(dev, sizeof(dev), sf);
+    rv = pclose(sf);
+    if (rv)
+        return;
+
+    asprintf(&umount_cmd, "/sbin/umount %s", dev);
+    system(umount_cmd);
+}
+
+int fuse_mount(const char *mountpoint, const char *opts)
+{
+    const char *mountprog = FUSERMOUNT_PROG;
+    int fd;
+    char *fdnam, *dev;
+    int pid;
+
+    fdnam = getenv("FUSE_DEV_FD");
+
+    if (fdnam) {
+        char *ep;
+
+        fd = strtol(fdnam, &ep, 10);
+
+        if (*ep != '\0') {
+            fprintf(stderr, "invalid value given in FUSE_DEV_FD");
+            return -1;
+        }
+
+        if (fd < 0)
+            return -1;
+
+        goto mount;
+    }
+
+    dev = getenv("FUSE_DEV_NAME");
+
+    if (! dev)
+       dev = "/dev/fuse";
+
+    if ((fd = open(dev, O_RDWR)) < 0) {
+        perror("fuse: failed to open fuse device");
+        return -1;
+    }
+
+mount:
+    if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
+        goto out;
+
+    pid = fork();
+
+    if (pid == -1) {
+        perror("fuse: fork() failed");
+        close(fd);
+        return -1;
+    }
+
+    if (pid == 0) {
+        pid = fork();
+
+        if (pid == -1) {
+            perror("fuse: fork() failed");
+            close(fd);
+            exit(1);
+        }
+
+        if (pid == 0) {
+            const char *argv[32];
+            int a = 0;
+
+            if (! fdnam)
+                asprintf(&fdnam, "%d", fd);
+
+            argv[a++] = mountprog;
+            if (opts) {
+                argv[a++] = "-o";
+                argv[a++] = opts;
+            }
+            argv[a++] = fdnam;
+            argv[a++] = mountpoint;
+            argv[a++] = NULL;
+            setenv("MOUNT_FUSEFS_SAFE", "1", 1);
+            execvp(mountprog, (char **) argv);
+            perror("fuse: failed to exec mount program");
+            exit(1);
+        }
+
+        exit(0);
+    }
+
+    waitpid(pid, NULL, 0);
+
+out:
+    return fd;
+}