7#include <QtCore/qbytearray.h>
8#include <QtCore/qoperatingsystemversion.h>
9#include <QtCore/qstring.h>
11#include <private/qoperatingsystemversion_p.h>
14# include <sys/utsname.h>
15# include <private/qcore_unix_p.h>
19#include <QtCore/private/qjnihelpers_p.h>
20#include <qjniobject.h>
23#if defined(Q_OS_SOLARIS)
24# include <sys/systeminfo.h>
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>
36# include <sys/sysctl.h>
40# include "qoperatingsystemversion_win_p.h"
41# include "private/qwinregistry_p.h"
42# include "qt_windows.h"
49using namespace Qt::StringLiterals;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
71
72
73
74
75
76
77
78
81
82
83
84
85
86
87
89#if defined(Q_OS_DARWIN)
91static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
94 switch (version.majorVersion()) {
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";
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";
125#elif defined(Q_OS_WIN)
127# ifndef QT_BOOTSTRAPPED
128class QWindowsSockInit
136QWindowsSockInit::QWindowsSockInit()
141 if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {
142 qWarning(
"QTcpSocketAPI: WinSock v2.2 initialization failed.");
148QWindowsSockInit::~QWindowsSockInit()
152Q_GLOBAL_STATIC(QWindowsSockInit, winsockInit)
155static QString readVersionRegistryString(
const wchar_t *subKey)
157 return QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)")
158 .stringValue(subKey);
161static inline QString windowsDisplayVersion()
165 if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::Windows10_20H2)
166 return readVersionRegistryString(L"DisplayVersion");
168 return readVersionRegistryString(L"ReleaseId");
171static QString winSp_helper()
173 const auto osv = qWindowsVersionInfo();
174 const qint16 major = osv.wServicePackMajor;
176 QString sp = QStringLiteral(
"SP ") + QString::number(major);
177 const qint16 minor = osv.wServicePackMinor;
179 sp += u'.' + QString::number(minor);
186static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
189 const OSVERSIONINFOEX osver = qWindowsVersionInfo();
190 const bool workstation = osver.wProductType == VER_NT_WORKSTATION;
192#define Q_WINVER(major, minor) (major << 8
| minor)
193 switch (Q_WINVER(osver.dwMajorVersion, osver.dwMinorVersion)) {
194 case Q_WINVER(10, 0):
196 if (osver.dwBuildNumber >= 22000)
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";
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
222 QString productVersion;
226static QString unquote(QByteArrayView str)
237 if (str.size() >= 2 && str.front() ==
'"' && str.back() ==
'"')
238 str = str.sliced(1).chopped(1);
239 return QString::fromUtf8(str);
242static QByteArray getEtcFileContent(
const char *filename)
245 int fd = qt_safe_open(filename, O_RDONLY);
250 if (QT_FSTAT(fd, &sbuf) == -1) {
255 QByteArray buffer(sbuf.st_size, Qt::Uninitialized);
256 buffer.resize(qt_safe_read(fd, buffer.data(), sbuf.st_size));
261static bool readEtcFile(QUnixOSVersion &v,
const char *filename,
262 const QByteArray &idKey,
const QByteArray &versionKey,
const QByteArray &prettyNameKey)
265 QByteArray buffer = getEtcFileContent(filename);
266 if (buffer.isEmpty())
269 const char *ptr = buffer.constData();
270 const char *end = buffer.constEnd();
273 for (; ptr != end; ptr = eol + 1) {
275 eol =
static_cast<
const char *>(memchr(ptr,
'\n', end - ptr));
278 line.setRawData(ptr, eol - ptr);
280 if (line.startsWith(idKey)) {
282 v.productType = unquote({ptr, eol});
286 if (line.startsWith(prettyNameKey)) {
287 ptr += prettyNameKey.size();
288 v.prettyName = unquote({ptr, eol});
292 if (line.startsWith(versionKey)) {
293 ptr += versionKey.size();
294 v.productVersion = unquote({ptr, eol});
302static bool readOsRelease(QUnixOSVersion &v)
304 QByteArray id = QByteArrayLiteral(
"ID=");
305 QByteArray versionId = QByteArrayLiteral(
"VERSION_ID=");
306 QByteArray prettyName = QByteArrayLiteral(
"PRETTY_NAME=");
313 return readEtcFile(v,
"/etc/os-release", id, versionId, prettyName) ||
314 readEtcFile(v,
"/usr/lib/os-release", id, versionId, prettyName);
317static bool readEtcLsbRelease(QUnixOSVersion &v)
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)) {
326 QByteArray distrorelease =
"/etc/" + v.productType.toLatin1().toLower() +
"-release";
327 int fd = qt_safe_open(distrorelease, O_RDONLY);
330 if (QT_FSTAT(fd, &sbuf) != -1 && sbuf.st_size > v.prettyName.size()) {
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());
344 return ok && !(v.productType.isEmpty() && v.productVersion.isEmpty());
347#if defined(Q_OS_LINUX)
348static QByteArray getEtcFileFirstLine(
const char *fileName)
350 QByteArray buffer = getEtcFileContent(fileName);
351 if (buffer.isEmpty())
354 const char *ptr = buffer.constData();
355 return QByteArray(ptr, buffer.indexOf(
"\n")).trimmed();
358static bool readEtcRedHatRelease(QUnixOSVersion &v)
363 QByteArray line = getEtcFileFirstLine(
"/etc/redhat-release");
367 v.prettyName = QString::fromLatin1(line);
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));
378static bool readEtcDebianVersion(QUnixOSVersion &v)
383 QByteArray line = getEtcFileFirstLine(
"/etc/debian_version");
387 v.productType = QStringLiteral(
"Debian");
388 v.productVersion = QString::fromLatin1(line);
393static bool findUnixOsVersion(QUnixOSVersion &v)
395 if (readOsRelease(v))
397 if (readEtcLsbRelease(v))
399#if defined(Q_OS_LINUX)
400 if (readEtcRedHatRelease(v))
402 if (readEtcDebianVersion(v))
411static const char *osVer_helper(QOperatingSystemVersion)
415 const int sdk_int = QtAndroidPrivate::androidSdkVersion();
429 return "Gingerbread";
436 return "Ice Cream Sandwich";
448 return "Marshmallow";
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505QString QSysInfo::buildCpuArchitecture()
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542QString QSysInfo::currentCpuArchitecture()
549 GetNativeSystemInfo(&info);
550 switch (info.wProcessorArchitecture) {
551# ifdef PROCESSOR_ARCHITECTURE_AMD64
552 case PROCESSOR_ARCHITECTURE_AMD64:
553 return QStringLiteral(
"x86_64");
555# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
556 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
558 case PROCESSOR_ARCHITECTURE_IA64:
559 return QStringLiteral(
"ia64");
561#elif defined(Q_OS_DARWIN) && !defined(Q_OS_MACOS)
563 return buildCpuArchitecture();
564#elif defined(Q_OS_UNIX)
568# if defined(Q_OS_SOLARIS)
575 ret = sysinfo(SI_ARCHITECTURE_64, u.machine,
sizeof u.machine);
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");
591# if defined(Q_PROCESSOR_POWER) || defined(QT_BUILD_INTERNAL)
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)
600# if defined(Q_PROCESSOR_SPARC) || defined(QT_BUILD_INTERNAL)
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");
608# if defined(Q_PROCESSOR_X86) || defined(QT_BUILD_INTERNAL)
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)
614 return QStringLiteral(
"x86_64");
616 return QString::fromLatin1(u.machine);
619 return buildCpuArchitecture();
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656QString QSysInfo::buildAbi()
667 return QStringLiteral(
"unknown");
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693QString QSysInfo::kernelType()
696 return QStringLiteral(
"winnt");
697#elif defined(Q_OS_UNIX)
700 return QString::fromLatin1(u.sysname).toLower();
702 return unknownText();
706
707
708
709
710
711
712
713
714
715
716
717
718
719QString QSysInfo::kernelVersion()
722 const auto osver = QOperatingSystemVersion::current();
723 return QString::asprintf(
"%d.%d.%d",
724 osver.majorVersion(), osver.minorVersion(), osver.microVersion());
727 if (uname(&u) == 0) {
730 auto versionStr = QByteArrayView(u.kernelversion);
731 if (
auto lastSpace = versionStr.lastIndexOf(
' '); lastSpace != -1) {
732 return QString::fromLatin1(versionStr.sliced(lastSpace + 1));
735 return QString::fromLatin1(u.release);
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780QString QSysInfo::productType()
784 return QStringLiteral(
"windows");
786#elif defined(Q_OS_QNX)
787 return QStringLiteral(
"qnx");
789#elif defined(Q_OS_ANDROID)
790 return QStringLiteral(
"android");
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");
809#elif defined(USE_ETC_OS_RELEASE)
810 QUnixOSVersion unixOsVersion;
811 findUnixOsVersion(unixOsVersion);
812 if (!unixOsVersion.productType.isEmpty())
813 return unixOsVersion.productType;
815 return unknownText();
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853QString QSysInfo::productVersion()
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();
866 const QLatin1Char spaceChar(
' ');
867 return QString::fromLatin1(version).remove(spaceChar).toLower() + winSp_helper().remove(spaceChar).toLower();
871#elif defined(Q_OS_VXWORKS)
874 return QString::fromLatin1(u.releaseversion);
877#elif defined(USE_ETC_OS_RELEASE)
878 QUnixOSVersion unixOsVersion;
879 findUnixOsVersion(unixOsVersion);
880 if (!unixOsVersion.productVersion.isEmpty())
881 return unixOsVersion.productVersion;
885 return unknownText();
889
890
891
892
893
894
895
896
897
898
899
900
901
902QString QSysInfo::prettyProductName()
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(),
914 versionString = QString::asprintf(
"%d.%d", version.majorVersion(),
915 version.minorVersion());
916 QString result = version.name() + u' ';
917 const char *name = osVer_helper(version);
919 return result + versionString;
920 result += QLatin1StringView(name);
921# if !defined(Q_OS_WIN)
922 return result +
" ("_L1 + versionString + u')';
925 const auto displayVersion = windowsDisplayVersion();
926 if (!displayVersion.isEmpty())
927 result +=
" Version "_L1 + displayVersion;
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;
941 return QString::fromLatin1(u.sysname) + u' ' + QString::fromLatin1(u.release);
943 return unknownText();
946#ifndef QT_BOOTSTRAPPED
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962QString QSysInfo::machineHostName()
965#if defined(Q_OS_LINUX)
970 return QString::fromLocal8Bit(u.nodename);
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()),
986 hostName.truncate(len);
991 if (gethostname(hostName,
sizeof(hostName)) == -1)
993 hostName[
sizeof(hostName) - 1] =
'\0';
994 return QString::fromLocal8Bit(hostName);
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026QByteArray QSysInfo::machineUniqueId()
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)
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);
1053 qint64 len = qt_safe_read(fd, buffer,
sizeof(buffer));
1057 return QByteArray(buffer, len);
1059#elif defined(Q_OS_WIN)
1061 const QString machineGuid = QWinRegistryKey(HKEY_LOCAL_MACHINE, LR"(SOFTWARE\Microsoft\Cryptography)")
1062 .stringValue(L"MachineGuid");
1063 if (!machineGuid.isEmpty())
1064 return machineGuid.toLatin1();
1066 return QByteArray();
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082QByteArray QSysInfo::bootUniqueId()
1086 int fd = qt_safe_open(
"/proc/sys/kernel/random/boot_id", O_RDONLY);
1088 char uuid[UuidStringLen];
1089 qint64 len = qt_safe_read(fd, uuid,
sizeof(uuid));
1091 if (len == UuidStringLen)
1092 return QByteArray(uuid, UuidStringLen);
1094#elif defined(Q_OS_DARWIN)
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);
1102 return QByteArray();
static QString unknownText()