xref: /qemu/util/qemu-config.c (revision f43e47dbf6de24db20ec9b588bb6cc762093dd69)
17282a033SGerd Hoffmann #include "qemu-common.h"
21de7afc9SPaolo Bonzini #include "qemu/error-report.h"
31de7afc9SPaolo Bonzini #include "qemu/option.h"
41de7afc9SPaolo Bonzini #include "qemu/config-file.h"
5b4a42f81SPaolo Bonzini #include "qapi/qmp/qerror.h"
6d0fef6fbSGerd Hoffmann #include "hw/qdev.h"
77b1b5d19SPaolo Bonzini #include "qapi/error.h"
81f8f987dSAmos Kong #include "qmp-commands.h"
97282a033SGerd Hoffmann 
104d454574SPaolo Bonzini static QemuOptsList *vm_config_groups[32];
11968854c8SAmos Kong static QemuOptsList *drive_config_groups[4];
12d058fe03SGerd Hoffmann 
132ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
142ac20613SLuiz Capitulino                                Error **errp)
15d058fe03SGerd Hoffmann {
16ddc97855SGerd Hoffmann     int i;
17d058fe03SGerd Hoffmann 
18d058fe03SGerd Hoffmann     for (i = 0; lists[i] != NULL; i++) {
19d058fe03SGerd Hoffmann         if (strcmp(lists[i]->name, group) == 0)
20d058fe03SGerd Hoffmann             break;
21d058fe03SGerd Hoffmann     }
22d058fe03SGerd Hoffmann     if (lists[i] == NULL) {
23f231b88dSCole Robinson         error_setg(errp, "There is no option group '%s'", group);
24ddc97855SGerd Hoffmann     }
25ddc97855SGerd Hoffmann     return lists[i];
26ddc97855SGerd Hoffmann }
27ddc97855SGerd Hoffmann 
28490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group)
29490b648eSKevin Wolf {
302ac20613SLuiz Capitulino     QemuOptsList *ret;
312ac20613SLuiz Capitulino     Error *local_err = NULL;
322ac20613SLuiz Capitulino 
332ac20613SLuiz Capitulino     ret = find_list(vm_config_groups, group, &local_err);
3484d18f06SMarkus Armbruster     if (local_err) {
35565f65d2SMarkus Armbruster         error_report_err(local_err);
362ac20613SLuiz Capitulino     }
372ac20613SLuiz Capitulino 
382ac20613SLuiz Capitulino     return ret;
39490b648eSKevin Wolf }
40490b648eSKevin Wolf 
41e96e5ae8SPaolo Bonzini QemuOpts *qemu_find_opts_singleton(const char *group)
42e96e5ae8SPaolo Bonzini {
43e96e5ae8SPaolo Bonzini     QemuOptsList *list;
44e96e5ae8SPaolo Bonzini     QemuOpts *opts;
45e96e5ae8SPaolo Bonzini 
46e96e5ae8SPaolo Bonzini     list = qemu_find_opts(group);
47e96e5ae8SPaolo Bonzini     assert(list);
48e96e5ae8SPaolo Bonzini     opts = qemu_opts_find(list, NULL);
49e96e5ae8SPaolo Bonzini     if (!opts) {
50e96e5ae8SPaolo Bonzini         opts = qemu_opts_create(list, NULL, 0, &error_abort);
51e96e5ae8SPaolo Bonzini     }
52e96e5ae8SPaolo Bonzini     return opts;
53e96e5ae8SPaolo Bonzini }
54e96e5ae8SPaolo Bonzini 
551f8f987dSAmos Kong static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
561f8f987dSAmos Kong {
571f8f987dSAmos Kong     CommandLineParameterInfoList *param_list = NULL, *entry;
581f8f987dSAmos Kong     CommandLineParameterInfo *info;
591f8f987dSAmos Kong     int i;
601f8f987dSAmos Kong 
611f8f987dSAmos Kong     for (i = 0; desc[i].name != NULL; i++) {
621f8f987dSAmos Kong         info = g_malloc0(sizeof(*info));
631f8f987dSAmos Kong         info->name = g_strdup(desc[i].name);
641f8f987dSAmos Kong 
651f8f987dSAmos Kong         switch (desc[i].type) {
661f8f987dSAmos Kong         case QEMU_OPT_STRING:
671f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
681f8f987dSAmos Kong             break;
691f8f987dSAmos Kong         case QEMU_OPT_BOOL:
701f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
711f8f987dSAmos Kong             break;
721f8f987dSAmos Kong         case QEMU_OPT_NUMBER:
731f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
741f8f987dSAmos Kong             break;
751f8f987dSAmos Kong         case QEMU_OPT_SIZE:
761f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
771f8f987dSAmos Kong             break;
781f8f987dSAmos Kong         }
791f8f987dSAmos Kong 
801f8f987dSAmos Kong         if (desc[i].help) {
811f8f987dSAmos Kong             info->has_help = true;
821f8f987dSAmos Kong             info->help = g_strdup(desc[i].help);
831f8f987dSAmos Kong         }
84e36af94fSChunyan Liu         if (desc[i].def_value_str) {
85e36af94fSChunyan Liu             info->has_q_default = true;
86e36af94fSChunyan Liu             info->q_default = g_strdup(desc[i].def_value_str);
87e36af94fSChunyan Liu         }
881f8f987dSAmos Kong 
891f8f987dSAmos Kong         entry = g_malloc0(sizeof(*entry));
901f8f987dSAmos Kong         entry->value = info;
911f8f987dSAmos Kong         entry->next = param_list;
921f8f987dSAmos Kong         param_list = entry;
931f8f987dSAmos Kong     }
941f8f987dSAmos Kong 
951f8f987dSAmos Kong     return param_list;
961f8f987dSAmos Kong }
971f8f987dSAmos Kong 
98968854c8SAmos Kong /* remove repeated entry from the info list */
99968854c8SAmos Kong static void cleanup_infolist(CommandLineParameterInfoList *head)
100968854c8SAmos Kong {
101968854c8SAmos Kong     CommandLineParameterInfoList *pre_entry, *cur, *del_entry;
102968854c8SAmos Kong 
103968854c8SAmos Kong     cur = head;
104968854c8SAmos Kong     while (cur->next) {
105968854c8SAmos Kong         pre_entry = head;
106968854c8SAmos Kong         while (pre_entry != cur->next) {
107968854c8SAmos Kong             if (!strcmp(pre_entry->value->name, cur->next->value->name)) {
108968854c8SAmos Kong                 del_entry = cur->next;
109968854c8SAmos Kong                 cur->next = cur->next->next;
110968854c8SAmos Kong                 g_free(del_entry);
111968854c8SAmos Kong                 break;
112968854c8SAmos Kong             }
113968854c8SAmos Kong             pre_entry = pre_entry->next;
114968854c8SAmos Kong         }
115968854c8SAmos Kong         cur = cur->next;
116968854c8SAmos Kong     }
117968854c8SAmos Kong }
118968854c8SAmos Kong 
119968854c8SAmos Kong /* merge the description items of two parameter infolists */
120968854c8SAmos Kong static void connect_infolist(CommandLineParameterInfoList *head,
121968854c8SAmos Kong                              CommandLineParameterInfoList *new)
122968854c8SAmos Kong {
123968854c8SAmos Kong     CommandLineParameterInfoList *cur;
124968854c8SAmos Kong 
125968854c8SAmos Kong     cur = head;
126968854c8SAmos Kong     while (cur->next) {
127968854c8SAmos Kong         cur = cur->next;
128968854c8SAmos Kong     }
129968854c8SAmos Kong     cur->next = new;
130968854c8SAmos Kong }
131968854c8SAmos Kong 
132968854c8SAmos Kong /* access all the local QemuOptsLists for drive option */
133968854c8SAmos Kong static CommandLineParameterInfoList *get_drive_infolist(void)
134968854c8SAmos Kong {
135968854c8SAmos Kong     CommandLineParameterInfoList *head = NULL, *cur;
136968854c8SAmos Kong     int i;
137968854c8SAmos Kong 
138968854c8SAmos Kong     for (i = 0; drive_config_groups[i] != NULL; i++) {
139968854c8SAmos Kong         if (!head) {
140968854c8SAmos Kong             head = query_option_descs(drive_config_groups[i]->desc);
141968854c8SAmos Kong         } else {
142968854c8SAmos Kong             cur = query_option_descs(drive_config_groups[i]->desc);
143968854c8SAmos Kong             connect_infolist(head, cur);
144968854c8SAmos Kong         }
145968854c8SAmos Kong     }
146968854c8SAmos Kong     cleanup_infolist(head);
147968854c8SAmos Kong 
148968854c8SAmos Kong     return head;
149968854c8SAmos Kong }
150968854c8SAmos Kong 
1511f8f987dSAmos Kong CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
1521f8f987dSAmos Kong                                                           const char *option,
1531f8f987dSAmos Kong                                                           Error **errp)
1541f8f987dSAmos Kong {
1551f8f987dSAmos Kong     CommandLineOptionInfoList *conf_list = NULL, *entry;
1561f8f987dSAmos Kong     CommandLineOptionInfo *info;
1571f8f987dSAmos Kong     int i;
1581f8f987dSAmos Kong 
1591f8f987dSAmos Kong     for (i = 0; vm_config_groups[i] != NULL; i++) {
1601f8f987dSAmos Kong         if (!has_option || !strcmp(option, vm_config_groups[i]->name)) {
1611f8f987dSAmos Kong             info = g_malloc0(sizeof(*info));
1621f8f987dSAmos Kong             info->option = g_strdup(vm_config_groups[i]->name);
163968854c8SAmos Kong             if (!strcmp("drive", vm_config_groups[i]->name)) {
164968854c8SAmos Kong                 info->parameters = get_drive_infolist();
165968854c8SAmos Kong             } else {
166968854c8SAmos Kong                 info->parameters =
167968854c8SAmos Kong                     query_option_descs(vm_config_groups[i]->desc);
168968854c8SAmos Kong             }
1691f8f987dSAmos Kong             entry = g_malloc0(sizeof(*entry));
1701f8f987dSAmos Kong             entry->value = info;
1711f8f987dSAmos Kong             entry->next = conf_list;
1721f8f987dSAmos Kong             conf_list = entry;
1731f8f987dSAmos Kong         }
1741f8f987dSAmos Kong     }
1751f8f987dSAmos Kong 
1761f8f987dSAmos Kong     if (conf_list == NULL) {
1771f8f987dSAmos Kong         error_setg(errp, "invalid option name: %s", option);
1781f8f987dSAmos Kong     }
1791f8f987dSAmos Kong 
1801f8f987dSAmos Kong     return conf_list;
1811f8f987dSAmos Kong }
1821f8f987dSAmos Kong 
18360d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
18460d5666fSLuiz Capitulino {
18560d5666fSLuiz Capitulino     return find_list(vm_config_groups, group, errp);
18660d5666fSLuiz Capitulino }
18760d5666fSLuiz Capitulino 
188968854c8SAmos Kong void qemu_add_drive_opts(QemuOptsList *list)
189968854c8SAmos Kong {
190968854c8SAmos Kong     int entries, i;
191968854c8SAmos Kong 
192968854c8SAmos Kong     entries = ARRAY_SIZE(drive_config_groups);
193968854c8SAmos Kong     entries--; /* keep list NULL terminated */
194968854c8SAmos Kong     for (i = 0; i < entries; i++) {
195968854c8SAmos Kong         if (drive_config_groups[i] == NULL) {
196968854c8SAmos Kong             drive_config_groups[i] = list;
197968854c8SAmos Kong             return;
198968854c8SAmos Kong         }
199968854c8SAmos Kong     }
200968854c8SAmos Kong     fprintf(stderr, "ran out of space in drive_config_groups");
201968854c8SAmos Kong     abort();
202968854c8SAmos Kong }
203968854c8SAmos Kong 
204dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list)
205dfe795e7SGerd Hoffmann {
206dfe795e7SGerd Hoffmann     int entries, i;
207dfe795e7SGerd Hoffmann 
208dfe795e7SGerd Hoffmann     entries = ARRAY_SIZE(vm_config_groups);
209dfe795e7SGerd Hoffmann     entries--; /* keep list NULL terminated */
210dfe795e7SGerd Hoffmann     for (i = 0; i < entries; i++) {
211dfe795e7SGerd Hoffmann         if (vm_config_groups[i] == NULL) {
212dfe795e7SGerd Hoffmann             vm_config_groups[i] = list;
213dfe795e7SGerd Hoffmann             return;
214dfe795e7SGerd Hoffmann         }
215dfe795e7SGerd Hoffmann     }
216dfe795e7SGerd Hoffmann     fprintf(stderr, "ran out of space in vm_config_groups");
217dfe795e7SGerd Hoffmann     abort();
218dfe795e7SGerd Hoffmann }
219dfe795e7SGerd Hoffmann 
220ddc97855SGerd Hoffmann int qemu_set_option(const char *str)
221ddc97855SGerd Hoffmann {
222*f43e47dbSMarkus Armbruster     Error *local_err = NULL;
223ddc97855SGerd Hoffmann     char group[64], id[64], arg[64];
224ddc97855SGerd Hoffmann     QemuOptsList *list;
225ddc97855SGerd Hoffmann     QemuOpts *opts;
226ddc97855SGerd Hoffmann     int rc, offset;
227ddc97855SGerd Hoffmann 
228ddc97855SGerd Hoffmann     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
229ddc97855SGerd Hoffmann     if (rc < 3 || str[offset] != '=') {
2301ecda02bSMarkus Armbruster         error_report("can't parse: \"%s\"", str);
231d058fe03SGerd Hoffmann         return -1;
232d058fe03SGerd Hoffmann     }
233d058fe03SGerd Hoffmann 
234304329eeSMarkus Armbruster     list = qemu_find_opts(group);
235ddc97855SGerd Hoffmann     if (list == NULL) {
236ddc97855SGerd Hoffmann         return -1;
237ddc97855SGerd Hoffmann     }
238ddc97855SGerd Hoffmann 
239ddc97855SGerd Hoffmann     opts = qemu_opts_find(list, id);
240d058fe03SGerd Hoffmann     if (!opts) {
2411ecda02bSMarkus Armbruster         error_report("there is no %s \"%s\" defined",
242ddc97855SGerd Hoffmann                      list->name, id);
243d058fe03SGerd Hoffmann         return -1;
244d058fe03SGerd Hoffmann     }
245d058fe03SGerd Hoffmann 
246*f43e47dbSMarkus Armbruster     qemu_opt_set(opts, arg, str + offset + 1, &local_err);
247*f43e47dbSMarkus Armbruster     if (local_err) {
248*f43e47dbSMarkus Armbruster         error_report_err(local_err);
249d058fe03SGerd Hoffmann         return -1;
250d058fe03SGerd Hoffmann     }
251d058fe03SGerd Hoffmann     return 0;
252d058fe03SGerd Hoffmann }
253d058fe03SGerd Hoffmann 
2549d993394SGerd Hoffmann struct ConfigWriteData {
2559d993394SGerd Hoffmann     QemuOptsList *list;
2569d993394SGerd Hoffmann     FILE *fp;
2579d993394SGerd Hoffmann };
2589d993394SGerd Hoffmann 
2599d993394SGerd Hoffmann static int config_write_opt(const char *name, const char *value, void *opaque)
2609d993394SGerd Hoffmann {
2619d993394SGerd Hoffmann     struct ConfigWriteData *data = opaque;
2629d993394SGerd Hoffmann 
2639d993394SGerd Hoffmann     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
2649d993394SGerd Hoffmann     return 0;
2659d993394SGerd Hoffmann }
2669d993394SGerd Hoffmann 
2679d993394SGerd Hoffmann static int config_write_opts(QemuOpts *opts, void *opaque)
2689d993394SGerd Hoffmann {
2699d993394SGerd Hoffmann     struct ConfigWriteData *data = opaque;
2709d993394SGerd Hoffmann     const char *id = qemu_opts_id(opts);
2719d993394SGerd Hoffmann 
2729d993394SGerd Hoffmann     if (id) {
2739d993394SGerd Hoffmann         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
2749d993394SGerd Hoffmann     } else {
2759d993394SGerd Hoffmann         fprintf(data->fp, "[%s]\n", data->list->name);
2769d993394SGerd Hoffmann     }
2779d993394SGerd Hoffmann     qemu_opt_foreach(opts, config_write_opt, data, 0);
2789d993394SGerd Hoffmann     fprintf(data->fp, "\n");
2799d993394SGerd Hoffmann     return 0;
2809d993394SGerd Hoffmann }
2819d993394SGerd Hoffmann 
2829d993394SGerd Hoffmann void qemu_config_write(FILE *fp)
2839d993394SGerd Hoffmann {
2849d993394SGerd Hoffmann     struct ConfigWriteData data = { .fp = fp };
285490b648eSKevin Wolf     QemuOptsList **lists = vm_config_groups;
2869d993394SGerd Hoffmann     int i;
2879d993394SGerd Hoffmann 
2889d993394SGerd Hoffmann     fprintf(fp, "# qemu config file\n\n");
2899d993394SGerd Hoffmann     for (i = 0; lists[i] != NULL; i++) {
2909d993394SGerd Hoffmann         data.list = lists[i];
2919d993394SGerd Hoffmann         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
2929d993394SGerd Hoffmann     }
2939d993394SGerd Hoffmann }
29442262ba8SGerd Hoffmann 
295490b648eSKevin Wolf int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
29642262ba8SGerd Hoffmann {
29742262ba8SGerd Hoffmann     char line[1024], group[64], id[64], arg[64], value[1024];
298cf5a65aaSMarkus Armbruster     Location loc;
29942262ba8SGerd Hoffmann     QemuOptsList *list = NULL;
3002ac20613SLuiz Capitulino     Error *local_err = NULL;
30142262ba8SGerd Hoffmann     QemuOpts *opts = NULL;
302cf5a65aaSMarkus Armbruster     int res = -1, lno = 0;
30342262ba8SGerd Hoffmann 
304cf5a65aaSMarkus Armbruster     loc_push_none(&loc);
30542262ba8SGerd Hoffmann     while (fgets(line, sizeof(line), fp) != NULL) {
306cf5a65aaSMarkus Armbruster         loc_set_file(fname, ++lno);
30742262ba8SGerd Hoffmann         if (line[0] == '\n') {
30842262ba8SGerd Hoffmann             /* skip empty lines */
30942262ba8SGerd Hoffmann             continue;
31042262ba8SGerd Hoffmann         }
31142262ba8SGerd Hoffmann         if (line[0] == '#') {
31242262ba8SGerd Hoffmann             /* comment */
31342262ba8SGerd Hoffmann             continue;
31442262ba8SGerd Hoffmann         }
31542262ba8SGerd Hoffmann         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
31642262ba8SGerd Hoffmann             /* group with id */
3172ac20613SLuiz Capitulino             list = find_list(lists, group, &local_err);
31884d18f06SMarkus Armbruster             if (local_err) {
319565f65d2SMarkus Armbruster                 error_report_err(local_err);
320cf5a65aaSMarkus Armbruster                 goto out;
3212ac20613SLuiz Capitulino             }
3228be7e7e4SLuiz Capitulino             opts = qemu_opts_create(list, id, 1, NULL);
32342262ba8SGerd Hoffmann             continue;
32442262ba8SGerd Hoffmann         }
32542262ba8SGerd Hoffmann         if (sscanf(line, "[%63[^]]]", group) == 1) {
32642262ba8SGerd Hoffmann             /* group without id */
3272ac20613SLuiz Capitulino             list = find_list(lists, group, &local_err);
32884d18f06SMarkus Armbruster             if (local_err) {
329565f65d2SMarkus Armbruster                 error_report_err(local_err);
330cf5a65aaSMarkus Armbruster                 goto out;
3312ac20613SLuiz Capitulino             }
33287ea75d5SPeter Crosthwaite             opts = qemu_opts_create(list, NULL, 0, &error_abort);
33342262ba8SGerd Hoffmann             continue;
33442262ba8SGerd Hoffmann         }
33542262ba8SGerd Hoffmann         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
33642262ba8SGerd Hoffmann             /* arg = value */
33742262ba8SGerd Hoffmann             if (opts == NULL) {
338cf5a65aaSMarkus Armbruster                 error_report("no group defined");
339cf5a65aaSMarkus Armbruster                 goto out;
34042262ba8SGerd Hoffmann             }
341*f43e47dbSMarkus Armbruster             qemu_opt_set(opts, arg, value, &local_err);
342*f43e47dbSMarkus Armbruster             if (local_err) {
343*f43e47dbSMarkus Armbruster                 error_report_err(local_err);
344cf5a65aaSMarkus Armbruster                 goto out;
34542262ba8SGerd Hoffmann             }
34642262ba8SGerd Hoffmann             continue;
34742262ba8SGerd Hoffmann         }
348cf5a65aaSMarkus Armbruster         error_report("parse error");
349cf5a65aaSMarkus Armbruster         goto out;
35042262ba8SGerd Hoffmann     }
351ef82516dSMarkus Armbruster     if (ferror(fp)) {
352ef82516dSMarkus Armbruster         error_report("error reading file");
353ef82516dSMarkus Armbruster         goto out;
354ef82516dSMarkus Armbruster     }
355cf5a65aaSMarkus Armbruster     res = 0;
356cf5a65aaSMarkus Armbruster out:
357cf5a65aaSMarkus Armbruster     loc_pop(&loc);
358cf5a65aaSMarkus Armbruster     return res;
35942262ba8SGerd Hoffmann }
360dcfb0939SKevin Wolf 
361dcfb0939SKevin Wolf int qemu_read_config_file(const char *filename)
362dcfb0939SKevin Wolf {
363dcfb0939SKevin Wolf     FILE *f = fopen(filename, "r");
364019e78baSKevin Wolf     int ret;
365019e78baSKevin Wolf 
366dcfb0939SKevin Wolf     if (f == NULL) {
367dcfb0939SKevin Wolf         return -errno;
368dcfb0939SKevin Wolf     }
369dcfb0939SKevin Wolf 
370019e78baSKevin Wolf     ret = qemu_config_parse(f, vm_config_groups, filename);
371dcfb0939SKevin Wolf     fclose(f);
372dcfb0939SKevin Wolf 
373019e78baSKevin Wolf     if (ret == 0) {
374dcfb0939SKevin Wolf         return 0;
375019e78baSKevin Wolf     } else {
376019e78baSKevin Wolf         return -EINVAL;
377019e78baSKevin Wolf     }
378dcfb0939SKevin Wolf }
379adf5c449SMax Reitz 
380adf5c449SMax Reitz static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
381adf5c449SMax Reitz                                        Error **errp)
382adf5c449SMax Reitz {
383adf5c449SMax Reitz     QemuOpts *subopts;
384adf5c449SMax Reitz     QDict *subqdict;
385adf5c449SMax Reitz     QList *list = NULL;
386adf5c449SMax Reitz     Error *local_err = NULL;
387adf5c449SMax Reitz     size_t orig_size, enum_size;
388adf5c449SMax Reitz     char *prefix;
389adf5c449SMax Reitz 
390adf5c449SMax Reitz     prefix = g_strdup_printf("%s.", opts->name);
391adf5c449SMax Reitz     qdict_extract_subqdict(options, &subqdict, prefix);
392adf5c449SMax Reitz     g_free(prefix);
393adf5c449SMax Reitz     orig_size = qdict_size(subqdict);
394adf5c449SMax Reitz     if (!orig_size) {
395adf5c449SMax Reitz         goto out;
396adf5c449SMax Reitz     }
397adf5c449SMax Reitz 
398adf5c449SMax Reitz     subopts = qemu_opts_create(opts, NULL, 0, &local_err);
39984d18f06SMarkus Armbruster     if (local_err) {
400adf5c449SMax Reitz         error_propagate(errp, local_err);
401adf5c449SMax Reitz         goto out;
402adf5c449SMax Reitz     }
403adf5c449SMax Reitz 
404adf5c449SMax Reitz     qemu_opts_absorb_qdict(subopts, subqdict, &local_err);
40584d18f06SMarkus Armbruster     if (local_err) {
406adf5c449SMax Reitz         error_propagate(errp, local_err);
407adf5c449SMax Reitz         goto out;
408adf5c449SMax Reitz     }
409adf5c449SMax Reitz 
410adf5c449SMax Reitz     enum_size = qdict_size(subqdict);
411adf5c449SMax Reitz     if (enum_size < orig_size && enum_size) {
412adf5c449SMax Reitz         error_setg(errp, "Unknown option '%s' for [%s]",
413adf5c449SMax Reitz                    qdict_first(subqdict)->key, opts->name);
414adf5c449SMax Reitz         goto out;
415adf5c449SMax Reitz     }
416adf5c449SMax Reitz 
417adf5c449SMax Reitz     if (enum_size) {
418adf5c449SMax Reitz         /* Multiple, enumerated sections */
419adf5c449SMax Reitz         QListEntry *list_entry;
420adf5c449SMax Reitz         unsigned i = 0;
421adf5c449SMax Reitz 
422adf5c449SMax Reitz         /* Not required anymore */
423adf5c449SMax Reitz         qemu_opts_del(subopts);
424adf5c449SMax Reitz 
425adf5c449SMax Reitz         qdict_array_split(subqdict, &list);
426adf5c449SMax Reitz         if (qdict_size(subqdict)) {
427adf5c449SMax Reitz             error_setg(errp, "Unused option '%s' for [%s]",
428adf5c449SMax Reitz                        qdict_first(subqdict)->key, opts->name);
429adf5c449SMax Reitz             goto out;
430adf5c449SMax Reitz         }
431adf5c449SMax Reitz 
432adf5c449SMax Reitz         QLIST_FOREACH_ENTRY(list, list_entry) {
433adf5c449SMax Reitz             QDict *section = qobject_to_qdict(qlist_entry_obj(list_entry));
434adf5c449SMax Reitz             char *opt_name;
435adf5c449SMax Reitz 
436ae39c4b2SMax Reitz             if (!section) {
437ae39c4b2SMax Reitz                 error_setg(errp, "[%s] section (index %u) does not consist of "
438ae39c4b2SMax Reitz                            "keys", opts->name, i);
439ae39c4b2SMax Reitz                 goto out;
440ae39c4b2SMax Reitz             }
441ae39c4b2SMax Reitz 
442adf5c449SMax Reitz             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
443adf5c449SMax Reitz             subopts = qemu_opts_create(opts, opt_name, 1, &local_err);
444adf5c449SMax Reitz             g_free(opt_name);
44584d18f06SMarkus Armbruster             if (local_err) {
446adf5c449SMax Reitz                 error_propagate(errp, local_err);
447adf5c449SMax Reitz                 goto out;
448adf5c449SMax Reitz             }
449adf5c449SMax Reitz 
450adf5c449SMax Reitz             qemu_opts_absorb_qdict(subopts, section, &local_err);
45184d18f06SMarkus Armbruster             if (local_err) {
452adf5c449SMax Reitz                 error_propagate(errp, local_err);
453adf5c449SMax Reitz                 qemu_opts_del(subopts);
454adf5c449SMax Reitz                 goto out;
455adf5c449SMax Reitz             }
456adf5c449SMax Reitz 
457adf5c449SMax Reitz             if (qdict_size(section)) {
458adf5c449SMax Reitz                 error_setg(errp, "[%s] section doesn't support the option '%s'",
459adf5c449SMax Reitz                            opts->name, qdict_first(section)->key);
460adf5c449SMax Reitz                 qemu_opts_del(subopts);
461adf5c449SMax Reitz                 goto out;
462adf5c449SMax Reitz             }
463adf5c449SMax Reitz         }
464adf5c449SMax Reitz     }
465adf5c449SMax Reitz 
466adf5c449SMax Reitz out:
467adf5c449SMax Reitz     QDECREF(subqdict);
468adf5c449SMax Reitz     QDECREF(list);
469adf5c449SMax Reitz }
470adf5c449SMax Reitz 
471adf5c449SMax Reitz void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
472adf5c449SMax Reitz                              Error **errp)
473adf5c449SMax Reitz {
474adf5c449SMax Reitz     int i;
475adf5c449SMax Reitz     Error *local_err = NULL;
476adf5c449SMax Reitz 
477adf5c449SMax Reitz     for (i = 0; lists[i]; i++) {
478adf5c449SMax Reitz         config_parse_qdict_section(options, lists[i], &local_err);
47984d18f06SMarkus Armbruster         if (local_err) {
480adf5c449SMax Reitz             error_propagate(errp, local_err);
481adf5c449SMax Reitz             return;
482adf5c449SMax Reitz         }
483adf5c449SMax Reitz     }
484adf5c449SMax Reitz }
485