"Fossies" - the Fresh Open Source Software Archive

Member "fuse-3.2.3/lib/fuse_opt.c" (11 May 2018, 8882 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 "fuse_opt.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2   FUSE: Filesystem in Userspace
    3   Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
    4 
    5   Implementation of option parsing routines (dealing with `struct
    6   fuse_args`).
    7 
    8   This program can be distributed under the terms of the GNU LGPLv2.
    9   See the file COPYING.LIB
   10 */
   11 
   12 #include "config.h"
   13 #include "fuse_opt.h"
   14 #include "fuse_misc.h"
   15 
   16 #include <stdio.h>
   17 #include <stdlib.h>
   18 #include <string.h>
   19 #include <assert.h>
   20 
   21 struct fuse_opt_context {
   22     void *data;
   23     const struct fuse_opt *opt;
   24     fuse_opt_proc_t proc;
   25     int argctr;
   26     int argc;
   27     char **argv;
   28     struct fuse_args outargs;
   29     char *opts;
   30     int nonopt;
   31 };
   32 
   33 void fuse_opt_free_args(struct fuse_args *args)
   34 {
   35     if (args) {
   36         if (args->argv && args->allocated) {
   37             int i;
   38             for (i = 0; i < args->argc; i++)
   39                 free(args->argv[i]);
   40             free(args->argv);
   41         }
   42         args->argc = 0;
   43         args->argv = NULL;
   44         args->allocated = 0;
   45     }
   46 }
   47 
   48 static int alloc_failed(void)
   49 {
   50     fprintf(stderr, "fuse: memory allocation failed\n");
   51     return -1;
   52 }
   53 
   54 int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
   55 {
   56     char **newargv;
   57     char *newarg;
   58 
   59     assert(!args->argv || args->allocated);
   60 
   61     newarg = strdup(arg);
   62     if (!newarg)
   63         return alloc_failed();
   64 
   65     newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
   66     if (!newargv) {
   67         free(newarg);
   68         return alloc_failed();
   69     }
   70 
   71     args->argv = newargv;
   72     args->allocated = 1;
   73     args->argv[args->argc++] = newarg;
   74     args->argv[args->argc] = NULL;
   75     return 0;
   76 }
   77 
   78 static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
   79                       const char *arg)
   80 {
   81     assert(pos <= args->argc);
   82     if (fuse_opt_add_arg(args, arg) == -1)
   83         return -1;
   84 
   85     if (pos != args->argc - 1) {
   86         char *newarg = args->argv[args->argc - 1];
   87         memmove(&args->argv[pos + 1], &args->argv[pos],
   88             sizeof(char *) * (args->argc - pos - 1));
   89         args->argv[pos] = newarg;
   90     }
   91     return 0;
   92 }
   93 
   94 int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
   95 {
   96     return fuse_opt_insert_arg_common(args, pos, arg);
   97 }
   98 
   99 static int next_arg(struct fuse_opt_context *ctx, const char *opt)
  100 {
  101     if (ctx->argctr + 1 >= ctx->argc) {
  102         fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
  103         return -1;
  104     }
  105     ctx->argctr++;
  106     return 0;
  107 }
  108 
  109 static int add_arg(struct fuse_opt_context *ctx, const char *arg)
  110 {
  111     return fuse_opt_add_arg(&ctx->outargs, arg);
  112 }
  113 
  114 static int add_opt_common(char **opts, const char *opt, int esc)
  115 {
  116     unsigned oldlen = *opts ? strlen(*opts) : 0;
  117     char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
  118 
  119     if (!d)
  120         return alloc_failed();
  121 
  122     *opts = d;
  123     if (oldlen) {
  124         d += oldlen;
  125         *d++ = ',';
  126     }
  127 
  128     for (; *opt; opt++) {
  129         if (esc && (*opt == ',' || *opt == '\\'))
  130             *d++ = '\\';
  131         *d++ = *opt;
  132     }
  133     *d = '\0';
  134 
  135     return 0;
  136 }
  137 
  138 int fuse_opt_add_opt(char **opts, const char *opt)
  139 {
  140     return add_opt_common(opts, opt, 0);
  141 }
  142 
  143 int fuse_opt_add_opt_escaped(char **opts, const char *opt)
  144 {
  145     return add_opt_common(opts, opt, 1);
  146 }
  147 
  148 static int add_opt(struct fuse_opt_context *ctx, const char *opt)
  149 {
  150     return add_opt_common(&ctx->opts, opt, 1);
  151 }
  152 
  153 static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
  154              int iso)
  155 {
  156     if (key == FUSE_OPT_KEY_DISCARD)
  157         return 0;
  158 
  159     if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
  160         int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
  161         if (res == -1 || !res)
  162             return res;
  163     }
  164     if (iso)
  165         return add_opt(ctx, arg);
  166     else
  167         return add_arg(ctx, arg);
  168 }
  169 
  170 static int match_template(const char *t, const char *arg, unsigned *sepp)
  171 {
  172     int arglen = strlen(arg);
  173     const char *sep = strchr(t, '=');
  174     sep = sep ? sep : strchr(t, ' ');
  175     if (sep && (!sep[1] || sep[1] == '%')) {
  176         int tlen = sep - t;
  177         if (sep[0] == '=')
  178             tlen ++;
  179         if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
  180             *sepp = sep - t;
  181             return 1;
  182         }
  183     }
  184     if (strcmp(t, arg) == 0) {
  185         *sepp = 0;
  186         return 1;
  187     }
  188     return 0;
  189 }
  190 
  191 static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
  192                        const char *arg, unsigned *sepp)
  193 {
  194     for (; opt && opt->templ; opt++)
  195         if (match_template(opt->templ, arg, sepp))
  196             return opt;
  197     return NULL;
  198 }
  199 
  200 int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
  201 {
  202     unsigned dummy;
  203     return find_opt(opts, opt, &dummy) ? 1 : 0;
  204 }
  205 
  206 static int process_opt_param(void *var, const char *format, const char *param,
  207                  const char *arg)
  208 {
  209     assert(format[0] == '%');
  210     if (format[1] == 's') {
  211         char **s = var;
  212         char *copy = strdup(param);
  213         if (!copy)
  214             return alloc_failed();
  215 
  216         free(*s);
  217         *s = copy;
  218     } else {
  219         if (sscanf(param, format, var) != 1) {
  220             fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
  221             return -1;
  222         }
  223     }
  224     return 0;
  225 }
  226 
  227 static int process_opt(struct fuse_opt_context *ctx,
  228                const struct fuse_opt *opt, unsigned sep,
  229                const char *arg, int iso)
  230 {
  231     if (opt->offset == -1U) {
  232         if (call_proc(ctx, arg, opt->value, iso) == -1)
  233             return -1;
  234     } else {
  235         void *var = ctx->data + opt->offset;
  236         if (sep && opt->templ[sep + 1]) {
  237             const char *param = arg + sep;
  238             if (opt->templ[sep] == '=')
  239                 param ++;
  240             if (process_opt_param(var, opt->templ + sep + 1,
  241                           param, arg) == -1)
  242                 return -1;
  243         } else
  244             *(int *)var = opt->value;
  245     }
  246     return 0;
  247 }
  248 
  249 static int process_opt_sep_arg(struct fuse_opt_context *ctx,
  250                    const struct fuse_opt *opt, unsigned sep,
  251                    const char *arg, int iso)
  252 {
  253     int res;
  254     char *newarg;
  255     char *param;
  256 
  257     if (next_arg(ctx, arg) == -1)
  258         return -1;
  259 
  260     param = ctx->argv[ctx->argctr];
  261     newarg = malloc(sep + strlen(param) + 1);
  262     if (!newarg)
  263         return alloc_failed();
  264 
  265     memcpy(newarg, arg, sep);
  266     strcpy(newarg + sep, param);
  267     res = process_opt(ctx, opt, sep, newarg, iso);
  268     free(newarg);
  269 
  270     return res;
  271 }
  272 
  273 static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
  274 {
  275     unsigned sep;
  276     const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
  277     if (opt) {
  278         for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
  279             int res;
  280             if (sep && opt->templ[sep] == ' ' && !arg[sep])
  281                 res = process_opt_sep_arg(ctx, opt, sep, arg,
  282                               iso);
  283             else
  284                 res = process_opt(ctx, opt, sep, arg, iso);
  285             if (res == -1)
  286                 return -1;
  287         }
  288         return 0;
  289     } else
  290         return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
  291 }
  292 
  293 static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
  294 {
  295     char *s = opts;
  296     char *d = s;
  297     int end = 0;
  298 
  299     while (!end) {
  300         if (*s == '\0')
  301             end = 1;
  302         if (*s == ',' || end) {
  303             int res;
  304 
  305             *d = '\0';
  306             res = process_gopt(ctx, opts, 1);
  307             if (res == -1)
  308                 return -1;
  309             d = opts;
  310         } else {
  311             if (s[0] == '\\' && s[1] != '\0') {
  312                 s++;
  313                 if (s[0] >= '0' && s[0] <= '3' &&
  314                     s[1] >= '0' && s[1] <= '7' &&
  315                     s[2] >= '0' && s[2] <= '7') {
  316                     *d++ = (s[0] - '0') * 0100 +
  317                         (s[1] - '0') * 0010 +
  318                         (s[2] - '0');
  319                     s += 2;
  320                 } else {
  321                     *d++ = *s;
  322                 }
  323             } else {
  324                 *d++ = *s;
  325             }
  326         }
  327         s++;
  328     }
  329 
  330     return 0;
  331 }
  332 
  333 static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
  334 {
  335     int res;
  336     char *copy = strdup(opts);
  337 
  338     if (!copy) {
  339         fprintf(stderr, "fuse: memory allocation failed\n");
  340         return -1;
  341     }
  342     res = process_real_option_group(ctx, copy);
  343     free(copy);
  344     return res;
  345 }
  346 
  347 static int process_one(struct fuse_opt_context *ctx, const char *arg)
  348 {
  349     if (ctx->nonopt || arg[0] != '-')
  350         return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
  351     else if (arg[1] == 'o') {
  352         if (arg[2])
  353             return process_option_group(ctx, arg + 2);
  354         else {
  355             if (next_arg(ctx, arg) == -1)
  356                 return -1;
  357 
  358             return process_option_group(ctx,
  359                             ctx->argv[ctx->argctr]);
  360         }
  361     } else if (arg[1] == '-' && !arg[2]) {
  362         if (add_arg(ctx, arg) == -1)
  363             return -1;
  364         ctx->nonopt = ctx->outargs.argc;
  365         return 0;
  366     } else
  367         return process_gopt(ctx, arg, 0);
  368 }
  369 
  370 static int opt_parse(struct fuse_opt_context *ctx)
  371 {
  372     if (ctx->argc) {
  373         if (add_arg(ctx, ctx->argv[0]) == -1)
  374             return -1;
  375     }
  376 
  377     for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
  378         if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
  379             return -1;
  380 
  381     if (ctx->opts) {
  382         if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
  383             fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
  384             return -1;
  385     }
  386 
  387     /* If option separator ("--") is the last argument, remove it */
  388     if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
  389         strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
  390         free(ctx->outargs.argv[ctx->outargs.argc - 1]);
  391         ctx->outargs.argv[--ctx->outargs.argc] = NULL;
  392     }
  393 
  394     return 0;
  395 }
  396 
  397 int fuse_opt_parse(struct fuse_args *args, void *data,
  398            const struct fuse_opt opts[], fuse_opt_proc_t proc)
  399 {
  400     int res;
  401     struct fuse_opt_context ctx = {
  402         .data = data,
  403         .opt = opts,
  404         .proc = proc,
  405     };
  406 
  407     if (!args || !args->argv || !args->argc)
  408         return 0;
  409 
  410     ctx.argc = args->argc;
  411     ctx.argv = args->argv;
  412 
  413     res = opt_parse(&ctx);
  414     if (res != -1) {
  415         struct fuse_args tmp = *args;
  416         *args = ctx.outargs;
  417         ctx.outargs = tmp;
  418     }
  419     free(ctx.opts);
  420     fuse_opt_free_args(&ctx.outargs);
  421     return res;
  422 }