Statistics
| Branch: | Revision:

root / qemu-config.c @ 44bd6907

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 of 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 = "sasl",
392
            .type = QEMU_OPT_BOOL,
393
        },{
394
            .name = "x509-dir",
395
            .type = QEMU_OPT_STRING,
396
        },{
397
            .name = "x509-key-file",
398
            .type = QEMU_OPT_STRING,
399
        },{
400
            .name = "x509-key-password",
401
            .type = QEMU_OPT_STRING,
402
        },{
403
            .name = "x509-cert-file",
404
            .type = QEMU_OPT_STRING,
405
        },{
406
            .name = "x509-cacert-file",
407
            .type = QEMU_OPT_STRING,
408
        },{
409
            .name = "x509-dh-key-file",
410
            .type = QEMU_OPT_STRING,
411
        },{
412
            .name = "tls-ciphers",
413
            .type = QEMU_OPT_STRING,
414
        },{
415
            .name = "tls-channel",
416
            .type = QEMU_OPT_STRING,
417
        },{
418
            .name = "plaintext-channel",
419
            .type = QEMU_OPT_STRING,
420
        },{
421
            .name = "image-compression",
422
            .type = QEMU_OPT_STRING,
423
        },{
424
            .name = "jpeg-wan-compression",
425
            .type = QEMU_OPT_STRING,
426
        },{
427
            .name = "zlib-glz-wan-compression",
428
            .type = QEMU_OPT_STRING,
429
        },{
430
            .name = "streaming-video",
431
            .type = QEMU_OPT_STRING,
432
        },{
433
            .name = "agent-mouse",
434
            .type = QEMU_OPT_BOOL,
435
        },{
436
            .name = "playback-compression",
437
            .type = QEMU_OPT_BOOL,
438
        },
439
        { /* end of list */ }
440
    },
441
};
442

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

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

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

    
490
static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
491
{
492
    int i;
493

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

    
504
QemuOptsList *qemu_find_opts(const char *group)
505
{
506
    return find_list(vm_config_groups, group);
507
}
508

    
509
void qemu_add_opts(QemuOptsList *list)
510
{
511
    int entries, i;
512

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

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

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

    
538
    list = qemu_find_opts(group);
539
    if (list == NULL) {
540
        return -1;
541
    }
542

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

    
550
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
551
        return -1;
552
    }
553
    return 0;
554
}
555

    
556
int qemu_global_option(const char *str)
557
{
558
    char driver[64], property[64];
559
    QemuOpts *opts;
560
    int rc, offset;
561

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

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

    
575
struct ConfigWriteData {
576
    QemuOptsList *list;
577
    FILE *fp;
578
};
579

    
580
static int config_write_opt(const char *name, const char *value, void *opaque)
581
{
582
    struct ConfigWriteData *data = opaque;
583

    
584
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
585
    return 0;
586
}
587

    
588
static int config_write_opts(QemuOpts *opts, void *opaque)
589
{
590
    struct ConfigWriteData *data = opaque;
591
    const char *id = qemu_opts_id(opts);
592

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

    
603
void qemu_config_write(FILE *fp)
604
{
605
    struct ConfigWriteData data = { .fp = fp };
606
    QemuOptsList **lists = vm_config_groups;
607
    int i;
608

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

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

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

    
675
int qemu_read_config_file(const char *filename)
676
{
677
    FILE *f = fopen(filename, "r");
678
    int ret;
679

    
680
    if (f == NULL) {
681
        return -errno;
682
    }
683

    
684
    ret = qemu_config_parse(f, vm_config_groups, filename);
685
    fclose(f);
686

    
687
    if (ret == 0) {
688
        return 0;
689
    } else {
690
        return -EINVAL;
691
    }
692
}