2
0

qmp-input-visitor.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Input Visitor
  3. *
  4. * Copyright IBM, Corp. 2011
  5. *
  6. * Authors:
  7. * Anthony Liguori <aliguori@us.ibm.com>
  8. *
  9. * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
  10. * See the COPYING.LIB file in the top-level directory.
  11. *
  12. */
  13. #include "qmp-input-visitor.h"
  14. #include "qapi/qapi-visit-impl.h"
  15. #include "qemu-queue.h"
  16. #include "qemu-common.h"
  17. #include "qemu-objects.h"
  18. #include "qerror.h"
  19. #define QIV_STACK_SIZE 1024
  20. typedef struct StackObject
  21. {
  22. QObject *obj;
  23. const QListEntry *entry;
  24. GHashTable *h;
  25. } StackObject;
  26. struct QmpInputVisitor
  27. {
  28. Visitor visitor;
  29. StackObject stack[QIV_STACK_SIZE];
  30. int nb_stack;
  31. bool strict;
  32. };
  33. static QmpInputVisitor *to_qiv(Visitor *v)
  34. {
  35. return container_of(v, QmpInputVisitor, visitor);
  36. }
  37. static QObject *qmp_input_get_object(QmpInputVisitor *qiv,
  38. const char *name)
  39. {
  40. QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj;
  41. if (qobj) {
  42. if (name && qobject_type(qobj) == QTYPE_QDICT) {
  43. if (qiv->stack[qiv->nb_stack - 1].h) {
  44. g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name);
  45. }
  46. return qdict_get(qobject_to_qdict(qobj), name);
  47. } else if (qiv->stack[qiv->nb_stack - 1].entry) {
  48. return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
  49. }
  50. }
  51. return qobj;
  52. }
  53. static void qdict_add_key(const char *key, QObject *obj, void *opaque)
  54. {
  55. GHashTable *h = opaque;
  56. g_hash_table_insert(h, (gpointer) key, NULL);
  57. }
  58. static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
  59. {
  60. GHashTable *h;
  61. if (qiv->nb_stack >= QIV_STACK_SIZE) {
  62. error_set(errp, QERR_BUFFER_OVERRUN);
  63. return;
  64. }
  65. qiv->stack[qiv->nb_stack].obj = obj;
  66. qiv->stack[qiv->nb_stack].entry = NULL;
  67. qiv->stack[qiv->nb_stack].h = NULL;
  68. if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
  69. h = g_hash_table_new(g_str_hash, g_str_equal);
  70. qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
  71. qiv->stack[qiv->nb_stack].h = h;
  72. }
  73. qiv->nb_stack++;
  74. }
  75. /** Only for qmp_input_pop. */
  76. static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
  77. {
  78. *(const char **)user_pkey = (const char *)key;
  79. return TRUE;
  80. }
  81. static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
  82. {
  83. assert(qiv->nb_stack > 0);
  84. if (qiv->strict) {
  85. GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
  86. if (top_ht) {
  87. if (g_hash_table_size(top_ht)) {
  88. const char *key;
  89. g_hash_table_find(top_ht, always_true, &key);
  90. error_set(errp, QERR_QMP_EXTRA_MEMBER, key);
  91. }
  92. g_hash_table_unref(top_ht);
  93. }
  94. }
  95. qiv->nb_stack--;
  96. }
  97. static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
  98. const char *name, size_t size, Error **errp)
  99. {
  100. QmpInputVisitor *qiv = to_qiv(v);
  101. QObject *qobj = qmp_input_get_object(qiv, name);
  102. Error *err = NULL;
  103. if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
  104. error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  105. "QDict");
  106. return;
  107. }
  108. qmp_input_push(qiv, qobj, &err);
  109. if (err) {
  110. error_propagate(errp, err);
  111. return;
  112. }
  113. if (obj) {
  114. *obj = g_malloc0(size);
  115. }
  116. }
  117. static void qmp_input_end_struct(Visitor *v, Error **errp)
  118. {
  119. QmpInputVisitor *qiv = to_qiv(v);
  120. qmp_input_pop(qiv, errp);
  121. }
  122. static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
  123. {
  124. QmpInputVisitor *qiv = to_qiv(v);
  125. QObject *qobj = qmp_input_get_object(qiv, name);
  126. if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
  127. error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  128. "list");
  129. return;
  130. }
  131. qmp_input_push(qiv, qobj, errp);
  132. }
  133. static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
  134. Error **errp)
  135. {
  136. QmpInputVisitor *qiv = to_qiv(v);
  137. GenericList *entry;
  138. StackObject *so = &qiv->stack[qiv->nb_stack - 1];
  139. bool first;
  140. if (so->entry == NULL) {
  141. so->entry = qlist_first(qobject_to_qlist(so->obj));
  142. first = true;
  143. } else {
  144. so->entry = qlist_next(so->entry);
  145. first = false;
  146. }
  147. if (so->entry == NULL) {
  148. return NULL;
  149. }
  150. entry = g_malloc0(sizeof(*entry));
  151. if (first) {
  152. *list = entry;
  153. } else {
  154. (*list)->next = entry;
  155. }
  156. return entry;
  157. }
  158. static void qmp_input_end_list(Visitor *v, Error **errp)
  159. {
  160. QmpInputVisitor *qiv = to_qiv(v);
  161. qmp_input_pop(qiv, errp);
  162. }
  163. static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
  164. Error **errp)
  165. {
  166. QmpInputVisitor *qiv = to_qiv(v);
  167. QObject *qobj = qmp_input_get_object(qiv, name);
  168. if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
  169. error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  170. "integer");
  171. return;
  172. }
  173. *obj = qint_get_int(qobject_to_qint(qobj));
  174. }
  175. static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
  176. Error **errp)
  177. {
  178. QmpInputVisitor *qiv = to_qiv(v);
  179. QObject *qobj = qmp_input_get_object(qiv, name);
  180. if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
  181. error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  182. "boolean");
  183. return;
  184. }
  185. *obj = qbool_get_int(qobject_to_qbool(qobj));
  186. }
  187. static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
  188. Error **errp)
  189. {
  190. QmpInputVisitor *qiv = to_qiv(v);
  191. QObject *qobj = qmp_input_get_object(qiv, name);
  192. if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
  193. error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  194. "string");
  195. return;
  196. }
  197. *obj = g_strdup(qstring_get_str(qobject_to_qstring(qobj)));
  198. }
  199. static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
  200. Error **errp)
  201. {
  202. QmpInputVisitor *qiv = to_qiv(v);
  203. QObject *qobj = qmp_input_get_object(qiv, name);
  204. if (!qobj || (qobject_type(qobj) != QTYPE_QFLOAT &&
  205. qobject_type(qobj) != QTYPE_QINT)) {
  206. error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  207. "number");
  208. return;
  209. }
  210. if (qobject_type(qobj) == QTYPE_QINT) {
  211. *obj = qint_get_int(qobject_to_qint(qobj));
  212. } else {
  213. *obj = qfloat_get_double(qobject_to_qfloat(qobj));
  214. }
  215. }
  216. static void qmp_input_start_optional(Visitor *v, bool *present,
  217. const char *name, Error **errp)
  218. {
  219. QmpInputVisitor *qiv = to_qiv(v);
  220. QObject *qobj = qmp_input_get_object(qiv, name);
  221. if (!qobj) {
  222. *present = false;
  223. return;
  224. }
  225. *present = true;
  226. }
  227. Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
  228. {
  229. return &v->visitor;
  230. }
  231. void qmp_input_visitor_cleanup(QmpInputVisitor *v)
  232. {
  233. qobject_decref(v->stack[0].obj);
  234. g_free(v);
  235. }
  236. QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
  237. {
  238. QmpInputVisitor *v;
  239. v = g_malloc0(sizeof(*v));
  240. v->visitor.start_struct = qmp_input_start_struct;
  241. v->visitor.end_struct = qmp_input_end_struct;
  242. v->visitor.start_list = qmp_input_start_list;
  243. v->visitor.next_list = qmp_input_next_list;
  244. v->visitor.end_list = qmp_input_end_list;
  245. v->visitor.type_enum = input_type_enum;
  246. v->visitor.type_int = qmp_input_type_int;
  247. v->visitor.type_bool = qmp_input_type_bool;
  248. v->visitor.type_str = qmp_input_type_str;
  249. v->visitor.type_number = qmp_input_type_number;
  250. v->visitor.start_optional = qmp_input_start_optional;
  251. qmp_input_push(v, obj, NULL);
  252. qobject_incref(obj);
  253. return v;
  254. }
  255. QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj)
  256. {
  257. QmpInputVisitor *v;
  258. v = qmp_input_visitor_new(obj);
  259. v->strict = true;
  260. return v;
  261. }