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