X-Git-Url: https://git.kernel.dk/?a=blobdiff_plain;f=parse.c;h=45f4f2d3dd6db800f4f8e11a168c8ef36e788d3b;hb=0551c57127daf6b3773fed9b471b70a0d983ca59;hp=5d88d910e0ce6437ff302b469cb382eeffdb1e28;hpb=e26029be10ee2c570cba2c4cc2b1987568306cd2;p=fio.git diff --git a/parse.c b/parse.c index 5d88d910..45f4f2d3 100644 --- a/parse.c +++ b/parse.c @@ -37,6 +37,7 @@ static const char *opt_type_names[] = { "OPT_BOOL", "OPT_FLOAT_LIST", "OPT_STR_SET", + "OPT_STR_VAL_ZONE", "OPT_DEPRECATED", "OPT_SOFT_DEPRECATED", "OPT_UNSUPPORTED", @@ -373,12 +374,16 @@ int str_to_decimal(const char *str, long long *val, int kilo, void *data, #endif if (rc == 1) { + char *endptr; + if (strstr(str, "0x") || strstr(str, "0X")) base = 16; else base = 10; - *val = strtoll(str, NULL, base); + *val = strtoll(str, &endptr, base); + if (*val == 0 && endptr == str) + return 1; if (*val == LONG_MAX && errno == ERANGE) return 1; } @@ -497,7 +502,7 @@ static int str_match_len(const struct value_pair *vp, const char *str) static const char *opt_type_name(const struct fio_option *o) { - compiletime_assert(ARRAY_SIZE(opt_type_names) - 1 == FIO_OPT_UNSUPPORTED, + compiletime_assert(FIO_ARRAY_SIZE(opt_type_names) - 1 == FIO_OPT_UNSUPPORTED, "opt_type_names[] index"); if (o->type <= FIO_OPT_UNSUPPORTED) @@ -506,6 +511,33 @@ static const char *opt_type_name(const struct fio_option *o) return "OPT_UNKNOWN?"; } +static bool val_too_large(const struct fio_option *o, unsigned long long val, + bool is_uint) +{ + if (!o->maxval) + return false; + + if (is_uint) { + if ((int) val < 0) + return (int) val > (int) o->maxval; + return (unsigned int) val > o->maxval; + } + + return val > o->maxval; +} + +static bool val_too_small(const struct fio_option *o, unsigned long long val, + bool is_uint) +{ + if (!o->minval) + return false; + + if (is_uint) + return (int) val < o->minval; + + return val < o->minval; +} + static int __handle_option(const struct fio_option *o, const char *ptr, void *data, int first, int more, int curr) { @@ -565,18 +597,43 @@ static int __handle_option(const struct fio_option *o, const char *ptr, } case FIO_OPT_STR_VAL_TIME: is_time = 1; - /* fall through */ + fallthrough; case FIO_OPT_ULL: case FIO_OPT_INT: - case FIO_OPT_STR_VAL: { + case FIO_OPT_STR_VAL: + case FIO_OPT_STR_VAL_ZONE: + { fio_opt_str_val_fn *fn = o->cb; char tmp[128], *p; + size_t len = strlen(ptr); + + if (len > 0 && ptr[len - 1] == 'z') { + if (o->type == FIO_OPT_STR_VAL_ZONE) { + char *ep; + unsigned long long val; + + errno = 0; + val = strtoul(ptr, &ep, 10); + if (errno == 0 && ep != ptr && *ep == 'z') { + ull = ZONE_BASE_VAL + (uint32_t)val; + ret = 0; + goto store_option_value; + } else { + log_err("%s: unexpected zone value '%s'\n", + o->name, ptr); + return 1; + } + } else { + log_err("%s: 'z' suffix isn't applicable\n", + o->name); + return 1; + } + } if (!is_time && o->is_time) is_time = o->is_time; - tmp[sizeof(tmp) - 1] = '\0'; - strncpy(tmp, ptr, sizeof(tmp) - 1); + snprintf(tmp, sizeof(tmp), "%s", ptr); p = strchr(tmp, ','); if (p) *p = '\0'; @@ -595,14 +652,14 @@ static int __handle_option(const struct fio_option *o, const char *ptr, return 1; } - if (o->maxval && ull > o->maxval) { - log_err("max value out of range: %llu" - " (%llu max)\n", ull, o->maxval); + if (val_too_large(o, ull, o->type == FIO_OPT_INT)) { + log_err("%s: max value out of range: %llu" + " (%llu max)\n", o->name, ull, o->maxval); return 1; } - if (o->minval && ull < o->minval) { - log_err("min value out of range: %lld" - " (%d min)\n", ull, o->minval); + if (val_too_small(o, ull, o->type == FIO_OPT_INT)) { + log_err("%s: min value out of range: %lld" + " (%d min)\n", o->name, ull, o->minval); return 1; } if (o->posval[0].ival) { @@ -625,6 +682,7 @@ static int __handle_option(const struct fio_option *o, const char *ptr, } } +store_option_value: if (fn) ret = fn(data, &ull); else { @@ -756,6 +814,11 @@ static int __handle_option(const struct fio_option *o, const char *ptr, if (o->off1) { cp = td_var(data, o, o->off1); *cp = strdup(ptr); + if (strlen(ptr) > o->maxlen - 1) { + log_err("value exceeds max length of %d\n", + o->maxlen); + return 1; + } } if (fn) @@ -802,8 +865,7 @@ static int __handle_option(const struct fio_option *o, const char *ptr, char tmp[128]; char *p1, *p2; - tmp[sizeof(tmp) - 1] = '\0'; - strncpy(tmp, ptr, sizeof(tmp) - 1); + snprintf(tmp, sizeof(tmp), "%s", ptr); /* Handle bsrange with separate read,write values: */ p1 = strchr(tmp, ','); @@ -912,7 +974,7 @@ static int __handle_option(const struct fio_option *o, const char *ptr, } case FIO_OPT_DEPRECATED: ret = 1; - /* fall through */ + fallthrough; case FIO_OPT_SOFT_DEPRECATED: log_info("Option %s is deprecated\n", o->name); break; @@ -1019,7 +1081,20 @@ struct fio_option *find_option(struct fio_option *options, const char *opt) const struct fio_option * find_option_c(const struct fio_option *options, const char *opt) { - return find_option((struct fio_option *)options, opt); + const struct fio_option *o; + + for (o = &options[0]; o->name; o++) { + if (!o_match(o, opt)) + continue; + if (o->type == FIO_OPT_UNSUPPORTED) { + log_err("Option <%s>: %s\n", o->name, o->help); + continue; + } + + return o; + } + + return NULL; } static const struct fio_option *