VirtualBox

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

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

*: a few uint32_t warnings

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