/** * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * * Copyright (C) 2013-2019 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** * See sysinfo.h for a description of this file. * * Base Author: Haru @ http://herc.ws */ #define HERCULES_CORE #include "sysinfo.h" #include "common/cbasetypes.h" #include "common/core.h" #include "common/memmgr.h" #include "common/nullpo.h" #include "common/strlib.h" #include // fopen #include // atoi #ifdef WIN32 # include #else # include // time constants # include #endif /// Private interface fields struct sysinfo_private { char *platform; char *osversion; char *cpu; int cpucores; char *arch; char *compiler; char *cflags; char *vcstype_name; int vcstype; char *vcsrevision_src; char *vcsrevision_scripts; }; /// sysinfo.c interface source static struct sysinfo_interface sysinfo_s; static struct sysinfo_private sysinfo_p; struct sysinfo_interface *sysinfo; #define VCSTYPE_UNKNOWN 0 #define VCSTYPE_GIT 1 #define VCSTYPE_SVN 2 #define VCSTYPE_NONE (-1) #ifdef WIN32 /** * Values to be used with GetProductInfo. * * These aren't defined in MSVC2008/WindowsXP, so we gotta define them here. * Values from: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724358%28v=vs.85%29.aspx */ enum windows_product_type { msPRODUCT_UNDEFINED = 0x00000000, ///< An unknown product msPRODUCT_ULTIMATE = 0x00000001, ///< Ultimate msPRODUCT_HOME_BASIC = 0x00000002, ///< Home Basic msPRODUCT_HOME_PREMIUM = 0x00000003, ///< Home Premium msPRODUCT_ENTERPRISE = 0x00000004, ///< Enterprise msPRODUCT_HOME_BASIC_N = 0x00000005, ///< Home Basic N msPRODUCT_BUSINESS = 0x00000006, ///< Business msPRODUCT_STANDARD_SERVER = 0x00000007, ///< Server Standard msPRODUCT_DATACENTER_SERVER = 0x00000008, ///< Server Datacenter (full installation) msPRODUCT_SMALLBUSINESS_SERVER = 0x00000009, ///< Windows Small Business Server msPRODUCT_ENTERPRISE_SERVER = 0x0000000A, ///< Server Enterprise (full installation) msPRODUCT_STARTER = 0x0000000B, ///< Starter msPRODUCT_DATACENTER_SERVER_CORE = 0x0000000C, ///< Server Datacenter (core installation) msPRODUCT_ENTERPRISE_SERVER_CORE = 0x0000000E, ///< Server Enterprise (core installation) msPRODUCT_STANDARD_SERVER_CORE = 0x0000000D, ///< Server Standard (core installation) msPRODUCT_ENTERPRISE_SERVER_IA64 = 0x0000000F, ///< Server Enterprise for Itanium-based Systems msPRODUCT_BUSINESS_N = 0x00000010, ///< Business N msPRODUCT_WEB_SERVER = 0x00000011, ///< Web Server (full installation) msPRODUCT_CLUSTER_SERVER = 0x00000012, ///< HPC Edition msPRODUCT_HOME_SERVER = 0x00000013, ///< Windows Storage Server 2008 R2 Essentials msPRODUCT_STORAGE_EXPRESS_SERVER = 0x00000014, ///< Storage Server Express msPRODUCT_STORAGE_STANDARD_SERVER = 0x00000015, ///< Storage Server Standard msPRODUCT_STORAGE_WORKGROUP_SERVER = 0x00000016, ///< Storage Server Workgroup msPRODUCT_STORAGE_ENTERPRISE_SERVER = 0x00000017, ///< Storage Server Enterprise msPRODUCT_SERVER_FOR_SMALLBUSINESS = 0x00000018, ///< Windows Server 2008 for Windows Essential Server Solutions msPRODUCT_SMALLBUSINESS_SERVER_PREMIUM = 0x00000019, ///< Small Business Server Premium msPRODUCT_HOME_PREMIUM_N = 0x0000001A, ///< Home Premium N msPRODUCT_ENTERPRISE_N = 0x0000001B, ///< Enterprise N msPRODUCT_ULTIMATE_N = 0x0000001C, ///< Ultimate N msPRODUCT_WEB_SERVER_CORE = 0x0000001D, ///< Web Server (core installation) msPRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E, ///< Windows Essential Business Server Management Server msPRODUCT_MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F, ///< Windows Essential Business Server Security Server msPRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020, ///< Windows Essential Business Server Messaging Server msPRODUCT_SERVER_FOUNDATION = 0x00000021, ///< Server Foundation msPRODUCT_HOME_PREMIUM_SERVER = 0x00000022, ///< Windows Home Server 2011 msPRODUCT_SERVER_FOR_SMALLBUSINESS_V = 0x00000023, ///< Windows Server 2008 without Hyper-V for Windows Essential Server Solutions msPRODUCT_STANDARD_SERVER_V = 0x00000024, ///< Server Standard without Hyper-V msPRODUCT_DATACENTER_SERVER_V = 0x00000025, ///< Server Datacenter without Hyper-V (full installation) msPRODUCT_ENTERPRISE_SERVER_V = 0x00000026, ///< Server Enterprise without Hyper-V (full installation) msPRODUCT_DATACENTER_SERVER_CORE_V = 0x00000027, ///< Server Datacenter without Hyper-V (core installation) msPRODUCT_STANDARD_SERVER_CORE_V = 0x00000028, ///< Server Standard without Hyper-V (core installation) msPRODUCT_ENTERPRISE_SERVER_CORE_V = 0x00000029, ///< Server Enterprise without Hyper-V (core installation) msPRODUCT_HYPERV = 0x0000002A, ///< Microsoft Hyper-V Server msPRODUCT_STORAGE_EXPRESS_SERVER_CORE = 0x0000002B, ///< Storage Server Express (core installation) msPRODUCT_STORAGE_STANDARD_SERVER_CORE = 0x0000002C, ///< Storage Server Standard (core installation) msPRODUCT_STORAGE_WORKGROUP_SERVER_CORE = 0x0000002D, ///< Storage Server Workgroup (core installation) msPRODUCT_STORAGE_ENTERPRISE_SERVER_CORE = 0x0000002E, ///< Storage Server Enterprise (core installation) msPRODUCT_STARTER_N = 0x0000002F, ///< Starter N msPRODUCT_PROFESSIONAL = 0x00000030, ///< Professional msPRODUCT_PROFESSIONAL_N = 0x00000031, ///< Professional N msPRODUCT_SB_SOLUTION_SERVER = 0x00000032, ///< Windows Small Business Server 2011 Essentials msPRODUCT_SERVER_FOR_SB_SOLUTIONS = 0x00000033, ///< Server For SB Solutions msPRODUCT_STANDARD_SERVER_SOLUTIONS = 0x00000034, ///< Server Solutions Premium msPRODUCT_STANDARD_SERVER_SOLUTIONS_CORE = 0x00000035, ///< Server Solutions Premium (core installation) msPRODUCT_SB_SOLUTION_SERVER_EM = 0x00000036, ///< Server For SB Solutions EM msPRODUCT_SERVER_FOR_SB_SOLUTIONS_EM = 0x00000037, ///< Server For SB Solutions EM msPRODUCT_SOLUTION_EMBEDDEDSERVER = 0x00000038, ///< Windows MultiPoint Server msPRODUCT_ESSENTIALBUSINESS_SERVER_MGMT = 0x0000003B, ///< Windows Essential Server Solution Management msPRODUCT_ESSENTIALBUSINESS_SERVER_ADDL = 0x0000003C, ///< Windows Essential Server Solution Additional msPRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC = 0x0000003D, ///< Windows Essential Server Solution Management SVC msPRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC = 0x0000003E, ///< Windows Essential Server Solution Additional SVC msPRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x0000003F, ///< Small Business Server Premium (core installation) msPRODUCT_CLUSTER_SERVER_V = 0x00000040, ///< Server Hyper Core V msPRODUCT_STARTER_E = 0x00000042, ///< Not supported msPRODUCT_HOME_BASIC_E = 0x00000043, ///< Not supported msPRODUCT_HOME_PREMIUM_E = 0x00000044, ///< Not supported msPRODUCT_PROFESSIONAL_E = 0x00000045, ///< Not supported msPRODUCT_ENTERPRISE_E = 0x00000046, ///< Not supported msPRODUCT_ULTIMATE_E = 0x00000047, ///< Not supported msPRODUCT_ENTERPRISE_EVALUATION = 0x00000048, ///< Server Enterprise (evaluation installation) msPRODUCT_MULTIPOINT_STANDARD_SERVER = 0x0000004C, ///< Windows MultiPoint Server Standard (full installation) msPRODUCT_MULTIPOINT_PREMIUM_SERVER = 0x0000004D, ///< Windows MultiPoint Server Premium (full installation) msPRODUCT_STANDARD_EVALUATION_SERVER = 0x0000004F, ///< Server Standard (evaluation installation) msPRODUCT_DATACENTER_EVALUATION_SERVER = 0x00000050, ///< Server Datacenter (evaluation installation) msPRODUCT_ENTERPRISE_N_EVALUATION = 0x00000054, ///< Enterprise N (evaluation installation) msPRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER = 0x0000005F, ///< Storage Server Workgroup (evaluation installation) msPRODUCT_STORAGE_STANDARD_EVALUATION_SERVER = 0x00000060, ///< Storage Server Standard (evaluation installation) msPRODUCT_CORE_N = 0x00000062, ///< Windows 8 N msPRODUCT_CORE_COUNTRYSPECIFIC = 0x00000063, ///< Windows 8 China msPRODUCT_CORE_SINGLELANGUAGE = 0x00000064, ///< Windows 8 Single Language msPRODUCT_CORE = 0x00000065, ///< Windows 8 msPRODUCT_PROFESSIONAL_WMC = 0x00000067, ///< Professional with Media Center }; /** * Values to be used with GetSystemMetrics. * * Values from http://msdn.microsoft.com/en-us/library/windows/desktop/ms724385%28v=vs.85%29.aspx */ enum windows_metrics { msSM_SERVERR2 = 89, ///< Obtains the build number if the system is Windows Server 2003 R2; otherwise, 0. }; /** * Values to be used with OSVERSIONINFOEX.wSuiteMask. * * Values from http://msdn.microsoft.com/en-us/library/windows/desktop/ms724833%28v=vs.85%29.aspx */ enum windows_ver_suite { msVER_SUITE_BLADE = 0x00000400, ///< Windows Server 2003, Web Edition is installed. msVER_SUITE_STORAGE_SERVER = 0x00002000, ///< Windows Storage Server 2003 R2 or Windows Storage Server 2003 is installed. msVER_SUITE_COMPUTE_SERVER = 0x00004000, ///< Windows Server 2003, Compute Cluster Edition is installed. msVER_SUITE_WH_SERVER = 0x00008000, ///< Windows Home Server is installed. }; #else // not WIN32 // UNIX. Use build-time cached values #include "sysinfo.inc" #endif // WIN32 // Compiler detection #if defined(__BORLANDC__) #define SYSINFO_COMPILER "Borland C++" #elif defined(__clang__) #define SYSINFO_COMPILER "Clang v" EXPAND_AND_QUOTE(__clang_major__) "." EXPAND_AND_QUOTE(__clang_minor__) "." EXPAND_AND_QUOTE(__clang_patchlevel__) #elif defined(__INTEL_COMPILER) #define SYSINFO_COMPILER "Intel CC v" EXPAND_AND_QUOTE(__INTEL_COMPILER) #elif defined(__MINGW32__) #if defined(__MINGW64__) #define SYSINFO_COMPILER "MinGW-w64 64 Bit v" EXPAND_AND_QUOTE(__MINGW64_VERSION_MAJOR) "." EXPAND_AND_QUOTE(__MINGW64_VERSION_MINOR) \ " (MinGW " EXPAND_AND_QUOTE(__MINGW32_MAJOR_VERSION) "." EXPAND_AND_QUOTE(__MINGW32_MINOR_VERSION) ")" #elif defined(__MINGW64_VERSION_MAJOR) #define SYSINFO_COMPILER "MinGW-w64 32 Bit v" EXPAND_AND_QUOTE(__MINGW64_VERSION_MAJOR) "." EXPAND_AND_QUOTE(__MINGW64_VERSION_MINOR) \ " (MinGW " EXPAND_AND_QUOTE(__MINGW32_MAJOR_VERSION) "." EXPAND_AND_QUOTE(__MINGW32_MINOR_VERSION) ")" #else #define SYSINFO_COMPILER "MinGW32 v" EXPAND_AND_QUOTE(__MINGW32_MAJOR_VERSION) "." EXPAND_AND_QUOTE(__MINGW32_MINOR_VERSION) #endif #elif defined(__GNUC__) #define SYSINFO_COMPILER "GCC v" EXPAND_AND_QUOTE(__GNUC__) "." EXPAND_AND_QUOTE(__GNUC_MINOR__) "." EXPAND_AND_QUOTE(__GNUC_PATCHLEVEL__) #elif defined(_MSC_VER) #if _MSC_VER >= 1300 && _MSC_VER < 1310 #define SYSINFO_COMPILER "Microsoft Visual C++ 7.0 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1310 && _MSC_VER < 1400 #define SYSINFO_COMPILER "Microsoft Visual C++ 2003 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1400 && _MSC_VER < 1500 #define SYSINFO_COMPILER "Microsoft Visual C++ 2005 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1500 && _MSC_VER < 1600 #define SYSINFO_COMPILER "Microsoft Visual C++ 2008 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1600 && _MSC_VER < 1700 #define SYSINFO_COMPILER "Microsoft Visual C++ 2010 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1700 && _MSC_VER < 1800 #define SYSINFO_COMPILER "Microsoft Visual C++ 2012 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1800 && _MSC_VER < 1900 #define SYSINFO_COMPILER "Microsoft Visual C++ 2013 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1900 && _MSC_VER < 1910 #define SYSINFO_COMPILER "Microsoft Visual C++ 2015 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1910 && _MSC_VER < 1920 #define SYSINFO_COMPILER "Microsoft Visual C++ 2017 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #elif _MSC_VER >= 1920 && _MSC_VER < 2000 #define SYSINFO_COMPILER "Microsoft Visual C++ 2019 (v" EXPAND_AND_QUOTE(_MSC_VER) ")" #else // < 1300 || >= 2000 #define SYSINFO_COMPILER "Microsoft Visual C++ v" EXPAND_AND_QUOTE(_MSC_VER) #endif #else #define SYSINFO_COMPILER "Unknown" #endif // end compiler detection /** * Retrieves the current SVN revision. * * @param out[out] a string pointer to return the value (to be aFree()'d.) * @retval true if a revision was correctly detected. * @retval false if no revision was detected. out is set to NULL in this case. */ static bool sysinfo_svn_get_revision(char **out) { // Only include SVN support if detected it, or we're on MSVC #if !defined(SYSINFO_VCSTYPE) || SYSINFO_VCSTYPE == VCSTYPE_SVN || SYSINFO_VCSTYPE == VCSTYPE_UNKNOWN FILE *fp; nullpo_ret(out); // subversion 1.7 uses a sqlite3 database // FIXME this is hackish at best... // - ignores database file structure // - assumes the data in NODES.dav_cache column ends with "!svn/ver//)" // - since it's a cache column, the data might not even exist if ((fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL) { #ifndef SVNNODEPATH //not sure how to handle branches, so I'll leave this overridable define until a better solution comes up #define SVNNODEPATH trunk #endif // SVNNODEPATH const char* prefix = "!svn/ver/"; const char* postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this size_t prefix_len = strlen(prefix); size_t postfix_len = strlen(postfix); size_t i,j,flen; char* buffer; // read file to buffer fseek(fp, 0, SEEK_END); flen = ftell(fp); buffer = (char*)aMalloc(flen + 1); fseek(fp, 0, SEEK_SET); flen = fread(buffer, 1, flen, fp); buffer[flen] = '\0'; fclose(fp); // parse buffer for (i = prefix_len + 1; i + postfix_len <= flen; ++i) { if (buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0) continue; // postfix mismatch for (j = i; j > 0; --j) { // skip digits if (!ISDIGIT(buffer[j - 1])) break; } if (memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0) continue; // prefix mismatch // done if (*out != NULL) aFree(*out); *out = aCalloc(1, 8); snprintf(*out, 8, "%d", atoi(buffer + j)); break; } aFree(buffer); if (*out != NULL) return true; } #else nullpo_ret(out); #endif if (*out != NULL) aFree(*out); *out = NULL; return false; } /** * Retrieves the current Git revision. * * @param out[out] a string pointer to return the value (to be aFree()'d.) * @retval true if a revision was correctly detected. * @retval false if no revision was detected. out is set to NULL in this case. */ static bool sysinfo_git_get_revision(char **out) { // Only include Git support if we detected it, or we're on MSVC #if !defined(SYSINFO_VCSTYPE) || SYSINFO_VCSTYPE == VCSTYPE_GIT || SYSINFO_VCSTYPE == VCSTYPE_UNKNOWN char ref[128], filepath[128], line[128]; nullpo_ret(out); strcpy(ref, "HEAD"); while (*ref) { FILE *fp; safesnprintf(filepath, sizeof(filepath), ".git/%s", ref); if ((fp = fopen(filepath, "r")) != NULL) { if (fgets(line, sizeof(line)-1, fp) == NULL) { fclose(fp); break; } fclose(fp); if (sscanf(line, "ref: %127[^\n]", ref) == 1) { continue; } else if (sscanf(line, "%127[a-f0-9]", ref) == 1 && strlen(ref) == 40) { if (*out != NULL) aFree(*out); *out = aStrdup(ref); } } break; } if (*out != NULL) return true; #else nullpo_ret(out); if (*out != NULL) aFree(*out); *out = NULL; #endif return false; } #ifdef WIN32 /// Windows-specific runtime detection functions. typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD); /** * Retrieves the Operating System version (Windows only). * * Once retrieved, the version string is stored into sysinfo->p->osversion. */ static void sysinfo_osversion_retrieve(void) { OSVERSIONINFOEX osvi; StringBuf buf; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); StrBuf->Init(&buf); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (sysinfo->p->osversion != NULL) { aFree(sysinfo->p->osversion); sysinfo->p->osversion = NULL; } /* * #pragma rantmode (on) * Some engineer at Microsoft moronically decided that, since some applications use this information to do version checks and refuse to * run if they detect a new, unknown version of Windows, now nobody will be able to rely on this information anymore, not even those who * need it for reporting or logging. * The correct fix was to let those applications break, and their developer fix them (and in the meanwhile let the users use the * Compatibility settings to run them) but no, they decided they'd deprecate the API, and make it lie for those who use it, reporting * windows 8 even if they're running on 8.1 or newer. * The API wasn't broken, applications were. Now we have broken applications, and a broken API. Great move, Microsoft. Oh right, * there's the Version API helper functions. Or maybe not, since you can only do 'are we running on at least version X?' checks with * those, it's not what we need. * You know what? I'll just silence your deprecation warning for the time being. Maybe by the time you release the next version of * Windows, you'll have provided a less crippled API or something. * #pragma rantmode (off) */ #pragma warning (push) #pragma warning (disable : 4996) if (!GetVersionEx((OSVERSIONINFO*) &osvi)) { sysinfo->p->osversion = aStrdup("Unknown Version"); return; } #pragma warning (pop) if (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId // Windows NT Family && ((osvi.dwMajorVersion > 4 && osvi.dwMajorVersion < 6) || (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion <= 3)) // Between XP and 8.1 ) { if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion <= 3) { // Between Vista and 8.1 PGPI pGPI; DWORD dwType; if (osvi.dwMinorVersion == 0) { StrBuf->AppendStr(&buf, osvi.wProductType == VER_NT_WORKSTATION ? "Windows Vista" : "Windows Server 2008"); } else if (osvi.dwMinorVersion == 1) { StrBuf->AppendStr(&buf, osvi.wProductType == VER_NT_WORKSTATION ? "Windows 7" : "Windows Server 2008 R2"); } else { // If it's 2, it can be Windows 8, or any newer version (8.1 at the time of writing this) -- see above for the reason. switch (osvi.dwMinorVersion) { case 2: { ULONGLONG mask = 0; OSVERSIONINFOEX osvi2; ZeroMemory(&osvi2, sizeof(OSVERSIONINFOEX)); osvi2.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osvi2.dwMajorVersion = 6; osvi2.dwMinorVersion = 2; VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_LESS_EQUAL); VER_SET_CONDITION(mask, VER_MINORVERSION, VER_LESS_EQUAL); if (VerifyVersionInfo(&osvi2, VER_MAJORVERSION | VER_MINORVERSION, mask)) { StrBuf->AppendStr(&buf, osvi.wProductType == VER_NT_WORKSTATION ? "Windows 8" : "Windows Server 2012"); break; } } case 3: StrBuf->AppendStr(&buf, osvi.wProductType == VER_NT_WORKSTATION ? "Windows 8.1" : "Windows Server 2012 R2"); } } pGPI = (PGPI) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo"); pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType); switch (dwType) { case msPRODUCT_ULTIMATE: case msPRODUCT_ULTIMATE_N: StrBuf->AppendStr(&buf, " Ultimate"); break; case msPRODUCT_PROFESSIONAL: case msPRODUCT_PROFESSIONAL_N: case msPRODUCT_PROFESSIONAL_WMC: StrBuf->AppendStr(&buf, " Professional"); break; case msPRODUCT_HOME_PREMIUM: case msPRODUCT_HOME_PREMIUM_N: StrBuf->AppendStr(&buf, " Home Premium"); break; case msPRODUCT_HOME_BASIC: case msPRODUCT_HOME_BASIC_N: StrBuf->AppendStr(&buf, " Home Basic"); break; case msPRODUCT_ENTERPRISE: case msPRODUCT_ENTERPRISE_N: case msPRODUCT_ENTERPRISE_SERVER: case msPRODUCT_ENTERPRISE_SERVER_CORE: case msPRODUCT_ENTERPRISE_SERVER_IA64: case msPRODUCT_ENTERPRISE_SERVER_V: case msPRODUCT_ENTERPRISE_SERVER_CORE_V: case msPRODUCT_ENTERPRISE_EVALUATION: case msPRODUCT_ENTERPRISE_N_EVALUATION: StrBuf->AppendStr(&buf, " Enterprise"); break; case msPRODUCT_BUSINESS: case msPRODUCT_BUSINESS_N: StrBuf->AppendStr(&buf, " Business"); break; case msPRODUCT_STARTER: case msPRODUCT_STARTER_N: StrBuf->AppendStr(&buf, " Starter"); break; case msPRODUCT_CLUSTER_SERVER: case msPRODUCT_CLUSTER_SERVER_V: StrBuf->AppendStr(&buf, " Cluster Server"); break; case msPRODUCT_DATACENTER_SERVER: case msPRODUCT_DATACENTER_SERVER_CORE: case msPRODUCT_DATACENTER_SERVER_V: case msPRODUCT_DATACENTER_SERVER_CORE_V: case msPRODUCT_DATACENTER_EVALUATION_SERVER: StrBuf->AppendStr(&buf, " Datacenter"); break; case msPRODUCT_SMALLBUSINESS_SERVER: case msPRODUCT_SMALLBUSINESS_SERVER_PREMIUM: case msPRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE: StrBuf->AppendStr(&buf, " Small Business Server"); break; case PRODUCT_STANDARD_SERVER: case PRODUCT_STANDARD_SERVER_CORE: case msPRODUCT_STANDARD_SERVER_V: case msPRODUCT_STANDARD_SERVER_CORE_V: case msPRODUCT_STANDARD_EVALUATION_SERVER: StrBuf->AppendStr(&buf, " Standard"); break; case msPRODUCT_WEB_SERVER: case msPRODUCT_WEB_SERVER_CORE: StrBuf->AppendStr(&buf, " Web Server"); break; case msPRODUCT_STORAGE_EXPRESS_SERVER: case msPRODUCT_STORAGE_STANDARD_SERVER: case msPRODUCT_STORAGE_WORKGROUP_SERVER: case msPRODUCT_STORAGE_ENTERPRISE_SERVER: case msPRODUCT_STORAGE_EXPRESS_SERVER_CORE: case msPRODUCT_STORAGE_STANDARD_SERVER_CORE: case msPRODUCT_STORAGE_WORKGROUP_SERVER_CORE: case msPRODUCT_STORAGE_ENTERPRISE_SERVER_CORE: case msPRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER: case msPRODUCT_STORAGE_STANDARD_EVALUATION_SERVER: StrBuf->AppendStr(&buf, " Storage Server"); break; case msPRODUCT_HOME_SERVER: case msPRODUCT_SERVER_FOR_SMALLBUSINESS: case msPRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT: case msPRODUCT_MEDIUMBUSINESS_SERVER_SECURITY: case msPRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING: case msPRODUCT_SERVER_FOR_SMALLBUSINESS_V: case msPRODUCT_SERVER_FOUNDATION: case msPRODUCT_HOME_PREMIUM_SERVER: case msPRODUCT_HYPERV: case msPRODUCT_SB_SOLUTION_SERVER: case msPRODUCT_SERVER_FOR_SB_SOLUTIONS: case msPRODUCT_STANDARD_SERVER_SOLUTIONS: case msPRODUCT_STANDARD_SERVER_SOLUTIONS_CORE: case msPRODUCT_SB_SOLUTION_SERVER_EM: case msPRODUCT_SERVER_FOR_SB_SOLUTIONS_EM: case msPRODUCT_SOLUTION_EMBEDDEDSERVER: case msPRODUCT_ESSENTIALBUSINESS_SERVER_MGMT: case msPRODUCT_ESSENTIALBUSINESS_SERVER_ADDL: case msPRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC: case msPRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC: case msPRODUCT_MULTIPOINT_STANDARD_SERVER: case msPRODUCT_MULTIPOINT_PREMIUM_SERVER: StrBuf->AppendStr(&buf, " Server (other)"); break; case msPRODUCT_CORE_N: case msPRODUCT_CORE_COUNTRYSPECIFIC: case msPRODUCT_CORE_SINGLELANGUAGE: case msPRODUCT_CORE: StrBuf->AppendStr(&buf, " Workstation (other)"); break; } } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) { // XP x64 and Server 2003 if (osvi.wProductType == VER_NT_WORKSTATION) { StrBuf->AppendStr(&buf, "Windows XP Professional"); } else { if (GetSystemMetrics(msSM_SERVERR2)) StrBuf->AppendStr(&buf, "Windows Server 2003 R2"); else if (osvi.wSuiteMask & msVER_SUITE_STORAGE_SERVER) StrBuf->AppendStr(&buf, "Windows Storage Server 2003"); else if (osvi.wSuiteMask & msVER_SUITE_WH_SERVER) StrBuf->AppendStr(&buf, "Windows Home Server"); else StrBuf->AppendStr(&buf, "Windows Server 2003"); // Test for the server type. if (osvi.wSuiteMask & msVER_SUITE_COMPUTE_SERVER) StrBuf->AppendStr(&buf, " Compute Cluster"); else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) StrBuf->AppendStr(&buf, " Datacenter"); else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) StrBuf->AppendStr(&buf, " Enterprise"); else if (osvi.wSuiteMask & msVER_SUITE_BLADE) StrBuf->AppendStr(&buf, " Web"); else StrBuf->AppendStr(&buf, " Standard"); } } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) { // XP StrBuf->AppendStr(&buf, "Windows XP"); if (osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT) StrBuf->AppendStr(&buf, " Embedded"); else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) StrBuf->AppendStr(&buf, " Home"); else StrBuf->AppendStr(&buf, " Professional"); } else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) { // 2000 StrBuf->AppendStr(&buf, "Windows 2000"); if (osvi.wProductType == VER_NT_WORKSTATION) StrBuf->AppendStr(&buf, " Professional"); else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) StrBuf->AppendStr(&buf, " Datacenter Server"); else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) StrBuf->AppendStr(&buf, " Advanced Server"); else StrBuf->AppendStr(&buf, " Server"); } else { StrBuf->Printf(&buf, "Unknown Windows version %d.%d", osvi.dwMajorVersion, osvi.dwMinorVersion); } } // Include service pack (if any) and build number. if (osvi.szCSDVersion[0] != '\0') { StrBuf->Printf(&buf, " %s", osvi.szCSDVersion); } StrBuf->Printf(&buf, " (build %d)", osvi.dwBuildNumber); sysinfo->p->osversion = aStrdup(StrBuf->Value(&buf)); StrBuf->Destroy(&buf); return; } typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); /** * Retrieves SYSTEM_INFO (Windows only) * System info is not stored anywhere after retrieval * @see http://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx **/ static void sysinfo_systeminfo_retrieve(LPSYSTEM_INFO info) { PGNSI pGNSI; // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); if (NULL != pGNSI) pGNSI(info); else GetSystemInfo(info); return; } /** * Returns number of bytes in a memory page * Only needed when compiling with MSVC **/ static long sysinfo_getpagesize(void) { SYSTEM_INFO si; ZeroMemory(&si, sizeof(SYSTEM_INFO)); sysinfo_systeminfo_retrieve(&si); return si.dwPageSize; } /** * Retrieves the CPU type (Windows only). * * Once retrieved, the name is stored into sysinfo->p->cpu and the * number of cores in sysinfo->p->cpucores. */ static void sysinfo_cpu_retrieve(void) { StringBuf buf; SYSTEM_INFO si; ZeroMemory(&si, sizeof(SYSTEM_INFO)); StrBuf->Init(&buf); if (sysinfo->p->cpu != NULL) { aFree(sysinfo->p->cpu); sysinfo->p->cpu = NULL; } sysinfo_systeminfo_retrieve(&si); if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL || si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ) { StrBuf->Printf(&buf, "%s CPU, Family %d, Model %d, Stepping %d", si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL ? "x86" : "x86_64", si.wProcessorLevel, (si.wProcessorRevision&0xff00)>>8, (si.wProcessorRevision&0xff)); } else { StrBuf->AppendStr(&buf, "Unknown"); } sysinfo->p->cpu = aStrdup(StrBuf->Value(&buf)); sysinfo->p->cpucores = si.dwNumberOfProcessors; StrBuf->Destroy(&buf); } /** * Retrieves the OS architecture (Windows only). * * Once retrieved, the name is stored into sysinfo->p->arch. */ static void sysinfo_arch_retrieve(void) { SYSTEM_INFO si; ZeroMemory(&si, sizeof(SYSTEM_INFO)); if (sysinfo->p->arch != NULL) { aFree(sysinfo->p->arch); sysinfo->p->arch = NULL; } sysinfo_systeminfo_retrieve(&si); if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) // x64 sysinfo->p->arch = aStrdup("x86_64"); else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) // x32 sysinfo->p->arch = aStrdup("x86"); else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM) // ARM sysinfo->p->arch = aStrdup("ARM"); else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) // Itanium sysinfo->p->arch = aStrdup("IA-64"); else sysinfo->p->arch = aStrdup("Unknown"); } /** * Retrieves the startup-time VCS revision information. * * Once retrieved, the value is stored in sysinfo->p->vcsrevision_src. */ static void sysinfo_vcsrevision_src_retrieve(void) { if (sysinfo->p->vcsrevision_src != NULL) { aFree(sysinfo->p->vcsrevision_src); sysinfo->p->vcsrevision_src = NULL; } // Try Git, then SVN if (sysinfo_git_get_revision(&sysinfo->p->vcsrevision_src)) { sysinfo->p->vcstype = VCSTYPE_GIT; return; } if (sysinfo_svn_get_revision(&sysinfo->p->vcsrevision_src)) { sysinfo->p->vcstype = VCSTYPE_SVN; return; } sysinfo->p->vcstype = VCSTYPE_NONE; sysinfo->p->vcsrevision_src = aStrdup("Unknown"); } #endif // WIN32 /** * Retrieves the VCS type name. * * Once retrieved, the value is stored in sysinfo->p->vcstype_name. */ static void sysinfo_vcstype_name_retrieve(void) { if (sysinfo->p->vcstype_name != NULL) { aFree(sysinfo->p->vcstype_name); sysinfo->p->vcstype_name = NULL; } switch (sysinfo->p->vcstype) { case VCSTYPE_GIT: sysinfo->p->vcstype_name = aStrdup("Git"); break; case VCSTYPE_SVN: sysinfo->p->vcstype_name = aStrdup("SVN"); break; default: sysinfo->p->vcstype_name = aStrdup("Exported"); break; } } /** * Returns the platform (OS type) this application is running on. * * This information is cached at compile time, since it's unlikely to change. * * @return the OS platform name. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: "Linux", "Darwin", "Windows", etc. */ static const char *sysinfo_platform(void) { return sysinfo->p->platform; } /** * Returns the Operating System version the application is running on. * * On platforms other than Windows (MSVC), this information is cached at * compile time, since it is uncommon that an application is compiled and runs * on different machines. * * @return the OS name. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: "Windows 2008 Small Business Server", "OS X 10.8 Mountain Lion", * "Gentoo Base System Release 2.2", "Debian GNU/Linux 6.0.6 (squeeze)", etc. */ static const char *sysinfo_osversion(void) { return sysinfo->p->osversion; } /** * Returns the CPU model the application is running on. * * On platforms other than Windows (MSVC), this information is cached at * compile time, since it is uncommon that an application is compiled and runs * on different machines. * * @return the CPU model name. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: "Intel(R) Atom(TM) CPU D2500 @ 1.86GHz", * "Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz", "Intel Core i7", * "x86 CPU, Family 6, Model 54, Stepping 1", etc. */ static const char *sysinfo_cpu(void) { return sysinfo->p->cpu; } /** * Returns the number of CPU cores available. * * On platforms other than Windows (MSVC), this information is cached at * compile time, since it is uncommon that an application is compiled and runs * on different machines. * * @return the number of CPU cores. */ static int sysinfo_cpucores(void) { return sysinfo->p->cpucores; } /** * Returns the CPU architecture the application was compiled for. * * On platforms other than Windows (MSVC), this information is cached at * compile time, since it is uncommon that an application is compiled and runs * on different machines. * * @return the CPU architecture name. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: "x86", "x86_64", "IA-64", "ARM", etc. */ static const char *sysinfo_arch(void) { return sysinfo->p->arch; } /** * Returns info about the 32 or 64 bit build of Hercules. * * @retval true if this is a 64 bit build. * @retval false if this isn't a 64 bit build (i.e. it is a 32 bit build). */ static bool sysinfo_is64bit(void) { #ifdef _LP64 return true; #else return false; #endif } /** * Returns the compiler the application was compiled with. * * @return the compiler name. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: "Microsoft Visual C++ 2012 (v170050727)", * "Clang v5.0.0", "MinGW32 v3.20", "GCC v4.7.3", etc. */ static const char *sysinfo_compiler(void) { return sysinfo->p->compiler; } /** * Returns the compiler flags the application was compiled with. * * On Windows (MSVC), an empty string is returned instead. * * @return the compiler flags. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: "-ggdb -O2 -flto -pipe -ffast-math ..." */ static const char *sysinfo_cflags(void) { return sysinfo->p->cflags; } /** * Returns the Version Control System the application was downloaded with. * * On platforms other than Windows (MSVC), this information is cached at * compile time. On Windows (MSVC), it is cached when the function is first * called (most likely on server startup). * * @return the VCS type (numerical). * * @see VCSTYPE_NONE, VCSTYPE_GIT, VCSTYPE_SVN, VCSTYPE_UNKNOWN */ static int sysinfo_vcstypeid(void) { return sysinfo->p->vcstype; } /** * Returns the Version Control System the application was downloaded with. * * On platforms other than Windows (MSVC), this information is cached at * compile time. On Windows (MSVC), it is cached when the function is first * called (most likely on server startup). * * @return the VCS type. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: "Git", "SVN", "Exported" */ static const char *sysinfo_vcstype(void) { return sysinfo->p->vcstype_name; } /** * Returns the Version Control System revision. * * On platforms other than Windows (MSVC), this information is cached at * compile time for better reliability. On Windows (MSVC), it is cached when * the function is first called (most likely on server startup), so it may * diverge from the actual revision that was compiled. * * @return the VCS revision. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: Git: "9128feccf3bddda94a7f8a170305565416815b40", SVN: "17546" */ static const char *sysinfo_vcsrevision_src(void) { return sysinfo->p->vcsrevision_src; } /** * Returns the Version Control System revision. * * This information is cached during a script reload, so that it matches the * version of the loaded scripts. * * @return the VCS revision. * * Note: Ownership is NOT transferred, the value should not be freed. * * Output example: Git: "9128feccf3bddda94a7f8a170305565416815b40", SVN: "17546" */ static const char *sysinfo_vcsrevision_scripts(void) { return sysinfo->p->vcsrevision_scripts; } /** * Reloads the run-time (scripts) VCS revision information. To be used during * script reloads to refresh the cached version. */ static void sysinfo_vcsrevision_reload(void) { if (sysinfo->p->vcsrevision_scripts != NULL) { aFree(sysinfo->p->vcsrevision_scripts); sysinfo->p->vcsrevision_scripts = NULL; } // Try Git, then SVN if (sysinfo_git_get_revision(&sysinfo->p->vcsrevision_scripts)) { return; } if (sysinfo_svn_get_revision(&sysinfo->p->vcsrevision_scripts)) { return; } sysinfo->p->vcsrevision_scripts = aStrdup("Unknown"); } /** * Checks if we're running (unnecessarily) as superuser. * * @retval true if the current process is running as UNIX super-user. * @retval false if the current process is running as regular user, or * in any case under Windows. */ static bool sysinfo_is_superuser(void) { #ifndef _WIN32 if (geteuid() == 0) return true; #endif return false; } /** * Interface runtime initialization. */ static void sysinfo_init(void) { sysinfo->p->compiler = SYSINFO_COMPILER; #ifdef WIN32 sysinfo->p->platform = "Windows"; sysinfo->p->cflags = "N/A"; sysinfo_osversion_retrieve(); sysinfo_cpu_retrieve(); sysinfo_arch_retrieve(); sysinfo_vcsrevision_src_retrieve(); #else sysinfo->p->platform = SYSINFO_PLATFORM; sysinfo->p->osversion = SYSINFO_OSVERSION; sysinfo->p->cpucores = SYSINFO_CPUCORES; sysinfo->p->cpu = SYSINFO_CPU; sysinfo->p->arch = SYSINFO_ARCH; sysinfo->p->cflags = SYSINFO_CFLAGS; sysinfo->p->vcstype = SYSINFO_VCSTYPE; sysinfo->p->vcsrevision_src = SYSINFO_VCSREV; #endif sysinfo->vcsrevision_reload(); sysinfo_vcstype_name_retrieve(); // Must be called after setting vcstype } /** * Interface shutdown cleanup. */ static void sysinfo_final(void) { #ifdef WIN32 // Only need to be free'd in win32, they're #defined elsewhere if (sysinfo->p->osversion) aFree(sysinfo->p->osversion); if (sysinfo->p->cpu) aFree(sysinfo->p->cpu); if (sysinfo->p->arch) aFree(sysinfo->p->arch); if (sysinfo->p->vcsrevision_src) aFree(sysinfo->p->vcsrevision_src); #endif sysinfo->p->platform = NULL; sysinfo->p->osversion = NULL; sysinfo->p->cpu = NULL; sysinfo->p->arch = NULL; sysinfo->p->vcsrevision_src = NULL; sysinfo->p->cflags = NULL; if (sysinfo->p->vcsrevision_scripts) aFree(sysinfo->p->vcsrevision_scripts); sysinfo->p->vcsrevision_scripts = NULL; if (sysinfo->p->vcstype_name) aFree(sysinfo->p->vcstype_name); sysinfo->p->vcstype_name = NULL; } static const char *sysinfo_time(void) { #if defined(WIN32) return "ticks count"; #elif defined(ENABLE_RDTSC) return "rdtsc"; #elif defined(HAVE_MONOTONIC_CLOCK) return "monotonic clock"; #else return "time of day"; #endif } /** * Interface default values initialization. */ void sysinfo_defaults(void) { sysinfo = &sysinfo_s; memset(&sysinfo_p, '\0', sizeof(sysinfo_p)); sysinfo->p = &sysinfo_p; #if defined(WIN32) && !defined(__CYGWIN__) sysinfo->getpagesize = sysinfo_getpagesize; #else sysinfo->getpagesize = getpagesize; #endif sysinfo->platform = sysinfo_platform; sysinfo->osversion = sysinfo_osversion; sysinfo->cpu = sysinfo_cpu; sysinfo->cpucores = sysinfo_cpucores; sysinfo->arch = sysinfo_arch; sysinfo->is64bit = sysinfo_is64bit; sysinfo->compiler = sysinfo_compiler; sysinfo->cflags = sysinfo_cflags; sysinfo->time = sysinfo_time; sysinfo->vcstype = sysinfo_vcstype; sysinfo->vcstypeid = sysinfo_vcstypeid; sysinfo->vcsrevision_src = sysinfo_vcsrevision_src; sysinfo->vcsrevision_scripts = sysinfo_vcsrevision_scripts; sysinfo->vcsrevision_reload = sysinfo_vcsrevision_reload; sysinfo->is_superuser = sysinfo_is_superuser; sysinfo->init = sysinfo_init; sysinfo->final = sysinfo_final; }