qemu-config.c 23 KB

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