diff options
Diffstat (limited to 'gprofng/libcollector/envmgmt.c')
-rw-r--r-- | gprofng/libcollector/envmgmt.c | 840 |
1 files changed, 840 insertions, 0 deletions
diff --git a/gprofng/libcollector/envmgmt.c b/gprofng/libcollector/envmgmt.c new file mode 100644 index 0000000..b4418d6 --- /dev/null +++ b/gprofng/libcollector/envmgmt.c @@ -0,0 +1,840 @@ +/* Copyright (C) 2021 Free Software Foundation, Inc. + Contributed by Oracle. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +/* + * Routines for managing the target's environment array + */ + +#include "config.h" +#include "descendants.h" + +#define MAX_LD_PRELOADS 2 + +/* TprintfT(<level>,...) definitions. Adjust per module as needed */ +#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings +#define DBG_LT1 1 // for configuration details, warnings +#define DBG_LT2 2 +#define DBG_LT3 3 +#define DBG_LT4 4 + +/* original environment settings to be saved for later restoration */ +static char *sp_preloads[MAX_LD_PRELOADS]; +static char *sp_libpaths[MAX_LD_PRELOADS]; +char **sp_env_backup; + +static const char *SP_ENV[]; +static const char *LD_ENV[]; +static const char *SP_PRELOAD[]; +static const char *LD_PRELOAD[]; +static const char *SP_LIBRARY_PATH[]; +static const char *LD_LIBRARY_PATH[]; +static int NUM_SP_ENV_VARS; +static int NUM_LD_ENV_VARS; +static int NUM_SP_PRELOADS; +static int NUM_LD_PRELOADS; +static int NUM_SP_LIBPATHS; +static int NUM_LD_LIBPATHS; + +static const char *SP_ENV[] = { + SP_COLLECTOR_PARAMS, /* data descriptor */ + SP_COLLECTOR_EXPNAME, /* experiment name */ + SP_COLLECTOR_FOLLOW_SPEC, /* linetrace */ + SP_COLLECTOR_FOUNDER, /* determine founder exp */ + SP_PRELOAD_STRINGS, /* LD_PRELOADs for data collection */ + SP_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs for data collection */ + "SP_COLLECTOR_TRACELEVEL", /* tprintf */ +#if DEBUG + "SP_COLLECTOR_SIGACTION", /* dispatcher, hwprofile */ +#endif + /* JAVA* */ + /* LD_DEBUG=audit,bindings,detail */ + /* LD_ORIGIN=yes */ + NULL +}; + +static const char *LD_ENV[] = { + LD_PRELOAD_STRINGS, /* LD_PRELOADs */ + LD_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs */ + JAVA_TOOL_OPTIONS, /* enable -agentlib:collector for JVMTI */ + NULL +}; + +static const char *SP_PRELOAD[] = { + SP_PRELOAD_STRINGS, + NULL +}; + +static const char *LD_PRELOAD[] = { + LD_PRELOAD_STRINGS, + NULL +}; + +static const char *SP_LIBRARY_PATH[] = { + SP_LIBPATH_STRINGS, + NULL +}; +static const char *LD_LIBRARY_PATH[] = { + LD_LIBPATH_STRINGS, + NULL +}; + +void +__collector_env_save_preloads () +{ + /* save the list of SP_PRELOADs */ + int v; + for (v = 0; SP_PRELOAD[v]; v++) + { + sp_preloads[v] = __collector_strdup (CALL_UTIL (getenv)(SP_PRELOAD[v])); + TprintfT (DBG_LT3, "__collector_env_save_preloads: %s=%s\n", SP_PRELOAD[v], sp_preloads[v]); + } + NUM_SP_PRELOADS = v; + for (v = 0; SP_LIBRARY_PATH[v]; v++) + { + sp_libpaths[v] = __collector_strdup (CALL_UTIL (getenv)(SP_LIBRARY_PATH[v])); + TprintfT (DBG_LT4, "__collector_env_save_preloads: %s=%s\n", SP_LIBRARY_PATH[v], + sp_libpaths[v] ? sp_libpaths[v] : "NULL"); + } + NUM_SP_LIBPATHS = v; + for (v = 0; LD_PRELOAD[v]; v++) + ; + NUM_LD_PRELOADS = v; + for (v = 0; LD_LIBRARY_PATH[v]; v++) + ; + NUM_LD_LIBPATHS = v; + for (v = 0; SP_ENV[v]; v++) + ; + NUM_SP_ENV_VARS = v; + for (v = 0; LD_ENV[v]; v++) + ; + NUM_LD_ENV_VARS = v; +} + +/* free the memory involved in backing up the environment */ +void +__collector_env_backup_free () +{ + int v = 0; + TprintfT (DBG_LT2, "env_backup_free()\n"); + for (v = 0; sp_env_backup[v]; v++) + { + TprintfT (DBG_LT2, "env_backup_free():sp_env_backup[%d]=%s \n", v, sp_env_backup[v]); + __collector_freeCSize (__collector_heap, (char *) sp_env_backup[v], __collector_strlen (sp_env_backup[v]) + 1); + } + __collector_freeCSize (__collector_heap, (char**) sp_env_backup, + (NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1) * sizeof (char*)); +} + +char ** +__collector_env_backup () +{ + TprintfT (DBG_LT2, "env_backup_()\n"); + char **backup = __collector_env_allocate (NULL, 1); + __collector_env_update (backup); + TprintfT (DBG_LT2, "env_backup_()\n"); + return backup; +} + +/* + function: env_prepend() + given an <old_str>, check to see if <str> + is already defined by it. If not, allocate + a new string and concat <envvar>=<str><separator><old_str> + params: + old_str: original string + str: substring to prepend + return: pointer to updated string or NULL if string was not updated. + */ +static char * +env_prepend (const char *envvar, const char *str, const char *separator, + const char *old_str) +{ + if (!envvar || *envvar == 0 || !str || *str == 0) + { + /* nothing to do */ + TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") -- nothing to do\n", + envvar, str, separator, old_str); + + return NULL; + } + TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\")\n", + envvar, str, separator, old_str); + char *ev; + size_t strsz; + if (!old_str || *old_str == 0) + { + strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) + 1; + ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1); + if (ev) + { + CALL_UTIL (snprintf)(ev, strsz, "%s=%s", envvar, str); + assert (__collector_strlen (ev) + 1 == strsz); + } + else + TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n"); + } + else + { + char *p = CALL_UTIL (strstr)(old_str, str); + if (p) + { + TprintfT (DBG_LT2, "env_prepend(): %s=%s was already set\n", + envvar, old_str); + return NULL; + } + strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) + + __collector_strlen (separator) + __collector_strlen (old_str) + 1; + ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1); + if (ev) + { + CALL_UTIL (snprintf)(ev, strsz, "%s=%s%s%s", envvar, str, separator, old_str); + assert (__collector_strlen (ev) + 1 == strsz); + } + else + TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n"); + } + TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") returns \"%s\"\n", + envvar, str, separator, old_str, (ev == NULL ? "NULL" : ev)); + return ev; +} + +/* + function: putenv_prepend() + get environment variable <envvar>, check to see if <str> + is already defined by it. If not prepend <str> + and put it back to environment. + params: + envvar: environment variable + str: substring to find + return: 0==success, nonzero on failure. + */ +int +putenv_prepend (const char *envvar, const char *str, const char *separator) +{ + if (!envvar || *envvar == 0) + return 1; + const char * old_str = CALL_UTIL (getenv)(envvar); + char * newstr = env_prepend (envvar, str, separator, old_str); + if (newstr) + // now put the new variable into the environment + if (CALL_UTIL (putenv)(newstr) != 0) + { + TprintfT (DBG_LT2, "putenv_prepend(): ERROR %s is not set!\n", newstr); + return 1; + } + return 0; +} + +/* + function: env_strip() + Finds substr in origstr; Removes + all characters from previous ':' or ' ' + up to and including any trailing ':' or ' '. + params: + env: environment variable contents + str: substring to find + return: count of instances removed from env + */ +static int +env_strip (char *origstr, const char *substr) +{ + int removed = 0; + char *p, *q; + if (origstr == NULL || substr == NULL || *substr == 0) + return 0; + while ((p = q = CALL_UTIL (strstr)(origstr, substr))) + { + p += __collector_strlen (substr); + while (*p == ':' || *p == ' ') /* strip trailing separator */ + p++; + while (*q != ':' && *q != ' ' && *q != '=' && q != origstr) /* strip path */ + q--; + if (q != origstr) /* restore leading separator (if any) */ + q++; + __collector_strlcpy (q, p, __collector_strlen (p) + 1); + removed++; + } + return removed; +} + +/* + function: env_ld_preload_strip() + Removes known libcollector shared objects from envv. + params: + var: shared object name (leading characters don't have to match) + return: 0 = so's removed, non-zero = so's not found. + */ +static int +env_ld_preload_strip (char *envv) +{ + if (!envv || *envv == 0) + { + TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - envv is NULL\n"); + return -1; + } + for (int v = 0; SP_PRELOAD[v]; v++) + if (env_strip (envv, sp_preloads[v])) + return 0; + if (line_mode != LM_CLOSED) + TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - could not strip SP_PRELOADS from '%s'\n", + envv); + return -2; +} + +void +__collector_env_print (char * label) +{ +#if DEBUG + TprintfT (DBG_LT2, "__collector_env_print(%s)\n", label); + for (int v = 0; v < MAX_LD_PRELOADS; v++) + TprintfT (DBG_LT2, " %s sp_preloads[%d] (0x%p)=%s\n", label, + v, sp_preloads[v], (sp_preloads[v] == NULL ? "NULL" : sp_preloads[v])); + for (int v = 0; SP_ENV[v]; v++) + { + char *s = CALL_UTIL (getenv)(SP_ENV[v]); + if (s == NULL) + s = "<null>"; + TprintfT (DBG_LT2, " %s SP_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, SP_ENV[v], SP_ENV[v], s); + } + for (int v = 0; LD_ENV[v]; v++) + { + char *s = CALL_UTIL (getenv)(LD_ENV[v]); + if (s == NULL) + s = "<null>"; + TprintfT (DBG_LT2, " %s LD_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, LD_ENV[v], LD_ENV[v], s); + } +#endif +} + +void +__collector_env_printall (char *label, char *envp[]) +{ +#if DEBUG + TprintfT (DBG_LT2, "__collector_env_printall(%s): environment @ 0x%p\n", label, envp); + for (int i = 0; envp[i]; i++) + Tprintf (DBG_LT2, "\tenv[%d]@0x%p == %s\n", i, envp[i], envp[i]); +#endif +} + +/* match collector environment variable */ +int +env_match (char *envp[], const char *envvar) +{ + int match = -1; + if (envp == NULL) + TprintfT (DBG_LT1, "env_match(%s): NULL envp!\n", envvar); + else + { + int i = 0; + while ((envp[i] != NULL) && (__collector_strStartWith (envp[i], envvar))) + i++; + if ((envp[i] == NULL) || (envp[i][__collector_strlen (envvar)] != '=')) + TprintfT (DBG_LT4, "env_match(): @%p []%s not defined in envp\n", envp, envvar); + else + { + TprintfT (DBG_LT4, "env_match(): @%p [%d]%s defined in envp\n", envp, i, envp[i]); + match = i; + } + } + TprintfT (DBG_LT1, "env_match(%s): found in slot %d\n", envvar, match); + return (match); +} + +/* allocate new environment with collector variables */ +/* 1) copy all current envp[] ptrs into a new array, coll_env[] */ +/* 2) if collector-related env ptrs not in envp[], append them to coll_env */ +/* from processes' "environ" (allocate_env==1) */ +/* or from sp_env_backup (allocate_env==0)*/ +/* If they already exist in envp, probably is an error... */ +/* 3) return coll_env */ + +/* __collector__env_update() need be called after this to set LD_ENV*/ +char ** +__collector_env_allocate (char *const old_env[], int allocate_env) +{ + extern char **environ; /* the process' actual environment */ + char **new_env; /* a new environment for collection */ + TprintfT (DBG_LT3, "__collector_env_allocate(old_env=0x%p %s environ=0x%p)\n", + old_env, (old_env == environ) ? "==" : "!=", environ); + /* set up a copy of the provided old_env for collector use */ + int old_env_size = 0; + + /* determine number of (used) slots in old_env */ + if (old_env) + while (old_env[old_env_size] != NULL) + old_env_size++; + /* allocate a new vector with additional slots */ + int new_env_alloc_sz = old_env_size + NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1; + new_env = (char**) __collector_allocCSize (__collector_heap, new_env_alloc_sz * sizeof (char*), 1); + if (new_env == NULL) + return NULL; + TprintfT (DBG_LT4, "__collector_env_allocate(): old_env has %d entries, new_env @ 0x%p\n", old_env_size, new_env); + + /* copy provided old_env pointers to new collector environment */ + int new_env_size = 0; + for (new_env_size = 0; new_env_size < old_env_size; new_env_size++) + new_env[new_env_size] = old_env[new_env_size]; + + /* check each required environment variable, adding as required */ + const char * env_var; + int v; + for (v = 0; (env_var = SP_ENV[v]) != NULL; v++) + { + if (env_match ((char**) old_env, env_var) == -1) + { + int idx; + /* not found in old_env */ + if (allocate_env) + { + if ((idx = env_match (environ, env_var)) != -1) + { + /* found in environ */ + TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n", + new_env_size, environ[idx]); + int varsz = __collector_strlen (environ[idx]) + 1; + char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1); + if (var == NULL) + return NULL; + __collector_strlcpy (var, environ[idx], varsz); + new_env[new_env_size++] = var; + } + else + { + /* not found in environ */ + if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) || + (__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0)) + TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n", + env_var); + } + } + else + { + if ((idx = env_match (sp_env_backup, env_var)) != -1) + { + /* found in backup */ + TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n", + new_env_size, sp_env_backup[idx]); + new_env[new_env_size++] = sp_env_backup[idx]; + } + else + { + /* not found in environ */ + if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) || + (__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0)) + TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n", + env_var); + } + } + } + } + + for (v = 0; (env_var = LD_ENV[v]) != NULL; v++) + { + if (env_match ((char**) old_env, env_var) == -1) + { + int idx; + /* not found in old_env */ + if (allocate_env) + { + if ((idx = env_match (environ, env_var)) != -1) + { + /* found in environ */ + TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n", + new_env_size, environ[idx]); + + int varsz = __collector_strlen (env_var) + 2; + char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1); + if (var == NULL) + return NULL; + // assume __collector_env_update() will fill content of env_var + CALL_UTIL (snprintf)(var, varsz, "%s=", env_var); + new_env[new_env_size++] = var; + } + } + else + { + if ((idx = env_match (sp_env_backup, env_var)) != -1) + { + /* found in backup */ + TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n", + new_env_size, sp_env_backup[idx]); + new_env[new_env_size++] = sp_env_backup[idx]; + } + } + } + } + + /* ensure new_env vector ends with NULL */ + new_env[new_env_size] = NULL; + assert (new_env_size <= new_env_alloc_sz); + TprintfT (DBG_LT4, "__collector_env_allocate(): new_env has %d entries (%d added), new_env=0x%p\n", + new_env_size, new_env_size - old_env_size, new_env); + if (new_env_size != old_env_size && !allocate_env) + __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n", + SP_JCMD_CWARN, COL_WARN_EXECENV, new_env_size - old_env_size); + __collector_env_printall ("__collector_env_allocate", new_env); + return (new_env); +} + +/* unset collection environment variables */ +/* if they exist in env... */ +/* 1) push non-collectorized version to env */ + +/* Not mt safe */ +void +__collector_env_unset (char *envp[]) +{ + int v; + const char * env_name; + TprintfT (DBG_LT3, "env_unset(envp=0x%p)\n", envp); + if (envp == NULL) + { + for (v = 0; (env_name = LD_PRELOAD[v]); v++) + { + const char *env_val = CALL_UTIL (getenv)(env_name); + if (env_val && CALL_UTIL (strstr)(env_val, sp_preloads[v])) + { + size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1; + char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1); + if (ev == NULL) + return; + CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val); + assert (__collector_strlen (ev) + 1 == sz); + TprintfT (DBG_LT4, "env_unset(): old %s\n", ev); + env_ld_preload_strip (ev); + CALL_UTIL (putenv)(ev); + TprintfT (DBG_LT4, "env_unset(): new %s\n", ev); + } + } + // unset JAVA_TOOL_OPTIONS + env_name = JAVA_TOOL_OPTIONS; + const char * env_val = CALL_UTIL (getenv)(env_name); + if (env_val && CALL_UTIL (strstr)(env_val, COLLECTOR_JVMTI_OPTION)) + { + size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1; + char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1); + if (ev == NULL) + return; + CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val); + assert (__collector_strlen (ev) + 1 == sz); + TprintfT (DBG_LT4, "env_unset(): old %s\n", ev); + env_strip (ev, COLLECTOR_JVMTI_OPTION); + CALL_UTIL (putenv)(ev); + TprintfT (DBG_LT4, "env_unset(): new %s\n", ev); + } + __collector_env_print ("__collector_env_unset"); + } + else + { + __collector_env_printall ("__collector_env_unset, before", envp); + for (v = 0; (env_name = LD_PRELOAD[v]); v++) + { + int idx = env_match (envp, env_name); + if (idx != -1) + { + char *env_val = envp[idx]; + TprintfT (DBG_LT4, "env_unset(): old %s\n", env_val); + envp[idx] = "junk="; /* xxxx is it ok to use original string? */ + env_ld_preload_strip (env_val); + envp[idx] = env_val; + TprintfT (DBG_LT4, "env_unset(): new %s\n", envp[idx]); + } + } + // unset JAVA_TOOL_OPTIONS + env_name = JAVA_TOOL_OPTIONS; + int idx = env_match(envp, env_name); + if (idx != -1) { + char *env_val = envp[idx]; + TprintfT(DBG_LT4, "env_unset(): old %s\n", env_val); + envp[idx] = "junk="; /* xxxx is it ok to use original string? */ + env_strip(env_val, COLLECTOR_JVMTI_OPTION); + envp[idx] = env_val; + TprintfT(DBG_LT4, "env_unset(): new %s\n", envp[idx]); + } + __collector_env_printall ("__collector_env_unset, after", envp ); + } +} + +/* update collection environment variables */ +/* update LD_PRELOADs and push them */ +/* not mt safe */ +void +__collector_env_update (char *envp[]) +{ + const char *env_name; + TprintfT (DBG_LT1, "__collector_env_update(envp=0x%p)\n", envp); + extern char **environ; + if (envp == NULL) + { + int v; + TprintfT (DBG_LT2, "__collector_env_update(envp=NULL)\n"); + __collector_env_printall (" environ array, before", environ); + __collector_env_print (" env_update at entry "); + + /* SP_ENV */ + for (v = 0; (env_name = SP_ENV[v]) != NULL; v++) + { + if (env_match (environ, env_name) == -1) + { + int idx; + if ((idx = env_match (sp_env_backup, env_name)) != -1) + { + unsigned strsz = __collector_strlen (sp_env_backup[idx]) + 1; + char *ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1); + CALL_UTIL (snprintf)(ev, strsz, "%s", sp_env_backup[idx]); + if (CALL_UTIL (putenv)(ev) != 0) + TprintfT (DBG_LT2, "__collector_env_update(): ERROR %s is not set!\n", + sp_env_backup[idx]); + } + } + } + __collector_env_print (" env_update after SP_ENV settings "); + + /* LD_LIBRARY_PATH */ + for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++) + /* assumes same index used between LD and SP vars */ + if (putenv_prepend (env_name, sp_libpaths[v], ":")) + TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n", + env_name, sp_libpaths[v]); + __collector_env_print (" env_update after LD_LIBRARY_PATH settings "); + + /* LD_PRELOAD */ + for (v = 0; (env_name = LD_PRELOAD[v]); v++) + /* assumes same index used between LD and SP vars */ + if (putenv_prepend (env_name, sp_preloads[v], " ")) + TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n", + env_name, sp_preloads[v]); + __collector_env_print (" env_update after LD_PRELOAD settings "); + + /* JAVA_TOOL_OPTIONS */ + if (java_mode) + if (putenv_prepend (JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION, " ")) + TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n", + JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION); + __collector_env_print (" env_update after JAVA_TOOL settings "); + } + else + { + int v; + int idx; + TprintfT (DBG_LT2, "__collector_env_update(envp=0x%p) not NULL\n", envp); + __collector_env_printall ("__collector_env_update, before", envp); + /* LD_LIBRARY_PATH */ + for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++) + { + int idx = env_match (envp, env_name); + if (idx != -1) + { + char *env_val = __collector_strchr (envp[idx], '='); + if (env_val) + env_val++; /* skip '=' */ + /* assumes same index used between LD and SP vars */ + char *new_str = env_prepend (env_name, sp_libpaths[v], + ":", env_val); + if (new_str) + envp[idx] = new_str; + } + } + + /* LD_PRELOAD */ + for (v = 0; (env_name = LD_PRELOAD[v]); v++) + { + int idx = env_match (envp, env_name); + if (idx != -1) + { + char *env_val = __collector_strchr (envp[idx], '='); + if (env_val) + env_val++; /* skip '=' */ + /* assumes same index used between LD and SP vars */ + char *new_str = env_prepend (env_name, sp_preloads[v], + " ", env_val); + if (new_str) + envp[idx] = new_str; + } + } + + /* JAVA_TOOL_OPTIONS */ + if (java_mode) + { + env_name = JAVA_TOOL_OPTIONS; + idx = env_match (envp, env_name); + if (idx != -1) + { + char *env_val = __collector_strchr (envp[idx], '='); + if (env_val) + env_val++; /* skip '=' */ + char *new_str = env_prepend (env_name, COLLECTOR_JVMTI_OPTION, + " ", env_val); + if (new_str) + envp[idx] = new_str; + } + } + } + __collector_env_printall ("__collector_env_update, after", environ); +} + + +/*------------------------------------------------------------- putenv */ +int putenv () __attribute__ ((weak, alias ("__collector_putenv"))); +int _putenv () __attribute__ ((weak, alias ("__collector_putenv"))); + +int +__collector_putenv (char * string) +{ + if (CALL_UTIL (putenv) == __collector_putenv || + CALL_UTIL (putenv) == NULL) + { // __collector_libc_funcs_init failed + CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_NEXT, "putenv"); + if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv) + CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_DEFAULT, "putenv"); + if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv) + { + TprintfT (DBG_LT2, "__collector_putenv(): ERROR: no pointer found.\n"); + errno = EBUSY; + return -1; + } + } + if (user_follow_mode == FOLLOW_NONE) + return CALL_UTIL (putenv)(string); + char * envp[] = {string, NULL}; + __collector_env_update (envp); + return CALL_UTIL (putenv)(envp[0]); +} + +/*------------------------------------------------------------- setenv */ +int setenv () __attribute__ ((weak, alias ("__collector_setenv"))); +int _setenv () __attribute__ ((weak, alias ("__collector_setenv"))); + +int +__collector_setenv (const char *name, const char *value, int overwrite) +{ + if (CALL_UTIL (setenv) == __collector_setenv || + CALL_UTIL (setenv) == NULL) + { // __collector_libc_funcs_init failed + CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_NEXT, "setenv"); + if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv) + CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_DEFAULT, "setenv"); + if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv) + { + TprintfT (DBG_LT2, "__collector_setenv(): ERROR: no pointer found.\n"); + errno = EBUSY; + return -1; + } + } + if (user_follow_mode == FOLLOW_NONE || !overwrite) + return CALL_UTIL (setenv)(name, value, overwrite); + size_t sz = __collector_strlen (name) + 1 + __collector_strlen (value) + 1; + char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1); + if (ev == NULL) + return CALL_UTIL (setenv)(name, value, overwrite); + CALL_UTIL (snprintf)(ev, sz, "%s=%s", name, value); + char * envp[] = {ev, NULL}; + __collector_env_update (envp); + if (envp[0] == ev) + { + __collector_freeCSize (__collector_heap, ev, sz); + return CALL_UTIL (setenv)(name, value, overwrite); + } + else + { + char *env_val = __collector_strchr (envp[0], '='); + if (env_val) + { + *env_val = '\0'; + env_val++; /* skip '=' */ + } + return CALL_UTIL (setenv)(envp[0], env_val, overwrite); + } +} + +/*------------------------------------------------------------- unsetenv */ +int unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv"))); +int _unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv"))); + +int +__collector_unsetenv (const char *name) +{ + if (CALL_UTIL (unsetenv) == __collector_unsetenv || + CALL_UTIL (unsetenv) == NULL) + { // __collector_libc_funcs_init failed + CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_NEXT, "unsetenv"); + if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv) + CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_DEFAULT, "unsetenv"); + if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv) + { + TprintfT (DBG_LT2, "__collector_unsetenv(): ERROR: no pointer found.\n"); + errno = EBUSY; + return -1; + } + } + int ret = CALL_UTIL (unsetenv)(name); + if (user_follow_mode == FOLLOW_NONE) + return ret; + TprintfT (DBG_LT2, "__collector_unsetenv(): %d.\n", user_follow_mode); + size_t sz = __collector_strlen (name) + 1 + 1; + char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1); + if (ev == NULL) + return ret; + CALL_UTIL (snprintf)(ev, sz, "%s=", name); + char * envp[] = {ev, NULL}; + __collector_env_update (envp); + if (envp[0] == ev) + __collector_freeCSize (__collector_heap, ev, sz); + else + CALL_UTIL (putenv)(envp[0]); + return ret; +} + +/*------------------------------------------------------------- clearenv */ +int clearenv () __attribute__ ((weak, alias ("__collector_clearenv"))); + +int +__collector_clearenv (void) +{ + if (CALL_UTIL (clearenv) == __collector_clearenv || CALL_UTIL (clearenv) == NULL) + { + /* __collector_libc_funcs_init failed; look up clearenv now */ + CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_NEXT, "clearenv"); + if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv) + /* still not found; try again */ + CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_DEFAULT, "clearenv"); + if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv) + { + /* still not found -- a fatal error */ + TprintfT (DBG_LT2, "__collector_clearenv(): ERROR: %s\n", dlerror ()); + CALL_UTIL (fprintf)(stderr, "__collector_clearenv(): ERROR: %s\n", dlerror ()); + errno = EBUSY; + return -1; + } + } + int ret = CALL_UTIL (clearenv)(); + if (user_follow_mode == FOLLOW_NONE) + return ret; + if (sp_env_backup == NULL) + { + TprintfT (DBG_LT2, "__collector_clearenv: ERROR sp_env_backup is not set!\n"); + return ret; + } + for (int v = 0; v < NUM_SP_ENV_VARS + NUM_LD_ENV_VARS; v++) + if (sp_env_backup[v] && CALL_UTIL (putenv)(sp_env_backup[v]) != 0) + TprintfT (DBG_LT2, "__collector_clearenv: ERROR %s is not set!\n", + sp_env_backup[v]); + return ret; +} |