GuestCtrlImpl.cpp revision 038fb20139baee46969c6aa2521d6bd18c5d263d
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * VirtualBox COM class implementation: Guest
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Copyright (C) 2006-2011 Oracle Corporation
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * available from http://www.virtualbox.org. This file is free software;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * you can redistribute it and/or modify it under the terms of the GNU
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * General Public License (GPL) as published by the Free Software
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync// public methods only for internal purposes
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/////////////////////////////////////////////////////////////////////////////
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Appends environment variables to the environment block.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Each var=value pair is separated by the null character ('\\0'). The whole
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * block will be stored in one blob and disassembled on the guest side later to
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * fit into the HGCM param structure.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @returns VBox status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pszEnvVar The environment variable=value to append to the
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * environment block.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param ppvList This is actually a pointer to a char pointer
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * variable which keeps track of the environment block
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * that we're constructing.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pcbList Pointer to the variable holding the current size of
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * the environment block. (List is a misnomer, go
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * ahead a be confused.)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pcEnvVars Pointer to the variable holding count of variables
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * stored in the environment block.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnvVars)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t cchEnv = strlen(pszEnv); Assert(cchEnv >= 2);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t cbNewLen = *pcbList + cchEnv + 1; /* Include zero termination. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync char *pvTmp = (char *)RTMemRealloc(*ppvList, cbNewLen);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Reset counters. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *pcbList += cchEnv + 1; /* Include zero termination. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *pcEnvVars += 1; /* Increase env variable count. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Adds a callback with a user provided data block and an optional progress object
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * to the callback map. A callback is identified by a unique context ID which is used
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * to identify a callback from the guest side.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pCallback
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param puContextID
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Guest::callbackAdd(const PVBOXGUESTCTRL_CALLBACK pCallback, uint32_t *puContextID)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertPtrReturn(pCallback, VERR_INVALID_PARAMETER);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* puContextID is optional. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Create a new context ID and assign it. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Create a new context ID ... */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Is the context ID already used? Try next ID ... */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Callback with context ID was not found. This means
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * we can use this context ID for our new callback we want
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * to add below. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Add callback with new context ID to our callback map. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Report back new context ID. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Destroys the formerly allocated callback data. The callback then
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * needs to get removed from the callback map via callbackRemove().
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Does not do locking!
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param uContextID
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CallbackMapIter it = mCallbackMap.find(uContextID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("Callback with CID=%u found\n", uContextID));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("Destroying callback with CID=%u ...\n", uContextID));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Removes a callback from the callback map.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Does not do locking!
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param uContextID
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CallbackMapIter it = mCallbackMap.find(uContextID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Guest::callbackGetUserData(uint32_t uContextID, eVBoxGuestCtrlCallbackType *pEnmType,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* pEnmType is optional. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* ppvData is optional. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* pcbData is optional. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CallbackMapIterConst it = mCallbackMap.find(uContextID);
if ( ppvData
if (pcbData)
return VINF_SUCCESS;
if (pcbData)
return NULL;
switch (enmType)
PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS));
return vrc;
if (pProgress)
&& !fCanceled)
if (pProgress)
&& fCompleted)
if (pProgress)
return VERR_CANCELLED;
return VINF_SUCCESS;
return VERR_NOT_FOUND;
&& fCanceled)
return VINF_SUCCESS;
if (pProgress)
&& !fCompleted)
* cancel won't work!). This could happen if the client thread (e.g. VBoxService, thread of a spawned process)
return S_OK;
return vrc;
if (lStage < 0)
return vrc;
void *pvParms,
using namespace guestControl;
#ifdef DEBUG_andy
switch (u32Function)
case GUEST_DISCONNECTED:
PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms);
AssertReturn(CALLBACKDATAMAGIC_CLIENT_DISCONNECTED == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
case GUEST_EXEC_SEND_STATUS:
case GUEST_EXEC_SEND_OUTPUT:
return rc;
/* Function for handling the execution start/termination notification. */
if (pCallbackData)
if (!fCanceled)
case PROC_STS_TES:
case PROC_STS_TOK:
case PROC_STS_STARTED:
case PROC_STS_TOK:
LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */
case PROC_STS_TOA:
LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */
case PROC_STS_DWN:
LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
* even if the executed process was killed because the system/VBoxService is shutting down.
case PROC_STS_ERROR:
case VERR_MAX_PROCS_REACHED:
LogRel(("Guest process could not be started because maximum number of parallel guest processes has been reached\n"));
return vrc;
if (pCallbackData)
int vrc;
return vrc;
if (pCallbackData)
* after the process was marked as exited/terminated.
* exited/terminated.
bool fRemove)
if (pProcess)
/* If the is marked as stopped/terminated
if ( fRemove
return VINF_SUCCESS;
return VERR_NOT_FOUND;
int Guest::processSetStatus(uint32_t u32PID, ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
return VINF_SUCCESS;
return hRC;
return hRC;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
#ifdef VBOX_WITH_GUEST_CONTROL
if (uFlagsToAdd)
bool fWaitForOutput = false;
&& pObjStdOut)
&& pObjStdErr))
fWaitForOutput = true;
&& fWaitForOutput)
&& !fCompleted)
if (fCanceled)
&& pObjStdOut)
&& pObjStdErr)
if (aProgress)
if (aPID)
return rc;
case PROC_STS_STARTED:
case PROC_STS_TOK:
case PROC_STS_TOA:
case PROC_STS_DWN:
case PROC_STS_ERROR:
return rc;
return rc;
return rc;
int rc;
bool fDrainStream = true;
if (fDrainStream)
cPairs = 0;
fDrainStream = false;
while (!cPairs);
return rc;
int rc;
return rc;
HRESULT Guest::executeStreamParse(ULONG ulPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects)
return rc;
&& fCanceled)
return E_ABORT;
&& !fCompleted)
: uTimeoutMS);
rc);
return hRC;
if (pRetStatus)
if (puRetExitCode)
return rc;
using namespace guestControl;
if (pRC)
TRUE,
if (aTimeoutMS == 0)
if (aArguments)
if (uNumArgs > 0)
if (aEnvironment)
if (pVMMDev)
i, paParms);
for (unsigned i = 0; i < uNumArgs; i++)
if (pRC)
return rc;
STDMETHODIMP Guest::SetProcessInput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten)
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
if (aFlags)
if (aTimeoutMS == 0)
if (pVMMDev)
i, paParms);
case INPUT_STS_WRITTEN:
case INPUT_STS_ERROR:
case INPUT_STS_TERMINATED:
case INPUT_STS_OVERFLOW:
return rc;
STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData))
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
if (aSize < 0)
if (aSize == 0)
if (aFlags)
if (aTimeoutMS == 0)
if (pVMMDev)
i, paParms);
if (pRC)
return rc;
STDMETHODIMP Guest::GetProcessStatus(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ExecuteProcessStatus_T *aStatus)
#ifndef VBOX_WITH_GUEST_CONTROL
if (aExitCode)
if (aFlags)
if (aStatus)
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
if (aFlags)
return rc;