regen config
[binutils-gdb.git] / gprofng / libcollector / envmgmt.c
1 /* Copyright (C) 2021-2023 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
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
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 **
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 *
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
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
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
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
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
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
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 **
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
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
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
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
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
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
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 }