On Fri, Aug 14, 2026 at 13:47:48 +0200, Michal Privoznik via Devel wrote:
> From: Michal Privoznik <[email protected]>
> 
> QEMU agent has 'guest-get-info` command. Even though it's
> currently implemented only for Windows, it shows some interesting
> information from inside the guest, like device drivers, their
> versions, and so on.
> 
> Looking at the command definition in qga/qapi-schema.json the
> only non-optional field in returned data is 'driver-name'. The
> rest is optional. Although looking at the current implementation
> either all fields are set or device is ignored completely.
> Nevertheless, our code should follow QMP schema.
> 
> New qemuAgentGuestDeviceInfo structure is introduced among with
> qemuAgentGetGuestDeviceInfo() function which parses reply from
> agent and fills the structure. Optional fields are either set to
> NULL or -1, if missing.
> 
> Signed-off-by: Michal Privoznik <[email protected]>
> ---
>  src/hypervisor/qemu_agent.c | 119 ++++++++++++++++++++++++++++++++++++
>  src/hypervisor/qemu_agent.h |  21 +++++++
>  src/libvirt_private.syms    |   2 +
>  3 files changed, 142 insertions(+)
> 
> diff --git a/src/hypervisor/qemu_agent.c b/src/hypervisor/qemu_agent.c
> index 418386317d..fbfaafc1bb 100644
> --- a/src/hypervisor/qemu_agent.c
> +++ b/src/hypervisor/qemu_agent.c
> @@ -2843,3 +2843,122 @@ qemuAgentInterfaceFormatParams(virDomainInterfacePtr 
> *ifaces,
>          }
>      }
>  }
> +
> +
> +void
> +qemuAgentGuestDeviceInfoFree(qemuAgentGuestDeviceInfo *info)
> +{
> +    if (!info)
> +        return;
> +
> +    g_free(info->driverName);
> +    g_free(info->driverVersion);
> +    g_free(info->pci);
> +    g_free(info);
> +}
> +
> +
> +int
> +qemuAgentGetGuestDeviceInfo(qemuAgent *agent,
> +                            qemuAgentGuestDeviceInfo ***info,
> +                            bool report_unsupported)
> +{
> +    g_autoptr(virJSONValue) cmd = NULL;
> +    g_autoptr(virJSONValue) reply = NULL;
> +    virJSONValue *data = NULL;
> +    size_t ndata;
> +    size_t i;
> +    int rc;
> +
> +    if (!(cmd = qemuAgentMakeCommand("guest-get-devices", NULL)))
> +        return -1;
> +
> +    if ((rc = qemuAgentCommandFull(agent, cmd, &reply, agent->timeout,
> +                                   report_unsupported)) < 0)
> +        return rc;
> +
> +    if (!(data = virJSONValueObjectGetArray(reply, "return"))) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("qemu agent didn't return an array of devices"));
> +        return -1;
> +    }
> +
> +    ndata = virJSONValueArraySize(data);
> +
> +    *info = g_new0(qemuAgentGuestDeviceInfo *, ndata);
> +
> +    for (i = 0; i < ndata; i++) {
> +        g_autoptr(qemuAgentGuestDeviceInfo) oneInfo = NULL;
> +        virJSONValue *entry = virJSONValueArrayGet(data, i);
> +        virJSONValue *dDate = NULL;
> +        virJSONValue *idObj = NULL;
> +
> +        if (!entry) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("array element missing in guest-get-devices 
> return value"));
> +            goto error;
> +        }
> +
> +        oneInfo = g_new0(qemuAgentGuestDeviceInfo, 1);
> +
> +        oneInfo->driverName = g_strdup(virJSONValueObjectGetString(entry, 
> "driver-name"));
> +        if (!oneInfo->driverName) {
> +            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                           _("'driver-name' missing in reply of 
> guest-get-devices"));
> +            goto error;
> +        }
> +
> +        if ((dDate = virJSONValueObjectGet(entry, "driver-date"))) {
> +            if (virJSONValueGetNumberLong(dDate, &oneInfo->driverDate) < 0) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                               _("malformed 'driver-date' in reply of 
> guest-get-devices"));
> +                goto error;
> +            }
> +        } else {
> +            oneInfo->driverDate = -1;
> +        }
> +
> +        oneInfo->driverVersion = g_strdup(virJSONValueObjectGetString(entry, 
> "driver-version"));
> +
> +        if ((idObj = virJSONValueObjectGet(entry, "id"))) {
> +            const char *type = NULL;
> +
> +            if (!(type = virJSONValueObjectGetString(idObj, "type"))) {
> +                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                               _("missing 'type' in reply of 
> guest-get-devices"));
> +                goto error;
> +            }
> +
> +            if (STREQ("pci", type)) {
> +                g_autofree qemuAgentGuestDeviceInfoPCI *pci = NULL;
> +
> +                pci = g_new0(qemuAgentGuestDeviceInfoPCI, 1);
> +
> +                if (virJSONValueObjectGetNumberUint(idObj, "vendor-id", 
> &pci->vendorID) < 0) {
> +                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                                   _("missing or malformed 'vendor-id' in 
> reply of guest-get-devices"));
> +                    goto error;
> +                }
> +
> +                if (virJSONValueObjectGetNumberUint(idObj, "device-id", 
> &pci->deviceID) < 0) {
> +                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                                   _("missing or malformed 'device-id' in 
> reply of guest-get-devices"));
> +                    goto error;
> +                }
> +
> +                oneInfo->pci = g_steal_pointer(&pci);
> +            }
> +        }
> +
> +        (*info)[i] = g_steal_pointer(&oneInfo);
> +    }
> +
> +    return ndata;
> +
> + error:
> +    for (i = 0; i < ndata; i++) {
> +        qemuAgentGuestDeviceInfoFree((*info)[i]);
> +    }
> +    g_clear_pointer(info, g_free);
> +    return -1;
> +}



> diff --git a/src/hypervisor/qemu_agent.h b/src/hypervisor/qemu_agent.h
> index def6f983d4..35d2057bac 100644
> --- a/src/hypervisor/qemu_agent.h
> +++ b/src/hypervisor/qemu_agent.h
> @@ -218,3 +218,24 @@ void
>  qemuAgentInterfaceFormatParams(virDomainInterfacePtr *ifaces,
>                                 int nifaces,
>                                 virTypedParamList *list);
> +
> +typedef struct _qemuAgentGuestDeviceInfoPCI qemuAgentGuestDeviceInfoPCI;
> +struct _qemuAgentGuestDeviceInfoPCI {
> +    unsigned int vendorID;
> +    unsigned int deviceID;
> +};
> +
> +typedef struct _qemuAgentGuestDeviceInfo qemuAgentGuestDeviceInfo;
> +struct _qemuAgentGuestDeviceInfo {
> +    char *driverName;
> +    long long driverDate;

Please add the unit as a comment so it's obvious. You parse it as-is
from qemu so the value I suppose is 'nanoseconds since epoch' if the
docs are correct.


> +    char *driverVersion;
> +    qemuAgentGuestDeviceInfoPCI *pci;
> +};

Reply via email to