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 int
_PyPathConfig_ComputeArgv0(int argc,wchar_t ** argv,PyObject ** argv0_p)282 _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv, PyObject **argv0_p)
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 assert(*argv0_p == NULL);
301
302 argv0 = argv[0];
303 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)
310 if (!_Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath))) {
311 return 0;
312 }
313 argv0 = fullpath;
314 n = wcslen(argv0);
315 #else
316 argv0 = L".";
317 n = 1;
318 #endif
319 }
320
321 #ifdef HAVE_READLINK
322 if (have_script_arg)
323 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 */
350 if (have_script_arg) {
351 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 */
374 if (have_script_arg) {
375 #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
391 *argv0_p = PyUnicode_FromWideChar(argv0, n);
392 return 1;
393 }
394
395
396 /* Search for a prefix value in an environment file (pyvenv.cfg).
397 If found, copy it into the provided buffer. */
398 int
_Py_FindEnvConfigValue(FILE * env_file,const wchar_t * key,wchar_t * value,size_t value_size)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);
408
409 if (p == NULL) {
410 break;
411 }
412
413 size_t n = strlen(p);
414 if (p[n - 1] != '\n') {
415 /* line has overflowed - bail */
416 break;
417 }
418 if (p[0] == '#') {
419 /* Comment - skip */
420 continue;
421 }
422
423 wchar_t *tmpbuffer = _Py_DecodeUTF8_surrogateescape(buffer, n);
424 if (tmpbuffer) {
425 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
445 #ifdef __cplusplus
446 }
447 #endif
448