VirtualBox

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

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

Main/GuestCtrl: Use active listeners instead of passive ones because of performance reasons (untested).

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

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