1 /** @file 2 Return the initial module search path. 3 4 This file is based upon the Modules/getpath.c file from the Python distribution 5 but has had everything not exactly necessary for operation on EDK II stripped 6 out. 7 8 Search in specified locations for the associated Python libraries. 9 10 For the EDK II, UEFI, implementation of Python, PREFIX and EXEC_PREFIX 11 are set as follows: 12 PREFIX = /Efi/StdLib 13 EXEC_PREFIX = PREFIX 14 15 The volume is assumed to be the current volume when Python was started. 16 17 Py_GetPath returns module_search_path. 18 Py_GetPrefix returns PREFIX 19 Py_GetExec_Prefix returns PREFIX 20 Py_GetProgramFullPath returns the full path to the python executable. 21 22 These are built dynamically so that the proper volume name can be prefixed 23 to the paths. 24 25 The following final paths (for Python 2.7.10) are assumed: 26 /Efi/Tools/Python.efi The Python executable. 27 /Efi/StdLib/lib/python27.10 The version dependent Python modules. 28 /Efi/StdLib/lib/python.27 The version independent Python modules. 29 /Efi/StdLib/lib/python27.10/lib-dynload Dynamically loadable Python extension modules. 30 31 Copyright (c) 2015, Daryl McDaniel. All rights reserved.<BR> 32 Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR> 33 This program and the accompanying materials are licensed and made available under 34 the terms and conditions of the BSD License that accompanies this distribution. 35 The full text of the license may be found at 36 http://opensource.org/licenses/bsd-license. 37 38 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 39 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 40 **/ 41 #include <Python.h> 42 #include <osdefs.h> 43 #include <ctype.h> 44 45 #define SIFY_I( x ) #x 46 #define SIFY( y ) SIFY_I( y ) 47 48 /* VERSION must be at least two characters long. */ 49 #ifndef VERSION 50 #define VERSION SIFY(PY_MAJOR_VERSION) SIFY(PY_MINOR_VERSION) 51 #endif 52 53 #ifndef VPATH 54 #define VPATH "." 55 #endif 56 57 /* Search path entry delimiter */ 58 #ifdef DELIM 59 #define sDELIM ";" 60 #endif 61 62 #ifndef PREFIX 63 #define PREFIX "/Efi/StdLib" 64 #endif 65 66 #ifndef EXEC_PREFIX 67 #define EXEC_PREFIX PREFIX 68 #endif 69 70 #ifndef LIBPYTHON 71 #define LIBPYTHON "lib/python" VERSION "." SIFY(PY_MICRO_VERSION) 72 #endif 73 74 #ifndef PYTHONPATH 75 #define PYTHONPATH LIBPYTHON 76 #endif 77 78 #ifndef LANDMARK 79 #define LANDMARK "os.py" 80 #endif 81 82 #ifdef __cplusplus 83 extern "C" { 84 #endif 85 86 static char prefix[MAXPATHLEN+1]; 87 static char exec_prefix[MAXPATHLEN+1]; 88 static char progpath[MAXPATHLEN+1]; 89 static char *module_search_path = NULL; 90 static char lib_python[] = LIBPYTHON; 91 static char volume_name[32] = { 0 }; 92 93 /** Determine if "ch" is a separator character. 94 95 @param[in] ch The character to test. 96 97 @retval TRUE ch is a separator character. 98 @retval FALSE ch is NOT a separator character. 99 **/ 100 static int 101 is_sep(char ch) 102 { 103 return ch == SEP || ch == ALTSEP; 104 } 105 106 /** Reduce a path by its last element. 107 108 The last element (everything to the right of the last separator character) 109 in the path, dir, is removed from the path. Parameter dir is modified in place. 110 111 @param[in,out] dir Pointer to the path to modify. 112 **/ 113 static void 114 reduce(char *dir) 115 { 116 size_t i = strlen(dir); 117 while (i > 0 && !is_sep(dir[i])) 118 --i; 119 dir[i] = '\0'; 120 } 121 122 /** Determine if a path is absolute, or not. 123 An absolute path consists of a volume name, "VOL:", followed by a rooted path, 124 "/path/elements". If both of these components are present, the path is absolute. 125 126 Let P be a pointer to the path to test. 127 Let A be a pointer to the first ':' in P. 128 Let B be a pointer to the first '/' or '\\' in P. 129 130 If A and B are not NULL 131 If (A-P+1) == (B-P) then the path is absolute. 132 Otherwise, the path is NOT absolute. 133 134 @param[in] path The path to test. 135 136 @retval -1 Path is absolute but lacking volume name. 137 @retval 0 Path is NOT absolute. 138 @retval 1 Path is absolute. 139 */ 140 static int 141 is_absolute(char *path) 142 { 143 char *A; 144 char *B; 145 146 A = strchr(path, ':'); 147 B = strpbrk(path, "/\\"); 148 149 if(B != NULL) { 150 if(A == NULL) { 151 if(B == path) { 152 return -1; 153 } 154 } 155 else { 156 if(((A - path) + 1) == (B - path)) { 157 return 1; 158 } 159 } 160 } 161 return 0; 162 } 163 164 165 /** Add a path component, by appending stuff to buffer. 166 buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a 167 NUL-terminated string with no more than MAXPATHLEN characters (not counting 168 the trailing NUL). It's a fatal error if it contains a string longer than 169 that (callers must be careful!). If these requirements are met, it's 170 guaranteed that buffer will still be a NUL-terminated string with no more 171 than MAXPATHLEN characters at exit. If stuff is too long, only as much of 172 stuff as fits will be appended. 173 174 @param[in,out] buffer The path to be extended. 175 @param[in] stuff The stuff to join onto the path. 176 */ 177 static void 178 joinpath(char *buffer, char *stuff) 179 { 180 size_t n, k; 181 182 k = 0; 183 if (is_absolute(stuff) == 1) { 184 n = 0; 185 } 186 else { 187 n = strlen(buffer); 188 if(n == 0) { 189 strncpy(buffer, volume_name, MAXPATHLEN); 190 n = strlen(buffer); 191 } 192 /* We must not use an else clause here because we want to test n again. 193 volume_name may have been empty. 194 */ 195 if (n > 0 && n < MAXPATHLEN) { 196 if(!is_sep(buffer[n-1])) { 197 buffer[n++] = SEP; 198 } 199 if(is_sep(stuff[0])) ++stuff; 200 } 201 } 202 if (n > MAXPATHLEN) 203 Py_FatalError("buffer overflow in getpath.c's joinpath()"); 204 k = strlen(stuff); 205 if (n + k > MAXPATHLEN) 206 k = MAXPATHLEN - n; 207 strncpy(buffer+n, stuff, k); 208 buffer[n+k] = '\0'; 209 } 210 211 /** Is filename an executable file? 212 213 An executable file: 214 1) exists 215 2) is a file, not a directory 216 3) has a name ending with ".efi" 217 4) Only has a single '.' in the name. 218 219 If basename(filename) does not contain a '.', append ".efi" to filename 220 If filename ends in ".efi", it is executable, else it isn't. 221 222 This routine is used to when searching for the file named by argv[0]. 223 As such, there is no need to search for extensions other than ".efi". 224 225 @param[in] filename The name of the file to test. It may, or may not, have an extension. 226 227 @retval 0 filename already has a path other than ".efi", or it doesn't exist, or is a directory. 228 @retval 1 filename refers to an executable file. 229 **/ 230 static int 231 isxfile(char *filename) 232 { 233 struct stat buf; 234 char *bn; 235 char *newbn; 236 int bnlen; 237 238 bn = basename(filename); // Separate off the file name component 239 reduce(filename); // and isolate the path component 240 bnlen = strlen(bn); 241 newbn = strrchr(bn, '.'); // Does basename contain a period? 242 if(newbn == NULL) { // Does NOT contain a period. 243 newbn = &bn[bnlen]; 244 strncpyX(newbn, ".efi", MAXPATHLEN - bnlen); // append ".efi" to basename 245 bnlen += 4; 246 } 247 else if(strcmp(newbn, ".efi") != 0) { 248 return 0; // File can not be executable. 249 } 250 joinpath(filename, bn); // Stitch path and file name back together 251 252 if (stat(filename, &buf) != 0) { // Now, verify that file exists 253 return 0; 254 } 255 if(S_ISDIR(buf.st_mode)) { // And it is not a directory. 256 return 0; 257 } 258 259 return 1; 260 } 261 262 /** Copy p into path, ensuring that the result is an absolute path. 263 264 copy_absolute requires that path be allocated at least 265 MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. 266 267 @param[out] path Destination to receive the absolute path. 268 @param[in] p Path to be tested and possibly converted. 269 **/ 270 static void 271 copy_absolute(char *path, char *p) 272 { 273 if (is_absolute(p) == 1) 274 strcpy(path, p); 275 else { 276 if (!getcwd(path, MAXPATHLEN)) { 277 /* unable to get the current directory */ 278 if(volume_name[0] != 0) { 279 strcpy(path, volume_name); 280 joinpath(path, p); 281 } 282 else 283 strcpy(path, p); 284 return; 285 } 286 if (p[0] == '.' && is_sep(p[1])) 287 p += 2; 288 joinpath(path, p); 289 } 290 } 291 292 /** Modify path so that the result is an absolute path. 293 absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. 294 295 @param[in,out] path The path to be made absolute. 296 */ 297 static void 298 absolutize(char *path) 299 { 300 char buffer[MAXPATHLEN + 1]; 301 302 if (is_absolute(path) == 1) 303 return; 304 copy_absolute(buffer, path); 305 strcpy(path, buffer); 306 } 307 308 /** Extract the volume name from a path. 309 310 @param[out] Dest Pointer to location in which to store the extracted volume name. 311 @param[in] path Pointer to the path to extract the volume name from. 312 **/ 313 static void 314 set_volume(char *Dest, char *path) 315 { 316 size_t VolLen; 317 318 if(is_absolute(path)) { 319 VolLen = strcspn(path, "/\\:"); 320 if((VolLen != 0) && (path[VolLen] == ':')) { 321 (void) strncpyX(Dest, path, VolLen + 1); 322 } 323 } 324 } 325 326 327 /** Determine paths. 328 329 Two directories must be found, the platform independent directory 330 (prefix), containing the common .py and .pyc files, and the platform 331 dependent directory (exec_prefix), containing the shared library 332 modules. Note that prefix and exec_prefix are the same directory 333 for UEFI installations. 334 335 Separate searches are carried out for prefix and exec_prefix. 336 Each search tries a number of different locations until a ``landmark'' 337 file or directory is found. If no prefix or exec_prefix is found, a 338 warning message is issued and the preprocessor defined PREFIX and 339 EXEC_PREFIX are used (even though they may not work); python carries on 340 as best as is possible, but some imports may fail. 341 342 Before any searches are done, the location of the executable is 343 determined. If argv[0] has one or more slashes in it, it is used 344 unchanged. Otherwise, it must have been invoked from the shell's path, 345 so we search %PATH% for the named executable and use that. If the 346 executable was not found on %PATH% (or there was no %PATH% environment 347 variable), the original argv[0] string is used. 348 349 Finally, argv0_path is set to the directory containing the executable 350 (i.e. the last component is stripped). 351 352 With argv0_path in hand, we perform a number of steps. The same steps 353 are performed for prefix and for exec_prefix, but with a different 354 landmark. 355 356 The prefix landmark will always be lib/python.VERSION/os.py and the 357 exec_prefix will always be lib/python.VERSION/dynaload, where VERSION 358 is Python's version number as defined at the beginning of this file. 359 360 First. See if the %PYTHONHOME% environment variable points to the 361 installed location of the Python libraries. If %PYTHONHOME% is set, then 362 it points to prefix and exec_prefix. %PYTHONHOME% can be a single 363 directory, which is used for both, or the prefix and exec_prefix 364 directories separated by the DELIM character. 365 366 Next. Search the directories pointed to by the preprocessor variables 367 PREFIX and EXEC_PREFIX. These paths are prefixed with the volume name 368 extracted from argv0_path. The volume names correspond to the UEFI 369 shell "map" names. 370 371 That's it! 372 373 Well, almost. Once we have determined prefix and exec_prefix, the 374 preprocessor variable PYTHONPATH is used to construct a path. Each 375 relative path on PYTHONPATH is prefixed with prefix. Then the directory 376 containing the shared library modules is appended. The environment 377 variable $PYTHONPATH is inserted in front of it all. Finally, the 378 prefix and exec_prefix globals are tweaked so they reflect the values 379 expected by other code, by stripping the "lib/python$VERSION/..." stuff 380 off. This seems to make more sense given that currently the only 381 known use of sys.prefix and sys.exec_prefix is for the ILU installation 382 process to find the installed Python tree. 383 384 The final, fully resolved, paths should look something like: 385 fs0:/Efi/Tools/python.efi 386 fs0:/Efi/StdLib/lib/python27 387 fs0:/Efi/StdLib/lib/python27/dynaload 388 389 **/ 390 static void 391 calculate_path(void) 392 { 393 extern char *Py_GetProgramName(void); 394 395 static char delimiter[2] = {DELIM, '\0'}; 396 static char separator[2] = {SEP, '\0'}; 397 char *pythonpath = PYTHONPATH; 398 char *rtpypath = Py_GETENV("PYTHONPATH"); 399 //char *home = Py_GetPythonHome(); 400 char *path = getenv("path"); 401 char *prog = Py_GetProgramName(); 402 char argv0_path[MAXPATHLEN+1]; 403 char zip_path[MAXPATHLEN+1]; 404 char *buf; 405 size_t bufsz; 406 size_t prefixsz; 407 char *defpath; 408 409 410 /* ########################################################################### 411 Determine path to the Python.efi binary. 412 Produces progpath, argv0_path, and volume_name. 413 ########################################################################### */ 414 415 /* If there is no slash in the argv0 path, then we have to 416 * assume python is on the user's $PATH, since there's no 417 * other way to find a directory to start the search from. If 418 * $PATH isn't exported, you lose. 419 */ 420 if (strchr(prog, SEP)) 421 strncpy(progpath, prog, MAXPATHLEN); 422 else if (path) { 423 while (1) { 424 char *delim = strchr(path, DELIM); 425 426 if (delim) { 427 size_t len = delim - path; 428 if (len > MAXPATHLEN) 429 len = MAXPATHLEN; 430 strncpy(progpath, path, len); 431 *(progpath + len) = '\0'; 432 } 433 else 434 strncpy(progpath, path, MAXPATHLEN); 435 436 joinpath(progpath, prog); 437 if (isxfile(progpath)) 438 break; 439 440 if (!delim) { 441 progpath[0] = '\0'; 442 break; 443 } 444 path = delim + 1; 445 } 446 } 447 else 448 progpath[0] = '\0'; 449 if ( (!is_absolute(progpath)) && (progpath[0] != '\0') ) 450 absolutize(progpath); 451 strncpy(argv0_path, progpath, MAXPATHLEN); 452 argv0_path[MAXPATHLEN] = '\0'; 453 set_volume(volume_name, argv0_path); 454 455 reduce(argv0_path); 456 /* At this point, argv0_path is guaranteed to be less than 457 MAXPATHLEN bytes long. 458 */ 459 460 /* ########################################################################### 461 Build the FULL prefix string, including volume name. 462 This is the full path to the platform independent libraries. 463 ########################################################################### */ 464 465 strncpy(prefix, volume_name, MAXPATHLEN); 466 joinpath(prefix, PREFIX); 467 joinpath(prefix, lib_python); 468 469 /* ########################################################################### 470 Build the FULL path to the zipped-up Python library. 471 ########################################################################### */ 472 473 strncpy(zip_path, prefix, MAXPATHLEN); 474 zip_path[MAXPATHLEN] = '\0'; 475 reduce(zip_path); 476 joinpath(zip_path, "python00.zip"); 477 bufsz = strlen(zip_path); /* Replace "00" with version */ 478 zip_path[bufsz - 6] = VERSION[0]; 479 zip_path[bufsz - 5] = VERSION[1]; 480 481 /* ########################################################################### 482 Build the FULL path to dynamically loadable libraries. 483 ########################################################################### */ 484 485 strncpy(exec_prefix, volume_name, MAXPATHLEN); // "fs0:" 486 joinpath(exec_prefix, EXEC_PREFIX); // "fs0:/Efi/StdLib" 487 joinpath(exec_prefix, lib_python); // "fs0:/Efi/StdLib/lib/python.27" 488 joinpath(exec_prefix, "lib-dynload"); // "fs0:/Efi/StdLib/lib/python.27/lib-dynload" 489 490 /* ########################################################################### 491 Build the module search path. 492 ########################################################################### */ 493 494 /* Reduce prefix and exec_prefix to their essence, 495 * e.g. /usr/local/lib/python1.5 is reduced to /usr/local. 496 * If we're loading relative to the build directory, 497 * return the compiled-in defaults instead. 498 */ 499 reduce(prefix); 500 reduce(prefix); 501 /* The prefix is the root directory, but reduce() chopped 502 * off the "/". */ 503 if (!prefix[0]) { 504 strcpy(prefix, volume_name); 505 } 506 bufsz = strlen(prefix); 507 if(prefix[bufsz-1] == ':') { // if prefix consists solely of a volume_name 508 prefix[bufsz] = SEP; // then append SEP indicating the root directory 509 prefix[bufsz+1] = 0; // and ensure the new string is terminated 510 } 511 512 /* Calculate size of return buffer. 513 */ 514 defpath = pythonpath; 515 bufsz = 0; 516 517 if (rtpypath) 518 bufsz += strlen(rtpypath) + 1; 519 520 prefixsz = strlen(prefix) + 1; 521 522 while (1) { 523 char *delim = strchr(defpath, DELIM); 524 525 if (is_absolute(defpath) == 0) 526 /* Paths are relative to prefix */ 527 bufsz += prefixsz; 528 529 if (delim) 530 bufsz += delim - defpath + 1; 531 else { 532 bufsz += strlen(defpath) + 1; 533 break; 534 } 535 defpath = delim + 1; 536 } 537 538 bufsz += strlen(zip_path) + 1; 539 bufsz += strlen(exec_prefix) + 1; 540 541 /* This is the only malloc call in this file */ 542 buf = (char *)PyMem_Malloc(bufsz); 543 544 if (buf == NULL) { 545 /* We can't exit, so print a warning and limp along */ 546 fprintf(stderr, "Not enough memory for dynamic PYTHONPATH.\n"); 547 fprintf(stderr, "Using default static PYTHONPATH.\n"); 548 module_search_path = PYTHONPATH; 549 } 550 else { 551 /* Run-time value of $PYTHONPATH goes first */ 552 if (rtpypath) { 553 strcpy(buf, rtpypath); 554 strcat(buf, delimiter); 555 } 556 else 557 buf[0] = '\0'; 558 559 /* Next is the default zip path */ 560 strcat(buf, zip_path); 561 strcat(buf, delimiter); 562 563 /* Next goes merge of compile-time $PYTHONPATH with 564 * dynamically located prefix. 565 */ 566 defpath = pythonpath; 567 while (1) { 568 char *delim = strchr(defpath, DELIM); 569 570 if (is_absolute(defpath) != 1) { 571 strcat(buf, prefix); 572 strcat(buf, separator); 573 } 574 575 if (delim) { 576 size_t len = delim - defpath + 1; 577 size_t end = strlen(buf) + len; 578 strncat(buf, defpath, len); 579 *(buf + end) = '\0'; 580 } 581 else { 582 strcat(buf, defpath); 583 break; 584 } 585 defpath = delim + 1; 586 } 587 strcat(buf, delimiter); 588 589 /* Finally, on goes the directory for dynamic-load modules */ 590 strcat(buf, exec_prefix); 591 592 /* And publish the results */ 593 module_search_path = buf; 594 } 595 /* At this point, exec_prefix is set to VOL:/Efi/StdLib/lib/python.27/dynalib. 596 We want to get back to the root value, so we have to remove the final three 597 segments to get VOL:/Efi/StdLib. Because we don't know what VOL is, and 598 EXEC_PREFIX is also indeterminate, we just remove the three final segments. 599 */ 600 reduce(exec_prefix); 601 reduce(exec_prefix); 602 reduce(exec_prefix); 603 if (!exec_prefix[0]) { 604 strcpy(exec_prefix, volume_name); 605 } 606 bufsz = strlen(exec_prefix); 607 if(exec_prefix[bufsz-1] == ':') { 608 exec_prefix[bufsz] = SEP; 609 exec_prefix[bufsz+1] = 0; 610 } 611 if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: module_search_path = \"%s\"\n", __func__, __LINE__, module_search_path); 612 if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: prefix = \"%s\"\n", __func__, __LINE__, prefix); 613 if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: exec_prefix = \"%s\"\n", __func__, __LINE__, exec_prefix); 614 if (Py_VerboseFlag) PySys_WriteStderr("%s[%d]: progpath = \"%s\"\n", __func__, __LINE__, progpath); 615 } 616 617 618 /* External interface */ 619 620 char * 621 Py_GetPath(void) 622 { 623 if (!module_search_path) 624 calculate_path(); 625 return module_search_path; 626 } 627 628 char * 629 Py_GetPrefix(void) 630 { 631 if (!module_search_path) 632 calculate_path(); 633 return prefix; 634 } 635 636 char * 637 Py_GetExecPrefix(void) 638 { 639 if (!module_search_path) 640 calculate_path(); 641 return exec_prefix; 642 } 643 644 char * 645 Py_GetProgramFullPath(void) 646 { 647 if (!module_search_path) 648 calculate_path(); 649 return progpath; 650 } 651 652 653 #ifdef __cplusplus 654 } 655 #endif 656 657