2 Member functions of EFI_SHELL_PROTOCOL and functions for creation,
3 manipulation, and initialization of EFI_SHELL_PROTOCOL.
5 Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Close an open file handle.
21 This function closes a specified file handle. All "dirty" cached file data is
22 flushed to the device, and the file is closed. In all cases the handle is
25 @param[in] FileHandle The file handle to close.
27 @retval EFI_SUCCESS The file handle was closed successfully.
32 IN SHELL_FILE_HANDLE FileHandle
35 ShellFileHandleRemove(FileHandle
);
36 return (FileHandleClose(ConvertShellHandleToEfiFileProtocol(FileHandle
)));
40 Internal worker to determine whether there is a BlockIo somewhere
41 upon the device path specified.
43 @param[in] DevicePath The device path to test.
45 @retval TRUE gEfiBlockIoProtocolGuid was installed on a handle with this device path
46 @retval FALSE gEfiBlockIoProtocolGuid was not found.
50 InternalShellProtocolIsBlockIoPresent(
51 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
54 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
60 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
61 Status
= gBS
->LocateDevicePath(&gEfiBlockIoProtocolGuid
, &DevicePathCopy
, &Handle
);
63 if ((Handle
!= NULL
) && (!EFI_ERROR(Status
))) {
70 Internal worker to determine whether there is a file system somewhere
71 upon the device path specified.
73 @param[in] DevicePath The device path to test.
75 @retval TRUE gEfiSimpleFileSystemProtocolGuid was installed on a handle with this device path
76 @retval FALSE gEfiSimpleFileSystemProtocolGuid was not found.
80 InternalShellProtocolIsSimpleFileSystemPresent(
81 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
84 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
90 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
;
91 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &Handle
);
93 if ((Handle
!= NULL
) && (!EFI_ERROR(Status
))) {
100 Internal worker debug helper function to print out maps as they are added.
102 @param[in] Mapping string mapping that has been added
103 @param[in] DevicePath pointer to device path that has been mapped.
105 @retval EFI_SUCCESS the operation was successful.
106 @return other an error ocurred
113 InternalShellProtocolDebugPrintMessage (
114 IN CONST CHAR16
*Mapping
,
115 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
121 Status
= EFI_SUCCESS
;
124 if (Mapping
!= NULL
) {
125 DEBUG((EFI_D_INFO
, "Added new map item:\"%S\"\r\n", Mapping
));
127 Temp
= ConvertDevicePathToText(DevicePath
, TRUE
, TRUE
);
128 DEBUG((EFI_D_INFO
, "DevicePath: %S\r\n", Temp
));
136 This function creates a mapping for a device path.
138 If both DeviecPath and Mapping are NULL, this will reset the mapping to default values.
140 @param DevicePath Points to the device path. If this is NULL and Mapping points to a valid mapping,
141 then the mapping will be deleted.
142 @param Mapping Points to the NULL-terminated mapping for the device path. Must end with a ':'
144 @retval EFI_SUCCESS Mapping created or deleted successfully.
145 @retval EFI_NO_MAPPING There is no handle that corresponds exactly to DevicePath. See the
146 boot service function LocateDevicePath().
147 @retval EFI_ACCESS_DENIED The mapping is a built-in alias.
148 @retval EFI_INVALID_PARAMETER Mapping was NULL
149 @retval EFI_INVALID_PARAMETER Mapping did not end with a ':'
150 @retval EFI_INVALID_PARAMETER DevicePath was not pointing at a device that had a SIMPLE_FILE_SYSTEM_PROTOCOL installed.
151 @retval EFI_NOT_FOUND There was no mapping found to delete
152 @retval EFI_OUT_OF_RESOURCES Memory allocation failed
157 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath OPTIONAL
,
158 IN CONST CHAR16
*Mapping
162 SHELL_MAP_LIST
*MapListNode
;
164 if (Mapping
== NULL
){
165 return (EFI_INVALID_PARAMETER
);
168 if (Mapping
[StrLen(Mapping
)-1] != ':') {
169 return (EFI_INVALID_PARAMETER
);
173 // Delete the mapping
175 if (DevicePath
== NULL
) {
176 if (IsListEmpty(&gShellMapList
.Link
)) {
177 return (EFI_NOT_FOUND
);
179 for ( MapListNode
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
180 ; !IsNull(&gShellMapList
.Link
, &MapListNode
->Link
)
181 ; MapListNode
= (SHELL_MAP_LIST
*)GetNextNode(&gShellMapList
.Link
, &MapListNode
->Link
)
183 if (StringNoCaseCompare(&MapListNode
->MapName
, &Mapping
) == 0) {
184 RemoveEntryList(&MapListNode
->Link
);
185 FreePool(MapListNode
);
186 return (EFI_SUCCESS
);
191 // We didnt find one to delete
193 return (EFI_NOT_FOUND
);
197 // make sure this is a valid to add device path
199 ///@todo add BlockIo to this test...
200 if (!InternalShellProtocolIsSimpleFileSystemPresent(DevicePath
)
201 && !InternalShellProtocolIsBlockIoPresent(DevicePath
)) {
202 return (EFI_INVALID_PARAMETER
);
206 // First make sure there is no old mapping
208 Status
= EfiShellSetMap(NULL
, Mapping
);
209 if ((Status
!= EFI_SUCCESS
) && (Status
!= EFI_NOT_FOUND
)) {
214 // now add the new one.
216 Status
= ShellCommandAddMapItemAndUpdatePath(Mapping
, DevicePath
, 0, FALSE
);
222 Gets the device path from the mapping.
224 This function gets the device path associated with a mapping.
226 @param Mapping A pointer to the mapping
228 @retval !=NULL Pointer to the device path that corresponds to the
229 device mapping. The returned pointer does not need
231 @retval NULL There is no device path associated with the
234 CONST EFI_DEVICE_PATH_PROTOCOL
*
236 EfiShellGetDevicePathFromMap(
237 IN CONST CHAR16
*Mapping
240 SHELL_MAP_LIST
*MapListItem
;
247 StrnCatGrow(&NewName
, &Size
, Mapping
, 0);
248 if (Mapping
[StrLen(Mapping
)-1] != L
':') {
249 StrnCatGrow(&NewName
, &Size
, L
":", 0);
252 MapListItem
= ShellCommandFindMapItem(NewName
);
256 if (MapListItem
!= NULL
) {
257 return (MapListItem
->DevicePath
);
263 Gets the mapping(s) that most closely matches the device path.
265 This function gets the mapping which corresponds to the device path *DevicePath. If
266 there is no exact match, then the mapping which most closely matches *DevicePath
267 is returned, and *DevicePath is updated to point to the remaining portion of the
268 device path. If there is an exact match, the mapping is returned and *DevicePath
269 points to the end-of-device-path node.
271 If there are multiple map names they will be semi-colon seperated in the
272 NULL-terminated string.
274 @param DevicePath On entry, points to a device path pointer. On
275 exit, updates the pointer to point to the
276 portion of the device path after the mapping.
278 @retval NULL No mapping was found.
279 @return !=NULL Pointer to NULL-terminated mapping. The buffer
280 is callee allocated and should be freed by the caller.
284 EfiShellGetMapFromDevicePath(
285 IN OUT EFI_DEVICE_PATH_PROTOCOL
**DevicePath
288 SHELL_MAP_LIST
*Node
;
289 CHAR16
*PathForReturn
;
291 // EFI_HANDLE PathHandle;
292 // EFI_HANDLE MapHandle;
293 // EFI_STATUS Status;
294 // EFI_DEVICE_PATH_PROTOCOL *DevicePathCopy;
295 // EFI_DEVICE_PATH_PROTOCOL *MapPathCopy;
297 if (DevicePath
== NULL
|| *DevicePath
== NULL
) {
301 PathForReturn
= NULL
;
304 for ( Node
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
305 ; !IsNull(&gShellMapList
.Link
, &Node
->Link
)
306 ; Node
= (SHELL_MAP_LIST
*)GetNextNode(&gShellMapList
.Link
, &Node
->Link
)
309 // check for exact match
311 if (DevicePathCompare(DevicePath
, &Node
->DevicePath
) == 0) {
312 ASSERT((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
314 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, L
";", 0);
316 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, Node
->MapName
, 0);
319 if (PathForReturn
!= NULL
) {
320 while (!IsDevicePathEndType (*DevicePath
)) {
321 *DevicePath
= NextDevicePathNode (*DevicePath
);
323 SetDevicePathEndNode (*DevicePath
);
326 ///@todo finish code for inexact matches.
327 if (PathForReturn == NULL) {
330 DevicePathCopy = DuplicateDevicePath(*DevicePath);
331 ASSERT(DevicePathCopy != NULL);
332 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &DevicePathCopy, &PathHandle);
333 ASSERT_EFI_ERROR(Status);
335 // check each of the device paths we have to get the root of the path for consist mappings
337 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
338 ; !IsNull(&gShellMapList.Link, &Node->Link)
339 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)
341 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) == 0) {
344 MapPathCopy = DuplicateDevicePath(Node->DevicePath);
345 ASSERT(MapPathCopy != NULL);
346 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);
347 if (MapHandle == PathHandle) {
349 *DevicePath = DevicePathCopy;
352 DevicePathCopy = NULL;
353 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);
354 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);
359 // now add on the non-consistent mappings
361 for ( Node = (SHELL_MAP_LIST *)GetFirstNode(&gShellMapList.Link)
362 ; !IsNull(&gShellMapList.Link, &Node->Link)
363 ; Node = (SHELL_MAP_LIST *)GetNextNode(&gShellMapList.Link, &Node->Link)
365 if ((Node->Flags & SHELL_MAP_FLAGS_CONSIST) != 0) {
368 MapPathCopy = Node->DevicePath;
369 ASSERT(MapPathCopy != NULL);
370 Status = gBS->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid, &MapPathCopy, &MapHandle);
371 if (MapHandle == PathHandle) {
372 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, Node->MapName, 0);
373 PathForReturn = StrnCatGrow(&PathForReturn, &PathSize, L";", 0);
380 return (AddBufferToFreeList(PathForReturn
));
384 Converts a device path to a file system-style path.
386 This function converts a device path to a file system path by replacing part, or all, of
387 the device path with the file-system mapping. If there are more than one application
388 file system mappings, the one that most closely matches Path will be used.
390 @param Path The pointer to the device path
392 @retval NULL the device path could not be found.
393 @return all The pointer of the NULL-terminated file path. The path
394 is callee-allocated and should be freed by the caller.
398 EfiShellGetFilePathFromDevicePath(
399 IN CONST EFI_DEVICE_PATH_PROTOCOL
*Path
402 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
403 EFI_DEVICE_PATH_PROTOCOL
*MapPathCopy
;
404 SHELL_MAP_LIST
*MapListItem
;
405 CHAR16
*PathForReturn
;
407 EFI_HANDLE PathHandle
;
408 EFI_HANDLE MapHandle
;
410 FILEPATH_DEVICE_PATH
*FilePath
;
411 FILEPATH_DEVICE_PATH
*AlignedNode
;
413 PathForReturn
= NULL
;
416 DevicePathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)Path
;
417 ASSERT(DevicePathCopy
!= NULL
);
418 if (DevicePathCopy
== NULL
) {
422 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &PathHandle
);
424 if (EFI_ERROR(Status
)) {
428 // check each of the device paths we have to get the root of the path
430 for ( MapListItem
= (SHELL_MAP_LIST
*)GetFirstNode(&gShellMapList
.Link
)
431 ; !IsNull(&gShellMapList
.Link
, &MapListItem
->Link
)
432 ; MapListItem
= (SHELL_MAP_LIST
*)GetNextNode(&gShellMapList
.Link
, &MapListItem
->Link
)
434 MapPathCopy
= (EFI_DEVICE_PATH_PROTOCOL
*)MapListItem
->DevicePath
;
435 ASSERT(MapPathCopy
!= NULL
);
437 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
, &MapPathCopy
, &MapHandle
);
438 if (MapHandle
== PathHandle
) {
439 ASSERT((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
440 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, MapListItem
->MapName
, 0);
442 // go through all the remaining nodes in the device path
444 for ( FilePath
= (FILEPATH_DEVICE_PATH
*)DevicePathCopy
445 ; !IsDevicePathEnd (&FilePath
->Header
)
446 ; FilePath
= (FILEPATH_DEVICE_PATH
*)NextDevicePathNode (&FilePath
->Header
)
449 // all the rest should be file path nodes
451 if ((DevicePathType(&FilePath
->Header
) != MEDIA_DEVICE_PATH
) ||
452 (DevicePathSubType(&FilePath
->Header
) != MEDIA_FILEPATH_DP
)) {
453 FreePool(PathForReturn
);
454 PathForReturn
= NULL
;
458 // append the path part onto the filepath.
460 ASSERT((PathForReturn
== NULL
&& PathSize
== 0) || (PathForReturn
!= NULL
));
462 AlignedNode
= AllocateCopyPool (DevicePathNodeLength(FilePath
), FilePath
);
463 ASSERT (AlignedNode
!= NULL
);
465 // File Path Device Path Nodes 'can optionally add a "\" separator to
466 // the beginning and/or the end of the Path Name string.'
467 // (UEFI Spec 2.4 section 9.3.6.4).
468 // If necessary, add a "\", but otherwise don't
469 // (This is specified in the above section, and also implied by the
470 // UEFI Shell spec section 3.7)
471 if ((PathSize
!= 0) &&
472 (PathForReturn
!= NULL
) &&
473 (PathForReturn
[PathSize
- 1] != L
'\\') &&
474 (AlignedNode
->PathName
[0] != L
'\\')) {
475 PathForReturn
= StrnCatGrow (&PathForReturn
, &PathSize
, L
"\\", 1);
478 PathForReturn
= StrnCatGrow(&PathForReturn
, &PathSize
, AlignedNode
->PathName
, 0);
479 FreePool(AlignedNode
);
481 } // for loop of remaining nodes
483 if (PathForReturn
!= NULL
) {
486 } // for loop of paths to check
487 return(PathForReturn
);
491 Converts a file system style name to a device path.
493 This function converts a file system style name to a device path, by replacing any
494 mapping references to the associated device path.
496 @param[in] Path The pointer to the path.
498 @return The pointer of the file path. The file path is callee
499 allocated and should be freed by the caller.
500 @retval NULL The path could not be found.
501 @retval NULL There was not enough available memory.
503 EFI_DEVICE_PATH_PROTOCOL
*
505 EfiShellGetDevicePathFromFilePath(
506 IN CONST CHAR16
*Path
513 CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
514 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopy
;
515 EFI_DEVICE_PATH_PROTOCOL
*DevicePathCopyForFree
;
516 EFI_DEVICE_PATH_PROTOCOL
*DevicePathForReturn
;
527 if (StrStr(Path
, L
":") == NULL
) {
528 Cwd
= EfiShellGetCurDir(NULL
);
533 Size
+= StrSize(Path
);
534 NewPath
= AllocateZeroPool(Size
);
535 if (NewPath
== NULL
) {
538 StrCpy(NewPath
, Cwd
);
539 if (*Path
== L
'\\') {
541 while (PathRemoveLastItem(NewPath
)) ;
543 StrCat(NewPath
, Path
);
544 DevicePathForReturn
= EfiShellGetDevicePathFromFilePath(NewPath
);
546 return (DevicePathForReturn
);
551 // find the part before (but including) the : for the map name
553 ASSERT((MapName
== NULL
&& Size
== 0) || (MapName
!= NULL
));
554 MapName
= StrnCatGrow(&MapName
, &Size
, Path
, (StrStr(Path
, L
":")-Path
+1));
555 if (MapName
== NULL
|| MapName
[StrLen(MapName
)-1] != L
':') {
560 // look up the device path in the map
562 DevicePath
= EfiShellGetDevicePathFromMap(MapName
);
563 if (DevicePath
== NULL
) {
565 // Must have been a bad Mapname
571 // make a copy for LocateDevicePath to modify (also save a pointer to call FreePool with)
573 DevicePathCopyForFree
= DevicePathCopy
= DuplicateDevicePath(DevicePath
);
574 if (DevicePathCopy
== NULL
) {
583 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
, &DevicePathCopy
, &Handle
);
584 if (EFI_ERROR(Status
)) {
585 if (DevicePathCopyForFree
!= NULL
) {
586 FreePool(DevicePathCopyForFree
);
593 // build the full device path
595 if (*(Path
+StrLen(MapName
)+1) == CHAR_NULL
) {
596 DevicePathForReturn
= FileDevicePath(Handle
, L
"\\");
598 DevicePathForReturn
= FileDevicePath(Handle
, Path
+StrLen(MapName
));
602 if (DevicePathCopyForFree
!= NULL
) {
603 FreePool(DevicePathCopyForFree
);
606 return (DevicePathForReturn
);
610 Gets the name of the device specified by the device handle.
612 This function gets the user-readable name of the device specified by the device
613 handle. If no user-readable name could be generated, then *BestDeviceName will be
614 NULL and EFI_NOT_FOUND will be returned.
616 If EFI_DEVICE_NAME_USE_COMPONENT_NAME is set, then the function will return the
617 device's name using the EFI_COMPONENT_NAME2_PROTOCOL, if present on
620 If EFI_DEVICE_NAME_USE_DEVICE_PATH is set, then the function will return the
621 device's name using the EFI_DEVICE_PATH_PROTOCOL, if present on DeviceHandle.
622 If both EFI_DEVICE_NAME_USE_COMPONENT_NAME and
623 EFI_DEVICE_NAME_USE_DEVICE_PATH are set, then
624 EFI_DEVICE_NAME_USE_COMPONENT_NAME will have higher priority.
626 @param DeviceHandle The handle of the device.
627 @param Flags Determines the possible sources of component names.
629 EFI_DEVICE_NAME_USE_COMPONENT_NAME
630 EFI_DEVICE_NAME_USE_DEVICE_PATH
631 @param Language A pointer to the language specified for the device
632 name, in the same format as described in the UEFI
633 specification, Appendix M
634 @param BestDeviceName On return, points to the callee-allocated NULL-
635 terminated name of the device. If no device name
636 could be found, points to NULL. The name must be
637 freed by the caller...
639 @retval EFI_SUCCESS Get the name successfully.
640 @retval EFI_NOT_FOUND Fail to get the device name.
641 @retval EFI_INVALID_PARAMETER Flags did not have a valid bit set.
642 @retval EFI_INVALID_PARAMETER BestDeviceName was NULL
643 @retval EFI_INVALID_PARAMETER DeviceHandle was NULL
647 EfiShellGetDeviceName(
648 IN EFI_HANDLE DeviceHandle
,
649 IN EFI_SHELL_DEVICE_NAME_FLAGS Flags
,
651 OUT CHAR16
**BestDeviceName
655 EFI_COMPONENT_NAME2_PROTOCOL
*CompName2
;
656 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
657 EFI_HANDLE
*HandleList
;
660 CHAR16
*DeviceNameToReturn
;
662 UINTN ParentControllerCount
;
663 EFI_HANDLE
*ParentControllerBuffer
;
664 UINTN ParentDriverCount
;
665 EFI_HANDLE
*ParentDriverBuffer
;
667 if (BestDeviceName
== NULL
||
670 return (EFI_INVALID_PARAMETER
);
674 // make sure one of the 2 supported bits is on
676 if (((Flags
& EFI_DEVICE_NAME_USE_COMPONENT_NAME
) == 0) &&
677 ((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
,
694 for (LoopVar
= 0; LoopVar
< HandleCount
; LoopVar
++){
696 // Go through those handles until we get one that passes for GetComponentName
698 Status
= gBS
->OpenProtocol(
700 &gEfiComponentName2ProtocolGuid
,
704 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
705 if (EFI_ERROR(Status
)) {
706 Status
= gBS
->OpenProtocol(
708 &gEfiComponentNameProtocolGuid
,
712 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
715 if (EFI_ERROR(Status
)) {
718 Lang
= GetBestLanguageForDriver(CompName2
->SupportedLanguages
, Language
, FALSE
);
719 Status
= CompName2
->GetControllerName(CompName2
, DeviceHandle
, NULL
, Lang
, &DeviceNameToReturn
);
722 if (!EFI_ERROR(Status
) && DeviceNameToReturn
!= NULL
) {
726 if (HandleList
!= NULL
) {
727 FreePool(HandleList
);
731 // Now check the parent controller using this as the child.
733 if (DeviceNameToReturn
== NULL
){
734 PARSE_HANDLE_DATABASE_PARENTS(DeviceHandle
, &ParentControllerCount
, &ParentControllerBuffer
);
735 for (LoopVar
= 0 ; LoopVar
< ParentControllerCount
; LoopVar
++) {
736 PARSE_HANDLE_DATABASE_UEFI_DRIVERS(ParentControllerBuffer
[LoopVar
], &ParentDriverCount
, &ParentDriverBuffer
);
737 for (HandleCount
= 0 ; HandleCount
< ParentDriverCount
; HandleCount
++) {
739 // try using that driver's component name with controller and our driver as the child.
741 Status
= gBS
->OpenProtocol(
742 ParentDriverBuffer
[HandleCount
],
743 &gEfiComponentName2ProtocolGuid
,
747 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
748 if (EFI_ERROR(Status
)) {
749 Status
= gBS
->OpenProtocol(
750 ParentDriverBuffer
[HandleCount
],
751 &gEfiComponentNameProtocolGuid
,
755 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
758 if (EFI_ERROR(Status
)) {
761 Lang
= GetBestLanguageForDriver(CompName2
->SupportedLanguages
, Language
, FALSE
);
762 Status
= CompName2
->GetControllerName(CompName2
, ParentControllerBuffer
[LoopVar
], DeviceHandle
, Lang
, &DeviceNameToReturn
);
765 if (!EFI_ERROR(Status
) && DeviceNameToReturn
!= NULL
) {
772 SHELL_FREE_NON_NULL(ParentDriverBuffer
);
773 if (!EFI_ERROR(Status
) && DeviceNameToReturn
!= NULL
) {
777 SHELL_FREE_NON_NULL(ParentControllerBuffer
);
780 // dont return on fail since we will try device path if that bit is on
782 if (DeviceNameToReturn
!= NULL
){
783 ASSERT(BestDeviceName
!= NULL
);
784 StrnCatGrow(BestDeviceName
, NULL
, DeviceNameToReturn
, 0);
785 return (EFI_SUCCESS
);
788 if ((Flags
& EFI_DEVICE_NAME_USE_DEVICE_PATH
) != 0) {
789 Status
= gBS
->OpenProtocol(
791 &gEfiDevicePathProtocolGuid
,
795 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
796 if (!EFI_ERROR(Status
)) {
798 // use device path to text on the device path
800 *BestDeviceName
= ConvertDevicePathToText(DevicePath
, TRUE
, TRUE
);
801 return (EFI_SUCCESS
);
805 // none of the selected bits worked.
807 return (EFI_NOT_FOUND
);
811 Opens the root directory of a device on a handle
813 This function opens the root directory of a device and returns a file handle to it.
815 @param DeviceHandle The handle of the device that contains the volume.
816 @param FileHandle On exit, points to the file handle corresponding to the root directory on the
819 @retval EFI_SUCCESS Root opened successfully.
820 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory
822 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.
823 @retval EFI_DEVICE_ERROR The device had an error
827 EfiShellOpenRootByHandle(
828 IN EFI_HANDLE DeviceHandle
,
829 OUT SHELL_FILE_HANDLE
*FileHandle
833 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
*SimpleFileSystem
;
834 EFI_FILE_PROTOCOL
*RealFileHandle
;
835 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
838 // get the simple file system interface
840 Status
= gBS
->OpenProtocol(DeviceHandle
,
841 &gEfiSimpleFileSystemProtocolGuid
,
842 (VOID
**)&SimpleFileSystem
,
845 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
846 if (EFI_ERROR(Status
)) {
847 return (EFI_NOT_FOUND
);
850 Status
= gBS
->OpenProtocol(DeviceHandle
,
851 &gEfiDevicePathProtocolGuid
,
855 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
856 if (EFI_ERROR(Status
)) {
857 return (EFI_NOT_FOUND
);
860 // Open the root volume now...
862 Status
= SimpleFileSystem
->OpenVolume(SimpleFileSystem
, &RealFileHandle
);
863 *FileHandle
= ConvertEfiFileProtocolToShellHandle(RealFileHandle
, EfiShellGetMapFromDevicePath(&DevPath
));
868 Opens the root directory of a device.
870 This function opens the root directory of a device and returns a file handle to it.
872 @param DevicePath Points to the device path corresponding to the device where the
873 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL is installed.
874 @param FileHandle On exit, points to the file handle corresponding to the root directory on the
877 @retval EFI_SUCCESS Root opened successfully.
878 @retval EFI_NOT_FOUND EFI_SIMPLE_FILE_SYSTEM could not be found or the root directory
880 @retval EFI_VOLUME_CORRUPTED The data structures in the volume were corrupted.
881 @retval EFI_DEVICE_ERROR The device had an error
882 @retval EFI_INVALID_PARAMETER FileHandle is NULL.
887 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
888 OUT SHELL_FILE_HANDLE
*FileHandle
894 if (FileHandle
== NULL
) {
895 return (EFI_INVALID_PARAMETER
);
899 // find the handle of the device with that device handle and the file system
902 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
,
905 if (EFI_ERROR(Status
)) {
906 return (EFI_NOT_FOUND
);
909 return (EfiShellOpenRootByHandle(Handle
, FileHandle
));
913 Returns whether any script files are currently being processed.
915 @retval TRUE There is at least one script file active.
916 @retval FALSE No script files are active now.
921 EfiShellBatchIsActive (
925 if (ShellCommandGetCurrentScriptFile() == NULL
) {
932 Worker function to open a file based on a device path. this will open the root
933 of the volume and then traverse down to the file itself.
935 @param DevicePath Device Path of the file.
936 @param FileHandle Pointer to the file upon a successful return.
937 @param OpenMode mode to open file in.
938 @param Attributes the File Attributes to use when creating a new file.
940 @retval EFI_SUCCESS the file is open and FileHandle is valid
941 @retval EFI_UNSUPPORTED the device path cotained non-path elements
942 @retval other an error ocurred.
946 InternalOpenFileDevicePath(
947 IN OUT EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
948 OUT SHELL_FILE_HANDLE
*FileHandle
,
950 IN UINT64 Attributes OPTIONAL
954 FILEPATH_DEVICE_PATH
*FilePathNode
;
956 SHELL_FILE_HANDLE ShellHandle
;
957 EFI_FILE_PROTOCOL
*Handle1
;
958 EFI_FILE_PROTOCOL
*Handle2
;
959 FILEPATH_DEVICE_PATH
*AlignedNode
;
961 if (FileHandle
== NULL
) {
962 return (EFI_INVALID_PARAMETER
);
972 Status
= EfiShellOpenRoot(DevicePath
, &ShellHandle
);
974 if (!EFI_ERROR(Status
)) {
975 Handle1
= ConvertShellHandleToEfiFileProtocol(ShellHandle
);
976 if (Handle1
!= NULL
) {
978 // chop off the begining part before the file system part...
981 Status
= gBS
->LocateDevicePath(&gEfiSimpleFileSystemProtocolGuid
,
984 if (!EFI_ERROR(Status
)) {
986 // To access as a file system, the file path should only
987 // contain file path components. Follow the file path nodes
988 // and find the target file
990 for ( FilePathNode
= (FILEPATH_DEVICE_PATH
*)DevicePath
991 ; !IsDevicePathEnd (&FilePathNode
->Header
)
992 ; FilePathNode
= (FILEPATH_DEVICE_PATH
*) NextDevicePathNode (&FilePathNode
->Header
)
994 SHELL_FREE_NON_NULL(AlignedNode
);
995 AlignedNode
= AllocateCopyPool (DevicePathNodeLength(FilePathNode
), FilePathNode
);
997 // For file system access each node should be a file path component
999 if (DevicePathType (&FilePathNode
->Header
) != MEDIA_DEVICE_PATH
||
1000 DevicePathSubType (&FilePathNode
->Header
) != MEDIA_FILEPATH_DP
1002 Status
= EFI_UNSUPPORTED
;
1007 // Open this file path node
1013 // if this is the last node in the DevicePath always create (if that was requested).
1015 if (IsDevicePathEnd ((NextDevicePathNode (&FilePathNode
->Header
)))) {
1016 Status
= Handle2
->Open (
1019 AlignedNode
->PathName
,
1026 // This is not the last node and we dont want to 'create' existing
1027 // directory entries...
1031 // open without letting it create
1032 // prevents error on existing files/directories
1034 Status
= Handle2
->Open (
1037 AlignedNode
->PathName
,
1038 OpenMode
&~EFI_FILE_MODE_CREATE
,
1042 // if above failed now open and create the 'item'
1043 // if OpenMode EFI_FILE_MODE_CREATE bit was on (but disabled above)
1045 if ((EFI_ERROR (Status
)) && ((OpenMode
& EFI_FILE_MODE_CREATE
) != 0)) {
1046 Status
= Handle2
->Open (
1049 AlignedNode
->PathName
,
1056 // Close the last node
1058 ShellInfoObject
.NewEfiShellProtocol
->CloseFile (Handle2
);
1061 // If there's been an error, stop
1063 if (EFI_ERROR (Status
)) {
1070 SHELL_FREE_NON_NULL(AlignedNode
);
1071 if (EFI_ERROR(Status
)) {
1072 if (Handle1
!= NULL
) {
1073 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(Handle1
);
1076 *FileHandle
= ConvertEfiFileProtocolToShellHandle(Handle1
, ShellFileHandleGetPath(ShellHandle
));
1082 Creates a file or directory by name.
1084 This function creates an empty new file or directory with the specified attributes and
1085 returns the new file's handle. If the file already exists and is read-only, then
1086 EFI_INVALID_PARAMETER will be returned.
1088 If the file already existed, it is truncated and its attributes updated. If the file is
1089 created successfully, the FileHandle is the file's handle, else, the FileHandle is NULL.
1091 If the file name begins with >v, then the file handle which is returned refers to the
1092 shell environment variable with the specified name. If the shell environment variable
1093 already exists and is non-volatile then EFI_INVALID_PARAMETER is returned.
1095 @param FileName Pointer to NULL-terminated file path
1096 @param FileAttribs The new file's attrbiutes. the different attributes are
1097 described in EFI_FILE_PROTOCOL.Open().
1098 @param FileHandle On return, points to the created file handle or directory's handle
1100 @retval EFI_SUCCESS The file was opened. FileHandle points to the new file's handle.
1101 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
1102 @retval EFI_UNSUPPORTED could not open the file path
1103 @retval EFI_NOT_FOUND the specified file could not be found on the devide, or could not
1104 file the file system on the device.
1105 @retval EFI_NO_MEDIA the device has no medium.
1106 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
1108 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according
1110 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
1111 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write
1112 when the media is write-protected.
1113 @retval EFI_ACCESS_DENIED The service denied access to the file.
1114 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.
1115 @retval EFI_VOLUME_FULL The volume is full.
1120 IN CONST CHAR16
*FileName
,
1121 IN UINT64 FileAttribs
,
1122 OUT SHELL_FILE_HANDLE
*FileHandle
1125 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1129 // Is this for an environment variable
1130 // do we start with >v
1132 if (StrStr(FileName
, L
">v") == FileName
) {
1133 if (!IsVolatileEnv(FileName
+2)) {
1134 return (EFI_INVALID_PARAMETER
);
1136 *FileHandle
= CreateFileInterfaceEnv(FileName
+2);
1137 return (EFI_SUCCESS
);
1141 // We are opening a regular file.
1143 DevicePath
= EfiShellGetDevicePathFromFilePath(FileName
);
1144 if (DevicePath
== NULL
) {
1145 return (EFI_NOT_FOUND
);
1148 Status
= InternalOpenFileDevicePath(DevicePath
, FileHandle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_CREATE
, FileAttribs
); // 0 = no specific file attributes
1149 FreePool(DevicePath
);
1155 Opens a file or a directory by file name.
1157 This function opens the specified file in the specified OpenMode and returns a file
1159 If the file name begins with >v, then the file handle which is returned refers to the
1160 shell environment variable with the specified name. If the shell environment variable
1161 exists, is non-volatile and the OpenMode indicates EFI_FILE_MODE_WRITE, then
1162 EFI_INVALID_PARAMETER is returned.
1164 If the file name is >i, then the file handle which is returned refers to the standard
1165 input. If the OpenMode indicates EFI_FILE_MODE_WRITE, then EFI_INVALID_PARAMETER
1168 If the file name is >o, then the file handle which is returned refers to the standard
1169 output. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER
1172 If the file name is >e, then the file handle which is returned refers to the standard
1173 error. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER
1176 If the file name is NUL, then the file handle that is returned refers to the standard NUL
1177 file. If the OpenMode indicates EFI_FILE_MODE_READ, then EFI_INVALID_PARAMETER is
1180 If return EFI_SUCCESS, the FileHandle is the opened file's handle, else, the
1183 @param FileName Points to the NULL-terminated UCS-2 encoded file name.
1184 @param FileHandle On return, points to the file handle.
1185 @param OpenMode File open mode. Either EFI_FILE_MODE_READ or
1186 EFI_FILE_MODE_WRITE from section 12.4 of the UEFI
1188 @retval EFI_SUCCESS The file was opened. FileHandle has the opened file's handle.
1189 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. FileHandle is NULL.
1190 @retval EFI_UNSUPPORTED Could not open the file path. FileHandle is NULL.
1191 @retval EFI_NOT_FOUND The specified file could not be found on the device or the file
1192 system could not be found on the device. FileHandle is NULL.
1193 @retval EFI_NO_MEDIA The device has no medium. FileHandle is NULL.
1194 @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no
1195 longer supported. FileHandle is NULL.
1196 @retval EFI_DEVICE_ERROR The device reported an error or can't get the file path according
1197 the FileName. FileHandle is NULL.
1198 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. FileHandle is NULL.
1199 @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write
1200 when the media is write-protected. FileHandle is NULL.
1201 @retval EFI_ACCESS_DENIED The service denied access to the file. FileHandle is NULL.
1202 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. FileHandle
1204 @retval EFI_VOLUME_FULL The volume is full. FileHandle is NULL.
1208 EfiShellOpenFileByName(
1209 IN CONST CHAR16
*FileName
,
1210 OUT SHELL_FILE_HANDLE
*FileHandle
,
1214 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
1220 // Is this for StdIn
1222 if (StrCmp(FileName
, L
">i") == 0) {
1224 // make sure not writing to StdIn
1226 if ((OpenMode
& EFI_FILE_MODE_WRITE
) != 0) {
1227 return (EFI_INVALID_PARAMETER
);
1229 *FileHandle
= ShellInfoObject
.NewShellParametersProtocol
->StdIn
;
1230 ASSERT(*FileHandle
!= NULL
);
1231 return (EFI_SUCCESS
);
1235 // Is this for StdOut
1237 if (StrCmp(FileName
, L
">o") == 0) {
1239 // make sure not writing to StdIn
1241 if ((OpenMode
& EFI_FILE_MODE_READ
) != 0) {
1242 return (EFI_INVALID_PARAMETER
);
1244 *FileHandle
= &FileInterfaceStdOut
;
1245 return (EFI_SUCCESS
);
1249 // Is this for NUL file
1251 if (StrCmp(FileName
, L
"NUL") == 0) {
1252 *FileHandle
= &FileInterfaceNulFile
;
1253 return (EFI_SUCCESS
);
1257 // Is this for StdErr
1259 if (StrCmp(FileName
, L
">e") == 0) {
1261 // make sure not writing to StdIn
1263 if ((OpenMode
& EFI_FILE_MODE_READ
) != 0) {
1264 return (EFI_INVALID_PARAMETER
);
1266 *FileHandle
= &FileInterfaceStdErr
;
1267 return (EFI_SUCCESS
);
1271 // Is this for an environment variable
1272 // do we start with >v
1274 if (StrStr(FileName
, L
">v") == FileName
) {
1275 if (!IsVolatileEnv(FileName
+2) &&
1276 ((OpenMode
& EFI_FILE_MODE_WRITE
) != 0)) {
1277 return (EFI_INVALID_PARAMETER
);
1279 *FileHandle
= CreateFileInterfaceEnv(FileName
+2);
1280 return (EFI_SUCCESS
);
1284 // We are opening a regular file.
1286 DevicePath
= EfiShellGetDevicePathFromFilePath(FileName
);
1287 // DEBUG_CODE(InternalShellProtocolDebugPrintMessage (NULL, DevicePath););
1288 if (DevicePath
== NULL
) {
1289 return (EFI_NOT_FOUND
);
1293 // Copy the device path, open the file, then free the memory
1295 Status
= InternalOpenFileDevicePath(DevicePath
, FileHandle
, OpenMode
, 0); // 0 = no specific file attributes
1296 FreePool(DevicePath
);
1302 Deletes the file specified by the file name.
1304 This function deletes a file.
1306 @param FileName Points to the NULL-terminated file name.
1308 @retval EFI_SUCCESS The file was closed and deleted, and the handle was closed.
1309 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.
1310 @sa EfiShellCreateFile
1314 EfiShellDeleteFileByName(
1315 IN CONST CHAR16
*FileName
1318 SHELL_FILE_HANDLE FileHandle
;
1322 // get a handle to the file
1324 Status
= EfiShellCreateFile(FileName
,
1327 if (EFI_ERROR(Status
)) {
1331 // now delete the file
1333 return (ShellInfoObject
.NewEfiShellProtocol
->DeleteFile(FileHandle
));
1337 Disables the page break output mode.
1341 EfiShellDisablePageBreak (
1345 ShellInfoObject
.PageBreakEnabled
= FALSE
;
1349 Enables the page break output mode.
1353 EfiShellEnablePageBreak (
1357 ShellInfoObject
.PageBreakEnabled
= TRUE
;
1361 internal worker function to load and run an image via device path.
1363 @param ParentImageHandle A handle of the image that is executing the specified
1365 @param DevicePath device path of the file to execute
1366 @param CommandLine Points to the NULL-terminated UCS-2 encoded string
1367 containing the command line. If NULL then the command-
1369 @param Environment Points to a NULL-terminated array of environment
1370 variables with the format 'x=y', where x is the
1371 environment variable name and y is the value. If this
1372 is NULL, then the current shell environment is used.
1374 @param[out] StartImageStatus Returned status from gBS->StartImage.
1375 @param[out] ExitDataSize ExitDataSize as returned from gBS->StartImage
1376 @param[out] ExitData ExitData as returned from gBS->StartImage
1378 @retval EFI_SUCCESS The command executed successfully. The status code
1379 returned by the command is pointed to by StatusCode.
1380 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1381 @retval EFI_OUT_OF_RESOURCES Out of resources.
1382 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.
1386 InternalShellExecuteDevicePath(
1387 IN CONST EFI_HANDLE
*ParentImageHandle
,
1388 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
1389 IN CONST CHAR16
*CommandLine OPTIONAL
,
1390 IN CONST CHAR16
**Environment OPTIONAL
,
1391 OUT EFI_STATUS
*StartImageStatus OPTIONAL
,
1392 OUT UINTN
*ExitDataSize OPTIONAL
,
1393 OUT CHAR16
**ExitData OPTIONAL
1397 EFI_STATUS StartStatus
;
1398 EFI_STATUS CleanupStatus
;
1399 EFI_HANDLE NewHandle
;
1400 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
1401 LIST_ENTRY OrigEnvs
;
1402 EFI_SHELL_PARAMETERS_PROTOCOL ShellParamsProtocol
;
1403 UINTN InternalExitDataSize
;
1404 UINTN
*ExitDataSizePtr
;
1408 // ExitDataSize is not OPTIONAL for gBS->BootServices, provide somewhere for
1409 // it to be dumped if the caller doesn't want it.
1410 if (ExitData
== NULL
) {
1411 ExitDataSizePtr
= &InternalExitDataSize
;
1413 ExitDataSizePtr
= ExitDataSize
;
1416 if (ParentImageHandle
== NULL
) {
1417 return (EFI_INVALID_PARAMETER
);
1420 InitializeListHead(&OrigEnvs
);
1425 // Load the image with:
1426 // FALSE - not from boot manager and NULL, 0 being not already in memory
1428 Status
= gBS
->LoadImage(
1431 (EFI_DEVICE_PATH_PROTOCOL
*)DevicePath
,
1436 if (EFI_ERROR(Status
)) {
1437 if (NewHandle
!= NULL
) {
1438 gBS
->UnloadImage(NewHandle
);
1442 Status
= gBS
->OpenProtocol(
1444 &gEfiLoadedImageProtocolGuid
,
1445 (VOID
**)&LoadedImage
,
1448 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
1450 if (!EFI_ERROR(Status
)) {
1451 ASSERT(LoadedImage
->LoadOptionsSize
== 0);
1452 if (CommandLine
!= NULL
) {
1453 LoadedImage
->LoadOptionsSize
= (UINT32
)StrSize(CommandLine
);
1454 LoadedImage
->LoadOptions
= (VOID
*)CommandLine
;
1458 // Save our current environment settings for later restoration if necessary
1460 if (Environment
!= NULL
) {
1461 Status
= GetEnvironmentVariableList(&OrigEnvs
);
1462 if (!EFI_ERROR(Status
)) {
1463 Status
= SetEnvironmentVariables(Environment
);
1468 // Initialize and install a shell parameters protocol on the image.
1470 ShellParamsProtocol
.StdIn
= ShellInfoObject
.NewShellParametersProtocol
->StdIn
;
1471 ShellParamsProtocol
.StdOut
= ShellInfoObject
.NewShellParametersProtocol
->StdOut
;
1472 ShellParamsProtocol
.StdErr
= ShellInfoObject
.NewShellParametersProtocol
->StdErr
;
1473 Status
= UpdateArgcArgv(&ShellParamsProtocol
, CommandLine
, NULL
, NULL
);
1474 ASSERT_EFI_ERROR(Status
);
1476 // Replace Argv[0] with the full path of the binary we're executing:
1477 // If the command line was "foo", the binary might be called "foo.efi".
1478 // "The first entry in [Argv] is always the full file path of the
1479 // executable" - UEFI Shell Spec section 2.3
1481 ImagePath
= EfiShellGetFilePathFromDevicePath (DevicePath
);
1482 // The image we're executing isn't necessarily in a filesystem - it might
1483 // be memory mapped. In this case EfiShellGetFilePathFromDevicePath will
1484 // return NULL, and we'll leave Argv[0] as UpdateArgcArgv set it.
1485 if (ImagePath
!= NULL
) {
1486 if (ShellParamsProtocol
.Argv
== NULL
) {
1487 // Command line was empty or null.
1488 // (UpdateArgcArgv sets Argv to NULL when CommandLine is "" or NULL)
1489 ShellParamsProtocol
.Argv
= AllocatePool (sizeof (CHAR16
*));
1490 if (ShellParamsProtocol
.Argv
== NULL
) {
1491 Status
= EFI_OUT_OF_RESOURCES
;
1494 ShellParamsProtocol
.Argc
= 1;
1496 // Free the string UpdateArgcArgv put in Argv[0];
1497 FreePool (ShellParamsProtocol
.Argv
[0]);
1499 ShellParamsProtocol
.Argv
[0] = ImagePath
;
1502 Status
= gBS
->InstallProtocolInterface(&NewHandle
, &gEfiShellParametersProtocolGuid
, EFI_NATIVE_INTERFACE
, &ShellParamsProtocol
);
1503 ASSERT_EFI_ERROR(Status
);
1505 ///@todo initialize and install ShellInterface protocol on the new image for compatibility if - PcdGetBool(PcdShellSupportOldProtocols)
1508 // now start the image, passing up exit data if the caller requested it
1510 if (!EFI_ERROR(Status
)) {
1511 StartStatus
= gBS
->StartImage(
1516 if (StartImageStatus
!= NULL
) {
1517 *StartImageStatus
= StartStatus
;
1520 CleanupStatus
= gBS
->UninstallProtocolInterface(
1522 &gEfiShellParametersProtocolGuid
,
1523 &ShellParamsProtocol
1525 ASSERT_EFI_ERROR(CleanupStatus
);
1531 // Unload image - We should only get here if we didn't call StartImage
1532 gBS
->UnloadImage (NewHandle
);
1535 // Free Argv (Allocated in UpdateArgcArgv)
1536 if (ShellParamsProtocol
.Argv
!= NULL
) {
1537 for (Index
= 0; Index
< ShellParamsProtocol
.Argc
; Index
++) {
1538 if (ShellParamsProtocol
.Argv
[Index
] != NULL
) {
1539 FreePool (ShellParamsProtocol
.Argv
[Index
]);
1542 FreePool (ShellParamsProtocol
.Argv
);
1546 // Restore environment variables
1547 if (!IsListEmpty(&OrigEnvs
)) {
1548 CleanupStatus
= SetEnvironmentVariableList(&OrigEnvs
);
1549 ASSERT_EFI_ERROR (CleanupStatus
);
1555 Execute the command line.
1557 This function creates a nested instance of the shell and executes the specified
1558 command (CommandLine) with the specified environment (Environment). Upon return,
1559 the status code returned by the specified command is placed in StatusCode.
1561 If Environment is NULL, then the current environment is used and all changes made
1562 by the commands executed will be reflected in the current environment. If the
1563 Environment is non-NULL, then the changes made will be discarded.
1565 The CommandLine is executed from the current working directory on the current
1568 @param ParentImageHandle A handle of the image that is executing the specified
1570 @param CommandLine Points to the NULL-terminated UCS-2 encoded string
1571 containing the command line. If NULL then the command-
1573 @param Environment Points to a NULL-terminated array of environment
1574 variables with the format 'x=y', where x is the
1575 environment variable name and y is the value. If this
1576 is NULL, then the current shell environment is used.
1577 @param StatusCode Points to the status code returned by the command.
1579 @retval EFI_SUCCESS The command executed successfully. The status code
1580 returned by the command is pointed to by StatusCode.
1581 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1582 @retval EFI_OUT_OF_RESOURCES Out of resources.
1583 @retval EFI_UNSUPPORTED Nested shell invocations are not allowed.
1584 @retval EFI_UNSUPPORTED The support level required for this function is not present.
1586 @sa InternalShellExecuteDevicePath
1591 IN EFI_HANDLE
*ParentImageHandle
,
1592 IN CHAR16
*CommandLine OPTIONAL
,
1593 IN CHAR16
**Environment OPTIONAL
,
1594 OUT EFI_STATUS
*StatusCode OPTIONAL
1599 EFI_DEVICE_PATH_PROTOCOL
*DevPath
;
1604 if ((PcdGet8(PcdShellSupportLevel
) < 1)) {
1605 return (EFI_UNSUPPORTED
);
1608 DevPath
= AppendDevicePath (ShellInfoObject
.ImageDevPath
, ShellInfoObject
.FileDevPath
);
1611 Temp
= ConvertDevicePathToText(ShellInfoObject
.FileDevPath
, TRUE
, TRUE
);
1613 Temp
= ConvertDevicePathToText(ShellInfoObject
.ImageDevPath
, TRUE
, TRUE
);
1615 Temp
= ConvertDevicePathToText(DevPath
, TRUE
, TRUE
);
1621 ASSERT((Temp
== NULL
&& Size
== 0) || (Temp
!= NULL
));
1622 StrnCatGrow(&Temp
, &Size
, L
"Shell.efi -_exit ", 0);
1623 StrnCatGrow(&Temp
, &Size
, CommandLine
, 0);
1625 Status
= InternalShellExecuteDevicePath(
1629 (CONST CHAR16
**)Environment
,
1634 if (Status
== EFI_ABORTED
) {
1635 // If the command exited with an error, the shell should put the exit
1636 // status in ExitData, preceded by a null-terminated string.
1637 ASSERT (ExitDataSize
== StrSize (ExitData
) + sizeof (SHELL_STATUS
));
1639 if (StatusCode
!= NULL
) {
1640 // Skip the null-terminated string
1641 ExitData
+= StrLen (ExitData
) + 1;
1643 // Use CopyMem to avoid alignment faults
1644 CopyMem (StatusCode
, ExitData
, sizeof (SHELL_STATUS
));
1646 // Convert from SHELL_STATUS to EFI_STATUS
1647 // EFI_STATUSes have top bit set when they are errors.
1648 // (See UEFI Spec Appendix D)
1649 if (*StatusCode
!= SHELL_SUCCESS
) {
1650 *StatusCode
= (EFI_STATUS
) *StatusCode
| MAX_BIT
;
1653 FreePool (ExitData
);
1654 Status
= EFI_SUCCESS
;
1658 // de-allocate and return
1666 Utility cleanup function for EFI_SHELL_FILE_INFO objects.
1668 1) frees all pointers (non-NULL)
1669 2) Closes the SHELL_FILE_HANDLE
1671 @param FileListNode pointer to the list node to free
1675 InternalFreeShellFileInfoNode(
1676 IN EFI_SHELL_FILE_INFO
*FileListNode
1679 if (FileListNode
->Info
!= NULL
) {
1680 FreePool((VOID
*)FileListNode
->Info
);
1682 if (FileListNode
->FileName
!= NULL
) {
1683 FreePool((VOID
*)FileListNode
->FileName
);
1685 if (FileListNode
->FullName
!= NULL
) {
1686 FreePool((VOID
*)FileListNode
->FullName
);
1688 if (FileListNode
->Handle
!= NULL
) {
1689 ShellInfoObject
.NewEfiShellProtocol
->CloseFile(FileListNode
->Handle
);
1691 FreePool(FileListNode
);
1694 Frees the file list.
1696 This function cleans up the file list and any related data structures. It has no
1697 impact on the files themselves.
1699 @param FileList The file list to free. Type EFI_SHELL_FILE_INFO is
1700 defined in OpenFileList()
1702 @retval EFI_SUCCESS Free the file list successfully.
1703 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;
1707 EfiShellFreeFileList(
1708 IN EFI_SHELL_FILE_INFO
**FileList
1711 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1713 if (FileList
== NULL
|| *FileList
== NULL
) {
1714 return (EFI_INVALID_PARAMETER
);
1717 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&(*FileList
)->Link
)
1718 ; !IsListEmpty(&(*FileList
)->Link
)
1719 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&(*FileList
)->Link
)
1721 RemoveEntryList(&ShellFileListItem
->Link
);
1722 InternalFreeShellFileInfoNode(ShellFileListItem
);
1724 InternalFreeShellFileInfoNode(*FileList
);
1726 return(EFI_SUCCESS
);
1730 Deletes the duplicate file names files in the given file list.
1732 This function deletes the reduplicate files in the given file list.
1734 @param FileList A pointer to the first entry in the file list.
1736 @retval EFI_SUCCESS Always success.
1737 @retval EFI_INVALID_PARAMETER FileList was NULL or *FileList was NULL;
1741 EfiShellRemoveDupInFileList(
1742 IN EFI_SHELL_FILE_INFO
**FileList
1745 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1746 EFI_SHELL_FILE_INFO
*ShellFileListItem2
;
1747 EFI_SHELL_FILE_INFO
*TempNode
;
1749 if (FileList
== NULL
|| *FileList
== NULL
) {
1750 return (EFI_INVALID_PARAMETER
);
1752 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&(*FileList
)->Link
)
1753 ; !IsNull(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1754 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1756 for ( ShellFileListItem2
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
1757 ; !IsNull(&(*FileList
)->Link
, &ShellFileListItem2
->Link
)
1758 ; ShellFileListItem2
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&(*FileList
)->Link
, &ShellFileListItem2
->Link
)
1760 if (gUnicodeCollation
->StriColl(
1762 (CHAR16
*)ShellFileListItem
->FullName
,
1763 (CHAR16
*)ShellFileListItem2
->FullName
) == 0
1765 TempNode
= (EFI_SHELL_FILE_INFO
*)GetPreviousNode(
1767 &ShellFileListItem2
->Link
1769 RemoveEntryList(&ShellFileListItem2
->Link
);
1770 InternalFreeShellFileInfoNode(ShellFileListItem2
);
1771 // Set ShellFileListItem2 to PreviousNode so we don't access Freed
1772 // memory in GetNextNode in the loop expression above.
1773 ShellFileListItem2
= TempNode
;
1777 return (EFI_SUCCESS
);
1781 // This is the same structure as the external version, but it has no CONST qualifiers.
1784 LIST_ENTRY Link
; ///< Linked list members.
1785 EFI_STATUS Status
; ///< Status of opening the file. Valid only if Handle != NULL.
1786 CHAR16
*FullName
; ///< Fully qualified filename.
1787 CHAR16
*FileName
; ///< name of this file.
1788 SHELL_FILE_HANDLE Handle
; ///< Handle for interacting with the opened file or NULL if closed.
1789 EFI_FILE_INFO
*Info
; ///< Pointer to the FileInfo struct for this file or NULL.
1790 } EFI_SHELL_FILE_INFO_NO_CONST
;
1793 Allocates and duplicates a EFI_SHELL_FILE_INFO node.
1795 @param[in] Node The node to copy from.
1796 @param[in] Save TRUE to set Node->Handle to NULL, FALSE otherwise.
1798 @retval NULL a memory allocation error ocurred
1799 @return != NULL a pointer to the new node
1801 EFI_SHELL_FILE_INFO
*
1803 InternalDuplicateShellFileInfo(
1804 IN EFI_SHELL_FILE_INFO
*Node
,
1808 EFI_SHELL_FILE_INFO_NO_CONST
*NewNode
;
1811 // try to confirm that the objects are in sync
1813 ASSERT(sizeof(EFI_SHELL_FILE_INFO_NO_CONST
) == sizeof(EFI_SHELL_FILE_INFO
));
1815 NewNode
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1816 if (NewNode
== NULL
) {
1819 NewNode
->FullName
= AllocateZeroPool(StrSize(Node
->FullName
));
1821 NewNode
->FileName
= AllocateZeroPool(StrSize(Node
->FileName
));
1822 NewNode
->Info
= AllocateZeroPool((UINTN
)Node
->Info
->Size
);
1823 if ( NewNode
->FullName
== NULL
1824 || NewNode
->FileName
== NULL
1825 || NewNode
->Info
== NULL
1827 SHELL_FREE_NON_NULL(NewNode
->FullName
);
1828 SHELL_FREE_NON_NULL(NewNode
->FileName
);
1829 SHELL_FREE_NON_NULL(NewNode
->Info
);
1830 SHELL_FREE_NON_NULL(NewNode
);
1833 NewNode
->Status
= Node
->Status
;
1834 NewNode
->Handle
= Node
->Handle
;
1836 Node
->Handle
= NULL
;
1838 StrCpy((CHAR16
*)NewNode
->FullName
, Node
->FullName
);
1839 StrCpy((CHAR16
*)NewNode
->FileName
, Node
->FileName
);
1840 CopyMem(NewNode
->Info
, Node
->Info
, (UINTN
)Node
->Info
->Size
);
1842 return((EFI_SHELL_FILE_INFO
*)NewNode
);
1846 Allocates and populates a EFI_SHELL_FILE_INFO structure. if any memory operation
1847 failed it will return NULL.
1849 @param[in] BasePath the Path to prepend onto filename for FullPath
1850 @param[in] Status Status member initial value.
1851 @param[in] FileName FileName member initial value.
1852 @param[in] Handle Handle member initial value.
1853 @param[in] Info Info struct to copy.
1855 @retval NULL An error ocurred.
1856 @return a pointer to the newly allocated structure.
1858 EFI_SHELL_FILE_INFO
*
1860 CreateAndPopulateShellFileInfo(
1861 IN CONST CHAR16
*BasePath
,
1862 IN CONST EFI_STATUS Status
,
1863 IN CONST CHAR16
*FileName
,
1864 IN CONST SHELL_FILE_HANDLE Handle
,
1865 IN CONST EFI_FILE_INFO
*Info
1868 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1875 ShellFileListItem
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
1876 if (ShellFileListItem
== NULL
) {
1879 if (Info
!= NULL
&& Info
->Size
!= 0) {
1880 ShellFileListItem
->Info
= AllocateZeroPool((UINTN
)Info
->Size
);
1881 if (ShellFileListItem
->Info
== NULL
) {
1882 FreePool(ShellFileListItem
);
1885 CopyMem(ShellFileListItem
->Info
, Info
, (UINTN
)Info
->Size
);
1887 ShellFileListItem
->Info
= NULL
;
1889 if (FileName
!= NULL
) {
1890 ASSERT(TempString
== NULL
);
1891 ShellFileListItem
->FileName
= StrnCatGrow(&TempString
, 0, FileName
, 0);
1892 if (ShellFileListItem
->FileName
== NULL
) {
1893 FreePool(ShellFileListItem
->Info
);
1894 FreePool(ShellFileListItem
);
1898 ShellFileListItem
->FileName
= NULL
;
1902 if (BasePath
!= NULL
) {
1903 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
1904 TempString
= StrnCatGrow(&TempString
, &Size
, BasePath
, 0);
1905 if (TempString
== NULL
) {
1906 FreePool((VOID
*)ShellFileListItem
->FileName
);
1907 SHELL_FREE_NON_NULL(ShellFileListItem
->Info
);
1908 FreePool(ShellFileListItem
);
1912 if (ShellFileListItem
->FileName
!= NULL
) {
1913 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
1914 TempString
= StrnCatGrow(&TempString
, &Size
, ShellFileListItem
->FileName
, 0);
1915 if (TempString
== NULL
) {
1916 FreePool((VOID
*)ShellFileListItem
->FileName
);
1917 FreePool(ShellFileListItem
->Info
);
1918 FreePool(ShellFileListItem
);
1923 TempString
= PathCleanUpDirectories(TempString
);
1925 ShellFileListItem
->FullName
= TempString
;
1926 ShellFileListItem
->Status
= Status
;
1927 ShellFileListItem
->Handle
= Handle
;
1929 return (ShellFileListItem
);
1933 Find all files in a specified directory.
1935 @param FileDirHandle Handle of the directory to search.
1936 @param FileList On return, points to the list of files in the directory
1937 or NULL if there are no files in the directory.
1939 @retval EFI_SUCCESS File information was returned successfully.
1940 @retval EFI_VOLUME_CORRUPTED The file system structures have been corrupted.
1941 @retval EFI_DEVICE_ERROR The device reported an error.
1942 @retval EFI_NO_MEDIA The device media is not present.
1943 @retval EFI_INVALID_PARAMETER The FileDirHandle was not a directory.
1944 @return An error from FileHandleGetFileName().
1948 EfiShellFindFilesInDir(
1949 IN SHELL_FILE_HANDLE FileDirHandle
,
1950 OUT EFI_SHELL_FILE_INFO
**FileList
1953 EFI_SHELL_FILE_INFO
*ShellFileList
;
1954 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
1955 EFI_FILE_INFO
*FileInfo
;
1963 Status
= FileHandleGetFileName(FileDirHandle
, &BasePath
);
1964 if (EFI_ERROR(Status
)) {
1968 if (ShellFileHandleGetPath(FileDirHandle
) != NULL
) {
1971 TempString
= StrnCatGrow(&TempString
, &Size
, ShellFileHandleGetPath(FileDirHandle
), 0);
1972 if (TempString
== NULL
) {
1973 SHELL_FREE_NON_NULL(BasePath
);
1974 return (EFI_OUT_OF_RESOURCES
);
1976 TempSpot
= StrStr(TempString
, L
";");
1978 if (TempSpot
!= NULL
) {
1979 *TempSpot
= CHAR_NULL
;
1982 TempString
= StrnCatGrow(&TempString
, &Size
, BasePath
, 0);
1983 if (TempString
== NULL
) {
1984 SHELL_FREE_NON_NULL(BasePath
);
1985 return (EFI_OUT_OF_RESOURCES
);
1987 SHELL_FREE_NON_NULL(BasePath
);
1988 BasePath
= TempString
;
1992 ShellFileList
= NULL
;
1993 ShellFileListItem
= NULL
;
1995 Status
= EFI_SUCCESS
;
1998 for ( Status
= FileHandleFindFirstFile(FileDirHandle
, &FileInfo
)
1999 ; !EFI_ERROR(Status
) && !NoFile
2000 ; Status
= FileHandleFindNextFile(FileDirHandle
, FileInfo
, &NoFile
)
2003 // allocate a new EFI_SHELL_FILE_INFO and populate it...
2005 ShellFileListItem
= CreateAndPopulateShellFileInfo(
2007 EFI_SUCCESS
, // success since we didnt fail to open it...
2009 NULL
, // no handle since not open
2012 if (ShellFileList
== NULL
) {
2013 ShellFileList
= (EFI_SHELL_FILE_INFO
*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
2014 ASSERT(ShellFileList
!= NULL
);
2015 InitializeListHead(&ShellFileList
->Link
);
2017 InsertTailList(&ShellFileList
->Link
, &ShellFileListItem
->Link
);
2019 if (EFI_ERROR(Status
)) {
2020 EfiShellFreeFileList(&ShellFileList
);
2023 *FileList
= ShellFileList
;
2025 SHELL_FREE_NON_NULL(BasePath
);
2030 Updates a file name to be preceeded by the mapped drive name
2032 @param[in] BasePath the Mapped drive name to prepend
2033 @param[in, out] Path pointer to pointer to the file name to update.
2036 @retval EFI_OUT_OF_RESOURCES
2041 IN CONST CHAR16
*BasePath
,
2042 IN OUT CHAR16
**Path
2051 ASSERT(Path
!= NULL
);
2052 ASSERT(*Path
!= NULL
);
2053 ASSERT(BasePath
!= NULL
);
2056 // convert a local path to an absolute path
2058 if (StrStr(*Path
, L
":") == NULL
) {
2059 ASSERT((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
2060 StrnCatGrow(&Path2
, &Path2Size
, BasePath
, 0);
2061 if (Path2
== NULL
) {
2062 return (EFI_OUT_OF_RESOURCES
);
2064 ASSERT((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
2065 StrnCatGrow(&Path2
, &Path2Size
, (*Path
)[0] == L
'\\'?(*Path
) + 1 :*Path
, 0);
2066 if (Path2
== NULL
) {
2067 return (EFI_OUT_OF_RESOURCES
);
2074 return (EFI_SUCCESS
);
2078 If FileHandle is a directory then the function reads from FileHandle and reads in
2079 each of the FileInfo structures. If one of them matches the Pattern's first
2080 "level" then it opens that handle and calls itself on that handle.
2082 If FileHandle is a file and matches all of the remaining Pattern (which would be
2083 on its last node), then add a EFI_SHELL_FILE_INFO object for this file to fileList.
2085 Upon a EFI_SUCCESS return fromt he function any the caller is responsible to call
2086 FreeFileList with FileList.
2088 @param[in] FilePattern The FilePattern to check against.
2089 @param[in] UnicodeCollation The pointer to EFI_UNICODE_COLLATION_PROTOCOL structure
2090 @param[in] FileHandle The FileHandle to start with
2091 @param[in, out] FileList pointer to pointer to list of found files.
2092 @param[in] ParentNode The node for the parent. Same file as identified by HANDLE.
2093 @param[in] MapName The file system name this file is on.
2095 @retval EFI_SUCCESS all files were found and the FileList contains a list.
2096 @retval EFI_NOT_FOUND no files were found
2097 @retval EFI_OUT_OF_RESOURCES a memory allocation failed
2102 IN CONST CHAR16
*FilePattern
,
2103 IN EFI_UNICODE_COLLATION_PROTOCOL
*UnicodeCollation
,
2104 IN SHELL_FILE_HANDLE FileHandle
,
2105 IN OUT EFI_SHELL_FILE_INFO
**FileList
,
2106 IN CONST EFI_SHELL_FILE_INFO
*ParentNode OPTIONAL
,
2107 IN CONST CHAR16
*MapName
2111 CONST CHAR16
*NextFilePatternStart
;
2112 CHAR16
*CurrentFilePattern
;
2113 EFI_SHELL_FILE_INFO
*ShellInfo
;
2114 EFI_SHELL_FILE_INFO
*ShellInfoNode
;
2115 EFI_SHELL_FILE_INFO
*NewShellNode
;
2116 EFI_FILE_INFO
*FileInfo
;
2118 CHAR16
*NewFullName
;
2121 if ( FilePattern
== NULL
2122 || UnicodeCollation
== NULL
2125 return (EFI_INVALID_PARAMETER
);
2128 CurrentFilePattern
= NULL
;
2130 if (*FilePattern
== L
'\\') {
2134 for( NextFilePatternStart
= FilePattern
2135 ; *NextFilePatternStart
!= CHAR_NULL
&& *NextFilePatternStart
!= L
'\\'
2136 ; NextFilePatternStart
++);
2138 CurrentFilePattern
= AllocateZeroPool((NextFilePatternStart
-FilePattern
+1)*sizeof(CHAR16
));
2139 ASSERT(CurrentFilePattern
!= NULL
);
2140 StrnCpy(CurrentFilePattern
, FilePattern
, NextFilePatternStart
-FilePattern
);
2142 if (CurrentFilePattern
[0] == CHAR_NULL
2143 &&NextFilePatternStart
[0] == CHAR_NULL
2146 // we want the parent or root node (if no parent)
2148 if (ParentNode
== NULL
) {
2150 // We want the root node. create the node.
2152 FileInfo
= FileHandleGetInfo(FileHandle
);
2153 NewShellNode
= CreateAndPopulateShellFileInfo(
2160 SHELL_FREE_NON_NULL(FileInfo
);
2163 // Add the current parameter FileHandle to the list, then end...
2165 NewShellNode
= InternalDuplicateShellFileInfo((EFI_SHELL_FILE_INFO
*)ParentNode
, TRUE
);
2167 if (NewShellNode
== NULL
) {
2168 Status
= EFI_OUT_OF_RESOURCES
;
2170 NewShellNode
->Handle
= NULL
;
2171 if (*FileList
== NULL
) {
2172 *FileList
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
2173 InitializeListHead(&((*FileList
)->Link
));
2177 // Add to the returning to use list
2179 InsertTailList(&(*FileList
)->Link
, &NewShellNode
->Link
);
2181 Status
= EFI_SUCCESS
;
2184 Status
= EfiShellFindFilesInDir(FileHandle
, &ShellInfo
);
2186 if (!EFI_ERROR(Status
)){
2187 if (StrStr(NextFilePatternStart
, L
"\\") != NULL
){
2192 for ( ShellInfoNode
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ShellInfo
->Link
)
2193 ; !IsNull (&ShellInfo
->Link
, &ShellInfoNode
->Link
)
2194 ; ShellInfoNode
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ShellInfo
->Link
, &ShellInfoNode
->Link
)
2196 if (UnicodeCollation
->MetaiMatch(UnicodeCollation
, (CHAR16
*)ShellInfoNode
->FileName
, CurrentFilePattern
)){
2197 if (ShellInfoNode
->FullName
!= NULL
&& StrStr(ShellInfoNode
->FullName
, L
":") == NULL
) {
2198 Size
= StrSize(ShellInfoNode
->FullName
);
2199 Size
+= StrSize(MapName
) + sizeof(CHAR16
);
2200 NewFullName
= AllocateZeroPool(Size
);
2201 if (NewFullName
== NULL
) {
2202 Status
= EFI_OUT_OF_RESOURCES
;
2204 StrCpy(NewFullName
, MapName
);
2205 StrCat(NewFullName
, ShellInfoNode
->FullName
+1);
2206 FreePool((VOID
*)ShellInfoNode
->FullName
);
2207 ShellInfoNode
->FullName
= NewFullName
;
2210 if (Directory
&& !EFI_ERROR(Status
) && ShellInfoNode
->FullName
!= NULL
&& ShellInfoNode
->FileName
!= NULL
){
2212 // should be a directory
2216 // don't open the . and .. directories
2218 if ( (StrCmp(ShellInfoNode
->FileName
, L
".") != 0)
2219 && (StrCmp(ShellInfoNode
->FileName
, L
"..") != 0)
2224 if (EFI_ERROR(Status
)) {
2228 // Open the directory since we need that handle in the next recursion.
2230 ShellInfoNode
->Status
= EfiShellOpenFileByName (ShellInfoNode
->FullName
, &ShellInfoNode
->Handle
, EFI_FILE_MODE_READ
);
2233 // recurse with the next part of the pattern
2235 Status
= ShellSearchHandle(NextFilePatternStart
, UnicodeCollation
, ShellInfoNode
->Handle
, FileList
, ShellInfoNode
, MapName
);
2237 } else if (!EFI_ERROR(Status
)) {
2243 // copy the information we need into a new Node
2245 NewShellNode
= InternalDuplicateShellFileInfo(ShellInfoNode
, FALSE
);
2246 ASSERT(NewShellNode
!= NULL
);
2247 if (NewShellNode
== NULL
) {
2248 Status
= EFI_OUT_OF_RESOURCES
;
2250 if (*FileList
== NULL
) {
2251 *FileList
= AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO
));
2252 InitializeListHead(&((*FileList
)->Link
));
2256 // Add to the returning to use list
2258 InsertTailList(&(*FileList
)->Link
, &NewShellNode
->Link
);
2261 if (EFI_ERROR(Status
)) {
2265 if (EFI_ERROR(Status
)) {
2266 EfiShellFreeFileList(&ShellInfo
);
2268 Status
= EfiShellFreeFileList(&ShellInfo
);
2273 FreePool(CurrentFilePattern
);
2278 Find files that match a specified pattern.
2280 This function searches for all files and directories that match the specified
2281 FilePattern. The FilePattern can contain wild-card characters. The resulting file
2282 information is placed in the file list FileList.
2284 Wildcards are processed
2285 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1.
2287 The files in the file list are not opened. The OpenMode field is set to 0 and the FileInfo
2288 field is set to NULL.
2290 if *FileList is not NULL then it must be a pre-existing and properly initialized list.
2292 @param FilePattern Points to a NULL-terminated shell file path, including wildcards.
2293 @param FileList On return, points to the start of a file list containing the names
2294 of all matching files or else points to NULL if no matching files
2295 were found. only on a EFI_SUCCESS return will; this be non-NULL.
2297 @retval EFI_SUCCESS Files found. FileList is a valid list.
2298 @retval EFI_NOT_FOUND No files found.
2299 @retval EFI_NO_MEDIA The device has no media
2300 @retval EFI_DEVICE_ERROR The device reported an error
2301 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted
2306 IN CONST CHAR16
*FilePattern
,
2307 OUT EFI_SHELL_FILE_INFO
**FileList
2311 CHAR16
*PatternCopy
;
2312 CHAR16
*PatternCurrentLocation
;
2313 EFI_DEVICE_PATH_PROTOCOL
*RootDevicePath
;
2314 SHELL_FILE_HANDLE RootFileHandle
;
2318 if ( FilePattern
== NULL
2320 || StrStr(FilePattern
, L
":") == NULL
2322 return (EFI_INVALID_PARAMETER
);
2324 Status
= EFI_SUCCESS
;
2325 RootDevicePath
= NULL
;
2326 RootFileHandle
= NULL
;
2328 PatternCopy
= AllocateZeroPool(StrSize(FilePattern
));
2329 if (PatternCopy
== NULL
) {
2330 return (EFI_OUT_OF_RESOURCES
);
2332 StrCpy(PatternCopy
, FilePattern
);
2334 PatternCopy
= PathCleanUpDirectories(PatternCopy
);
2336 Count
= StrStr(PatternCopy
, L
":") - PatternCopy
;
2339 ASSERT(MapName
== NULL
);
2340 MapName
= StrnCatGrow(&MapName
, NULL
, PatternCopy
, Count
);
2341 if (MapName
== NULL
) {
2342 Status
= EFI_OUT_OF_RESOURCES
;
2344 RootDevicePath
= EfiShellGetDevicePathFromFilePath(PatternCopy
);
2345 if (RootDevicePath
== NULL
) {
2346 Status
= EFI_INVALID_PARAMETER
;
2348 Status
= EfiShellOpenRoot(RootDevicePath
, &RootFileHandle
);
2349 if (!EFI_ERROR(Status
)) {
2350 for ( PatternCurrentLocation
= PatternCopy
2351 ; *PatternCurrentLocation
!= ':'
2352 ; PatternCurrentLocation
++);
2353 PatternCurrentLocation
++;
2354 Status
= ShellSearchHandle(PatternCurrentLocation
, gUnicodeCollation
, RootFileHandle
, FileList
, NULL
, MapName
);
2356 FreePool(RootDevicePath
);
2360 SHELL_FREE_NON_NULL(PatternCopy
);
2361 SHELL_FREE_NON_NULL(MapName
);
2367 Opens the files that match the path specified.
2369 This function opens all of the files specified by Path. Wildcards are processed
2370 according to the rules specified in UEFI Shell 2.0 spec section 3.7.1. Each
2371 matching file has an EFI_SHELL_FILE_INFO structure created in a linked list.
2373 @param Path A pointer to the path string.
2374 @param OpenMode Specifies the mode used to open each file, EFI_FILE_MODE_READ or
2375 EFI_FILE_MODE_WRITE.
2376 @param FileList Points to the start of a list of files opened.
2378 @retval EFI_SUCCESS Create the file list successfully.
2379 @return Others Can't create the file list.
2383 EfiShellOpenFileList(
2386 IN OUT EFI_SHELL_FILE_INFO
**FileList
2390 EFI_SHELL_FILE_INFO
*ShellFileListItem
;
2393 CONST CHAR16
*CurDir
;
2396 PathCleanUpDirectories(Path
);
2401 if (FileList
== NULL
|| *FileList
== NULL
) {
2402 return (EFI_INVALID_PARAMETER
);
2405 if (*Path
== L
'.' && *(Path
+1) == L
'\\') {
2410 // convert a local path to an absolute path
2412 if (StrStr(Path
, L
":") == NULL
) {
2413 CurDir
= EfiShellGetCurDir(NULL
);
2414 ASSERT((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
2415 StrnCatGrow(&Path2
, &Path2Size
, CurDir
, 0);
2416 if (*Path
== L
'\\') {
2418 while (PathRemoveLastItem(Path2
)) ;
2420 ASSERT((Path2
== NULL
&& Path2Size
== 0) || (Path2
!= NULL
));
2421 StrnCatGrow(&Path2
, &Path2Size
, Path
, 0);
2423 ASSERT(Path2
== NULL
);
2424 StrnCatGrow(&Path2
, NULL
, Path
, 0);
2427 PathCleanUpDirectories (Path2
);
2432 Status
= EfiShellFindFiles(Path2
, FileList
);
2436 if (EFI_ERROR(Status
)) {
2442 // We had no errors so open all the files (that are not already opened...)
2444 for ( ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&(*FileList
)->Link
)
2445 ; !IsNull(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
2446 ; ShellFileListItem
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&(*FileList
)->Link
, &ShellFileListItem
->Link
)
2448 if (ShellFileListItem
->Status
== 0 && ShellFileListItem
->Handle
== NULL
) {
2449 ShellFileListItem
->Status
= EfiShellOpenFileByName (ShellFileListItem
->FullName
, &ShellFileListItem
->Handle
, OpenMode
);
2455 return (EFI_NOT_FOUND
);
2457 return(EFI_SUCCESS
);
2461 This function updated with errata.
2463 Gets either a single or list of environment variables.
2465 If name is not NULL then this function returns the current value of the specified
2466 environment variable.
2468 If Name is NULL, then a list of all environment variable names is returned. Each is a
2469 NULL terminated string with a double NULL terminating the list.
2471 @param Name A pointer to the environment variable name. If
2472 Name is NULL, then the function will return all
2473 of the defined shell environment variables. In
2474 the case where multiple environment variables are
2475 being returned, each variable will be terminated by
2476 a NULL, and the list will be terminated by a double
2479 @return !=NULL A pointer to the returned string.
2480 The returned pointer does not need to be freed by the caller.
2482 @retval NULL The environment variable doesn't exist or there are
2483 no environment variables.
2488 IN CONST CHAR16
*Name
2496 CHAR16
*CurrentWriteLocation
;
2503 // Get all our environment variables
2505 InitializeListHead(&List
);
2506 Status
= GetEnvironmentVariableList(&List
);
2507 if (EFI_ERROR(Status
)){
2512 // Build the semi-colon delimited list. (2 passes)
2514 for ( Node
= (ENV_VAR_LIST
*)GetFirstNode(&List
)
2515 ; !IsNull(&List
, &Node
->Link
)
2516 ; Node
= (ENV_VAR_LIST
*)GetNextNode(&List
, &Node
->Link
)
2518 ASSERT(Node
->Key
!= NULL
);
2519 Size
+= StrSize(Node
->Key
);
2522 Size
+= 2*sizeof(CHAR16
);
2524 Buffer
= AllocateZeroPool(Size
);
2525 if (Buffer
== NULL
) {
2526 if (!IsListEmpty (&List
)) {
2527 FreeEnvironmentVariableList(&List
);
2531 CurrentWriteLocation
= (CHAR16
*)Buffer
;
2533 for ( Node
= (ENV_VAR_LIST
*)GetFirstNode(&List
)
2534 ; !IsNull(&List
, &Node
->Link
)
2535 ; Node
= (ENV_VAR_LIST
*)GetNextNode(&List
, &Node
->Link
)
2537 ASSERT(Node
->Key
!= NULL
);
2538 StrCpy(CurrentWriteLocation
, Node
->Key
);
2539 CurrentWriteLocation
+= StrLen(CurrentWriteLocation
) + 1;
2545 if (!IsListEmpty (&List
)) {
2546 FreeEnvironmentVariableList(&List
);
2550 // We are doing a specific environment variable
2554 // get the size we need for this EnvVariable
2556 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(Name
, &Size
, Buffer
);
2557 if (Status
== EFI_BUFFER_TOO_SMALL
) {
2559 // Allocate the space and recall the get function
2561 Buffer
= AllocateZeroPool(Size
);
2562 ASSERT(Buffer
!= NULL
);
2563 Status
= SHELL_GET_ENVIRONMENT_VARIABLE(Name
, &Size
, Buffer
);
2566 // we didnt get it (might not exist)
2567 // free the memory if we allocated any and return NULL
2569 if (EFI_ERROR(Status
)) {
2570 if (Buffer
!= NULL
) {
2578 // return the buffer
2580 return (AddBufferToFreeList(Buffer
));
2584 Internal variable setting function. Allows for setting of the read only variables.
2586 @param Name Points to the NULL-terminated environment variable name.
2587 @param Value Points to the NULL-terminated environment variable value. If the value is an
2588 empty string then the environment variable is deleted.
2589 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
2591 @retval EFI_SUCCESS The environment variable was successfully updated.
2595 InternalEfiShellSetEnv(
2596 IN CONST CHAR16
*Name
,
2597 IN CONST CHAR16
*Value
,
2601 if (Value
== NULL
|| StrLen(Value
) == 0) {
2602 return (SHELL_DELETE_ENVIRONMENT_VARIABLE(Name
));
2604 SHELL_DELETE_ENVIRONMENT_VARIABLE(Name
);
2606 return (SHELL_SET_ENVIRONMENT_VARIABLE_V(Name
, StrSize(Value
), Value
));
2608 return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(Name
, StrSize(Value
), Value
));
2614 Sets the environment variable.
2616 This function changes the current value of the specified environment variable. If the
2617 environment variable exists and the Value is an empty string, then the environment
2618 variable is deleted. If the environment variable exists and the Value is not an empty
2619 string, then the value of the environment variable is changed. If the environment
2620 variable does not exist and the Value is an empty string, there is no action. If the
2621 environment variable does not exist and the Value is a non-empty string, then the
2622 environment variable is created and assigned the specified value.
2624 For a description of volatile and non-volatile environment variables, see UEFI Shell
2625 2.0 specification section 3.6.1.
2627 @param Name Points to the NULL-terminated environment variable name.
2628 @param Value Points to the NULL-terminated environment variable value. If the value is an
2629 empty string then the environment variable is deleted.
2630 @param Volatile Indicates whether the variable is non-volatile (FALSE) or volatile (TRUE).
2632 @retval EFI_SUCCESS The environment variable was successfully updated.
2637 IN CONST CHAR16
*Name
,
2638 IN CONST CHAR16
*Value
,
2642 if (Name
== NULL
|| *Name
== CHAR_NULL
) {
2643 return (EFI_INVALID_PARAMETER
);
2646 // Make sure we dont 'set' a predefined read only variable
2648 if (gUnicodeCollation
->StriColl(
2652 ||gUnicodeCollation
->StriColl(
2656 ||gUnicodeCollation
->StriColl(
2660 ||gUnicodeCollation
->StriColl(
2663 L
"uefishellsupport") == 0
2664 ||gUnicodeCollation
->StriColl(
2667 L
"uefishellversion") == 0
2668 ||gUnicodeCollation
->StriColl(
2671 L
"uefiversion") == 0
2673 return (EFI_INVALID_PARAMETER
);
2675 return (InternalEfiShellSetEnv(Name
, Value
, Volatile
));
2679 Returns the current directory on the specified device.
2681 If FileSystemMapping is NULL, it returns the current working directory. If the
2682 FileSystemMapping is not NULL, it returns the current directory associated with the
2683 FileSystemMapping. In both cases, the returned name includes the file system
2684 mapping (i.e. fs0:\current-dir).
2686 @param FileSystemMapping A pointer to the file system mapping. If NULL,
2687 then the current working directory is returned.
2689 @retval !=NULL The current directory.
2690 @retval NULL Current directory does not exist.
2695 IN CONST CHAR16
*FileSystemMapping OPTIONAL
2698 CHAR16
*PathToReturn
;
2700 SHELL_MAP_LIST
*MapListItem
;
2701 if (!IsListEmpty(&gShellMapList
.Link
)) {
2703 // if parameter is NULL, use current
2705 if (FileSystemMapping
== NULL
) {
2706 return (EfiShellGetEnv(L
"cwd"));
2709 PathToReturn
= NULL
;
2710 MapListItem
= ShellCommandFindMapItem(FileSystemMapping
);
2711 if (MapListItem
!= NULL
) {
2712 ASSERT((PathToReturn
== NULL
&& Size
== 0) || (PathToReturn
!= NULL
));
2713 PathToReturn
= StrnCatGrow(&PathToReturn
, &Size
, MapListItem
->MapName
, 0);
2714 PathToReturn
= StrnCatGrow(&PathToReturn
, &Size
, MapListItem
->CurrentDirectoryPath
, 0);
2717 return (AddBufferToFreeList(PathToReturn
));
2724 Changes the current directory on the specified device.
2726 If the FileSystem is NULL, and the directory Dir does not contain a file system's
2727 mapped name, this function changes the current working directory.
2729 If the FileSystem is NULL and the directory Dir contains a mapped name, then the
2730 current file system and the current directory on that file system are changed.
2732 If FileSystem is NULL, and Dir is not NULL, then this changes the current working file
2735 If FileSystem is not NULL and Dir is not NULL, then this function changes the current
2736 directory on the specified file system.
2738 If the current working directory or the current working file system is changed then the
2739 %cwd% environment variable will be updated
2741 @param FileSystem A pointer to the file system's mapped name. If NULL, then the current working
2742 directory is changed.
2743 @param Dir Points to the NULL-terminated directory on the device specified by FileSystem.
2745 @retval EFI_SUCCESS The operation was sucessful
2746 @retval EFI_NOT_FOUND The file system could not be found
2751 IN CONST CHAR16
*FileSystem OPTIONAL
,
2752 IN CONST CHAR16
*Dir
2756 SHELL_MAP_LIST
*MapListItem
;
2760 CHAR16
*DirectoryName
;
2767 DirectoryName
= NULL
;
2769 if ((FileSystem
== NULL
&& Dir
== NULL
) || Dir
== NULL
) {
2770 return (EFI_INVALID_PARAMETER
);
2773 if (IsListEmpty(&gShellMapList
.Link
)){
2774 return (EFI_NOT_FOUND
);
2777 DirectoryName
= StrnCatGrow(&DirectoryName
, NULL
, Dir
, 0);
2778 ASSERT(DirectoryName
!= NULL
);
2780 PathCleanUpDirectories(DirectoryName
);
2782 if (FileSystem
== NULL
) {
2784 // determine the file system mapping to use
2786 if (StrStr(DirectoryName
, L
":") != NULL
) {
2787 ASSERT(MapName
== NULL
);
2788 MapName
= StrnCatGrow(&MapName
, NULL
, DirectoryName
, (StrStr(DirectoryName
, L
":")-DirectoryName
+1));
2791 // find the file system mapping's entry in the list
2794 if (MapName
!= NULL
) {
2795 MapListItem
= ShellCommandFindMapItem(MapName
);
2798 // make that the current file system mapping
2800 if (MapListItem
!= NULL
) {
2801 gShellCurDir
= MapListItem
;
2804 MapListItem
= gShellCurDir
;
2807 if (MapListItem
== NULL
) {
2808 return (EFI_NOT_FOUND
);
2812 // now update the MapListItem's current directory
2814 if (MapListItem
->CurrentDirectoryPath
!= NULL
&& DirectoryName
[StrLen(DirectoryName
) - 1] != L
':') {
2815 FreePool(MapListItem
->CurrentDirectoryPath
);
2816 MapListItem
->CurrentDirectoryPath
= NULL
;
2818 if (MapName
!= NULL
) {
2819 TempLen
= StrLen(MapName
);
2820 if (TempLen
!= StrLen(DirectoryName
)) {
2821 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2822 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
+StrLen(MapName
), 0);
2825 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2826 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
, 0);
2828 if ((MapListItem
->CurrentDirectoryPath
!= NULL
&& MapListItem
->CurrentDirectoryPath
[StrLen(MapListItem
->CurrentDirectoryPath
)-1] != L
'\\') || (MapListItem
->CurrentDirectoryPath
== NULL
)) {
2829 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2830 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, L
"\\", 0);
2834 // cant have a mapping in the directory...
2836 if (StrStr(DirectoryName
, L
":") != NULL
) {
2837 return (EFI_INVALID_PARAMETER
);
2840 // FileSystem != NULL
2842 MapListItem
= ShellCommandFindMapItem(FileSystem
);
2843 if (MapListItem
== NULL
) {
2844 return (EFI_INVALID_PARAMETER
);
2846 // gShellCurDir = MapListItem;
2847 if (DirectoryName
!= NULL
) {
2849 // change current dir on that file system
2852 if (MapListItem
->CurrentDirectoryPath
!= NULL
) {
2853 FreePool(MapListItem
->CurrentDirectoryPath
);
2854 DEBUG_CODE(MapListItem
->CurrentDirectoryPath
= NULL
;);
2856 // ASSERT((MapListItem->CurrentDirectoryPath == NULL && Size == 0) || (MapListItem->CurrentDirectoryPath != NULL));
2857 // MapListItem->CurrentDirectoryPath = StrnCatGrow(&MapListItem->CurrentDirectoryPath, &Size, FileSystem, 0);
2858 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2859 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, L
"\\", 0);
2860 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2861 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, DirectoryName
, 0);
2862 if (MapListItem
->CurrentDirectoryPath
!= NULL
&& MapListItem
->CurrentDirectoryPath
[StrLen(MapListItem
->CurrentDirectoryPath
)-1] != L
'\\') {
2863 ASSERT((MapListItem
->CurrentDirectoryPath
== NULL
&& Size
== 0) || (MapListItem
->CurrentDirectoryPath
!= NULL
));
2864 MapListItem
->CurrentDirectoryPath
= StrnCatGrow(&MapListItem
->CurrentDirectoryPath
, &Size
, L
"\\", 0);
2869 // if updated the current directory then update the environment variable
2871 if (MapListItem
== gShellCurDir
) {
2873 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
2874 StrnCatGrow(&TempString
, &Size
, MapListItem
->MapName
, 0);
2875 ASSERT((TempString
== NULL
&& Size
== 0) || (TempString
!= NULL
));
2876 StrnCatGrow(&TempString
, &Size
, MapListItem
->CurrentDirectoryPath
, 0);
2877 Status
= InternalEfiShellSetEnv(L
"cwd", TempString
, TRUE
);
2878 FreePool(TempString
);
2881 return(EFI_SUCCESS
);
2885 Return help information about a specific command.
2887 This function returns the help information for the specified command. The help text
2888 can be internal to the shell or can be from a UEFI Shell manual page.
2890 If Sections is specified, then each section name listed will be compared in a casesensitive
2891 manner, to the section names described in Appendix B. If the section exists,
2892 it will be appended to the returned help text. If the section does not exist, no
2893 information will be returned. If Sections is NULL, then all help text information
2894 available will be returned.
2896 @param Command Points to the NULL-terminated UEFI Shell command name.
2897 @param Sections Points to the NULL-terminated comma-delimited
2898 section names to return. If NULL, then all
2899 sections will be returned.
2900 @param HelpText On return, points to a callee-allocated buffer
2901 containing all specified help text.
2903 @retval EFI_SUCCESS The help text was returned.
2904 @retval EFI_OUT_OF_RESOURCES The necessary buffer could not be allocated to hold the
2906 @retval EFI_INVALID_PARAMETER HelpText is NULL
2907 @retval EFI_NOT_FOUND There is no help text available for Command.
2911 EfiShellGetHelpText(
2912 IN CONST CHAR16
*Command
,
2913 IN CONST CHAR16
*Sections OPTIONAL
,
2914 OUT CHAR16
**HelpText
2917 CONST CHAR16
*ManFileName
;
2921 ASSERT(HelpText
!= NULL
);
2924 ManFileName
= ShellCommandGetManFileNameHandler(Command
);
2926 if (ManFileName
!= NULL
) {
2927 return (ProcessManFile(ManFileName
, Command
, Sections
, NULL
, HelpText
));
2929 if ((StrLen(Command
)> 4)
2930 && (Command
[StrLen(Command
)-1] == L
'i' || Command
[StrLen(Command
)-1] == L
'I')
2931 && (Command
[StrLen(Command
)-2] == L
'f' || Command
[StrLen(Command
)-2] == L
'F')
2932 && (Command
[StrLen(Command
)-3] == L
'e' || Command
[StrLen(Command
)-3] == L
'E')
2933 && (Command
[StrLen(Command
)-4] == L
'.')
2935 FixCommand
= AllocateZeroPool(StrSize(Command
) - 4 * sizeof (CHAR16
));
2936 ASSERT(FixCommand
!= NULL
);
2938 StrnCpy(FixCommand
, Command
, StrLen(Command
)-4);
2939 Status
= ProcessManFile(FixCommand
, FixCommand
, Sections
, NULL
, HelpText
);
2940 FreePool(FixCommand
);
2943 return (ProcessManFile(Command
, Command
, Sections
, NULL
, HelpText
));
2949 Gets the enable status of the page break output mode.
2951 User can use this function to determine current page break mode.
2953 @retval TRUE The page break output mode is enabled.
2954 @retval FALSE The page break output mode is disabled.
2958 EfiShellGetPageBreak(
2962 return(ShellInfoObject
.PageBreakEnabled
);
2966 Judges whether the active shell is the root shell.
2968 This function makes the user to know that whether the active Shell is the root shell.
2970 @retval TRUE The active Shell is the root Shell.
2971 @retval FALSE The active Shell is NOT the root Shell.
2975 EfiShellIsRootShell(
2979 return(ShellInfoObject
.RootShellInstance
);
2983 function to return a semi-colon delimeted list of all alias' in the current shell
2985 up to caller to free the memory.
2987 @retval NULL No alias' were found
2988 @retval NULL An error ocurred getting alias'
2989 @return !NULL a list of all alias'
2993 InternalEfiShellGetListAlias(
3001 CHAR16
*VariableName
;
3006 Status
= gRT
->QueryVariableInfo(EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
, &MaxStorSize
, &RemStorSize
, &MaxVarSize
);
3007 ASSERT_EFI_ERROR(Status
);
3009 VariableName
= AllocateZeroPool((UINTN
)MaxVarSize
);
3013 if (VariableName
== NULL
) {
3017 VariableName
[0] = CHAR_NULL
;
3020 NameSize
= (UINTN
)MaxVarSize
;
3021 Status
= gRT
->GetNextVariableName(&NameSize
, VariableName
, &Guid
);
3022 if (Status
== EFI_NOT_FOUND
){
3025 ASSERT_EFI_ERROR(Status
);
3026 if (EFI_ERROR(Status
)) {
3029 if (CompareGuid(&Guid
, &gShellAliasGuid
)){
3030 ASSERT((RetVal
== NULL
&& RetSize
== 0) || (RetVal
!= NULL
));
3031 RetVal
= StrnCatGrow(&RetVal
, &RetSize
, VariableName
, 0);
3032 RetVal
= StrnCatGrow(&RetVal
, &RetSize
, L
";", 0);
3035 FreePool(VariableName
);
3041 Convert a null-terminated unicode string, in-place, to all lowercase.
3044 @param Str The null-terminated string to be converted to all lowercase.
3046 @return The null-terminated string converted into all lowercase.
3055 for (Index
= 0; Str
[Index
] != L
'\0'; Index
++) {
3056 if (Str
[Index
] >= L
'A' && Str
[Index
] <= L
'Z') {
3057 Str
[Index
] -= (CHAR16
)(L
'A' - L
'a');
3064 This function returns the command associated with a alias or a list of all
3067 @param[in] Alias Points to the NULL-terminated shell alias.
3068 If this parameter is NULL, then all
3069 aliases will be returned in ReturnedData.
3070 @param[out] Volatile upon return of a single command if TRUE indicates
3071 this is stored in a volatile fashion. FALSE otherwise.
3073 @return If Alias is not NULL, it will return a pointer to
3074 the NULL-terminated command for that alias.
3075 If Alias is NULL, ReturnedData points to a ';'
3076 delimited list of alias (e.g.
3077 ReturnedData = "dir;del;copy;mfp") that is NULL-terminated.
3078 @retval NULL an error ocurred
3079 @retval NULL Alias was not a valid Alias
3084 IN CONST CHAR16
*Alias
,
3085 OUT BOOLEAN
*Volatile OPTIONAL
3094 // Convert to lowercase to make aliases case-insensitive
3095 if (Alias
!= NULL
) {
3096 AliasLower
= AllocateCopyPool (StrSize (Alias
), Alias
);
3097 ASSERT (AliasLower
!= NULL
);
3098 ToLower (AliasLower
);
3100 if (Volatile
== NULL
) {
3101 return (AddBufferToFreeList(GetVariable(AliasLower
, &gShellAliasGuid
)));
3105 Status
= gRT
->GetVariable(AliasLower
, &gShellAliasGuid
, &Attribs
, &RetSize
, RetVal
);
3106 if (Status
== EFI_BUFFER_TOO_SMALL
) {
3107 RetVal
= AllocateZeroPool(RetSize
);
3108 Status
= gRT
->GetVariable(AliasLower
, &gShellAliasGuid
, &Attribs
, &RetSize
, RetVal
);
3110 if (EFI_ERROR(Status
)) {
3111 if (RetVal
!= NULL
) {
3116 if ((EFI_VARIABLE_NON_VOLATILE
& Attribs
) == EFI_VARIABLE_NON_VOLATILE
) {
3122 FreePool (AliasLower
);
3123 return (AddBufferToFreeList(RetVal
));
3125 return (AddBufferToFreeList(InternalEfiShellGetListAlias()));
3129 Changes a shell command alias.
3131 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.
3133 this function does not check for built in alias'.
3135 @param[in] Command Points to the NULL-terminated shell command or existing alias.
3136 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and
3137 Command refers to an alias, that alias will be deleted.
3138 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the
3139 Alias being set will be stored in a non-volatile fashion.
3141 @retval EFI_SUCCESS Alias created or deleted successfully.
3142 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found
3147 IN CONST CHAR16
*Command
,
3148 IN CONST CHAR16
*Alias
,
3155 // Convert to lowercase to make aliases case-insensitive
3156 if (Alias
!= NULL
) {
3157 AliasLower
= AllocateCopyPool (StrSize (Alias
), Alias
);
3158 ASSERT (AliasLower
!= NULL
);
3159 ToLower (AliasLower
);
3165 // We must be trying to remove one if Alias is NULL
3167 if (Alias
== NULL
) {
3169 // remove an alias (but passed in COMMAND parameter)
3171 Status
= (gRT
->SetVariable((CHAR16
*)Command
, &gShellAliasGuid
, 0, 0, NULL
));
3174 // Add and replace are the same
3177 // We dont check the error return on purpose since the variable may not exist.
3178 gRT
->SetVariable((CHAR16
*)Command
, &gShellAliasGuid
, 0, 0, NULL
);
3180 Status
= (gRT
->SetVariable((CHAR16
*)Alias
, &gShellAliasGuid
, EFI_VARIABLE_BOOTSERVICE_ACCESS
|(Volatile
?0:EFI_VARIABLE_NON_VOLATILE
), StrSize(Command
), (VOID
*)Command
));
3183 if (Alias
!= NULL
) {
3184 FreePool (AliasLower
);
3190 Changes a shell command alias.
3192 This function creates an alias for a shell command or if Alias is NULL it will delete an existing alias.
3195 @param[in] Command Points to the NULL-terminated shell command or existing alias.
3196 @param[in] Alias Points to the NULL-terminated alias for the shell command. If this is NULL, and
3197 Command refers to an alias, that alias will be deleted.
3198 @param[in] Replace If TRUE and the alias already exists, then the existing alias will be replaced. If
3199 FALSE and the alias already exists, then the existing alias is unchanged and
3200 EFI_ACCESS_DENIED is returned.
3201 @param[in] Volatile if TRUE the Alias being set will be stored in a volatile fashion. if FALSE the
3202 Alias being set will be stored in a non-volatile fashion.
3204 @retval EFI_SUCCESS Alias created or deleted successfully.
3205 @retval EFI_NOT_FOUND the Alias intended to be deleted was not found
3206 @retval EFI_ACCESS_DENIED The alias is a built-in alias or already existed and Replace was set to
3208 @retval EFI_INVALID_PARAMETER Command is null or the empty string.
3213 IN CONST CHAR16
*Command
,
3214 IN CONST CHAR16
*Alias
,
3219 if (ShellCommandIsOnAliasList(Alias
==NULL
?Command
:Alias
)) {
3221 // cant set over a built in alias
3223 return (EFI_ACCESS_DENIED
);
3224 } else if (Command
== NULL
|| *Command
== CHAR_NULL
|| StrLen(Command
) == 0) {
3226 // Command is null or empty
3228 return (EFI_INVALID_PARAMETER
);
3229 } else if (EfiShellGetAlias(Command
, NULL
) != NULL
&& !Replace
) {
3231 // Alias already exists, Replace not set
3233 return (EFI_ACCESS_DENIED
);
3235 return (InternalSetAlias(Command
, Alias
, Volatile
));
3239 // Pure FILE_HANDLE operations are passed to FileHandleLib
3240 // these functions are indicated by the *
3241 EFI_SHELL_PROTOCOL mShellProtocol
= {
3247 EfiShellGetHelpText
,
3248 EfiShellGetDevicePathFromMap
,
3249 EfiShellGetMapFromDevicePath
,
3250 EfiShellGetDevicePathFromFilePath
,
3251 EfiShellGetFilePathFromDevicePath
,
3255 EfiShellOpenFileList
,
3256 EfiShellFreeFileList
,
3257 EfiShellRemoveDupInFileList
,
3258 EfiShellBatchIsActive
,
3259 EfiShellIsRootShell
,
3260 EfiShellEnablePageBreak
,
3261 EfiShellDisablePageBreak
,
3262 EfiShellGetPageBreak
,
3263 EfiShellGetDeviceName
,
3264 (EFI_SHELL_GET_FILE_INFO
)FileHandleGetInfo
, //*
3265 (EFI_SHELL_SET_FILE_INFO
)FileHandleSetInfo
, //*
3266 EfiShellOpenFileByName
,
3269 (EFI_SHELL_READ_FILE
)FileHandleRead
, //*
3270 (EFI_SHELL_WRITE_FILE
)FileHandleWrite
, //*
3271 (EFI_SHELL_DELETE_FILE
)FileHandleDelete
, //*
3272 EfiShellDeleteFileByName
,
3273 (EFI_SHELL_GET_FILE_POSITION
)FileHandleGetPosition
, //*
3274 (EFI_SHELL_SET_FILE_POSITION
)FileHandleSetPosition
, //*
3275 (EFI_SHELL_FLUSH_FILE
)FileHandleFlush
, //*
3277 EfiShellFindFilesInDir
,
3278 (EFI_SHELL_GET_FILE_SIZE
)FileHandleGetSize
, //*
3280 EfiShellOpenRootByHandle
,
3282 SHELL_MAJOR_VERSION
,
3287 Function to create and install on the current handle.
3289 Will overwrite any existing ShellProtocols in the system to be sure that
3290 the current shell is in control.
3292 This must be removed via calling CleanUpShellProtocol().
3294 @param[in, out] NewShell The pointer to the pointer to the structure
3297 @retval EFI_SUCCESS The operation was successful.
3298 @return An error from LocateHandle, CreateEvent, or other core function.
3302 CreatePopulateInstallShellProtocol (
3303 IN OUT EFI_SHELL_PROTOCOL
**NewShell
3309 UINTN HandleCounter
;
3310 SHELL_PROTOCOL_HANDLE_LIST
*OldProtocolNode
;
3312 if (NewShell
== NULL
) {
3313 return (EFI_INVALID_PARAMETER
);
3318 OldProtocolNode
= NULL
;
3319 InitializeListHead(&ShellInfoObject
.OldShellList
.Link
);
3322 // Initialize EfiShellProtocol object...
3324 Status
= gBS
->CreateEvent(0,
3328 &mShellProtocol
.ExecutionBreak
);
3329 if (EFI_ERROR(Status
)) {
3334 // Get the size of the buffer we need.
3336 Status
= gBS
->LocateHandle(ByProtocol
,
3337 &gEfiShellProtocolGuid
,
3341 if (Status
== EFI_BUFFER_TOO_SMALL
) {
3343 // Allocate and recall with buffer of correct size
3345 Buffer
= AllocateZeroPool(BufferSize
);
3346 if (Buffer
== NULL
) {
3347 return (EFI_OUT_OF_RESOURCES
);
3349 Status
= gBS
->LocateHandle(ByProtocol
,
3350 &gEfiShellProtocolGuid
,
3354 if (EFI_ERROR(Status
)) {
3359 // now overwrite each of them, but save the info to restore when we end.
3361 for (HandleCounter
= 0 ; HandleCounter
< (BufferSize
/sizeof(EFI_HANDLE
)) ; HandleCounter
++) {
3362 OldProtocolNode
= AllocateZeroPool(sizeof(SHELL_PROTOCOL_HANDLE_LIST
));
3363 ASSERT(OldProtocolNode
!= NULL
);
3364 Status
= gBS
->OpenProtocol(Buffer
[HandleCounter
],
3365 &gEfiShellProtocolGuid
,
3366 (VOID
**) &(OldProtocolNode
->Interface
),
3369 EFI_OPEN_PROTOCOL_GET_PROTOCOL
3371 if (!EFI_ERROR(Status
)) {
3373 // reinstall over the old one...
3375 OldProtocolNode
->Handle
= Buffer
[HandleCounter
];
3376 Status
= gBS
->ReinstallProtocolInterface(
3377 OldProtocolNode
->Handle
,
3378 &gEfiShellProtocolGuid
,
3379 OldProtocolNode
->Interface
,
3380 (VOID
*)(&mShellProtocol
));
3381 if (!EFI_ERROR(Status
)) {
3383 // we reinstalled sucessfully. log this so we can reverse it later.
3387 // add to the list for subsequent...
3389 InsertTailList(&ShellInfoObject
.OldShellList
.Link
, &OldProtocolNode
->Link
);
3394 } else if (Status
== EFI_NOT_FOUND
) {
3395 ASSERT(IsListEmpty(&ShellInfoObject
.OldShellList
.Link
));
3397 // no one else published yet. just publish it ourselves.
3399 Status
= gBS
->InstallProtocolInterface (
3401 &gEfiShellProtocolGuid
,
3402 EFI_NATIVE_INTERFACE
,
3403 (VOID
*)(&mShellProtocol
));
3406 if (PcdGetBool(PcdShellSupportOldProtocols
)){
3407 ///@todo support ShellEnvironment2
3408 ///@todo do we need to support ShellEnvironment (not ShellEnvironment2) also?
3411 if (!EFI_ERROR(Status
)) {
3412 *NewShell
= &mShellProtocol
;
3418 Opposite of CreatePopulateInstallShellProtocol.
3420 Free all memory and restore the system to the state it was in before calling
3421 CreatePopulateInstallShellProtocol.
3423 @param[in, out] NewShell The pointer to the new shell protocol structure.
3425 @retval EFI_SUCCESS The operation was successful.
3429 CleanUpShellProtocol (
3430 IN OUT EFI_SHELL_PROTOCOL
*NewShell
3434 SHELL_PROTOCOL_HANDLE_LIST
*Node2
;
3435 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleEx
;
3438 // if we need to restore old protocols...
3440 if (!IsListEmpty(&ShellInfoObject
.OldShellList
.Link
)) {
3441 for (Node2
= (SHELL_PROTOCOL_HANDLE_LIST
*)GetFirstNode(&ShellInfoObject
.OldShellList
.Link
)
3442 ; !IsListEmpty (&ShellInfoObject
.OldShellList
.Link
)
3443 ; Node2
= (SHELL_PROTOCOL_HANDLE_LIST
*)GetFirstNode(&ShellInfoObject
.OldShellList
.Link
)
3445 RemoveEntryList(&Node2
->Link
);
3446 Status
= gBS
->ReinstallProtocolInterface(Node2
->Handle
,
3447 &gEfiShellProtocolGuid
,
3454 // no need to restore
3456 Status
= gBS
->UninstallProtocolInterface(gImageHandle
,
3457 &gEfiShellProtocolGuid
,
3460 Status
= gBS
->CloseEvent(NewShell
->ExecutionBreak
);
3461 NewShell
->ExecutionBreak
= NULL
;
3463 Status
= gBS
->OpenProtocol(
3464 gST
->ConsoleInHandle
,
3465 &gEfiSimpleTextInputExProtocolGuid
,
3469 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
3471 if (!EFI_ERROR (Status
)) {
3472 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle1
);
3473 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle2
);
3474 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle3
);
3475 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlCNotifyHandle4
);
3476 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle1
);
3477 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle2
);
3478 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle3
);
3479 Status
= SimpleEx
->UnregisterKeyNotify(SimpleEx
, ShellInfoObject
.CtrlSNotifyHandle4
);
3485 Notification function for keystrokes.
3487 @param[in] KeyData The key that was pressed.
3489 @retval EFI_SUCCESS The operation was successful.
3493 NotificationFunction(
3494 IN EFI_KEY_DATA
*KeyData
3497 if ( ((KeyData
->Key
.UnicodeChar
== L
'c') &&
3498 (KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
) || KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
))) ||
3499 (KeyData
->Key
.UnicodeChar
== 3)
3501 if (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
== NULL
) {
3502 return (EFI_UNSUPPORTED
);
3504 return (gBS
->SignalEvent(ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
));
3505 } else if ((KeyData
->Key
.UnicodeChar
== L
's') &&
3506 (KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
) || KeyData
->KeyState
.KeyShiftState
== (EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
))
3508 ShellInfoObject
.HaltOutput
= TRUE
;
3510 return (EFI_SUCCESS
);
3514 Function to start monitoring for CTRL-C using SimpleTextInputEx. This
3515 feature's enabled state was not known when the shell initially launched.
3517 @retval EFI_SUCCESS The feature is enabled.
3518 @retval EFI_OUT_OF_RESOURCES There is not enough mnemory available.
3522 InernalEfiShellStartMonitor(
3526 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*SimpleEx
;
3527 EFI_KEY_DATA KeyData
;
3530 Status
= gBS
->OpenProtocol(
3531 gST
->ConsoleInHandle
,
3532 &gEfiSimpleTextInputExProtocolGuid
,
3536 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
3537 if (EFI_ERROR(Status
)) {
3542 STRING_TOKEN (STR_SHELL_NO_IN_EX
),
3543 ShellInfoObject
.HiiHandle
);
3544 return (EFI_SUCCESS
);
3547 if (ShellInfoObject
.NewEfiShellProtocol
->ExecutionBreak
== NULL
) {
3548 return (EFI_UNSUPPORTED
);
3551 KeyData
.KeyState
.KeyToggleState
= 0;
3552 KeyData
.Key
.ScanCode
= 0;
3553 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
3554 KeyData
.Key
.UnicodeChar
= L
'c';
3556 Status
= SimpleEx
->RegisterKeyNotify(
3559 NotificationFunction
,
3560 &ShellInfoObject
.CtrlCNotifyHandle1
);
3562 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
3563 if (!EFI_ERROR(Status
)) {
3564 Status
= SimpleEx
->RegisterKeyNotify(
3567 NotificationFunction
,
3568 &ShellInfoObject
.CtrlCNotifyHandle2
);
3570 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_LEFT_CONTROL_PRESSED
;
3571 KeyData
.Key
.UnicodeChar
= 3;
3572 if (!EFI_ERROR(Status
)) {
3573 Status
= SimpleEx
->RegisterKeyNotify(
3576 NotificationFunction
,
3577 &ShellInfoObject
.CtrlCNotifyHandle3
);
3579 KeyData
.KeyState
.KeyShiftState
= EFI_SHIFT_STATE_VALID
|EFI_RIGHT_CONTROL_PRESSED
;
3580 if (!EFI_ERROR(Status
)) {
3581 Status
= SimpleEx
->RegisterKeyNotify(
3584 NotificationFunction
,
3585 &ShellInfoObject
.CtrlCNotifyHandle4
);