11 #include "fuse_config.h"
13 #include "fuse_misc.h"
15 #include "mount_util.h"
25 #include <sys/socket.h>
28 #include <sys/mount.h>
33 #define MS_RDONLY MNT_RDONLY
34 #define MS_NOSUID MNT_NOSUID
35 #define MS_NODEV MNT_NODEV
36 #define MS_NOEXEC MNT_NOEXEC
37 #define MS_SYNCHRONOUS MNT_SYNCHRONOUS
38 #define MS_NOATIME MNT_NOATIME
40 #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
43 #define FUSERMOUNT_PROG "fusermount3"
44 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
47 #define fork() vfork()
51 #define MS_DIRSYNC 128
73 char *fusermount_opts;
78 #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
80 static const struct fuse_opt fuse_mount_opts[] = {
81 FUSE_MOUNT_OPT(
"allow_other", allow_other),
82 FUSE_MOUNT_OPT(
"blkdev", blkdev),
83 FUSE_MOUNT_OPT(
"auto_unmount", auto_unmount),
84 FUSE_MOUNT_OPT(
"fsname=%s", fsname),
85 FUSE_MOUNT_OPT(
"max_read=%u", max_read),
86 FUSE_MOUNT_OPT(
"subtype=%s", subtype),
118 static void exec_fusermount(
const char *argv[])
120 execv(FUSERMOUNT_DIR
"/" FUSERMOUNT_PROG, (
char **) argv);
121 execvp(FUSERMOUNT_PROG, (
char **) argv);
124 void fuse_mount_version(
void)
128 const char *argv[] = { FUSERMOUNT_PROG,
"--version", NULL };
129 exec_fusermount(argv);
131 }
else if (pid != -1)
132 waitpid(pid, NULL, 0);
141 static const struct mount_flags mount_flags[] = {
142 {
"rw", MS_RDONLY, 0},
143 {
"ro", MS_RDONLY, 1},
144 {
"suid", MS_NOSUID, 0},
145 {
"nosuid", MS_NOSUID, 1},
146 {
"dev", MS_NODEV, 0},
147 {
"nodev", MS_NODEV, 1},
148 {
"exec", MS_NOEXEC, 0},
149 {
"noexec", MS_NOEXEC, 1},
150 {
"async", MS_SYNCHRONOUS, 0},
151 {
"sync", MS_SYNCHRONOUS, 1},
152 {
"atime", MS_NOATIME, 0},
153 {
"noatime", MS_NOATIME, 1},
155 {
"dirsync", MS_DIRSYNC, 1},
160 unsigned get_max_read(
struct mount_opts *o)
165 static void set_mount_flag(
const char *s,
int *flags)
169 for (i = 0; mount_flags[i].opt != NULL; i++) {
170 const char *opt = mount_flags[i].opt;
171 if (strcmp(opt, s) == 0) {
172 if (mount_flags[i].on)
173 *flags |= mount_flags[i].flag;
175 *flags &= ~mount_flags[i].flag;
179 fuse_log(FUSE_LOG_ERR,
"fuse: internal error, can't find mount flag\n");
183 static int fuse_mount_opt_proc(
void *data,
const char *arg,
int key,
187 struct mount_opts *mo = data;
194 set_mount_flag(arg, &mo->flags);
200 case KEY_FUSERMOUNT_OPT:
203 case KEY_SUBTYPE_OPT:
218 static int receive_fd(
int fd)
224 size_t ccmsg[CMSG_SPACE(
sizeof(
int)) /
sizeof(size_t)];
225 struct cmsghdr *cmsg;
230 memset(&msg, 0,
sizeof(msg));
237 msg.msg_control = ccmsg;
238 msg.msg_controllen =
sizeof(ccmsg);
240 while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
250 cmsg = CMSG_FIRSTHDR(&msg);
251 if (cmsg->cmsg_type != SCM_RIGHTS) {
252 fuse_log(FUSE_LOG_ERR,
"got control message of unknown type %d\n",
256 return *(
int*)CMSG_DATA(cmsg);
259 void fuse_kern_unmount(
const char *mountpoint,
int fd)
269 res = poll(&pfd, 1, 0);
281 if (res == 1 && (pfd.revents & POLLERR))
285 if (geteuid() == 0) {
286 fuse_mnt_umount(
"fuse", mountpoint, mountpoint, 1);
290 res = umount2(mountpoint, 2);
299 const char *argv[] = { FUSERMOUNT_PROG,
"-u",
"-q",
"-z",
300 "--", mountpoint, NULL };
302 exec_fusermount(argv);
305 waitpid(pid, NULL, 0);
308 static int fuse_mount_fusermount(
const char *mountpoint,
struct mount_opts *mo,
309 const char *opts,
int quiet)
316 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
320 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
322 perror(
"fuse: socketpair() failed");
328 perror(
"fuse: fork() failed");
336 const char *argv[32];
340 int fd = open(
"/dev/null", O_RDONLY);
347 argv[a++] = FUSERMOUNT_PROG;
353 argv[a++] = mountpoint;
357 fcntl(fds[0], F_SETFD, 0);
358 snprintf(env,
sizeof(env),
"%i", fds[0]);
359 setenv(FUSE_COMMFD_ENV, env, 1);
360 exec_fusermount(argv);
361 perror(
"fuse: failed to exec fusermount3");
366 rv = receive_fd(fds[1]);
368 if (!mo->auto_unmount) {
372 waitpid(pid, NULL, 0);
376 fcntl(rv, F_SETFD, FD_CLOEXEC);
385 static int fuse_mount_sys(
const char *mnt,
struct mount_opts *mo,
386 const char *mnt_opts)
389 const char *devname =
"/dev/fuse";
397 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
401 res = stat(mnt, &stbuf);
403 fuse_log(FUSE_LOG_ERR,
"fuse: failed to access mountpoint %s: %s\n",
404 mnt, strerror(errno));
408 if (mo->auto_unmount) {
414 fd = open(devname, O_RDWR | O_CLOEXEC);
416 if (errno == ENODEV || errno == ENOENT)
417 fuse_log(FUSE_LOG_ERR,
"fuse: device not found, try 'modprobe fuse' first\n");
419 fuse_log(FUSE_LOG_ERR,
"fuse: failed to open %s: %s\n",
420 devname, strerror(errno));
424 fcntl(fd, F_SETFD, FD_CLOEXEC);
426 snprintf(tmp,
sizeof(tmp),
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
427 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
433 source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
434 (mo->subtype ? strlen(mo->subtype) : 0) +
435 strlen(devname) + 32);
437 type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
438 if (!type || !source) {
439 fuse_log(FUSE_LOG_ERR,
"fuse: failed to allocate memory\n");
443 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
446 strcat(type, mo->subtype);
449 mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
451 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
452 if (res == -1 && errno == ENODEV && mo->subtype) {
454 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
457 sprintf(source,
"%s#%s", mo->subtype,
460 strcpy(source, type);
462 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
469 if (errno == EPERM) {
472 int errno_save = errno;
473 if (mo->blkdev && errno == ENODEV &&
474 !fuse_mnt_check_fuseblk())
476 "fuse: 'fuseblk' support missing\n");
478 fuse_log(FUSE_LOG_ERR,
"fuse: mount failed: %s\n",
479 strerror(errno_save));
486 if (geteuid() == 0) {
487 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
492 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
513 static int get_mnt_flag_opts(
char **mnt_optsp,
int flags)
520 for (i = 0; mount_flags[i].opt != NULL; i++) {
521 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
528 struct mount_opts *parse_mount_opts(
struct fuse_args *args)
530 struct mount_opts *mo;
532 mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
536 memset(mo, 0,
sizeof(
struct mount_opts));
537 mo->flags = MS_NOSUID | MS_NODEV;
540 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
546 destroy_mount_opts(mo);
550 void destroy_mount_opts(
struct mount_opts *mo)
554 free(mo->fusermount_opts);
555 free(mo->subtype_opt);
556 free(mo->kernel_opts);
562 int fuse_kern_mount(
const char *mountpoint,
struct mount_opts *mo)
565 char *mnt_opts = NULL;
568 if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
575 res = fuse_mount_sys(mountpoint, mo, mnt_opts);
577 if (mo->fusermount_opts &&
582 char *tmp_opts = NULL;
591 res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
594 res = fuse_mount_fusermount(mountpoint, mo,
597 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)