21 # include <sys/param.h>
25 # include <Evil.h> /* for realpath */
30 #endif /* ! HAVE_EVIL */
32 #include "embryo_cc_prefix.h"
34 /* local subsystem functions */
35 static int _e_prefix_share_hunt(void);
36 static int _e_prefix_fallbacks(void);
37 static int _e_prefix_try_proc(void);
38 static int _e_prefix_try_argv(char *argv0);
40 /* local subsystem globals */
41 static char *_exe_path = NULL;
42 static char *_prefix_path = NULL;
43 static char *_prefix_path_bin = NULL;
44 static char *_prefix_path_data = NULL;
45 static char *_prefix_path_lib = NULL;
47 #define E_FREE(p) { if (p) {free(p); p = NULL;} }
49 /*#define PREFIX_CACHE_FILE 1*/
50 #define SHARE_D "share/embryo"
51 #define MAGIC_FILE "include/default.inc"
52 #define MAGIC_DAT SHARE_D"/"MAGIC_FILE
54 /* externally accessible functions */
56 e_prefix_determine(char *argv0)
63 /* if user provides E_PREFIX - then use that or also more specific sub
64 * dirs for bin, lib, data and locale */
65 if (getenv("EMBRYO_PREFIX"))
67 _prefix_path = strdup(getenv("EMBRYO_PREFIX"));
68 if (getenv("EMBRYO_BIN_DIR"))
69 snprintf(buf, sizeof(buf), "%s/bin", getenv("EMBRYO_BIN_DIR"));
71 snprintf(buf, sizeof(buf), "%s/bin", _prefix_path);
72 _prefix_path_bin = strdup(buf);
74 if (getenv("EMBRYO_LIB_DIR"))
75 snprintf(buf, sizeof(buf), "%s/lib", getenv("EMBRYO_LIB_DIR"));
77 snprintf(buf, sizeof(buf), "%s/lib", _prefix_path);
78 _prefix_path_lib = strdup(buf);
80 if (getenv("EMBRYO_DATA_DIR"))
81 snprintf(buf, sizeof(buf), "%s/"SHARE_D, getenv("EMBRYO_DATA_DIR"));
83 snprintf(buf, sizeof(buf), "%s/"SHARE_D, _prefix_path);
84 _prefix_path_data = strdup(buf);
87 /* no env var - examine process and possible argv0 */
88 if (!_e_prefix_try_proc())
90 if (!_e_prefix_try_argv(argv0))
92 _e_prefix_fallbacks();
96 /* _exe_path is now a full absolute path TO this exe - figure out rest */
98 * exe = /blah/whatever/bin/exe
100 * prefix = /blah/whatever
101 * bin_dir = /blah/whatever/bin
102 * data_dir = /blah/whatever/share/enlightenment
103 * lib_dir = /blah/whatever/lib
105 p = strrchr(_exe_path, '/');
109 while (p >= _exe_path)
113 _prefix_path = malloc(p - _exe_path + 1);
116 strncpy(_prefix_path, _exe_path, p - _exe_path);
117 _prefix_path[p - _exe_path] = 0;
119 /* bin and lib always together */
120 snprintf(buf, sizeof(buf), "%s/bin", _prefix_path);
121 _prefix_path_bin = strdup(buf);
122 snprintf(buf, sizeof(buf), "%s/lib", _prefix_path);
123 _prefix_path_lib = strdup(buf);
125 /* check if AUTHORS file is there - then our guess is right */
126 snprintf(buf, sizeof(buf), "%s/"MAGIC_DAT, _prefix_path);
127 if (stat(buf, &st) == 0)
129 snprintf(buf, sizeof(buf), "%s/"SHARE_D, _prefix_path);
130 _prefix_path_data = strdup(buf);
132 /* AUTHORS file not there. time to start hunting! */
135 if (_e_prefix_share_hunt())
161 e_prefix_shutdown(void)
164 E_FREE(_prefix_path);
165 E_FREE(_prefix_path_bin);
166 E_FREE(_prefix_path_data);
167 E_FREE(_prefix_path_lib);
171 e_prefix_fallback(void)
174 _e_prefix_fallbacks();
184 e_prefix_bin_get(void)
186 return _prefix_path_bin;
190 e_prefix_data_get(void)
192 return _prefix_path_data;
196 e_prefix_lib_get(void)
198 return _prefix_path_lib;
201 /* local subsystem functions */
203 _e_prefix_share_hunt(void)
205 char buf[4096], buf2[4096], *p;
208 /* sometimes this isn't the case - so we need to do a more exhaustive search
209 * through more parent and subdirs. hre is an example i have seen:
211 * /blah/whatever/exec/bin/exe
213 * /blah/whatever/exec/bin
214 * /blah/whatever/common/share/enlightenment
215 * /blah/whatever/exec/lib
218 /* this is pure black magic to try and find data shares */
219 /* 2. cache file doesn't exist or is invalid - we need to search - this is
220 * where the real black magic begins */
223 * /blah/whatever/dir1/bin
224 * /blah/whatever/dir2/share/enlightenment
226 if (!_prefix_path_data)
231 snprintf(buf, sizeof(buf), "%s", _prefix_path);
232 p = strrchr(buf, '/');
239 while ((dp = readdir(dirp)))
241 if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, "..")))
244 snprintf(buf2, sizeof(buf2), "%s/%s/"MAGIC_DAT, buf, file);
245 if (stat(buf2, &st) == 0)
247 snprintf(buf2, sizeof(buf2), "%s/%s/"SHARE_D, buf, file);
248 _prefix_path_data = strdup(buf2);
258 * /blah/whatever/dir1/bin
259 * /blah/whatever/share/enlightenment
261 if (!_prefix_path_data)
263 snprintf(buf, sizeof(buf), "%s", _prefix_path);
264 p = strrchr(buf, '/');
266 snprintf(buf2, sizeof(buf2), "%s/"MAGIC_DAT, buf);
267 if (stat(buf, &st) == 0)
269 snprintf(buf2, sizeof(buf2), "%s/"SHARE_D, buf);
270 _prefix_path_data = strdup(buf2);
274 /* add more black magic as required as we discover weridnesss - remember
275 * this is to save users having to set environment variables to tell
276 * e where it lives, so e auto-adapts. so these code snippets are just
277 * logic to figure that out for the user
280 /* done. we found it - write cache file */
281 if (_prefix_path_data)
285 /* fail. everything failed */
290 _e_prefix_fallbacks(void)
294 _prefix_path = strdup(PACKAGE_BIN_DIR);
295 p = strrchr(_prefix_path, '/');
297 _prefix_path_bin = strdup(PACKAGE_BIN_DIR);
298 _prefix_path_data = strdup(PACKAGE_DATA_DIR);
299 _prefix_path_lib = strdup(PACKAGE_LIB_DIR);
300 printf("WARNING: Embryo could not determine its installed prefix\n"
301 " and is falling back on the compiled in default:\n"
303 " You might like to try setting the following environment variables:\n"
304 " EMBRYO_PREFIX - points to the base prefix of install\n"
305 " EMBRYO_BIN_DIR - optional in addition to E_PREFIX to provide\n"
306 " a more specific binary directory\n"
307 " EMBRYO_LIB_DIR - optional in addition to E_PREFIX to provide\n"
308 " a more specific library dir\n"
309 " EMBRYO_DATA_DIR - optional in addition to E_PREFIX to provide\n"
310 " a more specific location for shared data\n"
317 _e_prefix_try_proc(void)
323 func = (void *)_e_prefix_try_proc;
324 f = fopen("/proc/self/maps", "r");
326 while (fgets(buf, sizeof(buf), f))
329 char *p, mode[5] = "";
330 unsigned long ptr1 = 0, ptr2 = 0;
333 if (buf[len - 1] == '\n')
338 if (sscanf(buf, "%lx-%lx %4s", &ptr1, &ptr2, mode) == 3)
340 if (!strcmp(mode, "r-xp"))
342 if (((void *)ptr1 <= func) && (func < (void *)ptr2))
344 p = strchr(buf, '/');
349 if (!strcmp(buf + len - 10, " (deleted)"))
352 _exe_path = strdup(p);
367 _e_prefix_try_argv(char *argv0)
369 char *path, *p, *cp, *s;
371 char buf[4096], buf2[4096], buf3[4096];
373 /* 1. is argv0 abs path? */
376 _exe_path = strdup(argv0);
377 if (access(_exe_path, X_OK) == 0) return 1;
382 /* 2. relative path */
383 if (strchr(argv0, '/'))
385 if (getcwd(buf3, sizeof(buf3)))
387 snprintf(buf2, sizeof(buf2), "%s/%s", buf3, argv0);
388 if (realpath(buf2, buf))
390 _exe_path = strdup(buf);
391 if (access(_exe_path, X_OK) == 0) return 1;
397 /* 3. argv0 no path - look in PATH */
398 path = getenv("PATH");
402 lenexe = strlen(argv0);
403 while ((p = strchr(cp, ':')))
406 s = malloc(len + 1 + lenexe + 1);
411 strcpy(s + len + 1, argv0);
412 if (realpath(s, buf))
414 if (access(buf, X_OK) == 0)
416 _exe_path = strdup(buf);
426 s = malloc(len + 1 + lenexe + 1);
431 strcpy(s + len + 1, argv0);
432 if (realpath(s, buf))
434 if (access(buf, X_OK) == 0)
436 _exe_path = strdup(buf);
443 /* 4. big problems. arg[0] != executable - weird execution */