You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

720 lines
18 KiB

  1. /* Path configuration like module_search_path (sys.path) */
  2. #include "Python.h"
  3. #include "osdefs.h"
  4. #include "pycore_fileutils.h"
  5. #include "pycore_pathconfig.h"
  6. #include "pycore_pymem.h"
  7. #include "pycore_pystate.h"
  8. #include <wchar.h>
  9. #ifdef __cplusplus
  10. extern "C" {
  11. #endif
  12. _PyPathConfig _Py_path_config = _PyPathConfig_INIT;
  13. static int
  14. copy_wstr(wchar_t **dst, const wchar_t *src)
  15. {
  16. if (src != NULL) {
  17. *dst = _PyMem_RawWcsdup(src);
  18. if (*dst == NULL) {
  19. return -1;
  20. }
  21. }
  22. else {
  23. *dst = NULL;
  24. }
  25. return 0;
  26. }
  27. static void
  28. _PyPathConfig_Clear(_PyPathConfig *config)
  29. {
  30. /* _PyMem_SetDefaultAllocator() is needed to get a known memory allocator,
  31. since Py_SetPath(), Py_SetPythonHome() and Py_SetProgramName() can be
  32. called before Py_Initialize() which can changes the memory allocator. */
  33. PyMemAllocatorEx old_alloc;
  34. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  35. #define CLEAR(ATTR) \
  36. do { \
  37. PyMem_RawFree(ATTR); \
  38. ATTR = NULL; \
  39. } while (0)
  40. CLEAR(config->prefix);
  41. CLEAR(config->program_full_path);
  42. #ifdef MS_WINDOWS
  43. CLEAR(config->dll_path);
  44. #else
  45. CLEAR(config->exec_prefix);
  46. #endif
  47. CLEAR(config->module_search_path);
  48. CLEAR(config->home);
  49. CLEAR(config->program_name);
  50. #undef CLEAR
  51. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  52. }
  53. /* Calculate the path configuration: initialize path_config from core_config */
  54. static _PyInitError
  55. _PyPathConfig_Calculate(_PyPathConfig *path_config,
  56. const _PyCoreConfig *core_config)
  57. {
  58. _PyInitError err;
  59. _PyPathConfig new_config = _PyPathConfig_INIT;
  60. PyMemAllocatorEx old_alloc;
  61. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  62. /* Calculate program_full_path, prefix, exec_prefix (Unix)
  63. or dll_path (Windows), and module_search_path */
  64. err = _PyPathConfig_Calculate_impl(&new_config, core_config);
  65. if (_Py_INIT_FAILED(err)) {
  66. goto err;
  67. }
  68. /* Copy home and program_name from core_config */
  69. if (copy_wstr(&new_config.home, core_config->home) < 0) {
  70. err = _Py_INIT_NO_MEMORY();
  71. goto err;
  72. }
  73. if (copy_wstr(&new_config.program_name, core_config->program_name) < 0) {
  74. err = _Py_INIT_NO_MEMORY();
  75. goto err;
  76. }
  77. _PyPathConfig_Clear(path_config);
  78. *path_config = new_config;
  79. err = _Py_INIT_OK();
  80. goto done;
  81. err:
  82. _PyPathConfig_Clear(&new_config);
  83. done:
  84. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  85. return err;
  86. }
  87. _PyInitError
  88. _PyPathConfig_SetGlobal(const _PyPathConfig *config)
  89. {
  90. _PyInitError err;
  91. _PyPathConfig new_config = _PyPathConfig_INIT;
  92. PyMemAllocatorEx old_alloc;
  93. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  94. #define COPY_ATTR(ATTR) \
  95. do { \
  96. if (copy_wstr(&new_config.ATTR, config->ATTR) < 0) { \
  97. _PyPathConfig_Clear(&new_config); \
  98. err = _Py_INIT_NO_MEMORY(); \
  99. goto done; \
  100. } \
  101. } while (0)
  102. COPY_ATTR(program_full_path);
  103. COPY_ATTR(prefix);
  104. #ifdef MS_WINDOWS
  105. COPY_ATTR(dll_path);
  106. #else
  107. COPY_ATTR(exec_prefix);
  108. #endif
  109. COPY_ATTR(module_search_path);
  110. COPY_ATTR(program_name);
  111. COPY_ATTR(home);
  112. _PyPathConfig_Clear(&_Py_path_config);
  113. /* Steal new_config strings; don't clear new_config */
  114. _Py_path_config = new_config;
  115. err = _Py_INIT_OK();
  116. done:
  117. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  118. return err;
  119. }
  120. void
  121. _PyPathConfig_ClearGlobal(void)
  122. {
  123. _PyPathConfig_Clear(&_Py_path_config);
  124. }
  125. static wchar_t*
  126. wstrlist_join(wchar_t sep, int count, wchar_t **list)
  127. {
  128. size_t len = 1; /* NUL terminator */
  129. for (int i=0; i < count; i++) {
  130. if (i != 0) {
  131. len++;
  132. }
  133. len += wcslen(list[i]);
  134. }
  135. wchar_t *text = PyMem_RawMalloc(len * sizeof(wchar_t));
  136. if (text == NULL) {
  137. return NULL;
  138. }
  139. wchar_t *str = text;
  140. for (int i=0; i < count; i++) {
  141. wchar_t *path = list[i];
  142. if (i != 0) {
  143. *str++ = SEP;
  144. }
  145. len = wcslen(path);
  146. memcpy(str, path, len * sizeof(wchar_t));
  147. str += len;
  148. }
  149. *str = L'\0';
  150. return text;
  151. }
  152. /* Set the global path configuration from core_config. */
  153. _PyInitError
  154. _PyCoreConfig_SetPathConfig(const _PyCoreConfig *core_config)
  155. {
  156. PyMemAllocatorEx old_alloc;
  157. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  158. _PyInitError err;
  159. _PyPathConfig path_config = _PyPathConfig_INIT;
  160. path_config.module_search_path = wstrlist_join(DELIM,
  161. core_config->nmodule_search_path,
  162. core_config->module_search_paths);
  163. if (path_config.module_search_path == NULL) {
  164. goto no_memory;
  165. }
  166. if (copy_wstr(&path_config.program_full_path, core_config->executable) < 0) {
  167. goto no_memory;
  168. }
  169. if (copy_wstr(&path_config.prefix, core_config->prefix) < 0) {
  170. goto no_memory;
  171. }
  172. #ifdef MS_WINDOWS
  173. if (copy_wstr(&path_config.dll_path, core_config->dll_path) < 0) {
  174. goto no_memory;
  175. }
  176. #else
  177. if (copy_wstr(&path_config.exec_prefix, core_config->exec_prefix) < 0) {
  178. goto no_memory;
  179. }
  180. #endif
  181. if (copy_wstr(&path_config.program_name, core_config->program_name) < 0) {
  182. goto no_memory;
  183. }
  184. if (copy_wstr(&path_config.home, core_config->home) < 0) {
  185. goto no_memory;
  186. }
  187. err = _PyPathConfig_SetGlobal(&path_config);
  188. if (_Py_INIT_FAILED(err)) {
  189. goto done;
  190. }
  191. err = _Py_INIT_OK();
  192. goto done;
  193. no_memory:
  194. err = _Py_INIT_NO_MEMORY();
  195. done:
  196. _PyPathConfig_Clear(&path_config);
  197. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  198. return err;
  199. }
  200. static _PyInitError
  201. core_config_init_module_search_paths(_PyCoreConfig *config,
  202. _PyPathConfig *path_config)
  203. {
  204. assert(config->module_search_paths == NULL);
  205. assert(config->nmodule_search_path < 0);
  206. config->nmodule_search_path = 0;
  207. const wchar_t *sys_path = path_config->module_search_path;
  208. const wchar_t delim = DELIM;
  209. const wchar_t *p = sys_path;
  210. while (1) {
  211. p = wcschr(sys_path, delim);
  212. if (p == NULL) {
  213. p = sys_path + wcslen(sys_path); /* End of string */
  214. }
  215. size_t path_len = (p - sys_path);
  216. wchar_t *path = PyMem_RawMalloc((path_len + 1) * sizeof(wchar_t));
  217. if (path == NULL) {
  218. return _Py_INIT_NO_MEMORY();
  219. }
  220. memcpy(path, sys_path, path_len * sizeof(wchar_t));
  221. path[path_len] = L'\0';
  222. _PyInitError err = _Py_wstrlist_append(&config->nmodule_search_path,
  223. &config->module_search_paths,
  224. path);
  225. PyMem_RawFree(path);
  226. if (_Py_INIT_FAILED(err)) {
  227. return err;
  228. }
  229. if (*p == '\0') {
  230. break;
  231. }
  232. sys_path = p + 1;
  233. }
  234. return _Py_INIT_OK();
  235. }
  236. static _PyInitError
  237. _PyCoreConfig_CalculatePathConfig(_PyCoreConfig *config)
  238. {
  239. _PyPathConfig path_config = _PyPathConfig_INIT;
  240. _PyInitError err;
  241. err = _PyPathConfig_Calculate(&path_config, config);
  242. if (_Py_INIT_FAILED(err)) {
  243. goto error;
  244. }
  245. if (config->nmodule_search_path < 0) {
  246. err = core_config_init_module_search_paths(config, &path_config);
  247. if (_Py_INIT_FAILED(err)) {
  248. goto error;
  249. }
  250. }
  251. if (config->executable == NULL) {
  252. if (copy_wstr(&config->executable,
  253. path_config.program_full_path) < 0) {
  254. goto no_memory;
  255. }
  256. }
  257. if (config->prefix == NULL) {
  258. if (copy_wstr(&config->prefix, path_config.prefix) < 0) {
  259. goto no_memory;
  260. }
  261. }
  262. if (config->exec_prefix == NULL) {
  263. #ifdef MS_WINDOWS
  264. wchar_t *exec_prefix = path_config.prefix;
  265. #else
  266. wchar_t *exec_prefix = path_config.exec_prefix;
  267. #endif
  268. if (copy_wstr(&config->exec_prefix, exec_prefix) < 0) {
  269. goto no_memory;
  270. }
  271. }
  272. #ifdef MS_WINDOWS
  273. if (config->dll_path == NULL) {
  274. if (copy_wstr(&config->dll_path, path_config.dll_path) < 0) {
  275. goto no_memory;
  276. }
  277. }
  278. #endif
  279. if (path_config.isolated != -1) {
  280. config->isolated = path_config.isolated;
  281. }
  282. if (path_config.site_import != -1) {
  283. config->site_import = path_config.site_import;
  284. }
  285. _PyPathConfig_Clear(&path_config);
  286. return _Py_INIT_OK();
  287. no_memory:
  288. err = _Py_INIT_NO_MEMORY();
  289. error:
  290. _PyPathConfig_Clear(&path_config);
  291. return err;
  292. }
  293. _PyInitError
  294. _PyCoreConfig_InitPathConfig(_PyCoreConfig *config)
  295. {
  296. /* Do we need to calculate the path? */
  297. if ((config->nmodule_search_path < 0)
  298. || (config->executable == NULL)
  299. || (config->prefix == NULL)
  300. #ifdef MS_WINDOWS
  301. || (config->dll_path == NULL)
  302. #endif
  303. || (config->exec_prefix == NULL))
  304. {
  305. _PyInitError err = _PyCoreConfig_CalculatePathConfig(config);
  306. if (_Py_INIT_FAILED(err)) {
  307. return err;
  308. }
  309. }
  310. if (config->base_prefix == NULL) {
  311. if (copy_wstr(&config->base_prefix, config->prefix) < 0) {
  312. return _Py_INIT_NO_MEMORY();
  313. }
  314. }
  315. if (config->base_exec_prefix == NULL) {
  316. if (copy_wstr(&config->base_exec_prefix, config->exec_prefix) < 0) {
  317. return _Py_INIT_NO_MEMORY();
  318. }
  319. }
  320. return _Py_INIT_OK();
  321. }
  322. static void
  323. pathconfig_global_init(void)
  324. {
  325. if (_Py_path_config.module_search_path != NULL) {
  326. /* Already initialized */
  327. return;
  328. }
  329. _PyInitError err;
  330. _PyCoreConfig config = _PyCoreConfig_INIT;
  331. err = _PyCoreConfig_Read(&config);
  332. if (_Py_INIT_FAILED(err)) {
  333. goto error;
  334. }
  335. err = _PyCoreConfig_SetPathConfig(&config);
  336. if (_Py_INIT_FAILED(err)) {
  337. goto error;
  338. }
  339. _PyCoreConfig_Clear(&config);
  340. return;
  341. error:
  342. _PyCoreConfig_Clear(&config);
  343. _Py_FatalInitError(err);
  344. }
  345. /* External interface */
  346. void
  347. Py_SetPath(const wchar_t *path)
  348. {
  349. if (path == NULL) {
  350. _PyPathConfig_Clear(&_Py_path_config);
  351. return;
  352. }
  353. PyMemAllocatorEx old_alloc;
  354. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  355. _PyPathConfig new_config;
  356. new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName());
  357. int alloc_error = (new_config.program_full_path == NULL);
  358. new_config.prefix = _PyMem_RawWcsdup(L"");
  359. alloc_error |= (new_config.prefix == NULL);
  360. #ifdef MS_WINDOWS
  361. new_config.dll_path = _PyMem_RawWcsdup(L"");
  362. alloc_error |= (new_config.dll_path == NULL);
  363. #else
  364. new_config.exec_prefix = _PyMem_RawWcsdup(L"");
  365. alloc_error |= (new_config.exec_prefix == NULL);
  366. #endif
  367. new_config.module_search_path = _PyMem_RawWcsdup(path);
  368. alloc_error |= (new_config.module_search_path == NULL);
  369. /* steal the home and program_name values (to leave them unchanged) */
  370. new_config.home = _Py_path_config.home;
  371. _Py_path_config.home = NULL;
  372. new_config.program_name = _Py_path_config.program_name;
  373. _Py_path_config.program_name = NULL;
  374. _PyPathConfig_Clear(&_Py_path_config);
  375. _Py_path_config = new_config;
  376. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  377. if (alloc_error) {
  378. Py_FatalError("Py_SetPath() failed: out of memory");
  379. }
  380. }
  381. void
  382. Py_SetPythonHome(const wchar_t *home)
  383. {
  384. if (home == NULL) {
  385. return;
  386. }
  387. PyMemAllocatorEx old_alloc;
  388. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  389. PyMem_RawFree(_Py_path_config.home);
  390. _Py_path_config.home = _PyMem_RawWcsdup(home);
  391. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  392. if (_Py_path_config.home == NULL) {
  393. Py_FatalError("Py_SetPythonHome() failed: out of memory");
  394. }
  395. }
  396. void
  397. Py_SetProgramName(const wchar_t *program_name)
  398. {
  399. if (program_name == NULL || program_name[0] == L'\0') {
  400. return;
  401. }
  402. PyMemAllocatorEx old_alloc;
  403. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  404. PyMem_RawFree(_Py_path_config.program_name);
  405. _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
  406. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  407. if (_Py_path_config.program_name == NULL) {
  408. Py_FatalError("Py_SetProgramName() failed: out of memory");
  409. }
  410. }
  411. wchar_t *
  412. Py_GetPath(void)
  413. {
  414. pathconfig_global_init();
  415. return _Py_path_config.module_search_path;
  416. }
  417. wchar_t *
  418. Py_GetPrefix(void)
  419. {
  420. pathconfig_global_init();
  421. return _Py_path_config.prefix;
  422. }
  423. wchar_t *
  424. Py_GetExecPrefix(void)
  425. {
  426. #ifdef MS_WINDOWS
  427. return Py_GetPrefix();
  428. #else
  429. pathconfig_global_init();
  430. return _Py_path_config.exec_prefix;
  431. #endif
  432. }
  433. wchar_t *
  434. Py_GetProgramFullPath(void)
  435. {
  436. pathconfig_global_init();
  437. return _Py_path_config.program_full_path;
  438. }
  439. wchar_t*
  440. Py_GetPythonHome(void)
  441. {
  442. pathconfig_global_init();
  443. return _Py_path_config.home;
  444. }
  445. wchar_t *
  446. Py_GetProgramName(void)
  447. {
  448. pathconfig_global_init();
  449. return _Py_path_config.program_name;
  450. }
  451. /* Compute argv[0] which will be prepended to sys.argv */
  452. PyObject*
  453. _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv)
  454. {
  455. wchar_t *argv0;
  456. wchar_t *p = NULL;
  457. Py_ssize_t n = 0;
  458. int have_script_arg = 0;
  459. int have_module_arg = 0;
  460. #ifdef HAVE_READLINK
  461. wchar_t link[MAXPATHLEN+1];
  462. wchar_t argv0copy[2*MAXPATHLEN+1];
  463. int nr = 0;
  464. #endif
  465. #if defined(HAVE_REALPATH)
  466. wchar_t fullpath[MAXPATHLEN];
  467. #elif defined(MS_WINDOWS)
  468. wchar_t fullpath[MAX_PATH];
  469. #endif
  470. argv0 = argv[0];
  471. if (argc > 0 && argv0 != NULL) {
  472. have_module_arg = (wcscmp(argv0, L"-m") == 0);
  473. have_script_arg = !have_module_arg && (wcscmp(argv0, L"-c") != 0);
  474. }
  475. if (have_module_arg) {
  476. #if defined(HAVE_REALPATH) || defined(MS_WINDOWS)
  477. _Py_wgetcwd(fullpath, Py_ARRAY_LENGTH(fullpath));
  478. argv0 = fullpath;
  479. n = wcslen(argv0);
  480. #else
  481. argv0 = L".";
  482. n = 1;
  483. #endif
  484. }
  485. #ifdef HAVE_READLINK
  486. if (have_script_arg)
  487. nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
  488. if (nr > 0) {
  489. /* It's a symlink */
  490. link[nr] = '\0';
  491. if (link[0] == SEP)
  492. argv0 = link; /* Link to absolute path */
  493. else if (wcschr(link, SEP) == NULL)
  494. ; /* Link without path */
  495. else {
  496. /* Must join(dirname(argv0), link) */
  497. wchar_t *q = wcsrchr(argv0, SEP);
  498. if (q == NULL)
  499. argv0 = link; /* argv0 without path */
  500. else {
  501. /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */
  502. wcsncpy(argv0copy, argv0, MAXPATHLEN);
  503. q = wcsrchr(argv0copy, SEP);
  504. wcsncpy(q+1, link, MAXPATHLEN);
  505. q[MAXPATHLEN + 1] = L'\0';
  506. argv0 = argv0copy;
  507. }
  508. }
  509. }
  510. #endif /* HAVE_READLINK */
  511. #if SEP == '\\'
  512. /* Special case for Microsoft filename syntax */
  513. if (have_script_arg) {
  514. wchar_t *q;
  515. #if defined(MS_WINDOWS)
  516. /* Replace the first element in argv with the full path. */
  517. wchar_t *ptemp;
  518. if (GetFullPathNameW(argv0,
  519. Py_ARRAY_LENGTH(fullpath),
  520. fullpath,
  521. &ptemp)) {
  522. argv0 = fullpath;
  523. }
  524. #endif
  525. p = wcsrchr(argv0, SEP);
  526. /* Test for alternate separator */
  527. q = wcsrchr(p ? p : argv0, '/');
  528. if (q != NULL)
  529. p = q;
  530. if (p != NULL) {
  531. n = p + 1 - argv0;
  532. if (n > 1 && p[-1] != ':')
  533. n--; /* Drop trailing separator */
  534. }
  535. }
  536. #else /* All other filename syntaxes */
  537. if (have_script_arg) {
  538. #if defined(HAVE_REALPATH)
  539. if (_Py_wrealpath(argv0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
  540. argv0 = fullpath;
  541. }
  542. #endif
  543. p = wcsrchr(argv0, SEP);
  544. }
  545. if (p != NULL) {
  546. n = p + 1 - argv0;
  547. #if SEP == '/' /* Special case for Unix filename syntax */
  548. if (n > 1)
  549. n--; /* Drop trailing separator */
  550. #endif /* Unix */
  551. }
  552. #endif /* All others */
  553. return PyUnicode_FromWideChar(argv0, n);
  554. }
  555. /* Search for a prefix value in an environment file (pyvenv.cfg).
  556. If found, copy it into the provided buffer. */
  557. int
  558. _Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
  559. wchar_t *value, size_t value_size)
  560. {
  561. int result = 0; /* meaning not found */
  562. char buffer[MAXPATHLEN*2+1]; /* allow extra for key, '=', etc. */
  563. fseek(env_file, 0, SEEK_SET);
  564. while (!feof(env_file)) {
  565. char * p = fgets(buffer, MAXPATHLEN*2, env_file);
  566. if (p == NULL) {
  567. break;
  568. }
  569. size_t n = strlen(p);
  570. if (p[n - 1] != '\n') {
  571. /* line has overflowed - bail */
  572. break;
  573. }
  574. if (p[0] == '#') {
  575. /* Comment - skip */
  576. continue;
  577. }
  578. wchar_t *tmpbuffer = _Py_DecodeUTF8_surrogateescape(buffer, n);
  579. if (tmpbuffer) {
  580. wchar_t * state;
  581. wchar_t * tok = wcstok(tmpbuffer, L" \t\r\n", &state);
  582. if ((tok != NULL) && !wcscmp(tok, key)) {
  583. tok = wcstok(NULL, L" \t", &state);
  584. if ((tok != NULL) && !wcscmp(tok, L"=")) {
  585. tok = wcstok(NULL, L"\r\n", &state);
  586. if (tok != NULL) {
  587. wcsncpy(value, tok, MAXPATHLEN);
  588. result = 1;
  589. PyMem_RawFree(tmpbuffer);
  590. break;
  591. }
  592. }
  593. }
  594. PyMem_RawFree(tmpbuffer);
  595. }
  596. }
  597. return result;
  598. }
  599. #ifdef __cplusplus
  600. }
  601. #endif