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