VirtualBox

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

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

GuestCtrl: More error checking.

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