linux-user: Use safe_syscall for execve syscall
[qemu.git] / qapi / qmp-input-visitor.c
1 /*
2 * Input Visitor
3 *
4 * Copyright (C) 2012-2016 Red Hat, Inc.
5 * Copyright IBM, Corp. 2011
6 *
7 * Authors:
8 * Anthony Liguori <aliguori@us.ibm.com>
9 *
10 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
11 * See the COPYING.LIB file in the top-level directory.
12 *
13 */
14
15 #include "qemu/osdep.h"
16 #include "qapi/error.h"
17 #include "qapi/qmp-input-visitor.h"
18 #include "qapi/visitor-impl.h"
19 #include "qemu/queue.h"
20 #include "qemu-common.h"
21 #include "qapi/qmp/types.h"
22 #include "qapi/qmp/qerror.h"
23
24 #define QIV_STACK_SIZE 1024
25
26 typedef struct StackObject
27 {
28 QObject *obj; /* Object being visited */
29
30 GHashTable *h; /* If obj is dict: unvisited keys */
31 const QListEntry *entry; /* If obj is list: unvisited tail */
32 } StackObject;
33
34 struct QmpInputVisitor
35 {
36 Visitor visitor;
37
38 /* Root of visit at visitor creation. */
39 QObject *root;
40
41 /* Stack of objects being visited (all entries will be either
42 * QDict or QList). */
43 StackObject stack[QIV_STACK_SIZE];
44 int nb_stack;
45
46 /* True to reject parse in visit_end_struct() if unvisited keys remain. */
47 bool strict;
48 };
49
50 static QmpInputVisitor *to_qiv(Visitor *v)
51 {
52 return container_of(v, QmpInputVisitor, visitor);
53 }
54
55 static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
56 const char *name,
57 bool consume)
58 {
59 StackObject *tos;
60 QObject *qobj;
61 QObject *ret;
62
63 if (!qiv->nb_stack) {
64 /* Starting at root, name is ignored. */
65 return qiv->root;
66 }
67
68 /* We are in a container; find the next element. */
69 tos = &qiv->stack[qiv->nb_stack - 1];
70 qobj = tos->obj;
71 assert(qobj);
72
73 if (qobject_type(qobj) == QTYPE_QDICT) {
74 assert(name);
75 ret = qdict_get(qobject_to_qdict(qobj), name);
76 if (tos->h && consume && ret) {
77 bool removed = g_hash_table_remove(tos->h, name);
78 assert(removed);
79 }
80 } else {
81 assert(qobject_type(qobj) == QTYPE_QLIST);
82 assert(!name);
83 ret = qlist_entry_obj(tos->entry);
84 if (consume) {
85 tos->entry = qlist_next(tos->entry);
86 }
87 }
88
89 return ret;
90 }
91
92 static void qdict_add_key(const char *key, QObject *obj, void *opaque)
93 {
94 GHashTable *h = opaque;
95 g_hash_table_insert(h, (gpointer) key, NULL);
96 }
97
98 static const QListEntry *qmp_input_push(QmpInputVisitor *qiv, QObject *obj,
99 Error **errp)
100 {
101 GHashTable *h;
102 StackObject *tos = &qiv->stack[qiv->nb_stack];
103
104 assert(obj);
105 if (qiv->nb_stack >= QIV_STACK_SIZE) {
106 error_setg(errp, "An internal buffer overran");
107 return NULL;
108 }
109
110 tos->obj = obj;
111 assert(!tos->h);
112 assert(!tos->entry);
113
114 if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
115 h = g_hash_table_new(g_str_hash, g_str_equal);
116 qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
117 tos->h = h;
118 } else if (qobject_type(obj) == QTYPE_QLIST) {
119 tos->entry = qlist_first(qobject_to_qlist(obj));
120 }
121
122 qiv->nb_stack++;
123 return tos->entry;
124 }
125
126
127 static void qmp_input_check_struct(Visitor *v, Error **errp)
128 {
129 QmpInputVisitor *qiv = to_qiv(v);
130 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
131
132 assert(qiv->nb_stack > 0);
133
134 if (qiv->strict) {
135 GHashTable *const top_ht = tos->h;
136 if (top_ht) {
137 GHashTableIter iter;
138 const char *key;
139
140 g_hash_table_iter_init(&iter, top_ht);
141 if (g_hash_table_iter_next(&iter, (void **)&key, NULL)) {
142 error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
143 }
144 }
145 }
146 }
147
148 static void qmp_input_pop(Visitor *v)
149 {
150 QmpInputVisitor *qiv = to_qiv(v);
151 StackObject *tos = &qiv->stack[qiv->nb_stack - 1];
152
153 assert(qiv->nb_stack > 0);
154
155 if (qiv->strict) {
156 GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
157 if (top_ht) {
158 g_hash_table_unref(top_ht);
159 }
160 tos->h = NULL;
161 }
162
163 qiv->nb_stack--;
164 }
165
166 static void qmp_input_start_struct(Visitor *v, const char *name, void **obj,
167 size_t size, Error **errp)
168 {
169 QmpInputVisitor *qiv = to_qiv(v);
170 QObject *qobj = qmp_input_get_object(qiv, name, true);
171 Error *err = NULL;
172
173 if (obj) {
174 *obj = NULL;
175 }
176 if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
177 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
178 "QDict");
179 return;
180 }
181
182 qmp_input_push(qiv, qobj, &err);
183 if (err) {
184 error_propagate(errp, err);
185 return;
186 }
187
188 if (obj) {
189 *obj = g_malloc0(size);
190 }
191 }
192
193
194 static void qmp_input_start_list(Visitor *v, const char *name,
195 GenericList **list, size_t size, Error **errp)
196 {
197 QmpInputVisitor *qiv = to_qiv(v);
198 QObject *qobj = qmp_input_get_object(qiv, name, true);
199 const QListEntry *entry;
200
201 if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
202 if (list) {
203 *list = NULL;
204 }
205 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
206 "list");
207 return;
208 }
209
210 entry = qmp_input_push(qiv, qobj, errp);
211 if (list) {
212 if (entry) {
213 *list = g_malloc0(size);
214 } else {
215 *list = NULL;
216 }
217 }
218 }
219
220 static GenericList *qmp_input_next_list(Visitor *v, GenericList *tail,
221 size_t size)
222 {
223 QmpInputVisitor *qiv = to_qiv(v);
224 StackObject *so = &qiv->stack[qiv->nb_stack - 1];
225
226 if (!so->entry) {
227 return NULL;
228 }
229 tail->next = g_malloc0(size);
230 return tail->next;
231 }
232
233
234 static void qmp_input_start_alternate(Visitor *v, const char *name,
235 GenericAlternate **obj, size_t size,
236 bool promote_int, Error **errp)
237 {
238 QmpInputVisitor *qiv = to_qiv(v);
239 QObject *qobj = qmp_input_get_object(qiv, name, false);
240
241 if (!qobj) {
242 *obj = NULL;
243 error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
244 return;
245 }
246 *obj = g_malloc0(size);
247 (*obj)->type = qobject_type(qobj);
248 if (promote_int && (*obj)->type == QTYPE_QINT) {
249 (*obj)->type = QTYPE_QFLOAT;
250 }
251 }
252
253 static void qmp_input_type_int64(Visitor *v, const char *name, int64_t *obj,
254 Error **errp)
255 {
256 QmpInputVisitor *qiv = to_qiv(v);
257 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
258
259 if (!qint) {
260 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
261 "integer");
262 return;
263 }
264
265 *obj = qint_get_int(qint);
266 }
267
268 static void qmp_input_type_uint64(Visitor *v, const char *name, uint64_t *obj,
269 Error **errp)
270 {
271 /* FIXME: qobject_to_qint mishandles values over INT64_MAX */
272 QmpInputVisitor *qiv = to_qiv(v);
273 QInt *qint = qobject_to_qint(qmp_input_get_object(qiv, name, true));
274
275 if (!qint) {
276 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
277 "integer");
278 return;
279 }
280
281 *obj = qint_get_int(qint);
282 }
283
284 static void qmp_input_type_bool(Visitor *v, const char *name, bool *obj,
285 Error **errp)
286 {
287 QmpInputVisitor *qiv = to_qiv(v);
288 QBool *qbool = qobject_to_qbool(qmp_input_get_object(qiv, name, true));
289
290 if (!qbool) {
291 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
292 "boolean");
293 return;
294 }
295
296 *obj = qbool_get_bool(qbool);
297 }
298
299 static void qmp_input_type_str(Visitor *v, const char *name, char **obj,
300 Error **errp)
301 {
302 QmpInputVisitor *qiv = to_qiv(v);
303 QString *qstr = qobject_to_qstring(qmp_input_get_object(qiv, name, true));
304
305 if (!qstr) {
306 *obj = NULL;
307 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
308 "string");
309 return;
310 }
311
312 *obj = g_strdup(qstring_get_str(qstr));
313 }
314
315 static void qmp_input_type_number(Visitor *v, const char *name, double *obj,
316 Error **errp)
317 {
318 QmpInputVisitor *qiv = to_qiv(v);
319 QObject *qobj = qmp_input_get_object(qiv, name, true);
320 QInt *qint;
321 QFloat *qfloat;
322
323 qint = qobject_to_qint(qobj);
324 if (qint) {
325 *obj = qint_get_int(qobject_to_qint(qobj));
326 return;
327 }
328
329 qfloat = qobject_to_qfloat(qobj);
330 if (qfloat) {
331 *obj = qfloat_get_double(qobject_to_qfloat(qobj));
332 return;
333 }
334
335 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
336 "number");
337 }
338
339 static void qmp_input_type_any(Visitor *v, const char *name, QObject **obj,
340 Error **errp)
341 {
342 QmpInputVisitor *qiv = to_qiv(v);
343 QObject *qobj = qmp_input_get_object(qiv, name, true);
344
345 qobject_incref(qobj);
346 *obj = qobj;
347 }
348
349 static void qmp_input_type_null(Visitor *v, const char *name, Error **errp)
350 {
351 QmpInputVisitor *qiv = to_qiv(v);
352 QObject *qobj = qmp_input_get_object(qiv, name, true);
353
354 if (qobject_type(qobj) != QTYPE_QNULL) {
355 error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
356 "null");
357 }
358 }
359
360 static void qmp_input_optional(Visitor *v, const char *name, bool *present)
361 {
362 QmpInputVisitor *qiv = to_qiv(v);
363 QObject *qobj = qmp_input_get_object(qiv, name, false);
364
365 if (!qobj) {
366 *present = false;
367 return;
368 }
369
370 *present = true;
371 }
372
373 Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
374 {
375 return &v->visitor;
376 }
377
378 void qmp_input_visitor_cleanup(QmpInputVisitor *v)
379 {
380 qobject_decref(v->root);
381 g_free(v);
382 }
383
384 QmpInputVisitor *qmp_input_visitor_new(QObject *obj, bool strict)
385 {
386 QmpInputVisitor *v;
387
388 v = g_malloc0(sizeof(*v));
389
390 v->visitor.type = VISITOR_INPUT;
391 v->visitor.start_struct = qmp_input_start_struct;
392 v->visitor.check_struct = qmp_input_check_struct;
393 v->visitor.end_struct = qmp_input_pop;
394 v->visitor.start_list = qmp_input_start_list;
395 v->visitor.next_list = qmp_input_next_list;
396 v->visitor.end_list = qmp_input_pop;
397 v->visitor.start_alternate = qmp_input_start_alternate;
398 v->visitor.type_int64 = qmp_input_type_int64;
399 v->visitor.type_uint64 = qmp_input_type_uint64;
400 v->visitor.type_bool = qmp_input_type_bool;
401 v->visitor.type_str = qmp_input_type_str;
402 v->visitor.type_number = qmp_input_type_number;
403 v->visitor.type_any = qmp_input_type_any;
404 v->visitor.type_null = qmp_input_type_null;
405 v->visitor.optional = qmp_input_optional;
406 v->strict = strict;
407
408 v->root = obj;
409 qobject_incref(obj);
410
411 return v;
412 }