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 } 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 } 99 KMP_STRNCPY_S(result, len, value, len); 100 } 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 } 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 } 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 } 134 } 135 } 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 } 167 return 0; 168 } 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 } 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 } 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 } 201 } 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 } 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 } 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 } 264 ++delimiters; 265 ptr += 1; 266 } 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 } 289 } 290 291 // Fill out result. 292 block->bulk = bulk; 293 block->vars = vars; 294 block->count = count; 295 } 296 297 /* Windows* OS (actually, DOS) environment block is a piece of memory with 298 environment variables. Each variable is terminated with zero byte, entire 299 block is terminated with one extra zero byte, so we have two zero bytes at 300 the end of environment block, e. g.: 301 302 "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00" 303 304 It is not clear how empty environment is represented. "\x00\x00"? 305 */ 306 307 #if KMP_OS_WINDOWS 308 static void ___kmp_env_blk_parse_windows( 309 kmp_env_blk_t *block, // M: Env block to fill. 310 char const *env // I: Pointer to Windows* OS (DOS) environment block. 311 ) { 312 313 char *bulk = NULL; 314 kmp_env_var_t *vars = NULL; 315 int count = 0; // Number of used elements in vars array. 316 int size = 0; // Size of bulk. 317 318 char *name; // Pointer to name of variable. 319 char *value; // Pointer to value. 320 321 if (env != NULL) { 322 323 // Loop thru all the vars in environment block. Count variables, find size 324 // of block. 325 { 326 char const *var; // Pointer to beginning of var. 327 int len; // Length of variable. 328 count = 0; 329 var = 330 env; // The first variable starts and beginning of environment block. 331 len = KMP_STRLEN(var); 332 while (len != 0) { 333 ++count; 334 size = size + len + 1; 335 var = var + len + 336 1; // Move pointer to the beginning of the next variable. 337 len = KMP_STRLEN(var); 338 } 339 size = 340 size + 1; // Total size of env block, including terminating zero byte. 341 } 342 343 // Copy original block to bulk, we will modify bulk, not original block. 344 bulk = (char *)allocate(size); 345 KMP_MEMCPY_S(bulk, size, env, size); 346 // Allocate vars array. 347 vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t)); 348 349 // Loop thru all the vars, now in bulk. 350 { 351 char *var; // Pointer to beginning of var. 352 int len; // Length of variable. 353 count = 0; 354 var = bulk; 355 len = KMP_STRLEN(var); 356 while (len != 0) { 357 // Save variable in vars array. 358 __kmp_str_split(var, '=', &name, &value); 359 vars[count].name = name; 360 vars[count].value = value; 361 ++count; 362 // Get the next var. 363 var = var + len + 1; 364 len = KMP_STRLEN(var); 365 } 366 } 367 } 368 369 // Fill out result. 370 block->bulk = bulk; 371 block->vars = vars; 372 block->count = count; 373 } 374 #endif 375 376 /* Unix environment block is a array of pointers to variables, last pointer in 377 array is NULL: 378 379 { "HOME=/home/lev", "TERM=xterm", NULL } 380 */ 381 382 static void 383 ___kmp_env_blk_parse_unix(kmp_env_blk_t *block, // M: Env block to fill. 384 char **env // I: Unix environment to parse. 385 ) { 386 387 char *bulk = NULL; 388 kmp_env_var_t *vars = NULL; 389 int count = 0; 390 int size = 0; // Size of bulk. 391 392 // Count number of variables and length of required bulk. 393 { 394 count = 0; 395 size = 0; 396 while (env[count] != NULL) { 397 size += KMP_STRLEN(env[count]) + 1; 398 ++count; 399 } 400 } 401 402 // Allocate memory. 403 bulk = (char *)allocate(size); 404 vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t)); 405 406 // Loop thru all the vars. 407 { 408 char *var; // Pointer to beginning of var. 409 char *name; // Pointer to name of variable. 410 char *value; // Pointer to value. 411 int len; // Length of variable. 412 int i; 413 var = bulk; 414 for (i = 0; i < count; ++i) { 415 // Copy variable to bulk. 416 len = KMP_STRLEN(env[i]); 417 KMP_MEMCPY_S(var, size, env[i], len + 1); 418 // Save found variable in vars array. 419 __kmp_str_split(var, '=', &name, &value); 420 vars[i].name = name; 421 vars[i].value = value; 422 // Move pointer. 423 var += len + 1; 424 } 425 } 426 427 // Fill out result. 428 block->bulk = bulk; 429 block->vars = vars; 430 block->count = count; 431 } 432 433 void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize. 434 char const *bulk // I: Initialization string, or NULL. 435 ) { 436 437 if (bulk != NULL) { 438 ___kmp_env_blk_parse_string(block, bulk); 439 } else { 440 #if KMP_OS_UNIX 441 ___kmp_env_blk_parse_unix(block, environ); 442 #elif KMP_OS_WINDOWS 443 { 444 char *mem = GetEnvironmentStrings(); 445 if (mem == NULL) { 446 DWORD error = GetLastError(); 447 __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error), 448 __kmp_msg_null); 449 } 450 ___kmp_env_blk_parse_windows(block, mem); 451 FreeEnvironmentStrings(mem); 452 } 453 #else 454 #error Unknown or unsupported OS. 455 #endif 456 } 457 458 } // __kmp_env_blk_init 459 460 static int ___kmp_env_var_cmp( // Comparison function for qsort(). 461 kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) { 462 return strcmp(lhs->name, rhs->name); 463 } 464 465 void __kmp_env_blk_sort( 466 kmp_env_blk_t *block // M: Block of environment variables to sort. 467 ) { 468 469 qsort(CCAST(kmp_env_var_t *, block->vars), block->count, 470 sizeof(kmp_env_var_t), 471 (int (*)(void const *, void const *)) & ___kmp_env_var_cmp); 472 473 } // __kmp_env_block_sort 474 475 void __kmp_env_blk_free( 476 kmp_env_blk_t *block // M: Block of environment variables to free. 477 ) { 478 479 KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars)); 480 __kmp_str_free(&(block->bulk)); 481 482 block->count = 0; 483 block->vars = NULL; 484 485 } // __kmp_env_blk_free 486 487 char const * // R: Value of variable or NULL if variable does not exist. 488 __kmp_env_blk_var( 489 kmp_env_blk_t *block, // I: Block of environment variables. 490 char const *name // I: Name of variable to find. 491 ) { 492 493 int i; 494 for (i = 0; i < block->count; ++i) { 495 if (strcmp(block->vars[i].name, name) == 0) { 496 return block->vars[i].value; 497 } 498 } 499 return NULL; 500 501 } // __kmp_env_block_var 502 503 // end of file // 504