1aafd7584SPeter Maydell #include "qemu/osdep.h"
2609f45eaSMax Reitz #include "block/qdict.h" /* for qdict_extract_subqdict() */
3e688df6bSMarkus Armbruster #include "qapi/error.h"
4*407bc4bfSDaniel P. Berrangé #include "qobject/qdict.h"
5*407bc4bfSDaniel P. Berrangé #include "qobject/qlist.h"
61de7afc9SPaolo Bonzini #include "qemu/error-report.h"
71de7afc9SPaolo Bonzini #include "qemu/option.h"
81de7afc9SPaolo Bonzini #include "qemu/config-file.h"
97282a033SGerd Hoffmann
103df4c288SPhilippe Mathieu-Daudé QemuOptsList *vm_config_groups[48];
113df4c288SPhilippe Mathieu-Daudé QemuOptsList *drive_config_groups[5];
12d058fe03SGerd Hoffmann
find_list(QemuOptsList ** lists,const char * group,Error ** errp)132ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
142ac20613SLuiz Capitulino Error **errp)
15d058fe03SGerd Hoffmann {
16ddc97855SGerd Hoffmann int i;
17d058fe03SGerd Hoffmann
18632a8873SPaolo Bonzini qemu_load_module_for_opts(group);
19d058fe03SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) {
20d058fe03SGerd Hoffmann if (strcmp(lists[i]->name, group) == 0)
21d058fe03SGerd Hoffmann break;
22d058fe03SGerd Hoffmann }
23d058fe03SGerd Hoffmann if (lists[i] == NULL) {
24f231b88dSCole Robinson error_setg(errp, "There is no option group '%s'", group);
25ddc97855SGerd Hoffmann }
26ddc97855SGerd Hoffmann return lists[i];
27ddc97855SGerd Hoffmann }
28ddc97855SGerd Hoffmann
qemu_find_opts(const char * group)29490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group)
30490b648eSKevin Wolf {
312ac20613SLuiz Capitulino QemuOptsList *ret;
322ac20613SLuiz Capitulino Error *local_err = NULL;
332ac20613SLuiz Capitulino
342ac20613SLuiz Capitulino ret = find_list(vm_config_groups, group, &local_err);
3584d18f06SMarkus Armbruster if (local_err) {
36565f65d2SMarkus Armbruster error_report_err(local_err);
372ac20613SLuiz Capitulino }
382ac20613SLuiz Capitulino
392ac20613SLuiz Capitulino return ret;
40490b648eSKevin Wolf }
41490b648eSKevin Wolf
qemu_find_opts_singleton(const char * group)42e96e5ae8SPaolo Bonzini QemuOpts *qemu_find_opts_singleton(const char *group)
43e96e5ae8SPaolo Bonzini {
44e96e5ae8SPaolo Bonzini QemuOptsList *list;
45e96e5ae8SPaolo Bonzini QemuOpts *opts;
46e96e5ae8SPaolo Bonzini
47e96e5ae8SPaolo Bonzini list = qemu_find_opts(group);
48e96e5ae8SPaolo Bonzini assert(list);
49e96e5ae8SPaolo Bonzini opts = qemu_opts_find(list, NULL);
50e96e5ae8SPaolo Bonzini if (!opts) {
51e96e5ae8SPaolo Bonzini opts = qemu_opts_create(list, NULL, 0, &error_abort);
52e96e5ae8SPaolo Bonzini }
53e96e5ae8SPaolo Bonzini return opts;
54e96e5ae8SPaolo Bonzini }
55e96e5ae8SPaolo Bonzini
qemu_find_opts_err(const char * group,Error ** errp)5660d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
5760d5666fSLuiz Capitulino {
5860d5666fSLuiz Capitulino return find_list(vm_config_groups, group, errp);
5960d5666fSLuiz Capitulino }
6060d5666fSLuiz Capitulino
qemu_add_drive_opts(QemuOptsList * list)61968854c8SAmos Kong void qemu_add_drive_opts(QemuOptsList *list)
62968854c8SAmos Kong {
63968854c8SAmos Kong int entries, i;
64968854c8SAmos Kong
65968854c8SAmos Kong entries = ARRAY_SIZE(drive_config_groups);
66968854c8SAmos Kong entries--; /* keep list NULL terminated */
67968854c8SAmos Kong for (i = 0; i < entries; i++) {
68968854c8SAmos Kong if (drive_config_groups[i] == NULL) {
69968854c8SAmos Kong drive_config_groups[i] = list;
70968854c8SAmos Kong return;
71968854c8SAmos Kong }
72968854c8SAmos Kong }
73968854c8SAmos Kong fprintf(stderr, "ran out of space in drive_config_groups");
74968854c8SAmos Kong abort();
75968854c8SAmos Kong }
76968854c8SAmos Kong
qemu_add_opts(QemuOptsList * list)77dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list)
78dfe795e7SGerd Hoffmann {
79dfe795e7SGerd Hoffmann int entries, i;
80dfe795e7SGerd Hoffmann
81dfe795e7SGerd Hoffmann entries = ARRAY_SIZE(vm_config_groups);
82dfe795e7SGerd Hoffmann entries--; /* keep list NULL terminated */
83dfe795e7SGerd Hoffmann for (i = 0; i < entries; i++) {
84dfe795e7SGerd Hoffmann if (vm_config_groups[i] == NULL) {
85dfe795e7SGerd Hoffmann vm_config_groups[i] = list;
86dfe795e7SGerd Hoffmann return;
87dfe795e7SGerd Hoffmann }
88dfe795e7SGerd Hoffmann }
89dfe795e7SGerd Hoffmann fprintf(stderr, "ran out of space in vm_config_groups");
90dfe795e7SGerd Hoffmann abort();
91dfe795e7SGerd Hoffmann }
92dfe795e7SGerd Hoffmann
93e5766d6eSEduardo Habkost /* Returns number of config groups on success, -errno on error */
qemu_config_foreach(FILE * fp,QEMUConfigCB * cb,void * opaque,const char * fname,Error ** errp)9437701411SPaolo Bonzini static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque,
9537701411SPaolo Bonzini const char *fname, Error **errp)
9642262ba8SGerd Hoffmann {
970a3090b1SMarkus Armbruster ERRP_GUARD();
9837701411SPaolo Bonzini char line[1024], prev_group[64], group[64], arg[64], value[1024];
99cf5a65aaSMarkus Armbruster Location loc;
10037701411SPaolo Bonzini QDict *qdict = NULL;
101e5766d6eSEduardo Habkost int res = -EINVAL, lno = 0;
102e5766d6eSEduardo Habkost int count = 0;
10342262ba8SGerd Hoffmann
104cf5a65aaSMarkus Armbruster loc_push_none(&loc);
10542262ba8SGerd Hoffmann while (fgets(line, sizeof(line), fp) != NULL) {
10637701411SPaolo Bonzini ++lno;
10742262ba8SGerd Hoffmann if (line[0] == '\n') {
10842262ba8SGerd Hoffmann /* skip empty lines */
10942262ba8SGerd Hoffmann continue;
11042262ba8SGerd Hoffmann }
11142262ba8SGerd Hoffmann if (line[0] == '#') {
11242262ba8SGerd Hoffmann /* comment */
11342262ba8SGerd Hoffmann continue;
11442262ba8SGerd Hoffmann }
11537701411SPaolo Bonzini if (line[0] == '[') {
11637701411SPaolo Bonzini QDict *prev = qdict;
11737701411SPaolo Bonzini if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) {
11837701411SPaolo Bonzini qdict = qdict_new();
11937701411SPaolo Bonzini qdict_put_str(qdict, "id", value);
12037701411SPaolo Bonzini count++;
12137701411SPaolo Bonzini } else if (sscanf(line, "[%63[^]]]", group) == 1) {
12237701411SPaolo Bonzini qdict = qdict_new();
12337701411SPaolo Bonzini count++;
12437701411SPaolo Bonzini }
12537701411SPaolo Bonzini if (qdict != prev) {
12637701411SPaolo Bonzini if (prev) {
1270a3090b1SMarkus Armbruster cb(prev_group, prev, opaque, errp);
12837701411SPaolo Bonzini qobject_unref(prev);
1290a3090b1SMarkus Armbruster if (*errp) {
130cf5a65aaSMarkus Armbruster goto out;
1312ac20613SLuiz Capitulino }
13237701411SPaolo Bonzini }
13337701411SPaolo Bonzini strcpy(prev_group, group);
13442262ba8SGerd Hoffmann continue;
13542262ba8SGerd Hoffmann }
1362ac20613SLuiz Capitulino }
13737701411SPaolo Bonzini loc_set_file(fname, lno);
138d9f7e29eSEduardo Habkost value[0] = '\0';
139d9f7e29eSEduardo Habkost if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
140d9f7e29eSEduardo Habkost sscanf(line, " %63s = \"\"", arg) == 1) {
14142262ba8SGerd Hoffmann /* arg = value */
14237701411SPaolo Bonzini if (qdict == NULL) {
143f7544edcSPaolo Bonzini error_setg(errp, "no group defined");
144cf5a65aaSMarkus Armbruster goto out;
14542262ba8SGerd Hoffmann }
14637701411SPaolo Bonzini qdict_put_str(qdict, arg, value);
14742262ba8SGerd Hoffmann continue;
14842262ba8SGerd Hoffmann }
149f7544edcSPaolo Bonzini error_setg(errp, "parse error");
150cf5a65aaSMarkus Armbruster goto out;
15142262ba8SGerd Hoffmann }
152ef82516dSMarkus Armbruster if (ferror(fp)) {
153f7544edcSPaolo Bonzini loc_pop(&loc);
154f7544edcSPaolo Bonzini error_setg_errno(errp, errno, "Cannot read config file");
155461fea9bSPaolo Bonzini goto out_no_loc;
156ef82516dSMarkus Armbruster }
157e5766d6eSEduardo Habkost res = count;
15837701411SPaolo Bonzini if (qdict) {
15937701411SPaolo Bonzini cb(group, qdict, opaque, errp);
16037701411SPaolo Bonzini }
161e72f9524SPaolo Bonzini out:
162cf5a65aaSMarkus Armbruster loc_pop(&loc);
163461fea9bSPaolo Bonzini out_no_loc:
164e72f9524SPaolo Bonzini qobject_unref(qdict);
165cf5a65aaSMarkus Armbruster return res;
16642262ba8SGerd Hoffmann }
167dcfb0939SKevin Wolf
qemu_config_do_parse(const char * group,QDict * qdict,void * opaque,Error ** errp)16837701411SPaolo Bonzini void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp)
16937701411SPaolo Bonzini {
17037701411SPaolo Bonzini QemuOptsList **lists = opaque;
17137701411SPaolo Bonzini QemuOptsList *list;
17237701411SPaolo Bonzini
17337701411SPaolo Bonzini list = find_list(lists, group, errp);
17437701411SPaolo Bonzini if (!list) {
17537701411SPaolo Bonzini return;
17637701411SPaolo Bonzini }
17737701411SPaolo Bonzini
178e7d85d95SPaolo Bonzini qemu_opts_from_qdict(list, qdict, errp);
17937701411SPaolo Bonzini }
18037701411SPaolo Bonzini
qemu_config_parse(FILE * fp,QemuOptsList ** lists,const char * fname,Error ** errp)18137701411SPaolo Bonzini int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
18237701411SPaolo Bonzini {
18337701411SPaolo Bonzini return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp);
18437701411SPaolo Bonzini }
18537701411SPaolo Bonzini
qemu_read_config_file(const char * filename,QEMUConfigCB * cb,Error ** errp)18637701411SPaolo Bonzini int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp)
187dcfb0939SKevin Wolf {
188dcfb0939SKevin Wolf FILE *f = fopen(filename, "r");
189019e78baSKevin Wolf int ret;
190019e78baSKevin Wolf
191dcfb0939SKevin Wolf if (f == NULL) {
192f7544edcSPaolo Bonzini error_setg_file_open(errp, errno, filename);
193dcfb0939SKevin Wolf return -errno;
194dcfb0939SKevin Wolf }
195dcfb0939SKevin Wolf
19637701411SPaolo Bonzini ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp);
197dcfb0939SKevin Wolf fclose(f);
198e5766d6eSEduardo Habkost return ret;
199dcfb0939SKevin Wolf }
200adf5c449SMax Reitz
config_parse_qdict_section(QDict * options,QemuOptsList * opts,Error ** errp)201f766e6dcSMarkus Armbruster static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts,
202adf5c449SMax Reitz Error **errp)
203adf5c449SMax Reitz {
204adf5c449SMax Reitz QemuOpts *subopts;
205f766e6dcSMarkus Armbruster g_autoptr(QDict) subqdict = NULL;
206f766e6dcSMarkus Armbruster g_autoptr(QList) list = NULL;
207adf5c449SMax Reitz size_t orig_size, enum_size;
208adf5c449SMax Reitz char *prefix;
209adf5c449SMax Reitz
210adf5c449SMax Reitz prefix = g_strdup_printf("%s.", opts->name);
211adf5c449SMax Reitz qdict_extract_subqdict(options, &subqdict, prefix);
212adf5c449SMax Reitz g_free(prefix);
213adf5c449SMax Reitz orig_size = qdict_size(subqdict);
214adf5c449SMax Reitz if (!orig_size) {
215f766e6dcSMarkus Armbruster return true;
216adf5c449SMax Reitz }
217adf5c449SMax Reitz
218c6ecec43SMarkus Armbruster subopts = qemu_opts_create(opts, NULL, 0, errp);
219c6ecec43SMarkus Armbruster if (!subopts) {
220f766e6dcSMarkus Armbruster return false;
221adf5c449SMax Reitz }
222adf5c449SMax Reitz
223668f62ecSMarkus Armbruster if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) {
224f766e6dcSMarkus Armbruster return false;
225adf5c449SMax Reitz }
226adf5c449SMax Reitz
227adf5c449SMax Reitz enum_size = qdict_size(subqdict);
228adf5c449SMax Reitz if (enum_size < orig_size && enum_size) {
229adf5c449SMax Reitz error_setg(errp, "Unknown option '%s' for [%s]",
230adf5c449SMax Reitz qdict_first(subqdict)->key, opts->name);
231f766e6dcSMarkus Armbruster return false;
232adf5c449SMax Reitz }
233adf5c449SMax Reitz
234adf5c449SMax Reitz if (enum_size) {
235adf5c449SMax Reitz /* Multiple, enumerated sections */
236adf5c449SMax Reitz QListEntry *list_entry;
237adf5c449SMax Reitz unsigned i = 0;
238adf5c449SMax Reitz
239adf5c449SMax Reitz /* Not required anymore */
240adf5c449SMax Reitz qemu_opts_del(subopts);
241adf5c449SMax Reitz
242adf5c449SMax Reitz qdict_array_split(subqdict, &list);
243adf5c449SMax Reitz if (qdict_size(subqdict)) {
244adf5c449SMax Reitz error_setg(errp, "Unused option '%s' for [%s]",
245adf5c449SMax Reitz qdict_first(subqdict)->key, opts->name);
246f766e6dcSMarkus Armbruster return false;
247adf5c449SMax Reitz }
248adf5c449SMax Reitz
249adf5c449SMax Reitz QLIST_FOREACH_ENTRY(list, list_entry) {
2507dc847ebSMax Reitz QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry));
251adf5c449SMax Reitz char *opt_name;
252adf5c449SMax Reitz
253ae39c4b2SMax Reitz if (!section) {
254ae39c4b2SMax Reitz error_setg(errp, "[%s] section (index %u) does not consist of "
255ae39c4b2SMax Reitz "keys", opts->name, i);
256f766e6dcSMarkus Armbruster return false;
257ae39c4b2SMax Reitz }
258ae39c4b2SMax Reitz
259adf5c449SMax Reitz opt_name = g_strdup_printf("%s.%u", opts->name, i++);
260c6ecec43SMarkus Armbruster subopts = qemu_opts_create(opts, opt_name, 1, errp);
261adf5c449SMax Reitz g_free(opt_name);
262c6ecec43SMarkus Armbruster if (!subopts) {
263f766e6dcSMarkus Armbruster return false;
264adf5c449SMax Reitz }
265adf5c449SMax Reitz
266668f62ecSMarkus Armbruster if (!qemu_opts_absorb_qdict(subopts, section, errp)) {
267adf5c449SMax Reitz qemu_opts_del(subopts);
268f766e6dcSMarkus Armbruster return false;
269adf5c449SMax Reitz }
270adf5c449SMax Reitz
271adf5c449SMax Reitz if (qdict_size(section)) {
272adf5c449SMax Reitz error_setg(errp, "[%s] section doesn't support the option '%s'",
273adf5c449SMax Reitz opts->name, qdict_first(section)->key);
274adf5c449SMax Reitz qemu_opts_del(subopts);
275f766e6dcSMarkus Armbruster return false;
276adf5c449SMax Reitz }
277adf5c449SMax Reitz }
278adf5c449SMax Reitz }
279adf5c449SMax Reitz
280f766e6dcSMarkus Armbruster return true;
281adf5c449SMax Reitz }
282adf5c449SMax Reitz
qemu_config_parse_qdict(QDict * options,QemuOptsList ** lists,Error ** errp)283f766e6dcSMarkus Armbruster bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
284adf5c449SMax Reitz Error **errp)
285adf5c449SMax Reitz {
286adf5c449SMax Reitz int i;
287adf5c449SMax Reitz
288adf5c449SMax Reitz for (i = 0; lists[i]; i++) {
289f766e6dcSMarkus Armbruster if (!config_parse_qdict_section(options, lists[i], errp)) {
290f766e6dcSMarkus Armbruster return false;
291adf5c449SMax Reitz }
292adf5c449SMax Reitz }
293f766e6dcSMarkus Armbruster
294f766e6dcSMarkus Armbruster return true;
295adf5c449SMax Reitz }
296