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