16881f68fSopenharmony_ci/*
26881f68fSopenharmony_ci  FUSE: Filesystem in Userspace
36881f68fSopenharmony_ci  Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
46881f68fSopenharmony_ci
56881f68fSopenharmony_ci  Helper functions to create (simple) standalone programs. With the
66881f68fSopenharmony_ci  aid of these functions it should be possible to create full FUSE
76881f68fSopenharmony_ci  file system by implementing nothing but the request handlers.
86881f68fSopenharmony_ci
96881f68fSopenharmony_ci  This program can be distributed under the terms of the GNU LGPLv2.
106881f68fSopenharmony_ci  See the file COPYING.LIB.
116881f68fSopenharmony_ci*/
126881f68fSopenharmony_ci
136881f68fSopenharmony_ci#include "fuse_config.h"
146881f68fSopenharmony_ci#include "fuse_i.h"
156881f68fSopenharmony_ci#include "fuse_misc.h"
166881f68fSopenharmony_ci#include "fuse_opt.h"
176881f68fSopenharmony_ci#include "fuse_lowlevel.h"
186881f68fSopenharmony_ci#include "mount_util.h"
196881f68fSopenharmony_ci
206881f68fSopenharmony_ci#include <stdio.h>
216881f68fSopenharmony_ci#include <stdlib.h>
226881f68fSopenharmony_ci#include <stddef.h>
236881f68fSopenharmony_ci#include <unistd.h>
246881f68fSopenharmony_ci#include <string.h>
256881f68fSopenharmony_ci#include <limits.h>
266881f68fSopenharmony_ci#include <errno.h>
276881f68fSopenharmony_ci#include <sys/param.h>
286881f68fSopenharmony_ci
296881f68fSopenharmony_ci#define FUSE_HELPER_OPT(t, p) \
306881f68fSopenharmony_ci	{ t, offsetof(struct fuse_cmdline_opts, p), 1 }
316881f68fSopenharmony_ci
326881f68fSopenharmony_cistatic const struct fuse_opt fuse_helper_opts[] = {
336881f68fSopenharmony_ci	FUSE_HELPER_OPT("-h",		show_help),
346881f68fSopenharmony_ci	FUSE_HELPER_OPT("--help",	show_help),
356881f68fSopenharmony_ci	FUSE_HELPER_OPT("-V",		show_version),
366881f68fSopenharmony_ci	FUSE_HELPER_OPT("--version",	show_version),
376881f68fSopenharmony_ci	FUSE_HELPER_OPT("-d",		debug),
386881f68fSopenharmony_ci	FUSE_HELPER_OPT("debug",	debug),
396881f68fSopenharmony_ci	FUSE_HELPER_OPT("-d",		foreground),
406881f68fSopenharmony_ci	FUSE_HELPER_OPT("debug",	foreground),
416881f68fSopenharmony_ci	FUSE_OPT_KEY("-d",		FUSE_OPT_KEY_KEEP),
426881f68fSopenharmony_ci	FUSE_OPT_KEY("debug",		FUSE_OPT_KEY_KEEP),
436881f68fSopenharmony_ci	FUSE_HELPER_OPT("-f",		foreground),
446881f68fSopenharmony_ci	FUSE_HELPER_OPT("-s",		singlethread),
456881f68fSopenharmony_ci	FUSE_HELPER_OPT("fsname=",	nodefault_subtype),
466881f68fSopenharmony_ci	FUSE_OPT_KEY("fsname=",		FUSE_OPT_KEY_KEEP),
476881f68fSopenharmony_ci#ifndef __FreeBSD__
486881f68fSopenharmony_ci	FUSE_HELPER_OPT("subtype=",	nodefault_subtype),
496881f68fSopenharmony_ci	FUSE_OPT_KEY("subtype=",	FUSE_OPT_KEY_KEEP),
506881f68fSopenharmony_ci#endif
516881f68fSopenharmony_ci	FUSE_HELPER_OPT("clone_fd",	clone_fd),
526881f68fSopenharmony_ci	FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
536881f68fSopenharmony_ci	FUSE_HELPER_OPT("max_threads=%u", max_threads),
546881f68fSopenharmony_ci	FUSE_OPT_END
556881f68fSopenharmony_ci};
566881f68fSopenharmony_ci
576881f68fSopenharmony_cistruct fuse_conn_info_opts {
586881f68fSopenharmony_ci	int atomic_o_trunc;
596881f68fSopenharmony_ci	int no_remote_posix_lock;
606881f68fSopenharmony_ci	int no_remote_flock;
616881f68fSopenharmony_ci	int splice_write;
626881f68fSopenharmony_ci	int splice_move;
636881f68fSopenharmony_ci	int splice_read;
646881f68fSopenharmony_ci	int no_splice_write;
656881f68fSopenharmony_ci	int no_splice_move;
666881f68fSopenharmony_ci	int no_splice_read;
676881f68fSopenharmony_ci	int auto_inval_data;
686881f68fSopenharmony_ci	int no_auto_inval_data;
696881f68fSopenharmony_ci	int no_readdirplus;
706881f68fSopenharmony_ci	int no_readdirplus_auto;
716881f68fSopenharmony_ci	int async_dio;
726881f68fSopenharmony_ci	int no_async_dio;
736881f68fSopenharmony_ci	int writeback_cache;
746881f68fSopenharmony_ci	int no_writeback_cache;
756881f68fSopenharmony_ci	int async_read;
766881f68fSopenharmony_ci	int sync_read;
776881f68fSopenharmony_ci	unsigned max_write;
786881f68fSopenharmony_ci	unsigned max_readahead;
796881f68fSopenharmony_ci	unsigned max_background;
806881f68fSopenharmony_ci	unsigned congestion_threshold;
816881f68fSopenharmony_ci	unsigned time_gran;
826881f68fSopenharmony_ci	int set_max_write;
836881f68fSopenharmony_ci	int set_max_readahead;
846881f68fSopenharmony_ci	int set_max_background;
856881f68fSopenharmony_ci	int set_congestion_threshold;
866881f68fSopenharmony_ci	int set_time_gran;
876881f68fSopenharmony_ci};
886881f68fSopenharmony_ci
896881f68fSopenharmony_ci#define CONN_OPTION(t, p, v)					\
906881f68fSopenharmony_ci	{ t, offsetof(struct fuse_conn_info_opts, p), v }
916881f68fSopenharmony_cistatic const struct fuse_opt conn_info_opt_spec[] = {
926881f68fSopenharmony_ci	CONN_OPTION("max_write=%u", max_write, 0),
936881f68fSopenharmony_ci	CONN_OPTION("max_write=", set_max_write, 1),
946881f68fSopenharmony_ci	CONN_OPTION("max_readahead=%u", max_readahead, 0),
956881f68fSopenharmony_ci	CONN_OPTION("max_readahead=", set_max_readahead, 1),
966881f68fSopenharmony_ci	CONN_OPTION("max_background=%u", max_background, 0),
976881f68fSopenharmony_ci	CONN_OPTION("max_background=", set_max_background, 1),
986881f68fSopenharmony_ci	CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0),
996881f68fSopenharmony_ci	CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1),
1006881f68fSopenharmony_ci	CONN_OPTION("sync_read", sync_read, 1),
1016881f68fSopenharmony_ci	CONN_OPTION("async_read", async_read, 1),
1026881f68fSopenharmony_ci	CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1),
1036881f68fSopenharmony_ci	CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1),
1046881f68fSopenharmony_ci	CONN_OPTION("no_remote_lock", no_remote_flock, 1),
1056881f68fSopenharmony_ci	CONN_OPTION("no_remote_flock", no_remote_flock, 1),
1066881f68fSopenharmony_ci	CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1),
1076881f68fSopenharmony_ci	CONN_OPTION("splice_write", splice_write, 1),
1086881f68fSopenharmony_ci	CONN_OPTION("no_splice_write", no_splice_write, 1),
1096881f68fSopenharmony_ci	CONN_OPTION("splice_move", splice_move, 1),
1106881f68fSopenharmony_ci	CONN_OPTION("no_splice_move", no_splice_move, 1),
1116881f68fSopenharmony_ci	CONN_OPTION("splice_read", splice_read, 1),
1126881f68fSopenharmony_ci	CONN_OPTION("no_splice_read", no_splice_read, 1),
1136881f68fSopenharmony_ci	CONN_OPTION("auto_inval_data", auto_inval_data, 1),
1146881f68fSopenharmony_ci	CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1),
1156881f68fSopenharmony_ci	CONN_OPTION("readdirplus=no", no_readdirplus, 1),
1166881f68fSopenharmony_ci	CONN_OPTION("readdirplus=yes", no_readdirplus, 0),
1176881f68fSopenharmony_ci	CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1),
1186881f68fSopenharmony_ci	CONN_OPTION("readdirplus=auto", no_readdirplus, 0),
1196881f68fSopenharmony_ci	CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0),
1206881f68fSopenharmony_ci	CONN_OPTION("async_dio", async_dio, 1),
1216881f68fSopenharmony_ci	CONN_OPTION("no_async_dio", no_async_dio, 1),
1226881f68fSopenharmony_ci	CONN_OPTION("writeback_cache", writeback_cache, 1),
1236881f68fSopenharmony_ci	CONN_OPTION("no_writeback_cache", no_writeback_cache, 1),
1246881f68fSopenharmony_ci	CONN_OPTION("time_gran=%u", time_gran, 0),
1256881f68fSopenharmony_ci	CONN_OPTION("time_gran=", set_time_gran, 1),
1266881f68fSopenharmony_ci	FUSE_OPT_END
1276881f68fSopenharmony_ci};
1286881f68fSopenharmony_ci
1296881f68fSopenharmony_ci
1306881f68fSopenharmony_civoid fuse_cmdline_help(void)
1316881f68fSopenharmony_ci{
1326881f68fSopenharmony_ci	printf("    -h   --help            print help\n"
1336881f68fSopenharmony_ci	       "    -V   --version         print version\n"
1346881f68fSopenharmony_ci	       "    -d   -o debug          enable debug output (implies -f)\n"
1356881f68fSopenharmony_ci	       "    -f                     foreground operation\n"
1366881f68fSopenharmony_ci	       "    -s                     disable multi-threaded operation\n"
1376881f68fSopenharmony_ci	       "    -o clone_fd            use separate fuse device fd for each thread\n"
1386881f68fSopenharmony_ci	       "                           (may improve performance)\n"
1396881f68fSopenharmony_ci	       "    -o max_idle_threads    the maximum number of idle worker threads\n"
1406881f68fSopenharmony_ci	       "                           allowed (default: -1)\n"
1416881f68fSopenharmony_ci	       "    -o max_threads         the maximum number of worker threads\n"
1426881f68fSopenharmony_ci	       "                           allowed (default: 10)\n");
1436881f68fSopenharmony_ci}
1446881f68fSopenharmony_ci
1456881f68fSopenharmony_cistatic int fuse_helper_opt_proc(void *data, const char *arg, int key,
1466881f68fSopenharmony_ci				struct fuse_args *outargs)
1476881f68fSopenharmony_ci{
1486881f68fSopenharmony_ci	(void) outargs;
1496881f68fSopenharmony_ci	struct fuse_cmdline_opts *opts = data;
1506881f68fSopenharmony_ci
1516881f68fSopenharmony_ci	switch (key) {
1526881f68fSopenharmony_ci	case FUSE_OPT_KEY_NONOPT:
1536881f68fSopenharmony_ci		if (!opts->mountpoint) {
1546881f68fSopenharmony_ci			if (fuse_mnt_parse_fuse_fd(arg) != -1) {
1556881f68fSopenharmony_ci				return fuse_opt_add_opt(&opts->mountpoint, arg);
1566881f68fSopenharmony_ci			}
1576881f68fSopenharmony_ci
1586881f68fSopenharmony_ci			char mountpoint[PATH_MAX] = "";
1596881f68fSopenharmony_ci			if (realpath(arg, mountpoint) == NULL) {
1606881f68fSopenharmony_ci				fuse_log(FUSE_LOG_ERR,
1616881f68fSopenharmony_ci					"fuse: bad mount point `%s': %s\n",
1626881f68fSopenharmony_ci					arg, strerror(errno));
1636881f68fSopenharmony_ci				return -1;
1646881f68fSopenharmony_ci			}
1656881f68fSopenharmony_ci			return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
1666881f68fSopenharmony_ci		} else {
1676881f68fSopenharmony_ci			fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
1686881f68fSopenharmony_ci			return -1;
1696881f68fSopenharmony_ci		}
1706881f68fSopenharmony_ci
1716881f68fSopenharmony_ci	default:
1726881f68fSopenharmony_ci		/* Pass through unknown options */
1736881f68fSopenharmony_ci		return 1;
1746881f68fSopenharmony_ci	}
1756881f68fSopenharmony_ci}
1766881f68fSopenharmony_ci
1776881f68fSopenharmony_ci/* Under FreeBSD, there is no subtype option so this
1786881f68fSopenharmony_ci   function actually sets the fsname */
1796881f68fSopenharmony_cistatic int add_default_subtype(const char *progname, struct fuse_args *args)
1806881f68fSopenharmony_ci{
1816881f68fSopenharmony_ci	int res;
1826881f68fSopenharmony_ci	char *subtype_opt;
1836881f68fSopenharmony_ci
1846881f68fSopenharmony_ci	const char *basename = strrchr(progname, '/');
1856881f68fSopenharmony_ci	if (basename == NULL)
1866881f68fSopenharmony_ci		basename = progname;
1876881f68fSopenharmony_ci	else if (basename[1] != '\0')
1886881f68fSopenharmony_ci		basename++;
1896881f68fSopenharmony_ci
1906881f68fSopenharmony_ci	subtype_opt = (char *) malloc(strlen(basename) + 64);
1916881f68fSopenharmony_ci	if (subtype_opt == NULL) {
1926881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
1936881f68fSopenharmony_ci		return -1;
1946881f68fSopenharmony_ci	}
1956881f68fSopenharmony_ci#ifdef __FreeBSD__
1966881f68fSopenharmony_ci	sprintf(subtype_opt, "-ofsname=%s", basename);
1976881f68fSopenharmony_ci#else
1986881f68fSopenharmony_ci	sprintf(subtype_opt, "-osubtype=%s", basename);
1996881f68fSopenharmony_ci#endif
2006881f68fSopenharmony_ci	res = fuse_opt_add_arg(args, subtype_opt);
2016881f68fSopenharmony_ci	free(subtype_opt);
2026881f68fSopenharmony_ci	return res;
2036881f68fSopenharmony_ci}
2046881f68fSopenharmony_ci
2056881f68fSopenharmony_ciint fuse_parse_cmdline_312(struct fuse_args *args,
2066881f68fSopenharmony_ci			   struct fuse_cmdline_opts *opts);
2076881f68fSopenharmony_ciFUSE_SYMVER("fuse_parse_cmdline_312", "fuse_parse_cmdline@@FUSE_3.12")
2086881f68fSopenharmony_ciint fuse_parse_cmdline_312(struct fuse_args *args,
2096881f68fSopenharmony_ci			   struct fuse_cmdline_opts *opts)
2106881f68fSopenharmony_ci{
2116881f68fSopenharmony_ci	memset(opts, 0, sizeof(struct fuse_cmdline_opts));
2126881f68fSopenharmony_ci
2136881f68fSopenharmony_ci	opts->max_idle_threads = UINT_MAX; /* new default in fuse version 3.12 */
2146881f68fSopenharmony_ci	opts->max_threads = 10;
2156881f68fSopenharmony_ci
2166881f68fSopenharmony_ci	if (fuse_opt_parse(args, opts, fuse_helper_opts,
2176881f68fSopenharmony_ci			   fuse_helper_opt_proc) == -1)
2186881f68fSopenharmony_ci		return -1;
2196881f68fSopenharmony_ci
2206881f68fSopenharmony_ci	/* *Linux*: if neither -o subtype nor -o fsname are specified,
2216881f68fSopenharmony_ci	   set subtype to program's basename.
2226881f68fSopenharmony_ci	   *FreeBSD*: if fsname is not specified, set to program's
2236881f68fSopenharmony_ci	   basename. */
2246881f68fSopenharmony_ci	if (!opts->nodefault_subtype)
2256881f68fSopenharmony_ci		if (add_default_subtype(args->argv[0], args) == -1)
2266881f68fSopenharmony_ci			return -1;
2276881f68fSopenharmony_ci
2286881f68fSopenharmony_ci	return 0;
2296881f68fSopenharmony_ci}
2306881f68fSopenharmony_ci
2316881f68fSopenharmony_ci/**
2326881f68fSopenharmony_ci * struct fuse_cmdline_opts got extended in libfuse-3.12
2336881f68fSopenharmony_ci */
2346881f68fSopenharmony_ciint fuse_parse_cmdline_30(struct fuse_args *args,
2356881f68fSopenharmony_ci		       struct fuse_cmdline_opts *opts);
2366881f68fSopenharmony_ciFUSE_SYMVER("fuse_parse_cmdline_30", "fuse_parse_cmdline@FUSE_3.0")
2376881f68fSopenharmony_ciint fuse_parse_cmdline_30(struct fuse_args *args,
2386881f68fSopenharmony_ci			  struct fuse_cmdline_opts *out_opts)
2396881f68fSopenharmony_ci{
2406881f68fSopenharmony_ci	struct fuse_cmdline_opts opts;
2416881f68fSopenharmony_ci
2426881f68fSopenharmony_ci	int rc = fuse_parse_cmdline_312(args, &opts);
2436881f68fSopenharmony_ci	if (rc == 0) {
2446881f68fSopenharmony_ci		/* copy up to the size of the old pre 3.12 struct */
2456881f68fSopenharmony_ci		memcpy(out_opts, &opts,
2466881f68fSopenharmony_ci		       offsetof(struct fuse_cmdline_opts, max_idle_threads) +
2476881f68fSopenharmony_ci		       sizeof(opts.max_idle_threads));
2486881f68fSopenharmony_ci	}
2496881f68fSopenharmony_ci
2506881f68fSopenharmony_ci	return rc;
2516881f68fSopenharmony_ci}
2526881f68fSopenharmony_ci
2536881f68fSopenharmony_ciint fuse_daemonize(int foreground)
2546881f68fSopenharmony_ci{
2556881f68fSopenharmony_ci	if (!foreground) {
2566881f68fSopenharmony_ci		int nullfd;
2576881f68fSopenharmony_ci		int waiter[2];
2586881f68fSopenharmony_ci		char completed;
2596881f68fSopenharmony_ci
2606881f68fSopenharmony_ci		if (pipe(waiter)) {
2616881f68fSopenharmony_ci			perror("fuse_daemonize: pipe");
2626881f68fSopenharmony_ci			return -1;
2636881f68fSopenharmony_ci		}
2646881f68fSopenharmony_ci
2656881f68fSopenharmony_ci		/*
2666881f68fSopenharmony_ci		 * demonize current process by forking it and killing the
2676881f68fSopenharmony_ci		 * parent.  This makes current process as a child of 'init'.
2686881f68fSopenharmony_ci		 */
2696881f68fSopenharmony_ci		switch(fork()) {
2706881f68fSopenharmony_ci		case -1:
2716881f68fSopenharmony_ci			perror("fuse_daemonize: fork");
2726881f68fSopenharmony_ci			return -1;
2736881f68fSopenharmony_ci		case 0:
2746881f68fSopenharmony_ci			break;
2756881f68fSopenharmony_ci		default:
2766881f68fSopenharmony_ci			(void) read(waiter[0], &completed, sizeof(completed));
2776881f68fSopenharmony_ci			_exit(0);
2786881f68fSopenharmony_ci		}
2796881f68fSopenharmony_ci
2806881f68fSopenharmony_ci		if (setsid() == -1) {
2816881f68fSopenharmony_ci			perror("fuse_daemonize: setsid");
2826881f68fSopenharmony_ci			return -1;
2836881f68fSopenharmony_ci		}
2846881f68fSopenharmony_ci
2856881f68fSopenharmony_ci		(void) chdir("/");
2866881f68fSopenharmony_ci
2876881f68fSopenharmony_ci		nullfd = open("/dev/null", O_RDWR, 0);
2886881f68fSopenharmony_ci		if (nullfd != -1) {
2896881f68fSopenharmony_ci			(void) dup2(nullfd, 0);
2906881f68fSopenharmony_ci			(void) dup2(nullfd, 1);
2916881f68fSopenharmony_ci			(void) dup2(nullfd, 2);
2926881f68fSopenharmony_ci			if (nullfd > 2)
2936881f68fSopenharmony_ci				close(nullfd);
2946881f68fSopenharmony_ci		}
2956881f68fSopenharmony_ci
2966881f68fSopenharmony_ci		/* Propagate completion of daemon initialization */
2976881f68fSopenharmony_ci		completed = 1;
2986881f68fSopenharmony_ci		(void) write(waiter[1], &completed, sizeof(completed));
2996881f68fSopenharmony_ci		close(waiter[0]);
3006881f68fSopenharmony_ci		close(waiter[1]);
3016881f68fSopenharmony_ci	} else {
3026881f68fSopenharmony_ci		(void) chdir("/");
3036881f68fSopenharmony_ci	}
3046881f68fSopenharmony_ci	return 0;
3056881f68fSopenharmony_ci}
3066881f68fSopenharmony_ci
3076881f68fSopenharmony_ciint fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
3086881f68fSopenharmony_ci		   size_t op_size, void *user_data)
3096881f68fSopenharmony_ci{
3106881f68fSopenharmony_ci	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3116881f68fSopenharmony_ci	struct fuse *fuse;
3126881f68fSopenharmony_ci	struct fuse_cmdline_opts opts;
3136881f68fSopenharmony_ci	int res;
3146881f68fSopenharmony_ci	struct fuse_loop_config *loop_config = NULL;
3156881f68fSopenharmony_ci
3166881f68fSopenharmony_ci	if (fuse_parse_cmdline(&args, &opts) != 0)
3176881f68fSopenharmony_ci		return 1;
3186881f68fSopenharmony_ci
3196881f68fSopenharmony_ci	if (opts.show_version) {
3206881f68fSopenharmony_ci		printf("FUSE library version %s\n", PACKAGE_VERSION);
3216881f68fSopenharmony_ci		fuse_lowlevel_version();
3226881f68fSopenharmony_ci		res = 0;
3236881f68fSopenharmony_ci		goto out1;
3246881f68fSopenharmony_ci	}
3256881f68fSopenharmony_ci
3266881f68fSopenharmony_ci	if (opts.show_help) {
3276881f68fSopenharmony_ci		if(args.argv[0][0] != '\0')
3286881f68fSopenharmony_ci			printf("usage: %s [options] <mountpoint>\n\n",
3296881f68fSopenharmony_ci			       args.argv[0]);
3306881f68fSopenharmony_ci		printf("FUSE options:\n");
3316881f68fSopenharmony_ci		fuse_cmdline_help();
3326881f68fSopenharmony_ci		fuse_lib_help(&args);
3336881f68fSopenharmony_ci		res = 0;
3346881f68fSopenharmony_ci		goto out1;
3356881f68fSopenharmony_ci	}
3366881f68fSopenharmony_ci
3376881f68fSopenharmony_ci	if (!opts.show_help &&
3386881f68fSopenharmony_ci	    !opts.mountpoint) {
3396881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "error: no mountpoint specified\n");
3406881f68fSopenharmony_ci		res = 2;
3416881f68fSopenharmony_ci		goto out1;
3426881f68fSopenharmony_ci	}
3436881f68fSopenharmony_ci
3446881f68fSopenharmony_ci
3456881f68fSopenharmony_ci	fuse = fuse_new_31(&args, op, op_size, user_data);
3466881f68fSopenharmony_ci	if (fuse == NULL) {
3476881f68fSopenharmony_ci		res = 3;
3486881f68fSopenharmony_ci		goto out1;
3496881f68fSopenharmony_ci	}
3506881f68fSopenharmony_ci
3516881f68fSopenharmony_ci	if (fuse_mount(fuse,opts.mountpoint) != 0) {
3526881f68fSopenharmony_ci		res = 4;
3536881f68fSopenharmony_ci		goto out2;
3546881f68fSopenharmony_ci	}
3556881f68fSopenharmony_ci
3566881f68fSopenharmony_ci	if (fuse_daemonize(opts.foreground) != 0) {
3576881f68fSopenharmony_ci		res = 5;
3586881f68fSopenharmony_ci		goto out3;
3596881f68fSopenharmony_ci	}
3606881f68fSopenharmony_ci
3616881f68fSopenharmony_ci	struct fuse_session *se = fuse_get_session(fuse);
3626881f68fSopenharmony_ci	if (fuse_set_signal_handlers(se) != 0) {
3636881f68fSopenharmony_ci		res = 6;
3646881f68fSopenharmony_ci		goto out3;
3656881f68fSopenharmony_ci	}
3666881f68fSopenharmony_ci
3676881f68fSopenharmony_ci	if (opts.singlethread)
3686881f68fSopenharmony_ci		res = fuse_loop(fuse);
3696881f68fSopenharmony_ci	else {
3706881f68fSopenharmony_ci		loop_config = fuse_loop_cfg_create();
3716881f68fSopenharmony_ci		if (loop_config == NULL) {
3726881f68fSopenharmony_ci			res = 7;
3736881f68fSopenharmony_ci			goto out3;
3746881f68fSopenharmony_ci		}
3756881f68fSopenharmony_ci
3766881f68fSopenharmony_ci		fuse_loop_cfg_set_clone_fd(loop_config, opts.clone_fd);
3776881f68fSopenharmony_ci
3786881f68fSopenharmony_ci		fuse_loop_cfg_set_idle_threads(loop_config, opts.max_idle_threads);
3796881f68fSopenharmony_ci		fuse_loop_cfg_set_max_threads(loop_config, opts.max_threads);
3806881f68fSopenharmony_ci		res = fuse_loop_mt(fuse, loop_config);
3816881f68fSopenharmony_ci	}
3826881f68fSopenharmony_ci	if (res)
3836881f68fSopenharmony_ci		res = 8;
3846881f68fSopenharmony_ci
3856881f68fSopenharmony_ci	fuse_remove_signal_handlers(se);
3866881f68fSopenharmony_ciout3:
3876881f68fSopenharmony_ci	fuse_unmount(fuse);
3886881f68fSopenharmony_ciout2:
3896881f68fSopenharmony_ci	fuse_destroy(fuse);
3906881f68fSopenharmony_ciout1:
3916881f68fSopenharmony_ci	fuse_loop_cfg_destroy(loop_config);
3926881f68fSopenharmony_ci	free(opts.mountpoint);
3936881f68fSopenharmony_ci	fuse_opt_free_args(&args);
3946881f68fSopenharmony_ci	return res;
3956881f68fSopenharmony_ci}
3966881f68fSopenharmony_ci
3976881f68fSopenharmony_ci
3986881f68fSopenharmony_civoid fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
3996881f68fSopenharmony_ci			       struct fuse_conn_info *conn)
4006881f68fSopenharmony_ci{
4016881f68fSopenharmony_ci	if(opts->set_max_write)
4026881f68fSopenharmony_ci		conn->max_write = opts->max_write;
4036881f68fSopenharmony_ci	if(opts->set_max_background)
4046881f68fSopenharmony_ci		conn->max_background = opts->max_background;
4056881f68fSopenharmony_ci	if(opts->set_congestion_threshold)
4066881f68fSopenharmony_ci		conn->congestion_threshold = opts->congestion_threshold;
4076881f68fSopenharmony_ci	if(opts->set_time_gran)
4086881f68fSopenharmony_ci		conn->time_gran = opts->time_gran;
4096881f68fSopenharmony_ci	if(opts->set_max_readahead)
4106881f68fSopenharmony_ci		conn->max_readahead = opts->max_readahead;
4116881f68fSopenharmony_ci
4126881f68fSopenharmony_ci#define LL_ENABLE(cond,cap) \
4136881f68fSopenharmony_ci	if (cond) conn->want |= (cap)
4146881f68fSopenharmony_ci#define LL_DISABLE(cond,cap) \
4156881f68fSopenharmony_ci	if (cond) conn->want &= ~(cap)
4166881f68fSopenharmony_ci
4176881f68fSopenharmony_ci	LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
4186881f68fSopenharmony_ci	LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
4196881f68fSopenharmony_ci
4206881f68fSopenharmony_ci	LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
4216881f68fSopenharmony_ci	LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
4226881f68fSopenharmony_ci
4236881f68fSopenharmony_ci	LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
4246881f68fSopenharmony_ci	LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
4256881f68fSopenharmony_ci
4266881f68fSopenharmony_ci	LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
4276881f68fSopenharmony_ci	LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
4286881f68fSopenharmony_ci
4296881f68fSopenharmony_ci	LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
4306881f68fSopenharmony_ci	LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
4316881f68fSopenharmony_ci
4326881f68fSopenharmony_ci	LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
4336881f68fSopenharmony_ci	LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
4346881f68fSopenharmony_ci
4356881f68fSopenharmony_ci	LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
4366881f68fSopenharmony_ci	LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
4376881f68fSopenharmony_ci
4386881f68fSopenharmony_ci	LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
4396881f68fSopenharmony_ci	LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
4406881f68fSopenharmony_ci
4416881f68fSopenharmony_ci	LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS);
4426881f68fSopenharmony_ci	LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS);
4436881f68fSopenharmony_ci}
4446881f68fSopenharmony_ci
4456881f68fSopenharmony_cistruct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args)
4466881f68fSopenharmony_ci{
4476881f68fSopenharmony_ci	struct fuse_conn_info_opts *opts;
4486881f68fSopenharmony_ci
4496881f68fSopenharmony_ci	opts = calloc(1, sizeof(struct fuse_conn_info_opts));
4506881f68fSopenharmony_ci	if(opts == NULL) {
4516881f68fSopenharmony_ci		fuse_log(FUSE_LOG_ERR, "calloc failed\n");
4526881f68fSopenharmony_ci		return NULL;
4536881f68fSopenharmony_ci	}
4546881f68fSopenharmony_ci	if(fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) {
4556881f68fSopenharmony_ci		free(opts);
4566881f68fSopenharmony_ci		return NULL;
4576881f68fSopenharmony_ci	}
4586881f68fSopenharmony_ci	return opts;
4596881f68fSopenharmony_ci}
4606881f68fSopenharmony_ci
4616881f68fSopenharmony_ciint fuse_open_channel(const char *mountpoint, const char* options)
4626881f68fSopenharmony_ci{
4636881f68fSopenharmony_ci	struct mount_opts *opts = NULL;
4646881f68fSopenharmony_ci	int fd = -1;
4656881f68fSopenharmony_ci	const char *argv[] = { "", "-o", options };
4666881f68fSopenharmony_ci	int argc = sizeof(argv) / sizeof(argv[0]);
4676881f68fSopenharmony_ci	struct fuse_args args = FUSE_ARGS_INIT(argc, (char**) argv);
4686881f68fSopenharmony_ci
4696881f68fSopenharmony_ci	opts = parse_mount_opts(&args);
4706881f68fSopenharmony_ci	if (opts == NULL)
4716881f68fSopenharmony_ci		return -1;
4726881f68fSopenharmony_ci
4736881f68fSopenharmony_ci	fd = fuse_kern_mount(mountpoint, opts);
4746881f68fSopenharmony_ci	destroy_mount_opts(opts);
4756881f68fSopenharmony_ci
4766881f68fSopenharmony_ci	return fd;
4776881f68fSopenharmony_ci}
478