qemu/qemu-config.c
<<
>>
Prefs
   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
   8QemuOptsList 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, unsafe)",
  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
  87QemuOptsList 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
 155QemuOptsList 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            .name = "security_model",
 168            .type = QEMU_OPT_STRING,
 169        },
 170        { /*End of list */ }
 171    },
 172};
 173#endif
 174
 175#ifdef CONFIG_LINUX
 176QemuOptsList qemu_virtfs_opts = {
 177    .name = "virtfs",
 178    .implied_opt_name = "fstype",
 179    .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
 180    .desc = {
 181        {
 182            .name = "fstype",
 183            .type = QEMU_OPT_STRING,
 184        }, {
 185            .name = "path",
 186            .type = QEMU_OPT_STRING,
 187        }, {
 188            .name = "mount_tag",
 189            .type = QEMU_OPT_STRING,
 190        }, {
 191            .name = "security_model",
 192            .type = QEMU_OPT_STRING,
 193        },
 194
 195        { /*End of list */ }
 196    },
 197};
 198#endif
 199
 200QemuOptsList qemu_device_opts = {
 201    .name = "device",
 202    .implied_opt_name = "driver",
 203    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
 204    .desc = {
 205        /*
 206         * no elements => accept any
 207         * sanity checking will happen later
 208         * when setting device properties
 209         */
 210        { /* end if list */ }
 211    },
 212};
 213
 214QemuOptsList qemu_netdev_opts = {
 215    .name = "netdev",
 216    .implied_opt_name = "type",
 217    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
 218    .desc = {
 219        /*
 220         * no elements => accept any params
 221         * validation will happen later
 222         */
 223        { /* end of list */ }
 224    },
 225};
 226
 227QemuOptsList qemu_net_opts = {
 228    .name = "net",
 229    .implied_opt_name = "type",
 230    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
 231    .desc = {
 232        /*
 233         * no elements => accept any params
 234         * validation will happen later
 235         */
 236        { /* end of list */ }
 237    },
 238};
 239
 240QemuOptsList qemu_rtc_opts = {
 241    .name = "rtc",
 242    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
 243    .desc = {
 244        {
 245            .name = "base",
 246            .type = QEMU_OPT_STRING,
 247        },{
 248            .name = "clock",
 249            .type = QEMU_OPT_STRING,
 250#ifdef TARGET_I386
 251        },{
 252            .name = "driftfix",
 253            .type = QEMU_OPT_STRING,
 254#endif
 255        },
 256        { /* end if list */ }
 257    },
 258};
 259
 260QemuOptsList qemu_global_opts = {
 261    .name = "global",
 262    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
 263    .desc = {
 264        {
 265            .name = "driver",
 266            .type = QEMU_OPT_STRING,
 267        },{
 268            .name = "property",
 269            .type = QEMU_OPT_STRING,
 270        },{
 271            .name = "value",
 272            .type = QEMU_OPT_STRING,
 273        },
 274        { /* end if list */ }
 275    },
 276};
 277
 278QemuOptsList qemu_mon_opts = {
 279    .name = "mon",
 280    .implied_opt_name = "chardev",
 281    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
 282    .desc = {
 283        {
 284            .name = "mode",
 285            .type = QEMU_OPT_STRING,
 286        },{
 287            .name = "chardev",
 288            .type = QEMU_OPT_STRING,
 289        },{
 290            .name = "default",
 291            .type = QEMU_OPT_BOOL,
 292        },
 293        { /* end if list */ }
 294    },
 295};
 296
 297QemuOptsList qemu_cpudef_opts = {
 298    .name = "cpudef",
 299    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
 300    .desc = {
 301        {
 302            .name = "name",
 303            .type = QEMU_OPT_STRING,
 304        },{
 305            .name = "level",
 306            .type = QEMU_OPT_NUMBER,
 307        },{
 308            .name = "vendor",
 309            .type = QEMU_OPT_STRING,
 310        },{
 311            .name = "family",
 312            .type = QEMU_OPT_NUMBER,
 313        },{
 314            .name = "model",
 315            .type = QEMU_OPT_NUMBER,
 316        },{
 317            .name = "stepping",
 318            .type = QEMU_OPT_NUMBER,
 319        },{
 320            .name = "feature_edx",      /* cpuid 0000_0001.edx */
 321            .type = QEMU_OPT_STRING,
 322        },{
 323            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
 324            .type = QEMU_OPT_STRING,
 325        },{
 326            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
 327            .type = QEMU_OPT_STRING,
 328        },{
 329            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
 330            .type = QEMU_OPT_STRING,
 331        },{
 332            .name = "xlevel",
 333            .type = QEMU_OPT_NUMBER,
 334        },{
 335            .name = "model_id",
 336            .type = QEMU_OPT_STRING,
 337        },{
 338            .name = "vendor_override",
 339            .type = QEMU_OPT_NUMBER,
 340        },
 341        { /* end of list */ }
 342    },
 343};
 344
 345static QemuOptsList *vm_config_groups[] = {
 346    &qemu_drive_opts,
 347    &qemu_chardev_opts,
 348    &qemu_device_opts,
 349    &qemu_netdev_opts,
 350    &qemu_net_opts,
 351    &qemu_rtc_opts,
 352    &qemu_global_opts,
 353    &qemu_mon_opts,
 354    &qemu_cpudef_opts,
 355    NULL,
 356};
 357
 358static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
 359{
 360    int i;
 361
 362    for (i = 0; lists[i] != NULL; i++) {
 363        if (strcmp(lists[i]->name, group) == 0)
 364            break;
 365    }
 366    if (lists[i] == NULL) {
 367        error_report("there is no option group \"%s\"", group);
 368    }
 369    return lists[i];
 370}
 371
 372QemuOptsList *qemu_find_opts(const char *group)
 373{
 374    return find_list(vm_config_groups, group);
 375}
 376
 377int qemu_set_option(const char *str)
 378{
 379    char group[64], id[64], arg[64];
 380    QemuOptsList *list;
 381    QemuOpts *opts;
 382    int rc, offset;
 383
 384    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
 385    if (rc < 3 || str[offset] != '=') {
 386        error_report("can't parse: \"%s\"", str);
 387        return -1;
 388    }
 389
 390    list = qemu_find_opts(group);
 391    if (list == NULL) {
 392        return -1;
 393    }
 394
 395    opts = qemu_opts_find(list, id);
 396    if (!opts) {
 397        error_report("there is no %s \"%s\" defined",
 398                     list->name, id);
 399        return -1;
 400    }
 401
 402    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
 403        return -1;
 404    }
 405    return 0;
 406}
 407
 408int qemu_global_option(const char *str)
 409{
 410    char driver[64], property[64];
 411    QemuOpts *opts;
 412    int rc, offset;
 413
 414    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
 415    if (rc < 2 || str[offset] != '=') {
 416        error_report("can't parse: \"%s\"", str);
 417        return -1;
 418    }
 419
 420    opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
 421    qemu_opt_set(opts, "driver", driver);
 422    qemu_opt_set(opts, "property", property);
 423    qemu_opt_set(opts, "value", str+offset+1);
 424    return 0;
 425}
 426
 427struct ConfigWriteData {
 428    QemuOptsList *list;
 429    FILE *fp;
 430};
 431
 432static int config_write_opt(const char *name, const char *value, void *opaque)
 433{
 434    struct ConfigWriteData *data = opaque;
 435
 436    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
 437    return 0;
 438}
 439
 440static int config_write_opts(QemuOpts *opts, void *opaque)
 441{
 442    struct ConfigWriteData *data = opaque;
 443    const char *id = qemu_opts_id(opts);
 444
 445    if (id) {
 446        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
 447    } else {
 448        fprintf(data->fp, "[%s]\n", data->list->name);
 449    }
 450    qemu_opt_foreach(opts, config_write_opt, data, 0);
 451    fprintf(data->fp, "\n");
 452    return 0;
 453}
 454
 455void qemu_config_write(FILE *fp)
 456{
 457    struct ConfigWriteData data = { .fp = fp };
 458    QemuOptsList **lists = vm_config_groups;
 459    int i;
 460
 461    fprintf(fp, "# qemu config file\n\n");
 462    for (i = 0; lists[i] != NULL; i++) {
 463        data.list = lists[i];
 464        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
 465    }
 466}
 467
 468int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
 469{
 470    char line[1024], group[64], id[64], arg[64], value[1024];
 471    Location loc;
 472    QemuOptsList *list = NULL;
 473    QemuOpts *opts = NULL;
 474    int res = -1, lno = 0;
 475
 476    loc_push_none(&loc);
 477    while (fgets(line, sizeof(line), fp) != NULL) {
 478        loc_set_file(fname, ++lno);
 479        if (line[0] == '\n') {
 480            /* skip empty lines */
 481            continue;
 482        }
 483        if (line[0] == '#') {
 484            /* comment */
 485            continue;
 486        }
 487        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
 488            /* group with id */
 489            list = find_list(lists, group);
 490            if (list == NULL)
 491                goto out;
 492            opts = qemu_opts_create(list, id, 1);
 493            continue;
 494        }
 495        if (sscanf(line, "[%63[^]]]", group) == 1) {
 496            /* group without id */
 497            list = find_list(lists, group);
 498            if (list == NULL)
 499                goto out;
 500            opts = qemu_opts_create(list, NULL, 0);
 501            continue;
 502        }
 503        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
 504            /* arg = value */
 505            if (opts == NULL) {
 506                error_report("no group defined");
 507                goto out;
 508            }
 509            if (qemu_opt_set(opts, arg, value) != 0) {
 510                goto out;
 511            }
 512            continue;
 513        }
 514        error_report("parse error");
 515        goto out;
 516    }
 517    if (ferror(fp)) {
 518        error_report("error reading file");
 519        goto out;
 520    }
 521    res = 0;
 522out:
 523    loc_pop(&loc);
 524    return res;
 525}
 526
 527int qemu_read_config_file(const char *filename)
 528{
 529    FILE *f = fopen(filename, "r");
 530    int ret;
 531
 532    if (f == NULL) {
 533        return -errno;
 534    }
 535
 536    ret = qemu_config_parse(f, vm_config_groups, filename);
 537    fclose(f);
 538
 539    if (ret == 0) {
 540        return 0;
 541    } else {
 542        return -EINVAL;
 543    }
 544}
 545