]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Application/Shell/ShellProtocol.c
ShellPkg/IsVolatileEnv: Handle memory allocation failure
[mirror_edk2.git] / ShellPkg / Application / Shell / ShellProtocol.c
CommitLineData
a405b86d 1/** @file\r
2 Member functions of EFI_SHELL_PROTOCOL and functions for creation,\r
3 manipulation, and initialization of EFI_SHELL_PROTOCOL.\r
4\r
c011b6c9 5 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>\r
dcbdb8bf 6 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
a405b86d 7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "Shell.h"\r
a405b86d 18\r
654a012b
QS
19#define INIT_NAME_BUFFER_SIZE 128\r
20\r
a405b86d 21/**\r
22 Close an open file handle.\r
23\r
24 This function closes a specified file handle. All "dirty" cached file data is\r
25 flushed to the device, and the file is closed. In all cases the handle is\r
26 closed.\r
27\r
28 @param[in] FileHandle The file handle to close.\r
29\r
30 @retval EFI_SUCCESS The file handle was closed successfully.\r
31**/\r
32EFI_STATUS\r
33EFIAPI\r
34EfiShellClose (\r
35 IN SHELL_FILE_HANDLE FileHandle\r
36 )\r
37{\r
38 ShellFileHandleRemove(FileHandle);\r
8be0ba36 39 return (FileHandleClose(ConvertShellHandleToEfiFileProtocol(FileHandle)));\r
a405b86d 40}\r
41\r
733f138d 42/**\r
43 Internal worker to determine whether there is a BlockIo somewhere\r
44 upon the device path specified.\r
45\r
46 @param[in] DevicePath The device path to test.\r
47\r
48 @retval TRUE gEfiBlockIoProtocolGuid was installed on a handle with this device path\r
49 @retval FALSE gEfiBlockIoProtocolGuid was not found.\r
50**/\r
51BOOLEAN\r
52EFIAPI\r
53InternalShellProtocolIsBlockIoPresent(\r
54 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
55 )\r
56{\r
57 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
58 EFI_STATUS Status;\r
59 EFI_HANDLE Handle;\r
60\r
61 Handle = NULL;\r
62\r
63 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath;\r
64 Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, &DevicePathCopy, &Handle);\r
65\r
66 if ((Handle != NULL) && (!EFI_ERROR(Status))) {\r
67 return (TRUE);\r
68 }\r
69 return (FALSE);\r
70}\r
71\r
a405b86d 72/**\r
73 Internal worker to determine whether there is a file system somewhere\r
74 upon the device path specified.\r
75\r
76 @param[in] DevicePath The device path to test.\r
77\r
78 @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path\r
79 @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found.\r
80**/\r
81BOOLEAN\r
82EFIAPI\r
83InternalShellProtocolIsSimpleFileSystemPresent(\r
84 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
85 )\r
86{\r
87 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
88 EFI_STATUS Status;\r
89 EFI_HANDLE Handle;\r
90\r
91 Handle = NULL;\r
92\r
93 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)DevicePath;\r
94 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);\r
95\r
96 if ((Handle != NULL) && (!EFI_ERROR(Status))) {\r
97 return (TRUE);\r
98 }\r
99 return (FALSE);\r
100}\r
101\r
102/**\r
103 Internal worker debug helper function to print out maps as they are added.\r
104\r
105 @param[in] Mapping string mapping that has been added\r
106 @param[in] DevicePath pointer to device path that has been mapped.\r
107\r
108 @retval EFI_SUCCESS the operation was successful.\r
109 @return other an error ocurred\r
110\r
111 @sa LocateHandle\r
112 @sa OpenProtocol\r
113**/\r
114EFI_STATUS\r
115EFIAPI\r
116InternalShellProtocolDebugPrintMessage (\r
117 IN CONST CHAR16 *Mapping,\r
118 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath\r
119 )\r
120{\r
a405b86d 121 EFI_STATUS Status;\r
122 CHAR16 *Temp;\r
123\r
e3df6949 124 Status = EFI_SUCCESS;\r
a405b86d 125 DEBUG_CODE_BEGIN();\r
a405b86d 126\r
a405b86d 127 if (Mapping != NULL) {\r
128 DEBUG((EFI_D_INFO, "Added new map item:\"%S\"\r\n", Mapping));\r
129 }\r
863986b3
RN
130 Temp = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
131 DEBUG((EFI_D_INFO, "DevicePath: %S\r\n", Temp));\r
132 FreePool(Temp);\r
133\r
a405b86d 134 DEBUG_CODE_END();\r
135 return (Status);\r
136}\r
137\r
138/**\r
139 This function creates a mapping for a device path.\r
140\r
141 If both DeviecPath and Mapping are NULL, this will reset the mapping to default values.\r
142\r
143 @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping,\r
144 then the mapping will be deleted.\r
145 @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':'\r
146\r
147 @retval EFI_SUCCESS Mapping created or deleted successfully.\r
148 @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the\r
149 boot service function LocateDevicePath().\r
150 @retval EFI_ACCESS_DENIED The mapping is a built-in alias.\r
151 @retval EFI_INVALID_PARAMETER Mapping was NULL\r
152 @retval EFI_INVALID_PARAMETER Mapping did not end with a ':'\r
153 @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed.\r
154 @retval EFI_NOT_FOUND There was no mapping found to delete\r
155 @retval EFI_OUT_OF_RESOURCES Memory allocation failed\r
156**/\r
157EFI_STATUS\r
158EFIAPI\r
159EfiShellSetMap(\r
160 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,\r
161 IN CONST CHAR16 *Mapping\r
162 )\r
163{\r
164 EFI_STATUS Status;\r
165 SHELL_MAP_LIST *MapListNode;\r
166\r
167 if (Mapping == NULL){\r
168 return (EFI_INVALID_PARAMETER);\r
169 }\r
170\r
171 if (Mapping[StrLen(Mapping)-1] != ':') {\r
172 return (EFI_INVALID_PARAMETER);\r
173 }\r
174\r
175 //\r
176 // Delete the mapping\r
177 //\r
178 if (DevicePath == NULL) {\r
179 if (IsListEmpty(&gShellMapList.Link)) {\r
180 return (EFI_NOT_FOUND);\r
181 }\r
182 for ( MapListNode = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
183 ; !IsNull(&gShellMapList.Link, &MapListNode->Link)\r
184 ; MapListNode = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListNode->Link)\r
185 ){\r
186 if (StringNoCaseCompare(&MapListNode->MapName, &Mapping) == 0) {\r
187 RemoveEntryList(&MapListNode->Link);\r
4aec9fe3
JY
188 SHELL_FREE_NON_NULL(MapListNode->DevicePath);\r
189 SHELL_FREE_NON_NULL(MapListNode->MapName);\r
190 SHELL_FREE_NON_NULL(MapListNode->CurrentDirectoryPath);\r
a405b86d 191 FreePool(MapListNode);\r
192 return (EFI_SUCCESS);\r
193 }\r
194 } // for loop\r
195\r
196 //\r
197 // We didnt find one to delete\r
198 //\r
199 return (EFI_NOT_FOUND);\r
200 }\r
201\r
202 //\r
203 // make sure this is a valid to add device path\r
204 //\r
205 ///@todo add BlockIo to this test...\r
733f138d 206 if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath)\r
207 && !InternalShellProtocolIsBlockIoPresent(DevicePath)) {\r
a405b86d 208 return (EFI_INVALID_PARAMETER);\r
209 }\r
210\r
211 //\r
212 // First make sure there is no old mapping\r
213 //\r
214 Status = EfiShellSetMap(NULL, Mapping);\r
215 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_FOUND)) {\r
216 return (Status);\r
217 }\r
218\r
219 //\r
220 // now add the new one.\r
221 //\r
222 Status = ShellCommandAddMapItemAndUpdatePath(Mapping, DevicePath, 0, FALSE);\r
223\r
224 return(Status);\r
225}\r
226\r
227/**\r
228 Gets the device path from the mapping.\r
229\r
230 This function gets the device path associated with a mapping.\r
231\r
232 @param Mapping A pointer to the mapping\r
233\r
234 @retval !=NULL Pointer to the device path that corresponds to the\r
235 device mapping. The returned pointer does not need\r
236 to be freed.\r
237 @retval NULL There is no device path associated with the\r
238 specified mapping.\r
239**/\r
240CONST EFI_DEVICE_PATH_PROTOCOL *\r
241EFIAPI\r
242EfiShellGetDevicePathFromMap(\r
243 IN CONST CHAR16 *Mapping\r
244 )\r
245{\r
246 SHELL_MAP_LIST *MapListItem;\r
247 CHAR16 *NewName;\r
248 UINTN Size;\r
249\r
250 NewName = NULL;\r
251 Size = 0;\r
252\r
253 StrnCatGrow(&NewName, &Size, Mapping, 0);\r
254 if (Mapping[StrLen(Mapping)-1] != L':') {\r
255 StrnCatGrow(&NewName, &Size, L":", 0);\r
256 }\r
257\r
258 MapListItem = ShellCommandFindMapItem(NewName);\r
259\r
260 FreePool(NewName);\r
261\r
262 if (MapListItem != NULL) {\r
263 return (MapListItem->DevicePath);\r
264 }\r
265 return(NULL);\r
266}\r
267\r
268/**\r
269 Gets the mapping(s) that most closely matches the device path.\r
270\r
271 This function gets the mapping which corresponds to the device path *DevicePath. If\r
272 there is no exact match, then the mapping which most closely matches *DevicePath\r
273 is returned, and *DevicePath is updated to point to the remaining portion of the\r
274 device path. If there is an exact match, the mapping is returned and *DevicePath\r
275 points to the end-of-device-path node.\r
276\r
277 If there are multiple map names they will be semi-colon seperated in the\r
278 NULL-terminated string.\r
279\r
280 @param DevicePath On entry, points to a device path pointer. On\r
281 exit, updates the pointer to point to the\r
282 portion of the device path after the mapping.\r
283\r
284 @retval NULL No mapping was found.\r
285 @return !=NULL Pointer to NULL-terminated mapping. The buffer\r
286 is callee allocated and should be freed by the caller.\r
287**/\r
288CONST CHAR16 *\r
289EFIAPI\r
290EfiShellGetMapFromDevicePath(\r
291 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
292 )\r
293{\r
294 SHELL_MAP_LIST *Node;\r
295 CHAR16 *PathForReturn;\r
296 UINTN PathSize;\r
297// EFI_HANDLE PathHandle;\r
298// EFI_HANDLE MapHandle;\r
299// EFI_STATUS Status;\r
300// EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
301// EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;\r
302\r
303 if (DevicePath == NULL || *DevicePath == NULL) {\r
304 return (NULL);\r
305 }\r
306\r
307 PathForReturn = NULL;\r
308 PathSize = 0;\r
309\r
310 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
311 ; !IsNull(&gShellMapList.Link, &Node->Link)\r
312 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
313 ){\r
314 //\r
315 // check for exact match\r
316 //\r
317 if (DevicePathCompare(DevicePath, &Node->DevicePath) == 0) {\r
318 ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
319 if (PathSize != 0) {\r
320 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
321 }\r
322 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
323 }\r
324 }\r
325 if (PathForReturn != NULL) {\r
326 while (!IsDevicePathEndType (*DevicePath)) {\r
327 *DevicePath = NextDevicePathNode (*DevicePath);\r
328 }\r
329 SetDevicePathEndNode (*DevicePath);\r
330 }\r
331/*\r
332 ///@todo finish code for inexact matches.\r
333 if (PathForReturn == NULL) {\r
334 PathSize = 0;\r
335\r
336 DevicePathCopy = DuplicateDevicePath(*DevicePath);\r
337 ASSERT(DevicePathCopy != NULL);\r
338 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);\r
339 ASSERT_EFI_ERROR(Status);\r
340 //\r
341 // check each of the device paths we have to get the root of the path for consist mappings\r
342 //\r
343 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
344 ; !IsNull(&gShellMapList.Link, &Node->Link)\r
345 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
346 ){\r
347 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) {\r
348 continue;\r
349 }\r
350 MapPathCopy = DuplicateDevicePath(Node->DevicePath);\r
351 ASSERT(MapPathCopy != NULL);\r
352 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
353 if (MapHandle == PathHandle) {\r
354\r
355 *DevicePath = DevicePathCopy;\r
356\r
357 MapPathCopy = NULL;\r
358 DevicePathCopy = NULL;\r
359 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
360 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
361 break;\r
362 }\r
363 }\r
364 //\r
365 // now add on the non-consistent mappings\r
366 //\r
367 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
368 ; !IsNull(&gShellMapList.Link, &Node->Link)\r
369 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)\r
370 ){\r
371 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) {\r
372 continue;\r
373 }\r
374 MapPathCopy = Node->DevicePath;\r
375 ASSERT(MapPathCopy != NULL);\r
376 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
377 if (MapHandle == PathHandle) {\r
378 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);\r
379 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);\r
380 break;\r
381 }\r
382 }\r
383 }\r
384*/\r
385\r
386 return (AddBufferToFreeList(PathForReturn));\r
387}\r
388\r
389/**\r
390 Converts a device path to a file system-style path.\r
391\r
392 This function converts a device path to a file system path by replacing part, or all, of\r
393 the device path with the file-system mapping. If there are more than one application\r
394 file system mappings, the one that most closely matches Path will be used.\r
395\r
396 @param Path The pointer to the device path\r
397\r
398 @retval NULL the device path could not be found.\r
399 @return all The pointer of the NULL-terminated file path. The path\r
400 is callee-allocated and should be freed by the caller.\r
401**/\r
402CHAR16 *\r
403EFIAPI\r
404EfiShellGetFilePathFromDevicePath(\r
405 IN CONST EFI_DEVICE_PATH_PROTOCOL *Path\r
406 )\r
407{\r
408 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
409 EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;\r
410 SHELL_MAP_LIST *MapListItem;\r
411 CHAR16 *PathForReturn;\r
412 UINTN PathSize;\r
413 EFI_HANDLE PathHandle;\r
414 EFI_HANDLE MapHandle;\r
415 EFI_STATUS Status;\r
416 FILEPATH_DEVICE_PATH *FilePath;\r
f5020428 417 FILEPATH_DEVICE_PATH *AlignedNode;\r
a405b86d 418\r
419 PathForReturn = NULL;\r
420 PathSize = 0;\r
421\r
422 DevicePathCopy = (EFI_DEVICE_PATH_PROTOCOL*)Path;\r
423 ASSERT(DevicePathCopy != NULL);\r
424 if (DevicePathCopy == NULL) {\r
425 return (NULL);\r
426 }\r
427 ///@todo BlockIo?\r
428 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);\r
429\r
430 if (EFI_ERROR(Status)) {\r
431 return (NULL);\r
432 }\r
433 //\r
434 // check each of the device paths we have to get the root of the path\r
435 //\r
436 for ( MapListItem = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)\r
437 ; !IsNull(&gShellMapList.Link, &MapListItem->Link)\r
438 ; MapListItem = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &MapListItem->Link)\r
439 ){\r
440 MapPathCopy = (EFI_DEVICE_PATH_PROTOCOL*)MapListItem->DevicePath;\r
441 ASSERT(MapPathCopy != NULL);\r
442 ///@todo BlockIo?\r
443 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);\r
444 if (MapHandle == PathHandle) {\r
445 ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
446 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, MapListItem->MapName, 0);\r
447 //\r
448 // go through all the remaining nodes in the device path\r
449 //\r
450 for ( FilePath = (FILEPATH_DEVICE_PATH*)DevicePathCopy\r
451 ; !IsDevicePathEnd (&FilePath->Header)\r
452 ; FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode (&FilePath->Header)\r
453 ){\r
454 //\r
898378c2 455 // If any node is not a file path node, then the conversion can not be completed\r
a405b86d 456 //\r
457 if ((DevicePathType(&FilePath->Header) != MEDIA_DEVICE_PATH) ||\r
458 (DevicePathSubType(&FilePath->Header) != MEDIA_FILEPATH_DP)) {\r
459 FreePool(PathForReturn);\r
898378c2
MK
460 return NULL;\r
461 }\r
6ddc2ff3 462\r
898378c2
MK
463 //\r
464 // append the path part onto the filepath.\r
465 //\r
466 ASSERT((PathForReturn == NULL && PathSize == 0) || (PathForReturn != NULL));\r
467\r
468 AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePath), FilePath);\r
469 ASSERT (AlignedNode != NULL);\r
470\r
471 // File Path Device Path Nodes 'can optionally add a "\" separator to\r
472 // the beginning and/or the end of the Path Name string.'\r
473 // (UEFI Spec 2.4 section 9.3.6.4).\r
474 // If necessary, add a "\", but otherwise don't\r
475 // (This is specified in the above section, and also implied by the\r
476 // UEFI Shell spec section 3.7)\r
477 if ((PathSize != 0) &&\r
478 (PathForReturn != NULL) &&\r
479 (PathForReturn[PathSize - 1] != L'\\') &&\r
480 (AlignedNode->PathName[0] != L'\\')) {\r
481 PathForReturn = StrnCatGrow (&PathForReturn, &PathSize, L"\\", 1);\r
a405b86d 482 }\r
898378c2
MK
483\r
484 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, AlignedNode->PathName, 0);\r
485 FreePool(AlignedNode);\r
a405b86d 486 } // for loop of remaining nodes\r
487 }\r
488 if (PathForReturn != NULL) {\r
489 break;\r
490 }\r
491 } // for loop of paths to check\r
492 return(PathForReturn);\r
493}\r
494\r
495/**\r
496 Converts a file system style name to a device path.\r
497\r
498 This function converts a file system style name to a device path, by replacing any\r
499 mapping references to the associated device path.\r
500\r
532691c8 501 @param[in] Path The pointer to the path.\r
a405b86d 502\r
532691c8 503 @return The pointer of the file path. The file path is callee\r
a405b86d 504 allocated and should be freed by the caller.\r
532691c8 505 @retval NULL The path could not be found.\r
506 @retval NULL There was not enough available memory.\r
a405b86d 507**/\r
508EFI_DEVICE_PATH_PROTOCOL *\r
509EFIAPI\r
510EfiShellGetDevicePathFromFilePath(\r
511 IN CONST CHAR16 *Path\r
512 )\r
513{\r
514 CHAR16 *MapName;\r
515 CHAR16 *NewPath;\r
516 CONST CHAR16 *Cwd;\r
517 UINTN Size;\r
518 CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
519 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;\r
520 EFI_DEVICE_PATH_PROTOCOL *DevicePathCopyForFree;\r
521 EFI_DEVICE_PATH_PROTOCOL *DevicePathForReturn;\r
522 EFI_HANDLE Handle;\r
523 EFI_STATUS Status;\r
524\r
8be0ba36 525 if (Path == NULL) {\r
526 return (NULL);\r
527 }\r
528\r
a405b86d 529 MapName = NULL;\r
8be0ba36 530 NewPath = NULL;\r
a405b86d 531\r
532 if (StrStr(Path, L":") == NULL) {\r
533 Cwd = EfiShellGetCurDir(NULL);\r
534 if (Cwd == NULL) {\r
535 return (NULL);\r
536 }\r
fbd2dfad 537 Size = StrSize(Cwd) + StrSize(Path);\r
a405b86d 538 NewPath = AllocateZeroPool(Size);\r
532691c8 539 if (NewPath == NULL) {\r
540 return (NULL);\r
541 }\r
e75390f0 542 StrCpyS(NewPath, Size/sizeof(CHAR16), Cwd);\r
fbd2dfad 543 StrCatS(NewPath, Size/sizeof(CHAR16), L"\\");\r
733f138d 544 if (*Path == L'\\') {\r
545 Path++;\r
ab94587a 546 while (PathRemoveLastItem(NewPath)) ;\r
a405b86d 547 }\r
e75390f0 548 StrCatS(NewPath, Size/sizeof(CHAR16), Path);\r
a405b86d 549 DevicePathForReturn = EfiShellGetDevicePathFromFilePath(NewPath);\r
550 FreePool(NewPath);\r
551 return (DevicePathForReturn);\r
552 }\r
553\r
554 Size = 0;\r
555 //\r
556 // find the part before (but including) the : for the map name\r
557 //\r
558 ASSERT((MapName == NULL && Size == 0) || (MapName != NULL));\r
559 MapName = StrnCatGrow(&MapName, &Size, Path, (StrStr(Path, L":")-Path+1));\r
532691c8 560 if (MapName == NULL || MapName[StrLen(MapName)-1] != L':') {\r
a405b86d 561 return (NULL);\r
562 }\r
563\r
564 //\r
565 // look up the device path in the map\r
566 //\r
567 DevicePath = EfiShellGetDevicePathFromMap(MapName);\r
568 if (DevicePath == NULL) {\r
569 //\r
570 // Must have been a bad Mapname\r
571 //\r
572 return (NULL);\r
573 }\r
574\r
575 //\r
576 // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with)\r
577 //\r
578 DevicePathCopyForFree = DevicePathCopy = DuplicateDevicePath(DevicePath);\r
579 if (DevicePathCopy == NULL) {\r
a405b86d 580 FreePool(MapName);\r
581 return (NULL);\r
582 }\r
583\r
584 //\r
585 // get the handle\r
586 //\r
587 ///@todo BlockIo?\r
588 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &Handle);\r
589 if (EFI_ERROR(Status)) {\r
590 if (DevicePathCopyForFree != NULL) {\r
591 FreePool(DevicePathCopyForFree);\r
592 }\r
593 FreePool(MapName);\r
594 return (NULL);\r
595 }\r
596\r
597 //\r
598 // build the full device path\r
599 //\r
e35b5317 600 if (*(Path+StrLen(MapName)+1) == CHAR_NULL) {\r
601 DevicePathForReturn = FileDevicePath(Handle, L"\\");\r
602 } else {\r
f9125972 603 DevicePathForReturn = FileDevicePath(Handle, Path+StrLen(MapName));\r
e35b5317 604 }\r
a405b86d 605\r
606 FreePool(MapName);\r
607 if (DevicePathCopyForFree != NULL) {\r
608 FreePool(DevicePathCopyForFree);\r
609 }\r
610\r
611 return (DevicePathForReturn);\r
612}\r
613\r
614/**\r
615 Gets the name of the device specified by the device handle.\r
616\r
617 This function gets the user-readable name of the device specified by the device\r
618 handle. If no user-readable name could be generated, then *BestDeviceName will be\r
619 NULL and EFI_NOT_FOUND will be returned.\r
620\r
621 If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the\r
622 device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on\r
623 DeviceHandle.\r
624\r
625 If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the\r
626 device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle.\r
627 If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and\r
628 EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then\r
629 EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority.\r
630\r
631 @param DeviceHandle The handle of the device.\r
632 @param Flags Determines the possible sources of component names.\r
633 Valid bits are:\r
634 EFI_DEVICE_NAME_USE_COMPONENT_NAME\r
635 EFI_DEVICE_NAME_USE_DEVICE_PATH\r
636 @param Language A pointer to the language specified for the device\r
637 name, in the same format as described in the UEFI\r
638 specification, Appendix M\r
639 @param BestDeviceName On return, points to the callee-allocated NULL-\r
640 terminated name of the device. If no device name\r
641 could be found, points to NULL. The name must be\r
642 freed by the caller...\r
643\r
644 @retval EFI_SUCCESS Get the name successfully.\r
645 @retval EFI_NOT_FOUND Fail to get the device name.\r
646 @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set.\r
647 @retval EFI_INVALID_PARAMETER BestDeviceName was NULL\r
648 @retval EFI_INVALID_PARAMETER DeviceHandle was NULL\r
649**/\r
650EFI_STATUS\r
651EFIAPI\r
652EfiShellGetDeviceName(\r
653 IN EFI_HANDLE DeviceHandle,\r
654 IN EFI_SHELL_DEVICE_NAME_FLAGS Flags,\r
655 IN CHAR8 *Language,\r
656 OUT CHAR16 **BestDeviceName\r
657 )\r
658{\r
659 EFI_STATUS Status;\r
660 EFI_COMPONENT_NAME2_PROTOCOL *CompName2;\r
a405b86d 661 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
662 EFI_HANDLE *HandleList;\r
663 UINTN HandleCount;\r
664 UINTN LoopVar;\r
665 CHAR16 *DeviceNameToReturn;\r
666 CHAR8 *Lang;\r
733f138d 667 UINTN ParentControllerCount;\r
668 EFI_HANDLE *ParentControllerBuffer;\r
669 UINTN ParentDriverCount;\r
670 EFI_HANDLE *ParentDriverBuffer;\r
671\r
a405b86d 672 if (BestDeviceName == NULL ||\r
673 DeviceHandle == NULL\r
674 ){\r
675 return (EFI_INVALID_PARAMETER);\r
676 }\r
677\r
678 //\r
679 // make sure one of the 2 supported bits is on\r
680 //\r
681 if (((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) == 0) &&\r
682 ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) == 0)) {\r
683 return (EFI_INVALID_PARAMETER);\r
684 }\r
685\r
686 DeviceNameToReturn = NULL;\r
687 *BestDeviceName = NULL;\r
688 HandleList = NULL;\r
689 HandleCount = 0;\r
690 Lang = NULL;\r
691\r
692 if ((Flags & EFI_DEVICE_NAME_USE_COMPONENT_NAME) != 0) {\r
693 Status = ParseHandleDatabaseByRelationship(\r
694 NULL,\r
695 DeviceHandle,\r
696 HR_DRIVER_BINDING_HANDLE|HR_DEVICE_DRIVER,\r
697 &HandleCount,\r
698 &HandleList);\r
699 for (LoopVar = 0; LoopVar < HandleCount ; LoopVar++){\r
700 //\r
701 // Go through those handles until we get one that passes for GetComponentName\r
702 //\r
703 Status = gBS->OpenProtocol(\r
704 HandleList[LoopVar],\r
705 &gEfiComponentName2ProtocolGuid,\r
706 (VOID**)&CompName2,\r
707 gImageHandle,\r
708 NULL,\r
709 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
710 if (EFI_ERROR(Status)) {\r
711 Status = gBS->OpenProtocol(\r
712 HandleList[LoopVar],\r
713 &gEfiComponentNameProtocolGuid,\r
714 (VOID**)&CompName2,\r
715 gImageHandle,\r
716 NULL,\r
717 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
718 }\r
719\r
720 if (EFI_ERROR(Status)) {\r
721 continue;\r
722 }\r
a71003f2 723 Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);\r
a405b86d 724 Status = CompName2->GetControllerName(CompName2, DeviceHandle, NULL, Lang, &DeviceNameToReturn);\r
725 FreePool(Lang);\r
726 Lang = NULL;\r
727 if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {\r
728 break;\r
729 }\r
730 }\r
731 if (HandleList != NULL) {\r
732 FreePool(HandleList);\r
733 }\r
733f138d 734\r
735 //\r
736 // Now check the parent controller using this as the child.\r
737 //\r
738 if (DeviceNameToReturn == NULL){\r
739 PARSE_HANDLE_DATABASE_PARENTS(DeviceHandle, &ParentControllerCount, &ParentControllerBuffer);\r
740 for (LoopVar = 0 ; LoopVar < ParentControllerCount ; LoopVar++) {\r
741 PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ParentControllerBuffer[LoopVar], &ParentDriverCount, &ParentDriverBuffer);\r
742 for (HandleCount = 0 ; HandleCount < ParentDriverCount ; HandleCount++) {\r
743 //\r
744 // try using that driver's component name with controller and our driver as the child.\r
745 //\r
746 Status = gBS->OpenProtocol(\r
747 ParentDriverBuffer[HandleCount],\r
748 &gEfiComponentName2ProtocolGuid,\r
749 (VOID**)&CompName2,\r
750 gImageHandle,\r
751 NULL,\r
752 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
753 if (EFI_ERROR(Status)) {\r
754 Status = gBS->OpenProtocol(\r
755 ParentDriverBuffer[HandleCount],\r
756 &gEfiComponentNameProtocolGuid,\r
757 (VOID**)&CompName2,\r
758 gImageHandle,\r
759 NULL,\r
760 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
761 }\r
762\r
763 if (EFI_ERROR(Status)) {\r
764 continue;\r
765 }\r
a71003f2 766 Lang = GetBestLanguageForDriver(CompName2->SupportedLanguages, Language, FALSE);\r
733f138d 767 Status = CompName2->GetControllerName(CompName2, ParentControllerBuffer[LoopVar], DeviceHandle, Lang, &DeviceNameToReturn);\r
768 FreePool(Lang);\r
769 Lang = NULL;\r
770 if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {\r
771 break;\r
772 }\r
773\r
774\r
775\r
776 }\r
777 SHELL_FREE_NON_NULL(ParentDriverBuffer);\r
778 if (!EFI_ERROR(Status) && DeviceNameToReturn != NULL) {\r
779 break;\r
780 }\r
781 }\r
782 SHELL_FREE_NON_NULL(ParentControllerBuffer);\r
783 }\r
784 //\r
785 // dont return on fail since we will try device path if that bit is on\r
786 //\r
a405b86d 787 if (DeviceNameToReturn != NULL){\r
3c865f20 788 ASSERT(BestDeviceName != NULL);\r
a405b86d 789 StrnCatGrow(BestDeviceName, NULL, DeviceNameToReturn, 0);\r
790 return (EFI_SUCCESS);\r
791 }\r
a405b86d 792 }\r
793 if ((Flags & EFI_DEVICE_NAME_USE_DEVICE_PATH) != 0) {\r
863986b3
RN
794 Status = gBS->OpenProtocol(\r
795 DeviceHandle,\r
796 &gEfiDevicePathProtocolGuid,\r
797 (VOID**)&DevicePath,\r
798 gImageHandle,\r
a405b86d 799 NULL,\r
863986b3 800 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
a405b86d 801 if (!EFI_ERROR(Status)) {\r
863986b3
RN
802 //\r
803 // use device path to text on the device path\r
804 //\r
805 *BestDeviceName = ConvertDevicePathToText(DevicePath, TRUE, TRUE);\r
806 return (EFI_SUCCESS);\r
a405b86d 807 }\r
808 }\r
809 //\r
810 // none of the selected bits worked.\r
811 //\r
812 return (EFI_NOT_FOUND);\r
813}\r
814\r
815/**\r
816 Opens the root directory of a device on a handle\r
817\r
818 This function opens the root directory of a device and returns a file handle to it.\r
819\r
820 @param DeviceHandle The handle of the device that contains the volume.\r
821 @param FileHandle On exit, points to the file handle corresponding to the root directory on the\r
822 device.\r
823\r
824 @retval EFI_SUCCESS Root opened successfully.\r
825 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
826 could not be opened.\r
827 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.\r
828 @retval EFI_DEVICE_ERROR The device had an error\r
829**/\r
830EFI_STATUS\r
831EFIAPI\r
832EfiShellOpenRootByHandle(\r
833 IN EFI_HANDLE DeviceHandle,\r
834 OUT SHELL_FILE_HANDLE *FileHandle\r
835 )\r
836{\r
837 EFI_STATUS Status;\r
838 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;\r
839 EFI_FILE_PROTOCOL *RealFileHandle;\r
840 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
841\r
842 //\r
843 // get the simple file system interface\r
844 //\r
845 Status = gBS->OpenProtocol(DeviceHandle,\r
846 &gEfiSimpleFileSystemProtocolGuid,\r
847 (VOID**)&SimpleFileSystem,\r
848 gImageHandle,\r
849 NULL,\r
850 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
851 if (EFI_ERROR(Status)) {\r
852 return (EFI_NOT_FOUND);\r
853 }\r
854\r
855 Status = gBS->OpenProtocol(DeviceHandle,\r
856 &gEfiDevicePathProtocolGuid,\r
857 (VOID**)&DevPath,\r
858 gImageHandle,\r
859 NULL,\r
860 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
861 if (EFI_ERROR(Status)) {\r
862 return (EFI_NOT_FOUND);\r
863 }\r
864 //\r
865 // Open the root volume now...\r
866 //\r
867 Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &RealFileHandle);\r
868 *FileHandle = ConvertEfiFileProtocolToShellHandle(RealFileHandle, EfiShellGetMapFromDevicePath(&DevPath));\r
869 return (Status);\r
870}\r
871\r
872/**\r
873 Opens the root directory of a device.\r
874\r
875 This function opens the root directory of a device and returns a file handle to it.\r
876\r
877 @param DevicePath Points to the device path corresponding to the device where the\r
878 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed.\r
879 @param FileHandle On exit, points to the file handle corresponding to the root directory on the\r
880 device.\r
881\r
882 @retval EFI_SUCCESS Root opened successfully.\r
883 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory\r
884 could not be opened.\r
885 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.\r
886 @retval EFI_DEVICE_ERROR The device had an error\r
8be0ba36 887 @retval EFI_INVALID_PARAMETER FileHandle is NULL.\r
a405b86d 888**/\r
889EFI_STATUS\r
890EFIAPI\r
891EfiShellOpenRoot(\r
892 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
893 OUT SHELL_FILE_HANDLE *FileHandle\r
894 )\r
895{\r
896 EFI_STATUS Status;\r
897 EFI_HANDLE Handle;\r
898\r
8be0ba36 899 if (FileHandle == NULL) {\r
900 return (EFI_INVALID_PARAMETER);\r
901 }\r
902\r
a405b86d 903 //\r
904 // find the handle of the device with that device handle and the file system\r
905 //\r
906 ///@todo BlockIo?\r
907 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,\r
908 &DevicePath,\r
909 &Handle);\r
910 if (EFI_ERROR(Status)) {\r
911 return (EFI_NOT_FOUND);\r
912 }\r
913\r
914 return (EfiShellOpenRootByHandle(Handle, FileHandle));\r
915}\r
916\r
917/**\r
918 Returns whether any script files are currently being processed.\r
919\r
920 @retval TRUE There is at least one script file active.\r
921 @retval FALSE No script files are active now.\r
922\r
923**/\r
924BOOLEAN\r
925EFIAPI\r
926EfiShellBatchIsActive (\r
927 VOID\r
928 )\r
929{\r
930 if (ShellCommandGetCurrentScriptFile() == NULL) {\r
931 return (FALSE);\r
932 }\r
933 return (TRUE);\r
934}\r
935\r
936/**\r
937 Worker function to open a file based on a device path. this will open the root\r
938 of the volume and then traverse down to the file itself.\r
939\r
940 @param DevicePath Device Path of the file.\r
941 @param FileHandle Pointer to the file upon a successful return.\r
942 @param OpenMode mode to open file in.\r
943 @param Attributes the File Attributes to use when creating a new file.\r
944\r
945 @retval EFI_SUCCESS the file is open and FileHandle is valid\r
946 @retval EFI_UNSUPPORTED the device path cotained non-path elements\r
947 @retval other an error ocurred.\r
948**/\r
949EFI_STATUS\r
950EFIAPI\r
951InternalOpenFileDevicePath(\r
952 IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
953 OUT SHELL_FILE_HANDLE *FileHandle,\r
954 IN UINT64 OpenMode,\r
955 IN UINT64 Attributes OPTIONAL\r
956 )\r
957{\r
958 EFI_STATUS Status;\r
959 FILEPATH_DEVICE_PATH *FilePathNode;\r
960 EFI_HANDLE Handle;\r
961 SHELL_FILE_HANDLE ShellHandle;\r
962 EFI_FILE_PROTOCOL *Handle1;\r
963 EFI_FILE_PROTOCOL *Handle2;\r
8be0ba36 964 FILEPATH_DEVICE_PATH *AlignedNode;\r
a405b86d 965\r
8be0ba36 966 if (FileHandle == NULL) {\r
967 return (EFI_INVALID_PARAMETER);\r
968 }\r
969 *FileHandle = NULL;\r
970 Handle1 = NULL;\r
971 Handle2 = NULL;\r
972 Handle = NULL;\r
8be0ba36 973 ShellHandle = NULL;\r
974 FilePathNode = NULL;\r
975 AlignedNode = NULL;\r
a405b86d 976\r
977 Status = EfiShellOpenRoot(DevicePath, &ShellHandle);\r
978\r
979 if (!EFI_ERROR(Status)) {\r
980 Handle1 = ConvertShellHandleToEfiFileProtocol(ShellHandle);\r
c154b997 981 if (Handle1 != NULL) {\r
a405b86d 982 //\r
c154b997 983 // chop off the begining part before the file system part...\r
a405b86d 984 //\r
c154b997 985 ///@todo BlockIo?\r
986 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid,\r
987 &DevicePath,\r
988 &Handle);\r
989 if (!EFI_ERROR(Status)) {\r
a405b86d 990 //\r
c154b997 991 // To access as a file system, the file path should only\r
992 // contain file path components. Follow the file path nodes\r
993 // and find the target file\r
a405b86d 994 //\r
c154b997 995 for ( FilePathNode = (FILEPATH_DEVICE_PATH *)DevicePath\r
996 ; !IsDevicePathEnd (&FilePathNode->Header)\r
997 ; FilePathNode = (FILEPATH_DEVICE_PATH *) NextDevicePathNode (&FilePathNode->Header)\r
998 ){\r
999 SHELL_FREE_NON_NULL(AlignedNode);\r
1000 AlignedNode = AllocateCopyPool (DevicePathNodeLength(FilePathNode), FilePathNode);\r
a405b86d 1001 //\r
c154b997 1002 // For file system access each node should be a file path component\r
a405b86d 1003 //\r
c154b997 1004 if (DevicePathType (&FilePathNode->Header) != MEDIA_DEVICE_PATH ||\r
1005 DevicePathSubType (&FilePathNode->Header) != MEDIA_FILEPATH_DP\r
1006 ) {\r
1007 Status = EFI_UNSUPPORTED;\r
1008 break;\r
1009 }\r
a405b86d 1010\r
1011 //\r
c154b997 1012 // Open this file path node\r
a405b86d 1013 //\r
c154b997 1014 Handle2 = Handle1;\r
1015 Handle1 = NULL;\r
1016\r
a405b86d 1017 //\r
c154b997 1018 // if this is the last node in the DevicePath always create (if that was requested).\r
a405b86d 1019 //\r
c154b997 1020 if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode->Header)))) {\r
a405b86d 1021 Status = Handle2->Open (\r
1022 Handle2,\r
1023 &Handle1,\r
8be0ba36 1024 AlignedNode->PathName,\r
a405b86d 1025 OpenMode,\r
1026 Attributes\r
1027 );\r
c154b997 1028 } else {\r
1029\r
1030 //\r
1031 // This is not the last node and we dont want to 'create' existing\r
1032 // directory entries...\r
1033 //\r
1034\r
1035 //\r
1036 // open without letting it create\r
1037 // prevents error on existing files/directories\r
1038 //\r
1039 Status = Handle2->Open (\r
1040 Handle2,\r
1041 &Handle1,\r
1042 AlignedNode->PathName,\r
1043 OpenMode &~EFI_FILE_MODE_CREATE,\r
1044 Attributes\r
1045 );\r
1046 //\r
1047 // if above failed now open and create the 'item'\r
1048 // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)\r
1049 //\r
1050 if ((EFI_ERROR (Status)) && ((OpenMode & EFI_FILE_MODE_CREATE) != 0)) {\r
1051 Status = Handle2->Open (\r
1052 Handle2,\r
1053 &Handle1,\r
1054 AlignedNode->PathName,\r
1055 OpenMode,\r
1056 Attributes\r
1057 );\r
1058 }\r
a405b86d 1059 }\r
c154b997 1060 //\r
1061 // Close the last node\r
1062 //\r
1063 ShellInfoObject.NewEfiShellProtocol->CloseFile (Handle2);\r
a405b86d 1064\r
c154b997 1065 //\r
1066 // If there's been an error, stop\r
1067 //\r
1068 if (EFI_ERROR (Status)) {\r
1069 break;\r
1070 }\r
1071 } // for loop\r
1072 }\r
a405b86d 1073 }\r
1074 }\r
8be0ba36 1075 SHELL_FREE_NON_NULL(AlignedNode);\r
a405b86d 1076 if (EFI_ERROR(Status)) {\r
1077 if (Handle1 != NULL) {\r
8be0ba36 1078 ShellInfoObject.NewEfiShellProtocol->CloseFile(Handle1);\r
a405b86d 1079 }\r
1080 } else {\r
1081 *FileHandle = ConvertEfiFileProtocolToShellHandle(Handle1, ShellFileHandleGetPath(ShellHandle));\r
1082 }\r
1083 return (Status);\r
1084}\r
1085\r
1086/**\r
1087 Creates a file or directory by name.\r
1088\r
1089 This function creates an empty new file or directory with the specified attributes and\r
1090 returns the new file's handle. If the file already exists and is read-only, then\r
1091 EFI_INVALID_PARAMETER will be returned.\r
1092\r
1093 If the file already existed, it is truncated and its attributes updated. If the file is\r
1094 created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL.\r
1095\r
1096 If the file name begins with >v, then the file handle which is returned refers to the\r
1097 shell environment variable with the specified name. If the shell environment variable\r
1098 already exists and is non-volatile then EFI_INVALID_PARAMETER is returned.\r
1099\r
1100 @param FileName Pointer to NULL-terminated file path\r
1101 @param FileAttribs The new file's attrbiutes. the different attributes are\r
1102 described in EFI_FILE_PROTOCOL.Open().\r
1103 @param FileHandle On return, points to the created file handle or directory's handle\r
1104\r
1105 @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle.\r
1106 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
1107 @retval EFI_UNSUPPORTED could not open the file path\r
1108 @retval EFI_NOT_FOUND the specified file could not be found on the devide, or could not\r
1109 file the file system on the device.\r
1110 @retval EFI_NO_MEDIA the device has no medium.\r
1111 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no\r
1112 longer supported.\r
1113 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according\r
1114 the DirName.\r
1115 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
1116 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write\r
1117 when the media is write-protected.\r
1118 @retval EFI_ACCESS_DENIED The service denied access to the file.\r
1119 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
1120 @retval EFI_VOLUME_FULL The volume is full.\r
1121**/\r
1122EFI_STATUS\r
1123EFIAPI\r
1124EfiShellCreateFile(\r
1125 IN CONST CHAR16 *FileName,\r
1126 IN UINT64 FileAttribs,\r
1127 OUT SHELL_FILE_HANDLE *FileHandle\r
1128 )\r
1129{\r
1130 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1131 EFI_STATUS Status;\r
31e5b912 1132 BOOLEAN Volatile;\r
a405b86d 1133\r
1134 //\r
1135 // Is this for an environment variable\r
1136 // do we start with >v\r
1137 //\r
1138 if (StrStr(FileName, L">v") == FileName) {\r
31e5b912
RN
1139 Status = IsVolatileEnv (FileName + 2, &Volatile);\r
1140 if (EFI_ERROR (Status)) {\r
1141 return Status;\r
1142 }\r
1143 if (!Volatile) {\r
a405b86d 1144 return (EFI_INVALID_PARAMETER);\r
1145 }\r
1146 *FileHandle = CreateFileInterfaceEnv(FileName+2);\r
1147 return (EFI_SUCCESS);\r
1148 }\r
1149\r
1150 //\r
1151 // We are opening a regular file.\r
1152 //\r
1153 DevicePath = EfiShellGetDevicePathFromFilePath(FileName);\r
1154 if (DevicePath == NULL) {\r
1155 return (EFI_NOT_FOUND);\r
1156 }\r
1157\r
09fd5328 1158 Status = InternalOpenFileDevicePath(DevicePath, FileHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, FileAttribs);\r
a405b86d 1159 FreePool(DevicePath);\r
1160\r
1161 return(Status);\r
1162}\r
1163\r
09fd5328
JC
1164/**\r
1165 Register a GUID and a localized human readable name for it.\r
1166\r
1167 If Guid is not assigned a name, then assign GuidName to Guid. This list of GUID\r
1168 names must be used whenever a shell command outputs GUID information.\r
1169\r
1170 This function is only available when the major and minor versions in the\r
1171 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
1172\r
1173 @param[in] Guid A pointer to the GUID being registered.\r
1174 @param[in] GuidName A pointer to the localized name for the GUID being registered.\r
1175\r
1176 @retval EFI_SUCCESS The operation was successful.\r
1177 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
1178 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
1179 @retval EFI_ACCESS_DENIED Guid already is assigned a name.\r
1180**/\r
1181EFI_STATUS\r
1182EFIAPI \r
1183EfiShellRegisterGuidName(\r
1184 IN CONST EFI_GUID *Guid,\r
1185 IN CONST CHAR16 *GuidName\r
1186 )\r
1187{\r
1188 return (AddNewGuidNameMapping(Guid, GuidName, NULL));\r
1189}\r
1190\r
a405b86d 1191/**\r
1192 Opens a file or a directory by file name.\r
1193\r
1194 This function opens the specified file in the specified OpenMode and returns a file\r
1195 handle.\r
1196 If the file name begins with >v, then the file handle which is returned refers to the\r
1197 shell environment variable with the specified name. If the shell environment variable\r
1198 exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then\r
1199 EFI_INVALID_PARAMETER is returned.\r
1200\r
1201 If the file name is >i, then the file handle which is returned refers to the standard\r
1202 input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER\r
1203 is returned.\r
1204\r
1205 If the file name is >o, then the file handle which is returned refers to the standard\r
1206 output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER\r
1207 is returned.\r
1208\r
1209 If the file name is >e, then the file handle which is returned refers to the standard\r
1210 error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER\r
1211 is returned.\r
1212\r
1213 If the file name is NUL, then the file handle that is returned refers to the standard NUL\r
1214 file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is\r
1215 returned.\r
1216\r
1217 If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the\r
1218 FileHandle is NULL.\r
1219\r
1220 @param FileName Points to the NULL-terminated UCS-2 encoded file name.\r
1221 @param FileHandle On return, points to the file handle.\r
1222 @param OpenMode File open mode. Either EFI_FILE_MODE_READ or\r
1223 EFI_FILE_MODE_WRITE from section 12.4 of the UEFI\r
1224 Specification.\r
1225 @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle.\r
1226 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL.\r
1227 @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL.\r
1228 @retval EFI_NOT_FOUND The specified file could not be found on the device or the file\r
1229 system could not be found on the device. FileHandle is NULL.\r
1230 @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL.\r
1231 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no\r
1232 longer supported. FileHandle is NULL.\r
1233 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according\r
1234 the FileName. FileHandle is NULL.\r
1235 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL.\r
1236 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write\r
1237 when the media is write-protected. FileHandle is NULL.\r
1238 @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL.\r
1239 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle\r
1240 is NULL.\r
1241 @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL.\r
1242**/\r
1243EFI_STATUS\r
1244EFIAPI\r
1245EfiShellOpenFileByName(\r
1246 IN CONST CHAR16 *FileName,\r
1247 OUT SHELL_FILE_HANDLE *FileHandle,\r
1248 IN UINT64 OpenMode\r
1249 )\r
1250{\r
1251 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
1252 EFI_STATUS Status;\r
31e5b912 1253 BOOLEAN Volatile;\r
a405b86d 1254\r
1255 *FileHandle = NULL;\r
1256\r
1257 //\r
1258 // Is this for StdIn\r
1259 //\r
1260 if (StrCmp(FileName, L">i") == 0) {\r
1261 //\r
1262 // make sure not writing to StdIn\r
1263 //\r
1264 if ((OpenMode & EFI_FILE_MODE_WRITE) != 0) {\r
1265 return (EFI_INVALID_PARAMETER);\r
1266 }\r
1267 *FileHandle = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
1268 ASSERT(*FileHandle != NULL);\r
1269 return (EFI_SUCCESS);\r
1270 }\r
1271\r
1272 //\r
1273 // Is this for StdOut\r
1274 //\r
1275 if (StrCmp(FileName, L">o") == 0) {\r
1276 //\r
1277 // make sure not writing to StdIn\r
1278 //\r
1279 if ((OpenMode & EFI_FILE_MODE_READ) != 0) {\r
1280 return (EFI_INVALID_PARAMETER);\r
1281 }\r
1282 *FileHandle = &FileInterfaceStdOut;\r
1283 return (EFI_SUCCESS);\r
1284 }\r
1285\r
1286 //\r
1287 // Is this for NUL file\r
1288 //\r
1289 if (StrCmp(FileName, L"NUL") == 0) {\r
1290 *FileHandle = &FileInterfaceNulFile;\r
1291 return (EFI_SUCCESS);\r
1292 }\r
1293\r
1294 //\r
1295 // Is this for StdErr\r
1296 //\r
1297 if (StrCmp(FileName, L">e") == 0) {\r
1298 //\r
1299 // make sure not writing to StdIn\r
1300 //\r
1301 if ((OpenMode & EFI_FILE_MODE_READ) != 0) {\r
1302 return (EFI_INVALID_PARAMETER);\r
1303 }\r
1304 *FileHandle = &FileInterfaceStdErr;\r
1305 return (EFI_SUCCESS);\r
1306 }\r
1307\r
1308 //\r
1309 // Is this for an environment variable\r
1310 // do we start with >v\r
1311 //\r
1312 if (StrStr(FileName, L">v") == FileName) {\r
31e5b912
RN
1313 Status = IsVolatileEnv (FileName + 2, &Volatile);\r
1314 if (EFI_ERROR (Status)) {\r
1315 return Status;\r
1316 }\r
1317 if (!Volatile &&\r
a405b86d 1318 ((OpenMode & EFI_FILE_MODE_WRITE) != 0)) {\r
1319 return (EFI_INVALID_PARAMETER);\r
1320 }\r
1321 *FileHandle = CreateFileInterfaceEnv(FileName+2);\r
1322 return (EFI_SUCCESS);\r
1323 }\r
1324\r
1325 //\r
1326 // We are opening a regular file.\r
1327 //\r
1328 DevicePath = EfiShellGetDevicePathFromFilePath(FileName);\r
1329// DEBUG_CODE(InternalShellProtocolDebugPrintMessage (NULL, DevicePath););\r
1330 if (DevicePath == NULL) {\r
1331 return (EFI_NOT_FOUND);\r
1332 }\r
1333\r
1334 //\r
1335 // Copy the device path, open the file, then free the memory\r
1336 //\r
1337 Status = InternalOpenFileDevicePath(DevicePath, FileHandle, OpenMode, 0); // 0 = no specific file attributes\r
1338 FreePool(DevicePath);\r
1339\r
1340 return(Status);\r
1341}\r
1342\r
1343/**\r
1344 Deletes the file specified by the file name.\r
1345\r
1346 This function deletes a file.\r
1347\r
1348 @param FileName Points to the NULL-terminated file name.\r
1349\r
1350 @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.\r
1351 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.\r
1352 @sa EfiShellCreateFile\r
1353**/\r
1354EFI_STATUS\r
1355EFIAPI\r
1356EfiShellDeleteFileByName(\r
1357 IN CONST CHAR16 *FileName\r
1358 )\r
1359{\r
1360 SHELL_FILE_HANDLE FileHandle;\r
1361 EFI_STATUS Status;\r
1362\r
0d807dae
ED
1363 FileHandle = NULL;\r
1364\r
a405b86d 1365 //\r
1366 // get a handle to the file\r
1367 //\r
1368 Status = EfiShellCreateFile(FileName,\r
1369 0,\r
1370 &FileHandle);\r
1371 if (EFI_ERROR(Status)) {\r
1372 return (Status);\r
1373 }\r
1374 //\r
1375 // now delete the file\r
1376 //\r
06e5ae77 1377 ShellFileHandleRemove(FileHandle);\r
a405b86d 1378 return (ShellInfoObject.NewEfiShellProtocol->DeleteFile(FileHandle));\r
1379}\r
1380\r
1381/**\r
1382 Disables the page break output mode.\r
1383**/\r
1384VOID\r
1385EFIAPI\r
1386EfiShellDisablePageBreak (\r
1387 VOID\r
1388 )\r
1389{\r
1390 ShellInfoObject.PageBreakEnabled = FALSE;\r
1391}\r
1392\r
1393/**\r
1394 Enables the page break output mode.\r
1395**/\r
1396VOID\r
1397EFIAPI\r
1398EfiShellEnablePageBreak (\r
1399 VOID\r
1400 )\r
1401{\r
1402 ShellInfoObject.PageBreakEnabled = TRUE;\r
1403}\r
1404\r
1405/**\r
1406 internal worker function to load and run an image via device path.\r
1407\r
b5ce69c3
QS
1408 @param ParentImageHandle A handle of the image that is executing the specified\r
1409 command line.\r
1410 @param DevicePath device path of the file to execute\r
1411 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1412 containing the command line. If NULL then the command-\r
1413 line will be empty.\r
1414 @param Environment Points to a NULL-terminated array of environment\r
1415 variables with the format 'x=y', where x is the\r
1416 environment variable name and y is the value. If this\r
1417 is NULL, then the current shell environment is used.\r
1418 \r
1419 @param[out] StartImageStatus Returned status from gBS->StartImage.\r
5223c121 1420\r
a405b86d 1421 @retval EFI_SUCCESS The command executed successfully. The status code\r
1422 returned by the command is pointed to by StatusCode.\r
1423 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1424 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1425 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1426**/\r
1427EFI_STATUS\r
1428EFIAPI\r
1429InternalShellExecuteDevicePath(\r
1430 IN CONST EFI_HANDLE *ParentImageHandle,\r
1431 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
1432 IN CONST CHAR16 *CommandLine OPTIONAL,\r
1433 IN CONST CHAR16 **Environment OPTIONAL,\r
a308e058 1434 OUT EFI_STATUS *StartImageStatus OPTIONAL\r
a405b86d 1435 )\r
1436{\r
1437 EFI_STATUS Status;\r
cd39fe08 1438 EFI_STATUS StartStatus;\r
d9c7741d 1439 EFI_STATUS CleanupStatus;\r
a405b86d 1440 EFI_HANDLE NewHandle;\r
1441 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;\r
1442 LIST_ENTRY OrigEnvs;\r
1443 EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol;\r
3e2b20a1 1444 CHAR16 *ImagePath;\r
fe6c94d2 1445 UINTN Index;\r
4b6b543e
QS
1446 CHAR16 *Walker;\r
1447 CHAR16 *NewCmdLine;\r
5223c121 1448\r
a405b86d 1449 if (ParentImageHandle == NULL) {\r
1450 return (EFI_INVALID_PARAMETER);\r
1451 }\r
1452\r
1453 InitializeListHead(&OrigEnvs);\r
91a92220 1454 ZeroMem(&ShellParamsProtocol, sizeof(EFI_SHELL_PARAMETERS_PROTOCOL));\r
a405b86d 1455\r
1456 NewHandle = NULL;\r
4b6b543e
QS
1457 \r
1458 NewCmdLine = AllocateCopyPool (StrSize (CommandLine), CommandLine);\r
1459 if (NewCmdLine == NULL) {\r
1460 return EFI_OUT_OF_RESOURCES;\r
1461 }\r
1462\r
1463 for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {\r
1464 if (*Walker == L'^' && *(Walker+1) == L'#') {\r
1465 CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));\r
1466 }\r
1467 }\r
a405b86d 1468\r
1469 //\r
1470 // Load the image with:\r
1471 // FALSE - not from boot manager and NULL, 0 being not already in memory\r
1472 //\r
1473 Status = gBS->LoadImage(\r
1474 FALSE,\r
1475 *ParentImageHandle,\r
1476 (EFI_DEVICE_PATH_PROTOCOL*)DevicePath,\r
1477 NULL,\r
1478 0,\r
1479 &NewHandle);\r
1480\r
1481 if (EFI_ERROR(Status)) {\r
1482 if (NewHandle != NULL) {\r
1483 gBS->UnloadImage(NewHandle);\r
1484 }\r
a5bc2ff8 1485 FreePool (NewCmdLine);\r
a405b86d 1486 return (Status);\r
1487 }\r
1488 Status = gBS->OpenProtocol(\r
1489 NewHandle,\r
1490 &gEfiLoadedImageProtocolGuid,\r
1491 (VOID**)&LoadedImage,\r
1492 gImageHandle,\r
1493 NULL,\r
1494 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
1495\r
1496 if (!EFI_ERROR(Status)) {\r
91a92220
QS
1497 //\r
1498 // If the image is not an app abort it.\r
1499 //\r
1500 if (LoadedImage->ImageCodeType != EfiLoaderCode){\r
1501 ShellPrintHiiEx(\r
1502 -1, \r
1503 -1, \r
1504 NULL,\r
1505 STRING_TOKEN (STR_SHELL_IMAGE_NOT_APP),\r
1506 ShellInfoObject.HiiHandle\r
1507 );\r
1508 goto UnloadImage;\r
1509 }\r
1510\r
a405b86d 1511 ASSERT(LoadedImage->LoadOptionsSize == 0);\r
4b6b543e
QS
1512 if (NewCmdLine != NULL) {\r
1513 LoadedImage->LoadOptionsSize = (UINT32)StrSize(NewCmdLine);\r
1514 LoadedImage->LoadOptions = (VOID*)NewCmdLine;\r
a405b86d 1515 }\r
1516\r
1517 //\r
1518 // Save our current environment settings for later restoration if necessary\r
1519 //\r
1520 if (Environment != NULL) {\r
1521 Status = GetEnvironmentVariableList(&OrigEnvs);\r
1522 if (!EFI_ERROR(Status)) {\r
1523 Status = SetEnvironmentVariables(Environment);\r
1524 }\r
1525 }\r
1526\r
1527 //\r
1528 // Initialize and install a shell parameters protocol on the image.\r
1529 //\r
1530 ShellParamsProtocol.StdIn = ShellInfoObject.NewShellParametersProtocol->StdIn;\r
1531 ShellParamsProtocol.StdOut = ShellInfoObject.NewShellParametersProtocol->StdOut;\r
1532 ShellParamsProtocol.StdErr = ShellInfoObject.NewShellParametersProtocol->StdErr;\r
d1c275c6 1533 Status = UpdateArgcArgv(&ShellParamsProtocol, NewCmdLine, Efi_Application, NULL, NULL);\r
a405b86d 1534 ASSERT_EFI_ERROR(Status);\r
3e2b20a1
BJ
1535 //\r
1536 // Replace Argv[0] with the full path of the binary we're executing:\r
1537 // If the command line was "foo", the binary might be called "foo.efi".\r
1538 // "The first entry in [Argv] is always the full file path of the\r
1539 // executable" - UEFI Shell Spec section 2.3\r
1540 //\r
1541 ImagePath = EfiShellGetFilePathFromDevicePath (DevicePath);\r
1542 // The image we're executing isn't necessarily in a filesystem - it might\r
1543 // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will\r
1544 // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it.\r
1545 if (ImagePath != NULL) {\r
1546 if (ShellParamsProtocol.Argv == NULL) {\r
1547 // Command line was empty or null.\r
1548 // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL)\r
1549 ShellParamsProtocol.Argv = AllocatePool (sizeof (CHAR16 *));\r
1550 if (ShellParamsProtocol.Argv == NULL) {\r
1551 Status = EFI_OUT_OF_RESOURCES;\r
fe6c94d2 1552 goto UnloadImage;\r
3e2b20a1
BJ
1553 }\r
1554 ShellParamsProtocol.Argc = 1;\r
1555 } else {\r
1556 // Free the string UpdateArgcArgv put in Argv[0];\r
1557 FreePool (ShellParamsProtocol.Argv[0]);\r
1558 }\r
1559 ShellParamsProtocol.Argv[0] = ImagePath;\r
1560 }\r
1561\r
a405b86d 1562 Status = gBS->InstallProtocolInterface(&NewHandle, &gEfiShellParametersProtocolGuid, EFI_NATIVE_INTERFACE, &ShellParamsProtocol);\r
1563 ASSERT_EFI_ERROR(Status);\r
1564\r
1565 ///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)\r
1566\r
1567 //\r
a308e058 1568 // now start the image and if the caller wanted the return code pass it to them...\r
a405b86d 1569 //\r
1570 if (!EFI_ERROR(Status)) {\r
cd39fe08 1571 StartStatus = gBS->StartImage(\r
5223c121 1572 NewHandle,\r
a308e058
RN
1573 0,\r
1574 NULL\r
5223c121 1575 );\r
cd39fe08
OM
1576 if (StartImageStatus != NULL) {\r
1577 *StartImageStatus = StartStatus;\r
1578 }\r
a405b86d 1579\r
d9c7741d
BJ
1580 CleanupStatus = gBS->UninstallProtocolInterface(\r
1581 NewHandle,\r
1582 &gEfiShellParametersProtocolGuid,\r
1583 &ShellParamsProtocol\r
1584 );\r
1585 ASSERT_EFI_ERROR(CleanupStatus);\r
fe6c94d2
BJ
1586\r
1587 goto FreeAlloc;\r
1588 }\r
1589\r
1590UnloadImage:\r
1591 // Unload image - We should only get here if we didn't call StartImage\r
1592 gBS->UnloadImage (NewHandle);\r
1593\r
1594FreeAlloc:\r
1595 // Free Argv (Allocated in UpdateArgcArgv)\r
1596 if (ShellParamsProtocol.Argv != NULL) {\r
1597 for (Index = 0; Index < ShellParamsProtocol.Argc; Index++) {\r
1598 if (ShellParamsProtocol.Argv[Index] != NULL) {\r
1599 FreePool (ShellParamsProtocol.Argv[Index]);\r
1600 }\r
1601 }\r
1602 FreePool (ShellParamsProtocol.Argv);\r
a405b86d 1603 }\r
1604 }\r
1605\r
fe6c94d2 1606 // Restore environment variables\r
a405b86d 1607 if (!IsListEmpty(&OrigEnvs)) {\r
fe6c94d2
BJ
1608 CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
1609 ASSERT_EFI_ERROR (CleanupStatus);\r
a405b86d 1610 }\r
1611\r
4b6b543e
QS
1612 FreePool (NewCmdLine);\r
1613\r
a405b86d 1614 return(Status);\r
1615}\r
dcbdb8bf
QS
1616\r
1617/**\r
1618 internal worker function to load and run an image in the current shell.\r
1619\r
1620 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1621 containing the command line. If NULL then the command-\r
1622 line will be empty.\r
1623 @param Environment Points to a NULL-terminated array of environment\r
1624 variables with the format 'x=y', where x is the\r
1625 environment variable name and y is the value. If this\r
1626 is NULL, then the current shell environment is used.\r
1627 \r
1628 @param[out] StartImageStatus Returned status from the command line.\r
1629\r
1630 @retval EFI_SUCCESS The command executed successfully. The status code\r
1631 returned by the command is pointed to by StatusCode.\r
1632 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1633 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1634 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1635**/\r
1636EFI_STATUS\r
1637EFIAPI\r
1638InternalShellExecute(\r
1639 IN CONST CHAR16 *CommandLine OPTIONAL,\r
1640 IN CONST CHAR16 **Environment OPTIONAL,\r
1641 OUT EFI_STATUS *StartImageStatus OPTIONAL\r
1642 )\r
1643{\r
1644 EFI_STATUS Status;\r
1645 EFI_STATUS CleanupStatus;\r
1646 LIST_ENTRY OrigEnvs;\r
1647\r
1648 InitializeListHead(&OrigEnvs);\r
1649\r
1650 //\r
1651 // Save our current environment settings for later restoration if necessary\r
1652 //\r
1653 if (Environment != NULL) {\r
1654 Status = GetEnvironmentVariableList(&OrigEnvs);\r
1655 if (!EFI_ERROR(Status)) {\r
1656 Status = SetEnvironmentVariables(Environment);\r
1657 } else {\r
1658 return Status;\r
1659 }\r
1660 }\r
1661\r
1662 Status = RunShellCommand(CommandLine, StartImageStatus);\r
1663\r
1664 // Restore environment variables\r
1665 if (!IsListEmpty(&OrigEnvs)) {\r
1666 CleanupStatus = SetEnvironmentVariableList(&OrigEnvs);\r
1667 ASSERT_EFI_ERROR (CleanupStatus);\r
1668 }\r
1669\r
1670 return(Status);\r
1671}\r
1672\r
1673/**\r
1674 Determine if the UEFI Shell is currently running with nesting enabled or disabled.\r
1675\r
1676 @retval FALSE nesting is required\r
1677 @retval other nesting is enabled\r
1678**/\r
1679STATIC\r
1680BOOLEAN\r
1681EFIAPI\r
1682NestingEnabled(\r
1683)\r
1684{\r
1685 EFI_STATUS Status;\r
1686 CHAR16 *Temp;\r
1687 CHAR16 *Temp2;\r
1688 UINTN TempSize;\r
1689 BOOLEAN RetVal;\r
1690\r
1691 RetVal = TRUE;\r
1692 Temp = NULL;\r
1693 Temp2 = NULL;\r
1694\r
1695 if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest) {\r
1696 TempSize = 0;\r
1697 Temp = NULL;\r
1698 Status = SHELL_GET_ENVIRONMENT_VARIABLE(mNoNestingEnvVarName, &TempSize, Temp);\r
1699 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1700 Temp = AllocateZeroPool(TempSize + sizeof(CHAR16));\r
1701 if (Temp != NULL) {\r
1702 Status = SHELL_GET_ENVIRONMENT_VARIABLE(mNoNestingEnvVarName, &TempSize, Temp);\r
1703 }\r
1704 }\r
1705 Temp2 = StrnCatGrow(&Temp2, NULL, mNoNestingTrue, 0);\r
1706 if (Temp != NULL && Temp2 != NULL && StringNoCaseCompare(&Temp, &Temp2) == 0) {\r
1707 //\r
1708 // Use the no nesting method.\r
1709 //\r
1710 RetVal = FALSE;\r
1711 }\r
1712 }\r
1713\r
1714 SHELL_FREE_NON_NULL(Temp);\r
1715 SHELL_FREE_NON_NULL(Temp2);\r
1716 return (RetVal);\r
1717}\r
1718\r
a405b86d 1719/**\r
1720 Execute the command line.\r
1721\r
1722 This function creates a nested instance of the shell and executes the specified\r
1723 command (CommandLine) with the specified environment (Environment). Upon return,\r
1724 the status code returned by the specified command is placed in StatusCode.\r
1725\r
1726 If Environment is NULL, then the current environment is used and all changes made\r
1727 by the commands executed will be reflected in the current environment. If the\r
1728 Environment is non-NULL, then the changes made will be discarded.\r
1729\r
1730 The CommandLine is executed from the current working directory on the current\r
1731 device.\r
1732\r
1733 @param ParentImageHandle A handle of the image that is executing the specified\r
1734 command line.\r
1735 @param CommandLine Points to the NULL-terminated UCS-2 encoded string\r
1736 containing the command line. If NULL then the command-\r
1737 line will be empty.\r
1738 @param Environment Points to a NULL-terminated array of environment\r
1739 variables with the format 'x=y', where x is the\r
1740 environment variable name and y is the value. If this\r
1741 is NULL, then the current shell environment is used.\r
dcbdb8bf 1742 @param StatusCode Points to the status code returned by the CommandLine.\r
a405b86d 1743\r
1744 @retval EFI_SUCCESS The command executed successfully. The status code\r
1745 returned by the command is pointed to by StatusCode.\r
1746 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1747 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
1748 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.\r
1749 @retval EFI_UNSUPPORTED The support level required for this function is not present.\r
1750\r
1751 @sa InternalShellExecuteDevicePath\r
1752**/\r
1753EFI_STATUS\r
1754EFIAPI\r
1755EfiShellExecute(\r
1756 IN EFI_HANDLE *ParentImageHandle,\r
1757 IN CHAR16 *CommandLine OPTIONAL,\r
1758 IN CHAR16 **Environment OPTIONAL,\r
1759 OUT EFI_STATUS *StatusCode OPTIONAL\r
1760 )\r
1761{\r
1762 EFI_STATUS Status;\r
1763 CHAR16 *Temp;\r
1764 EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
1765 UINTN Size;\r
c6173804 1766\r
a405b86d 1767 if ((PcdGet8(PcdShellSupportLevel) < 1)) {\r
1768 return (EFI_UNSUPPORTED);\r
1769 }\r
1770\r
dcbdb8bf 1771 if (NestingEnabled()) {\r
490ce43d 1772 DevPath = AppendDevicePath (ShellInfoObject.ImageDevPath, ShellInfoObject.FileDevPath);\r
dcbdb8bf 1773\r
490ce43d
QS
1774 DEBUG_CODE_BEGIN();\r
1775 Temp = ConvertDevicePathToText(ShellInfoObject.FileDevPath, TRUE, TRUE);\r
1776 FreePool(Temp);\r
1777 Temp = ConvertDevicePathToText(ShellInfoObject.ImageDevPath, TRUE, TRUE);\r
1778 FreePool(Temp);\r
1779 Temp = ConvertDevicePathToText(DevPath, TRUE, TRUE);\r
1780 FreePool(Temp);\r
1781 DEBUG_CODE_END();\r
1782\r
1783 Temp = NULL;\r
1784 Size = 0;\r
1785 ASSERT((Temp == NULL && Size == 0) || (Temp != NULL));\r
1786 StrnCatGrow(&Temp, &Size, L"Shell.efi -_exit ", 0);\r
1787 StrnCatGrow(&Temp, &Size, CommandLine, 0);\r
1788\r
1789 Status = InternalShellExecuteDevicePath(\r
1790 ParentImageHandle,\r
1791 DevPath,\r
1792 Temp,\r
1793 (CONST CHAR16**)Environment,\r
1794 StatusCode);\r
a405b86d 1795\r
490ce43d
QS
1796 //\r
1797 // de-allocate and return\r
1798 //\r
1799 FreePool(DevPath);\r
1800 FreePool(Temp);\r
1801 } else {\r
dcbdb8bf
QS
1802 Status = InternalShellExecute(\r
1803 (CONST CHAR16*)CommandLine,\r
1804 (CONST CHAR16**)Environment,\r
1805 StatusCode);\r
490ce43d 1806 }\r
a405b86d 1807\r
a405b86d 1808 return(Status);\r
1809}\r
1810\r
1811/**\r
1812 Utility cleanup function for EFI_SHELL_FILE_INFO objects.\r
1813\r
1814 1) frees all pointers (non-NULL)\r
1815 2) Closes the SHELL_FILE_HANDLE\r
1816\r
1817 @param FileListNode pointer to the list node to free\r
1818**/\r
1819VOID\r
1820EFIAPI\r
1821InternalFreeShellFileInfoNode(\r
1822 IN EFI_SHELL_FILE_INFO *FileListNode\r
1823 )\r
1824{\r
1825 if (FileListNode->Info != NULL) {\r
1826 FreePool((VOID*)FileListNode->Info);\r
1827 }\r
1828 if (FileListNode->FileName != NULL) {\r
1829 FreePool((VOID*)FileListNode->FileName);\r
1830 }\r
1831 if (FileListNode->FullName != NULL) {\r
1832 FreePool((VOID*)FileListNode->FullName);\r
1833 }\r
1834 if (FileListNode->Handle != NULL) {\r
1835 ShellInfoObject.NewEfiShellProtocol->CloseFile(FileListNode->Handle);\r
1836 }\r
1837 FreePool(FileListNode);\r
1838}\r
1839/**\r
1840 Frees the file list.\r
1841\r
1842 This function cleans up the file list and any related data structures. It has no\r
1843 impact on the files themselves.\r
1844\r
1845 @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is\r
1846 defined in OpenFileList()\r
1847\r
1848 @retval EFI_SUCCESS Free the file list successfully.\r
1849 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;\r
1850**/\r
1851EFI_STATUS\r
1852EFIAPI\r
1853EfiShellFreeFileList(\r
1854 IN EFI_SHELL_FILE_INFO **FileList\r
1855 )\r
1856{\r
1857 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
1858\r
1859 if (FileList == NULL || *FileList == NULL) {\r
1860 return (EFI_INVALID_PARAMETER);\r
1861 }\r
1862\r
1863 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)\r
1864 ; !IsListEmpty(&(*FileList)->Link)\r
1865 ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)\r
1866 ){\r
1867 RemoveEntryList(&ShellFileListItem->Link);\r
1868 InternalFreeShellFileInfoNode(ShellFileListItem);\r
1869 }\r
c1f9c346 1870 InternalFreeShellFileInfoNode(*FileList);\r
8844288c 1871 *FileList = NULL;\r
a405b86d 1872 return(EFI_SUCCESS);\r
1873}\r
1874\r
1875/**\r
1876 Deletes the duplicate file names files in the given file list.\r
1877\r
1878 This function deletes the reduplicate files in the given file list.\r
1879\r
1880 @param FileList A pointer to the first entry in the file list.\r
1881\r
1882 @retval EFI_SUCCESS Always success.\r
1883 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;\r
1884**/\r
1885EFI_STATUS\r
1886EFIAPI\r
1887EfiShellRemoveDupInFileList(\r
1888 IN EFI_SHELL_FILE_INFO **FileList\r
1889 )\r
1890{\r
1891 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
1892 EFI_SHELL_FILE_INFO *ShellFileListItem2;\r
3e2b20a1 1893 EFI_SHELL_FILE_INFO *TempNode;\r
a405b86d 1894\r
1895 if (FileList == NULL || *FileList == NULL) {\r
1896 return (EFI_INVALID_PARAMETER);\r
1897 }\r
1898 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)\r
1899 ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link)\r
1900 ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)\r
1901 ){\r
1902 for ( ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)\r
1903 ; !IsNull(&(*FileList)->Link, &ShellFileListItem2->Link)\r
1904 ; ShellFileListItem2 = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem2->Link)\r
1905 ){\r
1906 if (gUnicodeCollation->StriColl(\r
1907 gUnicodeCollation,\r
1908 (CHAR16*)ShellFileListItem->FullName,\r
1909 (CHAR16*)ShellFileListItem2->FullName) == 0\r
1910 ){\r
3e2b20a1
BJ
1911 TempNode = (EFI_SHELL_FILE_INFO *)GetPreviousNode(\r
1912 &(*FileList)->Link,\r
1913 &ShellFileListItem2->Link\r
1914 );\r
a405b86d 1915 RemoveEntryList(&ShellFileListItem2->Link);\r
1916 InternalFreeShellFileInfoNode(ShellFileListItem2);\r
3e2b20a1
BJ
1917 // Set ShellFileListItem2 to PreviousNode so we don't access Freed\r
1918 // memory in GetNextNode in the loop expression above.\r
1919 ShellFileListItem2 = TempNode;\r
a405b86d 1920 }\r
1921 }\r
1922 }\r
1923 return (EFI_SUCCESS);\r
1924}\r
4b5168d8
JC
1925\r
1926//\r
1927// This is the same structure as the external version, but it has no CONST qualifiers.\r
1928//\r
1929typedef struct {\r
1930 LIST_ENTRY Link; ///< Linked list members.\r
1931 EFI_STATUS Status; ///< Status of opening the file. Valid only if Handle != NULL.\r
1932 CHAR16 *FullName; ///< Fully qualified filename.\r
1933 CHAR16 *FileName; ///< name of this file.\r
1934 SHELL_FILE_HANDLE Handle; ///< Handle for interacting with the opened file or NULL if closed.\r
1935 EFI_FILE_INFO *Info; ///< Pointer to the FileInfo struct for this file or NULL.\r
1936} EFI_SHELL_FILE_INFO_NO_CONST;\r
1937\r
a405b86d 1938/**\r
1939 Allocates and duplicates a EFI_SHELL_FILE_INFO node.\r
1940\r
1941 @param[in] Node The node to copy from.\r
1942 @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise.\r
1943\r
1944 @retval NULL a memory allocation error ocurred\r
1945 @return != NULL a pointer to the new node\r
1946**/\r
1947EFI_SHELL_FILE_INFO*\r
1948EFIAPI\r
1949InternalDuplicateShellFileInfo(\r
1950 IN EFI_SHELL_FILE_INFO *Node,\r
1951 IN BOOLEAN Save\r
1952 )\r
1953{\r
4b5168d8
JC
1954 EFI_SHELL_FILE_INFO_NO_CONST *NewNode;\r
1955\r
1956 //\r
1957 // try to confirm that the objects are in sync\r
1958 //\r
1959 ASSERT(sizeof(EFI_SHELL_FILE_INFO_NO_CONST) == sizeof(EFI_SHELL_FILE_INFO));\r
a405b86d 1960\r
733f138d 1961 NewNode = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
a405b86d 1962 if (NewNode == NULL) {\r
1963 return (NULL);\r
1964 }\r
7f79b01e
JC
1965 NewNode->FullName = AllocateCopyPool(StrSize(Node->FullName), Node->FullName);\r
1966 NewNode->FileName = AllocateCopyPool(StrSize(Node->FileName), Node->FileName);\r
1967 NewNode->Info = AllocateCopyPool((UINTN)Node->Info->Size, Node->Info);\r
a405b86d 1968 if ( NewNode->FullName == NULL\r
1969 || NewNode->FileName == NULL\r
1970 || NewNode->Info == NULL\r
4b5168d8
JC
1971 ){\r
1972 SHELL_FREE_NON_NULL(NewNode->FullName);\r
1973 SHELL_FREE_NON_NULL(NewNode->FileName);\r
1974 SHELL_FREE_NON_NULL(NewNode->Info);\r
1975 SHELL_FREE_NON_NULL(NewNode);\r
a405b86d 1976 return(NULL);\r
1977 }\r
1978 NewNode->Status = Node->Status;\r
1979 NewNode->Handle = Node->Handle;\r
1980 if (!Save) {\r
1981 Node->Handle = NULL;\r
1982 }\r
a405b86d 1983\r
4b5168d8 1984 return((EFI_SHELL_FILE_INFO*)NewNode);\r
a405b86d 1985}\r
1986\r
1987/**\r
1988 Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation\r
1989 failed it will return NULL.\r
1990\r
1991 @param[in] BasePath the Path to prepend onto filename for FullPath\r
1992 @param[in] Status Status member initial value.\r
a405b86d 1993 @param[in] FileName FileName member initial value.\r
1994 @param[in] Handle Handle member initial value.\r
1995 @param[in] Info Info struct to copy.\r
1996\r
1997 @retval NULL An error ocurred.\r
1998 @return a pointer to the newly allocated structure.\r
1999**/\r
2000EFI_SHELL_FILE_INFO *\r
2001EFIAPI\r
2002CreateAndPopulateShellFileInfo(\r
2003 IN CONST CHAR16 *BasePath,\r
2004 IN CONST EFI_STATUS Status,\r
a405b86d 2005 IN CONST CHAR16 *FileName,\r
2006 IN CONST SHELL_FILE_HANDLE Handle,\r
2007 IN CONST EFI_FILE_INFO *Info\r
2008 )\r
2009{\r
2010 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2011 CHAR16 *TempString;\r
2012 UINTN Size;\r
2013\r
2014 TempString = NULL;\r
2015 Size = 0;\r
2016\r
2017 ShellFileListItem = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
2018 if (ShellFileListItem == NULL) {\r
2019 return (NULL);\r
2020 }\r
74fa83fd 2021 if (Info != NULL && Info->Size != 0) {\r
a405b86d 2022 ShellFileListItem->Info = AllocateZeroPool((UINTN)Info->Size);\r
2023 if (ShellFileListItem->Info == NULL) {\r
2024 FreePool(ShellFileListItem);\r
2025 return (NULL);\r
2026 }\r
2027 CopyMem(ShellFileListItem->Info, Info, (UINTN)Info->Size);\r
2028 } else {\r
2029 ShellFileListItem->Info = NULL;\r
2030 }\r
2031 if (FileName != NULL) {\r
2032 ASSERT(TempString == NULL);\r
2033 ShellFileListItem->FileName = StrnCatGrow(&TempString, 0, FileName, 0);\r
2034 if (ShellFileListItem->FileName == NULL) {\r
2035 FreePool(ShellFileListItem->Info);\r
2036 FreePool(ShellFileListItem);\r
2037 return (NULL);\r
2038 }\r
2039 } else {\r
2040 ShellFileListItem->FileName = NULL;\r
2041 }\r
2042 Size = 0;\r
2043 TempString = NULL;\r
2044 if (BasePath != NULL) {\r
2045 ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
2046 TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
2047 if (TempString == NULL) {\r
2048 FreePool((VOID*)ShellFileListItem->FileName);\r
d0a5723f 2049 SHELL_FREE_NON_NULL(ShellFileListItem->Info);\r
a405b86d 2050 FreePool(ShellFileListItem);\r
2051 return (NULL);\r
2052 }\r
2053 }\r
2054 if (ShellFileListItem->FileName != NULL) {\r
2055 ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
2056 TempString = StrnCatGrow(&TempString, &Size, ShellFileListItem->FileName, 0);\r
2057 if (TempString == NULL) {\r
2058 FreePool((VOID*)ShellFileListItem->FileName);\r
2059 FreePool(ShellFileListItem->Info);\r
2060 FreePool(ShellFileListItem);\r
2061 return (NULL);\r
2062 }\r
2063 }\r
2064\r
bbf904d1
JC
2065 TempString = PathCleanUpDirectories(TempString);\r
2066\r
a405b86d 2067 ShellFileListItem->FullName = TempString;\r
2068 ShellFileListItem->Status = Status;\r
2069 ShellFileListItem->Handle = Handle;\r
2070\r
2071 return (ShellFileListItem);\r
2072}\r
2073\r
2074/**\r
2075 Find all files in a specified directory.\r
2076\r
2077 @param FileDirHandle Handle of the directory to search.\r
2078 @param FileList On return, points to the list of files in the directory\r
2079 or NULL if there are no files in the directory.\r
2080\r
2081 @retval EFI_SUCCESS File information was returned successfully.\r
2082 @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted.\r
2083 @retval EFI_DEVICE_ERROR The device reported an error.\r
2084 @retval EFI_NO_MEDIA The device media is not present.\r
2085 @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory.\r
2086 @return An error from FileHandleGetFileName().\r
2087**/\r
2088EFI_STATUS\r
2089EFIAPI\r
2090EfiShellFindFilesInDir(\r
2091 IN SHELL_FILE_HANDLE FileDirHandle,\r
2092 OUT EFI_SHELL_FILE_INFO **FileList\r
2093 )\r
2094{\r
2095 EFI_SHELL_FILE_INFO *ShellFileList;\r
2096 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2097 EFI_FILE_INFO *FileInfo;\r
2098 EFI_STATUS Status;\r
2099 BOOLEAN NoFile;\r
2100 CHAR16 *TempString;\r
2101 CHAR16 *BasePath;\r
2102 UINTN Size;\r
2103 CHAR16 *TempSpot;\r
2104\r
0d807dae 2105 BasePath = NULL;\r
a405b86d 2106 Status = FileHandleGetFileName(FileDirHandle, &BasePath);\r
2107 if (EFI_ERROR(Status)) {\r
2108 return (Status);\r
2109 }\r
2110\r
2111 if (ShellFileHandleGetPath(FileDirHandle) != NULL) {\r
2112 TempString = NULL;\r
2113 Size = 0;\r
2114 TempString = StrnCatGrow(&TempString, &Size, ShellFileHandleGetPath(FileDirHandle), 0);\r
532691c8 2115 if (TempString == NULL) {\r
c1f9c346 2116 SHELL_FREE_NON_NULL(BasePath);\r
532691c8 2117 return (EFI_OUT_OF_RESOURCES);\r
2118 }\r
a405b86d 2119 TempSpot = StrStr(TempString, L";");\r
2120\r
2121 if (TempSpot != NULL) {\r
2122 *TempSpot = CHAR_NULL;\r
2123 }\r
2124\r
2125 TempString = StrnCatGrow(&TempString, &Size, BasePath, 0);\r
532691c8 2126 if (TempString == NULL) {\r
c1f9c346 2127 SHELL_FREE_NON_NULL(BasePath);\r
532691c8 2128 return (EFI_OUT_OF_RESOURCES);\r
2129 }\r
c1f9c346 2130 SHELL_FREE_NON_NULL(BasePath);\r
a405b86d 2131 BasePath = TempString;\r
2132 }\r
2133\r
2134 NoFile = FALSE;\r
2135 ShellFileList = NULL;\r
2136 ShellFileListItem = NULL;\r
2137 FileInfo = NULL;\r
2138 Status = EFI_SUCCESS;\r
2139\r
2140\r
2141 for ( Status = FileHandleFindFirstFile(FileDirHandle, &FileInfo)\r
2142 ; !EFI_ERROR(Status) && !NoFile\r
2143 ; Status = FileHandleFindNextFile(FileDirHandle, FileInfo, &NoFile)\r
2144 ){\r
a405b86d 2145 //\r
2146 // allocate a new EFI_SHELL_FILE_INFO and populate it...\r
2147 //\r
a405b86d 2148 ShellFileListItem = CreateAndPopulateShellFileInfo(\r
2149 BasePath,\r
c1f9c346 2150 EFI_SUCCESS, // success since we didnt fail to open it...\r
a405b86d 2151 FileInfo->FileName,\r
c1f9c346 2152 NULL, // no handle since not open\r
a405b86d 2153 FileInfo);\r
2154\r
2155 if (ShellFileList == NULL) {\r
2156 ShellFileList = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
2157 ASSERT(ShellFileList != NULL);\r
2158 InitializeListHead(&ShellFileList->Link);\r
2159 }\r
2160 InsertTailList(&ShellFileList->Link, &ShellFileListItem->Link);\r
2161 }\r
2162 if (EFI_ERROR(Status)) {\r
2163 EfiShellFreeFileList(&ShellFileList);\r
2164 *FileList = NULL;\r
2165 } else {\r
2166 *FileList = ShellFileList;\r
2167 }\r
2168 SHELL_FREE_NON_NULL(BasePath);\r
2169 return(Status);\r
33fe8308 2170}\r
09fd5328
JC
2171\r
2172/**\r
2173 Get the GUID value from a human readable name.\r
2174\r
2175 If GuidName is a known GUID name, then update Guid to have the correct value for\r
2176 that GUID.\r
2177\r
2178 This function is only available when the major and minor versions in the\r
2179 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
2180\r
2181 @param[in] GuidName A pointer to the localized name for the GUID being queried.\r
2182 @param[out] Guid A pointer to the GUID structure to be filled in.\r
2183\r
2184 @retval EFI_SUCCESS The operation was successful.\r
2185 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
2186 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
2187 @retval EFI_NOT_FOUND GuidName is not a known GUID Name.\r
2188**/\r
2189EFI_STATUS\r
2190EFIAPI \r
2191EfiShellGetGuidFromName(\r
2192 IN CONST CHAR16 *GuidName,\r
2193 OUT EFI_GUID *Guid\r
2194 )\r
2195{\r
2196 EFI_GUID *NewGuid;\r
2197 EFI_STATUS Status;\r
2198\r
2199 if (Guid == NULL || GuidName == NULL) {\r
2200 return (EFI_INVALID_PARAMETER);\r
2201 }\r
2202 \r
2203 Status = GetGuidFromStringName(GuidName, NULL, &NewGuid);\r
2204\r
2205 if (!EFI_ERROR(Status)) {\r
2206 CopyGuid(NewGuid, Guid);\r
2207 }\r
2208\r
2209 return (Status);\r
2210}\r
2211\r
2212/**\r
2213 Get the human readable name for a GUID from the value.\r
2214\r
2215 If Guid is assigned a name, then update *GuidName to point to the name. The callee\r
2216 should not modify the value.\r
2217\r
2218 This function is only available when the major and minor versions in the\r
2219 EfiShellProtocol are greater than or equal to 2 and 1, respectively.\r
2220\r
2221 @param[in] Guid A pointer to the GUID being queried.\r
2222 @param[out] GuidName A pointer to a pointer the localized to name for the GUID being requested\r
2223\r
2224 @retval EFI_SUCCESS The operation was successful.\r
2225 @retval EFI_INVALID_PARAMETER Guid was NULL.\r
2226 @retval EFI_INVALID_PARAMETER GuidName was NULL.\r
2227 @retval EFI_NOT_FOUND Guid is not assigned a name.\r
2228**/\r
2229EFI_STATUS\r
2230EFIAPI \r
2231EfiShellGetGuidName(\r
2232 IN CONST EFI_GUID *Guid,\r
2233 OUT CONST CHAR16 **GuidName\r
2234 )\r
2235{\r
2236 CHAR16 *Name;\r
2237\r
2238 if (Guid == NULL || GuidName == NULL) {\r
2239 return (EFI_INVALID_PARAMETER);\r
2240 }\r
2241\r
2242 Name = GetStringNameFromGuid(Guid, NULL);\r
2243 if (Name == NULL || StrLen(Name) == 0) {\r
2244 SHELL_FREE_NON_NULL(Name);\r
2245 return (EFI_NOT_FOUND);\r
2246 }\r
2247\r
2248 *GuidName = AddBufferToFreeList(Name);\r
2249\r
2250 return (EFI_SUCCESS);\r
a405b86d 2251}\r
2252\r
2253/**\r
2254 Updates a file name to be preceeded by the mapped drive name\r
2255\r
4ff7e37b
ED
2256 @param[in] BasePath the Mapped drive name to prepend\r
2257 @param[in, out] Path pointer to pointer to the file name to update.\r
a405b86d 2258\r
2259 @retval EFI_SUCCESS\r
2260 @retval EFI_OUT_OF_RESOURCES\r
2261**/\r
2262EFI_STATUS\r
2263EFIAPI\r
2264UpdateFileName(\r
2265 IN CONST CHAR16 *BasePath,\r
2266 IN OUT CHAR16 **Path\r
2267 )\r
2268{\r
2269 CHAR16 *Path2;\r
2270 UINTN Path2Size;\r
2271\r
2272 Path2Size = 0;\r
2273 Path2 = NULL;\r
2274\r
2275 ASSERT(Path != NULL);\r
2276 ASSERT(*Path != NULL);\r
2277 ASSERT(BasePath != NULL);\r
2278\r
2279 //\r
2280 // convert a local path to an absolute path\r
2281 //\r
2282 if (StrStr(*Path, L":") == NULL) {\r
2283 ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
2284 StrnCatGrow(&Path2, &Path2Size, BasePath, 0);\r
2285 if (Path2 == NULL) {\r
2286 return (EFI_OUT_OF_RESOURCES);\r
2287 }\r
2288 ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
2289 StrnCatGrow(&Path2, &Path2Size, (*Path)[0] == L'\\'?(*Path) + 1 :*Path, 0);\r
2290 if (Path2 == NULL) {\r
2291 return (EFI_OUT_OF_RESOURCES);\r
2292 }\r
2293 }\r
2294\r
2295 FreePool(*Path);\r
2296 (*Path) = Path2;\r
2297\r
2298 return (EFI_SUCCESS);\r
2299}\r
2300\r
2301/**\r
2302 If FileHandle is a directory then the function reads from FileHandle and reads in\r
2303 each of the FileInfo structures. If one of them matches the Pattern's first\r
2304 "level" then it opens that handle and calls itself on that handle.\r
2305\r
2306 If FileHandle is a file and matches all of the remaining Pattern (which would be\r
2307 on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.\r
2308\r
a405b86d 2309 Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call\r
2310 FreeFileList with FileList.\r
2311\r
4ff7e37b
ED
2312 @param[in] FilePattern The FilePattern to check against.\r
2313 @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure\r
2314 @param[in] FileHandle The FileHandle to start with\r
2315 @param[in, out] FileList pointer to pointer to list of found files.\r
2316 @param[in] ParentNode The node for the parent. Same file as identified by HANDLE.\r
2317 @param[in] MapName The file system name this file is on.\r
a405b86d 2318\r
2319 @retval EFI_SUCCESS all files were found and the FileList contains a list.\r
2320 @retval EFI_NOT_FOUND no files were found\r
2321 @retval EFI_OUT_OF_RESOURCES a memory allocation failed\r
2322**/\r
2323EFI_STATUS\r
2324EFIAPI\r
2325ShellSearchHandle(\r
2326 IN CONST CHAR16 *FilePattern,\r
2327 IN EFI_UNICODE_COLLATION_PROTOCOL *UnicodeCollation,\r
2328 IN SHELL_FILE_HANDLE FileHandle,\r
2329 IN OUT EFI_SHELL_FILE_INFO **FileList,\r
8be0ba36 2330 IN CONST EFI_SHELL_FILE_INFO *ParentNode OPTIONAL,\r
2331 IN CONST CHAR16 *MapName\r
a405b86d 2332 )\r
2333{\r
2334 EFI_STATUS Status;\r
2335 CONST CHAR16 *NextFilePatternStart;\r
2336 CHAR16 *CurrentFilePattern;\r
2337 EFI_SHELL_FILE_INFO *ShellInfo;\r
2338 EFI_SHELL_FILE_INFO *ShellInfoNode;\r
2339 EFI_SHELL_FILE_INFO *NewShellNode;\r
d0a5723f 2340 EFI_FILE_INFO *FileInfo;\r
a405b86d 2341 BOOLEAN Directory;\r
8be0ba36 2342 CHAR16 *NewFullName;\r
2343 UINTN Size;\r
a405b86d 2344\r
2345 if ( FilePattern == NULL\r
2346 || UnicodeCollation == NULL\r
2347 || FileList == NULL\r
2348 ){\r
2349 return (EFI_INVALID_PARAMETER);\r
2350 }\r
2351 ShellInfo = NULL;\r
2352 CurrentFilePattern = NULL;\r
2353\r
2354 if (*FilePattern == L'\\') {\r
2355 FilePattern++;\r
2356 }\r
2357\r
2358 for( NextFilePatternStart = FilePattern\r
2359 ; *NextFilePatternStart != CHAR_NULL && *NextFilePatternStart != L'\\'\r
2360 ; NextFilePatternStart++);\r
2361\r
2362 CurrentFilePattern = AllocateZeroPool((NextFilePatternStart-FilePattern+1)*sizeof(CHAR16));\r
2363 ASSERT(CurrentFilePattern != NULL);\r
a5e28cc1 2364 StrnCpyS(CurrentFilePattern, NextFilePatternStart-FilePattern+1, FilePattern, NextFilePatternStart-FilePattern);\r
a405b86d 2365\r
2366 if (CurrentFilePattern[0] == CHAR_NULL\r
2367 &&NextFilePatternStart[0] == CHAR_NULL\r
d0a5723f 2368 ){\r
a405b86d 2369 //\r
d0a5723f 2370 // we want the parent or root node (if no parent)\r
a405b86d 2371 //\r
2372 if (ParentNode == NULL) {\r
d0a5723f
JC
2373 //\r
2374 // We want the root node. create the node.\r
2375 //\r
2376 FileInfo = FileHandleGetInfo(FileHandle);\r
2377 NewShellNode = CreateAndPopulateShellFileInfo(\r
bbf904d1 2378 MapName,\r
d0a5723f
JC
2379 EFI_SUCCESS,\r
2380 L"\\",\r
2381 FileHandle,\r
2382 FileInfo\r
2383 );\r
2384 SHELL_FREE_NON_NULL(FileInfo);\r
a405b86d 2385 } else {\r
d0a5723f
JC
2386 //\r
2387 // Add the current parameter FileHandle to the list, then end...\r
2388 //\r
a405b86d 2389 NewShellNode = InternalDuplicateShellFileInfo((EFI_SHELL_FILE_INFO*)ParentNode, TRUE);\r
d0a5723f
JC
2390 }\r
2391 if (NewShellNode == NULL) {\r
2392 Status = EFI_OUT_OF_RESOURCES;\r
2393 } else {\r
2394 NewShellNode->Handle = NULL;\r
2395 if (*FileList == NULL) {\r
2396 *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
2397 InitializeListHead(&((*FileList)->Link));\r
2398 }\r
a405b86d 2399\r
d0a5723f
JC
2400 //\r
2401 // Add to the returning to use list\r
2402 //\r
2403 InsertTailList(&(*FileList)->Link, &NewShellNode->Link);\r
a405b86d 2404\r
d0a5723f 2405 Status = EFI_SUCCESS;\r
a405b86d 2406 }\r
2407 } else {\r
2408 Status = EfiShellFindFilesInDir(FileHandle, &ShellInfo);\r
2409\r
2410 if (!EFI_ERROR(Status)){\r
2411 if (StrStr(NextFilePatternStart, L"\\") != NULL){\r
2412 Directory = TRUE;\r
2413 } else {\r
2414 Directory = FALSE;\r
2415 }\r
2416 for ( ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetFirstNode(&ShellInfo->Link)\r
2417 ; !IsNull (&ShellInfo->Link, &ShellInfoNode->Link)\r
2418 ; ShellInfoNode = (EFI_SHELL_FILE_INFO*)GetNextNode(&ShellInfo->Link, &ShellInfoNode->Link)\r
2419 ){\r
2420 if (UnicodeCollation->MetaiMatch(UnicodeCollation, (CHAR16*)ShellInfoNode->FileName, CurrentFilePattern)){\r
8be0ba36 2421 if (ShellInfoNode->FullName != NULL && StrStr(ShellInfoNode->FullName, L":") == NULL) {\r
2422 Size = StrSize(ShellInfoNode->FullName);\r
2423 Size += StrSize(MapName) + sizeof(CHAR16);\r
2424 NewFullName = AllocateZeroPool(Size);\r
2425 if (NewFullName == NULL) {\r
2426 Status = EFI_OUT_OF_RESOURCES;\r
2427 } else {\r
e75390f0
QS
2428 StrCpyS(NewFullName, Size/sizeof(CHAR16), MapName);\r
2429 StrCatS(NewFullName, Size/sizeof(CHAR16), ShellInfoNode->FullName+1);\r
8be0ba36 2430 FreePool((VOID*)ShellInfoNode->FullName);\r
2431 ShellInfoNode->FullName = NewFullName;\r
2432 }\r
2433 }\r
c154b997 2434 if (Directory && !EFI_ERROR(Status) && ShellInfoNode->FullName != NULL && ShellInfoNode->FileName != NULL){\r
a405b86d 2435 //\r
2436 // should be a directory\r
2437 //\r
2438\r
2439 //\r
2440 // don't open the . and .. directories\r
2441 //\r
2442 if ( (StrCmp(ShellInfoNode->FileName, L".") != 0)\r
2443 && (StrCmp(ShellInfoNode->FileName, L"..") != 0)\r
2444 ){\r
2445 //\r
2446 //\r
2447 //\r
a405b86d 2448 if (EFI_ERROR(Status)) {\r
2449 break;\r
2450 }\r
2451 //\r
2452 // Open the directory since we need that handle in the next recursion.\r
2453 //\r
2454 ShellInfoNode->Status = EfiShellOpenFileByName (ShellInfoNode->FullName, &ShellInfoNode->Handle, EFI_FILE_MODE_READ);\r
2455\r
2456 //\r
2457 // recurse with the next part of the pattern\r
2458 //\r
8be0ba36 2459 Status = ShellSearchHandle(NextFilePatternStart, UnicodeCollation, ShellInfoNode->Handle, FileList, ShellInfoNode, MapName);\r
06e5ae77
QS
2460 EfiShellClose(ShellInfoNode->Handle);\r
2461 ShellInfoNode->Handle = NULL;\r
a405b86d 2462 }\r
8be0ba36 2463 } else if (!EFI_ERROR(Status)) {\r
a405b86d 2464 //\r
2465 // should be a file\r
2466 //\r
2467\r
2468 //\r
2469 // copy the information we need into a new Node\r
2470 //\r
2471 NewShellNode = InternalDuplicateShellFileInfo(ShellInfoNode, FALSE);\r
2472 ASSERT(NewShellNode != NULL);\r
2473 if (NewShellNode == NULL) {\r
2474 Status = EFI_OUT_OF_RESOURCES;\r
2475 }\r
2476 if (*FileList == NULL) {\r
733f138d 2477 *FileList = AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
a405b86d 2478 InitializeListHead(&((*FileList)->Link));\r
2479 }\r
2480\r
2481 //\r
2482 // Add to the returning to use list\r
2483 //\r
2484 InsertTailList(&(*FileList)->Link, &NewShellNode->Link);\r
2485 }\r
2486 }\r
2487 if (EFI_ERROR(Status)) {\r
2488 break;\r
2489 }\r
2490 }\r
2491 if (EFI_ERROR(Status)) {\r
2492 EfiShellFreeFileList(&ShellInfo);\r
2493 } else {\r
2494 Status = EfiShellFreeFileList(&ShellInfo);\r
2495 }\r
2496 }\r
2497 }\r
2498\r
2499 FreePool(CurrentFilePattern);\r
2500 return (Status);\r
2501}\r
2502\r
2503/**\r
2504 Find files that match a specified pattern.\r
2505\r
2506 This function searches for all files and directories that match the specified\r
2507 FilePattern. The FilePattern can contain wild-card characters. The resulting file\r
2508 information is placed in the file list FileList.\r
2509\r
2510 Wildcards are processed\r
2511 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1.\r
2512\r
2513 The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo\r
2514 field is set to NULL.\r
2515\r
2516 if *FileList is not NULL then it must be a pre-existing and properly initialized list.\r
2517\r
2518 @param FilePattern Points to a NULL-terminated shell file path, including wildcards.\r
2519 @param FileList On return, points to the start of a file list containing the names\r
2520 of all matching files or else points to NULL if no matching files\r
2521 were found. only on a EFI_SUCCESS return will; this be non-NULL.\r
2522\r
2523 @retval EFI_SUCCESS Files found. FileList is a valid list.\r
2524 @retval EFI_NOT_FOUND No files found.\r
2525 @retval EFI_NO_MEDIA The device has no media\r
2526 @retval EFI_DEVICE_ERROR The device reported an error\r
2527 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted\r
2528**/\r
2529EFI_STATUS\r
2530EFIAPI\r
2531EfiShellFindFiles(\r
2532 IN CONST CHAR16 *FilePattern,\r
2533 OUT EFI_SHELL_FILE_INFO **FileList\r
2534 )\r
2535{\r
2536 EFI_STATUS Status;\r
2537 CHAR16 *PatternCopy;\r
2538 CHAR16 *PatternCurrentLocation;\r
2539 EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;\r
2540 SHELL_FILE_HANDLE RootFileHandle;\r
2541 CHAR16 *MapName;\r
2542 UINTN Count;\r
2543\r
2544 if ( FilePattern == NULL\r
2545 || FileList == NULL\r
2546 || StrStr(FilePattern, L":") == NULL\r
2547 ){\r
2548 return (EFI_INVALID_PARAMETER);\r
2549 }\r
2550 Status = EFI_SUCCESS;\r
2551 RootDevicePath = NULL;\r
2552 RootFileHandle = NULL;\r
2553 MapName = NULL;\r
7f79b01e 2554 PatternCopy = AllocateCopyPool(StrSize(FilePattern), FilePattern);\r
a405b86d 2555 if (PatternCopy == NULL) {\r
2556 return (EFI_OUT_OF_RESOURCES);\r
2557 }\r
a405b86d 2558\r
ab94587a 2559 PatternCopy = PathCleanUpDirectories(PatternCopy);\r
a405b86d 2560\r
2561 Count = StrStr(PatternCopy, L":") - PatternCopy;\r
2562 Count += 2;\r
2563\r
2564 ASSERT(MapName == NULL);\r
2565 MapName = StrnCatGrow(&MapName, NULL, PatternCopy, Count);\r
532691c8 2566 if (MapName == NULL) {\r
2567 Status = EFI_OUT_OF_RESOURCES;\r
c8c22591 2568 } else {\r
a405b86d 2569 RootDevicePath = EfiShellGetDevicePathFromFilePath(PatternCopy);\r
2570 if (RootDevicePath == NULL) {\r
2571 Status = EFI_INVALID_PARAMETER;\r
2572 } else {\r
2573 Status = EfiShellOpenRoot(RootDevicePath, &RootFileHandle);\r
2574 if (!EFI_ERROR(Status)) {\r
2575 for ( PatternCurrentLocation = PatternCopy\r
2576 ; *PatternCurrentLocation != ':'\r
2577 ; PatternCurrentLocation++);\r
2578 PatternCurrentLocation++;\r
8be0ba36 2579 Status = ShellSearchHandle(PatternCurrentLocation, gUnicodeCollation, RootFileHandle, FileList, NULL, MapName);\r
06e5ae77 2580 EfiShellClose(RootFileHandle);\r
a405b86d 2581 }\r
2582 FreePool(RootDevicePath);\r
2583 }\r
2584 }\r
2585\r
8be0ba36 2586 SHELL_FREE_NON_NULL(PatternCopy);\r
2587 SHELL_FREE_NON_NULL(MapName);\r
a405b86d 2588\r
2589 return(Status);\r
2590}\r
2591\r
2592/**\r
2593 Opens the files that match the path specified.\r
2594\r
2595 This function opens all of the files specified by Path. Wildcards are processed\r
2596 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each\r
2597 matching file has an EFI_SHELL_FILE_INFO structure created in a linked list.\r
2598\r
2599 @param Path A pointer to the path string.\r
2600 @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or\r
2601 EFI_FILE_MODE_WRITE.\r
2602 @param FileList Points to the start of a list of files opened.\r
2603\r
2604 @retval EFI_SUCCESS Create the file list successfully.\r
2605 @return Others Can't create the file list.\r
2606**/\r
2607EFI_STATUS\r
2608EFIAPI\r
2609EfiShellOpenFileList(\r
2610 IN CHAR16 *Path,\r
2611 IN UINT64 OpenMode,\r
2612 IN OUT EFI_SHELL_FILE_INFO **FileList\r
2613 )\r
2614{\r
2615 EFI_STATUS Status;\r
2616 EFI_SHELL_FILE_INFO *ShellFileListItem;\r
2617 CHAR16 *Path2;\r
2618 UINTN Path2Size;\r
2619 CONST CHAR16 *CurDir;\r
733f138d 2620 BOOLEAN Found;\r
a405b86d 2621\r
ab94587a 2622 PathCleanUpDirectories(Path);\r
a405b86d 2623\r
2624 Path2Size = 0;\r
2625 Path2 = NULL;\r
2626\r
733f138d 2627 if (FileList == NULL || *FileList == NULL) {\r
2628 return (EFI_INVALID_PARAMETER);\r
2629 }\r
a405b86d 2630\r
2631 if (*Path == L'.' && *(Path+1) == L'\\') {\r
733f138d 2632 Path+=2;\r
a405b86d 2633 }\r
2634\r
2635 //\r
2636 // convert a local path to an absolute path\r
2637 //\r
2638 if (StrStr(Path, L":") == NULL) {\r
2639 CurDir = EfiShellGetCurDir(NULL);\r
2640 ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
2641 StrnCatGrow(&Path2, &Path2Size, CurDir, 0);\r
fbd2dfad 2642 StrnCatGrow(&Path2, &Path2Size, L"\\", 0);\r
a405b86d 2643 if (*Path == L'\\') {\r
2644 Path++;\r
ab94587a 2645 while (PathRemoveLastItem(Path2)) ;\r
a405b86d 2646 }\r
2647 ASSERT((Path2 == NULL && Path2Size == 0) || (Path2 != NULL));\r
2648 StrnCatGrow(&Path2, &Path2Size, Path, 0);\r
2649 } else {\r
2650 ASSERT(Path2 == NULL);\r
2651 StrnCatGrow(&Path2, NULL, Path, 0);\r
2652 }\r
2653\r
ab94587a 2654 PathCleanUpDirectories (Path2);\r
a405b86d 2655\r
2656 //\r
2657 // do the search\r
2658 //\r
2659 Status = EfiShellFindFiles(Path2, FileList);\r
2660\r
2661 FreePool(Path2);\r
2662\r
2663 if (EFI_ERROR(Status)) {\r
2664 return (Status);\r
2665 }\r
2666\r
733f138d 2667 Found = FALSE;\r
a405b86d 2668 //\r
2669 // We had no errors so open all the files (that are not already opened...)\r
2670 //\r
2671 for ( ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(*FileList)->Link)\r
2672 ; !IsNull(&(*FileList)->Link, &ShellFileListItem->Link)\r
2673 ; ShellFileListItem = (EFI_SHELL_FILE_INFO*)GetNextNode(&(*FileList)->Link, &ShellFileListItem->Link)\r
2674 ){\r
2675 if (ShellFileListItem->Status == 0 && ShellFileListItem->Handle == NULL) {\r
2676 ShellFileListItem->Status = EfiShellOpenFileByName (ShellFileListItem->FullName, &ShellFileListItem->Handle, OpenMode);\r
733f138d 2677 Found = TRUE;\r
a405b86d 2678 }\r
2679 }\r
2680\r
733f138d 2681 if (!Found) {\r
2682 return (EFI_NOT_FOUND);\r
2683 }\r
a405b86d 2684 return(EFI_SUCCESS);\r
2685}\r
2686\r
2687/**\r
09fd5328
JC
2688 Gets the environment variable and Attributes, or list of environment variables. Can be\r
2689 used instead of GetEnv().\r
2690\r
2691 This function returns the current value of the specified environment variable and\r
2692 the Attributes. If no variable name was specified, then all of the known\r
2693 variables will be returned.\r
2694\r
2695 @param[in] Name A pointer to the environment variable name. If Name is NULL,\r
2696 then the function will return all of the defined shell\r
2697 environment variables. In the case where multiple environment\r
2698 variables are being returned, each variable will be terminated\r
2699 by a NULL, and the list will be terminated by a double NULL.\r
2700 @param[out] Attributes If not NULL, a pointer to the returned attributes bitmask for\r
2701 the environment variable. In the case where Name is NULL, and\r
2702 multiple environment variables are being returned, Attributes\r
2703 is undefined.\r
2704\r
f5ba4007
QS
2705 @retval NULL The environment variable doesn't exist.\r
2706 @return A non-NULL value points to the variable's value. The returned\r
09fd5328 2707 pointer does not need to be freed by the caller.\r
a405b86d 2708**/\r
2709CONST CHAR16 *\r
09fd5328
JC
2710EFIAPI \r
2711EfiShellGetEnvEx(\r
2712 IN CONST CHAR16 *Name,\r
2713 OUT UINT32 *Attributes OPTIONAL\r
a405b86d 2714 )\r
2715{\r
2716 EFI_STATUS Status;\r
2717 VOID *Buffer;\r
2718 UINTN Size;\r
a405b86d 2719 ENV_VAR_LIST *Node;\r
2720 CHAR16 *CurrentWriteLocation;\r
2721\r
2722 Size = 0;\r
2723 Buffer = NULL;\r
2724\r
2725 if (Name == NULL) {\r
a405b86d 2726\r
2727 //\r
2728 // Build the semi-colon delimited list. (2 passes)\r
2729 //\r
b62bb885
QS
2730 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
2731 ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
2732 ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
a405b86d 2733 ){\r
2734 ASSERT(Node->Key != NULL);\r
2735 Size += StrSize(Node->Key);\r
2736 }\r
2737\r
2738 Size += 2*sizeof(CHAR16);\r
2739\r
2740 Buffer = AllocateZeroPool(Size);\r
3c865f20 2741 if (Buffer == NULL) {\r
3c865f20 2742 return (NULL);\r
2743 }\r
a405b86d 2744 CurrentWriteLocation = (CHAR16*)Buffer;\r
2745\r
b62bb885
QS
2746 for ( Node = (ENV_VAR_LIST*)GetFirstNode(&gShellEnvVarList.Link)\r
2747 ; !IsNull(&gShellEnvVarList.Link, &Node->Link)\r
2748 ; Node = (ENV_VAR_LIST*)GetNextNode(&gShellEnvVarList.Link, &Node->Link)\r
a405b86d 2749 ){\r
2750 ASSERT(Node->Key != NULL);\r
e75390f0
QS
2751 StrCpyS( CurrentWriteLocation, \r
2752 (Size)/sizeof(CHAR16) - (CurrentWriteLocation - ((CHAR16*)Buffer)), \r
2753 Node->Key\r
2754 );\r
a405b86d 2755 CurrentWriteLocation += StrLen(CurrentWriteLocation) + 1;\r
2756 }\r
2757\r
a405b86d 2758 } else {\r
2759 //\r
2760 // We are doing a specific environment variable\r
2761 //\r
b62bb885 2762 Status = ShellFindEnvVarInList(Name, (CHAR16**)&Buffer, &Size, Attributes);\r
a405b86d 2763\r
b62bb885 2764 if (EFI_ERROR(Status)){\r
a405b86d 2765 //\r
b62bb885 2766 // get the size we need for this EnvVariable\r
a405b86d 2767 //\r
09fd5328 2768 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);\r
b62bb885
QS
2769 if (Status == EFI_BUFFER_TOO_SMALL) {\r
2770 //\r
2771 // Allocate the space and recall the get function\r
2772 //\r
2773 Buffer = AllocateZeroPool(Size);\r
2774 Status = SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES(Name, Attributes, &Size, Buffer);\r
2775 }\r
2776 //\r
2777 // we didnt get it (might not exist)\r
2778 // free the memory if we allocated any and return NULL\r
2779 //\r
2780 if (EFI_ERROR(Status)) {\r
2781 if (Buffer != NULL) {\r
2782 FreePool(Buffer);\r
2783 }\r
2784 return (NULL);\r
2785 } else {\r
2786 //\r
2787 // If we did not find the environment variable in the gShellEnvVarList\r
2788 // but get it from UEFI variable storage successfully then we need update\r
2789 // the gShellEnvVarList.\r
2790 //\r
2791 ShellFreeEnvVarList ();\r
2792 Status = ShellInitEnvVarList ();\r
2793 ASSERT (Status == EFI_SUCCESS);\r
a405b86d 2794 }\r
a405b86d 2795 }\r
2796 }\r
2797\r
2798 //\r
2799 // return the buffer\r
2800 //\r
2801 return (AddBufferToFreeList(Buffer));\r
2802}\r
2803\r
09fd5328
JC
2804/**\r
2805 Gets either a single or list of environment variables.\r
2806\r
2807 If name is not NULL then this function returns the current value of the specified\r
2808 environment variable.\r
2809\r
2810 If Name is NULL, then a list of all environment variable names is returned. Each is a\r
2811 NULL terminated string with a double NULL terminating the list.\r
2812\r
2813 @param Name A pointer to the environment variable name. If\r
2814 Name is NULL, then the function will return all\r
2815 of the defined shell environment variables. In\r
2816 the case where multiple environment variables are\r
2817 being returned, each variable will be terminated by\r
2818 a NULL, and the list will be terminated by a double\r
2819 NULL.\r
2820\r
2821 @retval !=NULL A pointer to the returned string.\r
2822 The returned pointer does not need to be freed by the caller.\r
2823\r
2824 @retval NULL The environment variable doesn't exist or there are\r
2825 no environment variables.\r
2826**/\r
2827CONST CHAR16 *\r
2828EFIAPI\r
2829EfiShellGetEnv(\r
2830 IN CONST CHAR16 *Name\r
2831 )\r
2832{\r
2833 return (EfiShellGetEnvEx(Name, NULL));\r
2834}\r
2835\r
a405b86d 2836/**\r
2837 Internal variable setting function. Allows for setting of the read only variables.\r
2838\r
2839 @param Name Points to the NULL-terminated environment variable name.\r
2840 @param Value Points to the NULL-terminated environment variable value. If the value is an\r
2841 empty string then the environment variable is deleted.\r
2842 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).\r
2843\r
2844 @retval EFI_SUCCESS The environment variable was successfully updated.\r
2845**/\r
2846EFI_STATUS\r
2847EFIAPI\r
2848InternalEfiShellSetEnv(\r
2849 IN CONST CHAR16 *Name,\r
2850 IN CONST CHAR16 *Value,\r
2851 IN BOOLEAN Volatile\r
2852 )\r
2853{\r
b62bb885
QS
2854 EFI_STATUS Status;\r
2855 UINT32 Atts;\r
2856\r
2857 Atts = 0x0;\r
2858 \r
a405b86d 2859 if (Value == NULL || StrLen(Value) == 0) {\r
b62bb885
QS
2860 Status = SHELL_DELETE_ENVIRONMENT_VARIABLE(Name);\r
2861 if (!EFI_ERROR(Status)) {\r
2862 ShellRemvoeEnvVarFromList(Name);\r
2863 }\r
2864 return Status;\r
a405b86d 2865 } else {\r
2866 SHELL_DELETE_ENVIRONMENT_VARIABLE(Name);\r
2867 if (Volatile) {\r
b62bb885
QS
2868 Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(Name, StrSize(Value), Value);\r
2869 if (!EFI_ERROR(Status)) {\r
2870 Atts &= ~EFI_VARIABLE_NON_VOLATILE;\r
2871 Atts |= EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
2872 ShellAddEnvVarToList(Name, Value, StrSize(Value), Atts);\r
2873 }\r
2874 return Status;\r
a405b86d 2875 } else {\r
b62bb885
QS
2876 Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(Name, StrSize(Value), Value);\r
2877 if (!EFI_ERROR(Status)) {\r
2878 Atts |= EFI_VARIABLE_NON_VOLATILE;\r
2879 Atts |= EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
2880 ShellAddEnvVarToList(Name, Value, StrSize(Value), Atts);\r
2881 } \r
2882 return Status;\r
a405b86d 2883 }\r
2884 }\r
2885}\r
2886\r
2887/**\r
2888 Sets the environment variable.\r
2889\r
2890 This function changes the current value of the specified environment variable. If the\r
2891 environment variable exists and the Value is an empty string, then the environment\r
2892 variable is deleted. If the environment variable exists and the Value is not an empty\r
2893 string, then the value of the environment variable is changed. If the environment\r
2894 variable does not exist and the Value is an empty string, there is no action. If the\r
2895 environment variable does not exist and the Value is a non-empty string, then the\r
2896 environment variable is created and assigned the specified value.\r
2897\r
2898 For a description of volatile and non-volatile environment variables, see UEFI Shell\r
2899 2.0 specification section 3.6.1.\r
2900\r
2901 @param Name Points to the NULL-terminated environment variable name.\r
2902 @param Value Points to the NULL-terminated environment variable value. If the value is an\r
2903 empty string then the environment variable is deleted.\r
2904 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).\r
2905\r
2906 @retval EFI_SUCCESS The environment variable was successfully updated.\r
2907**/\r
2908EFI_STATUS\r
2909EFIAPI\r
2910EfiShellSetEnv(\r
2911 IN CONST CHAR16 *Name,\r
2912 IN CONST CHAR16 *Value,\r
2913 IN BOOLEAN Volatile\r
2914 )\r
2915{\r
2916 if (Name == NULL || *Name == CHAR_NULL) {\r
2917 return (EFI_INVALID_PARAMETER);\r
2918 }\r
2919 //\r
2920 // Make sure we dont 'set' a predefined read only variable\r
2921 //\r
2922 if (gUnicodeCollation->StriColl(\r
2923 gUnicodeCollation,\r
2924 (CHAR16*)Name,\r
2925 L"cwd") == 0\r
2926 ||gUnicodeCollation->StriColl(\r
2927 gUnicodeCollation,\r
2928 (CHAR16*)Name,\r
2929 L"Lasterror") == 0\r
2930 ||gUnicodeCollation->StriColl(\r
2931 gUnicodeCollation,\r
2932 (CHAR16*)Name,\r
2933 L"profiles") == 0\r
2934 ||gUnicodeCollation->StriColl(\r
2935 gUnicodeCollation,\r
2936 (CHAR16*)Name,\r
2937 L"uefishellsupport") == 0\r
2938 ||gUnicodeCollation->StriColl(\r
2939 gUnicodeCollation,\r
2940 (CHAR16*)Name,\r
2941 L"uefishellversion") == 0\r
2942 ||gUnicodeCollation->StriColl(\r
2943 gUnicodeCollation,\r
2944 (CHAR16*)Name,\r
2945 L"uefiversion") == 0\r
dcbdb8bf
QS
2946 ||(!ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoNest &&\r
2947 gUnicodeCollation->StriColl(\r
2948 gUnicodeCollation,\r
2949 (CHAR16*)Name,\r
2950 (CHAR16*)mNoNestingEnvVarName) == 0)\r
a405b86d 2951 ){\r
2952 return (EFI_INVALID_PARAMETER);\r
2953 }\r
2954 return (InternalEfiShellSetEnv(Name, Value, Volatile));\r
2955}\r
2956\r
2957/**\r
2958 Returns the current directory on the specified device.\r
2959\r
2960 If FileSystemMapping is NULL, it returns the current working directory. If the\r
2961 FileSystemMapping is not NULL, it returns the current directory associated with the\r
2962 FileSystemMapping. In both cases, the returned name includes the file system\r
2963 mapping (i.e. fs0:\current-dir).\r
dcbdb8bf 2964\r
fbd2dfad 2965 Note that the current directory string should exclude the tailing backslash character.\r
a405b86d 2966\r
2967 @param FileSystemMapping A pointer to the file system mapping. If NULL,\r
2968 then the current working directory is returned.\r
2969\r
2970 @retval !=NULL The current directory.\r
2971 @retval NULL Current directory does not exist.\r
2972**/\r
2973CONST CHAR16 *\r
2974EFIAPI\r
2975EfiShellGetCurDir(\r
2976 IN CONST CHAR16 *FileSystemMapping OPTIONAL\r
2977 )\r
2978{\r
2979 CHAR16 *PathToReturn;\r
2980 UINTN Size;\r
2981 SHELL_MAP_LIST *MapListItem;\r
2982 if (!IsListEmpty(&gShellMapList.Link)) {\r
2983 //\r
2984 // if parameter is NULL, use current\r
2985 //\r
2986 if (FileSystemMapping == NULL) {\r
2987 return (EfiShellGetEnv(L"cwd"));\r
2988 } else {\r
2989 Size = 0;\r
2990 PathToReturn = NULL;\r
2991 MapListItem = ShellCommandFindMapItem(FileSystemMapping);\r
2992 if (MapListItem != NULL) {\r
2993 ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL));\r
2994 PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->MapName, 0);\r
2995 PathToReturn = StrnCatGrow(&PathToReturn, &Size, MapListItem->CurrentDirectoryPath, 0);\r
2996 }\r
2997 }\r
2998 return (AddBufferToFreeList(PathToReturn));\r
2999 } else {\r
3000 return (NULL);\r
3001 }\r
3002}\r
3003\r
3004/**\r
3005 Changes the current directory on the specified device.\r
3006\r
3007 If the FileSystem is NULL, and the directory Dir does not contain a file system's\r
3008 mapped name, this function changes the current working directory.\r
3009\r
3010 If the FileSystem is NULL and the directory Dir contains a mapped name, then the\r
3011 current file system and the current directory on that file system are changed.\r
3012\r
3013 If FileSystem is NULL, and Dir is not NULL, then this changes the current working file\r
3014 system.\r
3015\r
3016 If FileSystem is not NULL and Dir is not NULL, then this function changes the current\r
3017 directory on the specified file system.\r
3018\r
3019 If the current working directory or the current working file system is changed then the\r
3020 %cwd% environment variable will be updated\r
3021\r
fbd2dfad
QS
3022 Note that the current directory string should exclude the tailing backslash character.\r
3023\r
a405b86d 3024 @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working\r
3025 directory is changed.\r
3026 @param Dir Points to the NULL-terminated directory on the device specified by FileSystem.\r
3027\r
3028 @retval EFI_SUCCESS The operation was sucessful\r
3029 @retval EFI_NOT_FOUND The file system could not be found\r
3030**/\r
3031EFI_STATUS\r
3032EFIAPI\r
3033EfiShellSetCurDir(\r
3034 IN CONST CHAR16 *FileSystem OPTIONAL,\r
3035 IN CONST CHAR16 *Dir\r
3036 )\r
3037{\r
3038 CHAR16 *MapName;\r
3039 SHELL_MAP_LIST *MapListItem;\r
3040 UINTN Size;\r
3041 EFI_STATUS Status;\r
3042 CHAR16 *TempString;\r
3043 CHAR16 *DirectoryName;\r
3044 UINTN TempLen;\r
3045\r
3046 Size = 0;\r
3047 MapName = NULL;\r
3048 MapListItem = NULL;\r
3049 TempString = NULL;\r
3050 DirectoryName = NULL;\r
3051\r
3c865f20 3052 if ((FileSystem == NULL && Dir == NULL) || Dir == NULL) {\r
a405b86d 3053 return (EFI_INVALID_PARAMETER);\r
3054 }\r
3055\r
3056 if (IsListEmpty(&gShellMapList.Link)){\r
3057 return (EFI_NOT_FOUND);\r
3058 }\r
3059\r
3060 DirectoryName = StrnCatGrow(&DirectoryName, NULL, Dir, 0);\r
3061 ASSERT(DirectoryName != NULL);\r
3062\r
ab94587a 3063 PathCleanUpDirectories(DirectoryName);\r
a405b86d 3064\r
3065 if (FileSystem == NULL) {\r
3066 //\r
3067 // determine the file system mapping to use\r
3068 //\r
3069 if (StrStr(DirectoryName, L":") != NULL) {\r
3070 ASSERT(MapName == NULL);\r
3071 MapName = StrnCatGrow(&MapName, NULL, DirectoryName, (StrStr(DirectoryName, L":")-DirectoryName+1));\r
3072 }\r
3073 //\r
3074 // find the file system mapping's entry in the list\r
3075 // or use current\r
3076 //\r
3077 if (MapName != NULL) {\r
3078 MapListItem = ShellCommandFindMapItem(MapName);\r
3079\r
3080 //\r
3081 // make that the current file system mapping\r
3082 //\r
3083 if (MapListItem != NULL) {\r
3084 gShellCurDir = MapListItem;\r
3085 }\r
3086 } else {\r
3087 MapListItem = gShellCurDir;\r
3088 }\r
3089\r
3090 if (MapListItem == NULL) {\r
4aec9fe3
JY
3091 FreePool (DirectoryName);\r
3092 SHELL_FREE_NON_NULL(MapName);\r
a405b86d 3093 return (EFI_NOT_FOUND);\r
3094 }\r
3095\r
3096 //\r
3097 // now update the MapListItem's current directory\r
3098 //\r
3099 if (MapListItem->CurrentDirectoryPath != NULL && DirectoryName[StrLen(DirectoryName) - 1] != L':') {\r
3100 FreePool(MapListItem->CurrentDirectoryPath);\r
3101 MapListItem->CurrentDirectoryPath = NULL;\r
3102 }\r
3103 if (MapName != NULL) {\r
3104 TempLen = StrLen(MapName);\r
3105 if (TempLen != StrLen(DirectoryName)) {\r
3106 ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3107 MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName+StrLen(MapName), 0);\r
3108 }\r
4aec9fe3 3109 FreePool (MapName);\r
a405b86d 3110 } else {\r
3111 ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3112 MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
3113 }\r
fbd2dfad 3114 if ((MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') || (MapListItem->CurrentDirectoryPath == NULL)) {\r
a405b86d 3115 ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
fbd2dfad
QS
3116 if (MapListItem->CurrentDirectoryPath != NULL) {\r
3117 MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
dcbdb8bf 3118 }\r
a405b86d 3119 }\r
3120 } else {\r
3121 //\r
3122 // cant have a mapping in the directory...\r
3123 //\r
3124 if (StrStr(DirectoryName, L":") != NULL) {\r
4aec9fe3 3125 FreePool (DirectoryName);\r
a405b86d 3126 return (EFI_INVALID_PARAMETER);\r
3127 }\r
3128 //\r
3129 // FileSystem != NULL\r
3130 //\r
3131 MapListItem = ShellCommandFindMapItem(FileSystem);\r
3132 if (MapListItem == NULL) {\r
4aec9fe3 3133 FreePool (DirectoryName);\r
a405b86d 3134 return (EFI_INVALID_PARAMETER);\r
3135 }\r
3136// gShellCurDir = MapListItem;\r
3137 if (DirectoryName != NULL) {\r
3138 //\r
3139 // change current dir on that file system\r
3140 //\r
3141\r
3142 if (MapListItem->CurrentDirectoryPath != NULL) {\r
3143 FreePool(MapListItem->CurrentDirectoryPath);\r
3144 DEBUG_CODE(MapListItem->CurrentDirectoryPath = NULL;);\r
3145 }\r
3146// ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3147// MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);\r
3148 ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3149 MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, L"\\", 0);\r
3150 ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
3151 MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, DirectoryName, 0);\r
fbd2dfad 3152 if (MapListItem->CurrentDirectoryPath != NULL && MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] == L'\\') {\r
a405b86d 3153 ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));\r
fbd2dfad 3154 MapListItem->CurrentDirectoryPath[StrLen(MapListItem->CurrentDirectoryPath)-1] = CHAR_NULL;\r
a405b86d 3155 }\r
3156 }\r
3157 }\r
4aec9fe3 3158 FreePool (DirectoryName);\r
a405b86d 3159 //\r
3160 // if updated the current directory then update the environment variable\r
3161 //\r
3162 if (MapListItem == gShellCurDir) {\r
3163 Size = 0;\r
3164 ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
3165 StrnCatGrow(&TempString, &Size, MapListItem->MapName, 0);\r
3166 ASSERT((TempString == NULL && Size == 0) || (TempString != NULL));\r
3167 StrnCatGrow(&TempString, &Size, MapListItem->CurrentDirectoryPath, 0);\r
3168 Status = InternalEfiShellSetEnv(L"cwd", TempString, TRUE);\r
3169 FreePool(TempString);\r
3170 return (Status);\r
3171 }\r
3172 return(EFI_SUCCESS);\r
3173}\r
3174\r
3175/**\r
3176 Return help information about a specific command.\r
3177\r
3178 This function returns the help information for the specified command. The help text\r
3179 can be internal to the shell or can be from a UEFI Shell manual page.\r
3180\r
3181 If Sections is specified, then each section name listed will be compared in a casesensitive\r
3182 manner, to the section names described in Appendix B. If the section exists,\r
3183 it will be appended to the returned help text. If the section does not exist, no\r
3184 information will be returned. If Sections is NULL, then all help text information\r
3185 available will be returned.\r
3186\r
3187 @param Command Points to the NULL-terminated UEFI Shell command name.\r
3188 @param Sections Points to the NULL-terminated comma-delimited\r
3189 section names to return. If NULL, then all\r
3190 sections will be returned.\r
3191 @param HelpText On return, points to a callee-allocated buffer\r
3192 containing all specified help text.\r
3193\r
3194 @retval EFI_SUCCESS The help text was returned.\r
3195 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the\r
3196 returned help text.\r
3197 @retval EFI_INVALID_PARAMETER HelpText is NULL\r
3198 @retval EFI_NOT_FOUND There is no help text available for Command.\r
3199**/\r
3200EFI_STATUS\r
3201EFIAPI\r
3202EfiShellGetHelpText(\r
3203 IN CONST CHAR16 *Command,\r
3204 IN CONST CHAR16 *Sections OPTIONAL,\r
3205 OUT CHAR16 **HelpText\r
3206 )\r
3207{\r
3208 CONST CHAR16 *ManFileName;\r
42f75495
SQ
3209 CHAR16 *FixCommand;\r
3210 EFI_STATUS Status;\r
a405b86d 3211\r
3212 ASSERT(HelpText != NULL);\r
42f75495 3213 FixCommand = NULL;\r
a405b86d 3214\r
3215 ManFileName = ShellCommandGetManFileNameHandler(Command);\r
3216\r
3217 if (ManFileName != NULL) {\r
3218 return (ProcessManFile(ManFileName, Command, Sections, NULL, HelpText));\r
3219 } else {\r
42f75495
SQ
3220 if ((StrLen(Command)> 4)\r
3221 && (Command[StrLen(Command)-1] == L'i' || Command[StrLen(Command)-1] == L'I')\r
3222 && (Command[StrLen(Command)-2] == L'f' || Command[StrLen(Command)-2] == L'F')\r
3223 && (Command[StrLen(Command)-3] == L'e' || Command[StrLen(Command)-3] == L'E')\r
3224 && (Command[StrLen(Command)-4] == L'.')\r
3225 ) {\r
3226 FixCommand = AllocateZeroPool(StrSize(Command) - 4 * sizeof (CHAR16));\r
3227 ASSERT(FixCommand != NULL);\r
3228\r
e75390f0
QS
3229 StrnCpyS( FixCommand, \r
3230 (StrSize(Command) - 4 * sizeof (CHAR16))/sizeof(CHAR16), \r
3231 Command, \r
3232 StrLen(Command)-4\r
3233 );\r
42f75495
SQ
3234 Status = ProcessManFile(FixCommand, FixCommand, Sections, NULL, HelpText);\r
3235 FreePool(FixCommand);\r
3236 return Status;\r
3237 } else {\r
3238 return (ProcessManFile(Command, Command, Sections, NULL, HelpText));\r
3239 }\r
a405b86d 3240 }\r
3241}\r
3242\r
3243/**\r
3244 Gets the enable status of the page break output mode.\r
3245\r
3246 User can use this function to determine current page break mode.\r
3247\r
3248 @retval TRUE The page break output mode is enabled.\r
3249 @retval FALSE The page break output mode is disabled.\r
3250**/\r
3251BOOLEAN\r
3252EFIAPI\r
3253EfiShellGetPageBreak(\r
3254 VOID\r
3255 )\r
3256{\r
3257 return(ShellInfoObject.PageBreakEnabled);\r
3258}\r
3259\r
3260/**\r
3261 Judges whether the active shell is the root shell.\r
3262\r
3263 This function makes the user to know that whether the active Shell is the root shell.\r
3264\r
3265 @retval TRUE The active Shell is the root Shell.\r
3266 @retval FALSE The active Shell is NOT the root Shell.\r
3267**/\r
3268BOOLEAN\r
3269EFIAPI\r
3270EfiShellIsRootShell(\r
3271 VOID\r
3272 )\r
3273{\r
3274 return(ShellInfoObject.RootShellInstance);\r
3275}\r
3276\r
3277/**\r
3278 function to return a semi-colon delimeted list of all alias' in the current shell\r
3279\r
3280 up to caller to free the memory.\r
3281\r
3282 @retval NULL No alias' were found\r
3283 @retval NULL An error ocurred getting alias'\r
3284 @return !NULL a list of all alias'\r
3285**/\r
3286CHAR16 *\r
3287EFIAPI\r
3288InternalEfiShellGetListAlias(\r
3289 )\r
3290{\r
654a012b 3291 \r
a405b86d 3292 EFI_STATUS Status;\r
3293 EFI_GUID Guid;\r
3294 CHAR16 *VariableName;\r
3295 UINTN NameSize;\r
654a012b 3296 UINTN NameBufferSize;\r
a405b86d 3297 CHAR16 *RetVal;\r
3298 UINTN RetSize;\r
a405b86d 3299\r
654a012b
QS
3300 NameBufferSize = INIT_NAME_BUFFER_SIZE;\r
3301 VariableName = AllocateZeroPool(NameBufferSize);\r
a405b86d 3302 RetSize = 0;\r
3303 RetVal = NULL;\r
3304\r
3c865f20 3305 if (VariableName == NULL) {\r
3306 return (NULL);\r
3307 }\r
3308\r
a405b86d 3309 VariableName[0] = CHAR_NULL;\r
3310\r
3311 while (TRUE) {\r
654a012b 3312 NameSize = NameBufferSize;\r
a405b86d 3313 Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
3314 if (Status == EFI_NOT_FOUND){\r
3315 break;\r
654a012b
QS
3316 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
3317 NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;\r
3318 SHELL_FREE_NON_NULL(VariableName);\r
3319 VariableName = AllocateZeroPool(NameBufferSize);\r
3320 if (VariableName == NULL) {\r
3321 Status = EFI_OUT_OF_RESOURCES;\r
3322 SHELL_FREE_NON_NULL(RetVal);\r
3323 RetVal = NULL;\r
3324 break;\r
3325 }\r
3326 \r
3327 NameSize = NameBufferSize;\r
3328 Status = gRT->GetNextVariableName(&NameSize, VariableName, &Guid);\r
3329 }\r
3330 \r
3331 if (EFI_ERROR (Status)) {\r
3332 SHELL_FREE_NON_NULL(RetVal);\r
3333 RetVal = NULL;\r
a405b86d 3334 break;\r
3335 }\r
654a012b 3336 \r
a405b86d 3337 if (CompareGuid(&Guid, &gShellAliasGuid)){\r
a405b86d 3338 ASSERT((RetVal == NULL && RetSize == 0) || (RetVal != NULL));\r
3339 RetVal = StrnCatGrow(&RetVal, &RetSize, VariableName, 0);\r
3340 RetVal = StrnCatGrow(&RetVal, &RetSize, L";", 0);\r
3341 } // compare guid\r
3342 } // while\r
654a012b 3343 SHELL_FREE_NON_NULL(VariableName);\r
a405b86d 3344\r
3345 return (RetVal);\r
3346}\r
3347\r
b9b77ab1
BJ
3348/**\r
3349 Convert a null-terminated unicode string, in-place, to all lowercase.\r
3350 Then return it.\r
4f344fff
SQ
3351 \r
3352 @param Str The null-terminated string to be converted to all lowercase.\r
3353 \r
3354 @return The null-terminated string converted into all lowercase. \r
b9b77ab1 3355**/\r
de4caceb 3356CHAR16 *\r
b9b77ab1
BJ
3357ToLower (\r
3358 CHAR16 *Str\r
3359 )\r
3360{\r
3361 UINTN Index;\r
3362\r
3363 for (Index = 0; Str[Index] != L'\0'; Index++) {\r
3364 if (Str[Index] >= L'A' && Str[Index] <= L'Z') {\r
f716d7b8 3365 Str[Index] -= (CHAR16)(L'A' - L'a');\r
b9b77ab1
BJ
3366 }\r
3367 }\r
3368 return Str;\r
3369}\r
3370\r
a405b86d 3371/**\r
3372 This function returns the command associated with a alias or a list of all\r
3373 alias'.\r
3374\r
3375 @param[in] Alias Points to the NULL-terminated shell alias.\r
3376 If this parameter is NULL, then all\r
3377 aliases will be returned in ReturnedData.\r
3378 @param[out] Volatile upon return of a single command if TRUE indicates\r
3379 this is stored in a volatile fashion. FALSE otherwise.\r
3380\r
3381 @return If Alias is not NULL, it will return a pointer to\r
3382 the NULL-terminated command for that alias.\r
3383 If Alias is NULL, ReturnedData points to a ';'\r
3384 delimited list of alias (e.g.\r
3385 ReturnedData = "dir;del;copy;mfp") that is NULL-terminated.\r
3386 @retval NULL an error ocurred\r
3387 @retval NULL Alias was not a valid Alias\r
3388**/\r
3389CONST CHAR16 *\r
3390EFIAPI\r
3391EfiShellGetAlias(\r
3392 IN CONST CHAR16 *Alias,\r
3393 OUT BOOLEAN *Volatile OPTIONAL\r
3394 )\r
3395{\r
3396 CHAR16 *RetVal;\r
3397 UINTN RetSize;\r
3398 UINT32 Attribs;\r
3399 EFI_STATUS Status;\r
b9b77ab1 3400 CHAR16 *AliasLower;\r
4c33aace 3401 CHAR16 *AliasVal;\r
a405b86d 3402\r
b9b77ab1 3403 // Convert to lowercase to make aliases case-insensitive\r
a405b86d 3404 if (Alias != NULL) {\r
b9b77ab1
BJ
3405 AliasLower = AllocateCopyPool (StrSize (Alias), Alias);\r
3406 ASSERT (AliasLower != NULL);\r
3407 ToLower (AliasLower);\r
3408\r
a405b86d 3409 if (Volatile == NULL) {\r
4c33aace 3410 GetVariable2 (AliasLower, &gShellAliasGuid, (VOID **)&AliasVal, NULL);\r
06e5ae77 3411 FreePool(AliasLower);\r
4c33aace 3412 return (AddBufferToFreeList(AliasVal));\r
a405b86d 3413 }\r
3414 RetSize = 0;\r
3415 RetVal = NULL;\r
b9b77ab1 3416 Status = gRT->GetVariable(AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
a405b86d 3417 if (Status == EFI_BUFFER_TOO_SMALL) {\r
3418 RetVal = AllocateZeroPool(RetSize);\r
b9b77ab1 3419 Status = gRT->GetVariable(AliasLower, &gShellAliasGuid, &Attribs, &RetSize, RetVal);\r
a405b86d 3420 }\r
3421 if (EFI_ERROR(Status)) {\r
3422 if (RetVal != NULL) {\r
3423 FreePool(RetVal);\r
3424 }\r
06e5ae77 3425 FreePool(AliasLower);\r
a405b86d 3426 return (NULL);\r
3427 }\r
3428 if ((EFI_VARIABLE_NON_VOLATILE & Attribs) == EFI_VARIABLE_NON_VOLATILE) {\r
3429 *Volatile = FALSE;\r
3430 } else {\r
3431 *Volatile = TRUE;\r
3432 }\r
3433\r
b9b77ab1 3434 FreePool (AliasLower);\r
a405b86d 3435 return (AddBufferToFreeList(RetVal));\r
3436 }\r
3437 return (AddBufferToFreeList(InternalEfiShellGetListAlias()));\r
3438}\r
3439\r
3440/**\r
3441 Changes a shell command alias.\r
3442\r
3443 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.\r
3444\r
3445 this function does not check for built in alias'.\r
3446\r
3447 @param[in] Command Points to the NULL-terminated shell command or existing alias.\r
3448 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and\r
3449 Command refers to an alias, that alias will be deleted.\r
3450 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the\r
3451 Alias being set will be stored in a non-volatile fashion.\r
3452\r
3453 @retval EFI_SUCCESS Alias created or deleted successfully.\r
3454 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found\r
3455**/\r
3456EFI_STATUS\r
3457EFIAPI\r
3458InternalSetAlias(\r
3459 IN CONST CHAR16 *Command,\r
3460 IN CONST CHAR16 *Alias,\r
3461 IN BOOLEAN Volatile\r
3462 )\r
3463{\r
b9b77ab1
BJ
3464 EFI_STATUS Status;\r
3465 CHAR16 *AliasLower;\r
3466\r
3467 // Convert to lowercase to make aliases case-insensitive\r
3468 if (Alias != NULL) {\r
3469 AliasLower = AllocateCopyPool (StrSize (Alias), Alias);\r
3470 ASSERT (AliasLower != NULL);\r
3471 ToLower (AliasLower);\r
3472 } else {\r
3473 AliasLower = NULL;\r
3474 }\r
3475\r
a405b86d 3476 //\r
3477 // We must be trying to remove one if Alias is NULL\r
3478 //\r
3479 if (Alias == NULL) {\r
3480 //\r
3481 // remove an alias (but passed in COMMAND parameter)\r
3482 //\r
b9b77ab1 3483 Status = (gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL));\r
a405b86d 3484 } else {\r
3485 //\r
3486 // Add and replace are the same\r
3487 //\r
3488\r
3489 // We dont check the error return on purpose since the variable may not exist.\r
3490 gRT->SetVariable((CHAR16*)Command, &gShellAliasGuid, 0, 0, NULL);\r
3491\r
b9b77ab1 3492 Status = (gRT->SetVariable((CHAR16*)Alias, &gShellAliasGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS|(Volatile?0:EFI_VARIABLE_NON_VOLATILE), StrSize(Command), (VOID*)Command));\r
a405b86d 3493 }\r
b9b77ab1
BJ
3494\r
3495 if (Alias != NULL) {\r
3496 FreePool (AliasLower);\r
3497 }\r
3498 return Status;\r
a405b86d 3499}\r
3500\r
3501/**\r
3502 Changes a shell command alias.\r
3503\r
3504 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.\r
3505\r
3506\r
3507 @param[in] Command Points to the NULL-terminated shell command or existing alias.\r
3508 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and\r
3509 Command refers to an alias, that alias will be deleted.\r
3510 @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If\r
3511 FALSE and the alias already exists, then the existing alias is unchanged and\r
3512 EFI_ACCESS_DENIED is returned.\r
3513 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the\r
3514 Alias being set will be stored in a non-volatile fashion.\r
3515\r
3516 @retval EFI_SUCCESS Alias created or deleted successfully.\r
3517 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found\r
3518 @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to\r
3519 FALSE.\r
b9b77ab1 3520 @retval EFI_INVALID_PARAMETER Command is null or the empty string.\r
a405b86d 3521**/\r
3522EFI_STATUS\r
3523EFIAPI\r
3524EfiShellSetAlias(\r
3525 IN CONST CHAR16 *Command,\r
3526 IN CONST CHAR16 *Alias,\r
3527 IN BOOLEAN Replace,\r
3528 IN BOOLEAN Volatile\r
3529 )\r
3530{\r
a405b86d 3531 if (ShellCommandIsOnAliasList(Alias==NULL?Command:Alias)) {\r
b9b77ab1
BJ
3532 //\r
3533 // cant set over a built in alias\r
3534 //\r
a405b86d 3535 return (EFI_ACCESS_DENIED);\r
b9b77ab1
BJ
3536 } else if (Command == NULL || *Command == CHAR_NULL || StrLen(Command) == 0) {\r
3537 //\r
3538 // Command is null or empty\r
3539 //\r
a405b86d 3540 return (EFI_INVALID_PARAMETER);\r
b9b77ab1
BJ
3541 } else if (EfiShellGetAlias(Command, NULL) != NULL && !Replace) {\r
3542 //\r
3543 // Alias already exists, Replace not set\r
3544 //\r
a405b86d 3545 return (EFI_ACCESS_DENIED);\r
b9b77ab1
BJ
3546 } else {\r
3547 return (InternalSetAlias(Command, Alias, Volatile));\r
a405b86d 3548 }\r
a405b86d 3549}\r
3550\r
3551// Pure FILE_HANDLE operations are passed to FileHandleLib\r
3552// these functions are indicated by the *\r
838b31a6 3553EFI_SHELL_PROTOCOL mShellProtocol = {\r
a405b86d 3554 EfiShellExecute,\r
3555 EfiShellGetEnv,\r
3556 EfiShellSetEnv,\r
3557 EfiShellGetAlias,\r
3558 EfiShellSetAlias,\r
3559 EfiShellGetHelpText,\r
3560 EfiShellGetDevicePathFromMap,\r
3561 EfiShellGetMapFromDevicePath,\r
3562 EfiShellGetDevicePathFromFilePath,\r
3563 EfiShellGetFilePathFromDevicePath,\r
3564 EfiShellSetMap,\r
3565 EfiShellGetCurDir,\r
3566 EfiShellSetCurDir,\r
3567 EfiShellOpenFileList,\r
3568 EfiShellFreeFileList,\r
3569 EfiShellRemoveDupInFileList,\r
3570 EfiShellBatchIsActive,\r
3571 EfiShellIsRootShell,\r
3572 EfiShellEnablePageBreak,\r
3573 EfiShellDisablePageBreak,\r
3574 EfiShellGetPageBreak,\r
3575 EfiShellGetDeviceName,\r
3576 (EFI_SHELL_GET_FILE_INFO)FileHandleGetInfo, //*\r
3577 (EFI_SHELL_SET_FILE_INFO)FileHandleSetInfo, //*\r
3578 EfiShellOpenFileByName,\r
3579 EfiShellClose,\r
3580 EfiShellCreateFile,\r
3581 (EFI_SHELL_READ_FILE)FileHandleRead, //*\r
3582 (EFI_SHELL_WRITE_FILE)FileHandleWrite, //*\r
3583 (EFI_SHELL_DELETE_FILE)FileHandleDelete, //*\r
3584 EfiShellDeleteFileByName,\r
3585 (EFI_SHELL_GET_FILE_POSITION)FileHandleGetPosition, //*\r
3586 (EFI_SHELL_SET_FILE_POSITION)FileHandleSetPosition, //*\r
3587 (EFI_SHELL_FLUSH_FILE)FileHandleFlush, //*\r
3588 EfiShellFindFiles,\r
3589 EfiShellFindFilesInDir,\r
3590 (EFI_SHELL_GET_FILE_SIZE)FileHandleGetSize, //*\r
3591 EfiShellOpenRoot,\r
3592 EfiShellOpenRootByHandle,\r
3593 NULL,\r
838b31a6
CP
3594 SHELL_MAJOR_VERSION,\r
3595 SHELL_MINOR_VERSION,\r
09fd5328
JC
3596\r
3597 // New for UEFI Shell 2.1\r
3598 EfiShellRegisterGuidName,\r
3599 EfiShellGetGuidName,\r
3600 EfiShellGetGuidFromName,\r
3601 EfiShellGetEnvEx\r
a405b86d 3602};\r
3603\r
3604/**\r
3605 Function to create and install on the current handle.\r
3606\r
3607 Will overwrite any existing ShellProtocols in the system to be sure that\r
3608 the current shell is in control.\r
3609\r
3610 This must be removed via calling CleanUpShellProtocol().\r
3611\r
4ff7e37b 3612 @param[in, out] NewShell The pointer to the pointer to the structure\r
a405b86d 3613 to install.\r
3614\r
3615 @retval EFI_SUCCESS The operation was successful.\r
3616 @return An error from LocateHandle, CreateEvent, or other core function.\r
3617**/\r
3618EFI_STATUS\r
3619EFIAPI\r
3620CreatePopulateInstallShellProtocol (\r
838b31a6 3621 IN OUT EFI_SHELL_PROTOCOL **NewShell\r
a405b86d 3622 )\r
3623{\r
3624 EFI_STATUS Status;\r
3625 UINTN BufferSize;\r
3626 EFI_HANDLE *Buffer;\r
3627 UINTN HandleCounter;\r
3628 SHELL_PROTOCOL_HANDLE_LIST *OldProtocolNode;\r
3629\r
8be0ba36 3630 if (NewShell == NULL) {\r
3631 return (EFI_INVALID_PARAMETER);\r
3632 }\r
3633\r
a405b86d 3634 BufferSize = 0;\r
3635 Buffer = NULL;\r
3636 OldProtocolNode = NULL;\r
3637 InitializeListHead(&ShellInfoObject.OldShellList.Link);\r
3638\r
a405b86d 3639 //\r
3640 // Initialize EfiShellProtocol object...\r
3641 //\r
a405b86d 3642 Status = gBS->CreateEvent(0,\r
3643 0,\r
3644 NULL,\r
3645 NULL,\r
3646 &mShellProtocol.ExecutionBreak);\r
8be0ba36 3647 if (EFI_ERROR(Status)) {\r
3648 return (Status);\r
3649 }\r
a405b86d 3650\r
3651 //\r
3652 // Get the size of the buffer we need.\r
3653 //\r
3654 Status = gBS->LocateHandle(ByProtocol,\r
3655 &gEfiShellProtocolGuid,\r
3656 NULL,\r
3657 &BufferSize,\r
3658 Buffer);\r
3659 if (Status == EFI_BUFFER_TOO_SMALL) {\r
3660 //\r
3661 // Allocate and recall with buffer of correct size\r
3662 //\r
3663 Buffer = AllocateZeroPool(BufferSize);\r
8be0ba36 3664 if (Buffer == NULL) {\r
3665 return (EFI_OUT_OF_RESOURCES);\r
3666 }\r
a405b86d 3667 Status = gBS->LocateHandle(ByProtocol,\r
3668 &gEfiShellProtocolGuid,\r
3669 NULL,\r
3670 &BufferSize,\r
3671 Buffer);\r
8be0ba36 3672 if (EFI_ERROR(Status)) {\r
3673 FreePool(Buffer);\r
3674 return (Status);\r
3675 }\r
a405b86d 3676 //\r
3677 // now overwrite each of them, but save the info to restore when we end.\r
3678 //\r
3679 for (HandleCounter = 0 ; HandleCounter < (BufferSize/sizeof(EFI_HANDLE)) ; HandleCounter++) {\r
3680 OldProtocolNode = AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST));\r
3681 ASSERT(OldProtocolNode != NULL);\r
3682 Status = gBS->OpenProtocol(Buffer[HandleCounter],\r
3683 &gEfiShellProtocolGuid,\r
3684 (VOID **) &(OldProtocolNode->Interface),\r
3685 gImageHandle,\r
3686 NULL,\r
3687 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
3688 );\r
3689 if (!EFI_ERROR(Status)) {\r
3690 //\r
3691 // reinstall over the old one...\r
3692 //\r
3693 OldProtocolNode->Handle = Buffer[HandleCounter];\r
3694 Status = gBS->ReinstallProtocolInterface(\r
3695 OldProtocolNode->Handle,\r
3696 &gEfiShellProtocolGuid,\r
3697 OldProtocolNode->Interface,\r
8be0ba36 3698 (VOID*)(&mShellProtocol));\r
a405b86d 3699 if (!EFI_ERROR(Status)) {\r
3700 //\r
3701 // we reinstalled sucessfully. log this so we can reverse it later.\r
3702 //\r
3703\r
3704 //\r
3705 // add to the list for subsequent...\r
3706 //\r
3707 InsertTailList(&ShellInfoObject.OldShellList.Link, &OldProtocolNode->Link);\r
3708 }\r
3709 }\r
3710 }\r
3711 FreePool(Buffer);\r
3712 } else if (Status == EFI_NOT_FOUND) {\r
3713 ASSERT(IsListEmpty(&ShellInfoObject.OldShellList.Link));\r
3714 //\r
3715 // no one else published yet. just publish it ourselves.\r
3716 //\r
3717 Status = gBS->InstallProtocolInterface (\r
3718 &gImageHandle,\r
3719 &gEfiShellProtocolGuid,\r
3720 EFI_NATIVE_INTERFACE,\r
8be0ba36 3721 (VOID*)(&mShellProtocol));\r
a405b86d 3722 }\r
3723\r
3724 if (PcdGetBool(PcdShellSupportOldProtocols)){\r
3725 ///@todo support ShellEnvironment2\r
3726 ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also?\r
3727 }\r
3728\r
8be0ba36 3729 if (!EFI_ERROR(Status)) {\r
3730 *NewShell = &mShellProtocol;\r
3731 }\r
a405b86d 3732 return (Status);\r
3733}\r
3734\r
3735/**\r
e9723321 3736 Opposite of CreatePopulateInstallShellProtocol.\r
a405b86d 3737\r
3738 Free all memory and restore the system to the state it was in before calling\r
3739 CreatePopulateInstallShellProtocol.\r
3740\r
4ff7e37b 3741 @param[in, out] NewShell The pointer to the new shell protocol structure.\r
a405b86d 3742\r
3743 @retval EFI_SUCCESS The operation was successful.\r
3744**/\r
3745EFI_STATUS\r
3746EFIAPI\r
3747CleanUpShellProtocol (\r
838b31a6 3748 IN OUT EFI_SHELL_PROTOCOL *NewShell\r
a405b86d 3749 )\r
3750{\r
8be0ba36 3751 EFI_STATUS Status;\r
3752 SHELL_PROTOCOL_HANDLE_LIST *Node2;\r
3753 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
a405b86d 3754\r
3755 //\r
3756 // if we need to restore old protocols...\r
3757 //\r
3758 if (!IsListEmpty(&ShellInfoObject.OldShellList.Link)) {\r
3759 for (Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link)\r
3760 ; !IsListEmpty (&ShellInfoObject.OldShellList.Link)\r
3761 ; Node2 = (SHELL_PROTOCOL_HANDLE_LIST *)GetFirstNode(&ShellInfoObject.OldShellList.Link)\r
3762 ){\r
3763 RemoveEntryList(&Node2->Link);\r
3764 Status = gBS->ReinstallProtocolInterface(Node2->Handle,\r
3765 &gEfiShellProtocolGuid,\r
3766 NewShell,\r
3767 Node2->Interface);\r
a405b86d 3768 FreePool(Node2);\r
3769 }\r
3770 } else {\r
3771 //\r
3772 // no need to restore\r
3773 //\r
3774 Status = gBS->UninstallProtocolInterface(gImageHandle,\r
3775 &gEfiShellProtocolGuid,\r
3776 NewShell);\r
a405b86d 3777 }\r
3778 Status = gBS->CloseEvent(NewShell->ExecutionBreak);\r
8be0ba36 3779 NewShell->ExecutionBreak = NULL;\r
3780\r
3781 Status = gBS->OpenProtocol(\r
3782 gST->ConsoleInHandle,\r
3783 &gEfiSimpleTextInputExProtocolGuid,\r
3784 (VOID**)&SimpleEx,\r
3785 gImageHandle,\r
3786 NULL,\r
3787 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
3788\r
a7a394a4 3789 if (!EFI_ERROR (Status)) {\r
3790 Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle1);\r
3791 Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle2);\r
3792 Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle3);\r
3793 Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlCNotifyHandle4);\r
3794 Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle1);\r
3795 Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle2);\r
3796 Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle3);\r
3797 Status = SimpleEx->UnregisterKeyNotify(SimpleEx, ShellInfoObject.CtrlSNotifyHandle4);\r
3798 }\r
a405b86d 3799 return (Status);\r
3800}\r
3801\r
8be0ba36 3802/**\r
3803 Notification function for keystrokes.\r
3804\r
3805 @param[in] KeyData The key that was pressed.\r
3806\r
3807 @retval EFI_SUCCESS The operation was successful.\r
3808**/\r
3809EFI_STATUS\r
3810EFIAPI\r
3811NotificationFunction(\r
3812 IN EFI_KEY_DATA *KeyData\r
3813 )\r
3814{\r
41cf3e45 3815 if ( ((KeyData->Key.UnicodeChar == L'c') &&\r
3816 (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))) ||\r
3817 (KeyData->Key.UnicodeChar == 3)\r
733f138d 3818 ){ \r
3819 if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
3820 return (EFI_UNSUPPORTED);\r
3821 }\r
3822 return (gBS->SignalEvent(ShellInfoObject.NewEfiShellProtocol->ExecutionBreak));\r
3823 } else if ((KeyData->Key.UnicodeChar == L's') &&\r
3824 (KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED) || KeyData->KeyState.KeyShiftState == (EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED))\r
3825 ){ \r
a49f6a2f 3826 ShellInfoObject.HaltOutput = TRUE;\r
8be0ba36 3827 }\r
733f138d 3828 return (EFI_SUCCESS);\r
8be0ba36 3829}\r
3830\r
3831/**\r
3832 Function to start monitoring for CTRL-C using SimpleTextInputEx. This \r
3833 feature's enabled state was not known when the shell initially launched.\r
3834\r
3835 @retval EFI_SUCCESS The feature is enabled.\r
3836 @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.\r
3837**/\r
3838EFI_STATUS\r
3839EFIAPI\r
3840InernalEfiShellStartMonitor(\r
3841 VOID\r
3842 )\r
3843{\r
3844 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleEx;\r
3845 EFI_KEY_DATA KeyData;\r
3846 EFI_STATUS Status;\r
3847\r
3848 Status = gBS->OpenProtocol(\r
3849 gST->ConsoleInHandle,\r
3850 &gEfiSimpleTextInputExProtocolGuid,\r
3851 (VOID**)&SimpleEx,\r
3852 gImageHandle,\r
3853 NULL,\r
3854 EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
3855 if (EFI_ERROR(Status)) {\r
3856 ShellPrintHiiEx(\r
3857 -1, \r
3858 -1, \r
3859 NULL,\r
3860 STRING_TOKEN (STR_SHELL_NO_IN_EX),\r
3861 ShellInfoObject.HiiHandle);\r
3862 return (EFI_SUCCESS);\r
3863 }\r
a405b86d 3864\r
8be0ba36 3865 if (ShellInfoObject.NewEfiShellProtocol->ExecutionBreak == NULL) {\r
3866 return (EFI_UNSUPPORTED);\r
3867 }\r
3868\r
3869 KeyData.KeyState.KeyToggleState = 0;\r
3870 KeyData.Key.ScanCode = 0;\r
3871 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
3872 KeyData.Key.UnicodeChar = L'c';\r
3873\r
3874 Status = SimpleEx->RegisterKeyNotify(\r
3875 SimpleEx,\r
3876 &KeyData,\r
3877 NotificationFunction,\r
3878 &ShellInfoObject.CtrlCNotifyHandle1);\r
3879 \r
3880 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
3881 if (!EFI_ERROR(Status)) {\r
3882 Status = SimpleEx->RegisterKeyNotify(\r
3883 SimpleEx,\r
3884 &KeyData,\r
3885 NotificationFunction,\r
3886 &ShellInfoObject.CtrlCNotifyHandle2);\r
3887 }\r
3888 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_LEFT_CONTROL_PRESSED;\r
3889 KeyData.Key.UnicodeChar = 3;\r
3890 if (!EFI_ERROR(Status)) {\r
3891 Status = SimpleEx->RegisterKeyNotify(\r
3892 SimpleEx,\r
3893 &KeyData,\r
3894 NotificationFunction,\r
3895 &ShellInfoObject.CtrlCNotifyHandle3);\r
3896 }\r
3897 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID|EFI_RIGHT_CONTROL_PRESSED;\r
3898 if (!EFI_ERROR(Status)) {\r
3899 Status = SimpleEx->RegisterKeyNotify(\r
3900 SimpleEx,\r
3901 &KeyData,\r
3902 NotificationFunction,\r
3903 &ShellInfoObject.CtrlCNotifyHandle4);\r
3904 }\r
3905 return (Status);\r
3906}\r
4f344fff 3907\r