Statistics
| Branch: | Revision:

root / qemu-config.c @ a08784dd

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

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

    
453
static QemuOptsList *vm_config_groups[32] = {
454
    &qemu_drive_opts,
455
    &qemu_chardev_opts,
456
    &qemu_device_opts,
457
    &qemu_netdev_opts,
458
    &qemu_net_opts,
459
    &qemu_rtc_opts,
460
    &qemu_global_opts,
461
    &qemu_mon_opts,
462
    &qemu_cpudef_opts,
463
#ifdef CONFIG_SIMPLE_TRACE
464
    &qemu_trace_opts,
465
#endif
466
    &qemu_option_rom_opts,
467
    NULL,
468
};
469

    
470
static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
471
{
472
    int i;
473

    
474
    for (i = 0; lists[i] != NULL; i++) {
475
        if (strcmp(lists[i]->name, group) == 0)
476
            break;
477
    }
478
    if (lists[i] == NULL) {
479
        error_report("there is no option group \"%s\"", group);
480
    }
481
    return lists[i];
482
}
483

    
484
QemuOptsList *qemu_find_opts(const char *group)
485
{
486
    return find_list(vm_config_groups, group);
487
}
488

    
489
void qemu_add_opts(QemuOptsList *list)
490
{
491
    int entries, i;
492

    
493
    entries = ARRAY_SIZE(vm_config_groups);
494
    entries--; /* keep list NULL terminated */
495
    for (i = 0; i < entries; i++) {
496
        if (vm_config_groups[i] == NULL) {
497
            vm_config_groups[i] = list;
498
            return;
499
        }
500
    }
501
    fprintf(stderr, "ran out of space in vm_config_groups");
502
    abort();
503
}
504

    
505
int qemu_set_option(const char *str)
506
{
507
    char group[64], id[64], arg[64];
508
    QemuOptsList *list;
509
    QemuOpts *opts;
510
    int rc, offset;
511

    
512
    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
513
    if (rc < 3 || str[offset] != '=') {
514
        error_report("can't parse: \"%s\"", str);
515
        return -1;
516
    }
517

    
518
    list = qemu_find_opts(group);
519
    if (list == NULL) {
520
        return -1;
521
    }
522

    
523
    opts = qemu_opts_find(list, id);
524
    if (!opts) {
525
        error_report("there is no %s \"%s\" defined",
526
                     list->name, id);
527
        return -1;
528
    }
529

    
530
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
531
        return -1;
532
    }
533
    return 0;
534
}
535

    
536
int qemu_global_option(const char *str)
537
{
538
    char driver[64], property[64];
539
    QemuOpts *opts;
540
    int rc, offset;
541

    
542
    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
543
    if (rc < 2 || str[offset] != '=') {
544
        error_report("can't parse: \"%s\"", str);
545
        return -1;
546
    }
547

    
548
    opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
549
    qemu_opt_set(opts, "driver", driver);
550
    qemu_opt_set(opts, "property", property);
551
    qemu_opt_set(opts, "value", str+offset+1);
552
    return 0;
553
}
554

    
555
struct ConfigWriteData {
556
    QemuOptsList *list;
557
    FILE *fp;
558
};
559

    
560
static int config_write_opt(const char *name, const char *value, void *opaque)
561
{
562
    struct ConfigWriteData *data = opaque;
563

    
564
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
565
    return 0;
566
}
567

    
568
static int config_write_opts(QemuOpts *opts, void *opaque)
569
{
570
    struct ConfigWriteData *data = opaque;
571
    const char *id = qemu_opts_id(opts);
572

    
573
    if (id) {
574
        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
575
    } else {
576
        fprintf(data->fp, "[%s]\n", data->list->name);
577
    }
578
    qemu_opt_foreach(opts, config_write_opt, data, 0);
579
    fprintf(data->fp, "\n");
580
    return 0;
581
}
582

    
583
void qemu_config_write(FILE *fp)
584
{
585
    struct ConfigWriteData data = { .fp = fp };
586
    QemuOptsList **lists = vm_config_groups;
587
    int i;
588

    
589
    fprintf(fp, "# qemu config file\n\n");
590
    for (i = 0; lists[i] != NULL; i++) {
591
        data.list = lists[i];
592
        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
593
    }
594
}
595

    
596
int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
597
{
598
    char line[1024], group[64], id[64], arg[64], value[1024];
599
    Location loc;
600
    QemuOptsList *list = NULL;
601
    QemuOpts *opts = NULL;
602
    int res = -1, lno = 0;
603

    
604
    loc_push_none(&loc);
605
    while (fgets(line, sizeof(line), fp) != NULL) {
606
        loc_set_file(fname, ++lno);
607
        if (line[0] == '\n') {
608
            /* skip empty lines */
609
            continue;
610
        }
611
        if (line[0] == '#') {
612
            /* comment */
613
            continue;
614
        }
615
        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
616
            /* group with id */
617
            list = find_list(lists, group);
618
            if (list == NULL)
619
                goto out;
620
            opts = qemu_opts_create(list, id, 1);
621
            continue;
622
        }
623
        if (sscanf(line, "[%63[^]]]", group) == 1) {
624
            /* group without id */
625
            list = find_list(lists, group);
626
            if (list == NULL)
627
                goto out;
628
            opts = qemu_opts_create(list, NULL, 0);
629
            continue;
630
        }
631
        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
632
            /* arg = value */
633
            if (opts == NULL) {
634
                error_report("no group defined");
635
                goto out;
636
            }
637
            if (qemu_opt_set(opts, arg, value) != 0) {
638
                goto out;
639
            }
640
            continue;
641
        }
642
        error_report("parse error");
643
        goto out;
644
    }
645
    if (ferror(fp)) {
646
        error_report("error reading file");
647
        goto out;
648
    }
649
    res = 0;
650
out:
651
    loc_pop(&loc);
652
    return res;
653
}
654

    
655
int qemu_read_config_file(const char *filename)
656
{
657
    FILE *f = fopen(filename, "r");
658
    int ret;
659

    
660
    if (f == NULL) {
661
        return -errno;
662
    }
663

    
664
    ret = qemu_config_parse(f, vm_config_groups, filename);
665
    fclose(f);
666

    
667
    if (ret == 0) {
668
        return 0;
669
    } else {
670
        return -EINVAL;
671
    }
672
}