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