qemu-option: move help handling to get_opt_name_value

Right now, help options are parsed normally and then checked
specially in opt_validate, but only if coming from
qemu_opts_parse_noisily.  has_help_option does the check on its own.

opt_validate() has two callers: qemu_opt_set(), which passes null and is
therefore unaffected, and opts_do_parse(), which is affected.

opts_do_parse() is called by qemu_opts_do_parse(), which passes null and
is therefore unaffected, and opts_parse().

opts_parse() is called by qemu_opts_parse() and qemu_opts_set_defaults(),
which pass null and are therefore unaffected, and
qemu_opts_parse_noisily().

Move the check from opt_validate to the parsing workhorse of QemuOpts,
get_opt_name_value.  This will come in handy in the next patch, which
will raise a warning for "-object memory-backend-ram,share" ("flag" option
with no =on/=off part) but not for "-object memory-backend-ram,help".

As a result:

- opts_parse and opts_do_parse do not return an error anymore
  when help is requested; qemu_opts_parse_noisily does not have
  to work around that anymore.

- various crazy ways to request help are not recognized anymore:
  - "help=..."
  - "nohelp" (sugar for "help=off")
  - "?=..."
  - "no?" (sugar for "?=off")

- "help" would be recognized as help request even if there is a (foolishly
  named) parameter "help".  No such parameters exist, though.

Reviewed-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2020-11-03 08:48:11 -05:00
parent 63758d1073
commit afd736252f

View file

@ -496,8 +496,7 @@ static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value,
return opt; return opt;
} }
static bool opt_validate(QemuOpt *opt, bool *help_wanted, static bool opt_validate(QemuOpt *opt, Error **errp)
Error **errp)
{ {
const QemuOptDesc *desc; const QemuOptDesc *desc;
const QemuOptsList *list = opt->opts->list; const QemuOptsList *list = opt->opts->list;
@ -505,9 +504,6 @@ static bool opt_validate(QemuOpt *opt, bool *help_wanted,
desc = find_desc_by_name(list->desc, opt->name); desc = find_desc_by_name(list->desc, opt->name);
if (!desc && !opts_accepts_any(list)) { if (!desc && !opts_accepts_any(list)) {
error_setg(errp, QERR_INVALID_PARAMETER, opt->name); error_setg(errp, QERR_INVALID_PARAMETER, opt->name);
if (help_wanted && is_help_option(opt->name)) {
*help_wanted = true;
}
return false; return false;
} }
@ -524,7 +520,7 @@ bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
{ {
QemuOpt *opt = opt_create(opts, name, g_strdup(value), false); QemuOpt *opt = opt_create(opts, name, g_strdup(value), false);
if (!opt_validate(opt, NULL, errp)) { if (!opt_validate(opt, errp)) {
qemu_opt_del(opt); qemu_opt_del(opt);
return false; return false;
} }
@ -760,10 +756,12 @@ void qemu_opts_print(QemuOpts *opts, const char *separator)
static const char *get_opt_name_value(const char *params, static const char *get_opt_name_value(const char *params,
const char *firstname, const char *firstname,
bool *help_wanted,
char **name, char **value) char **name, char **value)
{ {
const char *p; const char *p;
size_t len; size_t len;
bool is_help = false;
len = strcspn(params, "=,"); len = strcspn(params, "=,");
if (params[len] != '=') { if (params[len] != '=') {
@ -780,6 +778,7 @@ static const char *get_opt_name_value(const char *params,
*value = g_strdup("off"); *value = g_strdup("off");
} else { } else {
*value = g_strdup("on"); *value = g_strdup("on");
is_help = is_help_option(*name);
} }
} }
} else { } else {
@ -791,6 +790,9 @@ static const char *get_opt_name_value(const char *params,
} }
assert(!*p || *p == ','); assert(!*p || *p == ',');
if (help_wanted && is_help) {
*help_wanted = true;
}
if (*p == ',') { if (*p == ',') {
p++; p++;
} }
@ -806,7 +808,12 @@ static bool opts_do_parse(QemuOpts *opts, const char *params,
QemuOpt *opt; QemuOpt *opt;
for (p = params; *p;) { for (p = params; *p;) {
p = get_opt_name_value(p, firstname, &option, &value); p = get_opt_name_value(p, firstname, help_wanted, &option, &value);
if (help_wanted && *help_wanted) {
g_free(option);
g_free(value);
return false;
}
firstname = NULL; firstname = NULL;
if (!strcmp(option, "id")) { if (!strcmp(option, "id")) {
@ -817,7 +824,7 @@ static bool opts_do_parse(QemuOpts *opts, const char *params,
opt = opt_create(opts, option, value, prepend); opt = opt_create(opts, option, value, prepend);
g_free(option); g_free(option);
if (!opt_validate(opt, help_wanted, errp)) { if (!opt_validate(opt, errp)) {
qemu_opt_del(opt); qemu_opt_del(opt);
return false; return false;
} }
@ -832,7 +839,7 @@ static char *opts_parse_id(const char *params)
char *name, *value; char *name, *value;
for (p = params; *p;) { for (p = params; *p;) {
p = get_opt_name_value(p, NULL, &name, &value); p = get_opt_name_value(p, NULL, NULL, &name, &value);
if (!strcmp(name, "id")) { if (!strcmp(name, "id")) {
g_free(name); g_free(name);
return value; return value;
@ -848,11 +855,10 @@ bool has_help_option(const char *params)
{ {
const char *p; const char *p;
char *name, *value; char *name, *value;
bool ret; bool ret = false;
for (p = params; *p;) { for (p = params; *p;) {
p = get_opt_name_value(p, NULL, &name, &value); p = get_opt_name_value(p, NULL, &ret, &name, &value);
ret = is_help_option(name);
g_free(name); g_free(name);
g_free(value); g_free(value);
if (ret) { if (ret) {
@ -937,11 +943,13 @@ QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
QemuOpts *opts; QemuOpts *opts;
bool help_wanted = false; bool help_wanted = false;
opts = opts_parse(list, params, permit_abbrev, false, &help_wanted, &err); opts = opts_parse(list, params, permit_abbrev, false,
if (err) { opts_accepts_any(list) ? NULL : &help_wanted,
&err);
if (!opts) {
assert(!!err + !!help_wanted == 1);
if (help_wanted) { if (help_wanted) {
qemu_opts_print_help(list, true); qemu_opts_print_help(list, true);
error_free(err);
} else { } else {
error_report_err(err); error_report_err(err);
} }