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.

409 lines
9.8 KiB

  1. /* Path configuration like module_search_path (sys.path) */
  2. #include "Python.h"
  3. #include "osdefs.h"
  4. #include "internal/pystate.h"
  5. #ifdef __cplusplus
  6. extern "C" {
  7. #endif
  8. _PyPathConfig _Py_path_config = _PyPathConfig_INIT;
  9. void
  10. _PyPathConfig_Clear(_PyPathConfig *config)
  11. {
  12. /* _PyMem_SetDefaultAllocator() is needed to get a known memory allocator,
  13. since Py_SetPath(), Py_SetPythonHome() and Py_SetProgramName() can be
  14. called before Py_Initialize() which can changes the memory allocator. */
  15. PyMemAllocatorEx old_alloc;
  16. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  17. #define CLEAR(ATTR) \
  18. do { \
  19. PyMem_RawFree(ATTR); \
  20. ATTR = NULL; \
  21. } while (0)
  22. CLEAR(config->prefix);
  23. CLEAR(config->program_full_path);
  24. #ifdef MS_WINDOWS
  25. CLEAR(config->dll_path);
  26. #else
  27. CLEAR(config->exec_prefix);
  28. #endif
  29. CLEAR(config->module_search_path);
  30. CLEAR(config->home);
  31. CLEAR(config->program_name);
  32. #undef CLEAR
  33. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  34. }
  35. /* Initialize paths for Py_GetPath(), Py_GetPrefix(), Py_GetExecPrefix()
  36. and Py_GetProgramFullPath() */
  37. _PyInitError
  38. _PyPathConfig_Init(const _PyCoreConfig *core_config)
  39. {
  40. if (_Py_path_config.module_search_path) {
  41. /* Already initialized */
  42. return _Py_INIT_OK();
  43. }
  44. _PyInitError err;
  45. _PyPathConfig new_config = _PyPathConfig_INIT;
  46. PyMemAllocatorEx old_alloc;
  47. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  48. /* Calculate program_full_path, prefix, exec_prefix (Unix)
  49. or dll_path (Windows), and module_search_path */
  50. err = _PyPathConfig_Calculate(&new_config, core_config);
  51. if (_Py_INIT_FAILED(err)) {
  52. _PyPathConfig_Clear(&new_config);
  53. goto done;
  54. }
  55. /* Copy home and program_name from core_config */
  56. if (core_config->home != NULL) {
  57. new_config.home = _PyMem_RawWcsdup(core_config->home);
  58. if (new_config.home == NULL) {
  59. err = _Py_INIT_NO_MEMORY();
  60. goto done;
  61. }
  62. }
  63. else {
  64. new_config.home = NULL;
  65. }
  66. new_config.program_name = _PyMem_RawWcsdup(core_config->program_name);
  67. if (new_config.program_name == NULL) {
  68. err = _Py_INIT_NO_MEMORY();
  69. goto done;
  70. }
  71. _PyPathConfig_Clear(&_Py_path_config);
  72. _Py_path_config = new_config;
  73. err = _Py_INIT_OK();
  74. done:
  75. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  76. return err;
  77. }
  78. static void
  79. pathconfig_global_init(void)
  80. {
  81. if (_Py_path_config.module_search_path) {
  82. /* Already initialized */
  83. return;
  84. }
  85. _PyInitError err;
  86. _PyCoreConfig config = _PyCoreConfig_INIT;
  87. err = _PyCoreConfig_Read(&config);
  88. if (_Py_INIT_FAILED(err)) {
  89. goto error;
  90. }
  91. err = _PyPathConfig_Init(&config);
  92. if (_Py_INIT_FAILED(err)) {
  93. goto error;
  94. }
  95. _PyCoreConfig_Clear(&config);
  96. return;
  97. error:
  98. _PyCoreConfig_Clear(&config);
  99. _Py_FatalInitError(err);
  100. }
  101. /* External interface */
  102. void
  103. Py_SetPath(const wchar_t *path)
  104. {
  105. if (path == NULL) {
  106. _PyPathConfig_Clear(&_Py_path_config);
  107. return;
  108. }
  109. PyMemAllocatorEx old_alloc;
  110. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  111. _PyPathConfig new_config;
  112. new_config.program_full_path = _PyMem_RawWcsdup(Py_GetProgramName());
  113. new_config.prefix = _PyMem_RawWcsdup(L"");
  114. #ifdef MS_WINDOWS
  115. new_config.dll_path = _PyMem_RawWcsdup(L"");
  116. #else
  117. new_config.exec_prefix = _PyMem_RawWcsdup(L"");
  118. #endif
  119. new_config.module_search_path = _PyMem_RawWcsdup(path);
  120. /* steal the home and program_name values (to leave them unchanged) */
  121. new_config.home = _Py_path_config.home;
  122. _Py_path_config.home = NULL;
  123. new_config.program_name = _Py_path_config.program_name;
  124. _Py_path_config.program_name = NULL;
  125. _PyPathConfig_Clear(&_Py_path_config);
  126. _Py_path_config = new_config;
  127. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  128. }
  129. void
  130. Py_SetPythonHome(const wchar_t *home)
  131. {
  132. if (home == NULL) {
  133. return;
  134. }
  135. PyMemAllocatorEx old_alloc;
  136. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  137. PyMem_RawFree(_Py_path_config.home);
  138. _Py_path_config.home = _PyMem_RawWcsdup(home);
  139. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  140. if (_Py_path_config.home == NULL) {
  141. Py_FatalError("Py_SetPythonHome() failed: out of memory");
  142. }
  143. }
  144. void
  145. Py_SetProgramName(const wchar_t *program_name)
  146. {
  147. if (program_name == NULL || program_name[0] == L'\0') {
  148. return;
  149. }
  150. PyMemAllocatorEx old_alloc;
  151. _PyMem_SetDefaultAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  152. PyMem_RawFree(_Py_path_config.program_name);
  153. _Py_path_config.program_name = _PyMem_RawWcsdup(program_name);
  154. PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &old_alloc);
  155. if (_Py_path_config.program_name == NULL) {
  156. Py_FatalError("Py_SetProgramName() failed: out of memory");
  157. }
  158. }
  159. wchar_t *
  160. Py_GetPath(void)
  161. {
  162. pathconfig_global_init();
  163. return _Py_path_config.module_search_path;
  164. }
  165. wchar_t *
  166. Py_GetPrefix(void)
  167. {
  168. pathconfig_global_init();
  169. return _Py_path_config.prefix;
  170. }
  171. wchar_t *
  172. Py_GetExecPrefix(void)
  173. {
  174. #ifdef MS_WINDOWS
  175. return Py_GetPrefix();
  176. #else
  177. pathconfig_global_init();
  178. return _Py_path_config.exec_prefix;
  179. #endif
  180. }
  181. wchar_t *
  182. Py_GetProgramFullPath(void)
  183. {
  184. pathconfig_global_init();
  185. return _Py_path_config.program_full_path;
  186. }
  187. wchar_t*
  188. Py_GetPythonHome(void)
  189. {
  190. pathconfig_global_init();
  191. return _Py_path_config.home;
  192. }
  193. wchar_t *
  194. Py_GetProgramName(void)
  195. {
  196. pathconfig_global_init();
  197. return _Py_path_config.program_name;
  198. }
  199. #define _HAVE_SCRIPT_ARGUMENT(argc, argv) \
  200. (argc > 0 && argv0 != NULL && \
  201. wcscmp(argv0, L"-c") != 0 && wcscmp(argv0, L"-m") != 0)
  202. /* Compute argv[0] which will be prepended to sys.argv */
  203. PyObject*
  204. _PyPathConfig_ComputeArgv0(int argc, wchar_t **argv)
  205. {
  206. wchar_t *argv0;
  207. wchar_t *p = NULL;
  208. Py_ssize_t n = 0;
  209. #ifdef HAVE_READLINK
  210. wchar_t link[MAXPATHLEN+1];
  211. wchar_t argv0copy[2*MAXPATHLEN+1];
  212. int nr = 0;
  213. #endif
  214. #if defined(HAVE_REALPATH)
  215. wchar_t fullpath[MAXPATHLEN];
  216. #elif defined(MS_WINDOWS)
  217. wchar_t fullpath[MAX_PATH];
  218. #endif
  219. argv0 = argv[0];
  220. #ifdef HAVE_READLINK
  221. if (_HAVE_SCRIPT_ARGUMENT(argc, argv))
  222. nr = _Py_wreadlink(argv0, link, MAXPATHLEN);
  223. if (nr > 0) {
  224. /* It's a symlink */
  225. link[nr] = '\0';
  226. if (link[0] == SEP)
  227. argv0 = link; /* Link to absolute path */
  228. else if (wcschr(link, SEP) == NULL)
  229. ; /* Link without path */
  230. else {
  231. /* Must join(dirname(argv0), link) */
  232. wchar_t *q = wcsrchr(argv0, SEP);
  233. if (q == NULL)
  234. argv0 = link; /* argv0 without path */
  235. else {
  236. /* Must make a copy, argv0copy has room for 2 * MAXPATHLEN */
  237. wcsncpy(argv0copy, argv0, MAXPATHLEN);
  238. q = wcsrchr(argv0copy, SEP);
  239. wcsncpy(q+1, link, MAXPATHLEN);
  240. q[MAXPATHLEN + 1] = L'\0';
  241. argv0 = argv0copy;
  242. }
  243. }
  244. }
  245. #endif /* HAVE_READLINK */
  246. #if SEP == '\\'
  247. /* Special case for Microsoft filename syntax */
  248. if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) {
  249. wchar_t *q;
  250. #if defined(MS_WINDOWS)
  251. /* Replace the first element in argv with the full path. */
  252. wchar_t *ptemp;
  253. if (GetFullPathNameW(argv0,
  254. Py_ARRAY_LENGTH(fullpath),
  255. fullpath,
  256. &ptemp)) {
  257. argv0 = fullpath;
  258. }
  259. #endif
  260. p = wcsrchr(argv0, SEP);
  261. /* Test for alternate separator */
  262. q = wcsrchr(p ? p : argv0, '/');
  263. if (q != NULL)
  264. p = q;
  265. if (p != NULL) {
  266. n = p + 1 - argv0;
  267. if (n > 1 && p[-1] != ':')
  268. n--; /* Drop trailing separator */
  269. }
  270. }
  271. #else /* All other filename syntaxes */
  272. if (_HAVE_SCRIPT_ARGUMENT(argc, argv)) {
  273. #if defined(HAVE_REALPATH)
  274. if (_Py_wrealpath(argv0, fullpath, Py_ARRAY_LENGTH(fullpath))) {
  275. argv0 = fullpath;
  276. }
  277. #endif
  278. p = wcsrchr(argv0, SEP);
  279. }
  280. if (p != NULL) {
  281. n = p + 1 - argv0;
  282. #if SEP == '/' /* Special case for Unix filename syntax */
  283. if (n > 1)
  284. n--; /* Drop trailing separator */
  285. #endif /* Unix */
  286. }
  287. #endif /* All others */
  288. return PyUnicode_FromWideChar(argv0, n);
  289. }
  290. /* Search for a prefix value in an environment file (pyvenv.cfg).
  291. If found, copy it into the provided buffer. */
  292. int
  293. _Py_FindEnvConfigValue(FILE *env_file, const wchar_t *key,
  294. wchar_t *value, size_t value_size)
  295. {
  296. int result = 0; /* meaning not found */
  297. char buffer[MAXPATHLEN*2+1]; /* allow extra for key, '=', etc. */
  298. fseek(env_file, 0, SEEK_SET);
  299. while (!feof(env_file)) {
  300. char * p = fgets(buffer, MAXPATHLEN*2, env_file);
  301. if (p == NULL) {
  302. break;
  303. }
  304. size_t n = strlen(p);
  305. if (p[n - 1] != '\n') {
  306. /* line has overflowed - bail */
  307. break;
  308. }
  309. if (p[0] == '#') {
  310. /* Comment - skip */
  311. continue;
  312. }
  313. wchar_t *tmpbuffer = _Py_DecodeUTF8_surrogateescape(buffer, n);
  314. if (tmpbuffer) {
  315. wchar_t * state;
  316. wchar_t * tok = wcstok(tmpbuffer, L" \t\r\n", &state);
  317. if ((tok != NULL) && !wcscmp(tok, key)) {
  318. tok = wcstok(NULL, L" \t", &state);
  319. if ((tok != NULL) && !wcscmp(tok, L"=")) {
  320. tok = wcstok(NULL, L"\r\n", &state);
  321. if (tok != NULL) {
  322. wcsncpy(value, tok, MAXPATHLEN);
  323. result = 1;
  324. PyMem_RawFree(tmpbuffer);
  325. break;
  326. }
  327. }
  328. }
  329. PyMem_RawFree(tmpbuffer);
  330. }
  331. }
  332. return result;
  333. }
  334. #ifdef __cplusplus
  335. }
  336. #endif