/* Add @value to the current QObject being built. * If the stack is visiting a dictionary or list, @value is now owned * by that container. Otherwise, @value is now the root. */ static void qobject_output_add_obj(QObjectOutputVisitor *qov, const char *name, QObject *value) { QStackEntry *e = QSLIST_FIRST(&qov->stack); QObject *cur = e ? e->value : NULL; if (!cur) { /* Don't allow reuse of visitor on more than one root */ assert(!qov->root); qov->root = value; } else { switch (qobject_type(cur)) { case QTYPE_QDICT: assert(name); qdict_put_obj(qobject_to(QDict, cur), name, value); break; case QTYPE_QLIST: assert(!name); qlist_append_obj(qobject_to(QList, cur), value); break; default: g_assert_not_reached(); } } }
/* test commands that involve both input parameters and return values */ static void test_dispatch_cmd_io(void) { QDict *req = qdict_new(); QDict *args = qdict_new(); QDict *args3 = qdict_new(); QDict *ud1a = qdict_new(); QDict *ud1b = qdict_new(); QDict *ret, *ret_dict, *ret_dict_dict, *ret_dict_dict_userdef; QDict *ret_dict_dict2, *ret_dict_dict2_userdef; QNum *ret3; int64_t val; qdict_put_int(ud1a, "integer", 42); qdict_put_str(ud1a, "string", "hello"); qdict_put_int(ud1b, "integer", 422); qdict_put_str(ud1b, "string", "hello2"); qdict_put(args, "ud1a", ud1a); qdict_put(args, "ud1b", ud1b); qdict_put(req, "arguments", args); qdict_put_str(req, "execute", "user_def_cmd2"); ret = qobject_to(QDict, test_qmp_dispatch(req)); assert(!strcmp(qdict_get_str(ret, "string0"), "blah1")); ret_dict = qdict_get_qdict(ret, "dict1"); assert(!strcmp(qdict_get_str(ret_dict, "string1"), "blah2")); ret_dict_dict = qdict_get_qdict(ret_dict, "dict2"); ret_dict_dict_userdef = qdict_get_qdict(ret_dict_dict, "userdef"); assert(qdict_get_int(ret_dict_dict_userdef, "integer") == 42); assert(!strcmp(qdict_get_str(ret_dict_dict_userdef, "string"), "hello")); assert(!strcmp(qdict_get_str(ret_dict_dict, "string"), "blah3")); ret_dict_dict2 = qdict_get_qdict(ret_dict, "dict3"); ret_dict_dict2_userdef = qdict_get_qdict(ret_dict_dict2, "userdef"); assert(qdict_get_int(ret_dict_dict2_userdef, "integer") == 422); assert(!strcmp(qdict_get_str(ret_dict_dict2_userdef, "string"), "hello2")); assert(!strcmp(qdict_get_str(ret_dict_dict2, "string"), "blah4")); qobject_unref(ret); qdict_put_int(args3, "a", 66); qdict_put(req, "arguments", args3); qdict_put_str(req, "execute", "guest-get-time"); ret3 = qobject_to(QNum, test_qmp_dispatch(req)); g_assert(qnum_get_try_int(ret3, &val)); g_assert_cmpint(val, ==, 66); qobject_unref(ret3); qobject_unref(req); }
QDict *qmp_dispatch(QmpCommandList *cmds, QObject *request, bool allow_oob) { Error *err = NULL; QDict *dict = qobject_to(QDict, request); QObject *ret, *id = dict ? qdict_get(dict, "id") : NULL; QDict *rsp; ret = do_qmp_dispatch(cmds, request, allow_oob, &err); if (err) { rsp = qmp_error_response(err); } else if (ret) { rsp = qdict_new(); qdict_put_obj(rsp, "return", ret); } else { /* Can only happen for commands with QCO_NO_SUCCESS_RESP */ rsp = NULL; } if (rsp && id) { qdict_put_obj(rsp, "id", qobject_ref(id)); } return rsp; }
static bool qom_get_bool(const char *path, const char *prop) { QBool *value = qobject_to(QBool, qom_get(path, prop)); bool b = qbool_get_bool(value); qobject_unref(value); return b; }
static QString *from_json_str(const char *jstr, bool single, Error **errp) { char quote = single ? '\'' : '"'; char *qjstr = g_strdup_printf("%c%s%c", quote, jstr, quote); QString *ret = qobject_to(QString, qobject_from_json(qjstr, errp)); g_free(qjstr); return ret; }
/** * qnum_is_equal(): Test whether the two QNums are equal * * Negative integers are never considered equal to unsigned integers, * but positive integers in the range [0, INT64_MAX] are considered * equal independently of whether the QNum's kind is i64 or u64. * * Doubles are never considered equal to integers. */ bool qnum_is_equal(const QObject *x, const QObject *y) { QNum *num_x = qobject_to(QNum, x); QNum *num_y = qobject_to(QNum, y); switch (num_x->kind) { case QNUM_I64: switch (num_y->kind) { case QNUM_I64: /* Comparison in native int64_t type */ return num_x->u.i64 == num_y->u.i64; case QNUM_U64: /* Implicit conversion of x to uin64_t, so we have to * check its sign before */ return num_x->u.i64 >= 0 && num_x->u.i64 == num_y->u.u64; case QNUM_DOUBLE: return false; } abort(); case QNUM_U64: switch (num_y->kind) { case QNUM_I64: return qnum_is_equal(y, x); case QNUM_U64: /* Comparison in native uint64_t type */ return num_x->u.u64 == num_y->u.u64; case QNUM_DOUBLE: return false; } abort(); case QNUM_DOUBLE: switch (num_y->kind) { case QNUM_I64: case QNUM_U64: return false; case QNUM_DOUBLE: /* Comparison in native double type */ return num_x->u.dbl == num_y->u.dbl; } abort(); } abort(); }
static void test_qga_get_vcpus(gconstpointer fix) { const TestFixture *fixture = fix; QDict *ret; QList *list; const QListEntry *entry; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-vcpus'}"); g_assert_nonnull(ret); qmp_assert_no_error(ret); /* check there is at least a cpu */ list = qdict_get_qlist(ret, "return"); entry = qlist_first(list); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "online")); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "logical-id")); qobject_unref(ret); }
static QDict *qmp_dispatch_check_obj(const QObject *request, bool allow_oob, Error **errp) { const char *exec_key = NULL; const QDictEntry *ent; const char *arg_name; const QObject *arg_obj; QDict *dict; dict = qobject_to(QDict, request); if (!dict) { error_setg(errp, "QMP input must be a JSON object"); return NULL; } for (ent = qdict_first(dict); ent; ent = qdict_next(dict, ent)) { arg_name = qdict_entry_key(ent); arg_obj = qdict_entry_value(ent); if (!strcmp(arg_name, "execute") || (!strcmp(arg_name, "exec-oob") && allow_oob)) { if (qobject_type(arg_obj) != QTYPE_QSTRING) { error_setg(errp, "QMP input member '%s' must be a string", arg_name); return NULL; } if (exec_key) { error_setg(errp, "QMP input member '%s' clashes with '%s'", arg_name, exec_key); return NULL; } exec_key = arg_name; } else if (!strcmp(arg_name, "arguments")) { if (qobject_type(arg_obj) != QTYPE_QDICT) { error_setg(errp, "QMP input member 'arguments' must be an object"); return NULL; } } else if (!strcmp(arg_name, "id")) { continue; } else { error_setg(errp, "QMP input member '%s' is unexpected", arg_name); return NULL; } } if (!exec_key) { error_setg(errp, "QMP input lacks member 'execute'"); return NULL; } return dict; }
static void qdict_crumple_test_empty(void) { QDict *src, *dst; src = qdict_new(); dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); g_assert_cmpint(qdict_size(dst), ==, 0); qobject_unref(src); qobject_unref(dst); }
static void qlit_equal_qobject_test(void) { QObject *qobj = make_qobject(); g_assert(qlit_equal_qobject(&qlit, qobj)); g_assert(!qlit_equal_qobject(&qlit_foo, qobj)); qdict_put(qobject_to(QDict, qobj), "bee", qlist_new()); g_assert(!qlit_equal_qobject(&qlit, qobj)); qobject_unref(qobj); }
static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json, Error **errp) { QList *keypairs; QString *name; QString *value; const char *key; size_t remaining; int ret = 0; if (!keypairs_json) { return ret; } keypairs = qobject_to(QList, qobject_from_json(keypairs_json, &error_abort)); remaining = qlist_size(keypairs) / 2; assert(remaining); while (remaining--) { name = qobject_to(QString, qlist_pop(keypairs)); value = qobject_to(QString, qlist_pop(keypairs)); assert(name && value); key = qstring_get_str(name); ret = rados_conf_set(cluster, key, qstring_get_str(value)); qobject_unref(value); if (ret < 0) { error_setg_errno(errp, -ret, "invalid conf option %s", key); qobject_unref(name); ret = -EINVAL; break; } qobject_unref(name); } qobject_unref(keypairs); return ret; }
static void test_qga_get_fsinfo(gconstpointer fix) { const TestFixture *fixture = fix; QDict *ret; QList *list; const QListEntry *entry; ret = qmp_fd(fixture->fd, "{'execute': 'guest-get-fsinfo'}"); g_assert_nonnull(ret); qmp_assert_no_error(ret); /* sanity-check the response if there are any filesystems */ list = qdict_get_qlist(ret, "return"); entry = qlist_first(list); if (entry) { g_assert(qdict_haskey(qobject_to(QDict, entry->value), "name")); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "mountpoint")); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "type")); g_assert(qdict_haskey(qobject_to(QDict, entry->value), "disk")); } qobject_unref(ret); }
static void qobject_from_qlit_test(void) { QObject *obj, *qobj = qobject_from_qlit(&qlit); QDict *qdict; QList *bee; qdict = qobject_to(QDict, qobj); g_assert_cmpint(qdict_get_int(qdict, "foo"), ==, 42); g_assert_cmpstr(qdict_get_str(qdict, "bar"), ==, "hello world"); g_assert(qobject_type(qdict_get(qdict, "baz")) == QTYPE_QNULL); bee = qdict_get_qlist(qdict, "bee"); obj = qlist_pop(bee); g_assert_cmpint(qnum_get_int(qobject_to(QNum, obj)), ==, 43); qobject_unref(obj); obj = qlist_pop(bee); g_assert_cmpint(qnum_get_int(qobject_to(QNum, obj)), ==, 44); qobject_unref(obj); obj = qlist_pop(bee); g_assert(qbool_get_bool(qobject_to(QBool, obj))); qobject_unref(obj); qobject_unref(qobj); }
static char *get_cpu0_qom_path(void) { QDict *resp; QList *ret; QDict *cpu0; char *path; resp = qmp("{'execute': 'query-cpus', 'arguments': {}}"); g_assert(qdict_haskey(resp, "return")); ret = qdict_get_qlist(resp, "return"); cpu0 = qobject_to(QDict, qlist_peek(ret)); path = g_strdup(qdict_get_str(cpu0, "qom_path")); qobject_unref(resp); return path; }
/* handle requests/control events coming in over the channel */ static void process_event(JSONMessageParser *parser, GQueue *tokens) { GAState *s = container_of(parser, GAState, parser); QDict *qdict; Error *err = NULL; int ret; g_assert(s && parser); g_debug("process_event: called"); qdict = qobject_to(QDict, json_parser_parse_err(tokens, NULL, &err)); if (err || !qdict) { qobject_unref(qdict); qdict = qdict_new(); if (!err) { g_warning("failed to parse event: unknown error"); error_setg(&err, QERR_JSON_PARSING); } else { g_warning("failed to parse event: %s", error_get_pretty(err)); } qdict_put_obj(qdict, "error", qmp_build_error_object(err)); error_free(err); } /* handle host->guest commands */ if (qdict_haskey(qdict, "execute")) { process_command(s, qdict); } else { if (!qdict_haskey(qdict, "error")) { qobject_unref(qdict); qdict = qdict_new(); g_warning("unrecognized payload format"); error_setg(&err, QERR_UNSUPPORTED); qdict_put_obj(qdict, "error", qmp_build_error_object(err)); error_free(err); } ret = send_response(s, QOBJECT(qdict)); if (ret < 0) { g_warning("error sending error response: %s", strerror(-ret)); } } qobject_unref(qdict); }
static QAuthZ * qauthz_list_file_load(QAuthZListFile *fauthz, Error **errp) { GError *err = NULL; gchar *content = NULL; gsize len; QObject *obj = NULL; QDict *pdict; Visitor *v = NULL; QAuthZ *ret = NULL; trace_qauthz_list_file_load(fauthz, fauthz->filename); if (!g_file_get_contents(fauthz->filename, &content, &len, &err)) { error_setg(errp, "Unable to read '%s': %s", fauthz->filename, err->message); goto cleanup; } obj = qobject_from_json(content, errp); if (!obj) { goto cleanup; } pdict = qobject_to(QDict, obj); if (!pdict) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, "obj", "dict"); goto cleanup; } v = qobject_input_visitor_new(obj); ret = (QAuthZ *)user_creatable_add_type(TYPE_QAUTHZ_LIST, NULL, pdict, v, errp); cleanup: visit_free(v); qobject_unref(obj); if (err) { g_error_free(err); } g_free(content); return ret; }
/* handle requests/control events coming in over the channel */ static void process_event(JSONMessageParser *parser, GQueue *tokens) { GAState *s = container_of(parser, GAState, parser); QObject *obj; QDict *req, *rsp; Error *err = NULL; int ret; g_assert(s && parser); g_debug("process_event: called"); obj = json_parser_parse_err(tokens, NULL, &err); if (err) { goto err; } req = qobject_to(QDict, obj); if (!req) { error_setg(&err, QERR_JSON_PARSING); goto err; } if (!qdict_haskey(req, "execute")) { g_warning("unrecognized payload format"); error_setg(&err, QERR_UNSUPPORTED); goto err; } process_command(s, req); qobject_unref(obj); return; err: g_warning("failed to parse event: %s", error_get_pretty(err)); rsp = qmp_error_response(err); ret = send_response(s, rsp); if (ret < 0) { g_warning("error sending error response: %s", strerror(-ret)); } qobject_unref(rsp); qobject_unref(obj); }
/** * qnum_destroy_obj(): Free all memory allocated by a * QNum object */ void qnum_destroy_obj(QObject *obj) { assert(obj != NULL); g_free(qobject_to(QNum, obj)); }
static void qdict_crumple_test_recursive(void) { QDict *src, *dst, *rule, *vnc, *acl, *listen; QDict *empty, *empty_dict, *empty_list_0; QList *rules, *empty_list, *empty_dict_a; src = qdict_new(); qdict_put_str(src, "vnc.listen.addr", "127.0.0.1"); qdict_put_str(src, "vnc.listen.port", "5901"); qdict_put_str(src, "vnc.acl.rules.0.match", "fred"); qdict_put_str(src, "vnc.acl.rules.0.policy", "allow"); qdict_put_str(src, "vnc.acl.rules.1.match", "bob"); qdict_put_str(src, "vnc.acl.rules.1.policy", "deny"); qdict_put_str(src, "vnc.acl.default", "deny"); qdict_put_str(src, "vnc.acl..name", "acl0"); qdict_put_str(src, "vnc.acl.rule..name", "acl0"); qdict_put(src, "empty.dict.a", qlist_new()); qdict_put(src, "empty.list.0", qdict_new()); dst = qobject_to(QDict, qdict_crumple(src, &error_abort)); g_assert(dst); g_assert_cmpint(qdict_size(dst), ==, 2); vnc = qdict_get_qdict(dst, "vnc"); g_assert(vnc); g_assert_cmpint(qdict_size(vnc), ==, 3); listen = qdict_get_qdict(vnc, "listen"); g_assert(listen); g_assert_cmpint(qdict_size(listen), ==, 2); g_assert_cmpstr("127.0.0.1", ==, qdict_get_str(listen, "addr")); g_assert_cmpstr("5901", ==, qdict_get_str(listen, "port")); acl = qdict_get_qdict(vnc, "acl"); g_assert(acl); g_assert_cmpint(qdict_size(acl), ==, 3); rules = qdict_get_qlist(acl, "rules"); g_assert(rules); g_assert_cmpint(qlist_size(rules), ==, 2); rule = qobject_to(QDict, qlist_pop(rules)); g_assert(rule); g_assert_cmpint(qdict_size(rule), ==, 2); g_assert_cmpstr("fred", ==, qdict_get_str(rule, "match")); g_assert_cmpstr("allow", ==, qdict_get_str(rule, "policy")); qobject_unref(rule); rule = qobject_to(QDict, qlist_pop(rules)); g_assert(rule); g_assert_cmpint(qdict_size(rule), ==, 2); g_assert_cmpstr("bob", ==, qdict_get_str(rule, "match")); g_assert_cmpstr("deny", ==, qdict_get_str(rule, "policy")); qobject_unref(rule); /* With recursive crumpling, we should see all names unescaped */ g_assert_cmpstr("acl0", ==, qdict_get_str(vnc, "acl.name")); g_assert_cmpstr("acl0", ==, qdict_get_str(acl, "rule.name")); empty = qdict_get_qdict(dst, "empty"); g_assert(empty); g_assert_cmpint(qdict_size(empty), ==, 2); empty_dict = qdict_get_qdict(empty, "dict"); g_assert(empty_dict); g_assert_cmpint(qdict_size(empty_dict), ==, 1); empty_dict_a = qdict_get_qlist(empty_dict, "a"); g_assert(empty_dict_a && qlist_empty(empty_dict_a)); empty_list = qdict_get_qlist(empty, "list"); g_assert(empty_list); g_assert_cmpint(qlist_size(empty_list), ==, 1); empty_list_0 = qobject_to(QDict, qlist_pop(empty_list)); g_assert(empty_list_0); g_assert_cmpint(qdict_size(empty_list_0), ==, 0); qobject_unref(src); qobject_unref(dst); }
static void qobject_is_equal_dict_test(void) { Error *local_err = NULL; QDict *dict_0, *dict_1, *dict_cloned; QDict *dict_different_key, *dict_different_value, *dict_different_null_key; QDict *dict_longer, *dict_shorter, *dict_nested; QDict *dict_crumpled; dict_0 = qdict_new(); dict_1 = qdict_new(); dict_different_key = qdict_new(); dict_different_value = qdict_new(); dict_different_null_key = qdict_new(); dict_longer = qdict_new(); dict_shorter = qdict_new(); dict_nested = qdict_new(); qdict_put_int(dict_0, "f.o", 1); qdict_put_int(dict_0, "bar", 2); qdict_put_int(dict_0, "baz", 3); qdict_put_null(dict_0, "null"); qdict_put_int(dict_1, "f.o", 1); qdict_put_int(dict_1, "bar", 2); qdict_put_int(dict_1, "baz", 3); qdict_put_null(dict_1, "null"); qdict_put_int(dict_different_key, "F.o", 1); qdict_put_int(dict_different_key, "bar", 2); qdict_put_int(dict_different_key, "baz", 3); qdict_put_null(dict_different_key, "null"); qdict_put_int(dict_different_value, "f.o", 42); qdict_put_int(dict_different_value, "bar", 2); qdict_put_int(dict_different_value, "baz", 3); qdict_put_null(dict_different_value, "null"); qdict_put_int(dict_different_null_key, "f.o", 1); qdict_put_int(dict_different_null_key, "bar", 2); qdict_put_int(dict_different_null_key, "baz", 3); qdict_put_null(dict_different_null_key, "none"); qdict_put_int(dict_longer, "f.o", 1); qdict_put_int(dict_longer, "bar", 2); qdict_put_int(dict_longer, "baz", 3); qdict_put_int(dict_longer, "xyz", 4); qdict_put_null(dict_longer, "null"); qdict_put_int(dict_shorter, "f.o", 1); qdict_put_int(dict_shorter, "bar", 2); qdict_put_int(dict_shorter, "baz", 3); qdict_put(dict_nested, "f", qdict_new()); qdict_put_int(qdict_get_qdict(dict_nested, "f"), "o", 1); qdict_put_int(dict_nested, "bar", 2); qdict_put_int(dict_nested, "baz", 3); qdict_put_null(dict_nested, "null"); dict_cloned = qdict_clone_shallow(dict_0); check_equal(dict_0, dict_1, dict_cloned); check_unequal(dict_0, dict_different_key, dict_different_value, dict_different_null_key, dict_longer, dict_shorter, dict_nested); dict_crumpled = qobject_to(QDict, qdict_crumple(dict_1, &local_err)); g_assert(!local_err); check_equal(dict_crumpled, dict_nested); qdict_flatten(dict_nested); check_equal(dict_0, dict_nested); /* Containing an NaN value will make this dict compare unequal to * itself */ qdict_put(dict_0, "NaN", qnum_from_double(NAN)); g_assert(qobject_is_equal(QOBJECT(dict_0), QOBJECT(dict_0)) == false); free_all(dict_0, dict_1, dict_cloned, dict_different_key, dict_different_value, dict_different_null_key, dict_longer, dict_shorter, dict_nested, dict_crumpled); }
static void qdict_array_split_test(void) { QDict *test_dict = qdict_new(); QDict *dict1, *dict2; QNum *int1; QList *test_list; /* * Test the split of * * { * "1.x": 0, * "4.y": 1, * "0.a": 42, * "o.o": 7, * "0.b": 23, * "2": 66 * } * * to * * [ * { * "a": 42, * "b": 23 * }, * { * "x": 0 * }, * 66 * ] * * and * * { * "4.y": 1, * "o.o": 7 * } * * (remaining in the old QDict) * * This example is given in the comment of qdict_array_split(). */ qdict_put_int(test_dict, "1.x", 0); qdict_put_int(test_dict, "4.y", 1); qdict_put_int(test_dict, "0.a", 42); qdict_put_int(test_dict, "o.o", 7); qdict_put_int(test_dict, "0.b", 23); qdict_put_int(test_dict, "2", 66); qdict_array_split(test_dict, &test_list); dict1 = qobject_to(QDict, qlist_pop(test_list)); dict2 = qobject_to(QDict, qlist_pop(test_list)); int1 = qobject_to(QNum, qlist_pop(test_list)); g_assert(dict1); g_assert(dict2); g_assert(int1); g_assert(qlist_empty(test_list)); qobject_unref(test_list); g_assert(qdict_get_int(dict1, "a") == 42); g_assert(qdict_get_int(dict1, "b") == 23); g_assert(qdict_size(dict1) == 2); qobject_unref(dict1); g_assert(qdict_get_int(dict2, "x") == 0); g_assert(qdict_size(dict2) == 1); qobject_unref(dict2); g_assert_cmpint(qnum_get_int(int1), ==, 66); qobject_unref(int1); g_assert(qdict_get_int(test_dict, "4.y") == 1); g_assert(qdict_get_int(test_dict, "o.o") == 7); g_assert(qdict_size(test_dict) == 2); qobject_unref(test_dict); /* * Test the split of * * { * "0": 42, * "1": 23, * "1.x": 84 * } * * to * * [ * 42 * ] * * and * * { * "1": 23, * "1.x": 84 * } * * That is, test whether splitting stops if there is both an entry with key * of "%u" and other entries with keys prefixed "%u." for the same index. */ test_dict = qdict_new(); qdict_put_int(test_dict, "0", 42); qdict_put_int(test_dict, "1", 23); qdict_put_int(test_dict, "1.x", 84); qdict_array_split(test_dict, &test_list); int1 = qobject_to(QNum, qlist_pop(test_list)); g_assert(int1); g_assert(qlist_empty(test_list)); qobject_unref(test_list); g_assert_cmpint(qnum_get_int(int1), ==, 42); qobject_unref(int1); g_assert(qdict_get_int(test_dict, "1") == 23); g_assert(qdict_get_int(test_dict, "1.x") == 84); g_assert(qdict_size(test_dict) == 2); qobject_unref(test_dict); }