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