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
25static struct fio_option *__fio_options;
26
27static 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
35static 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
53static 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
75static 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
95static 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
129static 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
173static 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
186static 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
245static 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
271extern 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 */
278int 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 */
299int 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
353int 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
358int 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
363void 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
375void 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
398static 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
410static 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
425static 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
436static 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
450static 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
841static 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
901static 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
923static 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
949void 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
956int 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
974int 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 */
1022int 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
1059static 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
1071static 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
1092static 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
1116int 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 */
1192void 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
1203void 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 */
1239void 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
1252void 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