xref: /openbmc/qemu/util/qemu-config.c (revision 7acafcfa)
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 int qemu_set_option(const char *str)
317 {
318     Error *local_err = NULL;
319     char group[64], id[64], arg[64];
320     QemuOptsList *list;
321     QemuOpts *opts;
322     int rc, offset;
323 
324     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
325     if (rc < 3 || str[offset] != '=') {
326         error_report("can't parse: \"%s\"", str);
327         return -1;
328     }
329 
330     list = qemu_find_opts(group);
331     if (list == NULL) {
332         return -1;
333     }
334 
335     opts = qemu_opts_find(list, id);
336     if (!opts) {
337         error_report("there is no %s \"%s\" defined",
338                      list->name, id);
339         return -1;
340     }
341 
342     if (!qemu_opt_set(opts, arg, str + offset + 1, &local_err)) {
343         error_report_err(local_err);
344         return -1;
345     }
346     return 0;
347 }
348 
349 struct ConfigWriteData {
350     QemuOptsList *list;
351     FILE *fp;
352 };
353 
354 static int config_write_opt(void *opaque, const char *name, const char *value,
355                             Error **errp)
356 {
357     struct ConfigWriteData *data = opaque;
358 
359     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
360     return 0;
361 }
362 
363 static int config_write_opts(void *opaque, QemuOpts *opts, Error **errp)
364 {
365     struct ConfigWriteData *data = opaque;
366     const char *id = qemu_opts_id(opts);
367 
368     if (id) {
369         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
370     } else {
371         fprintf(data->fp, "[%s]\n", data->list->name);
372     }
373     qemu_opt_foreach(opts, config_write_opt, data, NULL);
374     fprintf(data->fp, "\n");
375     return 0;
376 }
377 
378 void qemu_config_write(FILE *fp)
379 {
380     struct ConfigWriteData data = { .fp = fp };
381     QemuOptsList **lists = vm_config_groups;
382     int i;
383 
384     fprintf(fp, "# qemu config file\n\n");
385     for (i = 0; lists[i] != NULL; i++) {
386         data.list = lists[i];
387         qemu_opts_foreach(data.list, config_write_opts, &data, NULL);
388     }
389 }
390 
391 /* Returns number of config groups on success, -errno on error */
392 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
393 {
394     char line[1024], group[64], id[64], arg[64], value[1024];
395     Location loc;
396     QemuOptsList *list = NULL;
397     Error *local_err = NULL;
398     QemuOpts *opts = NULL;
399     int res = -EINVAL, lno = 0;
400     int count = 0;
401 
402     loc_push_none(&loc);
403     while (fgets(line, sizeof(line), fp) != NULL) {
404         loc_set_file(fname, ++lno);
405         if (line[0] == '\n') {
406             /* skip empty lines */
407             continue;
408         }
409         if (line[0] == '#') {
410             /* comment */
411             continue;
412         }
413         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
414             /* group with id */
415             list = find_list(lists, group, &local_err);
416             if (local_err) {
417                 error_report_err(local_err);
418                 goto out;
419             }
420             opts = qemu_opts_create(list, id, 1, NULL);
421             count++;
422             continue;
423         }
424         if (sscanf(line, "[%63[^]]]", group) == 1) {
425             /* group without id */
426             list = find_list(lists, group, &local_err);
427             if (local_err) {
428                 error_report_err(local_err);
429                 goto out;
430             }
431             opts = qemu_opts_create(list, NULL, 0, &error_abort);
432             count++;
433             continue;
434         }
435         value[0] = '\0';
436         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
437             sscanf(line, " %63s = \"\"", arg) == 1) {
438             /* arg = value */
439             if (opts == NULL) {
440                 error_report("no group defined");
441                 goto out;
442             }
443             if (!qemu_opt_set(opts, arg, value, &local_err)) {
444                 error_report_err(local_err);
445                 goto out;
446             }
447             continue;
448         }
449         error_report("parse error");
450         goto out;
451     }
452     if (ferror(fp)) {
453         error_report("error reading file");
454         goto out;
455     }
456     res = count;
457 out:
458     loc_pop(&loc);
459     return res;
460 }
461 
462 int qemu_read_config_file(const char *filename)
463 {
464     FILE *f = fopen(filename, "r");
465     int ret;
466 
467     if (f == NULL) {
468         return -errno;
469     }
470 
471     ret = qemu_config_parse(f, vm_config_groups, filename);
472     fclose(f);
473     return ret;
474 }
475 
476 static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
477                                        Error **errp)
478 {
479     QemuOpts *subopts;
480     QDict *subqdict;
481     QList *list = NULL;
482     size_t orig_size, enum_size;
483     char *prefix;
484 
485     prefix = g_strdup_printf("%s.", opts->name);
486     qdict_extract_subqdict(options, &subqdict, prefix);
487     g_free(prefix);
488     orig_size = qdict_size(subqdict);
489     if (!orig_size) {
490         goto out;
491     }
492 
493     subopts = qemu_opts_create(opts, NULL, 0, errp);
494     if (!subopts) {
495         goto out;
496     }
497 
498     if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) {
499         goto out;
500     }
501 
502     enum_size = qdict_size(subqdict);
503     if (enum_size < orig_size && enum_size) {
504         error_setg(errp, "Unknown option '%s' for [%s]",
505                    qdict_first(subqdict)->key, opts->name);
506         goto out;
507     }
508 
509     if (enum_size) {
510         /* Multiple, enumerated sections */
511         QListEntry *list_entry;
512         unsigned i = 0;
513 
514         /* Not required anymore */
515         qemu_opts_del(subopts);
516 
517         qdict_array_split(subqdict, &list);
518         if (qdict_size(subqdict)) {
519             error_setg(errp, "Unused option '%s' for [%s]",
520                        qdict_first(subqdict)->key, opts->name);
521             goto out;
522         }
523 
524         QLIST_FOREACH_ENTRY(list, list_entry) {
525             QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry));
526             char *opt_name;
527 
528             if (!section) {
529                 error_setg(errp, "[%s] section (index %u) does not consist of "
530                            "keys", opts->name, i);
531                 goto out;
532             }
533 
534             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
535             subopts = qemu_opts_create(opts, opt_name, 1, errp);
536             g_free(opt_name);
537             if (!subopts) {
538                 goto out;
539             }
540 
541             if (!qemu_opts_absorb_qdict(subopts, section, errp)) {
542                 qemu_opts_del(subopts);
543                 goto out;
544             }
545 
546             if (qdict_size(section)) {
547                 error_setg(errp, "[%s] section doesn't support the option '%s'",
548                            opts->name, qdict_first(section)->key);
549                 qemu_opts_del(subopts);
550                 goto out;
551             }
552         }
553     }
554 
555 out:
556     qobject_unref(subqdict);
557     qobject_unref(list);
558 }
559 
560 void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
561                              Error **errp)
562 {
563     int i;
564     Error *local_err = NULL;
565 
566     for (i = 0; lists[i]; i++) {
567         config_parse_qdict_section(options, lists[i], &local_err);
568         if (local_err) {
569             error_propagate(errp, local_err);
570             return;
571         }
572     }
573 }
574