Home | History | Annotate | Download | only in StdLib
      1 /** @file
      2   Implementation of the <stdlib.h> functions responsible for communication with
      3   the environment:
      4     - abort(void)
      5     - atexit(void(*handler)(void))
      6     - exit(int status)
      7     - _Exit(int status)
      8 
      9   Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
     10   This program and the accompanying materials are licensed and made available under
     11   the terms and conditions of the BSD License that accompanies this distribution.
     12   The full text of the license may be found at
     13   http://opensource.org/licenses/bsd-license.
     14 
     15   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     16   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     17 
     18 **/
     19 #include  <Uefi.h>
     20 #include  <Library/UefiBootServicesTableLib.h>
     21 #include  <Library/BaseLib.h>
     22 #include  <Library/MemoryAllocationLib.h>
     23 #include  <Library/ShellLib.h>
     24 
     25 #include  <LibConfig.h>
     26 
     27 #include  <errno.h>
     28 #include  <signal.h>
     29 #include  <stdlib.h>
     30 #include  <MainData.h>
     31 
     32 /** Internal worker function used by exit().
     33 **/
     34 void  exitCleanup(INTN ExitVal);
     35 
     36 /* #################  Public Functions  ################################### */
     37 
     38 /** The abort function causes abnormal program termination to occur, unless
     39     the signal SIGABRT is being caught and the signal handler does not return.
     40 
     41     Open streams with unwritten buffered data are not flushed, open
     42     streams are not closed, and temporary files are not removed by abort.
     43 
     44 **/
     45 void
     46 abort(void)
     47 {
     48   if (!gMD->aborting) {
     49     gMD->aborting = TRUE;
     50 
     51     if (gMD->cleanup != NULL) {
     52       gMD->cleanup();
     53     }
     54   }
     55   raise(SIGABRT);
     56   _Exit(EXIT_FAILURE);  // In case raise returns.
     57 }
     58 
     59 /** The atexit function registers the function pointed to by func, to be
     60     called without arguments at normal program termination.
     61 
     62     The implementation shall support the registration of
     63     at least 32 functions.
     64 
     65     @return   The atexit function returns zero if the registration succeeds,
     66               nonzero if it fails.
     67 **/
     68 int
     69 atexit(void (*handler)(void))
     70 {
     71   int   retval = 1;
     72 
     73   if((handler != NULL) && (gMD->num_atexit < ATEXIT_MAX)) {
     74     gMD->atexit_handler[gMD->num_atexit++] = handler;
     75     retval = 0;
     76   }
     77   return retval;
     78 }
     79 
     80 /** The exit function causes normal program termination to occur. If more than
     81     one call to the exit function is executed by a program,
     82     the behavior is undefined.
     83 
     84     First, all functions registered by the atexit function are called, in the
     85     reverse order of their registration. If, during the call to any such function, a
     86     call to the longjmp function is made that would terminate the call to the
     87     registered function, the behavior is undefined.
     88 
     89     Next, all open streams with unwritten buffered data are flushed, all open
     90     streams are closed, and all files created by the tmpfile function
     91     are removed.
     92 
     93     The status returned to the host environment is determined in the same way
     94     as for the _Exit function.
     95 **/
     96 void
     97 exit(int status)
     98 {
     99   exitCleanup((INTN) status);
    100   _Exit(status);
    101 }
    102 
    103 /** The _Exit function causes normal program termination to occur and control
    104     to be returned to the host environment.
    105 
    106     No functions registered by the atexit function or signal handlers
    107     registered by the signal function are called.  Open streams with unwritten
    108     buffered data are not flushed, open streams are not closed, and temporary
    109     files are not removed by abort.
    110 
    111     Finally, control is returned to the host environment. If the value of
    112     status is zero, or EXIT_SUCCESS, status is returned unchanged. If the value
    113     of status is EXIT_FAILURE, RETURN_ABORTED is returned.
    114     Otherwise, status is returned unchanged.
    115 **/
    116 void
    117 _Exit(int status)
    118 {
    119   gMD->ExitValue = status;          // Save our exit status.  Allows a status of 0.
    120   longjmp(gMD->MainExit, 0x55);     // Get out of here.  longjmp can't return 0. Use 0x55 for a non-zero value.
    121 
    122 #ifdef __GNUC__
    123   _Exit(status);        /* Keep GCC happy - never reached */
    124 #endif
    125 }
    126 
    127 /** If string is a null pointer, the system function determines whether the
    128     host environment has a command processor. If string is not a null pointer,
    129     the system function passes the string pointed to by string to that command
    130     processor to be executed in a manner which the implementation shall
    131     document; this might then cause the program calling system to behave in a
    132     non-conforming manner or to terminate.
    133 
    134     @retval   EXIT_FAILURE    EFIerrno will contain the EFI status code
    135                               indicating the cause of failure.
    136 
    137     @retval   EXIT_SUCCESS    EFIerrno will contain the EFI status returned
    138                               by the executed command string.
    139     @retval   0               If string is NULL, 0 means a command processor
    140                               is not available.
    141     @retval   1               If string is NULL, 1 means a command processor
    142                               is available.
    143 **/
    144 int
    145 system(const char *string)
    146 {
    147   EFI_STATUS  CmdStat;
    148   EFI_STATUS  OpStat;
    149   EFI_HANDLE  MyHandle = gImageHandle;
    150 
    151   if( string == NULL) {
    152     return 1;
    153   }
    154   (void)AsciiStrToUnicodeStr( string, gMD->UString);
    155   OpStat = ShellExecute( &MyHandle, gMD->UString, FALSE, NULL, &CmdStat);
    156   if(OpStat == RETURN_SUCCESS) {
    157     EFIerrno = CmdStat;
    158     return EXIT_SUCCESS;
    159   }
    160   EFIerrno = OpStat;
    161   return EXIT_FAILURE;
    162 }
    163 
    164 /** The getenv function searches an environment list, provided by the host
    165     environment, for a string that matches the string pointed to by name.  The
    166     set of environment names and the method for altering the environment list
    167     are determined by the underlying UEFI Shell implementation.
    168 
    169     @return   The getenv function returns a pointer to a string associated with
    170               the matched list member.  The string pointed to shall not be
    171               modified by the program, but may be overwritten by a subsequent
    172               call to the getenv function.  If the specified name cannot be
    173               found, a null pointer is returned.
    174 **/
    175 char   *getenv(const char *name)
    176 {
    177   const CHAR16  *EfiEnv;
    178   char          *retval = NULL;
    179 
    180   (void)AsciiStrToUnicodeStr( name, gMD->UString);
    181   EfiEnv = ShellGetEnvironmentVariable(gMD->UString);
    182   if(EfiEnv != NULL) {
    183     retval = UnicodeStrToAsciiStr( EfiEnv, gMD->ASgetenv);
    184   }
    185 
    186   return retval;
    187 }
    188 
    189 
    190 /**
    191   Add or update a variable in the environment list
    192 
    193   @param name     Address of a zero terminated name string
    194   @param value    Address of a zero terminated value string
    195   @param rewrite  TRUE allows overwriting existing values
    196 
    197   @retval Returns 0 upon success
    198   @retval Returns -1 upon failure, sets errno with more information
    199 
    200   Errors
    201 
    202   EINVAL - name is NULL or points to a zero length string
    203   EALREADY - name already set and rewrite set to FALSE
    204   ENODEV - Unable to set non-volatile version of environment variable
    205   ENOMEM - Unable to set volatile version of environment variable
    206   ENOTSUP - Variable storage not supported
    207 
    208 **/
    209 int
    210 setenv (
    211   register const char * name,
    212   register const char * value,
    213   int rewrite
    214   )
    215 {
    216   CONST CHAR16 * HostName;
    217   int retval;
    218   EFI_STATUS Status;
    219   CHAR16 * UName;
    220   CHAR16 * UValue;
    221 
    222   //
    223   //  Assume failure
    224   //
    225   retval = -1;
    226 
    227   //
    228   //  Validate the inputs
    229   //
    230   errno = EINVAL;
    231   if (( NULL != name ) && ( 0 != *name )) {
    232     //
    233     //  Get the storage locations for the unicode strings
    234     //
    235     UName = &gMD->UString[0];
    236     UValue = &gMD->UString2[0];
    237 
    238     //
    239     //  Convert the strings
    240     //
    241     AsciiStrToUnicodeStr ( name, UName );
    242     AsciiStrToUnicodeStr ( value, UValue );
    243 
    244     //
    245     //  Determine if the string is already present
    246     //
    247     errno = EALREADY;
    248     HostName = ShellGetEnvironmentVariable ( UName );
    249     if ( rewrite || ( NULL == HostName )) {
    250       //
    251       //  Support systems that don't have non-volatile memory
    252       //
    253       errno = ENOMEM;
    254       Status = ShellSetEnvironmentVariable ( UName, UValue, TRUE );
    255       if ( EFI_ERROR ( Status )) {
    256         if ( EFI_UNSUPPORTED == Status ) {
    257           errno = ENOTSUP;
    258         }
    259       }
    260       else {
    261         //
    262         //  Permanently set the environment variable
    263         //
    264         errno = ENODEV;
    265         Status = ShellSetEnvironmentVariable ( UName, UValue, FALSE );
    266         if ( !EFI_ERROR ( Status )) {
    267           //
    268           //  Success
    269           //
    270           errno = 0;
    271           retval = 0;
    272         }
    273       }
    274     }
    275   }
    276 
    277   //
    278   //  Return the operation status
    279   //
    280   return retval;
    281 }
    282 
    283