SHEL23
[efi/shell/.git] / dmpstore / dmpstore.c
index 3dea364..403e190 100644 (file)
@@ -1,6 +1,6 @@
 /*++
 
-Copyright 2005, Intel Corporation                                                         
+Copyright (c) 2005 - 2009, Intel Corporation                                                         
 All rights reserved. This program and the accompanying materials                          
 are licensed and made available under the terms and conditions of the BSD License         
 which accompanies this distribution. The full text of the license may be found at         
@@ -32,10 +32,9 @@ extern UINT8  STRING_ARRAY_NAME[];
 // This is the generated header file which includes whatever needs to be exported (strings + IFR)
 //
 #include STRING_DEFINES_FILE
-//
-//
-//
-#define DEBUG_NAME_SIZE 1050
+
+#define INIT_NAME_BUFFER_SIZE  128
+#define INIT_DATA_BUFFER_SIZE  1024
 
 STATIC CHAR16   *AttrType[] = {
   L"invalid",   // 000
@@ -57,9 +56,47 @@ InitializeDumpStore (
   IN EFI_SYSTEM_TABLE   *SystemTable
   );
 
+EFI_STATUS
+LoadVariableStore (
+  IN CHAR16   *VarName,
+  IN CHAR16   *FileName
+  );
+
 EFI_STATUS
 DumpVariableStore (
-  CHAR16 *VarName
+  IN CHAR16           *VarName,
+  IN BOOLEAN          Delete,
+  IN EFI_FILE_HANDLE  FileHandle  
+  );
+
+EFI_STATUS
+CreateOutputFile (
+  IN CHAR16           *FileName, 
+  OUT EFI_FILE_HANDLE *FileHandle
+  );
+
+EFI_STATUS
+GetFileVariable (
+  IN EFI_FILE_HANDLE FileHandle,
+  OUT UINTN          *VariableNameSize,
+  IN OUT UINTN       *NameBufferSize,
+  IN OUT CHAR16      **VariableName,
+  IN EFI_GUID        *VendorGuid,
+  OUT UINT32         *Attributes,
+  OUT UINTN          *DataSize,
+  IN OUT UINTN       *DataBufferSize,
+  IN OUT VOID        **Data
+  );
+
+EFI_STATUS
+SetFileVariable (
+  IN EFI_FILE_HANDLE FileHandle,
+  IN UINTN           VariableNameSize,
+  IN CHAR16          *VariableName,
+  IN EFI_GUID        *VendorGuid,
+  IN UINT32          Attributes,
+  IN UINTN           DataSize,
+  IN VOID            *Data  
   );
 
 //
@@ -80,6 +117,24 @@ SHELL_VAR_CHECK_ITEM    DmpstoreCheckList[] = {
     0,
     FlagTypeSingle
   },
+  {
+    L"-d",
+    0x04,
+    0x18,
+    FlagTypeSingle
+  },
+  {
+    L"-s",
+    0x08,
+    0x14,
+    FlagTypeNeedVar
+  },  
+  {
+    L"-l",
+    0x10,
+    0x0c,
+    FlagTypeNeedVar
+  },  
   {
     NULL,
     0,
@@ -116,10 +171,12 @@ Returns:
 {
   CHAR16                  *VarName;
   EFI_STATUS              Status;
-
+  BOOLEAN                 Delete;
+  EFI_FILE_HANDLE         FileHandle;
   SHELL_VAR_CHECK_CODE    RetCode;
   CHAR16                  *Useful;
   SHELL_VAR_CHECK_PACKAGE ChkPck;
+  SHELL_ARG_LIST          *Item;
 
   ZeroMem (&ChkPck, sizeof (SHELL_VAR_CHECK_PACKAGE));
   //
@@ -128,6 +185,11 @@ Returns:
   //
   EFI_SHELL_APP_INIT (ImageHandle, SystemTable);
 
+  //
+  // Enable tab key which can pause the output
+  //
+  EnableOutputTabPause();
+   
   //
   // Register our string package with HII and return the handle to it.
   // If previously registered we will simply receive the handle
@@ -137,8 +199,10 @@ Returns:
     return Status;
   }
 
-  VarName = NULL;
-  Status  = EFI_SUCCESS;
+  VarName    = NULL;
+  Status     = EFI_SUCCESS;
+  Delete     = FALSE;
+  FileHandle = NULL;
 
   LibFilterNullArgs ();
   //
@@ -148,6 +212,10 @@ Returns:
   RetCode = LibCheckVariables (SI, DmpstoreCheckList, &ChkPck, &Useful);
   if (VarCheckOk != RetCode) {
     switch (RetCode) {
+    case VarCheckConflict:
+      PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_FLAG_CONFLICT), HiiHandle, L"dmpstore", Useful);
+      break;
+          
     case VarCheckDuplicate:
       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_DUP_FLAG), HiiHandle, L"dmpstore", Useful);
       break;
@@ -156,6 +224,10 @@ Returns:
       PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_UNKNOWN_FLAG), HiiHandle, L"dmpstore", Useful);
       break;
 
+    case VarCheckLackValue:
+      PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_LACK_ARG), HiiHandle, L"dmpstore", Useful);
+      break;
+      
     default:
       break;
     }
@@ -192,68 +264,284 @@ Returns:
   if (NULL != ChkPck.VarList) {
     VarName = ChkPck.VarList->VarStr;
   }
-  //
-  // Dump all variables in store
-  //
-  if (VarName == NULL) {
-    Status = DumpVariableStore (NULL);
+  
+  Item = LibCheckVarGetFlag (&ChkPck, L"-l");
+  if (Item != NULL) {
+    //
+    // Load and set variables from previous saved file
+    //
+    Status = LoadVariableStore (VarName, Item->VarStr);
     goto Done;
   }
+
+  Item = LibCheckVarGetFlag (&ChkPck, L"-s");
+  if (Item != NULL) {
+    //
+    // Create output file for saving variables
+    //
+    Status = CreateOutputFile (Item->VarStr, &FileHandle);
+    if (EFI_ERROR (Status)) {
+      goto Done;
+    }
+  }
+
+  if (LibCheckVarGetFlag (&ChkPck, L"-d") != NULL) {
+    Delete = TRUE;
+  }
+      
   //
-  // Dump one variable in store
+  // Dump variables in store
   //
-  if (VarName != NULL) {
-    Status = DumpVariableStore (VarName);
-  }
+  Status = DumpVariableStore (VarName, Delete, FileHandle);
+
   //
   // Done
   //
 Done:
   LibCheckVarFreeVarList (&ChkPck);
   LibUnInitializeStrings ();
+  if (FileHandle != NULL) {
+    LibCloseFile (FileHandle);
+  };
+  return Status;
+}
+
+EFI_STATUS
+LoadVariableStore (
+  IN CHAR16   *VarName,
+  IN CHAR16   *FileName
+  )
+{
+  EFI_STATUS         Status;
+  EFI_FILE_HANDLE    FileHandle;  
+  EFI_GUID           Guid;
+  UINT32             Attributes;
+  CHAR16             *Name;
+  UINTN              NameBufferSize;
+  UINTN              NameSize;
+  VOID               *Data;
+  UINTN              DataBufferSize;
+  UINTN              DataSize;
+  BOOLEAN            Found;
+  EFI_FILE_INFO      *FileInfo;
+
+  Found      = FALSE;
+  FileHandle = NULL;
+  FileInfo   = NULL;
+  
+  NameBufferSize = INIT_NAME_BUFFER_SIZE;
+  DataBufferSize = INIT_DATA_BUFFER_SIZE;
+  Name           = AllocateZeroPool (NameBufferSize);
+  Data           = AllocatePool (DataBufferSize);
+  if (Name == NULL || Data == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+  //
+  // Open the previous saved output file
+  //  
+  Status = LibOpenFileByName (
+             FileName,
+             &FileHandle,
+             EFI_FILE_MODE_READ,
+             0
+             );
+  if (EFI_ERROR (Status)) {
+    PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE), HiiHandle, L"dmpstore", FileName);
+    goto Done;
+  }
+  
+  //
+  // If the file is directory, abort
+  //
+  FileInfo = LibGetFileInfo (FileHandle);
+  if (FileInfo == NULL) {
+    Status = EFI_ABORTED;
+    PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE), HiiHandle, L"dmpstore", FileName);
+    goto Done;
+  } else if (FileInfo->Attribute & EFI_FILE_DIRECTORY) {
+    Status = EFI_ABORTED;
+    PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE), HiiHandle, L"dmpstore", FileName);
+    goto Done;
+  }
+  
+  PrintToken (STRING_TOKEN (STR_DMPSTORE_LOAD), HiiHandle);
+  do {
+    //
+    // Break the execution?
+    //
+    if (GetExecutionBreak ()) {
+      break;
+    }
+    
+    Status = GetFileVariable (FileHandle, &NameSize, &NameBufferSize, &Name, &Guid, &Attributes, &DataSize, &DataBufferSize, &Data);
+    if (Status == EFI_NOT_FOUND) {
+      Status = EFI_SUCCESS;
+      break;
+    }
+    if (EFI_ERROR (Status)) {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_LOAD_ERR2), HiiHandle);
+      goto Done;
+    }
+    if (VarName != NULL) {
+      if (!MetaiMatch (Name, VarName)) {
+        continue;
+      }
+    }
+    
+    Found = TRUE;
+    //
+    // Dump variable name
+    //        
+    PrintToken (
+      STRING_TOKEN (STR_DMPSTORE_VAR),
+      HiiHandle,
+      AttrType[Attributes & 7],
+      &Guid,
+      Name,
+      DataSize
+      );    
+    Status = RT->SetVariable (Name, &Guid, Attributes, DataSize, Data);
+    if (EFI_ERROR (Status)) {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_LOAD_ERR), HiiHandle);
+      goto Done;
+    }
+  } while (!EFI_ERROR (Status));
+
+  if (!Found) {
+    if (VarName != NULL) {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_VAR_NOT_FOUND), HiiHandle, VarName);
+    } else {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_VAR_EMPTY), HiiHandle);
+    }
+  }
+
+Done:
+  if (FileInfo != NULL) {
+    FreePool (FileInfo); 
+  }  
+  if (FileHandle != NULL) {
+    LibCloseFile (FileHandle);
+  }
+  if (Name != NULL) {
+    FreePool (Name);
+  }
+  if (Data != NULL) {
+    FreePool (Data);
+  }
   return Status;
 }
 
 EFI_STATUS
 DumpVariableStore (
-  CHAR16 *VarName
+  IN CHAR16           *VarName,
+  IN BOOLEAN          Delete,
+  IN EFI_FILE_HANDLE  FileHandle
   )
 {
   EFI_STATUS  Status;
   EFI_GUID    Guid;
   UINT32      Attributes;
-  CHAR16      Name[DEBUG_NAME_SIZE / 2];
+  CHAR16      *Name;
+  UINTN       NameBufferSize; // Allocated Name buffer size
   UINTN       NameSize;
-  CHAR16      Data[DEBUG_NAME_SIZE / 2];
+  CHAR16      *OldName;
+  UINTN       OldNameBufferSize;
+  VOID        *Data;
+  UINTN       DataBufferSize; // Allocated Name buffer size
   UINTN       DataSize;
   BOOLEAN     Found;
 
-  Found = FALSE;
+  Found  = FALSE;
+  Status = EFI_SUCCESS;
 
   if (VarName != NULL) {
-    PrintToken (STRING_TOKEN (STR_DMPSTORE_DUMP_ONE_VAR), HiiHandle, VarName);
+    if (Delete) {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_DELETE_ONE_VAR), HiiHandle, VarName);
+    } else if (FileHandle != NULL) {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_SAVE_ONE_VAR), HiiHandle, VarName);
+    } else {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_DUMP_ONE_VAR), HiiHandle, VarName);
+    }
   } else {
-    PrintToken (STRING_TOKEN (STR_DMPSTORE_DUMP), HiiHandle);
+    if (Delete) {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_DELETE), HiiHandle);
+    } else if (FileHandle != NULL) {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_SAVE), HiiHandle);
+    } else {
+      PrintToken (STRING_TOKEN (STR_DMPSTORE_DUMP), HiiHandle);
+    }    
   }
 
-  Name[0] = 0x0000;
+  NameBufferSize = INIT_NAME_BUFFER_SIZE;
+  DataBufferSize = INIT_DATA_BUFFER_SIZE;
+  Name           = AllocateZeroPool (NameBufferSize);
+  Data           = AllocatePool (DataBufferSize);
+  if (Name == NULL || Data == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
   do {
-    NameSize  = DEBUG_NAME_SIZE;
+    //
+    // Break the execution?
+    //
+    if (GetExecutionBreak ()) {
+      goto Done;
+    }
+    
+    NameSize  = NameBufferSize;
     Status    = RT->GetNextVariableName (&NameSize, Name, &Guid);
-    if (VarName != NULL) {
-      if (!MetaiMatch (Name, VarName)) {
-        continue;
+    if (Status == EFI_BUFFER_TOO_SMALL) {
+      OldName           = Name;
+      OldNameBufferSize = NameBufferSize;
+      //
+      // Expand at least twice to avoid reallocate many times
+      //
+      NameBufferSize = NameSize > NameBufferSize * 2 ? NameSize : NameBufferSize * 2;
+      Name           = AllocateZeroPool (NameBufferSize);
+      if (Name == NULL) {
+        Status = EFI_OUT_OF_RESOURCES;
+        FreePool (OldName);
+        goto Done;
       }
+      //
+      // Preserve the original content to get correct iteration for GetNextVariableName() call
+      //
+      CopyMem (Name, OldName, OldNameBufferSize);
+      FreePool (OldName);
+      NameSize = NameBufferSize;
+      Status = RT->GetNextVariableName (&NameSize, Name, &Guid);
     }
-
     if (!EFI_ERROR (Status)) {
+      if (VarName != NULL) {
+        if (!MetaiMatch (Name, VarName)) {
+          continue;
+        }
+      }      
+
       Found     = TRUE;
-      DataSize  = DEBUG_NAME_SIZE;
+      DataSize  = DataBufferSize;
       Status    = RT->GetVariable (Name, &Guid, &Attributes, &DataSize, Data);
-      if (!EFI_ERROR (Status)) {
+      if (Status == EFI_BUFFER_TOO_SMALL) {
         //
-        // dump variables
+        // Expand at least twice to avoid reallocate many times
         //
+        FreePool (Data);
+        DataBufferSize = DataSize > DataBufferSize * 2 ? DataSize : DataBufferSize * 2;
+        Data           = AllocatePool (DataBufferSize);
+        if (Data == NULL) {
+          Status = EFI_OUT_OF_RESOURCES;
+          goto Done;
+        }
+        DataSize = DataBufferSize;
+        Status   = RT->GetVariable (Name, &Guid, &Attributes, &DataSize, Data);
+      }
+      if (!EFI_ERROR (Status)) {
+        //
+        // Dump variable name
+        //        
         PrintToken (
           STRING_TOKEN (STR_DMPSTORE_VAR),
           HiiHandle,
@@ -262,15 +550,41 @@ DumpVariableStore (
           Name,
           DataSize
           );
-
-        if (PrivateDumpHex (2, 0, DataSize, Data)) {
-          goto Done;
+        if (Delete) {
+          //
+          // Delete variables
+          //
+          DataSize = 0;
+          Status   = RT->SetVariable (Name, &Guid, Attributes, DataSize, Data);
+          if (EFI_ERROR (Status)) {
+            PrintToken (STRING_TOKEN (STR_DMPSTORE_DELETE_ERR), HiiHandle);
+            goto Done;
+          } else {
+            Name[0] = 0x0000;
+          }
+        } else if (FileHandle != NULL) {
+          //
+          // Save variables to output file
+          //
+          Status = SetFileVariable (FileHandle, NameSize, Name, &Guid, Attributes, DataSize, Data);
+          if (EFI_ERROR (Status)) {
+            PrintToken (STRING_TOKEN (STR_DMPSTORE_SAVE_ERR), HiiHandle);
+            goto Done;
+          }
+        } else {
+          //
+          // Dump variable data
+          //
+          PrivateDumpHex (2, 0, DataSize, Data);
         }
       }
+    } else if (Status == EFI_NOT_FOUND) {
+      Status = EFI_SUCCESS;
+      break;
     }
   } while (!EFI_ERROR (Status));
 
-  if (Found == FALSE) {
+  if (!Found) {
     if (VarName != NULL) {
       PrintToken (STRING_TOKEN (STR_DMPSTORE_VAR_NOT_FOUND), HiiHandle, VarName);
     } else {
@@ -279,9 +593,208 @@ DumpVariableStore (
   }
 
 Done:
+  if (Name != NULL) {
+    FreePool (Name);
+  }
+  if (Data != NULL) {
+    FreePool (Data);
+  }
+  return Status;
+}
+
+EFI_STATUS
+CreateOutputFile (
+  IN CHAR16           *FileName, 
+  OUT EFI_FILE_HANDLE *FileHandle
+  )
+{
+  EFI_STATUS     Status;
+  EFI_FILE_INFO  *FileInfo;
+
+  FileInfo = NULL;
+  
+  //
+  // Delete the output file first if it exist
+  //  
+  Status = LibOpenFileByName (
+             FileName,
+             FileHandle,
+             EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE,
+             0
+             );
+  if (!EFI_ERROR (Status)) {
+    //
+    // If the existing file is directory, abort
+    //
+    FileInfo = LibGetFileInfo (*FileHandle);
+    if (FileInfo == NULL) {
+      Status = EFI_ABORTED;
+      goto Done;
+    } else if (FileInfo->Attribute & EFI_FILE_DIRECTORY) {
+      Status = EFI_ABORTED;
+      goto Done;
+    }    
+    LibDeleteFile (*FileHandle);
+  } else if (Status != EFI_NOT_FOUND) {
+    goto Done;
+  }
+
+  //
+  // Create the output file
+  //
+  Status = LibOpenFileByName (
+             FileName,
+             FileHandle,
+             EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE,
+             0
+             );
+  
+Done: 
+  if (FileInfo != NULL) {
+    FreePool (FileInfo); 
+  }
+  if (EFI_ERROR (Status)) {
+    PrintToken (STRING_TOKEN (STR_SHELLENV_GNC_CANNOT_OPEN_FILE), HiiHandle, L"dmpstore", FileName);
+  }
+  return Status;
+}
+
+EFI_STATUS
+GetFileVariable (
+  IN EFI_FILE_HANDLE FileHandle,
+  OUT UINTN          *VariableNameSize,
+  IN OUT UINTN       *NameBufferSize,
+  IN OUT CHAR16      **VariableName,
+  IN EFI_GUID        *VendorGuid,
+  OUT UINT32         *Attributes,
+  OUT UINTN          *DataSize,
+  IN OUT UINTN       *DataBufferSize,
+  IN OUT VOID        **Data
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BufferSize;
+  UINTN       NameSize;
+  UINTN       Size;
+  
+  NameSize   = 0;
+  BufferSize = sizeof (UINT32);
+  Status     = LibReadFile (FileHandle, &BufferSize, &NameSize);
+  if (!EFI_ERROR (Status) && (BufferSize == 0)) {
+    return EFI_NOT_FOUND; // End of file
+  }
+  if (EFI_ERROR (Status) || (BufferSize != sizeof (UINT32))) {
+    return EFI_ABORTED;
+  }
+  
+  if (NameSize > *NameBufferSize) {
+    //
+    // Expand at least twice to avoid reallocate many times
+    //
+    FreePool (*VariableName);
+    *NameBufferSize = NameSize > *NameBufferSize * 2 ? NameSize : *NameBufferSize * 2;
+    *VariableName   = AllocateZeroPool (*NameBufferSize);
+    if (*VariableName == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+  BufferSize = NameSize;
+  Status     = LibReadFile (FileHandle, &BufferSize, *VariableName);
+  if (EFI_ERROR (Status) || (BufferSize != NameSize)) {
+    return EFI_ABORTED;
+  }
+
+  BufferSize = sizeof (EFI_GUID);
+  Status     = LibReadFile (FileHandle, &BufferSize, VendorGuid);
+  if (EFI_ERROR (Status) || (BufferSize != sizeof (EFI_GUID))) {
+    return EFI_ABORTED;
+  }
+
+  BufferSize = sizeof (UINT32);
+  Status     = LibReadFile (FileHandle, &BufferSize, Attributes);
+  if (EFI_ERROR (Status) || (BufferSize != sizeof (UINT32))) {
+    return EFI_ABORTED;
+  }
+
+  Size       = 0;
+  BufferSize = sizeof (UINT32);
+  Status     = LibReadFile (FileHandle, &BufferSize, &Size);
+  if (EFI_ERROR (Status) || (BufferSize != sizeof (UINT32))) {
+    return EFI_ABORTED;
+  }
+  
+  if (Size > *DataBufferSize) {
+    //
+    // Expand at least twice to avoid reallocate many times
+    //
+    FreePool (*Data);
+    *DataBufferSize = Size > *DataBufferSize * 2 ? Size : *DataBufferSize * 2;
+    *Data           = AllocatePool (*DataBufferSize);
+    if (*Data == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  }
+  BufferSize = Size;
+  Status     = LibReadFile (FileHandle, &BufferSize, *Data);
+  if (EFI_ERROR (Status) || (BufferSize != Size)) {
+    return EFI_ABORTED;
+  }
+  
+  *VariableNameSize = NameSize;
+  *DataSize         = Size;
   return EFI_SUCCESS;
 }
 
+EFI_STATUS
+SetFileVariable (
+  IN EFI_FILE_HANDLE FileHandle,
+  IN UINTN           VariableNameSize,
+  IN CHAR16          *VariableName,
+  IN EFI_GUID        *VendorGuid,
+  IN UINT32          Attributes,
+  IN UINTN           DataSize,
+  IN VOID            *Data  
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BufferSize;
+
+  BufferSize = sizeof (UINT32);
+  Status = LibWriteFile (FileHandle, &BufferSize, &VariableNameSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  
+  BufferSize = VariableNameSize;
+  Status = LibWriteFile (FileHandle, &BufferSize, VariableName);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  BufferSize = sizeof (EFI_GUID);
+  Status = LibWriteFile (FileHandle, &BufferSize, VendorGuid);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  BufferSize = sizeof (UINT32);
+  Status = LibWriteFile (FileHandle, &BufferSize, &Attributes);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  BufferSize = sizeof (UINT32);
+  Status = LibWriteFile (FileHandle, &BufferSize, &DataSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  BufferSize = DataSize;
+  Status = LibWriteFile (FileHandle, &BufferSize, Data);
+
+  return Status;
+}
+
 EFI_STATUS
 InitializeDumpStoreGetLineHelp (
   OUT CHAR16                **Str