2 Member functions of EFI_SHELL_PROTOCOL and functions for creation,
3 manipulation, and initialization of EFI_SHELL_PROTOCOL.
5 Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Close an open file handle.
21 This function closes a specified file handle. All "dirty" cached file data is
22 flushed to the device, and the file is closed. In all cases the handle is
25 @param[in] FileHandle The file handle to close.
27 @retval EFI_SUCCESS The file handle was closed successfully.
32 IN SHELL_FILE_HANDLE FileHandle
35 ShellFileHandleRemove(FileHandle
);
36 return (FileHandleClose(ConvertShellHandleToEfiFileProtocol(FileHandle
)));
40 Internal worker to determine whether there is a BlockIo somewhere
41 upon the device path specified.
43 @param[in] DevicePath The device path to test.
45 @retval TRUE gEfiBlockIoProtocolGuid was installed on a handle with this device path
46 @retval FALSE gEfiBlockIoProtocolGuid was not found.
50 InternalShellProtocolIsBlockIoPresent(
51 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
54 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
60 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
61 Status
= gBS
->LocateDevicePath(&gEfiBlockIoProtocolGuid
, &DevicePathCopy
, &Handle
);
63 if ((Handle
!= NULL
) && (!EFI_ERROR(Status
))) {
70 Internal worker to determine whether there is a file system somewhere
71 upon the device path specified.
73 @param[in] DevicePath The device path to test.
75 @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path
76 @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found.
80 InternalShellProtocolIsSimpleFileSystemPresent(
81 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
84 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
90 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
91 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &Handle
);
93 if ((Handle
!= NULL
) && (!EFI_ERROR(Status
))) {
100 Internal worker debug helper function to print out maps as they are added.
102 @param[in] Mapping string mapping that has been added
103 @param[in] DevicePath pointer to device path that has been mapped.
105 @retval EFI_SUCCESS the operation was successful.
106 @return other an error ocurred
113 InternalShellProtocolDebugPrintMessage (
114 IN CONST CHAR16
*Mapping
,
115 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
123 if (Mapping
!= NULL
) {
124 DEBUG((EFI_D_INFO
, "Added new map item:\"%S\"\r\n", Mapping
));
126 Temp
= ConvertDevicePathToText(DevicePath
, TRUE
, TRUE
);
127 DEBUG((EFI_D_INFO
, "DevicePath: %S\r\n", Temp
));
135 This function creates a mapping for a device path.
137 If both DeviecPath and Mapping are NULL, this will reset the mapping to default values.
139 @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping,
140 then the mapping will be deleted.
141 @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':'
143 @retval EFI_SUCCESS Mapping created or deleted successfully.
144 @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the
145 boot service function LocateDevicePath().
146 @retval EFI_ACCESS_DENIED The mapping is a built-in alias.
147 @retval EFI_INVALID_PARAMETER Mapping was NULL
148 @retval EFI_INVALID_PARAMETER Mapping did not end with a ':'
149 @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed.
150 @retval EFI_NOT_FOUND There was no mapping found to delete
151 @retval EFI_OUT_OF_RESOURCES Memory allocation failed
156 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
,
157 IN CONST CHAR16
*Mapping
161 SHELL_MAP_LIST
*MapListNode
;
163 if (Mapping
== NULL
){
164 return (EFI_INVALID_PARAMETER
);
167 if (Mapping
[StrLen(Mapping
)-1] != ':') {
168 return (EFI_INVALID_PARAMETER
);
172 // Delete the mapping
174 if (DevicePath
== NULL
) {
175 if (IsListEmpty(&gShellMapList
.Link
)) {
176 return (EFI_NOT_FOUND
);
178 for ( MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
179 ; !IsNull(&gShellMapList
.Link
, &MapListNode
->Link
)
180 ; MapListNode
= (SHELL_MAP_LIST
*)GetNextNode(&gShellMapList
.Link
, &MapListNode
->Link
)
182 if (StringNoCaseCompare(&MapListNode
->MapName
, &Mapping
) == 0) {
183 RemoveEntryList(&MapListNode
->Link
);
184 FreePool(MapListNode
);
185 return (EFI_SUCCESS
);
190 // We didnt find one to delete
192 return (EFI_NOT_FOUND
);
196 // make sure this is a valid to add device path
198 ///@todo add BlockIo to this test...
199 if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath
)
200 && !InternalShellProtocolIsBlockIoPresent(DevicePath
)) {
201 return (EFI_INVALID_PARAMETER
);
205 // First make sure there is no old mapping
207 Status
= EfiShellSetMap(NULL
, Mapping
);
208 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_FOUND
)) {
213 // now add the new one.
215 Status
= ShellCommandAddMapItemAndUpdatePath(Mapping
, DevicePath
, 0, FALSE
);
221 Gets the device path from the mapping.
223 This function gets the device path associated with a mapping.
225 @param Mapping A pointer to the mapping
227 @retval !=NULL Pointer to the device path that corresponds to the
228 device mapping. The returned pointer does not need
230 @retval NULL There is no device path associated with the
233 CONST EFI_DEVICE_PATH_PROTOCOL
*
235 EfiShellGetDevicePathFromMap(
236 IN CONST CHAR16
*Mapping
239 SHELL_MAP_LIST
*MapListItem
;
246 StrnCatGrow(&NewName
, &Size
, Mapping
, 0);
247 if (Mapping
[StrLen(Mapping
)-1] != L
':') {
248 StrnCatGrow(&NewName
, &Size
, L
":", 0);
251 MapListItem
= ShellCommandFindMapItem(NewName
);
255 if (MapListItem
!= NULL
) {
256 return (MapListItem
->DevicePath
);
262 Gets the mapping(s) that most closely matches the device path.
264 This function gets the mapping which corresponds to the device path *DevicePath. If
265 there is no exact match, then the mapping which most closely matches *DevicePath
266 is returned, and *DevicePath is updated to point to the remaining portion of the
267 device path. If there is an exact match, the mapping is returned and *DevicePath
268 points to the end-of-device-path node.
270 If there are multiple map names they will be semi-colon seperated in the
271 NULL-terminated string.
273 @param DevicePath On entry, points to a device path pointer. On
274 exit, updates the pointer to point to the
275 portion of the device path after the mapping.
277 @retval NULL No mapping was found.
278 @return !=NULL Pointer to NULL-terminated mapping. The buffer
279 is callee allocated and should be freed by the caller.
283 EfiShellGetMapFromDevicePath(
284 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
287 SHELL_MAP_LIST
*Node
;
288 CHAR16
*PathForReturn
;
290 // EFI_HANDLE PathHandle;
291 // EFI_HANDLE MapHandle;
292 // EFI_STATUS Status;
293 // EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;
294 // EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;
296 if (DevicePath
== NULL
|| *DevicePath
== NULL
) {
300 PathForReturn
= NULL
;
303 for ( Node
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
304 ; !IsNull(&gShellMapList
.Link
, &Node
->Link
)
305 ; Node
= (SHELL_MAP_LIST
*)GetNextNode(&gShellMapList
.Link
, &Node
->Link
)
308 // check for exact match
310 if (DevicePathCompare(DevicePath
, &Node
->DevicePath
) == 0) {
311 ASSERT((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
313 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, L
";", 0);
315 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, Node
->MapName
, 0);
318 if (PathForReturn
!= NULL
) {
319 while (!IsDevicePathEndType (*DevicePath
)) {
320 *DevicePath
= NextDevicePathNode (*DevicePath
);
322 SetDevicePathEndNode (*DevicePath
);
325 ///@todo finish code for inexact matches.
326 if (PathForReturn == NULL) {
329 DevicePathCopy = DuplicateDevicePath(*DevicePath);
330 ASSERT(DevicePathCopy != NULL);
331 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);
332 ASSERT_EFI_ERROR(Status);
334 // check each of the device paths we have to get the root of the path for consist mappings
336 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
337 ; !IsNull(&gShellMapList.Link, &Node->Link)
338 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)
340 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) {
343 MapPathCopy = DuplicateDevicePath(Node->DevicePath);
344 ASSERT(MapPathCopy != NULL);
345 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);
346 if (MapHandle == PathHandle) {
348 *DevicePath = DevicePathCopy;
351 DevicePathCopy = NULL;
352 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);
353 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);
358 // now add on the non-consistent mappings
360 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
361 ; !IsNull(&gShellMapList.Link, &Node->Link)
362 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)
364 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) {
367 MapPathCopy = Node->DevicePath;
368 ASSERT(MapPathCopy != NULL);
369 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);
370 if (MapHandle == PathHandle) {
371 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);
372 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);
379 return (AddBufferToFreeList(PathForReturn
));
383 Converts a device path to a file system-style path.
385 This function converts a device path to a file system path by replacing part, or all, of
386 the device path with the file-system mapping. If there are more than one application
387 file system mappings, the one that most closely matches Path will be used.
389 @param Path The pointer to the device path
391 @retval NULL the device path could not be found.
392 @return all The pointer of the NULL-terminated file path. The path
393 is callee-allocated and should be freed by the caller.
397 EfiShellGetFilePathFromDevicePath(
398 IN CONST EFI_DEVICE_PATH_PROTOCOL
*Path
401 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
402 EFI_DEVICE_PATH_PROTOCOL
*MapPathCopy
;
403 SHELL_MAP_LIST
*MapListItem
;
404 CHAR16
*PathForReturn
;
406 EFI_HANDLE PathHandle
;
407 EFI_HANDLE MapHandle
;
409 FILEPATH_DEVICE_PATH
*FilePath
;
410 FILEPATH_DEVICE_PATH
*AlignedNode
;
412 PathForReturn
= NULL
;
415 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)Path
;
416 ASSERT(DevicePathCopy
!= NULL
);
417 if (DevicePathCopy
== NULL
) {
421 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &PathHandle
);
423 if (EFI_ERROR(Status
)) {
427 // check each of the device paths we have to get the root of the path
429 for ( MapListItem
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
430 ; !IsNull(&gShellMapList
.Link
, &MapListItem
->Link
)
431 ; MapListItem
= (SHELL_MAP_LIST
*)GetNextNode(&gShellMapList
.Link
, &MapListItem
->Link
)
433 MapPathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)MapListItem
->DevicePath
;
434 ASSERT(MapPathCopy
!= NULL
);
436 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
, &MapPathCopy
, &MapHandle
);
437 if (MapHandle
== PathHandle
) {
438 ASSERT((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
439 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, MapListItem
->MapName
, 0);
441 // go through all the remaining nodes in the device path
443 for ( FilePath
= (FILEPATH_DEVICE_PATH
*)DevicePathCopy
444 ; !IsDevicePathEnd (&FilePath
->Header
)
445 ; FilePath
= (FILEPATH_DEVICE_PATH
*)NextDevicePathNode (&FilePath
->Header
)
448 // all the rest should be file path nodes
450 if ((DevicePathType(&FilePath
->Header
) != MEDIA_DEVICE_PATH
) ||
451 (DevicePathSubType(&FilePath
->Header
) != MEDIA_FILEPATH_DP
)) {
452 FreePool(PathForReturn
);
453 PathForReturn
= NULL
;
457 // append the path part onto the filepath.
459 ASSERT((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
460 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, L
"\\", 1);
462 AlignedNode
= AllocateCopyPool (DevicePathNodeLength(FilePath
), FilePath
);
463 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, AlignedNode
->PathName
, 0);
464 FreePool(AlignedNode
);
466 } // for loop of remaining nodes
468 if (PathForReturn
!= NULL
) {
471 } // for loop of paths to check
472 return(PathForReturn
);
476 Converts a file system style name to a device path.
478 This function converts a file system style name to a device path, by replacing any
479 mapping references to the associated device path.
481 @param[in] Path The pointer to the path.
483 @return The pointer of the file path. The file path is callee
484 allocated and should be freed by the caller.
485 @retval NULL The path could not be found.
486 @retval NULL There was not enough available memory.
488 EFI_DEVICE_PATH_PROTOCOL
*
490 EfiShellGetDevicePathFromFilePath(
491 IN CONST CHAR16
*Path
498 CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
499 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
500 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopyForFree
;
501 EFI_DEVICE_PATH_PROTOCOL
*DevicePathForReturn
;
512 if (StrStr(Path
, L
":") == NULL
) {
513 Cwd
= EfiShellGetCurDir(NULL
);
518 Size
+= StrSize(Path
);
519 NewPath
= AllocateZeroPool(Size
);
520 if (NewPath
== NULL
) {
523 StrCpy(NewPath
, Cwd
);
524 if (*Path
== L
'\\') {
526 while (PathRemoveLastItem(NewPath
)) ;
528 StrCat(NewPath
, Path
);
529 DevicePathForReturn
= EfiShellGetDevicePathFromFilePath(NewPath
);
531 return (DevicePathForReturn
);
536 // find the part before (but including) the : for the map name
538 ASSERT((MapName
== NULL
&& Size
== 0) || (MapName
!= NULL
));
539 MapName
= StrnCatGrow(&MapName
, &Size
, Path
, (StrStr(Path
, L
":")-Path
+1));
540 if (MapName
== NULL
|| MapName
[StrLen(MapName
)-1] != L
':') {
545 // look up the device path in the map
547 DevicePath
= EfiShellGetDevicePathFromMap(MapName
);
548 if (DevicePath
== NULL
) {
550 // Must have been a bad Mapname
556 // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with)
558 DevicePathCopyForFree
= DevicePathCopy
= DuplicateDevicePath(DevicePath
);
559 if (DevicePathCopy
== NULL
) {
568 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &Handle
);
569 if (EFI_ERROR(Status
)) {
570 if (DevicePathCopyForFree
!= NULL
) {
571 FreePool(DevicePathCopyForFree
);
578 // build the full device path
580 if (*(Path
+StrLen(MapName
)+1) == CHAR_NULL
) {
581 DevicePathForReturn
= FileDevicePath(Handle
, L
"\\");
583 DevicePathForReturn
= FileDevicePath(Handle
, Path
+StrLen(MapName
));
587 if (DevicePathCopyForFree
!= NULL
) {
588 FreePool(DevicePathCopyForFree
);
591 return (DevicePathForReturn
);
595 Gets the name of the device specified by the device handle.
597 This function gets the user-readable name of the device specified by the device
598 handle. If no user-readable name could be generated, then *BestDeviceName will be
599 NULL and EFI_NOT_FOUND will be returned.
601 If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the
602 device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on
605 If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the
606 device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle.
607 If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and
608 EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then
609 EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority.
611 @param DeviceHandle The handle of the device.
612 @param Flags Determines the possible sources of component names.
614 EFI_DEVICE_NAME_USE_COMPONENT_NAME
615 EFI_DEVICE_NAME_USE_DEVICE_PATH
616 @param Language A pointer to the language specified for the device
617 name, in the same format as described in the UEFI
618 specification, Appendix M
619 @param BestDeviceName On return, points to the callee-allocated NULL-
620 terminated name of the device. If no device name
621 could be found, points to NULL. The name must be
622 freed by the caller...
624 @retval EFI_SUCCESS Get the name successfully.
625 @retval EFI_NOT_FOUND Fail to get the device name.
626 @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set.
627 @retval EFI_INVALID_PARAMETER BestDeviceName was NULL
628 @retval EFI_INVALID_PARAMETER DeviceHandle was NULL
632 EfiShellGetDeviceName(
633 IN EFI_HANDLE DeviceHandle
,
634 IN EFI_SHELL_DEVICE_NAME_FLAGS Flags
,
636 OUT CHAR16
**BestDeviceName
640 EFI_COMPONENT_NAME2_PROTOCOL
*CompName2
;
641 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
642 EFI_HANDLE
*HandleList
;
645 CHAR16
*DeviceNameToReturn
;
649 UINTN ParentControllerCount
;
650 EFI_HANDLE
*ParentControllerBuffer
;
651 UINTN ParentDriverCount
;
652 EFI_HANDLE
*ParentDriverBuffer
;
654 if (BestDeviceName
== NULL
||
657 return (EFI_INVALID_PARAMETER
);
661 // make sure one of the 2 supported bits is on
663 if (((Flags
& EFI_DEVICE_NAME_USE_COMPONENT_NAME
) == 0) &&
664 ((Flags
& EFI_DEVICE_NAME_USE_DEVICE_PATH
) == 0)) {
665 return (EFI_INVALID_PARAMETER
);
668 DeviceNameToReturn
= NULL
;
669 *BestDeviceName
= NULL
;
674 if ((Flags
& EFI_DEVICE_NAME_USE_COMPONENT_NAME
) != 0) {
675 Status
= ParseHandleDatabaseByRelationship(
678 HR_DRIVER_BINDING_HANDLE
|HR_DEVICE_DRIVER
,
681 for (LoopVar
= 0; LoopVar
< HandleCount
; LoopVar
++){
683 // Go through those handles until we get one that passes for GetComponentName
685 Status
= gBS
->OpenProtocol(
687 &gEfiComponentName2ProtocolGuid
,
691 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
692 if (EFI_ERROR(Status
)) {
693 Status
= gBS
->OpenProtocol(
695 &gEfiComponentNameProtocolGuid
,
699 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
702 if (EFI_ERROR(Status
)) {
705 if (Language
== NULL
) {
706 Lang
= AllocateZeroPool(AsciiStrSize(CompName2
->SupportedLanguages
));
708 return (EFI_OUT_OF_RESOURCES
);
710 AsciiStrCpy(Lang
, CompName2
->SupportedLanguages
);
711 TempChar
= AsciiStrStr(Lang
, ";");
712 if (TempChar
!= NULL
){
713 *TempChar
= CHAR_NULL
;
716 Lang
= AllocateZeroPool(AsciiStrSize(Language
));
718 return (EFI_OUT_OF_RESOURCES
);
720 AsciiStrCpy(Lang
, Language
);
722 Status
= CompName2
->GetControllerName(CompName2
, DeviceHandle
, NULL
, Lang
, &DeviceNameToReturn
);
725 if (!EFI_ERROR(Status
) && DeviceNameToReturn
!= NULL
) {
729 if (HandleList
!= NULL
) {
730 FreePool(HandleList
);
734 // Now check the parent controller using this as the child.
736 if (DeviceNameToReturn
== NULL
){
737 PARSE_HANDLE_DATABASE_PARENTS(DeviceHandle
, &ParentControllerCount
, &ParentControllerBuffer
);
738 for (LoopVar
= 0 ; LoopVar
< ParentControllerCount
; LoopVar
++) {
739 PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ParentControllerBuffer
[LoopVar
], &ParentDriverCount
, &ParentDriverBuffer
);
740 for (HandleCount
= 0 ; HandleCount
< ParentDriverCount
; HandleCount
++) {
742 // try using that driver's component name with controller and our driver as the child.
744 Status
= gBS
->OpenProtocol(
745 ParentDriverBuffer
[HandleCount
],
746 &gEfiComponentName2ProtocolGuid
,
750 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
751 if (EFI_ERROR(Status
)) {
752 Status
= gBS
->OpenProtocol(
753 ParentDriverBuffer
[HandleCount
],
754 &gEfiComponentNameProtocolGuid
,
758 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
761 if (EFI_ERROR(Status
)) {
764 if (Language
== NULL
) {
765 Lang
= AllocateZeroPool(AsciiStrSize(CompName2
->SupportedLanguages
));
767 return (EFI_OUT_OF_RESOURCES
);
769 AsciiStrCpy(Lang
, CompName2
->SupportedLanguages
);
770 TempChar
= AsciiStrStr(Lang
, ";");
771 if (TempChar
!= NULL
){
772 *TempChar
= CHAR_NULL
;
775 Lang
= AllocateZeroPool(AsciiStrSize(Language
));
777 return (EFI_OUT_OF_RESOURCES
);
779 AsciiStrCpy(Lang
, Language
);
781 Status
= CompName2
->GetControllerName(CompName2
, ParentControllerBuffer
[LoopVar
], DeviceHandle
, Lang
, &DeviceNameToReturn
);
784 if (!EFI_ERROR(Status
) && DeviceNameToReturn
!= NULL
) {
791 SHELL_FREE_NON_NULL(ParentDriverBuffer
);
792 if (!EFI_ERROR(Status
) && DeviceNameToReturn
!= NULL
) {
796 SHELL_FREE_NON_NULL(ParentControllerBuffer
);
799 // dont return on fail since we will try device path if that bit is on
801 if (DeviceNameToReturn
!= NULL
){
802 ASSERT(BestDeviceName
!= NULL
);
803 StrnCatGrow(BestDeviceName
, NULL
, DeviceNameToReturn
, 0);
804 return (EFI_SUCCESS
);
807 if ((Flags
& EFI_DEVICE_NAME_USE_DEVICE_PATH
) != 0) {
808 Status
= gBS
->OpenProtocol(
810 &gEfiDevicePathProtocolGuid
,
814 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
815 if (!EFI_ERROR(Status
)) {
817 // use device path to text on the device path
819 *BestDeviceName
= ConvertDevicePathToText(DevicePath
, TRUE
, TRUE
);
820 return (EFI_SUCCESS
);
824 // none of the selected bits worked.
826 return (EFI_NOT_FOUND
);
830 Opens the root directory of a device on a handle
832 This function opens the root directory of a device and returns a file handle to it.
834 @param DeviceHandle The handle of the device that contains the volume.
835 @param FileHandle On exit, points to the file handle corresponding to the root directory on the
838 @retval EFI_SUCCESS Root opened successfully.
839 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory
841 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.
842 @retval EFI_DEVICE_ERROR The device had an error
846 EfiShellOpenRootByHandle(
847 IN EFI_HANDLE DeviceHandle
,
848 OUT SHELL_FILE_HANDLE
*FileHandle
852 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFileSystem
;
853 EFI_FILE_PROTOCOL
*RealFileHandle
;
854 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
857 // get the simple file system interface
859 Status
= gBS
->OpenProtocol(DeviceHandle
,
860 &gEfiSimpleFileSystemProtocolGuid
,
861 (VOID
**)&SimpleFileSystem
,
864 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
865 if (EFI_ERROR(Status
)) {
866 return (EFI_NOT_FOUND
);
869 Status
= gBS
->OpenProtocol(DeviceHandle
,
870 &gEfiDevicePathProtocolGuid
,
874 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
875 if (EFI_ERROR(Status
)) {
876 return (EFI_NOT_FOUND
);
879 // Open the root volume now...
881 Status
= SimpleFileSystem
->OpenVolume(SimpleFileSystem
, &RealFileHandle
);
882 *FileHandle
= ConvertEfiFileProtocolToShellHandle(RealFileHandle
, EfiShellGetMapFromDevicePath(&DevPath
));
887 Opens the root directory of a device.
889 This function opens the root directory of a device and returns a file handle to it.
891 @param DevicePath Points to the device path corresponding to the device where the
892 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed.
893 @param FileHandle On exit, points to the file handle corresponding to the root directory on the
896 @retval EFI_SUCCESS Root opened successfully.
897 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory
899 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.
900 @retval EFI_DEVICE_ERROR The device had an error
901 @retval EFI_INVALID_PARAMETER FileHandle is NULL.
906 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
907 OUT SHELL_FILE_HANDLE
*FileHandle
913 if (FileHandle
== NULL
) {
914 return (EFI_INVALID_PARAMETER
);
918 // find the handle of the device with that device handle and the file system
921 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
,
924 if (EFI_ERROR(Status
)) {
925 return (EFI_NOT_FOUND
);
928 return (EfiShellOpenRootByHandle(Handle
, FileHandle
));
932 Returns whether any script files are currently being processed.
934 @retval TRUE There is at least one script file active.
935 @retval FALSE No script files are active now.
940 EfiShellBatchIsActive (
944 if (ShellCommandGetCurrentScriptFile() == NULL
) {
951 Worker function to open a file based on a device path. this will open the root
952 of the volume and then traverse down to the file itself.
954 @param DevicePath Device Path of the file.
955 @param FileHandle Pointer to the file upon a successful return.
956 @param OpenMode mode to open file in.
957 @param Attributes the File Attributes to use when creating a new file.
959 @retval EFI_SUCCESS the file is open and FileHandle is valid
960 @retval EFI_UNSUPPORTED the device path cotained non-path elements
961 @retval other an error ocurred.
965 InternalOpenFileDevicePath(
966 IN OUT EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
967 OUT SHELL_FILE_HANDLE
*FileHandle
,
969 IN UINT64 Attributes OPTIONAL
973 FILEPATH_DEVICE_PATH
*FilePathNode
;
975 SHELL_FILE_HANDLE ShellHandle
;
976 EFI_FILE_PROTOCOL
*Handle1
;
977 EFI_FILE_PROTOCOL
*Handle2
;
978 FILEPATH_DEVICE_PATH
*AlignedNode
;
980 if (FileHandle
== NULL
) {
981 return (EFI_INVALID_PARAMETER
);
991 Status
= EfiShellOpenRoot(DevicePath
, &ShellHandle
);
993 if (!EFI_ERROR(Status
)) {
994 Handle1
= ConvertShellHandleToEfiFileProtocol(ShellHandle
);
995 if (Handle1
!= NULL
) {
997 // chop off the begining part before the file system part...
1000 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
,
1003 if (!EFI_ERROR(Status
)) {
1005 // To access as a file system, the file path should only
1006 // contain file path components. Follow the file path nodes
1007 // and find the target file
1009 for ( FilePathNode
= (FILEPATH_DEVICE_PATH
*)DevicePath
1010 ; !IsDevicePathEnd (&FilePathNode
->Header
)
1011 ; FilePathNode
= (FILEPATH_DEVICE_PATH
*) NextDevicePathNode (&FilePathNode
->Header
)
1013 SHELL_FREE_NON_NULL(AlignedNode
);
1014 AlignedNode
= AllocateCopyPool (DevicePathNodeLength(FilePathNode
), FilePathNode
);
1016 // For file system access each node should be a file path component
1018 if (DevicePathType (&FilePathNode
->Header
) != MEDIA_DEVICE_PATH
||
1019 DevicePathSubType (&FilePathNode
->Header
) != MEDIA_FILEPATH_DP
1021 Status
= EFI_UNSUPPORTED
;
1026 // Open this file path node
1032 // if this is the last node in the DevicePath always create (if that was requested).
1034 if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode
->Header
)))) {
1035 Status
= Handle2
->Open (
1038 AlignedNode
->PathName
,
1045 // This is not the last node and we dont want to 'create' existing
1046 // directory entries...
1050 // open without letting it create
1051 // prevents error on existing files/directories
1053 Status
= Handle2
->Open (
1056 AlignedNode
->PathName
,
1057 OpenMode
&~EFI_FILE_MODE_CREATE
,
1061 // if above failed now open and create the 'item'
1062 // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)
1064 if ((EFI_ERROR (Status
)) && ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0)) {
1065 Status
= Handle2
->Open (
1068 AlignedNode
->PathName
,
1075 // Close the last node
1077 ShellInfoObject
.NewEfiShellProtocol
->CloseFile (Handle2
);
1080 // If there's been an error, stop
1082 if (EFI_ERROR (Status
)) {
1089 SHELL_FREE_NON_NULL(AlignedNode
);
1090 if (EFI_ERROR(Status
)) {
1091 if (Handle1
!= NULL
) {
1092 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(Handle1
);
1095 *FileHandle
= ConvertEfiFileProtocolToShellHandle(Handle1
, ShellFileHandleGetPath(ShellHandle
));
1101 Creates a file or directory by name.
1103 This function creates an empty new file or directory with the specified attributes and
1104 returns the new file's handle. If the file already exists and is read-only, then
1105 EFI_INVALID_PARAMETER will be returned.
1107 If the file already existed, it is truncated and its attributes updated. If the file is
1108 created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL.
1110 If the file name begins with >v, then the file handle which is returned refers to the
1111 shell environment variable with the specified name. If the shell environment variable
1112 already exists and is non-volatile then EFI_INVALID_PARAMETER is returned.
1114 @param FileName Pointer to NULL-terminated file path
1115 @param FileAttribs The new file's attrbiutes. the different attributes are
1116 described in EFI_FILE_PROTOCOL.Open().
1117 @param FileHandle On return, points to the created file handle or directory's handle
1119 @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle.
1120 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1121 @retval EFI_UNSUPPORTED could not open the file path
1122 @retval EFI_NOT_FOUND the specified file could not be found on the devide, or could not
1123 file the file system on the device.
1124 @retval EFI_NO_MEDIA the device has no medium.
1125 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
1127 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according
1129 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1130 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write
1131 when the media is write-protected.
1132 @retval EFI_ACCESS_DENIED The service denied access to the file.
1133 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
1134 @retval EFI_VOLUME_FULL The volume is full.
1139 IN CONST CHAR16
*FileName
,
1140 IN UINT64 FileAttribs
,
1141 OUT SHELL_FILE_HANDLE
*FileHandle
1144 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1148 // Is this for an environment variable
1149 // do we start with >v
1151 if (StrStr(FileName
, L
">v") == FileName
) {
1152 if (!IsVolatileEnv(FileName
+2)) {
1153 return (EFI_INVALID_PARAMETER
);
1155 *FileHandle
= CreateFileInterfaceEnv(FileName
+2);
1156 return (EFI_SUCCESS
);
1160 // We are opening a regular file.
1162 DevicePath
= EfiShellGetDevicePathFromFilePath(FileName
);
1163 if (DevicePath
== NULL
) {
1164 return (EFI_NOT_FOUND
);
1167 Status
= InternalOpenFileDevicePath(DevicePath
, FileHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_CREATE
, FileAttribs
); // 0 = no specific file attributes
1168 FreePool(DevicePath
);
1174 Opens a file or a directory by file name.
1176 This function opens the specified file in the specified OpenMode and returns a file
1178 If the file name begins with >v, then the file handle which is returned refers to the
1179 shell environment variable with the specified name. If the shell environment variable
1180 exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then
1181 EFI_INVALID_PARAMETER is returned.
1183 If the file name is >i, then the file handle which is returned refers to the standard
1184 input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER
1187 If the file name is >o, then the file handle which is returned refers to the standard
1188 output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER
1191 If the file name is >e, then the file handle which is returned refers to the standard
1192 error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER
1195 If the file name is NUL, then the file handle that is returned refers to the standard NUL
1196 file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is
1199 If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the
1202 @param FileName Points to the NULL-terminated UCS-2 encoded file name.
1203 @param FileHandle On return, points to the file handle.
1204 @param OpenMode File open mode. Either EFI_FILE_MODE_READ or
1205 EFI_FILE_MODE_WRITE from section 12.4 of the UEFI
1207 @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle.
1208 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL.
1209 @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL.
1210 @retval EFI_NOT_FOUND The specified file could not be found on the device or the file
1211 system could not be found on the device. FileHandle is NULL.
1212 @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL.
1213 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
1214 longer supported. FileHandle is NULL.
1215 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according
1216 the FileName. FileHandle is NULL.
1217 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL.
1218 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write
1219 when the media is write-protected. FileHandle is NULL.
1220 @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL.
1221 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle
1223 @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL.
1227 EfiShellOpenFileByName(
1228 IN CONST CHAR16
*FileName
,
1229 OUT SHELL_FILE_HANDLE
*FileHandle
,
1233 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1239 // Is this for StdIn
1241 if (StrCmp(FileName
, L
">i") == 0) {
1243 // make sure not writing to StdIn
1245 if ((OpenMode
& EFI_FILE_MODE_WRITE
) != 0) {
1246 return (EFI_INVALID_PARAMETER
);
1248 *FileHandle
= ShellInfoObject
.NewShellParametersProtocol
->StdIn
;
1249 ASSERT(*FileHandle
!= NULL
);
1250 return (EFI_SUCCESS
);
1254 // Is this for StdOut
1256 if (StrCmp(FileName
, L
">o") == 0) {
1258 // make sure not writing to StdIn
1260 if ((OpenMode
& EFI_FILE_MODE_READ
) != 0) {
1261 return (EFI_INVALID_PARAMETER
);
1263 *FileHandle
= &FileInterfaceStdOut
;
1264 return (EFI_SUCCESS
);
1268 // Is this for NUL file
1270 if (StrCmp(FileName
, L
"NUL") == 0) {
1271 *FileHandle
= &FileInterfaceNulFile
;
1272 return (EFI_SUCCESS
);
1276 // Is this for StdErr
1278 if (StrCmp(FileName
, L
">e") == 0) {
1280 // make sure not writing to StdIn
1282 if ((OpenMode
& EFI_FILE_MODE_READ
) != 0) {
1283 return (EFI_INVALID_PARAMETER
);
1285 *FileHandle
= &FileInterfaceStdErr
;
1286 return (EFI_SUCCESS
);
1290 // Is this for an environment variable
1291 // do we start with >v
1293 if (StrStr(FileName
, L
">v") == FileName
) {
1294 if (!IsVolatileEnv(FileName
+2) &&
1295 ((OpenMode
& EFI_FILE_MODE_WRITE
) != 0)) {
1296 return (EFI_INVALID_PARAMETER
);
1298 *FileHandle
= CreateFileInterfaceEnv(FileName
+2);
1299 return (EFI_SUCCESS
);
1303 // We are opening a regular file.
1305 DevicePath
= EfiShellGetDevicePathFromFilePath(FileName
);
1306 // DEBUG_CODE(InternalShellProtocolDebugPrintMessage (NULL, DevicePath););
1307 if (DevicePath
== NULL
) {
1308 return (EFI_NOT_FOUND
);
1312 // Copy the device path, open the file, then free the memory
1314 Status
= InternalOpenFileDevicePath(DevicePath
, FileHandle
, OpenMode
, 0); // 0 = no specific file attributes
1315 FreePool(DevicePath
);
1321 Deletes the file specified by the file name.
1323 This function deletes a file.
1325 @param FileName Points to the NULL-terminated file name.
1327 @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.
1328 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
1329 @sa EfiShellCreateFile
1333 EfiShellDeleteFileByName(
1334 IN CONST CHAR16
*FileName
1337 SHELL_FILE_HANDLE FileHandle
;
1341 // get a handle to the file
1343 Status
= EfiShellCreateFile(FileName
,
1346 if (EFI_ERROR(Status
)) {
1350 // now delete the file
1352 return (ShellInfoObject
.NewEfiShellProtocol
->DeleteFile(FileHandle
));
1356 Disables the page break output mode.
1360 EfiShellDisablePageBreak (
1364 ShellInfoObject
.PageBreakEnabled
= FALSE
;
1368 Enables the page break output mode.
1372 EfiShellEnablePageBreak (
1376 ShellInfoObject
.PageBreakEnabled
= TRUE
;
1380 internal worker function to load and run an image via device path.
1382 @param ParentImageHandle A handle of the image that is executing the specified
1384 @param DevicePath device path of the file to execute
1385 @param CommandLine Points to the NULL-terminated UCS-2 encoded string
1386 containing the command line. If NULL then the command-
1388 @param Environment Points to a NULL-terminated array of environment
1389 variables with the format 'x=y', where x is the
1390 environment variable name and y is the value. If this
1391 is NULL, then the current shell environment is used.
1392 @param StatusCode Points to the status code returned by the command.
1394 @retval EFI_SUCCESS The command executed successfully. The status code
1395 returned by the command is pointed to by StatusCode.
1396 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1397 @retval EFI_OUT_OF_RESOURCES Out of resources.
1398 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.
1402 InternalShellExecuteDevicePath(
1403 IN CONST EFI_HANDLE
*ParentImageHandle
,
1404 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1405 IN CONST CHAR16
*CommandLine OPTIONAL
,
1406 IN CONST CHAR16
**Environment OPTIONAL
,
1407 OUT EFI_STATUS
*StatusCode OPTIONAL
1411 EFI_HANDLE NewHandle
;
1412 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1413 LIST_ENTRY OrigEnvs
;
1414 EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol
;
1416 if (ParentImageHandle
== NULL
) {
1417 return (EFI_INVALID_PARAMETER
);
1420 InitializeListHead(&OrigEnvs
);
1425 // Load the image with:
1426 // FALSE - not from boot manager and NULL, 0 being not already in memory
1428 Status
= gBS
->LoadImage(
1431 (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
,
1436 if (EFI_ERROR(Status
)) {
1437 if (NewHandle
!= NULL
) {
1438 gBS
->UnloadImage(NewHandle
);
1442 Status
= gBS
->OpenProtocol(
1444 &gEfiLoadedImageProtocolGuid
,
1445 (VOID
**)&LoadedImage
,
1448 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
1450 if (!EFI_ERROR(Status
)) {
1451 ASSERT(LoadedImage
->LoadOptionsSize
== 0);
1452 if (CommandLine
!= NULL
) {
1453 LoadedImage
->LoadOptionsSize
= (UINT32
)StrSize(CommandLine
);
1454 LoadedImage
->LoadOptions
= (VOID
*)CommandLine
;
1458 // Save our current environment settings for later restoration if necessary
1460 if (Environment
!= NULL
) {
1461 Status
= GetEnvironmentVariableList(&OrigEnvs
);
1462 if (!EFI_ERROR(Status
)) {
1463 Status
= SetEnvironmentVariables(Environment
);
1468 // Initialize and install a shell parameters protocol on the image.
1470 ShellParamsProtocol
.StdIn
= ShellInfoObject
.NewShellParametersProtocol
->StdIn
;
1471 ShellParamsProtocol
.StdOut
= ShellInfoObject
.NewShellParametersProtocol
->StdOut
;
1472 ShellParamsProtocol
.StdErr
= ShellInfoObject
.NewShellParametersProtocol
->StdErr
;
1473 Status
= UpdateArgcArgv(&ShellParamsProtocol
, CommandLine
, NULL
, NULL
);
1474 ASSERT_EFI_ERROR(Status
);
1475 Status
= gBS
->InstallProtocolInterface(&NewHandle
, &gEfiShellParametersProtocolGuid
, EFI_NATIVE_INTERFACE
, &ShellParamsProtocol
);
1476 ASSERT_EFI_ERROR(Status
);
1478 ///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)
1481 // now start the image and if the caller wanted the return code pass it to them...
1483 if (!EFI_ERROR(Status
)) {
1484 if (StatusCode
!= NULL
) {
1485 *StatusCode
= gBS
->StartImage(NewHandle
, NULL
, NULL
);
1487 Status
= gBS
->StartImage(NewHandle
, NULL
, NULL
);
1492 // Cleanup (and dont overwrite errors)
1494 if (EFI_ERROR(Status
)) {
1495 gBS
->UninstallProtocolInterface(NewHandle
, &gEfiShellParametersProtocolGuid
, &ShellParamsProtocol
);
1497 Status
= gBS
->UninstallProtocolInterface(NewHandle
, &gEfiShellParametersProtocolGuid
, &ShellParamsProtocol
);
1498 ASSERT_EFI_ERROR(Status
);
1502 if (!IsListEmpty(&OrigEnvs
)) {
1503 if (EFI_ERROR(Status
)) {
1504 SetEnvironmentVariableList(&OrigEnvs
);
1506 Status
= SetEnvironmentVariableList(&OrigEnvs
);
1513 Execute the command line.
1515 This function creates a nested instance of the shell and executes the specified
1516 command (CommandLine) with the specified environment (Environment). Upon return,
1517 the status code returned by the specified command is placed in StatusCode.
1519 If Environment is NULL, then the current environment is used and all changes made
1520 by the commands executed will be reflected in the current environment. If the
1521 Environment is non-NULL, then the changes made will be discarded.
1523 The CommandLine is executed from the current working directory on the current
1526 @param ParentImageHandle A handle of the image that is executing the specified
1528 @param CommandLine Points to the NULL-terminated UCS-2 encoded string
1529 containing the command line. If NULL then the command-
1531 @param Environment Points to a NULL-terminated array of environment
1532 variables with the format 'x=y', where x is the
1533 environment variable name and y is the value. If this
1534 is NULL, then the current shell environment is used.
1535 @param StatusCode Points to the status code returned by the command.
1537 @retval EFI_SUCCESS The command executed successfully. The status code
1538 returned by the command is pointed to by StatusCode.
1539 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1540 @retval EFI_OUT_OF_RESOURCES Out of resources.
1541 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.
1542 @retval EFI_UNSUPPORTED The support level required for this function is not present.
1544 @sa InternalShellExecuteDevicePath
1549 IN EFI_HANDLE
*ParentImageHandle
,
1550 IN CHAR16
*CommandLine OPTIONAL
,
1551 IN CHAR16
**Environment OPTIONAL
,
1552 OUT EFI_STATUS
*StatusCode OPTIONAL
1557 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1560 if ((PcdGet8(PcdShellSupportLevel
) < 1)) {
1561 return (EFI_UNSUPPORTED
);
1564 DevPath
= AppendDevicePath (ShellInfoObject
.ImageDevPath
, ShellInfoObject
.FileDevPath
);
1567 Temp
= ConvertDevicePathToText(ShellInfoObject
.FileDevPath
, TRUE
, TRUE
);
1569 Temp
= ConvertDevicePathToText(ShellInfoObject
.ImageDevPath
, TRUE
, TRUE
);
1571 Temp
= ConvertDevicePathToText(DevPath
, TRUE
, TRUE
);
1577 ASSERT((Temp
== NULL
&& Size
== 0) || (Temp
!= NULL
));
1578 StrnCatGrow(&Temp
, &Size
, L
"Shell.efi -_exit ", 0);
1579 StrnCatGrow(&Temp
, &Size
, CommandLine
, 0);
1581 Status
= InternalShellExecuteDevicePath(
1585 (CONST CHAR16
**)Environment
,
1589 // de-allocate and return
1597 Utility cleanup function for EFI_SHELL_FILE_INFO objects.
1599 1) frees all pointers (non-NULL)
1600 2) Closes the SHELL_FILE_HANDLE
1602 @param FileListNode pointer to the list node to free
1606 InternalFreeShellFileInfoNode(
1607 IN EFI_SHELL_FILE_INFO
*FileListNode
1610 if (FileListNode
->Info
!= NULL
) {
1611 FreePool((VOID
*)FileListNode
->Info
);
1613 if (FileListNode
->FileName
!= NULL
) {
1614 FreePool((VOID
*)FileListNode
->FileName
);
1616 if (FileListNode
->FullName
!= NULL
) {
1617 FreePool((VOID
*)FileListNode
->FullName
);
1619 if (FileListNode
->Handle
!= NULL
) {
1620 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(FileListNode
->Handle
);
1622 FreePool(FileListNode
);
1625 Frees the file list.
1627 This function cleans up the file list and any related data structures. It has no
1628 impact on the files themselves.
1630 @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is
1631 defined in OpenFileList()
1633 @retval EFI_SUCCESS Free the file list successfully.
1634 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;
1638 EfiShellFreeFileList(
1639 IN EFI_SHELL_FILE_INFO
**FileList
1642 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1644 if (FileList
== NULL
|| *FileList
== NULL
) {
1645 return (EFI_INVALID_PARAMETER
);
1648 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&(*FileList
)->Link
)
1649 ; !IsListEmpty(&(*FileList
)->Link
)
1650 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&(*FileList
)->Link
)
1652 RemoveEntryList(&ShellFileListItem
->Link
);
1653 InternalFreeShellFileInfoNode(ShellFileListItem
);
1655 return(EFI_SUCCESS
);
1659 Deletes the duplicate file names files in the given file list.
1661 This function deletes the reduplicate files in the given file list.
1663 @param FileList A pointer to the first entry in the file list.
1665 @retval EFI_SUCCESS Always success.
1666 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;
1670 EfiShellRemoveDupInFileList(
1671 IN EFI_SHELL_FILE_INFO
**FileList
1674 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1675 EFI_SHELL_FILE_INFO
*ShellFileListItem2
;
1677 if (FileList
== NULL
|| *FileList
== NULL
) {
1678 return (EFI_INVALID_PARAMETER
);
1680 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&(*FileList
)->Link
)
1681 ; !IsNull(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1682 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1684 for ( ShellFileListItem2
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1685 ; !IsNull(&(*FileList
)->Link
, &ShellFileListItem2
->Link
)
1686 ; ShellFileListItem2
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&(*FileList
)->Link
, &ShellFileListItem2
->Link
)
1688 if (gUnicodeCollation
->StriColl(
1690 (CHAR16
*)ShellFileListItem
->FullName
,
1691 (CHAR16
*)ShellFileListItem2
->FullName
) == 0
1693 RemoveEntryList(&ShellFileListItem2
->Link
);
1694 InternalFreeShellFileInfoNode(ShellFileListItem2
);
1698 return (EFI_SUCCESS
);
1701 Allocates and duplicates a EFI_SHELL_FILE_INFO node.
1703 @param[in] Node The node to copy from.
1704 @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise.
1706 @retval NULL a memory allocation error ocurred
1707 @return != NULL a pointer to the new node
1709 EFI_SHELL_FILE_INFO
*
1711 InternalDuplicateShellFileInfo(
1712 IN EFI_SHELL_FILE_INFO
*Node
,
1716 EFI_SHELL_FILE_INFO
*NewNode
;
1718 NewNode
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1719 if (NewNode
== NULL
) {
1722 NewNode
->FullName
= AllocateZeroPool(StrSize(Node
->FullName
));
1724 NewNode
->FileName
= AllocateZeroPool(StrSize(Node
->FileName
));
1725 NewNode
->Info
= AllocateZeroPool((UINTN
)Node
->Info
->Size
);
1726 if ( NewNode
->FullName
== NULL
1727 || NewNode
->FileName
== NULL
1728 || NewNode
->Info
== NULL
1732 NewNode
->Status
= Node
->Status
;
1733 NewNode
->Handle
= Node
->Handle
;
1735 Node
->Handle
= NULL
;
1737 StrCpy((CHAR16
*)NewNode
->FullName
, Node
->FullName
);
1738 StrCpy((CHAR16
*)NewNode
->FileName
, Node
->FileName
);
1739 CopyMem(NewNode
->Info
, Node
->Info
, (UINTN
)Node
->Info
->Size
);
1745 Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation
1746 failed it will return NULL.
1748 @param[in] BasePath the Path to prepend onto filename for FullPath
1749 @param[in] Status Status member initial value.
1750 @param[in] FullName FullName member initial value.
1751 @param[in] FileName FileName member initial value.
1752 @param[in] Handle Handle member initial value.
1753 @param[in] Info Info struct to copy.
1755 @retval NULL An error ocurred.
1756 @return a pointer to the newly allocated structure.
1758 EFI_SHELL_FILE_INFO
*
1760 CreateAndPopulateShellFileInfo(
1761 IN CONST CHAR16
*BasePath
,
1762 IN CONST EFI_STATUS Status
,
1763 IN CONST CHAR16
*FullName
,
1764 IN CONST CHAR16
*FileName
,
1765 IN CONST SHELL_FILE_HANDLE Handle
,
1766 IN CONST EFI_FILE_INFO
*Info
1769 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1776 ShellFileListItem
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1777 if (ShellFileListItem
== NULL
) {
1780 if (Info
!= NULL
&& Info
->Size
!= 0) {
1781 ShellFileListItem
->Info
= AllocateZeroPool((UINTN
)Info
->Size
);
1782 if (ShellFileListItem
->Info
== NULL
) {
1783 FreePool(ShellFileListItem
);
1786 CopyMem(ShellFileListItem
->Info
, Info
, (UINTN
)Info
->Size
);
1788 ShellFileListItem
->Info
= NULL
;
1790 if (FileName
!= NULL
) {
1791 ASSERT(TempString
== NULL
);
1792 ShellFileListItem
->FileName
= StrnCatGrow(&TempString
, 0, FileName
, 0);
1793 if (ShellFileListItem
->FileName
== NULL
) {
1794 FreePool(ShellFileListItem
->Info
);
1795 FreePool(ShellFileListItem
);
1799 ShellFileListItem
->FileName
= NULL
;
1803 if (BasePath
!= NULL
) {
1804 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
1805 TempString
= StrnCatGrow(&TempString
, &Size
, BasePath
, 0);
1806 if (TempString
== NULL
) {
1807 FreePool((VOID
*)ShellFileListItem
->FileName
);
1808 FreePool(ShellFileListItem
->Info
);
1809 FreePool(ShellFileListItem
);
1813 if (ShellFileListItem
->FileName
!= NULL
) {
1814 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
1815 TempString
= StrnCatGrow(&TempString
, &Size
, ShellFileListItem
->FileName
, 0);
1816 if (TempString
== NULL
) {
1817 FreePool((VOID
*)ShellFileListItem
->FileName
);
1818 FreePool(ShellFileListItem
->Info
);
1819 FreePool(ShellFileListItem
);
1824 ShellFileListItem
->FullName
= TempString
;
1825 ShellFileListItem
->Status
= Status
;
1826 ShellFileListItem
->Handle
= Handle
;
1828 return (ShellFileListItem
);
1832 Find all files in a specified directory.
1834 @param FileDirHandle Handle of the directory to search.
1835 @param FileList On return, points to the list of files in the directory
1836 or NULL if there are no files in the directory.
1838 @retval EFI_SUCCESS File information was returned successfully.
1839 @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted.
1840 @retval EFI_DEVICE_ERROR The device reported an error.
1841 @retval EFI_NO_MEDIA The device media is not present.
1842 @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory.
1843 @return An error from FileHandleGetFileName().
1847 EfiShellFindFilesInDir(
1848 IN SHELL_FILE_HANDLE FileDirHandle
,
1849 OUT EFI_SHELL_FILE_INFO
**FileList
1852 EFI_SHELL_FILE_INFO
*ShellFileList
;
1853 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1854 EFI_FILE_INFO
*FileInfo
;
1862 Status
= FileHandleGetFileName(FileDirHandle
, &BasePath
);
1863 if (EFI_ERROR(Status
)) {
1867 if (ShellFileHandleGetPath(FileDirHandle
) != NULL
) {
1870 TempString
= StrnCatGrow(&TempString
, &Size
, ShellFileHandleGetPath(FileDirHandle
), 0);
1871 if (TempString
== NULL
) {
1872 return (EFI_OUT_OF_RESOURCES
);
1874 TempSpot
= StrStr(TempString
, L
";");
1876 if (TempSpot
!= NULL
) {
1877 *TempSpot
= CHAR_NULL
;
1880 TempString
= StrnCatGrow(&TempString
, &Size
, BasePath
, 0);
1881 if (TempString
== NULL
) {
1882 return (EFI_OUT_OF_RESOURCES
);
1884 BasePath
= TempString
;
1888 ShellFileList
= NULL
;
1889 ShellFileListItem
= NULL
;
1891 Status
= EFI_SUCCESS
;
1894 for ( Status
= FileHandleFindFirstFile(FileDirHandle
, &FileInfo
)
1895 ; !EFI_ERROR(Status
) && !NoFile
1896 ; Status
= FileHandleFindNextFile(FileDirHandle
, FileInfo
, &NoFile
)
1901 // allocate a new EFI_SHELL_FILE_INFO and populate it...
1903 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
1904 TempString
= StrnCatGrow(&TempString
, &Size
, BasePath
, 0);
1905 TempString
= StrnCatGrow(&TempString
, &Size
, FileInfo
->FileName
, 0);
1906 ShellFileListItem
= CreateAndPopulateShellFileInfo(
1908 EFI_SUCCESS
, // success since we didnt fail to open it...
1911 NULL
, // no handle since not open
1914 if (ShellFileList
== NULL
) {
1915 ShellFileList
= (EFI_SHELL_FILE_INFO
*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1916 ASSERT(ShellFileList
!= NULL
);
1917 InitializeListHead(&ShellFileList
->Link
);
1919 InsertTailList(&ShellFileList
->Link
, &ShellFileListItem
->Link
);
1921 if (EFI_ERROR(Status
)) {
1922 EfiShellFreeFileList(&ShellFileList
);
1925 *FileList
= ShellFileList
;
1927 SHELL_FREE_NON_NULL(BasePath
);
1932 Updates a file name to be preceeded by the mapped drive name
1934 @param[in] BasePath the Mapped drive name to prepend
1935 @param[in, out] Path pointer to pointer to the file name to update.
1938 @retval EFI_OUT_OF_RESOURCES
1943 IN CONST CHAR16
*BasePath
,
1944 IN OUT CHAR16
**Path
1953 ASSERT(Path
!= NULL
);
1954 ASSERT(*Path
!= NULL
);
1955 ASSERT(BasePath
!= NULL
);
1958 // convert a local path to an absolute path
1960 if (StrStr(*Path
, L
":") == NULL
) {
1961 ASSERT((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
1962 StrnCatGrow(&Path2
, &Path2Size
, BasePath
, 0);
1963 if (Path2
== NULL
) {
1964 return (EFI_OUT_OF_RESOURCES
);
1966 ASSERT((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
1967 StrnCatGrow(&Path2
, &Path2Size
, (*Path
)[0] == L
'\\'?(*Path
) + 1 :*Path
, 0);
1968 if (Path2
== NULL
) {
1969 return (EFI_OUT_OF_RESOURCES
);
1976 return (EFI_SUCCESS
);
1980 If FileHandle is a directory then the function reads from FileHandle and reads in
1981 each of the FileInfo structures. If one of them matches the Pattern's first
1982 "level" then it opens that handle and calls itself on that handle.
1984 If FileHandle is a file and matches all of the remaining Pattern (which would be
1985 on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.
1987 Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call
1988 FreeFileList with FileList.
1990 @param[in] FilePattern The FilePattern to check against.
1991 @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure
1992 @param[in] FileHandle The FileHandle to start with
1993 @param[in, out] FileList pointer to pointer to list of found files.
1994 @param[in] ParentNode The node for the parent. Same file as identified by HANDLE.
1995 @param[in] MapName The file system name this file is on.
1997 @retval EFI_SUCCESS all files were found and the FileList contains a list.
1998 @retval EFI_NOT_FOUND no files were found
1999 @retval EFI_OUT_OF_RESOURCES a memory allocation failed
2004 IN CONST CHAR16
*FilePattern
,
2005 IN EFI_UNICODE_COLLATION_PROTOCOL
*UnicodeCollation
,
2006 IN SHELL_FILE_HANDLE FileHandle
,
2007 IN OUT EFI_SHELL_FILE_INFO
**FileList
,
2008 IN CONST EFI_SHELL_FILE_INFO
*ParentNode OPTIONAL
,
2009 IN CONST CHAR16
*MapName
2013 CONST CHAR16
*NextFilePatternStart
;
2014 CHAR16
*CurrentFilePattern
;
2015 EFI_SHELL_FILE_INFO
*ShellInfo
;
2016 EFI_SHELL_FILE_INFO
*ShellInfoNode
;
2017 EFI_SHELL_FILE_INFO
*NewShellNode
;
2019 CHAR16
*NewFullName
;
2022 if ( FilePattern
== NULL
2023 || UnicodeCollation
== NULL
2026 return (EFI_INVALID_PARAMETER
);
2029 CurrentFilePattern
= NULL
;
2031 if (*FilePattern
== L
'\\') {
2035 for( NextFilePatternStart
= FilePattern
2036 ; *NextFilePatternStart
!= CHAR_NULL
&& *NextFilePatternStart
!= L
'\\'
2037 ; NextFilePatternStart
++);
2039 CurrentFilePattern
= AllocateZeroPool((NextFilePatternStart
-FilePattern
+1)*sizeof(CHAR16
));
2040 ASSERT(CurrentFilePattern
!= NULL
);
2041 StrnCpy(CurrentFilePattern
, FilePattern
, NextFilePatternStart
-FilePattern
);
2043 if (CurrentFilePattern
[0] == CHAR_NULL
2044 &&NextFilePatternStart
[0] == CHAR_NULL
2047 // Add the current parameter FileHandle to the list, then end...
2049 if (ParentNode
== NULL
) {
2050 Status
= EFI_INVALID_PARAMETER
;
2052 NewShellNode
= InternalDuplicateShellFileInfo((EFI_SHELL_FILE_INFO
*)ParentNode
, TRUE
);
2053 if (NewShellNode
== NULL
) {
2054 Status
= EFI_OUT_OF_RESOURCES
;
2056 NewShellNode
->Handle
= NULL
;
2057 if (*FileList
== NULL
) {
2058 *FileList
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
2059 InitializeListHead(&((*FileList
)->Link
));
2063 // Add to the returning to use list
2065 InsertTailList(&(*FileList
)->Link
, &NewShellNode
->Link
);
2067 Status
= EFI_SUCCESS
;
2071 Status
= EfiShellFindFilesInDir(FileHandle
, &ShellInfo
);
2073 if (!EFI_ERROR(Status
)){
2074 if (StrStr(NextFilePatternStart
, L
"\\") != NULL
){
2079 for ( ShellInfoNode
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ShellInfo
->Link
)
2080 ; !IsNull (&ShellInfo
->Link
, &ShellInfoNode
->Link
)
2081 ; ShellInfoNode
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ShellInfo
->Link
, &ShellInfoNode
->Link
)
2083 if (UnicodeCollation
->MetaiMatch(UnicodeCollation
, (CHAR16
*)ShellInfoNode
->FileName
, CurrentFilePattern
)){
2084 if (ShellInfoNode
->FullName
!= NULL
&& StrStr(ShellInfoNode
->FullName
, L
":") == NULL
) {
2085 Size
= StrSize(ShellInfoNode
->FullName
);
2086 Size
+= StrSize(MapName
) + sizeof(CHAR16
);
2087 NewFullName
= AllocateZeroPool(Size
);
2088 if (NewFullName
== NULL
) {
2089 Status
= EFI_OUT_OF_RESOURCES
;
2091 StrCpy(NewFullName
, MapName
);
2092 StrCat(NewFullName
, ShellInfoNode
->FullName
+1);
2093 FreePool((VOID
*)ShellInfoNode
->FullName
);
2094 ShellInfoNode
->FullName
= NewFullName
;
2097 if (Directory
&& !EFI_ERROR(Status
) && ShellInfoNode
->FullName
!= NULL
&& ShellInfoNode
->FileName
!= NULL
){
2099 // should be a directory
2103 // don't open the . and .. directories
2105 if ( (StrCmp(ShellInfoNode
->FileName
, L
".") != 0)
2106 && (StrCmp(ShellInfoNode
->FileName
, L
"..") != 0)
2111 if (EFI_ERROR(Status
)) {
2115 // Open the directory since we need that handle in the next recursion.
2117 ShellInfoNode
->Status
= EfiShellOpenFileByName (ShellInfoNode
->FullName
, &ShellInfoNode
->Handle
, EFI_FILE_MODE_READ
);
2120 // recurse with the next part of the pattern
2122 Status
= ShellSearchHandle(NextFilePatternStart
, UnicodeCollation
, ShellInfoNode
->Handle
, FileList
, ShellInfoNode
, MapName
);
2124 } else if (!EFI_ERROR(Status
)) {
2130 // copy the information we need into a new Node
2132 NewShellNode
= InternalDuplicateShellFileInfo(ShellInfoNode
, FALSE
);
2133 ASSERT(NewShellNode
!= NULL
);
2134 if (NewShellNode
== NULL
) {
2135 Status
= EFI_OUT_OF_RESOURCES
;
2137 if (*FileList
== NULL
) {
2138 *FileList
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
2139 InitializeListHead(&((*FileList
)->Link
));
2143 // Add to the returning to use list
2145 InsertTailList(&(*FileList
)->Link
, &NewShellNode
->Link
);
2148 if (EFI_ERROR(Status
)) {
2152 if (EFI_ERROR(Status
)) {
2153 EfiShellFreeFileList(&ShellInfo
);
2155 Status
= EfiShellFreeFileList(&ShellInfo
);
2160 FreePool(CurrentFilePattern
);
2165 Find files that match a specified pattern.
2167 This function searches for all files and directories that match the specified
2168 FilePattern. The FilePattern can contain wild-card characters. The resulting file
2169 information is placed in the file list FileList.
2171 Wildcards are processed
2172 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1.
2174 The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo
2175 field is set to NULL.
2177 if *FileList is not NULL then it must be a pre-existing and properly initialized list.
2179 @param FilePattern Points to a NULL-terminated shell file path, including wildcards.
2180 @param FileList On return, points to the start of a file list containing the names
2181 of all matching files or else points to NULL if no matching files
2182 were found. only on a EFI_SUCCESS return will; this be non-NULL.
2184 @retval EFI_SUCCESS Files found. FileList is a valid list.
2185 @retval EFI_NOT_FOUND No files found.
2186 @retval EFI_NO_MEDIA The device has no media
2187 @retval EFI_DEVICE_ERROR The device reported an error
2188 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted
2193 IN CONST CHAR16
*FilePattern
,
2194 OUT EFI_SHELL_FILE_INFO
**FileList
2198 CHAR16
*PatternCopy
;
2199 CHAR16
*PatternCurrentLocation
;
2200 EFI_DEVICE_PATH_PROTOCOL
*RootDevicePath
;
2201 SHELL_FILE_HANDLE RootFileHandle
;
2205 if ( FilePattern
== NULL
2207 || StrStr(FilePattern
, L
":") == NULL
2209 return (EFI_INVALID_PARAMETER
);
2211 Status
= EFI_SUCCESS
;
2212 RootDevicePath
= NULL
;
2213 RootFileHandle
= NULL
;
2215 PatternCopy
= AllocateZeroPool(StrSize(FilePattern
));
2216 if (PatternCopy
== NULL
) {
2217 return (EFI_OUT_OF_RESOURCES
);
2219 StrCpy(PatternCopy
, FilePattern
);
2221 PatternCopy
= PathCleanUpDirectories(PatternCopy
);
2223 Count
= StrStr(PatternCopy
, L
":") - PatternCopy
;
2226 ASSERT(MapName
== NULL
);
2227 MapName
= StrnCatGrow(&MapName
, NULL
, PatternCopy
, Count
);
2228 if (MapName
== NULL
) {
2229 Status
= EFI_OUT_OF_RESOURCES
;
2231 RootDevicePath
= EfiShellGetDevicePathFromFilePath(PatternCopy
);
2232 if (RootDevicePath
== NULL
) {
2233 Status
= EFI_INVALID_PARAMETER
;
2235 Status
= EfiShellOpenRoot(RootDevicePath
, &RootFileHandle
);
2236 if (!EFI_ERROR(Status
)) {
2237 for ( PatternCurrentLocation
= PatternCopy
2238 ; *PatternCurrentLocation
!= ':'
2239 ; PatternCurrentLocation
++);
2240 PatternCurrentLocation
++;
2241 Status
= ShellSearchHandle(PatternCurrentLocation
, gUnicodeCollation
, RootFileHandle
, FileList
, NULL
, MapName
);
2243 FreePool(RootDevicePath
);
2247 SHELL_FREE_NON_NULL(PatternCopy
);
2248 SHELL_FREE_NON_NULL(MapName
);
2254 Opens the files that match the path specified.
2256 This function opens all of the files specified by Path. Wildcards are processed
2257 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each
2258 matching file has an EFI_SHELL_FILE_INFO structure created in a linked list.
2260 @param Path A pointer to the path string.
2261 @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or
2262 EFI_FILE_MODE_WRITE.
2263 @param FileList Points to the start of a list of files opened.
2265 @retval EFI_SUCCESS Create the file list successfully.
2266 @return Others Can't create the file list.
2270 EfiShellOpenFileList(
2273 IN OUT EFI_SHELL_FILE_INFO
**FileList
2277 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
2280 CONST CHAR16
*CurDir
;
2283 PathCleanUpDirectories(Path
);
2288 if (FileList
== NULL
|| *FileList
== NULL
) {
2289 return (EFI_INVALID_PARAMETER
);
2292 if (*Path
== L
'.' && *(Path
+1) == L
'\\') {
2297 // convert a local path to an absolute path
2299 if (StrStr(Path
, L
":") == NULL
) {
2300 CurDir
= EfiShellGetCurDir(NULL
);
2301 ASSERT((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
2302 StrnCatGrow(&Path2
, &Path2Size
, CurDir
, 0);
2303 if (*Path
== L
'\\') {
2305 while (PathRemoveLastItem(Path2
)) ;
2307 ASSERT((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
2308 StrnCatGrow(&Path2
, &Path2Size
, Path
, 0);
2310 ASSERT(Path2
== NULL
);
2311 StrnCatGrow(&Path2
, NULL
, Path
, 0);
2314 PathCleanUpDirectories (Path2
);
2319 Status
= EfiShellFindFiles(Path2
, FileList
);
2323 if (EFI_ERROR(Status
)) {
2329 // We had no errors so open all the files (that are not already opened...)
2331 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&(*FileList
)->Link
)
2332 ; !IsNull(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
2333 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
2335 if (ShellFileListItem
->Status
== 0 && ShellFileListItem
->Handle
== NULL
) {
2336 ShellFileListItem
->Status
= EfiShellOpenFileByName (ShellFileListItem
->FullName
, &ShellFileListItem
->Handle
, OpenMode
);
2342 return (EFI_NOT_FOUND
);
2344 return(EFI_SUCCESS
);
2348 This function updated with errata.
2350 Gets either a single or list of environment variables.
2352 If name is not NULL then this function returns the current value of the specified
2353 environment variable.
2355 If Name is NULL, then a list of all environment variable names is returned. Each is a
2356 NULL terminated string with a double NULL terminating the list.
2358 @param Name A pointer to the environment variable name. If
2359 Name is NULL, then the function will return all
2360 of the defined shell environment variables. In
2361 the case where multiple environment variables are
2362 being returned, each variable will be terminated by
2363 a NULL, and the list will be terminated by a double
2366 @return !=NULL A pointer to the returned string.
2367 The returned pointer does not need to be freed by the caller.
2369 @retval NULL The environment variable doesn't exist or there are
2370 no environment variables.
2375 IN CONST CHAR16
*Name
2383 CHAR16
*CurrentWriteLocation
;
2390 // Get all our environment variables
2392 InitializeListHead(&List
);
2393 Status
= GetEnvironmentVariableList(&List
);
2394 if (EFI_ERROR(Status
)){
2399 // Build the semi-colon delimited list. (2 passes)
2401 for ( Node
= (ENV_VAR_LIST
*)GetFirstNode(&List
)
2402 ; !IsNull(&List
, &Node
->Link
)
2403 ; Node
= (ENV_VAR_LIST
*)GetNextNode(&List
, &Node
->Link
)
2405 ASSERT(Node
->Key
!= NULL
);
2406 Size
+= StrSize(Node
->Key
);
2409 Size
+= 2*sizeof(CHAR16
);
2411 Buffer
= AllocateZeroPool(Size
);
2412 if (Buffer
== NULL
) {
2413 if (!IsListEmpty (&List
)) {
2414 FreeEnvironmentVariableList(&List
);
2418 CurrentWriteLocation
= (CHAR16
*)Buffer
;
2420 for ( Node
= (ENV_VAR_LIST
*)GetFirstNode(&List
)
2421 ; !IsNull(&List
, &Node
->Link
)
2422 ; Node
= (ENV_VAR_LIST
*)GetNextNode(&List
, &Node
->Link
)
2424 ASSERT(Node
->Key
!= NULL
);
2425 StrCpy(CurrentWriteLocation
, Node
->Key
);
2426 CurrentWriteLocation
+= StrLen(CurrentWriteLocation
) + 1;
2432 if (!IsListEmpty (&List
)) {
2433 FreeEnvironmentVariableList(&List
);
2437 // We are doing a specific environment variable
2441 // get the size we need for this EnvVariable
2443 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(Name
, &Size
, Buffer
);
2444 if (Status
== EFI_BUFFER_TOO_SMALL
) {
2446 // Allocate the space and recall the get function
2448 Buffer
= AllocateZeroPool(Size
);
2449 ASSERT(Buffer
!= NULL
);
2450 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(Name
, &Size
, Buffer
);
2453 // we didnt get it (might not exist)
2454 // free the memory if we allocated any and return NULL
2456 if (EFI_ERROR(Status
)) {
2457 if (Buffer
!= NULL
) {
2465 // return the buffer
2467 return (AddBufferToFreeList(Buffer
));
2471 Internal variable setting function. Allows for setting of the read only variables.
2473 @param Name Points to the NULL-terminated environment variable name.
2474 @param Value Points to the NULL-terminated environment variable value. If the value is an
2475 empty string then the environment variable is deleted.
2476 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
2478 @retval EFI_SUCCESS The environment variable was successfully updated.
2482 InternalEfiShellSetEnv(
2483 IN CONST CHAR16
*Name
,
2484 IN CONST CHAR16
*Value
,
2488 if (Value
== NULL
|| StrLen(Value
) == 0) {
2489 return (SHELL_DELETE_ENVIRONMENT_VARIABLE(Name
));
2491 SHELL_DELETE_ENVIRONMENT_VARIABLE(Name
);
2493 return (SHELL_SET_ENVIRONMENT_VARIABLE_V(Name
, StrSize(Value
), Value
));
2495 return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(Name
, StrSize(Value
), Value
));
2501 Sets the environment variable.
2503 This function changes the current value of the specified environment variable. If the
2504 environment variable exists and the Value is an empty string, then the environment
2505 variable is deleted. If the environment variable exists and the Value is not an empty
2506 string, then the value of the environment variable is changed. If the environment
2507 variable does not exist and the Value is an empty string, there is no action. If the
2508 environment variable does not exist and the Value is a non-empty string, then the
2509 environment variable is created and assigned the specified value.
2511 For a description of volatile and non-volatile environment variables, see UEFI Shell
2512 2.0 specification section 3.6.1.
2514 @param Name Points to the NULL-terminated environment variable name.
2515 @param Value Points to the NULL-terminated environment variable value. If the value is an
2516 empty string then the environment variable is deleted.
2517 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
2519 @retval EFI_SUCCESS The environment variable was successfully updated.
2524 IN CONST CHAR16
*Name
,
2525 IN CONST CHAR16
*Value
,
2529 if (Name
== NULL
|| *Name
== CHAR_NULL
) {
2530 return (EFI_INVALID_PARAMETER
);
2533 // Make sure we dont 'set' a predefined read only variable
2535 if (gUnicodeCollation
->StriColl(
2539 ||gUnicodeCollation
->StriColl(
2543 ||gUnicodeCollation
->StriColl(
2547 ||gUnicodeCollation
->StriColl(
2550 L
"uefishellsupport") == 0
2551 ||gUnicodeCollation
->StriColl(
2554 L
"uefishellversion") == 0
2555 ||gUnicodeCollation
->StriColl(
2558 L
"uefiversion") == 0
2560 return (EFI_INVALID_PARAMETER
);
2562 return (InternalEfiShellSetEnv(Name
, Value
, Volatile
));
2566 Returns the current directory on the specified device.
2568 If FileSystemMapping is NULL, it returns the current working directory. If the
2569 FileSystemMapping is not NULL, it returns the current directory associated with the
2570 FileSystemMapping. In both cases, the returned name includes the file system
2571 mapping (i.e. fs0:\current-dir).
2573 @param FileSystemMapping A pointer to the file system mapping. If NULL,
2574 then the current working directory is returned.
2576 @retval !=NULL The current directory.
2577 @retval NULL Current directory does not exist.
2582 IN CONST CHAR16
*FileSystemMapping OPTIONAL
2585 CHAR16
*PathToReturn
;
2587 SHELL_MAP_LIST
*MapListItem
;
2588 if (!IsListEmpty(&gShellMapList
.Link
)) {
2590 // if parameter is NULL, use current
2592 if (FileSystemMapping
== NULL
) {
2593 return (EfiShellGetEnv(L
"cwd"));
2596 PathToReturn
= NULL
;
2597 MapListItem
= ShellCommandFindMapItem(FileSystemMapping
);
2598 if (MapListItem
!= NULL
) {
2599 ASSERT((PathToReturn
== NULL
&& Size
== 0) || (PathToReturn
!= NULL
));
2600 PathToReturn
= StrnCatGrow(&PathToReturn
, &Size
, MapListItem
->MapName
, 0);
2601 PathToReturn
= StrnCatGrow(&PathToReturn
, &Size
, MapListItem
->CurrentDirectoryPath
, 0);
2604 return (AddBufferToFreeList(PathToReturn
));
2611 Changes the current directory on the specified device.
2613 If the FileSystem is NULL, and the directory Dir does not contain a file system's
2614 mapped name, this function changes the current working directory.
2616 If the FileSystem is NULL and the directory Dir contains a mapped name, then the
2617 current file system and the current directory on that file system are changed.
2619 If FileSystem is NULL, and Dir is not NULL, then this changes the current working file
2622 If FileSystem is not NULL and Dir is not NULL, then this function changes the current
2623 directory on the specified file system.
2625 If the current working directory or the current working file system is changed then the
2626 %cwd% environment variable will be updated
2628 @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working
2629 directory is changed.
2630 @param Dir Points to the NULL-terminated directory on the device specified by FileSystem.
2632 @retval EFI_SUCCESS The operation was sucessful
2633 @retval EFI_NOT_FOUND The file system could not be found
2638 IN CONST CHAR16
*FileSystem OPTIONAL
,
2639 IN CONST CHAR16
*Dir
2643 SHELL_MAP_LIST
*MapListItem
;
2647 CHAR16
*DirectoryName
;
2654 DirectoryName
= NULL
;
2656 if ((FileSystem
== NULL
&& Dir
== NULL
) || Dir
== NULL
) {
2657 return (EFI_INVALID_PARAMETER
);
2660 if (IsListEmpty(&gShellMapList
.Link
)){
2661 return (EFI_NOT_FOUND
);
2664 DirectoryName
= StrnCatGrow(&DirectoryName
, NULL
, Dir
, 0);
2665 ASSERT(DirectoryName
!= NULL
);
2667 PathCleanUpDirectories(DirectoryName
);
2669 if (FileSystem
== NULL
) {
2671 // determine the file system mapping to use
2673 if (StrStr(DirectoryName
, L
":") != NULL
) {
2674 ASSERT(MapName
== NULL
);
2675 MapName
= StrnCatGrow(&MapName
, NULL
, DirectoryName
, (StrStr(DirectoryName
, L
":")-DirectoryName
+1));
2678 // find the file system mapping's entry in the list
2681 if (MapName
!= NULL
) {
2682 MapListItem
= ShellCommandFindMapItem(MapName
);
2685 // make that the current file system mapping
2687 if (MapListItem
!= NULL
) {
2688 gShellCurDir
= MapListItem
;
2691 MapListItem
= gShellCurDir
;
2694 if (MapListItem
== NULL
) {
2695 return (EFI_NOT_FOUND
);
2699 // now update the MapListItem's current directory
2701 if (MapListItem
->CurrentDirectoryPath
!= NULL
&& DirectoryName
[StrLen(DirectoryName
) - 1] != L
':') {
2702 FreePool(MapListItem
->CurrentDirectoryPath
);
2703 MapListItem
->CurrentDirectoryPath
= NULL
;
2705 if (MapName
!= NULL
) {
2706 TempLen
= StrLen(MapName
);
2707 if (TempLen
!= StrLen(DirectoryName
)) {
2708 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2709 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
+StrLen(MapName
), 0);
2712 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2713 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
, 0);
2715 if ((MapListItem
->CurrentDirectoryPath
!= NULL
&& MapListItem
->CurrentDirectoryPath
[StrLen(MapListItem
->CurrentDirectoryPath
)-1] != L
'\\') || (MapListItem
->CurrentDirectoryPath
== NULL
)) {
2716 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2717 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, L
"\\", 0);
2721 // cant have a mapping in the directory...
2723 if (StrStr(DirectoryName
, L
":") != NULL
) {
2724 return (EFI_INVALID_PARAMETER
);
2727 // FileSystem != NULL
2729 MapListItem
= ShellCommandFindMapItem(FileSystem
);
2730 if (MapListItem
== NULL
) {
2731 return (EFI_INVALID_PARAMETER
);
2733 // gShellCurDir = MapListItem;
2734 if (DirectoryName
!= NULL
) {
2736 // change current dir on that file system
2739 if (MapListItem
->CurrentDirectoryPath
!= NULL
) {
2740 FreePool(MapListItem
->CurrentDirectoryPath
);
2741 DEBUG_CODE(MapListItem
->CurrentDirectoryPath
= NULL
;);
2743 // ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
2744 // MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);
2745 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2746 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, L
"\\", 0);
2747 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2748 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
, 0);
2749 if (MapListItem
->CurrentDirectoryPath
!= NULL
&& MapListItem
->CurrentDirectoryPath
[StrLen(MapListItem
->CurrentDirectoryPath
)-1] != L
'\\') {
2750 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2751 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, L
"\\", 0);
2756 // if updated the current directory then update the environment variable
2758 if (MapListItem
== gShellCurDir
) {
2760 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
2761 StrnCatGrow(&TempString
, &Size
, MapListItem
->MapName
, 0);
2762 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
2763 StrnCatGrow(&TempString
, &Size
, MapListItem
->CurrentDirectoryPath
, 0);
2764 Status
= InternalEfiShellSetEnv(L
"cwd", TempString
, TRUE
);
2765 FreePool(TempString
);
2768 return(EFI_SUCCESS
);
2772 Return help information about a specific command.
2774 This function returns the help information for the specified command. The help text
2775 can be internal to the shell or can be from a UEFI Shell manual page.
2777 If Sections is specified, then each section name listed will be compared in a casesensitive
2778 manner, to the section names described in Appendix B. If the section exists,
2779 it will be appended to the returned help text. If the section does not exist, no
2780 information will be returned. If Sections is NULL, then all help text information
2781 available will be returned.
2783 @param Command Points to the NULL-terminated UEFI Shell command name.
2784 @param Sections Points to the NULL-terminated comma-delimited
2785 section names to return. If NULL, then all
2786 sections will be returned.
2787 @param HelpText On return, points to a callee-allocated buffer
2788 containing all specified help text.
2790 @retval EFI_SUCCESS The help text was returned.
2791 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the
2793 @retval EFI_INVALID_PARAMETER HelpText is NULL
2794 @retval EFI_NOT_FOUND There is no help text available for Command.
2798 EfiShellGetHelpText(
2799 IN CONST CHAR16
*Command
,
2800 IN CONST CHAR16
*Sections OPTIONAL
,
2801 OUT CHAR16
**HelpText
2804 CONST CHAR16
*ManFileName
;
2806 ASSERT(HelpText
!= NULL
);
2808 ManFileName
= ShellCommandGetManFileNameHandler(Command
);
2810 if (ManFileName
!= NULL
) {
2811 return (ProcessManFile(ManFileName
, Command
, Sections
, NULL
, HelpText
));
2813 return (ProcessManFile(Command
, Command
, Sections
, NULL
, HelpText
));
2818 Gets the enable status of the page break output mode.
2820 User can use this function to determine current page break mode.
2822 @retval TRUE The page break output mode is enabled.
2823 @retval FALSE The page break output mode is disabled.
2827 EfiShellGetPageBreak(
2831 return(ShellInfoObject
.PageBreakEnabled
);
2835 Judges whether the active shell is the root shell.
2837 This function makes the user to know that whether the active Shell is the root shell.
2839 @retval TRUE The active Shell is the root Shell.
2840 @retval FALSE The active Shell is NOT the root Shell.
2844 EfiShellIsRootShell(
2848 return(ShellInfoObject
.RootShellInstance
);
2852 function to return a semi-colon delimeted list of all alias' in the current shell
2854 up to caller to free the memory.
2856 @retval NULL No alias' were found
2857 @retval NULL An error ocurred getting alias'
2858 @return !NULL a list of all alias'
2862 InternalEfiShellGetListAlias(
2870 CHAR16
*VariableName
;
2875 Status
= gRT
->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
, &MaxStorSize
, &RemStorSize
, &MaxVarSize
);
2876 ASSERT_EFI_ERROR(Status
);
2878 VariableName
= AllocateZeroPool((UINTN
)MaxVarSize
);
2882 if (VariableName
== NULL
) {
2886 VariableName
[0] = CHAR_NULL
;
2889 NameSize
= (UINTN
)MaxVarSize
;
2890 Status
= gRT
->GetNextVariableName(&NameSize
, VariableName
, &Guid
);
2891 if (Status
== EFI_NOT_FOUND
){
2894 ASSERT_EFI_ERROR(Status
);
2895 if (EFI_ERROR(Status
)) {
2898 if (CompareGuid(&Guid
, &gShellAliasGuid
)){
2899 ASSERT((RetVal
== NULL
&& RetSize
== 0) || (RetVal
!= NULL
));
2900 RetVal
= StrnCatGrow(&RetVal
, &RetSize
, VariableName
, 0);
2901 RetVal
= StrnCatGrow(&RetVal
, &RetSize
, L
";", 0);
2904 FreePool(VariableName
);
2910 This function returns the command associated with a alias or a list of all
2913 @param[in] Alias Points to the NULL-terminated shell alias.
2914 If this parameter is NULL, then all
2915 aliases will be returned in ReturnedData.
2916 @param[out] Volatile upon return of a single command if TRUE indicates
2917 this is stored in a volatile fashion. FALSE otherwise.
2919 @return If Alias is not NULL, it will return a pointer to
2920 the NULL-terminated command for that alias.
2921 If Alias is NULL, ReturnedData points to a ';'
2922 delimited list of alias (e.g.
2923 ReturnedData = "dir;del;copy;mfp") that is NULL-terminated.
2924 @retval NULL an error ocurred
2925 @retval NULL Alias was not a valid Alias
2930 IN CONST CHAR16
*Alias
,
2931 OUT BOOLEAN
*Volatile OPTIONAL
2939 if (Alias
!= NULL
) {
2940 if (Volatile
== NULL
) {
2941 return (AddBufferToFreeList(GetVariable((CHAR16
*)Alias
, &gShellAliasGuid
)));
2945 Status
= gRT
->GetVariable((CHAR16
*)Alias
, &gShellAliasGuid
, &Attribs
, &RetSize
, RetVal
);
2946 if (Status
== EFI_BUFFER_TOO_SMALL
) {
2947 RetVal
= AllocateZeroPool(RetSize
);
2948 Status
= gRT
->GetVariable((CHAR16
*)Alias
, &gShellAliasGuid
, &Attribs
, &RetSize
, RetVal
);
2950 if (EFI_ERROR(Status
)) {
2951 if (RetVal
!= NULL
) {
2956 if ((EFI_VARIABLE_NON_VOLATILE
& Attribs
) == EFI_VARIABLE_NON_VOLATILE
) {
2962 return (AddBufferToFreeList(RetVal
));
2964 return (AddBufferToFreeList(InternalEfiShellGetListAlias()));
2968 Changes a shell command alias.
2970 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.
2972 this function does not check for built in alias'.
2974 @param[in] Command Points to the NULL-terminated shell command or existing alias.
2975 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and
2976 Command refers to an alias, that alias will be deleted.
2977 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the
2978 Alias being set will be stored in a non-volatile fashion.
2980 @retval EFI_SUCCESS Alias created or deleted successfully.
2981 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found
2986 IN CONST CHAR16
*Command
,
2987 IN CONST CHAR16
*Alias
,
2992 // We must be trying to remove one if Alias is NULL
2994 if (Alias
== NULL
) {
2996 // remove an alias (but passed in COMMAND parameter)
2998 return (gRT
->SetVariable((CHAR16
*)Command
, &gShellAliasGuid
, 0, 0, NULL
));
3001 // Add and replace are the same
3004 // We dont check the error return on purpose since the variable may not exist.
3005 gRT
->SetVariable((CHAR16
*)Command
, &gShellAliasGuid
, 0, 0, NULL
);
3007 return (gRT
->SetVariable((CHAR16
*)Alias
, &gShellAliasGuid
, EFI_VARIABLE_BOOTSERVICE_ACCESS
|(Volatile
?0:EFI_VARIABLE_NON_VOLATILE
), StrSize(Command
), (VOID
*)Command
));
3012 Changes a shell command alias.
3014 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.
3017 @param[in] Command Points to the NULL-terminated shell command or existing alias.
3018 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and
3019 Command refers to an alias, that alias will be deleted.
3020 @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If
3021 FALSE and the alias already exists, then the existing alias is unchanged and
3022 EFI_ACCESS_DENIED is returned.
3023 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the
3024 Alias being set will be stored in a non-volatile fashion.
3026 @retval EFI_SUCCESS Alias created or deleted successfully.
3027 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found
3028 @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to
3034 IN CONST CHAR16
*Command
,
3035 IN CONST CHAR16
*Alias
,
3041 // cant set over a built in alias
3043 if (ShellCommandIsOnAliasList(Alias
==NULL
?Command
:Alias
)) {
3044 return (EFI_ACCESS_DENIED
);
3046 if (Command
== NULL
|| *Command
== CHAR_NULL
|| StrLen(Command
) == 0) {
3047 return (EFI_INVALID_PARAMETER
);
3050 if (EfiShellGetAlias(Command
, NULL
) != NULL
&& !Replace
) {
3051 return (EFI_ACCESS_DENIED
);
3054 return (InternalSetAlias(Command
, Alias
, Volatile
));
3057 // Pure FILE_HANDLE operations are passed to FileHandleLib
3058 // these functions are indicated by the *
3059 EFI_SHELL_PROTOCOL mShellProtocol
= {
3065 EfiShellGetHelpText
,
3066 EfiShellGetDevicePathFromMap
,
3067 EfiShellGetMapFromDevicePath
,
3068 EfiShellGetDevicePathFromFilePath
,
3069 EfiShellGetFilePathFromDevicePath
,
3073 EfiShellOpenFileList
,
3074 EfiShellFreeFileList
,
3075 EfiShellRemoveDupInFileList
,
3076 EfiShellBatchIsActive
,
3077 EfiShellIsRootShell
,
3078 EfiShellEnablePageBreak
,
3079 EfiShellDisablePageBreak
,
3080 EfiShellGetPageBreak
,
3081 EfiShellGetDeviceName
,
3082 (EFI_SHELL_GET_FILE_INFO
)FileHandleGetInfo
, //*
3083 (EFI_SHELL_SET_FILE_INFO
)FileHandleSetInfo
, //*
3084 EfiShellOpenFileByName
,
3087 (EFI_SHELL_READ_FILE
)FileHandleRead
, //*
3088 (EFI_SHELL_WRITE_FILE
)FileHandleWrite
, //*
3089 (EFI_SHELL_DELETE_FILE
)FileHandleDelete
, //*
3090 EfiShellDeleteFileByName
,
3091 (EFI_SHELL_GET_FILE_POSITION
)FileHandleGetPosition
, //*
3092 (EFI_SHELL_SET_FILE_POSITION
)FileHandleSetPosition
, //*
3093 (EFI_SHELL_FLUSH_FILE
)FileHandleFlush
, //*
3095 EfiShellFindFilesInDir
,
3096 (EFI_SHELL_GET_FILE_SIZE
)FileHandleGetSize
, //*
3098 EfiShellOpenRootByHandle
,
3100 SHELL_MAJOR_VERSION
,
3105 Function to create and install on the current handle.
3107 Will overwrite any existing ShellProtocols in the system to be sure that
3108 the current shell is in control.
3110 This must be removed via calling CleanUpShellProtocol().
3112 @param[in, out] NewShell The pointer to the pointer to the structure
3115 @retval EFI_SUCCESS The operation was successful.
3116 @return An error from LocateHandle, CreateEvent, or other core function.
3120 CreatePopulateInstallShellProtocol (
3121 IN OUT EFI_SHELL_PROTOCOL
**NewShell
3127 UINTN HandleCounter
;
3128 SHELL_PROTOCOL_HANDLE_LIST
*OldProtocolNode
;
3130 if (NewShell
== NULL
) {
3131 return (EFI_INVALID_PARAMETER
);
3136 OldProtocolNode
= NULL
;
3137 InitializeListHead(&ShellInfoObject
.OldShellList
.Link
);
3140 // Initialize EfiShellProtocol object...
3142 Status
= gBS
->CreateEvent(0,
3146 &mShellProtocol
.ExecutionBreak
);
3147 if (EFI_ERROR(Status
)) {
3152 // Get the size of the buffer we need.
3154 Status
= gBS
->LocateHandle(ByProtocol
,
3155 &gEfiShellProtocolGuid
,
3159 if (Status
== EFI_BUFFER_TOO_SMALL
) {
3161 // Allocate and recall with buffer of correct size
3163 Buffer
= AllocateZeroPool(BufferSize
);
3164 if (Buffer
== NULL
) {
3165 return (EFI_OUT_OF_RESOURCES
);
3167 Status
= gBS
->LocateHandle(ByProtocol
,
3168 &gEfiShellProtocolGuid
,
3172 if (EFI_ERROR(Status
)) {
3177 // now overwrite each of them, but save the info to restore when we end.
3179 for (HandleCounter
= 0 ; HandleCounter
< (BufferSize
/sizeof(EFI_HANDLE
)) ; HandleCounter
++) {
3180 OldProtocolNode
= AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST
));
3181 ASSERT(OldProtocolNode
!= NULL
);
3182 Status
= gBS
->OpenProtocol(Buffer
[HandleCounter
],
3183 &gEfiShellProtocolGuid
,
3184 (VOID
**) &(OldProtocolNode
->Interface
),
3187 EFI_OPEN_PROTOCOL_GET_PROTOCOL
3189 if (!EFI_ERROR(Status
)) {
3191 // reinstall over the old one...
3193 OldProtocolNode
->Handle
= Buffer
[HandleCounter
];
3194 Status
= gBS
->ReinstallProtocolInterface(
3195 OldProtocolNode
->Handle
,
3196 &gEfiShellProtocolGuid
,
3197 OldProtocolNode
->Interface
,
3198 (VOID
*)(&mShellProtocol
));
3199 if (!EFI_ERROR(Status
)) {
3201 // we reinstalled sucessfully. log this so we can reverse it later.
3205 // add to the list for subsequent...
3207 InsertTailList(&ShellInfoObject
.OldShellList
.Link
, &OldProtocolNode
->Link
);
3212 } else if (Status
== EFI_NOT_FOUND
) {
3213 ASSERT(IsListEmpty(&ShellInfoObject
.OldShellList
.Link
));
3215 // no one else published yet. just publish it ourselves.
3217 Status
= gBS
->InstallProtocolInterface (
3219 &gEfiShellProtocolGuid
,
3220 EFI_NATIVE_INTERFACE
,
3221 (VOID
*)(&mShellProtocol
));
3224 if (PcdGetBool(PcdShellSupportOldProtocols
)){
3225 ///@todo support ShellEnvironment2
3226 ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also?
3229 if (!EFI_ERROR(Status
)) {
3230 *NewShell
= &mShellProtocol
;
3236 Opposite of CreatePopulateInstallShellProtocol.
3238 Free all memory and restore the system to the state it was in before calling
3239 CreatePopulateInstallShellProtocol.
3241 @param[in, out] NewShell The pointer to the new shell protocol structure.
3243 @retval EFI_SUCCESS The operation was successful.
3247 CleanUpShellProtocol (
3248 IN OUT EFI_SHELL_PROTOCOL
*NewShell
3252 SHELL_PROTOCOL_HANDLE_LIST
*Node2
;
3253 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleEx
;
3256 // if we need to restore old protocols...
3258 if (!IsListEmpty(&ShellInfoObject
.OldShellList
.Link
)) {
3259 for (Node2
= (SHELL_PROTOCOL_HANDLE_LIST
*)GetFirstNode(&ShellInfoObject
.OldShellList
.Link
)
3260 ; !IsListEmpty (&ShellInfoObject
.OldShellList
.Link
)
3261 ; Node2
= (SHELL_PROTOCOL_HANDLE_LIST
*)GetFirstNode(&ShellInfoObject
.OldShellList
.Link
)
3263 RemoveEntryList(&Node2
->Link
);
3264 Status
= gBS
->ReinstallProtocolInterface(Node2
->Handle
,
3265 &gEfiShellProtocolGuid
,
3272 // no need to restore
3274 Status
= gBS
->UninstallProtocolInterface(gImageHandle
,
3275 &gEfiShellProtocolGuid
,
3278 Status
= gBS
->CloseEvent(NewShell
->ExecutionBreak
);
3279 NewShell
->ExecutionBreak
= NULL
;
3281 Status
= gBS
->OpenProtocol(
3282 gST
->ConsoleInHandle
,
3283 &gEfiSimpleTextInputExProtocolGuid
,
3287 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
3289 if (!EFI_ERROR (Status
)) {
3290 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle1
);
3291 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle2
);
3292 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle3
);
3293 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle4
);
3294 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle1
);
3295 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle2
);
3296 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle3
);
3297 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle4
);
3303 Notification function for keystrokes.
3305 @param[in] KeyData The key that was pressed.
3307 @retval EFI_SUCCESS The operation was successful.
3311 NotificationFunction(
3312 IN EFI_KEY_DATA
*KeyData
3316 if ( ((KeyData
->Key
.UnicodeChar
== L
'c') &&
3317 (KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
) || KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
))) ||
3318 (KeyData
->Key
.UnicodeChar
== 3)
3320 if (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
== NULL
) {
3321 return (EFI_UNSUPPORTED
);
3323 return (gBS
->SignalEvent(ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
));
3324 } else if ((KeyData
->Key
.UnicodeChar
== L
's') &&
3325 (KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
) || KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
))
3327 ShellInfoObject
.HaltOutput
= TRUE
;
3330 // Make sure that there are no pending keystrokes to pervent the pause.
3332 gST
->ConIn
->Reset(gST
->ConIn
, FALSE
);
3333 while (gST
->ConIn
->ReadKeyStroke (gST
->ConIn
, &Key
)==EFI_SUCCESS
);
3335 return (EFI_SUCCESS
);
3339 Function to start monitoring for CTRL-C using SimpleTextInputEx. This
3340 feature's enabled state was not known when the shell initially launched.
3342 @retval EFI_SUCCESS The feature is enabled.
3343 @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.
3347 InernalEfiShellStartMonitor(
3351 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleEx
;
3352 EFI_KEY_DATA KeyData
;
3355 Status
= gBS
->OpenProtocol(
3356 gST
->ConsoleInHandle
,
3357 &gEfiSimpleTextInputExProtocolGuid
,
3361 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
3362 if (EFI_ERROR(Status
)) {
3367 STRING_TOKEN (STR_SHELL_NO_IN_EX
),
3368 ShellInfoObject
.HiiHandle
);
3369 return (EFI_SUCCESS
);
3372 if (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
== NULL
) {
3373 return (EFI_UNSUPPORTED
);
3376 KeyData
.KeyState
.KeyToggleState
= 0;
3377 KeyData
.Key
.ScanCode
= 0;
3378 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
3379 KeyData
.Key
.UnicodeChar
= L
'c';
3381 Status
= SimpleEx
->RegisterKeyNotify(
3384 NotificationFunction
,
3385 &ShellInfoObject
.CtrlCNotifyHandle1
);
3387 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
3388 if (!EFI_ERROR(Status
)) {
3389 Status
= SimpleEx
->RegisterKeyNotify(
3392 NotificationFunction
,
3393 &ShellInfoObject
.CtrlCNotifyHandle2
);
3395 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
3396 KeyData
.Key
.UnicodeChar
= 3;
3397 if (!EFI_ERROR(Status
)) {
3398 Status
= SimpleEx
->RegisterKeyNotify(
3401 NotificationFunction
,
3402 &ShellInfoObject
.CtrlCNotifyHandle3
);
3404 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
3405 if (!EFI_ERROR(Status
)) {
3406 Status
= SimpleEx
->RegisterKeyNotify(
3409 NotificationFunction
,
3410 &ShellInfoObject
.CtrlCNotifyHandle4
);