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