summaryrefslogtreecommitdiff
path: root/src/common/sysinfo.c
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2013-10-18 13:21:34 +0200
committerHaru <haru@dotalux.com>2014-04-17 06:09:49 +0200
commit7b12dd06420fae973fbcc2f81f5d385e59788c78 (patch)
tree5bad1c4f2e44f5d4b49c82fafdd46177d15b9b97 /src/common/sysinfo.c
parent8a84d46a19b0112b7e2417728b8816e8b34b7383 (diff)
downloadhercules-7b12dd06420fae973fbcc2f81f5d385e59788c78.tar.gz
hercules-7b12dd06420fae973fbcc2f81f5d385e59788c78.tar.bz2
hercules-7b12dd06420fae973fbcc2f81f5d385e59788c78.tar.xz
hercules-7b12dd06420fae973fbcc2f81f5d385e59788c78.zip
Added sysinfo (System Information) functionalities
- More informative messages are displayed during startup, to make it easier to identify what system and environment Hercules is running. - Git/SVN revision detection is improved, separating the source version (cached at compile time) from the runtime version, in case the user updated their working copy without recompiling the server. Git version detection is also more reliable, in case a non-default branch is used. - The get_revision script command has been removed (as it was useless to begin with, after the switch to git). An alternative will be provided later, for feature-probing purposes. - The patch was tested under Linux (Gentoo / gcc 4.7 on i686 and x86_64, Debian 6 / gcc 4.4 on i686, Raspbian / gcc 4.6 on armv6l, CentOS 5 / gcc 4.1 on i686, CentOS 6 / gcc 4.4 on x86_64, Linux Mint 15 / gcc 4.7 on x86_64, OS X Mountain Lion / clang 5.0 and gcc 4.8 on x86_64, Cygwin-NT-5.1/gcc 4.8 on i686, FreeBSD 8 / gcc 4.2 on i386, FreeBSD 9 / gcc 4.2 on amd64, FreeBSD 10 / clang 3.3 on amd64, NetBSD 5 / gcc 4.1 on i386, NetBSD 6 / gcc 4.5 on amd64, OpenBSD 5 / gcc 4.2 on amd64, Solaris 11 / gcc 4.5 on i86pc, Windows 7 / Visual Studio 2012 on x86, Windows 8 / Visual Studio 2010 on WOW64, Windows 8.1 / Visual Studio 2013 on WOW64. Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src/common/sysinfo.c')
-rw-r--r--src/common/sysinfo.c1022
1 files changed, 1022 insertions, 0 deletions
diff --git a/src/common/sysinfo.c b/src/common/sysinfo.c
new file mode 100644
index 000000000..a56896458
--- /dev/null
+++ b/src/common/sysinfo.c
@@ -0,0 +1,1022 @@
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Base Author: Haru @ http://hercules.ws
+
+/// See sysinfo.h for a description of this file
+
+#define _COMMON_SYSINFO_P_
+#include "sysinfo.h"
+#undef _COMMON_SYSINFO_P_
+
+#include "../common/cbasetypes.h"
+#include "../common/core.h"
+#include "../common/strlib.h"
+#include "../common/malloc.h"
+
+#ifdef WIN32
+#include <windows.h>
+#include <string.h> // strlen
+#else
+#include <unistd.h>
+#endif
+#include <stdio.h> // fopen
+#include <stdlib.h> // atoi
+
+/// sysinfo.c interface source
+struct sysinfo_interface sysinfo_s;
+struct sysinfo_private sysinfo_p;
+
+#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) ")"
+#else // < 1300 || >= 1900
+#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.
+ */
+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;
+
+ // 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;
+ }
+
+ // subversion 1.6 and older?
+ if ((fp = fopen(".svn/entries", "r")) != NULL) {
+ char line[1024];
+ int rev;
+ // Check the version
+ if (fgets(line, sizeof(line), fp)) {
+ if (!ISDIGIT(line[0])) {
+ // XML File format
+ while (fgets(line,sizeof(line),fp))
+ if (strstr(line,"revision=")) break;
+ if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) {
+ if (*out != NULL)
+ aFree(*out);
+ *out = aCalloc(1, 8);
+ snprintf(*out, 8, "%d", rev);
+ }
+ } else {
+ // Bin File format
+ if (fgets(line, sizeof(line), fp) == NULL) { printf("Can't get bin name\n"); } // Get the name
+ if (fgets(line, sizeof(line), fp) == NULL) { printf("Can't get entries kind\n"); } // Get the entries kind
+ if (fgets(line, sizeof(line), fp)) { // Get the rev numver
+ if (*out != NULL)
+ aFree(*out);
+ *out = aCalloc(1, 8);
+ snprintf(*out, 8, "%d", atoi(line));
+ }
+ }
+ }
+ fclose(fp);
+
+ if (*out != NULL)
+ return true;
+ }
+#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.
+ */
+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
+ FILE *fp;
+ char ref[128], filepath[128], line[128];
+
+ strcpy(ref, "HEAD");
+
+ while (*ref) {
+ snprintf(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
+ 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.
+ */
+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 (strlen(osvi.szCSDVersion) > 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 the CPU type (Windows only).
+ *
+ * Once retrieved, the name is stored into sysinfo->p->cpu and the
+ * number of cores in sysinfo->p->cpucores.
+ */
+void sysinfo_cpu_retrieve(void) {
+ StringBuf buf;
+ PGNSI pGNSI;
+ SYSTEM_INFO si;
+ ZeroMemory(&si, sizeof(SYSTEM_INFO));
+ StrBuf->Init(&buf);
+
+ if (sysinfo->p->cpu != NULL) {
+ aFree(sysinfo->p->cpu);
+ sysinfo->p->cpu = NULL;
+ }
+
+ // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
+ pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo");
+ if (NULL != pGNSI)
+ pGNSI(&si);
+ else
+ GetSystemInfo(&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.
+ */
+void sysinfo_arch_retrieve(void) {
+ PGNSI pGNSI;
+ SYSTEM_INFO si;
+ ZeroMemory(&si, sizeof(SYSTEM_INFO));
+
+ if (sysinfo->p->arch != NULL) {
+ aFree(sysinfo->p->arch);
+ sysinfo->p->arch = NULL;
+ }
+
+ // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
+ pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo");
+ if (NULL != pGNSI)
+ pGNSI(&si);
+ else
+ GetSystemInfo(&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.
+ */
+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
+
+/**
+ * Retrieevs the VCS type name.
+ *
+ * Once retrieved, the value is stored in sysinfo->p->vcstype_name.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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.
+ */
+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).
+ */
+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.
+ */
+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 ..."
+ */
+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
+ */
+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"
+ */
+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"
+ */
+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"
+ */
+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.
+ */
+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.
+ */
+bool sysinfo_is_superuser(void) {
+#ifndef _WIN32
+ if (geteuid() == 0)
+ return true;
+#endif
+ return false;
+}
+
+/**
+ * Interface runtime initialization.
+ */
+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.
+ */
+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;
+}
+
+/**
+ * Interface default values initialization.
+ */
+void sysinfo_defaults(void) {
+ sysinfo = &sysinfo_s;
+ memset(&sysinfo_p, '\0', sizeof(sysinfo_p));
+ sysinfo->p = &sysinfo_p;
+
+ 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->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;
+}