1aafd7584SPeter Maydell #include "qemu/osdep.h" 2609f45eaSMax Reitz #include "block/qdict.h" /* for qdict_extract_subqdict() */ 3e688df6bSMarkus Armbruster #include "qapi/error.h" 4112ed241SMarkus Armbruster #include "qapi/qapi-commands-misc.h" 537701411SPaolo Bonzini #include "qapi/qmp/qerror.h" 6452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 747e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h" 81de7afc9SPaolo Bonzini #include "qemu/error-report.h" 91de7afc9SPaolo Bonzini #include "qemu/option.h" 101de7afc9SPaolo Bonzini #include "qemu/config-file.h" 117282a033SGerd Hoffmann 121ceaefbdSGerd Hoffmann static QemuOptsList *vm_config_groups[48]; 13c5f3014bSKevin Wolf static QemuOptsList *drive_config_groups[5]; 14d058fe03SGerd Hoffmann 152ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group, 162ac20613SLuiz Capitulino Error **errp) 17d058fe03SGerd Hoffmann { 18ddc97855SGerd Hoffmann int i; 19d058fe03SGerd Hoffmann 20632a8873SPaolo Bonzini qemu_load_module_for_opts(group); 21d058fe03SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) { 22d058fe03SGerd Hoffmann if (strcmp(lists[i]->name, group) == 0) 23d058fe03SGerd Hoffmann break; 24d058fe03SGerd Hoffmann } 25d058fe03SGerd Hoffmann if (lists[i] == NULL) { 26f231b88dSCole Robinson error_setg(errp, "There is no option group '%s'", group); 27ddc97855SGerd Hoffmann } 28ddc97855SGerd Hoffmann return lists[i]; 29ddc97855SGerd Hoffmann } 30ddc97855SGerd Hoffmann 31490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group) 32490b648eSKevin Wolf { 332ac20613SLuiz Capitulino QemuOptsList *ret; 342ac20613SLuiz Capitulino Error *local_err = NULL; 352ac20613SLuiz Capitulino 362ac20613SLuiz Capitulino ret = find_list(vm_config_groups, group, &local_err); 3784d18f06SMarkus Armbruster if (local_err) { 38565f65d2SMarkus Armbruster error_report_err(local_err); 392ac20613SLuiz Capitulino } 402ac20613SLuiz Capitulino 412ac20613SLuiz Capitulino return ret; 42490b648eSKevin Wolf } 43490b648eSKevin Wolf 44e96e5ae8SPaolo Bonzini QemuOpts *qemu_find_opts_singleton(const char *group) 45e96e5ae8SPaolo Bonzini { 46e96e5ae8SPaolo Bonzini QemuOptsList *list; 47e96e5ae8SPaolo Bonzini QemuOpts *opts; 48e96e5ae8SPaolo Bonzini 49e96e5ae8SPaolo Bonzini list = qemu_find_opts(group); 50e96e5ae8SPaolo Bonzini assert(list); 51e96e5ae8SPaolo Bonzini opts = qemu_opts_find(list, NULL); 52e96e5ae8SPaolo Bonzini if (!opts) { 53e96e5ae8SPaolo Bonzini opts = qemu_opts_create(list, NULL, 0, &error_abort); 54e96e5ae8SPaolo Bonzini } 55e96e5ae8SPaolo Bonzini return opts; 56e96e5ae8SPaolo Bonzini } 57e96e5ae8SPaolo Bonzini 581f8f987dSAmos Kong static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc) 591f8f987dSAmos Kong { 6054aa3de7SEric Blake CommandLineParameterInfoList *param_list = NULL; 611f8f987dSAmos Kong CommandLineParameterInfo *info; 621f8f987dSAmos Kong int i; 631f8f987dSAmos Kong 641f8f987dSAmos Kong for (i = 0; desc[i].name != NULL; i++) { 651f8f987dSAmos Kong info = g_malloc0(sizeof(*info)); 661f8f987dSAmos Kong info->name = g_strdup(desc[i].name); 671f8f987dSAmos Kong 681f8f987dSAmos Kong switch (desc[i].type) { 691f8f987dSAmos Kong case QEMU_OPT_STRING: 701f8f987dSAmos Kong info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; 711f8f987dSAmos Kong break; 721f8f987dSAmos Kong case QEMU_OPT_BOOL: 731f8f987dSAmos Kong info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN; 741f8f987dSAmos Kong break; 751f8f987dSAmos Kong case QEMU_OPT_NUMBER: 761f8f987dSAmos Kong info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER; 771f8f987dSAmos Kong break; 781f8f987dSAmos Kong case QEMU_OPT_SIZE: 791f8f987dSAmos Kong info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE; 801f8f987dSAmos Kong break; 811f8f987dSAmos Kong } 821f8f987dSAmos Kong 831f8f987dSAmos Kong if (desc[i].help) { 841f8f987dSAmos Kong info->has_help = true; 851f8f987dSAmos Kong info->help = g_strdup(desc[i].help); 861f8f987dSAmos Kong } 87e36af94fSChunyan Liu if (desc[i].def_value_str) { 88e36af94fSChunyan Liu info->has_q_default = true; 89e36af94fSChunyan Liu info->q_default = g_strdup(desc[i].def_value_str); 90e36af94fSChunyan Liu } 911f8f987dSAmos Kong 9254aa3de7SEric Blake QAPI_LIST_PREPEND(param_list, info); 931f8f987dSAmos Kong } 941f8f987dSAmos Kong 951f8f987dSAmos Kong return param_list; 961f8f987dSAmos Kong } 971f8f987dSAmos Kong 98968854c8SAmos Kong /* remove repeated entry from the info list */ 99968854c8SAmos Kong static void cleanup_infolist(CommandLineParameterInfoList *head) 100968854c8SAmos Kong { 101968854c8SAmos Kong CommandLineParameterInfoList *pre_entry, *cur, *del_entry; 102968854c8SAmos Kong 103968854c8SAmos Kong cur = head; 104968854c8SAmos Kong while (cur->next) { 105968854c8SAmos Kong pre_entry = head; 106968854c8SAmos Kong while (pre_entry != cur->next) { 107968854c8SAmos Kong if (!strcmp(pre_entry->value->name, cur->next->value->name)) { 108968854c8SAmos Kong del_entry = cur->next; 109968854c8SAmos Kong cur->next = cur->next->next; 110b11e20fbSMarc-André Lureau del_entry->next = NULL; 111b11e20fbSMarc-André Lureau qapi_free_CommandLineParameterInfoList(del_entry); 112968854c8SAmos Kong break; 113968854c8SAmos Kong } 114968854c8SAmos Kong pre_entry = pre_entry->next; 115968854c8SAmos Kong } 116968854c8SAmos Kong cur = cur->next; 117968854c8SAmos Kong } 118968854c8SAmos Kong } 119968854c8SAmos Kong 120968854c8SAmos Kong /* merge the description items of two parameter infolists */ 121968854c8SAmos Kong static void connect_infolist(CommandLineParameterInfoList *head, 122968854c8SAmos Kong CommandLineParameterInfoList *new) 123968854c8SAmos Kong { 124968854c8SAmos Kong CommandLineParameterInfoList *cur; 125968854c8SAmos Kong 126968854c8SAmos Kong cur = head; 127968854c8SAmos Kong while (cur->next) { 128968854c8SAmos Kong cur = cur->next; 129968854c8SAmos Kong } 130968854c8SAmos Kong cur->next = new; 131968854c8SAmos Kong } 132968854c8SAmos Kong 133968854c8SAmos Kong /* access all the local QemuOptsLists for drive option */ 134968854c8SAmos Kong static CommandLineParameterInfoList *get_drive_infolist(void) 135968854c8SAmos Kong { 136968854c8SAmos Kong CommandLineParameterInfoList *head = NULL, *cur; 137968854c8SAmos Kong int i; 138968854c8SAmos Kong 139968854c8SAmos Kong for (i = 0; drive_config_groups[i] != NULL; i++) { 140968854c8SAmos Kong if (!head) { 141968854c8SAmos Kong head = query_option_descs(drive_config_groups[i]->desc); 142968854c8SAmos Kong } else { 143968854c8SAmos Kong cur = query_option_descs(drive_config_groups[i]->desc); 144968854c8SAmos Kong connect_infolist(head, cur); 145968854c8SAmos Kong } 146968854c8SAmos Kong } 147968854c8SAmos Kong cleanup_infolist(head); 148968854c8SAmos Kong 149968854c8SAmos Kong return head; 150968854c8SAmos Kong } 151968854c8SAmos Kong 1520a7cf217SMarcel Apfelbaum /* restore machine options that are now machine's properties */ 1530a7cf217SMarcel Apfelbaum static QemuOptsList machine_opts = { 1540a7cf217SMarcel Apfelbaum .merge_lists = true, 1550a7cf217SMarcel Apfelbaum .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head), 1560a7cf217SMarcel Apfelbaum .desc = { 1570a7cf217SMarcel Apfelbaum { 1580a7cf217SMarcel Apfelbaum .name = "type", 1590a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1600a7cf217SMarcel Apfelbaum .help = "emulated machine" 1610a7cf217SMarcel Apfelbaum },{ 1620a7cf217SMarcel Apfelbaum .name = "accel", 1630a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1640a7cf217SMarcel Apfelbaum .help = "accelerator list", 1650a7cf217SMarcel Apfelbaum },{ 1660a7cf217SMarcel Apfelbaum .name = "kernel_irqchip", 1670a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 1680a7cf217SMarcel Apfelbaum .help = "use KVM in-kernel irqchip", 1690a7cf217SMarcel Apfelbaum },{ 1700a7cf217SMarcel Apfelbaum .name = "kvm_shadow_mem", 1710a7cf217SMarcel Apfelbaum .type = QEMU_OPT_SIZE, 1720a7cf217SMarcel Apfelbaum .help = "KVM shadow MMU size", 1730a7cf217SMarcel Apfelbaum },{ 1740a7cf217SMarcel Apfelbaum .name = "kernel", 1750a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1760a7cf217SMarcel Apfelbaum .help = "Linux kernel image file", 1770a7cf217SMarcel Apfelbaum },{ 1780a7cf217SMarcel Apfelbaum .name = "initrd", 1790a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1800a7cf217SMarcel Apfelbaum .help = "Linux initial ramdisk file", 1810a7cf217SMarcel Apfelbaum },{ 1820a7cf217SMarcel Apfelbaum .name = "append", 1830a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1840a7cf217SMarcel Apfelbaum .help = "Linux kernel command line", 1850a7cf217SMarcel Apfelbaum },{ 1860a7cf217SMarcel Apfelbaum .name = "dtb", 1870a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1880a7cf217SMarcel Apfelbaum .help = "Linux kernel device tree file", 1890a7cf217SMarcel Apfelbaum },{ 1900a7cf217SMarcel Apfelbaum .name = "dumpdtb", 1910a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1920a7cf217SMarcel Apfelbaum .help = "Dump current dtb to a file and quit", 1930a7cf217SMarcel Apfelbaum },{ 1940a7cf217SMarcel Apfelbaum .name = "phandle_start", 1950a7cf217SMarcel Apfelbaum .type = QEMU_OPT_NUMBER, 1960a7cf217SMarcel Apfelbaum .help = "The first phandle ID we may generate dynamically", 1970a7cf217SMarcel Apfelbaum },{ 1980a7cf217SMarcel Apfelbaum .name = "dt_compatible", 1990a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 2000a7cf217SMarcel Apfelbaum .help = "Overrides the \"compatible\" property of the dt root node", 2010a7cf217SMarcel Apfelbaum },{ 2020a7cf217SMarcel Apfelbaum .name = "dump-guest-core", 2030a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2040a7cf217SMarcel Apfelbaum .help = "Include guest memory in a core dump", 2050a7cf217SMarcel Apfelbaum },{ 2060a7cf217SMarcel Apfelbaum .name = "mem-merge", 2070a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2080a7cf217SMarcel Apfelbaum .help = "enable/disable memory merge support", 2090a7cf217SMarcel Apfelbaum },{ 2100a7cf217SMarcel Apfelbaum .name = "usb", 2110a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2120a7cf217SMarcel Apfelbaum .help = "Set on/off to enable/disable usb", 2130a7cf217SMarcel Apfelbaum },{ 2140a7cf217SMarcel Apfelbaum .name = "firmware", 2150a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 2160a7cf217SMarcel Apfelbaum .help = "firmware image", 2170a7cf217SMarcel Apfelbaum },{ 2180a7cf217SMarcel Apfelbaum .name = "iommu", 2190a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2200a7cf217SMarcel Apfelbaum .help = "Set on/off to enable/disable Intel IOMMU (VT-d)", 2210a7cf217SMarcel Apfelbaum },{ 2220a7cf217SMarcel Apfelbaum .name = "suppress-vmdesc", 2230a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2240a7cf217SMarcel Apfelbaum .help = "Set on to disable self-describing migration", 2255bcfa0c5STony Krowiak },{ 2265bcfa0c5STony Krowiak .name = "aes-key-wrap", 2275bcfa0c5STony Krowiak .type = QEMU_OPT_BOOL, 2285bcfa0c5STony Krowiak .help = "enable/disable AES key wrapping using the CPACF wrapping key", 2295bcfa0c5STony Krowiak },{ 2305bcfa0c5STony Krowiak .name = "dea-key-wrap", 2315bcfa0c5STony Krowiak .type = QEMU_OPT_BOOL, 2325bcfa0c5STony Krowiak .help = "enable/disable DEA key wrapping using the CPACF wrapping key", 2335559716cSFarhan Ali },{ 2345559716cSFarhan Ali .name = "loadparm", 2355559716cSFarhan Ali .type = QEMU_OPT_STRING, 2365559716cSFarhan Ali .help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars" 2375559716cSFarhan Ali " converted to upper case) to pass to machine" 2385559716cSFarhan Ali " loader, boot manager, and guest kernel", 2390a7cf217SMarcel Apfelbaum }, 2400a7cf217SMarcel Apfelbaum { /* End of list */ } 2410a7cf217SMarcel Apfelbaum } 2420a7cf217SMarcel Apfelbaum }; 2430a7cf217SMarcel Apfelbaum 2441f8f987dSAmos Kong CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, 2451f8f987dSAmos Kong const char *option, 2461f8f987dSAmos Kong Error **errp) 2471f8f987dSAmos Kong { 24854aa3de7SEric Blake CommandLineOptionInfoList *conf_list = NULL; 2491f8f987dSAmos Kong CommandLineOptionInfo *info; 2501f8f987dSAmos Kong int i; 2511f8f987dSAmos Kong 2521f8f987dSAmos Kong for (i = 0; vm_config_groups[i] != NULL; i++) { 2531f8f987dSAmos Kong if (!has_option || !strcmp(option, vm_config_groups[i]->name)) { 2541f8f987dSAmos Kong info = g_malloc0(sizeof(*info)); 2551f8f987dSAmos Kong info->option = g_strdup(vm_config_groups[i]->name); 256968854c8SAmos Kong if (!strcmp("drive", vm_config_groups[i]->name)) { 257968854c8SAmos Kong info->parameters = get_drive_infolist(); 258968854c8SAmos Kong } else { 259968854c8SAmos Kong info->parameters = 260968854c8SAmos Kong query_option_descs(vm_config_groups[i]->desc); 261968854c8SAmos Kong } 26254aa3de7SEric Blake QAPI_LIST_PREPEND(conf_list, info); 2631f8f987dSAmos Kong } 2641f8f987dSAmos Kong } 2651f8f987dSAmos Kong 26640e07370SStefan Hajnoczi if (!has_option || !strcmp(option, "machine")) { 26740e07370SStefan Hajnoczi info = g_malloc0(sizeof(*info)); 26840e07370SStefan Hajnoczi info->option = g_strdup("machine"); 26940e07370SStefan Hajnoczi info->parameters = query_option_descs(machine_opts.desc); 27040e07370SStefan Hajnoczi QAPI_LIST_PREPEND(conf_list, info); 27140e07370SStefan Hajnoczi } 27240e07370SStefan Hajnoczi 2731f8f987dSAmos Kong if (conf_list == NULL) { 2741f8f987dSAmos Kong error_setg(errp, "invalid option name: %s", option); 2751f8f987dSAmos Kong } 2761f8f987dSAmos Kong 2771f8f987dSAmos Kong return conf_list; 2781f8f987dSAmos Kong } 2791f8f987dSAmos Kong 28060d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) 28160d5666fSLuiz Capitulino { 28260d5666fSLuiz Capitulino return find_list(vm_config_groups, group, errp); 28360d5666fSLuiz Capitulino } 28460d5666fSLuiz Capitulino 285968854c8SAmos Kong void qemu_add_drive_opts(QemuOptsList *list) 286968854c8SAmos Kong { 287968854c8SAmos Kong int entries, i; 288968854c8SAmos Kong 289968854c8SAmos Kong entries = ARRAY_SIZE(drive_config_groups); 290968854c8SAmos Kong entries--; /* keep list NULL terminated */ 291968854c8SAmos Kong for (i = 0; i < entries; i++) { 292968854c8SAmos Kong if (drive_config_groups[i] == NULL) { 293968854c8SAmos Kong drive_config_groups[i] = list; 294968854c8SAmos Kong return; 295968854c8SAmos Kong } 296968854c8SAmos Kong } 297968854c8SAmos Kong fprintf(stderr, "ran out of space in drive_config_groups"); 298968854c8SAmos Kong abort(); 299968854c8SAmos Kong } 300968854c8SAmos Kong 301dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list) 302dfe795e7SGerd Hoffmann { 303dfe795e7SGerd Hoffmann int entries, i; 304dfe795e7SGerd Hoffmann 305dfe795e7SGerd Hoffmann entries = ARRAY_SIZE(vm_config_groups); 306dfe795e7SGerd Hoffmann entries--; /* keep list NULL terminated */ 307dfe795e7SGerd Hoffmann for (i = 0; i < entries; i++) { 308dfe795e7SGerd Hoffmann if (vm_config_groups[i] == NULL) { 309dfe795e7SGerd Hoffmann vm_config_groups[i] = list; 310dfe795e7SGerd Hoffmann return; 311dfe795e7SGerd Hoffmann } 312dfe795e7SGerd Hoffmann } 313dfe795e7SGerd Hoffmann fprintf(stderr, "ran out of space in vm_config_groups"); 314dfe795e7SGerd Hoffmann abort(); 315dfe795e7SGerd Hoffmann } 316dfe795e7SGerd Hoffmann 317e5766d6eSEduardo Habkost /* Returns number of config groups on success, -errno on error */ 31837701411SPaolo Bonzini static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, 31937701411SPaolo Bonzini const char *fname, Error **errp) 32042262ba8SGerd Hoffmann { 321*0a3090b1SMarkus Armbruster ERRP_GUARD(); 32237701411SPaolo Bonzini char line[1024], prev_group[64], group[64], arg[64], value[1024]; 323cf5a65aaSMarkus Armbruster Location loc; 32437701411SPaolo Bonzini QDict *qdict = NULL; 325e5766d6eSEduardo Habkost int res = -EINVAL, lno = 0; 326e5766d6eSEduardo Habkost int count = 0; 32742262ba8SGerd Hoffmann 328cf5a65aaSMarkus Armbruster loc_push_none(&loc); 32942262ba8SGerd Hoffmann while (fgets(line, sizeof(line), fp) != NULL) { 33037701411SPaolo Bonzini ++lno; 33142262ba8SGerd Hoffmann if (line[0] == '\n') { 33242262ba8SGerd Hoffmann /* skip empty lines */ 33342262ba8SGerd Hoffmann continue; 33442262ba8SGerd Hoffmann } 33542262ba8SGerd Hoffmann if (line[0] == '#') { 33642262ba8SGerd Hoffmann /* comment */ 33742262ba8SGerd Hoffmann continue; 33842262ba8SGerd Hoffmann } 33937701411SPaolo Bonzini if (line[0] == '[') { 34037701411SPaolo Bonzini QDict *prev = qdict; 34137701411SPaolo Bonzini if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) { 34237701411SPaolo Bonzini qdict = qdict_new(); 34337701411SPaolo Bonzini qdict_put_str(qdict, "id", value); 34437701411SPaolo Bonzini count++; 34537701411SPaolo Bonzini } else if (sscanf(line, "[%63[^]]]", group) == 1) { 34637701411SPaolo Bonzini qdict = qdict_new(); 34737701411SPaolo Bonzini count++; 34837701411SPaolo Bonzini } 34937701411SPaolo Bonzini if (qdict != prev) { 35037701411SPaolo Bonzini if (prev) { 351*0a3090b1SMarkus Armbruster cb(prev_group, prev, opaque, errp); 35237701411SPaolo Bonzini qobject_unref(prev); 353*0a3090b1SMarkus Armbruster if (*errp) { 354cf5a65aaSMarkus Armbruster goto out; 3552ac20613SLuiz Capitulino } 35637701411SPaolo Bonzini } 35737701411SPaolo Bonzini strcpy(prev_group, group); 35842262ba8SGerd Hoffmann continue; 35942262ba8SGerd Hoffmann } 3602ac20613SLuiz Capitulino } 36137701411SPaolo Bonzini loc_set_file(fname, lno); 362d9f7e29eSEduardo Habkost value[0] = '\0'; 363d9f7e29eSEduardo Habkost if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 || 364d9f7e29eSEduardo Habkost sscanf(line, " %63s = \"\"", arg) == 1) { 36542262ba8SGerd Hoffmann /* arg = value */ 36637701411SPaolo Bonzini if (qdict == NULL) { 367f7544edcSPaolo Bonzini error_setg(errp, "no group defined"); 368cf5a65aaSMarkus Armbruster goto out; 36942262ba8SGerd Hoffmann } 37037701411SPaolo Bonzini qdict_put_str(qdict, arg, value); 37142262ba8SGerd Hoffmann continue; 37242262ba8SGerd Hoffmann } 373f7544edcSPaolo Bonzini error_setg(errp, "parse error"); 374cf5a65aaSMarkus Armbruster goto out; 37542262ba8SGerd Hoffmann } 376ef82516dSMarkus Armbruster if (ferror(fp)) { 377f7544edcSPaolo Bonzini loc_pop(&loc); 378f7544edcSPaolo Bonzini error_setg_errno(errp, errno, "Cannot read config file"); 379461fea9bSPaolo Bonzini goto out_no_loc; 380ef82516dSMarkus Armbruster } 381e5766d6eSEduardo Habkost res = count; 38237701411SPaolo Bonzini if (qdict) { 38337701411SPaolo Bonzini cb(group, qdict, opaque, errp); 38437701411SPaolo Bonzini } 385e72f9524SPaolo Bonzini out: 386cf5a65aaSMarkus Armbruster loc_pop(&loc); 387461fea9bSPaolo Bonzini out_no_loc: 388e72f9524SPaolo Bonzini qobject_unref(qdict); 389cf5a65aaSMarkus Armbruster return res; 39042262ba8SGerd Hoffmann } 391dcfb0939SKevin Wolf 39237701411SPaolo Bonzini void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp) 39337701411SPaolo Bonzini { 39437701411SPaolo Bonzini QemuOptsList **lists = opaque; 39537701411SPaolo Bonzini QemuOptsList *list; 39637701411SPaolo Bonzini 39737701411SPaolo Bonzini list = find_list(lists, group, errp); 39837701411SPaolo Bonzini if (!list) { 39937701411SPaolo Bonzini return; 40037701411SPaolo Bonzini } 40137701411SPaolo Bonzini 402e7d85d95SPaolo Bonzini qemu_opts_from_qdict(list, qdict, errp); 40337701411SPaolo Bonzini } 40437701411SPaolo Bonzini 40537701411SPaolo Bonzini int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp) 40637701411SPaolo Bonzini { 40737701411SPaolo Bonzini return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp); 40837701411SPaolo Bonzini } 40937701411SPaolo Bonzini 41037701411SPaolo Bonzini int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp) 411dcfb0939SKevin Wolf { 412dcfb0939SKevin Wolf FILE *f = fopen(filename, "r"); 413019e78baSKevin Wolf int ret; 414019e78baSKevin Wolf 415dcfb0939SKevin Wolf if (f == NULL) { 416f7544edcSPaolo Bonzini error_setg_file_open(errp, errno, filename); 417dcfb0939SKevin Wolf return -errno; 418dcfb0939SKevin Wolf } 419dcfb0939SKevin Wolf 42037701411SPaolo Bonzini ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp); 421dcfb0939SKevin Wolf fclose(f); 422e5766d6eSEduardo Habkost return ret; 423dcfb0939SKevin Wolf } 424adf5c449SMax Reitz 425f766e6dcSMarkus Armbruster static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts, 426adf5c449SMax Reitz Error **errp) 427adf5c449SMax Reitz { 428adf5c449SMax Reitz QemuOpts *subopts; 429f766e6dcSMarkus Armbruster g_autoptr(QDict) subqdict = NULL; 430f766e6dcSMarkus Armbruster g_autoptr(QList) list = NULL; 431adf5c449SMax Reitz size_t orig_size, enum_size; 432adf5c449SMax Reitz char *prefix; 433adf5c449SMax Reitz 434adf5c449SMax Reitz prefix = g_strdup_printf("%s.", opts->name); 435adf5c449SMax Reitz qdict_extract_subqdict(options, &subqdict, prefix); 436adf5c449SMax Reitz g_free(prefix); 437adf5c449SMax Reitz orig_size = qdict_size(subqdict); 438adf5c449SMax Reitz if (!orig_size) { 439f766e6dcSMarkus Armbruster return true; 440adf5c449SMax Reitz } 441adf5c449SMax Reitz 442c6ecec43SMarkus Armbruster subopts = qemu_opts_create(opts, NULL, 0, errp); 443c6ecec43SMarkus Armbruster if (!subopts) { 444f766e6dcSMarkus Armbruster return false; 445adf5c449SMax Reitz } 446adf5c449SMax Reitz 447668f62ecSMarkus Armbruster if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) { 448f766e6dcSMarkus Armbruster return false; 449adf5c449SMax Reitz } 450adf5c449SMax Reitz 451adf5c449SMax Reitz enum_size = qdict_size(subqdict); 452adf5c449SMax Reitz if (enum_size < orig_size && enum_size) { 453adf5c449SMax Reitz error_setg(errp, "Unknown option '%s' for [%s]", 454adf5c449SMax Reitz qdict_first(subqdict)->key, opts->name); 455f766e6dcSMarkus Armbruster return false; 456adf5c449SMax Reitz } 457adf5c449SMax Reitz 458adf5c449SMax Reitz if (enum_size) { 459adf5c449SMax Reitz /* Multiple, enumerated sections */ 460adf5c449SMax Reitz QListEntry *list_entry; 461adf5c449SMax Reitz unsigned i = 0; 462adf5c449SMax Reitz 463adf5c449SMax Reitz /* Not required anymore */ 464adf5c449SMax Reitz qemu_opts_del(subopts); 465adf5c449SMax Reitz 466adf5c449SMax Reitz qdict_array_split(subqdict, &list); 467adf5c449SMax Reitz if (qdict_size(subqdict)) { 468adf5c449SMax Reitz error_setg(errp, "Unused option '%s' for [%s]", 469adf5c449SMax Reitz qdict_first(subqdict)->key, opts->name); 470f766e6dcSMarkus Armbruster return false; 471adf5c449SMax Reitz } 472adf5c449SMax Reitz 473adf5c449SMax Reitz QLIST_FOREACH_ENTRY(list, list_entry) { 4747dc847ebSMax Reitz QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry)); 475adf5c449SMax Reitz char *opt_name; 476adf5c449SMax Reitz 477ae39c4b2SMax Reitz if (!section) { 478ae39c4b2SMax Reitz error_setg(errp, "[%s] section (index %u) does not consist of " 479ae39c4b2SMax Reitz "keys", opts->name, i); 480f766e6dcSMarkus Armbruster return false; 481ae39c4b2SMax Reitz } 482ae39c4b2SMax Reitz 483adf5c449SMax Reitz opt_name = g_strdup_printf("%s.%u", opts->name, i++); 484c6ecec43SMarkus Armbruster subopts = qemu_opts_create(opts, opt_name, 1, errp); 485adf5c449SMax Reitz g_free(opt_name); 486c6ecec43SMarkus Armbruster if (!subopts) { 487f766e6dcSMarkus Armbruster return false; 488adf5c449SMax Reitz } 489adf5c449SMax Reitz 490668f62ecSMarkus Armbruster if (!qemu_opts_absorb_qdict(subopts, section, errp)) { 491adf5c449SMax Reitz qemu_opts_del(subopts); 492f766e6dcSMarkus Armbruster return false; 493adf5c449SMax Reitz } 494adf5c449SMax Reitz 495adf5c449SMax Reitz if (qdict_size(section)) { 496adf5c449SMax Reitz error_setg(errp, "[%s] section doesn't support the option '%s'", 497adf5c449SMax Reitz opts->name, qdict_first(section)->key); 498adf5c449SMax Reitz qemu_opts_del(subopts); 499f766e6dcSMarkus Armbruster return false; 500adf5c449SMax Reitz } 501adf5c449SMax Reitz } 502adf5c449SMax Reitz } 503adf5c449SMax Reitz 504f766e6dcSMarkus Armbruster return true; 505adf5c449SMax Reitz } 506adf5c449SMax Reitz 507f766e6dcSMarkus Armbruster bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, 508adf5c449SMax Reitz Error **errp) 509adf5c449SMax Reitz { 510adf5c449SMax Reitz int i; 511adf5c449SMax Reitz 512adf5c449SMax Reitz for (i = 0; lists[i]; i++) { 513f766e6dcSMarkus Armbruster if (!config_parse_qdict_section(options, lists[i], errp)) { 514f766e6dcSMarkus Armbruster return false; 515adf5c449SMax Reitz } 516adf5c449SMax Reitz } 517f766e6dcSMarkus Armbruster 518f766e6dcSMarkus Armbruster return true; 519adf5c449SMax Reitz } 520