"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.1/example/cuse.c" (14 Nov 2017, 7251 Bytes) of package /linux/misc/fuse-3.2.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "cuse.c": 3.2.0_vs_3.2.1.

    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 GPL.
    7   See the file COPYING.
    8 
    9 */
   10 
   11 /** @file
   12  *
   13  * This example demonstrates how to implement a character device in
   14  * userspace ("CUSE"). This is only allowed for root. The character
   15  * device should appear in /dev under the specified name. It can be
   16  * tested with the cuse_client.c program.
   17  *
   18  * Mount the file system with:
   19  *
   20  *     cuse -f --name=mydevice
   21  *
   22  * You should now have a new /dev/mydevice character device. To "unmount" it,
   23  * kill the "cuse" process.
   24  *
   25  * To compile this example, run
   26  *
   27  *     gcc -Wall cuse.c `pkg-config fuse3 --cflags --libs` -o cuse
   28  *
   29  * ## Source code ##
   30  * \include cuse.c
   31  */
   32 
   33 
   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),
  262     FUSE_OPT_END
  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 }