windows-nt/Source/XPSP1/NT/base/efiutil/sdk/shell/newshell/init.c

478 lines
11 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Intel Corporation
Module Name:
init.c
Abstract:
Shell
Revision History
--*/
#include "nshell.h"
/*
* Globals
*/
CHAR16 *ShellEnvPathName[] = {
L"shellenv.efi",
L"efi\\shellenv.efi",
L"efi\\tools\\shellenv.efi",
NULL
} ;
/*
* Prototypes
*/
EFI_STATUS
InitializeShell (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
EFI_STATUS
ShellLoadEnvDriver (
IN EFI_HANDLE ImageHandle
);
EFI_STATUS
NShellPrompt (
IN EFI_HANDLE ImageHandle
);
BOOLEAN
ParseLoadOptions(
EFI_HANDLE ImageHandle,
OUT CHAR16 **CommandLine,
OUT CHAR16 **CurrentDir
);
/*
*
*/
EFI_DRIVER_ENTRY_POINT(InitializeShell)
EFI_STATUS
InitializeShell (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
/*++
Routine Description:
Arguments:
ImageHandle - The handle for this driver
SystemTable - The system table
Returns:
--*/
{
EFI_STATUS Status;
EFI_HANDLE Handle;
UINTN BufferSize;
VOID *Junk;
BOOLEAN IsRootInstance;
CHAR16 *CommandLine;
CHAR16 *CurrentDir;
/*
* The shell may be started as either:
* 1. the first time with no shell environment loaded yet
* 2. not the first time, but with a shell environment loaded
* 3. as a child of a parent shell image
*/
IsRootInstance = FALSE;
InitializeLib (ImageHandle, SystemTable);
/*
* If the shell environment is not loaded, load it now
*/
BufferSize = sizeof(Handle);
Status = BS->LocateHandle(ByProtocol, &ShellEnvProtocol, NULL, &BufferSize, &Handle);
if (EFI_ERROR(Status)) {
Status = ShellLoadEnvDriver (ImageHandle);
if (EFI_ERROR(Status)) {
Print(L"Shell environment driver not loaded\n");
BS->Exit (ImageHandle, Status, 0, NULL);
}
}
/*
* Check to see if we're a child of a previous shell
*/
Status = BS->HandleProtocol (ImageHandle, &ShellInterfaceProtocol, (VOID*)&Junk);
if (EFI_ERROR(Status)) {
/*
* Special case were the shell is being started directly (e.g., not
* as a child of another shell)
*/
BufferSize = sizeof(Handle);
Status = BS->LocateHandle(ByProtocol, &ShellEnvProtocol, NULL, &BufferSize, &Handle);
ASSERT (!EFI_ERROR(Status));
Status = BS->HandleProtocol(Handle, &ShellEnvProtocol, (VOID*)&SE);
ASSERT (!EFI_ERROR(Status));
/*
* Allocate a new shell interface structure, and assign it to our
* image handle
*/
SI = SE->NewShell(ImageHandle);
Status = LibInstallProtocolInterfaces (&ImageHandle, &ShellInterfaceProtocol, SI, NULL);
ASSERT (!EFI_ERROR(Status));
IsRootInstance = TRUE;
}
/*
* Now we can initialize like a normal shell app
*/
InitializeShellApplication (ImageHandle, SystemTable);
/*
* If there are load options, assume they contain a command line and
* possible current working directory
*/
if (ParseLoadOptions (ImageHandle, &CommandLine, &CurrentDir)) {
/*
* Skip the 1st argument which should be us.
*/
while (*CommandLine != L' ' && *CommandLine != 0) {
CommandLine++;
}
/*
* Get to the beginning of the next argument.
*/
while (*CommandLine == L' ') {
CommandLine++;
}
/*
* If there was a current working directory, set it.
*/
if (CurrentDir) {
CHAR16 CmdLine[256], *Tmp;
/*
* Set a mapping
*/
StrCpy (CmdLine, CurrentDir);
for (Tmp = CmdLine; *Tmp && *Tmp != L':'; Tmp++)
;
if ( *Tmp ) {
*(++Tmp) = 0;
ShellExecute (ImageHandle, CmdLine, TRUE);
}
/*
* Now change to that directory
*/
StrCpy (CmdLine, L"cd ");
if ((StrLen (CmdLine) + StrLen (CurrentDir) + sizeof(CHAR16)) <
(sizeof(CmdLine) / sizeof(CHAR16))) {
StrCat (CmdLine, CurrentDir);
ShellExecute (ImageHandle, CmdLine, TRUE);
}
}
/*
* Have the shell execute the remaining command line. If there is
* nothing remaining, run the shell main loop below.
*/
if ( *CommandLine != 0 )
return (ShellExecute (ImageHandle, CommandLine, TRUE));
}
/*
* If this is the root instance, execute the command to load the default values
*/
if (IsRootInstance) {
Print (L"%EEFI Shell version %01d.%02d [%d.%d]\n%N",
(ST->Hdr.Revision >> 16),
(ST->Hdr.Revision & 0xffff),
(ST->FirmwareRevision >> 16),
(ST->FirmwareRevision & 0xffff));
ShellExecute (ImageHandle, L"_load_defaults", TRUE);
/* dump device mappings, -r to sync with current hardware */
ShellExecute (ImageHandle, L"map -r", TRUE);
/* run startup script (if any) */
/*
* BugBug: I turned on echo so you can tell the startup.nsh is running
*
* ShellExecute (ImageHandle, L"echo -off", FALSE); */
ShellExecute (ImageHandle, L"startup.nsh", FALSE);
/* ShellExecute (ImageHandle, L"echo -on", FALSE); */
}
/*
* EFI Shell main loop
*/
Status = EFI_SUCCESS;
while (Status != -1) {
Status = NShellPrompt (ImageHandle);
}
/*
* Done - cleanup the shell
*/
Status = EFI_SUCCESS;
Print (L"Shell exit - %r\n", Status);
/*
* If this was a root instance, we allocate a dumby shell interface for ourselves
* free it now
*/
if (IsRootInstance) {
BS->UninstallProtocolInterface (ImageHandle, &ShellInterfaceProtocol, SI);
FreePool (SI);
}
return Status;
}
EFI_STATUS
ShellLoadEnvDriverByPath (
IN EFI_HANDLE ParentImageHandle,
IN EFI_HANDLE DeviceHandle
)
{
EFI_STATUS Status;
EFI_DEVICE_PATH *FilePath;
EFI_HANDLE NewImageHandle;
UINTN Index;
BOOLEAN SearchNext;
/*
* If there's no device to search forget it
*/
if (!DeviceHandle) {
return EFI_NOT_FOUND;
}
/*
* Try loading shellenv from each path
*/
SearchNext = TRUE;
for (Index=0; ShellEnvPathName[Index] && SearchNext; Index++) {
/*
* Load it
*/
FilePath = FileDevicePath (DeviceHandle, ShellEnvPathName[Index]);
ASSERT (FilePath);
Status = BS->LoadImage(FALSE, ParentImageHandle, FilePath, NULL, 0, &NewImageHandle);
FreePool (FilePath);
/*
* Only search the next path if it was not found on this path
*/
SearchNext = FALSE;
if (Status == EFI_LOAD_ERROR || Status == EFI_NOT_FOUND) {
SearchNext = TRUE;
}
/*
* If there was no error, start the image
*/
if (!EFI_ERROR(Status)) {
Status = BS->StartImage(NewImageHandle, NULL, 0);
}
}
return Status;
}
EFI_STATUS
ShellLoadEnvDriver (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
EFI_LOADED_IMAGE *Image;
UINTN Index, NoHandles;
EFI_HANDLE *Handles;
/*
* Get the file path for the current image
*/
Status = BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, (VOID*)&Image);
ASSERT (!EFI_ERROR(Status));
/*
* Attempt to load shellenv
*/
Status = ShellLoadEnvDriverByPath (Image->ParentHandle, Image->DeviceHandle);
if (EFI_ERROR(Status)) {
/*
* shellenv was not found. Search all filesystems for it
*/
Status = LibLocateHandle (ByProtocol, &FileSystemProtocol, NULL, &NoHandles, &Handles);
for (Index=0; Index < NoHandles; Index++) {
Status = ShellLoadEnvDriverByPath (Image->ParentHandle, Handles[Index]);
if (!EFI_ERROR(Status)) {
break;
}
}
if (Handles) {
FreePool (Handles);
}
}
/*
* Done
*/
return Status;
}
EFI_STATUS
NShellPrompt (
IN EFI_HANDLE ImageHandle
)
{
CHAR16 CmdLine[256];
CHAR16 *CurDir;
UINTN BufferSize;
EFI_STATUS Status;
/*
* Prompt for input
*/
CurDir = ShellCurDir(NULL);
if (CurDir) {
Print (L"%E%s> ", CurDir);
FreePool (CurDir);
} else {
Print (L"%EShell> ");
}
/*
* Read a line from the console
*/
BufferSize = sizeof(CmdLine)-1;
Status = SI->StdIn->Read (SI->StdIn, &BufferSize, CmdLine);
/*
* Null terminate the string and parse it
*/
if (!EFI_ERROR(Status)) {
CmdLine[BufferSize/sizeof(CHAR16)] = 0;
Status = ShellExecute (ImageHandle, CmdLine, TRUE);
}
/*
* Done with this command
*/
return Status;
}
BOOLEAN
ParseLoadOptions(
EFI_HANDLE ImageHandle,
OUT CHAR16 **CommandLine,
OUT CHAR16 **CurrentDir
)
{
EFI_LOADED_IMAGE *Image;
EFI_STATUS Status;
/*
* Set defaults.
*/
*CommandLine = NULL;
*CurrentDir = NULL;
Status = BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, (VOID*)&Image);
if (!EFI_ERROR(Status)) {
CHAR16 *CmdLine = Image->LoadOptions;
UINT32 CmdSize = Image->LoadOptionsSize & ~1; /* make sure it is power of 2 */
if (CmdLine && CmdSize) {
/*
* Set command line pointer for caller
*/
*CommandLine = CmdLine;
/*
* See if current working directory was passed.
*/
while ((*CmdLine != 0) && CmdSize) {
CmdLine++;
CmdSize -= sizeof(CHAR16);
}
/*
* If a current working directory was passed, set it.
*/
if (CmdSize > sizeof(CHAR16)) {
*CurrentDir = ++CmdLine;
}
return TRUE;
}
}
return FALSE;
}