Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

427 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "vstdlib/osversion.h"
  9. #include "winlite.h"
  10. #include "strtools.h"
  11. #include "tier0/dbg.h"
  12. #ifdef OSX
  13. #include <CoreServices/CoreServices.h>
  14. #endif
  15. //-----------------------------------------------------------------------------
  16. // Purpose: return the OS type for this machine
  17. //-----------------------------------------------------------------------------
  18. EOSType GetOSType()
  19. {
  20. static EOSType eOSVersion = k_eOSUnknown;
  21. #if defined( _WIN32 ) && !defined( _X360 )
  22. if ( eOSVersion == k_eOSUnknown || eOSVersion == k_eWinUnknown )
  23. {
  24. eOSVersion = k_eWinUnknown;
  25. OSVERSIONINFOEX osvi;
  26. Q_memset( &osvi, 0x00, sizeof(osvi) );
  27. osvi.dwOSVersionInfoSize = sizeof(osvi);
  28. if ( GetVersionEx( (OSVERSIONINFO *) &osvi ) )
  29. {
  30. switch ( osvi.dwPlatformId )
  31. {
  32. case VER_PLATFORM_WIN32_NT:
  33. if ( osvi.dwMajorVersion <= 4 )
  34. {
  35. eOSVersion = k_eWinNT;
  36. }
  37. else if ( osvi.dwMajorVersion == 5 )
  38. {
  39. switch( osvi.dwMinorVersion )
  40. {
  41. case 0:
  42. eOSVersion = k_eWin2000;
  43. break;
  44. case 1:
  45. eOSVersion = k_eWinXP;
  46. break;
  47. case 2:
  48. eOSVersion = k_eWin2003;
  49. break;
  50. }
  51. }
  52. else if ( osvi.dwMajorVersion >= 6 )
  53. {
  54. if ( osvi.wProductType == VER_NT_WORKSTATION )
  55. {
  56. switch ( osvi.dwMinorVersion )
  57. {
  58. case 0:
  59. eOSVersion = k_eWinVista;
  60. break;
  61. case 1:
  62. eOSVersion = k_eWindows7;
  63. break;
  64. }
  65. }
  66. else /* ( osvi.wProductType != VER_NT_WORKSTATION ) */
  67. {
  68. switch ( osvi.dwMinorVersion )
  69. {
  70. case 0:
  71. eOSVersion = k_eWin2008; // Windows 2008, not R2
  72. break;
  73. case 1:
  74. eOSVersion = k_eWin2008; // Windows 2008 R2
  75. break;
  76. }
  77. }
  78. }
  79. break;
  80. case VER_PLATFORM_WIN32_WINDOWS:
  81. switch ( osvi.dwMinorVersion )
  82. {
  83. case 0:
  84. eOSVersion = k_eWin95;
  85. break;
  86. case 10:
  87. eOSVersion = k_eWin98;
  88. break;
  89. case 90:
  90. eOSVersion = k_eWinME;
  91. break;
  92. }
  93. break;
  94. case VER_PLATFORM_WIN32s:
  95. eOSVersion = k_eWin311;
  96. break;
  97. }
  98. }
  99. }
  100. #elif defined(OSX)
  101. if ( eOSVersion == k_eOSUnknown )
  102. {
  103. SInt32 MajorVer = 0;
  104. SInt32 MinorVer = 0;
  105. SInt32 PatchVer = 0;
  106. OSErr err = noErr;
  107. err = Gestalt( gestaltSystemVersionMajor, &MajorVer );
  108. if ( err != noErr )
  109. return k_eOSUnknown;
  110. err = Gestalt( gestaltSystemVersionMinor, &MinorVer );
  111. if ( err != noErr )
  112. return k_eOSUnknown;
  113. err = Gestalt( gestaltSystemVersionBugFix, &PatchVer );
  114. if ( err != noErr )
  115. return k_eOSUnknown;
  116. switch ( MajorVer )
  117. {
  118. case 10:
  119. {
  120. switch( MinorVer )
  121. {
  122. case 4:
  123. eOSVersion = k_eMacOS104;
  124. break;
  125. case 5:
  126. eOSVersion = k_eMacOS105;
  127. switch ( PatchVer )
  128. {
  129. case 8:
  130. eOSVersion = k_eMacOS1058;
  131. default:
  132. break;
  133. }
  134. break;
  135. case 6:
  136. eOSVersion = k_eMacOS106;
  137. switch ( PatchVer )
  138. {
  139. case 1:
  140. case 2:
  141. break;
  142. case 3:
  143. default:
  144. // note the default here - 10.6.4 (5,6...) >= 10.6.3, so we want to
  145. // identify as 10.6.3 for sysreqs purposes
  146. eOSVersion = k_eMacOS1063;
  147. break;
  148. }
  149. break;
  150. case 7:
  151. eOSVersion = k_eMacOS107;
  152. break;
  153. default:
  154. break;
  155. }
  156. }
  157. default:
  158. break;
  159. }
  160. }
  161. #elif defined(LINUX)
  162. if ( eOSVersion == k_eOSUnknown )
  163. {
  164. FILE *fpKernelVer = fopen( "/proc/version", "r" );
  165. if ( !fpKernelVer )
  166. return k_eLinuxUnknown;
  167. char rgchVersionLine[1024];
  168. char *pchRet = fgets( rgchVersionLine, sizeof(rgchVersionLine), fpKernelVer );
  169. fclose( fpKernelVer );
  170. eOSVersion = k_eLinuxUnknown;
  171. // move past "Linux version "
  172. const char *pchVersion = rgchVersionLine + Q_strlen( "Linux version " );
  173. if ( pchRet && *pchVersion == '2' && *(pchVersion+1) == '.' )
  174. {
  175. pchVersion += 2; // move past "2."
  176. if ( *pchVersion == '2' && *(pchVersion+1) == '.' )
  177. eOSVersion = k_eLinux22;
  178. else if ( *pchVersion == '4' && *(pchVersion+1) == '.' )
  179. eOSVersion = k_eLinux24;
  180. else if ( *pchVersion == '6' && *(pchVersion+1) == '.' )
  181. eOSVersion = k_eLinux26;
  182. }
  183. }
  184. #endif
  185. return eOSVersion;
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Purpose: get platform-specific OS details (distro, on linux)
  189. // returns a pointer to the input buffer on success (for convenience),
  190. // NULL on failure.
  191. //-----------------------------------------------------------------------------
  192. const char *GetOSDetailString( char *pchOutBuf, int cchOutBuf )
  193. {
  194. #if defined WIN32
  195. (void)( pchOutBuf );
  196. (void)( cchOutBuf );
  197. // no interesting details
  198. return NULL;
  199. #else
  200. #if defined LINUX
  201. // we're about to go poking around to see if we can figure out distribution
  202. // looking @ any /etc file is fragile (people can change 'em),
  203. // but since this is just hardware survey data, we're not super concerned.
  204. // a bunch of OS-specific issue files
  205. const char *pszIssueFile[] =
  206. {
  207. "/etc/redhat-release",
  208. "/etc/fedora-release",
  209. "/etc/slackware-release",
  210. "/etc/debian_release",
  211. "/etc/mandrake-release",
  212. "/etc/yellowdog-release",
  213. "/etc/gentoo-release",
  214. "/etc/lsb-release",
  215. "/etc/SUSE-release",
  216. };
  217. if ( !pchOutBuf )
  218. return NULL;
  219. for (int i = 0; i < Q_ARRAYSIZE( pszIssueFile ); i++ )
  220. {
  221. FILE *fdInfo = fopen( pszIssueFile[i], "r" );
  222. if ( !fdInfo )
  223. continue;
  224. // prepend the buffer with the name of the file we found for easier grouping
  225. snprintf( pchOutBuf, cchOutBuf, "%s\n", pszIssueFile[i] );
  226. int cchIssueFile = strlen( pszIssueFile[i] ) + 1;
  227. ssize_t cubRead = fread( (void*) (pchOutBuf + cchIssueFile) , sizeof(char), cchOutBuf - cchIssueFile, fdInfo );
  228. fclose( fdInfo );
  229. if ( cubRead < 0 )
  230. return NULL;
  231. // null terminate
  232. pchOutBuf[ MIN( cubRead, cchOutBuf-1 ) ] = '\0';
  233. return pchOutBuf;
  234. }
  235. #endif
  236. // if all else fails, just send back uname -a
  237. if ( !pchOutBuf )
  238. return NULL;
  239. FILE *fpUname = popen( "uname -mrsv", "r" );
  240. if ( !fpUname )
  241. return NULL;
  242. size_t cchRead = fread( pchOutBuf, sizeof(char), cchOutBuf, fpUname );
  243. pclose( fpUname );
  244. pchOutBuf[ MIN( cchRead, (size_t)cchOutBuf-1 ) ] = '\0';
  245. return pchOutBuf;
  246. #endif
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Purpose: get a friendly name for an OS type
  250. //-----------------------------------------------------------------------------
  251. const char *GetNameFromOSType( EOSType eOSType )
  252. {
  253. switch ( eOSType )
  254. {
  255. case k_eWinUnknown:
  256. return "Windows";
  257. case k_eWin311:
  258. return "Windows 3.11";
  259. case k_eWin95:
  260. return "Windows 95";
  261. case k_eWin98:
  262. return "Windows 98";
  263. case k_eWinME:
  264. return "Windows ME";
  265. case k_eWinNT:
  266. return "Windows NT";
  267. case k_eWin2000:
  268. return "Windows 2000";
  269. case k_eWinXP:
  270. return "Windows XP";
  271. case k_eWin2003:
  272. return "Windows 2003";
  273. case k_eWinVista:
  274. return "Windows Vista";
  275. case k_eWindows7:
  276. return "Windows 7";
  277. case k_eWin2008:
  278. return "Windows 2008";
  279. #ifdef POSIX
  280. case k_eMacOSUnknown:
  281. return "Mac OS";
  282. case k_eMacOS104:
  283. return "MacOS 10.4";
  284. case k_eMacOS105:
  285. return "MacOS 10.5";
  286. case k_eMacOS1058:
  287. return "MacOS 10.5.8";
  288. case k_eMacOS106:
  289. return "MacOS 10.6";
  290. case k_eMacOS1063:
  291. return "MacOS 10.6.3";
  292. case k_eMacOS107:
  293. return "MacOS 10.7";
  294. case k_eLinuxUnknown:
  295. return "Linux";
  296. case k_eLinux22:
  297. return "Linux 2.2";
  298. case k_eLinux24:
  299. return "Linux 2.4";
  300. case k_eLinux26:
  301. return "Linux 2.6";
  302. #endif
  303. default:
  304. case k_eOSUnknown:
  305. return "Unknown";
  306. }
  307. }
  308. // friendly name to OS type, MUST be same size as EOSType enum
  309. struct OSTypeNameTuple
  310. {
  311. EOSType m_OSType;
  312. const char *m_pchOSName;
  313. };
  314. const OSTypeNameTuple k_rgOSTypeToName[] =
  315. {
  316. { k_eOSUnknown, "unknown" },
  317. { k_eMacOSUnknown, "macos" },
  318. { k_eMacOS104, "macos104" },
  319. { k_eMacOS105, "macos105" },
  320. { k_eMacOS1058, "macos1058" },
  321. { k_eMacOS106, "macos106" },
  322. { k_eMacOS1063, "macos1063" },
  323. { k_eMacOS107, "macos107" },
  324. { k_eLinuxUnknown, "linux" },
  325. { k_eLinux22, "linux22" },
  326. { k_eLinux24, "linux24" },
  327. { k_eLinux26, "linux26" },
  328. { k_eWinUnknown, "windows" },
  329. { k_eWin311, "win311" },
  330. { k_eWin95, "win95" },
  331. { k_eWin98, "win98" },
  332. { k_eWinME, "winME" },
  333. { k_eWinNT, "winNT" },
  334. { k_eWin2000, "win200" },
  335. { k_eWinXP, "winXP" },
  336. { k_eWin2003, "win2003" },
  337. { k_eWinVista, "winVista" },
  338. { k_eWindows7, "win7" },
  339. { k_eWin2008, "win2008" },
  340. };
  341. //-----------------------------------------------------------------------------
  342. // Purpose: convert a friendly OS name to a eostype
  343. //-----------------------------------------------------------------------------
  344. EOSType GetOSTypeFromString_Deprecated( const char *pchName )
  345. {
  346. EOSType eOSType;
  347. #ifdef WIN32
  348. eOSType = k_eWinUnknown;
  349. #else
  350. eOSType = k_eOSUnknown;
  351. #endif
  352. // if this fires, make sure all OS types are in the map
  353. Assert( Q_ARRAYSIZE( k_rgOSTypeToName ) == k_eOSTypeMax );
  354. if ( !pchName || Q_strlen( pchName ) == 0 )
  355. return eOSType;
  356. for ( int iOS = 0; iOS < Q_ARRAYSIZE( k_rgOSTypeToName ) ; iOS++ )
  357. {
  358. if ( !Q_stricmp( k_rgOSTypeToName[iOS].m_pchOSName, pchName ) )
  359. return k_rgOSTypeToName[iOS].m_OSType;
  360. }
  361. return eOSType;
  362. }
  363. bool OSTypesAreCompatible( EOSType eOSTypeDetected, EOSType eOSTypeRequired )
  364. {
  365. // check windows (on the positive side of the number line)
  366. if ( eOSTypeRequired >= k_eWinUnknown )
  367. return ( eOSTypeDetected >= eOSTypeRequired );
  368. if ( eOSTypeRequired == k_eOSUnknown )
  369. return true;
  370. // osx
  371. if ( eOSTypeRequired >= k_eMacOSUnknown && eOSTypeRequired < k_eOSUnknown )
  372. return ( eOSTypeDetected >= eOSTypeRequired && eOSTypeDetected < k_eOSUnknown );
  373. // and linux
  374. if ( eOSTypeRequired >= k_eLinuxUnknown && eOSTypeRequired < k_eMacOSUnknown )
  375. return ( eOSTypeDetected >= eOSTypeRequired && eOSTypeDetected < k_eMacOSUnknown );
  376. return false;
  377. }
  378. // these strings "windows", "macos", "linux" are part of the
  379. // interface, which is why they're hard-coded here, rather than using
  380. // the strings in k_rgOSTypeToName
  381. const char *GetPlatformName( bool *pbIs64Bit )
  382. {
  383. if ( pbIs64Bit )
  384. *pbIs64Bit = Is64BitOS();
  385. EOSType eType = GetOSType();
  386. if ( OSTypesAreCompatible( eType, k_eWinUnknown ) )
  387. return "windows";
  388. if ( OSTypesAreCompatible( eType, k_eMacOSUnknown ) )
  389. return "macos";
  390. if ( OSTypesAreCompatible( eType, k_eLinuxUnknown ) )
  391. return "linux";
  392. return "unknown";
  393. }