From: Mark Glines Date: Thu, 18 Apr 2002 14:41:48 +0000 (+0000) Subject: fuse_mount_ioslave() and helper util X-Git-Tag: debian_version_1_0-1~45 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=65ba219885aefa096437c2bd92ad8394a5ecda75;p=qemu-gpiodev%2Flibfuse.git fuse_mount_ioslave() and helper util --- diff --git a/ChangeLog b/ChangeLog index 99ea4a2..bb22b5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2002-04-18 Mark Glines + + * 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 * use struct fuse_statfs everywhere possible to avoid problems diff --git a/include/fuse.h b/include/fuse.h index b75978c..ea28d0d 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -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... * * ----------------------------------------------------------- */ diff --git a/lib/helper.c b/lib/helper.c index 556a1c1..c7c48ae 100644 --- a/lib/helper.c +++ b/lib/helper.c @@ -15,6 +15,10 @@ #include #include #include +#include +#include +#include +#include #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() { diff --git a/util/.cvsignore b/util/.cvsignore index 5f7d28d..ab2dc89 100644 --- a/util/.cvsignore +++ b/util/.cvsignore @@ -2,3 +2,4 @@ Makefile.in Makefile .deps fusermount +fuse_ioslave diff --git a/util/Makefile.am b/util/Makefile.am index 48f9957..0e4434f 100644 --- a/util/Makefile.am +++ b/util/Makefile.am @@ -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 index 0000000..1fa3bbf --- /dev/null +++ b/util/fuse_ioslave.c @@ -0,0 +1,57 @@ +#include /* fprintf */ +#include /* errno */ +#include /* strerror */ +#include /* read,write,close */ +#include /* getenv,strtol */ +#include /* select */ +#include /* send, recv */ +#include /* 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; +}