VirtualBox

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

Last change on this file since 44935 was 44935, checked in by vboxsync, 12 years ago

GuestCtrl: More code for guest session infrastructure handling (untested, work in progress). Added IGuestSession.status for (later) asynchronous handling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.7 KB
Line 
1
2/* $Id: GuestProcessImpl.cpp 44935 2013-03-06 16:40:36Z 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
36#include "Global.h"
37#include "AutoCaller.h"
38
39#include <memory> /* For auto_ptr. */
40
41#include <iprt/asm.h>
42#include <iprt/getopt.h>
43#include <VBox/com/array.h>
44
45#ifdef LOG_GROUP
46 #undef LOG_GROUP
47#endif
48#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
49#include <VBox/log.h>
50
51
52class GuestProcessTask
53{
54public:
55
56 GuestProcessTask(GuestProcess *pProcess)
57 : mProcess(pProcess),
58 mRC(VINF_SUCCESS) { }
59
60 virtual ~GuestProcessTask(void) { }
61
62 int rc(void) const { return mRC; }
63 bool isOk(void) const { return RT_SUCCESS(mRC); }
64 const ComObjPtr<GuestProcess> &Process(void) const { return mProcess; }
65
66protected:
67
68 const ComObjPtr<GuestProcess> mProcess;
69 int mRC;
70};
71
72class GuestProcessStartTask : public GuestProcessTask
73{
74public:
75
76 GuestProcessStartTask(GuestProcess *pProcess)
77 : GuestProcessTask(pProcess) { }
78};
79
80// constructor / destructor
81/////////////////////////////////////////////////////////////////////////////
82
83DEFINE_EMPTY_CTOR_DTOR(GuestProcess)
84
85HRESULT GuestProcess::FinalConstruct(void)
86{
87 LogFlowThisFuncEnter();
88
89 mData.mExitCode = 0;
90 mData.mPID = 0;
91 mData.mRC = VINF_SUCCESS;
92 mData.mStatus = ProcessStatus_Undefined;
93
94 mData.mWaitCount = 0;
95 mData.mWaitEvent = NULL;
96
97 HRESULT hr = BaseFinalConstruct();
98 return hr;
99}
100
101void GuestProcess::FinalRelease(void)
102{
103 LogFlowThisFuncEnter();
104 uninit();
105 BaseFinalRelease();
106 LogFlowThisFuncLeave();
107}
108
109// public initializer/uninitializer for internal purposes only
110/////////////////////////////////////////////////////////////////////////////
111
112int GuestProcess::init(Console *aConsole, GuestSession *aSession,
113 ULONG aProcessID, const GuestProcessStartupInfo &aProcInfo)
114{
115 LogFlowThisFunc(("aConsole=%p, aSession=%p, aProcessID=%RU32\n",
116 aConsole, aSession, aProcessID));
117
118 AssertPtrReturn(aConsole, VERR_INVALID_POINTER);
119 AssertPtrReturn(aSession, VERR_INVALID_POINTER);
120
121 /* Enclose the state transition NotReady->InInit->Ready. */
122 AutoInitSpan autoInitSpan(this);
123 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
124
125 int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */);
126 if (RT_SUCCESS(vrc))
127 {
128 mData.mProcess = aProcInfo;
129 /* Everything else will be set by the actual starting routine. */
130
131 /* Confirm a successful initialization when it's the case. */
132 autoInitSpan.setSucceeded();
133
134 return vrc;
135 }
136
137 autoInitSpan.setFailed();
138 return vrc;
139}
140
141/**
142 * Uninitializes the instance.
143 * Called from FinalRelease().
144 */
145void GuestProcess::uninit(void)
146{
147 LogFlowThisFunc(("mCmd=%s, PID=%RU32\n",
148 mData.mProcess.mCommand.c_str(), mData.mPID));
149
150 /* Enclose the state transition Ready->InUninit->NotReady. */
151 AutoUninitSpan autoUninitSpan(this);
152 if (autoUninitSpan.uninitDone())
153 return;
154
155 int vrc = VINF_SUCCESS;
156
157#ifdef VBOX_WITH_GUEST_CONTROL
158 /*
159 * Cancel + remove all callbacks + waiters.
160 * Note: Deleting them is the job of the caller!
161 */
162 callbackRemoveAll();
163
164 if (mData.mWaitEvent)
165 {
166 int rc2 = mData.mWaitEvent->Cancel();
167 if (RT_SUCCESS(vrc))
168 vrc = rc2;
169 }
170
171 mData.mStatus = ProcessStatus_Down; /** @todo Correct? */
172#endif
173
174 LogFlowFuncLeaveRC(vrc);
175}
176
177// implementation of public getters/setters for attributes
178/////////////////////////////////////////////////////////////////////////////
179
180STDMETHODIMP GuestProcess::COMGETTER(Arguments)(ComSafeArrayOut(BSTR, aArguments))
181{
182#ifndef VBOX_WITH_GUEST_CONTROL
183 ReturnComNotImplemented();
184#else
185 LogFlowThisFuncEnter();
186
187 CheckComArgOutSafeArrayPointerValid(aArguments);
188
189 AutoCaller autoCaller(this);
190 if (FAILED(autoCaller.rc())) return autoCaller.rc();
191
192 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
193
194 com::SafeArray<BSTR> collection(mData.mProcess.mArguments.size());
195 size_t s = 0;
196 for (ProcessArguments::const_iterator it = mData.mProcess.mArguments.begin();
197 it != mData.mProcess.mArguments.end();
198 it++, s++)
199 {
200 Bstr tmp = *it;
201 tmp.cloneTo(&collection[s]);
202 }
203
204 collection.detachTo(ComSafeArrayOutArg(aArguments));
205
206 return S_OK;
207#endif /* VBOX_WITH_GUEST_CONTROL */
208}
209
210STDMETHODIMP GuestProcess::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))
211{
212#ifndef VBOX_WITH_GUEST_CONTROL
213 ReturnComNotImplemented();
214#else
215 LogFlowThisFuncEnter();
216
217 CheckComArgOutSafeArrayPointerValid(aEnvironment);
218
219 AutoCaller autoCaller(this);
220 if (FAILED(autoCaller.rc())) return autoCaller.rc();
221
222 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
223
224 com::SafeArray<BSTR> arguments(mData.mProcess.mEnvironment.Size());
225 for (size_t i = 0; i < arguments.size(); i++)
226 {
227 Bstr tmp = mData.mProcess.mEnvironment.Get(i);
228 tmp.cloneTo(&arguments[i]);
229 }
230 arguments.detachTo(ComSafeArrayOutArg(aEnvironment));
231
232 return S_OK;
233#endif /* VBOX_WITH_GUEST_CONTROL */
234}
235
236STDMETHODIMP GuestProcess::COMGETTER(ExecutablePath)(BSTR *aExecutablePath)
237{
238#ifndef VBOX_WITH_GUEST_CONTROL
239 ReturnComNotImplemented();
240#else
241 LogFlowThisFuncEnter();
242
243 CheckComArgOutPointerValid(aExecutablePath);
244
245 AutoCaller autoCaller(this);
246 if (FAILED(autoCaller.rc())) return autoCaller.rc();
247
248 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
249
250 mData.mProcess.mCommand.cloneTo(aExecutablePath);
251
252 return S_OK;
253#endif /* VBOX_WITH_GUEST_CONTROL */
254}
255
256STDMETHODIMP GuestProcess::COMGETTER(ExitCode)(LONG *aExitCode)
257{
258#ifndef VBOX_WITH_GUEST_CONTROL
259 ReturnComNotImplemented();
260#else
261 LogFlowThisFuncEnter();
262
263 CheckComArgOutPointerValid(aExitCode);
264
265 AutoCaller autoCaller(this);
266 if (FAILED(autoCaller.rc())) return autoCaller.rc();
267
268 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
269
270 *aExitCode = mData.mExitCode;
271
272 return S_OK;
273#endif /* VBOX_WITH_GUEST_CONTROL */
274}
275
276STDMETHODIMP GuestProcess::COMGETTER(Name)(BSTR *aName)
277{
278#ifndef VBOX_WITH_GUEST_CONTROL
279 ReturnComNotImplemented();
280#else
281 LogFlowThisFuncEnter();
282
283 CheckComArgOutPointerValid(aName);
284
285 AutoCaller autoCaller(this);
286 if (FAILED(autoCaller.rc())) return autoCaller.rc();
287
288 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
289
290 mData.mProcess.mName.cloneTo(aName);
291
292 return S_OK;
293#endif /* VBOX_WITH_GUEST_CONTROL */
294}
295
296STDMETHODIMP GuestProcess::COMGETTER(PID)(ULONG *aPID)
297{
298#ifndef VBOX_WITH_GUEST_CONTROL
299 ReturnComNotImplemented();
300#else
301 LogFlowThisFuncEnter();
302
303 CheckComArgOutPointerValid(aPID);
304
305 AutoCaller autoCaller(this);
306 if (FAILED(autoCaller.rc())) return autoCaller.rc();
307
308 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
309
310 *aPID = mData.mPID;
311
312 return S_OK;
313#endif /* VBOX_WITH_GUEST_CONTROL */
314}
315
316STDMETHODIMP GuestProcess::COMGETTER(Status)(ProcessStatus_T *aStatus)
317{
318#ifndef VBOX_WITH_GUEST_CONTROL
319 ReturnComNotImplemented();
320#else
321 LogFlowThisFuncEnter();
322
323 AutoCaller autoCaller(this);
324 if (FAILED(autoCaller.rc())) return autoCaller.rc();
325
326 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
327
328 *aStatus = mData.mStatus;
329
330 return S_OK;
331#endif /* VBOX_WITH_GUEST_CONTROL */
332}
333
334// private methods
335/////////////////////////////////////////////////////////////////////////////
336
337int GuestProcess::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
338{
339 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
340 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
341#ifdef DEBUG
342 LogFlowThisFunc(("uPID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
343 mData.mPID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
344#endif
345
346 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
347
348 /* Get the optional callback associated to this context ID.
349 * The callback may not be around anymore if just kept locally by the caller when
350 * doing the actual HGCM sending stuff. */
351 GuestCtrlCallback *pCallback = NULL;
352 GuestCtrlCallbacks::const_iterator it
353 = mObject.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID));
354 if (it != mObject.mCallbacks.end())
355 {
356 pCallback = it->second;
357 AssertPtr(pCallback);
358#ifdef DEBUG
359 LogFlowThisFunc(("pCallback=%p, CID=%RU32, Count=%RU32\n",
360 pCallback, pCbCtx->uContextID, VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(pCbCtx->uContextID)));
361#endif
362 }
363
364 int vrc;
365 switch (pCbCtx->uFunction)
366 {
367 case GUEST_DISCONNECTED:
368 {
369 vrc = onGuestDisconnected(pCbCtx, pCallback, pSvcCb); /* Affects all callbacks. */
370 break;
371 }
372
373 case GUEST_EXEC_STATUS:
374 {
375 vrc = onProcessStatusChange(pCbCtx, pCallback, pSvcCb);
376 break;
377 }
378
379 case GUEST_EXEC_OUTPUT:
380 {
381 vrc = onProcessOutput(pCbCtx, pCallback, pSvcCb);
382 break;
383 }
384
385 case GUEST_EXEC_INPUT_STATUS:
386 {
387 vrc = onProcessInputStatus(pCbCtx, pCallback, pSvcCb);
388 break;
389 }
390
391 default:
392 /* Silently ignore not implemented functions. */
393 vrc = VERR_NOT_SUPPORTED;
394 break;
395 }
396
397#ifdef DEBUG
398 LogFlowFuncLeaveRC(vrc);
399#endif
400 return vrc;
401}
402
403/**
404 * Checks if the current assigned PID matches another PID (from a callback).
405 *
406 * In protocol v1 we don't have the possibility to terminate/kill
407 * processes so it can happen that a formerly started process A
408 * (which has the context ID 0 (session=0, process=0, count=0) will
409 * send a delayed message to the host if this process has already
410 * been discarded there and the same context ID was reused by
411 * a process B. Process B in turn then has a different guest PID.
412 *
413 * @return IPRT status code.
414 * @param uPID PID to check.
415 */
416inline int GuestProcess::checkPID(uint32_t uPID)
417{
418 /* Was there a PID assigned yet? */
419 if (mData.mPID)
420 {
421 /*
422
423 */
424 if (mObject.mSession->getProtocolVersion() < 2)
425 {
426 /* Simply ignore the stale requests. */
427 return (mData.mPID == uPID)
428 ? VINF_SUCCESS : VERR_NOT_FOUND;
429 }
430#ifndef DEBUG_andy
431 /* This should never happen! */
432 AssertReleaseMsg(mData.mPID == uPID, ("Unterminated guest process (PID %RU32) sent data to a newly started process (PID %RU32)\n",
433 uPID, mData.mPID));
434#endif
435 }
436
437 return VINF_SUCCESS;
438}
439
440/* static */
441Utf8Str GuestProcess::guestErrorToString(int guestRc)
442{
443 Utf8Str strError;
444
445 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
446 switch (guestRc)
447 {
448 case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
449 strError += Utf8StrFmt(tr("The specified file was not found on guest"));
450 break;
451
452 case VERR_INVALID_VM_HANDLE:
453 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
454 break;
455
456 case VERR_HGCM_SERVICE_NOT_FOUND:
457 strError += Utf8StrFmt(tr("The guest execution service is not available"));
458 break;
459
460 case VERR_PATH_NOT_FOUND:
461 strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
462 break;
463
464 case VERR_BAD_EXE_FORMAT:
465 strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
466 break;
467
468 case VERR_AUTHENTICATION_FAILURE:
469 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
470 break;
471
472 case VERR_INVALID_NAME:
473 strError += Utf8StrFmt(tr("The specified file is an invalid name"));
474 break;
475
476 case VERR_TIMEOUT:
477 strError += Utf8StrFmt(tr("The guest did not respond within time"));
478 break;
479
480 case VERR_CANCELLED:
481 strError += Utf8StrFmt(tr("The execution operation was canceled"));
482 break;
483
484 case VERR_PERMISSION_DENIED:
485 strError += Utf8StrFmt(tr("Invalid user/password credentials"));
486 break;
487
488 case VERR_MAX_PROCS_REACHED:
489 strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
490 break;
491
492 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
493 strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
494 break;
495
496 case VERR_NOT_FOUND:
497 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
498 break;
499
500 default:
501 strError += Utf8StrFmt("%Rrc", guestRc);
502 break;
503 }
504
505 return strError;
506}
507
508inline bool GuestProcess::isAlive(void)
509{
510 return ( mData.mStatus == ProcessStatus_Started
511 || mData.mStatus == ProcessStatus_Paused
512 || mData.mStatus == ProcessStatus_Terminating);
513}
514
515bool GuestProcess::isReady(void)
516{
517 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
518
519 if (mData.mStatus == ProcessStatus_Started)
520 {
521 Assert(mData.mPID); /* PID must not be 0. */
522 return true;
523 }
524
525 return false;
526}
527
528int GuestProcess::onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
529 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
530{
531 AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
532
533 LogFlowThisFunc(("uPID=%RU32, pCallback=%p\n", mData.mPID, pCallback));
534
535 mData.mStatus = ProcessStatus_Down;
536
537 /* First, signal callback in every case. */
538 if (pCallback)
539 pCallback->Signal();
540
541 /* Do we need to report a termination? */
542 ProcessWaitResult_T waitRes;
543 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
544 waitRes = ProcessWaitResult_Status; /* No, just report a status. */
545 else
546 waitRes = ProcessWaitResult_Terminate;
547
548 /* Signal in any case. */
549 int vrc = signalWaiters(waitRes);
550 AssertRC(vrc);
551
552 LogFlowFuncLeaveRC(vrc);
553 return vrc;
554}
555
556int GuestProcess::onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
557 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
558{
559 AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
560 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
561
562 if (pSvcCbData->mParms < 5)
563 return VERR_INVALID_PARAMETER;
564
565 CALLBACKDATA_PROC_INPUT dataCb;
566 /* pSvcCb->mpaParms[0] always contains the context ID. */
567 pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
568 pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus);
569 pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
570 pSvcCbData->mpaParms[4].getUInt32(&dataCb.uProcessed);
571
572 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32, pCallback=%p\n",
573 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed, pCallback));
574
575 int vrc = checkPID(dataCb.uPID);
576 if (RT_FAILURE(vrc))
577 return vrc;
578
579 /* First, signal callback in every case (if available). */
580 if (pCallback)
581 {
582 vrc = pCallback->SetData(&dataCb, sizeof(dataCb));
583
584 int rc2 = pCallback->Signal();
585 if (RT_SUCCESS(vrc))
586 vrc = rc2;
587 }
588
589 /* Then do the WaitFor signalling stuff. */
590 uint32_t uWaitFlags = mData.mWaitEvent
591 ? mData.mWaitEvent->GetWaitFlags() : 0;
592 if (uWaitFlags & ProcessWaitForFlag_StdIn)
593 {
594 int rc2 = signalWaiters(ProcessWaitResult_StdIn);
595 if (RT_SUCCESS(vrc))
596 vrc = rc2;
597 }
598
599 LogFlowFuncLeaveRC(vrc);
600 return vrc;
601}
602
603int GuestProcess::onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
604 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
605{
606 AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
607
608 return VERR_NOT_IMPLEMENTED;
609}
610
611int GuestProcess::onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
612 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
613{
614 /* pCallback is optional. */
615 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
616
617 if (pSvcCbData->mParms < 5)
618 return VERR_INVALID_PARAMETER;
619
620 CALLBACKDATA_PROC_STATUS dataCb;
621 /* pSvcCb->mpaParms[0] always contains the context ID. */
622 pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
623 pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus);
624 pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
625 pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
626
627 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, pCallback=%p, pSvcCbData=%p\n",
628 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, pCallback, pSvcCbData));
629
630 int vrc = checkPID(dataCb.uPID);
631 if (RT_FAILURE(vrc))
632 return vrc;
633
634 ProcessStatus_T procStatus = ProcessStatus_Undefined;
635 int procRc = VINF_SUCCESS;
636
637 bool fSignalWaiters = false;
638 ProcessWaitResult_T waitRes;
639
640 uint32_t uWaitFlags = mData.mWaitEvent
641 ? mData.mWaitEvent->GetWaitFlags() : 0;
642 switch (dataCb.uStatus)
643 {
644 case PROC_STS_STARTED:
645 {
646 fSignalWaiters = (uWaitFlags & ProcessWaitForFlag_Start);
647 /* If the caller only wants to wait until the process has been started,
648 * notify in any case. */
649 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
650 fSignalWaiters = true;
651 waitRes = ProcessWaitResult_Start;
652
653 procStatus = ProcessStatus_Started;
654 mData.mPID = dataCb.uPID; /* Set the process PID. */
655 break;
656 }
657
658 case PROC_STS_TEN:
659 {
660 fSignalWaiters = true; /* Signal in any case. */
661 waitRes = ProcessWaitResult_Terminate;
662
663 procStatus = ProcessStatus_TerminatedNormally;
664 mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */
665 break;
666 }
667
668 case PROC_STS_TES:
669 {
670 fSignalWaiters = true; /* Signal in any case. */
671 waitRes = ProcessWaitResult_Terminate;
672
673 procStatus = ProcessStatus_TerminatedSignal;
674 mData.mExitCode = dataCb.uFlags; /* Contains the signal. */
675 break;
676 }
677
678 case PROC_STS_TEA:
679 {
680 fSignalWaiters = true; /* Signal in any case. */
681 waitRes = ProcessWaitResult_Terminate;
682
683 procStatus = ProcessStatus_TerminatedAbnormally;
684 break;
685 }
686
687 case PROC_STS_TOK:
688 {
689 fSignalWaiters = true; /* Signal in any case. */
690 waitRes = ProcessWaitResult_Timeout;
691
692 procStatus = ProcessStatus_TimedOutKilled;
693 break;
694 }
695
696 case PROC_STS_TOA:
697 {
698 fSignalWaiters = true; /* Signal in any case. */
699 waitRes = ProcessWaitResult_Timeout;
700
701 procStatus = ProcessStatus_TimedOutAbnormally;
702 break;
703 }
704
705 case PROC_STS_DWN:
706 {
707 fSignalWaiters = true; /* Signal in any case. */
708 /* Do we need to report termination? */
709 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
710 waitRes = ProcessWaitResult_Status;
711 else
712 waitRes = ProcessWaitResult_Terminate;
713
714 procStatus = ProcessStatus_Down;
715 break;
716 }
717
718 case PROC_STS_ERROR:
719 {
720 fSignalWaiters = true; /* Signal in any case. */
721 waitRes = ProcessWaitResult_Error;
722
723 procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */
724 procStatus = ProcessStatus_Error;
725 break;
726 }
727
728 case PROC_STS_UNDEFINED:
729 default:
730 {
731 /* Silently skip this request. */
732 fSignalWaiters = true; /* Signal in any case. */
733 waitRes = ProcessWaitResult_Status;
734
735 procStatus = ProcessStatus_Undefined;
736 break;
737 }
738 }
739
740 LogFlowThisFunc(("Got rc=%Rrc, waitRes=%d, procSts=%ld, procRc=%Rrc, fSignalWaiters=%RTbool\n",
741 vrc, waitRes, procStatus, procRc, fSignalWaiters));
742
743 /* Set the process status. */
744 int rc2 = setProcessStatus(procStatus, procRc);
745 if (RT_SUCCESS(vrc))
746 vrc = rc2;
747
748 /*
749 * Now do the signalling stuff.
750 */
751 if (pCallback)
752 {
753 rc2 = pCallback->Signal(procRc);
754 if (RT_SUCCESS(vrc))
755 vrc = rc2;
756 }
757
758 if (fSignalWaiters)
759 {
760 rc2 = signalWaiters(waitRes, procRc);
761 if (RT_SUCCESS(vrc))
762 vrc = rc2;
763 }
764
765 LogFlowFuncLeaveRC(vrc);
766 return vrc;
767}
768
769int GuestProcess::onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx,
770 GuestCtrlCallback *pCallback, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
771{
772 AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
773 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
774
775 if (pSvcCbData->mParms < 5)
776 return VERR_INVALID_PARAMETER;
777
778 CALLBACKDATA_PROC_OUTPUT dataCb;
779 /* pSvcCb->mpaParms[0] always contains the context ID. */
780 pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
781 pSvcCbData->mpaParms[2].getUInt32(&dataCb.uHandle);
782 pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
783 pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
784
785 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32, pCallback=%p\n",
786 dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData, pCallback));
787
788 int vrc = checkPID(dataCb.uPID);
789 if (RT_FAILURE(vrc))
790 return vrc;
791
792 /* First, signal callback in every case (if available). */
793 if (pCallback)
794 {
795 vrc = pCallback->SetData(&dataCb, sizeof(dataCb));
796
797 int rc2 = pCallback->Signal();
798 if (RT_SUCCESS(vrc))
799 vrc = rc2;
800 }
801
802 /* Then do the WaitFor signalling stuff. */
803 BOOL fSignal = FALSE;
804 uint32_t uWaitFlags = mData.mWaitEvent
805 ? mData.mWaitEvent->GetWaitFlags() : 0;
806
807 if ( (uWaitFlags & ProcessWaitForFlag_StdOut)
808 || (uWaitFlags & ProcessWaitForFlag_StdErr))
809 {
810 fSignal = TRUE;
811 }
812 else if ( (uWaitFlags & ProcessWaitForFlag_StdOut)
813 && (dataCb.uHandle == OUTPUT_HANDLE_ID_STDOUT))
814 {
815 fSignal = TRUE;
816 }
817 else if ( (uWaitFlags & ProcessWaitForFlag_StdErr)
818 && (dataCb.uHandle == OUTPUT_HANDLE_ID_STDERR))
819 {
820 fSignal = TRUE;
821 }
822
823 if (fSignal)
824 {
825 int rc2;
826 if (dataCb.uHandle == OUTPUT_HANDLE_ID_STDOUT)
827 rc2 = signalWaiters(ProcessWaitResult_StdOut);
828 else if (dataCb.uHandle == OUTPUT_HANDLE_ID_STDERR)
829 rc2 = signalWaiters(ProcessWaitResult_StdErr);
830 if (RT_SUCCESS(vrc))
831 vrc = rc2;
832 }
833
834 LogFlowFuncLeaveRC(vrc);
835 return vrc;
836}
837
838int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
839 void *pvData, size_t cbData, size_t *pcbRead, int *pGuestRc)
840{
841 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n",
842 mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc));
843 AssertReturn(uSize, VERR_INVALID_PARAMETER);
844 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
845 AssertReturn(cbData >= uSize, VERR_INVALID_PARAMETER);
846 /* pcbRead is optional. */
847
848 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
849
850 if (mData.mStatus != ProcessStatus_Started)
851 {
852 if (pcbRead)
853 *pcbRead = 0;
854 if (pGuestRc)
855 *pGuestRc = VINF_SUCCESS;
856 return VINF_SUCCESS; /* Nothing to read anymore. */
857 }
858
859 int vrc = VINF_SUCCESS;
860
861 GuestCtrlCallback *pCallbackRead = NULL;
862 try
863 {
864 pCallbackRead = new GuestCtrlCallback();
865 }
866 catch(std::bad_alloc &)
867 {
868 vrc = VERR_NO_MEMORY;
869 }
870
871 /* Create callback and add it to the map. */
872 uint32_t uContextID = 0;
873 if (RT_SUCCESS(vrc))
874 {
875 vrc = pCallbackRead->Init(CALLBACKTYPE_PROC_OUTPUT);
876 if (RT_SUCCESS(vrc))
877 vrc = callbackAdd(pCallbackRead, &uContextID);
878 }
879
880 alock.release(); /* Drop the write lock again. */
881
882 if (RT_SUCCESS(vrc))
883 {
884 VBOXHGCMSVCPARM paParms[5];
885
886 int i = 0;
887 paParms[i++].setUInt32(uContextID);
888 paParms[i++].setUInt32(mData.mPID);
889 paParms[i++].setUInt32(uHandle);
890 paParms[i++].setUInt32(0 /* Flags, none set yet. */);
891
892 vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms);
893 if (RT_FAILURE(vrc))
894 {
895 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
896 AssertRC(rc2);
897 }
898 }
899
900 if (RT_SUCCESS(vrc))
901 {
902 /*
903 * Let's wait for the process being started.
904 * Note: Be sure not keeping a AutoRead/WriteLock here.
905 */
906 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
907 vrc = pCallbackRead->Wait(uTimeoutMS);
908 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
909 {
910 int guestRc = pCallbackRead->GetResultCode();
911 LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackRead->GetDataSize()));
912
913 if (RT_SUCCESS(guestRc))
914 {
915 Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATA_PROC_OUTPUT));
916 PCALLBACKDATA_PROC_OUTPUT pData = (PCALLBACKDATA_PROC_OUTPUT)pCallbackRead->GetDataRaw();
917 AssertPtr(pData);
918
919 size_t cbRead = pData->cbData;
920 if (cbRead)
921 {
922 Assert(cbData >= cbRead);
923 memcpy(pvData, pData->pvData, cbRead);
924 }
925
926 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
927
928 if (pcbRead)
929 *pcbRead = cbRead;
930 }
931 else
932 vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
933
934 if (pGuestRc)
935 *pGuestRc = guestRc;
936 }
937 }
938
939 alock.acquire();
940
941 AssertPtr(pCallbackRead);
942 int rc2 = callbackRemove(uContextID);
943 if (RT_SUCCESS(vrc))
944 vrc = rc2;
945
946 LogFlowFuncLeaveRC(vrc);
947 return vrc;
948}
949
950/* Does not do locking; caller is responsible for that! */
951int GuestProcess::setProcessStatus(ProcessStatus_T procStatus, int procRc)
952{
953 LogFlowThisFunc(("oldStatus=%ld, newStatus=%ld, procRc=%Rrc\n",
954 mData.mStatus, procStatus, procRc));
955
956#if 0
957 if (procStatus == ProcessStatus_Error)
958 {
959 AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc));
960 /* Do not allow overwriting an already set error. If this happens
961 * this means we forgot some error checking/locking somewhere. */
962 AssertMsg(RT_SUCCESS(mData.mRC), ("Guest rc already set (to %Rrc)\n", mData.mRC));
963 }
964 else
965 AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
966#endif
967
968 mData.mStatus = procStatus;
969 mData.mRC = procRc;
970
971 return VINF_SUCCESS;
972}
973
974/* static */
975HRESULT GuestProcess::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
976{
977 AssertPtr(pInterface);
978 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
979
980 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::guestErrorToString(guestRc).c_str());
981}
982
983int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult, int rc /*= VINF_SUCCESS */)
984{
985 LogFlowThisFunc(("enmWaitResult=%d, rc=%Rrc, mWaitCount=%RU32, mWaitEvent=%p\n",
986 enmWaitResult, rc, mData.mWaitCount, mData.mWaitEvent));
987
988 /* Note: No write locking here -- already done in the caller. */
989
990 int vrc = VINF_SUCCESS;
991 if (mData.mWaitEvent)
992 vrc = mData.mWaitEvent->Signal(enmWaitResult, rc);
993 LogFlowFuncLeaveRC(vrc);
994 return vrc;
995}
996
997int GuestProcess::startProcess(int *pGuestRc)
998{
999 LogFlowThisFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n",
1000 mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags));
1001
1002 /* Wait until the caller function (if kicked off by a thread)
1003 * has returned and continue operation. */
1004 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1005
1006 int vrc = VINF_SUCCESS;
1007 uint32_t uContextID = 0;
1008
1009 GuestCtrlCallback *pCallbackStart;
1010 try
1011 {
1012 pCallbackStart = new GuestCtrlCallback();
1013 }
1014 catch(std::bad_alloc &)
1015 {
1016 vrc = VERR_NO_MEMORY;
1017 }
1018
1019 if (RT_SUCCESS(vrc))
1020 {
1021 mData.mStatus = ProcessStatus_Starting;
1022
1023 /* Create callback and add it to the map. */
1024 vrc = pCallbackStart->Init(CALLBACKTYPE_PROC_STATUS);
1025 if (RT_SUCCESS(vrc))
1026 vrc = callbackAdd(pCallbackStart, &uContextID);
1027 }
1028
1029 if (RT_SUCCESS(vrc))
1030 {
1031 GuestSession *pSession = mObject.mSession;
1032 AssertPtr(pSession);
1033
1034 const GuestCredentials &sessionCreds = pSession->getCredentials();
1035
1036 /* Prepare arguments. */
1037 char *pszArgs = NULL;
1038 size_t cArgs = mData.mProcess.mArguments.size();
1039 if (cArgs >= UINT32_MAX)
1040 vrc = VERR_BUFFER_OVERFLOW;
1041
1042 if ( RT_SUCCESS(vrc)
1043 && cArgs)
1044 {
1045 char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
1046 AssertReturn(papszArgv, VERR_NO_MEMORY);
1047
1048 for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
1049 {
1050 const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
1051 AssertPtr(pszCurArg);
1052 vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
1053 }
1054 papszArgv[cArgs] = NULL;
1055
1056 if (RT_SUCCESS(vrc))
1057 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
1058
1059 if (papszArgv)
1060 {
1061 size_t i = 0;
1062 while (papszArgv[i])
1063 RTStrFree(papszArgv[i++]);
1064 RTMemFree(papszArgv);
1065 }
1066 }
1067
1068 /* Calculate arguments size (in bytes). */
1069 size_t cbArgs = 0;
1070 if (RT_SUCCESS(vrc))
1071 cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
1072
1073 /* Prepare environment. */
1074 void *pvEnv = NULL;
1075 size_t cbEnv = 0;
1076 if (RT_SUCCESS(vrc))
1077 vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
1078
1079 if (RT_SUCCESS(vrc))
1080 {
1081 AssertPtr(mObject.mSession);
1082 uint32_t uProtocol = mObject.mSession->getProtocolVersion();
1083
1084 /* Prepare HGCM call. */
1085 VBOXHGCMSVCPARM paParms[16];
1086 int i = 0;
1087 paParms[i++].setUInt32(uContextID);
1088 paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
1089 (ULONG)mData.mProcess.mCommand.length() + 1);
1090 paParms[i++].setUInt32(mData.mProcess.mFlags);
1091 paParms[i++].setUInt32(mData.mProcess.mArguments.size());
1092 paParms[i++].setPointer((void*)pszArgs, cbArgs);
1093 paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size());
1094 paParms[i++].setUInt32(cbEnv);
1095 paParms[i++].setPointer((void*)pvEnv, cbEnv);
1096 if (uProtocol < 2)
1097 {
1098 /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
1099 * call. In newer protocols these credentials are part of the opened guest
1100 * session, so not needed anymore here. */
1101 paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
1102 paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
1103 }
1104 /*
1105 * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
1106 * until the process was started - the process itself then gets an infinite timeout for execution.
1107 * This is handy when we want to start a process inside a worker thread within a certain timeout
1108 * but let the started process perform lengthly operations then.
1109 */
1110 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1111 paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
1112 else
1113 paParms[i++].setUInt32(mData.mProcess.mTimeoutMS);
1114 if (uProtocol >= 2)
1115 {
1116 paParms[i++].setUInt32(mData.mProcess.mPriority);
1117 /* CPU affinity: We only support one CPU affinity block at the moment,
1118 * so that makes up to 64 CPUs total. This can be more in the future. */
1119 paParms[i++].setUInt32(1);
1120 /* The actual CPU affinity blocks. */
1121 paParms[i++].setPointer((void*)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
1122 }
1123
1124 /* Note: Don't hold the write lock in here. */
1125 vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
1126 if (RT_FAILURE(vrc))
1127 {
1128 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
1129 AssertRC(rc2);
1130 }
1131 }
1132
1133 GuestEnvironment::FreeEnvironmentBlock(pvEnv);
1134 if (pszArgs)
1135 RTStrFree(pszArgs);
1136
1137 uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
1138
1139 /* Drop the write lock again before waiting. */
1140 alock.release();
1141
1142 if (RT_SUCCESS(vrc))
1143 {
1144 /*
1145 * Let's wait for the process being started.
1146 * Note: Be sure not keeping a AutoRead/WriteLock here.
1147 */
1148 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
1149 vrc = pCallbackStart->Wait(uTimeoutMS);
1150 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
1151 {
1152 int guestRc = pCallbackStart->GetResultCode();
1153 if (pGuestRc)
1154 *pGuestRc = guestRc;
1155 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
1156 }
1157 else
1158 vrc = VERR_TIMEOUT;
1159 }
1160
1161 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
1162
1163 AssertPtr(pCallbackStart);
1164 int rc2 = callbackRemove(uContextID);
1165 if (RT_SUCCESS(vrc))
1166 vrc = rc2;
1167 }
1168
1169 LogFlowFuncLeaveRC(vrc);
1170 return vrc;
1171}
1172
1173int GuestProcess::startProcessAsync(void)
1174{
1175 LogFlowThisFuncEnter();
1176
1177 int vrc;
1178
1179 try
1180 {
1181 /* Asynchronously start the process on the guest by kicking off a
1182 * worker thread. */
1183 std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
1184 AssertReturn(pTask->isOk(), pTask->rc());
1185
1186 vrc = RTThreadCreate(NULL, GuestProcess::startProcessThread,
1187 (void *)pTask.get(), 0,
1188 RTTHREADTYPE_MAIN_WORKER, 0,
1189 "gctlPrcStart");
1190 if (RT_SUCCESS(vrc))
1191 {
1192 /* pTask is now owned by startProcessThread(), so release it. */
1193 pTask.release();
1194 }
1195 }
1196 catch(std::bad_alloc &)
1197 {
1198 vrc = VERR_NO_MEMORY;
1199 }
1200
1201 LogFlowFuncLeaveRC(vrc);
1202 return vrc;
1203}
1204
1205/* static */
1206DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser)
1207{
1208 LogFlowFunc(("pvUser=%p\n", pvUser));
1209
1210 std::auto_ptr<GuestProcessStartTask> pTask(static_cast<GuestProcessStartTask*>(pvUser));
1211 AssertPtr(pTask.get());
1212
1213 const ComObjPtr<GuestProcess> pProcess(pTask->Process());
1214 Assert(!pProcess.isNull());
1215
1216 AutoCaller autoCaller(pProcess);
1217 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1218
1219 int vrc = pProcess->startProcess(NULL /* Guest rc, ignored */);
1220 /* Nothing to do here anymore. */
1221
1222 LogFlowFuncLeaveRC(vrc);
1223 return vrc;
1224}
1225
1226int GuestProcess::terminateProcess(int *pGuestRc)
1227{
1228 LogFlowThisFuncEnter();
1229
1230 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1231
1232 if (mObject.mSession->getProtocolVersion() < 2)
1233 return VERR_NOT_SUPPORTED;
1234
1235 if (mData.mStatus != ProcessStatus_Started)
1236 return VINF_SUCCESS; /* Nothing to do (anymore). */
1237
1238 int vrc = VINF_SUCCESS;
1239
1240 GuestCtrlCallback *pCallbackTerminate = NULL;
1241 try
1242 {
1243 pCallbackTerminate = new GuestCtrlCallback();
1244 }
1245 catch(std::bad_alloc &)
1246 {
1247 vrc = VERR_NO_MEMORY;
1248 }
1249
1250 /* Create callback and add it to the map. */
1251 uint32_t uContextID;
1252 if (RT_SUCCESS(vrc))
1253 vrc = callbackAdd(pCallbackTerminate, &uContextID);
1254
1255 alock.release(); /* Drop the write lock again. */
1256
1257 if (RT_SUCCESS(vrc))
1258 {
1259 VBOXHGCMSVCPARM paParms[5];
1260
1261 int i = 0;
1262 paParms[i++].setUInt32(uContextID);
1263 paParms[i++].setUInt32(mData.mPID);
1264
1265 //vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
1266 }
1267
1268 if (RT_SUCCESS(vrc))
1269 {
1270 /*
1271 * Let's wait for the process being terminated.
1272 * Note: Be sure not keeping a AutoRead/WriteLock here.
1273 */
1274 LogFlowThisFunc(("Waiting for callback (30s) ...\n"));
1275 vrc = pCallbackTerminate->Wait(30 * 1000);
1276 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
1277 {
1278 int guestRc = pCallbackTerminate->GetResultCode();
1279 if (RT_SUCCESS(guestRc))
1280 {
1281 /* Nothing to do here right now. */
1282 }
1283 else
1284 vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
1285
1286 if (pGuestRc)
1287 *pGuestRc = guestRc;
1288 LogFlowThisFunc(("Callback returned rc=%Rrc\n", guestRc));
1289 }
1290 }
1291
1292 alock.acquire();
1293
1294 AssertPtr(pCallbackTerminate);
1295 int rc2 = callbackRemove(uContextID);
1296 if (RT_SUCCESS(vrc))
1297 vrc = rc2;
1298
1299 LogFlowFuncLeaveRC(vrc);
1300 return vrc;
1301}
1302
1303int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, ProcessWaitResult_T &waitResult, int *pGuestRc)
1304{
1305 LogFlowThisFuncEnter();
1306
1307 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
1308
1309 LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p, pGuestRc=%p\n",
1310 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent, pGuestRc));
1311
1312 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1313
1314 /* Did some error occur before? Then skip waiting and return. */
1315 if (mData.mStatus == ProcessStatus_Error)
1316 {
1317 waitResult = ProcessWaitResult_Error;
1318 AssertMsg(RT_FAILURE(mData.mRC), ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mRC));
1319 if (pGuestRc)
1320 *pGuestRc = mData.mRC; /* Return last set error. */
1321 return VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
1322 }
1323
1324 waitResult = ProcessWaitResult_None;
1325 if ( (fWaitFlags & ProcessWaitForFlag_Terminate)
1326 || (fWaitFlags & ProcessWaitForFlag_StdIn)
1327 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1328 || (fWaitFlags & ProcessWaitForFlag_StdErr))
1329 {
1330 switch (mData.mStatus)
1331 {
1332 case ProcessStatus_TerminatedNormally:
1333 case ProcessStatus_TerminatedSignal:
1334 case ProcessStatus_TerminatedAbnormally:
1335 case ProcessStatus_Down:
1336 waitResult = ProcessWaitResult_Terminate;
1337 break;
1338
1339 case ProcessStatus_TimedOutKilled:
1340 case ProcessStatus_TimedOutAbnormally:
1341 waitResult = ProcessWaitResult_Timeout;
1342 break;
1343
1344 case ProcessStatus_Error:
1345 /* Handled above. */
1346 break;
1347
1348 case ProcessStatus_Started:
1349 {
1350 /*
1351 * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the
1352 * caller is not interested in getting further process statuses -- so just don't notify
1353 * anything here anymore and return.
1354 */
1355 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1356 waitResult = ProcessWaitResult_Start;
1357 break;
1358 }
1359
1360 case ProcessStatus_Undefined:
1361 case ProcessStatus_Starting:
1362 /* Do the waiting below. */
1363 break;
1364
1365 default:
1366 AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus));
1367 return VERR_NOT_IMPLEMENTED;
1368 }
1369 }
1370 else if (fWaitFlags & ProcessWaitForFlag_Start)
1371 {
1372 switch (mData.mStatus)
1373 {
1374 case ProcessStatus_Started:
1375 case ProcessStatus_Paused:
1376 case ProcessStatus_Terminating:
1377 case ProcessStatus_TerminatedNormally:
1378 case ProcessStatus_TerminatedSignal:
1379 case ProcessStatus_TerminatedAbnormally:
1380 case ProcessStatus_Down:
1381 waitResult = ProcessWaitResult_Start;
1382 break;
1383
1384 case ProcessStatus_Error:
1385 waitResult = ProcessWaitResult_Error;
1386 break;
1387
1388 case ProcessStatus_TimedOutKilled:
1389 case ProcessStatus_TimedOutAbnormally:
1390 waitResult = ProcessWaitResult_Timeout;
1391 break;
1392
1393 case ProcessStatus_Undefined:
1394 case ProcessStatus_Starting:
1395 /* Do the waiting below. */
1396 break;
1397
1398 default:
1399 AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus));
1400 return VERR_NOT_IMPLEMENTED;
1401 }
1402 }
1403
1404 /* Filter out waits which are *not* supported using
1405 * older guest control Guest Additions. */
1406 if (mObject.mSession->getProtocolVersion() < 2)
1407 {
1408 if ( waitResult == ProcessWaitResult_None
1409 /* We don't support waiting for stdin, out + err,
1410 * just skip waiting then. */
1411 && ( (fWaitFlags & ProcessWaitForFlag_StdIn)
1412 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1413 || (fWaitFlags & ProcessWaitForFlag_StdErr)
1414 )
1415 )
1416 {
1417 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
1418 waitResult = ProcessWaitResult_WaitFlagNotSupported;
1419 }
1420 }
1421
1422 LogFlowThisFunc(("procStatus=%ld, procRc=%Rrc, waitResult=%ld\n",
1423 mData.mStatus, mData.mRC, waitResult));
1424
1425 /* No waiting needed? Return immediately using the last set error. */
1426 if (waitResult != ProcessWaitResult_None)
1427 {
1428 if (pGuestRc)
1429 *pGuestRc = mData.mRC; /* Return last set error (if any). */
1430 return RT_SUCCESS(mData.mRC) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
1431 }
1432
1433 if (mData.mWaitCount > 0) /* We only support one waiting caller a time at the moment. */
1434 return VERR_ALREADY_EXISTS;
1435 mData.mWaitCount++;
1436
1437 int vrc = VINF_SUCCESS;
1438 try
1439 {
1440 Assert(mData.mWaitEvent == NULL);
1441 mData.mWaitEvent = new GuestProcessWaitEvent(fWaitFlags);
1442 }
1443 catch(std::bad_alloc &)
1444 {
1445 vrc = VERR_NO_MEMORY;
1446 }
1447
1448 if (RT_SUCCESS(vrc))
1449 {
1450 GuestProcessWaitEvent *pEvent = mData.mWaitEvent;
1451 AssertPtr(pEvent);
1452
1453 alock.release(); /* Release lock before waiting. */
1454
1455 vrc = pEvent->Wait(uTimeoutMS);
1456 LogFlowThisFunc(("Waiting completed with rc=%Rrc\n", vrc));
1457 if (RT_SUCCESS(vrc))
1458 {
1459 waitResult = pEvent->GetWaitResult();
1460 int waitRc = pEvent->GetWaitRc();
1461
1462 LogFlowThisFunc(("Waiting event returned rc=%Rrc\n", waitRc));
1463
1464 if (pGuestRc)
1465 *pGuestRc = waitRc;
1466
1467 vrc = RT_SUCCESS(waitRc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
1468 }
1469
1470 alock.acquire(); /* Get the lock again. */
1471
1472 /* Note: The caller always is responsible of deleting the
1473 * stuff it created before. See close() for more information. */
1474 delete mData.mWaitEvent;
1475 mData.mWaitEvent = NULL;
1476 }
1477
1478 Assert(mData.mWaitCount);
1479 mData.mWaitCount--;
1480
1481 LogFlowFuncLeaveRC(vrc);
1482 return vrc;
1483}
1484
1485int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
1486 void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc)
1487{
1488 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p, pGuestRc=%p\n",
1489 mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten, pGuestRc));
1490 /* All is optional. There can be 0 byte writes. */
1491
1492 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1493
1494 if (mData.mStatus != ProcessStatus_Started)
1495 {
1496 if (puWritten)
1497 *puWritten = 0;
1498 if (pGuestRc)
1499 *pGuestRc = VINF_SUCCESS;
1500 return VINF_SUCCESS; /* Not available for writing (anymore). */
1501 }
1502
1503 int vrc = VINF_SUCCESS;
1504
1505 GuestCtrlCallback *pCallbackWrite = NULL;
1506 try
1507 {
1508 pCallbackWrite = new GuestCtrlCallback();
1509 }
1510 catch(std::bad_alloc &)
1511 {
1512 vrc = VERR_NO_MEMORY;
1513 }
1514
1515 /* Create callback and add it to the map. */
1516 uint32_t uContextID = 0;
1517 if (RT_SUCCESS(vrc))
1518 {
1519 vrc = pCallbackWrite->Init(CALLBACKTYPE_PROC_INPUT);
1520 if (RT_SUCCESS(vrc))
1521 vrc = callbackAdd(pCallbackWrite, &uContextID);
1522 }
1523
1524 alock.release(); /* Drop the write lock again. */
1525
1526 if (RT_SUCCESS(vrc))
1527 {
1528 VBOXHGCMSVCPARM paParms[5];
1529
1530 int i = 0;
1531 paParms[i++].setUInt32(uContextID);
1532 paParms[i++].setUInt32(mData.mPID);
1533 paParms[i++].setUInt32(uFlags);
1534 paParms[i++].setPointer(pvData, cbData);
1535 paParms[i++].setUInt32(cbData);
1536
1537 vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
1538 if (RT_FAILURE(vrc))
1539 {
1540 int rc2 = setProcessStatus(ProcessStatus_Error, vrc);
1541 AssertRC(rc2);
1542 }
1543 }
1544
1545 if (RT_SUCCESS(vrc))
1546 {
1547 /*
1548 * Let's wait for the process being started.
1549 * Note: Be sure not keeping a AutoRead/WriteLock here.
1550 */
1551 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
1552 vrc = pCallbackWrite->Wait(uTimeoutMS);
1553 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
1554 {
1555 int guestRc = pCallbackWrite->GetResultCode();
1556 LogFlowThisFunc(("Callback returned rc=%Rrc, cbData=%RU32\n", guestRc, pCallbackWrite->GetDataSize()));
1557
1558 if (RT_SUCCESS(guestRc))
1559 {
1560 Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATA_PROC_INPUT));
1561 PCALLBACKDATA_PROC_INPUT pData = (PCALLBACKDATA_PROC_INPUT)pCallbackWrite->GetDataRaw();
1562 AssertPtr(pData);
1563
1564 uint32_t cbWritten = 0;
1565 switch (pData->uStatus)
1566 {
1567 case INPUT_STS_WRITTEN:
1568 cbWritten = pData->uProcessed;
1569 break;
1570
1571 case INPUT_STS_ERROR:
1572 vrc = pData->uFlags; /** @todo Fix int vs. uint32_t! */
1573 break;
1574
1575 case INPUT_STS_TERMINATED:
1576 vrc = VERR_CANCELLED;
1577 break;
1578
1579 case INPUT_STS_OVERFLOW:
1580 vrc = VERR_BUFFER_OVERFLOW;
1581 break;
1582
1583 default:
1584 /* Silently skip unknown errors. */
1585 break;
1586 }
1587
1588 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1589
1590 if (pGuestRc)
1591 *pGuestRc = guestRc;
1592
1593 if (puWritten)
1594 *puWritten = cbWritten;
1595
1596 if (RT_FAILURE(guestRc))
1597 vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
1598 }
1599 }
1600 }
1601
1602 alock.acquire();
1603
1604 int rc2 = callbackRemove(uContextID);
1605 if (RT_SUCCESS(vrc))
1606 vrc = rc2;
1607
1608 LogFlowFuncLeaveRC(vrc);
1609 return vrc;
1610}
1611
1612// implementation of public methods
1613/////////////////////////////////////////////////////////////////////////////
1614
1615STDMETHODIMP GuestProcess::Read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1616{
1617#ifndef VBOX_WITH_GUEST_CONTROL
1618 ReturnComNotImplemented();
1619#else
1620 if (aToRead == 0)
1621 return setError(E_INVALIDARG, tr("The size to read is zero"));
1622 CheckComArgOutSafeArrayPointerValid(aData);
1623
1624 AutoCaller autoCaller(this);
1625 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1626
1627 com::SafeArray<BYTE> data((size_t)aToRead);
1628 Assert(data.size() >= aToRead);
1629
1630 HRESULT hr = S_OK;
1631
1632 size_t cbRead; int guestRc;
1633 int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead, &guestRc);
1634 if (RT_SUCCESS(vrc))
1635 {
1636 if (data.size() != cbRead)
1637 data.resize(cbRead);
1638 data.detachTo(ComSafeArrayOutArg(aData));
1639 }
1640 else
1641 {
1642 switch (vrc)
1643 {
1644 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1645 hr = GuestProcess::setErrorExternal(this, guestRc);
1646 break;
1647
1648 default:
1649 hr = setError(VBOX_E_IPRT_ERROR,
1650 tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
1651 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1652 break;
1653 }
1654 }
1655
1656 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64\n", vrc, cbRead));
1657
1658 LogFlowFuncLeaveRC(vrc);
1659 return hr;
1660#endif /* VBOX_WITH_GUEST_CONTROL */
1661}
1662
1663STDMETHODIMP GuestProcess::Terminate(void)
1664{
1665#ifndef VBOX_WITH_GUEST_CONTROL
1666 ReturnComNotImplemented();
1667#else
1668 LogFlowThisFuncEnter();
1669
1670 AutoCaller autoCaller(this);
1671 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1672
1673 HRESULT hr = S_OK;
1674
1675 int guestRc;
1676 int vrc = terminateProcess(&guestRc);
1677 if (RT_FAILURE(vrc))
1678 {
1679 switch (vrc)
1680 {
1681 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1682 hr = GuestProcess::setErrorExternal(this, guestRc);
1683 break;
1684
1685 case VERR_NOT_SUPPORTED:
1686 hr = setError(VBOX_E_IPRT_ERROR,
1687 tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"),
1688 mData.mProcess.mCommand.c_str(), mData.mPID);
1689 break;
1690
1691 default:
1692 hr = setError(VBOX_E_IPRT_ERROR,
1693 tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"),
1694 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1695 break;
1696 }
1697 }
1698
1699 AssertPtr(mObject.mSession);
1700 mObject.mSession->processRemoveFromList(this);
1701
1702 /*
1703 * Release autocaller before calling uninit.
1704 */
1705 autoCaller.release();
1706
1707 uninit();
1708
1709 LogFlowFuncLeaveRC(vrc);
1710 return hr;
1711#endif /* VBOX_WITH_GUEST_CONTROL */
1712}
1713
1714STDMETHODIMP GuestProcess::WaitFor(ULONG aWaitFlags, ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1715{
1716#ifndef VBOX_WITH_GUEST_CONTROL
1717 ReturnComNotImplemented();
1718#else
1719 LogFlowThisFuncEnter();
1720
1721 CheckComArgOutPointerValid(aReason);
1722
1723 AutoCaller autoCaller(this);
1724 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1725
1726 /*
1727 * Note: Do not hold any locks here while waiting!
1728 */
1729 HRESULT hr = S_OK;
1730
1731 int guestRc; ProcessWaitResult_T waitResult;
1732 int vrc = waitFor(aWaitFlags, aTimeoutMS, waitResult, &guestRc);
1733 if (RT_SUCCESS(vrc))
1734 {
1735 *aReason = waitResult;
1736 }
1737 else
1738 {
1739 switch (vrc)
1740 {
1741 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1742 hr = GuestProcess::setErrorExternal(this, guestRc);
1743 break;
1744
1745 case VERR_TIMEOUT:
1746 *aReason = ProcessWaitResult_Timeout;
1747 break;
1748
1749 default:
1750 hr = setError(VBOX_E_IPRT_ERROR,
1751 tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
1752 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1753 break;
1754 }
1755 }
1756
1757 LogFlowFuncLeaveRC(vrc);
1758 return hr;
1759#endif /* VBOX_WITH_GUEST_CONTROL */
1760}
1761
1762STDMETHODIMP GuestProcess::WaitForArray(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1763{
1764#ifndef VBOX_WITH_GUEST_CONTROL
1765 ReturnComNotImplemented();
1766#else
1767 LogFlowThisFuncEnter();
1768
1769 CheckComArgOutPointerValid(aReason);
1770
1771 AutoCaller autoCaller(this);
1772 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1773
1774 /*
1775 * Note: Do not hold any locks here while waiting!
1776 */
1777 uint32_t fWaitFor = ProcessWaitForFlag_None;
1778 com::SafeArray<ProcessWaitForFlag_T> flags(ComSafeArrayInArg(aFlags));
1779 for (size_t i = 0; i < flags.size(); i++)
1780 fWaitFor |= flags[i];
1781
1782 return WaitFor(fWaitFor, aTimeoutMS, aReason);
1783#endif /* VBOX_WITH_GUEST_CONTROL */
1784}
1785
1786STDMETHODIMP GuestProcess::Write(ULONG aHandle, ULONG aFlags,
1787 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1788{
1789#ifndef VBOX_WITH_GUEST_CONTROL
1790 ReturnComNotImplemented();
1791#else
1792 LogFlowThisFuncEnter();
1793
1794 CheckComArgOutPointerValid(aWritten);
1795
1796 AutoCaller autoCaller(this);
1797 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1798
1799 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1800
1801 HRESULT hr = S_OK;
1802
1803 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData)); int guestRc;
1804 int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten, &guestRc);
1805 if (RT_FAILURE(vrc))
1806 {
1807 switch (vrc)
1808 {
1809 case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */
1810 hr = GuestProcess::setErrorExternal(this, guestRc);
1811 break;
1812
1813 default:
1814 hr = setError(VBOX_E_IPRT_ERROR,
1815 tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
1816 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1817 break;
1818 }
1819 }
1820
1821 LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, aWritten));
1822
1823 LogFlowFuncLeaveRC(vrc);
1824 return hr;
1825#endif /* VBOX_WITH_GUEST_CONTROL */
1826}
1827
1828STDMETHODIMP GuestProcess::WriteArray(ULONG aHandle, ComSafeArrayIn(ProcessInputFlag_T, aFlags),
1829 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1830{
1831#ifndef VBOX_WITH_GUEST_CONTROL
1832 ReturnComNotImplemented();
1833#else
1834 LogFlowThisFuncEnter();
1835
1836 CheckComArgOutPointerValid(aWritten);
1837
1838 AutoCaller autoCaller(this);
1839 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1840
1841 /*
1842 * Note: Do not hold any locks here while writing!
1843 */
1844 ULONG fWrite = ProcessInputFlag_None;
1845 com::SafeArray<ProcessInputFlag_T> flags(ComSafeArrayInArg(aFlags));
1846 for (size_t i = 0; i < flags.size(); i++)
1847 fWrite |= flags[i];
1848
1849 return Write(aHandle, fWrite, ComSafeArrayInArg(aData), aTimeoutMS, aWritten);
1850#endif /* VBOX_WITH_GUEST_CONTROL */
1851}
1852
1853///////////////////////////////////////////////////////////////////////////////
1854
1855GuestProcessTool::GuestProcessTool(void)
1856 : pSession(NULL)
1857{
1858}
1859
1860GuestProcessTool::~GuestProcessTool(void)
1861{
1862 Terminate();
1863}
1864
1865int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
1866 bool fAsync, int *pGuestRc)
1867{
1868 LogFlowThisFunc(("pGuestSession=%p, szCmd=%s, fAsync=%RTbool\n",
1869 pGuestSession, startupInfo.mCommand.c_str(), fAsync));
1870
1871 AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
1872
1873 pSession = pGuestSession;
1874 mStartupInfo = startupInfo;
1875
1876 /* Make sure the process is hidden. */
1877 mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
1878
1879 int vrc = pSession->processCreateExInteral(mStartupInfo, pProcess);
1880 if (RT_SUCCESS(vrc))
1881 vrc = fAsync ? pProcess->startProcessAsync() : pProcess->startProcess(pGuestRc);
1882
1883 if ( RT_SUCCESS(vrc)
1884 && !fAsync
1885 && ( pGuestRc
1886 && RT_FAILURE(*pGuestRc)
1887 )
1888 )
1889 {
1890 vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
1891 }
1892
1893 LogFlowFuncLeaveRC(vrc);
1894 return vrc;
1895}
1896
1897int GuestProcessTool::GetCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock)
1898{
1899 const GuestProcessStream *pStream = NULL;
1900 if (uHandle == OUTPUT_HANDLE_ID_STDOUT)
1901 pStream = &mStdOut;
1902 else if (uHandle == OUTPUT_HANDLE_ID_STDERR)
1903 pStream = &mStdErr;
1904
1905 if (!pStream)
1906 return VERR_INVALID_PARAMETER;
1907
1908 int vrc;
1909 do
1910 {
1911 /* Try parsing the data to see if the current block is complete. */
1912 vrc = mStdOut.ParseBlock(strmBlock);
1913 if (strmBlock.GetCount())
1914 break;
1915 } while (RT_SUCCESS(vrc));
1916
1917 LogFlowThisFunc(("rc=%Rrc, %RU64 pairs\n",
1918 vrc, strmBlock.GetCount()));
1919 return vrc;
1920}
1921
1922bool GuestProcessTool::IsRunning(void)
1923{
1924 AssertReturn(!pProcess.isNull(), true);
1925
1926 ProcessStatus_T procStatus = ProcessStatus_Undefined;
1927 HRESULT hr = pProcess->COMGETTER(Status(&procStatus));
1928 Assert(SUCCEEDED(hr));
1929
1930 if ( procStatus != ProcessStatus_Started
1931 && procStatus != ProcessStatus_Paused
1932 && procStatus != ProcessStatus_Terminating)
1933 {
1934 return false;
1935 }
1936
1937 return true;
1938}
1939
1940int GuestProcessTool::TerminatedOk(LONG *pExitCode)
1941{
1942 Assert(!pProcess.isNull());
1943 /* pExitCode is optional. */
1944
1945 if (!IsRunning())
1946 {
1947 LONG exitCode;
1948 HRESULT hr = pProcess->COMGETTER(ExitCode(&exitCode));
1949 Assert(SUCCEEDED(hr));
1950
1951 if (pExitCode)
1952 *pExitCode = exitCode;
1953
1954 if (exitCode != 0)
1955 return VERR_NOT_EQUAL; /** @todo Special guest control rc needed! */
1956 return VINF_SUCCESS;
1957 }
1958
1959 return VERR_INVALID_STATE; /** @todo Special guest control rc needed! */
1960}
1961
1962int GuestProcessTool::Wait(uint32_t fFlags, int *pGuestRc)
1963{
1964 return WaitEx(fFlags, NULL /* pStreamBlock */, pGuestRc);
1965}
1966
1967int GuestProcessTool::WaitEx(uint32_t fFlags, GuestProcessStreamBlock *pStreamBlock, int *pGuestRc)
1968{
1969 LogFlowThisFunc(("pSession=%p, fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n",
1970 pSession, fFlags, pStreamBlock, pGuestRc));
1971
1972 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
1973 Assert(!pProcess.isNull());
1974 /* Other parameters are optional. */
1975
1976 /* Can we parse the next block without waiting? */
1977 int vrc;
1978 if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)
1979 {
1980 AssertPtr(pStreamBlock);
1981 vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
1982 if (RT_SUCCESS(vrc))
1983 return vrc;
1984 }
1985
1986 /* Do the waiting. */
1987 uint32_t fWaitFlags = ProcessWaitForFlag_Terminate;
1988 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
1989 fWaitFlags |= ProcessWaitForFlag_StdOut;
1990 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
1991 fWaitFlags |= ProcessWaitForFlag_StdErr;
1992
1993 LogFlowFunc(("waitFlags=0x%x\n", fWaitFlags));
1994
1995 /** @todo Decrease timeout. */
1996 uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS;
1997
1998 int guestRc;
1999 bool fDone = false;
2000
2001 BYTE byBuf[_64K];
2002 size_t cbRead;
2003
2004 bool fHandleStdOut = false;
2005 bool fHandleStdErr = false;
2006
2007 ProcessWaitResult_T waitRes;
2008 do
2009 {
2010 vrc = pProcess->waitFor(fWaitFlags,
2011 uTimeoutMS, waitRes, &guestRc);
2012 if (RT_FAILURE(vrc))
2013 break;
2014
2015 switch (waitRes)
2016 {
2017 case ProcessWaitResult_StdIn:
2018 vrc = VERR_NOT_IMPLEMENTED;
2019 break;
2020
2021 case ProcessWaitResult_StdOut:
2022 fHandleStdOut = true;
2023 break;
2024
2025 case ProcessWaitResult_StdErr:
2026 fHandleStdErr = true;
2027 break;
2028
2029 case ProcessWaitResult_WaitFlagNotSupported:
2030 if (fWaitFlags & ProcessWaitForFlag_StdOut)
2031 fHandleStdOut = true;
2032 if (fWaitFlags & ProcessWaitForFlag_StdErr)
2033 fHandleStdErr = true;
2034 /* Since waiting for stdout / stderr is not supported by the guest,
2035 * wait a bit to not hog the CPU too much when polling for data. */
2036 RTThreadSleep(1); /* Optional, don't check rc. */
2037 break;
2038
2039 case ProcessWaitResult_Error:
2040 vrc = VERR_GENERAL_FAILURE; /** @todo Special guest control rc needed! */
2041 break;
2042
2043 case ProcessWaitResult_Terminate:
2044 fDone = true;
2045 break;
2046
2047 case ProcessWaitResult_Timeout:
2048 vrc = VERR_TIMEOUT;
2049 break;
2050
2051 case ProcessWaitResult_Start:
2052 case ProcessWaitResult_Status:
2053 /* Not used here, just skip. */
2054 break;
2055
2056 default:
2057 AssertReleaseMsgFailed(("Unhandled process wait result %ld\n", waitRes));
2058 break;
2059 }
2060
2061 if (fHandleStdOut)
2062 {
2063 vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
2064 uTimeoutMS, byBuf, sizeof(byBuf),
2065 &cbRead, &guestRc);
2066 if (RT_FAILURE(vrc))
2067 break;
2068
2069 if (cbRead)
2070 {
2071 LogFlowThisFunc(("Received %RU64 bytes from stdout\n", cbRead));
2072 vrc = mStdOut.AddData(byBuf, cbRead);
2073
2074 if ( RT_SUCCESS(vrc)
2075 && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK))
2076 {
2077 AssertPtr(pStreamBlock);
2078 vrc = GetCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStreamBlock);
2079 if (RT_SUCCESS(vrc))
2080 fDone = true;
2081 }
2082 }
2083
2084 fHandleStdOut = false;
2085 }
2086
2087 if (fHandleStdErr)
2088 {
2089 vrc = pProcess->readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf),
2090 uTimeoutMS, byBuf, sizeof(byBuf),
2091 &cbRead, &guestRc);
2092 if (RT_FAILURE(vrc))
2093 break;
2094
2095 if (cbRead)
2096 {
2097 LogFlowThisFunc(("Received %RU64 bytes from stderr\n", cbRead));
2098 vrc = mStdErr.AddData(byBuf, cbRead);
2099 }
2100
2101 fHandleStdErr = false;
2102 }
2103
2104 } while (!fDone && RT_SUCCESS(vrc));
2105
2106 LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%ld\n",
2107 vrc, guestRc, waitRes));
2108 if (pGuestRc)
2109 *pGuestRc = guestRc;
2110
2111 LogFlowFuncLeaveRC(vrc);
2112 return vrc;
2113}
2114
2115void GuestProcessTool::Terminate(void)
2116{
2117 LogFlowThisFuncEnter();
2118
2119 if (!pProcess.isNull())
2120 {
2121 /** @todo Add pProcess.Terminate() here as soon as it's implemented. */
2122
2123 Assert(pSession);
2124 int rc2 = pSession->processRemoveFromList(pProcess);
2125 AssertRC(rc2);
2126
2127 pProcess.setNull();
2128 }
2129
2130 LogFlowThisFuncLeave();
2131}
2132
Note: See TracBrowser for help on using the repository browser.

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