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