xref: /qemu/util/qemu-config.c (revision 0b7e89b103b899c21b9ab37dbf9b832db8d18108)
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     char group[64], id[64], arg[64];
223     QemuOptsList *list;
224     QemuOpts *opts;
225     int rc, offset;
226 
227     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
228     if (rc < 3 || str[offset] != '=') {
229         error_report("can't parse: \"%s\"", str);
230         return -1;
231     }
232 
233     list = qemu_find_opts(group);
234     if (list == NULL) {
235         return -1;
236     }
237 
238     opts = qemu_opts_find(list, id);
239     if (!opts) {
240         error_report("there is no %s \"%s\" defined",
241                      list->name, id);
242         return -1;
243     }
244 
245     if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
246         return -1;
247     }
248     return 0;
249 }
250 
251 struct ConfigWriteData {
252     QemuOptsList *list;
253     FILE *fp;
254 };
255 
256 static int config_write_opt(const char *name, const char *value, void *opaque)
257 {
258     struct ConfigWriteData *data = opaque;
259 
260     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
261     return 0;
262 }
263 
264 static int config_write_opts(QemuOpts *opts, void *opaque)
265 {
266     struct ConfigWriteData *data = opaque;
267     const char *id = qemu_opts_id(opts);
268 
269     if (id) {
270         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
271     } else {
272         fprintf(data->fp, "[%s]\n", data->list->name);
273     }
274     qemu_opt_foreach(opts, config_write_opt, data, 0);
275     fprintf(data->fp, "\n");
276     return 0;
277 }
278 
279 void qemu_config_write(FILE *fp)
280 {
281     struct ConfigWriteData data = { .fp = fp };
282     QemuOptsList **lists = vm_config_groups;
283     int i;
284 
285     fprintf(fp, "# qemu config file\n\n");
286     for (i = 0; lists[i] != NULL; i++) {
287         data.list = lists[i];
288         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
289     }
290 }
291 
292 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
293 {
294     char line[1024], group[64], id[64], arg[64], value[1024];
295     Location loc;
296     QemuOptsList *list = NULL;
297     Error *local_err = NULL;
298     QemuOpts *opts = NULL;
299     int res = -1, lno = 0;
300 
301     loc_push_none(&loc);
302     while (fgets(line, sizeof(line), fp) != NULL) {
303         loc_set_file(fname, ++lno);
304         if (line[0] == '\n') {
305             /* skip empty lines */
306             continue;
307         }
308         if (line[0] == '#') {
309             /* comment */
310             continue;
311         }
312         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
313             /* group with id */
314             list = find_list(lists, group, &local_err);
315             if (local_err) {
316                 error_report_err(local_err);
317                 goto out;
318             }
319             opts = qemu_opts_create(list, id, 1, NULL);
320             continue;
321         }
322         if (sscanf(line, "[%63[^]]]", group) == 1) {
323             /* group without id */
324             list = find_list(lists, group, &local_err);
325             if (local_err) {
326                 error_report_err(local_err);
327                 goto out;
328             }
329             opts = qemu_opts_create(list, NULL, 0, &error_abort);
330             continue;
331         }
332         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
333             /* arg = value */
334             if (opts == NULL) {
335                 error_report("no group defined");
336                 goto out;
337             }
338             if (qemu_opt_set(opts, arg, value) != 0) {
339                 goto out;
340             }
341             continue;
342         }
343         error_report("parse error");
344         goto out;
345     }
346     if (ferror(fp)) {
347         error_report("error reading file");
348         goto out;
349     }
350     res = 0;
351 out:
352     loc_pop(&loc);
353     return res;
354 }
355 
356 int qemu_read_config_file(const char *filename)
357 {
358     FILE *f = fopen(filename, "r");
359     int ret;
360 
361     if (f == NULL) {
362         return -errno;
363     }
364 
365     ret = qemu_config_parse(f, vm_config_groups, filename);
366     fclose(f);
367 
368     if (ret == 0) {
369         return 0;
370     } else {
371         return -EINVAL;
372     }
373 }
374 
375 static void config_parse_qdict_section(QDict *options, QemuOptsList *opts,
376                                        Error **errp)
377 {
378     QemuOpts *subopts;
379     QDict *subqdict;
380     QList *list = NULL;
381     Error *local_err = NULL;
382     size_t orig_size, enum_size;
383     char *prefix;
384 
385     prefix = g_strdup_printf("%s.", opts->name);
386     qdict_extract_subqdict(options, &subqdict, prefix);
387     g_free(prefix);
388     orig_size = qdict_size(subqdict);
389     if (!orig_size) {
390         goto out;
391     }
392 
393     subopts = qemu_opts_create(opts, NULL, 0, &local_err);
394     if (local_err) {
395         error_propagate(errp, local_err);
396         goto out;
397     }
398 
399     qemu_opts_absorb_qdict(subopts, subqdict, &local_err);
400     if (local_err) {
401         error_propagate(errp, local_err);
402         goto out;
403     }
404 
405     enum_size = qdict_size(subqdict);
406     if (enum_size < orig_size && enum_size) {
407         error_setg(errp, "Unknown option '%s' for [%s]",
408                    qdict_first(subqdict)->key, opts->name);
409         goto out;
410     }
411 
412     if (enum_size) {
413         /* Multiple, enumerated sections */
414         QListEntry *list_entry;
415         unsigned i = 0;
416 
417         /* Not required anymore */
418         qemu_opts_del(subopts);
419 
420         qdict_array_split(subqdict, &list);
421         if (qdict_size(subqdict)) {
422             error_setg(errp, "Unused option '%s' for [%s]",
423                        qdict_first(subqdict)->key, opts->name);
424             goto out;
425         }
426 
427         QLIST_FOREACH_ENTRY(list, list_entry) {
428             QDict *section = qobject_to_qdict(qlist_entry_obj(list_entry));
429             char *opt_name;
430 
431             if (!section) {
432                 error_setg(errp, "[%s] section (index %u) does not consist of "
433                            "keys", opts->name, i);
434                 goto out;
435             }
436 
437             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
438             subopts = qemu_opts_create(opts, opt_name, 1, &local_err);
439             g_free(opt_name);
440             if (local_err) {
441                 error_propagate(errp, local_err);
442                 goto out;
443             }
444 
445             qemu_opts_absorb_qdict(subopts, section, &local_err);
446             if (local_err) {
447                 error_propagate(errp, local_err);
448                 qemu_opts_del(subopts);
449                 goto out;
450             }
451 
452             if (qdict_size(section)) {
453                 error_setg(errp, "[%s] section doesn't support the option '%s'",
454                            opts->name, qdict_first(section)->key);
455                 qemu_opts_del(subopts);
456                 goto out;
457             }
458         }
459     }
460 
461 out:
462     QDECREF(subqdict);
463     QDECREF(list);
464 }
465 
466 void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
467                              Error **errp)
468 {
469     int i;
470     Error *local_err = NULL;
471 
472     for (i = 0; lists[i]; i++) {
473         config_parse_qdict_section(options, lists[i], &local_err);
474         if (local_err) {
475             error_propagate(errp, local_err);
476             return;
477         }
478     }
479 }
480