this repo has no description
at fixPythonPipStalling 384 lines 8.0 kB view raw
1/* 2This file is part of Darling. 3 4Copyright (C) 2017 Lubos Dolezel 5 6Darling is free software: you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation, either version 3 of the License, or 9(at your option) any later version. 10 11Darling is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with Darling. If not, see <http://www.gnu.org/licenses/>. 18*/ 19#include <stdlib.h> 20#include <fcntl.h> 21#include <unistd.h> 22#include <stdbool.h> 23#include <sys/stat.h> 24#include <stdlib.h> 25#include <errno.h> 26#include <string.h> 27#include <dlfcn.h> 28#include <stdio.h> 29#include "xcselect.h" 30 31static char path_buffer[1024]; 32 33static const char* get_developer_dir_from_file(const char* file) 34{ 35 int fd = open(file, O_RDONLY); 36 if (fd == -1) 37 return NULL; 38 39 int len = read(fd, path_buffer, sizeof(path_buffer)-1); 40 if (len <= 0) 41 { 42 close(fd); 43 return NULL; 44 } 45 46 path_buffer[len] = 0; 47 close(fd); 48 49 return path_buffer; 50} 51 52const char* get_developer_dir_from_symlink(const char* link) 53{ 54 ssize_t len; 55 56 len = readlink(link, path_buffer, sizeof(path_buffer)-1); 57 if (len <= 0) 58 return NULL; 59 60 path_buffer[len] = 0; 61 return path_buffer; 62} 63 64static bool dir_exists(const char* dir) 65{ 66 struct stat st; 67 68 if (stat(dir, &st) != 0) 69 return false; 70 71 return S_ISDIR(st.st_mode); 72} 73 74static bool valid_dev_path(const char* path) 75{ 76 char buffer[1024]; 77 size_t length; 78 79 strcpy(buffer, path); 80 strcat(buffer, "/"); 81 82 length = strlen(buffer); 83 strcat(buffer, "usr/lib/libxcrun.dylib"); 84 if (access(buffer, F_OK) == 0) 85 return true; 86 87 buffer[length] = 0; 88 strcat(buffer, "usr/bin/xcrun"); 89 if (access(buffer, F_OK) == 0) 90 return true; 91 92 return false; 93} 94 95bool xcselect_find_developer_contents_from_path(const char* p, char* dst, bool* is_cmd_line, size_t dst_size) 96{ 97 size_t length; 98 99 if (*p != '/') 100 { 101 getcwd(dst, dst_size); 102 strcat(dst, "/"); 103 strcat(dst, p); 104 } 105 else 106 strlcpy(dst, p, dst_size); 107 108 length = strlen(dst); 109 if (valid_dev_path(dst)) 110 return true; 111 112 dst[length++] = '/'; 113 dst[length] = 0; 114 115 strcat(dst, "Library/Developer/CommandLineTools"); 116 if (valid_dev_path(dst)) 117 { 118 *is_cmd_line = true; 119 return true; 120 } 121 122 dst[length] = 0; 123 strcat(dst, "CommandLineTools"); 124 if (valid_dev_path(dst)) 125 { 126 *is_cmd_line = true; 127 return true; 128 } 129 130 dst[length] = 0; 131 strcat(dst, "Contents/Developer"); 132 if (valid_dev_path(dst)) 133 return true; 134 135 return false; 136} 137 138bool xcselect_get_developer_dir_path(char* path, size_t path_len, bool* is_cmd_line) 139{ 140 const char* p; 141 char* slash; 142 143 *is_cmd_line = false; 144 145 p = getenv("DEVELOPER_DIR"); 146 if (p) 147 { 148 if (xcselect_find_developer_contents_from_path(p, path_buffer, is_cmd_line, sizeof(path_buffer))) 149 { 150 p = path_buffer; 151 goto have_path; 152 } 153 } 154 155 p = get_developer_dir_from_symlink("/var/db/xcode_select_link"); 156 if (p) 157 goto have_path; 158 159 p = get_developer_dir_from_symlink("/usr/share/xcode-select/xcode_dir_link"); 160 if (p) 161 goto have_path; 162 163 p = get_developer_dir_from_file("/usr/share/xcode-select/xcode_dir_path"); 164 if (p) 165 goto have_path; 166 167 if (dir_exists("/Applications/Xcode.app")) 168 { 169 p = "/Applications/Xcode.app/Contents/Developer"; 170 goto have_path; 171 } 172 else if (dir_exists("/Library/Developer/CommandLineTools")) 173 { 174 p = "/Library/Developer/CommandLineTools"; 175 goto have_path; 176 } 177 else if (dir_exists("/Library/Developer/DarlingCLT")) 178 { 179 p = "/Library/Developer/DarlingCLT"; 180 *is_cmd_line = true; 181 goto have_path; 182 } 183 184 return false; 185 186have_path: 187 slash = strrchr(p, '/'); 188 if (slash != NULL) 189 { 190 if (strcmp(slash+1, "CommandLineTools") == 0) 191 *is_cmd_line = true; 192 } 193 194 strlcpy(path, p, path_len); 195 strlcat(path, "/", path_len); 196 return true; 197} 198 199 200int xcselect_invoke_xcrun(const char* tool, int argc, char* argv[], int flags) 201{ 202 char dev_dir[1024]; 203 bool is_cmdline; 204 205 if (xcselect_get_developer_dir_path(dev_dir, sizeof(dev_dir), &is_cmdline)) 206 { 207 char* buf = (char*) malloc(2048); 208 size_t length; 209 void* lib; 210 211 if (is_cmdline && (flags & XCSELECT_FLAG_REQUIRE_XCODE)) 212 { 213 fprintf(stderr, "xcrun: tool '%s' requires Xcode installation, command line tools are insufficient.\n", tool); 214 exit(1); 215 } 216 217 strcpy(buf, dev_dir); 218 if (buf[strlen(buf) - 1] != '/') 219 { 220 strcat(buf, "/"); 221 } 222 length = strlen(buf); 223 224 strcat(buf, "usr/lib/libxcrun.dylib"); 225 lib = dlopen(buf, RTLD_LAZY); 226 227 if (lib != NULL) 228 { 229 void(*fn)(const char*, int, char**, const char*); 230 231 *((void**)&fn) = dlsym(lib, "xcrun_main"); 232 if (!fn) 233 { 234 fprintf(stderr, "xcrun: broken libxcrun.dylib at '%s'\n", buf); 235 } 236 else 237 { 238 fn(tool, argc, argv, dev_dir); 239 fprintf(stderr, "xcrun: xcrun_main unexpectedly exited\n"); 240 } 241 } 242 else 243 { 244 char** argv2; 245 int j = 0; 246 247 buf[length] = 0; 248 strcat(buf, "usr/bin/xcrun"); 249 250 // +3: buf, tool, NULL 251 argv2 = (char**) __builtin_alloca((argc+3) * sizeof(char*)); 252 argv2[j++] = buf; 253 254 if (tool != NULL) 255 argv2[j++] = (char*) tool; 256 257 for (int i = 0; i < argc; i++, j++) 258 argv2[j] = argv[i]; 259 argv2[j] = NULL; 260 261 execv(buf, argv2); 262 fprintf(stderr, "xcrun: developer path '%s' is invalid, failed to execute '%s': %s\n", 263 dev_dir, buf, strerror(errno)); 264 } 265 } 266 else 267 { 268 if (dir_exists("/usr/libexec/DeveloperTools") && tool != NULL) 269 { 270 char* buf = __builtin_alloca(strlen(tool) + 30); 271 strcpy(buf, "/usr/libexec/DeveloperTools/"); 272 strcat(buf, tool); 273 274 if (access(buf, F_OK) == 0) 275 { 276 char** argv2 = (char **) __builtin_alloca((argc+1+1) * sizeof(char*)); 277 argv2[0] = buf; 278 for (int i = 0; i < argc; i++) 279 argv2[i+1] = argv[i]; 280 argv2[argc+1] = NULL; 281 282 execv(buf, argv2); 283 fprintf(stderr, "xcrun: failed to exec '%s': %s\n", buf, strerror(errno)); 284 exit(1); 285 } 286 } 287 288 fprintf(stderr, "xcrun: cannot find developer tools, set DEVELOPER_DIR if you are using a non-standard location.\n"); 289 } 290 291 exit(1); 292} 293 294struct __xcselect_manpaths 295{ 296 unsigned int count; 297 char** paths; 298}; 299 300void xcselect_manpaths_append(xcselect_manpaths* paths, const char* path) 301{ 302 paths->count++; 303 paths->paths = realloc(paths->paths, sizeof(char*) * paths->count); 304 paths->paths[paths->count - 1] = strdup(path); 305} 306 307xcselect_manpaths* xcselect_get_manpaths(const char* sdkname) 308{ 309 char path[1024]; 310 bool unused; 311 size_t len; 312 xcselect_manpaths* rv; 313 314 if (!xcselect_get_developer_dir_path(path, sizeof(path), &unused)) 315 return NULL; 316 317 len = strlen(path); 318 strcat(path, "usr/lib/libxcrun.dylib"); 319 320 rv = (xcselect_manpaths*) malloc(sizeof(*rv)); 321 memset(rv, 0, sizeof(*rv)); 322 323 if (access(path, F_OK) == 0) 324 { 325 void* module = dlopen(path, RTLD_LAZY); 326 void (*fn)(const char* devpath, const char* sdkname, void (^)(const char*)); 327 328 if (!module) 329 { 330 free(rv); 331 fprintf(stderr, "%s: error: cannot load libxcrun (%s)\n", getprogname(), dlerror()); 332 return NULL; 333 } 334 335 *((void**)&fn) = dlsym(module, "xcrun_iter_manpaths"); 336 337 if (fn != NULL) 338 { 339 path[len] = 0; 340 fn(path, sdkname, ^(const char* path) { 341 xcselect_manpaths_append(rv, path); 342 }); 343 } 344 345 dlclose(module); 346 } 347 348 // Add standard paths 349 path[len] = 0; 350 strcat(path, "usr/share/man"); 351 xcselect_manpaths_append(rv, path); 352 353 path[len] = 0; 354 strcat(path, "usr/llvm-gcc-4,2/share/man"); 355 xcselect_manpaths_append(rv, path); 356 357 path[len] = 0; 358 strcat(path, "Toolchains/XcodeDefault.xctoolchain/usr/share/man"); 359 xcselect_manpaths_append(rv, path); 360 361 return rv; 362} 363 364unsigned int xcselect_manpaths_get_num_paths(xcselect_manpaths* p) 365{ 366 return p->count; 367} 368 369const char* xcselect_manpaths_get_path(xcselect_manpaths* p, unsigned int idx) 370{ 371 if (idx < xcselect_manpaths_get_num_paths(p)) 372 return p->paths[idx]; 373 else 374 return NULL; 375} 376 377void xcselect_manpaths_free(xcselect_manpaths* p) 378{ 379 for (unsigned int i = 0; i < p->count; i++) 380 free(p->paths[i]); 381 free(p->paths); 382 free(p); 383} 384