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  char *bulk = NULL;
384  kmp_env_var_t *vars = NULL;
385  int count = 0;
386  size_t size = 0; // Size of bulk.
387 
388  // Count number of variables and length of required bulk.
389  {
390  while (env[count] != NULL) {
391  size += KMP_STRLEN(env[count]) + 1;
392  ++count;
393  }
394  }
395 
396  // Allocate memory.
397  bulk = (char *)allocate(size);
398  vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
399 
400  // Loop thru all the vars.
401  {
402  char *var; // Pointer to beginning of var.
403  char *name; // Pointer to name of variable.
404  char *value; // Pointer to value.
405  size_t len; // Length of variable.
406  int i;
407  var = bulk;
408  for (i = 0; i < count; ++i) {
409  // Copy variable to bulk.
410  len = KMP_STRLEN(env[i]);
411  KMP_MEMCPY_S(var, size, env[i], len + 1);
412  // Save found variable in vars array.
413  __kmp_str_split(var, '=', &name, &value);
414  vars[i].name = name;
415  vars[i].value = value;
416  // Move pointer.
417  var += len + 1;
418  }
419  }
420 
421  // Fill out result.
422  block->bulk = bulk;
423  block->vars = vars;
424  block->count = count;
425 }
426 
427 void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize.
428  char const *bulk // I: Initialization string, or NULL.
429  ) {
430 
431  if (bulk != NULL) {
432  ___kmp_env_blk_parse_string(block, bulk);
433  } else {
434 #if KMP_OS_UNIX
435  ___kmp_env_blk_parse_unix(block, environ);
436 #elif KMP_OS_WINDOWS
437  {
438  char *mem = GetEnvironmentStrings();
439  if (mem == NULL) {
440  DWORD error = GetLastError();
441  __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error),
442  __kmp_msg_null);
443  }
444  ___kmp_env_blk_parse_windows(block, mem);
445  FreeEnvironmentStrings(mem);
446  }
447 #else
448 #error Unknown or unsupported OS.
449 #endif
450  }
451 
452 } // __kmp_env_blk_init
453 
454 static int ___kmp_env_var_cmp( // Comparison function for qsort().
455  kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) {
456  return strcmp(lhs->name, rhs->name);
457 }
458 
459 void __kmp_env_blk_sort(
460  kmp_env_blk_t *block // M: Block of environment variables to sort.
461  ) {
462 
463  qsort(CCAST(kmp_env_var_t *, block->vars), block->count,
464  sizeof(kmp_env_var_t),
465  (int (*)(void const *, void const *)) & ___kmp_env_var_cmp);
466 
467 } // __kmp_env_block_sort
468 
469 void __kmp_env_blk_free(
470  kmp_env_blk_t *block // M: Block of environment variables to free.
471  ) {
472 
473  KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars));
474  __kmp_str_free(&(block->bulk));
475 
476  block->count = 0;
477  block->vars = NULL;
478 
479 } // __kmp_env_blk_free
480 
481 char const * // R: Value of variable or NULL if variable does not exist.
482  __kmp_env_blk_var(
483  kmp_env_blk_t *block, // I: Block of environment variables.
484  char const *name // I: Name of variable to find.
485  ) {
486 
487  int i;
488  for (i = 0; i < block->count; ++i) {
489  if (strcmp(block->vars[i].name, name) == 0) {
490  return block->vars[i].value;
491  }
492  }
493  return NULL;
494 
495 } // __kmp_env_block_var
496 
497 // end of file //