"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.3/lib/cuse_lowlevel.c" (11 May 2018, 8807 Bytes) of package /linux/misc/fuse-3.2.3.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. For more information about "cuse_lowlevel.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.2.0_vs_3.2.1.

    1 /*
    2   CUSE: Character device in Userspace
    3   Copyright (C) 2008       SUSE Linux Products GmbH
    4   Copyright (C) 2008       Tejun Heo <teheo@suse.de>
    5 
    6   This program can be distributed under the terms of the GNU LGPLv2.
    7   See the file COPYING.LIB.
    8 */
    9 
   10 #include "config.h"
   11 #include "cuse_lowlevel.h"
   12 #include "fuse_kernel.h"
   13 #include "fuse_i.h"
   14 #include "fuse_opt.h"
   15 
   16 #include <stdio.h>
   17 #include <string.h>
   18 #include <stdlib.h>
   19 #include <stddef.h>
   20 #include <errno.h>
   21 #include <unistd.h>
   22 
   23 struct cuse_data {
   24     struct cuse_lowlevel_ops    clop;
   25     unsigned            max_read;
   26     unsigned            dev_major;
   27     unsigned            dev_minor;
   28     unsigned            flags;
   29     unsigned            dev_info_len;
   30     char                dev_info[];
   31 };
   32 
   33 static struct cuse_lowlevel_ops *req_clop(fuse_req_t req)
   34 {
   35     return &req->se->cuse_data->clop;
   36 }
   37 
   38 static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino,
   39               struct fuse_file_info *fi)
   40 {
   41     (void)ino;
   42     req_clop(req)->open(req, fi);
   43 }
   44 
   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)
   47 {
   48     (void)ino;
   49     req_clop(req)->read(req, size, off, fi);
   50 }
   51 
   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)
   54 {
   55     (void)ino;
   56     req_clop(req)->write(req, buf, size, off, fi);
   57 }
   58 
   59 static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino,
   60                struct fuse_file_info *fi)
   61 {
   62     (void)ino;
   63     req_clop(req)->flush(req, fi);
   64 }
   65 
   66 static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino,
   67                  struct fuse_file_info *fi)
   68 {
   69     (void)ino;
   70     req_clop(req)->release(req, fi);
   71 }
   72 
   73 static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
   74                struct fuse_file_info *fi)
   75 {
   76     (void)ino;
   77     req_clop(req)->fsync(req, datasync, fi);
   78 }
   79 
   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)
   83 {
   84     (void)ino;
   85     req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz,
   86                  out_bufsz);
   87 }
   88 
   89 static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino,
   90               struct fuse_file_info *fi, struct fuse_pollhandle *ph)
   91 {
   92     (void)ino;
   93     req_clop(req)->poll(req, fi, ph);
   94 }
   95 
   96 static size_t cuse_pack_info(int argc, const char **argv, char *buf)
   97 {
   98     size_t size = 0;
   99     int i;
  100 
  101     for (i = 0; i < argc; i++) {
  102         size_t len;
  103 
  104         len = strlen(argv[i]) + 1;
  105         size += len;
  106         if (buf) {
  107             memcpy(buf, argv[i], len);
  108             buf += len;
  109         }
  110     }
  111 
  112     return size;
  113 }
  114 
  115 static struct cuse_data *cuse_prep_data(const struct cuse_info *ci,
  116                     const struct cuse_lowlevel_ops *clop)
  117 {
  118     struct cuse_data *cd;
  119     size_t dev_info_len;
  120 
  121     dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv,
  122                       NULL);
  123 
  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);
  127         return NULL;
  128     }
  129 
  130     cd = calloc(1, sizeof(*cd) + dev_info_len);
  131     if (!cd) {
  132         fprintf(stderr, "cuse: failed to allocate cuse_data\n");
  133         return NULL;
  134     }
  135 
  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);
  143 
  144     return cd;
  145 }
  146 
  147 struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
  148                        const struct cuse_info *ci,
  149                        const struct cuse_lowlevel_ops *clop,
  150                        void *userdata)
  151 {
  152     struct fuse_lowlevel_ops lop;
  153     struct cuse_data *cd;
  154     struct fuse_session *se;
  155 
  156     cd = cuse_prep_data(ci, clop);
  157     if (!cd)
  158         return NULL;
  159 
  160     memset(&lop, 0, sizeof(lop));
  161     lop.init    = clop->init;
  162     lop.destroy = clop->destroy;
  163     lop.open    = clop->open        ? cuse_fll_open     : NULL;
  164     lop.read    = clop->read        ? cuse_fll_read     : NULL;
  165     lop.write   = clop->write       ? cuse_fll_write    : NULL;
  166     lop.flush   = clop->flush       ? cuse_fll_flush    : NULL;
  167     lop.release = clop->release     ? cuse_fll_release  : NULL;
  168     lop.fsync   = clop->fsync       ? cuse_fll_fsync    : NULL;
  169     lop.ioctl   = clop->ioctl       ? cuse_fll_ioctl    : NULL;
  170     lop.poll    = clop->poll        ? cuse_fll_poll     : NULL;
  171 
  172     se = fuse_session_new(args, &lop, sizeof(lop), userdata);
  173     if (!se) {
  174         free(cd);
  175         return NULL;
  176     }
  177     se->cuse_data = cd;
  178 
  179     return se;
  180 }
  181 
  182 static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg,
  183                char *dev_info, unsigned dev_info_len)
  184 {
  185     struct iovec iov[3];
  186 
  187     iov[1].iov_base = arg;
  188     iov[1].iov_len = sizeof(struct cuse_init_out);
  189     iov[2].iov_base = dev_info;
  190     iov[2].iov_len = dev_info_len;
  191 
  192     return fuse_send_reply_iov_nofree(req, 0, iov, 3);
  193 }
  194 
  195 void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  196 {
  197     struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
  198     struct cuse_init_out outarg;
  199     struct fuse_session *se = req->se;
  200     struct cuse_data *cd = se->cuse_data;
  201     size_t bufsize = se->bufsize;
  202     struct cuse_lowlevel_ops *clop = req_clop(req);
  203 
  204     (void) nodeid;
  205     if (se->debug) {
  206         fprintf(stderr, "CUSE_INIT: %u.%u\n", arg->major, arg->minor);
  207         fprintf(stderr, "flags=0x%08x\n", arg->flags);
  208     }
  209     se->conn.proto_major = arg->major;
  210     se->conn.proto_minor = arg->minor;
  211     se->conn.capable = 0;
  212     se->conn.want = 0;
  213 
  214     if (arg->major < 7) {
  215         fprintf(stderr, "cuse: unsupported protocol version: %u.%u\n",
  216             arg->major, arg->minor);
  217         fuse_reply_err(req, EPROTO);
  218         return;
  219     }
  220 
  221     if (bufsize < FUSE_MIN_READ_BUFFER) {
  222         fprintf(stderr, "cuse: warning: buffer size too small: %zu\n",
  223             bufsize);
  224         bufsize = FUSE_MIN_READ_BUFFER;
  225     }
  226 
  227     bufsize -= 4096;
  228     if (bufsize < se->conn.max_write)
  229         se->conn.max_write = bufsize;
  230 
  231     se->got_init = 1;
  232     if (se->op.init)
  233         se->op.init(se->userdata, &se->conn);
  234 
  235     memset(&outarg, 0, sizeof(outarg));
  236     outarg.major = FUSE_KERNEL_VERSION;
  237     outarg.minor = FUSE_KERNEL_MINOR_VERSION;
  238     outarg.flags = cd->flags;
  239     outarg.max_read = cd->max_read;
  240     outarg.max_write = se->conn.max_write;
  241     outarg.dev_major = cd->dev_major;
  242     outarg.dev_minor = cd->dev_minor;
  243 
  244     if (se->debug) {
  245         fprintf(stderr, "   CUSE_INIT: %u.%u\n",
  246             outarg.major, outarg.minor);
  247         fprintf(stderr, "   flags=0x%08x\n", outarg.flags);
  248         fprintf(stderr, "   max_read=0x%08x\n", outarg.max_read);
  249         fprintf(stderr, "   max_write=0x%08x\n", outarg.max_write);
  250         fprintf(stderr, "   dev_major=%u\n", outarg.dev_major);
  251         fprintf(stderr, "   dev_minor=%u\n", outarg.dev_minor);
  252         fprintf(stderr, "   dev_info: %.*s\n", cd->dev_info_len,
  253             cd->dev_info);
  254     }
  255 
  256     cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len);
  257 
  258     if (clop->init_done)
  259         clop->init_done(se->userdata);
  260 
  261     fuse_free_req(req);
  262 }
  263 
  264 struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
  265                      const struct cuse_info *ci,
  266                      const struct cuse_lowlevel_ops *clop,
  267                      int *multithreaded, void *userdata)
  268 {
  269     const char *devname = "/dev/cuse";
  270     static const struct fuse_opt kill_subtype_opts[] = {
  271         FUSE_OPT_KEY("subtype=",  FUSE_OPT_KEY_DISCARD),
  272         FUSE_OPT_END
  273     };
  274     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
  275     struct fuse_session *se;
  276     struct fuse_cmdline_opts opts;
  277     int fd;
  278     int res;
  279 
  280     if (fuse_parse_cmdline(&args, &opts) == -1)
  281         return NULL;
  282     *multithreaded = !opts.singlethread;
  283 
  284     /* Remove subtype= option */
  285     res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL);
  286     if (res == -1)
  287         goto out1;
  288 
  289     /*
  290      * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
  291      * would ensue.
  292      */
  293     do {
  294         fd = open("/dev/null", O_RDWR);
  295         if (fd > 2)
  296             close(fd);
  297     } while (fd >= 0 && fd <= 2);
  298 
  299     se = cuse_lowlevel_new(&args, ci, clop, userdata);
  300     if (se == NULL)
  301         goto out1;
  302 
  303     fd = open(devname, O_RDWR);
  304     if (fd == -1) {
  305         if (errno == ENODEV || errno == ENOENT)
  306             fprintf(stderr, "cuse: device not found, try 'modprobe cuse' first\n");
  307         else
  308             fprintf(stderr, "cuse: failed to open %s: %s\n",
  309                 devname, strerror(errno));
  310         goto err_se;
  311     }
  312     se->fd = fd;
  313 
  314     res = fuse_set_signal_handlers(se);
  315     if (res == -1)
  316         goto err_se;
  317 
  318     res = fuse_daemonize(opts.foreground);
  319     if (res == -1)
  320         goto err_sig;
  321 
  322     return se;
  323 
  324 err_sig:
  325     fuse_remove_signal_handlers(se);
  326 err_se:
  327     fuse_session_destroy(se);
  328 out1:
  329     free(opts.mountpoint);
  330     fuse_opt_free_args(&args);
  331     return NULL;
  332 }
  333 
  334 void cuse_lowlevel_teardown(struct fuse_session *se)
  335 {
  336     fuse_remove_signal_handlers(se);
  337     fuse_session_destroy(se);
  338 }
  339 
  340 int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
  341                const struct cuse_lowlevel_ops *clop, void *userdata)
  342 {
  343     struct fuse_session *se;
  344     int multithreaded;
  345     int res;
  346 
  347     se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded,
  348                  userdata);
  349     if (se == NULL)
  350         return 1;
  351 
  352     if (multithreaded) {
  353         struct fuse_loop_config config;
  354         config.clone_fd = 0;
  355         config.max_idle_threads = 10;
  356         res = fuse_session_loop_mt_32(se, &config);
  357     }
  358     else
  359         res = fuse_session_loop(se);
  360 
  361     cuse_lowlevel_teardown(se);
  362     if (res == -1)
  363         return 1;
  364 
  365     return 0;
  366 }