VirtualBox

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

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

Guest Control:

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

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