xref: /openbmc/qemu/util/qemu-config.c (revision 52f91c37)
1 #include "qemu-common.h"
2 #include "qemu/error-report.h"
3 #include "qemu/option.h"
4 #include "qemu/config-file.h"
5 #include "qapi/qmp/qerror.h"
6 #include "hw/qdev.h"
7 #include "qapi/error.h"
8 #include "qmp-commands.h"
9 
10 static QemuOptsList *vm_config_groups[32];
11 static QemuOptsList *drive_config_groups[4];
12 
13 static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
14                                Error **errp)
15 {
16     int i;
17 
18     for (i = 0; lists[i] != NULL; i++) {
19         if (strcmp(lists[i]->name, group) == 0)
20             break;
21     }
22     if (lists[i] == NULL) {
23         error_setg(errp, "There is no option group '%s'", group);
24     }
25     return lists[i];
26 }
27 
28 QemuOptsList *qemu_find_opts(const char *group)
29 {
30     QemuOptsList *ret;
31     Error *local_err = NULL;
32 
33     ret = find_list(vm_config_groups, group, &local_err);
34     if (local_err) {
35         error_report("%s", error_get_pretty(local_err));
36         error_free(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 
86         entry = g_malloc0(sizeof(*entry));
87         entry->value = info;
88         entry->next = param_list;
89         param_list = entry;
90     }
91 
92     return param_list;
93 }
94 
95 /* remove repeated entry from the info list */
96 static void cleanup_infolist(CommandLineParameterInfoList *head)
97 {
98     CommandLineParameterInfoList *pre_entry, *cur, *del_entry;
99 
100     cur = head;
101     while (cur->next) {
102         pre_entry = head;
103         while (pre_entry != cur->next) {
104             if (!strcmp(pre_entry->value->name, cur->next->value->name)) {
105                 del_entry = cur->next;
106                 cur->next = cur->next->next;
107                 g_free(del_entry);
108                 break;
109             }
110             pre_entry = pre_entry->next;
111         }
112         cur = cur->next;
113     }
114 }
115 
116 /* merge the description items of two parameter infolists */
117 static void connect_infolist(CommandLineParameterInfoList *head,
118                              CommandLineParameterInfoList *new)
119 {
120     CommandLineParameterInfoList *cur;
121 
122     cur = head;
123     while (cur->next) {
124         cur = cur->next;
125     }
126     cur->next = new;
127 }
128 
129 /* access all the local QemuOptsLists for drive option */
130 static CommandLineParameterInfoList *get_drive_infolist(void)
131 {
132     CommandLineParameterInfoList *head = NULL, *cur;
133     int i;
134 
135     for (i = 0; drive_config_groups[i] != NULL; i++) {
136         if (!head) {
137             head = query_option_descs(drive_config_groups[i]->desc);
138         } else {
139             cur = query_option_descs(drive_config_groups[i]->desc);
140             connect_infolist(head, cur);
141         }
142     }
143     cleanup_infolist(head);
144 
145     return head;
146 }
147 
148 CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
149                                                           const char *option,
150                                                           Error **errp)
151 {
152     CommandLineOptionInfoList *conf_list = NULL, *entry;
153     CommandLineOptionInfo *info;
154     int i;
155 
156     for (i = 0; vm_config_groups[i] != NULL; i++) {
157         if (!has_option || !strcmp(option, vm_config_groups[i]->name)) {
158             info = g_malloc0(sizeof(*info));
159             info->option = g_strdup(vm_config_groups[i]->name);
160             if (!strcmp("drive", vm_config_groups[i]->name)) {
161                 info->parameters = get_drive_infolist();
162             } else {
163                 info->parameters =
164                     query_option_descs(vm_config_groups[i]->desc);
165             }
166             entry = g_malloc0(sizeof(*entry));
167             entry->value = info;
168             entry->next = conf_list;
169             conf_list = entry;
170         }
171     }
172 
173     if (conf_list == NULL) {
174         error_setg(errp, "invalid option name: %s", option);
175     }
176 
177     return conf_list;
178 }
179 
180 QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
181 {
182     return find_list(vm_config_groups, group, errp);
183 }
184 
185 void qemu_add_drive_opts(QemuOptsList *list)
186 {
187     int entries, i;
188 
189     entries = ARRAY_SIZE(drive_config_groups);
190     entries--; /* keep list NULL terminated */
191     for (i = 0; i < entries; i++) {
192         if (drive_config_groups[i] == NULL) {
193             drive_config_groups[i] = list;
194             return;
195         }
196     }
197     fprintf(stderr, "ran out of space in drive_config_groups");
198     abort();
199 }
200 
201 void qemu_add_opts(QemuOptsList *list)
202 {
203     int entries, i;
204 
205     entries = ARRAY_SIZE(vm_config_groups);
206     entries--; /* keep list NULL terminated */
207     for (i = 0; i < entries; i++) {
208         if (vm_config_groups[i] == NULL) {
209             vm_config_groups[i] = list;
210             return;
211         }
212     }
213     fprintf(stderr, "ran out of space in vm_config_groups");
214     abort();
215 }
216 
217 int qemu_set_option(const char *str)
218 {
219     char group[64], id[64], arg[64];
220     QemuOptsList *list;
221     QemuOpts *opts;
222     int rc, offset;
223 
224     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
225     if (rc < 3 || str[offset] != '=') {
226         error_report("can't parse: \"%s\"", str);
227         return -1;
228     }
229 
230     list = qemu_find_opts(group);
231     if (list == NULL) {
232         return -1;
233     }
234 
235     opts = qemu_opts_find(list, id);
236     if (!opts) {
237         error_report("there is no %s \"%s\" defined",
238                      list->name, id);
239         return -1;
240     }
241 
242     if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
243         return -1;
244     }
245     return 0;
246 }
247 
248 struct ConfigWriteData {
249     QemuOptsList *list;
250     FILE *fp;
251 };
252 
253 static int config_write_opt(const char *name, const char *value, void *opaque)
254 {
255     struct ConfigWriteData *data = opaque;
256 
257     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
258     return 0;
259 }
260 
261 static int config_write_opts(QemuOpts *opts, void *opaque)
262 {
263     struct ConfigWriteData *data = opaque;
264     const char *id = qemu_opts_id(opts);
265 
266     if (id) {
267         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
268     } else {
269         fprintf(data->fp, "[%s]\n", data->list->name);
270     }
271     qemu_opt_foreach(opts, config_write_opt, data, 0);
272     fprintf(data->fp, "\n");
273     return 0;
274 }
275 
276 void qemu_config_write(FILE *fp)
277 {
278     struct ConfigWriteData data = { .fp = fp };
279     QemuOptsList **lists = vm_config_groups;
280     int i;
281 
282     fprintf(fp, "# qemu config file\n\n");
283     for (i = 0; lists[i] != NULL; i++) {
284         data.list = lists[i];
285         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
286     }
287 }
288 
289 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
290 {
291     char line[1024], group[64], id[64], arg[64], value[1024];
292     Location loc;
293     QemuOptsList *list = NULL;
294     Error *local_err = NULL;
295     QemuOpts *opts = NULL;
296     int res = -1, lno = 0;
297 
298     loc_push_none(&loc);
299     while (fgets(line, sizeof(line), fp) != NULL) {
300         loc_set_file(fname, ++lno);
301         if (line[0] == '\n') {
302             /* skip empty lines */
303             continue;
304         }
305         if (line[0] == '#') {
306             /* comment */
307             continue;
308         }
309         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
310             /* group with id */
311             list = find_list(lists, group, &local_err);
312             if (local_err) {
313                 error_report("%s", error_get_pretty(local_err));
314                 error_free(local_err);
315                 goto out;
316             }
317             opts = qemu_opts_create(list, id, 1, NULL);
318             continue;
319         }
320         if (sscanf(line, "[%63[^]]]", group) == 1) {
321             /* group without id */
322             list = find_list(lists, group, &local_err);
323             if (local_err) {
324                 error_report("%s", error_get_pretty(local_err));
325                 error_free(local_err);
326                 goto out;
327             }
328             opts = qemu_opts_create(list, NULL, 0, &error_abort);
329             continue;
330         }
331         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
332             /* arg = value */
333             if (opts == NULL) {
334                 error_report("no group defined");
335                 goto out;
336             }
337             if (qemu_opt_set(opts, arg, value) != 0) {
338                 goto out;
339             }
340             continue;
341         }
342         error_report("parse error");
343         goto out;
344     }
345     if (ferror(fp)) {
346         error_report("error reading file");
347         goto out;
348     }
349     res = 0;
350 out:
351     loc_pop(&loc);
352     return res;
353 }
354 
355 int qemu_read_config_file(const char *filename)
356 {
357     FILE *f = fopen(filename, "r");
358     int ret;
359 
360     if (f == NULL) {
361         return -errno;
362     }
363 
364     ret = qemu_config_parse(f, vm_config_groups, filename);
365     fclose(f);
366 
367     if (ret == 0) {
368         return 0;
369     } else {
370         return -EINVAL;
371     }
372 }
373 
374 static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
375                                        Error **errp)
376 {
377     QemuOpts *subopts;
378     QDict *subqdict;
379     QList *list = NULL;
380     Error *local_err = NULL;
381     size_t orig_size, enum_size;
382     char *prefix;
383 
384     prefix = g_strdup_printf("%s.", opts->name);
385     qdict_extract_subqdict(options, &subqdict, prefix);
386     g_free(prefix);
387     orig_size = qdict_size(subqdict);
388     if (!orig_size) {
389         goto out;
390     }
391 
392     subopts = qemu_opts_create(opts, NULL, 0, &local_err);
393     if (local_err) {
394         error_propagate(errp, local_err);
395         goto out;
396     }
397 
398     qemu_opts_absorb_qdict(subopts, subqdict, &local_err);
399     if (local_err) {
400         error_propagate(errp, local_err);
401         goto out;
402     }
403 
404     enum_size = qdict_size(subqdict);
405     if (enum_size < orig_size && enum_size) {
406         error_setg(errp, "Unknown option '%s' for [%s]",
407                    qdict_first(subqdict)->key, opts->name);
408         goto out;
409     }
410 
411     if (enum_size) {
412         /* Multiple, enumerated sections */
413         QListEntry *list_entry;
414         unsigned i = 0;
415 
416         /* Not required anymore */
417         qemu_opts_del(subopts);
418 
419         qdict_array_split(subqdict, &list);
420         if (qdict_size(subqdict)) {
421             error_setg(errp, "Unused option '%s' for [%s]",
422                        qdict_first(subqdict)->key, opts->name);
423             goto out;
424         }
425 
426         QLIST_FOREACH_ENTRY(list, list_entry) {
427             QDict *section = qobject_to_qdict(qlist_entry_obj(list_entry));
428             char *opt_name;
429 
430             if (!section) {
431                 error_setg(errp, "[%s] section (index %u) does not consist of "
432                            "keys", opts->name, i);
433                 goto out;
434             }
435 
436             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
437             subopts = qemu_opts_create(opts, opt_name, 1, &local_err);
438             g_free(opt_name);
439             if (local_err) {
440                 error_propagate(errp, local_err);
441                 goto out;
442             }
443 
444             qemu_opts_absorb_qdict(subopts, section, &local_err);
445             if (local_err) {
446                 error_propagate(errp, local_err);
447                 qemu_opts_del(subopts);
448                 goto out;
449             }
450 
451             if (qdict_size(section)) {
452                 error_setg(errp, "[%s] section doesn't support the option '%s'",
453                            opts->name, qdict_first(section)->key);
454                 qemu_opts_del(subopts);
455                 goto out;
456             }
457         }
458     }
459 
460 out:
461     QDECREF(subqdict);
462     QDECREF(list);
463 }
464 
465 void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
466                              Error **errp)
467 {
468     int i;
469     Error *local_err = NULL;
470 
471     for (i = 0; lists[i]; i++) {
472         config_parse_qdict_section(options, lists[i], &local_err);
473         if (local_err) {
474             error_propagate(errp, local_err);
475             return;
476         }
477     }
478 }
479