Reroutemount library for transparently mounting fuse partitions.
[vsys-wrappers.git] / fuse / reroutemount.c
1 #include <assert.h>
2 #include <errno.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7 #include "stolen_from_fuse.h"
8
9 char *socket_name = "/vsys/fd_fusemount.control";
10 unsigned int arg_length = 128;
11
12 void send_argument(int control_channel_fd, char *source) {
13     int sent;
14     sent=send(control_channel_fd, source, arg_length, 0);
15     if (sent<arg_length) {
16         printf("Error receiving arguments over the control buffer\n");
17         exit(1);
18     }
19 }
20 int connect_socket() {
21   int fd = socket( AF_UNIX, SOCK_STREAM, 0 );
22   struct sockaddr_un addr;
23   addr.sun_family = AF_UNIX;
24   strcpy( addr.sun_path, socket_name );
25   int len = strlen(socket_name) + sizeof(addr.sun_family);
26   assert( connect( fd, (struct sockaddr *) &addr, len ) == 0 );
27   return fd;
28 }
29
30 void do_umount( char *const argv[], int n, int fd ) {
31
32   // write the length
33   char buf[1024];
34   sprintf( buf, "%08x\n", n );
35   write( fd, buf, strlen(buf) );
36
37   // now write each arg
38   int i;
39   for( i = 0; i < n; i++ ) {
40     assert( strlen(argv[i]) < 1024 );
41     sprintf( buf, "%s\n", argv[i] );
42     write( fd, buf, strlen(buf) );
43   }
44
45   char inbuf[10];
46   int n2 = read( fd, inbuf, 10 );
47   inbuf[n2] = '\0';
48
49   int r = atoi(inbuf);
50
51 }
52
53 int umount2( const char *mnt, int flags ) {
54  
55   int fd = connect_socket();
56
57   const char *argv[3];
58   argv[0] = "fusermount";
59   argv[1] = "-u";
60   argv[2] = mnt;
61
62   do_umount( (char **const) argv, 3, fd );
63
64   close(fd);
65  
66 }
67
68 int get_magic_fd (char *data) {
69     char *ptr;
70     int fd;
71
72     data[arg_length-1]='\0';
73     ptr = strstr(data,"fd=");
74     if (!ptr)
75         return -1;
76
77     // Found two fd= expressions
78     if (strstr(ptr+3,"fd="))
79         return -1;
80
81     if (*(ptr+3)!='\0') {
82         sscanf(ptr+3,"%d",&fd);
83         return fd;
84     }
85     else
86         return -1;
87 }
88 int mount(const char *source, const char *target, const char *filesystemtype,
89         unsigned long mountflags, const void *data) {
90   int fd = connect_socket();
91   int old_fuse_fd, new_fuse_fd;
92
93   char buf[1024];
94
95   send_argument(fd, source);
96   send_argument(fd, target );
97   send_argument(fd, filesystemtype );
98   send_argument(fd, data );
99
100   old_fuse_fd = get_magic_fd (data);
101
102   send_fd(fd, old_fuse_fd);
103
104   if (fuse_fd == -1) {
105       printf ("Reroutemount: Could not identify FUSE fd: %d\n", fuse_fd);
106       exit(1);
107   }
108
109   new_fuse_fd=receive_fd(fd);
110
111   if (new_fuse_fd == -1) {
112       printf ("Reroutemount: Fusemount returned bad fd: %d\n", fuse_fd);
113       exit(1);
114   }
115
116   if( dup2(new_fuse_fd, old_fuse_fd ) != new_fuse_fd ) {
117       printf ("Could not duplicate returned file descriptor\n");
118       exit(1);
119   }
120
121   close(fd);
122   return 0;
123
124 }
125
126 int execv( const char *path, char *const argv[] ) {
127
128   if( strstr( path, "fusermount" ) == NULL ) {
129     return execv( path, argv );
130   }
131
132   // also make sure this is an unmount . . .
133   int n = 0;
134   char *arg = argv[n];
135   int found_u = 0;
136   while( arg != NULL ) {
137     if( strcmp( arg, "-u" ) == 0 ) {
138       found_u = 1;
139       break;
140     }
141     arg = argv[++n];
142   }
143
144   if( !found_u ) {
145     return execv( path, argv );
146   }
147
148   // Have root do any fusermounts we need done
149   int fd = connect_socket();
150
151   do_umount( argv, n, fd );
152
153   exit(0);
154
155 }
156