Skip to content

Commit

Permalink
qemu-option: Add qemu_config_parse_qdict()
Browse files Browse the repository at this point in the history
This function basically parses command-line options given as a QDict
replacing a config file.

For instance, the QDict {"section.opt1": 42, "section.opt2": 23}
corresponds to the config file:

[section]
opt1 = 42
opt2 = 23

It is possible to specify multiple sections and also multiple sections
of the same type. On the command line, this looks like the following:

inject-error.0.event=reftable_load,\
inject-error.1.event=l2_load,\
set-state.event=l1_update

This would correspond to the following config file:

[inject-error "inject-error.0"]
event = reftable_load

[inject-error "inject-error.1"]
event = l2_load

[set-state]
event = l1_update

Signed-off-by: Max Reitz <mreitz@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
  • Loading branch information
XanClic authored and kevmw committed Jan 22, 2014
1 parent 9f23fc0 commit adf5c44
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
6 changes: 6 additions & 0 deletions include/qemu/config-file.h
Expand Up @@ -4,6 +4,7 @@
#include <stdio.h>
#include "qemu/option.h"
#include "qapi/error.h"
#include "qapi/qmp/qdict.h"

QemuOptsList *qemu_find_opts(const char *group);
QemuOptsList *qemu_find_opts_err(const char *group, Error **errp);
Expand All @@ -18,6 +19,11 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname);

int qemu_read_config_file(const char *filename);

/* Parse QDict options as a replacement for a config file (allowing multiple
enumerated (0..(n-1)) configuration "sections") */
void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
Error **errp);

/* Read default QEMU config files
*/
int qemu_read_default_config_files(bool userconfig);
Expand Down
100 changes: 100 additions & 0 deletions util/qemu-config.c
Expand Up @@ -356,3 +356,103 @@ int qemu_read_config_file(const char *filename)
return -EINVAL;
}
}

static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
Error **errp)
{
QemuOpts *subopts;
QDict *subqdict;
QList *list = NULL;
Error *local_err = NULL;
size_t orig_size, enum_size;
char *prefix;

prefix = g_strdup_printf("%s.", opts->name);
qdict_extract_subqdict(options, &subqdict, prefix);
g_free(prefix);
orig_size = qdict_size(subqdict);
if (!orig_size) {
goto out;
}

subopts = qemu_opts_create(opts, NULL, 0, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
goto out;
}

qemu_opts_absorb_qdict(subopts, subqdict, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
goto out;
}

enum_size = qdict_size(subqdict);
if (enum_size < orig_size && enum_size) {
error_setg(errp, "Unknown option '%s' for [%s]",
qdict_first(subqdict)->key, opts->name);
goto out;
}

if (enum_size) {
/* Multiple, enumerated sections */
QListEntry *list_entry;
unsigned i = 0;

/* Not required anymore */
qemu_opts_del(subopts);

qdict_array_split(subqdict, &list);
if (qdict_size(subqdict)) {
error_setg(errp, "Unused option '%s' for [%s]",
qdict_first(subqdict)->key, opts->name);
goto out;
}

QLIST_FOREACH_ENTRY(list, list_entry) {
QDict *section = qobject_to_qdict(qlist_entry_obj(list_entry));
char *opt_name;

opt_name = g_strdup_printf("%s.%u", opts->name, i++);
subopts = qemu_opts_create(opts, opt_name, 1, &local_err);
g_free(opt_name);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
goto out;
}

qemu_opts_absorb_qdict(subopts, section, &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
qemu_opts_del(subopts);
goto out;
}

if (qdict_size(section)) {
error_setg(errp, "[%s] section doesn't support the option '%s'",
opts->name, qdict_first(section)->key);
qemu_opts_del(subopts);
goto out;
}
}
}

out:
QDECREF(subqdict);
QDECREF(list);
}

void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
Error **errp)
{
int i;
Error *local_err = NULL;

for (i = 0; lists[i]; i++) {
config_parse_qdict_section(options, lists[i], &local_err);
if (error_is_set(&local_err)) {
error_propagate(errp, local_err);
return;
}
}
}

0 comments on commit adf5c44

Please sign in to comment.