"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.10.4/doc/html/fuse-3_810_83_2example_2cuse_8c_source.html" (9 Jun 2021, 54080 Bytes) of package /linux/misc/fuse-3.10.4.tar.xz:


Caution: In this restricted "Fossies" environment the current HTML page may not be correctly presentated and may have some non-functional links. You can here alternatively try to browse the pure source code or just view or download the uninterpreted raw source code. If the rendering is insufficient you may try to find and view the page on the project site itself.

libfuse
cuse.c
Go to the documentation of this file.
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>
5 
6  This program can be distributed under the terms of the GNU GPLv2.
7  See the file COPYING.
8 
9 */
10 
34 #define FUSE_USE_VERSION 31
35 
36 #include <cuse_lowlevel.h>
37 #include <fuse_opt.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <errno.h>
44 
45 #include "ioctl.h"
46 
47 static void *cusexmp_buf;
48 static size_t cusexmp_size;
49 
50 static const char *usage =
51 "usage: cusexmp [options]\n"
52 "\n"
53 "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"
61 "\n";
62 
63 static int cusexmp_resize(size_t new_size)
64 {
65  void *new_buf;
66 
67  if (new_size == cusexmp_size)
68  return 0;
69 
70  new_buf = realloc(cusexmp_buf, new_size);
71  if (!new_buf && new_size)
72  return -ENOMEM;
73 
74  if (new_size > cusexmp_size)
75  memset(new_buf + cusexmp_size, 0, new_size - cusexmp_size);
76 
77  cusexmp_buf = new_buf;
78  cusexmp_size = new_size;
79 
80  return 0;
81 }
82 
83 static int cusexmp_expand(size_t new_size)
84 {
85  if (new_size > cusexmp_size)
86  return cusexmp_resize(new_size);
87  return 0;
88 }
89 
90 static void cusexmp_open(fuse_req_t req, struct fuse_file_info *fi)
91 {
92  fuse_reply_open(req, fi);
93 }
94 
95 static void cusexmp_read(fuse_req_t req, size_t size, off_t off,
96  struct fuse_file_info *fi)
97 {
98  (void)fi;
99 
100  if (off >= cusexmp_size)
101  off = cusexmp_size;
102  if (size > cusexmp_size - off)
103  size = cusexmp_size - off;
104 
105  fuse_reply_buf(req, cusexmp_buf + off, size);
106 }
107 
108 static void cusexmp_write(fuse_req_t req, const char *buf, size_t size,
109  off_t off, struct fuse_file_info *fi)
110 {
111  (void)fi;
112 
113  if (cusexmp_expand(off + size)) {
114  fuse_reply_err(req, ENOMEM);
115  return;
116  }
117 
118  memcpy(cusexmp_buf + off, buf, size);
119  fuse_reply_write(req, size);
120 }
121 
122 static void fioc_do_rw(fuse_req_t req, void *addr, const void *in_buf,
123  size_t in_bufsz, size_t out_bufsz, int is_read)
124 {
125  const struct fioc_rw_arg *arg;
126  struct iovec in_iov[2], out_iov[3], iov[3];
127  size_t cur_size;
128 
129  /* read in arg */
130  in_iov[0].iov_base = addr;
131  in_iov[0].iov_len = sizeof(*arg);
132  if (!in_bufsz) {
133  fuse_reply_ioctl_retry(req, in_iov, 1, NULL, 0);
134  return;
135  }
136  arg = in_buf;
137  in_buf += sizeof(*arg);
138  in_bufsz -= sizeof(*arg);
139 
140  /* prepare size outputs */
141  out_iov[0].iov_base =
142  addr + offsetof(struct fioc_rw_arg, prev_size);
143  out_iov[0].iov_len = sizeof(arg->prev_size);
144 
145  out_iov[1].iov_base =
146  addr + offsetof(struct fioc_rw_arg, new_size);
147  out_iov[1].iov_len = sizeof(arg->new_size);
148 
149  /* prepare client buf */
150  if (is_read) {
151  out_iov[2].iov_base = arg->buf;
152  out_iov[2].iov_len = arg->size;
153  if (!out_bufsz) {
154  fuse_reply_ioctl_retry(req, in_iov, 1, out_iov, 3);
155  return;
156  }
157  } else {
158  in_iov[1].iov_base = arg->buf;
159  in_iov[1].iov_len = arg->size;
160  if (arg->size && !in_bufsz) {
161  fuse_reply_ioctl_retry(req, in_iov, 2, out_iov, 2);
162  return;
163  }
164  }
165 
166  /* we're all set */
167  cur_size = cusexmp_size;
168  iov[0].iov_base = &cur_size;
169  iov[0].iov_len = sizeof(cur_size);
170 
171  iov[1].iov_base = &cusexmp_size;
172  iov[1].iov_len = sizeof(cusexmp_size);
173 
174  if (is_read) {
175  size_t off = arg->offset;
176  size_t size = arg->size;
177 
178  if (off >= cusexmp_size)
179  off = cusexmp_size;
180  if (size > cusexmp_size - off)
181  size = cusexmp_size - off;
182 
183  iov[2].iov_base = cusexmp_buf + off;
184  iov[2].iov_len = size;
185  fuse_reply_ioctl_iov(req, size, iov, 3);
186  } else {
187  if (cusexmp_expand(arg->offset + in_bufsz)) {
188  fuse_reply_err(req, ENOMEM);
189  return;
190  }
191 
192  memcpy(cusexmp_buf + arg->offset, in_buf, in_bufsz);
193  fuse_reply_ioctl_iov(req, in_bufsz, iov, 2);
194  }
195 }
196 
197 static void cusexmp_ioctl(fuse_req_t req, int cmd, void *arg,
198  struct fuse_file_info *fi, unsigned flags,
199  const void *in_buf, size_t in_bufsz, size_t out_bufsz)
200 {
201  int is_read = 0;
202 
203  (void)fi;
204 
205  if (flags & FUSE_IOCTL_COMPAT) {
206  fuse_reply_err(req, ENOSYS);
207  return;
208  }
209 
210  switch (cmd) {
211  case FIOC_GET_SIZE:
212  if (!out_bufsz) {
213  struct iovec iov = { arg, sizeof(size_t) };
214 
215  fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
216  } else
217  fuse_reply_ioctl(req, 0, &cusexmp_size,
218  sizeof(cusexmp_size));
219  break;
220 
221  case FIOC_SET_SIZE:
222  if (!in_bufsz) {
223  struct iovec iov = { arg, sizeof(size_t) };
224 
225  fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
226  } else {
227  cusexmp_resize(*(size_t *)in_buf);
228  fuse_reply_ioctl(req, 0, NULL, 0);
229  }
230  break;
231 
232  case FIOC_READ:
233  is_read = 1;
234  /* fall through */
235  case FIOC_WRITE:
236  fioc_do_rw(req, arg, in_buf, in_bufsz, out_bufsz, is_read);
237  break;
238 
239  default:
240  fuse_reply_err(req, EINVAL);
241  }
242 }
243 
244 struct cusexmp_param {
245  unsigned major;
246  unsigned minor;
247  char *dev_name;
248  int is_help;
249 };
250 
251 #define CUSEXMP_OPT(t, p) { t, offsetof(struct cusexmp_param, p), 1 }
252 
253 static const struct fuse_opt cusexmp_opts[] = {
254  CUSEXMP_OPT("-M %u", major),
255  CUSEXMP_OPT("--maj=%u", major),
256  CUSEXMP_OPT("-m %u", minor),
257  CUSEXMP_OPT("--min=%u", minor),
258  CUSEXMP_OPT("-n %s", dev_name),
259  CUSEXMP_OPT("--name=%s", dev_name),
260  FUSE_OPT_KEY("-h", 0),
261  FUSE_OPT_KEY("--help", 0),
263 };
264 
265 static int cusexmp_process_arg(void *data, const char *arg, int key,
266  struct fuse_args *outargs)
267 {
268  struct cusexmp_param *param = data;
269 
270  (void)outargs;
271  (void)arg;
272 
273  switch (key) {
274  case 0:
275  param->is_help = 1;
276  fprintf(stderr, "%s", usage);
277  return fuse_opt_add_arg(outargs, "-ho");
278  default:
279  return 1;
280  }
281 }
282 
283 static const struct cuse_lowlevel_ops cusexmp_clop = {
284  .open = cusexmp_open,
285  .read = cusexmp_read,
286  .write = cusexmp_write,
287  .ioctl = cusexmp_ioctl,
288 };
289 
290 int main(int argc, char **argv)
291 {
292  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
293  struct cusexmp_param param = { 0, 0, NULL, 0 };
294  char dev_name[128] = "DEVNAME=";
295  const char *dev_info_argv[] = { dev_name };
296  struct cuse_info ci;
297 
298  if (fuse_opt_parse(&args, &param, cusexmp_opts, cusexmp_process_arg)) {
299  printf("failed to parse option\n");
300  return 1;
301  }
302 
303  if (!param.is_help) {
304  if (!param.dev_name) {
305  fprintf(stderr, "Error: device name missing\n");
306  return 1;
307  }
308  strncat(dev_name, param.dev_name, sizeof(dev_name) - 9);
309  }
310 
311  memset(&ci, 0, sizeof(ci));
312  ci.dev_major = param.major;
313  ci.dev_minor = param.minor;
314  ci.dev_info_argc = 1;
315  ci.dev_info_argv = dev_info_argv;
316  ci.flags = CUSE_UNRESTRICTED_IOCTL;
317 
318  return cuse_lowlevel_main(args.argc, args.argv, &ci, &cusexmp_clop,
319  NULL);
320 }
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
#define FUSE_IOCTL_COMPAT
Definition: fuse_common.h:407
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
int argc
Definition: fuse_opt.h:111
#define FUSE_OPT_KEY(templ, key)
Definition: fuse_opt.h:98
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
char ** argv
Definition: fuse_opt.h:114
#define FUSE_OPT_END
Definition: fuse_opt.h:104
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:55
int fuse_reply_err(fuse_req_t req, int err)
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_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition: fuse_opt.c:398
int fuse_reply_write(fuse_req_t req, size_t count)
#define FUSE_ARGS_INIT(argc, argv)
Definition: fuse_opt.h:123