Statistics
| Branch: | Revision:

root / qemu-config.c @ 74db920c

History | View | Annotate | Download (12.7 kB)

1
#include "qemu-common.h"
2
#include "qemu-error.h"
3
#include "qemu-option.h"
4
#include "qemu-config.h"
5
#include "sysemu.h"
6
#include "hw/qdev.h"
7

    
8
QemuOptsList qemu_drive_opts = {
9
    .name = "drive",
10
    .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
11
    .desc = {
12
        {
13
            .name = "bus",
14
            .type = QEMU_OPT_NUMBER,
15
            .help = "bus number",
16
        },{
17
            .name = "unit",
18
            .type = QEMU_OPT_NUMBER,
19
            .help = "unit number (i.e. lun for scsi)",
20
        },{
21
            .name = "if",
22
            .type = QEMU_OPT_STRING,
23
            .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
24
        },{
25
            .name = "index",
26
            .type = QEMU_OPT_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
        },{
51
            .name = "file",
52
            .type = QEMU_OPT_STRING,
53
            .help = "disk image",
54
        },{
55
            .name = "cache",
56
            .type = QEMU_OPT_STRING,
57
            .help = "host cache usage (none, writeback, writethrough)",
58
        },{
59
            .name = "aio",
60
            .type = QEMU_OPT_STRING,
61
            .help = "host AIO implementation (threads, native)",
62
        },{
63
            .name = "format",
64
            .type = QEMU_OPT_STRING,
65
            .help = "disk format (raw, qcow2, ...)",
66
        },{
67
            .name = "serial",
68
            .type = QEMU_OPT_STRING,
69
        },{
70
            .name = "rerror",
71
            .type = QEMU_OPT_STRING,
72
        },{
73
            .name = "werror",
74
            .type = QEMU_OPT_STRING,
75
        },{
76
            .name = "addr",
77
            .type = QEMU_OPT_STRING,
78
            .help = "pci address (virtio only)",
79
        },{
80
            .name = "readonly",
81
            .type = QEMU_OPT_BOOL,
82
        },
83
        { /* end if list */ }
84
    },
85
};
86

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

    
154
#ifdef CONFIG_LINUX
155
QemuOptsList qemu_fsdev_opts = {
156
    .name = "fsdev",
157
    .implied_opt_name = "fstype",
158
    .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
159
    .desc = {
160
        {
161
            .name = "fstype",
162
            .type = QEMU_OPT_STRING,
163
        }, {
164
            .name = "path",
165
            .type = QEMU_OPT_STRING,
166
        },
167
        { /*End of list */ }
168
    },
169
};
170
#endif
171

    
172
QemuOptsList qemu_device_opts = {
173
    .name = "device",
174
    .implied_opt_name = "driver",
175
    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
176
    .desc = {
177
        /*
178
         * no elements => accept any
179
         * sanity checking will happen later
180
         * when setting device properties
181
         */
182
        { /* end if list */ }
183
    },
184
};
185

    
186
QemuOptsList qemu_netdev_opts = {
187
    .name = "netdev",
188
    .implied_opt_name = "type",
189
    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
190
    .desc = {
191
        /*
192
         * no elements => accept any params
193
         * validation will happen later
194
         */
195
        { /* end of list */ }
196
    },
197
};
198

    
199
QemuOptsList qemu_net_opts = {
200
    .name = "net",
201
    .implied_opt_name = "type",
202
    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
203
    .desc = {
204
        /*
205
         * no elements => accept any params
206
         * validation will happen later
207
         */
208
        { /* end of list */ }
209
    },
210
};
211

    
212
QemuOptsList qemu_rtc_opts = {
213
    .name = "rtc",
214
    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
215
    .desc = {
216
        {
217
            .name = "base",
218
            .type = QEMU_OPT_STRING,
219
        },{
220
            .name = "clock",
221
            .type = QEMU_OPT_STRING,
222
#ifdef TARGET_I386
223
        },{
224
            .name = "driftfix",
225
            .type = QEMU_OPT_STRING,
226
#endif
227
        },
228
        { /* end if list */ }
229
    },
230
};
231

    
232
QemuOptsList qemu_global_opts = {
233
    .name = "global",
234
    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
235
    .desc = {
236
        {
237
            .name = "driver",
238
            .type = QEMU_OPT_STRING,
239
        },{
240
            .name = "property",
241
            .type = QEMU_OPT_STRING,
242
        },{
243
            .name = "value",
244
            .type = QEMU_OPT_STRING,
245
        },
246
        { /* end if list */ }
247
    },
248
};
249

    
250
QemuOptsList qemu_mon_opts = {
251
    .name = "mon",
252
    .implied_opt_name = "chardev",
253
    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
254
    .desc = {
255
        {
256
            .name = "mode",
257
            .type = QEMU_OPT_STRING,
258
        },{
259
            .name = "chardev",
260
            .type = QEMU_OPT_STRING,
261
        },{
262
            .name = "default",
263
            .type = QEMU_OPT_BOOL,
264
        },
265
        { /* end if list */ }
266
    },
267
};
268

    
269
QemuOptsList qemu_cpudef_opts = {
270
    .name = "cpudef",
271
    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
272
    .desc = {
273
        {
274
            .name = "name",
275
            .type = QEMU_OPT_STRING,
276
        },{
277
            .name = "level",
278
            .type = QEMU_OPT_NUMBER,
279
        },{
280
            .name = "vendor",
281
            .type = QEMU_OPT_STRING,
282
        },{
283
            .name = "family",
284
            .type = QEMU_OPT_NUMBER,
285
        },{
286
            .name = "model",
287
            .type = QEMU_OPT_NUMBER,
288
        },{
289
            .name = "stepping",
290
            .type = QEMU_OPT_NUMBER,
291
        },{
292
            .name = "feature_edx",      /* cpuid 0000_0001.edx */
293
            .type = QEMU_OPT_STRING,
294
        },{
295
            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
296
            .type = QEMU_OPT_STRING,
297
        },{
298
            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
299
            .type = QEMU_OPT_STRING,
300
        },{
301
            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
302
            .type = QEMU_OPT_STRING,
303
        },{
304
            .name = "xlevel",
305
            .type = QEMU_OPT_NUMBER,
306
        },{
307
            .name = "model_id",
308
            .type = QEMU_OPT_STRING,
309
        },{
310
            .name = "vendor_override",
311
            .type = QEMU_OPT_NUMBER,
312
        },
313
        { /* end of list */ }
314
    },
315
};
316

    
317
static QemuOptsList *vm_config_groups[] = {
318
    &qemu_drive_opts,
319
    &qemu_chardev_opts,
320
    &qemu_device_opts,
321
    &qemu_netdev_opts,
322
    &qemu_net_opts,
323
    &qemu_rtc_opts,
324
    &qemu_global_opts,
325
    &qemu_mon_opts,
326
    &qemu_cpudef_opts,
327
    NULL,
328
};
329

    
330
static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
331
{
332
    int i;
333

    
334
    for (i = 0; lists[i] != NULL; i++) {
335
        if (strcmp(lists[i]->name, group) == 0)
336
            break;
337
    }
338
    if (lists[i] == NULL) {
339
        error_report("there is no option group \"%s\"", group);
340
    }
341
    return lists[i];
342
}
343

    
344
QemuOptsList *qemu_find_opts(const char *group)
345
{
346
    return find_list(vm_config_groups, group);
347
}
348

    
349
int qemu_set_option(const char *str)
350
{
351
    char group[64], id[64], arg[64];
352
    QemuOptsList *list;
353
    QemuOpts *opts;
354
    int rc, offset;
355

    
356
    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
357
    if (rc < 3 || str[offset] != '=') {
358
        error_report("can't parse: \"%s\"", str);
359
        return -1;
360
    }
361

    
362
    list = qemu_find_opts(group);
363
    if (list == NULL) {
364
        return -1;
365
    }
366

    
367
    opts = qemu_opts_find(list, id);
368
    if (!opts) {
369
        error_report("there is no %s \"%s\" defined",
370
                     list->name, id);
371
        return -1;
372
    }
373

    
374
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
375
        return -1;
376
    }
377
    return 0;
378
}
379

    
380
int qemu_global_option(const char *str)
381
{
382
    char driver[64], property[64];
383
    QemuOpts *opts;
384
    int rc, offset;
385

    
386
    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
387
    if (rc < 2 || str[offset] != '=') {
388
        error_report("can't parse: \"%s\"", str);
389
        return -1;
390
    }
391

    
392
    opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
393
    qemu_opt_set(opts, "driver", driver);
394
    qemu_opt_set(opts, "property", property);
395
    qemu_opt_set(opts, "value", str+offset+1);
396
    return 0;
397
}
398

    
399
struct ConfigWriteData {
400
    QemuOptsList *list;
401
    FILE *fp;
402
};
403

    
404
static int config_write_opt(const char *name, const char *value, void *opaque)
405
{
406
    struct ConfigWriteData *data = opaque;
407

    
408
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
409
    return 0;
410
}
411

    
412
static int config_write_opts(QemuOpts *opts, void *opaque)
413
{
414
    struct ConfigWriteData *data = opaque;
415
    const char *id = qemu_opts_id(opts);
416

    
417
    if (id) {
418
        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
419
    } else {
420
        fprintf(data->fp, "[%s]\n", data->list->name);
421
    }
422
    qemu_opt_foreach(opts, config_write_opt, data, 0);
423
    fprintf(data->fp, "\n");
424
    return 0;
425
}
426

    
427
void qemu_config_write(FILE *fp)
428
{
429
    struct ConfigWriteData data = { .fp = fp };
430
    QemuOptsList **lists = vm_config_groups;
431
    int i;
432

    
433
    fprintf(fp, "# qemu config file\n\n");
434
    for (i = 0; lists[i] != NULL; i++) {
435
        data.list = lists[i];
436
        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
437
    }
438
}
439

    
440
int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
441
{
442
    char line[1024], group[64], id[64], arg[64], value[1024];
443
    Location loc;
444
    QemuOptsList *list = NULL;
445
    QemuOpts *opts = NULL;
446
    int res = -1, lno = 0;
447

    
448
    loc_push_none(&loc);
449
    while (fgets(line, sizeof(line), fp) != NULL) {
450
        loc_set_file(fname, ++lno);
451
        if (line[0] == '\n') {
452
            /* skip empty lines */
453
            continue;
454
        }
455
        if (line[0] == '#') {
456
            /* comment */
457
            continue;
458
        }
459
        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
460
            /* group with id */
461
            list = find_list(lists, group);
462
            if (list == NULL)
463
                goto out;
464
            opts = qemu_opts_create(list, id, 1);
465
            continue;
466
        }
467
        if (sscanf(line, "[%63[^]]]", group) == 1) {
468
            /* group without id */
469
            list = find_list(lists, group);
470
            if (list == NULL)
471
                goto out;
472
            opts = qemu_opts_create(list, NULL, 0);
473
            continue;
474
        }
475
        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
476
            /* arg = value */
477
            if (opts == NULL) {
478
                error_report("no group defined");
479
                goto out;
480
            }
481
            if (qemu_opt_set(opts, arg, value) != 0) {
482
                goto out;
483
            }
484
            continue;
485
        }
486
        error_report("parse error");
487
        goto out;
488
    }
489
    if (ferror(fp)) {
490
        error_report("error reading file");
491
        goto out;
492
    }
493
    res = 0;
494
out:
495
    loc_pop(&loc);
496
    return res;
497
}
498

    
499
int qemu_read_config_file(const char *filename)
500
{
501
    FILE *f = fopen(filename, "r");
502
    if (f == NULL) {
503
        return -errno;
504
    }
505

    
506
    if (qemu_config_parse(f, vm_config_groups, filename) != 0) {
507
        return -EINVAL;
508
    }
509
    fclose(f);
510

    
511
    return 0;
512
}