LLVM OpenMP* Runtime Library
kmp_environment.cpp
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(CCAST(char *, *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(CCAST(kmp_env_var_t *, block->vars), block->count,
479  sizeof(kmp_env_var_t),
480  (int (*)(void const *, void const *)) & ___kmp_env_var_cmp);
481 
482 } // __kmp_env_block_sort
483 
484 void __kmp_env_blk_free(
485  kmp_env_blk_t *block // M: Block of environment variables to free.
486  ) {
487 
488  KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars));
489  __kmp_str_free(&(block->bulk));
490 
491  block->count = 0;
492  block->vars = NULL;
493 
494 } // __kmp_env_blk_free
495 
496 char const * // R: Value of variable or NULL if variable does not exist.
497  __kmp_env_blk_var(
498  kmp_env_blk_t *block, // I: Block of environment variables.
499  char const *name // I: Name of variable to find.
500  ) {
501 
502  int i;
503  for (i = 0; i < block->count; ++i) {
504  if (strcmp(block->vars[i].name, name) == 0) {
505  return block->vars[i].value;
506  }; // if
507  }; // for
508  return NULL;
509 
510 } // __kmp_env_block_var
511 
512 // end of file //