VirtualBox

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

最後變更 在這個檔案從55535是 55535,由 vboxsync 提交於 10 年 前

Main,VBoxManage,VBoxShell,ValidationKit: Changed the IGuestSession:createProcess[Ex] interfaces to take argv[0] as input separate from the executable name. This is not yet implemented on the guest side.

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

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