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