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.

421 lines
10 KiB

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