fuse_mount_ioslave() and helper util
authorMark Glines <mark@glines.org>
Thu, 18 Apr 2002 14:41:48 +0000 (14:41 +0000)
committerMark Glines <mark@glines.org>
Thu, 18 Apr 2002 14:41:48 +0000 (14:41 +0000)
ChangeLog
include/fuse.h
lib/helper.c
util/.cvsignore
util/Makefile.am
util/fuse_ioslave.c [new file with mode: 0644]

index 99ea4a22c965706c52d1d09697fd51d56880cc3e..bb22b5d312e5a1334195df44e9309a27456b0f78 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2002-04-18  Mark Glines <mark@glines.org>
+
+       * added an alternative to fuse_mount(), called
+      fuse_mount_ioslave(), which does not need to reexec the
+      FUSE program.
+       * added a small helper util needed by fuse_mount_ioslave().
+
 2002-03-16  Mark Glines <mark@glines.org>
 
        * use struct fuse_statfs everywhere possible to avoid problems
index b75978c623d893e035f56a068df61230cfaf88c7..ea28d0d5d8a989dd9cc2450e80b59ae14a691f51 100644 (file)
@@ -180,6 +180,17 @@ struct fuse_context *fuse_get_context(struct fuse *f);
  */
 void fuse_main(int argc, char *argv[], const struct fuse_operations *op);
 
+/*
+ * Spawn an I/O slave, creating an fd suitable for passing to fuse_new()
+ *
+ * This spawns fusermount, and then a small message tosser process to
+ * allow access to fuse_new() and fuse_loop() without the limitations
+ * of reexecuting the main FUSE process and destroying stdin.
+ *
+ * @param mountpoint a char pointer to the requested mountpoint
+ */
+int fuse_mount_ioslave(char *mountpoint);
+
 /* ----------------------------------------------------------- *
  * Advanced API for event handling, don't worry about this...  *
  * ----------------------------------------------------------- */
index 556a1c1f3a19672485543427cd7914ab2572f7e4..c7c48ae29ee5d48d91e065b9e4a5944081a2396c 100644 (file)
 #include <limits.h>
 #include <signal.h>
 #include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#include <sys/wait.h>
 
 #define FUSE_MOUNTED_ENV     "_FUSE_MOUNTED"
 #define FUSE_UMOUNT_CMD_ENV  "_FUSE_UNMOUNT_CMD"
@@ -71,6 +75,73 @@ static int fuse_mount(int *argcp, char **argv)
     return 0;
 }
 
+int receive_fd(int fd) {
+    struct msghdr msg;
+    struct iovec iov;
+    char buf[1];
+    int rv;
+    int connfd = -1;
+    char ccmsg[CMSG_SPACE(sizeof(connfd))];
+    struct cmsghdr *cmsg;
+
+    iov.iov_base = buf;
+    iov.iov_len = 1;
+
+    msg.msg_name = 0;
+    msg.msg_namelen = 0;
+    msg.msg_iov = &iov;
+    msg.msg_iovlen = 1;
+    /* old BSD implementations should use msg_accrights instead of
+     * msg_control; the interface is different. */
+    msg.msg_control = ccmsg;
+    msg.msg_controllen = sizeof(ccmsg);
+
+    rv = recvmsg(fd, &msg, 0);
+    if (rv == -1) {
+        perror("recvmsg");
+        return -1;
+    }
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    if (!cmsg->cmsg_type == SCM_RIGHTS) {
+        fprintf(stderr, "got control message of unknown type %d\n",
+                cmsg->cmsg_type);
+        return -1;
+    }
+    return *(int*)CMSG_DATA(cmsg);
+}
+
+int fuse_mount_ioslave(char *mountpoint) {
+    int fds[2], pid;
+    char env[10];
+    if(socketpair(PF_UNIX,SOCK_DGRAM,0,fds)) {
+        fprintf(stderr,"fuse: failed to socketpair()\n");
+        return -1;
+    }
+    pid = fork();
+    if(pid < 0) {
+        fprintf(stderr,"fuse: failed to fork()\n");
+        close(fds[0]);
+        close(fds[1]);
+        return -1;
+    }
+    if(pid) {
+        int rv, fd = fds[1];
+        close(fds[0]);
+        while((rv = receive_fd(fd)) < 0)
+               sleep(1);
+        close(fd);
+        while(wait(NULL) != pid); /* bury zombie */
+        return rv;
+    }
+    close(fds[1]);
+    fcntl(fds[0],F_SETFD,0);
+    snprintf(env,sizeof(env),"%i",fds[0]);
+    setenv("_FUSE_IOSLAVE_FD",env,1);
+    execlp("fusermount","fusermount",mountpoint,"fuse_ioslave",NULL);
+    fprintf(stderr,"fuse: failed to exec fusermount\n");
+    exit(1);
+}
 
 static void exit_handler()
 {
index 5f7d28d1e4abe5c95554f7b74850cba77f726c8f..ab2dc89f79f414b008691695b1a1f29c1d039bf0 100644 (file)
@@ -2,3 +2,4 @@ Makefile.in
 Makefile
 .deps
 fusermount
+fuse_ioslave
index 48f99576eec4187ee3dc203ca459cf55125d80fd..0e4434f2d7bf58c3775043c3cf6bbd473a28dcb2 100644 (file)
@@ -1,8 +1,9 @@
 ## Process this file with automake to produce Makefile.in
 
-bin_PROGRAMS = fusermount
+bin_PROGRAMS = fusermount fuse_ioslave
 
 fusermount_SOURCES = fusermount.c
+fuse_ioslave_SOURCES = fuse_ioslave.c
 
 install-exec-hook:
        -chown root $(DESTDIR)$(bindir)/fusermount
diff --git a/util/fuse_ioslave.c b/util/fuse_ioslave.c
new file mode 100644 (file)
index 0000000..1fa3bbf
--- /dev/null
@@ -0,0 +1,57 @@
+#include <stdio.h>                /* fprintf */
+#include <errno.h>                /* errno */
+#include <string.h>                /* strerror */
+#include <unistd.h>                /* read,write,close */
+#include <stdlib.h>                /* getenv,strtol */
+#include <sys/select.h>            /* select */
+#include <sys/socket.h>            /* send, recv */
+#include <sys/un.h>                /* struct sockaddr_un */
+#define BUFSIZE (2<<16)
+#undef IOSLAVE_DEBUG
+char *scratch;
+
+int send_fd(int sock_fd, int send_fd) {
+    int retval;
+    struct msghdr msg;
+    struct cmsghdr *p_cmsg;
+    struct iovec vec;
+    char cmsgbuf[CMSG_SPACE(sizeof(send_fd))];
+    int *p_fds;
+    char sendchar = 0;
+    msg.msg_control = cmsgbuf;
+    msg.msg_controllen = sizeof(cmsgbuf);
+    p_cmsg = CMSG_FIRSTHDR(&msg);
+    p_cmsg->cmsg_level = SOL_SOCKET;
+    p_cmsg->cmsg_type = SCM_RIGHTS;
+    p_cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd));
+    p_fds = (int *) CMSG_DATA(p_cmsg);
+    *p_fds = send_fd;
+    msg.msg_controllen = p_cmsg->cmsg_len;
+    msg.msg_name = NULL;
+    msg.msg_namelen = 0;
+    msg.msg_iov = &vec;
+    msg.msg_iovlen = 1;
+    msg.msg_flags = 0;
+    /* "To pass file descriptors or credentials you need to send/read at
+     * least one byte" (man 7 unix)
+     */
+    vec.iov_base = &sendchar;
+    vec.iov_len = sizeof(sendchar);
+    retval = sendmsg(sock_fd, &msg, 0);
+    if (retval != 1) {
+        perror("sendmsg");
+    }
+    return retval;
+}
+
+int main() {
+    char *env = getenv("_FUSE_IOSLAVE_FD");
+    int fd;
+    if (!env)
+        exit(fprintf(stderr, "fuse_ioslave: do not run me directly\n"));
+    fd = strtol(env, NULL, 0);
+    while (send_fd(fd, 0) < 0) {
+        sleep(5);
+    }
+    return 0;
+}