diff options
Diffstat (limited to 'util/qemu-option.c')
-rw-r--r-- | util/qemu-option.c | 255 |
1 files changed, 132 insertions, 123 deletions
diff --git a/util/qemu-option.c b/util/qemu-option.c index 0ebfd97a98..b9f93a7f8b 100644 --- a/util/qemu-option.c +++ b/util/qemu-option.c @@ -96,7 +96,7 @@ const char *get_opt_value(const char *p, char **value) return offset; } -static void parse_option_bool(const char *name, const char *value, bool *ret, +static bool parse_option_bool(const char *name, const char *value, bool *ret, Error **errp) { if (!strcmp(value, "on")) { @@ -106,10 +106,12 @@ static void parse_option_bool(const char *name, const char *value, bool *ret, } else { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'"); + return false; } + return true; } -static void parse_option_number(const char *name, const char *value, +static bool parse_option_number(const char *name, const char *value, uint64_t *ret, Error **errp) { uint64_t number; @@ -119,13 +121,14 @@ static void parse_option_number(const char *name, const char *value, if (err == -ERANGE) { error_setg(errp, "Value '%s' is too large for parameter '%s'", value, name); - return; + return false; } if (err) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, "a number"); - return; + return false; } *ret = number; + return true; } static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, @@ -142,7 +145,14 @@ static const QemuOptDesc *find_desc_by_name(const QemuOptDesc *desc, return NULL; } -void parse_option_size(const char *name, const char *value, +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; +} + +bool parse_option_size(const char *name, const char *value, uint64_t *ret, Error **errp) { uint64_t size; @@ -152,7 +162,7 @@ void parse_option_size(const char *name, const char *value, if (err == -ERANGE) { error_setg(errp, "Value '%s' is out of range for parameter '%s'", value, name); - return; + return false; } if (err) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, name, @@ -160,9 +170,10 @@ void parse_option_size(const char *name, const char *value, error_append_hint(errp, "Optional suffix k, M, G, T, P or E means" " kilo-, mega-, giga-, tera-, peta-\n" "and exabytes, respectively.\n"); - return; + return false; } *ret = size; + return true; } static const char *opt_type_to_string(enum QemuOptType type) @@ -277,12 +288,10 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name) opt = qemu_opt_find(opts, name); if (!opt) { - const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - return desc->def_value_str; - } + return find_default_by_name(opts, name); } - return opt ? opt->str : NULL; + + return opt->str; } void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name) @@ -311,8 +320,7 @@ const char *qemu_opt_iter_next(QemuOptsIter *iter) char *qemu_opt_get_del(QemuOpts *opts, const char *name) { QemuOpt *opt; - const QemuOptDesc *desc; - char *str = NULL; + char *str; if (opts == NULL) { return NULL; @@ -320,11 +328,7 @@ char *qemu_opt_get_del(QemuOpts *opts, const char *name) opt = qemu_opt_find(opts, name); if (!opt) { - desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - str = g_strdup(desc->def_value_str); - } - return str; + return g_strdup(find_default_by_name(opts, name)); } str = opt->str; opt->str = NULL; @@ -348,6 +352,7 @@ static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name, bool defval, bool del) { QemuOpt *opt; + const char *def_val; bool ret = defval; if (opts == NULL) { @@ -356,9 +361,9 @@ static bool qemu_opt_get_bool_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - parse_option_bool(name, desc->def_value_str, &ret, &error_abort); + def_val = find_default_by_name(opts, name); + if (def_val) { + parse_option_bool(name, def_val, &ret, &error_abort); } return ret; } @@ -384,6 +389,7 @@ static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name, uint64_t defval, bool del) { QemuOpt *opt; + const char *def_val; uint64_t ret = defval; if (opts == NULL) { @@ -392,9 +398,9 @@ static uint64_t qemu_opt_get_number_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - parse_option_number(name, desc->def_value_str, &ret, &error_abort); + def_val = find_default_by_name(opts, name); + if (def_val) { + parse_option_number(name, def_val, &ret, &error_abort); } return ret; } @@ -421,6 +427,7 @@ static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name, uint64_t defval, bool del) { QemuOpt *opt; + const char *def_val; uint64_t ret = defval; if (opts == NULL) { @@ -429,9 +436,9 @@ static uint64_t qemu_opt_get_size_helper(QemuOpts *opts, const char *name, opt = qemu_opt_find(opts, name); if (opt == NULL) { - const QemuOptDesc *desc = find_desc_by_name(opts->list->desc, name); - if (desc && desc->def_value_str) { - parse_option_size(name, desc->def_value_str, &ret, &error_abort); + def_val = find_default_by_name(opts, name); + if (def_val) { + parse_option_size(name, def_val, &ret, &error_abort); } return ret; } @@ -454,24 +461,24 @@ uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name, return qemu_opt_get_size_helper(opts, name, defval, true); } -static void qemu_opt_parse(QemuOpt *opt, Error **errp) +static bool qemu_opt_parse(QemuOpt *opt, Error **errp) { if (opt->desc == NULL) - return; + return true; switch (opt->desc->type) { case QEMU_OPT_STRING: /* nothing */ - return; + return true; case QEMU_OPT_BOOL: - parse_option_bool(opt->name, opt->str, &opt->value.boolean, errp); - break; + return parse_option_bool(opt->name, opt->str, &opt->value.boolean, + errp); case QEMU_OPT_NUMBER: - parse_option_number(opt->name, opt->str, &opt->value.uint, errp); - break; + return parse_option_number(opt->name, opt->str, &opt->value.uint, + errp); case QEMU_OPT_SIZE: - parse_option_size(opt->name, opt->str, &opt->value.uint, errp); - break; + return parse_option_size(opt->name, opt->str, &opt->value.uint, + errp); default: abort(); } @@ -496,86 +503,99 @@ int qemu_opt_unset(QemuOpts *opts, const char *name) } } -static void opt_set(QemuOpts *opts, const char *name, char *value, - bool prepend, bool *help_wanted, Error **errp) +static QemuOpt *opt_create(QemuOpts *opts, const char *name, char *value, + bool prepend) { - QemuOpt *opt; - const QemuOptDesc *desc; - Error *local_err = NULL; + QemuOpt *opt = g_malloc0(sizeof(*opt)); - desc = find_desc_by_name(opts->list->desc, name); - if (!desc && !opts_accepts_any(opts)) { - g_free(value); - error_setg(errp, QERR_INVALID_PARAMETER, name); - if (help_wanted && is_help_option(name)) { - *help_wanted = true; - } - return; - } - - 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; +} + +static bool opt_validate(QemuOpt *opt, bool *help_wanted, + Error **errp) +{ + const QemuOptDesc *desc; + + desc = find_desc_by_name(opt->opts->list->desc, opt->name); + if (!desc && !opts_accepts_any(opt->opts)) { + error_setg(errp, QERR_INVALID_PARAMETER, opt->name); + if (help_wanted && is_help_option(opt->name)) { + *help_wanted = true; + } + return false; + } + opt->desc = desc; - opt->str = value; - qemu_opt_parse(opt, &local_err); - if (local_err) { - error_propagate(errp, local_err); - qemu_opt_del(opt); + if (!qemu_opt_parse(opt, errp)) { + return false; } + + return true; } -void qemu_opt_set(QemuOpts *opts, const char *name, const char *value, +bool qemu_opt_set(QemuOpts *opts, const char *name, const char *value, Error **errp) { - opt_set(opts, name, g_strdup(value), false, NULL, errp); + QemuOpt *opt = opt_create(opts, name, g_strdup(value), false); + + if (!opt_validate(opt, NULL, errp)) { + qemu_opt_del(opt); + return false; + } + return true; } -void qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, +bool qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val, Error **errp) { QemuOpt *opt; - const QemuOptDesc *desc = opts->list->desc; + const QemuOptDesc *desc; - opt = g_malloc0(sizeof(*opt)); - opt->desc = find_desc_by_name(desc, name); - if (!opt->desc && !opts_accepts_any(opts)) { + desc = find_desc_by_name(opts->list->desc, name); + if (!desc && !opts_accepts_any(opts)) { error_setg(errp, QERR_INVALID_PARAMETER, name); - g_free(opt); - return; + return false; } + opt = g_malloc0(sizeof(*opt)); opt->name = g_strdup(name); opt->opts = opts; + opt->desc = desc; opt->value.boolean = !!val; opt->str = g_strdup(val ? "on" : "off"); QTAILQ_INSERT_TAIL(&opts->head, opt, next); + return true; } -void qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, +bool qemu_opt_set_number(QemuOpts *opts, const char *name, int64_t val, Error **errp) { QemuOpt *opt; - const QemuOptDesc *desc = opts->list->desc; + const QemuOptDesc *desc; - opt = g_malloc0(sizeof(*opt)); - opt->desc = find_desc_by_name(desc, name); - if (!opt->desc && !opts_accepts_any(opts)) { + desc = find_desc_by_name(opts->list->desc, name); + if (!desc && !opts_accepts_any(opts)) { error_setg(errp, QERR_INVALID_PARAMETER, name); - g_free(opt); - return; + return false; } + opt = g_malloc0(sizeof(*opt)); opt->name = g_strdup(name); opt->opts = opts; + opt->desc = desc; opt->value.uint = val; opt->str = g_strdup_printf("%" PRId64, val); QTAILQ_INSERT_TAIL(&opts->head, opt, next); + return true; } /** @@ -666,18 +686,16 @@ void qemu_opts_loc_restore(QemuOpts *opts) loc_restore(&opts->loc); } -void qemu_opts_set(QemuOptsList *list, const char *id, +bool qemu_opts_set(QemuOptsList *list, const char *id, const char *name, const char *value, Error **errp) { QemuOpts *opts; - Error *local_err = NULL; - opts = qemu_opts_create(list, id, 1, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + opts = qemu_opts_create(list, id, 1, errp); + if (!opts) { + return false; } - qemu_opt_set(opts, name, value, errp); + return qemu_opt_set(opts, name, value, errp); } const char *qemu_opts_id(QemuOpts *opts) @@ -803,13 +821,13 @@ static const char *get_opt_name_value(const char *params, return p; } -static void opts_do_parse(QemuOpts *opts, const char *params, +static bool opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, bool prepend, bool *help_wanted, Error **errp) { - Error *local_err = NULL; char *option, *value; const char *p; + QemuOpt *opt; for (p = params; *p;) { p = get_opt_name_value(p, firstname, &option, &value); @@ -821,13 +839,15 @@ static void opts_do_parse(QemuOpts *opts, const char *params, continue; } - opt_set(opts, option, value, prepend, help_wanted, &local_err); + opt = opt_create(opts, option, value, prepend); g_free(option); - if (local_err) { - error_propagate(errp, local_err); - return; + if (!opt_validate(opt, help_wanted, errp)) { + qemu_opt_del(opt); + return false; } } + + return true; } static char *opts_parse_id(const char *params) @@ -873,10 +893,10 @@ bool has_help_option(const char *params) * key=, and is treated as if key was @firstname. * On error, store an error object through @errp if non-null. */ -void qemu_opts_do_parse(QemuOpts *opts, const char *params, +bool qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname, Error **errp) { - opts_do_parse(opts, params, firstname, false, NULL, errp); + return opts_do_parse(opts, params, firstname, false, NULL, errp); } static QemuOpts *opts_parse(QemuOptsList *list, const char *params, @@ -886,7 +906,6 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, const char *firstname; char *id = opts_parse_id(params); QemuOpts *opts; - Error *local_err = NULL; assert(!permit_abbrev || list->implied_opt_name); firstname = permit_abbrev ? list->implied_opt_name : NULL; @@ -899,16 +918,14 @@ static QemuOpts *opts_parse(QemuOptsList *list, const char *params, * (if unlikely) future misuse: */ assert(!defaults || list->merge_lists); - opts = qemu_opts_create(list, id, !defaults, &local_err); + opts = qemu_opts_create(list, id, !defaults, errp); g_free(id); if (opts == NULL) { - error_propagate(errp, local_err); return NULL; } - opts_do_parse(opts, params, firstname, defaults, help_wanted, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!opts_do_parse(opts, params, firstname, defaults, help_wanted, + errp)) { qemu_opts_del(opts); return NULL; } @@ -965,17 +982,18 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params, assert(opts); } -static void qemu_opts_from_qdict_entry(QemuOpts *opts, +static bool qemu_opts_from_qdict_entry(QemuOpts *opts, const QDictEntry *entry, Error **errp) { const char *key = qdict_entry_key(entry); QObject *obj = qdict_entry_value(entry); - char buf[32], *tmp = NULL; + char buf[32]; + g_autofree char *tmp = NULL; const char *value; if (!strcmp(key, "id")) { - return; + return true; } switch (qobject_type(obj)) { @@ -992,11 +1010,10 @@ static void qemu_opts_from_qdict_entry(QemuOpts *opts, value = buf; break; default: - return; + return true; } - qemu_opt_set(opts, key, value, errp); - g_free(tmp); + return qemu_opt_set(opts, key, value, errp); } /* @@ -1008,14 +1025,11 @@ static void qemu_opts_from_qdict_entry(QemuOpts *opts, QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, Error **errp) { - Error *local_err = NULL; QemuOpts *opts; const QDictEntry *entry; - opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, - &local_err); - if (local_err) { - error_propagate(errp, local_err); + opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1, errp); + if (!opts) { return NULL; } @@ -1024,9 +1038,7 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, for (entry = qdict_first(qdict); entry; entry = qdict_next(qdict, entry)) { - qemu_opts_from_qdict_entry(opts, entry, &local_err); - if (local_err) { - error_propagate(errp, local_err); + if (!qemu_opts_from_qdict_entry(opts, entry, errp)) { qemu_opts_del(opts); return NULL; } @@ -1040,28 +1052,26 @@ QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict, * from the QDict. When this function returns, the QDict contains only those * entries that couldn't be added to the QemuOpts. */ -void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) +bool qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp) { const QDictEntry *entry, *next; entry = qdict_first(qdict); while (entry != NULL) { - Error *local_err = NULL; - next = qdict_next(qdict, entry); if (find_desc_by_name(opts->list->desc, entry->key)) { - qemu_opts_from_qdict_entry(opts, entry, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + if (!qemu_opts_from_qdict_entry(opts, entry, errp)) { + return false; } qdict_del(qdict, entry->key); } entry = next; } + + return true; } /* @@ -1121,10 +1131,9 @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict) /* Validate parsed opts against descriptions where no * descriptions were provided in the QemuOptsList. */ -void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) +bool qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) { QemuOpt *opt; - Error *local_err = NULL; assert(opts_accepts_any(opts)); @@ -1132,15 +1141,15 @@ void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error **errp) opt->desc = find_desc_by_name(desc, opt->name); if (!opt->desc) { error_setg(errp, QERR_INVALID_PARAMETER, opt->name); - return; + return false; } - qemu_opt_parse(opt, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + if (!qemu_opt_parse(opt, errp)) { + return false; } } + + return true; } /** |