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 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 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 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 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 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 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 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 * 230 Py_GetPath(void) 231 { 232 pathconfig_global_init(); 233 return _Py_path_config.module_search_path; 234 } 235 236 237 wchar_t * 238 Py_GetPrefix(void) 239 { 240 pathconfig_global_init(); 241 return _Py_path_config.prefix; 242 } 243 244 245 wchar_t * 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 * 258 Py_GetProgramFullPath(void) 259 { 260 pathconfig_global_init(); 261 return _Py_path_config.program_full_path; 262 } 263 264 265 wchar_t* 266 Py_GetPythonHome(void) 267 { 268 pathconfig_global_init(); 269 return _Py_path_config.home; 270 } 271 272 273 wchar_t * 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* 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 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