qmp-input-visitor.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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 "qapi/qmp-input-visitor.h"
  14. #include "qapi/visitor-impl.h"
  15. #include "qemu/queue.h"
  16. #include "qemu-common.h"
  17. #include "qapi/qmp/types.h"
  18. #include "qapi/qmp/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. bool consume)
  40. {
  41. QObject *qobj = qiv->stack[qiv->nb_stack - 1].obj;
  42. if (qobj) {
  43. if (name && qobject_type(qobj) == QTYPE_QDICT) {
  44. if (qiv->stack[qiv->nb_stack - 1].h && consume) {
  45. g_hash_table_remove(qiv->stack[qiv->nb_stack - 1].h, name);
  46. }
  47. return qdict_get(qobject_to_qdict(qobj), name);
  48. } else if (qiv->stack[qiv->nb_stack - 1].entry) {
  49. return qlist_entry_obj(qiv->stack[qiv->nb_stack - 1].entry);
  50. }
  51. }
  52. return qobj;
  53. }
  54. static void qdict_add_key(const char *key, QObject *obj, void *opaque)
  55. {
  56. GHashTable *h = opaque;
  57. g_hash_table_insert(h, (gpointer) key, NULL);
  58. }
  59. static void qmp_input_push(QmpInputVisitor *qiv, QObject *obj, Error **errp)
  60. {
  61. GHashTable *h;
  62. if (qiv->nb_stack >= QIV_STACK_SIZE) {
  63. error_setg(errp, "An internal buffer overran");
  64. return;
  65. }
  66. qiv->stack[qiv->nb_stack].obj = obj;
  67. qiv->stack[qiv->nb_stack].entry = NULL;
  68. qiv->stack[qiv->nb_stack].h = NULL;
  69. if (qiv->strict && qobject_type(obj) == QTYPE_QDICT) {
  70. h = g_hash_table_new(g_str_hash, g_str_equal);
  71. qdict_iter(qobject_to_qdict(obj), qdict_add_key, h);
  72. qiv->stack[qiv->nb_stack].h = h;
  73. }
  74. qiv->nb_stack++;
  75. }
  76. /** Only for qmp_input_pop. */
  77. static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
  78. {
  79. *(const char **)user_pkey = (const char *)key;
  80. return TRUE;
  81. }
  82. static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
  83. {
  84. assert(qiv->nb_stack > 0);
  85. if (qiv->strict) {
  86. GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
  87. if (top_ht) {
  88. if (g_hash_table_size(top_ht)) {
  89. const char *key;
  90. g_hash_table_find(top_ht, always_true, &key);
  91. error_setg(errp, QERR_QMP_EXTRA_MEMBER, key);
  92. }
  93. g_hash_table_unref(top_ht);
  94. }
  95. }
  96. qiv->nb_stack--;
  97. }
  98. static void qmp_input_start_struct(Visitor *v, void **obj, const char *kind,
  99. const char *name, size_t size, Error **errp)
  100. {
  101. QmpInputVisitor *qiv = to_qiv(v);
  102. QObject *qobj = qmp_input_get_object(qiv, name, true);
  103. Error *err = NULL;
  104. if (!qobj || qobject_type(qobj) != QTYPE_QDICT) {
  105. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  106. "QDict");
  107. return;
  108. }
  109. qmp_input_push(qiv, qobj, &err);
  110. if (err) {
  111. error_propagate(errp, err);
  112. return;
  113. }
  114. if (obj) {
  115. *obj = g_malloc0(size);
  116. }
  117. }
  118. static void qmp_input_end_struct(Visitor *v, Error **errp)
  119. {
  120. QmpInputVisitor *qiv = to_qiv(v);
  121. qmp_input_pop(qiv, errp);
  122. }
  123. static void qmp_input_start_implicit_struct(Visitor *v, void **obj,
  124. size_t size, Error **errp)
  125. {
  126. if (obj) {
  127. *obj = g_malloc0(size);
  128. }
  129. }
  130. static void qmp_input_end_implicit_struct(Visitor *v, Error **errp)
  131. {
  132. }
  133. static void qmp_input_start_list(Visitor *v, const char *name, Error **errp)
  134. {
  135. QmpInputVisitor *qiv = to_qiv(v);
  136. QObject *qobj = qmp_input_get_object(qiv, name, true);
  137. if (!qobj || qobject_type(qobj) != QTYPE_QLIST) {
  138. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  139. "list");
  140. return;
  141. }
  142. qmp_input_push(qiv, qobj, errp);
  143. }
  144. static GenericList *qmp_input_next_list(Visitor *v, GenericList **list,
  145. Error **errp)
  146. {
  147. QmpInputVisitor *qiv = to_qiv(v);
  148. GenericList *entry;
  149. StackObject *so = &qiv->stack[qiv->nb_stack - 1];
  150. bool first;
  151. if (so->entry == NULL) {
  152. so->entry = qlist_first(qobject_to_qlist(so->obj));
  153. first = true;
  154. } else {
  155. so->entry = qlist_next(so->entry);
  156. first = false;
  157. }
  158. if (so->entry == NULL) {
  159. return NULL;
  160. }
  161. entry = g_malloc0(sizeof(*entry));
  162. if (first) {
  163. *list = entry;
  164. } else {
  165. (*list)->next = entry;
  166. }
  167. return entry;
  168. }
  169. static void qmp_input_end_list(Visitor *v, Error **errp)
  170. {
  171. QmpInputVisitor *qiv = to_qiv(v);
  172. qmp_input_pop(qiv, errp);
  173. }
  174. static void qmp_input_get_next_type(Visitor *v, int *kind, const int *qobjects,
  175. const char *name, Error **errp)
  176. {
  177. QmpInputVisitor *qiv = to_qiv(v);
  178. QObject *qobj = qmp_input_get_object(qiv, name, false);
  179. if (!qobj) {
  180. error_setg(errp, QERR_MISSING_PARAMETER, name ? name : "null");
  181. return;
  182. }
  183. *kind = qobjects[qobject_type(qobj)];
  184. }
  185. static void qmp_input_type_int(Visitor *v, int64_t *obj, const char *name,
  186. Error **errp)
  187. {
  188. QmpInputVisitor *qiv = to_qiv(v);
  189. QObject *qobj = qmp_input_get_object(qiv, name, true);
  190. if (!qobj || qobject_type(qobj) != QTYPE_QINT) {
  191. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  192. "integer");
  193. return;
  194. }
  195. *obj = qint_get_int(qobject_to_qint(qobj));
  196. }
  197. static void qmp_input_type_bool(Visitor *v, bool *obj, const char *name,
  198. Error **errp)
  199. {
  200. QmpInputVisitor *qiv = to_qiv(v);
  201. QObject *qobj = qmp_input_get_object(qiv, name, true);
  202. if (!qobj || qobject_type(qobj) != QTYPE_QBOOL) {
  203. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  204. "boolean");
  205. return;
  206. }
  207. *obj = qbool_get_bool(qobject_to_qbool(qobj));
  208. }
  209. static void qmp_input_type_str(Visitor *v, char **obj, const char *name,
  210. Error **errp)
  211. {
  212. QmpInputVisitor *qiv = to_qiv(v);
  213. QObject *qobj = qmp_input_get_object(qiv, name, true);
  214. if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) {
  215. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  216. "string");
  217. return;
  218. }
  219. *obj = g_strdup(qstring_get_str(qobject_to_qstring(qobj)));
  220. }
  221. static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
  222. Error **errp)
  223. {
  224. QmpInputVisitor *qiv = to_qiv(v);
  225. QObject *qobj = qmp_input_get_object(qiv, name, true);
  226. if (!qobj || (qobject_type(qobj) != QTYPE_QFLOAT &&
  227. qobject_type(qobj) != QTYPE_QINT)) {
  228. error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
  229. "number");
  230. return;
  231. }
  232. if (qobject_type(qobj) == QTYPE_QINT) {
  233. *obj = qint_get_int(qobject_to_qint(qobj));
  234. } else {
  235. *obj = qfloat_get_double(qobject_to_qfloat(qobj));
  236. }
  237. }
  238. static void qmp_input_optional(Visitor *v, bool *present, const char *name,
  239. Error **errp)
  240. {
  241. QmpInputVisitor *qiv = to_qiv(v);
  242. QObject *qobj = qmp_input_get_object(qiv, name, true);
  243. if (!qobj) {
  244. *present = false;
  245. return;
  246. }
  247. *present = true;
  248. }
  249. Visitor *qmp_input_get_visitor(QmpInputVisitor *v)
  250. {
  251. return &v->visitor;
  252. }
  253. void qmp_input_visitor_cleanup(QmpInputVisitor *v)
  254. {
  255. qobject_decref(v->stack[0].obj);
  256. g_free(v);
  257. }
  258. QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
  259. {
  260. QmpInputVisitor *v;
  261. v = g_malloc0(sizeof(*v));
  262. v->visitor.start_struct = qmp_input_start_struct;
  263. v->visitor.end_struct = qmp_input_end_struct;
  264. v->visitor.start_implicit_struct = qmp_input_start_implicit_struct;
  265. v->visitor.end_implicit_struct = qmp_input_end_implicit_struct;
  266. v->visitor.start_list = qmp_input_start_list;
  267. v->visitor.next_list = qmp_input_next_list;
  268. v->visitor.end_list = qmp_input_end_list;
  269. v->visitor.type_enum = input_type_enum;
  270. v->visitor.type_int = qmp_input_type_int;
  271. v->visitor.type_bool = qmp_input_type_bool;
  272. v->visitor.type_str = qmp_input_type_str;
  273. v->visitor.type_number = qmp_input_type_number;
  274. v->visitor.optional = qmp_input_optional;
  275. v->visitor.get_next_type = qmp_input_get_next_type;
  276. qmp_input_push(v, obj, NULL);
  277. qobject_incref(obj);
  278. return v;
  279. }
  280. QmpInputVisitor *qmp_input_visitor_new_strict(QObject *obj)
  281. {
  282. QmpInputVisitor *v;
  283. v = qmp_input_visitor_new(obj);
  284. v->strict = true;
  285. return v;
  286. }