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" 5*b4a42f81SPaolo Bonzini #include "qapi/qmp/qerror.h" 6d0fef6fbSGerd Hoffmann #include "hw/qdev.h" 77b1b5d19SPaolo Bonzini #include "qapi/error.h" 87282a033SGerd Hoffmann 94d454574SPaolo Bonzini static QemuOptsList *vm_config_groups[32]; 10d058fe03SGerd Hoffmann 112ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group, 122ac20613SLuiz Capitulino Error **errp) 13d058fe03SGerd Hoffmann { 14ddc97855SGerd Hoffmann int i; 15d058fe03SGerd Hoffmann 16d058fe03SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) { 17d058fe03SGerd Hoffmann if (strcmp(lists[i]->name, group) == 0) 18d058fe03SGerd Hoffmann break; 19d058fe03SGerd Hoffmann } 20d058fe03SGerd Hoffmann if (lists[i] == NULL) { 212ac20613SLuiz Capitulino error_set(errp, QERR_INVALID_OPTION_GROUP, group); 22ddc97855SGerd Hoffmann } 23ddc97855SGerd Hoffmann return lists[i]; 24ddc97855SGerd Hoffmann } 25ddc97855SGerd Hoffmann 26490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group) 27490b648eSKevin Wolf { 282ac20613SLuiz Capitulino QemuOptsList *ret; 292ac20613SLuiz Capitulino Error *local_err = NULL; 302ac20613SLuiz Capitulino 312ac20613SLuiz Capitulino ret = find_list(vm_config_groups, group, &local_err); 322ac20613SLuiz Capitulino if (error_is_set(&local_err)) { 33312fd5f2SMarkus Armbruster error_report("%s", error_get_pretty(local_err)); 342ac20613SLuiz Capitulino error_free(local_err); 352ac20613SLuiz Capitulino } 362ac20613SLuiz Capitulino 372ac20613SLuiz Capitulino return ret; 38490b648eSKevin Wolf } 39490b648eSKevin Wolf 4060d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) 4160d5666fSLuiz Capitulino { 4260d5666fSLuiz Capitulino return find_list(vm_config_groups, group, errp); 4360d5666fSLuiz Capitulino } 4460d5666fSLuiz Capitulino 45dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list) 46dfe795e7SGerd Hoffmann { 47dfe795e7SGerd Hoffmann int entries, i; 48dfe795e7SGerd Hoffmann 49dfe795e7SGerd Hoffmann entries = ARRAY_SIZE(vm_config_groups); 50dfe795e7SGerd Hoffmann entries--; /* keep list NULL terminated */ 51dfe795e7SGerd Hoffmann for (i = 0; i < entries; i++) { 52dfe795e7SGerd Hoffmann if (vm_config_groups[i] == NULL) { 53dfe795e7SGerd Hoffmann vm_config_groups[i] = list; 54dfe795e7SGerd Hoffmann return; 55dfe795e7SGerd Hoffmann } 56dfe795e7SGerd Hoffmann } 57dfe795e7SGerd Hoffmann fprintf(stderr, "ran out of space in vm_config_groups"); 58dfe795e7SGerd Hoffmann abort(); 59dfe795e7SGerd Hoffmann } 60dfe795e7SGerd Hoffmann 61ddc97855SGerd Hoffmann int qemu_set_option(const char *str) 62ddc97855SGerd Hoffmann { 63ddc97855SGerd Hoffmann char group[64], id[64], arg[64]; 64ddc97855SGerd Hoffmann QemuOptsList *list; 65ddc97855SGerd Hoffmann QemuOpts *opts; 66ddc97855SGerd Hoffmann int rc, offset; 67ddc97855SGerd Hoffmann 68ddc97855SGerd Hoffmann rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset); 69ddc97855SGerd Hoffmann if (rc < 3 || str[offset] != '=') { 701ecda02bSMarkus Armbruster error_report("can't parse: \"%s\"", str); 71d058fe03SGerd Hoffmann return -1; 72d058fe03SGerd Hoffmann } 73d058fe03SGerd Hoffmann 74304329eeSMarkus Armbruster list = qemu_find_opts(group); 75ddc97855SGerd Hoffmann if (list == NULL) { 76ddc97855SGerd Hoffmann return -1; 77ddc97855SGerd Hoffmann } 78ddc97855SGerd Hoffmann 79ddc97855SGerd Hoffmann opts = qemu_opts_find(list, id); 80d058fe03SGerd Hoffmann if (!opts) { 811ecda02bSMarkus Armbruster error_report("there is no %s \"%s\" defined", 82ddc97855SGerd Hoffmann list->name, id); 83d058fe03SGerd Hoffmann return -1; 84d058fe03SGerd Hoffmann } 85d058fe03SGerd Hoffmann 863df04ac3SMark McLoughlin if (qemu_opt_set(opts, arg, str+offset+1) == -1) { 87d058fe03SGerd Hoffmann return -1; 88d058fe03SGerd Hoffmann } 89d058fe03SGerd Hoffmann return 0; 90d058fe03SGerd Hoffmann } 91d058fe03SGerd Hoffmann 929d993394SGerd Hoffmann struct ConfigWriteData { 939d993394SGerd Hoffmann QemuOptsList *list; 949d993394SGerd Hoffmann FILE *fp; 959d993394SGerd Hoffmann }; 969d993394SGerd Hoffmann 979d993394SGerd Hoffmann static int config_write_opt(const char *name, const char *value, void *opaque) 989d993394SGerd Hoffmann { 999d993394SGerd Hoffmann struct ConfigWriteData *data = opaque; 1009d993394SGerd Hoffmann 1019d993394SGerd Hoffmann fprintf(data->fp, " %s = \"%s\"\n", name, value); 1029d993394SGerd Hoffmann return 0; 1039d993394SGerd Hoffmann } 1049d993394SGerd Hoffmann 1059d993394SGerd Hoffmann static int config_write_opts(QemuOpts *opts, void *opaque) 1069d993394SGerd Hoffmann { 1079d993394SGerd Hoffmann struct ConfigWriteData *data = opaque; 1089d993394SGerd Hoffmann const char *id = qemu_opts_id(opts); 1099d993394SGerd Hoffmann 1109d993394SGerd Hoffmann if (id) { 1119d993394SGerd Hoffmann fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id); 1129d993394SGerd Hoffmann } else { 1139d993394SGerd Hoffmann fprintf(data->fp, "[%s]\n", data->list->name); 1149d993394SGerd Hoffmann } 1159d993394SGerd Hoffmann qemu_opt_foreach(opts, config_write_opt, data, 0); 1169d993394SGerd Hoffmann fprintf(data->fp, "\n"); 1179d993394SGerd Hoffmann return 0; 1189d993394SGerd Hoffmann } 1199d993394SGerd Hoffmann 1209d993394SGerd Hoffmann void qemu_config_write(FILE *fp) 1219d993394SGerd Hoffmann { 1229d993394SGerd Hoffmann struct ConfigWriteData data = { .fp = fp }; 123490b648eSKevin Wolf QemuOptsList **lists = vm_config_groups; 1249d993394SGerd Hoffmann int i; 1259d993394SGerd Hoffmann 1269d993394SGerd Hoffmann fprintf(fp, "# qemu config file\n\n"); 1279d993394SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) { 1289d993394SGerd Hoffmann data.list = lists[i]; 1299d993394SGerd Hoffmann qemu_opts_foreach(data.list, config_write_opts, &data, 0); 1309d993394SGerd Hoffmann } 1319d993394SGerd Hoffmann } 13242262ba8SGerd Hoffmann 133490b648eSKevin Wolf int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) 13442262ba8SGerd Hoffmann { 13542262ba8SGerd Hoffmann char line[1024], group[64], id[64], arg[64], value[1024]; 136cf5a65aaSMarkus Armbruster Location loc; 13742262ba8SGerd Hoffmann QemuOptsList *list = NULL; 1382ac20613SLuiz Capitulino Error *local_err = NULL; 13942262ba8SGerd Hoffmann QemuOpts *opts = NULL; 140cf5a65aaSMarkus Armbruster int res = -1, lno = 0; 14142262ba8SGerd Hoffmann 142cf5a65aaSMarkus Armbruster loc_push_none(&loc); 14342262ba8SGerd Hoffmann while (fgets(line, sizeof(line), fp) != NULL) { 144cf5a65aaSMarkus Armbruster loc_set_file(fname, ++lno); 14542262ba8SGerd Hoffmann if (line[0] == '\n') { 14642262ba8SGerd Hoffmann /* skip empty lines */ 14742262ba8SGerd Hoffmann continue; 14842262ba8SGerd Hoffmann } 14942262ba8SGerd Hoffmann if (line[0] == '#') { 15042262ba8SGerd Hoffmann /* comment */ 15142262ba8SGerd Hoffmann continue; 15242262ba8SGerd Hoffmann } 15342262ba8SGerd Hoffmann if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) { 15442262ba8SGerd Hoffmann /* group with id */ 1552ac20613SLuiz Capitulino list = find_list(lists, group, &local_err); 1562ac20613SLuiz Capitulino if (error_is_set(&local_err)) { 157312fd5f2SMarkus Armbruster error_report("%s", error_get_pretty(local_err)); 1582ac20613SLuiz Capitulino error_free(local_err); 159cf5a65aaSMarkus Armbruster goto out; 1602ac20613SLuiz Capitulino } 1618be7e7e4SLuiz Capitulino opts = qemu_opts_create(list, id, 1, NULL); 16242262ba8SGerd Hoffmann continue; 16342262ba8SGerd Hoffmann } 16442262ba8SGerd Hoffmann if (sscanf(line, "[%63[^]]]", group) == 1) { 16542262ba8SGerd Hoffmann /* group without id */ 1662ac20613SLuiz Capitulino list = find_list(lists, group, &local_err); 1672ac20613SLuiz Capitulino if (error_is_set(&local_err)) { 168312fd5f2SMarkus Armbruster error_report("%s", error_get_pretty(local_err)); 1692ac20613SLuiz Capitulino error_free(local_err); 170cf5a65aaSMarkus Armbruster goto out; 1712ac20613SLuiz Capitulino } 172e478b448SDong Xu Wang opts = qemu_opts_create_nofail(list); 17342262ba8SGerd Hoffmann continue; 17442262ba8SGerd Hoffmann } 17542262ba8SGerd Hoffmann if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) { 17642262ba8SGerd Hoffmann /* arg = value */ 17742262ba8SGerd Hoffmann if (opts == NULL) { 178cf5a65aaSMarkus Armbruster error_report("no group defined"); 179cf5a65aaSMarkus Armbruster goto out; 18042262ba8SGerd Hoffmann } 18142262ba8SGerd Hoffmann if (qemu_opt_set(opts, arg, value) != 0) { 182cf5a65aaSMarkus Armbruster goto out; 18342262ba8SGerd Hoffmann } 18442262ba8SGerd Hoffmann continue; 18542262ba8SGerd Hoffmann } 186cf5a65aaSMarkus Armbruster error_report("parse error"); 187cf5a65aaSMarkus Armbruster goto out; 18842262ba8SGerd Hoffmann } 189ef82516dSMarkus Armbruster if (ferror(fp)) { 190ef82516dSMarkus Armbruster error_report("error reading file"); 191ef82516dSMarkus Armbruster goto out; 192ef82516dSMarkus Armbruster } 193cf5a65aaSMarkus Armbruster res = 0; 194cf5a65aaSMarkus Armbruster out: 195cf5a65aaSMarkus Armbruster loc_pop(&loc); 196cf5a65aaSMarkus Armbruster return res; 19742262ba8SGerd Hoffmann } 198dcfb0939SKevin Wolf 199dcfb0939SKevin Wolf int qemu_read_config_file(const char *filename) 200dcfb0939SKevin Wolf { 201dcfb0939SKevin Wolf FILE *f = fopen(filename, "r"); 202019e78baSKevin Wolf int ret; 203019e78baSKevin Wolf 204dcfb0939SKevin Wolf if (f == NULL) { 205dcfb0939SKevin Wolf return -errno; 206dcfb0939SKevin Wolf } 207dcfb0939SKevin Wolf 208019e78baSKevin Wolf ret = qemu_config_parse(f, vm_config_groups, filename); 209dcfb0939SKevin Wolf fclose(f); 210dcfb0939SKevin Wolf 211019e78baSKevin Wolf if (ret == 0) { 212dcfb0939SKevin Wolf return 0; 213019e78baSKevin Wolf } else { 214019e78baSKevin Wolf return -EINVAL; 215019e78baSKevin Wolf } 216dcfb0939SKevin Wolf } 217