1aafd7584SPeter Maydell #include "qemu/osdep.h" 2609f45eaSMax Reitz #include "block/qdict.h" /* for qdict_extract_subqdict() */ 3e688df6bSMarkus Armbruster #include "qapi/error.h" 4452fcdbcSMarkus Armbruster #include "qapi/qmp/qdict.h" 547e6b297SMarkus Armbruster #include "qapi/qmp/qlist.h" 61de7afc9SPaolo Bonzini #include "qemu/error-report.h" 71de7afc9SPaolo Bonzini #include "qemu/option.h" 81de7afc9SPaolo Bonzini #include "qemu/config-file.h" 97282a033SGerd Hoffmann 10*3df4c288SPhilippe Mathieu-Daudé QemuOptsList *vm_config_groups[48]; 11*3df4c288SPhilippe Mathieu-Daudé QemuOptsList *drive_config_groups[5]; 12d058fe03SGerd Hoffmann 132ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group, 142ac20613SLuiz Capitulino Error **errp) 15d058fe03SGerd Hoffmann { 16ddc97855SGerd Hoffmann int i; 17d058fe03SGerd Hoffmann 18632a8873SPaolo Bonzini qemu_load_module_for_opts(group); 19d058fe03SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) { 20d058fe03SGerd Hoffmann if (strcmp(lists[i]->name, group) == 0) 21d058fe03SGerd Hoffmann break; 22d058fe03SGerd Hoffmann } 23d058fe03SGerd Hoffmann if (lists[i] == NULL) { 24f231b88dSCole Robinson error_setg(errp, "There is no option group '%s'", group); 25ddc97855SGerd Hoffmann } 26ddc97855SGerd Hoffmann return lists[i]; 27ddc97855SGerd Hoffmann } 28ddc97855SGerd Hoffmann 29490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group) 30490b648eSKevin Wolf { 312ac20613SLuiz Capitulino QemuOptsList *ret; 322ac20613SLuiz Capitulino Error *local_err = NULL; 332ac20613SLuiz Capitulino 342ac20613SLuiz Capitulino ret = find_list(vm_config_groups, group, &local_err); 3584d18f06SMarkus Armbruster if (local_err) { 36565f65d2SMarkus Armbruster error_report_err(local_err); 372ac20613SLuiz Capitulino } 382ac20613SLuiz Capitulino 392ac20613SLuiz Capitulino return ret; 40490b648eSKevin Wolf } 41490b648eSKevin Wolf 42e96e5ae8SPaolo Bonzini QemuOpts *qemu_find_opts_singleton(const char *group) 43e96e5ae8SPaolo Bonzini { 44e96e5ae8SPaolo Bonzini QemuOptsList *list; 45e96e5ae8SPaolo Bonzini QemuOpts *opts; 46e96e5ae8SPaolo Bonzini 47e96e5ae8SPaolo Bonzini list = qemu_find_opts(group); 48e96e5ae8SPaolo Bonzini assert(list); 49e96e5ae8SPaolo Bonzini opts = qemu_opts_find(list, NULL); 50e96e5ae8SPaolo Bonzini if (!opts) { 51e96e5ae8SPaolo Bonzini opts = qemu_opts_create(list, NULL, 0, &error_abort); 52e96e5ae8SPaolo Bonzini } 53e96e5ae8SPaolo Bonzini return opts; 54e96e5ae8SPaolo Bonzini } 55e96e5ae8SPaolo Bonzini 5660d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) 5760d5666fSLuiz Capitulino { 5860d5666fSLuiz Capitulino return find_list(vm_config_groups, group, errp); 5960d5666fSLuiz Capitulino } 6060d5666fSLuiz Capitulino 61968854c8SAmos Kong void qemu_add_drive_opts(QemuOptsList *list) 62968854c8SAmos Kong { 63968854c8SAmos Kong int entries, i; 64968854c8SAmos Kong 65968854c8SAmos Kong entries = ARRAY_SIZE(drive_config_groups); 66968854c8SAmos Kong entries--; /* keep list NULL terminated */ 67968854c8SAmos Kong for (i = 0; i < entries; i++) { 68968854c8SAmos Kong if (drive_config_groups[i] == NULL) { 69968854c8SAmos Kong drive_config_groups[i] = list; 70968854c8SAmos Kong return; 71968854c8SAmos Kong } 72968854c8SAmos Kong } 73968854c8SAmos Kong fprintf(stderr, "ran out of space in drive_config_groups"); 74968854c8SAmos Kong abort(); 75968854c8SAmos Kong } 76968854c8SAmos Kong 77dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list) 78dfe795e7SGerd Hoffmann { 79dfe795e7SGerd Hoffmann int entries, i; 80dfe795e7SGerd Hoffmann 81dfe795e7SGerd Hoffmann entries = ARRAY_SIZE(vm_config_groups); 82dfe795e7SGerd Hoffmann entries--; /* keep list NULL terminated */ 83dfe795e7SGerd Hoffmann for (i = 0; i < entries; i++) { 84dfe795e7SGerd Hoffmann if (vm_config_groups[i] == NULL) { 85dfe795e7SGerd Hoffmann vm_config_groups[i] = list; 86dfe795e7SGerd Hoffmann return; 87dfe795e7SGerd Hoffmann } 88dfe795e7SGerd Hoffmann } 89dfe795e7SGerd Hoffmann fprintf(stderr, "ran out of space in vm_config_groups"); 90dfe795e7SGerd Hoffmann abort(); 91dfe795e7SGerd Hoffmann } 92dfe795e7SGerd Hoffmann 93e5766d6eSEduardo Habkost /* Returns number of config groups on success, -errno on error */ 9437701411SPaolo Bonzini static int qemu_config_foreach(FILE *fp, QEMUConfigCB *cb, void *opaque, 9537701411SPaolo Bonzini const char *fname, Error **errp) 9642262ba8SGerd Hoffmann { 970a3090b1SMarkus Armbruster ERRP_GUARD(); 9837701411SPaolo Bonzini char line[1024], prev_group[64], group[64], arg[64], value[1024]; 99cf5a65aaSMarkus Armbruster Location loc; 10037701411SPaolo Bonzini QDict *qdict = NULL; 101e5766d6eSEduardo Habkost int res = -EINVAL, lno = 0; 102e5766d6eSEduardo Habkost int count = 0; 10342262ba8SGerd Hoffmann 104cf5a65aaSMarkus Armbruster loc_push_none(&loc); 10542262ba8SGerd Hoffmann while (fgets(line, sizeof(line), fp) != NULL) { 10637701411SPaolo Bonzini ++lno; 10742262ba8SGerd Hoffmann if (line[0] == '\n') { 10842262ba8SGerd Hoffmann /* skip empty lines */ 10942262ba8SGerd Hoffmann continue; 11042262ba8SGerd Hoffmann } 11142262ba8SGerd Hoffmann if (line[0] == '#') { 11242262ba8SGerd Hoffmann /* comment */ 11342262ba8SGerd Hoffmann continue; 11442262ba8SGerd Hoffmann } 11537701411SPaolo Bonzini if (line[0] == '[') { 11637701411SPaolo Bonzini QDict *prev = qdict; 11737701411SPaolo Bonzini if (sscanf(line, "[%63s \"%63[^\"]\"]", group, value) == 2) { 11837701411SPaolo Bonzini qdict = qdict_new(); 11937701411SPaolo Bonzini qdict_put_str(qdict, "id", value); 12037701411SPaolo Bonzini count++; 12137701411SPaolo Bonzini } else if (sscanf(line, "[%63[^]]]", group) == 1) { 12237701411SPaolo Bonzini qdict = qdict_new(); 12337701411SPaolo Bonzini count++; 12437701411SPaolo Bonzini } 12537701411SPaolo Bonzini if (qdict != prev) { 12637701411SPaolo Bonzini if (prev) { 1270a3090b1SMarkus Armbruster cb(prev_group, prev, opaque, errp); 12837701411SPaolo Bonzini qobject_unref(prev); 1290a3090b1SMarkus Armbruster if (*errp) { 130cf5a65aaSMarkus Armbruster goto out; 1312ac20613SLuiz Capitulino } 13237701411SPaolo Bonzini } 13337701411SPaolo Bonzini strcpy(prev_group, group); 13442262ba8SGerd Hoffmann continue; 13542262ba8SGerd Hoffmann } 1362ac20613SLuiz Capitulino } 13737701411SPaolo Bonzini loc_set_file(fname, lno); 138d9f7e29eSEduardo Habkost value[0] = '\0'; 139d9f7e29eSEduardo Habkost if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2 || 140d9f7e29eSEduardo Habkost sscanf(line, " %63s = \"\"", arg) == 1) { 14142262ba8SGerd Hoffmann /* arg = value */ 14237701411SPaolo Bonzini if (qdict == NULL) { 143f7544edcSPaolo Bonzini error_setg(errp, "no group defined"); 144cf5a65aaSMarkus Armbruster goto out; 14542262ba8SGerd Hoffmann } 14637701411SPaolo Bonzini qdict_put_str(qdict, arg, value); 14742262ba8SGerd Hoffmann continue; 14842262ba8SGerd Hoffmann } 149f7544edcSPaolo Bonzini error_setg(errp, "parse error"); 150cf5a65aaSMarkus Armbruster goto out; 15142262ba8SGerd Hoffmann } 152ef82516dSMarkus Armbruster if (ferror(fp)) { 153f7544edcSPaolo Bonzini loc_pop(&loc); 154f7544edcSPaolo Bonzini error_setg_errno(errp, errno, "Cannot read config file"); 155461fea9bSPaolo Bonzini goto out_no_loc; 156ef82516dSMarkus Armbruster } 157e5766d6eSEduardo Habkost res = count; 15837701411SPaolo Bonzini if (qdict) { 15937701411SPaolo Bonzini cb(group, qdict, opaque, errp); 16037701411SPaolo Bonzini } 161e72f9524SPaolo Bonzini out: 162cf5a65aaSMarkus Armbruster loc_pop(&loc); 163461fea9bSPaolo Bonzini out_no_loc: 164e72f9524SPaolo Bonzini qobject_unref(qdict); 165cf5a65aaSMarkus Armbruster return res; 16642262ba8SGerd Hoffmann } 167dcfb0939SKevin Wolf 16837701411SPaolo Bonzini void qemu_config_do_parse(const char *group, QDict *qdict, void *opaque, Error **errp) 16937701411SPaolo Bonzini { 17037701411SPaolo Bonzini QemuOptsList **lists = opaque; 17137701411SPaolo Bonzini QemuOptsList *list; 17237701411SPaolo Bonzini 17337701411SPaolo Bonzini list = find_list(lists, group, errp); 17437701411SPaolo Bonzini if (!list) { 17537701411SPaolo Bonzini return; 17637701411SPaolo Bonzini } 17737701411SPaolo Bonzini 178e7d85d95SPaolo Bonzini qemu_opts_from_qdict(list, qdict, errp); 17937701411SPaolo Bonzini } 18037701411SPaolo Bonzini 18137701411SPaolo Bonzini int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname, Error **errp) 18237701411SPaolo Bonzini { 18337701411SPaolo Bonzini return qemu_config_foreach(fp, qemu_config_do_parse, lists, fname, errp); 18437701411SPaolo Bonzini } 18537701411SPaolo Bonzini 18637701411SPaolo Bonzini int qemu_read_config_file(const char *filename, QEMUConfigCB *cb, Error **errp) 187dcfb0939SKevin Wolf { 188dcfb0939SKevin Wolf FILE *f = fopen(filename, "r"); 189019e78baSKevin Wolf int ret; 190019e78baSKevin Wolf 191dcfb0939SKevin Wolf if (f == NULL) { 192f7544edcSPaolo Bonzini error_setg_file_open(errp, errno, filename); 193dcfb0939SKevin Wolf return -errno; 194dcfb0939SKevin Wolf } 195dcfb0939SKevin Wolf 19637701411SPaolo Bonzini ret = qemu_config_foreach(f, cb, vm_config_groups, filename, errp); 197dcfb0939SKevin Wolf fclose(f); 198e5766d6eSEduardo Habkost return ret; 199dcfb0939SKevin Wolf } 200adf5c449SMax Reitz 201f766e6dcSMarkus Armbruster static bool config_parse_qdict_section(QDict *options, QemuOptsList *opts, 202adf5c449SMax Reitz Error **errp) 203adf5c449SMax Reitz { 204adf5c449SMax Reitz QemuOpts *subopts; 205f766e6dcSMarkus Armbruster g_autoptr(QDict) subqdict = NULL; 206f766e6dcSMarkus Armbruster g_autoptr(QList) list = NULL; 207adf5c449SMax Reitz size_t orig_size, enum_size; 208adf5c449SMax Reitz char *prefix; 209adf5c449SMax Reitz 210adf5c449SMax Reitz prefix = g_strdup_printf("%s.", opts->name); 211adf5c449SMax Reitz qdict_extract_subqdict(options, &subqdict, prefix); 212adf5c449SMax Reitz g_free(prefix); 213adf5c449SMax Reitz orig_size = qdict_size(subqdict); 214adf5c449SMax Reitz if (!orig_size) { 215f766e6dcSMarkus Armbruster return true; 216adf5c449SMax Reitz } 217adf5c449SMax Reitz 218c6ecec43SMarkus Armbruster subopts = qemu_opts_create(opts, NULL, 0, errp); 219c6ecec43SMarkus Armbruster if (!subopts) { 220f766e6dcSMarkus Armbruster return false; 221adf5c449SMax Reitz } 222adf5c449SMax Reitz 223668f62ecSMarkus Armbruster if (!qemu_opts_absorb_qdict(subopts, subqdict, errp)) { 224f766e6dcSMarkus Armbruster return false; 225adf5c449SMax Reitz } 226adf5c449SMax Reitz 227adf5c449SMax Reitz enum_size = qdict_size(subqdict); 228adf5c449SMax Reitz if (enum_size < orig_size && enum_size) { 229adf5c449SMax Reitz error_setg(errp, "Unknown option '%s' for [%s]", 230adf5c449SMax Reitz qdict_first(subqdict)->key, opts->name); 231f766e6dcSMarkus Armbruster return false; 232adf5c449SMax Reitz } 233adf5c449SMax Reitz 234adf5c449SMax Reitz if (enum_size) { 235adf5c449SMax Reitz /* Multiple, enumerated sections */ 236adf5c449SMax Reitz QListEntry *list_entry; 237adf5c449SMax Reitz unsigned i = 0; 238adf5c449SMax Reitz 239adf5c449SMax Reitz /* Not required anymore */ 240adf5c449SMax Reitz qemu_opts_del(subopts); 241adf5c449SMax Reitz 242adf5c449SMax Reitz qdict_array_split(subqdict, &list); 243adf5c449SMax Reitz if (qdict_size(subqdict)) { 244adf5c449SMax Reitz error_setg(errp, "Unused option '%s' for [%s]", 245adf5c449SMax Reitz qdict_first(subqdict)->key, opts->name); 246f766e6dcSMarkus Armbruster return false; 247adf5c449SMax Reitz } 248adf5c449SMax Reitz 249adf5c449SMax Reitz QLIST_FOREACH_ENTRY(list, list_entry) { 2507dc847ebSMax Reitz QDict *section = qobject_to(QDict, qlist_entry_obj(list_entry)); 251adf5c449SMax Reitz char *opt_name; 252adf5c449SMax Reitz 253ae39c4b2SMax Reitz if (!section) { 254ae39c4b2SMax Reitz error_setg(errp, "[%s] section (index %u) does not consist of " 255ae39c4b2SMax Reitz "keys", opts->name, i); 256f766e6dcSMarkus Armbruster return false; 257ae39c4b2SMax Reitz } 258ae39c4b2SMax Reitz 259adf5c449SMax Reitz opt_name = g_strdup_printf("%s.%u", opts->name, i++); 260c6ecec43SMarkus Armbruster subopts = qemu_opts_create(opts, opt_name, 1, errp); 261adf5c449SMax Reitz g_free(opt_name); 262c6ecec43SMarkus Armbruster if (!subopts) { 263f766e6dcSMarkus Armbruster return false; 264adf5c449SMax Reitz } 265adf5c449SMax Reitz 266668f62ecSMarkus Armbruster if (!qemu_opts_absorb_qdict(subopts, section, errp)) { 267adf5c449SMax Reitz qemu_opts_del(subopts); 268f766e6dcSMarkus Armbruster return false; 269adf5c449SMax Reitz } 270adf5c449SMax Reitz 271adf5c449SMax Reitz if (qdict_size(section)) { 272adf5c449SMax Reitz error_setg(errp, "[%s] section doesn't support the option '%s'", 273adf5c449SMax Reitz opts->name, qdict_first(section)->key); 274adf5c449SMax Reitz qemu_opts_del(subopts); 275f766e6dcSMarkus Armbruster return false; 276adf5c449SMax Reitz } 277adf5c449SMax Reitz } 278adf5c449SMax Reitz } 279adf5c449SMax Reitz 280f766e6dcSMarkus Armbruster return true; 281adf5c449SMax Reitz } 282adf5c449SMax Reitz 283f766e6dcSMarkus Armbruster bool qemu_config_parse_qdict(QDict *options, QemuOptsList **lists, 284adf5c449SMax Reitz Error **errp) 285adf5c449SMax Reitz { 286adf5c449SMax Reitz int i; 287adf5c449SMax Reitz 288adf5c449SMax Reitz for (i = 0; lists[i]; i++) { 289f766e6dcSMarkus Armbruster if (!config_parse_qdict_section(options, lists[i], errp)) { 290f766e6dcSMarkus Armbruster return false; 291adf5c449SMax Reitz } 292adf5c449SMax Reitz } 293f766e6dcSMarkus Armbruster 294f766e6dcSMarkus Armbruster return true; 295adf5c449SMax Reitz } 296