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 LGPL2.txt.
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#define FUSE_KERN_DEVICE_ENV "FUSE_KERN_DEVICE"
53
54#ifndef MS_DIRSYNC
55#define MS_DIRSYNC 128
56#endif
57
58enum {
59 KEY_KERN_FLAG,
60 KEY_KERN_OPT,
61 KEY_FUSERMOUNT_OPT,
62 KEY_SUBTYPE_OPT,
63 KEY_MTAB_OPT,
64 KEY_ALLOW_OTHER,
65 KEY_RO,
66};
67
68struct mount_opts {
69 int allow_other;
70 int flags;
71 int auto_unmount;
72 int blkdev;
73 char *fsname;
74 char *subtype;
75 char *subtype_opt;
76 char *mtab_opts;
77 char *fusermount_opts;
78 char *kernel_opts;
79 unsigned max_read;
80};
81
82#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
83
84static const struct fuse_opt fuse_mount_opts[] = {
85 FUSE_MOUNT_OPT("allow_other", allow_other),
86 FUSE_MOUNT_OPT("blkdev", blkdev),
87 FUSE_MOUNT_OPT("auto_unmount", auto_unmount),
88 FUSE_MOUNT_OPT("fsname=%s", fsname),
89 FUSE_MOUNT_OPT("max_read=%u", max_read),
90 FUSE_MOUNT_OPT("subtype=%s", subtype),
91 FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
92 FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT),
93 FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
94 FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
95 FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
96 FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
97 FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
98 FUSE_OPT_KEY("context=", KEY_KERN_OPT),
99 FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT),
100 FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT),
101 FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT),
102 FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
103 FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
104 FUSE_OPT_KEY("-n", KEY_MTAB_OPT),
105 FUSE_OPT_KEY("-r", KEY_RO),
106 FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
107 FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
108 FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
109 FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
110 FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
111 FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
112 FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
113 FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
114 FUSE_OPT_KEY("async", KEY_KERN_FLAG),
115 FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
116 FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
117 FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
118 FUSE_OPT_KEY("nodiratime", KEY_KERN_FLAG),
119 FUSE_OPT_KEY("nostrictatime", KEY_KERN_FLAG),
120 FUSE_OPT_KEY("symfollow", KEY_KERN_FLAG),
121 FUSE_OPT_KEY("nosymfollow", KEY_KERN_FLAG),
123};
124
125/*
126 * Running fusermount by calling 'posix_spawn'
127 *
128 * @param out_pid might be NULL
129 */
130static int fusermount_posix_spawn(posix_spawn_file_actions_t *action,
131 char const * const argv[], pid_t *out_pid)
132{
133 const char *full_path = FUSERMOUNT_DIR "/" FUSERMOUNT_PROG;
134 pid_t pid;
135
136 /* See man 7 environ for the global environ pointer */
137
138 /* first try the install path */
139 int status = posix_spawn(&pid, full_path, action, NULL,
140 (char * const *) argv, environ);
141 if (status != 0) {
142 /* if that fails, try a system install */
143 status = posix_spawnp(&pid, FUSERMOUNT_PROG, action, NULL,
144 (char * const *) argv, environ);
145 }
146
147 if (status != 0) {
148 fuse_log(FUSE_LOG_ERR, "Failed to call '%s': %s\n",
149 FUSERMOUNT_PROG, 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) {
298 fuse_log(FUSE_LOG_ERR, "error retrieving control message header\n");
299 return -1;
300 }
301 if (cmsg->cmsg_type != SCM_RIGHTS) {
302 fuse_log(FUSE_LOG_ERR, "got control message of unknown type %d\n",
303 cmsg->cmsg_type);
304 return -1;
305 }
306 return *(int*)CMSG_DATA(cmsg);
307}
308
309void fuse_kern_unmount(const char *mountpoint, int fd)
310{
311 int res;
312
313 if (fd != -1) {
314 struct pollfd pfd;
315
316 pfd.fd = fd;
317 pfd.events = 0;
318 res = poll(&pfd, 1, 0);
319
320 /* Need to close file descriptor, otherwise synchronous umount
321 would recurse into filesystem, and deadlock.
322
323 Caller expects fuse_kern_unmount to close the fd, so close it
324 anyway. */
325 close(fd);
326
327 /* If file poll returns POLLERR on the device file descriptor,
328 then the filesystem is already unmounted or the connection
329 was severed via /sys/fs/fuse/connections/NNN/abort */
330 if (res == 1 && (pfd.revents & POLLERR))
331 return;
332 }
333
334 if (geteuid() == 0) {
335 fuse_mnt_umount("fuse", mountpoint, mountpoint, 1);
336 return;
337 }
338
339 res = umount2(mountpoint, MNT_DETACH | UMOUNT_NOFOLLOW);
340 if (res == 0)
341 return;
342
343 char const * const argv[] =
344 { FUSERMOUNT_PROG, "--unmount", "--quiet", "--lazy",
345 "--", mountpoint, NULL };
346 int status = fusermount_posix_spawn(NULL, argv, NULL);
347 if(status != 0) {
348 fuse_log(FUSE_LOG_ERR, "Spawning %s to unmount failed: %s",
349 FUSERMOUNT_PROG, strerror(-status));
350 return;
351 }
352}
353
354static int setup_auto_unmount(const char *mountpoint, int quiet)
355{
356 int fds[2];
357 pid_t pid;
358 int res;
359
360 if (!mountpoint) {
361 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
362 return -1;
363 }
364
365 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
366 if(res == -1) {
367 fuse_log(FUSE_LOG_ERR, "Setting up auto-unmount socketpair() failed: %s\n",
368 strerror(errno));
369 return -1;
370 }
371
372 char arg_fd_entry[30];
373 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
374 setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
375 /*
376 * This helps to identify the FD hold by parent process.
377 * In auto-unmount case, parent process can close this FD explicitly to do unmount.
378 * The FD[1] can be got via getenv(FUSE_COMMFD2_ENV).
379 * One potential use case is to satisfy FD-Leak checks.
380 */
381 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]);
382 setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
383
384 char const *const argv[] = {
385 FUSERMOUNT_PROG,
386 "--auto-unmount",
387 "--",
388 mountpoint,
389 NULL,
390 };
391
392 // TODO: add error handling for all manipulations of action.
393 posix_spawn_file_actions_t action;
394 posix_spawn_file_actions_init(&action);
395
396 if (quiet) {
397 posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0);
398 posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0);
399 }
400 posix_spawn_file_actions_addclose(&action, fds[1]);
401
402 /*
403 * auto-umount runs in the background - it is not waiting for the
404 * process
405 */
406 int status = fusermount_posix_spawn(&action, argv, &pid);
407
408 posix_spawn_file_actions_destroy(&action);
409
410 if(status != 0) {
411 close(fds[0]);
412 close(fds[1]);
413 fuse_log(FUSE_LOG_ERR, "fuse: Setting up auto-unmount failed (spawn): %s",
414 strerror(-status));
415 return -1;
416 }
417 // passed to child now, so can close here.
418 close(fds[0]);
419
420 // Now fusermount3 will only exit when fds[1] closes automatically when our
421 // process exits.
422 return 0;
423 // Note: fds[1] is leakend and doesn't get FD_CLOEXEC
424}
425
426static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
427 const char *opts, int quiet)
428{
429 int fds[2];
430 pid_t pid;
431 int res;
432
433 if (!mountpoint) {
434 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
435 return -1;
436 }
437
438 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
439 if(res == -1) {
440 fuse_log(FUSE_LOG_ERR, "Running %s: socketpair() failed: %s\n",
441 FUSERMOUNT_PROG, strerror(errno));
442 return -1;
443 }
444
445 char arg_fd_entry[30];
446 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
447 setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
448 /*
449 * This helps to identify the FD hold by parent process.
450 * In auto-unmount case, parent process can close this FD explicitly to do unmount.
451 * The FD[1] can be got via getenv(FUSE_COMMFD2_ENV).
452 * One potential use case is to satisfy FD-Leak checks.
453 */
454 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]);
455 setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
456
457 char const *const argv[] = {
458 FUSERMOUNT_PROG,
459 "-o", opts ? opts : "",
460 "--",
461 mountpoint,
462 NULL,
463 };
464
465
466 posix_spawn_file_actions_t action;
467 posix_spawn_file_actions_init(&action);
468
469 if (quiet) {
470 posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0);
471 posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0);
472 }
473 posix_spawn_file_actions_addclose(&action, fds[1]);
474
475 int status = fusermount_posix_spawn(&action, argv, &pid);
476
477 posix_spawn_file_actions_destroy(&action);
478
479 if(status != 0) {
480 close(fds[0]);
481 close(fds[1]);
482 fuse_log(FUSE_LOG_ERR, "posix_spawn(p)() for %s failed: %s",
483 FUSERMOUNT_PROG, strerror(-status));
484 return -1;
485 }
486
487 // passed to child now, so can close here.
488 close(fds[0]);
489
490 int fd = receive_fd(fds[1]);
491
492 if (!mo->auto_unmount) {
493 /* with auto_unmount option fusermount3 will not exit until
494 this socket is closed */
495 close(fds[1]);
496 waitpid(pid, NULL, 0); /* bury zombie */
497 }
498
499 if (fd >= 0)
500 fcntl(fd, F_SETFD, FD_CLOEXEC);
501
502 return fd;
503}
504
505#ifndef O_CLOEXEC
506#define O_CLOEXEC 0
507#endif
508
509static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
510 const char *mnt_opts)
511{
512 char tmp[128];
513 const char *devname = getenv(FUSE_KERN_DEVICE_ENV) ?: "/dev/fuse";
514 char *source = NULL;
515 char *type = NULL;
516 struct stat stbuf;
517 int fd;
518 int res;
519
520 if (!mnt) {
521 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
522 return -1;
523 }
524
525 res = stat(mnt, &stbuf);
526 if (res == -1) {
527 fuse_log(FUSE_LOG_ERR, "fuse: failed to access mountpoint %s: %s\n",
528 mnt, strerror(errno));
529 return -1;
530 }
531
532 fd = open(devname, O_RDWR | O_CLOEXEC);
533 if (fd == -1) {
534 if (errno == ENODEV || errno == ENOENT)
535 fuse_log(FUSE_LOG_ERR,
536 "fuse: device %s not found. Kernel module not loaded?\n",
537 devname);
538 else
539 fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n",
540 devname, strerror(errno));
541 return -1;
542 }
543 if (!O_CLOEXEC)
544 fcntl(fd, F_SETFD, FD_CLOEXEC);
545
546 snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
547 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
548
549 res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
550 if (res == -1)
551 goto out_close;
552
553 source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
554 (mo->subtype ? strlen(mo->subtype) : 0) +
555 strlen(devname) + 32);
556
557 type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
558 if (!type || !source) {
559 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate memory\n");
560 goto out_close;
561 }
562
563 strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
564 if (mo->subtype) {
565 strcat(type, ".");
566 strcat(type, mo->subtype);
567 }
568 strcpy(source,
569 mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
570
571 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
572 if (res == -1 && errno == ENODEV && mo->subtype) {
573 /* Probably missing subtype support */
574 strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
575 if (mo->fsname) {
576 if (!mo->blkdev)
577 sprintf(source, "%s#%s", mo->subtype,
578 mo->fsname);
579 } else {
580 strcpy(source, type);
581 }
582 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
583 }
584 if (res == -1) {
585 /*
586 * Maybe kernel doesn't support unprivileged mounts, in this
587 * case try falling back to fusermount3
588 */
589 if (errno == EPERM) {
590 res = -2;
591 } else {
592 int errno_save = errno;
593 if (mo->blkdev && errno == ENODEV &&
594 !fuse_mnt_check_fuseblk())
595 fuse_log(FUSE_LOG_ERR,
596 "fuse: 'fuseblk' support missing\n");
597 else
598 fuse_log(FUSE_LOG_ERR, "fuse: mount failed: %s\n",
599 strerror(errno_save));
600 }
601
602 goto out_close;
603 }
604
605#ifndef IGNORE_MTAB
606 if (geteuid() == 0) {
607 char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
608 res = -1;
609 if (!newmnt)
610 goto out_umount;
611
612 res = fuse_mnt_add_mount("fuse", source, newmnt, type,
613 mnt_opts);
614 free(newmnt);
615 if (res == -1)
616 goto out_umount;
617 }
618#endif /* IGNORE_MTAB */
619 free(type);
620 free(source);
621
622 return fd;
623
624out_umount:
625 umount2(mnt, MNT_DETACH | UMOUNT_NOFOLLOW); /* lazy umount */
626out_close:
627 free(type);
628 free(source);
629 close(fd);
630 return res;
631}
632
633static int get_mnt_flag_opts(char **mnt_optsp, int flags)
634{
635 int i;
636
637 if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
638 return -1;
639
640 for (i = 0; mount_flags[i].opt != NULL; i++) {
641 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
642 fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
643 return -1;
644 }
645 return 0;
646}
647
648struct mount_opts *parse_mount_opts(struct fuse_args *args)
649{
650 struct mount_opts *mo;
651
652 mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
653 if (mo == NULL)
654 return NULL;
655
656 memset(mo, 0, sizeof(struct mount_opts));
657 mo->flags = MS_NOSUID | MS_NODEV;
658
659 if (args &&
660 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
661 goto err_out;
662
663 return mo;
664
665err_out:
666 destroy_mount_opts(mo);
667 return NULL;
668}
669
670void destroy_mount_opts(struct mount_opts *mo)
671{
672 free(mo->fsname);
673 free(mo->subtype);
674 free(mo->fusermount_opts);
675 free(mo->subtype_opt);
676 free(mo->kernel_opts);
677 free(mo->mtab_opts);
678 free(mo);
679}
680
681
682int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
683{
684 int res = -1;
685 char *mnt_opts = NULL;
686
687 res = -1;
688 if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
689 goto out;
690 if (mo->kernel_opts && fuse_opt_add_opt(&mnt_opts, mo->kernel_opts) == -1)
691 goto out;
692 if (mo->mtab_opts && fuse_opt_add_opt(&mnt_opts, mo->mtab_opts) == -1)
693 goto out;
694
695 res = fuse_mount_sys(mountpoint, mo, mnt_opts);
696 if (res >= 0 && mo->auto_unmount) {
697 if(0 > setup_auto_unmount(mountpoint, 0)) {
698 // Something went wrong, let's umount like in fuse_mount_sys.
699 umount2(mountpoint,
700 MNT_DETACH | UMOUNT_NOFOLLOW); /* lazy umount */
701 res = -1;
702 }
703 } else if (res == -2) {
704 if (mo->fusermount_opts &&
705 fuse_opt_add_opt(&mnt_opts, mo->fusermount_opts) == -1)
706 goto out;
707
708 if (mo->subtype) {
709 char *tmp_opts = NULL;
710
711 res = -1;
712 if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
713 fuse_opt_add_opt(&tmp_opts, mo->subtype_opt) == -1) {
714 free(tmp_opts);
715 goto out;
716 }
717
718 res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
719 free(tmp_opts);
720 if (res == -1)
721 res = fuse_mount_fusermount(mountpoint, mo,
722 mnt_opts, 0);
723 } else {
724 res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
725 }
726 }
727out:
728 free(mnt_opts);
729 return res;
730}
void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
#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