1 /*
2 * kmp_environment.cpp -- Handle environment variables OS-independently.
3 */
4
5 //===----------------------------------------------------------------------===//
6 //
7 // The LLVM Compiler Infrastructure
8 //
9 // This file is dual licensed under the MIT and the University of Illinois Open
10 // Source Licenses. See LICENSE.txt for details.
11 //
12 //===----------------------------------------------------------------------===//
13
14 /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the
15 act of loading a DLL on Windows* OS makes any user-set environment variables
16 (i.e. with putenv()) unavailable. getenv() apparently gets a clean copy of
17 the env variables as they existed at the start of the run. JH 12/23/2002
18
19 On Windows* OS, there are two environments (at least, see below):
20
21 1. Environment maintained by Windows* OS on IA-32 architecture. Accessible
22 through GetEnvironmentVariable(), SetEnvironmentVariable(), and
23 GetEnvironmentStrings().
24
25 2. Environment maintained by C RTL. Accessible through getenv(), putenv().
26
27 putenv() function updates both C and Windows* OS on IA-32 architecture.
28 getenv() function search for variables in C RTL environment only.
29 Windows* OS on IA-32 architecture functions work *only* with Windows* OS on
30 IA-32 architecture.
31
32 Windows* OS on IA-32 architecture maintained by OS, so there is always only
33 one Windows* OS on IA-32 architecture per process. Changes in Windows* OS on
34 IA-32 architecture are process-visible.
35
36 C environment maintained by C RTL. Multiple copies of C RTL may be present
37 in the process, and each C RTL maintains its own environment. :-(
38
39 Thus, proper way to work with environment on Windows* OS is:
40
41 1. Set variables with putenv() function -- both C and Windows* OS on IA-32
42 architecture are being updated. Windows* OS on IA-32 architecture may be
43 considered primary target, while updating C RTL environment is free bonus.
44
45 2. Get variables with GetEnvironmentVariable() -- getenv() does not
46 search Windows* OS on IA-32 architecture, and can not see variables
47 set with SetEnvironmentVariable().
48
49 2007-04-05 -- lev
50 */
51
52 #include "kmp_environment.h"
53
54 #include "kmp.h" //
55 #include "kmp_i18n.h"
56 #include "kmp_os.h" // KMP_OS_*.
57 #include "kmp_str.h" // __kmp_str_*().
58
59 #if KMP_OS_UNIX
60 #include <stdlib.h> // getenv, setenv, unsetenv.
61 #include <string.h> // strlen, strcpy.
62 #if KMP_OS_DARWIN
63 #include <crt_externs.h>
64 #define environ (*_NSGetEnviron())
65 #else
66 extern char **environ;
67 #endif
68 #elif KMP_OS_WINDOWS
69 #include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable,
70 // GetLastError.
71 #else
72 #error Unknown or unsupported OS.
73 #endif
74
75 // TODO: Eliminate direct memory allocations, use string operations instead.
76
allocate(size_t size)77 static inline void *allocate(size_t size) {
78 void *ptr = KMP_INTERNAL_MALLOC(size);
79 if (ptr == NULL) {
80 KMP_FATAL(MemoryAllocFailed);
81 }
82 return ptr;
83 } // allocate
84
__kmp_env_get(char const * name)85 char *__kmp_env_get(char const *name) {
86
87 char *result = NULL;
88
89 #if KMP_OS_UNIX
90 char const *value = getenv(name);
91 if (value != NULL) {
92 size_t len = KMP_STRLEN(value) + 1;
93 result = (char *)KMP_INTERNAL_MALLOC(len);
94 if (result == NULL) {
95 KMP_FATAL(MemoryAllocFailed);
96 }
97 KMP_STRNCPY_S(result, len, value, len);
98 }
99 #elif KMP_OS_WINDOWS
100 /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the
101 act of loading a DLL on Windows* OS makes any user-set environment
102 variables (i.e. with putenv()) unavailable. getenv() apparently gets a
103 clean copy of the env variables as they existed at the start of the run.
104 JH 12/23/2002 */
105 DWORD rc;
106 rc = GetEnvironmentVariable(name, NULL, 0);
107 if (!rc) {
108 DWORD error = GetLastError();
109 if (error != ERROR_ENVVAR_NOT_FOUND) {
110 __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
111 }
112 // Variable is not found, it's ok, just continue.
113 } else {
114 DWORD len = rc;
115 result = (char *)KMP_INTERNAL_MALLOC(len);
116 if (result == NULL) {
117 KMP_FATAL(MemoryAllocFailed);
118 }
119 rc = GetEnvironmentVariable(name, result, len);
120 if (!rc) {
121 // GetEnvironmentVariable() may return 0 if variable is empty.
122 // In such a case GetLastError() returns ERROR_SUCCESS.
123 DWORD error = GetLastError();
124 if (error != ERROR_SUCCESS) {
125 // Unexpected error. The variable should be in the environment,
126 // and buffer should be large enough.
127 __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error),
128 __kmp_msg_null);
129 KMP_INTERNAL_FREE((void *)result);
130 result = NULL;
131 }
132 }
133 }
134 #else
135 #error Unknown or unsupported OS.
136 #endif
137
138 return result;
139
140 } // func __kmp_env_get
141
142 // TODO: Find and replace all regular free() with __kmp_env_free().
143
__kmp_env_free(char const ** value)144 void __kmp_env_free(char const **value) {
145
146 KMP_DEBUG_ASSERT(value != NULL);
147 KMP_INTERNAL_FREE(CCAST(char *, *value));
148 *value = NULL;
149
150 } // func __kmp_env_free
151
__kmp_env_exists(char const * name)152 int __kmp_env_exists(char const *name) {
153
154 #if KMP_OS_UNIX
155 char const *value = getenv(name);
156 return ((value == NULL) ? (0) : (1));
157 #elif KMP_OS_WINDOWS
158 DWORD rc;
159 rc = GetEnvironmentVariable(name, NULL, 0);
160 if (rc == 0) {
161 DWORD error = GetLastError();
162 if (error != ERROR_ENVVAR_NOT_FOUND) {
163 __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
164 }
165 return 0;
166 }
167 return 1;
168 #else
169 #error Unknown or unsupported OS.
170 #endif
171
172 } // func __kmp_env_exists
173
__kmp_env_set(char const * name,char const * value,int overwrite)174 void __kmp_env_set(char const *name, char const *value, int overwrite) {
175
176 #if KMP_OS_UNIX
177 int rc = setenv(name, value, overwrite);
178 if (rc != 0) {
179 // Dead code. I tried to put too many variables into Linux* OS
180 // environment on IA-32 architecture. When application consumes
181 // more than ~2.5 GB of memory, entire system feels bad. Sometimes
182 // application is killed (by OS?), sometimes system stops
183 // responding... But this error message never appears. --ln
184 __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_HNT(NotEnoughMemory),
185 __kmp_msg_null);
186 }
187 #elif KMP_OS_WINDOWS
188 BOOL rc;
189 if (!overwrite) {
190 rc = GetEnvironmentVariable(name, NULL, 0);
191 if (rc) {
192 // Variable exists, do not overwrite.
193 return;
194 }
195 DWORD error = GetLastError();
196 if (error != ERROR_ENVVAR_NOT_FOUND) {
197 __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
198 }
199 }
200 rc = SetEnvironmentVariable(name, value);
201 if (!rc) {
202 DWORD error = GetLastError();
203 __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
204 }
205 #else
206 #error Unknown or unsupported OS.
207 #endif
208
209 } // func __kmp_env_set
210
__kmp_env_unset(char const * name)211 void __kmp_env_unset(char const *name) {
212
213 #if KMP_OS_UNIX
214 unsetenv(name);
215 #elif KMP_OS_WINDOWS
216 BOOL rc = SetEnvironmentVariable(name, NULL);
217 if (!rc) {
218 DWORD error = GetLastError();
219 __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
220 }
221 #else
222 #error Unknown or unsupported OS.
223 #endif
224
225 } // func __kmp_env_unset
226
227 /* Intel OpenMP RTL string representation of environment: just a string of
228 characters, variables are separated with vertical bars, e. g.:
229
230 "KMP_WARNINGS=0|KMP_AFFINITY=compact|"
231
232 Empty variables are allowed and ignored:
233
234 "||KMP_WARNINGS=1||"
235 */
236
237 static void
___kmp_env_blk_parse_string(kmp_env_blk_t * block,char const * env)238 ___kmp_env_blk_parse_string(kmp_env_blk_t *block, // M: Env block to fill.
239 char const *env // I: String to parse.
240 ) {
241
242 char const chr_delimiter = '|';
243 char const str_delimiter[] = {chr_delimiter, 0};
244
245 char *bulk = NULL;
246 kmp_env_var_t *vars = NULL;
247 int count = 0; // Number of used elements in vars array.
248 int delimiters = 0; // Number of delimiters in input string.
249
250 // Copy original string, we will modify the copy.
251 bulk = __kmp_str_format("%s", env);
252
253 // Loop thru all the vars in environment block. Count delimiters (maximum
254 // number of variables is number of delimiters plus one).
255 {
256 char const *ptr = bulk;
257 for (;;) {
258 ptr = strchr(ptr, chr_delimiter);
259 if (ptr == NULL) {
260 break;
261 }
262 ++delimiters;
263 ptr += 1;
264 }
265 }
266
267 // Allocate vars array.
268 vars = (kmp_env_var_t *)allocate((delimiters + 1) * sizeof(kmp_env_var_t));
269
270 // Loop thru all the variables.
271 {
272 char *var; // Pointer to variable (both name and value).
273 char *name; // Pointer to name of variable.
274 char *value; // Pointer to value.
275 char *buf; // Buffer for __kmp_str_token() function.
276 var = __kmp_str_token(bulk, str_delimiter, &buf); // Get the first var.
277 while (var != NULL) {
278 // Save found variable in vars array.
279 __kmp_str_split(var, '=', &name, &value);
280 KMP_DEBUG_ASSERT(count < delimiters + 1);
281 vars[count].name = name;
282 vars[count].value = value;
283 ++count;
284 // Get the next var.
285 var = __kmp_str_token(NULL, str_delimiter, &buf);
286 }
287 }
288
289 // Fill out result.
290 block->bulk = bulk;
291 block->vars = vars;
292 block->count = count;
293 }
294
295 /* Windows* OS (actually, DOS) environment block is a piece of memory with
296 environment variables. Each variable is terminated with zero byte, entire
297 block is terminated with one extra zero byte, so we have two zero bytes at
298 the end of environment block, e. g.:
299
300 "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
301
302 It is not clear how empty environment is represented. "\x00\x00"?
303 */
304
305 #if KMP_OS_WINDOWS
___kmp_env_blk_parse_windows(kmp_env_blk_t * block,char const * env)306 static void ___kmp_env_blk_parse_windows(
307 kmp_env_blk_t *block, // M: Env block to fill.
308 char const *env // I: Pointer to Windows* OS (DOS) environment block.
309 ) {
310
311 char *bulk = NULL;
312 kmp_env_var_t *vars = NULL;
313 int count = 0; // Number of used elements in vars array.
314 int size = 0; // Size of bulk.
315
316 char *name; // Pointer to name of variable.
317 char *value; // Pointer to value.
318
319 if (env != NULL) {
320
321 // Loop thru all the vars in environment block. Count variables, find size
322 // of block.
323 {
324 char const *var; // Pointer to beginning of var.
325 int len; // Length of variable.
326 count = 0;
327 var =
328 env; // The first variable starts and beginning of environment block.
329 len = KMP_STRLEN(var);
330 while (len != 0) {
331 ++count;
332 size = size + len + 1;
333 var = var + len +
334 1; // Move pointer to the beginning of the next variable.
335 len = KMP_STRLEN(var);
336 }
337 size =
338 size + 1; // Total size of env block, including terminating zero byte.
339 }
340
341 // Copy original block to bulk, we will modify bulk, not original block.
342 bulk = (char *)allocate(size);
343 KMP_MEMCPY_S(bulk, size, env, size);
344 // Allocate vars array.
345 vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
346
347 // Loop thru all the vars, now in bulk.
348 {
349 char *var; // Pointer to beginning of var.
350 int len; // Length of variable.
351 count = 0;
352 var = bulk;
353 len = KMP_STRLEN(var);
354 while (len != 0) {
355 // Save variable in vars array.
356 __kmp_str_split(var, '=', &name, &value);
357 vars[count].name = name;
358 vars[count].value = value;
359 ++count;
360 // Get the next var.
361 var = var + len + 1;
362 len = KMP_STRLEN(var);
363 }
364 }
365 }
366
367 // Fill out result.
368 block->bulk = bulk;
369 block->vars = vars;
370 block->count = count;
371 }
372 #endif
373
374 /* Unix environment block is a array of pointers to variables, last pointer in
375 array is NULL:
376
377 { "HOME=/home/lev", "TERM=xterm", NULL }
378 */
379
380 static void
___kmp_env_blk_parse_unix(kmp_env_blk_t * block,char ** env)381 ___kmp_env_blk_parse_unix(kmp_env_blk_t *block, // M: Env block to fill.
382 char **env // I: Unix environment to parse.
383 ) {
384
385 char *bulk = NULL;
386 kmp_env_var_t *vars = NULL;
387 int count = 0;
388 int size = 0; // Size of bulk.
389
390 // Count number of variables and length of required bulk.
391 {
392 count = 0;
393 size = 0;
394 while (env[count] != NULL) {
395 size += KMP_STRLEN(env[count]) + 1;
396 ++count;
397 }
398 }
399
400 // Allocate memory.
401 bulk = (char *)allocate(size);
402 vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
403
404 // Loop thru all the vars.
405 {
406 char *var; // Pointer to beginning of var.
407 char *name; // Pointer to name of variable.
408 char *value; // Pointer to value.
409 int len; // Length of variable.
410 int i;
411 var = bulk;
412 for (i = 0; i < count; ++i) {
413 // Copy variable to bulk.
414 len = KMP_STRLEN(env[i]);
415 KMP_MEMCPY_S(var, size, env[i], len + 1);
416 // Save found variable in vars array.
417 __kmp_str_split(var, '=', &name, &value);
418 vars[i].name = name;
419 vars[i].value = value;
420 // Move pointer.
421 var += len + 1;
422 }
423 }
424
425 // Fill out result.
426 block->bulk = bulk;
427 block->vars = vars;
428 block->count = count;
429 }
430
__kmp_env_blk_init(kmp_env_blk_t * block,char const * bulk)431 void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize.
432 char const *bulk // I: Initialization string, or NULL.
433 ) {
434
435 if (bulk != NULL) {
436 ___kmp_env_blk_parse_string(block, bulk);
437 } else {
438 #if KMP_OS_UNIX
439 ___kmp_env_blk_parse_unix(block, environ);
440 #elif KMP_OS_WINDOWS
441 {
442 char *mem = GetEnvironmentStrings();
443 if (mem == NULL) {
444 DWORD error = GetLastError();
445 __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error),
446 __kmp_msg_null);
447 }
448 ___kmp_env_blk_parse_windows(block, mem);
449 FreeEnvironmentStrings(mem);
450 }
451 #else
452 #error Unknown or unsupported OS.
453 #endif
454 }
455
456 } // __kmp_env_blk_init
457
___kmp_env_var_cmp(kmp_env_var_t const * lhs,kmp_env_var_t const * rhs)458 static int ___kmp_env_var_cmp( // Comparison function for qsort().
459 kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) {
460 return strcmp(lhs->name, rhs->name);
461 }
462
__kmp_env_blk_sort(kmp_env_blk_t * block)463 void __kmp_env_blk_sort(
464 kmp_env_blk_t *block // M: Block of environment variables to sort.
465 ) {
466
467 qsort(CCAST(kmp_env_var_t *, block->vars), block->count,
468 sizeof(kmp_env_var_t),
469 (int (*)(void const *, void const *)) & ___kmp_env_var_cmp);
470
471 } // __kmp_env_block_sort
472
__kmp_env_blk_free(kmp_env_blk_t * block)473 void __kmp_env_blk_free(
474 kmp_env_blk_t *block // M: Block of environment variables to free.
475 ) {
476
477 KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars));
478 __kmp_str_free(&(block->bulk));
479
480 block->count = 0;
481 block->vars = NULL;
482
483 } // __kmp_env_blk_free
484
485 char const * // R: Value of variable or NULL if variable does not exist.
__kmp_env_blk_var(kmp_env_blk_t * block,char const * name)486 __kmp_env_blk_var(
487 kmp_env_blk_t *block, // I: Block of environment variables.
488 char const *name // I: Name of variable to find.
489 ) {
490
491 int i;
492 for (i = 0; i < block->count; ++i) {
493 if (strcmp(block->vars[i].name, name) == 0) {
494 return block->vars[i].value;
495 }
496 }
497 return NULL;
498
499 } // __kmp_env_block_var
500
501 // end of file //
502