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_OHOS)
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 QByteArray getEtcFileFirstLine(const char *fileName)
355{
356 QByteArray buffer = getEtcFileContent(fileName);
357 if (buffer.isEmpty())
358 return QByteArray();
359
360 const char *ptr = buffer.constData();
361 return QByteArray(ptr, buffer.indexOf("\n")).trimmed();
362}
363
364static bool readEtcRedHatRelease(QUnixOSVersion &v)
365{
366 // /etc/redhat-release analysed should be a one line file
367 // the format of its content is <Vendor_ID release Version>
368 // i.e. "Red Hat Enterprise Linux Workstation release 6.5 (Santiago)"
369 QByteArray line = getEtcFileFirstLine("/etc/redhat-release");
370 if (line.isEmpty())
371 return false;
372
373 v.prettyName = QString::fromLatin1(line);
374
375 const char keyword[] = "release ";
376 const qsizetype releaseIndex = line.indexOf(keyword);
377 v.productType = QString::fromLatin1(line.mid(0, releaseIndex)).remove(u' ');
378 const qsizetype spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword));
379 v.productVersion = QString::fromLatin1(line.mid(releaseIndex + strlen(keyword),
380 spaceIndex > -1 ? spaceIndex - releaseIndex - int(strlen(keyword)) : -1));
381 return true;
382}
383
384static bool readEtcDebianVersion(QUnixOSVersion &v)
385{
386 // /etc/debian_version analysed should be a one line file
387 // the format of its content is <Release_ID/sid>
388 // i.e. "jessie/sid"
389 QByteArray line = getEtcFileFirstLine("/etc/debian_version");
390 if (line.isEmpty())
391 return false;
392
393 v.productType = QStringLiteral("Debian");
394 v.productVersion = QString::fromLatin1(line);
395 return true;
396}
397#endif
398
399[[maybe_unused]] static bool findUnixOsVersion(QUnixOSVersion &v)
400{
401 if (readOsRelease(v))
402 return true;
403 if (readEtcLsbRelease(v))
404 return true;
405#if defined(Q_OS_LINUX)
406 if (readEtcRedHatRelease(v))
407 return true;
408 if (readEtcDebianVersion(v))
409 return true;
410#endif
411 return false;
412}
413# endif // USE_ETC_OS_RELEASE
414#endif // Q_OS_UNIX
415
416#ifdef Q_OS_ANDROID
417static const char *osVer_helper(QOperatingSystemVersion)
418{
419 // https://source.android.com/source/build-numbers.html
420 // https://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels
421 const int sdk_int = QtAndroidPrivate::androidSdkVersion();
422 switch (sdk_int) {
423 case 3:
424 return "Cupcake";
425 case 4:
426 return "Donut";
427 case 5:
428 case 6:
429 case 7:
430 return "Eclair";
431 case 8:
432 return "Froyo";
433 case 9:
434 case 10:
435 return "Gingerbread";
436 case 11:
437 case 12:
438 case 13:
439 return "Honeycomb";
440 case 14:
441 case 15:
442 return "Ice Cream Sandwich";
443 case 16:
444 case 17:
445 case 18:
446 return "Jelly Bean";
447 case 19:
448 case 20:
449 return "KitKat";
450 case 21:
451 case 22:
452 return "Lollipop";
453 case 23:
454 return "Marshmallow";
455 case 24:
456 case 25:
457 return "Nougat";
458 case 26:
459 case 27:
460 return "Oreo";
461 case 28:
462 return "Pie";
463 case 29:
464 return "10";
465 case 30:
466 return "11";
467 case 31:
468 return "12";
469 case 32:
470 return "12L";
471 case 33:
472 return "13";
473 default:
474 break;
475 }
476
477 return "";
478}
479#endif
480
481/*!
482 \since 5.4
483
484 Returns the architecture of the CPU that Qt was compiled for, in text
485 format. Note that this may not match the actual CPU that the application is
486 running on if there's an emulation layer or if the CPU supports multiple
487 architectures (like x86-64 processors supporting i386 applications). To
488 detect that, use currentCpuArchitecture().
489
490 Values returned by this function are stable and will not change over time,
491 so applications can rely on the returned value as an identifier, except
492 that new CPU types may be added over time.
493
494 Typical returned values are (note: list not exhaustive):
495 \list
496 \li "arm"
497 \li "arm64"
498 \li "i386"
499 \li "ia64"
500 \li "mips"
501 \li "mips64"
502 \li "power"
503 \li "power64"
504 \li "sparc"
505 \li "sparcv9"
506 \li "x86_64"
507 \endlist
508
509 \sa QSysInfo::buildAbi(), QSysInfo::currentCpuArchitecture()
510*/
511QString QSysInfo::buildCpuArchitecture()
512{
513 return QStringLiteral(ARCH_PROCESSOR);
514}
515
516/*!
517 \since 5.4
518
519 Returns the architecture of the CPU that the application is running on, in
520 text format. Note that this function depends on what the OS will report and
521 may not detect the actual CPU architecture if the OS hides that information
522 or is unable to provide it. For example, a 32-bit OS running on a 64-bit
523 CPU is usually unable to determine the CPU is actually capable of running
524 64-bit programs.
525
526 Values returned by this function are mostly stable: an attempt will be made
527 to ensure that they stay constant over time and match the values returned
528 by buildCpuArchitecture(). However, due to the nature of the
529 operating system functions being used, there may be discrepancies.
530
531 Typical returned values are (note: list not exhaustive):
532 \list
533 \li "arm"
534 \li "arm64"
535 \li "i386"
536 \li "ia64"
537 \li "mips"
538 \li "mips64"
539 \li "power"
540 \li "power64"
541 \li "sparc"
542 \li "sparcv9"
543 \li "x86_64"
544 \endlist
545
546 \sa QSysInfo::buildAbi(), QSysInfo::buildCpuArchitecture()
547*/
548QString QSysInfo::currentCpuArchitecture()
549{
550#if defined(Q_OS_WIN)
551 // We don't need to catch all the CPU architectures in this function;
552 // only those where the host CPU might be different than the build target
553 // (usually, 64-bit platforms).
554 SYSTEM_INFO info;
555 GetNativeSystemInfo(&info);
556 switch (info.wProcessorArchitecture) {
557# ifdef PROCESSOR_ARCHITECTURE_AMD64
558 case PROCESSOR_ARCHITECTURE_AMD64:
559 return QStringLiteral("x86_64");
560# endif
561# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
562 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
563# endif
564 case PROCESSOR_ARCHITECTURE_IA64:
565 return QStringLiteral("ia64");
566 }
567#elif defined(Q_OS_DARWIN) && !defined(Q_OS_MACOS)
568 // iOS-based OSes do not return the architecture on uname(2)'s result.
569 return buildCpuArchitecture();
570#elif defined(Q_OS_UNIX)
571 long ret = -1;
572 struct utsname u;
573
574# if defined(Q_OS_SOLARIS)
575 // We need a special call for Solaris because uname(2) on x86 returns "i86pc" for
576 // both 32- and 64-bit CPUs. Reference:
577 // http://docs.oracle.com/cd/E18752_01/html/816-5167/sysinfo-2.html#REFMAN2sysinfo-2
578 // http://fxr.watson.org/fxr/source/common/syscall/systeminfo.c?v=OPENSOLARIS
579 // http://fxr.watson.org/fxr/source/common/conf/param.c?v=OPENSOLARIS;im=10#L530
580 if (ret == -1)
581 ret = sysinfo(SI_ARCHITECTURE_64, u.machine, sizeof u.machine);
582# endif
583
584 if (ret == -1)
585 ret = uname(&u);
586
587 // we could use detectUnixVersion() above, but we only need a field no other function does
588 if (ret != -1) {
589 // the use of QT_BUILD_INTERNAL here is simply to ensure all branches build
590 // as we don't often build on some of the less common platforms
591# if defined(Q_PROCESSOR_ARM) || defined(QT_BUILD_INTERNAL)
592 if (strcmp(u.machine, "aarch64") == 0)
593 return QStringLiteral("arm64");
594 if (strncmp(u.machine, "armv", 4) == 0)
595 return QStringLiteral("arm");
596# endif
597# if defined(Q_PROCESSOR_POWER) || defined(QT_BUILD_INTERNAL)
598 // harmonize "powerpc" and "ppc" to "power"
599 if (strncmp(u.machine, "ppc", 3) == 0)
600 return "power"_L1 + QLatin1StringView(u.machine + 3);
601 if (strncmp(u.machine, "powerpc", 7) == 0)
602 return "power"_L1 + QLatin1StringView(u.machine + 7);
603 if (strcmp(u.machine, "Power Macintosh") == 0)
604 return "power"_L1;
605# endif
606# if defined(Q_PROCESSOR_SPARC) || defined(QT_BUILD_INTERNAL)
607 // Solaris sysinfo(2) (above) uses "sparcv9", but uname -m says "sun4u";
608 // Linux says "sparc64"
609 if (strcmp(u.machine, "sun4u") == 0 || strcmp(u.machine, "sparc64") == 0)
610 return QStringLiteral("sparcv9");
611 if (strcmp(u.machine, "sparc32") == 0)
612 return QStringLiteral("sparc");
613# endif
614# if defined(Q_PROCESSOR_X86) || defined(QT_BUILD_INTERNAL)
615 // harmonize all "i?86" to "i386"
616 if (strlen(u.machine) == 4 && u.machine[0] == 'i'
617 && u.machine[2] == '8' && u.machine[3] == '6')
618 return QStringLiteral("i386");
619 if (strcmp(u.machine, "amd64") == 0) // Solaris
620 return QStringLiteral("x86_64");
621# endif
622 return QString::fromLatin1(u.machine);
623 }
624#endif
625 return buildCpuArchitecture();
626}
627
628/*!
629 \since 5.4
630
631 Returns the full architecture string that Qt was compiled for. This string
632 is useful for identifying different, incompatible builds. For example, it
633 can be used as an identifier to request an upgrade package from a server.
634
635 The values returned from this function are kept stable as follows: the
636 mandatory components of the result will not change in future versions of
637 Qt, but optional suffixes may be added.
638
639 The returned value is composed of three or more parts, separated by dashes
640 ("-"). They are:
641
642 \table
643 \header \li Component \li Value
644 \row \li CPU Architecture \li The same as QSysInfo::buildCpuArchitecture(), such as "arm", "i386", "mips" or "x86_64"
645 \row \li Endianness \li "little_endian" or "big_endian"
646 \row \li Word size \li Whether it's a 32- or 64-bit application. Possible values are:
647 "llp64" (Windows 64-bit), "lp64" (Unix 64-bit), "ilp32" (32-bit)
648 \row \li (Optional) ABI \li Zero or more components identifying different ABIs possible in this architecture.
649 Currently, Qt has optional ABI components for ARM and MIPS processors: one
650 component is the main ABI (such as "eabi", "o32", "n32", "o64"); another is
651 whether the calling convention is using hardware floating point registers ("hardfloat"
652 is present).
653
654 Additionally, if Qt was configured with \c{-qreal float}, the ABI option tag "qreal_float"
655 will be present. If Qt was configured with another type as qreal, that type is present after
656 "qreal_", with all characters other than letters and digits escaped by an underscore, followed
657 by two hex digits. For example, \c{-qreal long double} becomes "qreal_long_20double".
658 \endtable
659
660 \sa QSysInfo::buildCpuArchitecture()
661*/
662QString QSysInfo::buildAbi()
663{
664 // ARCH_FULL is a concatenation of strings (incl. ARCH_PROCESSOR), which breaks
665 // QStringLiteral on MSVC. Since the concatenation behavior we want is specified
666 // the same C++11 paper as the Unicode strings, we'll use that macro and hope
667 // that Microsoft implements the new behavior when they add support for Unicode strings.
668 return QStringLiteral(ARCH_FULL);
669}
670
671static QString unknownText()
672{
673 return QStringLiteral("unknown");
674}
675
676/*!
677 \since 5.4
678
679 Returns the type of the operating system kernel Qt was compiled for. It's
680 also the kernel the application is running on, unless the host operating
681 system is running a form of compatibility or virtualization layer.
682
683 Values returned by this function are stable and will not change over time,
684 so applications can rely on the returned value as an identifier, except
685 that new OS kernel types may be added over time.
686
687 On Windows, this function returns the type of Windows kernel, like "winnt".
688 On Unix systems, it returns the same as the output of \c{uname
689 -s} (lowercased).
690
691 \note This function may return surprising values: it returns "linux"
692 for all operating systems running Linux (including Android), "qnx" for all
693 operating systems running QNX, "freebsd" for
694 Debian/kFreeBSD, and "darwin" for \macos and iOS. For information on the type
695 of product the application is running on, see productType().
696
697 \sa QFileSelector, kernelVersion(), productType(), productVersion(), prettyProductName()
698*/
699QString QSysInfo::kernelType()
700{
701#if defined(Q_OS_WIN)
702 return QStringLiteral("winnt");
703#elif defined(Q_OS_UNIX)
704 struct utsname u;
705 if (uname(&u) == 0)
706 return QString::fromLatin1(u.sysname).toLower();
707#endif
708 return unknownText();
709}
710
711/*!
712 \since 5.4
713
714 Returns the release version of the operating system kernel. On Windows, it
715 returns the version of the NT kernel. On Unix systems, including
716 Android and \macos, it returns the same as the \c{uname -r}
717 command would return. On VxWorks, it returns the numeric part of the string
718 reported by kernelVersion().
719
720 If the version could not be determined, this function may return an empty
721 string.
722
723 \sa kernelType(), productType(), productVersion(), prettyProductName()
724*/
725QString QSysInfo::kernelVersion()
726{
727#ifdef Q_OS_WIN
728 const auto osver = QOperatingSystemVersion::current();
729 return QString::asprintf("%d.%d.%d",
730 osver.majorVersion(), osver.minorVersion(), osver.microVersion());
731#else
732 struct utsname u;
733 if (uname(&u) == 0) {
734# ifdef Q_OS_VXWORKS
735 // The string follows the pattern "Core Kernel version: w.x.y.z"
736 auto versionStr = QByteArrayView(u.kernelversion);
737 if (auto lastSpace = versionStr.lastIndexOf(' '); lastSpace != -1) {
738 return QString::fromLatin1(versionStr.sliced(lastSpace + 1));
739 }
740# else
741 return QString::fromLatin1(u.release);
742# endif
743 }
744 return QString();
745#endif
746}
747
748
749/*!
750 \since 5.4
751
752 Returns the product name of the operating system this application is
753 running in. If the application is running on some sort of emulation or
754 virtualization layer (such as WINE on a Unix system), this function will
755 inspect the emulation / virtualization layer.
756
757 Values returned by this function are stable and will not change over time,
758 so applications can rely on the returned value as an identifier, except
759 that new OS types may be added over time.
760
761 \b{Linux and Android note}: this function returns "android" for Linux
762 systems running Android userspace, notably when using the Bionic library.
763 For all other Linux systems, regardless of C library being used, it tries
764 to determine the distribution name and returns that. If determining the
765 distribution name failed, it returns "unknown".
766
767 \b{\macos note}: this function returns "macos" for all \macos systems,
768 regardless of Apple naming convention. Previously, in Qt 5, it returned
769 "osx", again regardless of Apple naming conventions.
770
771 \b{Darwin, iOS, tvOS, and watchOS note}: this function returns "ios" for
772 iOS systems, "tvos" for tvOS systems, "watchos" for watchOS systems, and
773 "darwin" in case the system could not be determined.
774
775 \b{FreeBSD note}: this function returns "debian" for Debian/kFreeBSD and
776 "unknown" otherwise.
777
778 \b{Windows note}: this function return "windows"
779
780 \b{VxWorks note}: this function return "vxworks"
781
782 For other Unix-type systems, this function usually returns "unknown".
783
784 \sa QFileSelector, kernelType(), kernelVersion(), productVersion(), prettyProductName()
785*/
786QString QSysInfo::productType()
787{
788 // similar, but not identical to QFileSelectorPrivate::platformSelectors
789#if defined(Q_OS_WIN)
790 return QStringLiteral("windows");
791
792#elif defined(Q_OS_QNX)
793 return QStringLiteral("qnx");
794
795#elif defined(Q_OS_ANDROID)
796 return QStringLiteral("android");
797
798#elif defined(Q_OS_OHOS)
799 return QStringLiteral("ohos");
800#elif defined(Q_OS_IOS)
801 return QStringLiteral("ios");
802#elif defined(Q_OS_TVOS)
803 return QStringLiteral("tvos");
804#elif defined(Q_OS_WATCHOS)
805 return QStringLiteral("watchos");
806#elif defined(Q_OS_VISIONOS)
807 return QStringLiteral("visionos");
808#elif defined(Q_OS_MACOS)
809 return QStringLiteral("macos");
810#elif defined(Q_OS_DARWIN)
811 return QStringLiteral("darwin");
812#elif defined(Q_OS_WASM)
813 return QStringLiteral("wasm");
814#elif defined(Q_OS_VXWORKS)
815 return QStringLiteral("vxworks");
816
817#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
818 QUnixOSVersion unixOsVersion;
819 findUnixOsVersion(unixOsVersion);
820 if (!unixOsVersion.productType.isEmpty())
821 return unixOsVersion.productType;
822#endif
823 return unknownText();
824}
825
826/*!
827 \since 5.4
828
829 Returns the product version of the operating system in string form. If the
830 version could not be determined, this function returns "unknown".
831
832 It will return the Android, iOS, \macos, VxWorks, Windows full-product
833 versions on those systems.
834
835 Typical returned values are (note: list not exhaustive):
836 \list
837 \li "12" (Android 12)
838 \li "36" (Fedora 36)
839 \li "15.5" (iOS 15.5)
840 \li "12.4" (macOS Monterey)
841 \li "22.04" (Ubuntu 22.04)
842 \li "8.6" (watchOS 8.6)
843 \li "11" (Windows 11)
844 \li "Server 2022" (Windows Server 2022)
845 \li "24.03" (VxWorks 7 - 24.03)
846 \endlist
847
848 On Linux systems, it will try to determine the distribution version and will
849 return that. This is also done on Debian/kFreeBSD, so this function will
850 return Debian version in that case.
851
852 In all other Unix-type systems, this function always returns "unknown".
853
854 \note The version string returned from this function is not guaranteed to
855 be orderable. On Linux, the version of
856 the distribution may jump unexpectedly, please refer to the distribution's
857 documentation for versioning practices.
858
859 \sa kernelType(), kernelVersion(), productType(), prettyProductName()
860*/
861QString QSysInfo::productVersion()
862{
863#if defined(Q_OS_ANDROID)
864 const auto version = QOperatingSystemVersion::current();
865 return QString::asprintf("%d.%d", version.majorVersion(), version.minorVersion());
866#elif defined(Q_OS_DARWIN) || defined(Q_OS_OHOS)
867 const auto version = QOperatingSystemVersion::current();
868 return QString::asprintf("%d.%d.%d", version.majorVersion(),
869 version.minorVersion(),
870 version.microVersion());
871#elif defined(Q_OS_WIN)
872 const char *version = osVer_helper();
873 if (version) {
874 const QLatin1Char spaceChar(' ');
875 return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower();
876 }
877 // fall through
878
879#elif defined(Q_OS_VXWORKS)
880 utsname u;
881 if (uname(&u) == 0)
882 return QString::fromLatin1(u.releaseversion);
883 // fall through
884
885#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
886 QUnixOSVersion unixOsVersion;
887 findUnixOsVersion(unixOsVersion);
888 if (!unixOsVersion.productVersion.isEmpty())
889 return unixOsVersion.productVersion;
890#endif
891
892 // fallback
893 return unknownText();
894}
895
896/*!
897 \since 5.4
898
899 Returns a prettier form of productType() and productVersion(), containing
900 other tokens like the operating system type, codenames and other
901 information. The result of this function is suitable for displaying to the
902 user, but not for long-term storage, as the string may change with updates
903 to Qt.
904
905 If productType() is "unknown", this function will instead use the
906 kernelType() and kernelVersion() functions.
907
908 \sa kernelType(), kernelVersion(), productType(), productVersion()
909*/
910QString QSysInfo::prettyProductName()
911{
912#if defined(Q_OS_ANDROID) || defined(Q_OS_DARWIN) || defined(Q_OS_WIN)
913 const auto version = QOperatingSystemVersion::current();
914 QString versionString;
915# if defined(Q_OS_DARWIN)
916 if (const int microVersion = version.microVersion(); microVersion > 0)
917 versionString = QString::asprintf("%d.%d.%d", version.majorVersion(),
918 version.minorVersion(),
919 microVersion);
920 else
921# endif // Darwin
922 versionString = QString::asprintf("%d.%d", version.majorVersion(),
923 version.minorVersion());
924 QString result = version.name() + u' ';
925 const char *name = osVer_helper(version);
926 if (!name)
927 return result + versionString;
928 result += QLatin1StringView(name);
929# if !defined(Q_OS_WIN)
930 return result + " ("_L1 + versionString + u')';
931# else
932 // (resembling winver.exe): Windows 10 "Windows 10 Version 1809"
933 const auto displayVersion = windowsDisplayVersion();
934 if (!displayVersion.isEmpty())
935 result += " Version "_L1 + displayVersion;
936 return result;
937# endif // Windows
938#elif defined(Q_OS_OHOS)
939 QString result = QString::asprintf("%s %s", OH_GetOSFullName(),
940 OH_GetDistributionOSReleaseType());
941 return result;
942#elif defined(Q_OS_HAIKU)
943 return "Haiku "_L1 + productVersion();
944#elif defined(Q_OS_UNIX)
945# ifdef USE_ETC_OS_RELEASE
946 QUnixOSVersion unixOsVersion;
947 findUnixOsVersion(unixOsVersion);
948 if (!unixOsVersion.prettyName.isEmpty())
949 return unixOsVersion.prettyName;
950# endif
951 struct utsname u;
952 if (uname(&u) == 0)
953 return QString::fromLatin1(u.sysname) + u' ' + QString::fromLatin1(u.release);
954#endif
955 return unknownText();
956}
957
958#ifndef QT_BOOTSTRAPPED
959/*!
960 \since 5.6
961
962 Returns this machine's host name, if one is configured. Note that hostnames
963 are not guaranteed to be globally unique, especially if they were
964 configured automatically.
965
966 This function does not guarantee the returned host name is a Fully
967 Qualified Domain Name (FQDN). For that, use QHostInfo to resolve the
968 returned name to an FQDN.
969
970 This function returns the same as QHostInfo::localHostName().
971
972 \sa QHostInfo::localDomainName, machineUniqueId()
973*/
974QString QSysInfo::machineHostName()
975{
976 // the hostname can change, so we can't cache it
977#if defined(Q_OS_LINUX)
978 // gethostname(3) on Linux just calls uname(2), so do it ourselves
979 // and avoid a memcpy
980 struct utsname u;
981 if (uname(&u) == 0)
982 return QString::fromLocal8Bit(u.nodename);
983 return QString();
984#else
985# ifdef Q_OS_WIN
986 // Important: QtNetwork depends on machineHostName() initializing ws2_32.dll
987 winsockInit();
988 QString hostName;
989 hostName.resize(512);
990 unsigned long len = hostName.size();
991 BOOL res = GetComputerNameEx(ComputerNameDnsHostname,
992 reinterpret_cast<wchar_t *>(hostName.data()), &len);
993 if (!res && len > 512) {
994 hostName.resize(len - 1);
995 GetComputerNameEx(ComputerNameDnsHostname, reinterpret_cast<wchar_t *>(hostName.data()),
996 &len);
997 }
998 hostName.truncate(len);
999 return hostName;
1000# else // !Q_OS_WIN
1001
1002 char hostName[512];
1003 if (gethostname(hostName, sizeof(hostName)) == -1)
1004 return QString();
1005 hostName[sizeof(hostName) - 1] = '\0';
1006 return QString::fromLocal8Bit(hostName);
1007# endif
1008#endif
1009}
1010#endif // QT_BOOTSTRAPPED
1011
1012enum {
1013 UuidStringLen = sizeof("00000000-0000-0000-0000-000000000000") - 1
1014};
1015
1016/*!
1017 \since 5.11
1018
1019 Returns a unique ID for this machine, if one can be determined. If no
1020 unique ID could be determined, this function returns an empty byte array.
1021 Unlike machineHostName(), the value returned by this function is likely
1022 globally unique.
1023
1024 A unique ID is useful in network operations to identify this machine for an
1025 extended period of time, when the IP address could change or if this
1026 machine could have more than one IP address. For example, the ID could be
1027 used when communicating with a server or when storing device-specific data
1028 in shared network storage.
1029
1030 Note that on some systems, this value will persist across reboots and on
1031 some it will not. Applications should not blindly depend on this fact
1032 without verifying the OS capabilities. In particular, on Linux systems,
1033 this ID is usually permanent and it matches the D-Bus machine ID, except
1034 for nodes without their own storage (replicated nodes).
1035
1036 \sa machineHostName(), bootUniqueId()
1037*/
1038QByteArray QSysInfo::machineUniqueId()
1039{
1040#if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
1041 char uuid[UuidStringLen + 1];
1042 io_service_t service = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
1043 QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
1044 CFStringGetCString(stringRef, uuid, sizeof(uuid), kCFStringEncodingMacRoman);
1045 return QByteArray(uuid);
1046#elif defined(Q_OS_BSD4) && defined(KERN_HOSTUUID)
1047 char uuid[UuidStringLen + 1];
1048 size_t uuidlen = sizeof(uuid);
1049 int name[] = { CTL_KERN, KERN_HOSTUUID };
1050 if (sysctl(name, sizeof name / sizeof name[0], &uuid, &uuidlen, nullptr, 0) == 0
1051 && uuidlen == sizeof(uuid))
1052 return QByteArray(uuid, uuidlen - 1);
1053#elif defined(Q_OS_UNIX)
1054 // The modern name on Linux is /etc/machine-id, but that path is
1055 // unlikely to exist on non-Linux (non-systemd) systems. The old
1056 // path is more than enough.
1057 static const char fullfilename[] = "/usr/local/var/lib/dbus/machine-id";
1058 const char *firstfilename = fullfilename + sizeof("/usr/local") - 1;
1059 int fd = qt_safe_open(firstfilename, O_RDONLY);
1060 if (fd == -1 && errno == ENOENT)
1061 fd = qt_safe_open(fullfilename, O_RDONLY);
1062
1063 if (fd != -1) {
1064 char buffer[32]; // 128 bits, hex-encoded
1065 qint64 len = qt_safe_read(fd, buffer, sizeof(buffer));
1066 qt_safe_close(fd);
1067
1068 if (len != -1)
1069 return QByteArray(buffer, len);
1070 }
1071#elif defined(Q_OS_WIN)
1072 // Let's poke at the registry
1073 const QString machineGuid = QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Cryptography)")
1074 .stringValue(L"MachineGuid");
1075 if (!machineGuid.isEmpty())
1076 return machineGuid.toLatin1();
1077#endif
1078 return QByteArray();
1079}
1080
1081/*!
1082 \since 5.11
1083
1084 Returns a unique ID for this machine's boot, if one can be determined. If
1085 no unique ID could be determined, this function returns an empty byte
1086 array. This value is expected to change after every boot and can be
1087 considered globally unique.
1088
1089 This function is currently only implemented for Linux and Apple operating
1090 systems.
1091
1092 \sa machineUniqueId()
1093*/
1094QByteArray QSysInfo::bootUniqueId()
1095{
1096#ifdef Q_OS_LINUX
1097 // use low-level API here for simplicity
1098 int fd = qt_safe_open("/proc/sys/kernel/random/boot_id", O_RDONLY);
1099 if (fd != -1) {
1100 char uuid[UuidStringLen];
1101 qint64 len = qt_safe_read(fd, uuid, sizeof(uuid));
1102 qt_safe_close(fd);
1103 if (len == UuidStringLen)
1104 return QByteArray(uuid, UuidStringLen);
1105 }
1106#elif defined(Q_OS_DARWIN)
1107 // "kern.bootsessionuuid" is only available by name
1108 char uuid[UuidStringLen + 1];
1109 size_t uuidlen = sizeof(uuid);
1110 if (sysctlbyname("kern.bootsessionuuid", uuid, &uuidlen, nullptr, 0) == 0
1111 && uuidlen == sizeof(uuid))
1112 return QByteArray(uuid, uuidlen - 1);
1113#endif
1114 return QByteArray();
1115};
1116
1117QT_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:671