1 /** @file
2   Main file for map shell level 2 command.
3 
4   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
5   (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
6   (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
7 
8   SPDX-License-Identifier: BSD-2-Clause-Patent
9 
10 **/
11 
12 #include "UefiShellLevel2CommandsLib.h"
13 #include <Protocol/SimpleFileSystem.h>
14 #include <Protocol/BlockIo.h>
15 #include <Library/DevicePathLib.h>
16 #include <Library/HandleParsingLib.h>
17 #include <Library/SortLib.h>
18 
19 /**
20   Determine if a string has only numbers and letters.
21 
22   This is useful for such things as Map names which can only be letters and numbers.
23 
24   @param[in] String       pointer to the string to analyze,
25   @param[in] Len          Number of characters to analyze.
26 
27   @retval TRUE            String has only numbers and letters
28   @retval FALSE           String has at least one other character.
29 **/
30 BOOLEAN
IsNumberLetterOnly(IN CONST CHAR16 * String,IN CONST UINTN Len)31 IsNumberLetterOnly(
32   IN CONST CHAR16 *String,
33   IN CONST UINTN  Len
34   )
35 {
36   UINTN Count;
37   for (Count = 0 ; Count < Len && String != NULL && *String != CHAR_NULL ; String++,Count++) {
38     if (! ((*String >= L'a' && *String <= L'z') ||
39            (*String >= L'A' && *String <= L'Z') ||
40            (*String >= L'0' && *String <= L'9'))
41         ){
42       return (FALSE);
43     }
44   }
45   return (TRUE);
46 }
47 
48 /**
49   Do a search in the Target delimited list.
50 
51   @param[in] List         The list to seatch in.
52   @param[in] MetaTarget   The item to search for. MetaMatching supported.
53   @param[out] FullName    Optional pointer to an allocated buffer containing
54                           the match.
55   @param[in] Meta         TRUE to use MetaMatching.
56   @param[in] SkipTrailingNumbers  TRUE to allow for numbers after the MetaTarget.
57   @param[in] Target       The single character that delimits list
58                           items (";" normally).
59 **/
60 BOOLEAN
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)61 SearchList(
62   IN CONST CHAR16   *List,
63   IN CONST CHAR16   *MetaTarget,
64   OUT CHAR16        **FullName OPTIONAL,
65   IN CONST BOOLEAN  Meta,
66   IN CONST BOOLEAN  SkipTrailingNumbers,
67   IN CONST CHAR16   *Target
68 
69   )
70 {
71   CHAR16        *TempList;
72   CONST CHAR16  *ListWalker;
73   BOOLEAN       Result;
74   CHAR16        *TempSpot;
75 
76   for (ListWalker = List , TempList = NULL
77      ; ListWalker != NULL && *ListWalker != CHAR_NULL
78      ;
79    ) {
80     TempList = StrnCatGrow(&TempList, NULL, ListWalker, 0);
81     ASSERT(TempList != NULL);
82     TempSpot = StrStr(TempList, Target);
83     if (TempSpot != NULL) {
84       *TempSpot = CHAR_NULL;
85     }
86 
87     while (SkipTrailingNumbers && (ShellIsDecimalDigitCharacter(TempList[StrLen(TempList)-1]) || TempList[StrLen(TempList)-1] == L':')) {
88       TempList[StrLen(TempList)-1] = CHAR_NULL;
89     }
90 
91     ListWalker = StrStr(ListWalker, Target);
92     while(ListWalker != NULL && *ListWalker == *Target) {
93       ListWalker++;
94     }
95     if (Meta) {
96       Result = gUnicodeCollation->MetaiMatch(gUnicodeCollation, (CHAR16*)TempList, (CHAR16*)MetaTarget);
97     } else {
98       Result = (BOOLEAN)(StrCmp(TempList, MetaTarget)==0);
99     }
100     if (Result) {
101       if (FullName != NULL) {
102         *FullName = TempList;
103       } else {
104         FreePool(TempList);
105       }
106       return (TRUE);
107     }
108     FreePool(TempList);
109     TempList = NULL;
110   }
111 
112   return (FALSE);
113 }
114 
115 /**
116   Determine what type of device is represented and return it's string.  The
117   string is in allocated memory and must be callee freed.  The HII is is listed below.
118   The actual string cannot be determined.
119 
120   @param[in] DevicePath     The device to analyze.
121 
122   @retval STR_MAP_MEDIA_UNKNOWN   The media type is unknown.
123   @retval STR_MAP_MEDIA_HARDDISK  The media is a hard drive.
124   @retval STR_MAP_MEDIA_CDROM     The media is a CD ROM.
125   @retval STR_MAP_MEDIA_FLOPPY    The media is a floppy drive.
126 **/
127 CHAR16*
GetDeviceMediaType(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)128 GetDeviceMediaType (
129   IN  EFI_DEVICE_PATH_PROTOCOL     *DevicePath
130   )
131 {
132   ACPI_HID_DEVICE_PATH  *Acpi;
133 
134   //
135   //  Parse the device path:
136   //  Devicepath sub type                 mediatype
137   //    MEDIA_HANRDDRIVE_DP      ->       Hard Disk
138   //    MEDIA_CDROM_DP           ->       CD Rom
139   //    Acpi.HID = 0X0604        ->       Floppy
140   //
141   if (NULL == DevicePath) {
142     return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_UNKNOWN), NULL);
143   }
144 
145   for (;!IsDevicePathEndType (DevicePath) ;DevicePath = NextDevicePathNode (DevicePath)) {
146     if (DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) {
147       switch (DevicePathSubType (DevicePath)) {
148       case MEDIA_HARDDRIVE_DP:
149         return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_HARDDISK), NULL);
150       case MEDIA_CDROM_DP:
151         return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_CDROM), NULL);
152       }
153     } else if (DevicePathType (DevicePath) == ACPI_DEVICE_PATH) {
154       Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
155       if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
156         return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_FLOPPY), NULL);
157       }
158     }
159   }
160 
161   return HiiGetString(gShellLevel2HiiHandle, STRING_TOKEN(STR_MAP_MEDIA_UNKNOWN), NULL);
162 }
163 
164 /**
165   Function to detemine if a handle has removable storage.
166 
167   @param[in] DevicePath             DevicePath to test.
168 
169   @retval TRUE                      The handle has removable storage.
170   @retval FALSE                     The handle does not have removable storage.
171 **/
172 BOOLEAN
IsRemoveableDevice(IN EFI_DEVICE_PATH_PROTOCOL * DevicePath)173 IsRemoveableDevice (
174   IN EFI_DEVICE_PATH_PROTOCOL      *DevicePath
175   )
176 {
177   if (NULL == DevicePath) {
178     return FALSE;
179   }
180 
181   while (!IsDevicePathEndType (DevicePath)) {
182     if (DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) {
183       switch (DevicePathSubType (DevicePath)) {
184       case MSG_USB_DP:
185       case MSG_SCSI_DP:
186         return TRUE;
187       default:
188         return FALSE;
189       }
190     }
191     DevicePath = NextDevicePathNode (DevicePath);
192   }
193   return FALSE;
194 }
195 
196 /**
197   Function to detemine if a something on the map list matches.
198 
199   @param[in] MapList          The pointer to the list to test.
200   @param[in] Specific         The pointer to a specific name to test for.
201   @param[in] TypeString       The pointer to the list of types.
202   @param[in] Normal           Always show normal mappings.
203   @param[in] Consist          Always show consistent mappings.
204 
205   @retval TRUE                The map should be displayed.
206   @retval FALSE               The map should not be displayed.
207 **/
208 BOOLEAN
MappingListHasType(IN CONST CHAR16 * MapList,IN CONST CHAR16 * Specific,IN CONST CHAR16 * TypeString,IN CONST BOOLEAN Normal,IN CONST BOOLEAN Consist)209 MappingListHasType(
210   IN CONST CHAR16     *MapList,
211   IN CONST CHAR16     *Specific,
212   IN CONST CHAR16     *TypeString,
213   IN CONST BOOLEAN    Normal,
214   IN CONST BOOLEAN    Consist
215   )
216 {
217   CHAR16              *NewSpecific;
218   RETURN_STATUS       Status;
219   UINTN               Length;
220 
221   //
222   // specific has priority
223   //
224   if (Specific != NULL) {
225     Length      = StrLen (Specific);
226     //
227     // Allocate enough buffer for Specific and potential ":"
228     //
229     NewSpecific = AllocatePool ((Length + 2) * sizeof(CHAR16));
230     if (NewSpecific == NULL){
231       return FALSE;
232     }
233     StrCpyS (NewSpecific, Length + 2, Specific);
234     if (Specific[Length - 1] != L':') {
235       Status = StrnCatS(NewSpecific, Length + 2, L":", StrLen(L":"));
236       if (EFI_ERROR (Status)) {
237         FreePool(NewSpecific);
238         return FALSE;
239       }
240     }
241 
242     if (SearchList(MapList, NewSpecific, NULL, TRUE, FALSE, L";")) {
243       FreePool(NewSpecific);
244       return (TRUE);
245     }
246     FreePool(NewSpecific);
247   }
248   if (  Consist
249     && Specific == NULL
250     && (SearchList(MapList, L"HD*",  NULL, TRUE, TRUE, L";")
251       ||SearchList(MapList, L"CD*",  NULL, TRUE, TRUE, L";")
252       ||SearchList(MapList, L"F*",   NULL, TRUE, TRUE, L";")
253       ||SearchList(MapList, L"FP*",  NULL, TRUE, TRUE, L";"))){
254     return (TRUE);
255   }
256 
257   if (  Normal
258     && Specific == NULL
259     && (SearchList(MapList, L"FS",  NULL, FALSE, TRUE, L";")
260       ||SearchList(MapList, L"BLK", NULL, FALSE, TRUE, L";"))){
261     return (TRUE);
262   }
263 
264   if (TypeString != NULL && SearchList(MapList, TypeString,  NULL, TRUE, TRUE, L";")) {
265     return (TRUE);
266   }
267   return (FALSE);
268 }
269 
270 
271 /**
272   Display a single map line for device Handle if conditions are met.
273 
274   @param[in] Verbose                TRUE to display (extra) verbose information.
275   @param[in] Consist                TRUE to display consistent mappings.
276   @param[in] Normal                 TRUE to display normal (not consist) mappings.
277   @param[in] TypeString             pointer to string of filter types.
278   @param[in] SFO                    TRUE to display output in Standard Output Format.
279   @param[in] Specific               pointer to string for specific map to display.
280   @param[in] Handle                 The handle to display from.
281 
282   @retval EFI_SUCCESS               The mapping was displayed.
283 **/
284 EFI_STATUS
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)285 PerformSingleMappingDisplay(
286   IN CONST BOOLEAN    Verbose,
287   IN CONST BOOLEAN    Consist,
288   IN CONST BOOLEAN    Normal,
289   IN CONST CHAR16     *TypeString,
290   IN CONST BOOLEAN    SFO,
291   IN CONST CHAR16     *Specific OPTIONAL,
292   IN CONST EFI_HANDLE Handle
293   )
294 {
295   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
296   EFI_DEVICE_PATH_PROTOCOL  *DevPathCopy;
297   CONST CHAR16              *MapList;
298   CHAR16                    *CurrentName;
299   CHAR16                    *MediaType;
300   CHAR16                    *DevPathString;
301   CHAR16                    *TempSpot;
302   CHAR16                    *Alias;
303   UINTN                     TempLen;
304   BOOLEAN                   Removable;
305   CONST CHAR16              *TempSpot2;
306 
307   Alias       = NULL;
308   TempSpot2   = NULL;
309   CurrentName = NULL;
310   DevPath = DevicePathFromHandle(Handle);
311   DevPathCopy = DevPath;
312   MapList = gEfiShellProtocol->GetMapFromDevicePath(&DevPathCopy);
313   if (MapList == NULL) {
314     return EFI_NOT_FOUND;
315   }
316 
317   if (!MappingListHasType(MapList, Specific, TypeString, Normal, Consist)){
318     return EFI_NOT_FOUND;
319   }
320 
321   if (Normal || !Consist) {
322     //
323     // need the Normal here since people can use both on command line.  otherwise unused.
324     //
325 
326     //
327     // Allocate a name
328     //
329     CurrentName = NULL;
330     CurrentName = StrnCatGrow(&CurrentName, 0, MapList, 0);
331     if (CurrentName == NULL) {
332       return (EFI_OUT_OF_RESOURCES);
333     }
334 
335     //
336     // Chop off the other names that become "Alias(s)"
337     // leaving just the normal name
338     //
339     TempSpot = StrStr(CurrentName, L";");
340     if (TempSpot != NULL) {
341       *TempSpot = CHAR_NULL;
342     }
343   } else {
344     CurrentName = NULL;
345 
346     //
347     // Skip the first name.  This is the standard name.
348     //
349     TempSpot = StrStr(MapList, L";");
350     if (TempSpot != NULL) {
351       TempSpot++;
352     }
353     SearchList(TempSpot, L"HD*", &CurrentName, TRUE, FALSE, L";");
354     if (CurrentName == NULL) {
355       SearchList(TempSpot, L"CD*", &CurrentName, TRUE, FALSE, L";");
356     }
357     if (CurrentName == NULL) {
358       SearchList(TempSpot, L"FP*", &CurrentName, TRUE, FALSE, L";");
359     }
360     if (CurrentName == NULL) {
361       SearchList(TempSpot, L"F*",  &CurrentName, TRUE, FALSE, L";");
362     }
363     if (CurrentName == NULL) {
364       //
365       // We didnt find anything, so just the first one in the list...
366       //
367       CurrentName = StrnCatGrow(&CurrentName, 0, MapList, 0);
368       if (CurrentName == NULL) {
369         return (EFI_OUT_OF_RESOURCES);
370       }
371       TempSpot = StrStr(CurrentName, L";");
372       if (TempSpot != NULL) {
373         *TempSpot = CHAR_NULL;
374       }
375     } else {
376       Alias = StrnCatGrow(&Alias, 0, MapList, 0);
377       if (Alias == NULL) {
378         return EFI_OUT_OF_RESOURCES;
379       }
380       TempSpot = StrStr(Alias, CurrentName);
381       if (TempSpot != NULL) {
382         TempSpot2 = StrStr(TempSpot, L";");
383         if (TempSpot2 != NULL) {
384           TempSpot2++; // Move past ";" from CurrentName
385           CopyMem(TempSpot, TempSpot2, StrSize(TempSpot2));
386         } else {
387           *TempSpot = CHAR_NULL;
388         }
389       }
390       if (Alias[StrLen(Alias)-1] == L';') {
391         Alias[StrLen(Alias)-1] = CHAR_NULL;
392       }
393     }
394   }
395   DevPathString = ConvertDevicePathToText(DevPath, TRUE, FALSE);
396   TempLen = StrLen(CurrentName);
397   if (!SFO) {
398     ShellPrintHiiEx (
399       -1,
400       -1,
401       NULL,
402       STRING_TOKEN (STR_MAP_ENTRY),
403       gShellLevel2HiiHandle,
404       CurrentName,
405       Alias!=NULL?Alias:(TempLen < StrLen(MapList)?MapList + TempLen+1:L""),
406       DevPathString
407      );
408     if (Verbose) {
409       //
410       // also print handle, media type, removable (y/n), and current directory
411       //
412       MediaType = GetDeviceMediaType(DevPath);
413       if ((TypeString != NULL &&MediaType != NULL && StrStr(TypeString, MediaType) != NULL) || TypeString == NULL) {
414         Removable = IsRemoveableDevice(DevPath);
415         TempSpot2 = ShellGetCurrentDir(CurrentName);
416         ShellPrintHiiEx (
417           -1,
418           -1,
419           NULL,
420           STRING_TOKEN (STR_MAP_ENTRY_VERBOSE),
421           gShellLevel2HiiHandle,
422           ConvertHandleToHandleIndex(Handle),
423           MediaType,
424           Removable?L"Yes":L"No",
425           TempSpot2
426          );
427       }
428       SHELL_FREE_NON_NULL(MediaType);
429     }
430   } else {
431     ShellPrintHiiEx (
432       -1,
433       -1,
434       NULL,
435       STRING_TOKEN (STR_MAP_SFO_MAPPINGS),
436       gShellLevel2HiiHandle,
437       CurrentName,
438       DevPathString,
439       Consist?L"":(TempLen < StrLen(MapList)?MapList + TempLen+1:L"")
440      );
441   }
442   SHELL_FREE_NON_NULL(DevPathString);
443   SHELL_FREE_NON_NULL(CurrentName);
444   SHELL_FREE_NON_NULL(Alias);
445   return EFI_SUCCESS;
446 }
447 
448 /**
449   Delete Specific from the list of maps for device Handle.
450 
451   @param[in] Specific   The name to delete.
452   @param[in] Handle     The device to look on.
453 
454   @retval EFI_SUCCESS     The delete was successful.
455   @retval EFI_NOT_FOUND   Name was not a map on Handle.
456 **/
457 EFI_STATUS
PerformSingleMappingDelete(IN CONST CHAR16 * Specific,IN CONST EFI_HANDLE Handle)458 PerformSingleMappingDelete(
459   IN CONST CHAR16     *Specific,
460   IN CONST EFI_HANDLE Handle
461   )
462 {
463   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
464   EFI_DEVICE_PATH_PROTOCOL  *DevPathCopy;
465   CONST CHAR16              *MapList;
466   CHAR16                    *CurrentName;
467 
468   DevPath     = DevicePathFromHandle(Handle);
469   DevPathCopy = DevPath;
470   MapList     = gEfiShellProtocol->GetMapFromDevicePath(&DevPathCopy);
471   CurrentName = NULL;
472 
473   if (MapList == NULL) {
474     return (EFI_NOT_FOUND);
475   }
476   //
477   // if there is a specific and its not on the list...
478   //
479   if (!SearchList(MapList, Specific, &CurrentName, TRUE, FALSE, L";")) {
480     return (EFI_NOT_FOUND);
481   }
482   return (gEfiShellProtocol->SetMap(NULL, CurrentName));
483 }
484 
485 CONST CHAR16 Cd[] = L"cd*";
486 CONST CHAR16 Hd[] = L"hd*";
487 CONST CHAR16 Fp[] = L"fp*";
488 CONST CHAR16 AnyF[] = L"F*";
489 /**
490   Function to display mapping information to the user.
491 
492   If Specific is specified then Consist and Normal will be ignored since information will
493   be printed for the specific item only.
494 
495   @param[in] Verbose                TRUE to display (extra) verbose information.
496   @param[in] Consist                TRUE to display consistent mappings.
497   @param[in] Normal                 TRUE to display normal (not consist) mappings.
498   @param[in] TypeString             Pointer to string of filter types.
499   @param[in] SFO                    TRUE to display output in Standard Output Format.
500   @param[in] Specific               Pointer to string for specific map to display.
501   @param[in] Header                 TRUE to print the header block.
502 
503   @retval SHELL_SUCCESS               The display was printed.
504   @retval SHELL_INVALID_PARAMETER     One of Consist or Normal must be TRUE if no Specific.
505 
506 **/
507 SHELL_STATUS
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)508 PerformMappingDisplay(
509   IN CONST BOOLEAN Verbose,
510   IN CONST BOOLEAN Consist,
511   IN CONST BOOLEAN Normal,
512   IN CONST CHAR16  *TypeString,
513   IN CONST BOOLEAN SFO,
514   IN CONST CHAR16  *Specific OPTIONAL,
515   IN CONST BOOLEAN Header
516   )
517 {
518   EFI_STATUS                Status;
519   EFI_HANDLE                *HandleBuffer;
520   UINTN                     BufferSize;
521   UINTN                     LoopVar;
522   CHAR16                    *Test;
523   BOOLEAN                   Found;
524 
525   if (!Consist && !Normal && Specific == NULL && TypeString == NULL) {
526     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"map");
527     return (SHELL_INVALID_PARAMETER);
528   }
529 
530   if (TypeString != NULL) {
531     Test = (CHAR16*)Cd;
532     if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) {
533       Test = (CHAR16*)Hd;
534       if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) {
535         Test = (CHAR16*)Fp;
536         if (StrnCmp(TypeString, Test, StrLen(Test)-1) != 0) {
537           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", TypeString);
538           return (SHELL_INVALID_PARAMETER);
539         }
540       } else if (Test == NULL) {
541         Test = (CHAR16*)AnyF;
542       }
543     }
544   } else {
545     Test = NULL;
546   }
547 
548   if (Header) {
549     //
550     // Print the header
551     //
552     if (!SFO) {
553       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_HEADER), gShellLevel2HiiHandle);
554     } else {
555       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel2HiiHandle, L"map");
556     }
557   }
558 
559   BufferSize    = 0;
560   HandleBuffer  = NULL;
561 
562   //
563   // Look up all SimpleFileSystems in the platform
564   //
565   Status = gBS->LocateHandle(
566     ByProtocol,
567     &gEfiSimpleFileSystemProtocolGuid,
568     NULL,
569     &BufferSize,
570     HandleBuffer);
571   if (Status == EFI_BUFFER_TOO_SMALL) {
572     HandleBuffer = AllocateZeroPool(BufferSize);
573     if (HandleBuffer == NULL) {
574       return (SHELL_OUT_OF_RESOURCES);
575     }
576     Status = gBS->LocateHandle(
577       ByProtocol,
578       &gEfiSimpleFileSystemProtocolGuid,
579       NULL,
580       &BufferSize,
581       HandleBuffer);
582   }
583 
584   //
585   // Get the map name(s) for each one.
586   //
587   for ( LoopVar = 0, Found = FALSE
588       ; LoopVar < (BufferSize / sizeof(EFI_HANDLE)) && HandleBuffer != NULL
589       ; LoopVar ++
590      ){
591     Status = PerformSingleMappingDisplay(
592       Verbose,
593       Consist,
594       Normal,
595       Test,
596       SFO,
597       Specific,
598       HandleBuffer[LoopVar]);
599     if (!EFI_ERROR(Status)) {
600       Found = TRUE;
601     }
602   }
603 
604   //
605   // Look up all BlockIo in the platform
606   //
607   Status = gBS->LocateHandle(
608     ByProtocol,
609     &gEfiBlockIoProtocolGuid,
610     NULL,
611     &BufferSize,
612     HandleBuffer);
613   if (Status == EFI_BUFFER_TOO_SMALL) {
614     SHELL_FREE_NON_NULL(HandleBuffer);
615     HandleBuffer = AllocateZeroPool(BufferSize);
616     if (HandleBuffer == NULL) {
617       return (SHELL_OUT_OF_RESOURCES);
618     }
619     Status = gBS->LocateHandle(
620       ByProtocol,
621       &gEfiBlockIoProtocolGuid,
622       NULL,
623       &BufferSize,
624       HandleBuffer);
625   }
626   if (!EFI_ERROR(Status) && HandleBuffer != NULL) {
627     //
628     // Get the map name(s) for each one.
629     //
630     for ( LoopVar = 0
631         ; LoopVar < BufferSize / sizeof(EFI_HANDLE)
632         ; LoopVar ++
633        ){
634       //
635       // Skip any that were already done...
636       //
637       if (gBS->OpenProtocol(
638         HandleBuffer[LoopVar],
639         &gEfiSimpleFileSystemProtocolGuid,
640         NULL,
641         gImageHandle,
642         NULL,
643         EFI_OPEN_PROTOCOL_TEST_PROTOCOL) == EFI_SUCCESS) {
644           continue;
645       }
646       Status = PerformSingleMappingDisplay(
647         Verbose,
648         Consist,
649         Normal,
650         Test,
651         SFO,
652         Specific,
653         HandleBuffer[LoopVar]);
654       if (!EFI_ERROR(Status)) {
655         Found = TRUE;
656       }
657     }
658     FreePool(HandleBuffer);
659   }
660   if (!Found) {
661     if (Specific != NULL) {
662       ShellPrintHiiEx(gST->ConOut->Mode->CursorColumn, gST->ConOut->Mode->CursorRow-1, NULL, STRING_TOKEN (STR_MAP_NF), gShellLevel2HiiHandle, L"map", Specific);
663     } else {
664       ShellPrintHiiEx(gST->ConOut->Mode->CursorColumn, gST->ConOut->Mode->CursorRow-1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"map");
665     }
666   }
667   return (SHELL_SUCCESS);
668 }
669 
670 /**
671   Perform a mapping display and parse for multiple types in the TypeString.
672 
673   @param[in] Verbose      TRUE to use verbose output.
674   @param[in] Consist      TRUE to display consistent names.
675   @param[in] Normal       TRUE to display normal names.
676   @param[in] TypeString   An optional comma-delimited list of types.
677   @param[in] SFO          TRUE to display in SFO format.  See Spec.
678   @param[in] Specific     An optional specific map name to display alone.
679 
680   @retval SHELL_INVALID_PARAMETER   A parameter was invalid.
681   @retval SHELL_SUCCESS             The display was successful.
682   @sa PerformMappingDisplay
683 **/
684 SHELL_STATUS
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)685 PerformMappingDisplay2(
686   IN CONST BOOLEAN Verbose,
687   IN CONST BOOLEAN Consist,
688   IN CONST BOOLEAN Normal,
689   IN CONST CHAR16  *TypeString,
690   IN CONST BOOLEAN SFO,
691   IN CONST CHAR16  *Specific OPTIONAL
692   )
693 {
694   CONST CHAR16  *TypeWalker;
695   SHELL_STATUS  ShellStatus;
696   CHAR16        *Comma;
697 
698 
699   if (TypeString == NULL) {
700     return (PerformMappingDisplay(Verbose, Consist, Normal, NULL, SFO, Specific, TRUE));
701   }
702   ShellStatus = SHELL_SUCCESS;
703   for (TypeWalker = TypeString ; TypeWalker != NULL && *TypeWalker != CHAR_NULL ;) {
704     Comma = StrStr(TypeWalker, L",");
705     if (Comma == NULL) {
706       if (ShellStatus == SHELL_SUCCESS) {
707         ShellStatus = PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString));
708       } else {
709         PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString));
710       }
711       break;
712     } else {
713       *Comma = CHAR_NULL;
714       if (ShellStatus == SHELL_SUCCESS) {
715         ShellStatus = PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString));
716       } else {
717         PerformMappingDisplay(Verbose, Consist, Normal, TypeWalker, SFO, Specific, (BOOLEAN)(TypeWalker == TypeString));
718       }
719       *Comma = L',';
720       TypeWalker = Comma + 1;
721     }
722   }
723 
724   return (ShellStatus);
725 }
726 
727 /**
728   Delete a specific map.
729 
730   @param[in] Specific  The pointer to the name of the map to delete.
731 
732   @retval EFI_INVALID_PARAMETER     Specific was NULL.
733   @retval EFI_SUCCESS               The operation was successful.
734   @retval EFI_NOT_FOUND             Specific could not be found.
735 **/
736 EFI_STATUS
PerformMappingDelete(IN CONST CHAR16 * Specific)737 PerformMappingDelete(
738   IN CONST CHAR16  *Specific
739   )
740 {
741   EFI_STATUS                Status;
742   EFI_HANDLE                *HandleBuffer;
743   UINTN                     BufferSize;
744   UINTN                     LoopVar;
745   BOOLEAN                   Deleted;
746 
747   if (Specific == NULL) {
748     return (EFI_INVALID_PARAMETER);
749   }
750 
751   BufferSize    = 0;
752   HandleBuffer  = NULL;
753   Deleted       = FALSE;
754 
755   //
756   // Look up all SimpleFileSystems in the platform
757   //
758   Status = gBS->LocateHandle(
759     ByProtocol,
760     &gEfiDevicePathProtocolGuid,
761     NULL,
762     &BufferSize,
763     HandleBuffer);
764   if (Status == EFI_BUFFER_TOO_SMALL) {
765     HandleBuffer = AllocateZeroPool(BufferSize);
766     if (HandleBuffer == NULL) {
767       return (EFI_OUT_OF_RESOURCES);
768     }
769     Status = gBS->LocateHandle(
770       ByProtocol,
771       &gEfiDevicePathProtocolGuid,
772       NULL,
773       &BufferSize,
774       HandleBuffer);
775   }
776   if (EFI_ERROR(Status)) {
777     SHELL_FREE_NON_NULL(HandleBuffer);
778     return (Status);
779   }
780 
781   if (HandleBuffer != NULL) {
782     //
783     // Get the map name(s) for each one.
784     //
785     for ( LoopVar = 0
786         ; LoopVar < BufferSize / sizeof(EFI_HANDLE)
787         ; LoopVar ++
788        ){
789       if (PerformSingleMappingDelete(Specific,HandleBuffer[LoopVar]) == SHELL_SUCCESS) {
790           Deleted = TRUE;
791       }
792     }
793   }
794   //
795   // Look up all BlockIo in the platform
796   //
797   Status = gBS->LocateHandle(
798     ByProtocol,
799     &gEfiBlockIoProtocolGuid,
800     NULL,
801     &BufferSize,
802     HandleBuffer);
803   if (Status == EFI_BUFFER_TOO_SMALL) {
804     FreePool(HandleBuffer);
805     HandleBuffer = AllocateZeroPool(BufferSize);
806     if (HandleBuffer == NULL) {
807       return (EFI_OUT_OF_RESOURCES);
808     }
809     Status = gBS->LocateHandle(
810       ByProtocol,
811       &gEfiBlockIoProtocolGuid,
812       NULL,
813       &BufferSize,
814       HandleBuffer);
815   }
816   if (EFI_ERROR(Status)) {
817     SHELL_FREE_NON_NULL(HandleBuffer);
818     return (Status);
819   }
820 
821   if (HandleBuffer != NULL) {
822     //
823     // Get the map name(s) for each one.
824     //
825     for ( LoopVar = 0
826         ; LoopVar < BufferSize / sizeof(EFI_HANDLE)
827         ; LoopVar ++
828        ){
829       //
830       // Skip any that were already done...
831       //
832       if (gBS->OpenProtocol(
833         HandleBuffer[LoopVar],
834         &gEfiDevicePathProtocolGuid,
835         NULL,
836         gImageHandle,
837         NULL,
838         EFI_OPEN_PROTOCOL_TEST_PROTOCOL) == EFI_SUCCESS) {
839           continue;
840       }
841       if (PerformSingleMappingDelete(Specific,HandleBuffer[LoopVar]) == SHELL_SUCCESS) {
842           Deleted = TRUE;
843       }
844     }
845   }
846   SHELL_FREE_NON_NULL(HandleBuffer);
847   if (!Deleted) {
848     return (EFI_NOT_FOUND);
849   }
850   return (EFI_SUCCESS);
851 }
852 
853 /**
854   function to add a mapping from mapping.
855 
856   This function will get the device path associated with the mapping and call SetMap.
857 
858   @param[in] Map         The Map to add a mapping for
859   @param[in] SName       The name of the new mapping
860 
861   @retval SHELL_SUCCESS             the mapping was added
862   @retval SHELL_INVALID_PARAMETER   the device path for Map could not be retrieved.
863   @return                           Shell version of a return value from EfiShellProtocol->SetMap
864 
865 **/
866 SHELL_STATUS
AddMappingFromMapping(IN CONST CHAR16 * Map,IN CONST CHAR16 * SName)867 AddMappingFromMapping(
868   IN CONST CHAR16     *Map,
869   IN CONST CHAR16     *SName
870   )
871 {
872   CONST EFI_DEVICE_PATH_PROTOCOL  *DevPath;
873   EFI_STATUS                      Status;
874   CHAR16                          *NewSName;
875   RETURN_STATUS                   StrRetStatus;
876 
877   NewSName = AllocateCopyPool(StrSize(SName) + sizeof(CHAR16), SName);
878   if (NewSName == NULL) {
879     return (SHELL_OUT_OF_RESOURCES);
880   }
881   if (NewSName[StrLen(NewSName)-1] != L':') {
882     StrRetStatus = StrnCatS(NewSName, (StrSize(SName) + sizeof(CHAR16))/sizeof(CHAR16), L":", StrLen(L":"));
883     if (EFI_ERROR(StrRetStatus)) {
884       FreePool(NewSName);
885       return ((SHELL_STATUS) (StrRetStatus & (~MAX_BIT)));
886     }
887   }
888 
889   if (!IsNumberLetterOnly(NewSName, StrLen(NewSName)-1)) {
890     FreePool(NewSName);
891     return (SHELL_INVALID_PARAMETER);
892   }
893 
894   DevPath = gEfiShellProtocol->GetDevicePathFromMap(Map);
895   if (DevPath == NULL) {
896     FreePool(NewSName);
897     return (SHELL_INVALID_PARAMETER);
898   }
899 
900   Status = gEfiShellProtocol->SetMap(DevPath, NewSName);
901   FreePool(NewSName);
902   if (EFI_ERROR(Status)) {
903     return (SHELL_DEVICE_ERROR);
904   }
905   return (SHELL_SUCCESS);
906 }
907 
908 /**
909   function to add a mapping from an EFI_HANDLE.
910 
911   This function will get the device path associated with the Handle and call SetMap.
912 
913   @param[in] Handle       The handle to add a mapping for
914   @param[in] SName        The name of the new mapping
915 
916   @retval SHELL_SUCCESS           the mapping was added
917   @retval SHELL_INVALID_PARAMETER SName was not valid for a map name.
918   @return                         Shell version of a return value from either
919                                   gBS->OpenProtocol or EfiShellProtocol->SetMap
920 
921 **/
922 SHELL_STATUS
AddMappingFromHandle(IN CONST EFI_HANDLE Handle,IN CONST CHAR16 * SName)923 AddMappingFromHandle(
924   IN CONST EFI_HANDLE Handle,
925   IN CONST CHAR16     *SName
926   )
927 {
928   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
929   EFI_STATUS                Status;
930   CHAR16                    *NewSName;
931   RETURN_STATUS             StrRetStatus;
932 
933   NewSName = AllocateCopyPool(StrSize(SName) + sizeof(CHAR16), SName);
934   if (NewSName == NULL) {
935     return (SHELL_OUT_OF_RESOURCES);
936   }
937   if (NewSName[StrLen(NewSName)-1] != L':') {
938     StrRetStatus = StrnCatS(NewSName, (StrSize(SName) + sizeof(CHAR16))/sizeof(CHAR16), L":", StrLen(L":"));
939     if (EFI_ERROR(StrRetStatus)) {
940       FreePool(NewSName);
941       return ((SHELL_STATUS) (StrRetStatus & (~MAX_BIT)));
942     }
943   }
944 
945   if (!IsNumberLetterOnly(NewSName, StrLen(NewSName)-1)) {
946     FreePool(NewSName);
947     return (SHELL_INVALID_PARAMETER);
948   }
949 
950   Status = gBS->OpenProtocol(
951     Handle,
952     &gEfiDevicePathProtocolGuid,
953     (VOID**)&DevPath,
954     gImageHandle,
955     NULL,
956     EFI_OPEN_PROTOCOL_GET_PROTOCOL
957    );
958   if (EFI_ERROR(Status)) {
959     FreePool(NewSName);
960     return (SHELL_DEVICE_ERROR);
961   }
962   Status = gEfiShellProtocol->SetMap(DevPath, NewSName);
963   FreePool(NewSName);
964   if (EFI_ERROR(Status)) {
965     return (SHELL_DEVICE_ERROR);
966   }
967   return (SHELL_SUCCESS);
968 }
969 
970 STATIC CONST SHELL_PARAM_ITEM MapParamList[] = {
971   {L"-d", TypeValue},
972   {L"-r", TypeFlag},
973   {L"-v", TypeFlag},
974   {L"-c", TypeFlag},
975   {L"-f", TypeFlag},
976   {L"-u", TypeFlag},
977   {L"-t", TypeValue},
978   {L"-sfo", TypeValue},
979   {NULL, TypeMax}
980   };
981 
982 /**
983   The routine issues dummy read for every physical block device to cause
984   the BlockIo re-installed if media change happened.
985 **/
986 VOID
ProbeForMediaChange(VOID)987 ProbeForMediaChange (
988   VOID
989   )
990 {
991   EFI_STATUS                            Status;
992   UINTN                                 HandleCount;
993   EFI_HANDLE                            *Handles;
994   EFI_BLOCK_IO_PROTOCOL                 *BlockIo;
995   UINTN                                 Index;
996 
997   gBS->LocateHandleBuffer (
998          ByProtocol,
999          &gEfiBlockIoProtocolGuid,
1000          NULL,
1001          &HandleCount,
1002          &Handles
1003          );
1004   //
1005   // Probe for media change for every physical block io
1006   //
1007   for (Index = 0; Index < HandleCount; Index++) {
1008     Status = gBS->HandleProtocol (
1009                     Handles[Index],
1010                     &gEfiBlockIoProtocolGuid,
1011                     (VOID **) &BlockIo
1012                     );
1013     if (!EFI_ERROR (Status)) {
1014       if (!BlockIo->Media->LogicalPartition) {
1015         //
1016         // Per spec:
1017         //   The function (ReadBlocks) must return EFI_NO_MEDIA or
1018         //   EFI_MEDIA_CHANGED even if LBA, BufferSize, or Buffer are invalid so the caller can probe
1019         //   for changes in media state.
1020         //
1021         BlockIo->ReadBlocks (
1022                    BlockIo,
1023                    BlockIo->Media->MediaId,
1024                    0,
1025                    0,
1026                    NULL
1027                    );
1028       }
1029     }
1030   }
1031 }
1032 
1033 /**
1034   Function for 'map' command.
1035 
1036   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
1037   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
1038 **/
1039 SHELL_STATUS
1040 EFIAPI
ShellCommandRunMap(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1041 ShellCommandRunMap (
1042   IN EFI_HANDLE        ImageHandle,
1043   IN EFI_SYSTEM_TABLE  *SystemTable
1044   )
1045 {
1046   EFI_STATUS    Status;
1047   LIST_ENTRY    *Package;
1048   CHAR16        *ProblemParam;
1049   CONST CHAR16  *SName;
1050   CONST CHAR16  *Mapping;
1051   EFI_HANDLE    MapAsHandle;
1052   SHELL_STATUS  ShellStatus;
1053   BOOLEAN       SfoMode;
1054   BOOLEAN       ConstMode;
1055   BOOLEAN       NormlMode;
1056   CONST CHAR16  *Param1;
1057   CONST CHAR16  *TypeString;
1058   UINTN         TempStringLength;
1059 
1060   ProblemParam  = NULL;
1061   Mapping       = NULL;
1062   SName         = NULL;
1063   ShellStatus   = SHELL_SUCCESS;
1064   MapAsHandle = NULL;
1065 
1066   //
1067   // initialize the shell lib (we must be in non-auto-init...)
1068   //
1069   Status = ShellInitialize();
1070   ASSERT_EFI_ERROR(Status);
1071 
1072   Status = CommandInit();
1073   ASSERT_EFI_ERROR(Status);
1074 
1075   //
1076   // parse the command line
1077   //
1078   Status = ShellCommandLineParse (MapParamList, &Package, &ProblemParam, TRUE);
1079   if (EFI_ERROR(Status)) {
1080     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
1081       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"map", ProblemParam);
1082       FreePool(ProblemParam);
1083       ShellStatus = SHELL_INVALID_PARAMETER;
1084     } else {
1085       ASSERT(FALSE);
1086     }
1087   } else {
1088     //
1089     // check for "-?"
1090     //
1091     SfoMode   = ShellCommandLineGetFlag(Package, L"-sfo");
1092     ConstMode = ShellCommandLineGetFlag(Package, L"-c");
1093     NormlMode = ShellCommandLineGetFlag(Package, L"-f");
1094     if (ShellCommandLineGetFlag(Package, L"-?")) {
1095       ASSERT(FALSE);
1096     } else if (ShellCommandLineGetRawValue(Package, 3) != NULL) {
1097       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"map");
1098       ShellStatus = SHELL_INVALID_PARAMETER;
1099     } else {
1100       //
1101       // Deleting a map name...
1102       //
1103       if (ShellCommandLineGetFlag(Package, L"-d")) {
1104         if ( ShellCommandLineGetFlag(Package, L"-r")
1105           || ShellCommandLineGetFlag(Package, L"-v")
1106           || ConstMode
1107           || NormlMode
1108           || ShellCommandLineGetFlag(Package, L"-u")
1109           || ShellCommandLineGetFlag(Package, L"-t")
1110          ){
1111           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CON), gShellLevel2HiiHandle, L"map");
1112           ShellStatus = SHELL_INVALID_PARAMETER;
1113         } else {
1114           SName = ShellCommandLineGetValue(Package, L"-d");
1115           if (SName != NULL) {
1116             Status = PerformMappingDelete(SName);
1117             if (EFI_ERROR(Status)) {
1118               if (Status == EFI_ACCESS_DENIED) {
1119                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel2HiiHandle, L"map");
1120                 ShellStatus = SHELL_ACCESS_DENIED;
1121               } else if (Status == EFI_NOT_FOUND) {
1122                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_NF), gShellLevel2HiiHandle, L"map", SName);
1123                 ShellStatus = SHELL_INVALID_PARAMETER;
1124               } else {
1125                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status);
1126                 ShellStatus = SHELL_UNSUPPORTED;
1127               }
1128             }
1129           } else {
1130             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"map");
1131             ShellStatus = SHELL_INVALID_PARAMETER;
1132           }
1133         }
1134       } else if ( ShellCommandLineGetFlag(Package, L"-r")
1135 //               || ShellCommandLineGetFlag(Package, L"-v")
1136                || ConstMode
1137                || NormlMode
1138                || ShellCommandLineGetFlag(Package, L"-u")
1139                || ShellCommandLineGetFlag(Package, L"-t")
1140               ){
1141         ProbeForMediaChange ();
1142         if ( ShellCommandLineGetFlag(Package, L"-r")) {
1143           //
1144           // Do the reset
1145           //
1146           Status = ShellCommandCreateInitialMappingsAndPaths();
1147           if (EFI_ERROR(Status)) {
1148             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status);
1149             ShellStatus = SHELL_UNSUPPORTED;
1150           }
1151         }
1152         if ( ShellStatus == SHELL_SUCCESS && ShellCommandLineGetFlag(Package, L"-u")) {
1153           //
1154           // Do the Update
1155           //
1156           Status = ShellCommandUpdateMapping ();
1157           if (EFI_ERROR(Status)) {
1158             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", Status);
1159             ShellStatus = SHELL_UNSUPPORTED;
1160           }
1161         }
1162         if (ShellStatus == SHELL_SUCCESS) {
1163           Param1 = ShellCommandLineGetRawValue(Package, 1);
1164           TypeString = ShellCommandLineGetValue(Package, L"-t");
1165           if (!ConstMode
1166             &&!NormlMode
1167             &&TypeString  == NULL
1168             ) {
1169             //
1170             // now do the display...
1171             //
1172             ShellStatus = PerformMappingDisplay(
1173               ShellCommandLineGetFlag(Package, L"-v"),
1174               TRUE,
1175               TRUE,
1176               NULL,
1177               SfoMode,
1178               Param1,
1179               TRUE
1180              );
1181           } else {
1182             //
1183             // now do the display...
1184             //
1185             ShellStatus = PerformMappingDisplay2(
1186               ShellCommandLineGetFlag(Package, L"-v"),
1187               ConstMode,
1188               NormlMode,
1189               TypeString,
1190               SfoMode,
1191               Param1
1192              );
1193           }
1194         }
1195       } else {
1196         //
1197         // adding or displaying (there were no flags)
1198         //
1199         SName = ShellCommandLineGetRawValue(Package, 1);
1200         Mapping = ShellCommandLineGetRawValue(Package, 2);
1201         if ( SName == NULL
1202           && Mapping == NULL
1203          ){
1204           //
1205           // display only since no flags
1206           //
1207           ShellStatus = PerformMappingDisplay(
1208             ShellCommandLineGetFlag(Package, L"-v"),
1209             TRUE,
1210             TRUE,
1211             NULL,
1212             SfoMode,
1213             NULL,
1214             TRUE
1215            );
1216         } else if ( SName == NULL
1217           || Mapping == NULL
1218          ){
1219             //
1220             // Display only the one specified
1221             //
1222           ShellStatus = PerformMappingDisplay(
1223             FALSE,
1224             FALSE,
1225             FALSE,
1226             NULL,
1227             SfoMode,
1228             SName, // note the variable here...
1229             TRUE
1230            );
1231         } else {
1232           if (ShellIsHexOrDecimalNumber(Mapping, TRUE, FALSE)) {
1233             MapAsHandle = ConvertHandleIndexToHandle(ShellStrToUintn(Mapping));
1234           } else {
1235             MapAsHandle = NULL;
1236           }
1237           if (MapAsHandle == NULL && Mapping[StrLen(Mapping)-1] != L':') {
1238             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", Mapping);
1239             ShellStatus = SHELL_INVALID_PARAMETER;
1240           } else {
1241             TempStringLength = StrLen(SName);
1242             if (!IsNumberLetterOnly(SName, TempStringLength-(SName[TempStringLength-1]==L':'?1:0))) {
1243               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", SName);
1244               ShellStatus = SHELL_INVALID_PARAMETER;
1245             }
1246 
1247             if (ShellStatus == SHELL_SUCCESS) {
1248               if (MapAsHandle != NULL) {
1249                 ShellStatus = AddMappingFromHandle(MapAsHandle, SName);
1250               } else {
1251                 ShellStatus = AddMappingFromMapping(Mapping, SName);
1252               }
1253 
1254               if (ShellStatus != SHELL_SUCCESS) {
1255                 switch (ShellStatus) {
1256                   case SHELL_ACCESS_DENIED:
1257                     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_AD), gShellLevel2HiiHandle, L"map");
1258                     break;
1259                   case SHELL_INVALID_PARAMETER:
1260                     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"map", Mapping);
1261                     break;
1262                   case SHELL_DEVICE_ERROR:
1263                     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MAP_NOF), gShellLevel2HiiHandle, L"map", Mapping);
1264                     break;
1265                   default:
1266                     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, L"map", ShellStatus|MAX_BIT);
1267                 }
1268               } else {
1269                 //
1270                 // now do the display...
1271                 //
1272                 ShellStatus = PerformMappingDisplay(
1273                   FALSE,
1274                   FALSE,
1275                   FALSE,
1276                   NULL,
1277                   SfoMode,
1278                   SName,
1279                   TRUE
1280                  );
1281               } // we were sucessful so do an output
1282             }
1283           } // got a valid map target
1284         } // got 2 variables
1285       } // we are adding a mapping
1286     } // got valid parameters
1287   }
1288 
1289   //
1290   // free the command line package
1291   //
1292   ShellCommandLineFreeVarList (Package);
1293 
1294   return (ShellStatus);
1295 }
1296 
1297