1 /** @file
2   Main file for DmpStore shell Debug1 function.
3 
4   (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "UefiShellDebug1CommandsLib.h"
11 
12 typedef enum {
13   DmpStoreDisplay,
14   DmpStoreDelete,
15   DmpStoreSave,
16   DmpStoreLoad
17 } DMP_STORE_TYPE;
18 
19 typedef struct {
20   UINT32     Signature;
21   CHAR16     *Name;
22   EFI_GUID   Guid;
23   UINT32     Attributes;
24   UINT32     DataSize;
25   UINT8      *Data;
26   LIST_ENTRY Link;
27 } DMP_STORE_VARIABLE;
28 
29 #define DMP_STORE_VARIABLE_SIGNATURE  SIGNATURE_32 ('_', 'd', 's', 's')
30 
31 /**
32   Base on the input attribute value to return the attribute string.
33 
34   @param[in]     Atts           The input attribute value
35 
36   @retval The attribute string info.
37 **/
38 CHAR16 *
GetAttrType(IN CONST UINT32 Atts)39 GetAttrType (
40   IN CONST UINT32 Atts
41   )
42 {
43   UINTN  BufLen;
44   CHAR16 *RetString;
45 
46   BufLen      = 0;
47   RetString   = NULL;
48 
49   if ((Atts & EFI_VARIABLE_NON_VOLATILE) != 0) {
50     StrnCatGrow (&RetString, &BufLen, L"+NV", 0);
51   }
52   if ((Atts & EFI_VARIABLE_RUNTIME_ACCESS) != 0) {
53     StrnCatGrow (&RetString, &BufLen, L"+RT+BS", 0);
54   } else if ((Atts & EFI_VARIABLE_BOOTSERVICE_ACCESS) != 0) {
55     StrnCatGrow (&RetString, &BufLen, L"+BS", 0);
56   }
57   if ((Atts & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
58     StrnCatGrow (&RetString, &BufLen, L"+HR", 0);
59   }
60   if ((Atts & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
61     StrnCatGrow (&RetString, &BufLen, L"+AW", 0);
62   }
63   if ((Atts & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
64     StrnCatGrow (&RetString, &BufLen, L"+AT", 0);
65   }
66 
67   if (RetString == NULL) {
68     RetString = StrnCatGrow(&RetString, &BufLen, L"Invalid", 0);
69   }
70 
71   if ((RetString != NULL) && (RetString[0] == L'+')) {
72     CopyMem(RetString, RetString + 1, StrSize(RetString + 1));
73   }
74 
75   return RetString;
76 }
77 
78 /**
79   Convert binary to hex format string.
80 
81   @param[in]  Buffer            The binary data.
82   @param[in]  BufferSize        The size in bytes of the binary data.
83   @param[in, out] HexString     Hex format string.
84   @param[in]      HexStringSize The size in bytes of the string.
85 
86   @return The hex format string.
87 **/
88 CHAR16*
BinaryToHexString(IN VOID * Buffer,IN UINTN BufferSize,IN OUT CHAR16 * HexString,IN UINTN HexStringSize)89 BinaryToHexString (
90   IN     VOID    *Buffer,
91   IN     UINTN   BufferSize,
92   IN OUT CHAR16  *HexString,
93   IN     UINTN   HexStringSize
94   )
95 {
96   UINTN Index;
97   UINTN StringIndex;
98 
99   ASSERT (Buffer != NULL);
100   ASSERT ((BufferSize * 2 + 1) * sizeof (CHAR16) <= HexStringSize);
101 
102   for (Index = 0, StringIndex = 0; Index < BufferSize; Index += 1) {
103     StringIndex +=
104       UnicodeSPrint (
105         &HexString[StringIndex],
106         HexStringSize - StringIndex * sizeof (CHAR16),
107         L"%02x",
108         ((UINT8 *) Buffer)[Index]
109         );
110   }
111   return HexString;
112 }
113 
114 /**
115   Load the variable data from file and set to variable data base.
116 
117   @param[in]  FileHandle     The file to be read.
118   @param[in]  Name           The name of the variables to be loaded.
119   @param[in]  Guid           The guid of the variables to be loaded.
120   @param[out] Found          TRUE when at least one variable was loaded and set.
121 
122   @retval SHELL_DEVICE_ERROR      Cannot access the file.
123   @retval SHELL_VOLUME_CORRUPTED  The file is in bad format.
124   @retval SHELL_OUT_OF_RESOURCES  There is not enough memory to perform the operation.
125   @retval SHELL_SUCCESS           Successfully load and set the variables.
126 **/
127 SHELL_STATUS
LoadVariablesFromFile(IN SHELL_FILE_HANDLE FileHandle,IN CONST CHAR16 * Name,IN CONST EFI_GUID * Guid,OUT BOOLEAN * Found)128 LoadVariablesFromFile (
129   IN SHELL_FILE_HANDLE FileHandle,
130   IN CONST CHAR16      *Name,
131   IN CONST EFI_GUID    *Guid,
132   OUT BOOLEAN          *Found
133   )
134 {
135   EFI_STATUS           Status;
136   SHELL_STATUS         ShellStatus;
137   UINT32               NameSize;
138   UINT32               DataSize;
139   UINTN                BufferSize;
140   UINTN                RemainingSize;
141   UINT64               Position;
142   UINT64               FileSize;
143   LIST_ENTRY           List;
144   DMP_STORE_VARIABLE   *Variable;
145   LIST_ENTRY           *Link;
146   CHAR16               *Attributes;
147   UINT8                *Buffer;
148   UINT32               Crc32;
149 
150   Status = ShellGetFileSize (FileHandle, &FileSize);
151   if (EFI_ERROR (Status)) {
152     return SHELL_DEVICE_ERROR;
153   }
154 
155   ShellStatus = SHELL_SUCCESS;
156 
157   InitializeListHead (&List);
158 
159   Position = 0;
160   while (Position < FileSize) {
161     //
162     // NameSize
163     //
164     BufferSize = sizeof (NameSize);
165     Status = ShellReadFile (FileHandle, &BufferSize, &NameSize);
166     if (EFI_ERROR (Status) || (BufferSize != sizeof (NameSize))) {
167       ShellStatus = SHELL_VOLUME_CORRUPTED;
168       break;
169     }
170 
171     //
172     // DataSize
173     //
174     BufferSize = sizeof (DataSize);
175     Status = ShellReadFile (FileHandle, &BufferSize, &DataSize);
176     if (EFI_ERROR (Status) || (BufferSize != sizeof (DataSize))) {
177       ShellStatus = SHELL_VOLUME_CORRUPTED;
178       break;
179     }
180 
181     //
182     // Name, Guid, Attributes, Data, Crc32
183     //
184     RemainingSize = NameSize + sizeof (EFI_GUID) + sizeof (UINT32) + DataSize + sizeof (Crc32);
185     BufferSize    = sizeof (NameSize) + sizeof (DataSize) + RemainingSize;
186     Buffer        = AllocatePool (BufferSize);
187     if (Buffer == NULL) {
188       ShellStatus = SHELL_OUT_OF_RESOURCES;
189       break;
190     }
191     BufferSize    = RemainingSize;
192     Status = ShellReadFile (FileHandle, &BufferSize, (UINT32 *) Buffer + 2);
193     if (EFI_ERROR (Status) || (BufferSize != RemainingSize)) {
194       ShellStatus = SHELL_VOLUME_CORRUPTED;
195       FreePool (Buffer);
196       break;
197     }
198 
199     //
200     // Check Crc32
201     //
202     * (UINT32 *) Buffer       = NameSize;
203     * ((UINT32 *) Buffer + 1) = DataSize;
204     BufferSize = RemainingSize + sizeof (NameSize) + sizeof (DataSize) - sizeof (Crc32);
205     gBS->CalculateCrc32 (
206            Buffer,
207            BufferSize,
208            &Crc32
209            );
210     if (Crc32 != * (UINT32 *) (Buffer + BufferSize)) {
211       FreePool (Buffer);
212       ShellStatus = SHELL_VOLUME_CORRUPTED;
213       break;
214     }
215 
216     Position += BufferSize + sizeof (Crc32);
217 
218     Variable = AllocateZeroPool (sizeof (*Variable) + NameSize + DataSize);
219     if (Variable == NULL) {
220       FreePool (Buffer);
221       ShellStatus = SHELL_OUT_OF_RESOURCES;
222       break;
223     }
224     Variable->Signature = DMP_STORE_VARIABLE_SIGNATURE;
225     Variable->Name      = (CHAR16 *) (Variable + 1);
226     Variable->DataSize  = DataSize;
227     Variable->Data      = (UINT8 *) Variable->Name + NameSize;
228     CopyMem (Variable->Name,        Buffer + sizeof (NameSize) + sizeof (DataSize),                                                  NameSize);
229     CopyMem (&Variable->Guid,       Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize,                                       sizeof (EFI_GUID));
230     CopyMem (&Variable->Attributes, Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize + sizeof (EFI_GUID),                   sizeof (UINT32));
231     CopyMem (Variable->Data,        Buffer + sizeof (NameSize) + sizeof (DataSize) + NameSize + sizeof (EFI_GUID) + sizeof (UINT32), DataSize);
232 
233     InsertTailList (&List, &Variable->Link);
234     FreePool (Buffer);
235   }
236 
237   if ((Position != FileSize) || (ShellStatus != SHELL_SUCCESS)) {
238     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_LOAD_BAD_FILE), gShellDebug1HiiHandle, L"dmpstore");
239     if (Position != FileSize) {
240       ShellStatus = SHELL_VOLUME_CORRUPTED;
241     }
242   }
243 
244   for ( Link = GetFirstNode (&List)
245       ; !IsNull (&List, Link) && (ShellStatus == SHELL_SUCCESS)
246       ; Link = GetNextNode (&List, Link)
247       ) {
248     Variable = CR (Link, DMP_STORE_VARIABLE, Link, DMP_STORE_VARIABLE_SIGNATURE);
249 
250     if (((Name == NULL) || gUnicodeCollation->MetaiMatch (gUnicodeCollation, Variable->Name, (CHAR16 *) Name)) &&
251         ((Guid == NULL) || CompareGuid (&Variable->Guid, Guid))
252        ) {
253       Attributes = GetAttrType (Variable->Attributes);
254       ShellPrintHiiEx (
255         -1, -1, NULL, STRING_TOKEN(STR_DMPSTORE_HEADER_LINE), gShellDebug1HiiHandle,
256         Attributes, &Variable->Guid, Variable->Name, Variable->DataSize
257         );
258       SHELL_FREE_NON_NULL(Attributes);
259 
260       *Found = TRUE;
261       Status = gRT->SetVariable (
262                       Variable->Name,
263                       &Variable->Guid,
264                       Variable->Attributes,
265                       Variable->DataSize,
266                       Variable->Data
267                       );
268       if (EFI_ERROR (Status)) {
269         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_LOAD_GEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", Variable->Name, Status);
270       }
271     }
272   }
273 
274   for (Link = GetFirstNode (&List); !IsNull (&List, Link); ) {
275     Variable = CR (Link, DMP_STORE_VARIABLE, Link, DMP_STORE_VARIABLE_SIGNATURE);
276     Link = RemoveEntryList (&Variable->Link);
277     FreePool (Variable);
278   }
279 
280   return ShellStatus;
281 }
282 
283 /**
284   Append one variable to file.
285 
286   @param[in] FileHandle        The file to be appended.
287   @param[in] Name              The variable name.
288   @param[in] Guid              The variable GUID.
289   @param[in] Attributes        The variable attributes.
290   @param[in] DataSize          The variable data size.
291   @param[in] Data              The variable data.
292 
293   @retval EFI_OUT_OF_RESOURCES  There is not enough memory to perform the operation.
294   @retval EFI_SUCCESS           The variable is appended to file successfully.
295   @retval others                Failed to append the variable to file.
296 **/
297 EFI_STATUS
AppendSingleVariableToFile(IN SHELL_FILE_HANDLE FileHandle,IN CONST CHAR16 * Name,IN CONST EFI_GUID * Guid,IN UINT32 Attributes,IN UINT32 DataSize,IN CONST UINT8 * Data)298 AppendSingleVariableToFile (
299   IN SHELL_FILE_HANDLE FileHandle,
300   IN CONST CHAR16      *Name,
301   IN CONST EFI_GUID    *Guid,
302   IN UINT32            Attributes,
303   IN UINT32            DataSize,
304   IN CONST UINT8       *Data
305   )
306 {
307   UINT32              NameSize;
308   UINT8               *Buffer;
309   UINT8               *Ptr;
310   UINTN               BufferSize;
311   EFI_STATUS          Status;
312 
313   NameSize   = (UINT32) StrSize (Name);
314   BufferSize = sizeof (NameSize) + sizeof (DataSize)
315              + sizeof (*Guid)
316              + sizeof (Attributes)
317              + NameSize + DataSize
318              + sizeof (UINT32);
319 
320   Buffer = AllocatePool (BufferSize);
321   if (Buffer == NULL) {
322     return EFI_OUT_OF_RESOURCES;
323   }
324 
325   Ptr = Buffer;
326   //
327   // NameSize and DataSize
328   //
329   * (UINT32 *) Ptr = NameSize;
330   Ptr += sizeof (NameSize);
331   *(UINT32 *) Ptr = DataSize;
332   Ptr += sizeof (DataSize);
333 
334   //
335   // Name
336   //
337   CopyMem (Ptr, Name, NameSize);
338   Ptr += NameSize;
339 
340   //
341   // Guid
342   //
343   CopyMem (Ptr, Guid, sizeof (*Guid));
344   Ptr += sizeof (*Guid);
345 
346   //
347   // Attributes
348   //
349   * (UINT32 *) Ptr = Attributes;
350   Ptr += sizeof (Attributes);
351 
352   //
353   // Data
354   //
355   CopyMem (Ptr, Data, DataSize);
356   Ptr += DataSize;
357 
358   //
359   // Crc32
360   //
361   gBS->CalculateCrc32 (Buffer, (UINTN) Ptr - (UINTN) Buffer, (UINT32 *) Ptr);
362 
363   Status = ShellWriteFile (FileHandle, &BufferSize, Buffer);
364   FreePool (Buffer);
365 
366   if (!EFI_ERROR (Status) &&
367       (BufferSize != sizeof (NameSize) + sizeof (DataSize) + sizeof (*Guid) + sizeof (Attributes) + NameSize + DataSize + sizeof (UINT32))
368     ) {
369     Status = EFI_DEVICE_ERROR;
370   }
371 
372   return Status;
373 }
374 
375 /**
376   Recursive function to display or delete variables.
377 
378   This function will call itself to create a stack-based list of allt he variables to process,
379   then fromt he last to the first, they will do either printing or deleting.
380 
381   This is necessary since once a delete happens GetNextVariableName() will work.
382 
383   @param[in] Name                 The variable name of the EFI variable (or NULL).
384   @param[in] Guid                 The GUID of the variable set (or NULL).
385   @param[in] Type                 The operation type.
386   @param[in] FileHandle           The file to operate on (or NULL).
387   @param[in] PrevName             The previous variable name from GetNextVariableName. L"" to start.
388   @param[in] FoundVarGuid         The previous GUID from GetNextVariableName. ignored at start.
389   @param[in] FoundOne             If a VariableName or Guid was specified and one was printed or
390                                   deleted, then set this to TRUE, otherwise ignored.
391   @param[in] StandardFormatOutput TRUE indicates Standard-Format Output.
392 
393   @retval SHELL_SUCCESS           The operation was successful.
394   @retval SHELL_OUT_OF_RESOURCES  A memorty allocation failed.
395   @retval SHELL_ABORTED           The abort message was received.
396   @retval SHELL_DEVICE_ERROR      UEFI Variable Services returned an error.
397   @retval SHELL_NOT_FOUND         the Name/Guid pair could not be found.
398 **/
399 SHELL_STATUS
CascadeProcessVariables(IN CONST CHAR16 * Name OPTIONAL,IN CONST EFI_GUID * Guid OPTIONAL,IN DMP_STORE_TYPE Type,IN EFI_FILE_PROTOCOL * FileHandle OPTIONAL,IN CONST CHAR16 * CONST PrevName,IN EFI_GUID FoundVarGuid,IN BOOLEAN * FoundOne,IN BOOLEAN StandardFormatOutput)400 CascadeProcessVariables (
401   IN CONST CHAR16      *Name        OPTIONAL,
402   IN CONST EFI_GUID    *Guid        OPTIONAL,
403   IN DMP_STORE_TYPE    Type,
404   IN EFI_FILE_PROTOCOL *FileHandle  OPTIONAL,
405   IN CONST CHAR16      * CONST PrevName,
406   IN EFI_GUID          FoundVarGuid,
407   IN BOOLEAN           *FoundOne,
408   IN BOOLEAN           StandardFormatOutput
409   )
410 {
411   EFI_STATUS                Status;
412   CHAR16                    *FoundVarName;
413   UINT8                     *DataBuffer;
414   UINTN                     DataSize;
415   UINT32                    Atts;
416   SHELL_STATUS              ShellStatus;
417   UINTN                     NameSize;
418   CHAR16                    *AttrString;
419   CHAR16                    *HexString;
420   EFI_STATUS                SetStatus;
421   CONST CHAR16              *GuidName;
422 
423   if (ShellGetExecutionBreakFlag()) {
424     return (SHELL_ABORTED);
425   }
426 
427   NameSize      = 0;
428   FoundVarName  = NULL;
429 
430   if (PrevName!=NULL) {
431     StrnCatGrow(&FoundVarName, &NameSize, PrevName, 0);
432   } else {
433     FoundVarName = AllocateZeroPool(sizeof(CHAR16));
434     NameSize = sizeof(CHAR16);
435   }
436 
437   Status = gRT->GetNextVariableName (&NameSize, FoundVarName, &FoundVarGuid);
438   if (Status == EFI_BUFFER_TOO_SMALL) {
439     SHELL_FREE_NON_NULL(FoundVarName);
440     FoundVarName = AllocateZeroPool (NameSize);
441     if (FoundVarName != NULL) {
442       if (PrevName != NULL) {
443         StrnCpyS(FoundVarName, NameSize/sizeof(CHAR16), PrevName, NameSize/sizeof(CHAR16) - 1);
444       }
445 
446       Status = gRT->GetNextVariableName (&NameSize, FoundVarName, &FoundVarGuid);
447     } else {
448       Status = EFI_OUT_OF_RESOURCES;
449     }
450   }
451 
452   //
453   // No more is fine.
454   //
455   if (Status == EFI_NOT_FOUND) {
456     SHELL_FREE_NON_NULL(FoundVarName);
457     return (SHELL_SUCCESS);
458   } else if (EFI_ERROR(Status)) {
459     SHELL_FREE_NON_NULL(FoundVarName);
460     return (SHELL_DEVICE_ERROR);
461   }
462 
463   //
464   // Recurse to the next iteration.  We know "our" variable's name.
465   //
466   ShellStatus = CascadeProcessVariables (Name, Guid, Type, FileHandle, FoundVarName, FoundVarGuid, FoundOne, StandardFormatOutput);
467 
468   if (ShellGetExecutionBreakFlag() || (ShellStatus == SHELL_ABORTED)) {
469     SHELL_FREE_NON_NULL(FoundVarName);
470     return (SHELL_ABORTED);
471   }
472 
473   //
474   // No matter what happened we process our own variable
475   // Only continue if Guid and VariableName are each either NULL or a match
476   //
477   if ( ( Name == NULL
478       || gUnicodeCollation->MetaiMatch(gUnicodeCollation, FoundVarName, (CHAR16*) Name) )
479      && ( Guid == NULL
480       || CompareGuid(&FoundVarGuid, Guid) )
481       ) {
482     DataSize      = 0;
483     DataBuffer    = NULL;
484     //
485     // do the print or delete
486     //
487     *FoundOne = TRUE;
488     Status = gRT->GetVariable (FoundVarName, &FoundVarGuid, &Atts, &DataSize, DataBuffer);
489     if (Status == EFI_BUFFER_TOO_SMALL) {
490       SHELL_FREE_NON_NULL (DataBuffer);
491       DataBuffer = AllocatePool (DataSize);
492       if (DataBuffer == NULL) {
493         Status = EFI_OUT_OF_RESOURCES;
494       } else {
495         Status = gRT->GetVariable (FoundVarName, &FoundVarGuid, &Atts, &DataSize, DataBuffer);
496       }
497     }
498       //
499       // Last error check then print this variable out.
500       //
501     if (Type == DmpStoreDisplay) {
502       if (!EFI_ERROR(Status) && (DataBuffer != NULL) && (FoundVarName != NULL)) {
503         AttrString = GetAttrType(Atts);
504         if (StandardFormatOutput) {
505           HexString = AllocatePool ((DataSize * 2 + 1) * sizeof (CHAR16));
506           if (HexString != NULL) {
507             ShellPrintHiiEx (
508               -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_VAR_SFO), gShellDebug1HiiHandle,
509               FoundVarName, &FoundVarGuid, Atts, DataSize,
510               BinaryToHexString (
511                 DataBuffer, DataSize, HexString, (DataSize * 2 + 1) * sizeof (CHAR16)
512                 )
513               );
514             FreePool (HexString);
515           } else {
516             Status = EFI_OUT_OF_RESOURCES;
517           }
518         } else {
519           Status = gEfiShellProtocol->GetGuidName(&FoundVarGuid, &GuidName);
520           if (EFI_ERROR (Status)) {
521             ShellPrintHiiEx (
522               -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_HEADER_LINE), gShellDebug1HiiHandle,
523               AttrString, &FoundVarGuid, FoundVarName, DataSize
524               );
525           } else {
526             ShellPrintHiiEx (
527               -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_HEADER_LINE2), gShellDebug1HiiHandle,
528               AttrString, GuidName, FoundVarName, DataSize
529               );
530           }
531           DumpHex (2, 0, DataSize, DataBuffer);
532         }
533         SHELL_FREE_NON_NULL (AttrString);
534       }
535     } else if (Type == DmpStoreSave) {
536       if (!EFI_ERROR(Status) && (DataBuffer != NULL) && (FoundVarName != NULL)) {
537         AttrString = GetAttrType (Atts);
538         ShellPrintHiiEx (
539           -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_HEADER_LINE), gShellDebug1HiiHandle,
540           AttrString, &FoundVarGuid, FoundVarName, DataSize
541           );
542         Status = AppendSingleVariableToFile (
543                    FileHandle,
544                    FoundVarName,
545                    &FoundVarGuid,
546                    Atts,
547                    (UINT32) DataSize,
548                    DataBuffer
549                    );
550         SHELL_FREE_NON_NULL (AttrString);
551       }
552     } else if (Type == DmpStoreDelete) {
553       //
554       // We only need name to delete it...
555       //
556       SetStatus = gRT->SetVariable (FoundVarName, &FoundVarGuid, Atts, 0, NULL);
557       if (StandardFormatOutput) {
558         if (SetStatus == EFI_SUCCESS) {
559           ShellPrintHiiEx (
560             -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_NG_SFO), gShellDebug1HiiHandle,
561             FoundVarName, &FoundVarGuid
562             );
563         }
564       } else {
565         ShellPrintHiiEx (
566           -1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_DELETE_LINE), gShellDebug1HiiHandle,
567           &FoundVarGuid, FoundVarName, SetStatus
568           );
569       }
570     }
571     SHELL_FREE_NON_NULL(DataBuffer);
572   }
573 
574   SHELL_FREE_NON_NULL(FoundVarName);
575 
576   if (Status == EFI_DEVICE_ERROR) {
577     ShellStatus = SHELL_DEVICE_ERROR;
578   } else if (Status == EFI_SECURITY_VIOLATION) {
579     ShellStatus = SHELL_SECURITY_VIOLATION;
580   } else if (EFI_ERROR(Status)) {
581     ShellStatus = SHELL_NOT_READY;
582   }
583 
584   return (ShellStatus);
585 }
586 
587 /**
588   Function to display or delete variables.  This will set up and call into the recursive function.
589 
590   @param[in] Name                 The variable name of the EFI variable (or NULL).
591   @param[in] Guid                 The GUID of the variable set (or NULL).
592   @param[in] Type                 The operation type.
593   @param[in] FileHandle           The file to save or load variables.
594   @param[in] StandardFormatOutput TRUE indicates Standard-Format Output.
595 
596   @retval SHELL_SUCCESS           The operation was successful.
597   @retval SHELL_OUT_OF_RESOURCES  A memorty allocation failed.
598   @retval SHELL_ABORTED           The abort message was received.
599   @retval SHELL_DEVICE_ERROR      UEFI Variable Services returned an error.
600   @retval SHELL_NOT_FOUND         the Name/Guid pair could not be found.
601 **/
602 SHELL_STATUS
ProcessVariables(IN CONST CHAR16 * Name OPTIONAL,IN CONST EFI_GUID * Guid OPTIONAL,IN DMP_STORE_TYPE Type,IN SHELL_FILE_HANDLE FileHandle OPTIONAL,IN BOOLEAN StandardFormatOutput)603 ProcessVariables (
604   IN CONST CHAR16      *Name      OPTIONAL,
605   IN CONST EFI_GUID    *Guid      OPTIONAL,
606   IN DMP_STORE_TYPE    Type,
607   IN SHELL_FILE_HANDLE FileHandle OPTIONAL,
608   IN BOOLEAN           StandardFormatOutput
609   )
610 {
611   SHELL_STATUS              ShellStatus;
612   BOOLEAN                   Found;
613   EFI_GUID                  FoundVarGuid;
614 
615   Found         = FALSE;
616   ShellStatus   = SHELL_SUCCESS;
617   ZeroMem (&FoundVarGuid, sizeof(EFI_GUID));
618 
619   if (StandardFormatOutput) {
620     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_SFO_HEADER), gShellDebug1HiiHandle, L"dmpstore");
621   }
622 
623   if (Type == DmpStoreLoad) {
624     ShellStatus = LoadVariablesFromFile (FileHandle, Name, Guid, &Found);
625   } else {
626     ShellStatus = CascadeProcessVariables (Name, Guid, Type, FileHandle, NULL, FoundVarGuid, &Found, StandardFormatOutput);
627   }
628 
629   if (!Found) {
630     if (ShellStatus == SHELL_OUT_OF_RESOURCES) {
631       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellDebug1HiiHandle, L"dmpstore");
632       return (ShellStatus);
633     } else if (Name != NULL && Guid == NULL) {
634       if (StandardFormatOutput) {
635         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_N_SFO), gShellDebug1HiiHandle, Name);
636       } else {
637         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_N), gShellDebug1HiiHandle, L"dmpstore", Name);
638       }
639     } else if (Name != NULL && Guid != NULL) {
640       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_GN), gShellDebug1HiiHandle, L"dmpstore", Guid, Name);
641     } else if (Name == NULL && Guid == NULL) {
642       if (StandardFormatOutput) {
643         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_SFO), gShellDebug1HiiHandle);
644       } else {
645         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND), gShellDebug1HiiHandle, L"dmpstore");
646       }
647     } else if (Name == NULL && Guid != NULL) {
648       if (StandardFormatOutput) {
649         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_G_SFO), gShellDebug1HiiHandle, Guid);
650       } else {
651         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_NO_VAR_FOUND_G), gShellDebug1HiiHandle, L"dmpstore", Guid);
652       }
653     }
654     return (SHELL_NOT_FOUND);
655   }
656   return (ShellStatus);
657 }
658 
659 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
660   {L"-d", TypeFlag},
661   {L"-l", TypeValue},
662   {L"-s", TypeValue},
663   {L"-all", TypeFlag},
664   {L"-guid", TypeValue},
665   {L"-sfo", TypeFlag},
666   {NULL, TypeMax}
667   };
668 
669 /**
670   Function for 'dmpstore' command.
671 
672   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
673   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
674 **/
675 SHELL_STATUS
676 EFIAPI
ShellCommandRunDmpStore(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)677 ShellCommandRunDmpStore (
678   IN EFI_HANDLE        ImageHandle,
679   IN EFI_SYSTEM_TABLE  *SystemTable
680   )
681 {
682   EFI_STATUS        Status;
683   RETURN_STATUS     RStatus;
684   LIST_ENTRY        *Package;
685   CHAR16            *ProblemParam;
686   SHELL_STATUS      ShellStatus;
687   CONST CHAR16      *GuidStr;
688   CONST CHAR16      *File;
689   EFI_GUID          *Guid;
690   EFI_GUID          GuidData;
691   CONST CHAR16      *Name;
692   DMP_STORE_TYPE    Type;
693   SHELL_FILE_HANDLE FileHandle;
694   EFI_FILE_INFO     *FileInfo;
695   BOOLEAN           StandardFormatOutput;
696 
697   ShellStatus          = SHELL_SUCCESS;
698   Package              = NULL;
699   FileHandle           = NULL;
700   File                 = NULL;
701   Type                 = DmpStoreDisplay;
702   StandardFormatOutput = FALSE;
703 
704   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
705   if (EFI_ERROR(Status)) {
706     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
707       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"dmpstore", ProblemParam);
708       FreePool(ProblemParam);
709       ShellStatus = SHELL_INVALID_PARAMETER;
710     } else {
711       ASSERT(FALSE);
712     }
713   } else {
714     if (ShellCommandLineGetCount(Package) > 2) {
715       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"dmpstore");
716       ShellStatus = SHELL_INVALID_PARAMETER;
717     } else if (ShellCommandLineGetFlag(Package, L"-all") && ShellCommandLineGetFlag(Package, L"-guid")) {
718       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDebug1HiiHandle, L"dmpstore", L"-all", L"-guid");
719       ShellStatus = SHELL_INVALID_PARAMETER;
720     } else if (ShellCommandLineGetFlag(Package, L"-s") && ShellCommandLineGetFlag(Package, L"-l")) {
721       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDebug1HiiHandle,  L"dmpstore", L"-l", L"-s");
722       ShellStatus = SHELL_INVALID_PARAMETER;
723     } else if ((ShellCommandLineGetFlag(Package, L"-s") || ShellCommandLineGetFlag(Package, L"-l")) && ShellCommandLineGetFlag(Package, L"-d")) {
724       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDebug1HiiHandle, L"dmpstore", L"-l or -s", L"-d");
725       ShellStatus = SHELL_INVALID_PARAMETER;
726     } else if ((ShellCommandLineGetFlag(Package, L"-s") || ShellCommandLineGetFlag(Package, L"-l")) && ShellCommandLineGetFlag(Package, L"-sfo")) {
727       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellDebug1HiiHandle, L"dmpstore", L"-l or -s", L"-sfo");
728       ShellStatus = SHELL_INVALID_PARAMETER;
729     } else {
730       //
731       // Determine the GUID to search for based on -all and -guid parameters
732       //
733       if (!ShellCommandLineGetFlag(Package, L"-all")) {
734         GuidStr = ShellCommandLineGetValue(Package, L"-guid");
735         if (GuidStr != NULL) {
736           RStatus = StrToGuid (GuidStr, &GuidData);
737           if (RETURN_ERROR (RStatus) || (GuidStr[GUID_STRING_LENGTH] != L'\0')) {
738             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellDebug1HiiHandle, L"dmpstore", GuidStr);
739             ShellStatus = SHELL_INVALID_PARAMETER;
740           }
741           Guid = &GuidData;
742         } else  {
743           Guid = &gEfiGlobalVariableGuid;
744         }
745       } else {
746         Guid  = NULL;
747       }
748 
749       //
750       // Get the Name of the variable to find
751       //
752       Name = ShellCommandLineGetRawValue(Package, 1);
753 
754       if (ShellStatus == SHELL_SUCCESS) {
755         if (ShellCommandLineGetFlag(Package, L"-s")) {
756           Type = DmpStoreSave;
757           File = ShellCommandLineGetValue(Package, L"-s");
758           if (File == NULL) {
759             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"dmpstore", L"-s");
760             ShellStatus = SHELL_INVALID_PARAMETER;
761           } else {
762             Status = ShellOpenFileByName (File, &FileHandle, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
763             if (!EFI_ERROR (Status)) {
764               //
765               // Delete existing file, but do not delete existing directory
766               //
767               FileInfo = ShellGetFileInfo (FileHandle);
768               if (FileInfo == NULL) {
769                 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File);
770                 Status = EFI_DEVICE_ERROR;
771               } else {
772                 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
773                   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_IS_DIRECTORY), gShellDebug1HiiHandle, L"dmpstore", File);
774                   Status = EFI_INVALID_PARAMETER;
775                 } else {
776                   Status = ShellDeleteFile (&FileHandle);
777                   if (EFI_ERROR (Status)) {
778                     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_DELETE_FAIL), gShellDebug1HiiHandle, L"dmpstore", File);
779                   }
780                 }
781                 FreePool (FileInfo);
782               }
783             } else if (Status == EFI_NOT_FOUND) {
784               //
785               // Good when file doesn't exist
786               //
787               Status = EFI_SUCCESS;
788             } else {
789               //
790               // Otherwise it's bad.
791               //
792               ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File);
793             }
794 
795             if (!EFI_ERROR (Status)) {
796               Status = ShellOpenFileByName (File, &FileHandle, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
797               if (EFI_ERROR (Status)) {
798                 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File);
799               }
800             }
801 
802             if (EFI_ERROR (Status)) {
803               ShellStatus = SHELL_INVALID_PARAMETER;
804             }
805           }
806         } else if (ShellCommandLineGetFlag(Package, L"-l")) {
807           Type = DmpStoreLoad;
808           File = ShellCommandLineGetValue(Package, L"-l");
809           if (File == NULL) {
810             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"dmpstore", L"-l");
811             ShellStatus = SHELL_INVALID_PARAMETER;
812           } else {
813             Status = ShellOpenFileByName (File, &FileHandle, EFI_FILE_MODE_READ, 0);
814             if (EFI_ERROR (Status)) {
815               ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File);
816               ShellStatus = SHELL_INVALID_PARAMETER;
817             } else {
818               FileInfo = ShellGetFileInfo (FileHandle);
819               if (FileInfo == NULL) {
820                 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"dmpstore", File);
821                 ShellStatus = SHELL_DEVICE_ERROR;
822               } else {
823                 if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
824                   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_IS_DIRECTORY), gShellDebug1HiiHandle, L"dmpstore", File);
825                   ShellStatus = SHELL_INVALID_PARAMETER;
826                 }
827                 FreePool (FileInfo);
828               }
829             }
830           }
831         } else if (ShellCommandLineGetFlag(Package, L"-d")) {
832           Type = DmpStoreDelete;
833         }
834 
835         if (ShellCommandLineGetFlag (Package,L"-sfo")) {
836           StandardFormatOutput = TRUE;
837         }
838       }
839 
840       if (ShellStatus == SHELL_SUCCESS) {
841         if (Type == DmpStoreSave) {
842           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_SAVE), gShellDebug1HiiHandle, File);
843         } else if (Type == DmpStoreLoad) {
844           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DMPSTORE_LOAD), gShellDebug1HiiHandle, File);
845         }
846         ShellStatus = ProcessVariables (Name, Guid, Type, FileHandle, StandardFormatOutput);
847         if ((Type == DmpStoreLoad) || (Type == DmpStoreSave)) {
848           ShellCloseFile (&FileHandle);
849         }
850       }
851     }
852   }
853 
854   if (Package != NULL) {
855     ShellCommandLineFreeVarList (Package);
856   }
857   return ShellStatus;
858 }
859 
860