libfuse

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