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 "hw/qdev.h"
   6
   7static 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            .help = "index 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            .help = "enable/disable snapshot mode",
  51        },{
  52            .name = "file",
  53            .type = QEMU_OPT_STRING,
  54            .help = "disk image",
  55        },{
  56            .name = "cache",
  57            .type = QEMU_OPT_STRING,
  58            .help = "host cache usage (none, writeback, writethrough, unsafe)",
  59        },{
  60            .name = "aio",
  61            .type = QEMU_OPT_STRING,
  62            .help = "host AIO implementation (threads, native)",
  63        },{
  64            .name = "format",
  65            .type = QEMU_OPT_STRING,
  66            .help = "disk format (raw, qcow2, ...)",
  67        },{
  68            .name = "serial",
  69            .type = QEMU_OPT_STRING,
  70            .help = "disk serial number",
  71        },{
  72            .name = "rerror",
  73            .type = QEMU_OPT_STRING,
  74            .help = "read error action",
  75        },{
  76            .name = "werror",
  77            .type = QEMU_OPT_STRING,
  78            .help = "write error action",
  79        },{
  80            .name = "addr",
  81            .type = QEMU_OPT_STRING,
  82            .help = "pci address (virtio only)",
  83        },{
  84            .name = "readonly",
  85            .type = QEMU_OPT_BOOL,
  86            .help = "open drive file as read-only",
  87        },
  88        { /* end of list */ }
  89    },
  90};
  91
  92static QemuOptsList qemu_chardev_opts = {
  93    .name = "chardev",
  94    .implied_opt_name = "backend",
  95    .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
  96    .desc = {
  97        {
  98            .name = "backend",
  99            .type = QEMU_OPT_STRING,
 100        },{
 101            .name = "path",
 102            .type = QEMU_OPT_STRING,
 103        },{
 104            .name = "host",
 105            .type = QEMU_OPT_STRING,
 106        },{
 107            .name = "port",
 108            .type = QEMU_OPT_STRING,
 109        },{
 110            .name = "localaddr",
 111            .type = QEMU_OPT_STRING,
 112        },{
 113            .name = "localport",
 114            .type = QEMU_OPT_STRING,
 115        },{
 116            .name = "to",
 117            .type = QEMU_OPT_NUMBER,
 118        },{
 119            .name = "ipv4",
 120            .type = QEMU_OPT_BOOL,
 121        },{
 122            .name = "ipv6",
 123            .type = QEMU_OPT_BOOL,
 124        },{
 125            .name = "wait",
 126            .type = QEMU_OPT_BOOL,
 127        },{
 128            .name = "server",
 129            .type = QEMU_OPT_BOOL,
 130        },{
 131            .name = "delay",
 132            .type = QEMU_OPT_BOOL,
 133        },{
 134            .name = "telnet",
 135            .type = QEMU_OPT_BOOL,
 136        },{
 137            .name = "width",
 138            .type = QEMU_OPT_NUMBER,
 139        },{
 140            .name = "height",
 141            .type = QEMU_OPT_NUMBER,
 142        },{
 143            .name = "cols",
 144            .type = QEMU_OPT_NUMBER,
 145        },{
 146            .name = "rows",
 147            .type = QEMU_OPT_NUMBER,
 148        },{
 149            .name = "mux",
 150            .type = QEMU_OPT_BOOL,
 151        },{
 152            .name = "signal",
 153            .type = QEMU_OPT_BOOL,
 154        },{
 155            .name = "name",
 156            .type = QEMU_OPT_STRING,
 157        },{
 158            .name = "debug",
 159            .type = QEMU_OPT_NUMBER,
 160        },
 161        { /* end of list */ }
 162    },
 163};
 164
 165QemuOptsList qemu_fsdev_opts = {
 166    .name = "fsdev",
 167    .implied_opt_name = "fstype",
 168    .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
 169    .desc = {
 170        {
 171            .name = "fstype",
 172            .type = QEMU_OPT_STRING,
 173        }, {
 174            .name = "path",
 175            .type = QEMU_OPT_STRING,
 176        }, {
 177            .name = "security_model",
 178            .type = QEMU_OPT_STRING,
 179        },
 180        { /*End of list */ }
 181    },
 182};
 183
 184QemuOptsList qemu_virtfs_opts = {
 185    .name = "virtfs",
 186    .implied_opt_name = "fstype",
 187    .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
 188    .desc = {
 189        {
 190            .name = "fstype",
 191            .type = QEMU_OPT_STRING,
 192        }, {
 193            .name = "path",
 194            .type = QEMU_OPT_STRING,
 195        }, {
 196            .name = "mount_tag",
 197            .type = QEMU_OPT_STRING,
 198        }, {
 199            .name = "security_model",
 200            .type = QEMU_OPT_STRING,
 201        },
 202
 203        { /*End of list */ }
 204    },
 205};
 206
 207static QemuOptsList qemu_device_opts = {
 208    .name = "device",
 209    .implied_opt_name = "driver",
 210    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
 211    .desc = {
 212        /*
 213         * no elements => accept any
 214         * sanity checking will happen later
 215         * when setting device properties
 216         */
 217        { /* end of list */ }
 218    },
 219};
 220
 221static QemuOptsList qemu_netdev_opts = {
 222    .name = "netdev",
 223    .implied_opt_name = "type",
 224    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
 225    .desc = {
 226        /*
 227         * no elements => accept any params
 228         * validation will happen later
 229         */
 230        { /* end of list */ }
 231    },
 232};
 233
 234static QemuOptsList qemu_net_opts = {
 235    .name = "net",
 236    .implied_opt_name = "type",
 237    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
 238    .desc = {
 239        /*
 240         * no elements => accept any params
 241         * validation will happen later
 242         */
 243        { /* end of list */ }
 244    },
 245};
 246
 247static QemuOptsList qemu_rtc_opts = {
 248    .name = "rtc",
 249    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
 250    .desc = {
 251        {
 252            .name = "base",
 253            .type = QEMU_OPT_STRING,
 254        },{
 255            .name = "clock",
 256            .type = QEMU_OPT_STRING,
 257        },{
 258            .name = "driftfix",
 259            .type = QEMU_OPT_STRING,
 260        },
 261        { /* end of list */ }
 262    },
 263};
 264
 265static QemuOptsList qemu_global_opts = {
 266    .name = "global",
 267    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
 268    .desc = {
 269        {
 270            .name = "driver",
 271            .type = QEMU_OPT_STRING,
 272        },{
 273            .name = "property",
 274            .type = QEMU_OPT_STRING,
 275        },{
 276            .name = "value",
 277            .type = QEMU_OPT_STRING,
 278        },
 279        { /* end of list */ }
 280    },
 281};
 282
 283static QemuOptsList qemu_mon_opts = {
 284    .name = "mon",
 285    .implied_opt_name = "chardev",
 286    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
 287    .desc = {
 288        {
 289            .name = "mode",
 290            .type = QEMU_OPT_STRING,
 291        },{
 292            .name = "chardev",
 293            .type = QEMU_OPT_STRING,
 294        },{
 295            .name = "default",
 296            .type = QEMU_OPT_BOOL,
 297        },{
 298            .name = "pretty",
 299            .type = QEMU_OPT_BOOL,
 300        },
 301        { /* end of list */ }
 302    },
 303};
 304
 305#ifdef CONFIG_SIMPLE_TRACE
 306static QemuOptsList qemu_trace_opts = {
 307    .name = "trace",
 308    .implied_opt_name = "trace",
 309    .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
 310    .desc = {
 311        {
 312            .name = "file",
 313            .type = QEMU_OPT_STRING,
 314        },
 315        { /* end of list */ }
 316    },
 317};
 318#endif
 319
 320static QemuOptsList qemu_cpudef_opts = {
 321    .name = "cpudef",
 322    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
 323    .desc = {
 324        {
 325            .name = "name",
 326            .type = QEMU_OPT_STRING,
 327        },{
 328            .name = "level",
 329            .type = QEMU_OPT_NUMBER,
 330        },{
 331            .name = "vendor",
 332            .type = QEMU_OPT_STRING,
 333        },{
 334            .name = "family",
 335            .type = QEMU_OPT_NUMBER,
 336        },{
 337            .name = "model",
 338            .type = QEMU_OPT_NUMBER,
 339        },{
 340            .name = "stepping",
 341            .type = QEMU_OPT_NUMBER,
 342        },{
 343            .name = "feature_edx",      /* cpuid 0000_0001.edx */
 344            .type = QEMU_OPT_STRING,
 345        },{
 346            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
 347            .type = QEMU_OPT_STRING,
 348        },{
 349            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
 350            .type = QEMU_OPT_STRING,
 351        },{
 352            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
 353            .type = QEMU_OPT_STRING,
 354        },{
 355            .name = "xlevel",
 356            .type = QEMU_OPT_NUMBER,
 357        },{
 358            .name = "model_id",
 359            .type = QEMU_OPT_STRING,
 360        },{
 361            .name = "vendor_override",
 362            .type = QEMU_OPT_NUMBER,
 363        },
 364        { /* end of list */ }
 365    },
 366};
 367
 368QemuOptsList qemu_spice_opts = {
 369    .name = "spice",
 370    .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
 371    .desc = {
 372        {
 373            .name = "port",
 374            .type = QEMU_OPT_NUMBER,
 375        },{
 376            .name = "tls-port",
 377            .type = QEMU_OPT_NUMBER,
 378        },{
 379            .name = "addr",
 380            .type = QEMU_OPT_STRING,
 381        },{
 382            .name = "ipv4",
 383            .type = QEMU_OPT_BOOL,
 384        },{
 385            .name = "ipv6",
 386            .type = QEMU_OPT_BOOL,
 387        },{
 388            .name = "password",
 389            .type = QEMU_OPT_STRING,
 390        },{
 391            .name = "disable-ticketing",
 392            .type = QEMU_OPT_BOOL,
 393        },{
 394            .name = "disable-copy-paste",
 395            .type = QEMU_OPT_BOOL,
 396        },{
 397            .name = "sasl",
 398            .type = QEMU_OPT_BOOL,
 399        },{
 400            .name = "x509-dir",
 401            .type = QEMU_OPT_STRING,
 402        },{
 403            .name = "x509-key-file",
 404            .type = QEMU_OPT_STRING,
 405        },{
 406            .name = "x509-key-password",
 407            .type = QEMU_OPT_STRING,
 408        },{
 409            .name = "x509-cert-file",
 410            .type = QEMU_OPT_STRING,
 411        },{
 412            .name = "x509-cacert-file",
 413            .type = QEMU_OPT_STRING,
 414        },{
 415            .name = "x509-dh-key-file",
 416            .type = QEMU_OPT_STRING,
 417        },{
 418            .name = "tls-ciphers",
 419            .type = QEMU_OPT_STRING,
 420        },{
 421            .name = "tls-channel",
 422            .type = QEMU_OPT_STRING,
 423        },{
 424            .name = "plaintext-channel",
 425            .type = QEMU_OPT_STRING,
 426        },{
 427            .name = "image-compression",
 428            .type = QEMU_OPT_STRING,
 429        },{
 430            .name = "jpeg-wan-compression",
 431            .type = QEMU_OPT_STRING,
 432        },{
 433            .name = "zlib-glz-wan-compression",
 434            .type = QEMU_OPT_STRING,
 435        },{
 436            .name = "streaming-video",
 437            .type = QEMU_OPT_STRING,
 438        },{
 439            .name = "agent-mouse",
 440            .type = QEMU_OPT_BOOL,
 441        },{
 442            .name = "playback-compression",
 443            .type = QEMU_OPT_BOOL,
 444        },
 445        { /* end of list */ }
 446    },
 447};
 448
 449QemuOptsList qemu_option_rom_opts = {
 450    .name = "option-rom",
 451    .implied_opt_name = "romfile",
 452    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
 453    .desc = {
 454        {
 455            .name = "bootindex",
 456            .type = QEMU_OPT_NUMBER,
 457        }, {
 458            .name = "romfile",
 459            .type = QEMU_OPT_STRING,
 460        },
 461        { /* end of list */ }
 462    },
 463};
 464
 465static QemuOptsList qemu_machine_opts = {
 466    .name = "machine",
 467    .implied_opt_name = "type",
 468    .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
 469    .desc = {
 470        {
 471            .name = "type",
 472            .type = QEMU_OPT_STRING,
 473            .help = "emulated machine"
 474        }, {
 475            .name = "accel",
 476            .type = QEMU_OPT_STRING,
 477            .help = "accelerator list",
 478        },
 479        { /* End of list */ }
 480    },
 481};
 482
 483static QemuOptsList *vm_config_groups[32] = {
 484    &qemu_drive_opts,
 485    &qemu_chardev_opts,
 486    &qemu_device_opts,
 487    &qemu_netdev_opts,
 488    &qemu_net_opts,
 489    &qemu_rtc_opts,
 490    &qemu_global_opts,
 491    &qemu_mon_opts,
 492    &qemu_cpudef_opts,
 493#ifdef CONFIG_SIMPLE_TRACE
 494    &qemu_trace_opts,
 495#endif
 496    &qemu_option_rom_opts,
 497    &qemu_machine_opts,
 498    NULL,
 499};
 500
 501static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
 502{
 503    int i;
 504
 505    for (i = 0; lists[i] != NULL; i++) {
 506        if (strcmp(lists[i]->name, group) == 0)
 507            break;
 508    }
 509    if (lists[i] == NULL) {
 510        error_report("there is no option group \"%s\"", group);
 511    }
 512    return lists[i];
 513}
 514
 515QemuOptsList *qemu_find_opts(const char *group)
 516{
 517    return find_list(vm_config_groups, group);
 518}
 519
 520void qemu_add_opts(QemuOptsList *list)
 521{
 522    int entries, i;
 523
 524    entries = ARRAY_SIZE(vm_config_groups);
 525    entries--; /* keep list NULL terminated */
 526    for (i = 0; i < entries; i++) {
 527        if (vm_config_groups[i] == NULL) {
 528            vm_config_groups[i] = list;
 529            return;
 530        }
 531    }
 532    fprintf(stderr, "ran out of space in vm_config_groups");
 533    abort();
 534}
 535
 536int qemu_set_option(const char *str)
 537{
 538    char group[64], id[64], arg[64];
 539    QemuOptsList *list;
 540    QemuOpts *opts;
 541    int rc, offset;
 542
 543    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
 544    if (rc < 3 || str[offset] != '=') {
 545        error_report("can't parse: \"%s\"", str);
 546        return -1;
 547    }
 548
 549    list = qemu_find_opts(group);
 550    if (list == NULL) {
 551        return -1;
 552    }
 553
 554    opts = qemu_opts_find(list, id);
 555    if (!opts) {
 556        error_report("there is no %s \"%s\" defined",
 557                     list->name, id);
 558        return -1;
 559    }
 560
 561    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
 562        return -1;
 563    }
 564    return 0;
 565}
 566
 567int qemu_global_option(const char *str)
 568{
 569    char driver[64], property[64];
 570    QemuOpts *opts;
 571    int rc, offset;
 572
 573    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
 574    if (rc < 2 || str[offset] != '=') {
 575        error_report("can't parse: \"%s\"", str);
 576        return -1;
 577    }
 578
 579    opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
 580    qemu_opt_set(opts, "driver", driver);
 581    qemu_opt_set(opts, "property", property);
 582    qemu_opt_set(opts, "value", str+offset+1);
 583    return 0;
 584}
 585
 586struct ConfigWriteData {
 587    QemuOptsList *list;
 588    FILE *fp;
 589};
 590
 591static int config_write_opt(const char *name, const char *value, void *opaque)
 592{
 593    struct ConfigWriteData *data = opaque;
 594
 595    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
 596    return 0;
 597}
 598
 599static int config_write_opts(QemuOpts *opts, void *opaque)
 600{
 601    struct ConfigWriteData *data = opaque;
 602    const char *id = qemu_opts_id(opts);
 603
 604    if (id) {
 605        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
 606    } else {
 607        fprintf(data->fp, "[%s]\n", data->list->name);
 608    }
 609    qemu_opt_foreach(opts, config_write_opt, data, 0);
 610    fprintf(data->fp, "\n");
 611    return 0;
 612}
 613
 614void qemu_config_write(FILE *fp)
 615{
 616    struct ConfigWriteData data = { .fp = fp };
 617    QemuOptsList **lists = vm_config_groups;
 618    int i;
 619
 620    fprintf(fp, "# qemu config file\n\n");
 621    for (i = 0; lists[i] != NULL; i++) {
 622        data.list = lists[i];
 623        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
 624    }
 625}
 626
 627int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
 628{
 629    char line[1024], group[64], id[64], arg[64], value[1024];
 630    Location loc;
 631    QemuOptsList *list = NULL;
 632    QemuOpts *opts = NULL;
 633    int res = -1, lno = 0;
 634
 635    loc_push_none(&loc);
 636    while (fgets(line, sizeof(line), fp) != NULL) {
 637        loc_set_file(fname, ++lno);
 638        if (line[0] == '\n') {
 639            /* skip empty lines */
 640            continue;
 641        }
 642        if (line[0] == '#') {
 643            /* comment */
 644            continue;
 645        }
 646        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
 647            /* group with id */
 648            list = find_list(lists, group);
 649            if (list == NULL)
 650                goto out;
 651            opts = qemu_opts_create(list, id, 1);
 652            continue;
 653        }
 654        if (sscanf(line, "[%63[^]]]", group) == 1) {
 655            /* group without id */
 656            list = find_list(lists, group);
 657            if (list == NULL)
 658                goto out;
 659            opts = qemu_opts_create(list, NULL, 0);
 660            continue;
 661        }
 662        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
 663            /* arg = value */
 664            if (opts == NULL) {
 665                error_report("no group defined");
 666                goto out;
 667            }
 668            if (qemu_opt_set(opts, arg, value) != 0) {
 669                goto out;
 670            }
 671            continue;
 672        }
 673        error_report("parse error");
 674        goto out;
 675    }
 676    if (ferror(fp)) {
 677        error_report("error reading file");
 678        goto out;
 679    }
 680    res = 0;
 681out:
 682    loc_pop(&loc);
 683    return res;
 684}
 685
 686int qemu_read_config_file(const char *filename)
 687{
 688    FILE *f = fopen(filename, "r");
 689    int ret;
 690
 691    if (f == NULL) {
 692        return -errno;
 693    }
 694
 695    ret = qemu_config_parse(f, vm_config_groups, filename);
 696    fclose(f);
 697
 698    if (ret == 0) {
 699        return 0;
 700    } else {
 701        return -EINVAL;
 702    }
 703}
 704