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