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