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