Statistics
| Branch: | Revision:

root / qemu-config.c @ d4970b07

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

    
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
        },{
27
            .name = "cyls",
28
            .type = QEMU_OPT_NUMBER,
29
            .help = "number of cylinders (ide disk geometry)",
30
        },{
31
            .name = "heads",
32
            .type = QEMU_OPT_NUMBER,
33
            .help = "number of heads (ide disk geometry)",
34
        },{
35
            .name = "secs",
36
            .type = QEMU_OPT_NUMBER,
37
            .help = "number of sectors (ide disk geometry)",
38
        },{
39
            .name = "trans",
40
            .type = QEMU_OPT_STRING,
41
            .help = "chs translation (auto, lba. none)",
42
        },{
43
            .name = "media",
44
            .type = QEMU_OPT_STRING,
45
            .help = "media type (disk, cdrom)",
46
        },{
47
            .name = "snapshot",
48
            .type = QEMU_OPT_BOOL,
49
        },{
50
            .name = "file",
51
            .type = QEMU_OPT_STRING,
52
            .help = "disk image",
53
        },{
54
            .name = "cache",
55
            .type = QEMU_OPT_STRING,
56
            .help = "host cache usage (none, writeback, writethrough, unsafe)",
57
        },{
58
            .name = "aio",
59
            .type = QEMU_OPT_STRING,
60
            .help = "host AIO implementation (threads, native)",
61
        },{
62
            .name = "format",
63
            .type = QEMU_OPT_STRING,
64
            .help = "disk format (raw, qcow2, ...)",
65
        },{
66
            .name = "serial",
67
            .type = QEMU_OPT_STRING,
68
        },{
69
            .name = "rerror",
70
            .type = QEMU_OPT_STRING,
71
        },{
72
            .name = "werror",
73
            .type = QEMU_OPT_STRING,
74
        },{
75
            .name = "addr",
76
            .type = QEMU_OPT_STRING,
77
            .help = "pci address (virtio only)",
78
        },{
79
            .name = "readonly",
80
            .type = QEMU_OPT_BOOL,
81
        },
82
        { /* end of list */ }
83
    },
84
};
85

    
86
static QemuOptsList qemu_chardev_opts = {
87
    .name = "chardev",
88
    .implied_opt_name = "backend",
89
    .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
90
    .desc = {
91
        {
92
            .name = "backend",
93
            .type = QEMU_OPT_STRING,
94
        },{
95
            .name = "path",
96
            .type = QEMU_OPT_STRING,
97
        },{
98
            .name = "host",
99
            .type = QEMU_OPT_STRING,
100
        },{
101
            .name = "port",
102
            .type = QEMU_OPT_STRING,
103
        },{
104
            .name = "localaddr",
105
            .type = QEMU_OPT_STRING,
106
        },{
107
            .name = "localport",
108
            .type = QEMU_OPT_STRING,
109
        },{
110
            .name = "to",
111
            .type = QEMU_OPT_NUMBER,
112
        },{
113
            .name = "ipv4",
114
            .type = QEMU_OPT_BOOL,
115
        },{
116
            .name = "ipv6",
117
            .type = QEMU_OPT_BOOL,
118
        },{
119
            .name = "wait",
120
            .type = QEMU_OPT_BOOL,
121
        },{
122
            .name = "server",
123
            .type = QEMU_OPT_BOOL,
124
        },{
125
            .name = "delay",
126
            .type = QEMU_OPT_BOOL,
127
        },{
128
            .name = "telnet",
129
            .type = QEMU_OPT_BOOL,
130
        },{
131
            .name = "width",
132
            .type = QEMU_OPT_NUMBER,
133
        },{
134
            .name = "height",
135
            .type = QEMU_OPT_NUMBER,
136
        },{
137
            .name = "cols",
138
            .type = QEMU_OPT_NUMBER,
139
        },{
140
            .name = "rows",
141
            .type = QEMU_OPT_NUMBER,
142
        },{
143
            .name = "mux",
144
            .type = QEMU_OPT_BOOL,
145
        },{
146
            .name = "signal",
147
            .type = QEMU_OPT_BOOL,
148
        },{
149
            .name = "name",
150
            .type = QEMU_OPT_STRING,
151
        },{
152
            .name = "debug",
153
            .type = QEMU_OPT_NUMBER,
154
        },
155
        { /* end of list */ }
156
    },
157
};
158

    
159
QemuOptsList qemu_fsdev_opts = {
160
    .name = "fsdev",
161
    .implied_opt_name = "fstype",
162
    .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
163
    .desc = {
164
        {
165
            .name = "fstype",
166
            .type = QEMU_OPT_STRING,
167
        }, {
168
            .name = "path",
169
            .type = QEMU_OPT_STRING,
170
        }, {
171
            .name = "security_model",
172
            .type = QEMU_OPT_STRING,
173
        },
174
        { /*End of list */ }
175
    },
176
};
177

    
178
QemuOptsList qemu_virtfs_opts = {
179
    .name = "virtfs",
180
    .implied_opt_name = "fstype",
181
    .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
182
    .desc = {
183
        {
184
            .name = "fstype",
185
            .type = QEMU_OPT_STRING,
186
        }, {
187
            .name = "path",
188
            .type = QEMU_OPT_STRING,
189
        }, {
190
            .name = "mount_tag",
191
            .type = QEMU_OPT_STRING,
192
        }, {
193
            .name = "security_model",
194
            .type = QEMU_OPT_STRING,
195
        },
196

    
197
        { /*End of list */ }
198
    },
199
};
200

    
201
static QemuOptsList qemu_device_opts = {
202
    .name = "device",
203
    .implied_opt_name = "driver",
204
    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
205
    .desc = {
206
        /*
207
         * no elements => accept any
208
         * sanity checking will happen later
209
         * when setting device properties
210
         */
211
        { /* end of list */ }
212
    },
213
};
214

    
215
static QemuOptsList qemu_netdev_opts = {
216
    .name = "netdev",
217
    .implied_opt_name = "type",
218
    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
219
    .desc = {
220
        /*
221
         * no elements => accept any params
222
         * validation will happen later
223
         */
224
        { /* end of list */ }
225
    },
226
};
227

    
228
static QemuOptsList qemu_net_opts = {
229
    .name = "net",
230
    .implied_opt_name = "type",
231
    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
232
    .desc = {
233
        /*
234
         * no elements => accept any params
235
         * validation will happen later
236
         */
237
        { /* end of list */ }
238
    },
239
};
240

    
241
static QemuOptsList qemu_rtc_opts = {
242
    .name = "rtc",
243
    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
244
    .desc = {
245
        {
246
            .name = "base",
247
            .type = QEMU_OPT_STRING,
248
        },{
249
            .name = "clock",
250
            .type = QEMU_OPT_STRING,
251
        },{
252
            .name = "driftfix",
253
            .type = QEMU_OPT_STRING,
254
        },
255
        { /* end of list */ }
256
    },
257
};
258

    
259
static QemuOptsList qemu_global_opts = {
260
    .name = "global",
261
    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
262
    .desc = {
263
        {
264
            .name = "driver",
265
            .type = QEMU_OPT_STRING,
266
        },{
267
            .name = "property",
268
            .type = QEMU_OPT_STRING,
269
        },{
270
            .name = "value",
271
            .type = QEMU_OPT_STRING,
272
        },
273
        { /* end of list */ }
274
    },
275
};
276

    
277
static QemuOptsList qemu_mon_opts = {
278
    .name = "mon",
279
    .implied_opt_name = "chardev",
280
    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
281
    .desc = {
282
        {
283
            .name = "mode",
284
            .type = QEMU_OPT_STRING,
285
        },{
286
            .name = "chardev",
287
            .type = QEMU_OPT_STRING,
288
        },{
289
            .name = "default",
290
            .type = QEMU_OPT_BOOL,
291
        },{
292
            .name = "pretty",
293
            .type = QEMU_OPT_BOOL,
294
        },
295
        { /* end of list */ }
296
    },
297
};
298

    
299
#ifdef CONFIG_SIMPLE_TRACE
300
static QemuOptsList qemu_trace_opts = {
301
    .name = "trace",
302
    .implied_opt_name = "trace",
303
    .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
304
    .desc = {
305
        {
306
            .name = "file",
307
            .type = QEMU_OPT_STRING,
308
        },
309
        { /* end if list */ }
310
    },
311
};
312
#endif
313

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

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

    
440
QemuOptsList qemu_option_rom_opts = {
441
    .name = "option-rom",
442
    .implied_opt_name = "romfile",
443
    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
444
    .desc = {
445
        {
446
            .name = "bootindex",
447
            .type = QEMU_OPT_NUMBER,
448
        }, {
449
            .name = "romfile",
450
            .type = QEMU_OPT_STRING,
451
        },
452
        { /* end if list */ }
453
    },
454
};
455

    
456
static QemuOptsList qemu_machine_opts = {
457
    .name = "machine",
458
    .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
459
    .desc = {
460
        {
461
            .name = "accel",
462
            .type = QEMU_OPT_STRING,
463
            .help = "accelerator list",
464
        },
465
        { /* End of list */ }
466
    },
467
};
468

    
469
static QemuOptsList *vm_config_groups[32] = {
470
    &qemu_drive_opts,
471
    &qemu_chardev_opts,
472
    &qemu_device_opts,
473
    &qemu_netdev_opts,
474
    &qemu_net_opts,
475
    &qemu_rtc_opts,
476
    &qemu_global_opts,
477
    &qemu_mon_opts,
478
    &qemu_cpudef_opts,
479
#ifdef CONFIG_SIMPLE_TRACE
480
    &qemu_trace_opts,
481
#endif
482
    &qemu_option_rom_opts,
483
    &qemu_machine_opts,
484
    NULL,
485
};
486

    
487
static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
488
{
489
    int i;
490

    
491
    for (i = 0; lists[i] != NULL; i++) {
492
        if (strcmp(lists[i]->name, group) == 0)
493
            break;
494
    }
495
    if (lists[i] == NULL) {
496
        error_report("there is no option group \"%s\"", group);
497
    }
498
    return lists[i];
499
}
500

    
501
QemuOptsList *qemu_find_opts(const char *group)
502
{
503
    return find_list(vm_config_groups, group);
504
}
505

    
506
void qemu_add_opts(QemuOptsList *list)
507
{
508
    int entries, i;
509

    
510
    entries = ARRAY_SIZE(vm_config_groups);
511
    entries--; /* keep list NULL terminated */
512
    for (i = 0; i < entries; i++) {
513
        if (vm_config_groups[i] == NULL) {
514
            vm_config_groups[i] = list;
515
            return;
516
        }
517
    }
518
    fprintf(stderr, "ran out of space in vm_config_groups");
519
    abort();
520
}
521

    
522
int qemu_set_option(const char *str)
523
{
524
    char group[64], id[64], arg[64];
525
    QemuOptsList *list;
526
    QemuOpts *opts;
527
    int rc, offset;
528

    
529
    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
530
    if (rc < 3 || str[offset] != '=') {
531
        error_report("can't parse: \"%s\"", str);
532
        return -1;
533
    }
534

    
535
    list = qemu_find_opts(group);
536
    if (list == NULL) {
537
        return -1;
538
    }
539

    
540
    opts = qemu_opts_find(list, id);
541
    if (!opts) {
542
        error_report("there is no %s \"%s\" defined",
543
                     list->name, id);
544
        return -1;
545
    }
546

    
547
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
548
        return -1;
549
    }
550
    return 0;
551
}
552

    
553
int qemu_global_option(const char *str)
554
{
555
    char driver[64], property[64];
556
    QemuOpts *opts;
557
    int rc, offset;
558

    
559
    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
560
    if (rc < 2 || str[offset] != '=') {
561
        error_report("can't parse: \"%s\"", str);
562
        return -1;
563
    }
564

    
565
    opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
566
    qemu_opt_set(opts, "driver", driver);
567
    qemu_opt_set(opts, "property", property);
568
    qemu_opt_set(opts, "value", str+offset+1);
569
    return 0;
570
}
571

    
572
struct ConfigWriteData {
573
    QemuOptsList *list;
574
    FILE *fp;
575
};
576

    
577
static int config_write_opt(const char *name, const char *value, void *opaque)
578
{
579
    struct ConfigWriteData *data = opaque;
580

    
581
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
582
    return 0;
583
}
584

    
585
static int config_write_opts(QemuOpts *opts, void *opaque)
586
{
587
    struct ConfigWriteData *data = opaque;
588
    const char *id = qemu_opts_id(opts);
589

    
590
    if (id) {
591
        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
592
    } else {
593
        fprintf(data->fp, "[%s]\n", data->list->name);
594
    }
595
    qemu_opt_foreach(opts, config_write_opt, data, 0);
596
    fprintf(data->fp, "\n");
597
    return 0;
598
}
599

    
600
void qemu_config_write(FILE *fp)
601
{
602
    struct ConfigWriteData data = { .fp = fp };
603
    QemuOptsList **lists = vm_config_groups;
604
    int i;
605

    
606
    fprintf(fp, "# qemu config file\n\n");
607
    for (i = 0; lists[i] != NULL; i++) {
608
        data.list = lists[i];
609
        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
610
    }
611
}
612

    
613
int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
614
{
615
    char line[1024], group[64], id[64], arg[64], value[1024];
616
    Location loc;
617
    QemuOptsList *list = NULL;
618
    QemuOpts *opts = NULL;
619
    int res = -1, lno = 0;
620

    
621
    loc_push_none(&loc);
622
    while (fgets(line, sizeof(line), fp) != NULL) {
623
        loc_set_file(fname, ++lno);
624
        if (line[0] == '\n') {
625
            /* skip empty lines */
626
            continue;
627
        }
628
        if (line[0] == '#') {
629
            /* comment */
630
            continue;
631
        }
632
        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
633
            /* group with id */
634
            list = find_list(lists, group);
635
            if (list == NULL)
636
                goto out;
637
            opts = qemu_opts_create(list, id, 1);
638
            continue;
639
        }
640
        if (sscanf(line, "[%63[^]]]", group) == 1) {
641
            /* group without id */
642
            list = find_list(lists, group);
643
            if (list == NULL)
644
                goto out;
645
            opts = qemu_opts_create(list, NULL, 0);
646
            continue;
647
        }
648
        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
649
            /* arg = value */
650
            if (opts == NULL) {
651
                error_report("no group defined");
652
                goto out;
653
            }
654
            if (qemu_opt_set(opts, arg, value) != 0) {
655
                goto out;
656
            }
657
            continue;
658
        }
659
        error_report("parse error");
660
        goto out;
661
    }
662
    if (ferror(fp)) {
663
        error_report("error reading file");
664
        goto out;
665
    }
666
    res = 0;
667
out:
668
    loc_pop(&loc);
669
    return res;
670
}
671

    
672
int qemu_read_config_file(const char *filename)
673
{
674
    FILE *f = fopen(filename, "r");
675
    int ret;
676

    
677
    if (f == NULL) {
678
        return -errno;
679
    }
680

    
681
    ret = qemu_config_parse(f, vm_config_groups, filename);
682
    fclose(f);
683

    
684
    if (ret == 0) {
685
        return 0;
686
    } else {
687
        return -EINVAL;
688
    }
689
}