diff --git a/legacy/embryo/src/bin/Makefile.am b/legacy/embryo/src/bin/Makefile.am index 5850b988ae..0d271f9887 100644 --- a/legacy/embryo/src/bin/Makefile.am +++ b/legacy/embryo/src/bin/Makefile.am @@ -23,7 +23,9 @@ embryo_cc_sc6.c \ embryo_cc_sc7.c \ embryo_cc_scexpand.c \ embryo_cc_sclist.c \ -embryo_cc_scvars.c +embryo_cc_scvars.c \ +embryo_cc_prefix.c \ +embryo_cc_prefix.h embryo_cc_LDADD = embryo_cc_DEPENDENCIES = diff --git a/legacy/embryo/src/bin/embryo_cc_prefix.c b/legacy/embryo/src/bin/embryo_cc_prefix.c new file mode 100644 index 0000000000..3033d06d23 --- /dev/null +++ b/legacy/embryo/src/bin/embryo_cc_prefix.c @@ -0,0 +1,442 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "embryo_cc_prefix.h" + +/* local subsystem functions */ +static int _e_prefix_share_hunt(void); +static int _e_prefix_fallbacks(void); +static int _e_prefix_try_proc(void); +static int _e_prefix_try_argv(char *argv0); + +/* local subsystem globals */ +static char *_exe_path = NULL; +static char *_prefix_path = NULL; +static char *_prefix_path_bin = NULL; +static char *_prefix_path_data = NULL; +static char *_prefix_path_lib = NULL; + +#define E_FREE(p) { if (p) {free(p); p = NULL;} } + +/*#define PREFIX_CACHE_FILE 1*/ +#define SHARE_D "share/embryo" +#define MAGIC_FILE "include/default.inc" +#define MAGIC_DAT SHARE_D"/"MAGIC_FILE + +/* externally accessible functions */ +int +e_prefix_determine(char *argv0) +{ + char *p, buf[4096]; + struct stat st; + + e_prefix_shutdown(); + + /* if user provides E_PREFIX - then use that or also more specific sub + * dirs for bin, lib, data and locale */ + if (getenv("E_PREFIX")) + { + _prefix_path = strdup(getenv("E_PREFIX")); + if (getenv("E_BIN_DIR")) + _prefix_path_bin = strdup(getenv("E_BIN_DIR")); + else + { + snprintf(buf, sizeof(buf), "%s/bin", _prefix_path); + _prefix_path_bin = strdup(buf); + } + if (getenv("E_LIB_DIR")) + _prefix_path_bin = strdup(getenv("E_LIB_DIR")); + else + { + snprintf(buf, sizeof(buf), "%s/lib", _prefix_path); + _prefix_path_lib = strdup(buf); + } + if (getenv("E_DATA_DIR")) + _prefix_path_data = strdup(getenv("E_DATA_DIR")); + else + { + snprintf(buf, sizeof(buf), "%s/"SHARE_D, _prefix_path); + _prefix_path_data = strdup(buf); + } + return 1; + } + /* no env var - examine process and possible argv0 */ + if (!_e_prefix_try_proc()) + { + if (!_e_prefix_try_argv(argv0)) + { + _e_prefix_fallbacks(); + return 0; + } + } + /* _exe_path is now a full absolute path TO this exe - figure out rest */ + /* if + * exe = /blah/whatever/bin/exe + * then + * prefix = /blah/whatever + * bin_dir = /blah/whatever/bin + * data_dir = /blah/whatever/share/enlightenment + * lib_dir = /blah/whatever/lib + */ + p = strrchr(_exe_path, '/'); + if (p) + { + p--; + while (p >= _exe_path) + { + if (*p == '/') + { + _prefix_path = malloc(p - _exe_path + 1); + if (_prefix_path) + { + strncpy(_prefix_path, _exe_path, p - _exe_path); + _prefix_path[p - _exe_path] = 0; + + /* bin and lib always together */ + snprintf(buf, sizeof(buf), "%s/bin", _prefix_path); + _prefix_path_bin = strdup(buf); + snprintf(buf, sizeof(buf), "%s/lib", _prefix_path); + _prefix_path_lib = strdup(buf); + + /* check if AUTHORS file is there - then our guess is right */ + snprintf(buf, sizeof(buf), "%s/"MAGIC_DAT, _prefix_path); + if (stat(buf, &st) == 0) + { + snprintf(buf, sizeof(buf), "%s/"SHARE_D, _prefix_path); + _prefix_path_data = strdup(buf); + } + /* AUTHORS file not there. time to start hunting! */ + else + { + if (_e_prefix_share_hunt()) + { + return 1; + } + else + { + e_prefix_fallback(); + return 0; + } + } + return 1; + } + else + { + e_prefix_fallback(); + return 0; + } + } + p--; + } + } + e_prefix_fallback(); + return 0; +} + +void +e_prefix_shutdown(void) +{ + E_FREE(_exe_path); + E_FREE(_prefix_path); + E_FREE(_prefix_path_bin); + E_FREE(_prefix_path_data); + E_FREE(_prefix_path_lib); +} + +void +e_prefix_fallback(void) +{ + e_prefix_shutdown(); + _e_prefix_fallbacks(); +} + +const char * +e_prefix_get(void) +{ + return _prefix_path; +} + +const char * +e_prefix_bin_get(void) +{ + return _prefix_path_bin; +} + +const char * +e_prefix_data_get(void) +{ + return _prefix_path_data; +} + +const char * +e_prefix_lib_get(void) +{ + return _prefix_path_lib; +} + +/* local subsystem functions */ +static int +_e_prefix_share_hunt(void) +{ + char buf[4096], buf2[4096], *p; + FILE *f; + struct stat st; + + /* sometimes this isnt the case - so we need to do a more exhaustive search + * through more parent and subdirs. hre is an example i have seen: + * + * /blah/whatever/exec/bin/exe + * -> + * /blah/whatever/exec/bin + * /blah/whatever/common/share/enlightenment + * /blah/whatever/exec/lib + */ + + /* this is pure black magic to try and find data shares */ + /* 2. cache file doesn't exist or is invalid - we need to search - this is + * where the real black magic begins */ + + /* BLACK MAGIC 1: + * /blah/whatever/dir1/bin + * /blah/whatever/dir2/share/enlightenment + */ + if (!_prefix_path_data) + { + DIR *dirp; + struct dirent *dp; + + snprintf(buf, sizeof(buf), "%s", _prefix_path); + p = strrchr(buf, '/'); + if (p) *p = 0; + dirp = opendir(buf); + if (dirp) + { + char *file; + + while ((dp = readdir(dirp))) + { + if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, ".."))) + { + file = dp->d_name; + snprintf(buf2, sizeof(buf2), "%s/%s/"MAGIC_DAT, buf, file); + if (stat(buf2, &st) == 0) + { + snprintf(buf2, sizeof(buf2), "%s/%s/"SHARE_D, buf, file); + _prefix_path_data = strdup(buf2); + break; + } + } + } + closedir(dirp); + } + } + + /* BLACK MAGIC 2: + * /blah/whatever/dir1/bin + * /blah/whatever/share/enlightenment + */ + if (!_prefix_path_data) + { + snprintf(buf, sizeof(buf), "%s", _prefix_path); + p = strrchr(buf, '/'); + if (p) *p = 0; + snprintf(buf2, sizeof(buf2), "%s/"MAGIC_DAT, buf); + if (stat(buf, &st) == 0) + { + snprintf(buf2, sizeof(buf2), "%s/"SHARE_D, buf); + _prefix_path_data = strdup(buf2); + } + } + + /* add more black magic as required as we discover weridnesss - remember + * this is to save users having to set environment variables to tell + * e where it lives, so e auto-adapts. so these code snippets are just + * logic to figure that out for the user + */ + + /* done. we found it - write cache file */ + if (_prefix_path_data) + { + return 1; + } + /* fail. everything failed */ + return 0; +} + +static int +_e_prefix_fallbacks(void) +{ + char *p; + + _prefix_path = strdup(PACKAGE_BIN_DIR); + p = strrchr(_prefix_path, '/'); + if (p) *p = 0; + _prefix_path_bin = strdup(PACKAGE_BIN_DIR); + _prefix_path_data = strdup(PACKAGE_DATA_DIR); + _prefix_path_lib = strdup(PACKAGE_LIB_DIR); + printf("WARNING: Embryo could not determine its installed prefix\n" + " and is falling back on the compiled in default:\n" + " %s\n", + " You might like to try setting the following environment variables:\n" + " E_PREFIX - points to the base prefix of install\n" + " E_BIN_DIR - optional in addition to E_PREFIX to provide\n" + " a more specific binary directory\n" + " E_LIB_DIR - optional in addition to E_PREFIX to provide\n" + " a more specific library dir\n" + " E_DATA_DIR - optional in addition to E_PREFIX to provide\n" + " a more specific location for shared data\n" + , + _prefix_path); + return 1; +} + +static int +_e_prefix_try_proc(void) +{ + FILE *f; + char buf[4096]; + void *func = NULL; + + func = (void *)_e_prefix_try_proc; + f = fopen("/proc/self/maps", "r"); + if (!f) return 0; + while (fgets(buf, sizeof(buf), f)) + { + int len; + char *p, mode[5] = ""; + unsigned long ptr1 = 0, ptr2 = 0; + + len = strlen(buf); + if (buf[len - 1] == '\n') + { + buf[len - 1] = 0; + len--; + } + if (sscanf(buf, "%lx-%lx %4s", &ptr1, &ptr2, mode) == 3) + { + if (!strcmp(mode, "r-xp")) + { + if (((void *)ptr1 <= func) && (func < (void *)ptr2)) + { + p = strchr(buf, '/'); + if (p) + { + if (len > 10) + { + if (!strcmp(buf + len - 10, " (deleted)")) + buf[len - 10] = 0; + } + _exe_path = strdup(p); + fclose(f); + return 1; + } + else + break; + } + } + } + } + fclose(f); + return 0; +} + +static int +_e_prefix_try_argv(char *argv0) +{ + char *path, *p, *cp, *s; + int len, lenexe; + char buf[4096], buf2[4096], buf3[4096]; + + /* 1. is argv0 abs path? */ + if (argv0[0] == '/') + { + _exe_path = strdup(argv0); + if (access(_exe_path, X_OK) == 0) return 1; + free(_exe_path); + _exe_path = NULL; + return 0; + } + /* 2. relative path */ + if (strchr(argv0, '/')) + { + if (getcwd(buf3, sizeof(buf3))) + { + snprintf(buf2, sizeof(buf2), "%s/%s", buf3, argv0); + if (realpath(buf2, buf)) + { + _exe_path = strdup(buf); + if (access(_exe_path, X_OK) == 0) return 1; + free(_exe_path); + _exe_path = NULL; + } + } + } + /* 3. argv0 no path - look in PATH */ + path = getenv("PATH"); + if (!path) return 0; + p = path; + cp = p; + lenexe = strlen(argv0); + while ((p = strchr(cp, ':'))) + { + len = p - cp; + s = malloc(len + 1 + lenexe + 1); + if (s) + { + strncpy(s, cp, len); + s[len] = '/'; + strcpy(s + len + 1, argv0); + if (realpath(s, buf)) + { + if (access(buf, X_OK) == 0) + { + _exe_path = strdup(buf); + free(s); + return 1; + } + } + free(s); + } + cp = p + 1; + } + len = strlen(cp); + s = malloc(len + 1 + lenexe + 1); + if (s) + { + strncpy(s, cp, len); + s[len] = '/'; + strcpy(s + len + 1, argv0); + if (realpath(s, buf)) + { + if (access(buf, X_OK) == 0) + { + _exe_path = strdup(buf); + free(s); + return 1; + } + } + free(s); + } + /* 4. big problems. arg[0] != executable - weird execution */ + return 0; +} diff --git a/legacy/embryo/src/bin/embryo_cc_prefix.h b/legacy/embryo/src/bin/embryo_cc_prefix.h new file mode 100644 index 0000000000..4bea3f9188 --- /dev/null +++ b/legacy/embryo/src/bin/embryo_cc_prefix.h @@ -0,0 +1,11 @@ +/* + * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 + */ + +int e_prefix_determine(char *argv0); +void e_prefix_shutdown(void); +void e_prefix_fallback(void); +const char *e_prefix_get(void); +const char *e_prefix_bin_get(void); +const char *e_prefix_data_get(void); +const char *e_prefix_lib_get(void); diff --git a/legacy/embryo/src/bin/embryo_cc_sc1.c b/legacy/embryo/src/bin/embryo_cc_sc1.c index 4b55ed5346..8f1ab347f4 100644 --- a/legacy/embryo/src/bin/embryo_cc_sc1.c +++ b/legacy/embryo/src/bin/embryo_cc_sc1.c @@ -38,6 +38,7 @@ #include #include "embryo_cc_osdefs.h" #include "embryo_cc_sc.h" +#include "embryo_cc_prefix.h" #define VERSION_STR "2.4" #define VERSION_INT 240 @@ -135,6 +136,8 @@ main(int argc, char *argv[], char *env[]) snprintf(argv0, _MAX_PATH, "%s/%s", pwd, argv[0]); } /* if */ argv[0] = argv0; /* set location to new first parameter */ + + e_prefix_determine(argv0); return sc_compile(argc, argv); } @@ -592,8 +595,9 @@ parseoptions(int argc, char **argv, char *iname, char *oname, size_t len; /* use embryo include dir always */ - insert_path(PACKAGE_DATA_DIR "/include/"); - insert_path(PACKAGE_DATA_DIR "./"); + snprintf(str, sizeof(str), "%s/include/", e_prefix_data_get()); + insert_path(str); + insert_path("./"); for (i = 1; i < argc; i++) {