+ SHELL_FREE_NON_NULL(CurrentParameter);\r
+\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ Function to update the shell variable "lasterror".\r
+\r
+ @param[in] ErrorCode the error code to put into lasterror.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetLastError(\r
+ IN CONST SHELL_STATUS ErrorCode\r
+ )\r
+{\r
+ CHAR16 LeString[19];\r
+ if (sizeof(EFI_STATUS) == sizeof(UINT64)) {\r
+ UnicodeSPrint(LeString, sizeof(LeString), L"0x%Lx", ErrorCode);\r
+ } else {\r
+ UnicodeSPrint(LeString, sizeof(LeString), L"0x%x", ErrorCode);\r
+ }\r
+ DEBUG_CODE(InternalEfiShellSetEnv(L"debuglasterror", LeString, TRUE););\r
+ InternalEfiShellSetEnv(L"lasterror", LeString, TRUE);\r
+\r
+ return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ Converts the command line to it's post-processed form. this replaces variables and alias' per UEFI Shell spec.\r
+\r
+ @param[in,out] CmdLine pointer to the command line to update\r
+\r
+ @retval EFI_SUCCESS The operation was successful\r
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
+ @return some other error occured\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ProcessCommandLineToFinal(\r
+ IN OUT CHAR16 **CmdLine\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ TrimSpaces(CmdLine);\r
+\r
+ Status = ShellSubstituteAliases(CmdLine);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+\r
+ TrimSpaces(CmdLine);\r
+\r
+ Status = ShellSubstituteVariables(CmdLine);\r
+ if (EFI_ERROR(Status)) {\r
+ return (Status);\r
+ }\r
+ ASSERT (*CmdLine != NULL);\r
+\r
+ TrimSpaces(CmdLine);\r
+\r
+ //\r
+ // update for help parsing\r
+ //\r
+ if (StrStr(*CmdLine, L"?") != NULL) {\r
+ //\r
+ // This may do nothing if the ? does not indicate help.\r
+ // Save all the details for in the API below.\r
+ //\r
+ Status = DoHelpUpdate(CmdLine);\r
+ }\r
+\r
+ TrimSpaces(CmdLine);\r
+\r
+ return (EFI_SUCCESS);\r
+}\r
+\r
+/**\r
+ Run an internal shell command.\r
+\r
+ This API will upadate the shell's environment since these commands are libraries.\r
+ \r
+ @param[in] CmdLine the command line to run.\r
+ @param[in] FirstParameter the first parameter on the command line\r
+ @param[in] ParamProtocol the shell parameters protocol pointer\r
+\r
+ @param[out] ExitStatus The exit code of the command. Ignored if NULL.\r
+\r
+ @retval EFI_SUCCESS The command was completed.\r
+ @retval EFI_ABORTED The command's operation was aborted.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RunInternalCommand(\r
+ IN CONST CHAR16 *CmdLine,\r
+ IN CHAR16 *FirstParameter,\r
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,\r
+ OUT SHELL_STATUS *ExitStatus OPTIONAL\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Argc;\r
+ CHAR16 **Argv;\r
+ SHELL_STATUS CommandReturnedStatus;\r
+ BOOLEAN LastError;\r
+ CHAR16 *Walker;\r
+ CHAR16 *NewCmdLine; \r
+\r
+ NewCmdLine = AllocateCopyPool (StrSize (CmdLine), CmdLine);\r
+ if (NewCmdLine == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ for (Walker = NewCmdLine; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {\r
+ if (*Walker == L'^' && *(Walker+1) == L'#') {\r
+ CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));\r
+ }\r
+ }\r
+\r
+ //\r
+ // get the argc and argv updated for internal commands\r
+ //\r
+ Status = UpdateArgcArgv(ParamProtocol, NewCmdLine, &Argv, &Argc);\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // Run the internal command.\r
+ //\r
+ Status = ShellCommandRunCommandHandler(FirstParameter, &CommandReturnedStatus, &LastError);\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ //\r
+ // Update last error status.\r
+ // some commands do not update last error.\r
+ //\r
+ if (LastError) {\r
+ SetLastError(CommandReturnedStatus);\r
+ }\r
+ if (ExitStatus != NULL) {\r
+ *ExitStatus = CommandReturnedStatus;\r
+ }\r
+\r
+ //\r
+ // Pass thru the exitcode from the app.\r
+ //\r
+ if (ShellCommandGetExit()) {\r
+ //\r
+ // An Exit was requested ("exit" command), pass its value up.\r
+ //\r
+ Status = CommandReturnedStatus;\r
+ } else if (CommandReturnedStatus != SHELL_SUCCESS && IsScriptOnlyCommand(FirstParameter)) {\r
+ //\r
+ // Always abort when a script only command fails for any reason\r
+ //\r
+ Status = EFI_ABORTED;\r
+ } else if (ShellCommandGetCurrentScriptFile() != NULL && CommandReturnedStatus == SHELL_ABORTED) {\r
+ //\r
+ // Abort when in a script and a command aborted\r
+ //\r
+ Status = EFI_ABORTED;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // This is guarenteed to be called after UpdateArgcArgv no matter what else happened.\r
+ // This is safe even if the update API failed. In this case, it may be a no-op.\r
+ //\r
+ RestoreArgcArgv(ParamProtocol, &Argv, &Argc);\r
+\r
+ //\r
+ // If a script is running and the command is not a scipt only command, then\r
+ // change return value to success so the script won't halt (unless aborted).\r
+ //\r
+ // Script only commands have to be able halt the script since the script will\r
+ // not operate if they are failing.\r
+ //\r
+ if ( ShellCommandGetCurrentScriptFile() != NULL\r
+ && !IsScriptOnlyCommand(FirstParameter)\r
+ && Status != EFI_ABORTED\r
+ ) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+\r
+ FreePool (NewCmdLine);\r
+ return (Status);\r
+}\r
+\r
+/**\r
+ Function to run the command or file.\r
+\r
+ @param[in] Type the type of operation being run.\r
+ @param[in] CmdLine the command line to run.\r
+ @param[in] FirstParameter the first parameter on the command line\r
+ @param[in] ParamProtocol the shell parameters protocol pointer\r
+\r
+ @param[out] ExitStatus The exit code of the command or file.\r
+ Ignored if NULL.\r
+\r
+ @retval EFI_SUCCESS The command was completed.\r
+ @retval EFI_ABORTED The command's operation was aborted.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RunCommandOrFile(\r
+ IN SHELL_OPERATION_TYPES Type,\r
+ IN CONST CHAR16 *CmdLine,\r
+ IN CHAR16 *FirstParameter,\r
+ IN EFI_SHELL_PARAMETERS_PROTOCOL *ParamProtocol,\r
+ OUT SHELL_STATUS *ExitStatus\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS StartStatus;\r
+ CHAR16 *CommandWithPath;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;\r
+ SHELL_STATUS CalleeExitStatus;\r
+\r
+ Status = EFI_SUCCESS;\r
+ CommandWithPath = NULL;\r
+ DevPath = NULL;\r
+ CalleeExitStatus = SHELL_INVALID_PARAMETER;\r
+\r
+ switch (Type) {\r
+ case Internal_Command:\r
+ Status = RunInternalCommand(\r
+ CmdLine,\r
+ FirstParameter,\r
+ ParamProtocol,\r
+ &CalleeExitStatus\r
+ );\r
+ break;\r
+ case Script_File_Name:\r
+ case Efi_Application:\r
+ //\r
+ // Process a fully qualified path\r
+ //\r
+ if (StrStr(FirstParameter, L":") != NULL) {\r
+ ASSERT (CommandWithPath == NULL);\r
+ if (ShellIsFile(FirstParameter) == EFI_SUCCESS) {\r
+ CommandWithPath = StrnCatGrow(&CommandWithPath, NULL, FirstParameter, 0);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Process a relative path and also check in the path environment variable\r
+ //\r
+ if (CommandWithPath == NULL) {\r
+ CommandWithPath = ShellFindFilePathEx(FirstParameter, mExecutableExtensions);\r
+ }\r
+\r
+ //\r
+ // This should be impossible now.\r
+ //\r
+ ASSERT(CommandWithPath != NULL);\r
+\r
+ //\r
+ // Make sure that path is not just a directory (or not found)\r
+ //\r
+ if (!EFI_ERROR(ShellIsDirectory(CommandWithPath))) {\r
+ ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_SHELL_NOT_FOUND), ShellInfoObject.HiiHandle, FirstParameter);\r
+ SetLastError(SHELL_NOT_FOUND);\r
+ }\r
+ switch (Type) {\r
+ case Script_File_Name:\r
+ Status = RunScriptFile (\r
+ CommandWithPath,\r
+ NULL,\r
+ CmdLine,\r
+ ParamProtocol,\r
+ &CalleeExitStatus\r
+ );\r
+ break;\r
+ case Efi_Application:\r
+ //\r
+ // Get the device path of the application image\r
+ //\r
+ DevPath = ShellInfoObject.NewEfiShellProtocol->GetDevicePathFromFilePath(CommandWithPath);\r
+ if (DevPath == NULL){\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Execute the device path\r
+ //\r
+ Status = InternalShellExecuteDevicePath(\r
+ &gImageHandle,\r
+ DevPath,\r
+ CmdLine,\r
+ NULL,\r
+ &StartStatus,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ SHELL_FREE_NON_NULL(DevPath);\r
+\r
+ if(EFI_ERROR (Status)) {\r
+ CalleeExitStatus = (SHELL_STATUS) (Status & (~MAX_BIT));\r
+ } else {\r
+ CalleeExitStatus = (SHELL_STATUS) StartStatus;\r
+ }\r
+\r
+ //\r
+ // Update last error status.\r
+ //\r
+ // Status is an EFI_STATUS. Clear top bit to convert to SHELL_STATUS\r
+ SetLastError(CalleeExitStatus);\r
+ break;\r
+ default:\r
+ //\r
+ // Do nothing.\r
+ //\r
+ break;\r
+ }\r
+ break;\r
+ default:\r
+ //\r
+ // Do nothing.\r
+ //\r
+ break;\r
+ }\r
+\r