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