Add CWD and thus a cd command to EBL shell. Fix WatchdogTimout code in EBL, it was...
authorandrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 10 Feb 2010 00:46:41 +0000 (00:46 +0000)
committerandrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524>
Wed, 10 Feb 2010 00:46:41 +0000 (00:46 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9958 6f19259b-4bc3-4df7-8a09-765794883524

EmbeddedPkg/Ebl/Dir.c
EmbeddedPkg/Ebl/Main.c
EmbeddedPkg/Include/Library/EfiFileLib.h
EmbeddedPkg/Library/EfiFileLib/EfiFileLib.c

index 4e9f7b98b2928d98d2c37e49fd813f9533fc1cee..ff1b557ed18a20e2d954e54dda9714f3b9adbd1e 100644 (file)
@@ -52,7 +52,7 @@ GLOBAL_REMOVE_IF_UNREFERENCED   CHAR8 *gFvFileType[] = {
                       only print out files that contain the string *.efi\r
   dir fv1:\         ; perform a dir on fv1: device in the efi directory \r
                     NOTE: fv devices do not contian subdirs \r
-  dir fv1:\ * PEIM  ; will match all files of type SEC\r
+  dir fv1:\ * PEIM  ; will match all files of type PEIM\r
 \r
   @param  Argc   Number of command arguments in Argv\r
   @param  Argv   Array of strings that represent the parsed command line. \r
@@ -88,14 +88,19 @@ EblDirCmd (
   UINTN                         Length;\r
   UINTN                         BestMatchCount;\r
   CHAR16                        UnicodeFileName[MAX_CMD_LINE];\r
+  CHAR8                         *Path;\r
 \r
 \r
   if (Argc <= 1) {\r
-    // CWD not currently supported \r
-    return EFI_SUCCESS;\r
+    Path = EfiGetCwd ();\r
+    if (Path == NULL) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  } else {\r
+    Path = Argv[1];\r
   }\r
 \r
-  File = EfiOpen (Argv[1], EFI_FILE_MODE_READ, 0);\r
+  File = EfiOpen (Path, EFI_FILE_MODE_READ, 0);\r
   if (File == NULL) {\r
     return EFI_SUCCESS;\r
   }\r
@@ -277,6 +282,32 @@ Done:
   return EFI_SUCCESS;\r
 }\r
 \r
+/**\r
+  Change the Current Working Directory\r
+\r
+  Argv[0] - "cd"\r
+  Argv[1] - Device Name:path. Path is optional \r
+\r
+  @param  Argc   Number of command arguments in Argv\r
+  @param  Argv   Array of strings that represent the parsed command line. \r
+                 Argv[0] is the comamnd name\r
+\r
+  @return EFI_SUCCESS\r
+\r
+**/\r
+EFI_STATUS\r
+EblCdCmd (\r
+  IN UINTN  Argc,\r
+  IN CHAR8  **Argv\r
+  )\r
+{\r
+  if (Argc <= 1) {\r
+    return EFI_SUCCESS;\r
+  } \r
+  \r
+  return EfiSetCwd (Argv[1]);\r
+}\r
+\r
 \r
 \r
 GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDirTemplate[] =\r
@@ -286,6 +317,12 @@ GLOBAL_REMOVE_IF_UNREFERENCED const EBL_COMMAND_TABLE mCmdDirTemplate[] =
     " dirdev [*match]; directory listing of dirdev. opt match a substring",\r
     NULL,\r
     EblDirCmd\r
+  },\r
+  {\r
+    "cd",\r
+    " device - set the current working directory",\r
+    NULL,\r
+    EblCdCmd\r
   }\r
 };\r
 \r
index d3dcc58a929f0744bea195dbdad6175e2028b5d3..ed2104cfe793b7631a464101c68cb66fa9107641 100644 (file)
@@ -464,7 +464,7 @@ EblPrompt (
   )\r
 {\r
   EblSetTextColor (EFI_YELLOW);\r
-  AsciiPrint ((CHAR8 *)PcdGetPtr (PcdEmbeddedPrompt));\r
+  AsciiPrint ((CHAR8 *)PcdGetPtr (PcdEmbeddedPrompt), EfiGetCwd ());\r
   EblSetTextColor (0);\r
   AsciiPrint ("%a", ">");\r
 }\r
@@ -559,6 +559,9 @@ EdkBootLoaderEntry (
   EblInitializeExternalCmd ();\r
   EblInitializeNetworkCmd();\r
   \r
+  // Disable the 5 minute EFI watchdog time so we don't get automatically reset\r
+  gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
+\r
   if (FeaturePcdGet (PcdEmbeddedMacBoot)) {\r
     // A MAC will boot in graphics mode, so turn it back to text here\r
     // This protocol was removed from edk2. It is only an edk thing. We need to make our own copy.\r
@@ -567,8 +570,6 @@ EdkBootLoaderEntry (
     // Enable the biggest output screen size possible\r
     gST->ConOut->SetMode (gST->ConOut, (UINTN)gST->ConOut->Mode->MaxMode - 1);\r
 \r
-    // Disable the 5 minute EFI watchdog time so we don't get automatically reset\r
-    gBS->SetWatchdogTimer (0, 0, 0, NULL);\r
   }\r
 \r
   // Save current screen mode\r
index 4e3c80d7ecbdd5e216931c587f74d58f6a6aa65d..4bbb1b26f138dddc279ed6e42b7c970a5d210f7a 100644 (file)
@@ -341,7 +341,7 @@ EfiSetCwd (
   \r
 **/\r
 CHAR8 *\r
-EfiGettCwd (\r
+EfiGetCwd (\r
   VOID\r
   );  \r
 \r
index cbe2aeecebddb626ab2eb547d6dcaef4b2105be0..c58d21e8200e06a2386a0ffc142564b5faf3dd2f 100644 (file)
@@ -647,7 +647,7 @@ EfiOpen (
   File->FvSectionType = SectionType;
 
   StrLen = AsciiStrSize (PathName);
-  if (StrLen <= 2) {
+  if (StrLen <= 1) {
     // Smallest valid path is 1 char and a null
     return NULL;
   }
@@ -659,7 +659,7 @@ EfiOpen (
     }
   }
 
-  if (FileStart == 0) {
+  if (FileStart == StrLen) {
     if (gCwd == NULL) {
       // No CWD
       return NULL;
@@ -671,8 +671,31 @@ EfiOpen (
       return NULL;
     }
     
-    AsciiStrCpy (CwdPlusPathName, gCwd);
+    if ((PathName[0] == '/') || (PathName[0] == '\\')) {
+      // PathName starts in / so this means we go to the root of the device in the CWD. 
+      CwdPlusPathName[0] = '\0';
+      for (FileStart = 0; gCwd[FileStart] != '\0'; FileStart++) {
+        CwdPlusPathName[FileStart] = gCwd[FileStart];
+        if (gCwd[FileStart] == ':') {
+          FileStart++;
+          CwdPlusPathName[FileStart] = '\0';
+          break;
+        }
+      }
+    } else {
+      AsciiStrCpy (CwdPlusPathName, gCwd);
+      StrLen = AsciiStrLen (gCwd);
+      if ((*PathName != '/') && (*PathName != '\\') && (gCwd[StrLen-1] != '/') && (gCwd[StrLen-1] != '\\')) {
+        AsciiStrCat (CwdPlusPathName, "/");
+      }
+    }
+    
     AsciiStrCat (CwdPlusPathName, PathName);
+    if (AsciiStrStr (CwdPlusPathName, ":") == NULL) {
+      // Extra error check to make sure we don't recusre and blow stack
+      return NULL;
+    }
+        
     File = EfiOpen (CwdPlusPathName, OpenMode, SectionType);
     FreePool (CwdPlusPathName);
     return File;
@@ -690,6 +713,10 @@ EfiOpen (
   AsciiStrCpy (File->DeviceName, PathName);
   File->DeviceName[FileStart - 1] = '\0';
   File->FileName = &File->DeviceName[FileStart];
+  if (File->FileName[0] == '\0') {
+    // if it is just a file name use / as root
+    File->FileName = "/";
+  } 
 
   //
   // Use best match algorithm on the dev names so we only need to look at the
@@ -1500,6 +1527,82 @@ EfiWrite (
 }
 
 
+/**
+  Given Cwd expand Path to remove .. and replace them with real 
+  directory names.
+  
+  @param  Cwd     Current Working Directory
+  @param  Path    Path to expand
+
+  @return NULL     Cwd or Path are not valid
+  @return 'other'  Path with .. expanded
+
+**/
+CHAR8 *
+ExpandPath (
+  IN CHAR8    *Cwd,
+  IN CHAR8    *Path
+  )
+{
+  CHAR8   *NewPath;
+  CHAR8   *Work, *Start, *End;
+  UINTN   StrLen;
+  UINTN   i;
+  
+  if (Cwd == NULL || Path == NULL) {
+    return NULL;
+  }
+  
+  StrLen = AsciiStrSize (Cwd);
+  if (StrLen <= 2) {
+    // Smallest valid path is 1 char and a null
+    return NULL;
+  }
+
+  StrLen = AsciiStrSize (Path);
+  NewPath = AllocatePool (AsciiStrSize (Cwd) + StrLen + 1);
+  if (NewPath == NULL) {
+    return NULL;
+  }
+  AsciiStrCpy (NewPath, Cwd);
+  
+  End = Path + StrLen;
+  for (Start = Path ;;) {
+    Work = AsciiStrStr (Start, "..") ;
+    if (Work == NULL) {
+      // Remaining part of Path contains no more ..
+      break;
+    } 
+    // append path prior to .. 
+    AsciiStrnCat (NewPath, Start, Work - Start);
+    StrLen = AsciiStrLen (NewPath);
+    for (i = StrLen; i >= 0; i--) {
+      if (NewPath[i] == ':') {
+        // too many ..
+        return NULL;
+      }
+      if (NewPath[i] == '/' || NewPath[i] == '\\') {
+        if ((i > 0) && (NewPath[i-1] == ':')) {
+          // leave the / before a :
+          NewPath[i+1] = '\0';
+        } else {
+          // replace / will Null to remove trailing file/dir reference
+          NewPath[i] = '\0';
+        }
+        break;
+      }
+    }
+    
+    Start = Work + 3;
+  } 
+  
+  // Handle the path that remains after the ..
+  AsciiStrnCat (NewPath, Start, End - Start);
+  
+  return NewPath;
+}
+
 
 /**
   Set the Curent Working Directory (CWD). If a call is made to EfiOpen () and 
@@ -1518,23 +1621,65 @@ EfiSetCwd (
   ) 
 {
   EFI_OPEN_FILE *File;
+  UINTN         Len;
+  CHAR8         *Path;
   
-  File = EfiOpen (Cwd, EFI_FILE_MODE_READ, 0);
-  if (File == NULL) {
+  if (Cwd == NULL) {
     return EFI_INVALID_PARAMETER;
   }
   
-  EfiClose (File);
+  if (AsciiStrCmp (Cwd, ".") == 0) {
+    // cd . is a no-op
+    return EFI_SUCCESS;
+  }
   
+  Path = Cwd;
+  if (AsciiStrStr (Cwd, "..") != NULL) {
+    if (gCwd == NULL) {
+      // no parent 
+      return EFI_SUCCESS;
+    }
+    
+    Len = AsciiStrLen (gCwd);
+    if ((gCwd[Len-2] == ':') && ((gCwd[Len-1] == '/') || (gCwd[Len-1] == '\\'))) {
+      // parent is device so nothing to do
+      return EFI_SUCCESS;
+    }
+    
+    // Expand .. in Cwd, given we know current working directory
+    Path = ExpandPath (gCwd, Cwd);
+    if (Path == NULL) {
+      return EFI_NOT_FOUND;
+    }
+  }
+  
+  File = EfiOpen (Path, EFI_FILE_MODE_READ, 0);
+  if (File == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+    
   if (gCwd != NULL) {
     FreePool (gCwd);
   }
   
-  gCwd = AllocatePool (AsciiStrSize (Cwd));
+  // Use the info returned from EfiOpen as it can add in CWD if needed. So Cwd could be
+  // relative to the current gCwd or not.
+  gCwd = AllocatePool (AsciiStrSize (File->DeviceName) + AsciiStrSize (File->FileName) + 1);
   if (gCwd == NULL) {
     return EFI_INVALID_PARAMETER;
   }
-  AsciiStrCpy (gCwd, Cwd);
+  AsciiStrCpy (gCwd, File->DeviceName);
+  if (File->FileName == NULL) {
+    AsciiStrCat (gCwd, ":\\");
+  } else {
+    AsciiStrCat (gCwd, ":");
+    AsciiStrCat (gCwd, File->FileName);
+  }
+  
+  EfiClose (File);
+  if (Path != Cwd) {
+    FreePool (Path);
+  }
   return EFI_SUCCESS;
 }
 
@@ -1549,15 +1694,18 @@ EfiSetCwd (
   @param  Cwd     Current Working Directory 
 
 
-  @return NULL    No CWD set
+  @return ""      No CWD set
   @return 'other' Returns buffer that contains CWD.
   
 **/
 CHAR8 *
-EfiGettCwd (
+EfiGetCwd (
   VOID
   )
 {
+  if (gCwd == NULL) {
+    return "";
+  }
   return gCwd;
 }