LLVM OpenMP* Runtime Library
kmp_environment.cpp
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 //