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/compat-policy.h" 17 #include "qapi/qobject-output-visitor.h" 18 #include "qapi/visitor-impl.h" 19 #include "qemu/queue.h" 20 #include "qapi/qmp/qbool.h" 21 #include "qapi/qmp/qdict.h" 22 #include "qapi/qmp/qlist.h" 23 #include "qapi/qmp/qnull.h" 24 #include "qapi/qmp/qnum.h" 25 #include "qapi/qmp/qstring.h" 26 27 typedef struct QStackEntry { 28 QObject *value; 29 void *qapi; /* sanity check that caller uses same pointer */ 30 QSLIST_ENTRY(QStackEntry) node; 31 } QStackEntry; 32 33 struct QObjectOutputVisitor { 34 Visitor visitor; 35 36 QSLIST_HEAD(, QStackEntry) stack; /* Stack of unfinished containers */ 37 QObject *root; /* Root of the output visit */ 38 QObject **result; /* User's storage location for result */ 39 }; 40 41 #define qobject_output_add(qov, name, value) \ 42 qobject_output_add_obj(qov, name, QOBJECT(value)) 43 #define qobject_output_push(qov, value, qapi) \ 44 qobject_output_push_obj(qov, QOBJECT(value), qapi) 45 46 static QObjectOutputVisitor *to_qov(Visitor *v) 47 { 48 return container_of(v, QObjectOutputVisitor, visitor); 49 } 50 51 /* Push @value onto the stack of current QObjects being built */ 52 static void qobject_output_push_obj(QObjectOutputVisitor *qov, QObject *value, 53 void *qapi) 54 { 55 QStackEntry *e = g_malloc0(sizeof(*e)); 56 57 assert(qov->root); 58 assert(value); 59 e->value = value; 60 e->qapi = qapi; 61 QSLIST_INSERT_HEAD(&qov->stack, e, node); 62 } 63 64 /* Pop a value off the stack of QObjects being built, and return it. */ 65 static QObject *qobject_output_pop(QObjectOutputVisitor *qov, void *qapi) 66 { 67 QStackEntry *e = QSLIST_FIRST(&qov->stack); 68 QObject *value; 69 70 assert(e); 71 assert(e->qapi == qapi); 72 QSLIST_REMOVE_HEAD(&qov->stack, node); 73 value = e->value; 74 assert(value); 75 g_free(e); 76 return value; 77 } 78 79 /* Add @value to the current QObject being built. 80 * If the stack is visiting a dictionary or list, @value is now owned 81 * by that container. Otherwise, @value is now the root. */ 82 static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name, 83 QObject *value) 84 { 85 QStackEntry *e = QSLIST_FIRST(&qov->stack); 86 QObject *cur = e ? e->value : NULL; 87 88 if (!cur) { 89 /* Don't allow reuse of visitor on more than one root */ 90 assert(!qov->root); 91 qov->root = value; 92 } else { 93 switch (qobject_type(cur)) { 94 case QTYPE_QDICT: 95 assert(name); 96 qdict_put_obj(qobject_to(QDict, cur), name, value); 97 break; 98 case QTYPE_QLIST: 99 assert(!name); 100 qlist_append_obj(qobject_to(QList, cur), value); 101 break; 102 default: 103 g_assert_not_reached(); 104 } 105 } 106 } 107 108 static bool qobject_output_start_struct(Visitor *v, const char *name, 109 void **obj, size_t unused, Error **errp) 110 { 111 QObjectOutputVisitor *qov = to_qov(v); 112 QDict *dict = qdict_new(); 113 114 qobject_output_add(qov, name, dict); 115 qobject_output_push(qov, dict, obj); 116 return true; 117 } 118 119 static void qobject_output_end_struct(Visitor *v, void **obj) 120 { 121 QObjectOutputVisitor *qov = to_qov(v); 122 QObject *value = qobject_output_pop(qov, obj); 123 assert(qobject_type(value) == QTYPE_QDICT); 124 } 125 126 static bool qobject_output_start_list(Visitor *v, const char *name, 127 GenericList **listp, size_t size, 128 Error **errp) 129 { 130 QObjectOutputVisitor *qov = to_qov(v); 131 QList *list = qlist_new(); 132 133 qobject_output_add(qov, name, list); 134 qobject_output_push(qov, list, listp); 135 return true; 136 } 137 138 static GenericList *qobject_output_next_list(Visitor *v, GenericList *tail, 139 size_t size) 140 { 141 return tail->next; 142 } 143 144 static void qobject_output_end_list(Visitor *v, void **obj) 145 { 146 QObjectOutputVisitor *qov = to_qov(v); 147 QObject *value = qobject_output_pop(qov, obj); 148 assert(qobject_type(value) == QTYPE_QLIST); 149 } 150 151 static bool qobject_output_type_int64(Visitor *v, const char *name, 152 int64_t *obj, Error **errp) 153 { 154 QObjectOutputVisitor *qov = to_qov(v); 155 qobject_output_add(qov, name, qnum_from_int(*obj)); 156 return true; 157 } 158 159 static bool qobject_output_type_uint64(Visitor *v, const char *name, 160 uint64_t *obj, Error **errp) 161 { 162 QObjectOutputVisitor *qov = to_qov(v); 163 qobject_output_add(qov, name, qnum_from_uint(*obj)); 164 return true; 165 } 166 167 static bool qobject_output_type_bool(Visitor *v, const char *name, bool *obj, 168 Error **errp) 169 { 170 QObjectOutputVisitor *qov = to_qov(v); 171 qobject_output_add(qov, name, qbool_from_bool(*obj)); 172 return true; 173 } 174 175 static bool qobject_output_type_str(Visitor *v, const char *name, char **obj, 176 Error **errp) 177 { 178 QObjectOutputVisitor *qov = to_qov(v); 179 if (*obj) { 180 qobject_output_add(qov, name, qstring_from_str(*obj)); 181 } else { 182 qobject_output_add(qov, name, qstring_from_str("")); 183 } 184 return true; 185 } 186 187 static bool qobject_output_type_number(Visitor *v, const char *name, 188 double *obj, Error **errp) 189 { 190 QObjectOutputVisitor *qov = to_qov(v); 191 qobject_output_add(qov, name, qnum_from_double(*obj)); 192 return true; 193 } 194 195 static bool qobject_output_type_any(Visitor *v, const char *name, 196 QObject **obj, Error **errp) 197 { 198 QObjectOutputVisitor *qov = to_qov(v); 199 200 qobject_output_add_obj(qov, name, qobject_ref(*obj)); 201 return true; 202 } 203 204 static bool qobject_output_type_null(Visitor *v, const char *name, 205 QNull **obj, Error **errp) 206 { 207 QObjectOutputVisitor *qov = to_qov(v); 208 qobject_output_add(qov, name, qnull()); 209 return true; 210 } 211 212 static bool qobject_output_policy_skip(Visitor *v, const char *name, 213 unsigned special_features) 214 { 215 CompatPolicy *pol = &v->compat_policy; 216 217 return ((special_features & 1u << QAPI_DEPRECATED) 218 && pol->deprecated_output == COMPAT_POLICY_OUTPUT_HIDE) 219 || ((special_features & 1u << QAPI_UNSTABLE) 220 && pol->unstable_output == COMPAT_POLICY_OUTPUT_HIDE); 221 } 222 223 /* Finish building, and return the root object. 224 * The root object is never null. The caller becomes the object's 225 * owner, and should use qobject_unref() when done with it. */ 226 static void qobject_output_complete(Visitor *v, void *opaque) 227 { 228 QObjectOutputVisitor *qov = to_qov(v); 229 230 /* A visit must have occurred, with each start paired with end. */ 231 assert(qov->root && QSLIST_EMPTY(&qov->stack)); 232 assert(opaque == qov->result); 233 234 *qov->result = qobject_ref(qov->root); 235 qov->result = NULL; 236 } 237 238 static void qobject_output_free(Visitor *v) 239 { 240 QObjectOutputVisitor *qov = to_qov(v); 241 QStackEntry *e; 242 243 while (!QSLIST_EMPTY(&qov->stack)) { 244 e = QSLIST_FIRST(&qov->stack); 245 QSLIST_REMOVE_HEAD(&qov->stack, node); 246 g_free(e); 247 } 248 249 qobject_unref(qov->root); 250 g_free(qov); 251 } 252 253 Visitor *qobject_output_visitor_new(QObject **result) 254 { 255 QObjectOutputVisitor *v; 256 257 v = g_malloc0(sizeof(*v)); 258 259 v->visitor.type = VISITOR_OUTPUT; 260 v->visitor.start_struct = qobject_output_start_struct; 261 v->visitor.end_struct = qobject_output_end_struct; 262 v->visitor.start_list = qobject_output_start_list; 263 v->visitor.next_list = qobject_output_next_list; 264 v->visitor.end_list = qobject_output_end_list; 265 v->visitor.type_int64 = qobject_output_type_int64; 266 v->visitor.type_uint64 = qobject_output_type_uint64; 267 v->visitor.type_bool = qobject_output_type_bool; 268 v->visitor.type_str = qobject_output_type_str; 269 v->visitor.type_number = qobject_output_type_number; 270 v->visitor.type_any = qobject_output_type_any; 271 v->visitor.type_null = qobject_output_type_null; 272 v->visitor.policy_skip = qobject_output_policy_skip; 273 v->visitor.complete = qobject_output_complete; 274 v->visitor.free = qobject_output_free; 275 276 *result = NULL; 277 v->result = result; 278 279 return &v->visitor; 280 } 281