VirtualBox

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

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

GuestCtrl: Various bugfixes required for test driver to pass.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.9 KB
Line 
1
2/* $Id: GuestProcessImpl.cpp 45697 2013-04-24 13:30:50Z 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 if (dataCb.cbData)
739 data.initFrom((BYTE*)dataCb.pvData, dataCb.cbData);
740
741 fireGuestProcessOutputEvent(mEventSource, mSession, this,
742 mData.mPID, dataCb.uHandle, dataCb.cbData, ComSafeArrayAsInParam(data));
743
744 LogFlowFuncLeaveRC(vrc);
745 return vrc;
746}
747
748int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
749 void *pvData, size_t cbData, uint32_t *pcbRead, int *pGuestRc)
750{
751 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n",
752 mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc));
753 AssertReturn(uSize, VERR_INVALID_PARAMETER);
754 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
755 AssertReturn(cbData >= uSize, VERR_INVALID_PARAMETER);
756 /* pcbRead is optional. */
757
758 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
759
760 if ( mData.mStatus != ProcessStatus_Started
761 /* Skip reading if the process wasn't started with the appropriate
762 * flags. */
763 || ( ( uHandle == OUTPUT_HANDLE_ID_STDOUT
764 || uHandle == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED)
765 && !(mData.mProcess.mFlags & ProcessCreateFlag_WaitForStdOut))
766 || ( uHandle == OUTPUT_HANDLE_ID_STDERR
767 && !(mData.mProcess.mFlags & ProcessCreateFlag_WaitForStdErr))
768 )
769 {
770 if (pcbRead)
771 *pcbRead = 0;
772 if (pGuestRc)
773 *pGuestRc = VINF_SUCCESS;
774 return VINF_SUCCESS; /* Nothing to read anymore. */
775 }
776
777 uint32_t uContextID;
778 int vrc = generateContextID(mSession->getId(), mObjectID,
779 &uContextID);
780 if (RT_SUCCESS(vrc))
781 {
782 VBOXHGCMSVCPARM paParms[8];
783 int i = 0;
784 paParms[i++].setUInt32(uContextID);
785 paParms[i++].setUInt32(mData.mPID);
786 paParms[i++].setUInt32(uHandle);
787 paParms[i++].setUInt32(0 /* Flags, none set yet. */);
788
789 alock.release(); /* Drop the write lock before sending. */
790
791 vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms);
792 }
793
794 if (RT_SUCCESS(vrc))
795 vrc = waitForOutput(uHandle, uTimeoutMS,
796 pvData, cbData, pcbRead);
797
798 LogFlowFuncLeaveRC(vrc);
799 return vrc;
800}
801
802/* Does not do locking; caller is responsible for that! */
803int GuestProcess::setProcessStatus(ProcessStatus_T procStatus, int procRc)
804{
805 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, procRc=%Rrc\n",
806 mData.mStatus, procStatus, procRc));
807
808 if (procStatus == ProcessStatus_Error)
809 {
810 AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc));
811 /* Do not allow overwriting an already set error. If this happens
812 * this means we forgot some error checking/locking somewhere. */
813 //AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
814 }
815 else
816 AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
817
818 if (mData.mStatus != procStatus)
819 {
820 mData.mStatus = procStatus;
821 mData.mRC = procRc;
822
823 ComObjPtr<GuestErrorInfo> errorInfo;
824 HRESULT hr = errorInfo.createObject();
825 ComAssertComRC(hr);
826 if (RT_FAILURE(mData.mRC))
827 {
828 int rc2 = errorInfo->init(mData.mRC, guestErrorToString(mData.mRC));
829 AssertRC(rc2);
830 }
831
832 fireGuestProcessStateChangedEvent(mEventSource, mSession, this,
833 mData.mPID, mData.mStatus, errorInfo);
834 }
835
836 return VINF_SUCCESS;
837}
838
839/* static */
840HRESULT GuestProcess::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
841{
842 AssertPtr(pInterface);
843 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
844
845 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str());
846}
847
848int GuestProcess::startProcess(int *pGuestRc)
849{
850 LogFlowThisFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n",
851 mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags));
852
853 /* Wait until the caller function (if kicked off by a thread)
854 * has returned and continue operation. */
855 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
856
857 mData.mStatus = ProcessStatus_Starting;
858
859 uint32_t uContextID;
860 int vrc = generateContextID(mSession->getId(), mObjectID,
861 &uContextID);
862 if (RT_SUCCESS(vrc))
863 {
864 GuestSession *pSession = mSession;
865 AssertPtr(pSession);
866
867 const GuestCredentials &sessionCreds = pSession->getCredentials();
868
869 /* Prepare arguments. */
870 char *pszArgs = NULL;
871 size_t cArgs = mData.mProcess.mArguments.size();
872 if (cArgs >= UINT32_MAX)
873 vrc = VERR_BUFFER_OVERFLOW;
874
875 if ( RT_SUCCESS(vrc)
876 && cArgs)
877 {
878 char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
879 AssertReturn(papszArgv, VERR_NO_MEMORY);
880
881 for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
882 {
883 const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
884 AssertPtr(pszCurArg);
885 vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
886 }
887 papszArgv[cArgs] = NULL;
888
889 if (RT_SUCCESS(vrc))
890 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
891
892 if (papszArgv)
893 {
894 size_t i = 0;
895 while (papszArgv[i])
896 RTStrFree(papszArgv[i++]);
897 RTMemFree(papszArgv);
898 }
899 }
900
901 /* Calculate arguments size (in bytes). */
902 size_t cbArgs = 0;
903 if (RT_SUCCESS(vrc))
904 cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
905
906 /* Prepare environment. */
907 void *pvEnv = NULL;
908 size_t cbEnv = 0;
909 if (RT_SUCCESS(vrc))
910 vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
911
912 uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
913
914 if (RT_SUCCESS(vrc))
915 {
916 AssertPtr(mSession);
917 uint32_t uProtocol = mSession->getProtocolVersion();
918
919 /* Prepare HGCM call. */
920 VBOXHGCMSVCPARM paParms[16];
921 int i = 0;
922 paParms[i++].setUInt32(uContextID);
923 paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
924 (ULONG)mData.mProcess.mCommand.length() + 1);
925 paParms[i++].setUInt32(mData.mProcess.mFlags);
926 paParms[i++].setUInt32(mData.mProcess.mArguments.size());
927 paParms[i++].setPointer((void*)pszArgs, cbArgs);
928 paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size());
929 paParms[i++].setUInt32(cbEnv);
930 paParms[i++].setPointer((void*)pvEnv, cbEnv);
931 if (uProtocol < 2)
932 {
933 /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
934 * call. In newer protocols these credentials are part of the opened guest
935 * session, so not needed anymore here. */
936 paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
937 paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
938 }
939 /*
940 * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
941 * until the process was started - the process itself then gets an infinite timeout for execution.
942 * This is handy when we want to start a process inside a worker thread within a certain timeout
943 * but let the started process perform lengthly operations then.
944 */
945 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
946 paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
947 else
948 paParms[i++].setUInt32(uTimeoutMS);
949 if (uProtocol >= 2)
950 {
951 paParms[i++].setUInt32(mData.mProcess.mPriority);
952 /* CPU affinity: We only support one CPU affinity block at the moment,
953 * so that makes up to 64 CPUs total. This can be more in the future. */
954 paParms[i++].setUInt32(1);
955 /* The actual CPU affinity blocks. */
956 paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
957 }
958
959 alock.release(); /* Drop the write lock before sending. */
960
961 /* Note: Don't hold the write lock in here. */
962 vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
963 if (RT_FAILURE(vrc))
964 {
965 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
966 AssertRC(rc2);
967 }
968 }
969
970 GuestEnvironment::FreeEnvironmentBlock(pvEnv);
971 if (pszArgs)
972 RTStrFree(pszArgs);
973
974 if (RT_SUCCESS(vrc))
975 {
976 vrc = waitForStatusChange(ProcessWaitForFlag_Start, uTimeoutMS,
977 NULL /* Process status */, pGuestRc);
978 }
979 }
980
981 LogFlowFuncLeaveRC(vrc);
982 return vrc;
983}
984
985int GuestProcess::startProcessAsync(void)
986{
987 LogFlowThisFuncEnter();
988
989 int vrc;
990
991 try
992 {
993 /* Asynchronously start the process on the guest by kicking off a
994 * worker thread. */
995 std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
996 AssertReturn(pTask->isOk(), pTask->rc());
997
998 vrc = RTThreadCreate(NULL, GuestProcess::startProcessThread,
999 (void *)pTask.get(), 0,
1000 RTTHREADTYPE_MAIN_WORKER, 0,
1001 "gctlPrcStart");
1002 if (RT_SUCCESS(vrc))
1003 {
1004 /* pTask is now owned by startProcessThread(), so release it. */
1005 pTask.release();
1006 }
1007 }
1008 catch(std::bad_alloc &)
1009 {
1010 vrc = VERR_NO_MEMORY;
1011 }
1012
1013 LogFlowFuncLeaveRC(vrc);
1014 return vrc;
1015}
1016
1017/* static */
1018DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser)
1019{
1020 LogFlowFunc(("pvUser=%p\n", pvUser));
1021
1022 std::auto_ptr<GuestProcessStartTask> pTask(static_cast<GuestProcessStartTask*>(pvUser));
1023 AssertPtr(pTask.get());
1024
1025 const ComObjPtr<GuestProcess> pProcess(pTask->Process());
1026 Assert(!pProcess.isNull());
1027
1028 AutoCaller autoCaller(pProcess);
1029 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1030
1031 int vrc = pProcess->startProcess(NULL /* Guest rc, ignored */);
1032 /* Nothing to do here anymore. */
1033
1034 LogFlowFuncLeaveRC(vrc);
1035 return vrc;
1036}
1037
1038int GuestProcess::terminateProcess(int *pGuestRc)
1039{
1040 LogFlowThisFuncEnter();
1041
1042 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1043
1044 AssertPtr(mSession);
1045 if (mSession->getProtocolVersion() < 99)
1046 return VERR_NOT_SUPPORTED;
1047
1048 if (mData.mStatus != ProcessStatus_Started)
1049 return VINF_SUCCESS; /* Nothing to do (anymore). */
1050
1051 uint32_t uContextID;
1052 int vrc = generateContextID(mSession->getId(), mObjectID,
1053 &uContextID);
1054 if (RT_SUCCESS(vrc))
1055 {
1056 VBOXHGCMSVCPARM paParms[4];
1057 int i = 0;
1058 paParms[i++].setUInt32(uContextID);
1059 paParms[i++].setUInt32(mData.mPID);
1060
1061 alock.release(); /* Drop the write lock before sending. */
1062
1063 vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
1064 }
1065
1066 if (RT_SUCCESS(vrc))
1067 vrc = waitForStatusChange(ProcessWaitForFlag_Terminate,
1068 30 * 1000 /* 30s timeout */,
1069 NULL /* ProcessStatus */, pGuestRc);
1070 LogFlowFuncLeaveRC(vrc);
1071 return vrc;
1072}
1073
1074int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc)
1075{
1076 LogFlowThisFuncEnter();
1077
1078 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
1079
1080 /*LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
1081 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));*/
1082
1083 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1084
1085 /* Did some error occur before? Then skip waiting and return. */
1086 if (mData.mStatus == ProcessStatus_Error)
1087 {
1088 waitResult = ProcessWaitResult_Error;
1089 AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mRC));
1090 if (pGuestRc)
1091 *pGuestRc = mData.mRC; /* Return last set error. */
1092 return VERR_GSTCTL_GUEST_ERROR;
1093 }
1094
1095 waitResult = ProcessWaitResult_None;
1096 if ( (fWaitFlags & ProcessWaitForFlag_Terminate)
1097 || (fWaitFlags & ProcessWaitForFlag_StdIn)
1098 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1099 || (fWaitFlags & ProcessWaitForFlag_StdErr))
1100 {
1101 switch (mData.mStatus)
1102 {
1103 case ProcessStatus_TerminatedNormally:
1104 case ProcessStatus_TerminatedSignal:
1105 case ProcessStatus_TerminatedAbnormally:
1106 case ProcessStatus_Down:
1107 waitResult = ProcessWaitResult_Terminate;
1108 break;
1109
1110 case ProcessStatus_TimedOutKilled:
1111 case ProcessStatus_TimedOutAbnormally:
1112 waitResult = ProcessWaitResult_Timeout;
1113 break;
1114
1115 case ProcessStatus_Error:
1116 /* Handled above. */
1117 break;
1118
1119 case ProcessStatus_Started:
1120 {
1121 /*
1122 * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the
1123 * caller is not interested in getting further process statuses -- so just don't notify
1124 * anything here anymore and return.
1125 */
1126 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1127 waitResult = ProcessWaitResult_Start;
1128 break;
1129 }
1130
1131 case ProcessStatus_Undefined:
1132 case ProcessStatus_Starting:
1133 /* Do the waiting below. */
1134 break;
1135
1136 default:
1137 AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus));
1138 return VERR_NOT_IMPLEMENTED;
1139 }
1140 }
1141 else if (fWaitFlags & ProcessWaitForFlag_Start)
1142 {
1143 switch (mData.mStatus)
1144 {
1145 case ProcessStatus_Started:
1146 case ProcessStatus_Paused:
1147 case ProcessStatus_Terminating:
1148 case ProcessStatus_TerminatedNormally:
1149 case ProcessStatus_TerminatedSignal:
1150 case ProcessStatus_TerminatedAbnormally:
1151 case ProcessStatus_Down:
1152 waitResult = ProcessWaitResult_Start;
1153 break;
1154
1155 case ProcessStatus_Error:
1156 waitResult = ProcessWaitResult_Error;
1157 break;
1158
1159 case ProcessStatus_TimedOutKilled:
1160 case ProcessStatus_TimedOutAbnormally:
1161 waitResult = ProcessWaitResult_Timeout;
1162 break;
1163
1164 case ProcessStatus_Undefined:
1165 case ProcessStatus_Starting:
1166 /* Do the waiting below. */
1167 break;
1168
1169 default:
1170 AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus));
1171 return VERR_NOT_IMPLEMENTED;
1172 }
1173 }
1174
1175 /* Filter out waits which are *not* supported using
1176 * older guest control Guest Additions.
1177 *
1178 ** @todo ProcessWaitForFlag_Std* flags are not implemented yet.
1179 */
1180 if (mSession->getProtocolVersion() < 99)
1181 {
1182 if ( waitResult == ProcessWaitResult_None
1183 /* We don't support waiting for stdin, out + err,
1184 * just skip waiting then. */
1185 && ( (fWaitFlags & ProcessWaitForFlag_StdIn)
1186 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1187 || (fWaitFlags & ProcessWaitForFlag_StdErr)
1188 )
1189 )
1190 {
1191 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
1192 waitResult = ProcessWaitResult_WaitFlagNotSupported;
1193 }
1194 }
1195
1196 LogFlowThisFunc(("procStatus=%ld, procRc=%Rrc, waitResult=%ld\n",
1197 mData.mStatus, mData.mRC, waitResult));
1198
1199 /* No waiting needed? Return immediately using the last set error. */
1200 if (waitResult != ProcessWaitResult_None)
1201 {
1202 if (pGuestRc)
1203 *pGuestRc = mData.mRC; /* Return last set error (if any). */
1204 return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR;
1205 }
1206
1207 alock.release(); /* Release lock before waiting. */
1208
1209 ProcessStatus_T processStatus;
1210 int vrc = waitForStatusChange(fWaitFlags, uTimeoutMS, &processStatus, pGuestRc);
1211 if (RT_SUCCESS(vrc))
1212 {
1213 switch (processStatus)
1214 {
1215 case ProcessStatus_Started:
1216 waitResult = ProcessWaitResult_Start;
1217 break;
1218
1219 case ProcessStatus_TerminatedNormally:
1220 case ProcessStatus_TerminatedAbnormally:
1221 case ProcessStatus_TerminatedSignal:
1222 waitResult = ProcessWaitResult_Terminate;
1223 break;
1224
1225 case ProcessStatus_TimedOutKilled:
1226 case ProcessStatus_TimedOutAbnormally:
1227 waitResult = ProcessWaitResult_Timeout;
1228 break;
1229
1230 case ProcessStatus_Down:
1231 waitResult = ProcessWaitResult_Terminate;
1232 break;
1233
1234 case ProcessStatus_Error:
1235 waitResult = ProcessWaitResult_Error;
1236 break;
1237
1238 default:
1239 waitResult = ProcessWaitResult_Status;
1240 break;
1241 }
1242 }
1243
1244 LogFlowFuncLeaveRC(vrc);
1245 return vrc;
1246}
1247
1248int GuestProcess::waitForEvents(uint32_t uTimeoutMS, ComSafeArrayIn(VBoxEventType_T, pEvents),
1249 VBoxEventType_T *pType, IEvent **ppEvent)
1250{
1251 AssertPtrReturn(pType, VERR_INVALID_POINTER);
1252 AssertPtrReturn(ppEvent, VERR_INVALID_POINTER);
1253
1254 int vrc;
1255
1256 /** @todo Parameter validation. */
1257
1258 com::SafeArray <VBoxEventType_T> arrEventTypes(ComSafeArrayInArg(pEvents));
1259
1260 ComPtr<IEventListener> pListener;
1261 HRESULT hr = mEventSource->CreateListener(pListener.asOutParam());
1262 if (SUCCEEDED(hr))
1263 hr = mEventSource->RegisterListener(pListener, ComSafeArrayAsInParam(arrEventTypes),
1264 FALSE /* Passive listener */);
1265 else
1266 vrc = VERR_COM_UNEXPECTED;
1267
1268 if (SUCCEEDED(hr))
1269 {
1270 LogFlowThisFunc(("Waiting for guest process event(s) (timeout=%RU32ms, %zu events) ...\n",
1271 uTimeoutMS, arrEventTypes.size()));
1272
1273 vrc = VINF_SUCCESS;
1274
1275 uint64_t u64Started = RTTimeMilliTS();
1276 bool fSignalled = false;
1277 do
1278 {
1279 unsigned cMsWait;
1280 if (uTimeoutMS == RT_INDEFINITE_WAIT)
1281 cMsWait = 1000;
1282 else
1283 {
1284 uint64_t cMsElapsed = RTTimeMilliTS() - u64Started;
1285 if (cMsElapsed >= uTimeoutMS)
1286 break; /* timed out */
1287 cMsWait = RT_MIN(1000, uTimeoutMS - (uint32_t)cMsElapsed);
1288 }
1289
1290 ComPtr<IEvent> pThisEvent;
1291 hr = mEventSource->GetEvent(pListener, cMsWait, pThisEvent.asOutParam());
1292 if ( SUCCEEDED(hr)
1293 && !pThisEvent.isNull())
1294 {
1295 VBoxEventType_T type;
1296 hr = pThisEvent->COMGETTER(Type)(&type);
1297 ComAssertComRC(hr);
1298
1299 for (size_t i = 0; i < arrEventTypes.size() && !fSignalled; i++)
1300 {
1301 if (type == arrEventTypes[i])
1302 {
1303 switch (type)
1304 {
1305 case VBoxEventType_OnGuestProcessStateChanged:
1306 case VBoxEventType_OnGuestProcessInputNotify:
1307 case VBoxEventType_OnGuestProcessOutput:
1308 {
1309 ComPtr<IGuestProcessEvent> pFileEvent = pThisEvent;
1310 Assert(!pFileEvent.isNull());
1311
1312 ComPtr<IGuestProcess> pProcess;
1313 pFileEvent->COMGETTER(Process)(pProcess.asOutParam());
1314 Assert(!pProcess.isNull());
1315
1316 fSignalled = (pProcess == this);
1317 break;
1318 }
1319
1320 default:
1321 AssertMsgFailed(("Unhandled event %ld\n", type));
1322 break;
1323 }
1324
1325 if (fSignalled)
1326 {
1327 if (pType)
1328 *pType = type;
1329 if (ppEvent)
1330 pThisEvent.queryInterfaceTo(ppEvent);
1331 if ( type == VBoxEventType_OnGuestProcessStateChanged
1332 && RT_SUCCESS(vrc))
1333 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1334 break;
1335 }
1336 }
1337 }
1338 }
1339
1340 } while (!fSignalled);
1341
1342 if ( RT_SUCCESS(vrc)
1343 && !fSignalled)
1344 {
1345 vrc = VERR_TIMEOUT;
1346 }
1347
1348 hr = mEventSource->UnregisterListener(pListener);
1349 ComAssertComRC(hr);
1350 }
1351 else
1352 vrc = VERR_COM_UNEXPECTED;
1353
1354 LogFlowFuncLeaveRC(vrc);
1355 return vrc;
1356}
1357
1358int GuestProcess::waitForInputNotify(uint32_t uHandle, uint32_t uTimeoutMS,
1359 ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed)
1360{
1361 VBoxEventType_T evtType;
1362 ComPtr<IEvent> pEvent;
1363 com::SafeArray<VBoxEventType_T> eventTypes;
1364 eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
1365 int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
1366 &evtType, pEvent.asOutParam());
1367 if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
1368 {
1369 Assert(evtType == VBoxEventType_OnGuestProcessInputNotify);
1370 ComPtr<IGuestProcessInputNotifyEvent> pProcessEvent = pEvent;
1371 Assert(!pProcessEvent.isNull());
1372
1373 if (pInputStatus)
1374 {
1375 HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus);
1376 ComAssertComRC(hr2);
1377 }
1378 if (pcbProcessed)
1379 {
1380 HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed);
1381 ComAssertComRC(hr2);
1382 }
1383 }
1384
1385 LogFlowFuncLeaveRC(vrc);
1386 return vrc;
1387}
1388
1389int GuestProcess::waitForOutput(uint32_t uHandle, uint32_t uTimeoutMS,
1390 void *pvData, size_t cbData, uint32_t *pcbRead)
1391{
1392 VBoxEventType_T evtType;
1393 ComPtr<IEvent> pEvent;
1394 com::SafeArray<VBoxEventType_T> eventTypes;
1395
1396 int vrc = VINF_SUCCESS;
1397
1398 try
1399 {
1400 eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
1401 }
1402 catch (std::bad_alloc)
1403 {
1404 vrc = VERR_NO_MEMORY;
1405 }
1406
1407 if (RT_FAILURE(vrc))
1408 return vrc;
1409
1410 do
1411 {
1412 vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
1413 &evtType, pEvent.asOutParam());
1414 if (vrc == VINF_SUCCESS) /* Can also return VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
1415 {
1416 Assert(evtType == VBoxEventType_OnGuestProcessOutput);
1417 ComPtr<IGuestProcessOutputEvent> pProcessEvent = pEvent;
1418 Assert(!pProcessEvent.isNull());
1419
1420 ULONG uHandleEvent;
1421 HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent);
1422 if (uHandleEvent == uHandle)
1423 {
1424 if (pvData)
1425 {
1426 com::SafeArray <BYTE> data;
1427 hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1428 ComAssertComRC(hr);
1429 size_t cbRead = data.size();
1430 if (cbRead)
1431 {
1432 if (cbRead <= cbData)
1433 {
1434 /* Copy data from event into our buffer. */
1435 memcpy(pvData, data.raw(), data.size());
1436 }
1437 else
1438 vrc = VERR_BUFFER_OVERFLOW;
1439 }
1440 }
1441 if (pcbRead)
1442 {
1443 ULONG cbRead;
1444 hr = pProcessEvent->COMGETTER(Processed)(&cbRead);
1445 ComAssertComRC(hr);
1446 *pcbRead = (uint32_t)cbRead;
1447 }
1448
1449 break;
1450 }
1451 }
1452
1453 } while (RT_SUCCESS(vrc));
1454
1455 LogFlowFuncLeaveRC(vrc);
1456 return vrc;
1457}
1458
1459int GuestProcess::waitForStatusChange(uint32_t fWaitFlags, uint32_t uTimeoutMS,
1460 ProcessStatus_T *pProcessStatus, int *pGuestRc)
1461{
1462 /* All pointers are optional. */
1463
1464 VBoxEventType_T evtType;
1465 ComPtr<IEvent> pEvent;
1466 com::SafeArray<VBoxEventType_T> eventTypes(1);
1467 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1468 int vrc = waitForEvents(uTimeoutMS, ComSafeArrayAsInParam(eventTypes),
1469 &evtType, pEvent.asOutParam());
1470 if (RT_SUCCESS(vrc)) /* Includes VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
1471 {
1472 Assert(evtType == VBoxEventType_OnGuestProcessStateChanged);
1473 ComPtr<IGuestProcessStateChangedEvent> pProcessEvent = pEvent;
1474 Assert(!pProcessEvent.isNull());
1475
1476 HRESULT hr;
1477 if (pProcessStatus)
1478 {
1479 hr = pProcessEvent->COMGETTER(Status)(pProcessStatus);
1480 ComAssertComRC(hr);
1481 }
1482
1483 ComPtr<IGuestErrorInfo> errorInfo;
1484 hr = pProcessEvent->COMGETTER(Error)(errorInfo.asOutParam());
1485 ComAssertComRC(hr);
1486
1487 LONG lGuestRc;
1488 hr = errorInfo->COMGETTER(Result)(&lGuestRc);
1489 ComAssertComRC(hr);
1490 if (RT_FAILURE((int)lGuestRc))
1491 vrc = VERR_GSTCTL_GUEST_ERROR;
1492
1493 if (pGuestRc)
1494 *pGuestRc = (int)lGuestRc;
1495 }
1496
1497 LogFlowFuncLeaveRC(vrc);
1498 return vrc;
1499}
1500
1501int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
1502 void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc)
1503{
1504 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p, pGuestRc=%p\n",
1505 mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten, pGuestRc));
1506 /* All is optional. There can be 0 byte writes. */
1507
1508 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1509
1510 if (mData.mStatus != ProcessStatus_Started)
1511 {
1512 if (puWritten)
1513 *puWritten = 0;
1514 if (pGuestRc)
1515 *pGuestRc = VINF_SUCCESS;
1516 return VINF_SUCCESS; /* Not available for writing (anymore). */
1517 }
1518
1519 uint32_t uContextID;
1520 int vrc = generateContextID(mSession->getId(), mObjectID,
1521 &uContextID);
1522 if (RT_SUCCESS(vrc))
1523 {
1524 VBOXHGCMSVCPARM paParms[5];
1525
1526 int i = 0;
1527 paParms[i++].setUInt32(uContextID);
1528 paParms[i++].setUInt32(mData.mPID);
1529 paParms[i++].setUInt32(uFlags);
1530 paParms[i++].setPointer(pvData, cbData);
1531 paParms[i++].setUInt32(cbData);
1532
1533 alock.release(); /* Drop the write lock before sending. */
1534
1535 vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
1536 }
1537
1538 if (RT_SUCCESS(vrc))
1539 {
1540 ProcessInputStatus_T inputStatus;
1541 uint32_t cbProcessed;
1542 vrc = waitForInputNotify(uHandle, uTimeoutMS, &inputStatus, &cbProcessed);
1543 if (RT_SUCCESS(vrc))
1544 {
1545 /** @todo Set guestRc. */
1546
1547 if (puWritten)
1548 *puWritten = cbProcessed;
1549 }
1550 /** @todo Error handling. */
1551 }
1552
1553 LogFlowFuncLeaveRC(vrc);
1554 return vrc;
1555}
1556
1557// implementation of public methods
1558/////////////////////////////////////////////////////////////////////////////
1559
1560STDMETHODIMP GuestProcess::Read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1561{
1562#ifndef VBOX_WITH_GUEST_CONTROL
1563 ReturnComNotImplemented();
1564#else
1565 if (aToRead == 0)
1566 return setError(E_INVALIDARG, tr("The size to read is zero"));
1567 CheckComArgOutSafeArrayPointerValid(aData);
1568
1569 AutoCaller autoCaller(this);
1570 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1571
1572 com::SafeArray<BYTE> data((size_t)aToRead);
1573 Assert(data.size() >= aToRead);
1574
1575 HRESULT hr = S_OK;
1576
1577 uint32_t cbRead; int guestRc;
1578 int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead, &guestRc);
1579 if (RT_SUCCESS(vrc))
1580 {
1581 if (data.size() != cbRead)
1582 data.resize(cbRead);
1583 data.detachTo(ComSafeArrayOutArg(aData));
1584 }
1585 else
1586 {
1587 switch (vrc)
1588 {
1589 case VERR_GSTCTL_GUEST_ERROR:
1590 hr = GuestProcess::setErrorExternal(this, guestRc);
1591 break;
1592
1593 default:
1594 hr = setError(VBOX_E_IPRT_ERROR,
1595 tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
1596 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1597 break;
1598 }
1599 }
1600
1601 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32\n", vrc, cbRead));
1602
1603 LogFlowFuncLeaveRC(vrc);
1604 return hr;
1605#endif /* VBOX_WITH_GUEST_CONTROL */
1606}
1607
1608STDMETHODIMP GuestProcess::Terminate(void)
1609{
1610#ifndef VBOX_WITH_GUEST_CONTROL
1611 ReturnComNotImplemented();
1612#else
1613 LogFlowThisFuncEnter();
1614
1615 AutoCaller autoCaller(this);
1616 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1617
1618 HRESULT hr = S_OK;
1619
1620 int guestRc;
1621 int vrc = terminateProcess(&guestRc);
1622 if (RT_FAILURE(vrc))
1623 {
1624 switch (vrc)
1625 {
1626 case VERR_GSTCTL_GUEST_ERROR:
1627 hr = GuestProcess::setErrorExternal(this, guestRc);
1628 break;
1629
1630 case VERR_NOT_SUPPORTED:
1631 hr = setError(VBOX_E_IPRT_ERROR,
1632 tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"),
1633 mData.mProcess.mCommand.c_str(), mData.mPID);
1634 break;
1635
1636 default:
1637 hr = setError(VBOX_E_IPRT_ERROR,
1638 tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"),
1639 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1640 break;
1641 }
1642 }
1643
1644 AssertPtr(mSession);
1645 mSession->processRemoveFromList(this);
1646
1647 /*
1648 * Release autocaller before calling uninit.
1649 */
1650 autoCaller.release();
1651
1652 uninit();
1653
1654 LogFlowFuncLeaveRC(vrc);
1655 return hr;
1656#endif /* VBOX_WITH_GUEST_CONTROL */
1657}
1658
1659STDMETHODIMP GuestProcess::WaitFor(ULONG aWaitFlags, ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1660{
1661#ifndef VBOX_WITH_GUEST_CONTROL
1662 ReturnComNotImplemented();
1663#else
1664 LogFlowThisFuncEnter();
1665
1666 CheckComArgOutPointerValid(aReason);
1667
1668 AutoCaller autoCaller(this);
1669 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1670
1671 /*
1672 * Note: Do not hold any locks here while waiting!
1673 */
1674 HRESULT hr = S_OK;
1675
1676 int guestRc; ProcessWaitResult_T waitResult;
1677 int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc);
1678 if (RT_SUCCESS(vrc))
1679 {
1680 *aReason = waitResult;
1681 }
1682 else
1683 {
1684 switch (vrc)
1685 {
1686 case VERR_GSTCTL_GUEST_ERROR:
1687 hr = GuestProcess::setErrorExternal(this, guestRc);
1688 break;
1689
1690 case VERR_TIMEOUT:
1691 *aReason = ProcessWaitResult_Timeout;
1692 break;
1693
1694 default:
1695 hr = setError(VBOX_E_IPRT_ERROR,
1696 tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
1697 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1698 break;
1699 }
1700 }
1701
1702 LogFlowFuncLeaveRC(vrc);
1703 return hr;
1704#endif /* VBOX_WITH_GUEST_CONTROL */
1705}
1706
1707STDMETHODIMP GuestProcess::WaitForArray(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1708{
1709#ifndef VBOX_WITH_GUEST_CONTROL
1710 ReturnComNotImplemented();
1711#else
1712 LogFlowThisFuncEnter();
1713
1714 CheckComArgOutPointerValid(aReason);
1715
1716 AutoCaller autoCaller(this);
1717 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1718
1719 /*
1720 * Note: Do not hold any locks here while waiting!
1721 */
1722 uint32_t fWaitFor = ProcessWaitForFlag_None;
1723 com::SafeArray<ProcessWaitForFlag_T> flags(ComSafeArrayInArg(aFlags));
1724 for (size_t i = 0; i < flags.size(); i++)
1725 fWaitFor |= flags[i];
1726
1727 return WaitFor(fWaitFor, aTimeoutMS, aReason);
1728#endif /* VBOX_WITH_GUEST_CONTROL */
1729}
1730
1731STDMETHODIMP GuestProcess::Write(ULONG aHandle, ULONG aFlags,
1732 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1733{
1734#ifndef VBOX_WITH_GUEST_CONTROL
1735 ReturnComNotImplemented();
1736#else
1737 LogFlowThisFuncEnter();
1738
1739 CheckComArgOutPointerValid(aWritten);
1740
1741 AutoCaller autoCaller(this);
1742 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1743
1744 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1745
1746 HRESULT hr = S_OK;
1747
1748 uint32_t cbWritten; int guestRc;
1749 int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, &cbWritten, &guestRc);
1750 if (RT_FAILURE(vrc))
1751 {
1752 switch (vrc)
1753 {
1754 case VERR_GSTCTL_GUEST_ERROR:
1755 hr = GuestProcess::setErrorExternal(this, guestRc);
1756 break;
1757
1758 default:
1759 hr = setError(VBOX_E_IPRT_ERROR,
1760 tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
1761 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1762 break;
1763 }
1764 }
1765
1766 LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, cbWritten));
1767
1768 *aWritten = (ULONG)cbWritten;
1769
1770 LogFlowFuncLeaveRC(vrc);
1771 return hr;
1772#endif /* VBOX_WITH_GUEST_CONTROL */
1773}
1774
1775STDMETHODIMP GuestProcess::WriteArray(ULONG aHandle, ComSafeArrayIn(ProcessInputFlag_T, aFlags),
1776 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1777{
1778#ifndef VBOX_WITH_GUEST_CONTROL
1779 ReturnComNotImplemented();
1780#else
1781 LogFlowThisFuncEnter();
1782
1783 CheckComArgOutPointerValid(aWritten);
1784
1785 AutoCaller autoCaller(this);
1786 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1787
1788 /*
1789 * Note: Do not hold any locks here while writing!
1790 */
1791 ULONG fWrite = ProcessInputFlag_None;
1792 com::SafeArray<ProcessInputFlag_T> flags(ComSafeArrayInArg(aFlags));
1793 for (size_t i = 0; i < flags.size(); i++)
1794 fWrite |= flags[i];
1795
1796 return Write(aHandle, fWrite, ComSafeArrayInArg(aData), aTimeoutMS, aWritten);
1797#endif /* VBOX_WITH_GUEST_CONTROL */
1798}
1799
1800///////////////////////////////////////////////////////////////////////////////
1801
1802GuestProcessTool::GuestProcessTool(void)
1803 : pSession(NULL)
1804{
1805}
1806
1807GuestProcessTool::~GuestProcessTool(void)
1808{
1809 Terminate();
1810}
1811
1812int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
1813 bool fAsync, int *pGuestRc)
1814{
1815 LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n",
1816 pGuestSession, startupInfo.mCommand.c_str(), fAsync));
1817
1818 AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
1819
1820 pSession = pGuestSession;
1821 mStartupInfo = startupInfo;
1822
1823 /* Make sure the process is hidden. */
1824 mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
1825
1826 int vrc = pSession->processCreateExInteral(mStartupInfo, pProcess);
1827 if (RT_SUCCESS(vrc))
1828 vrc = fAsync ? pProcess->startProcessAsync() : pProcess->startProcess(pGuestRc);
1829
1830 if ( RT_SUCCESS(vrc)
1831 && !fAsync
1832 && ( pGuestRc
1833 && RT_FAILURE(*pGuestRc)
1834 )
1835 )
1836 {
1837 vrc = VERR_GSTCTL_GUEST_ERROR;
1838 }
1839
1840 LogFlowFuncLeaveRC(vrc);
1841 return vrc;
1842}
1843
1844int GuestProcessTool::GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock)
1845{
1846 const GuestProcessStream *pStream = NULL;
1847 if (uHandle == OUTPUT_HANDLE_ID_STDOUT)
1848 pStream = &mStdOut;
1849 else if (uHandle == OUTPUT_HANDLE_ID_STDERR)
1850 pStream = &mStdErr;
1851
1852 if (!pStream)
1853 return VERR_INVALID_PARAMETER;
1854
1855 int vrc;
1856 do
1857 {
1858 /* Try parsing the data to see if the current block is complete. */
1859 vrc = mStdOut.ParseBlock(strmBlock);
1860 if (strmBlock.GetCount())
1861 break;
1862 } while (RT_SUCCESS(vrc));
1863
1864 LogFlowThisFunc(("rc=%Rrc, %RU64 pairs\n",
1865 vrc, strmBlock.GetCount()));
1866 return vrc;
1867}
1868
1869bool GuestProcessTool::IsRunning(void)
1870{
1871 AssertReturn(!pProcess.isNull(), true);
1872
1873 ProcessStatus_T procStatus = ProcessStatus_Undefined;
1874 HRESULT hr = pProcess->COMGETTER(Status(&procStatus));
1875 Assert(SUCCEEDED(hr));
1876
1877 if ( procStatus != ProcessStatus_Started
1878 && procStatus != ProcessStatus_Paused
1879 && procStatus != ProcessStatus_Terminating)
1880 {
1881 return false;
1882 }
1883
1884 return true;
1885}
1886
1887int GuestProcessTool::TerminatedOk(LONG *pExitCode)
1888{
1889 Assert(!pProcess.isNull());
1890 /* pExitCode is optional. */
1891
1892 if (!IsRunning())
1893 {
1894 LONG exitCode;
1895 HRESULT hr = pProcess->COMGETTER(ExitCode(&exitCode));
1896 Assert(SUCCEEDED(hr));
1897
1898 if (pExitCode)
1899 *pExitCode = exitCode;
1900
1901 if (exitCode != 0)
1902 return VERR_NOT_EQUAL; /** @todo Special guest control rc needed! */
1903 return VINF_SUCCESS;
1904 }
1905
1906 return VERR_INVALID_STATE; /** @todo Special guest control rc needed! */
1907}
1908
1909int GuestProcessTool::Wait(uint32_t fFlags, int *pGuestRc)
1910{
1911 return WaitEx(fFlags, NULL /* pStreamBlock */, pGuestRc);
1912}
1913
1914int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc)
1915{
1916 LogFlowThisFunc(("pSession=%p, fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n",
1917 pSession, fFlags, pStreamBlock, pGuestRc));
1918
1919 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
1920 Assert(!pProcess.isNull());
1921 /* Other parameters are optional. */
1922
1923 /* Can we parse the next block without waiting? */
1924 int vrc;
1925 if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)
1926 {
1927 AssertPtr(pStreamBlock);
1928 vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
1929 if (RT_SUCCESS(vrc))
1930 return vrc;
1931 }
1932
1933 /* Do the waiting. */
1934 uint32_t fWaitFlags = ProcessWaitForFlag_Terminate;
1935 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1936 fWaitFlags |= ProcessWaitForFlag_StdOut;
1937 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
1938 fWaitFlags |= ProcessWaitForFlag_StdErr;
1939
1940 LogFlowFunc(("waitFlags=0x%x\n", fWaitFlags));
1941
1942 /** @todo Decrease timeout. */
1943 uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS;
1944
1945 int guestRc;
1946 bool fDone = false;
1947
1948 BYTE byBuf[_64K];
1949 uint32_t cbRead;
1950
1951 bool fHandleStdOut = false;
1952 bool fHandleStdErr = false;
1953
1954 ProcessWaitResult_T waitRes;
1955 do
1956 {
1957 vrc = pProcess->waitFor(fWaitFlags,
1958 uTimeoutMS, waitRes, &guestRc);
1959 if (RT_FAILURE(vrc))
1960 break;
1961
1962 switch (waitRes)
1963 {
1964 case ProcessWaitResult_StdIn:
1965 vrc = VERR_NOT_IMPLEMENTED;
1966 break;
1967
1968 case ProcessWaitResult_StdOut:
1969 fHandleStdOut = true;
1970 break;
1971
1972 case ProcessWaitResult_StdErr:
1973 fHandleStdErr = true;
1974 break;
1975
1976 case ProcessWaitResult_WaitFlagNotSupported:
1977 if (fWaitFlags & ProcessWaitForFlag_StdOut)
1978 fHandleStdOut = true;
1979 if (fWaitFlags & ProcessWaitForFlag_StdErr)
1980 fHandleStdErr = true;
1981 /* Since waiting for stdout / stderr is not supported by the guest,
1982 * wait a bit to not hog the CPU too much when polling for data. */
1983 RTThreadSleep(1); /* Optional, don't check rc. */
1984 break;
1985
1986 case ProcessWaitResult_Error:
1987 vrc = VERR_GSTCTL_GUEST_ERROR;
1988 break;
1989
1990 case ProcessWaitResult_Terminate:
1991 fDone = true;
1992 break;
1993
1994 case ProcessWaitResult_Timeout:
1995 vrc = VERR_TIMEOUT;
1996 break;
1997
1998 case ProcessWaitResult_Start:
1999 case ProcessWaitResult_Status:
2000 /* Not used here, just skip. */
2001 break;
2002
2003 default:
2004 AssertReleaseMsgFailed(("Unhandled process wait result %ld\n", waitRes));
2005 break;
2006 }
2007
2008 if (fHandleStdOut)
2009 {
2010 vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
2011 uTimeoutMS, byBuf, sizeof(byBuf),
2012 &cbRead, &guestRc);
2013 if (RT_FAILURE(vrc))
2014 break;
2015
2016 if (cbRead)
2017 {
2018 LogFlowThisFunc(("Received %RU64 bytes from stdout\n", cbRead));
2019 vrc = mStdOut.AddData(byBuf, cbRead);
2020
2021 if ( RT_SUCCESS(vrc)
2022 && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK))
2023 {
2024 AssertPtr(pStreamBlock);
2025 vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
2026 if (RT_SUCCESS(vrc))
2027 fDone = true;
2028 }
2029 }
2030
2031 fHandleStdOut = false;
2032 }
2033
2034 if (fHandleStdErr)
2035 {
2036 vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf),
2037 uTimeoutMS, byBuf, sizeof(byBuf),
2038 &cbRead, &guestRc);
2039 if (RT_FAILURE(vrc))
2040 break;
2041
2042 if (cbRead)
2043 {
2044 LogFlowThisFunc(("Received %RU64 bytes from stderr\n", cbRead));
2045 vrc = mStdErr.AddData(byBuf, cbRead);
2046 }
2047
2048 fHandleStdErr = false;
2049 }
2050
2051 } while (!fDone && RT_SUCCESS(vrc));
2052
2053 LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%ld\n",
2054 vrc, guestRc, waitRes));
2055 if (pGuestRc)
2056 *pGuestRc = guestRc;
2057
2058 LogFlowFuncLeaveRC(vrc);
2059 return vrc;
2060}
2061
2062void GuestProcessTool::Terminate(void)
2063{
2064 LogFlowThisFuncEnter();
2065
2066 if (!pProcess.isNull())
2067 {
2068 /** @todo Add pProcess.Terminate() here as soon as it's implemented. */
2069
2070 Assert(pSession);
2071 int rc2 = pSession->processRemoveFromList(pProcess);
2072 AssertRC(rc2);
2073
2074 pProcess.setNull();
2075 }
2076
2077 LogFlowThisFuncLeave();
2078}
2079
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