Added sf\3tshell platform with support for building beagle textshell+fshell ROMs.
As part of that:
* Added baserom command and tweaked it to be more friendly with SF baselines.
* Lots of build fixes
Also cd now makes sure the current working directory matches the file system with respect to case.
// command_wrappers.cpp
//
// Copyright (c) 2006 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Accenture - Initial contribution
//
#include "command_wrappers.h"
//
// Constants.
//
const TInt KMaxHeapSize = KMinHeapSize * 1024;
//
// CCommandWrapperBase.
//
CCommandWrapperBase::CCommandWrapperBase()
{
}
CCommandWrapperBase::~CCommandWrapperBase()
{
iStdin.Close();
iStdout.Close();
iStderr.Close();
delete iName;
}
void CCommandWrapperBase::BaseConstructL(const TDesC& aName)
{
iName = aName.AllocL();
}
RIoReadHandle& CCommandWrapperBase::CmndStdin()
{
return iStdin;
}
RIoWriteHandle& CCommandWrapperBase::CmndStdout()
{
return iStdout;
}
RIoWriteHandle& CCommandWrapperBase::CmndStderr()
{
return iStderr;
}
const TDesC& CCommandWrapperBase::CmndName() const
{
return *iName;
}
TInt CCommandWrapperBase::CmndReattachStdin(RIoEndPoint& aStdinEndPoint)
{
TInt isForeground = iStdin.IsForeground();
if (isForeground < 0)
{
return isForeground;
}
return aStdinEndPoint.Attach(iStdin, isForeground ? RIoEndPoint::EForeground : RIoEndPoint::EBackground);
}
TInt CCommandWrapperBase::CmndReattachStdout(RIoEndPoint& aStdoutEndPoint)
{
return aStdoutEndPoint.Attach(iStdout);
}
TInt CCommandWrapperBase::CmndReattachStderr(RIoEndPoint& aStderrEndPoint)
{
return aStderrEndPoint.Attach(iStderr);
}
TBool CCommandWrapperBase::CmndIsDisownable() const
{
return EFalse;
}
void CCommandWrapperBase::CmndDisown()
{
ASSERT(EFalse);
}
void CCommandWrapperBase::CmndRelease()
{
delete this;
}
//
// CThreadCommand.
//
CThreadCommand* CThreadCommand::NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags)
{
CThreadCommand* self = new(ELeave) CThreadCommand(aCommandConstructor, aFlags);
CleanupStack::PushL(self);
self->ConstructL(aName);
CleanupStack::Pop(self);
return self;
}
CThreadCommand::~CThreadCommand()
{
delete iWatcher;
delete iArgs;
iThread.Close();
}
CThreadCommand::CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags)
: iFlags(aFlags), iCommandConstructor(aCommandConstructor)
{
iThread.SetHandle(0); // By default RThread refers to the current thread. This results in fshell's thread exiting if this object gets killed before it has managed to open a real thread handle.
if (iFlags & EUpdateEnvironment) iFlags |= ESharedHeap; // Update environment implies a shared heap, ever since we did away with the explict SwitchAllocator
}
void CThreadCommand::ConstructL(const TDesC& aName)
{
BaseConstructL(aName);
iWatcher = CThreadWatcher::NewL();
}
void CommandThreadStartL(CThreadCommand::TArgs& aArgs)
{
if (aArgs.iFlags & CThreadCommand::ESharedHeap)
{
// If we're sharing the main fshell heap, we have to play by the rules and not crash
User::SetCritical(User::EProcessCritical);
}
CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
HBufC* commandLine = aArgs.iCommandLine.AllocLC();
IoUtils::CEnvironment* env;
if (aArgs.iFlags & CThreadCommand::EUpdateEnvironment)
{
env = aArgs.iEnv.CreateSharedEnvironmentL();
}
else
{
// A straight-forward copy
env = IoUtils::CEnvironment::NewL(aArgs.iEnv);
}
CleanupStack::PushL(env);
CCommandBase* command = (*aArgs.iCommandConstructor)();
RThread parentThread;
User::LeaveIfError(parentThread.Open(aArgs.iParentThreadId));
parentThread.RequestComplete(aArgs.iParentStatus, KErrNone);
parentThread.Close();
command->RunCommandL(commandLine, env);
CleanupStack::PopAndDestroy(4, scheduler); // env, command, commandline, scheduler
}
TInt CommandThreadStart(TAny* aPtr)
{
CThreadCommand::TArgs args = *(CThreadCommand::TArgs*)aPtr;
TBool sharedHeap = (args.iFlags & CThreadCommand::ESharedHeap);
if (!sharedHeap)
{
__UHEAP_MARK;
}
TInt err = KErrNoMemory;
CTrapCleanup* cleanup = CTrapCleanup::New();
if (cleanup)
{
TRAP(err, CommandThreadStartL(args));
delete cleanup;
}
if (!sharedHeap)
{
__UHEAP_MARKEND;
}
return err;
}
void SetHandleOwnersL(TThreadId aThreadId, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr)
{
User::LeaveIfError(aStdin.SetOwner(aThreadId));
User::LeaveIfError(aStdout.SetOwner(aThreadId));
User::LeaveIfError(aStderr.SetOwner(aThreadId));
};
TInt CThreadCommand::CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession&)
{
ASSERT(iObserver == NULL);
TRequestStatus status(KRequestPending);
iArgs = new TArgs(iFlags, aEnv, iCommandConstructor, aCommandLine, status);
if (iArgs == NULL)
{
return KErrNoMemory;
}
TInt i = 0;
TName threadName;
TInt err = KErrNone;
do
{
const TDesC& name = CmndName();
threadName.Format(_L("%S_%02d"), &name, i++);
if (iFlags & ESharedHeap)
{
err = iThread.Create(threadName, CommandThreadStart, KDefaultStackSize, NULL, iArgs);
}
else
{
err = iThread.Create(threadName, CommandThreadStart, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, iArgs);
}
}
while (err == KErrAlreadyExists);
if (err)
{
return err;
}
err = iWatcher->Logon(*this, iThread, aObserver);
if (err)
{
iThread.Kill(0);
iThread.Close();
return err;
}
TThreadId threadId = iThread.Id();
TRAP(err, SetHandleOwnersL(threadId, CmndStdin(), CmndStdout(), CmndStderr()));
if (err)
{
iThread.Kill(0);
iThread.Close();
return err;
}
iThread.Resume();
User::WaitForRequest(status, iWatcher->iStatus);
if (status == KRequestPending)
{
iThread.Close();
return iWatcher->iStatus.Int();
}
iWatcher->SetActive();
iObserver = &aObserver;
return KErrNone;
}
void CThreadCommand::CmndForeground()
{
iThread.SetPriority(EPriorityAbsoluteForeground);
}
void CThreadCommand::CmndBackground()
{
iThread.SetPriority(EPriorityAbsoluteBackground);
}
void CThreadCommand::CmndKill()
{
if (iThread.Handle())
{
iThread.Kill(KErrAbort);
}
}
TInt CThreadCommand::CmndSuspend()
{
iThread.Suspend();
return KErrNone;
}
TInt CThreadCommand::CmndResume()
{
iThread.Resume();
return KErrNone;
}
TExitType CThreadCommand::CmndExitType() const
{
return iThread.ExitType();
}
TExitCategoryName CThreadCommand::CmndExitCategory() const
{
return iThread.ExitCategory();
}
//
// CThreadCommand::TArgs.
//
CThreadCommand::TArgs::TArgs(TUint aFlags, IoUtils::CEnvironment& aEnv, TCommandConstructor aCommandConstructor, const TDesC& aCommandLine, TRequestStatus& aParentStatus)
: iFlags(aFlags), iEnv(aEnv), iCommandConstructor(aCommandConstructor), iCommandLine(aCommandLine), iParentStatus(&aParentStatus), iParentThreadId(RThread().Id())
{
}
//
// CThreadCommand::CThreadWatcher.
//
CThreadCommand::CThreadWatcher* CThreadCommand::CThreadWatcher::NewL()
{
return new(ELeave) CThreadWatcher();
}
CThreadCommand::CThreadWatcher::~CThreadWatcher()
{
Cancel();
}
CThreadCommand::CThreadWatcher::CThreadWatcher()
: CActive(CActive::EPriorityStandard)
{
CActiveScheduler::Add(this);
}
TInt CThreadCommand::CThreadWatcher::Logon(CThreadCommand& aCommand, RThread& aThread, MCommandObserver& aObserver)
{
TInt ret = KErrNone;
aThread.Logon(iStatus);
if (iStatus != KRequestPending)
{
User::WaitForRequest(iStatus);
ret = iStatus.Int();
}
else
{
iCommand = &aCommand;
iThread = &aThread;
iObserver = &aObserver;
}
return ret;
}
void CThreadCommand::CThreadWatcher::SetActive()
{
CActive::SetActive();
}
void CThreadCommand::CThreadWatcher::RunL()
{
iObserver->HandleCommandComplete(*iCommand, iStatus.Int());
}
void CThreadCommand::CThreadWatcher::DoCancel()
{
if (iThread)
{
iThread->LogonCancel(iStatus);
}
}
//
// CProcessCommand.
//
CProcessCommand* CProcessCommand::NewL(const TDesC& aExeName)
{
CProcessCommand* self = new(ELeave) CProcessCommand();
CleanupStack::PushL(self);
self->ConstructL(aExeName);
CleanupStack::Pop(self);
return self;
}
CProcessCommand* CProcessCommand::NewL(const TDesC& aExeName, RProcess& aProcess)
{
CProcessCommand* self = new(ELeave) CProcessCommand();
CleanupStack::PushL(self);
self->ConstructL(aExeName, &aProcess);
CleanupStack::Pop(self);
return self;
}
CProcessCommand::~CProcessCommand()
{
delete iWatcher;
iProcess.Close();
}
CProcessCommand::CProcessCommand()
{
iProcess.SetHandle(KNullHandle); // By default RProcess refers to the current process (KCurrentProcessHandle). This results in fshell's process exiting if this object gets killed before it has managed to open a real process handle.
}
void CProcessCommand::ConstructL(const TDesC& aExeName, RProcess* aProcess)
{
BaseConstructL(aExeName);
iWatcher = CProcessWatcher::NewL();
if (aProcess)
{
// Don't take ownership of the aProcess handle until after everything that can leave has been run
iProcess.SetHandle(aProcess->Handle());
}
}
void CProcessCommand::CreateProcessL(const TDesC& aCommandLine, IoUtils::CEnvironment&)
{
if (iProcess.Handle() == KNullHandle)
{
// Don't create new proc if we were passed one in initially
User::LeaveIfError(iProcess.Create(CmndName(), aCommandLine));
}
}
void CProcessCommand::CmndRunL(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver)
{
CreateProcessL(aCommandLine, aEnv);
HBufC8* envBuf = aEnv.ExternalizeLC();
User::LeaveIfError(iProcess.SetParameter(IoUtils::KEnvironmentProcessSlot, *envBuf));
CleanupStack::PopAndDestroy(envBuf);
TFullName fullName(iProcess.Name());
_LIT(KThreadName,"::Main");
fullName.Append(KThreadName);
RThread thread;
User::LeaveIfError(thread.Open(fullName));
TThreadId threadId(thread.Id());
thread.Close();
User::LeaveIfError(CmndStdin().SetOwner(threadId));
User::LeaveIfError(CmndStdout().SetOwner(threadId));
User::LeaveIfError(CmndStderr().SetOwner(threadId));
TInt err = iWatcher->Logon(*this, iProcess, aObserver);
if (err)
{
iProcess.Kill(0);
}
User::LeaveIfError(err);
iObserver = &aObserver;
iProcess.Resume();
}
TInt CProcessCommand::CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession&)
{
ASSERT(iObserver == NULL);
TRAPD(err, CmndRunL(aCommandLine, aEnv, aObserver));
return err;
}
void CProcessCommand::CmndForeground()
{
iProcess.SetPriority(EPriorityForeground);
}
void CProcessCommand::CmndBackground()
{
iProcess.SetPriority(EPriorityBackground);
}
void CProcessCommand::CmndKill()
{
if (iProcess.Handle())
{
iProcess.Kill(KErrAbort);
}
}
TInt CProcessCommand::CmndSuspend()
{
#ifdef EKA2
// Can't currently support suspend in EKA2 - KERN-EXEC 46 will result.
return KErrNotSupported;
#else
TName processName(iProcess.Name());
processName.Append(_L("::*"));
TFullName threadName;
TFindThread threadFinder(processName);
while (threadFinder.Next(threadName) == KErrNone)
{
RThread thread;
if (thread.Open(threadName) == KErrNone)
{
thread.Suspend();
thread.Close();
}
}
return KErrNone;
#endif
}
TInt CProcessCommand::CmndResume()
{
#ifdef EKA2
// Can't currently support resume in EKA2 - KERN-EXEC 46 will result.
return KErrNotSupported;
#else
TName processName(iProcess.Name());
processName.Append(_L("::*"));
TFullName threadName;
TFindThread threadFinder(processName);
while (threadFinder.Next(threadName) == KErrNone)
{
RThread thread;
if (thread.Open(threadName) == KErrNone)
{
thread.Resume();
thread.Close();
}
}
return KErrNone;
#endif
}
TExitType CProcessCommand::CmndExitType() const
{
return iProcess.ExitType();
}
TExitCategoryName CProcessCommand::CmndExitCategory() const
{
return iProcess.ExitCategory();
}
TBool CProcessCommand::CmndIsDisownable() const
{
return ETrue;
}
void CProcessCommand::CmndDisown()
{
delete iWatcher;
iWatcher = NULL;
iProcess.Close();
}
//
// CProcessCommand::CProcessWatcher.
//
CProcessCommand::CProcessWatcher* CProcessCommand::CProcessWatcher::NewL()
{
return new(ELeave) CProcessWatcher();
}
CProcessCommand::CProcessWatcher::~CProcessWatcher()
{
Cancel();
}
TInt CProcessCommand::CProcessWatcher::Logon(CProcessCommand& aCommand, RProcess& aProcess, MCommandObserver& aObserver)
{
TInt ret = KErrNone;
aProcess.Logon(iStatus);
if (iStatus != KRequestPending)
{
User::WaitForRequest(iStatus);
ret = iStatus.Int();
}
else
{
iCommand = &aCommand;
iProcess = &aProcess;
iObserver = &aObserver;
SetActive();
}
return ret;
}
CProcessCommand::CProcessWatcher::CProcessWatcher()
: CActive(CActive::EPriorityStandard)
{
CActiveScheduler::Add(this);
}
void CProcessCommand::CProcessWatcher::RunL()
{
iObserver->HandleCommandComplete(*iCommand, iStatus.Int());
}
void CProcessCommand::CProcessWatcher::DoCancel()
{
if (iProcess)
{
iProcess->LogonCancel(iStatus);
}
}
//
// CPipsCommand.
//
CPipsCommand* CPipsCommand::NewL(const TDesC& aExeName)
{
CPipsCommand* self = new (ELeave) CPipsCommand();
CleanupStack::PushL(self);
self->ConstructL(aExeName);
CleanupStack::Pop(self);
return self;
}
CPipsCommand::CPipsCommand()
{
}
CPipsCommand::~CPipsCommand()
{
}
TInt CPipsCommand::CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession& aIoSession)
{
TInt err = CProcessCommand::CmndRun(aCommandLine, aEnv, aObserver, aIoSession);
if ((err == KErrNone) && iUsingPipsRun)
{
TRequestStatus status;
iProcess.Rendezvous(status);
User::WaitForRequest(status);
err = status.Int();
if (err > 0)
{
iPipsRunChildProcessId = err;
err = KErrNone;
}
}
return err;
}
void CPipsCommand::CmndKill()
{
CProcessCommand::CmndKill();
if (iUsingPipsRun)
{
RProcess pipsRunChildProcess;
if (pipsRunChildProcess.Open(iPipsRunChildProcessId) == KErrNone)
{
pipsRunChildProcess.Kill(KErrAbort);
pipsRunChildProcess.Close();
}
}
}
void CPipsCommand::CreateProcessL(const TDesC& aCommandLine, IoUtils::CEnvironment&)
{
_LIT(KPipsRunExe, "pipsrun");
TInt err = iProcess.Create(KPipsRunExe, KNullDesC);
if (err == KErrNotFound)
{
// Looks like pipsrun.exe isn't present - just load the PIPS exe directly.
User::LeaveIfError(iProcess.Create(CmndName(), aCommandLine));
}
else
{
User::LeaveIfError(err);
User::LeaveIfError(iProcess.SetParameter(IoUtils::KPipsCommandNameProcessSlot, CmndName()));
User::LeaveIfError(iProcess.SetParameter(IoUtils::KPipsCommandLineProcessSlot, aCommandLine));
iUsingPipsRun = ETrue;
}
}
//
// CAliasCommand.
//
CAliasCommand* CAliasCommand::NewL(MCommand& aAliasedCommand, const TDesC* aAdditionalArguments, const TDesC* aReplacementArguments)
{
CAliasCommand* self = new(ELeave) CAliasCommand(aAliasedCommand);
CleanupStack::PushL(self);
self->ConstructL(aAdditionalArguments, aReplacementArguments);
CleanupStack::Pop(self);
return self;
}
CAliasCommand::~CAliasCommand()
{
delete iAdditionalArguments;
delete iReplacementArguments;
iAliasedCommand.CmndRelease();
}
CAliasCommand::CAliasCommand(MCommand& aAliasedCommand)
: iAliasedCommand(aAliasedCommand)
{
}
void CAliasCommand::ConstructL(const TDesC* aAdditionalArguments, const TDesC* aReplacementArguments)
{
BaseConstructL(iAliasedCommand.CmndName());
if (aAdditionalArguments)
{
iAdditionalArguments = aAdditionalArguments->AllocL();
}
if (aReplacementArguments)
{
iReplacementArguments = aReplacementArguments->AllocL();
}
}
RIoReadHandle& CAliasCommand::CmndStdin()
{
return iAliasedCommand.CmndStdin();
}
RIoWriteHandle& CAliasCommand::CmndStdout()
{
return iAliasedCommand.CmndStdout();
}
RIoWriteHandle& CAliasCommand::CmndStderr()
{
return iAliasedCommand.CmndStderr();
}
TInt CAliasCommand::CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession& aIoSession)
{
if (iAdditionalArguments && !iReplacementArguments)
{
iAdditionalArguments = iAdditionalArguments->ReAlloc(iAdditionalArguments->Length() + aCommandLine.Length() + 1);
if (iAdditionalArguments == NULL)
{
return KErrNoMemory;
}
_LIT(KSpace, " ");
iAdditionalArguments->Des().Append(KSpace);
iAdditionalArguments->Des().Append(aCommandLine);
}
iCommandObserver = &aObserver;
const TDesC* args = &aCommandLine;
if (iReplacementArguments)
{
args = iReplacementArguments;
}
else if (iAdditionalArguments)
{
args = iAdditionalArguments;
}
return iAliasedCommand.CmndRun(*args, aEnv, *this, aIoSession);
}
void CAliasCommand::CmndForeground()
{
iAliasedCommand.CmndForeground();
}
void CAliasCommand::CmndBackground()
{
iAliasedCommand.CmndBackground();
}
void CAliasCommand::CmndKill()
{
iAliasedCommand.CmndKill();
}
TInt CAliasCommand::CmndSuspend()
{
return iAliasedCommand.CmndSuspend();
}
TInt CAliasCommand::CmndResume()
{
return iAliasedCommand.CmndResume();
}
TExitType CAliasCommand::CmndExitType() const
{
return iAliasedCommand.CmndExitType();
}
TExitCategoryName CAliasCommand::CmndExitCategory() const
{
return iAliasedCommand.CmndExitCategory();
}
void CAliasCommand::HandleCommandComplete(MCommand&, TInt aError)
{
iCommandObserver->HandleCommandComplete(*this, aError);
}