VBoxManageGuestCtrl.cpp revision 0426463996ec1b6d5af11e5e2845257f94496fbd
/* $Id$ */
/** @file
* VBoxManage - The 'guestcontrol' command.
*/
/*
* Copyright (C) 2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "VBoxManage.h"
#ifdef USE_XPCOM_QUEUE
# include <errno.h>
#endif
#include <signal.h>
#ifdef RT_OS_DARWIN
# include <CoreFoundation/CFRunLoop.h>
#endif
using namespace com;
/**
* IVirtualBoxCallback implementation for handling the GuestControlCallback in
* relation to the "guestcontrol * wait" command.
*/
/** @todo */
/** Set by the signal handler. */
static volatile bool g_fExecCanceled = false;
void usageGuestControl(void)
{
RTPrintf("VBoxManage guestcontrol execute <vmname>|<uuid>\n"
" <path to program> [--arguments \"<arguments>\"]\n"
" [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n"
" [--flags <flags>] [--timeout <msec>]\n"
" [--username <name> [--password <password>]]\n"
" [--verbose] [--wait-for exit,stdout,stderr||]\n"
"\n");
}
/**
* Signal handler that sets g_fCanceled.
*
* This can be executed on any thread in the process, on Windows it may even be
* a thread dedicated to delivering this signal. Do not doing anything
* unnecessary here.
*/
static void execProcessSignalHandler(int iSignal)
{
ASMAtomicWriteBool(&g_fExecCanceled, true);
}
static int handleExecProgram(HandlerArg *a)
{
/*
* Check the syntax. We can deduce the correct syntax from the number of
* arguments.
*/
uint32_t u32TimeoutMS = 0;
bool waitForExit = false;
bool waitForStdOut = false;
bool waitForStdErr = false;
bool verbose = false;
bool have_timeout = false;
/* Always use the actual command line as argv[0]. */
/* Iterate through all possible commands (if available). */
bool usageOK = true;
{
{
if (i + 1 >= a->argc)
usageOK = false;
else
{
char **papszArg;
int cArgs;
if (RT_SUCCESS(vrc))
{
for (int j = 0; j < cArgs; j++)
}
++i;
}
}
{
if (i + 1 >= a->argc)
usageOK = false;
else
{
char **papszArg;
int cArgs;
if (RT_SUCCESS(vrc))
{
for (int j = 0; j < cArgs; j++)
}
++i;
}
}
{
if ( i + 1 >= a->argc
usageOK = false;
else
++i;
}
{
if (i + 1 >= a->argc)
usageOK = false;
else
{
++i;
}
}
{
if (i + 1 >= a->argc)
usageOK = false;
else
{
++i;
}
}
{
if ( i + 1 >= a->argc
|| u32TimeoutMS == 0)
{
usageOK = false;
}
else
{
have_timeout = true;
++i;
}
}
{
if (i + 1 >= a->argc)
usageOK = false;
else
{
waitForExit = true;
{
waitForExit = true;
waitForStdOut = true;
}
{
waitForExit = true;
waitForStdErr = true;
}
else
usageOK = false;
++i;
}
}
{
verbose = true;
}
/** @todo Add fancy piping stuff here. */
else
{
return errorSyntax(USAGE_GUESTCONTROL,
}
}
if (!usageOK)
/* If a password was specified, check if we also got a user name. */
if ( !Utf8Password.isEmpty()
&& Utf8UserName.isEmpty())
{
return errorSyntax(USAGE_GUESTCONTROL,
"No user name for password specified!");
}
/* lookup VM. */
/* assume it's an UUID */
{
/* must be a name */
}
if (machine)
{
do
{
/* open an existing session for VM - so the VM has to be running */
/* get the mutable session machine */
/* get the associated console */
if (verbose)
{
if (u32TimeoutMS == 0)
RTPrintf("Waiting for guest to start process ...\n");
else
}
/* Get current time stamp to later calculate rest of timeout left. */
/* Execute the process. */
if (waitForExit)
{
if (have_timeout)
{
/* Calculate timeout value left after process has been started. */
/** @todo Check for uint64_t vs. uint32_t here! */
{
if (verbose)
}
else
{
if (verbose)
RTPrintf("No time left to wait for process!\n");
}
}
else if (verbose)
RTPrintf("Waiting for process to exit ...\n");
/* setup signal handling if cancelable */
bool fCanceledAlready = false;
fCancelable = FALSE;
if (fCancelable)
{
#ifdef SIGBREAK
#endif
}
/* Wait for process to exit ... */
BOOL fCompleted = false;
{
ULONG cbOutputData = 0;
/*
* Some data left to output?
*/
if ( waitForStdOut
|| waitForStdErr)
{
if (cbOutputData > 0)
{
/* aOutputData has a platform dependent line ending, standardize on
s++, d++)
{
if (*s == '\r')
{
/* skip over CR, adjust destination */
d--;
}
else if (s != d)
*d = *s;
}
}
}
if (cbOutputData <= 0)
{
if (fCompleted)
break;
if ( have_timeout
{
break;
}
}
/* process async cancelation */
if (g_fExecCanceled && !fCanceledAlready)
{
fCanceledAlready = true;
else
g_fExecCanceled = false;
}
}
/* undo signal handling */
if (fCancelable)
{
#ifdef SIGBREAK
#endif
}
if (fCanceled)
{
RTPrintf("Process execution canceled!\n");
}
else
{
if (fCompleted)
{
{
RTPrintf("\n\nProcess error details:\n");
RTPrintf("\n");
}
if (verbose)
{
}
}
}
}
} while (0);
}
}
/**
* Access the guest control store.
*
* @returns 0 on success, 1 on failure
* @note see the command line API description for parameters
*/
int handleGuestControl(HandlerArg *a)
{
HandlerArg arg = *a;
if (a->argc == 0)
/* switch (cmd) */
return handleExecProgram(&arg);
/* default: */
}