parse.c revision 4d651dad4b3ee17a9be223fc1c0489cd4e304f65
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 12#include "parse.h" 13 14static int vp_cmp(const void *p1, const void *p2) 15{ 16 const struct value_pair *vp1 = p1; 17 const struct value_pair *vp2 = p2; 18 19 return strlen(vp2->ival) - strlen(vp1->ival); 20} 21 22static void posval_sort(struct fio_option *o, struct value_pair *vpmap) 23{ 24 const struct value_pair *vp; 25 int entries; 26 27 memset(vpmap, 0, PARSE_MAX_VP * sizeof(struct value_pair)); 28 29 for (entries = 0; entries < PARSE_MAX_VP; entries++) { 30 vp = &o->posval[entries]; 31 if (!vp->ival || vp->ival[0] == '\0') 32 break; 33 34 memcpy(&vpmap[entries], vp, sizeof(*vp)); 35 } 36 37 qsort(vpmap, entries, sizeof(struct value_pair), vp_cmp); 38} 39 40static void show_option_range(struct fio_option *o) 41{ 42 if (!o->minval && !o->maxval) 43 return; 44 45 printf("%20s: min=%d, max=%d\n", "range", o->minval, o->maxval); 46} 47 48static void show_option_values(struct fio_option *o) 49{ 50 int i = 0; 51 52 do { 53 const struct value_pair *vp = &o->posval[i]; 54 55 if (!vp->ival) 56 break; 57 58 printf("%20s: %-10s", i == 0 ? "valid values" : "", vp->ival); 59 if (vp->help) 60 printf(" %s", vp->help); 61 printf("\n"); 62 i++; 63 } while (i < PARSE_MAX_VP); 64 65 if (i) 66 printf("\n"); 67} 68 69static unsigned long get_mult_time(char c) 70{ 71 switch (c) { 72 case 'm': 73 case 'M': 74 return 60; 75 case 'h': 76 case 'H': 77 return 60 * 60; 78 case 'd': 79 case 'D': 80 return 24 * 60 * 60; 81 default: 82 return 1; 83 } 84} 85 86static unsigned long get_mult_bytes(char c) 87{ 88 switch (c) { 89 case 'k': 90 case 'K': 91 return 1024; 92 case 'm': 93 case 'M': 94 return 1024 * 1024; 95 case 'g': 96 case 'G': 97 return 1024 * 1024 * 1024; 98 case 'e': 99 case 'E': 100 return 1024 * 1024 * 1024 * 1024UL; 101 default: 102 return 1; 103 } 104} 105 106/* 107 * convert string into decimal value, noting any size suffix 108 */ 109static int str_to_decimal(const char *str, long long *val, int kilo) 110{ 111 int len; 112 113 len = strlen(str); 114 if (!len) 115 return 1; 116 117 *val = strtoll(str, NULL, 10); 118 if (*val == LONG_MAX && errno == ERANGE) 119 return 1; 120 121 if (kilo) 122 *val *= get_mult_bytes(str[len - 1]); 123 else 124 *val *= get_mult_time(str[len - 1]); 125 126 return 0; 127} 128 129static int check_str_bytes(const char *p, long long *val) 130{ 131 return str_to_decimal(p, val, 1); 132} 133 134static int check_str_time(const char *p, long long *val) 135{ 136 return str_to_decimal(p, val, 0); 137} 138 139void strip_blank_front(char **p) 140{ 141 char *s = *p; 142 143 while (isspace(*s)) 144 s++; 145 146 *p = s; 147} 148 149void strip_blank_end(char *p) 150{ 151 char *s = p + strlen(p) - 1; 152 153 while (isspace(*s) || iscntrl(*s)) 154 s--; 155 156 *(s + 1) = '\0'; 157} 158 159static int check_range_bytes(const char *str, long *val) 160{ 161 char suffix; 162 163 if (!strlen(str)) 164 return 1; 165 166 if (sscanf(str, "%lu%c", val, &suffix) == 2) { 167 *val *= get_mult_bytes(suffix); 168 return 0; 169 } 170 171 if (sscanf(str, "%lu", val) == 1) 172 return 0; 173 174 return 1; 175} 176 177static int check_int(const char *p, int *val) 178{ 179 if (!strlen(p)) 180 return 1; 181 if (sscanf(p, "%u", val) == 1) 182 return 0; 183 184 return 1; 185} 186 187static struct fio_option *find_option(struct fio_option *options, 188 const char *opt) 189{ 190 struct fio_option *o; 191 192 for (o = &options[0]; o->name; o++) { 193 if (!strcmp(o->name, opt)) 194 return o; 195 else if (o->alias && !strcmp(o->alias, opt)) 196 return o; 197 } 198 199 return NULL; 200} 201 202#define val_store(ptr, val, off, data) \ 203 do { \ 204 ptr = td_var((data), (off)); \ 205 *ptr = (val); \ 206 } while (0) 207 208static int __handle_option(struct fio_option *o, const char *ptr, void *data, 209 int first, int more) 210{ 211 int il, *ilp; 212 long long ull, *ullp; 213 long ul1, ul2; 214 char **cp; 215 int ret = 0, is_time = 0; 216 217 if (!ptr && o->type != FIO_OPT_STR_SET) { 218 fprintf(stderr, "Option %s requires an argument\n", o->name); 219 return 1; 220 } 221 222 switch (o->type) { 223 case FIO_OPT_STR: { 224 fio_opt_str_fn *fn = o->cb; 225 const struct value_pair *vp; 226 struct value_pair posval[PARSE_MAX_VP]; 227 int i; 228 229 posval_sort(o, posval); 230 231 for (i = 0; i < PARSE_MAX_VP; i++) { 232 vp = &posval[i]; 233 if (!vp->ival || vp->ival[0] == '\0') 234 break; 235 ret = 1; 236 if (!strncmp(vp->ival, ptr, strlen(vp->ival))) { 237 ret = 0; 238 if (!o->off1) 239 break; 240 val_store(ilp, vp->oval, o->off1, data); 241 break; 242 } 243 } 244 245 if (ret) 246 show_option_values(o); 247 else if (fn) 248 ret = fn(data, ptr); 249 break; 250 } 251 case FIO_OPT_STR_VAL_TIME: 252 is_time = 1; 253 case FIO_OPT_STR_VAL: 254 case FIO_OPT_STR_VAL_INT: { 255 fio_opt_str_val_fn *fn = o->cb; 256 257 if (is_time) 258 ret = check_str_time(ptr, &ull); 259 else 260 ret = check_str_bytes(ptr, &ull); 261 262 if (ret) 263 break; 264 265 if (o->maxval && ull > o->maxval) { 266 fprintf(stderr, "max value out of range: %lld (%d max)\n", ull, o->maxval); 267 return 1; 268 } 269 if (o->minval && ull < o->minval) { 270 fprintf(stderr, "min value out of range: %lld (%d min)\n", ull, o->minval); 271 return 1; 272 } 273 274 if (fn) 275 ret = fn(data, &ull); 276 else { 277 if (o->type == FIO_OPT_STR_VAL_INT) { 278 if (first) 279 val_store(ilp, ull, o->off1, data); 280 if (!more && o->off2) 281 val_store(ilp, ull, o->off2, data); 282 } else { 283 if (first) 284 val_store(ullp, ull, o->off1, data); 285 if (!more && o->off2) 286 val_store(ullp, ull, o->off2, data); 287 } 288 } 289 break; 290 } 291 case FIO_OPT_STR_STORE: { 292 fio_opt_str_fn *fn = o->cb; 293 294 cp = td_var(data, o->off1); 295 *cp = strdup(ptr); 296 if (fn) { 297 ret = fn(data, ptr); 298 if (ret) { 299 free(*cp); 300 *cp = NULL; 301 } 302 } 303 break; 304 } 305 case FIO_OPT_RANGE: { 306 char tmp[128]; 307 char *p1, *p2; 308 309 strncpy(tmp, ptr, sizeof(tmp) - 1); 310 311 p1 = strchr(tmp, '-'); 312 if (!p1) { 313 p1 = strchr(tmp, ':'); 314 if (!p1) { 315 ret = 1; 316 break; 317 } 318 } 319 320 p2 = p1 + 1; 321 *p1 = '\0'; 322 p1 = tmp; 323 324 ret = 1; 325 if (!check_range_bytes(p1, &ul1) && !check_range_bytes(p2, &ul2)) { 326 ret = 0; 327 if (ul1 > ul2) { 328 unsigned long foo = ul1; 329 330 ul1 = ul2; 331 ul2 = foo; 332 } 333 334 if (first) { 335 val_store(ilp, ul1, o->off1, data); 336 val_store(ilp, ul2, o->off2, data); 337 } 338 if (!more && o->off3 && o->off4) { 339 val_store(ilp, ul1, o->off3, data); 340 val_store(ilp, ul2, o->off4, data); 341 } 342 } 343 344 break; 345 } 346 case FIO_OPT_INT: 347 case FIO_OPT_BOOL: { 348 fio_opt_int_fn *fn = o->cb; 349 350 ret = check_int(ptr, &il); 351 if (ret) 352 break; 353 354 if (o->maxval && il > (int) o->maxval) { 355 fprintf(stderr, "max value out of range: %d (%d max)\n", il, o->maxval); 356 return 1; 357 } 358 if (o->minval && il < o->minval) { 359 fprintf(stderr, "min value out of range: %d (%d min)\n", il, o->minval); 360 return 1; 361 } 362 363 if (o->neg) 364 il = !il; 365 366 if (fn) 367 ret = fn(data, &il); 368 else { 369 if (first) 370 val_store(ilp, il, o->off1, data); 371 if (!more && o->off2) 372 val_store(ilp, il, o->off2, data); 373 } 374 break; 375 } 376 case FIO_OPT_STR_SET: { 377 fio_opt_str_set_fn *fn = o->cb; 378 379 if (fn) 380 ret = fn(data); 381 else { 382 if (first) 383 val_store(ilp, 1, o->off1, data); 384 if (!more && o->off2) 385 val_store(ilp, 1, o->off2, data); 386 } 387 break; 388 } 389 default: 390 fprintf(stderr, "Bad option type %u\n", o->type); 391 ret = 1; 392 } 393 394 return ret; 395} 396 397static int handle_option(struct fio_option *o, const char *ptr, void *data) 398{ 399 const char *ptr2 = NULL; 400 int r1, r2; 401 402 /* 403 * See if we have a second set of parameters, hidden after a comma. 404 * Do this before parsing the first round, to check if we should 405 * copy set 1 options to set 2. 406 */ 407 if (ptr && 408 (o->type != FIO_OPT_STR_STORE) && 409 (o->type != FIO_OPT_STR)) { 410 ptr2 = strchr(ptr, ','); 411 if (!ptr2) 412 ptr2 = strchr(ptr, ':'); 413 if (!ptr2) 414 ptr2 = strchr(ptr, '-'); 415 } 416 417 /* 418 * Don't return early if parsing the first option fails - if 419 * we are doing multiple arguments, we can allow the first one 420 * being empty. 421 */ 422 r1 = __handle_option(o, ptr, data, 1, !!ptr2); 423 424 if (!ptr2) 425 return r1; 426 427 ptr2++; 428 r2 = __handle_option(o, ptr2, data, 0, 0); 429 430 return r1 && r2; 431} 432 433int parse_cmd_option(const char *opt, const char *val, 434 struct fio_option *options, void *data) 435{ 436 struct fio_option *o; 437 438 o = find_option(options, opt); 439 if (!o) { 440 fprintf(stderr, "Bad option %s\n", opt); 441 return 1; 442 } 443 444 if (!handle_option(o, val, data)) 445 return 0; 446 447 fprintf(stderr, "fio: failed parsing %s=%s\n", opt, val); 448 return 1; 449} 450 451int parse_option(const char *opt, struct fio_option *options, void *data) 452{ 453 struct fio_option *o; 454 char *pre, *post; 455 char tmp[64]; 456 457 strncpy(tmp, opt, sizeof(tmp) - 1); 458 459 pre = strchr(tmp, '='); 460 if (pre) { 461 post = pre; 462 *pre = '\0'; 463 pre = tmp; 464 post++; 465 o = find_option(options, pre); 466 } else { 467 o = find_option(options, tmp); 468 post = NULL; 469 } 470 471 if (!o) { 472 fprintf(stderr, "Bad option %s\n", tmp); 473 return 1; 474 } 475 476 if (!handle_option(o, post, data)) 477 return 0; 478 479 fprintf(stderr, "fio: failed parsing %s\n", opt); 480 return 1; 481} 482 483/* 484 * Option match, levenshtein distance. Handy for not quite remembering what 485 * the option name is. 486 */ 487static int string_distance(const char *s1, const char *s2) 488{ 489 unsigned int s1_len = strlen(s1); 490 unsigned int s2_len = strlen(s2); 491 unsigned int *p, *q, *r; 492 unsigned int i, j; 493 494 p = malloc(sizeof(unsigned int) * (s2_len + 1)); 495 q = malloc(sizeof(unsigned int) * (s2_len + 1)); 496 497 p[0] = 0; 498 for (i = 1; i <= s2_len; i++) 499 p[i] = p[i - 1] + 1; 500 501 for (i = 1; i <= s1_len; i++) { 502 q[0] = p[0] + 1; 503 for (j = 1; j <= s2_len; j++) { 504 unsigned int sub = p[j - 1]; 505 506 if (s1[i - 1] != s2[j - 1]) 507 sub++; 508 509 q[j] = min(p[j] + 1, min(q[j - 1] + 1, sub)); 510 } 511 r = p; 512 p = q; 513 q = r; 514 } 515 516 i = p[s2_len]; 517 free(p); 518 free(q); 519 return i; 520} 521 522static void show_option_help(struct fio_option *o) 523{ 524 const char *typehelp[] = { 525 "string (opt=bla)", 526 "string with possible k/m/g postfix (opt=4k)", 527 "string with range and postfix (opt=1k-4k)", 528 "string with time postfix (opt=10s)", 529 "string (opt=bla)", 530 "string with dual range (opt=1k-4k,4k-8k)", 531 "integer value (opt=100)", 532 "boolean value (opt=1)", 533 "no argument (opt)", 534 }; 535 536 if (o->alias) 537 printf("%20s: %s\n", "alias", o->alias); 538 539 printf("%20s: %s\n", "type", typehelp[o->type]); 540 printf("%20s: %s\n", "default", o->def ? o->def : "no default"); 541 show_option_range(o); 542 show_option_values(o); 543} 544 545int show_cmd_help(struct fio_option *options, const char *name) 546{ 547 struct fio_option *o, *closest; 548 unsigned int best_dist; 549 int found = 0; 550 int show_all = 0; 551 552 if (!name || !strcmp(name, "all")) 553 show_all = 1; 554 555 closest = NULL; 556 best_dist = -1; 557 for (o = &options[0]; o->name; o++) { 558 int match = 0; 559 560 if (name) { 561 if (!strcmp(name, o->name) || 562 (o->alias && !strcmp(name, o->alias))) 563 match = 1; 564 else { 565 unsigned int dist; 566 567 dist = string_distance(name, o->name); 568 if (dist < best_dist) { 569 best_dist = dist; 570 closest = o; 571 } 572 } 573 } 574 575 if (show_all || match) { 576 found = 1; 577 if (match) 578 printf("%20s: %s\n", o->name, o->help); 579 if (show_all) { 580 printf("%-20s: %s\n", o->name, o->help); 581 continue; 582 } 583 } 584 585 if (!match) 586 continue; 587 588 show_option_help(o); 589 } 590 591 if (found) 592 return 0; 593 594 printf("No such command: %s", name); 595 if (closest) { 596 printf(" - showing closest match\n"); 597 printf("%20s: %s\n", closest->name, closest->help); 598 show_option_help(closest); 599 } else 600 printf("\n"); 601 602 return 1; 603} 604 605/* 606 * Handle parsing of default parameters. 607 */ 608void fill_default_options(void *data, struct fio_option *options) 609{ 610 struct fio_option *o; 611 612 for (o = &options[0]; o->name; o++) 613 if (o->def) 614 handle_option(o, o->def, data); 615} 616 617/* 618 * Sanitize the options structure. For now it just sets min/max for bool 619 * values and whether both callback and offsets are given. 620 */ 621void options_init(struct fio_option *options) 622{ 623 struct fio_option *o; 624 625 for (o = &options[0]; o->name; o++) { 626 if (o->type == FIO_OPT_BOOL) { 627 o->minval = 0; 628 o->maxval = 1; 629 } 630 if (o->type == FIO_OPT_STR_SET && o->def) 631 fprintf(stderr, "Option %s: string set option with default will always be true\n", o->name); 632 if (!o->cb && !o->off1) 633 fprintf(stderr, "Option %s: neither cb nor offset given\n", o->name); 634 if (o->type == FIO_OPT_STR || o->type == FIO_OPT_STR_STORE) 635 continue; 636 if (o->cb && (o->off1 || o->off2 || o->off3 || o->off4)) 637 fprintf(stderr, "Option %s: both cb and offset given\n", o->name); 638 } 639} 640