blob: 07aa01c0304f2ca25253acfbf2ec78191c7c6445 [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 Coghland5d9e022018-03-25 23:03:10 +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
208wchar_t *
209Py_GetPath(void)
210{
211 pathconfig_global_init();
212 return _Py_path_config.module_search_path;
213}
214
215
216wchar_t *
217Py_GetPrefix(void)
218{
219 pathconfig_global_init();
220 return _Py_path_config.prefix;
221}
222
223
224wchar_t *
225Py_GetExecPrefix(void)
226{
227#ifdef MS_WINDOWS
228 return Py_GetPrefix();
229#else
230 pathconfig_global_init();
231 return _Py_path_config.exec_prefix;
232#endif
233}
234
235
236wchar_t *
237Py_GetProgramFullPath(void)
238{
239 pathconfig_global_init();
240 return _Py_path_config.program_full_path;
241}
242
243
244wchar_t*
245Py_GetPythonHome(void)
246{
247 pathconfig_global_init();
248 return _Py_path_config.home;
249}
250
251
252wchar_t *
253Py_GetProgramName(void)
254{
255 pathconfig_global_init();
256 return _Py_path_config.program_name;
257}
258
Victor Stinner11a247d2017-12-13 21:05:57 +0100259/* Compute argv[0] which will be prepended to sys.argv */
260PyObject*
261_PyPathConfig_ComputeArgv0(int argc, wchar_t **argv)
262{
263 wchar_t *argv0;
264 wchar_t *p = NULL;
265 Py_ssize_t n = 0;
Nick Coghland5d9e022018-03-25 23:03:10 +1000266 int have_script_arg = 0;
267 int have_module_arg = 0;
Victor Stinner11a247d2017-12-13 21:05:57 +0100268#ifdef HAVE_READLINK
269 wchar_t link[MAXPATHLEN+1];
270 wchar_t argv0copy[2*MAXPATHLEN+1];
271 int nr = 0;
272#endif
273#if defined(HAVE_REALPATH)
274 wchar_t fullpath[MAXPATHLEN];
275#elif defined(MS_WINDOWS)
276 wchar_t fullpath[MAX_PATH];
277#endif
278
Victor Stinner11a247d2017-12-13 21:05:57 +0100279 argv0 = argv[0];
Nick Coghland5d9e022018-03-25 23:03:10 +1000280 if (argc > 0 && argv0 != NULL) {
281 have_module_arg = (wcscmp(argv0, L"-m") == 0);
282 have_script_arg = !have_module_arg && (wcscmp(argv0, L"-c") != 0);
283 }
284
285 if (have_module_arg) {
286 #if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
287 _Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath));
288 argv0 = fullpath;
289 n = wcslen(argv0);
290 #else
291 argv0 = L".";
292 n = 1;
293 #endif
294 }
Victor Stinner11a247d2017-12-13 21:05:57 +0100295
296#ifdef HAVE_READLINK
Nick Coghland5d9e022018-03-25 23:03:10 +1000297 if (have_script_arg)
Victor Stinner11a247d2017-12-13 21:05:57 +0100298 nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
299 if (nr > 0) {
300 /* It's a symlink */
301 link[nr] = '\0';
302 if (link[0] == SEP)
303 argv0 = link; /* Link to absolute path */
304 else if (wcschr(link, SEP) == NULL)
305 ; /* Link without path */
306 else {
307 /* Must join(dirname(argv0), link) */
308 wchar_t *q = wcsrchr(argv0, SEP);
309 if (q == NULL)
310 argv0 = link; /* argv0 without path */
311 else {
312 /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */
313 wcsncpy(argv0copy, argv0, MAXPATHLEN);
314 q = wcsrchr(argv0copy, SEP);
315 wcsncpy(q+1, link, MAXPATHLEN);
316 q[MAXPATHLEN + 1] = L'\0';
317 argv0 = argv0copy;
318 }
319 }
320 }
321#endif /* HAVE_READLINK */
322
323#if SEP == '\\'
324 /* Special case for Microsoft filename syntax */
Nick Coghland5d9e022018-03-25 23:03:10 +1000325 if (have_script_arg) {
Victor Stinner11a247d2017-12-13 21:05:57 +0100326 wchar_t *q;
327#if defined(MS_WINDOWS)
328 /* Replace the first element in argv with the full path. */
329 wchar_t *ptemp;
330 if (GetFullPathNameW(argv0,
331 Py_ARRAY_LENGTH(fullpath),
332 fullpath,
333 &ptemp)) {
334 argv0 = fullpath;
335 }
336#endif
337 p = wcsrchr(argv0, SEP);
338 /* Test for alternate separator */
339 q = wcsrchr(p ? p : argv0, '/');
340 if (q != NULL)
341 p = q;
342 if (p != NULL) {
343 n = p + 1 - argv0;
344 if (n > 1 && p[-1] != ':')
345 n--; /* Drop trailing separator */
346 }
347 }
348#else /* All other filename syntaxes */
Nick Coghland5d9e022018-03-25 23:03:10 +1000349 if (have_script_arg) {
Victor Stinner11a247d2017-12-13 21:05:57 +0100350#if defined(HAVE_REALPATH)
351 if (_Py_wrealpath(argv0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
352 argv0 = fullpath;
353 }
354#endif
355 p = wcsrchr(argv0, SEP);
356 }
357 if (p != NULL) {
358 n = p + 1 - argv0;
359#if SEP == '/' /* Special case for Unix filename syntax */
360 if (n > 1)
361 n--; /* Drop trailing separator */
362#endif /* Unix */
363 }
364#endif /* All others */
365
366 return PyUnicode_FromWideChar(argv0, n);
367}
368
Victor Stinner9bee3292017-12-21 16:49:13 +0100369
370/* Search for a prefix value in an environment file (pyvenv.cfg).
371 If found, copy it into the provided buffer. */
372int
373_Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
374 wchar_t *value, size_t value_size)
375{
376 int result = 0; /* meaning not found */
377 char buffer[MAXPATHLEN*2+1]; /* allow extra for key, '=', etc. */
378
379 fseek(env_file, 0, SEEK_SET);
380 while (!feof(env_file)) {
381 char * p = fgets(buffer, MAXPATHLEN*2, env_file);
Victor Stinner9bee3292017-12-21 16:49:13 +0100382
383 if (p == NULL) {
384 break;
385 }
Victor Stinner05d68a82018-01-18 11:15:25 +0100386
387 size_t n = strlen(p);
Victor Stinner9bee3292017-12-21 16:49:13 +0100388 if (p[n - 1] != '\n') {
389 /* line has overflowed - bail */
390 break;
391 }
392 if (p[0] == '#') {
393 /* Comment - skip */
394 continue;
395 }
Victor Stinner05d68a82018-01-18 11:15:25 +0100396
397 wchar_t *tmpbuffer = _Py_DecodeUTF8_surrogateescape(buffer, n);
Victor Stinner7ed7aea2018-01-15 10:45:49 +0100398 if (tmpbuffer) {
Victor Stinner9bee3292017-12-21 16:49:13 +0100399 wchar_t * state;
400 wchar_t * tok = wcstok(tmpbuffer, L" \t\r\n", &state);
401 if ((tok != NULL) && !wcscmp(tok, key)) {
402 tok = wcstok(NULL, L" \t", &state);
403 if ((tok != NULL) && !wcscmp(tok, L"=")) {
404 tok = wcstok(NULL, L"\r\n", &state);
405 if (tok != NULL) {
406 wcsncpy(value, tok, MAXPATHLEN);
407 result = 1;
408 PyMem_RawFree(tmpbuffer);
409 break;
410 }
411 }
412 }
413 PyMem_RawFree(tmpbuffer);
414 }
415 }
416 return result;
417}
418
Victor Stinner31a83932017-12-04 13:39:15 +0100419#ifdef __cplusplus
420}
421#endif