16881f68fSopenharmony_ci/* 26881f68fSopenharmony_ci FUSE: Filesystem in Userspace 36881f68fSopenharmony_ci Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 46881f68fSopenharmony_ci 56881f68fSopenharmony_ci Architecture specific file system mounting (Linux). 66881f68fSopenharmony_ci 76881f68fSopenharmony_ci This program can be distributed under the terms of the GNU LGPLv2. 86881f68fSopenharmony_ci See the file COPYING.LIB. 96881f68fSopenharmony_ci*/ 106881f68fSopenharmony_ci 116881f68fSopenharmony_ci#include "fuse_config.h" 126881f68fSopenharmony_ci#include "fuse_i.h" 136881f68fSopenharmony_ci#include "fuse_misc.h" 146881f68fSopenharmony_ci#include "fuse_opt.h" 156881f68fSopenharmony_ci#include "mount_util.h" 166881f68fSopenharmony_ci 176881f68fSopenharmony_ci#include <stdio.h> 186881f68fSopenharmony_ci#include <stdlib.h> 196881f68fSopenharmony_ci#include <unistd.h> 206881f68fSopenharmony_ci#include <stddef.h> 216881f68fSopenharmony_ci#include <string.h> 226881f68fSopenharmony_ci#include <fcntl.h> 236881f68fSopenharmony_ci#include <errno.h> 246881f68fSopenharmony_ci#include <poll.h> 256881f68fSopenharmony_ci#include <sys/socket.h> 266881f68fSopenharmony_ci#include <sys/un.h> 276881f68fSopenharmony_ci#include <sys/wait.h> 286881f68fSopenharmony_ci 296881f68fSopenharmony_ci#include "fuse_mount_compat.h" 306881f68fSopenharmony_ci 316881f68fSopenharmony_ci#ifdef __NetBSD__ 326881f68fSopenharmony_ci#include <perfuse.h> 336881f68fSopenharmony_ci 346881f68fSopenharmony_ci#define MS_RDONLY MNT_RDONLY 356881f68fSopenharmony_ci#define MS_NOSUID MNT_NOSUID 366881f68fSopenharmony_ci#define MS_NODEV MNT_NODEV 376881f68fSopenharmony_ci#define MS_NOEXEC MNT_NOEXEC 386881f68fSopenharmony_ci#define MS_SYNCHRONOUS MNT_SYNCHRONOUS 396881f68fSopenharmony_ci#define MS_NOATIME MNT_NOATIME 406881f68fSopenharmony_ci 416881f68fSopenharmony_ci#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0) 426881f68fSopenharmony_ci#endif 436881f68fSopenharmony_ci 446881f68fSopenharmony_ci#define FUSERMOUNT_PROG "fusermount3" 456881f68fSopenharmony_ci#define FUSE_COMMFD_ENV "_FUSE_COMMFD" 466881f68fSopenharmony_ci 476881f68fSopenharmony_ci#ifndef HAVE_FORK 486881f68fSopenharmony_ci#define fork() vfork() 496881f68fSopenharmony_ci#endif 506881f68fSopenharmony_ci 516881f68fSopenharmony_ci#ifndef MS_DIRSYNC 526881f68fSopenharmony_ci#define MS_DIRSYNC 128 536881f68fSopenharmony_ci#endif 546881f68fSopenharmony_ci 556881f68fSopenharmony_cienum { 566881f68fSopenharmony_ci KEY_KERN_FLAG, 576881f68fSopenharmony_ci KEY_KERN_OPT, 586881f68fSopenharmony_ci KEY_FUSERMOUNT_OPT, 596881f68fSopenharmony_ci KEY_SUBTYPE_OPT, 606881f68fSopenharmony_ci KEY_MTAB_OPT, 616881f68fSopenharmony_ci KEY_ALLOW_OTHER, 626881f68fSopenharmony_ci KEY_RO, 636881f68fSopenharmony_ci}; 646881f68fSopenharmony_ci 656881f68fSopenharmony_cistruct mount_opts { 666881f68fSopenharmony_ci int allow_other; 676881f68fSopenharmony_ci int flags; 686881f68fSopenharmony_ci int auto_unmount; 696881f68fSopenharmony_ci int blkdev; 706881f68fSopenharmony_ci char *fsname; 716881f68fSopenharmony_ci char *subtype; 726881f68fSopenharmony_ci char *subtype_opt; 736881f68fSopenharmony_ci char *mtab_opts; 746881f68fSopenharmony_ci char *fusermount_opts; 756881f68fSopenharmony_ci char *kernel_opts; 766881f68fSopenharmony_ci unsigned max_read; 776881f68fSopenharmony_ci}; 786881f68fSopenharmony_ci 796881f68fSopenharmony_ci#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } 806881f68fSopenharmony_ci 816881f68fSopenharmony_cistatic const struct fuse_opt fuse_mount_opts[] = { 826881f68fSopenharmony_ci FUSE_MOUNT_OPT("allow_other", allow_other), 836881f68fSopenharmony_ci FUSE_MOUNT_OPT("blkdev", blkdev), 846881f68fSopenharmony_ci FUSE_MOUNT_OPT("auto_unmount", auto_unmount), 856881f68fSopenharmony_ci FUSE_MOUNT_OPT("fsname=%s", fsname), 866881f68fSopenharmony_ci FUSE_MOUNT_OPT("max_read=%u", max_read), 876881f68fSopenharmony_ci FUSE_MOUNT_OPT("subtype=%s", subtype), 886881f68fSopenharmony_ci FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), 896881f68fSopenharmony_ci FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT), 906881f68fSopenharmony_ci FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), 916881f68fSopenharmony_ci FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), 926881f68fSopenharmony_ci FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), 936881f68fSopenharmony_ci FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), 946881f68fSopenharmony_ci FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), 956881f68fSopenharmony_ci FUSE_OPT_KEY("context=", KEY_KERN_OPT), 966881f68fSopenharmony_ci FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT), 976881f68fSopenharmony_ci FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT), 986881f68fSopenharmony_ci FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT), 996881f68fSopenharmony_ci FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), 1006881f68fSopenharmony_ci FUSE_OPT_KEY("user=", KEY_MTAB_OPT), 1016881f68fSopenharmony_ci FUSE_OPT_KEY("-n", KEY_MTAB_OPT), 1026881f68fSopenharmony_ci FUSE_OPT_KEY("-r", KEY_RO), 1036881f68fSopenharmony_ci FUSE_OPT_KEY("ro", KEY_KERN_FLAG), 1046881f68fSopenharmony_ci FUSE_OPT_KEY("rw", KEY_KERN_FLAG), 1056881f68fSopenharmony_ci FUSE_OPT_KEY("suid", KEY_KERN_FLAG), 1066881f68fSopenharmony_ci FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), 1076881f68fSopenharmony_ci FUSE_OPT_KEY("dev", KEY_KERN_FLAG), 1086881f68fSopenharmony_ci FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), 1096881f68fSopenharmony_ci FUSE_OPT_KEY("exec", KEY_KERN_FLAG), 1106881f68fSopenharmony_ci FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), 1116881f68fSopenharmony_ci FUSE_OPT_KEY("async", KEY_KERN_FLAG), 1126881f68fSopenharmony_ci FUSE_OPT_KEY("sync", KEY_KERN_FLAG), 1136881f68fSopenharmony_ci FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), 1146881f68fSopenharmony_ci FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), 1156881f68fSopenharmony_ci FUSE_OPT_KEY("nodiratime", KEY_KERN_FLAG), 1166881f68fSopenharmony_ci FUSE_OPT_KEY("nostrictatime", KEY_KERN_FLAG), 1176881f68fSopenharmony_ci FUSE_OPT_END 1186881f68fSopenharmony_ci}; 1196881f68fSopenharmony_ci 1206881f68fSopenharmony_cistatic void exec_fusermount(const char *argv[]) 1216881f68fSopenharmony_ci{ 1226881f68fSopenharmony_ci execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv); 1236881f68fSopenharmony_ci execvp(FUSERMOUNT_PROG, (char **) argv); 1246881f68fSopenharmony_ci} 1256881f68fSopenharmony_ci 1266881f68fSopenharmony_civoid fuse_mount_version(void) 1276881f68fSopenharmony_ci{ 1286881f68fSopenharmony_ci int pid = fork(); 1296881f68fSopenharmony_ci if (!pid) { 1306881f68fSopenharmony_ci const char *argv[] = { FUSERMOUNT_PROG, "--version", NULL }; 1316881f68fSopenharmony_ci exec_fusermount(argv); 1326881f68fSopenharmony_ci _exit(1); 1336881f68fSopenharmony_ci } else if (pid != -1) 1346881f68fSopenharmony_ci waitpid(pid, NULL, 0); 1356881f68fSopenharmony_ci} 1366881f68fSopenharmony_ci 1376881f68fSopenharmony_cistruct mount_flags { 1386881f68fSopenharmony_ci const char *opt; 1396881f68fSopenharmony_ci unsigned long flag; 1406881f68fSopenharmony_ci int on; 1416881f68fSopenharmony_ci}; 1426881f68fSopenharmony_ci 1436881f68fSopenharmony_cistatic const struct mount_flags mount_flags[] = { 1446881f68fSopenharmony_ci {"rw", MS_RDONLY, 0}, 1456881f68fSopenharmony_ci {"ro", MS_RDONLY, 1}, 1466881f68fSopenharmony_ci {"suid", MS_NOSUID, 0}, 1476881f68fSopenharmony_ci {"nosuid", MS_NOSUID, 1}, 1486881f68fSopenharmony_ci {"dev", MS_NODEV, 0}, 1496881f68fSopenharmony_ci {"nodev", MS_NODEV, 1}, 1506881f68fSopenharmony_ci {"exec", MS_NOEXEC, 0}, 1516881f68fSopenharmony_ci {"noexec", MS_NOEXEC, 1}, 1526881f68fSopenharmony_ci {"async", MS_SYNCHRONOUS, 0}, 1536881f68fSopenharmony_ci {"sync", MS_SYNCHRONOUS, 1}, 1546881f68fSopenharmony_ci {"noatime", MS_NOATIME, 1}, 1556881f68fSopenharmony_ci {"nodiratime", MS_NODIRATIME, 1}, 1566881f68fSopenharmony_ci {"norelatime", MS_RELATIME, 0}, 1576881f68fSopenharmony_ci {"nostrictatime", MS_STRICTATIME, 0}, 1586881f68fSopenharmony_ci#ifndef __NetBSD__ 1596881f68fSopenharmony_ci {"dirsync", MS_DIRSYNC, 1}, 1606881f68fSopenharmony_ci#endif 1616881f68fSopenharmony_ci {NULL, 0, 0} 1626881f68fSopenharmony_ci}; 1636881f68fSopenharmony_ci 1646881f68fSopenharmony_ciunsigned get_max_read(struct mount_opts *o) 1656881f68fSopenharmony_ci{ 1666881f68fSopenharmony_ci return o->max_read; 1676881f68fSopenharmony_ci} 1686881f68fSopenharmony_ci 1696881f68fSopenharmony_cistatic void set_mount_flag(const char *s, int *flags) 1706881f68fSopenharmony_ci{ 1716881f68fSopenharmony_ci int i; 1726881f68fSopenharmony_ci 1736881f68fSopenharmony_ci for (i = 0; mount_flags[i].opt != NULL; i++) { 1746881f68fSopenharmony_ci const char *opt = mount_flags[i].opt; 1756881f68fSopenharmony_ci if (strcmp(opt, s) == 0) { 1766881f68fSopenharmony_ci if (mount_flags[i].on) 1776881f68fSopenharmony_ci *flags |= mount_flags[i].flag; 1786881f68fSopenharmony_ci else 1796881f68fSopenharmony_ci *flags &= ~mount_flags[i].flag; 1806881f68fSopenharmony_ci return; 1816881f68fSopenharmony_ci } 1826881f68fSopenharmony_ci } 1836881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: internal error, can't find mount flag\n"); 1846881f68fSopenharmony_ci abort(); 1856881f68fSopenharmony_ci} 1866881f68fSopenharmony_ci 1876881f68fSopenharmony_cistatic int fuse_mount_opt_proc(void *data, const char *arg, int key, 1886881f68fSopenharmony_ci struct fuse_args *outargs) 1896881f68fSopenharmony_ci{ 1906881f68fSopenharmony_ci (void) outargs; 1916881f68fSopenharmony_ci struct mount_opts *mo = data; 1926881f68fSopenharmony_ci 1936881f68fSopenharmony_ci switch (key) { 1946881f68fSopenharmony_ci case KEY_RO: 1956881f68fSopenharmony_ci arg = "ro"; 1966881f68fSopenharmony_ci /* fall through */ 1976881f68fSopenharmony_ci case KEY_KERN_FLAG: 1986881f68fSopenharmony_ci set_mount_flag(arg, &mo->flags); 1996881f68fSopenharmony_ci return 0; 2006881f68fSopenharmony_ci 2016881f68fSopenharmony_ci case KEY_KERN_OPT: 2026881f68fSopenharmony_ci return fuse_opt_add_opt(&mo->kernel_opts, arg); 2036881f68fSopenharmony_ci 2046881f68fSopenharmony_ci case KEY_FUSERMOUNT_OPT: 2056881f68fSopenharmony_ci return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg); 2066881f68fSopenharmony_ci 2076881f68fSopenharmony_ci case KEY_SUBTYPE_OPT: 2086881f68fSopenharmony_ci return fuse_opt_add_opt(&mo->subtype_opt, arg); 2096881f68fSopenharmony_ci 2106881f68fSopenharmony_ci case KEY_MTAB_OPT: 2116881f68fSopenharmony_ci return fuse_opt_add_opt(&mo->mtab_opts, arg); 2126881f68fSopenharmony_ci } 2136881f68fSopenharmony_ci 2146881f68fSopenharmony_ci /* Pass through unknown options */ 2156881f68fSopenharmony_ci return 1; 2166881f68fSopenharmony_ci} 2176881f68fSopenharmony_ci 2186881f68fSopenharmony_ci/* return value: 2196881f68fSopenharmony_ci * >= 0 => fd 2206881f68fSopenharmony_ci * -1 => error 2216881f68fSopenharmony_ci */ 2226881f68fSopenharmony_cistatic int receive_fd(int fd) 2236881f68fSopenharmony_ci{ 2246881f68fSopenharmony_ci struct msghdr msg; 2256881f68fSopenharmony_ci struct iovec iov; 2266881f68fSopenharmony_ci char buf[1]; 2276881f68fSopenharmony_ci int rv; 2286881f68fSopenharmony_ci size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; 2296881f68fSopenharmony_ci struct cmsghdr *cmsg; 2306881f68fSopenharmony_ci 2316881f68fSopenharmony_ci iov.iov_base = buf; 2326881f68fSopenharmony_ci iov.iov_len = 1; 2336881f68fSopenharmony_ci 2346881f68fSopenharmony_ci memset(&msg, 0, sizeof(msg)); 2356881f68fSopenharmony_ci msg.msg_name = 0; 2366881f68fSopenharmony_ci msg.msg_namelen = 0; 2376881f68fSopenharmony_ci msg.msg_iov = &iov; 2386881f68fSopenharmony_ci msg.msg_iovlen = 1; 2396881f68fSopenharmony_ci /* old BSD implementations should use msg_accrights instead of 2406881f68fSopenharmony_ci * msg_control; the interface is different. */ 2416881f68fSopenharmony_ci msg.msg_control = ccmsg; 2426881f68fSopenharmony_ci msg.msg_controllen = sizeof(ccmsg); 2436881f68fSopenharmony_ci 2446881f68fSopenharmony_ci while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); 2456881f68fSopenharmony_ci if (rv == -1) { 2466881f68fSopenharmony_ci perror("recvmsg"); 2476881f68fSopenharmony_ci return -1; 2486881f68fSopenharmony_ci } 2496881f68fSopenharmony_ci if(!rv) { 2506881f68fSopenharmony_ci /* EOF */ 2516881f68fSopenharmony_ci return -1; 2526881f68fSopenharmony_ci } 2536881f68fSopenharmony_ci 2546881f68fSopenharmony_ci cmsg = CMSG_FIRSTHDR(&msg); 2556881f68fSopenharmony_ci if (cmsg->cmsg_type != SCM_RIGHTS) { 2566881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "got control message of unknown type %d\n", 2576881f68fSopenharmony_ci cmsg->cmsg_type); 2586881f68fSopenharmony_ci return -1; 2596881f68fSopenharmony_ci } 2606881f68fSopenharmony_ci return *(int*)CMSG_DATA(cmsg); 2616881f68fSopenharmony_ci} 2626881f68fSopenharmony_ci 2636881f68fSopenharmony_civoid fuse_kern_unmount(const char *mountpoint, int fd) 2646881f68fSopenharmony_ci{ 2656881f68fSopenharmony_ci int res; 2666881f68fSopenharmony_ci int pid; 2676881f68fSopenharmony_ci 2686881f68fSopenharmony_ci if (fd != -1) { 2696881f68fSopenharmony_ci struct pollfd pfd; 2706881f68fSopenharmony_ci 2716881f68fSopenharmony_ci pfd.fd = fd; 2726881f68fSopenharmony_ci pfd.events = 0; 2736881f68fSopenharmony_ci res = poll(&pfd, 1, 0); 2746881f68fSopenharmony_ci 2756881f68fSopenharmony_ci /* Need to close file descriptor, otherwise synchronous umount 2766881f68fSopenharmony_ci would recurse into filesystem, and deadlock. 2776881f68fSopenharmony_ci 2786881f68fSopenharmony_ci Caller expects fuse_kern_unmount to close the fd, so close it 2796881f68fSopenharmony_ci anyway. */ 2806881f68fSopenharmony_ci close(fd); 2816881f68fSopenharmony_ci 2826881f68fSopenharmony_ci /* If file poll returns POLLERR on the device file descriptor, 2836881f68fSopenharmony_ci then the filesystem is already unmounted or the connection 2846881f68fSopenharmony_ci was severed via /sys/fs/fuse/connections/NNN/abort */ 2856881f68fSopenharmony_ci if (res == 1 && (pfd.revents & POLLERR)) 2866881f68fSopenharmony_ci return; 2876881f68fSopenharmony_ci } 2886881f68fSopenharmony_ci 2896881f68fSopenharmony_ci if (geteuid() == 0) { 2906881f68fSopenharmony_ci fuse_mnt_umount("fuse", mountpoint, mountpoint, 1); 2916881f68fSopenharmony_ci return; 2926881f68fSopenharmony_ci } 2936881f68fSopenharmony_ci 2946881f68fSopenharmony_ci res = umount2(mountpoint, 2); 2956881f68fSopenharmony_ci if (res == 0) 2966881f68fSopenharmony_ci return; 2976881f68fSopenharmony_ci 2986881f68fSopenharmony_ci pid = fork(); 2996881f68fSopenharmony_ci if(pid == -1) 3006881f68fSopenharmony_ci return; 3016881f68fSopenharmony_ci 3026881f68fSopenharmony_ci if(pid == 0) { 3036881f68fSopenharmony_ci const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z", 3046881f68fSopenharmony_ci "--", mountpoint, NULL }; 3056881f68fSopenharmony_ci 3066881f68fSopenharmony_ci exec_fusermount(argv); 3076881f68fSopenharmony_ci _exit(1); 3086881f68fSopenharmony_ci } 3096881f68fSopenharmony_ci waitpid(pid, NULL, 0); 3106881f68fSopenharmony_ci} 3116881f68fSopenharmony_ci 3126881f68fSopenharmony_cistatic int setup_auto_unmount(const char *mountpoint, int quiet) 3136881f68fSopenharmony_ci{ 3146881f68fSopenharmony_ci int fds[2], pid; 3156881f68fSopenharmony_ci int res; 3166881f68fSopenharmony_ci 3176881f68fSopenharmony_ci if (!mountpoint) { 3186881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n"); 3196881f68fSopenharmony_ci return -1; 3206881f68fSopenharmony_ci } 3216881f68fSopenharmony_ci 3226881f68fSopenharmony_ci res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); 3236881f68fSopenharmony_ci if(res == -1) { 3246881f68fSopenharmony_ci perror("fuse: socketpair() failed"); 3256881f68fSopenharmony_ci return -1; 3266881f68fSopenharmony_ci } 3276881f68fSopenharmony_ci 3286881f68fSopenharmony_ci pid = fork(); 3296881f68fSopenharmony_ci if(pid == -1) { 3306881f68fSopenharmony_ci perror("fuse: fork() failed"); 3316881f68fSopenharmony_ci close(fds[0]); 3326881f68fSopenharmony_ci close(fds[1]); 3336881f68fSopenharmony_ci return -1; 3346881f68fSopenharmony_ci } 3356881f68fSopenharmony_ci 3366881f68fSopenharmony_ci if(pid == 0) { 3376881f68fSopenharmony_ci char env[10]; 3386881f68fSopenharmony_ci const char *argv[32]; 3396881f68fSopenharmony_ci int a = 0; 3406881f68fSopenharmony_ci 3416881f68fSopenharmony_ci if (quiet) { 3426881f68fSopenharmony_ci int fd = open("/dev/null", O_RDONLY); 3436881f68fSopenharmony_ci if (fd != -1) { 3446881f68fSopenharmony_ci dup2(fd, 1); 3456881f68fSopenharmony_ci dup2(fd, 2); 3466881f68fSopenharmony_ci } 3476881f68fSopenharmony_ci } 3486881f68fSopenharmony_ci 3496881f68fSopenharmony_ci argv[a++] = FUSERMOUNT_PROG; 3506881f68fSopenharmony_ci argv[a++] = "--auto-unmount"; 3516881f68fSopenharmony_ci argv[a++] = "--"; 3526881f68fSopenharmony_ci argv[a++] = mountpoint; 3536881f68fSopenharmony_ci argv[a++] = NULL; 3546881f68fSopenharmony_ci 3556881f68fSopenharmony_ci close(fds[1]); 3566881f68fSopenharmony_ci fcntl(fds[0], F_SETFD, 0); 3576881f68fSopenharmony_ci snprintf(env, sizeof(env), "%i", fds[0]); 3586881f68fSopenharmony_ci setenv(FUSE_COMMFD_ENV, env, 1); 3596881f68fSopenharmony_ci exec_fusermount(argv); 3606881f68fSopenharmony_ci perror("fuse: failed to exec fusermount3"); 3616881f68fSopenharmony_ci _exit(1); 3626881f68fSopenharmony_ci } 3636881f68fSopenharmony_ci 3646881f68fSopenharmony_ci close(fds[0]); 3656881f68fSopenharmony_ci 3666881f68fSopenharmony_ci // Now fusermount3 will only exit when fds[1] closes automatically when our 3676881f68fSopenharmony_ci // process exits. 3686881f68fSopenharmony_ci return 0; 3696881f68fSopenharmony_ci} 3706881f68fSopenharmony_ci 3716881f68fSopenharmony_cistatic int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo, 3726881f68fSopenharmony_ci const char *opts, int quiet) 3736881f68fSopenharmony_ci{ 3746881f68fSopenharmony_ci int fds[2], pid; 3756881f68fSopenharmony_ci int res; 3766881f68fSopenharmony_ci int rv; 3776881f68fSopenharmony_ci 3786881f68fSopenharmony_ci if (!mountpoint) { 3796881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n"); 3806881f68fSopenharmony_ci return -1; 3816881f68fSopenharmony_ci } 3826881f68fSopenharmony_ci 3836881f68fSopenharmony_ci res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); 3846881f68fSopenharmony_ci if(res == -1) { 3856881f68fSopenharmony_ci perror("fuse: socketpair() failed"); 3866881f68fSopenharmony_ci return -1; 3876881f68fSopenharmony_ci } 3886881f68fSopenharmony_ci 3896881f68fSopenharmony_ci pid = fork(); 3906881f68fSopenharmony_ci if(pid == -1) { 3916881f68fSopenharmony_ci perror("fuse: fork() failed"); 3926881f68fSopenharmony_ci close(fds[0]); 3936881f68fSopenharmony_ci close(fds[1]); 3946881f68fSopenharmony_ci return -1; 3956881f68fSopenharmony_ci } 3966881f68fSopenharmony_ci 3976881f68fSopenharmony_ci if(pid == 0) { 3986881f68fSopenharmony_ci char env[10]; 3996881f68fSopenharmony_ci const char *argv[32]; 4006881f68fSopenharmony_ci int a = 0; 4016881f68fSopenharmony_ci 4026881f68fSopenharmony_ci if (quiet) { 4036881f68fSopenharmony_ci int fd = open("/dev/null", O_RDONLY); 4046881f68fSopenharmony_ci if (fd != -1) { 4056881f68fSopenharmony_ci dup2(fd, 1); 4066881f68fSopenharmony_ci dup2(fd, 2); 4076881f68fSopenharmony_ci } 4086881f68fSopenharmony_ci } 4096881f68fSopenharmony_ci 4106881f68fSopenharmony_ci argv[a++] = FUSERMOUNT_PROG; 4116881f68fSopenharmony_ci if (opts) { 4126881f68fSopenharmony_ci argv[a++] = "-o"; 4136881f68fSopenharmony_ci argv[a++] = opts; 4146881f68fSopenharmony_ci } 4156881f68fSopenharmony_ci argv[a++] = "--"; 4166881f68fSopenharmony_ci argv[a++] = mountpoint; 4176881f68fSopenharmony_ci argv[a++] = NULL; 4186881f68fSopenharmony_ci 4196881f68fSopenharmony_ci close(fds[1]); 4206881f68fSopenharmony_ci fcntl(fds[0], F_SETFD, 0); 4216881f68fSopenharmony_ci snprintf(env, sizeof(env), "%i", fds[0]); 4226881f68fSopenharmony_ci setenv(FUSE_COMMFD_ENV, env, 1); 4236881f68fSopenharmony_ci exec_fusermount(argv); 4246881f68fSopenharmony_ci perror("fuse: failed to exec fusermount3"); 4256881f68fSopenharmony_ci _exit(1); 4266881f68fSopenharmony_ci } 4276881f68fSopenharmony_ci 4286881f68fSopenharmony_ci close(fds[0]); 4296881f68fSopenharmony_ci rv = receive_fd(fds[1]); 4306881f68fSopenharmony_ci 4316881f68fSopenharmony_ci if (!mo->auto_unmount) { 4326881f68fSopenharmony_ci /* with auto_unmount option fusermount3 will not exit until 4336881f68fSopenharmony_ci this socket is closed */ 4346881f68fSopenharmony_ci close(fds[1]); 4356881f68fSopenharmony_ci waitpid(pid, NULL, 0); /* bury zombie */ 4366881f68fSopenharmony_ci } 4376881f68fSopenharmony_ci 4386881f68fSopenharmony_ci if (rv >= 0) 4396881f68fSopenharmony_ci fcntl(rv, F_SETFD, FD_CLOEXEC); 4406881f68fSopenharmony_ci 4416881f68fSopenharmony_ci return rv; 4426881f68fSopenharmony_ci} 4436881f68fSopenharmony_ci 4446881f68fSopenharmony_ci#ifndef O_CLOEXEC 4456881f68fSopenharmony_ci#define O_CLOEXEC 0 4466881f68fSopenharmony_ci#endif 4476881f68fSopenharmony_ci 4486881f68fSopenharmony_cistatic int fuse_mount_sys(const char *mnt, struct mount_opts *mo, 4496881f68fSopenharmony_ci const char *mnt_opts) 4506881f68fSopenharmony_ci{ 4516881f68fSopenharmony_ci char tmp[128]; 4526881f68fSopenharmony_ci const char *devname = "/dev/fuse"; 4536881f68fSopenharmony_ci char *source = NULL; 4546881f68fSopenharmony_ci char *type = NULL; 4556881f68fSopenharmony_ci struct stat stbuf; 4566881f68fSopenharmony_ci int fd; 4576881f68fSopenharmony_ci int res; 4586881f68fSopenharmony_ci 4596881f68fSopenharmony_ci if (!mnt) { 4606881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n"); 4616881f68fSopenharmony_ci return -1; 4626881f68fSopenharmony_ci } 4636881f68fSopenharmony_ci 4646881f68fSopenharmony_ci res = stat(mnt, &stbuf); 4656881f68fSopenharmony_ci if (res == -1) { 4666881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to access mountpoint %s: %s\n", 4676881f68fSopenharmony_ci mnt, strerror(errno)); 4686881f68fSopenharmony_ci return -1; 4696881f68fSopenharmony_ci } 4706881f68fSopenharmony_ci 4716881f68fSopenharmony_ci fd = open(devname, O_RDWR | O_CLOEXEC); 4726881f68fSopenharmony_ci if (fd == -1) { 4736881f68fSopenharmony_ci if (errno == ENODEV || errno == ENOENT) 4746881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: device not found, try 'modprobe fuse' first\n"); 4756881f68fSopenharmony_ci else 4766881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n", 4776881f68fSopenharmony_ci devname, strerror(errno)); 4786881f68fSopenharmony_ci return -1; 4796881f68fSopenharmony_ci } 4806881f68fSopenharmony_ci if (!O_CLOEXEC) 4816881f68fSopenharmony_ci fcntl(fd, F_SETFD, FD_CLOEXEC); 4826881f68fSopenharmony_ci 4836881f68fSopenharmony_ci snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u", 4846881f68fSopenharmony_ci fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); 4856881f68fSopenharmony_ci 4866881f68fSopenharmony_ci res = fuse_opt_add_opt(&mo->kernel_opts, tmp); 4876881f68fSopenharmony_ci if (res == -1) 4886881f68fSopenharmony_ci goto out_close; 4896881f68fSopenharmony_ci 4906881f68fSopenharmony_ci source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + 4916881f68fSopenharmony_ci (mo->subtype ? strlen(mo->subtype) : 0) + 4926881f68fSopenharmony_ci strlen(devname) + 32); 4936881f68fSopenharmony_ci 4946881f68fSopenharmony_ci type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); 4956881f68fSopenharmony_ci if (!type || !source) { 4966881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate memory\n"); 4976881f68fSopenharmony_ci goto out_close; 4986881f68fSopenharmony_ci } 4996881f68fSopenharmony_ci 5006881f68fSopenharmony_ci strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); 5016881f68fSopenharmony_ci if (mo->subtype) { 5026881f68fSopenharmony_ci strcat(type, "."); 5036881f68fSopenharmony_ci strcat(type, mo->subtype); 5046881f68fSopenharmony_ci } 5056881f68fSopenharmony_ci strcpy(source, 5066881f68fSopenharmony_ci mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); 5076881f68fSopenharmony_ci 5086881f68fSopenharmony_ci res = mount(source, mnt, type, mo->flags, mo->kernel_opts); 5096881f68fSopenharmony_ci if (res == -1 && errno == ENODEV && mo->subtype) { 5106881f68fSopenharmony_ci /* Probably missing subtype support */ 5116881f68fSopenharmony_ci strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); 5126881f68fSopenharmony_ci if (mo->fsname) { 5136881f68fSopenharmony_ci if (!mo->blkdev) 5146881f68fSopenharmony_ci sprintf(source, "%s#%s", mo->subtype, 5156881f68fSopenharmony_ci mo->fsname); 5166881f68fSopenharmony_ci } else { 5176881f68fSopenharmony_ci strcpy(source, type); 5186881f68fSopenharmony_ci } 5196881f68fSopenharmony_ci res = mount(source, mnt, type, mo->flags, mo->kernel_opts); 5206881f68fSopenharmony_ci } 5216881f68fSopenharmony_ci if (res == -1) { 5226881f68fSopenharmony_ci /* 5236881f68fSopenharmony_ci * Maybe kernel doesn't support unprivileged mounts, in this 5246881f68fSopenharmony_ci * case try falling back to fusermount3 5256881f68fSopenharmony_ci */ 5266881f68fSopenharmony_ci if (errno == EPERM) { 5276881f68fSopenharmony_ci res = -2; 5286881f68fSopenharmony_ci } else { 5296881f68fSopenharmony_ci int errno_save = errno; 5306881f68fSopenharmony_ci if (mo->blkdev && errno == ENODEV && 5316881f68fSopenharmony_ci !fuse_mnt_check_fuseblk()) 5326881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, 5336881f68fSopenharmony_ci "fuse: 'fuseblk' support missing\n"); 5346881f68fSopenharmony_ci else 5356881f68fSopenharmony_ci fuse_log(FUSE_LOG_ERR, "fuse: mount failed: %s\n", 5366881f68fSopenharmony_ci strerror(errno_save)); 5376881f68fSopenharmony_ci } 5386881f68fSopenharmony_ci 5396881f68fSopenharmony_ci goto out_close; 5406881f68fSopenharmony_ci } 5416881f68fSopenharmony_ci 5426881f68fSopenharmony_ci#ifndef IGNORE_MTAB 5436881f68fSopenharmony_ci if (geteuid() == 0) { 5446881f68fSopenharmony_ci char *newmnt = fuse_mnt_resolve_path("fuse", mnt); 5456881f68fSopenharmony_ci res = -1; 5466881f68fSopenharmony_ci if (!newmnt) 5476881f68fSopenharmony_ci goto out_umount; 5486881f68fSopenharmony_ci 5496881f68fSopenharmony_ci res = fuse_mnt_add_mount("fuse", source, newmnt, type, 5506881f68fSopenharmony_ci mnt_opts); 5516881f68fSopenharmony_ci free(newmnt); 5526881f68fSopenharmony_ci if (res == -1) 5536881f68fSopenharmony_ci goto out_umount; 5546881f68fSopenharmony_ci } 5556881f68fSopenharmony_ci#endif /* IGNORE_MTAB */ 5566881f68fSopenharmony_ci free(type); 5576881f68fSopenharmony_ci free(source); 5586881f68fSopenharmony_ci 5596881f68fSopenharmony_ci return fd; 5606881f68fSopenharmony_ci 5616881f68fSopenharmony_ciout_umount: 5626881f68fSopenharmony_ci umount2(mnt, 2); /* lazy umount */ 5636881f68fSopenharmony_ciout_close: 5646881f68fSopenharmony_ci free(type); 5656881f68fSopenharmony_ci free(source); 5666881f68fSopenharmony_ci close(fd); 5676881f68fSopenharmony_ci return res; 5686881f68fSopenharmony_ci} 5696881f68fSopenharmony_ci 5706881f68fSopenharmony_cistatic int get_mnt_flag_opts(char **mnt_optsp, int flags) 5716881f68fSopenharmony_ci{ 5726881f68fSopenharmony_ci int i; 5736881f68fSopenharmony_ci 5746881f68fSopenharmony_ci if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) 5756881f68fSopenharmony_ci return -1; 5766881f68fSopenharmony_ci 5776881f68fSopenharmony_ci for (i = 0; mount_flags[i].opt != NULL; i++) { 5786881f68fSopenharmony_ci if (mount_flags[i].on && (flags & mount_flags[i].flag) && 5796881f68fSopenharmony_ci fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) 5806881f68fSopenharmony_ci return -1; 5816881f68fSopenharmony_ci } 5826881f68fSopenharmony_ci return 0; 5836881f68fSopenharmony_ci} 5846881f68fSopenharmony_ci 5856881f68fSopenharmony_cistruct mount_opts *parse_mount_opts(struct fuse_args *args) 5866881f68fSopenharmony_ci{ 5876881f68fSopenharmony_ci struct mount_opts *mo; 5886881f68fSopenharmony_ci 5896881f68fSopenharmony_ci mo = (struct mount_opts*) malloc(sizeof(struct mount_opts)); 5906881f68fSopenharmony_ci if (mo == NULL) 5916881f68fSopenharmony_ci return NULL; 5926881f68fSopenharmony_ci 5936881f68fSopenharmony_ci memset(mo, 0, sizeof(struct mount_opts)); 5946881f68fSopenharmony_ci mo->flags = MS_NOSUID | MS_NODEV; 5956881f68fSopenharmony_ci 5966881f68fSopenharmony_ci if (args && 5976881f68fSopenharmony_ci fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) 5986881f68fSopenharmony_ci goto err_out; 5996881f68fSopenharmony_ci 6006881f68fSopenharmony_ci return mo; 6016881f68fSopenharmony_ci 6026881f68fSopenharmony_cierr_out: 6036881f68fSopenharmony_ci destroy_mount_opts(mo); 6046881f68fSopenharmony_ci return NULL; 6056881f68fSopenharmony_ci} 6066881f68fSopenharmony_ci 6076881f68fSopenharmony_civoid destroy_mount_opts(struct mount_opts *mo) 6086881f68fSopenharmony_ci{ 6096881f68fSopenharmony_ci free(mo->fsname); 6106881f68fSopenharmony_ci free(mo->subtype); 6116881f68fSopenharmony_ci free(mo->fusermount_opts); 6126881f68fSopenharmony_ci free(mo->subtype_opt); 6136881f68fSopenharmony_ci free(mo->kernel_opts); 6146881f68fSopenharmony_ci free(mo->mtab_opts); 6156881f68fSopenharmony_ci free(mo); 6166881f68fSopenharmony_ci} 6176881f68fSopenharmony_ci 6186881f68fSopenharmony_ci 6196881f68fSopenharmony_ciint fuse_kern_mount(const char *mountpoint, struct mount_opts *mo) 6206881f68fSopenharmony_ci{ 6216881f68fSopenharmony_ci int res = -1; 6226881f68fSopenharmony_ci char *mnt_opts = NULL; 6236881f68fSopenharmony_ci 6246881f68fSopenharmony_ci res = -1; 6256881f68fSopenharmony_ci if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1) 6266881f68fSopenharmony_ci goto out; 6276881f68fSopenharmony_ci if (mo->kernel_opts && fuse_opt_add_opt(&mnt_opts, mo->kernel_opts) == -1) 6286881f68fSopenharmony_ci goto out; 6296881f68fSopenharmony_ci if (mo->mtab_opts && fuse_opt_add_opt(&mnt_opts, mo->mtab_opts) == -1) 6306881f68fSopenharmony_ci goto out; 6316881f68fSopenharmony_ci 6326881f68fSopenharmony_ci res = fuse_mount_sys(mountpoint, mo, mnt_opts); 6336881f68fSopenharmony_ci if (res >= 0 && mo->auto_unmount) { 6346881f68fSopenharmony_ci if(0 > setup_auto_unmount(mountpoint, 0)) { 6356881f68fSopenharmony_ci // Something went wrong, let's umount like in fuse_mount_sys. 6366881f68fSopenharmony_ci umount2(mountpoint, MNT_DETACH); /* lazy umount */ 6376881f68fSopenharmony_ci res = -1; 6386881f68fSopenharmony_ci } 6396881f68fSopenharmony_ci } else if (res == -2) { 6406881f68fSopenharmony_ci if (mo->fusermount_opts && 6416881f68fSopenharmony_ci fuse_opt_add_opt(&mnt_opts, mo->fusermount_opts) == -1) 6426881f68fSopenharmony_ci goto out; 6436881f68fSopenharmony_ci 6446881f68fSopenharmony_ci if (mo->subtype) { 6456881f68fSopenharmony_ci char *tmp_opts = NULL; 6466881f68fSopenharmony_ci 6476881f68fSopenharmony_ci res = -1; 6486881f68fSopenharmony_ci if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || 6496881f68fSopenharmony_ci fuse_opt_add_opt(&tmp_opts, mo->subtype_opt) == -1) { 6506881f68fSopenharmony_ci free(tmp_opts); 6516881f68fSopenharmony_ci goto out; 6526881f68fSopenharmony_ci } 6536881f68fSopenharmony_ci 6546881f68fSopenharmony_ci res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1); 6556881f68fSopenharmony_ci free(tmp_opts); 6566881f68fSopenharmony_ci if (res == -1) 6576881f68fSopenharmony_ci res = fuse_mount_fusermount(mountpoint, mo, 6586881f68fSopenharmony_ci mnt_opts, 0); 6596881f68fSopenharmony_ci } else { 6606881f68fSopenharmony_ci res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0); 6616881f68fSopenharmony_ci } 6626881f68fSopenharmony_ci } 6636881f68fSopenharmony_ciout: 6646881f68fSopenharmony_ci free(mnt_opts); 6656881f68fSopenharmony_ci return res; 6666881f68fSopenharmony_ci} 667