]> Git Repo - qemu.git/blob - qemu-config.c
error: Track locations in configuration files
[qemu.git] / qemu-config.c
1 #include "qemu-common.h"
2 #include "qemu-error.h"
3 #include "qemu-option.h"
4 #include "qemu-config.h"
5 #include "sysemu.h"
6 #include "hw/qdev.h"
7
8 QemuOptsList qemu_drive_opts = {
9     .name = "drive",
10     .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
11     .desc = {
12         {
13             .name = "bus",
14             .type = QEMU_OPT_NUMBER,
15             .help = "bus number",
16         },{
17             .name = "unit",
18             .type = QEMU_OPT_NUMBER,
19             .help = "unit number (i.e. lun for scsi)",
20         },{
21             .name = "if",
22             .type = QEMU_OPT_STRING,
23             .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
24         },{
25             .name = "index",
26             .type = QEMU_OPT_NUMBER,
27         },{
28             .name = "cyls",
29             .type = QEMU_OPT_NUMBER,
30             .help = "number of cylinders (ide disk geometry)",
31         },{
32             .name = "heads",
33             .type = QEMU_OPT_NUMBER,
34             .help = "number of heads (ide disk geometry)",
35         },{
36             .name = "secs",
37             .type = QEMU_OPT_NUMBER,
38             .help = "number of sectors (ide disk geometry)",
39         },{
40             .name = "trans",
41             .type = QEMU_OPT_STRING,
42             .help = "chs translation (auto, lba. none)",
43         },{
44             .name = "media",
45             .type = QEMU_OPT_STRING,
46             .help = "media type (disk, cdrom)",
47         },{
48             .name = "snapshot",
49             .type = QEMU_OPT_BOOL,
50         },{
51             .name = "file",
52             .type = QEMU_OPT_STRING,
53             .help = "disk image",
54         },{
55             .name = "cache",
56             .type = QEMU_OPT_STRING,
57             .help = "host cache usage (none, writeback, writethrough)",
58         },{
59             .name = "aio",
60             .type = QEMU_OPT_STRING,
61             .help = "host AIO implementation (threads, native)",
62         },{
63             .name = "format",
64             .type = QEMU_OPT_STRING,
65             .help = "disk format (raw, qcow2, ...)",
66         },{
67             .name = "serial",
68             .type = QEMU_OPT_STRING,
69         },{
70             .name = "rerror",
71             .type = QEMU_OPT_STRING,
72         },{
73             .name = "werror",
74             .type = QEMU_OPT_STRING,
75         },{
76             .name = "addr",
77             .type = QEMU_OPT_STRING,
78             .help = "pci address (virtio only)",
79         },{
80             .name = "readonly",
81             .type = QEMU_OPT_BOOL,
82         },
83         { /* end if list */ }
84     },
85 };
86
87 QemuOptsList qemu_chardev_opts = {
88     .name = "chardev",
89     .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
90     .desc = {
91         {
92             .name = "backend",
93             .type = QEMU_OPT_STRING,
94         },{
95             .name = "path",
96             .type = QEMU_OPT_STRING,
97         },{
98             .name = "host",
99             .type = QEMU_OPT_STRING,
100         },{
101             .name = "port",
102             .type = QEMU_OPT_STRING,
103         },{
104             .name = "localaddr",
105             .type = QEMU_OPT_STRING,
106         },{
107             .name = "localport",
108             .type = QEMU_OPT_STRING,
109         },{
110             .name = "to",
111             .type = QEMU_OPT_NUMBER,
112         },{
113             .name = "ipv4",
114             .type = QEMU_OPT_BOOL,
115         },{
116             .name = "ipv6",
117             .type = QEMU_OPT_BOOL,
118         },{
119             .name = "wait",
120             .type = QEMU_OPT_BOOL,
121         },{
122             .name = "server",
123             .type = QEMU_OPT_BOOL,
124         },{
125             .name = "delay",
126             .type = QEMU_OPT_BOOL,
127         },{
128             .name = "telnet",
129             .type = QEMU_OPT_BOOL,
130         },{
131             .name = "width",
132             .type = QEMU_OPT_NUMBER,
133         },{
134             .name = "height",
135             .type = QEMU_OPT_NUMBER,
136         },{
137             .name = "cols",
138             .type = QEMU_OPT_NUMBER,
139         },{
140             .name = "rows",
141             .type = QEMU_OPT_NUMBER,
142         },{
143             .name = "mux",
144             .type = QEMU_OPT_BOOL,
145         },{
146             .name = "signal",
147             .type = QEMU_OPT_BOOL,
148         },
149         { /* end if list */ }
150     },
151 };
152
153 QemuOptsList qemu_device_opts = {
154     .name = "device",
155     .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
156     .desc = {
157         /*
158          * no elements => accept any
159          * sanity checking will happen later
160          * when setting device properties
161          */
162         { /* end if list */ }
163     },
164 };
165
166 QemuOptsList qemu_netdev_opts = {
167     .name = "netdev",
168     .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
169     .desc = {
170         /*
171          * no elements => accept any params
172          * validation will happen later
173          */
174         { /* end of list */ }
175     },
176 };
177
178 QemuOptsList qemu_net_opts = {
179     .name = "net",
180     .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
181     .desc = {
182         /*
183          * no elements => accept any params
184          * validation will happen later
185          */
186         { /* end of list */ }
187     },
188 };
189
190 QemuOptsList qemu_rtc_opts = {
191     .name = "rtc",
192     .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
193     .desc = {
194         {
195             .name = "base",
196             .type = QEMU_OPT_STRING,
197         },{
198             .name = "clock",
199             .type = QEMU_OPT_STRING,
200 #ifdef TARGET_I386
201         },{
202             .name = "driftfix",
203             .type = QEMU_OPT_STRING,
204 #endif
205         },
206         { /* end if list */ }
207     },
208 };
209
210 QemuOptsList qemu_global_opts = {
211     .name = "global",
212     .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
213     .desc = {
214         {
215             .name = "driver",
216             .type = QEMU_OPT_STRING,
217         },{
218             .name = "property",
219             .type = QEMU_OPT_STRING,
220         },{
221             .name = "value",
222             .type = QEMU_OPT_STRING,
223         },
224         { /* end if list */ }
225     },
226 };
227
228 QemuOptsList qemu_mon_opts = {
229     .name = "mon",
230     .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
231     .desc = {
232         {
233             .name = "mode",
234             .type = QEMU_OPT_STRING,
235         },{
236             .name = "chardev",
237             .type = QEMU_OPT_STRING,
238         },{
239             .name = "default",
240             .type = QEMU_OPT_BOOL,
241         },
242         { /* end if list */ }
243     },
244 };
245
246 QemuOptsList qemu_cpudef_opts = {
247     .name = "cpudef",
248     .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
249     .desc = {
250         {
251             .name = "name",
252             .type = QEMU_OPT_STRING,
253         },{
254             .name = "level",
255             .type = QEMU_OPT_NUMBER,
256         },{
257             .name = "vendor",
258             .type = QEMU_OPT_STRING,
259         },{
260             .name = "family",
261             .type = QEMU_OPT_NUMBER,
262         },{
263             .name = "model",
264             .type = QEMU_OPT_NUMBER,
265         },{
266             .name = "stepping",
267             .type = QEMU_OPT_NUMBER,
268         },{
269             .name = "feature_edx",      /* cpuid 0000_0001.edx */
270             .type = QEMU_OPT_STRING,
271         },{
272             .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
273             .type = QEMU_OPT_STRING,
274         },{
275             .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
276             .type = QEMU_OPT_STRING,
277         },{
278             .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
279             .type = QEMU_OPT_STRING,
280         },{
281             .name = "xlevel",
282             .type = QEMU_OPT_NUMBER,
283         },{
284             .name = "model_id",
285             .type = QEMU_OPT_STRING,
286         },{
287             .name = "vendor_override",
288             .type = QEMU_OPT_NUMBER,
289         },
290         { /* end of list */ }
291     },
292 };
293
294 static QemuOptsList *lists[] = {
295     &qemu_drive_opts,
296     &qemu_chardev_opts,
297     &qemu_device_opts,
298     &qemu_netdev_opts,
299     &qemu_net_opts,
300     &qemu_rtc_opts,
301     &qemu_global_opts,
302     &qemu_mon_opts,
303     &qemu_cpudef_opts,
304     NULL,
305 };
306
307 static QemuOptsList *find_list(const char *group)
308 {
309     int i;
310
311     for (i = 0; lists[i] != NULL; i++) {
312         if (strcmp(lists[i]->name, group) == 0)
313             break;
314     }
315     if (lists[i] == NULL) {
316         error_report("there is no option group \"%s\"", group);
317     }
318     return lists[i];
319 }
320
321 int qemu_set_option(const char *str)
322 {
323     char group[64], id[64], arg[64];
324     QemuOptsList *list;
325     QemuOpts *opts;
326     int rc, offset;
327
328     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
329     if (rc < 3 || str[offset] != '=') {
330         error_report("can't parse: \"%s\"", str);
331         return -1;
332     }
333
334     list = find_list(group);
335     if (list == NULL) {
336         return -1;
337     }
338
339     opts = qemu_opts_find(list, id);
340     if (!opts) {
341         error_report("there is no %s \"%s\" defined",
342                      list->name, id);
343         return -1;
344     }
345
346     if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
347         return -1;
348     }
349     return 0;
350 }
351
352 int qemu_global_option(const char *str)
353 {
354     char driver[64], property[64];
355     QemuOpts *opts;
356     int rc, offset;
357
358     rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
359     if (rc < 2 || str[offset] != '=') {
360         error_report("can't parse: \"%s\"", str);
361         return -1;
362     }
363
364     opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
365     qemu_opt_set(opts, "driver", driver);
366     qemu_opt_set(opts, "property", property);
367     qemu_opt_set(opts, "value", str+offset+1);
368     return 0;
369 }
370
371 static int qemu_add_one_global(QemuOpts *opts, void *opaque)
372 {
373     GlobalProperty *g;
374
375     g = qemu_mallocz(sizeof(*g));
376     g->driver   = qemu_opt_get(opts, "driver");
377     g->property = qemu_opt_get(opts, "property");
378     g->value    = qemu_opt_get(opts, "value");
379     qdev_prop_register_global(g);
380     return 0;
381 }
382
383 void qemu_add_globals(void)
384 {
385     qemu_opts_foreach(&qemu_global_opts, qemu_add_one_global, NULL, 0);
386 }
387
388 struct ConfigWriteData {
389     QemuOptsList *list;
390     FILE *fp;
391 };
392
393 static int config_write_opt(const char *name, const char *value, void *opaque)
394 {
395     struct ConfigWriteData *data = opaque;
396
397     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
398     return 0;
399 }
400
401 static int config_write_opts(QemuOpts *opts, void *opaque)
402 {
403     struct ConfigWriteData *data = opaque;
404     const char *id = qemu_opts_id(opts);
405
406     if (id) {
407         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
408     } else {
409         fprintf(data->fp, "[%s]\n", data->list->name);
410     }
411     qemu_opt_foreach(opts, config_write_opt, data, 0);
412     fprintf(data->fp, "\n");
413     return 0;
414 }
415
416 void qemu_config_write(FILE *fp)
417 {
418     struct ConfigWriteData data = { .fp = fp };
419     int i;
420
421     fprintf(fp, "# qemu config file\n\n");
422     for (i = 0; lists[i] != NULL; i++) {
423         data.list = lists[i];
424         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
425     }
426 }
427
428 int qemu_config_parse(FILE *fp, const char *fname)
429 {
430     char line[1024], group[64], id[64], arg[64], value[1024];
431     Location loc;
432     QemuOptsList *list = NULL;
433     QemuOpts *opts = NULL;
434     int res = -1, lno = 0;
435
436     loc_push_none(&loc);
437     while (fgets(line, sizeof(line), fp) != NULL) {
438         loc_set_file(fname, ++lno);
439         if (line[0] == '\n') {
440             /* skip empty lines */
441             continue;
442         }
443         if (line[0] == '#') {
444             /* comment */
445             continue;
446         }
447         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
448             /* group with id */
449             list = find_list(group);
450             if (list == NULL)
451                 goto out;
452             opts = qemu_opts_create(list, id, 1);
453             continue;
454         }
455         if (sscanf(line, "[%63[^]]]", group) == 1) {
456             /* group without id */
457             list = find_list(group);
458             if (list == NULL)
459                 goto out;
460             opts = qemu_opts_create(list, NULL, 0);
461             continue;
462         }
463         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
464             /* arg = value */
465             if (opts == NULL) {
466                 error_report("no group defined");
467                 goto out;
468             }
469             if (qemu_opt_set(opts, arg, value) != 0) {
470                 error_report("failed to set \"%s\" for %s", arg, group);
471                 goto out;
472             }
473             continue;
474         }
475         error_report("parse error");
476         goto out;
477     }
478     res = 0;
479 out:
480     loc_pop(&loc);
481     return res;
482 }
This page took 0.054602 seconds and 4 git commands to generate.