]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/builtins/os_version_check.c
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / builtins / os_version_check.c
1 /* ===-- os_version_check.c - OS version checking  -------------------------===
2  *
3  *                     The LLVM Compiler Infrastructure
4  *
5  * This file is dual licensed under the MIT and the University of Illinois Open
6  * Source Licenses. See LICENSE.TXT for details.
7  *
8  * ===----------------------------------------------------------------------===
9  *
10  * This file implements the function __isOSVersionAtLeast, used by
11  * Objective-C's @available
12  *
13  * ===----------------------------------------------------------------------===
14  */
15
16 #ifdef __APPLE__
17
18 #include <TargetConditionals.h>
19 #include <dispatch/dispatch.h>
20 #include <dlfcn.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 /* These three variables hold the host's OS version. */
27 static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
28 static dispatch_once_t DispatchOnceCounter;
29
30 /* We can't include <CoreFoundation/CoreFoundation.h> directly from here, so
31  * just forward declare everything that we need from it. */
32
33 typedef const void *CFDataRef, *CFAllocatorRef, *CFPropertyListRef,
34                    *CFStringRef, *CFDictionaryRef, *CFTypeRef, *CFErrorRef;
35
36 #if __LLP64__
37 typedef unsigned long long CFTypeID;
38 typedef unsigned long long CFOptionFlags;
39 typedef signed long long CFIndex;
40 #else
41 typedef unsigned long CFTypeID;
42 typedef unsigned long CFOptionFlags;
43 typedef signed long CFIndex;
44 #endif
45
46 typedef unsigned char UInt8;
47 typedef _Bool Boolean;
48 typedef CFIndex CFPropertyListFormat;
49 typedef uint32_t CFStringEncoding;
50
51 /* kCFStringEncodingASCII analog. */
52 #define CF_STRING_ENCODING_ASCII 0x0600
53 /* kCFStringEncodingUTF8 analog. */
54 #define CF_STRING_ENCODING_UTF8 0x08000100
55 #define CF_PROPERTY_LIST_IMMUTABLE 0
56
57 typedef CFDataRef (*CFDataCreateWithBytesNoCopyFuncTy)(CFAllocatorRef,
58                                                        const UInt8 *, CFIndex,
59                                                        CFAllocatorRef);
60 typedef CFPropertyListRef (*CFPropertyListCreateWithDataFuncTy)(
61     CFAllocatorRef, CFDataRef, CFOptionFlags, CFPropertyListFormat *,
62     CFErrorRef *);
63 typedef CFPropertyListRef (*CFPropertyListCreateFromXMLDataFuncTy)(
64     CFAllocatorRef, CFDataRef, CFOptionFlags, CFStringRef *);
65 typedef CFStringRef (*CFStringCreateWithCStringNoCopyFuncTy)(CFAllocatorRef,
66                                                              const char *,
67                                                              CFStringEncoding,
68                                                              CFAllocatorRef);
69 typedef const void *(*CFDictionaryGetValueFuncTy)(CFDictionaryRef,
70                                                   const void *);
71 typedef CFTypeID (*CFGetTypeIDFuncTy)(CFTypeRef);
72 typedef CFTypeID (*CFStringGetTypeIDFuncTy)(void);
73 typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex,
74                                             CFStringEncoding);
75 typedef void (*CFReleaseFuncTy)(CFTypeRef);
76
77 /* Find and parse the SystemVersion.plist file. */
78 static void parseSystemVersionPList(void *Unused) {
79   (void)Unused;
80   /* Load CoreFoundation dynamically */
81   const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
82   if (!NullAllocator)
83     return;
84   const CFAllocatorRef AllocatorNull = *(const CFAllocatorRef *)NullAllocator;
85   CFDataCreateWithBytesNoCopyFuncTy CFDataCreateWithBytesNoCopyFunc =
86       (CFDataCreateWithBytesNoCopyFuncTy)dlsym(RTLD_DEFAULT,
87                                                "CFDataCreateWithBytesNoCopy");
88   if (!CFDataCreateWithBytesNoCopyFunc)
89     return;
90   CFPropertyListCreateWithDataFuncTy CFPropertyListCreateWithDataFunc =
91       (CFPropertyListCreateWithDataFuncTy)dlsym(
92           RTLD_DEFAULT, "CFPropertyListCreateWithData");
93 /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
94  * will be NULL on earlier OS versions. */
95 #pragma clang diagnostic push
96 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
97   CFPropertyListCreateFromXMLDataFuncTy CFPropertyListCreateFromXMLDataFunc =
98       (CFPropertyListCreateFromXMLDataFuncTy)dlsym(
99           RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
100 #pragma clang diagnostic pop
101   /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
102    * might be NULL in future OS versions. */
103   if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
104     return;
105   CFStringCreateWithCStringNoCopyFuncTy CFStringCreateWithCStringNoCopyFunc =
106       (CFStringCreateWithCStringNoCopyFuncTy)dlsym(
107           RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
108   if (!CFStringCreateWithCStringNoCopyFunc)
109     return;
110   CFDictionaryGetValueFuncTy CFDictionaryGetValueFunc =
111       (CFDictionaryGetValueFuncTy)dlsym(RTLD_DEFAULT, "CFDictionaryGetValue");
112   if (!CFDictionaryGetValueFunc)
113     return;
114   CFGetTypeIDFuncTy CFGetTypeIDFunc =
115       (CFGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFGetTypeID");
116   if (!CFGetTypeIDFunc)
117     return;
118   CFStringGetTypeIDFuncTy CFStringGetTypeIDFunc =
119       (CFStringGetTypeIDFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
120   if (!CFStringGetTypeIDFunc)
121     return;
122   CFStringGetCStringFuncTy CFStringGetCStringFunc =
123       (CFStringGetCStringFuncTy)dlsym(RTLD_DEFAULT, "CFStringGetCString");
124   if (!CFStringGetCStringFunc)
125     return;
126   CFReleaseFuncTy CFReleaseFunc =
127       (CFReleaseFuncTy)dlsym(RTLD_DEFAULT, "CFRelease");
128   if (!CFReleaseFunc)
129     return;
130
131   char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
132
133 #if TARGET_OS_SIMULATOR
134   char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
135   if (!PListPathPrefix)
136     return;
137   char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
138   strcpy(FullPath, PListPathPrefix);
139   strcat(FullPath, PListPath);
140   PListPath = FullPath;
141 #endif
142   FILE *PropertyList = fopen(PListPath, "r");
143   if (!PropertyList)
144     return;
145
146   /* Dynamically allocated stuff. */
147   CFDictionaryRef PListRef = NULL;
148   CFDataRef FileContentsRef = NULL;
149   UInt8 *PListBuf = NULL;
150
151   fseek(PropertyList, 0, SEEK_END);
152   long PListFileSize = ftell(PropertyList);
153   if (PListFileSize < 0)
154     goto Fail;
155   rewind(PropertyList);
156
157   PListBuf = malloc((size_t)PListFileSize);
158   if (!PListBuf)
159     goto Fail;
160
161   size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
162   if (NumRead != (size_t)PListFileSize)
163     goto Fail;
164
165   /* Get the file buffer into CF's format. We pass in a null allocator here *
166    * because we free PListBuf ourselves */
167   FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
168       NULL, PListBuf, (CFIndex)NumRead, AllocatorNull);
169   if (!FileContentsRef)
170     goto Fail;
171
172   if (CFPropertyListCreateWithDataFunc)
173     PListRef = (*CFPropertyListCreateWithDataFunc)(
174         NULL, FileContentsRef, CF_PROPERTY_LIST_IMMUTABLE, NULL, NULL);
175   else
176     PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
177         NULL, FileContentsRef, CF_PROPERTY_LIST_IMMUTABLE, NULL);
178   if (!PListRef)
179     goto Fail;
180
181   CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
182       NULL, "ProductVersion", CF_STRING_ENCODING_ASCII, AllocatorNull);
183   if (!ProductVersion)
184     goto Fail;
185   CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
186   (*CFReleaseFunc)(ProductVersion);
187   if (!OpaqueValue ||
188       (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
189     goto Fail;
190
191   char VersionStr[32];
192   if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
193                                  sizeof(VersionStr), CF_STRING_ENCODING_UTF8))
194     goto Fail;
195   sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
196
197 Fail:
198   if (PListRef)
199     (*CFReleaseFunc)(PListRef);
200   if (FileContentsRef)
201     (*CFReleaseFunc)(FileContentsRef);
202   free(PListBuf);
203   fclose(PropertyList);
204 }
205
206 int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
207   /* Populate the global version variables, if they haven't already. */
208   dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
209
210   if (Major < GlobalMajor)
211     return 1;
212   if (Major > GlobalMajor)
213     return 0;
214   if (Minor < GlobalMinor)
215     return 1;
216   if (Minor > GlobalMinor)
217     return 0;
218   return Subminor <= GlobalSubminor;
219 }
220
221 #else
222
223 /* Silence an empty translation unit warning. */
224 typedef int unused;
225
226 #endif