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