Home | History | Annotate | Line # | Download | only in libcollector
envmgmt.c revision 1.1.1.1
      1 /* Copyright (C) 2021 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 }
    841