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