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