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