VirtualBox

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

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

Guest Control: Adjustments for supporting < 4.3 Guest Additions in conjunction with the new guest session, extended testcase (now passing using latest 4.2 Guest Additions with latest trunk).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use