From nobody Mon Apr 29 05:09:56 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1490955742271800.3102062339325; Fri, 31 Mar 2017 03:22:22 -0700 (PDT) Received: from localhost ([::1]:39895 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ctthE-0007tq-RW for importer@patchew.org; Fri, 31 Mar 2017 06:22:20 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49944) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cttew-0006VL-D1 for qemu-devel@nongnu.org; Fri, 31 Mar 2017 06:20:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cttet-0004dG-Qv for qemu-devel@nongnu.org; Fri, 31 Mar 2017 06:19:58 -0400 Received: from mx1.redhat.com ([209.132.183.28]:41968) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cttet-0004d6-HV for qemu-devel@nongnu.org; Fri, 31 Mar 2017 06:19:55 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 90A94C03BD6B; Fri, 31 Mar 2017 10:19:54 +0000 (UTC) Received: from evilvm.brq.redhat.com (dhcp131-51.brq.redhat.com [10.34.131.51]) by smtp.corp.redhat.com (Postfix) with ESMTP id F3475183C3; Fri, 31 Mar 2017 10:19:51 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 90A94C03BD6B Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=vfeenstr@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 90A94C03BD6B From: Vinzenz 'evilissimo' Feenstra To: qemu-devel@nongnu.org Date: Fri, 31 Mar 2017 12:19:47 +0200 Message-Id: <20170331101947.2046-2-vfeenstr@redhat.com> In-Reply-To: <20170331101947.2046-1-vfeenstr@redhat.com> References: <20170331101947.2046-1-vfeenstr@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Fri, 31 Mar 2017 10:19:54 +0000 (UTC) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 209.132.183.28 Subject: [Qemu-devel] [PATCH v3] qemu-ga: add guest-get-osrelease command X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: marcandre.lureau@gmail.com, mdroth@linux.vnet.ibm.com, Vinzenz Feenstra Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Vinzenz Feenstra Add a new 'guest-get-osrelease' command to report OS information in the os-release format. As documented here: https://www.freedesktop.org/software/systemd/man/os-release.html The win32 implementation generates the information. On POSIX systems the /etc/os-release or /usr/lib/os-release files content is returned when available and gets extended with the fields: - QGA_UNAME_RELEASE which is the content of `uname -r` - QGA_UNAME_VERSION which is the content of `uname -v` - QGA_UNAME_MACHINE which is the content of `uname -m` Here an example for a Fedora 25 VM: virsh # qemu-agent-command F25 '{ "execute": "guest-get-osrelease" }' {"return":{"content":"NAME=3DFedora\nVERSION=3D\"25 (Server Edition)\"\n ID=3Dfedora\nVERSION_ID=3D25\nPRETTY_NAME=3D\"Fedora 25 (Server Edition)\"\n ANSI_COLOR=3D\"0;34\"\nCPE_NAME=3D\"cpe:/o:fedoraproject:fedora:25\"\n HOME_URL=3D\"https://fedoraproject.org/\"\n BUG_REPORT_URL=3D\"https://bugzilla.redhat.com/\"\n REDHAT_BUGZILLA_PRODUCT=3D\"Fedora\"\n REDHAT_BUGZILLA_PRODUCT_VERSION=3D25\nREDHAT_SUPPORT_PRODUCT=3D\"Fedora\"\n REDHAT_SUPPORT_PRODUCT_VERSION=3D25\n PRIVACY_POLICY_URL=3Dhttps://fedoraproject.org/wiki/Legal:PrivacyPolicy\n VARIANT=3D\"Server Edition\"\nVARIANT_ID=3Dserver\n\n QGA_UNAME_RELEASE=3D\"4.8.6-300.fc25.x86_64\"\n QGA_UNAME_VERSION=3D\"#1 SMP Tue Nov 1 12:36:38 UTC 2016\"\n QGA_UNAME_MACHINE=3D\"x86_64\"\n"}} And an example for a Windows 2012 R2 VM: virsh # qemu-agent-command Win2k12r2 '{ "execute": "guest-get-osrelease" }' {"return":{"content":"NAME=3D\"Microsoft Windows\"\nID=3Dmswindows\n VERSION=3D\"Microsoft Windows Server 2012 R2 (6.3)\"\nVERSION_ID=3D6.3\n PRETTY_NAME=3D\"Windows Server 2012 R2 Datacenter\"\nVARIANT=3D\"server\"\n VARIANT_ID=3Dserver\n"}} Signed-off-by: Vinzenz Feenstra --- qga/commands-posix.c | 41 +++++++++++++++++ qga/commands-win32.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++= ++++ qga/qapi-schema.json | 29 ++++++++++++ 3 files changed, 197 insertions(+) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 73d93eb..0a1fa28 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -13,6 +13,7 @@ =20 #include "qemu/osdep.h" #include +#include #include #include #include "qga/guest-agent-core.h" @@ -2418,6 +2419,12 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_inf= o(Error **errp) return NULL; } =20 +GuestOSInfo *qmp_guest_get_osinfo(Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} + #endif =20 #if !defined(CONFIG_FSFREEZE) @@ -2515,3 +2522,37 @@ void ga_command_state_init(GAState *s, GACommandStat= e *cs) ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); #endif } + +GuestOSRelease *qmp_guest_get_osrelease(Error **errp) +{ + GuestOSRelease *info =3D g_new0(GuestOSRelease, 1); + memset(info, 0, sizeof(GuestOSRelease)); + + struct utsname kinfo; + uname(&kinfo); + + if (!g_file_get_contents("/etc/os-release", &info->content, NULL, + NULL)){ + g_file_get_contents("/usr/lib/os-release", &info->content, + NULL, NULL); + } + + char *extension =3D g_strdup_printf( + "\n" + "QGA_UNAME_RELEASE=3D\"%s\"\n" + "QGA_UNAME_VERSION=3D\"%s\"\n" + "QGA_UNAME_MACHINE=3D\"%s\"\n", + kinfo.release, + kinfo.version, + kinfo.machine + ); + if (info->content !=3D NULL) { + char *previous =3D info->content; + info->content =3D g_strconcat(previous, extension, NULL); + g_free(previous); + } else { + info->content =3D extension; + } + return info; +} + diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 19d72b2..a1c217e 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -1536,3 +1536,130 @@ void ga_command_state_init(GAState *s, GACommandSta= te *cs) ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); } } + +typedef struct _ga_matrix_lookup_t { + int major; + int minor; + char const *name; +} ga_matrix_lookup_t; + +static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][8] =3D { + { + { 5, 0, "Microsoft Windows 2000"}, + { 5, 1, "Microsoft Windows XP"}, + { 6, 0, "Microsoft Windows Vista"}, + { 6, 1, "Microsoft Windows 7"}, + + { 6, 2, "Microsoft Windows 8"}, + { 6, 3, "Microsoft Windows 8.1"}, + {10, 0, "Microsoft Windows 10"}, + { 0, 0, 0} + },{ + { 5, 2, "Microsoft Windows Server 2003"}, + { 6, 0, "Microsoft Windows Server 2008"}, + { 6, 1, "Microsoft Windows Server 2008 R2"}, + { 6, 2, "Microsoft Windows Server 2012"}, + { 6, 3, "Microsoft Windows Server 2012 R2"}, + {10, 0, "Microsoft Windows Server 2016"}, + { 0, 0, 0}, + { 0, 0, 0} + } +}; + +static void ga_get_version(OSVERSIONINFOEXW *info) +{ + typedef NTSTATUS(WINAPI * rtl_get_version_t)( + OSVERSIONINFOEXW *os_version_info_ex); + HMODULE module =3D GetModuleHandle("ntdll"); + PVOID fun =3D GetProcAddress(module, "RtlGetVersion"); + rtl_get_version_t rtl_get_version =3D (rtl_get_version_t)fun; + rtl_get_version(info); +} + +static char *ga_get_win_name(OSVERSIONINFOEXW const *os_version) +{ + int major =3D (int)os_version->dwMajorVersion; + int minor =3D (int)os_version->dwMinorVersion; + int tbl_idx =3D (os_version->wProductType !=3D VER_NT_WORKSTATION); + ga_matrix_lookup_t const *table =3D WIN_VERSION_MATRIX[tbl_idx]; + while (table->name !=3D NULL) { + if (major =3D=3D table->major && minor =3D=3D table->minor) { + return g_strdup(table->name); + } + ++table; + } + return g_strdup("N/A"); +} + +static char *ga_get_windows_product_name(void) +{ + HKEY key =3D NULL; + DWORD size =3D 128; + char *result =3D g_malloc0(size); + memset(result, 0, size); + LONG err =3D ERROR_SUCCESS; + + err =3D RegOpenKeyA(HKEY_LOCAL_MACHINE, + "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", + &key); + if (err =3D=3D ERROR_SUCCESS) { + err =3D RegQueryValueExA(key, "ProductName", NULL, NULL, + (LPBYTE)result, &size); + if (err =3D=3D ERROR_MORE_DATA) { + g_free(result); + result =3D NULL; + if (size > 0) { + result =3D g_malloc0(size); + memset(result, 0, size); + } + if (result !=3D NULL && size > 0) { + err =3D RegQueryValueExA(key, "ProductName", NULL, NULL, + (LPBYTE)result, &size); + if (err !=3D ERROR_SUCCESS) { + g_free(result); + result =3D NULL; + } + } + } + } + return result; +} + +GuestOSRelease *qmp_guest_get_osrelease(Error **errp) +{ + OSVERSIONINFOEXW os_version; + ga_get_version(&os_version); + int major =3D (int)os_version.dwMajorVersion; + int minor =3D (int)os_version.dwMinorVersion; + bool server =3D os_version.wProductType !=3D VER_NT_WORKSTATION; + char *product_name =3D ga_get_windows_product_name(); + if (product_name =3D=3D NULL) { + return NULL; + } + + GuestOSRelease *info =3D g_new0(GuestOSRelease, 1); + memset(info, 0, sizeof(GuestOSRelease)); + + info->content =3D g_strdup_printf( + "NAME=3D\"Microsoft Windows\"\n" + "ID=3Dmswindows\n" + "VERSION=3D\"%s (%d.%d)\"\n" + "VERSION_ID=3D%d.%d\n" + "PRETTY_NAME=3D\"%s\"\n" + "VARIANT=3D\"%s\"\n" + "VARIANT_ID=3D%s\n", + + /* VERSION */ + ga_get_win_name(&os_version), major, minor, + /* VERSION_ID */ + major, minor, + /* PRETTY_NAME */ + product_name, + /* VARIANT */ + server ? "server" : "client", + /* VARIANT_ID */ + server ? "server" : "client" + ); + g_free(product_name); + return info; +} diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index a02dbf2..268648c 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -1042,3 +1042,32 @@ 'data': { 'path': 'str', '*arg': ['str'], '*env': ['str'], '*input-data': 'str', '*capture-output': 'bool' }, 'returns': 'GuestExec' } + +## +# @GuestOSRelease: +# +# @content: OS information in the os-release format as specified at: +# https://www.freedesktop.org/software/systemd/man/os-release.ht= ml +# On GNU/Linux this will be content of /etc/os-release or +# /usr/lib/os-release if either exists. +# On Windows, the data will be generated in the os-release forma= t. +# Additionally on POSIX systems the os-release format will be +# extended with 3 fields QGA_UNAME_{VERSION,RELEASE,MACHINE} whi= ch +# are the retrieved through the uname syscall. +# +# Since: 2.10 +## +{ 'struct': 'GuestOSRelease', + 'data': { 'content': 'str' } } + +## +# @guest-get-osrelease: +# +# Retrieve guest operating system information +# +# Returns: operating system information on success +# +# Since 2.10 +## +{ 'command': 'guest-get-osrelease', + 'returns': 'GuestOSRelease' } --=20 2.9.3