xref: /qemu/util/qemu-config.c (revision c5f3014b82adc0e8f50bf5052031503d3467bea3)
1aafd7584SPeter Maydell #include "qemu/osdep.h"
27282a033SGerd Hoffmann #include "qemu-common.h"
31de7afc9SPaolo Bonzini #include "qemu/error-report.h"
41de7afc9SPaolo Bonzini #include "qemu/option.h"
51de7afc9SPaolo Bonzini #include "qemu/config-file.h"
61f8f987dSAmos Kong #include "qmp-commands.h"
77282a033SGerd Hoffmann 
81ceaefbdSGerd Hoffmann static QemuOptsList *vm_config_groups[48];
9*c5f3014bSKevin Wolf static QemuOptsList *drive_config_groups[5];
10d058fe03SGerd Hoffmann 
112ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
122ac20613SLuiz Capitulino                                Error **errp)
13d058fe03SGerd Hoffmann {
14ddc97855SGerd Hoffmann     int i;
15d058fe03SGerd Hoffmann 
16d058fe03SGerd Hoffmann     for (i = 0; lists[i] != NULL; i++) {
17d058fe03SGerd Hoffmann         if (strcmp(lists[i]->name, group) == 0)
18d058fe03SGerd Hoffmann             break;
19d058fe03SGerd Hoffmann     }
20d058fe03SGerd Hoffmann     if (lists[i] == NULL) {
21f231b88dSCole Robinson         error_setg(errp, "There is no option group '%s'", group);
22ddc97855SGerd Hoffmann     }
23ddc97855SGerd Hoffmann     return lists[i];
24ddc97855SGerd Hoffmann }
25ddc97855SGerd Hoffmann 
26490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group)
27490b648eSKevin Wolf {
282ac20613SLuiz Capitulino     QemuOptsList *ret;
292ac20613SLuiz Capitulino     Error *local_err = NULL;
302ac20613SLuiz Capitulino 
312ac20613SLuiz Capitulino     ret = find_list(vm_config_groups, group, &local_err);
3284d18f06SMarkus Armbruster     if (local_err) {
33565f65d2SMarkus Armbruster         error_report_err(local_err);
342ac20613SLuiz Capitulino     }
352ac20613SLuiz Capitulino 
362ac20613SLuiz Capitulino     return ret;
37490b648eSKevin Wolf }
38490b648eSKevin Wolf 
39e96e5ae8SPaolo Bonzini QemuOpts *qemu_find_opts_singleton(const char *group)
40e96e5ae8SPaolo Bonzini {
41e96e5ae8SPaolo Bonzini     QemuOptsList *list;
42e96e5ae8SPaolo Bonzini     QemuOpts *opts;
43e96e5ae8SPaolo Bonzini 
44e96e5ae8SPaolo Bonzini     list = qemu_find_opts(group);
45e96e5ae8SPaolo Bonzini     assert(list);
46e96e5ae8SPaolo Bonzini     opts = qemu_opts_find(list, NULL);
47e96e5ae8SPaolo Bonzini     if (!opts) {
48e96e5ae8SPaolo Bonzini         opts = qemu_opts_create(list, NULL, 0, &error_abort);
49e96e5ae8SPaolo Bonzini     }
50e96e5ae8SPaolo Bonzini     return opts;
51e96e5ae8SPaolo Bonzini }
52e96e5ae8SPaolo Bonzini 
531f8f987dSAmos Kong static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
541f8f987dSAmos Kong {
551f8f987dSAmos Kong     CommandLineParameterInfoList *param_list = NULL, *entry;
561f8f987dSAmos Kong     CommandLineParameterInfo *info;
571f8f987dSAmos Kong     int i;
581f8f987dSAmos Kong 
591f8f987dSAmos Kong     for (i = 0; desc[i].name != NULL; i++) {
601f8f987dSAmos Kong         info = g_malloc0(sizeof(*info));
611f8f987dSAmos Kong         info->name = g_strdup(desc[i].name);
621f8f987dSAmos Kong 
631f8f987dSAmos Kong         switch (desc[i].type) {
641f8f987dSAmos Kong         case QEMU_OPT_STRING:
651f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
661f8f987dSAmos Kong             break;
671f8f987dSAmos Kong         case QEMU_OPT_BOOL:
681f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
691f8f987dSAmos Kong             break;
701f8f987dSAmos Kong         case QEMU_OPT_NUMBER:
711f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
721f8f987dSAmos Kong             break;
731f8f987dSAmos Kong         case QEMU_OPT_SIZE:
741f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
751f8f987dSAmos Kong             break;
761f8f987dSAmos Kong         }
771f8f987dSAmos Kong 
781f8f987dSAmos Kong         if (desc[i].help) {
791f8f987dSAmos Kong             info->has_help = true;
801f8f987dSAmos Kong             info->help = g_strdup(desc[i].help);
811f8f987dSAmos Kong         }
82e36af94fSChunyan Liu         if (desc[i].def_value_str) {
83e36af94fSChunyan Liu             info->has_q_default = true;
84e36af94fSChunyan Liu             info->q_default = g_strdup(desc[i].def_value_str);
85e36af94fSChunyan Liu         }
861f8f987dSAmos Kong 
871f8f987dSAmos Kong         entry = g_malloc0(sizeof(*entry));
881f8f987dSAmos Kong         entry->value = info;
891f8f987dSAmos Kong         entry->next = param_list;
901f8f987dSAmos Kong         param_list = entry;
911f8f987dSAmos Kong     }
921f8f987dSAmos Kong 
931f8f987dSAmos Kong     return param_list;
941f8f987dSAmos Kong }
951f8f987dSAmos Kong 
96968854c8SAmos Kong /* remove repeated entry from the info list */
97968854c8SAmos Kong static void cleanup_infolist(CommandLineParameterInfoList *head)
98968854c8SAmos Kong {
99968854c8SAmos Kong     CommandLineParameterInfoList *pre_entry, *cur, *del_entry;
100968854c8SAmos Kong 
101968854c8SAmos Kong     cur = head;
102968854c8SAmos Kong     while (cur->next) {
103968854c8SAmos Kong         pre_entry = head;
104968854c8SAmos Kong         while (pre_entry != cur->next) {
105968854c8SAmos Kong             if (!strcmp(pre_entry->value->name, cur->next->value->name)) {
106968854c8SAmos Kong                 del_entry = cur->next;
107968854c8SAmos Kong                 cur->next = cur->next->next;
108968854c8SAmos Kong                 g_free(del_entry);
109968854c8SAmos Kong                 break;
110968854c8SAmos Kong             }
111968854c8SAmos Kong             pre_entry = pre_entry->next;
112968854c8SAmos Kong         }
113968854c8SAmos Kong         cur = cur->next;
114968854c8SAmos Kong     }
115968854c8SAmos Kong }
116968854c8SAmos Kong 
117968854c8SAmos Kong /* merge the description items of two parameter infolists */
118968854c8SAmos Kong static void connect_infolist(CommandLineParameterInfoList *head,
119968854c8SAmos Kong                              CommandLineParameterInfoList *new)
120968854c8SAmos Kong {
121968854c8SAmos Kong     CommandLineParameterInfoList *cur;
122968854c8SAmos Kong 
123968854c8SAmos Kong     cur = head;
124968854c8SAmos Kong     while (cur->next) {
125968854c8SAmos Kong         cur = cur->next;
126968854c8SAmos Kong     }
127968854c8SAmos Kong     cur->next = new;
128968854c8SAmos Kong }
129968854c8SAmos Kong 
130968854c8SAmos Kong /* access all the local QemuOptsLists for drive option */
131968854c8SAmos Kong static CommandLineParameterInfoList *get_drive_infolist(void)
132968854c8SAmos Kong {
133968854c8SAmos Kong     CommandLineParameterInfoList *head = NULL, *cur;
134968854c8SAmos Kong     int i;
135968854c8SAmos Kong 
136968854c8SAmos Kong     for (i = 0; drive_config_groups[i] != NULL; i++) {
137968854c8SAmos Kong         if (!head) {
138968854c8SAmos Kong             head = query_option_descs(drive_config_groups[i]->desc);
139968854c8SAmos Kong         } else {
140968854c8SAmos Kong             cur = query_option_descs(drive_config_groups[i]->desc);
141968854c8SAmos Kong             connect_infolist(head, cur);
142968854c8SAmos Kong         }
143968854c8SAmos Kong     }
144968854c8SAmos Kong     cleanup_infolist(head);
145968854c8SAmos Kong 
146968854c8SAmos Kong     return head;
147968854c8SAmos Kong }
148968854c8SAmos Kong 
1490a7cf217SMarcel Apfelbaum /* restore machine options that are now machine's properties */
1500a7cf217SMarcel Apfelbaum static QemuOptsList machine_opts = {
1510a7cf217SMarcel Apfelbaum     .merge_lists = true,
1520a7cf217SMarcel Apfelbaum     .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head),
1530a7cf217SMarcel Apfelbaum     .desc = {
1540a7cf217SMarcel Apfelbaum         {
1550a7cf217SMarcel Apfelbaum             .name = "type",
1560a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1570a7cf217SMarcel Apfelbaum             .help = "emulated machine"
1580a7cf217SMarcel Apfelbaum         },{
1590a7cf217SMarcel Apfelbaum             .name = "accel",
1600a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1610a7cf217SMarcel Apfelbaum             .help = "accelerator list",
1620a7cf217SMarcel Apfelbaum         },{
1630a7cf217SMarcel Apfelbaum             .name = "kernel_irqchip",
1640a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
1650a7cf217SMarcel Apfelbaum             .help = "use KVM in-kernel irqchip",
1660a7cf217SMarcel Apfelbaum         },{
1670a7cf217SMarcel Apfelbaum             .name = "kvm_shadow_mem",
1680a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_SIZE,
1690a7cf217SMarcel Apfelbaum             .help = "KVM shadow MMU size",
1700a7cf217SMarcel Apfelbaum         },{
1710a7cf217SMarcel Apfelbaum             .name = "kernel",
1720a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1730a7cf217SMarcel Apfelbaum             .help = "Linux kernel image file",
1740a7cf217SMarcel Apfelbaum         },{
1750a7cf217SMarcel Apfelbaum             .name = "initrd",
1760a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1770a7cf217SMarcel Apfelbaum             .help = "Linux initial ramdisk file",
1780a7cf217SMarcel Apfelbaum         },{
1790a7cf217SMarcel Apfelbaum             .name = "append",
1800a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1810a7cf217SMarcel Apfelbaum             .help = "Linux kernel command line",
1820a7cf217SMarcel Apfelbaum         },{
1830a7cf217SMarcel Apfelbaum             .name = "dtb",
1840a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1850a7cf217SMarcel Apfelbaum             .help = "Linux kernel device tree file",
1860a7cf217SMarcel Apfelbaum         },{
1870a7cf217SMarcel Apfelbaum             .name = "dumpdtb",
1880a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1890a7cf217SMarcel Apfelbaum             .help = "Dump current dtb to a file and quit",
1900a7cf217SMarcel Apfelbaum         },{
1910a7cf217SMarcel Apfelbaum             .name = "phandle_start",
1920a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_NUMBER,
1930a7cf217SMarcel Apfelbaum             .help = "The first phandle ID we may generate dynamically",
1940a7cf217SMarcel Apfelbaum         },{
1950a7cf217SMarcel Apfelbaum             .name = "dt_compatible",
1960a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
1970a7cf217SMarcel Apfelbaum             .help = "Overrides the \"compatible\" property of the dt root node",
1980a7cf217SMarcel Apfelbaum         },{
1990a7cf217SMarcel Apfelbaum             .name = "dump-guest-core",
2000a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2010a7cf217SMarcel Apfelbaum             .help = "Include guest memory in  a core dump",
2020a7cf217SMarcel Apfelbaum         },{
2030a7cf217SMarcel Apfelbaum             .name = "mem-merge",
2040a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2050a7cf217SMarcel Apfelbaum             .help = "enable/disable memory merge support",
2060a7cf217SMarcel Apfelbaum         },{
2070a7cf217SMarcel Apfelbaum             .name = "usb",
2080a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2090a7cf217SMarcel Apfelbaum             .help = "Set on/off to enable/disable usb",
2100a7cf217SMarcel Apfelbaum         },{
2110a7cf217SMarcel Apfelbaum             .name = "firmware",
2120a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_STRING,
2130a7cf217SMarcel Apfelbaum             .help = "firmware image",
2140a7cf217SMarcel Apfelbaum         },{
2150a7cf217SMarcel Apfelbaum             .name = "iommu",
2160a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2170a7cf217SMarcel Apfelbaum             .help = "Set on/off to enable/disable Intel IOMMU (VT-d)",
2180a7cf217SMarcel Apfelbaum         },{
2190a7cf217SMarcel Apfelbaum             .name = "suppress-vmdesc",
2200a7cf217SMarcel Apfelbaum             .type = QEMU_OPT_BOOL,
2210a7cf217SMarcel Apfelbaum             .help = "Set on to disable self-describing migration",
2225bcfa0c5STony Krowiak         },{
2235bcfa0c5STony Krowiak             .name = "aes-key-wrap",
2245bcfa0c5STony Krowiak             .type = QEMU_OPT_BOOL,
2255bcfa0c5STony Krowiak             .help = "enable/disable AES key wrapping using the CPACF wrapping key",
2265bcfa0c5STony Krowiak         },{
2275bcfa0c5STony Krowiak             .name = "dea-key-wrap",
2285bcfa0c5STony Krowiak             .type = QEMU_OPT_BOOL,
2295bcfa0c5STony Krowiak             .help = "enable/disable DEA key wrapping using the CPACF wrapping key",
2300a7cf217SMarcel Apfelbaum         },
2310a7cf217SMarcel Apfelbaum         { /* End of list */ }
2320a7cf217SMarcel Apfelbaum     }
2330a7cf217SMarcel Apfelbaum };
2340a7cf217SMarcel Apfelbaum 
2351f8f987dSAmos Kong CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
2361f8f987dSAmos Kong                                                           const char *option,
2371f8f987dSAmos Kong                                                           Error **errp)
2381f8f987dSAmos Kong {
2391f8f987dSAmos Kong     CommandLineOptionInfoList *conf_list = NULL, *entry;
2401f8f987dSAmos Kong     CommandLineOptionInfo *info;
2411f8f987dSAmos Kong     int i;
2421f8f987dSAmos Kong 
2431f8f987dSAmos Kong     for (i = 0; vm_config_groups[i] != NULL; i++) {
2441f8f987dSAmos Kong         if (!has_option || !strcmp(option, vm_config_groups[i]->name)) {
2451f8f987dSAmos Kong             info = g_malloc0(sizeof(*info));
2461f8f987dSAmos Kong             info->option = g_strdup(vm_config_groups[i]->name);
247968854c8SAmos Kong             if (!strcmp("drive", vm_config_groups[i]->name)) {
248968854c8SAmos Kong                 info->parameters = get_drive_infolist();
2490a7cf217SMarcel Apfelbaum             } else if (!strcmp("machine", vm_config_groups[i]->name)) {
2500a7cf217SMarcel Apfelbaum                 info->parameters = query_option_descs(machine_opts.desc);
251968854c8SAmos Kong             } else {
252968854c8SAmos Kong                 info->parameters =
253968854c8SAmos Kong                     query_option_descs(vm_config_groups[i]->desc);
254968854c8SAmos Kong             }
2551f8f987dSAmos Kong             entry = g_malloc0(sizeof(*entry));
2561f8f987dSAmos Kong             entry->value = info;
2571f8f987dSAmos Kong             entry->next = conf_list;
2581f8f987dSAmos Kong             conf_list = entry;
2591f8f987dSAmos Kong         }
2601f8f987dSAmos Kong     }
2611f8f987dSAmos Kong 
2621f8f987dSAmos Kong     if (conf_list == NULL) {
2631f8f987dSAmos Kong         error_setg(errp, "invalid option name: %s", option);
2641f8f987dSAmos Kong     }
2651f8f987dSAmos Kong 
2661f8f987dSAmos Kong     return conf_list;
2671f8f987dSAmos Kong }
2681f8f987dSAmos Kong 
26960d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
27060d5666fSLuiz Capitulino {
27160d5666fSLuiz Capitulino     return find_list(vm_config_groups, group, errp);
27260d5666fSLuiz Capitulino }
27360d5666fSLuiz Capitulino 
274968854c8SAmos Kong void qemu_add_drive_opts(QemuOptsList *list)
275968854c8SAmos Kong {
276968854c8SAmos Kong     int entries, i;
277968854c8SAmos Kong 
278968854c8SAmos Kong     entries = ARRAY_SIZE(drive_config_groups);
279968854c8SAmos Kong     entries--; /* keep list NULL terminated */
280968854c8SAmos Kong     for (i = 0; i < entries; i++) {
281968854c8SAmos Kong         if (drive_config_groups[i] == NULL) {
282968854c8SAmos Kong             drive_config_groups[i] = list;
283968854c8SAmos Kong             return;
284968854c8SAmos Kong         }
285968854c8SAmos Kong     }
286968854c8SAmos Kong     fprintf(stderr, "ran out of space in drive_config_groups");
287968854c8SAmos Kong     abort();
288968854c8SAmos Kong }
289968854c8SAmos Kong 
290dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list)
291dfe795e7SGerd Hoffmann {
292dfe795e7SGerd Hoffmann     int entries, i;
293dfe795e7SGerd Hoffmann 
294dfe795e7SGerd Hoffmann     entries = ARRAY_SIZE(vm_config_groups);
295dfe795e7SGerd Hoffmann     entries--; /* keep list NULL terminated */
296dfe795e7SGerd Hoffmann     for (i = 0; i < entries; i++) {
297dfe795e7SGerd Hoffmann         if (vm_config_groups[i] == NULL) {
298dfe795e7SGerd Hoffmann             vm_config_groups[i] = list;
299dfe795e7SGerd Hoffmann             return;
300dfe795e7SGerd Hoffmann         }
301dfe795e7SGerd Hoffmann     }
302dfe795e7SGerd Hoffmann     fprintf(stderr, "ran out of space in vm_config_groups");
303dfe795e7SGerd Hoffmann     abort();
304dfe795e7SGerd Hoffmann }
305dfe795e7SGerd Hoffmann 
306ddc97855SGerd Hoffmann int qemu_set_option(const char *str)
307ddc97855SGerd Hoffmann {
308f43e47dbSMarkus Armbruster     Error *local_err = NULL;
309ddc97855SGerd Hoffmann     char group[64], id[64], arg[64];
310ddc97855SGerd Hoffmann     QemuOptsList *list;
311ddc97855SGerd Hoffmann     QemuOpts *opts;
312ddc97855SGerd Hoffmann     int rc, offset;
313ddc97855SGerd Hoffmann 
314ddc97855SGerd Hoffmann     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
315ddc97855SGerd Hoffmann     if (rc < 3 || str[offset] != '=') {
3161ecda02bSMarkus Armbruster         error_report("can't parse: \"%s\"", str);
317d058fe03SGerd Hoffmann         return -1;
318d058fe03SGerd Hoffmann     }
319d058fe03SGerd Hoffmann 
320304329eeSMarkus Armbruster     list = qemu_find_opts(group);
321ddc97855SGerd Hoffmann     if (list == NULL) {
322ddc97855SGerd Hoffmann         return -1;
323ddc97855SGerd Hoffmann     }
324ddc97855SGerd Hoffmann 
325ddc97855SGerd Hoffmann     opts = qemu_opts_find(list, id);
326d058fe03SGerd Hoffmann     if (!opts) {
3271ecda02bSMarkus Armbruster         error_report("there is no %s \"%s\" defined",
328ddc97855SGerd Hoffmann                      list->name, id);
329d058fe03SGerd Hoffmann         return -1;
330d058fe03SGerd Hoffmann     }
331d058fe03SGerd Hoffmann 
332f43e47dbSMarkus Armbruster     qemu_opt_set(opts, arg, str + offset + 1, &local_err);
333f43e47dbSMarkus Armbruster     if (local_err) {
334f43e47dbSMarkus Armbruster         error_report_err(local_err);
335d058fe03SGerd Hoffmann         return -1;
336d058fe03SGerd Hoffmann     }
337d058fe03SGerd Hoffmann     return 0;
338d058fe03SGerd Hoffmann }
339d058fe03SGerd Hoffmann 
3409d993394SGerd Hoffmann struct ConfigWriteData {
3419d993394SGerd Hoffmann     QemuOptsList *list;
3429d993394SGerd Hoffmann     FILE *fp;
3439d993394SGerd Hoffmann };
3449d993394SGerd Hoffmann 
34571df1d83SMarkus Armbruster static int config_write_opt(void *opaque, const char *name, const char *value,
34671df1d83SMarkus Armbruster                             Error **errp)
3479d993394SGerd Hoffmann {
3489d993394SGerd Hoffmann     struct ConfigWriteData *data = opaque;
3499d993394SGerd Hoffmann 
3509d993394SGerd Hoffmann     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
3519d993394SGerd Hoffmann     return 0;
3529d993394SGerd Hoffmann }
3539d993394SGerd Hoffmann 
35428d0de7aSMarkus Armbruster static int config_write_opts(void *opaque, QemuOpts *opts, Error **errp)
3559d993394SGerd Hoffmann {
3569d993394SGerd Hoffmann     struct ConfigWriteData *data = opaque;
3579d993394SGerd Hoffmann     const char *id = qemu_opts_id(opts);
3589d993394SGerd Hoffmann 
3599d993394SGerd Hoffmann     if (id) {
3609d993394SGerd Hoffmann         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
3619d993394SGerd Hoffmann     } else {
3629d993394SGerd Hoffmann         fprintf(data->fp, "[%s]\n", data->list->name);
3639d993394SGerd Hoffmann     }
36471df1d83SMarkus Armbruster     qemu_opt_foreach(opts, config_write_opt, data, NULL);
3659d993394SGerd Hoffmann     fprintf(data->fp, "\n");
3669d993394SGerd Hoffmann     return 0;
3679d993394SGerd Hoffmann }
3689d993394SGerd Hoffmann 
3699d993394SGerd Hoffmann void qemu_config_write(FILE *fp)
3709d993394SGerd Hoffmann {
3719d993394SGerd Hoffmann     struct ConfigWriteData data = { .fp = fp };
372490b648eSKevin Wolf     QemuOptsList **lists = vm_config_groups;
3739d993394SGerd Hoffmann     int i;
3749d993394SGerd Hoffmann 
3759d993394SGerd Hoffmann     fprintf(fp, "# qemu config file\n\n");
3769d993394SGerd Hoffmann     for (i = 0; lists[i] != NULL; i++) {
3779d993394SGerd Hoffmann         data.list = lists[i];
37828d0de7aSMarkus Armbruster         qemu_opts_foreach(data.list, config_write_opts, &data, NULL);
3799d993394SGerd Hoffmann     }
3809d993394SGerd Hoffmann }
38142262ba8SGerd Hoffmann 
382490b648eSKevin Wolf int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
38342262ba8SGerd Hoffmann {
38442262ba8SGerd Hoffmann     char line[1024], group[64], id[64], arg[64], value[1024];
385cf5a65aaSMarkus Armbruster     Location loc;
38642262ba8SGerd Hoffmann     QemuOptsList *list = NULL;
3872ac20613SLuiz Capitulino     Error *local_err = NULL;
38842262ba8SGerd Hoffmann     QemuOpts *opts = NULL;
389cf5a65aaSMarkus Armbruster     int res = -1, lno = 0;
39042262ba8SGerd Hoffmann 
391cf5a65aaSMarkus Armbruster     loc_push_none(&loc);
39242262ba8SGerd Hoffmann     while (fgets(line, sizeof(line), fp) != NULL) {
393cf5a65aaSMarkus Armbruster         loc_set_file(fname, ++lno);
39442262ba8SGerd Hoffmann         if (line[0] == '\n') {
39542262ba8SGerd Hoffmann             /* skip empty lines */
39642262ba8SGerd Hoffmann             continue;
39742262ba8SGerd Hoffmann         }
39842262ba8SGerd Hoffmann         if (line[0] == '#') {
39942262ba8SGerd Hoffmann             /* comment */
40042262ba8SGerd Hoffmann             continue;
40142262ba8SGerd Hoffmann         }
40242262ba8SGerd Hoffmann         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
40342262ba8SGerd Hoffmann             /* group with id */
4042ac20613SLuiz Capitulino             list = find_list(lists, group, &local_err);
40584d18f06SMarkus Armbruster             if (local_err) {
406565f65d2SMarkus Armbruster                 error_report_err(local_err);
407cf5a65aaSMarkus Armbruster                 goto out;
4082ac20613SLuiz Capitulino             }
4098be7e7e4SLuiz Capitulino             opts = qemu_opts_create(list, id, 1, NULL);
41042262ba8SGerd Hoffmann             continue;
41142262ba8SGerd Hoffmann         }
41242262ba8SGerd Hoffmann         if (sscanf(line, "[%63[^]]]", group) == 1) {
41342262ba8SGerd Hoffmann             /* group without id */
4142ac20613SLuiz Capitulino             list = find_list(lists, group, &local_err);
41584d18f06SMarkus Armbruster             if (local_err) {
416565f65d2SMarkus Armbruster                 error_report_err(local_err);
417cf5a65aaSMarkus Armbruster                 goto out;
4182ac20613SLuiz Capitulino             }
41987ea75d5SPeter Crosthwaite             opts = qemu_opts_create(list, NULL, 0, &error_abort);
42042262ba8SGerd Hoffmann             continue;
42142262ba8SGerd Hoffmann         }
422d9f7e29eSEduardo Habkost         value[0] = '\0';
423d9f7e29eSEduardo Habkost         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
424d9f7e29eSEduardo Habkost             sscanf(line, " %63s = \"\"", arg) == 1) {
42542262ba8SGerd Hoffmann             /* arg = value */
42642262ba8SGerd Hoffmann             if (opts == NULL) {
427cf5a65aaSMarkus Armbruster                 error_report("no group defined");
428cf5a65aaSMarkus Armbruster                 goto out;
42942262ba8SGerd Hoffmann             }
430f43e47dbSMarkus Armbruster             qemu_opt_set(opts, arg, value, &local_err);
431f43e47dbSMarkus Armbruster             if (local_err) {
432f43e47dbSMarkus Armbruster                 error_report_err(local_err);
433cf5a65aaSMarkus Armbruster                 goto out;
43442262ba8SGerd Hoffmann             }
43542262ba8SGerd Hoffmann             continue;
43642262ba8SGerd Hoffmann         }
437cf5a65aaSMarkus Armbruster         error_report("parse error");
438cf5a65aaSMarkus Armbruster         goto out;
43942262ba8SGerd Hoffmann     }
440ef82516dSMarkus Armbruster     if (ferror(fp)) {
441ef82516dSMarkus Armbruster         error_report("error reading file");
442ef82516dSMarkus Armbruster         goto out;
443ef82516dSMarkus Armbruster     }
444cf5a65aaSMarkus Armbruster     res = 0;
445cf5a65aaSMarkus Armbruster out:
446cf5a65aaSMarkus Armbruster     loc_pop(&loc);
447cf5a65aaSMarkus Armbruster     return res;
44842262ba8SGerd Hoffmann }
449dcfb0939SKevin Wolf 
450dcfb0939SKevin Wolf int qemu_read_config_file(const char *filename)
451dcfb0939SKevin Wolf {
452dcfb0939SKevin Wolf     FILE *f = fopen(filename, "r");
453019e78baSKevin Wolf     int ret;
454019e78baSKevin Wolf 
455dcfb0939SKevin Wolf     if (f == NULL) {
456dcfb0939SKevin Wolf         return -errno;
457dcfb0939SKevin Wolf     }
458dcfb0939SKevin Wolf 
459019e78baSKevin Wolf     ret = qemu_config_parse(f, vm_config_groups, filename);
460dcfb0939SKevin Wolf     fclose(f);
461dcfb0939SKevin Wolf 
462019e78baSKevin Wolf     if (ret == 0) {
463dcfb0939SKevin Wolf         return 0;
464019e78baSKevin Wolf     } else {
465019e78baSKevin Wolf         return -EINVAL;
466019e78baSKevin Wolf     }
467dcfb0939SKevin Wolf }
468adf5c449SMax Reitz 
469adf5c449SMax Reitz static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
470adf5c449SMax Reitz                                        Error **errp)
471adf5c449SMax Reitz {
472adf5c449SMax Reitz     QemuOpts *subopts;
473adf5c449SMax Reitz     QDict *subqdict;
474adf5c449SMax Reitz     QList *list = NULL;
475adf5c449SMax Reitz     Error *local_err = NULL;
476adf5c449SMax Reitz     size_t orig_size, enum_size;
477adf5c449SMax Reitz     char *prefix;
478adf5c449SMax Reitz 
479adf5c449SMax Reitz     prefix = g_strdup_printf("%s.", opts->name);
480adf5c449SMax Reitz     qdict_extract_subqdict(options, &subqdict, prefix);
481adf5c449SMax Reitz     g_free(prefix);
482adf5c449SMax Reitz     orig_size = qdict_size(subqdict);
483adf5c449SMax Reitz     if (!orig_size) {
484adf5c449SMax Reitz         goto out;
485adf5c449SMax Reitz     }
486adf5c449SMax Reitz 
487adf5c449SMax Reitz     subopts = qemu_opts_create(opts, NULL, 0, &local_err);
48884d18f06SMarkus Armbruster     if (local_err) {
489adf5c449SMax Reitz         error_propagate(errp, local_err);
490adf5c449SMax Reitz         goto out;
491adf5c449SMax Reitz     }
492adf5c449SMax Reitz 
493adf5c449SMax Reitz     qemu_opts_absorb_qdict(subopts, subqdict, &local_err);
49484d18f06SMarkus Armbruster     if (local_err) {
495adf5c449SMax Reitz         error_propagate(errp, local_err);
496adf5c449SMax Reitz         goto out;
497adf5c449SMax Reitz     }
498adf5c449SMax Reitz 
499adf5c449SMax Reitz     enum_size = qdict_size(subqdict);
500adf5c449SMax Reitz     if (enum_size < orig_size && enum_size) {
501adf5c449SMax Reitz         error_setg(errp, "Unknown option '%s' for [%s]",
502adf5c449SMax Reitz                    qdict_first(subqdict)->key, opts->name);
503adf5c449SMax Reitz         goto out;
504adf5c449SMax Reitz     }
505adf5c449SMax Reitz 
506adf5c449SMax Reitz     if (enum_size) {
507adf5c449SMax Reitz         /* Multiple, enumerated sections */
508adf5c449SMax Reitz         QListEntry *list_entry;
509adf5c449SMax Reitz         unsigned i = 0;
510adf5c449SMax Reitz 
511adf5c449SMax Reitz         /* Not required anymore */
512adf5c449SMax Reitz         qemu_opts_del(subopts);
513adf5c449SMax Reitz 
514adf5c449SMax Reitz         qdict_array_split(subqdict, &list);
515adf5c449SMax Reitz         if (qdict_size(subqdict)) {
516adf5c449SMax Reitz             error_setg(errp, "Unused option '%s' for [%s]",
517adf5c449SMax Reitz                        qdict_first(subqdict)->key, opts->name);
518adf5c449SMax Reitz             goto out;
519adf5c449SMax Reitz         }
520adf5c449SMax Reitz 
521adf5c449SMax Reitz         QLIST_FOREACH_ENTRY(list, list_entry) {
522adf5c449SMax Reitz             QDict *section = qobject_to_qdict(qlist_entry_obj(list_entry));
523adf5c449SMax Reitz             char *opt_name;
524adf5c449SMax Reitz 
525ae39c4b2SMax Reitz             if (!section) {
526ae39c4b2SMax Reitz                 error_setg(errp, "[%s] section (index %u) does not consist of "
527ae39c4b2SMax Reitz                            "keys", opts->name, i);
528ae39c4b2SMax Reitz                 goto out;
529ae39c4b2SMax Reitz             }
530ae39c4b2SMax Reitz 
531adf5c449SMax Reitz             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
532adf5c449SMax Reitz             subopts = qemu_opts_create(opts, opt_name, 1, &local_err);
533adf5c449SMax Reitz             g_free(opt_name);
53484d18f06SMarkus Armbruster             if (local_err) {
535adf5c449SMax Reitz                 error_propagate(errp, local_err);
536adf5c449SMax Reitz                 goto out;
537adf5c449SMax Reitz             }
538adf5c449SMax Reitz 
539adf5c449SMax Reitz             qemu_opts_absorb_qdict(subopts, section, &local_err);
54084d18f06SMarkus Armbruster             if (local_err) {
541adf5c449SMax Reitz                 error_propagate(errp, local_err);
542adf5c449SMax Reitz                 qemu_opts_del(subopts);
543adf5c449SMax Reitz                 goto out;
544adf5c449SMax Reitz             }
545adf5c449SMax Reitz 
546adf5c449SMax Reitz             if (qdict_size(section)) {
547adf5c449SMax Reitz                 error_setg(errp, "[%s] section doesn't support the option '%s'",
548adf5c449SMax Reitz                            opts->name, qdict_first(section)->key);
549adf5c449SMax Reitz                 qemu_opts_del(subopts);
550adf5c449SMax Reitz                 goto out;
551adf5c449SMax Reitz             }
552adf5c449SMax Reitz         }
553adf5c449SMax Reitz     }
554adf5c449SMax Reitz 
555adf5c449SMax Reitz out:
556adf5c449SMax Reitz     QDECREF(subqdict);
557adf5c449SMax Reitz     QDECREF(list);
558adf5c449SMax Reitz }
559adf5c449SMax Reitz 
560adf5c449SMax Reitz void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
561adf5c449SMax Reitz                              Error **errp)
562adf5c449SMax Reitz {
563adf5c449SMax Reitz     int i;
564adf5c449SMax Reitz     Error *local_err = NULL;
565adf5c449SMax Reitz 
566adf5c449SMax Reitz     for (i = 0; lists[i]; i++) {
567adf5c449SMax Reitz         config_parse_qdict_section(options, lists[i], &local_err);
56884d18f06SMarkus Armbruster         if (local_err) {
569adf5c449SMax Reitz             error_propagate(errp, local_err);
570adf5c449SMax Reitz             return;
571adf5c449SMax Reitz         }
572adf5c449SMax Reitz     }
573adf5c449SMax Reitz }
574