xref: /qemu/util/qemu-config.c (revision f766e6dc6acfcfc7e2885518954b1e88111b5527)
1aafd7584SPeter Maydell #include "qemu/osdep.h"
2609f45eaSMax Reitz #include "block/qdict.h" /* for qdict_extract_subqdict() */
3e688df6bSMarkus Armbruster #include "qapi/error.h"
4112ed241SMarkus Armbruster #include "qapi/qapi-commands-misc.h"
537701411SPaolo Bonzini #include "qapi/qmp/qerror.h"
6452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
747e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h"
81de7afc9SPaolo Bonzini #include "qemu/error-report.h"
91de7afc9SPaolo Bonzini #include "qemu/option.h"
101de7afc9SPaolo Bonzini #include "qemu/config-file.h"
117282a033SGerd Hoffmann 
121ceaefbdSGerd Hoffmann static QemuOptsList *vm_config_groups[48];
13c5f3014bSKevin Wolf static QemuOptsList *drive_config_groups[5];
14d058fe03SGerd Hoffmann 
152ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
162ac20613SLuiz Capitulino                                Error **errp)
17d058fe03SGerd Hoffmann {
18ddc97855SGerd Hoffmann     int i;
19d058fe03SGerd Hoffmann 
20632a8873SPaolo Bonzini     qemu_load_module_for_opts(group);
21d058fe03SGerd Hoffmann     for (i = 0; lists[i] != NULL; i++) {
22d058fe03SGerd Hoffmann         if (strcmp(lists[i]->name, group) == 0)
23d058fe03SGerd Hoffmann             break;
24d058fe03SGerd Hoffmann     }
25d058fe03SGerd Hoffmann     if (lists[i] == NULL) {
26f231b88dSCole Robinson         error_setg(errp, "There is no option group '%s'", group);
27ddc97855SGerd Hoffmann     }
28ddc97855SGerd Hoffmann     return lists[i];
29ddc97855SGerd Hoffmann }
30ddc97855SGerd Hoffmann 
31490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group)
32490b648eSKevin Wolf {
332ac20613SLuiz Capitulino     QemuOptsList *ret;
342ac20613SLuiz Capitulino     Error *local_err = NULL;
352ac20613SLuiz Capitulino 
362ac20613SLuiz Capitulino     ret = find_list(vm_config_groups, group, &local_err);
3784d18f06SMarkus Armbruster     if (local_err) {
38565f65d2SMarkus Armbruster         error_report_err(local_err);
392ac20613SLuiz Capitulino     }
402ac20613SLuiz Capitulino 
412ac20613SLuiz Capitulino     return ret;
42490b648eSKevin Wolf }
43490b648eSKevin Wolf 
44e96e5ae8SPaolo Bonzini QemuOpts *qemu_find_opts_singleton(const char *group)
45e96e5ae8SPaolo Bonzini {
46e96e5ae8SPaolo Bonzini     QemuOptsList *list;
47e96e5ae8SPaolo Bonzini     QemuOpts *opts;
48e96e5ae8SPaolo Bonzini 
49e96e5ae8SPaolo Bonzini     list = qemu_find_opts(group);
50e96e5ae8SPaolo Bonzini     assert(list);
51e96e5ae8SPaolo Bonzini     opts = qemu_opts_find(list, NULL);
52e96e5ae8SPaolo Bonzini     if (!opts) {
53e96e5ae8SPaolo Bonzini         opts = qemu_opts_create(list, NULL, 0, &error_abort);
54e96e5ae8SPaolo Bonzini     }
55e96e5ae8SPaolo Bonzini     return opts;
56e96e5ae8SPaolo Bonzini }
57e96e5ae8SPaolo Bonzini 
581f8f987dSAmos Kong static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
591f8f987dSAmos Kong {
6054aa3de7SEric Blake     CommandLineParameterInfoList *param_list = NULL;
611f8f987dSAmos Kong     CommandLineParameterInfo *info;
621f8f987dSAmos Kong     int i;
631f8f987dSAmos Kong 
641f8f987dSAmos Kong     for (i = 0; desc[i].name != NULL; i++) {
651f8f987dSAmos Kong         info = g_malloc0(sizeof(*info));
661f8f987dSAmos Kong         info->name = g_strdup(desc[i].name);
671f8f987dSAmos Kong 
681f8f987dSAmos Kong         switch (desc[i].type) {
691f8f987dSAmos Kong         case QEMU_OPT_STRING:
701f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
711f8f987dSAmos Kong             break;
721f8f987dSAmos Kong         case QEMU_OPT_BOOL:
731f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
741f8f987dSAmos Kong             break;
751f8f987dSAmos Kong         case QEMU_OPT_NUMBER:
761f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
771f8f987dSAmos Kong             break;
781f8f987dSAmos Kong         case QEMU_OPT_SIZE:
791f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
801f8f987dSAmos Kong             break;
811f8f987dSAmos Kong         }
821f8f987dSAmos Kong 
831f8f987dSAmos Kong         if (desc[i].help) {
841f8f987dSAmos Kong             info->has_help = true;
851f8f987dSAmos Kong             info->help = g_strdup(desc[i].help);
861f8f987dSAmos Kong         }
87e36af94fSChunyan Liu         if (desc[i].def_value_str) {
88e36af94fSChunyan Liu             info->has_q_default = true;
89e36af94fSChunyan Liu             info->q_default = g_strdup(desc[i].def_value_str);
90e36af94fSChunyan Liu         }
911f8f987dSAmos Kong 
9254aa3de7SEric Blake         QAPI_LIST_PREPEND(param_list, info);
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;
110b11e20fbSMarc-André Lureau                 del_entry->next = NULL;
111b11e20fbSMarc-André Lureau                 qapi_free_CommandLineParameterInfoList(del_entry);
112968854c8SAmos Kong                 break;
113968854c8SAmos Kong             }
114968854c8SAmos Kong             pre_entry = pre_entry->next;
115968854c8SAmos Kong         }
116968854c8SAmos Kong         cur = cur->next;
117968854c8SAmos Kong     }
118968854c8SAmos Kong }
119968854c8SAmos Kong 
120968854c8SAmos Kong /* merge the description items of two parameter infolists */
121968854c8SAmos Kong static void connect_infolist(CommandLineParameterInfoList *head,
122968854c8SAmos Kong                              CommandLineParameterInfoList *new)
123968854c8SAmos Kong {
124968854c8SAmos Kong     CommandLineParameterInfoList *cur;
125968854c8SAmos Kong 
126968854c8SAmos Kong     cur = head;
127968854c8SAmos Kong     while (cur->next) {
128968854c8SAmos Kong         cur = cur->next;
129968854c8SAmos Kong     }
130968854c8SAmos Kong     cur->next = new;
131968854c8SAmos Kong }
132968854c8SAmos Kong 
133968854c8SAmos Kong /* access all the local QemuOptsLists for drive option */
134968854c8SAmos Kong static CommandLineParameterInfoList *get_drive_infolist(void)
135968854c8SAmos Kong {
136968854c8SAmos Kong     CommandLineParameterInfoList *head = NULL, *cur;
137968854c8SAmos Kong     int i;
138968854c8SAmos Kong 
139968854c8SAmos Kong     for (i = 0; drive_config_groups[i] != NULL; i++) {
140968854c8SAmos Kong         if (!head) {
141968854c8SAmos Kong             head = query_option_descs(drive_config_groups[i]->desc);
142968854c8SAmos Kong         } else {
143968854c8SAmos Kong             cur = query_option_descs(drive_config_groups[i]->desc);
144968854c8SAmos Kong             connect_infolist(head, cur);
145968854c8SAmos Kong         }
146968854c8SAmos Kong     }
147968854c8SAmos Kong     cleanup_infolist(head);
148968854c8SAmos Kong 
149968854c8SAmos Kong     return head;
150968854c8SAmos Kong }
151968854c8SAmos Kong 
1520a7cf217SMarcel Apfelbaum /* restore machine options that are now machine's properties */
1530a7cf217SMarcel Apfelbaum static QemuOptsList machine_opts = {
1540a7cf217SMarcel Apfelbaum     .merge_lists = true,
1550a7cf217SMarcel Apfelbaum     .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head),
1560a7cf217SMarcel Apfelbaum     .desc = {
1570a7cf217SMarcel Apfelbaum         {
1580a7cf217SMarcel Apfelbaum             .name = "type",
1590a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1600a7cf217SMarcel Apfelbaum             .help = "emulated machine"
1610a7cf217SMarcel Apfelbaum         },{
1620a7cf217SMarcel Apfelbaum             .name = "accel",
1630a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1640a7cf217SMarcel Apfelbaum             .help = "accelerator list",
1650a7cf217SMarcel Apfelbaum         },{
1660a7cf217SMarcel Apfelbaum             .name = "kernel_irqchip",
1670a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
1680a7cf217SMarcel Apfelbaum             .help = "use KVM in-kernel irqchip",
1690a7cf217SMarcel Apfelbaum         },{
1700a7cf217SMarcel Apfelbaum             .name = "kvm_shadow_mem",
1710a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_SIZE,
1720a7cf217SMarcel Apfelbaum             .help = "KVM shadow MMU size",
1730a7cf217SMarcel Apfelbaum         },{
1740a7cf217SMarcel Apfelbaum             .name = "kernel",
1750a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1760a7cf217SMarcel Apfelbaum             .help = "Linux kernel image file",
1770a7cf217SMarcel Apfelbaum         },{
1780a7cf217SMarcel Apfelbaum             .name = "initrd",
1790a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1800a7cf217SMarcel Apfelbaum             .help = "Linux initial ramdisk file",
1810a7cf217SMarcel Apfelbaum         },{
1820a7cf217SMarcel Apfelbaum             .name = "append",
1830a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1840a7cf217SMarcel Apfelbaum             .help = "Linux kernel command line",
1850a7cf217SMarcel Apfelbaum         },{
1860a7cf217SMarcel Apfelbaum             .name = "dtb",
1870a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1880a7cf217SMarcel Apfelbaum             .help = "Linux kernel device tree file",
1890a7cf217SMarcel Apfelbaum         },{
1900a7cf217SMarcel Apfelbaum             .name = "dumpdtb",
1910a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1920a7cf217SMarcel Apfelbaum             .help = "Dump current dtb to a file and quit",
1930a7cf217SMarcel Apfelbaum         },{
1940a7cf217SMarcel Apfelbaum             .name = "phandle_start",
1950a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_NUMBER,
1960a7cf217SMarcel Apfelbaum             .help = "The first phandle ID we may generate dynamically",
1970a7cf217SMarcel Apfelbaum         },{
1980a7cf217SMarcel Apfelbaum             .name = "dt_compatible",
1990a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
2000a7cf217SMarcel Apfelbaum             .help = "Overrides the \"compatible\" property of the dt root node",
2010a7cf217SMarcel Apfelbaum         },{
2020a7cf217SMarcel Apfelbaum             .name = "dump-guest-core",
2030a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2040a7cf217SMarcel Apfelbaum             .help = "Include guest memory in  a core dump",
2050a7cf217SMarcel Apfelbaum         },{
2060a7cf217SMarcel Apfelbaum             .name = "mem-merge",
2070a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2080a7cf217SMarcel Apfelbaum             .help = "enable/disable memory merge support",
2090a7cf217SMarcel Apfelbaum         },{
2100a7cf217SMarcel Apfelbaum             .name = "usb",
2110a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2120a7cf217SMarcel Apfelbaum             .help = "Set on/off to enable/disable usb",
2130a7cf217SMarcel Apfelbaum         },{
2140a7cf217SMarcel Apfelbaum             .name = "firmware",
2150a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
2160a7cf217SMarcel Apfelbaum             .help = "firmware image",
2170a7cf217SMarcel Apfelbaum         },{
2180a7cf217SMarcel Apfelbaum             .name = "iommu",
2190a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2200a7cf217SMarcel Apfelbaum             .help = "Set on/off to enable/disable Intel IOMMU (VT-d)",
2210a7cf217SMarcel Apfelbaum         },{
2220a7cf217SMarcel Apfelbaum             .name = "suppress-vmdesc",
2230a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2240a7cf217SMarcel Apfelbaum             .help = "Set on to disable self-describing migration",
2255bcfa0c5STony Krowiak         },{
2265bcfa0c5STony Krowiak             .name = "aes-key-wrap",
2275bcfa0c5STony Krowiak             .type = QEMU_OPT_BOOL,
2285bcfa0c5STony Krowiak             .help = "enable/disable AES key wrapping using the CPACF wrapping key",
2295bcfa0c5STony Krowiak         },{
2305bcfa0c5STony Krowiak             .name = "dea-key-wrap",
2315bcfa0c5STony Krowiak             .type = QEMU_OPT_BOOL,
2325bcfa0c5STony Krowiak             .help = "enable/disable DEA key wrapping using the CPACF wrapping key",
2335559716cSFarhan Ali         },{
2345559716cSFarhan Ali             .name = "loadparm",
2355559716cSFarhan Ali             .type = QEMU_OPT_STRING,
2365559716cSFarhan Ali             .help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars"
2375559716cSFarhan Ali                     " converted to upper case) to pass to machine"
2385559716cSFarhan Ali                     " loader, boot manager, and guest kernel",
2390a7cf217SMarcel Apfelbaum         },
2400a7cf217SMarcel Apfelbaum         { /* End of list */ }
2410a7cf217SMarcel Apfelbaum     }
2420a7cf217SMarcel Apfelbaum };
2430a7cf217SMarcel Apfelbaum 
2441f8f987dSAmos Kong CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
2451f8f987dSAmos Kong                                                           const char *option,
2461f8f987dSAmos Kong                                                           Error **errp)
2471f8f987dSAmos Kong {
24854aa3de7SEric Blake     CommandLineOptionInfoList *conf_list = NULL;
2491f8f987dSAmos Kong     CommandLineOptionInfo *info;
2501f8f987dSAmos Kong     int i;
2511f8f987dSAmos Kong 
2521f8f987dSAmos Kong     for (i = 0; vm_config_groups[i] != NULL; i++) {
2531f8f987dSAmos Kong         if (!has_option || !strcmp(option, vm_config_groups[i]->name)) {
2541f8f987dSAmos Kong             info = g_malloc0(sizeof(*info));
2551f8f987dSAmos Kong             info->option = g_strdup(vm_config_groups[i]->name);
256968854c8SAmos Kong             if (!strcmp("drive", vm_config_groups[i]->name)) {
257968854c8SAmos Kong                 info->parameters = get_drive_infolist();
258968854c8SAmos Kong             } else {
259968854c8SAmos Kong                 info->parameters =
260968854c8SAmos Kong                     query_option_descs(vm_config_groups[i]->desc);
261968854c8SAmos Kong             }
26254aa3de7SEric Blake             QAPI_LIST_PREPEND(conf_list, info);
2631f8f987dSAmos Kong         }
2641f8f987dSAmos Kong     }
2651f8f987dSAmos Kong 
26640e07370SStefan Hajnoczi     if (!has_option || !strcmp(option, "machine")) {
26740e07370SStefan Hajnoczi         info = g_malloc0(sizeof(*info));
26840e07370SStefan Hajnoczi         info->option = g_strdup("machine");
26940e07370SStefan Hajnoczi         info->parameters = query_option_descs(machine_opts.desc);
27040e07370SStefan Hajnoczi         QAPI_LIST_PREPEND(conf_list, info);
27140e07370SStefan Hajnoczi     }
27240e07370SStefan Hajnoczi 
2731f8f987dSAmos Kong     if (conf_list == NULL) {
2741f8f987dSAmos Kong         error_setg(errp, "invalid option name: %s", option);
2751f8f987dSAmos Kong     }
2761f8f987dSAmos Kong 
2771f8f987dSAmos Kong     return conf_list;
2781f8f987dSAmos Kong }
2791f8f987dSAmos Kong 
28060d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
28160d5666fSLuiz Capitulino {
28260d5666fSLuiz Capitulino     return find_list(vm_config_groups, group, errp);
28360d5666fSLuiz Capitulino }
28460d5666fSLuiz Capitulino 
285968854c8SAmos Kong void qemu_add_drive_opts(QemuOptsList *list)
286968854c8SAmos Kong {
287968854c8SAmos Kong     int entries, i;
288968854c8SAmos Kong 
289968854c8SAmos Kong     entries = ARRAY_SIZE(drive_config_groups);
290968854c8SAmos Kong     entries--; /* keep list NULL terminated */
291968854c8SAmos Kong     for (i = 0; i < entries; i++) {
292968854c8SAmos Kong         if (drive_config_groups[i] == NULL) {
293968854c8SAmos Kong             drive_config_groups[i] = list;
294968854c8SAmos Kong             return;
295968854c8SAmos Kong         }
296968854c8SAmos Kong     }
297968854c8SAmos Kong     fprintf(stderr, "ran out of space in drive_config_groups");
298968854c8SAmos Kong     abort();
299968854c8SAmos Kong }
300968854c8SAmos Kong 
301dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list)
302dfe795e7SGerd Hoffmann {
303dfe795e7SGerd Hoffmann     int entries, i;
304dfe795e7SGerd Hoffmann 
305dfe795e7SGerd Hoffmann     entries = ARRAY_SIZE(vm_config_groups);
306dfe795e7SGerd Hoffmann     entries--; /* keep list NULL terminated */
307dfe795e7SGerd Hoffmann     for (i = 0; i < entries; i++) {
308dfe795e7SGerd Hoffmann         if (vm_config_groups[i] == NULL) {
309dfe795e7SGerd Hoffmann             vm_config_groups[i] = list;
310dfe795e7SGerd Hoffmann             return;
311dfe795e7SGerd Hoffmann         }
312dfe795e7SGerd Hoffmann     }
313dfe795e7SGerd Hoffmann     fprintf(stderr, "ran out of space in vm_config_groups");
314dfe795e7SGerd Hoffmann     abort();
315dfe795e7SGerd Hoffmann }
316dfe795e7SGerd Hoffmann 
317e5766d6eSEduardo Habkost /* Returns number of config groups on success, -errno on error */
31837701411SPaolo Bonzini static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque,
31937701411SPaolo Bonzini                                const char *fname, Error **errp)
32042262ba8SGerd Hoffmann {
32137701411SPaolo Bonzini     char line[1024], prev_group[64], group[64], arg[64], value[1024];
322cf5a65aaSMarkus Armbruster     Location loc;
3232ac20613SLuiz Capitulino     Error *local_err = NULL;
32437701411SPaolo Bonzini     QDict *qdict = NULL;
325e5766d6eSEduardo Habkost     int res = -EINVAL, lno = 0;
326e5766d6eSEduardo Habkost     int count = 0;
32742262ba8SGerd Hoffmann 
328cf5a65aaSMarkus Armbruster     loc_push_none(&loc);
32942262ba8SGerd Hoffmann     while (fgets(line, sizeof(line), fp) != NULL) {
33037701411SPaolo Bonzini         ++lno;
33142262ba8SGerd Hoffmann         if (line[0] == '\n') {
33242262ba8SGerd Hoffmann             /* skip empty lines */
33342262ba8SGerd Hoffmann             continue;
33442262ba8SGerd Hoffmann         }
33542262ba8SGerd Hoffmann         if (line[0] == '#') {
33642262ba8SGerd Hoffmann             /* comment */
33742262ba8SGerd Hoffmann             continue;
33842262ba8SGerd Hoffmann         }
33937701411SPaolo Bonzini         if (line[0] == '[') {
34037701411SPaolo Bonzini             QDict *prev = qdict;
34137701411SPaolo Bonzini             if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) {
34237701411SPaolo Bonzini                 qdict = qdict_new();
34337701411SPaolo Bonzini                 qdict_put_str(qdict, "id", value);
34437701411SPaolo Bonzini                 count++;
34537701411SPaolo Bonzini             } else if (sscanf(line, "[%63[^]]]", group) == 1) {
34637701411SPaolo Bonzini                 qdict = qdict_new();
34737701411SPaolo Bonzini                 count++;
34837701411SPaolo Bonzini             }
34937701411SPaolo Bonzini             if (qdict != prev) {
35037701411SPaolo Bonzini                 if (prev) {
35137701411SPaolo Bonzini                     cb(prev_group, prev, opaque, &local_err);
35237701411SPaolo Bonzini                     qobject_unref(prev);
35384d18f06SMarkus Armbruster                     if (local_err) {
354f7544edcSPaolo Bonzini                         error_propagate(errp, local_err);
355cf5a65aaSMarkus Armbruster                         goto out;
3562ac20613SLuiz Capitulino                     }
35737701411SPaolo Bonzini                 }
35837701411SPaolo Bonzini                 strcpy(prev_group, group);
35942262ba8SGerd Hoffmann                 continue;
36042262ba8SGerd Hoffmann             }
3612ac20613SLuiz Capitulino         }
36237701411SPaolo Bonzini         loc_set_file(fname, lno);
363d9f7e29eSEduardo Habkost         value[0] = '\0';
364d9f7e29eSEduardo Habkost         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
365d9f7e29eSEduardo Habkost             sscanf(line, " %63s = \"\"", arg) == 1) {
36642262ba8SGerd Hoffmann             /* arg = value */
36737701411SPaolo Bonzini             if (qdict == NULL) {
368f7544edcSPaolo Bonzini                 error_setg(errp, "no group defined");
369cf5a65aaSMarkus Armbruster                 goto out;
37042262ba8SGerd Hoffmann             }
37137701411SPaolo Bonzini             qdict_put_str(qdict, arg, value);
37242262ba8SGerd Hoffmann             continue;
37342262ba8SGerd Hoffmann         }
374f7544edcSPaolo Bonzini         error_setg(errp, "parse error");
375cf5a65aaSMarkus Armbruster         goto out;
37642262ba8SGerd Hoffmann     }
377ef82516dSMarkus Armbruster     if (ferror(fp)) {
378f7544edcSPaolo Bonzini         loc_pop(&loc);
379f7544edcSPaolo Bonzini         error_setg_errno(errp, errno, "Cannot read config file");
380461fea9bSPaolo Bonzini         goto out_no_loc;
381ef82516dSMarkus Armbruster     }
382e5766d6eSEduardo Habkost     res = count;
38337701411SPaolo Bonzini     if (qdict) {
38437701411SPaolo Bonzini         cb(group, qdict, opaque, errp);
38537701411SPaolo Bonzini     }
386e72f9524SPaolo Bonzini out:
387cf5a65aaSMarkus Armbruster     loc_pop(&loc);
388461fea9bSPaolo Bonzini out_no_loc:
389e72f9524SPaolo Bonzini     qobject_unref(qdict);
390cf5a65aaSMarkus Armbruster     return res;
39142262ba8SGerd Hoffmann }
392dcfb0939SKevin Wolf 
39337701411SPaolo Bonzini void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp)
39437701411SPaolo Bonzini {
39537701411SPaolo Bonzini     QemuOptsList **lists = opaque;
39637701411SPaolo Bonzini     QemuOptsList *list;
39737701411SPaolo Bonzini 
39837701411SPaolo Bonzini     list = find_list(lists, group, errp);
39937701411SPaolo Bonzini     if (!list) {
40037701411SPaolo Bonzini         return;
40137701411SPaolo Bonzini     }
40237701411SPaolo Bonzini 
403e7d85d95SPaolo Bonzini     qemu_opts_from_qdict(list, qdict, errp);
40437701411SPaolo Bonzini }
40537701411SPaolo Bonzini 
40637701411SPaolo Bonzini int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
40737701411SPaolo Bonzini {
40837701411SPaolo Bonzini     return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp);
40937701411SPaolo Bonzini }
41037701411SPaolo Bonzini 
41137701411SPaolo Bonzini int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp)
412dcfb0939SKevin Wolf {
413dcfb0939SKevin Wolf     FILE *f = fopen(filename, "r");
414019e78baSKevin Wolf     int ret;
415019e78baSKevin Wolf 
416dcfb0939SKevin Wolf     if (f == NULL) {
417f7544edcSPaolo Bonzini         error_setg_file_open(errp, errno, filename);
418dcfb0939SKevin Wolf         return -errno;
419dcfb0939SKevin Wolf     }
420dcfb0939SKevin Wolf 
42137701411SPaolo Bonzini     ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp);
422dcfb0939SKevin Wolf     fclose(f);
423e5766d6eSEduardo Habkost     return ret;
424dcfb0939SKevin Wolf }
425adf5c449SMax Reitz 
426*f766e6dcSMarkus Armbruster static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts,
427adf5c449SMax Reitz                                        Error **errp)
428adf5c449SMax Reitz {
429adf5c449SMax Reitz     QemuOpts *subopts;
430*f766e6dcSMarkus Armbruster     g_autoptr(QDict) subqdict = NULL;
431*f766e6dcSMarkus Armbruster     g_autoptr(QList) list = NULL;
432adf5c449SMax Reitz     size_t orig_size, enum_size;
433adf5c449SMax Reitz     char *prefix;
434adf5c449SMax Reitz 
435adf5c449SMax Reitz     prefix = g_strdup_printf("%s.", opts->name);
436adf5c449SMax Reitz     qdict_extract_subqdict(options, &subqdict, prefix);
437adf5c449SMax Reitz     g_free(prefix);
438adf5c449SMax Reitz     orig_size = qdict_size(subqdict);
439adf5c449SMax Reitz     if (!orig_size) {
440*f766e6dcSMarkus Armbruster         return true;
441adf5c449SMax Reitz     }
442adf5c449SMax Reitz 
443c6ecec43SMarkus Armbruster     subopts = qemu_opts_create(opts, NULL, 0, errp);
444c6ecec43SMarkus Armbruster     if (!subopts) {
445*f766e6dcSMarkus Armbruster         return false;
446adf5c449SMax Reitz     }
447adf5c449SMax Reitz 
448668f62ecSMarkus Armbruster     if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) {
449*f766e6dcSMarkus Armbruster         return false;
450adf5c449SMax Reitz     }
451adf5c449SMax Reitz 
452adf5c449SMax Reitz     enum_size = qdict_size(subqdict);
453adf5c449SMax Reitz     if (enum_size < orig_size && enum_size) {
454adf5c449SMax Reitz         error_setg(errp, "Unknown option '%s' for [%s]",
455adf5c449SMax Reitz                    qdict_first(subqdict)->key, opts->name);
456*f766e6dcSMarkus Armbruster         return false;
457adf5c449SMax Reitz     }
458adf5c449SMax Reitz 
459adf5c449SMax Reitz     if (enum_size) {
460adf5c449SMax Reitz         /* Multiple, enumerated sections */
461adf5c449SMax Reitz         QListEntry *list_entry;
462adf5c449SMax Reitz         unsigned i = 0;
463adf5c449SMax Reitz 
464adf5c449SMax Reitz         /* Not required anymore */
465adf5c449SMax Reitz         qemu_opts_del(subopts);
466adf5c449SMax Reitz 
467adf5c449SMax Reitz         qdict_array_split(subqdict, &list);
468adf5c449SMax Reitz         if (qdict_size(subqdict)) {
469adf5c449SMax Reitz             error_setg(errp, "Unused option '%s' for [%s]",
470adf5c449SMax Reitz                        qdict_first(subqdict)->key, opts->name);
471*f766e6dcSMarkus Armbruster             return false;
472adf5c449SMax Reitz         }
473adf5c449SMax Reitz 
474adf5c449SMax Reitz         QLIST_FOREACH_ENTRY(list, list_entry) {
4757dc847ebSMax Reitz             QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry));
476adf5c449SMax Reitz             char *opt_name;
477adf5c449SMax Reitz 
478ae39c4b2SMax Reitz             if (!section) {
479ae39c4b2SMax Reitz                 error_setg(errp, "[%s] section (index %u) does not consist of "
480ae39c4b2SMax Reitz                            "keys", opts->name, i);
481*f766e6dcSMarkus Armbruster                 return false;
482ae39c4b2SMax Reitz             }
483ae39c4b2SMax Reitz 
484adf5c449SMax Reitz             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
485c6ecec43SMarkus Armbruster             subopts = qemu_opts_create(opts, opt_name, 1, errp);
486adf5c449SMax Reitz             g_free(opt_name);
487c6ecec43SMarkus Armbruster             if (!subopts) {
488*f766e6dcSMarkus Armbruster                 return false;
489adf5c449SMax Reitz             }
490adf5c449SMax Reitz 
491668f62ecSMarkus Armbruster             if (!qemu_opts_absorb_qdict(subopts, section, errp)) {
492adf5c449SMax Reitz                 qemu_opts_del(subopts);
493*f766e6dcSMarkus Armbruster                 return false;
494adf5c449SMax Reitz             }
495adf5c449SMax Reitz 
496adf5c449SMax Reitz             if (qdict_size(section)) {
497adf5c449SMax Reitz                 error_setg(errp, "[%s] section doesn't support the option '%s'",
498adf5c449SMax Reitz                            opts->name, qdict_first(section)->key);
499adf5c449SMax Reitz                 qemu_opts_del(subopts);
500*f766e6dcSMarkus Armbruster                 return false;
501adf5c449SMax Reitz             }
502adf5c449SMax Reitz         }
503adf5c449SMax Reitz     }
504adf5c449SMax Reitz 
505*f766e6dcSMarkus Armbruster     return true;
506adf5c449SMax Reitz }
507adf5c449SMax Reitz 
508*f766e6dcSMarkus Armbruster bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
509adf5c449SMax Reitz                              Error **errp)
510adf5c449SMax Reitz {
511adf5c449SMax Reitz     int i;
512adf5c449SMax Reitz 
513adf5c449SMax Reitz     for (i = 0; lists[i]; i++) {
514*f766e6dcSMarkus Armbruster         if (!config_parse_qdict_section(options, lists[i], errp)) {
515*f766e6dcSMarkus Armbruster             return false;
516adf5c449SMax Reitz         }
517adf5c449SMax Reitz     }
518*f766e6dcSMarkus Armbruster 
519*f766e6dcSMarkus Armbruster     return true;
520adf5c449SMax Reitz }
521