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