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