VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestProcessImpl.cpp@ 45482

Last change on this file since 45482 was 45482, checked in by vboxsync, 12 years ago

GuestCtrl: Added abstract IGuestProcessIOEvent event, removed duplicate code, making the testdriver execution tests pass.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.3 KB
Line 
1
2/* $Id: GuestProcessImpl.cpp 45482 2013-04-11 11:11:42Z vboxsync $ */
3/** @file
4 * VirtualBox Main - Guest process handling.
5 */
6
7/*
8 * Copyright (C) 2012-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/**
20 * Locking rules:
21 * - When the main dispatcher (callbackDispatcher) is called it takes the
22 * WriteLock while dispatching to the various on* methods.
23 * - All other outer functions (accessible by Main) must not own a lock
24 * while waiting for a callback or for an event.
25 * - Only keep Read/WriteLocks as short as possible and only when necessary.
26 */
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "GuestErrorInfoImpl.h"
32#include "GuestProcessImpl.h"
33#include "GuestSessionImpl.h"
34#include "GuestCtrlImplPrivate.h"
35#include "ConsoleImpl.h"
36#include "VBoxEvents.h"
37
38#include "Global.h"
39#include "AutoCaller.h"
40
41#include <memory> /* For auto_ptr. */
42
43#include <iprt/asm.h>
44#include <iprt/cpp/utils.h> /* For unconst(). */
45#include <iprt/getopt.h>
46
47#include <VBox/com/array.h>
48
49#ifdef LOG_GROUP
50 #undef LOG_GROUP
51#endif
52#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
53#include <VBox/log.h>
54
55
56class GuestProcessTask
57{
58public:
59
60 GuestProcessTask(GuestProcess *pProcess)
61 : mProcess(pProcess),
62 mRC(VINF_SUCCESS) { }
63
64 virtual ~GuestProcessTask(void) { }
65
66 int rc(void) const { return mRC; }
67 bool isOk(void) const { return RT_SUCCESS(mRC); }
68 const ComObjPtr<GuestProcess> &Process(void) const { return mProcess; }
69
70protected:
71
72 const ComObjPtr<GuestProcess> mProcess;
73 int mRC;
74};
75
76class GuestProcessStartTask : public GuestProcessTask
77{
78public:
79
80 GuestProcessStartTask(GuestProcess *pProcess)
81 : GuestProcessTask(pProcess) { }
82};
83
84// constructor / destructor
85/////////////////////////////////////////////////////////////////////////////
86
87DEFINE_EMPTY_CTOR_DTOR(GuestProcess)
88
89HRESULT GuestProcess::FinalConstruct(void)
90{
91 LogFlowThisFuncEnter();
92 return BaseFinalConstruct();
93}
94
95void GuestProcess::FinalRelease(void)
96{
97 LogFlowThisFuncEnter();
98 uninit();
99 BaseFinalRelease();
100 LogFlowThisFuncLeave();
101}
102
103// public initializer/uninitializer for internal purposes only
104/////////////////////////////////////////////////////////////////////////////
105
106int GuestProcess::init(Console *aConsole, GuestSession *aSession,
107 ULONG aProcessID, const GuestProcessStartupInfo &aProcInfo)
108{
109 LogFlowThisFunc(("aConsole=%p, aSession=%p, aProcessID=%RU32\n",
110 aConsole, aSession, aProcessID));
111
112 AssertPtrReturn(aConsole, VERR_INVALID_POINTER);
113 AssertPtrReturn(aSession, VERR_INVALID_POINTER);
114
115 /* Enclose the state transition NotReady->InInit->Ready. */
116 AutoInitSpan autoInitSpan(this);
117 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
118
119#ifndef VBOX_WITH_GUEST_CONTROL
120 autoInitSpan.setSucceeded();
121 return VINF_SUCCESS;
122#else
123 int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */);
124 if (RT_SUCCESS(vrc))
125 {
126 unconst(mEventSource).createObject();
127 Assert(!mEventSource.isNull());
128 HRESULT hr = mEventSource->init(static_cast<IGuestProcess*>(this));
129 if (FAILED(hr))
130 vrc = VERR_COM_UNEXPECTED;
131 }
132
133 if (RT_SUCCESS(vrc))
134 {
135 mData.mProcess = aProcInfo;
136 mData.mExitCode = 0;
137 mData.mPID = 0;
138 mData.mRC = VINF_SUCCESS;
139 mData.mStatus = ProcessStatus_Undefined;
140 /* Everything else will be set by the actual starting routine. */
141
142 /* Confirm a successful initialization when it's the case. */
143 autoInitSpan.setSucceeded();
144
145 return vrc;
146 }
147
148 autoInitSpan.setFailed();
149 return vrc;
150#endif
151}
152
153/**
154 * Uninitializes the instance.
155 * Called from FinalRelease().
156 */
157void GuestProcess::uninit(void)
158{
159 LogFlowThisFunc(("mCmd=%s, PID=%RU32\n",
160 mData.mProcess.mCommand.c_str(), mData.mPID));
161
162 /* Enclose the state transition Ready->InUninit->NotReady. */
163 AutoUninitSpan autoUninitSpan(this);
164 if (autoUninitSpan.uninitDone())
165 return;
166
167 int vrc = VINF_SUCCESS;
168
169#ifdef VBOX_WITH_GUEST_CONTROL
170 unconst(mEventSource).setNull();
171#endif
172
173 LogFlowFuncLeaveRC(vrc);
174}
175
176// implementation of public getters/setters for attributes
177/////////////////////////////////////////////////////////////////////////////
178
179STDMETHODIMP GuestProcess::COMGETTER(Arguments)(ComSafeArrayOut(BSTR, aArguments))
180{
181#ifndef VBOX_WITH_GUEST_CONTROL
182 ReturnComNotImplemented();
183#else
184 LogFlowThisFuncEnter();
185
186 CheckComArgOutSafeArrayPointerValid(aArguments);
187
188 AutoCaller autoCaller(this);
189 if (FAILED(autoCaller.rc())) return autoCaller.rc();
190
191 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
192
193 com::SafeArray<BSTR> collection(mData.mProcess.mArguments.size());
194 size_t s = 0;
195 for (ProcessArguments::const_iterator it = mData.mProcess.mArguments.begin();
196 it != mData.mProcess.mArguments.end();
197 it++, s++)
198 {
199 Bstr tmp = *it;
200 tmp.cloneTo(&collection[s]);
201 }
202
203 collection.detachTo(ComSafeArrayOutArg(aArguments));
204
205 return S_OK;
206#endif /* VBOX_WITH_GUEST_CONTROL */
207}
208
209STDMETHODIMP GuestProcess::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))
210{
211#ifndef VBOX_WITH_GUEST_CONTROL
212 ReturnComNotImplemented();
213#else
214 LogFlowThisFuncEnter();
215
216 CheckComArgOutSafeArrayPointerValid(aEnvironment);
217
218 AutoCaller autoCaller(this);
219 if (FAILED(autoCaller.rc())) return autoCaller.rc();
220
221 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
222
223 com::SafeArray<BSTR> arguments(mData.mProcess.mEnvironment.Size());
224 for (size_t i = 0; i < arguments.size(); i++)
225 {
226 Bstr tmp = mData.mProcess.mEnvironment.Get(i);
227 tmp.cloneTo(&arguments[i]);
228 }
229 arguments.detachTo(ComSafeArrayOutArg(aEnvironment));
230
231 return S_OK;
232#endif /* VBOX_WITH_GUEST_CONTROL */
233}
234
235STDMETHODIMP GuestProcess::COMGETTER(EventSource)(IEventSource ** aEventSource)
236{
237#ifndef VBOX_WITH_GUEST_CONTROL
238 ReturnComNotImplemented();
239#else
240 LogFlowThisFuncEnter();
241
242 CheckComArgOutPointerValid(aEventSource);
243
244 AutoCaller autoCaller(this);
245 if (FAILED(autoCaller.rc())) return autoCaller.rc();
246
247 // no need to lock - lifetime constant
248 mEventSource.queryInterfaceTo(aEventSource);
249
250 LogFlowFuncLeaveRC(S_OK);
251 return S_OK;
252#endif /* VBOX_WITH_GUEST_CONTROL */
253}
254
255STDMETHODIMP GuestProcess::COMGETTER(ExecutablePath)(BSTR *aExecutablePath)
256{
257#ifndef VBOX_WITH_GUEST_CONTROL
258 ReturnComNotImplemented();
259#else
260 LogFlowThisFuncEnter();
261
262 CheckComArgOutPointerValid(aExecutablePath);
263
264 AutoCaller autoCaller(this);
265 if (FAILED(autoCaller.rc())) return autoCaller.rc();
266
267 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
268
269 mData.mProcess.mCommand.cloneTo(aExecutablePath);
270
271 return S_OK;
272#endif /* VBOX_WITH_GUEST_CONTROL */
273}
274
275STDMETHODIMP GuestProcess::COMGETTER(ExitCode)(LONG *aExitCode)
276{
277#ifndef VBOX_WITH_GUEST_CONTROL
278 ReturnComNotImplemented();
279#else
280 LogFlowThisFuncEnter();
281
282 CheckComArgOutPointerValid(aExitCode);
283
284 AutoCaller autoCaller(this);
285 if (FAILED(autoCaller.rc())) return autoCaller.rc();
286
287 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
288
289 *aExitCode = mData.mExitCode;
290
291 return S_OK;
292#endif /* VBOX_WITH_GUEST_CONTROL */
293}
294
295STDMETHODIMP GuestProcess::COMGETTER(Name)(BSTR *aName)
296{
297#ifndef VBOX_WITH_GUEST_CONTROL
298 ReturnComNotImplemented();
299#else
300 LogFlowThisFuncEnter();
301
302 CheckComArgOutPointerValid(aName);
303
304 AutoCaller autoCaller(this);
305 if (FAILED(autoCaller.rc())) return autoCaller.rc();
306
307 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
308
309 mData.mProcess.mName.cloneTo(aName);
310
311 return S_OK;
312#endif /* VBOX_WITH_GUEST_CONTROL */
313}
314
315STDMETHODIMP GuestProcess::COMGETTER(PID)(ULONG *aPID)
316{
317#ifndef VBOX_WITH_GUEST_CONTROL
318 ReturnComNotImplemented();
319#else
320 LogFlowThisFuncEnter();
321
322 CheckComArgOutPointerValid(aPID);
323
324 AutoCaller autoCaller(this);
325 if (FAILED(autoCaller.rc())) return autoCaller.rc();
326
327 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
328
329 *aPID = mData.mPID;
330
331 return S_OK;
332#endif /* VBOX_WITH_GUEST_CONTROL */
333}
334
335STDMETHODIMP GuestProcess::COMGETTER(Status)(ProcessStatus_T *aStatus)
336{
337#ifndef VBOX_WITH_GUEST_CONTROL
338 ReturnComNotImplemented();
339#else
340 LogFlowThisFuncEnter();
341
342 AutoCaller autoCaller(this);
343 if (FAILED(autoCaller.rc())) return autoCaller.rc();
344
345 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
346
347 *aStatus = mData.mStatus;
348
349 return S_OK;
350#endif /* VBOX_WITH_GUEST_CONTROL */
351}
352
353// private methods
354/////////////////////////////////////////////////////////////////////////////
355
356int GuestProcess::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
357{
358 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
359 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
360#ifdef DEBUG
361 LogFlowThisFunc(("uPID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
362 mData.mPID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
363#endif
364
365 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
366
367 int vrc;
368 switch (pCbCtx->uFunction)
369 {
370 case GUEST_DISCONNECTED:
371 {
372 vrc = onGuestDisconnected(pCbCtx, pSvcCb);
373 break;
374 }
375
376 case GUEST_EXEC_STATUS:
377 {
378 vrc = onProcessStatusChange(pCbCtx, pSvcCb);
379 break;
380 }
381
382 case GUEST_EXEC_OUTPUT:
383 {
384 vrc = onProcessOutput(pCbCtx, pSvcCb);
385 break;
386 }
387
388 case GUEST_EXEC_INPUT_STATUS:
389 {
390 vrc = onProcessInputStatus(pCbCtx, pSvcCb);
391 break;
392 }
393
394 default:
395 /* Silently ignore not implemented functions. */
396 vrc = VERR_NOT_SUPPORTED;
397 break;
398 }
399
400#ifdef DEBUG
401 LogFlowFuncLeaveRC(vrc);
402#endif
403 return vrc;
404}
405
406/**
407 * Checks if the current assigned PID matches another PID (from a callback).
408 *
409 * In protocol v1 we don't have the possibility to terminate/kill
410 * processes so it can happen that a formerly started process A
411 * (which has the context ID 0 (session=0, process=0, count=0) will
412 * send a delayed message to the host if this process has already
413 * been discarded there and the same context ID was reused by
414 * a process B. Process B in turn then has a different guest PID.
415 *
416 * @return IPRT status code.
417 * @param uPID PID to check.
418 */
419inline int GuestProcess::checkPID(uint32_t uPID)
420{
421 /* Was there a PID assigned yet? */
422 if (mData.mPID)
423 {
424 /*
425
426 */
427 if (mSession->getProtocolVersion() < 2)
428 {
429 /* Simply ignore the stale requests. */
430 return (mData.mPID == uPID)
431 ? VINF_SUCCESS : VERR_NOT_FOUND;
432 }
433#ifndef DEBUG_andy
434 /* This should never happen! */
435 AssertReleaseMsg(mData.mPID == uPID, ("Unterminated guest process (PID %RU32) sent data to a newly started process (PID %RU32)\n",
436 uPID, mData.mPID));
437#endif
438 }
439
440 return VINF_SUCCESS;
441}
442
443/* static */
444Utf8Str GuestProcess::guestErrorToString(int guestRc)
445{
446 Utf8Str strError;
447
448 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
449 switch (guestRc)
450 {
451 case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
452 strError += Utf8StrFmt(tr("The specified file was not found on guest"));
453 break;
454
455 case VERR_INVALID_VM_HANDLE:
456 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
457 break;
458
459 case VERR_HGCM_SERVICE_NOT_FOUND:
460 strError += Utf8StrFmt(tr("The guest execution service is not available"));
461 break;
462
463 case VERR_PATH_NOT_FOUND:
464 strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
465 break;
466
467 case VERR_BAD_EXE_FORMAT:
468 strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
469 break;
470
471 case VERR_AUTHENTICATION_FAILURE:
472 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
473 break;
474
475 case VERR_INVALID_NAME:
476 strError += Utf8StrFmt(tr("The specified file is an invalid name"));
477 break;
478
479 case VERR_TIMEOUT:
480 strError += Utf8StrFmt(tr("The guest did not respond within time"));
481 break;
482
483 case VERR_CANCELLED:
484 strError += Utf8StrFmt(tr("The execution operation was canceled"));
485 break;
486
487 case VERR_PERMISSION_DENIED:
488 strError += Utf8StrFmt(tr("Invalid user/password credentials"));
489 break;
490
491 case VERR_MAX_PROCS_REACHED:
492 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
493 break;
494
495 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
496 strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
497 break;
498
499 case VERR_NOT_FOUND:
500 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
501 break;
502
503 default:
504 strError += Utf8StrFmt("%Rrc", guestRc);
505 break;
506 }
507
508 return strError;
509}
510
511inline bool GuestProcess::isAlive(void)
512{
513 return ( mData.mStatus == ProcessStatus_Started
514 || mData.mStatus == ProcessStatus_Paused
515 || mData.mStatus == ProcessStatus_Terminating);
516}
517
518bool GuestProcess::isReady(void)
519{
520 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
521
522 if (mData.mStatus == ProcessStatus_Started)
523 {
524 Assert(mData.mPID); /* PID must not be 0. */
525 return true;
526 }
527
528 return false;
529}
530
531int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
532{
533 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
534 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
535
536 LogFlowThisFunc(("uPID=%RU32\n", mData.mPID));
537
538 int vrc = setProcessStatus(ProcessStatus_Down, VINF_SUCCESS);
539
540 LogFlowFuncLeaveRC(vrc);
541 return vrc;
542}
543
544int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
545{
546 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
547 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
548 /* pCallback is optional. */
549
550 if (pSvcCbData->mParms < 5)
551 return VERR_INVALID_PARAMETER;
552
553 CALLBACKDATA_PROC_INPUT dataCb;
554 /* pSvcCb->mpaParms[0] always contains the context ID. */
555 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
556 AssertRCReturn(vrc, vrc);
557 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus);
558 AssertRCReturn(vrc, vrc);
559 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
560 AssertRCReturn(vrc, vrc);
561 vrc = pSvcCbData->mpaParms[4].getUInt32(&dataCb.uProcessed);
562 AssertRCReturn(vrc, vrc);
563
564 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32\n",
565 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed));
566
567 vrc = checkPID(dataCb.uPID);
568 AssertRCReturn(vrc, vrc);
569
570 ProcessInputStatus_T inputStatus = ProcessInputStatus_Undefined;
571 switch (dataCb.uStatus)
572 {
573 case INPUT_STS_WRITTEN:
574 inputStatus = ProcessInputStatus_Written;
575 break;
576 case INPUT_STS_ERROR:
577 inputStatus = ProcessInputStatus_Broken;
578 break;
579 case INPUT_STS_TERMINATED:
580 inputStatus = ProcessInputStatus_Broken;
581 break;
582 case INPUT_STS_OVERFLOW:
583 inputStatus = ProcessInputStatus_Overflow;
584 break;
585 case INPUT_STS_UNDEFINED:
586 /* Fall through is intentional. */
587 default:
588 AssertMsg(!dataCb.uProcessed, ("Processed data is not 0 in undefined input state\n"));
589 break;
590 }
591
592 if (inputStatus != ProcessInputStatus_Undefined)
593 {
594 fireGuestProcessInputNotifyEvent(mEventSource, mSession, this,
595 mData.mPID, 0 /* StdIn */, dataCb.uProcessed, inputStatus);
596 }
597
598 LogFlowFuncLeaveRC(vrc);
599 return vrc;
600}
601
602int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
603{
604 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
605 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
606
607 return VERR_NOT_IMPLEMENTED;
608}
609
610int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
611{
612 /* pCallback is optional. */
613 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
614
615 if (pSvcCbData->mParms < 5)
616 return VERR_INVALID_PARAMETER;
617
618 CALLBACKDATA_PROC_STATUS dataCb;
619 /* pSvcCb->mpaParms[0] always contains the context ID. */
620 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
621 AssertRCReturn(vrc, vrc);
622 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus);
623 AssertRCReturn(vrc, vrc);
624 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
625 AssertRCReturn(vrc, vrc);
626 vrc = pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
627 AssertRCReturn(vrc, vrc);
628
629 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32\n",
630 dataCb.uPID, dataCb.uStatus, dataCb.uFlags));
631
632 vrc = checkPID(dataCb.uPID);
633 AssertRCReturn(vrc, vrc);
634
635 ProcessStatus_T procStatus = ProcessStatus_Undefined;
636 int procRc = VINF_SUCCESS;
637
638 switch (dataCb.uStatus)
639 {
640 case PROC_STS_STARTED:
641 {
642 procStatus = ProcessStatus_Started;
643 mData.mPID = dataCb.uPID; /* Set the process PID. */
644 break;
645 }
646
647 case PROC_STS_TEN:
648 {
649 procStatus = ProcessStatus_TerminatedNormally;
650 mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */
651 break;
652 }
653
654 case PROC_STS_TES:
655 {
656 procStatus = ProcessStatus_TerminatedSignal;
657 mData.mExitCode = dataCb.uFlags; /* Contains the signal. */
658 break;
659 }
660
661 case PROC_STS_TEA:
662 {
663 procStatus = ProcessStatus_TerminatedAbnormally;
664 break;
665 }
666
667 case PROC_STS_TOK:
668 {
669 procStatus = ProcessStatus_TimedOutKilled;
670 break;
671 }
672
673 case PROC_STS_TOA:
674 {
675 procStatus = ProcessStatus_TimedOutAbnormally;
676 break;
677 }
678
679 case PROC_STS_DWN:
680 {
681 procStatus = ProcessStatus_Down;
682 break;
683 }
684
685 case PROC_STS_ERROR:
686 {
687 procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */
688 procStatus = ProcessStatus_Error;
689 break;
690 }
691
692 case PROC_STS_UNDEFINED:
693 default:
694 {
695 /* Silently skip this request. */
696 procStatus = ProcessStatus_Undefined;
697 break;
698 }
699 }
700
701 LogFlowThisFunc(("Got rc=%Rrc, procSts=%ld, procRc=%Rrc\n",
702 vrc, procStatus, procRc));
703
704 /* Set the process status. */
705 int rc2 = setProcessStatus(procStatus, procRc);
706 if (RT_SUCCESS(vrc))
707 vrc = rc2;
708
709 LogFlowFuncLeaveRC(vrc);
710 return vrc;
711}
712
713int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
714{
715 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
716
717 if (pSvcCbData->mParms < 5)
718 return VERR_INVALID_PARAMETER;
719
720 CALLBACKDATA_PROC_OUTPUT dataCb;
721 /* pSvcCb->mpaParms[0] always contains the context ID. */
722 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
723 AssertRCReturn(vrc, vrc);
724 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uHandle);
725 AssertRCReturn(vrc, vrc);
726 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
727 AssertRCReturn(vrc, vrc);
728 vrc = pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
729 AssertRCReturn(vrc, vrc);
730
731 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32\n",
732 dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData));
733
734 vrc = checkPID(dataCb.uPID);
735 AssertRCReturn(vrc, vrc);
736
737 com::SafeArray<BYTE> data((size_t)dataCb.cbData);
738 data.initFrom((BYTE*)dataCb.pvData, dataCb.cbData);
739
740 fireGuestProcessOutputEvent(mEventSource, mSession, this,
741 mData.mPID, dataCb.uHandle, dataCb.cbData, ComSafeArrayAsInParam(data));
742
743 LogFlowFuncLeaveRC(vrc);
744 return vrc;
745}
746
747int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
748 void *pvData, size_t cbData, uint32_t *pcbRead, int *pGuestRc)
749{
750 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n",
751 mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc));
752 AssertReturn(uSize, VERR_INVALID_PARAMETER);
753 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
754 AssertReturn(cbData >= uSize, VERR_INVALID_PARAMETER);
755 /* pcbRead is optional. */
756
757 /** @todo Validate uHandle. */
758
759 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
760
761 if (mData.mStatus != ProcessStatus_Started)
762 {
763 if (pcbRead)
764 *pcbRead = 0;
765 if (pGuestRc)
766 *pGuestRc = VINF_SUCCESS;
767 return VINF_SUCCESS; /* Nothing to read anymore. */
768 }
769
770 uint32_t uContextID;
771 int vrc = generateContextID(mSession->getId(), mObjectID,
772 &uContextID);
773 if (RT_SUCCESS(vrc))
774 {
775 VBOXHGCMSVCPARM paParms[8];
776 int i = 0;
777 paParms[i++].setUInt32(uContextID);
778 paParms[i++].setUInt32(mData.mPID);
779 paParms[i++].setUInt32(uHandle);
780 paParms[i++].setUInt32(0 /* Flags, none set yet. */);
781
782 vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms);
783 }
784
785 if (RT_SUCCESS(vrc))
786 {
787 alock.release(); /* Drop the write lock before waiting. */
788
789 vrc = waitForOutput(uHandle, uTimeoutMS,
790 pvData, cbData, pcbRead);
791 }
792
793 LogFlowFuncLeaveRC(vrc);
794 return vrc;
795}
796
797/* Does not do locking; caller is responsible for that! */
798int GuestProcess::setProcessStatus(ProcessStatus_T procStatus, int procRc)
799{
800 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, procRc=%Rrc\n",
801 mData.mStatus, procStatus, procRc));
802
803 if (procStatus == ProcessStatus_Error)
804 {
805 AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc));
806 /* Do not allow overwriting an already set error. If this happens
807 * this means we forgot some error checking/locking somewhere. */
808 //AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
809 }
810 else
811 AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
812
813 if (mData.mStatus != procStatus)
814 {
815 mData.mStatus = procStatus;
816 mData.mRC = procRc;
817
818 ComObjPtr<GuestErrorInfo> errorInfo;
819 HRESULT hr = errorInfo.createObject();
820 ComAssertComRC(hr);
821 if (RT_FAILURE(mData.mRC))
822 {
823 int rc2 = errorInfo->init(mData.mRC, guestErrorToString(mData.mRC));
824 AssertRC(rc2);
825 }
826
827 fireGuestProcessStateChangedEvent(mEventSource, mSession, this,
828 mData.mPID, mData.mStatus, errorInfo);
829 }
830
831 return VINF_SUCCESS;
832}
833
834/* static */
835HRESULT GuestProcess::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
836{
837 AssertPtr(pInterface);
838 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
839
840 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str());
841}
842
843int GuestProcess::startProcess(int *pGuestRc)
844{
845 LogFlowThisFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n",
846 mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags));
847
848 /* Wait until the caller function (if kicked off by a thread)
849 * has returned and continue operation. */
850 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
851
852 mData.mStatus = ProcessStatus_Starting;
853
854 uint32_t uContextID;
855 int vrc = generateContextID(mSession->getId(), mObjectID,
856 &uContextID);
857 if (RT_SUCCESS(vrc))
858 {
859 GuestSession *pSession = mSession;
860 AssertPtr(pSession);
861
862 const GuestCredentials &sessionCreds = pSession->getCredentials();
863
864 /* Prepare arguments. */
865 char *pszArgs = NULL;
866 size_t cArgs = mData.mProcess.mArguments.size();
867 if (cArgs >= UINT32_MAX)
868 vrc = VERR_BUFFER_OVERFLOW;
869
870 if ( RT_SUCCESS(vrc)
871 && cArgs)
872 {
873 char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
874 AssertReturn(papszArgv, VERR_NO_MEMORY);
875
876 for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
877 {
878 const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
879 AssertPtr(pszCurArg);
880 vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
881 }
882 papszArgv[cArgs] = NULL;
883
884 if (RT_SUCCESS(vrc))
885 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
886
887 if (papszArgv)
888 {
889 size_t i = 0;
890 while (papszArgv[i])
891 RTStrFree(papszArgv[i++]);
892 RTMemFree(papszArgv);
893 }
894 }
895
896 /* Calculate arguments size (in bytes). */
897 size_t cbArgs = 0;
898 if (RT_SUCCESS(vrc))
899 cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
900
901 /* Prepare environment. */
902 void *pvEnv = NULL;
903 size_t cbEnv = 0;
904 if (RT_SUCCESS(vrc))
905 vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
906
907 if (RT_SUCCESS(vrc))
908 {
909 AssertPtr(mSession);
910 uint32_t uProtocol = mSession->getProtocolVersion();
911
912 /* Prepare HGCM call. */
913 VBOXHGCMSVCPARM paParms[16];
914 int i = 0;
915 paParms[i++].setUInt32(uContextID);
916 paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
917 (ULONG)mData.mProcess.mCommand.length() + 1);
918 paParms[i++].setUInt32(mData.mProcess.mFlags);
919 paParms[i++].setUInt32(mData.mProcess.mArguments.size());
920 paParms[i++].setPointer((void*)pszArgs, cbArgs);
921 paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size());
922 paParms[i++].setUInt32(cbEnv);
923 paParms[i++].setPointer((void*)pvEnv, cbEnv);
924 if (uProtocol < 2)
925 {
926 /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
927 * call. In newer protocols these credentials are part of the opened guest
928 * session, so not needed anymore here. */
929 paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
930 paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
931 }
932 /*
933 * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
934 * until the process was started - the process itself then gets an infinite timeout for execution.
935 * This is handy when we want to start a process inside a worker thread within a certain timeout
936 * but let the started process perform lengthly operations then.
937 */
938 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
939 paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
940 else
941 paParms[i++].setUInt32(mData.mProcess.mTimeoutMS);
942 if (uProtocol >= 2)
943 {
944 paParms[i++].setUInt32(mData.mProcess.mPriority);
945 /* CPU affinity: We only support one CPU affinity block at the moment,
946 * so that makes up to 64 CPUs total. This can be more in the future. */
947 paParms[i++].setUInt32(1);
948 /* The actual CPU affinity blocks. */
949 paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
950 }
951
952 /* Note: Don't hold the write lock in here. */
953 vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
954 if (RT_FAILURE(vrc))
955 {
956 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
957 AssertRC(rc2);
958 }
959 }
960
961 GuestEnvironment::FreeEnvironmentBlock(pvEnv);
962 if (pszArgs)
963 RTStrFree(pszArgs);
964
965 uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
966
967 /* Drop the write lock again before waiting. */
968 alock.release();
969
970 if (RT_SUCCESS(vrc))
971 {
972 vrc = waitForStatusChange(ProcessWaitForFlag_Start, 30 * 1000 /* Timeout */,
973 NULL /* Process status */, pGuestRc);
974 }
975 }
976
977 LogFlowFuncLeaveRC(vrc);
978 return vrc;
979}
980
981int GuestProcess::startProcessAsync(void)
982{
983 LogFlowThisFuncEnter();
984
985 int vrc;
986
987 try
988 {
989 /* Asynchronously start the process on the guest by kicking off a
990 * worker thread. */
991 std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
992 AssertReturn(pTask->isOk(), pTask->rc());
993
994 vrc = RTThreadCreate(NULL, GuestProcess::startProcessThread,
995 (void *)pTask.get(), 0,
996 RTTHREADTYPE_MAIN_WORKER, 0,
997 "gctlPrcStart");
998 if (RT_SUCCESS(vrc))
999 {
1000 /* pTask is now owned by startProcessThread(), so release it. */
1001 pTask.release();
1002 }
1003 }
1004 catch(std::bad_alloc &)
1005 {
1006 vrc = VERR_NO_MEMORY;
1007 }
1008
1009 LogFlowFuncLeaveRC(vrc);
1010 return vrc;
1011}
1012
1013/* static */
1014DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser)
1015{
1016 LogFlowFunc(("pvUser=%p\n", pvUser));
1017
1018 std::auto_ptr<GuestProcessStartTask> pTask(static_cast<GuestProcessStartTask*>(pvUser));
1019 AssertPtr(pTask.get());
1020
1021 const ComObjPtr<GuestProcess> pProcess(pTask->Process());
1022 Assert(!pProcess.isNull());
1023
1024 AutoCaller autoCaller(pProcess);
1025 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1026
1027 int vrc = pProcess->startProcess(NULL /* Guest rc, ignored */);
1028 /* Nothing to do here anymore. */
1029
1030 LogFlowFuncLeaveRC(vrc);
1031 return vrc;
1032}
1033
1034int GuestProcess::terminateProcess(int *pGuestRc)
1035{
1036 LogFlowThisFuncEnter();
1037
1038 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1039
1040 AssertPtr(mSession);
1041 if (mSession->getProtocolVersion() < 99)
1042 return VERR_NOT_SUPPORTED;
1043
1044 if (mData.mStatus != ProcessStatus_Started)
1045 return VINF_SUCCESS; /* Nothing to do (anymore). */
1046
1047 uint32_t uContextID;
1048 int vrc = generateContextID(mSession->getId(), mObjectID,
1049 &uContextID);
1050 if (RT_SUCCESS(vrc))
1051 {
1052 VBOXHGCMSVCPARM paParms[4];
1053 int i = 0;
1054 paParms[i++].setUInt32(uContextID);
1055 paParms[i++].setUInt32(mData.mPID);
1056
1057 vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
1058 }
1059
1060 if (RT_SUCCESS(vrc))
1061 {
1062 alock.release(); /* Drop the write lock before waiting. */
1063
1064 vrc = waitForStatusChange(ProcessWaitForFlag_Terminate,
1065 30 * 1000 /* 30s timeout */,
1066 NULL /* ProcessStatus */, pGuestRc);
1067 }
1068
1069 LogFlowFuncLeaveRC(vrc);
1070 return vrc;
1071}
1072
1073int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc)
1074{
1075 LogFlowThisFuncEnter();
1076
1077 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
1078
1079 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
1080 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/
1081
1082 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1083
1084 /* Did some error occur before? Then skip waiting and return. */
1085 if (mData.mStatus == ProcessStatus_Error)
1086 {
1087 waitResult = ProcessWaitResult_Error;
1088 AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mRC));
1089 if (pGuestRc)
1090 *pGuestRc = mData.mRC; /* Return last set error. */
1091 return VERR_GSTCTL_GUEST_ERROR;
1092 }
1093
1094 waitResult = ProcessWaitResult_None;
1095 if ( (fWaitFlags & ProcessWaitForFlag_Terminate)
1096 || (fWaitFlags & ProcessWaitForFlag_StdIn)
1097 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1098 || (fWaitFlags & ProcessWaitForFlag_StdErr))
1099 {
1100 switch (mData.mStatus)
1101 {
1102 case ProcessStatus_TerminatedNormally:
1103 case ProcessStatus_TerminatedSignal:
1104 case ProcessStatus_TerminatedAbnormally:
1105 case ProcessStatus_Down:
1106 waitResult = ProcessWaitResult_Terminate;
1107 break;
1108
1109 case ProcessStatus_TimedOutKilled:
1110 case ProcessStatus_TimedOutAbnormally:
1111 waitResult = ProcessWaitResult_Timeout;
1112 break;
1113
1114 case ProcessStatus_Error:
1115 /* Handled above. */
1116 break;
1117
1118 case ProcessStatus_Started:
1119 {
1120 /*
1121 * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the
1122 * caller is not interested in getting further process statuses -- so just don't notify
1123 * anything here anymore and return.
1124 */
1125 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1126 waitResult = ProcessWaitResult_Start;
1127 break;
1128 }
1129
1130 case ProcessStatus_Undefined:
1131 case ProcessStatus_Starting:
1132 /* Do the waiting below. */
1133 break;
1134
1135 default:
1136 AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus));
1137 return VERR_NOT_IMPLEMENTED;
1138 }
1139 }
1140 else if (fWaitFlags & ProcessWaitForFlag_Start)
1141 {
1142 switch (mData.mStatus)
1143 {
1144 case ProcessStatus_Started:
1145 case ProcessStatus_Paused:
1146 case ProcessStatus_Terminating:
1147 case ProcessStatus_TerminatedNormally:
1148 case ProcessStatus_TerminatedSignal:
1149 case ProcessStatus_TerminatedAbnormally:
1150 case ProcessStatus_Down:
1151 waitResult = ProcessWaitResult_Start;
1152 break;
1153
1154 case ProcessStatus_Error:
1155 waitResult = ProcessWaitResult_Error;
1156 break;
1157
1158 case ProcessStatus_TimedOutKilled:
1159 case ProcessStatus_TimedOutAbnormally:
1160 waitResult = ProcessWaitResult_Timeout;
1161 break;
1162
1163 case ProcessStatus_Undefined:
1164 case ProcessStatus_Starting:
1165 /* Do the waiting below. */
1166 break;
1167
1168 default:
1169 AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus));
1170 return VERR_NOT_IMPLEMENTED;
1171 }
1172 }
1173
1174 /* Filter out waits which are *not* supported using
1175 * older guest control Guest Additions.
1176 *
1177 ** @todo ProcessWaitForFlag_Std* flags are not implemented yet.
1178 */
1179 if (mSession->getProtocolVersion() < 99)
1180 {
1181 if ( waitResult == ProcessWaitResult_None
1182 /* We don't support waiting for stdin, out + err,
1183 * just skip waiting then. */
1184 && ( (fWaitFlags & ProcessWaitForFlag_StdIn)
1185 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1186 || (fWaitFlags & ProcessWaitForFlag_StdErr)
1187 )
1188 )
1189 {
1190 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
1191 waitResult = ProcessWaitResult_WaitFlagNotSupported;
1192 }
1193 }
1194
1195 LogFlowThisFunc(("procStatus=%ld, procRc=%Rrc, waitResult=%ld\n",
1196 mData.mStatus, mData.mRC, waitResult));
1197
1198 /* No waiting needed? Return immediately using the last set error. */
1199 if (waitResult != ProcessWaitResult_None)
1200 {
1201 if (pGuestRc)
1202 *pGuestRc = mData.mRC; /* Return last set error (if any). */
1203 return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR;
1204 }
1205
1206 alock.release(); /* Release lock before waiting. */
1207
1208 ProcessStatus_T processStatus;
1209 int vrc = waitForStatusChange(fWaitFlags, uTimeoutMS, &processStatus, pGuestRc);
1210 if (RT_SUCCESS(vrc))
1211 {
1212 switch (processStatus)
1213 {
1214 case ProcessStatus_Started:
1215 waitResult = ProcessWaitResult_Start;
1216 break;
1217
1218 case ProcessStatus_TerminatedNormally:
1219 case ProcessStatus_TerminatedAbnormally:
1220 case ProcessStatus_TerminatedSignal:
1221 waitResult = ProcessWaitResult_Terminate;
1222 break;
1223
1224 case ProcessStatus_TimedOutKilled:
1225 case ProcessStatus_TimedOutAbnormally:
1226 waitResult = ProcessWaitResult_Timeout;
1227 break;
1228
1229 case ProcessStatus_Down:
1230 waitResult = ProcessWaitResult_Terminate;
1231 break;
1232
1233 case ProcessStatus_Error:
1234 waitResult = ProcessWaitResult_Error;
1235 break;
1236
1237 default:
1238 waitResult = ProcessWaitResult_Status;
1239 break;
1240 }
1241 }
1242
1243 LogFlowFuncLeaveRC(vrc);
1244 return vrc;
1245}
1246
1247int GuestProcess::waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents),
1248 VBoxEventType_T *pType, IEvent **ppEvent)
1249{
1250 AssertPtrReturn(pType, VERR_INVALID_POINTER);
1251 AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
1252
1253 int vrc;
1254
1255 /** @todo Parameter validation. */
1256
1257 com::SafeArray <VBoxEventType_T> arrEventTypes(ComSafeArrayInArg(pEvents));
1258
1259 ComPtr<IEventListener> pListener;
1260 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
1261 if (SUCCEEDED(hr))
1262 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(arrEventTypes),
1263 FALSE /* Passive listener */);
1264 else
1265 vrc = VERR_COM_UNEXPECTED;
1266
1267 if (SUCCEEDED(hr))
1268 {
1269 LogFlowThisFunc(("Waiting for guest file event(s) (timeout=%RU32ms, %zu events) ...\n",
1270 uTimeoutMS, arrEventTypes.size()));
1271
1272 vrc = VINF_SUCCESS;
1273
1274 uint64_t u64Started = RTTimeMilliTS();
1275 bool fSignalled = false;
1276 do
1277 {
1278 unsigned cMsWait;
1279 if (uTimeoutMS == RT_INDEFINITE_WAIT)
1280 cMsWait = 1000;
1281 else
1282 {
1283 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
1284 if (cMsElapsed >= uTimeoutMS)
1285 break; /* timed out */
1286 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
1287 }
1288
1289 ComPtr<IEvent> pThisEvent;
1290 hr = mEventSource->GetEvent(pListener, cMsWait, pThisEvent.asOutParam());
1291 if ( SUCCEEDED(hr)
1292 && !pThisEvent.isNull())
1293 {
1294 VBoxEventType_T type;
1295 hr = pThisEvent->COMGETTER(Type)(&type);
1296 ComAssertComRC(hr);
1297
1298 for (size_t i = 0; i < arrEventTypes.size() && !fSignalled; i++)
1299 {
1300 if (type == arrEventTypes[i])
1301 {
1302 switch (type)
1303 {
1304 case VBoxEventType_OnGuestProcessStateChanged:
1305 case VBoxEventType_OnGuestProcessInputNotify:
1306 case VBoxEventType_OnGuestProcessOutput:
1307 {
1308 ComPtr<IGuestProcessEvent> pFileEvent = pThisEvent;
1309 Assert(!pFileEvent.isNull());
1310
1311 ComPtr<IGuestProcess> pProcess;
1312 pFileEvent->COMGETTER(Process)(pProcess.asOutParam());
1313 Assert(!pProcess.isNull());
1314
1315 fSignalled = (pProcess == this);
1316 break;
1317 }
1318
1319 default:
1320 AssertMsgFailed(("Unhandled event %ld\n", type));
1321 break;
1322 }
1323
1324 if (fSignalled)
1325 {
1326 if (pType)
1327 *pType = type;
1328 if (ppEvent)
1329 pThisEvent.queryInterfaceTo(ppEvent);
1330 if ( type == VBoxEventType_OnGuestProcessStateChanged
1331 && RT_SUCCESS(vrc))
1332 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1333 break;
1334 }
1335 }
1336 }
1337 }
1338
1339 } while (!fSignalled);
1340
1341 if ( RT_SUCCESS(vrc)
1342 && !fSignalled)
1343 {
1344 vrc = VERR_TIMEOUT;
1345 }
1346
1347 hr = mEventSource->UnregisterListener(pListener);
1348 ComAssertComRC(hr);
1349 }
1350 else
1351 vrc = VERR_COM_UNEXPECTED;
1352
1353 LogFlowFuncLeaveRC(vrc);
1354 return vrc;
1355}
1356
1357int GuestProcess::waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS,
1358 ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed)
1359{
1360 VBoxEventType_T evtType;
1361 ComPtr<IEvent> pEvent;
1362 com::SafeArray<VBoxEventType_T> eventTypes;
1363 eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
1364 int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
1365 &evtType, pEvent.asOutParam());
1366 if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
1367 {
1368 Assert(evtType == VBoxEventType_OnGuestProcessInputNotify);
1369 ComPtr<IGuestProcessInputNotifyEvent> pProcessEvent = pEvent;
1370 Assert(!pProcessEvent.isNull());
1371
1372 if (pInputStatus)
1373 {
1374 HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus);
1375 ComAssertComRC(hr2);
1376 }
1377 if (pcbProcessed)
1378 {
1379 HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed);
1380 ComAssertComRC(hr2);
1381 }
1382 }
1383
1384 LogFlowFuncLeaveRC(vrc);
1385 return vrc;
1386}
1387
1388int GuestProcess::waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS,
1389 void *pvData, size_t cbData, uint32_t *pcbRead)
1390{
1391 VBoxEventType_T evtType;
1392 ComPtr<IEvent> pEvent;
1393 com::SafeArray<VBoxEventType_T> eventTypes;
1394
1395 int vrc = VINF_SUCCESS;
1396
1397 try
1398 {
1399 eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
1400 }
1401 catch (std::bad_alloc)
1402 {
1403 vrc = VERR_NO_MEMORY;
1404 }
1405
1406 if (RT_FAILURE(vrc))
1407 return vrc;
1408
1409 do
1410 {
1411 vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
1412 &evtType, pEvent.asOutParam());
1413 if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
1414 {
1415 Assert(evtType == VBoxEventType_OnGuestProcessOutput);
1416 ComPtr<IGuestProcessOutputEvent> pProcessEvent = pEvent;
1417 Assert(!pProcessEvent.isNull());
1418
1419 ULONG uHandleEvent;
1420 HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent);
1421 if (uHandleEvent == uHandle)
1422 {
1423 if (pvData)
1424 {
1425 com::SafeArray <BYTE> data;
1426 hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1427 ComAssertComRC(hr);
1428 size_t cbRead = data.size();
1429 if ( cbRead
1430 && cbRead <= cbData)
1431 {
1432 memcpy(pvData, data.raw(), data.size());
1433 }
1434 else
1435 vrc = VERR_BUFFER_OVERFLOW;
1436 }
1437 if (pcbRead)
1438 {
1439 hr = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbRead);
1440 ComAssertComRC(hr);
1441 }
1442
1443 break;
1444 }
1445 }
1446
1447 } while (RT_SUCCESS(vrc));
1448
1449 LogFlowFuncLeaveRC(vrc);
1450 return vrc;
1451}
1452
1453int GuestProcess::waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS,
1454 ProcessStatus_T *pProcessStatus, int *pGuestRc)
1455{
1456 /* All pointers are optional. */
1457
1458 VBoxEventType_T evtType;
1459 ComPtr<IEvent> pEvent;
1460 com::SafeArray<VBoxEventType_T> eventTypes(1);
1461 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1462 int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
1463 &evtType, pEvent.asOutParam());
1464 if (RT_SUCCESS(vrc)) /* Includes VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
1465 {
1466 Assert(evtType == VBoxEventType_OnGuestProcessStateChanged);
1467 ComPtr<IGuestProcessStateChangedEvent> pProcessEvent = pEvent;
1468 Assert(!pProcessEvent.isNull());
1469
1470 HRESULT hr;
1471 if (pProcessStatus)
1472 {
1473 hr = pProcessEvent->COMGETTER(Status)(pProcessStatus);
1474 ComAssertComRC(hr);
1475 }
1476
1477 ComPtr<IGuestErrorInfo> errorInfo;
1478 hr = pProcessEvent->COMGETTER(Error)(errorInfo.asOutParam());
1479 ComAssertComRC(hr);
1480
1481 LONG lGuestRc;
1482 hr = errorInfo->COMGETTER(Result)(&lGuestRc);
1483 ComAssertComRC(hr);
1484 if (RT_FAILURE((int)lGuestRc))
1485 vrc = VERR_GSTCTL_GUEST_ERROR;
1486
1487 if (pGuestRc)
1488 *pGuestRc = (int)lGuestRc;
1489 }
1490
1491 LogFlowFuncLeaveRC(vrc);
1492 return vrc;
1493}
1494
1495int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
1496 void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc)
1497{
1498 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p, pGuestRc=%p\n",
1499 mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten, pGuestRc));
1500 /* All is optional. There can be 0 byte writes. */
1501
1502 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1503
1504 if (mData.mStatus != ProcessStatus_Started)
1505 {
1506 if (puWritten)
1507 *puWritten = 0;
1508 if (pGuestRc)
1509 *pGuestRc = VINF_SUCCESS;
1510 return VINF_SUCCESS; /* Not available for writing (anymore). */
1511 }
1512
1513 uint32_t uContextID;
1514 int vrc = generateContextID(mSession->getId(), mObjectID,
1515 &uContextID);
1516 if (RT_SUCCESS(vrc))
1517 {
1518 VBOXHGCMSVCPARM paParms[5];
1519
1520 int i = 0;
1521 paParms[i++].setUInt32(uContextID);
1522 paParms[i++].setUInt32(mData.mPID);
1523 paParms[i++].setUInt32(uFlags);
1524 paParms[i++].setPointer(pvData, cbData);
1525 paParms[i++].setUInt32(cbData);
1526
1527 vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
1528 }
1529
1530 if (RT_SUCCESS(vrc))
1531 {
1532 alock.release(); /* Drop the write lock before waiting. */
1533
1534 ProcessInputStatus_T inputStatus;
1535 uint32_t cbProcessed;
1536 vrc = waitForInputNotify(uHandle, uTimeoutMS, &inputStatus, &cbProcessed);
1537 if (RT_SUCCESS(vrc))
1538 {
1539 /** @todo Set guestRc. */
1540
1541 if (puWritten)
1542 *puWritten = cbProcessed;
1543 }
1544 /** @todo Error handling. */
1545 }
1546
1547 LogFlowFuncLeaveRC(vrc);
1548 return vrc;
1549}
1550
1551// implementation of public methods
1552/////////////////////////////////////////////////////////////////////////////
1553
1554STDMETHODIMP GuestProcess::Read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1555{
1556#ifndef VBOX_WITH_GUEST_CONTROL
1557 ReturnComNotImplemented();
1558#else
1559 if (aToRead == 0)
1560 return setError(E_INVALIDARG, tr("The size to read is zero"));
1561 CheckComArgOutSafeArrayPointerValid(aData);
1562
1563 AutoCaller autoCaller(this);
1564 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1565
1566 com::SafeArray<BYTE> data((size_t)aToRead);
1567 Assert(data.size() >= aToRead);
1568
1569 HRESULT hr = S_OK;
1570
1571 uint32_t cbRead; int guestRc;
1572 int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead, &guestRc);
1573 if (RT_SUCCESS(vrc))
1574 {
1575 if (data.size() != cbRead)
1576 data.resize(cbRead);
1577 data.detachTo(ComSafeArrayOutArg(aData));
1578 }
1579 else
1580 {
1581 switch (vrc)
1582 {
1583 case VERR_GSTCTL_GUEST_ERROR:
1584 hr = GuestProcess::setErrorExternal(this, guestRc);
1585 break;
1586
1587 default:
1588 hr = setError(VBOX_E_IPRT_ERROR,
1589 tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
1590 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1591 break;
1592 }
1593 }
1594
1595 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64\n", vrc, cbRead));
1596
1597 LogFlowFuncLeaveRC(vrc);
1598 return hr;
1599#endif /* VBOX_WITH_GUEST_CONTROL */
1600}
1601
1602STDMETHODIMP GuestProcess::Terminate(void)
1603{
1604#ifndef VBOX_WITH_GUEST_CONTROL
1605 ReturnComNotImplemented();
1606#else
1607 LogFlowThisFuncEnter();
1608
1609 AutoCaller autoCaller(this);
1610 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1611
1612 HRESULT hr = S_OK;
1613
1614 int guestRc;
1615 int vrc = terminateProcess(&guestRc);
1616 if (RT_FAILURE(vrc))
1617 {
1618 switch (vrc)
1619 {
1620 case VERR_GSTCTL_GUEST_ERROR:
1621 hr = GuestProcess::setErrorExternal(this, guestRc);
1622 break;
1623
1624 case VERR_NOT_SUPPORTED:
1625 hr = setError(VBOX_E_IPRT_ERROR,
1626 tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"),
1627 mData.mProcess.mCommand.c_str(), mData.mPID);
1628 break;
1629
1630 default:
1631 hr = setError(VBOX_E_IPRT_ERROR,
1632 tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"),
1633 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1634 break;
1635 }
1636 }
1637
1638 AssertPtr(mSession);
1639 mSession->processRemoveFromList(this);
1640
1641 /*
1642 * Release autocaller before calling uninit.
1643 */
1644 autoCaller.release();
1645
1646 uninit();
1647
1648 LogFlowFuncLeaveRC(vrc);
1649 return hr;
1650#endif /* VBOX_WITH_GUEST_CONTROL */
1651}
1652
1653STDMETHODIMP GuestProcess::WaitFor(ULONG aWaitFlags, ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1654{
1655#ifndef VBOX_WITH_GUEST_CONTROL
1656 ReturnComNotImplemented();
1657#else
1658 LogFlowThisFuncEnter();
1659
1660 CheckComArgOutPointerValid(aReason);
1661
1662 AutoCaller autoCaller(this);
1663 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1664
1665 /*
1666 * Note: Do not hold any locks here while waiting!
1667 */
1668 HRESULT hr = S_OK;
1669
1670 int guestRc; ProcessWaitResult_T waitResult;
1671 int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc);
1672 if (RT_SUCCESS(vrc))
1673 {
1674 *aReason = waitResult;
1675 }
1676 else
1677 {
1678 switch (vrc)
1679 {
1680 case VERR_GSTCTL_GUEST_ERROR:
1681 hr = GuestProcess::setErrorExternal(this, guestRc);
1682 break;
1683
1684 case VERR_TIMEOUT:
1685 *aReason = ProcessWaitResult_Timeout;
1686 break;
1687
1688 default:
1689 hr = setError(VBOX_E_IPRT_ERROR,
1690 tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
1691 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1692 break;
1693 }
1694 }
1695
1696 LogFlowFuncLeaveRC(vrc);
1697 return hr;
1698#endif /* VBOX_WITH_GUEST_CONTROL */
1699}
1700
1701STDMETHODIMP GuestProcess::WaitForArray(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1702{
1703#ifndef VBOX_WITH_GUEST_CONTROL
1704 ReturnComNotImplemented();
1705#else
1706 LogFlowThisFuncEnter();
1707
1708 CheckComArgOutPointerValid(aReason);
1709
1710 AutoCaller autoCaller(this);
1711 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1712
1713 /*
1714 * Note: Do not hold any locks here while waiting!
1715 */
1716 uint32_t fWaitFor = ProcessWaitForFlag_None;
1717 com::SafeArray<ProcessWaitForFlag_T> flags(ComSafeArrayInArg(aFlags));
1718 for (size_t i = 0; i < flags.size(); i++)
1719 fWaitFor |= flags[i];
1720
1721 return WaitFor(fWaitFor, aTimeoutMS, aReason);
1722#endif /* VBOX_WITH_GUEST_CONTROL */
1723}
1724
1725STDMETHODIMP GuestProcess::Write(ULONG aHandle, ULONG aFlags,
1726 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1727{
1728#ifndef VBOX_WITH_GUEST_CONTROL
1729 ReturnComNotImplemented();
1730#else
1731 LogFlowThisFuncEnter();
1732
1733 CheckComArgOutPointerValid(aWritten);
1734
1735 AutoCaller autoCaller(this);
1736 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1737
1738 HRESULT hr = S_OK;
1739
1740 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc;
1741 int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten, &guestRc);
1742 if (RT_FAILURE(vrc))
1743 {
1744 switch (vrc)
1745 {
1746 case VERR_GSTCTL_GUEST_ERROR:
1747 hr = GuestProcess::setErrorExternal(this, guestRc);
1748 break;
1749
1750 default:
1751 hr = setError(VBOX_E_IPRT_ERROR,
1752 tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
1753 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1754 break;
1755 }
1756 }
1757
1758 LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, aWritten));
1759
1760 LogFlowFuncLeaveRC(vrc);
1761 return hr;
1762#endif /* VBOX_WITH_GUEST_CONTROL */
1763}
1764
1765STDMETHODIMP GuestProcess::WriteArray(ULONG aHandle, ComSafeArrayIn(ProcessInputFlag_T, aFlags),
1766 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1767{
1768#ifndef VBOX_WITH_GUEST_CONTROL
1769 ReturnComNotImplemented();
1770#else
1771 LogFlowThisFuncEnter();
1772
1773 CheckComArgOutPointerValid(aWritten);
1774
1775 AutoCaller autoCaller(this);
1776 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1777
1778 /*
1779 * Note: Do not hold any locks here while writing!
1780 */
1781 ULONG fWrite = ProcessInputFlag_None;
1782 com::SafeArray<ProcessInputFlag_T> flags(ComSafeArrayInArg(aFlags));
1783 for (size_t i = 0; i < flags.size(); i++)
1784 fWrite |= flags[i];
1785
1786 return Write(aHandle, fWrite, ComSafeArrayInArg(aData), aTimeoutMS, aWritten);
1787#endif /* VBOX_WITH_GUEST_CONTROL */
1788}
1789
1790///////////////////////////////////////////////////////////////////////////////
1791
1792GuestProcessTool::GuestProcessTool(void)
1793 : pSession(NULL)
1794{
1795}
1796
1797GuestProcessTool::~GuestProcessTool(void)
1798{
1799 Terminate();
1800}
1801
1802int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
1803 bool fAsync, int *pGuestRc)
1804{
1805 LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n",
1806 pGuestSession, startupInfo.mCommand.c_str(), fAsync));
1807
1808 AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
1809
1810 pSession = pGuestSession;
1811 mStartupInfo = startupInfo;
1812
1813 /* Make sure the process is hidden. */
1814 mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
1815
1816 int vrc = pSession->processCreateExInteral(mStartupInfo, pProcess);
1817 if (RT_SUCCESS(vrc))
1818 vrc = fAsync ? pProcess->startProcessAsync() : pProcess->startProcess(pGuestRc);
1819
1820 if ( RT_SUCCESS(vrc)
1821 && !fAsync
1822 && ( pGuestRc
1823 && RT_FAILURE(*pGuestRc)
1824 )
1825 )
1826 {
1827 vrc = VERR_GSTCTL_GUEST_ERROR;
1828 }
1829
1830 LogFlowFuncLeaveRC(vrc);
1831 return vrc;
1832}
1833
1834int GuestProcessTool::GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock)
1835{
1836 const GuestProcessStream *pStream = NULL;
1837 if (uHandle == OUTPUT_HANDLE_ID_STDOUT)
1838 pStream = &mStdOut;
1839 else if (uHandle == OUTPUT_HANDLE_ID_STDERR)
1840 pStream = &mStdErr;
1841
1842 if (!pStream)
1843 return VERR_INVALID_PARAMETER;
1844
1845 int vrc;
1846 do
1847 {
1848 /* Try parsing the data to see if the current block is complete. */
1849 vrc = mStdOut.ParseBlock(strmBlock);
1850 if (strmBlock.GetCount())
1851 break;
1852 } while (RT_SUCCESS(vrc));
1853
1854 LogFlowThisFunc(("rc=%Rrc, %RU64 pairs\n",
1855 vrc, strmBlock.GetCount()));
1856 return vrc;
1857}
1858
1859bool GuestProcessTool::IsRunning(void)
1860{
1861 AssertReturn(!pProcess.isNull(), true);
1862
1863 ProcessStatus_T procStatus = ProcessStatus_Undefined;
1864 HRESULT hr = pProcess->COMGETTER(Status(&procStatus));
1865 Assert(SUCCEEDED(hr));
1866
1867 if ( procStatus != ProcessStatus_Started
1868 && procStatus != ProcessStatus_Paused
1869 && procStatus != ProcessStatus_Terminating)
1870 {
1871 return false;
1872 }
1873
1874 return true;
1875}
1876
1877int GuestProcessTool::TerminatedOk(LONG *pExitCode)
1878{
1879 Assert(!pProcess.isNull());
1880 /* pExitCode is optional. */
1881
1882 if (!IsRunning())
1883 {
1884 LONG exitCode;
1885 HRESULT hr = pProcess->COMGETTER(ExitCode(&exitCode));
1886 Assert(SUCCEEDED(hr));
1887
1888 if (pExitCode)
1889 *pExitCode = exitCode;
1890
1891 if (exitCode != 0)
1892 return VERR_NOT_EQUAL; /** @todo Special guest control rc needed! */
1893 return VINF_SUCCESS;
1894 }
1895
1896 return VERR_INVALID_STATE; /** @todo Special guest control rc needed! */
1897}
1898
1899int GuestProcessTool::Wait(uint32_t fFlags, int *pGuestRc)
1900{
1901 return WaitEx(fFlags, NULL /* pStreamBlock */, pGuestRc);
1902}
1903
1904int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc)
1905{
1906 LogFlowThisFunc(("pSession=%p, fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n",
1907 pSession, fFlags, pStreamBlock, pGuestRc));
1908
1909 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
1910 Assert(!pProcess.isNull());
1911 /* Other parameters are optional. */
1912
1913 /* Can we parse the next block without waiting? */
1914 int vrc;
1915 if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)
1916 {
1917 AssertPtr(pStreamBlock);
1918 vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
1919 if (RT_SUCCESS(vrc))
1920 return vrc;
1921 }
1922
1923 /* Do the waiting. */
1924 uint32_t fWaitFlags = ProcessWaitForFlag_Terminate;
1925 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1926 fWaitFlags |= ProcessWaitForFlag_StdOut;
1927 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
1928 fWaitFlags |= ProcessWaitForFlag_StdErr;
1929
1930 LogFlowFunc(("waitFlags=0x%x\n", fWaitFlags));
1931
1932 /** @todo Decrease timeout. */
1933 uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS;
1934
1935 int guestRc;
1936 bool fDone = false;
1937
1938 BYTE byBuf[_64K];
1939 uint32_t cbRead;
1940
1941 bool fHandleStdOut = false;
1942 bool fHandleStdErr = false;
1943
1944 ProcessWaitResult_T waitRes;
1945 do
1946 {
1947 vrc = pProcess->waitFor(fWaitFlags,
1948 uTimeoutMS, waitRes, &guestRc);
1949 if (RT_FAILURE(vrc))
1950 break;
1951
1952 switch (waitRes)
1953 {
1954 case ProcessWaitResult_StdIn:
1955 vrc = VERR_NOT_IMPLEMENTED;
1956 break;
1957
1958 case ProcessWaitResult_StdOut:
1959 fHandleStdOut = true;
1960 break;
1961
1962 case ProcessWaitResult_StdErr:
1963 fHandleStdErr = true;
1964 break;
1965
1966 case ProcessWaitResult_WaitFlagNotSupported:
1967 if (fWaitFlags & ProcessWaitForFlag_StdOut)
1968 fHandleStdOut = true;
1969 if (fWaitFlags & ProcessWaitForFlag_StdErr)
1970 fHandleStdErr = true;
1971 /* Since waiting for stdout / stderr is not supported by the guest,
1972 * wait a bit to not hog the CPU too much when polling for data. */
1973 RTThreadSleep(1); /* Optional, don't check rc. */
1974 break;
1975
1976 case ProcessWaitResult_Error:
1977 vrc = VERR_GSTCTL_GUEST_ERROR;
1978 break;
1979
1980 case ProcessWaitResult_Terminate:
1981 fDone = true;
1982 break;
1983
1984 case ProcessWaitResult_Timeout:
1985 vrc = VERR_TIMEOUT;
1986 break;
1987
1988 case ProcessWaitResult_Start:
1989 case ProcessWaitResult_Status:
1990 /* Not used here, just skip. */
1991 break;
1992
1993 default:
1994 AssertReleaseMsgFailed(("Unhandled process wait result %ld\n", waitRes));
1995 break;
1996 }
1997
1998 if (fHandleStdOut)
1999 {
2000 vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
2001 uTimeoutMS, byBuf, sizeof(byBuf),
2002 &cbRead, &guestRc);
2003 if (RT_FAILURE(vrc))
2004 break;
2005
2006 if (cbRead)
2007 {
2008 LogFlowThisFunc(("Received %RU64 bytes from stdout\n", cbRead));
2009 vrc = mStdOut.AddData(byBuf, cbRead);
2010
2011 if ( RT_SUCCESS(vrc)
2012 && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK))
2013 {
2014 AssertPtr(pStreamBlock);
2015 vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
2016 if (RT_SUCCESS(vrc))
2017 fDone = true;
2018 }
2019 }
2020
2021 fHandleStdOut = false;
2022 }
2023
2024 if (fHandleStdErr)
2025 {
2026 vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf),
2027 uTimeoutMS, byBuf, sizeof(byBuf),
2028 &cbRead, &guestRc);
2029 if (RT_FAILURE(vrc))
2030 break;
2031
2032 if (cbRead)
2033 {
2034 LogFlowThisFunc(("Received %RU64 bytes from stderr\n", cbRead));
2035 vrc = mStdErr.AddData(byBuf, cbRead);
2036 }
2037
2038 fHandleStdErr = false;
2039 }
2040
2041 } while (!fDone && RT_SUCCESS(vrc));
2042
2043 LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%ld\n",
2044 vrc, guestRc, waitRes));
2045 if (pGuestRc)
2046 *pGuestRc = guestRc;
2047
2048 LogFlowFuncLeaveRC(vrc);
2049 return vrc;
2050}
2051
2052void GuestProcessTool::Terminate(void)
2053{
2054 LogFlowThisFuncEnter();
2055
2056 if (!pProcess.isNull())
2057 {
2058 /** @todo Add pProcess.Terminate() here as soon as it's implemented. */
2059
2060 Assert(pSession);
2061 int rc2 = pSession->processRemoveFromList(pProcess);
2062 AssertRC(rc2);
2063
2064 pProcess.setNull();
2065 }
2066
2067 LogFlowThisFuncLeave();
2068}
2069
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette