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
abort(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
atexit(void (* handler)(void))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
exit(int status)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
_Exit(int status)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
system(const char * string)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 **/
getenv(const char * name)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
setenv(register const char * name,register const char * value,int rewrite)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