From 55099c4bd22512e77e9706d639c222430283b87f Mon Sep 17 00:00:00 2001 From: Renaud Guillard Date: Thu, 18 Jun 2020 02:40:28 +0200 Subject: [PATCH] macOS os.getversion() improvements * Use system property list to retrieve current accurate system version * Add description for latest versions --- src/host/os_getversion.c | 191 +++++++++++++++++++++++++++------------ 1 file changed, 134 insertions(+), 57 deletions(-) diff --git a/src/host/os_getversion.c b/src/host/os_getversion.c index 9d3a1f6a..d3f47218 100644 --- a/src/host/os_getversion.c +++ b/src/host/os_getversion.c @@ -108,6 +108,7 @@ int getversion(struct OsVersionInfo* info) #elif defined(PLATFORM_MACOSX) +#include #include #include #include @@ -115,76 +116,152 @@ int getversion(struct OsVersionInfo* info) int getversion(struct OsVersionInfo* info) { + const char * propertyListFilePath = "/System/Library/CoreServices/SystemVersion.plist"; + Boolean fallback = TRUE; + info->description = "Mac OS"; + info->majorversion = 10; - int mib[] = { CTL_KERN, KERN_OSRELEASE }; - size_t len; - sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0); - - char kernel_version[len]; - sysctl(mib, sizeof(mib) / sizeof(mib[0]), kernel_version, &len, NULL, 0); - - int kern_major; - int kern_minor; - sscanf(kernel_version, "%d.%d.%*d", &kern_major, &kern_minor); - switch (kern_major) + if (access (propertyListFilePath, R_OK) == 0) { - case 8: - info->description = "Mac OS X Tiger"; - info->majorversion = 10; - info->minorversion = 4; - info->revision = kern_minor; + CFPropertyListFormat format; + CFErrorRef errorDescriptor = NULL; + CFStringRef stringRef = NULL; + CFURLRef urlRef = NULL; + CFReadStreamRef streamRef = NULL; + CFPropertyListRef propertyListRef = NULL; + CFTypeID typeId = 0; + Boolean result = FALSE; + + stringRef = CFStringCreateWithCStringNoCopy( + kCFAllocatorDefault, + propertyListFilePath, + kCFStringEncodingASCII, + kCFAllocatorNull); + if (stringRef == NULL) + { + goto getversion_macosx_cleanup; + }; + + urlRef = CFURLCreateWithFileSystemPath( + kCFAllocatorDefault, + stringRef, + kCFURLPOSIXPathStyle, + false); + if (urlRef == NULL) + { + goto getversion_macosx_cleanup; + } + + streamRef = CFReadStreamCreateWithFile( + kCFAllocatorDefault, + urlRef); + if (streamRef == NULL) + { + goto getversion_macosx_cleanup; + } + + result = CFReadStreamOpen (streamRef); + + if (result == FALSE) + { + goto getversion_macosx_cleanup; + } + + propertyListRef = CFPropertyListCreateWithStream( + kCFAllocatorDefault, + streamRef, + 0, + kCFPropertyListImmutable, + &format, + &errorDescriptor); + + CFReadStreamClose (streamRef); + + if (!(propertyListRef && CFPropertyListIsValid(propertyListRef, format)) || errorDescriptor) + { + goto getversion_macosx_cleanup; + } + + typeId = CFGetTypeID(propertyListRef); + if (typeId == CFDictionaryGetTypeID()) + { + const CFDictionaryRef dictionaryRef = (const CFDictionaryRef)propertyListRef; + char versionString[128]; + CFStringRef stringValueRef = NULL; + if (CFDictionaryGetValueIfPresent(dictionaryRef, CFSTR("ProductVersion"), (const void **)(&stringValueRef))) + { + CFStringGetCString(stringValueRef, &versionString[0], (CFIndex)sizeof (versionString), kCFStringEncodingASCII); + sscanf (versionString, "%d.%d.%d", &info->majorversion, &info->minorversion, &info->revision); + + fallback = FALSE; + } + } + +getversion_macosx_cleanup: + + if (propertyListRef) CFRelease (propertyListRef); + if (streamRef) CFRelease (streamRef); + if (urlRef) CFRelease (urlRef); + if (stringRef) CFRelease (stringRef); + } + + if (fallback == TRUE) + { + int mib[] = { CTL_KERN, KERN_OSRELEASE }; + size_t len; + sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0); + + char kernel_version[len]; + sysctl(mib, sizeof(mib) / sizeof(mib[0]), kernel_version, &len, NULL, 0); + + int kern_major; + int kern_minor; + sscanf(kernel_version, "%d.%d.%*d", &kern_major, &kern_minor); + + info->minorversion = kern_major - 4; + info->revision = kern_minor; + } + + if (info->majorversion == 10) + { + switch (info->minorversion) + { + case 4: + info->description = "Mac OS X Tiger"; break; - case 9: - info->description = "Mac OS X Leopard"; - info->majorversion = 10; - info->minorversion = 5; - info->revision = kern_minor; + case 5: + info->description = "Mac OS X Leopard"; break; - case 10: - info->description = "Mac OS X Snow Leopard"; - info->majorversion = 10; - info->minorversion = 6; - info->revision = kern_minor; + case 6: + info->description = "Mac OS X Snow Leopard"; break; - case 11: - info->description = "OS X Lion"; - info->majorversion = 10; - info->minorversion = 7; - info->revision = kern_minor; + case 7: + info->description = "OS X Lion"; break; - case 12: - info->description = "OS X Mountain Lion"; - info->majorversion = 10; - info->minorversion = 8; - info->revision = kern_minor; + case 8: + info->description = "OS X Mountain Lion"; break; - case 13: - info->description = "OS X Mavericks"; - info->majorversion = 10; - info->minorversion = 9; - info->revision = kern_minor; + case 9: + info->description = "OS X Mavericks"; + case 10: + info->description = "OS X Yosemite"; + case 11: + info->description = "OS X El Capitan"; break; - case 14: - info->description = "OS X Yosemite"; - info->majorversion = 10; - info->minorversion = 10; - info->revision = kern_minor; + case 12: + info->description = "macOS Sierra"; break; - case 15: - info->description = "OS X El Capitan"; - info->majorversion = 10; - info->minorversion = 11; - info->revision = kern_minor; + case 13: + info->description = "macOS High Sierra"; break; - case 16: - info->description = "macOS Sierra"; - info->majorversion = 10; - info->minorversion = 12; - info->revision = kern_minor; + case 14: + info->description = "macOS Mojave"; break; - default: + case 15: + info->description = "macOS Catalina"; break; + } } return 1;