2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
13 #include <sys/types.h>
17 #include <sys/param.h>
24 #include <dlfcn.h> /* dlopen,dlclose,etc */
26 # include <Evil.h> /* for realpath */
31 #endif /* ! HAVE_EVIL */
33 #include "embryo_cc_prefix.h"
35 /* local subsystem functions */
36 static int _e_prefix_share_hunt(void);
37 static int _e_prefix_fallbacks(void);
38 static int _e_prefix_try_proc(void);
39 static int _e_prefix_try_argv(char *argv0);
41 /* local subsystem globals */
42 static char *_exe_path = NULL;
43 static char *_prefix_path = NULL;
44 static char *_prefix_path_bin = NULL;
45 static char *_prefix_path_data = NULL;
46 static char *_prefix_path_lib = NULL;
48 #define E_FREE(p) { if (p) {free(p); p = NULL;} }
50 /*#define PREFIX_CACHE_FILE 1*/
51 #define SHARE_D "share/embryo"
52 #define MAGIC_FILE "include/default.inc"
53 #define MAGIC_DAT SHARE_D"/"MAGIC_FILE
55 /* externally accessible functions */
57 e_prefix_determine(char *argv0)
64 /* if user provides E_PREFIX - then use that or also more specific sub
65 * dirs for bin, lib, data and locale */
66 if (getenv("EMBRYO_PREFIX"))
68 _prefix_path = strdup(getenv("EMBRYO_PREFIX"));
69 if (getenv("EMBRYO_BIN_DIR"))
70 snprintf(buf, sizeof(buf), "%s/bin", getenv("EMBRYO_BIN_DIR"));
72 snprintf(buf, sizeof(buf), "%s/bin", _prefix_path);
73 _prefix_path_bin = strdup(buf);
75 if (getenv("EMBRYO_LIB_DIR"))
76 snprintf(buf, sizeof(buf), "%s/lib", getenv("EMBRYO_LIB_DIR"));
78 snprintf(buf, sizeof(buf), "%s/lib", _prefix_path);
79 _prefix_path_lib = strdup(buf);
81 if (getenv("EMBRYO_DATA_DIR"))
82 snprintf(buf, sizeof(buf), "%s/"SHARE_D, getenv("EMBRYO_DATA_DIR"));
84 snprintf(buf, sizeof(buf), "%s/"SHARE_D, _prefix_path);
85 _prefix_path_data = strdup(buf);
88 /* no env var - examine process and possible argv0 */
89 if (!_e_prefix_try_proc())
91 if (!_e_prefix_try_argv(argv0))
93 _e_prefix_fallbacks();
97 /* _exe_path is now a full absolute path TO this exe - figure out rest */
99 * exe = /blah/whatever/bin/exe
101 * prefix = /blah/whatever
102 * bin_dir = /blah/whatever/bin
103 * data_dir = /blah/whatever/share/enlightenment
104 * lib_dir = /blah/whatever/lib
106 p = strrchr(_exe_path, '/');
110 while (p >= _exe_path)
114 _prefix_path = malloc(p - _exe_path + 1);
117 strncpy(_prefix_path, _exe_path, p - _exe_path);
118 _prefix_path[p - _exe_path] = 0;
120 /* bin and lib always together */
121 snprintf(buf, sizeof(buf), "%s/bin", _prefix_path);
122 _prefix_path_bin = strdup(buf);
123 snprintf(buf, sizeof(buf), "%s/lib", _prefix_path);
124 _prefix_path_lib = strdup(buf);
126 /* check if AUTHORS file is there - then our guess is right */
127 snprintf(buf, sizeof(buf), "%s/"MAGIC_DAT, _prefix_path);
128 if (stat(buf, &st) == 0)
130 snprintf(buf, sizeof(buf), "%s/"SHARE_D, _prefix_path);
131 _prefix_path_data = strdup(buf);
133 /* AUTHORS file not there. time to start hunting! */
136 if (_e_prefix_share_hunt())
162 e_prefix_shutdown(void)
165 E_FREE(_prefix_path);
166 E_FREE(_prefix_path_bin);
167 E_FREE(_prefix_path_data);
168 E_FREE(_prefix_path_lib);
172 e_prefix_fallback(void)
175 _e_prefix_fallbacks();
185 e_prefix_bin_get(void)
187 return _prefix_path_bin;
191 e_prefix_data_get(void)
193 return _prefix_path_data;
197 e_prefix_lib_get(void)
199 return _prefix_path_lib;
202 /* local subsystem functions */
204 _e_prefix_share_hunt(void)
206 char buf[4096], buf2[4096], *p;
209 /* sometimes this isnt the case - so we need to do a more exhaustive search
210 * through more parent and subdirs. hre is an example i have seen:
212 * /blah/whatever/exec/bin/exe
214 * /blah/whatever/exec/bin
215 * /blah/whatever/common/share/enlightenment
216 * /blah/whatever/exec/lib
219 /* this is pure black magic to try and find data shares */
220 /* 2. cache file doesn't exist or is invalid - we need to search - this is
221 * where the real black magic begins */
224 * /blah/whatever/dir1/bin
225 * /blah/whatever/dir2/share/enlightenment
227 if (!_prefix_path_data)
232 snprintf(buf, sizeof(buf), "%s", _prefix_path);
233 p = strrchr(buf, '/');
240 while ((dp = readdir(dirp)))
242 if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, "..")))
245 snprintf(buf2, sizeof(buf2), "%s/%s/"MAGIC_DAT, buf, file);
246 if (stat(buf2, &st) == 0)
248 snprintf(buf2, sizeof(buf2), "%s/%s/"SHARE_D, buf, file);
249 _prefix_path_data = strdup(buf2);
259 * /blah/whatever/dir1/bin
260 * /blah/whatever/share/enlightenment
262 if (!_prefix_path_data)
264 snprintf(buf, sizeof(buf), "%s", _prefix_path);
265 p = strrchr(buf, '/');
267 snprintf(buf2, sizeof(buf2), "%s/"MAGIC_DAT, buf);
268 if (stat(buf, &st) == 0)
270 snprintf(buf2, sizeof(buf2), "%s/"SHARE_D, buf);
271 _prefix_path_data = strdup(buf2);
275 /* add more black magic as required as we discover weridnesss - remember
276 * this is to save users having to set environment variables to tell
277 * e where it lives, so e auto-adapts. so these code snippets are just
278 * logic to figure that out for the user
281 /* done. we found it - write cache file */
282 if (_prefix_path_data)
286 /* fail. everything failed */
291 _e_prefix_fallbacks(void)
295 _prefix_path = strdup(PACKAGE_BIN_DIR);
296 p = strrchr(_prefix_path, '/');
298 _prefix_path_bin = strdup(PACKAGE_BIN_DIR);
299 _prefix_path_data = strdup(PACKAGE_DATA_DIR);
300 _prefix_path_lib = strdup(PACKAGE_LIB_DIR);
301 printf("WARNING: Embryo could not determine its installed prefix\n"
302 " and is falling back on the compiled in default:\n"
304 " You might like to try setting the following environment variables:\n"
305 " EMBRYO_PREFIX - points to the base prefix of install\n"
306 " EMBRYO_BIN_DIR - optional in addition to E_PREFIX to provide\n"
307 " a more specific binary directory\n"
308 " EMBRYO_LIB_DIR - optional in addition to E_PREFIX to provide\n"
309 " a more specific library dir\n"
310 " EMBRYO_DATA_DIR - optional in addition to E_PREFIX to provide\n"
311 " a more specific location for shared data\n"
318 _e_prefix_try_proc(void)
324 func = (void *)_e_prefix_try_proc;
325 f = fopen("/proc/self/maps", "r");
327 while (fgets(buf, sizeof(buf), f))
330 char *p, mode[5] = "";
331 unsigned long ptr1 = 0, ptr2 = 0;
334 if (buf[len - 1] == '\n')
339 if (sscanf(buf, "%lx-%lx %4s", &ptr1, &ptr2, mode) == 3)
341 if (!strcmp(mode, "r-xp"))
343 if (((void *)ptr1 <= func) && (func < (void *)ptr2))
345 p = strchr(buf, '/');
350 if (!strcmp(buf + len - 10, " (deleted)"))
353 _exe_path = strdup(p);
368 _e_prefix_try_argv(char *argv0)
370 char *path, *p, *cp, *s;
372 char buf[4096], buf2[4096], buf3[4096];
374 /* 1. is argv0 abs path? */
377 _exe_path = strdup(argv0);
378 if (access(_exe_path, X_OK) == 0) return 1;
383 /* 2. relative path */
384 if (strchr(argv0, '/'))
386 if (getcwd(buf3, sizeof(buf3)))
388 snprintf(buf2, sizeof(buf2), "%s/%s", buf3, argv0);
389 if (realpath(buf2, buf))
391 _exe_path = strdup(buf);
392 if (access(_exe_path, X_OK) == 0) return 1;
398 /* 3. argv0 no path - look in PATH */
399 path = getenv("PATH");
403 lenexe = strlen(argv0);
404 while ((p = strchr(cp, ':')))
407 s = malloc(len + 1 + lenexe + 1);
412 strcpy(s + len + 1, argv0);
413 if (realpath(s, buf))
415 if (access(buf, X_OK) == 0)
417 _exe_path = strdup(buf);
427 s = malloc(len + 1 + lenexe + 1);
432 strcpy(s + len + 1, argv0);
433 if (realpath(s, buf))
435 if (access(buf, X_OK) == 0)
437 _exe_path = strdup(buf);
444 /* 4. big problems. arg[0] != executable - weird execution */