2 Member functions of EFI_SHELL_PROTOCOL and functions for creation,
3 manipulation, and initialization of EFI_SHELL_PROTOCOL.
5 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
7 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
14 #define INIT_NAME_BUFFER_SIZE 128
17 Close an open file handle.
19 This function closes a specified file handle. All "dirty" cached file data is
20 flushed to the device, and the file is closed. In all cases the handle is
23 @param[in] FileHandle The file handle to close.
25 @retval EFI_SUCCESS The file handle was closed successfully.
30 IN SHELL_FILE_HANDLE FileHandle
33 ShellFileHandleRemove (FileHandle
);
34 return (FileHandleClose (ConvertShellHandleToEfiFileProtocol (FileHandle
)));
38 Internal worker to determine whether there is a BlockIo somewhere
39 upon the device path specified.
41 @param[in] DevicePath The device path to test.
43 @retval TRUE gEfiBlockIoProtocolGuid was installed on a handle with this device path
44 @retval FALSE gEfiBlockIoProtocolGuid was not found.
47 InternalShellProtocolIsBlockIoPresent (
48 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
51 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
57 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
58 Status
= gBS
->LocateDevicePath (&gEfiBlockIoProtocolGuid
, &DevicePathCopy
, &Handle
);
60 if ((Handle
!= NULL
) && (!EFI_ERROR (Status
))) {
68 Internal worker to determine whether there is a file system somewhere
69 upon the device path specified.
71 @param[in] DevicePath The device path to test.
73 @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path
74 @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found.
77 InternalShellProtocolIsSimpleFileSystemPresent (
78 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
81 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
87 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
88 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &Handle
);
90 if ((Handle
!= NULL
) && (!EFI_ERROR (Status
))) {
98 This function creates a mapping for a device path.
100 If both DevicePath and Mapping are NULL, this will reset the mapping to default values.
102 @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping,
103 then the mapping will be deleted.
104 @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':'
106 @retval EFI_SUCCESS Mapping created or deleted successfully.
107 @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the
108 boot service function LocateDevicePath().
109 @retval EFI_ACCESS_DENIED The mapping is a built-in alias.
110 @retval EFI_INVALID_PARAMETER Mapping was NULL
111 @retval EFI_INVALID_PARAMETER Mapping did not end with a ':'
112 @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed.
113 @retval EFI_NOT_FOUND There was no mapping found to delete
114 @retval EFI_OUT_OF_RESOURCES Memory allocation failed
119 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
,
120 IN CONST CHAR16
*Mapping
124 SHELL_MAP_LIST
*MapListNode
;
126 if (Mapping
== NULL
) {
127 return (EFI_INVALID_PARAMETER
);
130 if (Mapping
[StrLen (Mapping
)-1] != ':') {
131 return (EFI_INVALID_PARAMETER
);
135 // Delete the mapping
137 if (DevicePath
== NULL
) {
138 if (IsListEmpty (&gShellMapList
.Link
)) {
139 return (EFI_NOT_FOUND
);
142 for ( MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode (&gShellMapList
.Link
)
143 ; !IsNull (&gShellMapList
.Link
, &MapListNode
->Link
)
144 ; MapListNode
= (SHELL_MAP_LIST
*)GetNextNode (&gShellMapList
.Link
, &MapListNode
->Link
)
147 if (StringNoCaseCompare (&MapListNode
->MapName
, &Mapping
) == 0) {
148 RemoveEntryList (&MapListNode
->Link
);
149 SHELL_FREE_NON_NULL (MapListNode
->DevicePath
);
150 SHELL_FREE_NON_NULL (MapListNode
->MapName
);
151 SHELL_FREE_NON_NULL (MapListNode
->CurrentDirectoryPath
);
152 FreePool (MapListNode
);
153 return (EFI_SUCCESS
);
158 // We didn't find one to delete
160 return (EFI_NOT_FOUND
);
164 // make sure this is a valid to add device path
166 /// @todo add BlockIo to this test...
167 if ( !InternalShellProtocolIsSimpleFileSystemPresent (DevicePath
)
168 && !InternalShellProtocolIsBlockIoPresent (DevicePath
))
170 return (EFI_INVALID_PARAMETER
);
174 // First make sure there is no old mapping
176 Status
= EfiShellSetMap (NULL
, Mapping
);
177 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_FOUND
)) {
182 // now add the new one.
184 Status
= ShellCommandAddMapItemAndUpdatePath (Mapping
, DevicePath
, 0, FALSE
);
190 Gets the device path from the mapping.
192 This function gets the device path associated with a mapping.
194 @param Mapping A pointer to the mapping
196 @retval !=NULL Pointer to the device path that corresponds to the
197 device mapping. The returned pointer does not need
199 @retval NULL There is no device path associated with the
202 CONST EFI_DEVICE_PATH_PROTOCOL
*
204 EfiShellGetDevicePathFromMap (
205 IN CONST CHAR16
*Mapping
208 SHELL_MAP_LIST
*MapListItem
;
215 StrnCatGrow (&NewName
, &Size
, Mapping
, 0);
216 if (Mapping
[StrLen (Mapping
)-1] != L
':') {
217 StrnCatGrow (&NewName
, &Size
, L
":", 0);
220 MapListItem
= ShellCommandFindMapItem (NewName
);
224 if (MapListItem
!= NULL
) {
225 return (MapListItem
->DevicePath
);
232 Gets the mapping(s) that most closely matches the device path.
234 This function gets the mapping which corresponds to the device path *DevicePath. If
235 there is no exact match, then the mapping which most closely matches *DevicePath
236 is returned, and *DevicePath is updated to point to the remaining portion of the
237 device path. If there is an exact match, the mapping is returned and *DevicePath
238 points to the end-of-device-path node.
240 If there are multiple map names they will be semi-colon separated in the
241 NULL-terminated string.
243 @param DevicePath On entry, points to a device path pointer. On
244 exit, updates the pointer to point to the
245 portion of the device path after the mapping.
247 @retval NULL No mapping was found.
248 @return !=NULL Pointer to NULL-terminated mapping. The buffer
249 is callee allocated and should be freed by the caller.
253 EfiShellGetMapFromDevicePath (
254 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
257 SHELL_MAP_LIST
*Node
;
258 CHAR16
*PathForReturn
;
261 // EFI_HANDLE PathHandle;
262 // EFI_HANDLE MapHandle;
263 // EFI_STATUS Status;
264 // EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;
265 // EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;
267 if ((DevicePath
== NULL
) || (*DevicePath
== NULL
)) {
271 PathForReturn
= NULL
;
274 for ( Node
= (SHELL_MAP_LIST
*)GetFirstNode (&gShellMapList
.Link
)
275 ; !IsNull (&gShellMapList
.Link
, &Node
->Link
)
276 ; Node
= (SHELL_MAP_LIST
*)GetNextNode (&gShellMapList
.Link
, &Node
->Link
)
280 // check for exact match
282 if (DevicePathCompare (DevicePath
, &Node
->DevicePath
) == 0) {
283 ASSERT ((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
285 PathForReturn
= StrnCatGrow (&PathForReturn
, &PathSize
, L
";", 0);
288 PathForReturn
= StrnCatGrow (&PathForReturn
, &PathSize
, Node
->MapName
, 0);
292 if (PathForReturn
!= NULL
) {
293 while (!IsDevicePathEndType (*DevicePath
)) {
294 *DevicePath
= NextDevicePathNode (*DevicePath
);
298 // Do not call SetDevicePathEndNode() if the device path node is already the
299 // end of an entire device path.
301 if (!IsDevicePathEnd (*DevicePath
)) {
302 SetDevicePathEndNode (*DevicePath
);
307 ///@todo finish code for inexact matches.
308 if (PathForReturn == NULL) {
311 DevicePathCopy = DuplicateDevicePath(*DevicePath);
312 ASSERT(DevicePathCopy != NULL);
313 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);
314 ASSERT_EFI_ERROR(Status);
316 // check each of the device paths we have to get the root of the path for consist mappings
318 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
319 ; !IsNull(&gShellMapList.Link, &Node->Link)
320 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)
322 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) {
325 MapPathCopy = DuplicateDevicePath(Node->DevicePath);
326 ASSERT(MapPathCopy != NULL);
327 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);
328 if (MapHandle == PathHandle) {
330 *DevicePath = DevicePathCopy;
333 DevicePathCopy = NULL;
334 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);
335 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);
340 // now add on the non-consistent mappings
342 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
343 ; !IsNull(&gShellMapList.Link, &Node->Link)
344 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)
346 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) {
349 MapPathCopy = Node->DevicePath;
350 ASSERT(MapPathCopy != NULL);
351 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);
352 if (MapHandle == PathHandle) {
353 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);
354 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);
361 return (AddBufferToFreeList (PathForReturn
));
365 Converts a device path to a file system-style path.
367 This function converts a device path to a file system path by replacing part, or all, of
368 the device path with the file-system mapping. If there are more than one application
369 file system mappings, the one that most closely matches Path will be used.
371 @param Path The pointer to the device path
373 @retval NULL the device path could not be found.
374 @return all The pointer of the NULL-terminated file path. The path
375 is callee-allocated and should be freed by the caller.
379 EfiShellGetFilePathFromDevicePath (
380 IN CONST EFI_DEVICE_PATH_PROTOCOL
*Path
383 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
384 EFI_DEVICE_PATH_PROTOCOL
*MapPathCopy
;
385 SHELL_MAP_LIST
*MapListItem
;
386 CHAR16
*PathForReturn
;
388 EFI_HANDLE PathHandle
;
389 EFI_HANDLE MapHandle
;
391 FILEPATH_DEVICE_PATH
*FilePath
;
392 FILEPATH_DEVICE_PATH
*AlignedNode
;
394 PathForReturn
= NULL
;
397 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)Path
;
398 ASSERT (DevicePathCopy
!= NULL
);
399 if (DevicePathCopy
== NULL
) {
404 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &PathHandle
);
406 if (EFI_ERROR (Status
)) {
411 // check each of the device paths we have to get the root of the path
413 for ( MapListItem
= (SHELL_MAP_LIST
*)GetFirstNode (&gShellMapList
.Link
)
414 ; !IsNull (&gShellMapList
.Link
, &MapListItem
->Link
)
415 ; MapListItem
= (SHELL_MAP_LIST
*)GetNextNode (&gShellMapList
.Link
, &MapListItem
->Link
)
418 MapPathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)MapListItem
->DevicePath
;
419 ASSERT (MapPathCopy
!= NULL
);
421 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &MapPathCopy
, &MapHandle
);
422 if (MapHandle
== PathHandle
) {
423 ASSERT ((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
424 PathForReturn
= StrnCatGrow (&PathForReturn
, &PathSize
, MapListItem
->MapName
, 0);
426 // go through all the remaining nodes in the device path
428 for ( FilePath
= (FILEPATH_DEVICE_PATH
*)DevicePathCopy
429 ; !IsDevicePathEnd (&FilePath
->Header
)
430 ; FilePath
= (FILEPATH_DEVICE_PATH
*)NextDevicePathNode (&FilePath
->Header
)
434 // If any node is not a file path node, then the conversion can not be completed
436 if ((DevicePathType (&FilePath
->Header
) != MEDIA_DEVICE_PATH
) ||
437 (DevicePathSubType (&FilePath
->Header
) != MEDIA_FILEPATH_DP
))
439 FreePool (PathForReturn
);
444 // append the path part onto the filepath.
446 ASSERT ((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
448 AlignedNode
= AllocateCopyPool (DevicePathNodeLength (FilePath
), FilePath
);
449 if (AlignedNode
== NULL
) {
450 FreePool (PathForReturn
);
454 // File Path Device Path Nodes 'can optionally add a "\" separator to
455 // the beginning and/or the end of the Path Name string.'
456 // (UEFI Spec 2.4 section 9.3.6.4).
457 // If necessary, add a "\", but otherwise don't
458 // (This is specified in the above section, and also implied by the
459 // UEFI Shell spec section 3.7)
460 if ((PathSize
!= 0) &&
461 (PathForReturn
!= NULL
) &&
462 (PathForReturn
[PathSize
/ sizeof (CHAR16
) - 1] != L
'\\') &&
463 (AlignedNode
->PathName
[0] != L
'\\'))
465 PathForReturn
= StrnCatGrow (&PathForReturn
, &PathSize
, L
"\\", 1);
468 PathForReturn
= StrnCatGrow (&PathForReturn
, &PathSize
, AlignedNode
->PathName
, 0);
469 FreePool (AlignedNode
);
470 } // for loop of remaining nodes
473 if (PathForReturn
!= NULL
) {
476 } // for loop of paths to check
478 return (PathForReturn
);
482 Converts a file system style name to a device path.
484 This function converts a file system style name to a device path, by replacing any
485 mapping references to the associated device path.
487 @param[in] Path The pointer to the path.
489 @return The pointer of the file path. The file path is callee
490 allocated and should be freed by the caller.
491 @retval NULL The path could not be found.
492 @retval NULL There was not enough available memory.
494 EFI_DEVICE_PATH_PROTOCOL
*
496 EfiShellGetDevicePathFromFilePath (
497 IN CONST CHAR16
*Path
504 CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
505 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
506 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopyForFree
;
507 EFI_DEVICE_PATH_PROTOCOL
*DevicePathForReturn
;
518 if (StrStr (Path
, L
":") == NULL
) {
519 Cwd
= EfiShellGetCurDir (NULL
);
524 Size
= StrSize (Cwd
) + StrSize (Path
);
525 NewPath
= AllocateZeroPool (Size
);
526 if (NewPath
== NULL
) {
530 StrCpyS (NewPath
, Size
/sizeof (CHAR16
), Cwd
);
531 StrCatS (NewPath
, Size
/sizeof (CHAR16
), L
"\\");
532 if (*Path
== L
'\\') {
534 while (PathRemoveLastItem (NewPath
)) {
538 StrCatS (NewPath
, Size
/sizeof (CHAR16
), Path
);
539 DevicePathForReturn
= EfiShellGetDevicePathFromFilePath (NewPath
);
541 return (DevicePathForReturn
);
546 // find the part before (but including) the : for the map name
548 ASSERT ((MapName
== NULL
&& Size
== 0) || (MapName
!= NULL
));
549 MapName
= StrnCatGrow (&MapName
, &Size
, Path
, (StrStr (Path
, L
":")-Path
+1));
550 if ((MapName
== NULL
) || (MapName
[StrLen (MapName
)-1] != L
':')) {
555 // look up the device path in the map
557 DevicePath
= EfiShellGetDevicePathFromMap (MapName
);
558 if (DevicePath
== NULL
) {
560 // Must have been a bad Mapname
566 // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with)
568 DevicePathCopyForFree
= DevicePathCopy
= DuplicateDevicePath (DevicePath
);
569 if (DevicePathCopy
== NULL
) {
578 Status
= gBS
->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &Handle
);
579 if (EFI_ERROR (Status
)) {
580 if (DevicePathCopyForFree
!= NULL
) {
581 FreePool (DevicePathCopyForFree
);
589 // build the full device path
591 if ((*(Path
+StrLen (MapName
)) != CHAR_NULL
) &&
592 (*(Path
+StrLen (MapName
)+1) == CHAR_NULL
))
594 DevicePathForReturn
= FileDevicePath (Handle
, L
"\\");
596 DevicePathForReturn
= FileDevicePath (Handle
, Path
+StrLen (MapName
));
600 if (DevicePathCopyForFree
!= NULL
) {
601 FreePool (DevicePathCopyForFree
);
604 return (DevicePathForReturn
);
608 Gets the name of the device specified by the device handle.
610 This function gets the user-readable name of the device specified by the device
611 handle. If no user-readable name could be generated, then *BestDeviceName will be
612 NULL and EFI_NOT_FOUND will be returned.
614 If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the
615 device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on
618 If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the
619 device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle.
620 If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and
621 EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then
622 EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority.
624 @param DeviceHandle The handle of the device.
625 @param Flags Determines the possible sources of component names.
627 EFI_DEVICE_NAME_USE_COMPONENT_NAME
628 EFI_DEVICE_NAME_USE_DEVICE_PATH
629 @param Language A pointer to the language specified for the device
630 name, in the same format as described in the UEFI
631 specification, Appendix M
632 @param BestDeviceName On return, points to the callee-allocated NULL-
633 terminated name of the device. If no device name
634 could be found, points to NULL. The name must be
635 freed by the caller...
637 @retval EFI_SUCCESS Get the name successfully.
638 @retval EFI_NOT_FOUND Fail to get the device name.
639 @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set.
640 @retval EFI_INVALID_PARAMETER BestDeviceName was NULL
641 @retval EFI_INVALID_PARAMETER DeviceHandle was NULL
645 EfiShellGetDeviceName (
646 IN EFI_HANDLE DeviceHandle
,
647 IN EFI_SHELL_DEVICE_NAME_FLAGS Flags
,
649 OUT CHAR16
**BestDeviceName
653 EFI_COMPONENT_NAME2_PROTOCOL
*CompName2
;
654 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
655 EFI_HANDLE
*HandleList
;
658 CHAR16
*DeviceNameToReturn
;
660 UINTN ParentControllerCount
;
661 EFI_HANDLE
*ParentControllerBuffer
;
662 UINTN ParentDriverCount
;
663 EFI_HANDLE
*ParentDriverBuffer
;
665 if ((BestDeviceName
== NULL
) ||
666 (DeviceHandle
== NULL
)
669 return (EFI_INVALID_PARAMETER
);
673 // make sure one of the 2 supported bits is on
675 if (((Flags
& EFI_DEVICE_NAME_USE_COMPONENT_NAME
) == 0) &&
676 ((Flags
& EFI_DEVICE_NAME_USE_DEVICE_PATH
) == 0))
678 return (EFI_INVALID_PARAMETER
);
681 DeviceNameToReturn
= NULL
;
682 *BestDeviceName
= NULL
;
687 if ((Flags
& EFI_DEVICE_NAME_USE_COMPONENT_NAME
) != 0) {
688 Status
= ParseHandleDatabaseByRelationship (
691 HR_DRIVER_BINDING_HANDLE
|HR_DEVICE_DRIVER
,
695 for (LoopVar
= 0; LoopVar
< HandleCount
; LoopVar
++) {
697 // Go through those handles until we get one that passes for GetComponentName
699 Status
= gBS
->OpenProtocol (
701 &gEfiComponentName2ProtocolGuid
,
705 EFI_OPEN_PROTOCOL_GET_PROTOCOL
707 if (EFI_ERROR (Status
)) {
708 Status
= gBS
->OpenProtocol (
710 &gEfiComponentNameProtocolGuid
,
714 EFI_OPEN_PROTOCOL_GET_PROTOCOL
718 if (EFI_ERROR (Status
)) {
722 Lang
= GetBestLanguageForDriver (CompName2
->SupportedLanguages
, Language
, FALSE
);
723 Status
= CompName2
->GetControllerName (CompName2
, DeviceHandle
, NULL
, Lang
, &DeviceNameToReturn
);
726 if (!EFI_ERROR (Status
) && (DeviceNameToReturn
!= NULL
)) {
731 if (HandleList
!= NULL
) {
732 FreePool (HandleList
);
736 // Now check the parent controller using this as the child.
738 if (DeviceNameToReturn
== NULL
) {
739 PARSE_HANDLE_DATABASE_PARENTS (DeviceHandle
, &ParentControllerCount
, &ParentControllerBuffer
);
740 for (LoopVar
= 0; LoopVar
< ParentControllerCount
; LoopVar
++) {
741 PARSE_HANDLE_DATABASE_UEFI_DRIVERS (ParentControllerBuffer
[LoopVar
], &ParentDriverCount
, &ParentDriverBuffer
);
742 for (HandleCount
= 0; HandleCount
< ParentDriverCount
; HandleCount
++) {
744 // try using that driver's component name with controller and our driver as the child.
746 Status
= gBS
->OpenProtocol (
747 ParentDriverBuffer
[HandleCount
],
748 &gEfiComponentName2ProtocolGuid
,
752 EFI_OPEN_PROTOCOL_GET_PROTOCOL
754 if (EFI_ERROR (Status
)) {
755 Status
= gBS
->OpenProtocol (
756 ParentDriverBuffer
[HandleCount
],
757 &gEfiComponentNameProtocolGuid
,
761 EFI_OPEN_PROTOCOL_GET_PROTOCOL
765 if (EFI_ERROR (Status
)) {
769 Lang
= GetBestLanguageForDriver (CompName2
->SupportedLanguages
, Language
, FALSE
);
770 Status
= CompName2
->GetControllerName (CompName2
, ParentControllerBuffer
[LoopVar
], DeviceHandle
, Lang
, &DeviceNameToReturn
);
773 if (!EFI_ERROR (Status
) && (DeviceNameToReturn
!= NULL
)) {
778 SHELL_FREE_NON_NULL (ParentDriverBuffer
);
779 if (!EFI_ERROR (Status
) && (DeviceNameToReturn
!= NULL
)) {
784 SHELL_FREE_NON_NULL (ParentControllerBuffer
);
788 // dont return on fail since we will try device path if that bit is on
790 if (DeviceNameToReturn
!= NULL
) {
791 ASSERT (BestDeviceName
!= NULL
);
792 StrnCatGrow (BestDeviceName
, NULL
, DeviceNameToReturn
, 0);
793 return (EFI_SUCCESS
);
797 if ((Flags
& EFI_DEVICE_NAME_USE_DEVICE_PATH
) != 0) {
798 Status
= gBS
->OpenProtocol (
800 &gEfiDevicePathProtocolGuid
,
801 (VOID
**)&DevicePath
,
804 EFI_OPEN_PROTOCOL_GET_PROTOCOL
806 if (!EFI_ERROR (Status
)) {
808 // use device path to text on the device path
810 *BestDeviceName
= ConvertDevicePathToText (DevicePath
, TRUE
, TRUE
);
811 return (EFI_SUCCESS
);
816 // none of the selected bits worked.
818 return (EFI_NOT_FOUND
);
822 Opens the root directory of a device on a handle
824 This function opens the root directory of a device and returns a file handle to it.
826 @param DeviceHandle The handle of the device that contains the volume.
827 @param FileHandle On exit, points to the file handle corresponding to the root directory on the
830 @retval EFI_SUCCESS Root opened successfully.
831 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory
833 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.
834 @retval EFI_DEVICE_ERROR The device had an error.
835 @retval Others Error status returned from EFI_SIMPLE_FILE_SYSTEM_PROTOCOL->OpenVolume().
839 EfiShellOpenRootByHandle (
840 IN EFI_HANDLE DeviceHandle
,
841 OUT SHELL_FILE_HANDLE
*FileHandle
845 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFileSystem
;
846 EFI_FILE_PROTOCOL
*RealFileHandle
;
847 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
850 // get the simple file system interface
852 Status
= gBS
->OpenProtocol (
854 &gEfiSimpleFileSystemProtocolGuid
,
855 (VOID
**)&SimpleFileSystem
,
858 EFI_OPEN_PROTOCOL_GET_PROTOCOL
860 if (EFI_ERROR (Status
)) {
861 return (EFI_NOT_FOUND
);
864 Status
= gBS
->OpenProtocol (
866 &gEfiDevicePathProtocolGuid
,
870 EFI_OPEN_PROTOCOL_GET_PROTOCOL
872 if (EFI_ERROR (Status
)) {
873 return (EFI_NOT_FOUND
);
877 // Open the root volume now...
879 Status
= SimpleFileSystem
->OpenVolume (SimpleFileSystem
, &RealFileHandle
);
880 if (EFI_ERROR (Status
)) {
884 *FileHandle
= ConvertEfiFileProtocolToShellHandle (RealFileHandle
, EfiShellGetMapFromDevicePath (&DevPath
));
885 return (EFI_SUCCESS
);
889 Opens the root directory of a device.
891 This function opens the root directory of a device and returns a file handle to it.
893 @param DevicePath Points to the device path corresponding to the device where the
894 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed.
895 @param FileHandle On exit, points to the file handle corresponding to the root directory on the
898 @retval EFI_SUCCESS Root opened successfully.
899 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory
901 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.
902 @retval EFI_DEVICE_ERROR The device had an error
903 @retval EFI_INVALID_PARAMETER FileHandle is NULL.
908 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
909 OUT SHELL_FILE_HANDLE
*FileHandle
915 if (FileHandle
== NULL
) {
916 return (EFI_INVALID_PARAMETER
);
920 // find the handle of the device with that device handle and the file system
923 Status
= gBS
->LocateDevicePath (
924 &gEfiSimpleFileSystemProtocolGuid
,
928 if (EFI_ERROR (Status
)) {
929 return (EFI_NOT_FOUND
);
932 return (EfiShellOpenRootByHandle (Handle
, FileHandle
));
936 Returns whether any script files are currently being processed.
938 @retval TRUE There is at least one script file active.
939 @retval FALSE No script files are active now.
944 EfiShellBatchIsActive (
948 if (ShellCommandGetCurrentScriptFile () == NULL
) {
956 Worker function to open a file based on a device path. this will open the root
957 of the volume and then traverse down to the file itself.
959 @param DevicePath Device Path of the file.
960 @param FileHandle Pointer to the file upon a successful return.
961 @param OpenMode mode to open file in.
962 @param Attributes the File Attributes to use when creating a new file.
964 @retval EFI_SUCCESS the file is open and FileHandle is valid
965 @retval EFI_UNSUPPORTED the device path contained non-path elements
966 @retval other an error occurred.
969 InternalOpenFileDevicePath (
970 IN OUT EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
971 OUT SHELL_FILE_HANDLE
*FileHandle
,
973 IN UINT64 Attributes OPTIONAL
977 FILEPATH_DEVICE_PATH
*FilePathNode
;
979 SHELL_FILE_HANDLE ShellHandle
;
980 EFI_FILE_PROTOCOL
*Handle1
;
981 EFI_FILE_PROTOCOL
*Handle2
;
982 FILEPATH_DEVICE_PATH
*AlignedNode
;
984 if (FileHandle
== NULL
) {
985 return (EFI_INVALID_PARAMETER
);
996 Status
= EfiShellOpenRoot (DevicePath
, &ShellHandle
);
998 if (!EFI_ERROR (Status
)) {
999 Handle1
= ConvertShellHandleToEfiFileProtocol (ShellHandle
);
1000 if (Handle1
!= NULL
) {
1002 // chop off the beginning part before the file system part...
1005 Status
= gBS
->LocateDevicePath (
1006 &gEfiSimpleFileSystemProtocolGuid
,
1010 if (!EFI_ERROR (Status
)) {
1012 // To access as a file system, the file path should only
1013 // contain file path components. Follow the file path nodes
1014 // and find the target file
1016 for ( FilePathNode
= (FILEPATH_DEVICE_PATH
*)DevicePath
1017 ; !IsDevicePathEnd (&FilePathNode
->Header
)
1018 ; FilePathNode
= (FILEPATH_DEVICE_PATH
*)NextDevicePathNode (&FilePathNode
->Header
)
1021 SHELL_FREE_NON_NULL (AlignedNode
);
1022 AlignedNode
= AllocateCopyPool (DevicePathNodeLength (FilePathNode
), FilePathNode
);
1024 // For file system access each node should be a file path component
1026 if ((DevicePathType (&FilePathNode
->Header
) != MEDIA_DEVICE_PATH
) ||
1027 (DevicePathSubType (&FilePathNode
->Header
) != MEDIA_FILEPATH_DP
)
1030 Status
= EFI_UNSUPPORTED
;
1035 // Open this file path node
1041 // if this is the last node in the DevicePath always create (if that was requested).
1043 if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode
->Header
)))) {
1044 Status
= Handle2
->Open (
1047 AlignedNode
->PathName
,
1053 // This is not the last node and we dont want to 'create' existing
1054 // directory entries...
1058 // open without letting it create
1059 // prevents error on existing files/directories
1061 Status
= Handle2
->Open (
1064 AlignedNode
->PathName
,
1065 OpenMode
&~EFI_FILE_MODE_CREATE
,
1069 // if above failed now open and create the 'item'
1070 // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)
1072 if ((EFI_ERROR (Status
)) && ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0)) {
1073 Status
= Handle2
->Open (
1076 AlignedNode
->PathName
,
1084 // Close the last node
1086 ShellInfoObject
.NewEfiShellProtocol
->CloseFile (Handle2
);
1089 // If there's been an error, stop
1091 if (EFI_ERROR (Status
)) {
1099 SHELL_FREE_NON_NULL (AlignedNode
);
1100 if (EFI_ERROR (Status
)) {
1101 if (Handle1
!= NULL
) {
1102 ShellInfoObject
.NewEfiShellProtocol
->CloseFile (Handle1
);
1105 *FileHandle
= ConvertEfiFileProtocolToShellHandle (Handle1
, ShellFileHandleGetPath (ShellHandle
));
1112 Creates a file or directory by name.
1114 This function creates an empty new file or directory with the specified attributes and
1115 returns the new file's handle. If the file already exists and is read-only, then
1116 EFI_INVALID_PARAMETER will be returned.
1118 If the file already existed, it is truncated and its attributes updated. If the file is
1119 created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL.
1121 If the file name begins with >v, then the file handle which is returned refers to the
1122 shell environment variable with the specified name. If the shell environment variable
1123 already exists and is non-volatile then EFI_INVALID_PARAMETER is returned.
1125 @param FileName Pointer to NULL-terminated file path
1126 @param FileAttribs The new file's attributes. the different attributes are
1127 described in EFI_FILE_PROTOCOL.Open().
1128 @param FileHandle On return, points to the created file handle or directory's handle
1130 @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle.
1131 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1132 @retval EFI_UNSUPPORTED could not open the file path
1133 @retval EFI_NOT_FOUND the specified file could not be found on the device, or could not
1134 file the file system on the device.
1135 @retval EFI_NO_MEDIA the device has no medium.
1136 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
1138 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according
1140 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1141 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write
1142 when the media is write-protected.
1143 @retval EFI_ACCESS_DENIED The service denied access to the file.
1144 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
1145 @retval EFI_VOLUME_FULL The volume is full.
1149 EfiShellCreateFile (
1150 IN CONST CHAR16
*FileName
,
1151 IN UINT64 FileAttribs
,
1152 OUT SHELL_FILE_HANDLE
*FileHandle
1155 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1160 // Is this for an environment variable
1161 // do we start with >v
1163 if (StrStr (FileName
, L
">v") == FileName
) {
1164 Status
= IsVolatileEnv (FileName
+ 2, &Volatile
);
1165 if (EFI_ERROR (Status
)) {
1170 return (EFI_INVALID_PARAMETER
);
1173 *FileHandle
= CreateFileInterfaceEnv (FileName
+2);
1174 return (EFI_SUCCESS
);
1178 // We are opening a regular file.
1180 DevicePath
= EfiShellGetDevicePathFromFilePath (FileName
);
1181 if (DevicePath
== NULL
) {
1182 return (EFI_NOT_FOUND
);
1185 Status
= InternalOpenFileDevicePath (DevicePath
, FileHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_CREATE
, FileAttribs
);
1186 FreePool (DevicePath
);
1192 Register a GUID and a localized human readable name for it.
1194 If Guid is not assigned a name, then assign GuidName to Guid. This list of GUID
1195 names must be used whenever a shell command outputs GUID information.
1197 This function is only available when the major and minor versions in the
1198 EfiShellProtocol are greater than or equal to 2 and 1, respectively.
1200 @param[in] Guid A pointer to the GUID being registered.
1201 @param[in] GuidName A pointer to the localized name for the GUID being registered.
1203 @retval EFI_SUCCESS The operation was successful.
1204 @retval EFI_INVALID_PARAMETER Guid was NULL.
1205 @retval EFI_INVALID_PARAMETER GuidName was NULL.
1206 @retval EFI_ACCESS_DENIED Guid already is assigned a name.
1210 EfiShellRegisterGuidName (
1211 IN CONST EFI_GUID
*Guid
,
1212 IN CONST CHAR16
*GuidName
1215 return (AddNewGuidNameMapping (Guid
, GuidName
, NULL
));
1219 Opens a file or a directory by file name.
1221 This function opens the specified file in the specified OpenMode and returns a file
1223 If the file name begins with >v, then the file handle which is returned refers to the
1224 shell environment variable with the specified name. If the shell environment variable
1225 exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then
1226 EFI_INVALID_PARAMETER is returned.
1228 If the file name is >i, then the file handle which is returned refers to the standard
1229 input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER
1232 If the file name is >o, then the file handle which is returned refers to the standard
1233 output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER
1236 If the file name is >e, then the file handle which is returned refers to the standard
1237 error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER
1240 If the file name is NUL, then the file handle that is returned refers to the standard NUL
1241 file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is
1244 If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the
1247 @param FileName Points to the NULL-terminated UCS-2 encoded file name.
1248 @param FileHandle On return, points to the file handle.
1249 @param OpenMode File open mode. Either EFI_FILE_MODE_READ or
1250 EFI_FILE_MODE_WRITE from section 12.4 of the UEFI
1252 @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle.
1253 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL.
1254 @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL.
1255 @retval EFI_NOT_FOUND The specified file could not be found on the device or the file
1256 system could not be found on the device. FileHandle is NULL.
1257 @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL.
1258 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
1259 longer supported. FileHandle is NULL.
1260 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according
1261 the FileName. FileHandle is NULL.
1262 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL.
1263 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write
1264 when the media is write-protected. FileHandle is NULL.
1265 @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL.
1266 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle
1268 @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL.
1272 EfiShellOpenFileByName (
1273 IN CONST CHAR16
*FileName
,
1274 OUT SHELL_FILE_HANDLE
*FileHandle
,
1278 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1285 // Is this for StdIn
1287 if (StrCmp (FileName
, L
">i") == 0) {
1289 // make sure not writing to StdIn
1291 if ((OpenMode
& EFI_FILE_MODE_WRITE
) != 0) {
1292 return (EFI_INVALID_PARAMETER
);
1295 *FileHandle
= ShellInfoObject
.NewShellParametersProtocol
->StdIn
;
1296 ASSERT (*FileHandle
!= NULL
);
1297 return (EFI_SUCCESS
);
1301 // Is this for StdOut
1303 if (StrCmp (FileName
, L
">o") == 0) {
1305 // make sure not writing to StdIn
1307 if ((OpenMode
& EFI_FILE_MODE_READ
) != 0) {
1308 return (EFI_INVALID_PARAMETER
);
1311 *FileHandle
= &FileInterfaceStdOut
;
1312 return (EFI_SUCCESS
);
1316 // Is this for NUL / NULL file
1318 if ((gUnicodeCollation
->StriColl (gUnicodeCollation
, (CHAR16
*)FileName
, L
"NUL") == 0) ||
1319 (gUnicodeCollation
->StriColl (gUnicodeCollation
, (CHAR16
*)FileName
, L
"NULL") == 0))
1321 *FileHandle
= &FileInterfaceNulFile
;
1322 return (EFI_SUCCESS
);
1326 // Is this for StdErr
1328 if (StrCmp (FileName
, L
">e") == 0) {
1330 // make sure not writing to StdIn
1332 if ((OpenMode
& EFI_FILE_MODE_READ
) != 0) {
1333 return (EFI_INVALID_PARAMETER
);
1336 *FileHandle
= &FileInterfaceStdErr
;
1337 return (EFI_SUCCESS
);
1341 // Is this for an environment variable
1342 // do we start with >v
1344 if (StrStr (FileName
, L
">v") == FileName
) {
1345 Status
= IsVolatileEnv (FileName
+ 2, &Volatile
);
1346 if (EFI_ERROR (Status
)) {
1351 ((OpenMode
& EFI_FILE_MODE_WRITE
) != 0))
1353 return (EFI_INVALID_PARAMETER
);
1356 *FileHandle
= CreateFileInterfaceEnv (FileName
+2);
1357 return (EFI_SUCCESS
);
1361 // We are opening a regular file.
1363 DevicePath
= EfiShellGetDevicePathFromFilePath (FileName
);
1365 if (DevicePath
== NULL
) {
1366 return (EFI_NOT_FOUND
);
1370 // Copy the device path, open the file, then free the memory
1372 Status
= InternalOpenFileDevicePath (DevicePath
, FileHandle
, OpenMode
, 0); // 0 = no specific file attributes
1373 FreePool (DevicePath
);
1379 Deletes the file specified by the file name.
1381 This function deletes a file.
1383 @param FileName Points to the NULL-terminated file name.
1385 @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.
1386 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
1387 @sa EfiShellCreateFile
1391 EfiShellDeleteFileByName (
1392 IN CONST CHAR16
*FileName
1395 SHELL_FILE_HANDLE FileHandle
;
1401 // get a handle to the file
1403 Status
= EfiShellCreateFile (
1408 if (EFI_ERROR (Status
)) {
1413 // now delete the file
1415 ShellFileHandleRemove (FileHandle
);
1416 return (ShellInfoObject
.NewEfiShellProtocol
->DeleteFile (FileHandle
));
1420 Disables the page break output mode.
1424 EfiShellDisablePageBreak (
1428 ShellInfoObject
.PageBreakEnabled
= FALSE
;
1432 Enables the page break output mode.
1436 EfiShellEnablePageBreak (
1440 ShellInfoObject
.PageBreakEnabled
= TRUE
;
1444 internal worker function to load and run an image via device path.
1446 @param ParentImageHandle A handle of the image that is executing the specified
1448 @param DevicePath device path of the file to execute
1449 @param CommandLine Points to the NULL-terminated UCS-2 encoded string
1450 containing the command line. If NULL then the command-
1452 @param Environment Points to a NULL-terminated array of environment
1453 variables with the format 'x=y', where x is the
1454 environment variable name and y is the value. If this
1455 is NULL, then the current shell environment is used.
1457 @param[out] StartImageStatus Returned status from gBS->StartImage.
1459 @retval EFI_SUCCESS The command executed successfully. The status code
1460 returned by the command is pointed to by StatusCode.
1461 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1462 @retval EFI_OUT_OF_RESOURCES Out of resources.
1463 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.
1466 InternalShellExecuteDevicePath (
1467 IN CONST EFI_HANDLE
*ParentImageHandle
,
1468 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1469 IN CONST CHAR16
*CommandLine OPTIONAL
,
1470 IN CONST CHAR16
**Environment OPTIONAL
,
1471 OUT EFI_STATUS
*StartImageStatus OPTIONAL
1475 EFI_STATUS StartStatus
;
1476 EFI_STATUS CleanupStatus
;
1477 EFI_HANDLE NewHandle
;
1478 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1479 LIST_ENTRY OrigEnvs
;
1480 EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol
;
1486 if (ParentImageHandle
== NULL
) {
1487 return (EFI_INVALID_PARAMETER
);
1490 InitializeListHead (&OrigEnvs
);
1491 ZeroMem (&ShellParamsProtocol
, sizeof (EFI_SHELL_PARAMETERS_PROTOCOL
));
1495 NewCmdLine
= AllocateCopyPool (StrSize (CommandLine
), CommandLine
);
1496 if (NewCmdLine
== NULL
) {
1497 return EFI_OUT_OF_RESOURCES
;
1500 for (Walker
= NewCmdLine
; Walker
!= NULL
&& *Walker
!= CHAR_NULL
; Walker
++) {
1501 if ((*Walker
== L
'^') && (*(Walker
+1) == L
'#')) {
1502 CopyMem (Walker
, Walker
+1, StrSize (Walker
) - sizeof (Walker
[0]));
1507 // Load the image with:
1508 // FALSE - not from boot manager and NULL, 0 being not already in memory
1510 Status
= gBS
->LoadImage (
1513 (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
,
1519 if (EFI_ERROR (Status
)) {
1520 if (NewHandle
!= NULL
) {
1521 gBS
->UnloadImage (NewHandle
);
1524 FreePool (NewCmdLine
);
1528 Status
= gBS
->OpenProtocol (
1530 &gEfiLoadedImageProtocolGuid
,
1531 (VOID
**)&LoadedImage
,
1534 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1537 if (!EFI_ERROR (Status
)) {
1539 // If the image is not an app abort it.
1541 if (LoadedImage
->ImageCodeType
!= EfiLoaderCode
) {
1546 STRING_TOKEN (STR_SHELL_IMAGE_NOT_APP
),
1547 ShellInfoObject
.HiiHandle
1552 ASSERT (LoadedImage
->LoadOptionsSize
== 0);
1553 if (NewCmdLine
!= NULL
) {
1554 LoadedImage
->LoadOptionsSize
= (UINT32
)StrSize (NewCmdLine
);
1555 LoadedImage
->LoadOptions
= (VOID
*)NewCmdLine
;
1559 // Save our current environment settings for later restoration if necessary
1561 if (Environment
!= NULL
) {
1562 Status
= GetEnvironmentVariableList (&OrigEnvs
);
1563 if (!EFI_ERROR (Status
)) {
1564 Status
= SetEnvironmentVariables (Environment
);
1569 // Initialize and install a shell parameters protocol on the image.
1571 ShellParamsProtocol
.StdIn
= ShellInfoObject
.NewShellParametersProtocol
->StdIn
;
1572 ShellParamsProtocol
.StdOut
= ShellInfoObject
.NewShellParametersProtocol
->StdOut
;
1573 ShellParamsProtocol
.StdErr
= ShellInfoObject
.NewShellParametersProtocol
->StdErr
;
1574 Status
= UpdateArgcArgv (&ShellParamsProtocol
, NewCmdLine
, Efi_Application
, NULL
, NULL
);
1575 if (EFI_ERROR (Status
)) {
1580 // Replace Argv[0] with the full path of the binary we're executing:
1581 // If the command line was "foo", the binary might be called "foo.efi".
1582 // "The first entry in [Argv] is always the full file path of the
1583 // executable" - UEFI Shell Spec section 2.3
1585 ImagePath
= EfiShellGetFilePathFromDevicePath (DevicePath
);
1586 // The image we're executing isn't necessarily in a filesystem - it might
1587 // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will
1588 // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it.
1589 if (ImagePath
!= NULL
) {
1590 if (ShellParamsProtocol
.Argv
== NULL
) {
1591 // Command line was empty or null.
1592 // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL)
1593 ShellParamsProtocol
.Argv
= AllocatePool (sizeof (CHAR16
*));
1594 if (ShellParamsProtocol
.Argv
== NULL
) {
1595 Status
= EFI_OUT_OF_RESOURCES
;
1599 ShellParamsProtocol
.Argc
= 1;
1601 // Free the string UpdateArgcArgv put in Argv[0];
1602 FreePool (ShellParamsProtocol
.Argv
[0]);
1605 ShellParamsProtocol
.Argv
[0] = ImagePath
;
1608 Status
= gBS
->InstallProtocolInterface (&NewHandle
, &gEfiShellParametersProtocolGuid
, EFI_NATIVE_INTERFACE
, &ShellParamsProtocol
);
1609 ASSERT_EFI_ERROR (Status
);
1611 /// @todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)
1614 // now start the image and if the caller wanted the return code pass it to them...
1616 if (!EFI_ERROR (Status
)) {
1617 StartStatus
= gBS
->StartImage (
1622 if (StartImageStatus
!= NULL
) {
1623 *StartImageStatus
= StartStatus
;
1626 CleanupStatus
= gBS
->UninstallProtocolInterface (
1628 &gEfiShellParametersProtocolGuid
,
1629 &ShellParamsProtocol
1631 ASSERT_EFI_ERROR (CleanupStatus
);
1637 // Unload image - We should only get here if we didn't call StartImage
1638 gBS
->UnloadImage (NewHandle
);
1641 // Free Argv (Allocated in UpdateArgcArgv)
1642 if (ShellParamsProtocol
.Argv
!= NULL
) {
1643 for (Index
= 0; Index
< ShellParamsProtocol
.Argc
; Index
++) {
1644 if (ShellParamsProtocol
.Argv
[Index
] != NULL
) {
1645 FreePool (ShellParamsProtocol
.Argv
[Index
]);
1649 FreePool (ShellParamsProtocol
.Argv
);
1653 // Restore environment variables
1654 if (!IsListEmpty (&OrigEnvs
)) {
1655 CleanupStatus
= SetEnvironmentVariableList (&OrigEnvs
);
1656 ASSERT_EFI_ERROR (CleanupStatus
);
1659 FreePool (NewCmdLine
);
1665 internal worker function to load and run an image in the current shell.
1667 @param CommandLine Points to the NULL-terminated UCS-2 encoded string
1668 containing the command line. If NULL then the command-
1670 @param Environment Points to a NULL-terminated array of environment
1671 variables with the format 'x=y', where x is the
1672 environment variable name and y is the value. If this
1673 is NULL, then the current shell environment is used.
1675 @param[out] StartImageStatus Returned status from the command line.
1677 @retval EFI_SUCCESS The command executed successfully. The status code
1678 returned by the command is pointed to by StatusCode.
1679 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1680 @retval EFI_OUT_OF_RESOURCES Out of resources.
1681 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.
1684 InternalShellExecute (
1685 IN CONST CHAR16
*CommandLine OPTIONAL
,
1686 IN CONST CHAR16
**Environment OPTIONAL
,
1687 OUT EFI_STATUS
*StartImageStatus OPTIONAL
1691 EFI_STATUS CleanupStatus
;
1692 LIST_ENTRY OrigEnvs
;
1694 InitializeListHead (&OrigEnvs
);
1697 // Save our current environment settings for later restoration if necessary
1699 if (Environment
!= NULL
) {
1700 Status
= GetEnvironmentVariableList (&OrigEnvs
);
1701 if (!EFI_ERROR (Status
)) {
1702 Status
= SetEnvironmentVariables (Environment
);
1708 Status
= RunShellCommand (CommandLine
, StartImageStatus
);
1710 // Restore environment variables
1711 if (!IsListEmpty (&OrigEnvs
)) {
1712 CleanupStatus
= SetEnvironmentVariableList (&OrigEnvs
);
1713 ASSERT_EFI_ERROR (CleanupStatus
);
1720 Determine if the UEFI Shell is currently running with nesting enabled or disabled.
1722 @retval FALSE nesting is required
1723 @retval other nesting is enabled
1741 if (ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoNest
) {
1744 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (mNoNestingEnvVarName
, &TempSize
, Temp
);
1745 if (Status
== EFI_BUFFER_TOO_SMALL
) {
1746 Temp
= AllocateZeroPool (TempSize
+ sizeof (CHAR16
));
1748 Status
= SHELL_GET_ENVIRONMENT_VARIABLE (mNoNestingEnvVarName
, &TempSize
, Temp
);
1752 Temp2
= StrnCatGrow (&Temp2
, NULL
, mNoNestingTrue
, 0);
1753 if ((Temp
!= NULL
) && (Temp2
!= NULL
) && (StringNoCaseCompare (&Temp
, &Temp2
) == 0)) {
1755 // Use the no nesting method.
1761 SHELL_FREE_NON_NULL (Temp
);
1762 SHELL_FREE_NON_NULL (Temp2
);
1767 Execute the command line.
1769 This function creates a nested instance of the shell and executes the specified
1770 command (CommandLine) with the specified environment (Environment). Upon return,
1771 the status code returned by the specified command is placed in StatusCode.
1773 If Environment is NULL, then the current environment is used and all changes made
1774 by the commands executed will be reflected in the current environment. If the
1775 Environment is non-NULL, then the changes made will be discarded.
1777 The CommandLine is executed from the current working directory on the current
1780 @param ParentImageHandle A handle of the image that is executing the specified
1782 @param CommandLine Points to the NULL-terminated UCS-2 encoded string
1783 containing the command line. If NULL then the command-
1785 @param Environment Points to a NULL-terminated array of environment
1786 variables with the format 'x=y', where x is the
1787 environment variable name and y is the value. If this
1788 is NULL, then the current shell environment is used.
1789 @param StatusCode Points to the status code returned by the CommandLine.
1791 @retval EFI_SUCCESS The command executed successfully. The status code
1792 returned by the command is pointed to by StatusCode.
1793 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1794 @retval EFI_OUT_OF_RESOURCES Out of resources.
1795 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.
1796 @retval EFI_UNSUPPORTED The support level required for this function is not present.
1798 @sa InternalShellExecuteDevicePath
1803 IN EFI_HANDLE
*ParentImageHandle
,
1804 IN CHAR16
*CommandLine OPTIONAL
,
1805 IN CHAR16
**Environment OPTIONAL
,
1806 OUT EFI_STATUS
*StatusCode OPTIONAL
1811 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1814 if ((PcdGet8 (PcdShellSupportLevel
) < 1)) {
1815 return (EFI_UNSUPPORTED
);
1818 if (NestingEnabled ()) {
1819 DevPath
= AppendDevicePath (ShellInfoObject
.ImageDevPath
, ShellInfoObject
.FileDevPath
);
1821 DEBUG_CODE_BEGIN ();
1822 Temp
= ConvertDevicePathToText (ShellInfoObject
.FileDevPath
, TRUE
, TRUE
);
1824 Temp
= ConvertDevicePathToText (ShellInfoObject
.ImageDevPath
, TRUE
, TRUE
);
1826 Temp
= ConvertDevicePathToText (DevPath
, TRUE
, TRUE
);
1832 ASSERT ((Temp
== NULL
&& Size
== 0) || (Temp
!= NULL
));
1833 StrnCatGrow (&Temp
, &Size
, L
"Shell.efi -exit ", 0);
1834 StrnCatGrow (&Temp
, &Size
, CommandLine
, 0);
1836 Status
= InternalShellExecuteDevicePath (
1840 (CONST CHAR16
**)Environment
,
1845 // de-allocate and return
1850 Status
= InternalShellExecute (
1851 (CONST CHAR16
*)CommandLine
,
1852 (CONST CHAR16
**)Environment
,
1861 Utility cleanup function for EFI_SHELL_FILE_INFO objects.
1863 1) frees all pointers (non-NULL)
1864 2) Closes the SHELL_FILE_HANDLE
1866 @param FileListNode pointer to the list node to free
1869 InternalFreeShellFileInfoNode (
1870 IN EFI_SHELL_FILE_INFO
*FileListNode
1873 if (FileListNode
->Info
!= NULL
) {
1874 FreePool ((VOID
*)FileListNode
->Info
);
1877 if (FileListNode
->FileName
!= NULL
) {
1878 FreePool ((VOID
*)FileListNode
->FileName
);
1881 if (FileListNode
->FullName
!= NULL
) {
1882 FreePool ((VOID
*)FileListNode
->FullName
);
1885 if (FileListNode
->Handle
!= NULL
) {
1886 ShellInfoObject
.NewEfiShellProtocol
->CloseFile (FileListNode
->Handle
);
1889 FreePool (FileListNode
);
1893 Frees the file list.
1895 This function cleans up the file list and any related data structures. It has no
1896 impact on the files themselves.
1898 @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is
1899 defined in OpenFileList()
1901 @retval EFI_SUCCESS Free the file list successfully.
1902 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;
1906 EfiShellFreeFileList (
1907 IN EFI_SHELL_FILE_INFO
**FileList
1910 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1912 if ((FileList
== NULL
) || (*FileList
== NULL
)) {
1913 return (EFI_INVALID_PARAMETER
);
1916 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&(*FileList
)->Link
)
1917 ; !IsListEmpty (&(*FileList
)->Link
)
1918 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&(*FileList
)->Link
)
1921 RemoveEntryList (&ShellFileListItem
->Link
);
1922 InternalFreeShellFileInfoNode (ShellFileListItem
);
1925 InternalFreeShellFileInfoNode (*FileList
);
1927 return (EFI_SUCCESS
);
1931 Deletes the duplicate file names files in the given file list.
1933 This function deletes the reduplicate files in the given file list.
1935 @param FileList A pointer to the first entry in the file list.
1937 @retval EFI_SUCCESS Always success.
1938 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;
1942 EfiShellRemoveDupInFileList (
1943 IN EFI_SHELL_FILE_INFO
**FileList
1947 EFI_SHELL_FILE_INFO
*Duplicates
;
1948 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1949 EFI_SHELL_FILE_INFO
*ShellFileListItem2
;
1950 EFI_SHELL_FILE_INFO
*TempNode
;
1952 if ((FileList
== NULL
) || (*FileList
== NULL
)) {
1953 return (EFI_INVALID_PARAMETER
);
1956 Status
= ShellSortFileList (
1959 ShellSortFileListByFullName
1961 if (!EFI_ERROR (Status
)) {
1962 EfiShellFreeFileList (&Duplicates
);
1967 // Fall back to the slow method that needs no extra memory, and so cannot
1970 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&(*FileList
)->Link
)
1971 ; !IsNull (&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1972 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1975 for ( ShellFileListItem2
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1976 ; !IsNull (&(*FileList
)->Link
, &ShellFileListItem2
->Link
)
1977 ; ShellFileListItem2
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&(*FileList
)->Link
, &ShellFileListItem2
->Link
)
1980 if (gUnicodeCollation
->StriColl (
1982 (CHAR16
*)ShellFileListItem
->FullName
,
1983 (CHAR16
*)ShellFileListItem2
->FullName
1987 TempNode
= (EFI_SHELL_FILE_INFO
*)GetPreviousNode (
1989 &ShellFileListItem2
->Link
1991 RemoveEntryList (&ShellFileListItem2
->Link
);
1992 InternalFreeShellFileInfoNode (ShellFileListItem2
);
1993 // Set ShellFileListItem2 to PreviousNode so we don't access Freed
1994 // memory in GetNextNode in the loop expression above.
1995 ShellFileListItem2
= TempNode
;
2000 return (EFI_SUCCESS
);
2004 // This is the same structure as the external version, but it has no CONST qualifiers.
2007 LIST_ENTRY Link
; ///< Linked list members.
2008 EFI_STATUS Status
; ///< Status of opening the file. Valid only if Handle != NULL.
2009 CHAR16
*FullName
; ///< Fully qualified filename.
2010 CHAR16
*FileName
; ///< name of this file.
2011 SHELL_FILE_HANDLE Handle
; ///< Handle for interacting with the opened file or NULL if closed.
2012 EFI_FILE_INFO
*Info
; ///< Pointer to the FileInfo struct for this file or NULL.
2013 } EFI_SHELL_FILE_INFO_NO_CONST
;
2016 Allocates and duplicates a EFI_SHELL_FILE_INFO node.
2018 @param[in] Node The node to copy from.
2019 @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise.
2021 @retval NULL a memory allocation error occurred
2022 @return != NULL a pointer to the new node
2024 EFI_SHELL_FILE_INFO
*
2025 InternalDuplicateShellFileInfo (
2026 IN EFI_SHELL_FILE_INFO
*Node
,
2030 EFI_SHELL_FILE_INFO_NO_CONST
*NewNode
;
2033 // try to confirm that the objects are in sync
2035 ASSERT (sizeof (EFI_SHELL_FILE_INFO_NO_CONST
) == sizeof (EFI_SHELL_FILE_INFO
));
2037 NewNode
= AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO
));
2038 if (NewNode
== NULL
) {
2042 NewNode
->FullName
= AllocateCopyPool (StrSize (Node
->FullName
), Node
->FullName
);
2043 NewNode
->FileName
= AllocateCopyPool (StrSize (Node
->FileName
), Node
->FileName
);
2044 NewNode
->Info
= AllocateCopyPool ((UINTN
)Node
->Info
->Size
, Node
->Info
);
2045 if ( (NewNode
->FullName
== NULL
)
2046 || (NewNode
->FileName
== NULL
)
2047 || (NewNode
->Info
== NULL
)
2050 SHELL_FREE_NON_NULL (NewNode
->FullName
);
2051 SHELL_FREE_NON_NULL (NewNode
->FileName
);
2052 SHELL_FREE_NON_NULL (NewNode
->Info
);
2053 SHELL_FREE_NON_NULL (NewNode
);
2057 NewNode
->Status
= Node
->Status
;
2058 NewNode
->Handle
= Node
->Handle
;
2060 Node
->Handle
= NULL
;
2063 return ((EFI_SHELL_FILE_INFO
*)NewNode
);
2067 Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation
2068 failed it will return NULL.
2070 @param[in] BasePath the Path to prepend onto filename for FullPath
2071 @param[in] Status Status member initial value.
2072 @param[in] FileName FileName member initial value.
2073 @param[in] Handle Handle member initial value.
2074 @param[in] Info Info struct to copy.
2076 @retval NULL An error occurred.
2077 @return a pointer to the newly allocated structure.
2079 EFI_SHELL_FILE_INFO
*
2080 CreateAndPopulateShellFileInfo (
2081 IN CONST CHAR16
*BasePath
,
2082 IN CONST EFI_STATUS Status
,
2083 IN CONST CHAR16
*FileName
,
2084 IN CONST SHELL_FILE_HANDLE Handle
,
2085 IN CONST EFI_FILE_INFO
*Info
2088 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
2095 ShellFileListItem
= AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO
));
2096 if (ShellFileListItem
== NULL
) {
2100 if ((Info
!= NULL
) && (Info
->Size
!= 0)) {
2101 ShellFileListItem
->Info
= AllocateZeroPool ((UINTN
)Info
->Size
);
2102 if (ShellFileListItem
->Info
== NULL
) {
2103 FreePool (ShellFileListItem
);
2107 CopyMem (ShellFileListItem
->Info
, Info
, (UINTN
)Info
->Size
);
2109 ShellFileListItem
->Info
= NULL
;
2112 if (FileName
!= NULL
) {
2113 ASSERT (TempString
== NULL
);
2114 ShellFileListItem
->FileName
= StrnCatGrow (&TempString
, 0, FileName
, 0);
2115 if (ShellFileListItem
->FileName
== NULL
) {
2116 FreePool (ShellFileListItem
->Info
);
2117 FreePool (ShellFileListItem
);
2121 ShellFileListItem
->FileName
= NULL
;
2126 if (BasePath
!= NULL
) {
2127 ASSERT ((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
2128 TempString
= StrnCatGrow (&TempString
, &Size
, BasePath
, 0);
2129 if (TempString
== NULL
) {
2130 FreePool ((VOID
*)ShellFileListItem
->FileName
);
2131 SHELL_FREE_NON_NULL (ShellFileListItem
->Info
);
2132 FreePool (ShellFileListItem
);
2137 if (ShellFileListItem
->FileName
!= NULL
) {
2138 ASSERT ((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
2139 TempString
= StrnCatGrow (&TempString
, &Size
, ShellFileListItem
->FileName
, 0);
2140 if (TempString
== NULL
) {
2141 FreePool ((VOID
*)ShellFileListItem
->FileName
);
2142 FreePool (ShellFileListItem
->Info
);
2143 FreePool (ShellFileListItem
);
2148 TempString
= PathCleanUpDirectories (TempString
);
2150 ShellFileListItem
->FullName
= TempString
;
2151 ShellFileListItem
->Status
= Status
;
2152 ShellFileListItem
->Handle
= Handle
;
2154 return (ShellFileListItem
);
2158 Find all files in a specified directory.
2160 @param FileDirHandle Handle of the directory to search.
2161 @param FileList On return, points to the list of files in the directory
2162 or NULL if there are no files in the directory.
2164 @retval EFI_SUCCESS File information was returned successfully.
2165 @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted.
2166 @retval EFI_DEVICE_ERROR The device reported an error.
2167 @retval EFI_NO_MEDIA The device media is not present.
2168 @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory.
2169 @return An error from FileHandleGetFileName().
2173 EfiShellFindFilesInDir (
2174 IN SHELL_FILE_HANDLE FileDirHandle
,
2175 OUT EFI_SHELL_FILE_INFO
**FileList
2178 EFI_SHELL_FILE_INFO
*ShellFileList
;
2179 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
2180 EFI_FILE_INFO
*FileInfo
;
2189 Status
= FileHandleGetFileName (FileDirHandle
, &BasePath
);
2190 if (EFI_ERROR (Status
)) {
2194 if (ShellFileHandleGetPath (FileDirHandle
) != NULL
) {
2197 TempString
= StrnCatGrow (&TempString
, &Size
, ShellFileHandleGetPath (FileDirHandle
), 0);
2198 if (TempString
== NULL
) {
2199 SHELL_FREE_NON_NULL (BasePath
);
2200 return (EFI_OUT_OF_RESOURCES
);
2203 TempSpot
= StrStr (TempString
, L
";");
2205 if (TempSpot
!= NULL
) {
2206 *TempSpot
= CHAR_NULL
;
2209 TempString
= StrnCatGrow (&TempString
, &Size
, BasePath
, 0);
2210 if (TempString
== NULL
) {
2211 SHELL_FREE_NON_NULL (BasePath
);
2212 return (EFI_OUT_OF_RESOURCES
);
2215 SHELL_FREE_NON_NULL (BasePath
);
2216 BasePath
= TempString
;
2220 ShellFileList
= NULL
;
2221 ShellFileListItem
= NULL
;
2223 Status
= EFI_SUCCESS
;
2225 for ( Status
= FileHandleFindFirstFile (FileDirHandle
, &FileInfo
)
2226 ; !EFI_ERROR (Status
) && !NoFile
2227 ; Status
= FileHandleFindNextFile (FileDirHandle
, FileInfo
, &NoFile
)
2230 if (ShellFileList
== NULL
) {
2231 ShellFileList
= (EFI_SHELL_FILE_INFO
*)AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO
));
2232 if (ShellFileList
== NULL
) {
2233 SHELL_FREE_NON_NULL (BasePath
);
2234 return EFI_OUT_OF_RESOURCES
;
2237 InitializeListHead (&ShellFileList
->Link
);
2241 // allocate a new EFI_SHELL_FILE_INFO and populate it...
2243 ShellFileListItem
= CreateAndPopulateShellFileInfo (
2245 EFI_SUCCESS
, // success since we didn't fail to open it...
2247 NULL
, // no handle since not open
2250 if (ShellFileListItem
== NULL
) {
2251 Status
= EFI_OUT_OF_RESOURCES
;
2253 // Free resources outside the loop.
2258 InsertTailList (&ShellFileList
->Link
, &ShellFileListItem
->Link
);
2261 if (EFI_ERROR (Status
)) {
2262 EfiShellFreeFileList (&ShellFileList
);
2265 *FileList
= ShellFileList
;
2268 SHELL_FREE_NON_NULL (BasePath
);
2273 Get the GUID value from a human readable name.
2275 If GuidName is a known GUID name, then update Guid to have the correct value for
2278 This function is only available when the major and minor versions in the
2279 EfiShellProtocol are greater than or equal to 2 and 1, respectively.
2281 @param[in] GuidName A pointer to the localized name for the GUID being queried.
2282 @param[out] Guid A pointer to the GUID structure to be filled in.
2284 @retval EFI_SUCCESS The operation was successful.
2285 @retval EFI_INVALID_PARAMETER Guid was NULL.
2286 @retval EFI_INVALID_PARAMETER GuidName was NULL.
2287 @retval EFI_NOT_FOUND GuidName is not a known GUID Name.
2291 EfiShellGetGuidFromName (
2292 IN CONST CHAR16
*GuidName
,
2299 if ((Guid
== NULL
) || (GuidName
== NULL
)) {
2300 return (EFI_INVALID_PARAMETER
);
2303 Status
= GetGuidFromStringName (GuidName
, NULL
, &NewGuid
);
2305 if (!EFI_ERROR (Status
)) {
2306 CopyGuid (Guid
, NewGuid
);
2313 Get the human readable name for a GUID from the value.
2315 If Guid is assigned a name, then update *GuidName to point to the name. The callee
2316 should not modify the value.
2318 This function is only available when the major and minor versions in the
2319 EfiShellProtocol are greater than or equal to 2 and 1, respectively.
2321 @param[in] Guid A pointer to the GUID being queried.
2322 @param[out] GuidName A pointer to a pointer the localized to name for the GUID being requested
2324 @retval EFI_SUCCESS The operation was successful.
2325 @retval EFI_INVALID_PARAMETER Guid was NULL.
2326 @retval EFI_INVALID_PARAMETER GuidName was NULL.
2327 @retval EFI_NOT_FOUND Guid is not assigned a name.
2331 EfiShellGetGuidName (
2332 IN CONST EFI_GUID
*Guid
,
2333 OUT CONST CHAR16
**GuidName
2338 if ((Guid
== NULL
) || (GuidName
== NULL
)) {
2339 return (EFI_INVALID_PARAMETER
);
2342 Name
= GetStringNameFromGuid (Guid
, NULL
);
2343 if ((Name
== NULL
) || (StrLen (Name
) == 0)) {
2344 SHELL_FREE_NON_NULL (Name
);
2345 return (EFI_NOT_FOUND
);
2348 *GuidName
= AddBufferToFreeList (Name
);
2350 return (EFI_SUCCESS
);
2354 If FileHandle is a directory then the function reads from FileHandle and reads in
2355 each of the FileInfo structures. If one of them matches the Pattern's first
2356 "level" then it opens that handle and calls itself on that handle.
2358 If FileHandle is a file and matches all of the remaining Pattern (which would be
2359 on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.
2361 Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call
2362 FreeFileList with FileList.
2364 @param[in] FilePattern The FilePattern to check against.
2365 @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure
2366 @param[in] FileHandle The FileHandle to start with
2367 @param[in, out] FileList pointer to pointer to list of found files.
2368 @param[in] ParentNode The node for the parent. Same file as identified by HANDLE.
2369 @param[in] MapName The file system name this file is on.
2371 @retval EFI_SUCCESS all files were found and the FileList contains a list.
2372 @retval EFI_NOT_FOUND no files were found
2373 @retval EFI_OUT_OF_RESOURCES a memory allocation failed
2377 IN CONST CHAR16
*FilePattern
,
2378 IN EFI_UNICODE_COLLATION_PROTOCOL
*UnicodeCollation
,
2379 IN SHELL_FILE_HANDLE FileHandle
,
2380 IN OUT EFI_SHELL_FILE_INFO
**FileList
,
2381 IN CONST EFI_SHELL_FILE_INFO
*ParentNode OPTIONAL
,
2382 IN CONST CHAR16
*MapName
2386 CONST CHAR16
*NextFilePatternStart
;
2387 CHAR16
*CurrentFilePattern
;
2388 EFI_SHELL_FILE_INFO
*ShellInfo
;
2389 EFI_SHELL_FILE_INFO
*ShellInfoNode
;
2390 EFI_SHELL_FILE_INFO
*NewShellNode
;
2391 EFI_FILE_INFO
*FileInfo
;
2393 CHAR16
*NewFullName
;
2396 if ( (FilePattern
== NULL
)
2397 || (UnicodeCollation
== NULL
)
2398 || (FileList
== NULL
)
2401 return (EFI_INVALID_PARAMETER
);
2405 CurrentFilePattern
= NULL
;
2407 if (*FilePattern
== L
'\\') {
2411 for ( NextFilePatternStart
= FilePattern
2412 ; *NextFilePatternStart
!= CHAR_NULL
&& *NextFilePatternStart
!= L
'\\'
2413 ; NextFilePatternStart
++)
2417 CurrentFilePattern
= AllocateZeroPool ((NextFilePatternStart
-FilePattern
+1)*sizeof (CHAR16
));
2418 if (CurrentFilePattern
== NULL
) {
2419 return EFI_OUT_OF_RESOURCES
;
2422 StrnCpyS (CurrentFilePattern
, NextFilePatternStart
-FilePattern
+1, FilePattern
, NextFilePatternStart
-FilePattern
);
2424 if ( (CurrentFilePattern
[0] == CHAR_NULL
)
2425 && (NextFilePatternStart
[0] == CHAR_NULL
)
2429 // we want the parent or root node (if no parent)
2431 if (ParentNode
== NULL
) {
2433 // We want the root node. create the node.
2435 FileInfo
= FileHandleGetInfo (FileHandle
);
2436 NewShellNode
= CreateAndPopulateShellFileInfo (
2443 SHELL_FREE_NON_NULL (FileInfo
);
2446 // Add the current parameter FileHandle to the list, then end...
2448 NewShellNode
= InternalDuplicateShellFileInfo ((EFI_SHELL_FILE_INFO
*)ParentNode
, TRUE
);
2451 if (NewShellNode
== NULL
) {
2452 Status
= EFI_OUT_OF_RESOURCES
;
2454 NewShellNode
->Handle
= NULL
;
2455 if (*FileList
== NULL
) {
2456 *FileList
= AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO
));
2457 InitializeListHead (&((*FileList
)->Link
));
2461 // Add to the returning to use list
2463 InsertTailList (&(*FileList
)->Link
, &NewShellNode
->Link
);
2465 Status
= EFI_SUCCESS
;
2468 Status
= EfiShellFindFilesInDir (FileHandle
, &ShellInfo
);
2470 if (!EFI_ERROR (Status
)) {
2471 if (StrStr (NextFilePatternStart
, L
"\\") != NULL
) {
2477 for ( ShellInfoNode
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&ShellInfo
->Link
)
2478 ; !IsNull (&ShellInfo
->Link
, &ShellInfoNode
->Link
)
2479 ; ShellInfoNode
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&ShellInfo
->Link
, &ShellInfoNode
->Link
)
2482 if (UnicodeCollation
->MetaiMatch (UnicodeCollation
, (CHAR16
*)ShellInfoNode
->FileName
, CurrentFilePattern
)) {
2483 if ((ShellInfoNode
->FullName
!= NULL
) && (StrStr (ShellInfoNode
->FullName
, L
":") == NULL
)) {
2484 Size
= StrSize (ShellInfoNode
->FullName
) + StrSize (MapName
);
2485 NewFullName
= AllocateZeroPool (Size
);
2486 if (NewFullName
== NULL
) {
2487 Status
= EFI_OUT_OF_RESOURCES
;
2489 StrCpyS (NewFullName
, Size
/ sizeof (CHAR16
), MapName
);
2490 StrCatS (NewFullName
, Size
/ sizeof (CHAR16
), ShellInfoNode
->FullName
);
2491 FreePool ((VOID
*)ShellInfoNode
->FullName
);
2492 ShellInfoNode
->FullName
= NewFullName
;
2496 if (Directory
&& !EFI_ERROR (Status
) && (ShellInfoNode
->FullName
!= NULL
) && (ShellInfoNode
->FileName
!= NULL
)) {
2498 // should be a directory
2502 // don't open the . and .. directories
2504 if ( (StrCmp (ShellInfoNode
->FileName
, L
".") != 0)
2505 && (StrCmp (ShellInfoNode
->FileName
, L
"..") != 0)
2511 if (EFI_ERROR (Status
)) {
2516 // Open the directory since we need that handle in the next recursion.
2518 ShellInfoNode
->Status
= EfiShellOpenFileByName (ShellInfoNode
->FullName
, &ShellInfoNode
->Handle
, EFI_FILE_MODE_READ
);
2521 // recurse with the next part of the pattern
2523 Status
= ShellSearchHandle (NextFilePatternStart
, UnicodeCollation
, ShellInfoNode
->Handle
, FileList
, ShellInfoNode
, MapName
);
2524 EfiShellClose (ShellInfoNode
->Handle
);
2525 ShellInfoNode
->Handle
= NULL
;
2527 } else if (!EFI_ERROR (Status
)) {
2533 // copy the information we need into a new Node
2535 NewShellNode
= InternalDuplicateShellFileInfo (ShellInfoNode
, FALSE
);
2536 if (NewShellNode
== NULL
) {
2537 Status
= EFI_OUT_OF_RESOURCES
;
2540 if (*FileList
== NULL
) {
2541 *FileList
= AllocateZeroPool (sizeof (EFI_SHELL_FILE_INFO
));
2542 InitializeListHead (&((*FileList
)->Link
));
2546 // Add to the returning to use list
2548 InsertTailList (&(*FileList
)->Link
, &NewShellNode
->Link
);
2552 if (EFI_ERROR (Status
)) {
2557 if (EFI_ERROR (Status
)) {
2558 EfiShellFreeFileList (&ShellInfo
);
2560 Status
= EfiShellFreeFileList (&ShellInfo
);
2565 if ((*FileList
== NULL
) || ((*FileList
!= NULL
) && IsListEmpty (&(*FileList
)->Link
))) {
2566 Status
= EFI_NOT_FOUND
;
2569 FreePool (CurrentFilePattern
);
2574 Find files that match a specified pattern.
2576 This function searches for all files and directories that match the specified
2577 FilePattern. The FilePattern can contain wild-card characters. The resulting file
2578 information is placed in the file list FileList.
2580 Wildcards are processed
2581 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1.
2583 The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo
2584 field is set to NULL.
2586 if *FileList is not NULL then it must be a pre-existing and properly initialized list.
2588 @param FilePattern Points to a NULL-terminated shell file path, including wildcards.
2589 @param FileList On return, points to the start of a file list containing the names
2590 of all matching files or else points to NULL if no matching files
2591 were found. only on a EFI_SUCCESS return will; this be non-NULL.
2593 @retval EFI_SUCCESS Files found. FileList is a valid list.
2594 @retval EFI_NOT_FOUND No files found.
2595 @retval EFI_NO_MEDIA The device has no media
2596 @retval EFI_DEVICE_ERROR The device reported an error
2597 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted
2602 IN CONST CHAR16
*FilePattern
,
2603 OUT EFI_SHELL_FILE_INFO
**FileList
2607 CHAR16
*PatternCopy
;
2608 CHAR16
*PatternCurrentLocation
;
2609 EFI_DEVICE_PATH_PROTOCOL
*RootDevicePath
;
2610 SHELL_FILE_HANDLE RootFileHandle
;
2614 if ( (FilePattern
== NULL
)
2615 || (FileList
== NULL
)
2616 || (StrStr (FilePattern
, L
":") == NULL
)
2619 return (EFI_INVALID_PARAMETER
);
2622 Status
= EFI_SUCCESS
;
2623 RootDevicePath
= NULL
;
2624 RootFileHandle
= NULL
;
2626 PatternCopy
= AllocateCopyPool (StrSize (FilePattern
), FilePattern
);
2627 if (PatternCopy
== NULL
) {
2628 return (EFI_OUT_OF_RESOURCES
);
2631 PatternCopy
= PathCleanUpDirectories (PatternCopy
);
2633 Count
= StrStr (PatternCopy
, L
":") - PatternCopy
+ 1;
2634 ASSERT (Count
<= StrLen (PatternCopy
));
2636 ASSERT (MapName
== NULL
);
2637 MapName
= StrnCatGrow (&MapName
, NULL
, PatternCopy
, Count
);
2638 if (MapName
== NULL
) {
2639 Status
= EFI_OUT_OF_RESOURCES
;
2641 RootDevicePath
= EfiShellGetDevicePathFromFilePath (PatternCopy
);
2642 if (RootDevicePath
== NULL
) {
2643 Status
= EFI_INVALID_PARAMETER
;
2645 Status
= EfiShellOpenRoot (RootDevicePath
, &RootFileHandle
);
2646 if (!EFI_ERROR (Status
)) {
2647 for ( PatternCurrentLocation
= PatternCopy
2648 ; *PatternCurrentLocation
!= ':'
2649 ; PatternCurrentLocation
++)
2653 PatternCurrentLocation
++;
2654 Status
= ShellSearchHandle (PatternCurrentLocation
, gUnicodeCollation
, RootFileHandle
, FileList
, NULL
, MapName
);
2655 EfiShellClose (RootFileHandle
);
2658 FreePool (RootDevicePath
);
2662 SHELL_FREE_NON_NULL (PatternCopy
);
2663 SHELL_FREE_NON_NULL (MapName
);
2669 Opens the files that match the path specified.
2671 This function opens all of the files specified by Path. Wildcards are processed
2672 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each
2673 matching file has an EFI_SHELL_FILE_INFO structure created in a linked list.
2675 @param Path A pointer to the path string.
2676 @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or
2677 EFI_FILE_MODE_WRITE.
2678 @param FileList Points to the start of a list of files opened.
2680 @retval EFI_SUCCESS Create the file list successfully.
2681 @return Others Can't create the file list.
2685 EfiShellOpenFileList (
2688 IN OUT EFI_SHELL_FILE_INFO
**FileList
2692 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
2695 CONST CHAR16
*CurDir
;
2698 PathCleanUpDirectories (Path
);
2703 if ((FileList
== NULL
) || (*FileList
== NULL
)) {
2704 return (EFI_INVALID_PARAMETER
);
2707 if ((*Path
== L
'.') && (*(Path
+1) == L
'\\')) {
2712 // convert a local path to an absolute path
2714 if (StrStr (Path
, L
":") == NULL
) {
2715 CurDir
= EfiShellGetCurDir (NULL
);
2716 ASSERT ((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
2717 StrnCatGrow (&Path2
, &Path2Size
, CurDir
, 0);
2718 StrnCatGrow (&Path2
, &Path2Size
, L
"\\", 0);
2719 if (*Path
== L
'\\') {
2721 while (PathRemoveLastItem (Path2
)) {
2725 ASSERT ((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
2726 StrnCatGrow (&Path2
, &Path2Size
, Path
, 0);
2728 ASSERT (Path2
== NULL
);
2729 StrnCatGrow (&Path2
, NULL
, Path
, 0);
2732 PathCleanUpDirectories (Path2
);
2737 Status
= EfiShellFindFiles (Path2
, FileList
);
2741 if (EFI_ERROR (Status
)) {
2747 // We had no errors so open all the files (that are not already opened...)
2749 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode (&(*FileList
)->Link
)
2750 ; !IsNull (&(*FileList
)->Link
, &ShellFileListItem
->Link
)
2751 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetNextNode (&(*FileList
)->Link
, &ShellFileListItem
->Link
)
2754 if ((ShellFileListItem
->Status
== 0) && (ShellFileListItem
->Handle
== NULL
)) {
2755 ShellFileListItem
->Status
= EfiShellOpenFileByName (ShellFileListItem
->FullName
, &ShellFileListItem
->Handle
, OpenMode
);
2761 return (EFI_NOT_FOUND
);
2764 return (EFI_SUCCESS
);
2768 Gets the environment variable and Attributes, or list of environment variables. Can be
2769 used instead of GetEnv().
2771 This function returns the current value of the specified environment variable and
2772 the Attributes. If no variable name was specified, then all of the known
2773 variables will be returned.
2775 @param[in] Name A pointer to the environment variable name. If Name is NULL,
2776 then the function will return all of the defined shell
2777 environment variables. In the case where multiple environment
2778 variables are being returned, each variable will be terminated
2779 by a NULL, and the list will be terminated by a double NULL.
2780 @param[out] Attributes If not NULL, a pointer to the returned attributes bitmask for
2781 the environment variable. In the case where Name is NULL, and
2782 multiple environment variables are being returned, Attributes
2785 @retval NULL The environment variable doesn't exist.
2786 @return A non-NULL value points to the variable's value. The returned
2787 pointer does not need to be freed by the caller.
2792 IN CONST CHAR16
*Name
,
2793 OUT UINT32
*Attributes OPTIONAL
2800 CHAR16
*CurrentWriteLocation
;
2807 // Build the semi-colon delimited list. (2 passes)
2809 for ( Node
= (ENV_VAR_LIST
*)GetFirstNode (&gShellEnvVarList
.Link
)
2810 ; !IsNull (&gShellEnvVarList
.Link
, &Node
->Link
)
2811 ; Node
= (ENV_VAR_LIST
*)GetNextNode (&gShellEnvVarList
.Link
, &Node
->Link
)
2814 ASSERT (Node
->Key
!= NULL
);
2815 Size
+= StrSize (Node
->Key
);
2818 Size
+= 2*sizeof (CHAR16
);
2820 Buffer
= AllocateZeroPool (Size
);
2821 if (Buffer
== NULL
) {
2825 CurrentWriteLocation
= (CHAR16
*)Buffer
;
2827 for ( Node
= (ENV_VAR_LIST
*)GetFirstNode (&gShellEnvVarList
.Link
)
2828 ; !IsNull (&gShellEnvVarList
.Link
, &Node
->Link
)
2829 ; Node
= (ENV_VAR_LIST
*)GetNextNode (&gShellEnvVarList
.Link
, &Node
->Link
)
2832 ASSERT (Node
->Key
!= NULL
);
2834 CurrentWriteLocation
,
2835 (Size
)/sizeof (CHAR16
) - (CurrentWriteLocation
- ((CHAR16
*)Buffer
)),
2838 CurrentWriteLocation
+= StrLen (CurrentWriteLocation
) + 1;
2842 // We are doing a specific environment variable
2844 Status
= ShellFindEnvVarInList (Name
, (CHAR16
**)&Buffer
, &Size
, Attributes
);
2846 if (EFI_ERROR (Status
)) {
2848 // get the size we need for this EnvVariable
2850 Status
= SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES (Name
, Attributes
, &Size
, Buffer
);
2851 if (Status
== EFI_BUFFER_TOO_SMALL
) {
2853 // Allocate the space and recall the get function
2855 Buffer
= AllocateZeroPool (Size
);
2856 Status
= SHELL_GET_ENVIRONMENT_VARIABLE_AND_ATTRIBUTES (Name
, Attributes
, &Size
, Buffer
);
2860 // we didn't get it (might not exist)
2861 // free the memory if we allocated any and return NULL
2863 if (EFI_ERROR (Status
)) {
2864 if (Buffer
!= NULL
) {
2871 // If we did not find the environment variable in the gShellEnvVarList
2872 // but get it from UEFI variable storage successfully then we need update
2873 // the gShellEnvVarList.
2875 ShellFreeEnvVarList ();
2876 Status
= ShellInitEnvVarList ();
2877 ASSERT (Status
== EFI_SUCCESS
);
2883 // return the buffer
2885 return (AddBufferToFreeList (Buffer
));
2889 Gets either a single or list of environment variables.
2891 If name is not NULL then this function returns the current value of the specified
2892 environment variable.
2894 If Name is NULL, then a list of all environment variable names is returned. Each is a
2895 NULL terminated string with a double NULL terminating the list.
2897 @param Name A pointer to the environment variable name. If
2898 Name is NULL, then the function will return all
2899 of the defined shell environment variables. In
2900 the case where multiple environment variables are
2901 being returned, each variable will be terminated by
2902 a NULL, and the list will be terminated by a double
2905 @retval !=NULL A pointer to the returned string.
2906 The returned pointer does not need to be freed by the caller.
2908 @retval NULL The environment variable doesn't exist or there are
2909 no environment variables.
2914 IN CONST CHAR16
*Name
2917 return (EfiShellGetEnvEx (Name
, NULL
));
2921 Internal variable setting function. Allows for setting of the read only variables.
2923 @param Name Points to the NULL-terminated environment variable name.
2924 @param Value Points to the NULL-terminated environment variable value. If the value is an
2925 empty string then the environment variable is deleted.
2926 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
2928 @retval EFI_SUCCESS The environment variable was successfully updated.
2931 InternalEfiShellSetEnv (
2932 IN CONST CHAR16
*Name
,
2933 IN CONST CHAR16
*Value
,
2939 if ((Value
== NULL
) || (StrLen (Value
) == 0)) {
2940 Status
= SHELL_DELETE_ENVIRONMENT_VARIABLE (Name
);
2941 if (!EFI_ERROR (Status
)) {
2942 ShellRemvoeEnvVarFromList (Name
);
2945 SHELL_DELETE_ENVIRONMENT_VARIABLE (Name
);
2946 Status
= ShellAddEnvVarToList (
2950 EFI_VARIABLE_BOOTSERVICE_ACCESS
| (Volatile
? 0 : EFI_VARIABLE_NON_VOLATILE
)
2952 if (!EFI_ERROR (Status
)) {
2954 ? SHELL_SET_ENVIRONMENT_VARIABLE_V (Name
, StrSize (Value
) - sizeof (CHAR16
), Value
)
2955 : SHELL_SET_ENVIRONMENT_VARIABLE_NV (Name
, StrSize (Value
) - sizeof (CHAR16
), Value
);
2956 if (EFI_ERROR (Status
)) {
2957 ShellRemvoeEnvVarFromList (Name
);
2966 Sets the environment variable.
2968 This function changes the current value of the specified environment variable. If the
2969 environment variable exists and the Value is an empty string, then the environment
2970 variable is deleted. If the environment variable exists and the Value is not an empty
2971 string, then the value of the environment variable is changed. If the environment
2972 variable does not exist and the Value is an empty string, there is no action. If the
2973 environment variable does not exist and the Value is a non-empty string, then the
2974 environment variable is created and assigned the specified value.
2976 For a description of volatile and non-volatile environment variables, see UEFI Shell
2977 2.0 specification section 3.6.1.
2979 @param Name Points to the NULL-terminated environment variable name.
2980 @param Value Points to the NULL-terminated environment variable value. If the value is an
2981 empty string then the environment variable is deleted.
2982 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
2984 @retval EFI_SUCCESS The environment variable was successfully updated.
2989 IN CONST CHAR16
*Name
,
2990 IN CONST CHAR16
*Value
,
2994 if ((Name
== NULL
) || (*Name
== CHAR_NULL
)) {
2995 return (EFI_INVALID_PARAMETER
);
2999 // Make sure we dont 'set' a predefined read only variable
3001 if ((StrCmp (Name
, L
"cwd") == 0) ||
3002 (StrCmp (Name
, L
"lasterror") == 0) ||
3003 (StrCmp (Name
, L
"profiles") == 0) ||
3004 (StrCmp (Name
, L
"uefishellsupport") == 0) ||
3005 (StrCmp (Name
, L
"uefishellversion") == 0) ||
3006 (StrCmp (Name
, L
"uefiversion") == 0) ||
3007 (!ShellInfoObject
.ShellInitSettings
.BitUnion
.Bits
.NoNest
&&
3008 (StrCmp (Name
, mNoNestingEnvVarName
) == 0))
3011 return (EFI_INVALID_PARAMETER
);
3014 return (InternalEfiShellSetEnv (Name
, Value
, Volatile
));
3018 Returns the current directory on the specified device.
3020 If FileSystemMapping is NULL, it returns the current working directory. If the
3021 FileSystemMapping is not NULL, it returns the current directory associated with the
3022 FileSystemMapping. In both cases, the returned name includes the file system
3023 mapping (i.e. fs0:\current-dir).
3025 Note that the current directory string should exclude the tailing backslash character.
3027 @param FileSystemMapping A pointer to the file system mapping. If NULL,
3028 then the current working directory is returned.
3030 @retval !=NULL The current directory.
3031 @retval NULL Current directory does not exist.
3036 IN CONST CHAR16
*FileSystemMapping OPTIONAL
3039 CHAR16
*PathToReturn
;
3041 SHELL_MAP_LIST
*MapListItem
;
3043 if (!IsListEmpty (&gShellMapList
.Link
)) {
3045 // if parameter is NULL, use current
3047 if (FileSystemMapping
== NULL
) {
3048 return (EfiShellGetEnv (L
"cwd"));
3051 PathToReturn
= NULL
;
3052 MapListItem
= ShellCommandFindMapItem (FileSystemMapping
);
3053 if (MapListItem
!= NULL
) {
3054 ASSERT ((PathToReturn
== NULL
&& Size
== 0) || (PathToReturn
!= NULL
));
3055 PathToReturn
= StrnCatGrow (&PathToReturn
, &Size
, MapListItem
->MapName
, 0);
3056 PathToReturn
= StrnCatGrow (&PathToReturn
, &Size
, MapListItem
->CurrentDirectoryPath
, 0);
3060 return (AddBufferToFreeList (PathToReturn
));
3067 Changes the current directory on the specified device.
3069 If the FileSystem is NULL, and the directory Dir does not contain a file system's
3070 mapped name, this function changes the current working directory.
3072 If the FileSystem is NULL and the directory Dir contains a mapped name, then the
3073 current file system and the current directory on that file system are changed.
3075 If FileSystem is NULL, and Dir is not NULL, then this changes the current working file
3078 If FileSystem is not NULL and Dir is not NULL, then this function changes the current
3079 directory on the specified file system.
3081 If the current working directory or the current working file system is changed then the
3082 %cwd% environment variable will be updated
3084 Note that the current directory string should exclude the tailing backslash character.
3086 @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working
3087 directory is changed.
3088 @param Dir Points to the NULL-terminated directory on the device specified by FileSystem.
3090 @retval EFI_SUCCESS The operation was successful
3091 @retval EFI_NOT_FOUND The file system could not be found
3096 IN CONST CHAR16
*FileSystem OPTIONAL
,
3097 IN CONST CHAR16
*Dir
3101 SHELL_MAP_LIST
*MapListItem
;
3105 CHAR16
*DirectoryName
;
3112 DirectoryName
= NULL
;
3114 if (((FileSystem
== NULL
) && (Dir
== NULL
)) || (Dir
== NULL
)) {
3115 return (EFI_INVALID_PARAMETER
);
3118 if (IsListEmpty (&gShellMapList
.Link
)) {
3119 return (EFI_NOT_FOUND
);
3122 DirectoryName
= StrnCatGrow (&DirectoryName
, NULL
, Dir
, 0);
3123 ASSERT (DirectoryName
!= NULL
);
3125 PathCleanUpDirectories (DirectoryName
);
3127 if (FileSystem
== NULL
) {
3129 // determine the file system mapping to use
3131 if (StrStr (DirectoryName
, L
":") != NULL
) {
3132 ASSERT (MapName
== NULL
);
3133 MapName
= StrnCatGrow (&MapName
, NULL
, DirectoryName
, (StrStr (DirectoryName
, L
":")-DirectoryName
+1));
3137 // find the file system mapping's entry in the list
3140 if (MapName
!= NULL
) {
3141 MapListItem
= ShellCommandFindMapItem (MapName
);
3144 // make that the current file system mapping
3146 if (MapListItem
!= NULL
) {
3147 gShellCurMapping
= MapListItem
;
3150 MapListItem
= gShellCurMapping
;
3153 if (MapListItem
== NULL
) {
3154 FreePool (DirectoryName
);
3155 SHELL_FREE_NON_NULL (MapName
);
3156 return (EFI_NOT_FOUND
);
3160 // now update the MapListItem's current directory
3162 if ((MapListItem
->CurrentDirectoryPath
!= NULL
) && (DirectoryName
[StrLen (DirectoryName
) - 1] != L
':')) {
3163 FreePool (MapListItem
->CurrentDirectoryPath
);
3164 MapListItem
->CurrentDirectoryPath
= NULL
;
3167 if (MapName
!= NULL
) {
3168 TempLen
= StrLen (MapName
);
3169 if (TempLen
!= StrLen (DirectoryName
)) {
3170 ASSERT ((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
3171 MapListItem
->CurrentDirectoryPath
= StrnCatGrow (&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
+StrLen (MapName
), 0);
3176 ASSERT ((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
3177 MapListItem
->CurrentDirectoryPath
= StrnCatGrow (&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
, 0);
3180 if (((MapListItem
->CurrentDirectoryPath
!= NULL
) && (MapListItem
->CurrentDirectoryPath
[StrLen (MapListItem
->CurrentDirectoryPath
)-1] == L
'\\')) || (MapListItem
->CurrentDirectoryPath
== NULL
)) {
3181 ASSERT ((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
3182 if (MapListItem
->CurrentDirectoryPath
!= NULL
) {
3183 MapListItem
->CurrentDirectoryPath
[StrLen (MapListItem
->CurrentDirectoryPath
)-1] = CHAR_NULL
;
3188 // cant have a mapping in the directory...
3190 if (StrStr (DirectoryName
, L
":") != NULL
) {
3191 FreePool (DirectoryName
);
3192 return (EFI_INVALID_PARAMETER
);
3196 // FileSystem != NULL
3198 MapListItem
= ShellCommandFindMapItem (FileSystem
);
3199 if (MapListItem
== NULL
) {
3200 FreePool (DirectoryName
);
3201 return (EFI_INVALID_PARAMETER
);
3204 // gShellCurMapping = MapListItem;
3205 if (DirectoryName
!= NULL
) {
3207 // change current dir on that file system
3210 if (MapListItem
->CurrentDirectoryPath
!= NULL
) {
3211 FreePool (MapListItem
->CurrentDirectoryPath
);
3213 MapListItem
->CurrentDirectoryPath
= NULL
;
3217 // ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
3218 // MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);
3219 ASSERT ((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
3220 MapListItem
->CurrentDirectoryPath
= StrnCatGrow (&MapListItem
->CurrentDirectoryPath
, &Size
, L
"\\", 0);
3221 ASSERT ((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
3222 MapListItem
->CurrentDirectoryPath
= StrnCatGrow (&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
, 0);
3223 if ((MapListItem
->CurrentDirectoryPath
!= NULL
) && (MapListItem
->CurrentDirectoryPath
[StrLen (MapListItem
->CurrentDirectoryPath
)-1] == L
'\\')) {
3224 ASSERT ((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
3225 MapListItem
->CurrentDirectoryPath
[StrLen (MapListItem
->CurrentDirectoryPath
)-1] = CHAR_NULL
;
3230 FreePool (DirectoryName
);
3232 // if updated the current directory then update the environment variable
3234 if (MapListItem
== gShellCurMapping
) {
3236 ASSERT ((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
3237 StrnCatGrow (&TempString
, &Size
, MapListItem
->MapName
, 0);
3238 ASSERT ((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
3239 StrnCatGrow (&TempString
, &Size
, MapListItem
->CurrentDirectoryPath
, 0);
3240 Status
= InternalEfiShellSetEnv (L
"cwd", TempString
, TRUE
);
3241 FreePool (TempString
);
3245 return (EFI_SUCCESS
);
3249 Return help information about a specific command.
3251 This function returns the help information for the specified command. The help text
3252 can be internal to the shell or can be from a UEFI Shell manual page.
3254 If Sections is specified, then each section name listed will be compared in a casesensitive
3255 manner, to the section names described in Appendix B. If the section exists,
3256 it will be appended to the returned help text. If the section does not exist, no
3257 information will be returned. If Sections is NULL, then all help text information
3258 available will be returned.
3260 @param Command Points to the NULL-terminated UEFI Shell command name.
3261 @param Sections Points to the NULL-terminated comma-delimited
3262 section names to return. If NULL, then all
3263 sections will be returned.
3264 @param HelpText On return, points to a callee-allocated buffer
3265 containing all specified help text.
3267 @retval EFI_SUCCESS The help text was returned.
3268 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the
3270 @retval EFI_INVALID_PARAMETER HelpText is NULL
3271 @retval EFI_NOT_FOUND There is no help text available for Command.
3275 EfiShellGetHelpText (
3276 IN CONST CHAR16
*Command
,
3277 IN CONST CHAR16
*Sections OPTIONAL
,
3278 OUT CHAR16
**HelpText
3281 CONST CHAR16
*ManFileName
;
3285 ASSERT (HelpText
!= NULL
);
3288 ManFileName
= ShellCommandGetManFileNameHandler (Command
);
3290 if (ManFileName
!= NULL
) {
3291 return (ProcessManFile (ManFileName
, Command
, Sections
, NULL
, HelpText
));
3293 if ( (StrLen (Command
) > 4)
3294 && ((Command
[StrLen (Command
)-1] == L
'i') || (Command
[StrLen (Command
)-1] == L
'I'))
3295 && ((Command
[StrLen (Command
)-2] == L
'f') || (Command
[StrLen (Command
)-2] == L
'F'))
3296 && ((Command
[StrLen (Command
)-3] == L
'e') || (Command
[StrLen (Command
)-3] == L
'E'))
3297 && (Command
[StrLen (Command
)-4] == L
'.')
3300 FixCommand
= AllocateZeroPool (StrSize (Command
) - 4 * sizeof (CHAR16
));
3301 if (FixCommand
== NULL
) {
3302 return EFI_OUT_OF_RESOURCES
;
3307 (StrSize (Command
) - 4 * sizeof (CHAR16
))/sizeof (CHAR16
),
3311 Status
= ProcessManFile (FixCommand
, FixCommand
, Sections
, NULL
, HelpText
);
3312 FreePool (FixCommand
);
3315 return (ProcessManFile (Command
, Command
, Sections
, NULL
, HelpText
));
3321 Gets the enable status of the page break output mode.
3323 User can use this function to determine current page break mode.
3325 @retval TRUE The page break output mode is enabled.
3326 @retval FALSE The page break output mode is disabled.
3330 EfiShellGetPageBreak (
3334 return (ShellInfoObject
.PageBreakEnabled
);
3338 Judges whether the active shell is the root shell.
3340 This function makes the user to know that whether the active Shell is the root shell.
3342 @retval TRUE The active Shell is the root Shell.
3343 @retval FALSE The active Shell is NOT the root Shell.
3347 EfiShellIsRootShell (
3351 return (ShellInfoObject
.RootShellInstance
);
3355 function to return a semi-colon delimited list of all alias' in the current shell
3357 up to caller to free the memory.
3359 @retval NULL No alias' were found
3360 @retval NULL An error occurred getting alias'
3361 @return !NULL a list of all alias'
3364 InternalEfiShellGetListAlias (
3370 CHAR16
*VariableName
;
3372 UINTN NameBufferSize
;
3376 NameBufferSize
= INIT_NAME_BUFFER_SIZE
;
3377 VariableName
= AllocateZeroPool (NameBufferSize
);
3381 if (VariableName
== NULL
) {
3385 VariableName
[0] = CHAR_NULL
;
3388 NameSize
= NameBufferSize
;
3389 Status
= gRT
->GetNextVariableName (&NameSize
, VariableName
, &Guid
);
3390 if (Status
== EFI_NOT_FOUND
) {
3392 } else if (Status
== EFI_BUFFER_TOO_SMALL
) {
3393 NameBufferSize
= NameSize
> NameBufferSize
* 2 ? NameSize
: NameBufferSize
* 2;
3394 SHELL_FREE_NON_NULL (VariableName
);
3395 VariableName
= AllocateZeroPool (NameBufferSize
);
3396 if (VariableName
== NULL
) {
3397 Status
= EFI_OUT_OF_RESOURCES
;
3398 SHELL_FREE_NON_NULL (RetVal
);
3403 NameSize
= NameBufferSize
;
3404 Status
= gRT
->GetNextVariableName (&NameSize
, VariableName
, &Guid
);
3407 if (EFI_ERROR (Status
)) {
3408 SHELL_FREE_NON_NULL (RetVal
);
3413 if (CompareGuid (&Guid
, &gShellAliasGuid
)) {
3414 ASSERT ((RetVal
== NULL
&& RetSize
== 0) || (RetVal
!= NULL
));
3415 RetVal
= StrnCatGrow (&RetVal
, &RetSize
, VariableName
, 0);
3416 RetVal
= StrnCatGrow (&RetVal
, &RetSize
, L
";", 0);
3420 SHELL_FREE_NON_NULL (VariableName
);
3426 Convert a null-terminated unicode string, in-place, to all lowercase.
3429 @param Str The null-terminated string to be converted to all lowercase.
3431 @return The null-terminated string converted into all lowercase.
3440 for (Index
= 0; Str
[Index
] != L
'\0'; Index
++) {
3441 if ((Str
[Index
] >= L
'A') && (Str
[Index
] <= L
'Z')) {
3442 Str
[Index
] -= (CHAR16
)(L
'A' - L
'a');
3450 This function returns the command associated with a alias or a list of all
3453 @param[in] Alias Points to the NULL-terminated shell alias.
3454 If this parameter is NULL, then all
3455 aliases will be returned in ReturnedData.
3456 @param[out] Volatile upon return of a single command if TRUE indicates
3457 this is stored in a volatile fashion. FALSE otherwise.
3459 @return If Alias is not NULL, it will return a pointer to
3460 the NULL-terminated command for that alias.
3461 If Alias is NULL, ReturnedData points to a ';'
3462 delimited list of alias (e.g.
3463 ReturnedData = "dir;del;copy;mfp") that is NULL-terminated.
3464 @retval NULL an error occurred
3465 @retval NULL Alias was not a valid Alias
3470 IN CONST CHAR16
*Alias
,
3471 OUT BOOLEAN
*Volatile OPTIONAL
3481 // Convert to lowercase to make aliases case-insensitive
3482 if (Alias
!= NULL
) {
3483 AliasLower
= AllocateCopyPool (StrSize (Alias
), Alias
);
3484 if (AliasLower
== NULL
) {
3488 ToLower (AliasLower
);
3490 if (Volatile
== NULL
) {
3491 GetVariable2 (AliasLower
, &gShellAliasGuid
, (VOID
**)&AliasVal
, NULL
);
3492 FreePool (AliasLower
);
3493 return (AddBufferToFreeList (AliasVal
));
3498 Status
= gRT
->GetVariable (AliasLower
, &gShellAliasGuid
, &Attribs
, &RetSize
, RetVal
);
3499 if (Status
== EFI_BUFFER_TOO_SMALL
) {
3500 RetVal
= AllocateZeroPool (RetSize
);
3501 Status
= gRT
->GetVariable (AliasLower
, &gShellAliasGuid
, &Attribs
, &RetSize
, RetVal
);
3504 if (EFI_ERROR (Status
)) {
3505 if (RetVal
!= NULL
) {
3509 FreePool (AliasLower
);
3513 if ((EFI_VARIABLE_NON_VOLATILE
& Attribs
) == EFI_VARIABLE_NON_VOLATILE
) {
3519 FreePool (AliasLower
);
3520 return (AddBufferToFreeList (RetVal
));
3523 return (AddBufferToFreeList (InternalEfiShellGetListAlias ()));
3527 Changes a shell command alias.
3529 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.
3531 this function does not check for built in alias'.
3533 @param[in] Command Points to the NULL-terminated shell command or existing alias.
3534 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and
3535 Command refers to an alias, that alias will be deleted.
3536 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the
3537 Alias being set will be stored in a non-volatile fashion.
3539 @retval EFI_SUCCESS Alias created or deleted successfully.
3540 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found
3544 IN CONST CHAR16
*Command
,
3545 IN CONST CHAR16
*Alias
,
3551 BOOLEAN DeleteAlias
;
3553 DeleteAlias
= FALSE
;
3554 if (Alias
== NULL
) {
3556 // We must be trying to remove one if Alias is NULL
3557 // remove an alias (but passed in COMMAND parameter)
3563 ASSERT (Alias
!= NULL
);
3566 // Convert to lowercase to make aliases case-insensitive
3568 AliasLower
= AllocateCopyPool (StrSize (Alias
), Alias
);
3569 if (AliasLower
== NULL
) {
3570 return EFI_OUT_OF_RESOURCES
;
3573 ToLower (AliasLower
);
3576 Status
= gRT
->SetVariable (AliasLower
, &gShellAliasGuid
, 0, 0, NULL
);
3578 Status
= gRT
->SetVariable (
3581 EFI_VARIABLE_BOOTSERVICE_ACCESS
| (Volatile
? 0 : EFI_VARIABLE_NON_VOLATILE
),
3587 FreePool (AliasLower
);
3593 Changes a shell command alias.
3595 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.
3598 @param[in] Command Points to the NULL-terminated shell command or existing alias.
3599 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and
3600 Command refers to an alias, that alias will be deleted.
3601 @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If
3602 FALSE and the alias already exists, then the existing alias is unchanged and
3603 EFI_ACCESS_DENIED is returned.
3604 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the
3605 Alias being set will be stored in a non-volatile fashion.
3607 @retval EFI_SUCCESS Alias created or deleted successfully.
3608 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found
3609 @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to
3611 @retval EFI_INVALID_PARAMETER Command is null or the empty string.
3616 IN CONST CHAR16
*Command
,
3617 IN CONST CHAR16
*Alias
,
3622 if (ShellCommandIsOnAliasList ((Alias
== NULL
) ? Command
: Alias
)) {
3624 // cant set over a built in alias
3626 return (EFI_ACCESS_DENIED
);
3627 } else if ((Command
== NULL
) || (*Command
== CHAR_NULL
) || (StrLen (Command
) == 0)) {
3629 // Command is null or empty
3631 return (EFI_INVALID_PARAMETER
);
3632 } else if ((EfiShellGetAlias (Command
, NULL
) != NULL
) && !Replace
) {
3634 // Alias already exists, Replace not set
3636 return (EFI_ACCESS_DENIED
);
3638 return (InternalSetAlias (Command
, Alias
, Volatile
));
3642 // Pure FILE_HANDLE operations are passed to FileHandleLib
3643 // these functions are indicated by the *
3644 EFI_SHELL_PROTOCOL mShellProtocol
= {
3650 EfiShellGetHelpText
,
3651 EfiShellGetDevicePathFromMap
,
3652 EfiShellGetMapFromDevicePath
,
3653 EfiShellGetDevicePathFromFilePath
,
3654 EfiShellGetFilePathFromDevicePath
,
3658 EfiShellOpenFileList
,
3659 EfiShellFreeFileList
,
3660 EfiShellRemoveDupInFileList
,
3661 EfiShellBatchIsActive
,
3662 EfiShellIsRootShell
,
3663 EfiShellEnablePageBreak
,
3664 EfiShellDisablePageBreak
,
3665 EfiShellGetPageBreak
,
3666 EfiShellGetDeviceName
,
3667 (EFI_SHELL_GET_FILE_INFO
)FileHandleGetInfo
, // *
3668 (EFI_SHELL_SET_FILE_INFO
)FileHandleSetInfo
, // *
3669 EfiShellOpenFileByName
,
3672 (EFI_SHELL_READ_FILE
)FileHandleRead
, // *
3673 (EFI_SHELL_WRITE_FILE
)FileHandleWrite
, // *
3674 (EFI_SHELL_DELETE_FILE
)FileHandleDelete
, // *
3675 EfiShellDeleteFileByName
,
3676 (EFI_SHELL_GET_FILE_POSITION
)FileHandleGetPosition
, // *
3677 (EFI_SHELL_SET_FILE_POSITION
)FileHandleSetPosition
, // *
3678 (EFI_SHELL_FLUSH_FILE
)FileHandleFlush
, // *
3680 EfiShellFindFilesInDir
,
3681 (EFI_SHELL_GET_FILE_SIZE
)FileHandleGetSize
, // *
3683 EfiShellOpenRootByHandle
,
3685 SHELL_MAJOR_VERSION
,
3686 SHELL_MINOR_VERSION
,
3688 // New for UEFI Shell 2.1
3689 EfiShellRegisterGuidName
,
3690 EfiShellGetGuidName
,
3691 EfiShellGetGuidFromName
,
3696 Function to create and install on the current handle.
3698 Will overwrite any existing ShellProtocols in the system to be sure that
3699 the current shell is in control.
3701 This must be removed via calling CleanUpShellProtocol().
3703 @param[in, out] NewShell The pointer to the pointer to the structure
3706 @retval EFI_SUCCESS The operation was successful.
3707 @return An error from LocateHandle, CreateEvent, or other core function.
3710 CreatePopulateInstallShellProtocol (
3711 IN OUT EFI_SHELL_PROTOCOL
**NewShell
3717 UINTN HandleCounter
;
3718 SHELL_PROTOCOL_HANDLE_LIST
*OldProtocolNode
;
3719 EFI_SHELL_PROTOCOL
*OldShell
;
3721 if (NewShell
== NULL
) {
3722 return (EFI_INVALID_PARAMETER
);
3727 OldProtocolNode
= NULL
;
3728 InitializeListHead (&ShellInfoObject
.OldShellList
.Link
);
3731 // Initialize EfiShellProtocol object...
3733 Status
= gBS
->CreateEvent (
3738 &mShellProtocol
.ExecutionBreak
3740 if (EFI_ERROR (Status
)) {
3745 // Get the size of the buffer we need.
3747 Status
= gBS
->LocateHandle (
3749 &gEfiShellProtocolGuid
,
3754 if (Status
== EFI_BUFFER_TOO_SMALL
) {
3756 // Allocate and recall with buffer of correct size
3758 Buffer
= AllocateZeroPool (BufferSize
);
3759 if (Buffer
== NULL
) {
3760 return (EFI_OUT_OF_RESOURCES
);
3763 Status
= gBS
->LocateHandle (
3765 &gEfiShellProtocolGuid
,
3770 if (EFI_ERROR (Status
)) {
3776 // now overwrite each of them, but save the info to restore when we end.
3778 for (HandleCounter
= 0; HandleCounter
< (BufferSize
/sizeof (EFI_HANDLE
)); HandleCounter
++) {
3779 Status
= gBS
->OpenProtocol (
3780 Buffer
[HandleCounter
],
3781 &gEfiShellProtocolGuid
,
3785 EFI_OPEN_PROTOCOL_GET_PROTOCOL
3787 if (!EFI_ERROR (Status
)) {
3788 OldProtocolNode
= AllocateZeroPool (sizeof (SHELL_PROTOCOL_HANDLE_LIST
));
3789 if (OldProtocolNode
== NULL
) {
3790 if (!IsListEmpty (&ShellInfoObject
.OldShellList
.Link
)) {
3791 CleanUpShellProtocol (&mShellProtocol
);
3794 Status
= EFI_OUT_OF_RESOURCES
;
3799 // reinstall over the old one...
3801 OldProtocolNode
->Handle
= Buffer
[HandleCounter
];
3802 OldProtocolNode
->Interface
= OldShell
;
3803 Status
= gBS
->ReinstallProtocolInterface (
3804 OldProtocolNode
->Handle
,
3805 &gEfiShellProtocolGuid
,
3806 OldProtocolNode
->Interface
,
3807 (VOID
*)(&mShellProtocol
)
3809 if (!EFI_ERROR (Status
)) {
3811 // we reinstalled successfully. log this so we can reverse it later.
3815 // add to the list for subsequent...
3817 InsertTailList (&ShellInfoObject
.OldShellList
.Link
, &OldProtocolNode
->Link
);
3823 } else if (Status
== EFI_NOT_FOUND
) {
3824 ASSERT (IsListEmpty (&ShellInfoObject
.OldShellList
.Link
));
3826 // no one else published yet. just publish it ourselves.
3828 Status
= gBS
->InstallProtocolInterface (
3830 &gEfiShellProtocolGuid
,
3831 EFI_NATIVE_INTERFACE
,
3832 (VOID
*)(&mShellProtocol
)
3836 if (PcdGetBool (PcdShellSupportOldProtocols
)) {
3837 /// @todo support ShellEnvironment2
3838 /// @todo do we need to support ShellEnvironment (not ShellEnvironment2) also?
3841 if (!EFI_ERROR (Status
)) {
3842 *NewShell
= &mShellProtocol
;
3849 Opposite of CreatePopulateInstallShellProtocol.
3851 Free all memory and restore the system to the state it was in before calling
3852 CreatePopulateInstallShellProtocol.
3854 @param[in, out] NewShell The pointer to the new shell protocol structure.
3856 @retval EFI_SUCCESS The operation was successful.
3859 CleanUpShellProtocol (
3860 IN OUT EFI_SHELL_PROTOCOL
*NewShell
3863 SHELL_PROTOCOL_HANDLE_LIST
*Node2
;
3866 // if we need to restore old protocols...
3868 if (!IsListEmpty (&ShellInfoObject
.OldShellList
.Link
)) {
3869 for (Node2
= (SHELL_PROTOCOL_HANDLE_LIST
*)GetFirstNode (&ShellInfoObject
.OldShellList
.Link
)
3870 ; !IsListEmpty (&ShellInfoObject
.OldShellList
.Link
)
3871 ; Node2
= (SHELL_PROTOCOL_HANDLE_LIST
*)GetFirstNode (&ShellInfoObject
.OldShellList
.Link
)
3874 RemoveEntryList (&Node2
->Link
);
3875 gBS
->ReinstallProtocolInterface (Node2
->Handle
, &gEfiShellProtocolGuid
, NewShell
, Node2
->Interface
);
3880 // no need to restore
3882 gBS
->UninstallProtocolInterface (gImageHandle
, &gEfiShellProtocolGuid
, NewShell
);
3889 Cleanup the shell environment.
3891 @param[in, out] NewShell The pointer to the new shell protocol structure.
3893 @retval EFI_SUCCESS The operation was successful.
3896 CleanUpShellEnvironment (
3897 IN OUT EFI_SHELL_PROTOCOL
*NewShell
3901 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleEx
;
3903 CleanUpShellProtocol (NewShell
);
3905 Status
= gBS
->CloseEvent (NewShell
->ExecutionBreak
);
3906 NewShell
->ExecutionBreak
= NULL
;
3908 Status
= gBS
->OpenProtocol (
3909 gST
->ConsoleInHandle
,
3910 &gEfiSimpleTextInputExProtocolGuid
,
3914 EFI_OPEN_PROTOCOL_GET_PROTOCOL
3917 if (!EFI_ERROR (Status
)) {
3918 Status
= SimpleEx
->UnregisterKeyNotify (SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle1
);
3919 Status
= SimpleEx
->UnregisterKeyNotify (SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle2
);
3920 Status
= SimpleEx
->UnregisterKeyNotify (SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle3
);
3921 Status
= SimpleEx
->UnregisterKeyNotify (SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle4
);
3922 Status
= SimpleEx
->UnregisterKeyNotify (SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle1
);
3923 Status
= SimpleEx
->UnregisterKeyNotify (SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle2
);
3924 Status
= SimpleEx
->UnregisterKeyNotify (SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle3
);
3925 Status
= SimpleEx
->UnregisterKeyNotify (SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle4
);
3932 Notification function for keystrokes.
3934 @param[in] KeyData The key that was pressed.
3936 @retval EFI_SUCCESS The operation was successful.
3940 NotificationFunction (
3941 IN EFI_KEY_DATA
*KeyData
3944 if (((KeyData
->Key
.UnicodeChar
== L
'c') &&
3945 ((KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
)) || (KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
)))) ||
3946 (KeyData
->Key
.UnicodeChar
== 3)
3949 if (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
== NULL
) {
3950 return (EFI_UNSUPPORTED
);
3953 return (gBS
->SignalEvent (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
));
3954 } else if ((KeyData
->Key
.UnicodeChar
== L
's') &&
3955 ((KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
)) || (KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
)))
3958 ShellInfoObject
.HaltOutput
= TRUE
;
3961 return (EFI_SUCCESS
);
3965 Function to start monitoring for CTRL-C using SimpleTextInputEx. This
3966 feature's enabled state was not known when the shell initially launched.
3968 @retval EFI_SUCCESS The feature is enabled.
3969 @retval EFI_OUT_OF_RESOURCES There is not enough memory available.
3972 InernalEfiShellStartMonitor (
3976 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleEx
;
3977 EFI_KEY_DATA KeyData
;
3980 Status
= gBS
->OpenProtocol (
3981 gST
->ConsoleInHandle
,
3982 &gEfiSimpleTextInputExProtocolGuid
,
3986 EFI_OPEN_PROTOCOL_GET_PROTOCOL
3988 if (EFI_ERROR (Status
)) {
3993 STRING_TOKEN (STR_SHELL_NO_IN_EX
),
3994 ShellInfoObject
.HiiHandle
3996 return (EFI_SUCCESS
);
3999 if (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
== NULL
) {
4000 return (EFI_UNSUPPORTED
);
4003 KeyData
.KeyState
.KeyToggleState
= 0;
4004 KeyData
.Key
.ScanCode
= 0;
4005 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
4006 KeyData
.Key
.UnicodeChar
= L
'c';
4008 Status
= SimpleEx
->RegisterKeyNotify (
4011 NotificationFunction
,
4012 &ShellInfoObject
.CtrlCNotifyHandle1
4015 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
4016 if (!EFI_ERROR (Status
)) {
4017 Status
= SimpleEx
->RegisterKeyNotify (
4020 NotificationFunction
,
4021 &ShellInfoObject
.CtrlCNotifyHandle2
4025 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
4026 KeyData
.Key
.UnicodeChar
= 3;
4027 if (!EFI_ERROR (Status
)) {
4028 Status
= SimpleEx
->RegisterKeyNotify (
4031 NotificationFunction
,
4032 &ShellInfoObject
.CtrlCNotifyHandle3
4036 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
4037 if (!EFI_ERROR (Status
)) {
4038 Status
= SimpleEx
->RegisterKeyNotify (
4041 NotificationFunction
,
4042 &ShellInfoObject
.CtrlCNotifyHandle4