blob: 3a431431351bf7fd80ccb80018b9735cc04fa1d7 [file] [log] [blame]
Victor Stinner31a83932017-12-04 13:39:15 +01001/* Path configuration like module_search_path (sys.path) */
2
3#include "Python.h"
4#include "osdefs.h"
5#include "internal/pystate.h"
Nick Coghlanee378452018-03-25 23:43:50 +10006#include <wchar.h>
Victor Stinner31a83932017-12-04 13:39:15 +01007
8#ifdef __cplusplus
9extern "C" {
10#endif
11
12
13_PyPathConfig _Py_path_config = _PyPathConfig_INIT;
14
15
16void
17_PyPathConfig_Clear(_PyPathConfig *config)
18{
19 /* _PyMem_SetDefaultAllocator() is needed to get a known memory allocator,
20 since Py_SetPath(), Py_SetPythonHome() and Py_SetProgramName() can be
21 called before Py_Initialize() which can changes the memory allocator. */
22 PyMemAllocatorEx old_alloc;
23 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
24
25#define CLEAR(ATTR) \
26 do { \
27 PyMem_RawFree(ATTR); \
28 ATTR = NULL; \
29 } while (0)
30
31 CLEAR(config->prefix);
32 CLEAR(config->program_full_path);
33#ifdef MS_WINDOWS
34 CLEAR(config->dll_path);
35#else
36 CLEAR(config->exec_prefix);
37#endif
38 CLEAR(config->module_search_path);
39 CLEAR(config->home);
40 CLEAR(config->program_name);
41#undef CLEAR
42
43 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
44}
45
46
47/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
48 and Py_GetProgramFullPath() */
49_PyInitError
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010050_PyPathConfig_Init(const _PyCoreConfig *core_config)
Victor Stinner31a83932017-12-04 13:39:15 +010051{
52 if (_Py_path_config.module_search_path) {
53 /* Already initialized */
54 return _Py_INIT_OK();
55 }
56
57 _PyInitError err;
58 _PyPathConfig new_config = _PyPathConfig_INIT;
59
60 PyMemAllocatorEx old_alloc;
61 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
62
63 /* Calculate program_full_path, prefix, exec_prefix (Unix)
64 or dll_path (Windows), and module_search_path */
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010065 err = _PyPathConfig_Calculate(&new_config, core_config);
Victor Stinner31a83932017-12-04 13:39:15 +010066 if (_Py_INIT_FAILED(err)) {
67 _PyPathConfig_Clear(&new_config);
68 goto done;
69 }
70
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010071 /* Copy home and program_name from core_config */
72 if (core_config->home != NULL) {
73 new_config.home = _PyMem_RawWcsdup(core_config->home);
Victor Stinner31a83932017-12-04 13:39:15 +010074 if (new_config.home == NULL) {
75 err = _Py_INIT_NO_MEMORY();
76 goto done;
77 }
78 }
79 else {
80 new_config.home = NULL;
81 }
82
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010083 new_config.program_name = _PyMem_RawWcsdup(core_config->program_name);
Victor Stinner31a83932017-12-04 13:39:15 +010084 if (new_config.program_name == NULL) {
85 err = _Py_INIT_NO_MEMORY();
86 goto done;
87 }
88
89 _PyPathConfig_Clear(&_Py_path_config);
90 _Py_path_config = new_config;
91
92 err = _Py_INIT_OK();
93
94done:
95 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
96 return err;
97}
98
99
100static void
101pathconfig_global_init(void)
102{
103 if (_Py_path_config.module_search_path) {
104 /* Already initialized */
105 return;
106 }
107
108 _PyInitError err;
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100109 _PyCoreConfig config = _PyCoreConfig_INIT;
Victor Stinner31a83932017-12-04 13:39:15 +0100110
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100111 err = _PyCoreConfig_Read(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100112 if (_Py_INIT_FAILED(err)) {
113 goto error;
114 }
115
116 err = _PyPathConfig_Init(&config);
117 if (_Py_INIT_FAILED(err)) {
118 goto error;
119 }
120
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100121 _PyCoreConfig_Clear(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100122 return;
123
124error:
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100125 _PyCoreConfig_Clear(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100126 _Py_FatalInitError(err);
127}
128
129
130/* External interface */
131
132void
133Py_SetPath(const wchar_t *path)
134{
135 if (path == NULL) {
136 _PyPathConfig_Clear(&_Py_path_config);
137 return;
138 }
139
140 PyMemAllocatorEx old_alloc;
141 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
142
143 _PyPathConfig new_config;
144 new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName());
145 new_config.prefix = _PyMem_RawWcsdup(L"");
146#ifdef MS_WINDOWS
147 new_config.dll_path = _PyMem_RawWcsdup(L"");
148#else
149 new_config.exec_prefix = _PyMem_RawWcsdup(L"");
150#endif
151 new_config.module_search_path = _PyMem_RawWcsdup(path);
152
153 /* steal the home and program_name values (to leave them unchanged) */
154 new_config.home = _Py_path_config.home;
155 _Py_path_config.home = NULL;
156 new_config.program_name = _Py_path_config.program_name;
157 _Py_path_config.program_name = NULL;
158
159 _PyPathConfig_Clear(&_Py_path_config);
160 _Py_path_config = new_config;
161
162 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
163}
164
165
166void
Serhiy Storchaka4ae06c52017-12-12 13:55:04 +0200167Py_SetPythonHome(const wchar_t *home)
Victor Stinner31a83932017-12-04 13:39:15 +0100168{
169 if (home == NULL) {
170 return;
171 }
172
173 PyMemAllocatorEx old_alloc;
174 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
175
176 PyMem_RawFree(_Py_path_config.home);
177 _Py_path_config.home = _PyMem_RawWcsdup(home);
178
179 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
180
181 if (_Py_path_config.home == NULL) {
182 Py_FatalError("Py_SetPythonHome() failed: out of memory");
183 }
184}
185
186
187void
Serhiy Storchaka4ae06c52017-12-12 13:55:04 +0200188Py_SetProgramName(const wchar_t *program_name)
Victor Stinner31a83932017-12-04 13:39:15 +0100189{
190 if (program_name == NULL || program_name[0] == L'\0') {
191 return;
192 }
193
194 PyMemAllocatorEx old_alloc;
195 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
196
197 PyMem_RawFree(_Py_path_config.program_name);
198 _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
199
200 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
201
202 if (_Py_path_config.program_name == NULL) {
203 Py_FatalError("Py_SetProgramName() failed: out of memory");
204 }
205}
206
207
Steve Dowere8510492018-11-17 20:42:08 -0800208void
209_Py_SetProgramFullPath(const wchar_t *program_full_path)
210{
211 if (program_full_path == NULL || program_full_path[0] == L'\0') {
212 return;
213 }
214
215 PyMemAllocatorEx old_alloc;
216 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
217
218 PyMem_RawFree(_Py_path_config.program_full_path);
219 _Py_path_config.program_full_path = _PyMem_RawWcsdup(program_full_path);
220
221 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
222
223 if (_Py_path_config.program_full_path == NULL) {
224 Py_FatalError("Py_SetProgramFullPath() failed: out of memory");
225 }
226}
227
228
Victor Stinner31a83932017-12-04 13:39:15 +0100229wchar_t *
230Py_GetPath(void)
231{
232 pathconfig_global_init();
233 return _Py_path_config.module_search_path;
234}
235
236
237wchar_t *
238Py_GetPrefix(void)
239{
240 pathconfig_global_init();
241 return _Py_path_config.prefix;
242}
243
244
245wchar_t *
246Py_GetExecPrefix(void)
247{
248#ifdef MS_WINDOWS
249 return Py_GetPrefix();
250#else
251 pathconfig_global_init();
252 return _Py_path_config.exec_prefix;
253#endif
254}
255
256
257wchar_t *
258Py_GetProgramFullPath(void)
259{
260 pathconfig_global_init();
261 return _Py_path_config.program_full_path;
262}
263
264
265wchar_t*
266Py_GetPythonHome(void)
267{
268 pathconfig_global_init();
269 return _Py_path_config.home;
270}
271
272
273wchar_t *
274Py_GetProgramName(void)
275{
276 pathconfig_global_init();
277 return _Py_path_config.program_name;
278}
279
Victor Stinner11a247d2017-12-13 21:05:57 +0100280/* Compute argv[0] which will be prepended to sys.argv */
Victor Stinnerf7959a92019-03-20 00:30:45 +0100281int
282_PyPathConfig_ComputeArgv0(int argc, wchar_t **argv, PyObject **argv0_p)
Victor Stinner11a247d2017-12-13 21:05:57 +0100283{
284 wchar_t *argv0;
285 wchar_t *p = NULL;
286 Py_ssize_t n = 0;
Nick Coghlanee378452018-03-25 23:43:50 +1000287 int have_script_arg = 0;
288 int have_module_arg = 0;
Victor Stinner11a247d2017-12-13 21:05:57 +0100289#ifdef HAVE_READLINK
290 wchar_t link[MAXPATHLEN+1];
291 wchar_t argv0copy[2*MAXPATHLEN+1];
292 int nr = 0;
293#endif
294#if defined(HAVE_REALPATH)
295 wchar_t fullpath[MAXPATHLEN];
296#elif defined(MS_WINDOWS)
297 wchar_t fullpath[MAX_PATH];
298#endif
299
Victor Stinnerf7959a92019-03-20 00:30:45 +0100300 assert(*argv0_p == NULL);
301
Victor Stinner11a247d2017-12-13 21:05:57 +0100302 argv0 = argv[0];
Nick Coghlanee378452018-03-25 23:43:50 +1000303 if (argc > 0 && argv0 != NULL) {
304 have_module_arg = (wcscmp(argv0, L"-m") == 0);
305 have_script_arg = !have_module_arg && (wcscmp(argv0, L"-c") != 0);
306 }
307
308 if (have_module_arg) {
309 #if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
Victor Stinnerf7959a92019-03-20 00:30:45 +0100310 if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) {
311 return 0;
312 }
Nick Coghlanee378452018-03-25 23:43:50 +1000313 argv0 = fullpath;
314 n = wcslen(argv0);
315 #else
316 argv0 = L".";
317 n = 1;
318 #endif
319 }
Victor Stinner11a247d2017-12-13 21:05:57 +0100320
321#ifdef HAVE_READLINK
Nick Coghlanee378452018-03-25 23:43:50 +1000322 if (have_script_arg)
Victor Stinner11a247d2017-12-13 21:05:57 +0100323 nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
324 if (nr > 0) {
325 /* It's a symlink */
326 link[nr] = '\0';
327 if (link[0] == SEP)
328 argv0 = link; /* Link to absolute path */
329 else if (wcschr(link, SEP) == NULL)
330 ; /* Link without path */
331 else {
332 /* Must join(dirname(argv0), link) */
333 wchar_t *q = wcsrchr(argv0, SEP);
334 if (q == NULL)
335 argv0 = link; /* argv0 without path */
336 else {
337 /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */
338 wcsncpy(argv0copy, argv0, MAXPATHLEN);
339 q = wcsrchr(argv0copy, SEP);
340 wcsncpy(q+1, link, MAXPATHLEN);
341 q[MAXPATHLEN + 1] = L'\0';
342 argv0 = argv0copy;
343 }
344 }
345 }
346#endif /* HAVE_READLINK */
347
348#if SEP == '\\'
349 /* Special case for Microsoft filename syntax */
Nick Coghlanee378452018-03-25 23:43:50 +1000350 if (have_script_arg) {
Victor Stinner11a247d2017-12-13 21:05:57 +0100351 wchar_t *q;
352#if defined(MS_WINDOWS)
353 /* Replace the first element in argv with the full path. */
354 wchar_t *ptemp;
355 if (GetFullPathNameW(argv0,
356 Py_ARRAY_LENGTH(fullpath),
357 fullpath,
358 &ptemp)) {
359 argv0 = fullpath;
360 }
361#endif
362 p = wcsrchr(argv0, SEP);
363 /* Test for alternate separator */
364 q = wcsrchr(p ? p : argv0, '/');
365 if (q != NULL)
366 p = q;
367 if (p != NULL) {
368 n = p + 1 - argv0;
369 if (n > 1 && p[-1] != ':')
370 n--; /* Drop trailing separator */
371 }
372 }
373#else /* All other filename syntaxes */
Nick Coghlanee378452018-03-25 23:43:50 +1000374 if (have_script_arg) {
Victor Stinner11a247d2017-12-13 21:05:57 +0100375#if defined(HAVE_REALPATH)
376 if (_Py_wrealpath(argv0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
377 argv0 = fullpath;
378 }
379#endif
380 p = wcsrchr(argv0, SEP);
381 }
382 if (p != NULL) {
383 n = p + 1 - argv0;
384#if SEP == '/' /* Special case for Unix filename syntax */
385 if (n > 1)
386 n--; /* Drop trailing separator */
387#endif /* Unix */
388 }
389#endif /* All others */
390
Victor Stinnerf7959a92019-03-20 00:30:45 +0100391 *argv0_p = PyUnicode_FromWideChar(argv0, n);
392 return 1;
Victor Stinner11a247d2017-12-13 21:05:57 +0100393}
394
Victor Stinner9bee3292017-12-21 16:49:13 +0100395
396/* Search for a prefix value in an environment file (pyvenv.cfg).
397 If found, copy it into the provided buffer. */
398int
399_Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
400 wchar_t *value, size_t value_size)
401{
402 int result = 0; /* meaning not found */
403 char buffer[MAXPATHLEN*2+1]; /* allow extra for key, '=', etc. */
404
405 fseek(env_file, 0, SEEK_SET);
406 while (!feof(env_file)) {
407 char * p = fgets(buffer, MAXPATHLEN*2, env_file);
Victor Stinner9bee3292017-12-21 16:49:13 +0100408
409 if (p == NULL) {
410 break;
411 }
Victor Stinner05d68a82018-01-18 11:15:25 +0100412
413 size_t n = strlen(p);
Victor Stinner9bee3292017-12-21 16:49:13 +0100414 if (p[n - 1] != '\n') {
415 /* line has overflowed - bail */
416 break;
417 }
418 if (p[0] == '#') {
419 /* Comment - skip */
420 continue;
421 }
Victor Stinner05d68a82018-01-18 11:15:25 +0100422
423 wchar_t *tmpbuffer = _Py_DecodeUTF8_surrogateescape(buffer, n);
Victor Stinner7ed7aea2018-01-15 10:45:49 +0100424 if (tmpbuffer) {
Victor Stinner9bee3292017-12-21 16:49:13 +0100425 wchar_t * state;
426 wchar_t * tok = wcstok(tmpbuffer, L" \t\r\n", &state);
427 if ((tok != NULL) && !wcscmp(tok, key)) {
428 tok = wcstok(NULL, L" \t", &state);
429 if ((tok != NULL) && !wcscmp(tok, L"=")) {
430 tok = wcstok(NULL, L"\r\n", &state);
431 if (tok != NULL) {
432 wcsncpy(value, tok, MAXPATHLEN);
433 result = 1;
434 PyMem_RawFree(tmpbuffer);
435 break;
436 }
437 }
438 }
439 PyMem_RawFree(tmpbuffer);
440 }
441 }
442 return result;
443}
444
Victor Stinner31a83932017-12-04 13:39:15 +0100445#ifdef __cplusplus
446}
447#endif