Makefile: disable build of t/read-to-pipe-async by default
[fio.git] / parse.c
... / ...
CommitLineData
1/*
2 * This file contains the ini and command liner parser main.
3 */
4#include <stdio.h>
5#include <stdlib.h>
6#include <unistd.h>
7#include <ctype.h>
8#include <string.h>
9#include <errno.h>
10#include <limits.h>
11#include <stdlib.h>
12#include <math.h>
13#include <float.h>
14
15#include "parse.h"
16#include "debug.h"
17#include "options.h"
18#include "optgroup.h"
19#include "minmax.h"
20#include "lib/ieee754.h"
21#include "lib/pow2.h"
22
23#ifdef CONFIG_ARITHMETIC
24#include "y.tab.h"
25#endif
26
27static struct fio_option *__fio_options;
28
29static int vp_cmp(const void *p1, const void *p2)
30{
31 const struct value_pair *vp1 = p1;
32 const struct value_pair *vp2 = p2;
33
34 return strlen(vp2->ival) - strlen(vp1->ival);
35}
36
37static void posval_sort(struct fio_option *o, struct value_pair *vpmap)
38{
39 const struct value_pair *vp;
40 int entries;
41
42 memset(vpmap, 0, PARSE_MAX_VP * sizeof(struct value_pair));
43
44 for (entries = 0; entries < PARSE_MAX_VP; entries++) {
45 vp = &o->posval[entries];
46 if (!vp->ival || vp->ival[0] == '\0')
47 break;
48
49 memcpy(&vpmap[entries], vp, sizeof(*vp));
50 }
51
52 qsort(vpmap, entries, sizeof(struct value_pair), vp_cmp);
53}
54
55static void show_option_range(struct fio_option *o,
56 size_t (*logger)(const char *format, ...))
57{
58 if (o->type == FIO_OPT_FLOAT_LIST) {
59 if (o->minfp == DBL_MIN && o->maxfp == DBL_MAX)
60 return;
61
62 logger("%20s: min=%f", "range", o->minfp);
63 if (o->maxfp != DBL_MAX)
64 logger(", max=%f", o->maxfp);
65 logger("\n");
66 } else if (!o->posval[0].ival) {
67 if (!o->minval && !o->maxval)
68 return;
69
70 logger("%20s: min=%d", "range", o->minval);
71 if (o->maxval)
72 logger(", max=%d", o->maxval);
73 logger("\n");
74 }
75}
76
77static void show_option_values(struct fio_option *o)
78{
79 int i;
80
81 for (i = 0; i < PARSE_MAX_VP; i++) {
82 const struct value_pair *vp = &o->posval[i];
83
84 if (!vp->ival)
85 continue;
86
87 log_info("%20s: %-10s", i == 0 ? "valid values" : "", vp->ival);
88 if (vp->help)
89 log_info(" %s", vp->help);
90 log_info("\n");
91 }
92
93 if (i)
94 log_info("\n");
95}
96
97static void show_option_help(struct fio_option *o, int is_err)
98{
99 const char *typehelp[] = {
100 "invalid",
101 "string (opt=bla)",
102 "string (opt=bla)",
103 "string with possible k/m/g postfix (opt=4k)",
104 "string with time postfix (opt=10s)",
105 "string (opt=bla)",
106 "string with dual range (opt=1k-4k,4k-8k)",
107 "integer value (opt=100)",
108 "boolean value (opt=1)",
109 "list of floating point values separated by ':' (opt=5.9:7.8)",
110 "no argument (opt)",
111 "deprecated",
112 };
113 size_t (*logger)(const char *format, ...);
114
115 if (is_err)
116 logger = log_err;
117 else
118 logger = log_info;
119
120 if (o->alias)
121 logger("%20s: %s\n", "alias", o->alias);
122
123 logger("%20s: %s\n", "type", typehelp[o->type]);
124 logger("%20s: %s\n", "default", o->def ? o->def : "no default");
125 if (o->prof_name)
126 logger("%20s: only for profile '%s'\n", "valid", o->prof_name);
127 show_option_range(o, logger);
128 show_option_values(o);
129}
130
131static unsigned long long get_mult_time(const char *str, int len,
132 int is_seconds)
133{
134 const char *p = str;
135 char *c;
136 unsigned long long mult = 1;
137
138 /*
139 * Go forward until we hit a non-digit, or +/- sign
140 */
141 while ((p - str) <= len) {
142 if (!isdigit((int) *p) && (*p != '+') && (*p != '-'))
143 break;
144 p++;
145 }
146
147 if (!isalpha((int) *p)) {
148 if (is_seconds)
149 return 1000000UL;
150 else
151 return 1;
152 }
153
154 c = strdup(p);
155 for (int i = 0; i < strlen(c); i++)
156 c[i] = tolower(c[i]);
157
158 if (!strncmp("us", c, 2) || !strncmp("usec", c, 4))
159 mult = 1;
160 else if (!strncmp("ms", c, 2) || !strncmp("msec", c, 4))
161 mult = 1000;
162 else if (!strcmp("s", c))
163 mult = 1000000;
164 else if (!strcmp("m", c))
165 mult = 60 * 1000000UL;
166 else if (!strcmp("h", c))
167 mult = 60 * 60 * 1000000UL;
168 else if (!strcmp("d", c))
169 mult = 24 * 60 * 60 * 1000000UL;
170
171 free(c);
172 return mult;
173}
174
175static int is_separator(char c)
176{
177 switch (c) {
178 case ':':
179 case '-':
180 case ',':
181 case '/':
182 return 1;
183 default:
184 return 0;
185 }
186}
187
188static unsigned long long __get_mult_bytes(const char *p, void *data,
189 int *percent)
190{
191 unsigned int kb_base = fio_get_kb_base(data);
192 unsigned long long ret = 1;
193 unsigned int i, pow = 0, mult = kb_base;
194 char *c;
195
196 if (!p)
197 return 1;
198
199 c = strdup(p);
200
201 for (i = 0; i < strlen(c); i++) {
202 c[i] = tolower(c[i]);
203 if (is_separator(c[i])) {
204 c[i] = '\0';
205 break;
206 }
207 }
208
209 if (!strncmp("pib", c, 3)) {
210 pow = 5;
211 mult = 1000;
212 } else if (!strncmp("tib", c, 3)) {
213 pow = 4;
214 mult = 1000;
215 } else if (!strncmp("gib", c, 3)) {
216 pow = 3;
217 mult = 1000;
218 } else if (!strncmp("mib", c, 3)) {
219 pow = 2;
220 mult = 1000;
221 } else if (!strncmp("kib", c, 3)) {
222 pow = 1;
223 mult = 1000;
224 } else if (!strncmp("p", c, 1) || !strncmp("pb", c, 2))
225 pow = 5;
226 else if (!strncmp("t", c, 1) || !strncmp("tb", c, 2))
227 pow = 4;
228 else if (!strncmp("g", c, 1) || !strncmp("gb", c, 2))
229 pow = 3;
230 else if (!strncmp("m", c, 1) || !strncmp("mb", c, 2))
231 pow = 2;
232 else if (!strncmp("k", c, 1) || !strncmp("kb", c, 2))
233 pow = 1;
234 else if (!strncmp("%", c, 1)) {
235 *percent = 1;
236 free(c);
237 return ret;
238 }
239
240 while (pow--)
241 ret *= (unsigned long long) mult;
242
243 free(c);
244 return ret;
245}
246
247static unsigned long long get_mult_bytes(const char *str, int len, void *data,
248 int *percent)
249{
250 const char *p = str;
251 int digit_seen = 0;
252
253 if (len < 2)
254 return __get_mult_bytes(str, data, percent);
255
256 /*
257 * Go forward until we hit a non-digit, or +/- sign
258 */
259 while ((p - str) <= len) {
260 if (!isdigit((int) *p) &&
261 (((*p != '+') && (*p != '-')) || digit_seen))
262 break;
263 digit_seen |= isdigit((int) *p);
264 p++;
265 }
266
267 if (!isalpha((int) *p) && (*p != '%'))
268 p = NULL;
269
270 return __get_mult_bytes(p, data, percent);
271}
272
273extern int evaluate_arithmetic_expression(const char *buffer, long long *ival,
274 double *dval, double implied_units,
275 int is_time);
276
277/*
278 * Convert string into a floating number. Return 1 for success and 0 otherwise.
279 */
280int str_to_float(const char *str, double *val, int is_time)
281{
282#ifdef CONFIG_ARITHMETIC
283 int rc;
284 long long ival;
285 double dval;
286
287 if (str[0] == '(') {
288 rc = evaluate_arithmetic_expression(str, &ival, &dval, 1.0, is_time);
289 if (!rc) {
290 *val = dval;
291 return 1;
292 }
293 }
294#endif
295 return 1 == sscanf(str, "%lf", val);
296}
297
298/*
299 * convert string into decimal value, noting any size suffix
300 */
301int str_to_decimal(const char *str, long long *val, int kilo, void *data,
302 int is_seconds, int is_time)
303{
304 int len, base;
305 int rc = 1;
306#ifdef CONFIG_ARITHMETIC
307 long long ival;
308 double dval;
309 double implied_units = 1.0;
310#endif
311
312 len = strlen(str);
313 if (!len)
314 return 1;
315
316#ifdef CONFIG_ARITHMETIC
317 if (is_seconds)
318 implied_units = 1000000.0;
319 if (str[0] == '(')
320 rc = evaluate_arithmetic_expression(str, &ival, &dval, implied_units, is_time);
321 if (str[0] == '(' && !rc) {
322 if (!kilo && is_seconds)
323 *val = ival / 1000000LL;
324 else
325 *val = ival;
326 }
327#endif
328
329 if (rc == 1) {
330 if (strstr(str, "0x") || strstr(str, "0X"))
331 base = 16;
332 else
333 base = 10;
334
335 *val = strtoll(str, NULL, base);
336 if (*val == LONG_MAX && errno == ERANGE)
337 return 1;
338 }
339
340 if (kilo) {
341 unsigned long long mult;
342 int perc = 0;
343
344 mult = get_mult_bytes(str, len, data, &perc);
345 if (perc)
346 *val = -1ULL - *val;
347 else
348 *val *= mult;
349 } else
350 *val *= get_mult_time(str, len, is_seconds);
351
352 return 0;
353}
354
355int check_str_bytes(const char *p, long long *val, void *data)
356{
357 return str_to_decimal(p, val, 1, data, 0, 0);
358}
359
360int check_str_time(const char *p, long long *val, int is_seconds)
361{
362 return str_to_decimal(p, val, 0, NULL, is_seconds, 1);
363}
364
365void strip_blank_front(char **p)
366{
367 char *s = *p;
368
369 if (!strlen(s))
370 return;
371 while (isspace((int) *s))
372 s++;
373
374 *p = s;
375}
376
377void strip_blank_end(char *p)
378{
379 char *start = p, *s;
380
381 if (!strlen(p))
382 return;
383
384 s = strchr(p, ';');
385 if (s)
386 *s = '\0';
387 s = strchr(p, '#');
388 if (s)
389 *s = '\0';
390 if (s)
391 p = s;
392
393 s = p + strlen(p);
394 while ((isspace((int) *s) || iscntrl((int) *s)) && (s > start))
395 s--;
396
397 *(s + 1) = '\0';
398}
399
400static int check_range_bytes(const char *str, long *val, void *data)
401{
402 long long __val;
403
404 if (!str_to_decimal(str, &__val, 1, data, 0, 0)) {
405 *val = __val;
406 return 0;
407 }
408
409 return 1;
410}
411
412static int check_int(const char *p, int *val)
413{
414 if (!strlen(p))
415 return 1;
416 if (strstr(p, "0x") || strstr(p, "0X")) {
417 if (sscanf(p, "%x", val) == 1)
418 return 0;
419 } else {
420 if (sscanf(p, "%u", val) == 1)
421 return 0;
422 }
423
424 return 1;
425}
426
427static size_t opt_len(const char *str)
428{
429 char *postfix;
430
431 postfix = strchr(str, ':');
432 if (!postfix)
433 return strlen(str);
434
435 return (int)(postfix - str);
436}
437
438static int str_match_len(const struct value_pair *vp, const char *str)
439{
440 return max(strlen(vp->ival), opt_len(str));
441}
442
443#define val_store(ptr, val, off, or, data, o) \
444 do { \
445 ptr = td_var((data), (o), (off)); \
446 if ((or)) \
447 *ptr |= (val); \
448 else \
449 *ptr = (val); \
450 } while (0)
451
452static int __handle_option(struct fio_option *o, const char *ptr, void *data,
453 int first, int more, int curr)
454{
455 int il=0, *ilp;
456 fio_fp64_t *flp;
457 long long ull, *ullp;
458 long ul1, ul2;
459 double uf;
460 char **cp = NULL;
461 int ret = 0, is_time = 0;
462 const struct value_pair *vp;
463 struct value_pair posval[PARSE_MAX_VP];
464 int i, all_skipped = 1;
465
466 dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name,
467 o->type, ptr);
468
469 if (!ptr && o->type != FIO_OPT_STR_SET && o->type != FIO_OPT_STR) {
470 log_err("Option %s requires an argument\n", o->name);
471 return 1;
472 }
473
474 switch (o->type) {
475 case FIO_OPT_STR:
476 case FIO_OPT_STR_MULTI: {
477 fio_opt_str_fn *fn = o->cb;
478
479 posval_sort(o, posval);
480
481 ret = 1;
482 for (i = 0; i < PARSE_MAX_VP; i++) {
483 vp = &posval[i];
484 if (!vp->ival || vp->ival[0] == '\0')
485 continue;
486 all_skipped = 0;
487 if (!ptr)
488 break;
489 if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) {
490 ret = 0;
491 if (o->off1)
492 val_store(ilp, vp->oval, o->off1, vp->orval, data, o);
493 continue;
494 }
495 }
496
497 if (ret && !all_skipped)
498 show_option_values(o);
499 else if (fn)
500 ret = fn(data, ptr);
501 break;
502 }
503 case FIO_OPT_STR_VAL_TIME:
504 is_time = 1;
505 case FIO_OPT_INT:
506 case FIO_OPT_STR_VAL: {
507 fio_opt_str_val_fn *fn = o->cb;
508 char tmp[128], *p;
509
510 if (!is_time && o->is_time)
511 is_time = o->is_time;
512
513 tmp[sizeof(tmp) - 1] = '\0';
514 strncpy(tmp, ptr, sizeof(tmp) - 1);
515 p = strchr(tmp, ',');
516 if (p)
517 *p = '\0';
518
519 if (is_time)
520 ret = check_str_time(tmp, &ull, o->is_seconds);
521 else
522 ret = check_str_bytes(tmp, &ull, data);
523
524 dprint(FD_PARSE, " ret=%d, out=%llu\n", ret, ull);
525
526 if (ret)
527 break;
528 if (o->pow2 && !is_power_of_2(ull)) {
529 log_err("%s: must be a power-of-2\n", o->name);
530 return 1;
531 }
532
533 if (o->maxval && ull > o->maxval) {
534 log_err("max value out of range: %llu"
535 " (%u max)\n", ull, o->maxval);
536 return 1;
537 }
538 if (o->minval && ull < o->minval) {
539 log_err("min value out of range: %llu"
540 " (%u min)\n", ull, o->minval);
541 return 1;
542 }
543 if (o->posval[0].ival) {
544 posval_sort(o, posval);
545
546 ret = 1;
547 for (i = 0; i < PARSE_MAX_VP; i++) {
548 vp = &posval[i];
549 if (!vp->ival || vp->ival[0] == '\0')
550 continue;
551 if (vp->oval == ull) {
552 ret = 0;
553 break;
554 }
555 }
556 if (ret) {
557 log_err("fio: value %llu not allowed:\n", ull);
558 show_option_values(o);
559 return 1;
560 }
561 }
562
563 if (fn)
564 ret = fn(data, &ull);
565 else {
566 if (o->type == FIO_OPT_INT) {
567 if (first)
568 val_store(ilp, ull, o->off1, 0, data, o);
569 if (curr == 1) {
570 if (o->off2)
571 val_store(ilp, ull, o->off2, 0, data, o);
572 }
573 if (curr == 2) {
574 if (o->off3)
575 val_store(ilp, ull, o->off3, 0, data, o);
576 }
577 if (!more) {
578 if (curr < 1) {
579 if (o->off2)
580 val_store(ilp, ull, o->off2, 0, data, o);
581 }
582 if (curr < 2) {
583 if (o->off3)
584 val_store(ilp, ull, o->off3, 0, data, o);
585 }
586 }
587 } else {
588 if (first)
589 val_store(ullp, ull, o->off1, 0, data, o);
590 if (!more) {
591 if (o->off2)
592 val_store(ullp, ull, o->off2, 0, data, o);
593 }
594 }
595 }
596 break;
597 }
598 case FIO_OPT_FLOAT_LIST: {
599 char *cp2;
600
601 if (first) {
602 /*
603 ** Initialize precision to 0 and zero out list
604 ** in case specified list is shorter than default
605 */
606 if (o->off2) {
607 ul2 = 0;
608 ilp = td_var(data, o, o->off2);
609 *ilp = ul2;
610 }
611
612 flp = td_var(data, o, o->off1);
613 for(i = 0; i < o->maxlen; i++)
614 flp[i].u.f = 0.0;
615 }
616 if (curr >= o->maxlen) {
617 log_err("the list exceeding max length %d\n",
618 o->maxlen);
619 return 1;
620 }
621 if (!str_to_float(ptr, &uf, 0)) { /* this breaks if we ever have lists of times */
622 log_err("not a floating point value: %s\n", ptr);
623 return 1;
624 }
625 if (uf > o->maxfp) {
626 log_err("value out of range: %f"
627 " (range max: %f)\n", uf, o->maxfp);
628 return 1;
629 }
630 if (uf < o->minfp) {
631 log_err("value out of range: %f"
632 " (range min: %f)\n", uf, o->minfp);
633 return 1;
634 }
635
636 flp = td_var(data, o, o->off1);
637 flp[curr].u.f = uf;
638
639 dprint(FD_PARSE, " out=%f\n", uf);
640
641 /*
642 ** Calculate precision for output by counting
643 ** number of digits after period. Find first
644 ** period in entire remaining list each time
645 */
646 cp2 = strchr(ptr, '.');
647 if (cp2 != NULL) {
648 int len = 0;
649
650 while (*++cp2 != '\0' && *cp2 >= '0' && *cp2 <= '9')
651 len++;
652
653 if (o->off2) {
654 ilp = td_var(data, o, o->off2);
655 if (len > *ilp)
656 *ilp = len;
657 }
658 }
659
660 break;
661 }
662 case FIO_OPT_STR_STORE: {
663 fio_opt_str_fn *fn = o->cb;
664
665 if (!strlen(ptr))
666 return 1;
667
668 if (o->off1) {
669 cp = td_var(data, o, o->off1);
670 *cp = strdup(ptr);
671 }
672
673 if (fn)
674 ret = fn(data, ptr);
675 else if (o->posval[0].ival) {
676 posval_sort(o, posval);
677
678 ret = 1;
679 for (i = 0; i < PARSE_MAX_VP; i++) {
680 vp = &posval[i];
681 if (!vp->ival || vp->ival[0] == '\0' || !cp)
682 continue;
683 all_skipped = 0;
684 if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) {
685 char *rest;
686
687 ret = 0;
688 if (vp->cb)
689 fn = vp->cb;
690 rest = strstr(*cp ?: ptr, ":");
691 if (rest) {
692 if (*cp)
693 *rest = '\0';
694 ptr = rest + 1;
695 } else
696 ptr = NULL;
697 break;
698 }
699 }
700 }
701
702 if (!all_skipped) {
703 if (ret && !*cp)
704 show_option_values(o);
705 else if (ret && *cp)
706 ret = 0;
707 else if (fn && ptr)
708 ret = fn(data, ptr);
709 }
710
711 break;
712 }
713 case FIO_OPT_RANGE: {
714 char tmp[128];
715 char *p1, *p2;
716
717 tmp[sizeof(tmp) - 1] = '\0';
718 strncpy(tmp, ptr, sizeof(tmp) - 1);
719
720 /* Handle bsrange with separate read,write values: */
721 p1 = strchr(tmp, ',');
722 if (p1)
723 *p1 = '\0';
724
725 p1 = strchr(tmp, '-');
726 if (!p1) {
727 p1 = strchr(tmp, ':');
728 if (!p1) {
729 ret = 1;
730 break;
731 }
732 }
733
734 p2 = p1 + 1;
735 *p1 = '\0';
736 p1 = tmp;
737
738 ret = 1;
739 if (!check_range_bytes(p1, &ul1, data) &&
740 !check_range_bytes(p2, &ul2, data)) {
741 ret = 0;
742 if (ul1 > ul2) {
743 unsigned long foo = ul1;
744
745 ul1 = ul2;
746 ul2 = foo;
747 }
748
749 if (first) {
750 val_store(ilp, ul1, o->off1, 0, data, o);
751 val_store(ilp, ul2, o->off2, 0, data, o);
752 }
753 if (curr == 1) {
754 if (o->off3 && o->off4) {
755 val_store(ilp, ul1, o->off3, 0, data, o);
756 val_store(ilp, ul2, o->off4, 0, data, o);
757 }
758 }
759 if (curr == 2) {
760 if (o->off5 && o->off6) {
761 val_store(ilp, ul1, o->off5, 0, data, o);
762 val_store(ilp, ul2, o->off6, 0, data, o);
763 }
764 }
765 if (!more) {
766 if (curr < 1) {
767 if (o->off3 && o->off4) {
768 val_store(ilp, ul1, o->off3, 0, data, o);
769 val_store(ilp, ul2, o->off4, 0, data, o);
770 }
771 }
772 if (curr < 2) {
773 if (o->off5 && o->off6) {
774 val_store(ilp, ul1, o->off5, 0, data, o);
775 val_store(ilp, ul2, o->off6, 0, data, o);
776 }
777 }
778 }
779 }
780
781 break;
782 }
783 case FIO_OPT_BOOL:
784 case FIO_OPT_STR_SET: {
785 fio_opt_int_fn *fn = o->cb;
786
787 if (ptr)
788 ret = check_int(ptr, &il);
789 else if (o->type == FIO_OPT_BOOL)
790 ret = 1;
791 else
792 il = 1;
793
794 dprint(FD_PARSE, " ret=%d, out=%d\n", ret, il);
795
796 if (ret)
797 break;
798
799 if (o->maxval && il > (int) o->maxval) {
800 log_err("max value out of range: %d (%d max)\n",
801 il, o->maxval);
802 return 1;
803 }
804 if (o->minval && il < o->minval) {
805 log_err("min value out of range: %d (%d min)\n",
806 il, o->minval);
807 return 1;
808 }
809
810 if (o->neg)
811 il = !il;
812
813 if (fn)
814 ret = fn(data, &il);
815 else {
816 if (first)
817 val_store(ilp, il, o->off1, 0, data, o);
818 if (!more) {
819 if (o->off2)
820 val_store(ilp, il, o->off2, 0, data, o);
821 }
822 }
823 break;
824 }
825 case FIO_OPT_DEPRECATED:
826 log_info("Option %s is deprecated\n", o->name);
827 ret = 1;
828 break;
829 default:
830 log_err("Bad option type %u\n", o->type);
831 ret = 1;
832 }
833
834 if (ret)
835 return ret;
836
837 if (o->verify) {
838 ret = o->verify(o, data);
839 if (ret) {
840 log_err("Correct format for offending option\n");
841 log_err("%20s: %s\n", o->name, o->help);
842 show_option_help(o, 1);
843 }
844 }
845
846 return ret;
847}
848
849static int handle_option(struct fio_option *o, const char *__ptr, void *data)
850{
851 char *o_ptr, *ptr, *ptr2;
852 int ret, done;
853
854 dprint(FD_PARSE, "handle_option=%s, ptr=%s\n", o->name, __ptr);
855
856 o_ptr = ptr = NULL;
857 if (__ptr)
858 o_ptr = ptr = strdup(__ptr);
859
860 /*
861 * See if we have another set of parameters, hidden after a comma.
862 * Do this before parsing this round, to check if we should
863 * copy set 1 options to set 2.
864 */
865 done = 0;
866 ret = 1;
867 do {
868 int __ret;
869
870 ptr2 = NULL;
871 if (ptr &&
872 (o->type != FIO_OPT_STR_STORE) &&
873 (o->type != FIO_OPT_STR) &&
874 (o->type != FIO_OPT_FLOAT_LIST)) {
875 ptr2 = strchr(ptr, ',');
876 if (ptr2 && *(ptr2 + 1) == '\0')
877 *ptr2 = '\0';
878 if (o->type != FIO_OPT_STR_MULTI && o->type != FIO_OPT_RANGE) {
879 if (!ptr2)
880 ptr2 = strchr(ptr, ':');
881 if (!ptr2)
882 ptr2 = strchr(ptr, '-');
883 }
884 } else if (ptr && o->type == FIO_OPT_FLOAT_LIST) {
885 ptr2 = strchr(ptr, ':');
886 }
887
888 /*
889 * Don't return early if parsing the first option fails - if
890 * we are doing multiple arguments, we can allow the first one
891 * being empty.
892 */
893 __ret = __handle_option(o, ptr, data, !done, !!ptr2, done);
894 if (ret)
895 ret = __ret;
896
897 if (!ptr2)
898 break;
899
900 ptr = ptr2 + 1;
901 done++;
902 } while (1);
903
904 if (o_ptr)
905 free(o_ptr);
906 return ret;
907}
908
909static struct fio_option *get_option(char *opt,
910 struct fio_option *options, char **post)
911{
912 struct fio_option *o;
913 char *ret;
914
915 ret = strchr(opt, '=');
916 if (ret) {
917 *post = ret;
918 *ret = '\0';
919 ret = opt;
920 (*post)++;
921 strip_blank_end(ret);
922 o = find_option(options, ret);
923 } else {
924 o = find_option(options, opt);
925 *post = NULL;
926 }
927
928 return o;
929}
930
931static int opt_cmp(const void *p1, const void *p2)
932{
933 struct fio_option *o;
934 char *s, *foo;
935 int prio1, prio2;
936
937 prio1 = prio2 = 0;
938
939 if (*(char **)p1) {
940 s = strdup(*((char **) p1));
941 o = get_option(s, __fio_options, &foo);
942 if (o)
943 prio1 = o->prio;
944 free(s);
945 }
946 if (*(char **)p2) {
947 s = strdup(*((char **) p2));
948 o = get_option(s, __fio_options, &foo);
949 if (o)
950 prio2 = o->prio;
951 free(s);
952 }
953
954 return prio2 - prio1;
955}
956
957void sort_options(char **opts, struct fio_option *options, int num_opts)
958{
959 __fio_options = options;
960 qsort(opts, num_opts, sizeof(char *), opt_cmp);
961 __fio_options = NULL;
962}
963
964static void add_to_dump_list(struct fio_option *o, struct flist_head *dump_list,
965 const char *post)
966{
967 struct print_option *p;
968
969 if (!dump_list)
970 return;
971
972 p = malloc(sizeof(*p));
973 p->name = strdup(o->name);
974 if (post)
975 p->value = strdup(post);
976 else
977 p->value = NULL;
978
979 flist_add_tail(&p->list, dump_list);
980}
981
982int parse_cmd_option(const char *opt, const char *val,
983 struct fio_option *options, void *data,
984 struct flist_head *dump_list)
985{
986 struct fio_option *o;
987
988 o = find_option(options, opt);
989 if (!o) {
990 log_err("Bad option <%s>\n", opt);
991 return 1;
992 }
993
994 if (handle_option(o, val, data)) {
995 log_err("fio: failed parsing %s=%s\n", opt, val);
996 return 1;
997 }
998
999 add_to_dump_list(o, dump_list, val);
1000 return 0;
1001}
1002
1003int parse_option(char *opt, const char *input,
1004 struct fio_option *options, struct fio_option **o, void *data,
1005 struct flist_head *dump_list)
1006{
1007 char *post;
1008
1009 if (!opt) {
1010 log_err("fio: failed parsing %s\n", input);
1011 *o = NULL;
1012 return 1;
1013 }
1014
1015 *o = get_option(opt, options, &post);
1016 if (!*o) {
1017 if (post) {
1018 int len = strlen(opt);
1019 if (opt + len + 1 != post)
1020 memmove(opt + len + 1, post, strlen(post));
1021 opt[len] = '=';
1022 }
1023 return 1;
1024 }
1025
1026 if (handle_option(*o, post, data)) {
1027 log_err("fio: failed parsing %s\n", input);
1028 return 1;
1029 }
1030
1031 add_to_dump_list(*o, dump_list, post);
1032 return 0;
1033}
1034
1035/*
1036 * Option match, levenshtein distance. Handy for not quite remembering what
1037 * the option name is.
1038 */
1039int string_distance(const char *s1, const char *s2)
1040{
1041 unsigned int s1_len = strlen(s1);
1042 unsigned int s2_len = strlen(s2);
1043 unsigned int *p, *q, *r;
1044 unsigned int i, j;
1045
1046 p = malloc(sizeof(unsigned int) * (s2_len + 1));
1047 q = malloc(sizeof(unsigned int) * (s2_len + 1));
1048
1049 p[0] = 0;
1050 for (i = 1; i <= s2_len; i++)
1051 p[i] = p[i - 1] + 1;
1052
1053 for (i = 1; i <= s1_len; i++) {
1054 q[0] = p[0] + 1;
1055 for (j = 1; j <= s2_len; j++) {
1056 unsigned int sub = p[j - 1];
1057 unsigned int pmin;
1058
1059 if (s1[i - 1] != s2[j - 1])
1060 sub++;
1061
1062 pmin = min(q[j - 1] + 1, sub);
1063 q[j] = min(p[j] + 1, pmin);
1064 }
1065 r = p;
1066 p = q;
1067 q = r;
1068 }
1069
1070 i = p[s2_len];
1071 free(p);
1072 free(q);
1073 return i;
1074}
1075
1076/*
1077 * Make a guess of whether the distance from 's1' is significant enough
1078 * to warrant printing the guess. We set this to a 1/2 match.
1079 */
1080int string_distance_ok(const char *opt, int distance)
1081{
1082 size_t len;
1083
1084 len = strlen(opt);
1085 len = (len + 1) / 2;
1086 return distance <= len;
1087}
1088
1089static struct fio_option *find_child(struct fio_option *options,
1090 struct fio_option *o)
1091{
1092 struct fio_option *__o;
1093
1094 for (__o = options + 1; __o->name; __o++)
1095 if (__o->parent && !strcmp(__o->parent, o->name))
1096 return __o;
1097
1098 return NULL;
1099}
1100
1101static void __print_option(struct fio_option *o, struct fio_option *org,
1102 int level)
1103{
1104 char name[256], *p;
1105 int depth;
1106
1107 if (!o)
1108 return;
1109 if (!org)
1110 org = o;
1111
1112 p = name;
1113 depth = level;
1114 while (depth--)
1115 p += sprintf(p, "%s", " ");
1116
1117 sprintf(p, "%s", o->name);
1118
1119 log_info("%-24s: %s\n", name, o->help);
1120}
1121
1122static void print_option(struct fio_option *o)
1123{
1124 struct fio_option *parent;
1125 struct fio_option *__o;
1126 unsigned int printed;
1127 unsigned int level;
1128
1129 __print_option(o, NULL, 0);
1130 parent = o;
1131 level = 0;
1132 do {
1133 level++;
1134 printed = 0;
1135
1136 while ((__o = find_child(o, parent)) != NULL) {
1137 __print_option(__o, o, level);
1138 o = __o;
1139 printed++;
1140 }
1141
1142 parent = o;
1143 } while (printed);
1144}
1145
1146int show_cmd_help(struct fio_option *options, const char *name)
1147{
1148 struct fio_option *o, *closest;
1149 unsigned int best_dist = -1U;
1150 int found = 0;
1151 int show_all = 0;
1152
1153 if (!name || !strcmp(name, "all"))
1154 show_all = 1;
1155
1156 closest = NULL;
1157 best_dist = -1;
1158 for (o = &options[0]; o->name; o++) {
1159 int match = 0;
1160
1161 if (o->type == FIO_OPT_DEPRECATED)
1162 continue;
1163 if (!exec_profile && o->prof_name)
1164 continue;
1165 if (exec_profile && !(o->prof_name && !strcmp(exec_profile, o->prof_name)))
1166 continue;
1167
1168 if (name) {
1169 if (!strcmp(name, o->name) ||
1170 (o->alias && !strcmp(name, o->alias)))
1171 match = 1;
1172 else {
1173 unsigned int dist;
1174
1175 dist = string_distance(name, o->name);
1176 if (dist < best_dist) {
1177 best_dist = dist;
1178 closest = o;
1179 }
1180 }
1181 }
1182
1183 if (show_all || match) {
1184 found = 1;
1185 if (match)
1186 log_info("%20s: %s\n", o->name, o->help);
1187 if (show_all) {
1188 if (!o->parent)
1189 print_option(o);
1190 continue;
1191 }
1192 }
1193
1194 if (!match)
1195 continue;
1196
1197 show_option_help(o, 0);
1198 }
1199
1200 if (found)
1201 return 0;
1202
1203 log_err("No such command: %s", name);
1204
1205 /*
1206 * Only print an appropriately close option, one where the edit
1207 * distance isn't too big. Otherwise we get crazy matches.
1208 */
1209 if (closest && best_dist < 3) {
1210 log_info(" - showing closest match\n");
1211 log_info("%20s: %s\n", closest->name, closest->help);
1212 show_option_help(closest, 0);
1213 } else
1214 log_info("\n");
1215
1216 return 1;
1217}
1218
1219/*
1220 * Handle parsing of default parameters.
1221 */
1222void fill_default_options(void *data, struct fio_option *options)
1223{
1224 struct fio_option *o;
1225
1226 dprint(FD_PARSE, "filling default options\n");
1227
1228 for (o = &options[0]; o->name; o++)
1229 if (o->def)
1230 handle_option(o, o->def, data);
1231}
1232
1233void option_init(struct fio_option *o)
1234{
1235 if (o->type == FIO_OPT_DEPRECATED)
1236 return;
1237 if (o->type == FIO_OPT_BOOL) {
1238 o->minval = 0;
1239 o->maxval = 1;
1240 }
1241 if (o->type == FIO_OPT_INT) {
1242 if (!o->maxval)
1243 o->maxval = UINT_MAX;
1244 }
1245 if (o->type == FIO_OPT_FLOAT_LIST) {
1246 o->minfp = DBL_MIN;
1247 o->maxfp = DBL_MAX;
1248 }
1249 if (o->type == FIO_OPT_STR_SET && o->def && !o->no_warn_def) {
1250 log_err("Option %s: string set option with"
1251 " default will always be true\n", o->name);
1252 }
1253 if (!o->cb && !o->off1)
1254 log_err("Option %s: neither cb nor offset given\n", o->name);
1255 if (!o->category) {
1256 log_info("Option %s: no category defined. Setting to misc\n", o->name);
1257 o->category = FIO_OPT_C_GENERAL;
1258 o->group = FIO_OPT_G_INVALID;
1259 }
1260 if (o->type == FIO_OPT_STR || o->type == FIO_OPT_STR_STORE ||
1261 o->type == FIO_OPT_STR_MULTI)
1262 return;
1263}
1264
1265/*
1266 * Sanitize the options structure. For now it just sets min/max for bool
1267 * values and whether both callback and offsets are given.
1268 */
1269void options_init(struct fio_option *options)
1270{
1271 struct fio_option *o;
1272
1273 dprint(FD_PARSE, "init options\n");
1274
1275 for (o = &options[0]; o->name; o++) {
1276 option_init(o);
1277 if (o->inverse)
1278 o->inv_opt = find_option(options, o->inverse);
1279 }
1280}
1281
1282void options_free(struct fio_option *options, void *data)
1283{
1284 struct fio_option *o;
1285 char **ptr;
1286
1287 dprint(FD_PARSE, "free options\n");
1288
1289 for (o = &options[0]; o->name; o++) {
1290 if (o->type != FIO_OPT_STR_STORE || !o->off1)
1291 continue;
1292
1293 ptr = td_var(data, o, o->off1);
1294 if (*ptr) {
1295 free(*ptr);
1296 *ptr = NULL;
1297 }
1298 }
1299}