1 /*
2 * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
3 * University Research and Technology
4 * Corporation. All rights reserved.
5 * Copyright (c) 2004-2005 The University of Tennessee and The University
6 * of Tennessee Research Foundation. All rights
7 * reserved.
8 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9 * University of Stuttgart. All rights reserved.
10 * Copyright (c) 2004-2005 The Regents of the University of California.
11 * All rights reserved.
12 * Copyright (c) 2006-2015 Cisco Systems, Inc. All rights reserved.
13 * Copyright (c) 2007-2013 Los Alamos National Security, LLC. All rights
14 * reserved.
15 * Copyright (c) 2014 Intel, Inc. All rights reserved.
16 * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved.
17 * $COPYRIGHT$
18 *
19 * Additional copyrights may follow
20 *
21 * $HEADER$
22 */
23
24 #include "opal_config.h"
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "opal/util/printf.h"
31 #include "opal/util/argv.h"
32 #include "opal/util/opal_environ.h"
33 #include "opal/constants.h"
34
35 #define OPAL_DEFAULT_TMPDIR "/tmp"
36
37 /*
38 * Merge two environ-like char arrays, ensuring that there are no
39 * duplicate entires
40 */
41 char **opal_environ_merge(char **minor, char **major)
42 {
43 int i;
44 char **ret = NULL;
45 char *name, *value;
46
47 /* Check for bozo cases */
48
49 if (NULL == major) {
50 if (NULL == minor) {
51 return NULL;
52 } else {
53 return opal_argv_copy(minor);
54 }
55 }
56
57 /* First, copy major */
58
59 ret = opal_argv_copy(major);
60
61 /* Do we have something in minor? */
62
63 if (NULL == minor) {
64 return ret;
65 }
66
67 /* Now go through minor and call opal_setenv(), but with overwrite
68 as false */
69
70 for (i = 0; NULL != minor[i]; ++i) {
71 value = strchr(minor[i], '=');
72 if (NULL == value) {
73 opal_setenv(minor[i], NULL, false, &ret);
74 } else {
75
76 /* strdup minor[i] in case it's a constat string */
77
78 name = strdup(minor[i]);
79 value = name + (value - minor[i]);
80 *value = '\0';
81 opal_setenv(name, value + 1, false, &ret);
82 free(name);
83 }
84 }
85
86 /* All done */
87
88 return ret;
89 }
90
91 /*
92 * Portable version of setenv(), allowing editing of any environ-like
93 * array
94 */
95 int opal_setenv(const char *name, const char *value, bool overwrite,
96 char ***env)
97 {
98 int i;
99 char *newvalue, *compare;
100 size_t len;
101
102 /* Make the new value */
103
104 if (NULL == value) {
105 value = "";
106 opal_asprintf(&newvalue, "%s=", name);
107 } else {
108 opal_asprintf(&newvalue, "%s=%s", name, value);
109 }
110 if (NULL == newvalue) {
111 return OPAL_ERR_OUT_OF_RESOURCE;
112 }
113
114 /* Check the bozo case */
115
116 if( NULL == env ) {
117 return OPAL_ERR_BAD_PARAM;
118 } else if (NULL == *env) {
119 i = 0;
120 opal_argv_append(&i, env, newvalue);
121 free(newvalue);
122 return OPAL_SUCCESS;
123 }
124
125 /* If this is the "environ" array, use putenv */
126 if( *env == environ ) {
127 /* THIS IS POTENTIALLY A MEMORY LEAK! But I am doing it
128 so that we don't violate the law of least
129 astonishment for OPAL developers (i.e., those that don't
130 check the return code of opal_setenv() and notice that we
131 returned an error if you passed in the real environ) */
132 #if defined (HAVE_SETENV)
133 setenv(name, value, overwrite);
134 /* setenv copies the value, so we can free it here */
135 free(newvalue);
136 #else
137 len = strlen(name);
138 for (i = 0; (*env)[i] != NULL; ++i) {
139 if (0 == strncmp((*env)[i], name, len)) {
140 /* if we find the value in the environ, then
141 * we need to check the overwrite flag to determine
142 * the correct response */
143 if (overwrite) {
144 /* since it was okay to overwrite, do so */
145 putenv(newvalue);
146 /* putenv does NOT copy the value, so we
147 * cannot free it here */
148 return OPAL_SUCCESS;
149 }
150 /* since overwrite was not allowed, we return
151 * an error as we cannot perform the requested action */
152 free(newvalue);
153 return OPAL_EXISTS;
154 }
155 }
156 /* since the value wasn't found, we can add it */
157 putenv(newvalue);
158 /* putenv does NOT copy the value, so we
159 * cannot free it here */
160 #endif
161 return OPAL_SUCCESS;
162 }
163
164 /* Make something easy to compare to */
165
166 opal_asprintf(&compare, "%s=", name);
167 if (NULL == compare) {
168 free(newvalue);
169 return OPAL_ERR_OUT_OF_RESOURCE;
170 }
171 len = strlen(compare);
172
173 /* Look for a duplicate that's already set in the env */
174
175 for (i = 0; (*env)[i] != NULL; ++i) {
176 if (0 == strncmp((*env)[i], compare, len)) {
177 if (overwrite) {
178 free((*env)[i]);
179 (*env)[i] = newvalue;
180 free(compare);
181 return OPAL_SUCCESS;
182 } else {
183 free(compare);
184 free(newvalue);
185 return OPAL_EXISTS;
186 }
187 }
188 }
189
190 /* If we found no match, append this value */
191
192 i = opal_argv_count(*env);
193 opal_argv_append(&i, env, newvalue);
194
195 /* All done */
196
197 free(compare);
198 free(newvalue);
199 return OPAL_SUCCESS;
200 }
201
202
203 /*
204 * Portable version of unsetenv(), allowing editing of any
205 * environ-like array
206 */
207 int opal_unsetenv(const char *name, char ***env)
208 {
209 int i;
210 char *compare;
211 size_t len;
212 bool found;
213
214 /* Check for bozo case */
215
216 if (NULL == *env) {
217 return OPAL_SUCCESS;
218 }
219
220 /* Make something easy to compare to */
221
222 opal_asprintf(&compare, "%s=", name);
223 if (NULL == compare) {
224 return OPAL_ERR_OUT_OF_RESOURCE;
225 }
226 len = strlen(compare);
227
228 /* Look for a duplicate that's already set in the env. If we find
229 it, free it, and then start shifting all elements down one in
230 the array. */
231
232 found = false;
233 for (i = 0; (*env)[i] != NULL; ++i) {
234 if (0 != strncmp((*env)[i], compare, len))
235 continue;
236 if (environ != *env) {
237 free((*env)[i]);
238 }
239 for (; (*env)[i] != NULL; ++i)
240 (*env)[i] = (*env)[i + 1];
241 found = true;
242 break;
243 }
244 free(compare);
245
246 /* All done */
247
248 return (found) ? OPAL_SUCCESS : OPAL_ERR_NOT_FOUND;
249 }
250
251 const char* opal_tmp_directory( void )
252 {
253 const char* str;
254
255 if( NULL == (str = getenv("TMPDIR")) )
256 if( NULL == (str = getenv("TEMP")) )
257 if( NULL == (str = getenv("TMP")) )
258 str = OPAL_DEFAULT_TMPDIR;
259 return str;
260 }
261
262 const char* opal_home_directory( void )
263 {
264 char* home = getenv("HOME");
265
266 return home;
267 }
268