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