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