11#include "fuse_config.h"
15#include "mount_util.h"
25#include <sys/socket.h>
29#include "fuse_mount_compat.h"
34#define MS_RDONLY MNT_RDONLY
35#define MS_NOSUID MNT_NOSUID
36#define MS_NODEV MNT_NODEV
37#define MS_NOEXEC MNT_NOEXEC
38#define MS_SYNCHRONOUS MNT_SYNCHRONOUS
39#define MS_NOATIME MNT_NOATIME
41#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
44#define FUSERMOUNT_PROG "fusermount3"
45#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
74 char *fusermount_opts;
79#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
81static const struct fuse_opt fuse_mount_opts[] = {
82 FUSE_MOUNT_OPT(
"allow_other", allow_other),
83 FUSE_MOUNT_OPT(
"blkdev", blkdev),
84 FUSE_MOUNT_OPT(
"auto_unmount", auto_unmount),
85 FUSE_MOUNT_OPT(
"fsname=%s", fsname),
86 FUSE_MOUNT_OPT(
"max_read=%u", max_read),
87 FUSE_MOUNT_OPT(
"subtype=%s", subtype),
120static void exec_fusermount(
const char *argv[])
122 execv(FUSERMOUNT_DIR
"/" FUSERMOUNT_PROG, (
char **) argv);
123 execvp(FUSERMOUNT_PROG, (
char **) argv);
126void fuse_mount_version(
void)
130 const char *argv[] = { FUSERMOUNT_PROG,
"--version", NULL };
131 exec_fusermount(argv);
133 }
else if (pid != -1)
134 waitpid(pid, NULL, 0);
143static const struct mount_flags mount_flags[] = {
144 {
"rw", MS_RDONLY, 0},
145 {
"ro", MS_RDONLY, 1},
146 {
"suid", MS_NOSUID, 0},
147 {
"nosuid", MS_NOSUID, 1},
148 {
"dev", MS_NODEV, 0},
149 {
"nodev", MS_NODEV, 1},
150 {
"exec", MS_NOEXEC, 0},
151 {
"noexec", MS_NOEXEC, 1},
152 {
"async", MS_SYNCHRONOUS, 0},
153 {
"sync", MS_SYNCHRONOUS, 1},
154 {
"noatime", MS_NOATIME, 1},
155 {
"nodiratime", MS_NODIRATIME, 1},
156 {
"norelatime", MS_RELATIME, 0},
157 {
"nostrictatime", MS_STRICTATIME, 0},
159 {
"dirsync", MS_DIRSYNC, 1},
164unsigned get_max_read(
struct mount_opts *o)
169static void set_mount_flag(
const char *s,
int *flags)
173 for (i = 0; mount_flags[i].opt != NULL; i++) {
174 const char *opt = mount_flags[i].opt;
175 if (strcmp(opt, s) == 0) {
176 if (mount_flags[i].on)
177 *flags |= mount_flags[i].flag;
179 *flags &= ~mount_flags[i].flag;
183 fuse_log(FUSE_LOG_ERR,
"fuse: internal error, can't find mount flag\n");
187static int fuse_mount_opt_proc(
void *data,
const char *arg,
int key,
191 struct mount_opts *mo = data;
198 set_mount_flag(arg, &mo->flags);
204 case KEY_FUSERMOUNT_OPT:
207 case KEY_SUBTYPE_OPT:
222static int receive_fd(
int fd)
228 size_t ccmsg[CMSG_SPACE(
sizeof(
int)) /
sizeof(size_t)];
229 struct cmsghdr *cmsg;
234 memset(&msg, 0,
sizeof(msg));
241 msg.msg_control = ccmsg;
242 msg.msg_controllen =
sizeof(ccmsg);
244 while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
254 cmsg = CMSG_FIRSTHDR(&msg);
255 if (cmsg->cmsg_type != SCM_RIGHTS) {
256 fuse_log(FUSE_LOG_ERR,
"got control message of unknown type %d\n",
260 return *(
int*)CMSG_DATA(cmsg);
263void fuse_kern_unmount(
const char *mountpoint,
int fd)
273 res = poll(&pfd, 1, 0);
285 if (res == 1 && (pfd.revents & POLLERR))
289 if (geteuid() == 0) {
290 fuse_mnt_umount(
"fuse", mountpoint, mountpoint, 1);
294 res = umount2(mountpoint, 2);
303 const char *argv[] = { FUSERMOUNT_PROG,
"-u",
"-q",
"-z",
304 "--", mountpoint, NULL };
306 exec_fusermount(argv);
309 waitpid(pid, NULL, 0);
312static int setup_auto_unmount(
const char *mountpoint,
int quiet)
318 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
322 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
324 perror(
"fuse: socketpair() failed");
330 perror(
"fuse: fork() failed");
338 const char *argv[32];
342 int fd = open(
"/dev/null", O_RDONLY);
349 argv[a++] = FUSERMOUNT_PROG;
350 argv[a++] =
"--auto-unmount";
352 argv[a++] = mountpoint;
356 fcntl(fds[0], F_SETFD, 0);
357 snprintf(env,
sizeof(env),
"%i", fds[0]);
358 setenv(FUSE_COMMFD_ENV, env, 1);
359 exec_fusermount(argv);
360 perror(
"fuse: failed to exec fusermount3");
371static int fuse_mount_fusermount(
const char *mountpoint,
struct mount_opts *mo,
372 const char *opts,
int quiet)
379 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
383 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
385 perror(
"fuse: socketpair() failed");
391 perror(
"fuse: fork() failed");
399 const char *argv[32];
403 int fd = open(
"/dev/null", O_RDONLY);
410 argv[a++] = FUSERMOUNT_PROG;
416 argv[a++] = mountpoint;
420 fcntl(fds[0], F_SETFD, 0);
421 snprintf(env,
sizeof(env),
"%i", fds[0]);
422 setenv(FUSE_COMMFD_ENV, env, 1);
423 exec_fusermount(argv);
424 perror(
"fuse: failed to exec fusermount3");
429 rv = receive_fd(fds[1]);
431 if (!mo->auto_unmount) {
435 waitpid(pid, NULL, 0);
439 fcntl(rv, F_SETFD, FD_CLOEXEC);
448static int fuse_mount_sys(
const char *mnt,
struct mount_opts *mo,
449 const char *mnt_opts)
452 const char *devname =
"/dev/fuse";
460 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
464 res = stat(mnt, &stbuf);
466 fuse_log(FUSE_LOG_ERR,
"fuse: failed to access mountpoint %s: %s\n",
467 mnt, strerror(errno));
471 fd = open(devname, O_RDWR | O_CLOEXEC);
473 if (errno == ENODEV || errno == ENOENT)
474 fuse_log(FUSE_LOG_ERR,
"fuse: device not found, try 'modprobe fuse' first\n");
476 fuse_log(FUSE_LOG_ERR,
"fuse: failed to open %s: %s\n",
477 devname, strerror(errno));
481 fcntl(fd, F_SETFD, FD_CLOEXEC);
483 snprintf(tmp,
sizeof(tmp),
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
484 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
490 source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
491 (mo->subtype ? strlen(mo->subtype) : 0) +
492 strlen(devname) + 32);
494 type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
495 if (!type || !source) {
496 fuse_log(FUSE_LOG_ERR,
"fuse: failed to allocate memory\n");
500 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
503 strcat(type, mo->subtype);
506 mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
508 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
509 if (res == -1 && errno == ENODEV && mo->subtype) {
511 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
514 sprintf(source,
"%s#%s", mo->subtype,
517 strcpy(source, type);
519 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
526 if (errno == EPERM) {
529 int errno_save = errno;
530 if (mo->blkdev && errno == ENODEV &&
531 !fuse_mnt_check_fuseblk())
533 "fuse: 'fuseblk' support missing\n");
535 fuse_log(FUSE_LOG_ERR,
"fuse: mount failed: %s\n",
536 strerror(errno_save));
543 if (geteuid() == 0) {
544 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
549 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
570static int get_mnt_flag_opts(
char **mnt_optsp,
int flags)
577 for (i = 0; mount_flags[i].opt != NULL; i++) {
578 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
585struct mount_opts *parse_mount_opts(
struct fuse_args *args)
587 struct mount_opts *mo;
589 mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
593 memset(mo, 0,
sizeof(
struct mount_opts));
594 mo->flags = MS_NOSUID | MS_NODEV;
597 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
603 destroy_mount_opts(mo);
607void destroy_mount_opts(
struct mount_opts *mo)
611 free(mo->fusermount_opts);
612 free(mo->subtype_opt);
613 free(mo->kernel_opts);
619int fuse_kern_mount(
const char *mountpoint,
struct mount_opts *mo)
622 char *mnt_opts = NULL;
625 if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
632 res = fuse_mount_sys(mountpoint, mo, mnt_opts);
633 if (res >= 0 && mo->auto_unmount) {
634 if(0 > setup_auto_unmount(mountpoint, 0)) {
636 umount2(mountpoint, MNT_DETACH);
639 }
else if (res == -2) {
640 if (mo->fusermount_opts &&
645 char *tmp_opts = NULL;
654 res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
657 res = fuse_mount_fusermount(mountpoint, mo,
660 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)