]> git.proxmox.com Git - rustc.git/blame - src/libcompiler_builtins/compiler-rt/lib/builtins/os_version_check.c
New upstream version 1.25.0+dfsg1
[rustc.git] / src / libcompiler_builtins / compiler-rt / lib / builtins / os_version_check.c
CommitLineData
2c00a5a8
XL
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. */
28static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
29static dispatch_once_t DispatchOnceCounter;
30
31/* Find and parse the SystemVersion.plist file. */
32static 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
153Fail:
154 if (PListRef)
155 (*CFReleaseFunc)(PListRef);
156 if (FileContentsRef)
157 (*CFReleaseFunc)(FileContentsRef);
158 free(PListBuf);
159 fclose(PropertyList);
160}
161
162int32_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. */
176typedef int unused;
177
178#endif