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