xref: /qemu/qapi/qapi-visit-core.c (revision 727385c4)
1 /*
2  * Core Definitions for QAPI Visitor Classes
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/compat-policy.h"
17 #include "qapi/error.h"
18 #include "qapi/qmp/qerror.h"
19 #include "qapi/visitor.h"
20 #include "qapi/visitor-impl.h"
21 #include "trace.h"
22 
23 /* Zero-initialization must result in default policy */
24 QEMU_BUILD_BUG_ON(COMPAT_POLICY_INPUT_ACCEPT || COMPAT_POLICY_OUTPUT_ACCEPT);
25 
26 
27 void visit_complete(Visitor *v, void *opaque)
28 {
29     assert(v->type != VISITOR_OUTPUT || v->complete);
30     trace_visit_complete(v, opaque);
31     if (v->complete) {
32         v->complete(v, opaque);
33     }
34 }
35 
36 void visit_free(Visitor *v)
37 {
38     trace_visit_free(v);
39     if (v) {
40         v->free(v);
41     }
42 }
43 
44 bool visit_start_struct(Visitor *v, const char *name, void **obj,
45                         size_t size, Error **errp)
46 {
47     bool ok;
48 
49     trace_visit_start_struct(v, name, obj, size);
50     if (obj) {
51         assert(size);
52         assert(!(v->type & VISITOR_OUTPUT) || *obj);
53     }
54     ok = v->start_struct(v, name, obj, size, errp);
55     if (obj && (v->type & VISITOR_INPUT)) {
56         assert(ok != !*obj);
57     }
58     return ok;
59 }
60 
61 bool visit_check_struct(Visitor *v, Error **errp)
62 {
63     trace_visit_check_struct(v);
64     return v->check_struct ? v->check_struct(v, errp) : true;
65 }
66 
67 void visit_end_struct(Visitor *v, void **obj)
68 {
69     trace_visit_end_struct(v, obj);
70     v->end_struct(v, obj);
71 }
72 
73 bool visit_start_list(Visitor *v, const char *name, GenericList **list,
74                       size_t size, Error **errp)
75 {
76     bool ok;
77 
78     assert(!list || size >= sizeof(GenericList));
79     trace_visit_start_list(v, name, list, size);
80     ok = v->start_list(v, name, list, size, errp);
81     if (list && (v->type & VISITOR_INPUT)) {
82         assert(ok || !*list);
83     }
84     return ok;
85 }
86 
87 GenericList *visit_next_list(Visitor *v, GenericList *tail, size_t size)
88 {
89     assert(tail && size >= sizeof(GenericList));
90     trace_visit_next_list(v, tail, size);
91     return v->next_list(v, tail, size);
92 }
93 
94 bool visit_check_list(Visitor *v, Error **errp)
95 {
96     trace_visit_check_list(v);
97     return v->check_list ? v->check_list(v, errp) : true;
98 }
99 
100 void visit_end_list(Visitor *v, void **obj)
101 {
102     trace_visit_end_list(v, obj);
103     v->end_list(v, obj);
104 }
105 
106 bool visit_start_alternate(Visitor *v, const char *name,
107                            GenericAlternate **obj, size_t size,
108                            Error **errp)
109 {
110     bool ok;
111 
112     assert(obj && size >= sizeof(GenericAlternate));
113     assert(!(v->type & VISITOR_OUTPUT) || *obj);
114     trace_visit_start_alternate(v, name, obj, size);
115     if (!v->start_alternate) {
116         assert(!(v->type & VISITOR_INPUT));
117         return true;
118     }
119     ok = v->start_alternate(v, name, obj, size, errp);
120     if (v->type & VISITOR_INPUT) {
121         assert(ok != !*obj);
122     }
123     return ok;
124 }
125 
126 void visit_end_alternate(Visitor *v, void **obj)
127 {
128     trace_visit_end_alternate(v, obj);
129     if (v->end_alternate) {
130         v->end_alternate(v, obj);
131     }
132 }
133 
134 bool visit_optional(Visitor *v, const char *name, bool *present)
135 {
136     trace_visit_optional(v, name, present);
137     if (v->optional) {
138         v->optional(v, name, present);
139     }
140     return *present;
141 }
142 
143 bool visit_policy_reject(Visitor *v, const char *name,
144                          unsigned special_features, Error **errp)
145 {
146     trace_visit_policy_reject(v, name);
147     if (v->policy_reject) {
148         return v->policy_reject(v, name, special_features, errp);
149     }
150     return false;
151 }
152 
153 bool visit_policy_skip(Visitor *v, const char *name,
154                        unsigned special_features)
155 {
156     trace_visit_policy_skip(v, name);
157     if (v->policy_skip) {
158         return v->policy_skip(v, name, special_features);
159     }
160     return false;
161 }
162 
163 void visit_set_policy(Visitor *v, CompatPolicy *policy)
164 {
165     v->compat_policy = *policy;
166 }
167 
168 bool visit_is_input(Visitor *v)
169 {
170     return v->type == VISITOR_INPUT;
171 }
172 
173 bool visit_is_dealloc(Visitor *v)
174 {
175     return v->type == VISITOR_DEALLOC;
176 }
177 
178 bool visit_type_int(Visitor *v, const char *name, int64_t *obj, Error **errp)
179 {
180     assert(obj);
181     trace_visit_type_int(v, name, obj);
182     return v->type_int64(v, name, obj, errp);
183 }
184 
185 static bool visit_type_uintN(Visitor *v, uint64_t *obj, const char *name,
186                              uint64_t max, const char *type, Error **errp)
187 {
188     uint64_t value = *obj;
189 
190     assert(v->type == VISITOR_INPUT || value <= max);
191 
192     if (!v->type_uint64(v, name, &value, errp)) {
193         return false;
194     }
195     if (value > max) {
196         assert(v->type == VISITOR_INPUT);
197         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
198                    name ? name : "null", type);
199         return false;
200     }
201     *obj = value;
202     return true;
203 }
204 
205 bool visit_type_uint8(Visitor *v, const char *name, uint8_t *obj,
206                       Error **errp)
207 {
208     uint64_t value;
209     bool ok;
210 
211     trace_visit_type_uint8(v, name, obj);
212     value = *obj;
213     ok = visit_type_uintN(v, &value, name, UINT8_MAX, "uint8_t", errp);
214     *obj = value;
215     return ok;
216 }
217 
218 bool visit_type_uint16(Visitor *v, const char *name, uint16_t *obj,
219                        Error **errp)
220 {
221     uint64_t value;
222     bool ok;
223 
224     trace_visit_type_uint16(v, name, obj);
225     value = *obj;
226     ok = visit_type_uintN(v, &value, name, UINT16_MAX, "uint16_t", errp);
227     *obj = value;
228     return ok;
229 }
230 
231 bool visit_type_uint32(Visitor *v, const char *name, uint32_t *obj,
232                        Error **errp)
233 {
234     uint64_t value;
235     bool ok;
236 
237     trace_visit_type_uint32(v, name, obj);
238     value = *obj;
239     ok = visit_type_uintN(v, &value, name, UINT32_MAX, "uint32_t", errp);
240     *obj = value;
241     return ok;
242 }
243 
244 bool visit_type_uint64(Visitor *v, const char *name, uint64_t *obj,
245                        Error **errp)
246 {
247     assert(obj);
248     trace_visit_type_uint64(v, name, obj);
249     return v->type_uint64(v, name, obj, errp);
250 }
251 
252 static bool visit_type_intN(Visitor *v, int64_t *obj, const char *name,
253                             int64_t min, int64_t max, const char *type,
254                             Error **errp)
255 {
256     int64_t value = *obj;
257 
258     assert(v->type == VISITOR_INPUT || (value >= min && value <= max));
259 
260     if (!v->type_int64(v, name, &value, errp)) {
261         return false;
262     }
263     if (value < min || value > max) {
264         assert(v->type == VISITOR_INPUT);
265         error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
266                    name ? name : "null", type);
267         return false;
268     }
269     *obj = value;
270     return true;
271 }
272 
273 bool visit_type_int8(Visitor *v, const char *name, int8_t *obj, Error **errp)
274 {
275     int64_t value;
276     bool ok;
277 
278     trace_visit_type_int8(v, name, obj);
279     value = *obj;
280     ok = visit_type_intN(v, &value, name, INT8_MIN, INT8_MAX, "int8_t", errp);
281     *obj = value;
282     return ok;
283 }
284 
285 bool visit_type_int16(Visitor *v, const char *name, int16_t *obj,
286                       Error **errp)
287 {
288     int64_t value;
289     bool ok;
290 
291     trace_visit_type_int16(v, name, obj);
292     value = *obj;
293     ok = visit_type_intN(v, &value, name, INT16_MIN, INT16_MAX, "int16_t",
294                          errp);
295     *obj = value;
296     return ok;
297 }
298 
299 bool visit_type_int32(Visitor *v, const char *name, int32_t *obj,
300                       Error **errp)
301 {
302     int64_t value;
303     bool ok;
304 
305     trace_visit_type_int32(v, name, obj);
306     value = *obj;
307     ok = visit_type_intN(v, &value, name, INT32_MIN, INT32_MAX, "int32_t",
308                         errp);
309     *obj = value;
310     return ok;
311 }
312 
313 bool visit_type_int64(Visitor *v, const char *name, int64_t *obj,
314                       Error **errp)
315 {
316     assert(obj);
317     trace_visit_type_int64(v, name, obj);
318     return v->type_int64(v, name, obj, errp);
319 }
320 
321 bool visit_type_size(Visitor *v, const char *name, uint64_t *obj,
322                      Error **errp)
323 {
324     assert(obj);
325     trace_visit_type_size(v, name, obj);
326     if (v->type_size) {
327         return v->type_size(v, name, obj, errp);
328     }
329     return v->type_uint64(v, name, obj, errp);
330 }
331 
332 bool visit_type_bool(Visitor *v, const char *name, bool *obj, Error **errp)
333 {
334     assert(obj);
335     trace_visit_type_bool(v, name, obj);
336     return v->type_bool(v, name, obj, errp);
337 }
338 
339 bool visit_type_str(Visitor *v, const char *name, char **obj, Error **errp)
340 {
341     bool ok;
342 
343     assert(obj);
344     /* TODO: Fix callers to not pass NULL when they mean "", so that we
345      * can enable:
346     assert(!(v->type & VISITOR_OUTPUT) || *obj);
347      */
348     trace_visit_type_str(v, name, obj);
349     ok = v->type_str(v, name, obj, errp);
350     if (v->type & VISITOR_INPUT) {
351         assert(ok != !*obj);
352     }
353     return ok;
354 }
355 
356 bool visit_type_number(Visitor *v, const char *name, double *obj,
357                        Error **errp)
358 {
359     assert(obj);
360     trace_visit_type_number(v, name, obj);
361     return v->type_number(v, name, obj, errp);
362 }
363 
364 bool visit_type_any(Visitor *v, const char *name, QObject **obj, Error **errp)
365 {
366     bool ok;
367 
368     assert(obj);
369     assert(v->type != VISITOR_OUTPUT || *obj);
370     trace_visit_type_any(v, name, obj);
371     ok = v->type_any(v, name, obj, errp);
372     if (v->type == VISITOR_INPUT) {
373         assert(ok != !*obj);
374     }
375     return ok;
376 }
377 
378 bool visit_type_null(Visitor *v, const char *name, QNull **obj,
379                      Error **errp)
380 {
381     trace_visit_type_null(v, name, obj);
382     return v->type_null(v, name, obj, errp);
383 }
384 
385 static bool output_type_enum(Visitor *v, const char *name, int *obj,
386                              const QEnumLookup *lookup, Error **errp)
387 {
388     int value = *obj;
389     char *enum_str;
390 
391     enum_str = (char *)qapi_enum_lookup(lookup, value);
392     return visit_type_str(v, name, &enum_str, errp);
393 }
394 
395 static bool input_type_enum(Visitor *v, const char *name, int *obj,
396                             const QEnumLookup *lookup, Error **errp)
397 {
398     int64_t value;
399     g_autofree char *enum_str = NULL;
400 
401     if (!visit_type_str(v, name, &enum_str, errp)) {
402         return false;
403     }
404 
405     value = qapi_enum_parse(lookup, enum_str, -1, NULL);
406     if (value < 0) {
407         error_setg(errp, "Parameter '%s' does not accept value '%s'",
408                    name ? name : "null", enum_str);
409         return false;
410     }
411 
412     if (lookup->special_features
413         && !compat_policy_input_ok(lookup->special_features[value],
414                                    &v->compat_policy,
415                                    ERROR_CLASS_GENERIC_ERROR,
416                                    "value", enum_str, errp)) {
417         return false;
418     }
419 
420     *obj = value;
421     return true;
422 }
423 
424 bool visit_type_enum(Visitor *v, const char *name, int *obj,
425                      const QEnumLookup *lookup, Error **errp)
426 {
427     assert(obj && lookup);
428     trace_visit_type_enum(v, name, obj);
429     switch (v->type) {
430     case VISITOR_INPUT:
431         return input_type_enum(v, name, obj, lookup, errp);
432     case VISITOR_OUTPUT:
433         return output_type_enum(v, name, obj, lookup, errp);
434     case VISITOR_CLONE:
435         /* nothing further to do, scalar value was already copied by
436          * g_memdup() during visit_start_*() */
437         return true;
438     case VISITOR_DEALLOC:
439         /* nothing to deallocate for a scalar */
440         return true;
441     default:
442         abort();
443     }
444 }
445