VBoxControl.cpp revision 51df2768ddb5c4dd975267b4ba82ba02da82d20a
/* $Id$ */
/** @file
* VBoxControl - Guest Additions Command Line Management Interface.
*/
/*
* Copyright (C) 2008-2013 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 <iprt/buildconfig.h>
#include <iprt/initterm.h>
#include <VBox/VBoxGuestLib.h>
#ifdef RT_OS_WINDOWS
# include <Windows.h>
#endif
#ifdef VBOX_WITH_GUEST_PROPS
#endif
# include <VBox/VBoxGuest.h>
# include "../VBoxGuestLib/VBGLR3Internal.h" /* HACK ALERT! Using vbglR3DoIOCtl directly!! */
#endif
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** The program name (derived from argv[0]). */
char const *g_pszProgName = "";
/** The current verbosity level. */
int g_cVerbosity = 0;
/**
* Displays the program usage message.
*
* @param u64Which
*
* @{
*/
/** Helper function */
{
/* Allow for up to 15 characters command name length (VBoxControl.exe) with
* perfect column alignment. Beyond that there's at least one space between
* the command if there are command line parameters. */
}
/** Enumerate the different parts of the usage we might want to print out */
enum VBoxControlUsage
{
#ifdef RT_OS_WINDOWS
#endif
#ifdef VBOX_WITH_GUEST_PROPS
#endif
#ifdef VBOX_WITH_SHARED_FOLDERS
#endif
#if !defined(VBOX_CONTROL_TEST)
#endif
HELP,
};
{
RTPrintf("Usage:\n\n");
RTPrintf("\n");
/* Exclude the Windows bits from the test version. Anyone who needs to
test them can fix this. */
#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
#endif
#ifdef VBOX_WITH_GUEST_PROPS
{
doUsage("[--timestamp <last timestamp>]");
doUsage("[--timeout <timeout in ms>");
}
#endif
#ifdef VBOX_WITH_SHARED_FOLDERS
{
}
#endif
#if !defined(VBOX_CONTROL_TEST)
#endif
}
/** @} */
/**
* Displays an error message.
*
* @returns RTEXITCODE_FAILURE.
* @param pszFormat The message text. No newline.
* @param ... Format arguments.
*/
{
return RTEXITCODE_FAILURE;
}
/**
* Displays an syntax error message.
*
* @returns RTEXITCODE_FAILURE.
* @param pszFormat The message text. No newline.
* @param ... Format arguments.
*/
{
return RTEXITCODE_FAILURE;
}
#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
LONG (WINAPI * gpfnChangeDisplaySettingsEx)(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
{
unsigned i;
for (i = 0; i < nRects; i++)
{
{
return i;
}
}
return ~0;
}
{
unsigned i;
for (i = 0; i < nRects; i++)
{
{
return i;
}
}
return ~0;
}
{
unsigned i;
for (i = 0; i < nRects; i++)
{
{
return i;
}
}
return ~0;
}
{
unsigned i;
for (i = 0; i < nRects; i++)
{
{
return i;
}
}
return ~0;
}
void resizeRect(RECTL *paRects, unsigned nRects, unsigned iPrimary, unsigned iResized, int NewWidth, int NewHeight)
{
paNewRects[iResized].bottom += NewHeight - (paNewRects[iResized].bottom - paNewRects[iResized].top);
/* Verify all pairs of originally adjacent rectangles for all 4 directions.
* If the pair has a "good" delta (that is the first rectangle intersects the second)
* at a direction and the second rectangle is not primary one (which can not be moved),
* move the second rectangle to make it adjacent to the first one.
*/
/* X positive. */
unsigned iRect;
{
/* Find the next adjacent original rect in x positive direction. */
{
continue;
}
/* Check whether there is an X intersection between these adjacent rects in the new rectangles
* and fix the intersection if delta is "good".
*/
if (delta > 0)
{
Log(("XP intersection right %d left %d, diff %d\n",
delta));
}
}
/* X negative. */
{
/* Find the next adjacent original rect in x negative direction. */
{
continue;
}
/* Check whether there is an X intersection between these adjacent rects in the new rectangles
* and fix the intersection if delta is "good".
*/
if (delta < 0)
{
Log(("XN intersection left %d right %d, diff %d\n",
delta));
}
}
/* Y positive (in the computer sense, top->down). */
{
/* Find the next adjacent original rect in y positive direction. */
{
continue;
}
/* Check whether there is an Y intersection between these adjacent rects in the new rectangles
* and fix the intersection if delta is "good".
*/
if (delta > 0)
{
Log(("YP intersection bottom %d top %d, diff %d\n",
delta));
}
}
/* Y negative (in the computer sense, down->top). */
{
/* Find the next adjacent original rect in x negative direction. */
{
continue;
}
/* Check whether there is an Y intersection between these adjacent rects in the new rectangles
* and fix the intersection if delta is "good".
*/
if (delta < 0)
{
Log(("YN intersection top %d bottom %d, diff %d\n",
delta));
}
}
return;
}
/* Returns TRUE to try again. */
{
/* Find out how many display devices the system has */
DWORD NumDevices = 0;
DWORD i = 0;
{
{
NumDevices++;
}
{
NumDevices++;
}
i++;
}
{
return FALSE;
}
/* Fetch information about current devices and modes. */
DWORD DevPrimaryNum = 0;
i = 0;
{
{
bFetchDevice = TRUE;
}
{
bFetchDevice = TRUE;
}
if (bFetchDevice)
{
if (DevNum >= NumDevices)
{
return FALSE;
}
{
return FALSE;
}
Log(("%dx%d at %d,%d\n",
DevNum++;
}
i++;
}
if (Width == 0)
{
}
if (Height == 0)
{
}
/* Check whether a mode reset or a change is requested. */
if ( !fModeReset
{
Log(("VBoxDisplayThread : already at desired resolution.\n"));
return FALSE;
}
#ifdef Log
for (i = 0; i < NumDevices; i++)
{
Log(("[%d]: %d,%d %dx%d\n",
}
#endif /* Log */
/* Without this, Windows will not ask the miniport for its
* mode table but uses an internal cache instead.
*/
/* Assign the new rectangles to displays. */
for (i = 0; i < NumDevices; i++)
{
if ( i == Id
&& BitsPerPixel != 0)
{
}
}
/* A second call to ChangeDisplaySettings updates the monitor. */
{
/* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
return FALSE;
}
/* Retry the request. */
return TRUE;
}
{
{
return RTEXITCODE_FAILURE;
}
if (argc == 4)
{
}
if (hUser)
{
*(uintptr_t *)&gpfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
{
/* The screen index is 0 based in the ResizeDisplayDevice call. */
/* Horizontal resolution must be a multiple of 8, round down. */
xres &= ~0x7;
RTPrintf("done.\n");
}
else
VBoxControlError("Error retrieving API for display change!");
}
else
VBoxControlError("Error retrieving handle to user32.dll!");
return RTEXITCODE_SUCCESS;
}
{
HKEY hkeyDeviceMap = 0;
status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkeyDeviceMap);
{
VBoxControlError("Error opening video device map registry key!\n");
return 0;
}
char szVideoLocation[256];
szVideoLocation[0] = 0;
status = RegQueryValueExA(hkeyDeviceMap, "\\Device\\Video0", NULL, &dwKeyType, (LPBYTE)szVideoLocation, &len);
/*
* This value will start with a weird value: \REGISTRY\Machine
* Make sure this is true.
*/
if ( (status == ERROR_SUCCESS)
{
/* open that branch */
status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, &szVideoLocation[18], 0, KEY_READ | (writable ? KEY_WRITE : 0), &hkeyVideo);
}
else
{
}
return hkeyVideo;
}
{
if (hkeyVideo)
{
/* query the actual value */
status = RegQueryValueExA(hkeyVideo, "EnableVideoAccel", NULL, &dwKeyType, (LPBYTE)&fAcceleration, &len);
if (status != ERROR_SUCCESS)
RTPrintf("Video acceleration: default\n");
else
}
return RTEXITCODE_SUCCESS;
}
{
/* must have exactly one argument: the new offset */
if ( (argc != 1)
{
return RTEXITCODE_FAILURE;
}
hkeyVideo = getVideoKey(true);
if (hkeyVideo)
{
int fAccel = 0;
fAccel = 1;
/* set a new value */
status = RegSetValueExA(hkeyVideo, "EnableVideoAccel", 0, REG_DWORD, (LPBYTE)&fAccel, sizeof(fAccel));
if (status != ERROR_SUCCESS)
{
}
}
return RTEXITCODE_SUCCESS;
}
#define MAX_CUSTOM_MODES 128
/* the table of custom modes */
struct
{
} customModes[MAX_CUSTOM_MODES] = {0};
{
int curMode = 0;
/* null out the table */
do
{
char valueName[20];
if (status != ERROR_SUCCESS)
break;
if (status != ERROR_SUCCESS)
break;
if (status != ERROR_SUCCESS)
break;
/* check if the mode is OK */
&& ( (bpp != 16)
|| (bpp != 24)
|| (bpp != 32)))
break;
/* add mode to table */
++curMode;
if (curMode >= MAX_CUSTOM_MODES)
break;
} while(1);
}
{
int tableIndex = 0;
int modeIndex = 0;
/* first remove all values */
for (int i = 0; i < MAX_CUSTOM_MODES; i++)
{
char valueName[20];
}
do
{
if (tableIndex >= MAX_CUSTOM_MODES)
break;
/* is the table entry present? */
{
tableIndex++;
continue;
}
RTPrintf("writing mode %d (%dx%dx%d)\n", modeIndex, customModes[tableIndex].xres, customModes[tableIndex].yres, customModes[tableIndex].bpp);
char valueName[20];
modeIndex++;
tableIndex++;
} while(1);
}
{
if (argc != 0)
{
return RTEXITCODE_FAILURE;
}
if (hkeyVideo)
{
for (int i = 0; i < (sizeof(customModes) / sizeof(customModes[0])); i++)
{
if ( !customModes[i].xres
|| !customModes[i].yres
|| !customModes[i].bpp)
continue;
RTPrintf("Mode: %d x %d x %d\n",
}
}
return RTEXITCODE_SUCCESS;
}
{
if (argc != 3)
{
return RTEXITCODE_FAILURE;
}
/** @todo better check including xres mod 8 = 0! */
&& ( (bpp != 16)
|| (bpp != 24)
|| (bpp != 32)))
{
VBoxControlError("invalid mode specified!\n");
return RTEXITCODE_FAILURE;
}
if (hkeyVideo)
{
int i;
int fModeExists = 0;
for (i = 0; i < MAX_CUSTOM_MODES; i++)
{
/* mode exists? */
)
{
fModeExists = 1;
}
}
if (!fModeExists)
{
for (i = 0; i < MAX_CUSTOM_MODES; i++)
{
/* item free? */
if (!customModes[i].xres)
{
break;
}
}
}
}
return RTEXITCODE_SUCCESS;
}
{
if (argc != 3)
{
return RTEXITCODE_FAILURE;
}
if (hkeyVideo)
{
for (int i = 0; i < MAX_CUSTOM_MODES; i++)
{
/* correct item? */
{
RTPrintf("found mode at index %d\n", i);
RT_ZERO(customModes[i]);
break;
}
}
}
return RTEXITCODE_SUCCESS;
}
#endif /* RT_OS_WINDOWS */
#ifdef VBOX_WITH_GUEST_PROPS
/**
* Retrieves a value from the guest property store.
* This is accessed through the "VBoxGuestPropSvc" HGCM service.
*
* @returns Command exit code.
* @note see the command line API description for parameters
*/
{
using namespace guestProp;
bool fVerbose = false;
if ( 2 == argc
)
fVerbose = true;
else if (argc != 1)
{
return RTEXITCODE_FAILURE;
}
uint32_t u32ClientId = 0;
int rc = VINF_SUCCESS;
if (!RT_SUCCESS(rc))
/*
* Here we actually retrieve the value from the host.
*/
uint64_t u64Timestamp = 0;
/* The buffer for storing the data and its initial size. We leave a bit
* of space here in case the maximum values are raised. */
if (RT_SUCCESS(rc))
{
/* Because there is a race condition between our reading the size of a
* property and the guest updating it, we loop a few times here and
* hope. Actually this should never go wrong, as we are generous
* enough with buffer space. */
bool finish = false;
for (unsigned i = 0; (i < 10) && !finish; ++i)
{
{
rc = VERR_NO_MEMORY;
VBoxControlError("Out of memory\n");
}
else
{
&cbBuf);
}
if (VERR_BUFFER_OVERFLOW == rc)
/* Leave a bit of extra space to be safe */
cbBuf += 1024;
else
finish = true;
}
if (VERR_TOO_MUCH_DATA == rc)
VBoxControlError("Temporarily unable to retrieve the property\n");
}
/*
* And display it on the guest console.
*/
if (VERR_NOT_FOUND == rc)
RTPrintf("No value set!\n");
else if (RT_SUCCESS(rc))
{
if (fVerbose)
{
}
}
if (u32ClientId != 0)
}
/**
* Writes a value to the guest property store.
* This is accessed through the "VBoxGuestPropSvc" HGCM service.
*
* @returns Command exit code.
* @note see the command line API description for parameters
*/
{
/*
* Check the syntax. We can deduce the correct syntax from the number of
* arguments.
*/
bool usageOK = true;
if (2 == argc)
{
}
else if (3 == argc)
usageOK = false;
else if (4 == argc)
{
usageOK = false;
}
else if (argc != 1)
usageOK = false;
if (!usageOK)
{
return RTEXITCODE_FAILURE;
}
/* This is always needed. */
/*
* Do the actual setting.
*/
uint32_t u32ClientId = 0;
int rc = VINF_SUCCESS;
if (!RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
else
if (!RT_SUCCESS(rc))
}
if (u32ClientId != 0)
}
/**
* Deletes a guest property from the guest property store.
* This is accessed through the "VBoxGuestPropSvc" HGCM service.
*
* @returns Command exit code.
* @note see the command line API description for parameters
*/
{
/*
* Check the syntax. We can deduce the correct syntax from the number of
* arguments.
*/
bool usageOK = true;
if (argc < 1)
usageOK = false;
if (!usageOK)
{
return RTEXITCODE_FAILURE;
}
/* This is always needed. */
/*
* Do the actual setting.
*/
uint32_t u32ClientId = 0;
if (!RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
{
if (!RT_SUCCESS(rc))
}
if (u32ClientId != 0)
}
/**
* Enumerates the properties in the guest property store.
* This is accessed through the "VBoxGuestPropSvc" HGCM service.
*
* @returns Command exit code.
* @note see the command line API description for parameters
*/
{
/*
* Check the syntax. We can deduce the correct syntax from the number of
* arguments.
*/
char const * const *papszPatterns = NULL;
if ( argc > 1
{
}
else if (argc != 0)
{
return RTEXITCODE_FAILURE;
}
/*
* Do the actual enumeration.
*/
uint32_t u32ClientId = 0;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
{
RTPrintf("Name: %s, value: %s, timestamp: %lld, flags: %s\n",
if (RT_FAILURE(rc))
}
}
else if (VERR_NOT_FOUND == rc)
RTPrintf("No properties found.\n");
else
}
else
}
/**
* Waits for notifications of changes to guest properties.
* This is accessed through the "VBoxGuestPropSvc" HGCM service.
*
* @returns Command exit code.
* @note see the command line API description for parameters
*/
{
using namespace guestProp;
/*
* Handle arguments
*/
const char *pszPatterns = NULL;
uint64_t u64TimestampIn = 0;
bool usageOK = true;
if (argc < 1)
usageOK = false;
pszPatterns = argv[0];
{
{
if ( i + 1 >= argc
!= VINF_SUCCESS
)
usageOK = false;
else
++i;
}
{
if ( i + 1 >= argc
!= VINF_SUCCESS
)
usageOK = false;
else
++i;
}
else
usageOK = false;
}
if (!usageOK)
{
return RTEXITCODE_FAILURE;
}
/*
* Connect to the service
*/
uint32_t u32ClientId = 0;
int rc = VINF_SUCCESS;
if (!RT_SUCCESS(rc))
/*
* Retrieve the notification from the host
*/
uint64_t u64TimestampOut = 0;
/* The buffer for storing the data and its initial size. We leave a bit
* of space here in case the maximum values are raised. */
/* Because there is a race condition between our reading the size of a
* property and the guest updating it, we loop a few times here and
* hope. Actually this should never go wrong, as we are generous
* enough with buffer space. */
bool finish = false;
for (unsigned i = 0;
++i)
{
{
rc = VERR_NO_MEMORY;
VBoxControlError("Out of memory\n");
}
else
{
}
if (VERR_BUFFER_OVERFLOW == rc)
/* Leave a bit of extra space to be safe */
cbBuf += 1024;
else
finish = true;
if (rc == VERR_TOO_MUCH_DATA)
VBoxControlError("Temporarily unable to get a notification\n");
else if (rc == VERR_INTERRUPTED)
VBoxControlError("The request timed out or was interrupted\n");
#ifndef RT_OS_WINDOWS /* Windows guests do not do this right */
#endif
}
/*
* And display it on the guest console.
*/
if (VERR_NOT_FOUND == rc)
RTPrintf("No value set!\n");
else if (rc == VERR_BUFFER_OVERFLOW)
RTPrintf("Internal error: unable to determine the size of the data!\n");
else if (RT_SUCCESS(rc))
{
}
if (u32ClientId != 0)
}
/**
* Access the guest property store through the "VBoxGuestPropSvc" HGCM
* service.
*
* @returns 0 on success, 1 on failure
* @note see the command line API description for parameters
*/
{
if (0 == argc)
{
return RTEXITCODE_FAILURE;
}
/* else */
return RTEXITCODE_FAILURE;
}
#endif
#ifdef VBOX_WITH_SHARED_FOLDERS
/**
* Lists the Shared Folders provided by the host.
*/
{
bool usageOK = true;
bool fOnlyShowAutoMount = false;
if (argc == 1)
{
fOnlyShowAutoMount = true;
else
usageOK = false;
}
else if (argc > 1)
usageOK = false;
if (!usageOK)
{
return RTEXITCODE_FAILURE;
}
if (!RT_SUCCESS(rc))
else
{
&paMappings, &cMappings);
if (RT_SUCCESS(rc))
{
if (fOnlyShowAutoMount)
else
{
char *pszName;
if (RT_SUCCESS(rc))
{
}
else
VBoxControlError("Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
}
if (!cMappings)
RTPrintf("No Shared Folders available.\n");
}
else
}
}
/**
* Handles Shared Folders control.
*
* @returns 0 on success, 1 on failure
* @note see the command line API description for parameters
* (r=bird: yeah, right. The API description contains nil about params)
*/
{
if (0 == argc)
{
return RTEXITCODE_FAILURE;
}
/* else */
return RTEXITCODE_FAILURE;
}
#endif
#if !defined(VBOX_CONTROL_TEST)
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: writecoredump}
*/
{
int rc = VbglR3WriteCoreDump();
if (RT_SUCCESS(rc))
{
RTPrintf("Guest core dump successful.\n");
return RTEXITCODE_SUCCESS;
}
else
{
return RTEXITCODE_FAILURE;
}
}
#endif
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: help}
*/
{
# ifndef VBOX_CONTROL_TEST
int rc;
for (int i = 0; i < 30; i++)
{
if (RT_FAILURE(rc))
break;
RTPrintf("%d\n", i);
}
# else
int rc = VERR_NOT_IMPLEMENTED;
# endif
if (RT_FAILURE(rc))
RTPrintf("Samples collection completed.\n");
return RTEXITCODE_SUCCESS;
}
#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: takesnapshot}
*/
{
//VbglR3VmTakeSnapshot(argv[0], argv[1]);
return VBoxControlError("not implemented");
}
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: savestate}
*/
{
//VbglR3VmSaveState();
return VBoxControlError("not implemented");
}
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: suspend|pause}
*/
{
//VbglR3VmSuspend();
return VBoxControlError("not implemented");
}
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: poweroff|powerdown}
*/
{
//VbglR3VmPowerOff();
return VBoxControlError("not implemented");
}
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: version}
*/
{
if (argc)
return VBoxControlSyntaxError("getversion does not take any arguments");
return RTEXITCODE_SUCCESS;
}
/**
* @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: help}
*/
{
/* ignore arguments for now. */
usage();
return RTEXITCODE_SUCCESS;
}
/** command handler type */
typedef FNVBOXCTRLCMDHANDLER *PFNVBOXCTRLCMDHANDLER;
/** The table of all registered command handlers. */
struct COMMANDHANDLER
{
const char *pszCommand;
} g_aCommandHandlers[] =
{
#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
{ "getvideoacceleration", handleGetVideoAcceleration },
{ "setvideoacceleration", handleSetVideoAcceleration },
{ "listcustommodes", handleListCustomModes },
{ "addcustommode", handleAddCustomMode },
{ "removecustommode", handleRemoveCustomMode },
{ "setvideomode", handleSetVideoMode },
#endif
#ifdef VBOX_WITH_GUEST_PROPS
{ "guestproperty", handleGuestProperty },
#endif
#ifdef VBOX_WITH_SHARED_FOLDERS
{ "sharedfolder", handleSharedFolder },
#endif
#if !defined(VBOX_CONTROL_TEST)
{ "writecoredump", handleWriteCoreDump },
#endif
{ "dpc", handleDpc },
#endif
{ "takesnapshot", handleTakeSnapshot },
{ "savestate", handleSaveState },
{ "suspend", handleSuspend },
{ "pause", handleSuspend },
{ "poweroff", handlePowerOff },
{ "powerdown", handlePowerOff },
{ "getversion", handleVersion },
{ "version", handleVersion },
{ "help", handleHelp }
};
/** Main function */
{
/** The application's global return code */
/** An IPRT return code for local use */
int rrc = VINF_SUCCESS;
/** The index of the command line argument we are currently processing */
int iArg = 1;
/** Should we show the logo text? */
bool fShowLogo = true;
/** Should we print the usage after the logo? For the -help switch. */
bool fDoHelp = false;
/** Will we be executing a command or just printing information? */
bool fOnlyInfo = false;
if (RT_FAILURE(rrc))
return RTMsgInitFailure(rrc);
/*
* Start by handling command line switches
*/
/** @todo RTGetOpt conversion of the whole file. */
bool done = false; /**< Are we finished with handling switches? */
{
)
{
/* Print version number, and do nothing else. */
fOnlyInfo = true;
fShowLogo = false;
done = true;
}
fShowLogo = false;
{
fOnlyInfo = true;
fDoHelp = true;
done = true;
}
else
/* We have found an argument which isn't a switch. Exit to the
* command processing bit. */
done = true;
if (!done)
++iArg;
}
/*
* Find the application name, show our logo if the user hasn't suppressed it,
* and show the usage if the user asked us to
*/
if (fShowLogo)
VBOX_VERSION_STRING "\n"
"All rights reserved.\n\n");
if (fDoHelp)
usage();
/*
* Do global initialisation for the programme if we will be handling a command
*/
if (!fOnlyInfo)
{
rrc = VbglR3Init();
if (RT_FAILURE(rrc))
{
VBoxControlError("Could not contact the host system. Make sure that you are running this\n"
"application inside a VirtualBox guest system, and that you have sufficient\n"
"user permissions.\n");
}
}
/*
* Now look for an actual command in the argument list and handle it.
*/
{
{
/*
* Try locate the command and execute it, complain if not found.
*/
unsigned i;
for (i = 0; i < RT_ELEMENTS(g_aCommandHandlers); i++)
{
break;
}
if (i >= RT_ELEMENTS(g_aCommandHandlers))
{
usage();
}
}
else
{
/* The user didn't specify a command. */
usage();
}
}
/*
* And exit, returning the status
*/
return rcExit;
}