summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2022-09-19 15:37:14 +0200
committerSona Kurazyan <sona.kurazyan@qt.io>2022-09-22 13:48:15 +0200
commit767beb7fff6f08f5574a193967f8f814970ac289 (patch)
tree06a3378b4163481ab21f534430954653ffe59581 /src/corelib
parent27197d1a123e721730cee28ea25e726aeb5768f5 (diff)
Move the implementation and docs of QSysInfo to qsysinfo.cpp
Task-number: QTBUG-106154 Change-Id: Ib2d812104b3514fb255d79ab6e4097ec6a851e21 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/CMakeLists.txt2
-rw-r--r--src/corelib/global/qglobal.cpp1046
-rw-r--r--src/corelib/global/qsysinfo.cpp1055
3 files changed, 1056 insertions, 1047 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 0a3ebd0b87..702322344d 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -75,7 +75,7 @@ qt_internal_add_module(Core
global/qprocessordetection.h
global/qrandom.cpp global/qrandom.h global/qrandom_p.h
global/qswap.h
- global/qsysinfo.h
+ global/qsysinfo.cpp global/qsysinfo.h
global/qsystemdetection.h
global/qtclasshelpermacros.h
global/qtconfigmacros.h
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 1228c98863..4b53b7e9f7 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -8,12 +8,6 @@
#include "qlist.h"
#include "qdir.h"
#include "qdatetime.h"
-#include "qoperatingsystemversion.h"
-#include "qoperatingsystemversion_p.h"
-#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
-# include "qoperatingsystemversion_win_p.h"
-# include "private/qwinregistry_p.h"
-#endif // Q_OS_WIN || Q_OS_CYGWIN
#include <private/qlocale_tools_p.h>
#include "qnativeinterface.h"
#include "qnativeinterface_p.h"
@@ -35,28 +29,6 @@
# include <envLib.h>
#endif
-#ifdef Q_OS_ANDROID
-#include <qjniobject.h>
-#endif
-
-#if defined(Q_OS_SOLARIS)
-# include <sys/systeminfo.h>
-#endif
-
-#if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
-# include <IOKit/IOKitLib.h>
-# include <private/qcore_mac_p.h>
-#endif
-
-#ifdef Q_OS_UNIX
-#include <sys/utsname.h>
-#include <private/qcore_unix_p.h>
-#endif
-
-#ifdef Q_OS_BSD4
-#include <sys/sysctl.h>
-#endif
-
#if defined(Q_OS_INTEGRITY)
extern "C" {
// Function mmap resides in libshm_client.a. To be able to link with it one needs
@@ -70,8 +42,6 @@ extern "C" {
}
#endif
-#include "archdetect.cpp"
-
#ifdef qFatal
// the qFatal in this file are just redirections from elsewhere, so
// don't capture any context again
@@ -208,44 +178,6 @@ using namespace Qt::StringLiterals;
*****************************************************************************/
/*!
- \class QSysInfo
- \inmodule QtCore
- \brief The QSysInfo class provides information about the system.
-
- \list
- \li \l WordSize specifies the size of a pointer for the platform
- on which the application is compiled.
- \li \l ByteOrder specifies whether the platform is big-endian or
- little-endian.
- \endlist
-
- Some constants are defined only on certain platforms. You can use
- the preprocessor symbols Q_OS_WIN and Q_OS_MACOS to test that
- the application is compiled under Windows or \macos.
-
- \sa QLibraryInfo
-*/
-
-/*!
- \enum QSysInfo::Sizes
-
- This enum provides platform-specific information about the sizes of data
- structures used by the underlying architecture.
-
- \value WordSize The size in bits of a pointer for the platform on which
- the application is compiled (32 or 64).
-*/
-
-/*!
- \enum QSysInfo::Endian
-
- \value BigEndian Big-endian byte order (also called Network byte order)
- \value LittleEndian Little-endian byte order
- \value ByteOrder Equals BigEndian or LittleEndian, depending on
- the platform's byte order.
-*/
-
-/*!
\macro Q_OS_DARWIN
\relates <QtGlobal>
@@ -945,984 +877,6 @@ using namespace Qt::StringLiterals;
\sa QT_DISABLE_DEPRECATED_BEFORE
*/
-#if defined(Q_OS_MAC)
-
-QT_BEGIN_INCLUDE_NAMESPACE
-#include "private/qcore_mac_p.h"
-#include "qnamespace.h"
-QT_END_INCLUDE_NAMESPACE
-
-#ifdef Q_OS_DARWIN
-static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
-{
-#ifdef Q_OS_MACOS
- if (version.majorVersion() == 12)
- return "Monterey";
- // Compare against predefined constant to handle 10.16/11.0
- if (QOperatingSystemVersion::MacOSBigSur.version().isPrefixOf(version.version()))
- return "Big Sur";
- if (version.majorVersion() == 10) {
- switch (version.minorVersion()) {
- case 9:
- return "Mavericks";
- case 10:
- return "Yosemite";
- case 11:
- return "El Capitan";
- case 12:
- return "Sierra";
- case 13:
- return "High Sierra";
- case 14:
- return "Mojave";
- case 15:
- return "Catalina";
- }
- }
- // unknown, future version
-#else
- Q_UNUSED(version);
-#endif
- return nullptr;
-}
-#endif
-
-#elif defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
-
-QT_BEGIN_INCLUDE_NAMESPACE
-#include "qt_windows.h"
-QT_END_INCLUDE_NAMESPACE
-
-# ifndef QT_BOOTSTRAPPED
-class QWindowsSockInit
-{
-public:
- QWindowsSockInit();
- ~QWindowsSockInit();
- int version;
-};
-
-QWindowsSockInit::QWindowsSockInit()
-: version(0)
-{
- //### should we try for 2.2 on all platforms ??
- WSAData wsadata;
-
- // IPv6 requires Winsock v2.0 or better.
- if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) {
- qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
- } else {
- version = 0x20;
- }
-}
-
-QWindowsSockInit::~QWindowsSockInit()
-{
- WSACleanup();
-}
-Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
-# endif // QT_BOOTSTRAPPED
-
-static QString readVersionRegistryString(const wchar_t *subKey)
-{
- return QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)")
- .stringValue(subKey);
-}
-
-static inline QString windowsDisplayVersion()
-{
- // https://tickets.puppetlabs.com/browse/FACT-3058
- // The "ReleaseId" key stopped updating since Windows 10 20H2.
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10_20H2)
- return readVersionRegistryString(L"DisplayVersion");
- else
- return readVersionRegistryString(L"ReleaseId");
-}
-
-static QString winSp_helper()
-{
- const auto osv = qWindowsVersionInfo();
- const qint16 major = osv.wServicePackMajor;
- if (major) {
- QString sp = QStringLiteral("SP ") + QString::number(major);
- const qint16 minor = osv.wServicePackMinor;
- if (minor)
- sp += u'.' + QString::number(minor);
-
- return sp;
- }
- return QString();
-}
-
-static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
-{
- Q_UNUSED(version);
- const OSVERSIONINFOEX osver = qWindowsVersionInfo();
- const bool workstation = osver.wProductType == VER_NT_WORKSTATION;
-
-#define Q_WINVER(major, minor) (major << 8 | minor)
- switch (Q_WINVER(osver.dwMajorVersion, osver.dwMinorVersion)) {
- case Q_WINVER(10, 0):
- if (workstation) {
- if (osver.dwBuildNumber >= 22000)
- return "11";
- return "10";
- }
- // else: Server
- if (osver.dwBuildNumber >= 20348)
- return "Server 2022";
- if (osver.dwBuildNumber >= 17763)
- return "Server 2019";
- return "Server 2016";
- }
-#undef Q_WINVER
- // unknown, future version
- return nullptr;
-}
-
-#endif
-#if defined(Q_OS_UNIX)
-# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
-# define USE_ETC_OS_RELEASE
-struct QUnixOSVersion
-{
- // from /etc/os-release older /etc/lsb-release // redhat /etc/redhat-release // debian /etc/debian_version
- QString productType; // $ID $DISTRIB_ID // single line file containing: // Debian
- QString productVersion; // $VERSION_ID $DISTRIB_RELEASE // <Vendor_ID release Version_ID> // single line file <Release_ID/sid>
- QString prettyName; // $PRETTY_NAME $DISTRIB_DESCRIPTION
-};
-
-static QString unquote(const char *begin, const char *end)
-{
- // man os-release says:
- // Variable assignment values must be enclosed in double
- // or single quotes if they include spaces, semicolons or
- // other special characters outside of A–Z, a–z, 0–9. Shell
- // special characters ("$", quotes, backslash, backtick)
- // must be escaped with backslashes, following shell style.
- // All strings should be in UTF-8 format, and non-printable
- // characters should not be used. It is not supported to
- // concatenate multiple individually quoted strings.
- if (*begin == '"') {
- Q_ASSERT(end[-1] == '"');
- return QString::fromUtf8(begin + 1, end - begin - 2);
- }
- return QString::fromUtf8(begin, end - begin);
-}
-static QByteArray getEtcFileContent(const char *filename)
-{
- // we're avoiding QFile here
- int fd = qt_safe_open(filename, O_RDONLY);
- if (fd == -1)
- return QByteArray();
-
- QT_STATBUF sbuf;
- if (QT_FSTAT(fd, &sbuf) == -1) {
- qt_safe_close(fd);
- return QByteArray();
- }
-
- QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
- buffer.resize(qt_safe_read(fd, buffer.data(), sbuf.st_size));
- qt_safe_close(fd);
- return buffer;
-}
-
-static bool readEtcFile(QUnixOSVersion &v, const char *filename,
- const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey)
-{
-
- QByteArray buffer = getEtcFileContent(filename);
- if (buffer.isEmpty())
- return false;
-
- const char *ptr = buffer.constData();
- const char *end = buffer.constEnd();
- const char *eol;
- QByteArray line;
- for (; ptr != end; ptr = eol + 1) {
- // find the end of the line after ptr
- eol = static_cast<const char *>(memchr(ptr, '\n', end - ptr));
- if (!eol)
- eol = end - 1;
- line.setRawData(ptr, eol - ptr);
-
- if (line.startsWith(idKey)) {
- ptr += idKey.length();
- v.productType = unquote(ptr, eol);
- continue;
- }
-
- if (line.startsWith(prettyNameKey)) {
- ptr += prettyNameKey.length();
- v.prettyName = unquote(ptr, eol);
- continue;
- }
-
- if (line.startsWith(versionKey)) {
- ptr += versionKey.length();
- v.productVersion = unquote(ptr, eol);
- continue;
- }
- }
-
- return true;
-}
-
-static bool readOsRelease(QUnixOSVersion &v)
-{
- QByteArray id = QByteArrayLiteral("ID=");
- QByteArray versionId = QByteArrayLiteral("VERSION_ID=");
- QByteArray prettyName = QByteArrayLiteral("PRETTY_NAME=");
-
- // man os-release(5) says:
- // The file /etc/os-release takes precedence over /usr/lib/os-release.
- // Applications should check for the former, and exclusively use its data
- // if it exists, and only fall back to /usr/lib/os-release if it is
- // missing.
- return readEtcFile(v, "/etc/os-release", id, versionId, prettyName) ||
- readEtcFile(v, "/usr/lib/os-release", id, versionId, prettyName);
-}
-
-static bool readEtcLsbRelease(QUnixOSVersion &v)
-{
- bool ok = readEtcFile(v, "/etc/lsb-release", QByteArrayLiteral("DISTRIB_ID="),
- QByteArrayLiteral("DISTRIB_RELEASE="), QByteArrayLiteral("DISTRIB_DESCRIPTION="));
- if (ok && (v.prettyName.isEmpty() || v.prettyName == v.productType)) {
- // some distributions have redundant information for the pretty name,
- // so try /etc/<lowercasename>-release
-
- // we're still avoiding QFile here
- QByteArray distrorelease = "/etc/" + v.productType.toLatin1().toLower() + "-release";
- int fd = qt_safe_open(distrorelease, O_RDONLY);
- if (fd != -1) {
- QT_STATBUF sbuf;
- if (QT_FSTAT(fd, &sbuf) != -1 && sbuf.st_size > v.prettyName.length()) {
- // file apparently contains interesting information
- QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
- buffer.resize(qt_safe_read(fd, buffer.data(), sbuf.st_size));
- v.prettyName = QString::fromLatin1(buffer.trimmed());
- }
- qt_safe_close(fd);
- }
- }
-
- // some distributions have a /etc/lsb-release file that does not provide the values
- // we are looking for, i.e. DISTRIB_ID, DISTRIB_RELEASE and DISTRIB_DESCRIPTION.
- // Assuming that neither DISTRIB_ID nor DISTRIB_RELEASE were found, or contained valid values,
- // returning false for readEtcLsbRelease will allow further /etc/<lowercasename>-release parsing.
- return ok && !(v.productType.isEmpty() && v.productVersion.isEmpty());
-}
-
-#if defined(Q_OS_LINUX)
-static QByteArray getEtcFileFirstLine(const char *fileName)
-{
- QByteArray buffer = getEtcFileContent(fileName);
- if (buffer.isEmpty())
- return QByteArray();
-
- const char *ptr = buffer.constData();
- int eol = buffer.indexOf("\n");
- return QByteArray(ptr, eol).trimmed();
-}
-
-static bool readEtcRedHatRelease(QUnixOSVersion &v)
-{
- // /etc/redhat-release analysed should be a one line file
- // the format of its content is <Vendor_ID release Version>
- // i.e. "Red Hat Enterprise Linux Workstation release 6.5 (Santiago)"
- QByteArray line = getEtcFileFirstLine("/etc/redhat-release");
- if (line.isEmpty())
- return false;
-
- v.prettyName = QString::fromLatin1(line);
-
- const char keyword[] = "release ";
- int releaseIndex = line.indexOf(keyword);
- v.productType = QString::fromLatin1(line.mid(0, releaseIndex)).remove(u' ');
- int spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword));
- v.productVersion = QString::fromLatin1(line.mid(releaseIndex + strlen(keyword),
- spaceIndex > -1 ? spaceIndex - releaseIndex - int(strlen(keyword)) : -1));
- return true;
-}
-
-static bool readEtcDebianVersion(QUnixOSVersion &v)
-{
- // /etc/debian_version analysed should be a one line file
- // the format of its content is <Release_ID/sid>
- // i.e. "jessie/sid"
- QByteArray line = getEtcFileFirstLine("/etc/debian_version");
- if (line.isEmpty())
- return false;
-
- v.productType = QStringLiteral("Debian");
- v.productVersion = QString::fromLatin1(line);
- return true;
-}
-#endif
-
-static bool findUnixOsVersion(QUnixOSVersion &v)
-{
- if (readOsRelease(v))
- return true;
- if (readEtcLsbRelease(v))
- return true;
-#if defined(Q_OS_LINUX)
- if (readEtcRedHatRelease(v))
- return true;
- if (readEtcDebianVersion(v))
- return true;
-#endif
- return false;
-}
-# endif // USE_ETC_OS_RELEASE
-#endif // Q_OS_UNIX
-
-#ifdef Q_OS_ANDROID
-static const char *osVer_helper(QOperatingSystemVersion)
-{
-/* Data:
-
-
-
-Cupcake
-Donut
-Eclair
-Eclair
-Eclair
-Froyo
-Gingerbread
-Gingerbread
-Honeycomb
-Honeycomb
-Honeycomb
-Ice Cream Sandwich
-Ice Cream Sandwich
-Jelly Bean
-Jelly Bean
-Jelly Bean
-KitKat
-KitKat
-Lollipop
-Lollipop
-Marshmallow
-Nougat
-Nougat
-Oreo
-*/
- static const char versions_string[] =
- "\0"
- "Cupcake\0"
- "Donut\0"
- "Eclair\0"
- "Froyo\0"
- "Gingerbread\0"
- "Honeycomb\0"
- "Ice Cream Sandwich\0"
- "Jelly Bean\0"
- "KitKat\0"
- "Lollipop\0"
- "Marshmallow\0"
- "Nougat\0"
- "Oreo\0"
- "\0";
-
- static const int versions_indices[] = {
- 0, 0, 0, 1, 9, 15, 15, 15,
- 22, 28, 28, 40, 40, 40, 50, 50,
- 69, 69, 69, 80, 80, 87, 87, 96,
- 108, 108, 115, -1
- };
-
- static const int versions_count = (sizeof versions_indices) / (sizeof versions_indices[0]);
-
- // https://source.android.com/source/build-numbers.html
- // https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels
- const int sdk_int = QJniObject::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT");
- return &versions_string[versions_indices[qBound(0, sdk_int, versions_count - 1)]];
-}
-#endif
-
-/*!
- \since 5.4
-
- Returns the architecture of the CPU that Qt was compiled for, in text
- format. Note that this may not match the actual CPU that the application is
- running on if there's an emulation layer or if the CPU supports multiple
- architectures (like x86-64 processors supporting i386 applications). To
- detect that, use currentCpuArchitecture().
-
- Values returned by this function are stable and will not change over time,
- so applications can rely on the returned value as an identifier, except
- that new CPU types may be added over time.
-
- Typical returned values are (note: list not exhaustive):
- \list
- \li "arm"
- \li "arm64"
- \li "i386"
- \li "ia64"
- \li "mips"
- \li "mips64"
- \li "power"
- \li "power64"
- \li "sparc"
- \li "sparcv9"
- \li "x86_64"
- \endlist
-
- \sa QSysInfo::buildAbi(), QSysInfo::currentCpuArchitecture()
-*/
-QString QSysInfo::buildCpuArchitecture()
-{
- return QStringLiteral(ARCH_PROCESSOR);
-}
-
-/*!
- \since 5.4
-
- Returns the architecture of the CPU that the application is running on, in
- text format. Note that this function depends on what the OS will report and
- may not detect the actual CPU architecture if the OS hides that information
- or is unable to provide it. For example, a 32-bit OS running on a 64-bit
- CPU is usually unable to determine the CPU is actually capable of running
- 64-bit programs.
-
- Values returned by this function are mostly stable: an attempt will be made
- to ensure that they stay constant over time and match the values returned
- by QSysInfo::builldCpuArchitecture(). However, due to the nature of the
- operating system functions being used, there may be discrepancies.
-
- Typical returned values are (note: list not exhaustive):
- \list
- \li "arm"
- \li "arm64"
- \li "i386"
- \li "ia64"
- \li "mips"
- \li "mips64"
- \li "power"
- \li "power64"
- \li "sparc"
- \li "sparcv9"
- \li "x86_64"
- \endlist
-
- \sa QSysInfo::buildAbi(), QSysInfo::buildCpuArchitecture()
-*/
-QString QSysInfo::currentCpuArchitecture()
-{
-#if defined(Q_OS_WIN)
- // We don't need to catch all the CPU architectures in this function;
- // only those where the host CPU might be different than the build target
- // (usually, 64-bit platforms).
- SYSTEM_INFO info;
- GetNativeSystemInfo(&info);
- switch (info.wProcessorArchitecture) {
-# ifdef PROCESSOR_ARCHITECTURE_AMD64
- case PROCESSOR_ARCHITECTURE_AMD64:
- return QStringLiteral("x86_64");
-# endif
-# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
- case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
-# endif
- case PROCESSOR_ARCHITECTURE_IA64:
- return QStringLiteral("ia64");
- }
-#elif defined(Q_OS_DARWIN) && !defined(Q_OS_MACOS)
- // iOS-based OSes do not return the architecture on uname(2)'s result.
- return buildCpuArchitecture();
-#elif defined(Q_OS_UNIX)
- long ret = -1;
- struct utsname u;
-
-# if defined(Q_OS_SOLARIS)
- // We need a special call for Solaris because uname(2) on x86 returns "i86pc" for
- // both 32- and 64-bit CPUs. Reference:
- // http://docs.oracle.com/cd/E18752_01/html/816-5167/sysinfo-2.html#REFMAN2sysinfo-2
- // http://fxr.watson.org/fxr/source/common/syscall/systeminfo.c?v=OPENSOLARIS
- // http://fxr.watson.org/fxr/source/common/conf/param.c?v=OPENSOLARIS;im=10#L530
- if (ret == -1)
- ret = sysinfo(SI_ARCHITECTURE_64, u.machine, sizeof u.machine);
-# endif
-
- if (ret == -1)
- ret = uname(&u);
-
- // we could use detectUnixVersion() above, but we only need a field no other function does
- if (ret != -1) {
- // the use of QT_BUILD_INTERNAL here is simply to ensure all branches build
- // as we don't often build on some of the less common platforms
-# if defined(Q_PROCESSOR_ARM) || defined(QT_BUILD_INTERNAL)
- if (strcmp(u.machine, "aarch64") == 0)
- return QStringLiteral("arm64");
- if (strncmp(u.machine, "armv", 4) == 0)
- return QStringLiteral("arm");
-# endif
-# if defined(Q_PROCESSOR_POWER) || defined(QT_BUILD_INTERNAL)
- // harmonize "powerpc" and "ppc" to "power"
- if (strncmp(u.machine, "ppc", 3) == 0)
- return "power"_L1 + QLatin1StringView(u.machine + 3);
- if (strncmp(u.machine, "powerpc", 7) == 0)
- return "power"_L1 + QLatin1StringView(u.machine + 7);
- if (strcmp(u.machine, "Power Macintosh") == 0)
- return "power"_L1;
-# endif
-# if defined(Q_PROCESSOR_SPARC) || defined(QT_BUILD_INTERNAL)
- // Solaris sysinfo(2) (above) uses "sparcv9", but uname -m says "sun4u";
- // Linux says "sparc64"
- if (strcmp(u.machine, "sun4u") == 0 || strcmp(u.machine, "sparc64") == 0)
- return QStringLiteral("sparcv9");
- if (strcmp(u.machine, "sparc32") == 0)
- return QStringLiteral("sparc");
-# endif
-# if defined(Q_PROCESSOR_X86) || defined(QT_BUILD_INTERNAL)
- // harmonize all "i?86" to "i386"
- if (strlen(u.machine) == 4 && u.machine[0] == 'i'
- && u.machine[2] == '8' && u.machine[3] == '6')
- return QStringLiteral("i386");
- if (strcmp(u.machine, "amd64") == 0) // Solaris
- return QStringLiteral("x86_64");
-# endif
- return QString::fromLatin1(u.machine);
- }
-#endif
- return buildCpuArchitecture();
-}
-
-/*!
- \since 5.4
-
- Returns the full architecture string that Qt was compiled for. This string
- is useful for identifying different, incompatible builds. For example, it
- can be used as an identifier to request an upgrade package from a server.
-
- The values returned from this function are kept stable as follows: the
- mandatory components of the result will not change in future versions of
- Qt, but optional suffixes may be added.
-
- The returned value is composed of three or more parts, separated by dashes
- ("-"). They are:
-
- \table
- \header \li Component \li Value
- \row \li CPU Architecture \li The same as QSysInfo::buildCpuArchitecture(), such as "arm", "i386", "mips" or "x86_64"
- \row \li Endianness \li "little_endian" or "big_endian"
- \row \li Word size \li Whether it's a 32- or 64-bit application. Possible values are:
- "llp64" (Windows 64-bit), "lp64" (Unix 64-bit), "ilp32" (32-bit)
- \row \li (Optional) ABI \li Zero or more components identifying different ABIs possible in this architecture.
- Currently, Qt has optional ABI components for ARM and MIPS processors: one
- component is the main ABI (such as "eabi", "o32", "n32", "o64"); another is
- whether the calling convention is using hardware floating point registers ("hardfloat"
- is present).
-
- Additionally, if Qt was configured with \c{-qreal float}, the ABI option tag "qreal_float"
- will be present. If Qt was configured with another type as qreal, that type is present after
- "qreal_", with all characters other than letters and digits escaped by an underscore, followed
- by two hex digits. For example, \c{-qreal long double} becomes "qreal_long_20double".
- \endtable
-
- \sa QSysInfo::buildCpuArchitecture()
-*/
-QString QSysInfo::buildAbi()
-{
- // ARCH_FULL is a concatenation of strings (incl. ARCH_PROCESSOR), which breaks
- // QStringLiteral on MSVC. Since the concatenation behavior we want is specified
- // the same C++11 paper as the Unicode strings, we'll use that macro and hope
- // that Microsoft implements the new behavior when they add support for Unicode strings.
- return QStringLiteral(ARCH_FULL);
-}
-
-static QString unknownText()
-{
- return QStringLiteral("unknown");
-}
-
-/*!
- \since 5.4
-
- Returns the type of the operating system kernel Qt was compiled for. It's
- also the kernel the application is running on, unless the host operating
- system is running a form of compatibility or virtualization layer.
-
- Values returned by this function are stable and will not change over time,
- so applications can rely on the returned value as an identifier, except
- that new OS kernel types may be added over time.
-
- On Windows, this function returns the type of Windows kernel, like "winnt".
- On Unix systems, it returns the same as the output of \c{uname
- -s} (lowercased).
-
- \note This function may return surprising values: it returns "linux"
- for all operating systems running Linux (including Android), "qnx" for all
- operating systems running QNX, "freebsd" for
- Debian/kFreeBSD, and "darwin" for \macos and iOS. For information on the type
- of product the application is running on, see productType().
-
- \sa QFileSelector, kernelVersion(), productType(), productVersion(), prettyProductName()
-*/
-QString QSysInfo::kernelType()
-{
-#if defined(Q_OS_WIN)
- return QStringLiteral("winnt");
-#elif defined(Q_OS_UNIX)
- struct utsname u;
- if (uname(&u) == 0)
- return QString::fromLatin1(u.sysname).toLower();
-#endif
- return unknownText();
-}
-
-/*!
- \since 5.4
-
- Returns the release version of the operating system kernel. On Windows, it
- returns the version of the NT kernel. On Unix systems, including
- Android and \macos, it returns the same as the \c{uname -r}
- command would return.
-
- If the version could not be determined, this function may return an empty
- string.
-
- \sa kernelType(), productType(), productVersion(), prettyProductName()
-*/
-QString QSysInfo::kernelVersion()
-{
-#ifdef Q_OS_WIN
- const auto osver = QOperatingSystemVersion::current();
- return QString::asprintf("%d.%d.%d",
- osver.majorVersion(), osver.minorVersion(), osver.microVersion());
-#else
- struct utsname u;
- if (uname(&u) == 0)
- return QString::fromLatin1(u.release);
- return QString();
-#endif
-}
-
-
-/*!
- \since 5.4
-
- Returns the product name of the operating system this application is
- running in. If the application is running on some sort of emulation or
- virtualization layer (such as WINE on a Unix system), this function will
- inspect the emulation / virtualization layer.
-
- Values returned by this function are stable and will not change over time,
- so applications can rely on the returned value as an identifier, except
- that new OS types may be added over time.
-
- \b{Linux and Android note}: this function returns "android" for Linux
- systems running Android userspace, notably when using the Bionic library.
- For all other Linux systems, regardless of C library being used, it tries
- to determine the distribution name and returns that. If determining the
- distribution name failed, it returns "unknown".
-
- \b{\macos note}: this function returns "macos" for all \macos systems,
- regardless of Apple naming convention. Previously, in Qt 5, it returned
- "osx", again regardless of Apple naming conventions.
-
- \b{Darwin, iOS, tvOS, and watchOS note}: this function returns "ios" for
- iOS systems, "tvos" for tvOS systems, "watchos" for watchOS systems, and
- "darwin" in case the system could not be determined.
-
- \b{FreeBSD note}: this function returns "debian" for Debian/kFreeBSD and
- "unknown" otherwise.
-
- \b{Windows note}: this function return "windows"
-
- For other Unix-type systems, this function usually returns "unknown".
-
- \sa QFileSelector, kernelType(), kernelVersion(), productVersion(), prettyProductName()
-*/
-QString QSysInfo::productType()
-{
- // similar, but not identical to QFileSelectorPrivate::platformSelectors
-#if defined(Q_OS_WIN)
- return QStringLiteral("windows");
-
-#elif defined(Q_OS_QNX)
- return QStringLiteral("qnx");
-
-#elif defined(Q_OS_ANDROID)
- return QStringLiteral("android");
-
-#elif defined(Q_OS_IOS)
- return QStringLiteral("ios");
-#elif defined(Q_OS_TVOS)
- return QStringLiteral("tvos");
-#elif defined(Q_OS_WATCHOS)
- return QStringLiteral("watchos");
-#elif defined(Q_OS_MACOS)
- return QStringLiteral("macos");
-#elif defined(Q_OS_DARWIN)
- return QStringLiteral("darwin");
-
-#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
- QUnixOSVersion unixOsVersion;
- findUnixOsVersion(unixOsVersion);
- if (!unixOsVersion.productType.isEmpty())
- return unixOsVersion.productType;
-#endif
- return unknownText();
-}
-
-/*!
- \since 5.4
-
- Returns the product version of the operating system in string form. If the
- version could not be determined, this function returns "unknown".
-
- It will return the Android, iOS, \macos, Windows full-product
- versions on those systems.
-
- Typical returned values are (note: list not exhaustive):
- \list
- \li "12" (Android 12)
- \li "36" (Fedora 36)
- \li "15.5" (iOS 15.5)
- \li "12.4" (macOS Monterey)
- \li "22.04" (Ubuntu 22.04)
- \li "8.6" (watchOS 8.6)
- \li "11" (Windows 11)
- \li "Server 2022" (Windows Server 2022)
- \endlist
-
- On Linux systems, it will try to determine the distribution version and will
- return that. This is also done on Debian/kFreeBSD, so this function will
- return Debian version in that case.
-
- In all other Unix-type systems, this function always returns "unknown".
-
- \note The version string returned from this function is not guaranteed to
- be orderable. On Linux, the version of
- the distribution may jump unexpectedly, please refer to the distribution's
- documentation for versioning practices.
-
- \sa kernelType(), kernelVersion(), productType(), prettyProductName()
-*/
-QString QSysInfo::productVersion()
-{
-#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
- const auto version = QOperatingSystemVersion::current();
- return QString::asprintf("%d.%d", version.majorVersion(), version.minorVersion());
-#elif defined(Q_OS_WIN)
- const char *version = osVer_helper();
- if (version) {
- const QLatin1Char spaceChar(' ');
- return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower();
- }
- // fall through
-
-#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
- QUnixOSVersion unixOsVersion;
- findUnixOsVersion(unixOsVersion);
- if (!unixOsVersion.productVersion.isEmpty())
- return unixOsVersion.productVersion;
-#endif
-
- // fallback
- return unknownText();
-}
-
-/*!
- \since 5.4
-
- Returns a prettier form of productType() and productVersion(), containing
- other tokens like the operating system type, codenames and other
- information. The result of this function is suitable for displaying to the
- user, but not for long-term storage, as the string may change with updates
- to Qt.
-
- If productType() is "unknown", this function will instead use the
- kernelType() and kernelVersion() functions.
-
- \sa kernelType(), kernelVersion(), productType(), productVersion()
-*/
-QString QSysInfo::prettyProductName()
-{
-#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
- const auto version = QOperatingSystemVersion::current();
- const int majorVersion = version.majorVersion();
- const QString versionString = QString::asprintf("%d.%d", majorVersion, version.minorVersion());
- QString result = version.name() + u' ';
- const char *name = osVer_helper(version);
- if (!name)
- return result + versionString;
- result += QLatin1StringView(name);
-# if !defined(Q_OS_WIN)
- return result + " ("_L1 + versionString + u')';
-# else
- // (resembling winver.exe): Windows 10 "Windows 10 Version 1809"
- const auto displayVersion = windowsDisplayVersion();
- if (!displayVersion.isEmpty())
- result += " Version "_L1 + displayVersion;
- return result;
-# endif // Windows
-#elif defined(Q_OS_HAIKU)
- return "Haiku "_L1 + productVersion();
-#elif defined(Q_OS_UNIX)
-# ifdef USE_ETC_OS_RELEASE
- QUnixOSVersion unixOsVersion;
- findUnixOsVersion(unixOsVersion);
- if (!unixOsVersion.prettyName.isEmpty())
- return unixOsVersion.prettyName;
-# endif
- struct utsname u;
- if (uname(&u) == 0)
- return QString::fromLatin1(u.sysname) + u' ' + QString::fromLatin1(u.release);
-#endif
- return unknownText();
-}
-
-#ifndef QT_BOOTSTRAPPED
-/*!
- \since 5.6
-
- Returns this machine's host name, if one is configured. Note that hostnames
- are not guaranteed to be globally unique, especially if they were
- configured automatically.
-
- This function does not guarantee the returned host name is a Fully
- Qualified Domain Name (FQDN). For that, use QHostInfo to resolve the
- returned name to an FQDN.
-
- This function returns the same as QHostInfo::localHostName().
-
- \sa QHostInfo::localDomainName, machineUniqueId()
-*/
-QString QSysInfo::machineHostName()
-{
- // the hostname can change, so we can't cache it
-#if defined(Q_OS_LINUX)
- // gethostname(3) on Linux just calls uname(2), so do it ourselves
- // and avoid a memcpy
- struct utsname u;
- if (uname(&u) == 0)
- return QString::fromLocal8Bit(u.nodename);
- return QString();
-#else
-# ifdef Q_OS_WIN
- // Important: QtNetwork depends on machineHostName() initializing ws2_32.dll
- winsockInit();
-# endif
-
- char hostName[512];
- if (gethostname(hostName, sizeof(hostName)) == -1)
- return QString();
- hostName[sizeof(hostName) - 1] = '\0';
- return QString::fromLocal8Bit(hostName);
-#endif
-}
-#endif // QT_BOOTSTRAPPED
-
-enum {
- UuidStringLen = sizeof("00000000-0000-0000-0000-000000000000") - 1
-};
-
-/*!
- \since 5.11
-
- Returns a unique ID for this machine, if one can be determined. If no
- unique ID could be determined, this function returns an empty byte array.
- Unlike machineHostName(), the value returned by this function is likely
- globally unique.
-
- A unique ID is useful in network operations to identify this machine for an
- extended period of time, when the IP address could change or if this
- machine could have more than one IP address. For example, the ID could be
- used when communicating with a server or when storing device-specific data
- in shared network storage.
-
- Note that on some systems, this value will persist across reboots and on
- some it will not. Applications should not blindly depend on this fact
- without verifying the OS capabilities. In particular, on Linux systems,
- this ID is usually permanent and it matches the D-Bus machine ID, except
- for nodes without their own storage (replicated nodes).
-
- \sa machineHostName(), bootUniqueId()
-*/
-QByteArray QSysInfo::machineUniqueId()
-{
-#if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
- char uuid[UuidStringLen + 1];
- static const mach_port_t defaultPort = 0; // Effectively kIOMasterPortDefault/kIOMainPortDefault
- io_service_t service = IOServiceGetMatchingService(defaultPort, IOServiceMatching("IOPlatformExpertDevice"));
- QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
- CFStringGetCString(stringRef, uuid, sizeof(uuid), kCFStringEncodingMacRoman);
- return QByteArray(uuid);
-#elif defined(Q_OS_BSD4) && defined(KERN_HOSTUUID)
- char uuid[UuidStringLen + 1];
- size_t uuidlen = sizeof(uuid);
- int name[] = { CTL_KERN, KERN_HOSTUUID };
- if (sysctl(name, sizeof name / sizeof name[0], &uuid, &uuidlen, nullptr, 0) == 0
- && uuidlen == sizeof(uuid))
- return QByteArray(uuid, uuidlen - 1);
-#elif defined(Q_OS_UNIX)
- // The modern name on Linux is /etc/machine-id, but that path is
- // unlikely to exist on non-Linux (non-systemd) systems. The old
- // path is more than enough.
- static const char fullfilename[] = "/usr/local/var/lib/dbus/machine-id";
- const char *firstfilename = fullfilename + sizeof("/usr/local") - 1;
- int fd = qt_safe_open(firstfilename, O_RDONLY);
- if (fd == -1 && errno == ENOENT)
- fd = qt_safe_open(fullfilename, O_RDONLY);
-
- if (fd != -1) {
- char buffer[32]; // 128 bits, hex-encoded
- qint64 len = qt_safe_read(fd, buffer, sizeof(buffer));
- qt_safe_close(fd);
-
- if (len != -1)
- return QByteArray(buffer, len);
- }
-#elif defined(Q_OS_WIN)
- // Let's poke at the registry
- const QString machineGuid = QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Cryptography)")
- .stringValue(u"MachineGuid"_s);
- if (!machineGuid.isEmpty())
- return machineGuid.toLatin1();
-#endif
- return QByteArray();
-}
-
-/*!
- \since 5.11
-
- Returns a unique ID for this machine's boot, if one can be determined. If
- no unique ID could be determined, this function returns an empty byte
- array. This value is expected to change after every boot and can be
- considered globally unique.
-
- This function is currently only implemented for Linux and Apple operating
- systems.
-
- \sa machineUniqueId()
-*/
-QByteArray QSysInfo::bootUniqueId()
-{
-#ifdef Q_OS_LINUX
- // use low-level API here for simplicity
- int fd = qt_safe_open("/proc/sys/kernel/random/boot_id", O_RDONLY);
- if (fd != -1) {
- char uuid[UuidStringLen];
- qint64 len = qt_safe_read(fd, uuid, sizeof(uuid));
- qt_safe_close(fd);
- if (len == UuidStringLen)
- return QByteArray(uuid, UuidStringLen);
- }
-#elif defined(Q_OS_DARWIN)
- // "kern.bootsessionuuid" is only available by name
- char uuid[UuidStringLen + 1];
- size_t uuidlen = sizeof(uuid);
- if (sysctlbyname("kern.bootsessionuuid", uuid, &uuidlen, nullptr, 0) == 0
- && uuidlen == sizeof(uuid))
- return QByteArray(uuid, uuidlen - 1);
-#endif
- return QByteArray();
-};
-
/*!
\macro void Q_FALLTHROUGH()
\relates <QtGlobal>
diff --git a/src/corelib/global/qsysinfo.cpp b/src/corelib/global/qsysinfo.cpp
new file mode 100644
index 0000000000..55e0fa0688
--- /dev/null
+++ b/src/corelib/global/qsysinfo.cpp
@@ -0,0 +1,1055 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// Copyright (C) 2022 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qsysinfo.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/qstring.h>
+
+#include <private/qoperatingsystemversion_p.h>
+
+#ifdef Q_OS_UNIX
+# include <sys/utsname.h>
+# include <private/qcore_unix_p.h>
+#endif
+
+#ifdef Q_OS_ANDROID
+#include <qjniobject.h>
+#endif
+
+#if defined(Q_OS_SOLARIS)
+# include <sys/systeminfo.h>
+#endif
+
+#if defined(Q_OS_DARWIN)
+# include "qnamespace.h"
+# include <private/qcore_mac_p.h>
+# if __has_include(<IOKit/IOKitLib.h>)
+# include <IOKit/IOKitLib.h>
+# endif
+#endif
+
+#ifdef Q_OS_BSD4
+# include <sys/sysctl.h>
+#endif
+
+#if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
+# include "qoperatingsystemversion_win_p.h"
+# include "private/qwinregistry_p.h"
+# include "qt_windows.h"
+#endif // Q_OS_WIN || Q_OS_CYGWIN
+
+#include "archdetect.cpp"
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+/*!
+ \class QSysInfo
+ \inmodule QtCore
+ \brief The QSysInfo class provides information about the system.
+
+ \list
+ \li \l WordSize specifies the size of a pointer for the platform
+ on which the application is compiled.
+ \li \l ByteOrder specifies whether the platform is big-endian or
+ little-endian.
+ \endlist
+
+ Some constants are defined only on certain platforms. You can use
+ the preprocessor symbols Q_OS_WIN and Q_OS_MACOS to test that
+ the application is compiled under Windows or \macos.
+
+ \sa QLibraryInfo
+*/
+
+/*!
+ \enum QSysInfo::Sizes
+
+ This enum provides platform-specific information about the sizes of data
+ structures used by the underlying architecture.
+
+ \value WordSize The size in bits of a pointer for the platform on which
+ the application is compiled (32 or 64).
+*/
+
+/*!
+ \enum QSysInfo::Endian
+
+ \value BigEndian Big-endian byte order (also called Network byte order)
+ \value LittleEndian Little-endian byte order
+ \value ByteOrder Equals BigEndian or LittleEndian, depending on
+ the platform's byte order.
+*/
+
+#if defined(Q_OS_DARWIN)
+
+static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
+{
+#ifdef Q_OS_MACOS
+ if (version.majorVersion() == 12)
+ return "Monterey";
+ // Compare against predefined constant to handle 10.16/11.0
+ if (QOperatingSystemVersion::MacOSBigSur.version().isPrefixOf(version.version()))
+ return "Big Sur";
+ if (version.majorVersion() == 10) {
+ switch (version.minorVersion()) {
+ case 9:
+ return "Mavericks";
+ case 10:
+ return "Yosemite";
+ case 11:
+ return "El Capitan";
+ case 12:
+ return "Sierra";
+ case 13:
+ return "High Sierra";
+ case 14:
+ return "Mojave";
+ case 15:
+ return "Catalina";
+ }
+ }
+ // unknown, future version
+#else
+ Q_UNUSED(version);
+#endif
+ return nullptr;
+}
+
+#elif defined(Q_OS_WIN) || defined(Q_OS_CYGWIN)
+
+# ifndef QT_BOOTSTRAPPED
+class QWindowsSockInit
+{
+public:
+ QWindowsSockInit();
+ ~QWindowsSockInit();
+ int version;
+};
+
+QWindowsSockInit::QWindowsSockInit()
+: version(0)
+{
+ //### should we try for 2.2 on all platforms ??
+ WSAData wsadata;
+
+ // IPv6 requires Winsock v2.0 or better.
+ if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) {
+ qWarning("QTcpSocketAPI: WinSock v2.0 initialization failed.");
+ } else {
+ version = 0x20;
+ }
+}
+
+QWindowsSockInit::~QWindowsSockInit()
+{
+ WSACleanup();
+}
+Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
+# endif // QT_BOOTSTRAPPED
+
+static QString readVersionRegistryString(const wchar_t *subKey)
+{
+ return QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)")
+ .stringValue(subKey);
+}
+
+static inline QString windowsDisplayVersion()
+{
+ // https://tickets.puppetlabs.com/browse/FACT-3058
+ // The "ReleaseId" key stopped updating since Windows 10 20H2.
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10_20H2)
+ return readVersionRegistryString(L"DisplayVersion");
+ else
+ return readVersionRegistryString(L"ReleaseId");
+}
+
+static QString winSp_helper()
+{
+ const auto osv = qWindowsVersionInfo();
+ const qint16 major = osv.wServicePackMajor;
+ if (major) {
+ QString sp = QStringLiteral("SP ") + QString::number(major);
+ const qint16 minor = osv.wServicePackMinor;
+ if (minor)
+ sp += u'.' + QString::number(minor);
+
+ return sp;
+ }
+ return QString();
+}
+
+static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
+{
+ Q_UNUSED(version);
+ const OSVERSIONINFOEX osver = qWindowsVersionInfo();
+ const bool workstation = osver.wProductType == VER_NT_WORKSTATION;
+
+#define Q_WINVER(major, minor) (major << 8 | minor)
+ switch (Q_WINVER(osver.dwMajorVersion, osver.dwMinorVersion)) {
+ case Q_WINVER(10, 0):
+ if (workstation) {
+ if (osver.dwBuildNumber >= 22000)
+ return "11";
+ return "10";
+ }
+ // else: Server
+ if (osver.dwBuildNumber >= 20348)
+ return "Server 2022";
+ if (osver.dwBuildNumber >= 17763)
+ return "Server 2019";
+ return "Server 2016";
+ }
+#undef Q_WINVER
+ // unknown, future version
+ return nullptr;
+}
+
+#endif
+#if defined(Q_OS_UNIX)
+# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
+# define USE_ETC_OS_RELEASE
+struct QUnixOSVersion
+{
+ // from /etc/os-release older /etc/lsb-release // redhat /etc/redhat-release // debian /etc/debian_version
+ QString productType; // $ID $DISTRIB_ID // single line file containing: // Debian
+ QString productVersion; // $VERSION_ID $DISTRIB_RELEASE // <Vendor_ID release Version_ID> // single line file <Release_ID/sid>
+ QString prettyName; // $PRETTY_NAME $DISTRIB_DESCRIPTION
+};
+
+static QString unquote(const char *begin, const char *end)
+{
+ // man os-release says:
+ // Variable assignment values must be enclosed in double
+ // or single quotes if they include spaces, semicolons or
+ // other special characters outside of A–Z, a–z, 0–9. Shell
+ // special characters ("$", quotes, backslash, backtick)
+ // must be escaped with backslashes, following shell style.
+ // All strings should be in UTF-8 format, and non-printable
+ // characters should not be used. It is not supported to
+ // concatenate multiple individually quoted strings.
+ if (*begin == '"') {
+ Q_ASSERT(end[-1] == '"');
+ return QString::fromUtf8(begin + 1, end - begin - 2);
+ }
+ return QString::fromUtf8(begin, end - begin);
+}
+static QByteArray getEtcFileContent(const char *filename)
+{
+ // we're avoiding QFile here
+ int fd = qt_safe_open(filename, O_RDONLY);
+ if (fd == -1)
+ return QByteArray();
+
+ QT_STATBUF sbuf;
+ if (QT_FSTAT(fd, &sbuf) == -1) {
+ qt_safe_close(fd);
+ return QByteArray();
+ }
+
+ QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
+ buffer.resize(qt_safe_read(fd, buffer.data(), sbuf.st_size));
+ qt_safe_close(fd);
+ return buffer;
+}
+
+static bool readEtcFile(QUnixOSVersion &v, const char *filename,
+ const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey)
+{
+
+ QByteArray buffer = getEtcFileContent(filename);
+ if (buffer.isEmpty())
+ return false;
+
+ const char *ptr = buffer.constData();
+ const char *end = buffer.constEnd();
+ const char *eol;
+ QByteArray line;
+ for (; ptr != end; ptr = eol + 1) {
+ // find the end of the line after ptr
+ eol = static_cast<const char *>(memchr(ptr, '\n', end - ptr));
+ if (!eol)
+ eol = end - 1;
+ line.setRawData(ptr, eol - ptr);
+
+ if (line.startsWith(idKey)) {
+ ptr += idKey.length();
+ v.productType = unquote(ptr, eol);
+ continue;
+ }
+
+ if (line.startsWith(prettyNameKey)) {
+ ptr += prettyNameKey.length();
+ v.prettyName = unquote(ptr, eol);
+ continue;
+ }
+
+ if (line.startsWith(versionKey)) {
+ ptr += versionKey.length();
+ v.productVersion = unquote(ptr, eol);
+ continue;
+ }
+ }
+
+ return true;
+}
+
+static bool readOsRelease(QUnixOSVersion &v)
+{
+ QByteArray id = QByteArrayLiteral("ID=");
+ QByteArray versionId = QByteArrayLiteral("VERSION_ID=");
+ QByteArray prettyName = QByteArrayLiteral("PRETTY_NAME=");
+
+ // man os-release(5) says:
+ // The file /etc/os-release takes precedence over /usr/lib/os-release.
+ // Applications should check for the former, and exclusively use its data
+ // if it exists, and only fall back to /usr/lib/os-release if it is
+ // missing.
+ return readEtcFile(v, "/etc/os-release", id, versionId, prettyName) ||
+ readEtcFile(v, "/usr/lib/os-release", id, versionId, prettyName);
+}
+
+static bool readEtcLsbRelease(QUnixOSVersion &v)
+{
+ bool ok = readEtcFile(v, "/etc/lsb-release", QByteArrayLiteral("DISTRIB_ID="),
+ QByteArrayLiteral("DISTRIB_RELEASE="), QByteArrayLiteral("DISTRIB_DESCRIPTION="));
+ if (ok && (v.prettyName.isEmpty() || v.prettyName == v.productType)) {
+ // some distributions have redundant information for the pretty name,
+ // so try /etc/<lowercasename>-release
+
+ // we're still avoiding QFile here
+ QByteArray distrorelease = "/etc/" + v.productType.toLatin1().toLower() + "-release";
+ int fd = qt_safe_open(distrorelease, O_RDONLY);
+ if (fd != -1) {
+ QT_STATBUF sbuf;
+ if (QT_FSTAT(fd, &sbuf) != -1 && sbuf.st_size > v.prettyName.length()) {
+ // file apparently contains interesting information
+ QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
+ buffer.resize(qt_safe_read(fd, buffer.data(), sbuf.st_size));
+ v.prettyName = QString::fromLatin1(buffer.trimmed());
+ }
+ qt_safe_close(fd);
+ }
+ }
+
+ // some distributions have a /etc/lsb-release file that does not provide the values
+ // we are looking for, i.e. DISTRIB_ID, DISTRIB_RELEASE and DISTRIB_DESCRIPTION.
+ // Assuming that neither DISTRIB_ID nor DISTRIB_RELEASE were found, or contained valid values,
+ // returning false for readEtcLsbRelease will allow further /etc/<lowercasename>-release parsing.
+ return ok && !(v.productType.isEmpty() && v.productVersion.isEmpty());
+}
+
+#if defined(Q_OS_LINUX)
+static QByteArray getEtcFileFirstLine(const char *fileName)
+{
+ QByteArray buffer = getEtcFileContent(fileName);
+ if (buffer.isEmpty())
+ return QByteArray();
+
+ const char *ptr = buffer.constData();
+ int eol = buffer.indexOf("\n");
+ return QByteArray(ptr, eol).trimmed();
+}
+
+static bool readEtcRedHatRelease(QUnixOSVersion &v)
+{
+ // /etc/redhat-release analysed should be a one line file
+ // the format of its content is <Vendor_ID release Version>
+ // i.e. "Red Hat Enterprise Linux Workstation release 6.5 (Santiago)"
+ QByteArray line = getEtcFileFirstLine("/etc/redhat-release");
+ if (line.isEmpty())
+ return false;
+
+ v.prettyName = QString::fromLatin1(line);
+
+ const char keyword[] = "release ";
+ int releaseIndex = line.indexOf(keyword);
+ v.productType = QString::fromLatin1(line.mid(0, releaseIndex)).remove(u' ');
+ int spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword));
+ v.productVersion = QString::fromLatin1(line.mid(releaseIndex + strlen(keyword),
+ spaceIndex > -1 ? spaceIndex - releaseIndex - int(strlen(keyword)) : -1));
+ return true;
+}
+
+static bool readEtcDebianVersion(QUnixOSVersion &v)
+{
+ // /etc/debian_version analysed should be a one line file
+ // the format of its content is <Release_ID/sid>
+ // i.e. "jessie/sid"
+ QByteArray line = getEtcFileFirstLine("/etc/debian_version");
+ if (line.isEmpty())
+ return false;
+
+ v.productType = QStringLiteral("Debian");
+ v.productVersion = QString::fromLatin1(line);
+ return true;
+}
+#endif
+
+static bool findUnixOsVersion(QUnixOSVersion &v)
+{
+ if (readOsRelease(v))
+ return true;
+ if (readEtcLsbRelease(v))
+ return true;
+#if defined(Q_OS_LINUX)
+ if (readEtcRedHatRelease(v))
+ return true;
+ if (readEtcDebianVersion(v))
+ return true;
+#endif
+ return false;
+}
+# endif // USE_ETC_OS_RELEASE
+#endif // Q_OS_UNIX
+
+#ifdef Q_OS_ANDROID
+static const char *osVer_helper(QOperatingSystemVersion)
+{
+/* Data:
+
+
+
+Cupcake
+Donut
+Eclair
+Eclair
+Eclair
+Froyo
+Gingerbread
+Gingerbread
+Honeycomb
+Honeycomb
+Honeycomb
+Ice Cream Sandwich
+Ice Cream Sandwich
+Jelly Bean
+Jelly Bean
+Jelly Bean
+KitKat
+KitKat
+Lollipop
+Lollipop
+Marshmallow
+Nougat
+Nougat
+Oreo
+*/
+ static const char versions_string[] =
+ "\0"
+ "Cupcake\0"
+ "Donut\0"
+ "Eclair\0"
+ "Froyo\0"
+ "Gingerbread\0"
+ "Honeycomb\0"
+ "Ice Cream Sandwich\0"
+ "Jelly Bean\0"
+ "KitKat\0"
+ "Lollipop\0"
+ "Marshmallow\0"
+ "Nougat\0"
+ "Oreo\0"
+ "\0";
+
+ static const int versions_indices[] = {
+ 0, 0, 0, 1, 9, 15, 15, 15,
+ 22, 28, 28, 40, 40, 40, 50, 50,
+ 69, 69, 69, 80, 80, 87, 87, 96,
+ 108, 108, 115, -1
+ };
+
+ static const int versions_count = (sizeof versions_indices) / (sizeof versions_indices[0]);
+
+ // https://source.android.com/source/build-numbers.html
+ // https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels
+ const int sdk_int = QJniObject::getStaticField<jint>("android/os/Build$VERSION", "SDK_INT");
+ return &versions_string[versions_indices[qBound(0, sdk_int, versions_count - 1)]];
+}
+#endif
+
+/*!
+ \since 5.4
+
+ Returns the architecture of the CPU that Qt was compiled for, in text
+ format. Note that this may not match the actual CPU that the application is
+ running on if there's an emulation layer or if the CPU supports multiple
+ architectures (like x86-64 processors supporting i386 applications). To
+ detect that, use currentCpuArchitecture().
+
+ Values returned by this function are stable and will not change over time,
+ so applications can rely on the returned value as an identifier, except
+ that new CPU types may be added over time.
+
+ Typical returned values are (note: list not exhaustive):
+ \list
+ \li "arm"
+ \li "arm64"
+ \li "i386"
+ \li "ia64"
+ \li "mips"
+ \li "mips64"
+ \li "power"
+ \li "power64"
+ \li "sparc"
+ \li "sparcv9"
+ \li "x86_64"
+ \endlist
+
+ \sa QSysInfo::buildAbi(), QSysInfo::currentCpuArchitecture()
+*/
+QString QSysInfo::buildCpuArchitecture()
+{
+ return QStringLiteral(ARCH_PROCESSOR);
+}
+
+/*!
+ \since 5.4
+
+ Returns the architecture of the CPU that the application is running on, in
+ text format. Note that this function depends on what the OS will report and
+ may not detect the actual CPU architecture if the OS hides that information
+ or is unable to provide it. For example, a 32-bit OS running on a 64-bit
+ CPU is usually unable to determine the CPU is actually capable of running
+ 64-bit programs.
+
+ Values returned by this function are mostly stable: an attempt will be made
+ to ensure that they stay constant over time and match the values returned
+ by QSysInfo::builldCpuArchitecture(). However, due to the nature of the
+ operating system functions being used, there may be discrepancies.
+
+ Typical returned values are (note: list not exhaustive):
+ \list
+ \li "arm"
+ \li "arm64"
+ \li "i386"
+ \li "ia64"
+ \li "mips"
+ \li "mips64"
+ \li "power"
+ \li "power64"
+ \li "sparc"
+ \li "sparcv9"
+ \li "x86_64"
+ \endlist
+
+ \sa QSysInfo::buildAbi(), QSysInfo::buildCpuArchitecture()
+*/
+QString QSysInfo::currentCpuArchitecture()
+{
+#if defined(Q_OS_WIN)
+ // We don't need to catch all the CPU architectures in this function;
+ // only those where the host CPU might be different than the build target
+ // (usually, 64-bit platforms).
+ SYSTEM_INFO info;
+ GetNativeSystemInfo(&info);
+ switch (info.wProcessorArchitecture) {
+# ifdef PROCESSOR_ARCHITECTURE_AMD64
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ return QStringLiteral("x86_64");
+# endif
+# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
+ case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
+# endif
+ case PROCESSOR_ARCHITECTURE_IA64:
+ return QStringLiteral("ia64");
+ }
+#elif defined(Q_OS_DARWIN) && !defined(Q_OS_MACOS)
+ // iOS-based OSes do not return the architecture on uname(2)'s result.
+ return buildCpuArchitecture();
+#elif defined(Q_OS_UNIX)
+ long ret = -1;
+ struct utsname u;
+
+# if defined(Q_OS_SOLARIS)
+ // We need a special call for Solaris because uname(2) on x86 returns "i86pc" for
+ // both 32- and 64-bit CPUs. Reference:
+ // http://docs.oracle.com/cd/E18752_01/html/816-5167/sysinfo-2.html#REFMAN2sysinfo-2
+ // http://fxr.watson.org/fxr/source/common/syscall/systeminfo.c?v=OPENSOLARIS
+ // http://fxr.watson.org/fxr/source/common/conf/param.c?v=OPENSOLARIS;im=10#L530
+ if (ret == -1)
+ ret = sysinfo(SI_ARCHITECTURE_64, u.machine, sizeof u.machine);
+# endif
+
+ if (ret == -1)
+ ret = uname(&u);
+
+ // we could use detectUnixVersion() above, but we only need a field no other function does
+ if (ret != -1) {
+ // the use of QT_BUILD_INTERNAL here is simply to ensure all branches build
+ // as we don't often build on some of the less common platforms
+# if defined(Q_PROCESSOR_ARM) || defined(QT_BUILD_INTERNAL)
+ if (strcmp(u.machine, "aarch64") == 0)
+ return QStringLiteral("arm64");
+ if (strncmp(u.machine, "armv", 4) == 0)
+ return QStringLiteral("arm");
+# endif
+# if defined(Q_PROCESSOR_POWER) || defined(QT_BUILD_INTERNAL)
+ // harmonize "powerpc" and "ppc" to "power"
+ if (strncmp(u.machine, "ppc", 3) == 0)
+ return "power"_L1 + QLatin1StringView(u.machine + 3);
+ if (strncmp(u.machine, "powerpc", 7) == 0)
+ return "power"_L1 + QLatin1StringView(u.machine + 7);
+ if (strcmp(u.machine, "Power Macintosh") == 0)
+ return "power"_L1;
+# endif
+# if defined(Q_PROCESSOR_SPARC) || defined(QT_BUILD_INTERNAL)
+ // Solaris sysinfo(2) (above) uses "sparcv9", but uname -m says "sun4u";
+ // Linux says "sparc64"
+ if (strcmp(u.machine, "sun4u") == 0 || strcmp(u.machine, "sparc64") == 0)
+ return QStringLiteral("sparcv9");
+ if (strcmp(u.machine, "sparc32") == 0)
+ return QStringLiteral("sparc");
+# endif
+# if defined(Q_PROCESSOR_X86) || defined(QT_BUILD_INTERNAL)
+ // harmonize all "i?86" to "i386"
+ if (strlen(u.machine) == 4 && u.machine[0] == 'i'
+ && u.machine[2] == '8' && u.machine[3] == '6')
+ return QStringLiteral("i386");
+ if (strcmp(u.machine, "amd64") == 0) // Solaris
+ return QStringLiteral("x86_64");
+# endif
+ return QString::fromLatin1(u.machine);
+ }
+#endif
+ return buildCpuArchitecture();
+}
+
+/*!
+ \since 5.4
+
+ Returns the full architecture string that Qt was compiled for. This string
+ is useful for identifying different, incompatible builds. For example, it
+ can be used as an identifier to request an upgrade package from a server.
+
+ The values returned from this function are kept stable as follows: the
+ mandatory components of the result will not change in future versions of
+ Qt, but optional suffixes may be added.
+
+ The returned value is composed of three or more parts, separated by dashes
+ ("-"). They are:
+
+ \table
+ \header \li Component \li Value
+ \row \li CPU Architecture \li The same as QSysInfo::buildCpuArchitecture(), such as "arm", "i386", "mips" or "x86_64"
+ \row \li Endianness \li "little_endian" or "big_endian"
+ \row \li Word size \li Whether it's a 32- or 64-bit application. Possible values are:
+ "llp64" (Windows 64-bit), "lp64" (Unix 64-bit), "ilp32" (32-bit)
+ \row \li (Optional) ABI \li Zero or more components identifying different ABIs possible in this architecture.
+ Currently, Qt has optional ABI components for ARM and MIPS processors: one
+ component is the main ABI (such as "eabi", "o32", "n32", "o64"); another is
+ whether the calling convention is using hardware floating point registers ("hardfloat"
+ is present).
+
+ Additionally, if Qt was configured with \c{-qreal float}, the ABI option tag "qreal_float"
+ will be present. If Qt was configured with another type as qreal, that type is present after
+ "qreal_", with all characters other than letters and digits escaped by an underscore, followed
+ by two hex digits. For example, \c{-qreal long double} becomes "qreal_long_20double".
+ \endtable
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+QString QSysInfo::buildAbi()
+{
+ // ARCH_FULL is a concatenation of strings (incl. ARCH_PROCESSOR), which breaks
+ // QStringLiteral on MSVC. Since the concatenation behavior we want is specified
+ // the same C++11 paper as the Unicode strings, we'll use that macro and hope
+ // that Microsoft implements the new behavior when they add support for Unicode strings.
+ return QStringLiteral(ARCH_FULL);
+}
+
+static QString unknownText()
+{
+ return QStringLiteral("unknown");
+}
+
+/*!
+ \since 5.4
+
+ Returns the type of the operating system kernel Qt was compiled for. It's
+ also the kernel the application is running on, unless the host operating
+ system is running a form of compatibility or virtualization layer.
+
+ Values returned by this function are stable and will not change over time,
+ so applications can rely on the returned value as an identifier, except
+ that new OS kernel types may be added over time.
+
+ On Windows, this function returns the type of Windows kernel, like "winnt".
+ On Unix systems, it returns the same as the output of \c{uname
+ -s} (lowercased).
+
+ \note This function may return surprising values: it returns "linux"
+ for all operating systems running Linux (including Android), "qnx" for all
+ operating systems running QNX, "freebsd" for
+ Debian/kFreeBSD, and "darwin" for \macos and iOS. For information on the type
+ of product the application is running on, see productType().
+
+ \sa QFileSelector, kernelVersion(), productType(), productVersion(), prettyProductName()
+*/
+QString QSysInfo::kernelType()
+{
+#if defined(Q_OS_WIN)
+ return QStringLiteral("winnt");
+#elif defined(Q_OS_UNIX)
+ struct utsname u;
+ if (uname(&u) == 0)
+ return QString::fromLatin1(u.sysname).toLower();
+#endif
+ return unknownText();
+}
+
+/*!
+ \since 5.4
+
+ Returns the release version of the operating system kernel. On Windows, it
+ returns the version of the NT kernel. On Unix systems, including
+ Android and \macos, it returns the same as the \c{uname -r}
+ command would return.
+
+ If the version could not be determined, this function may return an empty
+ string.
+
+ \sa kernelType(), productType(), productVersion(), prettyProductName()
+*/
+QString QSysInfo::kernelVersion()
+{
+#ifdef Q_OS_WIN
+ const auto osver = QOperatingSystemVersion::current();
+ return QString::asprintf("%d.%d.%d",
+ osver.majorVersion(), osver.minorVersion(), osver.microVersion());
+#else
+ struct utsname u;
+ if (uname(&u) == 0)
+ return QString::fromLatin1(u.release);
+ return QString();
+#endif
+}
+
+
+/*!
+ \since 5.4
+
+ Returns the product name of the operating system this application is
+ running in. If the application is running on some sort of emulation or
+ virtualization layer (such as WINE on a Unix system), this function will
+ inspect the emulation / virtualization layer.
+
+ Values returned by this function are stable and will not change over time,
+ so applications can rely on the returned value as an identifier, except
+ that new OS types may be added over time.
+
+ \b{Linux and Android note}: this function returns "android" for Linux
+ systems running Android userspace, notably when using the Bionic library.
+ For all other Linux systems, regardless of C library being used, it tries
+ to determine the distribution name and returns that. If determining the
+ distribution name failed, it returns "unknown".
+
+ \b{\macos note}: this function returns "macos" for all \macos systems,
+ regardless of Apple naming convention. Previously, in Qt 5, it returned
+ "osx", again regardless of Apple naming conventions.
+
+ \b{Darwin, iOS, tvOS, and watchOS note}: this function returns "ios" for
+ iOS systems, "tvos" for tvOS systems, "watchos" for watchOS systems, and
+ "darwin" in case the system could not be determined.
+
+ \b{FreeBSD note}: this function returns "debian" for Debian/kFreeBSD and
+ "unknown" otherwise.
+
+ \b{Windows note}: this function return "windows"
+
+ For other Unix-type systems, this function usually returns "unknown".
+
+ \sa QFileSelector, kernelType(), kernelVersion(), productVersion(), prettyProductName()
+*/
+QString QSysInfo::productType()
+{
+ // similar, but not identical to QFileSelectorPrivate::platformSelectors
+#if defined(Q_OS_WIN)
+ return QStringLiteral("windows");
+
+#elif defined(Q_OS_QNX)
+ return QStringLiteral("qnx");
+
+#elif defined(Q_OS_ANDROID)
+ return QStringLiteral("android");
+
+#elif defined(Q_OS_IOS)
+ return QStringLiteral("ios");
+#elif defined(Q_OS_TVOS)
+ return QStringLiteral("tvos");
+#elif defined(Q_OS_WATCHOS)
+ return QStringLiteral("watchos");
+#elif defined(Q_OS_MACOS)
+ return QStringLiteral("macos");
+#elif defined(Q_OS_DARWIN)
+ return QStringLiteral("darwin");
+
+#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
+ QUnixOSVersion unixOsVersion;
+ findUnixOsVersion(unixOsVersion);
+ if (!unixOsVersion.productType.isEmpty())
+ return unixOsVersion.productType;
+#endif
+ return unknownText();
+}
+
+/*!
+ \since 5.4
+
+ Returns the product version of the operating system in string form. If the
+ version could not be determined, this function returns "unknown".
+
+ It will return the Android, iOS, \macos, Windows full-product
+ versions on those systems.
+
+ Typical returned values are (note: list not exhaustive):
+ \list
+ \li "12" (Android 12)
+ \li "36" (Fedora 36)
+ \li "15.5" (iOS 15.5)
+ \li "12.4" (macOS Monterey)
+ \li "22.04" (Ubuntu 22.04)
+ \li "8.6" (watchOS 8.6)
+ \li "11" (Windows 11)
+ \li "Server 2022" (Windows Server 2022)
+ \endlist
+
+ On Linux systems, it will try to determine the distribution version and will
+ return that. This is also done on Debian/kFreeBSD, so this function will
+ return Debian version in that case.
+
+ In all other Unix-type systems, this function always returns "unknown".
+
+ \note The version string returned from this function is not guaranteed to
+ be orderable. On Linux, the version of
+ the distribution may jump unexpectedly, please refer to the distribution's
+ documentation for versioning practices.
+
+ \sa kernelType(), kernelVersion(), productType(), prettyProductName()
+*/
+QString QSysInfo::productVersion()
+{
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN)
+ const auto version = QOperatingSystemVersion::current();
+ return QString::asprintf("%d.%d", version.majorVersion(), version.minorVersion());
+#elif defined(Q_OS_WIN)
+ const char *version = osVer_helper();
+ if (version) {
+ const QLatin1Char spaceChar(' ');
+ return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower();
+ }
+ // fall through
+
+#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
+ QUnixOSVersion unixOsVersion;
+ findUnixOsVersion(unixOsVersion);
+ if (!unixOsVersion.productVersion.isEmpty())
+ return unixOsVersion.productVersion;
+#endif
+
+ // fallback
+ return unknownText();
+}
+
+/*!
+ \since 5.4
+
+ Returns a prettier form of productType() and productVersion(), containing
+ other tokens like the operating system type, codenames and other
+ information. The result of this function is suitable for displaying to the
+ user, but not for long-term storage, as the string may change with updates
+ to Qt.
+
+ If productType() is "unknown", this function will instead use the
+ kernelType() and kernelVersion() functions.
+
+ \sa kernelType(), kernelVersion(), productType(), productVersion()
+*/
+QString QSysInfo::prettyProductName()
+{
+#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
+ const auto version = QOperatingSystemVersion::current();
+ const int majorVersion = version.majorVersion();
+ const QString versionString = QString::asprintf("%d.%d", majorVersion, version.minorVersion());
+ QString result = version.name() + u' ';
+ const char *name = osVer_helper(version);
+ if (!name)
+ return result + versionString;
+ result += QLatin1StringView(name);
+# if !defined(Q_OS_WIN)
+ return result + " ("_L1 + versionString + u')';
+# else
+ // (resembling winver.exe): Windows 10 "Windows 10 Version 1809"
+ const auto displayVersion = windowsDisplayVersion();
+ if (!displayVersion.isEmpty())
+ result += " Version "_L1 + displayVersion;
+ return result;
+# endif // Windows
+#elif defined(Q_OS_HAIKU)
+ return "Haiku "_L1 + productVersion();
+#elif defined(Q_OS_UNIX)
+# ifdef USE_ETC_OS_RELEASE
+ QUnixOSVersion unixOsVersion;
+ findUnixOsVersion(unixOsVersion);
+ if (!unixOsVersion.prettyName.isEmpty())
+ return unixOsVersion.prettyName;
+# endif
+ struct utsname u;
+ if (uname(&u) == 0)
+ return QString::fromLatin1(u.sysname) + u' ' + QString::fromLatin1(u.release);
+#endif
+ return unknownText();
+}
+
+#ifndef QT_BOOTSTRAPPED
+/*!
+ \since 5.6
+
+ Returns this machine's host name, if one is configured. Note that hostnames
+ are not guaranteed to be globally unique, especially if they were
+ configured automatically.
+
+ This function does not guarantee the returned host name is a Fully
+ Qualified Domain Name (FQDN). For that, use QHostInfo to resolve the
+ returned name to an FQDN.
+
+ This function returns the same as QHostInfo::localHostName().
+
+ \sa QHostInfo::localDomainName, machineUniqueId()
+*/
+QString QSysInfo::machineHostName()
+{
+ // the hostname can change, so we can't cache it
+#if defined(Q_OS_LINUX)
+ // gethostname(3) on Linux just calls uname(2), so do it ourselves
+ // and avoid a memcpy
+ struct utsname u;
+ if (uname(&u) == 0)
+ return QString::fromLocal8Bit(u.nodename);
+ return QString();
+#else
+# ifdef Q_OS_WIN
+ // Important: QtNetwork depends on machineHostName() initializing ws2_32.dll
+ winsockInit();
+# endif
+
+ char hostName[512];
+ if (gethostname(hostName, sizeof(hostName)) == -1)
+ return QString();
+ hostName[sizeof(hostName) - 1] = '\0';
+ return QString::fromLocal8Bit(hostName);
+#endif
+}
+#endif // QT_BOOTSTRAPPED
+
+enum {
+ UuidStringLen = sizeof("00000000-0000-0000-0000-000000000000") - 1
+};
+
+/*!
+ \since 5.11
+
+ Returns a unique ID for this machine, if one can be determined. If no
+ unique ID could be determined, this function returns an empty byte array.
+ Unlike machineHostName(), the value returned by this function is likely
+ globally unique.
+
+ A unique ID is useful in network operations to identify this machine for an
+ extended period of time, when the IP address could change or if this
+ machine could have more than one IP address. For example, the ID could be
+ used when communicating with a server or when storing device-specific data
+ in shared network storage.
+
+ Note that on some systems, this value will persist across reboots and on
+ some it will not. Applications should not blindly depend on this fact
+ without verifying the OS capabilities. In particular, on Linux systems,
+ this ID is usually permanent and it matches the D-Bus machine ID, except
+ for nodes without their own storage (replicated nodes).
+
+ \sa machineHostName(), bootUniqueId()
+*/
+QByteArray QSysInfo::machineUniqueId()
+{
+#if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
+ char uuid[UuidStringLen + 1];
+ static const mach_port_t defaultPort = 0; // Effectively kIOMasterPortDefault/kIOMainPortDefault
+ io_service_t service = IOServiceGetMatchingService(defaultPort, IOServiceMatching("IOPlatformExpertDevice"));
+ QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
+ CFStringGetCString(stringRef, uuid, sizeof(uuid), kCFStringEncodingMacRoman);
+ return QByteArray(uuid);
+#elif defined(Q_OS_BSD4) && defined(KERN_HOSTUUID)
+ char uuid[UuidStringLen + 1];
+ size_t uuidlen = sizeof(uuid);
+ int name[] = { CTL_KERN, KERN_HOSTUUID };
+ if (sysctl(name, sizeof name / sizeof name[0], &uuid, &uuidlen, nullptr, 0) == 0
+ && uuidlen == sizeof(uuid))
+ return QByteArray(uuid, uuidlen - 1);
+#elif defined(Q_OS_UNIX)
+ // The modern name on Linux is /etc/machine-id, but that path is
+ // unlikely to exist on non-Linux (non-systemd) systems. The old
+ // path is more than enough.
+ static const char fullfilename[] = "/usr/local/var/lib/dbus/machine-id";
+ const char *firstfilename = fullfilename + sizeof("/usr/local") - 1;
+ int fd = qt_safe_open(firstfilename, O_RDONLY);
+ if (fd == -1 && errno == ENOENT)
+ fd = qt_safe_open(fullfilename, O_RDONLY);
+
+ if (fd != -1) {
+ char buffer[32]; // 128 bits, hex-encoded
+ qint64 len = qt_safe_read(fd, buffer, sizeof(buffer));
+ qt_safe_close(fd);
+
+ if (len != -1)
+ return QByteArray(buffer, len);
+ }
+#elif defined(Q_OS_WIN)
+ // Let's poke at the registry
+ const QString machineGuid = QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Cryptography)")
+ .stringValue(u"MachineGuid"_s);
+ if (!machineGuid.isEmpty())
+ return machineGuid.toLatin1();
+#endif
+ return QByteArray();
+}
+
+/*!
+ \since 5.11
+
+ Returns a unique ID for this machine's boot, if one can be determined. If
+ no unique ID could be determined, this function returns an empty byte
+ array. This value is expected to change after every boot and can be
+ considered globally unique.
+
+ This function is currently only implemented for Linux and Apple operating
+ systems.
+
+ \sa machineUniqueId()
+*/
+QByteArray QSysInfo::bootUniqueId()
+{
+#ifdef Q_OS_LINUX
+ // use low-level API here for simplicity
+ int fd = qt_safe_open("/proc/sys/kernel/random/boot_id", O_RDONLY);
+ if (fd != -1) {
+ char uuid[UuidStringLen];
+ qint64 len = qt_safe_read(fd, uuid, sizeof(uuid));
+ qt_safe_close(fd);
+ if (len == UuidStringLen)
+ return QByteArray(uuid, UuidStringLen);
+ }
+#elif defined(Q_OS_DARWIN)
+ // "kern.bootsessionuuid" is only available by name
+ char uuid[UuidStringLen + 1];
+ size_t uuidlen = sizeof(uuid);
+ if (sysctlbyname("kern.bootsessionuuid", uuid, &uuidlen, nullptr, 0) == 0
+ && uuidlen == sizeof(uuid))
+ return QByteArray(uuid, uuidlen - 1);
+#endif
+ return QByteArray();
+};
+
+QT_END_NAMESPACE