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