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