1 /* ===-- os_version_check.c - OS version checking -------------------------===
3 * The LLVM Compiler Infrastructure
5 * This file is dual licensed under the MIT and the University of Illinois Open
6 * Source Licenses. See LICENSE.TXT for details.
8 * ===----------------------------------------------------------------------===
10 * This file implements the function __isOSVersionAtLeast, used by
11 * Objective-C's @available
13 * ===----------------------------------------------------------------------===
18 #include <CoreFoundation/CoreFoundation.h>
19 #include <TargetConditionals.h>
20 #include <dispatch/dispatch.h>
27 /* These three variables hold the host's OS version. */
28 static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
29 static dispatch_once_t DispatchOnceCounter;
31 typedef CFDataRef (*CFDataCreateWithBytesNoCopyFuncTy)(CFAllocatorRef,
32 const UInt8 *, CFIndex,
34 typedef CFPropertyListRef (*CFPropertyListCreateWithDataFuncTy)(
35 CFAllocatorRef, CFDataRef, CFOptionFlags, CFPropertyListFormat *,
37 typedef CFPropertyListRef (*CFPropertyListCreateFromXMLDataFuncTy)(
38 CFAllocatorRef, CFDataRef, CFOptionFlags, CFStringRef *);
39 typedef CFStringRef (*CFStringCreateWithCStringNoCopyFuncTy)(CFAllocatorRef,
43 typedef const void *(*CFDictionaryGetValueFuncTy)(CFDictionaryRef,
45 typedef CFTypeID (*CFGetTypeIDFuncTy)(CFTypeRef);
46 typedef CFTypeID (*CFStringGetTypeIDFuncTy)(void);
47 typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex,
49 typedef void (*CFReleaseFuncTy)(CFTypeRef);
51 /* Find and parse the SystemVersion.plist file. */
52 static void parseSystemVersionPList(void *Unused) {
54 /* Load CoreFoundation dynamically */
55 const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
58 const CFAllocatorRef kCFAllocatorNull =
59 *(const CFAllocatorRef *)NullAllocator;
60 CFDataCreateWithBytesNoCopyFuncTy CFDataCreateWithBytesNoCopyFunc =
61 (CFDataCreateWithBytesNoCopyFuncTy)dlsym(RTLD_DEFAULT,
62 "CFDataCreateWithBytesNoCopy");
63 if (!CFDataCreateWithBytesNoCopyFunc)
65 CFPropertyListCreateWithDataFuncTy CFPropertyListCreateWithDataFunc =
66 (CFPropertyListCreateWithDataFuncTy)dlsym(
67 RTLD_DEFAULT, "CFPropertyListCreateWithData");
68 /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
69 * will be NULL on earlier OS versions. */
70 #pragma clang diagnostic push
71 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
72 CFPropertyListCreateFromXMLDataFuncTy CFPropertyListCreateFromXMLDataFunc =
73 (CFPropertyListCreateFromXMLDataFuncTy)dlsym(
74 RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
75 #pragma clang diagnostic pop
76 /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
77 * might be NULL in future OS versions. */
78 if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
80 CFStringCreateWithCStringNoCopyFuncTy CFStringCreateWithCStringNoCopyFunc =
81 (CFStringCreateWithCStringNoCopyFuncTy)dlsym(
82 RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
83 if (!CFStringCreateWithCStringNoCopyFunc)
85 CFDictionaryGetValueFuncTy CFDictionaryGetValueFunc =
86 (CFDictionaryGetValueFuncTy)dlsym(RTLD_DEFAULT, "CFDictionaryGetValue");
87 if (!CFDictionaryGetValueFunc)
89 CFGetTypeIDFuncTy CFGetTypeIDFunc =
90 (CFGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFGetTypeID");
93 CFStringGetTypeIDFuncTy CFStringGetTypeIDFunc =
94 (CFStringGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
95 if (!CFStringGetTypeIDFunc)
97 CFStringGetCStringFuncTy CFStringGetCStringFunc =
98 (CFStringGetCStringFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetCString");
99 if (!CFStringGetCStringFunc)
101 CFReleaseFuncTy CFReleaseFunc =
102 (CFReleaseFuncTy)dlsym(RTLD_DEFAULT, "CFRelease");
106 char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
108 #if TARGET_OS_SIMULATOR
109 char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
110 if (!PListPathPrefix)
112 char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
113 strcpy(FullPath, PListPathPrefix);
114 strcat(FullPath, PListPath);
115 PListPath = FullPath;
117 FILE *PropertyList = fopen(PListPath, "r");
121 /* Dynamically allocated stuff. */
122 CFDictionaryRef PListRef = NULL;
123 CFDataRef FileContentsRef = NULL;
124 UInt8 *PListBuf = NULL;
126 fseek(PropertyList, 0, SEEK_END);
127 long PListFileSize = ftell(PropertyList);
128 if (PListFileSize < 0)
130 rewind(PropertyList);
132 PListBuf = malloc((size_t)PListFileSize);
136 size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
137 if (NumRead != (size_t)PListFileSize)
140 /* Get the file buffer into CF's format. We pass in a null allocator here *
141 * because we free PListBuf ourselves */
142 FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
143 NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
144 if (!FileContentsRef)
147 if (CFPropertyListCreateWithDataFunc)
148 PListRef = (*CFPropertyListCreateWithDataFunc)(
149 NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
151 PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
152 NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
156 CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
157 NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
160 CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
161 (*CFReleaseFunc)(ProductVersion);
163 (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
167 if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
168 sizeof(VersionStr), kCFStringEncodingUTF8))
170 sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
174 (*CFReleaseFunc)(PListRef);
176 (*CFReleaseFunc)(FileContentsRef);
178 fclose(PropertyList);
181 int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
182 /* Populate the global version variables, if they haven't already. */
183 dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
185 if (Major < GlobalMajor)
187 if (Major > GlobalMajor)
189 if (Minor < GlobalMinor)
191 if (Minor > GlobalMinor)
193 return Subminor <= GlobalSubminor;
198 /* Silence an empty translation unit warning. */