VirtualBox

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

最後變更 在這個檔案從55640是 55613,由 vboxsync 提交於 10 年 前

IGuestSession: Added a pathStyle attribute (read-only) that translates the OS type reported by the guest additions into a DOS, UNIX or Unknown path styles values. Added two methods fsExists and fsQueryInfo that aren't as narrow minded as fileQueryInfo and directoryQueryInfo and has parameters for how to treat symbolic links.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 72.9 KB
 
1/* $Id: GuestProcessImpl.cpp 55613 2015-05-03 04:12:35Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest process handling.
4 */
5
6/*
7 * Copyright (C) 2012-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/**
19 * Locking rules:
20 * - When the main dispatcher (callbackDispatcher) is called it takes the
21 * WriteLock while dispatching to the various on* methods.
22 * - All other outer functions (accessible by Main) must not own a lock
23 * while waiting for a callback or for an event.
24 * - Only keep Read/WriteLocks as short as possible and only when necessary.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include "GuestProcessImpl.h"
31#include "GuestSessionImpl.h"
32#include "GuestCtrlImplPrivate.h"
33#include "ConsoleImpl.h"
34#include "VirtualBoxErrorInfoImpl.h"
35
36#include "Global.h"
37#include "AutoCaller.h"
38#include "VBoxEvents.h"
39
40#include <memory> /* For auto_ptr. */
41
42#include <iprt/asm.h>
43#include <iprt/cpp/utils.h> /* For unconst(). */
44#include <iprt/getopt.h>
45
46#include <VBox/com/listeners.h>
47
48#include <VBox/com/array.h>
49
50#ifdef LOG_GROUP
51 #undef LOG_GROUP
52#endif
53#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
54#include <VBox/log.h>
55
56
57class GuestProcessTask
58{
59public:
60
61 GuestProcessTask(GuestProcess *pProcess)
62 : mProcess(pProcess),
63 mRC(VINF_SUCCESS) { }
64
65 virtual ~GuestProcessTask(void) { }
66
67 int i_rc(void) const { return mRC; }
68 bool i_isOk(void) const { return RT_SUCCESS(mRC); }
69 const ComObjPtr<GuestProcess> &i_process(void) const { return mProcess; }
70
71protected:
72
73 const ComObjPtr<GuestProcess> mProcess;
74 int mRC;
75};
76
77class GuestProcessStartTask : public GuestProcessTask
78{
79public:
80
81 GuestProcessStartTask(GuestProcess *pProcess)
82 : GuestProcessTask(pProcess) { }
83};
84
85/**
86 * Internal listener class to serve events in an
87 * active manner, e.g. without polling delays.
88 */
89class GuestProcessListener
90{
91public:
92
93 GuestProcessListener(void)
94 {
95 }
96
97 HRESULT init(GuestProcess *pProcess)
98 {
99 AssertPtrReturn(pProcess, E_POINTER);
100 mProcess = pProcess;
101 return S_OK;
102 }
103
104 void uninit(void)
105 {
106 mProcess = NULL;
107 }
108
109 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
110 {
111 switch (aType)
112 {
113 case VBoxEventType_OnGuestProcessStateChanged:
114 case VBoxEventType_OnGuestProcessInputNotify:
115 case VBoxEventType_OnGuestProcessOutput:
116 {
117 AssertPtrReturn(mProcess, E_POINTER);
118 int rc2 = mProcess->signalWaitEvent(aType, aEvent);
119#ifdef DEBUG
120 LogFlowThisFunc(("Signalling events of type=%RU32, pProcess=%p resulted in rc=%Rrc\n",
121 aType, &mProcess, rc2));
122#endif
123 break;
124 }
125
126 default:
127 AssertMsgFailed(("Unhandled event %RU32\n", aType));
128 break;
129 }
130
131 return S_OK;
132 }
133
134private:
135
136 GuestProcess *mProcess;
137};
138typedef ListenerImpl<GuestProcessListener, GuestProcess*> GuestProcessListenerImpl;
139
140VBOX_LISTENER_DECLARE(GuestProcessListenerImpl)
141
142// constructor / destructor
143/////////////////////////////////////////////////////////////////////////////
144
145DEFINE_EMPTY_CTOR_DTOR(GuestProcess)
146
147HRESULT GuestProcess::FinalConstruct(void)
148{
149 LogFlowThisFuncEnter();
150 return BaseFinalConstruct();
151}
152
153void GuestProcess::FinalRelease(void)
154{
155 LogFlowThisFuncEnter();
156 uninit();
157 BaseFinalRelease();
158 LogFlowThisFuncLeave();
159}
160
161// public initializer/uninitializer for internal purposes only
162/////////////////////////////////////////////////////////////////////////////
163
164int GuestProcess::init(Console *aConsole, GuestSession *aSession, ULONG aProcessID,
165 const GuestProcessStartupInfo &aProcInfo, const GuestEnvironment *pBaseEnv)
166{
167 LogFlowThisFunc(("aConsole=%p, aSession=%p, aProcessID=%RU32 pBaseEnv=%p\n",
168 aConsole, aSession, aProcessID, pBaseEnv));
169
170 AssertPtrReturn(aConsole, VERR_INVALID_POINTER);
171 AssertPtrReturn(aSession, VERR_INVALID_POINTER);
172
173 /* Enclose the state transition NotReady->InInit->Ready. */
174 AutoInitSpan autoInitSpan(this);
175 AssertReturn(autoInitSpan.isOk(), VERR_OBJECT_DESTROYED);
176
177#ifndef VBOX_WITH_GUEST_CONTROL
178 autoInitSpan.setSucceeded();
179 return VINF_SUCCESS;
180#else
181 HRESULT hr;
182
183 int vrc = bindToSession(aConsole, aSession, aProcessID /* Object ID */);
184 if (RT_SUCCESS(vrc))
185 {
186 hr = unconst(mEventSource).createObject();
187 if (FAILED(hr))
188 vrc = VERR_NO_MEMORY;
189 else
190 {
191 hr = mEventSource->init();
192 if (FAILED(hr))
193 vrc = VERR_COM_UNEXPECTED;
194 }
195 }
196
197 if (RT_SUCCESS(vrc))
198 {
199 try
200 {
201 GuestProcessListener *pListener = new GuestProcessListener();
202 ComObjPtr<GuestProcessListenerImpl> thisListener;
203 hr = thisListener.createObject();
204 if (SUCCEEDED(hr))
205 hr = thisListener->init(pListener, this);
206
207 if (SUCCEEDED(hr))
208 {
209 com::SafeArray <VBoxEventType_T> eventTypes;
210 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
211 eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
212 eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
213 hr = mEventSource->RegisterListener(thisListener,
214 ComSafeArrayAsInParam(eventTypes),
215 TRUE /* Active listener */);
216 if (SUCCEEDED(hr))
217 {
218 vrc = baseInit();
219 if (RT_SUCCESS(vrc))
220 {
221 mLocalListener = thisListener;
222 }
223 }
224 else
225 vrc = VERR_COM_UNEXPECTED;
226 }
227 else
228 vrc = VERR_COM_UNEXPECTED;
229 }
230 catch(std::bad_alloc &)
231 {
232 vrc = VERR_NO_MEMORY;
233 }
234 }
235
236 if (RT_SUCCESS(vrc))
237 {
238 mData.mProcess = aProcInfo;
239 mData.mpSessionBaseEnv = pBaseEnv;
240 if (pBaseEnv)
241 pBaseEnv->retainConst();
242 mData.mExitCode = 0;
243 mData.mPID = 0;
244 mData.mLastError = VINF_SUCCESS;
245 mData.mStatus = ProcessStatus_Undefined;
246 /* Everything else will be set by the actual starting routine. */
247
248 /* Confirm a successful initialization when it's the case. */
249 autoInitSpan.setSucceeded();
250
251 return vrc;
252 }
253
254 autoInitSpan.setFailed();
255 return vrc;
256#endif
257}
258
259/**
260 * Uninitializes the instance.
261 * Called from FinalRelease() or IGuestSession::uninit().
262 */
263void GuestProcess::uninit(void)
264{
265 /* Enclose the state transition Ready->InUninit->NotReady. */
266 AutoUninitSpan autoUninitSpan(this);
267 if (autoUninitSpan.uninitDone())
268 return;
269
270#ifdef VBOX_WITH_GUEST_CONTROL
271 LogFlowThisFunc(("mExe=%s, PID=%RU32\n", mData.mProcess.mExecutable.c_str(), mData.mPID));
272
273 /* Terminate process if not already done yet. */
274 int guestRc = VINF_SUCCESS;
275 int vrc = i_terminateProcess(30 * 1000, &guestRc); /** @todo Make timeouts configurable. */
276 /* Note: Don't return here yet; first uninit all other stuff in
277 * case of failure. */
278
279 if (mData.mpSessionBaseEnv)
280 {
281 mData.mpSessionBaseEnv->releaseConst();
282 mData.mpSessionBaseEnv = NULL;
283 }
284
285 baseUninit();
286
287 LogFlowThisFunc(("Returning rc=%Rrc, guestRc=%Rrc\n",
288 vrc, guestRc));
289#endif
290}
291
292// implementation of public getters/setters for attributes
293/////////////////////////////////////////////////////////////////////////////
294HRESULT GuestProcess::getArguments(std::vector<com::Utf8Str> &aArguments)
295{
296#ifndef VBOX_WITH_GUEST_CONTROL
297 ReturnComNotImplemented();
298#else
299 LogFlowThisFuncEnter();
300
301 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
302 aArguments = mData.mProcess.mArguments;
303 return S_OK;
304#endif /* VBOX_WITH_GUEST_CONTROL */
305}
306
307HRESULT GuestProcess::getEnvironment(std::vector<com::Utf8Str> &aEnvironment)
308{
309#ifndef VBOX_WTIH_GUEST_CONTROL
310 ReturnComNotImplemented();
311#else
312 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); /* (Paranoia since both environment objects are immutable.) */
313 HRESULT hrc;
314 if (mData.mpSessionBaseEnv)
315 {
316 int vrc;
317 if (mData.mProcess.mEnvironmentChanges.count() == 0)
318 vrc = mData.mpSessionBaseEnv->queryPutEnvArray(&aEnvironment);
319 else
320 {
321 GuestEnvironment TmpEnv;
322 vrc = TmpEnv.copy(*mData.mpSessionBaseEnv);
323 if (RT_SUCCESS(vrc))
324 {
325 vrc = TmpEnv.applyChanges(mData.mProcess.mEnvironmentChanges);
326 if (RT_SUCCESS(rc))
327 vrc = TmpEnv.queryPutEnvArray(&aEnvironment);
328 }
329 }
330 hrc = Global::vboxStatusCodeToCOM(vrc);
331 }
332 else
333 hrc = setError(VBOX_E_NOT_SUPPORTED, tr("The base environment feature is not supported by the guest additions"));
334 LogFlowThisFuncLeave();
335 return hrc;
336#endif
337}
338
339HRESULT GuestProcess::getEventSource(ComPtr<IEventSource> &aEventSource)
340{
341#ifndef VBOX_WITH_GUEST_CONTROL
342 ReturnComNotImplemented();
343#else
344 LogFlowThisFuncEnter();
345
346 // no need to lock - lifetime constant
347 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
348
349 LogFlowThisFuncLeave();
350 return S_OK;
351#endif /* VBOX_WITH_GUEST_CONTROL */
352}
353
354HRESULT GuestProcess::getExecutablePath(com::Utf8Str &aExecutablePath)
355{
356#ifndef VBOX_WITH_GUEST_CONTROL
357 ReturnComNotImplemented();
358#else
359 LogFlowThisFuncEnter();
360
361 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
362
363 aExecutablePath = mData.mProcess.mExecutable;
364
365 return S_OK;
366#endif /* VBOX_WITH_GUEST_CONTROL */
367}
368
369HRESULT GuestProcess::getExitCode(LONG *aExitCode)
370{
371#ifndef VBOX_WITH_GUEST_CONTROL
372 ReturnComNotImplemented();
373#else
374 LogFlowThisFuncEnter();
375
376 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
377
378 *aExitCode = mData.mExitCode;
379
380 return S_OK;
381#endif /* VBOX_WITH_GUEST_CONTROL */
382}
383
384HRESULT GuestProcess::getName(com::Utf8Str &aName)
385{
386#ifndef VBOX_WITH_GUEST_CONTROL
387 ReturnComNotImplemented();
388#else
389 LogFlowThisFuncEnter();
390
391 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
392
393 aName = mData.mProcess.mName;
394
395 return S_OK;
396#endif /* VBOX_WITH_GUEST_CONTROL */
397}
398
399HRESULT GuestProcess::getPID(ULONG *aPID)
400{
401#ifndef VBOX_WITH_GUEST_CONTROL
402 ReturnComNotImplemented();
403#else
404 LogFlowThisFuncEnter();
405
406 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
407
408 *aPID = mData.mPID;
409
410 return S_OK;
411#endif /* VBOX_WITH_GUEST_CONTROL */
412}
413
414HRESULT GuestProcess::getStatus(ProcessStatus_T *aStatus)
415{
416#ifndef VBOX_WITH_GUEST_CONTROL
417 ReturnComNotImplemented();
418#else
419 LogFlowThisFuncEnter();
420
421 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
422
423 *aStatus = mData.mStatus;
424
425 return S_OK;
426#endif /* VBOX_WITH_GUEST_CONTROL */
427}
428
429// private methods
430/////////////////////////////////////////////////////////////////////////////
431
432int GuestProcess::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
433{
434 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
435 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
436#ifdef DEBUG
437 LogFlowThisFunc(("uPID=%RU32, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
438 mData.mPID, pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
439#endif
440
441 int vrc;
442 switch (pCbCtx->uFunction)
443 {
444 case GUEST_DISCONNECTED:
445 {
446 vrc = i_onGuestDisconnected(pCbCtx, pSvcCb);
447 break;
448 }
449
450 case GUEST_EXEC_STATUS:
451 {
452 vrc = i_onProcessStatusChange(pCbCtx, pSvcCb);
453 break;
454 }
455
456 case GUEST_EXEC_OUTPUT:
457 {
458 vrc = i_onProcessOutput(pCbCtx, pSvcCb);
459 break;
460 }
461
462 case GUEST_EXEC_INPUT_STATUS:
463 {
464 vrc = i_onProcessInputStatus(pCbCtx, pSvcCb);
465 break;
466 }
467
468 default:
469 /* Silently ignore not implemented functions. */
470 vrc = VERR_NOT_SUPPORTED;
471 break;
472 }
473
474#ifdef DEBUG
475 LogFlowFuncLeaveRC(vrc);
476#endif
477 return vrc;
478}
479
480/**
481 * Checks if the current assigned PID matches another PID (from a callback).
482 *
483 * In protocol v1 we don't have the possibility to terminate/kill
484 * processes so it can happen that a formerly started process A
485 * (which has the context ID 0 (session=0, process=0, count=0) will
486 * send a delayed message to the host if this process has already
487 * been discarded there and the same context ID was reused by
488 * a process B. Process B in turn then has a different guest PID.
489 *
490 * Note: This also can happen when restoring from a saved state which
491 * had a guest process running.
492 *
493 * @return IPRT status code.
494 * @param uPID PID to check.
495 */
496inline int GuestProcess::i_checkPID(uint32_t uPID)
497{
498 int rc = VINF_SUCCESS;
499
500 /* Was there a PID assigned yet? */
501 if (mData.mPID)
502 {
503 if (RT_UNLIKELY(mData.mPID != uPID))
504 {
505 LogFlowFunc(("Stale guest process (PID=%RU32) sent data to a newly started process (pProcesS=%p, PID=%RU32, status=%RU32)\n",
506 uPID, this, mData.mPID, mData.mStatus));
507 rc = VERR_NOT_FOUND;
508 }
509 }
510
511 return rc;
512}
513
514/* static */
515Utf8Str GuestProcess::i_guestErrorToString(int guestRc)
516{
517 Utf8Str strError;
518
519 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
520 switch (guestRc)
521 {
522 case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
523 strError += Utf8StrFmt(tr("The specified file was not found on guest"));
524 break;
525
526 case VERR_INVALID_VM_HANDLE:
527 strError += Utf8StrFmt(tr("VMM device is not available (is the VM running?)"));
528 break;
529
530 case VERR_HGCM_SERVICE_NOT_FOUND:
531 strError += Utf8StrFmt(tr("The guest execution service is not available"));
532 break;
533
534 case VERR_PATH_NOT_FOUND:
535 strError += Utf8StrFmt(tr("Could not resolve path to specified file was not found on guest"));
536 break;
537
538 case VERR_BAD_EXE_FORMAT:
539 strError += Utf8StrFmt(tr("The specified file is not an executable format on guest"));
540 break;
541
542 case VERR_AUTHENTICATION_FAILURE:
543 strError += Utf8StrFmt(tr("The specified user was not able to logon on guest"));
544 break;
545
546 case VERR_INVALID_NAME:
547 strError += Utf8StrFmt(tr("The specified file is an invalid name"));
548 break;
549
550 case VERR_TIMEOUT:
551 strError += Utf8StrFmt(tr("The guest did not respond within time"));
552 break;
553
554 case VERR_CANCELLED:
555 strError += Utf8StrFmt(tr("The execution operation was canceled"));
556 break;
557
558 case VERR_PERMISSION_DENIED:
559 strError += Utf8StrFmt(tr("Invalid user/password credentials"));
560 break;
561
562 case VERR_MAX_PROCS_REACHED:
563 strError += Utf8StrFmt(tr("Maximum number of concurrent guest processes has been reached"));
564 break;
565
566 case VERR_NOT_EQUAL: /** @todo Imprecise to the user; can mean anything and all. */
567 strError += Utf8StrFmt(tr("Unable to retrieve requested information"));
568 break;
569
570 case VERR_NOT_FOUND:
571 strError += Utf8StrFmt(tr("The guest execution service is not ready (yet)"));
572 break;
573
574 default:
575 strError += Utf8StrFmt("%Rrc", guestRc);
576 break;
577 }
578
579 return strError;
580}
581
582inline bool GuestProcess::i_isAlive(void)
583{
584 return ( mData.mStatus == ProcessStatus_Started
585 || mData.mStatus == ProcessStatus_Paused
586 || mData.mStatus == ProcessStatus_Terminating);
587}
588
589inline bool GuestProcess::i_hasEnded(void)
590{
591 return ( mData.mStatus == ProcessStatus_TerminatedNormally
592 || mData.mStatus == ProcessStatus_TerminatedSignal
593 || mData.mStatus == ProcessStatus_TerminatedAbnormally
594 || mData.mStatus == ProcessStatus_TimedOutKilled
595 || mData.mStatus == ProcessStatus_TimedOutAbnormally
596 || mData.mStatus == ProcessStatus_Down
597 || mData.mStatus == ProcessStatus_Error);
598}
599
600int GuestProcess::i_onGuestDisconnected(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
601{
602 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
603 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
604
605 int vrc = i_setProcessStatus(ProcessStatus_Down, VINF_SUCCESS);
606
607 LogFlowFuncLeaveRC(vrc);
608 return vrc;
609}
610
611int GuestProcess::i_onProcessInputStatus(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
612{
613 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
614 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
615 /* pCallback is optional. */
616
617 if (pSvcCbData->mParms < 5)
618 return VERR_INVALID_PARAMETER;
619
620 CALLBACKDATA_PROC_INPUT dataCb;
621 /* pSvcCb->mpaParms[0] always contains the context ID. */
622 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
623 AssertRCReturn(vrc, vrc);
624 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus);
625 AssertRCReturn(vrc, vrc);
626 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
627 AssertRCReturn(vrc, vrc);
628 vrc = pSvcCbData->mpaParms[4].getUInt32(&dataCb.uProcessed);
629 AssertRCReturn(vrc, vrc);
630
631 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RI32, cbProcessed=%RU32\n",
632 dataCb.uPID, dataCb.uStatus, dataCb.uFlags, dataCb.uProcessed));
633
634 vrc = i_checkPID(dataCb.uPID);
635 if (RT_SUCCESS(vrc))
636 {
637 ProcessInputStatus_T inputStatus = ProcessInputStatus_Undefined;
638 switch (dataCb.uStatus)
639 {
640 case INPUT_STS_WRITTEN:
641 inputStatus = ProcessInputStatus_Written;
642 break;
643 case INPUT_STS_ERROR:
644 inputStatus = ProcessInputStatus_Broken;
645 break;
646 case INPUT_STS_TERMINATED:
647 inputStatus = ProcessInputStatus_Broken;
648 break;
649 case INPUT_STS_OVERFLOW:
650 inputStatus = ProcessInputStatus_Overflow;
651 break;
652 case INPUT_STS_UNDEFINED:
653 /* Fall through is intentional. */
654 default:
655 AssertMsg(!dataCb.uProcessed, ("Processed data is not 0 in undefined input state\n"));
656 break;
657 }
658
659 if (inputStatus != ProcessInputStatus_Undefined)
660 {
661 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
662
663 /* Copy over necessary data before releasing lock again. */
664 uint32_t uPID = mData.mPID;
665 /** @todo Also handle mSession? */
666
667 alock.release(); /* Release lock before firing off event. */
668
669 fireGuestProcessInputNotifyEvent(mEventSource, mSession, this,
670 uPID, 0 /* StdIn */, dataCb.uProcessed, inputStatus);
671 }
672 }
673
674 LogFlowFuncLeaveRC(vrc);
675 return vrc;
676}
677
678int GuestProcess::i_onProcessNotifyIO(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
679{
680 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
681 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
682
683 return VERR_NOT_IMPLEMENTED;
684}
685
686int GuestProcess::i_onProcessStatusChange(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
687{
688 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
689 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
690
691 if (pSvcCbData->mParms < 5)
692 return VERR_INVALID_PARAMETER;
693
694 CALLBACKDATA_PROC_STATUS dataCb;
695 /* pSvcCb->mpaParms[0] always contains the context ID. */
696 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
697 AssertRCReturn(vrc, vrc);
698 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uStatus);
699 AssertRCReturn(vrc, vrc);
700 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
701 AssertRCReturn(vrc, vrc);
702 vrc = pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
703 AssertRCReturn(vrc, vrc);
704
705 LogFlowThisFunc(("uPID=%RU32, uStatus=%RU32, uFlags=%RU32\n",
706 dataCb.uPID, dataCb.uStatus, dataCb.uFlags));
707
708 vrc = i_checkPID(dataCb.uPID);
709 if (RT_SUCCESS(vrc))
710 {
711 ProcessStatus_T procStatus = ProcessStatus_Undefined;
712 int procRc = VINF_SUCCESS;
713
714 switch (dataCb.uStatus)
715 {
716 case PROC_STS_STARTED:
717 {
718 procStatus = ProcessStatus_Started;
719
720 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
721 mData.mPID = dataCb.uPID; /* Set the process PID. */
722 break;
723 }
724
725 case PROC_STS_TEN:
726 {
727 procStatus = ProcessStatus_TerminatedNormally;
728
729 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
730 mData.mExitCode = dataCb.uFlags; /* Contains the exit code. */
731 break;
732 }
733
734 case PROC_STS_TES:
735 {
736 procStatus = ProcessStatus_TerminatedSignal;
737
738 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
739 mData.mExitCode = dataCb.uFlags; /* Contains the signal. */
740 break;
741 }
742
743 case PROC_STS_TEA:
744 {
745 procStatus = ProcessStatus_TerminatedAbnormally;
746 break;
747 }
748
749 case PROC_STS_TOK:
750 {
751 procStatus = ProcessStatus_TimedOutKilled;
752 break;
753 }
754
755 case PROC_STS_TOA:
756 {
757 procStatus = ProcessStatus_TimedOutAbnormally;
758 break;
759 }
760
761 case PROC_STS_DWN:
762 {
763 procStatus = ProcessStatus_Down;
764 break;
765 }
766
767 case PROC_STS_ERROR:
768 {
769 procRc = dataCb.uFlags; /* mFlags contains the IPRT error sent from the guest. */
770 procStatus = ProcessStatus_Error;
771 break;
772 }
773
774 case PROC_STS_UNDEFINED:
775 default:
776 {
777 /* Silently skip this request. */
778 procStatus = ProcessStatus_Undefined;
779 break;
780 }
781 }
782
783 LogFlowThisFunc(("Got rc=%Rrc, procSts=%RU32, procRc=%Rrc\n",
784 vrc, procStatus, procRc));
785
786 /* Set the process status. */
787 int rc2 = i_setProcessStatus(procStatus, procRc);
788 if (RT_SUCCESS(vrc))
789 vrc = rc2;
790 }
791
792 LogFlowFuncLeaveRC(vrc);
793 return vrc;
794}
795
796int GuestProcess::i_onProcessOutput(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
797{
798 AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
799
800 if (pSvcCbData->mParms < 5)
801 return VERR_INVALID_PARAMETER;
802
803 CALLBACKDATA_PROC_OUTPUT dataCb;
804 /* pSvcCb->mpaParms[0] always contains the context ID. */
805 int vrc = pSvcCbData->mpaParms[1].getUInt32(&dataCb.uPID);
806 AssertRCReturn(vrc, vrc);
807 vrc = pSvcCbData->mpaParms[2].getUInt32(&dataCb.uHandle);
808 AssertRCReturn(vrc, vrc);
809 vrc = pSvcCbData->mpaParms[3].getUInt32(&dataCb.uFlags);
810 AssertRCReturn(vrc, vrc);
811 vrc = pSvcCbData->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
812 AssertRCReturn(vrc, vrc);
813
814 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RI32, pvData=%p, cbData=%RU32\n",
815 dataCb.uPID, dataCb.uHandle, dataCb.uFlags, dataCb.pvData, dataCb.cbData));
816
817 vrc = i_checkPID(dataCb.uPID);
818 if (RT_SUCCESS(vrc))
819 {
820 com::SafeArray<BYTE> data((size_t)dataCb.cbData);
821 if (dataCb.cbData)
822 data.initFrom((BYTE*)dataCb.pvData, dataCb.cbData);
823
824 fireGuestProcessOutputEvent(mEventSource, mSession, this,
825 mData.mPID, dataCb.uHandle, dataCb.cbData, ComSafeArrayAsInParam(data));
826 }
827
828 LogFlowFuncLeaveRC(vrc);
829 return vrc;
830}
831
832/**
833 * Called by IGuestSession right before this process gets
834 * removed from the public process list.
835 */
836int GuestProcess::i_onRemove(void)
837{
838 LogFlowThisFuncEnter();
839
840 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
841
842 int vrc = VINF_SUCCESS;
843
844 /*
845 * Note: The event source stuff holds references to this object,
846 * so make sure that this is cleaned up *before* calling uninit().
847 */
848 if (!mEventSource.isNull())
849 {
850 mEventSource->UnregisterListener(mLocalListener);
851
852 mLocalListener.setNull();
853 unconst(mEventSource).setNull();
854 }
855
856 LogFlowFuncLeaveRC(vrc);
857 return vrc;
858}
859
860int GuestProcess::i_readData(uint32_t uHandle, uint32_t uSize, uint32_t uTimeoutMS,
861 void *pvData, size_t cbData, uint32_t *pcbRead, int *pGuestRc)
862{
863 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uSize=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%RU32, pGuestRc=%p\n",
864 mData.mPID, uHandle, uSize, uTimeoutMS, pvData, cbData, pGuestRc));
865 AssertReturn(uSize, VERR_INVALID_PARAMETER);
866 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
867 AssertReturn(cbData >= uSize, VERR_INVALID_PARAMETER);
868 /* pcbRead is optional. */
869
870 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
871
872 if ( mData.mStatus != ProcessStatus_Started
873 /* Skip reading if the process wasn't started with the appropriate
874 * flags. */
875 || ( ( uHandle == OUTPUT_HANDLE_ID_STDOUT
876 || uHandle == OUTPUT_HANDLE_ID_STDOUT_DEPRECATED)
877 && !(mData.mProcess.mFlags & ProcessCreateFlag_WaitForStdOut))
878 || ( uHandle == OUTPUT_HANDLE_ID_STDERR
879 && !(mData.mProcess.mFlags & ProcessCreateFlag_WaitForStdErr))
880 )
881 {
882 if (pcbRead)
883 *pcbRead = 0;
884 if (pGuestRc)
885 *pGuestRc = VINF_SUCCESS;
886 return VINF_SUCCESS; /* Nothing to read anymore. */
887 }
888
889 int vrc;
890
891 GuestWaitEvent *pEvent = NULL;
892 GuestEventTypes eventTypes;
893 try
894 {
895 /*
896 * On Guest Additions < 4.3 there is no guarantee that the process status
897 * change arrives *after* the output event, e.g. if this was the last output
898 * block being read and the process will report status "terminate".
899 * So just skip checking for process status change and only wait for the
900 * output event.
901 */
902 if (mSession->i_getProtocolVersion() >= 2)
903 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
904 eventTypes.push_back(VBoxEventType_OnGuestProcessOutput);
905
906 vrc = registerWaitEvent(eventTypes, &pEvent);
907 }
908 catch (std::bad_alloc)
909 {
910 vrc = VERR_NO_MEMORY;
911 }
912
913 if (RT_FAILURE(vrc))
914 return vrc;
915
916 if (RT_SUCCESS(vrc))
917 {
918 VBOXHGCMSVCPARM paParms[8];
919 int i = 0;
920 paParms[i++].setUInt32(pEvent->ContextID());
921 paParms[i++].setUInt32(mData.mPID);
922 paParms[i++].setUInt32(uHandle);
923 paParms[i++].setUInt32(0 /* Flags, none set yet. */);
924
925 alock.release(); /* Drop the write lock before sending. */
926
927 vrc = sendCommand(HOST_EXEC_GET_OUTPUT, i, paParms);
928 }
929
930 if (RT_SUCCESS(vrc))
931 vrc = i_waitForOutput(pEvent, uHandle, uTimeoutMS,
932 pvData, cbData, pcbRead);
933
934 unregisterWaitEvent(pEvent);
935
936 LogFlowFuncLeaveRC(vrc);
937 return vrc;
938}
939
940/* Does not do locking; caller is responsible for that! */
941int GuestProcess::i_setProcessStatus(ProcessStatus_T procStatus, int procRc)
942{
943 LogFlowThisFuncEnter();
944
945 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
946
947 LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, procRc=%Rrc\n",
948 mData.mStatus, procStatus, procRc));
949
950 if (procStatus == ProcessStatus_Error)
951 {
952 AssertMsg(RT_FAILURE(procRc), ("Guest rc must be an error (%Rrc)\n", procRc));
953 /* Do not allow overwriting an already set error. If this happens
954 * this means we forgot some error checking/locking somewhere. */
955 AssertMsg(RT_SUCCESS(mData.mLastError), ("Guest rc already set (to %Rrc)\n", mData.mLastError));
956 }
957 else
958 AssertMsg(RT_SUCCESS(procRc), ("Guest rc must not be an error (%Rrc)\n", procRc));
959
960 int rc = VINF_SUCCESS;
961
962 if (mData.mStatus != procStatus) /* Was there a process status change? */
963 {
964 mData.mStatus = procStatus;
965 mData.mLastError = procRc;
966
967 ComObjPtr<VirtualBoxErrorInfo> errorInfo;
968 HRESULT hr = errorInfo.createObject();
969 ComAssertComRC(hr);
970 if (RT_FAILURE(mData.mLastError))
971 {
972 hr = errorInfo->initEx(VBOX_E_IPRT_ERROR, mData.mLastError,
973 COM_IIDOF(IGuestProcess), getComponentName(),
974 i_guestErrorToString(mData.mLastError));
975 ComAssertComRC(hr);
976 }
977
978 /* Copy over necessary data before releasing lock again. */
979 uint32_t uPID = mData.mPID;
980 /** @todo Also handle mSession? */
981
982 alock.release(); /* Release lock before firing off event. */
983
984 fireGuestProcessStateChangedEvent(mEventSource, mSession, this,
985 uPID, procStatus, errorInfo);
986#if 0
987 /*
988 * On Guest Additions < 4.3 there is no guarantee that outstanding
989 * requests will be delivered to the host after the process has ended,
990 * so just cancel all waiting events here to not let clients run
991 * into timeouts.
992 */
993 if ( mSession->getProtocolVersion() < 2
994 && hasEnded())
995 {
996 LogFlowThisFunc(("Process ended, canceling outstanding wait events ...\n"));
997 rc = cancelWaitEvents();
998 }
999#endif
1000 }
1001
1002 return rc;
1003}
1004
1005/* static */
1006HRESULT GuestProcess::i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
1007{
1008 AssertPtr(pInterface);
1009 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
1010
1011 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(guestRc).c_str());
1012}
1013
1014int GuestProcess::i_startProcess(uint32_t uTimeoutMS, int *pGuestRc)
1015{
1016 LogFlowThisFunc(("uTimeoutMS=%RU32, procExe=%s, procTimeoutMS=%RU32, procFlags=%x, sessionID=%RU32\n",
1017 uTimeoutMS, mData.mProcess.mExecutable.c_str(), mData.mProcess.mTimeoutMS, mData.mProcess.mFlags,
1018 mSession->i_getId()));
1019
1020 /* Wait until the caller function (if kicked off by a thread)
1021 * has returned and continue operation. */
1022 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1023
1024 mData.mStatus = ProcessStatus_Starting;
1025
1026 int vrc;
1027
1028 GuestWaitEvent *pEvent = NULL;
1029 GuestEventTypes eventTypes;
1030 try
1031 {
1032 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1033
1034 vrc = registerWaitEvent(eventTypes, &pEvent);
1035 }
1036 catch (std::bad_alloc)
1037 {
1038 vrc = VERR_NO_MEMORY;
1039 }
1040
1041 if (RT_FAILURE(vrc))
1042 return vrc;
1043
1044 GuestSession *pSession = mSession;
1045 AssertPtr(pSession);
1046 uint32_t const uProtocol = pSession->i_getProtocolVersion();
1047
1048 const GuestCredentials &sessionCreds = pSession->i_getCredentials();
1049
1050
1051 /* Prepare arguments. */
1052 char *pszArgs = NULL;
1053 size_t cArgs = mData.mProcess.mArguments.size();
1054 if (cArgs >= UINT32_MAX)
1055 vrc = VERR_BUFFER_OVERFLOW;
1056
1057 if ( RT_SUCCESS(vrc)
1058 && cArgs)
1059 {
1060 char const **papszArgv = (char const **)RTMemAlloc((cArgs + 1) * sizeof(papszArgv[0]));
1061 AssertReturn(papszArgv, VERR_NO_MEMORY);
1062
1063 for (size_t i = 0; i < cArgs; i++)
1064 {
1065 papszArgv[i] = mData.mProcess.mArguments[i].c_str();
1066 AssertPtr(papszArgv[i]);
1067 }
1068 papszArgv[cArgs] = NULL;
1069
1070 if (uProtocol < UINT32_C(0xdeadbeef) ) /** @todo implement a way of sending argv[0], best idea is a new command. */
1071 vrc = RTGetOptArgvToString(&pszArgs, papszArgv + 1, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
1072 else
1073 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_BOURNE_SH);
1074
1075 RTMemFree(papszArgv);
1076 }
1077
1078 /* Calculate arguments size (in bytes). */
1079 size_t cbArgs = 0;
1080 if (RT_SUCCESS(vrc))
1081 cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
1082
1083 /* Prepare environment. The guest service dislikes the empty string at the end, so drop it. */
1084 size_t cbEnvBlock;
1085 char *pszzEnvBlock;
1086 if (RT_SUCCESS(vrc))
1087 vrc = mData.mProcess.mEnvironmentChanges.queryUtf8Block(&pszzEnvBlock, &cbEnvBlock);
1088 if (RT_SUCCESS(vrc))
1089 {
1090 Assert(cbEnvBlock > 0);
1091 cbEnvBlock--;
1092
1093 /* Prepare HGCM call. */
1094 VBOXHGCMSVCPARM paParms[16];
1095 int i = 0;
1096 paParms[i++].setUInt32(pEvent->ContextID());
1097 paParms[i++].setCppString(mData.mProcess.mExecutable);
1098 paParms[i++].setUInt32(mData.mProcess.mFlags);
1099 paParms[i++].setUInt32((uint32_t)mData.mProcess.mArguments.size());
1100 paParms[i++].setPointer(pszArgs, (uint32_t)cbArgs);
1101 paParms[i++].setUInt32(mData.mProcess.mEnvironmentChanges.count());
1102 paParms[i++].setUInt32((uint32_t)cbEnvBlock);
1103 paParms[i++].setPointer(pszzEnvBlock, (uint32_t)cbEnvBlock);
1104 if (uProtocol < 2)
1105 {
1106 /* In protocol v1 (VBox < 4.3) the credentials were part of the execution
1107 * call. In newer protocols these credentials are part of the opened guest
1108 * session, so not needed anymore here. */
1109 paParms[i++].setCppString(sessionCreds.mUser);
1110 paParms[i++].setCppString(sessionCreds.mPassword);
1111 }
1112 /*
1113 * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
1114 * until the process was started - the process itself then gets an infinite timeout for execution.
1115 * This is handy when we want to start a process inside a worker thread within a certain timeout
1116 * but let the started process perform lengthly operations then.
1117 */
1118 if (mData.mProcess.mFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1119 paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
1120 else
1121 paParms[i++].setUInt32(mData.mProcess.mTimeoutMS);
1122 if (uProtocol >= 2)
1123 {
1124 paParms[i++].setUInt32(mData.mProcess.mPriority);
1125 /* CPU affinity: We only support one CPU affinity block at the moment,
1126 * so that makes up to 64 CPUs total. This can be more in the future. */
1127 paParms[i++].setUInt32(1);
1128 /* The actual CPU affinity blocks. */
1129 paParms[i++].setPointer((void *)&mData.mProcess.mAffinity, sizeof(mData.mProcess.mAffinity));
1130 }
1131
1132 alock.release(); /* Drop the write lock before sending. */
1133
1134 vrc = sendCommand(HOST_EXEC_CMD, i, paParms);
1135 if (RT_FAILURE(vrc))
1136 {
1137 int rc2 = i_setProcessStatus(ProcessStatus_Error, vrc);
1138 AssertRC(rc2);
1139 }
1140
1141 mData.mProcess.mEnvironmentChanges.freeUtf8Block(pszzEnvBlock);
1142 }
1143
1144 if (pszArgs)
1145 RTStrFree(pszArgs);
1146
1147 if (RT_SUCCESS(vrc))
1148 vrc = i_waitForStatusChange(pEvent, uTimeoutMS,
1149 NULL /* Process status */, pGuestRc);
1150 unregisterWaitEvent(pEvent);
1151
1152 LogFlowFuncLeaveRC(vrc);
1153 return vrc;
1154}
1155
1156int GuestProcess::i_startProcessAsync(void)
1157{
1158 LogFlowThisFuncEnter();
1159
1160 int vrc;
1161
1162 try
1163 {
1164 /* Asynchronously start the process on the guest by kicking off a
1165 * worker thread. */
1166 std::auto_ptr<GuestProcessStartTask> pTask(new GuestProcessStartTask(this));
1167 AssertReturn(pTask->i_isOk(), pTask->i_rc());
1168
1169 vrc = RTThreadCreate(NULL, GuestProcess::i_startProcessThread,
1170 (void *)pTask.get(), 0,
1171 RTTHREADTYPE_MAIN_WORKER, 0,
1172 "gctlPrcStart");
1173 if (RT_SUCCESS(vrc))
1174 {
1175 /* pTask is now owned by startProcessThread(), so release it. */
1176 pTask.release();
1177 }
1178 }
1179 catch(std::bad_alloc &)
1180 {
1181 vrc = VERR_NO_MEMORY;
1182 }
1183
1184 LogFlowFuncLeaveRC(vrc);
1185 return vrc;
1186}
1187
1188/* static */
1189DECLCALLBACK(int) GuestProcess::i_startProcessThread(RTTHREAD Thread, void *pvUser)
1190{
1191 LogFlowFunc(("pvUser=%p\n", pvUser));
1192
1193 std::auto_ptr<GuestProcessStartTask> pTask(static_cast<GuestProcessStartTask*>(pvUser));
1194 AssertPtr(pTask.get());
1195
1196 const ComObjPtr<GuestProcess> pProcess(pTask->i_process());
1197 Assert(!pProcess.isNull());
1198
1199 AutoCaller autoCaller(pProcess);
1200 if (FAILED(autoCaller.rc())) return autoCaller.rc();
1201
1202 int vrc = pProcess->i_startProcess(30 * 1000 /* 30s timeout */,
1203 NULL /* Guest rc, ignored */);
1204 /* Nothing to do here anymore. */
1205
1206 LogFlowFunc(("pProcess=%p returning rc=%Rrc\n", (GuestProcess *)pProcess, vrc));
1207 return vrc;
1208}
1209
1210int GuestProcess::i_terminateProcess(uint32_t uTimeoutMS, int *pGuestRc)
1211{
1212 /* pGuestRc is optional. */
1213 LogFlowThisFunc(("uTimeoutMS=%RU32\n", uTimeoutMS));
1214
1215 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1216
1217 int vrc = VINF_SUCCESS;
1218
1219 if (mData.mStatus != ProcessStatus_Started)
1220 {
1221 LogFlowThisFunc(("Process not in started state (state is %RU32), skipping termination\n",
1222 mData.mStatus));
1223 }
1224 else
1225 {
1226 AssertPtr(mSession);
1227 /* Note: VBox < 4.3 (aka protocol version 1) does not
1228 * support this, so just skip. */
1229 if (mSession->i_getProtocolVersion() < 2)
1230 vrc = VERR_NOT_SUPPORTED;
1231
1232 if (RT_SUCCESS(vrc))
1233 {
1234 GuestWaitEvent *pEvent = NULL;
1235 GuestEventTypes eventTypes;
1236 try
1237 {
1238 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1239
1240 vrc = registerWaitEvent(eventTypes, &pEvent);
1241 }
1242 catch (std::bad_alloc)
1243 {
1244 vrc = VERR_NO_MEMORY;
1245 }
1246
1247 if (RT_FAILURE(vrc))
1248 return vrc;
1249
1250 VBOXHGCMSVCPARM paParms[4];
1251 int i = 0;
1252 paParms[i++].setUInt32(pEvent->ContextID());
1253 paParms[i++].setUInt32(mData.mPID);
1254
1255 alock.release(); /* Drop the write lock before sending. */
1256
1257 vrc = sendCommand(HOST_EXEC_TERMINATE, i, paParms);
1258 if (RT_SUCCESS(vrc))
1259 vrc = i_waitForStatusChange(pEvent, uTimeoutMS,
1260 NULL /* ProcessStatus */, pGuestRc);
1261 unregisterWaitEvent(pEvent);
1262 }
1263 }
1264
1265 LogFlowFuncLeaveRC(vrc);
1266 return vrc;
1267}
1268
1269/* static */
1270ProcessWaitResult_T GuestProcess::i_waitFlagsToResultEx(uint32_t fWaitFlags,
1271 ProcessStatus_T oldStatus, ProcessStatus_T newStatus,
1272 uint32_t uProcFlags, uint32_t uProtocol)
1273{
1274 ProcessWaitResult_T waitResult = ProcessWaitResult_None;
1275
1276 switch (newStatus)
1277 {
1278 case ProcessStatus_TerminatedNormally:
1279 case ProcessStatus_TerminatedSignal:
1280 case ProcessStatus_TerminatedAbnormally:
1281 case ProcessStatus_Down:
1282 /* Nothing to wait for anymore. */
1283 waitResult = ProcessWaitResult_Terminate;
1284 break;
1285
1286 case ProcessStatus_TimedOutKilled:
1287 case ProcessStatus_TimedOutAbnormally:
1288 /* Dito. */
1289 waitResult = ProcessWaitResult_Timeout;
1290 break;
1291
1292 case ProcessStatus_Started:
1293 switch (oldStatus)
1294 {
1295 case ProcessStatus_Undefined:
1296 case ProcessStatus_Starting:
1297 /* Also wait for process start. */
1298 if (fWaitFlags & ProcessWaitForFlag_Start)
1299 waitResult = ProcessWaitResult_Start;
1300 else
1301 {
1302 /*
1303 * If ProcessCreateFlag_WaitForProcessStartOnly was specified on process creation the
1304 * caller is not interested in getting further process statuses -- so just don't notify
1305 * anything here anymore and return.
1306 */
1307 if (uProcFlags & ProcessCreateFlag_WaitForProcessStartOnly)
1308 waitResult = ProcessWaitResult_Start;
1309 }
1310 break;
1311
1312 case ProcessStatus_Started:
1313 /* Only wait for process start. */
1314 if (fWaitFlags == ProcessWaitForFlag_Start)
1315 waitResult = ProcessWaitResult_Start;
1316 break;
1317
1318 default:
1319 AssertMsgFailed(("Unhandled old status %RU32 before new status 'started'\n",
1320 oldStatus));
1321 waitResult = ProcessWaitResult_Start;
1322 break;
1323 }
1324 break;
1325
1326 case ProcessStatus_Error:
1327 /* Nothing to wait for anymore. */
1328 waitResult = ProcessWaitResult_Error;
1329 break;
1330
1331 case ProcessStatus_Undefined:
1332 case ProcessStatus_Starting:
1333 /* No result available yet, leave wait
1334 * flags untouched. */
1335 break;
1336 }
1337
1338 if (newStatus == ProcessStatus_Started)
1339 {
1340 /**
1341 * Filter out waits which are *not* supported using
1342 * older guest control Guest Additions.
1343 *
1344 ** @todo ProcessWaitForFlag_Std* flags are not implemented yet.
1345 */
1346 if (uProtocol < 99) /* See @todo above. */
1347 {
1348 if ( waitResult == ProcessWaitResult_None
1349 /* We don't support waiting for stdin, out + err,
1350 * just skip waiting then. */
1351 && ( (fWaitFlags & ProcessWaitForFlag_StdIn)
1352 || (fWaitFlags & ProcessWaitForFlag_StdOut)
1353 || (fWaitFlags & ProcessWaitForFlag_StdErr)
1354 )
1355 )
1356 {
1357 /* Use _WaitFlagNotSupported because we don't know what to tell the caller. */
1358 waitResult = ProcessWaitResult_WaitFlagNotSupported;
1359 }
1360 }
1361 }
1362
1363#ifdef DEBUG
1364 LogFlowFunc(("oldStatus=%RU32, newStatus=%RU32, fWaitFlags=0x%x, waitResult=%RU32\n",
1365 oldStatus, newStatus, fWaitFlags, waitResult));
1366#endif
1367 return waitResult;
1368}
1369
1370ProcessWaitResult_T GuestProcess::i_waitFlagsToResult(uint32_t fWaitFlags)
1371{
1372 AssertPtr(mSession);
1373 return GuestProcess::i_waitFlagsToResultEx(fWaitFlags,
1374 mData.mStatus /* curStatus */, mData.mStatus /* newStatus */,
1375 mData.mProcess.mFlags, mSession->i_getProtocolVersion());
1376}
1377
1378int GuestProcess::i_waitFor(uint32_t fWaitFlags, ULONG uTimeoutMS,
1379 ProcessWaitResult_T &waitResult, int *pGuestRc)
1380{
1381 AssertReturn(fWaitFlags, VERR_INVALID_PARAMETER);
1382
1383 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1384
1385 LogFlowThisFunc(("fWaitFlags=0x%x, uTimeoutMS=%RU32, procStatus=%RU32, procRc=%Rrc, pGuestRc=%p\n",
1386 fWaitFlags, uTimeoutMS, mData.mStatus, mData.mLastError, pGuestRc));
1387
1388 /* Did some error occur before? Then skip waiting and return. */
1389 ProcessStatus_T curStatus = mData.mStatus;
1390 if (curStatus == ProcessStatus_Error)
1391 {
1392 waitResult = ProcessWaitResult_Error;
1393 AssertMsg(RT_FAILURE(mData.mLastError),
1394 ("No error rc (%Rrc) set when guest process indicated an error\n", mData.mLastError));
1395 if (pGuestRc)
1396 *pGuestRc = mData.mLastError; /* Return last set error. */
1397 LogFlowThisFunc(("Process is in error state (guestRc=%Rrc)\n", mData.mLastError));
1398 return VERR_GSTCTL_GUEST_ERROR;
1399 }
1400
1401 waitResult = i_waitFlagsToResult(fWaitFlags);
1402
1403 /* No waiting needed? Return immediately using the last set error. */
1404 if (waitResult != ProcessWaitResult_None)
1405 {
1406 if (pGuestRc)
1407 *pGuestRc = mData.mLastError; /* Return last set error (if any). */
1408 LogFlowThisFunc(("Nothing to wait for (guestRc=%Rrc)\n", mData.mLastError));
1409 return RT_SUCCESS(mData.mLastError) ? VINF_SUCCESS : VERR_GSTCTL_GUEST_ERROR;
1410 }
1411
1412 /* Adjust timeout. Passing 0 means RT_INDEFINITE_WAIT. */
1413 if (!uTimeoutMS)
1414 uTimeoutMS = RT_INDEFINITE_WAIT;
1415
1416 int vrc;
1417
1418 GuestWaitEvent *pEvent = NULL;
1419 GuestEventTypes eventTypes;
1420 try
1421 {
1422 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1423
1424 vrc = registerWaitEvent(eventTypes, &pEvent);
1425 }
1426 catch (std::bad_alloc)
1427 {
1428 vrc = VERR_NO_MEMORY;
1429 }
1430
1431 if (RT_FAILURE(vrc))
1432 return vrc;
1433
1434 alock.release(); /* Release lock before waiting. */
1435
1436 /*
1437 * Do the actual waiting.
1438 */
1439 ProcessStatus_T newStatus = ProcessStatus_Undefined;
1440 uint64_t u64StartMS = RTTimeMilliTS();
1441 for (;;)
1442 {
1443 uint64_t u64ElapsedMS = RTTimeMilliTS() - u64StartMS;
1444 if ( uTimeoutMS != RT_INDEFINITE_WAIT
1445 && u64ElapsedMS >= uTimeoutMS)
1446 {
1447 vrc = VERR_TIMEOUT;
1448 break;
1449 }
1450
1451 vrc = i_waitForStatusChange(pEvent,
1452 uTimeoutMS == RT_INDEFINITE_WAIT
1453 ? RT_INDEFINITE_WAIT : uTimeoutMS - (uint32_t)u64ElapsedMS,
1454 &newStatus, pGuestRc);
1455 if (RT_SUCCESS(vrc))
1456 {
1457 alock.acquire();
1458
1459 waitResult = i_waitFlagsToResultEx(fWaitFlags, curStatus, newStatus,
1460 mData.mProcess.mFlags, mSession->i_getProtocolVersion());
1461#ifdef DEBUG
1462 LogFlowThisFunc(("Got new status change: fWaitFlags=0x%x, newStatus=%RU32, waitResult=%RU32\n",
1463 fWaitFlags, newStatus, waitResult));
1464#endif
1465 if (ProcessWaitResult_None != waitResult) /* We got a waiting result. */
1466 break;
1467 }
1468 else /* Waiting failed, bail out. */
1469 break;
1470
1471 alock.release(); /* Don't hold lock in next waiting round. */
1472 }
1473
1474 unregisterWaitEvent(pEvent);
1475
1476 LogFlowThisFunc(("Returned waitResult=%RU32, newStatus=%RU32, rc=%Rrc\n",
1477 waitResult, newStatus, vrc));
1478 return vrc;
1479}
1480
1481int GuestProcess::i_waitForInputNotify(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS,
1482 ProcessInputStatus_T *pInputStatus, uint32_t *pcbProcessed)
1483{
1484 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1485
1486 VBoxEventType_T evtType;
1487 ComPtr<IEvent> pIEvent;
1488 int vrc = waitForEvent(pEvent, uTimeoutMS,
1489 &evtType, pIEvent.asOutParam());
1490 if (RT_SUCCESS(vrc))
1491 {
1492 if (evtType == VBoxEventType_OnGuestProcessInputNotify)
1493 {
1494 ComPtr<IGuestProcessInputNotifyEvent> pProcessEvent = pIEvent;
1495 Assert(!pProcessEvent.isNull());
1496
1497 if (pInputStatus)
1498 {
1499 HRESULT hr2 = pProcessEvent->COMGETTER(Status)(pInputStatus);
1500 ComAssertComRC(hr2);
1501 }
1502 if (pcbProcessed)
1503 {
1504 HRESULT hr2 = pProcessEvent->COMGETTER(Processed)((ULONG*)pcbProcessed);
1505 ComAssertComRC(hr2);
1506 }
1507 }
1508 else
1509 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1510 }
1511
1512 LogFlowThisFunc(("Returning pEvent=%p, uHandle=%RU32, rc=%Rrc\n",
1513 pEvent, uHandle, vrc));
1514 return vrc;
1515}
1516
1517int GuestProcess::i_waitForOutput(GuestWaitEvent *pEvent, uint32_t uHandle, uint32_t uTimeoutMS,
1518 void *pvData, size_t cbData, uint32_t *pcbRead)
1519{
1520 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1521 /* pvData is optional. */
1522 /* cbData is optional. */
1523 /* pcbRead is optional. */
1524
1525 LogFlowThisFunc(("cEventTypes=%zu, pEvent=%p, uHandle=%RU32, uTimeoutMS=%RU32, pvData=%p, cbData=%zu, pcbRead=%p\n",
1526 pEvent->TypeCount(), pEvent, uHandle, uTimeoutMS, pvData, cbData, pcbRead));
1527
1528 int vrc;
1529
1530 VBoxEventType_T evtType;
1531 ComPtr<IEvent> pIEvent;
1532 do
1533 {
1534 vrc = waitForEvent(pEvent, uTimeoutMS,
1535 &evtType, pIEvent.asOutParam());
1536 if (RT_SUCCESS(vrc))
1537 {
1538 if (evtType == VBoxEventType_OnGuestProcessOutput)
1539 {
1540 ComPtr<IGuestProcessOutputEvent> pProcessEvent = pIEvent;
1541 Assert(!pProcessEvent.isNull());
1542
1543 ULONG uHandleEvent;
1544 HRESULT hr = pProcessEvent->COMGETTER(Handle)(&uHandleEvent);
1545 if ( SUCCEEDED(hr)
1546 && uHandleEvent == uHandle)
1547 {
1548 if (pvData)
1549 {
1550 com::SafeArray <BYTE> data;
1551 hr = pProcessEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
1552 ComAssertComRC(hr);
1553 size_t cbRead = data.size();
1554 if (cbRead)
1555 {
1556 if (cbRead <= cbData)
1557 {
1558 /* Copy data from event into our buffer. */
1559 memcpy(pvData, data.raw(), data.size());
1560 }
1561 else
1562 vrc = VERR_BUFFER_OVERFLOW;
1563
1564 LogFlowThisFunc(("Read %zu bytes (uHandle=%RU32), rc=%Rrc\n",
1565 cbRead, uHandleEvent, vrc));
1566 }
1567 }
1568
1569 if ( RT_SUCCESS(vrc)
1570 && pcbRead)
1571 {
1572 ULONG cbRead;
1573 hr = pProcessEvent->COMGETTER(Processed)(&cbRead);
1574 ComAssertComRC(hr);
1575 *pcbRead = (uint32_t)cbRead;
1576 }
1577
1578 break;
1579 }
1580 else if (FAILED(hr))
1581 vrc = VERR_COM_UNEXPECTED;
1582 }
1583 else
1584 vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
1585 }
1586
1587 } while (vrc == VINF_SUCCESS);
1588
1589 if ( vrc != VINF_SUCCESS
1590 && pcbRead)
1591 {
1592 *pcbRead = 0;
1593 }
1594
1595 LogFlowFuncLeaveRC(vrc);
1596 return vrc;
1597}
1598
1599int GuestProcess::i_waitForStatusChange(GuestWaitEvent *pEvent, uint32_t uTimeoutMS,
1600 ProcessStatus_T *pProcessStatus, int *pGuestRc)
1601{
1602 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
1603 /* pProcessStatus is optional. */
1604 /* pGuestRc is optional. */
1605
1606 VBoxEventType_T evtType;
1607 ComPtr<IEvent> pIEvent;
1608 int vrc = waitForEvent(pEvent, uTimeoutMS,
1609 &evtType, pIEvent.asOutParam());
1610 if (RT_SUCCESS(vrc))
1611 {
1612 Assert(evtType == VBoxEventType_OnGuestProcessStateChanged);
1613 ComPtr<IGuestProcessStateChangedEvent> pProcessEvent = pIEvent;
1614 Assert(!pProcessEvent.isNull());
1615
1616 ProcessStatus_T procStatus;
1617 HRESULT hr = pProcessEvent->COMGETTER(Status)(&procStatus);
1618 ComAssertComRC(hr);
1619 if (pProcessStatus)
1620 *pProcessStatus = procStatus;
1621
1622 ComPtr<IVirtualBoxErrorInfo> errorInfo;
1623 hr = pProcessEvent->COMGETTER(Error)(errorInfo.asOutParam());
1624 ComAssertComRC(hr);
1625
1626 LONG lGuestRc;
1627 hr = errorInfo->COMGETTER(ResultDetail)(&lGuestRc);
1628 ComAssertComRC(hr);
1629
1630 LogFlowThisFunc(("Got procStatus=%RU32, guestRc=%RI32 (%Rrc)\n",
1631 procStatus, lGuestRc, lGuestRc));
1632
1633 if (RT_FAILURE((int)lGuestRc))
1634 vrc = VERR_GSTCTL_GUEST_ERROR;
1635
1636 if (pGuestRc)
1637 *pGuestRc = (int)lGuestRc;
1638 }
1639
1640 LogFlowFuncLeaveRC(vrc);
1641 return vrc;
1642}
1643
1644/* static */
1645bool GuestProcess::i_waitResultImpliesEx(ProcessWaitResult_T waitResult,
1646 ProcessStatus_T procStatus, uint32_t uProcFlags,
1647 uint32_t uProtocol)
1648{
1649 bool fImplies;
1650
1651 switch (waitResult)
1652 {
1653 case ProcessWaitResult_Start:
1654 fImplies = procStatus == ProcessStatus_Started;
1655 break;
1656
1657 case ProcessWaitResult_Terminate:
1658 fImplies = ( procStatus == ProcessStatus_TerminatedNormally
1659 || procStatus == ProcessStatus_TerminatedSignal
1660 || procStatus == ProcessStatus_TerminatedAbnormally
1661 || procStatus == ProcessStatus_TimedOutKilled
1662 || procStatus == ProcessStatus_TimedOutAbnormally
1663 || procStatus == ProcessStatus_Down
1664 || procStatus == ProcessStatus_Error);
1665 break;
1666
1667 default:
1668 fImplies = false;
1669 break;
1670 }
1671
1672 return fImplies;
1673}
1674
1675int GuestProcess::i_writeData(uint32_t uHandle, uint32_t uFlags,
1676 void *pvData, size_t cbData, uint32_t uTimeoutMS, uint32_t *puWritten, int *pGuestRc)
1677{
1678 LogFlowThisFunc(("uPID=%RU32, uHandle=%RU32, uFlags=%RU32, pvData=%p, cbData=%RU32, uTimeoutMS=%RU32, puWritten=%p, pGuestRc=%p\n",
1679 mData.mPID, uHandle, uFlags, pvData, cbData, uTimeoutMS, puWritten, pGuestRc));
1680 /* All is optional. There can be 0 byte writes. */
1681 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1682
1683 if (mData.mStatus != ProcessStatus_Started)
1684 {
1685 if (puWritten)
1686 *puWritten = 0;
1687 if (pGuestRc)
1688 *pGuestRc = VINF_SUCCESS;
1689 return VINF_SUCCESS; /* Not available for writing (anymore). */
1690 }
1691
1692 int vrc;
1693
1694 GuestWaitEvent *pEvent = NULL;
1695 GuestEventTypes eventTypes;
1696 try
1697 {
1698 /*
1699 * On Guest Additions < 4.3 there is no guarantee that the process status
1700 * change arrives *after* the input event, e.g. if this was the last input
1701 * block being written and the process will report status "terminate".
1702 * So just skip checking for process status change and only wait for the
1703 * input event.
1704 */
1705 if (mSession->i_getProtocolVersion() >= 2)
1706 eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
1707 eventTypes.push_back(VBoxEventType_OnGuestProcessInputNotify);
1708
1709 vrc = registerWaitEvent(eventTypes, &pEvent);
1710 }
1711 catch (std::bad_alloc)
1712 {
1713 vrc = VERR_NO_MEMORY;
1714 }
1715
1716 if (RT_FAILURE(vrc))
1717 return vrc;
1718
1719 VBOXHGCMSVCPARM paParms[5];
1720 int i = 0;
1721 paParms[i++].setUInt32(pEvent->ContextID());
1722 paParms[i++].setUInt32(mData.mPID);
1723 paParms[i++].setUInt32(uFlags);
1724 paParms[i++].setPointer(pvData, (uint32_t)cbData);
1725 paParms[i++].setUInt32((uint32_t)cbData);
1726
1727 alock.release(); /* Drop the write lock before sending. */
1728
1729 uint32_t cbProcessed = 0;
1730 vrc = sendCommand(HOST_EXEC_SET_INPUT, i, paParms);
1731 if (RT_SUCCESS(vrc))
1732 {
1733 ProcessInputStatus_T inputStatus;
1734 vrc = i_waitForInputNotify(pEvent, uHandle, uTimeoutMS,
1735 &inputStatus, &cbProcessed);
1736 if (RT_SUCCESS(vrc))
1737 {
1738 /** @todo Set guestRc. */
1739
1740 if (puWritten)
1741 *puWritten = cbProcessed;
1742 }
1743 /** @todo Error handling. */
1744 }
1745
1746 unregisterWaitEvent(pEvent);
1747
1748 LogFlowThisFunc(("Returning cbProcessed=%RU32, rc=%Rrc\n",
1749 cbProcessed, vrc));
1750 return vrc;
1751}
1752
1753// implementation of public methods
1754/////////////////////////////////////////////////////////////////////////////
1755
1756HRESULT GuestProcess::read(ULONG aHandle, ULONG aToRead, ULONG aTimeoutMS, std::vector<BYTE> &aData)
1757{
1758#ifndef VBOX_WITH_GUEST_CONTROL
1759 ReturnComNotImplemented();
1760#else
1761 LogFlowThisFuncEnter();
1762
1763 if (aToRead == 0)
1764 return setError(E_INVALIDARG, tr("The size to read is zero"));
1765
1766 aData.resize(aToRead);
1767
1768 HRESULT hr = S_OK;
1769
1770 uint32_t cbRead; int guestRc;
1771 int vrc = i_readData(aHandle, aToRead, aTimeoutMS, &aData.front(), aToRead, &cbRead, &guestRc);
1772 if (RT_SUCCESS(vrc))
1773 {
1774 if (aData.size() != cbRead)
1775 aData.resize(cbRead);
1776 }
1777 else
1778 {
1779 aData.resize(0);
1780
1781 switch (vrc)
1782 {
1783 case VERR_GSTCTL_GUEST_ERROR:
1784 hr = GuestProcess::i_setErrorExternal(this, guestRc);
1785 break;
1786
1787 default:
1788 hr = setError(VBOX_E_IPRT_ERROR,
1789 tr("Reading from process \"%s\" (PID %RU32) failed: %Rrc"),
1790 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
1791 break;
1792 }
1793 }
1794
1795 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU32\n", vrc, cbRead));
1796
1797 LogFlowFuncLeaveRC(vrc);
1798 return hr;
1799#endif /* VBOX_WITH_GUEST_CONTROL */
1800}
1801
1802HRESULT GuestProcess::terminate()
1803{
1804#ifndef VBOX_WITH_GUEST_CONTROL
1805 ReturnComNotImplemented();
1806#else
1807
1808 HRESULT hr = S_OK;
1809
1810 int guestRc;
1811 int vrc = i_terminateProcess(30 * 1000 /* Timeout in ms */,
1812 &guestRc);
1813 if (RT_FAILURE(vrc))
1814 {
1815 switch (vrc)
1816 {
1817 case VERR_GSTCTL_GUEST_ERROR:
1818 hr = GuestProcess::i_setErrorExternal(this, guestRc);
1819 break;
1820
1821 case VERR_NOT_SUPPORTED:
1822 hr = setError(VBOX_E_IPRT_ERROR,
1823 tr("Terminating process \"%s\" (PID %RU32) not supported by installed Guest Additions"),
1824 mData.mProcess.mExecutable.c_str(), mData.mPID);
1825 break;
1826
1827 default:
1828 hr = setError(VBOX_E_IPRT_ERROR,
1829 tr("Terminating process \"%s\" (PID %RU32) failed: %Rrc"),
1830 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
1831 break;
1832 }
1833 }
1834
1835 /* Remove process from guest session list. Now only API clients
1836 * still can hold references to it. */
1837 AssertPtr(mSession);
1838 int rc2 = mSession->i_processRemoveFromList(this);
1839 if (RT_SUCCESS(vrc))
1840 vrc = rc2;
1841
1842 LogFlowFuncLeaveRC(vrc);
1843 return hr;
1844#endif /* VBOX_WITH_GUEST_CONTROL */
1845}
1846
1847HRESULT GuestProcess::waitFor(ULONG aWaitFor,
1848 ULONG aTimeoutMS,
1849 ProcessWaitResult_T *aReason)
1850{
1851#ifndef VBOX_WITH_GUEST_CONTROL
1852 ReturnComNotImplemented();
1853#else
1854
1855 /*
1856 * Note: Do not hold any locks here while waiting!
1857 */
1858 HRESULT hr = S_OK;
1859
1860 int guestRc;
1861 ProcessWaitResult_T waitResult;
1862 int vrc = i_waitFor(aWaitFor, aTimeoutMS, waitResult, &guestRc);
1863 if (RT_SUCCESS(vrc))
1864 {
1865 *aReason = waitResult;
1866 }
1867 else
1868 {
1869 switch (vrc)
1870 {
1871 case VERR_GSTCTL_GUEST_ERROR:
1872 hr = GuestProcess::i_setErrorExternal(this, guestRc);
1873 break;
1874
1875 case VERR_TIMEOUT:
1876 *aReason = ProcessWaitResult_Timeout;
1877 break;
1878
1879 default:
1880 hr = setError(VBOX_E_IPRT_ERROR,
1881 tr("Waiting for process \"%s\" (PID %RU32) failed: %Rrc"),
1882 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
1883 break;
1884 }
1885 }
1886
1887 LogFlowFuncLeaveRC(vrc);
1888 return hr;
1889#endif /* VBOX_WITH_GUEST_CONTROL */
1890}
1891
1892HRESULT GuestProcess::waitForArray(const std::vector<ProcessWaitForFlag_T> &aWaitFor,
1893 ULONG aTimeoutMS, ProcessWaitResult_T *aReason)
1894{
1895#ifndef VBOX_WITH_GUEST_CONTROL
1896 ReturnComNotImplemented();
1897#else
1898 /*
1899 * Note: Do not hold any locks here while waiting!
1900 */
1901 uint32_t fWaitFor = ProcessWaitForFlag_None;
1902 for (size_t i = 0; i < aWaitFor.size(); i++)
1903 fWaitFor |= aWaitFor[i];
1904
1905 return WaitFor(fWaitFor, aTimeoutMS, aReason);
1906#endif /* VBOX_WITH_GUEST_CONTROL */
1907}
1908
1909HRESULT GuestProcess::write(ULONG aHandle, ULONG aFlags, const std::vector<BYTE> &aData,
1910 ULONG aTimeoutMS, ULONG *aWritten)
1911{
1912#ifndef VBOX_WITH_GUEST_CONTROL
1913 ReturnComNotImplemented();
1914#else
1915 LogFlowThisFuncEnter();
1916
1917 HRESULT hr = S_OK;
1918
1919 uint32_t cbWritten; int guestRc;
1920 uint32_t cbData = (uint32_t)aData.size();
1921 void *pvData = cbData > 0? (void *)&aData.front(): NULL;
1922 int vrc = i_writeData(aHandle, aFlags, pvData, cbData, aTimeoutMS, &cbWritten, &guestRc);
1923 if (RT_FAILURE(vrc))
1924 {
1925 switch (vrc)
1926 {
1927 case VERR_GSTCTL_GUEST_ERROR:
1928 hr = GuestProcess::i_setErrorExternal(this, guestRc);
1929 break;
1930
1931 default:
1932 hr = setError(VBOX_E_IPRT_ERROR,
1933 tr("Writing to process \"%s\" (PID %RU32) failed: %Rrc"),
1934 mData.mProcess.mExecutable.c_str(), mData.mPID, vrc);
1935 break;
1936 }
1937 }
1938
1939 LogFlowThisFunc(("rc=%Rrc, aWritten=%RU32\n", vrc, cbWritten));
1940
1941 *aWritten = (ULONG)cbWritten;
1942
1943 LogFlowFuncLeaveRC(vrc);
1944 return hr;
1945#endif /* VBOX_WITH_GUEST_CONTROL */
1946}
1947
1948HRESULT GuestProcess::writeArray(ULONG aHandle, const std::vector<ProcessInputFlag_T> &aFlags,
1949 const std::vector<BYTE> &aData, ULONG aTimeoutMS, ULONG *aWritten)
1950{
1951#ifndef VBOX_WITH_GUEST_CONTROL
1952 ReturnComNotImplemented();
1953#else
1954 LogFlowThisFuncEnter();
1955
1956 /*
1957 * Note: Do not hold any locks here while writing!
1958 */
1959 ULONG fWrite = ProcessInputFlag_None;
1960 for (size_t i = 0; i < aFlags.size(); i++)
1961 fWrite |= aFlags[i];
1962
1963 return write(aHandle, fWrite, aData, aTimeoutMS, aWritten);
1964#endif /* VBOX_WITH_GUEST_CONTROL */
1965}
1966
1967///////////////////////////////////////////////////////////////////////////////
1968
1969GuestProcessTool::GuestProcessTool(void)
1970 : pSession(NULL),
1971 pProcess(NULL)
1972{
1973}
1974
1975GuestProcessTool::~GuestProcessTool(void)
1976{
1977 i_terminate(30 * 1000, NULL /* pGuestRc */);
1978}
1979
1980int GuestProcessTool::Init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
1981 bool fAsync, int *pGuestRc)
1982{
1983 LogFlowThisFunc(("pGuestSession=%p, exe=%s, fAsync=%RTbool\n",
1984 pGuestSession, startupInfo.mExecutable.c_str(), fAsync));
1985
1986 AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
1987
1988 pSession = pGuestSession;
1989 mStartupInfo = startupInfo;
1990
1991 /* Make sure the process is hidden. */
1992 mStartupInfo.mFlags |= ProcessCreateFlag_Hidden;
1993
1994 int vrc = pSession->i_processCreateExInternal(mStartupInfo, pProcess);
1995 if (RT_SUCCESS(vrc))
1996 vrc = fAsync
1997 ? pProcess->i_startProcessAsync()
1998 : pProcess->i_startProcess(30 * 1000 /* 30s timeout */, pGuestRc);
1999
2000 if ( RT_SUCCESS(vrc)
2001 && !fAsync
2002 && ( pGuestRc
2003 && RT_FAILURE(*pGuestRc)
2004 )
2005 )
2006 {
2007 vrc = VERR_GSTCTL_GUEST_ERROR;
2008 }
2009
2010 LogFlowFuncLeaveRC(vrc);
2011 return vrc;
2012}
2013
2014int GuestProcessTool::i_getCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock)
2015{
2016 const GuestProcessStream *pStream = NULL;
2017 if (uHandle == OUTPUT_HANDLE_ID_STDOUT)
2018 pStream = &mStdOut;
2019 else if (uHandle == OUTPUT_HANDLE_ID_STDERR)
2020 pStream = &mStdErr;
2021
2022 if (!pStream)
2023 return VERR_INVALID_PARAMETER;
2024
2025 int vrc;
2026 do
2027 {
2028 /* Try parsing the data to see if the current block is complete. */
2029 vrc = mStdOut.ParseBlock(strmBlock);
2030 if (strmBlock.GetCount())
2031 break;
2032 } while (RT_SUCCESS(vrc));
2033
2034 LogFlowThisFunc(("rc=%Rrc, %RU64 pairs\n",
2035 vrc, strmBlock.GetCount()));
2036 return vrc;
2037}
2038
2039bool GuestProcessTool::i_isRunning(void)
2040{
2041 AssertReturn(!pProcess.isNull(), false);
2042
2043 ProcessStatus_T procStatus = ProcessStatus_Undefined;
2044 HRESULT hr = pProcess->COMGETTER(Status(&procStatus));
2045 Assert(SUCCEEDED(hr));
2046
2047 if ( procStatus == ProcessStatus_Started
2048 || procStatus == ProcessStatus_Paused
2049 || procStatus == ProcessStatus_Terminating)
2050 {
2051 return true;
2052 }
2053
2054 return false;
2055}
2056
2057/* static */
2058int GuestProcessTool::i_run( GuestSession *pGuestSession,
2059 const GuestProcessStartupInfo &startupInfo,
2060 int *pGuestRc)
2061{
2062 return i_runEx(pGuestSession, startupInfo,
2063 NULL /* pStrmOutObjects */, 0 /* cStrmOutObjects */,
2064 pGuestRc);
2065}
2066
2067/**
2068 * <Someone write documentation, pretty please!>
2069 *
2070 * @param pGuestRc Optional. Will be set to VINF_SUCCESS,
2071 * VERR_NOT_EQUAL or VERR_INVALID_STATE if the
2072 * process completed. Should it fail earlier that,
2073 * you're feel free to enlighten the rest of us...
2074 */
2075/* static */
2076int GuestProcessTool::i_runEx( GuestSession *pGuestSession,
2077 const GuestProcessStartupInfo &startupInfo,
2078 GuestCtrlStreamObjects *pStrmOutObjects,
2079 uint32_t cStrmOutObjects,
2080 int *pGuestRc)
2081{
2082 GuestProcessTool procTool; int guestRc;
2083 int vrc = procTool.Init(pGuestSession, startupInfo, false /* Async */, &guestRc);
2084 if (RT_SUCCESS(vrc))
2085 {
2086 while (cStrmOutObjects--)
2087 {
2088 try
2089 {
2090 GuestProcessStreamBlock strmBlk;
2091 vrc = procTool.i_waitEx( pStrmOutObjects
2092 ? GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK
2093 : GUESTPROCESSTOOL_FLAG_NONE, &strmBlk, &guestRc);
2094 if (pStrmOutObjects)
2095 pStrmOutObjects->push_back(strmBlk);
2096 }
2097 catch (std::bad_alloc)
2098 {
2099 vrc = VERR_NO_MEMORY;
2100 }
2101 }
2102 }
2103
2104 if (RT_SUCCESS(vrc))
2105 {
2106 /* Make sure the process runs until completion. */
2107 vrc = procTool.i_wait(GUESTPROCESSTOOL_FLAG_NONE, &guestRc);
2108 if (RT_SUCCESS(vrc))
2109 {
2110 guestRc = procTool.i_terminatedOk(NULL /* Exit code */);
2111 if (RT_FAILURE(guestRc))
2112 vrc = VERR_GSTCTL_GUEST_ERROR;
2113 }
2114 }
2115
2116 if (pGuestRc)
2117 *pGuestRc = guestRc;
2118
2119 LogFlowFunc(("Returned rc=%Rrc, guestRc=%Rrc\n", vrc, guestRc));
2120 return vrc;
2121}
2122
2123int GuestProcessTool::i_terminatedOk(LONG *pExitCode)
2124{
2125 Assert(!pProcess.isNull());
2126 /* pExitCode is optional. */
2127
2128 int vrc;
2129 if (!i_isRunning())
2130 {
2131 LONG exitCode;
2132 HRESULT hr = pProcess->COMGETTER(ExitCode(&exitCode));
2133 Assert(SUCCEEDED(hr));
2134
2135 if (pExitCode)
2136 *pExitCode = exitCode;
2137
2138 vrc = (exitCode != 0)
2139 /** @todo Special guest control rc needed! */
2140 ? VERR_NOT_EQUAL : VINF_SUCCESS;
2141 }
2142 else
2143 vrc = VERR_INVALID_STATE; /** @todo Special guest control rc needed! */
2144
2145 LogFlowFuncLeaveRC(vrc);
2146 return vrc;
2147}
2148
2149int GuestProcessTool::i_wait(uint32_t fFlags, int *pGuestRc)
2150{
2151 return i_waitEx(fFlags, NULL /* pStrmBlkOut */, pGuestRc);
2152}
2153
2154int GuestProcessTool::i_waitEx(uint32_t fFlags, GuestProcessStreamBlock *pStrmBlkOut, int *pGuestRc)
2155{
2156 LogFlowThisFunc(("fFlags=0x%x, pStreamBlock=%p, pGuestRc=%p\n",
2157 fFlags, pStrmBlkOut, pGuestRc));
2158
2159 /* Can we parse the next block without waiting? */
2160 int vrc;
2161 if (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK)
2162 {
2163 AssertPtr(pStrmBlkOut);
2164 vrc = i_getCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStrmBlkOut);
2165 if (RT_SUCCESS(vrc))
2166 return vrc;
2167 /* else do the the waiting below. */
2168 }
2169
2170 /* Do the waiting. */
2171 uint32_t fWaitFlags = ProcessWaitForFlag_Terminate;
2172 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdOut)
2173 fWaitFlags |= ProcessWaitForFlag_StdOut;
2174 if (mStartupInfo.mFlags & ProcessCreateFlag_WaitForStdErr)
2175 fWaitFlags |= ProcessWaitForFlag_StdErr;
2176
2177 /** @todo Decrease timeout while running. */
2178 uint64_t u64StartMS = RTTimeMilliTS();
2179 uint32_t uTimeoutMS = mStartupInfo.mTimeoutMS;
2180
2181 int guestRc;
2182 bool fDone = false;
2183
2184 BYTE byBuf[_64K];
2185 uint32_t cbRead;
2186
2187 bool fHandleStdOut = false;
2188 bool fHandleStdErr = false;
2189
2190 /**
2191 * Updates the elapsed time and checks if a
2192 * timeout happened, then breaking out of the loop.
2193 */
2194#define UPDATE_AND_CHECK_ELAPSED_TIME() \
2195 u64ElapsedMS = RTTimeMilliTS() - u64StartMS; \
2196 if ( uTimeoutMS != RT_INDEFINITE_WAIT \
2197 && u64ElapsedMS >= uTimeoutMS) \
2198 { \
2199 vrc = VERR_TIMEOUT; \
2200 break; \
2201 }
2202
2203 /**
2204 * Returns the remaining time (in ms).
2205 */
2206#define GET_REMAINING_TIME \
2207 uTimeoutMS == RT_INDEFINITE_WAIT \
2208 ? RT_INDEFINITE_WAIT : uTimeoutMS - (uint32_t)u64ElapsedMS \
2209
2210 ProcessWaitResult_T waitRes;
2211 do
2212 {
2213 uint64_t u64ElapsedMS;
2214 UPDATE_AND_CHECK_ELAPSED_TIME();
2215
2216 vrc = pProcess->i_waitFor(fWaitFlags, GET_REMAINING_TIME,
2217 waitRes, &guestRc);
2218 if (RT_FAILURE(vrc))
2219 break;
2220
2221 switch (waitRes)
2222 {
2223 case ProcessWaitResult_StdIn:
2224 vrc = VERR_NOT_IMPLEMENTED;
2225 break;
2226
2227 case ProcessWaitResult_StdOut:
2228 fHandleStdOut = true;
2229 break;
2230
2231 case ProcessWaitResult_StdErr:
2232 fHandleStdErr = true;
2233 break;
2234
2235 case ProcessWaitResult_WaitFlagNotSupported:
2236 if (fWaitFlags & ProcessWaitForFlag_StdOut)
2237 fHandleStdOut = true;
2238 if (fWaitFlags & ProcessWaitForFlag_StdErr)
2239 fHandleStdErr = true;
2240 /* Since waiting for stdout / stderr is not supported by the guest,
2241 * wait a bit to not hog the CPU too much when polling for data. */
2242 RTThreadSleep(1); /* Optional, don't check rc. */
2243 break;
2244
2245 case ProcessWaitResult_Error:
2246 vrc = VERR_GSTCTL_GUEST_ERROR;
2247 break;
2248
2249 case ProcessWaitResult_Terminate:
2250 fDone = true;
2251 break;
2252
2253 case ProcessWaitResult_Timeout:
2254 vrc = VERR_TIMEOUT;
2255 break;
2256
2257 case ProcessWaitResult_Start:
2258 case ProcessWaitResult_Status:
2259 /* Not used here, just skip. */
2260 break;
2261
2262 default:
2263 AssertMsgFailed(("Unhandled process wait result %RU32\n", waitRes));
2264 break;
2265 }
2266
2267 if (RT_FAILURE(vrc))
2268 break;
2269
2270 if (fHandleStdOut)
2271 {
2272 UPDATE_AND_CHECK_ELAPSED_TIME();
2273
2274 cbRead = 0;
2275 vrc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
2276 GET_REMAINING_TIME,
2277 byBuf, sizeof(byBuf),
2278 &cbRead, &guestRc);
2279 if ( RT_FAILURE(vrc)
2280 || vrc == VWRN_GSTCTL_OBJECTSTATE_CHANGED)
2281 break;
2282
2283 if (cbRead)
2284 {
2285 LogFlowThisFunc(("Received %RU32 bytes from stdout\n", cbRead));
2286 vrc = mStdOut.AddData(byBuf, cbRead);
2287
2288 if ( RT_SUCCESS(vrc)
2289 && (fFlags & GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK))
2290 {
2291 AssertPtr(pStrmBlkOut);
2292 vrc = i_getCurrentBlock(OUTPUT_HANDLE_ID_STDOUT, *pStrmBlkOut);
2293
2294 /* When successful, break out of the loop because we're done
2295 * with reading the first stream block. */
2296 if (RT_SUCCESS(vrc))
2297 fDone = true;
2298 }
2299 }
2300
2301 fHandleStdOut = false;
2302 }
2303
2304 if (fHandleStdErr)
2305 {
2306 UPDATE_AND_CHECK_ELAPSED_TIME();
2307
2308 cbRead = 0;
2309 vrc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDERR, sizeof(byBuf),
2310 GET_REMAINING_TIME,
2311 byBuf, sizeof(byBuf),
2312 &cbRead, &guestRc);
2313 if ( RT_FAILURE(vrc)
2314 || vrc == VWRN_GSTCTL_OBJECTSTATE_CHANGED)
2315 break;
2316
2317 if (cbRead)
2318 {
2319 LogFlowThisFunc(("Received %RU32 bytes from stderr\n", cbRead));
2320 vrc = mStdErr.AddData(byBuf, cbRead);
2321 }
2322
2323 fHandleStdErr = false;
2324 }
2325
2326 } while (!fDone && RT_SUCCESS(vrc));
2327
2328#undef UPDATE_AND_CHECK_ELAPSED_TIME
2329#undef GET_REMAINING_TIME
2330
2331 if (RT_FAILURE(guestRc))
2332 vrc = VERR_GSTCTL_GUEST_ERROR;
2333
2334 LogFlowThisFunc(("Loop ended with rc=%Rrc, guestRc=%Rrc, waitRes=%RU32\n",
2335 vrc, guestRc, waitRes));
2336 if (pGuestRc)
2337 *pGuestRc = guestRc;
2338
2339 LogFlowFuncLeaveRC(vrc);
2340 return vrc;
2341}
2342
2343int GuestProcessTool::i_terminate(uint32_t uTimeoutMS, int *pGuestRc)
2344{
2345 LogFlowThisFuncEnter();
2346
2347 int rc = VINF_SUCCESS;
2348 if (!pProcess.isNull())
2349 {
2350 rc = pProcess->i_terminateProcess(uTimeoutMS, pGuestRc);
2351 pProcess.setNull();
2352 }
2353 else
2354 rc = VERR_NOT_FOUND;
2355
2356 LogFlowFuncLeaveRC(rc);
2357 return rc;
2358}
2359
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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