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