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