xref: /aosp_15_r20/external/libfuse/lib/cuse_lowlevel.c (revision 9e5649576b786774a32d7b0252c9cd8c6538fa49)
1*9e564957SAndroid Build Coastguard Worker /*
2*9e564957SAndroid Build Coastguard Worker   CUSE: Character device in Userspace
3*9e564957SAndroid Build Coastguard Worker   Copyright (C) 2008       SUSE Linux Products GmbH
4*9e564957SAndroid Build Coastguard Worker   Copyright (C) 2008       Tejun Heo <[email protected]>
5*9e564957SAndroid Build Coastguard Worker 
6*9e564957SAndroid Build Coastguard Worker   This program can be distributed under the terms of the GNU LGPLv2.
7*9e564957SAndroid Build Coastguard Worker   See the file COPYING.LIB.
8*9e564957SAndroid Build Coastguard Worker */
9*9e564957SAndroid Build Coastguard Worker 
10*9e564957SAndroid Build Coastguard Worker #include "fuse_config.h"
11*9e564957SAndroid Build Coastguard Worker #include "cuse_lowlevel.h"
12*9e564957SAndroid Build Coastguard Worker #include "fuse_kernel.h"
13*9e564957SAndroid Build Coastguard Worker #include "fuse_i.h"
14*9e564957SAndroid Build Coastguard Worker #include "fuse_opt.h"
15*9e564957SAndroid Build Coastguard Worker 
16*9e564957SAndroid Build Coastguard Worker #include <stdio.h>
17*9e564957SAndroid Build Coastguard Worker #include <string.h>
18*9e564957SAndroid Build Coastguard Worker #include <stdlib.h>
19*9e564957SAndroid Build Coastguard Worker #include <stddef.h>
20*9e564957SAndroid Build Coastguard Worker #include <errno.h>
21*9e564957SAndroid Build Coastguard Worker #include <unistd.h>
22*9e564957SAndroid Build Coastguard Worker 
23*9e564957SAndroid Build Coastguard Worker struct cuse_data {
24*9e564957SAndroid Build Coastguard Worker 	struct cuse_lowlevel_ops	clop;
25*9e564957SAndroid Build Coastguard Worker 	unsigned			max_read;
26*9e564957SAndroid Build Coastguard Worker 	unsigned			dev_major;
27*9e564957SAndroid Build Coastguard Worker 	unsigned			dev_minor;
28*9e564957SAndroid Build Coastguard Worker 	unsigned			flags;
29*9e564957SAndroid Build Coastguard Worker 	unsigned			dev_info_len;
30*9e564957SAndroid Build Coastguard Worker 	char				dev_info[];
31*9e564957SAndroid Build Coastguard Worker };
32*9e564957SAndroid Build Coastguard Worker 
req_clop(fuse_req_t req)33*9e564957SAndroid Build Coastguard Worker static struct cuse_lowlevel_ops *req_clop(fuse_req_t req)
34*9e564957SAndroid Build Coastguard Worker {
35*9e564957SAndroid Build Coastguard Worker 	return &req->se->cuse_data->clop;
36*9e564957SAndroid Build Coastguard Worker }
37*9e564957SAndroid Build Coastguard Worker 
cuse_fll_open(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)38*9e564957SAndroid Build Coastguard Worker static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino,
39*9e564957SAndroid Build Coastguard Worker 			  struct fuse_file_info *fi)
40*9e564957SAndroid Build Coastguard Worker {
41*9e564957SAndroid Build Coastguard Worker 	(void)ino;
42*9e564957SAndroid Build Coastguard Worker 	req_clop(req)->open(req, fi);
43*9e564957SAndroid Build Coastguard Worker }
44*9e564957SAndroid Build Coastguard Worker 
cuse_fll_read(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)45*9e564957SAndroid Build Coastguard Worker static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
46*9e564957SAndroid Build Coastguard Worker 			  off_t off, struct fuse_file_info *fi)
47*9e564957SAndroid Build Coastguard Worker {
48*9e564957SAndroid Build Coastguard Worker 	(void)ino;
49*9e564957SAndroid Build Coastguard Worker 	req_clop(req)->read(req, size, off, fi);
50*9e564957SAndroid Build Coastguard Worker }
51*9e564957SAndroid Build Coastguard Worker 
cuse_fll_write(fuse_req_t req,fuse_ino_t ino,const char * buf,size_t size,off_t off,struct fuse_file_info * fi)52*9e564957SAndroid Build Coastguard Worker static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
53*9e564957SAndroid Build Coastguard Worker 			   size_t size, off_t off, struct fuse_file_info *fi)
54*9e564957SAndroid Build Coastguard Worker {
55*9e564957SAndroid Build Coastguard Worker 	(void)ino;
56*9e564957SAndroid Build Coastguard Worker 	req_clop(req)->write(req, buf, size, off, fi);
57*9e564957SAndroid Build Coastguard Worker }
58*9e564957SAndroid Build Coastguard Worker 
cuse_fll_flush(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)59*9e564957SAndroid Build Coastguard Worker static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino,
60*9e564957SAndroid Build Coastguard Worker 			   struct fuse_file_info *fi)
61*9e564957SAndroid Build Coastguard Worker {
62*9e564957SAndroid Build Coastguard Worker 	(void)ino;
63*9e564957SAndroid Build Coastguard Worker 	req_clop(req)->flush(req, fi);
64*9e564957SAndroid Build Coastguard Worker }
65*9e564957SAndroid Build Coastguard Worker 
cuse_fll_release(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)66*9e564957SAndroid Build Coastguard Worker static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino,
67*9e564957SAndroid Build Coastguard Worker 			     struct fuse_file_info *fi)
68*9e564957SAndroid Build Coastguard Worker {
69*9e564957SAndroid Build Coastguard Worker 	(void)ino;
70*9e564957SAndroid Build Coastguard Worker 	req_clop(req)->release(req, fi);
71*9e564957SAndroid Build Coastguard Worker }
72*9e564957SAndroid Build Coastguard Worker 
cuse_fll_fsync(fuse_req_t req,fuse_ino_t ino,int datasync,struct fuse_file_info * fi)73*9e564957SAndroid Build Coastguard Worker static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
74*9e564957SAndroid Build Coastguard Worker 			   struct fuse_file_info *fi)
75*9e564957SAndroid Build Coastguard Worker {
76*9e564957SAndroid Build Coastguard Worker 	(void)ino;
77*9e564957SAndroid Build Coastguard Worker 	req_clop(req)->fsync(req, datasync, fi);
78*9e564957SAndroid Build Coastguard Worker }
79*9e564957SAndroid Build Coastguard Worker 
cuse_fll_ioctl(fuse_req_t req,fuse_ino_t ino,unsigned int cmd,void * arg,struct fuse_file_info * fi,unsigned int flags,const void * in_buf,size_t in_bufsz,size_t out_bufsz)80*9e564957SAndroid Build Coastguard Worker static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg,
81*9e564957SAndroid Build Coastguard Worker 			   struct fuse_file_info *fi, unsigned int flags,
82*9e564957SAndroid Build Coastguard Worker 			   const void *in_buf, size_t in_bufsz, size_t out_bufsz)
83*9e564957SAndroid Build Coastguard Worker {
84*9e564957SAndroid Build Coastguard Worker 	(void)ino;
85*9e564957SAndroid Build Coastguard Worker 	req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz,
86*9e564957SAndroid Build Coastguard Worker 			     out_bufsz);
87*9e564957SAndroid Build Coastguard Worker }
88*9e564957SAndroid Build Coastguard Worker 
cuse_fll_poll(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi,struct fuse_pollhandle * ph)89*9e564957SAndroid Build Coastguard Worker static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino,
90*9e564957SAndroid Build Coastguard Worker 			  struct fuse_file_info *fi, struct fuse_pollhandle *ph)
91*9e564957SAndroid Build Coastguard Worker {
92*9e564957SAndroid Build Coastguard Worker 	(void)ino;
93*9e564957SAndroid Build Coastguard Worker 	req_clop(req)->poll(req, fi, ph);
94*9e564957SAndroid Build Coastguard Worker }
95*9e564957SAndroid Build Coastguard Worker 
cuse_pack_info(int argc,const char ** argv,char * buf)96*9e564957SAndroid Build Coastguard Worker static size_t cuse_pack_info(int argc, const char **argv, char *buf)
97*9e564957SAndroid Build Coastguard Worker {
98*9e564957SAndroid Build Coastguard Worker 	size_t size = 0;
99*9e564957SAndroid Build Coastguard Worker 	int i;
100*9e564957SAndroid Build Coastguard Worker 
101*9e564957SAndroid Build Coastguard Worker 	for (i = 0; i < argc; i++) {
102*9e564957SAndroid Build Coastguard Worker 		size_t len;
103*9e564957SAndroid Build Coastguard Worker 
104*9e564957SAndroid Build Coastguard Worker 		len = strlen(argv[i]) + 1;
105*9e564957SAndroid Build Coastguard Worker 		size += len;
106*9e564957SAndroid Build Coastguard Worker 		if (buf) {
107*9e564957SAndroid Build Coastguard Worker 			memcpy(buf, argv[i], len);
108*9e564957SAndroid Build Coastguard Worker 			buf += len;
109*9e564957SAndroid Build Coastguard Worker 		}
110*9e564957SAndroid Build Coastguard Worker 	}
111*9e564957SAndroid Build Coastguard Worker 
112*9e564957SAndroid Build Coastguard Worker 	return size;
113*9e564957SAndroid Build Coastguard Worker }
114*9e564957SAndroid Build Coastguard Worker 
cuse_prep_data(const struct cuse_info * ci,const struct cuse_lowlevel_ops * clop)115*9e564957SAndroid Build Coastguard Worker static struct cuse_data *cuse_prep_data(const struct cuse_info *ci,
116*9e564957SAndroid Build Coastguard Worker 					const struct cuse_lowlevel_ops *clop)
117*9e564957SAndroid Build Coastguard Worker {
118*9e564957SAndroid Build Coastguard Worker 	struct cuse_data *cd;
119*9e564957SAndroid Build Coastguard Worker 	size_t dev_info_len;
120*9e564957SAndroid Build Coastguard Worker 
121*9e564957SAndroid Build Coastguard Worker 	dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv,
122*9e564957SAndroid Build Coastguard Worker 				      NULL);
123*9e564957SAndroid Build Coastguard Worker 
124*9e564957SAndroid Build Coastguard Worker 	if (dev_info_len > CUSE_INIT_INFO_MAX) {
125*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "cuse: dev_info (%zu) too large, limit=%u\n",
126*9e564957SAndroid Build Coastguard Worker 			dev_info_len, CUSE_INIT_INFO_MAX);
127*9e564957SAndroid Build Coastguard Worker 		return NULL;
128*9e564957SAndroid Build Coastguard Worker 	}
129*9e564957SAndroid Build Coastguard Worker 
130*9e564957SAndroid Build Coastguard Worker 	cd = calloc(1, sizeof(*cd) + dev_info_len);
131*9e564957SAndroid Build Coastguard Worker 	if (!cd) {
132*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "cuse: failed to allocate cuse_data\n");
133*9e564957SAndroid Build Coastguard Worker 		return NULL;
134*9e564957SAndroid Build Coastguard Worker 	}
135*9e564957SAndroid Build Coastguard Worker 
136*9e564957SAndroid Build Coastguard Worker 	memcpy(&cd->clop, clop, sizeof(cd->clop));
137*9e564957SAndroid Build Coastguard Worker 	cd->max_read = 131072;
138*9e564957SAndroid Build Coastguard Worker 	cd->dev_major = ci->dev_major;
139*9e564957SAndroid Build Coastguard Worker 	cd->dev_minor = ci->dev_minor;
140*9e564957SAndroid Build Coastguard Worker 	cd->dev_info_len = dev_info_len;
141*9e564957SAndroid Build Coastguard Worker 	cd->flags = ci->flags;
142*9e564957SAndroid Build Coastguard Worker 	cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info);
143*9e564957SAndroid Build Coastguard Worker 
144*9e564957SAndroid Build Coastguard Worker 	return cd;
145*9e564957SAndroid Build Coastguard Worker }
146*9e564957SAndroid Build Coastguard Worker 
cuse_lowlevel_new(struct fuse_args * args,const struct cuse_info * ci,const struct cuse_lowlevel_ops * clop,void * userdata)147*9e564957SAndroid Build Coastguard Worker struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
148*9e564957SAndroid Build Coastguard Worker 				       const struct cuse_info *ci,
149*9e564957SAndroid Build Coastguard Worker 				       const struct cuse_lowlevel_ops *clop,
150*9e564957SAndroid Build Coastguard Worker 				       void *userdata)
151*9e564957SAndroid Build Coastguard Worker {
152*9e564957SAndroid Build Coastguard Worker 	struct fuse_lowlevel_ops lop;
153*9e564957SAndroid Build Coastguard Worker 	struct cuse_data *cd;
154*9e564957SAndroid Build Coastguard Worker 	struct fuse_session *se;
155*9e564957SAndroid Build Coastguard Worker 
156*9e564957SAndroid Build Coastguard Worker 	cd = cuse_prep_data(ci, clop);
157*9e564957SAndroid Build Coastguard Worker 	if (!cd)
158*9e564957SAndroid Build Coastguard Worker 		return NULL;
159*9e564957SAndroid Build Coastguard Worker 
160*9e564957SAndroid Build Coastguard Worker 	memset(&lop, 0, sizeof(lop));
161*9e564957SAndroid Build Coastguard Worker 	lop.init	= clop->init;
162*9e564957SAndroid Build Coastguard Worker 	lop.destroy	= clop->destroy;
163*9e564957SAndroid Build Coastguard Worker 	lop.open	= clop->open		? cuse_fll_open		: NULL;
164*9e564957SAndroid Build Coastguard Worker 	lop.read	= clop->read		? cuse_fll_read		: NULL;
165*9e564957SAndroid Build Coastguard Worker 	lop.write	= clop->write		? cuse_fll_write	: NULL;
166*9e564957SAndroid Build Coastguard Worker 	lop.flush	= clop->flush		? cuse_fll_flush	: NULL;
167*9e564957SAndroid Build Coastguard Worker 	lop.release	= clop->release		? cuse_fll_release	: NULL;
168*9e564957SAndroid Build Coastguard Worker 	lop.fsync	= clop->fsync		? cuse_fll_fsync	: NULL;
169*9e564957SAndroid Build Coastguard Worker 	lop.ioctl	= clop->ioctl		? cuse_fll_ioctl	: NULL;
170*9e564957SAndroid Build Coastguard Worker 	lop.poll	= clop->poll		? cuse_fll_poll		: NULL;
171*9e564957SAndroid Build Coastguard Worker 
172*9e564957SAndroid Build Coastguard Worker 	se = fuse_session_new(args, &lop, sizeof(lop), userdata);
173*9e564957SAndroid Build Coastguard Worker 	if (!se) {
174*9e564957SAndroid Build Coastguard Worker 		free(cd);
175*9e564957SAndroid Build Coastguard Worker 		return NULL;
176*9e564957SAndroid Build Coastguard Worker 	}
177*9e564957SAndroid Build Coastguard Worker 	se->cuse_data = cd;
178*9e564957SAndroid Build Coastguard Worker 
179*9e564957SAndroid Build Coastguard Worker 	return se;
180*9e564957SAndroid Build Coastguard Worker }
181*9e564957SAndroid Build Coastguard Worker 
cuse_reply_init(fuse_req_t req,struct cuse_init_out * arg,char * dev_info,unsigned dev_info_len)182*9e564957SAndroid Build Coastguard Worker static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg,
183*9e564957SAndroid Build Coastguard Worker 			   char *dev_info, unsigned dev_info_len)
184*9e564957SAndroid Build Coastguard Worker {
185*9e564957SAndroid Build Coastguard Worker 	struct iovec iov[3];
186*9e564957SAndroid Build Coastguard Worker 
187*9e564957SAndroid Build Coastguard Worker 	iov[1].iov_base = arg;
188*9e564957SAndroid Build Coastguard Worker 	iov[1].iov_len = sizeof(struct cuse_init_out);
189*9e564957SAndroid Build Coastguard Worker 	iov[2].iov_base = dev_info;
190*9e564957SAndroid Build Coastguard Worker 	iov[2].iov_len = dev_info_len;
191*9e564957SAndroid Build Coastguard Worker 
192*9e564957SAndroid Build Coastguard Worker 	return fuse_send_reply_iov_nofree(req, 0, iov, 3);
193*9e564957SAndroid Build Coastguard Worker }
194*9e564957SAndroid Build Coastguard Worker 
cuse_lowlevel_init(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)195*9e564957SAndroid Build Coastguard Worker void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
196*9e564957SAndroid Build Coastguard Worker {
197*9e564957SAndroid Build Coastguard Worker 	struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
198*9e564957SAndroid Build Coastguard Worker 	struct cuse_init_out outarg;
199*9e564957SAndroid Build Coastguard Worker 	struct fuse_session *se = req->se;
200*9e564957SAndroid Build Coastguard Worker 	struct cuse_data *cd = se->cuse_data;
201*9e564957SAndroid Build Coastguard Worker 	size_t bufsize = se->bufsize;
202*9e564957SAndroid Build Coastguard Worker 	struct cuse_lowlevel_ops *clop = req_clop(req);
203*9e564957SAndroid Build Coastguard Worker 
204*9e564957SAndroid Build Coastguard Worker 	(void) nodeid;
205*9e564957SAndroid Build Coastguard Worker 	if (se->debug) {
206*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "CUSE_INIT: %u.%u\n", arg->major, arg->minor);
207*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
208*9e564957SAndroid Build Coastguard Worker 	}
209*9e564957SAndroid Build Coastguard Worker 	se->conn.proto_major = arg->major;
210*9e564957SAndroid Build Coastguard Worker 	se->conn.proto_minor = arg->minor;
211*9e564957SAndroid Build Coastguard Worker 	se->conn.capable = 0;
212*9e564957SAndroid Build Coastguard Worker 	se->conn.want = 0;
213*9e564957SAndroid Build Coastguard Worker 
214*9e564957SAndroid Build Coastguard Worker 	if (arg->major < 7) {
215*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "cuse: unsupported protocol version: %u.%u\n",
216*9e564957SAndroid Build Coastguard Worker 			arg->major, arg->minor);
217*9e564957SAndroid Build Coastguard Worker 		fuse_reply_err(req, EPROTO);
218*9e564957SAndroid Build Coastguard Worker 		return;
219*9e564957SAndroid Build Coastguard Worker 	}
220*9e564957SAndroid Build Coastguard Worker 
221*9e564957SAndroid Build Coastguard Worker 	if (bufsize < FUSE_MIN_READ_BUFFER) {
222*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "cuse: warning: buffer size too small: %zu\n",
223*9e564957SAndroid Build Coastguard Worker 			bufsize);
224*9e564957SAndroid Build Coastguard Worker 		bufsize = FUSE_MIN_READ_BUFFER;
225*9e564957SAndroid Build Coastguard Worker 	}
226*9e564957SAndroid Build Coastguard Worker 
227*9e564957SAndroid Build Coastguard Worker 	bufsize -= 4096;
228*9e564957SAndroid Build Coastguard Worker 	if (bufsize < se->conn.max_write)
229*9e564957SAndroid Build Coastguard Worker 		se->conn.max_write = bufsize;
230*9e564957SAndroid Build Coastguard Worker 
231*9e564957SAndroid Build Coastguard Worker 	se->got_init = 1;
232*9e564957SAndroid Build Coastguard Worker 	if (se->op.init)
233*9e564957SAndroid Build Coastguard Worker 		se->op.init(se->userdata, &se->conn);
234*9e564957SAndroid Build Coastguard Worker 
235*9e564957SAndroid Build Coastguard Worker 	memset(&outarg, 0, sizeof(outarg));
236*9e564957SAndroid Build Coastguard Worker 	outarg.major = FUSE_KERNEL_VERSION;
237*9e564957SAndroid Build Coastguard Worker 	outarg.minor = FUSE_KERNEL_MINOR_VERSION;
238*9e564957SAndroid Build Coastguard Worker 	outarg.flags = cd->flags;
239*9e564957SAndroid Build Coastguard Worker 	outarg.max_read = cd->max_read;
240*9e564957SAndroid Build Coastguard Worker 	outarg.max_write = se->conn.max_write;
241*9e564957SAndroid Build Coastguard Worker 	outarg.dev_major = cd->dev_major;
242*9e564957SAndroid Build Coastguard Worker 	outarg.dev_minor = cd->dev_minor;
243*9e564957SAndroid Build Coastguard Worker 
244*9e564957SAndroid Build Coastguard Worker 	if (se->debug) {
245*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "   CUSE_INIT: %u.%u\n",
246*9e564957SAndroid Build Coastguard Worker 			outarg.major, outarg.minor);
247*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "   flags=0x%08x\n", outarg.flags);
248*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "   max_read=0x%08x\n", outarg.max_read);
249*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "   max_write=0x%08x\n", outarg.max_write);
250*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "   dev_major=%u\n", outarg.dev_major);
251*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "   dev_minor=%u\n", outarg.dev_minor);
252*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_DEBUG, "   dev_info: %.*s\n", cd->dev_info_len,
253*9e564957SAndroid Build Coastguard Worker 			cd->dev_info);
254*9e564957SAndroid Build Coastguard Worker 	}
255*9e564957SAndroid Build Coastguard Worker 
256*9e564957SAndroid Build Coastguard Worker 	cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len);
257*9e564957SAndroid Build Coastguard Worker 
258*9e564957SAndroid Build Coastguard Worker 	if (clop->init_done)
259*9e564957SAndroid Build Coastguard Worker 		clop->init_done(se->userdata);
260*9e564957SAndroid Build Coastguard Worker 
261*9e564957SAndroid Build Coastguard Worker 	fuse_free_req(req);
262*9e564957SAndroid Build Coastguard Worker }
263*9e564957SAndroid Build Coastguard Worker 
cuse_lowlevel_setup(int argc,char * argv[],const struct cuse_info * ci,const struct cuse_lowlevel_ops * clop,int * multithreaded,void * userdata)264*9e564957SAndroid Build Coastguard Worker struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
265*9e564957SAndroid Build Coastguard Worker 					 const struct cuse_info *ci,
266*9e564957SAndroid Build Coastguard Worker 					 const struct cuse_lowlevel_ops *clop,
267*9e564957SAndroid Build Coastguard Worker 					 int *multithreaded, void *userdata)
268*9e564957SAndroid Build Coastguard Worker {
269*9e564957SAndroid Build Coastguard Worker 	const char *devname = "/dev/cuse";
270*9e564957SAndroid Build Coastguard Worker 	static const struct fuse_opt kill_subtype_opts[] = {
271*9e564957SAndroid Build Coastguard Worker 		FUSE_OPT_KEY("subtype=",  FUSE_OPT_KEY_DISCARD),
272*9e564957SAndroid Build Coastguard Worker 		FUSE_OPT_END
273*9e564957SAndroid Build Coastguard Worker 	};
274*9e564957SAndroid Build Coastguard Worker 	struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
275*9e564957SAndroid Build Coastguard Worker 	struct fuse_session *se;
276*9e564957SAndroid Build Coastguard Worker 	struct fuse_cmdline_opts opts;
277*9e564957SAndroid Build Coastguard Worker 	int fd;
278*9e564957SAndroid Build Coastguard Worker 	int res;
279*9e564957SAndroid Build Coastguard Worker 
280*9e564957SAndroid Build Coastguard Worker 	if (fuse_parse_cmdline(&args, &opts) == -1)
281*9e564957SAndroid Build Coastguard Worker 		return NULL;
282*9e564957SAndroid Build Coastguard Worker 	*multithreaded = !opts.singlethread;
283*9e564957SAndroid Build Coastguard Worker 
284*9e564957SAndroid Build Coastguard Worker 	/* Remove subtype= option */
285*9e564957SAndroid Build Coastguard Worker 	res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL);
286*9e564957SAndroid Build Coastguard Worker 	if (res == -1)
287*9e564957SAndroid Build Coastguard Worker 		goto out1;
288*9e564957SAndroid Build Coastguard Worker 
289*9e564957SAndroid Build Coastguard Worker 	/*
290*9e564957SAndroid Build Coastguard Worker 	 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
291*9e564957SAndroid Build Coastguard Worker 	 * would ensue.
292*9e564957SAndroid Build Coastguard Worker 	 */
293*9e564957SAndroid Build Coastguard Worker 	do {
294*9e564957SAndroid Build Coastguard Worker 		fd = open("/dev/null", O_RDWR);
295*9e564957SAndroid Build Coastguard Worker 		if (fd > 2)
296*9e564957SAndroid Build Coastguard Worker 			close(fd);
297*9e564957SAndroid Build Coastguard Worker 	} while (fd >= 0 && fd <= 2);
298*9e564957SAndroid Build Coastguard Worker 
299*9e564957SAndroid Build Coastguard Worker 	se = cuse_lowlevel_new(&args, ci, clop, userdata);
300*9e564957SAndroid Build Coastguard Worker 	if (se == NULL)
301*9e564957SAndroid Build Coastguard Worker 		goto out1;
302*9e564957SAndroid Build Coastguard Worker 
303*9e564957SAndroid Build Coastguard Worker 	fd = open(devname, O_RDWR);
304*9e564957SAndroid Build Coastguard Worker 	if (fd == -1) {
305*9e564957SAndroid Build Coastguard Worker 		if (errno == ENODEV || errno == ENOENT)
306*9e564957SAndroid Build Coastguard Worker 			fuse_log(FUSE_LOG_ERR, "cuse: device not found, try 'modprobe cuse' first\n");
307*9e564957SAndroid Build Coastguard Worker 		else
308*9e564957SAndroid Build Coastguard Worker 			fuse_log(FUSE_LOG_ERR, "cuse: failed to open %s: %s\n",
309*9e564957SAndroid Build Coastguard Worker 				devname, strerror(errno));
310*9e564957SAndroid Build Coastguard Worker 		goto err_se;
311*9e564957SAndroid Build Coastguard Worker 	}
312*9e564957SAndroid Build Coastguard Worker 	se->fd = fd;
313*9e564957SAndroid Build Coastguard Worker 
314*9e564957SAndroid Build Coastguard Worker 	res = fuse_set_signal_handlers(se);
315*9e564957SAndroid Build Coastguard Worker 	if (res == -1)
316*9e564957SAndroid Build Coastguard Worker 		goto err_se;
317*9e564957SAndroid Build Coastguard Worker 
318*9e564957SAndroid Build Coastguard Worker 	res = fuse_daemonize(opts.foreground);
319*9e564957SAndroid Build Coastguard Worker 	if (res == -1)
320*9e564957SAndroid Build Coastguard Worker 		goto err_sig;
321*9e564957SAndroid Build Coastguard Worker 
322*9e564957SAndroid Build Coastguard Worker 	fuse_opt_free_args(&args);
323*9e564957SAndroid Build Coastguard Worker 	return se;
324*9e564957SAndroid Build Coastguard Worker 
325*9e564957SAndroid Build Coastguard Worker err_sig:
326*9e564957SAndroid Build Coastguard Worker 	fuse_remove_signal_handlers(se);
327*9e564957SAndroid Build Coastguard Worker err_se:
328*9e564957SAndroid Build Coastguard Worker 	fuse_session_destroy(se);
329*9e564957SAndroid Build Coastguard Worker out1:
330*9e564957SAndroid Build Coastguard Worker 	free(opts.mountpoint);
331*9e564957SAndroid Build Coastguard Worker 	fuse_opt_free_args(&args);
332*9e564957SAndroid Build Coastguard Worker 	return NULL;
333*9e564957SAndroid Build Coastguard Worker }
334*9e564957SAndroid Build Coastguard Worker 
cuse_lowlevel_teardown(struct fuse_session * se)335*9e564957SAndroid Build Coastguard Worker void cuse_lowlevel_teardown(struct fuse_session *se)
336*9e564957SAndroid Build Coastguard Worker {
337*9e564957SAndroid Build Coastguard Worker 	fuse_remove_signal_handlers(se);
338*9e564957SAndroid Build Coastguard Worker 	fuse_session_destroy(se);
339*9e564957SAndroid Build Coastguard Worker }
340*9e564957SAndroid Build Coastguard Worker 
cuse_lowlevel_main(int argc,char * argv[],const struct cuse_info * ci,const struct cuse_lowlevel_ops * clop,void * userdata)341*9e564957SAndroid Build Coastguard Worker int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
342*9e564957SAndroid Build Coastguard Worker 		       const struct cuse_lowlevel_ops *clop, void *userdata)
343*9e564957SAndroid Build Coastguard Worker {
344*9e564957SAndroid Build Coastguard Worker 	struct fuse_session *se;
345*9e564957SAndroid Build Coastguard Worker 	int multithreaded;
346*9e564957SAndroid Build Coastguard Worker 	int res;
347*9e564957SAndroid Build Coastguard Worker 
348*9e564957SAndroid Build Coastguard Worker 	se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded,
349*9e564957SAndroid Build Coastguard Worker 				 userdata);
350*9e564957SAndroid Build Coastguard Worker 	if (se == NULL)
351*9e564957SAndroid Build Coastguard Worker 		return 1;
352*9e564957SAndroid Build Coastguard Worker 
353*9e564957SAndroid Build Coastguard Worker 	if (multithreaded) {
354*9e564957SAndroid Build Coastguard Worker 		struct fuse_loop_config *config = fuse_loop_cfg_create();
355*9e564957SAndroid Build Coastguard Worker 		res = fuse_session_loop_mt(se, config);
356*9e564957SAndroid Build Coastguard Worker 		fuse_loop_cfg_destroy(config);
357*9e564957SAndroid Build Coastguard Worker 	}
358*9e564957SAndroid Build Coastguard Worker 	else
359*9e564957SAndroid Build Coastguard Worker 		res = fuse_session_loop(se);
360*9e564957SAndroid Build Coastguard Worker 
361*9e564957SAndroid Build Coastguard Worker 	cuse_lowlevel_teardown(se);
362*9e564957SAndroid Build Coastguard Worker 	if (res == -1)
363*9e564957SAndroid Build Coastguard Worker 		return 1;
364*9e564957SAndroid Build Coastguard Worker 
365*9e564957SAndroid Build Coastguard Worker 	return 0;
366*9e564957SAndroid Build Coastguard Worker }
367