From 4fc7df5ddeb2a52cafdd67cbc0b0d3182f14cfdb Mon Sep 17 00:00:00 2001 From: Davide Beatrici Date: Fri, 12 Feb 2021 08:27:15 +0100 Subject: [PATCH] FEAT: Improve OSInfo so that architecture and OS are properly reported This originally started as a Linux-only improvement (support for "/etc/os-release"), but it became pretty clear that OSInfo was not in a pretty state. Please note that the auto-update system is not affected, because it doesn't rely on OSInfo. The most important change involves the OS name. Before this commit we had "Win32", "WinX64", "OSX" and "X11". The latter was particularly misleading now that Wayland is a thing. We now have "Windows", "Linux", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "BSD", "UNIX" and "Unknown". The second most important change is the way we retrieve the version on OSes other than Windows and macOS. OSInfo had several methods, but none was aware of "/etc/os-release". We initially wanted to implement a new method, to be used as primary, that gathers info from that file. However, we later realized we can just use QSysInfo because it does exactly what we planned to do on our own. The reason why we're retaining our own methods for Windows and macOS is because they're MUCH more descriptive. For example, the build number is not in the strings returned by QSysInfo. In order to make the code easier to read, the parts that handled versions of Windows we no longer support is removed. The final change is about the info that is sent to our server. "is64bit" was set to the correct value on all platforms except for Windows, because IsWow64Process() returns true only when the process is 32 bit and running on a 64 bit OS. "arch" and "osarch" are introduced and represent the architecture of the program and the OS, respectively. "is64bit" is removed as it's now redundant. "osverbose" is also introduced and represents the full operating system version. --- src/OSInfo.cpp | 480 +++++++++++++++++-------------------------------- src/OSInfo.h | 24 ++- 2 files changed, 189 insertions(+), 315 deletions(-) diff --git a/src/OSInfo.cpp b/src/OSInfo.cpp index 82b5aa3ec..982b2864a 100644 --- a/src/OSInfo.cpp +++ b/src/OSInfo.cpp @@ -1,4 +1,4 @@ -// Copyright 2005-2020 The Mumble Developers. All rights reserved. +// Copyright 2005-2021 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . @@ -14,7 +14,7 @@ #include "Version.h" #include -#include +#include #include #include @@ -22,11 +22,7 @@ # include #endif -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) -# include -#endif - -#if defined(Q_OS_MAC) +#if defined(Q_OS_MACOS) # include # include # include @@ -35,7 +31,6 @@ // Ignore deprecation warnings for Gestalt. // See mumble-voip/mumble#3290 for more information. # pragma GCC diagnostic ignored "-Wdeprecated-declarations" - #endif #if defined(Q_OS_WIN) @@ -59,14 +54,14 @@ static QString regString(wchar_t *string, int size) { /// /// This returns a string of the kind: /// -/// Windows 10 Pro x86 1607 14390.0 +/// Windows 10 Enterprise 2009 19042.804 /// /// which is: /// -/// $ProductName $Arch $Version $Build.$Ubr +/// $ProductName $Version $Build.$Ubr /// /// Of note, $Version is formatted as YYMM. -/// So, 1607 is a Windows 10 update released in July 2016. +/// So, 2009 is a Windows 10 update released in September 2020. /// /// This function can be called on non-Windows 10 OSes. /// On those, this functions fails to query some of the @@ -75,31 +70,21 @@ static QString regString(wchar_t *string, int size) { /// this function, and if it returns an empty/null string, /// a legacy version string can be displayed. static QString win10DisplayableVersion() { - HKEY key = 0; - LONG err = 0; - DWORD len = 0; + HKEY key = 0; + auto err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &key); + if (err != ERROR_SUCCESS) { + RegCloseKey(key); + return QString(); + } + wchar_t buf[64]; - DWORD dw = 0; - - QString productName; - QString releaseId; - QString currentBuild; - QString ubr; - QString arch; - - err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &key); + DWORD len = sizeof(buf); + err = RegQueryValueEx(key, L"ProductName", nullptr, nullptr, reinterpret_cast< LPBYTE >(&buf[0]), &len); if (err != ERROR_SUCCESS) { RegCloseKey(key); return QString(); } - - len = sizeof(buf); - err = RegQueryValueEx(key, L"ProductName", nullptr, nullptr, reinterpret_cast< LPBYTE >(&buf[0]), &len); - if (err != ERROR_SUCCESS) { - RegCloseKey(key); - return QString(); - } - productName = regString(buf, static_cast< int >(len / sizeof(buf[0]))); + const auto productName = regString(buf, static_cast< int >(len / sizeof(buf[0]))); len = sizeof(buf); err = RegQueryValueEx(key, L"ReleaseId", nullptr, nullptr, reinterpret_cast< LPBYTE >(&buf[0]), &len); @@ -107,7 +92,7 @@ static QString win10DisplayableVersion() { RegCloseKey(key); return QString(); } - releaseId = regString(buf, static_cast< int >(len / sizeof(buf[0]))); + const auto releaseId = regString(buf, static_cast< int >(len / sizeof(buf[0]))); len = sizeof(buf); err = RegQueryValueEx(key, L"CurrentBuild", nullptr, nullptr, reinterpret_cast< LPBYTE >(&buf[0]), &len); @@ -115,32 +100,34 @@ static QString win10DisplayableVersion() { RegCloseKey(key); return QString(); } - currentBuild = regString(buf, static_cast< int >(len / sizeof(buf[0]))); + const auto currentBuild = regString(buf, static_cast< int >(len / sizeof(buf[0]))); - len = sizeof(dw); - err = RegQueryValueEx(key, L"UBR", nullptr, nullptr, reinterpret_cast< LPBYTE >(&dw), &len); + DWORD dw = 0; + len = sizeof(dw); + err = RegQueryValueEx(key, L"UBR", nullptr, nullptr, reinterpret_cast< LPBYTE >(&dw), &len); if (err != ERROR_SUCCESS) { RegCloseKey(key); return QString(); } - ubr = QString::number(static_cast< ulong >(dw), 10); + const auto ubr = QString::number(static_cast< ulong >(dw), 10); RegCloseKey(key); - _SYSTEM_INFO si; - GetNativeSystemInfo(&si); - if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { - arch = QLatin1String("x64"); - } else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { - arch = QLatin1String("x86"); - } else { - arch = QLatin1String("(unknown arch)"); - } - - return QString::fromLatin1("%1 %2 %3 %4.%5").arg(productName, arch, releaseId, currentBuild, ubr); + return QString::fromLatin1("%1 %2 %3.%4").arg(productName, releaseId, currentBuild, ubr); } #endif +QString OSInfo::getArchitecture(const bool build) { + QString architecture = build ? QSysInfo::buildCpuArchitecture() : QSysInfo::currentCpuArchitecture(); + if (architecture == QLatin1String("x86_64")) { + architecture = QLatin1String("x64"); + } else if (architecture == QLatin1String("i386")) { + architecture = QLatin1String("x86"); + } + + return architecture; +} + QString OSInfo::getMacHash(const QList< QHostAddress > &qlBind) { QString first, second, third; foreach (const QNetworkInterface &qni, QNetworkInterface::allInterfaces()) { @@ -182,180 +169,76 @@ QString OSInfo::getMacHash(const QList< QHostAddress > &qlBind) { QString OSInfo::getOS() { #if defined(Q_OS_WIN) -# if defined(Q_OS_WIN64) - return QLatin1String("WinX64"); -# else - return QLatin1String("Win"); -# endif -#elif defined(Q_OS_MAC) - return QLatin1String("OSX"); + return QLatin1String("Windows"); +#elif defined(Q_OS_LINUX) + return QLatin1String("Linux"); +#elif defined(Q_OS_MACOS) + return QLatin1String("macOS"); +#elif defined(Q_OS_FREEBSD) + return QLatin1String("FreeBSD"); +#elif defined(Q_OS_NETBSD) + return QLatin1String("NetBSD"); +#elif defined(Q_OS_OPENBSD) + return QLatin1String("OpenBSD"); +#elif defined(Q_OS_BSD4) + return QLatin1String("BSD"); +#elif defined(Q_OS_UNIX) + return QLatin1String("UNIX"); #else - return QLatin1String("X11"); + return QLatin1String("Unknown"); #endif } -QString OSInfo::getOSVersion() { - static QString qsCached; - - if (!qsCached.isNull()) - return qsCached.isEmpty() ? QString() : qsCached; - - QString os; - +QString OSInfo::getOSDisplayableVersion(const bool appendArch) { #if defined(Q_OS_WIN) - OSVERSIONINFOEXW ovi; - memset(&ovi, 0, sizeof(ovi)); - - ovi.dwOSVersionInfoSize = sizeof(ovi); - if (!GetVersionEx(reinterpret_cast< OSVERSIONINFOW * >(&ovi))) { - return QString(); - } - -# if QT_VERSION >= 0x050500 - os = QString::asprintf("%lu.%lu.%lu.%lu", static_cast< unsigned long >(ovi.dwMajorVersion), - static_cast< unsigned long >(ovi.dwMinorVersion), - static_cast< unsigned long >(ovi.dwBuildNumber), - (ovi.wProductType == VER_NT_WORKSTATION) ? 1UL : 0UL); -# else - // sprintf() has been deprecated in Qt 5.5 in favor for the static QString::asprintf() - os.sprintf("%lu.%lu.%lu.%lu", static_cast< unsigned long >(ovi.dwMajorVersion), - static_cast< unsigned long >(ovi.dwMinorVersion), static_cast< unsigned long >(ovi.dwBuildNumber), - (ovi.wProductType == VER_NT_WORKSTATION) ? 1UL : 0UL); -# endif // QT_VERSION >= 0x050500 - -#elif defined(Q_OS_MAC) - SInt32 major, minor, bugfix; - OSErr err = Gestalt(gestaltSystemVersionMajor, &major); - if (err == noErr) - err = Gestalt(gestaltSystemVersionMinor, &minor); - if (err == noErr) - err = Gestalt(gestaltSystemVersionBugFix, &bugfix); - if (err != noErr) - return QString::number(QSysInfo::MacintoshVersion, 16); - - char *buildno = nullptr; - char buildno_buf[32]; - size_t sz_buildno_buf = sizeof(buildno); - int ret = sysctlbyname("kern.osversion", buildno_buf, &sz_buildno_buf, nullptr, 0); - if (ret == 0) { - buildno = &buildno_buf[0]; - } - -# if QT_VERSION >= 0x050500 - os = QString::asprintf("%lu.%lu.%lu %s", static_cast< unsigned long >(major), static_cast< unsigned long >(minor), - static_cast< unsigned long >(bugfix), buildno ? buildno : "unknown"); -# else - // sprintf() has been deprecated in Qt 5.5 in favor for the static QString::asprintf() - os.sprintf("%lu.%lu.%lu %s", static_cast< unsigned long >(major), static_cast< unsigned long >(minor), - static_cast< unsigned long >(bugfix), buildno ? buildno : "unknown"); -# endif // QT_VERSION >= 0x050500 -#else -# ifdef Q_OS_LINUX - QProcess qp; - QStringList args; - args << QLatin1String("-s"); - args << QLatin1String("-d"); - qp.start(QLatin1String("lsb_release"), args); - if (qp.waitForFinished(5000)) { - os = QString::fromUtf8(qp.readAll()).simplified(); - if (os.startsWith(QLatin1Char('"')) && os.endsWith(QLatin1Char('"'))) - os = os.mid(1, os.length() - 2).trimmed(); - } - if (os.isEmpty()) - qWarning("OSInfo: Failed to execute lsb_release"); - - qp.terminate(); - if (!qp.waitForFinished(1000)) - qp.kill(); -# endif + QString os = win10DisplayableVersion(); if (os.isEmpty()) { - struct utsname un; -# ifdef Q_OS_SOLARIS - // Solaris's uname() returns a non-negative number on success. - if (uname(&un) >= 0) { -# else - // other UNIX-like systems return a 0 on success. - if (uname(&un) == 0) { -# endif -# if QT_VERSION >= 0x050500 - os = QString::asprintf("%s %s", un.sysname, un.release); -# else - // sprintf() has been deprecated in Qt 5.5 in favor for the static QString::asprintf() - os.sprintf("%s %s", un.sysname, un.release); -# endif // QT_VERSION >= 0x050500 + OSVERSIONINFOEXW ovi; + memset(&ovi, 0, sizeof(ovi)); + ovi.dwOSVersionInfoSize = sizeof(ovi); + if (!GetVersionEx(reinterpret_cast< OSVERSIONINFOW * >(&ovi))) { + return QString(); } - } -#endif - if (!os.isNull()) - qsCached = os; - else - qsCached = QLatin1String(""); + _SYSTEM_INFO si; + GetNativeSystemInfo(&si); - return qsCached; -} - -QString OSInfo::getOSDisplayableVersion() { -#if defined(Q_OS_WIN) - QString osdispver; - - // Try to query for a Windows 10-style - // displayable version. If this call - // returns a non-empty string, we're - // on Windows 10 or greater and should - // show that string. - osdispver = win10DisplayableVersion(); - if (!osdispver.isEmpty()) { - return osdispver; - } - - OSVERSIONINFOEXW ovi; - memset(&ovi, 0, sizeof(ovi)); - ovi.dwOSVersionInfoSize = sizeof(ovi); - if (!GetVersionEx(reinterpret_cast< OSVERSIONINFOW * >(&ovi))) { - return QString(); - } - - _SYSTEM_INFO si; - GetNativeSystemInfo(&si); - - if (ovi.dwMajorVersion >= 6) { if (ovi.dwMajorVersion == 10) { if (ovi.wProductType == VER_NT_WORKSTATION) { - osdispver = QLatin1String("Windows 10"); + os = QLatin1String("Windows 10"); } else { - osdispver = QLatin1String("Windows 10 Server"); + os = QLatin1String("Windows 10 Server"); } } else if (ovi.dwMajorVersion == 6) { if (ovi.dwMinorVersion == 0) { if (ovi.wProductType == VER_NT_WORKSTATION) { - osdispver = QLatin1String("Windows Vista"); + os = QLatin1String("Windows Vista"); } else { - osdispver = QLatin1String("Windows Server 2008"); + os = QLatin1String("Windows Server 2008"); } } else if (ovi.dwMinorVersion == 1) { if (ovi.wProductType == VER_NT_WORKSTATION) { - osdispver = QLatin1String("Windows 7"); + os = QLatin1String("Windows 7"); } else { - osdispver = QLatin1String("Windows Server 2008 R2"); + os = QLatin1String("Windows Server 2008 R2"); } } else if (ovi.dwMinorVersion == 2) { if (ovi.wProductType == VER_NT_WORKSTATION) { - osdispver = QLatin1String("Windows 8"); + os = QLatin1String("Windows 8"); } else { - osdispver = QLatin1String("Windows Server 2012"); + os = QLatin1String("Windows Server 2012"); } } else if (ovi.dwMinorVersion == 3) { if (ovi.wProductType == VER_NT_WORKSTATION) { - osdispver = QLatin1String("Windows 8.1"); + os = QLatin1String("Windows 8.1"); } else { - osdispver = QLatin1String("Windows Server 2012 R2"); + os = QLatin1String("Windows Server 2012 R2"); } } else if (ovi.dwMinorVersion == 4) { if (ovi.wProductType == VER_NT_WORKSTATION) { - osdispver = QLatin1String("Windows 10"); + os = QLatin1String("Windows 10"); } else { - osdispver = QLatin1String("Windows 10 Server"); + os = QLatin1String("Windows 10 Server"); } } } @@ -373,165 +256,136 @@ QString OSInfo::getOSDisplayableVersion() { switch (dwType) { case PRODUCT_ULTIMATE: - osdispver.append(QLatin1String(" Ultimate Edition")); + os.append(QLatin1String(" Ultimate Edition")); break; case PRODUCT_PROFESSIONAL: - osdispver.append(QLatin1String(" Professional")); + os.append(QLatin1String(" Professional")); break; case PRODUCT_HOME_PREMIUM: - osdispver.append(QLatin1String(" Home Premium Edition")); + os.append(QLatin1String(" Home Premium Edition")); break; case PRODUCT_HOME_BASIC: - osdispver.append(QLatin1String(" Home Basic Edition")); + os.append(QLatin1String(" Home Basic Edition")); break; case PRODUCT_ENTERPRISE: - osdispver.append(QLatin1String(" Enterprise Edition")); + os.append(QLatin1String(" Enterprise Edition")); break; case PRODUCT_BUSINESS: - osdispver.append(QLatin1String(" Business Edition")); + os.append(QLatin1String(" Business Edition")); break; case PRODUCT_STARTER: - osdispver.append(QLatin1String(" Starter Edition")); + os.append(QLatin1String(" Starter Edition")); break; case PRODUCT_CLUSTER_SERVER: - osdispver.append(QLatin1String(" Cluster Server Edition")); + os.append(QLatin1String(" Cluster Server Edition")); break; case PRODUCT_DATACENTER_SERVER: - osdispver.append(QLatin1String(" Datacenter Edition")); + os.append(QLatin1String(" Datacenter Edition")); break; case PRODUCT_DATACENTER_SERVER_CORE: - osdispver.append(QLatin1String(" Datacenter Edition (core installation)")); + os.append(QLatin1String(" Datacenter Edition (core installation)")); break; case PRODUCT_ENTERPRISE_SERVER: - osdispver.append(QLatin1String(" Enterprise Edition")); + os.append(QLatin1String(" Enterprise Edition")); break; case PRODUCT_ENTERPRISE_SERVER_CORE: - osdispver.append(QLatin1String(" Enterprise Edition (core installation)")); + os.append(QLatin1String(" Enterprise Edition (core installation)")); break; case PRODUCT_ENTERPRISE_SERVER_IA64: - osdispver.append(QLatin1String(" Enterprise Edition for Itanium-based Systems")); + os.append(QLatin1String(" Enterprise Edition for Itanium-based Systems")); break; case PRODUCT_SMALLBUSINESS_SERVER: - osdispver.append(QLatin1String(" Small Business Server")); + os.append(QLatin1String(" Small Business Server")); break; case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM: - osdispver.append(QLatin1String(" Small Business Server Premium Edition")); + os.append(QLatin1String(" Small Business Server Premium Edition")); break; case PRODUCT_STANDARD_SERVER: - osdispver.append(QLatin1String(" Standard Edition")); + os.append(QLatin1String(" Standard Edition")); break; case PRODUCT_STANDARD_SERVER_CORE: - osdispver.append(QLatin1String(" Standard Edition (core installation)")); + os.append(QLatin1String(" Standard Edition (core installation)")); break; case PRODUCT_WEB_SERVER: - osdispver.append(QLatin1String(" Web Server Edition")); + os.append(QLatin1String(" Web Server Edition")); break; } - } else if (ovi.dwMajorVersion == 5 && ovi.dwMinorVersion == 0) { - osdispver = QLatin1String("Windows 2000"); - if (ovi.wProductType == VER_NT_WORKSTATION) { - osdispver.append(QLatin1String(" Professional")); - } else { - if (ovi.wSuiteMask & VER_SUITE_DATACENTER) { - osdispver.append(QLatin1String(" Datacenter Server")); - } else if (ovi.wSuiteMask & VER_SUITE_ENTERPRISE) { - osdispver.append(QLatin1String(" Advanced Server")); - } else { - osdispver.append(QLatin1String(" Server")); - } - } - } else if (ovi.dwMajorVersion == 5 && ovi.dwMinorVersion == 1) { - osdispver = QLatin1String("Windows XP"); - if (ovi.wSuiteMask & VER_SUITE_PERSONAL) { - osdispver.append(QLatin1String(" Home Edition")); - } else { - osdispver.append(QLatin1String(" Professional")); - } - } else if (ovi.dwMajorVersion == 5 && ovi.dwMinorVersion == 2) { - if (GetSystemMetrics(SM_SERVERR2)) { - osdispver = QLatin1String("Windows Server 2003 R2"); - } else if (ovi.wSuiteMask & VER_SUITE_STORAGE_SERVER) { - osdispver = QLatin1String("Windows Storage Server 2003"); - } else if (ovi.wSuiteMask & VER_SUITE_WH_SERVER) { - osdispver = QLatin1String("Windows Home Server"); - } else if (ovi.wProductType == VER_NT_WORKSTATION - && si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { - osdispver = QLatin1String("Windows XP Professional x64 Edition"); - } else { - osdispver = QLatin1String("Windows Server 2003"); + + // Service Packs (may be empty) + static_assert(sizeof(TCHAR) == sizeof(wchar_t), "Expected Unicode TCHAR."); + auto tmp = QString::fromWCharArray(ovi.szCSDVersion); + if (!tmp.isEmpty()) { + os.append(QLatin1String(" ")); + os.append(tmp); } - if (ovi.wProductType != VER_NT_WORKSTATION) { - if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { - if (ovi.wSuiteMask & VER_SUITE_DATACENTER) { - osdispver.append(QLatin1String(" Datacenter x64 Edition")); - } else if (ovi.wSuiteMask & VER_SUITE_ENTERPRISE) { - osdispver.append(QLatin1String(" Enterprise x64 Edition")); - } else { - osdispver.append(QLatin1String(" Standard x64 Edition")); - } - } else { - if (ovi.wSuiteMask & VER_SUITE_COMPUTE_SERVER) { - osdispver.append(QLatin1String(" Compute Cluster Edition")); - } else if (ovi.wSuiteMask & VER_SUITE_DATACENTER) { - osdispver.append(QLatin1String(" Datacenter Edition")); - } else if (ovi.wSuiteMask & VER_SUITE_ENTERPRISE) { - osdispver.append(QLatin1String(" Enterprise Edition")); - } else if (ovi.wSuiteMask & VER_SUITE_BLADE) { - osdispver.append(QLatin1String(" Web Edition")); - } else { - osdispver.append(QLatin1String(" Standard Edition")); - } - } - } + tmp = QString::asprintf(" - %lu.%lu.%lu", static_cast< unsigned long >(ovi.dwMajorVersion), + static_cast< unsigned long >(ovi.dwMinorVersion), + static_cast< unsigned long >(ovi.dwBuildNumber)); + + os.append(tmp); + + return os; } - - // Service Packs (may be empty) - static_assert(sizeof(TCHAR) == sizeof(wchar_t), "Expected Unicode TCHAR."); - QString sp = QString::fromWCharArray(ovi.szCSDVersion); - if (!sp.isEmpty()) { - osdispver.append(QLatin1String(" ")); - osdispver.append(sp); - } - - // Architecture - if (ovi.dwMajorVersion >= 6) { - if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) { - osdispver.append(QLatin1String(" x64")); - } else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) { - osdispver.append(QLatin1String(" x86")); - } - } - - QString osv; -# if QT_VERSION >= 0x050500 - osv = QString::asprintf(" - %lu.%lu.%lu", static_cast< unsigned long >(ovi.dwMajorVersion), - static_cast< unsigned long >(ovi.dwMinorVersion), - static_cast< unsigned long >(ovi.dwBuildNumber)); -# else - // sprintf() has been deprecated in Qt 5.5 in favor for the static QString::asprintf() - osv.sprintf(" - %lu.%lu.%lu", static_cast< unsigned long >(ovi.dwMajorVersion), - static_cast< unsigned long >(ovi.dwMinorVersion), static_cast< unsigned long >(ovi.dwBuildNumber)); -# endif // QT_VERSION >= 0x050500 - osdispver.append(osv); - - return osdispver; #else - return OSInfo::getOSVersion(); + const QString os = QSysInfo::prettyProductName(); +#endif + if (!appendArch) { + return os; + } + + return os + QString(" [%1]").arg(getArchitecture(false)); +} + +QString OSInfo::getOSVersion() { +#if defined(Q_OS_WIN) + OSVERSIONINFOEXW ovi; + memset(&ovi, 0, sizeof(ovi)); + + ovi.dwOSVersionInfoSize = sizeof(ovi); + if (!GetVersionEx(reinterpret_cast< OSVERSIONINFOW * >(&ovi))) { + return QString(); + } + + return QString::asprintf("%lu.%lu.%lu.%lu", static_cast< unsigned long >(ovi.dwMajorVersion), + static_cast< unsigned long >(ovi.dwMinorVersion), + static_cast< unsigned long >(ovi.dwBuildNumber), + (ovi.wProductType == VER_NT_WORKSTATION) ? 1UL : 0UL); +#elif defined(Q_OS_MACOS) + SInt32 major, minor, bugfix; + OSErr err = Gestalt(gestaltSystemVersionMajor, &major); + if (err == noErr) + err = Gestalt(gestaltSystemVersionMinor, &minor); + if (err == noErr) + err = Gestalt(gestaltSystemVersionBugFix, &bugfix); + if (err != noErr) + return QString::number(QSysInfo::MacintoshVersion, 16); + + char *buildno = nullptr; + char buildno_buf[32]; + size_t sz_buildno_buf = sizeof(buildno); + int ret = sysctlbyname("kern.osversion", buildno_buf, &sz_buildno_buf, nullptr, 0); + if (ret == 0) { + buildno = &buildno_buf[0]; + } + + return QString::asprintf("%lu.%lu.%lu %s", static_cast< unsigned long >(major), static_cast< unsigned long >(minor), + static_cast< unsigned long >(bugfix), buildno ? buildno : "unknown"); +#else + return QSysInfo::productVersion(); #endif } void OSInfo::fillXml(QDomDocument &doc, QDomElement &root, const QString &os, const QString &osver, const QList< QHostAddress > &qlBind) { - QDomElement tag; - QDomText t; - bool bIs64; - bool bSSE2 = false; - QString cpu_id, cpu_extid; - - tag = doc.createElement(QLatin1String("machash")); + QDomElement tag = doc.createElement(QLatin1String("machash")); root.appendChild(tag); - t = doc.createTextNode(OSInfo::getMacHash(qlBind)); + QDomText t = doc.createTextNode(getMacHash(qlBind)); + tag.appendChild(t); + + tag = doc.createElement(QLatin1String("arch")); + root.appendChild(tag); + t = doc.createTextNode(getArchitecture(true)); tag.appendChild(t); tag = doc.createElement(QLatin1String("version")); @@ -549,28 +403,28 @@ void OSInfo::fillXml(QDomDocument &doc, QDomElement &root, const QString &os, co t = doc.createTextNode(os); tag.appendChild(t); + tag = doc.createElement(QLatin1String("osarch")); + root.appendChild(tag); + t = doc.createTextNode(getArchitecture(false)); + tag.appendChild(t); + tag = doc.createElement(QLatin1String("osver")); root.appendChild(tag); t = doc.createTextNode(osver); tag.appendChild(t); + tag = doc.createElement(QLatin1String("osverbose")); + root.appendChild(tag); + t = doc.createTextNode(getOSDisplayableVersion(false)); + tag.appendChild(t); + tag = doc.createElement(QLatin1String("qt")); root.appendChild(tag); t = doc.createTextNode(QString::fromLatin1(qVersion())); tag.appendChild(t); -#if defined(Q_OS_WIN) - BOOL bIsWow64 = FALSE; - IsWow64Process(GetCurrentProcess(), &bIsWow64); - bIs64 = bIsWow64; -#else - bIs64 = (QSysInfo::WordSize == 64); -#endif - tag = doc.createElement(QLatin1String("is64bit")); - root.appendChild(tag); - t = doc.createTextNode(QString::number(bIs64 ? 1 : 0)); - tag.appendChild(t); - + QString cpu_id, cpu_extid; + bool bSSE2 = false; #if defined(Q_OS_WIN) # define regstr(x) QString::fromLatin1(reinterpret_cast< const char * >(&x), 4) int chop; diff --git a/src/OSInfo.h b/src/OSInfo.h index 287c6d414..ae2936da8 100644 --- a/src/OSInfo.h +++ b/src/OSInfo.h @@ -1,4 +1,4 @@ -// Copyright 2005-2020 The Mumble Developers. All rights reserved. +// Copyright 2005-2021 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . @@ -15,10 +15,30 @@ class QHostAddress; class OSInfo { public: + /// If \p build is false, returns the operating system architecture. + /// If \p build is true, returns the build architecture. + static QString getArchitecture(const bool build); + + /// Returns an hash generated from the primary network interface's MAC address. static QString getMacHash(const QList< QHostAddress > & = QList< QHostAddress >()); + + /// Returns the operating system's basename. + /// Examples: "Windows", "Linux", "macOS", "FreeBSD", "Unknown", etc. static QString getOS(); + + /// Returns the complete operating system version. + /// + /// Examples: + /// "Windows 10 Enterprise 2009 19042.804 [x64]" + /// "Debian GNU/Linux bullseye/sid [x64]" + /// + /// The architecture is not explicitly added when \p appendArch is false. + static QString getOSDisplayableVersion(const bool appendArch = true); + + /// Returns the operating system's version. + /// Examples: "10.0.19042.1", "10.16.0 20C69" static QString getOSVersion(); - static QString getOSDisplayableVersion(); + static void fillXml(QDomDocument &doc, QDomElement &root, const QString &os = OSInfo::getOS(), const QString &osver = OSInfo::getOSVersion(), const QList< QHostAddress > & = QList< QHostAddress >());