VirtualBox

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

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

GuestCtrl: Infrastructure changes for handling and executing dedicated guest sessions and protocol versioning (untested, work in progress).

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