GuestCtrlImpl.cpp revision 5578b2c35a8afa21ffc1a8972e315a17ee505737
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * VirtualBox COM class implementation: Guest
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Copyright (C) 2006-2011 Oracle Corporation
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * This file is part of VirtualBox Open Source Edition (OSE), as
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * available from http://www.virtualbox.org. This file is free software;
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * you can redistribute it and/or modify it under the terms of the GNU
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * General Public License (GPL) as published by the Free Software
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * Foundation, in version 2 as it comes in the "COPYING" file of the
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey /** Copies a file from host to the guest. */
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey /** Copies a file from guest to the host. */
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey /** Update Guest Additions by directly copying the required installer
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * off the .ISO file, transfer it to the guest and execute the installer
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey * with system privileges. */
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey TaskGuest(TaskType aTaskType, Guest *aThat, Progress *aProgress)
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey static int taskThread(RTTHREAD aThread, void *pvUser);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey static int uploadProgress(unsigned uPercent, void *pvUser);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey static HRESULT setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, const char * pszText, ...);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey static HRESULT setProgressErrorInfo(HRESULT hr, ComObjPtr<Progress> pProgress, ComObjPtr<Guest> pGuest);
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey /* Task data. */
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey int vrc = RTThreadCreate(NULL, Guest::TaskGuest::taskThread, this,
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey "Guest::Task");
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey return Guest::setErrorStatic(E_FAIL, Utf8StrFmt("Could not create taskThreadGuest (%Rrc)\n", vrc));
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. MaskeyDECLCALLBACK(int) Guest::TaskGuest::taskThread(RTTHREAD /* aThread */, void *pvUser)
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey std::auto_ptr<TaskGuest> task(static_cast<TaskGuest*>(pvUser));
6ba597c56d749c61b4f783157f63196d7b2445f0Anurag S. Maskey AssertReturn(task.get(), VERR_GENERAL_FAILURE);
#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)
&& !fCompleted)
if (!cbToRead)
cbRead = 0;
&& fCanceled)
if (cbToRead == 0)
if (fCanceled)
&& fCanceled)
rc = pGuest->waitForProcessStatusChange(uPID, &retStatus, &uRetExitCode, 10 * 1000 /* 10s timeout. */);
if ( uRetExitCode != 0
if (fCanceled)
if ( cbSize > 0
&& cbTransfered == 0)
return VINF_SUCCESS;
if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", aTask->strDest.c_str()) <= sizeof(szOutput) - 1)
&& !fCompleted)
if (!cbToRead)
cbRead = 0;
&& fCanceled)
if (cbToRead == 0)
if (fCanceled)
&& fCanceled)
rc = pGuest->waitForProcessStatusChange(uPID, &retStatus, &uRetExitCode, 10 * 1000 /* 10s timeout. */);
if ( uRetExitCode != 0
if (fCanceled)
if ( cbSize > 0
&& cbTransfered == 0)
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\""),
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:
case VERR_TIMEOUT:
&& !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;
int rc;
return rc;
if (pvData)
if (pEnmType)
if (pcbData)
return VINF_SUCCESS;
return VERR_NOT_FOUND;
if (pcbData)
return NULL;
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)
&& !pszMessage)
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 (!fCbCanceled)
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:
return vrc;
if (pCallbackData)
int vrc;
return vrc;
if (pCallbackData)
return VINF_SUCCESS;
return VERR_ALREADY_EXISTS;
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 VERR_NOT_FOUND;
return hRC;
return hRC;
HRESULT Guest::waitForProcessStatusChange(ULONG uPID, ExecuteProcessStatus_T *pRetStatus, ULONG *puRetExitCode, ULONG uTimeoutMS)
if (uTimeoutMS == 0)
return hRC;
case PROC_STS_STARTED:
case PROC_STS_TOK:
case PROC_STS_TOA:
case PROC_STS_DWN:
case PROC_STS_ERROR:
return rc;
#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 pStatus = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
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:
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 (aSize == 0)
if (aFlags)
if (aTimeoutMS == 0)
if (pVMMDev)
i, paParms);
return rc;
STDMETHODIMP Guest::GetProcessStatus(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ExecuteProcessStatus_T *aStatus)
#ifndef VBOX_WITH_GUEST_CONTROL
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
return VBOX_E_NOT_SUPPORTED;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
if (aMode > 0)
if (!fCompleted)
if (fCompleted)
else if (fCanceled)
return rc;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
return VBOX_E_NOT_SUPPORTED;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
return VBOX_E_NOT_SUPPORTED;
#ifndef VBOX_WITH_GUEST_CONTROL
using namespace guestControl;
return VBOX_E_NOT_SUPPORTED;
#ifndef VBOX_WITH_GUEST_CONTROL
if (aFlags)
return rc;