blob: 6de5481bc8dae2f9a906842be65caf743de1cc7d [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"
6
7#ifdef __cplusplus
8extern "C" {
9#endif
10
11
12_PyPathConfig _Py_path_config = _PyPathConfig_INIT;
13
14
15void
16_PyPathConfig_Clear(_PyPathConfig *config)
17{
18 /* _PyMem_SetDefaultAllocator() is needed to get a known memory allocator,
19 since Py_SetPath(), Py_SetPythonHome() and Py_SetProgramName() can be
20 called before Py_Initialize() which can changes the memory allocator. */
21 PyMemAllocatorEx old_alloc;
22 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
23
24#define CLEAR(ATTR) \
25 do { \
26 PyMem_RawFree(ATTR); \
27 ATTR = NULL; \
28 } while (0)
29
30 CLEAR(config->prefix);
31 CLEAR(config->program_full_path);
32#ifdef MS_WINDOWS
33 CLEAR(config->dll_path);
34#else
35 CLEAR(config->exec_prefix);
36#endif
37 CLEAR(config->module_search_path);
38 CLEAR(config->home);
39 CLEAR(config->program_name);
40#undef CLEAR
41
42 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
43}
44
45
46/* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
47 and Py_GetProgramFullPath() */
48_PyInitError
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010049_PyPathConfig_Init(const _PyCoreConfig *core_config)
Victor Stinner31a83932017-12-04 13:39:15 +010050{
51 if (_Py_path_config.module_search_path) {
52 /* Already initialized */
53 return _Py_INIT_OK();
54 }
55
56 _PyInitError err;
57 _PyPathConfig new_config = _PyPathConfig_INIT;
58
59 PyMemAllocatorEx old_alloc;
60 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
61
62 /* Calculate program_full_path, prefix, exec_prefix (Unix)
63 or dll_path (Windows), and module_search_path */
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010064 err = _PyPathConfig_Calculate(&new_config, core_config);
Victor Stinner31a83932017-12-04 13:39:15 +010065 if (_Py_INIT_FAILED(err)) {
66 _PyPathConfig_Clear(&new_config);
67 goto done;
68 }
69
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010070 /* Copy home and program_name from core_config */
71 if (core_config->home != NULL) {
72 new_config.home = _PyMem_RawWcsdup(core_config->home);
Victor Stinner31a83932017-12-04 13:39:15 +010073 if (new_config.home == NULL) {
74 err = _Py_INIT_NO_MEMORY();
75 goto done;
76 }
77 }
78 else {
79 new_config.home = NULL;
80 }
81
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +010082 new_config.program_name = _PyMem_RawWcsdup(core_config->program_name);
Victor Stinner31a83932017-12-04 13:39:15 +010083 if (new_config.program_name == NULL) {
84 err = _Py_INIT_NO_MEMORY();
85 goto done;
86 }
87
88 _PyPathConfig_Clear(&_Py_path_config);
89 _Py_path_config = new_config;
90
91 err = _Py_INIT_OK();
92
93done:
94 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
95 return err;
96}
97
98
99static void
100pathconfig_global_init(void)
101{
102 if (_Py_path_config.module_search_path) {
103 /* Already initialized */
104 return;
105 }
106
107 _PyInitError err;
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100108 _PyCoreConfig config = _PyCoreConfig_INIT;
Victor Stinner31a83932017-12-04 13:39:15 +0100109
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100110 err = _PyCoreConfig_Read(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100111 if (_Py_INIT_FAILED(err)) {
112 goto error;
113 }
114
115 err = _PyPathConfig_Init(&config);
116 if (_Py_INIT_FAILED(err)) {
117 goto error;
118 }
119
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100120 _PyCoreConfig_Clear(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100121 return;
122
123error:
Victor Stinnerb5fd9ad2017-12-14 02:20:52 +0100124 _PyCoreConfig_Clear(&config);
Victor Stinner31a83932017-12-04 13:39:15 +0100125 _Py_FatalInitError(err);
126}
127
128
129/* External interface */
130
131void
132Py_SetPath(const wchar_t *path)
133{
134 if (path == NULL) {
135 _PyPathConfig_Clear(&_Py_path_config);
136 return;
137 }
138
139 PyMemAllocatorEx old_alloc;
140 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
141
142 _PyPathConfig new_config;
143 new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName());
144 new_config.prefix = _PyMem_RawWcsdup(L"");
145#ifdef MS_WINDOWS
146 new_config.dll_path = _PyMem_RawWcsdup(L"");
147#else
148 new_config.exec_prefix = _PyMem_RawWcsdup(L"");
149#endif
150 new_config.module_search_path = _PyMem_RawWcsdup(path);
151
152 /* steal the home and program_name values (to leave them unchanged) */
153 new_config.home = _Py_path_config.home;
154 _Py_path_config.home = NULL;
155 new_config.program_name = _Py_path_config.program_name;
156 _Py_path_config.program_name = NULL;
157
158 _PyPathConfig_Clear(&_Py_path_config);
159 _Py_path_config = new_config;
160
161 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
162}
163
164
165void
Serhiy Storchaka4ae06c52017-12-12 13:55:04 +0200166Py_SetPythonHome(const wchar_t *home)
Victor Stinner31a83932017-12-04 13:39:15 +0100167{
168 if (home == NULL) {
169 return;
170 }
171
172 PyMemAllocatorEx old_alloc;
173 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
174
175 PyMem_RawFree(_Py_path_config.home);
176 _Py_path_config.home = _PyMem_RawWcsdup(home);
177
178 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
179
180 if (_Py_path_config.home == NULL) {
181 Py_FatalError("Py_SetPythonHome() failed: out of memory");
182 }
183}
184
185
186void
Serhiy Storchaka4ae06c52017-12-12 13:55:04 +0200187Py_SetProgramName(const wchar_t *program_name)
Victor Stinner31a83932017-12-04 13:39:15 +0100188{
189 if (program_name == NULL || program_name[0] == L'\0') {
190 return;
191 }
192
193 PyMemAllocatorEx old_alloc;
194 _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
195
196 PyMem_RawFree(_Py_path_config.program_name);
197 _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
198
199 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
200
201 if (_Py_path_config.program_name == NULL) {
202 Py_FatalError("Py_SetProgramName() failed: out of memory");
203 }
204}
205
206
207wchar_t *
208Py_GetPath(void)
209{
210 pathconfig_global_init();
211 return _Py_path_config.module_search_path;
212}
213
214
215wchar_t *
216Py_GetPrefix(void)
217{
218 pathconfig_global_init();
219 return _Py_path_config.prefix;
220}
221
222
223wchar_t *
224Py_GetExecPrefix(void)
225{
226#ifdef MS_WINDOWS
227 return Py_GetPrefix();
228#else
229 pathconfig_global_init();
230 return _Py_path_config.exec_prefix;
231#endif
232}
233
234
235wchar_t *
236Py_GetProgramFullPath(void)
237{
238 pathconfig_global_init();
239 return _Py_path_config.program_full_path;
240}
241
242
243wchar_t*
244Py_GetPythonHome(void)
245{
246 pathconfig_global_init();
247 return _Py_path_config.home;
248}
249
250
251wchar_t *
252Py_GetProgramName(void)
253{
254 pathconfig_global_init();
255 return _Py_path_config.program_name;
256}
257
258
Victor Stinner11a247d2017-12-13 21:05:57 +0100259#define _HAVE_SCRIPT_ARGUMENT(argc, argv) \
260 (argc > 0 && argv0 != NULL && \
261 wcscmp(argv0, L"-c") != 0 && wcscmp(argv0, L"-m") != 0)
262
263/* Compute argv[0] which will be prepended to sys.argv */
264PyObject*
265_PyPathConfig_ComputeArgv0(int argc, wchar_t **argv)
266{
267 wchar_t *argv0;
268 wchar_t *p = NULL;
269 Py_ssize_t n = 0;
270#ifdef HAVE_READLINK
271 wchar_t link[MAXPATHLEN+1];
272 wchar_t argv0copy[2*MAXPATHLEN+1];
273 int nr = 0;
274#endif
275#if defined(HAVE_REALPATH)
276 wchar_t fullpath[MAXPATHLEN];
277#elif defined(MS_WINDOWS)
278 wchar_t fullpath[MAX_PATH];
279#endif
280
281
282 argv0 = argv[0];
283
284#ifdef HAVE_READLINK
285 if (_HAVE_SCRIPT_ARGUMENT(argc, argv))
286 nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
287 if (nr > 0) {
288 /* It's a symlink */
289 link[nr] = '\0';
290 if (link[0] == SEP)
291 argv0 = link; /* Link to absolute path */
292 else if (wcschr(link, SEP) == NULL)
293 ; /* Link without path */
294 else {
295 /* Must join(dirname(argv0), link) */
296 wchar_t *q = wcsrchr(argv0, SEP);
297 if (q == NULL)
298 argv0 = link; /* argv0 without path */
299 else {
300 /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */
301 wcsncpy(argv0copy, argv0, MAXPATHLEN);
302 q = wcsrchr(argv0copy, SEP);
303 wcsncpy(q+1, link, MAXPATHLEN);
304 q[MAXPATHLEN + 1] = L'\0';
305 argv0 = argv0copy;
306 }
307 }
308 }
309#endif /* HAVE_READLINK */
310
311#if SEP == '\\'
312 /* Special case for Microsoft filename syntax */
313 if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) {
314 wchar_t *q;
315#if defined(MS_WINDOWS)
316 /* Replace the first element in argv with the full path. */
317 wchar_t *ptemp;
318 if (GetFullPathNameW(argv0,
319 Py_ARRAY_LENGTH(fullpath),
320 fullpath,
321 &ptemp)) {
322 argv0 = fullpath;
323 }
324#endif
325 p = wcsrchr(argv0, SEP);
326 /* Test for alternate separator */
327 q = wcsrchr(p ? p : argv0, '/');
328 if (q != NULL)
329 p = q;
330 if (p != NULL) {
331 n = p + 1 - argv0;
332 if (n > 1 && p[-1] != ':')
333 n--; /* Drop trailing separator */
334 }
335 }
336#else /* All other filename syntaxes */
337 if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) {
338#if defined(HAVE_REALPATH)
339 if (_Py_wrealpath(argv0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
340 argv0 = fullpath;
341 }
342#endif
343 p = wcsrchr(argv0, SEP);
344 }
345 if (p != NULL) {
346 n = p + 1 - argv0;
347#if SEP == '/' /* Special case for Unix filename syntax */
348 if (n > 1)
349 n--; /* Drop trailing separator */
350#endif /* Unix */
351 }
352#endif /* All others */
353
354 return PyUnicode_FromWideChar(argv0, n);
355}
356
Victor Stinner9bee3292017-12-21 16:49:13 +0100357
358/* Search for a prefix value in an environment file (pyvenv.cfg).
359 If found, copy it into the provided buffer. */
360int
361_Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
362 wchar_t *value, size_t value_size)
363{
364 int result = 0; /* meaning not found */
365 char buffer[MAXPATHLEN*2+1]; /* allow extra for key, '=', etc. */
366
367 fseek(env_file, 0, SEEK_SET);
368 while (!feof(env_file)) {
369 char * p = fgets(buffer, MAXPATHLEN*2, env_file);
Victor Stinner9bee3292017-12-21 16:49:13 +0100370
371 if (p == NULL) {
372 break;
373 }
Victor Stinner05d68a82018-01-18 11:15:25 +0100374
375 size_t n = strlen(p);
Victor Stinner9bee3292017-12-21 16:49:13 +0100376 if (p[n - 1] != '\n') {
377 /* line has overflowed - bail */
378 break;
379 }
380 if (p[0] == '#') {
381 /* Comment - skip */
382 continue;
383 }
Victor Stinner05d68a82018-01-18 11:15:25 +0100384
385 wchar_t *tmpbuffer = _Py_DecodeUTF8_surrogateescape(buffer, n);
Victor Stinner7ed7aea2018-01-15 10:45:49 +0100386 if (tmpbuffer) {
Victor Stinner9bee3292017-12-21 16:49:13 +0100387 wchar_t * state;
388 wchar_t * tok = wcstok(tmpbuffer, L" \t\r\n", &state);
389 if ((tok != NULL) && !wcscmp(tok, key)) {
390 tok = wcstok(NULL, L" \t", &state);
391 if ((tok != NULL) && !wcscmp(tok, L"=")) {
392 tok = wcstok(NULL, L"\r\n", &state);
393 if (tok != NULL) {
394 wcsncpy(value, tok, MAXPATHLEN);
395 result = 1;
396 PyMem_RawFree(tmpbuffer);
397 break;
398 }
399 }
400 }
401 PyMem_RawFree(tmpbuffer);
402 }
403 }
404 return result;
405}
406
Victor Stinner31a83932017-12-04 13:39:15 +0100407#ifdef __cplusplus
408}
409#endif