/**
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
* Copyright (C) 2013-2020 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 <http://www.gnu.org/licenses/>.
*/
/**
* 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 <stdio.h> // fopen
#include <stdlib.h> // atoi
#ifdef WIN32
# include <windows.h>
#else
# include <sys/time.h> // time constants
# include <unistd.h>
#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 <http://sourceforge.net/p/predef/wiki/Compilers/>
#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/<revision>/<path>)"
// - 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;
}