Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// cloggerconfig.cpp
//
// Copyright (c) 2007 - 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 <fshell/ioutils.h>
#include <fshell/clogger.h>
#include <BADESCA.H>
#include <e32msgqueue.h>
using namespace IoUtils;
class CCmdCloggerConfig : public CCommandBase
{
public:
static CCommandBase* NewLC();
~CCmdCloggerConfig();
private:
CCmdCloggerConfig();
void PrintLogL();
void GetBackupFileNameL(TFileName& aName);
void SetAllL(TBool aEnabled);
private: // From CCommandBase.
virtual const TDesC& Name() const;
virtual void DoRunL();
virtual void ArgumentsL(RCommandArgumentList& aArguments);
virtual void OptionsL(RCommandOptionList& aOptions);
private:
RClogger iClogger;
RCloggerLogConsumer iLogGetter;
TUint iGlobalOptions;
TBool iPersist;
TBool iReset;
HBufC* iTagName;
TUint iEnabledMask;
TUint iRotateOptions;
TBool iRotate;
TBool iFollow;
TBool iWipe;
TInt iNumBuffers;
TInt iBufferSize;
RBuf iTempBuffer;
TBool iRdebug;
TBool iBackup;
TBool iRestore;
TBool iDisableAll;
TBool iEnableAll;
};
CCommandBase* CCmdCloggerConfig::NewLC()
{
CCmdCloggerConfig* self = new(ELeave) CCmdCloggerConfig();
CleanupStack::PushL(self);
self->BaseConstructL();
return self;
}
CCmdCloggerConfig::~CCmdCloggerConfig()
{
iClogger.Close();
iLogGetter.Close();
delete iTagName;
iTempBuffer.Close();
}
CCmdCloggerConfig::CCmdCloggerConfig()
{
}
const TDesC& CCmdCloggerConfig::Name() const
{
_LIT(KName, "cloggerconfig");
return KName;
}
#define WRITEIF(opt, flag) if (opt & (RClogger :: flag)) { Write(_L(#flag)); Write(_L(" ")); }
void CCmdCloggerConfig::DoRunL()
{
if (iEnableAll && iDisableAll)
{
LeaveIfErr(KErrArgument, _L("Can't enable and disable all tags"));
}
User::LeaveIfError(iClogger.Connect());
TBool listSettings = ETrue;
if (iReset)
{
iClogger.ResetSettings();
listSettings = EFalse;
}
if (iOptions.IsPresent(&iGlobalOptions))
{
iClogger.SetGlobalOptions(iGlobalOptions);
listSettings = EFalse;
}
if (iOptions.IsPresent(&iRotateOptions))
{
TInt n;
iClogger.GetRotateBehaviour(&n);
iClogger.SetRotateBehaviour(n, iRotateOptions);
listSettings = EFalse;
}
if (iNumBuffers || iBufferSize)
{
if (iNumBuffers == 0)
{
// Need to read it in as we have to set both at once. Bad API...
iClogger.GetRamBufferSize(&iNumBuffers);
}
if (iBufferSize == 0)
{
// Same reason as above
iBufferSize = iClogger.GetRamBufferSize(NULL);
}
iClogger.SetRamBufferSize(iBufferSize, iNumBuffers);
listSettings = EFalse;
}
if (iPersist || iBackup || iRestore)
{
// We don't do anything here, we take action at the end of this function
listSettings = EFalse;
}
if (iRotate)
{
TFileName name;
TInt err = iClogger.Rotate(name);
Printf(_L("Log rotated to %S\r\n"), &name);
if (err) PrintError(err, _L("Rotate returned error"));
listSettings = EFalse;
}
else if (iWipe)
{
TInt oldLogs;
TUint rotopt = iClogger.GetRotateBehaviour(&oldLogs);
iClogger.SetRotateBehaviour(KMaxTInt, RClogger::EDoNothingSpecial); // Change rotate behaviour temporarily
TFileName name;
TInt err = iClogger.Rotate(name);
//Printf(_L("Log rotated to %S\r\n"), &name);
if (err) PrintError(err, _L("Rotate returned error"));
else
{
err = FsL().Delete(name);
iClogger.SetRotateBehaviour(oldLogs, rotopt); // Restore old behaviour
LeaveIfErr(err, _L("Couldn't remove wiped log %S"), &name);
}
listSettings = EFalse;
}
if (iDisableAll)
{
SetAllL(EFalse);
listSettings = EFalse;
}
if (iEnableAll)
{
SetAllL(ETrue);
listSettings = EFalse;
}
if (iRdebug)
{
TUint opts = iClogger.GetGlobalOptions();
opts |= RClogger::ERedirectRDebugPrintToClogger;
iClogger.SetGlobalOptions(opts);
PrintLogL();
}
if (iFollow)
{
PrintLogL(); // Does not return
}
if (iArguments.IsPresent(1))
{
// Set
TInt err = iClogger.SetEnabled(*iTagName, iEnabledMask);
if (err == KErrNotFound)
{
PrintError(err, _L("Tag does not exist, couldn't set it. (NOTE: This behaviour will be changed in the future so you can set tags that haven't been created yet!)"));
User::Leave(KErrNotFound);
}
LeaveIfErr(err, _L("Couldn't enable tag."));
listSettings = EFalse;
}
else if (iArguments.IsPresent(0))
{
// Get
TUint32 e = iClogger.IsEnabled(*iTagName);
Printf(_L("Tag [%S] enabled: 0x%x\r\n"), iTagName, e);
listSettings = EFalse;
}
if (listSettings)
{
// List global options
TUint globalOptions = iClogger.GetGlobalOptions();
Printf(_L("Global options: 0x%x ( "), globalOptions);
if (!globalOptions)
{
Write(_L("None "));
}
else
{
WRITEIF(globalOptions, EBufferLog);
WRITEIF(globalOptions, EMirrorToRDebugPrint);
WRITEIF(globalOptions, EMirrorToBluetooth);
WRITEIF(globalOptions, EMirrorToMessageQueue);
WRITEIF(globalOptions, ERedirectRDebugPrintToClogger);
WRITEIF(globalOptions, EDisableFileWriter);
}
Write(_L(")\r\n"));
// List rotate options
TInt numLogs = 0;
TUint rotateBehaviour = iClogger.GetRotateBehaviour(&numLogs);
Printf(_L("Number of rotated logs to keep: %i\r\n"), numLogs);
Printf(_L("Rotate behaviour: 0x%x ( "), rotateBehaviour);
if (!rotateBehaviour)
{
Write(_L("EDoNothingSpecial "));
}
else
{
WRITEIF(rotateBehaviour, ECopyRotatedToExternalMedia);
WRITEIF(rotateBehaviour, EAutoRotateAtStartup);
WRITEIF(rotateBehaviour, ECompressRotatedLogs);
}
Write(_L(")\r\n"));
// List buffer size
TInt numBuffers = 0;
TInt bufSize = iClogger.GetRamBufferSize(&numBuffers);
Printf(_L("Number of RAM buffers: %i\r\n"), numBuffers);
Printf(_L("Size of RAM buffers: %i\r\n"), bufSize);
// List tags
CDesC16Array* tags = NULL;
RBuf8 enabled;
iClogger.GetTagStatesL(tags, enabled);
TInt count = enabled.Size() / 4;
if (count) Printf(_L("\r\n"));
for (TInt i = 0; i < count; i++)
{
TPtrC tag = tags->operator[](i);
TUint32 e = ((TUint32*)enabled.Ptr())[i];
Printf(_L("Tag [%S] enabled: 0x%x\r\n"), &tag, e);
}
delete tags;
enabled.Close();
}
if (iPersist)
{
iClogger.PersistSettings();
}
if (iBackup)
{
// Args should be: --exec 'cp -ro C:\Private\10202be9\persists\10272efd.cre E:\Private\10202be9\persists\10272efd.cre'
TFileName args;
GetBackupFileNameL(args);
TInt len = args.Length();
args.Append(args);
args.Append('\'');
args[0] = 'C';
args.Insert(len, _L(" "));
args.Insert(0, _L("--exec 'cp -ro "));
RChildProcess shell;
shell.CreateL(_L("fshell.exe"), args, IoSession(), Stdin(), Stdout(), Stderr());
CleanupClosePushL(shell);
TRequestStatus stat;
shell.Run(stat);
User::WaitForRequest(stat);
LeaveIfErr(stat.Int(), _L("Failed to copy cenrep file"));
CleanupStack::PopAndDestroy(&shell);
const TPtrC name = args.Right(len+1);
Printf(_L("Settings backed up to '%S, use --restore option to restore.\r\n"), &name);
}
else if (iRestore)
{
TFileName args;
GetBackupFileNameL(args);
TInt len = args.Length();
//TEntry e;
//LeaveIfErr(FsL().Entry(args, e), _L("No backup file found"));
// Args should be: --exec 'cp E:\Private\10202be9\persists\10272efd.cre C:\Private\10202be9\persists\10272efd.cre'
args.Append(args);
args.Append('\'');
args[len] = 'C';
args.Insert(len, _L(" "));
args.Insert(0, _L("--exec 'cp -ro "));
RChildProcess shell;
shell.CreateL(_L("fshell.exe"), args, IoSession(), Stdin(), Stdout(), Stderr());
CleanupClosePushL(shell);
TRequestStatus stat;
shell.Run(stat);
User::WaitForRequest(stat);
LeaveIfErr(stat.Int(), _L("Failed to copy cenrep file"));
CleanupStack::PopAndDestroy(&shell);
Printf(_L("Settings restored. You must reboot or restart cloggerserver to get the new settings\r\n"));
}
}
void CCmdCloggerConfig::ArgumentsL(RCommandArgumentList& aArguments)
{
aArguments.AppendStringL(iTagName, _L("tag_name"));
aArguments.AppendUintL(iEnabledMask, _L("enabled_mask"));
}
void CCmdCloggerConfig::OptionsL(RCommandOptionList& aOptions)
{
aOptions.AppendUintL(iGlobalOptions, _L("set-global"));
aOptions.AppendBoolL(iPersist, _L("persist"));
aOptions.AppendBoolL(iReset, _L("reset"));
aOptions.AppendUintL(iRotateOptions, _L("set-rotate"));
aOptions.AppendBoolL(iRotate, _L("rotate"));
aOptions.AppendBoolL(iFollow, _L("follow"));
aOptions.AppendIntL(iNumBuffers, _L("num-buffers"));
aOptions.AppendUintL((TUint&)iBufferSize, _L("buffer-size"));
aOptions.AppendBoolL(iWipe, _L("wipe"));
aOptions.AppendBoolL(iRdebug, _L("rdebug"));
aOptions.AppendBoolL(iBackup, _L("backup"));
aOptions.AppendBoolL(iRestore, _L("restore"));
aOptions.AppendBoolL(iDisableAll, _L("disable-all"));
aOptions.AppendBoolL(iEnableAll, _L("enable-all"));
}
EXE_BOILER_PLATE(CCmdCloggerConfig)
void CCmdCloggerConfig::PrintLogL()
{
// Because of how RCloggerLogConsumer API works we can only 'see' things in the clogger ChunkForBufs. This however
// won't be where the descriptor being logged will be unless buffered logging is enabled. To fix properly,
// the rdebug chunk would need to be mapped into the client, and also the Server's iSessionTempBuf and
// CDebugRouterClient's iTempBuf would need to be moved to an accessible chunk
TUint opts = iClogger.GetGlobalOptions();
opts |= RClogger::EBufferLog;
iClogger.SetGlobalOptions(opts);
LeaveIfErr(iLogGetter.Connect(), _L("Couldn't connect to RCloggerLogConsumer"));
iTempBuffer.CreateL(2048);
TRequestStatus stat;
TPtrC8 logLine;
while (ETrue)
{
iLogGetter.GetNextLog(stat, logLine);
User::WaitForRequest(stat);
LeaveIfErr(stat.Int(), _L("GetNextLog returned error"));
// CCommandBase::Write doesn't take 8-bit descriptor so write in iTempBuffer-sized chunks
TPtrC8 lineFrag(logLine);
const TInt buflen = iTempBuffer.MaxLength();
while (lineFrag.Length())
{
TPtrC8 frag = lineFrag.Left(buflen);
iTempBuffer.Copy(frag);
//HexDumpL(frag, iTempBuffer);
TInt err = Stdout().Write(iTempBuffer);
LeaveIfErr(err, _L("Write of %d bytes (%d total) failed"), iTempBuffer.Length(), logLine.Length());
lineFrag.Set(lineFrag.Mid(frag.Length()));
}
}
}
void CCmdCloggerConfig::GetBackupFileNameL(TFileName& aName)
{
TInt err = KErrNone;
TInt theDrive = KErrNotFound;
// Figure out the first external media device
for (TInt drive = EDriveA; drive <= EDriveZ; drive++)
{
TVolumeInfo info;
err = FsL().Volume(info, drive);
if (err == KErrNone)
{
//LogNote(ELogDisks, _L8("Found drive %c iDrivaAtt=0x%x iType=0x%x"), 'A' + drive, info.iDrive.iDriveAtt, info.iDrive.iType);
}
if (err == KErrNone && ((info.iDrive.iDriveAtt & KDriveAttRemovable) || info.iDrive.iType == EMediaHardDisk)) // Added the check for hard disk so we can use _epoc_drive_d in the emulator
{
// Found one
theDrive = drive;
break;
}
}
LeaveIfErr(theDrive, _L("Couldn't find a removable drive to backup on to"));
aName = _L("?:\\private\\10202be9\\persists\\10272efd.cre");
TChar c;
Fs().DriveToChar(theDrive, c);
aName[0] = c;
}
void CCmdCloggerConfig::SetAllL(TBool aEnabled)
{
CDesC16Array* tags = NULL;
RBuf8 states;
CleanupClosePushL(states);
iClogger.GetTagStatesL(tags, states);
CleanupStack::PushL(tags);
if (aEnabled)
{
states.Fill(TChar(0xff));
}
else
{
states.FillZ();
}
iClogger.SetTagStatesL(tags, states);
CleanupStack::PopAndDestroy(2, &states);
}