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),
126 static void exec_fusermount(
const char *argv[])
128 execv(FUSERMOUNT_DIR
"/" FUSERMOUNT_PROG, (
char **) argv);
129 execvp(FUSERMOUNT_PROG, (
char **) argv);
132 void fuse_mount_version(
void)
136 const char *argv[] = { FUSERMOUNT_PROG,
"--version", NULL };
137 exec_fusermount(argv);
139 }
else if (pid != -1)
140 waitpid(pid, NULL, 0);
149 static const struct mount_flags mount_flags[] = {
150 {
"rw", MS_RDONLY, 0},
151 {
"ro", MS_RDONLY, 1},
152 {
"suid", MS_NOSUID, 0},
153 {
"nosuid", MS_NOSUID, 1},
154 {
"dev", MS_NODEV, 0},
155 {
"nodev", MS_NODEV, 1},
156 {
"exec", MS_NOEXEC, 0},
157 {
"noexec", MS_NOEXEC, 1},
158 {
"async", MS_SYNCHRONOUS, 0},
159 {
"sync", MS_SYNCHRONOUS, 1},
160 {
"atime", MS_NOATIME, 0},
161 {
"noatime", MS_NOATIME, 1},
162 {
"diratime", MS_NODIRATIME, 0},
163 {
"nodiratime", MS_NODIRATIME, 1},
164 {
"lazytime", MS_LAZYTIME, 1},
165 {
"nolazytime", MS_LAZYTIME, 0},
166 {
"relatime", MS_RELATIME, 1},
167 {
"norelatime", MS_RELATIME, 0},
168 {
"strictatime", MS_STRICTATIME, 1},
169 {
"nostrictatime", MS_STRICTATIME, 0},
171 {
"dirsync", MS_DIRSYNC, 1},
176 unsigned get_max_read(
struct mount_opts *o)
181 static void set_mount_flag(
const char *s,
int *flags)
185 for (i = 0; mount_flags[i].opt != NULL; i++) {
186 const char *opt = mount_flags[i].opt;
187 if (strcmp(opt, s) == 0) {
188 if (mount_flags[i].on)
189 *flags |= mount_flags[i].flag;
191 *flags &= ~mount_flags[i].flag;
195 fuse_log(FUSE_LOG_ERR,
"fuse: internal error, can't find mount flag\n");
199 static int fuse_mount_opt_proc(
void *data,
const char *arg,
int key,
203 struct mount_opts *mo = data;
210 set_mount_flag(arg, &mo->flags);
216 case KEY_FUSERMOUNT_OPT:
219 case KEY_SUBTYPE_OPT:
234 static int receive_fd(
int fd)
240 size_t ccmsg[CMSG_SPACE(
sizeof(
int)) /
sizeof(size_t)];
241 struct cmsghdr *cmsg;
246 memset(&msg, 0,
sizeof(msg));
253 msg.msg_control = ccmsg;
254 msg.msg_controllen =
sizeof(ccmsg);
256 while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
266 cmsg = CMSG_FIRSTHDR(&msg);
267 if (cmsg->cmsg_type != SCM_RIGHTS) {
268 fuse_log(FUSE_LOG_ERR,
"got control message of unknown type %d\n",
272 return *(
int*)CMSG_DATA(cmsg);
275 void fuse_kern_unmount(
const char *mountpoint,
int fd)
285 res = poll(&pfd, 1, 0);
297 if (res == 1 && (pfd.revents & POLLERR))
301 if (geteuid() == 0) {
302 fuse_mnt_umount(
"fuse", mountpoint, mountpoint, 1);
306 res = umount2(mountpoint, 2);
315 const char *argv[] = { FUSERMOUNT_PROG,
"-u",
"-q",
"-z",
316 "--", mountpoint, NULL };
318 exec_fusermount(argv);
321 waitpid(pid, NULL, 0);
324 static int fuse_mount_fusermount(
const char *mountpoint,
struct mount_opts *mo,
325 const char *opts,
int quiet)
332 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
336 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
338 perror(
"fuse: socketpair() failed");
344 perror(
"fuse: fork() failed");
352 const char *argv[32];
356 int fd = open(
"/dev/null", O_RDONLY);
363 argv[a++] = FUSERMOUNT_PROG;
369 argv[a++] = mountpoint;
373 fcntl(fds[0], F_SETFD, 0);
374 snprintf(env,
sizeof(env),
"%i", fds[0]);
375 setenv(FUSE_COMMFD_ENV, env, 1);
376 exec_fusermount(argv);
377 perror(
"fuse: failed to exec fusermount3");
382 rv = receive_fd(fds[1]);
384 if (!mo->auto_unmount) {
388 waitpid(pid, NULL, 0);
392 fcntl(rv, F_SETFD, FD_CLOEXEC);
401 static int fuse_mount_sys(
const char *mnt,
struct mount_opts *mo,
402 const char *mnt_opts)
405 const char *devname =
"/dev/fuse";
413 fuse_log(FUSE_LOG_ERR,
"fuse: missing mountpoint parameter\n");
417 res = stat(mnt, &stbuf);
419 fuse_log(FUSE_LOG_ERR,
"fuse: failed to access mountpoint %s: %s\n",
420 mnt, strerror(errno));
424 if (mo->auto_unmount) {
430 fd = open(devname, O_RDWR | O_CLOEXEC);
432 if (errno == ENODEV || errno == ENOENT)
433 fuse_log(FUSE_LOG_ERR,
"fuse: device not found, try 'modprobe fuse' first\n");
435 fuse_log(FUSE_LOG_ERR,
"fuse: failed to open %s: %s\n",
436 devname, strerror(errno));
440 fcntl(fd, F_SETFD, FD_CLOEXEC);
442 snprintf(tmp,
sizeof(tmp),
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
443 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
449 source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
450 (mo->subtype ? strlen(mo->subtype) : 0) +
451 strlen(devname) + 32);
453 type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
454 if (!type || !source) {
455 fuse_log(FUSE_LOG_ERR,
"fuse: failed to allocate memory\n");
459 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
462 strcat(type, mo->subtype);
465 mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
467 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
468 if (res == -1 && errno == ENODEV && mo->subtype) {
470 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
473 sprintf(source,
"%s#%s", mo->subtype,
476 strcpy(source, type);
478 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
485 if (errno == EPERM) {
488 int errno_save = errno;
489 if (mo->blkdev && errno == ENODEV &&
490 !fuse_mnt_check_fuseblk())
492 "fuse: 'fuseblk' support missing\n");
494 fuse_log(FUSE_LOG_ERR,
"fuse: mount failed: %s\n",
495 strerror(errno_save));
502 if (geteuid() == 0) {
503 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
508 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
529 static int get_mnt_flag_opts(
char **mnt_optsp,
int flags)
536 for (i = 0; mount_flags[i].opt != NULL; i++) {
537 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
544 struct mount_opts *parse_mount_opts(
struct fuse_args *args)
546 struct mount_opts *mo;
548 mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
552 memset(mo, 0,
sizeof(
struct mount_opts));
553 mo->flags = MS_NOSUID | MS_NODEV;
556 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
562 destroy_mount_opts(mo);
566 void destroy_mount_opts(
struct mount_opts *mo)
570 free(mo->fusermount_opts);
571 free(mo->subtype_opt);
572 free(mo->kernel_opts);
578 int fuse_kern_mount(
const char *mountpoint,
struct mount_opts *mo)
581 char *mnt_opts = NULL;
584 if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
591 res = fuse_mount_sys(mountpoint, mo, mnt_opts);
593 if (mo->fusermount_opts &&
598 char *tmp_opts = NULL;
607 res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
610 res = fuse_mount_fusermount(mountpoint, mo,
613 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)