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