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 /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the 17 act of loading a DLL on Windows* OS makes any user-set environment variables 18 (i.e. with putenv()) unavailable. getenv() apparently gets a clean copy of 19 the env variables as they existed at the start of the run. JH 12/23/2002 20 21 On Windows* OS, there are two environments (at least, see below): 22 23 1. Environment maintained by Windows* OS on IA-32 architecture. Accessible 24 through GetEnvironmentVariable(), SetEnvironmentVariable(), and 25 GetEnvironmentStrings(). 26 27 2. Environment maintained by C RTL. Accessible through getenv(), putenv(). 28 29 putenv() function updates both C and Windows* OS on IA-32 architecture. 30 getenv() function search for variables in C RTL environment only. 31 Windows* OS on IA-32 architecture functions work *only* with Windows* OS on 32 IA-32 architecture. 33 34 Windows* OS on IA-32 architecture maintained by OS, so there is always only 35 one Windows* OS on IA-32 architecture per process. Changes in Windows* OS on 36 IA-32 architecture are process-visible. 37 38 C environment maintained by C RTL. Multiple copies of C RTL may be present 39 in the process, and each C RTL maintains its own environment. :-( 40 41 Thus, proper way to work with environment on Windows* OS is: 42 43 1. Set variables with putenv() function -- both C and Windows* OS on IA-32 44 architecture are being updated. Windows* OS on IA-32 architecture may be 45 considered primary target, while updating C RTL environment is free bonus. 46 47 2. Get variables with GetEnvironmentVariable() -- getenv() does not 48 search Windows* OS on IA-32 architecture, and can not see variables 49 set with SetEnvironmentVariable(). 50 51 2007-04-05 -- lev 52 */ 53 54 #include "kmp_environment.h" 55 56 #include "kmp.h" // 57 #include "kmp_i18n.h" 58 #include "kmp_os.h" // KMP_OS_*. 59 #include "kmp_str.h" // __kmp_str_*(). 60 61 #if KMP_OS_UNIX 62 #include <stdlib.h> // getenv, setenv, unsetenv. 63 #include <string.h> // strlen, strcpy. 64 #if KMP_OS_DARWIN 65 #include <crt_externs.h> 66 #define environ (*_NSGetEnviron()) 67 #else 68 extern char **environ; 69 #endif 70 #elif KMP_OS_WINDOWS 71 #include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable, 72 // GetLastError. 73 #else 74 #error Unknown or unsupported OS. 75 #endif 76 77 // TODO: Eliminate direct memory allocations, use string operations instead. 78 79 static inline void *allocate(size_t size) { 80 void *ptr = KMP_INTERNAL_MALLOC(size); 81 if (ptr == NULL) { 82 KMP_FATAL(MemoryAllocFailed); 83 }; // if 84 return ptr; 85 } // allocate 86 87 char *__kmp_env_get(char const *name) { 88 89 char *result = NULL; 90 91 #if KMP_OS_UNIX 92 char const *value = getenv(name); 93 if (value != NULL) { 94 size_t len = KMP_STRLEN(value) + 1; 95 result = (char *)KMP_INTERNAL_MALLOC(len); 96 if (result == NULL) { 97 KMP_FATAL(MemoryAllocFailed); 98 }; // if 99 KMP_STRNCPY_S(result, len, value, len); 100 }; // if 101 #elif KMP_OS_WINDOWS 102 /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the 103 act of loading a DLL on Windows* OS makes any user-set environment 104 variables (i.e. with putenv()) unavailable. getenv() apparently gets a 105 clean copy of the env variables as they existed at the start of the run. 106 JH 12/23/2002 */ 107 DWORD rc; 108 rc = GetEnvironmentVariable(name, NULL, 0); 109 if (!rc) { 110 DWORD error = GetLastError(); 111 if (error != ERROR_ENVVAR_NOT_FOUND) { 112 __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 113 }; // if 114 // Variable is not found, it's ok, just continue. 115 } else { 116 DWORD len = rc; 117 result = (char *)KMP_INTERNAL_MALLOC(len); 118 if (result == NULL) { 119 KMP_FATAL(MemoryAllocFailed); 120 }; // if 121 rc = GetEnvironmentVariable(name, result, len); 122 if (!rc) { 123 // GetEnvironmentVariable() may return 0 if variable is empty. 124 // In such a case GetLastError() returns ERROR_SUCCESS. 125 DWORD error = GetLastError(); 126 if (error != ERROR_SUCCESS) { 127 // Unexpected error. The variable should be in the environment, 128 // and buffer should be large enough. 129 __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), 130 __kmp_msg_null); 131 KMP_INTERNAL_FREE((void *)result); 132 result = NULL; 133 }; // if 134 }; // if 135 }; // if 136 #else 137 #error Unknown or unsupported OS. 138 #endif 139 140 return result; 141 142 } // func __kmp_env_get 143 144 // TODO: Find and replace all regular free() with __kmp_env_free(). 145 146 void __kmp_env_free(char const **value) { 147 148 KMP_DEBUG_ASSERT(value != NULL); 149 KMP_INTERNAL_FREE(CCAST(char *, *value)); 150 *value = NULL; 151 152 } // func __kmp_env_free 153 154 int __kmp_env_exists(char const *name) { 155 156 #if KMP_OS_UNIX 157 char const *value = getenv(name); 158 return ((value == NULL) ? (0) : (1)); 159 #elif KMP_OS_WINDOWS 160 DWORD rc; 161 rc = GetEnvironmentVariable(name, NULL, 0); 162 if (rc == 0) { 163 DWORD error = GetLastError(); 164 if (error != ERROR_ENVVAR_NOT_FOUND) { 165 __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 166 }; // if 167 return 0; 168 }; // if 169 return 1; 170 #else 171 #error Unknown or unsupported OS. 172 #endif 173 174 } // func __kmp_env_exists 175 176 void __kmp_env_set(char const *name, char const *value, int overwrite) { 177 178 #if KMP_OS_UNIX 179 int rc = setenv(name, value, overwrite); 180 if (rc != 0) { 181 // Dead code. I tried to put too many variables into Linux* OS 182 // environment on IA-32 architecture. When application consumes 183 // more than ~2.5 GB of memory, entire system feels bad. Sometimes 184 // application is killed (by OS?), sometimes system stops 185 // responding... But this error message never appears. --ln 186 __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_HNT(NotEnoughMemory), 187 __kmp_msg_null); 188 }; // if 189 #elif KMP_OS_WINDOWS 190 BOOL rc; 191 if (!overwrite) { 192 rc = GetEnvironmentVariable(name, NULL, 0); 193 if (rc) { 194 // Variable exists, do not overwrite. 195 return; 196 }; // if 197 DWORD error = GetLastError(); 198 if (error != ERROR_ENVVAR_NOT_FOUND) { 199 __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 200 }; // if 201 }; // if 202 rc = SetEnvironmentVariable(name, value); 203 if (!rc) { 204 DWORD error = GetLastError(); 205 __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 206 }; // if 207 #else 208 #error Unknown or unsupported OS. 209 #endif 210 211 } // func __kmp_env_set 212 213 void __kmp_env_unset(char const *name) { 214 215 #if KMP_OS_UNIX 216 unsetenv(name); 217 #elif KMP_OS_WINDOWS 218 BOOL rc = SetEnvironmentVariable(name, NULL); 219 if (!rc) { 220 DWORD error = GetLastError(); 221 __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 222 }; // if 223 #else 224 #error Unknown or unsupported OS. 225 #endif 226 227 } // func __kmp_env_unset 228 229 /* Intel OpenMP RTL string representation of environment: just a string of 230 characters, variables are separated with vertical bars, e. g.: 231 232 "KMP_WARNINGS=0|KMP_AFFINITY=compact|" 233 234 Empty variables are allowed and ignored: 235 236 "||KMP_WARNINGS=1||" 237 */ 238 239 static void 240 ___kmp_env_blk_parse_string(kmp_env_blk_t *block, // M: Env block to fill. 241 char const *env // I: String to parse. 242 ) { 243 244 char const chr_delimiter = '|'; 245 char const str_delimiter[] = {chr_delimiter, 0}; 246 247 char *bulk = NULL; 248 kmp_env_var_t *vars = NULL; 249 int count = 0; // Number of used elements in vars array. 250 int delimiters = 0; // Number of delimiters in input string. 251 252 // Copy original string, we will modify the copy. 253 bulk = __kmp_str_format("%s", env); 254 255 // Loop thru all the vars in environment block. Count delimiters (maximum 256 // number of variables is number of delimiters plus one). 257 { 258 char const *ptr = bulk; 259 for (;;) { 260 ptr = strchr(ptr, chr_delimiter); 261 if (ptr == NULL) { 262 break; 263 }; // if 264 ++delimiters; 265 ptr += 1; 266 }; // forever 267 } 268 269 // Allocate vars array. 270 vars = (kmp_env_var_t *)allocate((delimiters + 1) * sizeof(kmp_env_var_t)); 271 272 // Loop thru all the variables. 273 { 274 char *var; // Pointer to variable (both name and value). 275 char *name; // Pointer to name of variable. 276 char *value; // Pointer to value. 277 char *buf; // Buffer for __kmp_str_token() function. 278 var = __kmp_str_token(bulk, str_delimiter, &buf); // Get the first var. 279 while (var != NULL) { 280 // Save found variable in vars array. 281 __kmp_str_split(var, '=', &name, &value); 282 KMP_DEBUG_ASSERT(count < delimiters + 1); 283 vars[count].name = name; 284 vars[count].value = value; 285 ++count; 286 // Get the next var. 287 var = __kmp_str_token(NULL, str_delimiter, &buf); 288 }; // while 289 } 290 291 // Fill out result. 292 block->bulk = bulk; 293 block->vars = vars; 294 block->count = count; 295 296 }; // ___kmp_env_blk_parse_string 297 298 /* Windows* OS (actually, DOS) environment block is a piece of memory with 299 environment variables. Each variable is terminated with zero byte, entire 300 block is terminated with one extra zero byte, so we have two zero bytes at 301 the end of environment block, e. g.: 302 303 "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00" 304 305 It is not clear how empty environment is represented. "\x00\x00"? 306 */ 307 308 #if KMP_OS_WINDOWS 309 static void ___kmp_env_blk_parse_windows( 310 kmp_env_blk_t *block, // M: Env block to fill. 311 char const *env // I: Pointer to Windows* OS (DOS) environment block. 312 ) { 313 314 char *bulk = NULL; 315 kmp_env_var_t *vars = NULL; 316 int count = 0; // Number of used elements in vars array. 317 int size = 0; // Size of bulk. 318 319 char *name; // Pointer to name of variable. 320 char *value; // Pointer to value. 321 322 if (env != NULL) { 323 324 // Loop thru all the vars in environment block. Count variables, find size 325 // of block. 326 { 327 char const *var; // Pointer to beginning of var. 328 int len; // Length of variable. 329 count = 0; 330 var = 331 env; // The first variable starts and beginning of environment block. 332 len = KMP_STRLEN(var); 333 while (len != 0) { 334 ++count; 335 size = size + len + 1; 336 var = var + len + 337 1; // Move pointer to the beginning of the next variable. 338 len = KMP_STRLEN(var); 339 }; // while 340 size = 341 size + 1; // Total size of env block, including terminating zero byte. 342 } 343 344 // Copy original block to bulk, we will modify bulk, not original block. 345 bulk = (char *)allocate(size); 346 KMP_MEMCPY_S(bulk, size, env, size); 347 // Allocate vars array. 348 vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t)); 349 350 // Loop thru all the vars, now in bulk. 351 { 352 char *var; // Pointer to beginning of var. 353 int len; // Length of variable. 354 count = 0; 355 var = bulk; 356 len = KMP_STRLEN(var); 357 while (len != 0) { 358 // Save variable in vars array. 359 __kmp_str_split(var, '=', &name, &value); 360 vars[count].name = name; 361 vars[count].value = value; 362 ++count; 363 // Get the next var. 364 var = var + len + 1; 365 len = KMP_STRLEN(var); 366 }; // while 367 } 368 369 }; // if 370 371 // Fill out result. 372 block->bulk = bulk; 373 block->vars = vars; 374 block->count = count; 375 376 }; // ___kmp_env_blk_parse_windows 377 #endif 378 379 /* Unix environment block is a array of pointers to variables, last pointer in 380 array is NULL: 381 382 { "HOME=/home/lev", "TERM=xterm", NULL } 383 */ 384 385 static void 386 ___kmp_env_blk_parse_unix(kmp_env_blk_t *block, // M: Env block to fill. 387 char **env // I: Unix environment to parse. 388 ) { 389 390 char *bulk = NULL; 391 kmp_env_var_t *vars = NULL; 392 int count = 0; 393 int size = 0; // Size of bulk. 394 395 // Count number of variables and length of required bulk. 396 { 397 count = 0; 398 size = 0; 399 while (env[count] != NULL) { 400 size += KMP_STRLEN(env[count]) + 1; 401 ++count; 402 }; // while 403 } 404 405 // Allocate memory. 406 bulk = (char *)allocate(size); 407 vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t)); 408 409 // Loop thru all the vars. 410 { 411 char *var; // Pointer to beginning of var. 412 char *name; // Pointer to name of variable. 413 char *value; // Pointer to value. 414 int len; // Length of variable. 415 int i; 416 var = bulk; 417 for (i = 0; i < count; ++i) { 418 // Copy variable to bulk. 419 len = KMP_STRLEN(env[i]); 420 KMP_MEMCPY_S(var, size, env[i], len + 1); 421 // Save found variable in vars array. 422 __kmp_str_split(var, '=', &name, &value); 423 vars[i].name = name; 424 vars[i].value = value; 425 // Move pointer. 426 var += len + 1; 427 }; // for 428 } 429 430 // Fill out result. 431 block->bulk = bulk; 432 block->vars = vars; 433 block->count = count; 434 435 }; // ___kmp_env_blk_parse_unix 436 437 void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize. 438 char const *bulk // I: Initialization string, or NULL. 439 ) { 440 441 if (bulk != NULL) { 442 ___kmp_env_blk_parse_string(block, bulk); 443 } else { 444 #if KMP_OS_UNIX 445 ___kmp_env_blk_parse_unix(block, environ); 446 #elif KMP_OS_WINDOWS 447 { 448 char *mem = GetEnvironmentStrings(); 449 if (mem == NULL) { 450 DWORD error = GetLastError(); 451 __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error), 452 __kmp_msg_null); 453 }; // if 454 ___kmp_env_blk_parse_windows(block, mem); 455 FreeEnvironmentStrings(mem); 456 } 457 #else 458 #error Unknown or unsupported OS. 459 #endif 460 }; // if 461 462 } // __kmp_env_blk_init 463 464 static int ___kmp_env_var_cmp( // Comparison function for qsort(). 465 kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) { 466 return strcmp(lhs->name, rhs->name); 467 } 468 469 void __kmp_env_blk_sort( 470 kmp_env_blk_t *block // M: Block of environment variables to sort. 471 ) { 472 473 qsort(CCAST(kmp_env_var_t *, block->vars), block->count, 474 sizeof(kmp_env_var_t), 475 (int (*)(void const *, void const *)) & ___kmp_env_var_cmp); 476 477 } // __kmp_env_block_sort 478 479 void __kmp_env_blk_free( 480 kmp_env_blk_t *block // M: Block of environment variables to free. 481 ) { 482 483 KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars)); 484 __kmp_str_free(&(block->bulk)); 485 486 block->count = 0; 487 block->vars = NULL; 488 489 } // __kmp_env_blk_free 490 491 char const * // R: Value of variable or NULL if variable does not exist. 492 __kmp_env_blk_var( 493 kmp_env_blk_t *block, // I: Block of environment variables. 494 char const *name // I: Name of variable to find. 495 ) { 496 497 int i; 498 for (i = 0; i < block->count; ++i) { 499 if (strcmp(block->vars[i].name, name) == 0) { 500 return block->vars[i].value; 501 }; // if 502 }; // for 503 return NULL; 504 505 } // __kmp_env_block_var 506 507 // end of file // 508