return "unknown QEMU command error";
}
+/* Checks whether the agent reply msg is an error caused by an unsupported
+ * command.
+ *
+ * Returns true when reply is CommandNotFound or CommandDisabled
+ * false otherwise
+ */
+static bool
+qemuAgentErrorCommandUnsupported(virJSONValuePtr reply)
+{
+ const char *klass;
+ virJSONValuePtr error = virJSONValueObjectGet(reply, "error");
+
+ if (!error)
+ return false;
+
+ klass = virJSONValueObjectGetString(error, "class");
+ return STREQ_NULLABLE(klass, "CommandNotFound") ||
+ STREQ_NULLABLE(klass, "CommandDisabled");
+}
+
/* Ignoring OOM in this method, since we're already reporting
* a more important error
*
return ret;
if (qemuAgentCommand(mon, cmd, &reply, true,
- VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+ VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+ if (qemuAgentErrorCommandUnsupported(reply))
+ ret = -2;
goto cleanup;
+ }
if (!(data = virJSONValueObjectGet(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
return 0;
}
+/* Returns: 0 on success
+ * -2 when agent command is not supported by the agent
+ * -1 otherwise
+ */
static int
qemuAgentGetFSInfoInternal(qemuAgentPtr mon,
qemuAgentFSInfoPtr **info,
return ret;
if (qemuAgentCommand(mon, cmd, &reply, true,
- VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+ VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+ if (qemuAgentErrorCommandUnsupported(reply))
+ ret = -2;
goto cleanup;
+ }
if (!(data = virJSONValueObjectGet(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
return ret;
}
+/* Returns: 0 on success
+ * -1 otherwise
+ */
int
qemuAgentGetFSInfo(qemuAgentPtr mon,
virDomainFSInfoPtr **info,
return ret;
}
+/* Returns: 0 on success
+ * -2 when agent command is not supported by the agent
+ * -1 otherwise
+ */
int
qemuAgentGetFSInfoParams(qemuAgentPtr mon,
virTypedParameterPtr *params,
int nfs;
if ((nfs = qemuAgentGetFSInfoInternal(mon, &fsinfo, vmdef)) < 0)
- return -1;
+ return nfs;
if (virTypedParamsAddUInt(params, nparams, maxparams,
"fs.count", nfs) < 0)
return ret;
}
+/* Returns: 0 on success
+ * -2 when agent command is not supported by the agent
+ * -1 otherwise
+ */
int
qemuAgentGetUsers(qemuAgentPtr mon,
virTypedParameterPtr *params,
return -1;
if (qemuAgentCommand(mon, cmd, &reply, true,
- VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+ VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+ if (qemuAgentErrorCommandUnsupported(reply))
+ return -2;
return -1;
+ }
if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
return ndata;
}
+/* Returns: 0 on success
+ * -2 when agent command is not supported by the agent
+ * -1 otherwise
+ */
int
qemuAgentGetOSInfo(qemuAgentPtr mon,
virTypedParameterPtr *params,
return -1;
if (qemuAgentCommand(mon, cmd, &reply, true,
- VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+ VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+ if (qemuAgentErrorCommandUnsupported(reply))
+ return -2;
return -1;
+ }
if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
return 0;
}
+/* Returns: 0 on success
+ * -2 when agent command is not supported by the agent
+ * -1 otherwise
+ */
int
qemuAgentGetTimezone(qemuAgentPtr mon,
virTypedParameterPtr *params,
return -1;
if (qemuAgentCommand(mon, cmd, &reply, true,
- VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
+ VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0) {
+ if (qemuAgentErrorCommandUnsupported(reply))
+ return -2;
return -1;
+ }
if (!(data = virJSONValueObjectGetObject(reply, "return"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
int maxparams = 0;
VIR_AUTOFREE(char *) hostname = NULL;
unsigned int supportedTypes = types;
+ int rc;
virCheckFlags(0, -1);
qemuDomainGetGuestInfoCheckSupport(&supportedTypes);
agent = qemuDomainObjEnterAgent(vm);
- /* Although the libvirt qemu driver supports all of these guest info types,
- * some guest agents might be too old to support these commands. If these
- * info categories were explicitly requested (i.e. 'types' is non-zero),
- * abort and report an error on any failures, otherwise continue and return
- * as much info as is supported by the guest agent. */
+ /* The agent info commands will return -2 for any commands that are not
+ * supported by the agent, or -1 for all other errors. In the case where no
+ * categories were explicitly requested (i.e. 'types' is 0), ignore
+ * 'unsupported' errors and gather as much information as we can. In all
+ * other cases, abort on error. */
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_USERS) {
- if (qemuAgentGetUsers(agent, params, nparams, &maxparams) < 0 &&
- types != 0)
+ rc = qemuAgentGetUsers(agent, params, nparams, &maxparams);
+ if (rc < 0 && !(rc == -2 && types == 0))
goto exitagent;
}
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_OS) {
- if (qemuAgentGetOSInfo(agent, params, nparams, &maxparams) < 0
- && types != 0)
+ rc = qemuAgentGetOSInfo(agent, params, nparams, &maxparams);
+ if (rc < 0 && !(rc == -2 && types == 0))
goto exitagent;
}
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_TIMEZONE) {
- if (qemuAgentGetTimezone(agent, params, nparams, &maxparams) < 0
- && types != 0)
+ rc = qemuAgentGetTimezone(agent, params, nparams, &maxparams);
+ if (rc < 0 && !(rc == -2 && types == 0))
goto exitagent;
}
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_HOSTNAME) {
- if (qemuAgentGetHostname(agent, &hostname) < 0) {
- if (types != 0)
- goto exitagent;
+ rc = qemuAgentGetHostname(agent, &hostname);
+ if (rc < 0 && !(rc == -2 && types == 0)) {
+ goto exitagent;
} else {
if (virTypedParamsAddString(params, nparams, &maxparams, "hostname",
hostname) < 0)
}
}
if (supportedTypes & VIR_DOMAIN_GUEST_INFO_FILESYSTEM) {
- if (qemuAgentGetFSInfoParams(agent, params, nparams, &maxparams, vm->def) < 0 &&
- types != 0)
+ rc = qemuAgentGetFSInfoParams(agent, params, nparams, &maxparams, vm->def);
+ if (rc < 0 && !(rc == -2 && types == 0))
goto exitagent;
}