Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsysinfo.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// Copyright (C) 2022 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#include "qsysinfo.h"
7
8#include <QtCore/qbytearray.h>
9#include <QtCore/qoperatingsystemversion.h>
10#include <QtCore/qstring.h>
11
12#include <private/qoperatingsystemversion_p.h>
13
14#ifdef Q_OS_UNIX
15# include <sys/utsname.h>
16# include <private/qcore_unix_p.h>
17#endif
18
19#ifdef Q_OS_ANDROID
20#include <QtCore/private/qjnihelpers_p.h>
21#include <qjniobject.h>
22#endif
23
24#if defined(Q_OS_HARMONY)
25#include <deviceinfo.h>
26#endif
27
28#if defined(Q_OS_SOLARIS)
29# include <sys/systeminfo.h>
30#endif
31
32#if defined(Q_OS_DARWIN)
33# include "qnamespace.h"
34# include <private/qcore_mac_p.h>
35# if __has_include(<IOKit/IOKitLib.h>)
36# include <IOKit/IOKitLib.h>
37# endif
38#endif
39
40#ifdef Q_OS_BSD4
41# include <sys/sysctl.h>
42#endif
43
44#ifdef Q_OS_WIN
45# include "qoperatingsystemversion_win_p.h"
46# include "private/qwinregistry_p.h"
47# include "qt_windows.h"
48#endif // Q_OS_WIN
49
50#include "archdetect.cpp"
51
53
54using namespace Qt::StringLiterals;
55
56/*!
57 \class QSysInfo
58 \inmodule QtCore
59 \brief The QSysInfo class provides information about the system.
60
61 \list
62 \li \l WordSize specifies the size of a pointer for the platform
63 on which the application is compiled.
64 \li \l ByteOrder specifies whether the platform is big-endian or
65 little-endian.
66 \endlist
67
68 Some constants are defined only on certain platforms. You can use
69 the preprocessor symbols Q_OS_WIN and Q_OS_MACOS to test that
70 the application is compiled under Windows or \macos.
71
72 \sa QLibraryInfo
73*/
74
75/*!
76 \enum QSysInfo::Sizes
77
78 This enum provides platform-specific information about the sizes of data
79 structures used by the underlying architecture.
80
81 \value WordSize The size in bits of a pointer for the platform on which
82 the application is compiled (32 or 64).
83*/
84
85/*!
86 \enum QSysInfo::Endian
87
88 \value BigEndian Big-endian byte order (also called Network byte order)
89 \value LittleEndian Little-endian byte order
90 \value ByteOrder Equals BigEndian or LittleEndian, depending on
91 the platform's byte order.
92*/
93
94#if defined(Q_OS_DARWIN)
95
96static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
97{
98#ifdef Q_OS_MACOS
99 switch (version.majorVersion()) {
100 case 10: {
101 switch (version.minorVersion()) {
102 case 9: return "Mavericks";
103 case 10: return "Yosemite";
104 case 11: return "El Capitan";
105 case 12: return "Sierra";
106 case 13: return "High Sierra";
107 case 14: return "Mojave";
108 case 15: return "Catalina";
109 case 16: return "Big Sur";
110 default:
111 Q_UNREACHABLE();
112 }
113 }
114 case 11: return "Big Sur";
115 case 12: return "Monterey";
116 case 13: return "Ventura";
117 case 14: return "Sonoma";
118 case 15: return "Sequoia";
119 case 26: return "Tahoe";
120 case 27: return "Golden Gate";
121 default:
122 // Unknown, future version
123 break;
124 }
125#else
126 Q_UNUSED(version);
127#endif
128 return nullptr;
129}
130
131#elif defined(Q_OS_WIN)
132
133# ifndef QT_BOOTSTRAPPED
134class QWindowsSockInit
135{
136public:
137 QWindowsSockInit();
138 ~QWindowsSockInit();
139 int version;
140};
141
142QWindowsSockInit::QWindowsSockInit()
143: version(0)
144{
145 WSAData wsadata;
146
147 if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
148 qWarning("QTcpSocketAPI: WinSock v2.2 initialization failed.");
149 } else {
150 version = 0x22;
151 }
152}
153
154QWindowsSockInit::~QWindowsSockInit()
155{
156 WSACleanup();
157}
158Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
159# endif // QT_BOOTSTRAPPED
160
161static QString readVersionRegistryString(const wchar_t *subKey)
162{
163 return QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)")
164 .stringValue(subKey);
165}
166
167static inline QString windowsDisplayVersion()
168{
169 // https://tickets.puppetlabs.com/browse/FACT-3058
170 // The "ReleaseId" key stopped updating since Windows 10 20H2.
171 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10_20H2)
172 return readVersionRegistryString(L"DisplayVersion");
173 else
174 return readVersionRegistryString(L"ReleaseId");
175}
176
177static QString winSp_helper()
178{
179 const auto osv = qWindowsVersionInfo();
180 const qint16 major = osv.wServicePackMajor;
181 if (major) {
182 QString sp = QStringLiteral("SP ") + QString::number(major);
183 const qint16 minor = osv.wServicePackMinor;
184 if (minor)
185 sp += u'.' + QString::number(minor);
186
187 return sp;
188 }
189 return QString();
190}
191
192static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
193{
194 Q_UNUSED(version);
195 const OSVERSIONINFOEX osver = qWindowsVersionInfo();
196 const bool workstation = osver.wProductType == VER_NT_WORKSTATION;
197
198#define Q_WINVER(major, minor) (major << 8 | minor)
199 switch (Q_WINVER(osver.dwMajorVersion, osver.dwMinorVersion)) {
200 case Q_WINVER(10, 0):
201 if (workstation) {
202 if (osver.dwBuildNumber >= 22000)
203 return "11";
204 return "10";
205 }
206 // else: Server
207 if (osver.dwBuildNumber >= 26100)
208 return "Server 2025";
209 if (osver.dwBuildNumber >= 20348)
210 return "Server 2022";
211 if (osver.dwBuildNumber >= 17763)
212 return "Server 2019";
213 return "Server 2016";
214 }
215#undef Q_WINVER
216 // unknown, future version
217 return nullptr;
218}
219
220#endif
221#if defined(Q_OS_UNIX)
222# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
223# define USE_ETC_OS_RELEASE
224struct QUnixOSVersion
225{
226 // from /etc/os-release older /etc/lsb-release // redhat /etc/redhat-release // debian /etc/debian_version
227 QString productType; // $ID $DISTRIB_ID // single line file containing: // Debian
228 QString productVersion; // $VERSION_ID $DISTRIB_RELEASE // <Vendor_ID release Version_ID> // single line file <Release_ID/sid>
229 QString prettyName; // $PRETTY_NAME $DISTRIB_DESCRIPTION
230};
231
232static QString unquote(QByteArrayView str)
233{
234 // man os-release says:
235 // Variable assignment values must be enclosed in double
236 // or single quotes if they include spaces, semicolons or
237 // other special characters outside of A–Z, a–z, 0–9. Shell
238 // special characters ("$", quotes, backslash, backtick)
239 // must be escaped with backslashes, following shell style.
240 // All strings should be in UTF-8 format, and non-printable
241 // characters should not be used. It is not supported to
242 // concatenate multiple individually quoted strings.
243 if (str.size() >= 2 && str.front() == '"' && str.back() == '"')
244 str = str.sliced(1).chopped(1);
245 return QString::fromUtf8(str);
246}
247
248static QByteArray getEtcFileContent(const char *filename)
249{
250 // we're avoiding QFile here
251 int fd = qt_safe_open(filename, O_RDONLY);
252 if (fd == -1)
253 return QByteArray();
254
255 QT_STATBUF sbuf;
256 if (QT_FSTAT(fd, &sbuf) == -1) {
257 qt_safe_close(fd);
258 return QByteArray();
259 }
260
261 QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
262 buffer.resize(qt_safe_read(fd, buffer.data(), sbuf.st_size));
263 qt_safe_close(fd);
264 return buffer;
265}
266
267static bool readEtcFile(QUnixOSVersion &v, const char *filename,
268 const QByteArray &idKey, const QByteArray &versionKey, const QByteArray &prettyNameKey)
269{
270
271 QByteArray buffer = getEtcFileContent(filename);
272 if (buffer.isEmpty())
273 return false;
274
275 const char *ptr = buffer.constData();
276 const char *end = buffer.constEnd();
277 const char *eol;
278 QByteArray line;
279 for (; ptr != end; ptr = eol + 1) {
280 // find the end of the line after ptr
281 eol = static_cast<const char *>(memchr(ptr, '\n', end - ptr));
282 if (!eol)
283 eol = end - 1;
284 line.setRawData(ptr, eol - ptr);
285
286 if (line.startsWith(idKey)) {
287 ptr += idKey.size();
288 v.productType = unquote({ptr, eol});
289 continue;
290 }
291
292 if (line.startsWith(prettyNameKey)) {
293 ptr += prettyNameKey.size();
294 v.prettyName = unquote({ptr, eol});
295 continue;
296 }
297
298 if (line.startsWith(versionKey)) {
299 ptr += versionKey.size();
300 v.productVersion = unquote({ptr, eol});
301 continue;
302 }
303 }
304
305 return true;
306}
307
308static bool readOsRelease(QUnixOSVersion &v)
309{
310 QByteArray id = QByteArrayLiteral("ID=");
311 QByteArray versionId = QByteArrayLiteral("VERSION_ID=");
312 QByteArray prettyName = QByteArrayLiteral("PRETTY_NAME=");
313
314 // man os-release(5) says:
315 // The file /etc/os-release takes precedence over /usr/lib/os-release.
316 // Applications should check for the former, and exclusively use its data
317 // if it exists, and only fall back to /usr/lib/os-release if it is
318 // missing.
319 return readEtcFile(v, "/etc/os-release", id, versionId, prettyName) ||
320 readEtcFile(v, "/usr/lib/os-release", id, versionId, prettyName);
321}
322
323static bool readEtcLsbRelease(QUnixOSVersion &v)
324{
325 bool ok = readEtcFile(v, "/etc/lsb-release", QByteArrayLiteral("DISTRIB_ID="),
326 QByteArrayLiteral("DISTRIB_RELEASE="), QByteArrayLiteral("DISTRIB_DESCRIPTION="));
327 if (ok && (v.prettyName.isEmpty() || v.prettyName == v.productType)) {
328 // some distributions have redundant information for the pretty name,
329 // so try /etc/<lowercasename>-release
330
331 // we're still avoiding QFile here
332 QByteArray distrorelease = "/etc/" + v.productType.toLatin1().toLower() + "-release";
333 int fd = qt_safe_open(distrorelease, O_RDONLY);
334 if (fd != -1) {
335 QT_STATBUF sbuf;
336 if (QT_FSTAT(fd, &sbuf) != -1 && sbuf.st_size > v.prettyName.size()) {
337 // file apparently contains interesting information
338 QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
339 buffer.resize(qt_safe_read(fd, buffer.data(), sbuf.st_size));
340 v.prettyName = QString::fromLatin1(buffer.trimmed());
341 }
342 qt_safe_close(fd);
343 }
344 }
345
346 // some distributions have a /etc/lsb-release file that does not provide the values
347 // we are looking for, i.e. DISTRIB_ID, DISTRIB_RELEASE and DISTRIB_DESCRIPTION.
348 // Assuming that neither DISTRIB_ID nor DISTRIB_RELEASE were found, or contained valid values,
349 // returning false for readEtcLsbRelease will allow further /etc/<lowercasename>-release parsing.
350 return ok && !(v.productType.isEmpty() && v.productVersion.isEmpty());
351}
352
353#if defined(Q_OS_LINUX)
354static bool readEtcRedHatRelease(QUnixOSVersion &v)
355{
356 // /etc/redhat-release analysed should be a one line file
357 // the format of its content is <Vendor_ID release Version>
358 // i.e. "Red Hat Enterprise Linux Workstation release 6.5 (Santiago)"
359 QByteArray line = getEtcFileContent("/etc/redhat-release").trimmed();
360 if (line.isEmpty())
361 return false;
362
363 v.prettyName = QString::fromLatin1(line);
364
365 const char keyword[] = "release ";
366 const qsizetype releaseIndex = line.indexOf(keyword);
367 v.productType = QString::fromLatin1(line.mid(0, releaseIndex)).remove(u' ');
368 const qsizetype spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword));
369 v.productVersion = QString::fromLatin1(line.mid(releaseIndex + strlen(keyword),
370 spaceIndex > -1 ? spaceIndex - releaseIndex - int(strlen(keyword)) : -1));
371 return true;
372}
373
374static bool readEtcDebianVersion(QUnixOSVersion &v)
375{
376 // /etc/debian_version analysed should be a one line file
377 // the format of its content is <Release_ID/sid>
378 // i.e. "jessie/sid"
379 QByteArray line = getEtcFileContent("/etc/debian_version").trimmed();
380 if (line.isEmpty())
381 return false;
382
383 v.productType = QStringLiteral("Debian");
384 v.productVersion = QString::fromLatin1(line);
385 return true;
386}
387#endif
388
389[[maybe_unused]] static bool findUnixOsVersion(QUnixOSVersion &v)
390{
391 if (readOsRelease(v))
392 return true;
393 if (readEtcLsbRelease(v))
394 return true;
395#if defined(Q_OS_LINUX)
396 if (readEtcRedHatRelease(v))
397 return true;
398 if (readEtcDebianVersion(v))
399 return true;
400#endif
401 return false;
402}
403# endif // USE_ETC_OS_RELEASE
404#endif // Q_OS_UNIX
405
406#ifdef Q_OS_ANDROID
407static const char *osVer_helper(QOperatingSystemVersion)
408{
409 // https://source.android.com/source/build-numbers.html
410 // https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels
411 const int sdk_int = QtAndroidPrivate::androidSdkVersion();
412 switch (sdk_int) {
413 case 3:
414 return "Cupcake";
415 case 4:
416 return "Donut";
417 case 5:
418 case 6:
419 case 7:
420 return "Eclair";
421 case 8:
422 return "Froyo";
423 case 9:
424 case 10:
425 return "Gingerbread";
426 case 11:
427 case 12:
428 case 13:
429 return "Honeycomb";
430 case 14:
431 case 15:
432 return "Ice Cream Sandwich";
433 case 16:
434 case 17:
435 case 18:
436 return "Jelly Bean";
437 case 19:
438 case 20:
439 return "KitKat";
440 case 21:
441 case 22:
442 return "Lollipop";
443 case 23:
444 return "Marshmallow";
445 case 24:
446 case 25:
447 return "Nougat";
448 case 26:
449 case 27:
450 return "Oreo";
451 case 28:
452 return "Pie";
453 case 29:
454 return "10";
455 case 30:
456 return "11";
457 case 31:
458 return "12";
459 case 32:
460 return "12L";
461 case 33:
462 return "13";
463 default:
464 break;
465 }
466
467 return "";
468}
469#endif
470
471/*!
472 \since 5.4
473
474 Returns the architecture of the CPU that Qt was compiled for, in text
475 format. Note that this may not match the actual CPU that the application is
476 running on if there's an emulation layer or if the CPU supports multiple
477 architectures (like x86-64 processors supporting i386 applications). To
478 detect that, use currentCpuArchitecture().
479
480 Values returned by this function are stable and will not change over time,
481 so applications can rely on the returned value as an identifier, except
482 that new CPU types may be added over time.
483
484 Typical returned values are (note: list not exhaustive):
485 \list
486 \li "arm"
487 \li "arm64"
488 \li "i386"
489 \li "ia64"
490 \li "mips"
491 \li "mips64"
492 \li "power"
493 \li "power64"
494 \li "sparc"
495 \li "sparcv9"
496 \li "x86_64"
497 \endlist
498
499 \sa QSysInfo::buildAbi(), QSysInfo::currentCpuArchitecture()
500*/
501QString QSysInfo::buildCpuArchitecture()
502{
503 return QStringLiteral(ARCH_PROCESSOR);
504}
505
506/*!
507 \since 5.4
508
509 Returns the architecture of the CPU that the application is running on, in
510 text format. Note that this function depends on what the OS will report and
511 may not detect the actual CPU architecture if the OS hides that information
512 or is unable to provide it. For example, a 32-bit OS running on a 64-bit
513 CPU is usually unable to determine the CPU is actually capable of running
514 64-bit programs.
515
516 Values returned by this function are mostly stable: an attempt will be made
517 to ensure that they stay constant over time and match the values returned
518 by buildCpuArchitecture(). However, due to the nature of the
519 operating system functions being used, there may be discrepancies.
520
521 Typical returned values are (note: list not exhaustive):
522 \list
523 \li "arm"
524 \li "arm64"
525 \li "i386"
526 \li "ia64"
527 \li "mips"
528 \li "mips64"
529 \li "power"
530 \li "power64"
531 \li "sparc"
532 \li "sparcv9"
533 \li "x86_64"
534 \endlist
535
536 \sa QSysInfo::buildAbi(), QSysInfo::buildCpuArchitecture()
537*/
538QString QSysInfo::currentCpuArchitecture()
539{
540#if defined(Q_OS_WIN)
541 // We don't need to catch all the CPU architectures in this function;
542 // only those where the host CPU might be different than the build target
543 // (usually, 64-bit platforms).
544 SYSTEM_INFO info;
545 GetNativeSystemInfo(&info);
546 switch (info.wProcessorArchitecture) {
547# ifdef PROCESSOR_ARCHITECTURE_AMD64
548 case PROCESSOR_ARCHITECTURE_AMD64:
549 return QStringLiteral("x86_64");
550# endif
551# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
552 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
553# endif
554 case PROCESSOR_ARCHITECTURE_IA64:
555 return QStringLiteral("ia64");
556 }
557#elif defined(Q_OS_DARWIN) && !defined(Q_OS_MACOS)
558 // iOS-based OSes do not return the architecture on uname(2)'s result.
559 return buildCpuArchitecture();
560#elif defined(Q_OS_UNIX)
561 long ret = -1;
562 struct utsname u;
563
564# if defined(Q_OS_SOLARIS)
565 // We need a special call for Solaris because uname(2) on x86 returns "i86pc" for
566 // both 32- and 64-bit CPUs. Reference:
567 // http://docs.oracle.com/cd/E18752_01/html/816-5167/sysinfo-2.html#REFMAN2sysinfo-2
568 // http://fxr.watson.org/fxr/source/common/syscall/systeminfo.c?v=OPENSOLARIS
569 // http://fxr.watson.org/fxr/source/common/conf/param.c?v=OPENSOLARIS;im=10#L530
570 if (ret == -1)
571 ret = sysinfo(SI_ARCHITECTURE_64, u.machine, sizeof u.machine);
572# endif
573
574 if (ret == -1)
575 ret = uname(&u);
576
577 // we could use detectUnixVersion() above, but we only need a field no other function does
578 if (ret != -1) {
579 // the use of QT_BUILD_INTERNAL here is simply to ensure all branches build
580 // as we don't often build on some of the less common platforms
581# if defined(Q_PROCESSOR_ARM) || defined(QT_BUILD_INTERNAL)
582 if (strcmp(u.machine, "aarch64") == 0)
583 return QStringLiteral("arm64");
584 if (strncmp(u.machine, "armv", 4) == 0)
585 return QStringLiteral("arm");
586# endif
587# if defined(Q_PROCESSOR_POWER) || defined(QT_BUILD_INTERNAL)
588 // harmonize "powerpc" and "ppc" to "power"
589 if (strncmp(u.machine, "ppc", 3) == 0)
590 return "power"_L1 + QLatin1StringView(u.machine + 3);
591 if (strncmp(u.machine, "powerpc", 7) == 0)
592 return "power"_L1 + QLatin1StringView(u.machine + 7);
593 if (strcmp(u.machine, "Power Macintosh") == 0)
594 return "power"_L1;
595# endif
596# if defined(Q_PROCESSOR_SPARC) || defined(QT_BUILD_INTERNAL)
597 // Solaris sysinfo(2) (above) uses "sparcv9", but uname -m says "sun4u";
598 // Linux says "sparc64"
599 if (strcmp(u.machine, "sun4u") == 0 || strcmp(u.machine, "sparc64") == 0)
600 return QStringLiteral("sparcv9");
601 if (strcmp(u.machine, "sparc32") == 0)
602 return QStringLiteral("sparc");
603# endif
604# if defined(Q_PROCESSOR_X86) || defined(QT_BUILD_INTERNAL)
605 // harmonize all "i?86" to "i386"
606 if (strlen(u.machine) == 4 && u.machine[0] == 'i'
607 && u.machine[2] == '8' && u.machine[3] == '6')
608 return QStringLiteral("i386");
609 if (strcmp(u.machine, "amd64") == 0) // Solaris
610 return QStringLiteral("x86_64");
611# endif
612 return QString::fromLatin1(u.machine);
613 }
614#endif
615 return buildCpuArchitecture();
616}
617
618/*!
619 \since 5.4
620
621 Returns the full architecture string that Qt was compiled for. This string
622 is useful for identifying different, incompatible builds. For example, it
623 can be used as an identifier to request an upgrade package from a server.
624
625 The values returned from this function are kept stable as follows: the
626 mandatory components of the result will not change in future versions of
627 Qt, but optional suffixes may be added.
628
629 The returned value is composed of three or more parts, separated by dashes
630 ("-"). They are:
631
632 \table
633 \header \li Component \li Value
634 \row \li CPU Architecture \li The same as QSysInfo::buildCpuArchitecture(), such as "arm", "i386", "mips" or "x86_64"
635 \row \li Endianness \li "little_endian" or "big_endian"
636 \row \li Word size \li Whether it's a 32- or 64-bit application. Possible values are:
637 "llp64" (Windows 64-bit), "lp64" (Unix 64-bit), "ilp32" (32-bit)
638 \row \li (Optional) ABI \li Zero or more components identifying different ABIs possible in this architecture.
639 Currently, Qt has optional ABI components for ARM and MIPS processors: one
640 component is the main ABI (such as "eabi", "o32", "n32", "o64"); another is
641 whether the calling convention is using hardware floating point registers ("hardfloat"
642 is present).
643
644 Additionally, if Qt was configured with \c{-qreal float}, the ABI option tag "qreal_float"
645 will be present. If Qt was configured with another type as qreal, that type is present after
646 "qreal_", with all characters other than letters and digits escaped by an underscore, followed
647 by two hex digits. For example, \c{-qreal long double} becomes "qreal_long_20double".
648 \endtable
649
650 \sa QSysInfo::buildCpuArchitecture()
651*/
652QString QSysInfo::buildAbi()
653{
654 // ARCH_FULL is a concatenation of strings (incl. ARCH_PROCESSOR), which breaks
655 // QStringLiteral on MSVC. Since the concatenation behavior we want is specified
656 // the same C++11 paper as the Unicode strings, we'll use that macro and hope
657 // that Microsoft implements the new behavior when they add support for Unicode strings.
658 return QStringLiteral(ARCH_FULL);
659}
660
661static QString unknownText()
662{
663 return QStringLiteral("unknown");
664}
665
666/*!
667 \since 5.4
668
669 Returns the type of the operating system kernel Qt was compiled for. It's
670 also the kernel the application is running on, unless the host operating
671 system is running a form of compatibility or virtualization layer.
672
673 Values returned by this function are stable and will not change over time,
674 so applications can rely on the returned value as an identifier, except
675 that new OS kernel types may be added over time.
676
677 On Windows, this function returns the type of Windows kernel, like "winnt".
678 On Unix systems, it returns the same as the output of \c{uname
679 -s} (lowercased).
680
681 \note This function may return surprising values: it returns "linux"
682 for all operating systems running Linux (including Android), "qnx" for all
683 operating systems running QNX, "freebsd" for
684 Debian/kFreeBSD, and "darwin" for \macos and iOS. For information on the type
685 of product the application is running on, see productType().
686
687 \sa QFileSelector, kernelVersion(), productType(), productVersion(), prettyProductName()
688*/
689QString QSysInfo::kernelType()
690{
691#if defined(Q_OS_WIN)
692 return QStringLiteral("winnt");
693#elif defined(Q_OS_UNIX)
694 struct utsname u;
695 if (uname(&u) == 0)
696 return QString::fromLatin1(u.sysname).toLower();
697#endif
698 return unknownText();
699}
700
701/*!
702 \since 5.4
703
704 Returns the release version of the operating system kernel. On Windows, it
705 returns the version of the NT kernel. On Unix systems, including
706 Android and \macos, it returns the same as the \c{uname -r}
707 command would return. On VxWorks, it returns the numeric part of the string
708 reported by kernelVersion().
709
710 If the version could not be determined, this function may return an empty
711 string.
712
713 \sa kernelType(), productType(), productVersion(), prettyProductName()
714*/
715QString QSysInfo::kernelVersion()
716{
717#ifdef Q_OS_WIN
718 const auto osver = QOperatingSystemVersion::current();
719 return QString::asprintf("%d.%d.%d",
720 osver.majorVersion(), osver.minorVersion(), osver.microVersion());
721#else
722 struct utsname u;
723 if (uname(&u) == 0) {
724# ifdef Q_OS_VXWORKS
725 // The string follows the pattern "Core Kernel version: w.x.y.z"
726 auto versionStr = QByteArrayView(u.kernelversion);
727 if (auto lastSpace = versionStr.lastIndexOf(' '); lastSpace != -1) {
728 return QString::fromLatin1(versionStr.sliced(lastSpace + 1));
729 }
730# else
731 return QString::fromLatin1(u.release);
732# endif
733 }
734 return QString();
735#endif
736}
737
738
739/*!
740 \since 5.4
741
742 Returns the product name of the operating system this application is
743 running in. If the application is running on some sort of emulation or
744 virtualization layer (such as WINE on a Unix system), this function will
745 inspect the emulation / virtualization layer.
746
747 Values returned by this function are stable and will not change over time,
748 so applications can rely on the returned value as an identifier, except
749 that new OS types may be added over time.
750
751 \b{Linux and Android note}: this function returns "android" for Linux
752 systems running Android userspace, notably when using the Bionic library.
753 For all other Linux systems, regardless of C library being used, it tries
754 to determine the distribution name and returns that. If determining the
755 distribution name failed, it returns "unknown".
756
757 \b{\macos note}: this function returns "macos" for all \macos systems,
758 regardless of Apple naming convention. Previously, in Qt 5, it returned
759 "osx", again regardless of Apple naming conventions.
760
761 \b{Darwin, iOS, tvOS, and watchOS note}: this function returns "ios" for
762 iOS systems, "tvos" for tvOS systems, "watchos" for watchOS systems, and
763 "darwin" in case the system could not be determined.
764
765 \b{FreeBSD note}: this function returns "debian" for Debian/kFreeBSD and
766 "unknown" otherwise.
767
768 \b{Windows note}: this function return "windows"
769
770 \b{VxWorks note}: this function return "vxworks"
771
772 For other Unix-type systems, this function usually returns "unknown".
773
774 \sa QFileSelector, kernelType(), kernelVersion(), productVersion(), prettyProductName()
775*/
776QString QSysInfo::productType()
777{
778 // similar, but not identical to QFileSelectorPrivate::platformSelectors
779#if defined(Q_OS_WIN)
780 return QStringLiteral("windows");
781
782#elif defined(Q_OS_QNX)
783 return QStringLiteral("qnx");
784
785#elif defined(Q_OS_ANDROID)
786 return QStringLiteral("android");
787
788#elif defined(Q_OS_HARMONY)
789 return QStringLiteral("harmonyos");
790#elif defined(Q_OS_IOS)
791 return QStringLiteral("ios");
792#elif defined(Q_OS_TVOS)
793 return QStringLiteral("tvos");
794#elif defined(Q_OS_WATCHOS)
795 return QStringLiteral("watchos");
796#elif defined(Q_OS_VISIONOS)
797 return QStringLiteral("visionos");
798#elif defined(Q_OS_MACOS)
799 return QStringLiteral("macos");
800#elif defined(Q_OS_DARWIN)
801 return QStringLiteral("darwin");
802#elif defined(Q_OS_WASM)
803 return QStringLiteral("wasm");
804#elif defined(Q_OS_VXWORKS)
805 return QStringLiteral("vxworks");
806
807#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
808 QUnixOSVersion unixOsVersion;
809 findUnixOsVersion(unixOsVersion);
810 if (!unixOsVersion.productType.isEmpty())
811 return unixOsVersion.productType;
812#endif
813 return unknownText();
814}
815
816/*!
817 \since 5.4
818
819 Returns the product version of the operating system in string form. If the
820 version could not be determined, this function returns "unknown".
821
822 It will return the Android, iOS, \macos, VxWorks, Windows full-product
823 versions on those systems.
824
825 Typical returned values are (note: list not exhaustive):
826 \list
827 \li "12" (Android 12)
828 \li "36" (Fedora 36)
829 \li "15.5" (iOS 15.5)
830 \li "12.4" (macOS Monterey)
831 \li "22.04" (Ubuntu 22.04)
832 \li "8.6" (watchOS 8.6)
833 \li "11" (Windows 11)
834 \li "Server 2022" (Windows Server 2022)
835 \li "24.03" (VxWorks 7 - 24.03)
836 \endlist
837
838 On Linux systems, it will try to determine the distribution version and will
839 return that. This is also done on Debian/kFreeBSD, so this function will
840 return Debian version in that case.
841
842 In all other Unix-type systems, this function always returns "unknown".
843
844 \note The version string returned from this function is not guaranteed to
845 be orderable. On Linux, the version of
846 the distribution may jump unexpectedly, please refer to the distribution's
847 documentation for versioning practices.
848
849 \sa kernelType(), kernelVersion(), productType(), prettyProductName()
850*/
851QString QSysInfo::productVersion()
852{
853#if defined(Q_OS_ANDROID)
854 const auto version = QOperatingSystemVersion::current();
855 return QString::asprintf("%d.%d", version.majorVersion(), version.minorVersion());
856#elif defined(Q_OS_DARWIN) || defined(Q_OS_HARMONY)
857 const auto version = QOperatingSystemVersion::current();
858 return QString::asprintf("%d.%d.%d", version.majorVersion(),
859 version.minorVersion(),
860 version.microVersion());
861#elif defined(Q_OS_WIN)
862 const char *version = osVer_helper();
863 if (version) {
864 const QLatin1Char spaceChar(' ');
865 return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower();
866 }
867 // fall through
868
869#elif defined(Q_OS_VXWORKS)
870 utsname u;
871 if (uname(&u) == 0)
872 return QString::fromLatin1(u.releaseversion);
873 // fall through
874
875#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
876 QUnixOSVersion unixOsVersion;
877 findUnixOsVersion(unixOsVersion);
878 if (!unixOsVersion.productVersion.isEmpty())
879 return unixOsVersion.productVersion;
880#endif
881
882 // fallback
883 return unknownText();
884}
885
886/*!
887 \since 5.4
888
889 Returns a prettier form of productType() and productVersion(), containing
890 other tokens like the operating system type, codenames and other
891 information. The result of this function is suitable for displaying to the
892 user, but not for long-term storage, as the string may change with updates
893 to Qt.
894
895 If productType() is "unknown", this function will instead use the
896 kernelType() and kernelVersion() functions.
897
898 \sa kernelType(), kernelVersion(), productType(), productVersion()
899*/
900QString QSysInfo::prettyProductName()
901{
902#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
903 const auto version = QOperatingSystemVersion::current();
904 QString versionString;
905# if defined(Q_OS_DARWIN)
906 if (const int microVersion = version.microVersion(); microVersion > 0)
907 versionString = QString::asprintf("%d.%d.%d", version.majorVersion(),
908 version.minorVersion(),
909 microVersion);
910 else
911# endif // Darwin
912 versionString = QString::asprintf("%d.%d", version.majorVersion(),
913 version.minorVersion());
914 QString result = version.name() + u' ';
915 const char *name = osVer_helper(version);
916 if (!name)
917 return result + versionString;
918 result += QLatin1StringView(name);
919# if !defined(Q_OS_WIN)
920 return result + " ("_L1 + versionString + u')';
921# else
922 // (resembling winver.exe): Windows 10 "Windows 10 Version 1809"
923 const auto displayVersion = windowsDisplayVersion();
924 if (!displayVersion.isEmpty())
925 result += " Version "_L1 + displayVersion;
926 return result;
927# endif // Windows
928#elif defined(Q_OS_HARMONY)
929 QString result = QString::asprintf("%s %s", OH_GetOSFullName(),
930 OH_GetDistributionOSReleaseType());
931 return result;
932#elif defined(Q_OS_HAIKU)
933 return "Haiku "_L1 + productVersion();
934#elif defined(Q_OS_UNIX)
935# ifdef USE_ETC_OS_RELEASE
936 QUnixOSVersion unixOsVersion;
937 findUnixOsVersion(unixOsVersion);
938 if (!unixOsVersion.prettyName.isEmpty())
939 return unixOsVersion.prettyName;
940# endif
941 struct utsname u;
942 if (uname(&u) == 0)
943 return QString::fromLatin1(u.sysname) + u' ' + QString::fromLatin1(u.release);
944#endif
945 return unknownText();
946}
947
948#ifndef QT_BOOTSTRAPPED
949/*!
950 \since 5.6
951
952 Returns this machine's host name, if one is configured. Note that hostnames
953 are not guaranteed to be globally unique, especially if they were
954 configured automatically.
955
956 This function does not guarantee the returned host name is a Fully
957 Qualified Domain Name (FQDN). For that, use QHostInfo to resolve the
958 returned name to an FQDN.
959
960 This function returns the same as QHostInfo::localHostName().
961
962 \sa QHostInfo::localDomainName, machineUniqueId()
963*/
964QString QSysInfo::machineHostName()
965{
966 // the hostname can change, so we can't cache it
967#if defined(Q_OS_LINUX)
968 // gethostname(3) on Linux just calls uname(2), so do it ourselves
969 // and avoid a memcpy
970 struct utsname u;
971 if (uname(&u) == 0)
972 return QString::fromLocal8Bit(u.nodename);
973 return QString();
974#else
975# ifdef Q_OS_WIN
976 // Important: QtNetwork depends on machineHostName() initializing ws2_32.dll
977 winsockInit();
978 QString hostName;
979 hostName.resize(512);
980 unsigned long len = hostName.size();
981 BOOL res = GetComputerNameEx(ComputerNameDnsHostname,
982 reinterpret_cast<wchar_t *>(hostName.data()), &len);
983 if (!res && len > 512) {
984 hostName.resize(len - 1);
985 GetComputerNameEx(ComputerNameDnsHostname, reinterpret_cast<wchar_t *>(hostName.data()),
986 &len);
987 }
988 hostName.truncate(len);
989 return hostName;
990# else // !Q_OS_WIN
991
992 char hostName[512];
993 if (gethostname(hostName, sizeof(hostName)) == -1)
994 return QString();
995 hostName[sizeof(hostName) - 1] = '\0';
996 return QString::fromLocal8Bit(hostName);
997# endif
998#endif
999}
1000#endif // QT_BOOTSTRAPPED
1001
1002enum {
1003 UuidStringLen = sizeof("00000000-0000-0000-0000-000000000000") - 1
1004};
1005
1006/*!
1007 \since 5.11
1008
1009 Returns a unique ID for this machine, if one can be determined. If no
1010 unique ID could be determined, this function returns an empty byte array.
1011 Unlike machineHostName(), the value returned by this function is likely
1012 globally unique.
1013
1014 A unique ID is useful in network operations to identify this machine for an
1015 extended period of time, when the IP address could change or if this
1016 machine could have more than one IP address. For example, the ID could be
1017 used when communicating with a server or when storing device-specific data
1018 in shared network storage.
1019
1020 Note that on some systems, this value will persist across reboots and on
1021 some it will not. Applications should not blindly depend on this fact
1022 without verifying the OS capabilities. In particular, on Linux systems,
1023 this ID is usually permanent and it matches the D-Bus machine ID, except
1024 for nodes without their own storage (replicated nodes).
1025
1026 \sa machineHostName(), bootUniqueId()
1027*/
1028QByteArray QSysInfo::machineUniqueId()
1029{
1030#if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
1031 char uuid[UuidStringLen + 1];
1032 io_service_t service = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
1033 QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
1034 CFStringGetCString(stringRef, uuid, sizeof(uuid), kCFStringEncodingMacRoman);
1035 return QByteArray(uuid);
1036#elif defined(Q_OS_BSD4) && defined(KERN_HOSTUUID)
1037 char uuid[UuidStringLen + 1];
1038 size_t uuidlen = sizeof(uuid);
1039 int name[] = { CTL_KERN, KERN_HOSTUUID };
1040 if (sysctl(name, sizeof name / sizeof name[0], &uuid, &uuidlen, nullptr, 0) == 0
1041 && uuidlen == sizeof(uuid))
1042 return QByteArray(uuid, uuidlen - 1);
1043#elif defined(Q_OS_UNIX)
1044 // The modern name on Linux is /etc/machine-id, but that path is
1045 // unlikely to exist on non-Linux (non-systemd) systems. The old
1046 // path is more than enough.
1047 static const char fullfilename[] = "/usr/local/var/lib/dbus/machine-id";
1048 const char *firstfilename = fullfilename + sizeof("/usr/local") - 1;
1049 int fd = qt_safe_open(firstfilename, O_RDONLY);
1050 if (fd == -1 && errno == ENOENT)
1051 fd = qt_safe_open(fullfilename, O_RDONLY);
1052
1053 if (fd != -1) {
1054 char buffer[32]; // 128 bits, hex-encoded
1055 qint64 len = qt_safe_read(fd, buffer, sizeof(buffer));
1056 qt_safe_close(fd);
1057
1058 if (len != -1)
1059 return QByteArray(buffer, len);
1060 }
1061#elif defined(Q_OS_WIN)
1062 // Let's poke at the registry
1063 const QString machineGuid = QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Cryptography)")
1064 .stringValue(L"MachineGuid");
1065 if (!machineGuid.isEmpty())
1066 return machineGuid.toLatin1();
1067#endif
1068 return QByteArray();
1069}
1070
1071/*!
1072 \since 5.11
1073
1074 Returns a unique ID for this machine's boot, if one can be determined. If
1075 no unique ID could be determined, this function returns an empty byte
1076 array. This value is expected to change after every boot and can be
1077 considered globally unique.
1078
1079 This function is currently only implemented for Linux and Apple operating
1080 systems.
1081
1082 \sa machineUniqueId()
1083*/
1084QByteArray QSysInfo::bootUniqueId()
1085{
1086#ifdef Q_OS_LINUX
1087 // use low-level API here for simplicity
1088 int fd = qt_safe_open("/proc/sys/kernel/random/boot_id", O_RDONLY);
1089 if (fd != -1) {
1090 char uuid[UuidStringLen];
1091 qint64 len = qt_safe_read(fd, uuid, sizeof(uuid));
1092 qt_safe_close(fd);
1093 if (len == UuidStringLen)
1094 return QByteArray(uuid, UuidStringLen);
1095 }
1096#elif defined(Q_OS_DARWIN)
1097 // "kern.bootsessionuuid" is only available by name
1098 char uuid[UuidStringLen + 1];
1099 size_t uuidlen = sizeof(uuid);
1100 if (sysctlbyname("kern.bootsessionuuid", uuid, &uuidlen, nullptr, 0) == 0
1101 && uuidlen == sizeof(uuid))
1102 return QByteArray(uuid, uuidlen - 1);
1103#endif
1104 return QByteArray();
1105};
1106
1107QT_END_NAMESPACE
#define ARCH_PROCESSOR
#define ARCH_FULL
Combined button and popup list for selecting options.
#define __has_include(x)
@ UuidStringLen
static QString unknownText()
Definition qsysinfo.cpp:661