Statistics
| Branch: | Revision:

root / qemu-config.c @ a74cdab4

History | View | Annotate | Download (17.1 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 qemu_machine_opts = {
454
    .name = "machine",
455
    .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
456
    .desc = {
457
        {
458
            .name = "accel",
459
            .type = QEMU_OPT_STRING,
460
            .help = "accelerator list",
461
        },
462
        { /* End of list */ }
463
    },
464
};
465

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

    
484
static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
485
{
486
    int i;
487

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

    
498
QemuOptsList *qemu_find_opts(const char *group)
499
{
500
    return find_list(vm_config_groups, group);
501
}
502

    
503
void qemu_add_opts(QemuOptsList *list)
504
{
505
    int entries, i;
506

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

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

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

    
532
    list = qemu_find_opts(group);
533
    if (list == NULL) {
534
        return -1;
535
    }
536

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

    
544
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
545
        return -1;
546
    }
547
    return 0;
548
}
549

    
550
int qemu_global_option(const char *str)
551
{
552
    char driver[64], property[64];
553
    QemuOpts *opts;
554
    int rc, offset;
555

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

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

    
569
struct ConfigWriteData {
570
    QemuOptsList *list;
571
    FILE *fp;
572
};
573

    
574
static int config_write_opt(const char *name, const char *value, void *opaque)
575
{
576
    struct ConfigWriteData *data = opaque;
577

    
578
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
579
    return 0;
580
}
581

    
582
static int config_write_opts(QemuOpts *opts, void *opaque)
583
{
584
    struct ConfigWriteData *data = opaque;
585
    const char *id = qemu_opts_id(opts);
586

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

    
597
void qemu_config_write(FILE *fp)
598
{
599
    struct ConfigWriteData data = { .fp = fp };
600
    QemuOptsList **lists = vm_config_groups;
601
    int i;
602

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

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

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

    
669
int qemu_read_config_file(const char *filename)
670
{
671
    FILE *f = fopen(filename, "r");
672
    int ret;
673

    
674
    if (f == NULL) {
675
        return -errno;
676
    }
677

    
678
    ret = qemu_config_parse(f, vm_config_groups, filename);
679
    fclose(f);
680

    
681
    if (ret == 0) {
682
        return 0;
683
    } else {
684
        return -EINVAL;
685
    }
686
}