GuestCtrlImpl.cpp revision 03ebf396b0388dc686de9f9dc04181967327981b
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * VirtualBox COM class implementation: Guest
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2010 Oracle Corporation
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * available from http://www.virtualbox.org. This file is free software;
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * you can redistribute it and/or modify it under the terms of the GNU
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * General Public License (GPL) as published by the Free Software
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync /** Copies a file to the guest. */
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync /** Update Guest Additions by directly copying the required installer
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * off the .ISO file, transfer it to the guest and execute the installer
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync * with system privileges. */
c65add61051de67a4d9c78f29702ec4818ea9b5fvboxsync TaskGuest(TaskType aTaskType, Guest *aThat, Progress *aProgress)
~TaskGuest() {}
int startThread();
static HRESULT setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, const char * pszText, ...);
static HRESULT setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest);
return vrc;
#ifdef VBOX_WITH_GUEST_CONTROL
return VINF_SUCCESS;
if (pTask &&
if (fCanceled)
return VINF_SUCCESS;
HRESULT Guest::TaskGuest::setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, const char *pszText, ...)
&& !fCanceled
&& !fCompleted)
va);
return hr2;
return S_OK;
HRESULT Guest::TaskGuest::setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest)
#ifdef VBOX_WITH_GUEST_CONTROL
if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", aTask->strDest.c_str()) <= sizeof(szOutput) - 1)
args.push_back(Bstr(VBOXSERVICE_TOOL_CAT).raw()); /* The actual (internal) tool to use (as argv[0]). */
&& !fCompleted)
if (!cbToRead)
cbRead = 0;
&& fCanceled)
if (cbToRead == 0)
if (fCanceled)
&& fCanceled)
rc = pGuest->waitForProcessStatusChange(uPID, &uRetStatus, &uRetExitCode, 10 * 1000 /* 10s timeout. */);
if ( uRetExitCode != 0
if (fCanceled)
if (!cbTransfered)
return VINF_SUCCESS;
Guest::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
&& cbOffset
&& cbLength)
switch (vrc)
case VERR_FILE_NOT_FOUND:
Guest::tr("An unknown error (%Rrc) occured while retrieving information of setup file on installation medium \"%s\""),
args.push_back(Bstr(VBOXSERVICE_TOOL_CAT).raw()); /* The actual (internal) tool to use (as argv[0]). */
switch (vrc)
case VERR_NOT_FOUND:
/* Getting back a VERR_INVALID_PARAMETER indicates that the installed Guest Additions are supporting the guest
case VERR_INVALID_PARAMETER:
&& !fCompleted)
if (cbToRead)
if ( cbRead
if (cbRead > 0)
&& fCanceled)
#ifdef DEBUG_andy
if (fCanceled)
#ifdef DEBUG_andy
Guest::tr("Error while reading setup file \"%s\" (To read: %u, Size: %u) from installation medium (%Rrc)"),
&& fCanceled)
&& !fCanceled
installerArgs.push_back(Bstr(strInstallerPath).raw()); /* The actual (internal) installer image (as argv[0]). */
&& !fCompleted)
&& fCanceled)
&& fCanceled)
if (fCompleted)
if (uRetExitCode == 0)
&& !fCompleted)
&& fCanceled)
Guest::tr("Guest Additions update was canceled by the guest with exit code=%u (status=%u, flags=%u)"),
return VINF_SUCCESS;
#ifdef VBOX_WITH_GUEST_CONTROL
int Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnvVars)
if (*ppvList)
char *pszTmp;
*pcEnvVars = 0;
*pcbList = 0;
return rc;
void *pvParms,
using namespace guestControl;
#ifdef DEBUG_andy
switch (u32Function)
case GUEST_DISCONNECTED:
PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms);
case GUEST_EXEC_SEND_STATUS:
case GUEST_EXEC_SEND_OUTPUT:
return rc;
/* Function for handling the execution start/termination notification. */
&& !fCanceled)
case PROC_STS_STARTED:
hr = it->second.pProgress->SetNextOperation(Bstr(tr("Waiting for process to exit ...")).raw(), 1 /* Weight */);
LogRel(("Guest process (PID %u) exited normally\n", pCBData->u32PID)); /** @todo Add process name */
case PROC_STS_TOK:
LogRel(("Guest process (PID %u) timed out and was killed\n", pCBData->u32PID)); /** @todo Add process name */
case PROC_STS_TOA:
LogRel(("Guest process (PID %u) timed out and could not be killed\n", pCBData->u32PID)); /** @todo Add process name */
case PROC_STS_DWN:
LogRel(("Guest process (PID %u) killed because system is shutting down\n", pCBData->u32PID)); /** @todo Add process name */
* even if the executed process was killed because the system/VBoxService is shutting down.
case PROC_STS_ERROR:
LogFlowFunc(("Unexpected callback (magic=%u, CID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
return vrc;
&& !fCompleted)
LogFlowFunc(("Unexpected callback (magic=%u, CID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
return rc;
&& !fCompleted)
LogFlowFunc(("Unexpected callback (magic=%u, CID=%u) arrived\n", pData->hdr.u32Magic, pData->hdr.u32ContextID));
return rc;
return rc;
if (!fCompleted)
* cancel won't work!). This could happen if the client thread (e.g. VBoxService, thread of a spawned process)
pszText);
uint32_t Guest::addCtrlCallbackContext(eVBoxGuestCtrlCallbackType enmType, void *pvData, uint32_t cbData, Progress *pProgress)
&& uNewContext > 0)
AssertReleaseMsg(uNewContext, ("No free context ID found! uNewContext=%u, nCallbacks=%u", uNewContext, nCallbacks));
return uNewContext;
HRESULT Guest::waitForProcessStatusChange(ULONG uPID, ULONG *puRetStatus, ULONG *puRetExitCode, ULONG uTimeoutMS)
if (uTimeoutMS == 0)
return hRC;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
if (pRC)
TRUE,
if (aTimeoutMS == 0)
if (aArguments)
if (uNumArgs > 0)
if (aEnvironment)
PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
if (vmmDev)
i, paParms);
if (!fCanceled)
case PROC_STS_STARTED:
case PROC_STS_TOK:
case PROC_STS_TOA:
case PROC_STS_DWN:
case PROC_STS_ERROR:
case PROC_STS_UNDEFINED:
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)
*aBytesWritten = 0;
if (aTimeoutMS == 0)
PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS));
if (vmmDev)
i, paParms);
&& fCanceled)
return rc;
STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData))
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
if (aSize < 0)
if (aTimeoutMS == 0)
if (vmmDev)
i, paParms);
if (!fCanceled)
&& fCompleted)
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
args.push_back(Bstr(VBOXSERVICE_TOOL_MKDIR).raw()); /* The actual (internal) tool to use (as argv[0]). */
if (aMode > 0)
&& !fCompleted)
&& fCanceled)
TRUE);
if (fCompleted)
else if (fCanceled)
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
if (aFlags)
return rc;