xref: /openbmc/qemu/util/qemu-config.c (revision c63ca4ff)
1 #include "qemu/osdep.h"
2 #include "block/qdict.h" /* for qdict_extract_subqdict() */
3 #include "qapi/error.h"
4 #include "qapi/qapi-commands-misc.h"
5 #include "qapi/qmp/qdict.h"
6 #include "qapi/qmp/qlist.h"
7 #include "qemu/error-report.h"
8 #include "qemu/option.h"
9 #include "qemu/config-file.h"
10 
11 static QemuOptsList *vm_config_groups[48];
12 static QemuOptsList *drive_config_groups[5];
13 
14 static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
15                                Error **errp)
16 {
17     int i;
18 
19     for (i = 0; lists[i] != NULL; i++) {
20         if (strcmp(lists[i]->name, group) == 0)
21             break;
22     }
23     if (lists[i] == NULL) {
24         error_setg(errp, "There is no option group '%s'", group);
25     }
26     return lists[i];
27 }
28 
29 QemuOptsList *qemu_find_opts(const char *group)
30 {
31     QemuOptsList *ret;
32     Error *local_err = NULL;
33 
34     ret = find_list(vm_config_groups, group, &local_err);
35     if (local_err) {
36         error_report_err(local_err);
37     }
38 
39     return ret;
40 }
41 
42 QemuOpts *qemu_find_opts_singleton(const char *group)
43 {
44     QemuOptsList *list;
45     QemuOpts *opts;
46 
47     list = qemu_find_opts(group);
48     assert(list);
49     opts = qemu_opts_find(list, NULL);
50     if (!opts) {
51         opts = qemu_opts_create(list, NULL, 0, &error_abort);
52     }
53     return opts;
54 }
55 
56 static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
57 {
58     CommandLineParameterInfoList *param_list = NULL, *entry;
59     CommandLineParameterInfo *info;
60     int i;
61 
62     for (i = 0; desc[i].name != NULL; i++) {
63         info = g_malloc0(sizeof(*info));
64         info->name = g_strdup(desc[i].name);
65 
66         switch (desc[i].type) {
67         case QEMU_OPT_STRING:
68             info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
69             break;
70         case QEMU_OPT_BOOL:
71             info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
72             break;
73         case QEMU_OPT_NUMBER:
74             info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
75             break;
76         case QEMU_OPT_SIZE:
77             info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
78             break;
79         }
80 
81         if (desc[i].help) {
82             info->has_help = true;
83             info->help = g_strdup(desc[i].help);
84         }
85         if (desc[i].def_value_str) {
86             info->has_q_default = true;
87             info->q_default = g_strdup(desc[i].def_value_str);
88         }
89 
90         entry = g_malloc0(sizeof(*entry));
91         entry->value = info;
92         entry->next = param_list;
93         param_list = entry;
94     }
95 
96     return param_list;
97 }
98 
99 /* remove repeated entry from the info list */
100 static void cleanup_infolist(CommandLineParameterInfoList *head)
101 {
102     CommandLineParameterInfoList *pre_entry, *cur, *del_entry;
103 
104     cur = head;
105     while (cur->next) {
106         pre_entry = head;
107         while (pre_entry != cur->next) {
108             if (!strcmp(pre_entry->value->name, cur->next->value->name)) {
109                 del_entry = cur->next;
110                 cur->next = cur->next->next;
111                 del_entry->next = NULL;
112                 qapi_free_CommandLineParameterInfoList(del_entry);
113                 break;
114             }
115             pre_entry = pre_entry->next;
116         }
117         cur = cur->next;
118     }
119 }
120 
121 /* merge the description items of two parameter infolists */
122 static void connect_infolist(CommandLineParameterInfoList *head,
123                              CommandLineParameterInfoList *new)
124 {
125     CommandLineParameterInfoList *cur;
126 
127     cur = head;
128     while (cur->next) {
129         cur = cur->next;
130     }
131     cur->next = new;
132 }
133 
134 /* access all the local QemuOptsLists for drive option */
135 static CommandLineParameterInfoList *get_drive_infolist(void)
136 {
137     CommandLineParameterInfoList *head = NULL, *cur;
138     int i;
139 
140     for (i = 0; drive_config_groups[i] != NULL; i++) {
141         if (!head) {
142             head = query_option_descs(drive_config_groups[i]->desc);
143         } else {
144             cur = query_option_descs(drive_config_groups[i]->desc);
145             connect_infolist(head, cur);
146         }
147     }
148     cleanup_infolist(head);
149 
150     return head;
151 }
152 
153 /* restore machine options that are now machine's properties */
154 static QemuOptsList machine_opts = {
155     .merge_lists = true,
156     .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head),
157     .desc = {
158         {
159             .name = "type",
160             .type = QEMU_OPT_STRING,
161             .help = "emulated machine"
162         },{
163             .name = "accel",
164             .type = QEMU_OPT_STRING,
165             .help = "accelerator list",
166         },{
167             .name = "kernel_irqchip",
168             .type = QEMU_OPT_BOOL,
169             .help = "use KVM in-kernel irqchip",
170         },{
171             .name = "kvm_shadow_mem",
172             .type = QEMU_OPT_SIZE,
173             .help = "KVM shadow MMU size",
174         },{
175             .name = "kernel",
176             .type = QEMU_OPT_STRING,
177             .help = "Linux kernel image file",
178         },{
179             .name = "initrd",
180             .type = QEMU_OPT_STRING,
181             .help = "Linux initial ramdisk file",
182         },{
183             .name = "append",
184             .type = QEMU_OPT_STRING,
185             .help = "Linux kernel command line",
186         },{
187             .name = "dtb",
188             .type = QEMU_OPT_STRING,
189             .help = "Linux kernel device tree file",
190         },{
191             .name = "dumpdtb",
192             .type = QEMU_OPT_STRING,
193             .help = "Dump current dtb to a file and quit",
194         },{
195             .name = "phandle_start",
196             .type = QEMU_OPT_NUMBER,
197             .help = "The first phandle ID we may generate dynamically",
198         },{
199             .name = "dt_compatible",
200             .type = QEMU_OPT_STRING,
201             .help = "Overrides the \"compatible\" property of the dt root node",
202         },{
203             .name = "dump-guest-core",
204             .type = QEMU_OPT_BOOL,
205             .help = "Include guest memory in  a core dump",
206         },{
207             .name = "mem-merge",
208             .type = QEMU_OPT_BOOL,
209             .help = "enable/disable memory merge support",
210         },{
211             .name = "usb",
212             .type = QEMU_OPT_BOOL,
213             .help = "Set on/off to enable/disable usb",
214         },{
215             .name = "firmware",
216             .type = QEMU_OPT_STRING,
217             .help = "firmware image",
218         },{
219             .name = "iommu",
220             .type = QEMU_OPT_BOOL,
221             .help = "Set on/off to enable/disable Intel IOMMU (VT-d)",
222         },{
223             .name = "suppress-vmdesc",
224             .type = QEMU_OPT_BOOL,
225             .help = "Set on to disable self-describing migration",
226         },{
227             .name = "aes-key-wrap",
228             .type = QEMU_OPT_BOOL,
229             .help = "enable/disable AES key wrapping using the CPACF wrapping key",
230         },{
231             .name = "dea-key-wrap",
232             .type = QEMU_OPT_BOOL,
233             .help = "enable/disable DEA key wrapping using the CPACF wrapping key",
234         },{
235             .name = "loadparm",
236             .type = QEMU_OPT_STRING,
237             .help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars"
238                     " converted to upper case) to pass to machine"
239                     " loader, boot manager, and guest kernel",
240         },
241         { /* End of list */ }
242     }
243 };
244 
245 CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
246                                                           const char *option,
247                                                           Error **errp)
248 {
249     CommandLineOptionInfoList *conf_list = NULL, *entry;
250     CommandLineOptionInfo *info;
251     int i;
252 
253     for (i = 0; vm_config_groups[i] != NULL; i++) {
254         if (!has_option || !strcmp(option, vm_config_groups[i]->name)) {
255             info = g_malloc0(sizeof(*info));
256             info->option = g_strdup(vm_config_groups[i]->name);
257             if (!strcmp("drive", vm_config_groups[i]->name)) {
258                 info->parameters = get_drive_infolist();
259             } else if (!strcmp("machine", vm_config_groups[i]->name)) {
260                 info->parameters = query_option_descs(machine_opts.desc);
261             } else {
262                 info->parameters =
263                     query_option_descs(vm_config_groups[i]->desc);
264             }
265             entry = g_malloc0(sizeof(*entry));
266             entry->value = info;
267             entry->next = conf_list;
268             conf_list = entry;
269         }
270     }
271 
272     if (conf_list == NULL) {
273         error_setg(errp, "invalid option name: %s", option);
274     }
275 
276     return conf_list;
277 }
278 
279 QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
280 {
281     return find_list(vm_config_groups, group, errp);
282 }
283 
284 void qemu_add_drive_opts(QemuOptsList *list)
285 {
286     int entries, i;
287 
288     entries = ARRAY_SIZE(drive_config_groups);
289     entries--; /* keep list NULL terminated */
290     for (i = 0; i < entries; i++) {
291         if (drive_config_groups[i] == NULL) {
292             drive_config_groups[i] = list;
293             return;
294         }
295     }
296     fprintf(stderr, "ran out of space in drive_config_groups");
297     abort();
298 }
299 
300 void qemu_add_opts(QemuOptsList *list)
301 {
302     int entries, i;
303 
304     entries = ARRAY_SIZE(vm_config_groups);
305     entries--; /* keep list NULL terminated */
306     for (i = 0; i < entries; i++) {
307         if (vm_config_groups[i] == NULL) {
308             vm_config_groups[i] = list;
309             return;
310         }
311     }
312     fprintf(stderr, "ran out of space in vm_config_groups");
313     abort();
314 }
315 
316 struct ConfigWriteData {
317     QemuOptsList *list;
318     FILE *fp;
319 };
320 
321 static int config_write_opt(void *opaque, const char *name, const char *value,
322                             Error **errp)
323 {
324     struct ConfigWriteData *data = opaque;
325 
326     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
327     return 0;
328 }
329 
330 static int config_write_opts(void *opaque, QemuOpts *opts, Error **errp)
331 {
332     struct ConfigWriteData *data = opaque;
333     const char *id = qemu_opts_id(opts);
334 
335     if (id) {
336         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
337     } else {
338         fprintf(data->fp, "[%s]\n", data->list->name);
339     }
340     qemu_opt_foreach(opts, config_write_opt, data, NULL);
341     fprintf(data->fp, "\n");
342     return 0;
343 }
344 
345 void qemu_config_write(FILE *fp)
346 {
347     struct ConfigWriteData data = { .fp = fp };
348     QemuOptsList **lists = vm_config_groups;
349     int i;
350 
351     fprintf(fp, "# qemu config file\n\n");
352     for (i = 0; lists[i] != NULL; i++) {
353         data.list = lists[i];
354         qemu_opts_foreach(data.list, config_write_opts, &data, NULL);
355     }
356 }
357 
358 /* Returns number of config groups on success, -errno on error */
359 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
360 {
361     char line[1024], group[64], id[64], arg[64], value[1024];
362     Location loc;
363     QemuOptsList *list = NULL;
364     Error *local_err = NULL;
365     QemuOpts *opts = NULL;
366     int res = -EINVAL, lno = 0;
367     int count = 0;
368 
369     loc_push_none(&loc);
370     while (fgets(line, sizeof(line), fp) != NULL) {
371         loc_set_file(fname, ++lno);
372         if (line[0] == '\n') {
373             /* skip empty lines */
374             continue;
375         }
376         if (line[0] == '#') {
377             /* comment */
378             continue;
379         }
380         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
381             /* group with id */
382             list = find_list(lists, group, &local_err);
383             if (local_err) {
384                 error_report_err(local_err);
385                 goto out;
386             }
387             opts = qemu_opts_create(list, id, 1, NULL);
388             count++;
389             continue;
390         }
391         if (sscanf(line, "[%63[^]]]", group) == 1) {
392             /* group without id */
393             list = find_list(lists, group, &local_err);
394             if (local_err) {
395                 error_report_err(local_err);
396                 goto out;
397             }
398             opts = qemu_opts_create(list, NULL, 0, &error_abort);
399             count++;
400             continue;
401         }
402         value[0] = '\0';
403         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
404             sscanf(line, " %63s = \"\"", arg) == 1) {
405             /* arg = value */
406             if (opts == NULL) {
407                 error_report("no group defined");
408                 goto out;
409             }
410             if (!qemu_opt_set(opts, arg, value, &local_err)) {
411                 error_report_err(local_err);
412                 goto out;
413             }
414             continue;
415         }
416         error_report("parse error");
417         goto out;
418     }
419     if (ferror(fp)) {
420         error_report("error reading file");
421         goto out;
422     }
423     res = count;
424 out:
425     loc_pop(&loc);
426     return res;
427 }
428 
429 int qemu_read_config_file(const char *filename)
430 {
431     FILE *f = fopen(filename, "r");
432     int ret;
433 
434     if (f == NULL) {
435         return -errno;
436     }
437 
438     ret = qemu_config_parse(f, vm_config_groups, filename);
439     fclose(f);
440     return ret;
441 }
442 
443 static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
444                                        Error **errp)
445 {
446     QemuOpts *subopts;
447     QDict *subqdict;
448     QList *list = NULL;
449     size_t orig_size, enum_size;
450     char *prefix;
451 
452     prefix = g_strdup_printf("%s.", opts->name);
453     qdict_extract_subqdict(options, &subqdict, prefix);
454     g_free(prefix);
455     orig_size = qdict_size(subqdict);
456     if (!orig_size) {
457         goto out;
458     }
459 
460     subopts = qemu_opts_create(opts, NULL, 0, errp);
461     if (!subopts) {
462         goto out;
463     }
464 
465     if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) {
466         goto out;
467     }
468 
469     enum_size = qdict_size(subqdict);
470     if (enum_size < orig_size && enum_size) {
471         error_setg(errp, "Unknown option '%s' for [%s]",
472                    qdict_first(subqdict)->key, opts->name);
473         goto out;
474     }
475 
476     if (enum_size) {
477         /* Multiple, enumerated sections */
478         QListEntry *list_entry;
479         unsigned i = 0;
480 
481         /* Not required anymore */
482         qemu_opts_del(subopts);
483 
484         qdict_array_split(subqdict, &list);
485         if (qdict_size(subqdict)) {
486             error_setg(errp, "Unused option '%s' for [%s]",
487                        qdict_first(subqdict)->key, opts->name);
488             goto out;
489         }
490 
491         QLIST_FOREACH_ENTRY(list, list_entry) {
492             QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry));
493             char *opt_name;
494 
495             if (!section) {
496                 error_setg(errp, "[%s] section (index %u) does not consist of "
497                            "keys", opts->name, i);
498                 goto out;
499             }
500 
501             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
502             subopts = qemu_opts_create(opts, opt_name, 1, errp);
503             g_free(opt_name);
504             if (!subopts) {
505                 goto out;
506             }
507 
508             if (!qemu_opts_absorb_qdict(subopts, section, errp)) {
509                 qemu_opts_del(subopts);
510                 goto out;
511             }
512 
513             if (qdict_size(section)) {
514                 error_setg(errp, "[%s] section doesn't support the option '%s'",
515                            opts->name, qdict_first(section)->key);
516                 qemu_opts_del(subopts);
517                 goto out;
518             }
519         }
520     }
521 
522 out:
523     qobject_unref(subqdict);
524     qobject_unref(list);
525 }
526 
527 void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
528                              Error **errp)
529 {
530     int i;
531     Error *local_err = NULL;
532 
533     for (i = 0; lists[i]; i++) {
534         config_parse_qdict_section(options, lists[i], &local_err);
535         if (local_err) {
536             error_propagate(errp, local_err);
537             return;
538         }
539     }
540 }
541