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#include "error.h"
   7
   8static 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            .help = "index number",
  28        },{
  29            .name = "cyls",
  30            .type = QEMU_OPT_NUMBER,
  31            .help = "number of cylinders (ide disk geometry)",
  32        },{
  33            .name = "heads",
  34            .type = QEMU_OPT_NUMBER,
  35            .help = "number of heads (ide disk geometry)",
  36        },{
  37            .name = "secs",
  38            .type = QEMU_OPT_NUMBER,
  39            .help = "number of sectors (ide disk geometry)",
  40        },{
  41            .name = "trans",
  42            .type = QEMU_OPT_STRING,
  43            .help = "chs translation (auto, lba. none)",
  44        },{
  45            .name = "media",
  46            .type = QEMU_OPT_STRING,
  47            .help = "media type (disk, cdrom)",
  48        },{
  49            .name = "snapshot",
  50            .type = QEMU_OPT_BOOL,
  51            .help = "enable/disable snapshot mode",
  52        },{
  53            .name = "file",
  54            .type = QEMU_OPT_STRING,
  55            .help = "disk image",
  56        },{
  57            .name = "cache",
  58            .type = QEMU_OPT_STRING,
  59            .help = "host cache usage (none, writeback, writethrough, "
  60                    "directsync, unsafe)",
  61        },{
  62            .name = "aio",
  63            .type = QEMU_OPT_STRING,
  64            .help = "host AIO implementation (threads, native)",
  65        },{
  66            .name = "format",
  67            .type = QEMU_OPT_STRING,
  68            .help = "disk format (raw, qcow2, ...)",
  69        },{
  70            .name = "serial",
  71            .type = QEMU_OPT_STRING,
  72            .help = "disk serial number",
  73        },{
  74            .name = "rerror",
  75            .type = QEMU_OPT_STRING,
  76            .help = "read error action",
  77        },{
  78            .name = "werror",
  79            .type = QEMU_OPT_STRING,
  80            .help = "write error action",
  81        },{
  82            .name = "addr",
  83            .type = QEMU_OPT_STRING,
  84            .help = "pci address (virtio only)",
  85        },{
  86            .name = "readonly",
  87            .type = QEMU_OPT_BOOL,
  88            .help = "open drive file as read-only",
  89        },{
  90            .name = "iops",
  91            .type = QEMU_OPT_NUMBER,
  92            .help = "limit total I/O operations per second",
  93        },{
  94            .name = "iops_rd",
  95            .type = QEMU_OPT_NUMBER,
  96            .help = "limit read operations per second",
  97        },{
  98            .name = "iops_wr",
  99            .type = QEMU_OPT_NUMBER,
 100            .help = "limit write operations per second",
 101        },{
 102            .name = "bps",
 103            .type = QEMU_OPT_NUMBER,
 104            .help = "limit total bytes per second",
 105        },{
 106            .name = "bps_rd",
 107            .type = QEMU_OPT_NUMBER,
 108            .help = "limit read bytes per second",
 109        },{
 110            .name = "bps_wr",
 111            .type = QEMU_OPT_NUMBER,
 112            .help = "limit write bytes per second",
 113        },{
 114            .name = "copy-on-read",
 115            .type = QEMU_OPT_BOOL,
 116            .help = "copy read data from backing file into image file",
 117        },{
 118            .name = "boot",
 119            .type = QEMU_OPT_BOOL,
 120            .help = "(deprecated, ignored)",
 121        },
 122        { /* end of list */ }
 123    },
 124};
 125
 126static QemuOptsList qemu_iscsi_opts = {
 127    .name = "iscsi",
 128    .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head),
 129    .desc = {
 130        {
 131            .name = "user",
 132            .type = QEMU_OPT_STRING,
 133            .help = "username for CHAP authentication to target",
 134        },{
 135            .name = "password",
 136            .type = QEMU_OPT_STRING,
 137            .help = "password for CHAP authentication to target",
 138        },{
 139            .name = "header-digest",
 140            .type = QEMU_OPT_STRING,
 141            .help = "HeaderDigest setting. "
 142                    "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}",
 143        },{
 144            .name = "initiator-name",
 145            .type = QEMU_OPT_STRING,
 146            .help = "Initiator iqn name to use when connecting",
 147        },
 148        { /* end of list */ }
 149    },
 150};
 151
 152static QemuOptsList qemu_chardev_opts = {
 153    .name = "chardev",
 154    .implied_opt_name = "backend",
 155    .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
 156    .desc = {
 157        {
 158            .name = "backend",
 159            .type = QEMU_OPT_STRING,
 160        },{
 161            .name = "path",
 162            .type = QEMU_OPT_STRING,
 163        },{
 164            .name = "host",
 165            .type = QEMU_OPT_STRING,
 166        },{
 167            .name = "port",
 168            .type = QEMU_OPT_STRING,
 169        },{
 170            .name = "localaddr",
 171            .type = QEMU_OPT_STRING,
 172        },{
 173            .name = "localport",
 174            .type = QEMU_OPT_STRING,
 175        },{
 176            .name = "to",
 177            .type = QEMU_OPT_NUMBER,
 178        },{
 179            .name = "ipv4",
 180            .type = QEMU_OPT_BOOL,
 181        },{
 182            .name = "ipv6",
 183            .type = QEMU_OPT_BOOL,
 184        },{
 185            .name = "wait",
 186            .type = QEMU_OPT_BOOL,
 187        },{
 188            .name = "server",
 189            .type = QEMU_OPT_BOOL,
 190        },{
 191            .name = "delay",
 192            .type = QEMU_OPT_BOOL,
 193        },{
 194            .name = "telnet",
 195            .type = QEMU_OPT_BOOL,
 196        },{
 197            .name = "width",
 198            .type = QEMU_OPT_NUMBER,
 199        },{
 200            .name = "height",
 201            .type = QEMU_OPT_NUMBER,
 202        },{
 203            .name = "cols",
 204            .type = QEMU_OPT_NUMBER,
 205        },{
 206            .name = "rows",
 207            .type = QEMU_OPT_NUMBER,
 208        },{
 209            .name = "mux",
 210            .type = QEMU_OPT_BOOL,
 211        },{
 212            .name = "signal",
 213            .type = QEMU_OPT_BOOL,
 214        },{
 215            .name = "name",
 216            .type = QEMU_OPT_STRING,
 217        },{
 218            .name = "debug",
 219            .type = QEMU_OPT_NUMBER,
 220        },
 221        { /* end of list */ }
 222    },
 223};
 224
 225QemuOptsList qemu_fsdev_opts = {
 226    .name = "fsdev",
 227    .implied_opt_name = "fsdriver",
 228    .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
 229    .desc = {
 230        {
 231            .name = "fsdriver",
 232            .type = QEMU_OPT_STRING,
 233        }, {
 234            .name = "path",
 235            .type = QEMU_OPT_STRING,
 236        }, {
 237            .name = "security_model",
 238            .type = QEMU_OPT_STRING,
 239        }, {
 240            .name = "writeout",
 241            .type = QEMU_OPT_STRING,
 242        }, {
 243            .name = "readonly",
 244            .type = QEMU_OPT_BOOL,
 245
 246        }, {
 247            .name = "socket",
 248            .type = QEMU_OPT_STRING,
 249        }, {
 250            .name = "sock_fd",
 251            .type = QEMU_OPT_NUMBER,
 252        },
 253
 254        { /*End of list */ }
 255    },
 256};
 257
 258QemuOptsList qemu_virtfs_opts = {
 259    .name = "virtfs",
 260    .implied_opt_name = "fsdriver",
 261    .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
 262    .desc = {
 263        {
 264            .name = "fsdriver",
 265            .type = QEMU_OPT_STRING,
 266        }, {
 267            .name = "path",
 268            .type = QEMU_OPT_STRING,
 269        }, {
 270            .name = "mount_tag",
 271            .type = QEMU_OPT_STRING,
 272        }, {
 273            .name = "security_model",
 274            .type = QEMU_OPT_STRING,
 275        }, {
 276            .name = "writeout",
 277            .type = QEMU_OPT_STRING,
 278        }, {
 279            .name = "readonly",
 280            .type = QEMU_OPT_BOOL,
 281        }, {
 282            .name = "socket",
 283            .type = QEMU_OPT_STRING,
 284        }, {
 285            .name = "sock_fd",
 286            .type = QEMU_OPT_NUMBER,
 287        },
 288
 289        { /*End of list */ }
 290    },
 291};
 292
 293static QemuOptsList qemu_device_opts = {
 294    .name = "device",
 295    .implied_opt_name = "driver",
 296    .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
 297    .desc = {
 298        /*
 299         * no elements => accept any
 300         * sanity checking will happen later
 301         * when setting device properties
 302         */
 303        { /* end of list */ }
 304    },
 305};
 306
 307static QemuOptsList qemu_netdev_opts = {
 308    .name = "netdev",
 309    .implied_opt_name = "type",
 310    .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
 311    .desc = {
 312        /*
 313         * no elements => accept any params
 314         * validation will happen later
 315         */
 316        { /* end of list */ }
 317    },
 318};
 319
 320static QemuOptsList qemu_net_opts = {
 321    .name = "net",
 322    .implied_opt_name = "type",
 323    .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
 324    .desc = {
 325        /*
 326         * no elements => accept any params
 327         * validation will happen later
 328         */
 329        { /* end of list */ }
 330    },
 331};
 332
 333static QemuOptsList qemu_rtc_opts = {
 334    .name = "rtc",
 335    .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
 336    .desc = {
 337        {
 338            .name = "base",
 339            .type = QEMU_OPT_STRING,
 340        },{
 341            .name = "clock",
 342            .type = QEMU_OPT_STRING,
 343        },{
 344            .name = "driftfix",
 345            .type = QEMU_OPT_STRING,
 346        },
 347        { /* end of list */ }
 348    },
 349};
 350
 351static QemuOptsList qemu_global_opts = {
 352    .name = "global",
 353    .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
 354    .desc = {
 355        {
 356            .name = "driver",
 357            .type = QEMU_OPT_STRING,
 358        },{
 359            .name = "property",
 360            .type = QEMU_OPT_STRING,
 361        },{
 362            .name = "value",
 363            .type = QEMU_OPT_STRING,
 364        },
 365        { /* end of list */ }
 366    },
 367};
 368
 369QemuOptsList qemu_sandbox_opts = {
 370    .name = "sandbox",
 371    .implied_opt_name = "enable",
 372    .head = QTAILQ_HEAD_INITIALIZER(qemu_sandbox_opts.head),
 373    .desc = {
 374        {
 375            .name = "enable",
 376            .type = QEMU_OPT_BOOL,
 377        },
 378        { /* end of list */ }
 379    },
 380};
 381
 382static QemuOptsList qemu_mon_opts = {
 383    .name = "mon",
 384    .implied_opt_name = "chardev",
 385    .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
 386    .desc = {
 387        {
 388            .name = "mode",
 389            .type = QEMU_OPT_STRING,
 390        },{
 391            .name = "chardev",
 392            .type = QEMU_OPT_STRING,
 393        },{
 394            .name = "default",
 395            .type = QEMU_OPT_BOOL,
 396        },{
 397            .name = "pretty",
 398            .type = QEMU_OPT_BOOL,
 399        },
 400        { /* end of list */ }
 401    },
 402};
 403
 404static QemuOptsList qemu_trace_opts = {
 405    .name = "trace",
 406    .implied_opt_name = "trace",
 407    .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
 408    .desc = {
 409        {
 410            .name = "events",
 411            .type = QEMU_OPT_STRING,
 412        },{
 413            .name = "file",
 414            .type = QEMU_OPT_STRING,
 415        },
 416        { /* end of list */ }
 417    },
 418};
 419
 420static QemuOptsList qemu_cpudef_opts = {
 421    .name = "cpudef",
 422    .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
 423    .desc = {
 424        {
 425            .name = "name",
 426            .type = QEMU_OPT_STRING,
 427        },{
 428            .name = "level",
 429            .type = QEMU_OPT_NUMBER,
 430        },{
 431            .name = "vendor",
 432            .type = QEMU_OPT_STRING,
 433        },{
 434            .name = "family",
 435            .type = QEMU_OPT_NUMBER,
 436        },{
 437            .name = "model",
 438            .type = QEMU_OPT_NUMBER,
 439        },{
 440            .name = "stepping",
 441            .type = QEMU_OPT_NUMBER,
 442        },{
 443            .name = "feature_edx",      /* cpuid 0000_0001.edx */
 444            .type = QEMU_OPT_STRING,
 445        },{
 446            .name = "feature_ecx",      /* cpuid 0000_0001.ecx */
 447            .type = QEMU_OPT_STRING,
 448        },{
 449            .name = "extfeature_edx",   /* cpuid 8000_0001.edx */
 450            .type = QEMU_OPT_STRING,
 451        },{
 452            .name = "extfeature_ecx",   /* cpuid 8000_0001.ecx */
 453            .type = QEMU_OPT_STRING,
 454        },{
 455            .name = "xlevel",
 456            .type = QEMU_OPT_NUMBER,
 457        },{
 458            .name = "model_id",
 459            .type = QEMU_OPT_STRING,
 460        },{
 461            .name = "vendor_override",
 462            .type = QEMU_OPT_NUMBER,
 463        },
 464        { /* end of list */ }
 465    },
 466};
 467
 468QemuOptsList qemu_spice_opts = {
 469    .name = "spice",
 470    .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
 471    .desc = {
 472        {
 473            .name = "port",
 474            .type = QEMU_OPT_NUMBER,
 475        },{
 476            .name = "tls-port",
 477            .type = QEMU_OPT_NUMBER,
 478        },{
 479            .name = "addr",
 480            .type = QEMU_OPT_STRING,
 481        },{
 482            .name = "ipv4",
 483            .type = QEMU_OPT_BOOL,
 484        },{
 485            .name = "ipv6",
 486            .type = QEMU_OPT_BOOL,
 487        },{
 488            .name = "password",
 489            .type = QEMU_OPT_STRING,
 490        },{
 491            .name = "disable-ticketing",
 492            .type = QEMU_OPT_BOOL,
 493        },{
 494            .name = "disable-copy-paste",
 495            .type = QEMU_OPT_BOOL,
 496        },{
 497            .name = "sasl",
 498            .type = QEMU_OPT_BOOL,
 499        },{
 500            .name = "x509-dir",
 501            .type = QEMU_OPT_STRING,
 502        },{
 503            .name = "x509-key-file",
 504            .type = QEMU_OPT_STRING,
 505        },{
 506            .name = "x509-key-password",
 507            .type = QEMU_OPT_STRING,
 508        },{
 509            .name = "x509-cert-file",
 510            .type = QEMU_OPT_STRING,
 511        },{
 512            .name = "x509-cacert-file",
 513            .type = QEMU_OPT_STRING,
 514        },{
 515            .name = "x509-dh-key-file",
 516            .type = QEMU_OPT_STRING,
 517        },{
 518            .name = "tls-ciphers",
 519            .type = QEMU_OPT_STRING,
 520        },{
 521            .name = "tls-channel",
 522            .type = QEMU_OPT_STRING,
 523        },{
 524            .name = "plaintext-channel",
 525            .type = QEMU_OPT_STRING,
 526        },{
 527            .name = "image-compression",
 528            .type = QEMU_OPT_STRING,
 529        },{
 530            .name = "jpeg-wan-compression",
 531            .type = QEMU_OPT_STRING,
 532        },{
 533            .name = "zlib-glz-wan-compression",
 534            .type = QEMU_OPT_STRING,
 535        },{
 536            .name = "streaming-video",
 537            .type = QEMU_OPT_STRING,
 538        },{
 539            .name = "agent-mouse",
 540            .type = QEMU_OPT_BOOL,
 541        },{
 542            .name = "playback-compression",
 543            .type = QEMU_OPT_BOOL,
 544        }, {
 545            .name = "seamless-migration",
 546            .type = QEMU_OPT_BOOL,
 547        },
 548        { /* end of list */ }
 549    },
 550};
 551
 552QemuOptsList qemu_option_rom_opts = {
 553    .name = "option-rom",
 554    .implied_opt_name = "romfile",
 555    .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
 556    .desc = {
 557        {
 558            .name = "bootindex",
 559            .type = QEMU_OPT_NUMBER,
 560        }, {
 561            .name = "romfile",
 562            .type = QEMU_OPT_STRING,
 563        },
 564        { /* end of list */ }
 565    },
 566};
 567
 568static QemuOptsList qemu_machine_opts = {
 569    .name = "machine",
 570    .implied_opt_name = "type",
 571    .merge_lists = true,
 572    .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
 573    .desc = {
 574        {
 575            .name = "type",
 576            .type = QEMU_OPT_STRING,
 577            .help = "emulated machine"
 578        }, {
 579            .name = "accel",
 580            .type = QEMU_OPT_STRING,
 581            .help = "accelerator list",
 582        }, {
 583            .name = "kernel_irqchip",
 584            .type = QEMU_OPT_BOOL,
 585            .help = "use KVM in-kernel irqchip",
 586        }, {
 587            .name = "kvm_shadow_mem",
 588            .type = QEMU_OPT_SIZE,
 589            .help = "KVM shadow MMU size",
 590        }, {
 591            .name = "kernel",
 592            .type = QEMU_OPT_STRING,
 593            .help = "Linux kernel image file",
 594        }, {
 595            .name = "initrd",
 596            .type = QEMU_OPT_STRING,
 597            .help = "Linux initial ramdisk file",
 598        }, {
 599            .name = "append",
 600            .type = QEMU_OPT_STRING,
 601            .help = "Linux kernel command line",
 602        }, {
 603            .name = "dtb",
 604            .type = QEMU_OPT_STRING,
 605            .help = "Linux kernel device tree file",
 606        }, {
 607            .name = "dumpdtb",
 608            .type = QEMU_OPT_STRING,
 609            .help = "Dump current dtb to a file and quit",
 610        }, {
 611            .name = "phandle_start",
 612            .type = QEMU_OPT_STRING,
 613            .help = "The first phandle ID we may generate dynamically",
 614        }, {
 615            .name = "dt_compatible",
 616            .type = QEMU_OPT_STRING,
 617            .help = "Overrides the \"compatible\" property of the dt root node",
 618        }, {
 619            .name = "dump-guest-core",
 620            .type = QEMU_OPT_BOOL,
 621            .help = "Include guest memory in  a core dump",
 622        }, {
 623            .name = "mem-merge",
 624            .type = QEMU_OPT_BOOL,
 625            .help = "enable/disable memory merge support",
 626        },{
 627            .name = "usb",
 628            .type = QEMU_OPT_BOOL,
 629            .help = "Set on/off to enable/disable usb",
 630        },
 631        { /* End of list */ }
 632    },
 633};
 634
 635QemuOptsList qemu_boot_opts = {
 636    .name = "boot-opts",
 637    .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head),
 638    .desc = {
 639        /* the three names below are not used now */
 640        {
 641            .name = "order",
 642            .type = QEMU_OPT_STRING,
 643        }, {
 644            .name = "once",
 645            .type = QEMU_OPT_STRING,
 646        }, {
 647            .name = "menu",
 648            .type = QEMU_OPT_STRING,
 649        /* following are really used */
 650        }, {
 651            .name = "splash",
 652            .type = QEMU_OPT_STRING,
 653        }, {
 654            .name = "splash-time",
 655            .type = QEMU_OPT_STRING,
 656        }, {
 657            .name = "reboot-timeout",
 658            .type = QEMU_OPT_STRING,
 659        },
 660        { /*End of list */ }
 661    },
 662};
 663
 664static QemuOptsList qemu_add_fd_opts = {
 665    .name = "add-fd",
 666    .head = QTAILQ_HEAD_INITIALIZER(qemu_add_fd_opts.head),
 667    .desc = {
 668        {
 669            .name = "fd",
 670            .type = QEMU_OPT_NUMBER,
 671            .help = "file descriptor of which a duplicate is added to fd set",
 672        },{
 673            .name = "set",
 674            .type = QEMU_OPT_NUMBER,
 675            .help = "ID of the fd set to add fd to",
 676        },{
 677            .name = "opaque",
 678            .type = QEMU_OPT_STRING,
 679            .help = "free-form string used to describe fd",
 680        },
 681        { /* end of list */ }
 682    },
 683};
 684
 685static QemuOptsList qemu_object_opts = {
 686    .name = "object",
 687    .implied_opt_name = "qom-type",
 688    .head = QTAILQ_HEAD_INITIALIZER(qemu_object_opts.head),
 689    .desc = {
 690        { }
 691    },
 692};
 693
 694static QemuOptsList *vm_config_groups[32] = {
 695    &qemu_drive_opts,
 696    &qemu_chardev_opts,
 697    &qemu_device_opts,
 698    &qemu_netdev_opts,
 699    &qemu_net_opts,
 700    &qemu_rtc_opts,
 701    &qemu_global_opts,
 702    &qemu_mon_opts,
 703    &qemu_cpudef_opts,
 704    &qemu_trace_opts,
 705    &qemu_option_rom_opts,
 706    &qemu_machine_opts,
 707    &qemu_boot_opts,
 708    &qemu_iscsi_opts,
 709    &qemu_sandbox_opts,
 710    &qemu_add_fd_opts,
 711    &qemu_object_opts,
 712    NULL,
 713};
 714
 715static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
 716                               Error **errp)
 717{
 718    int i;
 719
 720    for (i = 0; lists[i] != NULL; i++) {
 721        if (strcmp(lists[i]->name, group) == 0)
 722            break;
 723    }
 724    if (lists[i] == NULL) {
 725        error_set(errp, QERR_INVALID_OPTION_GROUP, group);
 726    }
 727    return lists[i];
 728}
 729
 730QemuOptsList *qemu_find_opts(const char *group)
 731{
 732    QemuOptsList *ret;
 733    Error *local_err = NULL;
 734
 735    ret = find_list(vm_config_groups, group, &local_err);
 736    if (error_is_set(&local_err)) {
 737        error_report("%s\n", error_get_pretty(local_err));
 738        error_free(local_err);
 739    }
 740
 741    return ret;
 742}
 743
 744QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
 745{
 746    return find_list(vm_config_groups, group, errp);
 747}
 748
 749void qemu_add_opts(QemuOptsList *list)
 750{
 751    int entries, i;
 752
 753    entries = ARRAY_SIZE(vm_config_groups);
 754    entries--; /* keep list NULL terminated */
 755    for (i = 0; i < entries; i++) {
 756        if (vm_config_groups[i] == NULL) {
 757            vm_config_groups[i] = list;
 758            return;
 759        }
 760    }
 761    fprintf(stderr, "ran out of space in vm_config_groups");
 762    abort();
 763}
 764
 765int qemu_set_option(const char *str)
 766{
 767    char group[64], id[64], arg[64];
 768    QemuOptsList *list;
 769    QemuOpts *opts;
 770    int rc, offset;
 771
 772    rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
 773    if (rc < 3 || str[offset] != '=') {
 774        error_report("can't parse: \"%s\"", str);
 775        return -1;
 776    }
 777
 778    list = qemu_find_opts(group);
 779    if (list == NULL) {
 780        return -1;
 781    }
 782
 783    opts = qemu_opts_find(list, id);
 784    if (!opts) {
 785        error_report("there is no %s \"%s\" defined",
 786                     list->name, id);
 787        return -1;
 788    }
 789
 790    if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
 791        return -1;
 792    }
 793    return 0;
 794}
 795
 796int qemu_global_option(const char *str)
 797{
 798    char driver[64], property[64];
 799    QemuOpts *opts;
 800    int rc, offset;
 801
 802    rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
 803    if (rc < 2 || str[offset] != '=') {
 804        error_report("can't parse: \"%s\"", str);
 805        return -1;
 806    }
 807
 808    opts = qemu_opts_create(&qemu_global_opts, NULL, 0, NULL);
 809    qemu_opt_set(opts, "driver", driver);
 810    qemu_opt_set(opts, "property", property);
 811    qemu_opt_set(opts, "value", str+offset+1);
 812    return 0;
 813}
 814
 815struct ConfigWriteData {
 816    QemuOptsList *list;
 817    FILE *fp;
 818};
 819
 820static int config_write_opt(const char *name, const char *value, void *opaque)
 821{
 822    struct ConfigWriteData *data = opaque;
 823
 824    fprintf(data->fp, "  %s = \"%s\"\n", name, value);
 825    return 0;
 826}
 827
 828static int config_write_opts(QemuOpts *opts, void *opaque)
 829{
 830    struct ConfigWriteData *data = opaque;
 831    const char *id = qemu_opts_id(opts);
 832
 833    if (id) {
 834        fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
 835    } else {
 836        fprintf(data->fp, "[%s]\n", data->list->name);
 837    }
 838    qemu_opt_foreach(opts, config_write_opt, data, 0);
 839    fprintf(data->fp, "\n");
 840    return 0;
 841}
 842
 843void qemu_config_write(FILE *fp)
 844{
 845    struct ConfigWriteData data = { .fp = fp };
 846    QemuOptsList **lists = vm_config_groups;
 847    int i;
 848
 849    fprintf(fp, "# qemu config file\n\n");
 850    for (i = 0; lists[i] != NULL; i++) {
 851        data.list = lists[i];
 852        qemu_opts_foreach(data.list, config_write_opts, &data, 0);
 853    }
 854}
 855
 856int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
 857{
 858    char line[1024], group[64], id[64], arg[64], value[1024];
 859    Location loc;
 860    QemuOptsList *list = NULL;
 861    Error *local_err = NULL;
 862    QemuOpts *opts = NULL;
 863    int res = -1, lno = 0;
 864
 865    loc_push_none(&loc);
 866    while (fgets(line, sizeof(line), fp) != NULL) {
 867        loc_set_file(fname, ++lno);
 868        if (line[0] == '\n') {
 869            /* skip empty lines */
 870            continue;
 871        }
 872        if (line[0] == '#') {
 873            /* comment */
 874            continue;
 875        }
 876        if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
 877            /* group with id */
 878            list = find_list(lists, group, &local_err);
 879            if (error_is_set(&local_err)) {
 880                error_report("%s\n", error_get_pretty(local_err));
 881                error_free(local_err);
 882                goto out;
 883            }
 884            opts = qemu_opts_create(list, id, 1, NULL);
 885            continue;
 886        }
 887        if (sscanf(line, "[%63[^]]]", group) == 1) {
 888            /* group without id */
 889            list = find_list(lists, group, &local_err);
 890            if (error_is_set(&local_err)) {
 891                error_report("%s\n", error_get_pretty(local_err));
 892                error_free(local_err);
 893                goto out;
 894            }
 895            opts = qemu_opts_create(list, NULL, 0, NULL);
 896            continue;
 897        }
 898        if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
 899            /* arg = value */
 900            if (opts == NULL) {
 901                error_report("no group defined");
 902                goto out;
 903            }
 904            if (qemu_opt_set(opts, arg, value) != 0) {
 905                goto out;
 906            }
 907            continue;
 908        }
 909        error_report("parse error");
 910        goto out;
 911    }
 912    if (ferror(fp)) {
 913        error_report("error reading file");
 914        goto out;
 915    }
 916    res = 0;
 917out:
 918    loc_pop(&loc);
 919    return res;
 920}
 921
 922int qemu_read_config_file(const char *filename)
 923{
 924    FILE *f = fopen(filename, "r");
 925    int ret;
 926
 927    if (f == NULL) {
 928        return -errno;
 929    }
 930
 931    ret = qemu_config_parse(f, vm_config_groups, filename);
 932    fclose(f);
 933
 934    if (ret == 0) {
 935        return 0;
 936    } else {
 937        return -EINVAL;
 938    }
 939}
 940