linux-user: Use safe_syscall for execve syscall
[qemu.git] / qapi / qmp-output-visitor.c
1 /*
2 * Core Definitions for QAPI/QMP Command Registry
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/qmp-output-visitor.h"
17 #include "qapi/visitor-impl.h"
18 #include "qemu/queue.h"
19 #include "qemu-common.h"
20 #include "qapi/qmp/types.h"
21
22 typedef struct QStackEntry
23 {
24 QObject *value;
25 QTAILQ_ENTRY(QStackEntry) node;
26 } QStackEntry;
27
28 typedef QTAILQ_HEAD(QStack, QStackEntry) QStack;
29
30 struct QmpOutputVisitor
31 {
32 Visitor visitor;
33 QStack stack; /* Stack of containers that haven't yet been finished */
34 QObject *root; /* Root of the output visit */
35 };
36
37 #define qmp_output_add(qov, name, value) \
38 qmp_output_add_obj(qov, name, QOBJECT(value))
39 #define qmp_output_push(qov, value) qmp_output_push_obj(qov, QOBJECT(value))
40
41 static QmpOutputVisitor *to_qov(Visitor *v)
42 {
43 return container_of(v, QmpOutputVisitor, visitor);
44 }
45
46 /* Push @value onto the stack of current QObjects being built */
47 static void qmp_output_push_obj(QmpOutputVisitor *qov, QObject *value)
48 {
49 QStackEntry *e = g_malloc0(sizeof(*e));
50
51 assert(qov->root);
52 assert(value);
53 e->value = value;
54 QTAILQ_INSERT_HEAD(&qov->stack, e, node);
55 }
56
57 /* Pop a value off the stack of QObjects being built, and return it. */
58 static QObject *qmp_output_pop(QmpOutputVisitor *qov)
59 {
60 QStackEntry *e = QTAILQ_FIRST(&qov->stack);
61 QObject *value;
62
63 assert(e);
64 QTAILQ_REMOVE(&qov->stack, e, node);
65 value = e->value;
66 assert(value);
67 g_free(e);
68 return value;
69 }
70
71 /* Add @value to the current QObject being built.
72 * If the stack is visiting a dictionary or list, @value is now owned
73 * by that container. Otherwise, @value is now the root. */
74 static void qmp_output_add_obj(QmpOutputVisitor *qov, const char *name,
75 QObject *value)
76 {
77 QStackEntry *e = QTAILQ_FIRST(&qov->stack);
78 QObject *cur = e ? e->value : NULL;
79
80 if (!cur) {
81 /* Don't allow reuse of visitor on more than one root */
82 assert(!qov->root);
83 qov->root = value;
84 } else {
85 switch (qobject_type(cur)) {
86 case QTYPE_QDICT:
87 assert(name);
88 qdict_put_obj(qobject_to_qdict(cur), name, value);
89 break;
90 case QTYPE_QLIST:
91 assert(!name);
92 qlist_append_obj(qobject_to_qlist(cur), value);
93 break;
94 default:
95 g_assert_not_reached();
96 }
97 }
98 }
99
100 static void qmp_output_start_struct(Visitor *v, const char *name, void **obj,
101 size_t unused, Error **errp)
102 {
103 QmpOutputVisitor *qov = to_qov(v);
104 QDict *dict = qdict_new();
105
106 qmp_output_add(qov, name, dict);
107 qmp_output_push(qov, dict);
108 }
109
110 static void qmp_output_end_struct(Visitor *v)
111 {
112 QmpOutputVisitor *qov = to_qov(v);
113 QObject *value = qmp_output_pop(qov);
114 assert(qobject_type(value) == QTYPE_QDICT);
115 }
116
117 static void qmp_output_start_list(Visitor *v, const char *name,
118 GenericList **listp, size_t size,
119 Error **errp)
120 {
121 QmpOutputVisitor *qov = to_qov(v);
122 QList *list = qlist_new();
123
124 qmp_output_add(qov, name, list);
125 qmp_output_push(qov, list);
126 }
127
128 static GenericList *qmp_output_next_list(Visitor *v, GenericList *tail,
129 size_t size)
130 {
131 return tail->next;
132 }
133
134 static void qmp_output_end_list(Visitor *v)
135 {
136 QmpOutputVisitor *qov = to_qov(v);
137 QObject *value = qmp_output_pop(qov);
138 assert(qobject_type(value) == QTYPE_QLIST);
139 }
140
141 static void qmp_output_type_int64(Visitor *v, const char *name, int64_t *obj,
142 Error **errp)
143 {
144 QmpOutputVisitor *qov = to_qov(v);
145 qmp_output_add(qov, name, qint_from_int(*obj));
146 }
147
148 static void qmp_output_type_uint64(Visitor *v, const char *name, uint64_t *obj,
149 Error **errp)
150 {
151 /* FIXME: QMP outputs values larger than INT64_MAX as negative */
152 QmpOutputVisitor *qov = to_qov(v);
153 qmp_output_add(qov, name, qint_from_int(*obj));
154 }
155
156 static void qmp_output_type_bool(Visitor *v, const char *name, bool *obj,
157 Error **errp)
158 {
159 QmpOutputVisitor *qov = to_qov(v);
160 qmp_output_add(qov, name, qbool_from_bool(*obj));
161 }
162
163 static void qmp_output_type_str(Visitor *v, const char *name, char **obj,
164 Error **errp)
165 {
166 QmpOutputVisitor *qov = to_qov(v);
167 if (*obj) {
168 qmp_output_add(qov, name, qstring_from_str(*obj));
169 } else {
170 qmp_output_add(qov, name, qstring_from_str(""));
171 }
172 }
173
174 static void qmp_output_type_number(Visitor *v, const char *name, double *obj,
175 Error **errp)
176 {
177 QmpOutputVisitor *qov = to_qov(v);
178 qmp_output_add(qov, name, qfloat_from_double(*obj));
179 }
180
181 static void qmp_output_type_any(Visitor *v, const char *name, QObject **obj,
182 Error **errp)
183 {
184 QmpOutputVisitor *qov = to_qov(v);
185 qobject_incref(*obj);
186 qmp_output_add_obj(qov, name, *obj);
187 }
188
189 static void qmp_output_type_null(Visitor *v, const char *name, Error **errp)
190 {
191 QmpOutputVisitor *qov = to_qov(v);
192 qmp_output_add_obj(qov, name, qnull());
193 }
194
195 /* Finish building, and return the root object.
196 * The root object is never null. The caller becomes the object's
197 * owner, and should use qobject_decref() when done with it. */
198 QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
199 {
200 /* A visit must have occurred, with each start paired with end. */
201 assert(qov->root && QTAILQ_EMPTY(&qov->stack));
202
203 qobject_incref(qov->root);
204 return qov->root;
205 }
206
207 Visitor *qmp_output_get_visitor(QmpOutputVisitor *v)
208 {
209 return &v->visitor;
210 }
211
212 void qmp_output_visitor_cleanup(QmpOutputVisitor *v)
213 {
214 QStackEntry *e, *tmp;
215
216 QTAILQ_FOREACH_SAFE(e, &v->stack, node, tmp) {
217 QTAILQ_REMOVE(&v->stack, e, node);
218 g_free(e);
219 }
220
221 qobject_decref(v->root);
222 g_free(v);
223 }
224
225 QmpOutputVisitor *qmp_output_visitor_new(void)
226 {
227 QmpOutputVisitor *v;
228
229 v = g_malloc0(sizeof(*v));
230
231 v->visitor.type = VISITOR_OUTPUT;
232 v->visitor.start_struct = qmp_output_start_struct;
233 v->visitor.end_struct = qmp_output_end_struct;
234 v->visitor.start_list = qmp_output_start_list;
235 v->visitor.next_list = qmp_output_next_list;
236 v->visitor.end_list = qmp_output_end_list;
237 v->visitor.type_int64 = qmp_output_type_int64;
238 v->visitor.type_uint64 = qmp_output_type_uint64;
239 v->visitor.type_bool = qmp_output_type_bool;
240 v->visitor.type_str = qmp_output_type_str;
241 v->visitor.type_number = qmp_output_type_number;
242 v->visitor.type_any = qmp_output_type_any;
243 v->visitor.type_null = qmp_output_type_null;
244
245 QTAILQ_INIT(&v->stack);
246
247 return v;
248 }