a slice.
--- /dev/null
+all: reroutemount.c reroutemount_server.c stolen_from_fuse.c
+ gcc -g -c stolen_from_fuse.c -o stolen_from_fuse.o
+ gcc -g stolen_from_fuse.o reroutemount_server.c -o reroutemount_server
+ gcc -g -shared stolen_from_fuse.o reroutemount.c -o reroutemount.so
--- /dev/null
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "stolen_from_fuse.h"
+
+char *socket_name = "/vsys/local_fusemount.control";
+
+int rrm_connect_socket() {
+ int fd = socket( AF_UNIX, SOCK_STREAM, 0 );
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ strcpy( addr.sun_path, socket_name );
+ int len = strlen(socket_name) + sizeof(addr.sun_family);
+ assert( connect( fd, (struct sockaddr *) &addr, len ) == 0 );
+ return fd;
+}
+
+void rrm_do_umount( char *const argv[], int n, int fd ) {
+
+ // write the length
+ char buf[1024];
+ sprintf( buf, "%08x\n", n );
+ write( fd, buf, strlen(buf) );
+
+ // now write each arg
+ int i;
+ for( i = 0; i < n; i++ ) {
+ assert( strlen(argv[i]) < 1024 );
+ sprintf( buf, "%s\n", argv[i] );
+ write( fd, buf, strlen(buf) );
+ }
+
+ char inbuf[10];
+ int n2 = read( fd, inbuf, 10 );
+ inbuf[n2] = '\0';
+
+ int r = atoi(inbuf);
+
+}
+
+int umount2( const char *mnt, int flags ) {
+
+ int fd = rrm_connect_socket();
+
+ const char *argv[3];
+ argv[0] = "fusermount";
+ argv[1] = "-u";
+ argv[2] = mnt;
+
+ rrm_do_umount( (char **const) argv, 3, fd );
+
+ close(fd);
+
+}
+
+int mount(const char *source, const char *target, const char *filesystemtype,
+ unsigned long mountflags, const void *data) {
+
+ int fd = rrm_connect_socket();
+
+ char buf[1024];
+ sprintf( buf, "%08x\n", 0 );
+ write( fd, buf, strlen(buf) );
+
+ sprintf( buf, "%s\n%s\n%s\n%ld\n%s\n", source, target, filesystemtype,
+ mountflags, data );
+ write( fd, buf, strlen(buf) );
+
+ char inbuf[10];
+ int n = read( fd, inbuf, 9 );
+ inbuf[n] = '\0';
+
+ int r;
+ assert( sscanf( inbuf, "%08x\n", &r ) == 1);
+
+ int fuse_fd = 0;
+ if( r < 0 ) {
+ errno = r;
+ return -1;
+ } else if( r > 0 ) {
+ // get the fd
+ fuse_fd = rrm_receive_fd(fd);
+
+ // what was the old fd?
+ int old_fd;
+ char extra[1024];
+ int s = sscanf( data, "fd=%d,%s", &old_fd, extra );
+ assert( dup2( fuse_fd, old_fd ) == old_fd );
+
+ }
+
+ close(fd);
+ return 0;
+
+}
+
+int execv( const char *path, char *const argv[] ) {
+
+ if( strstr( path, "fusermount" ) == NULL ) {
+ return execv( path, argv );
+ }
+
+ // also make sure this is an unmount . . .
+ int n = 0;
+ char *arg = argv[n];
+ int found_u = 0;
+ while( arg != NULL ) {
+ if( strcmp( arg, "-u" ) == 0 ) {
+ found_u = 1;
+ break;
+ }
+ arg = argv[++n];
+ }
+
+ if( !found_u ) {
+ return execv( path, argv );
+ }
+
+ // Have root do any fusermounts we need done
+ int fd = rrm_connect_socket();
+
+ rrm_do_umount( argv, n, fd );
+
+ exit(0);
+
+}
+
--- /dev/null
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "stolen_from_fuse.h"
+
+// Most of this code is stolen from FUSE 2.7.4
+
+/** Function to pass a file descriptor over a UNIX socket.
+ *
+ * Sends the file descriptor fd over the channel sock_fd.
+ *
+ ***/
+int rrm_send_fd(int sock_fd, int fd)
+{
+ int retval;
+ struct msghdr msg;
+ struct cmsghdr *p_cmsg;
+ struct iovec vec;
+ size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
+ 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(fd));
+ p_fds = (int *) CMSG_DATA(p_cmsg);
+ *p_fds = 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);
+ while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
+ if (retval != 1) {
+ perror("sending file descriptor");
+ return -1;
+ }
+ return 0;
+}
+
+
+/* return value:
+ * >= 0 => fd
+ * -1 => error
+ */
+int rrm_receive_fd(int fd)
+{
+ struct msghdr msg;
+ struct iovec iov;
+ char buf[1];
+ int rv;
+ size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
+ 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);
+
+ while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
+ if (rv == -1) {
+ perror("recvmsg");
+ return -1;
+ }
+ if(!rv) {
+ /* EOF */
+ 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 rrm_fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
+{
+ int res;
+ int status;
+
+ res = umount2(mnt, lazy ? 2 : 0);
+ if (res == -1)
+ fprintf(stderr, "%s: failed to unmount %s: %s\n",
+ progname, mnt, strerror(errno));
+ return res;
+
+}
+
+static int rrm_try_open(const char *dev, char **devp, int silent)
+{
+ int fd = open(dev, O_RDWR);
+ if (fd != -1) {
+ *devp = strdup(dev);
+ if (*devp == NULL) {
+ fprintf(stderr, "failed to allocate memory\n" );
+
+ close(fd);
+ fd = -1;
+ }
+ } else if (errno == ENODEV ||
+ errno == ENOENT)/* check for ENOENT too, for the udev case */
+ return -2;
+ else if (!silent) {
+ fprintf(stderr, "failed to open %s: %s\n", dev,
+ strerror(errno));
+ }
+ return fd;
+}
+
+static int rrm_try_open_fuse_device(char **devp)
+{
+ int fd;
+ int err;
+
+ //drop_privs();
+ fd = rrm_try_open(FUSE_DEV_NEW, devp, 0);
+ //restore_privs();
+ if (fd >= 0)
+ return fd;
+
+ err = fd;
+ fd = rrm_try_open(FUSE_DEV_OLD, devp, 1);
+ if (fd >= 0)
+ return fd;
+
+ return err;
+}
+
+int rrm_open_fuse_device(char **devp)
+{
+ int fd = rrm_try_open_fuse_device(devp);
+ if (fd >= -1)
+ return fd;
+
+ fprintf(stderr,
+ "fuse device not found, try 'modprobe fuse' first\n");
+
+ return -1;
+}
--- /dev/null
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include "stolen_from_fuse.h"
+
+// Most of this code is stolen from FUSE 2.7.4
+
+int rrm_send_fd(int sock_fd, int fd)
+{
+ int retval;
+ struct msghdr msg;
+ struct cmsghdr *p_cmsg;
+ struct iovec vec;
+ size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
+ 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(fd));
+ p_fds = (int *) CMSG_DATA(p_cmsg);
+ *p_fds = 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);
+ while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
+ if (retval != 1) {
+ perror("sending file descriptor");
+ return -1;
+ }
+ return 0;
+}
+
+
+/* return value:
+ * >= 0 => fd
+ * -1 => error
+ */
+int rrm_receive_fd(int fd)
+{
+ struct msghdr msg;
+ struct iovec iov;
+ char buf[1];
+ int rv;
+ size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
+ 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);
+
+ while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
+ if (rv == -1) {
+ perror("recvmsg");
+ return -1;
+ }
+ if(!rv) {
+ /* EOF */
+ 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 rrm_fuse_mnt_umount(const char *progname, const char *mnt, int lazy)
+{
+ int res;
+ int status;
+
+ res = umount2(mnt, lazy ? 2 : 0);
+ if (res == -1)
+ fprintf(stderr, "%s: failed to unmount %s: %s\n",
+ progname, mnt, strerror(errno));
+ return res;
+
+}
+
+static int rrm_try_open(const char *dev, char **devp, int silent)
+{
+ int fd = open(dev, O_RDWR);
+ if (fd != -1) {
+ *devp = strdup(dev);
+ if (*devp == NULL) {
+ fprintf(stderr, "failed to allocate memory\n" );
+
+ close(fd);
+ fd = -1;
+ }
+ } else if (errno == ENODEV ||
+ errno == ENOENT)/* check for ENOENT too, for the udev case */
+ return -2;
+ else if (!silent) {
+ fprintf(stderr, "failed to open %s: %s\n", dev,
+ strerror(errno));
+ }
+ return fd;
+}
+
+static int rrm_try_open_fuse_device(char **devp)
+{
+ int fd;
+ int err;
+
+ //drop_privs();
+ fd = rrm_try_open(FUSE_DEV_NEW, devp, 0);
+ //restore_privs();
+ if (fd >= 0)
+ return fd;
+
+ err = fd;
+ fd = rrm_try_open(FUSE_DEV_OLD, devp, 1);
+ if (fd >= 0)
+ return fd;
+
+ return err;
+}
+
+int rrm_open_fuse_device(char **devp)
+{
+ int fd = rrm_try_open_fuse_device(devp);
+ if (fd >= -1)
+ return fd;
+
+ fprintf(stderr,
+ "fuse device not found, try 'modprobe fuse' first\n");
+
+ return -1;
+}