• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Return the initial module search path. */
2 
3 #include "Python.h"
4 #include "internal/pystate.h"
5 #include "osdefs.h"
6 
7 #include <sys/types.h>
8 #include <string.h>
9 
10 #ifdef __APPLE__
11 #  include <mach-o/dyld.h>
12 #endif
13 
14 /* Search in some common locations for the associated Python libraries.
15  *
16  * Two directories must be found, the platform independent directory
17  * (prefix), containing the common .py and .pyc files, and the platform
18  * dependent directory (exec_prefix), containing the shared library
19  * modules.  Note that prefix and exec_prefix can be the same directory,
20  * but for some installations, they are different.
21  *
22  * Py_GetPath() carries out separate searches for prefix and exec_prefix.
23  * Each search tries a number of different locations until a ``landmark''
24  * file or directory is found.  If no prefix or exec_prefix is found, a
25  * warning message is issued and the preprocessor defined PREFIX and
26  * EXEC_PREFIX are used (even though they will not work); python carries on
27  * as best as is possible, but most imports will fail.
28  *
29  * Before any searches are done, the location of the executable is
30  * determined.  If argv[0] has one or more slashes in it, it is used
31  * unchanged.  Otherwise, it must have been invoked from the shell's path,
32  * so we search $PATH for the named executable and use that.  If the
33  * executable was not found on $PATH (or there was no $PATH environment
34  * variable), the original argv[0] string is used.
35  *
36  * Next, the executable location is examined to see if it is a symbolic
37  * link.  If so, the link is chased (correctly interpreting a relative
38  * pathname if one is found) and the directory of the link target is used.
39  *
40  * Finally, argv0_path is set to the directory containing the executable
41  * (i.e. the last component is stripped).
42  *
43  * With argv0_path in hand, we perform a number of steps.  The same steps
44  * are performed for prefix and for exec_prefix, but with a different
45  * landmark.
46  *
47  * Step 1. Are we running python out of the build directory?  This is
48  * checked by looking for a different kind of landmark relative to
49  * argv0_path.  For prefix, the landmark's path is derived from the VPATH
50  * preprocessor variable (taking into account that its value is almost, but
51  * not quite, what we need).  For exec_prefix, the landmark is
52  * pybuilddir.txt.  If the landmark is found, we're done.
53  *
54  * For the remaining steps, the prefix landmark will always be
55  * lib/python$VERSION/os.py and the exec_prefix will always be
56  * lib/python$VERSION/lib-dynload, where $VERSION is Python's version
57  * number as supplied by the Makefile.  Note that this means that no more
58  * build directory checking is performed; if the first step did not find
59  * the landmarks, the assumption is that python is running from an
60  * installed setup.
61  *
62  * Step 2. See if the $PYTHONHOME environment variable points to the
63  * installed location of the Python libraries.  If $PYTHONHOME is set, then
64  * it points to prefix and exec_prefix.  $PYTHONHOME can be a single
65  * directory, which is used for both, or the prefix and exec_prefix
66  * directories separated by a colon.
67  *
68  * Step 3. Try to find prefix and exec_prefix relative to argv0_path,
69  * backtracking up the path until it is exhausted.  This is the most common
70  * step to succeed.  Note that if prefix and exec_prefix are different,
71  * exec_prefix is more likely to be found; however if exec_prefix is a
72  * subdirectory of prefix, both will be found.
73  *
74  * Step 4. Search the directories pointed to by the preprocessor variables
75  * PREFIX and EXEC_PREFIX.  These are supplied by the Makefile but can be
76  * passed in as options to the configure script.
77  *
78  * That's it!
79  *
80  * Well, almost.  Once we have determined prefix and exec_prefix, the
81  * preprocessor variable PYTHONPATH is used to construct a path.  Each
82  * relative path on PYTHONPATH is prefixed with prefix.  Then the directory
83  * containing the shared library modules is appended.  The environment
84  * variable $PYTHONPATH is inserted in front of it all.  Finally, the
85  * prefix and exec_prefix globals are tweaked so they reflect the values
86  * expected by other code, by stripping the "lib/python$VERSION/..." stuff
87  * off.  If either points to the build directory, the globals are reset to
88  * the corresponding preprocessor variables (so sys.prefix will reflect the
89  * installation location, even though sys.path points into the build
90  * directory).  This seems to make more sense given that currently the only
91  * known use of sys.prefix and sys.exec_prefix is for the ILU installation
92  * process to find the installed Python tree.
93  *
94  * An embedding application can use Py_SetPath() to override all of
95  * these authomatic path computations.
96  *
97  * NOTE: Windows MSVC builds use PC/getpathp.c instead!
98  */
99 
100 #ifdef __cplusplus
101 extern "C" {
102 #endif
103 
104 
105 #if !defined(PREFIX) || !defined(EXEC_PREFIX) || !defined(VERSION) || !defined(VPATH)
106 #error "PREFIX, EXEC_PREFIX, VERSION, and VPATH must be constant defined"
107 #endif
108 
109 #ifndef LANDMARK
110 #define LANDMARK L"os.py"
111 #endif
112 
113 #define DECODE_LOCALE_ERR(NAME, LEN) \
114     ((LEN) == (size_t)-2) \
115      ? _Py_INIT_USER_ERR("cannot decode " NAME) \
116      : _Py_INIT_NO_MEMORY()
117 
118 typedef struct {
119     wchar_t *path_env;                 /* PATH environment variable */
120 
121     wchar_t *pythonpath;               /* PYTHONPATH define */
122     wchar_t *prefix;                   /* PREFIX define */
123     wchar_t *exec_prefix;              /* EXEC_PREFIX define */
124 
125     wchar_t *lib_python;               /* "lib/pythonX.Y" */
126     wchar_t argv0_path[MAXPATHLEN+1];
127     wchar_t zip_path[MAXPATHLEN+1];    /* ".../lib/pythonXY.zip" */
128 
129     int prefix_found;         /* found platform independent libraries? */
130     int exec_prefix_found;    /* found the platform dependent libraries? */
131 } PyCalculatePath;
132 
133 static const wchar_t delimiter[2] = {DELIM, '\0'};
134 static const wchar_t separator[2] = {SEP, '\0'};
135 
136 
137 /* Get file status. Encode the path to the locale encoding. */
138 static int
_Py_wstat(const wchar_t * path,struct stat * buf)139 _Py_wstat(const wchar_t* path, struct stat *buf)
140 {
141     int err;
142     char *fname;
143     fname = _Py_EncodeLocaleRaw(path, NULL);
144     if (fname == NULL) {
145         errno = EINVAL;
146         return -1;
147     }
148     err = stat(fname, buf);
149     PyMem_RawFree(fname);
150     return err;
151 }
152 
153 
154 static void
reduce(wchar_t * dir)155 reduce(wchar_t *dir)
156 {
157     size_t i = wcslen(dir);
158     while (i > 0 && dir[i] != SEP)
159         --i;
160     dir[i] = '\0';
161 }
162 
163 
164 static int
isfile(wchar_t * filename)165 isfile(wchar_t *filename)          /* Is file, not directory */
166 {
167     struct stat buf;
168     if (_Py_wstat(filename, &buf) != 0) {
169         return 0;
170     }
171     if (!S_ISREG(buf.st_mode)) {
172         return 0;
173     }
174     return 1;
175 }
176 
177 
178 static int
ismodule(wchar_t * filename)179 ismodule(wchar_t *filename)        /* Is module -- check for .pyc too */
180 {
181     if (isfile(filename)) {
182         return 1;
183     }
184 
185     /* Check for the compiled version of prefix. */
186     if (wcslen(filename) < MAXPATHLEN) {
187         wcscat(filename, L"c");
188         if (isfile(filename)) {
189             return 1;
190         }
191     }
192     return 0;
193 }
194 
195 
196 /* Is executable file */
197 static int
isxfile(wchar_t * filename)198 isxfile(wchar_t *filename)
199 {
200     struct stat buf;
201     if (_Py_wstat(filename, &buf) != 0) {
202         return 0;
203     }
204     if (!S_ISREG(buf.st_mode)) {
205         return 0;
206     }
207     if ((buf.st_mode & 0111) == 0) {
208         return 0;
209     }
210     return 1;
211 }
212 
213 
214 /* Is directory */
215 static int
isdir(wchar_t * filename)216 isdir(wchar_t *filename)
217 {
218     struct stat buf;
219     if (_Py_wstat(filename, &buf) != 0) {
220         return 0;
221     }
222     if (!S_ISDIR(buf.st_mode)) {
223         return 0;
224     }
225     return 1;
226 }
227 
228 
229 /* Add a path component, by appending stuff to buffer.
230    buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
231    NUL-terminated string with no more than MAXPATHLEN characters (not counting
232    the trailing NUL).  It's a fatal error if it contains a string longer than
233    that (callers must be careful!).  If these requirements are met, it's
234    guaranteed that buffer will still be a NUL-terminated string with no more
235    than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
236    stuff as fits will be appended.
237 */
238 static void
joinpath(wchar_t * buffer,wchar_t * stuff)239 joinpath(wchar_t *buffer, wchar_t *stuff)
240 {
241     size_t n, k;
242     if (stuff[0] == SEP) {
243         n = 0;
244     }
245     else {
246         n = wcslen(buffer);
247         if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) {
248             buffer[n++] = SEP;
249         }
250     }
251     if (n > MAXPATHLEN) {
252         Py_FatalError("buffer overflow in getpath.c's joinpath()");
253     }
254     k = wcslen(stuff);
255     if (n + k > MAXPATHLEN) {
256         k = MAXPATHLEN - n;
257     }
258     wcsncpy(buffer+n, stuff, k);
259     buffer[n+k] = '\0';
260 }
261 
262 
263 /* copy_absolute requires that path be allocated at least
264    MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */
265 static void
copy_absolute(wchar_t * path,wchar_t * p,size_t pathlen)266 copy_absolute(wchar_t *path, wchar_t *p, size_t pathlen)
267 {
268     if (p[0] == SEP) {
269         wcscpy(path, p);
270     }
271     else {
272         if (!_Py_wgetcwd(path, pathlen)) {
273             /* unable to get the current directory */
274             wcscpy(path, p);
275             return;
276         }
277         if (p[0] == '.' && p[1] == SEP) {
278             p += 2;
279         }
280         joinpath(path, p);
281     }
282 }
283 
284 
285 /* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */
286 static void
absolutize(wchar_t * path)287 absolutize(wchar_t *path)
288 {
289     wchar_t buffer[MAXPATHLEN+1];
290 
291     if (path[0] == SEP) {
292         return;
293     }
294     copy_absolute(buffer, path, MAXPATHLEN+1);
295     wcscpy(path, buffer);
296 }
297 
298 
299 #if defined(__CYGWIN__) || defined(__MINGW32__)
300 /* add_exe_suffix requires that progpath be allocated at least
301    MAXPATHLEN + 1 bytes.
302 */
303 
304 #ifndef EXE_SUFFIX
305 #define EXE_SUFFIX L".exe"
306 #endif
307 
308 static void
add_exe_suffix(wchar_t * progpath)309 add_exe_suffix(wchar_t *progpath)
310 {
311     /* Check for already have an executable suffix */
312     size_t n = wcslen(progpath);
313     size_t s = wcslen(EXE_SUFFIX);
314     if (wcsncasecmp(EXE_SUFFIX, progpath+n-s, s) != 0) {
315         if (n + s > MAXPATHLEN) {
316             Py_FatalError("progpath overflow in getpath.c's add_exe_suffix()");
317         }
318         /* Save original path for revert */
319         wchar_t orig[MAXPATHLEN+1];
320         wcsncpy(orig, progpath, MAXPATHLEN);
321 
322         wcsncpy(progpath+n, EXE_SUFFIX, s);
323         progpath[n+s] = '\0';
324 
325         if (!isxfile(progpath)) {
326             /* Path that added suffix is invalid */
327             wcsncpy(progpath, orig, MAXPATHLEN);
328         }
329     }
330 }
331 #endif
332 
333 
334 /* search_for_prefix requires that argv0_path be no more than MAXPATHLEN
335    bytes long.
336 */
337 static int
search_for_prefix(const _PyCoreConfig * core_config,PyCalculatePath * calculate,wchar_t * prefix)338 search_for_prefix(const _PyCoreConfig *core_config,
339                   PyCalculatePath *calculate, wchar_t *prefix)
340 {
341     size_t n;
342     wchar_t *vpath;
343 
344     /* If PYTHONHOME is set, we believe it unconditionally */
345     if (core_config->home) {
346         wcsncpy(prefix, core_config->home, MAXPATHLEN);
347         prefix[MAXPATHLEN] = L'\0';
348         wchar_t *delim = wcschr(prefix, DELIM);
349         if (delim) {
350             *delim = L'\0';
351         }
352         joinpath(prefix, calculate->lib_python);
353         joinpath(prefix, LANDMARK);
354         return 1;
355     }
356 
357     /* Check to see if argv[0] is in the build directory */
358     wcsncpy(prefix, calculate->argv0_path, MAXPATHLEN);
359     prefix[MAXPATHLEN] = L'\0';
360     joinpath(prefix, L"Modules/Setup");
361     if (isfile(prefix)) {
362         /* Check VPATH to see if argv0_path is in the build directory. */
363         vpath = Py_DecodeLocale(VPATH, NULL);
364         if (vpath != NULL) {
365             wcsncpy(prefix, calculate->argv0_path, MAXPATHLEN);
366             prefix[MAXPATHLEN] = L'\0';
367             joinpath(prefix, vpath);
368             PyMem_RawFree(vpath);
369             joinpath(prefix, L"Lib");
370             joinpath(prefix, LANDMARK);
371             if (ismodule(prefix)) {
372                 return -1;
373             }
374         }
375     }
376 
377     /* Search from argv0_path, until root is found */
378     copy_absolute(prefix, calculate->argv0_path, MAXPATHLEN+1);
379     do {
380         n = wcslen(prefix);
381         joinpath(prefix, calculate->lib_python);
382         joinpath(prefix, LANDMARK);
383         if (ismodule(prefix)) {
384             return 1;
385         }
386         prefix[n] = L'\0';
387         reduce(prefix);
388     } while (prefix[0]);
389 
390     /* Look at configure's PREFIX */
391     wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
392     prefix[MAXPATHLEN] = L'\0';
393     joinpath(prefix, calculate->lib_python);
394     joinpath(prefix, LANDMARK);
395     if (ismodule(prefix)) {
396         return 1;
397     }
398 
399     /* Fail */
400     return 0;
401 }
402 
403 
404 static void
calculate_prefix(const _PyCoreConfig * core_config,PyCalculatePath * calculate,wchar_t * prefix)405 calculate_prefix(const _PyCoreConfig *core_config,
406                  PyCalculatePath *calculate, wchar_t *prefix)
407 {
408     calculate->prefix_found = search_for_prefix(core_config, calculate, prefix);
409     if (!calculate->prefix_found) {
410         if (!Py_FrozenFlag) {
411             fprintf(stderr,
412                 "Could not find platform independent libraries <prefix>\n");
413         }
414         wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
415         joinpath(prefix, calculate->lib_python);
416     }
417     else {
418         reduce(prefix);
419     }
420 }
421 
422 
423 static void
calculate_reduce_prefix(PyCalculatePath * calculate,wchar_t * prefix)424 calculate_reduce_prefix(PyCalculatePath *calculate, wchar_t *prefix)
425 {
426     /* Reduce prefix and exec_prefix to their essence,
427      * e.g. /usr/local/lib/python1.5 is reduced to /usr/local.
428      * If we're loading relative to the build directory,
429      * return the compiled-in defaults instead.
430      */
431     if (calculate->prefix_found > 0) {
432         reduce(prefix);
433         reduce(prefix);
434         /* The prefix is the root directory, but reduce() chopped
435          * off the "/". */
436         if (!prefix[0]) {
437             wcscpy(prefix, separator);
438         }
439     }
440     else {
441         wcsncpy(prefix, calculate->prefix, MAXPATHLEN);
442     }
443 }
444 
445 
446 /* search_for_exec_prefix requires that argv0_path be no more than
447    MAXPATHLEN bytes long.
448 */
449 static int
search_for_exec_prefix(const _PyCoreConfig * core_config,PyCalculatePath * calculate,wchar_t * exec_prefix)450 search_for_exec_prefix(const _PyCoreConfig *core_config,
451                        PyCalculatePath *calculate, wchar_t *exec_prefix)
452 {
453     size_t n;
454 
455     /* If PYTHONHOME is set, we believe it unconditionally */
456     if (core_config->home) {
457         wchar_t *delim = wcschr(core_config->home, DELIM);
458         if (delim) {
459             wcsncpy(exec_prefix, delim+1, MAXPATHLEN);
460         }
461         else {
462             wcsncpy(exec_prefix, core_config->home, MAXPATHLEN);
463         }
464         exec_prefix[MAXPATHLEN] = L'\0';
465         joinpath(exec_prefix, calculate->lib_python);
466         joinpath(exec_prefix, L"lib-dynload");
467         return 1;
468     }
469 
470     /* Check to see if argv[0] is in the build directory. "pybuilddir.txt"
471        is written by setup.py and contains the relative path to the location
472        of shared library modules. */
473     wcsncpy(exec_prefix, calculate->argv0_path, MAXPATHLEN);
474     exec_prefix[MAXPATHLEN] = L'\0';
475     joinpath(exec_prefix, L"pybuilddir.txt");
476     if (isfile(exec_prefix)) {
477         FILE *f = _Py_wfopen(exec_prefix, L"rb");
478         if (f == NULL) {
479             errno = 0;
480         }
481         else {
482             char buf[MAXPATHLEN+1];
483             wchar_t *rel_builddir_path;
484             n = fread(buf, 1, MAXPATHLEN, f);
485             buf[n] = '\0';
486             fclose(f);
487             rel_builddir_path = _Py_DecodeUTF8_surrogateescape(buf, n);
488             if (rel_builddir_path) {
489                 wcsncpy(exec_prefix, calculate->argv0_path, MAXPATHLEN);
490                 exec_prefix[MAXPATHLEN] = L'\0';
491                 joinpath(exec_prefix, rel_builddir_path);
492                 PyMem_RawFree(rel_builddir_path );
493                 return -1;
494             }
495         }
496     }
497 
498     /* Search from argv0_path, until root is found */
499     copy_absolute(exec_prefix, calculate->argv0_path, MAXPATHLEN+1);
500     do {
501         n = wcslen(exec_prefix);
502         joinpath(exec_prefix, calculate->lib_python);
503         joinpath(exec_prefix, L"lib-dynload");
504         if (isdir(exec_prefix)) {
505             return 1;
506         }
507         exec_prefix[n] = L'\0';
508         reduce(exec_prefix);
509     } while (exec_prefix[0]);
510 
511     /* Look at configure's EXEC_PREFIX */
512     wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
513     exec_prefix[MAXPATHLEN] = L'\0';
514     joinpath(exec_prefix, calculate->lib_python);
515     joinpath(exec_prefix, L"lib-dynload");
516     if (isdir(exec_prefix)) {
517         return 1;
518     }
519 
520     /* Fail */
521     return 0;
522 }
523 
524 
525 static void
calculate_exec_prefix(const _PyCoreConfig * core_config,PyCalculatePath * calculate,wchar_t * exec_prefix)526 calculate_exec_prefix(const _PyCoreConfig *core_config,
527                       PyCalculatePath *calculate, wchar_t *exec_prefix)
528 {
529     calculate->exec_prefix_found = search_for_exec_prefix(core_config,
530                                                           calculate,
531                                                           exec_prefix);
532     if (!calculate->exec_prefix_found) {
533         if (!Py_FrozenFlag) {
534             fprintf(stderr,
535                 "Could not find platform dependent libraries <exec_prefix>\n");
536         }
537         wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
538         joinpath(exec_prefix, L"lib/lib-dynload");
539     }
540     /* If we found EXEC_PREFIX do *not* reduce it!  (Yet.) */
541 }
542 
543 
544 static void
calculate_reduce_exec_prefix(PyCalculatePath * calculate,wchar_t * exec_prefix)545 calculate_reduce_exec_prefix(PyCalculatePath *calculate, wchar_t *exec_prefix)
546 {
547     if (calculate->exec_prefix_found > 0) {
548         reduce(exec_prefix);
549         reduce(exec_prefix);
550         reduce(exec_prefix);
551         if (!exec_prefix[0]) {
552             wcscpy(exec_prefix, separator);
553         }
554     }
555     else {
556         wcsncpy(exec_prefix, calculate->exec_prefix, MAXPATHLEN);
557     }
558 }
559 
560 
561 static _PyInitError
calculate_program_full_path(const _PyCoreConfig * core_config,PyCalculatePath * calculate,_PyPathConfig * config)562 calculate_program_full_path(const _PyCoreConfig *core_config,
563                             PyCalculatePath *calculate, _PyPathConfig *config)
564 {
565     wchar_t program_full_path[MAXPATHLEN+1];
566     memset(program_full_path, 0, sizeof(program_full_path));
567 
568 #ifdef __APPLE__
569 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
570     uint32_t nsexeclength = MAXPATHLEN;
571 #else
572     unsigned long nsexeclength = MAXPATHLEN;
573 #endif
574     char execpath[MAXPATHLEN+1];
575 #endif
576 
577     /* If there is no slash in the argv0 path, then we have to
578      * assume python is on the user's $PATH, since there's no
579      * other way to find a directory to start the search from.  If
580      * $PATH isn't exported, you lose.
581      */
582     if (wcschr(core_config->program_name, SEP)) {
583         wcsncpy(program_full_path, core_config->program_name, MAXPATHLEN);
584     }
585 #ifdef __APPLE__
586      /* On Mac OS X, if a script uses an interpreter of the form
587       * "#!/opt/python2.3/bin/python", the kernel only passes "python"
588       * as argv[0], which falls through to the $PATH search below.
589       * If /opt/python2.3/bin isn't in your path, or is near the end,
590       * this algorithm may incorrectly find /usr/bin/python. To work
591       * around this, we can use _NSGetExecutablePath to get a better
592       * hint of what the intended interpreter was, although this
593       * will fail if a relative path was used. but in that case,
594       * absolutize() should help us out below
595       */
596     else if(0 == _NSGetExecutablePath(execpath, &nsexeclength) &&
597             execpath[0] == SEP)
598     {
599         size_t len;
600         wchar_t *path = Py_DecodeLocale(execpath, &len);
601         if (path == NULL) {
602             return DECODE_LOCALE_ERR("executable path", len);
603         }
604         wcsncpy(program_full_path, path, MAXPATHLEN);
605         PyMem_RawFree(path);
606     }
607 #endif /* __APPLE__ */
608     else if (calculate->path_env) {
609         wchar_t *path = calculate->path_env;
610         while (1) {
611             wchar_t *delim = wcschr(path, DELIM);
612 
613             if (delim) {
614                 size_t len = delim - path;
615                 if (len > MAXPATHLEN) {
616                     len = MAXPATHLEN;
617                 }
618                 wcsncpy(program_full_path, path, len);
619                 program_full_path[len] = '\0';
620             }
621             else {
622                 wcsncpy(program_full_path, path, MAXPATHLEN);
623             }
624 
625             joinpath(program_full_path, core_config->program_name);
626             if (isxfile(program_full_path)) {
627                 break;
628             }
629 
630             if (!delim) {
631                 program_full_path[0] = L'\0';
632                 break;
633             }
634             path = delim + 1;
635         }
636     }
637     else {
638         program_full_path[0] = '\0';
639     }
640     if (program_full_path[0] != SEP && program_full_path[0] != '\0') {
641         absolutize(program_full_path);
642     }
643 #if defined(__CYGWIN__) || defined(__MINGW32__)
644     /* For these platforms it is necessary to ensure that the .exe suffix
645      * is appended to the filename, otherwise there is potential for
646      * sys.executable to return the name of a directory under the same
647      * path (bpo-28441).
648      */
649     if (program_full_path[0] != '\0') {
650         add_exe_suffix(program_full_path);
651     }
652 #endif
653 
654     config->program_full_path = _PyMem_RawWcsdup(program_full_path);
655     if (config->program_full_path == NULL) {
656         return _Py_INIT_NO_MEMORY();
657     }
658     return _Py_INIT_OK();
659 }
660 
661 
662 static _PyInitError
calculate_argv0_path(PyCalculatePath * calculate,const wchar_t * program_full_path)663 calculate_argv0_path(PyCalculatePath *calculate, const wchar_t *program_full_path)
664 {
665     wcsncpy(calculate->argv0_path, program_full_path, MAXPATHLEN);
666     calculate->argv0_path[MAXPATHLEN] = '\0';
667 
668 #ifdef WITH_NEXT_FRAMEWORK
669     NSModule pythonModule;
670 
671     /* On Mac OS X we have a special case if we're running from a framework.
672     ** This is because the python home should be set relative to the library,
673     ** which is in the framework, not relative to the executable, which may
674     ** be outside of the framework. Except when we're in the build directory...
675     */
676     pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize"));
677     /* Use dylib functions to find out where the framework was loaded from */
678     const char* modPath = NSLibraryNameForModule(pythonModule);
679     if (modPath != NULL) {
680         /* We're in a framework. */
681         /* See if we might be in the build directory. The framework in the
682         ** build directory is incomplete, it only has the .dylib and a few
683         ** needed symlinks, it doesn't have the Lib directories and such.
684         ** If we're running with the framework from the build directory we must
685         ** be running the interpreter in the build directory, so we use the
686         ** build-directory-specific logic to find Lib and such.
687         */
688         size_t len;
689         wchar_t* wbuf = Py_DecodeLocale(modPath, &len);
690         if (wbuf == NULL) {
691             return DECODE_LOCALE_ERR("framework location", len);
692         }
693 
694         wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
695         reduce(calculate->argv0_path);
696         joinpath(calculate->argv0_path, calculate->lib_python);
697         joinpath(calculate->argv0_path, LANDMARK);
698         if (!ismodule(calculate->argv0_path)) {
699             /* We are in the build directory so use the name of the
700                executable - we know that the absolute path is passed */
701             wcsncpy(calculate->argv0_path, program_full_path, MAXPATHLEN);
702         }
703         else {
704             /* Use the location of the library as the program_full_path */
705             wcsncpy(calculate->argv0_path, wbuf, MAXPATHLEN);
706         }
707         PyMem_RawFree(wbuf);
708     }
709 #endif
710 
711 #if HAVE_READLINK
712     wchar_t tmpbuffer[MAXPATHLEN+1];
713     int linklen = _Py_wreadlink(program_full_path, tmpbuffer, MAXPATHLEN);
714     while (linklen != -1) {
715         if (tmpbuffer[0] == SEP) {
716             /* tmpbuffer should never be longer than MAXPATHLEN,
717                but extra check does not hurt */
718             wcsncpy(calculate->argv0_path, tmpbuffer, MAXPATHLEN);
719         }
720         else {
721             /* Interpret relative to program_full_path */
722             reduce(calculate->argv0_path);
723             joinpath(calculate->argv0_path, tmpbuffer);
724         }
725         linklen = _Py_wreadlink(calculate->argv0_path, tmpbuffer, MAXPATHLEN);
726     }
727 #endif /* HAVE_READLINK */
728 
729     reduce(calculate->argv0_path);
730     /* At this point, argv0_path is guaranteed to be less than
731        MAXPATHLEN bytes long. */
732     return _Py_INIT_OK();
733 }
734 
735 
736 /* Search for an "pyvenv.cfg" environment configuration file, first in the
737    executable's directory and then in the parent directory.
738    If found, open it for use when searching for prefixes.
739 */
740 static void
calculate_read_pyenv(PyCalculatePath * calculate)741 calculate_read_pyenv(PyCalculatePath *calculate)
742 {
743     wchar_t tmpbuffer[MAXPATHLEN+1];
744     wchar_t *env_cfg = L"pyvenv.cfg";
745     FILE *env_file;
746 
747     wcscpy(tmpbuffer, calculate->argv0_path);
748 
749     joinpath(tmpbuffer, env_cfg);
750     env_file = _Py_wfopen(tmpbuffer, L"r");
751     if (env_file == NULL) {
752         errno = 0;
753 
754         reduce(tmpbuffer);
755         reduce(tmpbuffer);
756         joinpath(tmpbuffer, env_cfg);
757 
758         env_file = _Py_wfopen(tmpbuffer, L"r");
759         if (env_file == NULL) {
760             errno = 0;
761         }
762     }
763 
764     if (env_file == NULL) {
765         return;
766     }
767 
768     /* Look for a 'home' variable and set argv0_path to it, if found */
769     if (_Py_FindEnvConfigValue(env_file, L"home", tmpbuffer, MAXPATHLEN)) {
770         wcscpy(calculate->argv0_path, tmpbuffer);
771     }
772     fclose(env_file);
773 }
774 
775 
776 static void
calculate_zip_path(PyCalculatePath * calculate,const wchar_t * prefix)777 calculate_zip_path(PyCalculatePath *calculate, const wchar_t *prefix)
778 {
779     wcsncpy(calculate->zip_path, prefix, MAXPATHLEN);
780     calculate->zip_path[MAXPATHLEN] = L'\0';
781 
782     if (calculate->prefix_found > 0) {
783         /* Use the reduced prefix returned by Py_GetPrefix() */
784         reduce(calculate->zip_path);
785         reduce(calculate->zip_path);
786     }
787     else {
788         wcsncpy(calculate->zip_path, calculate->prefix, MAXPATHLEN);
789     }
790     joinpath(calculate->zip_path, L"lib/python00.zip");
791 
792     /* Replace "00" with version */
793     size_t bufsz = wcslen(calculate->zip_path);
794     calculate->zip_path[bufsz - 6] = VERSION[0];
795     calculate->zip_path[bufsz - 5] = VERSION[2];
796 }
797 
798 
799 static _PyInitError
calculate_module_search_path(const _PyCoreConfig * core_config,PyCalculatePath * calculate,const wchar_t * prefix,const wchar_t * exec_prefix,_PyPathConfig * config)800 calculate_module_search_path(const _PyCoreConfig *core_config,
801                              PyCalculatePath *calculate,
802                              const wchar_t *prefix, const wchar_t *exec_prefix,
803                              _PyPathConfig *config)
804 {
805     /* Calculate size of return buffer */
806     size_t bufsz = 0;
807     if (core_config->module_search_path_env != NULL) {
808         bufsz += wcslen(core_config->module_search_path_env) + 1;
809     }
810 
811     wchar_t *defpath = calculate->pythonpath;
812     size_t prefixsz = wcslen(prefix) + 1;
813     while (1) {
814         wchar_t *delim = wcschr(defpath, DELIM);
815 
816         if (defpath[0] != SEP) {
817             /* Paths are relative to prefix */
818             bufsz += prefixsz;
819         }
820 
821         if (delim) {
822             bufsz += delim - defpath + 1;
823         }
824         else {
825             bufsz += wcslen(defpath) + 1;
826             break;
827         }
828         defpath = delim + 1;
829     }
830 
831     bufsz += wcslen(calculate->zip_path) + 1;
832     bufsz += wcslen(exec_prefix) + 1;
833 
834     /* Allocate the buffer */
835     wchar_t *buf = PyMem_RawMalloc(bufsz * sizeof(wchar_t));
836     if (buf == NULL) {
837         return _Py_INIT_NO_MEMORY();
838     }
839     buf[0] = '\0';
840 
841     /* Run-time value of $PYTHONPATH goes first */
842     if (core_config->module_search_path_env) {
843         wcscpy(buf, core_config->module_search_path_env);
844         wcscat(buf, delimiter);
845     }
846 
847     /* Next is the default zip path */
848     wcscat(buf, calculate->zip_path);
849     wcscat(buf, delimiter);
850 
851     /* Next goes merge of compile-time $PYTHONPATH with
852      * dynamically located prefix.
853      */
854     defpath = calculate->pythonpath;
855     while (1) {
856         wchar_t *delim = wcschr(defpath, DELIM);
857 
858         if (defpath[0] != SEP) {
859             wcscat(buf, prefix);
860             if (prefixsz >= 2 && prefix[prefixsz - 2] != SEP &&
861                 defpath[0] != (delim ? DELIM : L'\0'))
862             {
863                 /* not empty */
864                 wcscat(buf, separator);
865             }
866         }
867 
868         if (delim) {
869             size_t len = delim - defpath + 1;
870             size_t end = wcslen(buf) + len;
871             wcsncat(buf, defpath, len);
872             buf[end] = '\0';
873         }
874         else {
875             wcscat(buf, defpath);
876             break;
877         }
878         defpath = delim + 1;
879     }
880     wcscat(buf, delimiter);
881 
882     /* Finally, on goes the directory for dynamic-load modules */
883     wcscat(buf, exec_prefix);
884 
885     config->module_search_path = buf;
886     return _Py_INIT_OK();
887 }
888 
889 
890 static _PyInitError
calculate_init(PyCalculatePath * calculate,const _PyCoreConfig * core_config)891 calculate_init(PyCalculatePath *calculate,
892                const _PyCoreConfig *core_config)
893 {
894     size_t len;
895     const char *path = getenv("PATH");
896     if (path) {
897         calculate->path_env = Py_DecodeLocale(path, &len);
898         if (!calculate->path_env) {
899             return DECODE_LOCALE_ERR("PATH environment variable", len);
900         }
901     }
902 
903     calculate->pythonpath = Py_DecodeLocale(PYTHONPATH, &len);
904     if (!calculate->pythonpath) {
905         return DECODE_LOCALE_ERR("PYTHONPATH define", len);
906     }
907     calculate->prefix = Py_DecodeLocale(PREFIX, &len);
908     if (!calculate->prefix) {
909         return DECODE_LOCALE_ERR("PREFIX define", len);
910     }
911     calculate->exec_prefix = Py_DecodeLocale(EXEC_PREFIX, &len);
912     if (!calculate->prefix) {
913         return DECODE_LOCALE_ERR("EXEC_PREFIX define", len);
914     }
915     calculate->lib_python = Py_DecodeLocale("lib/python" VERSION, &len);
916     if (!calculate->lib_python) {
917         return DECODE_LOCALE_ERR("EXEC_PREFIX define", len);
918     }
919     return _Py_INIT_OK();
920 }
921 
922 
923 static void
calculate_free(PyCalculatePath * calculate)924 calculate_free(PyCalculatePath *calculate)
925 {
926     PyMem_RawFree(calculate->pythonpath);
927     PyMem_RawFree(calculate->prefix);
928     PyMem_RawFree(calculate->exec_prefix);
929     PyMem_RawFree(calculate->lib_python);
930     PyMem_RawFree(calculate->path_env);
931 }
932 
933 
934 static _PyInitError
calculate_path_impl(const _PyCoreConfig * core_config,PyCalculatePath * calculate,_PyPathConfig * config)935 calculate_path_impl(const _PyCoreConfig *core_config,
936                     PyCalculatePath *calculate, _PyPathConfig *config)
937 {
938     _PyInitError err;
939 
940     err = calculate_program_full_path(core_config, calculate, config);
941     if (_Py_INIT_FAILED(err)) {
942         return err;
943     }
944 
945     err = calculate_argv0_path(calculate, config->program_full_path);
946     if (_Py_INIT_FAILED(err)) {
947         return err;
948     }
949 
950     calculate_read_pyenv(calculate);
951 
952     wchar_t prefix[MAXPATHLEN+1];
953     memset(prefix, 0, sizeof(prefix));
954     calculate_prefix(core_config, calculate, prefix);
955 
956     calculate_zip_path(calculate, prefix);
957 
958     wchar_t exec_prefix[MAXPATHLEN+1];
959     memset(exec_prefix, 0, sizeof(exec_prefix));
960     calculate_exec_prefix(core_config, calculate, exec_prefix);
961 
962     if ((!calculate->prefix_found || !calculate->exec_prefix_found) &&
963         !Py_FrozenFlag)
964     {
965         fprintf(stderr,
966                 "Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n");
967     }
968 
969     err = calculate_module_search_path(core_config, calculate,
970                                        prefix, exec_prefix, config);
971     if (_Py_INIT_FAILED(err)) {
972         return err;
973     }
974 
975     calculate_reduce_prefix(calculate, prefix);
976 
977     config->prefix = _PyMem_RawWcsdup(prefix);
978     if (config->prefix == NULL) {
979         return _Py_INIT_NO_MEMORY();
980     }
981 
982     calculate_reduce_exec_prefix(calculate, exec_prefix);
983 
984     config->exec_prefix = _PyMem_RawWcsdup(exec_prefix);
985     if (config->exec_prefix == NULL) {
986         return _Py_INIT_NO_MEMORY();
987     }
988 
989     return _Py_INIT_OK();
990 }
991 
992 
993 _PyInitError
_PyPathConfig_Calculate(_PyPathConfig * config,const _PyCoreConfig * core_config)994 _PyPathConfig_Calculate(_PyPathConfig *config, const _PyCoreConfig *core_config)
995 {
996     PyCalculatePath calculate;
997     memset(&calculate, 0, sizeof(calculate));
998 
999     _PyInitError err = calculate_init(&calculate, core_config);
1000     if (_Py_INIT_FAILED(err)) {
1001         goto done;
1002     }
1003 
1004     err = calculate_path_impl(core_config, &calculate, config);
1005     if (_Py_INIT_FAILED(err)) {
1006         goto done;
1007     }
1008 
1009     err = _Py_INIT_OK();
1010 
1011 done:
1012     calculate_free(&calculate);
1013     return err;
1014 }
1015 
1016 #ifdef __cplusplus
1017 }
1018 #endif
1019