"Fossies" - the Fresh Open Source Software Archive

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