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"
6baacf047SPaolo Bonzini #include "qemu/error-report.h"
7baacf047SPaolo Bonzini #include "qemu/option.h"
8baacf047SPaolo Bonzini #include "qemu/config-file.h"
9baacf047SPaolo Bonzini
10*3df4c288SPhilippe Mathieu-Daudé QemuOptsList *vm_config_groups[48];
11*3df4c288SPhilippe Mathieu-Daudé QemuOptsList *drive_config_groups[5];
12baacf047SPaolo Bonzini
find_list(QemuOptsList ** lists,const char * group,Error ** errp)13baacf047SPaolo Bonzini static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
14baacf047SPaolo Bonzini Error **errp)
15baacf047SPaolo Bonzini {
16baacf047SPaolo Bonzini int i;
17baacf047SPaolo Bonzini
18632a8873SPaolo Bonzini qemu_load_module_for_opts(group);
19baacf047SPaolo Bonzini for (i = 0; lists[i] != NULL; i++) {
20baacf047SPaolo Bonzini if (strcmp(lists[i]->name, group) == 0)
21baacf047SPaolo Bonzini break;
22baacf047SPaolo Bonzini }
23baacf047SPaolo Bonzini if (lists[i] == NULL) {
24f231b88dSCole Robinson error_setg(errp, "There is no option group '%s'", group);
25baacf047SPaolo Bonzini }
26baacf047SPaolo Bonzini return lists[i];
27baacf047SPaolo Bonzini }
28baacf047SPaolo Bonzini
qemu_find_opts(const char * group)29baacf047SPaolo Bonzini QemuOptsList *qemu_find_opts(const char *group)
30baacf047SPaolo Bonzini {
31baacf047SPaolo Bonzini QemuOptsList *ret;
32baacf047SPaolo Bonzini Error *local_err = NULL;
33baacf047SPaolo Bonzini
34baacf047SPaolo Bonzini ret = find_list(vm_config_groups, group, &local_err);
3584d18f06SMarkus Armbruster if (local_err) {
36565f65d2SMarkus Armbruster error_report_err(local_err);
37baacf047SPaolo Bonzini }
38baacf047SPaolo Bonzini
39baacf047SPaolo Bonzini return ret;
40baacf047SPaolo Bonzini }
41baacf047SPaolo Bonzini
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)56baacf047SPaolo Bonzini QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
57baacf047SPaolo Bonzini {
58baacf047SPaolo Bonzini return find_list(vm_config_groups, group, errp);
59baacf047SPaolo Bonzini }
60baacf047SPaolo Bonzini
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)77baacf047SPaolo Bonzini void qemu_add_opts(QemuOptsList *list)
78baacf047SPaolo Bonzini {
79baacf047SPaolo Bonzini int entries, i;
80baacf047SPaolo Bonzini
81baacf047SPaolo Bonzini entries = ARRAY_SIZE(vm_config_groups);
82baacf047SPaolo Bonzini entries--; /* keep list NULL terminated */
83baacf047SPaolo Bonzini for (i = 0; i < entries; i++) {
84baacf047SPaolo Bonzini if (vm_config_groups[i] == NULL) {
85baacf047SPaolo Bonzini vm_config_groups[i] = list;
86baacf047SPaolo Bonzini return;
87baacf047SPaolo Bonzini }
88baacf047SPaolo Bonzini }
89baacf047SPaolo Bonzini fprintf(stderr, "ran out of space in vm_config_groups");
90baacf047SPaolo Bonzini abort();
91baacf047SPaolo Bonzini }
92baacf047SPaolo Bonzini
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)
96baacf047SPaolo Bonzini {
970a3090b1SMarkus Armbruster ERRP_GUARD();
9837701411SPaolo Bonzini char line[1024], prev_group[64], group[64], arg[64], value[1024];
99baacf047SPaolo Bonzini Location loc;
10037701411SPaolo Bonzini QDict *qdict = NULL;
101e5766d6eSEduardo Habkost int res = -EINVAL, lno = 0;
102e5766d6eSEduardo Habkost int count = 0;
103baacf047SPaolo Bonzini
104baacf047SPaolo Bonzini loc_push_none(&loc);
105baacf047SPaolo Bonzini while (fgets(line, sizeof(line), fp) != NULL) {
10637701411SPaolo Bonzini ++lno;
107baacf047SPaolo Bonzini if (line[0] == '\n') {
108baacf047SPaolo Bonzini /* skip empty lines */
109baacf047SPaolo Bonzini continue;
110baacf047SPaolo Bonzini }
111baacf047SPaolo Bonzini if (line[0] == '#') {
112baacf047SPaolo Bonzini /* comment */
113baacf047SPaolo Bonzini continue;
114baacf047SPaolo Bonzini }
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) {
130baacf047SPaolo Bonzini goto out;
131baacf047SPaolo Bonzini }
13237701411SPaolo Bonzini }
13337701411SPaolo Bonzini strcpy(prev_group, group);
134baacf047SPaolo Bonzini continue;
135baacf047SPaolo Bonzini }
136baacf047SPaolo Bonzini }
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) {
141baacf047SPaolo Bonzini /* arg = value */
14237701411SPaolo Bonzini if (qdict == NULL) {
143f7544edcSPaolo Bonzini error_setg(errp, "no group defined");
144baacf047SPaolo Bonzini goto out;
145baacf047SPaolo Bonzini }
14637701411SPaolo Bonzini qdict_put_str(qdict, arg, value);
147baacf047SPaolo Bonzini continue;
148baacf047SPaolo Bonzini }
149f7544edcSPaolo Bonzini error_setg(errp, "parse error");
150baacf047SPaolo Bonzini goto out;
151baacf047SPaolo Bonzini }
152baacf047SPaolo Bonzini 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;
156baacf047SPaolo Bonzini }
157e5766d6eSEduardo Habkost res = count;
15837701411SPaolo Bonzini if (qdict) {
15937701411SPaolo Bonzini cb(group, qdict, opaque, errp);
16037701411SPaolo Bonzini }
161e72f9524SPaolo Bonzini out:
162baacf047SPaolo Bonzini loc_pop(&loc);
163461fea9bSPaolo Bonzini out_no_loc:
164e72f9524SPaolo Bonzini qobject_unref(qdict);
165baacf047SPaolo Bonzini return res;
166baacf047SPaolo Bonzini }
167baacf047SPaolo Bonzini
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)
187baacf047SPaolo Bonzini {
188baacf047SPaolo Bonzini FILE *f = fopen(filename, "r");
189baacf047SPaolo Bonzini int ret;
190baacf047SPaolo Bonzini
191baacf047SPaolo Bonzini if (f == NULL) {
192f7544edcSPaolo Bonzini error_setg_file_open(errp, errno, filename);
193baacf047SPaolo Bonzini return -errno;
194baacf047SPaolo Bonzini }
195baacf047SPaolo Bonzini
19637701411SPaolo Bonzini ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp);
197baacf047SPaolo Bonzini fclose(f);
198e5766d6eSEduardo Habkost return ret;
199baacf047SPaolo Bonzini }
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