diff options
author | Haru <haru@dotalux.com> | 2013-10-18 13:21:34 +0200 |
---|---|---|
committer | Haru <haru@dotalux.com> | 2014-04-17 06:09:49 +0200 |
commit | 7b12dd06420fae973fbcc2f81f5d385e59788c78 (patch) | |
tree | 5bad1c4f2e44f5d4b49c82fafdd46177d15b9b97 /src/common | |
parent | 8a84d46a19b0112b7e2417728b8816e8b34b7383 (diff) | |
download | hercules-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')
-rw-r--r-- | src/common/HPM.c | 2 | ||||
-rw-r--r-- | src/common/Makefile.in | 24 | ||||
-rw-r--r-- | src/common/console.c | 15 | ||||
-rw-r--r-- | src/common/core.c | 151 | ||||
-rw-r--r-- | src/common/core.h | 2 | ||||
-rw-r--r-- | src/common/malloc.c | 8 | ||||
-rw-r--r-- | src/common/sysinfo.c | 1022 | ||||
-rw-r--r-- | src/common/sysinfo.h | 62 |
8 files changed, 1131 insertions, 155 deletions
diff --git a/src/common/HPM.c b/src/common/HPM.c index 971eb83bd..6d2c45641 100644 --- a/src/common/HPM.c +++ b/src/common/HPM.c @@ -703,8 +703,6 @@ void hplugins_share_defaults(void) { HPM->share(&arg_c,"arg_c"); HPM->share(SERVER_NAME,"SERVER_NAME"); HPM->share(&SERVER_TYPE,"SERVER_TYPE"); - HPM->share((void*)get_svn_revision,"get_svn_revision"); - HPM->share((void*)get_git_hash,"get_git_hash"); HPM->share(DB, "DB"); HPM->share(HPMiMalloc, "iMalloc"); /* socket */ diff --git a/src/common/Makefile.in b/src/common/Makefile.in index 7bb9ae630..623c59c2e 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -1,3 +1,5 @@ +# Copyright (c) Hercules Dev Team, licensed under GNU GPL. +# See the LICENSE file CONFIG_D = ../config CONFIG_H = $(wildcard $(CONFIG_D)/*.h) $(wildcard $(CONFIG_D)/*/*.h) @@ -15,8 +17,8 @@ MT19937AR_H = $(MT19937AR_D)/mt19937ar.h MT19937AR_INCLUDE = -I$(MT19937AR_D) COMMON_SHARED_C = conf.c db.c des.c ers.c grfio.c HPM.c mapindex.c md5calc.c \ - mutex.c nullpo.c random.c showmsg.c strlib.c thread.c \ - timer.c utils.c + mutex.c nullpo.c random.c showmsg.c strlib.c sysinfo.c \ + thread.c timer.c utils.c COMMON_C = $(COMMON_SHARED_C) COMMON_SHARED_OBJ = $(patsubst %.c,%.o,$(COMMON_SHARED_C)) COMMON_OBJ = $(addprefix obj_all/, $(COMMON_SHARED_OBJ) \ @@ -27,11 +29,12 @@ COMMON_C += console.c core.c malloc.c socket.c COMMON_H = atomic.h cbasetypes.h conf.h console.h core.h db.h des.h ers.h \ grfio.h HPM.h HPMi.h malloc.h mapindex.h md5calc.h mmo.h mutex.h \ nullpo.h random.h showmsg.h socket.h spinlock.h sql.h strlib.h \ - thread.h timer.h utils.h winapi.h + sysinfo.h thread.h timer.h utils.h winapi.h COMMON_SQL_OBJ = obj_sql/sql.o COMMON_SQL_H = sql.h COMMON_C += sql.c +SYSINFO_INC = sysinfo.inc HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) @@ -54,7 +57,7 @@ sql: $(SQL_DEPENDS) buildclean: @echo " CLEAN common (build temp files)" - @rm -rf *.o obj_all obj_sql + @rm -rf *.o obj_all obj_sql sysinfo.inc clean: buildclean @echo " CLEAN common" @@ -71,6 +74,10 @@ help: Makefile: Makefile.in @$(MAKE) -C ../.. src/common/Makefile +$(SYSINFO_INC): $(COMMON_C) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) + @echo " MAKE $@" + @$(MAKE) -C ../.. sysinfo + needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 @@ -103,19 +110,20 @@ common_mini: $(COMMON_MINI_OBJ) $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) obj_all/common common_sql: $(COMMON_SQL_OBJ) obj_sql/common_sql.a Makefile -obj_all/%.o: %.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | obj_all +obj_all/sysinfo.o: sysinfo.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(SYSINFO_INC) | obj_all + +obj_all/%.o: %.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_all @echo " CC $<" @$(CC) @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj_all/mini%.o: %.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | obj_all +obj_all/mini%.o: %.c $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_all @echo " CC $<" @$(CC) @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) -DMINICORE @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) $(CONFIG_H) $(LIBCONFIG_H) | obj_sql +obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) $(CONFIG_H) $(LIBCONFIG_H) | $(SYSINFO_INC) obj_sql @echo " CC $<" @$(CC) @CFLAGS@ $(LIBCONFIG_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - # missing object files $(MT19937AR_OBJ): @echo " MAKE $@" diff --git a/src/common/console.c b/src/common/console.c index ec228b563..d8f352c8a 100644 --- a/src/common/console.c +++ b/src/common/console.c @@ -5,6 +5,7 @@ #include "../common/cbasetypes.h" #include "../common/showmsg.h" #include "../common/core.h" +#include "../common/sysinfo.h" #include "../config/core.h" #include "console.h" @@ -41,8 +42,7 @@ struct console_interface console_s; * CORE : Display title *--------------------------------------*/ void display_title(void) { - const char* svn = get_svn_revision(); - const char* git = get_git_hash(); + const char *vcstype = sysinfo->vcstype(); ShowMessage("\n"); ShowMessage(""CL_BG_RED""CL_BT_WHITE" "CL_CLL""CL_NORMAL"\n"); @@ -57,10 +57,13 @@ void display_title(void) { ShowMessage(""CL_BG_RED""CL_BT_WHITE" http://hercules.ws/board/ "CL_CLL""CL_NORMAL"\n"); ShowMessage(""CL_BG_RED""CL_BT_WHITE" "CL_CLL""CL_NORMAL"\n"); - if( git[0] != HERC_UNKNOWN_VER ) - ShowInfo("Git Hash: '"CL_WHITE"%s"CL_RESET"'\n", git); - else if( svn[0] != HERC_UNKNOWN_VER ) - ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'\n", svn); + ShowInfo("Hercules %d-bit for %s\n", sysinfo->is64bit() ? 64 : 32, sysinfo->platform()); + ShowInfo("%s revision (src): '"CL_WHITE"%s"CL_RESET"'\n", vcstype, sysinfo->vcsrevision_src()); + ShowInfo("%s revision (scripts): '"CL_WHITE"%s"CL_RESET"'\n", vcstype, sysinfo->vcsrevision_scripts()); + ShowInfo("OS version: '"CL_WHITE"%s"CL_RESET" [%s]'\n", sysinfo->osversion(), sysinfo->arch()); + ShowInfo("CPU: '"CL_WHITE"%s [%d]"CL_RESET"'\n", sysinfo->cpu(), sysinfo->cpucores()); + ShowInfo("Compiled with %s\n", sysinfo->compiler()); + ShowInfo("Compile Flags: %s\n", sysinfo->cflags()); } #ifdef CONSOLE_INPUT #if defined(WIN32) diff --git a/src/common/core.c b/src/common/core.c index c6075da40..798c832f0 100644 --- a/src/common/core.c +++ b/src/common/core.c @@ -9,6 +9,7 @@ #include "core.h" #include "../common/console.h" #include "../common/random.h" +#include "../common/sysinfo.h" #ifndef MINICORE #include "../common/db.h" @@ -78,7 +79,7 @@ sigfunc *compat_signal(int signo, sigfunc *func) { *--------------------------------------*/ #ifdef _WIN32 static BOOL WINAPI console_handler(DWORD c_event) { - switch(c_event) { + switch(c_event) { case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: @@ -89,8 +90,8 @@ static BOOL WINAPI console_handler(DWORD c_event) { break; default: return FALSE; - } - return TRUE; + } + return TRUE; } static void cevents_init() { @@ -152,134 +153,21 @@ void signals_init (void) { } #endif -const char* get_svn_revision(void) { - static char svn_version_buffer[16] = ""; - FILE *fp; - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - - // 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 - 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,len; - char* buffer; - - // read file to buffer - fseek(fp, 0, SEEK_END); - len = ftell(fp); - buffer = (char*)aMalloc(len + 1); - fseek(fp, 0, SEEK_SET); - len = fread(buffer, 1, len, fp); - buffer[len] = '\0'; - fclose(fp); - - // parse buffer - for( i = prefix_len + 1; i + postfix_len <= len; ++i ) { - if( buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0 ) - continue; // postfix missmatch - 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 missmatch - // done - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j)); - break; - } - aFree(buffer); - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - } - - // 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) { - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%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 - snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line)); - } - } - } - fclose(fp); - - if( svn_version_buffer[0] != '\0' ) - return svn_version_buffer; - } - - // fallback - svn_version_buffer[0] = HERC_UNKNOWN_VER; - return svn_version_buffer; -} -/* whats our origin */ -#define GIT_ORIGIN "refs/remotes/origin/master" -/* Grabs the hash from the last time the user updated his working copy (last pull) */ -const char *get_git_hash (void) { - static char HerculesGitHash[41] = "";//Sha(40) + 1 - FILE *fp; - - if( HerculesGitHash[0] != '\0' ) - return HerculesGitHash; - - if ( (fp = fopen (".git/"GIT_ORIGIN, "r")) != NULL) { - char line[64]; - char *rev = malloc (sizeof (char) * 50); - - if (fgets (line, sizeof (line), fp) && sscanf (line, "%50s", rev)) - snprintf (HerculesGitHash, sizeof (HerculesGitHash), "%s", rev); - - free (rev); - fclose (fp); - } else { - HerculesGitHash[0] = HERC_UNKNOWN_VER; - } - - if (! (*HerculesGitHash)) { - HerculesGitHash[0] = HERC_UNKNOWN_VER; - } - - return HerculesGitHash; -} -// Warning if executed as superuser (root) +/** + * Warns the user if executed as superuser (root) + */ void usercheck(void) { -#ifndef _WIN32 - if (geteuid() == 0) { - ShowWarning ("You are running Hercules with root privileges, it is not necessary.\n"); - } -#endif + if (sysinfo->is_superuser()) { + ShowWarning("You are running Hercules with root privileges, it is not necessary.\n"); + } } + void core_defaults(void) { #ifndef MINICORE hpm_defaults(); HCache_defaults(); #endif + sysinfo_defaults(); console_defaults(); strlib_defaults(); malloc_defaults(); @@ -318,16 +206,18 @@ int main (int argc, char **argv) { iMalloc->init();// needed for Show* in display_title() [FlavioJS] + sysinfo->init(); + if (!(msg_silent&0x1)) console->display_title(); - -#ifdef MINICORE // minimalist Core + usercheck(); + +#ifdef MINICORE // minimalist Core do_init(argc,argv); do_final(); #else// not MINICORE set_server_type(); - usercheck(); Sql_Init(); rathread_init(); @@ -348,10 +238,8 @@ int main (int argc, char **argv) { HCache->init(); -#ifndef MINICORE HPM->init(); -#endif - + sockt->init(); do_init(argc,argv); @@ -366,15 +254,14 @@ int main (int argc, char **argv) { console->final(); do_final(); -#ifndef MINICORE HPM->final(); -#endif timer->final(); sockt->final(); DB->final(); rathread_final(); ers_final(); #endif + sysinfo->final(); iMalloc->final(); diff --git a/src/common/core.h b/src/common/core.h index 72f956e1d..2cb623bc2 100644 --- a/src/common/core.h +++ b/src/common/core.h @@ -32,8 +32,6 @@ enum server_types { enum server_types SERVER_TYPE; -const char *get_svn_revision(void); -const char *get_git_hash (void); extern int do_init(int,char**); extern void set_server_type(void); extern void do_abort(void); diff --git a/src/common/malloc.c b/src/common/malloc.c index f7f108304..5b39cbab6 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -5,6 +5,7 @@ #include "../common/malloc.h" #include "../common/core.h" #include "../common/showmsg.h" +#include "../common/sysinfo.h" #include <stdio.h> #include <stdlib.h> @@ -574,17 +575,14 @@ static void memmgr_log (char *buf) if( !log_fp ) { time_t raw; struct tm* t; - const char* svn = get_svn_revision(); - const char* git = get_git_hash(); log_fp = fopen(memmer_logfile,"at"); if (!log_fp) log_fp = stdout; time(&raw); t = localtime(&raw); - fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (rev %s).\n", - (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, - git[0] != HERC_UNKNOWN_VER ? git : svn[0] != HERC_UNKNOWN_VER ? svn : "Unknown"); + fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (%s rev '%s').\n", + (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, sysinfo->vcstype(), sysinfo->vcsrevision_src()); } fprintf(log_fp, "%s", buf); return; 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; +} diff --git a/src/common/sysinfo.h b/src/common/sysinfo.h new file mode 100644 index 000000000..17faac26b --- /dev/null +++ b/src/common/sysinfo.h @@ -0,0 +1,62 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Base Author: Haru @ http://hercules.ws + +#ifndef _COMMON_SYSINFO_H_ +#define _COMMON_SYSINFO_H_ + +/** + * Provides various bits of information about the system Hercules is running on + * (note: on unix systems, to avoid runtime detection, most of the data is + * cached at compile time) + */ + +#include "../common/cbasetypes.h" + +#ifdef _COMMON_SYSINFO_P_ +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; +}; +#else +struct sysinfo_private; +#endif + +/** + * sysinfo.c interface + **/ +struct sysinfo_interface { + struct sysinfo_private *p; + + const char *(*platform) (void); + const char *(*osversion) (void); + const char *(*cpu) (void); + int (*cpucores) (void); + const char *(*arch) (void); + bool (*is64bit) (void); + const char *(*compiler) (void); + const char *(*cflags) (void); + const char *(*vcstype) (void); + int (*vcstypeid) (void); + const char *(*vcsrevision_src) (void); + const char *(*vcsrevision_scripts) (void); + void (*vcsrevision_reload) (void); + bool (*is_superuser) (void); + void (*init) (void); + void (*final) (void); +}; + +struct sysinfo_interface *sysinfo; + +void sysinfo_defaults(void); + +#endif /* _COMMON_SYSINFO_H_ */ |