Statistics
| Branch: | Revision:

root / qemu-config.c @ 4b1b1c89

History | View | Annotate | Download (22.5 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
        { /* end of list */ }
119
    },
120
};
121

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

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

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

    
242
        }, {
243
            .name = "socket",
244
            .type = QEMU_OPT_STRING,
245
        }, {
246
            .name = "sock_fd",
247
            .type = QEMU_OPT_NUMBER,
248
        },
249

    
250
        { /*End of list */ }
251
    },
252
};
253

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

    
285
        { /*End of list */ }
286
    },
287
};
288

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

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

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

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

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

    
365
static QemuOptsList qemu_mon_opts = {
366
    .name = "mon",
367
    .implied_opt_name = "chardev",
368
    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
369
    .desc = {
370
        {
371
            .name = "mode",
372
            .type = QEMU_OPT_STRING,
373
        },{
374
            .name = "chardev",
375
            .type = QEMU_OPT_STRING,
376
        },{
377
            .name = "default",
378
            .type = QEMU_OPT_BOOL,
379
        },{
380
            .name = "pretty",
381
            .type = QEMU_OPT_BOOL,
382
        },
383
        { /* end of list */ }
384
    },
385
};
386

    
387
static QemuOptsList qemu_trace_opts = {
388
    .name = "trace",
389
    .implied_opt_name = "trace",
390
    .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
391
    .desc = {
392
        {
393
            .name = "events",
394
            .type = QEMU_OPT_STRING,
395
        },{
396
            .name = "file",
397
            .type = QEMU_OPT_STRING,
398
        },
399
        { /* end of list */ }
400
    },
401
};
402

    
403
static QemuOptsList qemu_cpudef_opts = {
404
    .name = "cpudef",
405
    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
406
    .desc = {
407
        {
408
            .name = "name",
409
            .type = QEMU_OPT_STRING,
410
        },{
411
            .name = "level",
412
            .type = QEMU_OPT_NUMBER,
413
        },{
414
            .name = "vendor",
415
            .type = QEMU_OPT_STRING,
416
        },{
417
            .name = "family",
418
            .type = QEMU_OPT_NUMBER,
419
        },{
420
            .name = "model",
421
            .type = QEMU_OPT_NUMBER,
422
        },{
423
            .name = "stepping",
424
            .type = QEMU_OPT_NUMBER,
425
        },{
426
            .name = "feature_edx",      /* cpuid 0000_0001.edx */
427
            .type = QEMU_OPT_STRING,
428
        },{
429
            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
430
            .type = QEMU_OPT_STRING,
431
        },{
432
            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
433
            .type = QEMU_OPT_STRING,
434
        },{
435
            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
436
            .type = QEMU_OPT_STRING,
437
        },{
438
            .name = "xlevel",
439
            .type = QEMU_OPT_NUMBER,
440
        },{
441
            .name = "model_id",
442
            .type = QEMU_OPT_STRING,
443
        },{
444
            .name = "vendor_override",
445
            .type = QEMU_OPT_NUMBER,
446
        },
447
        { /* end of list */ }
448
    },
449
};
450

    
451
QemuOptsList qemu_spice_opts = {
452
    .name = "spice",
453
    .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
454
    .desc = {
455
        {
456
            .name = "port",
457
            .type = QEMU_OPT_NUMBER,
458
        },{
459
            .name = "tls-port",
460
            .type = QEMU_OPT_NUMBER,
461
        },{
462
            .name = "addr",
463
            .type = QEMU_OPT_STRING,
464
        },{
465
            .name = "ipv4",
466
            .type = QEMU_OPT_BOOL,
467
        },{
468
            .name = "ipv6",
469
            .type = QEMU_OPT_BOOL,
470
        },{
471
            .name = "password",
472
            .type = QEMU_OPT_STRING,
473
        },{
474
            .name = "disable-ticketing",
475
            .type = QEMU_OPT_BOOL,
476
        },{
477
            .name = "disable-copy-paste",
478
            .type = QEMU_OPT_BOOL,
479
        },{
480
            .name = "sasl",
481
            .type = QEMU_OPT_BOOL,
482
        },{
483
            .name = "x509-dir",
484
            .type = QEMU_OPT_STRING,
485
        },{
486
            .name = "x509-key-file",
487
            .type = QEMU_OPT_STRING,
488
        },{
489
            .name = "x509-key-password",
490
            .type = QEMU_OPT_STRING,
491
        },{
492
            .name = "x509-cert-file",
493
            .type = QEMU_OPT_STRING,
494
        },{
495
            .name = "x509-cacert-file",
496
            .type = QEMU_OPT_STRING,
497
        },{
498
            .name = "x509-dh-key-file",
499
            .type = QEMU_OPT_STRING,
500
        },{
501
            .name = "tls-ciphers",
502
            .type = QEMU_OPT_STRING,
503
        },{
504
            .name = "tls-channel",
505
            .type = QEMU_OPT_STRING,
506
        },{
507
            .name = "plaintext-channel",
508
            .type = QEMU_OPT_STRING,
509
        },{
510
            .name = "image-compression",
511
            .type = QEMU_OPT_STRING,
512
        },{
513
            .name = "jpeg-wan-compression",
514
            .type = QEMU_OPT_STRING,
515
        },{
516
            .name = "zlib-glz-wan-compression",
517
            .type = QEMU_OPT_STRING,
518
        },{
519
            .name = "streaming-video",
520
            .type = QEMU_OPT_STRING,
521
        },{
522
            .name = "agent-mouse",
523
            .type = QEMU_OPT_BOOL,
524
        },{
525
            .name = "playback-compression",
526
            .type = QEMU_OPT_BOOL,
527
        },
528
        { /* end of list */ }
529
    },
530
};
531

    
532
QemuOptsList qemu_option_rom_opts = {
533
    .name = "option-rom",
534
    .implied_opt_name = "romfile",
535
    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
536
    .desc = {
537
        {
538
            .name = "bootindex",
539
            .type = QEMU_OPT_NUMBER,
540
        }, {
541
            .name = "romfile",
542
            .type = QEMU_OPT_STRING,
543
        },
544
        { /* end of list */ }
545
    },
546
};
547

    
548
static QemuOptsList qemu_machine_opts = {
549
    .name = "machine",
550
    .implied_opt_name = "type",
551
    .merge_lists = true,
552
    .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
553
    .desc = {
554
        {
555
            .name = "type",
556
            .type = QEMU_OPT_STRING,
557
            .help = "emulated machine"
558
        }, {
559
            .name = "accel",
560
            .type = QEMU_OPT_STRING,
561
            .help = "accelerator list",
562
        }, {
563
            .name = "kernel_irqchip",
564
            .type = QEMU_OPT_BOOL,
565
            .help = "use KVM in-kernel irqchip",
566
        }, {
567
            .name = "kvm_shadow_mem",
568
            .type = QEMU_OPT_SIZE,
569
            .help = "KVM shadow MMU size",
570
        }, {
571
            .name = "kernel",
572
            .type = QEMU_OPT_STRING,
573
            .help = "Linux kernel image file",
574
        }, {
575
            .name = "initrd",
576
            .type = QEMU_OPT_STRING,
577
            .help = "Linux initial ramdisk file",
578
        }, {
579
            .name = "append",
580
            .type = QEMU_OPT_STRING,
581
            .help = "Linux kernel command line",
582
        }, {
583
            .name = "dtb",
584
            .type = QEMU_OPT_STRING,
585
            .help = "Linux kernel device tree file",
586
        }, {
587
            .name = "dumpdtb",
588
            .type = QEMU_OPT_STRING,
589
            .help = "Dump current dtb to a file and quit",
590
        }, {
591
            .name = "phandle_start",
592
            .type = QEMU_OPT_STRING,
593
            .help = "The first phandle ID we may generate dynamically",
594
        },
595
        { /* End of list */ }
596
    },
597
};
598

    
599
QemuOptsList qemu_boot_opts = {
600
    .name = "boot-opts",
601
    .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head),
602
    .desc = {
603
        /* the three names below are not used now */
604
        {
605
            .name = "order",
606
            .type = QEMU_OPT_STRING,
607
        }, {
608
            .name = "once",
609
            .type = QEMU_OPT_STRING,
610
        }, {
611
            .name = "menu",
612
            .type = QEMU_OPT_STRING,
613
        /* following are really used */
614
        }, {
615
            .name = "splash",
616
            .type = QEMU_OPT_STRING,
617
        }, {
618
            .name = "splash-time",
619
            .type = QEMU_OPT_STRING,
620
        },
621
        { /*End of list */ }
622
    },
623
};
624

    
625
static QemuOptsList *vm_config_groups[32] = {
626
    &qemu_drive_opts,
627
    &qemu_chardev_opts,
628
    &qemu_device_opts,
629
    &qemu_netdev_opts,
630
    &qemu_net_opts,
631
    &qemu_rtc_opts,
632
    &qemu_global_opts,
633
    &qemu_mon_opts,
634
    &qemu_cpudef_opts,
635
    &qemu_trace_opts,
636
    &qemu_option_rom_opts,
637
    &qemu_machine_opts,
638
    &qemu_boot_opts,
639
    &qemu_iscsi_opts,
640
    NULL,
641
};
642

    
643
static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
644
                               Error **errp)
645
{
646
    int i;
647

    
648
    for (i = 0; lists[i] != NULL; i++) {
649
        if (strcmp(lists[i]->name, group) == 0)
650
            break;
651
    }
652
    if (lists[i] == NULL) {
653
        error_set(errp, QERR_INVALID_OPTION_GROUP, group);
654
    }
655
    return lists[i];
656
}
657

    
658
QemuOptsList *qemu_find_opts(const char *group)
659
{
660
    QemuOptsList *ret;
661
    Error *local_err = NULL;
662

    
663
    ret = find_list(vm_config_groups, group, &local_err);
664
    if (error_is_set(&local_err)) {
665
        error_report("%s\n", error_get_pretty(local_err));
666
        error_free(local_err);
667
    }
668

    
669
    return ret;
670
}
671

    
672
QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
673
{
674
    return find_list(vm_config_groups, group, errp);
675
}
676

    
677
void qemu_add_opts(QemuOptsList *list)
678
{
679
    int entries, i;
680

    
681
    entries = ARRAY_SIZE(vm_config_groups);
682
    entries--; /* keep list NULL terminated */
683
    for (i = 0; i < entries; i++) {
684
        if (vm_config_groups[i] == NULL) {
685
            vm_config_groups[i] = list;
686
            return;
687
        }
688
    }
689
    fprintf(stderr, "ran out of space in vm_config_groups");
690
    abort();
691
}
692

    
693
int qemu_set_option(const char *str)
694
{
695
    char group[64], id[64], arg[64];
696
    QemuOptsList *list;
697
    QemuOpts *opts;
698
    int rc, offset;
699

    
700
    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
701
    if (rc < 3 || str[offset] != '=') {
702
        error_report("can't parse: \"%s\"", str);
703
        return -1;
704
    }
705

    
706
    list = qemu_find_opts(group);
707
    if (list == NULL) {
708
        return -1;
709
    }
710

    
711
    opts = qemu_opts_find(list, id);
712
    if (!opts) {
713
        error_report("there is no %s \"%s\" defined",
714
                     list->name, id);
715
        return -1;
716
    }
717

    
718
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
719
        return -1;
720
    }
721
    return 0;
722
}
723

    
724
int qemu_global_option(const char *str)
725
{
726
    char driver[64], property[64];
727
    QemuOpts *opts;
728
    int rc, offset;
729

    
730
    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
731
    if (rc < 2 || str[offset] != '=') {
732
        error_report("can't parse: \"%s\"", str);
733
        return -1;
734
    }
735

    
736
    opts = qemu_opts_create(&qemu_global_opts, NULL, 0, NULL);
737
    qemu_opt_set(opts, "driver", driver);
738
    qemu_opt_set(opts, "property", property);
739
    qemu_opt_set(opts, "value", str+offset+1);
740
    return 0;
741
}
742

    
743
struct ConfigWriteData {
744
    QemuOptsList *list;
745
    FILE *fp;
746
};
747

    
748
static int config_write_opt(const char *name, const char *value, void *opaque)
749
{
750
    struct ConfigWriteData *data = opaque;
751

    
752
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
753
    return 0;
754
}
755

    
756
static int config_write_opts(QemuOpts *opts, void *opaque)
757
{
758
    struct ConfigWriteData *data = opaque;
759
    const char *id = qemu_opts_id(opts);
760

    
761
    if (id) {
762
        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
763
    } else {
764
        fprintf(data->fp, "[%s]\n", data->list->name);
765
    }
766
    qemu_opt_foreach(opts, config_write_opt, data, 0);
767
    fprintf(data->fp, "\n");
768
    return 0;
769
}
770

    
771
void qemu_config_write(FILE *fp)
772
{
773
    struct ConfigWriteData data = { .fp = fp };
774
    QemuOptsList **lists = vm_config_groups;
775
    int i;
776

    
777
    fprintf(fp, "# qemu config file\n\n");
778
    for (i = 0; lists[i] != NULL; i++) {
779
        data.list = lists[i];
780
        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
781
    }
782
}
783

    
784
int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
785
{
786
    char line[1024], group[64], id[64], arg[64], value[1024];
787
    Location loc;
788
    QemuOptsList *list = NULL;
789
    Error *local_err = NULL;
790
    QemuOpts *opts = NULL;
791
    int res = -1, lno = 0;
792

    
793
    loc_push_none(&loc);
794
    while (fgets(line, sizeof(line), fp) != NULL) {
795
        loc_set_file(fname, ++lno);
796
        if (line[0] == '\n') {
797
            /* skip empty lines */
798
            continue;
799
        }
800
        if (line[0] == '#') {
801
            /* comment */
802
            continue;
803
        }
804
        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
805
            /* group with id */
806
            list = find_list(lists, group, &local_err);
807
            if (error_is_set(&local_err)) {
808
                error_report("%s\n", error_get_pretty(local_err));
809
                error_free(local_err);
810
                goto out;
811
            }
812
            opts = qemu_opts_create(list, id, 1, NULL);
813
            continue;
814
        }
815
        if (sscanf(line, "[%63[^]]]", group) == 1) {
816
            /* group without id */
817
            list = find_list(lists, group, &local_err);
818
            if (error_is_set(&local_err)) {
819
                error_report("%s\n", error_get_pretty(local_err));
820
                error_free(local_err);
821
                goto out;
822
            }
823
            opts = qemu_opts_create(list, NULL, 0, NULL);
824
            continue;
825
        }
826
        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
827
            /* arg = value */
828
            if (opts == NULL) {
829
                error_report("no group defined");
830
                goto out;
831
            }
832
            if (qemu_opt_set(opts, arg, value) != 0) {
833
                goto out;
834
            }
835
            continue;
836
        }
837
        error_report("parse error");
838
        goto out;
839
    }
840
    if (ferror(fp)) {
841
        error_report("error reading file");
842
        goto out;
843
    }
844
    res = 0;
845
out:
846
    loc_pop(&loc);
847
    return res;
848
}
849

    
850
int qemu_read_config_file(const char *filename)
851
{
852
    FILE *f = fopen(filename, "r");
853
    int ret;
854

    
855
    if (f == NULL) {
856
        return -errno;
857
    }
858

    
859
    ret = qemu_config_parse(f, vm_config_groups, filename);
860
    fclose(f);
861

    
862
    if (ret == 0) {
863
        return 0;
864
    } else {
865
        return -EINVAL;
866
    }
867
}