97a9a944b5887e91042b019776c41d5dd74557aferikabele/*
97a9a944b5887e91042b019776c41d5dd74557aferikabele * Fuse: Filesystem in Userspace
97a9a944b5887e91042b019776c41d5dd74557aferikabele *
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive *
a945f35eff8b6a88009ce73de6d4c862ce58de3cslive * This program can be distributed under the terms of the GNU LGPLv2.
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd * See the file COPYING.LIB
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd#include "fuse.h"
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen#include "fuse_opt.h"
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen#include <libuvfs.h>
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen#include "fuse_impl.h"
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd#include <string.h>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd#include <assert.h>
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen/*
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * Add an argument to the end of a fuse_args array. The second argument
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd * is copied.
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd */
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
3f08db06526d6901aa08c110b5bc7dde6bc39905ndint
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndfuse_opt_add_arg(struct fuse_args *args, const char *arg)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd{
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd char **old_argv = args->argv;
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd int i;
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor
7f5b59ccc63c0c0e3e678a168f09ee6a2f51f9d0nd args->argc++;
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd args->argv = umem_alloc(sizeof (char *) * (args->argc + 1),
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd UMEM_NOFAIL);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (old_argv != NULL)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (args->allocated)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd (void) memcpy(args->argv, old_argv,
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd sizeof (char *) * args->argc);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd else
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd for (i = 0; i < args->argc - 1; i++)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->argv[i] = libfuse_strdup(old_argv[i]);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->argv[args->argc] = NULL;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->argv[args->argc - 1] = libfuse_strdup(arg);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (args->allocated)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive umem_free(old_argv, sizeof (char *) * args->argc);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->allocated = B_TRUE;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (0);
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd}
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd
5b10fd3977e6dfff19afe770e612e276962f7950nd/*
5b10fd3977e6dfff19afe770e612e276962f7950nd * Insert an argument into an arbitrary slot in a fuse_args array. The
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd * third argument is copied.
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd */
53bae66d3dc14a667e14a451f7bc65a893dd450fnd
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedoohint
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4ndfuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd{
53bae66d3dc14a667e14a451f7bc65a893dd450fnd (void) fuse_opt_add_arg(args, arg);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (pos < args->argc - 1) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive void *src = args->argv + pos;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive void *dest = args->argv + pos + 1;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int len = args->argc - pos;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive (void) memmove(dest, src, len * sizeof (char *));
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->argv[pos] = args->argv[args->argc];
9bcfc3697a91b5215893a7d0206865b13fc72148nd args->argv[args->argc] = NULL;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (0);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive/*
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * Drop an arbitrary argument from a fuse_args array.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic void
06ba4a61654b3763ad65f52283832ebf058fdf1cslivefuse_opt_drop_arg(struct fuse_args *args, uint_t which)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive char **oldargs = args->argv;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int i, j;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive assert(args->argc > 0);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->argc--;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->argv = umem_alloc(sizeof (char *) * (args->argc + 1),
06ba4a61654b3763ad65f52283832ebf058fdf1cslive UMEM_NOFAIL);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive for (i = j = 0; i < args->argc + 1; i++) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (i != which) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (args->allocated)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->argv[j++] = oldargs[i];
06ba4a61654b3763ad65f52283832ebf058fdf1cslive else
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->argv[j++] = libfuse_strdup(oldargs[i]);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive } else if (args->allocated) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive libfuse_strfree(oldargs[i]);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe args->argv[args->argc] = NULL;
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe if (args->allocated)
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe umem_free(oldargs, sizeof (char *) * (args->argc + 2));
06ba4a61654b3763ad65f52283832ebf058fdf1cslive args->allocated = B_TRUE;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive/*
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * Add an option to a comma-separated list of options. Initially,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * the first argument should be the address of a character pointer
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * pointing to NULL. This may be reused, and eventually freed
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * with libfuse_strfree().
06ba4a61654b3763ad65f52283832ebf058fdf1cslive */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1csliveint
06ba4a61654b3763ad65f52283832ebf058fdf1cslivefuse_opt_add_opt(char **opts, const char *opt)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive char *newopts, *oldopts;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int oldlen, optlen, newlen;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (opts == NULL)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (-1);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (*opts == NULL) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive *opts = libfuse_strdup(opt);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (0);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive }
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive oldopts = *opts;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive oldlen = strlen(oldopts);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive optlen = strlen(opt);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive newlen = oldlen + optlen + 2;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive newopts = umem_alloc(newlen, UMEM_NOFAIL);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive (void) strlcpy(newopts, oldopts, newlen);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive (void) strlcat(newopts, ",", newlen);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive (void) strlcat(newopts, opt, newlen);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive umem_free(oldopts, oldlen + 1);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive *opts = newopts;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (0);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive/*
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * Free a fuse_args structure.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslivevoid
06ba4a61654b3763ad65f52283832ebf058fdf1cslivefuse_opt_free_args(struct fuse_args *args)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive int i;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if ((args == NULL) || (! args->allocated))
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive for (i = 0; i < args->argc; i++)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (args->argv[i] != NULL)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive libfuse_strfree(args->argv[i]);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive umem_free(args->argv, sizeof (char *) * (args->argc + 1));
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive/*
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * Shift the zeroth argument off of the fuse_args array, storing
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * it in the second argument. A pointer to the second argument is
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * returned.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic char *
06ba4a61654b3763ad65f52283832ebf058fdf1cslivefuse_opt_shift_arg(struct fuse_args *args, char *buffer, int bufsiz)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if ((args == NULL) || (args->argv[0] == NULL))
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (NULL);
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe
06ba4a61654b3763ad65f52283832ebf058fdf1cslive (void) strlcpy(buffer, args->argv[0], bufsiz);
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe fuse_opt_drop_arg(args, 0);
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe return (buffer);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe
06ba4a61654b3763ad65f52283832ebf058fdf1cslive/*
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * Process an argument according to the key, calling proc if necessary.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic int
06ba4a61654b3763ad65f52283832ebf058fdf1cslivefuse_opt_proc(struct fuse_args *args, const char *arg, int key,
06ba4a61654b3763ad65f52283832ebf058fdf1cslive fuse_opt_proc_t proc, void *data)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (key == FUSE_OPT_KEY_DISCARD)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (0);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (key == FUSE_OPT_KEY_KEEP)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (1);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if ((proc == NULL) || (data == NULL))
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (1);
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive return (proc(data, arg, key, args));
06ba4a61654b3763ad65f52283832ebf058fdf1cslive}
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive/*
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * Find the next matching option for the given argument. If an equal
06ba4a61654b3763ad65f52283832ebf058fdf1cslive * sign or a space separates, set *sepp to the index.
06ba4a61654b3763ad65f52283832ebf058fdf1cslive */
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslivestatic const struct fuse_opt *
06ba4a61654b3763ad65f52283832ebf058fdf1cslivefuse_opt_next_match(const struct fuse_opt *opts, const char *arg,
1937357c6969cbc6a1eb245e80faa6f3723cfa0awrowe uint_t *sepp)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive{
06ba4a61654b3763ad65f52283832ebf058fdf1cslive const struct fuse_opt *opt;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive char *chop;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive uint_t sep, cmplen;
06ba4a61654b3763ad65f52283832ebf058fdf1cslive
06ba4a61654b3763ad65f52283832ebf058fdf1cslive for (opt = opts; opt->templ != NULL; opt++) {
06ba4a61654b3763ad65f52283832ebf058fdf1cslive chop = strrchr(opt->templ, '=');
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (chop == NULL)
06ba4a61654b3763ad65f52283832ebf058fdf1cslive chop = strrchr(opt->templ, ' ');
06ba4a61654b3763ad65f52283832ebf058fdf1cslive if (chop != NULL) {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd cmplen = sep = (uintptr_t)chop - (uintptr_t)opt->templ;
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd if (chop[0] == '=')
3b3b7fc78d1f5bfc2769903375050048ff41ff26nd ++cmplen;
ad74a0524a06bfe11b7de9e3b4ce7233ab3bd3f7nd if (strncmp(arg, opt->templ, cmplen) == 0) {
cc8190433d13f5e9de618c5d7f10c824c0c1919cgryzor *sepp = sep;
7f5b59ccc63c0c0e3e678a168f09ee6a2f51f9d0nd break;
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung }
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh } else {
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh if (strcmp(arg, opt->templ) == 0) {
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh *sepp = 0;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh break;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh }
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh }
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh }
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh if (opt->templ == NULL)
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh opt = NULL;
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh return (opt);
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh}
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh/*
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh * Scan the input into the value, according to the format. If the
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh * format is %s, copy the string.
5effc8b39fae5cd169d17f342bfc265705840014rbowen */
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen
7fec19672a491661b2fe4b29f685bc7f4efa64d4ndstatic int
7fec19672a491661b2fe4b29f685bc7f4efa64d4ndfuse_opt_scan(const char *input, const char *format, void *value)
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd{
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd if (format[1] == 's') {
0c4abc32c00611fe1d52c9661f5cc79a3f74c6d4nd char **cpp = value;
*cpp = libfuse_strdup(input);
return (0);
}
if (sscanf(input, format, value) != 1)
return (-1);
return (0);
}
/*
* "apply" the given fuse_opt to the input. That is, if the offset is
* -1, call the callback; else, set the integer at the given offset
* to the given value.
*/
static int
fuse_opt_apply(struct fuse_args *new, const char *arg,
const struct fuse_opt *opt, fuse_opt_proc_t proc, void *data)
{
uintptr_t valaddr;
int rc;
if ((opt->offset == -1U) || (opt->offset == -1UL)) {
rc = fuse_opt_proc(new, arg, opt->value, proc, data);
} else {
valaddr = (uintptr_t)data + opt->offset;
*(int *)valaddr = opt->value;
rc = 0;
}
return (rc);
}
/*
* Apply each fuse_opt that is applicable to the arg. "apply" means to
* scan or strdup if a %-format is present, or to "apply" it as in
* fuse_opt_apply. If the return value is one, we add the argument to
* new. And, if a template for an option contains a space, we may
* concatenate the next argument before calling the callback.
*/
static int
fuse_opt_opt(struct fuse_args *old, struct fuse_args *new, const char *arg,
const struct fuse_opt opts[], fuse_opt_proc_t proc, void *data)
{
const struct fuse_opt *opt;
const char *post;
char buffy[BUFSIZ];
uint_t sep;
int save = 0;
int rc = 0;
opt = fuse_opt_next_match(opts, arg, &sep);
if ((opt == NULL) || (opt->templ == NULL))
return (fuse_opt_proc(new, arg, FUSE_OPT_KEY_OPT, proc, data));
do {
if (sep != 0) {
post = opt->templ + sep;
if (post[0] == '=') {
++post;
if (post[0] != '%') {
rc = fuse_opt_proc(new, arg, opt->value,
proc, data);
if (rc == 1)
save = 1;
} else {
uintptr_t valp = (uintptr_t)data +
opt->offset;
rc = fuse_opt_scan(arg + sep + 1, post,
(void *)valp);
}
} else {
(void) strlcpy(buffy, arg, sizeof (buffy));
if ((post[0] == ' ') && (arg[sep] == '\0') &&
(old->argv[0] != NULL)) {
(void) strlcat(buffy, old->argv[0],
sizeof (buffy));
}
rc = fuse_opt_apply(new, buffy, opt,
proc, data);
}
} else {
rc = fuse_opt_apply(new, arg, opt, proc, data);
if (rc == 1)
(void) fuse_opt_add_arg(new, arg);
}
++opt;
opt = fuse_opt_next_match(opt, arg, &sep);
} while ((rc != -1) && (opt != NULL) && (opt->templ != NULL));
return (save);
}
static int
fuse_opt_optgroup(struct fuse_args *old, struct fuse_args *new, const char *arg,
const struct fuse_opt opts[], fuse_opt_proc_t proc, char *data,
char **allopts)
{
char buffy[BUFSIZ], *opt, *lasts;
int rc = 0;
(void) strlcpy(buffy, arg, sizeof (buffy));
for (opt = strtok_r(buffy, ", ", &lasts); opt != NULL;
opt = strtok_r(NULL, ", ", &lasts)) {
rc = fuse_opt_opt(old, new, opt, opts, proc, data);
if (rc == -1)
break;
if (rc == 1)
rc = fuse_opt_add_opt(allopts, opt);
}
return (rc);
}
static int
fuse_opt_parse_all(struct fuse_args *old, struct fuse_args *new,
const struct fuse_opt opts[], fuse_opt_proc_t proc, void *data,
char **allopts)
{
char *arg, buffy[BUFSIZ];
int rc = 1;
while ((rc != -1) && (old->argv[0] != NULL)) {
if (strcmp(old->argv[0], "--") == 0) {
rc = 0;
break;
}
arg = fuse_opt_shift_arg(old, buffy, sizeof (buffy));
if (arg == NULL) {
rc = 0;
break;
}
if (arg[0] != '-') {
rc = fuse_opt_proc(new, arg, FUSE_OPT_KEY_NONOPT,
proc, data);
if (rc == 1)
(void) fuse_opt_add_arg(new, arg);
} else if (strcmp(arg, "-o") == 0) {
arg = fuse_opt_shift_arg(old, buffy, sizeof (buffy));
rc = fuse_opt_optgroup(old, new, arg, opts, proc, data,
allopts);
} else if (strncmp(arg, "-o ", 3) == 0) {
arg += 3;
rc = fuse_opt_optgroup(old, new, arg, opts, proc, data,
allopts);
} else {
rc = fuse_opt_opt(old, new, arg, opts, proc, data);
if (rc == 1)
(void) fuse_opt_add_arg(new, arg);
}
}
if (rc == 1)
rc = 0;
return (rc);
}
/*
* Parse the arguments and return the result. If the return is -1, there was
* a problem. Otherwise, args is altered such that the options, if any, are
* moved to the front in a single "-o a,b,c" pattern, and other arguments are
* kept or discarded according to the rules laid out in fuse_opt.h.
*/
int
fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc)
{
struct fuse_args *newargs;
char buffy[BUFSIZ];
char *allopts = NULL;
int rc;
if ((args == NULL) || (args->argc == 0) || (args->argv[0] == NULL) ||
(opts == NULL) || (opts[0].templ == NULL))
return (0);
assert(args->argv[args->argc] == NULL);
newargs = umem_zalloc(sizeof (*newargs), UMEM_NOFAIL);
(void) fuse_opt_add_arg(newargs, fuse_opt_shift_arg(args, buffy,
sizeof (buffy)));
rc = fuse_opt_parse_all(args, newargs, opts, proc, data, &allopts);
if (allopts != NULL) {
(void) fuse_opt_insert_arg(newargs, 1, "-o");
(void) fuse_opt_insert_arg(newargs, 2, allopts);
libfuse_strfree(allopts);
}
if (rc != -1) {
fuse_opt_free_args(args);
*args = *newargs; // structure assign
} else {
fuse_opt_free_args(newargs);
}
umem_free(newargs, sizeof (*newargs));
return (rc);
}