parse.c revision ec1aee01a92f2e390d7ca14d26eebf6453780c53
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
12#include "parse.h"
13
14static void show_option_range(struct fio_option *o)
15{
16	if (!o->minval && !o->maxval)
17		return;
18
19	printf("%20s: min=%d, max=%d\n", "range", o->minval, o->maxval);
20}
21
22static void show_option_values(struct fio_option *o)
23{
24	const char *msg;
25	int i = 0;
26
27	do {
28		msg = o->posval[i].ival;
29		if (!msg)
30			break;
31
32		if (!i)
33			printf("%20s: ", "valid values");
34
35		printf("%s,", msg);
36		i++;
37	} while (i < PARSE_MAX_VP);
38
39	if (i)
40		printf("\n");
41}
42
43static unsigned long get_mult_time(char c)
44{
45	switch (c) {
46		case 'm':
47		case 'M':
48			return 60;
49		case 'h':
50		case 'H':
51			return 60 * 60;
52		case 'd':
53		case 'D':
54			return 24 * 60 * 60;
55		default:
56			return 1;
57	}
58}
59
60static unsigned long get_mult_bytes(char c)
61{
62	switch (c) {
63		case 'k':
64		case 'K':
65			return 1024;
66		case 'm':
67		case 'M':
68			return 1024 * 1024;
69		case 'g':
70		case 'G':
71			return 1024 * 1024 * 1024;
72		case 'e':
73		case 'E':
74			return 1024 * 1024 * 1024 * 1024UL;
75		default:
76			return 1;
77	}
78}
79
80/*
81 * convert string into decimal value, noting any size suffix
82 */
83static int str_to_decimal(const char *str, long long *val, int kilo)
84{
85	int len;
86
87	len = strlen(str);
88	if (!len)
89		return 1;
90
91	*val = strtoll(str, NULL, 10);
92	if (*val == LONG_MAX && errno == ERANGE)
93		return 1;
94
95	if (kilo)
96		*val *= get_mult_bytes(str[len - 1]);
97	else
98		*val *= get_mult_time(str[len - 1]);
99
100	return 0;
101}
102
103static int check_str_bytes(const char *p, long long *val)
104{
105	return str_to_decimal(p, val, 1);
106}
107
108static int check_str_time(const char *p, long long *val)
109{
110	return str_to_decimal(p, val, 0);
111}
112
113void strip_blank_front(char **p)
114{
115	char *s = *p;
116
117	while (isspace(*s))
118		s++;
119}
120
121void strip_blank_end(char *p)
122{
123	char *s = p + strlen(p) - 1;
124
125	while (isspace(*s) || iscntrl(*s))
126		s--;
127
128	*(s + 1) = '\0';
129}
130
131static int check_range_bytes(const char *str, long *val)
132{
133	char suffix;
134
135	if (!strlen(str))
136		return 1;
137
138	if (sscanf(str, "%lu%c", val, &suffix) == 2) {
139		*val *= get_mult_bytes(suffix);
140		return 0;
141	}
142
143	if (sscanf(str, "%lu", val) == 1)
144		return 0;
145
146	return 1;
147}
148
149static int check_int(const char *p, int *val)
150{
151	if (!strlen(p))
152		return 1;
153	if (sscanf(p, "%u", val) == 1)
154		return 0;
155
156	return 1;
157}
158
159static struct fio_option *find_option(struct fio_option *options,
160				      const char *opt)
161{
162	struct fio_option *o;
163
164	for (o = &options[0]; o->name; o++) {
165		if (!strcmp(o->name, opt))
166			return o;
167		else if (o->alias && !strcmp(o->alias, opt))
168			return o;
169	}
170
171	return NULL;
172}
173
174#define val_store(ptr, val, off, data)			\
175	do {						\
176		ptr = td_var((data), (off));		\
177		*ptr = (val);				\
178	} while (0)
179
180static int __handle_option(struct fio_option *o, const char *ptr, void *data,
181			   int first, int more)
182{
183	int il, *ilp;
184	long long ull, *ullp;
185	long ul1, ul2;
186	char **cp;
187	int ret = 0, is_time = 0;
188
189	if (!ptr && o->type != FIO_OPT_STR_SET) {
190		fprintf(stderr, "Option %s requires an argument\n", o->name);
191		return 1;
192	}
193
194	switch (o->type) {
195	case FIO_OPT_STR: {
196		fio_opt_str_fn *fn = o->cb;
197		const struct value_pair *vp;
198		int i;
199
200		ret = 1;
201		for (i = 0; i < PARSE_MAX_VP; i++) {
202			vp = &o->posval[i];
203			if (!vp->ival || vp->ival[0] == '\0')
204				break;
205			if (!strncmp(vp->ival, ptr, strlen(vp->ival))) {
206				ret = 0;
207				if (!o->off1)
208					break;
209				val_store(ilp, vp->oval, o->off1, data);
210				break;
211			}
212		}
213
214		if (ret)
215			show_option_values(o);
216		else if (fn)
217			ret = fn(data, ptr);
218		break;
219	}
220	case FIO_OPT_STR_VAL_TIME:
221		is_time = 1;
222	case FIO_OPT_STR_VAL:
223	case FIO_OPT_STR_VAL_INT: {
224		fio_opt_str_val_fn *fn = o->cb;
225
226		if (is_time)
227			ret = check_str_time(ptr, &ull);
228		else
229			ret = check_str_bytes(ptr, &ull);
230
231		if (ret)
232			break;
233
234		if (o->maxval && ull > o->maxval) {
235			fprintf(stderr, "max value out of range: %lld (%d max)\n", ull, o->maxval);
236			return 1;
237		}
238		if (o->minval && ull < o->minval) {
239			fprintf(stderr, "min value out of range: %lld (%d min)\n", ull, o->minval);
240			return 1;
241		}
242
243		if (fn)
244			ret = fn(data, &ull);
245		else {
246			if (o->type == FIO_OPT_STR_VAL_INT) {
247				if (first)
248					val_store(ilp, ull, o->off1, data);
249				if (!more && o->off2)
250					val_store(ilp, ull, o->off2, data);
251			} else {
252				if (first)
253					val_store(ullp, ull, o->off1, data);
254				if (!more && o->off2)
255					val_store(ullp, ull, o->off2, data);
256			}
257		}
258		break;
259	}
260	case FIO_OPT_STR_STORE:
261		cp = td_var(data, o->off1);
262		*cp = strdup(ptr);
263		break;
264	case FIO_OPT_RANGE: {
265		char tmp[128];
266		char *p1, *p2;
267
268		strncpy(tmp, ptr, sizeof(tmp) - 1);
269
270		p1 = strchr(tmp, '-');
271		if (!p1) {
272			p1 = strchr(tmp, ':');
273			if (!p1) {
274				ret = 1;
275				break;
276			}
277		}
278
279		p2 = p1 + 1;
280		*p1 = '\0';
281		p1 = tmp;
282
283		ret = 1;
284		if (!check_range_bytes(p1, &ul1) && !check_range_bytes(p2, &ul2)) {
285			ret = 0;
286			if (ul1 > ul2) {
287				unsigned long foo = ul1;
288
289				ul1 = ul2;
290				ul2 = foo;
291			}
292
293			if (first) {
294				val_store(ilp, ul1, o->off1, data);
295				val_store(ilp, ul2, o->off2, data);
296			}
297			if (!more && o->off3 && o->off4) {
298				val_store(ilp, ul1, o->off3, data);
299				val_store(ilp, ul2, o->off4, data);
300			}
301		}
302
303		break;
304	}
305	case FIO_OPT_INT:
306	case FIO_OPT_BOOL: {
307		fio_opt_int_fn *fn = o->cb;
308
309		ret = check_int(ptr, &il);
310		if (ret)
311			break;
312
313		if (o->maxval && il > (int) o->maxval) {
314			fprintf(stderr, "max value out of range: %d (%d max)\n", il, o->maxval);
315			return 1;
316		}
317		if (o->minval && il < o->minval) {
318			fprintf(stderr, "min value out of range: %d (%d min)\n", il, o->minval);
319			return 1;
320		}
321
322		if (o->neg)
323			il = !il;
324
325		if (fn)
326			ret = fn(data, &il);
327		else {
328			if (first)
329				val_store(ilp, il, o->off1, data);
330			if (!more && o->off2)
331				val_store(ilp, il, o->off2, data);
332		}
333		break;
334	}
335	case FIO_OPT_STR_SET: {
336		fio_opt_str_set_fn *fn = o->cb;
337
338		if (fn)
339			ret = fn(data);
340		else {
341			if (first)
342				val_store(ilp, 1, o->off1, data);
343			if (!more && o->off2)
344				val_store(ilp, 1, o->off2, data);
345		}
346		break;
347	}
348	default:
349		fprintf(stderr, "Bad option type %u\n", o->type);
350		ret = 1;
351	}
352
353	return ret;
354}
355
356static int handle_option(struct fio_option *o, const char *ptr, void *data)
357{
358	const char *ptr2 = NULL;
359	int r1, r2;
360
361	/*
362	 * See if we have a second set of parameters, hidden after a comma.
363	 * Do this before parsing the first round, to check if we should
364	 * copy set 1 options to set 2.
365	 */
366	if (ptr && (o->type != FIO_OPT_STR_STORE)) {
367		ptr2 = strchr(ptr, ',');
368		if (!ptr2)
369			ptr2 = strchr(ptr, ':');
370	}
371
372	/*
373	 * Don't return early if parsing the first option fails - if
374	 * we are doing multiple arguments, we can allow the first one
375	 * being empty.
376	 */
377	r1 = __handle_option(o, ptr, data, 1, !!ptr2);
378
379	if (!ptr2)
380		return r1;
381
382	ptr2++;
383	r2 = __handle_option(o, ptr2, data, 0, 0);
384
385	return r1 && r2;
386}
387
388int parse_cmd_option(const char *opt, const char *val,
389		     struct fio_option *options, void *data)
390{
391	struct fio_option *o;
392
393	o = find_option(options, opt);
394	if (!o) {
395		fprintf(stderr, "Bad option %s\n", opt);
396		return 1;
397	}
398
399	if (!handle_option(o, val, data))
400		return 0;
401
402	fprintf(stderr, "fio: failed parsing %s=%s\n", opt, val);
403	return 1;
404}
405
406int parse_option(const char *opt, struct fio_option *options, void *data)
407{
408	struct fio_option *o;
409	char *pre, *post;
410	char tmp[64];
411
412	strncpy(tmp, opt, sizeof(tmp) - 1);
413
414	pre = strchr(tmp, '=');
415	if (pre) {
416		post = pre;
417		*pre = '\0';
418		pre = tmp;
419		post++;
420		o = find_option(options, pre);
421	} else {
422		o = find_option(options, tmp);
423		post = NULL;
424	}
425
426	if (!o) {
427		fprintf(stderr, "Bad option %s\n", tmp);
428		return 1;
429	}
430
431	if (!handle_option(o, post, data))
432		return 0;
433
434	fprintf(stderr, "fio: failed parsing %s\n", opt);
435	return 1;
436}
437
438int show_cmd_help(struct fio_option *options, const char *name)
439{
440	int show_all = !strcmp(name, "all");
441	const char *typehelp[] = {
442		"string (opt=bla)",
443		"string with possible k/m/g postfix (opt=4k)",
444		"string with range and postfix (opt=1k-4k)",
445		"string with time postfix (opt=10s)",
446		"string (opt=bla)",
447		"string with dual range (opt=1k-4k,4k-8k)",
448		"integer value (opt=100)",
449		"boolean value (opt=1)",
450		"no argument (opt)",
451	};
452	struct fio_option *o;
453	int found = 0;
454
455	for (o = &options[0]; o->name; o++) {
456		int match = !strcmp(name, o->name);
457
458		if (show_all || match) {
459			found = 1;
460			printf("%20s: %s\n", o->name, o->help);
461			if (show_all)
462				continue;
463		}
464
465		if (!match)
466			continue;
467
468		printf("%20s: %s\n", "type", typehelp[o->type]);
469		printf("%20s: %s\n", "default", o->def ? o->def : "no default");
470		show_option_range(o);
471		show_option_values(o);
472	}
473
474	if (found)
475		return 0;
476
477	printf("No such command: %s\n", name);
478	return 1;
479}
480
481/*
482 * Handle parsing of default parameters.
483 */
484void fill_default_options(void *data, struct fio_option *options)
485{
486	struct fio_option *o;
487
488	for (o = &options[0]; o->name; o++)
489		if (o->def)
490			handle_option(o, o->def, data);
491}
492
493/*
494 * Sanitize the options structure. For now it just sets min/max for bool
495 * values and whether both callback and offsets are given.
496 */
497void options_init(struct fio_option *options)
498{
499	struct fio_option *o;
500
501	for (o = &options[0]; o->name; o++) {
502		if (o->type == FIO_OPT_BOOL) {
503			o->minval = 0;
504			o->maxval = 1;
505		}
506		if (!o->cb && !o->off1)
507			fprintf(stderr, "Option %s: neither cb nor offset given\n", o->name);
508		if (o->type == FIO_OPT_STR)
509			continue;
510		if (o->cb && (o->off1 || o->off2 || o->off3 || o->off4))
511			fprintf(stderr, "Option %s: both cb and offset given\n", o->name);
512	}
513}
514