aboutsummaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2021-05-24 06:57:50 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2021-06-04 13:50:01 +0200
commit37701411397c7b7d709ae92abd347cc593940ee5 (patch)
treead45f77b74441f22488143ba90236e207ed70c38 /util
parent4db4385a7ab6512e9af08305f5725b26c8a980ee (diff)
qemu-config: parse configuration files to a QDict
Change the parser to put the values into a QDict and pass them to a callback. qemu_config_parse's QemuOpts creation is itself turned into a callback function. This is useful for -readconfig to support keyval-based options; getting a QDict from the parser removes a roundtrip from QDict to QemuOpts and then back to QDict. Unfortunately there is a disadvantage in that semantic errors will point to the last line of the group, because the entries of the QDict do not have a location attached. Cc: Kevin Wolf <kwolf@redhat.com> Cc: Markus Armbruster <armbru@redhat.com> Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20210524105752.3318299-2-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'util')
-rw-r--r--util/qemu-config.c98
1 files changed, 68 insertions, 30 deletions
diff --git a/util/qemu-config.c b/util/qemu-config.c
index 34974c4b47..374f3bc460 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -2,6 +2,7 @@
#include "block/qdict.h" /* for qdict_extract_subqdict() */
#include "qapi/error.h"
#include "qapi/qapi-commands-misc.h"
+#include "qapi/qmp/qerror.h"
#include "qapi/qmp/qdict.h"
#include "qapi/qmp/qlist.h"
#include "qemu/error-report.h"
@@ -351,19 +352,19 @@ void qemu_config_write(FILE *fp)
}
/* Returns number of config groups on success, -errno on error */
-int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
+static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque,
+ const char *fname, Error **errp)
{
- char line[1024], group[64], id[64], arg[64], value[1024];
+ char line[1024], prev_group[64], group[64], arg[64], value[1024];
Location loc;
- QemuOptsList *list = NULL;
Error *local_err = NULL;
- QemuOpts *opts = NULL;
+ QDict *qdict = NULL;
int res = -EINVAL, lno = 0;
int count = 0;
loc_push_none(&loc);
while (fgets(line, sizeof(line), fp) != NULL) {
- loc_set_file(fname, ++lno);
+ ++lno;
if (line[0] == '\n') {
/* skip empty lines */
continue;
@@ -372,39 +373,39 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error *
/* comment */
continue;
}
- if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
- /* group with id */
- list = find_list(lists, group, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
+ if (line[0] == '[') {
+ QDict *prev = qdict;
+ if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) {
+ qdict = qdict_new();
+ qdict_put_str(qdict, "id", value);
+ count++;
+ } else if (sscanf(line, "[%63[^]]]", group) == 1) {
+ qdict = qdict_new();
+ count++;
}
- opts = qemu_opts_create(list, id, 1, NULL);
- count++;
- continue;
- }
- if (sscanf(line, "[%63[^]]]", group) == 1) {
- /* group without id */
- list = find_list(lists, group, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- goto out;
+ if (qdict != prev) {
+ if (prev) {
+ cb(prev_group, prev, opaque, &local_err);
+ qobject_unref(prev);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto out;
+ }
+ }
+ strcpy(prev_group, group);
+ continue;
}
- opts = qemu_opts_create(list, NULL, 0, &error_abort);
- count++;
- continue;
}
+ loc_set_file(fname, lno);
value[0] = '\0';
if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
sscanf(line, " %63s = \"\"", arg) == 1) {
/* arg = value */
- if (opts == NULL) {
+ if (qdict == NULL) {
error_setg(errp, "no group defined");
goto out;
}
- if (!qemu_opt_set(opts, arg, value, errp)) {
- goto out;
- }
+ qdict_put_str(qdict, arg, value);
continue;
}
error_setg(errp, "parse error");
@@ -417,11 +418,48 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error *
}
res = count;
out:
+ if (qdict) {
+ cb(group, qdict, opaque, errp);
+ qobject_unref(qdict);
+ }
loc_pop(&loc);
return res;
}
-int qemu_read_config_file(const char *filename, Error **errp)
+void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp)
+{
+ QemuOptsList **lists = opaque;
+ const char *id = qdict_get_try_str(qdict, "id");
+ QemuOptsList *list;
+ QemuOpts *opts;
+ const QDictEntry *unrecognized;
+
+ list = find_list(lists, group, errp);
+ if (!list) {
+ return;
+ }
+
+ opts = qemu_opts_create(list, id, 1, errp);
+ if (!opts) {
+ return;
+ }
+ if (!qemu_opts_absorb_qdict(opts, qdict, errp)) {
+ qemu_opts_del(opts);
+ return;
+ }
+ unrecognized = qdict_first(qdict);
+ if (unrecognized) {
+ error_setg(errp, QERR_INVALID_PARAMETER, unrecognized->key);
+ qemu_opts_del(opts);
+ }
+}
+
+int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
+{
+ return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp);
+}
+
+int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp)
{
FILE *f = fopen(filename, "r");
int ret;
@@ -431,7 +469,7 @@ int qemu_read_config_file(const char *filename, Error **errp)
return -errno;
}
- ret = qemu_config_parse(f, vm_config_groups, filename, errp);
+ ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp);
fclose(f);
return ret;
}