libfuse
mount.c
1/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4
5 Architecture specific file system mounting (Linux).
6
7 This program can be distributed under the terms of the GNU LGPLv2.
8 See the file COPYING.LIB.
9*/
10
11/* For environ */
12#define _GNU_SOURCE
13
14#include "fuse_config.h"
15#include "fuse_i.h"
16#include "fuse_misc.h"
17#include "fuse_opt.h"
18#include "mount_util.h"
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <stddef.h>
24#include <string.h>
25#include <fcntl.h>
26#include <errno.h>
27#include <poll.h>
28#include <spawn.h>
29#include <sys/socket.h>
30#include <sys/un.h>
31#include <sys/wait.h>
32
33#include "fuse_mount_compat.h"
34
35#ifdef __NetBSD__
36#include <perfuse.h>
37
38#define MS_RDONLY MNT_RDONLY
39#define MS_NOSUID MNT_NOSUID
40#define MS_NODEV MNT_NODEV
41#define MS_NOEXEC MNT_NOEXEC
42#define MS_SYNCHRONOUS MNT_SYNCHRONOUS
43#define MS_NOATIME MNT_NOATIME
44#define MS_NOSYMFOLLOW MNT_NOSYMFOLLOW
45
46#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
47#endif
48
49#define FUSERMOUNT_PROG "fusermount3"
50#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
51#define FUSE_COMMFD2_ENV "_FUSE_COMMFD2"
52
53#ifndef MS_DIRSYNC
54#define MS_DIRSYNC 128
55#endif
56
57enum {
58 KEY_KERN_FLAG,
59 KEY_KERN_OPT,
60 KEY_FUSERMOUNT_OPT,
61 KEY_SUBTYPE_OPT,
62 KEY_MTAB_OPT,
63 KEY_ALLOW_OTHER,
64 KEY_RO,
65};
66
67struct mount_opts {
68 int allow_other;
69 int flags;
70 int auto_unmount;
71 int blkdev;
72 char *fsname;
73 char *subtype;
74 char *subtype_opt;
75 char *mtab_opts;
76 char *fusermount_opts;
77 char *kernel_opts;
78 unsigned max_read;
79};
80
81#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
82
83static const struct fuse_opt fuse_mount_opts[] = {
84 FUSE_MOUNT_OPT("allow_other", allow_other),
85 FUSE_MOUNT_OPT("blkdev", blkdev),
86 FUSE_MOUNT_OPT("auto_unmount", auto_unmount),
87 FUSE_MOUNT_OPT("fsname=%s", fsname),
88 FUSE_MOUNT_OPT("max_read=%u", max_read),
89 FUSE_MOUNT_OPT("subtype=%s", subtype),
90 FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
91 FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT),
92 FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
93 FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
94 FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
95 FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
96 FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
97 FUSE_OPT_KEY("context=", KEY_KERN_OPT),
98 FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT),
99 FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT),
100 FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT),
101 FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
102 FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
103 FUSE_OPT_KEY("-n", KEY_MTAB_OPT),
104 FUSE_OPT_KEY("-r", KEY_RO),
105 FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
106 FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
107 FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
108 FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
109 FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
110 FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
111 FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
112 FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
113 FUSE_OPT_KEY("async", KEY_KERN_FLAG),
114 FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
115 FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
116 FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
117 FUSE_OPT_KEY("nodiratime", KEY_KERN_FLAG),
118 FUSE_OPT_KEY("nostrictatime", KEY_KERN_FLAG),
119 FUSE_OPT_KEY("symfollow", KEY_KERN_FLAG),
120 FUSE_OPT_KEY("nosymfollow", KEY_KERN_FLAG),
122};
123
124/*
125 * Running fusermount by calling 'posix_spawn'
126 *
127 * @param out_pid might be NULL
128 */
129static int fusermount_posix_spawn(posix_spawn_file_actions_t *action,
130 char const * const argv[], pid_t *out_pid)
131{
132 const char *full_path = FUSERMOUNT_DIR "/" FUSERMOUNT_PROG;
133 pid_t pid;
134
135 /* See man 7 environ for the global environ pointer */
136
137 /* first try the install path */
138 int status = posix_spawn(&pid, full_path, action, NULL,
139 (char * const *) argv, environ);
140 if (status != 0) {
141 /* if that fails, try a system install */
142 status = posix_spawnp(&pid, FUSERMOUNT_PROG, action, NULL,
143 (char * const *) argv, environ);
144 }
145
146 if (status != 0) {
147 fuse_log(FUSE_LOG_ERR,
148 "On calling fusermount posix_spawn failed: %s\n",
149 strerror(status));
150 return -status;
151 }
152
153 if (out_pid)
154 *out_pid = pid;
155 else
156 waitpid(pid, NULL, 0); /* FIXME: check exit code and return error if any */
157
158 return 0;
159}
160
161void fuse_mount_version(void)
162{
163 char const *const argv[] = {FUSERMOUNT_PROG, "--version", NULL};
164 int status = fusermount_posix_spawn(NULL, argv, NULL);
165
166 if(status != 0)
167 fuse_log(FUSE_LOG_ERR, "Running '%s --version' failed",
168 FUSERMOUNT_PROG);
169}
170
171struct mount_flags {
172 const char *opt;
173 unsigned long flag;
174 int on;
175};
176
177static const struct mount_flags mount_flags[] = {
178 {"rw", MS_RDONLY, 0},
179 {"ro", MS_RDONLY, 1},
180 {"suid", MS_NOSUID, 0},
181 {"nosuid", MS_NOSUID, 1},
182 {"dev", MS_NODEV, 0},
183 {"nodev", MS_NODEV, 1},
184 {"exec", MS_NOEXEC, 0},
185 {"noexec", MS_NOEXEC, 1},
186 {"async", MS_SYNCHRONOUS, 0},
187 {"sync", MS_SYNCHRONOUS, 1},
188 {"noatime", MS_NOATIME, 1},
189 {"nodiratime", MS_NODIRATIME, 1},
190 {"norelatime", MS_RELATIME, 0},
191 {"nostrictatime", MS_STRICTATIME, 0},
192 {"symfollow", MS_NOSYMFOLLOW, 0},
193 {"nosymfollow", MS_NOSYMFOLLOW, 1},
194#ifndef __NetBSD__
195 {"dirsync", MS_DIRSYNC, 1},
196#endif
197 {NULL, 0, 0}
198};
199
200unsigned get_max_read(struct mount_opts *o)
201{
202 return o->max_read;
203}
204
205static void set_mount_flag(const char *s, int *flags)
206{
207 int i;
208
209 for (i = 0; mount_flags[i].opt != NULL; i++) {
210 const char *opt = mount_flags[i].opt;
211 if (strcmp(opt, s) == 0) {
212 if (mount_flags[i].on)
213 *flags |= mount_flags[i].flag;
214 else
215 *flags &= ~mount_flags[i].flag;
216 return;
217 }
218 }
219 fuse_log(FUSE_LOG_ERR, "fuse: internal error, can't find mount flag\n");
220 abort();
221}
222
223static int fuse_mount_opt_proc(void *data, const char *arg, int key,
224 struct fuse_args *outargs)
225{
226 (void) outargs;
227 struct mount_opts *mo = data;
228
229 switch (key) {
230 case KEY_RO:
231 arg = "ro";
232 /* fall through */
233 case KEY_KERN_FLAG:
234 set_mount_flag(arg, &mo->flags);
235 return 0;
236
237 case KEY_KERN_OPT:
238 return fuse_opt_add_opt(&mo->kernel_opts, arg);
239
240 case KEY_FUSERMOUNT_OPT:
241 return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg);
242
243 case KEY_SUBTYPE_OPT:
244 return fuse_opt_add_opt(&mo->subtype_opt, arg);
245
246 case KEY_MTAB_OPT:
247 return fuse_opt_add_opt(&mo->mtab_opts, arg);
248
249 /* Third party options like 'x-gvfs-notrash' */
250 case FUSE_OPT_KEY_OPT:
251 return (strncmp("x-", arg, 2) == 0) ?
252 fuse_opt_add_opt(&mo->mtab_opts, arg) :
253 1;
254 }
255
256 /* Pass through unknown options */
257 return 1;
258}
259
260/* return value:
261 * >= 0 => fd
262 * -1 => error
263 */
264static int receive_fd(int fd)
265{
266 struct msghdr msg;
267 struct iovec iov;
268 char buf[1];
269 int rv;
270 size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
271 struct cmsghdr *cmsg;
272
273 iov.iov_base = buf;
274 iov.iov_len = 1;
275
276 memset(&msg, 0, sizeof(msg));
277 msg.msg_name = 0;
278 msg.msg_namelen = 0;
279 msg.msg_iov = &iov;
280 msg.msg_iovlen = 1;
281 /* old BSD implementations should use msg_accrights instead of
282 * msg_control; the interface is different. */
283 msg.msg_control = ccmsg;
284 msg.msg_controllen = sizeof(ccmsg);
285
286 while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
287 if (rv == -1) {
288 fuse_log(FUSE_LOG_ERR, "recvmsg failed: %s", strerror(errno));
289 return -1;
290 }
291 if(!rv) {
292 /* EOF */
293 return -1;
294 }
295
296 cmsg = CMSG_FIRSTHDR(&msg);
297 if (cmsg->cmsg_type != SCM_RIGHTS) {
298 fuse_log(FUSE_LOG_ERR, "got control message of unknown type %d\n",
299 cmsg->cmsg_type);
300 return -1;
301 }
302 return *(int*)CMSG_DATA(cmsg);
303}
304
305void fuse_kern_unmount(const char *mountpoint, int fd)
306{
307 int res;
308
309 if (fd != -1) {
310 struct pollfd pfd;
311
312 pfd.fd = fd;
313 pfd.events = 0;
314 res = poll(&pfd, 1, 0);
315
316 /* Need to close file descriptor, otherwise synchronous umount
317 would recurse into filesystem, and deadlock.
318
319 Caller expects fuse_kern_unmount to close the fd, so close it
320 anyway. */
321 close(fd);
322
323 /* If file poll returns POLLERR on the device file descriptor,
324 then the filesystem is already unmounted or the connection
325 was severed via /sys/fs/fuse/connections/NNN/abort */
326 if (res == 1 && (pfd.revents & POLLERR))
327 return;
328 }
329
330 if (geteuid() == 0) {
331 fuse_mnt_umount("fuse", mountpoint, mountpoint, 1);
332 return;
333 }
334
335 res = umount2(mountpoint, 2);
336 if (res == 0)
337 return;
338
339 char const * const argv[] =
340 { FUSERMOUNT_PROG, "--unmount", "--quiet", "--lazy",
341 "--", mountpoint, NULL };
342 int status = fusermount_posix_spawn(NULL, argv, NULL);
343 if(status != 0) {
344 fuse_log(FUSE_LOG_ERR, "Spawning %s to unmount failed: %s",
345 FUSERMOUNT_PROG, strerror(-status));
346 return;
347 }
348}
349
350static int setup_auto_unmount(const char *mountpoint, int quiet)
351{
352 int fds[2];
353 pid_t pid;
354 int res;
355
356 if (!mountpoint) {
357 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
358 return -1;
359 }
360
361 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
362 if(res == -1) {
363 fuse_log(FUSE_LOG_ERR, "Setting up auto-unmountsocketpair() failed",
364 strerror(errno));
365 return -1;
366 }
367
368 char arg_fd_entry[30];
369 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
370 setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
371 /*
372 * This helps to identify the FD hold by parent process.
373 * In auto-unmount case, parent process can close this FD explicitly to do unmount.
374 * The FD[1] can be got via getenv(FUSE_COMMFD2_ENV).
375 * One potential use case is to satisfy FD-Leak checks.
376 */
377 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]);
378 setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
379
380 char const *const argv[] = {
381 FUSERMOUNT_PROG,
382 "--auto-unmount",
383 "--",
384 mountpoint,
385 NULL,
386 };
387
388 // TODO: add error handling for all manipulations of action.
389 posix_spawn_file_actions_t action;
390 posix_spawn_file_actions_init(&action);
391
392 if (quiet) {
393 posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0);
394 posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0);
395 }
396 posix_spawn_file_actions_addclose(&action, fds[1]);
397
398 /*
399 * auto-umount runs in the background - it is not waiting for the
400 * process
401 */
402 int status = fusermount_posix_spawn(&action, argv, &pid);
403
404 posix_spawn_file_actions_destroy(&action);
405
406 if(status != 0) {
407 close(fds[0]);
408 close(fds[1]);
409 fuse_log(FUSE_LOG_ERR, "fuse: Setting up auto-unmount failed (spawn): %s",
410 strerror(-status));
411 return -1;
412 }
413 // passed to child now, so can close here.
414 close(fds[0]);
415
416 // Now fusermount3 will only exit when fds[1] closes automatically when our
417 // process exits.
418 return 0;
419 // Note: fds[1] is leakend and doesn't get FD_CLOEXEC
420}
421
422static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
423 const char *opts, int quiet)
424{
425 int fds[2];
426 pid_t pid;
427 int res;
428
429 if (!mountpoint) {
430 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
431 return -1;
432 }
433
434 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
435 if(res == -1) {
436 fuse_log(FUSE_LOG_ERR, "Running %s: socketpair() failed: %s\n",
437 FUSERMOUNT_PROG, strerror(errno));
438 return -1;
439 }
440
441 char arg_fd_entry[30];
442 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
443 setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
444 /*
445 * This helps to identify the FD hold by parent process.
446 * In auto-unmount case, parent process can close this FD explicitly to do unmount.
447 * The FD[1] can be got via getenv(FUSE_COMMFD2_ENV).
448 * One potential use case is to satisfy FD-Leak checks.
449 */
450 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]);
451 setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
452
453 char const *const argv[] = {
454 FUSERMOUNT_PROG,
455 "-o", opts ? opts : "",
456 "--",
457 mountpoint,
458 NULL,
459 };
460
461
462 posix_spawn_file_actions_t action;
463 posix_spawn_file_actions_init(&action);
464
465 if (quiet) {
466 posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0);
467 posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0);
468 }
469 posix_spawn_file_actions_addclose(&action, fds[1]);
470
471 int status = fusermount_posix_spawn(&action, argv, &pid);
472
473 posix_spawn_file_actions_destroy(&action);
474
475 if(status != 0) {
476 close(fds[0]);
477 close(fds[1]);
478 fuse_log(FUSE_LOG_ERR, "posix_spawn(p)() for %s failed: %s",
479 FUSERMOUNT_PROG, strerror(-status));
480 return -1;
481 }
482
483 // passed to child now, so can close here.
484 close(fds[0]);
485
486 int fd = receive_fd(fds[1]);
487
488 if (!mo->auto_unmount) {
489 /* with auto_unmount option fusermount3 will not exit until
490 this socket is closed */
491 close(fds[1]);
492 waitpid(pid, NULL, 0); /* bury zombie */
493 }
494
495 if (fd >= 0)
496 fcntl(fd, F_SETFD, FD_CLOEXEC);
497
498 return fd;
499}
500
501#ifndef O_CLOEXEC
502#define O_CLOEXEC 0
503#endif
504
505static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
506 const char *mnt_opts)
507{
508 char tmp[128];
509 const char *devname = "/dev/fuse";
510 char *source = NULL;
511 char *type = NULL;
512 struct stat stbuf;
513 int fd;
514 int res;
515
516 if (!mnt) {
517 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
518 return -1;
519 }
520
521 res = stat(mnt, &stbuf);
522 if (res == -1) {
523 fuse_log(FUSE_LOG_ERR, "fuse: failed to access mountpoint %s: %s\n",
524 mnt, strerror(errno));
525 return -1;
526 }
527
528 fd = open(devname, O_RDWR | O_CLOEXEC);
529 if (fd == -1) {
530 if (errno == ENODEV || errno == ENOENT)
531 fuse_log(FUSE_LOG_ERR, "fuse: device not found, try 'modprobe fuse' first\n");
532 else
533 fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n",
534 devname, strerror(errno));
535 return -1;
536 }
537 if (!O_CLOEXEC)
538 fcntl(fd, F_SETFD, FD_CLOEXEC);
539
540 snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
541 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
542
543 res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
544 if (res == -1)
545 goto out_close;
546
547 source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
548 (mo->subtype ? strlen(mo->subtype) : 0) +
549 strlen(devname) + 32);
550
551 type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
552 if (!type || !source) {
553 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate memory\n");
554 goto out_close;
555 }
556
557 strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
558 if (mo->subtype) {
559 strcat(type, ".");
560 strcat(type, mo->subtype);
561 }
562 strcpy(source,
563 mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
564
565 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
566 if (res == -1 && errno == ENODEV && mo->subtype) {
567 /* Probably missing subtype support */
568 strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
569 if (mo->fsname) {
570 if (!mo->blkdev)
571 sprintf(source, "%s#%s", mo->subtype,
572 mo->fsname);
573 } else {
574 strcpy(source, type);
575 }
576 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
577 }
578 if (res == -1) {
579 /*
580 * Maybe kernel doesn't support unprivileged mounts, in this
581 * case try falling back to fusermount3
582 */
583 if (errno == EPERM) {
584 res = -2;
585 } else {
586 int errno_save = errno;
587 if (mo->blkdev && errno == ENODEV &&
588 !fuse_mnt_check_fuseblk())
589 fuse_log(FUSE_LOG_ERR,
590 "fuse: 'fuseblk' support missing\n");
591 else
592 fuse_log(FUSE_LOG_ERR, "fuse: mount failed: %s\n",
593 strerror(errno_save));
594 }
595
596 goto out_close;
597 }
598
599#ifndef IGNORE_MTAB
600 if (geteuid() == 0) {
601 char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
602 res = -1;
603 if (!newmnt)
604 goto out_umount;
605
606 res = fuse_mnt_add_mount("fuse", source, newmnt, type,
607 mnt_opts);
608 free(newmnt);
609 if (res == -1)
610 goto out_umount;
611 }
612#endif /* IGNORE_MTAB */
613 free(type);
614 free(source);
615
616 return fd;
617
618out_umount:
619 umount2(mnt, 2); /* lazy umount */
620out_close:
621 free(type);
622 free(source);
623 close(fd);
624 return res;
625}
626
627static int get_mnt_flag_opts(char **mnt_optsp, int flags)
628{
629 int i;
630
631 if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
632 return -1;
633
634 for (i = 0; mount_flags[i].opt != NULL; i++) {
635 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
636 fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
637 return -1;
638 }
639 return 0;
640}
641
642struct mount_opts *parse_mount_opts(struct fuse_args *args)
643{
644 struct mount_opts *mo;
645
646 mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
647 if (mo == NULL)
648 return NULL;
649
650 memset(mo, 0, sizeof(struct mount_opts));
651 mo->flags = MS_NOSUID | MS_NODEV;
652
653 if (args &&
654 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
655 goto err_out;
656
657 return mo;
658
659err_out:
660 destroy_mount_opts(mo);
661 return NULL;
662}
663
664void destroy_mount_opts(struct mount_opts *mo)
665{
666 free(mo->fsname);
667 free(mo->subtype);
668 free(mo->fusermount_opts);
669 free(mo->subtype_opt);
670 free(mo->kernel_opts);
671 free(mo->mtab_opts);
672 free(mo);
673}
674
675
676int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
677{
678 int res = -1;
679 char *mnt_opts = NULL;
680
681 res = -1;
682 if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
683 goto out;
684 if (mo->kernel_opts && fuse_opt_add_opt(&mnt_opts, mo->kernel_opts) == -1)
685 goto out;
686 if (mo->mtab_opts && fuse_opt_add_opt(&mnt_opts, mo->mtab_opts) == -1)
687 goto out;
688
689 res = fuse_mount_sys(mountpoint, mo, mnt_opts);
690 if (res >= 0 && mo->auto_unmount) {
691 if(0 > setup_auto_unmount(mountpoint, 0)) {
692 // Something went wrong, let's umount like in fuse_mount_sys.
693 umount2(mountpoint, MNT_DETACH); /* lazy umount */
694 res = -1;
695 }
696 } else if (res == -2) {
697 if (mo->fusermount_opts &&
698 fuse_opt_add_opt(&mnt_opts, mo->fusermount_opts) == -1)
699 goto out;
700
701 if (mo->subtype) {
702 char *tmp_opts = NULL;
703
704 res = -1;
705 if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
706 fuse_opt_add_opt(&tmp_opts, mo->subtype_opt) == -1) {
707 free(tmp_opts);
708 goto out;
709 }
710
711 res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
712 free(tmp_opts);
713 if (res == -1)
714 res = fuse_mount_fusermount(mountpoint, mo,
715 mnt_opts, 0);
716 } else {
717 res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
718 }
719 }
720out:
721 free(mnt_opts);
722 return res;
723}
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
#define FUSE_OPT_KEY_OPT
Definition fuse_opt.h:129
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
Definition fuse_opt.c:144
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