VirtualBox

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

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

GuestCtrl: More stuff for IGuestFile and IGuestSession handling (work in progress).

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

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