parse.c revision 75e6f36fae06978f29296fce76a7f00ca0df7b56
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 unsigned long get_mult_time(char c)
15{
16	switch (c) {
17		case 'm':
18		case 'M':
19			return 60;
20		case 'h':
21		case 'H':
22			return 60 * 60;
23		case 'd':
24		case 'D':
25			return 24 * 60 * 60;
26		default:
27			return 1;
28	}
29}
30
31static unsigned long get_mult_bytes(char c)
32{
33	switch (c) {
34		case 'k':
35		case 'K':
36			return 1024;
37		case 'm':
38		case 'M':
39			return 1024 * 1024;
40		case 'g':
41		case 'G':
42			return 1024 * 1024 * 1024;
43		default:
44			return 1;
45	}
46}
47
48/*
49 * convert string into decimal value, noting any size suffix
50 */
51static int str_to_decimal(const char *str, unsigned long long *val, int kilo)
52{
53	int len;
54
55	len = strlen(str);
56
57	*val = strtoul(str, NULL, 10);
58	if (*val == ULONG_MAX && errno == ERANGE)
59		return 1;
60
61	if (kilo)
62		*val *= get_mult_bytes(str[len - 1]);
63	else
64		*val *= get_mult_time(str[len - 1]);
65	return 0;
66}
67
68static int check_str_bytes(const char *p, unsigned long long *val)
69{
70	return str_to_decimal(p, val, 1);
71}
72
73static int check_str_time(const char *p, unsigned long long *val)
74{
75	return str_to_decimal(p, val, 0);
76}
77
78void strip_blank_front(char **p)
79{
80	char *s = *p;
81
82	while (isspace(*s))
83		s++;
84}
85
86void strip_blank_end(char *p)
87{
88	char *s = p + strlen(p) - 1;
89
90	while (isspace(*s) || iscntrl(*s))
91		s--;
92
93	*(s + 1) = '\0';
94}
95
96static int check_range_bytes(const char *str, unsigned long *val)
97{
98	char suffix;
99
100	if (sscanf(str, "%lu%c", val, &suffix) == 2) {
101		*val *= get_mult_bytes(suffix);
102		return 0;
103	}
104
105	if (sscanf(str, "%lu", val) == 1)
106		return 0;
107
108	return 1;
109}
110
111static int check_int(const char *p, unsigned int *val)
112{
113	if (sscanf(p, "%u", val) == 1)
114		return 0;
115
116	return 1;
117}
118
119static struct fio_option *find_option(struct fio_option *options,
120				      const char *opt)
121{
122	struct fio_option *o = &options[0];
123
124	while (o->name) {
125		if (!strcmp(o->name, opt))
126			return o;
127
128		o++;
129	}
130
131	return NULL;
132}
133
134static int handle_option(struct fio_option *o, const char *ptr, void *data)
135{
136	unsigned int il, *ilp1, *ilp2;
137	unsigned long long ull, *ullp;
138	unsigned long ul1, ul2;
139	char **cp;
140	int ret = 0, is_time = 0;
141
142	switch (o->type) {
143	case FIO_OPT_STR: {
144		fio_opt_str_fn *fn = o->cb;
145
146		ret = fn(data, ptr);
147		break;
148	}
149	case FIO_OPT_STR_VAL_TIME:
150		is_time = 1;
151	case FIO_OPT_STR_VAL:
152	case FIO_OPT_STR_VAL_INT: {
153		fio_opt_str_val_fn *fn = o->cb;
154
155		if (is_time)
156			ret = check_str_time(ptr, &ull);
157		else
158			ret = check_str_bytes(ptr, &ull);
159
160		if (ret)
161			break;
162
163		if (o->max_val && ull > o->max_val)
164			ull = o->max_val;
165
166		if (fn)
167			ret = fn(data, &ull);
168		else {
169			if (o->type == FIO_OPT_STR_VAL_INT) {
170				ilp1 = td_var(data, o->off1);
171				*ilp1 = ull;
172			} else {
173				ullp = td_var(data, o->off1);
174				*ullp = ull;
175			}
176		}
177		break;
178	}
179	case FIO_OPT_STR_STORE:
180		cp = td_var(data, o->off1);
181		*cp = strdup(ptr);
182		break;
183	case FIO_OPT_RANGE: {
184		char tmp[128];
185		char *p1, *p2;
186
187		strncpy(tmp, ptr, sizeof(tmp) - 1);
188
189		p1 = strchr(tmp, '-');
190		if (!p1) {
191			ret = 1;
192			break;
193		}
194
195		p2 = p1 + 1;
196		*p1 = '\0';
197		p1 = tmp;
198
199		ret = 1;
200		if (!check_range_bytes(p1, &ul1) && !check_range_bytes(p2, &ul2)) {
201			ret = 0;
202			ilp1 = td_var(data, o->off1);
203			ilp2 = td_var(data, o->off2);
204			if (ul1 > ul2) {
205				*ilp1 = ul2;
206				*ilp2 = ul1;
207			} else {
208				*ilp2 = ul2;
209				*ilp1 = ul1;
210			}
211		}
212
213		break;
214	}
215	case FIO_OPT_INT: {
216		fio_opt_int_fn *fn = o->cb;
217
218		ret = check_int(ptr, &il);
219		if (ret)
220			break;
221
222		if (o->max_val && il > o->max_val)
223			il = o->max_val;
224
225		if (fn)
226			ret = fn(data, &il);
227		else {
228			ilp1 = td_var(data, o->off1);
229			*ilp1 = il;
230		}
231		break;
232	}
233	case FIO_OPT_STR_SET: {
234		fio_opt_str_set_fn *fn = o->cb;
235
236		if (fn)
237			ret = fn(data);
238		else {
239			ilp1 = td_var(data, o->off1);
240			*ilp1 = 1;
241		}
242		break;
243	}
244	default:
245		fprintf(stderr, "Bad option type %d\n", o->type);
246		ret = 1;
247	}
248
249	return ret;
250}
251
252int parse_cmd_option(const char *opt, const char *val,
253		     struct fio_option *options, void *data)
254{
255	struct fio_option *o;
256
257	o = find_option(options, opt);
258	if (!o) {
259		fprintf(stderr, "Bad option %s\n", opt);
260		return 1;
261	}
262
263	if (!handle_option(o, val, data))
264		return 0;
265
266	fprintf(stderr, "fio: failed parsing %s=%s\n", opt, val);
267	return 1;
268}
269
270int parse_option(const char *opt, struct fio_option *options, void *data)
271{
272	struct fio_option *o;
273	char *pre, *post;
274	char tmp[64];
275
276	strncpy(tmp, opt, sizeof(tmp) - 1);
277
278	pre = strchr(tmp, '=');
279	if (pre) {
280		post = pre;
281		*pre = '\0';
282		pre = tmp;
283		post++;
284		o = find_option(options, pre);
285	} else {
286		o = find_option(options, tmp);
287		post = NULL;
288	}
289
290	if (!o) {
291		fprintf(stderr, "Bad option %s\n", tmp);
292		return 1;
293	}
294
295	if (!handle_option(o, post, data))
296		return 0;
297
298	fprintf(stderr, "fio: failed parsing %s\n", opt);
299	return 1;
300}
301