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