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