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