VirtualBox

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

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

Main/GuestProcessImpl: Fixed leak when building up argv vector.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 53.5 KB
Line 
1
2/* $Id: GuestProcessImpl.cpp 43062 2012-08-29 09:46:14Z vboxsync $ */
3/** @file
4 * VirtualBox Main - XXX.
5 */
6
7/*
8 * Copyright (C) 2012 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#include "VMMDev.h"
39
40#include <memory> /* For auto_ptr. */
41
42#include <iprt/asm.h>
43#include <iprt/getopt.h>
44#include <VBox/VMMDev.h>
45#include <VBox/com/array.h>
46
47#ifdef LOG_GROUP
48 #undef LOG_GROUP
49#endif
50#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
51#include <VBox/log.h>
52
53
54class GuestProcessTask
55{
56public:
57
58 GuestProcessTask(GuestProcess *pProcess)
59 : mProcess(pProcess),
60 mRC(VINF_SUCCESS) { }
61
62 virtual ~GuestProcessTask(void) { }
63
64 int rc(void) const { return mRC; }
65 bool isOk(void) const { return RT_SUCCESS(mRC); }
66 const ComObjPtr<GuestProcess> &Process(void) const { return mProcess; }
67
68protected:
69
70 const ComObjPtr<GuestProcess> mProcess;
71 int mRC;
72};
73
74class GuestProcessStartTask : public GuestProcessTask
75{
76public:
77
78 GuestProcessStartTask(GuestProcess *pProcess)
79 : GuestProcessTask(pProcess) { }
80};
81
82
83// constructor / destructor
84/////////////////////////////////////////////////////////////////////////////
85
86DEFINE_EMPTY_CTOR_DTOR(GuestProcess)
87
88HRESULT GuestProcess::FinalConstruct(void)
89{
90 LogFlowThisFuncEnter();
91
92 mData.mExitCode = 0;
93 mData.mNextContextID = 0;
94 mData.mPID = 0;
95 mData.mProcessID = 0;
96 mData.mRC = VINF_SUCCESS;
97 mData.mStatus = ProcessStatus_Undefined;
98
99 mData.mWaitCount = 0;
100 mData.mWaitEvent = NULL;
101
102 HRESULT hr = BaseFinalConstruct();
103 return hr;
104}
105
106void GuestProcess::FinalRelease(void)
107{
108 LogFlowThisFuncEnter();
109 uninit();
110 BaseFinalRelease();
111 LogFlowThisFuncLeave();
112}
113
114// public initializer/uninitializer for internal purposes only
115/////////////////////////////////////////////////////////////////////////////
116
117int GuestProcess::init(Console *aConsole, GuestSession *aSession, ULONG aProcessID, const GuestProcessStartupInfo &aProcInfo)
118{
119 LogFlowThisFunc(("aConsole=%p, aSession=%p, aProcessID=%RU32\n",
120 aConsole, aSession, aProcessID));
121
122 AssertPtrReturn(aSession, VERR_INVALID_POINTER);
123
124 /* Enclose the state transition NotReady->InInit->Ready. */
125 AutoInitSpan autoInitSpan(this);
126 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
127
128 mData.mConsole = aConsole;
129 mData.mParent = aSession;
130 mData.mProcessID = aProcessID;
131 mData.mProcess = aProcInfo;
132 /* Everything else will be set by the actual starting routine. */
133
134 /* Confirm a successful initialization when it's the case. */
135 autoInitSpan.setSucceeded();
136
137 return VINF_SUCCESS;
138}
139
140/**
141 * Uninitializes the instance.
142 * Called from FinalRelease().
143 */
144void GuestProcess::uninit(void)
145{
146 LogFlowThisFunc(("mCmd=%s, PID=%RU32\n",
147 mData.mProcess.mCommand.c_str(), mData.mPID));
148
149 /* Enclose the state transition Ready->InUninit->NotReady. */
150 AutoUninitSpan autoUninitSpan(this);
151 if (autoUninitSpan.uninitDone())
152 return;
153
154 int vrc = VINF_SUCCESS;
155
156#ifdef VBOX_WITH_GUEST_CONTROL
157 /*
158 * Cancel all callbacks + waiters.
159 * Note: Deleting them is the job of the caller!
160 */
161 for (GuestCtrlCallbacks::iterator itCallbacks = mData.mCallbacks.begin();
162 itCallbacks != mData.mCallbacks.end(); ++itCallbacks)
163 {
164 GuestCtrlCallback *pCallback = itCallbacks->second;
165 AssertPtr(pCallback);
166 int rc2 = pCallback->Cancel();
167 if (RT_SUCCESS(vrc))
168 vrc = rc2;
169 }
170 mData.mCallbacks.clear();
171
172 if (mData.mWaitEvent)
173 {
174 int rc2 = mData.mWaitEvent->Cancel();
175 if (RT_SUCCESS(vrc))
176 vrc = rc2;
177 }
178
179 mData.mStatus = ProcessStatus_Down; /** @todo Correct? */
180#endif
181
182 LogFlowFuncLeaveRC(vrc);
183}
184
185// implementation of public getters/setters for attributes
186/////////////////////////////////////////////////////////////////////////////
187
188STDMETHODIMP GuestProcess::COMGETTER(Arguments)(ComSafeArrayOut(BSTR, aArguments))
189{
190#ifndef VBOX_WITH_GUEST_CONTROL
191 ReturnComNotImplemented();
192#else
193 LogFlowThisFuncEnter();
194
195 CheckComArgOutSafeArrayPointerValid(aArguments);
196
197 AutoCaller autoCaller(this);
198 if (FAILED(autoCaller.rc())) return autoCaller.rc();
199
200 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
201
202 com::SafeArray<BSTR> collection(mData.mProcess.mArguments.size());
203 size_t s = 0;
204 for (ProcessArguments::const_iterator it = mData.mProcess.mArguments.begin();
205 it != mData.mProcess.mArguments.end();
206 it++, s++)
207 {
208 Bstr tmp = *it;
209 tmp.cloneTo(&collection[s]);
210 }
211
212 collection.detachTo(ComSafeArrayOutArg(aArguments));
213
214 return S_OK;
215#endif /* VBOX_WITH_GUEST_CONTROL */
216}
217
218STDMETHODIMP GuestProcess::COMGETTER(Environment)(ComSafeArrayOut(BSTR, aEnvironment))
219{
220#ifndef VBOX_WITH_GUEST_CONTROL
221 ReturnComNotImplemented();
222#else
223 LogFlowThisFuncEnter();
224
225 CheckComArgOutSafeArrayPointerValid(aEnvironment);
226
227 AutoCaller autoCaller(this);
228 if (FAILED(autoCaller.rc())) return autoCaller.rc();
229
230 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
231
232 com::SafeArray<BSTR> arguments(mData.mProcess.mEnvironment.Size());
233 for (size_t i = 0; i < arguments.size(); i++)
234 {
235 Bstr tmp = mData.mProcess.mEnvironment.Get(i);
236 tmp.cloneTo(&arguments[i]);
237 }
238 arguments.detachTo(ComSafeArrayOutArg(aEnvironment));
239
240 return S_OK;
241#endif /* VBOX_WITH_GUEST_CONTROL */
242}
243
244STDMETHODIMP GuestProcess::COMGETTER(ExecutablePath)(BSTR *aExecutablePath)
245{
246#ifndef VBOX_WITH_GUEST_CONTROL
247 ReturnComNotImplemented();
248#else
249 LogFlowThisFuncEnter();
250
251 CheckComArgOutPointerValid(aExecutablePath);
252
253 AutoCaller autoCaller(this);
254 if (FAILED(autoCaller.rc())) return autoCaller.rc();
255
256 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
257
258 mData.mProcess.mCommand.cloneTo(aExecutablePath);
259
260 return S_OK;
261#endif /* VBOX_WITH_GUEST_CONTROL */
262}
263
264STDMETHODIMP GuestProcess::COMGETTER(ExitCode)(LONG *aExitCode)
265{
266#ifndef VBOX_WITH_GUEST_CONTROL
267 ReturnComNotImplemented();
268#else
269 LogFlowThisFuncEnter();
270
271 CheckComArgOutPointerValid(aExitCode);
272
273 AutoCaller autoCaller(this);
274 if (FAILED(autoCaller.rc())) return autoCaller.rc();
275
276 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
277
278 *aExitCode = mData.mExitCode;
279
280 return S_OK;
281#endif /* VBOX_WITH_GUEST_CONTROL */
282}
283
284STDMETHODIMP GuestProcess::COMGETTER(Name)(BSTR *aName)
285{
286#ifndef VBOX_WITH_GUEST_CONTROL
287 ReturnComNotImplemented();
288#else
289 LogFlowThisFuncEnter();
290
291 CheckComArgOutPointerValid(aName);
292
293 AutoCaller autoCaller(this);
294 if (FAILED(autoCaller.rc())) return autoCaller.rc();
295
296 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
297
298 mData.mProcess.mName.cloneTo(aName);
299
300 return S_OK;
301#endif /* VBOX_WITH_GUEST_CONTROL */
302}
303
304STDMETHODIMP GuestProcess::COMGETTER(PID)(ULONG *aPID)
305{
306#ifndef VBOX_WITH_GUEST_CONTROL
307 ReturnComNotImplemented();
308#else
309 LogFlowThisFuncEnter();
310
311 CheckComArgOutPointerValid(aPID);
312
313 AutoCaller autoCaller(this);
314 if (FAILED(autoCaller.rc())) return autoCaller.rc();
315
316 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
317
318 *aPID = mData.mPID;
319
320 return S_OK;
321#endif /* VBOX_WITH_GUEST_CONTROL */
322}
323
324STDMETHODIMP GuestProcess::COMGETTER(Status)(ProcessStatus_T *aStatus)
325{
326#ifndef VBOX_WITH_GUEST_CONTROL
327 ReturnComNotImplemented();
328#else
329 LogFlowThisFuncEnter();
330
331 AutoCaller autoCaller(this);
332 if (FAILED(autoCaller.rc())) return autoCaller.rc();
333
334 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
335
336 *aStatus = mData.mStatus;
337
338 return S_OK;
339#endif /* VBOX_WITH_GUEST_CONTROL */
340}
341
342// private methods
343/////////////////////////////////////////////////////////////////////////////
344
345inline int GuestProcess::callbackAdd(GuestCtrlCallback *pCallback, uint32_t *puContextID)
346{
347 const ComObjPtr<GuestSession> pSession(mData.mParent);
348 Assert(!pSession.isNull());
349 ULONG uSessionID = 0;
350 HRESULT hr = pSession->COMGETTER(Id)(&uSessionID);
351 ComAssertComRC(hr);
352
353 /* Create a new context ID and assign it. */
354 int vrc = VERR_NOT_FOUND;
355
356 ULONG uCount = mData.mNextContextID++;
357 ULONG uNewContextID = 0;
358 ULONG uTries = 0;
359 for (;;)
360 {
361 if (uCount == VBOX_GUESTCTRL_MAX_CONTEXTS)
362 uCount = 0;
363
364 /* Create a new context ID ... */
365 uNewContextID = VBOX_GUESTCTRL_CONTEXTID_MAKE(uSessionID,
366 mData.mProcessID, uCount);
367
368 /* Is the context ID already used? Try next ID ... */
369 if (!callbackExists(uCount))
370 {
371 /* Callback with context ID was not found. This means
372 * we can use this context ID for our new callback we want
373 * to add below. */
374 vrc = VINF_SUCCESS;
375 break;
376 }
377
378 uCount++;
379 if (++uTries == UINT32_MAX)
380 break; /* Don't try too hard. */
381 }
382
383 if (RT_SUCCESS(vrc))
384 {
385 /* Add callback with new context ID to our callback map.
386 * Note: This is *not* uNewContextID (which also includes
387 * the session + process ID), just the context count
388 * will be used here. */
389 mData.mCallbacks[uCount] = pCallback;
390 Assert(mData.mCallbacks.size());
391
392 /* Report back new context ID. */
393 if (puContextID)
394 *puContextID = uNewContextID;
395
396 LogFlowThisFunc(("Added new callback (Session: %RU32, Process: %RU32, Count=%RU32) CID=%RU32\n",
397 uSessionID, mData.mProcessID, uCount, uNewContextID));
398 }
399
400 return vrc;
401}
402
403int GuestProcess::callbackDispatcher(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData)
404{
405#ifdef DEBUG
406 LogFlowThisFunc(("uPID=%RU32, uContextID=%RU32, uFunction=%RU32, pvData=%p, cbData=%RU32\n",
407 mData.mPID, uContextID, uFunction, pvData, cbData));
408#endif
409
410 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
411 AssertReturn(cbData, VERR_INVALID_PARAMETER);
412
413 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
414
415 int vrc;
416
417 /* Get the optional callback associated to this context ID.
418 * The callback may not be around anymore if just kept locally by the caller when
419 * doing the actual HGCM sending stuff. */
420 GuestCtrlCallback *pCallback = NULL;
421 GuestCtrlCallbacks::const_iterator it
422 = mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
423 if (it != mData.mCallbacks.end())
424 {
425 pCallback = it->second;
426 AssertPtr(pCallback);
427#ifdef DEBUG
428 LogFlowThisFunc(("pCallback=%p\n", pCallback));
429#endif
430 }
431
432 switch (uFunction)
433 {
434 case GUEST_DISCONNECTED:
435 {
436 PCALLBACKDATACLIENTDISCONNECTED pCallbackData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvData);
437 AssertPtr(pCallbackData);
438 AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbData, VERR_INVALID_PARAMETER);
439 AssertReturn(CALLBACKDATAMAGIC_CLIENT_DISCONNECTED == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER);
440
441 vrc = onGuestDisconnected(pCallback, pCallbackData); /* Affects all callbacks. */
442 break;
443 }
444
445 case GUEST_EXEC_SEND_STATUS:
446 {
447 PCALLBACKDATAEXECSTATUS pCallbackData = reinterpret_cast<PCALLBACKDATAEXECSTATUS>(pvData);
448 AssertPtr(pCallbackData);
449 AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbData, VERR_INVALID_PARAMETER);
450 AssertReturn(CALLBACKDATAMAGIC_EXEC_STATUS == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER);
451
452 vrc = onProcessStatusChange(pCallback, pCallbackData);
453 break;
454 }
455
456 case GUEST_EXEC_SEND_OUTPUT:
457 {
458 PCALLBACKDATAEXECOUT pCallbackData = reinterpret_cast<PCALLBACKDATAEXECOUT>(pvData);
459 AssertPtr(pCallbackData);
460 AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbData, VERR_INVALID_PARAMETER);
461 AssertReturn(CALLBACKDATAMAGIC_EXEC_OUT == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER);
462
463 vrc = onProcessOutput(pCallback, pCallbackData);
464 break;
465 }
466
467 case GUEST_EXEC_SEND_INPUT_STATUS:
468 {
469 PCALLBACKDATAEXECINSTATUS pCallbackData = reinterpret_cast<PCALLBACKDATAEXECINSTATUS>(pvData);
470 AssertPtr(pCallbackData);
471 AssertReturn(sizeof(CALLBACKDATAEXECINSTATUS) == cbData, VERR_INVALID_PARAMETER);
472 AssertReturn(CALLBACKDATAMAGIC_EXEC_IN_STATUS == pCallbackData->hdr.u32Magic, VERR_INVALID_PARAMETER);
473
474 vrc = onProcessInputStatus(pCallback, pCallbackData);
475 break;
476 }
477
478 default:
479 /* Silently ignore not implemented functions. */
480 vrc = VERR_NOT_IMPLEMENTED;
481 break;
482 }
483
484#ifdef DEBUG
485 LogFlowFuncLeaveRC(vrc);
486#endif
487 return vrc;
488}
489
490inline bool GuestProcess::callbackExists(uint32_t uContextID)
491{
492 GuestCtrlCallbacks::const_iterator it =
493 mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
494 return (it == mData.mCallbacks.end()) ? false : true;
495}
496
497inline int GuestProcess::callbackRemove(uint32_t uContextID)
498{
499 GuestCtrlCallbacks::iterator it =
500 mData.mCallbacks.find(VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID));
501 if (it != mData.mCallbacks.end())
502 {
503 delete it->second;
504 mData.mCallbacks.erase(it);
505
506 return VINF_SUCCESS;
507 }
508
509 return VERR_NOT_FOUND;
510}
511
512/**
513 * Checks if the current assigned PID matches another PID (from a callback).
514 *
515 * In protocol v1 we don't have the possibility to terminate/kill
516 * processes so it can happen that a formerly start process A
517 * (which has the context ID 0 (session=0, process=0, count=0) will
518 * send a delayed message to the host if this process has already
519 * been discarded there and the same context ID was reused by
520 * a process B. Process B in turn then has a different guest PID.
521 *
522 * @return IPRT status code.
523 * @param uPID PID to check.
524 */
525inline int GuestProcess::checkPID(uint32_t uPID)
526{
527 /* Was there a PID assigned yet? */
528 if (mData.mPID)
529 {
530 /*
531
532 */
533 if (mData.mParent->getProtocolVersion() < 2)
534 {
535 /* Simply ignore the stale requests. */
536 return (mData.mPID == uPID)
537 ? VINF_SUCCESS : VERR_NOT_FOUND;
538 }
539 /* This should never happen! */
540 AssertReleaseMsg(mData.mPID == uPID, ("Unterminated guest process (PID %RU32) sent data to a newly started process (PID %RU32)\n",
541 uPID, mData.mPID));
542 }
543
544 return VINF_SUCCESS;
545}
546
547inline bool GuestProcess::isAlive(void)
548{
549 return ( mData.mStatus == ProcessStatus_Started
550 || mData.mStatus == ProcessStatus_Paused
551 || mData.mStatus == ProcessStatus_Terminating);
552}
553
554bool GuestProcess::isReady(void)
555{
556 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
557
558 if (mData.mStatus == ProcessStatus_Started)
559 {
560 Assert(mData.mPID); /* PID must not be 0. */
561 return true;
562 }
563
564 return false;
565}
566
567int GuestProcess::onGuestDisconnected(GuestCtrlCallback *pCallback, PCALLBACKDATACLIENTDISCONNECTED pData)
568{
569 /* pCallback is optional. */
570 AssertPtrReturn(pData, VERR_INVALID_POINTER);
571
572 LogFlowThisFunc(("uPID=%RU32, pCallback=%p, pData=%p\n", mData.mPID, pCallback, pData));
573
574 mData.mStatus = ProcessStatus_Down;
575
576 /* First, signal callback in every case. */
577 if (pCallback)
578 pCallback->Signal();
579
580 /* Do we need to report a termination? */
581 ProcessWaitResult_T waitRes;
582 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
583 waitRes = ProcessWaitResult_Status; /* No, just report a status. */
584 else
585 waitRes = ProcessWaitResult_Terminate;
586
587 /* Signal in any case. */
588 int vrc = signalWaiters(waitRes);
589 AssertRC(vrc);
590
591 LogFlowFuncLeaveRC(vrc);
592 return vrc;
593}
594
595int GuestProcess::onProcessInputStatus(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECINSTATUS pData)
596{
597 /* pCallback is optional. */
598 AssertPtrReturn(pData, VERR_INVALID_POINTER);
599
600 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, cbProcessed=%RU32, pCallback=%p, pData=%p\n",
601 mData.mPID, pData->u32Status, pData->u32Flags, pData->cbProcessed, pCallback, pData));
602
603 int vrc = checkPID(pData->u32PID);
604 if (RT_FAILURE(vrc))
605 return vrc;
606
607 /* First, signal callback in every case (if available). */
608 if (pCallback)
609 {
610 vrc = pCallback->SetData(pData, sizeof(CALLBACKDATAEXECINSTATUS));
611
612 int rc2 = pCallback->Signal();
613 if (RT_SUCCESS(vrc))
614 vrc = rc2;
615 }
616
617 /* Then do the WaitFor signalling stuff. */
618 uint32_t uWaitFlags = mData.mWaitEvent
619 ? mData.mWaitEvent->GetWaitFlags() : 0;
620 if (uWaitFlags & ProcessWaitForFlag_StdIn)
621 {
622 int rc2 = signalWaiters(ProcessWaitResult_StdIn);
623 if (RT_SUCCESS(vrc))
624 vrc = rc2;
625 }
626
627 LogFlowFuncLeaveRC(vrc);
628 return vrc;
629}
630
631int GuestProcess::onProcessNotifyIO(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData)
632{
633 /* pCallback is optional. */
634 AssertPtrReturn(pData, VERR_INVALID_POINTER);
635
636 return 0;
637}
638
639int GuestProcess::onProcessStatusChange(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECSTATUS pData)
640{
641 /* pCallback is optional. */
642 AssertPtrReturn(pData, VERR_INVALID_POINTER);
643
644 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32, pCallback=%p, pData=%p\n",
645 pData->u32PID, pData->u32Status, pData->u32Flags, pCallback, pData));
646
647 int vrc = checkPID(pData->u32PID);
648 if (RT_FAILURE(vrc))
649 return vrc;
650
651 BOOL fSignal = FALSE;
652 ProcessWaitResult_T waitRes;
653 uint32_t uWaitFlags = mData.mWaitEvent
654 ? mData.mWaitEvent->GetWaitFlags() : 0;
655 switch (pData->u32Status)
656 {
657 case PROC_STS_STARTED:
658 {
659 fSignal = (uWaitFlags & ProcessWaitForFlag_Start);
660 /* If the caller only wants to wait until the process has been started,
661 * notify in any case. */
662 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
663 fSignal = true;
664 waitRes = ProcessWaitResult_Start;
665
666 mData.mStatus = ProcessStatus_Started;
667 mData.mPID = pData->u32PID;
668 break;
669 }
670
671 case PROC_STS_TEN:
672 {
673 fSignal = TRUE; /* Signal in any case. */
674 waitRes = ProcessWaitResult_Terminate;
675
676 mData.mStatus = ProcessStatus_TerminatedNormally;
677 mData.mExitCode = pData->u32Flags; /* Contains the exit code. */
678 break;
679 }
680
681 case PROC_STS_TES:
682 {
683 fSignal = TRUE; /* Signal in any case. */
684 waitRes = ProcessWaitResult_Terminate;
685
686 mData.mStatus = ProcessStatus_TerminatedSignal;
687 mData.mExitCode = pData->u32Flags; /* Contains the signal. */
688 break;
689 }
690
691 case PROC_STS_TEA:
692 {
693 fSignal = TRUE; /* Signal in any case. */
694 waitRes = ProcessWaitResult_Terminate;
695
696 mData.mStatus = ProcessStatus_TerminatedAbnormally;
697 break;
698 }
699
700 case PROC_STS_TOK:
701 {
702 fSignal = TRUE; /* Signal in any case. */
703 waitRes = ProcessWaitResult_Timeout;
704
705 mData.mStatus = ProcessStatus_TimedOutKilled;
706 break;
707 }
708
709 case PROC_STS_TOA:
710 {
711 fSignal = TRUE; /* Signal in any case. */
712 waitRes = ProcessWaitResult_Timeout;
713
714 mData.mStatus = ProcessStatus_TimedOutAbnormally;
715 break;
716 }
717
718 case PROC_STS_DWN:
719 {
720 fSignal = TRUE; /* Signal in any case. */
721 /* Do we need to report termination? */
722 if (mData.mProcess.mFlags & ProcessCreateFlag_IgnoreOrphanedProcesses)
723 waitRes = ProcessWaitResult_Status;
724 else
725 waitRes = ProcessWaitResult_Terminate;
726
727 mData.mStatus = ProcessStatus_Down;
728 break;
729 }
730
731 case PROC_STS_ERROR:
732 {
733 fSignal = TRUE; /* Signal in any case. */
734 waitRes = ProcessWaitResult_Error;
735
736 mData.mStatus = ProcessStatus_Error;
737
738 Utf8Str strError = Utf8StrFmt(tr("Guest process \"%s\" could not be started: "), mData.mProcess.mCommand.c_str());
739
740 /* Note: It's not required that the process has been started before. */
741 if (mData.mPID)
742 {
743 strError += Utf8StrFmt(tr("Error vrc=%Rrc occured (PID %RU32)"), vrc, mData.mPID);
744 }
745 else
746 {
747 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
748 switch (pData->u32Flags) /* pData->u32Flags contains the IPRT error code from guest side. */
749 {
750 case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
751 strError += Utf8StrFmt(tr("The specified file was not found on guest"));
752 break;
753
754 case VERR_PATH_NOT_FOUND:
755 strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
756 break;
757
758 case VERR_BAD_EXE_FORMAT:
759 strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
760 break;
761
762 case VERR_AUTHENTICATION_FAILURE:
763 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
764 break;
765
766 case VERR_INVALID_NAME:
767 strError += Utf8StrFmt(tr("The specified file is an invalid name"));
768 break;
769
770 case VERR_TIMEOUT:
771 strError += Utf8StrFmt(tr("The guest did not respond within time"));
772 break;
773
774 case VERR_CANCELLED:
775 strError += Utf8StrFmt(tr("The execution operation was canceled"));
776 break;
777
778 case VERR_PERMISSION_DENIED:
779 strError += Utf8StrFmt(tr("Invalid user/password credentials"));
780 break;
781
782 case VERR_MAX_PROCS_REACHED:
783 strError += Utf8StrFmt(tr("Maximum number of parallel guest processes has been reached"));
784 break;
785
786 default:
787 strError += Utf8StrFmt(tr("Reported error %Rrc"), pData->u32Flags);
788 break;
789 }
790 }
791
792 vrc = setErrorInternal(pData->u32Flags, strError);
793 AssertRC(vrc);
794 break;
795 }
796
797 case PROC_STS_UNDEFINED:
798 default:
799 {
800 /* Silently skip this request. */
801 fSignal = TRUE; /* Signal in any case. */
802 waitRes = ProcessWaitResult_Status;
803
804 mData.mStatus = ProcessStatus_Undefined;
805 break;
806 }
807 }
808
809 LogFlowThisFunc(("Got vrc=%Rrc, waitResult=%d\n", vrc, waitRes));
810
811 /*
812 * Now do the signalling stuff.
813 */
814 if (pCallback)
815 vrc = pCallback->Signal();
816
817 if (fSignal)
818 {
819 int rc2 = signalWaiters(waitRes);
820 if (RT_SUCCESS(vrc))
821 vrc = rc2;
822 }
823
824 LogFlowFuncLeaveRC(vrc);
825 return vrc;
826}
827
828int GuestProcess::onProcessOutput(GuestCtrlCallback *pCallback, PCALLBACKDATAEXECOUT pData)
829{
830 /* pCallback is optional. */
831 AssertPtrReturn(pData, VERR_INVALID_POINTER);
832
833 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, pCallback=%p, pData=%p\n",
834 mData.mPID, pData->u32HandleId, pData->u32Flags, pData->pvData, pData->cbData, pCallback, pData));
835
836 int vrc = checkPID(pData->u32PID);
837 if (RT_FAILURE(vrc))
838 return vrc;
839
840 /* First, signal callback in every case (if available). */
841 if (pCallback)
842 {
843 vrc = pCallback->SetData(pData, sizeof(CALLBACKDATAEXECOUT));
844
845 int rc2 = pCallback->Signal();
846 if (RT_SUCCESS(vrc))
847 vrc = rc2;
848 }
849
850 /* Then do the WaitFor signalling stuff. */
851 BOOL fSignal = FALSE;
852 uint32_t uWaitFlags = mData.mWaitEvent
853 ? mData.mWaitEvent->GetWaitFlags() : 0;
854
855 if ( (uWaitFlags & ProcessWaitForFlag_StdOut)
856 || (uWaitFlags & ProcessWaitForFlag_StdErr))
857 {
858 fSignal = TRUE;
859 }
860 else if ( (uWaitFlags & ProcessWaitForFlag_StdOut)
861 && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT))
862 {
863 fSignal = TRUE;
864 }
865 else if ( (uWaitFlags & ProcessWaitForFlag_StdErr)
866 && (pData->u32HandleId == OUTPUT_HANDLE_ID_STDERR))
867 {
868 fSignal = TRUE;
869 }
870
871 if (fSignal)
872 {
873 int rc2;
874 if (pData->u32HandleId == OUTPUT_HANDLE_ID_STDOUT)
875 rc2 = signalWaiters(ProcessWaitResult_StdOut);
876 else
877 rc2 = signalWaiters(ProcessWaitResult_StdErr);
878 if (RT_SUCCESS(vrc))
879 vrc = rc2;
880 }
881
882 LogFlowFuncLeaveRC(vrc);
883 return vrc;
884}
885
886int GuestProcess::readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
887 void *pvData, size_t cbData, size_t *pcbRead)
888{
889 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32\n",
890 mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData));
891 AssertReturn(uSize, VERR_INVALID_PARAMETER);
892 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
893 AssertReturn(cbData >= uSize, VERR_INVALID_PARAMETER);
894 /* pcbRead is optional. */
895
896 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
897
898 if (mData.mStatus != ProcessStatus_Started)
899 {
900 if (pcbRead)
901 *pcbRead = 0;
902 return VINF_SUCCESS; /* Nothing to read anymore. */
903 }
904
905 uint32_t uContextID = 0;
906 GuestCtrlCallback *pCallbackRead = new GuestCtrlCallback();
907 if (!pCallbackRead)
908 return VERR_NO_MEMORY;
909
910 /* Create callback and add it to the map. */
911 int vrc = pCallbackRead->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT);
912 if (RT_SUCCESS(vrc))
913 vrc = callbackAdd(pCallbackRead, &uContextID);
914
915 alock.release(); /* Drop the write lock again. */
916
917 if (RT_SUCCESS(vrc))
918 {
919 VBOXHGCMSVCPARM paParms[5];
920
921 int i = 0;
922 paParms[i++].setUInt32(uContextID);
923 paParms[i++].setUInt32(mData.mPID);
924 paParms[i++].setUInt32(uHandle);
925 paParms[i++].setUInt32(0 /* Flags, none set yet. */);
926
927 vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms);
928 }
929
930 if (RT_SUCCESS(vrc))
931 {
932 /*
933 * Let's wait for the process being started.
934 * Note: Be sure not keeping a AutoRead/WriteLock here.
935 */
936 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
937 vrc = pCallbackRead->Wait(uTimeoutMS);
938 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
939 {
940 vrc = pCallbackRead->GetResultCode();
941 LogFlowThisFunc(("Callback returned vrc=%Rrc, cbData=%RU32\n", vrc, pCallbackRead->GetDataSize()));
942
943 if (RT_SUCCESS(vrc))
944 {
945 Assert(pCallbackRead->GetDataSize() == sizeof(CALLBACKDATAEXECOUT));
946 PCALLBACKDATAEXECOUT pData = (PCALLBACKDATAEXECOUT)pCallbackRead->GetDataRaw();
947 AssertPtr(pData);
948
949 size_t cbRead = pData->cbData;
950 if (cbRead)
951 {
952 Assert(cbData >= cbRead);
953 memcpy(pvData, pData->pvData, cbRead);
954 }
955
956 LogFlowThisFunc(("cbRead=%RU32\n", cbRead));
957
958 if (pcbRead)
959 *pcbRead = cbRead;
960 }
961 }
962 else
963 vrc = VERR_TIMEOUT;
964 }
965
966 alock.acquire();
967
968 AssertPtr(pCallbackRead);
969 int rc2 = callbackRemove(uContextID);
970 if (RT_SUCCESS(vrc))
971 vrc = rc2;
972
973 LogFlowFuncLeaveRC(vrc);
974 return vrc;
975}
976
977int GuestProcess::sendCommand(uint32_t uFunction,
978 uint32_t uParms, PVBOXHGCMSVCPARM paParms)
979{
980 LogFlowThisFuncEnter();
981
982 ComObjPtr<Console> pConsole = mData.mConsole;
983 Assert(!pConsole.isNull());
984
985 /* Forward the information to the VMM device. */
986 VMMDev *pVMMDev = pConsole->getVMMDev();
987 AssertPtr(pVMMDev);
988
989 LogFlowThisFunc(("uFunction=%RU32, uParms=%RU32\n", uFunction, uParms));
990 int vrc = pVMMDev->hgcmHostCall("VBoxGuestControlSvc", uFunction, uParms, paParms);
991 if (RT_FAILURE(vrc))
992 {
993 int rc2;
994 if (vrc == VERR_INVALID_VM_HANDLE)
995 rc2 = setErrorInternal(vrc, tr("VMM device is not available (is the VM running?)"));
996 else if (vrc == VERR_NOT_FOUND)
997 rc2 = setErrorInternal(vrc, tr("The guest execution service is not ready (yet)"));
998 else if (vrc == VERR_HGCM_SERVICE_NOT_FOUND)
999 rc2 = setErrorInternal(vrc, tr("The guest execution service is not available"));
1000 else
1001 rc2 = setErrorInternal(vrc, Utf8StrFmt(tr("The HGCM call failed with error %Rrc"), vrc));
1002 AssertRC(rc2);
1003 }
1004
1005 LogFlowFuncLeaveRC(vrc);
1006 return vrc;
1007}
1008
1009/* Does not do locking; caller is responsible for that! */
1010int GuestProcess::setErrorInternal(int vrc, const Utf8Str &strMessage)
1011{
1012 LogFlowThisFunc(("vrc=%Rrc, strMsg=%s\n", vrc, strMessage.c_str()));
1013
1014 Assert(RT_FAILURE(vrc));
1015 Assert(!strMessage.isEmpty());
1016
1017#ifdef DEBUG
1018 /* Do not allow overwriting an already set error. If this happens
1019 * this means we forgot some error checking/locking somewhere. */
1020 Assert(RT_SUCCESS(mData.mRC));
1021 Assert(mData.mErrorMsg.isEmpty());
1022#endif
1023
1024 mData.mStatus = ProcessStatus_Error;
1025 mData.mRC = vrc;
1026 mData.mErrorMsg = strMessage;
1027
1028 int rc2 = signalWaiters(ProcessWaitResult_Error);
1029 LogFlowFuncLeaveRC(rc2);
1030 return rc2;
1031}
1032
1033HRESULT GuestProcess::setErrorExternal(void)
1034{
1035 return RT_SUCCESS(mData.mRC)
1036 ? S_OK : setError(VBOX_E_IPRT_ERROR, "%s", mData.mErrorMsg.c_str());
1037}
1038
1039int GuestProcess::signalWaiters(ProcessWaitResult_T enmWaitResult)
1040{
1041 LogFlowThisFunc(("enmWaitResult=%d, mWaitCount=%RU32, mWaitEvent=%p\n",
1042 enmWaitResult, mData.mWaitCount, mData.mWaitEvent));
1043
1044 /* Note: No write locking here -- already done in the caller. */
1045
1046 int vrc = VINF_SUCCESS;
1047 if (mData.mWaitEvent)
1048 vrc = mData.mWaitEvent->Signal(enmWaitResult);
1049 LogFlowFuncLeaveRC(vrc);
1050 return vrc;
1051}
1052
1053int GuestProcess::startProcess(void)
1054{
1055 LogFlowThisFunc(("aCmd=%s, aTimeoutMS=%RU32, fFlags=%x\n",
1056 mData.mProcess.mCommand.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags));
1057
1058 /* Wait until the caller function (if kicked off by a thread)
1059 * has returned and continue operation. */
1060 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1061
1062 int vrc;
1063 uint32_t uContextID = 0;
1064 GuestCtrlCallback *pCallbackStart = new GuestCtrlCallback();
1065 if (!pCallbackStart)
1066 return VERR_NO_MEMORY;
1067
1068 mData.mStatus = ProcessStatus_Starting;
1069
1070 /* Create callback and add it to the map. */
1071 vrc = pCallbackStart->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_START);
1072 if (RT_SUCCESS(vrc))
1073 vrc = callbackAdd(pCallbackStart, &uContextID);
1074
1075 if (RT_SUCCESS(vrc))
1076 {
1077 GuestSession *pSession = mData.mParent;
1078 AssertPtr(pSession);
1079
1080 const GuestCredentials &sessionCreds = pSession->getCredentials();
1081
1082 /* Prepare arguments. */
1083 char *pszArgs = NULL;
1084 size_t cArgs = mData.mProcess.mArguments.size();
1085 if (cArgs >= UINT32_MAX)
1086 vrc = VERR_BUFFER_OVERFLOW;
1087
1088 if ( RT_SUCCESS(vrc)
1089 && cArgs)
1090 {
1091 char **papszArgv = (char**)RTMemAlloc((cArgs + 1) * sizeof(char*));
1092 AssertReturn(papszArgv, VERR_NO_MEMORY);
1093
1094 for (size_t i = 0; i < cArgs && RT_SUCCESS(vrc); i++)
1095 {
1096 const char *pszCurArg = mData.mProcess.mArguments[i].c_str();
1097 AssertPtr(pszCurArg);
1098 vrc = RTStrDupEx(&papszArgv[i], pszCurArg);
1099 }
1100 papszArgv[cArgs] = NULL;
1101
1102 if (RT_SUCCESS(vrc))
1103 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
1104
1105 if (papszArgv)
1106 {
1107 size_t i = 0;
1108 while (papszArgv[i])
1109 RTStrFree(papszArgv[i++]);
1110 RTMemFree(papszArgv);
1111 }
1112 }
1113
1114 /* Calculate arguments size (in bytes). */
1115 size_t cbArgs = 0;
1116 if (RT_SUCCESS(vrc))
1117 cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
1118
1119 /* Prepare environment. */
1120 void *pvEnv = NULL;
1121 size_t cbEnv = 0;
1122 if (RT_SUCCESS(vrc))
1123 vrc = mData.mProcess.mEnvironment.BuildEnvironmentBlock(&pvEnv, &cbEnv, NULL /* cEnv */);
1124
1125 if (RT_SUCCESS(vrc))
1126 {
1127 /* Prepare HGCM call. */
1128 VBOXHGCMSVCPARM paParms[15];
1129 int i = 0;
1130 paParms[i++].setUInt32(uContextID);
1131 paParms[i++].setPointer((void*)mData.mProcess.mCommand.c_str(),
1132 (ULONG)mData.mProcess.mCommand.length() + 1);
1133 paParms[i++].setUInt32(mData.mProcess.mFlags);
1134 paParms[i++].setUInt32(mData.mProcess.mArguments.size());
1135 paParms[i++].setPointer((void*)pszArgs, cbArgs);
1136 paParms[i++].setUInt32(mData.mProcess.mEnvironment.Size());
1137 paParms[i++].setUInt32(cbEnv);
1138 paParms[i++].setPointer((void*)pvEnv, cbEnv);
1139 paParms[i++].setPointer((void*)sessionCreds.mUser.c_str(), (ULONG)sessionCreds.mUser.length() + 1);
1140 paParms[i++].setPointer((void*)sessionCreds.mPassword.c_str(), (ULONG)sessionCreds.mPassword.length() + 1);
1141 /** @todo New command needs the domain as well! */
1142
1143 /*
1144 * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
1145 * until the process was started - the process itself then gets an infinite timeout for execution.
1146 * This is handy when we want to start a process inside a worker thread within a certain timeout
1147 * but let the started process perform lengthly operations then.
1148 */
1149 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1150 paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
1151 else
1152 paParms[i++].setUInt32(mData.mProcess.mTimeoutMS);
1153
1154 /* Note: Don't hold the write lock in here, because setErrorInternal */
1155 vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
1156 }
1157
1158 GuestEnvironment::FreeEnvironmentBlock(pvEnv);
1159 if (pszArgs)
1160 RTStrFree(pszArgs);
1161
1162 uint32_t uTimeoutMS = mData.mProcess.mTimeoutMS;
1163
1164 /* Drop the write lock again before waiting. */
1165 alock.release();
1166
1167 if (RT_SUCCESS(vrc))
1168 {
1169 /*
1170 * Let's wait for the process being started.
1171 * Note: Be sure not keeping a AutoRead/WriteLock here.
1172 */
1173 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
1174 vrc = pCallbackStart->Wait(uTimeoutMS);
1175 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
1176 {
1177 vrc = pCallbackStart->GetResultCode();
1178 LogFlowThisFunc(("Callback returned vrc=%Rrc\n", vrc));
1179 }
1180 else
1181 vrc = VERR_TIMEOUT;
1182 }
1183
1184 AutoWriteLock awlock(this COMMA_LOCKVAL_SRC_POS);
1185
1186 AssertPtr(pCallbackStart);
1187 int rc2 = callbackRemove(uContextID);
1188 if (RT_SUCCESS(vrc))
1189 vrc = rc2;
1190 }
1191
1192 LogFlowFuncLeaveRC(vrc);
1193 return vrc;
1194}
1195
1196int GuestProcess::startProcessAsync(void)
1197{
1198 LogFlowThisFuncEnter();
1199
1200 int vrc;
1201
1202 try
1203 {
1204 /* Asynchronously start the process on the guest by kicking off a
1205 * worker thread. */
1206 std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
1207 AssertReturn(pTask->isOk(), pTask->rc());
1208
1209 vrc = RTThreadCreate(NULL, GuestProcess::startProcessThread,
1210 (void *)pTask.get(), 0,
1211 RTTHREADTYPE_MAIN_WORKER, 0,
1212 "gctlPrcStart");
1213 if (RT_SUCCESS(vrc))
1214 {
1215 /* pTask is now owned by startProcessThread(), so release it. */
1216 pTask.release();
1217 }
1218 }
1219 catch(std::bad_alloc &)
1220 {
1221 vrc = VERR_NO_MEMORY;
1222 }
1223
1224 LogFlowFuncLeaveRC(vrc);
1225 return vrc;
1226}
1227
1228/* static */
1229DECLCALLBACK(int) GuestProcess::startProcessThread(RTTHREAD Thread, void *pvUser)
1230{
1231 LogFlowFunc(("pvUser=%p\n", pvUser));
1232
1233 std::auto_ptr<GuestProcessStartTask> pTask(static_cast<GuestProcessStartTask*>(pvUser));
1234 AssertPtr(pTask.get());
1235
1236 const ComObjPtr<GuestProcess> pProcess(pTask->Process());
1237 Assert(!pProcess.isNull());
1238
1239 AutoCaller autoCaller(pProcess);
1240 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1241
1242 int vrc = pProcess->startProcess();
1243 if (RT_FAILURE(vrc))
1244 {
1245 /** @todo What now? */
1246 }
1247
1248 LogFlowFuncLeaveRC(vrc);
1249 return vrc;
1250}
1251
1252int GuestProcess::terminateProcess(void)
1253{
1254 LogFlowThisFuncEnter();
1255
1256 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1257
1258 if (mData.mParent->getProtocolVersion() < 2)
1259 return VERR_NOT_SUPPORTED;
1260
1261 LogFlowThisFuncLeave();
1262 return VERR_NOT_IMPLEMENTED;
1263}
1264
1265int GuestProcess::waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS, GuestProcessWaitResult &waitRes)
1266{
1267 LogFlowThisFuncEnter();
1268
1269 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
1270
1271 LogFlowThisFunc(("fWaitFlags=%x, uTimeoutMS=%RU32, mStatus=%RU32, mWaitCount=%RU32, mWaitEvent=%p\n",
1272 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mWaitCount, mData.mWaitEvent));
1273
1274 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1275
1276 ProcessStatus_T curStatus = mData.mStatus;
1277
1278 /* Did some error occur before? Then skip waiting and return. */
1279 if (curStatus == ProcessStatus_Error)
1280 {
1281 waitRes.mResult = ProcessWaitResult_Error;
1282 return VINF_SUCCESS;
1283 }
1284
1285 waitRes.mResult = ProcessWaitResult_None;
1286 waitRes.mRC = VINF_SUCCESS;
1287
1288 if ( (fWaitFlags & ProcessWaitForFlag_Terminate)
1289 || (fWaitFlags & ProcessWaitForFlag_StdIn)
1290 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1291 || (fWaitFlags & ProcessWaitForFlag_StdErr))
1292 {
1293 switch (mData.mStatus)
1294 {
1295 case ProcessStatus_TerminatedNormally:
1296 case ProcessStatus_TerminatedSignal:
1297 case ProcessStatus_TerminatedAbnormally:
1298 case ProcessStatus_Down:
1299 waitRes.mResult = ProcessWaitResult_Terminate;
1300 waitRes.mRC = mData.mRC;
1301 break;
1302
1303 case ProcessStatus_TimedOutKilled:
1304 case ProcessStatus_TimedOutAbnormally:
1305 waitRes.mResult = ProcessWaitResult_Timeout;
1306 waitRes.mRC = mData.mRC;
1307 break;
1308
1309 case ProcessStatus_Error:
1310 waitRes.mResult = ProcessWaitResult_Error;
1311 waitRes.mRC = mData.mRC;
1312 break;
1313
1314 case ProcessStatus_Started:
1315 {
1316 /* Filter out waits which are *not* supported using
1317 * older guest control Guest Additions. */
1318 if (mData.mParent->getProtocolVersion() < 2)
1319 {
1320 /* We don't support waiting for stdin, out + err,
1321 * just skip waiting then. */
1322 if ( (fWaitFlags & ProcessWaitForFlag_StdIn)
1323 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1324 || (fWaitFlags & ProcessWaitForFlag_StdErr))
1325 {
1326 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
1327 waitRes.mResult = ProcessWaitResult_WaitFlagNotSupported;
1328 }
1329 }
1330
1331 /*
1332 * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the
1333 * caller is not interested in getting further process statuses -- so just don't notify
1334 * anything here anymore and return.
1335 */
1336 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1337 waitRes.mResult = ProcessWaitResult_Start;
1338 break;
1339 }
1340
1341 case ProcessStatus_Undefined:
1342 case ProcessStatus_Starting:
1343 /* Do the waiting below. */
1344 break;
1345
1346 default:
1347 AssertMsgFailed(("Unhandled process status %ld\n", mData.mStatus));
1348 return VERR_NOT_IMPLEMENTED;
1349 }
1350 }
1351 else if (fWaitFlags & ProcessWaitForFlag_Start)
1352 {
1353 switch (mData.mStatus)
1354 {
1355 case ProcessStatus_Started:
1356 case ProcessStatus_Paused:
1357 case ProcessStatus_Terminating:
1358 case ProcessStatus_TerminatedNormally:
1359 case ProcessStatus_TerminatedSignal:
1360 case ProcessStatus_TerminatedAbnormally:
1361 case ProcessStatus_Down:
1362 waitRes.mResult = ProcessWaitResult_Start;
1363 break;
1364
1365 case ProcessStatus_Error:
1366 waitRes.mResult = ProcessWaitResult_Error;
1367 waitRes.mRC = mData.mRC;
1368 break;
1369
1370 case ProcessStatus_TimedOutKilled:
1371 case ProcessStatus_TimedOutAbnormally:
1372 waitRes.mResult = ProcessWaitResult_Timeout;
1373 waitRes.mRC = mData.mRC;
1374 break;
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
1387 LogFlowThisFunc(("waitResult=%ld, waitRC=%Rrc\n", waitRes.mResult, waitRes.mRC));
1388
1389 /* No waiting needed? Return immediately. */
1390 if (waitRes.mResult != ProcessWaitResult_None)
1391 return VINF_SUCCESS;
1392
1393 if (mData.mWaitCount > 0)
1394 return VERR_ALREADY_EXISTS;
1395 mData.mWaitCount++;
1396
1397 Assert(mData.mWaitEvent == NULL);
1398 mData.mWaitEvent = new GuestProcessEvent(fWaitFlags);
1399 AssertPtrReturn(mData.mWaitEvent, VERR_NO_MEMORY);
1400
1401 alock.release(); /* Release lock before waiting. */
1402
1403 int vrc = mData.mWaitEvent->Wait(uTimeoutMS);
1404 if (RT_SUCCESS(vrc))
1405 {
1406 waitRes = mData.mWaitEvent->GetResult();
1407 }
1408 else if (vrc == VERR_TIMEOUT)
1409 {
1410 waitRes.mRC = VINF_SUCCESS;
1411 waitRes.mResult = ProcessWaitResult_Timeout;
1412
1413 vrc = VINF_SUCCESS;
1414 }
1415
1416 alock.acquire(); /* Get the lock again. */
1417
1418 /* Note: The caller always is responsible of deleting the
1419 * stuff it created before. See close() for more information. */
1420 delete mData.mWaitEvent;
1421 mData.mWaitEvent = NULL;
1422
1423 mData.mWaitCount--;
1424
1425 LogFlowFuncLeaveRC(vrc);
1426 return vrc;
1427}
1428
1429int GuestProcess::waitForStart(uint32_t uTimeoutMS)
1430{
1431 LogFlowThisFunc(("uTimeoutMS=%RU32\n", uTimeoutMS));
1432
1433 int vrc = VINF_SUCCESS;
1434
1435 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1436 if (mData.mStatus != ProcessStatus_Started)
1437 {
1438 alock.release();
1439
1440 GuestProcessWaitResult waitRes;
1441 vrc = waitFor(ProcessWaitForFlag_Start, uTimeoutMS, waitRes);
1442 if ( RT_FAILURE(vrc)
1443 || waitRes.mResult == ProcessWaitResult_Start)
1444 {
1445 if (RT_SUCCESS(vrc))
1446 vrc = waitRes.mRC;
1447 }
1448 /** @todo More error handling needed. */
1449 }
1450
1451 LogFlowFuncLeaveRC(vrc);
1452 return vrc;
1453}
1454
1455int GuestProcess::writeData(uint32_t uHandle, uint32_t uFlags,
1456 void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten)
1457{
1458 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p\n",
1459 mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten));
1460 /* All is optional. There can be 0 byte writes. */
1461
1462 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1463
1464 if (mData.mStatus != ProcessStatus_Started)
1465 return VINF_SUCCESS; /* Not available for writing (anymore). */
1466
1467 uint32_t uContextID = 0;
1468 GuestCtrlCallback *pCallbackWrite = new GuestCtrlCallback();
1469 if (!pCallbackWrite)
1470 return VERR_NO_MEMORY;
1471
1472 /* Create callback and add it to the map. */
1473 int vrc = pCallbackWrite->Init(VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS);
1474 if (RT_SUCCESS(vrc))
1475 vrc = callbackAdd(pCallbackWrite, &uContextID);
1476
1477 alock.release(); /* Drop the write lock again. */
1478
1479 if (RT_SUCCESS(vrc))
1480 {
1481 VBOXHGCMSVCPARM paParms[5];
1482
1483 int i = 0;
1484 paParms[i++].setUInt32(uContextID);
1485 paParms[i++].setUInt32(mData.mPID);
1486 paParms[i++].setUInt32(uFlags);
1487 paParms[i++].setPointer(pvData, cbData);
1488 paParms[i++].setUInt32(cbData);
1489
1490 vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
1491 }
1492
1493 if (RT_SUCCESS(vrc))
1494 {
1495 /*
1496 * Let's wait for the process being started.
1497 * Note: Be sure not keeping a AutoRead/WriteLock here.
1498 */
1499 LogFlowThisFunc(("Waiting for callback (%RU32ms) ...\n", uTimeoutMS));
1500 vrc = pCallbackWrite->Wait(uTimeoutMS);
1501 if (RT_SUCCESS(vrc)) /* Wait was successful, check for supplied information. */
1502 {
1503 vrc = pCallbackWrite->GetResultCode();
1504 LogFlowThisFunc(("Callback returned vrc=%Rrc, cbData=%RU32\n", vrc, pCallbackWrite->GetDataSize()));
1505
1506 if (RT_SUCCESS(vrc))
1507 {
1508 Assert(pCallbackWrite->GetDataSize() == sizeof(CALLBACKDATAEXECINSTATUS));
1509 PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)pCallbackWrite->GetDataRaw();
1510 AssertPtr(pData);
1511
1512 uint32_t cbWritten = 0;
1513 switch (pData->u32Status)
1514 {
1515 case INPUT_STS_WRITTEN:
1516 cbWritten = pData->cbProcessed;
1517 break;
1518
1519 case INPUT_STS_ERROR:
1520 vrc = pData->u32Flags; /** @todo Fix int vs. uint32_t! */
1521 break;
1522
1523 case INPUT_STS_TERMINATED:
1524 vrc = VERR_CANCELLED;
1525 break;
1526
1527 case INPUT_STS_OVERFLOW:
1528 vrc = VERR_BUFFER_OVERFLOW;
1529 break;
1530
1531 default:
1532 /* Silently skip unknown errors. */
1533 break;
1534 }
1535
1536 LogFlowThisFunc(("cbWritten=%RU32\n", cbWritten));
1537
1538 if (puWritten)
1539 *puWritten = cbWritten;
1540 }
1541 }
1542 else
1543 vrc = VERR_TIMEOUT;
1544 }
1545
1546 alock.acquire();
1547
1548 AssertPtr(pCallbackWrite);
1549 int rc2 = callbackRemove(uContextID);
1550 if (RT_SUCCESS(vrc))
1551 vrc = rc2;
1552
1553 LogFlowFuncLeaveRC(vrc);
1554 return vrc;
1555}
1556
1557// implementation of public methods
1558/////////////////////////////////////////////////////////////////////////////
1559
1560STDMETHODIMP GuestProcess::Read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, ComSafeArrayOut(BYTE, aData))
1561{
1562#ifndef VBOX_WITH_GUEST_CONTROL
1563 ReturnComNotImplemented();
1564#else
1565 if (aToRead == 0)
1566 return setError(E_INVALIDARG, tr("The size to read is zero"));
1567 CheckComArgOutSafeArrayPointerValid(aData);
1568
1569 AutoCaller autoCaller(this);
1570 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1571
1572 com::SafeArray<BYTE> data((size_t)aToRead);
1573 Assert(data.size() >= aToRead);
1574
1575 size_t cbRead;
1576 int vrc = readData(aHandle, aToRead, aTimeoutMS, data.raw(), aToRead, &cbRead);
1577 if (RT_SUCCESS(vrc))
1578 {
1579 if (data.size() != cbRead)
1580 data.resize(cbRead);
1581 data.detachTo(ComSafeArrayOutArg(aData));
1582 }
1583
1584 LogFlowThisFunc(("readData returned %Rrc, cbRead=%RU64\n", vrc, cbRead));
1585
1586 /** @todo Do setError() here. */
1587 HRESULT hr = RT_SUCCESS(vrc) ? S_OK : VBOX_E_IPRT_ERROR;
1588 LogFlowFuncLeaveRC(vrc);
1589
1590 return hr;
1591#endif /* VBOX_WITH_GUEST_CONTROL */
1592}
1593
1594STDMETHODIMP GuestProcess::Terminate(void)
1595{
1596#ifndef VBOX_WITH_GUEST_CONTROL
1597 ReturnComNotImplemented();
1598#else
1599 LogFlowThisFuncEnter();
1600
1601 AutoCaller autoCaller(this);
1602 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1603
1604 HRESULT hr = S_OK;
1605
1606 int vrc = terminateProcess();
1607 if (RT_FAILURE(vrc))
1608 {
1609 switch (vrc)
1610 {
1611 case VERR_NOT_IMPLEMENTED:
1612 ReturnComNotImplemented();
1613 break; /* Never reached. */
1614
1615 case VERR_NOT_SUPPORTED:
1616 hr = setError(VBOX_E_IPRT_ERROR,
1617 tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"),
1618 mData.mProcess.mCommand.c_str(), mData.mPID);
1619 break;
1620
1621 default:
1622 hr = setError(VBOX_E_IPRT_ERROR,
1623 tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"),
1624 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1625 break;
1626 }
1627 }
1628
1629 AssertPtr(mData.mParent);
1630 mData.mParent->processRemoveFromList(this);
1631
1632 /*
1633 * Release autocaller before calling uninit.
1634 */
1635 autoCaller.release();
1636
1637 uninit();
1638
1639 LogFlowFuncLeaveRC(vrc);
1640 return hr;
1641#endif /* VBOX_WITH_GUEST_CONTROL */
1642}
1643
1644STDMETHODIMP GuestProcess::WaitFor(ULONG aWaitFlags, ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1645{
1646#ifndef VBOX_WITH_GUEST_CONTROL
1647 ReturnComNotImplemented();
1648#else
1649 LogFlowThisFuncEnter();
1650
1651 CheckComArgOutPointerValid(aReason);
1652
1653 AutoCaller autoCaller(this);
1654 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1655
1656 /*
1657 * Note: Do not hold any locks here while waiting!
1658 */
1659 HRESULT hr;
1660
1661 GuestProcessWaitResult waitRes;
1662 int vrc = waitFor(aWaitFlags, aTimeoutMS, waitRes);
1663 if (RT_SUCCESS(vrc))
1664 {
1665 *aReason = waitRes.mResult;
1666 hr = setErrorExternal();
1667 }
1668 else
1669 {
1670 hr = setError(VBOX_E_IPRT_ERROR,
1671 tr("Waiting for process \"%s\" (PID %RU32) failed with vrc=%Rrc"),
1672 mData.mProcess.mCommand.c_str(), mData.mPID, vrc);
1673 }
1674 LogFlowFuncLeaveRC(vrc);
1675 return hr;
1676#endif /* VBOX_WITH_GUEST_CONTROL */
1677}
1678
1679STDMETHODIMP GuestProcess::WaitForArray(ComSafeArrayIn(ProcessWaitForFlag_T, aFlags), ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1680{
1681#ifndef VBOX_WITH_GUEST_CONTROL
1682 ReturnComNotImplemented();
1683#else
1684 LogFlowThisFuncEnter();
1685
1686 CheckComArgOutPointerValid(aReason);
1687
1688 AutoCaller autoCaller(this);
1689 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1690
1691 /*
1692 * Note: Do not hold any locks here while waiting!
1693 */
1694 uint32_t fWaitFor = ProcessWaitForFlag_None;
1695 com::SafeArray<ProcessWaitForFlag_T> flags(ComSafeArrayInArg(aFlags));
1696 for (size_t i = 0; i < flags.size(); i++)
1697 fWaitFor |= flags[i];
1698
1699 return WaitFor(fWaitFor, aTimeoutMS, aReason);
1700#endif /* VBOX_WITH_GUEST_CONTROL */
1701}
1702
1703STDMETHODIMP GuestProcess::Write(ULONG aHandle, ULONG aFlags,
1704 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1705{
1706#ifndef VBOX_WITH_GUEST_CONTROL
1707 ReturnComNotImplemented();
1708#else
1709 LogFlowThisFuncEnter();
1710
1711 CheckComArgOutPointerValid(aWritten);
1712
1713 AutoCaller autoCaller(this);
1714 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1715
1716 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1717
1718 com::SafeArray<BYTE> data(ComSafeArrayInArg(aData));
1719 int vrc = writeData(aHandle, aFlags, data.raw(), data.size(), aTimeoutMS, (uint32_t*)aWritten);
1720
1721 LogFlowThisFunc(("writeData returned %Rrc, aWritten=%RU32\n", vrc, aWritten));
1722
1723 /** @todo Do setError() here. */
1724 HRESULT hr = RT_SUCCESS(vrc) ? S_OK : VBOX_E_IPRT_ERROR;
1725 LogFlowFuncLeaveRC(vrc);
1726
1727 return hr;
1728#endif /* VBOX_WITH_GUEST_CONTROL */
1729}
1730
1731STDMETHODIMP GuestProcess::WriteArray(ULONG aHandle, ComSafeArrayIn(ProcessInputFlag_T, aFlags),
1732 ComSafeArrayIn(BYTE, aData), ULONG aTimeoutMS, ULONG *aWritten)
1733{
1734#ifndef VBOX_WITH_GUEST_CONTROL
1735 ReturnComNotImplemented();
1736#else
1737 LogFlowThisFuncEnter();
1738
1739 CheckComArgOutPointerValid(aWritten);
1740
1741 AutoCaller autoCaller(this);
1742 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1743
1744 /*
1745 * Note: Do not hold any locks here while writing!
1746 */
1747 ULONG fWrite = ProcessInputFlag_None;
1748 com::SafeArray<ProcessInputFlag_T> flags(ComSafeArrayInArg(aFlags));
1749 for (size_t i = 0; i < flags.size(); i++)
1750 fWrite |= flags[i];
1751
1752 return Write(aHandle, fWrite, ComSafeArrayInArg(aData), aTimeoutMS, aWritten);
1753#endif /* VBOX_WITH_GUEST_CONTROL */
1754}
1755
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