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