17282a033SGerd Hoffmann #include "qemu-common.h" 21de7afc9SPaolo Bonzini #include "qemu/error-report.h" 31de7afc9SPaolo Bonzini #include "qemu/option.h" 41de7afc9SPaolo Bonzini #include "qemu/config-file.h" 5b4a42f81SPaolo Bonzini #include "qapi/qmp/qerror.h" 67b1b5d19SPaolo Bonzini #include "qapi/error.h" 71f8f987dSAmos Kong #include "qmp-commands.h" 87282a033SGerd Hoffmann 94d454574SPaolo Bonzini static QemuOptsList *vm_config_groups[32]; 10968854c8SAmos Kong static QemuOptsList *drive_config_groups[4]; 11d058fe03SGerd Hoffmann 122ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group, 132ac20613SLuiz Capitulino Error **errp) 14d058fe03SGerd Hoffmann { 15ddc97855SGerd Hoffmann int i; 16d058fe03SGerd Hoffmann 17d058fe03SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) { 18d058fe03SGerd Hoffmann if (strcmp(lists[i]->name, group) == 0) 19d058fe03SGerd Hoffmann break; 20d058fe03SGerd Hoffmann } 21d058fe03SGerd Hoffmann if (lists[i] == NULL) { 22f231b88dSCole Robinson error_setg(errp, "There is no option group '%s'", group); 23ddc97855SGerd Hoffmann } 24ddc97855SGerd Hoffmann return lists[i]; 25ddc97855SGerd Hoffmann } 26ddc97855SGerd Hoffmann 27490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group) 28490b648eSKevin Wolf { 292ac20613SLuiz Capitulino QemuOptsList *ret; 302ac20613SLuiz Capitulino Error *local_err = NULL; 312ac20613SLuiz Capitulino 322ac20613SLuiz Capitulino ret = find_list(vm_config_groups, group, &local_err); 3384d18f06SMarkus Armbruster if (local_err) { 34565f65d2SMarkus Armbruster error_report_err(local_err); 352ac20613SLuiz Capitulino } 362ac20613SLuiz Capitulino 372ac20613SLuiz Capitulino return ret; 38490b648eSKevin Wolf } 39490b648eSKevin Wolf 40e96e5ae8SPaolo Bonzini QemuOpts *qemu_find_opts_singleton(const char *group) 41e96e5ae8SPaolo Bonzini { 42e96e5ae8SPaolo Bonzini QemuOptsList *list; 43e96e5ae8SPaolo Bonzini QemuOpts *opts; 44e96e5ae8SPaolo Bonzini 45e96e5ae8SPaolo Bonzini list = qemu_find_opts(group); 46e96e5ae8SPaolo Bonzini assert(list); 47e96e5ae8SPaolo Bonzini opts = qemu_opts_find(list, NULL); 48e96e5ae8SPaolo Bonzini if (!opts) { 49e96e5ae8SPaolo Bonzini opts = qemu_opts_create(list, NULL, 0, &error_abort); 50e96e5ae8SPaolo Bonzini } 51e96e5ae8SPaolo Bonzini return opts; 52e96e5ae8SPaolo Bonzini } 53e96e5ae8SPaolo Bonzini 541f8f987dSAmos Kong static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc) 551f8f987dSAmos Kong { 561f8f987dSAmos Kong CommandLineParameterInfoList *param_list = NULL, *entry; 571f8f987dSAmos Kong CommandLineParameterInfo *info; 581f8f987dSAmos Kong int i; 591f8f987dSAmos Kong 601f8f987dSAmos Kong for (i = 0; desc[i].name != NULL; i++) { 611f8f987dSAmos Kong info = g_malloc0(sizeof(*info)); 621f8f987dSAmos Kong info->name = g_strdup(desc[i].name); 631f8f987dSAmos Kong 641f8f987dSAmos Kong switch (desc[i].type) { 651f8f987dSAmos Kong case QEMU_OPT_STRING: 661f8f987dSAmos Kong info->type = COMMAND_LINE_PARAMETER_TYPE_STRING; 671f8f987dSAmos Kong break; 681f8f987dSAmos Kong case QEMU_OPT_BOOL: 691f8f987dSAmos Kong info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN; 701f8f987dSAmos Kong break; 711f8f987dSAmos Kong case QEMU_OPT_NUMBER: 721f8f987dSAmos Kong info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER; 731f8f987dSAmos Kong break; 741f8f987dSAmos Kong case QEMU_OPT_SIZE: 751f8f987dSAmos Kong info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE; 761f8f987dSAmos Kong break; 771f8f987dSAmos Kong } 781f8f987dSAmos Kong 791f8f987dSAmos Kong if (desc[i].help) { 801f8f987dSAmos Kong info->has_help = true; 811f8f987dSAmos Kong info->help = g_strdup(desc[i].help); 821f8f987dSAmos Kong } 83e36af94fSChunyan Liu if (desc[i].def_value_str) { 84e36af94fSChunyan Liu info->has_q_default = true; 85e36af94fSChunyan Liu info->q_default = g_strdup(desc[i].def_value_str); 86e36af94fSChunyan Liu } 871f8f987dSAmos Kong 881f8f987dSAmos Kong entry = g_malloc0(sizeof(*entry)); 891f8f987dSAmos Kong entry->value = info; 901f8f987dSAmos Kong entry->next = param_list; 911f8f987dSAmos Kong param_list = entry; 921f8f987dSAmos Kong } 931f8f987dSAmos Kong 941f8f987dSAmos Kong return param_list; 951f8f987dSAmos Kong } 961f8f987dSAmos Kong 97968854c8SAmos Kong /* remove repeated entry from the info list */ 98968854c8SAmos Kong static void cleanup_infolist(CommandLineParameterInfoList *head) 99968854c8SAmos Kong { 100968854c8SAmos Kong CommandLineParameterInfoList *pre_entry, *cur, *del_entry; 101968854c8SAmos Kong 102968854c8SAmos Kong cur = head; 103968854c8SAmos Kong while (cur->next) { 104968854c8SAmos Kong pre_entry = head; 105968854c8SAmos Kong while (pre_entry != cur->next) { 106968854c8SAmos Kong if (!strcmp(pre_entry->value->name, cur->next->value->name)) { 107968854c8SAmos Kong del_entry = cur->next; 108968854c8SAmos Kong cur->next = cur->next->next; 109968854c8SAmos Kong g_free(del_entry); 110968854c8SAmos Kong break; 111968854c8SAmos Kong } 112968854c8SAmos Kong pre_entry = pre_entry->next; 113968854c8SAmos Kong } 114968854c8SAmos Kong cur = cur->next; 115968854c8SAmos Kong } 116968854c8SAmos Kong } 117968854c8SAmos Kong 118968854c8SAmos Kong /* merge the description items of two parameter infolists */ 119968854c8SAmos Kong static void connect_infolist(CommandLineParameterInfoList *head, 120968854c8SAmos Kong CommandLineParameterInfoList *new) 121968854c8SAmos Kong { 122968854c8SAmos Kong CommandLineParameterInfoList *cur; 123968854c8SAmos Kong 124968854c8SAmos Kong cur = head; 125968854c8SAmos Kong while (cur->next) { 126968854c8SAmos Kong cur = cur->next; 127968854c8SAmos Kong } 128968854c8SAmos Kong cur->next = new; 129968854c8SAmos Kong } 130968854c8SAmos Kong 131968854c8SAmos Kong /* access all the local QemuOptsLists for drive option */ 132968854c8SAmos Kong static CommandLineParameterInfoList *get_drive_infolist(void) 133968854c8SAmos Kong { 134968854c8SAmos Kong CommandLineParameterInfoList *head = NULL, *cur; 135968854c8SAmos Kong int i; 136968854c8SAmos Kong 137968854c8SAmos Kong for (i = 0; drive_config_groups[i] != NULL; i++) { 138968854c8SAmos Kong if (!head) { 139968854c8SAmos Kong head = query_option_descs(drive_config_groups[i]->desc); 140968854c8SAmos Kong } else { 141968854c8SAmos Kong cur = query_option_descs(drive_config_groups[i]->desc); 142968854c8SAmos Kong connect_infolist(head, cur); 143968854c8SAmos Kong } 144968854c8SAmos Kong } 145968854c8SAmos Kong cleanup_infolist(head); 146968854c8SAmos Kong 147968854c8SAmos Kong return head; 148968854c8SAmos Kong } 149968854c8SAmos Kong 1500a7cf217SMarcel Apfelbaum /* restore machine options that are now machine's properties */ 1510a7cf217SMarcel Apfelbaum static QemuOptsList machine_opts = { 1520a7cf217SMarcel Apfelbaum .merge_lists = true, 1530a7cf217SMarcel Apfelbaum .head = QTAILQ_HEAD_INITIALIZER(machine_opts.head), 1540a7cf217SMarcel Apfelbaum .desc = { 1550a7cf217SMarcel Apfelbaum { 1560a7cf217SMarcel Apfelbaum .name = "type", 1570a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1580a7cf217SMarcel Apfelbaum .help = "emulated machine" 1590a7cf217SMarcel Apfelbaum },{ 1600a7cf217SMarcel Apfelbaum .name = "accel", 1610a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1620a7cf217SMarcel Apfelbaum .help = "accelerator list", 1630a7cf217SMarcel Apfelbaum },{ 1640a7cf217SMarcel Apfelbaum .name = "kernel_irqchip", 1650a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 1660a7cf217SMarcel Apfelbaum .help = "use KVM in-kernel irqchip", 1670a7cf217SMarcel Apfelbaum },{ 1680a7cf217SMarcel Apfelbaum .name = "kvm_shadow_mem", 1690a7cf217SMarcel Apfelbaum .type = QEMU_OPT_SIZE, 1700a7cf217SMarcel Apfelbaum .help = "KVM shadow MMU size", 1710a7cf217SMarcel Apfelbaum },{ 1720a7cf217SMarcel Apfelbaum .name = "kernel", 1730a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1740a7cf217SMarcel Apfelbaum .help = "Linux kernel image file", 1750a7cf217SMarcel Apfelbaum },{ 1760a7cf217SMarcel Apfelbaum .name = "initrd", 1770a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1780a7cf217SMarcel Apfelbaum .help = "Linux initial ramdisk file", 1790a7cf217SMarcel Apfelbaum },{ 1800a7cf217SMarcel Apfelbaum .name = "append", 1810a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1820a7cf217SMarcel Apfelbaum .help = "Linux kernel command line", 1830a7cf217SMarcel Apfelbaum },{ 1840a7cf217SMarcel Apfelbaum .name = "dtb", 1850a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1860a7cf217SMarcel Apfelbaum .help = "Linux kernel device tree file", 1870a7cf217SMarcel Apfelbaum },{ 1880a7cf217SMarcel Apfelbaum .name = "dumpdtb", 1890a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1900a7cf217SMarcel Apfelbaum .help = "Dump current dtb to a file and quit", 1910a7cf217SMarcel Apfelbaum },{ 1920a7cf217SMarcel Apfelbaum .name = "phandle_start", 1930a7cf217SMarcel Apfelbaum .type = QEMU_OPT_NUMBER, 1940a7cf217SMarcel Apfelbaum .help = "The first phandle ID we may generate dynamically", 1950a7cf217SMarcel Apfelbaum },{ 1960a7cf217SMarcel Apfelbaum .name = "dt_compatible", 1970a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 1980a7cf217SMarcel Apfelbaum .help = "Overrides the \"compatible\" property of the dt root node", 1990a7cf217SMarcel Apfelbaum },{ 2000a7cf217SMarcel Apfelbaum .name = "dump-guest-core", 2010a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2020a7cf217SMarcel Apfelbaum .help = "Include guest memory in a core dump", 2030a7cf217SMarcel Apfelbaum },{ 2040a7cf217SMarcel Apfelbaum .name = "mem-merge", 2050a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2060a7cf217SMarcel Apfelbaum .help = "enable/disable memory merge support", 2070a7cf217SMarcel Apfelbaum },{ 2080a7cf217SMarcel Apfelbaum .name = "usb", 2090a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2100a7cf217SMarcel Apfelbaum .help = "Set on/off to enable/disable usb", 2110a7cf217SMarcel Apfelbaum },{ 2120a7cf217SMarcel Apfelbaum .name = "firmware", 2130a7cf217SMarcel Apfelbaum .type = QEMU_OPT_STRING, 2140a7cf217SMarcel Apfelbaum .help = "firmware image", 2150a7cf217SMarcel Apfelbaum },{ 2160a7cf217SMarcel Apfelbaum .name = "iommu", 2170a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2180a7cf217SMarcel Apfelbaum .help = "Set on/off to enable/disable Intel IOMMU (VT-d)", 2190a7cf217SMarcel Apfelbaum },{ 2200a7cf217SMarcel Apfelbaum .name = "suppress-vmdesc", 2210a7cf217SMarcel Apfelbaum .type = QEMU_OPT_BOOL, 2220a7cf217SMarcel Apfelbaum .help = "Set on to disable self-describing migration", 2230a7cf217SMarcel Apfelbaum }, 2240a7cf217SMarcel Apfelbaum { /* End of list */ } 2250a7cf217SMarcel Apfelbaum } 2260a7cf217SMarcel Apfelbaum }; 2270a7cf217SMarcel Apfelbaum 2281f8f987dSAmos Kong CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option, 2291f8f987dSAmos Kong const char *option, 2301f8f987dSAmos Kong Error **errp) 2311f8f987dSAmos Kong { 2321f8f987dSAmos Kong CommandLineOptionInfoList *conf_list = NULL, *entry; 2331f8f987dSAmos Kong CommandLineOptionInfo *info; 2341f8f987dSAmos Kong int i; 2351f8f987dSAmos Kong 2361f8f987dSAmos Kong for (i = 0; vm_config_groups[i] != NULL; i++) { 2371f8f987dSAmos Kong if (!has_option || !strcmp(option, vm_config_groups[i]->name)) { 2381f8f987dSAmos Kong info = g_malloc0(sizeof(*info)); 2391f8f987dSAmos Kong info->option = g_strdup(vm_config_groups[i]->name); 240968854c8SAmos Kong if (!strcmp("drive", vm_config_groups[i]->name)) { 241968854c8SAmos Kong info->parameters = get_drive_infolist(); 2420a7cf217SMarcel Apfelbaum } else if (!strcmp("machine", vm_config_groups[i]->name)) { 2430a7cf217SMarcel Apfelbaum info->parameters = query_option_descs(machine_opts.desc); 244968854c8SAmos Kong } else { 245968854c8SAmos Kong info->parameters = 246968854c8SAmos Kong query_option_descs(vm_config_groups[i]->desc); 247968854c8SAmos Kong } 2481f8f987dSAmos Kong entry = g_malloc0(sizeof(*entry)); 2491f8f987dSAmos Kong entry->value = info; 2501f8f987dSAmos Kong entry->next = conf_list; 2511f8f987dSAmos Kong conf_list = entry; 2521f8f987dSAmos Kong } 2531f8f987dSAmos Kong } 2541f8f987dSAmos Kong 2551f8f987dSAmos Kong if (conf_list == NULL) { 2561f8f987dSAmos Kong error_setg(errp, "invalid option name: %s", option); 2571f8f987dSAmos Kong } 2581f8f987dSAmos Kong 2591f8f987dSAmos Kong return conf_list; 2601f8f987dSAmos Kong } 2611f8f987dSAmos Kong 26260d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) 26360d5666fSLuiz Capitulino { 26460d5666fSLuiz Capitulino return find_list(vm_config_groups, group, errp); 26560d5666fSLuiz Capitulino } 26660d5666fSLuiz Capitulino 267968854c8SAmos Kong void qemu_add_drive_opts(QemuOptsList *list) 268968854c8SAmos Kong { 269968854c8SAmos Kong int entries, i; 270968854c8SAmos Kong 271968854c8SAmos Kong entries = ARRAY_SIZE(drive_config_groups); 272968854c8SAmos Kong entries--; /* keep list NULL terminated */ 273968854c8SAmos Kong for (i = 0; i < entries; i++) { 274968854c8SAmos Kong if (drive_config_groups[i] == NULL) { 275968854c8SAmos Kong drive_config_groups[i] = list; 276968854c8SAmos Kong return; 277968854c8SAmos Kong } 278968854c8SAmos Kong } 279968854c8SAmos Kong fprintf(stderr, "ran out of space in drive_config_groups"); 280968854c8SAmos Kong abort(); 281968854c8SAmos Kong } 282968854c8SAmos Kong 283dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list) 284dfe795e7SGerd Hoffmann { 285dfe795e7SGerd Hoffmann int entries, i; 286dfe795e7SGerd Hoffmann 287dfe795e7SGerd Hoffmann entries = ARRAY_SIZE(vm_config_groups); 288dfe795e7SGerd Hoffmann entries--; /* keep list NULL terminated */ 289dfe795e7SGerd Hoffmann for (i = 0; i < entries; i++) { 290dfe795e7SGerd Hoffmann if (vm_config_groups[i] == NULL) { 291dfe795e7SGerd Hoffmann vm_config_groups[i] = list; 292dfe795e7SGerd Hoffmann return; 293dfe795e7SGerd Hoffmann } 294dfe795e7SGerd Hoffmann } 295dfe795e7SGerd Hoffmann fprintf(stderr, "ran out of space in vm_config_groups"); 296dfe795e7SGerd Hoffmann abort(); 297dfe795e7SGerd Hoffmann } 298dfe795e7SGerd Hoffmann 299ddc97855SGerd Hoffmann int qemu_set_option(const char *str) 300ddc97855SGerd Hoffmann { 301f43e47dbSMarkus Armbruster Error *local_err = NULL; 302ddc97855SGerd Hoffmann char group[64], id[64], arg[64]; 303ddc97855SGerd Hoffmann QemuOptsList *list; 304ddc97855SGerd Hoffmann QemuOpts *opts; 305ddc97855SGerd Hoffmann int rc, offset; 306ddc97855SGerd Hoffmann 307ddc97855SGerd Hoffmann rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset); 308ddc97855SGerd Hoffmann if (rc < 3 || str[offset] != '=') { 3091ecda02bSMarkus Armbruster error_report("can't parse: \"%s\"", str); 310d058fe03SGerd Hoffmann return -1; 311d058fe03SGerd Hoffmann } 312d058fe03SGerd Hoffmann 313304329eeSMarkus Armbruster list = qemu_find_opts(group); 314ddc97855SGerd Hoffmann if (list == NULL) { 315ddc97855SGerd Hoffmann return -1; 316ddc97855SGerd Hoffmann } 317ddc97855SGerd Hoffmann 318ddc97855SGerd Hoffmann opts = qemu_opts_find(list, id); 319d058fe03SGerd Hoffmann if (!opts) { 3201ecda02bSMarkus Armbruster error_report("there is no %s \"%s\" defined", 321ddc97855SGerd Hoffmann list->name, id); 322d058fe03SGerd Hoffmann return -1; 323d058fe03SGerd Hoffmann } 324d058fe03SGerd Hoffmann 325f43e47dbSMarkus Armbruster qemu_opt_set(opts, arg, str + offset + 1, &local_err); 326f43e47dbSMarkus Armbruster if (local_err) { 327f43e47dbSMarkus Armbruster error_report_err(local_err); 328d058fe03SGerd Hoffmann return -1; 329d058fe03SGerd Hoffmann } 330d058fe03SGerd Hoffmann return 0; 331d058fe03SGerd Hoffmann } 332d058fe03SGerd Hoffmann 3339d993394SGerd Hoffmann struct ConfigWriteData { 3349d993394SGerd Hoffmann QemuOptsList *list; 3359d993394SGerd Hoffmann FILE *fp; 3369d993394SGerd Hoffmann }; 3379d993394SGerd Hoffmann 338*71df1d83SMarkus Armbruster static int config_write_opt(void *opaque, const char *name, const char *value, 339*71df1d83SMarkus Armbruster Error **errp) 3409d993394SGerd Hoffmann { 3419d993394SGerd Hoffmann struct ConfigWriteData *data = opaque; 3429d993394SGerd Hoffmann 3439d993394SGerd Hoffmann fprintf(data->fp, " %s = \"%s\"\n", name, value); 3449d993394SGerd Hoffmann return 0; 3459d993394SGerd Hoffmann } 3469d993394SGerd Hoffmann 34728d0de7aSMarkus Armbruster static int config_write_opts(void *opaque, QemuOpts *opts, Error **errp) 3489d993394SGerd Hoffmann { 3499d993394SGerd Hoffmann struct ConfigWriteData *data = opaque; 3509d993394SGerd Hoffmann const char *id = qemu_opts_id(opts); 3519d993394SGerd Hoffmann 3529d993394SGerd Hoffmann if (id) { 3539d993394SGerd Hoffmann fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id); 3549d993394SGerd Hoffmann } else { 3559d993394SGerd Hoffmann fprintf(data->fp, "[%s]\n", data->list->name); 3569d993394SGerd Hoffmann } 357*71df1d83SMarkus Armbruster qemu_opt_foreach(opts, config_write_opt, data, NULL); 3589d993394SGerd Hoffmann fprintf(data->fp, "\n"); 3599d993394SGerd Hoffmann return 0; 3609d993394SGerd Hoffmann } 3619d993394SGerd Hoffmann 3629d993394SGerd Hoffmann void qemu_config_write(FILE *fp) 3639d993394SGerd Hoffmann { 3649d993394SGerd Hoffmann struct ConfigWriteData data = { .fp = fp }; 365490b648eSKevin Wolf QemuOptsList **lists = vm_config_groups; 3669d993394SGerd Hoffmann int i; 3679d993394SGerd Hoffmann 3689d993394SGerd Hoffmann fprintf(fp, "# qemu config file\n\n"); 3699d993394SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) { 3709d993394SGerd Hoffmann data.list = lists[i]; 37128d0de7aSMarkus Armbruster qemu_opts_foreach(data.list, config_write_opts, &data, NULL); 3729d993394SGerd Hoffmann } 3739d993394SGerd Hoffmann } 37442262ba8SGerd Hoffmann 375490b648eSKevin Wolf int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) 37642262ba8SGerd Hoffmann { 37742262ba8SGerd Hoffmann char line[1024], group[64], id[64], arg[64], value[1024]; 378cf5a65aaSMarkus Armbruster Location loc; 37942262ba8SGerd Hoffmann QemuOptsList *list = NULL; 3802ac20613SLuiz Capitulino Error *local_err = NULL; 38142262ba8SGerd Hoffmann QemuOpts *opts = NULL; 382cf5a65aaSMarkus Armbruster int res = -1, lno = 0; 38342262ba8SGerd Hoffmann 384cf5a65aaSMarkus Armbruster loc_push_none(&loc); 38542262ba8SGerd Hoffmann while (fgets(line, sizeof(line), fp) != NULL) { 386cf5a65aaSMarkus Armbruster loc_set_file(fname, ++lno); 38742262ba8SGerd Hoffmann if (line[0] == '\n') { 38842262ba8SGerd Hoffmann /* skip empty lines */ 38942262ba8SGerd Hoffmann continue; 39042262ba8SGerd Hoffmann } 39142262ba8SGerd Hoffmann if (line[0] == '#') { 39242262ba8SGerd Hoffmann /* comment */ 39342262ba8SGerd Hoffmann continue; 39442262ba8SGerd Hoffmann } 39542262ba8SGerd Hoffmann if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) { 39642262ba8SGerd Hoffmann /* group with id */ 3972ac20613SLuiz Capitulino list = find_list(lists, group, &local_err); 39884d18f06SMarkus Armbruster if (local_err) { 399565f65d2SMarkus Armbruster error_report_err(local_err); 400cf5a65aaSMarkus Armbruster goto out; 4012ac20613SLuiz Capitulino } 4028be7e7e4SLuiz Capitulino opts = qemu_opts_create(list, id, 1, NULL); 40342262ba8SGerd Hoffmann continue; 40442262ba8SGerd Hoffmann } 40542262ba8SGerd Hoffmann if (sscanf(line, "[%63[^]]]", group) == 1) { 40642262ba8SGerd Hoffmann /* group without id */ 4072ac20613SLuiz Capitulino list = find_list(lists, group, &local_err); 40884d18f06SMarkus Armbruster if (local_err) { 409565f65d2SMarkus Armbruster error_report_err(local_err); 410cf5a65aaSMarkus Armbruster goto out; 4112ac20613SLuiz Capitulino } 41287ea75d5SPeter Crosthwaite opts = qemu_opts_create(list, NULL, 0, &error_abort); 41342262ba8SGerd Hoffmann continue; 41442262ba8SGerd Hoffmann } 415d9f7e29eSEduardo Habkost value[0] = '\0'; 416d9f7e29eSEduardo Habkost if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 || 417d9f7e29eSEduardo Habkost sscanf(line, " %63s = \"\"", arg) == 1) { 41842262ba8SGerd Hoffmann /* arg = value */ 41942262ba8SGerd Hoffmann if (opts == NULL) { 420cf5a65aaSMarkus Armbruster error_report("no group defined"); 421cf5a65aaSMarkus Armbruster goto out; 42242262ba8SGerd Hoffmann } 423f43e47dbSMarkus Armbruster qemu_opt_set(opts, arg, value, &local_err); 424f43e47dbSMarkus Armbruster if (local_err) { 425f43e47dbSMarkus Armbruster error_report_err(local_err); 426cf5a65aaSMarkus Armbruster goto out; 42742262ba8SGerd Hoffmann } 42842262ba8SGerd Hoffmann continue; 42942262ba8SGerd Hoffmann } 430cf5a65aaSMarkus Armbruster error_report("parse error"); 431cf5a65aaSMarkus Armbruster goto out; 43242262ba8SGerd Hoffmann } 433ef82516dSMarkus Armbruster if (ferror(fp)) { 434ef82516dSMarkus Armbruster error_report("error reading file"); 435ef82516dSMarkus Armbruster goto out; 436ef82516dSMarkus Armbruster } 437cf5a65aaSMarkus Armbruster res = 0; 438cf5a65aaSMarkus Armbruster out: 439cf5a65aaSMarkus Armbruster loc_pop(&loc); 440cf5a65aaSMarkus Armbruster return res; 44142262ba8SGerd Hoffmann } 442dcfb0939SKevin Wolf 443dcfb0939SKevin Wolf int qemu_read_config_file(const char *filename) 444dcfb0939SKevin Wolf { 445dcfb0939SKevin Wolf FILE *f = fopen(filename, "r"); 446019e78baSKevin Wolf int ret; 447019e78baSKevin Wolf 448dcfb0939SKevin Wolf if (f == NULL) { 449dcfb0939SKevin Wolf return -errno; 450dcfb0939SKevin Wolf } 451dcfb0939SKevin Wolf 452019e78baSKevin Wolf ret = qemu_config_parse(f, vm_config_groups, filename); 453dcfb0939SKevin Wolf fclose(f); 454dcfb0939SKevin Wolf 455019e78baSKevin Wolf if (ret == 0) { 456dcfb0939SKevin Wolf return 0; 457019e78baSKevin Wolf } else { 458019e78baSKevin Wolf return -EINVAL; 459019e78baSKevin Wolf } 460dcfb0939SKevin Wolf } 461adf5c449SMax Reitz 462adf5c449SMax Reitz static void config_parse_qdict_section(QDict *options, QemuOptsList *opts, 463adf5c449SMax Reitz Error **errp) 464adf5c449SMax Reitz { 465adf5c449SMax Reitz QemuOpts *subopts; 466adf5c449SMax Reitz QDict *subqdict; 467adf5c449SMax Reitz QList *list = NULL; 468adf5c449SMax Reitz Error *local_err = NULL; 469adf5c449SMax Reitz size_t orig_size, enum_size; 470adf5c449SMax Reitz char *prefix; 471adf5c449SMax Reitz 472adf5c449SMax Reitz prefix = g_strdup_printf("%s.", opts->name); 473adf5c449SMax Reitz qdict_extract_subqdict(options, &subqdict, prefix); 474adf5c449SMax Reitz g_free(prefix); 475adf5c449SMax Reitz orig_size = qdict_size(subqdict); 476adf5c449SMax Reitz if (!orig_size) { 477adf5c449SMax Reitz goto out; 478adf5c449SMax Reitz } 479adf5c449SMax Reitz 480adf5c449SMax Reitz subopts = qemu_opts_create(opts, NULL, 0, &local_err); 48184d18f06SMarkus Armbruster if (local_err) { 482adf5c449SMax Reitz error_propagate(errp, local_err); 483adf5c449SMax Reitz goto out; 484adf5c449SMax Reitz } 485adf5c449SMax Reitz 486adf5c449SMax Reitz qemu_opts_absorb_qdict(subopts, subqdict, &local_err); 48784d18f06SMarkus Armbruster if (local_err) { 488adf5c449SMax Reitz error_propagate(errp, local_err); 489adf5c449SMax Reitz goto out; 490adf5c449SMax Reitz } 491adf5c449SMax Reitz 492adf5c449SMax Reitz enum_size = qdict_size(subqdict); 493adf5c449SMax Reitz if (enum_size < orig_size && enum_size) { 494adf5c449SMax Reitz error_setg(errp, "Unknown option '%s' for [%s]", 495adf5c449SMax Reitz qdict_first(subqdict)->key, opts->name); 496adf5c449SMax Reitz goto out; 497adf5c449SMax Reitz } 498adf5c449SMax Reitz 499adf5c449SMax Reitz if (enum_size) { 500adf5c449SMax Reitz /* Multiple, enumerated sections */ 501adf5c449SMax Reitz QListEntry *list_entry; 502adf5c449SMax Reitz unsigned i = 0; 503adf5c449SMax Reitz 504adf5c449SMax Reitz /* Not required anymore */ 505adf5c449SMax Reitz qemu_opts_del(subopts); 506adf5c449SMax Reitz 507adf5c449SMax Reitz qdict_array_split(subqdict, &list); 508adf5c449SMax Reitz if (qdict_size(subqdict)) { 509adf5c449SMax Reitz error_setg(errp, "Unused option '%s' for [%s]", 510adf5c449SMax Reitz qdict_first(subqdict)->key, opts->name); 511adf5c449SMax Reitz goto out; 512adf5c449SMax Reitz } 513adf5c449SMax Reitz 514adf5c449SMax Reitz QLIST_FOREACH_ENTRY(list, list_entry) { 515adf5c449SMax Reitz QDict *section = qobject_to_qdict(qlist_entry_obj(list_entry)); 516adf5c449SMax Reitz char *opt_name; 517adf5c449SMax Reitz 518ae39c4b2SMax Reitz if (!section) { 519ae39c4b2SMax Reitz error_setg(errp, "[%s] section (index %u) does not consist of " 520ae39c4b2SMax Reitz "keys", opts->name, i); 521ae39c4b2SMax Reitz goto out; 522ae39c4b2SMax Reitz } 523ae39c4b2SMax Reitz 524adf5c449SMax Reitz opt_name = g_strdup_printf("%s.%u", opts->name, i++); 525adf5c449SMax Reitz subopts = qemu_opts_create(opts, opt_name, 1, &local_err); 526adf5c449SMax Reitz g_free(opt_name); 52784d18f06SMarkus Armbruster if (local_err) { 528adf5c449SMax Reitz error_propagate(errp, local_err); 529adf5c449SMax Reitz goto out; 530adf5c449SMax Reitz } 531adf5c449SMax Reitz 532adf5c449SMax Reitz qemu_opts_absorb_qdict(subopts, section, &local_err); 53384d18f06SMarkus Armbruster if (local_err) { 534adf5c449SMax Reitz error_propagate(errp, local_err); 535adf5c449SMax Reitz qemu_opts_del(subopts); 536adf5c449SMax Reitz goto out; 537adf5c449SMax Reitz } 538adf5c449SMax Reitz 539adf5c449SMax Reitz if (qdict_size(section)) { 540adf5c449SMax Reitz error_setg(errp, "[%s] section doesn't support the option '%s'", 541adf5c449SMax Reitz opts->name, qdict_first(section)->key); 542adf5c449SMax Reitz qemu_opts_del(subopts); 543adf5c449SMax Reitz goto out; 544adf5c449SMax Reitz } 545adf5c449SMax Reitz } 546adf5c449SMax Reitz } 547adf5c449SMax Reitz 548adf5c449SMax Reitz out: 549adf5c449SMax Reitz QDECREF(subqdict); 550adf5c449SMax Reitz QDECREF(list); 551adf5c449SMax Reitz } 552adf5c449SMax Reitz 553adf5c449SMax Reitz void qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, 554adf5c449SMax Reitz Error **errp) 555adf5c449SMax Reitz { 556adf5c449SMax Reitz int i; 557adf5c449SMax Reitz Error *local_err = NULL; 558adf5c449SMax Reitz 559adf5c449SMax Reitz for (i = 0; lists[i]; i++) { 560adf5c449SMax Reitz config_parse_qdict_section(options, lists[i], &local_err); 56184d18f06SMarkus Armbruster if (local_err) { 562adf5c449SMax Reitz error_propagate(errp, local_err); 563adf5c449SMax Reitz return; 564adf5c449SMax Reitz } 565adf5c449SMax Reitz } 566adf5c449SMax Reitz } 567