"OPT_BOOL",
"OPT_FLOAT_LIST",
"OPT_STR_SET",
+ "OPT_STR_VAL_ZONE",
"OPT_DEPRECATED",
"OPT_SOFT_DEPRECATED",
"OPT_UNSUPPORTED",
#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;
}
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)
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)
{
}
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';
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) {
}
}
+store_option_value:
if (fn)
ret = fn(data, &ull);
else {
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)
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, ',');
}
case FIO_OPT_DEPRECATED:
ret = 1;
- /* fall through */
+ fallthrough;
case FIO_OPT_SOFT_DEPRECATED:
log_info("Option %s is deprecated\n", o->name);
break;
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 *