1  /* Copyright (C) 2021-2023 Free Software Foundation, Inc.
       2     Contributed by Oracle.
       3  
       4     This file is part of GNU Binutils.
       5  
       6     This program is free software; you can redistribute it and/or modify
       7     it under the terms of the GNU General Public License as published by
       8     the Free Software Foundation; either version 3, or (at your option)
       9     any later version.
      10  
      11     This program is distributed in the hope that it will be useful,
      12     but WITHOUT ANY WARRANTY; without even the implied warranty of
      13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14     GNU General Public License for more details.
      15  
      16     You should have received a copy of the GNU General Public License
      17     along with this program; if not, write to the Free Software
      18     Foundation, 51 Franklin Street - Fifth Floor, Boston,
      19     MA 02110-1301, USA.  */
      20  
      21  /*
      22   *	Routines for managing the target's environment array
      23   */
      24  
      25  #include "config.h"
      26  #include "descendants.h"
      27  
      28  #define MAX_LD_PRELOADS 2
      29  
      30  /* TprintfT(<level>,...) definitions.  Adjust per module as needed */
      31  #define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
      32  #define DBG_LT1 1 // for configuration details, warnings
      33  #define DBG_LT2 2
      34  #define DBG_LT3 3
      35  #define DBG_LT4 4
      36  
      37  /* original environment settings to be saved for later restoration */
      38  static char *sp_preloads[MAX_LD_PRELOADS];
      39  static char *sp_libpaths[MAX_LD_PRELOADS];
      40  char **sp_env_backup;
      41  
      42  static const char *SP_ENV[];
      43  static const char *LD_ENV[];
      44  static const char *SP_PRELOAD[];
      45  static const char *LD_PRELOAD[];
      46  static const char *SP_LIBRARY_PATH[];
      47  static const char *LD_LIBRARY_PATH[];
      48  static int NUM_SP_ENV_VARS;
      49  static int NUM_LD_ENV_VARS;
      50  static int NUM_SP_PRELOADS;
      51  static int NUM_LD_PRELOADS;
      52  static int NUM_SP_LIBPATHS;
      53  static int NUM_LD_LIBPATHS;
      54  
      55  static const char *SP_ENV[] = {
      56    SP_COLLECTOR_PARAMS,      /* data descriptor */
      57    SP_COLLECTOR_EXPNAME,     /* experiment name */
      58    SP_COLLECTOR_FOLLOW_SPEC, /* linetrace */
      59    SP_COLLECTOR_FOUNDER,     /* determine founder exp */
      60    SP_PRELOAD_STRINGS,       /* LD_PRELOADs for data collection */
      61    SP_LIBPATH_STRINGS,       /* LD_LIBRARY_PATHs for data collection */
      62    "SP_COLLECTOR_TRACELEVEL", /* tprintf */
      63  #if DEBUG
      64    "SP_COLLECTOR_SIGACTION", /* dispatcher, hwprofile */
      65  #endif
      66    /* JAVA* */
      67    /* LD_DEBUG=audit,bindings,detail */
      68    /* LD_ORIGIN=yes */
      69    NULL
      70  };
      71  
      72  static const char *LD_ENV[] = {
      73    LD_PRELOAD_STRINGS,       /* LD_PRELOADs */
      74    LD_LIBPATH_STRINGS,       /* LD_LIBRARY_PATHs */
      75    JAVA_TOOL_OPTIONS,        /* enable -agentlib:collector for JVMTI */
      76    NULL
      77  };
      78  
      79  static const char *SP_PRELOAD[] = {
      80    SP_PRELOAD_STRINGS,
      81    NULL
      82  };
      83  
      84  static const char *LD_PRELOAD[] = {
      85    LD_PRELOAD_STRINGS,
      86    NULL
      87  };
      88  
      89  static const char *SP_LIBRARY_PATH[] = {
      90    SP_LIBPATH_STRINGS,
      91    NULL
      92  };
      93  static const char *LD_LIBRARY_PATH[] = {
      94    LD_LIBPATH_STRINGS,
      95    NULL
      96  };
      97  
      98  void
      99  __collector_env_save_preloads ()
     100  {
     101    /* save the list of SP_PRELOADs */
     102    int v;
     103    for (v = 0; SP_PRELOAD[v]; v++)
     104      {
     105        sp_preloads[v] = __collector_strdup (CALL_UTIL (getenv)(SP_PRELOAD[v]));
     106        TprintfT (DBG_LT3, "__collector_env_save_preloads: %s=%s\n", SP_PRELOAD[v], sp_preloads[v]);
     107      }
     108    NUM_SP_PRELOADS = v;
     109    for (v = 0; SP_LIBRARY_PATH[v]; v++)
     110      {
     111        sp_libpaths[v] = __collector_strdup (CALL_UTIL (getenv)(SP_LIBRARY_PATH[v]));
     112        TprintfT (DBG_LT4, "__collector_env_save_preloads: %s=%s\n", SP_LIBRARY_PATH[v],
     113  		sp_libpaths[v] ? sp_libpaths[v] : "NULL");
     114      }
     115    NUM_SP_LIBPATHS = v;
     116    for (v = 0; LD_PRELOAD[v]; v++)
     117      ;
     118    NUM_LD_PRELOADS = v;
     119    for (v = 0; LD_LIBRARY_PATH[v]; v++)
     120      ;
     121    NUM_LD_LIBPATHS = v;
     122    for (v = 0; SP_ENV[v]; v++)
     123      ;
     124    NUM_SP_ENV_VARS = v;
     125    for (v = 0; LD_ENV[v]; v++)
     126      ;
     127    NUM_LD_ENV_VARS = v;
     128  }
     129  
     130  /* free the memory involved in backing up the environment */
     131  void
     132  __collector_env_backup_free ()
     133  {
     134    int v = 0;
     135    TprintfT (DBG_LT2, "env_backup_free()\n");
     136    for (v = 0; sp_env_backup[v]; v++)
     137      {
     138        TprintfT (DBG_LT2, "env_backup_free():sp_env_backup[%d]=%s \n", v, sp_env_backup[v]);
     139        __collector_freeCSize (__collector_heap, (char *) sp_env_backup[v], __collector_strlen (sp_env_backup[v]) + 1);
     140      }
     141    __collector_freeCSize (__collector_heap, (char**) sp_env_backup,
     142  			 (NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1) * sizeof (char*));
     143  }
     144  
     145  char **
     146  __collector_env_backup ()
     147  {
     148    TprintfT (DBG_LT2, "env_backup_()\n");
     149    char **backup = __collector_env_allocate (NULL, 1);
     150    __collector_env_update (backup);
     151    TprintfT (DBG_LT2, "env_backup_()\n");
     152    return backup;
     153  }
     154  
     155  /*
     156     function: env_prepend()
     157       given an <old_str>, check to see if <str>
     158       is already defined by it.  If not, allocate
     159       a new string and concat <envvar>=<str><separator><old_str>
     160     params:
     161       old_str: original string
     162       str: substring to prepend
     163       return: pointer to updated string or NULL if string was not updated.
     164   */
     165  static char *
     166  env_prepend (const char *envvar, const char *str, const char *separator,
     167  	     const char *old_str)
     168  {
     169    if (!envvar || *envvar == 0 || !str || *str == 0)
     170      {
     171        /* nothing to do */
     172        TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") -- nothing to do\n",
     173  		envvar, str, separator, old_str);
     174  
     175        return NULL;
     176      }
     177    TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\")\n",
     178  	    envvar, str, separator, old_str);
     179    char *ev;
     180    size_t strsz;
     181    if (!old_str || *old_str == 0)
     182      {
     183        strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) + 1;
     184        ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
     185        if (ev)
     186  	{
     187  	  CALL_UTIL (snprintf)(ev, strsz, "%s=%s", envvar, str);
     188  	  assert (__collector_strlen (ev) + 1 == strsz);
     189  	}
     190        else
     191  	TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n");
     192      }
     193    else
     194      {
     195        char *p = CALL_UTIL (strstr)(old_str, str);
     196        if (p)
     197  	{
     198  	  TprintfT (DBG_LT2, "env_prepend(): %s=%s was already set\n",
     199  		    envvar, old_str);
     200  	  return NULL;
     201  	}
     202        strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) +
     203  	      __collector_strlen (separator) + __collector_strlen (old_str) + 1;
     204        ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
     205        if (ev)
     206  	{
     207  	  CALL_UTIL (snprintf)(ev, strsz, "%s=%s%s%s", envvar, str, separator, old_str);
     208  	  assert (__collector_strlen (ev) + 1 == strsz);
     209  	}
     210        else
     211  	TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n");
     212      }
     213    TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") returns \"%s\"\n",
     214  	    envvar, str, separator, old_str, (ev == NULL ? "NULL" : ev));
     215    return ev;
     216  }
     217  
     218  /*
     219     function: putenv_prepend()
     220       get environment variable <envvar>, check to see if <str>
     221       is already defined by it.  If not prepend <str>
     222       and put it back to environment.
     223     params:
     224       envvar: environment variable
     225       str: substring to find
     226       return: 0==success, nonzero on failure.
     227   */
     228  int
     229  putenv_prepend (const char *envvar, const char *str, const char *separator)
     230  {
     231    if (!envvar || *envvar == 0)
     232      return 1;
     233    const char * old_str = CALL_UTIL (getenv)(envvar);
     234    char * newstr = env_prepend (envvar, str, separator, old_str);
     235    if (newstr)
     236      // now put the new variable into the environment
     237      if (CALL_UTIL (putenv)(newstr) != 0)
     238        {
     239  	TprintfT (DBG_LT2, "putenv_prepend(): ERROR %s is not set!\n", newstr);
     240  	return 1;
     241        }
     242    return 0;
     243  }
     244  
     245  /*
     246     function: env_strip()
     247       Finds substr in origstr; Removes
     248       all characters from previous ':' or ' '
     249       up to and including any trailing ':' or ' '.
     250     params:
     251       env: environment variable contents
     252       str: substring to find
     253       return: count of instances removed from env
     254   */
     255  static int
     256  env_strip (char *origstr, const char *substr)
     257  {
     258    int removed = 0;
     259    char *p, *q;
     260    if (origstr == NULL || substr == NULL || *substr == 0)
     261      return 0;
     262    while ((p = q = CALL_UTIL (strstr)(origstr, substr)))
     263      {
     264        p += __collector_strlen (substr);
     265        while (*p == ':' || *p == ' ') /* strip trailing separator */
     266  	p++;
     267        while (*q != ':' && *q != ' ' && *q != '=' && q != origstr) /* strip path */
     268  	q--;
     269        if (q != origstr) /* restore leading separator (if any) */
     270  	q++;
     271        __collector_strlcpy (q, p, __collector_strlen (p) + 1);
     272        removed++;
     273      }
     274    return removed;
     275  }
     276  
     277  /*
     278     function: env_ld_preload_strip()
     279       Removes known libcollector shared objects from envv.
     280     params:
     281       var: shared object name (leading characters don't have to match)
     282       return: 0 = so's removed, non-zero = so's not found.
     283   */
     284  static int
     285  env_ld_preload_strip (char *envv)
     286  {
     287    if (!envv || *envv == 0)
     288      {
     289        TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - envv is NULL\n");
     290        return -1;
     291      }
     292    for (int v = 0; SP_PRELOAD[v]; v++)
     293      if (env_strip (envv, sp_preloads[v]))
     294        return 0;
     295    if (line_mode != LM_CLOSED)
     296      TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - could not strip SP_PRELOADS from '%s'\n",
     297  	      envv);
     298    return -2;
     299  }
     300  
     301  void
     302  __collector_env_print (char * label)
     303  {
     304  #if DEBUG
     305    TprintfT (DBG_LT2, "__collector_env_print(%s)\n", label);
     306    for (int v = 0; v < MAX_LD_PRELOADS; v++)
     307      TprintfT (DBG_LT2, " %s  sp_preloads[%d] (0x%p)=%s\n", label,
     308  	      v, sp_preloads[v], (sp_preloads[v] == NULL ? "NULL" : sp_preloads[v]));
     309    for (int v = 0; SP_ENV[v]; v++)
     310      {
     311        char *s = CALL_UTIL (getenv)(SP_ENV[v]);
     312        if (s == NULL)
     313  	s = "<null>";
     314        TprintfT (DBG_LT2, " %s  SP_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, SP_ENV[v], SP_ENV[v], s);
     315      }
     316    for (int v = 0; LD_ENV[v]; v++)
     317      {
     318        char *s = CALL_UTIL (getenv)(LD_ENV[v]);
     319        if (s == NULL)
     320  	s = "<null>";
     321        TprintfT (DBG_LT2, " %s  LD_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, LD_ENV[v], LD_ENV[v], s);
     322      }
     323  #endif
     324  }
     325  
     326  void
     327  __collector_env_printall (char *label, char *envp[])
     328  {
     329  #if DEBUG
     330    TprintfT (DBG_LT2, "__collector_env_printall(%s): environment @ 0x%p\n", label, envp);
     331    for (int i = 0; envp[i]; i++)
     332      Tprintf (DBG_LT2, "\tenv[%d]@0x%p == %s\n", i, envp[i], envp[i]);
     333  #endif
     334  }
     335  
     336  /* match collector environment variable */
     337  int
     338  env_match (char *envp[], const char *envvar)
     339  {
     340    int match = -1;
     341    if (envp == NULL)
     342      TprintfT (DBG_LT1, "env_match(%s): NULL envp!\n", envvar);
     343    else
     344      {
     345        int i = 0;
     346        while ((envp[i] != NULL) && (__collector_strStartWith (envp[i], envvar)))
     347  	i++;
     348        if ((envp[i] == NULL) || (envp[i][__collector_strlen (envvar)] != '='))
     349  	TprintfT (DBG_LT4, "env_match(): @%p []%s not defined in envp\n", envp, envvar);
     350        else
     351  	{
     352  	  TprintfT (DBG_LT4, "env_match(): @%p [%d]%s defined in envp\n", envp, i, envp[i]);
     353  	  match = i;
     354  	}
     355      }
     356    TprintfT (DBG_LT1, "env_match(%s): found in slot %d\n", envvar, match);
     357    return (match);
     358  }
     359  
     360  /* allocate new environment with collector variables */
     361  /* 1) copy all current envp[] ptrs into a new array, coll_env[] */
     362  /* 2) if collector-related env ptrs not in envp[], append them to coll_env */
     363  /*     from processes' "environ" (allocate_env==1) */
     364  /*     or from sp_env_backup (allocate_env==0)*/
     365  /*     If they already exist in envp, probably is an error... */
     366  /* 3) return coll_env */
     367  
     368  /* __collector__env_update() need be called after this to set LD_ENV*/
     369  char **
     370  __collector_env_allocate (char *const old_env[], int allocate_env)
     371  {
     372    extern char **environ;    /* the process' actual environment */
     373    char **new_env;           /* a new environment for collection */
     374    TprintfT (DBG_LT3, "__collector_env_allocate(old_env=0x%p %s environ=0x%p)\n",
     375  	    old_env, (old_env == environ) ? "==" : "!=", environ);
     376    /* set up a copy of the provided old_env for collector use */
     377    int old_env_size = 0;
     378  
     379    /* determine number of (used) slots in old_env */
     380    if (old_env)
     381      while (old_env[old_env_size] != NULL)
     382        old_env_size++;
     383    /* allocate a new vector with additional slots */
     384    int new_env_alloc_sz = old_env_size + NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1;
     385    new_env = (char**) __collector_allocCSize (__collector_heap, new_env_alloc_sz * sizeof (char*), 1);
     386    if (new_env == NULL)
     387      return NULL;
     388    TprintfT (DBG_LT4, "__collector_env_allocate(): old_env has %d entries, new_env @ 0x%p\n", old_env_size, new_env);
     389  
     390    /* copy provided old_env pointers to new collector environment */
     391    int new_env_size = 0;
     392    for (new_env_size = 0; new_env_size < old_env_size; new_env_size++)
     393      new_env[new_env_size] = old_env[new_env_size];
     394  
     395    /* check each required environment variable, adding as required */
     396    const char * env_var;
     397    int v;
     398    for (v = 0; (env_var = SP_ENV[v]) != NULL; v++)
     399      {
     400        if (env_match ((char**) old_env, env_var) == -1)
     401  	{
     402  	  int idx;
     403  	  /* not found in old_env */
     404  	  if (allocate_env)
     405  	    {
     406  	      if ((idx = env_match (environ, env_var)) != -1)
     407  		{
     408  		  /* found in environ */
     409  		  TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
     410  			    new_env_size, environ[idx]);
     411  		  int varsz = __collector_strlen (environ[idx]) + 1;
     412  		  char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1);
     413  		  if (var == NULL)
     414  		    return NULL;
     415  		  __collector_strlcpy (var, environ[idx], varsz);
     416  		  new_env[new_env_size++] = var;
     417  		}
     418  	      else
     419  		{
     420  		  /* not found in environ */
     421  		  if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) ||
     422  		      (__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0))
     423  		    TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n",
     424  			      env_var);
     425  		}
     426  	    }
     427  	  else
     428  	    {
     429  	      if ((idx = env_match (sp_env_backup, env_var)) != -1)
     430  		{
     431  		  /* found in backup */
     432  		  TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
     433  			    new_env_size, sp_env_backup[idx]);
     434  		  new_env[new_env_size++] = sp_env_backup[idx];
     435  		}
     436  	      else
     437  		{
     438  		  /* not found in environ */
     439  		  if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) ||
     440  		      (__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0))
     441  		    TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n",
     442  				env_var);
     443  		}
     444  	    }
     445  	}
     446      }
     447  
     448    for (v = 0; (env_var = LD_ENV[v]) != NULL; v++)
     449      {
     450        if (env_match ((char**) old_env, env_var) == -1)
     451  	{
     452  	  int idx;
     453  	  /* not found in old_env */
     454  	  if (allocate_env)
     455  	    {
     456  	      if ((idx = env_match (environ, env_var)) != -1)
     457  		{
     458  		  /* found in environ */
     459  		  TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
     460  			    new_env_size, environ[idx]);
     461  
     462  		  int varsz = __collector_strlen (env_var) + 2;
     463  		  char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1);
     464  		  if (var == NULL)
     465  		    return NULL;
     466  		  // assume __collector_env_update() will fill content of env_var
     467  		  CALL_UTIL (snprintf)(var, varsz, "%s=", env_var);
     468  		  new_env[new_env_size++] = var;
     469  		}
     470  	    }
     471  	  else
     472  	    {
     473  	      if ((idx = env_match (sp_env_backup, env_var)) != -1)
     474  		{
     475  		  /* found in backup */
     476  		  TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
     477  			    new_env_size, sp_env_backup[idx]);
     478  		  new_env[new_env_size++] = sp_env_backup[idx];
     479  		}
     480  	    }
     481  	}
     482      }
     483  
     484    /* ensure new_env vector ends with NULL */
     485    new_env[new_env_size] = NULL;
     486    assert (new_env_size <= new_env_alloc_sz);
     487    TprintfT (DBG_LT4, "__collector_env_allocate(): new_env has %d entries (%d added), new_env=0x%p\n",
     488  	    new_env_size, new_env_size - old_env_size, new_env);
     489    if (new_env_size != old_env_size && !allocate_env)
     490      __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
     491  			   SP_JCMD_CWARN, COL_WARN_EXECENV, new_env_size - old_env_size);
     492    __collector_env_printall ("__collector_env_allocate", new_env);
     493    return (new_env);
     494  }
     495  
     496  /* unset collection environment variables */
     497  /* if they exist in env... */
     498  /* 1) push non-collectorized version to env */
     499  
     500  /* Not mt safe */
     501  void
     502  __collector_env_unset (char *envp[])
     503  {
     504    int v;
     505    const char * env_name;
     506    TprintfT (DBG_LT3, "env_unset(envp=0x%p)\n", envp);
     507    if (envp == NULL)
     508      {
     509        for (v = 0; (env_name = LD_PRELOAD[v]); v++)
     510  	{
     511  	  const char *env_val = CALL_UTIL (getenv)(env_name);
     512  	  if (env_val && CALL_UTIL (strstr)(env_val, sp_preloads[v]))
     513  	    {
     514  	      size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1;
     515  	      char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
     516  	      if (ev == NULL)
     517  		return;
     518  	      CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val);
     519  	      assert (__collector_strlen (ev) + 1 == sz);
     520  	      TprintfT (DBG_LT4, "env_unset(): old %s\n", ev);
     521  	      env_ld_preload_strip (ev);
     522  	      CALL_UTIL (putenv)(ev);
     523  	      TprintfT (DBG_LT4, "env_unset(): new %s\n", ev);
     524  	    }
     525  	}
     526        // unset JAVA_TOOL_OPTIONS
     527        env_name = JAVA_TOOL_OPTIONS;
     528        const char * env_val = CALL_UTIL (getenv)(env_name);
     529        if (env_val && CALL_UTIL (strstr)(env_val, COLLECTOR_JVMTI_OPTION))
     530  	{
     531  	  size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1;
     532  	  char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
     533  	  if (ev == NULL)
     534  	    return;
     535  	  CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val);
     536  	  assert (__collector_strlen (ev) + 1 == sz);
     537  	  TprintfT (DBG_LT4, "env_unset(): old %s\n", ev);
     538  	  env_strip (ev, COLLECTOR_JVMTI_OPTION);
     539  	  CALL_UTIL (putenv)(ev);
     540  	  TprintfT (DBG_LT4, "env_unset(): new %s\n", ev);
     541  	}
     542        __collector_env_print ("__collector_env_unset");
     543      }
     544    else
     545      {
     546        __collector_env_printall ("__collector_env_unset, before", envp);
     547        for (v = 0; (env_name = LD_PRELOAD[v]); v++)
     548  	{
     549  	  int idx = env_match (envp, env_name);
     550  	  if (idx != -1)
     551  	    {
     552  	      char *env_val = envp[idx];
     553  	      TprintfT (DBG_LT4, "env_unset(): old %s\n", env_val);
     554  	      envp[idx] = "junk="; /* xxxx is it ok to use original string? */
     555  	      env_ld_preload_strip (env_val);
     556  	      envp[idx] = env_val;
     557  	      TprintfT (DBG_LT4, "env_unset(): new %s\n", envp[idx]);
     558  	    }
     559  	}
     560  	// unset JAVA_TOOL_OPTIONS
     561  	env_name = JAVA_TOOL_OPTIONS;
     562  	int idx = env_match(envp, env_name);
     563  	if (idx != -1) {
     564  	    char *env_val = envp[idx];
     565  	    TprintfT(DBG_LT4, "env_unset(): old %s\n", env_val);
     566  	    envp[idx] = "junk="; /* xxxx is it ok to use original string? */
     567  	    env_strip(env_val, COLLECTOR_JVMTI_OPTION);
     568  	    envp[idx] = env_val;
     569  	    TprintfT(DBG_LT4, "env_unset(): new %s\n", envp[idx]);
     570  	}
     571  	__collector_env_printall ("__collector_env_unset, after", envp );
     572      }
     573  }
     574  
     575  /* update collection environment variables */
     576  /* update LD_PRELOADs and push them */
     577  /* not mt safe */
     578  void
     579  __collector_env_update (char *envp[])
     580  {
     581    const char *env_name;
     582    TprintfT (DBG_LT1, "__collector_env_update(envp=0x%p)\n", envp);
     583    extern char **environ;
     584    if (envp == NULL)
     585      {
     586        int v;
     587        TprintfT (DBG_LT2, "__collector_env_update(envp=NULL)\n");
     588        __collector_env_printall ("  environ array, before", environ);
     589        __collector_env_print ("  env_update at entry ");
     590  
     591        /* SP_ENV */
     592        for (v = 0; (env_name = SP_ENV[v]) != NULL; v++)
     593  	{
     594  	  if (env_match (environ, env_name) == -1)
     595  	    {
     596  	      int idx;
     597  	      if ((idx = env_match (sp_env_backup, env_name)) != -1)
     598  		{
     599  		  unsigned strsz = __collector_strlen (sp_env_backup[idx]) + 1;
     600  		  char *ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
     601  		  CALL_UTIL (snprintf)(ev, strsz, "%s", sp_env_backup[idx]);
     602  		  if (CALL_UTIL (putenv)(ev) != 0)
     603  		    TprintfT (DBG_LT2, "__collector_env_update(): ERROR %s is not set!\n",
     604  				sp_env_backup[idx]);
     605  		}
     606  	    }
     607  	}
     608        __collector_env_print ("  env_update after SP_ENV settings ");
     609  
     610        /* LD_LIBRARY_PATH */
     611        for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++)
     612  	/* assumes same index used between LD and SP vars */
     613  	if (putenv_prepend (env_name, sp_libpaths[v], ":"))
     614  	  TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
     615  		    env_name, sp_libpaths[v]);
     616        __collector_env_print ("  env_update after LD_LIBRARY_PATH settings ");
     617  
     618        /* LD_PRELOAD */
     619        for (v = 0; (env_name = LD_PRELOAD[v]); v++)
     620  	/* assumes same index used between LD and SP vars */
     621  	if (putenv_prepend (env_name, sp_preloads[v], " "))
     622  	  TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
     623  		    env_name, sp_preloads[v]);
     624        __collector_env_print ("  env_update after LD_PRELOAD settings ");
     625  
     626        /* JAVA_TOOL_OPTIONS */
     627        if (java_mode)
     628  	if (putenv_prepend (JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION, " "))
     629  	  TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
     630  		    JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION);
     631        __collector_env_print ("  env_update after JAVA_TOOL settings ");
     632      }
     633    else
     634      {
     635        int v;
     636        int idx;
     637        TprintfT (DBG_LT2, "__collector_env_update(envp=0x%p) not NULL\n", envp);
     638        __collector_env_printall ("__collector_env_update, before", envp);
     639        /* LD_LIBRARY_PATH */
     640        for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++)
     641  	{
     642  	  int idx = env_match (envp, env_name);
     643  	  if (idx != -1)
     644  	    {
     645  	      char *env_val = __collector_strchr (envp[idx], '=');
     646  	      if (env_val)
     647  		env_val++; /* skip '=' */
     648  	      /* assumes same index used between LD and SP vars */
     649  	      char *new_str = env_prepend (env_name, sp_libpaths[v],
     650  					   ":", env_val);
     651  	      if (new_str)
     652  		envp[idx] = new_str;
     653  	    }
     654  	}
     655  
     656        /* LD_PRELOAD */
     657        for (v = 0; (env_name = LD_PRELOAD[v]); v++)
     658  	{
     659  	  int idx = env_match (envp, env_name);
     660  	  if (idx != -1)
     661  	    {
     662  	      char *env_val = __collector_strchr (envp[idx], '=');
     663  	      if (env_val)
     664  		env_val++; /* skip '=' */
     665  	      /* assumes same index used between LD and SP vars */
     666  	      char *new_str = env_prepend (env_name, sp_preloads[v],
     667  					   " ", env_val);
     668  	      if (new_str)
     669  		envp[idx] = new_str;
     670  	    }
     671  	}
     672  
     673        /* JAVA_TOOL_OPTIONS */
     674        if (java_mode)
     675  	{
     676  	  env_name = JAVA_TOOL_OPTIONS;
     677  	  idx = env_match (envp, env_name);
     678  	  if (idx != -1)
     679  	    {
     680  	      char *env_val = __collector_strchr (envp[idx], '=');
     681  	      if (env_val)
     682  		env_val++; /* skip '=' */
     683  	      char *new_str = env_prepend (env_name, COLLECTOR_JVMTI_OPTION,
     684  					   " ", env_val);
     685  	      if (new_str)
     686  		envp[idx] = new_str;
     687  	    }
     688  	}
     689      }
     690    __collector_env_printall ("__collector_env_update, after", environ);
     691  }
     692  
     693  
     694  /*------------------------------------------------------------- putenv */
     695  int putenv () __attribute__ ((weak, alias ("__collector_putenv")));
     696  int _putenv () __attribute__ ((weak, alias ("__collector_putenv")));
     697  
     698  int
     699  __collector_putenv (char * string)
     700  {
     701    if (CALL_UTIL (putenv) == __collector_putenv ||
     702        CALL_UTIL (putenv) == NULL)
     703      { // __collector_libc_funcs_init failed
     704        CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_NEXT, "putenv");
     705        if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv)
     706  	  CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_DEFAULT, "putenv");
     707        if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv)
     708  	{
     709  	  TprintfT (DBG_LT2, "__collector_putenv(): ERROR: no pointer found.\n");
     710  	  errno = EBUSY;
     711  	  return -1;
     712  	}
     713      }
     714    if (user_follow_mode == FOLLOW_NONE)
     715      return CALL_UTIL (putenv)(string);
     716    char * envp[] = {string, NULL};
     717    __collector_env_update (envp);
     718    return CALL_UTIL (putenv)(envp[0]);
     719  }
     720  
     721  /*------------------------------------------------------------- setenv */
     722  int setenv () __attribute__ ((weak, alias ("__collector_setenv")));
     723  int _setenv () __attribute__ ((weak, alias ("__collector_setenv")));
     724  
     725  int
     726  __collector_setenv (const char *name, const char *value, int overwrite)
     727  {
     728    if (CALL_UTIL (setenv) == __collector_setenv ||
     729        CALL_UTIL (setenv) == NULL)
     730      { // __collector_libc_funcs_init failed
     731        CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_NEXT, "setenv");
     732        if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv)
     733  	CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_DEFAULT, "setenv");
     734        if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv)
     735  	{
     736  	  TprintfT (DBG_LT2, "__collector_setenv(): ERROR: no pointer found.\n");
     737  	  errno = EBUSY;
     738  	  return -1;
     739  	}
     740      }
     741    if (user_follow_mode == FOLLOW_NONE || !overwrite)
     742      return CALL_UTIL (setenv)(name, value, overwrite);
     743    size_t sz = __collector_strlen (name) + 1 + __collector_strlen (value) + 1;
     744    char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
     745    if (ev == NULL)
     746      return CALL_UTIL (setenv)(name, value, overwrite);
     747    CALL_UTIL (snprintf)(ev, sz, "%s=%s", name, value);
     748    char * envp[] = {ev, NULL};
     749    __collector_env_update (envp);
     750    if (envp[0] == ev)
     751      {
     752        __collector_freeCSize (__collector_heap, ev, sz);
     753        return CALL_UTIL (setenv)(name, value, overwrite);
     754      }
     755    else
     756      {
     757        char *env_val = __collector_strchr (envp[0], '=');
     758        if (env_val)
     759  	{
     760  	  *env_val = '\0';
     761  	  env_val++; /* skip '=' */
     762  	}
     763        return CALL_UTIL (setenv)(envp[0], env_val, overwrite);
     764      }
     765  }
     766  
     767  /*------------------------------------------------------------- unsetenv */
     768  int unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv")));
     769  int _unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv")));
     770  
     771  int
     772  __collector_unsetenv (const char *name)
     773  {
     774    if (CALL_UTIL (unsetenv) == __collector_unsetenv ||
     775        CALL_UTIL (unsetenv) == NULL)
     776      { // __collector_libc_funcs_init failed
     777        CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_NEXT, "unsetenv");
     778        if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv)
     779  	CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_DEFAULT, "unsetenv");
     780        if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv)
     781  	{
     782  	  TprintfT (DBG_LT2, "__collector_unsetenv(): ERROR: no pointer found.\n");
     783  	  errno = EBUSY;
     784  	  return -1;
     785  	}
     786      }
     787    int ret = CALL_UTIL (unsetenv)(name);
     788    if (user_follow_mode == FOLLOW_NONE)
     789      return ret;
     790    TprintfT (DBG_LT2, "__collector_unsetenv(): %d.\n", user_follow_mode);
     791    size_t sz = __collector_strlen (name) + 1 + 1;
     792    char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
     793    if (ev == NULL)
     794      return ret;
     795    CALL_UTIL (snprintf)(ev, sz, "%s=", name);
     796    char * envp[] = {ev, NULL};
     797    __collector_env_update (envp);
     798    if (envp[0] == ev)
     799      __collector_freeCSize (__collector_heap, ev, sz);
     800    else
     801      CALL_UTIL (putenv)(envp[0]);
     802    return ret;
     803  }
     804  
     805  /*------------------------------------------------------------- clearenv */
     806  int clearenv () __attribute__ ((weak, alias ("__collector_clearenv")));
     807  
     808  int
     809  __collector_clearenv (void)
     810  {
     811    if (CALL_UTIL (clearenv) == __collector_clearenv || CALL_UTIL (clearenv) == NULL)
     812      {
     813        /* __collector_libc_funcs_init failed; look up clearenv now */
     814        CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_NEXT, "clearenv");
     815        if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv)
     816  	/* still not found; try again */
     817  	CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_DEFAULT, "clearenv");
     818        if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv)
     819  	{
     820  	  /* still not found -- a fatal error */
     821  	  TprintfT (DBG_LT2, "__collector_clearenv(): ERROR: %s\n", dlerror ());
     822  	  CALL_UTIL (fprintf)(stderr, "__collector_clearenv(): ERROR: %s\n", dlerror ());
     823  	  errno = EBUSY;
     824  	  return -1;
     825  	}
     826      }
     827    int ret = CALL_UTIL (clearenv)();
     828    if (user_follow_mode == FOLLOW_NONE)
     829      return ret;
     830    if (sp_env_backup == NULL)
     831      {
     832        TprintfT (DBG_LT2, "__collector_clearenv: ERROR sp_env_backup is not set!\n");
     833        return ret;
     834      }
     835    for (int v = 0; v < NUM_SP_ENV_VARS + NUM_LD_ENV_VARS; v++)
     836      if (sp_env_backup[v] && CALL_UTIL (putenv)(sp_env_backup[v]) != 0)
     837        TprintfT (DBG_LT2, "__collector_clearenv: ERROR %s is not set!\n",
     838  		sp_env_backup[v]);
     839    return ret;
     840  }