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   }
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     }
99     KMP_STRNCPY_S(result, len, value, len);
100   }
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_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
113     }
114     // Variable is not found, it's ok, just continue.
115   } else {
116     DWORD len = rc;
117     result = (char *)KMP_INTERNAL_MALLOC(len);
118     if (result == NULL) {
119       KMP_FATAL(MemoryAllocFailed);
120     }
121     rc = GetEnvironmentVariable(name, result, len);
122     if (!rc) {
123       // GetEnvironmentVariable() may return 0 if variable is empty.
124       // In such a case GetLastError() returns ERROR_SUCCESS.
125       DWORD error = GetLastError();
126       if (error != ERROR_SUCCESS) {
127         // Unexpected error. The variable should be in the environment,
128         // and buffer should be large enough.
129         __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error),
130                     __kmp_msg_null);
131         KMP_INTERNAL_FREE((void *)result);
132         result = NULL;
133       }
134     }
135   }
136 #else
137 #error Unknown or unsupported OS.
138 #endif
139 
140   return result;
141 
142 } // func __kmp_env_get
143 
144 // TODO: Find and replace all regular free() with __kmp_env_free().
145 
146 void __kmp_env_free(char const **value) {
147 
148   KMP_DEBUG_ASSERT(value != NULL);
149   KMP_INTERNAL_FREE(CCAST(char *, *value));
150   *value = NULL;
151 
152 } // func __kmp_env_free
153 
154 int __kmp_env_exists(char const *name) {
155 
156 #if KMP_OS_UNIX
157   char const *value = getenv(name);
158   return ((value == NULL) ? (0) : (1));
159 #elif KMP_OS_WINDOWS
160   DWORD rc;
161   rc = GetEnvironmentVariable(name, NULL, 0);
162   if (rc == 0) {
163     DWORD error = GetLastError();
164     if (error != ERROR_ENVVAR_NOT_FOUND) {
165       __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
166     }
167     return 0;
168   }
169   return 1;
170 #else
171 #error Unknown or unsupported OS.
172 #endif
173 
174 } // func __kmp_env_exists
175 
176 void __kmp_env_set(char const *name, char const *value, int overwrite) {
177 
178 #if KMP_OS_UNIX
179   int rc = setenv(name, value, overwrite);
180   if (rc != 0) {
181     // Dead code. I tried to put too many variables into Linux* OS
182     // environment on IA-32 architecture. When application consumes
183     // more than ~2.5 GB of memory, entire system feels bad. Sometimes
184     // application is killed (by OS?), sometimes system stops
185     // responding... But this error message never appears. --ln
186     __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_HNT(NotEnoughMemory),
187                 __kmp_msg_null);
188   }
189 #elif KMP_OS_WINDOWS
190   BOOL rc;
191   if (!overwrite) {
192     rc = GetEnvironmentVariable(name, NULL, 0);
193     if (rc) {
194       // Variable exists, do not overwrite.
195       return;
196     }
197     DWORD error = GetLastError();
198     if (error != ERROR_ENVVAR_NOT_FOUND) {
199       __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
200     }
201   }
202   rc = SetEnvironmentVariable(name, value);
203   if (!rc) {
204     DWORD error = GetLastError();
205     __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
206   }
207 #else
208 #error Unknown or unsupported OS.
209 #endif
210 
211 } // func __kmp_env_set
212 
213 void __kmp_env_unset(char const *name) {
214 
215 #if KMP_OS_UNIX
216   unsetenv(name);
217 #elif KMP_OS_WINDOWS
218   BOOL rc = SetEnvironmentVariable(name, NULL);
219   if (!rc) {
220     DWORD error = GetLastError();
221     __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
222   }
223 #else
224 #error Unknown or unsupported OS.
225 #endif
226 
227 } // func __kmp_env_unset
228 
229 /* Intel OpenMP RTL string representation of environment: just a string of
230    characters, variables are separated with vertical bars, e. g.:
231 
232         "KMP_WARNINGS=0|KMP_AFFINITY=compact|"
233 
234     Empty variables are allowed and ignored:
235 
236         "||KMP_WARNINGS=1||"
237 */
238 
239 static void
240 ___kmp_env_blk_parse_string(kmp_env_blk_t *block, // M: Env block to fill.
241                             char const *env // I: String to parse.
242                             ) {
243 
244   char const chr_delimiter = '|';
245   char const str_delimiter[] = {chr_delimiter, 0};
246 
247   char *bulk = NULL;
248   kmp_env_var_t *vars = NULL;
249   int count = 0; // Number of used elements in vars array.
250   int delimiters = 0; // Number of delimiters in input string.
251 
252   // Copy original string, we will modify the copy.
253   bulk = __kmp_str_format("%s", env);
254 
255   // Loop thru all the vars in environment block. Count delimiters (maximum
256   // number of variables is number of delimiters plus one).
257   {
258     char const *ptr = bulk;
259     for (;;) {
260       ptr = strchr(ptr, chr_delimiter);
261       if (ptr == NULL) {
262         break;
263       }
264       ++delimiters;
265       ptr += 1;
266     }
267   }
268 
269   // Allocate vars array.
270   vars = (kmp_env_var_t *)allocate((delimiters + 1) * sizeof(kmp_env_var_t));
271 
272   // Loop thru all the variables.
273   {
274     char *var; // Pointer to variable (both name and value).
275     char *name; // Pointer to name of variable.
276     char *value; // Pointer to value.
277     char *buf; // Buffer for __kmp_str_token() function.
278     var = __kmp_str_token(bulk, str_delimiter, &buf); // Get the first var.
279     while (var != NULL) {
280       // Save found variable in vars array.
281       __kmp_str_split(var, '=', &name, &value);
282       KMP_DEBUG_ASSERT(count < delimiters + 1);
283       vars[count].name = name;
284       vars[count].value = value;
285       ++count;
286       // Get the next var.
287       var = __kmp_str_token(NULL, str_delimiter, &buf);
288     }
289   }
290 
291   // Fill out result.
292   block->bulk = bulk;
293   block->vars = vars;
294   block->count = count;
295 }
296 
297 /* Windows* OS (actually, DOS) environment block is a piece of memory with
298    environment variables. Each variable is terminated with zero byte, entire
299    block is terminated with one extra zero byte, so we have two zero bytes at
300    the end of environment block, e. g.:
301 
302         "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
303 
304     It is not clear how empty environment is represented. "\x00\x00"?
305 */
306 
307 #if KMP_OS_WINDOWS
308 static void ___kmp_env_blk_parse_windows(
309     kmp_env_blk_t *block, // M: Env block to fill.
310     char const *env // I: Pointer to Windows* OS (DOS) environment block.
311     ) {
312 
313   char *bulk = NULL;
314   kmp_env_var_t *vars = NULL;
315   int count = 0; // Number of used elements in vars array.
316   int size = 0; // Size of bulk.
317 
318   char *name; // Pointer to name of variable.
319   char *value; // Pointer to value.
320 
321   if (env != NULL) {
322 
323     // Loop thru all the vars in environment block. Count variables, find size
324     // of block.
325     {
326       char const *var; // Pointer to beginning of var.
327       int len; // Length of variable.
328       count = 0;
329       var =
330           env; // The first variable starts and beginning of environment block.
331       len = KMP_STRLEN(var);
332       while (len != 0) {
333         ++count;
334         size = size + len + 1;
335         var = var + len +
336               1; // Move pointer to the beginning of the next variable.
337         len = KMP_STRLEN(var);
338       }
339       size =
340           size + 1; // Total size of env block, including terminating zero byte.
341     }
342 
343     // Copy original block to bulk, we will modify bulk, not original block.
344     bulk = (char *)allocate(size);
345     KMP_MEMCPY_S(bulk, size, env, size);
346     // Allocate vars array.
347     vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
348 
349     // Loop thru all the vars, now in bulk.
350     {
351       char *var; // Pointer to beginning of var.
352       int len; // Length of variable.
353       count = 0;
354       var = bulk;
355       len = KMP_STRLEN(var);
356       while (len != 0) {
357         // Save variable in vars array.
358         __kmp_str_split(var, '=', &name, &value);
359         vars[count].name = name;
360         vars[count].value = value;
361         ++count;
362         // Get the next var.
363         var = var + len + 1;
364         len = KMP_STRLEN(var);
365       }
366     }
367   }
368 
369   // Fill out result.
370   block->bulk = bulk;
371   block->vars = vars;
372   block->count = count;
373 }
374 #endif
375 
376 /* Unix environment block is a array of pointers to variables, last pointer in
377    array is NULL:
378 
379         { "HOME=/home/lev", "TERM=xterm", NULL }
380 */
381 
382 static void
383 ___kmp_env_blk_parse_unix(kmp_env_blk_t *block, // M: Env block to fill.
384                           char **env // I: Unix environment to parse.
385                           ) {
386 
387   char *bulk = NULL;
388   kmp_env_var_t *vars = NULL;
389   int count = 0;
390   int size = 0; // Size of bulk.
391 
392   // Count number of variables and length of required bulk.
393   {
394     count = 0;
395     size = 0;
396     while (env[count] != NULL) {
397       size += KMP_STRLEN(env[count]) + 1;
398       ++count;
399     }
400   }
401 
402   // Allocate memory.
403   bulk = (char *)allocate(size);
404   vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
405 
406   // Loop thru all the vars.
407   {
408     char *var; // Pointer to beginning of var.
409     char *name; // Pointer to name of variable.
410     char *value; // Pointer to value.
411     int len; // Length of variable.
412     int i;
413     var = bulk;
414     for (i = 0; i < count; ++i) {
415       // Copy variable to bulk.
416       len = KMP_STRLEN(env[i]);
417       KMP_MEMCPY_S(var, size, env[i], len + 1);
418       // Save found variable in vars array.
419       __kmp_str_split(var, '=', &name, &value);
420       vars[i].name = name;
421       vars[i].value = value;
422       // Move pointer.
423       var += len + 1;
424     }
425   }
426 
427   // Fill out result.
428   block->bulk = bulk;
429   block->vars = vars;
430   block->count = count;
431 }
432 
433 void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize.
434                         char const *bulk // I: Initialization string, or NULL.
435                         ) {
436 
437   if (bulk != NULL) {
438     ___kmp_env_blk_parse_string(block, bulk);
439   } else {
440 #if KMP_OS_UNIX
441     ___kmp_env_blk_parse_unix(block, environ);
442 #elif KMP_OS_WINDOWS
443     {
444       char *mem = GetEnvironmentStrings();
445       if (mem == NULL) {
446         DWORD error = GetLastError();
447         __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error),
448                     __kmp_msg_null);
449       }
450       ___kmp_env_blk_parse_windows(block, mem);
451       FreeEnvironmentStrings(mem);
452     }
453 #else
454 #error Unknown or unsupported OS.
455 #endif
456   }
457 
458 } // __kmp_env_blk_init
459 
460 static int ___kmp_env_var_cmp( // Comparison function for qsort().
461     kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) {
462   return strcmp(lhs->name, rhs->name);
463 }
464 
465 void __kmp_env_blk_sort(
466     kmp_env_blk_t *block // M: Block of environment variables to sort.
467     ) {
468 
469   qsort(CCAST(kmp_env_var_t *, block->vars), block->count,
470         sizeof(kmp_env_var_t),
471         (int (*)(void const *, void const *)) & ___kmp_env_var_cmp);
472 
473 } // __kmp_env_block_sort
474 
475 void __kmp_env_blk_free(
476     kmp_env_blk_t *block // M: Block of environment variables to free.
477     ) {
478 
479   KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars));
480   __kmp_str_free(&(block->bulk));
481 
482   block->count = 0;
483   block->vars = NULL;
484 
485 } // __kmp_env_blk_free
486 
487 char const * // R: Value of variable or NULL if variable does not exist.
488     __kmp_env_blk_var(
489         kmp_env_blk_t *block, // I: Block of environment variables.
490         char const *name // I: Name of variable to find.
491         ) {
492 
493   int i;
494   for (i = 0; i < block->count; ++i) {
495     if (strcmp(block->vars[i].name, name) == 0) {
496       return block->vars[i].value;
497     }
498   }
499   return NULL;
500 
501 } // __kmp_env_block_var
502 
503 // end of file //
504