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
80static char   prefix[MAXPATHLEN+1];
81static char   exec_prefix[MAXPATHLEN+1];
82static char   progpath[MAXPATHLEN+1];
83static char  *module_search_path          = NULL;
84static char   lib_python[]                = LIBPYTHON;
85static 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**/
94static int
95is_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**/
111static void
112reduce(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**/
128static int
129isfile(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**/
151static int
152ismodule(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**/
176static int
177isdir(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*/
209static int
210is_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*/
246static void
247joinpath(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**/
299static int
300isxfile(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**/
339static void
340copy_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*/
366static void
367absolutize(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**/
382static void
383set_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**/
459static void
460calculate_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
689char *
690Py_GetPath(void)
691{
692    if (!module_search_path)
693        calculate_path();
694    return module_search_path;
695}
696
697char *
698Py_GetPrefix(void)
699{
700    if (!module_search_path)
701        calculate_path();
702    return prefix;
703}
704
705char *
706Py_GetExecPrefix(void)
707{
708    if (!module_search_path)
709        calculate_path();
710    return exec_prefix;
711}
712
713char *
714Py_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