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