VirtualBox

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

Last change on this file since 50874 was 50874, checked in by vboxsync, 11 years ago

6813 src-all/ProgressImp.cpp + some formatting/line length sorting

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