]> git.proxmox.com Git - qemu.git/blob - qemu-config.c
kvm: x86: Fix merge artifact of f8d926e9 about mp_state
[qemu.git] / qemu-config.c
1 #include "qemu-common.h"
2 #include "qemu-option.h"
3 #include "qemu-config.h"
4 #include "sysemu.h"
5
6 QemuOptsList qemu_drive_opts = {
7 .name = "drive",
8 .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
9 .desc = {
10 {
11 .name = "bus",
12 .type = QEMU_OPT_NUMBER,
13 .help = "bus number",
14 },{
15 .name = "unit",
16 .type = QEMU_OPT_NUMBER,
17 .help = "unit number (i.e. lun for scsi)",
18 },{
19 .name = "if",
20 .type = QEMU_OPT_STRING,
21 .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
22 },{
23 .name = "index",
24 .type = QEMU_OPT_NUMBER,
25 },{
26 .name = "cyls",
27 .type = QEMU_OPT_NUMBER,
28 .help = "number of cylinders (ide disk geometry)",
29 },{
30 .name = "heads",
31 .type = QEMU_OPT_NUMBER,
32 .help = "number of heads (ide disk geometry)",
33 },{
34 .name = "secs",
35 .type = QEMU_OPT_NUMBER,
36 .help = "number of sectors (ide disk geometry)",
37 },{
38 .name = "trans",
39 .type = QEMU_OPT_STRING,
40 .help = "chs translation (auto, lba. none)",
41 },{
42 .name = "media",
43 .type = QEMU_OPT_STRING,
44 .help = "media type (disk, cdrom)",
45 },{
46 .name = "snapshot",
47 .type = QEMU_OPT_BOOL,
48 },{
49 .name = "file",
50 .type = QEMU_OPT_STRING,
51 .help = "disk image",
52 },{
53 .name = "cache",
54 .type = QEMU_OPT_STRING,
55 .help = "host cache usage (none, writeback, writethrough)",
56 },{
57 .name = "aio",
58 .type = QEMU_OPT_STRING,
59 .help = "host AIO implementation (threads, native)",
60 },{
61 .name = "format",
62 .type = QEMU_OPT_STRING,
63 .help = "disk format (raw, qcow2, ...)",
64 },{
65 .name = "serial",
66 .type = QEMU_OPT_STRING,
67 },{
68 .name = "rerror",
69 .type = QEMU_OPT_STRING,
70 },{
71 .name = "werror",
72 .type = QEMU_OPT_STRING,
73 },{
74 .name = "addr",
75 .type = QEMU_OPT_STRING,
76 .help = "pci address (virtio only)",
77 },{
78 .name = "readonly",
79 .type = QEMU_OPT_BOOL,
80 },
81 { /* end if list */ }
82 },
83 };
84
85 QemuOptsList qemu_chardev_opts = {
86 .name = "chardev",
87 .head = QTAILQ_HEAD_INITIALIZER(qemu_chardev_opts.head),
88 .desc = {
89 {
90 .name = "backend",
91 .type = QEMU_OPT_STRING,
92 },{
93 .name = "path",
94 .type = QEMU_OPT_STRING,
95 },{
96 .name = "host",
97 .type = QEMU_OPT_STRING,
98 },{
99 .name = "port",
100 .type = QEMU_OPT_STRING,
101 },{
102 .name = "localaddr",
103 .type = QEMU_OPT_STRING,
104 },{
105 .name = "localport",
106 .type = QEMU_OPT_STRING,
107 },{
108 .name = "to",
109 .type = QEMU_OPT_NUMBER,
110 },{
111 .name = "ipv4",
112 .type = QEMU_OPT_BOOL,
113 },{
114 .name = "ipv6",
115 .type = QEMU_OPT_BOOL,
116 },{
117 .name = "wait",
118 .type = QEMU_OPT_BOOL,
119 },{
120 .name = "server",
121 .type = QEMU_OPT_BOOL,
122 },{
123 .name = "delay",
124 .type = QEMU_OPT_BOOL,
125 },{
126 .name = "telnet",
127 .type = QEMU_OPT_BOOL,
128 },{
129 .name = "width",
130 .type = QEMU_OPT_NUMBER,
131 },{
132 .name = "height",
133 .type = QEMU_OPT_NUMBER,
134 },{
135 .name = "cols",
136 .type = QEMU_OPT_NUMBER,
137 },{
138 .name = "rows",
139 .type = QEMU_OPT_NUMBER,
140 },{
141 .name = "mux",
142 .type = QEMU_OPT_BOOL,
143 },{
144 .name = "signal",
145 .type = QEMU_OPT_BOOL,
146 },
147 { /* end if list */ }
148 },
149 };
150
151 QemuOptsList qemu_device_opts = {
152 .name = "device",
153 .head = QTAILQ_HEAD_INITIALIZER(qemu_device_opts.head),
154 .desc = {
155 /*
156 * no elements => accept any
157 * sanity checking will happen later
158 * when setting device properties
159 */
160 { /* end if list */ }
161 },
162 };
163
164 QemuOptsList qemu_netdev_opts = {
165 .name = "netdev",
166 .head = QTAILQ_HEAD_INITIALIZER(qemu_netdev_opts.head),
167 .desc = {
168 /*
169 * no elements => accept any params
170 * validation will happen later
171 */
172 { /* end of list */ }
173 },
174 };
175
176 QemuOptsList qemu_net_opts = {
177 .name = "net",
178 .head = QTAILQ_HEAD_INITIALIZER(qemu_net_opts.head),
179 .desc = {
180 /*
181 * no elements => accept any params
182 * validation will happen later
183 */
184 { /* end of list */ }
185 },
186 };
187
188 QemuOptsList qemu_rtc_opts = {
189 .name = "rtc",
190 .head = QTAILQ_HEAD_INITIALIZER(qemu_rtc_opts.head),
191 .desc = {
192 {
193 .name = "base",
194 .type = QEMU_OPT_STRING,
195 },{
196 .name = "clock",
197 .type = QEMU_OPT_STRING,
198 #ifdef TARGET_I386
199 },{
200 .name = "driftfix",
201 .type = QEMU_OPT_STRING,
202 #endif
203 },
204 { /* end if list */ }
205 },
206 };
207
208 static QemuOptsList *lists[] = {
209 &qemu_drive_opts,
210 &qemu_chardev_opts,
211 &qemu_device_opts,
212 &qemu_netdev_opts,
213 &qemu_net_opts,
214 &qemu_rtc_opts,
215 NULL,
216 };
217
218 static QemuOptsList *find_list(const char *group)
219 {
220 int i;
221
222 for (i = 0; lists[i] != NULL; i++) {
223 if (strcmp(lists[i]->name, group) == 0)
224 break;
225 }
226 if (lists[i] == NULL) {
227 qemu_error("there is no option group \"%s\"\n", group);
228 }
229 return lists[i];
230 }
231
232 int qemu_set_option(const char *str)
233 {
234 char group[64], id[64], arg[64];
235 QemuOptsList *list;
236 QemuOpts *opts;
237 int rc, offset;
238
239 rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
240 if (rc < 3 || str[offset] != '=') {
241 qemu_error("can't parse: \"%s\"\n", str);
242 return -1;
243 }
244
245 list = find_list(group);
246 if (list == NULL) {
247 return -1;
248 }
249
250 opts = qemu_opts_find(list, id);
251 if (!opts) {
252 qemu_error("there is no %s \"%s\" defined\n",
253 list->name, id);
254 return -1;
255 }
256
257 if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
258 return -1;
259 }
260 return 0;
261 }
262
263 struct ConfigWriteData {
264 QemuOptsList *list;
265 FILE *fp;
266 };
267
268 static int config_write_opt(const char *name, const char *value, void *opaque)
269 {
270 struct ConfigWriteData *data = opaque;
271
272 fprintf(data->fp, " %s = \"%s\"\n", name, value);
273 return 0;
274 }
275
276 static int config_write_opts(QemuOpts *opts, void *opaque)
277 {
278 struct ConfigWriteData *data = opaque;
279 const char *id = qemu_opts_id(opts);
280
281 if (id) {
282 fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
283 } else {
284 fprintf(data->fp, "[%s]\n", data->list->name);
285 }
286 qemu_opt_foreach(opts, config_write_opt, data, 0);
287 fprintf(data->fp, "\n");
288 return 0;
289 }
290
291 void qemu_config_write(FILE *fp)
292 {
293 struct ConfigWriteData data = { .fp = fp };
294 int i;
295
296 fprintf(fp, "# qemu config file\n\n");
297 for (i = 0; lists[i] != NULL; i++) {
298 data.list = lists[i];
299 qemu_opts_foreach(data.list, config_write_opts, &data, 0);
300 }
301 }
302
303 int qemu_config_parse(FILE *fp)
304 {
305 char line[1024], group[64], id[64], arg[64], value[1024];
306 QemuOptsList *list = NULL;
307 QemuOpts *opts = NULL;
308
309 while (fgets(line, sizeof(line), fp) != NULL) {
310 if (line[0] == '\n') {
311 /* skip empty lines */
312 continue;
313 }
314 if (line[0] == '#') {
315 /* comment */
316 continue;
317 }
318 if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
319 /* group with id */
320 list = find_list(group);
321 if (list == NULL)
322 return -1;
323 opts = qemu_opts_create(list, id, 1);
324 continue;
325 }
326 if (sscanf(line, "[%63[^]]]", group) == 1) {
327 /* group without id */
328 list = find_list(group);
329 if (list == NULL)
330 return -1;
331 opts = qemu_opts_create(list, NULL, 0);
332 continue;
333 }
334 if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
335 /* arg = value */
336 if (opts == NULL) {
337 fprintf(stderr, "no group defined\n");
338 return -1;
339 }
340 if (qemu_opt_set(opts, arg, value) != 0) {
341 fprintf(stderr, "failed to set \"%s\" for %s\n",
342 arg, group);
343 return -1;
344 }
345 continue;
346 }
347 fprintf(stderr, "parse error: %s\n", line);
348 return -1;
349 }
350 return 0;
351 }