xref: /openbmc/qemu/util/qemu-config.c (revision 6f1e91f7)
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"
5452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
647e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h"
7baacf047SPaolo Bonzini #include "qemu/error-report.h"
8baacf047SPaolo Bonzini #include "qemu/option.h"
9baacf047SPaolo Bonzini #include "qemu/config-file.h"
10*2f129fc1SThomas Huth #include "hw/boards.h"
11baacf047SPaolo Bonzini 
121ceaefbdSGerd Hoffmann static QemuOptsList *vm_config_groups[48];
13c5f3014bSKevin Wolf static QemuOptsList *drive_config_groups[5];
14baacf047SPaolo Bonzini 
find_list(QemuOptsList ** lists,const char * group,Error ** errp)15baacf047SPaolo Bonzini static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
16baacf047SPaolo Bonzini                                Error **errp)
17baacf047SPaolo Bonzini {
18baacf047SPaolo Bonzini     int i;
19baacf047SPaolo Bonzini 
20632a8873SPaolo Bonzini     qemu_load_module_for_opts(group);
21baacf047SPaolo Bonzini     for (i = 0; lists[i] != NULL; i++) {
22baacf047SPaolo Bonzini         if (strcmp(lists[i]->name, group) == 0)
23baacf047SPaolo Bonzini             break;
24baacf047SPaolo Bonzini     }
25baacf047SPaolo Bonzini     if (lists[i] == NULL) {
26f231b88dSCole Robinson         error_setg(errp, "There is no option group '%s'", group);
27baacf047SPaolo Bonzini     }
28baacf047SPaolo Bonzini     return lists[i];
29baacf047SPaolo Bonzini }
30baacf047SPaolo Bonzini 
qemu_find_opts(const char * group)31baacf047SPaolo Bonzini QemuOptsList *qemu_find_opts(const char *group)
32baacf047SPaolo Bonzini {
33baacf047SPaolo Bonzini     QemuOptsList *ret;
34baacf047SPaolo Bonzini     Error *local_err = NULL;
35baacf047SPaolo Bonzini 
36baacf047SPaolo Bonzini     ret = find_list(vm_config_groups, group, &local_err);
3784d18f06SMarkus Armbruster     if (local_err) {
38565f65d2SMarkus Armbruster         error_report_err(local_err);
39baacf047SPaolo Bonzini     }
40baacf047SPaolo Bonzini 
41baacf047SPaolo Bonzini     return ret;
42baacf047SPaolo Bonzini }
43baacf047SPaolo Bonzini 
qemu_find_opts_singleton(const char * group)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 
query_option_descs(const QemuOptDesc * desc)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         info->help = g_strdup(desc[i].help);
84e36af94fSChunyan Liu         info->q_default = g_strdup(desc[i].def_value_str);
851f8f987dSAmos Kong 
8654aa3de7SEric Blake         QAPI_LIST_PREPEND(param_list, info);
871f8f987dSAmos Kong     }
881f8f987dSAmos Kong 
891f8f987dSAmos Kong     return param_list;
901f8f987dSAmos Kong }
911f8f987dSAmos Kong 
92968854c8SAmos Kong /* remove repeated entry from the info list */
cleanup_infolist(CommandLineParameterInfoList * head)93968854c8SAmos Kong static void cleanup_infolist(CommandLineParameterInfoList *head)
94968854c8SAmos Kong {
95968854c8SAmos Kong     CommandLineParameterInfoList *pre_entry, *cur, *del_entry;
96968854c8SAmos Kong 
97968854c8SAmos Kong     cur = head;
98968854c8SAmos Kong     while (cur->next) {
99968854c8SAmos Kong         pre_entry = head;
100968854c8SAmos Kong         while (pre_entry != cur->next) {
101968854c8SAmos Kong             if (!strcmp(pre_entry->value->name, cur->next->value->name)) {
102968854c8SAmos Kong                 del_entry = cur->next;
103968854c8SAmos Kong                 cur->next = cur->next->next;
104b11e20fbSMarc-André Lureau                 del_entry->next = NULL;
105b11e20fbSMarc-André Lureau                 qapi_free_CommandLineParameterInfoList(del_entry);
106968854c8SAmos Kong                 break;
107968854c8SAmos Kong             }
108968854c8SAmos Kong             pre_entry = pre_entry->next;
109968854c8SAmos Kong         }
110968854c8SAmos Kong         cur = cur->next;
111968854c8SAmos Kong     }
112968854c8SAmos Kong }
113968854c8SAmos Kong 
114968854c8SAmos Kong /* merge the description items of two parameter infolists */
connect_infolist(CommandLineParameterInfoList * head,CommandLineParameterInfoList * new)115968854c8SAmos Kong static void connect_infolist(CommandLineParameterInfoList *head,
116968854c8SAmos Kong                              CommandLineParameterInfoList *new)
117968854c8SAmos Kong {
118968854c8SAmos Kong     CommandLineParameterInfoList *cur;
119968854c8SAmos Kong 
120968854c8SAmos Kong     cur = head;
121968854c8SAmos Kong     while (cur->next) {
122968854c8SAmos Kong         cur = cur->next;
123968854c8SAmos Kong     }
124968854c8SAmos Kong     cur->next = new;
125968854c8SAmos Kong }
126968854c8SAmos Kong 
127968854c8SAmos Kong /* access all the local QemuOptsLists for drive option */
get_drive_infolist(void)128968854c8SAmos Kong static CommandLineParameterInfoList *get_drive_infolist(void)
129968854c8SAmos Kong {
130968854c8SAmos Kong     CommandLineParameterInfoList *head = NULL, *cur;
131968854c8SAmos Kong     int i;
132968854c8SAmos Kong 
133968854c8SAmos Kong     for (i = 0; drive_config_groups[i] != NULL; i++) {
134968854c8SAmos Kong         if (!head) {
135968854c8SAmos Kong             head = query_option_descs(drive_config_groups[i]->desc);
136968854c8SAmos Kong         } else {
137968854c8SAmos Kong             cur = query_option_descs(drive_config_groups[i]->desc);
138968854c8SAmos Kong             connect_infolist(head, cur);
139968854c8SAmos Kong         }
140968854c8SAmos Kong     }
141968854c8SAmos Kong     cleanup_infolist(head);
142968854c8SAmos Kong 
143968854c8SAmos Kong     return head;
144968854c8SAmos Kong }
145968854c8SAmos Kong 
objprop_to_cmdline_prop(ObjectProperty * prop)146*2f129fc1SThomas Huth static CommandLineParameterInfo *objprop_to_cmdline_prop(ObjectProperty *prop)
1470a7cf217SMarcel Apfelbaum {
148*2f129fc1SThomas Huth     CommandLineParameterInfo *info;
149*2f129fc1SThomas Huth 
150*2f129fc1SThomas Huth     info = g_malloc0(sizeof(*info));
151*2f129fc1SThomas Huth     info->name = g_strdup(prop->name);
152*2f129fc1SThomas Huth 
153*2f129fc1SThomas Huth     if (g_str_equal(prop->type, "bool") || g_str_equal(prop->type, "OnOffAuto")) {
154*2f129fc1SThomas Huth         info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
155*2f129fc1SThomas Huth     } else if (g_str_equal(prop->type, "int")) {
156*2f129fc1SThomas Huth         info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
157*2f129fc1SThomas Huth     } else if (g_str_equal(prop->type, "size")) {
158*2f129fc1SThomas Huth         info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
159*2f129fc1SThomas Huth     } else {
160*2f129fc1SThomas Huth         info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
1610a7cf217SMarcel Apfelbaum     }
162*2f129fc1SThomas Huth 
163*2f129fc1SThomas Huth     if (prop->description) {
164*2f129fc1SThomas Huth         info->help = g_strdup(prop->description);
165*2f129fc1SThomas Huth     }
166*2f129fc1SThomas Huth 
167*2f129fc1SThomas Huth     return info;
168*2f129fc1SThomas Huth }
169*2f129fc1SThomas Huth 
query_all_machine_properties(void)170*2f129fc1SThomas Huth static CommandLineParameterInfoList *query_all_machine_properties(void)
171*2f129fc1SThomas Huth {
172*2f129fc1SThomas Huth     CommandLineParameterInfoList *params = NULL, *clpiter;
173*2f129fc1SThomas Huth     CommandLineParameterInfo *info;
174*2f129fc1SThomas Huth     GSList *machines, *curr_mach;
175*2f129fc1SThomas Huth     ObjectPropertyIterator op_iter;
176*2f129fc1SThomas Huth     ObjectProperty *prop;
177*2f129fc1SThomas Huth     bool is_new;
178*2f129fc1SThomas Huth 
179*2f129fc1SThomas Huth     machines = object_class_get_list(TYPE_MACHINE, false);
180*2f129fc1SThomas Huth     assert(machines);
181*2f129fc1SThomas Huth 
182*2f129fc1SThomas Huth     /* Loop over all machine classes */
183*2f129fc1SThomas Huth     for (curr_mach = machines; curr_mach; curr_mach = curr_mach->next) {
184*2f129fc1SThomas Huth         object_class_property_iter_init(&op_iter, curr_mach->data);
185*2f129fc1SThomas Huth         /* ... and over the properties of each machine: */
186*2f129fc1SThomas Huth         while ((prop = object_property_iter_next(&op_iter))) {
187*2f129fc1SThomas Huth             if (!prop->set) {
188*2f129fc1SThomas Huth                 continue;
189*2f129fc1SThomas Huth             }
190*2f129fc1SThomas Huth             /*
191*2f129fc1SThomas Huth              * Check whether the property has already been put into the list
192*2f129fc1SThomas Huth              * (via another machine class)
193*2f129fc1SThomas Huth              */
194*2f129fc1SThomas Huth             is_new = true;
195*2f129fc1SThomas Huth             for (clpiter = params; clpiter != NULL; clpiter = clpiter->next) {
196*2f129fc1SThomas Huth                 if (g_str_equal(clpiter->value->name, prop->name)) {
197*2f129fc1SThomas Huth                     is_new = false;
198*2f129fc1SThomas Huth                     break;
199*2f129fc1SThomas Huth                 }
200*2f129fc1SThomas Huth             }
201*2f129fc1SThomas Huth             /* If it hasn't been added before, add it now to the list */
202*2f129fc1SThomas Huth             if (is_new) {
203*2f129fc1SThomas Huth                 info = objprop_to_cmdline_prop(prop);
204*2f129fc1SThomas Huth                 QAPI_LIST_PREPEND(params, info);
205*2f129fc1SThomas Huth             }
206*2f129fc1SThomas Huth         }
207*2f129fc1SThomas Huth     }
208*2f129fc1SThomas Huth 
209*2f129fc1SThomas Huth     g_slist_free(machines);
210*2f129fc1SThomas Huth 
211*2f129fc1SThomas Huth     /* Add entry for the "type" parameter */
212*2f129fc1SThomas Huth     info = g_malloc0(sizeof(*info));
213*2f129fc1SThomas Huth     info->name = g_strdup("type");
214*2f129fc1SThomas Huth     info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
215*2f129fc1SThomas Huth     info->help = g_strdup("machine type");
216*2f129fc1SThomas Huth     QAPI_LIST_PREPEND(params, info);
217*2f129fc1SThomas Huth 
218*2f129fc1SThomas Huth     return params;
219*2f129fc1SThomas Huth }
2200a7cf217SMarcel Apfelbaum 
qmp_query_command_line_options(const char * option,Error ** errp)2219492718bSMarkus Armbruster CommandLineOptionInfoList *qmp_query_command_line_options(const char *option,
2221f8f987dSAmos Kong                                                           Error **errp)
2231f8f987dSAmos Kong {
22454aa3de7SEric Blake     CommandLineOptionInfoList *conf_list = NULL;
2251f8f987dSAmos Kong     CommandLineOptionInfo *info;
2261f8f987dSAmos Kong     int i;
2271f8f987dSAmos Kong 
2281f8f987dSAmos Kong     for (i = 0; vm_config_groups[i] != NULL; i++) {
2299492718bSMarkus Armbruster         if (!option || !strcmp(option, vm_config_groups[i]->name)) {
2301f8f987dSAmos Kong             info = g_malloc0(sizeof(*info));
2311f8f987dSAmos Kong             info->option = g_strdup(vm_config_groups[i]->name);
232968854c8SAmos Kong             if (!strcmp("drive", vm_config_groups[i]->name)) {
233968854c8SAmos Kong                 info->parameters = get_drive_infolist();
234968854c8SAmos Kong             } else {
235968854c8SAmos Kong                 info->parameters =
236968854c8SAmos Kong                     query_option_descs(vm_config_groups[i]->desc);
237968854c8SAmos Kong             }
23854aa3de7SEric Blake             QAPI_LIST_PREPEND(conf_list, info);
2391f8f987dSAmos Kong         }
2401f8f987dSAmos Kong     }
2411f8f987dSAmos Kong 
2429492718bSMarkus Armbruster     if (!option || !strcmp(option, "machine")) {
24340e07370SStefan Hajnoczi         info = g_malloc0(sizeof(*info));
24440e07370SStefan Hajnoczi         info->option = g_strdup("machine");
245*2f129fc1SThomas Huth         info->parameters = query_all_machine_properties();
24640e07370SStefan Hajnoczi         QAPI_LIST_PREPEND(conf_list, info);
24740e07370SStefan Hajnoczi     }
24840e07370SStefan Hajnoczi 
2491f8f987dSAmos Kong     if (conf_list == NULL) {
2501f8f987dSAmos Kong         error_setg(errp, "invalid option name: %s", option);
2511f8f987dSAmos Kong     }
2521f8f987dSAmos Kong 
2531f8f987dSAmos Kong     return conf_list;
2541f8f987dSAmos Kong }
2551f8f987dSAmos Kong 
qemu_find_opts_err(const char * group,Error ** errp)256baacf047SPaolo Bonzini QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
257baacf047SPaolo Bonzini {
258baacf047SPaolo Bonzini     return find_list(vm_config_groups, group, errp);
259baacf047SPaolo Bonzini }
260baacf047SPaolo Bonzini 
qemu_add_drive_opts(QemuOptsList * list)261968854c8SAmos Kong void qemu_add_drive_opts(QemuOptsList *list)
262968854c8SAmos Kong {
263968854c8SAmos Kong     int entries, i;
264968854c8SAmos Kong 
265968854c8SAmos Kong     entries = ARRAY_SIZE(drive_config_groups);
266968854c8SAmos Kong     entries--; /* keep list NULL terminated */
267968854c8SAmos Kong     for (i = 0; i < entries; i++) {
268968854c8SAmos Kong         if (drive_config_groups[i] == NULL) {
269968854c8SAmos Kong             drive_config_groups[i] = list;
270968854c8SAmos Kong             return;
271968854c8SAmos Kong         }
272968854c8SAmos Kong     }
273968854c8SAmos Kong     fprintf(stderr, "ran out of space in drive_config_groups");
274968854c8SAmos Kong     abort();
275968854c8SAmos Kong }
276968854c8SAmos Kong 
qemu_add_opts(QemuOptsList * list)277baacf047SPaolo Bonzini void qemu_add_opts(QemuOptsList *list)
278baacf047SPaolo Bonzini {
279baacf047SPaolo Bonzini     int entries, i;
280baacf047SPaolo Bonzini 
281baacf047SPaolo Bonzini     entries = ARRAY_SIZE(vm_config_groups);
282baacf047SPaolo Bonzini     entries--; /* keep list NULL terminated */
283baacf047SPaolo Bonzini     for (i = 0; i < entries; i++) {
284baacf047SPaolo Bonzini         if (vm_config_groups[i] == NULL) {
285baacf047SPaolo Bonzini             vm_config_groups[i] = list;
286baacf047SPaolo Bonzini             return;
287baacf047SPaolo Bonzini         }
288baacf047SPaolo Bonzini     }
289baacf047SPaolo Bonzini     fprintf(stderr, "ran out of space in vm_config_groups");
290baacf047SPaolo Bonzini     abort();
291baacf047SPaolo Bonzini }
292baacf047SPaolo Bonzini 
293e5766d6eSEduardo Habkost /* Returns number of config groups on success, -errno on error */
qemu_config_foreach(FILE * fp,QEMUConfigCB * cb,void * opaque,const char * fname,Error ** errp)29437701411SPaolo Bonzini static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque,
29537701411SPaolo Bonzini                                const char *fname, Error **errp)
296baacf047SPaolo Bonzini {
2970a3090b1SMarkus Armbruster     ERRP_GUARD();
29837701411SPaolo Bonzini     char line[1024], prev_group[64], group[64], arg[64], value[1024];
299baacf047SPaolo Bonzini     Location loc;
30037701411SPaolo Bonzini     QDict *qdict = NULL;
301e5766d6eSEduardo Habkost     int res = -EINVAL, lno = 0;
302e5766d6eSEduardo Habkost     int count = 0;
303baacf047SPaolo Bonzini 
304baacf047SPaolo Bonzini     loc_push_none(&loc);
305baacf047SPaolo Bonzini     while (fgets(line, sizeof(line), fp) != NULL) {
30637701411SPaolo Bonzini         ++lno;
307baacf047SPaolo Bonzini         if (line[0] == '\n') {
308baacf047SPaolo Bonzini             /* skip empty lines */
309baacf047SPaolo Bonzini             continue;
310baacf047SPaolo Bonzini         }
311baacf047SPaolo Bonzini         if (line[0] == '#') {
312baacf047SPaolo Bonzini             /* comment */
313baacf047SPaolo Bonzini             continue;
314baacf047SPaolo Bonzini         }
31537701411SPaolo Bonzini         if (line[0] == '[') {
31637701411SPaolo Bonzini             QDict *prev = qdict;
31737701411SPaolo Bonzini             if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) {
31837701411SPaolo Bonzini                 qdict = qdict_new();
31937701411SPaolo Bonzini                 qdict_put_str(qdict, "id", value);
32037701411SPaolo Bonzini                 count++;
32137701411SPaolo Bonzini             } else if (sscanf(line, "[%63[^]]]", group) == 1) {
32237701411SPaolo Bonzini                 qdict = qdict_new();
32337701411SPaolo Bonzini                 count++;
32437701411SPaolo Bonzini             }
32537701411SPaolo Bonzini             if (qdict != prev) {
32637701411SPaolo Bonzini                 if (prev) {
3270a3090b1SMarkus Armbruster                     cb(prev_group, prev, opaque, errp);
32837701411SPaolo Bonzini                     qobject_unref(prev);
3290a3090b1SMarkus Armbruster                     if (*errp) {
330baacf047SPaolo Bonzini                         goto out;
331baacf047SPaolo Bonzini                     }
33237701411SPaolo Bonzini                 }
33337701411SPaolo Bonzini                 strcpy(prev_group, group);
334baacf047SPaolo Bonzini                 continue;
335baacf047SPaolo Bonzini             }
336baacf047SPaolo Bonzini         }
33737701411SPaolo Bonzini         loc_set_file(fname, lno);
338d9f7e29eSEduardo Habkost         value[0] = '\0';
339d9f7e29eSEduardo Habkost         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
340d9f7e29eSEduardo Habkost             sscanf(line, " %63s = \"\"", arg) == 1) {
341baacf047SPaolo Bonzini             /* arg = value */
34237701411SPaolo Bonzini             if (qdict == NULL) {
343f7544edcSPaolo Bonzini                 error_setg(errp, "no group defined");
344baacf047SPaolo Bonzini                 goto out;
345baacf047SPaolo Bonzini             }
34637701411SPaolo Bonzini             qdict_put_str(qdict, arg, value);
347baacf047SPaolo Bonzini             continue;
348baacf047SPaolo Bonzini         }
349f7544edcSPaolo Bonzini         error_setg(errp, "parse error");
350baacf047SPaolo Bonzini         goto out;
351baacf047SPaolo Bonzini     }
352baacf047SPaolo Bonzini     if (ferror(fp)) {
353f7544edcSPaolo Bonzini         loc_pop(&loc);
354f7544edcSPaolo Bonzini         error_setg_errno(errp, errno, "Cannot read config file");
355461fea9bSPaolo Bonzini         goto out_no_loc;
356baacf047SPaolo Bonzini     }
357e5766d6eSEduardo Habkost     res = count;
35837701411SPaolo Bonzini     if (qdict) {
35937701411SPaolo Bonzini         cb(group, qdict, opaque, errp);
36037701411SPaolo Bonzini     }
361e72f9524SPaolo Bonzini out:
362baacf047SPaolo Bonzini     loc_pop(&loc);
363461fea9bSPaolo Bonzini out_no_loc:
364e72f9524SPaolo Bonzini     qobject_unref(qdict);
365baacf047SPaolo Bonzini     return res;
366baacf047SPaolo Bonzini }
367baacf047SPaolo Bonzini 
qemu_config_do_parse(const char * group,QDict * qdict,void * opaque,Error ** errp)36837701411SPaolo Bonzini void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp)
36937701411SPaolo Bonzini {
37037701411SPaolo Bonzini     QemuOptsList **lists = opaque;
37137701411SPaolo Bonzini     QemuOptsList *list;
37237701411SPaolo Bonzini 
37337701411SPaolo Bonzini     list = find_list(lists, group, errp);
37437701411SPaolo Bonzini     if (!list) {
37537701411SPaolo Bonzini         return;
37637701411SPaolo Bonzini     }
37737701411SPaolo Bonzini 
378e7d85d95SPaolo Bonzini     qemu_opts_from_qdict(list, qdict, errp);
37937701411SPaolo Bonzini }
38037701411SPaolo Bonzini 
qemu_config_parse(FILE * fp,QemuOptsList ** lists,const char * fname,Error ** errp)38137701411SPaolo Bonzini int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
38237701411SPaolo Bonzini {
38337701411SPaolo Bonzini     return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp);
38437701411SPaolo Bonzini }
38537701411SPaolo Bonzini 
qemu_read_config_file(const char * filename,QEMUConfigCB * cb,Error ** errp)38637701411SPaolo Bonzini int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp)
387baacf047SPaolo Bonzini {
388baacf047SPaolo Bonzini     FILE *f = fopen(filename, "r");
389baacf047SPaolo Bonzini     int ret;
390baacf047SPaolo Bonzini 
391baacf047SPaolo Bonzini     if (f == NULL) {
392f7544edcSPaolo Bonzini         error_setg_file_open(errp, errno, filename);
393baacf047SPaolo Bonzini         return -errno;
394baacf047SPaolo Bonzini     }
395baacf047SPaolo Bonzini 
39637701411SPaolo Bonzini     ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp);
397baacf047SPaolo Bonzini     fclose(f);
398e5766d6eSEduardo Habkost     return ret;
399baacf047SPaolo Bonzini }
400adf5c449SMax Reitz 
config_parse_qdict_section(QDict * options,QemuOptsList * opts,Error ** errp)401f766e6dcSMarkus Armbruster static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts,
402adf5c449SMax Reitz                                        Error **errp)
403adf5c449SMax Reitz {
404adf5c449SMax Reitz     QemuOpts *subopts;
405f766e6dcSMarkus Armbruster     g_autoptr(QDict) subqdict = NULL;
406f766e6dcSMarkus Armbruster     g_autoptr(QList) list = NULL;
407adf5c449SMax Reitz     size_t orig_size, enum_size;
408adf5c449SMax Reitz     char *prefix;
409adf5c449SMax Reitz 
410adf5c449SMax Reitz     prefix = g_strdup_printf("%s.", opts->name);
411adf5c449SMax Reitz     qdict_extract_subqdict(options, &subqdict, prefix);
412adf5c449SMax Reitz     g_free(prefix);
413adf5c449SMax Reitz     orig_size = qdict_size(subqdict);
414adf5c449SMax Reitz     if (!orig_size) {
415f766e6dcSMarkus Armbruster         return true;
416adf5c449SMax Reitz     }
417adf5c449SMax Reitz 
418c6ecec43SMarkus Armbruster     subopts = qemu_opts_create(opts, NULL, 0, errp);
419c6ecec43SMarkus Armbruster     if (!subopts) {
420f766e6dcSMarkus Armbruster         return false;
421adf5c449SMax Reitz     }
422adf5c449SMax Reitz 
423668f62ecSMarkus Armbruster     if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) {
424f766e6dcSMarkus Armbruster         return false;
425adf5c449SMax Reitz     }
426adf5c449SMax Reitz 
427adf5c449SMax Reitz     enum_size = qdict_size(subqdict);
428adf5c449SMax Reitz     if (enum_size < orig_size && enum_size) {
429adf5c449SMax Reitz         error_setg(errp, "Unknown option '%s' for [%s]",
430adf5c449SMax Reitz                    qdict_first(subqdict)->key, opts->name);
431f766e6dcSMarkus Armbruster         return false;
432adf5c449SMax Reitz     }
433adf5c449SMax Reitz 
434adf5c449SMax Reitz     if (enum_size) {
435adf5c449SMax Reitz         /* Multiple, enumerated sections */
436adf5c449SMax Reitz         QListEntry *list_entry;
437adf5c449SMax Reitz         unsigned i = 0;
438adf5c449SMax Reitz 
439adf5c449SMax Reitz         /* Not required anymore */
440adf5c449SMax Reitz         qemu_opts_del(subopts);
441adf5c449SMax Reitz 
442adf5c449SMax Reitz         qdict_array_split(subqdict, &list);
443adf5c449SMax Reitz         if (qdict_size(subqdict)) {
444adf5c449SMax Reitz             error_setg(errp, "Unused option '%s' for [%s]",
445adf5c449SMax Reitz                        qdict_first(subqdict)->key, opts->name);
446f766e6dcSMarkus Armbruster             return false;
447adf5c449SMax Reitz         }
448adf5c449SMax Reitz 
449adf5c449SMax Reitz         QLIST_FOREACH_ENTRY(list, list_entry) {
4507dc847ebSMax Reitz             QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry));
451adf5c449SMax Reitz             char *opt_name;
452adf5c449SMax Reitz 
453ae39c4b2SMax Reitz             if (!section) {
454ae39c4b2SMax Reitz                 error_setg(errp, "[%s] section (index %u) does not consist of "
455ae39c4b2SMax Reitz                            "keys", opts->name, i);
456f766e6dcSMarkus Armbruster                 return false;
457ae39c4b2SMax Reitz             }
458ae39c4b2SMax Reitz 
459adf5c449SMax Reitz             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
460c6ecec43SMarkus Armbruster             subopts = qemu_opts_create(opts, opt_name, 1, errp);
461adf5c449SMax Reitz             g_free(opt_name);
462c6ecec43SMarkus Armbruster             if (!subopts) {
463f766e6dcSMarkus Armbruster                 return false;
464adf5c449SMax Reitz             }
465adf5c449SMax Reitz 
466668f62ecSMarkus Armbruster             if (!qemu_opts_absorb_qdict(subopts, section, errp)) {
467adf5c449SMax Reitz                 qemu_opts_del(subopts);
468f766e6dcSMarkus Armbruster                 return false;
469adf5c449SMax Reitz             }
470adf5c449SMax Reitz 
471adf5c449SMax Reitz             if (qdict_size(section)) {
472adf5c449SMax Reitz                 error_setg(errp, "[%s] section doesn't support the option '%s'",
473adf5c449SMax Reitz                            opts->name, qdict_first(section)->key);
474adf5c449SMax Reitz                 qemu_opts_del(subopts);
475f766e6dcSMarkus Armbruster                 return false;
476adf5c449SMax Reitz             }
477adf5c449SMax Reitz         }
478adf5c449SMax Reitz     }
479adf5c449SMax Reitz 
480f766e6dcSMarkus Armbruster     return true;
481adf5c449SMax Reitz }
482adf5c449SMax Reitz 
qemu_config_parse_qdict(QDict * options,QemuOptsList ** lists,Error ** errp)483f766e6dcSMarkus Armbruster bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
484adf5c449SMax Reitz                              Error **errp)
485adf5c449SMax Reitz {
486adf5c449SMax Reitz     int i;
487adf5c449SMax Reitz 
488adf5c449SMax Reitz     for (i = 0; lists[i]; i++) {
489f766e6dcSMarkus Armbruster         if (!config_parse_qdict_section(options, lists[i], errp)) {
490f766e6dcSMarkus Armbruster             return false;
491adf5c449SMax Reitz         }
492adf5c449SMax Reitz     }
493f766e6dcSMarkus Armbruster 
494f766e6dcSMarkus Armbruster     return true;
495adf5c449SMax Reitz }
496