stat: fix reversed check for ramp time
[fio.git] / parse.c
CommitLineData
cb2c86fd
JA
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>
88b5a391 11#include <stdlib.h>
83349190 12#include <math.h>
ab9461ea 13#include <float.h>
cb2c86fd
JA
14
15#include "parse.h"
a3d741fa 16#include "debug.h"
9f988e2e 17#include "options.h"
d220c761 18#include "optgroup.h"
e25839d4 19#include "minmax.h"
fd112d34 20#include "lib/ieee754.h"
0f38bbef 21#include "lib/pow2.h"
cb2c86fd 22
b470a02c
SC
23#ifdef CONFIG_ARITHMETIC
24#include "y.tab.h"
25#endif
26
9af4a244 27static struct fio_option *__fio_options;
3b8b7135 28
f085737f
JA
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
ce952ab6 37static void posval_sort(struct fio_option *o, struct value_pair *vpmap)
f085737f
JA
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
06b0be6e 55static void show_option_range(struct fio_option *o,
5768cc2b 56 size_t (*logger)(const char *format, ...))
b1ec1da6 57{
3c037bcf 58 if (o->type == FIO_OPT_FLOAT_LIST) {
ab9461ea 59 if (o->minfp == DBL_MIN && o->maxfp == DBL_MAX)
83349190
YH
60 return;
61
06b0be6e 62 logger("%20s: min=%f", "range", o->minfp);
ab9461ea 63 if (o->maxfp != DBL_MAX)
06b0be6e
JA
64 logger(", max=%f", o->maxfp);
65 logger("\n");
3c037bcf 66 } else if (!o->posval[0].ival) {
83349190
YH
67 if (!o->minval && !o->maxval)
68 return;
b1ec1da6 69
06b0be6e 70 logger("%20s: min=%d", "range", o->minval);
83349190 71 if (o->maxval)
06b0be6e
JA
72 logger(", max=%d", o->maxval);
73 logger("\n");
83349190 74 }
b1ec1da6
JA
75}
76
77static void show_option_values(struct fio_option *o)
78{
a3073f4a 79 int i;
b1ec1da6 80
a3073f4a 81 for (i = 0; i < PARSE_MAX_VP; i++) {
7837213b 82 const struct value_pair *vp = &o->posval[i];
b1ec1da6 83
7837213b 84 if (!vp->ival)
a3073f4a 85 continue;
b1ec1da6 86
06b0be6e 87 log_info("%20s: %-10s", i == 0 ? "valid values" : "", vp->ival);
7837213b 88 if (vp->help)
06b0be6e
JA
89 log_info(" %s", vp->help);
90 log_info("\n");
a3073f4a 91 }
b1ec1da6
JA
92
93 if (i)
06b0be6e 94 log_info("\n");
b1ec1da6
JA
95}
96
06b0be6e 97static void show_option_help(struct fio_option *o, int is_err)
d447a8c2
JA
98{
99 const char *typehelp[] = {
07b3232d 100 "invalid",
d447a8c2 101 "string (opt=bla)",
ae3fb6fb 102 "string (opt=bla)",
d447a8c2
JA
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)",
83349190 109 "list of floating point values separated by ':' (opt=5.9:7.8)",
d447a8c2 110 "no argument (opt)",
07b3232d 111 "deprecated",
d447a8c2 112 };
5768cc2b 113 size_t (*logger)(const char *format, ...);
06b0be6e
JA
114
115 if (is_err)
116 logger = log_err;
117 else
118 logger = log_info;
d447a8c2
JA
119
120 if (o->alias)
06b0be6e 121 logger("%20s: %s\n", "alias", o->alias);
d447a8c2 122
06b0be6e
JA
123 logger("%20s: %s\n", "type", typehelp[o->type]);
124 logger("%20s: %s\n", "default", o->def ? o->def : "no default");
07b3232d 125 if (o->prof_name)
06b0be6e
JA
126 logger("%20s: only for profile '%s'\n", "valid", o->prof_name);
127 show_option_range(o, logger);
d447a8c2
JA
128 show_option_values(o);
129}
130
0de5b26f
JA
131static unsigned long long get_mult_time(const char *str, int len,
132 int is_seconds)
cb2c86fd 133{
74454ce4
CE
134 const char *p = str;
135 char *c;
e4668264 136 unsigned long long mult = 1;
74454ce4
CE
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++;
cb2c86fd 145 }
74454ce4 146
0de5b26f
JA
147 if (!isalpha((int) *p)) {
148 if (is_seconds)
149 return 1000000UL;
150 else
151 return 1;
152 }
74454ce4
CE
153
154 c = strdup(p);
155 for (int i = 0; i < strlen(c); i++)
156 c[i] = tolower(c[i]);
157
e4668264 158 if (!strncmp("us", c, 2) || !strncmp("usec", c, 4))
74454ce4 159 mult = 1;
e4668264 160 else if (!strncmp("ms", c, 2) || !strncmp("msec", c, 4))
74454ce4 161 mult = 1000;
e4668264
JA
162 else if (!strcmp("s", c))
163 mult = 1000000;
74454ce4 164 else if (!strcmp("m", c))
e4668264 165 mult = 60 * 1000000UL;
74454ce4 166 else if (!strcmp("h", c))
e4668264 167 mult = 60 * 60 * 1000000UL;
74454ce4 168 else if (!strcmp("d", c))
e4668264 169 mult = 24 * 60 * 60 * 1000000UL;
74454ce4
CE
170
171 free(c);
172 return mult;
cb2c86fd
JA
173}
174
a03fb65f
JA
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
7bb59102
JA
188static unsigned long long __get_mult_bytes(const char *p, void *data,
189 int *percent)
cb2c86fd 190{
d6978a32 191 unsigned int kb_base = fio_get_kb_base(data);
a639f0bb 192 unsigned long long ret = 1;
57fc29fa
JA
193 unsigned int i, pow = 0, mult = kb_base;
194 char *c;
a639f0bb 195
57fc29fa
JA
196 if (!p)
197 return 1;
a639f0bb 198
57fc29fa
JA
199 c = strdup(p);
200
a03fb65f 201 for (i = 0; i < strlen(c); i++) {
57fc29fa 202 c[i] = tolower(c[i]);
a03fb65f
JA
203 if (is_separator(c[i])) {
204 c[i] = '\0';
205 break;
206 }
207 }
57fc29fa 208
a04f158d 209 if (!strncmp("pib", c, 3)) {
57fc29fa
JA
210 pow = 5;
211 mult = 1000;
a04f158d 212 } else if (!strncmp("tib", c, 3)) {
57fc29fa
JA
213 pow = 4;
214 mult = 1000;
a04f158d 215 } else if (!strncmp("gib", c, 3)) {
57fc29fa
JA
216 pow = 3;
217 mult = 1000;
a04f158d 218 } else if (!strncmp("mib", c, 3)) {
57fc29fa
JA
219 pow = 2;
220 mult = 1000;
a04f158d 221 } else if (!strncmp("kib", c, 3)) {
57fc29fa
JA
222 pow = 1;
223 mult = 1000;
a04f158d 224 } else if (!strncmp("p", c, 1) || !strncmp("pb", c, 2))
57fc29fa 225 pow = 5;
a04f158d 226 else if (!strncmp("t", c, 1) || !strncmp("tb", c, 2))
57fc29fa 227 pow = 4;
a04f158d 228 else if (!strncmp("g", c, 1) || !strncmp("gb", c, 2))
57fc29fa 229 pow = 3;
a04f158d 230 else if (!strncmp("m", c, 1) || !strncmp("mb", c, 2))
57fc29fa 231 pow = 2;
a04f158d 232 else if (!strncmp("k", c, 1) || !strncmp("kb", c, 2))
57fc29fa 233 pow = 1;
a04f158d 234 else if (!strncmp("%", c, 1)) {
7bb59102 235 *percent = 1;
e721c57f 236 free(c);
7bb59102
JA
237 return ret;
238 }
57fc29fa
JA
239
240 while (pow--)
241 ret *= (unsigned long long) mult;
242
243 free(c);
a639f0bb 244 return ret;
cb2c86fd
JA
245}
246
7bb59102 247static unsigned long long get_mult_bytes(const char *str, int len, void *data,
6925dd35 248 int *percent)
57fc29fa 249{
55ed9636 250 const char *p = str;
ba4ddd69 251 int digit_seen = 0;
57fc29fa 252
1d1c187b 253 if (len < 2)
7bb59102 254 return __get_mult_bytes(str, data, percent);
1d1c187b 255
d0c814ec
SL
256 /*
257 * Go forward until we hit a non-digit, or +/- sign
258 */
55ed9636 259 while ((p - str) <= len) {
ba4ddd69
JA
260 if (!isdigit((int) *p) &&
261 (((*p != '+') && (*p != '-')) || digit_seen))
55ed9636 262 break;
3c703d13 263 digit_seen |= isdigit((int) *p);
55ed9636
JA
264 p++;
265 }
266
7bb59102 267 if (!isalpha((int) *p) && (*p != '%'))
57fc29fa
JA
268 p = NULL;
269
7bb59102 270 return __get_mult_bytes(p, data, percent);
57fc29fa
JA
271}
272
b470a02c 273extern int evaluate_arithmetic_expression(const char *buffer, long long *ival,
88038bc7
SC
274 double *dval, double implied_units,
275 int is_time);
b470a02c 276
83349190
YH
277/*
278 * Convert string into a floating number. Return 1 for success and 0 otherwise.
279 */
88038bc7 280int str_to_float(const char *str, double *val, int is_time)
83349190 281{
b470a02c
SC
282#ifdef CONFIG_ARITHMETIC
283 int rc;
284 long long ival;
285 double dval;
286
287 if (str[0] == '(') {
88038bc7 288 rc = evaluate_arithmetic_expression(str, &ival, &dval, 1.0, is_time);
b470a02c
SC
289 if (!rc) {
290 *val = dval;
291 return 1;
292 }
293 }
294#endif
295 return 1 == sscanf(str, "%lf", val);
83349190
YH
296}
297
cb2c86fd 298/*
e1f36503 299 * convert string into decimal value, noting any size suffix
cb2c86fd 300 */
0de5b26f 301int str_to_decimal(const char *str, long long *val, int kilo, void *data,
88038bc7 302 int is_seconds, int is_time)
cb2c86fd 303{
b347f9da 304 int len, base;
b470a02c
SC
305 int rc = 1;
306#ifdef CONFIG_ARITHMETIC
307 long long ival;
308 double dval;
8e2c678f 309 double implied_units = 1.0;
b470a02c 310#endif
cb2c86fd 311
cb2c86fd 312 len = strlen(str);
f90eff5a
JA
313 if (!len)
314 return 1;
cb2c86fd 315
b470a02c 316#ifdef CONFIG_ARITHMETIC
8e2c678f
SC
317 if (is_seconds)
318 implied_units = 1000000.0;
b470a02c 319 if (str[0] == '(')
88038bc7 320 rc = evaluate_arithmetic_expression(str, &ival, &dval, implied_units, is_time);
18722a18
SC
321 if (str[0] == '(' && !rc) {
322 if (!kilo && is_seconds)
323 *val = ival / 1000000LL;
324 else
325 *val = ival;
326 }
b470a02c 327#endif
b347f9da 328
b470a02c
SC
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 }
cb2c86fd 339
7bb59102
JA
340 if (kilo) {
341 unsigned long long mult;
342 int perc = 0;
343
6925dd35 344 mult = get_mult_bytes(str, len, data, &perc);
7bb59102
JA
345 if (perc)
346 *val = -1ULL - *val;
347 else
348 *val *= mult;
349 } else
0de5b26f 350 *val *= get_mult_time(str, len, is_seconds);
1d31d1bc 351
cb2c86fd
JA
352 return 0;
353}
354
9af4a244 355int check_str_bytes(const char *p, long long *val, void *data)
cb2c86fd 356{
88038bc7 357 return str_to_decimal(p, val, 1, data, 0, 0);
cb2c86fd
JA
358}
359
0de5b26f 360int check_str_time(const char *p, long long *val, int is_seconds)
cb2c86fd 361{
88038bc7 362 return str_to_decimal(p, val, 0, NULL, is_seconds, 1);
cb2c86fd
JA
363}
364
365void strip_blank_front(char **p)
366{
367 char *s = *p;
368
4c8e9640
JA
369 if (!strlen(s))
370 return;
76cd9378 371 while (isspace((int) *s))
cb2c86fd 372 s++;
4d651dad
JA
373
374 *p = s;
cb2c86fd
JA
375}
376
377void strip_blank_end(char *p)
378{
853ee7fc 379 char *start = p, *s;
523bfadb 380
4c8e9640
JA
381 if (!strlen(p))
382 return;
383
523bfadb
JA
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
7f7e6e59 393 s = p + strlen(p);
76cd9378 394 while ((isspace((int) *s) || iscntrl((int) *s)) && (s > start))
cb2c86fd
JA
395 s--;
396
397 *(s + 1) = '\0';
398}
399
d6978a32 400static int check_range_bytes(const char *str, long *val, void *data)
cb2c86fd 401{
57fc29fa 402 long long __val;
cb2c86fd 403
88038bc7 404 if (!str_to_decimal(str, &__val, 1, data, 0, 0)) {
57fc29fa 405 *val = __val;
cb2c86fd
JA
406 return 0;
407 }
408
cb2c86fd
JA
409 return 1;
410}
411
63f29372 412static int check_int(const char *p, int *val)
cb2c86fd 413{
787f7e95
JA
414 if (!strlen(p))
415 return 1;
d78ee463 416 if (strstr(p, "0x") || strstr(p, "0X")) {
a61bdfd8
JA
417 if (sscanf(p, "%x", val) == 1)
418 return 0;
419 } else {
420 if (sscanf(p, "%u", val) == 1)
421 return 0;
422 }
cb2c86fd 423
e1f36503
JA
424 return 1;
425}
cb2c86fd 426
e6f735f0 427static size_t opt_len(const char *str)
808def70
JA
428{
429 char *postfix;
430
431 postfix = strchr(str, ':');
432 if (!postfix)
433 return strlen(str);
434
435 return (int)(postfix - str);
436}
437
119cd939
JA
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
f0fdbcaf
JA
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); \
17abbe89
JA
450 } while (0)
451
f90eff5a 452static int __handle_option(struct fio_option *o, const char *ptr, void *data,
83349190 453 int first, int more, int curr)
cb2c86fd 454{
2fdbefdd 455 int il=0, *ilp;
fd112d34 456 fio_fp64_t *flp;
63f29372
JA
457 long long ull, *ullp;
458 long ul1, ul2;
83349190 459 double uf;
bfe1d592 460 char **cp = NULL;
e42b01eb 461 int ret = 0, is_time = 0;
c44b1ff5
JA
462 const struct value_pair *vp;
463 struct value_pair posval[PARSE_MAX_VP];
464 int i, all_skipped = 1;
cb2c86fd 465
a3d741fa
JA
466 dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name,
467 o->type, ptr);
468
e3cedca7 469 if (!ptr && o->type != FIO_OPT_STR_SET && o->type != FIO_OPT_STR) {
28d7c363 470 log_err("Option %s requires an argument\n", o->name);
08e26e35
JA
471 return 1;
472 }
473
e1f36503 474 switch (o->type) {
5f6ddf1e
JA
475 case FIO_OPT_STR:
476 case FIO_OPT_STR_MULTI: {
e1f36503 477 fio_opt_str_fn *fn = o->cb;
b1ec1da6 478
f085737f
JA
479 posval_sort(o, posval);
480
5f6ddf1e 481 ret = 1;
b1ec1da6 482 for (i = 0; i < PARSE_MAX_VP; i++) {
f085737f 483 vp = &posval[i];
b1ec1da6 484 if (!vp->ival || vp->ival[0] == '\0')
a3073f4a 485 continue;
ae2ddba4 486 all_skipped = 0;
078b46d1
JA
487 if (!ptr)
488 break;
119cd939 489 if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) {
b1ec1da6 490 ret = 0;
7b504edd 491 if (o->off1)
ebadc0ce 492 val_store(ilp, vp->oval, o->off1, vp->orval, data, o);
5f6ddf1e 493 continue;
b1ec1da6
JA
494 }
495 }
cb2c86fd 496
ae2ddba4 497 if (ret && !all_skipped)
b1ec1da6
JA
498 show_option_values(o);
499 else if (fn)
500 ret = fn(data, ptr);
e1f36503
JA
501 break;
502 }
e42b01eb
JA
503 case FIO_OPT_STR_VAL_TIME:
504 is_time = 1;
1a1137d9 505 case FIO_OPT_INT:
e42b01eb
JA
506 case FIO_OPT_STR_VAL: {
507 fio_opt_str_val_fn *fn = o->cb;
6eaf09d6
SL
508 char tmp[128], *p;
509
88038bc7
SC
510 if (!is_time && o->is_time)
511 is_time = o->is_time;
512
209e1037 513 tmp[sizeof(tmp) - 1] = '\0';
6eaf09d6
SL
514 strncpy(tmp, ptr, sizeof(tmp) - 1);
515 p = strchr(tmp, ',');
516 if (p)
517 *p = '\0';
e42b01eb
JA
518
519 if (is_time)
0de5b26f 520 ret = check_str_time(tmp, &ull, o->is_seconds);
e42b01eb 521 else
6eaf09d6 522 ret = check_str_bytes(tmp, &ull, data);
e1f36503 523
ae3fcb5a
JA
524 dprint(FD_PARSE, " ret=%d, out=%llu\n", ret, ull);
525
e1f36503
JA
526 if (ret)
527 break;
0f38bbef
JA
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 }
e1f36503 532
db8e0165 533 if (o->maxval && ull > o->maxval) {
d4fc2f04
JA
534 log_err("max value out of range: %llu"
535 " (%u max)\n", ull, o->maxval);
db8e0165
JA
536 return 1;
537 }
538 if (o->minval && ull < o->minval) {
d4fc2f04
JA
539 log_err("min value out of range: %llu"
540 " (%u min)\n", ull, o->minval);
db8e0165
JA
541 return 1;
542 }
d926d535
JA
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) {
128e4caf
JA
557 log_err("fio: value %llu not allowed:\n", ull);
558 show_option_values(o);
d926d535
JA
559 return 1;
560 }
561 }
e1f36503
JA
562
563 if (fn)
564 ret = fn(data, &ull);
565 else {
e01b22b8 566 if (o->type == FIO_OPT_INT) {
7b504edd
JA
567 if (first)
568 val_store(ilp, ull, o->off1, 0, data, o);
6eaf09d6 569 if (curr == 1) {
7b504edd
JA
570 if (o->off2)
571 val_store(ilp, ull, o->off2, 0, data, o);
02c6aad5 572 }
6eaf09d6 573 if (curr == 2) {
7b504edd
JA
574 if (o->off3)
575 val_store(ilp, ull, o->off3, 0, data, o);
6eaf09d6
SL
576 }
577 if (!more) {
578 if (curr < 1) {
7b504edd
JA
579 if (o->off2)
580 val_store(ilp, ull, o->off2, 0, data, o);
6eaf09d6
SL
581 }
582 if (curr < 2) {
7b504edd
JA
583 if (o->off3)
584 val_store(ilp, ull, o->off3, 0, data, o);
6eaf09d6
SL
585 }
586 }
75e6f36f 587 } else {
7b504edd
JA
588 if (first)
589 val_store(ullp, ull, o->off1, 0, data, o);
02c6aad5 590 if (!more) {
7b504edd
JA
591 if (o->off2)
592 val_store(ullp, ull, o->off2, 0, data, o);
02c6aad5 593 }
75e6f36f 594 }
e1f36503
JA
595 }
596 break;
597 }
83349190 598 case FIO_OPT_FLOAT_LIST: {
eef02441
JA
599 char *cp2;
600
435d195a
VKF
601 if (first) {
602 /*
603 ** Initialize precision to 0 and zero out list
604 ** in case specified list is shorter than default
605 */
3e260a46
JA
606 if (o->off2) {
607 ul2 = 0;
f0fdbcaf 608 ilp = td_var(data, o, o->off2);
3e260a46
JA
609 *ilp = ul2;
610 }
435d195a 611
f0fdbcaf 612 flp = td_var(data, o, o->off1);
435d195a
VKF
613 for(i = 0; i < o->maxlen; i++)
614 flp[i].u.f = 0.0;
615 }
83349190 616 if (curr >= o->maxlen) {
28d7c363 617 log_err("the list exceeding max length %d\n",
83349190
YH
618 o->maxlen);
619 return 1;
620 }
88038bc7 621 if (!str_to_float(ptr, &uf, 0)) { /* this breaks if we ever have lists of times */
28d7c363 622 log_err("not a floating point value: %s\n", ptr);
83349190
YH
623 return 1;
624 }
26650695 625 if (uf > o->maxfp) {
28d7c363 626 log_err("value out of range: %f"
83349190
YH
627 " (range max: %f)\n", uf, o->maxfp);
628 return 1;
629 }
26650695 630 if (uf < o->minfp) {
28d7c363 631 log_err("value out of range: %f"
83349190
YH
632 " (range min: %f)\n", uf, o->minfp);
633 return 1;
634 }
635
f0fdbcaf 636 flp = td_var(data, o, o->off1);
fd112d34 637 flp[curr].u.f = uf;
83349190 638
ae3fcb5a
JA
639 dprint(FD_PARSE, " out=%f\n", uf);
640
435d195a
VKF
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) {
eef02441 648 int len = 0;
435d195a
VKF
649
650 while (*++cp2 != '\0' && *cp2 >= '0' && *cp2 <= '9')
651 len++;
652
3e260a46 653 if (o->off2) {
f0fdbcaf 654 ilp = td_var(data, o, o->off2);
3e260a46
JA
655 if (len > *ilp)
656 *ilp = len;
657 }
435d195a
VKF
658 }
659
83349190
YH
660 break;
661 }
af52b345
JA
662 case FIO_OPT_STR_STORE: {
663 fio_opt_str_fn *fn = o->cb;
664
f75c69a1
JA
665 if (!strlen(ptr))
666 return 1;
667
7b504edd 668 if (o->off1) {
f0fdbcaf 669 cp = td_var(data, o, o->off1);
184b4098 670 *cp = strdup(ptr);
1c964ce5 671 }
02c6aad5 672
184b4098
SL
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];
ab50817f 681 if (!vp->ival || vp->ival[0] == '\0' || !cp)
184b4098
SL
682 continue;
683 all_skipped = 0;
119cd939 684 if (!strncmp(vp->ival, ptr, str_match_len(vp, ptr))) {
184b4098
SL
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 }
af52b345
JA
699 }
700 }
c44b1ff5 701
184b4098
SL
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 }
c44b1ff5 710
e1f36503 711 break;
af52b345 712 }
e1f36503 713 case FIO_OPT_RANGE: {
b765a372 714 char tmp[128];
e1f36503
JA
715 char *p1, *p2;
716
209e1037 717 tmp[sizeof(tmp) - 1] = '\0';
0bbab0e7 718 strncpy(tmp, ptr, sizeof(tmp) - 1);
b765a372 719
31d23f47
DE
720 /* Handle bsrange with separate read,write values: */
721 p1 = strchr(tmp, ',');
722 if (p1)
723 *p1 = '\0';
724
b765a372 725 p1 = strchr(tmp, '-');
e1f36503 726 if (!p1) {
0c9baf91
JA
727 p1 = strchr(tmp, ':');
728 if (!p1) {
729 ret = 1;
730 break;
731 }
e1f36503
JA
732 }
733
734 p2 = p1 + 1;
735 *p1 = '\0';
b765a372 736 p1 = tmp;
e1f36503
JA
737
738 ret = 1;
d6978a32
JA
739 if (!check_range_bytes(p1, &ul1, data) &&
740 !check_range_bytes(p2, &ul2, data)) {
e1f36503 741 ret = 0;
e1f36503 742 if (ul1 > ul2) {
f90eff5a
JA
743 unsigned long foo = ul1;
744
745 ul1 = ul2;
746 ul2 = foo;
747 }
748
749 if (first) {
7b504edd
JA
750 val_store(ilp, ul1, o->off1, 0, data, o);
751 val_store(ilp, ul2, o->off2, 0, data, o);
17abbe89 752 }
6eaf09d6 753 if (curr == 1) {
7b504edd
JA
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);
6eaf09d6
SL
757 }
758 }
759 if (curr == 2) {
7b504edd
JA
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);
6eaf09d6
SL
763 }
764 }
765 if (!more) {
766 if (curr < 1) {
7b504edd
JA
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);
6eaf09d6
SL
770 }
771 }
772 if (curr < 2) {
7b504edd
JA
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);
6eaf09d6
SL
776 }
777 }
e1f36503 778 }
17abbe89
JA
779 }
780
e1f36503
JA
781 break;
782 }
74ba1808
JA
783 case FIO_OPT_BOOL:
784 case FIO_OPT_STR_SET: {
e1f36503
JA
785 fio_opt_int_fn *fn = o->cb;
786
74ba1808
JA
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
ae3fcb5a
JA
794 dprint(FD_PARSE, " ret=%d, out=%d\n", ret, il);
795
e1f36503
JA
796 if (ret)
797 break;
798
db8e0165 799 if (o->maxval && il > (int) o->maxval) {
28d7c363 800 log_err("max value out of range: %d (%d max)\n",
5ec10eaa 801 il, o->maxval);
db8e0165
JA
802 return 1;
803 }
804 if (o->minval && il < o->minval) {
28d7c363 805 log_err("min value out of range: %d (%d min)\n",
5ec10eaa 806 il, o->minval);
db8e0165
JA
807 return 1;
808 }
e1f36503 809
76a43db4
JA
810 if (o->neg)
811 il = !il;
812
e1f36503
JA
813 if (fn)
814 ret = fn(data, &il);
815 else {
7b504edd
JA
816 if (first)
817 val_store(ilp, il, o->off1, 0, data, o);
02c6aad5 818 if (!more) {
7b504edd
JA
819 if (o->off2)
820 val_store(ilp, il, o->off2, 0, data, o);
02c6aad5 821 }
e1f36503
JA
822 }
823 break;
824 }
15ca150e 825 case FIO_OPT_DEPRECATED:
06b0be6e 826 log_info("Option %s is deprecated\n", o->name);
d9472271 827 ret = 1;
15ca150e 828 break;
e1f36503 829 default:
06b0be6e 830 log_err("Bad option type %u\n", o->type);
e1f36503
JA
831 ret = 1;
832 }
cb2c86fd 833
70a4c0c8
JA
834 if (ret)
835 return ret;
836
d447a8c2 837 if (o->verify) {
70a4c0c8 838 ret = o->verify(o, data);
d447a8c2 839 if (ret) {
28d7c363
JA
840 log_err("Correct format for offending option\n");
841 log_err("%20s: %s\n", o->name, o->help);
06b0be6e 842 show_option_help(o, 1);
d447a8c2
JA
843 }
844 }
70a4c0c8 845
e1f36503 846 return ret;
cb2c86fd
JA
847}
848
7c8f1a5c 849static int handle_option(struct fio_option *o, const char *__ptr, void *data)
f90eff5a 850{
b62bdf2c
JA
851 char *o_ptr, *ptr, *ptr2;
852 int ret, done;
f90eff5a 853
7c8f1a5c
JA
854 dprint(FD_PARSE, "handle_option=%s, ptr=%s\n", o->name, __ptr);
855
b62bdf2c 856 o_ptr = ptr = NULL;
7c8f1a5c 857 if (__ptr)
b62bdf2c 858 o_ptr = ptr = strdup(__ptr);
a3d741fa 859
f90eff5a 860 /*
b62bdf2c
JA
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
787f7e95 863 * copy set 1 options to set 2.
f90eff5a 864 */
b62bdf2c
JA
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) &&
83349190
YH
873 (o->type != FIO_OPT_STR) &&
874 (o->type != FIO_OPT_FLOAT_LIST)) {
b62bdf2c
JA
875 ptr2 = strchr(ptr, ',');
876 if (ptr2 && *(ptr2 + 1) == '\0')
877 *ptr2 = '\0';
6eaf09d6 878 if (o->type != FIO_OPT_STR_MULTI && o->type != FIO_OPT_RANGE) {
b62bdf2c
JA
879 if (!ptr2)
880 ptr2 = strchr(ptr, ':');
881 if (!ptr2)
882 ptr2 = strchr(ptr, '-');
883 }
83349190
YH
884 } else if (ptr && o->type == FIO_OPT_FLOAT_LIST) {
885 ptr2 = strchr(ptr, ':');
b62bdf2c 886 }
787f7e95 887
b62bdf2c
JA
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 */
83349190 893 __ret = __handle_option(o, ptr, data, !done, !!ptr2, done);
b62bdf2c
JA
894 if (ret)
895 ret = __ret;
787f7e95 896
b62bdf2c
JA
897 if (!ptr2)
898 break;
f90eff5a 899
b62bdf2c
JA
900 ptr = ptr2 + 1;
901 done++;
902 } while (1);
787f7e95 903
b62bdf2c
JA
904 if (o_ptr)
905 free(o_ptr);
906 return ret;
f90eff5a
JA
907}
908
de890a1e 909static struct fio_option *get_option(char *opt,
07b3232d 910 struct fio_option *options, char **post)
3b8b7135
JA
911{
912 struct fio_option *o;
913 char *ret;
914
915 ret = strchr(opt, '=');
916 if (ret) {
917 *post = ret;
918 *ret = '\0';
de890a1e 919 ret = opt;
3b8b7135 920 (*post)++;
43c129b4 921 strip_blank_end(ret);
07b3232d 922 o = find_option(options, ret);
3b8b7135 923 } else {
07b3232d 924 o = find_option(options, opt);
3b8b7135
JA
925 *post = NULL;
926 }
927
928 return o;
929}
930
931static int opt_cmp(const void *p1, const void *p2)
932{
de890a1e
SL
933 struct fio_option *o;
934 char *s, *foo;
8cdabc1d 935 int prio1, prio2;
3b8b7135 936
8cdabc1d 937 prio1 = prio2 = 0;
3b8b7135 938
de890a1e
SL
939 if (*(char **)p1) {
940 s = strdup(*((char **) p1));
9af4a244 941 o = get_option(s, __fio_options, &foo);
de890a1e
SL
942 if (o)
943 prio1 = o->prio;
944 free(s);
945 }
946 if (*(char **)p2) {
947 s = strdup(*((char **) p2));
9af4a244 948 o = get_option(s, __fio_options, &foo);
de890a1e
SL
949 if (o)
950 prio2 = o->prio;
951 free(s);
952 }
953
8cdabc1d 954 return prio2 - prio1;
3b8b7135
JA
955}
956
957void sort_options(char **opts, struct fio_option *options, int num_opts)
958{
9af4a244 959 __fio_options = options;
3b8b7135 960 qsort(opts, num_opts, sizeof(char *), opt_cmp);
9af4a244 961 __fio_options = NULL;
3b8b7135
JA
962}
963
d8b4f395
JA
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
b4692828 982int parse_cmd_option(const char *opt, const char *val,
d8b4f395
JA
983 struct fio_option *options, void *data,
984 struct flist_head *dump_list)
b4692828
JA
985{
986 struct fio_option *o;
987
07b3232d 988 o = find_option(options, opt);
b4692828 989 if (!o) {
06b0be6e 990 log_err("Bad option <%s>\n", opt);
b4692828
JA
991 return 1;
992 }
993
d8b4f395
JA
994 if (handle_option(o, val, data)) {
995 log_err("fio: failed parsing %s=%s\n", opt, val);
996 return 1;
997 }
b1508cf9 998
d8b4f395
JA
999 add_to_dump_list(o, dump_list, val);
1000 return 0;
b4692828
JA
1001}
1002
de890a1e 1003int parse_option(char *opt, const char *input,
292cc475 1004 struct fio_option *options, struct fio_option **o, void *data,
c2292325 1005 struct flist_head *dump_list)
cb2c86fd 1006{
d0c814ec 1007 char *post;
e1f36503 1008
d0c814ec
SL
1009 if (!opt) {
1010 log_err("fio: failed parsing %s\n", input);
de890a1e 1011 *o = NULL;
38789b58 1012 return 1;
d0c814ec 1013 }
e1f36503 1014
de890a1e
SL
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 }
e1f36503
JA
1023 return 1;
1024 }
1025
292cc475
JA
1026 if (handle_option(*o, post, data)) {
1027 log_err("fio: failed parsing %s\n", input);
1028 return 1;
1029 }
b1508cf9 1030
d8b4f395 1031 add_to_dump_list(*o, dump_list, post);
292cc475 1032 return 0;
e1f36503 1033}
fd28ca49 1034
0e9f7fac
JA
1035/*
1036 * Option match, levenshtein distance. Handy for not quite remembering what
1037 * the option name is.
1038 */
a893c261 1039int string_distance(const char *s1, const char *s2)
0e9f7fac
JA
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];
8a1db9a1 1057 unsigned int pmin;
0e9f7fac
JA
1058
1059 if (s1[i - 1] != s2[j - 1])
1060 sub++;
1061
8a1db9a1
JA
1062 pmin = min(q[j - 1] + 1, sub);
1063 q[j] = min(p[j] + 1, pmin);
0e9f7fac
JA
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
3701636d
JA
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
afdf9352
JA
1089static struct fio_option *find_child(struct fio_option *options,
1090 struct fio_option *o)
1091{
1092 struct fio_option *__o;
1093
fdf28744
JA
1094 for (__o = options + 1; __o->name; __o++)
1095 if (__o->parent && !strcmp(__o->parent, o->name))
afdf9352
JA
1096 return __o;
1097
1098 return NULL;
1099}
1100
323d9113
JA
1101static void __print_option(struct fio_option *o, struct fio_option *org,
1102 int level)
afdf9352
JA
1103{
1104 char name[256], *p;
323d9113 1105 int depth;
afdf9352
JA
1106
1107 if (!o)
1108 return;
ef9aff52
JA
1109 if (!org)
1110 org = o;
5ec10eaa 1111
afdf9352 1112 p = name;
323d9113
JA
1113 depth = level;
1114 while (depth--)
1115 p += sprintf(p, "%s", " ");
afdf9352
JA
1116
1117 sprintf(p, "%s", o->name);
1118
28d7c363 1119 log_info("%-24s: %s\n", name, o->help);
323d9113
JA
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);
afdf9352
JA
1144}
1145
07b3232d 1146int show_cmd_help(struct fio_option *options, const char *name)
0e9f7fac
JA
1147{
1148 struct fio_option *o, *closest;
d091d099 1149 unsigned int best_dist = -1U;
29fc6afe 1150 int found = 0;
320beefe
JA
1151 int show_all = 0;
1152
1153 if (!name || !strcmp(name, "all"))
1154 show_all = 1;
fd28ca49 1155
0e9f7fac
JA
1156 closest = NULL;
1157 best_dist = -1;
4945ba12 1158 for (o = &options[0]; o->name; o++) {
320beefe
JA
1159 int match = 0;
1160
15ca150e
JA
1161 if (o->type == FIO_OPT_DEPRECATED)
1162 continue;
07b3232d
JA
1163 if (!exec_profile && o->prof_name)
1164 continue;
4ac23d27
JA
1165 if (exec_profile && !(o->prof_name && !strcmp(exec_profile, o->prof_name)))
1166 continue;
15ca150e 1167
0e9f7fac 1168 if (name) {
7f9348f8
JA
1169 if (!strcmp(name, o->name) ||
1170 (o->alias && !strcmp(name, o->alias)))
0e9f7fac
JA
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 }
fd28ca49
JA
1182
1183 if (show_all || match) {
29fc6afe 1184 found = 1;
c167dedc 1185 if (match)
28d7c363 1186 log_info("%20s: %s\n", o->name, o->help);
c167dedc 1187 if (show_all) {
afdf9352 1188 if (!o->parent)
323d9113 1189 print_option(o);
4945ba12 1190 continue;
c167dedc 1191 }
fd28ca49
JA
1192 }
1193
70df2f19
JA
1194 if (!match)
1195 continue;
1196
06b0be6e 1197 show_option_help(o, 0);
fd28ca49
JA
1198 }
1199
29fc6afe
JA
1200 if (found)
1201 return 0;
fd28ca49 1202
28d7c363 1203 log_err("No such command: %s", name);
d091d099
JA
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) {
28d7c363
JA
1210 log_info(" - showing closest match\n");
1211 log_info("%20s: %s\n", closest->name, closest->help);
06b0be6e 1212 show_option_help(closest, 0);
0e9f7fac 1213 } else
28d7c363 1214 log_info("\n");
0e9f7fac 1215
29fc6afe 1216 return 1;
fd28ca49 1217}
ee738499 1218
13335ddb
JA
1219/*
1220 * Handle parsing of default parameters.
1221 */
ee738499
JA
1222void fill_default_options(void *data, struct fio_option *options)
1223{
4945ba12 1224 struct fio_option *o;
ee738499 1225
a3d741fa
JA
1226 dprint(FD_PARSE, "filling default options\n");
1227
4945ba12 1228 for (o = &options[0]; o->name; o++)
ee738499
JA
1229 if (o->def)
1230 handle_option(o, o->def, data);
ee738499 1231}
13335ddb 1232
9f988e2e
JA
1233void option_init(struct fio_option *o)
1234{
1235 if (o->type == FIO_OPT_DEPRECATED)
1236 return;
bbcacb72
JA
1237 if (o->name && !o->lname)
1238 log_err("Option %s: missing long option name\n", o->name);
9f988e2e
JA
1239 if (o->type == FIO_OPT_BOOL) {
1240 o->minval = 0;
1241 o->maxval = 1;
1242 }
d4fc2f04
JA
1243 if (o->type == FIO_OPT_INT) {
1244 if (!o->maxval)
1245 o->maxval = UINT_MAX;
1246 }
83349190 1247 if (o->type == FIO_OPT_FLOAT_LIST) {
ab9461ea
BC
1248 o->minfp = DBL_MIN;
1249 o->maxfp = DBL_MAX;
83349190 1250 }
c8931876 1251 if (o->type == FIO_OPT_STR_SET && o->def && !o->no_warn_def) {
06b0be6e 1252 log_err("Option %s: string set option with"
9f988e2e
JA
1253 " default will always be true\n", o->name);
1254 }
7b504edd 1255 if (!o->cb && !o->off1)
06b0be6e 1256 log_err("Option %s: neither cb nor offset given\n", o->name);
22754746 1257 if (!o->category) {
cca5b5bc 1258 log_info("Option %s: no category defined. Setting to misc\n", o->name);
22754746 1259 o->category = FIO_OPT_C_GENERAL;
ffd7821f 1260 o->group = FIO_OPT_G_INVALID;
22754746 1261 }
5f6ddf1e
JA
1262 if (o->type == FIO_OPT_STR || o->type == FIO_OPT_STR_STORE ||
1263 o->type == FIO_OPT_STR_MULTI)
9f988e2e 1264 return;
9f988e2e
JA
1265}
1266
13335ddb
JA
1267/*
1268 * Sanitize the options structure. For now it just sets min/max for bool
5b0a8880 1269 * values and whether both callback and offsets are given.
13335ddb
JA
1270 */
1271void options_init(struct fio_option *options)
1272{
4945ba12 1273 struct fio_option *o;
13335ddb 1274
a3d741fa
JA
1275 dprint(FD_PARSE, "init options\n");
1276
90265353 1277 for (o = &options[0]; o->name; o++) {
9f988e2e 1278 option_init(o);
90265353
JA
1279 if (o->inverse)
1280 o->inv_opt = find_option(options, o->inverse);
1281 }
13335ddb 1282}
7e356b2d
JA
1283
1284void options_free(struct fio_option *options, void *data)
1285{
1286 struct fio_option *o;
1287 char **ptr;
1288
1289 dprint(FD_PARSE, "free options\n");
1290
1291 for (o = &options[0]; o->name; o++) {
de890a1e 1292 if (o->type != FIO_OPT_STR_STORE || !o->off1)
7e356b2d
JA
1293 continue;
1294
f0fdbcaf 1295 ptr = td_var(data, o, o->off1);
7e356b2d
JA
1296 if (*ptr) {
1297 free(*ptr);
1298 *ptr = NULL;
1299 }
1300 }
1301}