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; }
int qemuAgentShutdown(qemuAgentPtr mon, qemuAgentShutdownMode mode) { int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; cmd = qemuAgentMakeCommand("guest-shutdown", "s:mode", qemuAgentShutdownModeTypeToString(mode), NULL); if (!cmd) return -1; if (mode == QEMU_AGENT_SHUTDOWN_REBOOT) mon->await_event = QEMU_AGENT_EVENT_RESET; else mon->await_event = QEMU_AGENT_EVENT_SHUTDOWN; ret = qemuAgentCommand(mon, cmd, &reply, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK); if (reply && ret == 0) ret = qemuAgentCheckError(cmd, reply); virJSONValueFree(cmd); virJSONValueFree(reply); return ret; }
static virJSONValuePtr qemuAgentMakeStringsArray(const char **strings, unsigned int len) { size_t i; virJSONValuePtr ret = virJSONValueNewArray(), str; if (!ret) return NULL; for (i = 0; i < len; i++) { str = virJSONValueNewString(strings[i]); if (!str) goto error; if (virJSONValueArrayAppend(ret, str) < 0) { virJSONValueFree(str); goto error; } } return ret; error: virJSONValueFree(ret); return NULL; }
/* * qemuAgentFSThaw: * @mon: Agent * * Issue guest-fsfreeze-thaw command to guest agent, * which unfreezes all mounted file systems and returns * number of thawed file systems on success. * * Returns: number of file system thawed on success, * -1 on error. */ int qemuAgentFSThaw(qemuAgentPtr mon) { int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; cmd = qemuAgentMakeCommand("guest-fsfreeze-thaw", NULL); if (!cmd) return -1; if (qemuAgentCommand(mon, cmd, &reply, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0 || qemuAgentCheckError(cmd, reply) < 0) goto cleanup; if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed return value")); } cleanup: virJSONValueFree(cmd); virJSONValueFree(reply); return ret; }
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; }
void virJSONValueFree(virJSONValuePtr value) { int i; if (!value || value->protect) return; switch ((virJSONType) value->type) { case VIR_JSON_TYPE_OBJECT: for (i = 0 ; i < value->data.object.npairs; i++) { VIR_FREE(value->data.object.pairs[i].key); virJSONValueFree(value->data.object.pairs[i].value); } VIR_FREE(value->data.object.pairs); break; case VIR_JSON_TYPE_ARRAY: for (i = 0 ; i < value->data.array.nvalues ; i++) virJSONValueFree(value->data.array.values[i]); VIR_FREE(value->data.array.values); break; case VIR_JSON_TYPE_STRING: VIR_FREE(value->data.string); break; case VIR_JSON_TYPE_NUMBER: VIR_FREE(value->data.number); break; case VIR_JSON_TYPE_BOOLEAN: case VIR_JSON_TYPE_NULL: break; } VIR_FREE(value); }
static int virJSONParserHandleStartMap(void *ctx) { virJSONParserPtr parser = ctx; virJSONValuePtr value = virJSONValueNewObject(); VIR_DEBUG("parser=%p", parser); if (!value) return 0; if (virJSONParserInsertValue(parser, value) < 0) { virJSONValueFree(value); return 0; } if (VIR_REALLOC_N(parser->state, parser->nstate + 1) < 0) { virJSONValueFree(value); return 0; } parser->state[parser->nstate].value = value; parser->state[parser->nstate].key = NULL; parser->nstate++; return 1; }
/** * Set the VCPU state using guest agent. * * Returns -1 on error, ninfo in case everything was successful and less than * ninfo on a partial failure. */ int qemuAgentSetVCPUs(qemuAgentPtr mon, qemuAgentCPUInfoPtr info, size_t ninfo) { int ret = -1; virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; virJSONValuePtr cpus = NULL; virJSONValuePtr cpu = NULL; size_t i; /* create the key data array */ if (!(cpus = virJSONValueNewArray())) goto cleanup; for (i = 0; i < ninfo; i++) { qemuAgentCPUInfoPtr in = &info[i]; /* create single cpu object */ if (!(cpu = virJSONValueNewObject())) goto cleanup; if (virJSONValueObjectAppendNumberInt(cpu, "logical-id", in->id) < 0) goto cleanup; if (virJSONValueObjectAppendBoolean(cpu, "online", in->online) < 0) goto cleanup; if (virJSONValueArrayAppend(cpus, cpu) < 0) goto cleanup; cpu = NULL; } if (!(cmd = qemuAgentMakeCommand("guest-set-vcpus", "a:vcpus", cpus, NULL))) goto cleanup; cpus = NULL; if (qemuAgentCommand(mon, cmd, &reply, true, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) goto cleanup; if (virJSONValueObjectGetNumberInt(reply, "return", &ret) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("malformed return value")); } cleanup: virJSONValueFree(cmd); virJSONValueFree(reply); virJSONValueFree(cpu); virJSONValueFree(cpus); return ret; }
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; }
virJSONValuePtr virNetServerClientPreExecRestart(virNetServerClientPtr client) { virJSONValuePtr object = virJSONValueNewObject(); virJSONValuePtr child; if (!object) return NULL; virObjectLock(client); if (virJSONValueObjectAppendNumberUlong(object, "id", client->id) < 0) goto error; if (virJSONValueObjectAppendNumberInt(object, "auth", client->auth) < 0) goto error; if (virJSONValueObjectAppendBoolean(object, "readonly", client->readonly) < 0) goto error; if (virJSONValueObjectAppendNumberUint(object, "nrequests_max", client->nrequests_max) < 0) goto error; if (client->conn_time && virJSONValueObjectAppendNumberLong(object, "conn_time", client->conn_time) < 0) goto error; if (!(child = virNetSocketPreExecRestart(client->sock))) goto error; if (virJSONValueObjectAppend(object, "sock", child) < 0) { virJSONValueFree(child); goto error; } if (client->privateData && client->privateDataPreExecRestart) { if (!(child = client->privateDataPreExecRestart(client, client->privateData))) goto error; if (virJSONValueObjectAppend(object, "privateData", child) < 0) { virJSONValueFree(child); goto error; } } virObjectUnlock(client); return object; error: virObjectUnlock(client); virJSONValueFree(object); return NULL; }
virNetServerPtr virNetDaemonAddServerPostExec(virNetDaemonPtr dmn, virNetServerClientPrivNew clientPrivNew, virNetServerClientPrivNewPostExecRestart clientPrivNewPostExecRestart, virNetServerClientPrivPreExecRestart clientPrivPreExecRestart, virFreeCallback clientPrivFree, void *clientPrivOpaque) { virJSONValuePtr object = NULL; virNetServerPtr srv = NULL; virObjectLock(dmn); if (!dmn->srvObject) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Cannot add more servers post-exec than " "there were pre-exec")); goto error; } if (virJSONValueIsArray(dmn->srvObject)) { object = virJSONValueArraySteal(dmn->srvObject, 0); if (virJSONValueArraySize(dmn->srvObject) == 0) { virJSONValueFree(dmn->srvObject); dmn->srvObject = NULL; } } else { object = dmn->srvObject; dmn->srvObject = NULL; } srv = virNetServerNewPostExecRestart(object, clientPrivNew, clientPrivNewPostExecRestart, clientPrivPreExecRestart, clientPrivFree, clientPrivOpaque); if (!srv || VIR_APPEND_ELEMENT_COPY(dmn->servers, dmn->nservers, srv) < 0) goto error; virJSONValueFree(object); virObjectUnlock(dmn); return srv; error: virObjectUnlock(dmn); virObjectUnref(srv); virJSONValueFree(object); return NULL; }
/** * qemuAgentSetTime: * @setTime: time to set * @sync: let guest agent to read domain's RTC (@setTime is ignored) */ int qemuAgentSetTime(qemuAgentPtr mon, long long seconds, unsigned int nseconds, bool rtcSync) { int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; if (rtcSync) { cmd = qemuAgentMakeCommand("guest-set-time", NULL); } else { /* guest agent expect time with nanosecond granularity. * Impressing. */ long long json_time; /* Check if we overflow. For some reason qemu doesn't handle unsigned * long long on the monitor well as it silently truncates numbers to * signed long long. Therefore we must check overflow against LLONG_MAX * not ULLONG_MAX. */ if (seconds > LLONG_MAX / 1000000000LL) { virReportError(VIR_ERR_INVALID_ARG, _("Time '%lld' is too big for guest agent"), seconds); return ret; } json_time = seconds * 1000000000LL; json_time += nseconds; cmd = qemuAgentMakeCommand("guest-set-time", "I:time", json_time, NULL); } if (!cmd) return ret; if (qemuAgentCommand(mon, cmd, &reply, true, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) goto cleanup; ret = 0; cleanup: virJSONValueFree(cmd); virJSONValueFree(reply); return ret; }
static int testJSONFromString(const void *data) { const struct testInfo *info = data; virJSONValuePtr json; int ret = -1; json = virJSONValueFromString(info->doc); if (info->pass) { if (!json) { VIR_TEST_VERBOSE("Fail to parse %s\n", info->doc); ret = -1; goto cleanup; } else { VIR_TEST_DEBUG("Parsed %s\n", info->doc); } } else { if (json) { VIR_TEST_VERBOSE("Should not have parsed %s\n", info->doc); ret = -1; goto cleanup; } else { VIR_TEST_DEBUG("Fail to parse %s\n", info->doc); } } ret = 0; cleanup: virJSONValueFree(json); return ret; }
/** * qemuAgentGuestSync: * @mon: Monitor * * Send guest-sync with unique ID * and wait for reply. If we get one, check if * received ID is equal to given. * * Returns: 0 on success, * -1 otherwise */ static int qemuAgentGuestSync(qemuAgentPtr mon) { int ret = -1; int send_ret; unsigned long long id, id_ret; qemuAgentMessage sync_msg; memset(&sync_msg, 0, sizeof(sync_msg)); if (virTimeMillisNow(&id) < 0) return -1; if (virAsprintf(&sync_msg.txBuffer, "{\"execute\":\"guest-sync\", " "\"arguments\":{\"id\":%llu}}", id) < 0) { virReportOOMError(); return -1; } sync_msg.txLength = strlen(sync_msg.txBuffer); VIR_DEBUG("Sending guest-sync command with ID: %llu", id); send_ret = qemuAgentSend(mon, &sync_msg, true); VIR_DEBUG("qemuAgentSend returned: %d", send_ret); if (send_ret < 0) { /* error reported */ goto cleanup; } if (!sync_msg.rxObject) { qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing monitor reply object")); goto cleanup; } if (virJSONValueObjectGetNumberUlong(sync_msg.rxObject, "return", &id_ret) < 0) { qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Malformed return value")); goto cleanup; } VIR_DEBUG("Guest returned ID: %llu", id_ret); if (id_ret != id) { qemuReportError(VIR_ERR_INTERNAL_ERROR, _("Guest agent returned ID: %llu instead of %llu"), id_ret, id); goto cleanup; } ret = 0; cleanup: virJSONValueFree(sync_msg.rxObject); VIR_FREE(sync_msg.txBuffer); return ret; }
/* Remove the key-value pair tied to @key out of @object. If @value is * not NULL, the dropped value object is returned instead of freed. * Returns 1 on success, 0 if no key was found, and -1 on error. */ int virJSONValueObjectRemoveKey(virJSONValuePtr object, const char *key, virJSONValuePtr *value) { size_t i; if (value) *value = NULL; if (object->type != VIR_JSON_TYPE_OBJECT) return -1; for (i = 0; i < object->data.object.npairs; i++) { if (STREQ(object->data.object.pairs[i].key, key)) { if (value) { *value = object->data.object.pairs[i].value; object->data.object.pairs[i].value = NULL; } VIR_FREE(object->data.object.pairs[i].key); virJSONValueFree(object->data.object.pairs[i].value); VIR_DELETE_ELEMENT(object->data.object.pairs, i, object->data.object.npairs); return 1; } } return 0; }
static int virJSONParserHandleNumber(void *ctx, const char *s, yajl_size_t l) { virJSONParserPtr parser = ctx; char *str = strndup(s, l); virJSONValuePtr value; if (!str) return -1; value = virJSONValueNewNumber(str); VIR_FREE(str); VIR_DEBUG("parser=%p str=%s", parser, str); if (!value) return 0; if (virJSONParserInsertValue(parser, value) < 0) { virJSONValueFree(value); return 0; } return 1; }
static int qemuAgentIOProcessLine(qemuAgentPtr mon, const char *line, qemuAgentMessagePtr msg) { virJSONValuePtr obj = NULL; int ret = -1; unsigned long long id; VIR_DEBUG("Line [%s]", line); if (!(obj = virJSONValueFromString(line))) goto cleanup; if (obj->type != VIR_JSON_TYPE_OBJECT) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Parsed JSON reply '%s' isn't an object"), line); goto cleanup; } if (virJSONValueObjectHasKey(obj, "QMP") == 1) { ret = 0; } else if (virJSONValueObjectHasKey(obj, "event") == 1) { ret = qemuAgentIOProcessEvent(mon, obj); } else if (virJSONValueObjectHasKey(obj, "error") == 1 || virJSONValueObjectHasKey(obj, "return") == 1) { if (msg) { msg->rxObject = obj; msg->finished = 1; obj = NULL; ret = 0; } else { /* If we've received something like: * {"return": 1234} * it is likely that somebody started GA * which is now processing our previous * guest-sync commands. Check if this is * the case and don't report an error but * return silently. */ if (virJSONValueObjectGetNumberUlong(obj, "return", &id) == 0) { VIR_DEBUG("Ignoring delayed reply to guest-sync: %llu", id); ret = 0; goto cleanup; } virReportError(VIR_ERR_INTERNAL_ERROR, _("Unexpected JSON reply '%s'"), line); } } else { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown JSON reply '%s'"), line); } cleanup: virJSONValueFree(obj); return ret; }
/* XXX add an incremental streaming parser - yajl trivially supports it */ virJSONValuePtr virJSONValueFromString(const char *jsonstring) { yajl_handle hand; virJSONParser parser = { NULL, NULL, 0 }; virJSONValuePtr ret = NULL; # ifndef WITH_YAJL2 yajl_parser_config cfg = { 1, 1 }; # endif VIR_DEBUG("string=%s", jsonstring); # ifdef WITH_YAJL2 hand = yajl_alloc(&parserCallbacks, NULL, &parser); if (hand) { yajl_config(hand, yajl_allow_comments, 1); yajl_config(hand, yajl_dont_validate_strings, 0); } # else hand = yajl_alloc(&parserCallbacks, &cfg, NULL, &parser); # endif if (!hand) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unable to create JSON parser")); goto cleanup; } if (yajl_parse(hand, (const unsigned char *)jsonstring, strlen(jsonstring)) != yajl_status_ok) { unsigned char *errstr = yajl_get_error(hand, 1, (const unsigned char*)jsonstring, strlen(jsonstring)); virReportError(VIR_ERR_INTERNAL_ERROR, _("cannot parse json %s: %s"), jsonstring, (const char*) errstr); VIR_FREE(errstr); virJSONValueFree(parser.head); goto cleanup; } ret = parser.head; cleanup: yajl_free(hand); if (parser.nstate) { size_t i; for (i = 0; i < parser.nstate; i++) { VIR_FREE(parser.state[i].key); } VIR_FREE(parser.state); } VIR_DEBUG("result=%p", parser.head); return ret; }
static int qemuAgentShutdownTestMonitorHandler(qemuMonitorTestPtr test, qemuMonitorTestItemPtr item, const char *cmdstr) { struct qemuAgentShutdownTestData *data; virJSONValuePtr val = NULL; virJSONValuePtr args; const char *cmdname; const char *mode; int ret = -1; data = qemuMonitorTestItemGetPrivateData(item); if (!(val = virJSONValueFromString(cmdstr))) return -1; if (!(cmdname = virJSONValueObjectGetString(val, "execute"))) { ret = qemuMonitorReportError(test, "Missing command name in %s", cmdstr); goto cleanup; } if (STRNEQ(cmdname, "guest-shutdown")) { ret = qemuMonitorTestAddInvalidCommandResponse(test, "guest-shutdown", cmdname); goto cleanup; } if (!(args = virJSONValueObjectGet(val, "arguments"))) { ret = qemuMonitorReportError(test, "Missing arguments section"); goto cleanup; } if (!(mode = virJSONValueObjectGetString(args, "mode"))) { ret = qemuMonitorReportError(test, "Missing shutdown mode"); goto cleanup; } if (STRNEQ(mode, data->mode)) { ret = qemuMonitorReportError(test, "expected shutdown mode '%s' got '%s'", data->mode, mode); goto cleanup; } /* now don't reply but return a qemu agent event */ qemuAgentNotifyEvent(qemuMonitorTestGetAgent(test), data->event); ret = 0; cleanup: virJSONValueFree(val); return ret; }
int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key) { virJSONValuePtr jvalue = virJSONValueNewNull(); if (!jvalue) return -1; if (virJSONValueObjectAppend(object, key, jvalue) < 0) { virJSONValueFree(jvalue); return -1; } return 0; }
int virJSONValueObjectAppendBoolean(virJSONValuePtr object, const char *key, int boolean_) { virJSONValuePtr jvalue = virJSONValueNewBoolean(boolean_); if (!jvalue) return -1; if (virJSONValueObjectAppend(object, key, jvalue) < 0) { virJSONValueFree(jvalue); return -1; } return 0; }
int virJSONValueObjectAppendNumberDouble(virJSONValuePtr object, const char *key, double number) { virJSONValuePtr jvalue = virJSONValueNewNumberDouble(number); if (!jvalue) return -1; if (virJSONValueObjectAppend(object, key, jvalue) < 0) { virJSONValueFree(jvalue); return -1; } return 0; }
int virJSONValueObjectAppendNumberUlong(virJSONValuePtr object, const char *key, unsigned long long number) { virJSONValuePtr jvalue = virJSONValueNewNumberUlong(number); if (!jvalue) return -1; if (virJSONValueObjectAppend(object, key, jvalue) < 0) { virJSONValueFree(jvalue); return -1; } return 0; }
int virJSONValueObjectAppendString(virJSONValuePtr object, const char *key, const char *value) { virJSONValuePtr jvalue = virJSONValueNewString(value); if (!jvalue) return -1; if (virJSONValueObjectAppend(object, key, jvalue) < 0) { virJSONValueFree(jvalue); return -1; } return 0; }
static void testQemuDiskXMLToPropsClear(struct testQemuDiskXMLToJSONData *data) { size_t i; for (i = 0; i < data->nprops; i++) virJSONValueFree(data->props[i]); data->nprops = 0; VIR_FREE(data->props); }
int qemuAgentSuspend(qemuAgentPtr mon, unsigned int target) { int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; cmd = qemuAgentMakeCommand(qemuAgentSuspendModeTypeToString(target), NULL); if (!cmd) return -1; mon->await_event = QEMU_AGENT_EVENT_SUSPEND; ret = qemuAgentCommand(mon, cmd, &reply, false, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK); virJSONValueFree(cmd); virJSONValueFree(reply); return ret; }
int qemuAgentFSTrim(qemuAgentPtr mon, unsigned long long minimum) { int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; cmd = qemuAgentMakeCommand("guest-fstrim", "U:minimum", minimum, NULL); if (!cmd) return ret; ret = qemuAgentCommand(mon, cmd, &reply, false, VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK); virJSONValueFree(cmd); virJSONValueFree(reply); return ret; }
int qemuAgentSuspend(qemuAgentPtr mon, unsigned int target) { int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; cmd = qemuAgentMakeCommand(qemuAgentSuspendModeTypeToString(target), NULL); if (!cmd) return -1; ret = qemuAgentCommand(mon, cmd, &reply); if (ret == 0) ret = qemuAgentCheckError(cmd, reply); virJSONValueFree(cmd); virJSONValueFree(reply); return ret; }
int qemuAgentShutdown(qemuAgentPtr mon, qemuAgentShutdownMode mode) { int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; cmd = qemuAgentMakeCommand("guest-shutdown", "s:mode", qemuAgentShutdownModeTypeToString(mode), NULL); if (!cmd) return -1; ret = qemuAgentCommand(mon, cmd, &reply); if (ret == 0) ret = qemuAgentCheckError(cmd, reply); virJSONValueFree(cmd); virJSONValueFree(reply); return ret; }
virJSONValuePtr virNetDaemonPreExecRestart(virNetDaemonPtr dmn) { virJSONValuePtr object, srvArray = NULL; size_t i; virObjectLock(dmn); if (!(object = virJSONValueNewObject())) goto error; if (!(srvArray = virJSONValueNewArray()) || virJSONValueObjectAppend(object, "servers", srvArray) < 0) goto error; for (i = 0; i < dmn->nservers; i++) { virJSONValuePtr srvJSON = NULL; srvJSON = virNetServerPreExecRestart(dmn->servers[i]); if (!srvJSON) goto error; if (virJSONValueArrayAppend(srvArray, srvJSON) < 0) { virJSONValueFree(srvJSON); goto error; } } virObjectUnlock(dmn); return object; error: virJSONValueFree(object); virJSONValueFree(srvArray); virObjectUnlock(dmn); return NULL; }