]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/builtins/os_version_check.c
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r304149, and update
[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 <CoreFoundation/CoreFoundation.h>
19 #include <dispatch/dispatch.h>
20 #include <TargetConditionals.h>
21 #include <dlfcn.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 /* These three variables hold the host's OS version. */
28 static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
29 static dispatch_once_t DispatchOnceCounter;
30
31 /* Find and parse the SystemVersion.plist file. */
32 static void parseSystemVersionPList(void *Unused) {
33   (void)Unused;
34   /* Load CoreFoundation dynamically */
35   const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
36   if (!NullAllocator)
37     return;
38   const CFAllocatorRef kCFAllocatorNull =
39       *(const CFAllocatorRef *)NullAllocator;
40   typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc =
41       (typeof(CFDataCreateWithBytesNoCopy) *)dlsym(
42           RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy");
43   if (!CFDataCreateWithBytesNoCopyFunc)
44     return;
45   typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc =
46       (typeof(CFPropertyListCreateWithData) *)dlsym(
47           RTLD_DEFAULT, "CFPropertyListCreateWithData");
48   /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
49    * will be NULL on earlier OS versions. */
50 #pragma clang diagnostic push
51 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
52   typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc =
53       (typeof(CFPropertyListCreateFromXMLData) *)dlsym(
54           RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
55 #pragma clang diagnostic pop
56   /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
57    * might be NULL in future OS versions. */
58   if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
59     return;
60   typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc =
61       (typeof(CFStringCreateWithCStringNoCopy) *)dlsym(
62           RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
63   if (!CFStringCreateWithCStringNoCopyFunc)
64     return;
65   typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc =
66       (typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT,
67                                             "CFDictionaryGetValue");
68   if (!CFDictionaryGetValueFunc)
69     return;
70   typeof(CFGetTypeID) *CFGetTypeIDFunc =
71       (typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID");
72   if (!CFGetTypeIDFunc)
73     return;
74   typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc =
75       (typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
76   if (!CFStringGetTypeIDFunc)
77     return;
78   typeof(CFStringGetCString) *CFStringGetCStringFunc =
79       (typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString");
80   if (!CFStringGetCStringFunc)
81     return;
82   typeof(CFRelease) *CFReleaseFunc =
83       (typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease");
84   if (!CFReleaseFunc)
85     return;
86
87   char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
88
89 #if TARGET_OS_SIMULATOR
90   char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
91   if (!PListPathPrefix)
92     return;
93   char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
94   strcpy(FullPath, PListPathPrefix);
95   strcat(FullPath, PListPath);
96   PListPath = FullPath;
97 #endif
98   FILE *PropertyList = fopen(PListPath, "r");
99   if (!PropertyList)
100     return;
101
102   /* Dynamically allocated stuff. */
103   CFDictionaryRef PListRef = NULL;
104   CFDataRef FileContentsRef = NULL;
105   UInt8 *PListBuf = NULL;
106
107   fseek(PropertyList, 0, SEEK_END);
108   long PListFileSize = ftell(PropertyList);
109   if (PListFileSize < 0)
110     goto Fail;
111   rewind(PropertyList);
112
113   PListBuf = malloc((size_t)PListFileSize);
114   if (!PListBuf)
115     goto Fail;
116
117   size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
118   if (NumRead != (size_t)PListFileSize)
119     goto Fail;
120
121   /* Get the file buffer into CF's format. We pass in a null allocator here *
122    * because we free PListBuf ourselves */
123   FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
124       NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
125   if (!FileContentsRef)
126     goto Fail;
127
128   if (CFPropertyListCreateWithDataFunc)
129     PListRef = (*CFPropertyListCreateWithDataFunc)(
130         NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
131   else
132     PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
133         NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
134   if (!PListRef)
135     goto Fail;
136
137   CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
138       NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
139   if (!ProductVersion)
140     goto Fail;
141   CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
142   (*CFReleaseFunc)(ProductVersion);
143   if (!OpaqueValue ||
144       (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
145     goto Fail;
146
147   char VersionStr[32];
148   if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
149                                  sizeof(VersionStr), kCFStringEncodingUTF8))
150     goto Fail;
151   sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
152
153 Fail:
154   if (PListRef)
155     (*CFReleaseFunc)(PListRef);
156   if (FileContentsRef)
157     (*CFReleaseFunc)(FileContentsRef);
158   free(PListBuf);
159   fclose(PropertyList);
160 }
161
162 int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
163   /* Populate the global version variables, if they haven't already. */
164   dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
165
166   if (Major < GlobalMajor) return 1;
167   if (Major > GlobalMajor) return 0;
168   if (Minor < GlobalMinor) return 1;
169   if (Minor > GlobalMinor) return 0;
170   return Subminor <= GlobalSubminor;
171 }
172
173 #else
174
175 /* Silence an empty translation unit warning. */
176 typedef int unused;
177
178 #endif