xref: /openbmc/qemu/util/qemu-config.c (revision 7d87775f)
1 #include "qemu/osdep.h"
2 #include "block/qdict.h" /* for qdict_extract_subqdict() */
3 #include "qapi/error.h"
4 #include "qapi/qmp/qdict.h"
5 #include "qapi/qmp/qlist.h"
6 #include "qemu/error-report.h"
7 #include "qemu/option.h"
8 #include "qemu/config-file.h"
9 
10 QemuOptsList *vm_config_groups[48];
11 QemuOptsList *drive_config_groups[5];
12 
13 static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
14                                Error **errp)
15 {
16     int i;
17 
18     qemu_load_module_for_opts(group);
19     for (i = 0; lists[i] != NULL; i++) {
20         if (strcmp(lists[i]->name, group) == 0)
21             break;
22     }
23     if (lists[i] == NULL) {
24         error_setg(errp, "There is no option group '%s'", group);
25     }
26     return lists[i];
27 }
28 
29 QemuOptsList *qemu_find_opts(const char *group)
30 {
31     QemuOptsList *ret;
32     Error *local_err = NULL;
33 
34     ret = find_list(vm_config_groups, group, &local_err);
35     if (local_err) {
36         error_report_err(local_err);
37     }
38 
39     return ret;
40 }
41 
42 QemuOpts *qemu_find_opts_singleton(const char *group)
43 {
44     QemuOptsList *list;
45     QemuOpts *opts;
46 
47     list = qemu_find_opts(group);
48     assert(list);
49     opts = qemu_opts_find(list, NULL);
50     if (!opts) {
51         opts = qemu_opts_create(list, NULL, 0, &error_abort);
52     }
53     return opts;
54 }
55 
56 QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
57 {
58     return find_list(vm_config_groups, group, errp);
59 }
60 
61 void qemu_add_drive_opts(QemuOptsList *list)
62 {
63     int entries, i;
64 
65     entries = ARRAY_SIZE(drive_config_groups);
66     entries--; /* keep list NULL terminated */
67     for (i = 0; i < entries; i++) {
68         if (drive_config_groups[i] == NULL) {
69             drive_config_groups[i] = list;
70             return;
71         }
72     }
73     fprintf(stderr, "ran out of space in drive_config_groups");
74     abort();
75 }
76 
77 void qemu_add_opts(QemuOptsList *list)
78 {
79     int entries, i;
80 
81     entries = ARRAY_SIZE(vm_config_groups);
82     entries--; /* keep list NULL terminated */
83     for (i = 0; i < entries; i++) {
84         if (vm_config_groups[i] == NULL) {
85             vm_config_groups[i] = list;
86             return;
87         }
88     }
89     fprintf(stderr, "ran out of space in vm_config_groups");
90     abort();
91 }
92 
93 /* Returns number of config groups on success, -errno on error */
94 static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque,
95                                const char *fname, Error **errp)
96 {
97     ERRP_GUARD();
98     char line[1024], prev_group[64], group[64], arg[64], value[1024];
99     Location loc;
100     QDict *qdict = NULL;
101     int res = -EINVAL, lno = 0;
102     int count = 0;
103 
104     loc_push_none(&loc);
105     while (fgets(line, sizeof(line), fp) != NULL) {
106         ++lno;
107         if (line[0] == '\n') {
108             /* skip empty lines */
109             continue;
110         }
111         if (line[0] == '#') {
112             /* comment */
113             continue;
114         }
115         if (line[0] == '[') {
116             QDict *prev = qdict;
117             if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) {
118                 qdict = qdict_new();
119                 qdict_put_str(qdict, "id", value);
120                 count++;
121             } else if (sscanf(line, "[%63[^]]]", group) == 1) {
122                 qdict = qdict_new();
123                 count++;
124             }
125             if (qdict != prev) {
126                 if (prev) {
127                     cb(prev_group, prev, opaque, errp);
128                     qobject_unref(prev);
129                     if (*errp) {
130                         goto out;
131                     }
132                 }
133                 strcpy(prev_group, group);
134                 continue;
135             }
136         }
137         loc_set_file(fname, lno);
138         value[0] = '\0';
139         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 ||
140             sscanf(line, " %63s = \"\"", arg) == 1) {
141             /* arg = value */
142             if (qdict == NULL) {
143                 error_setg(errp, "no group defined");
144                 goto out;
145             }
146             qdict_put_str(qdict, arg, value);
147             continue;
148         }
149         error_setg(errp, "parse error");
150         goto out;
151     }
152     if (ferror(fp)) {
153         loc_pop(&loc);
154         error_setg_errno(errp, errno, "Cannot read config file");
155         goto out_no_loc;
156     }
157     res = count;
158     if (qdict) {
159         cb(group, qdict, opaque, errp);
160     }
161 out:
162     loc_pop(&loc);
163 out_no_loc:
164     qobject_unref(qdict);
165     return res;
166 }
167 
168 void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp)
169 {
170     QemuOptsList **lists = opaque;
171     QemuOptsList *list;
172 
173     list = find_list(lists, group, errp);
174     if (!list) {
175         return;
176     }
177 
178     qemu_opts_from_qdict(list, qdict, errp);
179 }
180 
181 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp)
182 {
183     return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp);
184 }
185 
186 int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp)
187 {
188     FILE *f = fopen(filename, "r");
189     int ret;
190 
191     if (f == NULL) {
192         error_setg_file_open(errp, errno, filename);
193         return -errno;
194     }
195 
196     ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp);
197     fclose(f);
198     return ret;
199 }
200 
201 static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts,
202                                        Error **errp)
203 {
204     QemuOpts *subopts;
205     g_autoptr(QDict) subqdict = NULL;
206     g_autoptr(QList) list = NULL;
207     size_t orig_size, enum_size;
208     char *prefix;
209 
210     prefix = g_strdup_printf("%s.", opts->name);
211     qdict_extract_subqdict(options, &subqdict, prefix);
212     g_free(prefix);
213     orig_size = qdict_size(subqdict);
214     if (!orig_size) {
215         return true;
216     }
217 
218     subopts = qemu_opts_create(opts, NULL, 0, errp);
219     if (!subopts) {
220         return false;
221     }
222 
223     if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) {
224         return false;
225     }
226 
227     enum_size = qdict_size(subqdict);
228     if (enum_size < orig_size && enum_size) {
229         error_setg(errp, "Unknown option '%s' for [%s]",
230                    qdict_first(subqdict)->key, opts->name);
231         return false;
232     }
233 
234     if (enum_size) {
235         /* Multiple, enumerated sections */
236         QListEntry *list_entry;
237         unsigned i = 0;
238 
239         /* Not required anymore */
240         qemu_opts_del(subopts);
241 
242         qdict_array_split(subqdict, &list);
243         if (qdict_size(subqdict)) {
244             error_setg(errp, "Unused option '%s' for [%s]",
245                        qdict_first(subqdict)->key, opts->name);
246             return false;
247         }
248 
249         QLIST_FOREACH_ENTRY(list, list_entry) {
250             QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry));
251             char *opt_name;
252 
253             if (!section) {
254                 error_setg(errp, "[%s] section (index %u) does not consist of "
255                            "keys", opts->name, i);
256                 return false;
257             }
258 
259             opt_name = g_strdup_printf("%s.%u", opts->name, i++);
260             subopts = qemu_opts_create(opts, opt_name, 1, errp);
261             g_free(opt_name);
262             if (!subopts) {
263                 return false;
264             }
265 
266             if (!qemu_opts_absorb_qdict(subopts, section, errp)) {
267                 qemu_opts_del(subopts);
268                 return false;
269             }
270 
271             if (qdict_size(section)) {
272                 error_setg(errp, "[%s] section doesn't support the option '%s'",
273                            opts->name, qdict_first(section)->key);
274                 qemu_opts_del(subopts);
275                 return false;
276             }
277         }
278     }
279 
280     return true;
281 }
282 
283 bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists,
284                              Error **errp)
285 {
286     int i;
287 
288     for (i = 0; lists[i]; i++) {
289         if (!config_parse_qdict_section(options, lists[i], errp)) {
290             return false;
291         }
292     }
293 
294     return true;
295 }
296