commands/cloggerconfig/cloggerconfig.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 0 7f656887cf89
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// 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);
	}