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