|
|
3f2699 |
From 2db11b426c4e16b64926f78baea594792c183f57 Mon Sep 17 00:00:00 2001
|
|
|
3f2699 |
From: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
3f2699 |
Date: Thu, 19 Apr 2018 12:33:46 -0300
|
|
|
3f2699 |
Subject: [PATCH 5/7] qemu-ga: add guest-get-osinfo command
|
|
|
3f2699 |
MIME-Version: 1.0
|
|
|
3f2699 |
Content-Type: text/plain; charset=UTF-8
|
|
|
3f2699 |
Content-Transfer-Encoding: 8bit
|
|
|
3f2699 |
|
|
|
3f2699 |
RH-Author: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
3f2699 |
Message-id: <032a36a732e654dc0d6e2043a47eb294db3ac75f.1524139831.git.mrezanin@redhat.com>
|
|
|
3f2699 |
Patchwork-id: 79704
|
|
|
3f2699 |
O-Subject: [RHEL-7.5.z qemu-guest-agent PATCH 5/7] qemu-ga: add guest-get-osinfo command
|
|
|
3f2699 |
Bugzilla: 1598210
|
|
|
3f2699 |
RH-Acked-by: Marc-André Lureau <marcandre.lureau@redhat.com>
|
|
|
3f2699 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
3f2699 |
RH-Acked-by: Tomáš Golembiovský <tgolembi@redhat.com>
|
|
|
3f2699 |
|
|
|
3f2699 |
From: Tomáš Golembiovský <tgolembi@redhat.com>
|
|
|
3f2699 |
|
|
|
3f2699 |
Add a new 'guest-get-osinfo' command for reporting basic information of
|
|
|
3f2699 |
the guest operating system. This includes machine architecture,
|
|
|
3f2699 |
version and release of the kernel and several fields from os-release
|
|
|
3f2699 |
file if it is present (as defined in [1]).
|
|
|
3f2699 |
|
|
|
3f2699 |
[1] https://www.freedesktop.org/software/systemd/man/os-release.html
|
|
|
3f2699 |
|
|
|
3f2699 |
Signed-off-by: Vinzenz Feenstra <vfeenstr@redhat.com>
|
|
|
3f2699 |
Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com>
|
|
|
3f2699 |
* moved declarations to beginning of functions
|
|
|
3f2699 |
* dropped unecessary initialization of struct utsname
|
|
|
3f2699 |
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
|
|
|
3f2699 |
(cherry picked from commit 9848f79740dc3bd2e0515470d24b8bec53904473)
|
|
|
3f2699 |
Signed-off-by: Wainer dos Santos Moschetta <wainersm@redhat.com>
|
|
|
3f2699 |
---
|
|
|
3f2699 |
qga/commands-posix.c | 135 ++++++++++++++++++++++++++++++++++++
|
|
|
3f2699 |
qga/commands-win32.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
3f2699 |
qga/qapi-schema.json | 65 ++++++++++++++++++
|
|
|
3f2699 |
3 files changed, 391 insertions(+)
|
|
|
3f2699 |
|
|
|
3f2699 |
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
|
|
|
3f2699 |
index 70348aa8c8..add8a51f2b 100644
|
|
|
3f2699 |
--- a/qga/commands-posix.c
|
|
|
3f2699 |
+++ b/qga/commands-posix.c
|
|
|
3f2699 |
@@ -13,6 +13,7 @@
|
|
|
3f2699 |
|
|
|
3f2699 |
#include "qemu/osdep.h"
|
|
|
3f2699 |
#include <sys/ioctl.h>
|
|
|
3f2699 |
+#include <sys/utsname.h>
|
|
|
3f2699 |
#include <sys/wait.h>
|
|
|
3f2699 |
#include <dirent.h>
|
|
|
3f2699 |
#include "qga/guest-agent-core.h"
|
|
|
3f2699 |
@@ -2587,3 +2588,137 @@ GuestUserList *qmp_guest_get_users(Error **errp)
|
|
|
3f2699 |
}
|
|
|
3f2699 |
|
|
|
3f2699 |
#endif
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+/* Replace escaped special characters with theire real values. The replacement
|
|
|
3f2699 |
+ * is done in place -- returned value is in the original string.
|
|
|
3f2699 |
+ */
|
|
|
3f2699 |
+static void ga_osrelease_replace_special(gchar *value)
|
|
|
3f2699 |
+{
|
|
|
3f2699 |
+ gchar *p, *p2, quote;
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ /* Trim the string at first space or semicolon if it is not enclosed in
|
|
|
3f2699 |
+ * single or double quotes. */
|
|
|
3f2699 |
+ if ((value[0] != '"') || (value[0] == '\'')) {
|
|
|
3f2699 |
+ p = strchr(value, ' ');
|
|
|
3f2699 |
+ if (p != NULL) {
|
|
|
3f2699 |
+ *p = 0;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ p = strchr(value, ';');
|
|
|
3f2699 |
+ if (p != NULL) {
|
|
|
3f2699 |
+ *p = 0;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ return;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ quote = value[0];
|
|
|
3f2699 |
+ p2 = value;
|
|
|
3f2699 |
+ p = value + 1;
|
|
|
3f2699 |
+ while (*p != 0) {
|
|
|
3f2699 |
+ if (*p == '\\') {
|
|
|
3f2699 |
+ p++;
|
|
|
3f2699 |
+ switch (*p) {
|
|
|
3f2699 |
+ case '$':
|
|
|
3f2699 |
+ case '\'':
|
|
|
3f2699 |
+ case '"':
|
|
|
3f2699 |
+ case '\\':
|
|
|
3f2699 |
+ case '`':
|
|
|
3f2699 |
+ break;
|
|
|
3f2699 |
+ default:
|
|
|
3f2699 |
+ /* Keep literal backslash followed by whatever is there */
|
|
|
3f2699 |
+ p--;
|
|
|
3f2699 |
+ break;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ } else if (*p == quote) {
|
|
|
3f2699 |
+ *p2 = 0;
|
|
|
3f2699 |
+ break;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ *(p2++) = *(p++);
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+}
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+static GKeyFile *ga_parse_osrelease(const char *fname)
|
|
|
3f2699 |
+{
|
|
|
3f2699 |
+ gchar *content = NULL;
|
|
|
3f2699 |
+ gchar *content2 = NULL;
|
|
|
3f2699 |
+ GError *err = NULL;
|
|
|
3f2699 |
+ GKeyFile *keys = g_key_file_new();
|
|
|
3f2699 |
+ const char *group = "[os-release]\n";
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ if (!g_file_get_contents(fname, &content, NULL, &err)) {
|
|
|
3f2699 |
+ slog("failed to read '%s', error: %s", fname, err->message);
|
|
|
3f2699 |
+ goto fail;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ if (!g_utf8_validate(content, -1, NULL)) {
|
|
|
3f2699 |
+ slog("file is not utf-8 encoded: %s", fname);
|
|
|
3f2699 |
+ goto fail;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ content2 = g_strdup_printf("%s%s", group, content);
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ if (!g_key_file_load_from_data(keys, content2, -1, G_KEY_FILE_NONE,
|
|
|
3f2699 |
+ &err)) {
|
|
|
3f2699 |
+ slog("failed to parse file '%s', error: %s", fname, err->message);
|
|
|
3f2699 |
+ goto fail;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ g_free(content);
|
|
|
3f2699 |
+ g_free(content2);
|
|
|
3f2699 |
+ return keys;
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+fail:
|
|
|
3f2699 |
+ g_error_free(err);
|
|
|
3f2699 |
+ g_free(content);
|
|
|
3f2699 |
+ g_free(content2);
|
|
|
3f2699 |
+ g_key_file_free(keys);
|
|
|
3f2699 |
+ return NULL;
|
|
|
3f2699 |
+}
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
|
|
|
3f2699 |
+{
|
|
|
3f2699 |
+ GuestOSInfo *info = NULL;
|
|
|
3f2699 |
+ struct utsname kinfo;
|
|
|
3f2699 |
+ GKeyFile *osrelease;
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ info = g_new0(GuestOSInfo, 1);
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ if (uname(&kinfo) != 0) {
|
|
|
3f2699 |
+ error_setg_errno(errp, errno, "uname failed");
|
|
|
3f2699 |
+ } else {
|
|
|
3f2699 |
+ info->has_kernel_version = true;
|
|
|
3f2699 |
+ info->kernel_version = g_strdup(kinfo.version);
|
|
|
3f2699 |
+ info->has_kernel_release = true;
|
|
|
3f2699 |
+ info->kernel_release = g_strdup(kinfo.release);
|
|
|
3f2699 |
+ info->has_machine = true;
|
|
|
3f2699 |
+ info->machine = g_strdup(kinfo.machine);
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ osrelease = ga_parse_osrelease("/etc/os-release");
|
|
|
3f2699 |
+ if (osrelease == NULL) {
|
|
|
3f2699 |
+ osrelease = ga_parse_osrelease("/usr/lib/os-release");
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ if (osrelease != NULL) {
|
|
|
3f2699 |
+ char *value;
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+#define GET_FIELD(field, osfield) do { \
|
|
|
3f2699 |
+ value = g_key_file_get_value(osrelease, "os-release", osfield, NULL); \
|
|
|
3f2699 |
+ if (value != NULL) { \
|
|
|
3f2699 |
+ ga_osrelease_replace_special(value); \
|
|
|
3f2699 |
+ info->has_ ## field = true; \
|
|
|
3f2699 |
+ info->field = value; \
|
|
|
3f2699 |
+ } \
|
|
|
3f2699 |
+} while (0)
|
|
|
3f2699 |
+ GET_FIELD(id, "ID");
|
|
|
3f2699 |
+ GET_FIELD(name, "NAME");
|
|
|
3f2699 |
+ GET_FIELD(pretty_name, "PRETTY_NAME");
|
|
|
3f2699 |
+ GET_FIELD(version, "VERSION");
|
|
|
3f2699 |
+ GET_FIELD(version_id, "VERSION_ID");
|
|
|
3f2699 |
+ GET_FIELD(variant, "VARIANT");
|
|
|
3f2699 |
+ GET_FIELD(variant_id, "VARIANT_ID");
|
|
|
3f2699 |
+#undef GET_FIELD
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ g_key_file_free(osrelease);
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ return info;
|
|
|
3f2699 |
+}
|
|
|
3f2699 |
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
|
|
|
3f2699 |
index fa99a8f846..9ae9836df5 100644
|
|
|
3f2699 |
--- a/qga/commands-win32.c
|
|
|
3f2699 |
+++ b/qga/commands-win32.c
|
|
|
3f2699 |
@@ -1639,3 +1639,194 @@ GuestUserList *qmp_guest_get_users(Error **err)
|
|
|
3f2699 |
return NULL;
|
|
|
3f2699 |
#endif
|
|
|
3f2699 |
}
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+typedef struct _ga_matrix_lookup_t {
|
|
|
3f2699 |
+ int major;
|
|
|
3f2699 |
+ int minor;
|
|
|
3f2699 |
+ char const *version;
|
|
|
3f2699 |
+ char const *version_id;
|
|
|
3f2699 |
+} ga_matrix_lookup_t;
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][8] = {
|
|
|
3f2699 |
+ {
|
|
|
3f2699 |
+ /* Desktop editions */
|
|
|
3f2699 |
+ { 5, 0, "Microsoft Windows 2000", "2000"},
|
|
|
3f2699 |
+ { 5, 1, "Microsoft Windows XP", "xp"},
|
|
|
3f2699 |
+ { 6, 0, "Microsoft Windows Vista", "vista"},
|
|
|
3f2699 |
+ { 6, 1, "Microsoft Windows 7" "7"},
|
|
|
3f2699 |
+ { 6, 2, "Microsoft Windows 8", "8"},
|
|
|
3f2699 |
+ { 6, 3, "Microsoft Windows 8.1", "8.1"},
|
|
|
3f2699 |
+ {10, 0, "Microsoft Windows 10", "10"},
|
|
|
3f2699 |
+ { 0, 0, 0}
|
|
|
3f2699 |
+ },{
|
|
|
3f2699 |
+ /* Server editions */
|
|
|
3f2699 |
+ { 5, 2, "Microsoft Windows Server 2003", "2003"},
|
|
|
3f2699 |
+ { 6, 0, "Microsoft Windows Server 2008", "2008"},
|
|
|
3f2699 |
+ { 6, 1, "Microsoft Windows Server 2008 R2", "2008r2"},
|
|
|
3f2699 |
+ { 6, 2, "Microsoft Windows Server 2012", "2012"},
|
|
|
3f2699 |
+ { 6, 3, "Microsoft Windows Server 2012 R2", "2012r2"},
|
|
|
3f2699 |
+ {10, 0, "Microsoft Windows Server 2016", "2016"},
|
|
|
3f2699 |
+ { 0, 0, 0},
|
|
|
3f2699 |
+ { 0, 0, 0}
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+};
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+static void ga_get_win_version(RTL_OSVERSIONINFOEXW *info, Error **errp)
|
|
|
3f2699 |
+{
|
|
|
3f2699 |
+ typedef NTSTATUS(WINAPI * rtl_get_version_t)(
|
|
|
3f2699 |
+ RTL_OSVERSIONINFOEXW *os_version_info_ex);
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ info->dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ HMODULE module = GetModuleHandle("ntdll");
|
|
|
3f2699 |
+ PVOID fun = GetProcAddress(module, "RtlGetVersion");
|
|
|
3f2699 |
+ if (fun == NULL) {
|
|
|
3f2699 |
+ error_setg(errp, QERR_QGA_COMMAND_FAILED,
|
|
|
3f2699 |
+ "Failed to get address of RtlGetVersion");
|
|
|
3f2699 |
+ return;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ rtl_get_version_t rtl_get_version = (rtl_get_version_t)fun;
|
|
|
3f2699 |
+ rtl_get_version(info);
|
|
|
3f2699 |
+ return;
|
|
|
3f2699 |
+}
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+static char *ga_get_win_name(OSVERSIONINFOEXW const *os_version, bool id)
|
|
|
3f2699 |
+{
|
|
|
3f2699 |
+ DWORD major = os_version->dwMajorVersion;
|
|
|
3f2699 |
+ DWORD minor = os_version->dwMinorVersion;
|
|
|
3f2699 |
+ int tbl_idx = (os_version->wProductType != VER_NT_WORKSTATION);
|
|
|
3f2699 |
+ ga_matrix_lookup_t const *table = WIN_VERSION_MATRIX[tbl_idx];
|
|
|
3f2699 |
+ while (table->version != NULL) {
|
|
|
3f2699 |
+ if (major == table->major && minor == table->minor) {
|
|
|
3f2699 |
+ if (id) {
|
|
|
3f2699 |
+ return g_strdup(table->version_id);
|
|
|
3f2699 |
+ } else {
|
|
|
3f2699 |
+ return g_strdup(table->version);
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ ++table;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ slog("failed to lookup Windows version: major=%lu, minor=%lu",
|
|
|
3f2699 |
+ major, minor);
|
|
|
3f2699 |
+ return g_strdup("N/A");
|
|
|
3f2699 |
+}
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+static char *ga_get_win_product_name(Error **errp)
|
|
|
3f2699 |
+{
|
|
|
3f2699 |
+ HKEY key = NULL;
|
|
|
3f2699 |
+ DWORD size = 128;
|
|
|
3f2699 |
+ char *result = g_malloc0(size);
|
|
|
3f2699 |
+ LONG err = ERROR_SUCCESS;
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ err = RegOpenKeyA(HKEY_LOCAL_MACHINE,
|
|
|
3f2699 |
+ "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
|
|
3f2699 |
+ &key);
|
|
|
3f2699 |
+ if (err != ERROR_SUCCESS) {
|
|
|
3f2699 |
+ error_setg_win32(errp, err, "failed to open registry key");
|
|
|
3f2699 |
+ goto fail;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ err = RegQueryValueExA(key, "ProductName", NULL, NULL,
|
|
|
3f2699 |
+ (LPBYTE)result, &size);
|
|
|
3f2699 |
+ if (err == ERROR_MORE_DATA) {
|
|
|
3f2699 |
+ slog("ProductName longer than expected (%lu bytes), retrying",
|
|
|
3f2699 |
+ size);
|
|
|
3f2699 |
+ g_free(result);
|
|
|
3f2699 |
+ result = NULL;
|
|
|
3f2699 |
+ if (size > 0) {
|
|
|
3f2699 |
+ result = g_malloc0(size);
|
|
|
3f2699 |
+ err = RegQueryValueExA(key, "ProductName", NULL, NULL,
|
|
|
3f2699 |
+ (LPBYTE)result, &size);
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ if (err != ERROR_SUCCESS) {
|
|
|
3f2699 |
+ error_setg_win32(errp, err, "failed to retrive ProductName");
|
|
|
3f2699 |
+ goto fail;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ return result;
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+fail:
|
|
|
3f2699 |
+ g_free(result);
|
|
|
3f2699 |
+ return NULL;
|
|
|
3f2699 |
+}
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+static char *ga_get_current_arch(void)
|
|
|
3f2699 |
+{
|
|
|
3f2699 |
+ SYSTEM_INFO info;
|
|
|
3f2699 |
+ GetNativeSystemInfo(&info;;
|
|
|
3f2699 |
+ char *result = NULL;
|
|
|
3f2699 |
+ switch (info.wProcessorArchitecture) {
|
|
|
3f2699 |
+ case PROCESSOR_ARCHITECTURE_AMD64:
|
|
|
3f2699 |
+ result = g_strdup("x86_64");
|
|
|
3f2699 |
+ break;
|
|
|
3f2699 |
+ case PROCESSOR_ARCHITECTURE_ARM:
|
|
|
3f2699 |
+ result = g_strdup("arm");
|
|
|
3f2699 |
+ break;
|
|
|
3f2699 |
+ case PROCESSOR_ARCHITECTURE_IA64:
|
|
|
3f2699 |
+ result = g_strdup("ia64");
|
|
|
3f2699 |
+ break;
|
|
|
3f2699 |
+ case PROCESSOR_ARCHITECTURE_INTEL:
|
|
|
3f2699 |
+ result = g_strdup("x86");
|
|
|
3f2699 |
+ break;
|
|
|
3f2699 |
+ case PROCESSOR_ARCHITECTURE_UNKNOWN:
|
|
|
3f2699 |
+ default:
|
|
|
3f2699 |
+ slog("unknown processor architecture 0x%0x",
|
|
|
3f2699 |
+ info.wProcessorArchitecture);
|
|
|
3f2699 |
+ result = g_strdup("unknown");
|
|
|
3f2699 |
+ break;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+ return result;
|
|
|
3f2699 |
+}
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
|
|
|
3f2699 |
+{
|
|
|
3f2699 |
+ Error *local_err = NULL;
|
|
|
3f2699 |
+ OSVERSIONINFOEXW os_version = {0};
|
|
|
3f2699 |
+ bool server;
|
|
|
3f2699 |
+ char *product_name;
|
|
|
3f2699 |
+ GuestOSInfo *info;
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ ga_get_win_version(&os_version, &local_err);
|
|
|
3f2699 |
+ if (local_err) {
|
|
|
3f2699 |
+ error_propagate(errp, local_err);
|
|
|
3f2699 |
+ return NULL;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ server = os_version.wProductType != VER_NT_WORKSTATION;
|
|
|
3f2699 |
+ product_name = ga_get_win_product_name(&local_err);
|
|
|
3f2699 |
+ if (product_name == NULL) {
|
|
|
3f2699 |
+ error_propagate(errp, local_err);
|
|
|
3f2699 |
+ return NULL;
|
|
|
3f2699 |
+ }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ info = g_new0(GuestOSInfo, 1);
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ info->has_kernel_version = true;
|
|
|
3f2699 |
+ info->kernel_version = g_strdup_printf("%lu.%lu",
|
|
|
3f2699 |
+ os_version.dwMajorVersion,
|
|
|
3f2699 |
+ os_version.dwMinorVersion);
|
|
|
3f2699 |
+ info->has_kernel_release = true;
|
|
|
3f2699 |
+ info->kernel_release = g_strdup_printf("%lu",
|
|
|
3f2699 |
+ os_version.dwBuildNumber);
|
|
|
3f2699 |
+ info->has_machine = true;
|
|
|
3f2699 |
+ info->machine = ga_get_current_arch();
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ info->has_id = true;
|
|
|
3f2699 |
+ info->id = g_strdup("mswindows");
|
|
|
3f2699 |
+ info->has_name = true;
|
|
|
3f2699 |
+ info->name = g_strdup("Microsoft Windows");
|
|
|
3f2699 |
+ info->has_pretty_name = true;
|
|
|
3f2699 |
+ info->pretty_name = product_name;
|
|
|
3f2699 |
+ info->has_version = true;
|
|
|
3f2699 |
+ info->version = ga_get_win_name(&os_version, false);
|
|
|
3f2699 |
+ info->has_version_id = true;
|
|
|
3f2699 |
+ info->version_id = ga_get_win_name(&os_version, true);
|
|
|
3f2699 |
+ info->has_variant = true;
|
|
|
3f2699 |
+ info->variant = g_strdup(server ? "server" : "client");
|
|
|
3f2699 |
+ info->has_variant_id = true;
|
|
|
3f2699 |
+ info->variant_id = g_strdup(server ? "server" : "client");
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+ return info;
|
|
|
3f2699 |
+}
|
|
|
3f2699 |
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
|
|
|
3f2699 |
index 5af73fedae..43ce3feeaa 100644
|
|
|
3f2699 |
--- a/qga/qapi-schema.json
|
|
|
3f2699 |
+++ b/qga/qapi-schema.json
|
|
|
3f2699 |
@@ -1104,3 +1104,68 @@
|
|
|
3f2699 |
##
|
|
|
3f2699 |
{ 'command': 'guest-get-timezone',
|
|
|
3f2699 |
'returns': 'GuestTimezone' }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+##
|
|
|
3f2699 |
+# @GuestOSInfo:
|
|
|
3f2699 |
+#
|
|
|
3f2699 |
+# @kernel-release:
|
|
|
3f2699 |
+# * POSIX: release field returned by uname(2)
|
|
|
3f2699 |
+# * Windows: version number of the OS
|
|
|
3f2699 |
+# @kernel-version:
|
|
|
3f2699 |
+# * POSIX: version field returned by uname(2)
|
|
|
3f2699 |
+# * Windows: build number of the OS
|
|
|
3f2699 |
+# @machine:
|
|
|
3f2699 |
+# * POSIX: machine field returned by uname(2)
|
|
|
3f2699 |
+# * Windows: one of x86, x86_64, arm, ia64
|
|
|
3f2699 |
+# @id:
|
|
|
3f2699 |
+# * POSIX: as defined by os-release(5)
|
|
|
3f2699 |
+# * Windows: contains string "mswindows"
|
|
|
3f2699 |
+# @name:
|
|
|
3f2699 |
+# * POSIX: as defined by os-release(5)
|
|
|
3f2699 |
+# * Windows: contains string "Microsoft Windows"
|
|
|
3f2699 |
+# @pretty-name:
|
|
|
3f2699 |
+# * POSIX: as defined by os-release(5)
|
|
|
3f2699 |
+# * Windows: product name, e.g. "Microsoft Windows 10 Enterprise"
|
|
|
3f2699 |
+# @version:
|
|
|
3f2699 |
+# * POSIX: as defined by os-release(5)
|
|
|
3f2699 |
+# * Windows: long version string, e.g. "Microsoft Windows Server 2008"
|
|
|
3f2699 |
+# @version-id:
|
|
|
3f2699 |
+# * POSIX: as defined by os-release(5)
|
|
|
3f2699 |
+# * Windows: short version identifier, e.g. "7" or "20012r2"
|
|
|
3f2699 |
+# @variant:
|
|
|
3f2699 |
+# * POSIX: as defined by os-release(5)
|
|
|
3f2699 |
+# * Windows: contains string "server" or "client"
|
|
|
3f2699 |
+# @variant-id:
|
|
|
3f2699 |
+# * POSIX: as defined by os-release(5)
|
|
|
3f2699 |
+# * Windows: contains string "server" or "client"
|
|
|
3f2699 |
+#
|
|
|
3f2699 |
+# Notes:
|
|
|
3f2699 |
+#
|
|
|
3f2699 |
+# On POSIX systems the fields @id, @name, @pretty-name, @version, @version-id,
|
|
|
3f2699 |
+# @variant and @variant-id follow the definition specified in os-release(5).
|
|
|
3f2699 |
+# Refer to the manual page for exact description of the fields. Their values
|
|
|
3f2699 |
+# are taken from the os-release file. If the file is not present in the system,
|
|
|
3f2699 |
+# or the values are not present in the file, the fields are not included.
|
|
|
3f2699 |
+#
|
|
|
3f2699 |
+# On Windows the values are filled from information gathered from the system.
|
|
|
3f2699 |
+#
|
|
|
3f2699 |
+# Since: 2.10
|
|
|
3f2699 |
+##
|
|
|
3f2699 |
+{ 'struct': 'GuestOSInfo',
|
|
|
3f2699 |
+ 'data': {
|
|
|
3f2699 |
+ '*kernel-release': 'str', '*kernel-version': 'str',
|
|
|
3f2699 |
+ '*machine': 'str', '*id': 'str', '*name': 'str',
|
|
|
3f2699 |
+ '*pretty-name': 'str', '*version': 'str', '*version-id': 'str',
|
|
|
3f2699 |
+ '*variant': 'str', '*variant-id': 'str' } }
|
|
|
3f2699 |
+
|
|
|
3f2699 |
+##
|
|
|
3f2699 |
+# @guest-get-osinfo:
|
|
|
3f2699 |
+#
|
|
|
3f2699 |
+# Retrieve guest operating system information
|
|
|
3f2699 |
+#
|
|
|
3f2699 |
+# Returns: @GuestOSInfo
|
|
|
3f2699 |
+#
|
|
|
3f2699 |
+# Since: 2.10
|
|
|
3f2699 |
+##
|
|
|
3f2699 |
+{ 'command': 'guest-get-osinfo',
|
|
|
3f2699 |
+ 'returns': 'GuestOSInfo' }
|
|
|
3f2699 |
--
|
|
|
3f2699 |
2.13.6
|
|
|
3f2699 |
|