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