Statistics
| Branch: | Revision:

root / qemu-config.c @ 23d15e86

History | View | Annotate | Download (18.4 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

    
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 = "fstype",
169
    .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
170
    .desc = {
171
        {
172
            .name = "fstype",
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
        { /*End of list */ }
182
    },
183
};
184

    
185
QemuOptsList qemu_virtfs_opts = {
186
    .name = "virtfs",
187
    .implied_opt_name = "fstype",
188
    .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
189
    .desc = {
190
        {
191
            .name = "fstype",
192
            .type = QEMU_OPT_STRING,
193
        }, {
194
            .name = "path",
195
            .type = QEMU_OPT_STRING,
196
        }, {
197
            .name = "mount_tag",
198
            .type = QEMU_OPT_STRING,
199
        }, {
200
            .name = "security_model",
201
            .type = QEMU_OPT_STRING,
202
        },
203

    
204
        { /*End of list */ }
205
    },
206
};
207

    
208
static QemuOptsList qemu_device_opts = {
209
    .name = "device",
210
    .implied_opt_name = "driver",
211
    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
212
    .desc = {
213
        /*
214
         * no elements => accept any
215
         * sanity checking will happen later
216
         * when setting device properties
217
         */
218
        { /* end of list */ }
219
    },
220
};
221

    
222
static QemuOptsList qemu_netdev_opts = {
223
    .name = "netdev",
224
    .implied_opt_name = "type",
225
    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
226
    .desc = {
227
        /*
228
         * no elements => accept any params
229
         * validation will happen later
230
         */
231
        { /* end of list */ }
232
    },
233
};
234

    
235
static QemuOptsList qemu_net_opts = {
236
    .name = "net",
237
    .implied_opt_name = "type",
238
    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
239
    .desc = {
240
        /*
241
         * no elements => accept any params
242
         * validation will happen later
243
         */
244
        { /* end of list */ }
245
    },
246
};
247

    
248
static QemuOptsList qemu_rtc_opts = {
249
    .name = "rtc",
250
    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
251
    .desc = {
252
        {
253
            .name = "base",
254
            .type = QEMU_OPT_STRING,
255
        },{
256
            .name = "clock",
257
            .type = QEMU_OPT_STRING,
258
        },{
259
            .name = "driftfix",
260
            .type = QEMU_OPT_STRING,
261
        },
262
        { /* end of list */ }
263
    },
264
};
265

    
266
static QemuOptsList qemu_global_opts = {
267
    .name = "global",
268
    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
269
    .desc = {
270
        {
271
            .name = "driver",
272
            .type = QEMU_OPT_STRING,
273
        },{
274
            .name = "property",
275
            .type = QEMU_OPT_STRING,
276
        },{
277
            .name = "value",
278
            .type = QEMU_OPT_STRING,
279
        },
280
        { /* end of list */ }
281
    },
282
};
283

    
284
static QemuOptsList qemu_mon_opts = {
285
    .name = "mon",
286
    .implied_opt_name = "chardev",
287
    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
288
    .desc = {
289
        {
290
            .name = "mode",
291
            .type = QEMU_OPT_STRING,
292
        },{
293
            .name = "chardev",
294
            .type = QEMU_OPT_STRING,
295
        },{
296
            .name = "default",
297
            .type = QEMU_OPT_BOOL,
298
        },{
299
            .name = "pretty",
300
            .type = QEMU_OPT_BOOL,
301
        },
302
        { /* end of list */ }
303
    },
304
};
305

    
306
static QemuOptsList qemu_trace_opts = {
307
    .name = "trace",
308
    .implied_opt_name = "trace",
309
    .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
310
    .desc = {
311
        {
312
            .name = "events",
313
            .type = QEMU_OPT_STRING,
314
        },{
315
            .name = "file",
316
            .type = QEMU_OPT_STRING,
317
        },
318
        { /* end of list */ }
319
    },
320
};
321

    
322
static QemuOptsList qemu_cpudef_opts = {
323
    .name = "cpudef",
324
    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
325
    .desc = {
326
        {
327
            .name = "name",
328
            .type = QEMU_OPT_STRING,
329
        },{
330
            .name = "level",
331
            .type = QEMU_OPT_NUMBER,
332
        },{
333
            .name = "vendor",
334
            .type = QEMU_OPT_STRING,
335
        },{
336
            .name = "family",
337
            .type = QEMU_OPT_NUMBER,
338
        },{
339
            .name = "model",
340
            .type = QEMU_OPT_NUMBER,
341
        },{
342
            .name = "stepping",
343
            .type = QEMU_OPT_NUMBER,
344
        },{
345
            .name = "feature_edx",      /* cpuid 0000_0001.edx */
346
            .type = QEMU_OPT_STRING,
347
        },{
348
            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
349
            .type = QEMU_OPT_STRING,
350
        },{
351
            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
352
            .type = QEMU_OPT_STRING,
353
        },{
354
            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
355
            .type = QEMU_OPT_STRING,
356
        },{
357
            .name = "xlevel",
358
            .type = QEMU_OPT_NUMBER,
359
        },{
360
            .name = "model_id",
361
            .type = QEMU_OPT_STRING,
362
        },{
363
            .name = "vendor_override",
364
            .type = QEMU_OPT_NUMBER,
365
        },
366
        { /* end of list */ }
367
    },
368
};
369

    
370
QemuOptsList qemu_spice_opts = {
371
    .name = "spice",
372
    .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
373
    .desc = {
374
        {
375
            .name = "port",
376
            .type = QEMU_OPT_NUMBER,
377
        },{
378
            .name = "tls-port",
379
            .type = QEMU_OPT_NUMBER,
380
        },{
381
            .name = "addr",
382
            .type = QEMU_OPT_STRING,
383
        },{
384
            .name = "ipv4",
385
            .type = QEMU_OPT_BOOL,
386
        },{
387
            .name = "ipv6",
388
            .type = QEMU_OPT_BOOL,
389
        },{
390
            .name = "password",
391
            .type = QEMU_OPT_STRING,
392
        },{
393
            .name = "disable-ticketing",
394
            .type = QEMU_OPT_BOOL,
395
        },{
396
            .name = "disable-copy-paste",
397
            .type = QEMU_OPT_BOOL,
398
        },{
399
            .name = "sasl",
400
            .type = QEMU_OPT_BOOL,
401
        },{
402
            .name = "x509-dir",
403
            .type = QEMU_OPT_STRING,
404
        },{
405
            .name = "x509-key-file",
406
            .type = QEMU_OPT_STRING,
407
        },{
408
            .name = "x509-key-password",
409
            .type = QEMU_OPT_STRING,
410
        },{
411
            .name = "x509-cert-file",
412
            .type = QEMU_OPT_STRING,
413
        },{
414
            .name = "x509-cacert-file",
415
            .type = QEMU_OPT_STRING,
416
        },{
417
            .name = "x509-dh-key-file",
418
            .type = QEMU_OPT_STRING,
419
        },{
420
            .name = "tls-ciphers",
421
            .type = QEMU_OPT_STRING,
422
        },{
423
            .name = "tls-channel",
424
            .type = QEMU_OPT_STRING,
425
        },{
426
            .name = "plaintext-channel",
427
            .type = QEMU_OPT_STRING,
428
        },{
429
            .name = "image-compression",
430
            .type = QEMU_OPT_STRING,
431
        },{
432
            .name = "jpeg-wan-compression",
433
            .type = QEMU_OPT_STRING,
434
        },{
435
            .name = "zlib-glz-wan-compression",
436
            .type = QEMU_OPT_STRING,
437
        },{
438
            .name = "streaming-video",
439
            .type = QEMU_OPT_STRING,
440
        },{
441
            .name = "agent-mouse",
442
            .type = QEMU_OPT_BOOL,
443
        },{
444
            .name = "playback-compression",
445
            .type = QEMU_OPT_BOOL,
446
        },
447
        { /* end of list */ }
448
    },
449
};
450

    
451
QemuOptsList qemu_option_rom_opts = {
452
    .name = "option-rom",
453
    .implied_opt_name = "romfile",
454
    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
455
    .desc = {
456
        {
457
            .name = "bootindex",
458
            .type = QEMU_OPT_NUMBER,
459
        }, {
460
            .name = "romfile",
461
            .type = QEMU_OPT_STRING,
462
        },
463
        { /* end of list */ }
464
    },
465
};
466

    
467
static QemuOptsList qemu_machine_opts = {
468
    .name = "machine",
469
    .implied_opt_name = "type",
470
    .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
471
    .desc = {
472
        {
473
            .name = "type",
474
            .type = QEMU_OPT_STRING,
475
            .help = "emulated machine"
476
        }, {
477
            .name = "accel",
478
            .type = QEMU_OPT_STRING,
479
            .help = "accelerator list",
480
        },
481
        { /* End of list */ }
482
    },
483
};
484

    
485
QemuOptsList qemu_boot_opts = {
486
    .name = "boot-opts",
487
    .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head),
488
    .desc = {
489
        /* the three names below are not used now */
490
        {
491
            .name = "order",
492
            .type = QEMU_OPT_STRING,
493
        }, {
494
            .name = "once",
495
            .type = QEMU_OPT_STRING,
496
        }, {
497
            .name = "menu",
498
            .type = QEMU_OPT_STRING,
499
        /* following are really used */
500
        }, {
501
            .name = "splash",
502
            .type = QEMU_OPT_STRING,
503
        }, {
504
            .name = "splash-time",
505
            .type = QEMU_OPT_STRING,
506
        },
507
        { /*End of list */ }
508
    },
509
};
510

    
511
static QemuOptsList *vm_config_groups[32] = {
512
    &qemu_drive_opts,
513
    &qemu_chardev_opts,
514
    &qemu_device_opts,
515
    &qemu_netdev_opts,
516
    &qemu_net_opts,
517
    &qemu_rtc_opts,
518
    &qemu_global_opts,
519
    &qemu_mon_opts,
520
    &qemu_cpudef_opts,
521
    &qemu_trace_opts,
522
    &qemu_option_rom_opts,
523
    &qemu_machine_opts,
524
    &qemu_boot_opts,
525
    NULL,
526
};
527

    
528
static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
529
{
530
    int i;
531

    
532
    for (i = 0; lists[i] != NULL; i++) {
533
        if (strcmp(lists[i]->name, group) == 0)
534
            break;
535
    }
536
    if (lists[i] == NULL) {
537
        error_report("there is no option group \"%s\"", group);
538
    }
539
    return lists[i];
540
}
541

    
542
QemuOptsList *qemu_find_opts(const char *group)
543
{
544
    return find_list(vm_config_groups, group);
545
}
546

    
547
void qemu_add_opts(QemuOptsList *list)
548
{
549
    int entries, i;
550

    
551
    entries = ARRAY_SIZE(vm_config_groups);
552
    entries--; /* keep list NULL terminated */
553
    for (i = 0; i < entries; i++) {
554
        if (vm_config_groups[i] == NULL) {
555
            vm_config_groups[i] = list;
556
            return;
557
        }
558
    }
559
    fprintf(stderr, "ran out of space in vm_config_groups");
560
    abort();
561
}
562

    
563
int qemu_set_option(const char *str)
564
{
565
    char group[64], id[64], arg[64];
566
    QemuOptsList *list;
567
    QemuOpts *opts;
568
    int rc, offset;
569

    
570
    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
571
    if (rc < 3 || str[offset] != '=') {
572
        error_report("can't parse: \"%s\"", str);
573
        return -1;
574
    }
575

    
576
    list = qemu_find_opts(group);
577
    if (list == NULL) {
578
        return -1;
579
    }
580

    
581
    opts = qemu_opts_find(list, id);
582
    if (!opts) {
583
        error_report("there is no %s \"%s\" defined",
584
                     list->name, id);
585
        return -1;
586
    }
587

    
588
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
589
        return -1;
590
    }
591
    return 0;
592
}
593

    
594
int qemu_global_option(const char *str)
595
{
596
    char driver[64], property[64];
597
    QemuOpts *opts;
598
    int rc, offset;
599

    
600
    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
601
    if (rc < 2 || str[offset] != '=') {
602
        error_report("can't parse: \"%s\"", str);
603
        return -1;
604
    }
605

    
606
    opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
607
    qemu_opt_set(opts, "driver", driver);
608
    qemu_opt_set(opts, "property", property);
609
    qemu_opt_set(opts, "value", str+offset+1);
610
    return 0;
611
}
612

    
613
struct ConfigWriteData {
614
    QemuOptsList *list;
615
    FILE *fp;
616
};
617

    
618
static int config_write_opt(const char *name, const char *value, void *opaque)
619
{
620
    struct ConfigWriteData *data = opaque;
621

    
622
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
623
    return 0;
624
}
625

    
626
static int config_write_opts(QemuOpts *opts, void *opaque)
627
{
628
    struct ConfigWriteData *data = opaque;
629
    const char *id = qemu_opts_id(opts);
630

    
631
    if (id) {
632
        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
633
    } else {
634
        fprintf(data->fp, "[%s]\n", data->list->name);
635
    }
636
    qemu_opt_foreach(opts, config_write_opt, data, 0);
637
    fprintf(data->fp, "\n");
638
    return 0;
639
}
640

    
641
void qemu_config_write(FILE *fp)
642
{
643
    struct ConfigWriteData data = { .fp = fp };
644
    QemuOptsList **lists = vm_config_groups;
645
    int i;
646

    
647
    fprintf(fp, "# qemu config file\n\n");
648
    for (i = 0; lists[i] != NULL; i++) {
649
        data.list = lists[i];
650
        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
651
    }
652
}
653

    
654
int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
655
{
656
    char line[1024], group[64], id[64], arg[64], value[1024];
657
    Location loc;
658
    QemuOptsList *list = NULL;
659
    QemuOpts *opts = NULL;
660
    int res = -1, lno = 0;
661

    
662
    loc_push_none(&loc);
663
    while (fgets(line, sizeof(line), fp) != NULL) {
664
        loc_set_file(fname, ++lno);
665
        if (line[0] == '\n') {
666
            /* skip empty lines */
667
            continue;
668
        }
669
        if (line[0] == '#') {
670
            /* comment */
671
            continue;
672
        }
673
        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
674
            /* group with id */
675
            list = find_list(lists, group);
676
            if (list == NULL)
677
                goto out;
678
            opts = qemu_opts_create(list, id, 1);
679
            continue;
680
        }
681
        if (sscanf(line, "[%63[^]]]", group) == 1) {
682
            /* group without id */
683
            list = find_list(lists, group);
684
            if (list == NULL)
685
                goto out;
686
            opts = qemu_opts_create(list, NULL, 0);
687
            continue;
688
        }
689
        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
690
            /* arg = value */
691
            if (opts == NULL) {
692
                error_report("no group defined");
693
                goto out;
694
            }
695
            if (qemu_opt_set(opts, arg, value) != 0) {
696
                goto out;
697
            }
698
            continue;
699
        }
700
        error_report("parse error");
701
        goto out;
702
    }
703
    if (ferror(fp)) {
704
        error_report("error reading file");
705
        goto out;
706
    }
707
    res = 0;
708
out:
709
    loc_pop(&loc);
710
    return res;
711
}
712

    
713
int qemu_read_config_file(const char *filename)
714
{
715
    FILE *f = fopen(filename, "r");
716
    int ret;
717

    
718
    if (f == NULL) {
719
        return -errno;
720
    }
721

    
722
    ret = qemu_config_parse(f, vm_config_groups, filename);
723
    fclose(f);
724

    
725
    if (ret == 0) {
726
        return 0;
727
    } else {
728
        return -EINVAL;
729
    }
730
}