Intel® OpenMP* Runtime Library
 All Classes Functions Variables Typedefs Enumerations Enumerator Modules Pages
kmp_environment.c
1 /*
2  * kmp_environment.c -- Handle environment variables OS-independently.
3  */
4 
5 /* <copyright>
6  Copyright (c) 1997-2015 Intel Corporation. All Rights Reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions
10  are met:
11 
12  * Redistributions of source code must retain the above copyright
13  notice, this list of conditions and the following disclaimer.
14  * Redistributions in binary form must reproduce the above copyright
15  notice, this list of conditions and the following disclaimer in the
16  documentation and/or other materials provided with the distribution.
17  * Neither the name of Intel Corporation nor the names of its
18  contributors may be used to endorse or promote products derived
19  from this software without specific prior written permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 </copyright> */
34 
35 /*
36  ------------------------------------------------------------------------------------------------
37  We use GetEnvironmentVariable for Windows* OS instead of getenv because the act of
38  loading a DLL on Windows* OS makes any user-set environment variables (i.e. with putenv())
39  unavailable. getenv() apparently gets a clean copy of the env variables as they existed
40  at the start of the run.
41  JH 12/23/2002
42  ------------------------------------------------------------------------------------------------
43  On Windows* OS, there are two environments (at least, see below):
44 
45  1. Environment maintained by Windows* OS on IA-32 architecture.
46  Accessible through GetEnvironmentVariable(),
47  SetEnvironmentVariable(), and GetEnvironmentStrings().
48 
49  2. Environment maintained by C RTL. Accessible through getenv(), putenv().
50 
51  putenv() function updates both C and Windows* OS on IA-32 architecture. getenv() function
52  search for variables in C RTL environment only. Windows* OS on IA-32 architecture functions work *only*
53  with Windows* OS on IA-32 architecture.
54 
55  Windows* OS on IA-32 architecture maintained by OS, so there is always only one Windows* OS on
56  IA-32 architecture per process. Changes in Windows* OS on IA-32 architecture are process-visible.
57 
58  C environment maintained by C RTL. Multiple copies of C RTL may be present in the process, and
59  each C RTL maintains its own environment. :-(
60 
61  Thus, proper way to work with environment on Windows* OS is:
62 
63  1. Set variables with putenv() function -- both C and Windows* OS on
64  IA-32 architecture are being updated. Windows* OS on
65  IA-32 architecture may be considered as primary target,
66  while updating C RTL environment is a free bonus.
67 
68  2. Get variables with GetEnvironmentVariable() -- getenv() does not
69  search Windows* OS on IA-32 architecture, and can not see variables
70  set with SetEnvironmentVariable().
71 
72  2007-04-05 -- lev
73  ------------------------------------------------------------------------------------------------
74 */
75 
76 #include "kmp_environment.h"
77 
78 #include "kmp_os.h" // KMP_OS_*.
79 #include "kmp.h" //
80 #include "kmp_str.h" // __kmp_str_*().
81 #include "kmp_i18n.h"
82 
83 #if KMP_OS_UNIX
84  #include <stdlib.h> // getenv, setenv, unsetenv.
85  #include <string.h> // strlen, strcpy.
86  #if KMP_OS_LINUX || KMP_OS_FREEBSD
87  extern char * * environ;
88  #elif KMP_OS_DARWIN
89  #include <crt_externs.h>
90  #define environ (*_NSGetEnviron())
91  #else
92  #error Unknown or unsupported OS.
93  #endif
94 #elif KMP_OS_WINDOWS
95  #include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable, GetLastError.
96 #else
97  #error Unknown or unsupported OS.
98 #endif
99 
100 
101 // TODO: Eliminate direct memory allocations, use string operations instead.
102 
103 static inline
104 void *
105 allocate(
106  size_t size
107 ) {
108  void * ptr = KMP_INTERNAL_MALLOC( size );
109  if ( ptr == NULL ) {
110  KMP_FATAL( MemoryAllocFailed );
111  }; // if
112  return ptr;
113 } // allocate
114 
115 
116 char *
117 __kmp_env_get( char const * name ) {
118 
119  char * result = NULL;
120 
121  #if KMP_OS_UNIX
122  char const * value = getenv( name );
123  if ( value != NULL ) {
124  size_t len = KMP_STRLEN( value ) + 1;
125  result = (char *) KMP_INTERNAL_MALLOC( len );
126  if ( result == NULL ) {
127  KMP_FATAL( MemoryAllocFailed );
128  }; // if
129  KMP_STRNCPY_S( result, len, value, len );
130  }; // if
131  #elif KMP_OS_WINDOWS
132  /*
133  We use GetEnvironmentVariable for Windows* OS instead of getenv because the act of
134  loading a DLL on Windows* OS makes any user-set environment variables (i.e. with putenv())
135  unavailable. getenv() apparently gets a clean copy of the env variables as they existed
136  at the start of the run.
137  JH 12/23/2002
138  */
139  DWORD rc;
140  rc = GetEnvironmentVariable( name, NULL, 0 );
141  if ( ! rc ) {
142  DWORD error = GetLastError();
143  if ( error != ERROR_ENVVAR_NOT_FOUND ) {
144  __kmp_msg(
145  kmp_ms_fatal,
146  KMP_MSG( CantGetEnvVar, name ),
147  KMP_ERR( error ),
148  __kmp_msg_null
149  );
150  }; // if
151  // Variable is not found, it's ok, just continue.
152  } else {
153  DWORD len = rc;
154  result = (char *) KMP_INTERNAL_MALLOC( len );
155  if ( result == NULL ) {
156  KMP_FATAL( MemoryAllocFailed );
157  }; // if
158  rc = GetEnvironmentVariable( name, result, len );
159  if ( ! rc ) {
160  // GetEnvironmentVariable() may return 0 if variable is empty.
161  // In such a case GetLastError() returns ERROR_SUCCESS.
162  DWORD error = GetLastError();
163  if ( error != ERROR_SUCCESS ) {
164  // Unexpected error. The variable should be in the environment,
165  // and buffer should be large enough.
166  __kmp_msg(
167  kmp_ms_fatal,
168  KMP_MSG( CantGetEnvVar, name ),
169  KMP_ERR( error ),
170  __kmp_msg_null
171  );
172  KMP_INTERNAL_FREE( (void *) result );
173  result = NULL;
174  }; // if
175  }; // if
176  }; // if
177  #else
178  #error Unknown or unsupported OS.
179  #endif
180 
181  return result;
182 
183 } // func __kmp_env_get
184 
185 
186 // TODO: Find and replace all regular free() with __kmp_env_free().
187 
188 void
189 __kmp_env_free( char const * * value ) {
190 
191  KMP_DEBUG_ASSERT( value != NULL );
192  KMP_INTERNAL_FREE( (void *) * value );
193  * value = NULL;
194 
195 } // func __kmp_env_free
196 
197 
198 
199 int
200 __kmp_env_exists( char const * name ) {
201 
202  #if KMP_OS_UNIX
203  char const * value = getenv( name );
204  return ( ( value == NULL ) ? ( 0 ) : ( 1 ) );
205  #elif KMP_OS_WINDOWS
206  DWORD rc;
207  rc = GetEnvironmentVariable( name, NULL, 0 );
208  if ( rc == 0 ) {
209  DWORD error = GetLastError();
210  if ( error != ERROR_ENVVAR_NOT_FOUND ) {
211  __kmp_msg(
212  kmp_ms_fatal,
213  KMP_MSG( CantGetEnvVar, name ),
214  KMP_ERR( error ),
215  __kmp_msg_null
216  );
217  }; // if
218  return 0;
219  }; // if
220  return 1;
221  #else
222  #error Unknown or unsupported OS.
223  #endif
224 
225 } // func __kmp_env_exists
226 
227 
228 
229 void
230 __kmp_env_set( char const * name, char const * value, int overwrite ) {
231 
232  #if KMP_OS_UNIX
233  int rc = setenv( name, value, overwrite );
234  if ( rc != 0 ) {
235  // Dead code. I tried to put too many variables into Linux* OS
236  // environment on IA-32 architecture. When application consumes
237  // more than ~2.5 GB of memory, entire system feels bad. Sometimes
238  // application is killed (by OS?), sometimes system stops
239  // responding... But this error message never appears. --ln
240  __kmp_msg(
241  kmp_ms_fatal,
242  KMP_MSG( CantSetEnvVar, name ),
243  KMP_HNT( NotEnoughMemory ),
244  __kmp_msg_null
245  );
246  }; // if
247  #elif KMP_OS_WINDOWS
248  BOOL rc;
249  if ( ! overwrite ) {
250  rc = GetEnvironmentVariable( name, NULL, 0 );
251  if ( rc ) {
252  // Variable exists, do not overwrite.
253  return;
254  }; // if
255  DWORD error = GetLastError();
256  if ( error != ERROR_ENVVAR_NOT_FOUND ) {
257  __kmp_msg(
258  kmp_ms_fatal,
259  KMP_MSG( CantGetEnvVar, name ),
260  KMP_ERR( error ),
261  __kmp_msg_null
262  );
263  }; // if
264  }; // if
265  rc = SetEnvironmentVariable( name, value );
266  if ( ! rc ) {
267  DWORD error = GetLastError();
268  __kmp_msg(
269  kmp_ms_fatal,
270  KMP_MSG( CantSetEnvVar, name ),
271  KMP_ERR( error ),
272  __kmp_msg_null
273  );
274  }; // if
275  #else
276  #error Unknown or unsupported OS.
277  #endif
278 
279 } // func __kmp_env_set
280 
281 
282 
283 void
284 __kmp_env_unset( char const * name ) {
285 
286  #if KMP_OS_UNIX
287  unsetenv( name );
288  #elif KMP_OS_WINDOWS
289  BOOL rc = SetEnvironmentVariable( name, NULL );
290  if ( ! rc ) {
291  DWORD error = GetLastError();
292  __kmp_msg(
293  kmp_ms_fatal,
294  KMP_MSG( CantSetEnvVar, name ),
295  KMP_ERR( error ),
296  __kmp_msg_null
297  );
298  }; // if
299  #else
300  #error Unknown or unsupported OS.
301  #endif
302 
303 } // func __kmp_env_unset
304 
305 // -------------------------------------------------------------------------------------------------
306 
307 /*
308  Intel OpenMP RTL string representation of environment: just a string of characters, variables
309  are separated with vertical bars, e. g.:
310 
311  "KMP_WARNINGS=0|KMP_AFFINITY=compact|"
312 
313  Empty variables are allowed and ignored:
314 
315  "||KMP_WARNINGS=1||"
316 
317 */
318 
319 static
320 void
321 ___kmp_env_blk_parse_string(
322  kmp_env_blk_t * block, // M: Env block to fill.
323  char const * env // I: String to parse.
324 ) {
325 
326  char const chr_delimiter = '|';
327  char const str_delimiter[] = { chr_delimiter, 0 };
328 
329  char * bulk = NULL;
330  kmp_env_var_t * vars = NULL;
331  int count = 0; // Number of used elements in vars array.
332  int delimiters = 0; // Number of delimiters in input string.
333 
334  // Copy original string, we will modify the copy.
335  bulk = __kmp_str_format( "%s", env );
336 
337  // Loop thru all the vars in environment block. Count delimiters (maximum number of variables
338  // is number of delimiters plus one).
339  {
340  char const * ptr = bulk;
341  for ( ; ; ) {
342  ptr = strchr( ptr, chr_delimiter );
343  if ( ptr == NULL ) {
344  break;
345  }; // if
346  ++ delimiters;
347  ptr += 1;
348  }; // forever
349  }
350 
351  // Allocate vars array.
352  vars = (kmp_env_var_t *) allocate( ( delimiters + 1 ) * sizeof( kmp_env_var_t ) );
353 
354  // Loop thru all the variables.
355  {
356  char * var; // Pointer to variable (both name and value).
357  char * name; // Pointer to name of variable.
358  char * value; // Pointer to value.
359  char * buf; // Buffer for __kmp_str_token() function.
360  var = __kmp_str_token( bulk, str_delimiter, & buf ); // Get the first var.
361  while ( var != NULL ) {
362  // Save found variable in vars array.
363  __kmp_str_split( var, '=', & name, & value );
364  KMP_DEBUG_ASSERT( count < delimiters + 1 );
365  vars[ count ].name = name;
366  vars[ count ].value = value;
367  ++ count;
368  // Get the next var.
369  var = __kmp_str_token( NULL, str_delimiter, & buf );
370  }; // while
371  }
372 
373  // Fill out result.
374  block->bulk = bulk;
375  block->vars = vars;
376  block->count = count;
377 
378 }; // ___kmp_env_blk_parse_string
379 
380 
381 
382 /*
383  Windows* OS (actually, DOS) environment block is a piece of memory with environment variables. Each
384  variable is terminated with zero byte, entire block is terminated with one extra zero byte, so
385  we have two zero bytes at the end of environment block, e. g.:
386 
387  "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
388 
389  It is not clear how empty environment is represented. "\x00\x00"?
390 */
391 
392 static
393 void
394 ___kmp_env_blk_parse_windows(
395  kmp_env_blk_t * block, // M: Env block to fill.
396  char const * env // I: Pointer to Windows* OS (DOS) environment block.
397 ) {
398 
399  char * bulk = NULL;
400  kmp_env_var_t * vars = NULL;
401  int count = 0; // Number of used elements in vars array.
402  int size = 0; // Size of bulk.
403 
404  char * name; // Pointer to name of variable.
405  char * value; // Pointer to value.
406 
407  if ( env != NULL ) {
408 
409  // Loop thru all the vars in environment block. Count variables, find size of block.
410  {
411  char const * var; // Pointer to beginning of var.
412  int len; // Length of variable.
413  count = 0;
414  var = env; // The first variable starts and beginning of environment block.
415  len = KMP_STRLEN( var );
416  while ( len != 0 ) {
417  ++ count;
418  size = size + len + 1;
419  var = var + len + 1; // Move pointer to the beginning of the next variable.
420  len = KMP_STRLEN( var );
421  }; // while
422  size = size + 1; // Total size of env block, including terminating zero byte.
423  }
424 
425  // Copy original block to bulk, we will modify bulk, not original block.
426  bulk = (char *) allocate( size );
427  KMP_MEMCPY_S( bulk, size, env, size );
428  // Allocate vars array.
429  vars = (kmp_env_var_t *) allocate( count * sizeof( kmp_env_var_t ) );
430 
431  // Loop thru all the vars, now in bulk.
432  {
433  char * var; // Pointer to beginning of var.
434  int len; // Length of variable.
435  count = 0;
436  var = bulk;
437  len = KMP_STRLEN( var );
438  while ( len != 0 ) {
439  // Save variable in vars array.
440  __kmp_str_split( var, '=', & name, & value );
441  vars[ count ].name = name;
442  vars[ count ].value = value;
443  ++ count;
444  // Get the next var.
445  var = var + len + 1;
446  len = KMP_STRLEN( var );
447  }; // while
448  }
449 
450  }; // if
451 
452  // Fill out result.
453  block->bulk = bulk;
454  block->vars = vars;
455  block->count = count;
456 
457 }; // ___kmp_env_blk_parse_windows
458 
459 
460 
461 /*
462  Unix environment block is a array of pointers to variables, last pointer in array is NULL:
463 
464  { "HOME=/home/lev", "TERM=xterm", NULL }
465 */
466 
467 static
468 void
469 ___kmp_env_blk_parse_unix(
470  kmp_env_blk_t * block, // M: Env block to fill.
471  char * * env // I: Unix environment to parse.
472 ) {
473 
474  char * bulk = NULL;
475  kmp_env_var_t * vars = NULL;
476  int count = 0;
477  int size = 0; // Size of bulk.
478 
479  // Count number of variables and length of required bulk.
480  {
481  count = 0;
482  size = 0;
483  while ( env[ count ] != NULL ) {
484  size += KMP_STRLEN( env[ count ] ) + 1;
485  ++ count;
486  }; // while
487  }
488 
489  // Allocate memory.
490  bulk = (char *) allocate( size );
491  vars = (kmp_env_var_t *) allocate( count * sizeof( kmp_env_var_t ) );
492 
493  // Loop thru all the vars.
494  {
495  char * var; // Pointer to beginning of var.
496  char * name; // Pointer to name of variable.
497  char * value; // Pointer to value.
498  int len; // Length of variable.
499  int i;
500  var = bulk;
501  for ( i = 0; i < count; ++ i ) {
502  // Copy variable to bulk.
503  len = KMP_STRLEN( env[ i ] );
504  KMP_MEMCPY_S( var, size, env[ i ], len + 1 );
505  // Save found variable in vars array.
506  __kmp_str_split( var, '=', & name, & value );
507  vars[ i ].name = name;
508  vars[ i ].value = value;
509  // Move pointer.
510  var += len + 1;
511  }; // for
512  }
513 
514  // Fill out result.
515  block->bulk = bulk;
516  block->vars = vars;
517  block->count = count;
518 
519 }; // ___kmp_env_blk_parse_unix
520 
521 
522 
523 void
524 __kmp_env_blk_init(
525  kmp_env_blk_t * block, // M: Block to initialize.
526  char const * bulk // I: Initialization string, or NULL.
527 ) {
528 
529  if ( bulk != NULL ) {
530  ___kmp_env_blk_parse_string( block, bulk );
531  } else {
532  #if KMP_OS_UNIX
533  ___kmp_env_blk_parse_unix( block, environ );
534  #elif KMP_OS_WINDOWS
535  {
536  char * mem = GetEnvironmentStrings();
537  if ( mem == NULL ) {
538  DWORD error = GetLastError();
539  __kmp_msg(
540  kmp_ms_fatal,
541  KMP_MSG( CantGetEnvironment ),
542  KMP_ERR( error ),
543  __kmp_msg_null
544  );
545  }; // if
546  ___kmp_env_blk_parse_windows( block, mem );
547  FreeEnvironmentStrings( mem );
548  }
549  #else
550  #error Unknown or unsupported OS.
551  #endif
552  }; // if
553 
554 } // __kmp_env_blk_init
555 
556 
557 
558 static
559 int
560 ___kmp_env_var_cmp( // Comparison function for qsort().
561  kmp_env_var_t const * lhs,
562  kmp_env_var_t const * rhs
563 ) {
564  return strcmp( lhs->name, rhs->name );
565 }
566 
567 void
568 __kmp_env_blk_sort(
569  kmp_env_blk_t * block // M: Block of environment variables to sort.
570 ) {
571 
572  qsort(
573  (void *) block->vars,
574  block->count,
575  sizeof( kmp_env_var_t ),
576  ( int ( * )( void const *, void const * ) ) & ___kmp_env_var_cmp
577  );
578 
579 } // __kmp_env_block_sort
580 
581 
582 
583 void
584 __kmp_env_blk_free(
585  kmp_env_blk_t * block // M: Block of environment variables to free.
586 ) {
587 
588  KMP_INTERNAL_FREE( (void *) block->vars );
589  KMP_INTERNAL_FREE( (void *) block->bulk );
590 
591  block->count = 0;
592  block->vars = NULL;
593  block->bulk = NULL;
594 
595 } // __kmp_env_blk_free
596 
597 
598 
599 char const * // R: Value of variable or NULL if variable does not exist.
600 __kmp_env_blk_var(
601  kmp_env_blk_t * block, // I: Block of environment variables.
602  char const * name // I: Name of variable to find.
603 ) {
604 
605  int i;
606  for ( i = 0; i < block->count; ++ i ) {
607  if ( strcmp( block->vars[ i ].name, name ) == 0 ) {
608  return block->vars[ i ].value;
609  }; // if
610  }; // for
611  return NULL;
612 
613 } // __kmp_env_block_var
614 
615 
616 // end of file //