1 /*
2  * kmp_environment.cpp -- Handle environment variables OS-independently.
3  */
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 
26         1. Environment maintained by Windows* OS on IA-32 architecture.
27 	   Accessible through GetEnvironmentVariable(),
28            SetEnvironmentVariable(), and GetEnvironmentStrings().
29 
30         2. Environment maintained by C RTL. Accessible through getenv(), putenv().
31 
32     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*
34     with Windows* OS on IA-32 architecture.
35 
36     Windows* OS on IA-32 architecture maintained by OS, so there is always only one Windows* OS on
37     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
45 	   IA-32 architecture are being updated. Windows* OS on
46 	   IA-32 architecture may be considered as primary target,
47 	   while updating C RTL environment is a free bonus.
48 
49         2. Get variables with GetEnvironmentVariable() -- getenv() does not
50 	   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.
67     #if KMP_OS_DARWIN
68         #include <crt_externs.h>
69         #define environ (*_NSGetEnviron())
70     #else
71         extern char * * environ;
72     #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 
82 static inline
83 void *
84 allocate(
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 
95 char *
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 ) {
103             size_t len = KMP_STRLEN( value ) + 1;
104             result = (char *) KMP_INTERNAL_MALLOC( len );
105             if ( result == NULL ) {
106 		KMP_FATAL( MemoryAllocFailed );
107             }; // if
108             KMP_STRNCPY_S( result, len, value, len );
109         }; // 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 
167 void
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 
178 int
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 
208 void
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
217             // application is killed (by OS?), sometimes system stops
218             // 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 
262 void
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 
298 static
299 void
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 
371 #if KMP_OS_WINDOWS
372 static
373 void
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.
395             len = KMP_STRLEN( var );
396             while ( len != 0 ) {
397                 ++ count;
398                 size = size + len + 1;
399                 var = var + len + 1; // Move pointer to the beginning of the next variable.
400                 len = KMP_STRLEN( var );
401             }; // 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 );
407         KMP_MEMCPY_S( bulk, size, env, size );
408         // 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;
417             len = KMP_STRLEN( var );
418             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;
426                 len = KMP_STRLEN( var );
427             }; // 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
438 #endif
439 
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 
447 static
448 void
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 ) {
464             size += KMP_STRLEN( env[ count ] ) + 1;
465             ++ 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.
483             len = KMP_STRLEN( env[ i ] );
484             KMP_MEMCPY_S( var, size, env[ i ], len + 1 );
485             // 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 
503 void
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 
538 static
539 int
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 
547 void
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 
563 void
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 );
569     __kmp_str_free(&(block->bulk));
570 
571     block->count = 0;
572     block->vars  = NULL;
573 
574 } // __kmp_env_blk_free
575 
576 
577 
578 char 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 //
596