forked from OSchip/llvm-project
600 lines
18 KiB
C
600 lines
18 KiB
C
/*
|
|
* kmp_environment.c -- Handle environment variables OS-independently.
|
|
* $Revision: 43084 $
|
|
* $Date: 2014-04-15 09:15:14 -0500 (Tue, 15 Apr 2014) $
|
|
*/
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is dual licensed under the MIT and the University of Illinois Open
|
|
// Source Licenses. See LICENSE.txt for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
/*
|
|
------------------------------------------------------------------------------------------------
|
|
We use GetEnvironmentVariable for Windows* OS instead of getenv because the act of
|
|
loading a DLL on Windows* OS makes any user-set environment variables (i.e. with putenv())
|
|
unavailable. getenv() apparently gets a clean copy of the env variables as they existed
|
|
at the start of the run.
|
|
JH 12/23/2002
|
|
------------------------------------------------------------------------------------------------
|
|
On Windows* OS, there are two environments (at least, see below):
|
|
|
|
1. Environment maintained by Windows* OS on IA-32 architecture.
|
|
Accessible through GetEnvironmentVariable(),
|
|
SetEnvironmentVariable(), and GetEnvironmentStrings().
|
|
|
|
2. Environment maintained by C RTL. Accessible through getenv(), putenv().
|
|
|
|
putenv() function updates both C and Windows* OS on IA-32 architecture. getenv() function
|
|
search for variables in C RTL environment only. Windows* OS on IA-32 architecture functions work *only*
|
|
with Windows* OS on IA-32 architecture.
|
|
|
|
Windows* OS on IA-32 architecture maintained by OS, so there is always only one Windows* OS on
|
|
IA-32 architecture per process. Changes in Windows* OS on IA-32 architecture are process-visible.
|
|
|
|
C environment maintained by C RTL. Multiple copies of C RTL may be present in the process, and
|
|
each C RTL maintains its own environment. :-(
|
|
|
|
Thus, proper way to work with environment on Windows* OS is:
|
|
|
|
1. Set variables with putenv() function -- both C and Windows* OS on
|
|
IA-32 architecture are being updated. Windows* OS on
|
|
IA-32 architecture may be considered as primary target,
|
|
while updating C RTL environment is a free bonus.
|
|
|
|
2. Get variables with GetEnvironmentVariable() -- getenv() does not
|
|
search Windows* OS on IA-32 architecture, and can not see variables
|
|
set with SetEnvironmentVariable().
|
|
|
|
2007-04-05 -- lev
|
|
------------------------------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "kmp_environment.h"
|
|
|
|
#include "kmp_os.h" // KMP_OS_*.
|
|
#include "kmp.h" //
|
|
#include "kmp_str.h" // __kmp_str_*().
|
|
#include "kmp_i18n.h"
|
|
|
|
#if KMP_OS_UNIX
|
|
#include <stdlib.h> // getenv, setenv, unsetenv.
|
|
#include <string.h> // strlen, strcpy.
|
|
#if KMP_OS_LINUX || KMP_OS_FREEBSD
|
|
extern char * * environ;
|
|
#elif KMP_OS_DARWIN
|
|
#include <crt_externs.h>
|
|
#define environ (*_NSGetEnviron())
|
|
#else
|
|
#error Unknown or unsupported OS.
|
|
#endif
|
|
#elif KMP_OS_WINDOWS
|
|
#include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable, GetLastError.
|
|
#else
|
|
#error Unknown or unsupported OS.
|
|
#endif
|
|
|
|
|
|
// TODO: Eliminate direct memory allocations, use string operations instead.
|
|
|
|
static inline
|
|
void *
|
|
allocate(
|
|
size_t size
|
|
) {
|
|
void * ptr = KMP_INTERNAL_MALLOC( size );
|
|
if ( ptr == NULL ) {
|
|
KMP_FATAL( MemoryAllocFailed );
|
|
}; // if
|
|
return ptr;
|
|
} // allocate
|
|
|
|
|
|
char *
|
|
__kmp_env_get( char const * name ) {
|
|
|
|
char * result = NULL;
|
|
|
|
#if KMP_OS_UNIX
|
|
char const * value = getenv( name );
|
|
if ( value != NULL ) {
|
|
size_t len = strlen( value ) + 1;
|
|
result = (char *) KMP_INTERNAL_MALLOC( len );
|
|
if ( result == NULL ) {
|
|
KMP_FATAL( MemoryAllocFailed );
|
|
}; // if
|
|
strncpy( result, value, len );
|
|
}; // if
|
|
#elif KMP_OS_WINDOWS
|
|
/*
|
|
We use GetEnvironmentVariable for Windows* OS instead of getenv because the act of
|
|
loading a DLL on Windows* OS makes any user-set environment variables (i.e. with putenv())
|
|
unavailable. getenv() apparently gets a clean copy of the env variables as they existed
|
|
at the start of the run.
|
|
JH 12/23/2002
|
|
*/
|
|
DWORD rc;
|
|
rc = GetEnvironmentVariable( name, NULL, 0 );
|
|
if ( ! rc ) {
|
|
DWORD error = GetLastError();
|
|
if ( error != ERROR_ENVVAR_NOT_FOUND ) {
|
|
__kmp_msg(
|
|
kmp_ms_fatal,
|
|
KMP_MSG( CantGetEnvVar, name ),
|
|
KMP_ERR( error ),
|
|
__kmp_msg_null
|
|
);
|
|
}; // if
|
|
// Variable is not found, it's ok, just continue.
|
|
} else {
|
|
DWORD len = rc;
|
|
result = (char *) KMP_INTERNAL_MALLOC( len );
|
|
if ( result == NULL ) {
|
|
KMP_FATAL( MemoryAllocFailed );
|
|
}; // if
|
|
rc = GetEnvironmentVariable( name, result, len );
|
|
if ( ! rc ) {
|
|
// GetEnvironmentVariable() may return 0 if variable is empty.
|
|
// In such a case GetLastError() returns ERROR_SUCCESS.
|
|
DWORD error = GetLastError();
|
|
if ( error != ERROR_SUCCESS ) {
|
|
// Unexpected error. The variable should be in the environment,
|
|
// and buffer should be large enough.
|
|
__kmp_msg(
|
|
kmp_ms_fatal,
|
|
KMP_MSG( CantGetEnvVar, name ),
|
|
KMP_ERR( error ),
|
|
__kmp_msg_null
|
|
);
|
|
KMP_INTERNAL_FREE( (void *) result );
|
|
result = NULL;
|
|
}; // if
|
|
}; // if
|
|
}; // if
|
|
#else
|
|
#error Unknown or unsupported OS.
|
|
#endif
|
|
|
|
return result;
|
|
|
|
} // func __kmp_env_get
|
|
|
|
|
|
// TODO: Find and replace all regular free() with __kmp_env_free().
|
|
|
|
void
|
|
__kmp_env_free( char const * * value ) {
|
|
|
|
KMP_DEBUG_ASSERT( value != NULL );
|
|
KMP_INTERNAL_FREE( (void *) * value );
|
|
* value = NULL;
|
|
|
|
} // func __kmp_env_free
|
|
|
|
|
|
|
|
int
|
|
__kmp_env_exists( char const * name ) {
|
|
|
|
#if KMP_OS_UNIX
|
|
char const * value = getenv( name );
|
|
return ( ( value == NULL ) ? ( 0 ) : ( 1 ) );
|
|
#elif KMP_OS_WINDOWS
|
|
DWORD rc;
|
|
rc = GetEnvironmentVariable( name, NULL, 0 );
|
|
if ( rc == 0 ) {
|
|
DWORD error = GetLastError();
|
|
if ( error != ERROR_ENVVAR_NOT_FOUND ) {
|
|
__kmp_msg(
|
|
kmp_ms_fatal,
|
|
KMP_MSG( CantGetEnvVar, name ),
|
|
KMP_ERR( error ),
|
|
__kmp_msg_null
|
|
);
|
|
}; // if
|
|
return 0;
|
|
}; // if
|
|
return 1;
|
|
#else
|
|
#error Unknown or unsupported OS.
|
|
#endif
|
|
|
|
} // func __kmp_env_exists
|
|
|
|
|
|
|
|
void
|
|
__kmp_env_set( char const * name, char const * value, int overwrite ) {
|
|
|
|
#if KMP_OS_UNIX
|
|
int rc = setenv( name, value, overwrite );
|
|
if ( rc != 0 ) {
|
|
// Dead code. I tried to put too many variables into Linux* OS
|
|
// environment on IA-32 architecture. When application consumes
|
|
// more than ~2.5 GB of memory, entire system feels bad. Sometimes
|
|
// application is killed (by OS?), sometimes system stops
|
|
// responding... But this error message never appears. --ln
|
|
__kmp_msg(
|
|
kmp_ms_fatal,
|
|
KMP_MSG( CantSetEnvVar, name ),
|
|
KMP_HNT( NotEnoughMemory ),
|
|
__kmp_msg_null
|
|
);
|
|
}; // if
|
|
#elif KMP_OS_WINDOWS
|
|
BOOL rc;
|
|
if ( ! overwrite ) {
|
|
rc = GetEnvironmentVariable( name, NULL, 0 );
|
|
if ( rc ) {
|
|
// Variable exists, do not overwrite.
|
|
return;
|
|
}; // if
|
|
DWORD error = GetLastError();
|
|
if ( error != ERROR_ENVVAR_NOT_FOUND ) {
|
|
__kmp_msg(
|
|
kmp_ms_fatal,
|
|
KMP_MSG( CantGetEnvVar, name ),
|
|
KMP_ERR( error ),
|
|
__kmp_msg_null
|
|
);
|
|
}; // if
|
|
}; // if
|
|
rc = SetEnvironmentVariable( name, value );
|
|
if ( ! rc ) {
|
|
DWORD error = GetLastError();
|
|
__kmp_msg(
|
|
kmp_ms_fatal,
|
|
KMP_MSG( CantSetEnvVar, name ),
|
|
KMP_ERR( error ),
|
|
__kmp_msg_null
|
|
);
|
|
}; // if
|
|
#else
|
|
#error Unknown or unsupported OS.
|
|
#endif
|
|
|
|
} // func __kmp_env_set
|
|
|
|
|
|
|
|
void
|
|
__kmp_env_unset( char const * name ) {
|
|
|
|
#if KMP_OS_UNIX
|
|
unsetenv( name );
|
|
#elif KMP_OS_WINDOWS
|
|
BOOL rc = SetEnvironmentVariable( name, NULL );
|
|
if ( ! rc ) {
|
|
DWORD error = GetLastError();
|
|
__kmp_msg(
|
|
kmp_ms_fatal,
|
|
KMP_MSG( CantSetEnvVar, name ),
|
|
KMP_ERR( error ),
|
|
__kmp_msg_null
|
|
);
|
|
}; // if
|
|
#else
|
|
#error Unknown or unsupported OS.
|
|
#endif
|
|
|
|
} // func __kmp_env_unset
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
/*
|
|
Intel OpenMP RTL string representation of environment: just a string of characters, variables
|
|
are separated with vertical bars, e. g.:
|
|
|
|
"KMP_WARNINGS=0|KMP_AFFINITY=compact|"
|
|
|
|
Empty variables are allowed and ignored:
|
|
|
|
"||KMP_WARNINGS=1||"
|
|
|
|
*/
|
|
|
|
static
|
|
void
|
|
___kmp_env_blk_parse_string(
|
|
kmp_env_blk_t * block, // M: Env block to fill.
|
|
char const * env // I: String to parse.
|
|
) {
|
|
|
|
char const chr_delimiter = '|';
|
|
char const str_delimiter[] = { chr_delimiter, 0 };
|
|
|
|
char * bulk = NULL;
|
|
kmp_env_var_t * vars = NULL;
|
|
int count = 0; // Number of used elements in vars array.
|
|
int delimiters = 0; // Number of delimiters in input string.
|
|
|
|
// Copy original string, we will modify the copy.
|
|
bulk = __kmp_str_format( "%s", env );
|
|
|
|
// Loop thru all the vars in environment block. Count delimiters (maximum number of variables
|
|
// is number of delimiters plus one).
|
|
{
|
|
char const * ptr = bulk;
|
|
for ( ; ; ) {
|
|
ptr = strchr( ptr, chr_delimiter );
|
|
if ( ptr == NULL ) {
|
|
break;
|
|
}; // if
|
|
++ delimiters;
|
|
ptr += 1;
|
|
}; // forever
|
|
}
|
|
|
|
// Allocate vars array.
|
|
vars = (kmp_env_var_t *) allocate( ( delimiters + 1 ) * sizeof( kmp_env_var_t ) );
|
|
|
|
// Loop thru all the variables.
|
|
{
|
|
char * var; // Pointer to variable (both name and value).
|
|
char * name; // Pointer to name of variable.
|
|
char * value; // Pointer to value.
|
|
char * buf; // Buffer for __kmp_str_token() function.
|
|
var = __kmp_str_token( bulk, str_delimiter, & buf ); // Get the first var.
|
|
while ( var != NULL ) {
|
|
// Save found variable in vars array.
|
|
__kmp_str_split( var, '=', & name, & value );
|
|
KMP_DEBUG_ASSERT( count < delimiters + 1 );
|
|
vars[ count ].name = name;
|
|
vars[ count ].value = value;
|
|
++ count;
|
|
// Get the next var.
|
|
var = __kmp_str_token( NULL, str_delimiter, & buf );
|
|
}; // while
|
|
}
|
|
|
|
// Fill out result.
|
|
block->bulk = bulk;
|
|
block->vars = vars;
|
|
block->count = count;
|
|
|
|
}; // ___kmp_env_blk_parse_string
|
|
|
|
|
|
|
|
/*
|
|
Windows* OS (actually, DOS) environment block is a piece of memory with environment variables. Each
|
|
variable is terminated with zero byte, entire block is terminated with one extra zero byte, so
|
|
we have two zero bytes at the end of environment block, e. g.:
|
|
|
|
"HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
|
|
|
|
It is not clear how empty environment is represented. "\x00\x00"?
|
|
*/
|
|
|
|
static
|
|
void
|
|
___kmp_env_blk_parse_windows(
|
|
kmp_env_blk_t * block, // M: Env block to fill.
|
|
char const * env // I: Pointer to Windows* OS (DOS) environment block.
|
|
) {
|
|
|
|
char * bulk = NULL;
|
|
kmp_env_var_t * vars = NULL;
|
|
int count = 0; // Number of used elements in vars array.
|
|
int size = 0; // Size of bulk.
|
|
|
|
char * name; // Pointer to name of variable.
|
|
char * value; // Pointer to value.
|
|
|
|
if ( env != NULL ) {
|
|
|
|
// Loop thru all the vars in environment block. Count variables, find size of block.
|
|
{
|
|
char const * var; // Pointer to beginning of var.
|
|
int len; // Length of variable.
|
|
count = 0;
|
|
var = env; // The first variable starts and beginning of environment block.
|
|
len = strlen( var );
|
|
while ( len != 0 ) {
|
|
++ count;
|
|
size = size + len + 1;
|
|
var = var + len + 1; // Move pointer to the beginning of the next variable.
|
|
len = strlen( var );
|
|
}; // while
|
|
size = size + 1; // Total size of env block, including terminating zero byte.
|
|
}
|
|
|
|
// Copy original block to bulk, we will modify bulk, not original block.
|
|
bulk = (char *) allocate( size );
|
|
memcpy( bulk, env, size );
|
|
// Allocate vars array.
|
|
vars = (kmp_env_var_t *) allocate( count * sizeof( kmp_env_var_t ) );
|
|
|
|
// Loop thru all the vars, now in bulk.
|
|
{
|
|
char * var; // Pointer to beginning of var.
|
|
int len; // Length of variable.
|
|
count = 0;
|
|
var = bulk;
|
|
len = strlen( var );
|
|
while ( len != 0 ) {
|
|
// Save variable in vars array.
|
|
__kmp_str_split( var, '=', & name, & value );
|
|
vars[ count ].name = name;
|
|
vars[ count ].value = value;
|
|
++ count;
|
|
// Get the next var.
|
|
var = var + len + 1;
|
|
len = strlen( var );
|
|
}; // while
|
|
}
|
|
|
|
}; // if
|
|
|
|
// Fill out result.
|
|
block->bulk = bulk;
|
|
block->vars = vars;
|
|
block->count = count;
|
|
|
|
}; // ___kmp_env_blk_parse_windows
|
|
|
|
|
|
|
|
/*
|
|
Unix environment block is a array of pointers to variables, last pointer in array is NULL:
|
|
|
|
{ "HOME=/home/lev", "TERM=xterm", NULL }
|
|
*/
|
|
|
|
static
|
|
void
|
|
___kmp_env_blk_parse_unix(
|
|
kmp_env_blk_t * block, // M: Env block to fill.
|
|
char * * env // I: Unix environment to parse.
|
|
) {
|
|
|
|
char * bulk = NULL;
|
|
kmp_env_var_t * vars = NULL;
|
|
int count = 0;
|
|
int size = 0; // Size of bulk.
|
|
|
|
// Count number of variables and length of required bulk.
|
|
{
|
|
count = 0;
|
|
size = 0;
|
|
while ( env[ count ] != NULL ) {
|
|
size += strlen( env[ count ] ) + 1;
|
|
++ count;
|
|
}; // while
|
|
}
|
|
|
|
// Allocate memory.
|
|
bulk = (char *) allocate( size );
|
|
vars = (kmp_env_var_t *) allocate( count * sizeof( kmp_env_var_t ) );
|
|
|
|
// Loop thru all the vars.
|
|
{
|
|
char * var; // Pointer to beginning of var.
|
|
char * name; // Pointer to name of variable.
|
|
char * value; // Pointer to value.
|
|
int len; // Length of variable.
|
|
int i;
|
|
var = bulk;
|
|
for ( i = 0; i < count; ++ i ) {
|
|
// Copy variable to bulk.
|
|
len = strlen( env[ i ] );
|
|
memcpy( var, env[ i ], len + 1 );
|
|
// Save found variable in vars array.
|
|
__kmp_str_split( var, '=', & name, & value );
|
|
vars[ i ].name = name;
|
|
vars[ i ].value = value;
|
|
// Move pointer.
|
|
var += len + 1;
|
|
}; // for
|
|
}
|
|
|
|
// Fill out result.
|
|
block->bulk = bulk;
|
|
block->vars = vars;
|
|
block->count = count;
|
|
|
|
}; // ___kmp_env_blk_parse_unix
|
|
|
|
|
|
|
|
void
|
|
__kmp_env_blk_init(
|
|
kmp_env_blk_t * block, // M: Block to initialize.
|
|
char const * bulk // I: Initialization string, or NULL.
|
|
) {
|
|
|
|
if ( bulk != NULL ) {
|
|
___kmp_env_blk_parse_string( block, bulk );
|
|
} else {
|
|
#if KMP_OS_UNIX
|
|
___kmp_env_blk_parse_unix( block, environ );
|
|
#elif KMP_OS_WINDOWS
|
|
{
|
|
char * mem = GetEnvironmentStrings();
|
|
if ( mem == NULL ) {
|
|
DWORD error = GetLastError();
|
|
__kmp_msg(
|
|
kmp_ms_fatal,
|
|
KMP_MSG( CantGetEnvironment ),
|
|
KMP_ERR( error ),
|
|
__kmp_msg_null
|
|
);
|
|
}; // if
|
|
___kmp_env_blk_parse_windows( block, mem );
|
|
FreeEnvironmentStrings( mem );
|
|
}
|
|
#else
|
|
#error Unknown or unsupported OS.
|
|
#endif
|
|
}; // if
|
|
|
|
} // __kmp_env_blk_init
|
|
|
|
|
|
|
|
static
|
|
int
|
|
___kmp_env_var_cmp( // Comparison function for qsort().
|
|
kmp_env_var_t const * lhs,
|
|
kmp_env_var_t const * rhs
|
|
) {
|
|
return strcmp( lhs->name, rhs->name );
|
|
}
|
|
|
|
void
|
|
__kmp_env_blk_sort(
|
|
kmp_env_blk_t * block // M: Block of environment variables to sort.
|
|
) {
|
|
|
|
qsort(
|
|
(void *) block->vars,
|
|
block->count,
|
|
sizeof( kmp_env_var_t ),
|
|
( int ( * )( void const *, void const * ) ) & ___kmp_env_var_cmp
|
|
);
|
|
|
|
} // __kmp_env_block_sort
|
|
|
|
|
|
|
|
void
|
|
__kmp_env_blk_free(
|
|
kmp_env_blk_t * block // M: Block of environment variables to free.
|
|
) {
|
|
|
|
KMP_INTERNAL_FREE( (void *) block->vars );
|
|
KMP_INTERNAL_FREE( (void *) block->bulk );
|
|
|
|
block->count = 0;
|
|
block->vars = NULL;
|
|
block->bulk = NULL;
|
|
|
|
} // __kmp_env_blk_free
|
|
|
|
|
|
|
|
char const * // R: Value of variable or NULL if variable does not exist.
|
|
__kmp_env_blk_var(
|
|
kmp_env_blk_t * block, // I: Block of environment variables.
|
|
char const * name // I: Name of variable to find.
|
|
) {
|
|
|
|
int i;
|
|
for ( i = 0; i < block->count; ++ i ) {
|
|
if ( strcmp( block->vars[ i ].name, name ) == 0 ) {
|
|
return block->vars[ i ].value;
|
|
}; // if
|
|
}; // for
|
|
return NULL;
|
|
|
|
} // __kmp_env_block_var
|
|
|
|
|
|
// end of file //
|