Statistics
| Branch: | Revision:

root / qemu-config.c @ 511c68d3

History | View | Annotate | Download (23.2 kB)

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
#include "error.h"
7

    
8
static 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
            .help = "index number",
28
        },{
29
            .name = "cyls",
30
            .type = QEMU_OPT_NUMBER,
31
            .help = "number of cylinders (ide disk geometry)",
32
        },{
33
            .name = "heads",
34
            .type = QEMU_OPT_NUMBER,
35
            .help = "number of heads (ide disk geometry)",
36
        },{
37
            .name = "secs",
38
            .type = QEMU_OPT_NUMBER,
39
            .help = "number of sectors (ide disk geometry)",
40
        },{
41
            .name = "trans",
42
            .type = QEMU_OPT_STRING,
43
            .help = "chs translation (auto, lba. none)",
44
        },{
45
            .name = "media",
46
            .type = QEMU_OPT_STRING,
47
            .help = "media type (disk, cdrom)",
48
        },{
49
            .name = "snapshot",
50
            .type = QEMU_OPT_BOOL,
51
            .help = "enable/disable snapshot mode",
52
        },{
53
            .name = "file",
54
            .type = QEMU_OPT_STRING,
55
            .help = "disk image",
56
        },{
57
            .name = "cache",
58
            .type = QEMU_OPT_STRING,
59
            .help = "host cache usage (none, writeback, writethrough, "
60
                    "directsync, unsafe)",
61
        },{
62
            .name = "aio",
63
            .type = QEMU_OPT_STRING,
64
            .help = "host AIO implementation (threads, native)",
65
        },{
66
            .name = "format",
67
            .type = QEMU_OPT_STRING,
68
            .help = "disk format (raw, qcow2, ...)",
69
        },{
70
            .name = "serial",
71
            .type = QEMU_OPT_STRING,
72
            .help = "disk serial number",
73
        },{
74
            .name = "rerror",
75
            .type = QEMU_OPT_STRING,
76
            .help = "read error action",
77
        },{
78
            .name = "werror",
79
            .type = QEMU_OPT_STRING,
80
            .help = "write error action",
81
        },{
82
            .name = "addr",
83
            .type = QEMU_OPT_STRING,
84
            .help = "pci address (virtio only)",
85
        },{
86
            .name = "readonly",
87
            .type = QEMU_OPT_BOOL,
88
            .help = "open drive file as read-only",
89
        },{
90
            .name = "iops",
91
            .type = QEMU_OPT_NUMBER,
92
            .help = "limit total I/O operations per second",
93
        },{
94
            .name = "iops_rd",
95
            .type = QEMU_OPT_NUMBER,
96
            .help = "limit read operations per second",
97
        },{
98
            .name = "iops_wr",
99
            .type = QEMU_OPT_NUMBER,
100
            .help = "limit write operations per second",
101
        },{
102
            .name = "bps",
103
            .type = QEMU_OPT_NUMBER,
104
            .help = "limit total bytes per second",
105
        },{
106
            .name = "bps_rd",
107
            .type = QEMU_OPT_NUMBER,
108
            .help = "limit read bytes per second",
109
        },{
110
            .name = "bps_wr",
111
            .type = QEMU_OPT_NUMBER,
112
            .help = "limit write bytes per second",
113
        },{
114
            .name = "copy-on-read",
115
            .type = QEMU_OPT_BOOL,
116
            .help = "copy read data from backing file into image file",
117
        },{
118
            .name = "boot",
119
            .type = QEMU_OPT_BOOL,
120
            .help = "(deprecated, ignored)",
121
        },
122
        { /* end of list */ }
123
    },
124
};
125

    
126
static QemuOptsList qemu_iscsi_opts = {
127
    .name = "iscsi",
128
    .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head),
129
    .desc = {
130
        {
131
            .name = "user",
132
            .type = QEMU_OPT_STRING,
133
            .help = "username for CHAP authentication to target",
134
        },{
135
            .name = "password",
136
            .type = QEMU_OPT_STRING,
137
            .help = "password for CHAP authentication to target",
138
        },{
139
            .name = "header-digest",
140
            .type = QEMU_OPT_STRING,
141
            .help = "HeaderDigest setting. "
142
                    "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}",
143
        },{
144
            .name = "initiator-name",
145
            .type = QEMU_OPT_STRING,
146
            .help = "Initiator iqn name to use when connecting",
147
        },
148
        { /* end of list */ }
149
    },
150
};
151

    
152
static QemuOptsList qemu_chardev_opts = {
153
    .name = "chardev",
154
    .implied_opt_name = "backend",
155
    .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
156
    .desc = {
157
        {
158
            .name = "backend",
159
            .type = QEMU_OPT_STRING,
160
        },{
161
            .name = "path",
162
            .type = QEMU_OPT_STRING,
163
        },{
164
            .name = "host",
165
            .type = QEMU_OPT_STRING,
166
        },{
167
            .name = "port",
168
            .type = QEMU_OPT_STRING,
169
        },{
170
            .name = "localaddr",
171
            .type = QEMU_OPT_STRING,
172
        },{
173
            .name = "localport",
174
            .type = QEMU_OPT_STRING,
175
        },{
176
            .name = "to",
177
            .type = QEMU_OPT_NUMBER,
178
        },{
179
            .name = "ipv4",
180
            .type = QEMU_OPT_BOOL,
181
        },{
182
            .name = "ipv6",
183
            .type = QEMU_OPT_BOOL,
184
        },{
185
            .name = "wait",
186
            .type = QEMU_OPT_BOOL,
187
        },{
188
            .name = "server",
189
            .type = QEMU_OPT_BOOL,
190
        },{
191
            .name = "delay",
192
            .type = QEMU_OPT_BOOL,
193
        },{
194
            .name = "telnet",
195
            .type = QEMU_OPT_BOOL,
196
        },{
197
            .name = "width",
198
            .type = QEMU_OPT_NUMBER,
199
        },{
200
            .name = "height",
201
            .type = QEMU_OPT_NUMBER,
202
        },{
203
            .name = "cols",
204
            .type = QEMU_OPT_NUMBER,
205
        },{
206
            .name = "rows",
207
            .type = QEMU_OPT_NUMBER,
208
        },{
209
            .name = "mux",
210
            .type = QEMU_OPT_BOOL,
211
        },{
212
            .name = "signal",
213
            .type = QEMU_OPT_BOOL,
214
        },{
215
            .name = "name",
216
            .type = QEMU_OPT_STRING,
217
        },{
218
            .name = "debug",
219
            .type = QEMU_OPT_NUMBER,
220
        },
221
        { /* end of list */ }
222
    },
223
};
224

    
225
QemuOptsList qemu_fsdev_opts = {
226
    .name = "fsdev",
227
    .implied_opt_name = "fsdriver",
228
    .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
229
    .desc = {
230
        {
231
            .name = "fsdriver",
232
            .type = QEMU_OPT_STRING,
233
        }, {
234
            .name = "path",
235
            .type = QEMU_OPT_STRING,
236
        }, {
237
            .name = "security_model",
238
            .type = QEMU_OPT_STRING,
239
        }, {
240
            .name = "writeout",
241
            .type = QEMU_OPT_STRING,
242
        }, {
243
            .name = "readonly",
244
            .type = QEMU_OPT_BOOL,
245

    
246
        }, {
247
            .name = "socket",
248
            .type = QEMU_OPT_STRING,
249
        }, {
250
            .name = "sock_fd",
251
            .type = QEMU_OPT_NUMBER,
252
        },
253

    
254
        { /*End of list */ }
255
    },
256
};
257

    
258
QemuOptsList qemu_virtfs_opts = {
259
    .name = "virtfs",
260
    .implied_opt_name = "fsdriver",
261
    .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
262
    .desc = {
263
        {
264
            .name = "fsdriver",
265
            .type = QEMU_OPT_STRING,
266
        }, {
267
            .name = "path",
268
            .type = QEMU_OPT_STRING,
269
        }, {
270
            .name = "mount_tag",
271
            .type = QEMU_OPT_STRING,
272
        }, {
273
            .name = "security_model",
274
            .type = QEMU_OPT_STRING,
275
        }, {
276
            .name = "writeout",
277
            .type = QEMU_OPT_STRING,
278
        }, {
279
            .name = "readonly",
280
            .type = QEMU_OPT_BOOL,
281
        }, {
282
            .name = "socket",
283
            .type = QEMU_OPT_STRING,
284
        }, {
285
            .name = "sock_fd",
286
            .type = QEMU_OPT_NUMBER,
287
        },
288

    
289
        { /*End of list */ }
290
    },
291
};
292

    
293
static QemuOptsList qemu_device_opts = {
294
    .name = "device",
295
    .implied_opt_name = "driver",
296
    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
297
    .desc = {
298
        /*
299
         * no elements => accept any
300
         * sanity checking will happen later
301
         * when setting device properties
302
         */
303
        { /* end of list */ }
304
    },
305
};
306

    
307
static QemuOptsList qemu_netdev_opts = {
308
    .name = "netdev",
309
    .implied_opt_name = "type",
310
    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
311
    .desc = {
312
        /*
313
         * no elements => accept any params
314
         * validation will happen later
315
         */
316
        { /* end of list */ }
317
    },
318
};
319

    
320
static QemuOptsList qemu_net_opts = {
321
    .name = "net",
322
    .implied_opt_name = "type",
323
    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
324
    .desc = {
325
        /*
326
         * no elements => accept any params
327
         * validation will happen later
328
         */
329
        { /* end of list */ }
330
    },
331
};
332

    
333
static QemuOptsList qemu_rtc_opts = {
334
    .name = "rtc",
335
    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
336
    .desc = {
337
        {
338
            .name = "base",
339
            .type = QEMU_OPT_STRING,
340
        },{
341
            .name = "clock",
342
            .type = QEMU_OPT_STRING,
343
        },{
344
            .name = "driftfix",
345
            .type = QEMU_OPT_STRING,
346
        },
347
        { /* end of list */ }
348
    },
349
};
350

    
351
static QemuOptsList qemu_global_opts = {
352
    .name = "global",
353
    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
354
    .desc = {
355
        {
356
            .name = "driver",
357
            .type = QEMU_OPT_STRING,
358
        },{
359
            .name = "property",
360
            .type = QEMU_OPT_STRING,
361
        },{
362
            .name = "value",
363
            .type = QEMU_OPT_STRING,
364
        },
365
        { /* end of list */ }
366
    },
367
};
368

    
369
QemuOptsList qemu_sandbox_opts = {
370
    .name = "sandbox",
371
    .implied_opt_name = "enable",
372
    .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head),
373
    .desc = {
374
        {
375
            .name = "enable",
376
            .type = QEMU_OPT_BOOL,
377
        },
378
        { /* end of list */ }
379
    },
380
};
381

    
382
static QemuOptsList qemu_mon_opts = {
383
    .name = "mon",
384
    .implied_opt_name = "chardev",
385
    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
386
    .desc = {
387
        {
388
            .name = "mode",
389
            .type = QEMU_OPT_STRING,
390
        },{
391
            .name = "chardev",
392
            .type = QEMU_OPT_STRING,
393
        },{
394
            .name = "default",
395
            .type = QEMU_OPT_BOOL,
396
        },{
397
            .name = "pretty",
398
            .type = QEMU_OPT_BOOL,
399
        },
400
        { /* end of list */ }
401
    },
402
};
403

    
404
static QemuOptsList qemu_trace_opts = {
405
    .name = "trace",
406
    .implied_opt_name = "trace",
407
    .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
408
    .desc = {
409
        {
410
            .name = "events",
411
            .type = QEMU_OPT_STRING,
412
        },{
413
            .name = "file",
414
            .type = QEMU_OPT_STRING,
415
        },
416
        { /* end of list */ }
417
    },
418
};
419

    
420
QemuOptsList qemu_spice_opts = {
421
    .name = "spice",
422
    .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
423
    .desc = {
424
        {
425
            .name = "port",
426
            .type = QEMU_OPT_NUMBER,
427
        },{
428
            .name = "tls-port",
429
            .type = QEMU_OPT_NUMBER,
430
        },{
431
            .name = "addr",
432
            .type = QEMU_OPT_STRING,
433
        },{
434
            .name = "ipv4",
435
            .type = QEMU_OPT_BOOL,
436
        },{
437
            .name = "ipv6",
438
            .type = QEMU_OPT_BOOL,
439
        },{
440
            .name = "password",
441
            .type = QEMU_OPT_STRING,
442
        },{
443
            .name = "disable-ticketing",
444
            .type = QEMU_OPT_BOOL,
445
        },{
446
            .name = "disable-copy-paste",
447
            .type = QEMU_OPT_BOOL,
448
        },{
449
            .name = "sasl",
450
            .type = QEMU_OPT_BOOL,
451
        },{
452
            .name = "x509-dir",
453
            .type = QEMU_OPT_STRING,
454
        },{
455
            .name = "x509-key-file",
456
            .type = QEMU_OPT_STRING,
457
        },{
458
            .name = "x509-key-password",
459
            .type = QEMU_OPT_STRING,
460
        },{
461
            .name = "x509-cert-file",
462
            .type = QEMU_OPT_STRING,
463
        },{
464
            .name = "x509-cacert-file",
465
            .type = QEMU_OPT_STRING,
466
        },{
467
            .name = "x509-dh-key-file",
468
            .type = QEMU_OPT_STRING,
469
        },{
470
            .name = "tls-ciphers",
471
            .type = QEMU_OPT_STRING,
472
        },{
473
            .name = "tls-channel",
474
            .type = QEMU_OPT_STRING,
475
        },{
476
            .name = "plaintext-channel",
477
            .type = QEMU_OPT_STRING,
478
        },{
479
            .name = "image-compression",
480
            .type = QEMU_OPT_STRING,
481
        },{
482
            .name = "jpeg-wan-compression",
483
            .type = QEMU_OPT_STRING,
484
        },{
485
            .name = "zlib-glz-wan-compression",
486
            .type = QEMU_OPT_STRING,
487
        },{
488
            .name = "streaming-video",
489
            .type = QEMU_OPT_STRING,
490
        },{
491
            .name = "agent-mouse",
492
            .type = QEMU_OPT_BOOL,
493
        },{
494
            .name = "playback-compression",
495
            .type = QEMU_OPT_BOOL,
496
        }, {
497
            .name = "seamless-migration",
498
            .type = QEMU_OPT_BOOL,
499
        },
500
        { /* end of list */ }
501
    },
502
};
503

    
504
QemuOptsList qemu_option_rom_opts = {
505
    .name = "option-rom",
506
    .implied_opt_name = "romfile",
507
    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
508
    .desc = {
509
        {
510
            .name = "bootindex",
511
            .type = QEMU_OPT_NUMBER,
512
        }, {
513
            .name = "romfile",
514
            .type = QEMU_OPT_STRING,
515
        },
516
        { /* end of list */ }
517
    },
518
};
519

    
520
static QemuOptsList qemu_machine_opts = {
521
    .name = "machine",
522
    .implied_opt_name = "type",
523
    .merge_lists = true,
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
            .name = "kvm_shadow_mem",
540
            .type = QEMU_OPT_SIZE,
541
            .help = "KVM shadow MMU size",
542
        }, {
543
            .name = "kernel",
544
            .type = QEMU_OPT_STRING,
545
            .help = "Linux kernel image file",
546
        }, {
547
            .name = "initrd",
548
            .type = QEMU_OPT_STRING,
549
            .help = "Linux initial ramdisk file",
550
        }, {
551
            .name = "append",
552
            .type = QEMU_OPT_STRING,
553
            .help = "Linux kernel command line",
554
        }, {
555
            .name = "dtb",
556
            .type = QEMU_OPT_STRING,
557
            .help = "Linux kernel device tree file",
558
        }, {
559
            .name = "dumpdtb",
560
            .type = QEMU_OPT_STRING,
561
            .help = "Dump current dtb to a file and quit",
562
        }, {
563
            .name = "phandle_start",
564
            .type = QEMU_OPT_STRING,
565
            .help = "The first phandle ID we may generate dynamically",
566
        }, {
567
            .name = "dt_compatible",
568
            .type = QEMU_OPT_STRING,
569
            .help = "Overrides the \"compatible\" property of the dt root node",
570
        }, {
571
            .name = "dump-guest-core",
572
            .type = QEMU_OPT_BOOL,
573
            .help = "Include guest memory in  a core dump",
574
        }, {
575
            .name = "mem-merge",
576
            .type = QEMU_OPT_BOOL,
577
            .help = "enable/disable memory merge support",
578
        },{
579
            .name = "usb",
580
            .type = QEMU_OPT_BOOL,
581
            .help = "Set on/off to enable/disable usb",
582
        },
583
        { /* End of list */ }
584
    },
585
};
586

    
587
QemuOptsList qemu_boot_opts = {
588
    .name = "boot-opts",
589
    .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head),
590
    .desc = {
591
        /* the three names below are not used now */
592
        {
593
            .name = "order",
594
            .type = QEMU_OPT_STRING,
595
        }, {
596
            .name = "once",
597
            .type = QEMU_OPT_STRING,
598
        }, {
599
            .name = "menu",
600
            .type = QEMU_OPT_STRING,
601
        /* following are really used */
602
        }, {
603
            .name = "splash",
604
            .type = QEMU_OPT_STRING,
605
        }, {
606
            .name = "splash-time",
607
            .type = QEMU_OPT_STRING,
608
        }, {
609
            .name = "reboot-timeout",
610
            .type = QEMU_OPT_STRING,
611
        },
612
        { /*End of list */ }
613
    },
614
};
615

    
616
static QemuOptsList qemu_add_fd_opts = {
617
    .name = "add-fd",
618
    .head = QTAILQ_HEAD_INITIALIZER(qemu_add_fd_opts.head),
619
    .desc = {
620
        {
621
            .name = "fd",
622
            .type = QEMU_OPT_NUMBER,
623
            .help = "file descriptor of which a duplicate is added to fd set",
624
        },{
625
            .name = "set",
626
            .type = QEMU_OPT_NUMBER,
627
            .help = "ID of the fd set to add fd to",
628
        },{
629
            .name = "opaque",
630
            .type = QEMU_OPT_STRING,
631
            .help = "free-form string used to describe fd",
632
        },
633
        { /* end of list */ }
634
    },
635
};
636

    
637
static QemuOptsList qemu_object_opts = {
638
    .name = "object",
639
    .implied_opt_name = "qom-type",
640
    .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
641
    .desc = {
642
        { }
643
    },
644
};
645

    
646
static QemuOptsList *vm_config_groups[32] = {
647
    &qemu_drive_opts,
648
    &qemu_chardev_opts,
649
    &qemu_device_opts,
650
    &qemu_netdev_opts,
651
    &qemu_net_opts,
652
    &qemu_rtc_opts,
653
    &qemu_global_opts,
654
    &qemu_mon_opts,
655
    &qemu_trace_opts,
656
    &qemu_option_rom_opts,
657
    &qemu_machine_opts,
658
    &qemu_boot_opts,
659
    &qemu_iscsi_opts,
660
    &qemu_sandbox_opts,
661
    &qemu_add_fd_opts,
662
    &qemu_object_opts,
663
    NULL,
664
};
665

    
666
static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
667
                               Error **errp)
668
{
669
    int i;
670

    
671
    for (i = 0; lists[i] != NULL; i++) {
672
        if (strcmp(lists[i]->name, group) == 0)
673
            break;
674
    }
675
    if (lists[i] == NULL) {
676
        error_set(errp, QERR_INVALID_OPTION_GROUP, group);
677
    }
678
    return lists[i];
679
}
680

    
681
QemuOptsList *qemu_find_opts(const char *group)
682
{
683
    QemuOptsList *ret;
684
    Error *local_err = NULL;
685

    
686
    ret = find_list(vm_config_groups, group, &local_err);
687
    if (error_is_set(&local_err)) {
688
        error_report("%s\n", error_get_pretty(local_err));
689
        error_free(local_err);
690
    }
691

    
692
    return ret;
693
}
694

    
695
QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
696
{
697
    return find_list(vm_config_groups, group, errp);
698
}
699

    
700
void qemu_add_opts(QemuOptsList *list)
701
{
702
    int entries, i;
703

    
704
    entries = ARRAY_SIZE(vm_config_groups);
705
    entries--; /* keep list NULL terminated */
706
    for (i = 0; i < entries; i++) {
707
        if (vm_config_groups[i] == NULL) {
708
            vm_config_groups[i] = list;
709
            return;
710
        }
711
    }
712
    fprintf(stderr, "ran out of space in vm_config_groups");
713
    abort();
714
}
715

    
716
int qemu_set_option(const char *str)
717
{
718
    char group[64], id[64], arg[64];
719
    QemuOptsList *list;
720
    QemuOpts *opts;
721
    int rc, offset;
722

    
723
    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
724
    if (rc < 3 || str[offset] != '=') {
725
        error_report("can't parse: \"%s\"", str);
726
        return -1;
727
    }
728

    
729
    list = qemu_find_opts(group);
730
    if (list == NULL) {
731
        return -1;
732
    }
733

    
734
    opts = qemu_opts_find(list, id);
735
    if (!opts) {
736
        error_report("there is no %s \"%s\" defined",
737
                     list->name, id);
738
        return -1;
739
    }
740

    
741
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
742
        return -1;
743
    }
744
    return 0;
745
}
746

    
747
int qemu_global_option(const char *str)
748
{
749
    char driver[64], property[64];
750
    QemuOpts *opts;
751
    int rc, offset;
752

    
753
    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
754
    if (rc < 2 || str[offset] != '=') {
755
        error_report("can't parse: \"%s\"", str);
756
        return -1;
757
    }
758

    
759
    opts = qemu_opts_create(&qemu_global_opts, NULL, 0, NULL);
760
    qemu_opt_set(opts, "driver", driver);
761
    qemu_opt_set(opts, "property", property);
762
    qemu_opt_set(opts, "value", str+offset+1);
763
    return 0;
764
}
765

    
766
struct ConfigWriteData {
767
    QemuOptsList *list;
768
    FILE *fp;
769
};
770

    
771
static int config_write_opt(const char *name, const char *value, void *opaque)
772
{
773
    struct ConfigWriteData *data = opaque;
774

    
775
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
776
    return 0;
777
}
778

    
779
static int config_write_opts(QemuOpts *opts, void *opaque)
780
{
781
    struct ConfigWriteData *data = opaque;
782
    const char *id = qemu_opts_id(opts);
783

    
784
    if (id) {
785
        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
786
    } else {
787
        fprintf(data->fp, "[%s]\n", data->list->name);
788
    }
789
    qemu_opt_foreach(opts, config_write_opt, data, 0);
790
    fprintf(data->fp, "\n");
791
    return 0;
792
}
793

    
794
void qemu_config_write(FILE *fp)
795
{
796
    struct ConfigWriteData data = { .fp = fp };
797
    QemuOptsList **lists = vm_config_groups;
798
    int i;
799

    
800
    fprintf(fp, "# qemu config file\n\n");
801
    for (i = 0; lists[i] != NULL; i++) {
802
        data.list = lists[i];
803
        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
804
    }
805
}
806

    
807
int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
808
{
809
    char line[1024], group[64], id[64], arg[64], value[1024];
810
    Location loc;
811
    QemuOptsList *list = NULL;
812
    Error *local_err = NULL;
813
    QemuOpts *opts = NULL;
814
    int res = -1, lno = 0;
815

    
816
    loc_push_none(&loc);
817
    while (fgets(line, sizeof(line), fp) != NULL) {
818
        loc_set_file(fname, ++lno);
819
        if (line[0] == '\n') {
820
            /* skip empty lines */
821
            continue;
822
        }
823
        if (line[0] == '#') {
824
            /* comment */
825
            continue;
826
        }
827
        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
828
            /* group with id */
829
            list = find_list(lists, group, &local_err);
830
            if (error_is_set(&local_err)) {
831
                error_report("%s\n", error_get_pretty(local_err));
832
                error_free(local_err);
833
                goto out;
834
            }
835
            opts = qemu_opts_create(list, id, 1, NULL);
836
            continue;
837
        }
838
        if (sscanf(line, "[%63[^]]]", group) == 1) {
839
            /* group without id */
840
            list = find_list(lists, group, &local_err);
841
            if (error_is_set(&local_err)) {
842
                error_report("%s\n", error_get_pretty(local_err));
843
                error_free(local_err);
844
                goto out;
845
            }
846
            opts = qemu_opts_create(list, NULL, 0, NULL);
847
            continue;
848
        }
849
        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
850
            /* arg = value */
851
            if (opts == NULL) {
852
                error_report("no group defined");
853
                goto out;
854
            }
855
            if (qemu_opt_set(opts, arg, value) != 0) {
856
                goto out;
857
            }
858
            continue;
859
        }
860
        error_report("parse error");
861
        goto out;
862
    }
863
    if (ferror(fp)) {
864
        error_report("error reading file");
865
        goto out;
866
    }
867
    res = 0;
868
out:
869
    loc_pop(&loc);
870
    return res;
871
}
872

    
873
int qemu_read_config_file(const char *filename)
874
{
875
    FILE *f = fopen(filename, "r");
876
    int ret;
877

    
878
    if (f == NULL) {
879
        return -errno;
880
    }
881

    
882
    ret = qemu_config_parse(f, vm_config_groups, filename);
883
    fclose(f);
884

    
885
    if (ret == 0) {
886
        return 0;
887
    } else {
888
        return -EINVAL;
889
    }
890
}