Statistics
| Branch: | Revision:

root / qemu-config.c @ 8212c64f

History | View | Annotate | Download (12.3 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
QemuOptsList qemu_device_opts = {
155
    .name = "device",
156
    .implied_opt_name = "driver",
157
    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
158
    .desc = {
159
        /*
160
         * no elements => accept any
161
         * sanity checking will happen later
162
         * when setting device properties
163
         */
164
        { /* end if list */ }
165
    },
166
};
167

    
168
QemuOptsList qemu_netdev_opts = {
169
    .name = "netdev",
170
    .implied_opt_name = "type",
171
    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
172
    .desc = {
173
        /*
174
         * no elements => accept any params
175
         * validation will happen later
176
         */
177
        { /* end of list */ }
178
    },
179
};
180

    
181
QemuOptsList qemu_net_opts = {
182
    .name = "net",
183
    .implied_opt_name = "type",
184
    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
185
    .desc = {
186
        /*
187
         * no elements => accept any params
188
         * validation will happen later
189
         */
190
        { /* end of list */ }
191
    },
192
};
193

    
194
QemuOptsList qemu_rtc_opts = {
195
    .name = "rtc",
196
    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
197
    .desc = {
198
        {
199
            .name = "base",
200
            .type = QEMU_OPT_STRING,
201
        },{
202
            .name = "clock",
203
            .type = QEMU_OPT_STRING,
204
#ifdef TARGET_I386
205
        },{
206
            .name = "driftfix",
207
            .type = QEMU_OPT_STRING,
208
#endif
209
        },
210
        { /* end if list */ }
211
    },
212
};
213

    
214
QemuOptsList qemu_global_opts = {
215
    .name = "global",
216
    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
217
    .desc = {
218
        {
219
            .name = "driver",
220
            .type = QEMU_OPT_STRING,
221
        },{
222
            .name = "property",
223
            .type = QEMU_OPT_STRING,
224
        },{
225
            .name = "value",
226
            .type = QEMU_OPT_STRING,
227
        },
228
        { /* end if list */ }
229
    },
230
};
231

    
232
QemuOptsList qemu_mon_opts = {
233
    .name = "mon",
234
    .implied_opt_name = "chardev",
235
    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
236
    .desc = {
237
        {
238
            .name = "mode",
239
            .type = QEMU_OPT_STRING,
240
        },{
241
            .name = "chardev",
242
            .type = QEMU_OPT_STRING,
243
        },{
244
            .name = "default",
245
            .type = QEMU_OPT_BOOL,
246
        },
247
        { /* end if list */ }
248
    },
249
};
250

    
251
QemuOptsList qemu_cpudef_opts = {
252
    .name = "cpudef",
253
    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
254
    .desc = {
255
        {
256
            .name = "name",
257
            .type = QEMU_OPT_STRING,
258
        },{
259
            .name = "level",
260
            .type = QEMU_OPT_NUMBER,
261
        },{
262
            .name = "vendor",
263
            .type = QEMU_OPT_STRING,
264
        },{
265
            .name = "family",
266
            .type = QEMU_OPT_NUMBER,
267
        },{
268
            .name = "model",
269
            .type = QEMU_OPT_NUMBER,
270
        },{
271
            .name = "stepping",
272
            .type = QEMU_OPT_NUMBER,
273
        },{
274
            .name = "feature_edx",      /* cpuid 0000_0001.edx */
275
            .type = QEMU_OPT_STRING,
276
        },{
277
            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
278
            .type = QEMU_OPT_STRING,
279
        },{
280
            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
281
            .type = QEMU_OPT_STRING,
282
        },{
283
            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
284
            .type = QEMU_OPT_STRING,
285
        },{
286
            .name = "xlevel",
287
            .type = QEMU_OPT_NUMBER,
288
        },{
289
            .name = "model_id",
290
            .type = QEMU_OPT_STRING,
291
        },{
292
            .name = "vendor_override",
293
            .type = QEMU_OPT_NUMBER,
294
        },
295
        { /* end of list */ }
296
    },
297
};
298

    
299
static QemuOptsList *lists[] = {
300
    &qemu_drive_opts,
301
    &qemu_chardev_opts,
302
    &qemu_device_opts,
303
    &qemu_netdev_opts,
304
    &qemu_net_opts,
305
    &qemu_rtc_opts,
306
    &qemu_global_opts,
307
    &qemu_mon_opts,
308
    &qemu_cpudef_opts,
309
    NULL,
310
};
311

    
312
static QemuOptsList *find_list(const char *group)
313
{
314
    int i;
315

    
316
    for (i = 0; lists[i] != NULL; i++) {
317
        if (strcmp(lists[i]->name, group) == 0)
318
            break;
319
    }
320
    if (lists[i] == NULL) {
321
        error_report("there is no option group \"%s\"", group);
322
    }
323
    return lists[i];
324
}
325

    
326
int qemu_set_option(const char *str)
327
{
328
    char group[64], id[64], arg[64];
329
    QemuOptsList *list;
330
    QemuOpts *opts;
331
    int rc, offset;
332

    
333
    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
334
    if (rc < 3 || str[offset] != '=') {
335
        error_report("can't parse: \"%s\"", str);
336
        return -1;
337
    }
338

    
339
    list = find_list(group);
340
    if (list == NULL) {
341
        return -1;
342
    }
343

    
344
    opts = qemu_opts_find(list, id);
345
    if (!opts) {
346
        error_report("there is no %s \"%s\" defined",
347
                     list->name, id);
348
        return -1;
349
    }
350

    
351
    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
352
        return -1;
353
    }
354
    return 0;
355
}
356

    
357
int qemu_global_option(const char *str)
358
{
359
    char driver[64], property[64];
360
    QemuOpts *opts;
361
    int rc, offset;
362

    
363
    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
364
    if (rc < 2 || str[offset] != '=') {
365
        error_report("can't parse: \"%s\"", str);
366
        return -1;
367
    }
368

    
369
    opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
370
    qemu_opt_set(opts, "driver", driver);
371
    qemu_opt_set(opts, "property", property);
372
    qemu_opt_set(opts, "value", str+offset+1);
373
    return 0;
374
}
375

    
376
static int qemu_add_one_global(QemuOpts *opts, void *opaque)
377
{
378
    GlobalProperty *g;
379

    
380
    g = qemu_mallocz(sizeof(*g));
381
    g->driver   = qemu_opt_get(opts, "driver");
382
    g->property = qemu_opt_get(opts, "property");
383
    g->value    = qemu_opt_get(opts, "value");
384
    qdev_prop_register_global(g);
385
    return 0;
386
}
387

    
388
void qemu_add_globals(void)
389
{
390
    qemu_opts_foreach(&qemu_global_opts, qemu_add_one_global, NULL, 0);
391
}
392

    
393
struct ConfigWriteData {
394
    QemuOptsList *list;
395
    FILE *fp;
396
};
397

    
398
static int config_write_opt(const char *name, const char *value, void *opaque)
399
{
400
    struct ConfigWriteData *data = opaque;
401

    
402
    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
403
    return 0;
404
}
405

    
406
static int config_write_opts(QemuOpts *opts, void *opaque)
407
{
408
    struct ConfigWriteData *data = opaque;
409
    const char *id = qemu_opts_id(opts);
410

    
411
    if (id) {
412
        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
413
    } else {
414
        fprintf(data->fp, "[%s]\n", data->list->name);
415
    }
416
    qemu_opt_foreach(opts, config_write_opt, data, 0);
417
    fprintf(data->fp, "\n");
418
    return 0;
419
}
420

    
421
void qemu_config_write(FILE *fp)
422
{
423
    struct ConfigWriteData data = { .fp = fp };
424
    int i;
425

    
426
    fprintf(fp, "# qemu config file\n\n");
427
    for (i = 0; lists[i] != NULL; i++) {
428
        data.list = lists[i];
429
        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
430
    }
431
}
432

    
433
int qemu_config_parse(FILE *fp, const char *fname)
434
{
435
    char line[1024], group[64], id[64], arg[64], value[1024];
436
    Location loc;
437
    QemuOptsList *list = NULL;
438
    QemuOpts *opts = NULL;
439
    int res = -1, lno = 0;
440

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