1 
2 /* Return the initial module search path. */
3 /* This version used by OS/2+EMX */
4 
5 /* ----------------------------------------------------------------
6    PATH RULES FOR OS/2+EMX:
7    This describes how sys.path is formed on OS/2+EMX.  It describes the
8    functionality, not the implementation (ie, the order in which these
9    are actually fetched is different)
10 
11    * Python always adds an empty entry at the start, which corresponds
12      to the current directory.
13 
14    * If the PYTHONPATH env. var. exists, its entries are added next.
15 
16    * We attempt to locate the "Python Home" - if the PYTHONHOME env var
17      is set, we believe it.  Otherwise, we use the path of our host .EXE's
18      to try and locate our "landmark" (lib\\os.py) and deduce our home.
19      - If we DO have a Python Home: The relevant sub-directories (Lib,
20        plat-win, lib-tk, etc) are based on the Python Home
21      - If we DO NOT have a Python Home, the core Python Path is
22        loaded from the registry.  This is the main PythonPath key,
23        and both HKLM and HKCU are combined to form the path)
24 
25    * Iff - we can not locate the Python Home, and have not had a PYTHONPATH
26      specified (ie, we have _nothing_ we can assume is a good path), a
27      default path with relative entries is used (eg. .\Lib;.\plat-win, etc)
28 
29 
30   The end result of all this is:
31   * When running python.exe, or any other .exe in the main Python directory
32     (either an installed version, or directly from the PCbuild directory),
33     the core path is deduced.
34 
35   * When Python is hosted in another exe (different directory, embedded via
36     COM, etc), the Python Home will not be deduced, so the core path from
37     the registry is used.  Other "application paths "in the registry are
38     always read.
39 
40   * If Python can't find its home and there is no registry (eg, frozen
41     exe, some very strange installation setup) you get a path with
42     some default, but relative, paths.
43 
44    ---------------------------------------------------------------- */
45 
46 
47 #include "Python.h"
48 #include "osdefs.h"
49 
50 #ifndef PYOS_OS2
51 #error This file only compilable on OS/2
52 #endif
53 
54 #define INCL_DOS
55 #include <os2.h>
56 
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <string.h>
60 
61 #if HAVE_UNISTD_H
62 #include <unistd.h>
63 #endif /* HAVE_UNISTD_H */
64 
65 /* Search in some common locations for the associated Python libraries.
66  *
67  * Py_GetPath() tries to return a sensible Python module search path.
68  *
69  * The approach is an adaptation for Windows of the strategy used in
70  * ../Modules/getpath.c; it uses the Windows Registry as one of its
71  * information sources.
72  */
73 
74 #ifndef LANDMARK
75 #if defined(PYCC_GCC)
76 #define LANDMARK "lib/os.py"
77 #else
78 #define LANDMARK "lib\\os.py"
79 #endif
80 #endif
81 
82 static char prefix[MAXPATHLEN+1];
83 static char progpath[MAXPATHLEN+1];
84 static char *module_search_path = NULL;
85 
86 
87 static int
is_sep(char ch)88 is_sep(char ch) /* determine if "ch" is a separator character */
89 {
90 #ifdef ALTSEP
91     return ch == SEP || ch == ALTSEP;
92 #else
93     return ch == SEP;
94 #endif
95 }
96 
97 /* assumes 'dir' null terminated in bounds.
98  * Never writes beyond existing terminator.
99  */
100 static void
reduce(char * dir)101 reduce(char *dir)
102 {
103     size_t i = strlen(dir);
104     while (i > 0 && !is_sep(dir[i]))
105         --i;
106     dir[i] = '\0';
107 }
108 
109 static int
exists(char * filename)110 exists(char *filename)
111 {
112     struct stat buf;
113     return stat(filename, &buf) == 0;
114 }
115 
116 /* Is module  (check for .pyc/.pyo too)
117  * Assumes 'filename' MAXPATHLEN+1 bytes long -
118  * may extend 'filename' by one character.
119  */
120 static int
ismodule(char * filename)121 ismodule(char *filename)
122 {
123     if (exists(filename))
124         return 1;
125 
126     /* Check for the compiled version of prefix. */
127     if (strlen(filename) < MAXPATHLEN) {
128         strcat(filename, Py_OptimizeFlag ? "o" : "c");
129         if (exists(filename))
130             return 1;
131     }
132     return 0;
133 }
134 
135 /* Add a path component, by appending stuff to buffer.
136    buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a
137    NUL-terminated string with no more than MAXPATHLEN characters (not counting
138    the trailing NUL).  It's a fatal error if it contains a string longer than
139    that (callers must be careful!).  If these requirements are met, it's
140    guaranteed that buffer will still be a NUL-terminated string with no more
141    than MAXPATHLEN characters at exit.  If stuff is too long, only as much of
142    stuff as fits will be appended.
143 */
144 
145 static void
join(char * buffer,char * stuff)146 join(char *buffer, char *stuff)
147 {
148     size_t n, k;
149     if (is_sep(stuff[0]))
150         n = 0;
151     else {
152         n = strlen(buffer);
153         if (n > 0 && !is_sep(buffer[n-1]) && n < MAXPATHLEN)
154             buffer[n++] = SEP;
155     }
156     if (n > MAXPATHLEN)
157         Py_FatalError("buffer overflow in getpathp.c's joinpath()");
158     k = strlen(stuff);
159     if (n + k > MAXPATHLEN)
160         k = MAXPATHLEN - n;
161     strncpy(buffer+n, stuff, k);
162     buffer[n+k] = '\0';
163 }
164 
165 /* gotlandmark only called by search_for_prefix, which ensures
166  * 'prefix' is null terminated in bounds.  join() ensures
167  * 'landmark' can not overflow prefix if too long.
168  */
169 static int
gotlandmark(char * landmark)170 gotlandmark(char *landmark)
171 {
172     int n, ok;
173 
174     n = strlen(prefix);
175     join(prefix, landmark);
176     ok = ismodule(prefix);
177     prefix[n] = '\0';
178     return ok;
179 }
180 
181 /* assumes argv0_path is MAXPATHLEN+1 bytes long, already \0 term'd.
182  * assumption provided by only caller, calculate_path()
183  */
184 static int
search_for_prefix(char * argv0_path,char * landmark)185 search_for_prefix(char *argv0_path, char *landmark)
186 {
187     /* Search from argv0_path, until landmark is found */
188     strcpy(prefix, argv0_path);
189     do {
190         if (gotlandmark(landmark))
191             return 1;
192         reduce(prefix);
193     } while (prefix[0]);
194     return 0;
195 }
196 
197 
198 static void
get_progpath(void)199 get_progpath(void)
200 {
201     extern char *Py_GetProgramName(void);
202     char *path = getenv("PATH");
203     char *prog = Py_GetProgramName();
204 
205     PPIB pib;
206     if ((DosGetInfoBlocks(NULL, &pib) == 0) &&
207         (DosQueryModuleName(pib->pib_hmte, sizeof(progpath), progpath) == 0))
208         return;
209 
210     if (prog == NULL || *prog == '\0')
211         prog = "python";
212 
213     /* If there is no slash in the argv0 path, then we have to
214      * assume python is on the user's $PATH, since there's no
215      * other way to find a directory to start the search from.  If
216      * $PATH isn't exported, you lose.
217      */
218 #ifdef ALTSEP
219     if (strchr(prog, SEP) || strchr(prog, ALTSEP))
220 #else
221     if (strchr(prog, SEP))
222 #endif
223         strncpy(progpath, prog, MAXPATHLEN);
224     else if (path) {
225         while (1) {
226             char *delim = strchr(path, DELIM);
227 
228             if (delim) {
229                 size_t len = delim - path;
230                 /* ensure we can't overwrite buffer */
231 #if !defined(PYCC_GCC)
232                 len = min(MAXPATHLEN,len);
233 #else
234                 len = MAXPATHLEN < len ? MAXPATHLEN : len;
235 #endif
236                 strncpy(progpath, path, len);
237                 *(progpath + len) = '\0';
238             }
239             else
240                 strncpy(progpath, path, MAXPATHLEN);
241 
242             /* join() is safe for MAXPATHLEN+1 size buffer */
243             join(progpath, prog);
244             if (exists(progpath))
245                 break;
246 
247             if (!delim) {
248                 progpath[0] = '\0';
249                 break;
250             }
251             path = delim + 1;
252         }
253     }
254     else
255         progpath[0] = '\0';
256 }
257 
258 static void
calculate_path(void)259 calculate_path(void)
260 {
261     char argv0_path[MAXPATHLEN+1];
262     char *buf;
263     size_t bufsz;
264     char *pythonhome = Py_GetPythonHome();
265     char *envpath = getenv("PYTHONPATH");
266     char zip_path[MAXPATHLEN+1];
267     size_t len;
268 
269     get_progpath();
270     /* progpath guaranteed \0 terminated in MAXPATH+1 bytes. */
271     strcpy(argv0_path, progpath);
272     reduce(argv0_path);
273     if (pythonhome == NULL || *pythonhome == '\0') {
274         if (search_for_prefix(argv0_path, LANDMARK))
275             pythonhome = prefix;
276         else
277             pythonhome = NULL;
278     }
279     else
280         strncpy(prefix, pythonhome, MAXPATHLEN);
281 
282     if (envpath && *envpath == '\0')
283         envpath = NULL;
284 
285     /* Calculate zip archive path */
286     strncpy(zip_path, progpath, MAXPATHLEN);
287     zip_path[MAXPATHLEN] = '\0';
288     len = strlen(zip_path);
289     if (len > 4) {
290         zip_path[len-3] = 'z';  /* change ending to "zip" */
291         zip_path[len-2] = 'i';
292         zip_path[len-1] = 'p';
293     }
294     else {
295         zip_path[0] = 0;
296     }
297 
298     /* We need to construct a path from the following parts.
299      * (1) the PYTHONPATH environment variable, if set;
300      * (2) the zip archive file path;
301      * (3) the PYTHONPATH config macro, with the leading "."
302      *     of each component replaced with pythonhome, if set;
303      * (4) the directory containing the executable (argv0_path).
304      * The length calculation calculates #3 first.
305      */
306 
307     /* Calculate size of return buffer */
308     if (pythonhome != NULL) {
309         char *p;
310         bufsz = 1;
311         for (p = PYTHONPATH; *p; p++) {
312             if (*p == DELIM)
313                 bufsz++; /* number of DELIM plus one */
314         }
315         bufsz *= strlen(pythonhome);
316     }
317     else
318         bufsz = 0;
319     bufsz += strlen(PYTHONPATH) + 1;
320     bufsz += strlen(argv0_path) + 1;
321     bufsz += strlen(zip_path) + 1;
322     if (envpath != NULL)
323         bufsz += strlen(envpath) + 1;
324 
325     module_search_path = buf = malloc(bufsz);
326     if (buf == NULL) {
327         /* We can't exit, so print a warning and limp along */
328         fprintf(stderr, "Can't malloc dynamic PYTHONPATH.\n");
329         if (envpath) {
330             fprintf(stderr, "Using environment $PYTHONPATH.\n");
331             module_search_path = envpath;
332         }
333         else {
334             fprintf(stderr, "Using default static path.\n");
335             module_search_path = PYTHONPATH;
336         }
337         return;
338     }
339 
340     if (envpath) {
341         strcpy(buf, envpath);
342         buf = strchr(buf, '\0');
343         *buf++ = DELIM;
344     }
345     if (zip_path[0]) {
346         strcpy(buf, zip_path);
347         buf = strchr(buf, '\0');
348         *buf++ = DELIM;
349     }
350 
351     if (pythonhome == NULL) {
352         strcpy(buf, PYTHONPATH);
353         buf = strchr(buf, '\0');
354     }
355     else {
356         char *p = PYTHONPATH;
357         char *q;
358         size_t n;
359         for (;;) {
360             q = strchr(p, DELIM);
361             if (q == NULL)
362                 n = strlen(p);
363             else
364                 n = q-p;
365             if (p[0] == '.' && is_sep(p[1])) {
366                 strcpy(buf, pythonhome);
367                 buf = strchr(buf, '\0');
368                 p++;
369                 n--;
370             }
371             strncpy(buf, p, n);
372             buf += n;
373             if (q == NULL)
374                 break;
375             *buf++ = DELIM;
376             p = q+1;
377         }
378     }
379     if (argv0_path) {
380         *buf++ = DELIM;
381         strcpy(buf, argv0_path);
382         buf = strchr(buf, '\0');
383     }
384     *buf = '\0';
385 }
386 
387 
388 /* External interface */
389 
390 char *
Py_GetPath(void)391 Py_GetPath(void)
392 {
393     if (!module_search_path)
394         calculate_path();
395     return module_search_path;
396 }
397 
398 char *
Py_GetPrefix(void)399 Py_GetPrefix(void)
400 {
401     if (!module_search_path)
402         calculate_path();
403     return prefix;
404 }
405 
406 char *
Py_GetExecPrefix(void)407 Py_GetExecPrefix(void)
408 {
409     return Py_GetPrefix();
410 }
411 
412 char *
Py_GetProgramFullPath(void)413 Py_GetProgramFullPath(void)
414 {
415     if (!module_search_path)
416         calculate_path();
417     return progpath;
418 }
419