kmp_environment.c

Go to the documentation of this file.
00001 /*
00002  * kmp_environment.c -- Handle environment variables OS-independently.
00003  * $Revision: 42263 $
00004  * $Date: 2013-04-04 11:03:19 -0500 (Thu, 04 Apr 2013) $
00005  */
00006 
00007 /* <copyright>
00008     Copyright (c) 1997-2013 Intel Corporation.  All Rights Reserved.
00009 
00010     Redistribution and use in source and binary forms, with or without
00011     modification, are permitted provided that the following conditions
00012     are met:
00013 
00014       * Redistributions of source code must retain the above copyright
00015         notice, this list of conditions and the following disclaimer.
00016       * Redistributions in binary form must reproduce the above copyright
00017         notice, this list of conditions and the following disclaimer in the
00018         documentation and/or other materials provided with the distribution.
00019       * Neither the name of Intel Corporation nor the names of its
00020         contributors may be used to endorse or promote products derived
00021         from this software without specific prior written permission.
00022 
00023     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00026     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 
00035 
00036 ------------------------------------------------------------------------
00037 
00038     Portions of this software are protected under the following patents:
00039         U.S. Patent 5,812,852
00040         U.S. Patent 6,792,599
00041         U.S. Patent 7,069,556
00042         U.S. Patent 7,328,433
00043         U.S. Patent 7,500,242
00044 
00045 </copyright> */
00046 
00047 /*
00048     ------------------------------------------------------------------------------------------------
00049     We use GetEnvironmentVariable for Windows* OS instead of getenv because the act of
00050     loading a DLL on Windows* OS makes any user-set environment variables (i.e. with putenv())
00051     unavailable.  getenv() apparently gets a clean copy of the env variables as they existed
00052     at the start of the run.
00053     JH 12/23/2002
00054     ------------------------------------------------------------------------------------------------
00055     On Windows* OS, there are two environments (at least, see below):
00056 
00057         1. Environment maintained by Windows* OS on IA-32 architecture. 
00058        Accessible through GetEnvironmentVariable(),
00059            SetEnvironmentVariable(), and GetEnvironmentStrings().
00060 
00061         2. Environment maintained by C RTL. Accessible through getenv(), putenv().
00062 
00063     putenv() function updates both C and Windows* OS on IA-32 architecture. getenv() function 
00064     search for variables in C RTL environment only. Windows* OS on IA-32 architecture functions work *only* 
00065     with Windows* OS on IA-32 architecture.
00066 
00067     Windows* OS on IA-32 architecture maintained by OS, so there is always only one Windows* OS on 
00068     IA-32 architecture per process. Changes in Windows* OS on IA-32 architecture are process-visible.
00069 
00070     C environment maintained by C RTL. Multiple copies of C RTL may be present in the process, and
00071     each C RTL maintains its own environment. :-(
00072 
00073     Thus, proper way to work with environment on Windows* OS is:
00074 
00075         1. Set variables with putenv() function -- both C and Windows* OS on
00076        IA-32 architecture are being updated. Windows* OS on 
00077        IA-32 architecture may be considered as primary target,
00078        while updating C RTL environment is a free bonus.
00079 
00080         2. Get variables with GetEnvironmentVariable() -- getenv() does not 
00081        search Windows* OS on IA-32 architecture, and can not see variables
00082        set with SetEnvironmentVariable().
00083 
00084     2007-04-05 -- lev
00085     ------------------------------------------------------------------------------------------------
00086 */
00087 
00088 #include "kmp_environment.h"
00089 
00090 #include "kmp_os.h"    // KMP_OS_*.
00091 #include "kmp.h"       //
00092 #include "kmp_str.h"   // __kmp_str_*().
00093 #include "kmp_i18n.h"
00094 
00095 #if KMP_OS_UNIX
00096     #include <stdlib.h>    // getenv, setenv, unsetenv.
00097     #include <string.h>    // strlen, strcpy.
00098     #if KMP_OS_LINUX
00099         extern char * * environ;
00100     #elif KMP_OS_DARWIN
00101         #include <crt_externs.h>
00102         #define environ (*_NSGetEnviron())
00103     #else
00104         #error Unknown or unsupported OS.
00105     #endif
00106 #elif KMP_OS_WINDOWS
00107     #include <windows.h>   // GetEnvironmentVariable, SetEnvironmentVariable, GetLastError.
00108 #else
00109     #error Unknown or unsupported OS.
00110 #endif
00111 
00112 
00113 // TODO: Eliminate direct memory allocations, use string operations instead.
00114 
00115 static inline
00116 void *
00117 allocate(
00118     size_t size
00119 ) {
00120     void * ptr = KMP_INTERNAL_MALLOC( size );
00121     if ( ptr == NULL ) {
00122     KMP_FATAL( MemoryAllocFailed );
00123     }; // if
00124     return ptr;
00125 } // allocate
00126 
00127 
00128 char *
00129 __kmp_env_get( char const * name ) {
00130 
00131     char * result = NULL;
00132 
00133     #if KMP_OS_UNIX
00134         char const * value = getenv( name );
00135         if ( value != NULL ) {
00136             size_t len = strlen( value ) + 1;
00137             result = (char *) KMP_INTERNAL_MALLOC( len );
00138             if ( result == NULL ) {
00139         KMP_FATAL( MemoryAllocFailed );
00140             }; // if
00141             strncpy( result, value, len );
00142         }; // if
00143     #elif KMP_OS_WINDOWS
00144         /*
00145             We use GetEnvironmentVariable for Windows* OS instead of getenv because the act of
00146             loading a DLL on Windows* OS makes any user-set environment variables (i.e. with putenv())
00147             unavailable.  getenv() apparently gets a clean copy of the env variables as they existed
00148             at the start of the run.
00149             JH 12/23/2002
00150         */
00151         DWORD rc;
00152         rc = GetEnvironmentVariable( name, NULL, 0 );
00153         if ( ! rc ) {
00154             DWORD error = GetLastError();
00155             if ( error != ERROR_ENVVAR_NOT_FOUND ) {
00156                 __kmp_msg(
00157                     kmp_ms_fatal,
00158                     KMP_MSG( CantGetEnvVar, name ),
00159                     KMP_ERR( error ),
00160                     __kmp_msg_null
00161                 );
00162             }; // if
00163             // Variable is not found, it's ok, just continue.
00164         } else {
00165             DWORD len = rc;
00166             result = (char *) KMP_INTERNAL_MALLOC( len );
00167             if ( result == NULL ) {
00168         KMP_FATAL( MemoryAllocFailed );
00169             }; // if
00170             rc = GetEnvironmentVariable( name, result, len );
00171             if ( ! rc ) {
00172                 // GetEnvironmentVariable() may return 0 if variable is empty.
00173                 // In such a case GetLastError() returns ERROR_SUCCESS.
00174                 DWORD error = GetLastError();
00175                 if ( error != ERROR_SUCCESS ) {
00176                     // Unexpected error. The variable should be in the environment,
00177                     // and buffer should be large enough.
00178                     __kmp_msg(
00179                         kmp_ms_fatal,
00180                         KMP_MSG( CantGetEnvVar, name ),
00181                         KMP_ERR( error ),
00182                         __kmp_msg_null
00183                     );
00184                     KMP_INTERNAL_FREE( (void *) result );
00185                     result = NULL;
00186                 }; // if
00187             }; // if
00188         }; // if
00189     #else
00190         #error Unknown or unsupported OS.
00191     #endif
00192 
00193     return result;
00194 
00195 } // func __kmp_env_get
00196 
00197 
00198 // TODO: Find and replace all regular free() with __kmp_env_free().
00199 
00200 void
00201 __kmp_env_free( char const * * value ) {
00202 
00203     KMP_DEBUG_ASSERT( value != NULL );
00204     KMP_INTERNAL_FREE( (void *) * value );
00205     * value = NULL;
00206 
00207 } // func __kmp_env_free
00208 
00209 
00210 
00211 int
00212 __kmp_env_exists( char const * name ) {
00213 
00214     #if KMP_OS_UNIX
00215         char const * value = getenv( name );
00216         return ( ( value == NULL ) ? ( 0 ) : ( 1 ) );
00217     #elif KMP_OS_WINDOWS
00218         DWORD rc;
00219         rc = GetEnvironmentVariable( name, NULL, 0 );
00220         if ( rc == 0 ) {
00221             DWORD error = GetLastError();
00222             if ( error != ERROR_ENVVAR_NOT_FOUND ) {
00223                 __kmp_msg(
00224                     kmp_ms_fatal,
00225                     KMP_MSG( CantGetEnvVar, name ),
00226                     KMP_ERR( error ),
00227                     __kmp_msg_null
00228                 );
00229             }; // if
00230             return 0;
00231         }; // if
00232         return 1;
00233     #else
00234         #error Unknown or unsupported OS.
00235     #endif
00236 
00237 } // func __kmp_env_exists
00238 
00239 
00240 
00241 void
00242 __kmp_env_set( char const * name, char const * value, int overwrite ) {
00243 
00244     #if KMP_OS_UNIX
00245         int rc = setenv( name, value, overwrite );
00246         if ( rc != 0 ) {
00247             // Dead code. I tried to put too many variables into Linux* OS
00248             // environment on IA-32 architecture. When application consumes
00249             // more than ~2.5 GB of memory, entire system feels bad. Sometimes
00250             // application is killed (by OS?), sometimes system stops 
00251             // responding... But this error message never appears. --ln
00252             __kmp_msg(
00253                 kmp_ms_fatal,
00254                 KMP_MSG( CantSetEnvVar, name ),
00255                 KMP_HNT( NotEnoughMemory ),
00256                 __kmp_msg_null
00257             );
00258         }; // if
00259     #elif KMP_OS_WINDOWS
00260         BOOL rc;
00261         if ( ! overwrite ) {
00262             rc = GetEnvironmentVariable( name, NULL, 0 );
00263             if ( rc ) {
00264                 // Variable exists, do not overwrite.
00265                 return;
00266             }; // if
00267             DWORD error = GetLastError();
00268             if ( error != ERROR_ENVVAR_NOT_FOUND ) {
00269                 __kmp_msg(
00270                     kmp_ms_fatal,
00271                     KMP_MSG( CantGetEnvVar, name ),
00272                     KMP_ERR( error ),
00273                     __kmp_msg_null
00274                 );
00275             }; // if
00276         }; // if
00277         rc = SetEnvironmentVariable( name, value );
00278         if ( ! rc ) {
00279             DWORD error = GetLastError();
00280             __kmp_msg(
00281                 kmp_ms_fatal,
00282                 KMP_MSG( CantSetEnvVar, name ),
00283                 KMP_ERR( error ),
00284                 __kmp_msg_null
00285             );
00286         }; // if
00287     #else
00288         #error Unknown or unsupported OS.
00289     #endif
00290 
00291 } // func __kmp_env_set
00292 
00293 
00294 
00295 void
00296 __kmp_env_unset( char const * name ) {
00297 
00298     #if KMP_OS_UNIX
00299         unsetenv( name );
00300     #elif KMP_OS_WINDOWS
00301         BOOL rc = SetEnvironmentVariable( name, NULL );
00302         if ( ! rc ) {
00303             DWORD error = GetLastError();
00304             __kmp_msg(
00305                 kmp_ms_fatal,
00306                 KMP_MSG( CantSetEnvVar, name ),
00307                 KMP_ERR( error ),
00308                 __kmp_msg_null
00309             );
00310         }; // if
00311     #else
00312         #error Unknown or unsupported OS.
00313     #endif
00314 
00315 } // func __kmp_env_unset
00316 
00317 // -------------------------------------------------------------------------------------------------
00318 
00319 /*
00320     Intel OpenMP RTL string representation of environment: just a string of characters, variables
00321     are separated with vertical bars, e. g.:
00322 
00323         "KMP_WARNINGS=0|KMP_AFFINITY=compact|"
00324 
00325     Empty variables are allowed and ignored:
00326 
00327         "||KMP_WARNINGS=1||"
00328 
00329 */
00330 
00331 static
00332 void
00333 ___kmp_env_blk_parse_string(
00334     kmp_env_blk_t * block,   // M: Env block to fill.
00335     char const *    env      // I: String to parse.
00336 ) {
00337 
00338     char const chr_delimiter   = '|';
00339     char const str_delimiter[] = { chr_delimiter, 0 };
00340 
00341     char *          bulk       = NULL;
00342     kmp_env_var_t * vars       = NULL;
00343     int             count      = 0;  // Number of used elements in vars array.
00344     int             delimiters = 0;  // Number of delimiters in input string.
00345 
00346     // Copy original string, we will modify the copy.
00347     bulk = __kmp_str_format( "%s", env );
00348 
00349     // Loop thru all the vars in environment block. Count delimiters (maximum number of variables
00350     // is number of delimiters plus one).
00351     {
00352         char const * ptr = bulk;
00353         for ( ; ; ) {
00354             ptr = strchr( ptr, chr_delimiter );
00355             if ( ptr == NULL ) {
00356                 break;
00357             }; // if
00358             ++ delimiters;
00359             ptr += 1;
00360         }; // forever
00361     }
00362 
00363     // Allocate vars array.
00364     vars = (kmp_env_var_t *) allocate( ( delimiters + 1 ) * sizeof( kmp_env_var_t ) );
00365 
00366     // Loop thru all the variables.
00367     {
00368         char * var;     // Pointer to variable (both name and value).
00369         char * name;    // Pointer to name of variable.
00370         char * value;   // Pointer to value.
00371         char * buf;     // Buffer for __kmp_str_token() function.
00372         var = __kmp_str_token( bulk, str_delimiter, & buf );      // Get the first var.
00373         while ( var != NULL ) {
00374             // Save found variable in vars array.
00375             __kmp_str_split( var, '=', & name, & value );
00376             KMP_DEBUG_ASSERT( count < delimiters + 1 );
00377             vars[ count ].name  = name;
00378             vars[ count ].value = value;
00379             ++ count;
00380             // Get the next var.
00381             var = __kmp_str_token( NULL, str_delimiter, & buf );
00382         }; // while
00383     }
00384 
00385     // Fill out result.
00386     block->bulk  = bulk;
00387     block->vars  = vars;
00388     block->count = count;
00389 
00390 }; // ___kmp_env_blk_parse_string
00391 
00392 
00393 
00394 /*
00395     Windows* OS (actually, DOS) environment block is a piece of memory with environment variables. Each
00396     variable is terminated with zero byte, entire block is terminated with one extra zero byte, so
00397     we have two zero bytes at the end of environment block, e. g.:
00398 
00399         "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
00400 
00401     It is not clear how empty environment is represented. "\x00\x00"?
00402 */
00403 
00404 static
00405 void
00406 ___kmp_env_blk_parse_windows(
00407     kmp_env_blk_t * block,   // M: Env block to fill.
00408     char const *    env      // I: Pointer to Windows* OS (DOS) environment block.
00409 ) {
00410 
00411     char *          bulk  = NULL;
00412     kmp_env_var_t * vars  = NULL;
00413     int             count = 0;     // Number of used elements in vars array.
00414     int             size  = 0;     // Size of bulk.
00415 
00416     char * name;    // Pointer to name of variable.
00417     char * value;   // Pointer to value.
00418 
00419     if ( env != NULL ) {
00420 
00421         // Loop thru all the vars in environment block. Count variables, find size of block.
00422         {
00423             char const * var;     // Pointer to beginning of var.
00424             int          len;     // Length of variable.
00425             count = 0;
00426             var = env;            // The first variable starts and beginning of environment block.
00427             len = strlen( var );
00428             while ( len != 0 ) {
00429                 ++ count;
00430                 size = size + len + 1;
00431                 var = var + len + 1; // Move pointer to the beginning of the next variable.
00432                 len = strlen( var );
00433             }; // while
00434             size = size + 1;         // Total size of env block, including terminating zero byte.
00435         }
00436 
00437         // Copy original block to bulk, we will modify bulk, not original block.
00438         bulk = (char *) allocate( size );
00439         memcpy( bulk, env, size );
00440         // Allocate vars array.
00441         vars = (kmp_env_var_t *) allocate( count * sizeof( kmp_env_var_t ) );
00442 
00443         // Loop thru all the vars, now in bulk.
00444         {
00445             char * var;     // Pointer to beginning of var.
00446             int    len;     // Length of variable.
00447             count = 0;
00448             var = bulk;
00449             len = strlen( var );
00450             while ( len != 0 ) {
00451                 // Save variable in vars array.
00452                 __kmp_str_split( var, '=', & name, & value );
00453                 vars[ count ].name  = name;
00454                 vars[ count ].value = value;
00455                 ++ count;
00456                 // Get the next var.
00457                 var = var + len + 1;
00458                 len = strlen( var );
00459             }; // while
00460         }
00461 
00462     }; // if
00463 
00464     // Fill out result.
00465     block->bulk  = bulk;
00466     block->vars  = vars;
00467     block->count = count;
00468 
00469 }; // ___kmp_env_blk_parse_windows
00470 
00471 
00472 
00473 /*
00474     Unix environment block is a array of pointers to variables, last pointer in array is NULL:
00475 
00476         { "HOME=/home/lev", "TERM=xterm", NULL }
00477 */
00478 
00479 static
00480 void
00481 ___kmp_env_blk_parse_unix(
00482     kmp_env_blk_t * block,   // M: Env block to fill.
00483     char * *        env      // I: Unix environment to parse.
00484 ) {
00485 
00486     char *          bulk  = NULL;
00487     kmp_env_var_t * vars  = NULL;
00488     int             count = 0;
00489     int             size  = 0;    // Size of bulk.
00490 
00491     // Count number of variables and length of required bulk.
00492     {
00493         count = 0;
00494         size  = 0;
00495         while ( env[ count ] != NULL ) {
00496             size += strlen( env[ count ] ) + 1;
00497             ++ count;
00498         }; // while
00499     }
00500 
00501     // Allocate memory.
00502     bulk = (char *) allocate( size );
00503     vars = (kmp_env_var_t *) allocate( count * sizeof( kmp_env_var_t ) );
00504 
00505     // Loop thru all the vars.
00506     {
00507         char * var;     // Pointer to beginning of var.
00508         char * name;    // Pointer to name of variable.
00509         char * value;   // Pointer to value.
00510         int    len;     // Length of variable.
00511         int    i;
00512         var = bulk;
00513         for ( i = 0; i < count; ++ i ) {
00514             // Copy variable to bulk.
00515             len = strlen( env[ i ] );
00516             memcpy( var, env[ i ], len + 1 );
00517             // Save found variable in vars array.
00518             __kmp_str_split( var, '=', & name, & value );
00519             vars[ i ].name  = name;
00520             vars[ i ].value = value;
00521             // Move pointer.
00522             var += len + 1;
00523         }; // for
00524     }
00525 
00526     // Fill out result.
00527     block->bulk  = bulk;
00528     block->vars  = vars;
00529     block->count = count;
00530 
00531 }; // ___kmp_env_blk_parse_unix
00532 
00533 
00534 
00535 void
00536 __kmp_env_blk_init(
00537     kmp_env_blk_t * block,  // M: Block to initialize.
00538     char const *    bulk    // I: Initialization string, or NULL.
00539 ) {
00540 
00541     if ( bulk != NULL ) {
00542         ___kmp_env_blk_parse_string( block, bulk );
00543     } else {
00544         #if KMP_OS_UNIX
00545             ___kmp_env_blk_parse_unix( block, environ );
00546         #elif KMP_OS_WINDOWS
00547             {
00548                 char * mem = GetEnvironmentStrings();
00549                 if ( mem == NULL ) {
00550                     DWORD error = GetLastError();
00551                     __kmp_msg(
00552                         kmp_ms_fatal,
00553                         KMP_MSG( CantGetEnvironment ),
00554                         KMP_ERR( error ),
00555                         __kmp_msg_null
00556                     );
00557                 }; // if
00558                 ___kmp_env_blk_parse_windows( block, mem );
00559                 FreeEnvironmentStrings( mem );
00560             }
00561         #else
00562             #error Unknown or unsupported OS.
00563         #endif
00564     }; // if
00565 
00566 } // __kmp_env_blk_init
00567 
00568 
00569 
00570 static
00571 int
00572 ___kmp_env_var_cmp(                              // Comparison function for qsort().
00573     kmp_env_var_t const * lhs,
00574     kmp_env_var_t const * rhs
00575 ) {
00576     return strcmp( lhs->name, rhs->name );
00577 }
00578 
00579 void
00580 __kmp_env_blk_sort(
00581     kmp_env_blk_t * block  // M: Block of environment variables to sort.
00582 ) {
00583 
00584     qsort(
00585         (void *) block->vars,
00586         block->count,
00587         sizeof( kmp_env_var_t ),
00588         ( int ( * )( void const *, void const * ) ) & ___kmp_env_var_cmp
00589     );
00590 
00591 } // __kmp_env_block_sort
00592 
00593 
00594 
00595 void
00596 __kmp_env_blk_free(
00597     kmp_env_blk_t * block  // M: Block of environment variables to free.
00598 ) {
00599 
00600     KMP_INTERNAL_FREE( (void *) block->vars );
00601     KMP_INTERNAL_FREE( (void *) block->bulk );
00602 
00603     block->count = 0;
00604     block->vars  = NULL;
00605     block->bulk  = NULL;
00606 
00607 } // __kmp_env_blk_free
00608 
00609 
00610 
00611 char const *               // R: Value of variable or NULL if variable does not exist.
00612 __kmp_env_blk_var(
00613     kmp_env_blk_t * block, // I: Block of environment variables.
00614     char const *    name   // I: Name of variable to find.
00615 ) {
00616 
00617     int i;
00618     for ( i = 0; i < block->count; ++ i ) {
00619         if ( strcmp( block->vars[ i ].name, name ) == 0 ) {
00620             return block->vars[ i ].value;
00621         }; // if
00622     }; // for
00623     return NULL;
00624 
00625 } // __kmp_env_block_var
00626 
00627 
00628 // end of file //

Generated on 25 Aug 2013 for libomp_oss by  doxygen 1.6.1