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