qemu-config.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  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. static QemuOptsList qemu_drive_opts = {
  7. .name = "drive",
  8. .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
  9. .desc = {
  10. {
  11. .name = "bus",
  12. .type = QEMU_OPT_NUMBER,
  13. .help = "bus number",
  14. },{
  15. .name = "unit",
  16. .type = QEMU_OPT_NUMBER,
  17. .help = "unit number (i.e. lun for scsi)",
  18. },{
  19. .name = "if",
  20. .type = QEMU_OPT_STRING,
  21. .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
  22. },{
  23. .name = "index",
  24. .type = QEMU_OPT_NUMBER,
  25. .help = "index 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. .help = "enable/disable snapshot mode",
  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. "directsync, 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. .name = "iops",
  89. .type = QEMU_OPT_NUMBER,
  90. .help = "limit total I/O operations per second",
  91. },{
  92. .name = "iops_rd",
  93. .type = QEMU_OPT_NUMBER,
  94. .help = "limit read operations per second",
  95. },{
  96. .name = "iops_wr",
  97. .type = QEMU_OPT_NUMBER,
  98. .help = "limit write operations per second",
  99. },{
  100. .name = "bps",
  101. .type = QEMU_OPT_NUMBER,
  102. .help = "limit total bytes per second",
  103. },{
  104. .name = "bps_rd",
  105. .type = QEMU_OPT_NUMBER,
  106. .help = "limit read bytes per second",
  107. },{
  108. .name = "bps_wr",
  109. .type = QEMU_OPT_NUMBER,
  110. .help = "limit write bytes per second",
  111. },{
  112. .name = "copy-on-read",
  113. .type = QEMU_OPT_BOOL,
  114. .help = "copy read data from backing file into image file",
  115. },
  116. { /* end of list */ }
  117. },
  118. };
  119. static QemuOptsList qemu_iscsi_opts = {
  120. .name = "iscsi",
  121. .head = QTAILQ_HEAD_INITIALIZER(qemu_iscsi_opts.head),
  122. .desc = {
  123. {
  124. .name = "user",
  125. .type = QEMU_OPT_STRING,
  126. .help = "username for CHAP authentication to target",
  127. },{
  128. .name = "password",
  129. .type = QEMU_OPT_STRING,
  130. .help = "password for CHAP authentication to target",
  131. },{
  132. .name = "header-digest",
  133. .type = QEMU_OPT_STRING,
  134. .help = "HeaderDigest setting. "
  135. "{CRC32C|CRC32C-NONE|NONE-CRC32C|NONE}",
  136. },{
  137. .name = "initiator-name",
  138. .type = QEMU_OPT_STRING,
  139. .help = "Initiator iqn name to use when connecting",
  140. },
  141. { /* end of list */ }
  142. },
  143. };
  144. static QemuOptsList qemu_chardev_opts = {
  145. .name = "chardev",
  146. .implied_opt_name = "backend",
  147. .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
  148. .desc = {
  149. {
  150. .name = "backend",
  151. .type = QEMU_OPT_STRING,
  152. },{
  153. .name = "path",
  154. .type = QEMU_OPT_STRING,
  155. },{
  156. .name = "host",
  157. .type = QEMU_OPT_STRING,
  158. },{
  159. .name = "port",
  160. .type = QEMU_OPT_STRING,
  161. },{
  162. .name = "localaddr",
  163. .type = QEMU_OPT_STRING,
  164. },{
  165. .name = "localport",
  166. .type = QEMU_OPT_STRING,
  167. },{
  168. .name = "to",
  169. .type = QEMU_OPT_NUMBER,
  170. },{
  171. .name = "ipv4",
  172. .type = QEMU_OPT_BOOL,
  173. },{
  174. .name = "ipv6",
  175. .type = QEMU_OPT_BOOL,
  176. },{
  177. .name = "wait",
  178. .type = QEMU_OPT_BOOL,
  179. },{
  180. .name = "server",
  181. .type = QEMU_OPT_BOOL,
  182. },{
  183. .name = "delay",
  184. .type = QEMU_OPT_BOOL,
  185. },{
  186. .name = "telnet",
  187. .type = QEMU_OPT_BOOL,
  188. },{
  189. .name = "width",
  190. .type = QEMU_OPT_NUMBER,
  191. },{
  192. .name = "height",
  193. .type = QEMU_OPT_NUMBER,
  194. },{
  195. .name = "cols",
  196. .type = QEMU_OPT_NUMBER,
  197. },{
  198. .name = "rows",
  199. .type = QEMU_OPT_NUMBER,
  200. },{
  201. .name = "mux",
  202. .type = QEMU_OPT_BOOL,
  203. },{
  204. .name = "signal",
  205. .type = QEMU_OPT_BOOL,
  206. },{
  207. .name = "name",
  208. .type = QEMU_OPT_STRING,
  209. },{
  210. .name = "debug",
  211. .type = QEMU_OPT_NUMBER,
  212. },
  213. { /* end of list */ }
  214. },
  215. };
  216. QemuOptsList qemu_fsdev_opts = {
  217. .name = "fsdev",
  218. .implied_opt_name = "fsdriver",
  219. .head = QTAILQ_HEAD_INITIALIZER(qemu_fsdev_opts.head),
  220. .desc = {
  221. {
  222. .name = "fsdriver",
  223. .type = QEMU_OPT_STRING,
  224. }, {
  225. .name = "path",
  226. .type = QEMU_OPT_STRING,
  227. }, {
  228. .name = "security_model",
  229. .type = QEMU_OPT_STRING,
  230. }, {
  231. .name = "writeout",
  232. .type = QEMU_OPT_STRING,
  233. }, {
  234. .name = "readonly",
  235. .type = QEMU_OPT_BOOL,
  236. }, {
  237. .name = "socket",
  238. .type = QEMU_OPT_STRING,
  239. }, {
  240. .name = "sock_fd",
  241. .type = QEMU_OPT_NUMBER,
  242. },
  243. { /*End of list */ }
  244. },
  245. };
  246. QemuOptsList qemu_virtfs_opts = {
  247. .name = "virtfs",
  248. .implied_opt_name = "fsdriver",
  249. .head = QTAILQ_HEAD_INITIALIZER(qemu_virtfs_opts.head),
  250. .desc = {
  251. {
  252. .name = "fsdriver",
  253. .type = QEMU_OPT_STRING,
  254. }, {
  255. .name = "path",
  256. .type = QEMU_OPT_STRING,
  257. }, {
  258. .name = "mount_tag",
  259. .type = QEMU_OPT_STRING,
  260. }, {
  261. .name = "security_model",
  262. .type = QEMU_OPT_STRING,
  263. }, {
  264. .name = "writeout",
  265. .type = QEMU_OPT_STRING,
  266. }, {
  267. .name = "readonly",
  268. .type = QEMU_OPT_BOOL,
  269. }, {
  270. .name = "socket",
  271. .type = QEMU_OPT_STRING,
  272. }, {
  273. .name = "sock_fd",
  274. .type = QEMU_OPT_NUMBER,
  275. },
  276. { /*End of list */ }
  277. },
  278. };
  279. static QemuOptsList qemu_device_opts = {
  280. .name = "device",
  281. .implied_opt_name = "driver",
  282. .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
  283. .desc = {
  284. /*
  285. * no elements => accept any
  286. * sanity checking will happen later
  287. * when setting device properties
  288. */
  289. { /* end of list */ }
  290. },
  291. };
  292. static QemuOptsList qemu_netdev_opts = {
  293. .name = "netdev",
  294. .implied_opt_name = "type",
  295. .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
  296. .desc = {
  297. /*
  298. * no elements => accept any params
  299. * validation will happen later
  300. */
  301. { /* end of list */ }
  302. },
  303. };
  304. static QemuOptsList qemu_net_opts = {
  305. .name = "net",
  306. .implied_opt_name = "type",
  307. .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
  308. .desc = {
  309. /*
  310. * no elements => accept any params
  311. * validation will happen later
  312. */
  313. { /* end of list */ }
  314. },
  315. };
  316. static QemuOptsList qemu_rtc_opts = {
  317. .name = "rtc",
  318. .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
  319. .desc = {
  320. {
  321. .name = "base",
  322. .type = QEMU_OPT_STRING,
  323. },{
  324. .name = "clock",
  325. .type = QEMU_OPT_STRING,
  326. },{
  327. .name = "driftfix",
  328. .type = QEMU_OPT_STRING,
  329. },
  330. { /* end of list */ }
  331. },
  332. };
  333. static QemuOptsList qemu_global_opts = {
  334. .name = "global",
  335. .head = QTAILQ_HEAD_INITIALIZER(qemu_global_opts.head),
  336. .desc = {
  337. {
  338. .name = "driver",
  339. .type = QEMU_OPT_STRING,
  340. },{
  341. .name = "property",
  342. .type = QEMU_OPT_STRING,
  343. },{
  344. .name = "value",
  345. .type = QEMU_OPT_STRING,
  346. },
  347. { /* end of list */ }
  348. },
  349. };
  350. static QemuOptsList qemu_mon_opts = {
  351. .name = "mon",
  352. .implied_opt_name = "chardev",
  353. .head = QTAILQ_HEAD_INITIALIZER(qemu_mon_opts.head),
  354. .desc = {
  355. {
  356. .name = "mode",
  357. .type = QEMU_OPT_STRING,
  358. },{
  359. .name = "chardev",
  360. .type = QEMU_OPT_STRING,
  361. },{
  362. .name = "default",
  363. .type = QEMU_OPT_BOOL,
  364. },{
  365. .name = "pretty",
  366. .type = QEMU_OPT_BOOL,
  367. },
  368. { /* end of list */ }
  369. },
  370. };
  371. static QemuOptsList qemu_trace_opts = {
  372. .name = "trace",
  373. .implied_opt_name = "trace",
  374. .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
  375. .desc = {
  376. {
  377. .name = "events",
  378. .type = QEMU_OPT_STRING,
  379. },{
  380. .name = "file",
  381. .type = QEMU_OPT_STRING,
  382. },
  383. { /* end of list */ }
  384. },
  385. };
  386. static QemuOptsList qemu_cpudef_opts = {
  387. .name = "cpudef",
  388. .head = QTAILQ_HEAD_INITIALIZER(qemu_cpudef_opts.head),
  389. .desc = {
  390. {
  391. .name = "name",
  392. .type = QEMU_OPT_STRING,
  393. },{
  394. .name = "level",
  395. .type = QEMU_OPT_NUMBER,
  396. },{
  397. .name = "vendor",
  398. .type = QEMU_OPT_STRING,
  399. },{
  400. .name = "family",
  401. .type = QEMU_OPT_NUMBER,
  402. },{
  403. .name = "model",
  404. .type = QEMU_OPT_NUMBER,
  405. },{
  406. .name = "stepping",
  407. .type = QEMU_OPT_NUMBER,
  408. },{
  409. .name = "feature_edx", /* cpuid 0000_0001.edx */
  410. .type = QEMU_OPT_STRING,
  411. },{
  412. .name = "feature_ecx", /* cpuid 0000_0001.ecx */
  413. .type = QEMU_OPT_STRING,
  414. },{
  415. .name = "extfeature_edx", /* cpuid 8000_0001.edx */
  416. .type = QEMU_OPT_STRING,
  417. },{
  418. .name = "extfeature_ecx", /* cpuid 8000_0001.ecx */
  419. .type = QEMU_OPT_STRING,
  420. },{
  421. .name = "xlevel",
  422. .type = QEMU_OPT_NUMBER,
  423. },{
  424. .name = "model_id",
  425. .type = QEMU_OPT_STRING,
  426. },{
  427. .name = "vendor_override",
  428. .type = QEMU_OPT_NUMBER,
  429. },
  430. { /* end of list */ }
  431. },
  432. };
  433. QemuOptsList qemu_spice_opts = {
  434. .name = "spice",
  435. .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head),
  436. .desc = {
  437. {
  438. .name = "port",
  439. .type = QEMU_OPT_NUMBER,
  440. },{
  441. .name = "tls-port",
  442. .type = QEMU_OPT_NUMBER,
  443. },{
  444. .name = "addr",
  445. .type = QEMU_OPT_STRING,
  446. },{
  447. .name = "ipv4",
  448. .type = QEMU_OPT_BOOL,
  449. },{
  450. .name = "ipv6",
  451. .type = QEMU_OPT_BOOL,
  452. },{
  453. .name = "password",
  454. .type = QEMU_OPT_STRING,
  455. },{
  456. .name = "disable-ticketing",
  457. .type = QEMU_OPT_BOOL,
  458. },{
  459. .name = "disable-copy-paste",
  460. .type = QEMU_OPT_BOOL,
  461. },{
  462. .name = "sasl",
  463. .type = QEMU_OPT_BOOL,
  464. },{
  465. .name = "x509-dir",
  466. .type = QEMU_OPT_STRING,
  467. },{
  468. .name = "x509-key-file",
  469. .type = QEMU_OPT_STRING,
  470. },{
  471. .name = "x509-key-password",
  472. .type = QEMU_OPT_STRING,
  473. },{
  474. .name = "x509-cert-file",
  475. .type = QEMU_OPT_STRING,
  476. },{
  477. .name = "x509-cacert-file",
  478. .type = QEMU_OPT_STRING,
  479. },{
  480. .name = "x509-dh-key-file",
  481. .type = QEMU_OPT_STRING,
  482. },{
  483. .name = "tls-ciphers",
  484. .type = QEMU_OPT_STRING,
  485. },{
  486. .name = "tls-channel",
  487. .type = QEMU_OPT_STRING,
  488. },{
  489. .name = "plaintext-channel",
  490. .type = QEMU_OPT_STRING,
  491. },{
  492. .name = "image-compression",
  493. .type = QEMU_OPT_STRING,
  494. },{
  495. .name = "jpeg-wan-compression",
  496. .type = QEMU_OPT_STRING,
  497. },{
  498. .name = "zlib-glz-wan-compression",
  499. .type = QEMU_OPT_STRING,
  500. },{
  501. .name = "streaming-video",
  502. .type = QEMU_OPT_STRING,
  503. },{
  504. .name = "agent-mouse",
  505. .type = QEMU_OPT_BOOL,
  506. },{
  507. .name = "playback-compression",
  508. .type = QEMU_OPT_BOOL,
  509. },
  510. { /* end of list */ }
  511. },
  512. };
  513. QemuOptsList qemu_option_rom_opts = {
  514. .name = "option-rom",
  515. .implied_opt_name = "romfile",
  516. .head = QTAILQ_HEAD_INITIALIZER(qemu_option_rom_opts.head),
  517. .desc = {
  518. {
  519. .name = "bootindex",
  520. .type = QEMU_OPT_NUMBER,
  521. }, {
  522. .name = "romfile",
  523. .type = QEMU_OPT_STRING,
  524. },
  525. { /* end of list */ }
  526. },
  527. };
  528. static QemuOptsList qemu_machine_opts = {
  529. .name = "machine",
  530. .implied_opt_name = "type",
  531. .merge_lists = true,
  532. .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
  533. .desc = {
  534. {
  535. .name = "type",
  536. .type = QEMU_OPT_STRING,
  537. .help = "emulated machine"
  538. }, {
  539. .name = "accel",
  540. .type = QEMU_OPT_STRING,
  541. .help = "accelerator list",
  542. }, {
  543. .name = "kernel_irqchip",
  544. .type = QEMU_OPT_BOOL,
  545. .help = "use KVM in-kernel irqchip",
  546. }, {
  547. .name = "kvm_shadow_mem",
  548. .type = QEMU_OPT_SIZE,
  549. .help = "KVM shadow MMU size",
  550. }, {
  551. .name = "kernel",
  552. .type = QEMU_OPT_STRING,
  553. .help = "Linux kernel image file",
  554. }, {
  555. .name = "initrd",
  556. .type = QEMU_OPT_STRING,
  557. .help = "Linux initial ramdisk file",
  558. }, {
  559. .name = "append",
  560. .type = QEMU_OPT_STRING,
  561. .help = "Linux kernel command line",
  562. }, {
  563. .name = "dtb",
  564. .type = QEMU_OPT_STRING,
  565. .help = "Linux kernel device tree file",
  566. },
  567. { /* End of list */ }
  568. },
  569. };
  570. QemuOptsList qemu_boot_opts = {
  571. .name = "boot-opts",
  572. .head = QTAILQ_HEAD_INITIALIZER(qemu_boot_opts.head),
  573. .desc = {
  574. /* the three names below are not used now */
  575. {
  576. .name = "order",
  577. .type = QEMU_OPT_STRING,
  578. }, {
  579. .name = "once",
  580. .type = QEMU_OPT_STRING,
  581. }, {
  582. .name = "menu",
  583. .type = QEMU_OPT_STRING,
  584. /* following are really used */
  585. }, {
  586. .name = "splash",
  587. .type = QEMU_OPT_STRING,
  588. }, {
  589. .name = "splash-time",
  590. .type = QEMU_OPT_STRING,
  591. },
  592. { /*End of list */ }
  593. },
  594. };
  595. static QemuOptsList *vm_config_groups[32] = {
  596. &qemu_drive_opts,
  597. &qemu_chardev_opts,
  598. &qemu_device_opts,
  599. &qemu_netdev_opts,
  600. &qemu_net_opts,
  601. &qemu_rtc_opts,
  602. &qemu_global_opts,
  603. &qemu_mon_opts,
  604. &qemu_cpudef_opts,
  605. &qemu_trace_opts,
  606. &qemu_option_rom_opts,
  607. &qemu_machine_opts,
  608. &qemu_boot_opts,
  609. &qemu_iscsi_opts,
  610. NULL,
  611. };
  612. static QemuOptsList *find_list(QemuOptsList **lists, const char *group)
  613. {
  614. int i;
  615. for (i = 0; lists[i] != NULL; i++) {
  616. if (strcmp(lists[i]->name, group) == 0)
  617. break;
  618. }
  619. if (lists[i] == NULL) {
  620. error_report("there is no option group \"%s\"", group);
  621. }
  622. return lists[i];
  623. }
  624. QemuOptsList *qemu_find_opts(const char *group)
  625. {
  626. return find_list(vm_config_groups, group);
  627. }
  628. void qemu_add_opts(QemuOptsList *list)
  629. {
  630. int entries, i;
  631. entries = ARRAY_SIZE(vm_config_groups);
  632. entries--; /* keep list NULL terminated */
  633. for (i = 0; i < entries; i++) {
  634. if (vm_config_groups[i] == NULL) {
  635. vm_config_groups[i] = list;
  636. return;
  637. }
  638. }
  639. fprintf(stderr, "ran out of space in vm_config_groups");
  640. abort();
  641. }
  642. int qemu_set_option(const char *str)
  643. {
  644. char group[64], id[64], arg[64];
  645. QemuOptsList *list;
  646. QemuOpts *opts;
  647. int rc, offset;
  648. rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
  649. if (rc < 3 || str[offset] != '=') {
  650. error_report("can't parse: \"%s\"", str);
  651. return -1;
  652. }
  653. list = qemu_find_opts(group);
  654. if (list == NULL) {
  655. return -1;
  656. }
  657. opts = qemu_opts_find(list, id);
  658. if (!opts) {
  659. error_report("there is no %s \"%s\" defined",
  660. list->name, id);
  661. return -1;
  662. }
  663. if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
  664. return -1;
  665. }
  666. return 0;
  667. }
  668. int qemu_global_option(const char *str)
  669. {
  670. char driver[64], property[64];
  671. QemuOpts *opts;
  672. int rc, offset;
  673. rc = sscanf(str, "%63[^.].%63[^=]%n", driver, property, &offset);
  674. if (rc < 2 || str[offset] != '=') {
  675. error_report("can't parse: \"%s\"", str);
  676. return -1;
  677. }
  678. opts = qemu_opts_create(&qemu_global_opts, NULL, 0);
  679. qemu_opt_set(opts, "driver", driver);
  680. qemu_opt_set(opts, "property", property);
  681. qemu_opt_set(opts, "value", str+offset+1);
  682. return 0;
  683. }
  684. struct ConfigWriteData {
  685. QemuOptsList *list;
  686. FILE *fp;
  687. };
  688. static int config_write_opt(const char *name, const char *value, void *opaque)
  689. {
  690. struct ConfigWriteData *data = opaque;
  691. fprintf(data->fp, " %s = \"%s\"\n", name, value);
  692. return 0;
  693. }
  694. static int config_write_opts(QemuOpts *opts, void *opaque)
  695. {
  696. struct ConfigWriteData *data = opaque;
  697. const char *id = qemu_opts_id(opts);
  698. if (id) {
  699. fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
  700. } else {
  701. fprintf(data->fp, "[%s]\n", data->list->name);
  702. }
  703. qemu_opt_foreach(opts, config_write_opt, data, 0);
  704. fprintf(data->fp, "\n");
  705. return 0;
  706. }
  707. void qemu_config_write(FILE *fp)
  708. {
  709. struct ConfigWriteData data = { .fp = fp };
  710. QemuOptsList **lists = vm_config_groups;
  711. int i;
  712. fprintf(fp, "# qemu config file\n\n");
  713. for (i = 0; lists[i] != NULL; i++) {
  714. data.list = lists[i];
  715. qemu_opts_foreach(data.list, config_write_opts, &data, 0);
  716. }
  717. }
  718. int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
  719. {
  720. char line[1024], group[64], id[64], arg[64], value[1024];
  721. Location loc;
  722. QemuOptsList *list = NULL;
  723. QemuOpts *opts = NULL;
  724. int res = -1, lno = 0;
  725. loc_push_none(&loc);
  726. while (fgets(line, sizeof(line), fp) != NULL) {
  727. loc_set_file(fname, ++lno);
  728. if (line[0] == '\n') {
  729. /* skip empty lines */
  730. continue;
  731. }
  732. if (line[0] == '#') {
  733. /* comment */
  734. continue;
  735. }
  736. if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
  737. /* group with id */
  738. list = find_list(lists, group);
  739. if (list == NULL)
  740. goto out;
  741. opts = qemu_opts_create(list, id, 1);
  742. continue;
  743. }
  744. if (sscanf(line, "[%63[^]]]", group) == 1) {
  745. /* group without id */
  746. list = find_list(lists, group);
  747. if (list == NULL)
  748. goto out;
  749. opts = qemu_opts_create(list, NULL, 0);
  750. continue;
  751. }
  752. if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
  753. /* arg = value */
  754. if (opts == NULL) {
  755. error_report("no group defined");
  756. goto out;
  757. }
  758. if (qemu_opt_set(opts, arg, value) != 0) {
  759. goto out;
  760. }
  761. continue;
  762. }
  763. error_report("parse error");
  764. goto out;
  765. }
  766. if (ferror(fp)) {
  767. error_report("error reading file");
  768. goto out;
  769. }
  770. res = 0;
  771. out:
  772. loc_pop(&loc);
  773. return res;
  774. }
  775. int qemu_read_config_file(const char *filename)
  776. {
  777. FILE *f = fopen(filename, "r");
  778. int ret;
  779. if (f == NULL) {
  780. return -errno;
  781. }
  782. ret = qemu_config_parse(f, vm_config_groups, filename);
  783. fclose(f);
  784. if (ret == 0) {
  785. return 0;
  786. } else {
  787. return -EINVAL;
  788. }
  789. }