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