예제 #1
0
int
qemuAgentArbitraryCommand(qemuAgentPtr mon,
                          const char *cmd_str,
                          char **result,
                          int timeout)
{
    int ret = -1;
    virJSONValuePtr cmd;
    virJSONValuePtr reply = NULL;

    *result = NULL;
    if (timeout < VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN)
        return ret;

    cmd = virJSONValueFromString(cmd_str);
    if (!cmd)
        return ret;

    ret = qemuAgentCommand(mon, cmd, &reply, timeout);

    if (ret == 0) {
        ret = qemuAgentCheckError(cmd, reply);
        *result = virJSONValueToString(reply, false);
    }

    virJSONValueFree(cmd);
    virJSONValueFree(reply);
    return ret;
}
예제 #2
0
int
qemuAgentArbitraryCommand(qemuAgentPtr mon,
                          const char *cmd_str,
                          char **result,
                          int timeout)
{
    int ret = -1;
    virJSONValuePtr cmd = NULL;
    virJSONValuePtr reply = NULL;

    *result = NULL;
    if (timeout < VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("guest agent timeout '%d' is "
                         "less than the minimum '%d'"),
                       timeout, VIR_DOMAIN_QEMU_AGENT_COMMAND_MIN);
        goto cleanup;
    }

    if (!(cmd = virJSONValueFromString(cmd_str)))
        goto cleanup;

    if ((ret = qemuAgentCommand(mon, cmd, &reply, true, timeout)) < 0)
        goto cleanup;

    if (!(*result = virJSONValueToString(reply, false)))
        ret = -1;


 cleanup:
    virJSONValueFree(cmd);
    virJSONValueFree(reply);
    return ret;
}
예제 #3
0
static int
testQemuDiskXMLToPropsValidateSchema(const void *opaque)
{
    struct testQemuDiskXMLToJSONData *data = (void *) opaque;
    virBuffer debug = VIR_BUFFER_INITIALIZER;
    char *propsstr = NULL;
    char *debugmsg = NULL;
    int ret = 0;
    size_t i;

    if (data->fail)
        return EXIT_AM_SKIP;

    for (i = 0; i < data->nprops; i++) {
        if (testQEMUSchemaValidate(data->props[i], data->schemaroot,
                                   data->schema, &debug) < 0) {
            debugmsg = virBufferContentAndReset(&debug);
            propsstr = virJSONValueToString(data->props[i], true);
            VIR_TEST_VERBOSE("json does not conform to QAPI schema");
            VIR_TEST_DEBUG("json:\n%s\ndoes not match schema. Debug output:\n %s",
                           propsstr, NULLSTR(debugmsg));
            VIR_FREE(debugmsg);
            VIR_FREE(propsstr);
            ret = -1;
        }

        virBufferFreeAndReset(&debug);
    }
    return ret;
}
예제 #4
0
static int
qemuAgentCommand(qemuAgentPtr mon,
                 virJSONValuePtr cmd,
                 virJSONValuePtr *reply,
                 int seconds)
{
    int ret = -1;
    qemuAgentMessage msg;
    char *cmdstr = NULL;
    int await_event = mon->await_event;

    *reply = NULL;

    if (qemuAgentGuestSync(mon) < 0) {
        /* helper reported the error */
        return -1;
    }

    memset(&msg, 0, sizeof(msg));

    if (!(cmdstr = virJSONValueToString(cmd, false))) {
        virReportOOMError();
        goto cleanup;
    }
    if (virAsprintf(&msg.txBuffer, "%s" LINE_ENDING, cmdstr) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    msg.txLength = strlen(msg.txBuffer);

    VIR_DEBUG("Send command '%s' for write, seconds = %d", cmdstr, seconds);

    ret = qemuAgentSend(mon, &msg, seconds);

    VIR_DEBUG("Receive command reply ret=%d rxObject=%p",
              ret, msg.rxObject);

    if (ret == 0) {
        /* If we haven't obtained any reply but we wait for an
         * event, then don't report this as error */
        if (!msg.rxObject) {
            if (await_event) {
                VIR_DEBUG("Woken up by event %d", await_event);
            } else {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing monitor reply object"));
                ret = -1;
            }
        } else {
            *reply = msg.rxObject;
        }
    }

cleanup:
    VIR_FREE(cmdstr);
    VIR_FREE(msg.txBuffer);

    return ret;
}
예제 #5
0
static int
qemuAgentCheckError(virJSONValuePtr cmd,
                    virJSONValuePtr reply)
{
    if (virJSONValueObjectHasKey(reply, "error")) {
        virJSONValuePtr error = virJSONValueObjectGet(reply, "error");
        char *cmdstr = virJSONValueToString(cmd, false);
        char *replystr = virJSONValueToString(reply, false);

        /* Log the full JSON formatted command & error */
        VIR_DEBUG("unable to execute QEMU command %s: %s",
                  cmdstr, replystr);

        /* Only send the user the command name + friendly error */
        if (!error)
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unable to execute QEMU command '%s'"),
                           qemuAgentCommandName(cmd));
        else
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unable to execute QEMU command '%s': %s"),
                           qemuAgentCommandName(cmd),
                           qemuAgentStringifyError(error));

        VIR_FREE(cmdstr);
        VIR_FREE(replystr);
        return -1;
    } else if (!virJSONValueObjectHasKey(reply, "return")) {
        char *cmdstr = virJSONValueToString(cmd, false);
        char *replystr = virJSONValueToString(reply, false);

        VIR_DEBUG("Neither 'return' nor 'error' is set in the JSON reply %s: %s",
                  cmdstr, replystr);
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unable to execute QEMU command '%s'"),
                       qemuAgentCommandName(cmd));
        VIR_FREE(cmdstr);
        VIR_FREE(replystr);
        return -1;
    }
    return 0;
}
예제 #6
0
static int
testJSONDeflatten(const void *data)
{
    const struct testInfo *info = data;
    virJSONValuePtr injson = NULL;
    virJSONValuePtr deflattened = NULL;
    char *infile = NULL;
    char *indata = NULL;
    char *outfile = NULL;
    char *actual = NULL;
    int ret = -1;

    if (virAsprintf(&infile, "%s/virjsondata/deflatten-%s-in.json",
                    abs_srcdir, info->name) < 0 ||
        virAsprintf(&outfile, "%s/virjsondata/deflatten-%s-out.json",
                    abs_srcdir, info->name) < 0)
        goto cleanup;

    if (virTestLoadFile(infile, &indata) < 0)
        goto cleanup;

    if (!(injson = virJSONValueFromString(indata)))
        goto cleanup;

    if ((deflattened = virJSONValueObjectDeflatten(injson))) {
        if (!info->pass) {
            VIR_TEST_VERBOSE("%s: deflattening should have failed\n", info->name);
            goto cleanup;
        }
    } else {
        if (!info->pass)
            ret = 0;

        goto cleanup;
    }

    if (!(actual = virJSONValueToString(deflattened, true)))
        goto cleanup;

    if (virTestCompareToFile(actual, outfile) < 0)
        goto cleanup;

    ret = 0;

 cleanup:
    virJSONValueFree(injson);
    virJSONValueFree(deflattened);
    VIR_FREE(infile);
    VIR_FREE(indata);
    VIR_FREE(outfile);
    VIR_FREE(actual);

    return ret;
}
예제 #7
0
static int
qemuAgentCommand(qemuAgentPtr mon,
                 virJSONValuePtr cmd,
                 virJSONValuePtr *reply)
{
    int ret = -1;
    qemuAgentMessage msg;
    char *cmdstr = NULL;

    *reply = NULL;

    if (qemuAgentGuestSync(mon) < 0) {
        /* helper reported the error */
        return -1;
    }

    memset(&msg, 0, sizeof(msg));

    if (!(cmdstr = virJSONValueToString(cmd))) {
        virReportOOMError();
        goto cleanup;
    }
    if (virAsprintf(&msg.txBuffer, "%s" LINE_ENDING, cmdstr) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    msg.txLength = strlen(msg.txBuffer);

    VIR_DEBUG("Send command '%s' for write", cmdstr);

    ret = qemuAgentSend(mon, &msg, false);

    VIR_DEBUG("Receive command reply ret=%d rxObject=%p",
              ret, msg.rxObject);

    if (ret == 0) {
        if (!msg.rxObject) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("Missing monitor reply object"));
            ret = -1;
        } else {
            *reply = msg.rxObject;
        }
    }

cleanup:
    VIR_FREE(cmdstr);
    VIR_FREE(msg.txBuffer);

    return ret;
}
예제 #8
0
static int
testJSONFromString(const void *data)
{
    const struct testInfo *info = data;
    virJSONValuePtr json;
    const char *expectstr = info->expect ? info->expect : info->doc;
    char *formatted = NULL;
    int ret = -1;

    json = virJSONValueFromString(info->doc);

    if (!json) {
        if (info->pass) {
            VIR_TEST_VERBOSE("Fail to parse %s\n", info->doc);
            goto cleanup;
        } else {
            VIR_TEST_DEBUG("Fail to parse %s\n", info->doc);
            ret = 0;
            goto cleanup;
        }
    }

    if (!info->pass) {
        VIR_TEST_VERBOSE("Should not have parsed %s\n", info->doc);
        goto cleanup;
    }

    VIR_TEST_DEBUG("Parsed %s\n", info->doc);

    if (!(formatted = virJSONValueToString(json, false))) {
        VIR_TEST_VERBOSE("Failed to format json data\n");
        goto cleanup;
    }

    if (STRNEQ(expectstr, formatted)) {
        virTestDifference(stderr, expectstr, formatted);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    VIR_FREE(formatted);
    virJSONValueFree(json);
    return ret;
}
예제 #9
0
int
qemuMonitorJSONIOProcessLine(qemuMonitorPtr mon,
                             const char *line,
                             qemuMonitorMessagePtr msg)
{
    static bool first = true;
    virJSONValuePtr value = NULL;
    char *json = NULL;
    int ret;

    REAL_SYM(realQemuMonitorJSONIOProcessLine);

    ret = realQemuMonitorJSONIOProcessLine(mon, line, msg);

    if (ret == 0 &&
        (value = virJSONValueFromString(line)) &&
        (json = virJSONValueToString(value, 1))) {
        char *p;
        bool skip = false;

        if (first)
            first = false;
        else
            putchar('\n');

        for (p = json; *p; p++) {
            if (skip && *p == '\n') {
                continue;
            } else {
                skip = *p == '\n';
                putchar(*p);
            }
        }
    }

    VIR_FREE(json);
    virJSONValueFree(value);
    return ret;
}
예제 #10
0
static int
testQemuDiskXMLToPropsValidateFile(const void *opaque)
{
    struct testQemuDiskXMLToJSONData *data = (void *) opaque;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *jsonpath = NULL;
    char *actual = NULL;
    int ret = -1;
    size_t i;

    if (data->fail)
        return EXIT_AM_SKIP;

    if (virAsprintf(&jsonpath, "%s%s.json",
                    testQemuDiskXMLToJSONPath, data->name) < 0)
        goto cleanup;

    for (i = 0; i < data->nprops; i++) {
        char *jsonstr;

        if (!(jsonstr = virJSONValueToString(data->props[i], true)))
            goto cleanup;

        virBufferAdd(&buf, jsonstr, -1);
        VIR_FREE(jsonstr);
    }

    if (virBufferCheckError(&buf) < 0)
        goto cleanup;

    actual = virBufferContentAndReset(&buf);

    ret = virTestCompareToFile(actual, jsonpath);

 cleanup:
    VIR_FREE(jsonpath);
    VIR_FREE(actual);
    return ret;
}
예제 #11
0
static char *testGenerateJSON(void)
{
    virNetServerPtr srv = NULL;
    virJSONValuePtr json = NULL;
    char *jsonstr = NULL;
    bool has_ipv4, has_ipv6;

    /* Our pre-saved JSON file is created so that each service
     * only has one socket. If we let libvirt bind to IPv4 and
     * IPv6 we might end up with two sockets, so force one or
     * the other based on what's available on thehost
     */
    if (virNetSocketCheckProtocols(&has_ipv4,
                                   &has_ipv6) < 0)
        return NULL;

    if (!has_ipv4 && !has_ipv6)
        return NULL;

    if (!(srv = testCreateServer(
              has_ipv4 ? "127.0.0.1" : "::1",
              has_ipv4 ? AF_INET : AF_INET6)))
        goto cleanup;

    if (!(json = virNetServerPreExecRestart(srv)))
        goto cleanup;

    if (!(jsonstr = virJSONValueToString(json, true)))
        goto cleanup;
    fprintf(stderr, "%s\n", jsonstr);
 cleanup:
    virNetServerClose(srv);
    virObjectUnref(srv);
    virJSONValueFree(json);
    return jsonstr;
}
예제 #12
0
static int
testJSONAddRemove(const void *data)
{
    const struct testInfo *info = data;
    virJSONValuePtr json;
    virJSONValuePtr name = NULL;
    char *result = NULL;
    int ret = -1;

    json = virJSONValueFromString(info->doc);
    if (!json) {
        VIR_TEST_VERBOSE("Fail to parse %s\n", info->name);
        ret = -1;
        goto cleanup;
    }

    switch (virJSONValueObjectRemoveKey(json, "name", &name)) {
    case 1:
        if (!info->pass) {
            VIR_TEST_VERBOSE("should not remove from non-object %s\n",
                             info->name);
            goto cleanup;
        }
        break;
    case -1:
        if (!info->pass)
            ret = 0;
        else
            VIR_TEST_VERBOSE("Fail to recognize non-object %s\n", info->name);
        goto cleanup;
    default:
        VIR_TEST_VERBOSE("unexpected result when removing from %s\n",
                         info->name);
        goto cleanup;
    }
    if (STRNEQ_NULLABLE(virJSONValueGetString(name), "sample")) {
        VIR_TEST_VERBOSE("unexpected value after removing name: %s\n",
                         NULLSTR(virJSONValueGetString(name)));
        goto cleanup;
    }
    if (virJSONValueObjectRemoveKey(json, "name", NULL)) {
        VIR_TEST_VERBOSE("%s",
                         "unexpected success when removing missing key\n");
        goto cleanup;
    }
    if (virJSONValueObjectAppendString(json, "newname", "foo") < 0) {
        VIR_TEST_VERBOSE("%s", "unexpected failure adding new key\n");
        goto cleanup;
    }
    if (!(result = virJSONValueToString(json, false))) {
        VIR_TEST_VERBOSE("%s", "failed to stringize result\n");
        goto cleanup;
    }
    if (STRNEQ(info->expect, result)) {
        virTestDifference(stderr, info->expect, result);
        goto cleanup;
    }
    ret = 0;

 cleanup:
    virJSONValueFree(json);
    virJSONValueFree(name);
    VIR_FREE(result);
    return ret;
}
예제 #13
0
static int
testJSONCopy(const void *data)
{
    const struct testInfo *info = data;
    virJSONValuePtr json = NULL;
    virJSONValuePtr jsonCopy = NULL;
    char *result = NULL;
    char *resultCopy = NULL;
    int ret = -1;

    json = virJSONValueFromString(info->doc);
    if (!json) {
        VIR_TEST_VERBOSE("Failed to parse %s\n", info->doc);
        goto cleanup;
    }

    jsonCopy = virJSONValueCopy(json);
    if (!jsonCopy) {
        VIR_TEST_VERBOSE("Failed to copy JSON data\n");
        goto cleanup;
    }

    result = virJSONValueToString(json, false);
    if (!result) {
        VIR_TEST_VERBOSE("Failed to format original JSON data\n");
        goto cleanup;
    }

    resultCopy = virJSONValueToString(json, false);
    if (!resultCopy) {
        VIR_TEST_VERBOSE("Failed to format copied JSON data\n");
        goto cleanup;
    }

    if (STRNEQ(result, resultCopy)) {
        if (virTestGetVerbose())
            virTestDifference(stderr, result, resultCopy);
        goto cleanup;
    }

    VIR_FREE(result);
    VIR_FREE(resultCopy);

    result = virJSONValueToString(json, true);
    if (!result) {
        VIR_TEST_VERBOSE("Failed to format original JSON data\n");
        goto cleanup;
    }

    resultCopy = virJSONValueToString(json, true);
    if (!resultCopy) {
        VIR_TEST_VERBOSE("Failed to format copied JSON data\n");
        goto cleanup;
    }

    if (STRNEQ(result, resultCopy)) {
        if (virTestGetVerbose())
            virTestDifference(stderr, result, resultCopy);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    VIR_FREE(result);
    VIR_FREE(resultCopy);
    virJSONValueFree(json);
    virJSONValueFree(jsonCopy);
    return ret;
}
예제 #14
0
static int
testJSONLookup(const void *data)
{
    const struct testInfo *info = data;
    virJSONValuePtr json;
    virJSONValuePtr value = NULL;
    char *result = NULL;
    int rc;
    int number;
    const char *str;
    int ret = -1;

    json = virJSONValueFromString(info->doc);
    if (!json) {
        VIR_TEST_VERBOSE("Fail to parse %s\n", info->doc);
        ret = -1;
        goto cleanup;
    }

    value = virJSONValueObjectGetObject(json, "a");
    if (value) {
        if (!info->pass) {
            VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have failed\n",
                             info->doc);
            goto cleanup;
        } else {
            result = virJSONValueToString(value, false);
            if (STRNEQ_NULLABLE(result, "{}")) {
                VIR_TEST_VERBOSE("lookup for 'a' in '%s' found '%s' but "
                                 "should have found '{}'\n",
                                 info->doc, NULLSTR(result));
                goto cleanup;
            }
            VIR_FREE(result);
        }
    } else if (info->pass) {
        VIR_TEST_VERBOSE("lookup for 'a' in '%s' should have succeeded\n",
                         info->doc);
        goto cleanup;
    }

    number = 2;
    rc = virJSONValueObjectGetNumberInt(json, "b", &number);
    if (rc == 0) {
        if (!info->pass) {
            VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have failed\n",
                             info->doc);
            goto cleanup;
        } else if (number != 1) {
            VIR_TEST_VERBOSE("lookup for 'b' in '%s' found %d but "
                             "should have found 1\n",
                             info->doc, number);
            goto cleanup;
        }
    } else if (info->pass) {
        VIR_TEST_VERBOSE("lookup for 'b' in '%s' should have succeeded\n",
                         info->doc);
        goto cleanup;
    }

    str = virJSONValueObjectGetString(json, "c");
    if (str) {
        if (!info->pass) {
            VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have failed\n",
                             info->doc);
            goto cleanup;
        } else if (STRNEQ(str, "str")) {
            VIR_TEST_VERBOSE("lookup for 'c' in '%s' found '%s' but "
                             "should have found 'str'\n", info->doc, str);
                goto cleanup;
        }
    } else if (info->pass) {
        VIR_TEST_VERBOSE("lookup for 'c' in '%s' should have succeeded\n",
                         info->doc);
        goto cleanup;
    }

    value = virJSONValueObjectGetArray(json, "d");
    if (value) {
        if (!info->pass) {
            VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have failed\n",
                             info->doc);
            goto cleanup;
        } else {
            result = virJSONValueToString(value, false);
            if (STRNEQ_NULLABLE(result, "[]")) {
                VIR_TEST_VERBOSE("lookup for 'd' in '%s' found '%s' but "
                                 "should have found '[]'\n",
                                 info->doc, NULLSTR(result));
                goto cleanup;
            }
            VIR_FREE(result);
        }
    } else if (info->pass) {
        VIR_TEST_VERBOSE("lookup for 'd' in '%s' should have succeeded\n",
                         info->doc);
        goto cleanup;
    }

    ret = 0;

 cleanup:
    virJSONValueFree(json);
    VIR_FREE(result);
    return ret;
}
예제 #15
0
static int testExecRestart(const void *opaque)
{
    int ret = -1;
    virNetServerPtr srv = NULL;
    const struct testExecRestartData *data = opaque;
    char *infile = NULL, *outfile = NULL;
    char *injsonstr = NULL, *outjsonstr = NULL;
    virJSONValuePtr injson = NULL, outjson = NULL;
    int fdclient[2] = { -1, -1 }, fdserver[2] = { -1, -1 };

    if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdclient) < 0) {
        virReportSystemError(errno, "%s",
                             "Cannot create socket pair");
        goto cleanup;
    }

    if (socketpair(PF_UNIX, SOCK_STREAM, 0, fdserver) < 0) {
        virReportSystemError(errno, "%s",
                             "Cannot create socket pair");
        goto cleanup;
    }

    /* We're blindly assuming the test case isn't using
     * fds 100->103 for something else, which is probably
     * fairly reasonable in general
     */
    dup2(fdserver[0], 100);
    dup2(fdserver[1], 101);
    dup2(fdclient[0], 102);
    dup2(fdclient[1], 103);

    if (virAsprintf(&infile, "%s/virnetserverdata/input-data-%s.json",
                    abs_srcdir, data->jsonfile) < 0)
        goto cleanup;

    if (virAsprintf(&outfile, "%s/virnetserverdata/output-data-%s.json",
                    abs_srcdir, data->jsonfile) < 0)
        goto cleanup;

    if (virFileReadAll(infile, 8192, &injsonstr) < 0)
        goto cleanup;

    if (!(injson = virJSONValueFromString(injsonstr)))
        goto cleanup;

    if (!(srv = virNetServerNewPostExecRestart(injson,
                                               NULL, NULL, NULL,
                                               NULL, NULL)))
        goto cleanup;

    if (!(outjson = virNetServerPreExecRestart(srv)))
        goto cleanup;

    if (!(outjsonstr = virJSONValueToString(outjson, true)))
        goto cleanup;

    if (virtTestCompareToFile(outjsonstr, outfile) < 0)
        goto fail;

    ret = 0;

 cleanup:
    if (ret < 0) {
        virErrorPtr err = virGetLastError();
        /* Rather be safe, we have lot of missing errors */
        if (err)
            fprintf(stderr, "%s\n", err->message);
        else
            fprintf(stderr, "%s\n", "Unknown error");
    }
 fail:
    VIR_FREE(infile);
    VIR_FREE(outfile);
    VIR_FREE(injsonstr);
    VIR_FREE(outjsonstr);
    virJSONValueFree(injson);
    virJSONValueFree(outjson);
    virObjectUnref(srv);
    VIR_FORCE_CLOSE(fdserver[0]);
    VIR_FORCE_CLOSE(fdserver[1]);
    VIR_FORCE_CLOSE(fdclient[0]);
    VIR_FORCE_CLOSE(fdclient[1]);
    return ret;
}
예제 #16
0
static int
testBackingXMLjsonXML(const void *args)
{
    const struct testBackingXMLjsonXMLdata *data = args;
    VIR_AUTOPTR(xmlDoc) xml = NULL;
    VIR_AUTOPTR(xmlXPathContext) ctxt = NULL;
    VIR_AUTOCLEAN(virBuffer) buf = VIR_BUFFER_INITIALIZER;
    VIR_AUTOPTR(virJSONValue) backendprops = NULL;
    VIR_AUTOPTR(virJSONValue) wrapper = NULL;
    VIR_AUTOFREE(char *) propsstr = NULL;
    VIR_AUTOFREE(char *) protocolwrapper = NULL;
    VIR_AUTOFREE(char *) actualxml = NULL;
    VIR_AUTOUNREF(virStorageSourcePtr) xmlsrc = NULL;
    VIR_AUTOUNREF(virStorageSourcePtr) jsonsrc = NULL;

    if (!(xmlsrc = virStorageSourceNew()))
        return -1;

    xmlsrc->type = data->type;

    if (!(xml = virXMLParseStringCtxt(data->xml, "(test storage source XML)", &ctxt)))
        return -1;

    if (virDomainStorageSourceParse(ctxt->node, ctxt, xmlsrc, 0, NULL) < 0) {
        fprintf(stderr, "failed to parse disk source xml\n");
        return -1;
    }

    if (!(backendprops = qemuBlockStorageSourceGetBackendProps(xmlsrc, true))) {
        fprintf(stderr, "failed to format disk source json\n");
        return -1;
    }

    if (virJSONValueObjectCreate(&wrapper, "a:file", &backendprops, NULL) < 0)
        return -1;

    if (!(propsstr = virJSONValueToString(wrapper, false)))
        return -1;

    if (virAsprintf(&protocolwrapper, "json:%s", propsstr) < 0)
        return -1;

    if (!(jsonsrc = virStorageSourceNewFromBackingAbsolute(protocolwrapper))) {
        fprintf(stderr, "failed to parse disk json\n");
        return -1;
    }

    if (virDomainDiskSourceFormat(&buf, jsonsrc, 0, false, 0, NULL) < 0 ||
        !(actualxml = virBufferContentAndReset(&buf))) {
        fprintf(stderr, "failed to format disk source xml\n");
        return -1;
    }

    if (STRNEQ(actualxml, data->xml)) {
        fprintf(stderr, "\n expected storage source xml:\n'%s'\n"
                        "actual storage source xml:\n%s\n"
                        "intermediate json:\n%s\n",
                        data->xml, actualxml, protocolwrapper);
        return -1;
    }

    return 0;
}