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
86static char   prefix[MAXPATHLEN+1];
87static char   exec_prefix[MAXPATHLEN+1];
88static char   progpath[MAXPATHLEN+1];
89static char  *module_search_path          = NULL;
90static char   lib_python[]                = LIBPYTHON;
91static 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**/
100static int
101is_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**/
113static void
114reduce(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*/
140static int
141is_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*/
177static void
178joinpath(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**/
230static int
231isxfile(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**/
270static void
271copy_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*/
297static void
298absolutize(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**/
313static void
314set_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**/
390static void
391calculate_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
620char *
621Py_GetPath(void)
622{
623    if (!module_search_path)
624        calculate_path();
625    return module_search_path;
626}
627
628char *
629Py_GetPrefix(void)
630{
631    if (!module_search_path)
632        calculate_path();
633    return prefix;
634}
635
636char *
637Py_GetExecPrefix(void)
638{
639    if (!module_search_path)
640        calculate_path();
641    return exec_prefix;
642}
643
644char *
645Py_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