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