1 /* Path configuration like module_search_path (sys.path) */
2
3 #include "Python.h"
4 #include "osdefs.h"
5 #include "internal/pystate.h"
6 #include <wchar.h>
7
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11
12
13 _PyPathConfig _Py_path_config = _PyPathConfig_INIT;
14
15
16 void
_PyPathConfig_Clear(_PyPathConfig * config)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
_PyPathConfig_Init(const _PyCoreConfig * core_config)50 _PyPathConfig_Init(const _PyCoreConfig *core_config)
51 {
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 */
65 err = _PyPathConfig_Calculate(&new_config, core_config);
66 if (_Py_INIT_FAILED(err)) {
67 _PyPathConfig_Clear(&new_config);
68 goto done;
69 }
70
71 /* Copy home and program_name from core_config */
72 if (core_config->home != NULL) {
73 new_config.home = _PyMem_RawWcsdup(core_config->home);
74 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
83 new_config.program_name = _PyMem_RawWcsdup(core_config->program_name);
84 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
94 done:
95 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
96 return err;
97 }
98
99
100 static void
pathconfig_global_init(void)101 pathconfig_global_init(void)
102 {
103 if (_Py_path_config.module_search_path) {
104 /* Already initialized */
105 return;
106 }
107
108 _PyInitError err;
109 _PyCoreConfig config = _PyCoreConfig_INIT;
110
111 err = _PyCoreConfig_Read(&config);
112 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
121 _PyCoreConfig_Clear(&config);
122 return;
123
124 error:
125 _PyCoreConfig_Clear(&config);
126 _Py_FatalInitError(err);
127 }
128
129
130 /* External interface */
131
132 void
Py_SetPath(const wchar_t * path)133 Py_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
166 void
Py_SetPythonHome(const wchar_t * home)167 Py_SetPythonHome(const wchar_t *home)
168 {
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
187 void
Py_SetProgramName(const wchar_t * program_name)188 Py_SetProgramName(const wchar_t *program_name)
189 {
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
208 void
_Py_SetProgramFullPath(const wchar_t * program_full_path)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
229 wchar_t *
Py_GetPath(void)230 Py_GetPath(void)
231 {
232 pathconfig_global_init();
233 return _Py_path_config.module_search_path;
234 }
235
236
237 wchar_t *
Py_GetPrefix(void)238 Py_GetPrefix(void)
239 {
240 pathconfig_global_init();
241 return _Py_path_config.prefix;
242 }
243
244
245 wchar_t *
Py_GetExecPrefix(void)246 Py_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
257 wchar_t *
Py_GetProgramFullPath(void)258 Py_GetProgramFullPath(void)
259 {
260 pathconfig_global_init();
261 return _Py_path_config.program_full_path;
262 }
263
264
265 wchar_t*
Py_GetPythonHome(void)266 Py_GetPythonHome(void)
267 {
268 pathconfig_global_init();
269 return _Py_path_config.home;
270 }
271
272
273 wchar_t *
Py_GetProgramName(void)274 Py_GetProgramName(void)
275 {
276 pathconfig_global_init();
277 return _Py_path_config.program_name;
278 }
279
280 /* Compute argv[0] which will be prepended to sys.argv */
281 PyObject*
_PyPathConfig_ComputeArgv0(int argc,wchar_t ** argv)282 _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv)
283 {
284 wchar_t *argv0;
285 wchar_t *p = NULL;
286 Py_ssize_t n = 0;
287 int have_script_arg = 0;
288 int have_module_arg = 0;
289 #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
300 argv0 = argv[0];
301 if (argc > 0 && argv0 != NULL) {
302 have_module_arg = (wcscmp(argv0, L"-m") == 0);
303 have_script_arg = !have_module_arg && (wcscmp(argv0, L"-c") != 0);
304 }
305
306 if (have_module_arg) {
307 #if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
308 _Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath));
309 argv0 = fullpath;
310 n = wcslen(argv0);
311 #else
312 argv0 = L".";
313 n = 1;
314 #endif
315 }
316
317 #ifdef HAVE_READLINK
318 if (have_script_arg)
319 nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
320 if (nr > 0) {
321 /* It's a symlink */
322 link[nr] = '\0';
323 if (link[0] == SEP)
324 argv0 = link; /* Link to absolute path */
325 else if (wcschr(link, SEP) == NULL)
326 ; /* Link without path */
327 else {
328 /* Must join(dirname(argv0), link) */
329 wchar_t *q = wcsrchr(argv0, SEP);
330 if (q == NULL)
331 argv0 = link; /* argv0 without path */
332 else {
333 /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */
334 wcsncpy(argv0copy, argv0, MAXPATHLEN);
335 q = wcsrchr(argv0copy, SEP);
336 wcsncpy(q+1, link, MAXPATHLEN);
337 q[MAXPATHLEN + 1] = L'\0';
338 argv0 = argv0copy;
339 }
340 }
341 }
342 #endif /* HAVE_READLINK */
343
344 #if SEP == '\\'
345 /* Special case for Microsoft filename syntax */
346 if (have_script_arg) {
347 wchar_t *q;
348 #if defined(MS_WINDOWS)
349 /* Replace the first element in argv with the full path. */
350 wchar_t *ptemp;
351 if (GetFullPathNameW(argv0,
352 Py_ARRAY_LENGTH(fullpath),
353 fullpath,
354 &ptemp)) {
355 argv0 = fullpath;
356 }
357 #endif
358 p = wcsrchr(argv0, SEP);
359 /* Test for alternate separator */
360 q = wcsrchr(p ? p : argv0, '/');
361 if (q != NULL)
362 p = q;
363 if (p != NULL) {
364 n = p + 1 - argv0;
365 if (n > 1 && p[-1] != ':')
366 n--; /* Drop trailing separator */
367 }
368 }
369 #else /* All other filename syntaxes */
370 if (have_script_arg) {
371 #if defined(HAVE_REALPATH)
372 if (_Py_wrealpath(argv0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
373 argv0 = fullpath;
374 }
375 #endif
376 p = wcsrchr(argv0, SEP);
377 }
378 if (p != NULL) {
379 n = p + 1 - argv0;
380 #if SEP == '/' /* Special case for Unix filename syntax */
381 if (n > 1)
382 n--; /* Drop trailing separator */
383 #endif /* Unix */
384 }
385 #endif /* All others */
386
387 return PyUnicode_FromWideChar(argv0, n);
388 }
389
390
391 /* Search for a prefix value in an environment file (pyvenv.cfg).
392 If found, copy it into the provided buffer. */
393 int
_Py_FindEnvConfigValue(FILE * env_file,const wchar_t * key,wchar_t * value,size_t value_size)394 _Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
395 wchar_t *value, size_t value_size)
396 {
397 int result = 0; /* meaning not found */
398 char buffer[MAXPATHLEN*2+1]; /* allow extra for key, '=', etc. */
399
400 fseek(env_file, 0, SEEK_SET);
401 while (!feof(env_file)) {
402 char * p = fgets(buffer, MAXPATHLEN*2, env_file);
403
404 if (p == NULL) {
405 break;
406 }
407
408 size_t n = strlen(p);
409 if (p[n - 1] != '\n') {
410 /* line has overflowed - bail */
411 break;
412 }
413 if (p[0] == '#') {
414 /* Comment - skip */
415 continue;
416 }
417
418 wchar_t *tmpbuffer = _Py_DecodeUTF8_surrogateescape(buffer, n);
419 if (tmpbuffer) {
420 wchar_t * state;
421 wchar_t * tok = wcstok(tmpbuffer, L" \t\r\n", &state);
422 if ((tok != NULL) && !wcscmp(tok, key)) {
423 tok = wcstok(NULL, L" \t", &state);
424 if ((tok != NULL) && !wcscmp(tok, L"=")) {
425 tok = wcstok(NULL, L"\r\n", &state);
426 if (tok != NULL) {
427 wcsncpy(value, tok, MAXPATHLEN);
428 result = 1;
429 PyMem_RawFree(tmpbuffer);
430 break;
431 }
432 }
433 }
434 PyMem_RawFree(tmpbuffer);
435 }
436 }
437 return result;
438 }
439
440 #ifdef __cplusplus
441 }
442 #endif
443