VirtualBox

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

Last change on this file since 55591 was 55591, checked in by vboxsync, 10 years ago

Main: Renamed IGuestSession::environment to IGuestSession::environmentChanges, IGuestSession::environmentSet to IGuestSession::environmentScheduleSet, IGuestSession::environmentUnset to IGuestSession::environmentScheduleUnset. Introduced read only IGuestSession::environmentBase attribute and associated IGuestSession::environmentGetBaseVariable and IGuestSession::environmentDoesBaseVariableExist for future exploitations. Changed IGuestProcess::environment back to it's originally documented behavior, though that means it will fail with VBOX_E_NOT_SUPPORTED until the session base environment is implemented.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 72.4 KB
Line 
1/* $Id: GuestProcessImpl.cpp 55591 2015-05-02 01:57:14Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest process handling.
4 */
5
6/*
7 * Copyright (C) 2012-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/**
19 * Locking rules:
20 * - When the main dispatcher (callbackDispatcher) is called it takes the
21 * WriteLock while dispatching to the various on* methods.
22 * - All other outer functions (accessible by Main) must not own a lock
23 * while waiting for a callback or for an event.
24 * - Only keep Read/WriteLocks as short as possible and only when necessary.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include "GuestProcessImpl.h"
31#include "GuestSessionImpl.h"
32#include "GuestCtrlImplPrivate.h"
33#include "ConsoleImpl.h"
34#include "VirtualBoxErrorInfoImpl.h"
35
36#include "Global.h"
37#include "AutoCaller.h"
38#include "VBoxEvents.h"
39
40#include <memory> /* For auto_ptr. */
41
42#include <iprt/asm.h>
43#include <iprt/cpp/utils.h> /* For unconst(). */
44#include <iprt/getopt.h>
45
46#include <VBox/com/listeners.h>
47
48#include <VBox/com/array.h>
49
50#ifdef LOG_GROUP
51 #undef LOG_GROUP
52#endif
53#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
54#include <VBox/log.h>
55
56
57class GuestProcessTask
58{
59public:
60
61 GuestProcessTask(GuestProcess *pProcess)
62 : mProcess(pProcess),
63 mRC(VINF_SUCCESS) { }
64
65 virtual ~GuestProcessTask(void) { }
66
67 int i_rc(void) const { return mRC; }
68 bool i_isOk(void) const { return RT_SUCCESS(mRC); }
69 const ComObjPtr<GuestProcess> &i_process(void) const { return mProcess; }
70
71protected:
72
73 const ComObjPtr<GuestProcess> mProcess;
74 int mRC;
75};
76
77class GuestProcessStartTask : public GuestProcessTask
78{
79public:
80
81 GuestProcessStartTask(GuestProcess *pProcess)
82 : GuestProcessTask(pProcess) { }
83};
84
85/**
86 * Internal listener class to serve events in an
87 * active manner, e.g. without polling delays.
88 */
89class GuestProcessListener
90{
91public:
92
93 GuestProcessListener(void)
94 {
95 }
96
97 HRESULT init(GuestProcess *pProcess)
98 {
99 AssertPtrReturn(pProcess, E_POINTER);
100 mProcess = pProcess;
101 return S_OK;
102 }
103
104 void uninit(void)
105 {
106 mProcess = NULL;
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 AssertPtrReturn(mProcess, E_POINTER);
118 int rc2 = mProcess->signalWaitEvent(aType, aEvent);
119#ifdef DEBUG
120 LogFlowThisFunc(("Signalling events of type=%RU32, pProcess=%p resulted in rc=%Rrc\n",
121 aType, &mProcess, rc2));
122#endif
123 break;
124 }
125
126 default:
127 AssertMsgFailed(("Unhandled event %RU32\n", aType));
128 break;
129 }
130
131 return S_OK;
132 }
133
134private:
135
136 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, ULONG aProcessID,
165 const GuestProcessStartupInfo &aProcInfo, const GuestEnvironment *pBaseEnv)
166{
167 LogFlowThisFunc(("aConsole=%p, aSession=%p, aProcessID=%RU32 pBaseEnv=%p\n",
168 aConsole, aSession, aProcessID, pBaseEnv));
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 hr = unconst(mEventSource).createObject();
187 if (FAILED(hr))
188 vrc = VERR_NO_MEMORY;
189 else
190 {
191 hr = mEventSource->init();
192 if (FAILED(hr))
193 vrc = VERR_COM_UNEXPECTED;
194 }
195 }
196
197 if (RT_SUCCESS(vrc))
198 {
199 try
200 {
201 GuestProcessListener *pListener = new GuestProcessListener();
202 ComObjPtr<GuestProcessListenerImpl> thisListener;
203 hr = thisListener.createObject();
204 if (SUCCEEDED(hr))
205 hr = thisListener->init(pListener, this);
206
207 if (SUCCEEDED(hr))
208 {
209 com::SafeArray <VBoxEventType_T> eventTypes;
210 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
211 eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
212 eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
213 hr = mEventSource->RegisterListener(thisListener,
214 ComSafeArrayAsInParam(eventTypes),
215 TRUE /* Active listener */);
216 if (SUCCEEDED(hr))
217 {
218 vrc = baseInit();
219 if (RT_SUCCESS(vrc))
220 {
221 mLocalListener = thisListener;
222 }
223 }
224 else
225 vrc = VERR_COM_UNEXPECTED;
226 }
227 else
228 vrc = VERR_COM_UNEXPECTED;
229 }
230 catch(std::bad_alloc &)
231 {
232 vrc = VERR_NO_MEMORY;
233 }
234 }
235
236 if (RT_SUCCESS(vrc))
237 {
238 mData.mProcess = aProcInfo;
239 mData.mpSessionBaseEnv = pBaseEnv;
240 if (pBaseEnv)
241 pBaseEnv->retainConst();
242 mData.mExitCode = 0;
243 mData.mPID = 0;
244 mData.mLastError = VINF_SUCCESS;
245 mData.mStatus = ProcessStatus_Undefined;
246 /* Everything else will be set by the actual starting routine. */
247
248 /* Confirm a successful initialization when it's the case. */
249 autoInitSpan.setSucceeded();
250
251 return vrc;
252 }
253
254 autoInitSpan.setFailed();
255 return vrc;
256#endif
257}
258
259/**
260 * Uninitializes the instance.
261 * Called from FinalRelease() or IGuestSession::uninit().
262 */
263void GuestProcess::uninit(void)
264{
265 /* Enclose the state transition Ready->InUninit->NotReady. */
266 AutoUninitSpan autoUninitSpan(this);
267 if (autoUninitSpan.uninitDone())
268 return;
269
270#ifdef VBOX_WITH_GUEST_CONTROL
271 LogFlowThisFunc(("mExe=%s, PID=%RU32\n", mData.mProcess.mExecutable.c_str(), mData.mPID));
272
273 /* Terminate process if not already done yet. */
274 int guestRc = VINF_SUCCESS;
275 int vrc = i_terminateProcess(30 * 1000, &guestRc); /** @todo Make timeouts configurable. */
276 /* Note: Don't return here yet; first uninit all other stuff in
277 * case of failure. */
278
279 if (mData.mpSessionBaseEnv)
280 {
281 mData.mpSessionBaseEnv->releaseConst();
282 mData.mpSessionBaseEnv = NULL;
283 }
284
285 baseUninit();
286
287 LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n",
288 vrc, guestRc));
289#endif
290}
291
292// implementation of public getters/setters for attributes
293/////////////////////////////////////////////////////////////////////////////
294HRESULT GuestProcess::getArguments(std::vector<com::Utf8Str> &aArguments)
295{
296#ifndef VBOX_WITH_GUEST_CONTROL
297 ReturnComNotImplemented();
298#else
299 LogFlowThisFuncEnter();
300
301 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
302 aArguments = mData.mProcess.mArguments;
303 return S_OK;
304#endif /* VBOX_WITH_GUEST_CONTROL */
305}
306
307HRESULT GuestProcess::getEnvironment(std::vector<com::Utf8Str> &aEnvironment)
308{
309#ifndef VBOX_WTIH_GUEST_CONTROL
310 ReturnComNotImplemented();
311#else
312 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); /* (Paranoia since both environment objects are immutable.) */
313 HRESULT hrc;
314 if (mData.mpSessionBaseEnv)
315 {
316 int vrc;
317 if (mData.mProcess.mEnvironmentChanges.count() == 0)
318 vrc = mData.mpSessionBaseEnv->queryPutEnvArray(&aEnvironment);
319 else
320 {
321 GuestEnvironment TmpEnv;
322 vrc = TmpEnv.copy(*mData.mpSessionBaseEnv);
323 if (RT_SUCCESS(vrc))
324 {
325 vrc = TmpEnv.applyChanges(mData.mProcess.mEnvironmentChanges);
326 if (RT_SUCCESS(rc))
327 vrc = TmpEnv.queryPutEnvArray(&aEnvironment);
328 }
329 }
330 hrc = Global::vboxStatusCodeToCOM(vrc);
331 }
332 else
333 hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
334 LogFlowThisFuncLeave();
335 return hrc;
336#endif
337}
338
339HRESULT GuestProcess::getEventSource(ComPtr<IEventSource> &aEventSource)
340{
341#ifndef VBOX_WITH_GUEST_CONTROL
342 ReturnComNotImplemented();
343#else
344 LogFlowThisFuncEnter();
345
346 // no need to lock - lifetime constant
347 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
348
349 LogFlowThisFuncLeave();
350 return S_OK;
351#endif /* VBOX_WITH_GUEST_CONTROL */
352}
353
354HRESULT GuestProcess::getExecutablePath(com::Utf8Str &aExecutablePath)
355{
356#ifndef VBOX_WITH_GUEST_CONTROL
357 ReturnComNotImplemented();
358#else
359 LogFlowThisFuncEnter();
360
361 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
362
363 aExecutablePath = mData.mProcess.mExecutable;
364
365 return S_OK;
366#endif /* VBOX_WITH_GUEST_CONTROL */
367}
368
369HRESULT GuestProcess::getExitCode(LONG *aExitCode)
370{
371#ifndef VBOX_WITH_GUEST_CONTROL
372 ReturnComNotImplemented();
373#else
374 LogFlowThisFuncEnter();
375
376 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
377
378 *aExitCode = mData.mExitCode;
379
380 return S_OK;
381#endif /* VBOX_WITH_GUEST_CONTROL */
382}
383
384HRESULT GuestProcess::getName(com::Utf8Str &aName)
385{
386#ifndef VBOX_WITH_GUEST_CONTROL
387 ReturnComNotImplemented();
388#else
389 LogFlowThisFuncEnter();
390
391 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
392
393 aName = mData.mProcess.mName;
394
395 return S_OK;
396#endif /* VBOX_WITH_GUEST_CONTROL */
397}
398
399HRESULT GuestProcess::getPID(ULONG *aPID)
400{
401#ifndef VBOX_WITH_GUEST_CONTROL
402 ReturnComNotImplemented();
403#else
404 LogFlowThisFuncEnter();
405
406 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
407
408 *aPID = mData.mPID;
409
410 return S_OK;
411#endif /* VBOX_WITH_GUEST_CONTROL */
412}
413
414HRESULT GuestProcess::getStatus(ProcessStatus_T *aStatus)
415{
416#ifndef VBOX_WITH_GUEST_CONTROL
417 ReturnComNotImplemented();
418#else
419 LogFlowThisFuncEnter();
420
421 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
422
423 *aStatus = mData.mStatus;
424
425 return S_OK;
426#endif /* VBOX_WITH_GUEST_CONTROL */
427}
428
429// private methods
430/////////////////////////////////////////////////////////////////////////////
431
432int GuestProcess::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
433{
434 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
435 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
436#ifdef DEBUG
437 LogFlowThisFunc(("uPID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
438 mData.mPID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
439#endif
440
441 int vrc;
442 switch (pCbCtx->uFunction)
443 {
444 case GUEST_DISCONNECTED:
445 {
446 vrc = i_onGuestDisconnected(pCbCtx, pSvcCb);
447 break;
448 }
449
450 case GUEST_EXEC_STATUS:
451 {
452 vrc = i_onProcessStatusChange(pCbCtx, pSvcCb);
453 break;
454 }
455
456 case GUEST_EXEC_OUTPUT:
457 {
458 vrc = i_onProcessOutput(pCbCtx, pSvcCb);
459 break;
460 }
461
462 case GUEST_EXEC_INPUT_STATUS:
463 {
464 vrc = i_onProcessInputStatus(pCbCtx, pSvcCb);
465 break;
466 }
467
468 default:
469 /* Silently ignore not implemented functions. */
470 vrc = VERR_NOT_SUPPORTED;
471 break;
472 }
473
474#ifdef DEBUG
475 LogFlowFuncLeaveRC(vrc);
476#endif
477 return vrc;
478}
479
480/**
481 * Checks if the current assigned PID matches another PID (from a callback).
482 *
483 * In protocol v1 we don't have the possibility to terminate/kill
484 * processes so it can happen that a formerly started process A
485 * (which has the context ID 0 (session=0, process=0, count=0) will
486 * send a delayed message to the host if this process has already
487 * been discarded there and the same context ID was reused by
488 * a process B. Process B in turn then has a different guest PID.
489 *
490 * Note: This also can happen when restoring from a saved state which
491 * had a guest process running.
492 *
493 * @return IPRT status code.
494 * @param uPID PID to check.
495 */
496inline int GuestProcess::i_checkPID(uint32_t uPID)
497{
498 int rc = VINF_SUCCESS;
499
500 /* Was there a PID assigned yet? */
501 if (mData.mPID)
502 {
503 if (RT_UNLIKELY(mData.mPID != uPID))
504 {
505 LogFlowFunc(("Stale guest process (PID=%RU32) sent data to a newly started process (pProcesS=%p, PID=%RU32, status=%RU32)\n",
506 uPID, this, mData.mPID, mData.mStatus));
507 rc = VERR_NOT_FOUND;
508 }
509 }
510
511 return rc;
512}
513
514/* static */
515Utf8Str GuestProcess::i_guestErrorToString(int guestRc)
516{
517 Utf8Str strError;
518
519 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
520 switch (guestRc)
521 {
522 case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
523 strError += Utf8StrFmt(tr("The specified file was not found on guest"));
524 break;
525
526 case VERR_INVALID_VM_HANDLE:
527 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
528 break;
529
530 case VERR_HGCM_SERVICE_NOT_FOUND:
531 strError += Utf8StrFmt(tr("The guest execution service is not available"));
532 break;
533
534 case VERR_PATH_NOT_FOUND:
535 strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
536 break;
537
538 case VERR_BAD_EXE_FORMAT:
539 strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
540 break;
541
542 case VERR_AUTHENTICATION_FAILURE:
543 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
544 break;
545
546 case VERR_INVALID_NAME:
547 strError += Utf8StrFmt(tr("The specified file is an invalid name"));
548 break;
549
550 case VERR_TIMEOUT:
551 strError += Utf8StrFmt(tr("The guest did not respond within time"));
552 break;
553
554 case VERR_CANCELLED:
555 strError += Utf8StrFmt(tr("The execution operation was canceled"));
556 break;
557
558 case VERR_PERMISSION_DENIED:
559 strError += Utf8StrFmt(tr("Invalid user/password credentials"));
560 break;
561
562 case VERR_MAX_PROCS_REACHED:
563 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
564 break;
565
566 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
567 strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
568 break;
569
570 case VERR_NOT_FOUND:
571 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
572 break;
573
574 default:
575 strError += Utf8StrFmt("%Rrc", guestRc);
576 break;
577 }
578
579 return strError;
580}
581
582inline bool GuestProcess::i_isAlive(void)
583{
584 return ( mData.mStatus == ProcessStatus_Started
585 || mData.mStatus == ProcessStatus_Paused
586 || mData.mStatus == ProcessStatus_Terminating);
587}
588
589inline bool GuestProcess::i_hasEnded(void)
590{
591 return ( mData.mStatus == ProcessStatus_TerminatedNormally
592 || mData.mStatus == ProcessStatus_TerminatedSignal
593 || mData.mStatus == ProcessStatus_TerminatedAbnormally
594 || mData.mStatus == ProcessStatus_TimedOutKilled
595 || mData.mStatus == ProcessStatus_TimedOutAbnormally
596 || mData.mStatus == ProcessStatus_Down
597 || mData.mStatus == ProcessStatus_Error);
598}
599
600int GuestProcess::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
601{
602 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
603 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
604
605 int vrc = i_setProcessStatus(ProcessStatus_Down, VINF_SUCCESS);
606
607 LogFlowFuncLeaveRC(vrc);
608 return vrc;
609}
610
611int GuestProcess::i_onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
612{
613 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
614 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
615 /* pCallback is optional. */
616
617 if (pSvcCbData->mParms < 5)
618 return VERR_INVALID_PARAMETER;
619
620 CALLBACKDATA_PROC_INPUT dataCb;
621 /* pSvcCb->mpaParms[0] always contains the context ID. */
622 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
623 AssertRCReturn(vrc, vrc);
624 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus);
625 AssertRCReturn(vrc, vrc);
626 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
627 AssertRCReturn(vrc, vrc);
628 vrc = pSvcCbData->mpaParms[4].getUInt32(&dataCb.uProcessed);
629 AssertRCReturn(vrc, vrc);
630
631 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32\n",
632 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed));
633
634 vrc = i_checkPID(dataCb.uPID);
635 if (RT_SUCCESS(vrc))
636 {
637 ProcessInputStatus_T inputStatus = ProcessInputStatus_Undefined;
638 switch (dataCb.uStatus)
639 {
640 case INPUT_STS_WRITTEN:
641 inputStatus = ProcessInputStatus_Written;
642 break;
643 case INPUT_STS_ERROR:
644 inputStatus = ProcessInputStatus_Broken;
645 break;
646 case INPUT_STS_TERMINATED:
647 inputStatus = ProcessInputStatus_Broken;
648 break;
649 case INPUT_STS_OVERFLOW:
650 inputStatus = ProcessInputStatus_Overflow;
651 break;
652 case INPUT_STS_UNDEFINED:
653 /* Fall through is intentional. */
654 default:
655 AssertMsg(!dataCb.uProcessed, ("Processed data is not 0 in undefined input state\n"));
656 break;
657 }
658
659 if (inputStatus != ProcessInputStatus_Undefined)
660 {
661 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
662
663 /* Copy over necessary data before releasing lock again. */
664 uint32_t uPID = mData.mPID;
665 /** @todo Also handle mSession? */
666
667 alock.release(); /* Release lock before firing off event. */
668
669 fireGuestProcessInputNotifyEvent(mEventSource, mSession, this,
670 uPID, 0 /* StdIn */, dataCb.uProcessed, inputStatus);
671 }
672 }
673
674 LogFlowFuncLeaveRC(vrc);
675 return vrc;
676}
677
678int GuestProcess::i_onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
679{
680 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
681 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
682
683 return VERR_NOT_IMPLEMENTED;
684}
685
686int GuestProcess::i_onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
687{
688 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
689 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
690
691 if (pSvcCbData->mParms < 5)
692 return VERR_INVALID_PARAMETER;
693
694 CALLBACKDATA_PROC_STATUS dataCb;
695 /* pSvcCb->mpaParms[0] always contains the context ID. */
696 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
697 AssertRCReturn(vrc, vrc);
698 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus);
699 AssertRCReturn(vrc, vrc);
700 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
701 AssertRCReturn(vrc, vrc);
702 vrc = pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
703 AssertRCReturn(vrc, vrc);
704
705 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32\n",
706 dataCb.uPID, dataCb.uStatus, dataCb.uFlags));
707
708 vrc = i_checkPID(dataCb.uPID);
709 if (RT_SUCCESS(vrc))
710 {
711 ProcessStatus_T procStatus = ProcessStatus_Undefined;
712 int procRc = VINF_SUCCESS;
713
714 switch (dataCb.uStatus)
715 {
716 case PROC_STS_STARTED:
717 {
718 procStatus = ProcessStatus_Started;
719
720 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
721 mData.mPID = dataCb.uPID; /* Set the process PID. */
722 break;
723 }
724
725 case PROC_STS_TEN:
726 {
727 procStatus = ProcessStatus_TerminatedNormally;
728
729 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
730 mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */
731 break;
732 }
733
734 case PROC_STS_TES:
735 {
736 procStatus = ProcessStatus_TerminatedSignal;
737
738 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
739 mData.mExitCode = dataCb.uFlags; /* Contains the signal. */
740 break;
741 }
742
743 case PROC_STS_TEA:
744 {
745 procStatus = ProcessStatus_TerminatedAbnormally;
746 break;
747 }
748
749 case PROC_STS_TOK:
750 {
751 procStatus = ProcessStatus_TimedOutKilled;
752 break;
753 }
754
755 case PROC_STS_TOA:
756 {
757 procStatus = ProcessStatus_TimedOutAbnormally;
758 break;
759 }
760
761 case PROC_STS_DWN:
762 {
763 procStatus = ProcessStatus_Down;
764 break;
765 }
766
767 case PROC_STS_ERROR:
768 {
769 procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */
770 procStatus = ProcessStatus_Error;
771 break;
772 }
773
774 case PROC_STS_UNDEFINED:
775 default:
776 {
777 /* Silently skip this request. */
778 procStatus = ProcessStatus_Undefined;
779 break;
780 }
781 }
782
783 LogFlowThisFunc(("Got rc=%Rrc, procSts=%RU32, procRc=%Rrc\n",
784 vrc, procStatus, procRc));
785
786 /* Set the process status. */
787 int rc2 = i_setProcessStatus(procStatus, procRc);
788 if (RT_SUCCESS(vrc))
789 vrc = rc2;
790 }
791
792 LogFlowFuncLeaveRC(vrc);
793 return vrc;
794}
795
796int GuestProcess::i_onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
797{
798 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
799
800 if (pSvcCbData->mParms < 5)
801 return VERR_INVALID_PARAMETER;
802
803 CALLBACKDATA_PROC_OUTPUT dataCb;
804 /* pSvcCb->mpaParms[0] always contains the context ID. */
805 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
806 AssertRCReturn(vrc, vrc);
807 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uHandle);
808 AssertRCReturn(vrc, vrc);
809 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
810 AssertRCReturn(vrc, vrc);
811 vrc = pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
812 AssertRCReturn(vrc, vrc);
813
814 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32\n",
815 dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData));
816
817 vrc = i_checkPID(dataCb.uPID);
818 if (RT_SUCCESS(vrc))
819 {
820 com::SafeArray<BYTE> data((size_t)dataCb.cbData);
821 if (dataCb.cbData)
822 data.initFrom((BYTE*)dataCb.pvData, dataCb.cbData);
823
824 fireGuestProcessOutputEvent(mEventSource, mSession, this,
825 mData.mPID, dataCb.uHandle, dataCb.cbData, ComSafeArrayAsInParam(data));
826 }
827
828 LogFlowFuncLeaveRC(vrc);
829 return vrc;
830}
831
832/**
833 * Called by IGuestSession right before this process gets
834 * removed from the public process list.
835 */
836int GuestProcess::i_onRemove(void)
837{
838 LogFlowThisFuncEnter();
839
840 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
841
842 int vrc = VINF_SUCCESS;
843
844 /*
845 * Note: The event source stuff holds references to this object,
846 * so make sure that this is cleaned up *before* calling uninit().
847 */
848 if (!mEventSource.isNull())
849 {
850 mEventSource->UnregisterListener(mLocalListener);
851
852 mLocalListener.setNull();
853 unconst(mEventSource).setNull();
854 }
855
856 LogFlowFuncLeaveRC(vrc);
857 return vrc;
858}
859
860int GuestProcess::i_readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
861 void *pvData, size_t cbData, uint32_t *pcbRead, int *pGuestRc)
862{
863 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n",
864 mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc));
865 AssertReturn(uSize, VERR_INVALID_PARAMETER);
866 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
867 AssertReturn(cbData >= uSize, VERR_INVALID_PARAMETER);
868 /* pcbRead is optional. */
869
870 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
871
872 if ( mData.mStatus != ProcessStatus_Started
873 /* Skip reading if the process wasn't started with the appropriate
874 * flags. */
875 || ( ( uHandle == OUTPUT_HANDLE_ID_STDOUT
876 || uHandle == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED)
877 && !(mData.mProcess.mFlags & ProcessCreateFlag_WaitForStdOut))
878 || ( uHandle == OUTPUT_HANDLE_ID_STDERR
879 && !(mData.mProcess.mFlags & ProcessCreateFlag_WaitForStdErr))
880 )
881 {
882 if (pcbRead)
883 *pcbRead = 0;
884 if (pGuestRc)
885 *pGuestRc = VINF_SUCCESS;
886 return VINF_SUCCESS; /* Nothing to read anymore. */
887 }
888
889 int vrc;
890
891 GuestWaitEvent *pEvent = NULL;
892 GuestEventTypes eventTypes;
893 try
894 {
895 /*
896 * On Guest Additions < 4.3 there is no guarantee that the process status
897 * change arrives *after* the output event, e.g. if this was the last output
898 * block being read and the process will report status "terminate".
899 * So just skip checking for process status change and only wait for the
900 * output event.
901 */
902 if (mSession->i_getProtocolVersion() >= 2)
903 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
904 eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
905
906 vrc = registerWaitEvent(eventTypes, &pEvent);
907 }
908 catch (std::bad_alloc)
909 {
910 vrc = VERR_NO_MEMORY;
911 }
912
913 if (RT_FAILURE(vrc))
914 return vrc;
915
916 if (RT_SUCCESS(vrc))
917 {
918 VBOXHGCMSVCPARM paParms[8];
919 int i = 0;
920 paParms[i++].setUInt32(pEvent->ContextID());
921 paParms[i++].setUInt32(mData.mPID);
922 paParms[i++].setUInt32(uHandle);
923 paParms[i++].setUInt32(0 /* Flags, none set yet. */);
924
925 alock.release(); /* Drop the write lock before sending. */
926
927 vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms);
928 }
929
930 if (RT_SUCCESS(vrc))
931 vrc = i_waitForOutput(pEvent, uHandle, uTimeoutMS,
932 pvData, cbData, pcbRead);
933
934 unregisterWaitEvent(pEvent);
935
936 LogFlowFuncLeaveRC(vrc);
937 return vrc;
938}
939
940/* Does not do locking; caller is responsible for that! */
941int GuestProcess::i_setProcessStatus(ProcessStatus_T procStatus, int procRc)
942{
943 LogFlowThisFuncEnter();
944
945 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
946
947 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, procRc=%Rrc\n",
948 mData.mStatus, procStatus, procRc));
949
950 if (procStatus == ProcessStatus_Error)
951 {
952 AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc));
953 /* Do not allow overwriting an already set error. If this happens
954 * this means we forgot some error checking/locking somewhere. */
955 AssertMsg(RT_SUCCESS(mData.mLastError), ("Guest rc already set (to %Rrc)\n", mData.mLastError));
956 }
957 else
958 AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
959
960 int rc = VINF_SUCCESS;
961
962 if (mData.mStatus != procStatus) /* Was there a process status change? */
963 {
964 mData.mStatus = procStatus;
965 mData.mLastError = procRc;
966
967 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
968 HRESULT hr = errorInfo.createObject();
969 ComAssertComRC(hr);
970 if (RT_FAILURE(mData.mLastError))
971 {
972 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, mData.mLastError,
973 COM_IIDOF(IGuestProcess), getComponentName(),
974 i_guestErrorToString(mData.mLastError));
975 ComAssertComRC(hr);
976 }
977
978 /* Copy over necessary data before releasing lock again. */
979 uint32_t uPID = mData.mPID;
980 /** @todo Also handle mSession? */
981
982 alock.release(); /* Release lock before firing off event. */
983
984 fireGuestProcessStateChangedEvent(mEventSource, mSession, this,
985 uPID, procStatus, errorInfo);
986#if 0
987 /*
988 * On Guest Additions < 4.3 there is no guarantee that outstanding
989 * requests will be delivered to the host after the process has ended,
990 * so just cancel all waiting events here to not let clients run
991 * into timeouts.
992 */
993 if ( mSession->getProtocolVersion() < 2
994 && hasEnded())
995 {
996 LogFlowThisFunc(("Process ended, canceling outstanding wait events ...\n"));
997 rc = cancelWaitEvents();
998 }
999#endif
1000 }
1001
1002 return rc;
1003}
1004
1005/* static */
1006HRESULT GuestProcess::i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
1007{
1008 AssertPtr(pInterface);
1009 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
1010
1011 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(guestRc).c_str());
1012}
1013
1014int GuestProcess::i_startProcess(uint32_t uTimeoutMS, int *pGuestRc)
1015{
1016 LogFlowThisFunc(("uTimeoutMS=%RU32, procExe=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n",
1017 uTimeoutMS, mData.mProcess.mExecutable.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags,
1018 mSession->i_getId()));
1019
1020 /* Wait until the caller function (if kicked off by a thread)
1021 * has returned and continue operation. */
1022 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1023
1024 mData.mStatus = ProcessStatus_Starting;
1025
1026 int vrc;
1027
1028 GuestWaitEvent *pEvent = NULL;
1029 GuestEventTypes eventTypes;
1030 try
1031 {
1032 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1033
1034 vrc = registerWaitEvent(eventTypes, &pEvent);
1035 }
1036 catch (std::bad_alloc)
1037 {
1038 vrc = VERR_NO_MEMORY;
1039 }
1040
1041 if (RT_FAILURE(vrc))
1042 return vrc;
1043
1044 GuestSession *pSession = mSession;
1045 AssertPtr(pSession);
1046 uint32_t const uProtocol = pSession->i_getProtocolVersion();
1047
1048 const GuestCredentials &sessionCreds = pSession->i_getCredentials();
1049
1050
1051 /* Prepare arguments. */
1052 char *pszArgs = NULL;
1053 size_t cArgs = mData.mProcess.mArguments.size();
1054 if (cArgs >= UINT32_MAX)
1055 vrc = VERR_BUFFER_OVERFLOW;
1056
1057 if ( RT_SUCCESS(vrc)
1058 && cArgs)
1059 {
1060 char const **papszArgv = (char const **)RTMemAlloc((cArgs + 1) * sizeof(papszArgv[0]));
1061 AssertReturn(papszArgv, VERR_NO_MEMORY);
1062
1063 for (size_t i = 0; i < cArgs; i++)
1064 {
1065 papszArgv[i] = mData.mProcess.mArguments[i].c_str();
1066 AssertPtr(papszArgv[i]);
1067 }
1068 papszArgv[cArgs] = NULL;
1069
1070 if (uProtocol < UINT32_C(0xdeadbeef) ) /** @todo implement a way of sending argv[0], best idea is a new command. */
1071 vrc = RTGetOptArgvToString(&pszArgs, papszArgv + 1, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
1072 else
1073 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
1074
1075 RTMemFree(papszArgv);
1076 }
1077
1078 /* Calculate arguments size (in bytes). */
1079 size_t cbArgs = 0;
1080 if (RT_SUCCESS(vrc))
1081 cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
1082
1083 /* Prepare environment. */
1084 size_t cbEnvBlock;
1085 char *pszzEnvBlock;
1086 if (RT_SUCCESS(vrc))
1087 vrc = mData.mProcess.mEnvironmentChanges.queryUtf8Block(&pszzEnvBlock, &cbEnvBlock);
1088
1089 if (RT_SUCCESS(vrc))
1090 {
1091 /* Prepare HGCM call. */
1092 VBOXHGCMSVCPARM paParms[16];
1093 int i = 0;
1094 paParms[i++].setUInt32(pEvent->ContextID());
1095 paParms[i++].setCppString(mData.mProcess.mExecutable);
1096 paParms[i++].setUInt32(mData.mProcess.mFlags);
1097 paParms[i++].setUInt32((uint32_t)mData.mProcess.mArguments.size());
1098 paParms[i++].setPointer(pszArgs, (uint32_t)cbArgs);
1099 paParms[i++].setUInt32(mData.mProcess.mEnvironmentChanges.count());
1100 paParms[i++].setUInt32((uint32_t)cbEnvBlock);
1101 paParms[i++].setPointer(pszzEnvBlock, (uint32_t)cbEnvBlock);
1102 if (uProtocol < 2)
1103 {
1104 /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
1105 * call. In newer protocols these credentials are part of the opened guest
1106 * session, so not needed anymore here. */
1107 paParms[i++].setCppString(sessionCreds.mUser);
1108 paParms[i++].setCppString(sessionCreds.mPassword);
1109 }
1110 /*
1111 * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
1112 * until the process was started - the process itself then gets an infinite timeout for execution.
1113 * This is handy when we want to start a process inside a worker thread within a certain timeout
1114 * but let the started process perform lengthly operations then.
1115 */
1116 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1117 paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
1118 else
1119 paParms[i++].setUInt32(mData.mProcess.mTimeoutMS);
1120 if (uProtocol >= 2)
1121 {
1122 paParms[i++].setUInt32(mData.mProcess.mPriority);
1123 /* CPU affinity: We only support one CPU affinity block at the moment,
1124 * so that makes up to 64 CPUs total. This can be more in the future. */
1125 paParms[i++].setUInt32(1);
1126 /* The actual CPU affinity blocks. */
1127 paParms[i++].setPointer((void *)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
1128 }
1129
1130 alock.release(); /* Drop the write lock before sending. */
1131
1132 vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
1133 if (RT_FAILURE(vrc))
1134 {
1135 int rc2 = i_setProcessStatus(ProcessStatus_Error, vrc);
1136 AssertRC(rc2);
1137 }
1138
1139 mData.mProcess.mEnvironmentChanges.freeUtf8Block(pszzEnvBlock);
1140 }
1141
1142 if (pszArgs)
1143 RTStrFree(pszArgs);
1144
1145 if (RT_SUCCESS(vrc))
1146 vrc = i_waitForStatusChange(pEvent, uTimeoutMS,
1147 NULL /* Process status */, pGuestRc);
1148 unregisterWaitEvent(pEvent);
1149
1150 LogFlowFuncLeaveRC(vrc);
1151 return vrc;
1152}
1153
1154int GuestProcess::i_startProcessAsync(void)
1155{
1156 LogFlowThisFuncEnter();
1157
1158 int vrc;
1159
1160 try
1161 {
1162 /* Asynchronously start the process on the guest by kicking off a
1163 * worker thread. */
1164 std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
1165 AssertReturn(pTask->i_isOk(), pTask->i_rc());
1166
1167 vrc = RTThreadCreate(NULL, GuestProcess::i_startProcessThread,
1168 (void *)pTask.get(), 0,
1169 RTTHREADTYPE_MAIN_WORKER, 0,
1170 "gctlPrcStart");
1171 if (RT_SUCCESS(vrc))
1172 {
1173 /* pTask is now owned by startProcessThread(), so release it. */
1174 pTask.release();
1175 }
1176 }
1177 catch(std::bad_alloc &)
1178 {
1179 vrc = VERR_NO_MEMORY;
1180 }
1181
1182 LogFlowFuncLeaveRC(vrc);
1183 return vrc;
1184}
1185
1186/* static */
1187DECLCALLBACK(int) GuestProcess::i_startProcessThread(RTTHREAD Thread, void *pvUser)
1188{
1189 LogFlowFunc(("pvUser=%p\n", pvUser));
1190
1191 std::auto_ptr<GuestProcessStartTask> pTask(static_cast<GuestProcessStartTask*>(pvUser));
1192 AssertPtr(pTask.get());
1193
1194 const ComObjPtr<GuestProcess> pProcess(pTask->i_process());
1195 Assert(!pProcess.isNull());
1196
1197 AutoCaller autoCaller(pProcess);
1198 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1199
1200 int vrc = pProcess->i_startProcess(30 * 1000 /* 30s timeout */,
1201 NULL /* Guest rc, ignored */);
1202 /* Nothing to do here anymore. */
1203
1204 LogFlowFunc(("pProcess=%p returning rc=%Rrc\n", (GuestProcess *)pProcess, vrc));
1205 return vrc;
1206}
1207
1208int GuestProcess::i_terminateProcess(uint32_t uTimeoutMS, int *pGuestRc)
1209{
1210 /* pGuestRc is optional. */
1211 LogFlowThisFunc(("uTimeoutMS=%RU32\n", uTimeoutMS));
1212
1213 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1214
1215 int vrc = VINF_SUCCESS;
1216
1217 if (mData.mStatus != ProcessStatus_Started)
1218 {
1219 LogFlowThisFunc(("Process not in started state (state is %RU32), skipping termination\n",
1220 mData.mStatus));
1221 }
1222 else
1223 {
1224 AssertPtr(mSession);
1225 /* Note: VBox < 4.3 (aka protocol version 1) does not
1226 * support this, so just skip. */
1227 if (mSession->i_getProtocolVersion() < 2)
1228 vrc = VERR_NOT_SUPPORTED;
1229
1230 if (RT_SUCCESS(vrc))
1231 {
1232 GuestWaitEvent *pEvent = NULL;
1233 GuestEventTypes eventTypes;
1234 try
1235 {
1236 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1237
1238 vrc = registerWaitEvent(eventTypes, &pEvent);
1239 }
1240 catch (std::bad_alloc)
1241 {
1242 vrc = VERR_NO_MEMORY;
1243 }
1244
1245 if (RT_FAILURE(vrc))
1246 return vrc;
1247
1248 VBOXHGCMSVCPARM paParms[4];
1249 int i = 0;
1250 paParms[i++].setUInt32(pEvent->ContextID());
1251 paParms[i++].setUInt32(mData.mPID);
1252
1253 alock.release(); /* Drop the write lock before sending. */
1254
1255 vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
1256 if (RT_SUCCESS(vrc))
1257 vrc = i_waitForStatusChange(pEvent, uTimeoutMS,
1258 NULL /* ProcessStatus */, pGuestRc);
1259 unregisterWaitEvent(pEvent);
1260 }
1261 }
1262
1263 LogFlowFuncLeaveRC(vrc);
1264 return vrc;
1265}
1266
1267/* static */
1268ProcessWaitResult_T GuestProcess::i_waitFlagsToResultEx(uint32_t fWaitFlags,
1269 ProcessStatus_T oldStatus, ProcessStatus_T newStatus,
1270 uint32_t uProcFlags, uint32_t uProtocol)
1271{
1272 ProcessWaitResult_T waitResult = ProcessWaitResult_None;
1273
1274 switch (newStatus)
1275 {
1276 case ProcessStatus_TerminatedNormally:
1277 case ProcessStatus_TerminatedSignal:
1278 case ProcessStatus_TerminatedAbnormally:
1279 case ProcessStatus_Down:
1280 /* Nothing to wait for anymore. */
1281 waitResult = ProcessWaitResult_Terminate;
1282 break;
1283
1284 case ProcessStatus_TimedOutKilled:
1285 case ProcessStatus_TimedOutAbnormally:
1286 /* Dito. */
1287 waitResult = ProcessWaitResult_Timeout;
1288 break;
1289
1290 case ProcessStatus_Started:
1291 switch (oldStatus)
1292 {
1293 case ProcessStatus_Undefined:
1294 case ProcessStatus_Starting:
1295 /* Also wait for process start. */
1296 if (fWaitFlags & ProcessWaitForFlag_Start)
1297 waitResult = ProcessWaitResult_Start;
1298 else
1299 {
1300 /*
1301 * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the
1302 * caller is not interested in getting further process statuses -- so just don't notify
1303 * anything here anymore and return.
1304 */
1305 if (uProcFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1306 waitResult = ProcessWaitResult_Start;
1307 }
1308 break;
1309
1310 case ProcessStatus_Started:
1311 /* Only wait for process start. */
1312 if (fWaitFlags == ProcessWaitForFlag_Start)
1313 waitResult = ProcessWaitResult_Start;
1314 break;
1315
1316 default:
1317 AssertMsgFailed(("Unhandled old status %RU32 before new status 'started'\n",
1318 oldStatus));
1319 waitResult = ProcessWaitResult_Start;
1320 break;
1321 }
1322 break;
1323
1324 case ProcessStatus_Error:
1325 /* Nothing to wait for anymore. */
1326 waitResult = ProcessWaitResult_Error;
1327 break;
1328
1329 case ProcessStatus_Undefined:
1330 case ProcessStatus_Starting:
1331 /* No result available yet, leave wait
1332 * flags untouched. */
1333 break;
1334 }
1335
1336 if (newStatus == ProcessStatus_Started)
1337 {
1338 /**
1339 * Filter out waits which are *not* supported using
1340 * older guest control Guest Additions.
1341 *
1342 ** @todo ProcessWaitForFlag_Std* flags are not implemented yet.
1343 */
1344 if (uProtocol < 99) /* See @todo above. */
1345 {
1346 if ( waitResult == ProcessWaitResult_None
1347 /* We don't support waiting for stdin, out + err,
1348 * just skip waiting then. */
1349 && ( (fWaitFlags & ProcessWaitForFlag_StdIn)
1350 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1351 || (fWaitFlags & ProcessWaitForFlag_StdErr)
1352 )
1353 )
1354 {
1355 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
1356 waitResult = ProcessWaitResult_WaitFlagNotSupported;
1357 }
1358 }
1359 }
1360
1361#ifdef DEBUG
1362 LogFlowFunc(("oldStatus=%RU32, newStatus=%RU32, fWaitFlags=0x%x, waitResult=%RU32\n",
1363 oldStatus, newStatus, fWaitFlags, waitResult));
1364#endif
1365 return waitResult;
1366}
1367
1368ProcessWaitResult_T GuestProcess::i_waitFlagsToResult(uint32_t fWaitFlags)
1369{
1370 AssertPtr(mSession);
1371 return GuestProcess::i_waitFlagsToResultEx(fWaitFlags,
1372 mData.mStatus /* curStatus */, mData.mStatus /* newStatus */,
1373 mData.mProcess.mFlags, mSession->i_getProtocolVersion());
1374}
1375
1376int GuestProcess::i_waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS,
1377 ProcessWaitResult_T &waitResult, int *pGuestRc)
1378{
1379 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
1380
1381 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1382
1383 LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, procStatus=%RU32, procRc=%Rrc, pGuestRc=%p\n",
1384 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mLastError, pGuestRc));
1385
1386 /* Did some error occur before? Then skip waiting and return. */
1387 ProcessStatus_T curStatus = mData.mStatus;
1388 if (curStatus == ProcessStatus_Error)
1389 {
1390 waitResult = ProcessWaitResult_Error;
1391 AssertMsg(RT_FAILURE(mData.mLastError),
1392 ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mLastError));
1393 if (pGuestRc)
1394 *pGuestRc = mData.mLastError; /* Return last set error. */
1395 LogFlowThisFunc(("Process is in error state (guestRc=%Rrc)\n", mData.mLastError));
1396 return VERR_GSTCTL_GUEST_ERROR;
1397 }
1398
1399 waitResult = i_waitFlagsToResult(fWaitFlags);
1400
1401 /* No waiting needed? Return immediately using the last set error. */
1402 if (waitResult != ProcessWaitResult_None)
1403 {
1404 if (pGuestRc)
1405 *pGuestRc = mData.mLastError; /* Return last set error (if any). */
1406 LogFlowThisFunc(("Nothing to wait for (guestRc=%Rrc)\n", mData.mLastError));
1407 return RT_SUCCESS(mData.mLastError) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR;
1408 }
1409
1410 /* Adjust timeout. Passing 0 means RT_INDEFINITE_WAIT. */
1411 if (!uTimeoutMS)
1412 uTimeoutMS = RT_INDEFINITE_WAIT;
1413
1414 int vrc;
1415
1416 GuestWaitEvent *pEvent = NULL;
1417 GuestEventTypes eventTypes;
1418 try
1419 {
1420 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1421
1422 vrc = registerWaitEvent(eventTypes, &pEvent);
1423 }
1424 catch (std::bad_alloc)
1425 {
1426 vrc = VERR_NO_MEMORY;
1427 }
1428
1429 if (RT_FAILURE(vrc))
1430 return vrc;
1431
1432 alock.release(); /* Release lock before waiting. */
1433
1434 /*
1435 * Do the actual waiting.
1436 */
1437 ProcessStatus_T newStatus = ProcessStatus_Undefined;
1438 uint64_t u64StartMS = RTTimeMilliTS();
1439 for (;;)
1440 {
1441 uint64_t u64ElapsedMS = RTTimeMilliTS() - u64StartMS;
1442 if ( uTimeoutMS != RT_INDEFINITE_WAIT
1443 && u64ElapsedMS >= uTimeoutMS)
1444 {
1445 vrc = VERR_TIMEOUT;
1446 break;
1447 }
1448
1449 vrc = i_waitForStatusChange(pEvent,
1450 uTimeoutMS == RT_INDEFINITE_WAIT
1451 ? RT_INDEFINITE_WAIT : uTimeoutMS - (uint32_t)u64ElapsedMS,
1452 &newStatus, pGuestRc);
1453 if (RT_SUCCESS(vrc))
1454 {
1455 alock.acquire();
1456
1457 waitResult = i_waitFlagsToResultEx(fWaitFlags, curStatus, newStatus,
1458 mData.mProcess.mFlags, mSession->i_getProtocolVersion());
1459#ifdef DEBUG
1460 LogFlowThisFunc(("Got new status change: fWaitFlags=0x%x, newStatus=%RU32, waitResult=%RU32\n",
1461 fWaitFlags, newStatus, waitResult));
1462#endif
1463 if (ProcessWaitResult_None != waitResult) /* We got a waiting result. */
1464 break;
1465 }
1466 else /* Waiting failed, bail out. */
1467 break;
1468
1469 alock.release(); /* Don't hold lock in next waiting round. */
1470 }
1471
1472 unregisterWaitEvent(pEvent);
1473
1474 LogFlowThisFunc(("Returned waitResult=%RU32, newStatus=%RU32, rc=%Rrc\n",
1475 waitResult, newStatus, vrc));
1476 return vrc;
1477}
1478
1479int GuestProcess::i_waitForInputNotify(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS,
1480 ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed)
1481{
1482 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1483
1484 VBoxEventType_T evtType;
1485 ComPtr<IEvent> pIEvent;
1486 int vrc = waitForEvent(pEvent, uTimeoutMS,
1487 &evtType, pIEvent.asOutParam());
1488 if (RT_SUCCESS(vrc))
1489 {
1490 if (evtType == VBoxEventType_OnGuestProcessInputNotify)
1491 {
1492 ComPtr<IGuestProcessInputNotifyEvent> pProcessEvent = pIEvent;
1493 Assert(!pProcessEvent.isNull());
1494
1495 if (pInputStatus)
1496 {
1497 HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus);
1498 ComAssertComRC(hr2);
1499 }
1500 if (pcbProcessed)
1501 {
1502 HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed);
1503 ComAssertComRC(hr2);
1504 }
1505 }
1506 else
1507 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1508 }
1509
1510 LogFlowThisFunc(("Returning pEvent=%p, uHandle=%RU32, rc=%Rrc\n",
1511 pEvent, uHandle, vrc));
1512 return vrc;
1513}
1514
1515int GuestProcess::i_waitForOutput(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS,
1516 void *pvData, size_t cbData, uint32_t *pcbRead)
1517{
1518 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1519 /* pvData is optional. */
1520 /* cbData is optional. */
1521 /* pcbRead is optional. */
1522
1523 LogFlowThisFunc(("cEventTypes=%zu, pEvent=%p, uHandle=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu, pcbRead=%p\n",
1524 pEvent->TypeCount(), pEvent, uHandle, uTimeoutMS, pvData, cbData, pcbRead));
1525
1526 int vrc;
1527
1528 VBoxEventType_T evtType;
1529 ComPtr<IEvent> pIEvent;
1530 do
1531 {
1532 vrc = waitForEvent(pEvent, uTimeoutMS,
1533 &evtType, pIEvent.asOutParam());
1534 if (RT_SUCCESS(vrc))
1535 {
1536 if (evtType == VBoxEventType_OnGuestProcessOutput)
1537 {
1538 ComPtr<IGuestProcessOutputEvent> pProcessEvent = pIEvent;
1539 Assert(!pProcessEvent.isNull());
1540
1541 ULONG uHandleEvent;
1542 HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent);
1543 if ( SUCCEEDED(hr)
1544 && uHandleEvent == uHandle)
1545 {
1546 if (pvData)
1547 {
1548 com::SafeArray <BYTE> data;
1549 hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1550 ComAssertComRC(hr);
1551 size_t cbRead = data.size();
1552 if (cbRead)
1553 {
1554 if (cbRead <= cbData)
1555 {
1556 /* Copy data from event into our buffer. */
1557 memcpy(pvData, data.raw(), data.size());
1558 }
1559 else
1560 vrc = VERR_BUFFER_OVERFLOW;
1561
1562 LogFlowThisFunc(("Read %zu bytes (uHandle=%RU32), rc=%Rrc\n",
1563 cbRead, uHandleEvent, vrc));
1564 }
1565 }
1566
1567 if ( RT_SUCCESS(vrc)
1568 && pcbRead)
1569 {
1570 ULONG cbRead;
1571 hr = pProcessEvent->COMGETTER(Processed)(&cbRead);
1572 ComAssertComRC(hr);
1573 *pcbRead = (uint32_t)cbRead;
1574 }
1575
1576 break;
1577 }
1578 else if (FAILED(hr))
1579 vrc = VERR_COM_UNEXPECTED;
1580 }
1581 else
1582 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1583 }
1584
1585 } while (vrc == VINF_SUCCESS);
1586
1587 if ( vrc != VINF_SUCCESS
1588 && pcbRead)
1589 {
1590 *pcbRead = 0;
1591 }
1592
1593 LogFlowFuncLeaveRC(vrc);
1594 return vrc;
1595}
1596
1597int GuestProcess::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1598 ProcessStatus_T *pProcessStatus, int *pGuestRc)
1599{
1600 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1601 /* pProcessStatus is optional. */
1602 /* pGuestRc is optional. */
1603
1604 VBoxEventType_T evtType;
1605 ComPtr<IEvent> pIEvent;
1606 int vrc = waitForEvent(pEvent, uTimeoutMS,
1607 &evtType, pIEvent.asOutParam());
1608 if (RT_SUCCESS(vrc))
1609 {
1610 Assert(evtType == VBoxEventType_OnGuestProcessStateChanged);
1611 ComPtr<IGuestProcessStateChangedEvent> pProcessEvent = pIEvent;
1612 Assert(!pProcessEvent.isNull());
1613
1614 ProcessStatus_T procStatus;
1615 HRESULT hr = pProcessEvent->COMGETTER(Status)(&procStatus);
1616 ComAssertComRC(hr);
1617 if (pProcessStatus)
1618 *pProcessStatus = procStatus;
1619
1620 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1621 hr = pProcessEvent->COMGETTER(Error)(errorInfo.asOutParam());
1622 ComAssertComRC(hr);
1623
1624 LONG lGuestRc;
1625 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1626 ComAssertComRC(hr);
1627
1628 LogFlowThisFunc(("Got procStatus=%RU32, guestRc=%RI32 (%Rrc)\n",
1629 procStatus, lGuestRc, lGuestRc));
1630
1631 if (RT_FAILURE((int)lGuestRc))
1632 vrc = VERR_GSTCTL_GUEST_ERROR;
1633
1634 if (pGuestRc)
1635 *pGuestRc = (int)lGuestRc;
1636 }
1637
1638 LogFlowFuncLeaveRC(vrc);
1639 return vrc;
1640}
1641
1642/* static */
1643bool GuestProcess::i_waitResultImpliesEx(ProcessWaitResult_T waitResult,
1644 ProcessStatus_T procStatus, uint32_t uProcFlags,
1645 uint32_t uProtocol)
1646{
1647 bool fImplies;
1648
1649 switch (waitResult)
1650 {
1651 case ProcessWaitResult_Start:
1652 fImplies = procStatus == ProcessStatus_Started;
1653 break;
1654
1655 case ProcessWaitResult_Terminate:
1656 fImplies = ( procStatus == ProcessStatus_TerminatedNormally
1657 || procStatus == ProcessStatus_TerminatedSignal
1658 || procStatus == ProcessStatus_TerminatedAbnormally
1659 || procStatus == ProcessStatus_TimedOutKilled
1660 || procStatus == ProcessStatus_TimedOutAbnormally
1661 || procStatus == ProcessStatus_Down
1662 || procStatus == ProcessStatus_Error);
1663 break;
1664
1665 default:
1666 fImplies = false;
1667 break;
1668 }
1669
1670 return fImplies;
1671}
1672
1673int GuestProcess::i_writeData(uint32_t uHandle, uint32_t uFlags,
1674 void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc)
1675{
1676 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p, pGuestRc=%p\n",
1677 mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten, pGuestRc));
1678 /* All is optional. There can be 0 byte writes. */
1679 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1680
1681 if (mData.mStatus != ProcessStatus_Started)
1682 {
1683 if (puWritten)
1684 *puWritten = 0;
1685 if (pGuestRc)
1686 *pGuestRc = VINF_SUCCESS;
1687 return VINF_SUCCESS; /* Not available for writing (anymore). */
1688 }
1689
1690 int vrc;
1691
1692 GuestWaitEvent *pEvent = NULL;
1693 GuestEventTypes eventTypes;
1694 try
1695 {
1696 /*
1697 * On Guest Additions < 4.3 there is no guarantee that the process status
1698 * change arrives *after* the input event, e.g. if this was the last input
1699 * block being written and the process will report status "terminate".
1700 * So just skip checking for process status change and only wait for the
1701 * input event.
1702 */
1703 if (mSession->i_getProtocolVersion() >= 2)
1704 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1705 eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
1706
1707 vrc = registerWaitEvent(eventTypes, &pEvent);
1708 }
1709 catch (std::bad_alloc)
1710 {
1711 vrc = VERR_NO_MEMORY;
1712 }
1713
1714 if (RT_FAILURE(vrc))
1715 return vrc;
1716
1717 VBOXHGCMSVCPARM paParms[5];
1718 int i = 0;
1719 paParms[i++].setUInt32(pEvent->ContextID());
1720 paParms[i++].setUInt32(mData.mPID);
1721 paParms[i++].setUInt32(uFlags);
1722 paParms[i++].setPointer(pvData, (uint32_t)cbData);
1723 paParms[i++].setUInt32((uint32_t)cbData);
1724
1725 alock.release(); /* Drop the write lock before sending. */
1726
1727 uint32_t cbProcessed = 0;
1728 vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
1729 if (RT_SUCCESS(vrc))
1730 {
1731 ProcessInputStatus_T inputStatus;
1732 vrc = i_waitForInputNotify(pEvent, uHandle, uTimeoutMS,
1733 &inputStatus, &cbProcessed);
1734 if (RT_SUCCESS(vrc))
1735 {
1736 /** @todo Set guestRc. */
1737
1738 if (puWritten)
1739 *puWritten = cbProcessed;
1740 }
1741 /** @todo Error handling. */
1742 }
1743
1744 unregisterWaitEvent(pEvent);
1745
1746 LogFlowThisFunc(("Returning cbProcessed=%RU32, rc=%Rrc\n",
1747 cbProcessed, vrc));
1748 return vrc;
1749}
1750
1751// implementation of public methods
1752/////////////////////////////////////////////////////////////////////////////
1753
1754HRESULT GuestProcess::read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1755{
1756#ifndef VBOX_WITH_GUEST_CONTROL
1757 ReturnComNotImplemented();
1758#else
1759 LogFlowThisFuncEnter();
1760
1761 if (aToRead == 0)
1762 return setError(E_INVALIDARG, tr("The size to read is zero"));
1763
1764 aData.resize(aToRead);
1765
1766 HRESULT hr = S_OK;
1767
1768 uint32_t cbRead; int guestRc;
1769 int vrc = i_readData(aHandle, aToRead, aTimeoutMS, &aData.front(), aToRead, &cbRead, &guestRc);
1770 if (RT_SUCCESS(vrc))
1771 {
1772 if (aData.size() != cbRead)
1773 aData.resize(cbRead);
1774 }
1775 else
1776 {
1777 aData.resize(0);
1778
1779 switch (vrc)
1780 {
1781 case VERR_GSTCTL_GUEST_ERROR:
1782 hr = GuestProcess::i_setErrorExternal(this, guestRc);
1783 break;
1784
1785 default:
1786 hr = setError(VBOX_E_IPRT_ERROR,
1787 tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
1788 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
1789 break;
1790 }
1791 }
1792
1793 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32\n", vrc, cbRead));
1794
1795 LogFlowFuncLeaveRC(vrc);
1796 return hr;
1797#endif /* VBOX_WITH_GUEST_CONTROL */
1798}
1799
1800HRESULT GuestProcess::terminate()
1801{
1802#ifndef VBOX_WITH_GUEST_CONTROL
1803 ReturnComNotImplemented();
1804#else
1805
1806 HRESULT hr = S_OK;
1807
1808 int guestRc;
1809 int vrc = i_terminateProcess(30 * 1000 /* Timeout in ms */,
1810 &guestRc);
1811 if (RT_FAILURE(vrc))
1812 {
1813 switch (vrc)
1814 {
1815 case VERR_GSTCTL_GUEST_ERROR:
1816 hr = GuestProcess::i_setErrorExternal(this, guestRc);
1817 break;
1818
1819 case VERR_NOT_SUPPORTED:
1820 hr = setError(VBOX_E_IPRT_ERROR,
1821 tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"),
1822 mData.mProcess.mExecutable.c_str(), mData.mPID);
1823 break;
1824
1825 default:
1826 hr = setError(VBOX_E_IPRT_ERROR,
1827 tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"),
1828 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
1829 break;
1830 }
1831 }
1832
1833 /* Remove process from guest session list. Now only API clients
1834 * still can hold references to it. */
1835 AssertPtr(mSession);
1836 int rc2 = mSession->i_processRemoveFromList(this);
1837 if (RT_SUCCESS(vrc))
1838 vrc = rc2;
1839
1840 LogFlowFuncLeaveRC(vrc);
1841 return hr;
1842#endif /* VBOX_WITH_GUEST_CONTROL */
1843}
1844
1845HRESULT GuestProcess::waitFor(ULONG aWaitFor,
1846 ULONG aTimeoutMS,
1847 ProcessWaitResult_T *aReason)
1848{
1849#ifndef VBOX_WITH_GUEST_CONTROL
1850 ReturnComNotImplemented();
1851#else
1852
1853 /*
1854 * Note: Do not hold any locks here while waiting!
1855 */
1856 HRESULT hr = S_OK;
1857
1858 int guestRc;
1859 ProcessWaitResult_T waitResult;
1860 int vrc = i_waitFor(aWaitFor, aTimeoutMS, waitResult, &guestRc);
1861 if (RT_SUCCESS(vrc))
1862 {
1863 *aReason = waitResult;
1864 }
1865 else
1866 {
1867 switch (vrc)
1868 {
1869 case VERR_GSTCTL_GUEST_ERROR:
1870 hr = GuestProcess::i_setErrorExternal(this, guestRc);
1871 break;
1872
1873 case VERR_TIMEOUT:
1874 *aReason = ProcessWaitResult_Timeout;
1875 break;
1876
1877 default:
1878 hr = setError(VBOX_E_IPRT_ERROR,
1879 tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
1880 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
1881 break;
1882 }
1883 }
1884
1885 LogFlowFuncLeaveRC(vrc);
1886 return hr;
1887#endif /* VBOX_WITH_GUEST_CONTROL */
1888}
1889
1890HRESULT GuestProcess::waitForArray(const std::vector<ProcessWaitForFlag_T> &aWaitFor,
1891 ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1892{
1893#ifndef VBOX_WITH_GUEST_CONTROL
1894 ReturnComNotImplemented();
1895#else
1896 /*
1897 * Note: Do not hold any locks here while waiting!
1898 */
1899 uint32_t fWaitFor = ProcessWaitForFlag_None;
1900 for (size_t i = 0; i < aWaitFor.size(); i++)
1901 fWaitFor |= aWaitFor[i];
1902
1903 return WaitFor(fWaitFor, aTimeoutMS, aReason);
1904#endif /* VBOX_WITH_GUEST_CONTROL */
1905}
1906
1907HRESULT GuestProcess::write(ULONG aHandle, ULONG aFlags, const std::vector<BYTE> &aData,
1908 ULONG aTimeoutMS, ULONG *aWritten)
1909{
1910#ifndef VBOX_WITH_GUEST_CONTROL
1911 ReturnComNotImplemented();
1912#else
1913 LogFlowThisFuncEnter();
1914
1915 HRESULT hr = S_OK;
1916
1917 uint32_t cbWritten; int guestRc;
1918 uint32_t cbData = (uint32_t)aData.size();
1919 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1920 int vrc = i_writeData(aHandle, aFlags, pvData, cbData, aTimeoutMS, &cbWritten, &guestRc);
1921 if (RT_FAILURE(vrc))
1922 {
1923 switch (vrc)
1924 {
1925 case VERR_GSTCTL_GUEST_ERROR:
1926 hr = GuestProcess::i_setErrorExternal(this, guestRc);
1927 break;
1928
1929 default:
1930 hr = setError(VBOX_E_IPRT_ERROR,
1931 tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
1932 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
1933 break;
1934 }
1935 }
1936
1937 LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, cbWritten));
1938
1939 *aWritten = (ULONG)cbWritten;
1940
1941 LogFlowFuncLeaveRC(vrc);
1942 return hr;
1943#endif /* VBOX_WITH_GUEST_CONTROL */
1944}
1945
1946HRESULT GuestProcess::writeArray(ULONG aHandle, const std::vector<ProcessInputFlag_T> &aFlags,
1947 const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1948{
1949#ifndef VBOX_WITH_GUEST_CONTROL
1950 ReturnComNotImplemented();
1951#else
1952 LogFlowThisFuncEnter();
1953
1954 /*
1955 * Note: Do not hold any locks here while writing!
1956 */
1957 ULONG fWrite = ProcessInputFlag_None;
1958 for (size_t i = 0; i < aFlags.size(); i++)
1959 fWrite |= aFlags[i];
1960
1961 return write(aHandle, fWrite, aData, aTimeoutMS, aWritten);
1962#endif /* VBOX_WITH_GUEST_CONTROL */
1963}
1964
1965///////////////////////////////////////////////////////////////////////////////
1966
1967GuestProcessTool::GuestProcessTool(void)
1968 : pSession(NULL),
1969 pProcess(NULL)
1970{
1971}
1972
1973GuestProcessTool::~GuestProcessTool(void)
1974{
1975 i_terminate(30 * 1000, NULL /* pGuestRc */);
1976}
1977
1978int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
1979 bool fAsync, int *pGuestRc)
1980{
1981 LogFlowThisFunc(("pGuestSession=%p, exe=%s, fAsync=%RTbool\n",
1982 pGuestSession, startupInfo.mExecutable.c_str(), fAsync));
1983
1984 AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
1985
1986 pSession = pGuestSession;
1987 mStartupInfo = startupInfo;
1988
1989 /* Make sure the process is hidden. */
1990 mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
1991
1992 int vrc = pSession->i_processCreateExInternal(mStartupInfo, pProcess);
1993 if (RT_SUCCESS(vrc))
1994 vrc = fAsync
1995 ? pProcess->i_startProcessAsync()
1996 : pProcess->i_startProcess(30 * 1000 /* 30s timeout */, pGuestRc);
1997
1998 if ( RT_SUCCESS(vrc)
1999 && !fAsync
2000 && ( pGuestRc
2001 && RT_FAILURE(*pGuestRc)
2002 )
2003 )
2004 {
2005 vrc = VERR_GSTCTL_GUEST_ERROR;
2006 }
2007
2008 LogFlowFuncLeaveRC(vrc);
2009 return vrc;
2010}
2011
2012int GuestProcessTool::i_getCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock)
2013{
2014 const GuestProcessStream *pStream = NULL;
2015 if (uHandle == OUTPUT_HANDLE_ID_STDOUT)
2016 pStream = &mStdOut;
2017 else if (uHandle == OUTPUT_HANDLE_ID_STDERR)
2018 pStream = &mStdErr;
2019
2020 if (!pStream)
2021 return VERR_INVALID_PARAMETER;
2022
2023 int vrc;
2024 do
2025 {
2026 /* Try parsing the data to see if the current block is complete. */
2027 vrc = mStdOut.ParseBlock(strmBlock);
2028 if (strmBlock.GetCount())
2029 break;
2030 } while (RT_SUCCESS(vrc));
2031
2032 LogFlowThisFunc(("rc=%Rrc, %RU64 pairs\n",
2033 vrc, strmBlock.GetCount()));
2034 return vrc;
2035}
2036
2037bool GuestProcessTool::i_isRunning(void)
2038{
2039 AssertReturn(!pProcess.isNull(), false);
2040
2041 ProcessStatus_T procStatus = ProcessStatus_Undefined;
2042 HRESULT hr = pProcess->COMGETTER(Status(&procStatus));
2043 Assert(SUCCEEDED(hr));
2044
2045 if ( procStatus == ProcessStatus_Started
2046 || procStatus == ProcessStatus_Paused
2047 || procStatus == ProcessStatus_Terminating)
2048 {
2049 return true;
2050 }
2051
2052 return false;
2053}
2054
2055/* static */
2056int GuestProcessTool::i_run( GuestSession *pGuestSession,
2057 const GuestProcessStartupInfo &startupInfo,
2058 int *pGuestRc)
2059{
2060 return i_runEx(pGuestSession, startupInfo,
2061 NULL /* pStrmOutObjects */, 0 /* cStrmOutObjects */,
2062 pGuestRc);
2063}
2064
2065/* static */
2066int GuestProcessTool::i_runEx( GuestSession *pGuestSession,
2067 const GuestProcessStartupInfo &startupInfo,
2068 GuestCtrlStreamObjects *pStrmOutObjects,
2069 uint32_t cStrmOutObjects,
2070 int *pGuestRc)
2071{
2072 GuestProcessTool procTool; int guestRc;
2073 int vrc = procTool.Init(pGuestSession, startupInfo, false /* Async */, &guestRc);
2074 if (RT_SUCCESS(vrc))
2075 {
2076 while (cStrmOutObjects--)
2077 {
2078 try
2079 {
2080 GuestProcessStreamBlock strmBlk;
2081 vrc = procTool.i_waitEx( pStrmOutObjects
2082 ? GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK
2083 : GUESTPROCESSTOOL_FLAG_NONE, &strmBlk, &guestRc);
2084 if (pStrmOutObjects)
2085 pStrmOutObjects->push_back(strmBlk);
2086 }
2087 catch (std::bad_alloc)
2088 {
2089 vrc = VERR_NO_MEMORY;
2090 }
2091 }
2092 }
2093
2094 if (RT_SUCCESS(vrc))
2095 {
2096 /* Make sure the process runs until completion. */
2097 vrc = procTool.i_wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
2098 if (RT_SUCCESS(vrc))
2099 {
2100 guestRc = procTool.i_terminatedOk(NULL /* Exit code */);
2101 if (RT_FAILURE(guestRc))
2102 vrc = VERR_GSTCTL_GUEST_ERROR;
2103 }
2104 }
2105
2106 if (pGuestRc)
2107 *pGuestRc = guestRc;
2108
2109 LogFlowFunc(("Returned rc=%Rrc, guestRc=%Rrc\n", vrc, guestRc));
2110 return vrc;
2111}
2112
2113int GuestProcessTool::i_terminatedOk(LONG *pExitCode)
2114{
2115 Assert(!pProcess.isNull());
2116 /* pExitCode is optional. */
2117
2118 int vrc;
2119 if (!i_isRunning())
2120 {
2121 LONG exitCode;
2122 HRESULT hr = pProcess->COMGETTER(ExitCode(&exitCode));
2123 Assert(SUCCEEDED(hr));
2124
2125 if (pExitCode)
2126 *pExitCode = exitCode;
2127
2128 vrc = (exitCode != 0)
2129 /** @todo Special guest control rc needed! */
2130 ? VERR_NOT_EQUAL : VINF_SUCCESS;
2131 }
2132 else
2133 vrc = VERR_INVALID_STATE; /** @todo Special guest control rc needed! */
2134
2135 LogFlowFuncLeaveRC(vrc);
2136 return vrc;
2137}
2138
2139int GuestProcessTool::i_wait(uint32_t fFlags, int *pGuestRc)
2140{
2141 return i_waitEx(fFlags, NULL /* pStrmBlkOut */, pGuestRc);
2142}
2143
2144int GuestProcessTool::i_waitEx(uint32_t fFlags, GuestProcessStreamBlock *pStrmBlkOut, int *pGuestRc)
2145{
2146 LogFlowThisFunc(("fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n",
2147 fFlags, pStrmBlkOut, pGuestRc));
2148
2149 /* Can we parse the next block without waiting? */
2150 int vrc;
2151 if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)
2152 {
2153 AssertPtr(pStrmBlkOut);
2154 vrc = i_getCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStrmBlkOut);
2155 if (RT_SUCCESS(vrc))
2156 return vrc;
2157 /* else do the the waiting below. */
2158 }
2159
2160 /* Do the waiting. */
2161 uint32_t fWaitFlags = ProcessWaitForFlag_Terminate;
2162 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
2163 fWaitFlags |= ProcessWaitForFlag_StdOut;
2164 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
2165 fWaitFlags |= ProcessWaitForFlag_StdErr;
2166
2167 /** @todo Decrease timeout while running. */
2168 uint64_t u64StartMS = RTTimeMilliTS();
2169 uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS;
2170
2171 int guestRc;
2172 bool fDone = false;
2173
2174 BYTE byBuf[_64K];
2175 uint32_t cbRead;
2176
2177 bool fHandleStdOut = false;
2178 bool fHandleStdErr = false;
2179
2180 /**
2181 * Updates the elapsed time and checks if a
2182 * timeout happened, then breaking out of the loop.
2183 */
2184#define UPDATE_AND_CHECK_ELAPSED_TIME() \
2185 u64ElapsedMS = RTTimeMilliTS() - u64StartMS; \
2186 if ( uTimeoutMS != RT_INDEFINITE_WAIT \
2187 && u64ElapsedMS >= uTimeoutMS) \
2188 { \
2189 vrc = VERR_TIMEOUT; \
2190 break; \
2191 }
2192
2193 /**
2194 * Returns the remaining time (in ms).
2195 */
2196#define GET_REMAINING_TIME \
2197 uTimeoutMS == RT_INDEFINITE_WAIT \
2198 ? RT_INDEFINITE_WAIT : uTimeoutMS - (uint32_t)u64ElapsedMS \
2199
2200 ProcessWaitResult_T waitRes;
2201 do
2202 {
2203 uint64_t u64ElapsedMS;
2204 UPDATE_AND_CHECK_ELAPSED_TIME();
2205
2206 vrc = pProcess->i_waitFor(fWaitFlags, GET_REMAINING_TIME,
2207 waitRes, &guestRc);
2208 if (RT_FAILURE(vrc))
2209 break;
2210
2211 switch (waitRes)
2212 {
2213 case ProcessWaitResult_StdIn:
2214 vrc = VERR_NOT_IMPLEMENTED;
2215 break;
2216
2217 case ProcessWaitResult_StdOut:
2218 fHandleStdOut = true;
2219 break;
2220
2221 case ProcessWaitResult_StdErr:
2222 fHandleStdErr = true;
2223 break;
2224
2225 case ProcessWaitResult_WaitFlagNotSupported:
2226 if (fWaitFlags & ProcessWaitForFlag_StdOut)
2227 fHandleStdOut = true;
2228 if (fWaitFlags & ProcessWaitForFlag_StdErr)
2229 fHandleStdErr = true;
2230 /* Since waiting for stdout / stderr is not supported by the guest,
2231 * wait a bit to not hog the CPU too much when polling for data. */
2232 RTThreadSleep(1); /* Optional, don't check rc. */
2233 break;
2234
2235 case ProcessWaitResult_Error:
2236 vrc = VERR_GSTCTL_GUEST_ERROR;
2237 break;
2238
2239 case ProcessWaitResult_Terminate:
2240 fDone = true;
2241 break;
2242
2243 case ProcessWaitResult_Timeout:
2244 vrc = VERR_TIMEOUT;
2245 break;
2246
2247 case ProcessWaitResult_Start:
2248 case ProcessWaitResult_Status:
2249 /* Not used here, just skip. */
2250 break;
2251
2252 default:
2253 AssertMsgFailed(("Unhandled process wait result %RU32\n", waitRes));
2254 break;
2255 }
2256
2257 if (RT_FAILURE(vrc))
2258 break;
2259
2260 if (fHandleStdOut)
2261 {
2262 UPDATE_AND_CHECK_ELAPSED_TIME();
2263
2264 cbRead = 0;
2265 vrc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
2266 GET_REMAINING_TIME,
2267 byBuf, sizeof(byBuf),
2268 &cbRead, &guestRc);
2269 if ( RT_FAILURE(vrc)
2270 || vrc == VWRN_GSTCTL_OBJECTSTATE_CHANGED)
2271 break;
2272
2273 if (cbRead)
2274 {
2275 LogFlowThisFunc(("Received %RU32 bytes from stdout\n", cbRead));
2276 vrc = mStdOut.AddData(byBuf, cbRead);
2277
2278 if ( RT_SUCCESS(vrc)
2279 && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK))
2280 {
2281 AssertPtr(pStrmBlkOut);
2282 vrc = i_getCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStrmBlkOut);
2283
2284 /* When successful, break out of the loop because we're done
2285 * with reading the first stream block. */
2286 if (RT_SUCCESS(vrc))
2287 fDone = true;
2288 }
2289 }
2290
2291 fHandleStdOut = false;
2292 }
2293
2294 if (fHandleStdErr)
2295 {
2296 UPDATE_AND_CHECK_ELAPSED_TIME();
2297
2298 cbRead = 0;
2299 vrc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf),
2300 GET_REMAINING_TIME,
2301 byBuf, sizeof(byBuf),
2302 &cbRead, &guestRc);
2303 if ( RT_FAILURE(vrc)
2304 || vrc == VWRN_GSTCTL_OBJECTSTATE_CHANGED)
2305 break;
2306
2307 if (cbRead)
2308 {
2309 LogFlowThisFunc(("Received %RU32 bytes from stderr\n", cbRead));
2310 vrc = mStdErr.AddData(byBuf, cbRead);
2311 }
2312
2313 fHandleStdErr = false;
2314 }
2315
2316 } while (!fDone && RT_SUCCESS(vrc));
2317
2318#undef UPDATE_AND_CHECK_ELAPSED_TIME
2319#undef GET_REMAINING_TIME
2320
2321 if (RT_FAILURE(guestRc))
2322 vrc = VERR_GSTCTL_GUEST_ERROR;
2323
2324 LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%RU32\n",
2325 vrc, guestRc, waitRes));
2326 if (pGuestRc)
2327 *pGuestRc = guestRc;
2328
2329 LogFlowFuncLeaveRC(vrc);
2330 return vrc;
2331}
2332
2333int GuestProcessTool::i_terminate(uint32_t uTimeoutMS, int *pGuestRc)
2334{
2335 LogFlowThisFuncEnter();
2336
2337 int rc = VINF_SUCCESS;
2338 if (!pProcess.isNull())
2339 {
2340 rc = pProcess->i_terminateProcess(uTimeoutMS, pGuestRc);
2341 pProcess.setNull();
2342 }
2343 else
2344 rc = VERR_NOT_FOUND;
2345
2346 LogFlowFuncLeaveRC(rc);
2347 return rc;
2348}
2349
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