]> Git Repo - qemu.git/blob - qemu-config.c
pc: Fix floppy drives with if=none
[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 "hw/qdev.h"
6
7 static QemuOptsList qemu_drive_opts = {
8     .name = "drive",
9     .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
10     .desc = {
11         {
12             .name = "bus",
13             .type = QEMU_OPT_NUMBER,
14             .help = "bus number",
15         },{
16             .name = "unit",
17             .type = QEMU_OPT_NUMBER,
18             .help = "unit number (i.e. lun for scsi)",
19         },{
20             .name = "if",
21             .type = QEMU_OPT_STRING,
22             .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
23         },{
24             .name = "index",
25             .type = QEMU_OPT_NUMBER,
26             .help = "index 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             .help = "enable/disable snapshot mode",
51         },{
52             .name = "file",
53             .type = QEMU_OPT_STRING,
54             .help = "disk image",
55         },{
56             .name = "cache",
57             .type = QEMU_OPT_STRING,
58             .help = "host cache usage (none, writeback, writethrough, "
59                     "directsync, unsafe)",
60         },{
61             .name = "aio",
62             .type = QEMU_OPT_STRING,
63             .help = "host AIO implementation (threads, native)",
64         },{
65             .name = "format",
66             .type = QEMU_OPT_STRING,
67             .help = "disk format (raw, qcow2, ...)",
68         },{
69             .name = "serial",
70             .type = QEMU_OPT_STRING,
71             .help = "disk serial number",
72         },{
73             .name = "rerror",
74             .type = QEMU_OPT_STRING,
75             .help = "read error action",
76         },{
77             .name = "werror",
78             .type = QEMU_OPT_STRING,
79             .help = "write error action",
80         },{
81             .name = "addr",
82             .type = QEMU_OPT_STRING,
83             .help = "pci address (virtio only)",
84         },{
85             .name = "readonly",
86             .type = QEMU_OPT_BOOL,
87             .help = "open drive file as read-only",
88         },
89         { /* end of list */ }
90     },
91 };
92
93 static QemuOptsList qemu_chardev_opts = {
94     .name = "chardev",
95     .implied_opt_name = "backend",
96     .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
97     .desc = {
98         {
99             .name = "backend",
100             .type = QEMU_OPT_STRING,
101         },{
102             .name = "path",
103             .type = QEMU_OPT_STRING,
104         },{
105             .name = "host",
106             .type = QEMU_OPT_STRING,
107         },{
108             .name = "port",
109             .type = QEMU_OPT_STRING,
110         },{
111             .name = "localaddr",
112             .type = QEMU_OPT_STRING,
113         },{
114             .name = "localport",
115             .type = QEMU_OPT_STRING,
116         },{
117             .name = "to",
118             .type = QEMU_OPT_NUMBER,
119         },{
120             .name = "ipv4",
121             .type = QEMU_OPT_BOOL,
122         },{
123             .name = "ipv6",
124             .type = QEMU_OPT_BOOL,
125         },{
126             .name = "wait",
127             .type = QEMU_OPT_BOOL,
128         },{
129             .name = "server",
130             .type = QEMU_OPT_BOOL,
131         },{
132             .name = "delay",
133             .type = QEMU_OPT_BOOL,
134         },{
135             .name = "telnet",
136             .type = QEMU_OPT_BOOL,
137         },{
138             .name = "width",
139             .type = QEMU_OPT_NUMBER,
140         },{
141             .name = "height",
142             .type = QEMU_OPT_NUMBER,
143         },{
144             .name = "cols",
145             .type = QEMU_OPT_NUMBER,
146         },{
147             .name = "rows",
148             .type = QEMU_OPT_NUMBER,
149         },{
150             .name = "mux",
151             .type = QEMU_OPT_BOOL,
152         },{
153             .name = "signal",
154             .type = QEMU_OPT_BOOL,
155         },{
156             .name = "name",
157             .type = QEMU_OPT_STRING,
158         },{
159             .name = "debug",
160             .type = QEMU_OPT_NUMBER,
161         },
162         { /* end of list */ }
163     },
164 };
165
166 QemuOptsList qemu_fsdev_opts = {
167     .name = "fsdev",
168     .implied_opt_name = "fsdriver",
169     .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
170     .desc = {
171         {
172             .name = "fsdriver",
173             .type = QEMU_OPT_STRING,
174         }, {
175             .name = "path",
176             .type = QEMU_OPT_STRING,
177         }, {
178             .name = "security_model",
179             .type = QEMU_OPT_STRING,
180         }, {
181             .name = "writeout",
182             .type = QEMU_OPT_STRING,
183         },
184         { /*End of list */ }
185     },
186 };
187
188 QemuOptsList qemu_virtfs_opts = {
189     .name = "virtfs",
190     .implied_opt_name = "fsdriver",
191     .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
192     .desc = {
193         {
194             .name = "fsdriver",
195             .type = QEMU_OPT_STRING,
196         }, {
197             .name = "path",
198             .type = QEMU_OPT_STRING,
199         }, {
200             .name = "mount_tag",
201             .type = QEMU_OPT_STRING,
202         }, {
203             .name = "security_model",
204             .type = QEMU_OPT_STRING,
205         }, {
206             .name = "writeout",
207             .type = QEMU_OPT_STRING,
208         },
209
210         { /*End of list */ }
211     },
212 };
213
214 static QemuOptsList qemu_device_opts = {
215     .name = "device",
216     .implied_opt_name = "driver",
217     .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
218     .desc = {
219         /*
220          * no elements => accept any
221          * sanity checking will happen later
222          * when setting device properties
223          */
224         { /* end of list */ }
225     },
226 };
227
228 static QemuOptsList qemu_netdev_opts = {
229     .name = "netdev",
230     .implied_opt_name = "type",
231     .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
232     .desc = {
233         /*
234          * no elements => accept any params
235          * validation will happen later
236          */
237         { /* end of list */ }
238     },
239 };
240
241 static QemuOptsList qemu_net_opts = {
242     .name = "net",
243     .implied_opt_name = "type",
244     .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
245     .desc = {
246         /*
247          * no elements => accept any params
248          * validation will happen later
249          */
250         { /* end of list */ }
251     },
252 };
253
254 static QemuOptsList qemu_rtc_opts = {
255     .name = "rtc",
256     .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
257     .desc = {
258         {
259             .name = "base",
260             .type = QEMU_OPT_STRING,
261         },{
262             .name = "clock",
263             .type = QEMU_OPT_STRING,
264         },{
265             .name = "driftfix",
266             .type = QEMU_OPT_STRING,
267         },
268         { /* end of list */ }
269     },
270 };
271
272 static QemuOptsList qemu_global_opts = {
273     .name = "global",
274     .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
275     .desc = {
276         {
277             .name = "driver",
278             .type = QEMU_OPT_STRING,
279         },{
280             .name = "property",
281             .type = QEMU_OPT_STRING,
282         },{
283             .name = "value",
284             .type = QEMU_OPT_STRING,
285         },
286         { /* end of list */ }
287     },
288 };
289
290 static QemuOptsList qemu_mon_opts = {
291     .name = "mon",
292     .implied_opt_name = "chardev",
293     .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
294     .desc = {
295         {
296             .name = "mode",
297             .type = QEMU_OPT_STRING,
298         },{
299             .name = "chardev",
300             .type = QEMU_OPT_STRING,
301         },{
302             .name = "default",
303             .type = QEMU_OPT_BOOL,
304         },{
305             .name = "pretty",
306             .type = QEMU_OPT_BOOL,
307         },
308         { /* end of list */ }
309     },
310 };
311
312 static QemuOptsList qemu_trace_opts = {
313     .name = "trace",
314     .implied_opt_name = "trace",
315     .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
316     .desc = {
317         {
318             .name = "events",
319             .type = QEMU_OPT_STRING,
320         },{
321             .name = "file",
322             .type = QEMU_OPT_STRING,
323         },
324         { /* end of list */ }
325     },
326 };
327
328 static QemuOptsList qemu_cpudef_opts = {
329     .name = "cpudef",
330     .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
331     .desc = {
332         {
333             .name = "name",
334             .type = QEMU_OPT_STRING,
335         },{
336             .name = "level",
337             .type = QEMU_OPT_NUMBER,
338         },{
339             .name = "vendor",
340             .type = QEMU_OPT_STRING,
341         },{
342             .name = "family",
343             .type = QEMU_OPT_NUMBER,
344         },{
345             .name = "model",
346             .type = QEMU_OPT_NUMBER,
347         },{
348             .name = "stepping",
349             .type = QEMU_OPT_NUMBER,
350         },{
351             .name = "feature_edx",      /* cpuid 0000_0001.edx */
352             .type = QEMU_OPT_STRING,
353         },{
354             .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
355             .type = QEMU_OPT_STRING,
356         },{
357             .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
358             .type = QEMU_OPT_STRING,
359         },{
360             .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
361             .type = QEMU_OPT_STRING,
362         },{
363             .name = "xlevel",
364             .type = QEMU_OPT_NUMBER,
365         },{
366             .name = "model_id",
367             .type = QEMU_OPT_STRING,
368         },{
369             .name = "vendor_override",
370             .type = QEMU_OPT_NUMBER,
371         },
372         { /* end of list */ }
373     },
374 };
375
376 QemuOptsList qemu_spice_opts = {
377     .name = "spice",
378     .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
379     .desc = {
380         {
381             .name = "port",
382             .type = QEMU_OPT_NUMBER,
383         },{
384             .name = "tls-port",
385             .type = QEMU_OPT_NUMBER,
386         },{
387             .name = "addr",
388             .type = QEMU_OPT_STRING,
389         },{
390             .name = "ipv4",
391             .type = QEMU_OPT_BOOL,
392         },{
393             .name = "ipv6",
394             .type = QEMU_OPT_BOOL,
395         },{
396             .name = "password",
397             .type = QEMU_OPT_STRING,
398         },{
399             .name = "disable-ticketing",
400             .type = QEMU_OPT_BOOL,
401         },{
402             .name = "disable-copy-paste",
403             .type = QEMU_OPT_BOOL,
404         },{
405             .name = "sasl",
406             .type = QEMU_OPT_BOOL,
407         },{
408             .name = "x509-dir",
409             .type = QEMU_OPT_STRING,
410         },{
411             .name = "x509-key-file",
412             .type = QEMU_OPT_STRING,
413         },{
414             .name = "x509-key-password",
415             .type = QEMU_OPT_STRING,
416         },{
417             .name = "x509-cert-file",
418             .type = QEMU_OPT_STRING,
419         },{
420             .name = "x509-cacert-file",
421             .type = QEMU_OPT_STRING,
422         },{
423             .name = "x509-dh-key-file",
424             .type = QEMU_OPT_STRING,
425         },{
426             .name = "tls-ciphers",
427             .type = QEMU_OPT_STRING,
428         },{
429             .name = "tls-channel",
430             .type = QEMU_OPT_STRING,
431         },{
432             .name = "plaintext-channel",
433             .type = QEMU_OPT_STRING,
434         },{
435             .name = "image-compression",
436             .type = QEMU_OPT_STRING,
437         },{
438             .name = "jpeg-wan-compression",
439             .type = QEMU_OPT_STRING,
440         },{
441             .name = "zlib-glz-wan-compression",
442             .type = QEMU_OPT_STRING,
443         },{
444             .name = "streaming-video",
445             .type = QEMU_OPT_STRING,
446         },{
447             .name = "agent-mouse",
448             .type = QEMU_OPT_BOOL,
449         },{
450             .name = "playback-compression",
451             .type = QEMU_OPT_BOOL,
452         },
453         { /* end of list */ }
454     },
455 };
456
457 QemuOptsList qemu_option_rom_opts = {
458     .name = "option-rom",
459     .implied_opt_name = "romfile",
460     .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
461     .desc = {
462         {
463             .name = "bootindex",
464             .type = QEMU_OPT_NUMBER,
465         }, {
466             .name = "romfile",
467             .type = QEMU_OPT_STRING,
468         },
469         { /* end of list */ }
470     },
471 };
472
473 static QemuOptsList qemu_machine_opts = {
474     .name = "machine",
475     .implied_opt_name = "type",
476     .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
477     .desc = {
478         {
479             .name = "type",
480             .type = QEMU_OPT_STRING,
481             .help = "emulated machine"
482         }, {
483             .name = "accel",
484             .type = QEMU_OPT_STRING,
485             .help = "accelerator list",
486         },
487         { /* End of list */ }
488     },
489 };
490
491 QemuOptsList qemu_boot_opts = {
492     .name = "boot-opts",
493     .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head),
494     .desc = {
495         /* the three names below are not used now */
496         {
497             .name = "order",
498             .type = QEMU_OPT_STRING,
499         }, {
500             .name = "once",
501             .type = QEMU_OPT_STRING,
502         }, {
503             .name = "menu",
504             .type = QEMU_OPT_STRING,
505         /* following are really used */
506         }, {
507             .name = "splash",
508             .type = QEMU_OPT_STRING,
509         }, {
510             .name = "splash-time",
511             .type = QEMU_OPT_STRING,
512         },
513         { /*End of list */ }
514     },
515 };
516
517 static QemuOptsList *vm_config_groups[32] = {
518     &qemu_drive_opts,
519     &qemu_chardev_opts,
520     &qemu_device_opts,
521     &qemu_netdev_opts,
522     &qemu_net_opts,
523     &qemu_rtc_opts,
524     &qemu_global_opts,
525     &qemu_mon_opts,
526     &qemu_cpudef_opts,
527     &qemu_trace_opts,
528     &qemu_option_rom_opts,
529     &qemu_machine_opts,
530     &qemu_boot_opts,
531     NULL,
532 };
533
534 static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
535 {
536     int i;
537
538     for (i = 0; lists[i] != NULL; i++) {
539         if (strcmp(lists[i]->name, group) == 0)
540             break;
541     }
542     if (lists[i] == NULL) {
543         error_report("there is no option group \"%s\"", group);
544     }
545     return lists[i];
546 }
547
548 QemuOptsList *qemu_find_opts(const char *group)
549 {
550     return find_list(vm_config_groups, group);
551 }
552
553 void qemu_add_opts(QemuOptsList *list)
554 {
555     int entries, i;
556
557     entries = ARRAY_SIZE(vm_config_groups);
558     entries--; /* keep list NULL terminated */
559     for (i = 0; i < entries; i++) {
560         if (vm_config_groups[i] == NULL) {
561             vm_config_groups[i] = list;
562             return;
563         }
564     }
565     fprintf(stderr, "ran out of space in vm_config_groups");
566     abort();
567 }
568
569 int qemu_set_option(const char *str)
570 {
571     char group[64], id[64], arg[64];
572     QemuOptsList *list;
573     QemuOpts *opts;
574     int rc, offset;
575
576     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
577     if (rc < 3 || str[offset] != '=') {
578         error_report("can't parse: \"%s\"", str);
579         return -1;
580     }
581
582     list = qemu_find_opts(group);
583     if (list == NULL) {
584         return -1;
585     }
586
587     opts = qemu_opts_find(list, id);
588     if (!opts) {
589         error_report("there is no %s \"%s\" defined",
590                      list->name, id);
591         return -1;
592     }
593
594     if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
595         return -1;
596     }
597     return 0;
598 }
599
600 int qemu_global_option(const char *str)
601 {
602     char driver[64], property[64];
603     QemuOpts *opts;
604     int rc, offset;
605
606     rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
607     if (rc < 2 || str[offset] != '=') {
608         error_report("can't parse: \"%s\"", str);
609         return -1;
610     }
611
612     opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
613     qemu_opt_set(opts, "driver", driver);
614     qemu_opt_set(opts, "property", property);
615     qemu_opt_set(opts, "value", str+offset+1);
616     return 0;
617 }
618
619 struct ConfigWriteData {
620     QemuOptsList *list;
621     FILE *fp;
622 };
623
624 static int config_write_opt(const char *name, const char *value, void *opaque)
625 {
626     struct ConfigWriteData *data = opaque;
627
628     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
629     return 0;
630 }
631
632 static int config_write_opts(QemuOpts *opts, void *opaque)
633 {
634     struct ConfigWriteData *data = opaque;
635     const char *id = qemu_opts_id(opts);
636
637     if (id) {
638         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
639     } else {
640         fprintf(data->fp, "[%s]\n", data->list->name);
641     }
642     qemu_opt_foreach(opts, config_write_opt, data, 0);
643     fprintf(data->fp, "\n");
644     return 0;
645 }
646
647 void qemu_config_write(FILE *fp)
648 {
649     struct ConfigWriteData data = { .fp = fp };
650     QemuOptsList **lists = vm_config_groups;
651     int i;
652
653     fprintf(fp, "# qemu config file\n\n");
654     for (i = 0; lists[i] != NULL; i++) {
655         data.list = lists[i];
656         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
657     }
658 }
659
660 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
661 {
662     char line[1024], group[64], id[64], arg[64], value[1024];
663     Location loc;
664     QemuOptsList *list = NULL;
665     QemuOpts *opts = NULL;
666     int res = -1, lno = 0;
667
668     loc_push_none(&loc);
669     while (fgets(line, sizeof(line), fp) != NULL) {
670         loc_set_file(fname, ++lno);
671         if (line[0] == '\n') {
672             /* skip empty lines */
673             continue;
674         }
675         if (line[0] == '#') {
676             /* comment */
677             continue;
678         }
679         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
680             /* group with id */
681             list = find_list(lists, group);
682             if (list == NULL)
683                 goto out;
684             opts = qemu_opts_create(list, id, 1);
685             continue;
686         }
687         if (sscanf(line, "[%63[^]]]", group) == 1) {
688             /* group without id */
689             list = find_list(lists, group);
690             if (list == NULL)
691                 goto out;
692             opts = qemu_opts_create(list, NULL, 0);
693             continue;
694         }
695         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
696             /* arg = value */
697             if (opts == NULL) {
698                 error_report("no group defined");
699                 goto out;
700             }
701             if (qemu_opt_set(opts, arg, value) != 0) {
702                 goto out;
703             }
704             continue;
705         }
706         error_report("parse error");
707         goto out;
708     }
709     if (ferror(fp)) {
710         error_report("error reading file");
711         goto out;
712     }
713     res = 0;
714 out:
715     loc_pop(&loc);
716     return res;
717 }
718
719 int qemu_read_config_file(const char *filename)
720 {
721     FILE *f = fopen(filename, "r");
722     int ret;
723
724     if (f == NULL) {
725         return -errno;
726     }
727
728     ret = qemu_config_parse(f, vm_config_groups, filename);
729     fclose(f);
730
731     if (ret == 0) {
732         return 0;
733     } else {
734         return -EINVAL;
735     }
736 }
This page took 0.062356 seconds and 4 git commands to generate.