xref: /openbmc/qemu/util/qemu-config.c (revision fd506b4f)
1 #include "qemu-common.h"
2 #include "qemu/error-report.h"
3 #include "qemu/option.h"
4 #include "qemu/config-file.h"
5 #include "qapi/qmp/qerror.h"
6 #include "hw/qdev.h"
7 #include "qapi/error.h"
8 #include "qmp-commands.h"
9 
10 static QemuOptsList *vm_config_groups[32];
11 
12 static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
13                                Error **errp)
14 {
15     int i;
16 
17     for (i = 0; lists[i] != NULL; i++) {
18         if (strcmp(lists[i]->name, group) == 0)
19             break;
20     }
21     if (lists[i] == NULL) {
22         error_set(errp, QERR_INVALID_OPTION_GROUP, group);
23     }
24     return lists[i];
25 }
26 
27 QemuOptsList *qemu_find_opts(const char *group)
28 {
29     QemuOptsList *ret;
30     Error *local_err = NULL;
31 
32     ret = find_list(vm_config_groups, group, &local_err);
33     if (error_is_set(&local_err)) {
34         error_report("%s", error_get_pretty(local_err));
35         error_free(local_err);
36     }
37 
38     return ret;
39 }
40 
41 static CommandLineParameterInfoList *query_option_descs(const QemuOptDesc *desc)
42 {
43     CommandLineParameterInfoList *param_list = NULL, *entry;
44     CommandLineParameterInfo *info;
45     int i;
46 
47     for (i = 0; desc[i].name != NULL; i++) {
48         info = g_malloc0(sizeof(*info));
49         info->name = g_strdup(desc[i].name);
50 
51         switch (desc[i].type) {
52         case QEMU_OPT_STRING:
53             info->type = COMMAND_LINE_PARAMETER_TYPE_STRING;
54             break;
55         case QEMU_OPT_BOOL:
56             info->type = COMMAND_LINE_PARAMETER_TYPE_BOOLEAN;
57             break;
58         case QEMU_OPT_NUMBER:
59             info->type = COMMAND_LINE_PARAMETER_TYPE_NUMBER;
60             break;
61         case QEMU_OPT_SIZE:
62             info->type = COMMAND_LINE_PARAMETER_TYPE_SIZE;
63             break;
64         }
65 
66         if (desc[i].help) {
67             info->has_help = true;
68             info->help = g_strdup(desc[i].help);
69         }
70 
71         entry = g_malloc0(sizeof(*entry));
72         entry->value = info;
73         entry->next = param_list;
74         param_list = entry;
75     }
76 
77     return param_list;
78 }
79 
80 CommandLineOptionInfoList *qmp_query_command_line_options(bool has_option,
81                                                           const char *option,
82                                                           Error **errp)
83 {
84     CommandLineOptionInfoList *conf_list = NULL, *entry;
85     CommandLineOptionInfo *info;
86     int i;
87 
88     for (i = 0; vm_config_groups[i] != NULL; i++) {
89         if (!has_option || !strcmp(option, vm_config_groups[i]->name)) {
90             info = g_malloc0(sizeof(*info));
91             info->option = g_strdup(vm_config_groups[i]->name);
92             info->parameters = query_option_descs(vm_config_groups[i]->desc);
93             entry = g_malloc0(sizeof(*entry));
94             entry->value = info;
95             entry->next = conf_list;
96             conf_list = entry;
97         }
98     }
99 
100     if (conf_list == NULL) {
101         error_setg(errp, "invalid option name: %s", option);
102     }
103 
104     return conf_list;
105 }
106 
107 QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
108 {
109     return find_list(vm_config_groups, group, errp);
110 }
111 
112 void qemu_add_opts(QemuOptsList *list)
113 {
114     int entries, i;
115 
116     entries = ARRAY_SIZE(vm_config_groups);
117     entries--; /* keep list NULL terminated */
118     for (i = 0; i < entries; i++) {
119         if (vm_config_groups[i] == NULL) {
120             vm_config_groups[i] = list;
121             return;
122         }
123     }
124     fprintf(stderr, "ran out of space in vm_config_groups");
125     abort();
126 }
127 
128 int qemu_set_option(const char *str)
129 {
130     char group[64], id[64], arg[64];
131     QemuOptsList *list;
132     QemuOpts *opts;
133     int rc, offset;
134 
135     rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
136     if (rc < 3 || str[offset] != '=') {
137         error_report("can't parse: \"%s\"", str);
138         return -1;
139     }
140 
141     list = qemu_find_opts(group);
142     if (list == NULL) {
143         return -1;
144     }
145 
146     opts = qemu_opts_find(list, id);
147     if (!opts) {
148         error_report("there is no %s \"%s\" defined",
149                      list->name, id);
150         return -1;
151     }
152 
153     if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
154         return -1;
155     }
156     return 0;
157 }
158 
159 struct ConfigWriteData {
160     QemuOptsList *list;
161     FILE *fp;
162 };
163 
164 static int config_write_opt(const char *name, const char *value, void *opaque)
165 {
166     struct ConfigWriteData *data = opaque;
167 
168     fprintf(data->fp, "  %s = \"%s\"\n", name, value);
169     return 0;
170 }
171 
172 static int config_write_opts(QemuOpts *opts, void *opaque)
173 {
174     struct ConfigWriteData *data = opaque;
175     const char *id = qemu_opts_id(opts);
176 
177     if (id) {
178         fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
179     } else {
180         fprintf(data->fp, "[%s]\n", data->list->name);
181     }
182     qemu_opt_foreach(opts, config_write_opt, data, 0);
183     fprintf(data->fp, "\n");
184     return 0;
185 }
186 
187 void qemu_config_write(FILE *fp)
188 {
189     struct ConfigWriteData data = { .fp = fp };
190     QemuOptsList **lists = vm_config_groups;
191     int i;
192 
193     fprintf(fp, "# qemu config file\n\n");
194     for (i = 0; lists[i] != NULL; i++) {
195         data.list = lists[i];
196         qemu_opts_foreach(data.list, config_write_opts, &data, 0);
197     }
198 }
199 
200 int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
201 {
202     char line[1024], group[64], id[64], arg[64], value[1024];
203     Location loc;
204     QemuOptsList *list = NULL;
205     Error *local_err = NULL;
206     QemuOpts *opts = NULL;
207     int res = -1, lno = 0;
208 
209     loc_push_none(&loc);
210     while (fgets(line, sizeof(line), fp) != NULL) {
211         loc_set_file(fname, ++lno);
212         if (line[0] == '\n') {
213             /* skip empty lines */
214             continue;
215         }
216         if (line[0] == '#') {
217             /* comment */
218             continue;
219         }
220         if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
221             /* group with id */
222             list = find_list(lists, group, &local_err);
223             if (error_is_set(&local_err)) {
224                 error_report("%s", error_get_pretty(local_err));
225                 error_free(local_err);
226                 goto out;
227             }
228             opts = qemu_opts_create(list, id, 1, NULL);
229             continue;
230         }
231         if (sscanf(line, "[%63[^]]]", group) == 1) {
232             /* group without id */
233             list = find_list(lists, group, &local_err);
234             if (error_is_set(&local_err)) {
235                 error_report("%s", error_get_pretty(local_err));
236                 error_free(local_err);
237                 goto out;
238             }
239             opts = qemu_opts_create_nofail(list);
240             continue;
241         }
242         if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
243             /* arg = value */
244             if (opts == NULL) {
245                 error_report("no group defined");
246                 goto out;
247             }
248             if (qemu_opt_set(opts, arg, value) != 0) {
249                 goto out;
250             }
251             continue;
252         }
253         error_report("parse error");
254         goto out;
255     }
256     if (ferror(fp)) {
257         error_report("error reading file");
258         goto out;
259     }
260     res = 0;
261 out:
262     loc_pop(&loc);
263     return res;
264 }
265 
266 int qemu_read_config_file(const char *filename)
267 {
268     FILE *f = fopen(filename, "r");
269     int ret;
270 
271     if (f == NULL) {
272         return -errno;
273     }
274 
275     ret = qemu_config_parse(f, vm_config_groups, filename);
276     fclose(f);
277 
278     if (ret == 0) {
279         return 0;
280     } else {
281         return -EINVAL;
282     }
283 }
284