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"
14 #include "fuse_misc.h"
24 struct cuse_lowlevel_ops clop
;
29 unsigned dev_info_len
;
33 static struct cuse_lowlevel_ops
*req_clop(fuse_req_t req
)
35 return &req
->f
->cuse_data
->clop
;
38 static void cuse_fll_open(fuse_req_t req
, fuse_ino_t ino
,
39 struct fuse_file_info
*fi
)
42 req_clop(req
)->open(req
, fi
);
45 static void cuse_fll_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
46 off_t off
, struct fuse_file_info
*fi
)
49 req_clop(req
)->read(req
, size
, off
, fi
);
52 static void cuse_fll_write(fuse_req_t req
, fuse_ino_t ino
, const char *buf
,
53 size_t size
, off_t off
, struct fuse_file_info
*fi
)
56 req_clop(req
)->write(req
, buf
, size
, off
, fi
);
59 static void cuse_fll_flush(fuse_req_t req
, fuse_ino_t ino
,
60 struct fuse_file_info
*fi
)
63 req_clop(req
)->flush(req
, fi
);
66 static void cuse_fll_release(fuse_req_t req
, fuse_ino_t ino
,
67 struct fuse_file_info
*fi
)
70 req_clop(req
)->release(req
, fi
);
73 static void cuse_fll_fsync(fuse_req_t req
, fuse_ino_t ino
, int datasync
,
74 struct fuse_file_info
*fi
)
77 req_clop(req
)->fsync(req
, datasync
, fi
);
80 static void cuse_fll_ioctl(fuse_req_t req
, fuse_ino_t ino
, int cmd
, void *arg
,
81 struct fuse_file_info
*fi
, unsigned int flags
,
82 const void *in_buf
, size_t in_bufsz
, size_t out_bufsz
)
85 req_clop(req
)->ioctl(req
, cmd
, arg
, fi
, flags
, in_buf
, in_bufsz
,
89 static void cuse_fll_poll(fuse_req_t req
, fuse_ino_t ino
,
90 struct fuse_file_info
*fi
, struct fuse_pollhandle
*ph
)
93 req_clop(req
)->poll(req
, fi
, ph
);
96 static size_t cuse_pack_info(int argc
, const char **argv
, char *buf
)
101 for (i
= 0; i
< argc
; i
++) {
104 len
= strlen(argv
[i
]) + 1;
107 memcpy(buf
, argv
[i
], len
);
115 static struct cuse_data
*cuse_prep_data(const struct cuse_info
*ci
,
116 const struct cuse_lowlevel_ops
*clop
)
118 struct cuse_data
*cd
;
121 dev_info_len
= cuse_pack_info(ci
->dev_info_argc
, ci
->dev_info_argv
,
124 if (dev_info_len
> CUSE_INIT_INFO_MAX
) {
125 fprintf(stderr
, "cuse: dev_info (%zu) too large, limit=%u\n",
126 dev_info_len
, CUSE_INIT_INFO_MAX
);
130 cd
= calloc(1, sizeof(*cd
) + dev_info_len
);
132 fprintf(stderr
, "cuse: failed to allocate cuse_data\n");
136 memcpy(&cd
->clop
, clop
, sizeof(cd
->clop
));
137 cd
->max_read
= 131072;
138 cd
->dev_major
= ci
->dev_major
;
139 cd
->dev_minor
= ci
->dev_minor
;
140 cd
->dev_info_len
= dev_info_len
;
141 cd
->flags
= ci
->flags
;
142 cuse_pack_info(ci
->dev_info_argc
, ci
->dev_info_argv
, cd
->dev_info
);
147 struct fuse_session
*cuse_lowlevel_new(struct fuse_args
*args
,
148 const struct cuse_info
*ci
,
149 const struct cuse_lowlevel_ops
*clop
,
152 struct fuse_lowlevel_ops lop
;
153 struct cuse_data
*cd
;
154 struct fuse_session
*se
;
157 cd
= cuse_prep_data(ci
, clop
);
161 memset(&lop
, 0, sizeof(lop
));
162 lop
.init
= clop
->init
;
163 lop
.destroy
= clop
->destroy
;
164 lop
.open
= clop
->open
? cuse_fll_open
: NULL
;
165 lop
.read
= clop
->read
? cuse_fll_read
: NULL
;
166 lop
.write
= clop
->write
? cuse_fll_write
: NULL
;
167 lop
.flush
= clop
->flush
? cuse_fll_flush
: NULL
;
168 lop
.release
= clop
->release
? cuse_fll_release
: NULL
;
169 lop
.fsync
= clop
->fsync
? cuse_fll_fsync
: NULL
;
170 lop
.ioctl
= clop
->ioctl
? cuse_fll_ioctl
: NULL
;
171 lop
.poll
= clop
->poll
? cuse_fll_poll
: NULL
;
173 se
= fuse_lowlevel_new_common(args
, &lop
, sizeof(lop
), userdata
);
184 static int cuse_reply_init(fuse_req_t req
, struct cuse_init_out
*arg
,
185 char *dev_info
, unsigned dev_info_len
)
189 iov
[1].iov_base
= arg
;
190 iov
[1].iov_len
= sizeof(struct cuse_init_out
);
191 iov
[2].iov_base
= dev_info
;
192 iov
[2].iov_len
= dev_info_len
;
194 return fuse_send_reply_iov_nofree(req
, 0, iov
, 3);
197 void cuse_lowlevel_init(fuse_req_t req
, fuse_ino_t nodeid
, const void *inarg
)
199 struct fuse_init_in
*arg
= (struct fuse_init_in
*) inarg
;
200 struct cuse_init_out outarg
;
201 struct fuse_ll
*f
= req
->f
;
202 struct cuse_data
*cd
= f
->cuse_data
;
203 size_t bufsize
= fuse_chan_bufsize(req
->ch
);
204 struct cuse_lowlevel_ops
*clop
= req_clop(req
);
208 fprintf(stderr
, "CUSE_INIT: %u.%u\n", arg
->major
, arg
->minor
);
209 fprintf(stderr
, "flags=0x%08x\n", arg
->flags
);
211 f
->conn
.proto_major
= arg
->major
;
212 f
->conn
.proto_minor
= arg
->minor
;
216 if (arg
->major
< 7) {
217 fprintf(stderr
, "cuse: unsupported protocol version: %u.%u\n",
218 arg
->major
, arg
->minor
);
219 fuse_reply_err(req
, EPROTO
);
223 if (bufsize
< FUSE_MIN_READ_BUFFER
) {
224 fprintf(stderr
, "cuse: warning: buffer size too small: %zu\n",
226 bufsize
= FUSE_MIN_READ_BUFFER
;
230 if (bufsize
< f
->conn
.max_write
)
231 f
->conn
.max_write
= bufsize
;
235 f
->op
.init(f
->userdata
, &f
->conn
);
237 memset(&outarg
, 0, sizeof(outarg
));
238 outarg
.major
= FUSE_KERNEL_VERSION
;
239 outarg
.minor
= FUSE_KERNEL_MINOR_VERSION
;
240 outarg
.flags
= cd
->flags
;
241 outarg
.max_read
= cd
->max_read
;
242 outarg
.max_write
= f
->conn
.max_write
;
243 outarg
.dev_major
= cd
->dev_major
;
244 outarg
.dev_minor
= cd
->dev_minor
;
247 fprintf(stderr
, " CUSE_INIT: %u.%u\n",
248 outarg
.major
, outarg
.minor
);
249 fprintf(stderr
, " flags=0x%08x\n", outarg
.flags
);
250 fprintf(stderr
, " max_read=0x%08x\n", outarg
.max_read
);
251 fprintf(stderr
, " max_write=0x%08x\n", outarg
.max_write
);
252 fprintf(stderr
, " dev_major=%u\n", outarg
.dev_major
);
253 fprintf(stderr
, " dev_minor=%u\n", outarg
.dev_minor
);
254 fprintf(stderr
, " dev_info: %.*s\n", cd
->dev_info_len
,
258 cuse_reply_init(req
, &outarg
, cd
->dev_info
, cd
->dev_info_len
);
261 clop
->init_done(f
->userdata
);
266 struct fuse_session
*cuse_lowlevel_setup(int argc
, char *argv
[],
267 const struct cuse_info
*ci
,
268 const struct cuse_lowlevel_ops
*clop
,
269 int *multithreaded
, void *userdata
)
271 const char *devname
= "/dev/cuse";
272 static const struct fuse_opt kill_subtype_opts
[] = {
273 FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD
),
276 struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
277 struct fuse_session
*se
;
278 struct fuse_chan
*ch
;
283 res
= fuse_parse_cmdline(&args
, NULL
, multithreaded
, &foreground
);
287 res
= fuse_opt_parse(&args
, NULL
, kill_subtype_opts
, NULL
);
292 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
296 fd
= open("/dev/null", O_RDWR
);
299 } while (fd
>= 0 && fd
<= 2);
301 se
= cuse_lowlevel_new(&args
, ci
, clop
, userdata
);
302 fuse_opt_free_args(&args
);
306 fd
= open(devname
, O_RDWR
);
308 if (errno
== ENODEV
|| errno
== ENOENT
)
309 fprintf(stderr
, "cuse: device not found, try 'modprobe cuse' first\n");
311 fprintf(stderr
, "cuse: failed to open %s: %s\n",
312 devname
, strerror(errno
));
316 ch
= fuse_kern_chan_new(fd
);
322 fuse_session_add_chan(se
, ch
);
324 res
= fuse_set_signal_handlers(se
);
328 res
= fuse_daemonize(foreground
);
335 fuse_remove_signal_handlers(se
);
337 fuse_session_destroy(se
);
339 fuse_opt_free_args(&args
);
343 void cuse_lowlevel_teardown(struct fuse_session
*se
)
345 fuse_remove_signal_handlers(se
);
346 fuse_session_destroy(se
);
349 int cuse_lowlevel_main(int argc
, char *argv
[], const struct cuse_info
*ci
,
350 const struct cuse_lowlevel_ops
*clop
, void *userdata
)
352 struct fuse_session
*se
;
356 se
= cuse_lowlevel_setup(argc
, argv
, ci
, clop
, &multithreaded
,
362 res
= fuse_session_loop_mt(se
);
364 res
= fuse_session_loop(se
);
366 cuse_lowlevel_teardown(se
);