34#define FUSE_USE_VERSION 31
36#include <cuse_lowlevel.h>
47static void *cusexmp_buf;
48static size_t cusexmp_size;
50static const char *usage =
51"usage: cusexmp [options]\n"
54" --help|-h print this help message\n"
55" --maj=MAJ|-M MAJ device major number\n"
56" --min=MIN|-m MIN device minor number\n"
57" --name=NAME|-n NAME device name (mandatory)\n"
58" -d -o debug enable debug output (implies -f)\n"
59" -f foreground operation\n"
60" -s disable multi-threaded operation\n"
63static int cusexmp_resize(
size_t new_size)
67 if (new_size == cusexmp_size)
70 new_buf = realloc(cusexmp_buf, new_size);
71 if (!new_buf && new_size)
74 if (new_size > cusexmp_size)
75 memset(new_buf + cusexmp_size, 0, new_size - cusexmp_size);
77 cusexmp_buf = new_buf;
78 cusexmp_size = new_size;
83static int cusexmp_expand(
size_t new_size)
85 if (new_size > cusexmp_size)
86 return cusexmp_resize(new_size);
90static void cusexmp_init(
void *userdata,
struct fuse_conn_info *conn)
103static void cusexmp_read(
fuse_req_t req,
size_t size, off_t off,
108 if (off >= cusexmp_size)
110 if (size > cusexmp_size - off)
111 size = cusexmp_size - off;
116static void cusexmp_write(
fuse_req_t req,
const char *buf,
size_t size,
121 if (cusexmp_expand(off + size)) {
126 memcpy(cusexmp_buf + off, buf, size);
130static void fioc_do_rw(
fuse_req_t req,
void *addr,
const void *in_buf,
131 size_t in_bufsz,
size_t out_bufsz,
int is_read)
133 const struct fioc_rw_arg *arg;
134 struct iovec in_iov[2], out_iov[3], iov[3];
138 in_iov[0].iov_base = addr;
139 in_iov[0].iov_len =
sizeof(*arg);
145 in_buf +=
sizeof(*arg);
146 in_bufsz -=
sizeof(*arg);
149 out_iov[0].iov_base =
150 addr + offsetof(
struct fioc_rw_arg, prev_size);
151 out_iov[0].iov_len =
sizeof(arg->prev_size);
153 out_iov[1].iov_base =
154 addr + offsetof(
struct fioc_rw_arg, new_size);
155 out_iov[1].iov_len =
sizeof(arg->new_size);
159 out_iov[2].iov_base = arg->buf;
160 out_iov[2].iov_len = arg->size;
166 in_iov[1].iov_base = arg->buf;
167 in_iov[1].iov_len = arg->size;
168 if (arg->size && !in_bufsz) {
175 cur_size = cusexmp_size;
176 iov[0].iov_base = &cur_size;
177 iov[0].iov_len =
sizeof(cur_size);
179 iov[1].iov_base = &cusexmp_size;
180 iov[1].iov_len =
sizeof(cusexmp_size);
183 size_t off = arg->offset;
184 size_t size = arg->size;
186 if (off >= cusexmp_size)
188 if (size > cusexmp_size - off)
189 size = cusexmp_size - off;
191 iov[2].iov_base = cusexmp_buf + off;
192 iov[2].iov_len = size;
195 if (cusexmp_expand(arg->offset + in_bufsz)) {
200 memcpy(cusexmp_buf + arg->offset, in_buf, in_bufsz);
205static void cusexmp_ioctl(
fuse_req_t req,
int cmd,
void *arg,
207 const void *in_buf,
size_t in_bufsz,
size_t out_bufsz)
221 struct iovec iov = { arg,
sizeof(size_t) };
226 sizeof(cusexmp_size));
231 struct iovec iov = { arg,
sizeof(size_t) };
235 cusexmp_resize(*(
size_t *)in_buf);
244 fioc_do_rw(req, arg, in_buf, in_bufsz, out_bufsz, is_read);
252struct cusexmp_param {
259#define CUSEXMP_OPT(t, p) { t, offsetof(struct cusexmp_param, p), 1 }
261static const struct fuse_opt cusexmp_opts[] = {
262 CUSEXMP_OPT(
"-M %u", major),
263 CUSEXMP_OPT(
"--maj=%u", major),
264 CUSEXMP_OPT(
"-m %u", minor),
265 CUSEXMP_OPT(
"--min=%u", minor),
266 CUSEXMP_OPT(
"-n %s", dev_name),
267 CUSEXMP_OPT(
"--name=%s", dev_name),
273static int cusexmp_process_arg(
void *data,
const char *arg,
int key,
276 struct cusexmp_param *param = data;
284 fprintf(stderr,
"%s", usage);
291static const struct cuse_lowlevel_ops cusexmp_clop = {
292 .init = cusexmp_init,
293 .open = cusexmp_open,
294 .read = cusexmp_read,
295 .write = cusexmp_write,
296 .ioctl = cusexmp_ioctl,
299int main(
int argc,
char **argv)
302 struct cusexmp_param param = { 0, 0, NULL, 0 };
303 char dev_name[128] =
"DEVNAME=";
304 const char *dev_info_argv[] = { dev_name };
308 if (
fuse_opt_parse(&args, ¶m, cusexmp_opts, cusexmp_process_arg)) {
309 printf(
"failed to parse option\n");
310 free(param.dev_name);
314 if (!param.is_help) {
315 if (!param.dev_name) {
316 fprintf(stderr,
"Error: device name missing\n");
319 strncat(dev_name, param.dev_name,
sizeof(dev_name) -
sizeof(
"DEVNAME="));
320 free(param.dev_name);
323 memset(&ci, 0,
sizeof(ci));
324 ci.dev_major = param.major;
325 ci.dev_minor = param.minor;
326 ci.dev_info_argc = 1;
327 ci.dev_info_argv = dev_info_argv;
328 ci.flags = CUSE_UNRESTRICTED_IOCTL;
330 ret = cuse_lowlevel_main(args.
argc, args.
argv, &ci, &cusexmp_clop, NULL);
#define FUSE_IOCTL_COMPAT
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
int fuse_reply_err(fuse_req_t req, int err)
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
struct fuse_req * fuse_req_t
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
int fuse_reply_write(fuse_req_t req, size_t count)
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
void fuse_opt_free_args(struct fuse_args *args)
#define FUSE_OPT_KEY(templ, key)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
#define FUSE_ARGS_INIT(argc, argv)