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