core/src/pipe_line.cpp
changeset 0 7f656887cf89
child 78 b3ffff030d5c
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // pipe_line.cpp
       
     2 // 
       
     3 // Copyright (c) 2006 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include <fshell/ioutils.h>
       
    14 #include "error.h"
       
    15 #include "pipe_line.h"
       
    16 #include "console.h"
       
    17 #include "command_factory.h"
       
    18 #include "command_wrappers.h"
       
    19 
       
    20 
       
    21 //
       
    22 // RPipeSection.
       
    23 //
       
    24 
       
    25 RPipeSection::TRedirection::TRedirection()
       
    26 	: iType(ENotRedirected), iFileName(NULL), iHandle(EUnknown)
       
    27 	{
       
    28 	}
       
    29 
       
    30 void RPipeSection::TRedirection::SetFileNameL(const TDesC& aCwd, const TDesC& aName)
       
    31 	{
       
    32 	if ((aName == _L("NUL")) || (aName == _L("/dev/null")))
       
    33 		{
       
    34 		iType = ENull;
       
    35 		}
       
    36 	else
       
    37 		{
       
    38 		if (iFileName == NULL)
       
    39 			{
       
    40 			iFileName = new(ELeave) TFileName2();
       
    41 			}
       
    42 		*iFileName = aName;
       
    43 
       
    44 		if (iFileName->Length() > 0)
       
    45 			{
       
    46 			const TUint16 firstChar = (*iFileName)[0];
       
    47 			const TUint16 lastChar = (*iFileName)[iFileName->Length() - 1];
       
    48 			const TUint16 singleQuote = '\'';
       
    49 			const TUint16 doubleQuote = '"';
       
    50 			if (((firstChar == singleQuote) && (lastChar == singleQuote)) || ((firstChar == doubleQuote) && (lastChar == doubleQuote)))
       
    51 				{
       
    52 				// The string is quoted - remove the quotes.
       
    53 				*iFileName = iFileName->Mid(1, iFileName->Length() - 2);
       
    54 				}
       
    55 			}
       
    56 		iFileName->MakeAbsoluteL(aCwd);
       
    57 		}
       
    58 	}
       
    59 
       
    60 RPipeSection::RPipeSection()
       
    61 	: iCommandArguments(5), iCommandArgumentsBuf(NULL)
       
    62 	{
       
    63 	}
       
    64 
       
    65 void RPipeSection::Close()
       
    66 	{
       
    67 	iCommandArguments.Close();
       
    68 	delete iStdinRedirection.iFileName;
       
    69 	delete iStdoutRedirection.iFileName;
       
    70 	delete iStderrRedirection.iFileName;
       
    71 	delete iCommandArgumentsBuf;
       
    72 	iCommandArgumentsBuf = NULL;
       
    73 	}
       
    74 
       
    75 HBufC* RPipeSection::GetCommandArguments() const
       
    76 	{
       
    77 	if (iCommandArgumentsBuf) return iCommandArgumentsBuf;
       
    78 
       
    79 	TInt length = 0;
       
    80 	const TInt numArgs = iCommandArguments.Count();
       
    81 	for (TInt i = 0; i < numArgs; ++i)
       
    82 		{
       
    83 		length += iCommandArguments[i].Length() + 1;
       
    84 		}
       
    85 	iCommandArgumentsBuf = HBufC::New(length);
       
    86 	if (iCommandArgumentsBuf)
       
    87 		{
       
    88 		TPtr ptr(iCommandArgumentsBuf->Des());
       
    89 		for (TInt i = 0; i < numArgs; ++i)
       
    90 			{
       
    91 			ptr.Append(iCommandArguments[i]);
       
    92 			if (i < (numArgs - 1))
       
    93 				{
       
    94 				ptr.Append(_L(" "));
       
    95 				}
       
    96 			}
       
    97 		}
       
    98 	return iCommandArgumentsBuf;
       
    99 	}
       
   100 
       
   101 
       
   102 
       
   103 //
       
   104 // CPipeLine.
       
   105 //
       
   106 
       
   107 CPipeLine* CPipeLine::NewL(RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, const RArray<RPipeSection>& aPipeSections, TBool aBackground, MPipeLineObserver* aObserver, TError& aErrorContext)
       
   108 	{
       
   109 	CPipeLine* self = NewLC(aIoSession, aStdin, aStdout, aStderr, aEnv, aFactory, aPipeSections, aBackground, aObserver, aErrorContext);
       
   110 	CleanupStack::Pop(self);
       
   111 	return self;
       
   112 	}
       
   113 
       
   114 CPipeLine* CPipeLine::NewLC(RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, const RArray<RPipeSection>& aPipeSections, TBool aBackground, MPipeLineObserver* aObserver, TError& aErrorContext)
       
   115 	{
       
   116 	CPipeLine* self = new(ELeave) CPipeLine(aIoSession, aStdin, aStdout, aStderr, aEnv, aFactory, aObserver);
       
   117 	CleanupStack::PushL(self);
       
   118 	self->ConstructL(aPipeSections, aBackground, aErrorContext);
       
   119 	return self;
       
   120 	}
       
   121 
       
   122 CPipeLine::~CPipeLine()
       
   123 	{
       
   124 	const TInt count = iCommands.Count();
       
   125 	for (TInt i = 0; i < count; ++i)
       
   126 		{
       
   127 		iCommands[i].Close();
       
   128 		}
       
   129 	iCommands.Close();
       
   130 	delete iCompletionCallBack;
       
   131 	}
       
   132 
       
   133 void CPipeLine::Kill()
       
   134 	{
       
   135 	const TInt numCommands = iCommands.Count();
       
   136 	for (TInt i = 0; i < numCommands; ++i)
       
   137 		{
       
   138 		MCommand* command = iCommands[i].iCommand;
       
   139 		if (command)
       
   140 			{
       
   141 			command->CmndKill();
       
   142 			}
       
   143 		}
       
   144 	}
       
   145 
       
   146 TInt CPipeLine::Suspend()
       
   147 	{
       
   148 	TInt ret = KErrNone;
       
   149 	const TInt numCommands = iCommands.Count();
       
   150 	for (TInt i = 0; i < numCommands; ++i)
       
   151 		{
       
   152 		MCommand* command = iCommands[i].iCommand;
       
   153 		if (command)
       
   154 			{
       
   155 			TInt err = command->CmndSuspend();
       
   156 			if (err != KErrNone)
       
   157 				{
       
   158 				ret = err;
       
   159 				}
       
   160 			}
       
   161 		}
       
   162 	return ret;
       
   163 	}
       
   164 
       
   165 TInt CPipeLine::Resume()
       
   166 	{
       
   167 	TInt ret = KErrNone;
       
   168 	const TInt numCommands = iCommands.Count();
       
   169 	for (TInt i = 0; i < numCommands; ++i)
       
   170 		{
       
   171 		MCommand* command = iCommands[i].iCommand;
       
   172 		if (command)
       
   173 			{
       
   174 			TInt err = command->CmndResume();
       
   175 			if (err != KErrNone)
       
   176 				{
       
   177 				ret = err;
       
   178 				}
       
   179 			}
       
   180 		}
       
   181 	return ret;
       
   182 	}
       
   183 
       
   184 TInt CPipeLine::BringToForeground()
       
   185 	{
       
   186 	TInt ret = KErrNone;
       
   187 	const TInt numCommands = iCommands.Count();
       
   188 	if (numCommands > 0)
       
   189 		{
       
   190 		MCommand* command = iCommands[0].iCommand;
       
   191 		if (command)
       
   192 			{
       
   193 			ret = command->CmndStdin().SetToForeground();
       
   194 			}
       
   195 		else
       
   196 			{
       
   197 			ret = KErrDied;
       
   198 			}
       
   199 		if (ret == KErrNone)
       
   200 			{
       
   201 			for (TInt i = 0; i < numCommands; ++i)
       
   202 				{
       
   203 				MCommand* command = iCommands[i].iCommand;
       
   204 				if (command)
       
   205 					{
       
   206 					command->CmndForeground();
       
   207 					}
       
   208 				}
       
   209 			}
       
   210 		}
       
   211 	else
       
   212 		{
       
   213 		ret = KErrNotFound;
       
   214 		}
       
   215 	return ret;
       
   216 	}
       
   217 
       
   218 void CPipeLine::SendToBackground()
       
   219 	{
       
   220 	const TInt numCommands = iCommands.Count();
       
   221 	for (TInt i = 0; i < numCommands; ++i)
       
   222 		{
       
   223 		MCommand* command = iCommands[i].iCommand;
       
   224 		if (command)
       
   225 			{
       
   226 			command->CmndBackground();
       
   227 			}
       
   228 		}
       
   229 	}
       
   230 
       
   231 TInt CPipeLine::Reattach(RIoEndPoint& aStdinEndPoint, RIoEndPoint& aStdoutEndPoint, RIoEndPoint& aStderrEndPoint)
       
   232 	{
       
   233 	// Go through the array of pipe-commands attaching them to the new end points where appropriate.
       
   234 	// Note, some commands may have already completed, in which case they can be ignored.
       
   235 	// Also, we have to be careful to only reattach I/O handles that weren't explicitly redirected
       
   236 	// by the user, or by virtue of their position in the pipe-line.
       
   237 
       
   238 	TInt err = KErrNone;
       
   239 	const TInt numCommands = iCommands.Count();
       
   240 	for (TInt i = 0; i < numCommands; ++i)
       
   241 		{
       
   242 		RPipedCommand& pipedCommand = iCommands[i];
       
   243 		if (pipedCommand.iCommand)
       
   244 			{
       
   245 			if ((i == 0) && !pipedCommand.iStdinRedirected)
       
   246 				{
       
   247 				// The first command in the pipe-line whose stdin was not redirected.
       
   248 				err = pipedCommand.iCommand->CmndReattachStdin(aStdinEndPoint);
       
   249 				}
       
   250 			if ((err == KErrNone) && ((i < (numCommands - 1)) || (numCommands == 1)) && !pipedCommand.iStderrRedirected)
       
   251 				{
       
   252 				// A middle command in the pipe-line whose stderr has not been redirected.
       
   253 				err = pipedCommand.iCommand->CmndReattachStderr(aStderrEndPoint);
       
   254 				}
       
   255 			if ((err == KErrNone) && (i == (numCommands - 1)) && !pipedCommand.iStdoutRedirected)
       
   256 				{
       
   257 				// The last command in the pipe-line, whose stdout has not been redirected.
       
   258 				err = pipedCommand.iCommand->CmndReattachStdout(aStdoutEndPoint);
       
   259 				}
       
   260 			}
       
   261 		if (err)
       
   262 			{
       
   263 			break;
       
   264 			}
       
   265 		}
       
   266 	return err;
       
   267 	}
       
   268 
       
   269 TBool CPipeLine::IsDisownable() const
       
   270 	{
       
   271 	const TInt numCommands = iCommands.Count();
       
   272 	for (TInt i = 0; i < numCommands; ++i)
       
   273 		{
       
   274 		const RPipedCommand& pipedCommand = iCommands[i];
       
   275 		if (pipedCommand.iCommand && !pipedCommand.iCommand->CmndIsDisownable())
       
   276 			{
       
   277 			return EFalse;
       
   278 			}
       
   279 		}
       
   280 	return ETrue;
       
   281 	}
       
   282 
       
   283 void CPipeLine::Disown()
       
   284 	{
       
   285 	const TInt numCommands = iCommands.Count();
       
   286 	for (TInt i = 0; i < numCommands; ++i)
       
   287 		{
       
   288 		RPipedCommand& pipedCommand = iCommands[i];
       
   289 		if (pipedCommand.iCommand)
       
   290 			{
       
   291 			pipedCommand.iCommand->CmndDisown();
       
   292 			}
       
   293 		}
       
   294 	}
       
   295 
       
   296 CPipeLine::CPipeLine(RIoSession& aIoSession, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr, IoUtils::CEnvironment& aEnv, CCommandFactory& aFactory, MPipeLineObserver* aObserver)
       
   297 	: iIoSession(aIoSession), iStdin(aStdin), iStdout(aStdout), iStderr(aStderr), iEnv(aEnv), iFactory(aFactory), iObserver(aObserver), iCompletionError(aStderr, aEnv)
       
   298 	{
       
   299 	}
       
   300 
       
   301 void SetIoObjectName(RIoSession& aIoSession, TInt aObjHandle, TRefByValue<const TDesC> aFmt, ...)
       
   302 	{
       
   303 	TOverflowTruncate overflow;
       
   304 	VA_LIST list;
       
   305 	VA_START(list, aFmt);
       
   306 	TFullName name;
       
   307 	name.AppendFormatList(aFmt, list, &overflow);
       
   308 	aIoSession.SetObjectName(aObjHandle, name);
       
   309 	}
       
   310 
       
   311 void CPipeLine::ConstructL(const RArray<RPipeSection>& aPipeSections, TBool aBackground, TError& aErrorContext)
       
   312 	{
       
   313 	// Run the pipe-line in the background even if we weren't explicitly asked to if fshell's
       
   314 	// STDIN read handle isn't in the foreground. This prevents the pipe-line from stealing the
       
   315 	// foreground from whatever has it (normally another instance of fshell running in interactive
       
   316 	// mode).
       
   317 	if (!aBackground && !iStdin.IsForeground())
       
   318 		{
       
   319 		aBackground = ETrue;
       
   320 		}
       
   321 
       
   322 	if (iObserver)
       
   323 		{
       
   324 		iCompletionCallBack = new(ELeave) CAsyncCallBack(TCallBack(CompletionCallBack, this), CActive::EPriorityStandard);
       
   325 		}
       
   326 	
       
   327 	TInt i;
       
   328 	const TInt numPipeSections = aPipeSections.Count();
       
   329 
       
   330 	// Construct the command objects and IO handles.
       
   331 	// Note, all the IO handles are duplicated from the shell's to ensure that the underlying console is correctly set.
       
   332 	// Later redirections may cause some handles to be re-attached to different end points.
       
   333 	for (i = 0; i < numPipeSections; ++i)
       
   334 		{
       
   335 		const RPipeSection& thisPipeSection = aPipeSections[i];
       
   336 		User::LeaveIfError(iCommands.Append(RPipedCommand()));
       
   337 		RPipedCommand& pipedCommand = iCommands[i];
       
   338 		pipedCommand.iCommandName = thisPipeSection.iCommandName.AllocL();
       
   339 		HBufC* args = thisPipeSection.GetCommandArguments();
       
   340 		User::LeaveIfNull(args);
       
   341 		pipedCommand.iCommand = iFactory.CreateCommandL(thisPipeSection.iCommandName, aErrorContext, *args);
       
   342 		User::LeaveIfError(pipedCommand.iCommand->CmndStdin().Create(iIoSession));
       
   343 		User::LeaveIfError(pipedCommand.iCommand->CmndStdin().Duplicate(iStdin));
       
   344 		SetIoObjectName(iIoSession, pipedCommand.iCommand->CmndStdin().SubSessionHandle(), _L("%S_stdin"), &thisPipeSection.iFullName);
       
   345 		User::LeaveIfError(pipedCommand.iCommand->CmndStdout().Create(iIoSession));
       
   346 		User::LeaveIfError(pipedCommand.iCommand->CmndStdout().Duplicate(iStdout));
       
   347 		SetIoObjectName(iIoSession, pipedCommand.iCommand->CmndStdout().SubSessionHandle(), _L("%S_stdout"), &thisPipeSection.iFullName);
       
   348 		User::LeaveIfError(pipedCommand.iCommand->CmndStderr().Create(iIoSession));
       
   349 		User::LeaveIfError(pipedCommand.iCommand->CmndStderr().Duplicate(iStderr));
       
   350 		SetIoObjectName(iIoSession, pipedCommand.iCommand->CmndStderr().SubSessionHandle(), _L("%S_stderr"), &thisPipeSection.iFullName);
       
   351 		}
       
   352 
       
   353 	// Construct pipes.
       
   354 	RArray<RIoPipe> pipes;
       
   355 	CleanupClosePushL(pipes);
       
   356 	for (i = 1; i < numPipeSections; ++i)
       
   357 		{
       
   358 		RIoPipe pipe;
       
   359 		User::LeaveIfError(pipe.Create(iIoSession));
       
   360 		CleanupClosePushL(pipe);
       
   361 		SetIoObjectName(iIoSession, pipe.SubSessionHandle(), _L("%S ==> %S_pipe"), &aPipeSections[i - 1].iFullName, &aPipeSections[i].iFullName);
       
   362 		User::LeaveIfError(pipes.Append(pipe));
       
   363 		}
       
   364 
       
   365 	RIoNull null;
       
   366 	User::LeaveIfError(null.Create(iIoSession));
       
   367 	CleanupClosePushL(null);
       
   368 	SetIoObjectName(iIoSession, null.SubSessionHandle(), _L("null"));
       
   369 
       
   370 	// Connect the pipe-line.
       
   371 	for (i = 0; i < numPipeSections; ++i)
       
   372 		{
       
   373 		const RPipeSection& thisPipeSection = aPipeSections[i];
       
   374 		RPipedCommand& thisPipedCommand = iCommands[i];
       
   375 
       
   376 		switch (thisPipeSection.iStdinRedirection.iType)
       
   377 			{
       
   378 			case RPipeSection::TRedirection::ENotRedirected:
       
   379 				{
       
   380 				if (i == 0)
       
   381 					{
       
   382 					// This is the first pipe section. No wiring to do - already wired to the shell's stdin.
       
   383 					if (!aBackground)
       
   384 						{
       
   385 						User::LeaveIfError(thisPipedCommand.iCommand->CmndStdin().SetToForeground());
       
   386 						}
       
   387 					}
       
   388 				else
       
   389 					{
       
   390 					if (aPipeSections[i - 1].iStdoutRedirection.iType == RPipeSection::TRedirection::ENotRedirected)
       
   391 						{
       
   392 						// Wire intermediate pipe sections input up to the previous one's output via a pipe.
       
   393 						User::LeaveIfError(pipes[i - 1].Attach(thisPipedCommand.iCommand->CmndStdin(), RIoEndPoint::EForeground));
       
   394 						}
       
   395 					else
       
   396 						{
       
   397 						// The previous pipe section's output has been redirected, so attach this pipe section's input to null.
       
   398 						User::LeaveIfError(null.Attach(thisPipedCommand.iCommand->CmndStdin(), RIoEndPoint::EForeground));
       
   399 						}
       
   400 					}
       
   401 				break;
       
   402 				}
       
   403 			case RPipeSection::TRedirection::EFile:
       
   404 				{
       
   405 				RIoFile file;
       
   406 				User::LeaveIfError(file.Create(iIoSession, *thisPipeSection.iStdinRedirection.iFileName, RIoFile::ERead));
       
   407 				CleanupClosePushL(file);
       
   408 				SetIoObjectName(iIoSession, file.SubSessionHandle(), _L("file_%S"), thisPipeSection.iStdinRedirection.iFileName);
       
   409 				User::LeaveIfError(file.Attach(thisPipedCommand.iCommand->CmndStdin(), RIoEndPoint::EForeground));
       
   410 				CleanupStack::PopAndDestroy(&file);
       
   411 				if (i > 0)
       
   412 					{
       
   413 					if (aPipeSections[i - 1].iStdoutRedirection.iType == RPipeSection::TRedirection::ENotRedirected)
       
   414 						{
       
   415 						// Re-wire the previous pipe section's output to null.
       
   416 						User::LeaveIfError(null.Attach(iCommands[i - 1].iCommand->CmndStdout()));
       
   417 						}
       
   418 					}
       
   419 				thisPipedCommand.iStdinRedirected = ETrue;
       
   420 				break;
       
   421 				}
       
   422 			case RPipeSection::TRedirection::ENull:
       
   423 				{
       
   424 				User::LeaveIfError(null.Attach(thisPipedCommand.iCommand->CmndStdin(), RIoEndPoint::EForeground));
       
   425 				if (i > 0)
       
   426 					{
       
   427 					if (aPipeSections[i - 1].iStdoutRedirection.iType == RPipeSection::TRedirection::ENotRedirected)
       
   428 						{
       
   429 						// Re-wire the previous pipe section's output to null.
       
   430 						User::LeaveIfError(null.Attach(iCommands[i - 1].iCommand->CmndStdout()));
       
   431 						}
       
   432 					}
       
   433 				thisPipedCommand.iStdinRedirected = ETrue;
       
   434 				break;
       
   435 				}
       
   436 			case RPipeSection::TRedirection::EHandle:
       
   437 			case RPipeSection::TRedirection::EFileAppend:
       
   438 			default:
       
   439 				{
       
   440 				ASSERT(EFalse);
       
   441 				break;
       
   442 				}
       
   443 			}
       
   444 
       
   445 		switch (thisPipeSection.iStdoutRedirection.iType)
       
   446 			{
       
   447 			case RPipeSection::TRedirection::ENotRedirected:
       
   448 				{
       
   449 				if (i < (numPipeSections - 1))
       
   450 					{
       
   451 					// Attach this pipe section's output to the next one's input via a pipe.
       
   452 					User::LeaveIfError(pipes[i].Attach(thisPipedCommand.iCommand->CmndStdout()));
       
   453 					}
       
   454 				break;
       
   455 				}
       
   456 			case RPipeSection::TRedirection::EFile:
       
   457 			case RPipeSection::TRedirection::EFileAppend:
       
   458 				{
       
   459 				RIoFile file;
       
   460 				User::LeaveIfError(file.Create(iIoSession, *thisPipeSection.iStdoutRedirection.iFileName, (thisPipeSection.iStdoutRedirection.iType == RPipeSection::TRedirection::EFile) ? RIoFile::EOverwrite : RIoFile::EAppend));
       
   461 				CleanupClosePushL(file);
       
   462 				SetIoObjectName(iIoSession, file.SubSessionHandle(), _L("file_%S"), thisPipeSection.iStdoutRedirection.iFileName);
       
   463 				User::LeaveIfError(file.Attach(thisPipedCommand.iCommand->CmndStdout()));
       
   464 				CleanupStack::PopAndDestroy(&file);
       
   465 				thisPipedCommand.iStdoutRedirected = ETrue;
       
   466 				break;
       
   467 				}
       
   468 			case RPipeSection::TRedirection::ENull:
       
   469 				{
       
   470 				User::LeaveIfError(null.Attach(thisPipedCommand.iCommand->CmndStdout()));
       
   471 				thisPipedCommand.iStdoutRedirected = ETrue;
       
   472 				break;
       
   473 				}
       
   474 			case RPipeSection::TRedirection::EHandle:
       
   475 				{
       
   476 				// Handle redirection of stdout to stderr after stderr has been wired up.
       
   477 				thisPipedCommand.iStdoutRedirected = ETrue;
       
   478 				break;
       
   479 				}
       
   480 			default:
       
   481 				{
       
   482 				ASSERT(EFalse);
       
   483 				break;
       
   484 				}
       
   485 			}
       
   486 
       
   487 		switch (thisPipeSection.iStderrRedirection.iType)
       
   488 			{
       
   489 			case RPipeSection::TRedirection::ENotRedirected:
       
   490 				{
       
   491 				// Wire error output directly to the shell's stderr.
       
   492 				User::LeaveIfError(thisPipedCommand.iCommand->CmndStderr().Duplicate(iStderr));
       
   493 				break;
       
   494 				}
       
   495 			case RPipeSection::TRedirection::EFile:
       
   496 			case RPipeSection::TRedirection::EFileAppend:
       
   497 				{
       
   498 				RIoFile file;
       
   499 				User::LeaveIfError(file.Create(iIoSession, *thisPipeSection.iStderrRedirection.iFileName, (thisPipeSection.iStderrRedirection.iType == RPipeSection::TRedirection::EFile) ? RIoFile::EOverwrite : RIoFile::EAppend));
       
   500 				CleanupClosePushL(file);
       
   501 				SetIoObjectName(iIoSession, file.SubSessionHandle(), _L("file_%S"), thisPipeSection.iStderrRedirection.iFileName);
       
   502 				User::LeaveIfError(file.Attach(thisPipedCommand.iCommand->CmndStderr()));
       
   503 				CleanupStack::PopAndDestroy(&file);
       
   504 				thisPipedCommand.iStderrRedirected = ETrue;
       
   505 				break;
       
   506 				}
       
   507 			case RPipeSection::TRedirection::ENull:
       
   508 				{
       
   509 				User::LeaveIfError(null.Attach(thisPipedCommand.iCommand->CmndStderr()));
       
   510 				thisPipedCommand.iStderrRedirected = ETrue;
       
   511 				break;
       
   512 				}
       
   513 			case RPipeSection::TRedirection::EHandle:
       
   514 				{
       
   515 				ASSERT(thisPipeSection.iStderrRedirection.iHandle == RPipeSection::TRedirection::EStdout);
       
   516 				User::LeaveIfError(thisPipedCommand.iCommand->CmndStderr().Duplicate(thisPipedCommand.iCommand->CmndStdout()));
       
   517 				thisPipedCommand.iStderrRedirected = ETrue;
       
   518 				break;
       
   519 				}
       
   520 			default:
       
   521 				{
       
   522 				ASSERT(EFalse);
       
   523 				break;
       
   524 				}
       
   525 			}
       
   526 
       
   527 		if (thisPipeSection.iStdoutRedirection.iType == RPipeSection::TRedirection::EHandle)
       
   528 			{
       
   529 			ASSERT(thisPipeSection.iStdoutRedirection.iHandle == RPipeSection::TRedirection::EStderr);
       
   530 			User::LeaveIfError(thisPipedCommand.iCommand->CmndStdout().Duplicate(thisPipedCommand.iCommand->CmndStderr()));
       
   531 			}
       
   532 		}
       
   533 
       
   534 	// Pipe handles (if any) and null object (if needed) now held open by attached read a write handles.
       
   535 	CleanupStack::PopAndDestroy(&null);
       
   536 	if (numPipeSections > 1)
       
   537 		{
       
   538 		CleanupStack::PopAndDestroy(numPipeSections - 1); // The pipe handles.
       
   539 		}
       
   540 	CleanupStack::PopAndDestroy(&pipes);
       
   541 
       
   542 	// Run the pipe-line.
       
   543 	for (i = 0; i < numPipeSections; ++i)
       
   544 		{
       
   545 		const RPipeSection& thisPipeSection = aPipeSections[i];
       
   546 		RPipedCommand& thisPipedCommand = iCommands[i];
       
   547 		HBufC* args = thisPipeSection.GetCommandArguments();
       
   548 		TInt err = KErrNoMemory;
       
   549 		if (args)
       
   550 			{
       
   551 			err = thisPipedCommand.iCommand->CmndRun(*args, iEnv, *this, iIoSession);
       
   552 			if ((err == KErrNone) && thisPipedCommand.iCommand)
       
   553 				{
       
   554 				aBackground ? thisPipedCommand.iCommand->CmndBackground() : thisPipedCommand.iCommand->CmndForeground();
       
   555 				}
       
   556 			}
       
   557 		if (err)
       
   558 			{
       
   559 			Kill();
       
   560 			aErrorContext.Set(err, TError::EFailedToRunCommand, thisPipeSection.iFullName);
       
   561 			User::Leave(err);
       
   562 			}
       
   563 		}
       
   564 	}
       
   565 
       
   566 TInt CPipeLine::CompletionCallBack(TAny* aSelf)
       
   567 	{
       
   568 	CPipeLine* self = static_cast<CPipeLine*>(aSelf);
       
   569 	self->iCompletionError.Set(self->iCommands[self->iCommands.Count() - 1].iCompletionError, TError::ECommandError);
       
   570 	self->iObserver->HandlePipeLineComplete(*self, self->iCompletionError);
       
   571 	return KErrNone;
       
   572 	}
       
   573 
       
   574 void CPipeLine::HandleCommandComplete(MCommand& aCommand, TInt aError)
       
   575 	{
       
   576 	TBool allNowComplete(ETrue);
       
   577 	const TInt numCommands = iCommands.Count();
       
   578 	for (TInt i = 0; i < numCommands; ++i)
       
   579 		{
       
   580 		RPipedCommand& thisPipedCommand = iCommands[i];
       
   581 		if (thisPipedCommand.iCommand == &aCommand)
       
   582 			{
       
   583 			if (aCommand.CmndExitType() == EExitPanic)
       
   584 				{
       
   585 				_LIT(KFormat, "*** PANIC ***\r\n\tCommand:  \'%S\'\r\n\tCategory: \'%S\'\r\n\tReason:   %d\r\n");
       
   586 				TBuf<256> buf;
       
   587 				TOverflowTruncate overflow;
       
   588 				TExitCategoryName category(aCommand.CmndExitCategory());
       
   589 				buf.AppendFormat(KFormat, &overflow, thisPipedCommand.iCommandName, &category, aError);
       
   590 				iStderr.Write(buf);
       
   591 				if (aError >= 0)
       
   592 					{
       
   593 					// Panicking with KERN-EXEC 0 shouldn't equate to a completionerror of KErrNone!
       
   594 					aError = KErrDied;
       
   595 					}
       
   596 				}
       
   597 			else if (aCommand.CmndExitType() == EExitTerminate)
       
   598 				{
       
   599 				_LIT(KFormat, "Command '%S' terminated with reason %d\r\n");
       
   600 				TBuf<256> buf;
       
   601 				TOverflowTruncate overflow;
       
   602 				buf.AppendFormat(KFormat, &overflow, thisPipedCommand.iCommandName, aError);
       
   603 				iStderr.Write(buf);
       
   604 					if (aError >= 0)
       
   605 					{
       
   606 					// Terminate 0 shouldn't equate to a completionError of KErrNone
       
   607 					aError = KErrDied;
       
   608 					}
       
   609 				}
       
   610 			thisPipedCommand.iCommand->CmndRelease();
       
   611 			thisPipedCommand.iCommand = NULL;
       
   612 			thisPipedCommand.iCompletionError = aError;
       
   613 			}
       
   614 		else if (thisPipedCommand.iCommand)
       
   615 			{
       
   616 			allNowComplete = EFalse;
       
   617 			}
       
   618 		}
       
   619 
       
   620 	if (allNowComplete && iObserver)
       
   621 		{
       
   622 		iCompletionCallBack->CallBack();
       
   623 		}
       
   624 	}
       
   625 
       
   626 
       
   627 //
       
   628 // CPipeLine::RPipedCommand.
       
   629 //
       
   630 
       
   631 CPipeLine::RPipedCommand::RPipedCommand()
       
   632 	: iCommand(NULL), iCompletionError(KErrNone), iCommandName(NULL), iStdinRedirected(EFalse), iStdoutRedirected(EFalse), iStderrRedirected(EFalse)
       
   633 	{
       
   634 	}
       
   635 
       
   636 void CPipeLine::RPipedCommand::Close()
       
   637 	{
       
   638 	if (iCommand)
       
   639 		{
       
   640 		iCommand->CmndKill();
       
   641 		if (iCommand)
       
   642 			{
       
   643 			iCommand->CmndRelease();
       
   644 			iCommand = NULL;
       
   645 			}
       
   646 		}
       
   647 	if (iCommandName)
       
   648 		{
       
   649 		delete iCommandName;
       
   650 		}
       
   651 	}
       
   652