//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #include "vstdlib/osversion.h" #include "winlite.h" #include "strtools.h" #include "tier0/dbg.h" #ifdef OSX #include #endif //----------------------------------------------------------------------------- // Purpose: return the OS type for this machine //----------------------------------------------------------------------------- EOSType GetOSType() { static EOSType eOSVersion = k_eOSUnknown; #if defined( _WIN32 ) && !defined( _X360 ) if ( eOSVersion == k_eOSUnknown || eOSVersion == k_eWinUnknown ) { eOSVersion = k_eWinUnknown; OSVERSIONINFOEX osvi; Q_memset( &osvi, 0x00, sizeof(osvi) ); osvi.dwOSVersionInfoSize = sizeof(osvi); if ( GetVersionEx( (OSVERSIONINFO *) &osvi ) ) { switch ( osvi.dwPlatformId ) { case VER_PLATFORM_WIN32_NT: if ( osvi.dwMajorVersion <= 4 ) { eOSVersion = k_eWinNT; } else if ( osvi.dwMajorVersion == 5 ) { switch( osvi.dwMinorVersion ) { case 0: eOSVersion = k_eWin2000; break; case 1: eOSVersion = k_eWinXP; break; case 2: eOSVersion = k_eWin2003; break; } } else if ( osvi.dwMajorVersion >= 6 ) { if ( osvi.wProductType == VER_NT_WORKSTATION ) { switch ( osvi.dwMinorVersion ) { case 0: eOSVersion = k_eWinVista; break; case 1: eOSVersion = k_eWindows7; break; } } else /* ( osvi.wProductType != VER_NT_WORKSTATION ) */ { switch ( osvi.dwMinorVersion ) { case 0: eOSVersion = k_eWin2008; // Windows 2008, not R2 break; case 1: eOSVersion = k_eWin2008; // Windows 2008 R2 break; } } } break; case VER_PLATFORM_WIN32_WINDOWS: switch ( osvi.dwMinorVersion ) { case 0: eOSVersion = k_eWin95; break; case 10: eOSVersion = k_eWin98; break; case 90: eOSVersion = k_eWinME; break; } break; case VER_PLATFORM_WIN32s: eOSVersion = k_eWin311; break; } } } #elif defined(OSX) if ( eOSVersion == k_eOSUnknown ) { SInt32 MajorVer = 0; SInt32 MinorVer = 0; SInt32 PatchVer = 0; OSErr err = noErr; err = Gestalt( gestaltSystemVersionMajor, &MajorVer ); if ( err != noErr ) return k_eOSUnknown; err = Gestalt( gestaltSystemVersionMinor, &MinorVer ); if ( err != noErr ) return k_eOSUnknown; err = Gestalt( gestaltSystemVersionBugFix, &PatchVer ); if ( err != noErr ) return k_eOSUnknown; switch ( MajorVer ) { case 10: { switch( MinorVer ) { case 4: eOSVersion = k_eMacOS104; break; case 5: eOSVersion = k_eMacOS105; switch ( PatchVer ) { case 8: eOSVersion = k_eMacOS1058; default: break; } break; case 6: eOSVersion = k_eMacOS106; switch ( PatchVer ) { case 1: case 2: break; case 3: default: // note the default here - 10.6.4 (5,6...) >= 10.6.3, so we want to // identify as 10.6.3 for sysreqs purposes eOSVersion = k_eMacOS1063; break; } break; case 7: eOSVersion = k_eMacOS107; break; default: break; } } default: break; } } #elif defined(LINUX) if ( eOSVersion == k_eOSUnknown ) { FILE *fpKernelVer = fopen( "/proc/version", "r" ); if ( !fpKernelVer ) return k_eLinuxUnknown; char rgchVersionLine[1024]; char *pchRet = fgets( rgchVersionLine, sizeof(rgchVersionLine), fpKernelVer ); fclose( fpKernelVer ); eOSVersion = k_eLinuxUnknown; // move past "Linux version " const char *pchVersion = rgchVersionLine + Q_strlen( "Linux version " ); if ( pchRet && *pchVersion == '2' && *(pchVersion+1) == '.' ) { pchVersion += 2; // move past "2." if ( *pchVersion == '2' && *(pchVersion+1) == '.' ) eOSVersion = k_eLinux22; else if ( *pchVersion == '4' && *(pchVersion+1) == '.' ) eOSVersion = k_eLinux24; else if ( *pchVersion == '6' && *(pchVersion+1) == '.' ) eOSVersion = k_eLinux26; } } #endif return eOSVersion; } //----------------------------------------------------------------------------- // Purpose: get platform-specific OS details (distro, on linux) // returns a pointer to the input buffer on success (for convenience), // NULL on failure. //----------------------------------------------------------------------------- const char *GetOSDetailString( char *pchOutBuf, int cchOutBuf ) { #if defined WIN32 (void)( pchOutBuf ); (void)( cchOutBuf ); // no interesting details return NULL; #else #if defined LINUX // we're about to go poking around to see if we can figure out distribution // looking @ any /etc file is fragile (people can change 'em), // but since this is just hardware survey data, we're not super concerned. // a bunch of OS-specific issue files const char *pszIssueFile[] = { "/etc/redhat-release", "/etc/fedora-release", "/etc/slackware-release", "/etc/debian_release", "/etc/mandrake-release", "/etc/yellowdog-release", "/etc/gentoo-release", "/etc/lsb-release", "/etc/SUSE-release", }; if ( !pchOutBuf ) return NULL; for (int i = 0; i < Q_ARRAYSIZE( pszIssueFile ); i++ ) { FILE *fdInfo = fopen( pszIssueFile[i], "r" ); if ( !fdInfo ) continue; // prepend the buffer with the name of the file we found for easier grouping snprintf( pchOutBuf, cchOutBuf, "%s\n", pszIssueFile[i] ); int cchIssueFile = strlen( pszIssueFile[i] ) + 1; ssize_t cubRead = fread( (void*) (pchOutBuf + cchIssueFile) , sizeof(char), cchOutBuf - cchIssueFile, fdInfo ); fclose( fdInfo ); if ( cubRead < 0 ) return NULL; // null terminate pchOutBuf[ MIN( cubRead, cchOutBuf-1 ) ] = '\0'; return pchOutBuf; } #endif // if all else fails, just send back uname -a if ( !pchOutBuf ) return NULL; FILE *fpUname = popen( "uname -mrsv", "r" ); if ( !fpUname ) return NULL; size_t cchRead = fread( pchOutBuf, sizeof(char), cchOutBuf, fpUname ); pclose( fpUname ); pchOutBuf[ MIN( cchRead, (size_t)cchOutBuf-1 ) ] = '\0'; return pchOutBuf; #endif } //----------------------------------------------------------------------------- // Purpose: get a friendly name for an OS type //----------------------------------------------------------------------------- const char *GetNameFromOSType( EOSType eOSType ) { switch ( eOSType ) { case k_eWinUnknown: return "Windows"; case k_eWin311: return "Windows 3.11"; case k_eWin95: return "Windows 95"; case k_eWin98: return "Windows 98"; case k_eWinME: return "Windows ME"; case k_eWinNT: return "Windows NT"; case k_eWin2000: return "Windows 2000"; case k_eWinXP: return "Windows XP"; case k_eWin2003: return "Windows 2003"; case k_eWinVista: return "Windows Vista"; case k_eWindows7: return "Windows 7"; case k_eWin2008: return "Windows 2008"; #ifdef POSIX case k_eMacOSUnknown: return "Mac OS"; case k_eMacOS104: return "MacOS 10.4"; case k_eMacOS105: return "MacOS 10.5"; case k_eMacOS1058: return "MacOS 10.5.8"; case k_eMacOS106: return "MacOS 10.6"; case k_eMacOS1063: return "MacOS 10.6.3"; case k_eMacOS107: return "MacOS 10.7"; case k_eLinuxUnknown: return "Linux"; case k_eLinux22: return "Linux 2.2"; case k_eLinux24: return "Linux 2.4"; case k_eLinux26: return "Linux 2.6"; #endif default: case k_eOSUnknown: return "Unknown"; } } // friendly name to OS type, MUST be same size as EOSType enum struct OSTypeNameTuple { EOSType m_OSType; const char *m_pchOSName; }; const OSTypeNameTuple k_rgOSTypeToName[] = { { k_eOSUnknown, "unknown" }, { k_eMacOSUnknown, "macos" }, { k_eMacOS104, "macos104" }, { k_eMacOS105, "macos105" }, { k_eMacOS1058, "macos1058" }, { k_eMacOS106, "macos106" }, { k_eMacOS1063, "macos1063" }, { k_eMacOS107, "macos107" }, { k_eLinuxUnknown, "linux" }, { k_eLinux22, "linux22" }, { k_eLinux24, "linux24" }, { k_eLinux26, "linux26" }, { k_eWinUnknown, "windows" }, { k_eWin311, "win311" }, { k_eWin95, "win95" }, { k_eWin98, "win98" }, { k_eWinME, "winME" }, { k_eWinNT, "winNT" }, { k_eWin2000, "win200" }, { k_eWinXP, "winXP" }, { k_eWin2003, "win2003" }, { k_eWinVista, "winVista" }, { k_eWindows7, "win7" }, { k_eWin2008, "win2008" }, }; //----------------------------------------------------------------------------- // Purpose: convert a friendly OS name to a eostype //----------------------------------------------------------------------------- EOSType GetOSTypeFromString_Deprecated( const char *pchName ) { EOSType eOSType; #ifdef WIN32 eOSType = k_eWinUnknown; #else eOSType = k_eOSUnknown; #endif // if this fires, make sure all OS types are in the map Assert( Q_ARRAYSIZE( k_rgOSTypeToName ) == k_eOSTypeMax ); if ( !pchName || Q_strlen( pchName ) == 0 ) return eOSType; for ( int iOS = 0; iOS < Q_ARRAYSIZE( k_rgOSTypeToName ) ; iOS++ ) { if ( !Q_stricmp( k_rgOSTypeToName[iOS].m_pchOSName, pchName ) ) return k_rgOSTypeToName[iOS].m_OSType; } return eOSType; } bool OSTypesAreCompatible( EOSType eOSTypeDetected, EOSType eOSTypeRequired ) { // check windows (on the positive side of the number line) if ( eOSTypeRequired >= k_eWinUnknown ) return ( eOSTypeDetected >= eOSTypeRequired ); if ( eOSTypeRequired == k_eOSUnknown ) return true; // osx if ( eOSTypeRequired >= k_eMacOSUnknown && eOSTypeRequired < k_eOSUnknown ) return ( eOSTypeDetected >= eOSTypeRequired && eOSTypeDetected < k_eOSUnknown ); // and linux if ( eOSTypeRequired >= k_eLinuxUnknown && eOSTypeRequired < k_eMacOSUnknown ) return ( eOSTypeDetected >= eOSTypeRequired && eOSTypeDetected < k_eMacOSUnknown ); return false; } // these strings "windows", "macos", "linux" are part of the // interface, which is why they're hard-coded here, rather than using // the strings in k_rgOSTypeToName const char *GetPlatformName( bool *pbIs64Bit ) { if ( pbIs64Bit ) *pbIs64Bit = Is64BitOS(); EOSType eType = GetOSType(); if ( OSTypesAreCompatible( eType, k_eWinUnknown ) ) return "windows"; if ( OSTypesAreCompatible( eType, k_eMacOSUnknown ) ) return "macos"; if ( OSTypesAreCompatible( eType, k_eLinuxUnknown ) ) return "linux"; return "unknown"; }