1 |
dpavlin |
4 |
/* |
2 |
|
|
FUSE: Filesystem in Userspace |
3 |
|
|
Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu> |
4 |
|
|
|
5 |
|
|
This program can be distributed under the terms of the GNU LGPL. |
6 |
|
|
See the file COPYING.LIB. |
7 |
|
|
*/ |
8 |
|
|
|
9 |
|
|
#include "fuse.h" |
10 |
|
|
|
11 |
|
|
#include <stdio.h> |
12 |
|
|
#include <stdlib.h> |
13 |
|
|
#include <unistd.h> |
14 |
|
|
#include <fcntl.h> |
15 |
|
|
#include <errno.h> |
16 |
|
|
#include <sys/socket.h> |
17 |
|
|
#include <sys/un.h> |
18 |
|
|
#include <sys/wait.h> |
19 |
|
|
|
20 |
|
|
#define FUSERMOUNT_PROG "fusermount" |
21 |
|
|
#define FUSE_COMMFD_ENV "_FUSE_COMMFD" |
22 |
|
|
|
23 |
|
|
|
24 |
|
|
/* return value: |
25 |
|
|
* >= 0 => fd |
26 |
|
|
* -1 => error |
27 |
|
|
*/ |
28 |
|
|
static int receive_fd(int fd) |
29 |
|
|
{ |
30 |
|
|
struct msghdr msg; |
31 |
|
|
struct iovec iov; |
32 |
|
|
char buf[1]; |
33 |
|
|
int rv; |
34 |
|
|
int connfd = -1; |
35 |
|
|
char ccmsg[CMSG_SPACE(sizeof(connfd))]; |
36 |
|
|
struct cmsghdr *cmsg; |
37 |
|
|
|
38 |
|
|
iov.iov_base = buf; |
39 |
|
|
iov.iov_len = 1; |
40 |
|
|
|
41 |
|
|
msg.msg_name = 0; |
42 |
|
|
msg.msg_namelen = 0; |
43 |
|
|
msg.msg_iov = &iov; |
44 |
|
|
msg.msg_iovlen = 1; |
45 |
|
|
/* old BSD implementations should use msg_accrights instead of |
46 |
|
|
* msg_control; the interface is different. */ |
47 |
|
|
msg.msg_control = ccmsg; |
48 |
|
|
msg.msg_controllen = sizeof(ccmsg); |
49 |
|
|
|
50 |
|
|
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); |
51 |
|
|
if (rv == -1) { |
52 |
|
|
perror("recvmsg"); |
53 |
|
|
return -1; |
54 |
|
|
} |
55 |
|
|
if(!rv) { |
56 |
|
|
/* EOF */ |
57 |
|
|
return -1; |
58 |
|
|
} |
59 |
|
|
|
60 |
|
|
cmsg = CMSG_FIRSTHDR(&msg); |
61 |
|
|
if (!cmsg->cmsg_type == SCM_RIGHTS) { |
62 |
|
|
fprintf(stderr, "got control message of unknown type %d\n", |
63 |
|
|
cmsg->cmsg_type); |
64 |
|
|
return -1; |
65 |
|
|
} |
66 |
|
|
return *(int*)CMSG_DATA(cmsg); |
67 |
|
|
} |
68 |
|
|
|
69 |
|
|
void fuse_unmount(const char *mountpoint) |
70 |
|
|
{ |
71 |
|
|
const char *mountprog = FUSERMOUNT_PROG; |
72 |
|
|
char umount_cmd[1024]; |
73 |
|
|
|
74 |
|
|
snprintf(umount_cmd, sizeof(umount_cmd) - 1, "%s -u -q -z %s", mountprog, |
75 |
|
|
mountpoint); |
76 |
|
|
|
77 |
|
|
umount_cmd[sizeof(umount_cmd) - 1] = '\0'; |
78 |
|
|
system(umount_cmd); |
79 |
|
|
} |
80 |
|
|
|
81 |
|
|
int fuse_mount(const char *mountpoint, const char *opts) |
82 |
|
|
{ |
83 |
|
|
const char *mountprog = FUSERMOUNT_PROG; |
84 |
|
|
int fds[2], pid; |
85 |
|
|
int res; |
86 |
|
|
int rv; |
87 |
|
|
|
88 |
|
|
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); |
89 |
|
|
if(res == -1) { |
90 |
|
|
perror("fuse: socketpair() failed"); |
91 |
|
|
return -1; |
92 |
|
|
} |
93 |
|
|
|
94 |
|
|
pid = fork(); |
95 |
|
|
if(pid == -1) { |
96 |
|
|
perror("fuse: fork() failed"); |
97 |
|
|
close(fds[0]); |
98 |
|
|
close(fds[1]); |
99 |
|
|
return -1; |
100 |
|
|
} |
101 |
|
|
|
102 |
|
|
if(pid == 0) { |
103 |
|
|
char env[10]; |
104 |
|
|
const char *argv[] = {mountprog, opts ? "-o" : mountpoint, opts, |
105 |
|
|
mountpoint, NULL}; |
106 |
|
|
|
107 |
|
|
close(fds[1]); |
108 |
|
|
fcntl(fds[0], F_SETFD, 0); |
109 |
|
|
snprintf(env, sizeof(env), "%i", fds[0]); |
110 |
|
|
setenv(FUSE_COMMFD_ENV, env, 1); |
111 |
|
|
execvp(mountprog, (char **) argv); |
112 |
|
|
perror("fuse: failed to exec fusermount"); |
113 |
|
|
exit(1); |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
close(fds[0]); |
117 |
|
|
rv = receive_fd(fds[1]); |
118 |
|
|
close(fds[1]); |
119 |
|
|
waitpid(pid, NULL, 0); /* bury zombie */ |
120 |
|
|
|
121 |
|
|
return rv; |
122 |
|
|
} |