qemu-config.c 18 KB

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