1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
4
5 Architecture specific file system mounting (FreeBSD).
6
7 This program can be distributed under the terms of the GNU LGPLv2.
8 See the file COPYING.LIB.
9 */
10
11 #include "config.h"
12 #include "fuse_i.h"
13 #include "fuse_misc.h"
14 #include "fuse_opt.h"
15
16 #include <sys/param.h>
17 #include <sys/mount.h>
18
19 #include <sys/stat.h>
20 #include <sys/wait.h>
21 #include <sys/sysctl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <stddef.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <paths.h>
30 #include <limits.h>
31
32 #define FUSERMOUNT_PROG "mount_fusefs"
33 #define FUSE_DEV_TRUNK "/dev/fuse"
34
35 enum {
36 KEY_RO,
37 KEY_KERN
38 };
39
40 struct mount_opts {
41 int allow_other;
42 char *kernel_opts;
43 unsigned max_read;
44 };
45
46 #define FUSE_DUAL_OPT_KEY(templ, key) \
47 FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
48
49 static const struct fuse_opt fuse_mount_opts[] = {
50 { "allow_other", offsetof(struct mount_opts, allow_other), 1 },
51 { "max_read=%u", offsetof(struct mount_opts, max_read), 1 },
52 FUSE_OPT_KEY("-r", KEY_RO),
53 /* standard FreeBSD mount options */
54 FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
55 FUSE_DUAL_OPT_KEY("async", KEY_KERN),
56 FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
57 FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
58 FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
59 FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
60 FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
61 FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
62 FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
63 FUSE_DUAL_OPT_KEY("union", KEY_KERN),
64 FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
65 FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
66 FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
67 FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
68 FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
69 FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
70 FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
71 FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
72 FUSE_DUAL_OPT_KEY("force", KEY_KERN),
73 FUSE_DUAL_OPT_KEY("update", KEY_KERN),
74 FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
75 FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
76 FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
77 FUSE_DUAL_OPT_KEY("automounted", KEY_KERN),
78 /* options supported under both Linux and FBSD */
79 FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
80 FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
81 FUSE_OPT_KEY("max_read=", KEY_KERN),
82 FUSE_OPT_KEY("subtype=", KEY_KERN),
83 /* FBSD FUSE specific mount options */
84 FUSE_DUAL_OPT_KEY("private", KEY_KERN),
85 FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
86 FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
87 FUSE_OPT_KEY("nosync_unmount", KEY_KERN),
88 #if __FreeBSD_version >= 1200519
89 FUSE_DUAL_OPT_KEY("intr", KEY_KERN),
90 #endif
91 /* stock FBSD mountopt parsing routine lets anything be negated... */
92 /*
93 * Linux specific mount options, but let just the mount util
94 * handle them
95 */
96 FUSE_OPT_KEY("fsname=", KEY_KERN),
97 FUSE_OPT_END
98 };
99
fuse_mount_version(void)100 void fuse_mount_version(void)
101 {
102 system(FUSERMOUNT_PROG " --version");
103 }
104
get_max_read(struct mount_opts * o)105 unsigned get_max_read(struct mount_opts *o)
106 {
107 return o->max_read;
108 }
109
fuse_mount_opt_proc(void * data,const char * arg,int key,struct fuse_args * outargs)110 static int fuse_mount_opt_proc(void *data, const char *arg, int key,
111 struct fuse_args *outargs)
112 {
113 (void) outargs;
114 struct mount_opts *mo = data;
115
116 switch (key) {
117 case KEY_RO:
118 arg = "ro";
119 /* fall through */
120
121 case KEY_KERN:
122 return fuse_opt_add_opt(&mo->kernel_opts, arg);
123 }
124
125 /* Pass through unknown options */
126 return 1;
127 }
128
fuse_kern_unmount(const char * mountpoint,int fd)129 void fuse_kern_unmount(const char *mountpoint, int fd)
130 {
131 close(fd);
132 unmount(mountpoint, MNT_FORCE);
133 }
134
135 /* Check if kernel is doing init in background */
init_backgrounded(void)136 static int init_backgrounded(void)
137 {
138 unsigned ibg;
139 size_t len;
140
141 len = sizeof(ibg);
142
143 if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
144 return 0;
145
146 return ibg;
147 }
148
149
fuse_mount_core(const char * mountpoint,const char * opts)150 static int fuse_mount_core(const char *mountpoint, const char *opts)
151 {
152 const char *mountprog = FUSERMOUNT_PROG;
153 int fd;
154 char *fdnam, *dev;
155 pid_t pid, cpid;
156 int status;
157
158 fdnam = getenv("FUSE_DEV_FD");
159
160 if (fdnam) {
161 char *ep;
162
163 fd = strtol(fdnam, &ep, 10);
164
165 if (*ep != '\0') {
166 fuse_log(FUSE_LOG_ERR, "invalid value given in FUSE_DEV_FD\n");
167 return -1;
168 }
169
170 if (fd < 0)
171 return -1;
172
173 goto mount;
174 }
175
176 dev = getenv("FUSE_DEV_NAME");
177
178 if (! dev)
179 dev = (char *)FUSE_DEV_TRUNK;
180
181 if ((fd = open(dev, O_RDWR)) < 0) {
182 perror("fuse: failed to open fuse device");
183 return -1;
184 }
185
186 mount:
187 if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
188 goto out;
189
190 pid = fork();
191 cpid = pid;
192
193 if (pid == -1) {
194 perror("fuse: fork() failed");
195 close(fd);
196 return -1;
197 }
198
199 if (pid == 0) {
200 if (! init_backgrounded()) {
201 /*
202 * If init is not backgrounded, we have to
203 * call the mount util backgrounded, to avoid
204 * deadlock.
205 */
206
207 pid = fork();
208
209 if (pid == -1) {
210 perror("fuse: fork() failed");
211 close(fd);
212 exit(1);
213 }
214 }
215
216 if (pid == 0) {
217 const char *argv[32];
218 int a = 0;
219 int ret = -1;
220
221 if (! fdnam)
222 {
223 ret = asprintf(&fdnam, "%d", fd);
224 if(ret == -1)
225 {
226 perror("fuse: failed to assemble mount arguments");
227 close(fd);
228 exit(1);
229 }
230 }
231
232 argv[a++] = mountprog;
233 if (opts) {
234 argv[a++] = "-o";
235 argv[a++] = opts;
236 }
237 argv[a++] = fdnam;
238 argv[a++] = mountpoint;
239 argv[a++] = NULL;
240 execvp(mountprog, (char **) argv);
241 perror("fuse: failed to exec mount program");
242 free(fdnam);
243 exit(1);
244 }
245
246 exit(0);
247 }
248
249 if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
250 perror("fuse: failed to mount file system");
251 close(fd);
252 return -1;
253 }
254
255 out:
256 return fd;
257 }
258
parse_mount_opts(struct fuse_args * args)259 struct mount_opts *parse_mount_opts(struct fuse_args *args)
260 {
261 struct mount_opts *mo;
262
263 mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
264 if (mo == NULL)
265 return NULL;
266
267 memset(mo, 0, sizeof(struct mount_opts));
268
269 if (args &&
270 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
271 goto err_out;
272
273 return mo;
274
275 err_out:
276 destroy_mount_opts(mo);
277 return NULL;
278 }
279
destroy_mount_opts(struct mount_opts * mo)280 void destroy_mount_opts(struct mount_opts *mo)
281 {
282 free(mo->kernel_opts);
283 free(mo);
284 }
285
fuse_kern_mount(const char * mountpoint,struct mount_opts * mo)286 int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
287 {
288 /* mount util should not try to spawn the daemon */
289 setenv("MOUNT_FUSEFS_SAFE", "1", 1);
290 /* to notify the mount util it's called from lib */
291 setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
292
293 return fuse_mount_core(mountpoint, mo->kernel_opts);
294 }
295