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