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 "fuse_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 "fuse_mount_compat.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
36enum {
37 KEY_RO,
38 KEY_KERN
39};
40
41struct 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
50static 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#if __FreeBSD_version >= 1200519
90 FUSE_DUAL_OPT_KEY("intr", KEY_KERN),
91#endif
92 /* stock FBSD mountopt parsing routine lets anything be negated... */
93 /*
94 * Linux specific mount options, but let just the mount util
95 * handle them
96 */
97 FUSE_OPT_KEY("fsname=", KEY_KERN),
99};
100
101void fuse_mount_version(void)
102{
103 system(FUSERMOUNT_PROG " --version");
104}
105
106unsigned get_max_read(struct mount_opts *o)
107{
108 return o->max_read;
109}
110
111static int fuse_mount_opt_proc(void *data, const char *arg, int key,
112 struct fuse_args *outargs)
113{
114 (void) outargs;
115 struct mount_opts *mo = data;
116
117 switch (key) {
118 case KEY_RO:
119 arg = "ro";
120 /* fall through */
121
122 case KEY_KERN:
123 return fuse_opt_add_opt(&mo->kernel_opts, arg);
124 }
125
126 /* Pass through unknown options */
127 return 1;
128}
129
130void fuse_kern_unmount(const char *mountpoint, int fd)
131{
132 close(fd);
133 unmount(mountpoint, MNT_FORCE);
134}
135
136/* Check if kernel is doing init in background */
137static int init_backgrounded(void)
138{
139 unsigned ibg;
140 size_t len;
141
142 len = sizeof(ibg);
143
144 if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
145 return 0;
146
147 return ibg;
148}
149
150
151static int fuse_mount_core(const char *mountpoint, const char *opts)
152{
153 const char *mountprog = FUSERMOUNT_PROG;
154 int fd;
155 char *fdnam, *dev;
156 pid_t pid, cpid;
157 int status;
158 int err;
159
160 fdnam = getenv("FUSE_DEV_FD");
161
162 if (fdnam) {
163 err = libfuse_strtol(fdnam, &fd);
164 if (err) {
165 fuse_log(FUSE_LOG_ERR, "invalid value given in FUSE_DEV_FD\n");
166 return -1;
167 }
168
169 goto mount;
170 }
171
172 dev = getenv("FUSE_DEV_NAME");
173
174 if (! dev)
175 dev = (char *)FUSE_DEV_TRUNK;
176
177 if ((fd = open(dev, O_RDWR)) < 0) {
178 perror("fuse: failed to open fuse device");
179 return -1;
180 }
181
182mount:
183 if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
184 goto out;
185
186 pid = fork();
187 cpid = pid;
188
189 if (pid == -1) {
190 perror("fuse: fork() failed");
191 close(fd);
192 return -1;
193 }
194
195 if (pid == 0) {
196 if (! init_backgrounded()) {
197 /*
198 * If init is not backgrounded, we have to
199 * call the mount util backgrounded, to avoid
200 * deadlock.
201 */
202
203 pid = fork();
204
205 if (pid == -1) {
206 perror("fuse: fork() failed");
207 close(fd);
208 exit(1);
209 }
210 }
211
212 if (pid == 0) {
213 const char *argv[32];
214 int a = 0;
215 int ret = -1;
216
217 if (! fdnam)
218 {
219 ret = asprintf(&fdnam, "%d", fd);
220 if(ret == -1)
221 {
222 perror("fuse: failed to assemble mount arguments");
223 close(fd);
224 exit(1);
225 }
226 }
227
228 argv[a++] = mountprog;
229 if (opts) {
230 argv[a++] = "-o";
231 argv[a++] = opts;
232 }
233 argv[a++] = fdnam;
234 argv[a++] = mountpoint;
235 argv[a++] = NULL;
236 execvp(mountprog, (char **) argv);
237 perror("fuse: failed to exec mount program");
238 free(fdnam);
239 exit(1);
240 }
241
242 exit(0);
243 }
244
245 if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
246 perror("fuse: failed to mount file system");
247 close(fd);
248 return -1;
249 }
250
251out:
252 return fd;
253}
254
255struct mount_opts *parse_mount_opts(struct fuse_args *args)
256{
257 struct mount_opts *mo;
258
259 mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
260 if (mo == NULL)
261 return NULL;
262
263 memset(mo, 0, sizeof(struct mount_opts));
264
265 if (args &&
266 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
267 goto err_out;
268
269 return mo;
270
271err_out:
272 destroy_mount_opts(mo);
273 return NULL;
274}
275
276void destroy_mount_opts(struct mount_opts *mo)
277{
278 free(mo->kernel_opts);
279 free(mo);
280}
281
282int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
283{
284 /* mount util should not try to spawn the daemon */
285 setenv("MOUNT_FUSEFS_SAFE", "1", 1);
286 /* to notify the mount util it's called from lib */
287 setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
288
289 return fuse_mount_core(mountpoint, mo->kernel_opts);
290}
void fuse_log(enum fuse_log_level level, const char *fmt,...)
Definition fuse_log.c:77
#define FUSE_OPT_KEY(templ, key)
Definition fuse_opt.h:98
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition fuse_opt.c:398
int fuse_opt_add_opt(char **opts, const char *opt)
Definition fuse_opt.c:139
#define FUSE_OPT_END
Definition fuse_opt.h:104