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),
117 static void exec_fusermount(
const char *argv[])
119 execv(FUSERMOUNT_DIR
"/" FUSERMOUNT_PROG, (
char **) argv);
120 execvp(FUSERMOUNT_PROG, (
char **) argv);
123 void fuse_mount_version(
void)
127 const char *argv[] = { FUSERMOUNT_PROG,
"--version", NULL };
128 exec_fusermount(argv);
130 }
else if (pid != -1)
131 waitpid(pid, NULL, 0);
140 static const struct mount_flags mount_flags[] = {
141 {
"rw", MS_RDONLY, 0},
142 {
"ro", MS_RDONLY, 1},
143 {
"suid", MS_NOSUID, 0},
144 {
"nosuid", MS_NOSUID, 1},
145 {
"dev", MS_NODEV, 0},
146 {
"nodev", MS_NODEV, 1},
147 {
"exec", MS_NOEXEC, 0},
148 {
"noexec", MS_NOEXEC, 1},
149 {
"async", MS_SYNCHRONOUS, 0},
150 {
"sync", MS_SYNCHRONOUS, 1},
151 {
"atime", MS_NOATIME, 0},
152 {
"noatime", MS_NOATIME, 1},
154 {
"dirsync", MS_DIRSYNC, 1},
159 unsigned get_max_read(
struct mount_opts *o)
164 static void set_mount_flag(
const char *s,
int *flags)
168 for (i = 0; mount_flags[i].opt != NULL; i++) {
169 const char *opt = mount_flags[i].opt;
170 if (strcmp(opt, s) == 0) {
171 if (mount_flags[i].on)
172 *flags |= mount_flags[i].flag;
174 *flags &= ~mount_flags[i].flag;
178 fprintf(stderr,
"fuse: internal error, can't find mount flag\n");
182 static int fuse_mount_opt_proc(
void *data,
const char *arg,
int key,
186 struct mount_opts *mo = data;
193 set_mount_flag(arg, &mo->flags);
199 case KEY_FUSERMOUNT_OPT:
202 case KEY_SUBTYPE_OPT:
217 static int receive_fd(
int fd)
223 size_t ccmsg[CMSG_SPACE(
sizeof(
int)) /
sizeof(size_t)];
224 struct cmsghdr *cmsg;
229 memset(&msg, 0,
sizeof(msg));
236 msg.msg_control = ccmsg;
237 msg.msg_controllen =
sizeof(ccmsg);
239 while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
249 cmsg = CMSG_FIRSTHDR(&msg);
250 if (cmsg->cmsg_type != SCM_RIGHTS) {
251 fprintf(stderr,
"got control message of unknown type %d\n",
255 return *(
int*)CMSG_DATA(cmsg);
258 void fuse_kern_unmount(
const char *mountpoint,
int fd)
268 res = poll(&pfd, 1, 0);
280 if (res == 1 && (pfd.revents & POLLERR))
284 if (geteuid() == 0) {
285 fuse_mnt_umount(
"fuse", mountpoint, mountpoint, 1);
289 res = umount2(mountpoint, 2);
298 const char *argv[] = { FUSERMOUNT_PROG,
"-u",
"-q",
"-z",
299 "--", mountpoint, NULL };
301 exec_fusermount(argv);
304 waitpid(pid, NULL, 0);
307 static int fuse_mount_fusermount(
const char *mountpoint,
struct mount_opts *mo,
308 const char *opts,
int quiet)
315 fprintf(stderr,
"fuse: missing mountpoint parameter\n");
319 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
321 perror(
"fuse: socketpair() failed");
327 perror(
"fuse: fork() failed");
335 const char *argv[32];
339 int fd = open(
"/dev/null", O_RDONLY);
346 argv[a++] = FUSERMOUNT_PROG;
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");
365 rv = receive_fd(fds[1]);
367 if (!mo->auto_unmount) {
371 waitpid(pid, NULL, 0);
375 fcntl(rv, F_SETFD, FD_CLOEXEC);
384 static int fuse_mount_sys(
const char *mnt,
struct mount_opts *mo,
385 const char *mnt_opts)
388 const char *devname =
"/dev/fuse";
396 fprintf(stderr,
"fuse: missing mountpoint parameter\n");
400 res = stat(mnt, &stbuf);
402 fprintf(stderr ,
"fuse: failed to access mountpoint %s: %s\n",
403 mnt, strerror(errno));
407 if (mo->auto_unmount) {
413 fd = open(devname, O_RDWR | O_CLOEXEC);
415 if (errno == ENODEV || errno == ENOENT)
416 fprintf(stderr,
"fuse: device not found, try 'modprobe fuse' first\n");
418 fprintf(stderr,
"fuse: failed to open %s: %s\n",
419 devname, strerror(errno));
423 fcntl(fd, F_SETFD, FD_CLOEXEC);
425 snprintf(tmp,
sizeof(tmp),
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
426 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
432 source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
433 (mo->subtype ? strlen(mo->subtype) : 0) +
434 strlen(devname) + 32);
436 type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
437 if (!type || !source) {
438 fprintf(stderr,
"fuse: failed to allocate memory\n");
442 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
445 strcat(type, mo->subtype);
448 mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
450 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
451 if (res == -1 && errno == ENODEV && mo->subtype) {
453 strcpy(type, mo->blkdev ?
"fuseblk" :
"fuse");
456 sprintf(source,
"%s#%s", mo->subtype,
459 strcpy(source, type);
461 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
468 if (errno == EPERM) {
471 int errno_save = errno;
472 if (mo->blkdev && errno == ENODEV &&
473 !fuse_mnt_check_fuseblk())
475 "fuse: 'fuseblk' support missing\n");
477 fprintf(stderr,
"fuse: mount failed: %s\n",
478 strerror(errno_save));
485 if (geteuid() == 0) {
486 char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
491 res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
512 static int get_mnt_flag_opts(
char **mnt_optsp,
int flags)
519 for (i = 0; mount_flags[i].opt != NULL; i++) {
520 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
527 struct mount_opts *parse_mount_opts(
struct fuse_args *args)
529 struct mount_opts *mo;
531 mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
535 memset(mo, 0,
sizeof(
struct mount_opts));
536 mo->flags = MS_NOSUID | MS_NODEV;
539 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
545 destroy_mount_opts(mo);
549 void destroy_mount_opts(
struct mount_opts *mo)
553 free(mo->fusermount_opts);
554 free(mo->subtype_opt);
555 free(mo->kernel_opts);
561 int fuse_kern_mount(
const char *mountpoint,
struct mount_opts *mo)
564 char *mnt_opts = NULL;
567 if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
574 res = fuse_mount_sys(mountpoint, mo, mnt_opts);
576 if (mo->fusermount_opts &&
581 char *tmp_opts = NULL;
590 res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
593 res = fuse_mount_fusermount(mountpoint, mo,
596 res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
int fuse_opt_add_opt(char **opts, const char *opt)
#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)