2009-05-18 18:42:09 +04:00
|
|
|
/*
|
|
|
|
* Commandline option parsing functions
|
|
|
|
*
|
|
|
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
|
|
|
* Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2016-01-29 20:49:55 +03:00
|
|
|
#include "qemu/osdep.h"
|
2009-05-18 18:42:09 +04:00
|
|
|
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 11:01:28 +03:00
|
|
|
#include "qapi/error.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/error-report.h"
|
2018-02-01 14:18:35 +03:00
|
|
|
#include "qapi/qmp/qbool.h"
|
|
|
|
#include "qapi/qmp/qdict.h"
|
2018-02-01 14:18:36 +03:00
|
|
|
#include "qapi/qmp/qnum.h"
|
2018-02-01 14:18:35 +03:00
|
|
|
#include "qapi/qmp/qstring.h"
|
2012-12-17 21:19:43 +04:00
|
|
|
#include "qapi/qmp/qerror.h"
|
2012-12-17 21:20:00 +04:00
|
|
|
#include "qemu/option_int.h"
|
2016-03-20 20:16:19 +03:00
|
|
|
#include "qemu/cutils.h"
|
|
|
|
#include "qemu/id.h"
|
|
|
|
#include "qemu/help_option.h"
|
2009-05-18 18:42:09 +04:00
|
|
|
|
|
|
|
/*
|
2020-11-08 18:21:21 +03:00
|
|
|
* Extracts the name of an option from the parameter string (@p points at the
|
2009-05-18 18:42:09 +04:00
|
|
|
* first byte of the option name)
|
|
|
|
*
|
2020-11-08 18:21:21 +03:00
|
|
|
* The option name is @len characters long and is copied into @option. The
|
|
|
|
* caller is responsible for free'ing @option when no longer required.
|
2009-05-18 18:42:09 +04:00
|
|
|
*
|
|
|
|
* The return value is the position of the delimiter/zero byte after the option
|
2020-11-08 18:21:21 +03:00
|
|
|
* name in @p.
|
2009-05-18 18:42:09 +04:00
|
|
|
*/
|
2020-11-08 18:21:21 +03:00
|
|
|
static const char *get_opt_name(const char *p, char **option, size_t len)
|
2009-05-18 18:42:09 +04:00
|
|
|
{
|
2020-11-08 18:21:21 +03:00
|
|
|
*option = g_strndup(p, len);
|
|
|
|
return p + len;
|
2009-05-18 18:42:09 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extracts the value of an option from the parameter string p (p points at the
|
|
|
|
* first byte of the option value)
|
|
|
|
*
|
|
|
|
* This function is comparable to get_opt_name with the difference that the
|
|
|
|
* delimiter is fixed to be comma which starts a new option. To specify an
|
|
|
|
* option value that contains commas, double each comma.
|
|
|
|
*/
|
2018-04-16 14:17:43 +03:00
|
|
|
const char *get_opt_value(const char *p, char **value)
|
2009-05-18 18:42:09 +04:00
|
|
|
{
|
2018-04-16 14:17:43 +03:00
|
|
|
size_t capacity = 0, length;
|
|
|
|
const char *offset;
|
2009-05-18 18:42:09 +04:00
|
|
|
|
2018-05-14 20:19:13 +03:00
|
|
|
*value = NULL;
|
2018-04-16 14:17:43 +03:00
|
|
|
while (1) {
|
2018-06-29 13:32:10 +03:00
|
|
|
offset = qemu_strchrnul(p, ',');
|
2018-04-16 14:17:43 +03:00
|
|
|
length = offset - p;
|
|
|
|
if (*offset != '\0' && *(offset + 1) == ',') {
|
|
|
|
length++;
|
|
|
|
}
|
2018-05-14 20:19:13 +03:00
|
|
|
*value = g_renew(char, *value, capacity + length + 1);
|
|
|
|
strncpy(*value + capacity, p, length);
|
|
|
|
(*value)[capacity + length] = '\0';
|
2018-04-16 14:17:43 +03:00
|
|
|
capacity += length;
|
|
|
|
if (*offset == '\0' ||
|
|
|
|
*(offset + 1) != ',') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
p += (offset - p) + 2;
|
2009-05-18 18:42:09 +04:00
|
|
|
}
|
|
|
|
|
2018-04-16 14:17:43 +03:00
|
|
|
return offset;
|
2009-05-18 18:42:09 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
static bool parse_option_number(const char *name, const char *value,
|
2012-03-21 21:37:44 +04:00
|
|
|
uint64_t *ret, Error **errp)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
|
|
|
uint64_t number;
|
2017-02-21 23:13:53 +03:00
|
|
|
int err;
|
2009-07-22 18:43:03 +04:00
|
|
|
|
2017-02-21 23:13:53 +03:00
|
|
|
err = qemu_strtou64(value, NULL, 0, &number);
|
|
|
|
if (err == -ERANGE) {
|
|
|
|
error_setg(errp, "Value '%s' is too large for parameter '%s'",
|
|
|
|
value, name);
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2017-02-21 23:13:53 +03:00
|
|
|
}
|
|
|
|
if (err) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number");
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2017-02-21 23:13:46 +03:00
|
|
|
*ret = number;
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
|
2014-06-05 13:20:40 +04:00
|
|
|
static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; desc[i].name != NULL; i++) {
|
|
|
|
if (strcmp(desc[i].name, name) == 0) {
|
|
|
|
return &desc[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:37 +03:00
|
|
|
static const char *find_default_by_name(QemuOpts *opts, const char *name)
|
|
|
|
{
|
|
|
|
const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name);
|
|
|
|
|
|
|
|
return desc ? desc->def_value_str : NULL;
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
bool parse_option_size(const char *name, const char *value,
|
2013-07-29 18:47:56 +04:00
|
|
|
uint64_t *ret, Error **errp)
|
2009-07-22 18:43:02 +04:00
|
|
|
{
|
2017-02-21 23:14:08 +03:00
|
|
|
uint64_t size;
|
|
|
|
int err;
|
2009-07-22 18:43:02 +04:00
|
|
|
|
2017-02-21 23:14:08 +03:00
|
|
|
err = qemu_strtosz(value, NULL, &size);
|
|
|
|
if (err == -ERANGE) {
|
2017-02-27 15:55:43 +03:00
|
|
|
error_setg(errp, "Value '%s' is out of range for parameter '%s'",
|
2017-02-21 23:14:08 +03:00
|
|
|
value, name);
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2017-02-21 23:13:46 +03:00
|
|
|
}
|
2017-02-21 23:14:08 +03:00
|
|
|
if (err) {
|
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name,
|
|
|
|
"a non-negative number below 2^64");
|
|
|
|
error_append_hint(errp, "Optional suffix k, M, G, T, P or E means"
|
|
|
|
" kilo-, mega-, giga-, tera-, peta-\n"
|
|
|
|
"and exabytes, respectively.\n");
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2009-07-22 18:43:02 +04:00
|
|
|
}
|
2017-02-21 23:14:08 +03:00
|
|
|
*ret = size;
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2009-07-22 18:43:02 +04:00
|
|
|
}
|
|
|
|
|
2018-08-14 18:08:04 +03:00
|
|
|
static const char *opt_type_to_string(enum QemuOptType type)
|
|
|
|
{
|
|
|
|
switch (type) {
|
|
|
|
case QEMU_OPT_STRING:
|
|
|
|
return "str";
|
|
|
|
case QEMU_OPT_BOOL:
|
|
|
|
return "bool (on/off)";
|
|
|
|
case QEMU_OPT_NUMBER:
|
|
|
|
return "num";
|
|
|
|
case QEMU_OPT_SIZE:
|
|
|
|
return "size";
|
|
|
|
}
|
|
|
|
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
|
2018-10-19 19:49:25 +03:00
|
|
|
/**
|
|
|
|
* Print the list of options available in the given list. If
|
|
|
|
* @print_caption is true, a caption (including the list name, if it
|
|
|
|
* exists) is printed. The options itself will be indented, so
|
|
|
|
* @print_caption should only be set to false if the caller prints its
|
|
|
|
* own custom caption (so that the indentation makes sense).
|
|
|
|
*/
|
|
|
|
void qemu_opts_print_help(QemuOptsList *list, bool print_caption)
|
2014-06-05 13:20:47 +04:00
|
|
|
{
|
|
|
|
QemuOptDesc *desc;
|
2018-08-14 18:08:04 +03:00
|
|
|
int i;
|
|
|
|
GPtrArray *array = g_ptr_array_new();
|
2014-06-05 13:20:47 +04:00
|
|
|
|
|
|
|
assert(list);
|
|
|
|
desc = list->desc;
|
|
|
|
while (desc && desc->name) {
|
2018-08-14 18:08:04 +03:00
|
|
|
GString *str = g_string_new(NULL);
|
2018-10-19 19:49:25 +03:00
|
|
|
g_string_append_printf(str, " %s=<%s>", desc->name,
|
2018-08-14 18:08:04 +03:00
|
|
|
opt_type_to_string(desc->type));
|
|
|
|
if (desc->help) {
|
2018-10-19 19:49:25 +03:00
|
|
|
if (str->len < 24) {
|
|
|
|
g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
|
|
|
|
}
|
2018-08-14 18:08:04 +03:00
|
|
|
g_string_append_printf(str, " - %s", desc->help);
|
|
|
|
}
|
|
|
|
g_ptr_array_add(array, g_string_free(str, false));
|
2014-06-05 13:20:47 +04:00
|
|
|
desc++;
|
|
|
|
}
|
2018-08-14 18:08:04 +03:00
|
|
|
|
|
|
|
g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
|
2018-10-19 19:49:25 +03:00
|
|
|
if (print_caption && array->len > 0) {
|
|
|
|
if (list->name) {
|
|
|
|
printf("%s options:\n", list->name);
|
|
|
|
} else {
|
|
|
|
printf("Options:\n");
|
|
|
|
}
|
|
|
|
} else if (array->len == 0) {
|
|
|
|
if (list->name) {
|
|
|
|
printf("There are no options for %s.\n", list->name);
|
|
|
|
} else {
|
|
|
|
printf("No options available.\n");
|
|
|
|
}
|
|
|
|
}
|
2018-08-14 18:08:04 +03:00
|
|
|
for (i = 0; i < array->len; i++) {
|
|
|
|
printf("%s\n", (char *)array->pdata[i]);
|
|
|
|
}
|
|
|
|
g_ptr_array_set_free_func(array, g_free);
|
|
|
|
g_ptr_array_free(array, true);
|
|
|
|
|
2014-06-05 13:20:47 +04:00
|
|
|
}
|
2009-07-22 18:43:03 +04:00
|
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
|
2014-06-05 13:20:58 +04:00
|
|
|
QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
|
|
|
|
2018-12-06 15:10:34 +03:00
|
|
|
QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
|
2009-07-22 18:43:03 +04:00
|
|
|
if (strcmp(opt->name, name) != 0)
|
|
|
|
continue;
|
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-06-05 13:20:45 +04:00
|
|
|
static void qemu_opt_del(QemuOpt *opt)
|
|
|
|
{
|
|
|
|
QTAILQ_REMOVE(&opt->opts->head, opt, next);
|
|
|
|
g_free(opt->name);
|
|
|
|
g_free(opt->str);
|
|
|
|
g_free(opt);
|
|
|
|
}
|
|
|
|
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
/* qemu_opt_set allows many settings for the same option.
|
|
|
|
* This function deletes all settings for an option.
|
|
|
|
*/
|
|
|
|
static void qemu_opt_del_all(QemuOpts *opts, const char *name)
|
|
|
|
{
|
|
|
|
QemuOpt *opt, *next_opt;
|
|
|
|
|
|
|
|
QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next_opt) {
|
|
|
|
if (!strcmp(opt->name, name)) {
|
|
|
|
qemu_opt_del(opt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-22 18:43:03 +04:00
|
|
|
const char *qemu_opt_get(QemuOpts *opts, const char *name)
|
|
|
|
{
|
2014-06-18 06:47:26 +04:00
|
|
|
QemuOpt *opt;
|
|
|
|
|
|
|
|
if (opts == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-06-05 13:20:42 +04:00
|
|
|
|
2014-06-18 06:47:26 +04:00
|
|
|
opt = qemu_opt_find(opts, name);
|
2014-06-05 13:20:42 +04:00
|
|
|
if (!opt) {
|
2020-07-07 19:05:38 +03:00
|
|
|
return find_default_by_name(opts, name);
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
2020-07-07 19:05:38 +03:00
|
|
|
|
|
|
|
return opt->str;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
|
2017-02-03 15:06:48 +03:00
|
|
|
void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name)
|
|
|
|
{
|
|
|
|
iter->opts = opts;
|
|
|
|
iter->opt = QTAILQ_FIRST(&opts->head);
|
|
|
|
iter->name = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *qemu_opt_iter_next(QemuOptsIter *iter)
|
|
|
|
{
|
|
|
|
QemuOpt *ret = iter->opt;
|
|
|
|
if (iter->name) {
|
|
|
|
while (ret && !g_str_equal(iter->name, ret->name)) {
|
|
|
|
ret = QTAILQ_NEXT(ret, next);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
iter->opt = ret ? QTAILQ_NEXT(ret, next) : NULL;
|
|
|
|
return ret ? ret->str : NULL;
|
|
|
|
}
|
|
|
|
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
/* Get a known option (or its default) and remove it from the list
|
|
|
|
* all in one action. Return a malloced string of the option value.
|
|
|
|
* Result must be freed by caller with g_free().
|
|
|
|
*/
|
|
|
|
char *qemu_opt_get_del(QemuOpts *opts, const char *name)
|
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
2020-07-07 19:05:38 +03:00
|
|
|
char *str;
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
|
|
|
|
if (opts == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
opt = qemu_opt_find(opts, name);
|
|
|
|
if (!opt) {
|
2020-07-07 19:05:38 +03:00
|
|
|
return g_strdup(find_default_by_name(opts, name));
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
}
|
|
|
|
str = opt->str;
|
|
|
|
opt->str = NULL;
|
|
|
|
qemu_opt_del_all(opts, name);
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2012-08-02 16:45:54 +04:00
|
|
|
bool qemu_opt_has_help_opt(QemuOpts *opts)
|
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
|
|
|
|
2018-12-06 15:10:34 +03:00
|
|
|
QTAILQ_FOREACH_REVERSE(opt, &opts->head, next) {
|
2012-08-02 16:45:54 +04:00
|
|
|
if (is_help_option(opt->name)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name,
|
|
|
|
bool defval, bool del)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
2014-06-18 06:47:26 +04:00
|
|
|
QemuOpt *opt;
|
2020-07-07 19:05:37 +03:00
|
|
|
const char *def_val;
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
bool ret = defval;
|
2009-07-22 18:43:03 +04:00
|
|
|
|
2014-06-18 06:47:26 +04:00
|
|
|
if (opts == NULL) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
opt = qemu_opt_find(opts, name);
|
2014-06-05 13:20:42 +04:00
|
|
|
if (opt == NULL) {
|
2020-07-07 19:05:37 +03:00
|
|
|
def_val = find_default_by_name(opts, name);
|
|
|
|
if (def_val) {
|
2020-11-03 19:13:39 +03:00
|
|
|
qapi_bool_parse(name, def_val, &ret, &error_abort);
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
return ret;
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
2009-07-22 18:43:03 +04:00
|
|
|
assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
ret = opt->value.boolean;
|
|
|
|
if (del) {
|
|
|
|
qemu_opt_del_all(opts, name);
|
|
|
|
}
|
|
|
|
return ret;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
|
|
|
|
{
|
|
|
|
return qemu_opt_get_bool_helper(opts, name, defval, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval)
|
|
|
|
{
|
|
|
|
return qemu_opt_get_bool_helper(opts, name, defval, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name,
|
|
|
|
uint64_t defval, bool del)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
2014-06-18 06:47:26 +04:00
|
|
|
QemuOpt *opt;
|
2020-07-07 19:05:37 +03:00
|
|
|
const char *def_val;
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
uint64_t ret = defval;
|
2009-07-22 18:43:03 +04:00
|
|
|
|
2014-06-18 06:47:26 +04:00
|
|
|
if (opts == NULL) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
opt = qemu_opt_find(opts, name);
|
2014-06-05 13:20:42 +04:00
|
|
|
if (opt == NULL) {
|
2020-07-07 19:05:37 +03:00
|
|
|
def_val = find_default_by_name(opts, name);
|
|
|
|
if (def_val) {
|
|
|
|
parse_option_number(name, def_val, &ret, &error_abort);
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
return ret;
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
2009-07-22 18:43:03 +04:00
|
|
|
assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
ret = opt->value.uint;
|
|
|
|
if (del) {
|
|
|
|
qemu_opt_del_all(opts, name);
|
|
|
|
}
|
|
|
|
return ret;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
|
|
|
|
{
|
|
|
|
return qemu_opt_get_number_helper(opts, name, defval, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t qemu_opt_get_number_del(QemuOpts *opts, const char *name,
|
|
|
|
uint64_t defval)
|
|
|
|
{
|
|
|
|
return qemu_opt_get_number_helper(opts, name, defval, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name,
|
|
|
|
uint64_t defval, bool del)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
2014-06-18 06:47:26 +04:00
|
|
|
QemuOpt *opt;
|
2020-07-07 19:05:37 +03:00
|
|
|
const char *def_val;
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
uint64_t ret = defval;
|
2009-07-22 18:43:03 +04:00
|
|
|
|
2014-06-18 06:47:26 +04:00
|
|
|
if (opts == NULL) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
opt = qemu_opt_find(opts, name);
|
2014-06-05 13:20:42 +04:00
|
|
|
if (opt == NULL) {
|
2020-07-07 19:05:37 +03:00
|
|
|
def_val = find_default_by_name(opts, name);
|
|
|
|
if (def_val) {
|
|
|
|
parse_option_size(name, def_val, &ret, &error_abort);
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
return ret;
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
2009-07-22 18:43:03 +04:00
|
|
|
assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
|
QemuOpts: add qemu_opt_get_*_del functions for replace work
Add qemu_opt_get_del, qemu_opt_get_bool_del, qemu_opt_get_number_del and
qemu_opt_get_size_del to replace the same handling of QEMUOptionParameter
(get and delete).
Several drivers are coded to parse a known subset of options, then
remove them from the list before handing all remaining options to a
second driver for further option processing. get_*_del makes it easier
to retrieve a known option (or its default) and remove it from the list
all in one action.
Share common helper function:
For qemu_opt_get_bool/size/number, they and their get_*_del counterpart
could share most of the code except whether or not deleting the opt from
option list, so generate common helper functions.
For qemu_opt_get and qemu_opt_get_del, keep code duplication, since
1. qemu_opt_get_del returns malloc'd memory while qemu_opt_get returns
in-place memory
2. qemu_opt_get_del returns (char *), qemu_opt_get returns (const char *),
and could not change to (char *), since in one case, it will return
desc->def_value_str, which is (const char *).
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
Signed-off-by: Chunyan Liu <cyliu@suse.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
2014-06-05 13:20:46 +04:00
|
|
|
ret = opt->value.uint;
|
|
|
|
if (del) {
|
|
|
|
qemu_opt_del_all(opts, name);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
|
|
|
|
{
|
|
|
|
return qemu_opt_get_size_helper(opts, name, defval, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
|
|
|
|
uint64_t defval)
|
|
|
|
{
|
|
|
|
return qemu_opt_get_size_helper(opts, name, defval, true);
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
static bool qemu_opt_parse(QemuOpt *opt, Error **errp)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
|
|
|
if (opt->desc == NULL)
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2012-03-21 21:37:44 +04:00
|
|
|
|
2009-07-22 18:43:03 +04:00
|
|
|
switch (opt->desc->type) {
|
|
|
|
case QEMU_OPT_STRING:
|
|
|
|
/* nothing */
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2009-07-22 18:43:03 +04:00
|
|
|
case QEMU_OPT_BOOL:
|
2020-11-03 19:13:39 +03:00
|
|
|
return qapi_bool_parse(opt->name, opt->str, &opt->value.boolean, errp);
|
2009-07-22 18:43:03 +04:00
|
|
|
case QEMU_OPT_NUMBER:
|
2020-07-07 19:05:41 +03:00
|
|
|
return parse_option_number(opt->name, opt->str, &opt->value.uint,
|
|
|
|
errp);
|
2009-07-22 18:43:03 +04:00
|
|
|
case QEMU_OPT_SIZE:
|
2020-07-07 19:05:41 +03:00
|
|
|
return parse_option_size(opt->name, opt->str, &opt->value.uint,
|
|
|
|
errp);
|
2009-07-22 18:43:03 +04:00
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-09 11:50:46 +03:00
|
|
|
static bool opts_accepts_any(const QemuOptsList *list)
|
2012-12-06 10:47:18 +04:00
|
|
|
{
|
2020-11-09 11:50:46 +03:00
|
|
|
return list->desc[0].name == NULL;
|
2012-12-06 10:47:18 +04:00
|
|
|
}
|
|
|
|
|
2013-07-17 16:40:37 +04:00
|
|
|
int qemu_opt_unset(QemuOpts *opts, const char *name)
|
|
|
|
{
|
|
|
|
QemuOpt *opt = qemu_opt_find(opts, name);
|
|
|
|
|
2020-11-09 11:50:46 +03:00
|
|
|
assert(opts_accepts_any(opts->list));
|
2013-07-17 16:40:37 +04:00
|
|
|
|
|
|
|
if (opt == NULL) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
qemu_opt_del(opt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:39 +03:00
|
|
|
static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value,
|
|
|
|
bool prepend)
|
|
|
|
{
|
|
|
|
QemuOpt *opt = g_malloc0(sizeof(*opt));
|
|
|
|
|
|
|
|
opt->name = g_strdup(name);
|
|
|
|
opt->str = value;
|
|
|
|
opt->opts = opts;
|
|
|
|
if (prepend) {
|
|
|
|
QTAILQ_INSERT_HEAD(&opts->head, opt, next);
|
|
|
|
} else {
|
|
|
|
QTAILQ_INSERT_TAIL(&opts->head, opt, next);
|
|
|
|
}
|
|
|
|
|
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:40 +03:00
|
|
|
static bool opt_validate(QemuOpt *opt, bool *help_wanted,
|
|
|
|
Error **errp)
|
2012-12-06 10:47:18 +04:00
|
|
|
{
|
|
|
|
const QemuOptDesc *desc;
|
2020-11-09 11:50:46 +03:00
|
|
|
const QemuOptsList *list = opt->opts->list;
|
2012-12-06 10:47:18 +04:00
|
|
|
|
2020-11-09 11:50:46 +03:00
|
|
|
desc = find_desc_by_name(list->desc, opt->name);
|
|
|
|
if (!desc && !opts_accepts_any(list)) {
|
2020-07-07 19:05:40 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER, opt->name);
|
|
|
|
if (help_wanted && is_help_option(opt->name)) {
|
2020-04-15 10:49:24 +03:00
|
|
|
*help_wanted = true;
|
2018-08-15 22:50:50 +03:00
|
|
|
}
|
2020-07-07 19:05:40 +03:00
|
|
|
return false;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2009-10-06 15:17:04 +04:00
|
|
|
|
2012-12-06 10:47:18 +04:00
|
|
|
opt->desc = desc;
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
if (!qemu_opt_parse(opt, errp)) {
|
2020-07-07 19:05:40 +03:00
|
|
|
return false;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2020-07-07 19:05:40 +03:00
|
|
|
|
|
|
|
return true;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value,
|
2015-02-12 19:52:20 +03:00
|
|
|
Error **errp)
|
2012-03-21 23:17:21 +04:00
|
|
|
{
|
2020-07-07 19:05:40 +03:00
|
|
|
QemuOpt *opt = opt_create(opts, name, g_strdup(value), false);
|
|
|
|
|
|
|
|
if (!opt_validate(opt, NULL, errp)) {
|
|
|
|
qemu_opt_del(opt);
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2020-07-07 19:05:40 +03:00
|
|
|
}
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2012-03-21 23:17:21 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val,
|
2015-02-12 18:37:44 +03:00
|
|
|
Error **errp)
|
2011-10-25 10:40:39 +04:00
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
2020-07-07 19:05:36 +03:00
|
|
|
const QemuOptDesc *desc;
|
2020-11-09 11:50:46 +03:00
|
|
|
const QemuOptsList *list = opts->list;
|
2011-10-25 10:40:39 +04:00
|
|
|
|
2020-11-09 11:50:46 +03:00
|
|
|
desc = find_desc_by_name(list->desc, name);
|
|
|
|
if (!desc && !opts_accepts_any(list)) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER, name);
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2011-10-25 10:40:39 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:36 +03:00
|
|
|
opt = g_malloc0(sizeof(*opt));
|
2011-10-25 10:40:39 +04:00
|
|
|
opt->name = g_strdup(name);
|
|
|
|
opt->opts = opts;
|
2020-07-07 19:05:36 +03:00
|
|
|
opt->desc = desc;
|
2011-10-25 10:40:39 +04:00
|
|
|
opt->value.boolean = !!val;
|
2012-12-06 10:47:20 +04:00
|
|
|
opt->str = g_strdup(val ? "on" : "off");
|
|
|
|
QTAILQ_INSERT_TAIL(&opts->head, opt, next);
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2011-10-25 10:40:39 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val,
|
2015-02-12 18:46:36 +03:00
|
|
|
Error **errp)
|
2012-12-06 10:47:23 +04:00
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
2020-07-07 19:05:36 +03:00
|
|
|
const QemuOptDesc *desc;
|
2020-11-09 11:50:46 +03:00
|
|
|
const QemuOptsList *list = opts->list;
|
2012-12-06 10:47:23 +04:00
|
|
|
|
2020-11-09 11:50:46 +03:00
|
|
|
desc = find_desc_by_name(list->desc, name);
|
|
|
|
if (!desc && !opts_accepts_any(list)) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER, name);
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2012-12-06 10:47:23 +04:00
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:36 +03:00
|
|
|
opt = g_malloc0(sizeof(*opt));
|
2012-12-06 10:47:23 +04:00
|
|
|
opt->name = g_strdup(name);
|
|
|
|
opt->opts = opts;
|
2020-07-07 19:05:36 +03:00
|
|
|
opt->desc = desc;
|
2012-12-06 10:47:23 +04:00
|
|
|
opt->value.uint = val;
|
|
|
|
opt->str = g_strdup_printf("%" PRId64, val);
|
|
|
|
QTAILQ_INSERT_TAIL(&opts->head, opt, next);
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2012-12-06 10:47:23 +04:00
|
|
|
}
|
|
|
|
|
2015-03-12 09:45:10 +03:00
|
|
|
/**
|
2015-03-12 10:40:25 +03:00
|
|
|
* For each member of @opts, call @func(@opaque, name, value, @errp).
|
|
|
|
* @func() may store an Error through @errp, but must return non-zero then.
|
2015-03-12 09:45:10 +03:00
|
|
|
* When @func() returns non-zero, break the loop and return that value.
|
|
|
|
* Return zero when the loop completes.
|
|
|
|
*/
|
2015-03-12 10:40:25 +03:00
|
|
|
int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
|
|
|
|
Error **errp)
|
2009-07-31 14:25:32 +04:00
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
2015-03-12 09:45:10 +03:00
|
|
|
int rc;
|
2009-07-31 14:25:32 +04:00
|
|
|
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_FOREACH(opt, &opts->head, next) {
|
2015-03-12 10:40:25 +03:00
|
|
|
rc = func(opaque, opt->name, opt->str, errp);
|
2015-03-12 09:45:10 +03:00
|
|
|
if (rc) {
|
|
|
|
return rc;
|
|
|
|
}
|
2015-03-12 10:40:25 +03:00
|
|
|
assert(!errp || !*errp);
|
2009-07-31 14:25:32 +04:00
|
|
|
}
|
2015-03-12 09:45:10 +03:00
|
|
|
return 0;
|
2009-07-31 14:25:32 +04:00
|
|
|
}
|
|
|
|
|
2009-07-22 18:43:03 +04:00
|
|
|
QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
|
|
|
|
{
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_FOREACH(opts, &list->head, next) {
|
2013-07-04 17:09:17 +04:00
|
|
|
if (!opts->id && !id) {
|
|
|
|
return opts;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2013-07-04 17:09:17 +04:00
|
|
|
if (opts->id && id && !strcmp(opts->id, id)) {
|
|
|
|
return opts;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-03-20 22:51:57 +04:00
|
|
|
QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id,
|
|
|
|
int fail_if_exists, Error **errp)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
|
|
|
QemuOpts *opts = NULL;
|
|
|
|
|
|
|
|
if (id) {
|
2014-09-30 15:59:30 +04:00
|
|
|
if (!id_wellformed(id)) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "id",
|
|
|
|
"an identifier");
|
hmp: Allow for error message hints on HMP
Commits 7216ae3d and d2828429 disabled some error message hints,
all because a change to use modern error reporting meant that the
hint would be output prior to the actual error. Fix this by making
hints a first-class member of Error.
For example, we are now back to the pleasant:
$ qemu-system-x86_64 --nodefaults -S --vnc :0 --chardev null,id=,
qemu-system-x86_64: --chardev null,id=,: Parameter 'id' expects an identifier
Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.
Signed-off-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <1441901956-21991-1-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-09-10 19:19:16 +03:00
|
|
|
error_append_hint(errp, "Identifiers consist of letters, digits, "
|
2015-12-17 19:35:14 +03:00
|
|
|
"'-', '.', '_', starting with a letter.\n");
|
2010-06-08 15:54:26 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-07-22 18:43:03 +04:00
|
|
|
opts = qemu_opts_find(list, id);
|
|
|
|
if (opts != NULL) {
|
2012-02-08 09:41:37 +04:00
|
|
|
if (fail_if_exists && !list->merge_lists) {
|
2014-03-22 03:42:26 +04:00
|
|
|
error_setg(errp, "Duplicate ID '%s' for %s", id, list->name);
|
2009-07-22 18:43:03 +04:00
|
|
|
return NULL;
|
|
|
|
} else {
|
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
}
|
2012-02-08 09:41:37 +04:00
|
|
|
} else if (list->merge_lists) {
|
|
|
|
opts = qemu_opts_find(list, NULL);
|
|
|
|
if (opts) {
|
|
|
|
return opts;
|
|
|
|
}
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2011-08-21 07:09:37 +04:00
|
|
|
opts = g_malloc0(sizeof(*opts));
|
2013-01-22 14:07:57 +04:00
|
|
|
opts->id = g_strdup(id);
|
2009-07-22 18:43:03 +04:00
|
|
|
opts->list = list;
|
2010-02-18 21:46:49 +03:00
|
|
|
loc_save(&opts->loc);
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_INIT(&opts->head);
|
|
|
|
QTAILQ_INSERT_TAIL(&list->head, opts, next);
|
2009-07-22 18:43:03 +04:00
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
|
2010-06-01 12:47:34 +04:00
|
|
|
void qemu_opts_reset(QemuOptsList *list)
|
|
|
|
{
|
|
|
|
QemuOpts *opts, *next_opts;
|
|
|
|
|
|
|
|
QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts) {
|
|
|
|
qemu_opts_del(opts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-27 23:06:04 +04:00
|
|
|
void qemu_opts_loc_restore(QemuOpts *opts)
|
|
|
|
{
|
|
|
|
loc_restore(&opts->loc);
|
|
|
|
}
|
|
|
|
|
qemu-option: restrict qemu_opts_set to merge-lists QemuOpts
qemu_opts_set is used to create default network backends and to
parse sugar options -kernel, -initrd, -append, -bios and -dtb.
These are very different uses:
I would *expect* a function named qemu_opts_set to set an option in a
merge-lists QemuOptsList, such as -kernel, and possibly to set an option
in a non-merge-lists QemuOptsList with non-NULL id, similar to -set.
However, it wouldn't *work* to use qemu_opts_set for the latter
because qemu_opts_set uses fail_if_exists==1. So, for non-merge-lists
QemuOptsList and non-NULL id, the semantics of qemu_opts_set (fail if the
(QemuOptsList, id) pair already exists) are debatable.
On the other hand, I would not expect qemu_opts_set to create a
non-merge-lists QemuOpts with a single option; which it does, though.
For this case of non-merge-lists QemuOptsList and NULL id, qemu_opts_set
hardly adds value over qemu_opts_parse. It does skip some parsing and
unescaping, but that's not needed when creating default network
backends.
So qemu_opts_set has warty behavior for non-merge-lists QemuOptsList
if id is non-NULL, and it's mostly pointless if id is NULL. My
solution to keeping the API as simple as possible is to limit
qemu_opts_set to merge-lists QemuOptsList. For them, it's useful (we
don't want comma-unescaping for -kernel) *and* has sane semantics.
Network backend creation is switched to qemu_opts_parse.
qemu_opts_set is now only used on merge-lists QemuOptsList... except
in the testcase, which is changed to use a merge-list QemuOptsList.
With this change we can also remove the id parameter. With the
parameter always NULL, we know that qemu_opts_create cannot fail
and can pass &error_abort to it.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2020-11-09 12:46:30 +03:00
|
|
|
bool qemu_opts_set(QemuOptsList *list, const char *name, const char *value, Error **errp)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
qemu-option: restrict qemu_opts_set to merge-lists QemuOpts
qemu_opts_set is used to create default network backends and to
parse sugar options -kernel, -initrd, -append, -bios and -dtb.
These are very different uses:
I would *expect* a function named qemu_opts_set to set an option in a
merge-lists QemuOptsList, such as -kernel, and possibly to set an option
in a non-merge-lists QemuOptsList with non-NULL id, similar to -set.
However, it wouldn't *work* to use qemu_opts_set for the latter
because qemu_opts_set uses fail_if_exists==1. So, for non-merge-lists
QemuOptsList and non-NULL id, the semantics of qemu_opts_set (fail if the
(QemuOptsList, id) pair already exists) are debatable.
On the other hand, I would not expect qemu_opts_set to create a
non-merge-lists QemuOpts with a single option; which it does, though.
For this case of non-merge-lists QemuOptsList and NULL id, qemu_opts_set
hardly adds value over qemu_opts_parse. It does skip some parsing and
unescaping, but that's not needed when creating default network
backends.
So qemu_opts_set has warty behavior for non-merge-lists QemuOptsList
if id is non-NULL, and it's mostly pointless if id is NULL. My
solution to keeping the API as simple as possible is to limit
qemu_opts_set to merge-lists QemuOptsList. For them, it's useful (we
don't want comma-unescaping for -kernel) *and* has sane semantics.
Network backend creation is switched to qemu_opts_parse.
qemu_opts_set is now only used on merge-lists QemuOptsList... except
in the testcase, which is changed to use a merge-list QemuOptsList.
With this change we can also remove the id parameter. With the
parameter always NULL, we know that qemu_opts_create cannot fail
and can pass &error_abort to it.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2020-11-09 12:46:30 +03:00
|
|
|
assert(list->merge_lists);
|
|
|
|
opts = qemu_opts_create(list, NULL, 0, &error_abort);
|
2020-07-07 19:05:41 +03:00
|
|
|
return qemu_opt_set(opts, name, value, errp);
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
|
2009-07-31 14:25:32 +04:00
|
|
|
const char *qemu_opts_id(QemuOpts *opts)
|
|
|
|
{
|
|
|
|
return opts->id;
|
|
|
|
}
|
|
|
|
|
2013-07-11 14:52:34 +04:00
|
|
|
/* The id string will be g_free()d by qemu_opts_del */
|
|
|
|
void qemu_opts_set_id(QemuOpts *opts, char *id)
|
|
|
|
{
|
|
|
|
opts->id = id;
|
|
|
|
}
|
|
|
|
|
2009-07-22 18:43:03 +04:00
|
|
|
void qemu_opts_del(QemuOpts *opts)
|
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
|
|
|
|
2014-06-05 13:20:50 +04:00
|
|
|
if (opts == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-22 18:43:03 +04:00
|
|
|
for (;;) {
|
2009-09-12 11:36:22 +04:00
|
|
|
opt = QTAILQ_FIRST(&opts->head);
|
2009-07-22 18:43:03 +04:00
|
|
|
if (opt == NULL)
|
|
|
|
break;
|
|
|
|
qemu_opt_del(opt);
|
|
|
|
}
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_REMOVE(&opts->list->head, opts, next);
|
2011-08-21 07:09:37 +04:00
|
|
|
g_free(opts->id);
|
|
|
|
g_free(opts);
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
|
2015-07-07 17:42:10 +03:00
|
|
|
/* print value, escaping any commas in value */
|
|
|
|
static void escaped_print(const char *value)
|
|
|
|
{
|
|
|
|
const char *ptr;
|
|
|
|
|
|
|
|
for (ptr = value; *ptr; ++ptr) {
|
|
|
|
if (*ptr == ',') {
|
|
|
|
putchar(',');
|
|
|
|
}
|
|
|
|
putchar(*ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_opts_print(QemuOpts *opts, const char *separator)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
2014-06-05 13:20:42 +04:00
|
|
|
QemuOptDesc *desc = opts->list->desc;
|
2015-07-07 17:42:10 +03:00
|
|
|
const char *sep = "";
|
|
|
|
|
|
|
|
if (opts->id) {
|
|
|
|
printf("id=%s", opts->id); /* passed id_wellformed -> no commas */
|
|
|
|
sep = separator;
|
|
|
|
}
|
2009-07-22 18:43:03 +04:00
|
|
|
|
2014-06-05 13:20:42 +04:00
|
|
|
if (desc[0].name == NULL) {
|
|
|
|
QTAILQ_FOREACH(opt, &opts->head, next) {
|
2015-07-07 17:42:10 +03:00
|
|
|
printf("%s%s=", sep, opt->name);
|
|
|
|
escaped_print(opt->str);
|
|
|
|
sep = separator;
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (; desc && desc->name; desc++) {
|
|
|
|
const char *value;
|
2017-10-05 22:07:25 +03:00
|
|
|
opt = qemu_opt_find(opts, desc->name);
|
2014-06-05 13:20:42 +04:00
|
|
|
|
|
|
|
value = opt ? opt->str : desc->def_value_str;
|
|
|
|
if (!value) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (desc->type == QEMU_OPT_STRING) {
|
2015-07-07 17:42:10 +03:00
|
|
|
printf("%s%s=", sep, desc->name);
|
|
|
|
escaped_print(value);
|
2014-06-05 13:20:42 +04:00
|
|
|
} else if ((desc->type == QEMU_OPT_SIZE ||
|
|
|
|
desc->type == QEMU_OPT_NUMBER) && opt) {
|
2014-12-09 10:38:04 +03:00
|
|
|
printf("%s%s=%" PRId64, sep, desc->name, opt->value.uint);
|
2014-06-05 13:20:42 +04:00
|
|
|
} else {
|
2014-12-09 10:38:04 +03:00
|
|
|
printf("%s%s=%s", sep, desc->name, value);
|
2014-06-05 13:20:42 +04:00
|
|
|
}
|
2015-07-07 17:42:10 +03:00
|
|
|
sep = separator;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-15 10:49:20 +03:00
|
|
|
static const char *get_opt_name_value(const char *params,
|
|
|
|
const char *firstname,
|
|
|
|
char **name, char **value)
|
|
|
|
{
|
2020-11-08 18:21:21 +03:00
|
|
|
const char *p;
|
|
|
|
size_t len;
|
2020-04-15 10:49:20 +03:00
|
|
|
|
2020-11-08 18:21:21 +03:00
|
|
|
len = strcspn(params, "=,");
|
|
|
|
if (params[len] != '=') {
|
2020-04-15 10:49:20 +03:00
|
|
|
/* found "foo,more" */
|
|
|
|
if (firstname) {
|
|
|
|
/* implicitly named first option */
|
|
|
|
*name = g_strdup(firstname);
|
|
|
|
p = get_opt_value(params, value);
|
|
|
|
} else {
|
|
|
|
/* option without value, must be a flag */
|
2020-11-08 18:21:21 +03:00
|
|
|
p = get_opt_name(params, name, len);
|
2020-04-15 10:49:20 +03:00
|
|
|
if (strncmp(*name, "no", 2) == 0) {
|
|
|
|
memmove(*name, *name + 2, strlen(*name + 2) + 1);
|
|
|
|
*value = g_strdup("off");
|
|
|
|
} else {
|
|
|
|
*value = g_strdup("on");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* found "foo=bar,more" */
|
2020-11-08 18:21:21 +03:00
|
|
|
p = get_opt_name(params, name, len);
|
2020-04-15 10:49:20 +03:00
|
|
|
assert(*p == '=');
|
|
|
|
p++;
|
|
|
|
p = get_opt_value(p, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!*p || *p == ',');
|
|
|
|
if (*p == ',') {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
static bool opts_do_parse(QemuOpts *opts, const char *params,
|
2018-08-15 22:50:50 +03:00
|
|
|
const char *firstname, bool prepend,
|
2020-04-15 10:49:24 +03:00
|
|
|
bool *help_wanted, Error **errp)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
2020-04-15 10:49:20 +03:00
|
|
|
char *option, *value;
|
|
|
|
const char *p;
|
2020-07-07 19:05:40 +03:00
|
|
|
QemuOpt *opt;
|
2009-07-22 18:43:03 +04:00
|
|
|
|
2020-04-15 10:49:20 +03:00
|
|
|
for (p = params; *p;) {
|
|
|
|
p = get_opt_name_value(p, firstname, &option, &value);
|
|
|
|
firstname = NULL;
|
|
|
|
|
|
|
|
if (!strcmp(option, "id")) {
|
|
|
|
g_free(option);
|
|
|
|
g_free(value);
|
|
|
|
continue;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2020-04-15 10:49:20 +03:00
|
|
|
|
2020-07-07 19:05:40 +03:00
|
|
|
opt = opt_create(opts, option, value, prepend);
|
opts: don't silently truncate long parameter keys
The existing QemuOpts parsing code uses a fixed size 128 byte buffer
for storing the parameter keys. If a key exceeded this size it was
silently truncate and no error reported to the user. This behaviour was
reasonable & harmless because traditionally the key names are all
statically declared, and it was known that no code was declaring a key
longer than 127 bytes. This assumption, however, ceased to be valid once
the block layer added support for dot-separate compound keys. This
syntax allows for keys that can be arbitrarily long, limited only by the
number of block drivers you can stack up. With this usage, silently
truncating the key name can never lead to correct behaviour.
Hopefully such truncation would turn into an error, when the block code
then tried to extract options later, but there's no guarantee that will
happen. It is conceivable that an option specified by the user may be
truncated and then ignored. This could have serious consequences,
possibly even leading to security problems if the ignored option set a
security relevant parameter.
If the operating system didn't limit the user's argv when spawning QEMU,
the code should honour whatever length arguments were given without
imposing its own length restrictions. This patch thus changes the code
to use a heap allocated buffer for storing the keys during parsing,
lifting the arbitrary length restriction.
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20180416111743.8473-3-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
2018-04-16 14:17:42 +03:00
|
|
|
g_free(option);
|
2020-07-07 19:05:40 +03:00
|
|
|
if (!opt_validate(opt, help_wanted, errp)) {
|
|
|
|
qemu_opt_del(opt);
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2020-04-15 10:49:20 +03:00
|
|
|
}
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2020-07-07 19:05:41 +03:00
|
|
|
|
|
|
|
return true;
|
2009-09-10 12:58:33 +04:00
|
|
|
}
|
|
|
|
|
2020-04-15 10:49:21 +03:00
|
|
|
static char *opts_parse_id(const char *params)
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
char *name, *value;
|
|
|
|
|
|
|
|
for (p = params; *p;) {
|
|
|
|
p = get_opt_name_value(p, NULL, &name, &value);
|
|
|
|
if (!strcmp(name, "id")) {
|
|
|
|
g_free(name);
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
g_free(name);
|
|
|
|
g_free(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-04-15 10:49:22 +03:00
|
|
|
bool has_help_option(const char *params)
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
char *name, *value;
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
for (p = params; *p;) {
|
|
|
|
p = get_opt_name_value(p, NULL, &name, &value);
|
|
|
|
ret = is_help_option(name);
|
|
|
|
g_free(name);
|
|
|
|
g_free(value);
|
|
|
|
if (ret) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-12 20:37:11 +03:00
|
|
|
/**
|
|
|
|
* Store options parsed from @params into @opts.
|
|
|
|
* If @firstname is non-null, the first key=value in @params may omit
|
|
|
|
* key=, and is treated as if key was @firstname.
|
|
|
|
* On error, store an error object through @errp if non-null.
|
|
|
|
*/
|
2020-07-07 19:05:41 +03:00
|
|
|
bool qemu_opts_do_parse(QemuOpts *opts, const char *params,
|
2015-02-12 20:37:11 +03:00
|
|
|
const char *firstname, Error **errp)
|
2012-01-27 22:54:54 +04:00
|
|
|
{
|
2020-07-07 19:05:41 +03:00
|
|
|
return opts_do_parse(opts, params, firstname, false, NULL, errp);
|
2012-01-27 22:54:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
|
2018-08-15 22:50:50 +03:00
|
|
|
bool permit_abbrev, bool defaults,
|
2020-04-15 10:49:24 +03:00
|
|
|
bool *help_wanted, Error **errp)
|
2009-09-10 12:58:33 +04:00
|
|
|
{
|
2010-02-10 21:52:18 +03:00
|
|
|
const char *firstname;
|
2020-04-15 10:49:21 +03:00
|
|
|
char *id = opts_parse_id(params);
|
2009-09-10 12:58:33 +04:00
|
|
|
QemuOpts *opts;
|
|
|
|
|
2010-02-10 21:52:18 +03:00
|
|
|
assert(!permit_abbrev || list->implied_opt_name);
|
|
|
|
firstname = permit_abbrev ? list->implied_opt_name : NULL;
|
|
|
|
|
qemu-option: Guard against qemu_opts_set_defaults() misuse
Commit 6d4cd40 fixed qemu_opts_set_defaults() for an existing corner
case, but broke it for another one that can't be reached in current
code.
Quote from its commit message:
I believe [opts_parse()] attempts to do the following:
If options don't yet exist, create new options
Else, if defaults, modify the existing options
Else, if list->merge_lists, modify the existing options
Else, fail
The only caller that passes true for defaults is
qemu_opts_set_defaults().
The commit message then claims:
A straightforward call of qemu_opts_create() does exactly that.
Wrong. When !list->merge_lists, and the option string doesn't contain
id=, and options without ID exist, then we don't actually modify the
existing options, we create new ones.
Not reachable, because we never pass lists with !list->merge_lists to
qemu_opts_set_defaults().
Guard against possible (if unlikely) future misuse with assert().
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 1375428840-5275-1-git-send-email-armbru@redhat.com
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2013-08-02 11:34:00 +04:00
|
|
|
/*
|
|
|
|
* This code doesn't work for defaults && !list->merge_lists: when
|
|
|
|
* params has no id=, and list has an element with !opts->id, it
|
|
|
|
* appends a new element instead of returning the existing opts.
|
|
|
|
* However, we got no use for this case. Guard against possible
|
|
|
|
* (if unlikely) future misuse:
|
|
|
|
*/
|
|
|
|
assert(!defaults || list->merge_lists);
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
opts = qemu_opts_create(list, id, !defaults, errp);
|
2018-04-16 14:17:43 +03:00
|
|
|
g_free(id);
|
2012-03-20 22:51:57 +04:00
|
|
|
if (opts == NULL) {
|
2009-09-10 12:58:33 +04:00
|
|
|
return NULL;
|
2012-03-20 22:51:57 +04:00
|
|
|
}
|
2009-09-10 12:58:33 +04:00
|
|
|
|
qemu-option: Use returned bool to check for failure
The previous commit enables conversion of
foo(..., &err);
if (err) {
...
}
to
if (!foo(..., &err)) {
...
}
for QemuOpts functions that now return true / false on success /
error. Coccinelle script:
@@
identifier fun = {
opts_do_parse, parse_option_bool, parse_option_number,
parse_option_size, qemu_opt_parse, qemu_opt_rename, qemu_opt_set,
qemu_opt_set_bool, qemu_opt_set_number, qemu_opts_absorb_qdict,
qemu_opts_do_parse, qemu_opts_from_qdict_entry, qemu_opts_set,
qemu_opts_validate
};
expression list args, args2;
typedef Error;
Error *err;
@@
- fun(args, &err, args2);
- if (err)
+ if (!fun(args, &err, args2))
{
...
}
A few line breaks tidied up manually.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200707160613.848843-15-armbru@redhat.com>
[Conflict with commit 0b6786a9c1 "block/amend: refactor qcow2 amend
options" resolved by rerunning Coccinelle on master's version]
2020-07-07 19:05:42 +03:00
|
|
|
if (!opts_do_parse(opts, params, firstname, defaults, help_wanted,
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
errp)) {
|
2009-09-10 12:58:33 +04:00
|
|
|
qemu_opts_del(opts);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-07-22 18:43:03 +04:00
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
|
2015-02-12 20:24:10 +03:00
|
|
|
/**
|
|
|
|
* Create a QemuOpts in @list and with options parsed from @params.
|
|
|
|
* If @permit_abbrev, the first key=value in @params may omit key=,
|
|
|
|
* and is treated as if key was @list->implied_opt_name.
|
QemuOpts: Wean off qerror_report_err()
qerror_report_err() is a transitional interface to help with
converting existing monitor commands to QMP. It should not be used
elsewhere.
The only remaining user in qemu-option.c is qemu_opts_parse(). Is it
used in QMP context? If not, we can simply replace
qerror_report_err() by error_report_err().
The uses in qemu-img.c, qemu-io.c, qemu-nbd.c and under tests/ are
clearly not in QMP context.
The uses in vl.c aren't either, because the only QMP command handlers
there are qmp_query_status() and qmp_query_machines(), and they don't
call it.
Remaining uses:
* drive_def(): Command line -drive and such, HMP drive_add and pci_add
* hmp_chardev_add(): HMP chardev-add
* monitor_parse_command(): HMP core
* tmp_config_parse(): Command line -tpmdev
* net_host_device_add(): HMP host_net_add
* net_client_parse(): Command line -net and -netdev
* qemu_global_option(): Command line -global
* vnc_parse_func(): Command line -display, -vnc, default display, HMP
change, QMP change. Bummer.
* qemu_pci_hot_add_nic(): HMP pci_add
* usb_net_init(): Command line -usbdevice, HMP usb_add
Propagate errors through qemu_opts_parse(). Create a convenience
function qemu_opts_parse_noisily() that passes errors to
error_report_err(). Switch all non-QMP users outside tests to it.
That leaves vnc_parse_func(). Propagate errors through it. Since I'm
touching it anyway, rename it to vnc_parse().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-13 14:50:26 +03:00
|
|
|
* On error, store an error object through @errp if non-null.
|
2015-02-12 20:24:10 +03:00
|
|
|
* Return the new QemuOpts on success, null pointer on error.
|
|
|
|
*/
|
2012-01-27 22:54:54 +04:00
|
|
|
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
|
QemuOpts: Wean off qerror_report_err()
qerror_report_err() is a transitional interface to help with
converting existing monitor commands to QMP. It should not be used
elsewhere.
The only remaining user in qemu-option.c is qemu_opts_parse(). Is it
used in QMP context? If not, we can simply replace
qerror_report_err() by error_report_err().
The uses in qemu-img.c, qemu-io.c, qemu-nbd.c and under tests/ are
clearly not in QMP context.
The uses in vl.c aren't either, because the only QMP command handlers
there are qmp_query_status() and qmp_query_machines(), and they don't
call it.
Remaining uses:
* drive_def(): Command line -drive and such, HMP drive_add and pci_add
* hmp_chardev_add(): HMP chardev-add
* monitor_parse_command(): HMP core
* tmp_config_parse(): Command line -tpmdev
* net_host_device_add(): HMP host_net_add
* net_client_parse(): Command line -net and -netdev
* qemu_global_option(): Command line -global
* vnc_parse_func(): Command line -display, -vnc, default display, HMP
change, QMP change. Bummer.
* qemu_pci_hot_add_nic(): HMP pci_add
* usb_net_init(): Command line -usbdevice, HMP usb_add
Propagate errors through qemu_opts_parse(). Create a convenience
function qemu_opts_parse_noisily() that passes errors to
error_report_err(). Switch all non-QMP users outside tests to it.
That leaves vnc_parse_func(). Propagate errors through it. Since I'm
touching it anyway, rename it to vnc_parse().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-13 14:50:26 +03:00
|
|
|
bool permit_abbrev, Error **errp)
|
|
|
|
{
|
2018-08-15 22:50:50 +03:00
|
|
|
return opts_parse(list, params, permit_abbrev, false, NULL, errp);
|
QemuOpts: Wean off qerror_report_err()
qerror_report_err() is a transitional interface to help with
converting existing monitor commands to QMP. It should not be used
elsewhere.
The only remaining user in qemu-option.c is qemu_opts_parse(). Is it
used in QMP context? If not, we can simply replace
qerror_report_err() by error_report_err().
The uses in qemu-img.c, qemu-io.c, qemu-nbd.c and under tests/ are
clearly not in QMP context.
The uses in vl.c aren't either, because the only QMP command handlers
there are qmp_query_status() and qmp_query_machines(), and they don't
call it.
Remaining uses:
* drive_def(): Command line -drive and such, HMP drive_add and pci_add
* hmp_chardev_add(): HMP chardev-add
* monitor_parse_command(): HMP core
* tmp_config_parse(): Command line -tpmdev
* net_host_device_add(): HMP host_net_add
* net_client_parse(): Command line -net and -netdev
* qemu_global_option(): Command line -global
* vnc_parse_func(): Command line -display, -vnc, default display, HMP
change, QMP change. Bummer.
* qemu_pci_hot_add_nic(): HMP pci_add
* usb_net_init(): Command line -usbdevice, HMP usb_add
Propagate errors through qemu_opts_parse(). Create a convenience
function qemu_opts_parse_noisily() that passes errors to
error_report_err(). Switch all non-QMP users outside tests to it.
That leaves vnc_parse_func(). Propagate errors through it. Since I'm
touching it anyway, rename it to vnc_parse().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-13 14:50:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a QemuOpts in @list and with options parsed from @params.
|
|
|
|
* If @permit_abbrev, the first key=value in @params may omit key=,
|
|
|
|
* and is treated as if key was @list->implied_opt_name.
|
|
|
|
* Report errors with error_report_err(). This is inappropriate in
|
|
|
|
* QMP context. Do not use this function there!
|
|
|
|
* Return the new QemuOpts on success, null pointer on error.
|
|
|
|
*/
|
|
|
|
QemuOpts *qemu_opts_parse_noisily(QemuOptsList *list, const char *params,
|
|
|
|
bool permit_abbrev)
|
2012-01-27 22:54:54 +04:00
|
|
|
{
|
2015-02-12 20:24:10 +03:00
|
|
|
Error *err = NULL;
|
|
|
|
QemuOpts *opts;
|
2020-04-15 10:49:24 +03:00
|
|
|
bool help_wanted = false;
|
2015-02-12 20:24:10 +03:00
|
|
|
|
2020-04-15 10:49:24 +03:00
|
|
|
opts = opts_parse(list, params, permit_abbrev, false, &help_wanted, &err);
|
QemuOpts: Wean off qerror_report_err()
qerror_report_err() is a transitional interface to help with
converting existing monitor commands to QMP. It should not be used
elsewhere.
The only remaining user in qemu-option.c is qemu_opts_parse(). Is it
used in QMP context? If not, we can simply replace
qerror_report_err() by error_report_err().
The uses in qemu-img.c, qemu-io.c, qemu-nbd.c and under tests/ are
clearly not in QMP context.
The uses in vl.c aren't either, because the only QMP command handlers
there are qmp_query_status() and qmp_query_machines(), and they don't
call it.
Remaining uses:
* drive_def(): Command line -drive and such, HMP drive_add and pci_add
* hmp_chardev_add(): HMP chardev-add
* monitor_parse_command(): HMP core
* tmp_config_parse(): Command line -tpmdev
* net_host_device_add(): HMP host_net_add
* net_client_parse(): Command line -net and -netdev
* qemu_global_option(): Command line -global
* vnc_parse_func(): Command line -display, -vnc, default display, HMP
change, QMP change. Bummer.
* qemu_pci_hot_add_nic(): HMP pci_add
* usb_net_init(): Command line -usbdevice, HMP usb_add
Propagate errors through qemu_opts_parse(). Create a convenience
function qemu_opts_parse_noisily() that passes errors to
error_report_err(). Switch all non-QMP users outside tests to it.
That leaves vnc_parse_func(). Propagate errors through it. Since I'm
touching it anyway, rename it to vnc_parse().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Luiz Capitulino <lcapitulino@redhat.com>
2015-02-13 14:50:26 +03:00
|
|
|
if (err) {
|
2020-04-15 10:49:24 +03:00
|
|
|
if (help_wanted) {
|
2018-10-19 19:49:25 +03:00
|
|
|
qemu_opts_print_help(list, true);
|
2018-08-15 22:50:50 +03:00
|
|
|
error_free(err);
|
|
|
|
} else {
|
|
|
|
error_report_err(err);
|
|
|
|
}
|
2015-02-12 20:24:10 +03:00
|
|
|
}
|
|
|
|
return opts;
|
2012-01-27 22:54:54 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
|
|
|
|
int permit_abbrev)
|
|
|
|
{
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
2018-08-15 22:50:50 +03:00
|
|
|
opts = opts_parse(list, params, permit_abbrev, true, NULL, NULL);
|
2012-01-27 22:54:54 +04:00
|
|
|
assert(opts);
|
|
|
|
}
|
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
static bool qemu_opts_from_qdict_entry(QemuOpts *opts,
|
2020-04-15 11:30:48 +03:00
|
|
|
const QDictEntry *entry,
|
|
|
|
Error **errp)
|
2010-02-10 22:15:29 +03:00
|
|
|
{
|
2020-04-15 11:30:48 +03:00
|
|
|
const char *key = qdict_entry_key(entry);
|
|
|
|
QObject *obj = qdict_entry_value(entry);
|
2020-07-07 19:05:41 +03:00
|
|
|
char buf[32];
|
|
|
|
g_autofree char *tmp = NULL;
|
2010-02-10 22:15:29 +03:00
|
|
|
const char *value;
|
|
|
|
|
2020-04-15 11:30:48 +03:00
|
|
|
if (!strcmp(key, "id")) {
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2010-02-10 22:15:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (qobject_type(obj)) {
|
|
|
|
case QTYPE_QSTRING:
|
2018-02-24 18:40:29 +03:00
|
|
|
value = qstring_get_str(qobject_to(QString, obj));
|
2010-02-10 22:15:29 +03:00
|
|
|
break;
|
2017-06-07 19:35:58 +03:00
|
|
|
case QTYPE_QNUM:
|
2018-02-24 18:40:29 +03:00
|
|
|
tmp = qnum_to_string(qobject_to(QNum, obj));
|
2017-06-07 19:35:58 +03:00
|
|
|
value = tmp;
|
2010-02-10 22:15:29 +03:00
|
|
|
break;
|
|
|
|
case QTYPE_QBOOL:
|
2010-03-18 23:48:19 +03:00
|
|
|
pstrcpy(buf, sizeof(buf),
|
2018-02-24 18:40:29 +03:00
|
|
|
qbool_get_bool(qobject_to(QBool, obj)) ? "on" : "off");
|
2010-02-10 22:15:29 +03:00
|
|
|
value = buf;
|
|
|
|
break;
|
|
|
|
default:
|
2020-07-07 19:05:41 +03:00
|
|
|
return true;
|
2010-02-10 22:15:29 +03:00
|
|
|
}
|
2012-04-19 00:24:01 +04:00
|
|
|
|
2020-07-07 19:05:41 +03:00
|
|
|
return qemu_opt_set(opts, key, value, errp);
|
2010-02-10 22:15:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create QemuOpts from a QDict.
|
2017-06-07 19:35:58 +03:00
|
|
|
* Use value of key "id" as ID if it exists and is a QString. Only
|
|
|
|
* QStrings, QNums and QBools are copied. Entries with other types
|
|
|
|
* are silently ignored.
|
2010-02-10 22:15:29 +03:00
|
|
|
*/
|
2012-04-19 00:24:01 +04:00
|
|
|
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
|
|
|
|
Error **errp)
|
2010-02-10 22:15:29 +03:00
|
|
|
{
|
2012-04-19 00:24:01 +04:00
|
|
|
QemuOpts *opts;
|
2020-04-15 11:30:47 +03:00
|
|
|
const QDictEntry *entry;
|
2010-02-10 22:15:29 +03:00
|
|
|
|
2020-07-07 19:05:35 +03:00
|
|
|
opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, errp);
|
|
|
|
if (!opts) {
|
2010-02-10 22:15:29 +03:00
|
|
|
return NULL;
|
2012-03-20 22:51:57 +04:00
|
|
|
}
|
2010-02-10 22:15:29 +03:00
|
|
|
|
2012-03-20 22:51:57 +04:00
|
|
|
assert(opts != NULL);
|
2012-04-19 00:24:01 +04:00
|
|
|
|
2020-04-15 11:30:47 +03:00
|
|
|
for (entry = qdict_first(qdict);
|
|
|
|
entry;
|
|
|
|
entry = qdict_next(qdict, entry)) {
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
|
2020-04-15 11:30:48 +03:00
|
|
|
qemu_opts_del(opts);
|
|
|
|
return NULL;
|
|
|
|
}
|
2012-04-19 00:24:01 +04:00
|
|
|
}
|
|
|
|
|
2010-02-10 22:15:29 +03:00
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
|
2013-03-15 13:35:05 +04:00
|
|
|
/*
|
|
|
|
* Adds all QDict entries to the QemuOpts that can be added and removes them
|
|
|
|
* from the QDict. When this function returns, the QDict contains only those
|
|
|
|
* entries that couldn't be added to the QemuOpts.
|
|
|
|
*/
|
2020-07-07 19:05:41 +03:00
|
|
|
bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
|
2013-03-15 13:35:05 +04:00
|
|
|
{
|
|
|
|
const QDictEntry *entry, *next;
|
|
|
|
|
|
|
|
entry = qdict_first(qdict);
|
|
|
|
|
|
|
|
while (entry != NULL) {
|
|
|
|
next = qdict_next(qdict, entry);
|
|
|
|
|
|
|
|
if (find_desc_by_name(opts->list->desc, entry->key)) {
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
if (!qemu_opts_from_qdict_entry(opts, entry, errp)) {
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2013-03-15 13:35:05 +04:00
|
|
|
}
|
2020-04-15 11:30:48 +03:00
|
|
|
qdict_del(qdict, entry->key);
|
2013-03-15 13:35:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
entry = next;
|
|
|
|
}
|
2020-07-07 19:05:41 +03:00
|
|
|
|
|
|
|
return true;
|
2013-03-15 13:35:05 +04:00
|
|
|
}
|
|
|
|
|
2010-02-10 22:15:29 +03:00
|
|
|
/*
|
2018-01-11 19:37:23 +03:00
|
|
|
* Convert from QemuOpts to QDict. The QDict values are of type QString.
|
|
|
|
*
|
|
|
|
* If @list is given, only add those options to the QDict that are contained in
|
|
|
|
* the list. If @del is true, any options added to the QDict are removed from
|
|
|
|
* the QemuOpts, otherwise they remain there.
|
|
|
|
*
|
|
|
|
* If two options in @opts have the same name, they are processed in order
|
|
|
|
* so that the last one wins (consistent with the reverse iteration in
|
|
|
|
* qemu_opt_find()), but all of them are deleted if @del is true.
|
|
|
|
*
|
2010-02-10 22:15:29 +03:00
|
|
|
* TODO We'll want to use types appropriate for opt->desc->type, but
|
|
|
|
* this is enough for now.
|
|
|
|
*/
|
2018-01-11 19:37:23 +03:00
|
|
|
QDict *qemu_opts_to_qdict_filtered(QemuOpts *opts, QDict *qdict,
|
|
|
|
QemuOptsList *list, bool del)
|
2010-02-10 22:15:29 +03:00
|
|
|
{
|
2018-01-11 19:37:23 +03:00
|
|
|
QemuOpt *opt, *next;
|
2010-02-10 22:15:29 +03:00
|
|
|
|
|
|
|
if (!qdict) {
|
|
|
|
qdict = qdict_new();
|
|
|
|
}
|
|
|
|
if (opts->id) {
|
2017-04-28 00:58:17 +03:00
|
|
|
qdict_put_str(qdict, "id", opts->id);
|
2010-02-10 22:15:29 +03:00
|
|
|
}
|
2018-01-11 19:37:23 +03:00
|
|
|
QTAILQ_FOREACH_SAFE(opt, &opts->head, next, next) {
|
|
|
|
if (list) {
|
|
|
|
QemuOptDesc *desc;
|
|
|
|
bool found = false;
|
|
|
|
for (desc = list->desc; desc->name; desc++) {
|
|
|
|
if (!strcmp(desc->name, opt->name)) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!found) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2017-04-28 00:58:19 +03:00
|
|
|
qdict_put_str(qdict, opt->name, opt->str);
|
2018-01-11 19:37:23 +03:00
|
|
|
if (del) {
|
|
|
|
qemu_opt_del(opt);
|
|
|
|
}
|
2010-02-10 22:15:29 +03:00
|
|
|
}
|
|
|
|
return qdict;
|
|
|
|
}
|
|
|
|
|
2018-01-11 19:37:23 +03:00
|
|
|
/* Copy all options in a QemuOpts to the given QDict. See
|
|
|
|
* qemu_opts_to_qdict_filtered() for details. */
|
|
|
|
QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
|
|
|
|
{
|
|
|
|
return qemu_opts_to_qdict_filtered(opts, qdict, NULL, false);
|
|
|
|
}
|
|
|
|
|
2009-10-06 15:17:03 +04:00
|
|
|
/* Validate parsed opts against descriptions where no
|
|
|
|
* descriptions were provided in the QemuOptsList.
|
|
|
|
*/
|
2020-07-07 19:05:41 +03:00
|
|
|
bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp)
|
2009-10-06 15:17:03 +04:00
|
|
|
{
|
|
|
|
QemuOpt *opt;
|
|
|
|
|
2020-11-09 11:50:46 +03:00
|
|
|
assert(opts_accepts_any(opts->list));
|
2009-10-06 15:17:03 +04:00
|
|
|
|
|
|
|
QTAILQ_FOREACH(opt, &opts->head, next) {
|
2012-12-06 10:47:19 +04:00
|
|
|
opt->desc = find_desc_by_name(desc, opt->name);
|
|
|
|
if (!opt->desc) {
|
2015-03-17 13:54:50 +03:00
|
|
|
error_setg(errp, QERR_INVALID_PARAMETER, opt->name);
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2009-10-06 15:17:03 +04:00
|
|
|
}
|
|
|
|
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
if (!qemu_opt_parse(opt, errp)) {
|
2020-07-07 19:05:41 +03:00
|
|
|
return false;
|
2009-10-06 15:17:03 +04:00
|
|
|
}
|
|
|
|
}
|
2020-07-07 19:05:41 +03:00
|
|
|
|
|
|
|
return true;
|
2009-10-06 15:17:03 +04:00
|
|
|
}
|
|
|
|
|
2015-03-13 13:07:24 +03:00
|
|
|
/**
|
2015-03-13 15:35:14 +03:00
|
|
|
* For each member of @list, call @func(@opaque, member, @errp).
|
2015-03-13 13:07:24 +03:00
|
|
|
* Call it with the current location temporarily set to the member's.
|
2015-03-13 15:35:14 +03:00
|
|
|
* @func() may store an Error through @errp, but must return non-zero then.
|
2015-03-13 13:07:24 +03:00
|
|
|
* When @func() returns non-zero, break the loop and return that value.
|
|
|
|
* Return zero when the loop completes.
|
|
|
|
*/
|
|
|
|
int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
|
2015-03-13 15:35:14 +03:00
|
|
|
void *opaque, Error **errp)
|
2009-07-22 18:43:03 +04:00
|
|
|
{
|
2010-02-18 21:46:49 +03:00
|
|
|
Location loc;
|
2009-07-22 18:43:03 +04:00
|
|
|
QemuOpts *opts;
|
QemuOpts: Fix qemu_opts_foreach() dangling location regression
qemu_opts_foreach() pushes and pops a Location with automatic storage
duration. Except it fails to pop when @func() returns non-zero.
cur_loc then points to unused stack space, and will most likely get
clobbered in short order.
Clobbered cur_loc can make loc_pop() and error_print_loc() crash or
report bogus locations.
Affects several qemu command line options as well as qemu-img,
qemu-io, qemu-nbd -object, and blkdebug's configuration file.
Broken in commit a4c7367, v2.4.0.
Reproducer:
$ qemu-system-x86_64 -nodefaults -display none -object secret,id=foo,foo=bar
main() reports "Property '.foo' not found" like this:
if (qemu_opts_foreach(qemu_find_opts("object"),
user_creatable_add_opts_foreach,
object_create_delayed, &err)) {
error_report_err(err);
exit(1);
}
cur_loc then points to where qemu_opts_foreach()'s Location used to
be, i.e. unused stack space. With optimization, this Location doesn't
get clobbered for me, and also happens to be the correct location.
Without optimization, it does get clobbered in a way that makes
error_report_err() report no location.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1461767349-15329-2-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2016-04-27 17:29:07 +03:00
|
|
|
int rc = 0;
|
2009-07-22 18:43:03 +04:00
|
|
|
|
2010-02-18 21:46:49 +03:00
|
|
|
loc_push_none(&loc);
|
2009-09-12 11:36:22 +04:00
|
|
|
QTAILQ_FOREACH(opts, &list->head, next) {
|
2010-02-18 21:46:49 +03:00
|
|
|
loc_restore(&opts->loc);
|
2015-03-13 15:35:14 +03:00
|
|
|
rc = func(opaque, opts, errp);
|
2015-03-13 13:07:24 +03:00
|
|
|
if (rc) {
|
QemuOpts: Fix qemu_opts_foreach() dangling location regression
qemu_opts_foreach() pushes and pops a Location with automatic storage
duration. Except it fails to pop when @func() returns non-zero.
cur_loc then points to unused stack space, and will most likely get
clobbered in short order.
Clobbered cur_loc can make loc_pop() and error_print_loc() crash or
report bogus locations.
Affects several qemu command line options as well as qemu-img,
qemu-io, qemu-nbd -object, and blkdebug's configuration file.
Broken in commit a4c7367, v2.4.0.
Reproducer:
$ qemu-system-x86_64 -nodefaults -display none -object secret,id=foo,foo=bar
main() reports "Property '.foo' not found" like this:
if (qemu_opts_foreach(qemu_find_opts("object"),
user_creatable_add_opts_foreach,
object_create_delayed, &err)) {
error_report_err(err);
exit(1);
}
cur_loc then points to where qemu_opts_foreach()'s Location used to
be, i.e. unused stack space. With optimization, this Location doesn't
get clobbered for me, and also happens to be the correct location.
Without optimization, it does get clobbered in a way that makes
error_report_err() report no location.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1461767349-15329-2-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2016-04-27 17:29:07 +03:00
|
|
|
break;
|
2015-03-13 13:07:24 +03:00
|
|
|
}
|
2015-03-13 15:35:14 +03:00
|
|
|
assert(!errp || !*errp);
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2010-02-18 21:46:49 +03:00
|
|
|
loc_pop(&loc);
|
QemuOpts: Fix qemu_opts_foreach() dangling location regression
qemu_opts_foreach() pushes and pops a Location with automatic storage
duration. Except it fails to pop when @func() returns non-zero.
cur_loc then points to unused stack space, and will most likely get
clobbered in short order.
Clobbered cur_loc can make loc_pop() and error_print_loc() crash or
report bogus locations.
Affects several qemu command line options as well as qemu-img,
qemu-io, qemu-nbd -object, and blkdebug's configuration file.
Broken in commit a4c7367, v2.4.0.
Reproducer:
$ qemu-system-x86_64 -nodefaults -display none -object secret,id=foo,foo=bar
main() reports "Property '.foo' not found" like this:
if (qemu_opts_foreach(qemu_find_opts("object"),
user_creatable_add_opts_foreach,
object_create_delayed, &err)) {
error_report_err(err);
exit(1);
}
cur_loc then points to where qemu_opts_foreach()'s Location used to
be, i.e. unused stack space. With optimization, this Location doesn't
get clobbered for me, and also happens to be the correct location.
Without optimization, it does get clobbered in a way that makes
error_report_err() report no location.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <1461767349-15329-2-git-send-email-armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
2016-04-27 17:29:07 +03:00
|
|
|
return rc;
|
2009-07-22 18:43:03 +04:00
|
|
|
}
|
2014-06-05 13:20:48 +04:00
|
|
|
|
|
|
|
static size_t count_opts_list(QemuOptsList *list)
|
|
|
|
{
|
|
|
|
QemuOptDesc *desc = NULL;
|
|
|
|
size_t num_opts = 0;
|
|
|
|
|
|
|
|
if (!list) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
desc = list->desc;
|
|
|
|
while (desc && desc->name) {
|
|
|
|
num_opts++;
|
|
|
|
desc++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return num_opts;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_opts_free(QemuOptsList *list)
|
|
|
|
{
|
|
|
|
g_free(list);
|
|
|
|
}
|
2014-06-05 13:20:49 +04:00
|
|
|
|
2014-06-05 13:21:11 +04:00
|
|
|
/* Realloc dst option list and append options from an option list (list)
|
|
|
|
* to it. dst could be NULL or a malloced list.
|
2014-06-05 13:21:12 +04:00
|
|
|
* The lifetime of dst must be shorter than the input list because the
|
|
|
|
* QemuOptDesc->name, ->help, and ->def_value_str strings are shared.
|
2014-06-05 13:20:49 +04:00
|
|
|
*/
|
|
|
|
QemuOptsList *qemu_opts_append(QemuOptsList *dst,
|
2014-06-05 13:21:11 +04:00
|
|
|
QemuOptsList *list)
|
2014-06-05 13:20:49 +04:00
|
|
|
{
|
|
|
|
size_t num_opts, num_dst_opts;
|
|
|
|
QemuOptDesc *desc;
|
|
|
|
bool need_init = false;
|
2014-06-25 12:38:41 +04:00
|
|
|
bool need_head_update;
|
2014-06-05 13:20:49 +04:00
|
|
|
|
2014-06-05 13:21:11 +04:00
|
|
|
if (!list) {
|
2014-06-05 13:20:49 +04:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If dst is NULL, after realloc, some area of dst should be initialized
|
|
|
|
* before adding options to it.
|
|
|
|
*/
|
|
|
|
if (!dst) {
|
|
|
|
need_init = true;
|
2014-06-25 12:38:41 +04:00
|
|
|
need_head_update = true;
|
|
|
|
} else {
|
|
|
|
/* Moreover, even if dst is not NULL, the realloc may move it to a
|
|
|
|
* different address in which case we may get a stale tail pointer
|
|
|
|
* in dst->head. */
|
|
|
|
need_head_update = QTAILQ_EMPTY(&dst->head);
|
2014-06-05 13:20:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
num_opts = count_opts_list(dst);
|
|
|
|
num_dst_opts = num_opts;
|
|
|
|
num_opts += count_opts_list(list);
|
|
|
|
dst = g_realloc(dst, sizeof(QemuOptsList) +
|
|
|
|
(num_opts + 1) * sizeof(QemuOptDesc));
|
|
|
|
if (need_init) {
|
|
|
|
dst->name = NULL;
|
|
|
|
dst->implied_opt_name = NULL;
|
|
|
|
dst->merge_lists = false;
|
|
|
|
}
|
2014-06-25 12:38:41 +04:00
|
|
|
if (need_head_update) {
|
|
|
|
QTAILQ_INIT(&dst->head);
|
|
|
|
}
|
2014-06-05 13:20:49 +04:00
|
|
|
dst->desc[num_dst_opts].name = NULL;
|
|
|
|
|
|
|
|
/* append list->desc to dst->desc */
|
|
|
|
if (list) {
|
|
|
|
desc = list->desc;
|
|
|
|
while (desc && desc->name) {
|
|
|
|
if (find_desc_by_name(dst->desc, desc->name) == NULL) {
|
2014-06-05 13:21:12 +04:00
|
|
|
dst->desc[num_dst_opts++] = *desc;
|
2014-06-05 13:20:49 +04:00
|
|
|
dst->desc[num_dst_opts].name = NULL;
|
|
|
|
}
|
|
|
|
desc++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|