|
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 |