libfuse: remove "-D_FILE_OFFSET_BITS=64" from fuse.pc
[fuse.git] / lib / mount_bsd.c
blob52c55f53d704577504ef43b888e9d91cafc30b9a
1 /*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB.
7 */
9 #include "config.h"
10 #include "fuse_i.h"
11 #include "fuse_misc.h"
12 #include "fuse_opt.h"
14 #include <sys/stat.h>
15 #include <sys/wait.h>
16 #include <sys/sysctl.h>
17 #include <sys/user.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <stddef.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <paths.h>
26 #include <limits.h>
28 #define FUSERMOUNT_PROG "mount_fusefs"
29 #define FUSE_DEV_TRUNK "/dev/fuse"
31 enum {
32 KEY_ALLOW_ROOT,
33 KEY_RO,
34 KEY_HELP,
35 KEY_VERSION,
36 KEY_KERN
39 struct mount_opts {
40 int allow_other;
41 int allow_root;
42 int ishelp;
43 char *kernel_opts;
46 #define FUSE_DUAL_OPT_KEY(templ, key) \
47 FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
49 static const struct fuse_opt fuse_mount_opts[] = {
50 { "allow_other", offsetof(struct mount_opts, allow_other), 1 },
51 { "allow_root", offsetof(struct mount_opts, allow_root), 1 },
52 FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
53 FUSE_OPT_KEY("-r", KEY_RO),
54 FUSE_OPT_KEY("-h", KEY_HELP),
55 FUSE_OPT_KEY("--help", KEY_HELP),
56 FUSE_OPT_KEY("-V", KEY_VERSION),
57 FUSE_OPT_KEY("--version", KEY_VERSION),
58 /* standard FreeBSD mount options */
59 FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
60 FUSE_DUAL_OPT_KEY("async", KEY_KERN),
61 FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
62 FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
63 FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
64 FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
65 FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
66 FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
67 FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
68 FUSE_DUAL_OPT_KEY("union", KEY_KERN),
69 FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
70 FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
71 FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
72 FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
73 FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
74 FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
75 FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
76 FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
77 FUSE_DUAL_OPT_KEY("force", KEY_KERN),
78 FUSE_DUAL_OPT_KEY("update", KEY_KERN),
79 FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
80 FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
81 FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
82 /* options supported under both Linux and FBSD */
83 FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
84 FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
85 FUSE_OPT_KEY("max_read=", KEY_KERN),
86 FUSE_OPT_KEY("subtype=", KEY_KERN),
87 /* FBSD FUSE specific mount options */
88 FUSE_DUAL_OPT_KEY("private", KEY_KERN),
89 FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
90 FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
91 FUSE_OPT_KEY("nosync_unmount", KEY_KERN),
92 /* stock FBSD mountopt parsing routine lets anything be negated... */
94 * Linux specific mount options, but let just the mount util
95 * handle them
97 FUSE_OPT_KEY("fsname=", KEY_KERN),
98 FUSE_OPT_KEY("nonempty", KEY_KERN),
99 FUSE_OPT_KEY("large_read", KEY_KERN),
100 FUSE_OPT_END
103 static void mount_help(void)
105 fprintf(stderr,
106 " -o allow_root allow access to root\n"
108 system(FUSERMOUNT_PROG " --help");
109 fputc('\n', stderr);
112 static void mount_version(void)
114 system(FUSERMOUNT_PROG " --version");
117 static int fuse_mount_opt_proc(void *data, const char *arg, int key,
118 struct fuse_args *outargs)
120 struct mount_opts *mo = data;
122 switch (key) {
123 case KEY_ALLOW_ROOT:
124 if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
125 fuse_opt_add_arg(outargs, "-oallow_root") == -1)
126 return -1;
127 return 0;
129 case KEY_RO:
130 arg = "ro";
131 /* fall through */
133 case KEY_KERN:
134 return fuse_opt_add_opt(&mo->kernel_opts, arg);
136 case KEY_HELP:
137 mount_help();
138 mo->ishelp = 1;
139 break;
141 case KEY_VERSION:
142 mount_version();
143 mo->ishelp = 1;
144 break;
146 return 1;
149 void fuse_unmount_compat22(const char *mountpoint)
151 char dev[128];
152 char *ssc, *umount_cmd;
153 FILE *sf;
154 int rv;
155 char seekscript[] =
156 /* error message is annoying in help output */
157 "exec 2>/dev/null; "
158 "/usr/bin/fstat " FUSE_DEV_TRUNK "* | "
159 "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
160 " { if ($3 == %d) print $10; }' | "
161 "/usr/bin/sort | "
162 "/usr/bin/uniq | "
163 "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";
165 (void) mountpoint;
168 * If we don't know the fd, we have to resort to the scripted
169 * solution -- iterating over the fd-s is unpractical, as we
170 * don't know how many of open files we have. (This could be
171 * looked up in procfs -- however, that's optional on FBSD; or
172 * read out from the kmem -- however, that's bound to
173 * privileges (in fact, that's what happens when we call the
174 * setgid kmem fstat(1) utility).
176 if (asprintf(&ssc, seekscript, getpid()) == -1)
177 return;
179 errno = 0;
180 sf = popen(ssc, "r");
181 free(ssc);
182 if (! sf)
183 return;
185 fgets(dev, sizeof(dev), sf);
186 rv = pclose(sf);
187 if (rv)
188 return;
190 if (asprintf(&umount_cmd, "/sbin/umount %s", dev) == -1)
191 return;
192 system(umount_cmd);
193 free(umount_cmd);
196 static void do_unmount(char *dev, int fd)
198 char device_path[SPECNAMELEN + 12];
199 const char *argv[4];
200 const char umount_cmd[] = "/sbin/umount";
201 pid_t pid;
203 snprintf(device_path, SPECNAMELEN + 12, _PATH_DEV "%s", dev);
205 argv[0] = umount_cmd;
206 argv[1] = "-f";
207 argv[2] = device_path;
208 argv[3] = NULL;
210 pid = fork();
212 if (pid == -1)
213 return;
215 if (pid == 0) {
216 close(fd);
217 execvp(umount_cmd, (char **)argv);
218 exit(1);
221 waitpid(pid, NULL, 0);
224 void fuse_kern_unmount(const char *mountpoint, int fd)
226 char *ep, dev[128];
227 struct stat sbuf;
229 (void)mountpoint;
231 if (fstat(fd, &sbuf) == -1)
232 goto out;
234 devname_r(sbuf.st_rdev, S_IFCHR, dev, 128);
236 if (strncmp(dev, "fuse", 4))
237 goto out;
239 strtol(dev + 4, &ep, 10);
240 if (*ep != '\0')
241 goto out;
243 do_unmount(dev, fd);
245 out:
246 close(fd);
249 /* Check if kernel is doing init in background */
250 static int init_backgrounded(void)
252 unsigned ibg, len;
254 len = sizeof(ibg);
256 if (sysctlbyname("vfs.fuse.init_backgrounded", &ibg, &len, NULL, 0))
257 return 0;
259 return ibg;
263 static int fuse_mount_core(const char *mountpoint, const char *opts)
265 const char *mountprog = FUSERMOUNT_PROG;
266 int fd;
267 char *fdnam, *dev;
268 pid_t pid, cpid;
269 int status;
271 fdnam = getenv("FUSE_DEV_FD");
273 if (fdnam) {
274 char *ep;
276 fd = strtol(fdnam, &ep, 10);
278 if (*ep != '\0') {
279 fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
280 return -1;
283 if (fd < 0)
284 return -1;
286 goto mount;
289 dev = getenv("FUSE_DEV_NAME");
291 if (! dev)
292 dev = (char *)FUSE_DEV_TRUNK;
294 if ((fd = open(dev, O_RDWR)) < 0) {
295 perror("fuse: failed to open fuse device");
296 return -1;
299 mount:
300 if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
301 goto out;
303 pid = fork();
304 cpid = pid;
306 if (pid == -1) {
307 perror("fuse: fork() failed");
308 close(fd);
309 return -1;
312 if (pid == 0) {
313 if (! init_backgrounded()) {
315 * If init is not backgrounded, we have to
316 * call the mount util backgrounded, to avoid
317 * deadlock.
320 pid = fork();
322 if (pid == -1) {
323 perror("fuse: fork() failed");
324 close(fd);
325 exit(1);
329 if (pid == 0) {
330 const char *argv[32];
331 int a = 0;
333 if (! fdnam && asprintf(&fdnam, "%d", fd) == -1) {
334 perror("fuse: failed to assemble mount arguments");
335 exit(1);
338 argv[a++] = mountprog;
339 if (opts) {
340 argv[a++] = "-o";
341 argv[a++] = opts;
343 argv[a++] = fdnam;
344 argv[a++] = mountpoint;
345 argv[a++] = NULL;
346 execvp(mountprog, (char **) argv);
347 perror("fuse: failed to exec mount program");
348 exit(1);
351 exit(0);
354 if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
355 perror("fuse: failed to mount file system");
356 close(fd);
357 return -1;
360 out:
361 return fd;
364 int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
366 struct mount_opts mo;
367 int res = -1;
369 memset(&mo, 0, sizeof(mo));
370 /* mount util should not try to spawn the daemon */
371 setenv("MOUNT_FUSEFS_SAFE", "1", 1);
372 /* to notify the mount util it's called from lib */
373 setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
375 if (args &&
376 fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
377 return -1;
379 if (mo.allow_other && mo.allow_root) {
380 fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
381 goto out;
383 if (mo.ishelp)
384 return 0;
386 res = fuse_mount_core(mountpoint, mo.kernel_opts);
387 out:
388 free(mo.kernel_opts);
389 return res;