diff options
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_ */ |