parse.c revision a639f0bbd278365a2fa15031afd29a24dc917437
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 13#include "parse.h" 14#include "debug.h" 15 16static struct fio_option *fio_options; 17extern unsigned int fio_kb_base; 18 19static int vp_cmp(const void *p1, const void *p2) 20{ 21 const struct value_pair *vp1 = p1; 22 const struct value_pair *vp2 = p2; 23 24 return strlen(vp2->ival) - strlen(vp1->ival); 25} 26 27static void posval_sort(struct fio_option *o, struct value_pair *vpmap) 28{ 29 const struct value_pair *vp; 30 int entries; 31 32 memset(vpmap, 0, PARSE_MAX_VP * sizeof(struct value_pair)); 33 34 for (entries = 0; entries < PARSE_MAX_VP; entries++) { 35 vp = &o->posval[entries]; 36 if (!vp->ival || vp->ival[0] == '\0') 37 break; 38 39 memcpy(&vpmap[entries], vp, sizeof(*vp)); 40 } 41 42 qsort(vpmap, entries, sizeof(struct value_pair), vp_cmp); 43} 44 45static void show_option_range(struct fio_option *o, FILE *out) 46{ 47 if (!o->minval && !o->maxval) 48 return; 49 50 fprintf(out, "%20s: min=%d", "range", o->minval); 51 if (o->maxval) 52 fprintf(out, ", max=%d", o->maxval); 53 fprintf(out, "\n"); 54} 55 56static void show_option_values(struct fio_option *o) 57{ 58 int i = 0; 59 60 do { 61 const struct value_pair *vp = &o->posval[i]; 62 63 if (!vp->ival) 64 break; 65 66 printf("%20s: %-10s", i == 0 ? "valid values" : "", vp->ival); 67 if (vp->help) 68 printf(" %s", vp->help); 69 printf("\n"); 70 i++; 71 } while (i < PARSE_MAX_VP); 72 73 if (i) 74 printf("\n"); 75} 76 77static void show_option_help(struct fio_option *o, FILE *out) 78{ 79 const char *typehelp[] = { 80 "string (opt=bla)", 81 "string with possible k/m/g postfix (opt=4k)", 82 "string with time postfix (opt=10s)", 83 "string (opt=bla)", 84 "string with dual range (opt=1k-4k,4k-8k)", 85 "integer value (opt=100)", 86 "boolean value (opt=1)", 87 "no argument (opt)", 88 }; 89 90 if (o->alias) 91 fprintf(out, "%20s: %s\n", "alias", o->alias); 92 93 fprintf(out, "%20s: %s\n", "type", typehelp[o->type]); 94 fprintf(out, "%20s: %s\n", "default", o->def ? o->def : "no default"); 95 show_option_range(o, stdout); 96 show_option_values(o); 97} 98 99static unsigned long get_mult_time(char c) 100{ 101 switch (c) { 102 case 'm': 103 case 'M': 104 return 60; 105 case 'h': 106 case 'H': 107 return 60 * 60; 108 case 'd': 109 case 'D': 110 return 24 * 60 * 60; 111 default: 112 return 1; 113 } 114} 115 116static unsigned long long get_mult_bytes(char c) 117{ 118 unsigned long long ret = 1; 119 120 switch (c) { 121 default: 122 break; 123 case 'p': 124 case 'P': 125 ret *= (unsigned long long) fio_kb_base; 126 case 't': 127 case 'T': 128 ret *= (unsigned long long) fio_kb_base; 129 case 'g': 130 case 'G': 131 ret *= (unsigned long long) fio_kb_base; 132 case 'm': 133 case 'M': 134 ret *= (unsigned long long) fio_kb_base; 135 case 'k': 136 case 'K': 137 ret *= (unsigned long long) fio_kb_base; 138 break; 139 } 140 141 return ret; 142} 143 144/* 145 * convert string into decimal value, noting any size suffix 146 */ 147int str_to_decimal(const char *str, long long *val, int kilo) 148{ 149 int len, base; 150 151 len = strlen(str); 152 if (!len) 153 return 1; 154 155 if (strstr(str, "0x") || strstr(str, "0X")) 156 base = 16; 157 else 158 base = 10; 159 160 *val = strtoll(str, NULL, base); 161 if (*val == LONG_MAX && errno == ERANGE) 162 return 1; 163 164 if (kilo) 165 *val *= get_mult_bytes(str[len - 1]); 166 else 167 *val *= get_mult_time(str[len - 1]); 168 169 return 0; 170} 171 172static int check_str_bytes(const char *p, long long *val) 173{ 174 return str_to_decimal(p, val, 1); 175} 176 177static int check_str_time(const char *p, long long *val) 178{ 179 return str_to_decimal(p, val, 0); 180} 181 182void strip_blank_front(char **p) 183{ 184 char *s = *p; 185 186 while (isspace(*s)) 187 s++; 188 189 *p = s; 190} 191 192void strip_blank_end(char *p) 193{ 194 char *start = p, *s; 195 196 s = strchr(p, ';'); 197 if (s) 198 *s = '\0'; 199 s = strchr(p, '#'); 200 if (s) 201 *s = '\0'; 202 if (s) 203 p = s; 204 205 s = p + strlen(p); 206 while ((isspace(*s) || iscntrl(*s)) && (s > start)) 207 s--; 208 209 *(s + 1) = '\0'; 210} 211 212static int check_range_bytes(const char *str, long *val) 213{ 214 char suffix; 215 216 if (!strlen(str)) 217 return 1; 218 219 if (sscanf(str, "%lu%c", val, &suffix) == 2) { 220 *val *= get_mult_bytes(suffix); 221 return 0; 222 } 223 224 if (sscanf(str, "%lu", val) == 1) 225 return 0; 226 227 return 1; 228} 229 230static int check_int(const char *p, int *val) 231{ 232 if (!strlen(p)) 233 return 1; 234 if (strstr(p, "0x") || strstr(p, "0X")) { 235 if (sscanf(p, "%x", val) == 1) 236 return 0; 237 } else { 238 if (sscanf(p, "%u", val) == 1) 239 return 0; 240 } 241 242 return 1; 243} 244 245static struct fio_option *find_option(struct fio_option *options, 246 const char *opt) 247{ 248 struct fio_option *o; 249 250 for (o = &options[0]; o->name; o++) { 251 if (!strcmp(o->name, opt)) 252 return o; 253 else if (o->alias && !strcmp(o->alias, opt)) 254 return o; 255 } 256 257 return NULL; 258} 259 260#define val_store(ptr, val, off, data) \ 261 do { \ 262 ptr = td_var((data), (off)); \ 263 *ptr = (val); \ 264 } while (0) 265 266static int __handle_option(struct fio_option *o, const char *ptr, void *data, 267 int first, int more) 268{ 269 int il, *ilp; 270 long long ull, *ullp; 271 long ul1, ul2; 272 char **cp; 273 int ret = 0, is_time = 0; 274 275 dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name, 276 o->type, ptr); 277 278 if (!ptr && o->type != FIO_OPT_STR_SET && o->type != FIO_OPT_STR) { 279 fprintf(stderr, "Option %s requires an argument\n", o->name); 280 return 1; 281 } 282 283 switch (o->type) { 284 case FIO_OPT_STR: { 285 fio_opt_str_fn *fn = o->cb; 286 const struct value_pair *vp; 287 struct value_pair posval[PARSE_MAX_VP]; 288 int i; 289 290 posval_sort(o, posval); 291 292 for (i = 0; i < PARSE_MAX_VP; i++) { 293 vp = &posval[i]; 294 if (!vp->ival || vp->ival[0] == '\0') 295 break; 296 ret = 1; 297 if (!strncmp(vp->ival, ptr, strlen(vp->ival))) { 298 ret = 0; 299 if (!o->off1) 300 break; 301 val_store(ilp, vp->oval, o->off1, data); 302 break; 303 } 304 } 305 306 if (ret) 307 show_option_values(o); 308 else if (fn) 309 ret = fn(data, ptr); 310 break; 311 } 312 case FIO_OPT_STR_VAL_TIME: 313 is_time = 1; 314 case FIO_OPT_INT: 315 case FIO_OPT_STR_VAL: { 316 fio_opt_str_val_fn *fn = o->cb; 317 318 if (is_time) 319 ret = check_str_time(ptr, &ull); 320 else 321 ret = check_str_bytes(ptr, &ull); 322 323 if (ret) 324 break; 325 326 if (o->maxval && ull > o->maxval) { 327 fprintf(stderr, "max value out of range: %lld" 328 " (%d max)\n", ull, o->maxval); 329 return 1; 330 } 331 if (o->minval && ull < o->minval) { 332 fprintf(stderr, "min value out of range: %lld" 333 " (%d min)\n", ull, o->minval); 334 return 1; 335 } 336 337 if (fn) 338 ret = fn(data, &ull); 339 else { 340 if (o->type == FIO_OPT_INT) { 341 if (first) 342 val_store(ilp, ull, o->off1, data); 343 if (!more && o->off2) 344 val_store(ilp, ull, o->off2, data); 345 } else { 346 if (first) 347 val_store(ullp, ull, o->off1, data); 348 if (!more && o->off2) 349 val_store(ullp, ull, o->off2, data); 350 } 351 } 352 break; 353 } 354 case FIO_OPT_STR_STORE: { 355 fio_opt_str_fn *fn = o->cb; 356 357 cp = td_var(data, o->off1); 358 *cp = strdup(ptr); 359 if (fn) { 360 ret = fn(data, ptr); 361 if (ret) { 362 free(*cp); 363 *cp = NULL; 364 } 365 } 366 break; 367 } 368 case FIO_OPT_RANGE: { 369 char tmp[128]; 370 char *p1, *p2; 371 372 strncpy(tmp, ptr, sizeof(tmp) - 1); 373 374 p1 = strchr(tmp, '-'); 375 if (!p1) { 376 p1 = strchr(tmp, ':'); 377 if (!p1) { 378 ret = 1; 379 break; 380 } 381 } 382 383 p2 = p1 + 1; 384 *p1 = '\0'; 385 p1 = tmp; 386 387 ret = 1; 388 if (!check_range_bytes(p1, &ul1) && 389 !check_range_bytes(p2, &ul2)) { 390 ret = 0; 391 if (ul1 > ul2) { 392 unsigned long foo = ul1; 393 394 ul1 = ul2; 395 ul2 = foo; 396 } 397 398 if (first) { 399 val_store(ilp, ul1, o->off1, data); 400 val_store(ilp, ul2, o->off2, data); 401 } 402 if (o->off3 && o->off4) { 403 val_store(ilp, ul1, o->off3, data); 404 val_store(ilp, ul2, o->off4, data); 405 } 406 } 407 408 break; 409 } 410 case FIO_OPT_BOOL: { 411 fio_opt_int_fn *fn = o->cb; 412 413 ret = check_int(ptr, &il); 414 if (ret) 415 break; 416 417 if (o->maxval && il > (int) o->maxval) { 418 fprintf(stderr, "max value out of range: %d (%d max)\n", 419 il, o->maxval); 420 return 1; 421 } 422 if (o->minval && il < o->minval) { 423 fprintf(stderr, "min value out of range: %d (%d min)\n", 424 il, o->minval); 425 return 1; 426 } 427 428 if (o->neg) 429 il = !il; 430 431 if (fn) 432 ret = fn(data, &il); 433 else { 434 if (first) 435 val_store(ilp, il, o->off1, data); 436 if (!more && o->off2) 437 val_store(ilp, il, o->off2, data); 438 } 439 break; 440 } 441 case FIO_OPT_STR_SET: { 442 fio_opt_str_set_fn *fn = o->cb; 443 444 if (fn) 445 ret = fn(data); 446 else { 447 if (first) 448 val_store(ilp, 1, o->off1, data); 449 if (!more && o->off2) 450 val_store(ilp, 1, o->off2, data); 451 } 452 break; 453 } 454 case FIO_OPT_DEPRECATED: 455 fprintf(stdout, "Option %s is deprecated\n", o->name); 456 break; 457 default: 458 fprintf(stderr, "Bad option type %u\n", o->type); 459 ret = 1; 460 } 461 462 if (ret) 463 return ret; 464 465 if (o->verify) { 466 ret = o->verify(o, data); 467 if (ret) { 468 fprintf(stderr,"Correct format for offending option\n"); 469 fprintf(stderr, "%20s: %s\n", o->name, o->help); 470 show_option_help(o, stderr); 471 } 472 } 473 474 return ret; 475} 476 477static int handle_option(struct fio_option *o, const char *__ptr, void *data) 478{ 479 char *ptr, *ptr2 = NULL; 480 int r1, r2; 481 482 dprint(FD_PARSE, "handle_option=%s, ptr=%s\n", o->name, __ptr); 483 484 ptr = NULL; 485 if (__ptr) 486 ptr = strdup(__ptr); 487 488 /* 489 * See if we have a second set of parameters, hidden after a comma. 490 * Do this before parsing the first round, to check if we should 491 * copy set 1 options to set 2. 492 */ 493 if (ptr && 494 (o->type != FIO_OPT_STR_STORE) && 495 (o->type != FIO_OPT_STR)) { 496 ptr2 = strchr(ptr, ','); 497 if (ptr2 && *(ptr2 + 1) == '\0') 498 *ptr2 = '\0'; 499 if (!ptr2) 500 ptr2 = strchr(ptr, ':'); 501 if (!ptr2) 502 ptr2 = strchr(ptr, '-'); 503 } 504 505 /* 506 * Don't return early if parsing the first option fails - if 507 * we are doing multiple arguments, we can allow the first one 508 * being empty. 509 */ 510 r1 = __handle_option(o, ptr, data, 1, !!ptr2); 511 512 if (!ptr2) { 513 if (ptr) 514 free(ptr); 515 return r1; 516 } 517 518 ptr2++; 519 r2 = __handle_option(o, ptr2, data, 0, 0); 520 521 if (ptr) 522 free(ptr); 523 return r1 && r2; 524} 525 526static struct fio_option *get_option(const char *opt, 527 struct fio_option *options, char **post) 528{ 529 struct fio_option *o; 530 char *ret; 531 532 ret = strchr(opt, '='); 533 if (ret) { 534 *post = ret; 535 *ret = '\0'; 536 ret = (char *) opt; 537 (*post)++; 538 strip_blank_end(ret); 539 o = find_option(options, ret); 540 } else { 541 o = find_option(options, opt); 542 *post = NULL; 543 } 544 545 return o; 546} 547 548static int opt_cmp(const void *p1, const void *p2) 549{ 550 struct fio_option *o1, *o2; 551 char *s1, *s2, *foo; 552 int prio1, prio2; 553 554 s1 = strdup(*((char **) p1)); 555 s2 = strdup(*((char **) p2)); 556 557 o1 = get_option(s1, fio_options, &foo); 558 o2 = get_option(s2, fio_options, &foo); 559 560 prio1 = prio2 = 0; 561 if (o1) 562 prio1 = o1->prio; 563 if (o2) 564 prio2 = o2->prio; 565 566 free(s1); 567 free(s2); 568 return prio2 - prio1; 569} 570 571void sort_options(char **opts, struct fio_option *options, int num_opts) 572{ 573 fio_options = options; 574 qsort(opts, num_opts, sizeof(char *), opt_cmp); 575 fio_options = NULL; 576} 577 578int parse_cmd_option(const char *opt, const char *val, 579 struct fio_option *options, void *data) 580{ 581 struct fio_option *o; 582 583 o = find_option(options, opt); 584 if (!o) { 585 fprintf(stderr, "Bad option <%s>\n", opt); 586 return 1; 587 } 588 589 if (!handle_option(o, val, data)) 590 return 0; 591 592 fprintf(stderr, "fio: failed parsing %s=%s\n", opt, val); 593 return 1; 594} 595 596/* 597 * Return a copy of the input string with substrings of the form ${VARNAME} 598 * substituted with the value of the environment variable VARNAME. The 599 * substitution always occurs, even if VARNAME is empty or the corresponding 600 * environment variable undefined. 601 */ 602static char *option_dup_subs(const char *opt) 603{ 604 char out[OPT_LEN_MAX+1]; 605 char in[OPT_LEN_MAX+1]; 606 char *outptr = out; 607 char *inptr = in; 608 char *ch1, *ch2, *env; 609 ssize_t nchr = OPT_LEN_MAX; 610 size_t envlen; 611 612 in[OPT_LEN_MAX] = '\0'; 613 strncpy(in, opt, OPT_LEN_MAX); 614 615 while (*inptr && nchr > 0) { 616 if (inptr[0] == '$' && inptr[1] == '{') { 617 ch2 = strchr(inptr, '}'); 618 if (ch2 && inptr+1 < ch2) { 619 ch1 = inptr+2; 620 inptr = ch2+1; 621 *ch2 = '\0'; 622 623 env = getenv(ch1); 624 if (env) { 625 envlen = strlen(env); 626 if (envlen <= nchr) { 627 memcpy(outptr, env, envlen); 628 outptr += envlen; 629 nchr -= envlen; 630 } 631 } 632 633 continue; 634 } 635 } 636 637 *outptr++ = *inptr++; 638 --nchr; 639 } 640 641 *outptr = '\0'; 642 return strdup(out); 643} 644 645int parse_option(const char *opt, struct fio_option *options, void *data) 646{ 647 struct fio_option *o; 648 char *post, *tmp; 649 650 tmp = option_dup_subs(opt); 651 652 o = get_option(tmp, options, &post); 653 if (!o) { 654 fprintf(stderr, "Bad option <%s>\n", tmp); 655 free(tmp); 656 return 1; 657 } 658 659 if (!handle_option(o, post, data)) { 660 free(tmp); 661 return 0; 662 } 663 664 fprintf(stderr, "fio: failed parsing %s\n", opt); 665 free(tmp); 666 return 1; 667} 668 669/* 670 * Option match, levenshtein distance. Handy for not quite remembering what 671 * the option name is. 672 */ 673static int string_distance(const char *s1, const char *s2) 674{ 675 unsigned int s1_len = strlen(s1); 676 unsigned int s2_len = strlen(s2); 677 unsigned int *p, *q, *r; 678 unsigned int i, j; 679 680 p = malloc(sizeof(unsigned int) * (s2_len + 1)); 681 q = malloc(sizeof(unsigned int) * (s2_len + 1)); 682 683 p[0] = 0; 684 for (i = 1; i <= s2_len; i++) 685 p[i] = p[i - 1] + 1; 686 687 for (i = 1; i <= s1_len; i++) { 688 q[0] = p[0] + 1; 689 for (j = 1; j <= s2_len; j++) { 690 unsigned int sub = p[j - 1]; 691 692 if (s1[i - 1] != s2[j - 1]) 693 sub++; 694 695 q[j] = min(p[j] + 1, min(q[j - 1] + 1, sub)); 696 } 697 r = p; 698 p = q; 699 q = r; 700 } 701 702 i = p[s2_len]; 703 free(p); 704 free(q); 705 return i; 706} 707 708static struct fio_option *find_child(struct fio_option *options, 709 struct fio_option *o) 710{ 711 struct fio_option *__o; 712 713 for (__o = options + 1; __o->name; __o++) 714 if (__o->parent && !strcmp(__o->parent, o->name)) 715 return __o; 716 717 return NULL; 718} 719 720static void __print_option(struct fio_option *o, struct fio_option *org, 721 int level) 722{ 723 char name[256], *p; 724 int depth; 725 726 if (!o) 727 return; 728 if (!org) 729 org = o; 730 731 p = name; 732 depth = level; 733 while (depth--) 734 p += sprintf(p, "%s", " "); 735 736 sprintf(p, "%s", o->name); 737 738 printf("%-24s: %s\n", name, o->help); 739} 740 741static void print_option(struct fio_option *o) 742{ 743 struct fio_option *parent; 744 struct fio_option *__o; 745 unsigned int printed; 746 unsigned int level; 747 748 __print_option(o, NULL, 0); 749 parent = o; 750 level = 0; 751 do { 752 level++; 753 printed = 0; 754 755 while ((__o = find_child(o, parent)) != NULL) { 756 __print_option(__o, o, level); 757 o = __o; 758 printed++; 759 } 760 761 parent = o; 762 } while (printed); 763} 764 765int show_cmd_help(struct fio_option *options, const char *name) 766{ 767 struct fio_option *o, *closest; 768 unsigned int best_dist; 769 int found = 0; 770 int show_all = 0; 771 772 if (!name || !strcmp(name, "all")) 773 show_all = 1; 774 775 closest = NULL; 776 best_dist = -1; 777 for (o = &options[0]; o->name; o++) { 778 int match = 0; 779 780 if (o->type == FIO_OPT_DEPRECATED) 781 continue; 782 783 if (name) { 784 if (!strcmp(name, o->name) || 785 (o->alias && !strcmp(name, o->alias))) 786 match = 1; 787 else { 788 unsigned int dist; 789 790 dist = string_distance(name, o->name); 791 if (dist < best_dist) { 792 best_dist = dist; 793 closest = o; 794 } 795 } 796 } 797 798 if (show_all || match) { 799 found = 1; 800 if (match) 801 printf("%24s: %s\n", o->name, o->help); 802 if (show_all) { 803 if (!o->parent) 804 print_option(o); 805 continue; 806 } 807 } 808 809 if (!match) 810 continue; 811 812 show_option_help(o, stdout); 813 } 814 815 if (found) 816 return 0; 817 818 printf("No such command: %s", name); 819 if (closest) { 820 printf(" - showing closest match\n"); 821 printf("%20s: %s\n", closest->name, closest->help); 822 show_option_help(closest, stdout); 823 } else 824 printf("\n"); 825 826 return 1; 827} 828 829/* 830 * Handle parsing of default parameters. 831 */ 832void fill_default_options(void *data, struct fio_option *options) 833{ 834 struct fio_option *o; 835 836 dprint(FD_PARSE, "filling default options\n"); 837 838 for (o = &options[0]; o->name; o++) 839 if (o->def) 840 handle_option(o, o->def, data); 841} 842 843/* 844 * Sanitize the options structure. For now it just sets min/max for bool 845 * values and whether both callback and offsets are given. 846 */ 847void options_init(struct fio_option *options) 848{ 849 struct fio_option *o; 850 851 dprint(FD_PARSE, "init options\n"); 852 853 for (o = &options[0]; o->name; o++) { 854 if (o->type == FIO_OPT_DEPRECATED) 855 continue; 856 if (o->type == FIO_OPT_BOOL) { 857 o->minval = 0; 858 o->maxval = 1; 859 } 860 if (o->type == FIO_OPT_STR_SET && o->def) { 861 fprintf(stderr, "Option %s: string set option with" 862 " default will always be true\n", 863 o->name); 864 } 865 if (!o->cb && !o->off1) { 866 fprintf(stderr, "Option %s: neither cb nor offset" 867 " given\n", o->name); 868 } 869 if (o->type == FIO_OPT_STR || o->type == FIO_OPT_STR_STORE) 870 continue; 871 if (o->cb && (o->off1 || o->off2 || o->off3 || o->off4)) { 872 fprintf(stderr, "Option %s: both cb and offset given\n", 873 o->name); 874 } 875 } 876} 877