LLVM OpenMP* Runtime Library
kmp_environment.cpp
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 //