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