2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB.
12 #include "mount_util.h"
22 #include <sys/socket.h>
25 #include <sys/mount.h>
29 #define FUSERMOUNT_PROG "fusermount"
30 #define FUSE_COMMFD_ENV "_FUSE_COMMFD"
32 #ifndef FUSERMOUNT_DIR
33 #define FUSERMOUNT_DIR "/usr"
34 #endif /* FUSERMOUNT_DIR */
37 #define fork() vfork()
40 #endif /* __SOLARIS__ */
43 #define MS_DIRSYNC 128
74 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
[] = {
82 FUSE_MOUNT_OPT("allow_other", allow_other
),
83 FUSE_MOUNT_OPT("allow_root", allow_root
),
84 FUSE_MOUNT_OPT("nonempty", nonempty
),
85 FUSE_MOUNT_OPT("blkdev", blkdev
),
86 FUSE_MOUNT_OPT("fsname=%s", fsname
),
87 FUSE_MOUNT_OPT("subtype=%s", subtype
),
88 FUSE_OPT_KEY("allow_other", KEY_KERN_OPT
),
89 FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT
),
90 FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT
),
91 FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT
),
92 FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT
),
93 FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT
),
94 FUSE_OPT_KEY("large_read", KEY_KERN_OPT
),
95 FUSE_OPT_KEY("blksize=", KEY_KERN_OPT
),
96 FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT
),
97 FUSE_OPT_KEY("max_read=", KEY_KERN_OPT
),
98 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP
),
99 FUSE_OPT_KEY("user=", KEY_MTAB_OPT
),
100 FUSE_OPT_KEY("-r", KEY_RO
),
101 FUSE_OPT_KEY("ro", KEY_KERN_FLAG
),
102 FUSE_OPT_KEY("rw", KEY_KERN_FLAG
),
103 FUSE_OPT_KEY("suid", KEY_KERN_FLAG
),
104 FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG
),
105 FUSE_OPT_KEY("-g", KEY_KERN_FLAG
),
106 FUSE_OPT_KEY("-m", KEY_KERN_FLAG
),
107 FUSE_OPT_KEY("-O", KEY_KERN_FLAG
),
108 FUSE_OPT_KEY("setuid", KEY_KERN_OPT
),
109 FUSE_OPT_KEY("nosetuid", KEY_KERN_OPT
),
110 FUSE_OPT_KEY("devices", KEY_KERN_OPT
),
111 FUSE_OPT_KEY("nodevices", KEY_KERN_OPT
),
112 FUSE_OPT_KEY("exec", KEY_KERN_OPT
),
113 FUSE_OPT_KEY("noexec", KEY_KERN_OPT
),
114 FUSE_OPT_KEY("nbmand", KEY_KERN_OPT
),
115 FUSE_OPT_KEY("nonbmand", KEY_KERN_OPT
),
116 #else /* __SOLARIS__ */
117 FUSE_MOUNT_OPT("allow_other", allow_other
),
118 FUSE_MOUNT_OPT("allow_root", allow_root
),
119 FUSE_MOUNT_OPT("blkdev", blkdev
),
120 FUSE_MOUNT_OPT("fsname=%s", fsname
),
121 FUSE_OPT_KEY("allow_other", KEY_KERN_OPT
),
122 FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT
),
123 FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT
),
124 FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT
),
125 FUSE_OPT_KEY("large_read", KEY_KERN_OPT
),
126 FUSE_OPT_KEY("blksize=", KEY_KERN_OPT
),
127 FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT
),
128 FUSE_OPT_KEY("context=", KEY_KERN_OPT
),
129 FUSE_OPT_KEY("max_read=", KEY_KERN_OPT
),
130 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP
),
131 FUSE_OPT_KEY("user=", KEY_MTAB_OPT
),
132 FUSE_OPT_KEY("-r", KEY_RO
),
133 FUSE_OPT_KEY("ro", KEY_KERN_FLAG
),
134 FUSE_OPT_KEY("rw", KEY_KERN_FLAG
),
135 FUSE_OPT_KEY("suid", KEY_KERN_FLAG
),
136 FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG
),
137 FUSE_OPT_KEY("dev", KEY_KERN_FLAG
),
138 FUSE_OPT_KEY("nodev", KEY_KERN_FLAG
),
139 FUSE_OPT_KEY("exec", KEY_KERN_FLAG
),
140 FUSE_OPT_KEY("noexec", KEY_KERN_FLAG
),
141 FUSE_OPT_KEY("async", KEY_KERN_FLAG
),
142 FUSE_OPT_KEY("sync", KEY_KERN_FLAG
),
143 FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG
),
144 FUSE_OPT_KEY("atime", KEY_KERN_FLAG
),
145 FUSE_OPT_KEY("noatime", KEY_KERN_FLAG
),
146 #endif /* __SOLARIS__ */
147 FUSE_OPT_KEY("-h", KEY_HELP
),
148 FUSE_OPT_KEY("--help", KEY_HELP
),
149 FUSE_OPT_KEY("-V", KEY_VERSION
),
150 FUSE_OPT_KEY("--version", KEY_VERSION
),
156 static void mount_help(void)
159 " -o allow_other allow access to other users\n"
160 " -o allow_root allow access to root\n"
161 " -o nonempty allow mounts over non-empty file/dir\n"
162 " -o default_permissions enable permission checking by kernel\n"
163 " -o fsname=NAME set filesystem name\n"
164 " -o subtype=NAME set filesystem type\n"
165 " -o large_read issue large read requests (2.4 only)\n"
166 " -o max_read=N set maximum size of read requests\n"
171 static void exec_fusermount(const char *argv
[])
173 execv(FUSERMOUNT_DIR
"/" FUSERMOUNT_PROG
, (char **) argv
);
174 execvp(FUSERMOUNT_PROG
, (char **) argv
);
177 static void mount_version(void)
181 const char *argv
[] = { FUSERMOUNT_PROG
, "--version", NULL
};
182 exec_fusermount(argv
);
184 } else if (pid
!= -1)
185 waitpid(pid
, NULL
, 0);
188 #endif /* __SOLARIS__ */
196 static struct mount_flags mount_flags
[] = {
197 {"rw", MS_RDONLY
, 0},
198 {"ro", MS_RDONLY
, 1},
199 {"suid", MS_NOSUID
, 0},
200 {"nosuid", MS_NOSUID
, 1},
202 {"dev", MS_NODEV
, 0},
203 {"nodev", MS_NODEV
, 1},
204 {"exec", MS_NOEXEC
, 0},
205 {"noexec", MS_NOEXEC
, 1},
206 {"async", MS_SYNCHRONOUS
, 0},
207 {"sync", MS_SYNCHRONOUS
, 1},
208 {"atime", MS_NOATIME
, 0},
209 {"noatime", MS_NOATIME
, 1},
210 {"dirsync", MS_DIRSYNC
, 1},
211 #else /* __SOLARIS__ */
212 {"-g", MS_GLOBAL
, 1}, /* 1eaf4 */
213 {"-m", MS_NOMNTTAB
, 1}, /* 1eb00 */
214 {"-O", MS_OVERLAY
, 1}, /* 1eb0c */
215 #endif /* __SOLARIS__ */
222 * See comments in fuse_kern_mount()
224 struct solaris_mount_opts
{
232 #define SOLARIS_MOUNT_OPT(t, p, n) \
233 { t, offsetof(struct solaris_mount_opts, p), n }
234 static const struct fuse_opt solaris_mnt_opts
[] = {
235 SOLARIS_MOUNT_OPT("suid", setuid
, 1),
236 SOLARIS_MOUNT_OPT("suid", devices
, 1),
237 SOLARIS_MOUNT_OPT("nosuid", nosuid
, 1),
238 SOLARIS_MOUNT_OPT("setuid", setuid
, 1),
239 SOLARIS_MOUNT_OPT("nosetuid", nosetuid
, 1),
240 SOLARIS_MOUNT_OPT("devices", devices
, 1),
241 SOLARIS_MOUNT_OPT("nodevices", nodevices
, 1),
245 #endif /* __SOLARIS__ */
247 static void set_mount_flag(const char *s
, int *flags
)
251 for (i
= 0; mount_flags
[i
].opt
!= NULL
; i
++) {
252 const char *opt
= mount_flags
[i
].opt
;
253 if (strcmp(opt
, s
) == 0) {
254 if (mount_flags
[i
].on
)
255 *flags
|= mount_flags
[i
].flag
;
257 *flags
&= ~mount_flags
[i
].flag
;
261 fprintf(stderr
, "fuse: internal error, can't find mount flag\n");
265 static int fuse_mount_opt_proc(void *data
, const char *arg
, int key
,
266 struct fuse_args
*outargs
)
268 struct mount_opts
*mo
= data
;
272 if (fuse_opt_add_opt(&mo
->kernel_opts
, "allow_other") == -1 ||
273 fuse_opt_add_arg(outargs
, "-oallow_root") == -1)
281 set_mount_flag(arg
, &mo
->flags
);
285 return fuse_opt_add_opt(&mo
->kernel_opts
, arg
);
287 case KEY_FUSERMOUNT_OPT
:
288 return fuse_opt_add_opt(&mo
->fusermount_opts
, arg
);
291 case KEY_SUBTYPE_OPT
:
292 return fuse_opt_add_opt(&mo
->subtype_opt
, arg
);
293 #endif /* __SOLARIS__ */
296 return fuse_opt_add_opt(&mo
->mtab_opts
, arg
);
301 #endif /* __SOLARIS__ */
308 #endif /* __SOLARIS__ */
321 static int receive_fd(int fd
)
327 size_t ccmsg
[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
328 struct cmsghdr
*cmsg
;
337 /* old BSD implementations should use msg_accrights instead of
338 * msg_control; the interface is different. */
339 msg
.msg_control
= ccmsg
;
340 msg
.msg_controllen
= sizeof(ccmsg
);
342 while(((rv
= recvmsg(fd
, &msg
, 0)) == -1) && errno
== EINTR
);
352 cmsg
= CMSG_FIRSTHDR(&msg
);
353 if (!cmsg
->cmsg_type
== SCM_RIGHTS
) {
354 fprintf(stderr
, "got control message of unknown type %d\n",
358 return *(int*)CMSG_DATA(cmsg
);
361 #endif /* __SOLARIS__ */
363 void fuse_kern_unmount(const char *mountpoint
, int fd
)
368 #endif /* __SOLARIS__ */
378 res
= poll(&pfd
, 1, 0);
379 /* If file poll returns POLLERR on the device file descriptor,
380 then the filesystem is already unmounted */
381 if (res
== 1 && (pfd
.revents
& POLLERR
))
387 fusermount(1, 0, 1, "", mountpoint
);
388 #else /* __SOLARIS__ */
389 if (geteuid() == 0) {
390 fuse_mnt_umount("fuse", mountpoint
, 1);
394 res
= umount2(mountpoint
, 2);
404 { FUSERMOUNT_PROG
, "-u", "-q", "-z", "--", mountpoint
, NULL
};
406 exec_fusermount(argv
);
409 waitpid(pid
, NULL
, 0);
410 #endif /* __SOLARIS__ */
415 static int fuse_mount_fusermount(const char *mountpoint
, const char *opts
,
423 fprintf(stderr
, "fuse: missing mountpoint\n");
427 res
= socketpair(PF_UNIX
, SOCK_STREAM
, 0, fds
);
429 perror("fuse: socketpair() failed");
435 perror("fuse: fork() failed");
443 const char *argv
[32];
447 int fd
= open("/dev/null", O_RDONLY
);
452 argv
[a
++] = FUSERMOUNT_PROG
;
458 argv
[a
++] = mountpoint
;
462 fcntl(fds
[0], F_SETFD
, 0);
463 snprintf(env
, sizeof(env
), "%i", fds
[0]);
464 setenv(FUSE_COMMFD_ENV
, env
, 1);
465 exec_fusermount(argv
);
466 perror("fuse: failed to exec fusermount");
471 rv
= receive_fd(fds
[1]);
473 waitpid(pid
, NULL
, 0); /* bury zombie */
478 static int fuse_mount_sys(const char *mnt
, struct mount_opts
*mo
,
479 const char *mnt_opts
)
482 const char *devname
= "/dev/fuse";
490 fprintf(stderr
, "fuse: missing mountpoint\n");
494 res
= lstat(mnt
, &stbuf
);
496 fprintf(stderr
,"fuse: failed to access mountpoint %s: %s\n",
497 mnt
, strerror(errno
));
502 res
= fuse_mnt_check_empty("fuse", mnt
, stbuf
.st_mode
, stbuf
.st_size
);
507 fd
= open(devname
, O_RDWR
);
509 if (errno
== ENODEV
|| errno
== ENOENT
)
511 "fuse: device not found, try 'modprobe fuse' first\n");
513 fprintf(stderr
, "fuse: failed to open %s: %s\n", devname
,
518 snprintf(tmp
, sizeof(tmp
), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd
,
519 stbuf
.st_mode
& S_IFMT
, getuid(), getgid());
521 res
= fuse_opt_add_opt(&mo
->kernel_opts
, tmp
);
525 source
= malloc((mo
->fsname
? strlen(mo
->fsname
) : 0) +
526 (mo
->subtype
? strlen(mo
->subtype
) : 0) +
527 strlen(devname
) + 32);
529 type
= malloc((mo
->subtype
? strlen(mo
->subtype
) : 0) + 32);
530 if (!type
|| !source
) {
531 fprintf(stderr
, "fuse: failed to allocate memory\n");
535 strcpy(type
, mo
->blkdev
? "fuseblk" : "fuse");
538 strcat(type
, mo
->subtype
);
541 mo
->fsname
? mo
->fsname
: (mo
->subtype
? mo
->subtype
: devname
));
543 /* JPA added two final zeroes */
544 res
= mount(source
, mnt
, MS_OPTIONSTR
|mo
->flags
, type
, NULL
, 0,
545 mo
->kernel_opts
, MAX_MNTOPT_STR
, 0, 0);
547 if (res
== -1 && errno
== EINVAL
&& mo
->subtype
) {
548 /* Probably missing subtype support */
549 strcpy(type
, mo
->blkdev
? "fuseblk" : "fuse");
552 sprintf(source
, "%s#%s", mo
->subtype
, mo
->fsname
);
554 strcpy(source
, type
);
556 /* JPA two null args added */
557 res
= mount(source
, mnt
, MS_OPTIONSTR
|mo
->flags
, type
, NULL
, 0,
558 mo
->kernel_opts
, MAX_MNTOPT_STR
, 0, 0);
562 * Maybe kernel doesn't support unprivileged mounts, in this
563 * case try falling back to fusermount
565 if (errno
== EPERM
) {
568 int errno_save
= errno
;
569 if (mo
->blkdev
&& errno
== ENODEV
&& !fuse_mnt_check_fuseblk())
570 fprintf(stderr
, "fuse: 'fuseblk' support missing\n");
572 fprintf(stderr
, "fuse: mount failed: %s\n",
573 strerror(errno_save
));
582 umount2(mnt
, 2); /* lazy umount */
590 #endif /* __SOLARIS__ */
592 static int get_mnt_flag_opts(char **mnt_optsp
, int flags
)
596 if (!(flags
& MS_RDONLY
) && fuse_opt_add_opt(mnt_optsp
, "rw") == -1)
599 for (i
= 0; mount_flags
[i
].opt
!= NULL
; i
++) {
600 if (mount_flags
[i
].on
&& (flags
& mount_flags
[i
].flag
) &&
601 fuse_opt_add_opt(mnt_optsp
, mount_flags
[i
].opt
) == -1)
607 int fuse_kern_mount(const char *mountpoint
, struct fuse_args
*args
)
609 struct mount_opts mo
;
611 char *mnt_opts
= NULL
;
613 struct solaris_mount_opts smo
;
614 struct fuse_args sa
= FUSE_ARGS_INIT(0, NULL
);
615 #endif /* __SOLARIS__ */
617 memset(&mo
, 0, sizeof(mo
));
620 mo
.flags
= MS_NOSUID
| MS_NODEV
;
621 #else /* __SOLARIS__ */
623 memset(&smo
, 0, sizeof(smo
));
625 while (args
->argv
[sa
.argc
] != NULL
)
626 fuse_opt_add_arg(&sa
, args
->argv
[sa
.argc
]);
628 #endif /* __SOLARIS__ */
631 fuse_opt_parse(args
, &mo
, fuse_mount_opts
, fuse_mount_opt_proc
) == -1)
634 #else /* __SOLARIS__ */
635 goto out
; /* if SOLARIS, clean up 'sa' */
638 * In Solaris, nosuid is equivalent to nosetuid + nodevices. We only
639 * have MS_NOSUID for mount flags (no MS_(NO)SETUID, etc.). But if
640 * we set that as a default, it restricts specifying just nosetuid
641 * or nodevices; there is no way for the user to specify setuid +
642 * nodevices or vice-verse. So we parse the existing options, then
643 * add restrictive defaults if needed.
645 if (fuse_opt_parse(&sa
, &smo
, solaris_mnt_opts
, NULL
) == -1)
647 if (smo
.nosuid
|| (!smo
.nodevices
&& !smo
.devices
648 && !smo
.nosetuid
&& !smo
.setuid
)) {
649 mo
.flags
|= MS_NOSUID
;
652 * Defaults; if neither nodevices|devices,nosetuid|setuid has
653 * been specified, add the default negative option string. If
654 * both have been specified (i.e., -osuid,nosuid), leave them
655 * alone; the last option will have precedence.
657 if (!smo
.nodevices
&& !smo
.devices
)
658 if (fuse_opt_add_opt(&mo
.kernel_opts
, "nodevices") == -1)
660 if (!smo
.nosetuid
&& !smo
.setuid
)
661 if (fuse_opt_add_opt(&mo
.kernel_opts
, "nosetuid") == -1)
664 #endif /* __SOLARIS__ */
666 if (mo
.allow_other
&& mo
.allow_root
) {
667 fprintf(stderr
, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
675 if (get_mnt_flag_opts(&mnt_opts
, mo
.flags
) == -1)
678 if (!(mo
.flags
& MS_NODEV
) && fuse_opt_add_opt(&mnt_opts
, "dev") == -1)
680 if (!(mo
.flags
& MS_NOSUID
) && fuse_opt_add_opt(&mnt_opts
, "suid") == -1)
682 if (mo
.kernel_opts
&& fuse_opt_add_opt(&mnt_opts
, mo
.kernel_opts
) == -1)
684 if (mo
.mtab_opts
&& fuse_opt_add_opt(&mnt_opts
, mo
.mtab_opts
) == -1)
686 if (mo
.fusermount_opts
&& fuse_opt_add_opt(&mnt_opts
, mo
.fusermount_opts
) < 0)
688 res
= fusermount(0, 0, 0, mnt_opts
? mnt_opts
: "", mountpoint
);
689 #else /* __SOLARIS__ */
690 if (mo
.kernel_opts
&& fuse_opt_add_opt(&mnt_opts
, mo
.kernel_opts
) == -1)
692 if (mo
.mtab_opts
&& fuse_opt_add_opt(&mnt_opts
, mo
.mtab_opts
) == -1)
694 res
= fuse_mount_sys(mountpoint
, &mo
, mnt_opts
);
696 if (mo
.fusermount_opts
&&
697 fuse_opt_add_opt(&mnt_opts
, mo
.fusermount_opts
) == -1)
701 char *tmp_opts
= NULL
;
704 if (fuse_opt_add_opt(&tmp_opts
, mnt_opts
) == -1 ||
705 fuse_opt_add_opt(&tmp_opts
, mo
.subtype_opt
) == -1) {
710 res
= fuse_mount_fusermount(mountpoint
, tmp_opts
, 1);
713 res
= fuse_mount_fusermount(mountpoint
, mnt_opts
, 0);
715 res
= fuse_mount_fusermount(mountpoint
, mnt_opts
, 0);
718 #endif /* __SOLARIS__ */
723 fuse_opt_free_args(&sa
);
725 free(mo
.subtype_opt
);
726 #endif /* __SOLARIS__ */
728 free(mo
.fusermount_opts
);
729 free(mo
.kernel_opts
);