xref: /qemu/util/qemu-config.c (revision 1f8f987d349f8f1bace4b47a83323b68ab0e084c)
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"
6d0fef6fbSGerd Hoffmann #include "hw/qdev.h"
77b1b5d19SPaolo Bonzini #include "qapi/error.h"
8*1f8f987dSAmos Kong #include "qmp-commands.h"
97282a033SGerd Hoffmann 
104d454574SPaolo Bonzini static QemuOptsList *vm_config_groups[32];
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) {
222ac20613SLuiz Capitulino         error_set(errp, QERR_INVALID_OPTION_GROUP, 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);
332ac20613SLuiz Capitulino     if (error_is_set(&local_err)) {
34312fd5f2SMarkus Armbruster         error_report("%s", error_get_pretty(local_err));
352ac20613SLuiz Capitulino         error_free(local_err);
362ac20613SLuiz Capitulino     }
372ac20613SLuiz Capitulino 
382ac20613SLuiz Capitulino     return ret;
39490b648eSKevin Wolf }
40490b648eSKevin Wolf 
41*1f8f987dSAmos Kong static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
42*1f8f987dSAmos Kong {
43*1f8f987dSAmos Kong     CommandLineParameterInfoList *param_list = NULL, *entry;
44*1f8f987dSAmos Kong     CommandLineParameterInfo *info;
45*1f8f987dSAmos Kong     int i;
46*1f8f987dSAmos Kong 
47*1f8f987dSAmos Kong     for (i = 0; desc[i].name != NULL; i++) {
48*1f8f987dSAmos Kong         info = g_malloc0(sizeof(*info));
49*1f8f987dSAmos Kong         info->name = g_strdup(desc[i].name);
50*1f8f987dSAmos Kong 
51*1f8f987dSAmos Kong         switch (desc[i].type) {
52*1f8f987dSAmos Kong         case QEMU_OPT_STRING:
53*1f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
54*1f8f987dSAmos Kong             break;
55*1f8f987dSAmos Kong         case QEMU_OPT_BOOL:
56*1f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
57*1f8f987dSAmos Kong             break;
58*1f8f987dSAmos Kong         case QEMU_OPT_NUMBER:
59*1f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
60*1f8f987dSAmos Kong             break;
61*1f8f987dSAmos Kong         case QEMU_OPT_SIZE:
62*1f8f987dSAmos Kong             info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
63*1f8f987dSAmos Kong             break;
64*1f8f987dSAmos Kong         }
65*1f8f987dSAmos Kong 
66*1f8f987dSAmos Kong         if (desc[i].help) {
67*1f8f987dSAmos Kong             info->has_help = true;
68*1f8f987dSAmos Kong             info->help = g_strdup(desc[i].help);
69*1f8f987dSAmos Kong         }
70*1f8f987dSAmos Kong 
71*1f8f987dSAmos Kong         entry = g_malloc0(sizeof(*entry));
72*1f8f987dSAmos Kong         entry->value = info;
73*1f8f987dSAmos Kong         entry->next = param_list;
74*1f8f987dSAmos Kong         param_list = entry;
75*1f8f987dSAmos Kong     }
76*1f8f987dSAmos Kong 
77*1f8f987dSAmos Kong     return param_list;
78*1f8f987dSAmos Kong }
79*1f8f987dSAmos Kong 
80*1f8f987dSAmos Kong CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
81*1f8f987dSAmos Kong                                                           const char *option,
82*1f8f987dSAmos Kong                                                           Error **errp)
83*1f8f987dSAmos Kong {
84*1f8f987dSAmos Kong     CommandLineOptionInfoList *conf_list = NULL, *entry;
85*1f8f987dSAmos Kong     CommandLineOptionInfo *info;
86*1f8f987dSAmos Kong     int i;
87*1f8f987dSAmos Kong 
88*1f8f987dSAmos Kong     for (i = 0; vm_config_groups[i] != NULL; i++) {
89*1f8f987dSAmos Kong         if (!has_option || !strcmp(option, vm_config_groups[i]->name)) {
90*1f8f987dSAmos Kong             info = g_malloc0(sizeof(*info));
91*1f8f987dSAmos Kong             info->option = g_strdup(vm_config_groups[i]->name);
92*1f8f987dSAmos Kong             info->parameters = query_option_descs(vm_config_groups[i]->desc);
93*1f8f987dSAmos Kong             entry = g_malloc0(sizeof(*entry));
94*1f8f987dSAmos Kong             entry->value = info;
95*1f8f987dSAmos Kong             entry->next = conf_list;
96*1f8f987dSAmos Kong             conf_list = entry;
97*1f8f987dSAmos Kong         }
98*1f8f987dSAmos Kong     }
99*1f8f987dSAmos Kong 
100*1f8f987dSAmos Kong     if (conf_list == NULL) {
101*1f8f987dSAmos Kong         error_setg(errp, "invalid option name: %s", option);
102*1f8f987dSAmos Kong     }
103*1f8f987dSAmos Kong 
104*1f8f987dSAmos Kong     return conf_list;
105*1f8f987dSAmos Kong }
106*1f8f987dSAmos Kong 
10760d5666fSLuiz Capitulino QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
10860d5666fSLuiz Capitulino {
10960d5666fSLuiz Capitulino     return find_list(vm_config_groups, group, errp);
11060d5666fSLuiz Capitulino }
11160d5666fSLuiz Capitulino 
112dfe795e7SGerd Hoffmann void qemu_add_opts(QemuOptsList *list)
113dfe795e7SGerd Hoffmann {
114dfe795e7SGerd Hoffmann     int entries, i;
115dfe795e7SGerd Hoffmann 
116dfe795e7SGerd Hoffmann     entries = ARRAY_SIZE(vm_config_groups);
117dfe795e7SGerd Hoffmann     entries--; /* keep list NULL terminated */
118dfe795e7SGerd Hoffmann     for (i = 0; i < entries; i++) {
119dfe795e7SGerd Hoffmann         if (vm_config_groups[i] == NULL) {
120dfe795e7SGerd Hoffmann             vm_config_groups[i] = list;
121dfe795e7SGerd Hoffmann             return;
122dfe795e7SGerd Hoffmann         }
123dfe795e7SGerd Hoffmann     }
124dfe795e7SGerd Hoffmann     fprintf(stderr, "ran out of space in vm_config_groups");
125dfe795e7SGerd Hoffmann     abort();
126dfe795e7SGerd Hoffmann }
127dfe795e7SGerd Hoffmann 
128ddc97855SGerd Hoffmann int qemu_set_option(const char *str)
129ddc97855SGerd Hoffmann {
130ddc97855SGerd Hoffmann     char group[64], id[64], arg[64];
131ddc97855SGerd Hoffmann     QemuOptsList *list;
132ddc97855SGerd Hoffmann     QemuOpts *opts;
133ddc97855SGerd Hoffmann     int rc, offset;
134ddc97855SGerd Hoffmann 
135ddc97855SGerd Hoffmann     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
136ddc97855SGerd Hoffmann     if (rc < 3 || str[offset] != '=') {
1371ecda02bSMarkus Armbruster         error_report("can't parse: \"%s\"", str);
138d058fe03SGerd Hoffmann         return -1;
139d058fe03SGerd Hoffmann     }
140d058fe03SGerd Hoffmann 
141304329eeSMarkus Armbruster     list = qemu_find_opts(group);
142ddc97855SGerd Hoffmann     if (list == NULL) {
143ddc97855SGerd Hoffmann         return -1;
144ddc97855SGerd Hoffmann     }
145ddc97855SGerd Hoffmann 
146ddc97855SGerd Hoffmann     opts = qemu_opts_find(list, id);
147d058fe03SGerd Hoffmann     if (!opts) {
1481ecda02bSMarkus Armbruster         error_report("there is no %s \"%s\" defined",
149ddc97855SGerd Hoffmann                      list->name, id);
150d058fe03SGerd Hoffmann         return -1;
151d058fe03SGerd Hoffmann     }
152d058fe03SGerd Hoffmann 
1533df04ac3SMark McLoughlin     if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
154d058fe03SGerd Hoffmann         return -1;
155d058fe03SGerd Hoffmann     }
156d058fe03SGerd Hoffmann     return 0;
157d058fe03SGerd Hoffmann }
158d058fe03SGerd Hoffmann 
1599d993394SGerd Hoffmann struct ConfigWriteData {
1609d993394SGerd Hoffmann     QemuOptsList *list;
1619d993394SGerd Hoffmann     FILE *fp;
1629d993394SGerd Hoffmann };
1639d993394SGerd Hoffmann 
1649d993394SGerd Hoffmann static int config_write_opt(const char *name, const char *value, void *opaque)
1659d993394SGerd Hoffmann {
1669d993394SGerd Hoffmann     struct ConfigWriteData *data = opaque;
1679d993394SGerd Hoffmann 
1689d993394SGerd Hoffmann     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
1699d993394SGerd Hoffmann     return 0;
1709d993394SGerd Hoffmann }
1719d993394SGerd Hoffmann 
1729d993394SGerd Hoffmann static int config_write_opts(QemuOpts *opts, void *opaque)
1739d993394SGerd Hoffmann {
1749d993394SGerd Hoffmann     struct ConfigWriteData *data = opaque;
1759d993394SGerd Hoffmann     const char *id = qemu_opts_id(opts);
1769d993394SGerd Hoffmann 
1779d993394SGerd Hoffmann     if (id) {
1789d993394SGerd Hoffmann         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
1799d993394SGerd Hoffmann     } else {
1809d993394SGerd Hoffmann         fprintf(data->fp, "[%s]\n", data->list->name);
1819d993394SGerd Hoffmann     }
1829d993394SGerd Hoffmann     qemu_opt_foreach(opts, config_write_opt, data, 0);
1839d993394SGerd Hoffmann     fprintf(data->fp, "\n");
1849d993394SGerd Hoffmann     return 0;
1859d993394SGerd Hoffmann }
1869d993394SGerd Hoffmann 
1879d993394SGerd Hoffmann void qemu_config_write(FILE *fp)
1889d993394SGerd Hoffmann {
1899d993394SGerd Hoffmann     struct ConfigWriteData data = { .fp = fp };
190490b648eSKevin Wolf     QemuOptsList **lists = vm_config_groups;
1919d993394SGerd Hoffmann     int i;
1929d993394SGerd Hoffmann 
1939d993394SGerd Hoffmann     fprintf(fp, "# qemu config file\n\n");
1949d993394SGerd Hoffmann     for (i = 0; lists[i] != NULL; i++) {
1959d993394SGerd Hoffmann         data.list = lists[i];
1969d993394SGerd Hoffmann         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
1979d993394SGerd Hoffmann     }
1989d993394SGerd Hoffmann }
19942262ba8SGerd Hoffmann 
200490b648eSKevin Wolf int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
20142262ba8SGerd Hoffmann {
20242262ba8SGerd Hoffmann     char line[1024], group[64], id[64], arg[64], value[1024];
203cf5a65aaSMarkus Armbruster     Location loc;
20442262ba8SGerd Hoffmann     QemuOptsList *list = NULL;
2052ac20613SLuiz Capitulino     Error *local_err = NULL;
20642262ba8SGerd Hoffmann     QemuOpts *opts = NULL;
207cf5a65aaSMarkus Armbruster     int res = -1, lno = 0;
20842262ba8SGerd Hoffmann 
209cf5a65aaSMarkus Armbruster     loc_push_none(&loc);
21042262ba8SGerd Hoffmann     while (fgets(line, sizeof(line), fp) != NULL) {
211cf5a65aaSMarkus Armbruster         loc_set_file(fname, ++lno);
21242262ba8SGerd Hoffmann         if (line[0] == '\n') {
21342262ba8SGerd Hoffmann             /* skip empty lines */
21442262ba8SGerd Hoffmann             continue;
21542262ba8SGerd Hoffmann         }
21642262ba8SGerd Hoffmann         if (line[0] == '#') {
21742262ba8SGerd Hoffmann             /* comment */
21842262ba8SGerd Hoffmann             continue;
21942262ba8SGerd Hoffmann         }
22042262ba8SGerd Hoffmann         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
22142262ba8SGerd Hoffmann             /* group with id */
2222ac20613SLuiz Capitulino             list = find_list(lists, group, &local_err);
2232ac20613SLuiz Capitulino             if (error_is_set(&local_err)) {
224312fd5f2SMarkus Armbruster                 error_report("%s", error_get_pretty(local_err));
2252ac20613SLuiz Capitulino                 error_free(local_err);
226cf5a65aaSMarkus Armbruster                 goto out;
2272ac20613SLuiz Capitulino             }
2288be7e7e4SLuiz Capitulino             opts = qemu_opts_create(list, id, 1, NULL);
22942262ba8SGerd Hoffmann             continue;
23042262ba8SGerd Hoffmann         }
23142262ba8SGerd Hoffmann         if (sscanf(line, "[%63[^]]]", group) == 1) {
23242262ba8SGerd Hoffmann             /* group without id */
2332ac20613SLuiz Capitulino             list = find_list(lists, group, &local_err);
2342ac20613SLuiz Capitulino             if (error_is_set(&local_err)) {
235312fd5f2SMarkus Armbruster                 error_report("%s", error_get_pretty(local_err));
2362ac20613SLuiz Capitulino                 error_free(local_err);
237cf5a65aaSMarkus Armbruster                 goto out;
2382ac20613SLuiz Capitulino             }
239e478b448SDong Xu Wang             opts = qemu_opts_create_nofail(list);
24042262ba8SGerd Hoffmann             continue;
24142262ba8SGerd Hoffmann         }
24242262ba8SGerd Hoffmann         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
24342262ba8SGerd Hoffmann             /* arg = value */
24442262ba8SGerd Hoffmann             if (opts == NULL) {
245cf5a65aaSMarkus Armbruster                 error_report("no group defined");
246cf5a65aaSMarkus Armbruster                 goto out;
24742262ba8SGerd Hoffmann             }
24842262ba8SGerd Hoffmann             if (qemu_opt_set(opts, arg, value) != 0) {
249cf5a65aaSMarkus Armbruster                 goto out;
25042262ba8SGerd Hoffmann             }
25142262ba8SGerd Hoffmann             continue;
25242262ba8SGerd Hoffmann         }
253cf5a65aaSMarkus Armbruster         error_report("parse error");
254cf5a65aaSMarkus Armbruster         goto out;
25542262ba8SGerd Hoffmann     }
256ef82516dSMarkus Armbruster     if (ferror(fp)) {
257ef82516dSMarkus Armbruster         error_report("error reading file");
258ef82516dSMarkus Armbruster         goto out;
259ef82516dSMarkus Armbruster     }
260cf5a65aaSMarkus Armbruster     res = 0;
261cf5a65aaSMarkus Armbruster out:
262cf5a65aaSMarkus Armbruster     loc_pop(&loc);
263cf5a65aaSMarkus Armbruster     return res;
26442262ba8SGerd Hoffmann }
265dcfb0939SKevin Wolf 
266dcfb0939SKevin Wolf int qemu_read_config_file(const char *filename)
267dcfb0939SKevin Wolf {
268dcfb0939SKevin Wolf     FILE *f = fopen(filename, "r");
269019e78baSKevin Wolf     int ret;
270019e78baSKevin Wolf 
271dcfb0939SKevin Wolf     if (f == NULL) {
272dcfb0939SKevin Wolf         return -errno;
273dcfb0939SKevin Wolf     }
274dcfb0939SKevin Wolf 
275019e78baSKevin Wolf     ret = qemu_config_parse(f, vm_config_groups, filename);
276dcfb0939SKevin Wolf     fclose(f);
277dcfb0939SKevin Wolf 
278019e78baSKevin Wolf     if (ret == 0) {
279dcfb0939SKevin Wolf         return 0;
280019e78baSKevin Wolf     } else {
281019e78baSKevin Wolf         return -EINVAL;
282019e78baSKevin Wolf     }
283dcfb0939SKevin Wolf }
284