Home | History | Annotate | Download | only in Python
      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