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
find_list(QemuOptsList ** lists,const char * group,Error ** errp)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
qemu_find_opts(const char * group)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
qemu_find_opts_singleton(const char * group)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
qemu_find_opts_err(const char * group,Error ** errp)56 QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
57 {
58 return find_list(vm_config_groups, group, errp);
59 }
60
qemu_add_drive_opts(QemuOptsList * list)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
qemu_add_opts(QemuOptsList * list)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 */
qemu_config_foreach(FILE * fp,QEMUConfigCB * cb,void * opaque,const char * fname,Error ** errp)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
qemu_config_do_parse(const char * group,QDict * qdict,void * opaque,Error ** errp)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
qemu_config_parse(FILE * fp,QemuOptsList ** lists,const char * fname,Error ** errp)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
qemu_read_config_file(const char * filename,QEMUConfigCB * cb,Error ** errp)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
config_parse_qdict_section(QDict * options,QemuOptsList * opts,Error ** errp)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
qemu_config_parse_qdict(QDict * options,QemuOptsList ** lists,Error ** errp)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