14#include "fuse_config.h"
18#include "mount_util.h"
29#include <sys/socket.h>
33#include "fuse_mount_compat.h"
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
46#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
49#define FUSERMOUNT_PROG "fusermount3"
50#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
51#define FUSE_COMMFD2_ENV "_FUSE_COMMFD2"
76 char *fusermount_opts;
81#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
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),
129static int fusermount_posix_spawn(posix_spawn_file_actions_t *action,
130 char const *
const argv[], pid_t *out_pid)
132 const char *full_path = FUSERMOUNT_DIR
"/" FUSERMOUNT_PROG;
138 int status = posix_spawn(&pid, full_path, action, NULL,
139 (
char *
const *) argv, environ);
142 status = posix_spawnp(&pid, FUSERMOUNT_PROG, action, NULL,
143 (
char *
const *) argv, environ);
148 "On calling fusermount posix_spawn failed: %s\n",
156 waitpid(pid, NULL, 0);
161void fuse_mount_version(
void)
163 char const *
const argv[] = {FUSERMOUNT_PROG,
"--version", NULL};
164 int status = fusermount_posix_spawn(NULL, argv, NULL);
167 fuse_log(FUSE_LOG_ERR,
"Running '%s --version' failed",
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},
195 {
"dirsync", MS_DIRSYNC, 1},
200unsigned get_max_read(
struct mount_opts *o)
205static void set_mount_flag(
const char *s,
int *flags)
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;
215 *flags &= ~mount_flags[i].flag;
219 fuse_log(FUSE_LOG_ERR,
"fuse: internal error, can't find mount flag\n");
223static int fuse_mount_opt_proc(
void *data,
const char *arg,
int key,
227 struct mount_opts *mo = data;
234 set_mount_flag(arg, &mo->flags);
240 case KEY_FUSERMOUNT_OPT:
243 case KEY_SUBTYPE_OPT:
251 return (strncmp(
"x-", arg, 2) == 0) ?
264static int receive_fd(
int fd)
270 size_t ccmsg[CMSG_SPACE(
sizeof(
int)) /
sizeof(size_t)];
271 struct cmsghdr *cmsg;
276 memset(&msg, 0,
sizeof(msg));
283 msg.msg_control = ccmsg;
284 msg.msg_controllen =
sizeof(ccmsg);
286 while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
288 fuse_log(FUSE_LOG_ERR,
"recvmsg failed: %s", strerror(errno));
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",
302 return *(
int*)CMSG_DATA(cmsg);
305void fuse_kern_unmount(
const char *mountpoint,
int fd)
314 res = poll(&pfd, 1, 0);
326 if (res == 1 && (pfd.revents & POLLERR))
330 if (geteuid() == 0) {
331 fuse_mnt_umount(
"fuse", mountpoint, mountpoint, 1);
335 res = umount2(mountpoint, 2);
339 char const *
const argv[] =
340 { FUSERMOUNT_PROG,
"--unmount",
"--quiet",
"--lazy",
341 "--", mountpoint, NULL };
342 int status = fusermount_posix_spawn(NULL, argv, NULL);
344 fuse_log(FUSE_LOG_ERR,
"Spawaning %s to unumount failed",
350static int setup_auto_unmount(
const char *mountpoint,
int quiet)
357 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
361 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
363 fuse_log(FUSE_LOG_ERR,
"Setting up auto-unmountsocketpair() failed",
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);
377 snprintf(arg_fd_entry,
sizeof(arg_fd_entry),
"%i", fds[1]);
378 setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
380 char const *
const argv[] = {
389 posix_spawn_file_actions_t action;
390 posix_spawn_file_actions_init(&action);
393 posix_spawn_file_actions_addclose(&action, 1);
394 posix_spawn_file_actions_addclose(&action, 2);
396 posix_spawn_file_actions_addclose(&action, fds[1]);
402 int status = fusermount_posix_spawn(&action, argv, &pid);
404 posix_spawn_file_actions_destroy(&action);
409 fuse_log(FUSE_LOG_ERR,
"fuse: Setting up auto-unmount failed");
421static int fuse_mount_fusermount(
const char *mountpoint,
struct mount_opts *mo,
422 const char *opts,
int quiet)
429 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
433 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
435 fuse_log(FUSE_LOG_ERR,
"Running %s: socketpair() failed: %s\n",
436 FUSERMOUNT_PROG, strerror(errno));
440 char arg_fd_entry[30];
441 snprintf(arg_fd_entry,
sizeof(arg_fd_entry),
"%i", fds[0]);
442 setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
449 snprintf(arg_fd_entry,
sizeof(arg_fd_entry),
"%i", fds[1]);
450 setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
452 char const *
const argv[] = {
454 "-o", opts ? opts :
"",
461 posix_spawn_file_actions_t action;
462 posix_spawn_file_actions_init(&action);
465 posix_spawn_file_actions_addclose(&action, 1);
466 posix_spawn_file_actions_addclose(&action, 2);
468 posix_spawn_file_actions_addclose(&action, fds[1]);
470 int status = fusermount_posix_spawn(&action, argv, &pid);
472 posix_spawn_file_actions_destroy(&action);
477 fuse_log(FUSE_LOG_ERR,
"posix_spawnp() for %s failed",
478 FUSERMOUNT_PROG, strerror(errno));
485 int fd = receive_fd(fds[1]);
487 if (!mo->auto_unmount) {
491 waitpid(pid, NULL, 0);
495 fcntl(fd, F_SETFD, FD_CLOEXEC);
504static int fuse_mount_sys(
const char *mnt,
struct mount_opts *mo,
505 const char *mnt_opts)
508 const char *devname =
"/dev/fuse";
516 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
520 res = stat(mnt, &stbuf);
522 fuse_log(FUSE_LOG_ERR,
"fuse: failed to access mountpoint %s: %s\n",
523 mnt, strerror(errno));
527 fd = open(devname, O_RDWR | O_CLOEXEC);
529 if (errno == ENODEV || errno == ENOENT)
530 fuse_log(FUSE_LOG_ERR,
"fuse: device not found, try 'modprobe fuse' first\n");
532 fuse_log(FUSE_LOG_ERR,
"fuse: failed to open %s: %s\n",
533 devname, strerror(errno));
537 fcntl(fd, F_SETFD, FD_CLOEXEC);
539 snprintf(tmp,
sizeof(tmp),
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
540 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
546 source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
547 (mo->subtype ? strlen(mo->subtype) : 0) +
548 strlen(devname) + 32);
550 type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
551 if (!type || !source) {
552 fuse_log(FUSE_LOG_ERR,
"fuse: failed to allocate memory\n");
556 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
559 strcat(type, mo->subtype);
562 mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
564 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
565 if (res == -1 && errno == ENODEV && mo->subtype) {
567 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
570 sprintf(source,
"%s#%s", mo->subtype,
573 strcpy(source, type);
575 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
582 if (errno == EPERM) {
585 int errno_save = errno;
586 if (mo->blkdev && errno == ENODEV &&
587 !fuse_mnt_check_fuseblk())
589 "fuse: 'fuseblk' support missing\n");
591 fuse_log(FUSE_LOG_ERR,
"fuse: mount failed: %s\n",
592 strerror(errno_save));
599 if (geteuid() == 0) {
600 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
605 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
626static int get_mnt_flag_opts(
char **mnt_optsp,
int flags)
633 for (i = 0; mount_flags[i].opt != NULL; i++) {
634 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
641struct mount_opts *parse_mount_opts(
struct fuse_args *args)
643 struct mount_opts *mo;
645 mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
649 memset(mo, 0,
sizeof(
struct mount_opts));
650 mo->flags = MS_NOSUID | MS_NODEV;
653 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
659 destroy_mount_opts(mo);
663void destroy_mount_opts(
struct mount_opts *mo)
667 free(mo->fusermount_opts);
668 free(mo->subtype_opt);
669 free(mo->kernel_opts);
675int fuse_kern_mount(
const char *mountpoint,
struct mount_opts *mo)
678 char *mnt_opts = NULL;
681 if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
688 res = fuse_mount_sys(mountpoint, mo, mnt_opts);
689 if (res >= 0 && mo->auto_unmount) {
690 if(0 > setup_auto_unmount(mountpoint, 0)) {
692 umount2(mountpoint, MNT_DETACH);
695 }
else if (res == -2) {
696 if (mo->fusermount_opts &&
701 char *tmp_opts = NULL;
710 res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
713 res = fuse_mount_fusermount(mountpoint, mo,
716 res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
void fuse_log(enum fuse_log_level level, const char *fmt,...)
#define FUSE_OPT_KEY(templ, key)
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
int fuse_opt_add_opt(char **opts, const char *opt)