xref: /qemu/util/qemu-config.c (revision 3df4c28860e100011db3a51a8a331506a3fe51f0)
1aafd7584SPeter Maydell #include "qemu/osdep.h"
2609f45eaSMax Reitz #include "block/qdict.h" /* for qdict_extract_subqdict() */
3e688df6bSMarkus Armbruster #include "qapi/error.h"
4452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h"
547e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h"
61de7afc9SPaolo Bonzini #include "qemu/error-report.h"
71de7afc9SPaolo Bonzini #include "qemu/option.h"
81de7afc9SPaolo Bonzini #include "qemu/config-file.h"
97282a033SGerd Hoffmann 
10*3df4c288SPhilippe Mathieu-Daudé QemuOptsList *vm_config_groups[48];
11*3df4c288SPhilippe Mathieu-Daudé QemuOptsList *drive_config_groups[5];
12d058fe03SGerd Hoffmann 
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 
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 
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 
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 
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 
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 */
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 
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 
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 
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 
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 
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