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" 5d0fef6fbSGerd Hoffmann #include "hw/qdev.h" 67b1b5d19SPaolo Bonzini #include "qapi/error.h" 77282a033SGerd Hoffmann 84d454574SPaolo Bonzini static QemuOptsList *vm_config_groups[32]; 9d058fe03SGerd Hoffmann 102ac20613SLuiz Capitulino static QemuOptsList *find_list(QemuOptsList **lists, const char *group, 112ac20613SLuiz Capitulino Error **errp) 12d058fe03SGerd Hoffmann { 13ddc97855SGerd Hoffmann int i; 14d058fe03SGerd Hoffmann 15d058fe03SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) { 16d058fe03SGerd Hoffmann if (strcmp(lists[i]->name, group) == 0) 17d058fe03SGerd Hoffmann break; 18d058fe03SGerd Hoffmann } 19d058fe03SGerd Hoffmann if (lists[i] == NULL) { 202ac20613SLuiz Capitulino error_set(errp, QERR_INVALID_OPTION_GROUP, group); 21ddc97855SGerd Hoffmann } 22ddc97855SGerd Hoffmann return lists[i]; 23ddc97855SGerd Hoffmann } 24ddc97855SGerd Hoffmann 25490b648eSKevin Wolf QemuOptsList *qemu_find_opts(const char *group) 26490b648eSKevin Wolf { 272ac20613SLuiz Capitulino QemuOptsList *ret; 282ac20613SLuiz Capitulino Error *local_err = NULL; 292ac20613SLuiz Capitulino 302ac20613SLuiz Capitulino ret = find_list(vm_config_groups, group, &local_err); 312ac20613SLuiz Capitulino if (error_is_set(&local_err)) { 32*312fd5f2SMarkus Armbruster error_report("%s", error_get_pretty(local_err)); 332ac20613SLuiz Capitulino error_free(local_err); 342ac20613SLuiz Capitulino } 352ac20613SLuiz Capitulino 362ac20613SLuiz Capitulino return ret; 37490b648eSKevin Wolf } 38490b648eSKevin Wolf 3960d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp) 4060d5666fSLuiz Capitulino { 4160d5666fSLuiz Capitulino return find_list(vm_config_groups, group, errp); 4260d5666fSLuiz Capitulino } 4360d5666fSLuiz Capitulino 44dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list) 45dfe795e7SGerd Hoffmann { 46dfe795e7SGerd Hoffmann int entries, i; 47dfe795e7SGerd Hoffmann 48dfe795e7SGerd Hoffmann entries = ARRAY_SIZE(vm_config_groups); 49dfe795e7SGerd Hoffmann entries--; /* keep list NULL terminated */ 50dfe795e7SGerd Hoffmann for (i = 0; i < entries; i++) { 51dfe795e7SGerd Hoffmann if (vm_config_groups[i] == NULL) { 52dfe795e7SGerd Hoffmann vm_config_groups[i] = list; 53dfe795e7SGerd Hoffmann return; 54dfe795e7SGerd Hoffmann } 55dfe795e7SGerd Hoffmann } 56dfe795e7SGerd Hoffmann fprintf(stderr, "ran out of space in vm_config_groups"); 57dfe795e7SGerd Hoffmann abort(); 58dfe795e7SGerd Hoffmann } 59dfe795e7SGerd Hoffmann 60ddc97855SGerd Hoffmann int qemu_set_option(const char *str) 61ddc97855SGerd Hoffmann { 62ddc97855SGerd Hoffmann char group[64], id[64], arg[64]; 63ddc97855SGerd Hoffmann QemuOptsList *list; 64ddc97855SGerd Hoffmann QemuOpts *opts; 65ddc97855SGerd Hoffmann int rc, offset; 66ddc97855SGerd Hoffmann 67ddc97855SGerd Hoffmann rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset); 68ddc97855SGerd Hoffmann if (rc < 3 || str[offset] != '=') { 691ecda02bSMarkus Armbruster error_report("can't parse: \"%s\"", str); 70d058fe03SGerd Hoffmann return -1; 71d058fe03SGerd Hoffmann } 72d058fe03SGerd Hoffmann 73304329eeSMarkus Armbruster list = qemu_find_opts(group); 74ddc97855SGerd Hoffmann if (list == NULL) { 75ddc97855SGerd Hoffmann return -1; 76ddc97855SGerd Hoffmann } 77ddc97855SGerd Hoffmann 78ddc97855SGerd Hoffmann opts = qemu_opts_find(list, id); 79d058fe03SGerd Hoffmann if (!opts) { 801ecda02bSMarkus Armbruster error_report("there is no %s \"%s\" defined", 81ddc97855SGerd Hoffmann list->name, id); 82d058fe03SGerd Hoffmann return -1; 83d058fe03SGerd Hoffmann } 84d058fe03SGerd Hoffmann 853df04ac3SMark McLoughlin if (qemu_opt_set(opts, arg, str+offset+1) == -1) { 86d058fe03SGerd Hoffmann return -1; 87d058fe03SGerd Hoffmann } 88d058fe03SGerd Hoffmann return 0; 89d058fe03SGerd Hoffmann } 90d058fe03SGerd Hoffmann 919d993394SGerd Hoffmann struct ConfigWriteData { 929d993394SGerd Hoffmann QemuOptsList *list; 939d993394SGerd Hoffmann FILE *fp; 949d993394SGerd Hoffmann }; 959d993394SGerd Hoffmann 969d993394SGerd Hoffmann static int config_write_opt(const char *name, const char *value, void *opaque) 979d993394SGerd Hoffmann { 989d993394SGerd Hoffmann struct ConfigWriteData *data = opaque; 999d993394SGerd Hoffmann 1009d993394SGerd Hoffmann fprintf(data->fp, " %s = \"%s\"\n", name, value); 1019d993394SGerd Hoffmann return 0; 1029d993394SGerd Hoffmann } 1039d993394SGerd Hoffmann 1049d993394SGerd Hoffmann static int config_write_opts(QemuOpts *opts, void *opaque) 1059d993394SGerd Hoffmann { 1069d993394SGerd Hoffmann struct ConfigWriteData *data = opaque; 1079d993394SGerd Hoffmann const char *id = qemu_opts_id(opts); 1089d993394SGerd Hoffmann 1099d993394SGerd Hoffmann if (id) { 1109d993394SGerd Hoffmann fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id); 1119d993394SGerd Hoffmann } else { 1129d993394SGerd Hoffmann fprintf(data->fp, "[%s]\n", data->list->name); 1139d993394SGerd Hoffmann } 1149d993394SGerd Hoffmann qemu_opt_foreach(opts, config_write_opt, data, 0); 1159d993394SGerd Hoffmann fprintf(data->fp, "\n"); 1169d993394SGerd Hoffmann return 0; 1179d993394SGerd Hoffmann } 1189d993394SGerd Hoffmann 1199d993394SGerd Hoffmann void qemu_config_write(FILE *fp) 1209d993394SGerd Hoffmann { 1219d993394SGerd Hoffmann struct ConfigWriteData data = { .fp = fp }; 122490b648eSKevin Wolf QemuOptsList **lists = vm_config_groups; 1239d993394SGerd Hoffmann int i; 1249d993394SGerd Hoffmann 1259d993394SGerd Hoffmann fprintf(fp, "# qemu config file\n\n"); 1269d993394SGerd Hoffmann for (i = 0; lists[i] != NULL; i++) { 1279d993394SGerd Hoffmann data.list = lists[i]; 1289d993394SGerd Hoffmann qemu_opts_foreach(data.list, config_write_opts, &data, 0); 1299d993394SGerd Hoffmann } 1309d993394SGerd Hoffmann } 13142262ba8SGerd Hoffmann 132490b648eSKevin Wolf int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname) 13342262ba8SGerd Hoffmann { 13442262ba8SGerd Hoffmann char line[1024], group[64], id[64], arg[64], value[1024]; 135cf5a65aaSMarkus Armbruster Location loc; 13642262ba8SGerd Hoffmann QemuOptsList *list = NULL; 1372ac20613SLuiz Capitulino Error *local_err = NULL; 13842262ba8SGerd Hoffmann QemuOpts *opts = NULL; 139cf5a65aaSMarkus Armbruster int res = -1, lno = 0; 14042262ba8SGerd Hoffmann 141cf5a65aaSMarkus Armbruster loc_push_none(&loc); 14242262ba8SGerd Hoffmann while (fgets(line, sizeof(line), fp) != NULL) { 143cf5a65aaSMarkus Armbruster loc_set_file(fname, ++lno); 14442262ba8SGerd Hoffmann if (line[0] == '\n') { 14542262ba8SGerd Hoffmann /* skip empty lines */ 14642262ba8SGerd Hoffmann continue; 14742262ba8SGerd Hoffmann } 14842262ba8SGerd Hoffmann if (line[0] == '#') { 14942262ba8SGerd Hoffmann /* comment */ 15042262ba8SGerd Hoffmann continue; 15142262ba8SGerd Hoffmann } 15242262ba8SGerd Hoffmann if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) { 15342262ba8SGerd Hoffmann /* group with id */ 1542ac20613SLuiz Capitulino list = find_list(lists, group, &local_err); 1552ac20613SLuiz Capitulino if (error_is_set(&local_err)) { 156*312fd5f2SMarkus Armbruster error_report("%s", error_get_pretty(local_err)); 1572ac20613SLuiz Capitulino error_free(local_err); 158cf5a65aaSMarkus Armbruster goto out; 1592ac20613SLuiz Capitulino } 1608be7e7e4SLuiz Capitulino opts = qemu_opts_create(list, id, 1, NULL); 16142262ba8SGerd Hoffmann continue; 16242262ba8SGerd Hoffmann } 16342262ba8SGerd Hoffmann if (sscanf(line, "[%63[^]]]", group) == 1) { 16442262ba8SGerd Hoffmann /* group without id */ 1652ac20613SLuiz Capitulino list = find_list(lists, group, &local_err); 1662ac20613SLuiz Capitulino if (error_is_set(&local_err)) { 167*312fd5f2SMarkus Armbruster error_report("%s", error_get_pretty(local_err)); 1682ac20613SLuiz Capitulino error_free(local_err); 169cf5a65aaSMarkus Armbruster goto out; 1702ac20613SLuiz Capitulino } 171e478b448SDong Xu Wang opts = qemu_opts_create_nofail(list); 17242262ba8SGerd Hoffmann continue; 17342262ba8SGerd Hoffmann } 17442262ba8SGerd Hoffmann if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) { 17542262ba8SGerd Hoffmann /* arg = value */ 17642262ba8SGerd Hoffmann if (opts == NULL) { 177cf5a65aaSMarkus Armbruster error_report("no group defined"); 178cf5a65aaSMarkus Armbruster goto out; 17942262ba8SGerd Hoffmann } 18042262ba8SGerd Hoffmann if (qemu_opt_set(opts, arg, value) != 0) { 181cf5a65aaSMarkus Armbruster goto out; 18242262ba8SGerd Hoffmann } 18342262ba8SGerd Hoffmann continue; 18442262ba8SGerd Hoffmann } 185cf5a65aaSMarkus Armbruster error_report("parse error"); 186cf5a65aaSMarkus Armbruster goto out; 18742262ba8SGerd Hoffmann } 188ef82516dSMarkus Armbruster if (ferror(fp)) { 189ef82516dSMarkus Armbruster error_report("error reading file"); 190ef82516dSMarkus Armbruster goto out; 191ef82516dSMarkus Armbruster } 192cf5a65aaSMarkus Armbruster res = 0; 193cf5a65aaSMarkus Armbruster out: 194cf5a65aaSMarkus Armbruster loc_pop(&loc); 195cf5a65aaSMarkus Armbruster return res; 19642262ba8SGerd Hoffmann } 197dcfb0939SKevin Wolf 198dcfb0939SKevin Wolf int qemu_read_config_file(const char *filename) 199dcfb0939SKevin Wolf { 200dcfb0939SKevin Wolf FILE *f = fopen(filename, "r"); 201019e78baSKevin Wolf int ret; 202019e78baSKevin Wolf 203dcfb0939SKevin Wolf if (f == NULL) { 204dcfb0939SKevin Wolf return -errno; 205dcfb0939SKevin Wolf } 206dcfb0939SKevin Wolf 207019e78baSKevin Wolf ret = qemu_config_parse(f, vm_config_groups, filename); 208dcfb0939SKevin Wolf fclose(f); 209dcfb0939SKevin Wolf 210019e78baSKevin Wolf if (ret == 0) { 211dcfb0939SKevin Wolf return 0; 212019e78baSKevin Wolf } else { 213019e78baSKevin Wolf return -EINVAL; 214019e78baSKevin Wolf } 215dcfb0939SKevin Wolf } 216