#ifdef __NetBSD__ #define _NETBSD_SOURCE #endif #if __APPLE__ // don't play with POSIX and Darwin flags, they don't work! // they are defined in unistd.h, but enabling flags breaks other // system header files! #define _SC_NPROCESSORS_ONLN 58 #define _SC_PAGESIZE 29 #define _SC_PHYS_PAGES 200 #include #include typedef unsigned long u_long; typedef unsigned int u_int; typedef unsigned char u_char; typedef unsigned short u_short; #include #include #endif /* __APPLE__ */ #include "system.h" #include "port.h" #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #else #ifdef __FreeBSD__ #include #include #include #else /* __FreeBSD__ */ #include #include #ifdef __NetBSD__ #include #else /* __NetBSD__ */ #include #endif /* __NetBSD__ */ #endif /* __FreeBSD__ */ #endif /* _WIN32 */ #include #include #include unsigned int system_available_cpus( void ) { // operating specific cases #ifdef _WIN32 SYSTEM_INFO info; memset( &info, 0, sizeof( SYSTEM_INFO ) ); GetSystemInfo( &info ); return info.dwNumberOfProcessors; #else #ifdef __FreeBSD__ int req[2]; req[0] = CTL_HW; req[1] = HW_NCPU; int nprocs; size_t len = sizeof( nprocs ); if( sysctl( req, 2, &nprocs, &len, NULL, 0 ) < 0 ) { // assuming one CPU in case of error // (safe fallback) return 1; } return nprocs; #else // __FreeBSD__ // generic POSIX case #ifdef _SC_NPROCESSORS_ONLN long nprocs = sysconf( _SC_NPROCESSORS_ONLN ); if( nprocs < -1 ) { // assuming one CPU if we can't detect the number of // CPUs (safe fallback) return 1; } return nprocs; #else #error No _SC_NPROCESSORS_ONLN, must port first! #endif // _SC_NPROCESSORS_ONLN #endif // __FreeBSD__ #endif // _WIN32 } #ifdef _WIN32 static bool verifyVersion( const DWORD major, const DWORD minor ) { OSVERSIONINFOEX info; memset( &info, 0, sizeof( OSVERSIONINFOEX ) ); info.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX ); info.dwMajorVersion = major; info.dwMinorVersion = minor; info.dwPlatformId = VER_PLATFORM_WIN32_NT; // all other have gone.. DWORDLONG condMask = 0; VER_SET_CONDITION( condMask, VER_MAJORVERSION, VER_GREATER_EQUAL ); VER_SET_CONDITION( condMask, VER_MINORVERSION, VER_GREATER_EQUAL ); VER_SET_CONDITION( condMask, VER_PLATFORMID, VER_EQUAL ); const BOOL res = VerifyVersionInfo( &info, VER_MAJORVERSION | VER_MINORVERSION | VER_PLATFORMID, condMask ); if( !res ) { if( GetLastError( ) == ERROR_OLD_WIN_VERSION ) { return false; } else { fprintf( stderr, "VerifyVersionInfo( ) failed for %u.%u!\n", major, minor ); return false; } } return true; } #endif void system_os( char *name, size_t len ) { #ifdef _WIN32 OSVERSIONINFOEX info; memset( &info, 0, sizeof( OSVERSIONINFOEX ) ); info.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX ); if( !GetVersionEx( (LPOSVERSIONINFO)&info ) ) { snprintf( name, len, "cpe:/o:microsoft:windows:unknown" ); return; } DWORD major = info.dwMajorVersion; DWORD minor = info.dwMinorVersion; // GetVersionEx "lies" to us since Windows 8.1, so verify real // version with VerifyVersionInfo for( DWORD nextMajor = major + 1; nextMajor < 20; nextMajor++ ) { if( verifyVersion( nextMajor, 0 ) ) { major = nextMajor; break; } } for( DWORD nextMinor = minor + 1; nextMinor < 20; nextMinor++ ) { if( verifyVersion( major, nextMinor ) ) { minor = nextMinor; break; } } switch( major ) { case 6: switch( minor ) { case 3: switch( info.wProductType ) { case VER_NT_DOMAIN_CONTROLLER: case VER_NT_SERVER: snprintf( name, len, "cpe:/o:microsoft:windows_server_2012:r2" ); break; case VER_NT_WORKSTATION: snprintf( name, len, "cpe:/o:microsoft:windows_8.1" ); break; } break; case 2: switch( info.wProductType ) { case VER_NT_DOMAIN_CONTROLLER: case VER_NT_SERVER: snprintf( name, len, "cpe:/o:microsoft:windows_server_2012" ); break; case VER_NT_WORKSTATION: snprintf( name, len, "cpe:/o:microsoft:windows_8" ); break; } break; case 1: switch( info.wProductType ) { case VER_NT_DOMAIN_CONTROLLER: case VER_NT_SERVER: snprintf( name, len, "cpe:/o:microsoft:windows_server_2008:r2" ); break; case VER_NT_WORKSTATION: snprintf( name, len, "cpe:/o:microsoft:windows_7" ); break; } break; case 0: switch( info.wProductType ) { case VER_NT_DOMAIN_CONTROLLER: case VER_NT_SERVER: snprintf( name, len, "cpe:/o:microsoft:windows_server_2008" ); break; case VER_NT_WORKSTATION: snprintf( name, len, "cpe:/o:microsoft:windows_vista" ); break; } break; default: snprintf( name, len, "cpe:/o:microsoft:windows" ); break; } break; case 5: switch( minor ) { case 2: switch( info.wProductType ) { case VER_NT_DOMAIN_CONTROLLER: case VER_NT_SERVER: snprintf( name, len, "cpe:/o:microsoft:windows_server_2003" ); break; case VER_NT_WORKSTATION: snprintf( name, len, "cpe:/o:microsoft:windows" ); break; } break; case 1: switch( info.wProductType ) { case VER_NT_DOMAIN_CONTROLLER: case VER_NT_SERVER: snprintf( name, len, "cpe:/o:microsoft:windows" ); break; case VER_NT_WORKSTATION: snprintf( name, len, "cpe:/o:microsoft:windows_xp" ); break; } break; default: snprintf( name, len, "cpe:/o:microsoft:windows" ); break; } break; default: snprintf( name, len, "cpe:/o:microsoft:windows" ); break; } #elif defined( linux ) || defined( __linux ) || defined( __linux__ ) bool has_os_release = false; bool has_redhat_release = false; /* new systemd-way on modern Linux systems */ FILE *f = fopen( "/etc/os-release", "r" ); if( f == NULL ) { f = fopen( "/usr/lib/os-release", "r" ); if( f == NULL ) { f = fopen( "/etc/redhat-release", "r" ); if( f == NULL ) { snprintf( name, len, "cpe:/o:linux" ); return; } else { has_redhat_release = true; } /* TODO: test for /etc/xxx-release, /etc/xxx-version, not sure if we should also check and run lsb_release */ } else { has_os_release = true; } } else { has_os_release = true; } if( has_os_release ) { char line[100]; char *key; char *id = NULL; char *version_id = NULL; char *cpe_name = NULL; while( !feof( f ) ) { fgets( line, sizeof( line ), f ); if( line[0] == '#' ) continue; char *value = strchr( line, '=' ); if( value == NULL ) continue; key = line; *value++ = '\0'; char *p = value; char *q = p; while( *p != '\0' ) { if( *p == '\\' ) { ++p; if( *p == '\0' ) { break; } *q++ = *p++; } if( *p == '\"' || *p == '\'' || *p == '\n' ) { p++; } else { *q++ = *p++; } } *q = '\0'; if( strcmp( key, "CPE_NAME" ) == 0 ) { cpe_name = strdup( value ); } else if( strcmp( key, "ID" ) == 0 ) { id = strdup( value ); } else if( strcmp( key, "VERSION_ID" ) == 0 ) { version_id = strdup( value ); } } /* do we have a CPE_NAME? In this case CPE_NAME takes precedence */ if( cpe_name != NULL ) { snprintf( name, len, "%s", cpe_name ); } else { /* construct CPE_NAME from ID and VERSION_ID and any other information we find */ /* no version information, so we have a rolling release */ if( version_id == NULL ) { version_id = strdup( "rolling" ); } snprintf( name, len, "cpe:/o:%s:%s:%s", id, id, version_id ); } if( id != NULL ) free( id ); if( version_id != NULL ) free( version_id ); if( cpe_name != NULL ) free( cpe_name ); } if( has_redhat_release ) { //CentOS release 6.5 (Final) char line[100]; fgets( line, sizeof( line ), f ); if( strstr( line, "CentOS" ) != NULL ) { char *p = strtok( line, " " ); bool is_version = false; char *version = "unknown"; while( p != NULL ) { if( strcmp( p, "release" ) == 0 ) { is_version = true; p = strtok( NULL, " " ); continue; } if( is_version ) { version = p; is_version = false; } p = strtok( NULL, " " ); } char *major = strtok( version, "." ); if( p != NULL ) { snprintf( name, len, "cpe:/o:centos:centos:%s", major ); } else { snprintf( name, len, "cpe:/o:centos:centos:%s", version ); } } else { snprintf( name, len, "cpe:/o:redhat:unknown" ); } } fclose( f ) ; #elif defined( __FreeBSD__ ) || defined( __NetBSD__ ) /* resort to uname */ struct utsname uts; uname( &uts ); snprintf( name, len, "cpe:/o:%s:%s:%s", uts.sysname, uts.release, uts.version ); #elif defined( __APPLE__ ) /* resort to uname */ struct utsname uts; uname( &uts ); snprintf( name, len, "cpe:/o:apple:osx:%s", uts.release ); #else /* TODO: or should this be a compilation error? */ snprintf( name, len, "cpe:/o:unknown:unknown:unknown" ); #endif } void system_arch( char *name, size_t len ) { #ifdef _WIN32 SYSTEM_INFO info; memset( &info, 0, sizeof( SYSTEM_INFO ) ); GetSystemInfo( &info ); switch( info.wProcessorArchitecture ) { case PROCESSOR_ARCHITECTURE_AMD64: snprintf( name, len, "x86_64" ); break; case PROCESSOR_ARCHITECTURE_INTEL: snprintf( name, len, "i686" ); break; case PROCESSOR_ARCHITECTURE_ARM: snprintf( name, len, "arm" ); break; case PROCESSOR_ARCHITECTURE_IA64: snprintf( name, len, "ia64" ); break; case PROCESSOR_ARCHITECTURE_UNKNOWN: default: snprintf( name, len, "unknown" ); } #else struct utsname uts; uname( &uts ); snprintf( name, len, "%s", uts.machine ); #endif } int system_hostname( char *name, size_t len ) { #ifdef _WIN32 DWORD dwSize = len; int res = GetComputerNameExA( ComputerNamePhysicalDnsFullyQualified, name, &dwSize ); return ( res > 0 ) ? 0 : -1; #else return gethostname( name, len ); #endif } unsigned int system_phys_memory( ) { #ifdef _WIN32 MEMORYSTATUSEX memState; memset( &memState, 0, sizeof( MEMORYSTATUSEX ) ); memState.dwLength = sizeof( MEMORYSTATUSEX ); GlobalMemoryStatusEx( &memState ); return memState.ullTotalPhys / 1024; #elif defined( __APPLE__ ) uint64_t mem; size_t len = sizeof( mem ); sysctlbyname( "hw.memsize", &mem, &len, NULL, 0 ); return mem / 1024; #elif defined( linux ) || defined( __linux ) || defined( __linux__ ) || defined( __FreeBSD__ ) || defined( __NetBSD__ ) size_t pageSize; size_t nofPages; pageSize = sysconf( _SC_PAGESIZE ); nofPages = sysconf( _SC_PHYS_PAGES ); return ( pageSize / 1024 ) * nofPages; #else #error Not ported yet! #endif }