/** @file | |
Main file for map shell level 2 command. | |
(C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR> | |
Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR> | |
This program and the accompanying materials | |
are licensed and made available under the terms and conditions of the BSD License | |
which accompanies this distribution. The full text of the license may be found at | |
http://opensource.org/licenses/bsd-license.php | |
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
**/ | |
#include "UefiShellLevel2CommandsLib.h" | |
#include <Protocol/SimpleFileSystem.h> | |
#include <Protocol/BlockIo.h> | |
#include <Library/DevicePathLib.h> | |
#include <Library/HandleParsingLib.h> | |
#include <Library/SortLib.h> | |
/** | |
Determine if a string has only numbers and letters. | |
This is useful for such things as Map names which can only be letters and numbers. | |
@param[in] String pointer to the string to analyze, | |
@param[in] Len Number of characters to analyze. | |
@retval TRUE String has only numbers and letters | |
@retval FALSE String has at least one other character. | |
**/ | |
BOOLEAN | |
EFIAPI | |
IsNumberLetterOnly( | |
IN CONST CHAR16 *String, | |
IN CONST UINTN Len | |
) | |
{ | |
UINTN Count; | |
for (Count = 0 ; Count < Len && String != NULL && *String != CHAR_NULL ; String++,Count++) { | |
if (! ((*String >= L'a' && *String <= L'z') || | |
(*String >= L'A' && *String <= L'Z') || | |
(*String >= L'0' && *String <= L'9')) | |
){ | |
return (FALSE); | |
} | |
} | |
return (TRUE); | |
} | |
/** | |
Do a search in the Target delimited list. | |
@param[in] List The list to seatch in. | |
@param[in] MetaTarget The item to search for. MetaMatching supported. | |
@param[out] FullName Optional pointer to an allocated buffer containing | |
the match. | |
@param[in] Meta TRUE to use MetaMatching. | |
@param[in] SkipTrailingNumbers TRUE to allow for numbers after the MetaTarget. | |
@param[in] Target The single character that delimits list | |
items (";" normally). | |
**/ | |
BOOLEAN | |
EFIAPI | |
SearchList( | |
IN CONST CHAR16 *List, | |
IN CONST CHAR16 *MetaTarget, | |
OUT CHAR16 **FullName OPTIONAL, | |
IN CONST BOOLEAN Meta, | |
IN CONST BOOLEAN SkipTrailingNumbers, | |
IN CONST CHAR16 *Target | |
) | |
{ | |
CHAR16 *TempList; | |
CONST CHAR16 *ListWalker; | |
BOOLEAN Result; | |
CHAR16 *TempSpot; | |
for (ListWalker = List , TempList = NULL | |
; ListWalker != NULL && *ListWalker != CHAR_NULL | |
; | |
) { | |
TempList = StrnCatGrow(&TempList, NULL, ListWalker, 0); | |
ASSERT(TempList != NULL); | |
TempSpot = StrStr(TempList, Target); | |
if (TempSpot != NULL) { | |
*TempSpot = CHAR_NULL; | |
} | |
while (SkipTrailingNumbers && (ShellIsDecimalDigitCharacter(TempList[StrLen(TempList)-1]) || TempList[StrLen(TempList)-1] == L':')) { | |
TempList[StrLen(TempList)-1] = CHAR_NULL; | |
} | |
ListWalker = StrStr(ListWalker, Target); | |
while(ListWalker != NULL && *ListWalker == *Target) { | |
ListWalker++; | |
} | |
if (Meta) { | |
Result = gUnicodeCollation->MetaiMatch(gUnicodeCollation, (CHAR16*)TempList, (CHAR16*)MetaTarget); | |
} else { | |
Result = (BOOLEAN)(StrCmp(TempList, MetaTarget)==0); | |
} | |
if (Result) { | |
if (FullName != NULL) { | |
*FullName = TempList; | |
} else { | |
FreePool(TempList); | |
} | |
return (TRUE); | |
} | |
FreePool(TempList); | |
TempList = NULL; | |
} | |
return (FALSE); | |
} | |
/** | |
Determine what type of device is represented and return it's string. The | |
string is in allocated memory and must be callee freed. The HII is is listed below. | |
The actual string cannot be determined. | |
@param[in] DevicePath The device to analyze. | |
@retval STR_MAP_MEDIA_UNKNOWN The media type is unknown. | |
@retval STR_MAP_MEDIA_HARDDISK The media is a hard drive. | |
@retval STR_MAP_MEDIA_CDROM The media is a CD ROM. | |
@retval STR_MAP_MEDIA_FLOPPY The media is a floppy drive. | |
**/ | |
CHAR16* | |
EFIAPI | |
GetDeviceMediaType ( | |
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
) | |
{ | |
ACPI_HID_DEVICE_PATH *Acpi; | |
// | |
// Parse the device path: | |
// Devicepath sub type mediatype | |
// MEDIA_HANRDDRIVE_DP -> Hard Disk | |
// MEDIA_CDROM_DP -> CD Rom | |
// Acpi.HID = 0X0604 -> Floppy | |
// | |
if (NULL == DevicePath) { | |
return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_UNKNOWN), NULL); | |
} | |
for (;!IsDevicePathEndType (DevicePath) ;DevicePath = NextDevicePathNode (DevicePath)) { | |
if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) { | |
switch (DevicePathSubType (DevicePath)) { | |
case MEDIA_HARDDRIVE_DP: | |
return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_HARDDISK), NULL); | |
case MEDIA_CDROM_DP: | |
return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_CDROM), NULL); | |
} | |
} else if (DevicePathType (DevicePath) == ACPI_DEVICE_PATH) { | |
Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath; | |
if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) { | |
return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_FLOPPY), NULL); | |
} | |
} | |
} | |
return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_UNKNOWN), NULL); | |
} | |
/** | |
Function to detemine if a handle has removable storage. | |
@param[in] DevicePath DevicePath to test. | |
@retval TRUE The handle has removable storage. | |
@retval FALSE The handle does not have removable storage. | |
**/ | |
BOOLEAN | |
EFIAPI | |
IsRemoveableDevice ( | |
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath | |
) | |
{ | |
if (NULL == DevicePath) { | |
return FALSE; | |
} | |
while (!IsDevicePathEndType (DevicePath)) { | |
if (DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) { | |
switch (DevicePathSubType (DevicePath)) { | |
case MSG_USB_DP: | |
case MSG_SCSI_DP: | |
return TRUE; | |
default: | |
return FALSE; | |
} | |
} | |
DevicePath = NextDevicePathNode (DevicePath); | |
} | |
return FALSE; | |
} | |
/** | |
Function to detemine if a something on the map list matches. | |
@param[in] MapList The pointer to the list to test. | |
@param[in] Specific The pointer to a specific name to test for. | |
@param[in] TypeString The pointer to the list of types. | |
@param[in] Normal Always show normal mappings. | |
@param[in] Consist Always show consistent mappings. | |
@retval TRUE The map should be displayed. | |
@retval FALSE The map should not be displayed. | |
**/ | |
BOOLEAN | |
EFIAPI | |
MappingListHasType( | |
IN CONST CHAR16 *MapList, | |
IN CONST CHAR16 *Specific, | |
IN CONST CHAR16 *TypeString, | |
IN CONST BOOLEAN Normal, | |
IN CONST BOOLEAN Consist | |
) | |
{ | |
CHAR16 *NewSpecific; | |
RETURN_STATUS Status; | |
// | |
// specific has priority | |
// | |
if (Specific != NULL) { | |
NewSpecific = AllocateCopyPool(StrSize(Specific) + sizeof(CHAR16), Specific); | |
if (NewSpecific == NULL){ | |
return FALSE; | |
} | |
if (NewSpecific[StrLen(NewSpecific)-1] != L':') { | |
Status = StrnCatS(NewSpecific, (StrSize(Specific) + sizeof(CHAR16))/sizeof(CHAR16), L":", StrLen(L":")); | |
if (EFI_ERROR (Status)) { | |
FreePool(NewSpecific); | |
return FALSE; | |
} | |
} | |
if (SearchList(MapList, NewSpecific, NULL, TRUE, FALSE, L";")) { | |
FreePool(NewSpecific); | |
return (TRUE); | |
} | |
FreePool(NewSpecific); | |
} | |
if ( Consist | |
&& Specific == NULL | |
&& (SearchList(MapList, L"HD*", NULL, TRUE, TRUE, L";") | |
||SearchList(MapList, L"CD*", NULL, TRUE, TRUE, L";") | |
||SearchList(MapList, L"F*", NULL, TRUE, TRUE, L";") | |
||SearchList(MapList, L"FP*", NULL, TRUE, TRUE, L";"))){ | |
return (TRUE); | |
} | |
if ( Normal | |
&& Specific == NULL | |
&& (SearchList(MapList, L"FS", NULL, FALSE, TRUE, L";") | |
||SearchList(MapList, L"BLK", NULL, FALSE, TRUE, L";"))){ | |
return (TRUE); | |
} | |
if (TypeString != NULL && SearchList(MapList, TypeString, NULL, TRUE, TRUE, L";")) { | |
return (TRUE); | |
} | |
return (FALSE); | |
} | |
/** | |
Display a single map line for device Handle if conditions are met. | |
@param[in] Verbose TRUE to display (extra) verbose information. | |
@param[in] Consist TRUE to display consistent mappings. | |
@param[in] Normal TRUE to display normal (not consist) mappings. | |
@param[in] TypeString pointer to string of filter types. | |
@param[in] SFO TRUE to display output in Standard Output Format. | |
@param[in] Specific pointer to string for specific map to display. | |
@param[in] Handle The handle to display from. | |
@retval EFI_SUCCESS The mapping was displayed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
PerformSingleMappingDisplay( | |
IN CONST BOOLEAN Verbose, | |
IN CONST BOOLEAN Consist, | |
IN CONST BOOLEAN Normal, | |
IN CONST CHAR16 *TypeString, | |
IN CONST BOOLEAN SFO, | |
IN CONST CHAR16 *Specific OPTIONAL, | |
IN CONST EFI_HANDLE Handle | |
) | |
{ | |
EFI_DEVICE_PATH_PROTOCOL *DevPath; | |
EFI_DEVICE_PATH_PROTOCOL *DevPathCopy; | |
CONST CHAR16 *MapList; | |
CHAR16 *CurrentName; | |
CHAR16 *MediaType; | |
CHAR16 *DevPathString; | |
CHAR16 *TempSpot; | |
CHAR16 *Alias; | |
UINTN TempLen; | |
BOOLEAN Removable; | |
CONST CHAR16 *TempSpot2; | |
Alias = NULL; | |
TempSpot2 = NULL; | |
CurrentName = NULL; | |
DevPath = DevicePathFromHandle(Handle); | |
DevPathCopy = DevPath; | |
MapList = gEfiShellProtocol->GetMapFromDevicePath(&DevPathCopy); | |
if (MapList == NULL) { | |
return EFI_NOT_FOUND; | |
} | |
if (!MappingListHasType(MapList, Specific, TypeString, Normal, Consist)){ | |
return EFI_NOT_FOUND; | |
} | |
if (Normal || !Consist) { | |
// | |
// need the Normal here since people can use both on command line. otherwise unused. | |
// | |
// | |
// Allocate a name | |
// | |
CurrentName = NULL; | |
CurrentName = StrnCatGrow(&CurrentName, 0, MapList, 0); | |
if (CurrentName == NULL) { | |
return (EFI_OUT_OF_RESOURCES); | |
} | |
// | |
// Chop off the other names that become "Alias(s)" | |
// leaving just the normal name | |
// | |
TempSpot = StrStr(CurrentName, L";"); | |
if (TempSpot != NULL) { | |
*TempSpot = CHAR_NULL; | |
} | |
} else { | |
CurrentName = NULL; | |
// | |
// Skip the first name. This is the standard name. | |
// | |
TempSpot = StrStr(MapList, L";"); | |
if (TempSpot != NULL) { | |
TempSpot++; | |
} | |
SearchList(TempSpot, L"HD*", &CurrentName, TRUE, FALSE, L";"); | |
if (CurrentName == NULL) { | |
SearchList(TempSpot, L"CD*", &CurrentName, TRUE, FALSE, L";"); | |
} | |
if (CurrentName == NULL) { | |
SearchList(TempSpot, L"FP*", &CurrentName, TRUE, FALSE, L";"); | |
} | |
if (CurrentName == NULL) { | |
SearchList(TempSpot, L"F*", &CurrentName, TRUE, FALSE, L";"); | |
} | |
if (CurrentName == NULL) { | |
// | |
// We didnt find anything, so just the first one in the list... | |
// | |
CurrentName = StrnCatGrow(&CurrentName, 0, MapList, 0); | |
if (CurrentName == NULL) { | |
return (EFI_OUT_OF_RESOURCES); | |
} | |
TempSpot = StrStr(CurrentName, L";"); | |
if (TempSpot != NULL) { | |
*TempSpot = CHAR_NULL; | |
} | |
} else { | |
Alias = StrnCatGrow(&Alias, 0, MapList, 0); | |
if (Alias == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
TempSpot = StrStr(Alias, CurrentName); | |
if (TempSpot != NULL) { | |
TempSpot2 = StrStr(TempSpot, L";"); | |
if (TempSpot2 != NULL) { | |
TempSpot2++; // Move past ";" from CurrentName | |
CopyMem(TempSpot, TempSpot2, StrSize(TempSpot2)); | |
} else { | |
*TempSpot = CHAR_NULL; | |
} | |
} | |
if (Alias[StrLen(Alias)-1] == L';') { | |
Alias[StrLen(Alias)-1] = CHAR_NULL; | |
} | |
} | |
} | |
DevPathString = ConvertDevicePathToText(DevPath, TRUE, FALSE); | |
TempLen = StrLen(CurrentName); | |
if (!SFO) { | |
ShellPrintHiiEx ( | |
-1, | |
-1, | |
NULL, | |
STRING_TOKEN (STR_MAP_ENTRY), | |
gShellLevel2HiiHandle, | |
CurrentName, | |
Alias!=NULL?Alias:(TempLen < StrLen(MapList)?MapList + TempLen+1:L""), | |
DevPathString | |
); | |
if (Verbose) { | |
// | |
// also print handle, media type, removable (y/n), and current directory | |
// | |
MediaType = GetDeviceMediaType(DevPath); | |
if ((TypeString != NULL &&MediaType != NULL && StrStr(TypeString, MediaType) != NULL) || TypeString == NULL) { | |
Removable = IsRemoveableDevice(DevPath); | |
TempSpot2 = ShellGetCurrentDir(CurrentName); | |
ShellPrintHiiEx ( | |
-1, | |
-1, | |
NULL, | |
STRING_TOKEN (STR_MAP_ENTRY_VERBOSE), | |
gShellLevel2HiiHandle, | |
ConvertHandleToHandleIndex(Handle), | |
MediaType, | |
Removable?L"Yes":L"No", | |
TempSpot2 | |
); | |
} | |
SHELL_FREE_NON_NULL(MediaType); | |
} | |
} else { | |
ShellPrintHiiEx ( | |
-1, | |
-1, | |
NULL, | |
STRING_TOKEN (STR_MAP_SFO_MAPPINGS), | |
gShellLevel2HiiHandle, | |
CurrentName, | |
DevPathString, | |
Consist?L"":(TempLen < StrLen(MapList)?MapList + TempLen+1:L"") | |
); | |
} | |
SHELL_FREE_NON_NULL(DevPathString); | |
SHELL_FREE_NON_NULL(CurrentName); | |
SHELL_FREE_NON_NULL(Alias); | |
return EFI_SUCCESS; | |
} | |
/** | |
Delete Specific from the list of maps for device Handle. | |
@param[in] Specific The name to delete. | |
@param[in] Handle The device to look on. | |
@retval EFI_SUCCESS The delete was successful. | |
@retval EFI_NOT_FOUND Name was not a map on Handle. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
PerformSingleMappingDelete( | |
IN CONST CHAR16 *Specific, | |
IN CONST EFI_HANDLE Handle | |
) | |
{ | |
EFI_DEVICE_PATH_PROTOCOL *DevPath; | |
EFI_DEVICE_PATH_PROTOCOL *DevPathCopy; | |
CONST CHAR16 *MapList; | |
CHAR16 *CurrentName; | |
DevPath = DevicePathFromHandle(Handle); | |
DevPathCopy = DevPath; | |
MapList = gEfiShellProtocol->GetMapFromDevicePath(&DevPathCopy); | |
CurrentName = NULL; | |
if (MapList == NULL) { | |
return (EFI_NOT_FOUND); | |
} | |
// | |
// if there is a specific and its not on the list... | |
// | |
if (!SearchList(MapList, Specific, &CurrentName, TRUE, FALSE, L";")) { | |
return (EFI_NOT_FOUND); | |
} | |
return (gEfiShellProtocol->SetMap(NULL, CurrentName)); | |
} | |
CONST CHAR16 Cd[] = L"cd*"; | |
CONST CHAR16 Hd[] = L"hd*"; | |
CONST CHAR16 Fp[] = L"fp*"; | |
CONST CHAR16 AnyF[] = L"F*"; | |
/** | |
Function to display mapping information to the user. | |
If Specific is specified then Consist and Normal will be ignored since information will | |
be printed for the specific item only. | |
@param[in] Verbose TRUE to display (extra) verbose information. | |
@param[in] Consist TRUE to display consistent mappings. | |
@param[in] Normal TRUE to display normal (not consist) mappings. | |
@param[in] TypeString Pointer to string of filter types. | |
@param[in] SFO TRUE to display output in Standard Output Format. | |
@param[in] Specific Pointer to string for specific map to display. | |
@param[in] Header TRUE to print the header block. | |
@retval SHELL_SUCCESS The display was printed. | |
@retval SHELL_INVALID_PARAMETER One of Consist or Normal must be TRUE if no Specific. | |
**/ | |
SHELL_STATUS | |
EFIAPI | |
PerformMappingDisplay( | |
IN CONST BOOLEAN Verbose, | |
IN CONST BOOLEAN Consist, | |
IN CONST BOOLEAN Normal, | |
IN CONST CHAR16 *TypeString, | |
IN CONST BOOLEAN SFO, | |
IN CONST CHAR16 *Specific OPTIONAL, | |
IN CONST BOOLEAN Header | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE *HandleBuffer; | |
UINTN BufferSize; | |
UINTN LoopVar; | |
CHAR16 *Test; | |
BOOLEAN Found; | |
if (!Consist && !Normal && Specific == NULL && TypeString == NULL) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"map"); | |
return (SHELL_INVALID_PARAMETER); | |
} | |
if (TypeString != NULL) { | |
Test = (CHAR16*)Cd; | |
if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { | |
Test = (CHAR16*)Hd; | |
if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { | |
Test = (CHAR16*)Fp; | |
if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", TypeString); | |
return (SHELL_INVALID_PARAMETER); | |
} | |
} else if (Test == NULL) { | |
Test = (CHAR16*)AnyF; | |
} | |
} | |
} else { | |
Test = NULL; | |
} | |
if (Header) { | |
// | |
// Print the header | |
// | |
if (!SFO) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_HEADER), gShellLevel2HiiHandle); | |
} else { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel2HiiHandle, L"map"); | |
} | |
} | |
BufferSize = 0; | |
HandleBuffer = NULL; | |
// | |
// Look up all SimpleFileSystems in the platform | |
// | |
Status = gBS->LocateHandle( | |
ByProtocol, | |
&gEfiSimpleFileSystemProtocolGuid, | |
NULL, | |
&BufferSize, | |
HandleBuffer); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
HandleBuffer = AllocateZeroPool(BufferSize); | |
if (HandleBuffer == NULL) { | |
return (SHELL_OUT_OF_RESOURCES); | |
} | |
Status = gBS->LocateHandle( | |
ByProtocol, | |
&gEfiSimpleFileSystemProtocolGuid, | |
NULL, | |
&BufferSize, | |
HandleBuffer); | |
} | |
// | |
// Get the map name(s) for each one. | |
// | |
for ( LoopVar = 0, Found = FALSE | |
; LoopVar < (BufferSize / sizeof(EFI_HANDLE)) && HandleBuffer != NULL | |
; LoopVar ++ | |
){ | |
Status = PerformSingleMappingDisplay( | |
Verbose, | |
Consist, | |
Normal, | |
Test, | |
SFO, | |
Specific, | |
HandleBuffer[LoopVar]); | |
if (!EFI_ERROR(Status)) { | |
Found = TRUE; | |
} | |
} | |
// | |
// Look up all BlockIo in the platform | |
// | |
Status = gBS->LocateHandle( | |
ByProtocol, | |
&gEfiBlockIoProtocolGuid, | |
NULL, | |
&BufferSize, | |
HandleBuffer); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
SHELL_FREE_NON_NULL(HandleBuffer); | |
HandleBuffer = AllocateZeroPool(BufferSize); | |
if (HandleBuffer == NULL) { | |
return (SHELL_OUT_OF_RESOURCES); | |
} | |
Status = gBS->LocateHandle( | |
ByProtocol, | |
&gEfiBlockIoProtocolGuid, | |
NULL, | |
&BufferSize, | |
HandleBuffer); | |
} | |
if (!EFI_ERROR(Status) && HandleBuffer != NULL) { | |
// | |
// Get the map name(s) for each one. | |
// | |
for ( LoopVar = 0 | |
; LoopVar < BufferSize / sizeof(EFI_HANDLE) | |
; LoopVar ++ | |
){ | |
// | |
// Skip any that were already done... | |
// | |
if (gBS->OpenProtocol( | |
HandleBuffer[LoopVar], | |
&gEfiSimpleFileSystemProtocolGuid, | |
NULL, | |
gImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL) == EFI_SUCCESS) { | |
continue; | |
} | |
Status = PerformSingleMappingDisplay( | |
Verbose, | |
Consist, | |
Normal, | |
Test, | |
SFO, | |
Specific, | |
HandleBuffer[LoopVar]); | |
if (!EFI_ERROR(Status)) { | |
Found = TRUE; | |
} | |
} | |
FreePool(HandleBuffer); | |
} | |
if (!Found) { | |
if (Specific != NULL) { | |
ShellPrintHiiEx(gST->ConOut->Mode->CursorColumn, gST->ConOut->Mode->CursorRow-1, NULL, STRING_TOKEN (STR_MAP_NF), gShellLevel2HiiHandle, L"map", Specific); | |
} else { | |
ShellPrintHiiEx(gST->ConOut->Mode->CursorColumn, gST->ConOut->Mode->CursorRow-1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"map"); | |
} | |
} | |
return (SHELL_SUCCESS); | |
} | |
/** | |
Perform a mapping display and parse for multiple types in the TypeString. | |
@param[in] Verbose TRUE to use verbose output. | |
@param[in] Consist TRUE to display consistent names. | |
@param[in] Normal TRUE to display normal names. | |
@param[in] TypeString An optional comma-delimited list of types. | |
@param[in] SFO TRUE to display in SFO format. See Spec. | |
@param[in] Specific An optional specific map name to display alone. | |
@retval SHELL_INVALID_PARAMETER A parameter was invalid. | |
@retval SHELL_SUCCESS The display was successful. | |
@sa PerformMappingDisplay | |
**/ | |
SHELL_STATUS | |
EFIAPI | |
PerformMappingDisplay2( | |
IN CONST BOOLEAN Verbose, | |
IN CONST BOOLEAN Consist, | |
IN CONST BOOLEAN Normal, | |
IN CONST CHAR16 *TypeString, | |
IN CONST BOOLEAN SFO, | |
IN CONST CHAR16 *Specific OPTIONAL | |
) | |
{ | |
CONST CHAR16 *TypeWalker; | |
SHELL_STATUS ShellStatus; | |
CHAR16 *Comma; | |
if (TypeString == NULL) { | |
return (PerformMappingDisplay(Verbose, Consist, Normal, NULL, SFO, Specific, TRUE)); | |
} | |
ShellStatus = SHELL_SUCCESS; | |
for (TypeWalker = TypeString ; TypeWalker != NULL && *TypeWalker != CHAR_NULL ;) { | |
Comma = StrStr(TypeWalker, L","); | |
if (Comma == NULL) { | |
if (ShellStatus == SHELL_SUCCESS) { | |
ShellStatus = PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); | |
} else { | |
PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); | |
} | |
break; | |
} else { | |
*Comma = CHAR_NULL; | |
if (ShellStatus == SHELL_SUCCESS) { | |
ShellStatus = PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); | |
} else { | |
PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString)); | |
} | |
*Comma = L','; | |
TypeWalker = Comma + 1; | |
} | |
} | |
return (ShellStatus); | |
} | |
/** | |
Delete a specific map. | |
@param[in] Specific The pointer to the name of the map to delete. | |
@retval EFI_INVALID_PARAMETER Specific was NULL. | |
@retval EFI_SUCCESS The operation was successful. | |
@retval EFI_NOT_FOUND Specific could not be found. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
PerformMappingDelete( | |
IN CONST CHAR16 *Specific | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE *HandleBuffer; | |
UINTN BufferSize; | |
UINTN LoopVar; | |
BOOLEAN Deleted; | |
if (Specific == NULL) { | |
return (EFI_INVALID_PARAMETER); | |
} | |
BufferSize = 0; | |
HandleBuffer = NULL; | |
Deleted = FALSE; | |
// | |
// Look up all SimpleFileSystems in the platform | |
// | |
Status = gBS->LocateHandle( | |
ByProtocol, | |
&gEfiDevicePathProtocolGuid, | |
NULL, | |
&BufferSize, | |
HandleBuffer); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
HandleBuffer = AllocateZeroPool(BufferSize); | |
if (HandleBuffer == NULL) { | |
return (EFI_OUT_OF_RESOURCES); | |
} | |
Status = gBS->LocateHandle( | |
ByProtocol, | |
&gEfiDevicePathProtocolGuid, | |
NULL, | |
&BufferSize, | |
HandleBuffer); | |
} | |
if (EFI_ERROR(Status)) { | |
SHELL_FREE_NON_NULL(HandleBuffer); | |
return (Status); | |
} | |
if (HandleBuffer != NULL) { | |
// | |
// Get the map name(s) for each one. | |
// | |
for ( LoopVar = 0 | |
; LoopVar < BufferSize / sizeof(EFI_HANDLE) | |
; LoopVar ++ | |
){ | |
if (PerformSingleMappingDelete(Specific,HandleBuffer[LoopVar]) == SHELL_SUCCESS) { | |
Deleted = TRUE; | |
} | |
} | |
} | |
// | |
// Look up all BlockIo in the platform | |
// | |
Status = gBS->LocateHandle( | |
ByProtocol, | |
&gEfiBlockIoProtocolGuid, | |
NULL, | |
&BufferSize, | |
HandleBuffer); | |
if (Status == EFI_BUFFER_TOO_SMALL) { | |
FreePool(HandleBuffer); | |
HandleBuffer = AllocateZeroPool(BufferSize); | |
if (HandleBuffer == NULL) { | |
return (EFI_OUT_OF_RESOURCES); | |
} | |
Status = gBS->LocateHandle( | |
ByProtocol, | |
&gEfiBlockIoProtocolGuid, | |
NULL, | |
&BufferSize, | |
HandleBuffer); | |
} | |
if (EFI_ERROR(Status)) { | |
SHELL_FREE_NON_NULL(HandleBuffer); | |
return (Status); | |
} | |
if (HandleBuffer != NULL) { | |
// | |
// Get the map name(s) for each one. | |
// | |
for ( LoopVar = 0 | |
; LoopVar < BufferSize / sizeof(EFI_HANDLE) | |
; LoopVar ++ | |
){ | |
// | |
// Skip any that were already done... | |
// | |
if (gBS->OpenProtocol( | |
HandleBuffer[LoopVar], | |
&gEfiDevicePathProtocolGuid, | |
NULL, | |
gImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL) == EFI_SUCCESS) { | |
continue; | |
} | |
if (PerformSingleMappingDelete(Specific,HandleBuffer[LoopVar]) == SHELL_SUCCESS) { | |
Deleted = TRUE; | |
} | |
} | |
} | |
SHELL_FREE_NON_NULL(HandleBuffer); | |
if (!Deleted) { | |
return (EFI_NOT_FOUND); | |
} | |
return (EFI_SUCCESS); | |
} | |
/** | |
function to add a mapping from mapping. | |
This function will get the device path associated with the mapping and call SetMap. | |
@param[in] Map The Map to add a mapping for | |
@param[in] SName The name of the new mapping | |
@retval SHELL_SUCCESS the mapping was added | |
@retval SHELL_INVALID_PARAMETER the device path for Map could not be retrieved. | |
@return Shell version of a return value from EfiShellProtocol->SetMap | |
**/ | |
SHELL_STATUS | |
EFIAPI | |
AddMappingFromMapping( | |
IN CONST CHAR16 *Map, | |
IN CONST CHAR16 *SName | |
) | |
{ | |
CONST EFI_DEVICE_PATH_PROTOCOL *DevPath; | |
EFI_STATUS Status; | |
CHAR16 *NewSName; | |
RETURN_STATUS StrRetStatus; | |
NewSName = AllocateCopyPool(StrSize(SName) + sizeof(CHAR16), SName); | |
if (NewSName == NULL) { | |
return (SHELL_OUT_OF_RESOURCES); | |
} | |
if (NewSName[StrLen(NewSName)-1] != L':') { | |
StrRetStatus = StrnCatS(NewSName, (StrSize(SName) + sizeof(CHAR16))/sizeof(CHAR16), L":", StrLen(L":")); | |
if (EFI_ERROR(StrRetStatus)) { | |
FreePool(NewSName); | |
return ((SHELL_STATUS) (StrRetStatus & (~MAX_BIT))); | |
} | |
} | |
if (!IsNumberLetterOnly(NewSName, StrLen(NewSName)-1)) { | |
FreePool(NewSName); | |
return (SHELL_INVALID_PARAMETER); | |
} | |
DevPath = gEfiShellProtocol->GetDevicePathFromMap(Map); | |
if (DevPath == NULL) { | |
FreePool(NewSName); | |
return (SHELL_INVALID_PARAMETER); | |
} | |
Status = gEfiShellProtocol->SetMap(DevPath, NewSName); | |
FreePool(NewSName); | |
if (EFI_ERROR(Status)) { | |
return (SHELL_DEVICE_ERROR); | |
} | |
return (SHELL_SUCCESS); | |
} | |
/** | |
function to add a mapping from an EFI_HANDLE. | |
This function will get the device path associated with the Handle and call SetMap. | |
@param[in] Handle The handle to add a mapping for | |
@param[in] SName The name of the new mapping | |
@retval SHELL_SUCCESS the mapping was added | |
@retval SHELL_INVALID_PARAMETER SName was not valid for a map name. | |
@return Shell version of a return value from either | |
gBS->OpenProtocol or EfiShellProtocol->SetMap | |
**/ | |
SHELL_STATUS | |
EFIAPI | |
AddMappingFromHandle( | |
IN CONST EFI_HANDLE Handle, | |
IN CONST CHAR16 *SName | |
) | |
{ | |
EFI_DEVICE_PATH_PROTOCOL *DevPath; | |
EFI_STATUS Status; | |
CHAR16 *NewSName; | |
RETURN_STATUS StrRetStatus; | |
NewSName = AllocateCopyPool(StrSize(SName) + sizeof(CHAR16), SName); | |
if (NewSName == NULL) { | |
return (SHELL_OUT_OF_RESOURCES); | |
} | |
if (NewSName[StrLen(NewSName)-1] != L':') { | |
StrRetStatus = StrnCatS(NewSName, (StrSize(SName) + sizeof(CHAR16))/sizeof(CHAR16), L":", StrLen(L":")); | |
if (EFI_ERROR(StrRetStatus)) { | |
FreePool(NewSName); | |
return ((SHELL_STATUS) (StrRetStatus & (~MAX_BIT))); | |
} | |
} | |
if (!IsNumberLetterOnly(NewSName, StrLen(NewSName)-1)) { | |
FreePool(NewSName); | |
return (SHELL_INVALID_PARAMETER); | |
} | |
Status = gBS->OpenProtocol( | |
Handle, | |
&gEfiDevicePathProtocolGuid, | |
(VOID**)&DevPath, | |
gImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR(Status)) { | |
FreePool(NewSName); | |
return (SHELL_DEVICE_ERROR); | |
} | |
Status = gEfiShellProtocol->SetMap(DevPath, NewSName); | |
FreePool(NewSName); | |
if (EFI_ERROR(Status)) { | |
return (SHELL_DEVICE_ERROR); | |
} | |
return (SHELL_SUCCESS); | |
} | |
STATIC CONST SHELL_PARAM_ITEM MapParamList[] = { | |
{L"-d", TypeValue}, | |
{L"-r", TypeFlag}, | |
{L"-v", TypeFlag}, | |
{L"-c", TypeFlag}, | |
{L"-f", TypeFlag}, | |
{L"-u", TypeFlag}, | |
{L"-t", TypeValue}, | |
{L"-sfo", TypeValue}, | |
{NULL, TypeMax} | |
}; | |
/** | |
Function for 'map' command. | |
@param[in] ImageHandle Handle to the Image (NULL if Internal). | |
@param[in] SystemTable Pointer to the System Table (NULL if Internal). | |
**/ | |
SHELL_STATUS | |
EFIAPI | |
ShellCommandRunMap ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
LIST_ENTRY *Package; | |
CHAR16 *ProblemParam; | |
CONST CHAR16 *SName; | |
CONST CHAR16 *Mapping; | |
EFI_HANDLE MapAsHandle; | |
SHELL_STATUS ShellStatus; | |
BOOLEAN SfoMode; | |
BOOLEAN ConstMode; | |
BOOLEAN NormlMode; | |
CONST CHAR16 *Param1; | |
CONST CHAR16 *TypeString; | |
UINTN TempStringLength; | |
ProblemParam = NULL; | |
Mapping = NULL; | |
SName = NULL; | |
ShellStatus = SHELL_SUCCESS; | |
MapAsHandle = NULL; | |
// | |
// initialize the shell lib (we must be in non-auto-init...) | |
// | |
Status = ShellInitialize(); | |
ASSERT_EFI_ERROR(Status); | |
Status = CommandInit(); | |
ASSERT_EFI_ERROR(Status); | |
// | |
// parse the command line | |
// | |
Status = ShellCommandLineParse (MapParamList, &Package, &ProblemParam, TRUE); | |
if (EFI_ERROR(Status)) { | |
if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"map", ProblemParam); | |
FreePool(ProblemParam); | |
ShellStatus = SHELL_INVALID_PARAMETER; | |
} else { | |
ASSERT(FALSE); | |
} | |
} else { | |
// | |
// check for "-?" | |
// | |
SfoMode = ShellCommandLineGetFlag(Package, L"-sfo"); | |
ConstMode = ShellCommandLineGetFlag(Package, L"-c"); | |
NormlMode = ShellCommandLineGetFlag(Package, L"-f"); | |
if (ShellCommandLineGetFlag(Package, L"-?")) { | |
ASSERT(FALSE); | |
} else if (ShellCommandLineGetRawValue(Package, 3) != NULL) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"map"); | |
ShellStatus = SHELL_INVALID_PARAMETER; | |
} else { | |
// | |
// Deleting a map name... | |
// | |
if (ShellCommandLineGetFlag(Package, L"-d")) { | |
if ( ShellCommandLineGetFlag(Package, L"-r") | |
|| ShellCommandLineGetFlag(Package, L"-v") | |
|| ConstMode | |
|| NormlMode | |
|| ShellCommandLineGetFlag(Package, L"-u") | |
|| ShellCommandLineGetFlag(Package, L"-t") | |
){ | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel2HiiHandle, L"map"); | |
ShellStatus = SHELL_INVALID_PARAMETER; | |
} else { | |
SName = ShellCommandLineGetValue(Package, L"-d"); | |
if (SName != NULL) { | |
Status = PerformMappingDelete(SName); | |
if (EFI_ERROR(Status)) { | |
if (Status == EFI_ACCESS_DENIED) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel2HiiHandle, L"map"); | |
ShellStatus = SHELL_ACCESS_DENIED; | |
} else if (Status == EFI_NOT_FOUND) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_NF), gShellLevel2HiiHandle, L"map", SName); | |
ShellStatus = SHELL_INVALID_PARAMETER; | |
} else { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status); | |
ShellStatus = SHELL_UNSUPPORTED; | |
} | |
} | |
} else { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"map"); | |
ShellStatus = SHELL_INVALID_PARAMETER; | |
} | |
} | |
} else if ( ShellCommandLineGetFlag(Package, L"-r") | |
// || ShellCommandLineGetFlag(Package, L"-v") | |
|| ConstMode | |
|| NormlMode | |
|| ShellCommandLineGetFlag(Package, L"-u") | |
|| ShellCommandLineGetFlag(Package, L"-t") | |
){ | |
if ( ShellCommandLineGetFlag(Package, L"-r")) { | |
// | |
// Do the reset | |
// | |
Status = ShellCommandCreateInitialMappingsAndPaths(); | |
if (EFI_ERROR(Status)) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status); | |
ShellStatus = SHELL_UNSUPPORTED; | |
} | |
} | |
if ( ShellStatus == SHELL_SUCCESS && ShellCommandLineGetFlag(Package, L"-u")) { | |
// | |
// Do the Update | |
// | |
Status = ShellCommandUpdateMapping (); | |
if (EFI_ERROR(Status)) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status); | |
ShellStatus = SHELL_UNSUPPORTED; | |
} | |
} | |
if (ShellStatus == SHELL_SUCCESS) { | |
Param1 = ShellCommandLineGetRawValue(Package, 1); | |
TypeString = ShellCommandLineGetValue(Package, L"-t"); | |
if (!ConstMode | |
&&!NormlMode | |
&&TypeString == NULL | |
) { | |
// | |
// now do the display... | |
// | |
ShellStatus = PerformMappingDisplay( | |
ShellCommandLineGetFlag(Package, L"-v"), | |
TRUE, | |
TRUE, | |
NULL, | |
SfoMode, | |
Param1, | |
TRUE | |
); | |
} else { | |
// | |
// now do the display... | |
// | |
ShellStatus = PerformMappingDisplay2( | |
ShellCommandLineGetFlag(Package, L"-v"), | |
ConstMode, | |
NormlMode, | |
TypeString, | |
SfoMode, | |
Param1 | |
); | |
} | |
} | |
} else { | |
// | |
// adding or displaying (there were no flags) | |
// | |
SName = ShellCommandLineGetRawValue(Package, 1); | |
Mapping = ShellCommandLineGetRawValue(Package, 2); | |
if ( SName == NULL | |
&& Mapping == NULL | |
){ | |
// | |
// display only since no flags | |
// | |
ShellStatus = PerformMappingDisplay( | |
ShellCommandLineGetFlag(Package, L"-v"), | |
TRUE, | |
TRUE, | |
NULL, | |
SfoMode, | |
NULL, | |
TRUE | |
); | |
} else if ( SName == NULL | |
|| Mapping == NULL | |
){ | |
// | |
// Display only the one specified | |
// | |
ShellStatus = PerformMappingDisplay( | |
FALSE, | |
FALSE, | |
FALSE, | |
NULL, | |
SfoMode, | |
SName, // note the variable here... | |
TRUE | |
); | |
} else { | |
if (ShellIsHexOrDecimalNumber(Mapping, TRUE, FALSE)) { | |
MapAsHandle = ConvertHandleIndexToHandle(ShellStrToUintn(Mapping)); | |
} else { | |
MapAsHandle = NULL; | |
} | |
if (MapAsHandle == NULL && Mapping[StrLen(Mapping)-1] != L':') { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", Mapping); | |
ShellStatus = SHELL_INVALID_PARAMETER; | |
} else { | |
if (MapAsHandle != NULL) { | |
TempStringLength = StrLen(SName); | |
if (!IsNumberLetterOnly(SName, TempStringLength-(SName[TempStringLength-1]==L':'?1:0))) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", SName); | |
ShellStatus = SHELL_INVALID_PARAMETER; | |
} else { | |
ShellStatus = AddMappingFromHandle(MapAsHandle, SName); | |
} | |
} else { | |
TempStringLength = StrLen(SName); | |
if (!IsNumberLetterOnly(SName, TempStringLength-(SName[TempStringLength-1]==L':'?1:0))) { | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", SName); | |
ShellStatus = SHELL_INVALID_PARAMETER; | |
} else { | |
ShellStatus = AddMappingFromMapping(Mapping, SName); | |
} | |
} | |
if (ShellStatus != SHELL_SUCCESS) { | |
switch (ShellStatus) { | |
case SHELL_ACCESS_DENIED: | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel2HiiHandle, L"map"); | |
break; | |
case SHELL_INVALID_PARAMETER: | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", Mapping); | |
break; | |
case SHELL_DEVICE_ERROR: | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_NOF), gShellLevel2HiiHandle, L"map", Mapping); | |
break; | |
default: | |
ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", ShellStatus|MAX_BIT); | |
} | |
} else { | |
// | |
// now do the display... | |
// | |
ShellStatus = PerformMappingDisplay( | |
FALSE, | |
FALSE, | |
FALSE, | |
NULL, | |
SfoMode, | |
SName, | |
TRUE | |
); | |
} // we were sucessful so do an output | |
} // got a valid map target | |
} // got 2 variables | |
} // we are adding a mapping | |
} // got valid parameters | |
} | |
// | |
// free the command line package | |
// | |
ShellCommandLineFreeVarList (Package); | |
return (ShellStatus); | |
} | |