add missing argument check in ulockmgr.c
[fuse.git] / example / cusexmp.c
blob48ccf8c3882ce08c53ff07620d7410bf85350c69
1 /*
2 CUSE example: Character device in Userspace
3 Copyright (C) 2008-2009 SUSE Linux Products GmbH
4 Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
6 This program can be distributed under the terms of the GNU GPL.
7 See the file COPYING.
9 gcc -Wall `pkg-config fuse --cflags --libs` cusexmp.c -o cusexmp
12 #define FUSE_USE_VERSION 29
14 #include <cuse_lowlevel.h>
15 #include <fuse_opt.h>
16 #include <stddef.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <errno.h>
23 #include "fioc.h"
25 static void *cusexmp_buf;
26 static size_t cusexmp_size;
28 static const char *usage =
29 "usage: cusexmp [options]\n"
30 "\n"
31 "options:\n"
32 " --help|-h print this help message\n"
33 " --maj=MAJ|-M MAJ device major number\n"
34 " --min=MIN|-m MIN device minor number\n"
35 " --name=NAME|-n NAME device name (mandatory)\n"
36 "\n";
38 static int cusexmp_resize(size_t new_size)
40 void *new_buf;
42 if (new_size == cusexmp_size)
43 return 0;
45 new_buf = realloc(cusexmp_buf, new_size);
46 if (!new_buf && new_size)
47 return -ENOMEM;
49 if (new_size > cusexmp_size)
50 memset(new_buf + cusexmp_size, 0, new_size - cusexmp_size);
52 cusexmp_buf = new_buf;
53 cusexmp_size = new_size;
55 return 0;
58 static int cusexmp_expand(size_t new_size)
60 if (new_size > cusexmp_size)
61 return cusexmp_resize(new_size);
62 return 0;
65 static void cusexmp_open(fuse_req_t req, struct fuse_file_info *fi)
67 fuse_reply_open(req, fi);
70 static void cusexmp_read(fuse_req_t req, size_t size, off_t off,
71 struct fuse_file_info *fi)
73 (void)fi;
75 if (off >= cusexmp_size)
76 off = cusexmp_size;
77 if (size > cusexmp_size - off)
78 size = cusexmp_size - off;
80 fuse_reply_buf(req, cusexmp_buf + off, size);
83 static void cusexmp_write(fuse_req_t req, const char *buf, size_t size,
84 off_t off, struct fuse_file_info *fi)
86 (void)fi;
88 if (cusexmp_expand(off + size)) {
89 fuse_reply_err(req, ENOMEM);
90 return;
93 memcpy(cusexmp_buf + off, buf, size);
94 fuse_reply_write(req, size);
97 static void fioc_do_rw(fuse_req_t req, void *addr, const void *in_buf,
98 size_t in_bufsz, size_t out_bufsz, int is_read)
100 const struct fioc_rw_arg *arg;
101 struct iovec in_iov[2], out_iov[3], iov[3];
102 size_t cur_size;
104 /* read in arg */
105 in_iov[0].iov_base = addr;
106 in_iov[0].iov_len = sizeof(*arg);
107 if (!in_bufsz) {
108 fuse_reply_ioctl_retry(req, in_iov, 1, NULL, 0);
109 return;
111 arg = in_buf;
112 in_buf += sizeof(*arg);
113 in_bufsz -= sizeof(*arg);
115 /* prepare size outputs */
116 out_iov[0].iov_base =
117 addr + (unsigned long)&(((struct fioc_rw_arg *)0)->prev_size);
118 out_iov[0].iov_len = sizeof(arg->prev_size);
120 out_iov[1].iov_base =
121 addr + (unsigned long)&(((struct fioc_rw_arg *)0)->new_size);
122 out_iov[1].iov_len = sizeof(arg->new_size);
124 /* prepare client buf */
125 if (is_read) {
126 out_iov[2].iov_base = arg->buf;
127 out_iov[2].iov_len = arg->size;
128 if (!out_bufsz) {
129 fuse_reply_ioctl_retry(req, in_iov, 1, out_iov, 3);
130 return;
132 } else {
133 in_iov[1].iov_base = arg->buf;
134 in_iov[1].iov_len = arg->size;
135 if (arg->size && !in_bufsz) {
136 fuse_reply_ioctl_retry(req, in_iov, 2, out_iov, 2);
137 return;
141 /* we're all set */
142 cur_size = cusexmp_size;
143 iov[0].iov_base = &cur_size;
144 iov[0].iov_len = sizeof(cur_size);
146 iov[1].iov_base = &cusexmp_size;
147 iov[1].iov_len = sizeof(cusexmp_size);
149 if (is_read) {
150 size_t off = arg->offset;
151 size_t size = arg->size;
153 if (off >= cusexmp_size)
154 off = cusexmp_size;
155 if (size > cusexmp_size - off)
156 size = cusexmp_size - off;
158 iov[2].iov_base = cusexmp_buf + off;
159 iov[2].iov_len = size;
160 fuse_reply_ioctl_iov(req, size, iov, 3);
161 } else {
162 if (cusexmp_expand(arg->offset + in_bufsz)) {
163 fuse_reply_err(req, ENOMEM);
164 return;
167 memcpy(cusexmp_buf + arg->offset, in_buf, in_bufsz);
168 fuse_reply_ioctl_iov(req, in_bufsz, iov, 2);
172 static void cusexmp_ioctl(fuse_req_t req, int cmd, void *arg,
173 struct fuse_file_info *fi, unsigned flags,
174 const void *in_buf, size_t in_bufsz, size_t out_bufsz)
176 int is_read = 0;
178 (void)fi;
180 if (flags & FUSE_IOCTL_COMPAT) {
181 fuse_reply_err(req, ENOSYS);
182 return;
185 switch (cmd) {
186 case FIOC_GET_SIZE:
187 if (!out_bufsz) {
188 struct iovec iov = { arg, sizeof(size_t) };
190 fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
191 } else
192 fuse_reply_ioctl(req, 0, &cusexmp_size,
193 sizeof(cusexmp_size));
194 break;
196 case FIOC_SET_SIZE:
197 if (!in_bufsz) {
198 struct iovec iov = { arg, sizeof(size_t) };
200 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
201 } else {
202 cusexmp_resize(*(size_t *)in_buf);
203 fuse_reply_ioctl(req, 0, NULL, 0);
205 break;
207 case FIOC_READ:
208 is_read = 1;
209 case FIOC_WRITE:
210 fioc_do_rw(req, arg, in_buf, in_bufsz, out_bufsz, is_read);
211 break;
213 default:
214 fuse_reply_err(req, EINVAL);
218 struct cusexmp_param {
219 unsigned major;
220 unsigned minor;
221 char *dev_name;
222 int is_help;
225 #define CUSEXMP_OPT(t, p) { t, offsetof(struct cusexmp_param, p), 1 }
227 static const struct fuse_opt cusexmp_opts[] = {
228 CUSEXMP_OPT("-M %u", major),
229 CUSEXMP_OPT("--maj=%u", major),
230 CUSEXMP_OPT("-m %u", minor),
231 CUSEXMP_OPT("--min=%u", minor),
232 CUSEXMP_OPT("-n %s", dev_name),
233 CUSEXMP_OPT("--name=%s", dev_name),
234 FUSE_OPT_KEY("-h", 0),
235 FUSE_OPT_KEY("--help", 0),
236 FUSE_OPT_END
239 static int cusexmp_process_arg(void *data, const char *arg, int key,
240 struct fuse_args *outargs)
242 struct cusexmp_param *param = data;
244 (void)outargs;
245 (void)arg;
247 switch (key) {
248 case 0:
249 param->is_help = 1;
250 fprintf(stderr, usage);
251 return fuse_opt_add_arg(outargs, "-ho");
252 default:
253 return 1;
257 static const struct cuse_lowlevel_ops cusexmp_clop = {
258 .open = cusexmp_open,
259 .read = cusexmp_read,
260 .write = cusexmp_write,
261 .ioctl = cusexmp_ioctl,
264 int main(int argc, char **argv)
266 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
267 struct cusexmp_param param = { 0, 0, NULL, 0 };
268 char dev_name[128] = "DEVNAME=";
269 const char *dev_info_argv[] = { dev_name };
270 struct cuse_info ci;
272 if (fuse_opt_parse(&args, &param, cusexmp_opts, cusexmp_process_arg)) {
273 printf("failed to parse option\n");
274 return 1;
277 if (!param.is_help) {
278 if (!param.dev_name) {
279 fprintf(stderr, "Error: device name missing\n");
280 return 1;
282 strncat(dev_name, param.dev_name, sizeof(dev_name) - 9);
285 memset(&ci, 0, sizeof(ci));
286 ci.dev_major = param.major;
287 ci.dev_minor = param.minor;
288 ci.dev_info_argc = 1;
289 ci.dev_info_argv = dev_info_argv;
290 ci.flags = CUSE_UNRESTRICTED_IOCTL;
292 return cuse_lowlevel_main(args.argc, args.argv, &ci, &cusexmp_clop,
293 NULL);