summaryrefslogtreecommitdiff
path: root/src/VBox/Frontends/VBoxManage
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Frontends/VBoxManage')
-rw-r--r--src/VBox/Frontends/VBoxManage/Makefile.kmk22
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp20
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManage.cpp22
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManage.h59
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageAppliance.cpp237
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageBandwidthControl.cpp19
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp281
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageDHCPServer.cpp171
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp2
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp577
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp2858
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h233
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp484
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp60
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp320
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp2
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp216
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageList.cpp292
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageMetrics.cpp19
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp47
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp508
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageNATNetwork.cpp490
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp11
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageStorageController.cpp46
-rw-r--r--src/VBox/Frontends/VBoxManage/VBoxManageUSB.cpp51
25 files changed, 5392 insertions, 1655 deletions
diff --git a/src/VBox/Frontends/VBoxManage/Makefile.kmk b/src/VBox/Frontends/VBoxManage/Makefile.kmk
index 02427bf6..ae335991 100644
--- a/src/VBox/Frontends/VBoxManage/Makefile.kmk
+++ b/src/VBox/Frontends/VBoxManage/Makefile.kmk
@@ -4,7 +4,7 @@
#
#
-# Copyright (C) 2006-2012 Oracle Corporation
+# Copyright (C) 2006-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;
@@ -22,8 +22,10 @@ ifdef VBOX_WITH_DOCS
PROGRAMS += VBoxManageHelp
endif
VBoxManageHelp_TEMPLATE = VBoxAdvBldProg
-VBoxManageHelp_DEFS += VBOX_ONLY_DOCS
-VBoxManageHelp_SOURCES = \
+VBoxManageHelp_DEFS += \
+ VBOX_ONLY_DOCS \
+ $(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL)
+VBoxManageHelp_SOURCES = \
VBoxManage.cpp \
VBoxManageHelp.cpp \
$(if $(VBOX_WITH_GUEST_PROPS),VBoxManageGuestProp.cpp) \
@@ -34,7 +36,7 @@ ifndef VBOX_ONLY_DOCS
endif
VBoxManage_TEMPLATE = VBOXMAINCLIENTEXE
VBoxManage_DEFS.win = _WIN32_WINNT=0x0500
-VBoxManage_SOURCES = \
+VBoxManage_SOURCES = \
VBoxManage.cpp \
VBoxInternalManage.cpp \
VBoxManageAppliance.cpp \
@@ -44,6 +46,7 @@ VBoxManage_SOURCES = \
VBoxManageDHCPServer.cpp \
VBoxManageDisk.cpp \
$(if $(VBOX_WITH_GUEST_CONTROL),VBoxManageGuestCtrl.cpp) \
+ $(if $(VBOX_WITH_GUEST_CONTROL),VBoxManageGuestCtrlListener.cpp) \
$(if $(VBOX_WITH_GUEST_PROPS),VBoxManageGuestProp.cpp) \
VBoxManageHelp.cpp \
VBoxManageHostonly.cpp \
@@ -54,7 +57,9 @@ VBoxManage_SOURCES = \
VBoxManageModifyVM.cpp \
VBoxManageSnapshot.cpp \
VBoxManageStorageController.cpp \
- VBoxManageUSB.cpp
+ VBoxManageUSB.cpp \
+ $(if $(VBOX_WITH_NAT_SERVICE),VBoxManageNATNetwork.cpp,) \
+ $(if $(VBOX_WITH_NAT_SERVICE),../../NetworkServices/NetLib/VBoxNetPortForwardString.cpp,)
VBoxManage_LIBS += $(LIB_DDU)
VBoxManage_DEFS += \
@@ -76,7 +81,12 @@ VBoxManage_DEFS += \
$(if $(VBOX_WITH_VIRTIO),VBOX_WITH_VIRTIO) \
$(if $(VBOX_WITH_USB_CARDREADER),VBOX_WITH_USB_CARDREADER) \
$(if $(VBOX_WITH_PCI_PASSTHROUGH),VBOX_WITH_PCI_PASSTHROUGH) \
- $(if $(VBOX_WITH_VPX),VBOX_WITH_VPX)
+ $(if $(VBOX_WITH_VPX),VBOX_WITH_VPX) \
+ $(if $(VBOX_WITH_NAT_SERVICE),VBOX_WITH_NAT_SERVICE) \
+ $(if $(VBOX_WITH_VMSVGA),VBOX_WITH_VMSVGA)
+
+# VBoxNetPortForwardString.h
+VBoxManageNATNetwork.cpp_INCS += ../../NetworkServices/NetLib/
ifneq ($(KBUILD_TARGET),win)
# Workaround for buggy gcc-4.3 compilers, see
diff --git a/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp b/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp
index 5d3161a6..f4033f7b 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp
@@ -121,7 +121,7 @@ typedef struct HOSTPARTITION
typedef struct HOSTPARTITIONS
{
/** partitioning type - MBR or GPT */
- PARTITIONING_TYPE uPartitioningType;
+ VBOXHDDPARTTYPE uPartitioningType;
unsigned cPartitions;
HOSTPARTITION aPartitions[HOSTPARTITION_MAX];
} HOSTPARTITIONS, *PHOSTPARTITIONS;
@@ -145,13 +145,13 @@ void printUsageInternal(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" incompatible ways without warning.\n",
(u64Cmd & USAGE_LOADMAP)
- ? " loadmap <vmname>|<uuid> <symfile> <address> [module] [subtrahend] [segment]\n"
+ ? " loadmap <vmname|uuid> <symfile> <address> [module] [subtrahend] [segment]\n"
" This will instruct DBGF to load the given map file\n"
" during initialization. (See also loadmap in the debugger.)\n"
"\n"
: "",
(u64Cmd & USAGE_LOADSYMS)
- ? " loadsyms <vmname>|<uuid> <symfile> [delta] [module] [module address]\n"
+ ? " loadsyms <vmname|uuid> <symfile> [delta] [module] [module address]\n"
" This will instruct DBGF to load the given symbol file\n"
" during initialization.\n"
"\n"
@@ -243,7 +243,7 @@ void printUsageInternal(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
"",
#endif
(u64Cmd & USAGE_DEBUGLOG)
- ? " debuglog <vmname>|<uuid> [--enable|--disable] [--flags todo]\n"
+ ? " debuglog <vmname|uuid> [--enable|--disable] [--flags todo]\n"
" [--groups todo] [--destinations todo]\n"
" Controls debug logging.\n"
"\n"
@@ -254,7 +254,7 @@ void printUsageInternal(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
"\n"
: "",
(u64Cmd & USAGE_GUESTSTATS)
- ? " gueststats <vmname>|<uuid> [--interval <seconds>]\n"
+ ? " gueststats <vmname|uuid> [--interval <seconds>]\n"
" Obtains and prints internal guest statistics.\n"
" Sets the update interval if specified.\n"
"\n"
@@ -672,7 +672,7 @@ static int CmdSetHDUUID(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox,
}
/* Open the image */
- rc = VDOpen(pDisk, pszFormat, argv[1], VD_OPEN_FLAGS_NORMAL, NULL);
+ rc = VDOpen(pDisk, pszFormat, argv[1], VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_INFO, NULL);
if (RT_FAILURE(rc))
{
RTMsgError("Cannot open the image: %Rrc", rc);
@@ -754,7 +754,7 @@ static int partRead(RTFILE File, PHOSTPARTITIONS pPart)
uint64_t lastUsableLBA = 0;
int rc;
- PARTITIONING_TYPE partitioningType;
+ VBOXHDDPARTTYPE partitioningType;
pPart->cPartitions = 0;
memset(pPart->aPartitions, '\0', sizeof(pPart->aPartitions));
@@ -2383,7 +2383,7 @@ int CmdDebugLog(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<I
break;
default:
- return errorGetOpt(USAGE_DEBUGLOG , ch, &ValueUnion);
+ return errorGetOpt(USAGE_DEBUGLOG, ch, &ValueUnion);
}
}
@@ -2453,7 +2453,7 @@ int CmdGuestStats(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr
break;
default:
- return errorGetOpt(USAGE_GUESTSTATS , ch, &ValueUnion);
+ return errorGetOpt(USAGE_GUESTSTATS, ch, &ValueUnion);
}
}
@@ -2522,7 +2522,7 @@ int handleInternalCommands(HandlerArg *a)
if (!strcmp(pszCmd, "loadsyms"))
return CmdLoadSyms(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
//if (!strcmp(pszCmd, "unloadsyms"))
- // return CmdUnloadSyms(argc - 1 , &a->argv[1]);
+ // return CmdUnloadSyms(argc - 1, &a->argv[1]);
if (!strcmp(pszCmd, "sethduuid") || !strcmp(pszCmd, "sethdparentuuid"))
return CmdSetHDUUID(a->argc, &a->argv[0], a->virtualBox, a->session);
if (!strcmp(pszCmd, "dumphdinfo"))
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManage.cpp b/src/VBox/Frontends/VBoxManage/VBoxManage.cpp
index 1d881aac..533b30fc 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManage.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManage.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -26,7 +26,7 @@
# include <VBox/com/array.h>
# include <VBox/com/ErrorInfo.h>
# include <VBox/com/errorprint.h>
-# include <VBox/com/EventQueue.h>
+# include <VBox/com/NativeEventQueue.h>
# include <VBox/com/VirtualBox.h>
#endif /* !VBOX_ONLY_DOCS */
@@ -90,7 +90,7 @@ HRESULT showProgress(ComPtr<IProgress> progress)
ULONG ulLastOperation = (ULONG)-1;
Bstr bstrOperationDescription;
- EventQueue::getMainEventQueue()->processEventQueue(0);
+ NativeEventQueue::getMainEventQueue()->processEventQueue(0);
ULONG cOperations = 1;
HRESULT hrc = progress->COMGETTER(OperationCount)(&cOperations);
@@ -159,7 +159,8 @@ HRESULT showProgress(ComPtr<IProgress> progress)
LONG lSecsRem = 0;
progress->COMGETTER(TimeRemaining)(&lSecsRem);
- RTStrmPrintf(g_pStdErr, "(%u/%u) %ls %02u%% => %02u%% (%d s remaining)\n", ulOperation + 1, cOperations, bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
+ RTStrmPrintf(g_pStdErr, "(%u/%u) %ls %02u%% => %02u%% (%d s remaining)\n", ulOperation + 1, cOperations,
+ bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
ulLastPercent = ulCurrentPercent;
ulLastOperationPercent = ulCurrentOperationPercent;
}
@@ -197,7 +198,7 @@ HRESULT showProgress(ComPtr<IProgress> progress)
/* make sure the loop is not too tight */
progress->WaitForCompletion(100);
- EventQueue::getMainEventQueue()->processEventQueue(0);
+ NativeEventQueue::getMainEventQueue()->processEventQueue(0);
hrc = progress->COMGETTER(Completed(&fCompleted));
}
@@ -331,7 +332,7 @@ int main(int argc, char *argv[])
if (i >= argc - 1)
{
showLogo(g_pStdOut);
- printUsage(USAGE_ALL, g_pStdOut);
+ printUsage(USAGE_ALL, ~0U, g_pStdOut);
return 0;
}
fShowLogo = true;
@@ -355,7 +356,7 @@ int main(int argc, char *argv[])
{
/* Special option to dump really all commands,
* even the ones not understood on this platform. */
- printUsage(USAGE_DUMPOPTS, g_pStdOut);
+ printUsage(USAGE_DUMPOPTS, ~0U, g_pStdOut);
return 0;
}
@@ -514,6 +515,9 @@ int main(int argc, char *argv[])
{ "hostonlyif", USAGE_HOSTONLYIFS, handleHostonlyIf },
#endif
{ "dhcpserver", USAGE_DHCPSERVER, handleDHCPServer},
+#ifdef VBOX_WITH_NAT_SERVICE
+ { "natnetwork", USAGE_NATNETWORK, handleNATNetwork},
+#endif
{ "extpack", USAGE_EXTPACK, handleExtPack},
{ "bandwidthctl", USAGE_BANDWIDTHCONTROL, handleBandwidthControl},
{ "debugvm", USAGE_DEBUGVM, handleDebugVM},
@@ -550,7 +554,7 @@ int main(int argc, char *argv[])
|| ( argc - iCmdArg == 0
&& s_commandHandlers[commandIndex].help))
{
- printUsage(s_commandHandlers[commandIndex].help, g_pStdOut);
+ printUsage(s_commandHandlers[commandIndex].help, ~0U, g_pStdOut);
rcExit = RTEXITCODE_FAILURE; /* error */
}
else
@@ -580,7 +584,7 @@ int main(int argc, char *argv[])
* state file (if the machine was in the Saved state before). */
session->UnlockMachine();
- EventQueue::getMainEventQueue()->processEventQueue(0);
+ NativeEventQueue::getMainEventQueue()->processEventQueue(0);
// end "all-stuff" scope
///////////////////////////////////////////////////////////////////////////
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManage.h b/src/VBox/Frontends/VBoxManage/VBoxManage.h
index e8f4214b..f2c23ee4 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManage.h
+++ b/src/VBox/Frontends/VBoxManage/VBoxManage.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -29,6 +29,7 @@
#include <iprt/types.h>
#include <iprt/message.h>
#include <iprt/stream.h>
+#include <iprt/getopt.h>
////////////////////////////////////////////////////////////////////////////////
//
@@ -101,9 +102,28 @@
#define USAGE_BANDWIDTHCONTROL RT_BIT_64(56)
#define USAGE_GUESTSTATS RT_BIT_64(57)
#define USAGE_REPAIRHD RT_BIT_64(58)
+#define USAGE_NATNETWORK RT_BIT_64(59)
#define USAGE_ALL (~(uint64_t)0)
/** @} */
+#ifdef VBOX_WITH_GUEST_CONTROL
+# define USAGE_GSTCTRL_EXEC RT_BIT(0)
+# define USAGE_GSTCTRL_COPYFROM RT_BIT(1)
+# define USAGE_GSTCTRL_COPYTO RT_BIT(2)
+# define USAGE_GSTCTRL_CREATEDIR RT_BIT(3)
+# define USAGE_GSTCTRL_REMOVEDIR RT_BIT(4)
+# define USAGE_GSTCTRL_REMOVEFILE RT_BIT(5)
+# define USAGE_GSTCTRL_RENAME RT_BIT(6)
+# define USAGE_GSTCTRL_CREATETEMP RT_BIT(7)
+# define USAGE_GSTCTRL_LIST RT_BIT(8)
+# define USAGE_GSTCTRL_PROCESS RT_BIT(9)
+# define USAGE_GSTCTRL_KILL RT_BIT(10)
+# define USAGE_GSTCTRL_SESSION RT_BIT(11)
+# define USAGE_GSTCTRL_STAT RT_BIT(12)
+# define USAGE_GSTCTRL_UPDATEADDS RT_BIT(13)
+# define USAGE_GSTCTRL_WATCH RT_BIT(14)
+#endif
+
typedef uint64_t USAGECATEGORY;
/** command handler argument */
@@ -146,12 +166,14 @@ extern bool g_fDetailedProgress; // in VBoxManage.cpp
////////////////////////////////////////////////////////////////////////////////
/* VBoxManageHelp.cpp */
-void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm);
-RTEXITCODE errorSyntax(USAGECATEGORY u64Cmd, const char *pszFormat, ...);
-RTEXITCODE errorGetOpt(USAGECATEGORY u64Cmd, int rc, union RTGETOPTUNION const *pValueUnion);
+void printUsage(USAGECATEGORY fCategory, uint32_t fSubCategory, PRTSTREAM pStrm);
+RTEXITCODE errorSyntax(USAGECATEGORY fCategory, const char *pszFormat, ...);
+RTEXITCODE errorSyntaxEx(USAGECATEGORY fCategory, uint32_t fSubCategory, const char *pszFormat, ...);
+RTEXITCODE errorGetOpt(USAGECATEGORY fCategory, int rc, union RTGETOPTUNION const *pValueUnion);
+RTEXITCODE errorGetOptEx(USAGECATEGORY fCategory, uint32_t fSubCategory, int rc, union RTGETOPTUNION const *pValueUnion);
RTEXITCODE errorArgument(const char *pszFormat, ...);
-void printUsageInternal(USAGECATEGORY u64Cmd, PRTSTREAM pStrm);
+void printUsageInternal(USAGECATEGORY fCategory, PRTSTREAM pStrm);
#ifndef VBOX_ONLY_DOCS
HRESULT showProgress(ComPtr<IProgress> progress);
@@ -185,7 +207,7 @@ int handleDebugVM(HandlerArg *a);
extern void usageGuestProperty(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2);
/* VBoxManageGuestCtrl.cpp */
-extern void usageGuestControl(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2);
+extern void usageGuestControl(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2, uint32_t fSubCategory);
#ifndef VBOX_ONLY_DOCS
/* VBoxManageGuestProp.cpp */
@@ -198,13 +220,13 @@ extern int handleGuestControl(HandlerArg *a);
HRESULT showSnapshots(ComPtr<ISnapshot> &rootSnapshot,
ComPtr<ISnapshot> &currentSnapshot,
VMINFO_DETAILS details,
- const com::Bstr &prefix = "",
+ const com::Utf8Str &prefix = "",
int level = 0);
int handleShowVMInfo(HandlerArg *a);
HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
ComPtr<IMachine> machine,
VMINFO_DETAILS details = VMINFO_NONE,
- ComPtr <IConsole> console = ComPtr<IConsole>());
+ ComPtr<IConsole> console = ComPtr<IConsole>());
const char *machineStateToName(MachineState_T machineState, bool fShort);
HRESULT showBandwidthGroups(ComPtr<IBandwidthControl> &bwCtrl,
VMINFO_DETAILS details);
@@ -230,17 +252,18 @@ int handleSharedFolder(HandlerArg *a);
int handleExtPack(HandlerArg *a);
/* VBoxManageDisk.cpp */
-HRESULT findMedium(HandlerArg *a, const char *pszFilenameOrUuid,
- DeviceType_T enmDevType, bool fSilent,
- ComPtr<IMedium> &pMedium);
-HRESULT findOrOpenMedium(HandlerArg *a, const char *pszFilenameOrUuid,
- DeviceType_T enmDevType, AccessMode_T enmAccessMode,
- ComPtr<IMedium> &pMedium, bool fForceNewUuidOnOpen,
- bool *pfWasUnknown);
+HRESULT openMedium(HandlerArg *a, const char *pszFilenameOrUuid,
+ DeviceType_T enmDevType, AccessMode_T enmAccessMode,
+ ComPtr<IMedium> &pMedium, bool fForceNewUuidOnOpen,
+ bool fSilent);
int handleCreateHardDisk(HandlerArg *a);
int handleModifyHardDisk(HandlerArg *a);
int handleCloneHardDisk(HandlerArg *a);
RTEXITCODE handleConvertFromRaw(int argc, char *argv[]);
+HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
+ const ComPtr<IMedium> &pMedium,
+ const char *pszParentUUID,
+ bool fOptLong);
int handleShowHardDiskInfo(HandlerArg *a);
int handleCloseMedium(HandlerArg *a);
int parseDiskType(const char *psz, MediumType_T *pDiskType);
@@ -263,9 +286,13 @@ int handleUSBFilter(HandlerArg *a);
/* VBoxManageHostonly.cpp */
int handleHostonlyIf(HandlerArg *a);
-/* VBoxManageHostonly.cpp */
+/* VBoxManageDHCPServer.cpp */
int handleDHCPServer(HandlerArg *a);
+/* VBoxManageNATNetwork.cpp */
+int handleNATNetwork(HandlerArg *a);
+
+
/* VBoxManageBandwidthControl.cpp */
int handleBandwidthControl(HandlerArg *a);
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageAppliance.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageAppliance.cpp
index 76c8be19..279bd447 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageAppliance.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageAppliance.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -27,8 +27,6 @@
#include <VBox/com/array.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
-
#include <VBox/com/VirtualBox.h>
#include <list>
@@ -376,13 +374,13 @@ int handleImportAppliance(HandlerArg *arg)
com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
com::SafeArray<BSTR> aRefs;
com::SafeArray<BSTR> aOvfValues;
- com::SafeArray<BSTR> aVboxValues;
+ com::SafeArray<BSTR> aVBoxValues;
com::SafeArray<BSTR> aExtraConfigValues;
CHECK_ERROR_BREAK(aVirtualSystemDescriptions[i],
GetDescription(ComSafeArrayAsOutParam(retTypes),
ComSafeArrayAsOutParam(aRefs),
ComSafeArrayAsOutParam(aOvfValues),
- ComSafeArrayAsOutParam(aVboxValues),
+ ComSafeArrayAsOutParam(aVBoxValues),
ComSafeArrayAsOutParam(aExtraConfigValues)));
RTPrintf("Virtual system %u:\n", i);
@@ -403,7 +401,7 @@ int handleImportAppliance(HandlerArg *arg)
Utf8Str strOverride;
- Bstr bstrFinalValue = aVboxValues[a];
+ Bstr bstrFinalValue = aVBoxValues[a];
bool fIgnoreThis = mapIgnoresMapsPerVsys[i][a];
@@ -439,27 +437,27 @@ int handleImportAppliance(HandlerArg *arg)
case VirtualSystemDescriptionType_Product:
RTPrintf("%2u: Product (ignored): %ls\n",
- a, aVboxValues[a]);
+ a, aVBoxValues[a]);
break;
case VirtualSystemDescriptionType_ProductUrl:
RTPrintf("%2u: ProductUrl (ignored): %ls\n",
- a, aVboxValues[a]);
+ a, aVBoxValues[a]);
break;
case VirtualSystemDescriptionType_Vendor:
RTPrintf("%2u: Vendor (ignored): %ls\n",
- a, aVboxValues[a]);
+ a, aVBoxValues[a]);
break;
case VirtualSystemDescriptionType_VendorUrl:
RTPrintf("%2u: VendorUrl (ignored): %ls\n",
- a, aVboxValues[a]);
+ a, aVBoxValues[a]);
break;
case VirtualSystemDescriptionType_Version:
RTPrintf("%2u: Version (ignored): %ls\n",
- a, aVboxValues[a]);
+ a, aVBoxValues[a]);
break;
case VirtualSystemDescriptionType_Description:
@@ -552,14 +550,14 @@ int handleImportAppliance(HandlerArg *arg)
{
RTPrintf("%2u: IDE controller, type %ls -- disabled\n",
a,
- aVboxValues[a]);
+ aVBoxValues[a]);
aEnabled[a] = false;
}
else
RTPrintf("%2u: IDE controller, type %ls"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a,
- aVboxValues[a],
+ aVBoxValues[a],
i, a);
break;
@@ -568,14 +566,14 @@ int handleImportAppliance(HandlerArg *arg)
{
RTPrintf("%2u: SATA controller, type %ls -- disabled\n",
a,
- aVboxValues[a]);
+ aVBoxValues[a]);
aEnabled[a] = false;
}
else
RTPrintf("%2u: SATA controller, type %ls"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a,
- aVboxValues[a],
+ aVBoxValues[a],
i, a);
break;
@@ -584,14 +582,14 @@ int handleImportAppliance(HandlerArg *arg)
{
RTPrintf("%2u: SAS controller, type %ls -- disabled\n",
a,
- aVboxValues[a]);
+ aVBoxValues[a]);
aEnabled[a] = false;
}
else
RTPrintf("%2u: SAS controller, type %ls"
"\n (disable with \"--vsys %u --unit %u --ignore\")\n",
a,
- aVboxValues[a],
+ aVBoxValues[a],
i, a);
break;
@@ -600,7 +598,7 @@ int handleImportAppliance(HandlerArg *arg)
{
RTPrintf("%2u: SCSI controller, type %ls -- disabled\n",
a,
- aVboxValues[a]);
+ aVBoxValues[a]);
aEnabled[a] = false;
}
else
@@ -619,7 +617,7 @@ int handleImportAppliance(HandlerArg *arg)
"\n (change with \"--vsys %u --unit %u --scsitype {BusLogic|LsiLogic}\";"
"\n disable with \"--vsys %u --unit %u --ignore\")\n",
a,
- aVboxValues[a],
+ aVBoxValues[a],
i, a, i, a);
}
break;
@@ -673,7 +671,7 @@ int handleImportAppliance(HandlerArg *arg)
RTPrintf("%2u: Hard disk image: source image=%ls, target path=%ls, %ls\n",
a,
aOvfValues[a],
- aVboxValues[a],
+ aVBoxValues[a],
aExtraConfigValues[a]);
}
#endif
@@ -683,7 +681,7 @@ int handleImportAppliance(HandlerArg *arg)
"\n disable with \"--vsys %u --unit %u --ignore\")\n",
a,
aOvfValues[a],
- aVboxValues[a],
+ aVBoxValues[a],
aExtraConfigValues[a],
i, a, i, a);
}
@@ -719,7 +717,7 @@ int handleImportAppliance(HandlerArg *arg)
RTPrintf("%2u: Network adapter: orig %ls, config %ls, extra %ls\n", // @todo implement once we have a plan for the back-end
a,
aOvfValues[a],
- aVboxValues[a],
+ aVBoxValues[a],
aExtraConfigValues[a]);
break;
@@ -789,23 +787,67 @@ int handleImportAppliance(HandlerArg *arg)
return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
-static const RTGETOPTDEF g_aExportOptions[]
- = {
- { "--output", 'o', RTGETOPT_REQ_STRING },
- { "--legacy09", 'l', RTGETOPT_REQ_NOTHING },
- { "--ovf09", 'l', RTGETOPT_REQ_NOTHING },
- { "--ovf10", '1', RTGETOPT_REQ_NOTHING },
- { "--ovf20", '2', RTGETOPT_REQ_NOTHING },
- { "--manifest", 'm', RTGETOPT_REQ_NOTHING },
- { "--vsys", 's', RTGETOPT_REQ_UINT32 },
- { "--product", 'p', RTGETOPT_REQ_STRING },
- { "--producturl", 'P', RTGETOPT_REQ_STRING },
- { "--vendor", 'd', RTGETOPT_REQ_STRING },
- { "--vendorurl", 'D', RTGETOPT_REQ_STRING },
- { "--version", 'v', RTGETOPT_REQ_STRING },
- { "--eula", 'e', RTGETOPT_REQ_STRING },
- { "--eulafile", 'E', RTGETOPT_REQ_STRING },
- };
+static int parseExportOptions(const char *psz, com::SafeArray<ExportOptions_T> *options)
+{
+ int rc = VINF_SUCCESS;
+ while (psz && *psz && RT_SUCCESS(rc))
+ {
+ size_t len;
+ const char *pszComma = strchr(psz, ',');
+ if (pszComma)
+ len = pszComma - psz;
+ else
+ len = strlen(psz);
+ if (len > 0)
+ {
+ if (!RTStrNICmp(psz, "CreateManifest", len))
+ options->push_back(ExportOptions_CreateManifest);
+ else if (!RTStrNICmp(psz, "manifest", len))
+ options->push_back(ExportOptions_CreateManifest);
+ else if (!RTStrNICmp(psz, "ExportDVDImages", len))
+ options->push_back(ExportOptions_ExportDVDImages);
+ else if (!RTStrNICmp(psz, "iso", len))
+ options->push_back(ExportOptions_ExportDVDImages);
+ else if (!RTStrNICmp(psz, "StripAllMACs", len))
+ options->push_back(ExportOptions_StripAllMACs);
+ else if (!RTStrNICmp(psz, "nomacs", len))
+ options->push_back(ExportOptions_StripAllMACs);
+ else if (!RTStrNICmp(psz, "StripAllNonNATMACs", len))
+ options->push_back(ExportOptions_StripAllNonNATMACs);
+ else if (!RTStrNICmp(psz, "nomacsbutnat", len))
+ options->push_back(ExportOptions_StripAllNonNATMACs);
+ else
+ rc = VERR_PARSE_ERROR;
+ }
+ if (pszComma)
+ psz += len + 1;
+ else
+ psz += len;
+ }
+
+ return rc;
+}
+
+static const RTGETOPTDEF g_aExportOptions[] =
+{
+ { "--output", 'o', RTGETOPT_REQ_STRING },
+ { "--legacy09", 'l', RTGETOPT_REQ_NOTHING },
+ { "--ovf09", 'l', RTGETOPT_REQ_NOTHING },
+ { "--ovf10", '1', RTGETOPT_REQ_NOTHING },
+ { "--ovf20", '2', RTGETOPT_REQ_NOTHING },
+ { "--manifest", 'm', RTGETOPT_REQ_NOTHING }, // obsoleted by --options
+ { "--iso", 'I', RTGETOPT_REQ_NOTHING }, // obsoleted by --options
+ { "--vsys", 's', RTGETOPT_REQ_UINT32 },
+ { "--product", 'p', RTGETOPT_REQ_STRING },
+ { "--producturl", 'P', RTGETOPT_REQ_STRING },
+ { "--vendor", 'n', RTGETOPT_REQ_STRING },
+ { "--vendorurl", 'N', RTGETOPT_REQ_STRING },
+ { "--version", 'v', RTGETOPT_REQ_STRING },
+ { "--description", 'd', RTGETOPT_REQ_STRING },
+ { "--eula", 'e', RTGETOPT_REQ_STRING },
+ { "--eulafile", 'E', RTGETOPT_REQ_STRING },
+ { "--options", 'O', RTGETOPT_REQ_STRING },
+};
int handleExportAppliance(HandlerArg *a)
{
@@ -814,6 +856,8 @@ int handleExportAppliance(HandlerArg *a)
Utf8Str strOutputFile;
Utf8Str strOvfFormat("ovf-1.0"); // the default export version
bool fManifest = false; // the default
+ bool fExportISOImages = false; // the default
+ com::SafeArray<ExportOptions_T> options;
std::list< ComPtr<IMachine> > llMachines;
uint32_t ulCurVsys = (uint32_t)-1;
@@ -842,66 +886,81 @@ int handleExportAppliance(HandlerArg *a)
break;
case 'l': // --legacy09/--ovf09
- strOvfFormat = "ovf-0.9";
- break;
+ strOvfFormat = "ovf-0.9";
+ break;
case '1': // --ovf10
- strOvfFormat = "ovf-1.0";
- break;
+ strOvfFormat = "ovf-1.0";
+ break;
case '2': // --ovf20
- strOvfFormat = "ovf-2.0";
- break;
+ strOvfFormat = "ovf-2.0";
+ break;
+
+ case 'I': // --iso
+ fExportISOImages = true;
+ break;
case 'm': // --manifest
- fManifest = true;
- break;
+ fManifest = true;
+ break;
case 's': // --vsys
- ulCurVsys = ValueUnion.u32;
- break;
+ ulCurVsys = ValueUnion.u32;
+ break;
case 'p': // --product
- if (ulCurVsys == (uint32_t)-1)
- return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
- mapArgsMapsPerVsys[ulCurVsys]["product"] = ValueUnion.psz;
- break;
+ if (ulCurVsys == (uint32_t)-1)
+ return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
+ mapArgsMapsPerVsys[ulCurVsys]["product"] = ValueUnion.psz;
+ break;
case 'P': // --producturl
- if (ulCurVsys == (uint32_t)-1)
- return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
- mapArgsMapsPerVsys[ulCurVsys]["producturl"] = ValueUnion.psz;
- break;
-
- case 'd': // --vendor
- if (ulCurVsys == (uint32_t)-1)
- return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
- mapArgsMapsPerVsys[ulCurVsys]["vendor"] = ValueUnion.psz;
- break;
-
- case 'D': // --vendorurl
- if (ulCurVsys == (uint32_t)-1)
- return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
- mapArgsMapsPerVsys[ulCurVsys]["vendorurl"] = ValueUnion.psz;
- break;
+ if (ulCurVsys == (uint32_t)-1)
+ return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
+ mapArgsMapsPerVsys[ulCurVsys]["producturl"] = ValueUnion.psz;
+ break;
+
+ case 'n': // --vendor
+ if (ulCurVsys == (uint32_t)-1)
+ return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
+ mapArgsMapsPerVsys[ulCurVsys]["vendor"] = ValueUnion.psz;
+ break;
+
+ case 'N': // --vendorurl
+ if (ulCurVsys == (uint32_t)-1)
+ return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
+ mapArgsMapsPerVsys[ulCurVsys]["vendorurl"] = ValueUnion.psz;
+ break;
case 'v': // --version
- if (ulCurVsys == (uint32_t)-1)
- return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
- mapArgsMapsPerVsys[ulCurVsys]["version"] = ValueUnion.psz;
- break;
+ if (ulCurVsys == (uint32_t)-1)
+ return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
+ mapArgsMapsPerVsys[ulCurVsys]["version"] = ValueUnion.psz;
+ break;
+
+ case 'd': // --description
+ if (ulCurVsys == (uint32_t)-1)
+ return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
+ mapArgsMapsPerVsys[ulCurVsys]["description"] = ValueUnion.psz;
+ break;
case 'e': // --eula
- if (ulCurVsys == (uint32_t)-1)
- return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
- mapArgsMapsPerVsys[ulCurVsys]["eula"] = ValueUnion.psz;
- break;
+ if (ulCurVsys == (uint32_t)-1)
+ return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
+ mapArgsMapsPerVsys[ulCurVsys]["eula"] = ValueUnion.psz;
+ break;
case 'E': // --eulafile
- if (ulCurVsys == (uint32_t)-1)
- return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
- mapArgsMapsPerVsys[ulCurVsys]["eulafile"] = ValueUnion.psz;
- break;
+ if (ulCurVsys == (uint32_t)-1)
+ return errorSyntax(USAGE_EXPORTAPPLIANCE, "Option \"%s\" requires preceding --vsys argument.", GetState.pDef->pszLong);
+ mapArgsMapsPerVsys[ulCurVsys]["eulafile"] = ValueUnion.psz;
+ break;
+
+ case 'O': // --options
+ if (RT_FAILURE(parseExportOptions(ValueUnion.psz, &options)))
+ return errorArgument("Invalid export options '%s'\n", ValueUnion.psz);
+ break;
case VINF_GETOPT_NOT_OPTION:
{
@@ -976,7 +1035,7 @@ int handleExportAppliance(HandlerArg *a)
{
ComPtr<IMachine> pMachine = *itM;
ComPtr<IVirtualSystemDescription> pVSD;
- CHECK_ERROR_BREAK(pMachine, Export(pAppliance, Bstr(pszAbsFilePath).raw(), pVSD.asOutParam()));
+ CHECK_ERROR_BREAK(pMachine, ExportTo(pAppliance, Bstr(pszAbsFilePath).raw(), pVSD.asOutParam()));
// Add additional info to the virtual system description if the user wants so
ArgsMap *pmapArgs = NULL;
ArgsMapsMap::iterator itm = mapArgsMapsPerVsys.find(i);
@@ -1009,6 +1068,10 @@ int handleExportAppliance(HandlerArg *a)
pVSD->AddDescription(VirtualSystemDescriptionType_Version,
Bstr(itD->second).raw(),
Bstr(itD->second).raw());
+ else if (itD->first == "description")
+ pVSD->AddDescription(VirtualSystemDescriptionType_Description,
+ Bstr(itD->second).raw(),
+ Bstr(itD->second).raw());
else if (itD->first == "eula")
pVSD->AddDescription(VirtualSystemDescriptionType_License,
Bstr(itD->second).raw(),
@@ -1021,7 +1084,7 @@ int handleExportAppliance(HandlerArg *a)
int irc = RTFileReadAll(itD->second.c_str(), &pvFile, &cbFile);
if (RT_SUCCESS(irc))
{
- Bstr bstrContent((char*)pvFile);
+ Bstr bstrContent((char*)pvFile, cbFile);
pVSD->AddDescription(VirtualSystemDescriptionType_License,
bstrContent.raw(),
bstrContent.raw());
@@ -1041,9 +1104,15 @@ int handleExportAppliance(HandlerArg *a)
if (FAILED(rc))
break;
+ if (fManifest)
+ options.push_back(ExportOptions_CreateManifest);
+
+ if (fExportISOImages)
+ options.push_back(ExportOptions_ExportDVDImages);
+
ComPtr<IProgress> progress;
CHECK_ERROR_BREAK(pAppliance, Write(Bstr(strOvfFormat).raw(),
- fManifest,
+ ComSafeArrayAsInParam(options),
Bstr(pszAbsFilePath).raw(),
progress.asOutParam()));
RTStrFree(pszAbsFilePath);
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageBandwidthControl.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageBandwidthControl.cpp
index 6e708f9c..2765372b 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageBandwidthControl.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageBandwidthControl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -107,6 +107,12 @@ static RTEXITCODE handleBandwidthControlAdd(HandlerArg *a, ComPtr<IBandwidthCont
Bstr name(a->argv[2]);
+ if (name.isEmpty())
+ {
+ errorArgument("Bandwidth group name must not be empty!\n");
+ return RTEXITCODE_FAILURE;
+ }
+
const char *pszType = NULL;
int64_t cMaxBytesPerSec = INT64_MAX;
@@ -166,7 +172,7 @@ static RTEXITCODE handleBandwidthControlAdd(HandlerArg *a, ComPtr<IBandwidthCont
errorArgument("Invalid bandwidth group type\n");
return RTEXITCODE_FAILURE;
}
-
+
CHECK_ERROR2_RET(bwCtrl, CreateBandwidthGroup(name.raw(), enmType, (LONG64)cMaxBytesPerSec), RTEXITCODE_FAILURE);
return RTEXITCODE_SUCCESS;
@@ -226,7 +232,7 @@ static RTEXITCODE handleBandwidthControlSet(HandlerArg *a, ComPtr<IBandwidthCont
}
}
-
+
if (cMaxBytesPerSec != INT64_MAX)
{
ComPtr<IBandwidthGroup> bwGroup;
@@ -274,8 +280,11 @@ static RTEXITCODE handleBandwidthControlList(HandlerArg *pArgs, ComPtr<IBandwidt
{
switch (c)
{
- case 'M': enmDetails = VMINFO_MACHINEREADABLE; break;
- default: return errorGetOpt(USAGE_BANDWIDTHCONTROL, c, &ValueUnion);
+ case 'M':
+ enmDetails = VMINFO_MACHINEREADABLE;
+ break;
+ default:
+ return errorGetOpt(USAGE_BANDWIDTHCONTROL, c, &ValueUnion);
}
}
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp
index e75310f1..31982d06 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -25,8 +25,6 @@
#include <VBox/com/array.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
-
#include <VBox/com/VirtualBox.h>
#include <iprt/ctype.h>
@@ -66,7 +64,7 @@ static unsigned parseNum(const char *psz, unsigned cMaxNum, const char *name)
unsigned int getMaxNics(IVirtualBox* vbox, IMachine* mach)
{
- ComPtr <ISystemProperties> info;
+ ComPtr<ISystemProperties> info;
ChipsetType_T aChipset;
ULONG NetworkAdapterCount = 0;
HRESULT rc;
@@ -92,7 +90,7 @@ int handleControlVM(HandlerArg *a)
return errorSyntax(USAGE_CONTROLVM, "Not enough parameters");
/* try to find the given machine */
- ComPtr <IMachine> machine;
+ ComPtr<IMachine> machine;
CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
machine.asOutParam()));
if (FAILED(rc))
@@ -283,8 +281,14 @@ int handleControlVM(HandlerArg *a)
}
else if (!strcmp(a->argv[1], "keyboardputscancode"))
{
- ComPtr<IKeyboard> keyboard;
- CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(keyboard.asOutParam()));
+ ComPtr<IKeyboard> pKeyboard;
+ CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
+ if (!pKeyboard)
+ {
+ RTMsgError("Guest not running");
+ rc = E_FAIL;
+ break;
+ }
if (a->argc <= 1 + 1)
{
@@ -328,7 +332,7 @@ int handleControlVM(HandlerArg *a)
/* Send scancodes to the VM. */
com::SafeArray<LONG> saScancodes(llScancodes);
ULONG codesStored = 0;
- CHECK_ERROR_BREAK(keyboard, PutScancodes(ComSafeArrayAsInParam(saScancodes),
+ CHECK_ERROR_BREAK(pKeyboard, PutScancodes(ComSafeArrayAsInParam(saScancodes),
&codesStored));
if (codesStored < saScancodes.size())
{
@@ -620,6 +624,53 @@ int handleControlVM(HandlerArg *a)
RTMsgError("The NIC %d is currently disabled and thus its properties can't be changed", n);
}
}
+ else if (!strncmp(a->argv[1], "nicpromisc", 10))
+ {
+ /* Get the number of network adapters */
+ ULONG NetworkAdapterCount = getMaxNics(a->virtualBox,sessionMachine) ;
+ unsigned n = parseNum(&a->argv[1][10], NetworkAdapterCount, "NIC");
+ if (!n)
+ {
+ rc = E_FAIL;
+ break;
+ }
+ if (a->argc <= 2)
+ {
+ errorArgument("Missing argument to '%s'", a->argv[1]);
+ rc = E_FAIL;
+ break;
+ }
+
+ /* get the corresponding network adapter */
+ ComPtr<INetworkAdapter> adapter;
+ CHECK_ERROR_BREAK(sessionMachine, GetNetworkAdapter(n - 1, adapter.asOutParam()));
+ if (adapter)
+ {
+ BOOL fEnabled;
+ adapter->COMGETTER(Enabled)(&fEnabled);
+ if (fEnabled)
+ {
+ NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
+ if (!strcmp(a->argv[2], "deny"))
+ enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
+ else if ( !strcmp(a->argv[2], "allow-vms")
+ || !strcmp(a->argv[2], "allow-network"))
+ enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
+ else if (!strcmp(a->argv[2], "allow-all"))
+ enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
+ else
+ {
+ errorArgument("Unknown promiscuous mode policy '%s'", a->argv[2]);
+ rc = E_INVALIDARG;
+ break;
+ }
+
+ CHECK_ERROR(adapter, COMSETTER(PromiscModePolicy)(enmPromiscModePolicy));
+ }
+ else
+ RTMsgError("The NIC %d is currently disabled and thus its promiscuous mode can't be changed", n);
+ }
+ }
else if (!strncmp(a->argv[1], "nic", 3))
{
/* Get the number of network adapters */
@@ -709,6 +760,18 @@ int handleControlVM(HandlerArg *a)
CHECK_ERROR_RET(adapter, COMSETTER(GenericDriver)(Bstr(a->argv[3]).raw()), 1);
CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic), 1);
}
+ else if (!strcmp(a->argv[2], "natnetwork"))
+ {
+ if (a->argc <= 3)
+ {
+ errorArgument("Missing argument to '%s'", a->argv[2]);
+ rc = E_FAIL;
+ break;
+ }
+ CHECK_ERROR_RET(adapter, COMSETTER(Enabled)(TRUE), 1);
+ CHECK_ERROR_RET(adapter, COMSETTER(NATNetwork)(Bstr(a->argv[3]).raw()), 1);
+ CHECK_ERROR_RET(adapter, COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork), 1);
+ }
/** @todo obsolete, remove eventually */
else if (!strcmp(a->argv[2], "vde"))
{
@@ -873,16 +936,18 @@ int handleControlVM(HandlerArg *a)
bool attach = !strcmp(a->argv[1], "usbattach");
Bstr usbId = a->argv[2];
- if (Guid(usbId).isEmpty())
+
+ Guid guid(usbId);
+ if (!guid.isValid())
{
// assume address
if (attach)
{
- ComPtr <IHost> host;
+ ComPtr<IHost> host;
CHECK_ERROR_BREAK(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
SafeIfaceArray <IHostUSBDevice> coll;
CHECK_ERROR_BREAK(host, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
- ComPtr <IHostUSBDevice> dev;
+ ComPtr<IHostUSBDevice> dev;
CHECK_ERROR_BREAK(host, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
dev.asOutParam()));
CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
@@ -891,18 +956,24 @@ int handleControlVM(HandlerArg *a)
{
SafeIfaceArray <IUSBDevice> coll;
CHECK_ERROR_BREAK(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)));
- ComPtr <IUSBDevice> dev;
+ ComPtr<IUSBDevice> dev;
CHECK_ERROR_BREAK(console, FindUSBDeviceByAddress(Bstr(a->argv[2]).raw(),
dev.asOutParam()));
CHECK_ERROR_BREAK(dev, COMGETTER(Id)(usbId.asOutParam()));
}
}
+ else if (guid.isZero())
+ {
+ errorArgument("Zero UUID argument '%s'", a->argv[2]);
+ rc = E_FAIL;
+ break;
+ }
if (attach)
CHECK_ERROR_BREAK(console, AttachUSBDevice(usbId.raw()));
else
{
- ComPtr <IUSBDevice> dev;
+ ComPtr<IUSBDevice> dev;
CHECK_ERROR_BREAK(console, DetachUSBDevice(usbId.raw(),
dev.asOutParam()));
}
@@ -943,11 +1014,17 @@ int handleControlVM(HandlerArg *a)
fChangeOrigin = true;
}
- ComPtr<IDisplay> display;
- CHECK_ERROR_BREAK(console, COMGETTER(Display)(display.asOutParam()));
- CHECK_ERROR_BREAK(display, SetVideoModeHint(uDisplayIdx, fEnabled,
- fChangeOrigin, iOriginX, iOriginY,
- uXRes, uYRes, uBpp));
+ ComPtr<IDisplay> pDisplay;
+ CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
+ if (!pDisplay)
+ {
+ RTMsgError("Guest not running");
+ rc = E_FAIL;
+ break;
+ }
+ CHECK_ERROR_BREAK(pDisplay, SetVideoModeHint(uDisplayIdx, fEnabled,
+ fChangeOrigin, iOriginX, iOriginY,
+ uXRes, uYRes, uBpp));
}
else if (!strcmp(a->argv[1], "setcredentials"))
{
@@ -993,12 +1070,18 @@ int handleControlVM(HandlerArg *a)
domain = a->argv[5];
}
- ComPtr<IGuest> guest;
- CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
- CHECK_ERROR_BREAK(guest, SetCredentials(Bstr(a->argv[2]).raw(),
- Bstr(passwd).raw(),
- Bstr(domain).raw(),
- fAllowLocalLogon));
+ ComPtr<IGuest> pGuest;
+ CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest.asOutParam()));
+ if (!pGuest)
+ {
+ RTMsgError("Guest not running");
+ rc = E_FAIL;
+ break;
+ }
+ CHECK_ERROR_BREAK(pGuest, SetCredentials(Bstr(a->argv[2]).raw(),
+ Bstr(passwd).raw(),
+ Bstr(domain).raw(),
+ fAllowLocalLogon));
}
#if 0 /* TODO: review & remove */
else if (!strcmp(a->argv[1], "dvdattach"))
@@ -1140,10 +1223,18 @@ int handleControlVM(HandlerArg *a)
break;
}
/* guest is running; update IGuest */
- ComPtr <IGuest> guest;
- rc = console->COMGETTER(Guest)(guest.asOutParam());
+ ComPtr<IGuest> pGuest;
+ rc = console->COMGETTER(Guest)(pGuest.asOutParam());
if (SUCCEEDED(rc))
- CHECK_ERROR(guest, COMSETTER(MemoryBalloonSize)(uVal));
+ {
+ if (!pGuest)
+ {
+ RTMsgError("Guest not running");
+ rc = E_FAIL;
+ break;
+ }
+ CHECK_ERROR(pGuest, COMSETTER(MemoryBalloonSize)(uVal));
+ }
}
else if (!strcmp(a->argv[1], "teleport"))
{
@@ -1219,10 +1310,10 @@ int handleControlVM(HandlerArg *a)
break;
}
int vrc;
- uint32_t displayIdx = 0;
+ uint32_t iScreen = 0;
if (a->argc == 4)
{
- vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &displayIdx);
+ vrc = RTStrToUInt32Ex(a->argv[3], NULL, 0, &iScreen);
if (vrc != VINF_SUCCESS)
{
errorArgument("Error parsing display number '%s'", a->argv[3]);
@@ -1232,10 +1323,17 @@ int handleControlVM(HandlerArg *a)
}
ComPtr<IDisplay> pDisplay;
CHECK_ERROR_BREAK(console, COMGETTER(Display)(pDisplay.asOutParam()));
+ if (!pDisplay)
+ {
+ RTMsgError("Guest not running");
+ rc = E_FAIL;
+ break;
+ }
ULONG width, height, bpp;
- CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(displayIdx, &width, &height, &bpp));
+ LONG xOrigin, yOrigin;
+ CHECK_ERROR_BREAK(pDisplay, GetScreenResolution(iScreen, &width, &height, &bpp, &xOrigin, &yOrigin));
com::SafeArray<BYTE> saScreenshot;
- CHECK_ERROR_BREAK(pDisplay, TakeScreenShotPNGToArray(displayIdx, width, height, ComSafeArrayAsOutParam(saScreenshot)));
+ CHECK_ERROR_BREAK(pDisplay, TakeScreenShotPNGToArray(iScreen, width, height, ComSafeArrayAsOutParam(saScreenshot)));
RTFILE pngFile = NIL_RTFILE;
vrc = RTFileOpen(&pngFile, a->argv[2], RTFILE_O_OPEN_CREATE | RTFILE_O_WRITE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_ALL);
if (RT_FAILURE(vrc))
@@ -1252,6 +1350,127 @@ int handleControlVM(HandlerArg *a)
}
RTFileClose(pngFile);
}
+ else if ( !strcmp(a->argv[1], "vcpenabled"))
+ {
+ if (a->argc != 3)
+ {
+ errorArgument("Missing argument to '%s'", a->argv[1]);
+ rc = E_FAIL;
+ break;
+ }
+ if (!strcmp(a->argv[2], "on"))
+ {
+ CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(TRUE), 1);
+ }
+ else if (!strcmp(a->argv[2], "off"))
+ {
+ CHECK_ERROR_RET(sessionMachine, COMSETTER(VideoCaptureEnabled)(FALSE), 1);
+ }
+ else
+ {
+ errorArgument("Invalid state '%s'", Utf8Str(a->argv[2]).c_str());
+ rc = E_FAIL;
+ break;
+ }
+ }
+ else if ( !strcmp(a->argv[1], "videocapturescreens"))
+ {
+ ULONG cMonitors = 64;
+ CHECK_ERROR_BREAK(machine, COMGETTER(MonitorCount)(&cMonitors));
+ com::SafeArray<BOOL> saScreens(cMonitors);
+ if ( a->argc == 3
+ && !strcmp(a->argv[2], "all"))
+ {
+ /* enable all screens */
+ for (unsigned i = 0; i < cMonitors; i++)
+ saScreens[i] = true;
+ }
+ else if ( a->argc == 3
+ && !strcmp(a->argv[2], "none"))
+ {
+ /* disable all screens */
+ for (unsigned i = 0; i < cMonitors; i++)
+ saScreens[i] = false;
+ }
+ else
+ {
+ /* enable selected screens */
+ for (unsigned i = 0; i < cMonitors; i++)
+ saScreens[i] = false;
+ for (int i = 2; SUCCEEDED(rc) && i < a->argc; i++)
+ {
+ uint32_t iScreen;
+ int vrc = RTStrToUInt32Ex(a->argv[i], NULL, 0, &iScreen);
+ if (vrc != VINF_SUCCESS)
+ {
+ errorArgument("Error parsing display number '%s'", a->argv[i]);
+ rc = E_FAIL;
+ break;
+ }
+ if (iScreen >= cMonitors)
+ {
+ errorArgument("Invalid screen ID specified '%u'", iScreen);
+ rc = E_FAIL;
+ break;
+ }
+ saScreens[iScreen] = true;
+ }
+ }
+
+ CHECK_ERROR_BREAK(sessionMachine, COMSETTER(VideoCaptureScreens)(ComSafeArrayAsInParam(saScreens)));
+ }
+ else if (!strcmp(a->argv[1], "webcam"))
+ {
+ if (a->argc < 3)
+ {
+ errorArgument("Missing argument to '%s'", a->argv[1]);
+ rc = E_FAIL;
+ break;
+ }
+
+ ComPtr<IEmulatedUSB> pEmulatedUSB;
+ CHECK_ERROR_BREAK(console, COMGETTER(EmulatedUSB)(pEmulatedUSB.asOutParam()));
+ if (!pEmulatedUSB)
+ {
+ RTMsgError("Guest not running");
+ rc = E_FAIL;
+ break;
+ }
+
+ if (!strcmp(a->argv[2], "attach"))
+ {
+ Bstr path("");
+ if (a->argc >= 4)
+ path = a->argv[3];
+ Bstr settings("");
+ if (a->argc >= 5)
+ settings = a->argv[4];
+ CHECK_ERROR_BREAK(pEmulatedUSB, WebcamAttach(path.raw(), settings.raw()));
+ }
+ else if (!strcmp(a->argv[2], "detach"))
+ {
+ Bstr path("");
+ if (a->argc >= 4)
+ path = a->argv[3];
+ CHECK_ERROR_BREAK(pEmulatedUSB, WebcamDetach(path.raw()));
+ }
+ else if (!strcmp(a->argv[2], "list"))
+ {
+ com::SafeArray <BSTR> webcams;
+ CHECK_ERROR_BREAK(pEmulatedUSB, COMGETTER(Webcams)(ComSafeArrayAsOutParam(webcams)));
+ for (size_t i = 0; i < webcams.size(); ++i)
+ {
+ RTPrintf("%ls\n", webcams[i][0]? webcams[i]: Bstr("default").raw());
+ }
+ }
+ else
+ {
+ errorArgument("Invalid argument to '%s'", a->argv[1]);
+ rc = E_FAIL;
+ break;
+ }
+
+ }
else
{
errorSyntax(USAGE_CONTROLVM, "Invalid parameter '%s'", a->argv[1]);
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageDHCPServer.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageDHCPServer.cpp
index 68ef44fc..e680cfe0 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageDHCPServer.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageDHCPServer.cpp
@@ -23,8 +23,6 @@
#include <VBox/com/array.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
-
#include <VBox/com/VirtualBox.h>
#endif /* !VBOX_ONLY_DOCS */
@@ -41,6 +39,10 @@
#include "VBoxManage.h"
+#include <string>
+#include <vector>
+#include <map>
+
#ifndef VBOX_ONLY_DOCS
using namespace com;
@@ -51,6 +53,37 @@ typedef enum enMainOpCodes
OP_MODIFY
} OPCODE;
+typedef std::map<DhcpOpt_T, std::string> DhcpOptMap;
+typedef DhcpOptMap::iterator DhcpOptIterator;
+typedef DhcpOptMap::value_type DhcpOptValuePair;
+
+struct VmNameSlotKey;
+typedef struct VmNameSlotKey VmNameSlotKey;
+
+struct VmNameSlotKey
+{
+ std::string VmName;
+ uint8_t u8Slot;
+
+ VmNameSlotKey(std::string aVmName, uint8_t aSlot) :
+ VmName(aVmName),
+ u8Slot(aSlot) {}
+
+ bool operator< (const VmNameSlotKey& that) const
+ {
+ if (VmName == that.VmName)
+ return u8Slot < that.u8Slot;
+ else
+ return VmName < that.VmName;
+ }
+};
+
+typedef std::map<VmNameSlotKey, DhcpOptMap> VmSlot2OptionsM;
+typedef VmSlot2OptionsM::iterator VmSlot2OptionsIterator;
+typedef VmSlot2OptionsM::value_type VmSlot2OptionsPair;
+
+typedef std::vector<VmNameSlotKey> VmConfigs;
+
static const RTGETOPTDEF g_aDHCPIPOptions[]
= {
{ "--netname", 't', RTGETOPT_REQ_STRING }, /* we use 't' instead of 'n' to avoid
@@ -73,7 +106,13 @@ static const RTGETOPTDEF g_aDHCPIPOptions[]
{ "--enable", 'e', RTGETOPT_REQ_NOTHING },
{ "-enable", 'e', RTGETOPT_REQ_NOTHING }, // deprecated
{ "--disable", 'd', RTGETOPT_REQ_NOTHING },
- { "-disable", 'd', RTGETOPT_REQ_NOTHING } // deprecated
+ { "-disable", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
+ { "--options", 'o', RTGETOPT_REQ_NOTHING },
+ {"--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
+ {"--slot", 's', RTGETOPT_REQ_UINT8}, /* only with -o and -n */
+ {"--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
+ {"--value", 'p', RTGETOPT_REQ_STRING} /* only with -i */
+
};
static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
@@ -83,15 +122,26 @@ static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
int index = iStart;
HRESULT rc;
+ bool fOptionsRead = false;
+ bool fVmOptionRead = false;
+ const char *pszVmName = NULL;
const char *pNetName = NULL;
const char *pIfName = NULL;
const char * pIp = NULL;
const char * pNetmask = NULL;
const char * pLowerIp = NULL;
const char * pUpperIp = NULL;
+
+ uint8_t u8OptId = (uint8_t)~0;
+ uint8_t u8Slot = (uint8_t)~0;
+
int enable = -1;
+ DhcpOptMap GlobalDhcpOptions;
+ VmSlot2OptionsM VmSlot2Options;
+ VmConfigs VmConfigs2Delete;
+
int c;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
@@ -177,6 +227,78 @@ static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
case VINF_GETOPT_NOT_OPTION:
return errorSyntax(USAGE_DHCPSERVER, "unhandled parameter: %s", ValueUnion.psz);
break;
+
+ case 'o': // --options
+ {
+ // {"--vm", 'n', RTGETOPT_REQ_STRING}, /* only with -o */
+ // {"--slot", 's', RTGETOPT_REQ_UINT8}, /* only with -o and -n*/
+ // {"--id", 'i', RTGETOPT_REQ_UINT8}, /* only with -o */
+ // {"--value", 'p', RTGETOPT_REQ_STRING} /* only with -i */
+ if (fOptionsRead)
+ return errorSyntax(USAGE_DHCPSERVER,
+ "previos option edition wasn't finished");
+ fOptionsRead = true;
+ fVmOptionRead = false; /* we want specify new global or vm option*/
+ u8Slot = (uint8_t)~0;
+ u8OptId = (uint8_t)~0;
+ pszVmName = NULL;
+ } /* end of --options */
+ break;
+
+ case 'n': // --vm-name
+ {
+ if (fVmOptionRead)
+ return errorSyntax(USAGE_DHCPSERVER,
+ "previous vm option edition wasn't finished");
+ else
+ fVmOptionRead = true;
+ u8Slot = (uint8_t)~0; /* clear slor */
+ pszVmName = RTStrDup(ValueUnion.psz);
+ }
+ break; /* end of --vm-name */
+
+ case 's': // --slot
+ {
+ if (!fVmOptionRead)
+ return errorSyntax(USAGE_DHCPSERVER,
+ "vm name wasn't specified");
+
+ u8Slot = ValueUnion.u8;
+ }
+ break; /* end of --slot */
+
+ case 'i': // --id
+ {
+ if (!fOptionsRead)
+ return errorSyntax(USAGE_DHCPSERVER,
+ "-o wasn't found");
+
+ u8OptId = ValueUnion.u8;
+ }
+ break; /* end of --id */
+
+ case 'p': // --value
+ {
+ if (!fOptionsRead)
+ return errorSyntax(USAGE_DHCPSERVER,
+ "-o wasn't found");
+
+ if (u8OptId == (uint8_t)~0)
+ return errorSyntax(USAGE_DHCPSERVER,
+ "--id wasn't found");
+ if ( fVmOptionRead
+ && u8Slot == (uint8_t)~0)
+ return errorSyntax(USAGE_DHCPSERVER,
+ "--slot wasn't found");
+
+ DhcpOptMap& map = fVmOptionRead ? VmSlot2Options[VmNameSlotKey(pszVmName, u8Slot)]
+ : GlobalDhcpOptions;
+ std::string strVal = ValueUnion.psz;
+ map.insert(DhcpOptValuePair((DhcpOpt_T)u8OptId, strVal));
+
+ }
+ break; // --end of value
+
default:
if (c > 0)
{
@@ -197,7 +319,9 @@ static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
if(! pNetName && !pIfName)
return errorSyntax(USAGE_DHCPSERVER, "You need to specify either --netname or --ifname to identify the DHCP server");
- if(enmCode != OP_REMOVE)
+ if( enmCode != OP_REMOVE
+ && GlobalDhcpOptions.size() == 0
+ && VmSlot2Options.size() == 0)
{
if(enable < 0 || pIp || pNetmask || pLowerIp || pUpperIp)
{
@@ -255,7 +379,11 @@ static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
{
if (pIp || pNetmask || pLowerIp || pUpperIp)
{
- CHECK_ERROR(svr, SetConfiguration (Bstr(pIp).mutableRaw(), Bstr(pNetmask).mutableRaw(), Bstr(pLowerIp).mutableRaw(), Bstr(pUpperIp).mutableRaw()));
+ CHECK_ERROR(svr, SetConfiguration (
+ Bstr(pIp).mutableRaw(),
+ Bstr(pNetmask).mutableRaw(),
+ Bstr(pLowerIp).mutableRaw(),
+ Bstr(pUpperIp).mutableRaw()));
if(FAILED(rc))
return errorArgument("Failed to set configuration");
}
@@ -264,6 +392,39 @@ static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
{
CHECK_ERROR(svr, COMSETTER(Enabled) ((BOOL)enable));
}
+
+ /* option processing */
+ DhcpOptIterator itOpt;
+ VmSlot2OptionsIterator it;
+
+ /* Global Options */
+ for(itOpt = GlobalDhcpOptions.begin();
+ itOpt != GlobalDhcpOptions.end();
+ ++itOpt)
+ {
+ CHECK_ERROR(svr,
+ AddGlobalOption(
+ itOpt->first,
+ com::Bstr(itOpt->second.c_str()).raw()));
+ }
+
+ /* heh, vm slot options. */
+
+ for (it = VmSlot2Options.begin();
+ it != VmSlot2Options.end();
+ ++it)
+ {
+ for(itOpt = it->second.begin();
+ itOpt != it->second.end();
+ ++itOpt)
+ {
+ CHECK_ERROR(svr,
+ AddVmSlotOption(Bstr(it->first.VmName.c_str()).raw(),
+ it->first.u8Slot,
+ itOpt->first,
+ com::Bstr(itOpt->second.c_str()).raw()));
+ }
+ }
}
else
{
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp
index 5901c534..86cffce3 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageDebugVM.cpp
@@ -25,8 +25,6 @@
#include <VBox/com/array.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
-
#include <VBox/com/VirtualBox.h>
#include <iprt/ctype.h>
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
index e960c26e..d6b1f201 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -47,7 +47,7 @@ using namespace com;
static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
{
- RTMsgError(pszFormat, va);
+ RTMsgErrorV(pszFormat, va);
RTMsgError("Error code %Rrc at %s(%u) in function %s", rc, RT_SRC_POS_ARGS);
}
@@ -148,16 +148,17 @@ int parseBool(const char *psz, bool *pb)
return rc;
}
-HRESULT findMedium(HandlerArg *a, const char *pszFilenameOrUuid,
- DeviceType_T enmDevType, bool fSilent,
- ComPtr<IMedium> &pMedium)
+HRESULT openMedium(HandlerArg *a, const char *pszFilenameOrUuid,
+ DeviceType_T enmDevType, AccessMode_T enmAccessMode,
+ ComPtr<IMedium> &pMedium, bool fForceNewUuidOnOpen,
+ bool fSilent)
{
HRESULT rc;
Guid id(pszFilenameOrUuid);
char szFilenameAbs[RTPATH_MAX] = "";
/* If it is no UUID, convert the filename to an absolute one. */
- if (id.isEmpty())
+ if (!id.isValid())
{
int irc = RTPathAbs(pszFilenameOrUuid, szFilenameAbs, sizeof(szFilenameAbs));
if (RT_FAILURE(irc))
@@ -170,59 +171,18 @@ HRESULT findMedium(HandlerArg *a, const char *pszFilenameOrUuid,
}
if (!fSilent)
- CHECK_ERROR(a->virtualBox, OpenMedium(Bstr(pszFilenameOrUuid).raw(),
- enmDevType,
- AccessMode_ReadWrite,
- /*fForceNewUidOnOpen */ false,
- pMedium.asOutParam()));
- else
- rc = a->virtualBox->OpenMedium(Bstr(pszFilenameOrUuid).raw(),
- enmDevType,
- AccessMode_ReadWrite,
- /*fForceNewUidOnOpen */ false,
- pMedium.asOutParam());
- return rc;
-}
-
-HRESULT findOrOpenMedium(HandlerArg *a, const char *pszFilenameOrUuid,
- DeviceType_T enmDevType, AccessMode_T enmAccessMode,
- ComPtr<IMedium> &pMedium, bool fForceNewUuidOnOpen,
- bool *pfWasUnknown)
-{
- HRESULT rc;
- bool fWasUnknown = false;
- Guid id(pszFilenameOrUuid);
- char szFilenameAbs[RTPATH_MAX] = "";
-
- /* If it is no UUID, convert the filename to an absolute one. */
- if (id.isEmpty())
- {
- int irc = RTPathAbs(pszFilenameOrUuid, szFilenameAbs, sizeof(szFilenameAbs));
- if (RT_FAILURE(irc))
- {
- RTMsgError("Cannot convert filename \"%s\" to absolute path", pszFilenameOrUuid);
- return E_FAIL;
- }
- pszFilenameOrUuid = szFilenameAbs;
- }
-
- rc = a->virtualBox->OpenMedium(Bstr(pszFilenameOrUuid).raw(),
- enmDevType,
- enmAccessMode,
- /*fForceNewUidOnOpen */ false,
- pMedium.asOutParam());
- /* If the medium is unknown try to open it. */
- if (!pMedium)
- {
CHECK_ERROR(a->virtualBox, OpenMedium(Bstr(pszFilenameOrUuid).raw(),
- enmDevType, enmAccessMode,
+ enmDevType,
+ enmAccessMode,
fForceNewUuidOnOpen,
pMedium.asOutParam()));
- if (SUCCEEDED(rc))
- fWasUnknown = true;
- }
- if (RT_VALID_PTR(pfWasUnknown))
- *pfWasUnknown = fWasUnknown;
+ else
+ rc = a->virtualBox->OpenMedium(Bstr(pszFilenameOrUuid).raw(),
+ enmDevType,
+ enmAccessMode,
+ fForceNewUuidOnOpen,
+ pMedium.asOutParam());
+
return rc;
}
@@ -343,7 +303,6 @@ int handleCreateHardDisk(HandlerArg *a)
}
/* check the outcome */
- bool fUnknownParent = false;
ComPtr<IMedium> parentHardDisk;
if (fBase)
{
@@ -372,9 +331,9 @@ int handleCreateHardDisk(HandlerArg *a)
else
format = pszExt;
}
- rc = findOrOpenMedium(a, diffparent, DeviceType_HardDisk, AccessMode_ReadWrite,
- parentHardDisk, false /* fForceNewUuidOnOpen */,
- &fUnknownParent);
+ rc = openMedium(a, diffparent, DeviceType_HardDisk,
+ AccessMode_ReadWrite, parentHardDisk,
+ false /* fForceNewUuidOnOpen */, false /* fSilent */);
if (FAILED(rc))
return 1;
if (parentHardDisk.isNull())
@@ -413,10 +372,19 @@ int handleCreateHardDisk(HandlerArg *a)
if (SUCCEEDED(rc) && hardDisk)
{
ComPtr<IProgress> progress;
+ com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
+
+ for (ULONG i = 0; i < l_variants.size(); ++i)
+ {
+ ULONG temp = DiskVariant;
+ temp &= 1<<i;
+ l_variants [i] = (MediumVariant_T)temp;
+ }
+
if (fBase)
- CHECK_ERROR(hardDisk, CreateBaseStorage(size, DiskVariant, progress.asOutParam()));
+ CHECK_ERROR(hardDisk, CreateBaseStorage(size, ComSafeArrayAsInParam(l_variants), progress.asOutParam()));
else
- CHECK_ERROR(parentHardDisk, CreateDiffStorage(hardDisk, DiskVariant, progress.asOutParam()));
+ CHECK_ERROR(parentHardDisk, CreateDiffStorage(hardDisk, ComSafeArrayAsInParam(l_variants), progress.asOutParam()));
if (SUCCEEDED(rc) && progress)
{
rc = showProgress(progress);
@@ -430,8 +398,6 @@ int handleCreateHardDisk(HandlerArg *a)
}
CHECK_ERROR(hardDisk, Close());
- if (!fBase && fUnknownParent)
- CHECK_ERROR(parentHardDisk, Close());
}
return SUCCEEDED(rc) ? 0 : 1;
}
@@ -444,6 +410,7 @@ static const RTGETOPTDEF g_aModifyHardDiskOptions[] =
{ "--autoreset", 'z', RTGETOPT_REQ_STRING },
{ "-autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
{ "autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
+ { "--property", 'p', RTGETOPT_REQ_STRING },
{ "--compact", 'c', RTGETOPT_REQ_NOTHING },
{ "-compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
{ "compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
@@ -458,11 +425,15 @@ int handleModifyHardDisk(HandlerArg *a)
ComPtr<IMedium> hardDisk;
MediumType_T DiskType;
bool AutoReset = false;
- bool fModifyDiskType = false, fModifyAutoReset = false, fModifyCompact = false;
+ SafeArray<BSTR> mediumPropNames;
+ SafeArray<BSTR> mediumPropValues;
+ bool fModifyDiskType = false;
+ bool fModifyAutoReset = false;
+ bool fModifyProperties = false;
+ bool fModifyCompact = false;
bool fModifyResize = false;
uint64_t cbResize = 0;
const char *FilenameOrUuid = NULL;
- bool unknown = false;
int c;
RTGETOPTUNION ValueUnion;
@@ -488,6 +459,38 @@ int handleModifyHardDisk(HandlerArg *a)
fModifyAutoReset = true;
break;
+ case 'p': // --property
+ {
+ /* Parse 'name=value' */
+ char *pszProperty = RTStrDup(ValueUnion.psz);
+ if (pszProperty)
+ {
+ char *pDelimiter = strchr(pszProperty, '=');
+ if (pDelimiter)
+ {
+ *pDelimiter = '\0';
+
+ Bstr bstrName(pszProperty);
+ Bstr bstrValue(&pDelimiter[1]);
+ bstrName.detachTo(mediumPropNames.appendedRaw());
+ bstrValue.detachTo(mediumPropValues.appendedRaw());
+ fModifyProperties = true;
+ }
+ else
+ {
+ errorArgument("Invalid --property argument '%s'", ValueUnion.psz);
+ rc = E_FAIL;
+ }
+ RTStrFree(pszProperty);
+ }
+ else
+ {
+ RTStrmPrintf(g_pStdErr, "Error: Failed to allocate memory for medium property '%s'\n", ValueUnion.psz);
+ rc = E_FAIL;
+ }
+ break;
+ }
+
case 'c': // --compact
fModifyCompact = true;
break;
@@ -529,16 +532,13 @@ int handleModifyHardDisk(HandlerArg *a)
if (!FilenameOrUuid)
return errorSyntax(USAGE_MODIFYHD, "Disk name or UUID required");
- if (!fModifyDiskType && !fModifyAutoReset && !fModifyCompact && !fModifyResize)
+ if (!fModifyDiskType && !fModifyAutoReset && !fModifyProperties && !fModifyCompact && !fModifyResize)
return errorSyntax(USAGE_MODIFYHD, "No operation specified");
- /* Depending on the operation the medium must be in the registry or
- * may be opened on demand. */
- if (fModifyDiskType || fModifyAutoReset)
- rc = findMedium(a, FilenameOrUuid, DeviceType_HardDisk, false /* fSilent */, hardDisk);
- else
- rc = findOrOpenMedium(a, FilenameOrUuid, DeviceType_HardDisk, AccessMode_ReadWrite,
- hardDisk, false /* fForceNewUuidOnOpen */, &unknown);
+ /* Always open the medium if necessary, there is no other way. */
+ rc = openMedium(a, FilenameOrUuid, DeviceType_HardDisk,
+ AccessMode_ReadWrite, hardDisk,
+ false /* fForceNewUuidOnOpen */, false /* fSilent */);
if (FAILED(rc))
return 1;
if (hardDisk.isNull())
@@ -561,6 +561,11 @@ int handleModifyHardDisk(HandlerArg *a)
CHECK_ERROR(hardDisk, COMSETTER(AutoReset)(AutoReset));
}
+ if (fModifyProperties)
+ {
+ CHECK_ERROR(hardDisk, SetProperties(ComSafeArrayAsInParam(mediumPropNames), ComSafeArrayAsInParam(mediumPropValues)));
+ }
+
if (fModifyCompact)
{
ComPtr<IProgress> progress;
@@ -597,9 +602,6 @@ int handleModifyHardDisk(HandlerArg *a)
}
}
- if (unknown)
- hardDisk->Close();
-
return SUCCEEDED(rc) ? 0 : 1;
}
@@ -691,11 +693,10 @@ int handleCloneHardDisk(HandlerArg *a)
ComPtr<IMedium> srcDisk;
ComPtr<IMedium> dstDisk;
- bool fSrcUnknown = false;
- bool fDstUnknown = false;
- rc = findOrOpenMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly,
- srcDisk, false /* fForceNewUuidOnOpen */, &fSrcUnknown);
+ rc = openMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly,
+ srcDisk, false /* fForceNewUuidOnOpen */,
+ false /* fSilent */);
if (FAILED(rc))
return 1;
@@ -704,8 +705,10 @@ int handleCloneHardDisk(HandlerArg *a)
/* open/create destination hard disk */
if (fExisting)
{
- rc = findOrOpenMedium(a, pszDst, DeviceType_HardDisk, AccessMode_ReadWrite,
- dstDisk, false /* fForceNewUuidOnOpen */, &fDstUnknown);
+ rc = openMedium(a, pszDst, DeviceType_HardDisk,
+ AccessMode_ReadWrite, dstDisk,
+ false /* fForceNewUuidOnOpen */,
+ false /* fSilent */);
if (FAILED(rc))
break;
@@ -722,11 +725,19 @@ int handleCloneHardDisk(HandlerArg *a)
rc = createHardDisk(a, Utf8Str(format).c_str(), pszDst, dstDisk);
if (FAILED(rc))
break;
- fDstUnknown = true;
}
ComPtr<IProgress> progress;
- CHECK_ERROR_BREAK(srcDisk, CloneTo(dstDisk, DiskVariant, NULL, progress.asOutParam()));
+ com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);
+
+ for (ULONG i = 0; i < l_variants.size(); ++i)
+ {
+ ULONG temp = DiskVariant;
+ temp &= 1<<i;
+ l_variants [i] = (MediumVariant_T)temp;
+ }
+
+ CHECK_ERROR_BREAK(srcDisk, CloneTo(dstDisk, ComSafeArrayAsInParam(l_variants), NULL, progress.asOutParam()));
rc = showProgress(progress);
CHECK_PROGRESS_ERROR_BREAK(progress, ("Failed to clone hard disk"));
@@ -739,17 +750,6 @@ int handleCloneHardDisk(HandlerArg *a)
}
while (0);
- if (fDstUnknown && !dstDisk.isNull())
- {
- /* forget the created clone */
- dstDisk->Close();
- }
- if (fSrcUnknown)
- {
- /* close the unknown hard disk to forget it again */
- srcDisk->Close();
- }
-
return SUCCEEDED(rc) ? 0 : 1;
}
@@ -797,14 +797,15 @@ RTEXITCODE handleConvertFromRaw(int argc, char *argv[])
break;
case 'm': // --variant
- MediumVariant_T DiskVariant;
+ {
+ MediumVariant_T DiskVariant = MediumVariant_Standard;
rc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
if (RT_FAILURE(rc))
return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
/// @todo cleaner solution than assuming 1:1 mapping?
uImageFlags = (unsigned)DiskVariant;
break;
-
+ }
case VINF_GETOPT_NOT_OPTION:
if (!srcfilename)
{
@@ -935,106 +936,73 @@ out:
return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
-static const RTGETOPTDEF g_aShowHardDiskInfoOptions[] =
-{
- { "--dummy", 256, RTGETOPT_REQ_NOTHING }, // placeholder for C++
-};
-
-int handleShowHardDiskInfo(HandlerArg *a)
+HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
+ const ComPtr<IMedium> &pMedium,
+ const char *pszParentUUID,
+ bool fOptLong)
{
- HRESULT rc;
- const char *FilenameOrUuid = NULL;
-
- int c;
- RTGETOPTUNION ValueUnion;
- RTGETOPTSTATE GetState;
- // start at 0 because main() has hacked both the argc and argv given to us
- RTGetOptInit(&GetState, a->argc, a->argv, g_aShowHardDiskInfoOptions, RT_ELEMENTS(g_aShowHardDiskInfoOptions),
- 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
- while ((c = RTGetOpt(&GetState, &ValueUnion)))
- {
- switch (c)
- {
- case VINF_GETOPT_NOT_OPTION:
- if (!FilenameOrUuid)
- FilenameOrUuid = ValueUnion.psz;
- else
- return errorSyntax(USAGE_SHOWHDINFO, "Invalid parameter '%s'", ValueUnion.psz);
- break;
-
- default:
- if (c > 0)
- {
- if (RT_C_IS_PRINT(c))
- return errorSyntax(USAGE_SHOWHDINFO, "Invalid option -%c", c);
- else
- return errorSyntax(USAGE_SHOWHDINFO, "Invalid option case %i", c);
- }
- else if (c == VERR_GETOPT_UNKNOWN_OPTION)
- return errorSyntax(USAGE_SHOWHDINFO, "unknown option: %s\n", ValueUnion.psz);
- else if (ValueUnion.pDef)
- return errorSyntax(USAGE_SHOWHDINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
- else
- return errorSyntax(USAGE_SHOWHDINFO, "error: %Rrs", c);
- }
- }
-
- /* check for required options */
- if (!FilenameOrUuid)
- return errorSyntax(USAGE_SHOWHDINFO, "Disk name or UUID required");
-
- ComPtr<IMedium> hardDisk;
- bool unknown = false;
-
- rc = findOrOpenMedium(a, FilenameOrUuid, DeviceType_HardDisk, AccessMode_ReadOnly,
- hardDisk, false /* fForceNewUuidOnOpen */, &unknown);
- if (FAILED(rc))
- return 1;
-
+ HRESULT rc = S_OK;
do
{
Bstr uuid;
- hardDisk->COMGETTER(Id)(uuid.asOutParam());
- RTPrintf("UUID: %s\n", Utf8Str(uuid).c_str());
+ pMedium->COMGETTER(Id)(uuid.asOutParam());
+ RTPrintf("UUID: %ls\n", uuid.raw());
+ if (pszParentUUID)
+ RTPrintf("Parent UUID: %s\n", pszParentUUID);
/* check for accessibility */
- /// @todo NEWMEDIA check accessibility of all parents
- /// @todo NEWMEDIA print the full state value
- MediumState_T state;
- CHECK_ERROR_BREAK(hardDisk, RefreshState(&state));
- RTPrintf("Accessible: %s\n", state != MediumState_Inaccessible ? "yes" : "no");
+ MediumState_T enmState;
+ CHECK_ERROR_BREAK(pMedium, RefreshState(&enmState));
+ pMedium->RefreshState(&enmState);
+ const char *pszState = "unknown";
+ switch (enmState)
+ {
+ case MediumState_NotCreated:
+ pszState = "not created";
+ break;
+ case MediumState_Created:
+ pszState = "created";
+ break;
+ case MediumState_LockedRead:
+ pszState = "locked read";
+ break;
+ case MediumState_LockedWrite:
+ pszState = "locked write";
+ break;
+ case MediumState_Inaccessible:
+ pszState = "inaccessible";
+ break;
+ case MediumState_Creating:
+ pszState = "creating";
+ break;
+ case MediumState_Deleting:
+ pszState = "deleting";
+ break;
+ }
+ RTPrintf("State: %s\n", pszState);
- if (state == MediumState_Inaccessible)
+ if (fOptLong && enmState == MediumState_Inaccessible)
{
Bstr err;
- CHECK_ERROR_BREAK(hardDisk, COMGETTER(LastAccessError)(err.asOutParam()));
- RTPrintf("Access Error: %ls\n", err.raw());
+ CHECK_ERROR_BREAK(pMedium, COMGETTER(LastAccessError)(err.asOutParam()));
+ RTPrintf("Access Error: %ls\n", err.raw());
}
- Bstr description;
- hardDisk->COMGETTER(Description)(description.asOutParam());
- if (!description.isEmpty())
+ if (fOptLong)
{
- RTPrintf("Description: %ls\n", description.raw());
+ Bstr description;
+ pMedium->COMGETTER(Description)(description.asOutParam());
+ if (!description.isEmpty())
+ RTPrintf("Description: %ls\n", description.raw());
}
- LONG64 logicalSize;
- hardDisk->COMGETTER(LogicalSize)(&logicalSize);
- RTPrintf("Logical size: %lld MBytes\n", logicalSize >> 20);
- LONG64 actualSize;
- hardDisk->COMGETTER(Size)(&actualSize);
- RTPrintf("Current size on disk: %lld MBytes\n", actualSize >> 20);
-
- ComPtr <IMedium> parent;
- hardDisk->COMGETTER(Parent)(parent.asOutParam());
-
MediumType_T type;
- hardDisk->COMGETTER(Type)(&type);
+ pMedium->COMGETTER(Type)(&type);
const char *typeStr = "unknown";
switch (type)
{
case MediumType_Normal:
- if (!parent.isNull())
+ if (pszParentUUID && Guid(pszParentUUID).isValid())
typeStr = "normal (differencing)";
else
typeStr = "normal (base)";
@@ -1055,78 +1023,215 @@ int handleShowHardDiskInfo(HandlerArg *a)
typeStr = "multiattach";
break;
}
- RTPrintf("Type: %s\n", typeStr);
+ RTPrintf("Type: %s\n", typeStr);
+
+ /* print out information specific for differencing hard disks */
+ if (fOptLong && pszParentUUID && Guid(pszParentUUID).isValid())
+ {
+ BOOL autoReset = FALSE;
+ pMedium->COMGETTER(AutoReset)(&autoReset);
+ RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
+ }
+
+ Bstr loc;
+ pMedium->COMGETTER(Location)(loc.asOutParam());
+ RTPrintf("Location: %ls\n", loc.raw());
Bstr format;
- hardDisk->COMGETTER(Format)(format.asOutParam());
- RTPrintf("Storage format: %ls\n", format.raw());
- ULONG variant;
- hardDisk->COMGETTER(Variant)(&variant);
- const char *variantStr = "unknown";
- switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
+ pMedium->COMGETTER(Format)(format.asOutParam());
+ RTPrintf("Storage format: %ls\n", format.raw());
+
+ if (fOptLong)
{
- case MediumVariant_VmdkSplit2G:
- variantStr = "split2G";
- break;
- case MediumVariant_VmdkStreamOptimized:
- variantStr = "streamOptimized";
- break;
- case MediumVariant_VmdkESX:
- variantStr = "ESX";
- break;
- case MediumVariant_Standard:
- variantStr = "default";
- break;
+ com::SafeArray<MediumVariant_T> safeArray_variant;
+
+ pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(safeArray_variant));
+ ULONG variant=0;
+ for (size_t i = 0; i < safeArray_variant.size(); i++)
+ variant |= safeArray_variant[i];
+
+ const char *variantStr = "unknown";
+ switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
+ {
+ case MediumVariant_VmdkSplit2G:
+ variantStr = "split2G";
+ break;
+ case MediumVariant_VmdkStreamOptimized:
+ variantStr = "streamOptimized";
+ break;
+ case MediumVariant_VmdkESX:
+ variantStr = "ESX";
+ break;
+ case MediumVariant_Standard:
+ variantStr = "default";
+ break;
+ }
+ const char *variantTypeStr = "dynamic";
+ if (variant & MediumVariant_Fixed)
+ variantTypeStr = "fixed";
+ else if (variant & MediumVariant_Diff)
+ variantTypeStr = "differencing";
+ RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
+ }
+
+ LONG64 logicalSize;
+ pMedium->COMGETTER(LogicalSize)(&logicalSize);
+ RTPrintf("Capacity: %lld MBytes\n", logicalSize >> 20);
+ if (fOptLong)
+ {
+ LONG64 actualSize;
+ pMedium->COMGETTER(Size)(&actualSize);
+ RTPrintf("Size on disk: %lld MBytes\n", actualSize >> 20);
}
- const char *variantTypeStr = "dynamic";
- if (variant & MediumVariant_Fixed)
- variantTypeStr = "fixed";
- else if (variant & MediumVariant_Diff)
- variantTypeStr = "differencing";
- RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
- /// @todo also dump config parameters (iSCSI)
+ if (fOptLong)
+ {
+ com::SafeArray<BSTR> names;
+ com::SafeArray<BSTR> values;
+ pMedium->GetProperties(Bstr().raw(), ComSafeArrayAsOutParam(names), ComSafeArrayAsOutParam(values));
+ size_t cNames = names.size();
+ size_t cValues = values.size();
+ bool fFirst = true;
+ for (size_t i = 0; i < cNames; i++)
+ {
+ Bstr value;
+ if (i < cValues)
+ value = values[i];
+ RTPrintf("%s%ls=%ls\n",
+ fFirst ? "Property: " : " ",
+ names[i], value.raw());
+ }
+ }
- if (!unknown)
+ if (fOptLong)
{
+ bool fFirst = true;
com::SafeArray<BSTR> machineIds;
- hardDisk->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
- for (size_t j = 0; j < machineIds.size(); ++ j)
+ pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
+ for (size_t i = 0; i < machineIds.size(); i++)
{
ComPtr<IMachine> machine;
- CHECK_ERROR(a->virtualBox, FindMachine(machineIds[j], machine.asOutParam()));
- ASSERT(machine);
- Bstr name;
- machine->COMGETTER(Name)(name.asOutParam());
- machine->COMGETTER(Id)(uuid.asOutParam());
- RTPrintf("%s%ls (UUID: %ls)\n",
- j == 0 ? "In use by VMs: " : " ",
- name.raw(), machineIds[j]);
+ CHECK_ERROR(pVirtualBox, FindMachine(machineIds[i], machine.asOutParam()));
+ if (machine)
+ {
+ Bstr name;
+ machine->COMGETTER(Name)(name.asOutParam());
+ machine->COMGETTER(Id)(uuid.asOutParam());
+ RTPrintf("%s%ls (UUID: %ls)",
+ fFirst ? "In use by VMs: " : " ",
+ name.raw(), machineIds[i]);
+ fFirst = false;
+ com::SafeArray<BSTR> snapshotIds;
+ pMedium->GetSnapshotIds(machineIds[i],
+ ComSafeArrayAsOutParam(snapshotIds));
+ for (size_t j = 0; j < snapshotIds.size(); j++)
+ {
+ ComPtr<ISnapshot> snapshot;
+ machine->FindSnapshot(snapshotIds[j], snapshot.asOutParam());
+ if (snapshot)
+ {
+ Bstr snapshotName;
+ snapshot->COMGETTER(Name)(snapshotName.asOutParam());
+ RTPrintf(" [%ls (UUID: %ls)]", snapshotName.raw(), snapshotIds[j]);
+ }
+ }
+ RTPrintf("\n");
+ }
}
- /// @todo NEWMEDIA check usage in snapshots too
- /// @todo NEWMEDIA also list children
}
- Bstr loc;
- hardDisk->COMGETTER(Location)(loc.asOutParam());
- RTPrintf("Location: %ls\n", loc.raw());
-
- /* print out information specific for differencing hard disks */
- if (!parent.isNull())
+ if (fOptLong)
{
- BOOL autoReset = FALSE;
- hardDisk->COMGETTER(AutoReset)(&autoReset);
- RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
+ com::SafeIfaceArray<IMedium> children;
+ pMedium->COMGETTER(Children)(ComSafeArrayAsOutParam(children));
+ bool fFirst = true;
+ for (size_t i = 0; i < children.size(); i++)
+ {
+ ComPtr<IMedium> pChild(children[i]);
+ if (pChild)
+ {
+ Bstr childUUID;
+ pChild->COMGETTER(Id)(childUUID.asOutParam());
+ RTPrintf("%s%ls\n",
+ fFirst ? "Child UUIDs: " : " ",
+ childUUID.raw());
+ fFirst = false;
+ }
+ }
}
}
while (0);
- if (unknown)
+ return rc;
+}
+
+static const RTGETOPTDEF g_aShowHardDiskInfoOptions[] =
+{
+ { "--dummy", 256, RTGETOPT_REQ_NOTHING }, // placeholder for C++
+};
+
+int handleShowHardDiskInfo(HandlerArg *a)
+{
+ HRESULT rc;
+ const char *FilenameOrUuid = NULL;
+
+ int c;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ // start at 0 because main() has hacked both the argc and argv given to us
+ RTGetOptInit(&GetState, a->argc, a->argv, g_aShowHardDiskInfoOptions, RT_ELEMENTS(g_aShowHardDiskInfoOptions),
+ 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
+ while ((c = RTGetOpt(&GetState, &ValueUnion)))
{
- /* close the unknown hard disk to forget it again */
- hardDisk->Close();
+ switch (c)
+ {
+ case VINF_GETOPT_NOT_OPTION:
+ if (!FilenameOrUuid)
+ FilenameOrUuid = ValueUnion.psz;
+ else
+ return errorSyntax(USAGE_SHOWHDINFO, "Invalid parameter '%s'", ValueUnion.psz);
+ break;
+
+ default:
+ if (c > 0)
+ {
+ if (RT_C_IS_PRINT(c))
+ return errorSyntax(USAGE_SHOWHDINFO, "Invalid option -%c", c);
+ else
+ return errorSyntax(USAGE_SHOWHDINFO, "Invalid option case %i", c);
+ }
+ else if (c == VERR_GETOPT_UNKNOWN_OPTION)
+ return errorSyntax(USAGE_SHOWHDINFO, "unknown option: %s\n", ValueUnion.psz);
+ else if (ValueUnion.pDef)
+ return errorSyntax(USAGE_SHOWHDINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
+ else
+ return errorSyntax(USAGE_SHOWHDINFO, "error: %Rrs", c);
+ }
}
+ /* check for required options */
+ if (!FilenameOrUuid)
+ return errorSyntax(USAGE_SHOWHDINFO, "Disk name or UUID required");
+
+ ComPtr<IMedium> hardDisk;
+ rc = openMedium(a, FilenameOrUuid, DeviceType_HardDisk,
+ AccessMode_ReadOnly, hardDisk,
+ false /* fForceNewUuidOnOpen */, false /* fSilent */);
+ if (FAILED(rc))
+ return 1;
+
+ Utf8Str strParentUUID("base");
+ ComPtr<IMedium> parent;
+ hardDisk->COMGETTER(Parent)(parent.asOutParam());
+ if (!parent.isNull())
+ {
+ Bstr bstrParentUUID;
+ parent->COMGETTER(Id)(bstrParentUUID.asOutParam());
+ strParentUUID = bstrParentUUID;
+ }
+
+ rc = showMediumInfo(a->virtualBox, hardDisk, strParentUUID.c_str(), true);
+
return SUCCEEDED(rc) ? 0 : 1;
}
@@ -1215,11 +1320,17 @@ int handleCloseMedium(HandlerArg *a)
ComPtr<IMedium> medium;
if (cmd == CMD_DISK)
- rc = findMedium(a, FilenameOrUuid, DeviceType_HardDisk, false /* fSilent */, medium);
+ rc = openMedium(a, FilenameOrUuid, DeviceType_HardDisk,
+ AccessMode_ReadWrite, medium,
+ false /* fForceNewUuidOnOpen */, false /* fSilent */);
else if (cmd == CMD_DVD)
- rc = findMedium(a, FilenameOrUuid, DeviceType_DVD, false /* fSilent */, medium);
+ rc = openMedium(a, FilenameOrUuid, DeviceType_DVD,
+ AccessMode_ReadOnly, medium,
+ false /* fForceNewUuidOnOpen */, false /* fSilent */);
else if (cmd == CMD_FLOPPY)
- rc = findMedium(a, FilenameOrUuid, DeviceType_Floppy, false /* fSilent */, medium);
+ rc = openMedium(a, FilenameOrUuid, DeviceType_Floppy,
+ AccessMode_ReadWrite, medium,
+ false /* fForceNewUuidOnOpen */, false /* fSilent */);
if (SUCCEEDED(rc) && medium)
{
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
index 53fe4336..ced18c1b 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2010-2012 Oracle Corporation
+ * Copyright (C) 2010-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;
@@ -20,16 +20,18 @@
* Header Files *
*******************************************************************************/
#include "VBoxManage.h"
+#include "VBoxManageGuestCtrl.h"
#ifndef VBOX_ONLY_DOCS
-#include <VBox/com/com.h>
-#include <VBox/com/string.h>
#include <VBox/com/array.h>
+#include <VBox/com/com.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
+#include <VBox/com/listeners.h>
+#include <VBox/com/NativeEventQueue.h>
+#include <VBox/com/string.h>
#include <VBox/com/VirtualBox.h>
-#include <VBox/com/EventQueue.h>
#include <VBox/err.h>
#include <VBox/log.h>
@@ -41,6 +43,7 @@
#include <iprt/getopt.h>
#include <iprt/list.h>
#include <iprt/path.h>
+#include <iprt/process.h> /* For RTProcSelf(). */
#include <iprt/thread.h>
#include <map>
@@ -59,25 +62,85 @@
using namespace com;
+/** Set by the signal handler when current guest control
+ * action shall be aborted. */
+static volatile bool g_fGuestCtrlCanceled = false;
+
/**
- * IVirtualBoxCallback implementation for handling the GuestControlCallback in
- * relation to the "guestcontrol * wait" command.
+ * Listener declarations.
*/
-/** @todo */
+VBOX_LISTENER_DECLARE(GuestFileEventListenerImpl)
+VBOX_LISTENER_DECLARE(GuestProcessEventListenerImpl)
+VBOX_LISTENER_DECLARE(GuestSessionEventListenerImpl)
+VBOX_LISTENER_DECLARE(GuestEventListenerImpl)
-/** Set by the signal handler. */
-static volatile bool g_fGuestCtrlCanceled = false;
+/**
+ * Command context flags.
+ */
+/** No flags set. */
+#define CTLCMDCTX_FLAGS_NONE 0
+/** Don't install a signal handler (CTRL+C trap). */
+#define CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER RT_BIT(0)
+/** No guest session needed. */
+#define CTLCMDCTX_FLAGS_SESSION_ANONYMOUS RT_BIT(1)
+/** Detach the guest session. That is, don't close the
+ * guest session automatically on exit. */
+#define CTLCMDCTX_FLAGS_SESSION_DETACH RT_BIT(2)
+
+/**
+ * Context for handling a specific command.
+ */
+typedef struct GCTLCMDCTX
+{
+ HandlerArg handlerArg;
+ /** Command-specific argument count. */
+ int iArgc;
+ /** Command-specific argument vector. */
+ char **ppaArgv;
+ /** First argv to start parsing with. */
+ int iFirstArgc;
+ /** Command context flags. */
+ uint32_t uFlags;
+ /** Verbose flag. */
+ bool fVerbose;
+ /** User name. */
+ Utf8Str strUsername;
+ /** Password. */
+ Utf8Str strPassword;
+ /** Domain. */
+ Utf8Str strDomain;
+ /** Pointer to the IGuest interface. */
+ ComPtr<IGuest> pGuest;
+ /** Pointer to the to be used guest session. */
+ ComPtr<IGuestSession> pGuestSession;
+ /** The guest session ID. */
+ ULONG uSessionID;
+
+} GCTLCMDCTX, *PGCTLCMDCTX;
+
+typedef struct GCTLCMD
+{
+ /**
+ * Actual command handler callback.
+ *
+ * @param pCtx Pointer to command context to use.
+ */
+ DECLR3CALLBACKMEMBER(RTEXITCODE, pfnHandler, (PGCTLCMDCTX pCtx));
+
+} GCTLCMD, *PGCTLCMD;
typedef struct COPYCONTEXT
{
- COPYCONTEXT() : fVerbose(false), fDryRun(false), fHostToGuest(false)
+ COPYCONTEXT()
+ : fDryRun(false),
+ fHostToGuest(false)
{
}
- ComPtr<IGuestSession> pGuestSession;
- bool fVerbose;
+ PGCTLCMDCTX pCmdCtx;
bool fDryRun;
bool fHostToGuest;
+
} COPYCONTEXT, *PCOPYCONTEXT;
/**
@@ -174,6 +237,15 @@ enum EXITCODEEXEC
EXITCODEEXEC_CANCELED = 22
};
+/*
+ * Common getopt definitions, starting at 1000.
+ * Specific command definitions will start all at 2000.
+ */
+enum GETOPTDEF_COMMON
+{
+ GETOPTDEF_COMMON_PASSWORD = 1000
+};
+
/**
* RTGetOpt-IDs for the guest execution control command line.
*/
@@ -184,7 +256,6 @@ enum GETOPTDEF_EXEC
GETOPTDEF_EXEC_OUTPUTFORMAT,
GETOPTDEF_EXEC_DOS2UNIX,
GETOPTDEF_EXEC_UNIX2DOS,
- GETOPTDEF_EXEC_PASSWORD,
GETOPTDEF_EXEC_WAITFOREXIT,
GETOPTDEF_EXEC_WAITFORSTDOUT,
GETOPTDEF_EXEC_WAITFORSTDERR
@@ -194,18 +265,28 @@ enum GETOPTDEF_COPY
{
GETOPTDEF_COPY_DRYRUN = 1000,
GETOPTDEF_COPY_FOLLOW,
- GETOPTDEF_COPY_PASSWORD,
GETOPTDEF_COPY_TARGETDIR
};
enum GETOPTDEF_MKDIR
{
- GETOPTDEF_MKDIR_PASSWORD = 1000
+};
+
+enum GETOPTDEF_RM
+{
+};
+
+enum GETOPTDEF_RMDIR
+{
+};
+
+enum GETOPTDEF_SESSIONCLOSE
+{
+ GETOPTDEF_SESSIONCLOSE_ALL = 2000
};
enum GETOPTDEF_STAT
{
- GETOPTDEF_STAT_PASSWORD = 1000
};
enum OUTPUTTYPE
@@ -219,57 +300,152 @@ static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest, const char *psz
#endif /* VBOX_ONLY_DOCS */
-void usageGuestControl(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2)
+void usageGuestControl(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2, uint32_t uSubCmd)
{
RTStrmPrintf(pStrm,
- "%s guestcontrol %s <vmname>|<uuid>\n"
- " exec[ute]\n"
- " --image <path to program> --username <name>\n"
- " [--passwordfile <file> | --password <password>]\n"
- " [--domain <domain>] [--verbose] [--timeout <msec>]\n"
- " [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n"
- " [--wait-exit] [--wait-stdout] [--wait-stderr]\n"
- " [--dos2unix] [--unix2dos]\n"
- " [-- [<argument1>] ... [<argumentN>]]\n"
- /** @todo Add a "--" parameter (has to be last parameter) to directly execute
- * stuff, e.g. "VBoxManage guestcontrol execute <VMName> --username <> ... -- /bin/rm -Rf /foo". */
- "\n"
- " copyfrom\n"
- " <guest source> <host dest> --username <name>\n"
- " [--passwordfile <file> | --password <password>]\n"
- " [--domain <domain>] [--verbose]\n"
- " [--dryrun] [--follow] [--recursive]\n"
- "\n"
- " copyto|cp\n"
- " <host source> <guest dest> --username <name>\n"
- " [--passwordfile <file> | --password <password>]\n"
- " [--domain <domain>] [--verbose]\n"
- " [--dryrun] [--follow] [--recursive]\n"
- "\n"
- " createdir[ectory]|mkdir|md\n"
- " <guest directory>... --username <name>\n"
- " [--passwordfile <file> | --password <password>]\n"
- " [--domain <domain>] [--verbose]\n"
- " [--parents] [--mode <mode>]\n"
- "\n"
- " stat\n"
- " <file>... --username <name>\n"
- " [--passwordfile <file> | --password <password>]\n"
- " [--domain <domain>] [--verbose]\n"
- "\n"
- " updateadditions\n"
- " [--source <guest additions .ISO>] [--verbose]\n"
- " [--wait-start]\n"
- "\n", pcszSep1, pcszSep2);
+ "%s guestcontrol %s <uuid|vmname>\n%s",
+ pcszSep1, pcszSep2,
+ uSubCmd == ~0U ? "\n" : "");
+ if (uSubCmd & USAGE_GSTCTRL_EXEC)
+ RTStrmPrintf(pStrm,
+ " exec[ute]\n"
+ " --image <path to program> --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--domain <domain>] [--verbose] [--timeout <msec>]\n"
+ " [--environment \"<NAME>=<VALUE> [<NAME>=<VALUE>]\"]\n"
+ " [--wait-exit] [--wait-stdout] [--wait-stderr]\n"
+ " [--dos2unix] [--unix2dos]\n"
+ " [-- [<argument1>] ... [<argumentN>]]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_COPYFROM)
+ RTStrmPrintf(pStrm,
+ " copyfrom\n"
+ " <guest source> <host dest> --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--domain <domain>] [--verbose]\n"
+ " [--dryrun] [--follow] [--recursive]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_COPYTO)
+ RTStrmPrintf(pStrm,
+ " copyto|cp\n"
+ " <host source> <guest dest> --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--domain <domain>] [--verbose]\n"
+ " [--dryrun] [--follow] [--recursive]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_CREATEDIR)
+ RTStrmPrintf(pStrm,
+ " createdir[ectory]|mkdir|md\n"
+ " <guest directory>... --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--domain <domain>] [--verbose]\n"
+ " [--parents] [--mode <mode>]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_REMOVEDIR)
+ RTStrmPrintf(pStrm,
+ " removedir[ectory]|rmdir\n"
+ " <guest directory>... --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--domain <domain>] [--verbose]\n"
+ " [--recursive|-R|-r]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_REMOVEFILE)
+ RTStrmPrintf(pStrm,
+ " removefile|rm\n"
+ " <guest file>... --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--domain <domain>] [--verbose]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_RENAME)
+ RTStrmPrintf(pStrm,
+ " ren[ame]|mv\n"
+ " <source>... <dest> --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--domain <domain>] [--verbose]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_CREATETEMP)
+ RTStrmPrintf(pStrm,
+ " createtemp[orary]|mktemp\n"
+ " <template> --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--directory] [--secure] [--tmpdir <directory>]\n"
+ " [--domain <domain>] [--mode <mode>] [--verbose]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_LIST)
+ RTStrmPrintf(pStrm,
+ " list <all|sessions|processes|files> [--verbose]\n"
+ "\n");
+ /** @todo Add an own help group for "session" and "process" sub commands. */
+ if (uSubCmd & USAGE_GSTCTRL_PROCESS)
+ RTStrmPrintf(pStrm,
+ " process kill --session-id <ID>\n"
+ " | --session-name <name or pattern>\n"
+ " [--verbose]\n"
+ " <PID> ... <PID n>\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_KILL)
+ RTStrmPrintf(pStrm,
+ " [p[s]]kill --session-id <ID>\n"
+ " | --session-name <name or pattern>\n"
+ " [--verbose]\n"
+ " <PID> ... <PID n>\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_SESSION)
+ RTStrmPrintf(pStrm,
+ " session close --session-id <ID>\n"
+ " | --session-name <name or pattern>\n"
+ " | --all\n"
+ " [--verbose]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_STAT)
+ RTStrmPrintf(pStrm,
+ " stat\n"
+ " <file>... --username <name>\n"
+ " [--passwordfile <file> | --password <password>]\n"
+ " [--domain <domain>] [--verbose]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_UPDATEADDS)
+ RTStrmPrintf(pStrm,
+ " updateadditions\n"
+ " [--source <guest additions .ISO>] [--verbose]\n"
+ " [--wait-start]\n"
+ " [-- [<argument1>] ... [<argumentN>]]\n"
+ "\n");
+ if (uSubCmd & USAGE_GSTCTRL_WATCH)
+ RTStrmPrintf(pStrm,
+ " watch [--verbose]\n"
+ "\n");
}
#ifndef VBOX_ONLY_DOCS
+#ifdef RT_OS_WINDOWS
+static BOOL WINAPI guestCtrlSignalHandler(DWORD dwCtrlType)
+{
+ bool fEventHandled = FALSE;
+ switch (dwCtrlType)
+ {
+ /* User pressed CTRL+C or CTRL+BREAK or an external event was sent
+ * via GenerateConsoleCtrlEvent(). */
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ case CTRL_C_EVENT:
+ ASMAtomicWriteBool(&g_fGuestCtrlCanceled, true);
+ fEventHandled = TRUE;
+ break;
+ default:
+ break;
+ /** @todo Add other events here. */
+ }
+
+ return fEventHandled;
+}
+#else /* !RT_OS_WINDOWS */
/**
* Signal handler that sets g_fGuestCtrlCanceled.
*
* 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
+ * a thread dedicated to delivering this signal. Don't do anything
* unnecessary here.
*/
static void guestCtrlSignalHandler(int iSignal)
@@ -277,35 +453,58 @@ static void guestCtrlSignalHandler(int iSignal)
NOREF(iSignal);
ASMAtomicWriteBool(&g_fGuestCtrlCanceled, true);
}
+#endif
/**
* Installs a custom signal handler to get notified
* whenever the user wants to intercept the program.
+ *
+ ** @todo Make this handler available for all VBoxManage modules?
*/
-static void ctrlSignalHandlerInstall()
+static int ctrlSignalHandlerInstall(void)
{
+ int rc = VINF_SUCCESS;
+#ifdef RT_OS_WINDOWS
+ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)guestCtrlSignalHandler, TRUE /* Add handler */))
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ RTMsgError("Unable to install console control handler, rc=%Rrc\n", rc);
+ }
+#else
signal(SIGINT, guestCtrlSignalHandler);
-#ifdef SIGBREAK
+# ifdef SIGBREAK
signal(SIGBREAK, guestCtrlSignalHandler);
+# endif
#endif
+ return rc;
}
/**
* Uninstalls a previously installed signal handler.
*/
-static void ctrlSignalHandlerUninstall()
+static int ctrlSignalHandlerUninstall(void)
{
+ int rc = VINF_SUCCESS;
+#ifdef RT_OS_WINDOWS
+ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)NULL, FALSE /* Remove handler */))
+ {
+ rc = RTErrConvertFromWin32(GetLastError());
+ RTMsgError("Unable to uninstall console control handler, rc=%Rrc\n", rc);
+ }
+#else
signal(SIGINT, SIG_DFL);
-#ifdef SIGBREAK
+# ifdef SIGBREAK
signal(SIGBREAK, SIG_DFL);
+# endif
#endif
+ return rc;
}
/**
* Translates a process status to a human readable
* string.
*/
-static const char *ctrlExecProcessStatusToText(ProcessStatus_T enmStatus)
+const char *ctrlProcessStatusToText(ProcessStatus_T enmStatus)
{
switch (enmStatus)
{
@@ -384,6 +583,90 @@ static int ctrlExecProcessStatusToExitCode(ProcessStatus_T enmStatus, ULONG uExi
return vrc;
}
+const char *ctrlProcessWaitResultToText(ProcessWaitResult_T enmWaitResult)
+{
+ switch (enmWaitResult)
+ {
+ case ProcessWaitResult_Start:
+ return "started";
+ case ProcessWaitResult_Terminate:
+ return "terminated";
+ case ProcessWaitResult_Status:
+ return "status changed";
+ case ProcessWaitResult_Error:
+ return "error";
+ case ProcessWaitResult_Timeout:
+ return "timed out";
+ case ProcessWaitResult_StdIn:
+ return "stdin ready";
+ case ProcessWaitResult_StdOut:
+ return "data on stdout";
+ case ProcessWaitResult_StdErr:
+ return "data on stderr";
+ case ProcessWaitResult_WaitFlagNotSupported:
+ return "waiting flag not supported";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
+/**
+ * Translates a guest session status to a human readable
+ * string.
+ */
+const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus)
+{
+ switch (enmStatus)
+ {
+ case GuestSessionStatus_Starting:
+ return "starting";
+ case GuestSessionStatus_Started:
+ return "started";
+ case GuestSessionStatus_Terminating:
+ return "terminating";
+ case GuestSessionStatus_Terminated:
+ return "terminated";
+ case GuestSessionStatus_TimedOutKilled:
+ return "timed out";
+ case GuestSessionStatus_TimedOutAbnormally:
+ return "timed out, hanging";
+ case GuestSessionStatus_Down:
+ return "killed";
+ case GuestSessionStatus_Error:
+ return "error";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
+/**
+ * Translates a guest file status to a human readable
+ * string.
+ */
+const char *ctrlFileStatusToText(FileStatus_T enmStatus)
+{
+ switch (enmStatus)
+ {
+ case FileStatus_Opening:
+ return "opening";
+ case FileStatus_Open:
+ return "open";
+ case FileStatus_Closing:
+ return "closing";
+ case FileStatus_Closed:
+ return "closed";
+ case FileStatus_Down:
+ return "killed";
+ case FileStatus_Error:
+ return "error";
+ default:
+ break;
+ }
+ return "unknown";
+}
+
static int ctrlPrintError(com::ErrorInfo &errorInfo)
{
if ( errorInfo.isFullAvailable()
@@ -432,37 +715,86 @@ static int ctrlPrintProgressError(ComPtr<IProgress> pProgress)
} while(0);
- if (FAILED(rc))
- AssertMsgStmt(NULL, ("Could not lookup progress information\n"), vrc = VERR_COM_UNEXPECTED);
+ AssertMsgStmt(SUCCEEDED(rc), ("Could not lookup progress information\n"), vrc = VERR_COM_UNEXPECTED);
return vrc;
}
/**
* Un-initializes the VM after guest control usage.
+ * @param pCmdCtx Pointer to command context.
+ * @param uFlags Command context flags.
*/
-static void ctrlUninitVM(HandlerArg *pArg)
+static void ctrlUninitVM(PGCTLCMDCTX pCtx, uint32_t uFlags)
{
- AssertPtrReturnVoid(pArg);
- if (pArg->session)
- pArg->session->UnlockMachine();
+ AssertPtrReturnVoid(pCtx);
+
+ if (!(pCtx->uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
+ ctrlSignalHandlerUninstall();
+
+ HRESULT rc;
+
+ do
+ {
+ if (!pCtx->pGuestSession.isNull())
+ {
+ if ( !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS)
+ && !(pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH))
+ {
+ if (pCtx->fVerbose)
+ RTPrintf("Closing guest session ...\n");
+
+ CHECK_ERROR(pCtx->pGuestSession, Close());
+ /* Keep going - don't break here. Try to unlock the
+ * machine down below. */
+ }
+ else if ( (pCtx->uFlags & CTLCMDCTX_FLAGS_SESSION_DETACH)
+ && pCtx->fVerbose)
+ RTPrintf("Guest session detached\n");
+
+ pCtx->pGuestSession.setNull();
+ }
+
+ if (pCtx->handlerArg.session)
+ CHECK_ERROR(pCtx->handlerArg.session, UnlockMachine());
+
+ } while (0);
+
+ for (int i = 0; i < pCtx->iArgc; i++)
+ RTStrFree(pCtx->ppaArgv[i]);
+ RTMemFree(pCtx->ppaArgv);
+ pCtx->iArgc = 0;
}
/**
* Initializes the VM for IGuest operations.
*
* That is, checks whether it's up and running, if it can be locked (shared
- * only) and returns a valid IGuest pointer on success.
+ * only) and returns a valid IGuest pointer on success. Also, it does some
+ * basic command line processing and opens a guest session, if required.
*
- * @return IPRT status code.
- * @param pArg Our command line argument structure.
- * @param pszNameOrId The VM's name or UUID.
- * @param pGuest Where to return the IGuest interface pointer.
+ * @return RTEXITCODE status code.
+ * @param pArg Pointer to command line argument structure.
+ * @param pCmdCtx Pointer to command context.
+ * @param uFlags Command context flags.
*/
-static int ctrlInitVM(HandlerArg *pArg, const char *pszNameOrId, ComPtr<IGuest> *pGuest)
+static RTEXITCODE ctrlInitVM(HandlerArg *pArg,
+ PGCTLCMDCTX pCtx, uint32_t uFlags, uint32_t uUsage)
{
- AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
- AssertPtrReturn(pszNameOrId, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pArg, RTEXITCODE_FAILURE);
+ AssertReturn(pArg->argc > 1, RTEXITCODE_FAILURE);
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+#ifdef DEBUG_andy
+ RTPrintf("Original argv:\n");
+ for (int i=0; i<pArg->argc;i++)
+ RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
+#endif
+
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+
+ const char *pszNameOrId = pArg->argv[0];
+ const char *pszCmd = pArg->argv[1];
/* Lookup VM. */
ComPtr<IMachine> machine;
@@ -470,36 +802,243 @@ static int ctrlInitVM(HandlerArg *pArg, const char *pszNameOrId, ComPtr<IGuest>
HRESULT rc;
CHECK_ERROR(pArg->virtualBox, FindMachine(Bstr(pszNameOrId).raw(),
machine.asOutParam()));
- if (FAILED(rc))
- return VERR_NOT_FOUND;
+ if (SUCCEEDED(rc))
+ {
+ /* Machine is running? */
+ MachineState_T machineState;
+ CHECK_ERROR(machine, COMGETTER(State)(&machineState));
+ if ( SUCCEEDED(rc)
+ && (machineState != MachineState_Running))
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Machine \"%s\" is not running (currently %s)!\n",
+ pszNameOrId, machineStateToName(machineState, false));
+ }
+ else
+ rcExit = RTEXITCODE_FAILURE;
- /* Machine is running? */
- MachineState_T machineState;
- CHECK_ERROR_RET(machine, COMGETTER(State)(&machineState), 1);
- if (machineState != MachineState_Running)
+ if (rcExit == RTEXITCODE_SUCCESS)
{
- RTMsgError("Machine \"%s\" is not running (currently %s)!\n",
- pszNameOrId, machineStateToName(machineState, false));
- return VERR_VM_INVALID_VM_STATE;
+ /*
+ * Process standard options which are served by all commands.
+ */
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ { "--username", 'u', RTGETOPT_REQ_STRING },
+ { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
+ { "--password", GETOPTDEF_COMMON_PASSWORD, RTGETOPT_REQ_STRING },
+ { "--domain", 'd', RTGETOPT_REQ_STRING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+ };
+
+ /*
+ * Allocate per-command argv. This then only contains the specific arguments
+ * the command needs.
+ */
+ pCtx->ppaArgv = (char**)RTMemAlloc(pArg->argc * sizeof(char*) + 1);
+ if (!pCtx->ppaArgv)
+ {
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Not enough memory for per-command argv\n");
+ }
+ else
+ {
+ pCtx->iArgc = 0;
+
+ int iArgIdx = 2; /* Skip VM name and guest control command */
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, pArg->argc, pArg->argv,
+ s_aOptions, RT_ELEMENTS(s_aOptions),
+ iArgIdx, 0);
+
+ while ( (ch = RTGetOpt(&GetState, &ValueUnion))
+ && (rcExit == RTEXITCODE_SUCCESS))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
+ {
+ case 'u': /* User name */
+ if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+ pCtx->strUsername = ValueUnion.psz;
+ iArgIdx = GetState.iNext;
+ break;
+
+ case GETOPTDEF_COMMON_PASSWORD: /* Password */
+ if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+ {
+ if (pCtx->strPassword.isEmpty())
+ pCtx->strPassword = ValueUnion.psz;
+ }
+ iArgIdx = GetState.iNext;
+ break;
+
+ case 'p': /* Password file */
+ {
+ if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+ rcExit = readPasswordFile(ValueUnion.psz, &pCtx->strPassword);
+ iArgIdx = GetState.iNext;
+ break;
+ }
+
+ case 'd': /* domain */
+ if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+ pCtx->strDomain = ValueUnion.psz;
+ iArgIdx = GetState.iNext;
+ break;
+
+ case 'v': /* Verbose */
+ pCtx->fVerbose = true;
+ iArgIdx = GetState.iNext;
+ break;
+
+ case 'h': /* Help */
+ errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion);
+ return RTEXITCODE_SYNTAX;
+
+ default:
+ /* Simply skip; might be handled in a specific command
+ * handler later. */
+ break;
+
+ } /* switch */
+
+ int iArgDiff = GetState.iNext - iArgIdx;
+ if (iArgDiff)
+ {
+#ifdef DEBUG_andy
+ RTPrintf("Not handled (iNext=%d, iArgsCur=%d):\n", GetState.iNext, iArgIdx);
+#endif
+ for (int i = iArgIdx; i < GetState.iNext; i++)
+ {
+ char *pszArg = RTStrDup(pArg->argv[i]);
+ if (!pszArg)
+ {
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,
+ "Not enough memory for command line handling\n");
+ break;
+ }
+ pCtx->ppaArgv[pCtx->iArgc] = pszArg;
+ pCtx->iArgc++;
+#ifdef DEBUG_andy
+ RTPrintf("\targv[%d]=%s\n", i, pArg->argv[i]);
+#endif
+ }
+
+ iArgIdx = GetState.iNext;
+ }
+
+ } /* while RTGetOpt */
+ }
}
- do
+ /*
+ * Check for mandatory stuff.
+ */
+ if (rcExit == RTEXITCODE_SUCCESS)
{
- /* Open a session for the VM. */
- CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared));
- /* Get the associated console. */
- ComPtr<IConsole> console;
- CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam()));
- /* ... and session machine. */
- ComPtr<IMachine> sessionMachine;
- CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
- /* Get IGuest interface. */
- CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pGuest->asOutParam()));
- } while (0);
+#if 0
+ RTPrintf("argc=%d\n", pCtx->iArgc);
+ for (int i = 0; i < pCtx->iArgc; i++)
+ RTPrintf("argv[%d]=%s\n", i, pCtx->ppaArgv[i]);
+#endif
+ if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+ {
+ if (pCtx->strUsername.isEmpty())
+ rcExit = errorSyntaxEx(USAGE_GUESTCONTROL, uUsage, "No user name specified!");
+ }
+ }
- if (FAILED(rc))
- ctrlUninitVM(pArg);
- return SUCCEEDED(rc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
+ if (rcExit == RTEXITCODE_SUCCESS)
+ {
+ /*
+ * Build up a reasonable guest session name. Useful for identifying
+ * a specific session when listing / searching for them.
+ */
+ char *pszSessionName;
+ if (0 >= RTStrAPrintf(&pszSessionName,
+ "[%RU32] VBoxManage Guest Control [%s] - %s",
+ RTProcSelf(), pszNameOrId, pszCmd))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "No enough memory for session name\n");
+
+ do
+ {
+ /* Open a session for the VM. */
+ CHECK_ERROR_BREAK(machine, LockMachine(pArg->session, LockType_Shared));
+ /* Get the associated console. */
+ ComPtr<IConsole> console;
+ CHECK_ERROR_BREAK(pArg->session, COMGETTER(Console)(console.asOutParam()));
+ /* ... and session machine. */
+ ComPtr<IMachine> sessionMachine;
+ CHECK_ERROR_BREAK(pArg->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
+ /* Get IGuest interface. */
+ CHECK_ERROR_BREAK(console, COMGETTER(Guest)(pCtx->pGuest.asOutParam()));
+ if (!(uFlags & CTLCMDCTX_FLAGS_SESSION_ANONYMOUS))
+ {
+ if (pCtx->fVerbose)
+ RTPrintf("Opening guest session as user '%s' ...\n", pCtx->strUsername.c_str());
+
+ /* Open a guest session. */
+ Assert(!pCtx->pGuest.isNull());
+ CHECK_ERROR_BREAK(pCtx->pGuest, CreateSession(Bstr(pCtx->strUsername).raw(),
+ Bstr(pCtx->strPassword).raw(),
+ Bstr(pCtx->strDomain).raw(),
+ Bstr(pszSessionName).raw(),
+ pCtx->pGuestSession.asOutParam()));
+
+ /*
+ * Wait for guest session to start.
+ */
+ if (pCtx->fVerbose)
+ RTPrintf("Waiting for guest session to start ...\n");
+
+ com::SafeArray<GuestSessionWaitForFlag_T> aSessionWaitFlags;
+ aSessionWaitFlags.push_back(GuestSessionWaitForFlag_Start);
+ GuestSessionWaitResult_T sessionWaitResult;
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, WaitForArray(ComSafeArrayAsInParam(aSessionWaitFlags),
+ /** @todo Make session handling timeouts configurable. */
+ 30 * 1000, &sessionWaitResult));
+
+ if ( sessionWaitResult == GuestSessionWaitResult_Start
+ /* Note: This might happen when Guest Additions < 4.3 are installed which don't
+ * support dedicated guest sessions. */
+ || sessionWaitResult == GuestSessionWaitResult_WaitFlagNotSupported)
+ {
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Id)(&pCtx->uSessionID));
+ if (pCtx->fVerbose)
+ RTPrintf("Guest session (ID %RU32) has been started\n", pCtx->uSessionID);
+ }
+ else
+ {
+ GuestSessionStatus_T sessionStatus;
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, COMGETTER(Status)(&sessionStatus));
+ rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Error starting guest session (current status is: %s)\n",
+ ctrlSessionStatusToText(sessionStatus));
+ break;
+ }
+ }
+
+ if ( SUCCEEDED(rc)
+ && !(uFlags & CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER))
+ {
+ ctrlSignalHandlerInstall();
+ }
+
+ } while (0);
+
+ if (FAILED(rc))
+ rcExit = RTEXITCODE_FAILURE;
+
+ RTStrFree(pszSessionName);
+ }
+
+ if (rcExit == RTEXITCODE_SUCCESS)
+ {
+ pCtx->handlerArg = *pArg;
+ pCtx->uFlags = uFlags;
+ }
+ else /* Clean up on failure. */
+ ctrlUninitVM(pCtx, uFlags);
+
+ return rcExit;
}
/**
@@ -508,10 +1047,11 @@ static int ctrlInitVM(HandlerArg *pArg, const char *pszNameOrId, ComPtr<IGuest>
* @return IPRT status code.
* @param pProcess Pointer to appropriate process object.
* @param pStrmOutput Where to write the data.
- * @param hStream Where to read the data from.
+ * @param uHandle Handle where to read the data from.
+ * @param uTimeoutMS Timeout (in ms) to wait for the operation to complete.
*/
static int ctrlExecPrintOutput(IProcess *pProcess, PRTSTREAM pStrmOutput,
- ULONG uHandle)
+ ULONG uHandle, ULONG uTimeoutMS)
{
AssertPtrReturn(pProcess, VERR_INVALID_POINTER);
AssertPtrReturn(pStrmOutput, VERR_INVALID_POINTER);
@@ -519,16 +1059,58 @@ static int ctrlExecPrintOutput(IProcess *pProcess, PRTSTREAM pStrmOutput,
int vrc = VINF_SUCCESS;
SafeArray<BYTE> aOutputData;
- HRESULT rc = pProcess->Read(uHandle, _64K, 30 * 1000 /* 30s timeout. */,
+ HRESULT rc = pProcess->Read(uHandle, _64K, uTimeoutMS,
ComSafeArrayAsOutParam(aOutputData));
if (FAILED(rc))
vrc = ctrlPrintError(pProcess, COM_IIDOF(IProcess));
else
{
- /** @todo implement the dos2unix/unix2dos conversions */
- vrc = RTStrmWrite(pStrmOutput, aOutputData.raw(), aOutputData.size());
- if (RT_FAILURE(vrc))
- RTMsgError("Unable to write output, rc=%Rrc\n", vrc);
+ size_t cbOutputData = aOutputData.size();
+ if (cbOutputData > 0)
+ {
+ BYTE *pBuf = aOutputData.raw();
+ AssertPtr(pBuf);
+ pBuf[cbOutputData - 1] = 0; /* Properly terminate buffer. */
+
+ /** @todo implement the dos2unix/unix2dos conversions */
+
+ /*
+ * If aOutputData is text data from the guest process' stdout or stderr,
+ * it has a platform dependent line ending. So standardize on
+ * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
+ * Windows. Otherwise we end up with CR/CR/LF on Windows.
+ */
+
+ char *pszBufUTF8;
+ vrc = RTStrCurrentCPToUtf8(&pszBufUTF8, (const char*)aOutputData.raw());
+ if (RT_SUCCESS(vrc))
+ {
+ cbOutputData = strlen(pszBufUTF8);
+
+ ULONG cbOutputDataPrint = cbOutputData;
+ for (char *s = pszBufUTF8, *d = s;
+ s - pszBufUTF8 < (ssize_t)cbOutputData;
+ s++, d++)
+ {
+ if (*s == '\r')
+ {
+ /* skip over CR, adjust destination */
+ d--;
+ cbOutputDataPrint--;
+ }
+ else if (s != d)
+ *d = *s;
+ }
+
+ vrc = RTStrmWrite(pStrmOutput, pszBufUTF8, cbOutputDataPrint);
+ if (RT_FAILURE(vrc))
+ RTMsgError("Unable to write output, rc=%Rrc\n", vrc);
+
+ RTStrFree(pszBufUTF8);
+ }
+ else
+ RTMsgError("Unable to convert output, rc=%Rrc\n", vrc);
+ }
}
return vrc;
@@ -547,17 +1129,16 @@ inline RTMSINTERVAL ctrlExecGetRemainingTime(uint64_t u64StartMs, RTMSINTERVAL c
if (!cMsTimeout || cMsTimeout == RT_INDEFINITE_WAIT) /* If no timeout specified, wait forever. */
return RT_INDEFINITE_WAIT;
- uint32_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
+ uint64_t u64ElapsedMs = RTTimeMilliTS() - u64StartMs;
if (u64ElapsedMs >= cMsTimeout)
return 0;
- return cMsTimeout - u64ElapsedMs;
+ return cMsTimeout - (RTMSINTERVAL)u64ElapsedMs;
}
-/* <Missing documentation> */
-static int handleCtrlExecProgram(ComPtr<IGuest> pGuest, HandlerArg *pArg)
+static DECLCALLBACK(RTEXITCODE) handleCtrlProcessExec(PGCTLCMDCTX pCtx)
{
- AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
/*
* Parse arguments.
@@ -570,352 +1151,374 @@ static int handleCtrlExecProgram(ComPtr<IGuest> pGuest, HandlerArg *pArg)
{ "--ignore-operhaned-processes", GETOPTDEF_EXEC_IGNOREORPHANEDPROCESSES, RTGETOPT_REQ_NOTHING },
{ "--image", 'i', RTGETOPT_REQ_STRING },
{ "--no-profile", GETOPTDEF_EXEC_NO_PROFILE, RTGETOPT_REQ_NOTHING },
- { "--username", 'u', RTGETOPT_REQ_STRING },
- { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
- { "--password", GETOPTDEF_EXEC_PASSWORD, RTGETOPT_REQ_STRING },
- { "--domain", 'd', RTGETOPT_REQ_STRING },
{ "--timeout", 't', RTGETOPT_REQ_UINT32 },
{ "--unix2dos", GETOPTDEF_EXEC_UNIX2DOS, RTGETOPT_REQ_NOTHING },
- { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
{ "--wait-exit", GETOPTDEF_EXEC_WAITFOREXIT, RTGETOPT_REQ_NOTHING },
{ "--wait-stdout", GETOPTDEF_EXEC_WAITFORSTDOUT, RTGETOPT_REQ_NOTHING },
{ "--wait-stderr", GETOPTDEF_EXEC_WAITFORSTDERR, RTGETOPT_REQ_NOTHING }
};
+#ifdef DEBUG_andy
+ RTPrintf("first=%d\n", pCtx->iFirstArgc);
+ for (int i=0; i<pCtx->iArgc;i++)
+ RTPrintf("\targv[%d]=%s\n", i, pCtx->ppaArgv[i]);
+#endif
+
int ch;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
- RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions),
+ pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
- Utf8Str strCmd;
+ Utf8Str strCmd;
com::SafeArray<ProcessCreateFlag_T> aCreateFlags;
com::SafeArray<ProcessWaitForFlag_T> aWaitFlags;
- com::SafeArray<IN_BSTR> args;
- com::SafeArray<IN_BSTR> env;
- Utf8Str strUsername;
- Utf8Str strPassword;
- Utf8Str strDomain;
+ com::SafeArray<IN_BSTR> aArgs;
+ com::SafeArray<IN_BSTR> aEnv;
RTMSINTERVAL cMsTimeout = 0;
OUTPUTTYPE eOutputType = OUTPUTTYPE_UNDEFINED;
- bool fWaitForExit = false;
- bool fVerbose = false;
+ bool fDetached = true;
int vrc = VINF_SUCCESS;
- /* Wait for process start in any case. This is useful for scripting VBoxManage
- * when relying on its overall exit code. */
- aWaitFlags.push_back(ProcessWaitForFlag_Start);
-
- while ( (ch = RTGetOpt(&GetState, &ValueUnion))
- && RT_SUCCESS(vrc))
+ try
{
- /* For options that require an argument, ValueUnion has received the value. */
- switch (ch)
- {
- case GETOPTDEF_EXEC_DOS2UNIX:
- if (eOutputType != OUTPUTTYPE_UNDEFINED)
- return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!");
- eOutputType = OUTPUTTYPE_DOS2UNIX;
- break;
+ /* Wait for process start in any case. This is useful for scripting VBoxManage
+ * when relying on its overall exit code. */
+ aWaitFlags.push_back(ProcessWaitForFlag_Start);
- case 'e': /* Environment */
+ while ( (ch = RTGetOpt(&GetState, &ValueUnion))
+ && RT_SUCCESS(vrc))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
{
- char **papszArg;
- int cArgs;
-
- vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL);
- if (RT_FAILURE(vrc))
- return errorSyntax(USAGE_GUESTCONTROL, "Failed to parse environment value, rc=%Rrc", vrc);
- for (int j = 0; j < cArgs; j++)
- env.push_back(Bstr(papszArg[j]).raw());
-
- RTGetOptArgvFree(papszArg);
- break;
- }
-
- case GETOPTDEF_EXEC_IGNOREORPHANEDPROCESSES:
- aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses);
- break;
+ case GETOPTDEF_EXEC_DOS2UNIX:
+ if (eOutputType != OUTPUTTYPE_UNDEFINED)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
+ "More than one output type (dos2unix/unix2dos) specified!");
+ eOutputType = OUTPUTTYPE_DOS2UNIX;
+ break;
- case GETOPTDEF_EXEC_NO_PROFILE:
- aCreateFlags.push_back(ProcessCreateFlag_NoProfile);
- break;
+ case 'e': /* Environment */
+ {
+ char **papszArg;
+ int cArgs;
- case 'i':
- strCmd = ValueUnion.psz;
- break;
+ vrc = RTGetOptArgvFromString(&papszArg, &cArgs, ValueUnion.psz, NULL);
+ if (RT_FAILURE(vrc))
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
+ "Failed to parse environment value, rc=%Rrc", vrc);
+ for (int j = 0; j < cArgs; j++)
+ aEnv.push_back(Bstr(papszArg[j]).raw());
- /** @todo Add a hidden flag. */
+ RTGetOptArgvFree(papszArg);
+ break;
+ }
- case 'u': /* User name */
- strUsername = ValueUnion.psz;
- break;
+ case GETOPTDEF_EXEC_IGNOREORPHANEDPROCESSES:
+ aCreateFlags.push_back(ProcessCreateFlag_IgnoreOrphanedProcesses);
+ break;
- case GETOPTDEF_EXEC_PASSWORD: /* Password */
- strPassword = ValueUnion.psz;
- break;
+ case GETOPTDEF_EXEC_NO_PROFILE:
+ aCreateFlags.push_back(ProcessCreateFlag_NoProfile);
+ break;
- case 'p': /* Password file */
- {
- RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);
- if (rcExit != RTEXITCODE_SUCCESS)
- return rcExit;
- break;
- }
+ case 'i':
+ strCmd = ValueUnion.psz;
+ break;
- case 'd': /* domain */
- strDomain = ValueUnion.psz;
- break;
+ /** @todo Add a hidden flag. */
- case 't': /* Timeout */
- cMsTimeout = ValueUnion.u32;
- break;
+ case 't': /* Timeout */
+ cMsTimeout = ValueUnion.u32;
+ break;
- case GETOPTDEF_EXEC_UNIX2DOS:
- if (eOutputType != OUTPUTTYPE_UNDEFINED)
- return errorSyntax(USAGE_GUESTCONTROL, "More than one output type (dos2unix/unix2dos) specified!");
- eOutputType = OUTPUTTYPE_UNIX2DOS;
- break;
+ case GETOPTDEF_EXEC_UNIX2DOS:
+ if (eOutputType != OUTPUTTYPE_UNDEFINED)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
+ "More than one output type (dos2unix/unix2dos) specified!");
+ eOutputType = OUTPUTTYPE_UNIX2DOS;
+ break;
- case 'v': /* Verbose */
- fVerbose = true;
- break;
+ case GETOPTDEF_EXEC_WAITFOREXIT:
+ aWaitFlags.push_back(ProcessWaitForFlag_Terminate);
+ fDetached = false;
+ break;
- case GETOPTDEF_EXEC_WAITFOREXIT:
- aWaitFlags.push_back(ProcessWaitForFlag_Terminate);
- fWaitForExit = true;
- break;
+ case GETOPTDEF_EXEC_WAITFORSTDOUT:
+ aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut);
+ aWaitFlags.push_back(ProcessWaitForFlag_StdOut);
+ fDetached = false;
+ break;
- case GETOPTDEF_EXEC_WAITFORSTDOUT:
- aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut);
- aWaitFlags.push_back(ProcessWaitForFlag_StdOut);
- fWaitForExit = true;
- break;
+ case GETOPTDEF_EXEC_WAITFORSTDERR:
+ aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr);
+ aWaitFlags.push_back(ProcessWaitForFlag_StdErr);
+ fDetached = false;
+ break;
- case GETOPTDEF_EXEC_WAITFORSTDERR:
- aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr);
- aWaitFlags.push_back(ProcessWaitForFlag_StdErr);
- fWaitForExit = true;
- break;
+ case VINF_GETOPT_NOT_OPTION:
+ if (aArgs.size() == 0 && strCmd.isEmpty())
+ strCmd = ValueUnion.psz;
+ else
+ aArgs.push_back(Bstr(ValueUnion.psz).raw());
+ break;
- case VINF_GETOPT_NOT_OPTION:
- {
- if (args.size() == 0 && strCmd.isEmpty())
- strCmd = ValueUnion.psz;
- else
- args.push_back(Bstr(ValueUnion.psz).raw());
- break;
- }
+ default:
+ /* Note: Necessary for handling non-options (after --) which
+ * contain a single dash, e.g. "-- foo.exe -s". */
+ if (GetState.argc == GetState.iNext)
+ aArgs.push_back(Bstr(ValueUnion.psz).raw());
+ else
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC, ch, &ValueUnion);
+ break;
- default:
- return RTGetOptPrintError(ch, &ValueUnion);
- }
+ } /* switch */
+ } /* while RTGetOpt */
}
-
- if (strCmd.isEmpty())
- return errorSyntax(USAGE_GUESTCONTROL, "No command to execute specified!");
-
- if (strUsername.isEmpty())
- return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");
-
- /* Any output conversion not supported yet! */
- if (eOutputType != OUTPUTTYPE_UNDEFINED)
- return errorSyntax(USAGE_GUESTCONTROL, "Output conversion not implemented yet!");
-
- /*
- * Start with the real work.
- */
- HRESULT rc = S_OK;
- if (fVerbose)
+ catch (std::bad_alloc &)
{
- if (cMsTimeout == 0)
- RTPrintf("Waiting for guest to start process ...\n");
- else
- RTPrintf("Waiting for guest to start process (within %ums)\n", cMsTimeout);
+ vrc = VERR_NO_MEMORY;
}
- /** @todo This eventually needs a bit of revamping so that a valid session gets passed
- * into this function already so that we don't need to mess around with closing
- * the session all over the places below again. Later. */
-
- ComPtr<IGuestSession> pGuestSession;
- rc = pGuest->CreateSession(Bstr(strUsername).raw(),
- Bstr(strPassword).raw(),
- Bstr(strDomain).raw(),
- Bstr("VBoxManage Guest Control Exec").raw(),
- pGuestSession.asOutParam());
- if (FAILED(rc))
- {
- ctrlPrintError(pGuest, COM_IIDOF(IGuest));
- return RTEXITCODE_FAILURE;
- }
+ if (RT_FAILURE(vrc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize, rc=%Rrc\n", vrc);
- /* Get current time stamp to later calculate rest of timeout left. */
- uint64_t u64StartMS = RTTimeMilliTS();
+ if (strCmd.isEmpty())
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
+ "No command to execute specified!");
- /*
- * Execute the process.
- */
- ComPtr<IGuestProcess> pProcess;
- rc = pGuestSession->ProcessCreate(Bstr(strCmd).raw(),
- ComSafeArrayAsInParam(args),
- ComSafeArrayAsInParam(env),
- ComSafeArrayAsInParam(aCreateFlags),
- cMsTimeout,
- pProcess.asOutParam());
- if (FAILED(rc))
- {
- ctrlPrintError(pGuestSession, COM_IIDOF(IGuestSession));
+ /** @todo Any output conversion not supported yet! */
+ if (eOutputType != OUTPUTTYPE_UNDEFINED)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_EXEC,
+ "Output conversion not implemented yet!");
- pGuestSession->Close();
- return RTEXITCODE_FAILURE;
- }
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ HRESULT rc;
- if (fWaitForExit)
+ try
{
- if (fVerbose)
+ do
{
- if (cMsTimeout) /* Wait with a certain timeout. */
+ /* Adjust process creation flags if we don't want to wait for process termination. */
+ if (fDetached)
+ aCreateFlags.push_back(ProcessCreateFlag_WaitForProcessStartOnly);
+
+ /* Get current time stamp to later calculate rest of timeout left. */
+ uint64_t u64StartMS = RTTimeMilliTS();
+
+ if (pCtx->fVerbose)
{
- /* Calculate timeout value left after process has been started. */
- uint64_t u64Elapsed = RTTimeMilliTS() - u64StartMS;
- /* Is timeout still bigger than current difference? */
- if (cMsTimeout > u64Elapsed)
- RTPrintf("Waiting for process to exit (%ums left) ...\n", cMsTimeout - u64Elapsed);
+ if (cMsTimeout == 0)
+ RTPrintf("Starting guest process ...\n");
else
- RTPrintf("No time left to wait for process!\n"); /** @todo a bit misleading ... */
+ RTPrintf("Starting guest process (within %ums)\n", cMsTimeout);
}
- else /* Wait forever. */
- RTPrintf("Waiting for process to exit ...\n");
- }
- /** @todo does this need signal handling? there's no progress object etc etc */
-
- vrc = RTStrmSetMode(g_pStdOut, 1 /* Binary mode */, -1 /* Code set, unchanged */);
- if (RT_FAILURE(vrc))
- RTMsgError("Unable to set stdout's binary mode, rc=%Rrc\n", vrc);
- vrc = RTStrmSetMode(g_pStdErr, 1 /* Binary mode */, -1 /* Code set, unchanged */);
- if (RT_FAILURE(vrc))
- RTMsgError("Unable to set stderr's binary mode, rc=%Rrc\n", vrc);
-
- /* Wait for process to exit ... */
- RTMSINTERVAL cMsTimeLeft = 1;
- bool fReadStdOut, fReadStdErr;
- fReadStdOut = fReadStdErr = false;
- bool fCompleted = false;
- while (!fCompleted && cMsTimeLeft != 0)
- {
- cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
+ /*
+ * Execute the process.
+ */
+ ComPtr<IGuestProcess> pProcess;
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, ProcessCreate(Bstr(strCmd).raw(),
+ ComSafeArrayAsInParam(aArgs),
+ ComSafeArrayAsInParam(aEnv),
+ ComSafeArrayAsInParam(aCreateFlags),
+ ctrlExecGetRemainingTime(u64StartMS, cMsTimeout),
+ pProcess.asOutParam()));
+
+ /*
+ * Explicitly wait for the guest process to be in a started
+ * state.
+ */
+ com::SafeArray<ProcessWaitForFlag_T> aWaitStartFlags;
+ aWaitStartFlags.push_back(ProcessWaitForFlag_Start);
ProcessWaitResult_T waitResult;
- rc = pProcess->WaitForArray(ComSafeArrayAsInParam(aWaitFlags), cMsTimeLeft, &waitResult);
- if (FAILED(rc))
- {
- ctrlPrintError(pProcess, COM_IIDOF(IProcess));
+ CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitStartFlags),
+ ctrlExecGetRemainingTime(u64StartMS, cMsTimeout), &waitResult));
+ bool fCompleted = false;
- pGuestSession->Close();
- return RTEXITCODE_FAILURE;
+ ULONG uPID = 0;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
+ if (!fDetached && pCtx->fVerbose)
+ {
+ RTPrintf("Process '%s' (PID %RU32) started\n",
+ strCmd.c_str(), uPID);
+ }
+ else if (fDetached) /** @todo Introduce a --quiet option for not printing this. */
+ {
+ /* Just print plain PID to make it easier for scripts
+ * invoking VBoxManage. */
+ RTPrintf("[%RU32 - Session %RU32]\n", uPID, pCtx->uSessionID);
}
- switch (waitResult)
+ vrc = RTStrmSetMode(g_pStdOut, 1 /* Binary mode */, -1 /* Code set, unchanged */);
+ if (RT_FAILURE(vrc))
+ RTMsgError("Unable to set stdout's binary mode, rc=%Rrc\n", vrc);
+ vrc = RTStrmSetMode(g_pStdErr, 1 /* Binary mode */, -1 /* Code set, unchanged */);
+ if (RT_FAILURE(vrc))
+ RTMsgError("Unable to set stderr's binary mode, rc=%Rrc\n", vrc);
+
+ /* Wait for process to exit ... */
+ RTMSINTERVAL cMsTimeLeft = 1; /* Will be calculated. */
+ bool fReadStdOut, fReadStdErr;
+ fReadStdOut = fReadStdErr = false;
+
+ while ( !fCompleted
+ && !fDetached
+ && cMsTimeLeft != 0)
{
- case ProcessWaitResult_Start:
+ cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
+ CHECK_ERROR_BREAK(pProcess, WaitForArray(ComSafeArrayAsInParam(aWaitFlags),
+ 500 /* ms */, &waitResult));
+ switch (waitResult)
{
- if (fVerbose)
+ case ProcessWaitResult_Start:
{
- ULONG uPID = 0;
- rc = pProcess->COMGETTER(PID)(&uPID);
- if (FAILED(rc))
- {
- ctrlPrintError(pProcess, COM_IIDOF(IProcess));
+ /* We're done here if we don't want to wait for termination. */
+ if (fDetached)
+ fCompleted = true;
- pGuestSession->Close();
- return RTEXITCODE_FAILURE;
- }
- RTPrintf("Process '%s' (PID: %u) started\n", strCmd.c_str(), uPID);
+ break;
}
- break;
+ case ProcessWaitResult_StdOut:
+ fReadStdOut = true;
+ break;
+ case ProcessWaitResult_StdErr:
+ fReadStdErr = true;
+ break;
+ case ProcessWaitResult_Terminate:
+ if (pCtx->fVerbose)
+ RTPrintf("Process terminated\n");
+ /* Process terminated, we're done. */
+ fCompleted = true;
+ break;
+ case ProcessWaitResult_WaitFlagNotSupported:
+ {
+ /* The guest does not support waiting for stdout/err, so
+ * yield to reduce the CPU load due to busy waiting. */
+ RTThreadYield(); /* Optional, don't check rc. */
+
+ /* Try both, stdout + stderr. */
+ fReadStdOut = fReadStdErr = true;
+ break;
+ }
+ case ProcessWaitResult_Timeout:
+ /* Fall through is intentional. */
+ default:
+ /* Ignore all other results, let the timeout expire */
+ break;
}
- case ProcessWaitResult_StdOut:
- fReadStdOut = true;
- break;
- case ProcessWaitResult_StdErr:
- fReadStdErr = true;
- break;
- case ProcessWaitResult_Terminate:
- /* Process terminated, we're done */
- fCompleted = true;
+
+ if (g_fGuestCtrlCanceled)
break;
- case ProcessWaitResult_WaitFlagNotSupported:
+
+ if (fReadStdOut) /* Do we need to fetch stdout data? */
{
- /* The guest does not support waiting for stdout/err, so
- * yield to reduce the CPU load due to busy waiting. */
- RTThreadYield(); /* Optional, don't check rc. */
+ cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
+ vrc = ctrlExecPrintOutput(pProcess, g_pStdOut,
+ 1 /* StdOut */, cMsTimeLeft);
+ fReadStdOut = false;
+ }
- /* Try both, stdout + stderr. */
- fReadStdOut = fReadStdErr = true;
- break;
+ if (fReadStdErr) /* Do we need to fetch stdout data? */
+ {
+ cMsTimeLeft = ctrlExecGetRemainingTime(u64StartMS, cMsTimeout);
+ vrc = ctrlExecPrintOutput(pProcess, g_pStdErr,
+ 2 /* StdErr */, cMsTimeLeft);
+ fReadStdErr = false;
}
- default:
- /* Ignore all other results, let the timeout expire */;
- break;
- }
- if (fReadStdOut) /* Do we need to fetch stdout data? */
- {
- vrc = ctrlExecPrintOutput(pProcess, g_pStdOut, 1 /* StdOut */);
- fReadStdOut = false;
- }
+ if ( RT_FAILURE(vrc)
+ || g_fGuestCtrlCanceled)
+ break;
- if (fReadStdErr) /* Do we need to fetch stdout data? */
- {
- vrc = ctrlExecPrintOutput(pProcess, g_pStdErr, 2 /* StdErr */);
- fReadStdErr = false;
- }
+ /* Did we run out of time? */
+ if ( cMsTimeout
+ && RTTimeMilliTS() - u64StartMS > cMsTimeout)
+ break;
- if (RT_FAILURE(vrc))
- break;
+ NativeEventQueue::getMainEventQueue()->processEventQueue(0);
- } /* while */
+ } /* while */
- /* Report status back to the user. */
- if (fCompleted)
- {
- ProcessStatus_T status;
- rc = pProcess->COMGETTER(Status)(&status);
- if (FAILED(rc))
+ if (!fDetached)
{
- ctrlPrintError(pProcess, COM_IIDOF(IProcess));
+ /* Report status back to the user. */
+ if ( fCompleted
+ && !g_fGuestCtrlCanceled)
+ {
- pGuestSession->Close();
- return RTEXITCODE_FAILURE;
- }
- LONG exitCode;
- rc = pProcess->COMGETTER(ExitCode)(&exitCode);
- if (FAILED(rc))
- {
- ctrlPrintError(pProcess, COM_IIDOF(IProcess));
+ {
+ ProcessStatus_T procStatus;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(Status)(&procStatus));
+ if ( procStatus == ProcessStatus_TerminatedNormally
+ || procStatus == ProcessStatus_TerminatedAbnormally
+ || procStatus == ProcessStatus_TerminatedSignal)
+ {
+ LONG exitCode;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(ExitCode)(&exitCode));
+ if (pCtx->fVerbose)
+ RTPrintf("Exit code=%u (Status=%u [%s])\n",
+ exitCode, procStatus, ctrlProcessStatusToText(procStatus));
- pGuestSession->Close();
- return RTEXITCODE_FAILURE;
+ rcExit = (RTEXITCODE)ctrlExecProcessStatusToExitCode(procStatus, exitCode);
+ }
+ else if (pCtx->fVerbose)
+ RTPrintf("Process now is in status [%s]\n", ctrlProcessStatusToText(procStatus));
+ }
+ }
+ else
+ {
+ if (pCtx->fVerbose)
+ RTPrintf("Process execution aborted!\n");
+
+ rcExit = (RTEXITCODE)EXITCODEEXEC_TERM_ABEND;
+ }
}
- if (fVerbose)
- RTPrintf("Exit code=%u (Status=%u [%s])\n", exitCode, status, ctrlExecProcessStatusToText(status));
- pGuestSession->Close();
- return ctrlExecProcessStatusToExitCode(status, exitCode);
- }
- else
- {
- if (fVerbose)
- RTPrintf("Process execution aborted!\n");
+ } while (0);
+ }
+ catch (std::bad_alloc)
+ {
+ rc = E_OUTOFMEMORY;
+ }
- pGuestSession->Close();
- return EXITCODEEXEC_TERM_ABEND;
- }
+ /*
+ * Decide what to do with the guest session. If we started a
+ * detached guest process (that is, without waiting for it to exit),
+ * don't close the guest session it is part of.
+ */
+ bool fCloseSession = false;
+ if (SUCCEEDED(rc))
+ {
+ /*
+ * Only close the guest session if we waited for the guest
+ * process to exit. Otherwise we wouldn't have any chance to
+ * access and/or kill detached guest process lateron.
+ */
+ fCloseSession = !fDetached;
+
+ /*
+ * If execution was aborted from the host side (signal handler),
+ * close the guest session in any case.
+ */
+ if (g_fGuestCtrlCanceled)
+ fCloseSession = true;
}
+ else /* Close session on error. */
+ fCloseSession = true;
+
+ if (!fCloseSession)
+ pCtx->uFlags |= CTLCMDCTX_FLAGS_SESSION_DETACH;
- pGuestSession->Close();
+ if ( rcExit == RTEXITCODE_SUCCESS
+ && FAILED(rc))
+ {
+ /* Make sure an appropriate exit code is set on error. */
+ rcExit = RTEXITCODE_FAILURE;
+ }
- return RT_FAILURE(vrc) || FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
+ return rcExit;
}
/**
@@ -923,44 +1526,36 @@ static int handleCtrlExecProgram(ComPtr<IGuest> pGuest, HandlerArg *pArg)
* guest control copy functions. Needs to be free'd with ctrlCopyContextFree().
*
* @return IPRT status code.
- * @param pGuest Pointer to IGuest interface to use.
- * @param fVerbose Flag indicating if we want to run in verbose mode.
+ * @param pCtx Pointer to command context.
* @param fDryRun Flag indicating if we want to run a dry run only.
* @param fHostToGuest Flag indicating if we want to copy from host to guest
* or vice versa.
- * @param strUsername Username of account to use on the guest side.
- * @param strPassword Password of account to use.
- * @param strDomain Domain of account to use.
* @param strSessionName Session name (only for identification purposes).
* @param ppContext Pointer which receives the allocated copy context.
*/
-static int ctrlCopyContextCreate(IGuest *pGuest, bool fVerbose, bool fDryRun,
- bool fHostToGuest, const Utf8Str &strUsername,
- const Utf8Str &strPassword, const Utf8Str &strDomain,
+static int ctrlCopyContextCreate(PGCTLCMDCTX pCtx, bool fDryRun, bool fHostToGuest,
const Utf8Str &strSessionName,
PCOPYCONTEXT *ppContext)
{
- AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
- PCOPYCONTEXT pContext = new COPYCONTEXT();
- AssertPtrReturn(pContext, VERR_NO_MEMORY); /**< @todo r=klaus cannot happen with new */
- ComPtr<IGuestSession> pGuestSession;
- HRESULT rc = pGuest->CreateSession(Bstr(strUsername).raw(),
- Bstr(strPassword).raw(),
- Bstr(strDomain).raw(),
- Bstr(strSessionName).raw(),
- pGuestSession.asOutParam());
- if (FAILED(rc))
- return ctrlPrintError(pGuest, COM_IIDOF(IGuest));
+ int vrc = VINF_SUCCESS;
+ try
+ {
+ PCOPYCONTEXT pContext = new COPYCONTEXT();
- pContext->fVerbose = fVerbose;
- pContext->fDryRun = fDryRun;
- pContext->fHostToGuest = fHostToGuest;
- pContext->pGuestSession = pGuestSession;
+ pContext->pCmdCtx = pCtx;
+ pContext->fDryRun = fDryRun;
+ pContext->fHostToGuest = fHostToGuest;
- *ppContext = pContext;
+ *ppContext = pContext;
+ }
+ catch (std::bad_alloc)
+ {
+ vrc = VERR_NO_MEMORY;
+ }
- return VINF_SUCCESS;
+ return vrc;
}
/**
@@ -971,11 +1566,7 @@ static int ctrlCopyContextCreate(IGuest *pGuest, bool fVerbose, bool fDryRun,
static void ctrlCopyContextFree(PCOPYCONTEXT pContext)
{
if (pContext)
- {
- if (pContext->pGuestSession)
- pContext->pGuestSession->Close();
delete pContext;
- }
}
/**
@@ -1129,7 +1720,7 @@ static int ctrlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)
if ( RT_SUCCESS(vrc)
&& fDirExists)
{
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
RTPrintf("Directory \"%s\" already exists\n", pszDir);
return VINF_SUCCESS;
}
@@ -1139,7 +1730,7 @@ static int ctrlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)
if (RT_FAILURE(vrc))
return vrc;
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
RTPrintf("Creating directory \"%s\" ...\n", pszDir);
if (pContext->fDryRun)
@@ -1149,10 +1740,10 @@ static int ctrlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)
{
SafeArray<DirectoryCreateFlag_T> dirCreateFlags;
dirCreateFlags.push_back(DirectoryCreateFlag_Parents);
- HRESULT rc = pContext->pGuestSession->DirectoryCreate(Bstr(pszDir).raw(),
- 0700, ComSafeArrayAsInParam(dirCreateFlags));
+ HRESULT rc = pContext->pCmdCtx->pGuestSession->DirectoryCreate(Bstr(pszDir).raw(),
+ 0700, ComSafeArrayAsInParam(dirCreateFlags));
if (FAILED(rc))
- vrc = ctrlPrintError(pContext->pGuestSession, COM_IIDOF(IGuestSession));
+ vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
}
else /* ... or on the host. */
{
@@ -1168,13 +1759,13 @@ static int ctrlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)
*
* @return IPRT status code.
* @param pContext Pointer to current copy control context.
- * @param bGuest true if directory needs to be checked on the guest
+ * @param fOnGuest true if directory needs to be checked on the guest
* or false if on the host.
* @param pszDir Actual directory to check.
* @param fExists Pointer which receives the result if the
* given directory exists or not.
*/
-static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest,
+static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool fOnGuest,
const char *pszDir, bool *fExists)
{
AssertPtrReturn(pContext, false);
@@ -1182,12 +1773,12 @@ static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest,
AssertPtrReturn(fExists, false);
int vrc = VINF_SUCCESS;
- if (bGuest)
+ if (fOnGuest)
{
BOOL fDirExists = FALSE;
- HRESULT rc = pContext->pGuestSession->DirectoryExists(Bstr(pszDir).raw(), &fDirExists);
+ HRESULT rc = pContext->pCmdCtx->pGuestSession->DirectoryExists(Bstr(pszDir).raw(), &fDirExists);
if (FAILED(rc))
- vrc = ctrlPrintError(pContext->pGuestSession, COM_IIDOF(IGuestSession));
+ vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
else
*fExists = fDirExists ? true : false;
}
@@ -1252,9 +1843,9 @@ static int ctrlCopyFileExists(PCOPYCONTEXT pContext, bool bOnGuest,
if (bOnGuest)
{
BOOL fFileExists = FALSE;
- HRESULT rc = pContext->pGuestSession->FileExists(Bstr(pszFile).raw(), &fFileExists);
+ HRESULT rc = pContext->pCmdCtx->pGuestSession->FileExists(Bstr(pszFile).raw(), &fFileExists);
if (FAILED(rc))
- vrc = ctrlPrintError(pContext->pGuestSession, COM_IIDOF(IGuestSession));
+ vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
else
*fExists = fFileExists ? true : false;
}
@@ -1315,7 +1906,7 @@ static int ctrlCopyFileToDest(PCOPYCONTEXT pContext, const char *pszFileSource,
AssertPtrReturn(pszFileDest, VERR_INVALID_POINTER);
AssertReturn(!fFlags, VERR_INVALID_POINTER); /* No flags supported yet. */
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
RTPrintf("Copying \"%s\" to \"%s\" ...\n",
pszFileSource, pszFileDest);
@@ -1328,26 +1919,25 @@ static int ctrlCopyFileToDest(PCOPYCONTEXT pContext, const char *pszFileSource,
if (pContext->fHostToGuest)
{
SafeArray<CopyFileFlag_T> copyFlags;
- rc = pContext->pGuestSession->CopyTo(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(),
- ComSafeArrayAsInParam(copyFlags),
-
- pProgress.asOutParam());
+ rc = pContext->pCmdCtx->pGuestSession->CopyTo(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(),
+ ComSafeArrayAsInParam(copyFlags),
+ pProgress.asOutParam());
}
else
{
SafeArray<CopyFileFlag_T> copyFlags;
- rc = pContext->pGuestSession->CopyFrom(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(),
+ rc = pContext->pCmdCtx->pGuestSession->CopyFrom(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(),
ComSafeArrayAsInParam(copyFlags),
pProgress.asOutParam());
}
if (FAILED(rc))
{
- vrc = ctrlPrintError(pContext->pGuestSession, COM_IIDOF(IGuestSession));
+ vrc = ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
}
else
{
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
rc = showProgress(pProgress);
else
rc = pProgress->WaitForCompletion(-1 /* No timeout */);
@@ -1390,7 +1980,7 @@ static int ctrlCopyDirToGuest(PCOPYCONTEXT pContext,
if (RT_SUCCESS(vrc) && pszSubDir)
vrc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir);
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
RTPrintf("Processing host directory: %s\n", szCurDir);
/* Flag indicating whether the current directory was created on the
@@ -1423,6 +2013,9 @@ static int ctrlCopyDirToGuest(PCOPYCONTEXT pContext,
vrc = VINF_SUCCESS;
break;
}
+ /** @todo r=bird: This ain't gonna work on most UNIX file systems because
+ * enmType is RTDIRENTRYTYPE_UNKNOWN. This is clearly documented in
+ * RTDIRENTRY::enmType. For trunk, RTDirQueryUnknownType can be used. */
switch (DirEntry.enmType)
{
case RTDIRENTRYTYPE_DIRECTORY:
@@ -1432,7 +2025,7 @@ static int ctrlCopyDirToGuest(PCOPYCONTEXT pContext,
|| !strcmp(DirEntry.szName, ".."))
break;
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
RTPrintf("Directory: %s\n", DirEntry.szName);
if (fFlags & CopyFileFlag_Recursive)
@@ -1476,7 +2069,7 @@ static int ctrlCopyDirToGuest(PCOPYCONTEXT pContext,
break; /* Filter does not match. */
}
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
RTPrintf("File: %s\n", DirEntry.szName);
if (!fDirCreated)
@@ -1559,7 +2152,7 @@ static int ctrlCopyDirToHost(PCOPYCONTEXT pContext,
if (RT_FAILURE(vrc))
return vrc;
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
RTPrintf("Processing guest directory: %s\n", szCurDir);
/* Flag indicating whether the current directory was created on the
@@ -1567,11 +2160,11 @@ static int ctrlCopyDirToHost(PCOPYCONTEXT pContext,
bool fDirCreated = false;
SafeArray<DirectoryOpenFlag_T> dirOpenFlags; /* No flags supported yet. */
ComPtr<IGuestDirectory> pDirectory;
- HRESULT rc = pContext->pGuestSession->DirectoryOpen(Bstr(szCurDir).raw(), Bstr(pszFilter).raw(),
+ HRESULT rc = pContext->pCmdCtx->pGuestSession->DirectoryOpen(Bstr(szCurDir).raw(), Bstr(pszFilter).raw(),
ComSafeArrayAsInParam(dirOpenFlags),
pDirectory.asOutParam());
if (FAILED(rc))
- return ctrlPrintError(pContext->pGuestSession, COM_IIDOF(IGuestSession));
+ return ctrlPrintError(pContext->pCmdCtx->pGuestSession, COM_IIDOF(IGuestSession));
ComPtr<IFsObjInfo> dirEntry;
while (true)
{
@@ -1596,7 +2189,7 @@ static int ctrlCopyDirToHost(PCOPYCONTEXT pContext,
|| !strName.compare(Bstr("..")))
break;
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
{
Utf8Str strDir(strName);
RTPrintf("Directory: %s\n", strDir.c_str());
@@ -1646,7 +2239,7 @@ static int ctrlCopyDirToHost(PCOPYCONTEXT pContext,
break; /* Filter does not match. */
}
- if (pContext->fVerbose)
+ if (pContext->pCmdCtx->fVerbose)
RTPrintf("File: %s\n", strFile.c_str());
if (!fDirCreated)
@@ -1803,10 +2396,9 @@ static void ctrlCopyFreeSourceRoot(char *pszSourceRoot)
RTStrFree(pszSourceRoot);
}
-static int handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg,
- bool fHostToGuest)
+static RTEXITCODE handleCtrlCopy(PGCTLCMDCTX pCtx, bool fHostToGuest)
{
- AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
/** @todo r=bird: This command isn't very unix friendly in general. mkdir
* is much better (partly because it is much simpler of course). The main
@@ -1826,30 +2418,22 @@ static int handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg,
{
{ "--dryrun", GETOPTDEF_COPY_DRYRUN, RTGETOPT_REQ_NOTHING },
{ "--follow", GETOPTDEF_COPY_FOLLOW, RTGETOPT_REQ_NOTHING },
- { "--username", 'u', RTGETOPT_REQ_STRING },
- { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
- { "--password", GETOPTDEF_COPY_PASSWORD, RTGETOPT_REQ_STRING },
- { "--domain", 'd', RTGETOPT_REQ_STRING },
{ "--recursive", 'R', RTGETOPT_REQ_NOTHING },
- { "--target-directory", GETOPTDEF_COPY_TARGETDIR, RTGETOPT_REQ_STRING },
- { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+ { "--target-directory", GETOPTDEF_COPY_TARGETDIR, RTGETOPT_REQ_STRING }
};
int ch;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
- RTGetOptInit(&GetState, pArg->argc, pArg->argv,
- s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
Utf8Str strSource;
Utf8Str strDest;
- Utf8Str strUsername;
- Utf8Str strPassword;
- Utf8Str strDomain;
uint32_t fFlags = CopyFileFlag_None;
- bool fVerbose = false;
bool fCopyRecursive = false;
bool fDryRun = false;
+ uint32_t uUsage = fHostToGuest ? USAGE_GSTCTRL_COPYTO : USAGE_GSTCTRL_COPYFROM;
SOURCEVEC vecSources;
@@ -1867,26 +2451,6 @@ static int handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg,
fFlags |= CopyFileFlag_FollowLinks;
break;
- case 'u': /* User name */
- strUsername = ValueUnion.psz;
- break;
-
- case GETOPTDEF_COPY_PASSWORD: /* Password */
- strPassword = ValueUnion.psz;
- break;
-
- case 'p': /* Password file */
- {
- RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);
- if (rcExit != RTEXITCODE_SUCCESS)
- return rcExit;
- break;
- }
-
- case 'd': /* domain */
- strDomain = ValueUnion.psz;
- break;
-
case 'R': /* Recursive processing */
fFlags |= CopyFileFlag_Recursive;
break;
@@ -1895,16 +2459,12 @@ static int handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg,
strDest = ValueUnion.psz;
break;
- case 'v': /* Verbose */
- fVerbose = true;
- break;
-
case VINF_GETOPT_NOT_OPTION:
{
/* Last argument and no destination specified with
* --target-directory yet? Then use the current
* (= last) argument as destination. */
- if ( pArg->argc == GetState.iNext
+ if ( pCtx->iArgc == GetState.iNext
&& strDest.isEmpty())
{
strDest = ValueUnion.psz;
@@ -1918,26 +2478,22 @@ static int handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg,
}
default:
- return RTGetOptPrintError(ch, &ValueUnion);
+ return errorGetOptEx(USAGE_GUESTCONTROL, uUsage, ch, &ValueUnion);
}
}
if (!vecSources.size())
- return errorSyntax(USAGE_GUESTCONTROL,
- "No source(s) specified!");
+ return errorSyntaxEx(USAGE_GUESTCONTROL, uUsage,
+ "No source(s) specified!");
if (strDest.isEmpty())
- return errorSyntax(USAGE_GUESTCONTROL,
- "No destination specified!");
-
- if (strUsername.isEmpty())
- return errorSyntax(USAGE_GUESTCONTROL,
- "No user name specified!");
+ return errorSyntaxEx(USAGE_GUESTCONTROL, uUsage,
+ "No destination specified!");
/*
* Done parsing arguments, do some more preparations.
*/
- if (fVerbose)
+ if (pCtx->fVerbose)
{
if (fHostToGuest)
RTPrintf("Copying from host to guest ...\n");
@@ -1950,9 +2506,10 @@ static int handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg,
/* Create the copy context -- it contains all information
* the routines need to know when handling the actual copying. */
PCOPYCONTEXT pContext = NULL;
- vrc = ctrlCopyContextCreate(guest, fVerbose, fDryRun, fHostToGuest,
- strUsername, strPassword, strDomain,
- "VBoxManage Guest Control Copy", &pContext);
+ vrc = ctrlCopyContextCreate(pCtx, fDryRun, fHostToGuest,
+ fHostToGuest
+ ? "VBoxManage Guest Control - Copy to guest"
+ : "VBoxManage Guest Control - Copy from guest", &pContext);
if (RT_FAILURE(vrc))
{
RTMsgError("Unable to create copy context, rc=%Rrc\n", vrc);
@@ -2010,7 +2567,7 @@ static int handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg,
break;
}
- if (fVerbose)
+ if (pCtx->fVerbose)
RTPrintf("Source: %s\n", pszSource);
/** @todo Files with filter?? */
@@ -2097,40 +2654,34 @@ static int handleCtrlCopy(ComPtr<IGuest> guest, HandlerArg *pArg,
return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
-static int handleCtrlCreateDirectory(ComPtr<IGuest> pGuest, HandlerArg *pArg)
+static DECLCALLBACK(RTEXITCODE) handleCtrlCopyFrom(PGCTLCMDCTX pCtx)
{
- AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
+ return handleCtrlCopy(pCtx, false /* Guest to host */);
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlCopyTo(PGCTLCMDCTX pCtx)
+{
+ return handleCtrlCopy(pCtx, true /* Host to guest */);
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlCreateDirectory(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
- /*
- * Parse arguments.
- *
- * Note! No direct returns here, everyone must go thru the cleanup at the
- * end of this function.
- */
static const RTGETOPTDEF s_aOptions[] =
{
{ "--mode", 'm', RTGETOPT_REQ_UINT32 },
- { "--parents", 'P', RTGETOPT_REQ_NOTHING },
- { "--username", 'u', RTGETOPT_REQ_STRING },
- { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
- { "--password", GETOPTDEF_MKDIR_PASSWORD, RTGETOPT_REQ_STRING },
- { "--domain", 'd', RTGETOPT_REQ_STRING },
- { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+ { "--parents", 'P', RTGETOPT_REQ_NOTHING }
};
int ch;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
- RTGetOptInit(&GetState, pArg->argc, pArg->argv,
- s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
- Utf8Str strUsername;
- Utf8Str strPassword;
- Utf8Str strDomain;
SafeArray<DirectoryCreateFlag_T> dirCreateFlags;
uint32_t fDirMode = 0; /* Default mode. */
- bool fVerbose = false;
-
DESTDIRMAP mapDirs;
while ((ch = RTGetOpt(&GetState, &ValueUnion)))
@@ -2146,124 +2697,353 @@ static int handleCtrlCreateDirectory(ComPtr<IGuest> pGuest, HandlerArg *pArg)
dirCreateFlags.push_back(DirectoryCreateFlag_Parents);
break;
- case 'u': /* User name */
- strUsername = ValueUnion.psz;
+ case VINF_GETOPT_NOT_OPTION:
+ mapDirs[ValueUnion.psz]; /* Add destination directory to map. */
break;
- case GETOPTDEF_MKDIR_PASSWORD: /* Password */
- strPassword = ValueUnion.psz;
- break;
+ default:
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATEDIR, ch, &ValueUnion);
+ }
+ }
- case 'p': /* Password file */
- {
- RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);
- if (rcExit != RTEXITCODE_SUCCESS)
- return rcExit;
- break;
- }
+ uint32_t cDirs = mapDirs.size();
+ if (!cDirs)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATEDIR,
+ "No directory to create specified!");
- case 'd': /* domain */
- strDomain = ValueUnion.psz;
- break;
+ /*
+ * Create the directories.
+ */
+ HRESULT rc = S_OK;
+ if (pCtx->fVerbose && cDirs)
+ RTPrintf("Creating %RU32 directories ...\n", cDirs);
+
+ DESTDIRMAPITER it = mapDirs.begin();
+ while ( (it != mapDirs.end())
+ && !g_fGuestCtrlCanceled)
+ {
+ if (pCtx->fVerbose)
+ RTPrintf("Creating directory \"%s\" ...\n", it->first.c_str());
+
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, DirectoryCreate(Bstr(it->first).raw(),
+ fDirMode, ComSafeArrayAsInParam(dirCreateFlags)));
+ it++;
+ }
+
+ return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlRemoveDirectory(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ { "--recursive", 'R', RTGETOPT_REQ_NOTHING }
+ };
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+ bool fRecursive = false;
+ DESTDIRMAP mapDirs;
- case 'v': /* Verbose */
- fVerbose = true;
+ while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
+ {
+ case 'R':
+ fRecursive = true;
break;
case VINF_GETOPT_NOT_OPTION:
- {
mapDirs[ValueUnion.psz]; /* Add destination directory to map. */
break;
- }
default:
- return RTGetOptPrintError(ch, &ValueUnion);
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEDIR, ch, &ValueUnion);
}
}
uint32_t cDirs = mapDirs.size();
if (!cDirs)
- return errorSyntax(USAGE_GUESTCONTROL, "No directory to create specified!");
-
- if (strUsername.isEmpty())
- return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEDIR,
+ "No directory to remove specified!");
/*
- * Create the directories.
+ * Remove the directories.
*/
- HRESULT hrc = S_OK;
- if (fVerbose && cDirs)
- RTPrintf("Creating %u directories ...\n", cDirs);
-
- ComPtr<IGuestSession> pGuestSession;
- hrc = pGuest->CreateSession(Bstr(strUsername).raw(),
- Bstr(strPassword).raw(),
- Bstr(strDomain).raw(),
- Bstr("VBoxManage Guest Control MkDir").raw(),
- pGuestSession.asOutParam());
- if (FAILED(hrc))
- return ctrlPrintError(pGuest, COM_IIDOF(IGuest));
+ HRESULT rc = S_OK;
+ if (pCtx->fVerbose && cDirs)
+ RTPrintf("Removing %RU32 directories ...\n", cDirs);
DESTDIRMAPITER it = mapDirs.begin();
- while (it != mapDirs.end())
+ while ( (it != mapDirs.end())
+ && !g_fGuestCtrlCanceled)
{
- if (fVerbose)
- RTPrintf("Creating directory \"%s\" ...\n", it->first.c_str());
+ if (pCtx->fVerbose)
+ RTPrintf("%s directory \"%s\" ...\n",
+ fRecursive ? "Recursively removing" : "Removing",
+ it->first.c_str());
+ try
+ {
+ if (fRecursive)
+ {
+ com::SafeArray<DirectoryRemoveRecFlag_T> aRemRecFlags;
+ /** @todo Make flags configurable. */
+ aRemRecFlags.push_back(DirectoryRemoveRecFlag_ContentAndDir);
+
+ ComPtr<IProgress> pProgress;
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, DirectoryRemoveRecursive(Bstr(it->first).raw(),
+ ComSafeArrayAsInParam(aRemRecFlags),
+ pProgress.asOutParam()));
+ if (pCtx->fVerbose)
+ rc = showProgress(pProgress);
+ else
+ rc = pProgress->WaitForCompletion(-1 /* No timeout */);
+ if (SUCCEEDED(rc))
+ CHECK_PROGRESS_ERROR(pProgress, ("Directory deletion failed"));
- hrc = pGuestSession->DirectoryCreate(Bstr(it->first).raw(), fDirMode, ComSafeArrayAsInParam(dirCreateFlags));
- if (FAILED(hrc))
+ pProgress.setNull();
+ }
+ else
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, DirectoryRemove(Bstr(it->first).raw()));
+ }
+ catch (std::bad_alloc)
{
- ctrlPrintError(pGuest, COM_IIDOF(IGuestSession)); /* Return code ignored, save original rc. */
+ rc = E_OUTOFMEMORY;
break;
}
it++;
}
- if (!pGuestSession.isNull())
- pGuestSession->Close();
+ return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlRemoveFile(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ NULL /* s_aOptions */, 0 /* RT_ELEMENTS(s_aOptions) */,
+ pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+ DESTDIRMAP mapDirs;
+
+ while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
+ {
+ case VINF_GETOPT_NOT_OPTION:
+ mapDirs[ValueUnion.psz]; /* Add destination directory to map. */
+ break;
+
+ default:
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEFILE, ch, &ValueUnion);
+ }
+ }
+
+ uint32_t cFiles = mapDirs.size();
+ if (!cFiles)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_REMOVEFILE,
+ "No file to remove specified!");
+
+ /*
+ * Create the directories.
+ */
+ HRESULT rc = S_OK;
+ if (pCtx->fVerbose && cFiles)
+ RTPrintf("Removing %RU32 file(s) ...\n", cFiles);
+
+ DESTDIRMAPITER it = mapDirs.begin();
+ while ( (it != mapDirs.end())
+ && !g_fGuestCtrlCanceled)
+ {
+ if (pCtx->fVerbose)
+ RTPrintf("Removing file \"%s\" ...\n", it->first.c_str());
- return FAILED(hrc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, FileRemove(Bstr(it->first).raw()));
+
+ it++;
+ }
+
+ return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
}
-static int handleCtrlCreateTemp(ComPtr<IGuest> pGuest, HandlerArg *pArg)
+static DECLCALLBACK(RTEXITCODE) handleCtrlRename(PGCTLCMDCTX pCtx)
{
- AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ static const RTGETOPTDEF s_aOptions[] = { 0 };
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ NULL /*s_aOptions*/, 0 /*RT_ELEMENTS(s_aOptions)*/, pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+ int vrc = VINF_SUCCESS;
+
+ bool fDryrun = false;
+ std::vector< Utf8Str > vecSources;
+ Utf8Str strDest;
+ com::SafeArray<PathRenameFlag_T> aRenameFlags;
+
+ try
+ {
+ /** @todo Make flags configurable. */
+ aRenameFlags.push_back(PathRenameFlag_NoReplace);
+
+ while ( (ch = RTGetOpt(&GetState, &ValueUnion))
+ && RT_SUCCESS(vrc))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
+ {
+ /** @todo Implement a --dryrun command. */
+ /** @todo Implement rename flags. */
+
+ case VINF_GETOPT_NOT_OPTION:
+ vecSources.push_back(Utf8Str(ValueUnion.psz));
+ strDest = ValueUnion.psz;
+ break;
+
+ default:
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME, ch, &ValueUnion);
+ }
+ }
+ }
+ catch (std::bad_alloc)
+ {
+ vrc = VERR_NO_MEMORY;
+ }
+
+ if (RT_FAILURE(vrc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize, rc=%Rrc\n", vrc);
+
+ uint32_t cSources = vecSources.size();
+ if (!cSources)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME,
+ "No source(s) to move specified!");
+ if (cSources < 2)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_RENAME,
+ "No destination specified!");
+
+ /* Delete last element, which now is the destination. */
+ vecSources.pop_back();
+ cSources = vecSources.size();
+
+ HRESULT rc = S_OK;
+
+ if (cSources > 1)
+ {
+ ComPtr<IGuestFsObjInfo> pFsObjInfo;
+ rc = pCtx->pGuestSession->DirectoryQueryInfo(Bstr(strDest).raw(), pFsObjInfo.asOutParam());
+ if (FAILED(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "Destination must be a directory when specifying multiple sources\n");
+ }
/*
- * Parse arguments.
- *
- * Note! No direct returns here, everyone must go thru the cleanup at the
- * end of this function.
+ * Rename (move) the entries.
*/
+ if (pCtx->fVerbose && cSources)
+ RTPrintf("Renaming %RU32 %s ...\n", cSources,
+ cSources > 1
+ ? "entries" : "entry");
+
+ std::vector< Utf8Str >::iterator it = vecSources.begin();
+ while ( (it != vecSources.end())
+ && !g_fGuestCtrlCanceled)
+ {
+ bool fSourceIsDirectory = false;
+ Utf8Str strCurSource = (*it);
+ Utf8Str strCurDest = strDest;
+
+ /** @todo Slooooow, but works for now. */
+ ComPtr<IGuestFsObjInfo> pFsObjInfo;
+ rc = pCtx->pGuestSession->FileQueryInfo(Bstr(strCurSource).raw(), pFsObjInfo.asOutParam());
+ if (FAILED(rc))
+ {
+ rc = pCtx->pGuestSession->DirectoryQueryInfo(Bstr(strCurSource).raw(), pFsObjInfo.asOutParam());
+ fSourceIsDirectory = SUCCEEDED(rc);
+ }
+ if (FAILED(rc))
+ {
+ if (pCtx->fVerbose)
+ RTPrintf("Warning: Cannot stat for element \"%s\": No such element\n",
+ strCurSource.c_str());
+ it++;
+ continue; /* Skip. */
+ }
+
+ if (pCtx->fVerbose)
+ RTPrintf("Renaming %s \"%s\" to \"%s\" ...\n",
+ fSourceIsDirectory ? "directory" : "file",
+ strCurSource.c_str(), strCurDest.c_str());
+
+ if (!fDryrun)
+ {
+ if (fSourceIsDirectory)
+ {
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, DirectoryRename(Bstr(strCurSource).raw(),
+ Bstr(strCurDest).raw(),
+ ComSafeArrayAsInParam(aRenameFlags)));
+
+ /* Break here, since it makes no sense to rename mroe than one source to
+ * the same directory. */
+ it = vecSources.end();
+ break;
+ }
+ else
+ CHECK_ERROR_BREAK(pCtx->pGuestSession, FileRename(Bstr(strCurSource).raw(),
+ Bstr(strCurDest).raw(),
+ ComSafeArrayAsInParam(aRenameFlags)));
+ }
+
+ it++;
+ }
+
+ if ( (it != vecSources.end())
+ && pCtx->fVerbose)
+ {
+ RTPrintf("Warning: Not all sources were renamed\n");
+ }
+
+ return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlCreateTemp(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
static const RTGETOPTDEF s_aOptions[] =
{
{ "--mode", 'm', RTGETOPT_REQ_UINT32 },
{ "--directory", 'D', RTGETOPT_REQ_NOTHING },
{ "--secure", 's', RTGETOPT_REQ_NOTHING },
- { "--tmpdir", 't', RTGETOPT_REQ_STRING },
- { "--username", 'u', RTGETOPT_REQ_STRING },
- { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
- { "--password", GETOPTDEF_MKDIR_PASSWORD, RTGETOPT_REQ_STRING },
- { "--domain", 'd', RTGETOPT_REQ_STRING },
- { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+ { "--tmpdir", 't', RTGETOPT_REQ_STRING }
};
int ch;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
- RTGetOptInit(&GetState, pArg->argc, pArg->argv,
- s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
- Utf8Str strUsername;
- Utf8Str strPassword;
- Utf8Str strDomain;
Utf8Str strTemplate;
uint32_t fMode = 0; /* Default mode. */
bool fDirectory = false;
bool fSecure = false;
Utf8Str strTempDir;
- bool fVerbose = false;
DESTDIRMAP mapDirs;
@@ -2288,59 +3068,33 @@ static int handleCtrlCreateTemp(ComPtr<IGuest> pGuest, HandlerArg *pArg)
strTempDir = ValueUnion.psz;
break;
- case 'u': /* User name */
- strUsername = ValueUnion.psz;
- break;
-
- case GETOPTDEF_MKDIR_PASSWORD: /* Password */
- strPassword = ValueUnion.psz;
- break;
-
- case 'p': /* Password file */
- {
- RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);
- if (rcExit != RTEXITCODE_SUCCESS)
- return rcExit;
- break;
- }
-
- case 'd': /* domain */
- strDomain = ValueUnion.psz;
- break;
-
- case 'v': /* Verbose */
- fVerbose = true;
- break;
-
case VINF_GETOPT_NOT_OPTION:
{
if (strTemplate.isEmpty())
strTemplate = ValueUnion.psz;
else
- return errorSyntax(USAGE_GUESTCONTROL,
- "More than one template specified!\n");
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATETEMP,
+ "More than one template specified!\n");
break;
}
default:
- return RTGetOptPrintError(ch, &ValueUnion);
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATETEMP, ch, &ValueUnion);
}
}
if (strTemplate.isEmpty())
- return errorSyntax(USAGE_GUESTCONTROL, "No template specified!");
-
- if (strUsername.isEmpty())
- return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATETEMP,
+ "No template specified!");
if (!fDirectory)
- return errorSyntax(USAGE_GUESTCONTROL, "Creating temporary files is currently not supported!");
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_CREATETEMP,
+ "Creating temporary files is currently not supported!");
/*
* Create the directories.
*/
- HRESULT hrc = S_OK;
- if (fVerbose)
+ if (pCtx->fVerbose)
{
if (fDirectory && !strTempDir.isEmpty())
RTPrintf("Creating temporary directory from template '%s' in directory '%s' ...\n",
@@ -2356,63 +3110,40 @@ static int handleCtrlCreateTemp(ComPtr<IGuest> pGuest, HandlerArg *pArg)
strTemplate.c_str());
}
- ComPtr<IGuestSession> pGuestSession;
- hrc = pGuest->CreateSession(Bstr(strUsername).raw(),
- Bstr(strPassword).raw(),
- Bstr(strDomain).raw(),
- Bstr("VBoxManage Guest Control MkTemp").raw(),
- pGuestSession.asOutParam());
- if (FAILED(hrc))
- return ctrlPrintError(pGuest, COM_IIDOF(IGuest));
-
+ HRESULT rc = S_OK;
if (fDirectory)
{
Bstr directory;
- hrc = pGuestSession->DirectoryCreateTemp(Bstr(strTemplate).raw(),
- fMode, Bstr(strTempDir).raw(),
- fSecure,
- directory.asOutParam());
- if (SUCCEEDED(hrc))
+ CHECK_ERROR(pCtx->pGuestSession, DirectoryCreateTemp(Bstr(strTemplate).raw(),
+ fMode, Bstr(strTempDir).raw(),
+ fSecure,
+ directory.asOutParam()));
+ if (SUCCEEDED(rc))
RTPrintf("Directory name: %ls\n", directory.raw());
}
// else - temporary file not yet implemented
- if (FAILED(hrc))
- ctrlPrintError(pGuest, COM_IIDOF(IGuestSession)); /* Return code ignored, save original rc. */
- if (!pGuestSession.isNull())
- pGuestSession->Close();
-
- return FAILED(hrc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
+ return FAILED(rc) ? RTEXITCODE_FAILURE : RTEXITCODE_SUCCESS;
}
-static int handleCtrlStat(ComPtr<IGuest> pGuest, HandlerArg *pArg)
+static DECLCALLBACK(RTEXITCODE) handleCtrlStat(PGCTLCMDCTX pCtx)
{
- AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
static const RTGETOPTDEF s_aOptions[] =
{
{ "--dereference", 'L', RTGETOPT_REQ_NOTHING },
{ "--file-system", 'f', RTGETOPT_REQ_NOTHING },
{ "--format", 'c', RTGETOPT_REQ_STRING },
- { "--username", 'u', RTGETOPT_REQ_STRING },
- { "--passwordfile", 'p', RTGETOPT_REQ_STRING },
- { "--password", GETOPTDEF_STAT_PASSWORD, RTGETOPT_REQ_STRING },
- { "--domain", 'd', RTGETOPT_REQ_STRING },
- { "--terse", 't', RTGETOPT_REQ_NOTHING },
- { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+ { "--terse", 't', RTGETOPT_REQ_NOTHING }
};
int ch;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
- RTGetOptInit(&GetState, pArg->argc, pArg->argv,
- s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
-
- Utf8Str strUsername;
- Utf8Str strPassword;
- Utf8Str strDomain;
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
- bool fVerbose = false;
DESTDIRMAP mapObjs;
while ((ch = RTGetOpt(&GetState, &ValueUnion)))
@@ -2420,85 +3151,49 @@ static int handleCtrlStat(ComPtr<IGuest> pGuest, HandlerArg *pArg)
/* For options that require an argument, ValueUnion has received the value. */
switch (ch)
{
- case 'u': /* User name */
- strUsername = ValueUnion.psz;
- break;
-
- case GETOPTDEF_STAT_PASSWORD: /* Password */
- strPassword = ValueUnion.psz;
- break;
-
- case 'p': /* Password file */
- {
- RTEXITCODE rcExit = readPasswordFile(ValueUnion.psz, &strPassword);
- if (rcExit != RTEXITCODE_SUCCESS)
- return rcExit;
- break;
- }
-
- case 'd': /* domain */
- strDomain = ValueUnion.psz;
- break;
-
case 'L': /* Dereference */
case 'f': /* File-system */
case 'c': /* Format */
case 't': /* Terse */
- return errorSyntax(USAGE_GUESTCONTROL, "Command \"%s\" not implemented yet!",
- ValueUnion.psz);
- break; /* Never reached. */
-
- case 'v': /* Verbose */
- fVerbose = true;
- break;
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_STAT,
+ "Command \"%s\" not implemented yet!", ValueUnion.psz);
case VINF_GETOPT_NOT_OPTION:
- {
mapObjs[ValueUnion.psz]; /* Add element to check to map. */
break;
- }
default:
- return RTGetOptPrintError(ch, &ValueUnion);
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_STAT, ch, &ValueUnion);
}
}
uint32_t cObjs = mapObjs.size();
if (!cObjs)
- return errorSyntax(USAGE_GUESTCONTROL, "No element(s) to check specified!");
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_STAT,
+ "No element(s) to check specified!");
- if (strUsername.isEmpty())
- return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");
-
- ComPtr<IGuestSession> pGuestSession;
- HRESULT hrc = pGuest->CreateSession(Bstr(strUsername).raw(),
- Bstr(strPassword).raw(),
- Bstr(strDomain).raw(),
- Bstr("VBoxManage Guest Control Stat").raw(),
- pGuestSession.asOutParam());
- if (FAILED(hrc))
- return ctrlPrintError(pGuest, COM_IIDOF(IGuest));
+ HRESULT rc;
/*
- * Create the directories.
+ * Doing the checks.
*/
RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
DESTDIRMAPITER it = mapObjs.begin();
while (it != mapObjs.end())
{
- if (fVerbose)
+ if (pCtx->fVerbose)
RTPrintf("Checking for element \"%s\" ...\n", it->first.c_str());
ComPtr<IGuestFsObjInfo> pFsObjInfo;
- hrc = pGuestSession->FileQueryInfo(Bstr(it->first).raw(), pFsObjInfo.asOutParam());
- if (FAILED(hrc))
- hrc = pGuestSession->DirectoryQueryInfo(Bstr(it->first).raw(), pFsObjInfo.asOutParam());
+ rc = pCtx->pGuestSession->FileQueryInfo(Bstr(it->first).raw(), pFsObjInfo.asOutParam());
+ if (FAILED(rc))
+ rc = pCtx->pGuestSession->DirectoryQueryInfo(Bstr(it->first).raw(), pFsObjInfo.asOutParam());
- if (FAILED(hrc))
+ if (FAILED(rc))
{
/* If there's at least one element which does not exist on the guest,
* drop out with exitcode 1. */
- if (fVerbose)
+ if (pCtx->fVerbose)
RTPrintf("Cannot stat for element \"%s\": No such element\n",
it->first.c_str());
rcExit = RTEXITCODE_FAILURE;
@@ -2506,9 +3201,7 @@ static int handleCtrlStat(ComPtr<IGuest> pGuest, HandlerArg *pArg)
else
{
FsObjType_T objType;
- hrc = pFsObjInfo->COMGETTER(Type)(&objType);
- if (FAILED(hrc))
- return ctrlPrintError(pGuest, COM_IIDOF(IGuestFsObjInfo));
+ pFsObjInfo->COMGETTER(Type)(&objType);
switch (objType)
{
case FsObjType_File:
@@ -2534,35 +3227,31 @@ static int handleCtrlStat(ComPtr<IGuest> pGuest, HandlerArg *pArg)
it++;
}
- if (!pGuestSession.isNull())
- pGuestSession->Close();
-
return rcExit;
}
-static int handleCtrlUpdateAdditions(ComPtr<IGuest> guest, HandlerArg *pArg)
+static DECLCALLBACK(RTEXITCODE) handleCtrlUpdateAdditions(PGCTLCMDCTX pCtx)
{
- AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
/*
* Check the syntax. We can deduce the correct syntax from the number of
* arguments.
*/
Utf8Str strSource;
- bool fVerbose = false;
+ com::SafeArray<IN_BSTR> aArgs;
bool fWaitStartOnly = false;
static const RTGETOPTDEF s_aOptions[] =
{
{ "--source", 's', RTGETOPT_REQ_STRING },
- { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
{ "--wait-start", 'w', RTGETOPT_REQ_NOTHING }
};
int ch;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetState;
- RTGetOptInit(&GetState, pArg->argc, pArg->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv, s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, 0);
int vrc = VINF_SUCCESS;
while ( (ch = RTGetOpt(&GetState, &ValueUnion))
@@ -2574,27 +3263,30 @@ static int handleCtrlUpdateAdditions(ComPtr<IGuest> guest, HandlerArg *pArg)
strSource = ValueUnion.psz;
break;
- case 'v':
- fVerbose = true;
- break;
-
case 'w':
fWaitStartOnly = true;
break;
+ case VINF_GETOPT_NOT_OPTION:
+ if (aArgs.size() == 0 && strSource.isEmpty())
+ strSource = ValueUnion.psz;
+ else
+ aArgs.push_back(Bstr(ValueUnion.psz).raw());
+ break;
+
default:
- return RTGetOptPrintError(ch, &ValueUnion);
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_UPDATEADDS, ch, &ValueUnion);
}
}
- if (fVerbose)
+ if (pCtx->fVerbose)
RTPrintf("Updating Guest Additions ...\n");
HRESULT rc = S_OK;
while (strSource.isEmpty())
{
ComPtr<ISystemProperties> pProperties;
- CHECK_ERROR_BREAK(pArg->virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam()));
+ CHECK_ERROR_BREAK(pCtx->handlerArg.virtualBox, COMGETTER(SystemProperties)(pProperties.asOutParam()));
Bstr strISO;
CHECK_ERROR_BREAK(pProperties, COMGETTER(DefaultAdditionsISO)(strISO.asOutParam()));
strSource = strISO;
@@ -2615,27 +3307,28 @@ static int handleCtrlUpdateAdditions(ComPtr<IGuest> guest, HandlerArg *pArg)
if (RT_SUCCESS(vrc))
{
- if (fVerbose)
+ if (pCtx->fVerbose)
RTPrintf("Using source: %s\n", strSource.c_str());
com::SafeArray<AdditionsUpdateFlag_T> aUpdateFlags;
if (fWaitStartOnly)
{
aUpdateFlags.push_back(AdditionsUpdateFlag_WaitForUpdateStartOnly);
- if (fVerbose)
+ if (pCtx->fVerbose)
RTPrintf("Preparing and waiting for Guest Additions installer to start ...\n");
}
ComPtr<IProgress> pProgress;
- CHECK_ERROR(guest, UpdateGuestAdditions(Bstr(strSource).raw(),
+ CHECK_ERROR(pCtx->pGuest, UpdateGuestAdditions(Bstr(strSource).raw(),
+ ComSafeArrayAsInParam(aArgs),
/* Wait for whole update process to complete. */
ComSafeArrayAsInParam(aUpdateFlags),
pProgress.asOutParam()));
if (FAILED(rc))
- vrc = ctrlPrintError(guest, COM_IIDOF(IGuest));
+ vrc = ctrlPrintError(pCtx->pGuest, COM_IIDOF(IGuest));
else
{
- if (fVerbose)
+ if (pCtx->fVerbose)
rc = showProgress(pProgress);
else
rc = pProgress->WaitForCompletion(-1 /* No timeout */);
@@ -2644,7 +3337,7 @@ static int handleCtrlUpdateAdditions(ComPtr<IGuest> guest, HandlerArg *pArg)
CHECK_PROGRESS_ERROR(pProgress, ("Guest additions update failed"));
vrc = ctrlPrintProgressError(pProgress);
if ( RT_SUCCESS(vrc)
- && fVerbose)
+ && pCtx->fVerbose)
{
RTPrintf("Guest Additions update successful\n");
}
@@ -2654,6 +3347,569 @@ static int handleCtrlUpdateAdditions(ComPtr<IGuest> guest, HandlerArg *pArg)
return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
+static DECLCALLBACK(RTEXITCODE) handleCtrlList(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ if (pCtx->iArgc < 1)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST,
+ "Must specify a listing category");
+
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+
+ /** Use RTGetOpt here when handling command line args gets more complex. */
+
+ bool fListAll = false;
+ bool fListSessions = false;
+ bool fListProcesses = false;
+ bool fListFiles = false;
+ if ( !RTStrICmp(pCtx->ppaArgv[0], "sessions")
+ || !RTStrICmp(pCtx->ppaArgv[0], "sess"))
+ fListSessions = true;
+ else if ( !RTStrICmp(pCtx->ppaArgv[0], "processes")
+ || !RTStrICmp(pCtx->ppaArgv[0], "procs"))
+ fListSessions = fListProcesses = true; /* Showing processes implies showing sessions. */
+ else if ( !RTStrICmp(pCtx->ppaArgv[0], "files"))
+ fListSessions = fListFiles = true; /* Showing files implies showing sessions. */
+ else if (!RTStrICmp(pCtx->ppaArgv[0], "all"))
+ fListAll = true;
+
+ /** @todo Handle "--verbose" using RTGetOpt. */
+ /** @todo Do we need a machine-readable output here as well? */
+
+ if ( fListAll
+ || fListSessions)
+ {
+ HRESULT rc;
+ do
+ {
+ size_t cTotalProcs = 0;
+ size_t cTotalFiles = 0;
+
+ SafeIfaceArray <IGuestSession> collSessions;
+ CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));
+ size_t cSessions = collSessions.size();
+
+ if (cSessions)
+ {
+ RTPrintf("Active guest sessions:\n");
+
+ /** @todo Make this output a bit prettier. No time now. */
+
+ for (size_t i = 0; i < cSessions; i++)
+ {
+ ComPtr<IGuestSession> pCurSession = collSessions[i];
+ if (!pCurSession.isNull())
+ {
+ ULONG uID;
+ CHECK_ERROR_BREAK(pCurSession, COMGETTER(Id)(&uID));
+ Bstr strName;
+ CHECK_ERROR_BREAK(pCurSession, COMGETTER(Name)(strName.asOutParam()));
+ Bstr strUser;
+ CHECK_ERROR_BREAK(pCurSession, COMGETTER(User)(strUser.asOutParam()));
+ GuestSessionStatus_T sessionStatus;
+ CHECK_ERROR_BREAK(pCurSession, COMGETTER(Status)(&sessionStatus));
+ RTPrintf("\n\tSession #%-3zu ID=%-3RU32 User=%-16ls Status=[%s] Name=%ls",
+ i, uID, strUser.raw(), ctrlSessionStatusToText(sessionStatus), strName.raw());
+
+ if ( fListAll
+ || fListProcesses)
+ {
+ SafeIfaceArray <IGuestProcess> collProcesses;
+ CHECK_ERROR_BREAK(pCurSession, COMGETTER(Processes)(ComSafeArrayAsOutParam(collProcesses)));
+ for (size_t a = 0; a < collProcesses.size(); a++)
+ {
+ ComPtr<IGuestProcess> pCurProcess = collProcesses[a];
+ if (!pCurProcess.isNull())
+ {
+ ULONG uPID;
+ CHECK_ERROR_BREAK(pCurProcess, COMGETTER(PID)(&uPID));
+ Bstr strExecPath;
+ CHECK_ERROR_BREAK(pCurProcess, COMGETTER(ExecutablePath)(strExecPath.asOutParam()));
+ ProcessStatus_T procStatus;
+ CHECK_ERROR_BREAK(pCurProcess, COMGETTER(Status)(&procStatus));
+
+ RTPrintf("\n\t\tProcess #%-03zu PID=%-6RU32 Status=[%s] Command=%ls",
+ a, uPID, ctrlProcessStatusToText(procStatus), strExecPath.raw());
+ }
+ }
+
+ cTotalProcs += collProcesses.size();
+ }
+
+ if ( fListAll
+ || fListFiles)
+ {
+ SafeIfaceArray <IGuestFile> collFiles;
+ CHECK_ERROR_BREAK(pCurSession, COMGETTER(Files)(ComSafeArrayAsOutParam(collFiles)));
+ for (size_t a = 0; a < collFiles.size(); a++)
+ {
+ ComPtr<IGuestFile> pCurFile = collFiles[a];
+ if (!pCurFile.isNull())
+ {
+ CHECK_ERROR_BREAK(pCurFile, COMGETTER(Id)(&uID));
+ CHECK_ERROR_BREAK(pCurFile, COMGETTER(FileName)(strName.asOutParam()));
+ FileStatus_T fileStatus;
+ CHECK_ERROR_BREAK(pCurFile, COMGETTER(Status)(&fileStatus));
+
+ RTPrintf("\n\t\tFile #%-03zu ID=%-6RU32 Status=[%s] Name=%ls",
+ a, uID, ctrlFileStatusToText(fileStatus), strName.raw());
+ }
+ }
+
+ cTotalFiles += collFiles.size();
+ }
+ }
+ }
+
+ RTPrintf("\n\nTotal guest sessions: %zu\n", collSessions.size());
+ if (fListAll || fListProcesses)
+ RTPrintf("Total guest processes: %zu\n", cTotalProcs);
+ if (fListAll || fListFiles)
+ RTPrintf("Total guest files: %zu\n", cTotalFiles);
+ }
+ else
+ RTPrintf("No active guest sessions found\n");
+
+ } while (0);
+
+ if (FAILED(rc))
+ rcExit = RTEXITCODE_FAILURE;
+ }
+ else
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_LIST,
+ "Invalid listing category '%s", pCtx->ppaArgv[0]);
+
+ return rcExit;
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlProcessClose(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ if (pCtx->iArgc < 1)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+ "Must specify at least a PID to close");
+
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ { "--session-id", 'i', RTGETOPT_REQ_UINT32 },
+ { "--session-name", 'n', RTGETOPT_REQ_STRING }
+ };
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+ std::vector < uint32_t > vecPID;
+ ULONG ulSessionID = UINT32_MAX;
+ Utf8Str strSessionName;
+
+ int vrc = VINF_SUCCESS;
+
+ while ( (ch = RTGetOpt(&GetState, &ValueUnion))
+ && RT_SUCCESS(vrc))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
+ {
+ case 'n': /* Session name (or pattern) */
+ strSessionName = ValueUnion.psz;
+ break;
+
+ case 'i': /* Session ID */
+ ulSessionID = ValueUnion.u32;
+ break;
+
+ case VINF_GETOPT_NOT_OPTION:
+ if (pCtx->iArgc == GetState.iNext)
+ {
+ /* Treat every else specified as a PID to kill. */
+ try
+ {
+ uint32_t uPID = RTStrToUInt32(ValueUnion.psz);
+ if (uPID) /** @todo Is this what we want? If specifying PID 0
+ this is not going to work on most systems anyway. */
+ vecPID.push_back(uPID);
+ else
+ vrc = VERR_INVALID_PARAMETER;
+ }
+ catch(std::bad_alloc &)
+ {
+ vrc = VERR_NO_MEMORY;
+ }
+ }
+ break;
+
+ default:
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS, ch, &ValueUnion);
+ }
+ }
+
+ if (vecPID.empty())
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+ "At least one PID must be specified to kill!");
+
+ if ( strSessionName.isEmpty()
+ && ulSessionID == UINT32_MAX)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+ "No session ID specified!");
+
+ if ( !strSessionName.isEmpty()
+ && ulSessionID != UINT32_MAX)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+ "Either session ID or name (pattern) must be specified");
+
+ if (RT_FAILURE(vrc))
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+ "Invalid parameters specified");
+
+ HRESULT rc = S_OK;
+
+ ComPtr<IGuestSession> pSession;
+ ComPtr<IGuestProcess> pProcess;
+ do
+ {
+ uint32_t uProcsTerminated = 0;
+ bool fSessionFound = false;
+
+ SafeIfaceArray <IGuestSession> collSessions;
+ CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));
+ size_t cSessions = collSessions.size();
+
+ uint32_t uSessionsHandled = 0;
+ for (size_t i = 0; i < cSessions; i++)
+ {
+ pSession = collSessions[i];
+ Assert(!pSession.isNull());
+
+ ULONG uID; /* Session ID */
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID));
+ Bstr strName;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam()));
+ Utf8Str strNameUtf8(strName); /* Session name */
+ if (strSessionName.isEmpty()) /* Search by ID. Slow lookup. */
+ {
+ fSessionFound = uID == ulSessionID;
+ }
+ else /* ... or by naming pattern. */
+ {
+ if (RTStrSimplePatternMatch(strSessionName.c_str(), strNameUtf8.c_str()))
+ fSessionFound = true;
+ }
+
+ if (fSessionFound)
+ {
+ AssertStmt(!pSession.isNull(), break);
+ uSessionsHandled++;
+
+ SafeIfaceArray <IGuestProcess> collProcs;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Processes)(ComSafeArrayAsOutParam(collProcs)));
+
+ size_t cProcs = collProcs.size();
+ for (size_t p = 0; p < cProcs; p++)
+ {
+ pProcess = collProcs[p];
+ Assert(!pProcess.isNull());
+
+ ULONG uPID; /* Process ID */
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
+
+ bool fProcFound = false;
+ for (size_t a = 0; a < vecPID.size(); a++) /* Slow, but works. */
+ {
+ fProcFound = vecPID[a] == uPID;
+ if (fProcFound)
+ break;
+ }
+
+ if (fProcFound)
+ {
+ if (pCtx->fVerbose)
+ RTPrintf("Terminating process (PID %RU32) (session ID %RU32) ...\n",
+ uPID, uID);
+ CHECK_ERROR_BREAK(pProcess, Terminate());
+ uProcsTerminated++;
+ }
+ else
+ {
+ if (ulSessionID != UINT32_MAX)
+ RTPrintf("No matching process(es) for session ID %RU32 found\n",
+ ulSessionID);
+ }
+
+ pProcess.setNull();
+ }
+
+ pSession.setNull();
+ }
+ }
+
+ if (!uSessionsHandled)
+ RTPrintf("No matching session(s) found\n");
+
+ if (uProcsTerminated)
+ RTPrintf("%RU32 %s terminated\n",
+ uProcsTerminated, uProcsTerminated == 1 ? "process" : "processes");
+
+ } while (0);
+
+ pProcess.setNull();
+ pSession.setNull();
+
+ return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlProcess(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ if (pCtx->iArgc < 1)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+ "Must specify an action");
+
+ /** Use RTGetOpt here when handling command line args gets more complex. */
+
+ if ( !RTStrICmp(pCtx->ppaArgv[0], "close")
+ || !RTStrICmp(pCtx->ppaArgv[0], "kill")
+ || !RTStrICmp(pCtx->ppaArgv[0], "terminate"))
+ {
+ pCtx->iFirstArgc++; /* Skip process action. */
+ return handleCtrlProcessClose(pCtx);
+ }
+
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_PROCESS,
+ "Invalid process action '%s'", pCtx->ppaArgv[0]);
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlSessionClose(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ if (pCtx->iArgc < 1)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
+ "Must specify at least a session to close");
+
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ { "--all", GETOPTDEF_SESSIONCLOSE_ALL, RTGETOPT_REQ_NOTHING },
+ { "--session-id", 'i', RTGETOPT_REQ_UINT32 },
+ { "--session-name", 'n', RTGETOPT_REQ_STRING }
+ };
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ s_aOptions, RT_ELEMENTS(s_aOptions), pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+ ULONG ulSessionID = UINT32_MAX;
+ Utf8Str strSessionName;
+
+ while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
+ {
+ case 'n': /* Session name pattern */
+ strSessionName = ValueUnion.psz;
+ break;
+
+ case 'i': /* Session ID */
+ ulSessionID = ValueUnion.u32;
+ break;
+
+ case GETOPTDEF_SESSIONCLOSE_ALL:
+ strSessionName = "*";
+ break;
+
+ case VINF_GETOPT_NOT_OPTION:
+ /** @todo Supply a CSV list of IDs or patterns to close? */
+ break;
+
+ default:
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION, ch, &ValueUnion);
+ }
+ }
+
+ if ( strSessionName.isEmpty()
+ && ulSessionID == UINT32_MAX)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
+ "No session ID specified!");
+
+ if ( !strSessionName.isEmpty()
+ && ulSessionID != UINT32_MAX)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
+ "Either session ID or name (pattern) must be specified");
+
+ HRESULT rc = S_OK;
+
+ do
+ {
+ bool fSessionFound = false;
+ size_t cSessionsHandled = 0;
+
+ SafeIfaceArray <IGuestSession> collSessions;
+ CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(Sessions)(ComSafeArrayAsOutParam(collSessions)));
+ size_t cSessions = collSessions.size();
+
+ for (size_t i = 0; i < cSessions; i++)
+ {
+ ComPtr<IGuestSession> pSession = collSessions[i];
+ Assert(!pSession.isNull());
+
+ ULONG uID; /* Session ID */
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID));
+ Bstr strName;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam()));
+ Utf8Str strNameUtf8(strName); /* Session name */
+
+ if (strSessionName.isEmpty()) /* Search by ID. Slow lookup. */
+ {
+ fSessionFound = uID == ulSessionID;
+ }
+ else /* ... or by naming pattern. */
+ {
+ if (RTStrSimplePatternMatch(strSessionName.c_str(), strNameUtf8.c_str()))
+ fSessionFound = true;
+ }
+
+ if (fSessionFound)
+ {
+ cSessionsHandled++;
+
+ Assert(!pSession.isNull());
+ if (pCtx->fVerbose)
+ RTPrintf("Closing guest session ID=#%RU32 \"%s\" ...\n",
+ uID, strNameUtf8.c_str());
+ CHECK_ERROR_BREAK(pSession, Close());
+ if (pCtx->fVerbose)
+ RTPrintf("Guest session successfully closed\n");
+
+ pSession.setNull();
+ }
+ }
+
+ if (!cSessionsHandled)
+ {
+ RTPrintf("No guest session(s) found\n");
+ rc = E_ABORT; /* To set exit code accordingly. */
+ }
+
+ } while (0);
+
+ return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlSession(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ if (pCtx->iArgc < 1)
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
+ "Must specify an action");
+
+ /** Use RTGetOpt here when handling command line args gets more complex. */
+
+ if ( !RTStrICmp(pCtx->ppaArgv[0], "close")
+ || !RTStrICmp(pCtx->ppaArgv[0], "kill")
+ || !RTStrICmp(pCtx->ppaArgv[0], "terminate"))
+ {
+ pCtx->iFirstArgc++; /* Skip session action. */
+ return handleCtrlSessionClose(pCtx);
+ }
+
+ return errorSyntaxEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_SESSION,
+ "Invalid session action '%s'", pCtx->ppaArgv[0]);
+}
+
+static DECLCALLBACK(RTEXITCODE) handleCtrlWatch(PGCTLCMDCTX pCtx)
+{
+ AssertPtrReturn(pCtx, RTEXITCODE_FAILURE);
+
+ /*
+ * Parse arguments.
+ */
+ static const RTGETOPTDEF s_aOptions[] = { 0 };
+
+ int ch;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+ RTGetOptInit(&GetState, pCtx->iArgc, pCtx->ppaArgv,
+ NULL /*s_aOptions*/, 0 /*RT_ELEMENTS(s_aOptions)*/, pCtx->iFirstArgc, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+
+ while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+ {
+ /* For options that require an argument, ValueUnion has received the value. */
+ switch (ch)
+ {
+ case VINF_GETOPT_NOT_OPTION:
+ break;
+
+ default:
+ return errorGetOptEx(USAGE_GUESTCONTROL, USAGE_GSTCTRL_WATCH, ch, &ValueUnion);
+ }
+ }
+
+ /** @todo Specify categories to watch for. */
+ /** @todo Specify a --timeout for waiting only for a certain amount of time? */
+
+ HRESULT rc;
+
+ try
+ {
+ ComObjPtr<GuestEventListenerImpl> pGuestListener;
+ do
+ {
+ /* Listener creation. */
+ pGuestListener.createObject();
+ pGuestListener->init(new GuestEventListener());
+
+ /* Register for IGuest events. */
+ ComPtr<IEventSource> es;
+ CHECK_ERROR_BREAK(pCtx->pGuest, COMGETTER(EventSource)(es.asOutParam()));
+ com::SafeArray<VBoxEventType_T> eventTypes;
+ eventTypes.push_back(VBoxEventType_OnGuestSessionRegistered);
+ /** @todo Also register for VBoxEventType_OnGuestUserStateChanged on demand? */
+ CHECK_ERROR_BREAK(es, RegisterListener(pGuestListener, ComSafeArrayAsInParam(eventTypes),
+ true /* Active listener */));
+ /* Note: All other guest control events have to be registered
+ * as their corresponding objects appear. */
+
+ } while (0);
+
+ if (pCtx->fVerbose)
+ RTPrintf("Waiting for events ...\n");
+
+ while (!g_fGuestCtrlCanceled)
+ {
+ /** @todo Timeout handling (see above)? */
+ RTThreadSleep(10);
+ }
+
+ if (pCtx->fVerbose)
+ RTPrintf("Signal caught, exiting ...\n");
+
+ if (!pGuestListener.isNull())
+ {
+ /* Guest callback unregistration. */
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR(pCtx->pGuest, COMGETTER(EventSource)(pES.asOutParam()));
+ if (!pES.isNull())
+ CHECK_ERROR(pES, UnregisterListener(pGuestListener));
+ pGuestListener.setNull();
+ }
+ }
+ catch (std::bad_alloc &)
+ {
+ rc = E_OUTOFMEMORY;
+ }
+
+ return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
+}
+
/**
* Access the guest control store.
*
@@ -2662,56 +3918,142 @@ static int handleCtrlUpdateAdditions(ComPtr<IGuest> guest, HandlerArg *pArg)
*/
int handleGuestControl(HandlerArg *pArg)
{
- AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pArg, VERR_INVALID_POINTER);
#ifdef DEBUG_andy_disabled
if (RT_FAILURE(tstTranslatePath()))
return RTEXITCODE_FAILURE;
#endif
- HandlerArg arg = *pArg;
- arg.argc = pArg->argc - 2; /* Skip VM name and sub command. */
- arg.argv = pArg->argv + 2; /* Same here. */
+ /* pArg->argv[0] contains the VM name. */
+ /* pArg->argv[1] contains the guest control command. */
+ if (pArg->argc < 2)
+ return errorSyntax(USAGE_GUESTCONTROL, "No sub command specified!");
- ComPtr<IGuest> guest;
- int vrc = ctrlInitVM(pArg, pArg->argv[0] /* VM Name */, &guest);
- if (RT_SUCCESS(vrc))
+ uint32_t uCmdCtxFlags = 0;
+ uint32_t uUsage;
+ GCTLCMD gctlCmd;
+ if ( !RTStrICmp(pArg->argv[1], "exec")
+ || !RTStrICmp(pArg->argv[1], "execute"))
{
- int rcExit;
- if (pArg->argc < 2)
- rcExit = errorSyntax(USAGE_GUESTCONTROL, "No sub command specified!");
- else if ( !strcmp(pArg->argv[1], "exec")
- || !strcmp(pArg->argv[1], "execute"))
- rcExit = handleCtrlExecProgram(guest, &arg);
- else if (!strcmp(pArg->argv[1], "copyfrom"))
- rcExit = handleCtrlCopy(guest, &arg, false /* Guest to host */);
- else if ( !strcmp(pArg->argv[1], "copyto")
- || !strcmp(pArg->argv[1], "cp"))
- rcExit = handleCtrlCopy(guest, &arg, true /* Host to guest */);
- else if ( !strcmp(pArg->argv[1], "createdirectory")
- || !strcmp(pArg->argv[1], "createdir")
- || !strcmp(pArg->argv[1], "mkdir")
- || !strcmp(pArg->argv[1], "md"))
- rcExit = handleCtrlCreateDirectory(guest, &arg);
- else if ( !strcmp(pArg->argv[1], "createtemporary")
- || !strcmp(pArg->argv[1], "createtemp")
- || !strcmp(pArg->argv[1], "mktemp"))
- rcExit = handleCtrlCreateTemp(guest, &arg);
- else if ( !strcmp(pArg->argv[1], "stat"))
- rcExit = handleCtrlStat(guest, &arg);
- else if ( !strcmp(pArg->argv[1], "updateadditions")
- || !strcmp(pArg->argv[1], "updateadds"))
- rcExit = handleCtrlUpdateAdditions(guest, &arg);
- /** @todo Implement a "sessions list" command to list all opened
- * guest sessions along with their (friendly) names. */
- else
- rcExit = errorSyntax(USAGE_GUESTCONTROL, "Unknown sub command '%s' specified!", pArg->argv[1]);
+ gctlCmd.pfnHandler = handleCtrlProcessExec;
+ uUsage = USAGE_GSTCTRL_EXEC;
+ }
+ else if (!RTStrICmp(pArg->argv[1], "copyfrom"))
+ {
+ gctlCmd.pfnHandler = handleCtrlCopyFrom;
+ uUsage = USAGE_GSTCTRL_COPYFROM;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "copyto")
+ || !RTStrICmp(pArg->argv[1], "cp"))
+ {
+ gctlCmd.pfnHandler = handleCtrlCopyTo;
+ uUsage = USAGE_GSTCTRL_COPYTO;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "createdirectory")
+ || !RTStrICmp(pArg->argv[1], "createdir")
+ || !RTStrICmp(pArg->argv[1], "mkdir")
+ || !RTStrICmp(pArg->argv[1], "md"))
+ {
+ gctlCmd.pfnHandler = handleCtrlCreateDirectory;
+ uUsage = USAGE_GSTCTRL_CREATEDIR;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "removedirectory")
+ || !RTStrICmp(pArg->argv[1], "removedir")
+ || !RTStrICmp(pArg->argv[1], "rmdir"))
+ {
+ gctlCmd.pfnHandler = handleCtrlRemoveDirectory;
+ uUsage = USAGE_GSTCTRL_REMOVEDIR;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "rm")
+ || !RTStrICmp(pArg->argv[1], "removefile"))
+ {
+ gctlCmd.pfnHandler = handleCtrlRemoveFile;
+ uUsage = USAGE_GSTCTRL_REMOVEFILE;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "ren")
+ || !RTStrICmp(pArg->argv[1], "rename")
+ || !RTStrICmp(pArg->argv[1], "mv"))
+ {
+ gctlCmd.pfnHandler = handleCtrlRename;
+ uUsage = USAGE_GSTCTRL_RENAME;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "createtemporary")
+ || !RTStrICmp(pArg->argv[1], "createtemp")
+ || !RTStrICmp(pArg->argv[1], "mktemp"))
+ {
+ gctlCmd.pfnHandler = handleCtrlCreateTemp;
+ uUsage = USAGE_GSTCTRL_CREATETEMP;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "kill") /* Linux. */
+ || !RTStrICmp(pArg->argv[1], "pkill") /* Solaris / *BSD. */
+ || !RTStrICmp(pArg->argv[1], "pskill")) /* SysInternals version. */
+ {
+ /** @todo What about "taskkill" on Windows? */
+ uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
+ | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
+ gctlCmd.pfnHandler = handleCtrlProcessClose;
+ uUsage = USAGE_GSTCTRL_KILL;
+ }
+ /** @todo Implement "killall"? */
+ else if ( !RTStrICmp(pArg->argv[1], "stat"))
+ {
+ gctlCmd.pfnHandler = handleCtrlStat;
+ uUsage = USAGE_GSTCTRL_STAT;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "updateadditions")
+ || !RTStrICmp(pArg->argv[1], "updateadds"))
+ {
+ uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
+ | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
+ gctlCmd.pfnHandler = handleCtrlUpdateAdditions;
+ uUsage = USAGE_GSTCTRL_UPDATEADDS;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "list"))
+ {
+ uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
+ | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
+ gctlCmd.pfnHandler = handleCtrlList;
+ uUsage = USAGE_GSTCTRL_LIST;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "session"))
+ {
+ uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
+ | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
+ gctlCmd.pfnHandler = handleCtrlSession;
+ uUsage = USAGE_GSTCTRL_SESSION;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "process"))
+ {
+ uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
+ | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
+ gctlCmd.pfnHandler = handleCtrlProcess;
+ uUsage = USAGE_GSTCTRL_PROCESS;
+ }
+ else if ( !RTStrICmp(pArg->argv[1], "watch"))
+ {
+ uCmdCtxFlags = CTLCMDCTX_FLAGS_SESSION_ANONYMOUS
+ | CTLCMDCTX_FLAGS_NO_SIGNAL_HANDLER;
+ gctlCmd.pfnHandler = handleCtrlWatch;
+ uUsage = USAGE_GSTCTRL_WATCH;
+ }
+ else
+ return errorSyntax(USAGE_GUESTCONTROL, "Unknown sub command '%s' specified!", pArg->argv[1]);
+
+ GCTLCMDCTX cmdCtx;
+ RT_ZERO(cmdCtx);
+
+ RTEXITCODE rcExit = ctrlInitVM(pArg, &cmdCtx, uCmdCtxFlags, uUsage);
+ if (rcExit == RTEXITCODE_SUCCESS)
+ {
+ /* Kick off the actual command handler. */
+ rcExit = gctlCmd.pfnHandler(&cmdCtx);
- ctrlUninitVM(pArg);
+ ctrlUninitVM(&cmdCtx, cmdCtx.uFlags);
return rcExit;
}
- return RTEXITCODE_FAILURE;
-}
+ return rcExit;
+}
#endif /* !VBOX_ONLY_DOCS */
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h
new file mode 100644
index 00000000..e172f388
--- /dev/null
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.h
@@ -0,0 +1,233 @@
+/* $Id: VBoxManageGuestCtrl.h $ */
+/** @file
+ * VBoxManageGuestCtrl.h - Definitions for guest control.
+ */
+
+/*
+ * Copyright (C) 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;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * 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.
+ */
+
+#ifndef ___H_VBOXMANAGE_GUESTCTRL
+#define ___H_VBOXMANAGE_GUESTCTRL
+
+#ifndef VBOX_ONLY_DOCS
+
+#include <VBox/com/com.h>
+#include <VBox/com/listeners.h>
+#include <VBox/com/VirtualBox.h>
+
+#include <iprt/time.h>
+
+#include <map>
+
+const char *ctrlFileStatusToText(FileStatus_T enmStatus);
+const char *ctrlProcessStatusToText(ProcessStatus_T enmStatus);
+const char *ctrlSessionStatusToText(GuestSessionStatus_T enmStatus);
+
+using namespace com;
+
+class GuestFileEventListener;
+typedef ListenerImpl<GuestFileEventListener> GuestFileEventListenerImpl;
+
+class GuestProcessEventListener;
+typedef ListenerImpl<GuestProcessEventListener> GuestProcessEventListenerImpl;
+
+class GuestSessionEventListener;
+typedef ListenerImpl<GuestSessionEventListener> GuestSessionEventListenerImpl;
+
+class GuestEventListener;
+typedef ListenerImpl<GuestEventListener> GuestEventListenerImpl;
+
+/** Simple statistics class for binding locally
+ * held data to a specific guest object. */
+class GuestEventStats
+{
+
+public:
+
+ GuestEventStats(void)
+ : uLastUpdatedMS(RTTimeMilliTS())
+ {
+ }
+
+ /** @todo Make this more a class than a structure. */
+public:
+
+ uint64_t uLastUpdatedMS;
+};
+
+class GuestFileStats : public GuestEventStats
+{
+
+public:
+
+ GuestFileStats(void) { }
+
+ GuestFileStats(ComObjPtr<GuestFileEventListenerImpl> pListenerImpl)
+ : mListener(pListenerImpl)
+ {
+ }
+
+public: /** @todo */
+
+ ComObjPtr<GuestFileEventListenerImpl> mListener;
+};
+
+class GuestProcStats : public GuestEventStats
+{
+
+public:
+
+ GuestProcStats(void) { }
+
+ GuestProcStats(ComObjPtr<GuestProcessEventListenerImpl> pListenerImpl)
+ : mListener(pListenerImpl)
+ {
+ }
+
+public: /** @todo */
+
+ ComObjPtr<GuestProcessEventListenerImpl> mListener;
+};
+
+class GuestSessionStats : public GuestEventStats
+{
+
+public:
+
+ GuestSessionStats(void) { }
+
+ GuestSessionStats(ComObjPtr<GuestSessionEventListenerImpl> pListenerImpl)
+ : mListener(pListenerImpl)
+ {
+ }
+
+public: /** @todo */
+
+ ComObjPtr<GuestSessionEventListenerImpl> mListener;
+};
+
+/** Map containing all watched guest files. */
+typedef std::map< ComPtr<IGuestFile>, GuestFileStats > GuestEventFiles;
+/** Map containing all watched guest processes. */
+typedef std::map< ComPtr<IGuestProcess>, GuestProcStats > GuestEventProcs;
+/** Map containing all watched guest sessions. */
+typedef std::map< ComPtr<IGuestSession>, GuestSessionStats > GuestEventSessions;
+
+class GuestListenerBase
+{
+public:
+
+ GuestListenerBase(void);
+
+ virtual ~GuestListenerBase(void);
+
+public:
+
+ HRESULT init(bool fVerbose = false);
+
+protected:
+
+ /** Verbose flag. */
+ bool mfVerbose;
+};
+
+/**
+ * Handler for guest process events.
+ */
+class GuestFileEventListener : public GuestListenerBase
+{
+public:
+
+ GuestFileEventListener(void);
+
+ virtual ~GuestFileEventListener(void);
+
+public:
+
+ void uninit(void);
+
+ STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent);
+
+protected:
+
+};
+
+/**
+ * Handler for guest process events.
+ */
+class GuestProcessEventListener : public GuestListenerBase
+{
+public:
+
+ GuestProcessEventListener(void);
+
+ virtual ~GuestProcessEventListener(void);
+
+public:
+
+ void uninit(void);
+
+ STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent);
+
+protected:
+
+};
+
+/**
+ * Handler for guest session events.
+ */
+class GuestSessionEventListener : public GuestListenerBase
+{
+public:
+
+ GuestSessionEventListener(void);
+
+ virtual ~GuestSessionEventListener(void);
+
+public:
+
+ void uninit(void);
+
+ STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent);
+
+protected:
+
+ GuestEventFiles mFiles;
+ GuestEventProcs mProcs;
+};
+
+/**
+ * Handler for guest events.
+ */
+class GuestEventListener : public GuestListenerBase
+{
+
+public:
+
+ GuestEventListener(void);
+
+ virtual ~GuestEventListener(void);
+
+public:
+
+ void uninit(void);
+
+ STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent);
+
+protected:
+
+ GuestEventSessions mSessions;
+};
+#endif /* !VBOX_ONLY_DOCS */
+
+#endif /* !___H_VBOXMANAGE_GUESTCTRL */
+
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp
new file mode 100644
index 00000000..04c5c575
--- /dev/null
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrlListener.cpp
@@ -0,0 +1,484 @@
+/* $Id: VBoxManageGuestCtrlListener.cpp $ */
+/** @file
+ * VBoxManage - Guest control listener implementations.
+ */
+
+/*
+ * Copyright (C) 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;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * 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"
+#include "VBoxManageGuestCtrl.h"
+
+#ifndef VBOX_ONLY_DOCS
+
+#include <VBox/com/com.h>
+#include <VBox/com/ErrorInfo.h>
+#include <VBox/com/errorprint.h>
+
+#include <iprt/time.h>
+
+#include <map>
+#include <vector>
+
+GuestListenerBase::GuestListenerBase(void)
+ : mfVerbose(false)
+{
+}
+
+GuestListenerBase::~GuestListenerBase(void)
+{
+}
+
+HRESULT GuestListenerBase::init(bool fVerbose)
+{
+ mfVerbose = fVerbose;
+ return S_OK;
+}
+
+
+GuestFileEventListener::GuestFileEventListener(void)
+{
+}
+
+GuestFileEventListener::~GuestFileEventListener(void)
+{
+}
+
+void GuestFileEventListener::uninit(void)
+{
+
+}
+
+STDMETHODIMP GuestFileEventListener::HandleEvent(VBoxEventType_T aType, IEvent *aEvent)
+{
+ switch (aType)
+ {
+ case VBoxEventType_OnGuestFileStateChanged:
+ {
+ HRESULT rc;
+ do
+ {
+ ComPtr<IGuestFileStateChangedEvent> pEvent = aEvent;
+ Assert(!pEvent.isNull());
+
+ ComPtr<IGuestFile> pProcess;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(File)(pProcess.asOutParam()));
+ AssertBreak(!pProcess.isNull());
+ FileStatus_T fileSts;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Status)(&fileSts));
+ Bstr strPath;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(FileName)(strPath.asOutParam()));
+ ULONG uID;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(Id)(&uID));
+
+ RTPrintf("File ID=%RU32 \"%s\" changed status to [%s]\n",
+ uID, Utf8Str(strPath).c_str(),
+ ctrlFileStatusToText(fileSts));
+
+ } while (0);
+ break;
+ }
+
+ default:
+ AssertFailed();
+ }
+
+ return S_OK;
+}
+
+GuestProcessEventListener::GuestProcessEventListener(void)
+{
+}
+
+GuestProcessEventListener::~GuestProcessEventListener(void)
+{
+}
+
+void GuestProcessEventListener::uninit(void)
+{
+
+}
+
+STDMETHODIMP GuestProcessEventListener::HandleEvent(VBoxEventType_T aType, IEvent *aEvent)
+{
+ switch (aType)
+ {
+ case VBoxEventType_OnGuestProcessStateChanged:
+ {
+ HRESULT rc;
+ do
+ {
+ ComPtr<IGuestProcessStateChangedEvent> pEvent = aEvent;
+ Assert(!pEvent.isNull());
+
+ ComPtr<IGuestProcess> pProcess;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Process)(pProcess.asOutParam()));
+ AssertBreak(!pProcess.isNull());
+ ProcessStatus_T procSts;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Status)(&procSts));
+ Bstr strPath;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(ExecutablePath)(strPath.asOutParam()));
+ ULONG uPID;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(PID)(&uPID));
+
+ RTPrintf("Process PID=%RU32 \"%s\" changed status to [%s]\n",
+ uPID, Utf8Str(strPath).c_str(),
+ ctrlProcessStatusToText(procSts));
+
+ } while (0);
+ break;
+ }
+
+ default:
+ AssertFailed();
+ }
+
+ return S_OK;
+}
+
+GuestSessionEventListener::GuestSessionEventListener(void)
+{
+}
+
+GuestSessionEventListener::~GuestSessionEventListener(void)
+{
+}
+
+void GuestSessionEventListener::uninit(void)
+{
+ GuestEventProcs::iterator itProc = mProcs.begin();
+ while (itProc != mProcs.end())
+ {
+ if (!itProc->first.isNull())
+ {
+ HRESULT rc;
+ do
+ {
+ /* Listener unregistration. */
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR_BREAK(itProc->first, COMGETTER(EventSource)(pES.asOutParam()));
+ if (!pES.isNull())
+ CHECK_ERROR_BREAK(pES, UnregisterListener(itProc->second.mListener));
+ } while (0);
+ itProc->first->Release();
+ }
+
+ itProc++;
+ }
+ mProcs.clear();
+
+ GuestEventFiles::iterator itFile = mFiles.begin();
+ while (itFile != mFiles.end())
+ {
+ if (!itFile->first.isNull())
+ {
+ HRESULT rc;
+ do
+ {
+ /* Listener unregistration. */
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR_BREAK(itFile->first, COMGETTER(EventSource)(pES.asOutParam()));
+ if (!pES.isNull())
+ CHECK_ERROR_BREAK(pES, UnregisterListener(itFile->second.mListener));
+ } while (0);
+ itFile->first->Release();
+ }
+
+ itFile++;
+ }
+ mFiles.clear();
+}
+
+STDMETHODIMP GuestSessionEventListener::HandleEvent(VBoxEventType_T aType, IEvent *aEvent)
+{
+ switch (aType)
+ {
+ case VBoxEventType_OnGuestFileRegistered:
+ {
+ HRESULT rc;
+ do
+ {
+ ComPtr<IGuestFileRegisteredEvent> pEvent = aEvent;
+ Assert(!pEvent.isNull());
+
+ ComPtr<IGuestFile> pFile;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(File)(pFile.asOutParam()));
+ AssertBreak(!pFile.isNull());
+ BOOL fRegistered;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered));
+ Bstr strPath;
+ CHECK_ERROR_BREAK(pFile, COMGETTER(FileName)(strPath.asOutParam()));
+
+ RTPrintf("File \"%s\" %s\n",
+ Utf8Str(strPath).c_str(),
+ fRegistered ? "registered" : "unregistered");
+ if (fRegistered)
+ {
+ if (mfVerbose)
+ RTPrintf("Registering ...\n");
+
+ /* Register for IGuestFile events. */
+ ComObjPtr<GuestFileEventListenerImpl> pListener;
+ pListener.createObject();
+ CHECK_ERROR_BREAK(pListener, init(new GuestFileEventListener()));
+
+ ComPtr<IEventSource> es;
+ CHECK_ERROR_BREAK(pFile, COMGETTER(EventSource)(es.asOutParam()));
+ com::SafeArray<VBoxEventType_T> eventTypes;
+ eventTypes.push_back(VBoxEventType_OnGuestFileStateChanged);
+ CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes),
+ true /* Active listener */));
+
+ GuestFileStats fileStats(pListener);
+ mFiles[pFile] = fileStats;
+ }
+ else
+ {
+ GuestEventFiles::iterator itFile = mFiles.find(pFile);
+ if (itFile != mFiles.end())
+ {
+ if (mfVerbose)
+ RTPrintf("Unregistering file ...\n");
+
+ if (!itFile->first.isNull())
+ {
+ /* Listener unregistration. */
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR(itFile->first, COMGETTER(EventSource)(pES.asOutParam()));
+ if (!pES.isNull())
+ CHECK_ERROR(pES, UnregisterListener(itFile->second.mListener));
+ itFile->first->Release();
+ }
+
+ mFiles.erase(itFile);
+ }
+ }
+
+ } while (0);
+ break;
+ }
+
+ case VBoxEventType_OnGuestProcessRegistered:
+ {
+ HRESULT rc;
+ do
+ {
+ ComPtr<IGuestProcessRegisteredEvent> pEvent = aEvent;
+ Assert(!pEvent.isNull());
+
+ ComPtr<IGuestProcess> pProcess;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Process)(pProcess.asOutParam()));
+ AssertBreak(!pProcess.isNull());
+ BOOL fRegistered;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered));
+ Bstr strPath;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(ExecutablePath)(strPath.asOutParam()));
+
+ RTPrintf("Process \"%s\" %s\n",
+ Utf8Str(strPath).c_str(),
+ fRegistered ? "registered" : "unregistered");
+ if (fRegistered)
+ {
+ if (mfVerbose)
+ RTPrintf("Registering ...\n");
+
+ /* Register for IGuestProcess events. */
+ ComObjPtr<GuestProcessEventListenerImpl> pListener;
+ pListener.createObject();
+ CHECK_ERROR_BREAK(pListener, init(new GuestProcessEventListener()));
+
+ ComPtr<IEventSource> es;
+ CHECK_ERROR_BREAK(pProcess, COMGETTER(EventSource)(es.asOutParam()));
+ com::SafeArray<VBoxEventType_T> eventTypes;
+ eventTypes.push_back(VBoxEventType_OnGuestProcessStateChanged);
+ CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes),
+ true /* Active listener */));
+
+ GuestProcStats procStats(pListener);
+ mProcs[pProcess] = procStats;
+ }
+ else
+ {
+ GuestEventProcs::iterator itProc = mProcs.find(pProcess);
+ if (itProc != mProcs.end())
+ {
+ if (mfVerbose)
+ RTPrintf("Unregistering process ...\n");
+
+ if (!itProc->first.isNull())
+ {
+ /* Listener unregistration. */
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR(itProc->first, COMGETTER(EventSource)(pES.asOutParam()));
+ if (!pES.isNull())
+ CHECK_ERROR(pES, UnregisterListener(itProc->second.mListener));
+ itProc->first->Release();
+ }
+
+ mProcs.erase(itProc);
+ }
+ }
+
+ } while (0);
+ break;
+ }
+
+ case VBoxEventType_OnGuestSessionStateChanged:
+ {
+ HRESULT rc;
+ do
+ {
+ ComPtr<IGuestSessionStateChangedEvent> pEvent = aEvent;
+ Assert(!pEvent.isNull());
+ ComPtr<IGuestSession> pSession;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Session)(pSession.asOutParam()));
+ AssertBreak(!pSession.isNull());
+
+ GuestSessionStatus_T sessSts;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Status)(&sessSts));
+ ULONG uID;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID));
+ Bstr strName;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam()));
+
+ RTPrintf("Session ID=%RU32 \"%s\" changed status to [%s]\n",
+ uID, Utf8Str(strName).c_str(),
+ ctrlSessionStatusToText(sessSts));
+
+ } while (0);
+ break;
+ }
+
+ default:
+ AssertFailed();
+ }
+
+ return S_OK;
+}
+
+GuestEventListener::GuestEventListener(void)
+{
+}
+
+GuestEventListener::~GuestEventListener(void)
+{
+}
+
+void GuestEventListener::uninit(void)
+{
+ GuestEventSessions::iterator itSession = mSessions.begin();
+ while (itSession != mSessions.end())
+ {
+ if (!itSession->first.isNull())
+ {
+ HRESULT rc;
+ do
+ {
+ /* Listener unregistration. */
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR_BREAK(itSession->first, COMGETTER(EventSource)(pES.asOutParam()));
+ if (!pES.isNull())
+ CHECK_ERROR_BREAK(pES, UnregisterListener(itSession->second.mListener));
+
+ } while (0);
+ itSession->first->Release();
+ }
+
+ itSession++;
+ }
+ mSessions.clear();
+}
+
+STDMETHODIMP GuestEventListener::HandleEvent(VBoxEventType_T aType, IEvent *aEvent)
+{
+ switch (aType)
+ {
+ case VBoxEventType_OnGuestSessionRegistered:
+ {
+ HRESULT rc;
+ do
+ {
+ ComPtr<IGuestSessionRegisteredEvent> pEvent = aEvent;
+ Assert(!pEvent.isNull());
+
+ ComPtr<IGuestSession> pSession;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Session)(pSession.asOutParam()));
+ AssertBreak(!pSession.isNull());
+ BOOL fRegistered;
+ CHECK_ERROR_BREAK(pEvent, COMGETTER(Registered)(&fRegistered));
+ Bstr strName;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Name)(strName.asOutParam()));
+ ULONG uID;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(Id)(&uID));
+
+ RTPrintf("Session ID=%RU32 \"%s\" %s\n",
+ uID, Utf8Str(strName).c_str(),
+ fRegistered ? "registered" : "unregistered");
+ if (fRegistered)
+ {
+ if (mfVerbose)
+ RTPrintf("Registering ...\n");
+
+ /* Register for IGuestSession events. */
+ ComObjPtr<GuestSessionEventListenerImpl> pListener;
+ pListener.createObject();
+ CHECK_ERROR_BREAK(pListener, init(new GuestSessionEventListener()));
+
+ ComPtr<IEventSource> es;
+ CHECK_ERROR_BREAK(pSession, COMGETTER(EventSource)(es.asOutParam()));
+ com::SafeArray<VBoxEventType_T> eventTypes;
+ eventTypes.push_back(VBoxEventType_OnGuestFileRegistered);
+ eventTypes.push_back(VBoxEventType_OnGuestProcessRegistered);
+ CHECK_ERROR_BREAK(es, RegisterListener(pListener, ComSafeArrayAsInParam(eventTypes),
+ true /* Active listener */));
+
+ GuestSessionStats sessionStats(pListener);
+ mSessions[pSession] = sessionStats;
+ }
+ else
+ {
+ GuestEventSessions::iterator itSession = mSessions.find(pSession);
+ if (itSession != mSessions.end())
+ {
+ if (mfVerbose)
+ RTPrintf("Unregistering ...\n");
+
+ if (!itSession->first.isNull())
+ {
+ /* Listener unregistration. */
+ ComPtr<IEventSource> pES;
+ CHECK_ERROR_BREAK(itSession->first, COMGETTER(EventSource)(pES.asOutParam()));
+ if (!pES.isNull())
+ CHECK_ERROR_BREAK(pES, UnregisterListener(itSession->second.mListener));
+ itSession->first->Release();
+ }
+
+ mSessions.erase(itSession);
+ }
+ }
+
+ } while (0);
+ break;
+ }
+
+ default:
+ AssertFailed();
+ }
+
+ return S_OK;
+}
+#endif /* !VBOX_ONLY_DOCS */
+
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp
index d072a4ea..7d95bb57 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageGuestProp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -28,9 +28,7 @@
#include <VBox/com/array.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-
#include <VBox/com/VirtualBox.h>
-#include <VBox/com/EventQueue.h>
#include <VBox/log.h>
#include <iprt/asm.h>
@@ -55,19 +53,23 @@ using namespace com;
void usageGuestProperty(PRTSTREAM pStrm, const char *pcszSep1, const char *pcszSep2)
{
RTStrmPrintf(pStrm,
- "%s guestproperty %s get <vmname>|<uuid>\n"
+ "%s guestproperty %s get <uuid|vmname>\n"
" <property> [--verbose]\n"
"\n", pcszSep1, pcszSep2);
RTStrmPrintf(pStrm,
- "%s guestproperty %s set <vmname>|<uuid>\n"
+ "%s guestproperty %s set <uuid|vmname>\n"
" <property> [<value> [--flags <flags>]]\n"
"\n", pcszSep1, pcszSep2);
RTStrmPrintf(pStrm,
- "%s guestproperty %s enumerate <vmname>|<uuid>\n"
+ "%s guestproperty %s delete|unset <uuid|vmname>\n"
+ " <property>\n"
+ "\n", pcszSep1, pcszSep2);
+ RTStrmPrintf(pStrm,
+ "%s guestproperty %s enumerate <uuid|vmname>\n"
" [--patterns <patterns>]\n"
"\n", pcszSep1, pcszSep2);
RTStrmPrintf(pStrm,
- "%s guestproperty %s wait <vmname>|<uuid> <patterns>\n"
+ "%s guestproperty %s wait <uuid|vmname> <patterns>\n"
" [--timeout <msec>] [--fail-on-timeout]\n"
"\n", pcszSep1, pcszSep2);
}
@@ -158,9 +160,7 @@ static int handleSetGuestProperty(HandlerArg *a)
/* get the mutable session machine */
a->session->COMGETTER(Machine)(machine.asOutParam());
- if (!pszValue && !pszFlags)
- CHECK_ERROR(machine, DeleteGuestProperty(Bstr(pszName).raw()));
- else if (!pszFlags)
+ if (!pszFlags)
CHECK_ERROR(machine, SetGuestPropertyValue(Bstr(pszName).raw(),
Bstr(pszValue).raw()));
else
@@ -176,6 +176,44 @@ static int handleSetGuestProperty(HandlerArg *a)
return SUCCEEDED(rc) ? 0 : 1;
}
+static int handleDeleteGuestProperty(HandlerArg *a)
+{
+ HRESULT rc = S_OK;
+
+ /*
+ * Check the syntax. We can deduce the correct syntax from the number of
+ * arguments.
+ */
+ bool usageOK = true;
+ const char *pszName = NULL;
+ if (a->argc != 2)
+ usageOK = false;
+ if (!usageOK)
+ return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");
+ /* This is always needed. */
+ pszName = a->argv[1];
+
+ ComPtr<IMachine> machine;
+ CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
+ machine.asOutParam()));
+ if (machine)
+ {
+ /* open a session for the VM - new or existing */
+ CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
+
+ /* get the mutable session machine */
+ a->session->COMGETTER(Machine)(machine.asOutParam());
+
+ CHECK_ERROR(machine, DeleteGuestProperty(Bstr(pszName).raw()));
+
+ if (SUCCEEDED(rc))
+ CHECK_ERROR(machine, SaveSettings());
+
+ a->session->UnlockMachine();
+ }
+ return SUCCEEDED(rc) ? 0 : 1;
+}
+
/**
* Enumerates the properties in the guest property store.
*
@@ -384,6 +422,8 @@ int handleGuestProperty(HandlerArg *a)
return handleGetGuestProperty(&arg);
if (strcmp(a->argv[0], "set") == 0)
return handleSetGuestProperty(&arg);
+ if (strcmp(a->argv[0], "delete") == 0 || strcmp(a->argv[0], "unset") == 0)
+ return handleDeleteGuestProperty(&arg);
if (strcmp(a->argv[0], "enumerate") == 0)
return handleEnumGuestProperty(&arg);
if (strcmp(a->argv[0], "wait") == 0)
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
index 6c28c3b5..cc3ab446 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -46,7 +46,7 @@ void showLogo(PRTSTREAM pStrm)
}
}
-void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
+void printUsage(USAGECATEGORY fCategory, uint32_t fSubCategory, PRTSTREAM pStrm)
{
bool fDumpOpts = false;
#ifdef RT_OS_LINUX
@@ -80,7 +80,7 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
bool fVBoxSDL = false;
#endif
- if (u64Cmd == USAGE_DUMPOPTS)
+ if (fCategory == USAGE_DUMPOPTS)
{
fDumpOpts = true;
fLinux = true;
@@ -89,14 +89,14 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
fFreeBSD = true;
fDarwin = true;
fVBoxSDL = true;
- u64Cmd = USAGE_ALL;
+ fCategory = USAGE_ALL;
}
RTStrmPrintf(pStrm,
"Usage:\n"
"\n");
- if (u64Cmd == USAGE_ALL)
+ if (fCategory == USAGE_ALL)
RTStrmPrintf(pStrm,
" VBoxManage [<general option>] <command>\n"
" \n \n"
@@ -110,7 +110,7 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
const char *pcszSep1 = " ";
const char *pcszSep2 = " ";
- if (u64Cmd != USAGE_ALL)
+ if (fCategory != USAGE_ALL)
{
pcszSep1 = "VBoxManage";
pcszSep2 = "";
@@ -118,37 +118,37 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
#define SEP pcszSep1, pcszSep2
- if (u64Cmd & USAGE_LIST)
+ if (fCategory & USAGE_LIST)
RTStrmPrintf(pStrm,
"%s list [--long|-l]%s vms|runningvms|ostypes|hostdvds|hostfloppies|\n"
#if defined(VBOX_WITH_NETFLT)
- " bridgedifs|hostonlyifs|dhcpservers|hostinfo|\n"
+ " intnets|bridgedifs|hostonlyifs|natnets|dhcpservers|\n"
#else
- " bridgedifs|dhcpservers|hostinfo|\n"
+ " intnets|bridgedifs|natnets|dhcpservers|hostinfo|\n"
#endif
- " hostcpuids|hddbackends|hdds|dvds|floppies|\n"
+ " hostinfo|hostcpuids|hddbackends|hdds|dvds|floppies|\n"
" usbhost|usbfilters|systemproperties|extpacks|\n"
- " groups\n"
+ " groups|webcams\n"
"\n", SEP);
- if (u64Cmd & USAGE_SHOWVMINFO)
+ if (fCategory & USAGE_SHOWVMINFO)
RTStrmPrintf(pStrm,
- "%s showvminfo %s <uuid>|<name> [--details]\n"
+ "%s showvminfo %s <uuid|vmname> [--details]\n"
" [--machinereadable]\n"
- "%s showvminfo %s <uuid>|<name> --log <idx>\n"
+ "%s showvminfo %s <uuid|vmname> --log <idx>\n"
"\n", SEP, SEP);
- if (u64Cmd & USAGE_REGISTERVM)
+ if (fCategory & USAGE_REGISTERVM)
RTStrmPrintf(pStrm,
"%s registervm %s <filename>\n"
"\n", SEP);
- if (u64Cmd & USAGE_UNREGISTERVM)
+ if (fCategory & USAGE_UNREGISTERVM)
RTStrmPrintf(pStrm,
- "%s unregistervm %s <uuid>|<name> [--delete]\n"
+ "%s unregistervm %s <uuid|vmname> [--delete]\n"
"\n", SEP);
- if (u64Cmd & USAGE_CREATEVM)
+ if (fCategory & USAGE_CREATEVM)
RTStrmPrintf(pStrm,
"%s createvm %s --name <name>\n"
" [--groups <group>, ...]\n"
@@ -158,13 +158,14 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--uuid <uuid>]\n"
"\n", SEP);
- if (u64Cmd & USAGE_MODIFYVM)
+ if (fCategory & USAGE_MODIFYVM)
{
RTStrmPrintf(pStrm,
- "%s modifyvm %s <uuid|name>\n"
+ "%s modifyvm %s <uuid|vmname>\n"
" [--name <name>]\n"
" [--groups <group>, ...]\n"
" [--ostype <ostype>]\n"
+ " [--iconfile <filename>]\n"
" [--memory <memorysize in MB>]\n"
" [--pagefusion on|off]\n"
" [--vram <vramsize in MB>]\n"
@@ -175,13 +176,15 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--pcidetach 03:04.0]\n"
#endif
" [--ioapic on|off]\n"
- " [--pae on|off]\n"
" [--hpet on|off]\n"
+ " [--triplefaultreset on|off]\n"
" [--hwvirtex on|off]\n"
- " [--hwvirtexexcl on|off]\n"
" [--nestedpaging on|off]\n"
" [--largepages on|off]\n"
" [--vtxvpid on|off]\n"
+ " [--vtxux on|off]\n"
+ " [--pae on|off]\n"
+ " [--longmode on|off]\n"
" [--synthcpu on|off]\n"
" [--cpuidset <leaf> <eax> <ebx> <ecx> <edx>]\n"
" [--cpuidremove <leaf>]\n"
@@ -193,6 +196,11 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--unplugcpu <id>]\n"
" [--cpuexecutioncap <1-100>]\n"
" [--rtcuseutc on|off]\n"
+#ifdef VBOX_WITH_VMSVGA
+ " [--graphicscontroller none|vboxvga|vmsvga]\n"
+#else
+ " [--graphicscontroller none|vboxvga]\n"
+#endif
" [--monitorcount <number>]\n"
" [--accelerate3d on|off]\n"
#ifdef VBOX_WITH_VIDEOHWACCEL
@@ -213,7 +221,7 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
"|hostonly"
#endif
"|\n"
- " generic"
+ " generic|natnetwork"
"]\n"
" [--nictype<1-N> Am79C970A|Am79C973"
#ifdef VBOX_WITH_E1000
@@ -236,8 +244,9 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--hostonlyadapter<1-N> none|<devicename>]\n"
#endif
" [--intnet<1-N> <network name>]\n"
- " [--natnet<1-N> <network>|default]\n"
+ " [--nat-network<1-N> <network name>]\n"
" [--nicgenericdrv<1-N> <driver>\n"
+ " [--natnet<1-N> <network>|default]\n"
" [--natsettings<1-N> [<mtu>],[<socksnd>],\n"
" [<sockrcv>],[<tcpsnd>],\n"
" [<tcprcv>]]\n"
@@ -254,7 +263,7 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--nataliasmode<1-N> default|[log],[proxyonly],\n"
" [sameports]]\n"
" [--macaddress<1-N> auto|<mac>]\n"
- " [--mouse ps2|usb|usbtablet\n"
+ " [--mouse ps2|usb|usbtablet|usbmultitouch]\n"
" [--keyboard ps2|usb\n"
" [--uart<1-N> off|<I/O base> <IRQ>]\n"
" [--uartmode<1-N> disconnected|\n"
@@ -267,7 +276,6 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--lptmode<1-N> <devicename>]\n"
#endif
" [--guestmemoryballoon <balloonsize in MB>]\n"
- " [--gueststatisticsinterval <seconds>]\n"
" [--audio none|null", SEP);
if (fWin)
{
@@ -340,7 +348,7 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--teleporterport <port>]\n"
" [--teleporteraddress <address|empty>\n"
" [--teleporterpassword <password>]\n"
- " [--teleporterpasswordfile <file>|stdin]\n"
+ " [--teleporterpasswordfile <file>|stdin]\n"
" [--tracing-enabled on|off]\n"
" [--tracing-config <config-string>]\n"
" [--tracing-allow-vm-access on|off]\n"
@@ -364,12 +372,22 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--autostop-type disabled|savestate|poweroff|\n"
" acpishutdown]\n"
#endif
+#ifdef VBOX_WITH_VPX
+ " [--vcpenabled on|off]\n"
+ " [--vcpscreens [<display>],...\n"
+ " [--vcpfile <filename>]\n"
+ " [--vcpwidth <width>]\n"
+ " [--vcpheight <height>]\n"
+ " [--vcprate <rate>]\n"
+ " [--vcpfps <fps>]\n"
+#endif
+ " [--defaultfrontend default|<name>]\n"
"\n");
}
- if (u64Cmd & USAGE_CLONEVM)
+ if (fCategory & USAGE_CLONEVM)
RTStrmPrintf(pStrm,
- "%s clonevm %s <uuid>|<name>\n"
+ "%s clonevm %s <uuid|vmname>\n"
" [--snapshot <uuid>|<name>]\n"
" [--mode machine|machineandchildren|all]\n"
" [--options link|keepallmacs|keepnatmacs|\n"
@@ -381,34 +399,37 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--register]\n"
"\n", SEP);
- if (u64Cmd & USAGE_IMPORTAPPLIANCE)
+ if (fCategory & USAGE_IMPORTAPPLIANCE)
RTStrmPrintf(pStrm,
- "%s import %s <ovf/ova>\n"
+ "%s import %s <ovfname/ovaname>\n"
" [--dry-run|-n]\n"
" [--options keepallmacs|keepnatmacs]\n"
" [more options]\n"
" (run with -n to have options displayed\n"
" for a particular OVF)\n\n", SEP);
- if (u64Cmd & USAGE_EXPORTAPPLIANCE)
+ if (fCategory & USAGE_EXPORTAPPLIANCE)
RTStrmPrintf(pStrm,
"%s export %s <machines> --output|-o <name>.<ovf/ova>\n"
" [--legacy09|--ovf09|--ovf10|--ovf20]\n"
" [--manifest]\n"
+ " [--iso]\n"
+ " [--options manifest|iso|nomacs|nomacsbutnat]\n"
" [--vsys <number of virtual system>]\n"
" [--product <product name>]\n"
" [--producturl <product url>]\n"
" [--vendor <vendor name>]\n"
" [--vendorurl <vendor url>]\n"
" [--version <version info>]\n"
+ " [--description <description info>]\n"
" [--eula <license text>]\n"
" [--eulafile <filename>]\n"
"\n", SEP);
- if (u64Cmd & USAGE_STARTVM)
+ if (fCategory & USAGE_STARTVM)
{
RTStrmPrintf(pStrm,
- "%s startvm %s <uuid>|<name>...\n"
+ "%s startvm %s <uuid|vmname>...\n"
" [--type gui", SEP);
if (fVBoxSDL)
RTStrmPrintf(pStrm, "|sdl");
@@ -417,43 +438,44 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
"\n");
}
- if (u64Cmd & USAGE_CONTROLVM)
+ if (fCategory & USAGE_CONTROLVM)
{
RTStrmPrintf(pStrm,
- "%s controlvm %s <uuid>|<name>\n"
+ "%s controlvm %s <uuid|vmname>\n"
" pause|resume|reset|poweroff|savestate|\n"
" acpipowerbutton|acpisleepbutton|\n"
" keyboardputscancode <hex> [<hex> ...]|\n"
" setlinkstate<1-N> on|off |\n"
#if defined(VBOX_WITH_NETFLT)
- " nic<1-N> null|nat|bridged|intnet|hostonly|generic"
- "\n"
- " [<devicename>] |\n"
+ " nic<1-N> null|nat|bridged|intnet|hostonly|generic|\n"
+ " natnetwork [<devicename>] |\n"
#else /* !VBOX_WITH_NETFLT */
- " nic<1-N> null|nat|bridged|intnet|generic\n"
+ " nic<1-N> null|nat|bridged|intnet|generic|natnetwork\n"
" [<devicename>] |\n"
#endif /* !VBOX_WITH_NETFLT */
- " nictrace<1-N> on|off\n"
- " nictracefile<1-N> <filename>\n"
- " nicproperty<1-N> name=[value]\n"
+ " nictrace<1-N> on|off |\n"
+ " nictracefile<1-N> <filename> |\n"
+ " nicproperty<1-N> name=[value] |\n"
+ " nicpromisc<1-N> deny|allow-vms|allow-all |\n"
" natpf<1-N> [<rulename>],tcp|udp,[<hostip>],\n"
- " <hostport>,[<guestip>],<guestport>\n"
- " natpf<1-N> delete <rulename>\n"
- " guestmemoryballoon <balloonsize in MB>]\n"
- " gueststatisticsinterval <seconds>]\n"
+ " <hostport>,[<guestip>],<guestport> |\n"
+ " natpf<1-N> delete <rulename> |\n"
+ " guestmemoryballoon <balloonsize in MB> |\n"
" usbattach <uuid>|<address> |\n"
" usbdetach <uuid>|<address> |\n"
" clipboard disabled|hosttoguest|guesttohost|\n"
- " bidirectional]\n"
- " draganddrop disabled|hosttoguest]\n"
+ " bidirectional |\n"
+ " draganddrop disabled|hosttoguest |\n"
" vrde on|off |\n"
" vrdeport <port> |\n"
" vrdeproperty <name=[value]> |\n"
- " vrdevideochannelquality <percent>\n"
+ " vrdevideochannelquality <percent> |\n"
" setvideomodehint <xres> <yres> <bpp>\n"
- " [[<display>] [<enabled:yes|no>\n"
+ " [[<display>] [<enabled:yes|no> |\n"
" [<xorigin> <yorigin>]]] |\n"
" screenshotpng <file> [display] |\n"
+ " vcpenabled on|off |\n"
+ " vcpscreens all|none|<screen>,[<screen>...] |\n"
" setcredentials <username>\n"
" --passwordfile <file> | <password>\n"
" <domain>\n"
@@ -461,52 +483,53 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" teleport --host <name> --port <port>\n"
" [--maxdowntime <msec>]\n"
" [--passwordfile <file> |\n"
- " --password <password>]\n"
- " plugcpu <id>\n"
- " unplugcpu <id>\n"
+ " --password <password>] |\n"
+ " plugcpu <id> |\n"
+ " unplugcpu <id> |\n"
" cpuexecutioncap <1-100>\n"
+ " webcam <attach [path [settings]]> | <detach [path]> | <list>\n"
"\n", SEP);
}
- if (u64Cmd & USAGE_DISCARDSTATE)
+ if (fCategory & USAGE_DISCARDSTATE)
RTStrmPrintf(pStrm,
- "%s discardstate %s <uuid>|<name>\n"
+ "%s discardstate %s <uuid|vmname>\n"
"\n", SEP);
- if (u64Cmd & USAGE_ADOPTSTATE)
+ if (fCategory & USAGE_ADOPTSTATE)
RTStrmPrintf(pStrm,
- "%s adoptstate %s <uuid>|<name> <state_file>\n"
+ "%s adoptstate %s <uuid|vmname> <state_file>\n"
"\n", SEP);
- if (u64Cmd & USAGE_SNAPSHOT)
+ if (fCategory & USAGE_SNAPSHOT)
RTStrmPrintf(pStrm,
- "%s snapshot %s <uuid>|<name>\n"
- " take <name> [--description <desc>] [--pause] |\n"
- " delete <uuid>|<name> |\n"
- " restore <uuid>|<name> |\n"
+ "%s snapshot %s <uuid|vmname>\n"
+ " take <name> [--description <desc>] [--live] |\n"
+ " delete <uuid|snapname> |\n"
+ " restore <uuid|snapname> |\n"
" restorecurrent |\n"
- " edit <uuid>|<name>|--current\n"
+ " edit <uuid|snapname>|--current\n"
" [--name <name>]\n"
" [--description <desc>] |\n"
" list [--details|--machinereadable]\n"
- " showvminfo <uuid>|<name>\n"
+ " showvminfo <uuid|snapname>\n"
"\n", SEP);
- if (u64Cmd & USAGE_CLOSEMEDIUM)
+ if (fCategory & USAGE_CLOSEMEDIUM)
RTStrmPrintf(pStrm,
- "%s closemedium %s disk|dvd|floppy <uuid>|<filename>\n"
+ "%s closemedium %s disk|dvd|floppy <uuid|filename>\n"
" [--delete]\n"
"\n", SEP);
- if (u64Cmd & USAGE_STORAGEATTACH)
+ if (fCategory & USAGE_STORAGEATTACH)
RTStrmPrintf(pStrm,
"%s storageattach %s <uuid|vmname>\n"
" --storagectl <name>\n"
" [--port <number>]\n"
" [--device <number>]\n"
" [--type dvddrive|hdd|fdd]\n"
- " [--medium none|emptydrive|\n"
- " <uuid>|<filename>|host:<drive>|iscsi]\n"
+ " [--medium none|emptydrive|additions|\n"
+ " <uuid|filename>|host:<drive>|iscsi]\n"
" [--mtype normal|writethrough|immutable|shareable|\n"
" readonly|multiattach]\n"
" [--comment <text>]\n"
@@ -529,20 +552,20 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--intnet]\n"
"\n", SEP);
- if (u64Cmd & USAGE_STORAGECONTROLLER)
+ if (fCategory & USAGE_STORAGECONTROLLER)
RTStrmPrintf(pStrm,
"%s storagectl %s <uuid|vmname>\n"
" --name <name>\n"
" [--add ide|sata|scsi|floppy|sas]\n"
" [--controller LSILogic|LSILogicSAS|BusLogic|\n"
" IntelAHCI|PIIX3|PIIX4|ICH6|I82078]\n"
- " [--sataportcount <1-30>]\n"
+ " [--portcount <1-30>]\n"
" [--hostiocache on|off]\n"
" [--bootable on|off]\n"
" [--remove]\n"
"\n", SEP);
- if (u64Cmd & USAGE_BANDWIDTHCONTROL)
+ if (fCategory & USAGE_BANDWIDTHCONTROL)
RTStrmPrintf(pStrm,
"%s bandwidthctl %s <uuid|vmname>\n"
" add <name> --type disk|network\n"
@@ -555,12 +578,12 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" K=kilobyte, M=megabyte, G=gigabyte)\n"
"\n", SEP);
- if (u64Cmd & USAGE_SHOWHDINFO)
+ if (fCategory & USAGE_SHOWHDINFO)
RTStrmPrintf(pStrm,
- "%s showhdinfo %s <uuid>|<filename>\n"
+ "%s showhdinfo %s <uuid|filename>\n"
"\n", SEP);
- if (u64Cmd & USAGE_CREATEHD)
+ if (fCategory & USAGE_CREATEHD)
RTStrmPrintf(pStrm,
"%s createhd %s --filename <filename>\n"
" [--size <megabytes>|--sizebyte <bytes>]\n"
@@ -569,25 +592,26 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--variant Standard,Fixed,Split2G,Stream,ESX]\n"
"\n", SEP);
- if (u64Cmd & USAGE_MODIFYHD)
+ if (fCategory & USAGE_MODIFYHD)
RTStrmPrintf(pStrm,
- "%s modifyhd %s <uuid>|<filename>\n"
+ "%s modifyhd %s <uuid|filename>\n"
" [--type normal|writethrough|immutable|shareable|\n"
" readonly|multiattach]\n"
" [--autoreset on|off]\n"
+ " [--property <name=[value]>]\n"
" [--compact]\n"
" [--resize <megabytes>|--resizebyte <bytes>]\n"
"\n", SEP);
- if (u64Cmd & USAGE_CLONEHD)
+ if (fCategory & USAGE_CLONEHD)
RTStrmPrintf(pStrm,
- "%s clonehd %s <uuid>|<filename> <uuid>|<outputfile>\n"
+ "%s clonehd %s <uuid|inputfile> <uuid|outputfile>\n"
" [--format VDI|VMDK|VHD|RAW|<other>]\n"
" [--variant Standard,Fixed,Split2G,Stream,ESX]\n"
" [--existing]\n"
"\n", SEP);
- if (u64Cmd & USAGE_CONVERTFROMRAW)
+ if (fCategory & USAGE_CONVERTFROMRAW)
RTStrmPrintf(pStrm,
"%s convertfromraw %s <filename> <outputfile>\n"
" [--format VDI|VMDK|VHD]\n"
@@ -599,33 +623,35 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--uuid <uuid>]\n"
"\n", SEP, SEP);
- if (u64Cmd & USAGE_GETEXTRADATA)
+ if (fCategory & USAGE_GETEXTRADATA)
RTStrmPrintf(pStrm,
- "%s getextradata %s global|<uuid>|<name>\n"
+ "%s getextradata %s global|<uuid|vmname>\n"
" <key>|enumerate\n"
"\n", SEP);
- if (u64Cmd & USAGE_SETEXTRADATA)
+ if (fCategory & USAGE_SETEXTRADATA)
RTStrmPrintf(pStrm,
- "%s setextradata %s global|<uuid>|<name>\n"
+ "%s setextradata %s global|<uuid|vmname>\n"
" <key>\n"
" [<value>] (no value deletes key)\n"
"\n", SEP);
- if (u64Cmd & USAGE_SETPROPERTY)
+ if (fCategory & USAGE_SETPROPERTY)
RTStrmPrintf(pStrm,
"%s setproperty %s machinefolder default|<folder> |\n"
+ " hwvirtexclusive on|off |\n"
" vrdeauthlibrary default|<library> |\n"
" websrvauthlibrary default|null|<library> |\n"
" vrdeextpack null|<library> |\n"
" autostartdbpath null|<folder> |\n"
" loghistorycount <value>\n"
+ " defaultfrontend default|<name>\n"
"\n", SEP);
- if (u64Cmd & USAGE_USBFILTER_ADD)
+ if (fCategory & USAGE_USBFILTER_ADD)
RTStrmPrintf(pStrm,
"%s usbfilter %s add <index,0-N>\n"
- " --target <uuid>|<name>|global\n"
+ " --target <uuid|vmname>|global\n"
" --name <string>\n"
" --action ignore|hold (global filters only)\n"
" [--active yes|no] (yes)\n"
@@ -639,10 +665,10 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--maskedinterfaces <XXXXXXXX>]\n"
"\n", SEP);
- if (u64Cmd & USAGE_USBFILTER_MODIFY)
+ if (fCategory & USAGE_USBFILTER_MODIFY)
RTStrmPrintf(pStrm,
"%s usbfilter %s modify <index,0-N>\n"
- " --target <uuid>|<name>|global\n"
+ " --target <uuid|vmname>|global\n"
" [--name <string>]\n"
" [--action ignore|hold] (global filters only)\n"
" [--active yes|no]\n"
@@ -656,39 +682,39 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--maskedinterfaces <XXXXXXXX>]\n"
"\n", SEP);
- if (u64Cmd & USAGE_USBFILTER_REMOVE)
+ if (fCategory & USAGE_USBFILTER_REMOVE)
RTStrmPrintf(pStrm,
"%s usbfilter %s remove <index,0-N>\n"
- " --target <uuid>|<name>|global\n"
+ " --target <uuid|vmname>|global\n"
"\n", SEP);
- if (u64Cmd & USAGE_SHAREDFOLDER_ADD)
+ if (fCategory & USAGE_SHAREDFOLDER_ADD)
RTStrmPrintf(pStrm,
- "%s sharedfolder %s add <vmname>|<uuid>\n"
+ "%s sharedfolder %s add <uuid|vmname>\n"
" --name <name> --hostpath <hostpath>\n"
" [--transient] [--readonly] [--automount]\n"
"\n", SEP);
- if (u64Cmd & USAGE_SHAREDFOLDER_REMOVE)
+ if (fCategory & USAGE_SHAREDFOLDER_REMOVE)
RTStrmPrintf(pStrm,
- "%s sharedfolder %s remove <vmname>|<uuid>\n"
+ "%s sharedfolder %s remove <uuid|vmname>\n"
" --name <name> [--transient]\n"
"\n", SEP);
#ifdef VBOX_WITH_GUEST_PROPS
- if (u64Cmd & USAGE_GUESTPROPERTY)
+ if (fCategory & USAGE_GUESTPROPERTY)
usageGuestProperty(pStrm, SEP);
#endif /* VBOX_WITH_GUEST_PROPS defined */
#ifdef VBOX_WITH_GUEST_CONTROL
- if (u64Cmd & USAGE_GUESTCONTROL)
- usageGuestControl(pStrm, SEP);
+ if (fCategory & USAGE_GUESTCONTROL)
+ usageGuestControl(pStrm, SEP, fSubCategory);
#endif /* VBOX_WITH_GUEST_CONTROL defined */
- if (u64Cmd & USAGE_DEBUGVM)
+ if (fCategory & USAGE_DEBUGVM)
{
RTStrmPrintf(pStrm,
- "%s debugvm %s <uuid>|<name>\n"
+ "%s debugvm %s <uuid|vmname>\n"
" dumpguestcore --filename <name> |\n"
" info <item> [args] |\n"
" injectnmi |\n"
@@ -707,7 +733,7 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [--descriptions]\n"
"\n", SEP);
}
- if (u64Cmd & USAGE_METRICS)
+ if (fCategory & USAGE_METRICS)
RTStrmPrintf(pStrm,
"%s metrics %s list [*|host|<vmname> [<metric_list>]]\n"
" (comma-separated)\n\n"
@@ -731,8 +757,39 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
" [*|host|<vmname> [<metric_list>]]\n"
"\n", SEP, SEP, SEP, SEP, SEP, SEP);
+#if defined(VBOX_WITH_NAT_SERVICE)
+ if (fCategory & USAGE_NATNETWORK)
+ {
+ RTStrmPrintf(pStrm,
+ "%s natnetwork %s add --netname <name>\n"
+ " --network <network>\n"
+ " [--enable|--disable]\n"
+ " [--dhcp on|off]\n"
+ " [--port-forward-4 <rule>]\n"
+ " [--loopback-4 <rule>]\n"
+ " [--ipv6 on|off]\n"
+ " [--port-forward-6 <rule>]\n"
+ " [--loopback-6 <rule>]\n\n"
+ "%s natnetwork %s remove --netname <name>\n\n"
+ "%s natnetwork %s modify --netname <name>\n"
+ " [--network <network>]\n"
+ " [--enable|--disable]\n"
+ " [--dhcp on|off]\n"
+ " [--port-forward-4 <rule>]\n"
+ " [--loopback-4 <rule>]\n"
+ " [--ipv6 on|off]\n"
+ " [--port-forward-6 <rule>]\n"
+ " [--loopback-6 <rule>]\n\n"
+ "%s natnetwork %s start --netname <name>\n\n"
+ "%s natnetwork %s stop --netname <name>\n"
+ "\n", SEP, SEP, SEP, SEP, SEP);
+
+
+ }
+#endif
+
#if defined(VBOX_WITH_NETFLT)
- if (u64Cmd & USAGE_HOSTONLYIFS)
+ if (fCategory & USAGE_HOSTONLYIFS)
{
RTStrmPrintf(pStrm,
"%s hostonlyif %s ipconfig <name>\n"
@@ -747,7 +804,7 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
}
#endif
- if (u64Cmd & USAGE_DHCPSERVER)
+ if (fCategory & USAGE_DHCPSERVER)
{
RTStrmPrintf(pStrm,
"%s dhcpserver %s add|modify --netname <network_name> |\n"
@@ -765,7 +822,7 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
#endif
"\n", SEP, SEP);
}
- if (u64Cmd & USAGE_EXTPACK)
+ if (fCategory & USAGE_EXTPACK)
{
RTStrmPrintf(pStrm,
"%s extpack %s install [--replace] <tarball> |\n"
@@ -779,15 +836,35 @@ void printUsage(USAGECATEGORY u64Cmd, PRTSTREAM pStrm)
* Print a usage synopsis and the syntax error message.
* @returns RTEXITCODE_SYNTAX.
*/
-RTEXITCODE errorSyntax(USAGECATEGORY u64Cmd, const char *pszFormat, ...)
+RTEXITCODE errorSyntax(USAGECATEGORY fCategory, const char *pszFormat, ...)
+{
+ va_list args;
+ showLogo(g_pStdErr); // show logo even if suppressed
+#ifndef VBOX_ONLY_DOCS
+ if (g_fInternalMode)
+ printUsageInternal(fCategory, g_pStdErr);
+ else
+ printUsage(fCategory, ~0U, g_pStdErr);
+#endif /* !VBOX_ONLY_DOCS */
+ va_start(args, pszFormat);
+ RTStrmPrintf(g_pStdErr, "\nSyntax error: %N\n", pszFormat, &args);
+ va_end(args);
+ return RTEXITCODE_SYNTAX;
+}
+
+/**
+ * Print a usage synopsis and the syntax error message.
+ * @returns RTEXITCODE_SYNTAX.
+ */
+RTEXITCODE errorSyntaxEx(USAGECATEGORY fCategory, uint32_t fSubCategory, const char *pszFormat, ...)
{
va_list args;
showLogo(g_pStdErr); // show logo even if suppressed
#ifndef VBOX_ONLY_DOCS
if (g_fInternalMode)
- printUsageInternal(u64Cmd, g_pStdErr);
+ printUsageInternal(fCategory, g_pStdErr);
else
- printUsage(u64Cmd, g_pStdErr);
+ printUsage(fCategory, fSubCategory, g_pStdErr);
#endif /* !VBOX_ONLY_DOCS */
va_start(args, pszFormat);
RTStrmPrintf(g_pStdErr, "\nSyntax error: %N\n", pszFormat, &args);
@@ -800,11 +877,12 @@ RTEXITCODE errorSyntax(USAGECATEGORY u64Cmd, const char *pszFormat, ...)
*
* @returns RTEXITCODE_SYNTAX.
*
- * @param fUsageCategory The usage category of the command.
+ * @param fCategory The usage category of the command.
+ * @param fSubCategory The usage sub-category of the command.
* @param rc The RTGetOpt return code.
* @param pValueUnion The value union.
*/
-RTEXITCODE errorGetOpt(USAGECATEGORY fUsageCategory, int rc, union RTGETOPTUNION const *pValueUnion)
+RTEXITCODE errorGetOptEx(USAGECATEGORY fCategory, uint32_t fSubCategory, int rc, union RTGETOPTUNION const *pValueUnion)
{
/*
* Check if it is an unhandled standard option.
@@ -820,9 +898,9 @@ RTEXITCODE errorGetOpt(USAGECATEGORY fUsageCategory, int rc, union RTGETOPTUNION
showLogo(g_pStdErr);
#ifndef VBOX_ONLY_DOCS
if (g_fInternalMode)
- printUsageInternal(fUsageCategory, g_pStdOut);
+ printUsageInternal(fCategory, g_pStdOut);
else
- printUsage(fUsageCategory, g_pStdOut);
+ printUsage(fCategory, fSubCategory, g_pStdOut);
#endif
return RTEXITCODE_SUCCESS;
}
@@ -833,9 +911,9 @@ RTEXITCODE errorGetOpt(USAGECATEGORY fUsageCategory, int rc, union RTGETOPTUNION
showLogo(g_pStdErr); // show logo even if suppressed
#ifndef VBOX_ONLY_DOCS
if (g_fInternalMode)
- printUsageInternal(fUsageCategory, g_pStdErr);
+ printUsageInternal(fCategory, g_pStdErr);
else
- printUsage(fUsageCategory, g_pStdErr);
+ printUsage(fCategory, fSubCategory, g_pStdErr);
#endif /* !VBOX_ONLY_DOCS */
if (rc == VINF_GETOPT_NOT_OPTION)
@@ -856,6 +934,20 @@ RTEXITCODE errorGetOpt(USAGECATEGORY fUsageCategory, int rc, union RTGETOPTUNION
}
/**
+ * errorSyntax for RTGetOpt users.
+ *
+ * @returns RTEXITCODE_SYNTAX.
+ *
+ * @param fUsageCategory The usage category of the command.
+ * @param rc The RTGetOpt return code.
+ * @param pValueUnion The value union.
+ */
+RTEXITCODE errorGetOpt(USAGECATEGORY fCategory, int rc, union RTGETOPTUNION const *pValueUnion)
+{
+ return errorGetOptEx(fCategory, ~0U, rc, pValueUnion);
+}
+
+/**
* Print an error message without the syntax stuff.
*
* @returns RTEXITCODE_SYNTAX.
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp
index 3b3aed79..26b87a7e 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageHostonly.cpp
@@ -23,8 +23,6 @@
#include <VBox/com/array.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
-
#include <VBox/com/VirtualBox.h>
#endif /* !VBOX_ONLY_DOCS */
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
index dd49dd94..789bc792 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -50,29 +50,41 @@ using namespace com;
HRESULT showSnapshots(ComPtr<ISnapshot> &rootSnapshot,
ComPtr<ISnapshot> &currentSnapshot,
VMINFO_DETAILS details,
- const Bstr &prefix /* = ""*/,
+ const Utf8Str &prefix /* = ""*/,
int level /*= 0*/)
{
/* start with the root */
Bstr name;
Bstr uuid;
- CHECK_ERROR2_RET(rootSnapshot,COMGETTER(Name)(name.asOutParam()), hrcCheck);
- CHECK_ERROR2_RET(rootSnapshot,COMGETTER(Id)(uuid.asOutParam()), hrcCheck);
+ Bstr description;
+ CHECK_ERROR2_RET(rootSnapshot, COMGETTER(Name)(name.asOutParam()), hrcCheck);
+ CHECK_ERROR2_RET(rootSnapshot, COMGETTER(Id)(uuid.asOutParam()), hrcCheck);
+ CHECK_ERROR2_RET(rootSnapshot, COMGETTER(Description)(description.asOutParam()), hrcCheck);
+ bool fCurrent = (rootSnapshot == currentSnapshot);
if (details == VMINFO_MACHINEREADABLE)
{
/* print with hierarchical numbering */
- RTPrintf("SnapshotName%ls=\"%ls\"\n", prefix.raw(), name.raw());
- RTPrintf("SnapshotUUID%ls=\"%s\"\n", prefix.raw(), Utf8Str(uuid).c_str());
+ RTPrintf("SnapshotName%s=\"%ls\"\n", prefix.c_str(), name.raw());
+ RTPrintf("SnapshotUUID%s=\"%s\"\n", prefix.c_str(), Utf8Str(uuid).c_str());
+ if (!description.isEmpty())
+ RTPrintf("SnapshotDescription%s=\"%ls\"\n", prefix.c_str(), description.raw());
+ if (fCurrent)
+ {
+ RTPrintf("CurrentSnapshotName=\"%ls\"\n", name.raw());
+ RTPrintf("CurrentSnapshotUUID=\"%s\"\n", Utf8Str(uuid).c_str());
+ RTPrintf("CurrentSnapshotNode=\"SnapshotName%s\"\n", prefix.c_str());
+ }
}
else
{
/* print with indentation */
- bool fCurrent = (rootSnapshot == currentSnapshot);
- RTPrintf(" %lsName: %ls (UUID: %s)%s\n",
- prefix.raw(),
+ RTPrintf(" %sName: %ls (UUID: %s)%s\n",
+ prefix.c_str(),
name.raw(),
Utf8Str(uuid).c_str(),
(fCurrent) ? " *" : "");
+ if (!description.isEmpty())
+ RTPrintf(" %sDescription:\n%ls\n", prefix.c_str(), description.raw());
}
/* get the children */
@@ -86,12 +98,12 @@ HRESULT showSnapshots(ComPtr<ISnapshot> &rootSnapshot,
ComPtr<ISnapshot> snapshot = coll[index];
if (snapshot)
{
- Bstr newPrefix;
+ Utf8Str newPrefix;
if (details == VMINFO_MACHINEREADABLE)
- newPrefix = Utf8StrFmt("%ls-%d", prefix.raw(), index + 1);
+ newPrefix = Utf8StrFmt("%s-%d", prefix.c_str(), index + 1);
else
{
- newPrefix = Utf8StrFmt("%ls ", prefix.raw());
+ newPrefix = Utf8StrFmt("%s ", prefix.c_str());
}
/* recursive call */
@@ -341,7 +353,7 @@ HRESULT showBandwidthGroups(ComPtr<IBandwidthControl> &bwCtrl,
HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
ComPtr<IMachine> machine,
VMINFO_DETAILS details /*= VMINFO_NONE*/,
- ComPtr<IConsole> console /*= ComPtr <IConsole> ()*/)
+ ComPtr<IConsole> console /*= ComPtr<IConsole> ()*/)
{
HRESULT rc;
@@ -534,7 +546,9 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
RTPrintf("Firmware: %s\n", pszFirmwareType);
SHOW_ULONG_PROP( machine, CPUCount, "cpus", "Number of CPUs", "");
- SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_Synthetic, &f), "synthcpu", "Synthetic Cpu");
+ SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_PAE, &f), "pae", "PAE");
+ SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_LongMode, &f), "longmode", "Long Mode");
+ SHOW_BOOLEAN_METHOD( machine, GetCPUProperty(CPUPropertyType_Synthetic, &f), "synthcpu", "Synthetic CPU");
if (details != VMINFO_MACHINEREADABLE)
RTPrintf("CPUID overrides: ");
@@ -565,7 +579,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
if (!cFound && details != VMINFO_MACHINEREADABLE)
RTPrintf("None\n");
- ComPtr <IBIOSSettings> biosSettings;
+ ComPtr<IBIOSSettings> biosSettings;
CHECK_ERROR2_RET(machine, COMGETTER(BIOSSettings)(biosSettings.asOutParam()), hrcCheck);
BIOSBootMenuMode_T bootMenuMode;
@@ -654,14 +668,13 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
SHOW_BOOLEAN_PROP(biosSettings, ACPIEnabled, "acpi", "ACPI");
SHOW_BOOLEAN_PROP(biosSettings, IOAPICEnabled, "ioapic", "IOAPIC");
- SHOW_BOOLEAN_METHOD(machine, GetCPUProperty(CPUPropertyType_PAE, &f), "pae", "PAE");
SHOW_LONG64_PROP(biosSettings, TimeOffset, "biossystemtimeoffset", "Time offset", "ms");
SHOW_BOOLEAN_PROP_EX(machine, RTCUseUTC, "rtcuseutc", "RTC", "UTC", "local time");
SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &f), "hwvirtex", "Hardw. virt.ext");
- SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_Exclusive, &f), "hwvirtexexcl", "Hardw. virt.ext exclusive");
SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &f),"nestedpaging", "Nested Paging");
SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &f), "largepages", "Large Pages");
SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_VPID, &f), "vtxvpid", "VT-x VPID");
+ SHOW_BOOLEAN_METHOD(machine, GetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, &f), "vtxux", "VT-x unr. exec.");
MachineState_T machineState;
CHECK_ERROR2_RET(machine, COMGETTER(State)(&machineState), hrcCheck);
@@ -700,6 +713,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
SHOW_STRING_PROP( machine, TracingConfig, "tracing-config", "Tracing Configuration");
SHOW_BOOLEAN_PROP( machine, AutostartEnabled, "autostart-enabled", "Autostart Enabled");
SHOW_ULONG_PROP( machine, AutostartDelay, "autostart-delay", "Autostart Delay", "");
+ SHOW_STRING_PROP( machine, DefaultFrontend, "defaultfrontend", "Default Frontend");
/** @todo Convert the remainder of the function to SHOW_XXX macros and add error
* checking where missing. */
@@ -1006,13 +1020,13 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
RTPrintf("natnet%d=\"%ls\"\n", currentNIC + 1, strNetwork.length() ? strNetwork.raw(): Bstr("nat").raw());
strAttachment = "nat";
strNatSettings = Utf8StrFmt("mtu=\"%d\"\nsockSnd=\"%d\"\nsockRcv=\"%d\"\ntcpWndSnd=\"%d\"\ntcpWndRcv=\"%d\"\n",
- mtu, sockSnd ? sockSnd : 64, sockRcv ? sockRcv : 64 , tcpSnd ? tcpSnd : 64, tcpRcv ? tcpRcv : 64);
+ mtu, sockSnd ? sockSnd : 64, sockRcv ? sockRcv : 64, tcpSnd ? tcpSnd : 64, tcpRcv ? tcpRcv : 64);
}
else
{
strAttachment = "NAT";
strNatSettings = Utf8StrFmt("NIC %d Settings: MTU: %d, Socket (send: %d, receive: %d), TCP Window (send:%d, receive: %d)\n",
- currentNIC + 1, mtu, sockSnd ? sockSnd : 64, sockRcv ? sockRcv : 64 , tcpSnd ? tcpSnd : 64, tcpRcv ? tcpRcv : 64);
+ currentNIC + 1, mtu, sockSnd ? sockSnd : 64, sockRcv ? sockRcv : 64, tcpSnd ? tcpSnd : 64, tcpRcv ? tcpRcv : 64);
}
break;
}
@@ -1058,6 +1072,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
strAttachment = Utf8StrFmt("Host-only Interface '%ls'", strHostonlyAdp.raw());
break;
}
+
case NetworkAttachmentType_Generic:
{
Bstr strGenericDriver;
@@ -1088,6 +1103,21 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
}
break;
}
+
+ case NetworkAttachmentType_NATNetwork:
+ {
+ Bstr strNetwork;
+ nic->COMGETTER(NATNetwork)(strNetwork.asOutParam());
+ if (details == VMINFO_MACHINEREADABLE)
+ {
+ RTPrintf("nat-network%d=\"%ls\"\n", currentNIC + 1, strNetwork.raw());
+ strAttachment = "natnetwork";
+ }
+ else
+ strAttachment = Utf8StrFmt("NAT Network '%s'", Utf8Str(strNetwork).c_str());
+ break;
+ }
+
default:
strAttachment = "unknown";
break;
@@ -1106,7 +1136,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
case NetworkAdapterPromiscModePolicy_Deny: pszPromiscuousGuestPolicy = "deny"; break;
case NetworkAdapterPromiscModePolicy_AllowNetwork: pszPromiscuousGuestPolicy = "allow-vms"; break;
case NetworkAdapterPromiscModePolicy_AllowAll: pszPromiscuousGuestPolicy = "allow-all"; break;
- default: AssertFailedReturn(VERR_INTERNAL_ERROR_4);
+ default: AssertFailedReturn(E_INVALIDARG);
}
/* trace stuff */
@@ -1203,6 +1233,10 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
pszHID = "USB Tablet and PS/2 Mouse";
pszMrHID = "combomouse";
break;
+ case PointingHIDType_USBMultiTouch:
+ pszHID = "USB Multi-Touch";
+ pszMrHID = "usbmultitouch";
+ break;
default:
break;
}
@@ -1553,7 +1587,24 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
if (details == VMINFO_MACHINEREADABLE)
RTPrintf("draganddrop=\"%s\"\n", psz);
else
- RTPrintf("Drag'n'drop Mode: %s\n", psz);
+ RTPrintf("Drag'n'drop Mode: %s\n", psz);
+ }
+
+ {
+ SessionState_T sessState;
+ rc = machine->COMGETTER(SessionState)(&sessState);
+ if (SUCCEEDED(rc) && sessState != SessionState_Unlocked)
+ {
+ Bstr sessType;
+ rc = machine->COMGETTER(SessionType)(sessType.asOutParam());
+ if (SUCCEEDED(rc) && !sessType.isEmpty())
+ {
+ if (details == VMINFO_MACHINEREADABLE)
+ RTPrintf("SessionType=\"%ls\"\n", sessType.raw());
+ else
+ RTPrintf("Session type: %ls\n", sessType.raw());
+ }
+ }
}
if (console)
@@ -1570,7 +1621,8 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
return rc;
}
ULONG xRes, yRes, bpp;
- rc = display->GetScreenResolution(0, &xRes, &yRes, &bpp);
+ LONG xOrigin, yOrigin;
+ rc = display->GetScreenResolution(0, &xRes, &yRes, &bpp, &xOrigin, &yOrigin);
if (rc == E_ACCESSDENIED)
break; /* VM not powered up */
if (FAILED(rc))
@@ -1580,9 +1632,9 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
return rc;
}
if (details == VMINFO_MACHINEREADABLE)
- RTPrintf("VideoMode=\"%d,%d,%d\"\n", xRes, yRes, bpp);
+ RTPrintf("VideoMode=\"%d,%d,%d\"@%d,%d\n", xRes, yRes, bpp, xOrigin, yOrigin);
else
- RTPrintf("Video mode: %dx%dx%d\n", xRes, yRes, bpp);
+ RTPrintf("Video mode: %dx%dx%d at %d,%d\n", xRes, yRes, bpp, xOrigin, yOrigin);
}
while (0);
}
@@ -1712,30 +1764,51 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
/*
* USB.
*/
- ComPtr<IUSBController> USBCtl;
- rc = machine->COMGETTER(USBController)(USBCtl.asOutParam());
+ SafeIfaceArray<IUSBController> USBCtlColl;
+ rc = machine->COMGETTER(USBControllers)(ComSafeArrayAsOutParam(USBCtlColl));
if (SUCCEEDED(rc))
{
- BOOL fEnabled;
- BOOL fEHCIEnabled;
- rc = USBCtl->COMGETTER(Enabled)(&fEnabled);
- if (FAILED(rc))
- fEnabled = false;
+ bool fOhciEnabled = false;
+ bool fEhciEnabled = false;
+
+ for (unsigned i = 0; i < USBCtlColl.size(); i++)
+ {
+ USBControllerType_T enmType;
+
+ rc = USBCtlColl[i]->COMGETTER(Type)(&enmType);
+ if (SUCCEEDED(rc))
+ {
+ switch (enmType)
+ {
+ case USBControllerType_OHCI:
+ fOhciEnabled = true;
+ break;
+ case USBControllerType_EHCI:
+ fEhciEnabled = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
if (details == VMINFO_MACHINEREADABLE)
- RTPrintf("usb=\"%s\"\n", fEnabled ? "on" : "off");
+ RTPrintf("usb=\"%s\"\n", fOhciEnabled ? "on" : "off");
else
- RTPrintf("USB: %s\n", fEnabled ? "enabled" : "disabled");
+ RTPrintf("USB: %s\n", fOhciEnabled ? "enabled" : "disabled");
- rc = USBCtl->COMGETTER(EnabledEHCI)(&fEHCIEnabled);
- if (FAILED(rc))
- fEHCIEnabled = false;
if (details == VMINFO_MACHINEREADABLE)
- RTPrintf("ehci=\"%s\"\n", fEHCIEnabled ? "on" : "off");
+ RTPrintf("ehci=\"%s\"\n", fEhciEnabled ? "on" : "off");
else
- RTPrintf("EHCI: %s\n", fEHCIEnabled ? "enabled" : "disabled");
+ RTPrintf("EHCI: %s\n", fEhciEnabled ? "enabled" : "disabled");
+ }
+ ComPtr<IUSBDeviceFilters> USBFlts;
+ rc = machine->COMGETTER(USBDeviceFilters)(USBFlts.asOutParam());
+ if (SUCCEEDED(rc))
+ {
SafeIfaceArray <IUSBDeviceFilter> Coll;
- rc = USBCtl->COMGETTER(DeviceFilters)(ComSafeArrayAsOutParam(Coll));
+ rc = USBFlts->COMGETTER(DeviceFilters)(ComSafeArrayAsOutParam(Coll));
if (SUCCEEDED(rc))
{
if (details != VMINFO_MACHINEREADABLE)
@@ -1836,7 +1909,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
{
for (size_t index = 0; index < coll.size(); ++index)
{
- ComPtr <IHostUSBDevice> dev = coll[index];
+ ComPtr<IHostUSBDevice> dev = coll[index];
/* Query info. */
Bstr id;
@@ -1925,7 +1998,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
{
for (size_t index = 0; index < coll.size(); ++index)
{
- ComPtr <IUSBDevice> dev = coll[index];
+ ComPtr<IUSBDevice> dev = coll[index];
/* Query info. */
Bstr id;
@@ -2082,7 +2155,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
for (size_t i = 0; i < folders.size(); ++i)
{
- ComPtr <ISharedFolder> sf = folders[i];
+ ComPtr<ISharedFolder> sf = folders[i];
Bstr name, hostPath;
BOOL writable;
@@ -2113,7 +2186,7 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
for (size_t i = 0; i < folders.size(); ++i)
{
- ComPtr <ISharedFolder> sf = folders[i];
+ ComPtr<ISharedFolder> sf = folders[i];
Bstr name, hostPath;
sf->COMGETTER(Name)(name.asOutParam());
@@ -2269,6 +2342,60 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
RTPrintf("\n");
}
+ {
+ /* Video capture */
+ BOOL bActive = FALSE;
+ CHECK_ERROR_RET(machine, COMGETTER(VideoCaptureEnabled)(&bActive), rc);
+ com::SafeArray<BOOL> screens;
+ CHECK_ERROR_RET(machine, COMGETTER(VideoCaptureScreens)(ComSafeArrayAsOutParam(screens)), rc);
+ ULONG Width;
+ CHECK_ERROR_RET(machine, COMGETTER(VideoCaptureWidth)(&Width), rc);
+ ULONG Height;
+ CHECK_ERROR_RET(machine, COMGETTER(VideoCaptureHeight)(&Height), rc);
+ ULONG Rate;
+ CHECK_ERROR_RET(machine, COMGETTER(VideoCaptureRate)(&Rate), rc);
+ ULONG Fps;
+ CHECK_ERROR_RET(machine, COMGETTER(VideoCaptureFPS)(&Fps), rc);
+ Bstr File;
+ CHECK_ERROR_RET(machine, COMGETTER(VideoCaptureFile)(File.asOutParam()), rc);
+ if (details == VMINFO_MACHINEREADABLE)
+ {
+ RTPrintf("vcpenabled=\"%s\"\n", bActive ? "on" : "off");
+ RTPrintf("vcpscreens=");
+ bool fComma = false;
+ for (unsigned i = 0; i < screens.size(); i++)
+ if (screens[i])
+ {
+ RTPrintf("%s%u", fComma ? "," : "", i);
+ fComma = true;
+ }
+ RTPrintf("\n");
+ RTPrintf("vcpfile=\"%ls\"\n", File.raw());
+ RTPrintf("vcpwidth=%u\n", (unsigned)Width);
+ RTPrintf("vcpheight=%u\n", (unsigned)Height);
+ RTPrintf("vcprate=%u\n", (unsigned)Rate);
+ RTPrintf("vcpfps=%u\n", (unsigned)Fps);
+ }
+ else
+ {
+ RTPrintf("Video capturing: %s\n", bActive ? "active" : "not active");
+ RTPrintf("Capture screens: ");
+ bool fComma = false;
+ for (unsigned i = 0; i < screens.size(); i++)
+ if (screens[i])
+ {
+ RTPrintf("%s%u", fComma ? "," : "", i);
+ fComma = true;
+ }
+ RTPrintf("\n");
+ RTPrintf("Capture file: %ls\n", File.raw());
+ RTPrintf("Capture dimensions: %ux%u\n", Width, Height);
+ RTPrintf("Capture rate: %u kbps\n", Rate);
+ RTPrintf("Capture FPS: %u\n", Fps);
+ RTPrintf("\n");
+ }
+ }
+
if ( details == VMINFO_STANDARD
|| details == VMINFO_FULL
|| details == VMINFO_MACHINEREADABLE)
@@ -2284,7 +2411,6 @@ HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
}
}
-
if (details != VMINFO_MACHINEREADABLE)
RTPrintf("Guest:\n\n");
@@ -2479,7 +2605,7 @@ int handleShowVMInfo(HandlerArg *a)
return errorSyntax(USAGE_SHOWVMINFO, "VM name or UUID required");
/* try to find the given machine */
- ComPtr <IMachine> machine;
+ ComPtr<IMachine> machine;
CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMNameOrUuid).raw(),
machine.asOutParam()));
if (FAILED(rc))
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageList.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageList.cpp
index b98e2e04..ce7a7619 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageList.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageList.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -75,10 +75,31 @@ static const char*getDeviceTypeText(DeviceType_T enmType)
/**
+ * List internal networks.
+ *
+ * @returns See produceList.
+ * @param pVirtualBox Reference to the IVirtualBox smart pointer.
+ */
+static HRESULT listInternalNetworks(const ComPtr<IVirtualBox> pVirtualBox)
+{
+ HRESULT rc;
+ com::SafeArray<BSTR> internalNetworks;
+ CHECK_ERROR(pVirtualBox, COMGETTER(InternalNetworks)(ComSafeArrayAsOutParam(internalNetworks)));
+ for (size_t i = 0; i < internalNetworks.size(); ++i)
+ {
+ RTPrintf("Name: %ls\n", internalNetworks[i]);
+ }
+ return rc;
+}
+
+
+/**
* List network interfaces information (bridged/host only).
*
* @returns See produceList.
* @param pVirtualBox Reference to the IVirtualBox smart pointer.
+ * @param fIsBridged Selects between listing host interfaces (for
+ * use with bridging) or host only interfaces.
*/
static HRESULT listNetworkInterfaces(const ComPtr<IVirtualBox> pVirtualBox,
bool fIsBridged)
@@ -174,6 +195,12 @@ static HRESULT listHostInfo(const ComPtr<IVirtualBox> pVirtualBox)
ULONG processorCount = 0;
CHECK_ERROR(Host, COMGETTER(ProcessorCount)(&processorCount));
RTPrintf("Processor count: %lu\n", processorCount);
+ ULONG processorOnlineCoreCount = 0;
+ CHECK_ERROR(Host, COMGETTER(ProcessorOnlineCoreCount)(&processorOnlineCoreCount));
+ RTPrintf("Processor online core count: %lu\n", processorOnlineCoreCount);
+ ULONG processorCoreCount = 0;
+ CHECK_ERROR(Host, COMGETTER(ProcessorCoreCount)(&processorCoreCount));
+ RTPrintf("Processor core count: %lu\n", processorCoreCount);
ULONG processorSpeed = 0;
Bstr processorDescription;
for (ULONG i = 0; i < processorCount; i++)
@@ -182,7 +209,7 @@ static HRESULT listHostInfo(const ComPtr<IVirtualBox> pVirtualBox)
if (processorSpeed)
RTPrintf("Processor#%u speed: %lu MHz\n", i, processorSpeed);
else
- RTPrintf("Processor#%u speed: unknown\n", i, processorSpeed);
+ RTPrintf("Processor#%u speed: unknown\n", i);
CHECK_ERROR(Host, GetProcessorDescription(i, processorDescription.asOutParam()));
RTPrintf("Processor#%u description: %ls\n", i, processorDescription.raw());
}
@@ -211,118 +238,33 @@ static HRESULT listHostInfo(const ComPtr<IVirtualBox> pVirtualBox)
*
* @returns See produceList.
* @param pVirtualBox Reference to the IVirtualBox smart pointer.
+ * @param aMedia Medium objects to list information for.
+ * @param pszParentUUIDStr String with the parent UUID string (or "base").
+ * @param fOptLong Long (@c true) or short list format.
*/
static HRESULT listMedia(const ComPtr<IVirtualBox> pVirtualBox,
const com::SafeIfaceArray<IMedium> &aMedia,
- const char *pszParentUUIDStr)
+ const char *pszParentUUIDStr,
+ bool fOptLong)
{
HRESULT rc = S_OK;
for (size_t i = 0; i < aMedia.size(); ++i)
{
ComPtr<IMedium> pMedium = aMedia[i];
- Bstr uuid;
- pMedium->COMGETTER(Id)(uuid.asOutParam());
- RTPrintf("UUID: %s\n", Utf8Str(uuid).c_str());
- if (pszParentUUIDStr)
- RTPrintf("Parent UUID: %s\n", pszParentUUIDStr);
- Bstr format;
- pMedium->COMGETTER(Format)(format.asOutParam());
- RTPrintf("Format: %ls\n", format.raw());
- Bstr filepath;
- pMedium->COMGETTER(Location)(filepath.asOutParam());
- RTPrintf("Location: %ls\n", filepath.raw());
-
- MediumState_T enmState;
- pMedium->RefreshState(&enmState);
- const char *stateStr = "unknown";
- switch (enmState)
- {
- case MediumState_NotCreated:
- stateStr = "not created";
- break;
- case MediumState_Created:
- stateStr = "created";
- break;
- case MediumState_LockedRead:
- stateStr = "locked read";
- break;
- case MediumState_LockedWrite:
- stateStr = "locked write";
- break;
- case MediumState_Inaccessible:
- stateStr = "inaccessible";
- break;
- case MediumState_Creating:
- stateStr = "creating";
- break;
- case MediumState_Deleting:
- stateStr = "deleting";
- break;
- }
- RTPrintf("State: %s\n", stateStr);
- MediumType_T type;
- pMedium->COMGETTER(Type)(&type);
- const char *typeStr = "unknown";
- switch (type)
- {
- case MediumType_Normal:
- typeStr = "normal";
- break;
- case MediumType_Immutable:
- typeStr = "immutable";
- break;
- case MediumType_Writethrough:
- typeStr = "writethrough";
- break;
- case MediumType_Shareable:
- typeStr = "shareable";
- break;
- case MediumType_Readonly:
- typeStr = "readonly";
- break;
- case MediumType_MultiAttach:
- typeStr = "multiattach";
- break;
- }
- RTPrintf("Type: %s\n", typeStr);
+ rc = showMediumInfo(pVirtualBox, pMedium, pszParentUUIDStr, fOptLong);
- com::SafeArray<BSTR> machineIds;
- pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
- for (size_t j = 0; j < machineIds.size(); ++j)
- {
- ComPtr<IMachine> machine;
- CHECK_ERROR(pVirtualBox, FindMachine(machineIds[j], machine.asOutParam()));
- ASSERT(machine);
- Bstr name;
- machine->COMGETTER(Name)(name.asOutParam());
- RTPrintf("%s%ls (UUID: %ls)",
- j == 0 ? "Usage: " : " ",
- name.raw(), machineIds[j]);
- com::SafeArray<BSTR> snapshotIds;
- pMedium->GetSnapshotIds(machineIds[j],
- ComSafeArrayAsOutParam(snapshotIds));
- for (size_t k = 0; k < snapshotIds.size(); ++k)
- {
- ComPtr<ISnapshot> snapshot;
- machine->FindSnapshot(snapshotIds[k], snapshot.asOutParam());
- if (snapshot)
- {
- Bstr snapshotName;
- snapshot->COMGETTER(Name)(snapshotName.asOutParam());
- RTPrintf(" [%ls (UUID: %ls)]", snapshotName.raw(), snapshotIds[k]);
- }
- }
- RTPrintf("\n");
- }
RTPrintf("\n");
com::SafeIfaceArray<IMedium> children;
CHECK_ERROR(pMedium, COMGETTER(Children)(ComSafeArrayAsOutParam(children)));
if (children.size() > 0)
{
+ Bstr uuid;
+ pMedium->COMGETTER(Id)(uuid.asOutParam());
+
// depth first listing of child media
- rc = listMedia(pVirtualBox, children, Utf8Str(uuid).c_str());
+ rc = listMedia(pVirtualBox, children, Utf8Str(uuid).c_str(), fOptLong);
}
}
@@ -353,18 +295,22 @@ static HRESULT listHddBackends(const ComPtr<IVirtualBox> pVirtualBox)
Bstr description;
CHECK_ERROR(mediumFormats[i],
- COMGETTER(Id)(description.asOutParam()));
+ COMGETTER(Name)(description.asOutParam()));
- ULONG caps;
+ ULONG caps = 0;
+ com::SafeArray <MediumFormatCapabilities_T> mediumFormatCap;
CHECK_ERROR(mediumFormats[i],
- COMGETTER(Capabilities)(&caps));
+ COMGETTER(Capabilities)(ComSafeArrayAsOutParam(mediumFormatCap)));
+ for (ULONG j = 0; j < mediumFormatCap.size(); j++)
+ caps |= mediumFormatCap[j];
+
RTPrintf("Backend %u: id='%ls' description='%ls' capabilities=%#06x extensions='",
i, id.raw(), description.raw(), caps);
/* File extensions */
- com::SafeArray <BSTR> fileExtensions;
- com::SafeArray <DeviceType_T> deviceTypes;
+ com::SafeArray<BSTR> fileExtensions;
+ com::SafeArray<DeviceType_T> deviceTypes;
CHECK_ERROR(mediumFormats[i],
DescribeFileExtensions(ComSafeArrayAsOutParam(fileExtensions), ComSafeArrayAsOutParam(deviceTypes)));
for (size_t j = 0; j < fileExtensions.size(); ++j)
@@ -376,11 +322,11 @@ static HRESULT listHddBackends(const ComPtr<IVirtualBox> pVirtualBox)
RTPrintf("'");
/* Configuration keys */
- com::SafeArray <BSTR> propertyNames;
- com::SafeArray <BSTR> propertyDescriptions;
- com::SafeArray <DataType_T> propertyTypes;
- com::SafeArray <ULONG> propertyFlags;
- com::SafeArray <BSTR> propertyDefaults;
+ com::SafeArray<BSTR> propertyNames;
+ com::SafeArray<BSTR> propertyDescriptions;
+ com::SafeArray<DataType_T> propertyTypes;
+ com::SafeArray<ULONG> propertyFlags;
+ com::SafeArray<BSTR> propertyDefaults;
CHECK_ERROR(mediumFormats[i],
DescribeProperties(ComSafeArrayAsOutParam(propertyNames),
ComSafeArrayAsOutParam(propertyDescriptions),
@@ -438,7 +384,7 @@ static HRESULT listUsbHost(const ComPtr<IVirtualBox> &pVirtualBox)
{
for (size_t i = 0; i < CollPtr.size(); ++i)
{
- ComPtr <IHostUSBDevice> dev = CollPtr[i];
+ ComPtr<IHostUSBDevice> dev = CollPtr[i];
/* Query info. */
Bstr id;
@@ -605,6 +551,7 @@ static HRESULT listSystemProperties(const ComPtr<IVirtualBox> &pVirtualBox)
Bstr str;
ULONG ulValue;
LONG64 i64Value;
+ BOOL fValue;
pVirtualBox->COMGETTER(APIVersion)(str.asOutParam());
RTPrintf("API version: %ls\n", str.raw());
@@ -617,6 +564,8 @@ static HRESULT listSystemProperties(const ComPtr<IVirtualBox> &pVirtualBox)
RTPrintf("Minimum video RAM size: %u Megabytes\n", ulValue);
systemProperties->COMGETTER(MaxGuestVRAM)(&ulValue);
RTPrintf("Maximum video RAM size: %u Megabytes\n", ulValue);
+ systemProperties->COMGETTER(MaxGuestMonitors)(&ulValue);
+ RTPrintf("Maximum guest monitor count: %u\n", ulValue);
systemProperties->COMGETTER(MinGuestCPUCount)(&ulValue);
RTPrintf("Minimum guest CPU count: %u\n", ulValue);
systemProperties->COMGETTER(MaxGuestCPUCount)(&ulValue);
@@ -673,8 +622,22 @@ static HRESULT listSystemProperties(const ComPtr<IVirtualBox> &pVirtualBox)
RTPrintf("Maximum Floppy Port count: %u\n", ulValue);
systemProperties->GetMaxDevicesPerPortForStorageBus(StorageBus_Floppy, &ulValue);
RTPrintf("Maximum Devices per Floppy Port: %u\n", ulValue);
+#if 0
+ systemProperties->GetFreeDiskSpaceWarning(&i64Value);
+ RTPrintf("Free disk space warning at: %u Bytes\n", i64Value);
+ systemProperties->GetFreeDiskSpacePercentWarning(&ulValue);
+ RTPrintf("Free disk space warning at: %u %%\n", ulValue);
+ systemProperties->GetFreeDiskSpaceError(&i64Value);
+ RTPrintf("Free disk space error at: %u Bytes\n", i64Value);
+ systemProperties->GetFreeDiskSpacePercentError(&ulValue);
+ RTPrintf("Free disk space error at: %u %%\n", ulValue);
+#endif
systemProperties->COMGETTER(DefaultMachineFolder)(str.asOutParam());
RTPrintf("Default machine folder: %ls\n", str.raw());
+ systemProperties->COMGETTER(ExclusiveHwVirt)(&fValue);
+ RTPrintf("Exclusive HW virtualization use: %ls\n", fValue ? L"on" : L"off");
+ systemProperties->COMGETTER(DefaultHardDiskFormat)(str.asOutParam());
+ RTPrintf("Default hard disk format: %ls\n", str.raw());
systemProperties->COMGETTER(VRDEAuthLibrary)(str.asOutParam());
RTPrintf("VRDE auth library: %ls\n", str.raw());
systemProperties->COMGETTER(WebServiceAuthLibrary)(str.asOutParam());
@@ -683,6 +646,8 @@ static HRESULT listSystemProperties(const ComPtr<IVirtualBox> &pVirtualBox)
RTPrintf("Remote desktop ExtPack: %ls\n", str.raw());
systemProperties->COMGETTER(LogHistoryCount)(&ulValue);
RTPrintf("Log history count: %u\n", ulValue);
+ systemProperties->COMGETTER(DefaultFrontend)(str.asOutParam());
+ RTPrintf("Default frontend: %ls\n", str.raw());
systemProperties->COMGETTER(AutostartDatabasePath)(str.asOutParam());
RTPrintf("Autostart database path: %ls\n", str.raw());
systemProperties->COMGETTER(DefaultAdditionsISO)(str.asOutParam());
@@ -773,6 +738,35 @@ static HRESULT listGroups(const ComPtr<IVirtualBox> &pVirtualBox)
/**
+ * List video capture devices.
+ *
+ * @returns See produceList.
+ * @param pVirtualBox Reference to the IVirtualBox pointer.
+ */
+static HRESULT listVideoInputDevices(const ComPtr<IVirtualBox> pVirtualBox)
+{
+ HRESULT rc;
+ ComPtr<IHost> host;
+ CHECK_ERROR(pVirtualBox, COMGETTER(Host)(host.asOutParam()));
+ com::SafeIfaceArray<IHostVideoInputDevice> hostVideoInputDevices;
+ CHECK_ERROR(host, COMGETTER(VideoInputDevices)(ComSafeArrayAsOutParam(hostVideoInputDevices)));
+ RTPrintf("Video Input Devices: %u\n", hostVideoInputDevices.size());
+ for (size_t i = 0; i < hostVideoInputDevices.size(); ++i)
+ {
+ ComPtr<IHostVideoInputDevice> p = hostVideoInputDevices[i];
+ Bstr name;
+ p->COMGETTER(Name)(name.asOutParam());
+ Bstr path;
+ p->COMGETTER(Path)(path.asOutParam());
+ Bstr alias;
+ p->COMGETTER(Alias)(alias.asOutParam());
+ RTPrintf("%ls \"%ls\"\n%ls\n", alias.raw(), name.raw(), path.raw());
+ }
+ return rc;
+}
+
+
+/**
* The type of lists we can produce.
*/
enum enmListType
@@ -783,6 +777,7 @@ enum enmListType
kListOsTypes,
kListHostDvds,
kListHostFloppies,
+ kListInternalNetworks,
kListBridgedInterfaces,
#if defined(VBOX_WITH_NETFLT)
kListHostOnlyInterfaces,
@@ -798,7 +793,9 @@ enum enmListType
kListSystemProperties,
kListDhcpServers,
kListExtPacks,
- kListGroups
+ kListGroups,
+ kListNatNetworks,
+ kListVideoInputDevices
};
@@ -954,6 +951,10 @@ static HRESULT produceList(enum enmListType enmCommand, bool fOptLong, const Com
break;
}
+ case kListInternalNetworks:
+ rc = listInternalNetworks(pVirtualBox);
+ break;
+
case kListBridgedInterfaces:
#if defined(VBOX_WITH_NETFLT)
case kListHostOnlyInterfaces:
@@ -1002,7 +1003,7 @@ static HRESULT produceList(enum enmListType enmCommand, bool fOptLong, const Com
{
com::SafeIfaceArray<IMedium> hdds;
CHECK_ERROR(pVirtualBox, COMGETTER(HardDisks)(ComSafeArrayAsOutParam(hdds)));
- rc = listMedia(pVirtualBox, hdds, "base");
+ rc = listMedia(pVirtualBox, hdds, "base", fOptLong);
break;
}
@@ -1010,7 +1011,7 @@ static HRESULT produceList(enum enmListType enmCommand, bool fOptLong, const Com
{
com::SafeIfaceArray<IMedium> dvds;
CHECK_ERROR(pVirtualBox, COMGETTER(DVDImages)(ComSafeArrayAsOutParam(dvds)));
- rc = listMedia(pVirtualBox, dvds, NULL);
+ rc = listMedia(pVirtualBox, dvds, NULL, fOptLong);
break;
}
@@ -1018,7 +1019,7 @@ static HRESULT produceList(enum enmListType enmCommand, bool fOptLong, const Com
{
com::SafeIfaceArray<IMedium> floppies;
CHECK_ERROR(pVirtualBox, COMGETTER(FloppyImages)(ComSafeArrayAsOutParam(floppies)));
- rc = listMedia(pVirtualBox, floppies, NULL);
+ rc = listMedia(pVirtualBox, floppies, NULL, fOptLong);
break;
}
@@ -1072,6 +1073,66 @@ static HRESULT produceList(enum enmListType enmCommand, bool fOptLong, const Com
rc = listGroups(pVirtualBox);
break;
+ case kListNatNetworks:
+ {
+ com::SafeIfaceArray<INATNetwork> nets;
+ CHECK_ERROR(pVirtualBox, COMGETTER(NATNetworks)(ComSafeArrayAsOutParam(nets)));
+ for (size_t i = 0; i < nets.size(); ++i)
+ {
+ ComPtr<INATNetwork> net = nets[i];
+ Bstr netName;
+ net->COMGETTER(NetworkName)(netName.asOutParam());
+ RTPrintf("NetworkName: %ls\n", netName.raw());
+ Bstr gateway;
+ net->COMGETTER(Gateway)(gateway.asOutParam());
+ RTPrintf("IP: %ls\n", gateway.raw());
+ Bstr network;
+ net->COMGETTER(Network)(network.asOutParam());
+ RTPrintf("Network: %ls\n", network.raw());
+ BOOL fEnabled;
+ net->COMGETTER(IPv6Enabled)(&fEnabled);
+ RTPrintf("IPv6 Enabled: %s\n", fEnabled ? "Yes" : "No");
+ Bstr ipv6prefix;
+ net->COMGETTER(Network)(network.asOutParam());
+ RTPrintf("IPv6 Prefix: %ls\n", ipv6prefix.raw());
+ net->COMGETTER(NeedDhcpServer)(&fEnabled);
+ RTPrintf("DHCP Enabled: %s\n", fEnabled ? "Yes" : "No");
+ net->COMGETTER(Enabled)(&fEnabled);
+ RTPrintf("Enabled: %s\n", fEnabled ? "Yes" : "No");
+
+#define PRINT_STRING_ARRAY(title) \
+ if (strs.size() > 0) \
+ { \
+ RTPrintf(title); \
+ size_t j = 0; \
+ for (;j < strs.size(); ++j) \
+ RTPrintf(" %s\n", Utf8Str(strs[j]).c_str()); \
+ }
+
+ com::SafeArray<BSTR> strs;
+
+ CHECK_ERROR(nets[i], COMGETTER(PortForwardRules4)(ComSafeArrayAsOutParam(strs)));
+ PRINT_STRING_ARRAY("Port-forwarding (ipv4)\n");
+ strs.setNull();
+
+ CHECK_ERROR(nets[i], COMGETTER(PortForwardRules6)(ComSafeArrayAsOutParam(strs)));
+ PRINT_STRING_ARRAY("Port-forwarding (ipv6)\n");
+ strs.setNull();
+
+ CHECK_ERROR(nets[i], COMGETTER(LocalMappings)(ComSafeArrayAsOutParam(strs)));
+ PRINT_STRING_ARRAY("loopback mappings (ipv4)\n");
+ strs.setNull();
+
+#undef PRINT_STRING_ARRAY
+ RTPrintf("\n");
+ }
+ break;
+ }
+
+ case kListVideoInputDevices:
+ rc = listVideoInputDevices(pVirtualBox);
+ break;
+
/* No default here, want gcc warnings. */
} /* end switch */
@@ -1100,11 +1161,14 @@ int handleList(HandlerArg *a)
{ "ostypes", kListOsTypes, RTGETOPT_REQ_NOTHING },
{ "hostdvds", kListHostDvds, RTGETOPT_REQ_NOTHING },
{ "hostfloppies", kListHostFloppies, RTGETOPT_REQ_NOTHING },
+ { "intnets", kListInternalNetworks, RTGETOPT_REQ_NOTHING },
{ "hostifs", kListBridgedInterfaces, RTGETOPT_REQ_NOTHING }, /* backward compatibility */
{ "bridgedifs", kListBridgedInterfaces, RTGETOPT_REQ_NOTHING },
#if defined(VBOX_WITH_NETFLT)
{ "hostonlyifs", kListHostOnlyInterfaces, RTGETOPT_REQ_NOTHING },
#endif
+ { "natnetworks", kListNatNetworks, RTGETOPT_REQ_NOTHING },
+ { "natnets", kListNatNetworks, RTGETOPT_REQ_NOTHING },
{ "hostinfo", kListHostInfo, RTGETOPT_REQ_NOTHING },
{ "hostcpuids", kListHostCpuIDs, RTGETOPT_REQ_NOTHING },
{ "hddbackends", kListHddBackends, RTGETOPT_REQ_NOTHING },
@@ -1117,6 +1181,7 @@ int handleList(HandlerArg *a)
{ "dhcpservers", kListDhcpServers, RTGETOPT_REQ_NOTHING },
{ "extpacks", kListExtPacks, RTGETOPT_REQ_NOTHING },
{ "groups", kListGroups, RTGETOPT_REQ_NOTHING },
+ { "webcams", kListVideoInputDevices, RTGETOPT_REQ_NOTHING },
};
int ch;
@@ -1144,6 +1209,7 @@ int handleList(HandlerArg *a)
case kListOsTypes:
case kListHostDvds:
case kListHostFloppies:
+ case kListInternalNetworks:
case kListBridgedInterfaces:
#if defined(VBOX_WITH_NETFLT)
case kListHostOnlyInterfaces:
@@ -1160,6 +1226,8 @@ int handleList(HandlerArg *a)
case kListDhcpServers:
case kListExtPacks:
case kListGroups:
+ case kListNatNetworks:
+ case kListVideoInputDevices:
enmOptCommand = (enum enmListType)ch;
if (fOptMultiple)
{
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageMetrics.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageMetrics.cpp
index 86b23b65..fa6b4942 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageMetrics.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageMetrics.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -77,7 +77,7 @@ static int parseFilterParameters(int argc, char *argv[],
}
else
{
- ComPtr <IMachine> machine;
+ ComPtr<IMachine> machine;
rc = aVirtualBox->FindMachine(Bstr(argv[0]).raw(),
machine.asOutParam());
if (SUCCEEDED (rc))
@@ -103,11 +103,18 @@ static int parseFilterParameters(int argc, char *argv[],
static Bstr toBaseName(Utf8Str& aFullName)
{
char *pszRaw = aFullName.mutableRaw();
- char *pszSlash = strrchr(pszRaw, '/');
- if (pszSlash)
+ /*
+ * Currently there are two metrics which base name is the same as the
+ * sub-metric name: CPU/MHz and Net/<iface>/LinkSpeed.
+ */
+ if (strcmp(pszRaw, "CPU/MHz") && !RTStrSimplePatternMatch("Net/*/LinkSpeed", pszRaw))
{
- *pszSlash = 0;
- aFullName.jolt();
+ char *pszSlash = strrchr(pszRaw, '/');
+ if (pszSlash)
+ {
+ *pszSlash = 0;
+ aFullName.jolt();
+ }
}
return Bstr(aFullName);
}
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
index cc71cb04..a1158dd5 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -26,8 +26,6 @@
# include <VBox/com/array.h>
# include <VBox/com/ErrorInfo.h>
# include <VBox/com/errorprint.h>
-# include <VBox/com/EventQueue.h>
-
# include <VBox/com/VirtualBox.h>
#endif /* !VBOX_ONLY_DOCS */
@@ -155,18 +153,32 @@ int handleUnregisterVM(HandlerArg *a)
machine.asOutParam()),
RTEXITCODE_FAILURE);
SafeIfaceArray<IMedium> aMedia;
- CHECK_ERROR_RET(machine, Unregister(fDelete ? (CleanupMode_T)CleanupMode_DetachAllReturnHardDisksOnly : (CleanupMode_T)CleanupMode_DetachAllReturnNone,
+ CHECK_ERROR_RET(machine, Unregister(CleanupMode_DetachAllReturnHardDisksOnly,
ComSafeArrayAsOutParam(aMedia)),
RTEXITCODE_FAILURE);
if (fDelete)
{
ComPtr<IProgress> pProgress;
- CHECK_ERROR_RET(machine, Delete(ComSafeArrayAsInParam(aMedia), pProgress.asOutParam()),
+ CHECK_ERROR_RET(machine, DeleteConfig(ComSafeArrayAsInParam(aMedia), pProgress.asOutParam()),
RTEXITCODE_FAILURE);
rc = showProgress(pProgress);
CHECK_PROGRESS_ERROR_RET(pProgress, ("Machine delete failed"), RTEXITCODE_FAILURE);
}
+ else
+ {
+ /* Note that the IMachine::Unregister method will return the medium
+ * reference in a sane order, which means that closing will normally
+ * succeed, unless there is still another machine which uses the
+ * medium. No harm done if we ignore the error. */
+ for (size_t i = 0; i < aMedia.size(); i++)
+ {
+ IMedium *pMedium = aMedia[i];
+ if (pMedium)
+ rc = pMedium->Close();
+ }
+ rc = S_OK;
+ }
return RTEXITCODE_SUCCESS;
}
@@ -485,7 +497,7 @@ int handleStartVM(HandlerArg *a)
{
HRESULT rc = S_OK;
std::list<const char *> VMs;
- Bstr sessionType = "gui";
+ Bstr sessionType;
static const RTGETOPTDEF s_aStartVMOptions[] =
{
@@ -825,6 +837,18 @@ int handleSetProperty(HandlerArg *a)
else
CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(a->argv[1]).raw()));
}
+ else if (!strcmp(a->argv[0], "hwvirtexclusive"))
+ {
+ bool fHwVirtExclusive;
+
+ if (!strcmp(a->argv[1], "on"))
+ fHwVirtExclusive = true;
+ else if (!strcmp(a->argv[1], "off"))
+ fHwVirtExclusive = false;
+ else
+ return errorArgument("Invalid hwvirtexclusive argument '%s'", a->argv[1]);
+ CHECK_ERROR(systemProperties, COMSETTER(ExclusiveHwVirt)(fHwVirtExclusive));
+ }
else if ( !strcmp(a->argv[0], "vrdeauthlibrary")
|| !strcmp(a->argv[0], "vrdpauthlibrary"))
{
@@ -870,6 +894,13 @@ int handleSetProperty(HandlerArg *a)
else
CHECK_ERROR(systemProperties, COMSETTER(AutostartDatabasePath)(Bstr(a->argv[1]).raw()));
}
+ else if (!strcmp(a->argv[0], "defaultfrontend"))
+ {
+ Bstr bstrDefaultFrontend(a->argv[1]);
+ if (!strcmp(a->argv[1], "default"))
+ bstrDefaultFrontend.setNull();
+ CHECK_ERROR(systemProperties, COMSETTER(DefaultFrontend)(bstrDefaultFrontend.raw()));
+ }
else
return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
@@ -950,7 +981,7 @@ int handleSharedFolder(HandlerArg *a)
if (fTransient)
{
- ComPtr <IConsole> console;
+ ComPtr<IConsole> console;
/* open an existing session for the VM */
CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
@@ -1016,7 +1047,7 @@ int handleSharedFolder(HandlerArg *a)
if (fTransient)
{
- ComPtr <IConsole> console;
+ ComPtr<IConsole> console;
/* open an existing session for the VM */
CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
index 6d57035d..d7515fc7 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageModifyVM.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2012 Oracle Corporation
+ * Copyright (C) 2006-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;
@@ -23,8 +23,6 @@
#include <VBox/com/array.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
-
#include <VBox/com/VirtualBox.h>
#endif /* !VBOX_ONLY_DOCS */
@@ -50,7 +48,9 @@ enum
{
MODIFYVM_NAME = 1000,
MODIFYVM_GROUPS,
+ MODIFYVM_DESCRIPTION,
MODIFYVM_OSTYPE,
+ MODIFYVM_ICONFILE,
MODIFYVM_MEMORY,
MODIFYVM_PAGEFUSION,
MODIFYVM_VRAM,
@@ -58,12 +58,14 @@ enum
MODIFYVM_ACPI,
MODIFYVM_IOAPIC,
MODIFYVM_PAE,
+ MODIFYVM_LONGMODE,
MODIFYVM_SYNTHCPU,
+ MODIFYVM_TFRESET,
MODIFYVM_HWVIRTEX,
- MODIFYVM_HWVIRTEXEXCLUSIVE,
MODIFYVM_NESTEDPAGING,
MODIFYVM_LARGEPAGES,
MODIFYVM_VTXVPID,
+ MODIFYVM_VTXUX,
MODIFYVM_CPUS,
MODIFYVM_CPUHOTPLUG,
MODIFYVM_PLUGCPU,
@@ -71,6 +73,7 @@ enum
MODIFYVM_SETCPUID,
MODIFYVM_DELCPUID,
MODIFYVM_DELALLCPUID,
+ MODIFYVM_GRAPHICSCONTROLLER,
MODIFYVM_MONITORCOUNT,
MODIFYVM_ACCELERATE3D,
#ifdef VBOX_WITH_VIDEOHWACCEL
@@ -110,8 +113,9 @@ enum
MODIFYVM_BRIDGEADAPTER,
MODIFYVM_HOSTONLYADAPTER,
MODIFYVM_INTNET,
- MODIFYVM_NATNET,
MODIFYVM_GENERICDRV,
+ MODIFYVM_NATNETWORKNAME,
+ MODIFYVM_NATNET,
MODIFYVM_NATBINDIP,
MODIFYVM_NATSETTINGS,
MODIFYVM_NATPF,
@@ -187,20 +191,26 @@ enum
#ifdef VBOX_WITH_USB_CARDREADER
MODIFYVM_USBCARDREADER,
#endif
- MODIFYVM_CHIPSET,
#ifdef VBOX_WITH_VPX
MODIFYVM_VCP,
+ MODIFYVM_VCP_SCREENS,
MODIFYVM_VCP_FILENAME,
MODIFYVM_VCP_WIDTH,
- MODIFYVM_VCP_HEIGHT
+ MODIFYVM_VCP_HEIGHT,
+ MODIFYVM_VCP_RATE,
+ MODIFYVM_VCP_FPS,
#endif
+ MODIFYVM_CHIPSET,
+ MODIFYVM_DEFAULTFRONTEND
};
static const RTGETOPTDEF g_aModifyVMOptions[] =
{
{ "--name", MODIFYVM_NAME, RTGETOPT_REQ_STRING },
{ "--groups", MODIFYVM_GROUPS, RTGETOPT_REQ_STRING },
+ { "--description", MODIFYVM_DESCRIPTION, RTGETOPT_REQ_STRING },
{ "--ostype", MODIFYVM_OSTYPE, RTGETOPT_REQ_STRING },
+ { "--iconfile", MODIFYVM_ICONFILE, RTGETOPT_REQ_STRING },
{ "--memory", MODIFYVM_MEMORY, RTGETOPT_REQ_UINT32 },
{ "--pagefusion", MODIFYVM_PAGEFUSION, RTGETOPT_REQ_BOOL_ONOFF },
{ "--vram", MODIFYVM_VRAM, RTGETOPT_REQ_UINT32 },
@@ -208,12 +218,14 @@ static const RTGETOPTDEF g_aModifyVMOptions[] =
{ "--acpi", MODIFYVM_ACPI, RTGETOPT_REQ_BOOL_ONOFF },
{ "--ioapic", MODIFYVM_IOAPIC, RTGETOPT_REQ_BOOL_ONOFF },
{ "--pae", MODIFYVM_PAE, RTGETOPT_REQ_BOOL_ONOFF },
+ { "--longmode", MODIFYVM_LONGMODE, RTGETOPT_REQ_BOOL_ONOFF },
{ "--synthcpu", MODIFYVM_SYNTHCPU, RTGETOPT_REQ_BOOL_ONOFF },
+ { "--triplefaultreset", MODIFYVM_TFRESET, RTGETOPT_REQ_BOOL_ONOFF },
{ "--hwvirtex", MODIFYVM_HWVIRTEX, RTGETOPT_REQ_BOOL_ONOFF },
- { "--hwvirtexexcl", MODIFYVM_HWVIRTEXEXCLUSIVE, RTGETOPT_REQ_BOOL_ONOFF },
{ "--nestedpaging", MODIFYVM_NESTEDPAGING, RTGETOPT_REQ_BOOL_ONOFF },
{ "--largepages", MODIFYVM_LARGEPAGES, RTGETOPT_REQ_BOOL_ONOFF },
{ "--vtxvpid", MODIFYVM_VTXVPID, RTGETOPT_REQ_BOOL_ONOFF },
+ { "--vtxux", MODIFYVM_VTXUX, RTGETOPT_REQ_BOOL_ONOFF },
{ "--cpuidset", MODIFYVM_SETCPUID, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX},
{ "--cpuidremove", MODIFYVM_DELCPUID, RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_HEX},
{ "--cpuidremoveall", MODIFYVM_DELALLCPUID, RTGETOPT_REQ_NOTHING},
@@ -223,6 +235,7 @@ static const RTGETOPTDEF g_aModifyVMOptions[] =
{ "--unplugcpu", MODIFYVM_UNPLUGCPU, RTGETOPT_REQ_UINT32 },
{ "--cpuexecutioncap", MODIFYVM_CPU_EXECTUION_CAP, RTGETOPT_REQ_UINT32 },
{ "--rtcuseutc", MODIFYVM_RTCUSEUTC, RTGETOPT_REQ_BOOL_ONOFF },
+ { "--graphicscontroller", MODIFYVM_GRAPHICSCONTROLLER, RTGETOPT_REQ_STRING },
{ "--monitorcount", MODIFYVM_MONITORCOUNT, RTGETOPT_REQ_UINT32 },
{ "--accelerate3d", MODIFYVM_ACCELERATE3D, RTGETOPT_REQ_BOOL_ONOFF },
#ifdef VBOX_WITH_VIDEOHWACCEL
@@ -262,8 +275,10 @@ static const RTGETOPTDEF g_aModifyVMOptions[] =
{ "--bridgeadapter", MODIFYVM_BRIDGEADAPTER, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
{ "--hostonlyadapter", MODIFYVM_HOSTONLYADAPTER, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
{ "--intnet", MODIFYVM_INTNET, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
- { "--natnet", MODIFYVM_NATNET, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
{ "--nicgenericdrv", MODIFYVM_GENERICDRV, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
+ { "--nat-network", MODIFYVM_NATNETWORKNAME, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
+ { "--natnetwork", MODIFYVM_NATNETWORKNAME, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
+ { "--natnet", MODIFYVM_NATNET, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
{ "--natbindip", MODIFYVM_NATBINDIP, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
{ "--natsettings", MODIFYVM_NATSETTINGS, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
{ "--natpf", MODIFYVM_NATPF, RTGETOPT_REQ_STRING | RTGETOPT_FLAG_INDEX },
@@ -331,9 +346,12 @@ static const RTGETOPTDEF g_aModifyVMOptions[] =
{ "--chipset", MODIFYVM_CHIPSET, RTGETOPT_REQ_STRING },
#ifdef VBOX_WITH_VPX
{ "--vcpenabled", MODIFYVM_VCP, RTGETOPT_REQ_BOOL_ONOFF },
+ { "--vcpscreens", MODIFYVM_VCP_SCREENS, RTGETOPT_REQ_STRING },
{ "--vcpfile", MODIFYVM_VCP_FILENAME, RTGETOPT_REQ_STRING },
{ "--vcpwidth", MODIFYVM_VCP_WIDTH, RTGETOPT_REQ_UINT32 },
{ "--vcpheight", MODIFYVM_VCP_HEIGHT, RTGETOPT_REQ_UINT32 },
+ { "--vcprate", MODIFYVM_VCP_RATE, RTGETOPT_REQ_UINT32 },
+ { "--vcpfps", MODIFYVM_VCP_FPS, RTGETOPT_REQ_UINT32 },
#endif
{ "--autostart-enabled", MODIFYVM_AUTOSTART_ENABLED, RTGETOPT_REQ_BOOL_ONOFF },
{ "--autostart-delay", MODIFYVM_AUTOSTART_DELAY, RTGETOPT_REQ_UINT32 },
@@ -345,6 +363,7 @@ static const RTGETOPTDEF g_aModifyVMOptions[] =
#ifdef VBOX_WITH_USB_CARDREADER
{ "--usbcardreader", MODIFYVM_USBCARDREADER, RTGETOPT_REQ_BOOL_ONOFF },
#endif
+ { "--defaultfrontend", MODIFYVM_DEFAULTFRONTEND, RTGETOPT_REQ_STRING },
};
static void vrdeWarningDeprecatedOption(const char *pszOption)
@@ -392,6 +411,30 @@ void parseGroups(const char *pcszGroups, com::SafeArray<BSTR> *pGroups)
}
}
+int parseScreens(const char *pcszScreens, com::SafeArray<BOOL> *pScreens)
+{
+ while (pcszScreens && *pcszScreens)
+ {
+ char *pszNext;
+ uint32_t iScreen;
+ int rc = RTStrToUInt32Ex(pcszScreens, &pszNext, 0, &iScreen);
+ if (RT_FAILURE(rc))
+ return 1;
+ if (iScreen >= pScreens->size())
+ return 1;
+ if (pszNext && *pszNext)
+ {
+ pszNext = RTStrStripL(pszNext);
+ if (*pszNext != ',')
+ return 1;
+ pszNext++;
+ }
+ (*pScreens)[iScreen] = true;
+ pcszScreens = pszNext;
+ }
+ return 0;
+}
+
int handleModifyVM(HandlerArg *a)
{
int c;
@@ -399,8 +442,8 @@ int handleModifyVM(HandlerArg *a)
Bstr name;
RTGETOPTUNION ValueUnion;
RTGETOPTSTATE GetOptState;
- ComPtr <IMachine> machine;
- ComPtr <IBIOSSettings> biosSettings;
+ ComPtr<IMachine> machine;
+ ComPtr<IBIOSSettings> biosSettings;
/* VM ID + at least one parameter. Parameter arguments are checked
* individually. */
@@ -442,6 +485,11 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR(machine, COMSETTER(Groups)(ComSafeArrayAsInParam(groups)));
break;
}
+ case MODIFYVM_DESCRIPTION:
+ {
+ CHECK_ERROR(machine, COMSETTER(Description)(Bstr(ValueUnion.psz).raw()));
+ break;
+ }
case MODIFYVM_OSTYPE:
{
ComPtr<IGuestOSType> guestOSType;
@@ -453,9 +501,46 @@ int handleModifyVM(HandlerArg *a)
}
else
{
- errorArgument("Invalid guest OS type '%s'", Utf8Str(ValueUnion.psz).c_str());
+ errorArgument("Invalid guest OS type '%s'", ValueUnion.psz);
+ rc = E_FAIL;
+ }
+ break;
+ }
+
+ case MODIFYVM_ICONFILE:
+ {
+ RTFILE iconFile;
+ int vrc = RTFileOpen(&iconFile, ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
+ if (RT_FAILURE(vrc))
+ {
+ RTMsgError("Cannot open file \"%s\": %Rrc", ValueUnion.psz, vrc);
+ rc = E_FAIL;
+ break;
+ }
+ uint64_t cbSize;
+ vrc = RTFileGetSize(iconFile, &cbSize);
+ if (RT_FAILURE(vrc))
+ {
+ RTMsgError("Cannot get size of file \"%s\": %Rrc", ValueUnion.psz, vrc);
+ rc = E_FAIL;
+ break;
+ }
+ if (cbSize > _256K)
+ {
+ RTMsgError("File \"%s\" is bigger than 256KByte", ValueUnion.psz);
rc = E_FAIL;
+ break;
+ }
+ SafeArray<BYTE> icon((size_t)cbSize);
+ rc = RTFileRead(iconFile, icon.raw(), (size_t)cbSize, NULL);
+ if (RT_FAILURE(vrc))
+ {
+ RTMsgError("Cannot read contents of file \"%s\": %Rrc", ValueUnion.psz, vrc);
+ rc = E_FAIL;
+ break;
}
+ RTFileClose(iconFile);
+ CHECK_ERROR(machine, COMSETTER(Icon)(ComSafeArrayAsInParam(icon)));
break;
}
@@ -479,23 +564,23 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_FIRMWARE:
{
- if (!strcmp(ValueUnion.psz, "efi"))
+ if (!RTStrICmp(ValueUnion.psz, "efi"))
{
CHECK_ERROR(machine, COMSETTER(FirmwareType)(FirmwareType_EFI));
}
- else if (!strcmp(ValueUnion.psz, "efi32"))
+ else if (!RTStrICmp(ValueUnion.psz, "efi32"))
{
CHECK_ERROR(machine, COMSETTER(FirmwareType)(FirmwareType_EFI32));
}
- else if (!strcmp(ValueUnion.psz, "efi64"))
+ else if (!RTStrICmp(ValueUnion.psz, "efi64"))
{
CHECK_ERROR(machine, COMSETTER(FirmwareType)(FirmwareType_EFI64));
}
- else if (!strcmp(ValueUnion.psz, "efidual"))
+ else if (!RTStrICmp(ValueUnion.psz, "efidual"))
{
CHECK_ERROR(machine, COMSETTER(FirmwareType)(FirmwareType_EFIDUAL));
}
- else if (!strcmp(ValueUnion.psz, "bios"))
+ else if (!RTStrICmp(ValueUnion.psz, "bios"))
{
CHECK_ERROR(machine, COMSETTER(FirmwareType)(FirmwareType_BIOS));
}
@@ -525,21 +610,27 @@ int handleModifyVM(HandlerArg *a)
break;
}
+ case MODIFYVM_LONGMODE:
+ {
+ CHECK_ERROR(machine, SetCPUProperty(CPUPropertyType_LongMode, ValueUnion.f));
+ break;
+ }
+
case MODIFYVM_SYNTHCPU:
{
CHECK_ERROR(machine, SetCPUProperty(CPUPropertyType_Synthetic, ValueUnion.f));
break;
}
- case MODIFYVM_HWVIRTEX:
+ case MODIFYVM_TFRESET:
{
- CHECK_ERROR(machine, SetHWVirtExProperty(HWVirtExPropertyType_Enabled, ValueUnion.f));
+ CHECK_ERROR(machine, SetCPUProperty(CPUPropertyType_TripleFaultReset, ValueUnion.f));
break;
}
- case MODIFYVM_HWVIRTEXEXCLUSIVE:
+ case MODIFYVM_HWVIRTEX:
{
- CHECK_ERROR(machine, SetHWVirtExProperty(HWVirtExPropertyType_Exclusive, ValueUnion.f));
+ CHECK_ERROR(machine, SetHWVirtExProperty(HWVirtExPropertyType_Enabled, ValueUnion.f));
break;
}
@@ -591,6 +682,12 @@ int handleModifyVM(HandlerArg *a)
break;
}
+ case MODIFYVM_VTXUX:
+ {
+ CHECK_ERROR(machine, SetHWVirtExProperty(HWVirtExPropertyType_UnrestrictedExecution, ValueUnion.f));
+ break;
+ }
+
case MODIFYVM_CPUS:
{
CHECK_ERROR(machine, COMSETTER(CPUCount)(ValueUnion.u32));
@@ -627,6 +724,29 @@ int handleModifyVM(HandlerArg *a)
break;
}
+ case MODIFYVM_GRAPHICSCONTROLLER:
+ {
+ if ( !RTStrICmp(ValueUnion.psz, "none")
+ || !RTStrICmp(ValueUnion.psz, "disabled"))
+ CHECK_ERROR(machine, COMSETTER(GraphicsControllerType)(GraphicsControllerType_Null));
+ else if ( !RTStrICmp(ValueUnion.psz, "vboxvga")
+ || !RTStrICmp(ValueUnion.psz, "vbox")
+ || !RTStrICmp(ValueUnion.psz, "vga")
+ || !RTStrICmp(ValueUnion.psz, "vesa"))
+ CHECK_ERROR(machine, COMSETTER(GraphicsControllerType)(GraphicsControllerType_VBoxVGA));
+#ifdef VBOX_WITH_VMSVGA
+ else if ( !RTStrICmp(ValueUnion.psz, "vmsvga")
+ || !RTStrICmp(ValueUnion.psz, "vmware"))
+ CHECK_ERROR(machine, COMSETTER(GraphicsControllerType)(GraphicsControllerType_VMSVGA));
+#endif
+ else
+ {
+ errorArgument("Invalid --graphicscontroller argument '%s'", ValueUnion.psz);
+ rc = E_FAIL;
+ }
+ break;
+ }
+
case MODIFYVM_MONITORCOUNT:
{
CHECK_ERROR(machine, COMSETTER(MonitorCount)(ValueUnion.u32));
@@ -673,15 +793,15 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_BIOSBOOTMENU:
{
- if (!strcmp(ValueUnion.psz, "disabled"))
+ if (!RTStrICmp(ValueUnion.psz, "disabled"))
{
CHECK_ERROR(biosSettings, COMSETTER(BootMenuMode)(BIOSBootMenuMode_Disabled));
}
- else if (!strcmp(ValueUnion.psz, "menuonly"))
+ else if (!RTStrICmp(ValueUnion.psz, "menuonly"))
{
CHECK_ERROR(biosSettings, COMSETTER(BootMenuMode)(BIOSBootMenuMode_MenuOnly));
}
- else if (!strcmp(ValueUnion.psz, "messageandmenu"))
+ else if (!RTStrICmp(ValueUnion.psz, "messageandmenu"))
{
CHECK_ERROR(biosSettings, COMSETTER(BootMenuMode)(BIOSBootMenuMode_MessageAndMenu));
}
@@ -707,23 +827,23 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_BOOT:
{
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
CHECK_ERROR(machine, SetBootOrder(GetOptState.uIndex, DeviceType_Null));
}
- else if (!strcmp(ValueUnion.psz, "floppy"))
+ else if (!RTStrICmp(ValueUnion.psz, "floppy"))
{
CHECK_ERROR(machine, SetBootOrder(GetOptState.uIndex, DeviceType_Floppy));
}
- else if (!strcmp(ValueUnion.psz, "dvd"))
+ else if (!RTStrICmp(ValueUnion.psz, "dvd"))
{
CHECK_ERROR(machine, SetBootOrder(GetOptState.uIndex, DeviceType_DVD));
}
- else if (!strcmp(ValueUnion.psz, "disk"))
+ else if (!RTStrICmp(ValueUnion.psz, "disk"))
{
CHECK_ERROR(machine, SetBootOrder(GetOptState.uIndex, DeviceType_HardDisk));
}
- else if (!strcmp(ValueUnion.psz, "net"))
+ else if (!RTStrICmp(ValueUnion.psz, "net"))
{
CHECK_ERROR(machine, SetBootOrder(GetOptState.uIndex, DeviceType_Network));
}
@@ -762,16 +882,17 @@ int handleModifyVM(HandlerArg *a)
break;
}
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
machine->DetachDevice(bstrController.raw(), u1, u2);
}
else
{
ComPtr<IMedium> hardDisk;
- rc = findOrOpenMedium(a, ValueUnion.psz, DeviceType_HardDisk,
- AccessMode_ReadWrite, hardDisk,
- false /* fForceNewUuidOnOpen */, NULL);
+ rc = openMedium(a, ValueUnion.psz, DeviceType_HardDisk,
+ AccessMode_ReadWrite, hardDisk,
+ false /* fForceNewUuidOnOpen */,
+ false /* fSilent */);
if (FAILED(rc))
break;
if (hardDisk)
@@ -826,7 +947,7 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_SATA: // deprecated
{
- if (!strcmp(ValueUnion.psz, "on") || !strcmp(ValueUnion.psz, "enable"))
+ if (!RTStrICmp(ValueUnion.psz, "on") || !RTStrICmp(ValueUnion.psz, "enable"))
{
ComPtr<IStorageController> ctl;
CHECK_ERROR(machine, AddStorageController(Bstr("SATA").raw(),
@@ -834,7 +955,7 @@ int handleModifyVM(HandlerArg *a)
ctl.asOutParam()));
CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_IntelAhci));
}
- else if (!strcmp(ValueUnion.psz, "off") || !strcmp(ValueUnion.psz, "disable"))
+ else if (!RTStrICmp(ValueUnion.psz, "off") || !RTStrICmp(ValueUnion.psz, "disable"))
CHECK_ERROR(machine, RemoveStorageController(Bstr("SATA").raw()));
else
return errorArgument("Invalid --usb argument '%s'", ValueUnion.psz);
@@ -843,7 +964,7 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_SCSIPORT: // deprecated
{
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
rc = machine->DetachDevice(Bstr("LsiLogic").raw(),
GetOptState.uIndex, 0);
@@ -854,9 +975,10 @@ int handleModifyVM(HandlerArg *a)
else
{
ComPtr<IMedium> hardDisk;
- rc = findOrOpenMedium(a, ValueUnion.psz, DeviceType_HardDisk,
- AccessMode_ReadWrite, hardDisk,
- false /* fForceNewUuidOnOpen */, NULL);
+ rc = openMedium(a, ValueUnion.psz, DeviceType_HardDisk,
+ AccessMode_ReadWrite, hardDisk,
+ false /* fForceNewUuidOnOpen */,
+ false /* fSilent */);
if (FAILED(rc))
break;
if (hardDisk)
@@ -917,7 +1039,7 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_SCSI: // deprecated
{
- if (!strcmp(ValueUnion.psz, "on") || !strcmp(ValueUnion.psz, "enable"))
+ if (!RTStrICmp(ValueUnion.psz, "on") || !RTStrICmp(ValueUnion.psz, "enable"))
{
ComPtr<IStorageController> ctl;
@@ -927,7 +1049,7 @@ int handleModifyVM(HandlerArg *a)
if (SUCCEEDED(rc))
CHECK_ERROR(ctl, COMSETTER(ControllerType)(StorageControllerType_BusLogic));
}
- else if (!strcmp(ValueUnion.psz, "off") || !strcmp(ValueUnion.psz, "disable"))
+ else if (!RTStrICmp(ValueUnion.psz, "off") || !RTStrICmp(ValueUnion.psz, "disable"))
{
rc = machine->RemoveStorageController(Bstr("BusLogic").raw());
if (FAILED(rc))
@@ -940,7 +1062,7 @@ int handleModifyVM(HandlerArg *a)
{
CHECK_ERROR(machine, PassthroughDevice(Bstr("IDE Controller").raw(),
1, 0,
- !strcmp(ValueUnion.psz, "on")));
+ !RTStrICmp(ValueUnion.psz, "on")));
break;
}
@@ -949,12 +1071,12 @@ int handleModifyVM(HandlerArg *a)
ComPtr<IMedium> dvdMedium;
/* unmount? */
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
/* nothing to do, NULL object will cause unmount */
}
/* host drive? */
- else if (!strncmp(ValueUnion.psz, "host:", 5))
+ else if (!RTStrNICmp(ValueUnion.psz, "host:", 5))
{
ComPtr<IHost> host;
CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
@@ -982,9 +1104,10 @@ int handleModifyVM(HandlerArg *a)
}
else
{
- rc = findOrOpenMedium(a, ValueUnion.psz, DeviceType_DVD,
- AccessMode_ReadOnly, dvdMedium,
- false /* fForceNewUuidOnOpen */, NULL);
+ rc = openMedium(a, ValueUnion.psz, DeviceType_DVD,
+ AccessMode_ReadOnly, dvdMedium,
+ false /* fForceNewUuidOnOpen */,
+ false /* fSilent */);
if (FAILED(rc))
break;
if (!dvdMedium)
@@ -1009,7 +1132,7 @@ int handleModifyVM(HandlerArg *a)
0, 0, floppyAttachment.asOutParam());
/* disable? */
- if (!strcmp(ValueUnion.psz, "disabled"))
+ if (!RTStrICmp(ValueUnion.psz, "disabled"))
{
/* disable the controller */
if (floppyAttachment)
@@ -1025,13 +1148,13 @@ int handleModifyVM(HandlerArg *a)
DeviceType_Floppy));
/* unmount? */
- if ( !strcmp(ValueUnion.psz, "none")
- || !strcmp(ValueUnion.psz, "empty")) // deprecated
+ if ( !RTStrICmp(ValueUnion.psz, "none")
+ || !RTStrICmp(ValueUnion.psz, "empty")) // deprecated
{
/* nothing to do, NULL object will cause unmount */
}
/* host drive? */
- else if (!strncmp(ValueUnion.psz, "host:", 5))
+ else if (!RTStrNICmp(ValueUnion.psz, "host:", 5))
{
ComPtr<IHost> host;
CHECK_ERROR(a->virtualBox, COMGETTER(Host)(host.asOutParam()));
@@ -1046,9 +1169,10 @@ int handleModifyVM(HandlerArg *a)
}
else
{
- rc = findOrOpenMedium(a, ValueUnion.psz, DeviceType_Floppy,
- AccessMode_ReadWrite, floppyMedium,
- false /* fForceNewUuidOnOpen */, NULL);
+ rc = openMedium(a, ValueUnion.psz, DeviceType_Floppy,
+ AccessMode_ReadWrite, floppyMedium,
+ false /* fForceNewUuidOnOpen */,
+ false /* fSilent */);
if (FAILED(rc))
break;
if (!floppyMedium)
@@ -1131,30 +1255,30 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR_BREAK(machine, GetNetworkAdapter(GetOptState.uIndex - 1, nic.asOutParam()));
ASSERT(nic);
- if (!strcmp(ValueUnion.psz, "Am79C970A"))
+ if (!RTStrICmp(ValueUnion.psz, "Am79C970A"))
{
CHECK_ERROR(nic, COMSETTER(AdapterType)(NetworkAdapterType_Am79C970A));
}
- else if (!strcmp(ValueUnion.psz, "Am79C973"))
+ else if (!RTStrICmp(ValueUnion.psz, "Am79C973"))
{
CHECK_ERROR(nic, COMSETTER(AdapterType)(NetworkAdapterType_Am79C973));
}
#ifdef VBOX_WITH_E1000
- else if (!strcmp(ValueUnion.psz, "82540EM"))
+ else if (!RTStrICmp(ValueUnion.psz, "82540EM"))
{
CHECK_ERROR(nic, COMSETTER(AdapterType)(NetworkAdapterType_I82540EM));
}
- else if (!strcmp(ValueUnion.psz, "82543GC"))
+ else if (!RTStrICmp(ValueUnion.psz, "82543GC"))
{
CHECK_ERROR(nic, COMSETTER(AdapterType)(NetworkAdapterType_I82543GC));
}
- else if (!strcmp(ValueUnion.psz, "82545EM"))
+ else if (!RTStrICmp(ValueUnion.psz, "82545EM"))
{
CHECK_ERROR(nic, COMSETTER(AdapterType)(NetworkAdapterType_I82545EM));
}
#endif
#ifdef VBOX_WITH_VIRTIO
- else if (!strcmp(ValueUnion.psz, "virtio"))
+ else if (!RTStrICmp(ValueUnion.psz, "virtio"))
{
CHECK_ERROR(nic, COMSETTER(AdapterType)(NetworkAdapterType_Virtio));
}
@@ -1204,12 +1328,12 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_NICPROMISC:
{
NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy;
- if (!strcmp(ValueUnion.psz, "deny"))
+ if (!RTStrICmp(ValueUnion.psz, "deny"))
enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_Deny;
- else if ( !strcmp(ValueUnion.psz, "allow-vms")
- || !strcmp(ValueUnion.psz, "allow-network"))
+ else if ( !RTStrICmp(ValueUnion.psz, "allow-vms")
+ || !RTStrICmp(ValueUnion.psz, "allow-network"))
enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowNetwork;
- else if (!strcmp(ValueUnion.psz, "allow-all"))
+ else if (!RTStrICmp(ValueUnion.psz, "allow-all"))
enmPromiscModePolicy = NetworkAdapterPromiscModePolicy_AllowAll;
else
{
@@ -1263,43 +1387,49 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR_BREAK(machine, GetNetworkAdapter(GetOptState.uIndex - 1, nic.asOutParam()));
ASSERT(nic);
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
CHECK_ERROR(nic, COMSETTER(Enabled)(FALSE));
}
- else if (!strcmp(ValueUnion.psz, "null"))
+ else if (!RTStrICmp(ValueUnion.psz, "null"))
{
CHECK_ERROR(nic, COMSETTER(Enabled)(TRUE));
CHECK_ERROR(nic, COMSETTER(AttachmentType)(NetworkAttachmentType_Null));
}
- else if (!strcmp(ValueUnion.psz, "nat"))
+ else if (!RTStrICmp(ValueUnion.psz, "nat"))
{
CHECK_ERROR(nic, COMSETTER(Enabled)(TRUE));
CHECK_ERROR(nic, COMSETTER(AttachmentType)(NetworkAttachmentType_NAT));
}
- else if ( !strcmp(ValueUnion.psz, "bridged")
- || !strcmp(ValueUnion.psz, "hostif")) /* backward compatibility */
+ else if ( !RTStrICmp(ValueUnion.psz, "bridged")
+ || !RTStrICmp(ValueUnion.psz, "hostif")) /* backward compatibility */
{
CHECK_ERROR(nic, COMSETTER(Enabled)(TRUE));
CHECK_ERROR(nic, COMSETTER(AttachmentType)(NetworkAttachmentType_Bridged));
}
- else if (!strcmp(ValueUnion.psz, "intnet"))
+ else if (!RTStrICmp(ValueUnion.psz, "intnet"))
{
CHECK_ERROR(nic, COMSETTER(Enabled)(TRUE));
CHECK_ERROR(nic, COMSETTER(AttachmentType)(NetworkAttachmentType_Internal));
}
- else if (!strcmp(ValueUnion.psz, "hostonly"))
+ else if (!RTStrICmp(ValueUnion.psz, "hostonly"))
{
CHECK_ERROR(nic, COMSETTER(Enabled)(TRUE));
CHECK_ERROR(nic, COMSETTER(AttachmentType)(NetworkAttachmentType_HostOnly));
}
- else if (!strcmp(ValueUnion.psz, "generic"))
+ else if (!RTStrICmp(ValueUnion.psz, "generic"))
{
CHECK_ERROR(nic, COMSETTER(Enabled)(TRUE));
CHECK_ERROR(nic, COMSETTER(AttachmentType)(NetworkAttachmentType_Generic));
}
+ else if (!RTStrICmp(ValueUnion.psz, "natnetwork"))
+ {
+
+ CHECK_ERROR(nic, COMSETTER(Enabled)(TRUE));
+ CHECK_ERROR(nic, COMSETTER(AttachmentType)(NetworkAttachmentType_NATNetwork));
+ }
else
{
errorArgument("Invalid type '%s' specfied for NIC %u", ValueUnion.psz, GetOptState.uIndex);
@@ -1327,7 +1457,7 @@ int handleModifyVM(HandlerArg *a)
ASSERT(nic);
/* remove it? */
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
CHECK_ERROR(nic, COMSETTER(BridgedInterface)(Bstr().raw()));
}
@@ -1346,7 +1476,7 @@ int handleModifyVM(HandlerArg *a)
ASSERT(nic);
/* remove it? */
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
CHECK_ERROR(nic, COMSETTER(HostOnlyInterface)(Bstr().raw()));
}
@@ -1365,7 +1495,7 @@ int handleModifyVM(HandlerArg *a)
ASSERT(nic);
/* remove it? */
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
CHECK_ERROR(nic, COMSETTER(InternalNetwork)(Bstr().raw()));
}
@@ -1387,6 +1517,17 @@ int handleModifyVM(HandlerArg *a)
break;
}
+ case MODIFYVM_NATNETWORKNAME:
+ {
+ ComPtr<INetworkAdapter> nic;
+
+ CHECK_ERROR_BREAK(machine, GetNetworkAdapter(GetOptState.uIndex - 1, nic.asOutParam()));
+ ASSERT(nic);
+
+ CHECK_ERROR(nic, COMSETTER(NATNetwork)(Bstr(ValueUnion.psz).raw()));
+ break;
+ }
+
case MODIFYVM_NATNET:
{
ComPtr<INetworkAdapter> nic;
@@ -1398,7 +1539,7 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR(nic, COMGETTER(NATEngine)(engine.asOutParam()));
const char *psz = ValueUnion.psz;
- if (!strcmp("default", psz))
+ if (!RTStrICmp("default", psz))
psz = "";
CHECK_ERROR(engine, COMSETTER(Network)(Bstr(psz).raw()));
@@ -1535,7 +1676,7 @@ int handleModifyVM(HandlerArg *a)
ASSERT(nic);
CHECK_ERROR(nic, COMGETTER(NATEngine)(engine.asOutParam()));
- if (RTStrCmp(ValueUnion.psz,"default") == 0)
+ if (RTStrCmp(ValueUnion.psz, "default") == 0)
{
aliasMode = 0;
}
@@ -1644,7 +1785,7 @@ int handleModifyVM(HandlerArg *a)
ASSERT(nic);
/* generate one? */
- if (!strcmp(ValueUnion.psz, "auto"))
+ if (!RTStrICmp(ValueUnion.psz, "auto"))
{
CHECK_ERROR(nic, COMSETTER(MACAddress)(Bstr().raw()));
}
@@ -1658,22 +1799,28 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_HIDPTR:
{
bool fEnableUsb = false;
- if (!strcmp(ValueUnion.psz, "ps2"))
+ if (!RTStrICmp(ValueUnion.psz, "ps2"))
{
CHECK_ERROR(machine, COMSETTER(PointingHIDType)(PointingHIDType_PS2Mouse));
}
- else if (!strcmp(ValueUnion.psz, "usb"))
+ else if (!RTStrICmp(ValueUnion.psz, "usb"))
{
CHECK_ERROR(machine, COMSETTER(PointingHIDType)(PointingHIDType_USBMouse));
if (SUCCEEDED(rc))
fEnableUsb = true;
}
- else if (!strcmp(ValueUnion.psz, "usbtablet"))
+ else if (!RTStrICmp(ValueUnion.psz, "usbtablet"))
{
CHECK_ERROR(machine, COMSETTER(PointingHIDType)(PointingHIDType_USBTablet));
if (SUCCEEDED(rc))
fEnableUsb = true;
}
+ else if (!RTStrICmp(ValueUnion.psz, "usbmultitouch"))
+ {
+ CHECK_ERROR(machine, COMSETTER(PointingHIDType)(PointingHIDType_USBMultiTouch));
+ if (SUCCEEDED(rc))
+ fEnableUsb = true;
+ }
else
{
errorArgument("Invalid type '%s' specfied for pointing device", ValueUnion.psz);
@@ -1682,16 +1829,14 @@ int handleModifyVM(HandlerArg *a)
if (fEnableUsb)
{
/* Make sure the OHCI controller is enabled. */
- ComPtr<IUSBController> UsbCtl;
- rc = machine->COMGETTER(USBController)(UsbCtl.asOutParam());
- if (SUCCEEDED(rc))
+ ULONG cOhciCtrls = 0;
+ rc = machine->GetUSBControllerCountByType(USBControllerType_OHCI, &cOhciCtrls);
+ if ( SUCCEEDED(rc)
+ && !cOhciCtrls)
{
- BOOL fEnabled;
- rc = UsbCtl->COMGETTER(Enabled)(&fEnabled);
- if (FAILED(rc))
- fEnabled = false;
- if (!fEnabled)
- CHECK_ERROR(UsbCtl, COMSETTER(Enabled)(true));
+ ComPtr<IUSBController> UsbCtl;
+ CHECK_ERROR(machine, AddUSBController(Bstr("OHCI").raw(), USBControllerType_OHCI,
+ UsbCtl.asOutParam()));
}
}
break;
@@ -1700,11 +1845,11 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_HIDKBD:
{
bool fEnableUsb = false;
- if (!strcmp(ValueUnion.psz, "ps2"))
+ if (!RTStrICmp(ValueUnion.psz, "ps2"))
{
CHECK_ERROR(machine, COMSETTER(KeyboardHIDType)(KeyboardHIDType_PS2Keyboard));
}
- else if (!strcmp(ValueUnion.psz, "usb"))
+ else if (!RTStrICmp(ValueUnion.psz, "usb"))
{
CHECK_ERROR(machine, COMSETTER(KeyboardHIDType)(KeyboardHIDType_USBKeyboard));
if (SUCCEEDED(rc))
@@ -1718,16 +1863,14 @@ int handleModifyVM(HandlerArg *a)
if (fEnableUsb)
{
/* Make sure the OHCI controller is enabled. */
- ComPtr<IUSBController> UsbCtl;
- rc = machine->COMGETTER(USBController)(UsbCtl.asOutParam());
- if (SUCCEEDED(rc))
+ ULONG cOhciCtrls = 0;
+ rc = machine->GetUSBControllerCountByType(USBControllerType_OHCI, &cOhciCtrls);
+ if ( SUCCEEDED(rc)
+ && !cOhciCtrls)
{
- BOOL fEnabled;
- rc = UsbCtl->COMGETTER(Enabled)(&fEnabled);
- if (FAILED(rc))
- fEnabled = false;
- if (!fEnabled)
- CHECK_ERROR(UsbCtl, COMSETTER(Enabled)(true));
+ ComPtr<IUSBController> UsbCtl;
+ CHECK_ERROR(machine, AddUSBController(Bstr("OHCI").raw(), USBControllerType_OHCI,
+ UsbCtl.asOutParam()));
}
}
break;
@@ -1741,13 +1884,13 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR_BREAK(machine, GetSerialPort(GetOptState.uIndex - 1, uart.asOutParam()));
ASSERT(uart);
- if (!strcmp(ValueUnion.psz, "disconnected"))
+ if (!RTStrICmp(ValueUnion.psz, "disconnected"))
{
CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_Disconnected));
}
- else if ( !strcmp(ValueUnion.psz, "server")
- || !strcmp(ValueUnion.psz, "client")
- || !strcmp(ValueUnion.psz, "file"))
+ else if ( !RTStrICmp(ValueUnion.psz, "server")
+ || !RTStrICmp(ValueUnion.psz, "client")
+ || !RTStrICmp(ValueUnion.psz, "file"))
{
const char *pszMode = ValueUnion.psz;
@@ -1759,17 +1902,17 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR(uart, COMSETTER(Path)(Bstr(ValueUnion.psz).raw()));
- if (!strcmp(pszMode, "server"))
+ if (!RTStrICmp(pszMode, "server"))
{
CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostPipe));
CHECK_ERROR(uart, COMSETTER(Server)(TRUE));
}
- else if (!strcmp(pszMode, "client"))
+ else if (!RTStrICmp(pszMode, "client"))
{
CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_HostPipe));
CHECK_ERROR(uart, COMSETTER(Server)(FALSE));
}
- else if (!strcmp(pszMode, "file"))
+ else if (!RTStrICmp(pszMode, "file"))
{
CHECK_ERROR(uart, COMSETTER(HostMode)(PortMode_RawFile));
}
@@ -1789,7 +1932,7 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR_BREAK(machine, GetSerialPort(GetOptState.uIndex - 1, uart.asOutParam()));
ASSERT(uart);
- if (!strcmp(ValueUnion.psz, "off") || !strcmp(ValueUnion.psz, "disable"))
+ if (!RTStrICmp(ValueUnion.psz, "off") || !RTStrICmp(ValueUnion.psz, "disable"))
CHECK_ERROR(uart, COMSETTER(Enabled)(FALSE));
else
{
@@ -1834,7 +1977,7 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR_BREAK(machine, GetParallelPort(GetOptState.uIndex - 1, lpt.asOutParam()));
ASSERT(lpt);
- if (!strcmp(ValueUnion.psz, "off") || !strcmp(ValueUnion.psz, "disable"))
+ if (!RTStrICmp(ValueUnion.psz, "off") || !RTStrICmp(ValueUnion.psz, "disable"))
CHECK_ERROR(lpt, COMSETTER(Enabled)(FALSE));
else
{
@@ -1872,11 +2015,11 @@ int handleModifyVM(HandlerArg *a)
machine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
ASSERT(audioAdapter);
- if (!strcmp(ValueUnion.psz, "sb16"))
+ if (!RTStrICmp(ValueUnion.psz, "sb16"))
CHECK_ERROR(audioAdapter, COMSETTER(AudioController)(AudioControllerType_SB16));
- else if (!strcmp(ValueUnion.psz, "ac97"))
+ else if (!RTStrICmp(ValueUnion.psz, "ac97"))
CHECK_ERROR(audioAdapter, COMSETTER(AudioController)(AudioControllerType_AC97));
- else if (!strcmp(ValueUnion.psz, "hda"))
+ else if (!RTStrICmp(ValueUnion.psz, "hda"))
CHECK_ERROR(audioAdapter, COMSETTER(AudioController)(AudioControllerType_HDA));
else
{
@@ -1893,24 +2036,24 @@ int handleModifyVM(HandlerArg *a)
ASSERT(audioAdapter);
/* disable? */
- if (!strcmp(ValueUnion.psz, "none"))
+ if (!RTStrICmp(ValueUnion.psz, "none"))
{
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(false));
}
- else if (!strcmp(ValueUnion.psz, "null"))
+ else if (!RTStrICmp(ValueUnion.psz, "null"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_Null));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
}
#ifdef RT_OS_WINDOWS
#ifdef VBOX_WITH_WINMM
- else if (!strcmp(ValueUnion.psz, "winmm"))
+ else if (!RTStrICmp(ValueUnion.psz, "winmm"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_WinMM));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
}
#endif
- else if (!strcmp(ValueUnion.psz, "dsound"))
+ else if (!RTStrICmp(ValueUnion.psz, "dsound"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_DirectSound));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
@@ -1918,14 +2061,14 @@ int handleModifyVM(HandlerArg *a)
#endif /* RT_OS_WINDOWS */
#ifdef RT_OS_LINUX
# ifdef VBOX_WITH_ALSA
- else if (!strcmp(ValueUnion.psz, "alsa"))
+ else if (!RTStrICmp(ValueUnion.psz, "alsa"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_ALSA));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
}
# endif
# ifdef VBOX_WITH_PULSE
- else if (!strcmp(ValueUnion.psz, "pulse"))
+ else if (!RTStrICmp(ValueUnion.psz, "pulse"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_Pulse));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
@@ -1933,20 +2076,20 @@ int handleModifyVM(HandlerArg *a)
# endif
#endif /* !RT_OS_LINUX */
#ifdef RT_OS_SOLARIS
- else if (!strcmp(ValueUnion.psz, "solaudio"))
+ else if (!RTStrICmp(ValueUnion.psz, "solaudio"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_SolAudio));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
}
#endif /* !RT_OS_SOLARIS */
#ifdef RT_OS_FREEBSD
- else if (!strcmp(ValueUnion.psz, "oss"))
+ else if (!RTStrICmp(ValueUnion.psz, "oss"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_OSS));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
}
# ifdef VBOX_WITH_PULSE
- else if (!strcmp(ValueUnion.psz, "pulse"))
+ else if (!RTStrICmp(ValueUnion.psz, "pulse"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_Pulse));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
@@ -1954,7 +2097,7 @@ int handleModifyVM(HandlerArg *a)
# endif
#endif /* !RT_OS_FREEBSD */
#ifdef RT_OS_DARWIN
- else if (!strcmp(ValueUnion.psz, "coreaudio"))
+ else if (!RTStrICmp(ValueUnion.psz, "coreaudio"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_CoreAudio));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
@@ -1962,7 +2105,7 @@ int handleModifyVM(HandlerArg *a)
#endif /* !RT_OS_DARWIN */
# if defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(VBOX_WITH_SOLARIS_OSS)
- else if (!strcmp(ValueUnion.psz, "oss"))
+ else if (!RTStrICmp(ValueUnion.psz, "oss"))
{
CHECK_ERROR(audioAdapter, COMSETTER(AudioDriver)(AudioDriverType_OSS));
CHECK_ERROR(audioAdapter, COMSETTER(Enabled)(true));
@@ -1979,13 +2122,13 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_CLIPBOARD:
{
ClipboardMode_T mode;
- if (!strcmp(ValueUnion.psz, "disabled"))
+ if (!RTStrICmp(ValueUnion.psz, "disabled"))
mode = ClipboardMode_Disabled;
- else if (!strcmp(ValueUnion.psz, "hosttoguest"))
+ else if (!RTStrICmp(ValueUnion.psz, "hosttoguest"))
mode = ClipboardMode_HostToGuest;
- else if (!strcmp(ValueUnion.psz, "guesttohost"))
+ else if (!RTStrICmp(ValueUnion.psz, "guesttohost"))
mode = ClipboardMode_GuestToHost;
- else if (!strcmp(ValueUnion.psz, "bidirectional"))
+ else if (!RTStrICmp(ValueUnion.psz, "bidirectional"))
mode = ClipboardMode_Bidirectional;
else
{
@@ -2002,13 +2145,13 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_DRAGANDDROP:
{
DragAndDropMode_T mode;
- if (!strcmp(ValueUnion.psz, "disabled"))
+ if (!RTStrICmp(ValueUnion.psz, "disabled"))
mode = DragAndDropMode_Disabled;
- else if (!strcmp(ValueUnion.psz, "hosttoguest"))
+ else if (!RTStrICmp(ValueUnion.psz, "hosttoguest"))
mode = DragAndDropMode_HostToGuest;
- else if (!strcmp(ValueUnion.psz, "guesttohost"))
+ else if (!RTStrICmp(ValueUnion.psz, "guesttohost"))
mode = DragAndDropMode_GuestToHost;
- else if (!strcmp(ValueUnion.psz, "bidirectional"))
+ else if (!RTStrICmp(ValueUnion.psz, "bidirectional"))
mode = DragAndDropMode_Bidirectional;
else
{
@@ -2030,7 +2173,7 @@ int handleModifyVM(HandlerArg *a)
if (vrdeServer)
{
- if (strcmp(ValueUnion.psz, "default") != 0)
+ if (RTStrICmp(ValueUnion.psz, "default") != 0)
{
Bstr bstr(ValueUnion.psz);
CHECK_ERROR(vrdeServer, COMSETTER(VRDEExtPack)(bstr.raw()));
@@ -2090,7 +2233,7 @@ int handleModifyVM(HandlerArg *a)
machine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
ASSERT(vrdeServer);
- if (!strcmp(ValueUnion.psz, "default"))
+ if (!RTStrICmp(ValueUnion.psz, "default"))
CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), Bstr("0").raw()));
else
CHECK_ERROR(vrdeServer, SetVRDEProperty(Bstr("TCP/Ports").raw(), Bstr(ValueUnion.psz).raw()));
@@ -2118,15 +2261,15 @@ int handleModifyVM(HandlerArg *a)
machine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
ASSERT(vrdeServer);
- if (!strcmp(ValueUnion.psz, "null"))
+ if (!RTStrICmp(ValueUnion.psz, "null"))
{
CHECK_ERROR(vrdeServer, COMSETTER(AuthType)(AuthType_Null));
}
- else if (!strcmp(ValueUnion.psz, "external"))
+ else if (!RTStrICmp(ValueUnion.psz, "external"))
{
CHECK_ERROR(vrdeServer, COMSETTER(AuthType)(AuthType_External));
}
- else if (!strcmp(ValueUnion.psz, "guest"))
+ else if (!RTStrICmp(ValueUnion.psz, "guest"))
{
CHECK_ERROR(vrdeServer, COMSETTER(AuthType)(AuthType_Guest));
}
@@ -2146,7 +2289,7 @@ int handleModifyVM(HandlerArg *a)
if (vrdeServer)
{
- if (strcmp(ValueUnion.psz, "default") != 0)
+ if (RTStrICmp(ValueUnion.psz, "default") != 0)
{
Bstr bstr(ValueUnion.psz);
CHECK_ERROR(vrdeServer, COMSETTER(AuthLibrary)(bstr.raw()));
@@ -2221,25 +2364,43 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_USBEHCI:
{
- ComPtr<IUSBController> UsbCtl;
- CHECK_ERROR(machine, COMGETTER(USBController)(UsbCtl.asOutParam()));
+ ULONG cEhciCtrls = 0;
+ rc = machine->GetUSBControllerCountByType(USBControllerType_EHCI, &cEhciCtrls);
if (SUCCEEDED(rc))
- CHECK_ERROR(UsbCtl, COMSETTER(EnabledEHCI)(ValueUnion.f));
+ {
+ if (!cEhciCtrls && ValueUnion.f)
+ {
+ ComPtr<IUSBController> UsbCtl;
+ CHECK_ERROR(machine, AddUSBController(Bstr("EHCI").raw(), USBControllerType_EHCI,
+ UsbCtl.asOutParam()));
+ }
+ else if (cEhciCtrls && !ValueUnion.f)
+ CHECK_ERROR(machine, RemoveUSBController(Bstr("EHCI").raw()));
+ }
break;
}
case MODIFYVM_USB:
{
- ComPtr<IUSBController> UsbCtl;
- CHECK_ERROR(machine, COMGETTER(USBController)(UsbCtl.asOutParam()));
+ ULONG cOhciCtrls = 0;
+ rc = machine->GetUSBControllerCountByType(USBControllerType_OHCI, &cOhciCtrls);
if (SUCCEEDED(rc))
- CHECK_ERROR(UsbCtl, COMSETTER(Enabled)(ValueUnion.f));
+ {
+ if (!cOhciCtrls && ValueUnion.f)
+ {
+ ComPtr<IUSBController> UsbCtl;
+ CHECK_ERROR(machine, AddUSBController(Bstr("OHCI").raw(), USBControllerType_OHCI,
+ UsbCtl.asOutParam()));
+ }
+ else if (cOhciCtrls && !ValueUnion.f)
+ CHECK_ERROR(machine, RemoveUSBController(Bstr("OHCI").raw()));
+ }
break;
}
case MODIFYVM_SNAPSHOTFOLDER:
{
- if (!strcmp(ValueUnion.psz, "default"))
+ if (!RTStrICmp(ValueUnion.psz, "default"))
CHECK_ERROR(machine, COMSETTER(SnapshotFolder)(Bstr().raw()));
else
CHECK_ERROR(machine, COMSETTER(SnapshotFolder)(Bstr(ValueUnion.psz).raw()));
@@ -2301,12 +2462,12 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_FAULT_TOLERANCE:
{
- if (!strcmp(ValueUnion.psz, "master"))
+ if (!RTStrICmp(ValueUnion.psz, "master"))
{
CHECK_ERROR(machine, COMSETTER(FaultToleranceState(FaultToleranceState_Master)));
}
else
- if (!strcmp(ValueUnion.psz, "standby"))
+ if (!RTStrICmp(ValueUnion.psz, "standby"))
{
CHECK_ERROR(machine, COMSETTER(FaultToleranceState(FaultToleranceState_Standby)));
}
@@ -2368,11 +2529,11 @@ int handleModifyVM(HandlerArg *a)
case MODIFYVM_CHIPSET:
{
- if (!strcmp(ValueUnion.psz, "piix3"))
+ if (!RTStrICmp(ValueUnion.psz, "piix3"))
{
CHECK_ERROR(machine, COMSETTER(ChipsetType)(ChipsetType_PIIX3));
}
- else if (!strcmp(ValueUnion.psz, "ich9"))
+ else if (!RTStrICmp(ValueUnion.psz, "ich9"))
{
CHECK_ERROR(machine, COMSETTER(ChipsetType)(ChipsetType_ICH9));
BOOL fIoApic = FALSE;
@@ -2396,9 +2557,36 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR(machine, COMSETTER(VideoCaptureEnabled)(ValueUnion.f));
break;
}
+ case MODIFYVM_VCP_SCREENS:
+ {
+ ULONG cMonitors = 64;
+ CHECK_ERROR(machine, COMGETTER(MonitorCount)(&cMonitors));
+ com::SafeArray<BOOL> screens(cMonitors);
+ if (parseScreens(ValueUnion.psz, &screens))
+ {
+ errorArgument("Invalid list of screens specified\n");
+ rc = E_FAIL;
+ break;
+ }
+ CHECK_ERROR(machine, COMSETTER(VideoCaptureScreens)(ComSafeArrayAsInParam(screens)));
+ break;
+ }
case MODIFYVM_VCP_FILENAME:
{
- Bstr bstr(ValueUnion.psz);
+ Bstr bstr;
+ /* empty string will fall through, leaving bstr empty */
+ if (*ValueUnion.psz)
+ {
+ char szVCFileAbs[RTPATH_MAX] = "";
+ int vrc = RTPathAbs(ValueUnion.psz, szVCFileAbs, sizeof(szVCFileAbs));
+ if (RT_FAILURE(vrc))
+ {
+ errorArgument("Cannot convert filename \"%s\" to absolute path\n", ValueUnion.psz);
+ rc = E_FAIL;
+ break;
+ }
+ bstr = szVCFileAbs;
+ }
CHECK_ERROR(machine, COMSETTER(VideoCaptureFile)(bstr.raw()));
break;
}
@@ -2412,6 +2600,16 @@ int handleModifyVM(HandlerArg *a)
CHECK_ERROR(machine, COMSETTER(VideoCaptureHeight)(ValueUnion.u32));
break;
}
+ case MODIFYVM_VCP_RATE:
+ {
+ CHECK_ERROR(machine, COMSETTER(VideoCaptureRate)(ValueUnion.u32));
+ break;
+ }
+ case MODIFYVM_VCP_FPS:
+ {
+ CHECK_ERROR(machine, COMSETTER(VideoCaptureFPS)(ValueUnion.u32));
+ break;
+ }
#endif
case MODIFYVM_AUTOSTART_ENABLED:
{
@@ -2486,6 +2684,7 @@ int handleModifyVM(HandlerArg *a)
break;
}
#endif
+
#ifdef VBOX_WITH_USB_CARDREADER
case MODIFYVM_USBCARDREADER:
{
@@ -2494,6 +2693,15 @@ int handleModifyVM(HandlerArg *a)
}
#endif /* VBOX_WITH_USB_CARDREADER */
+ case MODIFYVM_DEFAULTFRONTEND:
+ {
+ Bstr bstr(ValueUnion.psz);
+ if (bstr == "default")
+ bstr = Bstr::Empty;
+ CHECK_ERROR(machine, COMSETTER(DefaultFrontend)(bstr.raw()));
+ break;
+ }
+
default:
{
errorGetOpt(USAGE_MODIFYVM, c, &ValueUnion);
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageNATNetwork.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageNATNetwork.cpp
new file mode 100644
index 00000000..ef4f916e
--- /dev/null
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageNATNetwork.cpp
@@ -0,0 +1,490 @@
+/* $Id: VBoxManageNATNetwork.cpp $ */
+/** @file
+ * VBoxManage - Implementation of NAT Network command command.
+ */
+
+/*
+ * Copyright (C) 2006-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;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * 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 *
+*******************************************************************************/
+#ifndef VBOX_ONLY_DOCS
+
+#include <VBox/com/com.h>
+#include <VBox/com/array.h>
+#include <VBox/com/ErrorInfo.h>
+#include <VBox/com/errorprint.h>
+#include <VBox/com/VirtualBox.h>
+#endif /* !VBOX_ONLY_DOCS */
+
+#ifndef RT_OS_WINDOWS
+# include <netinet/in.h>
+#else
+/* from <ws2ipdef.h> */
+# define INET6_ADDRSTRLEN 65
+#endif
+
+#define IPv6
+
+#include <iprt/cdefs.h>
+#include <iprt/cidr.h>
+#include <iprt/param.h>
+#include <iprt/path.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/net.h>
+#include <iprt/getopt.h>
+#include <iprt/ctype.h>
+
+#include <VBox/log.h>
+
+#include <vector>
+#include <string>
+
+#include "VBoxManage.h"
+#include "VBoxPortForwardString.h"
+
+#ifndef VBOX_ONLY_DOCS
+
+using namespace com;
+
+typedef enum enMainOpCodes
+{
+ OP_ADD = 1000,
+ OP_REMOVE,
+ OP_MODIFY,
+ OP_START,
+ OP_STOP
+} OPCODE;
+
+static const RTGETOPTDEF g_aNATNetworkIPOptions[]
+ = {
+ { "--netname", 't', RTGETOPT_REQ_STRING },
+ { "--network", 'n', RTGETOPT_REQ_STRING },
+ { "--dhcp", 'h', RTGETOPT_REQ_BOOL },
+ { "--ipv6", '6', RTGETOPT_REQ_BOOL},
+ { "--enable", 'e', RTGETOPT_REQ_NOTHING },
+ { "--disable", 'd', RTGETOPT_REQ_NOTHING },
+ { "--port-forward-4", 'p', RTGETOPT_REQ_STRING },
+ { "--port-forward-6", 'P', RTGETOPT_REQ_STRING },
+ { "--loopback-4", 'l', RTGETOPT_REQ_STRING },
+ { "--loopback-6", 'L', RTGETOPT_REQ_STRING },
+
+ };
+
+typedef struct PFNAME2DELETE
+{
+ char szName[PF_NAMELEN];
+ bool fIPv6;
+} PFNAME2DELETE, *PPFNAME2DELETE;
+
+typedef std::vector<PFNAME2DELETE> VPF2DELETE;
+typedef VPF2DELETE::const_iterator VPF2DELETEITERATOR;
+
+typedef std::vector<PORTFORWARDRULE> VPF2ADD;
+typedef VPF2ADD::const_iterator VPF2ADDITERATOR;
+
+typedef std::vector<std::string> LOOPBACK2DELETEADD;
+typedef LOOPBACK2DELETEADD::iterator LOOPBACK2DELETEADDITERATOR;
+
+static int handleOp(HandlerArg *a, OPCODE enmCode, int iStart, int *pcProcessed)
+{
+ if (a->argc - iStart < 2)
+ return errorSyntax(USAGE_NATNETWORK, "Not enough parameters");
+
+ int index = iStart;
+ HRESULT rc;
+
+ const char *pNetName = NULL;
+ const char *pNetworkCidr = NULL;
+ int enable = -1;
+ int dhcp = -1;
+ int ipv6 = -1;
+
+ VPF2DELETE vPfName2Delete;
+ VPF2ADD vPf2Add;
+
+ LOOPBACK2DELETEADD vLoopback2Delete;
+ LOOPBACK2DELETEADD vLoopback2Add;
+
+ LONG loopback6Offset = 0; /* ignore me */
+
+ int c;
+ RTGETOPTUNION ValueUnion;
+ RTGETOPTSTATE GetState;
+
+ RTGetOptInit(&GetState,
+ a->argc,
+ a->argv,
+ g_aNATNetworkIPOptions,
+ enmCode != OP_REMOVE ? RT_ELEMENTS(g_aNATNetworkIPOptions) : 4, /* we use only --netname and --ifname for remove*/
+ index,
+ RTGETOPTINIT_FLAGS_NO_STD_OPTS);
+ while ((c = RTGetOpt(&GetState, &ValueUnion)))
+ {
+ switch (c)
+ {
+ case 't': // --netname
+ if (pNetName)
+ return errorSyntax(USAGE_NATNETWORK, "You can only specify --netname only once.");
+ else
+ pNetName = ValueUnion.psz;
+ break;
+
+ case 'n': // --network
+ if (pNetworkCidr)
+ return errorSyntax(USAGE_NATNETWORK, "You can only specify --network only once.");
+ else
+ pNetworkCidr = ValueUnion.psz;
+ break;
+
+ case 'e': // --enable
+ if (enable >= 0)
+ return errorSyntax(USAGE_NATNETWORK, "You can specify either --enable or --disable once.");
+ else
+ enable = 1;
+ break;
+
+ case 'd': // --disable
+ if (enable >= 0)
+ return errorSyntax(USAGE_NATNETWORK, "You can specify either --enable or --disable once.");
+ else
+ enable = 0;
+ break;
+
+ case 'h':
+ if (dhcp != -1)
+ return errorSyntax(USAGE_NATNETWORK, "You can specify --dhcp only once.");
+ dhcp = ValueUnion.f;
+ break;
+
+ case '6':
+ if (ipv6 != -1)
+ return errorSyntax(USAGE_NATNETWORK, "You can specify --ipv6 only once.");
+ ipv6 = ValueUnion.f;
+ break;
+
+ case 'L': /* ipv6 loopback */
+ case 'l': /* ipv4 loopback */
+ if (RTStrCmp(ValueUnion.psz, "delete") == 0)
+ {
+ /* deletion */
+ if (enmCode != OP_MODIFY)
+ errorSyntax(USAGE_NATNETWORK,
+ "loopback couldn't be deleted on modified\n");
+ if (c == 'L')
+ loopback6Offset = -1;
+ else
+ {
+ int vrc;
+ RTGETOPTUNION Addr2Delete;
+ vrc = RTGetOptFetchValue(&GetState,
+ &Addr2Delete,
+ RTGETOPT_REQ_STRING);
+ if (RT_FAILURE(vrc))
+ return errorSyntax(USAGE_NATNETWORK,
+ "Not enough parmaters\n");
+
+ vLoopback2Delete.push_back(std::string(Addr2Delete.psz));
+ }
+ }
+ else /* addition */
+ {
+ if (c == 'L')
+ loopback6Offset = ValueUnion.u32;
+ else
+ vLoopback2Add.push_back(std::string(ValueUnion.psz));
+ }
+ break;
+
+ case 'P': /* ipv6 portforwarding*/
+ case 'p': /* ipv4 portforwarding */
+ {
+ if (RTStrCmp(ValueUnion.psz, "delete") != 0)
+ {
+ PORTFORWARDRULE Pfr;
+
+ /* netPfStrToPf will clean up the Pfr */
+ int irc = netPfStrToPf(ValueUnion.psz, (c == 'P'), &Pfr);
+ if (RT_FAILURE(irc))
+ return errorSyntax(USAGE_NATNETWORK,
+ "Invalid port-forward rule %s\n",
+ ValueUnion.psz);
+
+ vPf2Add.push_back(Pfr);
+ }
+ else
+ {
+ int vrc;
+ RTGETOPTUNION NamePf2DeleteUnion;
+ PFNAME2DELETE Name2Delete;
+
+ if (enmCode != OP_MODIFY)
+ return errorSyntax(USAGE_NATNETWORK,
+ "Port-forward could be deleted on modify \n");
+
+ vrc = RTGetOptFetchValue(&GetState,
+ &NamePf2DeleteUnion,
+ RTGETOPT_REQ_STRING);
+ if (RT_FAILURE(vrc))
+ return errorSyntax(USAGE_NATNETWORK,
+ "Not enough parmaters\n");
+
+ if (strlen(NamePf2DeleteUnion.psz) > PF_NAMELEN)
+ return errorSyntax(USAGE_NATNETWORK,
+ "Port-forward rule name is too long\n");
+
+ RT_ZERO(Name2Delete);
+ RTStrCopy(Name2Delete.szName, PF_NAMELEN, NamePf2DeleteUnion.psz);
+ Name2Delete.fIPv6 = (c == 'P');
+
+ vPfName2Delete.push_back(Name2Delete);
+ }
+ break;
+ }
+
+ case VINF_GETOPT_NOT_OPTION:
+ return errorSyntax(USAGE_NATNETWORK,
+ "unhandled parameter: %s",
+ ValueUnion.psz);
+
+ default:
+ if (c > 0)
+ {
+ if (RT_C_IS_GRAPH(c))
+ return errorSyntax(USAGE_NATNETWORK,
+ "unhandled option: -%c", c);
+ else
+ return errorSyntax(USAGE_NATNETWORK,
+ "unhandled option: %i", c);
+ }
+ else if (c == VERR_GETOPT_UNKNOWN_OPTION)
+ return errorSyntax(USAGE_NATNETWORK,
+ "unknown option: %s", ValueUnion.psz);
+ else if (ValueUnion.pDef)
+ return errorSyntax(USAGE_NATNETWORK,
+ "%s: %Rrs", ValueUnion.pDef->pszLong, c);
+ else
+ return errorSyntax(USAGE_NATNETWORK, "%Rrs", c);
+ }
+ }
+
+ if (!pNetName)
+ return errorSyntax(USAGE_NATNETWORK,
+ "You need to specify the --netname option");
+ /* verification */
+ switch (enmCode)
+ {
+ case OP_ADD:
+ if (!pNetworkCidr)
+ return errorSyntax(USAGE_NATNETWORK,
+ "You need to specify the --network option");
+ break;
+ case OP_MODIFY:
+ case OP_REMOVE:
+ case OP_START:
+ case OP_STOP:
+ break;
+ default:
+ AssertMsgFailedReturn(("Unknown operation (:%d)", enmCode), VERR_NOT_IMPLEMENTED);
+ }
+
+ Bstr NetName;
+ NetName = Bstr(pNetName);
+
+ ComPtr<INATNetwork> net;
+ rc = a->virtualBox->FindNATNetworkByName(NetName.mutableRaw(), net.asOutParam());
+ if (enmCode == OP_ADD)
+ {
+ if (SUCCEEDED(rc))
+ return errorArgument("NATNetwork server already exists");
+
+ CHECK_ERROR(a->virtualBox, CreateNATNetwork(NetName.raw(), net.asOutParam()));
+ if (FAILED(rc))
+ return errorArgument("Failed to create the NAT network service");
+ }
+ else if (FAILED(rc))
+ return errorArgument("NATNetwork server does not exist");
+
+ switch (enmCode)
+ {
+ case OP_ADD:
+ case OP_MODIFY:
+ {
+ if (pNetworkCidr)
+ {
+ CHECK_ERROR(net, COMSETTER(Network)(Bstr(pNetworkCidr).raw()));
+ if (FAILED(rc))
+ return errorArgument("Failed to set configuration");
+ }
+ if (dhcp >= 0)
+ {
+ CHECK_ERROR(net, COMSETTER(NeedDhcpServer) ((BOOL)dhcp));
+ if (FAILED(rc))
+ return errorArgument("Failed to set configuration");
+ }
+
+ if (ipv6 >= 0)
+ {
+ CHECK_ERROR(net, COMSETTER(IPv6Enabled) ((BOOL)ipv6));
+ if (FAILED(rc))
+ return errorArgument("Failed to set configuration");
+ }
+
+ if (!vPfName2Delete.empty())
+ {
+ VPF2DELETEITERATOR it;
+ for (it = vPfName2Delete.begin(); it != vPfName2Delete.end(); ++it)
+ {
+ CHECK_ERROR(net, RemovePortForwardRule((BOOL)(*it).fIPv6,
+ Bstr((*it).szName).raw()));
+ if (FAILED(rc))
+ return errorArgument("Failed to delete pf");
+ }
+ }
+
+ if (!vPf2Add.empty())
+ {
+ VPF2ADDITERATOR it;
+ for (it = vPf2Add.begin(); it != vPf2Add.end(); ++it)
+ {
+ NATProtocol_T proto = NATProtocol_TCP;
+ if ((*it).iPfrProto == IPPROTO_TCP)
+ proto = NATProtocol_TCP;
+ else if ((*it).iPfrProto == IPPROTO_UDP)
+ proto = NATProtocol_UDP;
+ else
+ continue; /* XXX: warning here. */
+
+ CHECK_ERROR(net, AddPortForwardRule((BOOL)(*it).fPfrIPv6,
+ Bstr((*it).szPfrName).raw(),
+ proto,
+ Bstr((*it).szPfrHostAddr).raw(),
+ (*it).u16PfrHostPort,
+ Bstr((*it).szPfrGuestAddr).raw(),
+ (*it).u16PfrGuestPort));
+ if (FAILED(rc))
+ return errorArgument("Failed to add pf");
+ }
+ }
+
+ if (loopback6Offset)
+ {
+ if (loopback6Offset == -1)
+ loopback6Offset = 0; /* deletion */
+
+ CHECK_ERROR_RET(net, COMSETTER(LoopbackIp6)(loopback6Offset), rc);
+ }
+
+ /* addLocalMapping (hostid, offset) */
+ if (!vLoopback2Add.empty())
+ {
+ /* we're expecting stings 127.0.0.1=5 */
+ LOOPBACK2DELETEADDITERATOR it;
+ for (it = vLoopback2Add.begin();
+ it != vLoopback2Add.end();
+ ++it)
+ {
+ std::string address, strOffset;
+ int pos = it->find('=');
+ LONG lOffset = 0;
+ Bstr bstrAddress;
+
+ AssertReturn(pos != -1, errorArgument("invalid loopback string"));
+
+ address = it->substr(0, pos);
+ strOffset = it->substr(pos + 1);
+
+ lOffset = RTStrToUInt32(strOffset.c_str());
+ AssertReturn(lOffset > 0, errorArgument("invalid loopback string"));
+
+ bstrAddress = Bstr(address.c_str());
+
+ CHECK_ERROR_RET(net, AddLocalMapping(bstrAddress.raw(), lOffset), rc);
+ }
+ }
+
+ if (!vLoopback2Delete.empty())
+ {
+ /* we're expecting stings 127.0.0.1 */
+ LOOPBACK2DELETEADDITERATOR it;
+ for (it = vLoopback2Add.begin();
+ it != vLoopback2Add.end();
+ ++it)
+ {
+ Bstr bstrAddress;
+ bstrAddress = Bstr(it->c_str());
+
+ CHECK_ERROR_RET(net, AddLocalMapping(bstrAddress.raw(), 0), rc);
+ }
+ }
+
+ if (enable >= 0)
+ {
+ CHECK_ERROR(net, COMSETTER(Enabled) ((BOOL)enable));
+ if (FAILED(rc))
+ return errorArgument("Failed to set configuration");
+ }
+ break;
+ }
+ case OP_REMOVE:
+ {
+ CHECK_ERROR(a->virtualBox, RemoveNATNetwork(net));
+ if (FAILED(rc))
+ return errorArgument("Failed to remove nat network");
+ break;
+ }
+ case OP_START:
+ {
+ CHECK_ERROR(net, Start(Bstr("whatever").raw()));
+ if (FAILED(rc))
+ return errorArgument("Failed to start network");
+ break;
+ }
+ case OP_STOP:
+ {
+ CHECK_ERROR(net, Stop());
+ if (FAILED(rc))
+ return errorArgument("Failed to start network");
+ break;
+ }
+ default:;
+ }
+ return 0;
+}
+
+
+int handleNATNetwork(HandlerArg *a)
+{
+ if (a->argc < 1)
+ return errorSyntax(USAGE_NATNETWORK, "Not enough parameters");
+
+ int result;
+ int cProcessed;
+ if (strcmp(a->argv[0], "modify") == 0)
+ result = handleOp(a, OP_MODIFY, 1, &cProcessed);
+ else if (strcmp(a->argv[0], "add") == 0)
+ result = handleOp(a, OP_ADD, 1, &cProcessed);
+ else if (strcmp(a->argv[0], "remove") == 0)
+ result = handleOp(a, OP_REMOVE, 1, &cProcessed);
+ else if (strcmp(a->argv[0], "start") == 0)
+ result = handleOp(a, OP_START, 1, &cProcessed);
+ else if (strcmp(a->argv[0], "stop") == 0)
+ result = handleOp(a, OP_STOP, 1, &cProcessed);
+ else
+ result = errorSyntax(USAGE_NATNETWORK, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
+
+ return result;
+}
+
+#endif /* !VBOX_ONLY_DOCS */
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp
index b76b94ba..1ac7dddd 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageSnapshot.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -306,13 +306,14 @@ int handleSnapshot(HandlerArg *a)
/* parse the optional arguments */
Bstr desc;
- bool fPause = false;
+ bool fPause = true; /* default is NO live snapshot */
static const RTGETOPTDEF s_aTakeOptions[] =
{
{ "--description", 'd', RTGETOPT_REQ_STRING },
{ "-description", 'd', RTGETOPT_REQ_STRING },
{ "-desc", 'd', RTGETOPT_REQ_STRING },
- { "--pause", 'p', RTGETOPT_REQ_NOTHING }
+ { "--pause", 'p', RTGETOPT_REQ_NOTHING },
+ { "--live", 'l', RTGETOPT_REQ_NOTHING }
};
RTGETOPTSTATE GetOptState;
RTGetOptInit(&GetOptState, a->argc, a->argv, s_aTakeOptions, RT_ELEMENTS(s_aTakeOptions),
@@ -328,6 +329,10 @@ int handleSnapshot(HandlerArg *a)
fPause = true;
break;
+ case 'l':
+ fPause = false;
+ break;
+
case 'd':
desc = Value.psz;
break;
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageStorageController.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageStorageController.cpp
index 8bafaae6..2de0befe 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageStorageController.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageStorageController.cpp
@@ -101,6 +101,8 @@ int handleStorageAttach(HandlerArg *a)
Bstr bstrUsername;
Bstr bstrPassword;
Bstr bstrInitiator;
+ Bstr bstrIso;
+ Utf8Str strIso;
bool fIntNet = false;
RTGETOPTUNION ValueUnion;
@@ -138,7 +140,7 @@ int handleStorageAttach(HandlerArg *a)
break;
}
- case 'm': // medium <none|emptydrive|uuid|filename|host:<drive>|iSCSI>
+ case 'm': // medium <none|emptydrive|additions|uuid|filename|host:<drive>|iSCSI>
{
if (ValueUnion.psz)
pszMedium = ValueUnion.psz;
@@ -192,7 +194,7 @@ int handleStorageAttach(HandlerArg *a)
break;
}
- case 'u': // nonrotational <on|off>
+ case 'u': // discard <on|off>
{
if (ValueUnion.psz)
pszDiscard = ValueUnion.psz;
@@ -482,9 +484,25 @@ int handleStorageAttach(HandlerArg *a)
if (pszMedium)
{
+ if (!RTStrICmp(pszMedium, "additions"))
+ {
+ ComPtr<ISystemProperties> pProperties;
+ CHECK_ERROR(a->virtualBox,
+ COMGETTER(SystemProperties)(pProperties.asOutParam()));
+ CHECK_ERROR(pProperties, COMGETTER(DefaultAdditionsISO)(bstrIso.asOutParam()));
+ strIso = Utf8Str(bstrIso);
+ if (strIso.isEmpty())
+ throw Utf8Str("Cannot find the Guest Additions ISO image\n");
+ pszMedium = strIso.c_str();
+ if (devTypeRequested == DeviceType_Null)
+ devTypeRequested = DeviceType_DVD;
+ }
ComPtr<IMedium> pExistingMedium;
- rc = findMedium(a, pszMedium, deviceType, true /* fSilent */,
- pExistingMedium);
+ rc = openMedium(a, pszMedium, deviceType,
+ AccessMode_ReadWrite,
+ pExistingMedium,
+ false /* fForceNewUuidOnOpen */,
+ true /* fSilent */);
if (SUCCEEDED(rc) && pExistingMedium)
{
if ( (deviceType == DeviceType_DVD)
@@ -601,7 +619,7 @@ int handleStorageAttach(HandlerArg *a)
Bstr("InitiatorSecret").detachTo(names.appendedRaw());
bstrPassword.detachTo(values.appendedRaw());
}
- if (!bstrPassword.isEmpty())
+ if (!bstrInitiator.isEmpty())
{
Bstr("InitiatorName").detachTo(names.appendedRaw());
bstrInitiator.detachTo(values.appendedRaw());
@@ -637,9 +655,9 @@ int handleStorageAttach(HandlerArg *a)
else
{
Bstr bstrMedium(pszMedium);
- rc = findOrOpenMedium(a, pszMedium, devTypeRequested,
- AccessMode_ReadWrite, pMedium2Mount,
- fSetNewUuid, NULL);
+ rc = openMedium(a, pszMedium, devTypeRequested,
+ AccessMode_ReadWrite, pMedium2Mount,
+ fSetNewUuid, false /* fSilent */);
if (FAILED(rc) || !pMedium2Mount)
throw Utf8StrFmt("Invalid UUID or filename \"%s\"", pszMedium);
}
@@ -888,7 +906,7 @@ static const RTGETOPTDEF g_aStorageControllerOptions[] =
{ "--name", 'n', RTGETOPT_REQ_STRING },
{ "--add", 'a', RTGETOPT_REQ_STRING },
{ "--controller", 'c', RTGETOPT_REQ_STRING },
- { "--sataportcount", 'p', RTGETOPT_REQ_UINT32 },
+ { "--portcount", 'p', RTGETOPT_REQ_UINT32 },
{ "--remove", 'r', RTGETOPT_REQ_NOTHING },
{ "--hostiocache", 'i', RTGETOPT_REQ_STRING },
{ "--bootable", 'b', RTGETOPT_REQ_STRING },
@@ -905,7 +923,7 @@ int handleStorageController(HandlerArg *a)
const char *pszBootable = NULL;
ULONG satabootdev = ~0U;
ULONG sataidedev = ~0U;
- ULONG sataportcount = ~0U;
+ ULONG portcount = ~0U;
bool fRemoveCtl = false;
ComPtr<IMachine> machine;
RTGETOPTUNION ValueUnion;
@@ -949,9 +967,9 @@ int handleStorageController(HandlerArg *a)
break;
}
- case 'p': // sataportcount
+ case 'p': // portcount
{
- sataportcount = ValueUnion.u32;
+ portcount = ValueUnion.u32;
break;
}
@@ -1105,7 +1123,7 @@ int handleStorageController(HandlerArg *a)
}
}
- if ( (sataportcount != ~0U)
+ if ( (portcount != ~0U)
&& SUCCEEDED(rc))
{
ComPtr<IStorageController> ctl;
@@ -1115,7 +1133,7 @@ int handleStorageController(HandlerArg *a)
if (SUCCEEDED(rc))
{
- CHECK_ERROR(ctl, COMSETTER(PortCount)(sataportcount));
+ CHECK_ERROR(ctl, COMSETTER(PortCount)(portcount));
}
else
{
diff --git a/src/VBox/Frontends/VBoxManage/VBoxManageUSB.cpp b/src/VBox/Frontends/VBoxManage/VBoxManageUSB.cpp
index 91d98781..08f0d433 100644
--- a/src/VBox/Frontends/VBoxManage/VBoxManageUSB.cpp
+++ b/src/VBox/Frontends/VBoxManage/VBoxManageUSB.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * Copyright (C) 2006-2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -21,25 +21,12 @@
#include <VBox/com/array.h>
#include <VBox/com/ErrorInfo.h>
#include <VBox/com/errorprint.h>
-#include <VBox/com/EventQueue.h>
-
#include <VBox/com/VirtualBox.h>
#include "VBoxManage.h"
#include <iprt/asm.h>
-/* missing XPCOM <-> COM wrappers */
-#ifndef STDMETHOD_
-# define STDMETHOD_(ret, meth) NS_IMETHOD_(ret) meth
-#endif
-#ifndef NS_GET_IID
-# define NS_GET_IID(I) IID_##I
-#endif
-#ifndef RT_OS_WINDOWS
-#define IUnknown nsISupports
-#endif
-
using namespace com;
/**
@@ -72,13 +59,13 @@ public:
STDMETHOD(QueryInterface)(const IID &iid, void **ppvObject)
{
Guid guid(iid);
- if (guid == Guid(NS_GET_IID(IUnknown)))
+ if (guid == Guid(COM_IIDOF(IUnknown)))
*ppvObject = (IUnknown *)this;
#ifdef RT_OS_WINDOWS
- else if (guid == Guid(NS_GET_IID(IDispatch)))
+ else if (guid == Guid(COM_IIDOF(IDispatch)))
*ppvObject = (IDispatch *)this;
#endif
- else if (guid == Guid(NS_GET_IID(IUSBDevice)))
+ else if (guid == Guid(COM_IIDOF(IUSBDevice)))
*ppvObject = (IUSBDevice *)this;
else
return E_NOINTERFACE;
@@ -400,18 +387,18 @@ int handleUSBFilter(HandlerArg *a)
USBFilterCmd::USBFilter &f = cmd.mFilter;
- ComPtr <IHost> host;
- ComPtr <IUSBController> ctl;
+ ComPtr<IHost> host;
+ ComPtr<IUSBDeviceFilters> flts;
if (cmd.mGlobal)
CHECK_ERROR_RET(a->virtualBox, COMGETTER(Host)(host.asOutParam()), 1);
else
{
/* open a session for the VM */
- CHECK_ERROR_RET(cmd.mMachine, LockMachine(a->session, LockType_Write), 1);
+ CHECK_ERROR_RET(cmd.mMachine, LockMachine(a->session, LockType_Shared), 1);
/* get the mutable session machine */
a->session->COMGETTER(Machine)(cmd.mMachine.asOutParam());
- /* and get the USB controller */
- CHECK_ERROR_RET(cmd.mMachine, COMGETTER(USBController)(ctl.asOutParam()), 1);
+ /* and get the USB device filters */
+ CHECK_ERROR_RET(cmd.mMachine, COMGETTER(USBDeviceFilters)(flts.asOutParam()), 1);
}
switch (cmd.mAction)
@@ -420,7 +407,7 @@ int handleUSBFilter(HandlerArg *a)
{
if (cmd.mGlobal)
{
- ComPtr <IHostUSBDeviceFilter> flt;
+ ComPtr<IHostUSBDeviceFilter> flt;
CHECK_ERROR_BREAK(host, CreateUSBDeviceFilter(f.mName.raw(),
flt.asOutParam()));
@@ -446,8 +433,8 @@ int handleUSBFilter(HandlerArg *a)
}
else
{
- ComPtr <IUSBDeviceFilter> flt;
- CHECK_ERROR_BREAK(ctl, CreateDeviceFilter(f.mName.raw(),
+ ComPtr<IUSBDeviceFilter> flt;
+ CHECK_ERROR_BREAK(flts, CreateDeviceFilter(f.mName.raw(),
flt.asOutParam()));
if (!f.mActive.isNull())
@@ -467,7 +454,7 @@ int handleUSBFilter(HandlerArg *a)
if (!f.mMaskedInterfaces.isNull())
CHECK_ERROR_BREAK(flt, COMSETTER(MaskedInterfaces)(f.mMaskedInterfaces));
- CHECK_ERROR_BREAK(ctl, InsertDeviceFilter(cmd.mIndex, flt));
+ CHECK_ERROR_BREAK(flts, InsertDeviceFilter(cmd.mIndex, flt));
}
break;
}
@@ -478,7 +465,7 @@ int handleUSBFilter(HandlerArg *a)
SafeIfaceArray <IHostUSBDeviceFilter> coll;
CHECK_ERROR_BREAK(host, COMGETTER(USBDeviceFilters)(ComSafeArrayAsOutParam(coll)));
- ComPtr <IHostUSBDeviceFilter> flt = coll[cmd.mIndex];
+ ComPtr<IHostUSBDeviceFilter> flt = coll[cmd.mIndex];
if (!f.mName.isEmpty())
CHECK_ERROR_BREAK(flt, COMSETTER(Name)(f.mName.raw()));
@@ -503,9 +490,9 @@ int handleUSBFilter(HandlerArg *a)
else
{
SafeIfaceArray <IUSBDeviceFilter> coll;
- CHECK_ERROR_BREAK(ctl, COMGETTER(DeviceFilters)(ComSafeArrayAsOutParam(coll)));
+ CHECK_ERROR_BREAK(flts, COMGETTER(DeviceFilters)(ComSafeArrayAsOutParam(coll)));
- ComPtr <IUSBDeviceFilter> flt = coll[cmd.mIndex];
+ ComPtr<IUSBDeviceFilter> flt = coll[cmd.mIndex];
if (!f.mName.isEmpty())
CHECK_ERROR_BREAK(flt, COMSETTER(Name)(f.mName.raw()));
@@ -532,13 +519,13 @@ int handleUSBFilter(HandlerArg *a)
{
if (cmd.mGlobal)
{
- ComPtr <IHostUSBDeviceFilter> flt;
+ ComPtr<IHostUSBDeviceFilter> flt;
CHECK_ERROR_BREAK(host, RemoveUSBDeviceFilter(cmd.mIndex));
}
else
{
- ComPtr <IUSBDeviceFilter> flt;
- CHECK_ERROR_BREAK(ctl, RemoveDeviceFilter(cmd.mIndex, flt.asOutParam()));
+ ComPtr<IUSBDeviceFilter> flt;
+ CHECK_ERROR_BREAK(flts, RemoveDeviceFilter(cmd.mIndex, flt.asOutParam()));
}
break;
}