diff mbox series

[v2,3/3] qga: add implementation of guest-get-disks for Windows

Message ID 2cd59ce454e0da02eeb75ab7461ef420b30864f5.1599470071.git.tgolembi@redhat.com
State Superseded
Headers show
Series qga: add command guest-get-disk | expand

Commit Message

Tomáš Golembiovský Sept. 7, 2020, 9:14 a.m. UTC
The command lists all the physical disk drives. Unlike for Linux
partitions and virtual volumes are not listed.

Example output:

{
  "return": [
    {
      "name": "\\\\.\\PhysicalDrive0",
      "partition": false,
      "address": {
        "serial": "QM00001",
        "bus-type": "sata",
        ...
      },
      "slaves": []
    }
  ]
}

Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com>
---
 qga/commands-win32.c | 97 +++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 91 insertions(+), 6 deletions(-)

Comments

Marc-André Lureau Sept. 29, 2020, 3:31 p.m. UTC | #1
Hi

On Mon, Sep 7, 2020 at 1:15 PM Tomáš Golembiovský <tgolembi@redhat.com>
wrote:

> The command lists all the physical disk drives. Unlike for Linux

> partitions and virtual volumes are not listed.

>

> Example output:

>

> {

>   "return": [

>     {

>       "name": "\\\\.\\PhysicalDrive0",

>       "partition": false,

>       "address": {

>         "serial": "QM00001",

>         "bus-type": "sata",

>         ...

>       },

>       "slaves": []

>     }

>   ]

> }

>

> Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com>

> ---

>  qga/commands-win32.c | 97 +++++++++++++++++++++++++++++++++++++++++---

>  1 file changed, 91 insertions(+), 6 deletions(-)

>

> diff --git a/qga/commands-win32.c b/qga/commands-win32.c

> index e9976a0c46..9ac847a187 100644

> --- a/qga/commands-win32.c

> +++ b/qga/commands-win32.c

> @@ -945,6 +945,91 @@ out:

>      return list;

>  }

>

> +GuestDiskInfoList *qmp_guest_get_disks(Error **errp)

> +{

> +    GuestDiskInfoList *new = NULL, *ret = NULL;

> +    HDEVINFO dev_info;

> +    SP_DEVICE_INTERFACE_DATA dev_iface_data;

> +    int i;

> +

> +    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0,

> +        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);

> +    if (dev_info == INVALID_HANDLE_VALUE) {

> +        error_setg_win32(errp, GetLastError(), "failed to get device

> tree");

> +        return NULL;

> +    }

> +

> +    g_debug("enumerating devices");

> +    dev_iface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

> +    for (i = 0;

> +        SetupDiEnumDeviceInterfaces(dev_info, NULL,

> &GUID_DEVINTERFACE_DISK,

> +            i, &dev_iface_data);

> +        i++) {

> +        GuestDiskAddress *address = NULL;

> +        GuestDiskInfo *disk = NULL;

> +        Error *local_err = NULL;

> +        g_autofree PSP_DEVICE_INTERFACE_DETAIL_DATA

> +            pdev_iface_detail_data = NULL;

> +        STORAGE_DEVICE_NUMBER sdn;

> +        HANDLE dev_file;

> +        DWORD size = 0;

> +

> +        g_debug("  getting device path");

> +        while (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,

> +                pdev_iface_detail_data,

> +                size, &size,

> +                NULL)) {

> +            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {

> +                pdev_iface_detail_data = g_malloc(size);

>


Since this is called in a loop, you should use g_realloc() to avoid
potential leaks.

+                pdev_iface_detail_data->cbSize =
> +                    sizeof(*pdev_iface_detail_data);

> +            } else {

> +                g_debug("failed to get device interface details");

> +                continue;

> +            }

> +        }

> +

> +        g_debug("  device: %s", pdev_iface_detail_data->DevicePath);

> +        dev_file = CreateFile(pdev_iface_detail_data->DevicePath, 0,

> +            FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);

> +        if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER,

> +                NULL, 0, &sdn, sizeof(sdn), &size, NULL)) {

> +            CloseHandle(dev_file);

> +            debug_error("failed to get storage device number");

> +            continue;

> +        }

> +        CloseHandle(dev_file);

> +

> +        disk = g_new0(GuestDiskInfo, 1);

> +        disk->name = g_strdup_printf("\\\\.\\PhysicalDrive%lu",

> +            sdn.DeviceNumber);

> +

> +        g_debug("  number: %lu", sdn.DeviceNumber);

> +        address = g_malloc0(sizeof(GuestDiskAddress));

> +        address->has_dev = true;

> +        address->dev = g_strdup(disk->name);

> +        get_single_disk_info(sdn.DeviceNumber, address, &local_err);

> +        if (local_err) {

> +            g_debug("failed to get disk info: %s",

> +                error_get_pretty(local_err));

> +            error_free(local_err);

> +            qapi_free_GuestDiskAddress(address);

> +            address = NULL;

> +        } else {

> +            disk->address = address;

> +            disk->has_address = true;

> +        }

> +

> +        new = g_malloc0(sizeof(GuestDiskInfoList));

> +        new->value = disk;

> +        new->next = ret;

> +        ret = new;

> +    }

> +

> +    SetupDiDestroyDeviceInfoList(dev_info);

> +    return ret;

> +}

> +

>  #else

>

>  static GuestDiskAddressList *build_guest_disk_info(char *guid, Error

> **errp)

> @@ -952,6 +1037,12 @@ static GuestDiskAddressList

> *build_guest_disk_info(char *guid, Error **errp)

>      return NULL;

>  }

>

> +GuestDiskInfoList *qmp_guest_get_disks(Error **errp)

> +{

> +    error_setg(errp, QERR_UNSUPPORTED);

> +    return NULL;

> +}

> +

>  #endif /* CONFIG_QGA_NTDDSCSI */

>

>  static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)

> @@ -2229,9 +2320,3 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp)

>

>      return info;

>  }

> -

> -GuestDiskInfoList *qmp_guest_get_disks(Error **errp)

> -{

> -    error_setg(errp, QERR_UNSUPPORTED);

> -    return NULL;

> -}

> --

> 2.25.0

>

>

>

The rest looks ok to me.

-- 
Marc-André Lureau
<div dir="ltr"><div dir="ltr">Hi<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Sep 7, 2020 at 1:15 PM Tomáš Golembiovský &lt;<a href="mailto:tgolembi@redhat.com">tgolembi@redhat.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The command lists all the physical disk drives. Unlike for Linux<br>
partitions and virtual volumes are not listed.<br>
<br>
Example output:<br>
<br>
{<br>
  &quot;return&quot;: [<br>
    {<br>
      &quot;name&quot;: &quot;\\\\.\\PhysicalDrive0&quot;,<br>
      &quot;partition&quot;: false,<br>
      &quot;address&quot;: {<br>
        &quot;serial&quot;: &quot;QM00001&quot;,<br>
        &quot;bus-type&quot;: &quot;sata&quot;,<br>
        ...<br>
      },<br>
      &quot;slaves&quot;: []<br>
    }<br>
  ]<br>
}<br>
<br>
Signed-off-by: Tomáš Golembiovský &lt;<a href="mailto:tgolembi@redhat.com" target="_blank">tgolembi@redhat.com</a>&gt;<br>

---<br>
 qga/commands-win32.c | 97 +++++++++++++++++++++++++++++++++++++++++---<br>
 1 file changed, 91 insertions(+), 6 deletions(-)<br>
<br>
diff --git a/qga/commands-win32.c b/qga/commands-win32.c<br>
index e9976a0c46..9ac847a187 100644<br>
--- a/qga/commands-win32.c<br>
+++ b/qga/commands-win32.c<br>
@@ -945,6 +945,91 @@ out:<br>
     return list;<br>
 }<br>
<br>
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)<br>
+{<br>
+    GuestDiskInfoList *new = NULL, *ret = NULL;<br>
+    HDEVINFO dev_info;<br>
+    SP_DEVICE_INTERFACE_DATA dev_iface_data;<br>
+    int i;<br>
+<br>
+    dev_info = SetupDiGetClassDevs(&amp;GUID_DEVINTERFACE_DISK, 0, 0,<br>
+        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);<br>
+    if (dev_info == INVALID_HANDLE_VALUE) {<br>
+        error_setg_win32(errp, GetLastError(), &quot;failed to get device tree&quot;);<br>
+        return NULL;<br>
+    }<br>
+<br>
+    g_debug(&quot;enumerating devices&quot;);<br>
+    dev_iface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);<br>
+    for (i = 0;<br>
+        SetupDiEnumDeviceInterfaces(dev_info, NULL, &amp;GUID_DEVINTERFACE_DISK,<br>
+            i, &amp;dev_iface_data);<br>
+        i++) {<br>
+        GuestDiskAddress *address = NULL;<br>
+        GuestDiskInfo *disk = NULL;<br>
+        Error *local_err = NULL;<br>
+        g_autofree PSP_DEVICE_INTERFACE_DETAIL_DATA<br>
+            pdev_iface_detail_data = NULL;<br>
+        STORAGE_DEVICE_NUMBER sdn;<br>
+        HANDLE dev_file;<br>
+        DWORD size = 0;<br>
+<br>
+        g_debug(&quot;  getting device path&quot;);<br>
+        while (!SetupDiGetDeviceInterfaceDetail(dev_info, &amp;dev_iface_data,<br>
+                pdev_iface_detail_data,<br>
+                size, &amp;size,<br>
+                NULL)) {<br>
+            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {<br>
+                pdev_iface_detail_data = g_malloc(size);<br></blockquote><div><br></div><div>Since this is called in a loop, you should use g_realloc() to avoid potential leaks.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+                pdev_iface_detail_data-&gt;cbSize =<br>
+                    sizeof(*pdev_iface_detail_data);<br>
+            } else {<br>
+                g_debug(&quot;failed to get device interface details&quot;);<br>
+                continue;<br>
+            }<br>
+        }<br>
+<br>
+        g_debug(&quot;  device: %s&quot;, pdev_iface_detail_data-&gt;DevicePath);<br>
+        dev_file = CreateFile(pdev_iface_detail_data-&gt;DevicePath, 0,<br>
+            FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);<br>
+        if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER,<br>
+                NULL, 0, &amp;sdn, sizeof(sdn), &amp;size, NULL)) {<br>
+            CloseHandle(dev_file);<br>
+            debug_error(&quot;failed to get storage device number&quot;);<br>
+            continue;<br>
+        }<br>
+        CloseHandle(dev_file);<br>
+<br>
+        disk = g_new0(GuestDiskInfo, 1);<br>
+        disk-&gt;name = g_strdup_printf(&quot;\\\\.\\PhysicalDrive%lu&quot;,<br>
+            sdn.DeviceNumber);<br>
+<br>
+        g_debug(&quot;  number: %lu&quot;, sdn.DeviceNumber);<br>
+        address = g_malloc0(sizeof(GuestDiskAddress));<br>
+        address-&gt;has_dev = true;<br>
+        address-&gt;dev = g_strdup(disk-&gt;name);<br>
+        get_single_disk_info(sdn.DeviceNumber, address, &amp;local_err);<br>
+        if (local_err) {<br>
+            g_debug(&quot;failed to get disk info: %s&quot;,<br>
+                error_get_pretty(local_err));<br>
+            error_free(local_err);<br>
+            qapi_free_GuestDiskAddress(address);<br>
+            address = NULL;<br>
+        } else {<br>
+            disk-&gt;address = address;<br>
+            disk-&gt;has_address = true;<br>
+        }<br>
+<br>
+        new = g_malloc0(sizeof(GuestDiskInfoList));<br>
+        new-&gt;value = disk;<br>
+        new-&gt;next = ret;<br>
+        ret = new;<br>
+    }<br>
+<br>
+    SetupDiDestroyDeviceInfoList(dev_info);<br>
+    return ret;<br>
+}<br>
+<br>
 #else<br>
<br>
 static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)<br>
@@ -952,6 +1037,12 @@ static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)<br>
     return NULL;<br>
 }<br>
<br>
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)<br>
+{<br>
+    error_setg(errp, QERR_UNSUPPORTED);<br>
+    return NULL;<br>
+}<br>
+<br>
 #endif /* CONFIG_QGA_NTDDSCSI */<br>
<br>
 static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)<br>
@@ -2229,9 +2320,3 @@ GuestOSInfo *qmp_guest_get_osinfo(Error **errp)<br>
<br>
     return info;<br>
 }<br>
-<br>
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)<br>
-{<br>
-    error_setg(errp, QERR_UNSUPPORTED);<br>
-    return NULL;<br>
-}<br>
-- <br>
2.25.0<br>
<br>
<br>
</blockquote></div><div><br></div><div>The rest looks ok to me.<br></div><br>-- <br><div dir="ltr" class="gmail_signature">Marc-André Lureau<br></div></div>
diff mbox series

Patch

diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index e9976a0c46..9ac847a187 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -945,6 +945,91 @@  out:
     return list;
 }
 
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
+{
+    GuestDiskInfoList *new = NULL, *ret = NULL;
+    HDEVINFO dev_info;
+    SP_DEVICE_INTERFACE_DATA dev_iface_data;
+    int i;
+
+    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0,
+        DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+    if (dev_info == INVALID_HANDLE_VALUE) {
+        error_setg_win32(errp, GetLastError(), "failed to get device tree");
+        return NULL;
+    }
+
+    g_debug("enumerating devices");
+    dev_iface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+    for (i = 0;
+        SetupDiEnumDeviceInterfaces(dev_info, NULL, &GUID_DEVINTERFACE_DISK,
+            i, &dev_iface_data);
+        i++) {
+        GuestDiskAddress *address = NULL;
+        GuestDiskInfo *disk = NULL;
+        Error *local_err = NULL;
+        g_autofree PSP_DEVICE_INTERFACE_DETAIL_DATA
+            pdev_iface_detail_data = NULL;
+        STORAGE_DEVICE_NUMBER sdn;
+        HANDLE dev_file;
+        DWORD size = 0;
+
+        g_debug("  getting device path");
+        while (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_data,
+                pdev_iface_detail_data,
+                size, &size,
+                NULL)) {
+            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+                pdev_iface_detail_data = g_malloc(size);
+                pdev_iface_detail_data->cbSize =
+                    sizeof(*pdev_iface_detail_data);
+            } else {
+                g_debug("failed to get device interface details");
+                continue;
+            }
+        }
+
+        g_debug("  device: %s", pdev_iface_detail_data->DevicePath);
+        dev_file = CreateFile(pdev_iface_detail_data->DevicePath, 0,
+            FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+        if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER,
+                NULL, 0, &sdn, sizeof(sdn), &size, NULL)) {
+            CloseHandle(dev_file);
+            debug_error("failed to get storage device number");
+            continue;
+        }
+        CloseHandle(dev_file);
+
+        disk = g_new0(GuestDiskInfo, 1);
+        disk->name = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
+            sdn.DeviceNumber);
+
+        g_debug("  number: %lu", sdn.DeviceNumber);
+        address = g_malloc0(sizeof(GuestDiskAddress));
+        address->has_dev = true;
+        address->dev = g_strdup(disk->name);
+        get_single_disk_info(sdn.DeviceNumber, address, &local_err);
+        if (local_err) {
+            g_debug("failed to get disk info: %s",
+                error_get_pretty(local_err));
+            error_free(local_err);
+            qapi_free_GuestDiskAddress(address);
+            address = NULL;
+        } else {
+            disk->address = address;
+            disk->has_address = true;
+        }
+
+        new = g_malloc0(sizeof(GuestDiskInfoList));
+        new->value = disk;
+        new->next = ret;
+        ret = new;
+    }
+
+    SetupDiDestroyDeviceInfoList(dev_info);
+    return ret;
+}
+
 #else
 
 static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
@@ -952,6 +1037,12 @@  static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
     return NULL;
 }
 
+GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
+{
+    error_setg(errp, QERR_UNSUPPORTED);
+    return NULL;
+}
+
 #endif /* CONFIG_QGA_NTDDSCSI */
 
 static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)
@@ -2229,9 +2320,3 @@  GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
 
     return info;
 }
-
-GuestDiskInfoList *qmp_guest_get_disks(Error **errp)
-{
-    error_setg(errp, QERR_UNSUPPORTED);
-    return NULL;
-}