X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=parse.c;h=d44d13082c91dd8951cbe0be7edf2c51dd73d7e0;hb=fc2a6f2266bc616f6444fb580053f9ea26e6e563;hp=0636c6b3758ab2bf96c3a0a52a0efa94827fc184;hpb=c1f75438a5888d96b3aa4f6a0cac50c4d4047f14;p=fio.git diff --git a/parse.c b/parse.c index 0636c6b3..d44d1308 100644 --- a/parse.c +++ b/parse.c @@ -14,6 +14,7 @@ #include "debug.h" static struct fio_option *fio_options; +extern unsigned int fio_get_kb_base(void *); static int vp_cmp(const void *p1, const void *p2) { @@ -41,12 +42,15 @@ static void posval_sort(struct fio_option *o, struct value_pair *vpmap) qsort(vpmap, entries, sizeof(struct value_pair), vp_cmp); } -static void show_option_range(struct fio_option *o) +static void show_option_range(struct fio_option *o, FILE *out) { if (!o->minval && !o->maxval) return; - printf("%20s: min=%d, max=%d\n", "range", o->minval, o->maxval); + fprintf(out, "%20s: min=%d", "range", o->minval); + if (o->maxval) + fprintf(out, ", max=%d", o->maxval); + fprintf(out, "\n"); } static void show_option_values(struct fio_option *o) @@ -70,6 +74,28 @@ static void show_option_values(struct fio_option *o) printf("\n"); } +static void show_option_help(struct fio_option *o, FILE *out) +{ + const char *typehelp[] = { + "string (opt=bla)", + "string with possible k/m/g postfix (opt=4k)", + "string with time postfix (opt=10s)", + "string (opt=bla)", + "string with dual range (opt=1k-4k,4k-8k)", + "integer value (opt=100)", + "boolean value (opt=1)", + "no argument (opt)", + }; + + if (o->alias) + fprintf(out, "%20s: %s\n", "alias", o->alias); + + fprintf(out, "%20s: %s\n", "type", typehelp[o->type]); + fprintf(out, "%20s: %s\n", "default", o->def ? o->def : "no default"); + show_option_range(o, stdout); + show_option_values(o); +} + static unsigned long get_mult_time(char c) { switch (c) { @@ -87,30 +113,39 @@ static unsigned long get_mult_time(char c) } } -static unsigned long get_mult_bytes(char c) +static unsigned long long get_mult_bytes(char c, void *data) { + unsigned int kb_base = fio_get_kb_base(data); + unsigned long long ret = 1; + switch (c) { - case 'k': - case 'K': - return 1024; - case 'm': - case 'M': - return 1024 * 1024; + default: + break; + case 'p': + case 'P': + ret *= (unsigned long long) kb_base; + case 't': + case 'T': + ret *= (unsigned long long) kb_base; case 'g': case 'G': - return 1024 * 1024 * 1024; - case 'e': - case 'E': - return 1024 * 1024 * 1024 * 1024UL; - default: - return 1; + ret *= (unsigned long long) kb_base; + case 'm': + case 'M': + ret *= (unsigned long long) kb_base; + case 'k': + case 'K': + ret *= (unsigned long long) kb_base; + break; } + + return ret; } /* * convert string into decimal value, noting any size suffix */ -int str_to_decimal(const char *str, long long *val, int kilo) +int str_to_decimal(const char *str, long long *val, int kilo, void *data) { int len, base; @@ -127,22 +162,32 @@ int str_to_decimal(const char *str, long long *val, int kilo) if (*val == LONG_MAX && errno == ERANGE) return 1; - if (kilo) - *val *= get_mult_bytes(str[len - 1]); - else + if (kilo) { + const char *p; + /* + * if the last char is 'b' or 'B', the user likely used + * "1gb" instead of just "1g". If the second to last is also + * a letter, adjust. + */ + p = str + len - 1; + if ((*p == 'b' || *p == 'B') && isalpha(*(p - 1))) + --p; + + *val *= get_mult_bytes(*p, data); + } else *val *= get_mult_time(str[len - 1]); return 0; } -static int check_str_bytes(const char *p, long long *val) +static int check_str_bytes(const char *p, long long *val, void *data) { - return str_to_decimal(p, val, 1); + return str_to_decimal(p, val, 1, data); } static int check_str_time(const char *p, long long *val) { - return str_to_decimal(p, val, 0); + return str_to_decimal(p, val, 0, NULL); } void strip_blank_front(char **p) @@ -175,7 +220,7 @@ void strip_blank_end(char *p) *(s + 1) = '\0'; } -static int check_range_bytes(const char *str, long *val) +static int check_range_bytes(const char *str, long *val, void *data) { char suffix; @@ -183,7 +228,7 @@ static int check_range_bytes(const char *str, long *val) return 1; if (sscanf(str, "%lu%c", val, &suffix) == 2) { - *val *= get_mult_bytes(suffix); + *val *= get_mult_bytes(suffix, data); return 0; } @@ -284,7 +329,7 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, if (is_time) ret = check_str_time(ptr, &ull); else - ret = check_str_bytes(ptr, &ull); + ret = check_str_bytes(ptr, &ull, data); if (ret) break; @@ -351,8 +396,8 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, p1 = tmp; ret = 1; - if (!check_range_bytes(p1, &ul1) && - !check_range_bytes(p2, &ul2)) { + if (!check_range_bytes(p1, &ul1, data) && + !check_range_bytes(p2, &ul2, data)) { ret = 0; if (ul1 > ul2) { unsigned long foo = ul1; @@ -425,6 +470,18 @@ static int __handle_option(struct fio_option *o, const char *ptr, void *data, ret = 1; } + if (ret) + return ret; + + if (o->verify) { + ret = o->verify(o, data); + if (ret) { + fprintf(stderr,"Correct format for offending option\n"); + fprintf(stderr, "%20s: %s\n", o->name, o->help); + show_option_help(o, stderr); + } + } + return ret; } @@ -510,7 +567,7 @@ static int opt_cmp(const void *p1, const void *p2) o1 = get_option(s1, fio_options, &foo); o2 = get_option(s2, fio_options, &foo); - + prio1 = prio2 = 0; if (o1) prio1 = o1->prio; @@ -563,6 +620,11 @@ static char *option_dup_subs(const char *opt) ssize_t nchr = OPT_LEN_MAX; size_t envlen; + if (strlen(in) + 1 > OPT_LEN_MAX) { + fprintf(stderr, "OPT_LEN_MAX (%d) is too small\n", OPT_LEN_MAX); + return NULL; + } + in[OPT_LEN_MAX] = '\0'; strncpy(in, opt, OPT_LEN_MAX); @@ -602,6 +664,8 @@ int parse_option(const char *opt, struct fio_option *options, void *data) char *post, *tmp; tmp = option_dup_subs(opt); + if (!tmp) + return 1; o = get_option(tmp, options, &post); if (!o) { @@ -659,28 +723,6 @@ static int string_distance(const char *s1, const char *s2) return i; } -static void show_option_help(struct fio_option *o) -{ - const char *typehelp[] = { - "string (opt=bla)", - "string with possible k/m/g postfix (opt=4k)", - "string with time postfix (opt=10s)", - "string (opt=bla)", - "string with dual range (opt=1k-4k,4k-8k)", - "integer value (opt=100)", - "boolean value (opt=1)", - "no argument (opt)", - }; - - if (o->alias) - printf("%20s: %s\n", "alias", o->alias); - - printf("%20s: %s\n", "type", typehelp[o->type]); - printf("%20s: %s\n", "default", o->def ? o->def : "no default"); - show_option_range(o); - show_option_values(o); -} - static struct fio_option *find_child(struct fio_option *options, struct fio_option *o) { @@ -785,7 +827,7 @@ int show_cmd_help(struct fio_option *options, const char *name) if (!match) continue; - show_option_help(o); + show_option_help(o, stdout); } if (found) @@ -795,7 +837,7 @@ int show_cmd_help(struct fio_option *options, const char *name) if (closest) { printf(" - showing closest match\n"); printf("%20s: %s\n", closest->name, closest->help); - show_option_help(closest); + show_option_help(closest, stdout); } else printf("\n");