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