2 CUSE: Character device in Userspace
3 Copyright (C) 2008 SUSE Linux Products GmbH
4 Copyright (C) 2008 Tejun Heo <teheo@suse.de>
6 This program can be distributed under the terms of the GNU LGPLv2.
7 See the file COPYING.LIB.
10 #include "cuse_lowlevel.h"
11 #include "fuse_kernel.h"
23 struct cuse_lowlevel_ops clop
;
28 unsigned dev_info_len
;
32 static struct cuse_lowlevel_ops
*req_clop(fuse_req_t req
)
34 return &req
->f
->cuse_data
->clop
;
37 static void cuse_fll_open(fuse_req_t req
, fuse_ino_t ino
,
38 struct fuse_file_info
*fi
)
41 req_clop(req
)->open(req
, fi
);
44 static void cuse_fll_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
45 off_t off
, struct fuse_file_info
*fi
)
48 req_clop(req
)->read(req
, size
, off
, fi
);
51 static void cuse_fll_write(fuse_req_t req
, fuse_ino_t ino
, const char *buf
,
52 size_t size
, off_t off
, struct fuse_file_info
*fi
)
55 req_clop(req
)->write(req
, buf
, size
, off
, fi
);
58 static void cuse_fll_flush(fuse_req_t req
, fuse_ino_t ino
,
59 struct fuse_file_info
*fi
)
62 req_clop(req
)->flush(req
, fi
);
65 static void cuse_fll_release(fuse_req_t req
, fuse_ino_t ino
,
66 struct fuse_file_info
*fi
)
69 req_clop(req
)->release(req
, fi
);
72 static void cuse_fll_fsync(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
73 struct fuse_file_info
*fi
)
76 req_clop(req
)->fsync(req
, datasync
, fi
);
79 static void cuse_fll_ioctl(fuse_req_t req
, fuse_ino_t ino
, int cmd
, void *arg
,
80 struct fuse_file_info
*fi
, unsigned int flags
,
81 const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
84 req_clop(req
)->ioctl(req
, cmd
, arg
, fi
, flags
, in_buf
, in_bufsz
,
88 static void cuse_fll_poll(fuse_req_t req
, fuse_ino_t ino
,
89 struct fuse_file_info
*fi
, struct fuse_pollhandle
*ph
)
92 req_clop(req
)->poll(req
, fi
, ph
);
95 static size_t cuse_pack_info(int argc
, const char **argv
, char *buf
)
100 for (i
= 0; i
< argc
; i
++) {
103 len
= strlen(argv
[i
]) + 1;
106 memcpy(buf
, argv
[i
], len
);
114 static struct cuse_data
*cuse_prep_data(const struct cuse_info
*ci
,
115 const struct cuse_lowlevel_ops
*clop
)
117 struct cuse_data
*cd
;
120 dev_info_len
= cuse_pack_info(ci
->dev_info_argc
, ci
->dev_info_argv
,
123 if (dev_info_len
> CUSE_INIT_INFO_MAX
) {
124 fprintf(stderr
, "cuse: dev_info (%zu) too large, limit=%u\n",
125 dev_info_len
, CUSE_INIT_INFO_MAX
);
129 cd
= calloc(1, sizeof(*cd
) + dev_info_len
);
131 fprintf(stderr
, "cuse: failed to allocate cuse_data\n");
135 memcpy(&cd
->clop
, clop
, sizeof(cd
->clop
));
136 cd
->max_read
= 131072;
137 cd
->dev_major
= ci
->dev_major
;
138 cd
->dev_minor
= ci
->dev_minor
;
139 cd
->dev_info_len
= dev_info_len
;
140 cd
->flags
= ci
->flags
;
141 cuse_pack_info(ci
->dev_info_argc
, ci
->dev_info_argv
, cd
->dev_info
);
146 struct fuse_session
*cuse_lowlevel_new(struct fuse_args
*args
,
147 const struct cuse_info
*ci
,
148 const struct cuse_lowlevel_ops
*clop
,
151 struct fuse_lowlevel_ops lop
;
152 struct cuse_data
*cd
;
153 struct fuse_session
*se
;
156 cd
= cuse_prep_data(ci
, clop
);
160 memset(&lop
, 0, sizeof(lop
));
161 lop
.init
= clop
->init
;
162 lop
.destroy
= clop
->destroy
;
163 lop
.open
= clop
->open
? cuse_fll_open
: NULL
;
164 lop
.read
= clop
->read
? cuse_fll_read
: NULL
;
165 lop
.write
= clop
->write
? cuse_fll_write
: NULL
;
166 lop
.flush
= clop
->flush
? cuse_fll_flush
: NULL
;
167 lop
.release
= clop
->release
? cuse_fll_release
: NULL
;
168 lop
.fsync
= clop
->fsync
? cuse_fll_fsync
: NULL
;
169 lop
.ioctl
= clop
->ioctl
? cuse_fll_ioctl
: NULL
;
170 lop
.poll
= clop
->poll
? cuse_fll_poll
: NULL
;
172 se
= fuse_lowlevel_new(args
, &lop
, sizeof(lop
), userdata
);
183 static int cuse_reply_init(fuse_req_t req
, struct cuse_init_out
*arg
,
184 char *dev_info
, unsigned dev_info_len
)
188 iov
[1].iov_base
= arg
;
189 iov
[1].iov_len
= sizeof(struct cuse_init_out
);
190 iov
[2].iov_base
= dev_info
;
191 iov
[2].iov_len
= dev_info_len
;
193 return fuse_send_reply_iov_nofree(req
, 0, iov
, 3);
196 void cuse_lowlevel_init(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
198 struct fuse_init_in
*arg
= (struct fuse_init_in
*) inarg
;
199 struct cuse_init_out outarg
;
200 struct fuse_ll
*f
= req
->f
;
201 struct cuse_data
*cd
= f
->cuse_data
;
202 size_t bufsize
= f
->bufsize
;
203 struct cuse_lowlevel_ops
*clop
= req_clop(req
);
207 fprintf(stderr
, "CUSE_INIT: %u.%u\n", arg
->major
, arg
->minor
);
208 fprintf(stderr
, "flags=0x%08x\n", arg
->flags
);
210 f
->conn
.proto_major
= arg
->major
;
211 f
->conn
.proto_minor
= arg
->minor
;
215 if (arg
->major
< 7) {
216 fprintf(stderr
, "cuse: unsupported protocol version: %u.%u\n",
217 arg
->major
, arg
->minor
);
218 fuse_reply_err(req
, EPROTO
);
222 if (bufsize
< FUSE_MIN_READ_BUFFER
) {
223 fprintf(stderr
, "cuse: warning: buffer size too small: %zu\n",
225 bufsize
= FUSE_MIN_READ_BUFFER
;
229 if (bufsize
< f
->conn
.max_write
)
230 f
->conn
.max_write
= bufsize
;
234 f
->op
.init(f
->userdata
, &f
->conn
);
236 memset(&outarg
, 0, sizeof(outarg
));
237 outarg
.major
= FUSE_KERNEL_VERSION
;
238 outarg
.minor
= FUSE_KERNEL_MINOR_VERSION
;
239 outarg
.flags
= cd
->flags
;
240 outarg
.max_read
= cd
->max_read
;
241 outarg
.max_write
= f
->conn
.max_write
;
242 outarg
.dev_major
= cd
->dev_major
;
243 outarg
.dev_minor
= cd
->dev_minor
;
246 fprintf(stderr
, " CUSE_INIT: %u.%u\n",
247 outarg
.major
, outarg
.minor
);
248 fprintf(stderr
, " flags=0x%08x\n", outarg
.flags
);
249 fprintf(stderr
, " max_read=0x%08x\n", outarg
.max_read
);
250 fprintf(stderr
, " max_write=0x%08x\n", outarg
.max_write
);
251 fprintf(stderr
, " dev_major=%u\n", outarg
.dev_major
);
252 fprintf(stderr
, " dev_minor=%u\n", outarg
.dev_minor
);
253 fprintf(stderr
, " dev_info: %.*s\n", cd
->dev_info_len
,
257 cuse_reply_init(req
, &outarg
, cd
->dev_info
, cd
->dev_info_len
);
260 clop
->init_done(f
->userdata
);
265 struct fuse_session
*cuse_lowlevel_setup(int argc
, char *argv
[],
266 const struct cuse_info
*ci
,
267 const struct cuse_lowlevel_ops
*clop
,
268 int *multithreaded
, void *userdata
)
270 const char *devname
= "/dev/cuse";
271 static const struct fuse_opt kill_subtype_opts
[] = {
272 FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD
),
275 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
276 struct fuse_session
*se
;
277 struct fuse_chan
*ch
;
282 res
= fuse_parse_cmdline(&args
, NULL
, multithreaded
, &foreground
);
286 res
= fuse_opt_parse(&args
, NULL
, kill_subtype_opts
, NULL
);
291 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
295 fd
= open("/dev/null", O_RDWR
);
298 } while (fd
>= 0 && fd
<= 2);
300 se
= cuse_lowlevel_new(&args
, ci
, clop
, userdata
);
301 fuse_opt_free_args(&args
);
305 fd
= open(devname
, O_RDWR
);
307 if (errno
== ENODEV
|| errno
== ENOENT
)
308 fprintf(stderr
, "cuse: device not found, try 'modprobe cuse' first\n");
310 fprintf(stderr
, "cuse: failed to open %s: %s\n",
311 devname
, strerror(errno
));
315 ch
= fuse_kern_chan_new(fd
);
321 fuse_session_add_chan(se
, ch
);
323 res
= fuse_set_signal_handlers(se
);
327 res
= fuse_daemonize(foreground
);
334 fuse_remove_signal_handlers(se
);
336 fuse_session_destroy(se
);
338 fuse_opt_free_args(&args
);
342 void cuse_lowlevel_teardown(struct fuse_session
*se
)
344 fuse_remove_signal_handlers(se
);
345 fuse_session_destroy(se
);
348 int cuse_lowlevel_main(int argc
, char *argv
[], const struct cuse_info
*ci
,
349 const struct cuse_lowlevel_ops
*clop
, void *userdata
)
351 struct fuse_session
*se
;
355 se
= cuse_lowlevel_setup(argc
, argv
, ci
, clop
, &multithreaded
,
361 res
= fuse_session_loop_mt(se
);
363 res
= fuse_session_loop(se
);
365 cuse_lowlevel_teardown(se
);