diff options
Diffstat (limited to 'subsurfacesysinfo.cpp')
-rw-r--r-- | subsurfacesysinfo.cpp | 443 |
1 files changed, 278 insertions, 165 deletions
diff --git a/subsurfacesysinfo.cpp b/subsurfacesysinfo.cpp index 4a55e7315..58301b0c8 100644 --- a/subsurfacesysinfo.cpp +++ b/subsurfacesysinfo.cpp @@ -42,16 +42,19 @@ #include "subsurfacesysinfo.h" #include <QString> -#include <QFile> -#include <QSettings> -#include <QTextStream> + +#ifdef Q_OS_UNIX +#include <sys/utsname.h> +#endif + +#if QT_VERSION < QT_VERSION_CHECK(5, 4, 0) #ifndef QStringLiteral # define QStringLiteral QString::fromUtf8 #endif #ifdef Q_OS_UNIX -#include <sys/utsname.h> +#include <qplatformdefs.h> #endif #ifdef __APPLE__ @@ -132,6 +135,7 @@ #define ARCH_FULL ARCH_PROCESSOR "-" ARCH_ENDIANNESS "-" ARCH_POINTER ARCH_ABI // --- end of archdetect.cpp --- +// copied from Qt 5.4.1's src/corelib/global/qglobal.cpp #if defined(Q_OS_WIN) || defined(Q_OS_CYGWIN) || defined(Q_OS_WINCE) || defined(Q_OS_WINRT) @@ -140,33 +144,50 @@ QT_BEGIN_INCLUDE_NAMESPACE QT_END_INCLUDE_NAMESPACE #ifndef Q_OS_WINRT +# ifndef Q_OS_WINCE +// Fallback for determining Windows versions >= 8 by looping using the +// version check macros. Note that it will return build number=0 to avoid +// inefficient looping. +static inline void determineWinOsVersionFallbackPost8(OSVERSIONINFO *result) +{ + result->dwBuildNumber = 0; + DWORDLONG conditionMask = 0; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL); + OSVERSIONINFOEX checkVersion = { sizeof(OSVERSIONINFOEX), result->dwMajorVersion, 0, + result->dwBuildNumber, result->dwPlatformId, {'\0'}, 0, 0, 0, 0, 0 }; + for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMajorVersion) + result->dwMajorVersion = checkVersion.dwMajorVersion; + conditionMask = 0; + checkVersion.dwMajorVersion = result->dwMajorVersion; + checkVersion.dwMinorVersion = 0; + VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); + VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL); + for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMinorVersion) + result->dwMinorVersion = checkVersion.dwMinorVersion; +} + +# endif // !Q_OS_WINCE + static inline OSVERSIONINFO winOsVersion() { OSVERSIONINFO result = { sizeof(OSVERSIONINFO), 0, 0, 0, 0, {'\0'}}; // GetVersionEx() has been deprecated in Windows 8.1 and will return // only Windows 8 from that version on. -# if defined(_MSC_VER) && _MSC_VER >= 1800 -# pragma warning( push ) -# pragma warning( disable : 4996 ) -# endif +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# pragma warning( push ) +# pragma warning( disable : 4996 ) +# endif GetVersionEx(&result); -# if defined(_MSC_VER) && _MSC_VER >= 1800 -# pragma warning( pop ) -# endif -# ifndef Q_OS_WINCE - if (result.dwMajorVersion == 6 && result.dwMinorVersion == 2) { - // This could be Windows 8.1 or higher. Note that as of Windows 9, - // the major version needs to be checked as well. - DWORDLONG conditionMask = 0; - VER_SET_CONDITION(conditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); - VER_SET_CONDITION(conditionMask, VER_MINORVERSION, VER_GREATER_EQUAL); - VER_SET_CONDITION(conditionMask, VER_PLATFORMID, VER_EQUAL); - OSVERSIONINFOEX checkVersion = { sizeof(OSVERSIONINFOEX), result.dwMajorVersion, result.dwMinorVersion, - result.dwBuildNumber, result.dwPlatformId, {'\0'}, 0, 0, 0, 0, 0 }; - for ( ; VerifyVersionInfo(&checkVersion, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, conditionMask); ++checkVersion.dwMinorVersion) - result.dwMinorVersion = checkVersion.dwMinorVersion; - } -# endif // !Q_OS_WINCE +# if defined(_MSC_VER) && _MSC_VER >= 1800 +# pragma warning( pop ) +# endif +# ifndef Q_OS_WINCE + if (result.dwMajorVersion == 6 && result.dwMinorVersion == 2) { + determineWinOsVersionFallbackPost8(&result); + } +# endif // !Q_OS_WINCE return result; } #endif // !Q_OS_WINRT @@ -206,105 +227,217 @@ static const char *winVer_helper() #endif #if defined(Q_OS_UNIX) -# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD) -# define USE_ETC_OS_RELEASE -# endif +# if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD) +# define USE_ETC_OS_RELEASE struct QUnixOSVersion { - // from uname(2) - QString sysName; - QString sysNameLower; - QString sysRelease; - -# if !defined(Q_OS_ANDROID) && !defined(Q_OS_BLACKBERRY) && !defined(Q_OS_MAC) - // from /etc/os-release or guessed - QString versionIdentifier; // ${ID}_$VERSION_ID - QString versionText; // $PRETTY_NAME -# endif + // from /etc/os-release + QString productType; // $ID + QString productVersion; // $VERSION_ID + QString prettyName; // $PRETTY_NAME }; +static QString unquote(const char *begin, const char *end) +{ + if (*begin == '"') { + Q_ASSERT(end[-1] == '"'); + return QString::fromLatin1(begin + 1, end - begin - 2); + } + return QString::fromLatin1(begin, end - begin); +} -#ifdef USE_ETC_OS_RELEASE static bool readEtcOsRelease(QUnixOSVersion &v) { - QFile osRelease("/etc/os-release"); - if (osRelease.exists()) { - QSettings parse("/etc/os-release", QSettings::IniFormat); - if (parse.contains("PRETTY_NAME")) { - v.versionText = parse.value("PRETTY_NAME").toString(); - } - return true; + // we're avoiding QFile here + int fd = QT_OPEN("/etc/os-release", O_RDONLY); + if (fd == -1) + return false; + + QT_STATBUF sbuf; + if (QT_FSTAT(fd, &sbuf) == -1) { + QT_CLOSE(fd); + return false; } - QFile lsbRelease("/etc/lsb-release"); - if (lsbRelease.exists()) { - QSettings parse("/etc/lsb-release", QSettings::IniFormat); - if (parse.contains("DISTRIB_DESCRIPTION")) { - v.versionText = parse.value("DISTRIB_DESCRIPTION").toString(); - if (v.versionText == "PCLinuxOS") { - QFile release("/etc/release"); - if (release.exists()) { - if (release.open(QFile::ReadOnly | QFile::Text)) { - QTextStream in(&release); - v.versionText = in.readAll(); - // need to get rid of the redundant text after '(' - int i = v.versionText.indexOf('('); - v.versionText.remove(i, 1000); - } - } - } + + QByteArray buffer(sbuf.st_size, Qt::Uninitialized); + buffer.resize(QT_READ(fd, buffer.data(), sbuf.st_size)); + QT_CLOSE(fd); + + const char *ptr = buffer.constData(); + const char *end = buffer.constEnd(); + const char *eol; + for ( ; ptr != end; ptr = eol + 1) { + static const char idString[] = "ID="; + static const char prettyNameString[] = "PRETTY_NAME="; + static const char versionIdString[] = "VERSION_ID="; + + // find the end of the line after ptr + eol = static_cast<const char *>(memchr(ptr, '\n', end - ptr)); + if (!eol) + eol = end - 1; + + // note: we're doing a binary search here, so comparison + // must always be sorted + int cmp = strncmp(ptr, idString, strlen(idString)); + if (cmp < 0) + continue; + if (cmp == 0) { + ptr += strlen(idString); + v.productType = unquote(ptr, eol); + continue; + } + + cmp = strncmp(ptr, prettyNameString, strlen(prettyNameString)); + if (cmp < 0) + continue; + if (cmp == 0) { + ptr += strlen(prettyNameString); + v.prettyName = unquote(ptr, eol); + continue; + } + + cmp = strncmp(ptr, versionIdString, strlen(versionIdString)); + if (cmp < 0) + continue; + if (cmp == 0) { + ptr += strlen(versionIdString); + v.productVersion = unquote(ptr, eol); + continue; } - return true; } - return false; + + return true; } -#endif // USE_ETC_OS_RELEASE +# endif // USE_ETC_OS_RELEASE +#endif // Q_OS_UNIX -static QUnixOSVersion detectUnixVersion() +static QString unknownText() { - QUnixOSVersion v; - struct utsname u; - if (uname(&u) != -1) { - v.sysName = QString::fromLatin1(u.sysname); - v.sysNameLower = v.sysName.toLower(); - v.sysRelease = QString::fromLatin1(u.release); - } else { - v.sysName = QLatin1String("Detection failed"); - // leave sysNameLower & sysRelease unset - } + return QStringLiteral("unknown"); +} -# if !defined(Q_OS_ANDROID) && !defined(Q_OS_BLACKBERRY) && !defined(Q_OS_MAC) -# ifdef USE_ETC_OS_RELEASE - if (readEtcOsRelease(v)) - return v; -# endif +QString SubsurfaceSysInfo::buildCpuArchitecture() +{ + return QStringLiteral(ARCH_PROCESSOR); +} - if (!v.sysNameLower.isEmpty()) { - // will produce "qnx_6.5" or "sunos_5.9" - v.versionIdentifier = v.sysNameLower + QLatin1Char('_') + v.sysRelease; +QString SubsurfaceSysInfo::currentCpuArchitecture() +{ +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) + // We don't need to catch all the CPU architectures in this function; + // only those where the host CPU might be different than the build target + // (usually, 64-bit platforms). + SYSTEM_INFO info; + GetNativeSystemInfo(&info); + switch (info.wProcessorArchitecture) { +# ifdef PROCESSOR_ARCHITECTURE_AMD64 + case PROCESSOR_ARCHITECTURE_AMD64: + return QStringLiteral("x86_64"); +# endif +# ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: +# endif + case PROCESSOR_ARCHITECTURE_IA64: + return QStringLiteral("ia64"); } +#elif defined(Q_OS_UNIX) + long ret = -1; + struct utsname u; + +# if defined(Q_OS_SOLARIS) + // We need a special call for Solaris because uname(2) on x86 returns "i86pc" for + // both 32- and 64-bit CPUs. Reference: + // http://docs.oracle.com/cd/E18752_01/html/816-5167/sysinfo-2.html#REFMAN2sysinfo-2 + // http://fxr.watson.org/fxr/source/common/syscall/systeminfo.c?v=OPENSOLARIS + // http://fxr.watson.org/fxr/source/common/conf/param.c?v=OPENSOLARIS;im=10#L530 + if (ret == -1) + ret = sysinfo(SI_ARCHITECTURE_64, u.machine, sizeof u.machine); # endif - return v; -} + if (ret == -1) + ret = uname(&u); + + // we could use detectUnixVersion() above, but we only need a field no other function does + if (ret != -1) { + // the use of QT_BUILD_INTERNAL here is simply to ensure all branches build + // as we don't often build on some of the less common platforms +# if defined(Q_PROCESSOR_ARM) || defined(QT_BUILD_INTERNAL) + if (strcmp(u.machine, "aarch64") == 0) + return QStringLiteral("arm64"); + if (strncmp(u.machine, "armv", 4) == 0) + return QStringLiteral("arm"); +# endif +# if defined(Q_PROCESSOR_POWER) || defined(QT_BUILD_INTERNAL) + // harmonize "powerpc" and "ppc" to "power" + if (strncmp(u.machine, "ppc", 3) == 0) + return QLatin1String("power") + QLatin1String(u.machine + 3); + if (strncmp(u.machine, "powerpc", 7) == 0) + return QLatin1String("power") + QLatin1String(u.machine + 7); + if (strcmp(u.machine, "Power Macintosh") == 0) + return QLatin1String("power"); +# endif +# if defined(Q_PROCESSOR_SPARC) || defined(QT_BUILD_INTERNAL) + // Solaris sysinfo(2) (above) uses "sparcv9", but uname -m says "sun4u"; + // Linux says "sparc64" + if (strcmp(u.machine, "sun4u") == 0 || strcmp(u.machine, "sparc64") == 0) + return QStringLiteral("sparcv9"); + if (strcmp(u.machine, "sparc32") == 0) + return QStringLiteral("sparc"); +# endif +# if defined(Q_PROCESSOR_X86) || defined(QT_BUILD_INTERNAL) + // harmonize all "i?86" to "i386" + if (strlen(u.machine) == 4 && u.machine[0] == 'i' + && u.machine[2] == '8' && u.machine[3] == '6') + return QStringLiteral("i386"); + if (strcmp(u.machine, "amd64") == 0) // Solaris + return QStringLiteral("x86_64"); +# endif + return QString::fromLatin1(u.machine); + } #endif + return buildCpuArchitecture(); +} -static QString unknownText() + +QString SubsurfaceSysInfo::buildAbi() { - return QStringLiteral("unknown"); + return QLatin1String(ARCH_FULL); } -QString SubsurfaceSysInfo::cpuArchitecture() +QString SubsurfaceSysInfo::kernelType() { - return QStringLiteral(ARCH_PROCESSOR); +#if defined(Q_OS_WINCE) + return QStringLiteral("wince"); +#elif defined(Q_OS_WIN) + return QStringLiteral("winnt"); +#elif defined(Q_OS_UNIX) + struct utsname u; + if (uname(&u) == 0) + return QString::fromLatin1(u.sysname).toLower(); +#endif + return unknownText(); } -QString SubsurfaceSysInfo::fullCpuArchitecture() +QString SubsurfaceSysInfo::kernelVersion() { - return QLatin1String(ARCH_FULL); +#ifdef Q_OS_WINRT + // TBD + return QString(); +#elif defined(Q_OS_WIN) + const OSVERSIONINFO osver = winOsVersion(); + return QString::number(int(osver.dwMajorVersion)) + QLatin1Char('.') + QString::number(int(osver.dwMinorVersion)) + + QLatin1Char('.') + QString::number(int(osver.dwBuildNumber)); +#else + struct utsname u; + if (uname(&u) == 0) + return QString::fromLatin1(u.release); + return QString(); +#endif } -QString SubsurfaceSysInfo::osType() +QString SubsurfaceSysInfo::productType() { + // similar, but not identical to QFileSelectorPrivate::platformSelectors #if defined(Q_OS_WINPHONE) return QStringLiteral("winphone"); #elif defined(Q_OS_WINRT) @@ -321,8 +454,6 @@ QString SubsurfaceSysInfo::osType() #elif defined(Q_OS_ANDROID) return QStringLiteral("android"); -#elif defined(Q_OS_LINUX) - return QStringLiteral("linux"); #elif defined(Q_OS_IOS) return QStringLiteral("ios"); @@ -331,31 +462,16 @@ QString SubsurfaceSysInfo::osType() #elif defined(Q_OS_DARWIN) return QStringLiteral("darwin"); -#elif defined(Q_OS_FREEBSD_KERNEL) - return QStringLiteral("freebsd"); -#elif defined(Q_OS_UNIX) - QUnixOSVersion unixOsVersion = detectUnixVersion(); - if (!unixOsVersion.sysNameLower.isEmpty()) - return unixOsVersion.sysNameLower; +#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX + QUnixOSVersion unixOsVersion; + readEtcOsRelease(unixOsVersion); + if (!unixOsVersion.productType.isEmpty()) + return unixOsVersion.productType; #endif return unknownText(); } -QString SubsurfaceSysInfo::osKernelVersion() -{ -#ifdef Q_OS_WINRT - // TBD - return QString(); -#elif defined(Q_OS_WIN) - const OSVERSIONINFO osver = winOsVersion(); - return QString::number(int(osver.dwMajorVersion)) + QLatin1Char('.') + QString::number(int(osver.dwMinorVersion)) - + QLatin1Char('.') + QString::number(int(osver.dwBuildNumber)); -#else - return detectUnixVersion().sysRelease; -#endif -} - -QString SubsurfaceSysInfo::osVersion() +QString SubsurfaceSysInfo::productVersion() { #if defined(Q_OS_IOS) int major = (int(MacintoshVersion) >> 4) & 0xf; @@ -392,24 +508,34 @@ QString SubsurfaceSysInfo::osVersion() deviceinfo_free_details(&deviceInfo); return bbVersion; } -#elif defined(Q_OS_UNIX) - QUnixOSVersion unixOsVersion = detectUnixVersion(); - if (!unixOsVersion.versionIdentifier.isEmpty()) - return unixOsVersion.versionIdentifier; +#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX + QUnixOSVersion unixOsVersion; + readEtcOsRelease(unixOsVersion); + if (!unixOsVersion.productVersion.isEmpty()) + return unixOsVersion.productVersion; #endif // fallback return unknownText(); } -QString SubsurfaceSysInfo::prettyOsName() +QString SubsurfaceSysInfo::prettyProductName() { #if defined(Q_OS_IOS) - return QLatin1String("iOS ") + osVersion(); + return QLatin1String("iOS ") + productVersion(); #elif defined(Q_OS_OSX) // get the known codenames const char *basename = 0; switch (int(MacintoshVersion)) { + case MV_CHEETAH: + case MV_PUMA: + case MV_JAGUAR: + case MV_PANTHER: + case MV_TIGER: + // This version of Qt does not run on those versions of OS X + // so this case label will never be reached + Q_UNREACHABLE(); + break; case MV_LEOPARD: basename = "Mac OS X Leopard ("; break; @@ -422,11 +548,7 @@ QString SubsurfaceSysInfo::prettyOsName() case MV_MOUNTAINLION: basename = "OS X Mountain Lion ("; break; -#ifdef MV_MAVERICKS case MV_MAVERICKS: -#else - case 0x000B: // MV_MAVERICKS -#endif basename = "OS X Mavericks ("; break; #ifdef MV_YOSEMITE @@ -438,63 +560,54 @@ QString SubsurfaceSysInfo::prettyOsName() break; } if (basename) - return QLatin1String(basename) + osVersion() + QLatin1Char(')'); + return QLatin1String(basename) + productVersion() + QLatin1Char(')'); // a future version of OS X - return QLatin1String("OS X ") + osVersion(); + return QLatin1String("OS X ") + productVersion(); #elif defined(Q_OS_WINPHONE) return QLatin1String("Windows Phone ") + QLatin1String(winVer_helper()); #elif defined(Q_OS_WIN) return QLatin1String("Windows ") + QLatin1String(winVer_helper()); #elif defined(Q_OS_ANDROID) - return QLatin1String("Android ") + osVersion(); + return QLatin1String("Android ") + productVersion(); #elif defined(Q_OS_BLACKBERRY) - return QLatin1String("BlackBerry ") + osVersion(); + return QLatin1String("BlackBerry ") + productVersion(); #elif defined(Q_OS_UNIX) - QUnixOSVersion unixOsVersion = detectUnixVersion(); - if (unixOsVersion.versionText.isEmpty()) - return unixOsVersion.sysName; - else - return unixOsVersion.sysName + QLatin1String(" (") + unixOsVersion.versionText + QLatin1Char(')'); -#else - return unknownText(); +# ifdef USE_ETC_OS_RELEASE + QUnixOSVersion unixOsVersion; + readEtcOsRelease(unixOsVersion); + if (!unixOsVersion.prettyName.isEmpty()) + return unixOsVersion.prettyName; +# endif + struct utsname u; + if (uname(&u) == 0) + return QString::fromLatin1(u.sysname) + QLatin1Char(' ') + QString::fromLatin1(u.release); #endif + return unknownText(); } -// detect if the OS we are running on is 64 or 32bit -// we only care when building on Intel for 32bit -QString SubsurfaceSysInfo::osArch() +#endif // Qt >= 5.4 + +QString SubsurfaceSysInfo::prettyOsName() { - QString res = ""; -#if defined(Q_PROCESSOR_X86_32) -#if defined(Q_OS_UNIX) + // Matches the pre-release version of Qt 5.4 + QString pretty = prettyProductName(); +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID) + // QSysInfo::kernelType() returns lowercase ("linux" instead of "Linux") struct utsname u; - if (uname(&u) != -1) { - res = u.machine; - } -#elif defined(Q_OS_WIN) - - /* this code is from - * http://mark.koli.ch/reliably-checking-os-bitness-32-or-64-bit-on-windows-with-a-tiny-c-app - * there is no license given, but 5 lines of code should be fine to reuse unless explicitly forbidden */ - typedef BOOL (WINAPI *IW64PFP)(HANDLE, BOOL *); - BOOL os64 = FALSE; - IW64PFP IW64P = (IW64PFP)GetProcAddress( - GetModuleHandle((LPCSTR)"kernel32"), "IsWow64Process"); - - if(IW64P != NULL){ - IW64P(GetCurrentProcess(), &os64); - } - res = os64 ? "x86_64" : "i386"; + if (uname(&u) == 0) + return QString::fromLatin1(u.sysname) + QLatin1String(" (") + pretty + QLatin1Char(')'); #endif -#endif - return res; + return pretty; } extern "C" { bool isWin7Or8() { - QString os = SubsurfaceSysInfo::prettyOsName(); - return os == "Windows 7" || os.startsWith("Windows 8"); +#ifdef Q_OS_WIN + return (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based) >= QSysInfo::WV_WINDOWS7; +#else + return false; +#endif } } |