• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
is_sep(char ch)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
reduce(char * dir)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
is_absolute(char * path)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
joinpath(char * buffer,char * stuff)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
isxfile(char * filename)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
copy_absolute(char * path,char * p)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
absolutize(char * path)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
set_volume(char * Dest,char * path)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
calculate_path(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 *
Py_GetPath(void)621 Py_GetPath(void)
622 {
623     if (!module_search_path)
624         calculate_path();
625     return module_search_path;
626 }
627 
628 char *
Py_GetPrefix(void)629 Py_GetPrefix(void)
630 {
631     if (!module_search_path)
632         calculate_path();
633     return prefix;
634 }
635 
636 char *
Py_GetExecPrefix(void)637 Py_GetExecPrefix(void)
638 {
639     if (!module_search_path)
640         calculate_path();
641     return exec_prefix;
642 }
643 
644 char *
Py_GetProgramFullPath(void)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