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_msg(kmp_ms_fatal, KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), 113 __kmp_msg_null); 114 }; // if 115 // Variable is not found, it's ok, just continue. 116 } else { 117 DWORD len = rc; 118 result = (char *)KMP_INTERNAL_MALLOC(len); 119 if (result == NULL) { 120 KMP_FATAL(MemoryAllocFailed); 121 }; // if 122 rc = GetEnvironmentVariable(name, result, len); 123 if (!rc) { 124 // GetEnvironmentVariable() may return 0 if variable is empty. 125 // In such a case GetLastError() returns ERROR_SUCCESS. 126 DWORD error = GetLastError(); 127 if (error != ERROR_SUCCESS) { 128 // Unexpected error. The variable should be in the environment, 129 // and buffer should be large enough. 130 __kmp_msg(kmp_ms_fatal, KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), 131 __kmp_msg_null); 132 KMP_INTERNAL_FREE((void *)result); 133 result = NULL; 134 }; // if 135 }; // if 136 }; // if 137 #else 138 #error Unknown or unsupported OS. 139 #endif 140 141 return result; 142 143 } // func __kmp_env_get 144 145 // TODO: Find and replace all regular free() with __kmp_env_free(). 146 147 void __kmp_env_free(char const **value) { 148 149 KMP_DEBUG_ASSERT(value != NULL); 150 KMP_INTERNAL_FREE((void *)*value); 151 *value = NULL; 152 153 } // func __kmp_env_free 154 155 int __kmp_env_exists(char const *name) { 156 157 #if KMP_OS_UNIX 158 char const *value = getenv(name); 159 return ((value == NULL) ? (0) : (1)); 160 #elif KMP_OS_WINDOWS 161 DWORD rc; 162 rc = GetEnvironmentVariable(name, NULL, 0); 163 if (rc == 0) { 164 DWORD error = GetLastError(); 165 if (error != ERROR_ENVVAR_NOT_FOUND) { 166 __kmp_msg(kmp_ms_fatal, KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), 167 __kmp_msg_null); 168 }; // if 169 return 0; 170 }; // if 171 return 1; 172 #else 173 #error Unknown or unsupported OS. 174 #endif 175 176 } // func __kmp_env_exists 177 178 void __kmp_env_set(char const *name, char const *value, int overwrite) { 179 180 #if KMP_OS_UNIX 181 int rc = setenv(name, value, overwrite); 182 if (rc != 0) { 183 // Dead code. I tried to put too many variables into Linux* OS 184 // environment on IA-32 architecture. When application consumes 185 // more than ~2.5 GB of memory, entire system feels bad. Sometimes 186 // application is killed (by OS?), sometimes system stops 187 // responding... But this error message never appears. --ln 188 __kmp_msg(kmp_ms_fatal, KMP_MSG(CantSetEnvVar, name), 189 KMP_HNT(NotEnoughMemory), __kmp_msg_null); 190 }; // if 191 #elif KMP_OS_WINDOWS 192 BOOL rc; 193 if (!overwrite) { 194 rc = GetEnvironmentVariable(name, NULL, 0); 195 if (rc) { 196 // Variable exists, do not overwrite. 197 return; 198 }; // if 199 DWORD error = GetLastError(); 200 if (error != ERROR_ENVVAR_NOT_FOUND) { 201 __kmp_msg(kmp_ms_fatal, KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), 202 __kmp_msg_null); 203 }; // if 204 }; // if 205 rc = SetEnvironmentVariable(name, value); 206 if (!rc) { 207 DWORD error = GetLastError(); 208 __kmp_msg(kmp_ms_fatal, KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), 209 __kmp_msg_null); 210 }; // if 211 #else 212 #error Unknown or unsupported OS. 213 #endif 214 215 } // func __kmp_env_set 216 217 void __kmp_env_unset(char const *name) { 218 219 #if KMP_OS_UNIX 220 unsetenv(name); 221 #elif KMP_OS_WINDOWS 222 BOOL rc = SetEnvironmentVariable(name, NULL); 223 if (!rc) { 224 DWORD error = GetLastError(); 225 __kmp_msg(kmp_ms_fatal, KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), 226 __kmp_msg_null); 227 }; // if 228 #else 229 #error Unknown or unsupported OS. 230 #endif 231 232 } // func __kmp_env_unset 233 234 /* Intel OpenMP RTL string representation of environment: just a string of 235 characters, variables are separated with vertical bars, e. g.: 236 237 "KMP_WARNINGS=0|KMP_AFFINITY=compact|" 238 239 Empty variables are allowed and ignored: 240 241 "||KMP_WARNINGS=1||" 242 */ 243 244 static void 245 ___kmp_env_blk_parse_string(kmp_env_blk_t *block, // M: Env block to fill. 246 char const *env // I: String to parse. 247 ) { 248 249 char const chr_delimiter = '|'; 250 char const str_delimiter[] = {chr_delimiter, 0}; 251 252 char *bulk = NULL; 253 kmp_env_var_t *vars = NULL; 254 int count = 0; // Number of used elements in vars array. 255 int delimiters = 0; // Number of delimiters in input string. 256 257 // Copy original string, we will modify the copy. 258 bulk = __kmp_str_format("%s", env); 259 260 // Loop thru all the vars in environment block. Count delimiters (maximum 261 // number of variables is number of delimiters plus one). 262 { 263 char const *ptr = bulk; 264 for (;;) { 265 ptr = strchr(ptr, chr_delimiter); 266 if (ptr == NULL) { 267 break; 268 }; // if 269 ++delimiters; 270 ptr += 1; 271 }; // forever 272 } 273 274 // Allocate vars array. 275 vars = (kmp_env_var_t *)allocate((delimiters + 1) * sizeof(kmp_env_var_t)); 276 277 // Loop thru all the variables. 278 { 279 char *var; // Pointer to variable (both name and value). 280 char *name; // Pointer to name of variable. 281 char *value; // Pointer to value. 282 char *buf; // Buffer for __kmp_str_token() function. 283 var = __kmp_str_token(bulk, str_delimiter, &buf); // Get the first var. 284 while (var != NULL) { 285 // Save found variable in vars array. 286 __kmp_str_split(var, '=', &name, &value); 287 KMP_DEBUG_ASSERT(count < delimiters + 1); 288 vars[count].name = name; 289 vars[count].value = value; 290 ++count; 291 // Get the next var. 292 var = __kmp_str_token(NULL, str_delimiter, &buf); 293 }; // while 294 } 295 296 // Fill out result. 297 block->bulk = bulk; 298 block->vars = vars; 299 block->count = count; 300 301 }; // ___kmp_env_blk_parse_string 302 303 /* Windows* OS (actually, DOS) environment block is a piece of memory with 304 environment variables. Each variable is terminated with zero byte, entire 305 block is terminated with one extra zero byte, so we have two zero bytes at 306 the end of environment block, e. g.: 307 308 "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00" 309 310 It is not clear how empty environment is represented. "\x00\x00"? 311 */ 312 313 #if KMP_OS_WINDOWS 314 static void ___kmp_env_blk_parse_windows( 315 kmp_env_blk_t *block, // M: Env block to fill. 316 char const *env // I: Pointer to Windows* OS (DOS) environment block. 317 ) { 318 319 char *bulk = NULL; 320 kmp_env_var_t *vars = NULL; 321 int count = 0; // Number of used elements in vars array. 322 int size = 0; // Size of bulk. 323 324 char *name; // Pointer to name of variable. 325 char *value; // Pointer to value. 326 327 if (env != NULL) { 328 329 // Loop thru all the vars in environment block. Count variables, find size 330 // of block. 331 { 332 char const *var; // Pointer to beginning of var. 333 int len; // Length of variable. 334 count = 0; 335 var = 336 env; // The first variable starts and beginning of environment block. 337 len = KMP_STRLEN(var); 338 while (len != 0) { 339 ++count; 340 size = size + len + 1; 341 var = var + len + 342 1; // Move pointer to the beginning of the next variable. 343 len = KMP_STRLEN(var); 344 }; // while 345 size = 346 size + 1; // Total size of env block, including terminating zero byte. 347 } 348 349 // Copy original block to bulk, we will modify bulk, not original block. 350 bulk = (char *)allocate(size); 351 KMP_MEMCPY_S(bulk, size, env, size); 352 // Allocate vars array. 353 vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t)); 354 355 // Loop thru all the vars, now in bulk. 356 { 357 char *var; // Pointer to beginning of var. 358 int len; // Length of variable. 359 count = 0; 360 var = bulk; 361 len = KMP_STRLEN(var); 362 while (len != 0) { 363 // Save variable in vars array. 364 __kmp_str_split(var, '=', &name, &value); 365 vars[count].name = name; 366 vars[count].value = value; 367 ++count; 368 // Get the next var. 369 var = var + len + 1; 370 len = KMP_STRLEN(var); 371 }; // while 372 } 373 374 }; // if 375 376 // Fill out result. 377 block->bulk = bulk; 378 block->vars = vars; 379 block->count = count; 380 381 }; // ___kmp_env_blk_parse_windows 382 #endif 383 384 /* Unix environment block is a array of pointers to variables, last pointer in 385 array is NULL: 386 387 { "HOME=/home/lev", "TERM=xterm", NULL } 388 */ 389 390 static void 391 ___kmp_env_blk_parse_unix(kmp_env_blk_t *block, // M: Env block to fill. 392 char **env // I: Unix environment to parse. 393 ) { 394 395 char *bulk = NULL; 396 kmp_env_var_t *vars = NULL; 397 int count = 0; 398 int size = 0; // Size of bulk. 399 400 // Count number of variables and length of required bulk. 401 { 402 count = 0; 403 size = 0; 404 while (env[count] != NULL) { 405 size += KMP_STRLEN(env[count]) + 1; 406 ++count; 407 }; // while 408 } 409 410 // Allocate memory. 411 bulk = (char *)allocate(size); 412 vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t)); 413 414 // Loop thru all the vars. 415 { 416 char *var; // Pointer to beginning of var. 417 char *name; // Pointer to name of variable. 418 char *value; // Pointer to value. 419 int len; // Length of variable. 420 int i; 421 var = bulk; 422 for (i = 0; i < count; ++i) { 423 // Copy variable to bulk. 424 len = KMP_STRLEN(env[i]); 425 KMP_MEMCPY_S(var, size, env[i], len + 1); 426 // Save found variable in vars array. 427 __kmp_str_split(var, '=', &name, &value); 428 vars[i].name = name; 429 vars[i].value = value; 430 // Move pointer. 431 var += len + 1; 432 }; // for 433 } 434 435 // Fill out result. 436 block->bulk = bulk; 437 block->vars = vars; 438 block->count = count; 439 440 }; // ___kmp_env_blk_parse_unix 441 442 void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize. 443 char const *bulk // I: Initialization string, or NULL. 444 ) { 445 446 if (bulk != NULL) { 447 ___kmp_env_blk_parse_string(block, bulk); 448 } else { 449 #if KMP_OS_UNIX 450 ___kmp_env_blk_parse_unix(block, environ); 451 #elif KMP_OS_WINDOWS 452 { 453 char *mem = GetEnvironmentStrings(); 454 if (mem == NULL) { 455 DWORD error = GetLastError(); 456 __kmp_msg(kmp_ms_fatal, KMP_MSG(CantGetEnvironment), KMP_ERR(error), 457 __kmp_msg_null); 458 }; // if 459 ___kmp_env_blk_parse_windows(block, mem); 460 FreeEnvironmentStrings(mem); 461 } 462 #else 463 #error Unknown or unsupported OS. 464 #endif 465 }; // if 466 467 } // __kmp_env_blk_init 468 469 static int ___kmp_env_var_cmp( // Comparison function for qsort(). 470 kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) { 471 return strcmp(lhs->name, rhs->name); 472 } 473 474 void __kmp_env_blk_sort( 475 kmp_env_blk_t *block // M: Block of environment variables to sort. 476 ) { 477 478 qsort((void *)block->vars, block->count, sizeof(kmp_env_var_t), 479 (int (*)(void const *, void const *)) & ___kmp_env_var_cmp); 480 481 } // __kmp_env_block_sort 482 483 void __kmp_env_blk_free( 484 kmp_env_blk_t *block // M: Block of environment variables to free. 485 ) { 486 487 KMP_INTERNAL_FREE((void *)block->vars); 488 __kmp_str_free(&(block->bulk)); 489 490 block->count = 0; 491 block->vars = NULL; 492 493 } // __kmp_env_blk_free 494 495 char const * // R: Value of variable or NULL if variable does not exist. 496 __kmp_env_blk_var( 497 kmp_env_blk_t *block, // I: Block of environment variables. 498 char const *name // I: Name of variable to find. 499 ) { 500 501 int i; 502 for (i = 0; i < block->count; ++i) { 503 if (strcmp(block->vars[i].name, name) == 0) { 504 return block->vars[i].value; 505 }; // if 506 }; // for 507 return NULL; 508 509 } // __kmp_env_block_var 510 511 // end of file // 512