1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5
6 #include <stdbool.h>
7
8 /* user defined includes */
9 #include <linux/types.h>
10 #include <kvm/util.h>
11 #include <kvm/parse-options.h>
12 #include <kvm/strbuf.h>
13
14 #define OPT_SHORT 1
15 #define OPT_UNSET 2
16
opterror(const struct option * opt,const char * reason,int flags)17 static int opterror(const struct option *opt, const char *reason, int flags)
18 {
19 if (flags & OPT_SHORT)
20 pr_err("switch `%c' %s", opt->short_name, reason);
21 else if (flags & OPT_UNSET)
22 pr_err("option `no-%s' %s", opt->long_name, reason);
23 else
24 pr_err("option `%s' %s", opt->long_name, reason);
25
26 return -1;
27 }
28
get_arg(struct parse_opt_ctx_t * p,const struct option * opt,int flags,const char ** arg)29 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
30 int flags, const char **arg)
31 {
32 if (p->opt) {
33 *arg = p->opt;
34 p->opt = NULL;
35 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
36 **(p->argv + 1) == '-')) {
37 *arg = (const char *)opt->defval;
38 } else if (p->argc > 1) {
39 p->argc--;
40 *arg = *++p->argv;
41 } else
42 return opterror(opt, "requires a value", flags);
43 return 0;
44 }
45
readnum(const struct option * opt,int flags,const char * str,char ** end)46 static int readnum(const struct option *opt, int flags,
47 const char *str, char **end)
48 {
49 switch (opt->type) {
50 case OPTION_INTEGER:
51 *(int *)opt->value = strtol(str, end, 0);
52 break;
53 case OPTION_UINTEGER:
54 *(unsigned int *)opt->value = strtol(str, end, 0);
55 break;
56 case OPTION_LONG:
57 *(long *)opt->value = strtol(str, end, 0);
58 break;
59 case OPTION_U64:
60 *(u64 *)opt->value = strtoull(str, end, 0);
61 break;
62 default:
63 return opterror(opt, "invalid numeric conversion", flags);
64 }
65
66 return 0;
67 }
68
get_value(struct parse_opt_ctx_t * p,const struct option * opt,int flags)69 static int get_value(struct parse_opt_ctx_t *p,
70 const struct option *opt, int flags)
71 {
72 const char *s, *arg = NULL;
73 const int unset = flags & OPT_UNSET;
74
75 if (unset && p->opt)
76 return opterror(opt, "takes no value", flags);
77 if (unset && (opt->flags & PARSE_OPT_NONEG))
78 return opterror(opt, "isn't available", flags);
79
80 if (!(flags & OPT_SHORT) && p->opt) {
81 switch (opt->type) {
82 case OPTION_CALLBACK:
83 if (!(opt->flags & PARSE_OPT_NOARG))
84 break;
85 /* FALLTHROUGH */
86 case OPTION_BOOLEAN:
87 case OPTION_INCR:
88 case OPTION_BIT:
89 case OPTION_SET_UINT:
90 case OPTION_SET_PTR:
91 return opterror(opt, "takes no value", flags);
92 case OPTION_END:
93 case OPTION_ARGUMENT:
94 case OPTION_GROUP:
95 case OPTION_STRING:
96 case OPTION_INTEGER:
97 case OPTION_UINTEGER:
98 case OPTION_LONG:
99 case OPTION_U64:
100 default:
101 break;
102 }
103 }
104
105 switch (opt->type) {
106 case OPTION_BIT:
107 if (unset)
108 *(int *)opt->value &= ~opt->defval;
109 else
110 *(int *)opt->value |= opt->defval;
111 return 0;
112
113 case OPTION_BOOLEAN:
114 *(bool *)opt->value = unset ? false : true;
115 return 0;
116
117 case OPTION_INCR:
118 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
119 return 0;
120
121 case OPTION_SET_UINT:
122 *(unsigned int *)opt->value = unset ? 0 : opt->defval;
123 return 0;
124
125 case OPTION_SET_PTR:
126 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
127 return 0;
128
129 case OPTION_STRING:
130 if (unset)
131 *(const char **)opt->value = NULL;
132 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
133 *(const char **)opt->value = (const char *)opt->defval;
134 else
135 return get_arg(p, opt, flags,
136 (const char **)opt->value);
137 return 0;
138
139 case OPTION_CALLBACK:
140 if (unset)
141 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
142 if (opt->flags & PARSE_OPT_NOARG)
143 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
144 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
145 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
146 if (get_arg(p, opt, flags, &arg))
147 return -1;
148 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
149
150 case OPTION_INTEGER:
151 if (unset) {
152 *(int *)opt->value = 0;
153 return 0;
154 }
155 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
156 *(int *)opt->value = opt->defval;
157 return 0;
158 }
159 if (get_arg(p, opt, flags, &arg))
160 return -1;
161 return readnum(opt, flags, arg, (char **)&s);
162
163 case OPTION_UINTEGER:
164 if (unset) {
165 *(unsigned int *)opt->value = 0;
166 return 0;
167 }
168 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
169 *(unsigned int *)opt->value = opt->defval;
170 return 0;
171 }
172 if (get_arg(p, opt, flags, &arg))
173 return -1;
174 return readnum(opt, flags, arg, (char **)&s);
175
176 case OPTION_LONG:
177 if (unset) {
178 *(long *)opt->value = 0;
179 return 0;
180 }
181 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
182 *(long *)opt->value = opt->defval;
183 return 0;
184 }
185 if (get_arg(p, opt, flags, &arg))
186 return -1;
187 return readnum(opt, flags, arg, (char **)&s);
188
189 case OPTION_U64:
190 if (unset) {
191 *(u64 *)opt->value = 0;
192 return 0;
193 }
194 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
195 *(u64 *)opt->value = opt->defval;
196 return 0;
197 }
198 if (get_arg(p, opt, flags, &arg))
199 return -1;
200 return readnum(opt, flags, arg, (char **)&s);
201
202 case OPTION_END:
203 case OPTION_ARGUMENT:
204 case OPTION_GROUP:
205 default:
206 die("should not happen, someone must be hit on the forehead");
207 }
208 }
209
210 #define USAGE_OPTS_WIDTH 24
211 #define USAGE_GAP 2
212
usage_with_options_internal(const char * const * usagestr,const struct option * opts,int full)213 static int usage_with_options_internal(const char * const *usagestr,
214 const struct option *opts, int full)
215 {
216 if (!usagestr)
217 return PARSE_OPT_HELP;
218
219 fprintf(stderr, "\n usage: %s\n", *usagestr++);
220 while (*usagestr && **usagestr)
221 fprintf(stderr, " or: %s\n", *usagestr++);
222 while (*usagestr) {
223 fprintf(stderr, "%s%s\n",
224 **usagestr ? " " : "",
225 *usagestr);
226 usagestr++;
227 }
228
229 if (opts->type != OPTION_GROUP)
230 fputc('\n', stderr);
231
232 for (; opts->type != OPTION_END; opts++) {
233 size_t pos;
234 int pad;
235
236 if (opts->type == OPTION_GROUP) {
237 fputc('\n', stderr);
238 if (*opts->help)
239 fprintf(stderr, "%s\n", opts->help);
240 continue;
241 }
242 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
243 continue;
244
245 pos = fprintf(stderr, " ");
246 if (opts->short_name)
247 pos += fprintf(stderr, "-%c", opts->short_name);
248 else
249 pos += fprintf(stderr, " ");
250
251 if (opts->long_name && opts->short_name)
252 pos += fprintf(stderr, ", ");
253 if (opts->long_name)
254 pos += fprintf(stderr, "--%s", opts->long_name);
255
256 switch (opts->type) {
257 case OPTION_ARGUMENT:
258 break;
259 case OPTION_LONG:
260 case OPTION_U64:
261 case OPTION_INTEGER:
262 case OPTION_UINTEGER:
263 if (opts->flags & PARSE_OPT_OPTARG)
264 if (opts->long_name)
265 pos += fprintf(stderr, "[=<n>]");
266 else
267 pos += fprintf(stderr, "[<n>]");
268 else
269 pos += fprintf(stderr, " <n>");
270 break;
271 case OPTION_CALLBACK:
272 if (opts->flags & PARSE_OPT_NOARG)
273 break;
274 /* FALLTHROUGH */
275 case OPTION_STRING:
276 if (opts->argh) {
277 if (opts->flags & PARSE_OPT_OPTARG)
278 if (opts->long_name)
279 pos += fprintf(stderr, "[=<%s>]", opts->argh);
280 else
281 pos += fprintf(stderr, "[<%s>]", opts->argh);
282 else
283 pos += fprintf(stderr, " <%s>", opts->argh);
284 } else {
285 if (opts->flags & PARSE_OPT_OPTARG)
286 if (opts->long_name)
287 pos += fprintf(stderr, "[=...]");
288 else
289 pos += fprintf(stderr, "[...]");
290 else
291 pos += fprintf(stderr, " ...");
292 }
293 break;
294 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
295 case OPTION_END:
296 case OPTION_GROUP:
297 case OPTION_BIT:
298 case OPTION_BOOLEAN:
299 case OPTION_INCR:
300 case OPTION_SET_UINT:
301 case OPTION_SET_PTR:
302 break;
303 }
304 if (pos <= USAGE_OPTS_WIDTH)
305 pad = USAGE_OPTS_WIDTH - pos;
306 else {
307 fputc('\n', stderr);
308 pad = USAGE_OPTS_WIDTH;
309 }
310 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
311 }
312 fputc('\n', stderr);
313
314 return PARSE_OPT_HELP;
315 }
316
usage_with_options(const char * const * usagestr,const struct option * opts)317 void usage_with_options(const char * const *usagestr,
318 const struct option *opts)
319 {
320 usage_with_options_internal(usagestr, opts, 0);
321 exit(129);
322 }
323
check_typos(const char * arg,const struct option * options)324 static void check_typos(const char *arg, const struct option *options)
325 {
326 if (strlen(arg) < 3)
327 return;
328
329 if (!prefixcmp(arg, "no-")) {
330 pr_err("did you mean `--%s` (with two dashes ?)", arg);
331 exit(129);
332 }
333
334 for (; options->type != OPTION_END; options++) {
335 if (!options->long_name)
336 continue;
337 if (!prefixcmp(options->long_name, arg)) {
338 pr_err("did you mean `--%s` (with two dashes ?)", arg);
339 exit(129);
340 }
341 }
342 }
343
parse_options_usage(const char * const * usagestr,const struct option * opts)344 static int parse_options_usage(const char * const *usagestr,
345 const struct option *opts)
346 {
347 return usage_with_options_internal(usagestr, opts, 0);
348 }
349
parse_short_opt(struct parse_opt_ctx_t * p,const struct option * options)350 static int parse_short_opt(struct parse_opt_ctx_t *p,
351 const struct option *options)
352 {
353 for (; options->type != OPTION_END; options++) {
354 if (options->short_name == *p->opt) {
355 p->opt = p->opt[1] ? p->opt + 1 : NULL;
356 return get_value(p, options, OPT_SHORT);
357 }
358 }
359 return -2;
360 }
361
parse_long_opt(struct parse_opt_ctx_t * p,const char * arg,const struct option * options)362 static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
363 const struct option *options)
364 {
365 const char *arg_end = strchr(arg, '=');
366 const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
367 int abbrev_flags = 0, ambiguous_flags = 0;
368
369 if (!arg_end)
370 arg_end = arg + strlen(arg);
371
372 for (; options->type != OPTION_END; options++) {
373 const char *rest;
374 int flags = 0;
375
376 if (!options->long_name)
377 continue;
378
379 rest = skip_prefix(arg, options->long_name);
380 if (options->type == OPTION_ARGUMENT) {
381 if (!rest)
382 continue;
383 if (*rest == '=')
384 return opterror(options, "takes no value",
385 flags);
386 if (*rest)
387 continue;
388 p->out[p->cpidx++] = arg - 2;
389 return 0;
390 }
391 if (!rest) {
392 /* abbreviated? */
393 if (!strncmp(options->long_name, arg, arg_end - arg)) {
394 is_abbreviated:
395 if (abbrev_option) {
396 /*
397 * If this is abbreviated, it is
398 * ambiguous. So when there is no
399 * exact match later, we need to
400 * error out.
401 */
402 ambiguous_option = abbrev_option;
403 ambiguous_flags = abbrev_flags;
404 }
405 if (!(flags & OPT_UNSET) && *arg_end)
406 p->opt = arg_end + 1;
407 abbrev_option = options;
408 abbrev_flags = flags;
409 continue;
410 }
411 /* negated and abbreviated very much? */
412 if (!prefixcmp("no-", arg)) {
413 flags |= OPT_UNSET;
414 goto is_abbreviated;
415 }
416 /* negated? */
417 if (strncmp(arg, "no-", 3))
418 continue;
419 flags |= OPT_UNSET;
420 rest = skip_prefix(arg + 3, options->long_name);
421 /* abbreviated and negated? */
422 if (!rest && !prefixcmp(options->long_name, arg + 3))
423 goto is_abbreviated;
424 if (!rest)
425 continue;
426 }
427 if (*rest) {
428 if (*rest != '=')
429 continue;
430 p->opt = rest + 1;
431 }
432 return get_value(p, options, flags);
433 }
434
435 if (ambiguous_option) {
436 pr_err("Ambiguous option: %s (could be --%s%s or --%s%s)",
437 arg,
438 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
439 ambiguous_option->long_name,
440 (abbrev_flags & OPT_UNSET) ? "no-" : "",
441 abbrev_option->long_name);
442 return -1;
443 }
444 if (abbrev_option)
445 return get_value(p, abbrev_option, abbrev_flags);
446 return -2;
447 }
448
449
parse_options_start(struct parse_opt_ctx_t * ctx,int argc,const char ** argv,int flags)450 static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc,
451 const char **argv, int flags)
452 {
453 memset(ctx, 0, sizeof(*ctx));
454 ctx->argc = argc;
455 ctx->argv = argv;
456 ctx->out = argv;
457 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
458 ctx->flags = flags;
459 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
460 (flags & PARSE_OPT_STOP_AT_NON_OPTION))
461 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
462 }
463
parse_options_end(struct parse_opt_ctx_t * ctx)464 static int parse_options_end(struct parse_opt_ctx_t *ctx)
465 {
466 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
467 ctx->out[ctx->cpidx + ctx->argc] = NULL;
468 return ctx->cpidx + ctx->argc;
469 }
470
471
parse_options_step(struct parse_opt_ctx_t * ctx,const struct option * options,const char * const usagestr[])472 static int parse_options_step(struct parse_opt_ctx_t *ctx,
473 const struct option *options, const char * const usagestr[])
474 {
475 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
476
477 /* we must reset ->opt, unknown short option leave it dangling */
478 ctx->opt = NULL;
479
480 for (; ctx->argc; ctx->argc--, ctx->argv++) {
481 const char *arg = ctx->argv[0];
482
483 if (*arg != '-' || !arg[1]) {
484 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
485 break;
486 ctx->out[ctx->cpidx++] = ctx->argv[0];
487 continue;
488 }
489
490 if (arg[1] != '-') {
491 ctx->opt = arg + 1;
492 if (internal_help && *ctx->opt == 'h')
493 return parse_options_usage(usagestr, options);
494 switch (parse_short_opt(ctx, options)) {
495 case -1:
496 return parse_options_usage(usagestr, options);
497 case -2:
498 goto unknown;
499 default:
500 break;
501 }
502 if (ctx->opt)
503 check_typos(arg + 1, options);
504 while (ctx->opt) {
505 if (internal_help && *ctx->opt == 'h')
506 return parse_options_usage(usagestr,
507 options);
508 switch (parse_short_opt(ctx, options)) {
509 case -1:
510 return parse_options_usage(usagestr,
511 options);
512 case -2:
513 /* fake a short option thing to hide
514 * the fact that we may have
515 * started to parse aggregated stuff
516 *
517 * This is leaky, too bad.
518 */
519 ctx->argv[0] = strdup(ctx->opt - 1);
520 *(char *)ctx->argv[0] = '-';
521 goto unknown;
522 default:
523 break;
524 }
525 }
526 continue;
527 }
528
529 if (!arg[2]) { /* "--" */
530 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
531 ctx->argc--;
532 ctx->argv++;
533 }
534 break;
535 }
536
537 if (internal_help && !strcmp(arg + 2, "help-all"))
538 return usage_with_options_internal(usagestr, options,
539 1);
540 if (internal_help && !strcmp(arg + 2, "help"))
541 return parse_options_usage(usagestr, options);
542 switch (parse_long_opt(ctx, arg + 2, options)) {
543 case -1:
544 return parse_options_usage(usagestr, options);
545 case -2:
546 goto unknown;
547 default:
548 break;
549 }
550 continue;
551 unknown:
552 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
553 return PARSE_OPT_UNKNOWN;
554 ctx->out[ctx->cpidx++] = ctx->argv[0];
555 ctx->opt = NULL;
556 }
557 return PARSE_OPT_DONE;
558 }
559
parse_options(int argc,const char ** argv,const struct option * options,const char * const usagestr[],int flags)560 int parse_options(int argc, const char **argv, const struct option *options,
561 const char * const usagestr[], int flags)
562 {
563 struct parse_opt_ctx_t ctx;
564
565 parse_options_start(&ctx, argc, argv, flags);
566 switch (parse_options_step(&ctx, options, usagestr)) {
567 case PARSE_OPT_HELP:
568 exit(129);
569 case PARSE_OPT_DONE:
570 break;
571 default: /* PARSE_OPT_UNKNOWN */
572 if (ctx.argv[0][1] == '-') {
573 pr_err("unknown option `%s'", ctx.argv[0] + 2);
574 } else {
575 pr_err("unknown switch `%c'", *ctx.opt);
576 }
577 usage_with_options(usagestr, options);
578 }
579
580 return parse_options_end(&ctx);
581 }
582