summaryrefslogtreecommitdiff
path: root/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp')
-rw-r--r--src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp188
1 files changed, 187 insertions, 1 deletions
diff --git a/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp b/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp
index a2ee69ae..19d814ae 100644
--- a/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp
+++ b/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp
@@ -26,6 +26,7 @@
#include <iprt/stream.h>
#include <iprt/log.h>
#include <iprt/assert.h>
+#include <iprt/message.h>
#include <algorithm>
#include <list>
@@ -35,11 +36,196 @@
using namespace com;
+/**
+ * VM list entry.
+ */
+typedef struct AUTOSTOPVM
+{
+ /** ID of the VM to start. */
+ Bstr strId;
+ /** Action to do with the VM. */
+ AutostopType_T enmAutostopType;
+} AUTOSTOPVM;
+
+static HRESULT autostartSaveVMState(ComPtr<IConsole> &console)
+{
+ HRESULT rc = S_OK;
+ ComPtr<IProgress> progress;
+
+ do
+ {
+ /* first pause so we don't trigger a live save which needs more time/resources */
+ bool fPaused = false;
+ rc = console->Pause();
+ if (FAILED(rc))
+ {
+ bool fError = true;
+ if (rc == VBOX_E_INVALID_VM_STATE)
+ {
+ /* check if we are already paused */
+ MachineState_T machineState;
+ CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
+ /* the error code was lost by the previous instruction */
+ rc = VBOX_E_INVALID_VM_STATE;
+ if (machineState != MachineState_Paused)
+ {
+ RTMsgError("Machine in invalid state %d -- %s\n",
+ machineState, machineStateToName(machineState, false));
+ }
+ else
+ {
+ fError = false;
+ fPaused = true;
+ }
+ }
+ if (fError)
+ break;
+ }
+
+ CHECK_ERROR(console, SaveState(progress.asOutParam()));
+ if (FAILED(rc))
+ {
+ if (!fPaused)
+ console->Resume();
+ break;
+ }
+
+ rc = showProgress(progress);
+ CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state"));
+ if (FAILED(rc))
+ {
+ if (!fPaused)
+ console->Resume();
+ }
+ } while (0);
+
+ return rc;
+}
+
DECLHIDDEN(RTEXITCODE) autostartStopMain(PCFGAST pCfgAst)
{
RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ int vrc = VINF_SUCCESS;
+ std::list<AUTOSTOPVM> listVM;
+
+ /*
+ * Build a list of all VMs we need to autostop first, apply the overrides
+ * from the configuration and start the VMs afterwards.
+ */
+ com::SafeIfaceArray<IMachine> machines;
+ HRESULT rc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
+ if (SUCCEEDED(rc))
+ {
+ /*
+ * Iterate through the collection and construct a list of machines
+ * we have to check.
+ */
+ for (size_t i = 0; i < machines.size(); ++i)
+ {
+ if (machines[i])
+ {
+ BOOL fAccessible;
+ CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
+ if (!fAccessible)
+ continue;
+
+ AutostopType_T enmAutostopType;
+ CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostopType)(&enmAutostopType));
+ if (enmAutostopType != AutostopType_Disabled)
+ {
+ AUTOSTOPVM autostopVM;
+
+ CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(autostopVM.strId.asOutParam()));
+ autostopVM.enmAutostopType = enmAutostopType;
+
+ listVM.push_back(autostopVM);
+ }
+ }
+ }
+
+ if ( SUCCEEDED(rc)
+ && listVM.size())
+ {
+ std::list<AUTOSTOPVM>::iterator it;
+ for (it = listVM.begin(); it != listVM.end(); it++)
+ {
+ MachineState_T enmMachineState;
+ ComPtr<IMachine> machine;
+
+ CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(),
+ machine.asOutParam()));
+
+ CHECK_ERROR_BREAK(machine, COMGETTER(State)(&enmMachineState));
+
+ /* Wait until the VM changes from a transient state back. */
+ while ( enmMachineState >= MachineState_FirstTransient
+ && enmMachineState <= MachineState_LastTransient)
+ {
+ RTThreadSleep(1000);
+ CHECK_ERROR_BREAK(machine, COMGETTER(State)(&enmMachineState));
+ }
+
+ /* Only power off running machines. */
+ if ( enmMachineState == MachineState_Running
+ || enmMachineState == MachineState_Paused)
+ {
+ ComPtr<IConsole> console;
+ ComPtr<IProgress> progress;
+
+ /* open a session for the VM */
+ CHECK_ERROR_BREAK(machine, LockMachine(g_pSession, LockType_Shared));
+
+ /* get the associated console */
+ CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
+
+ switch ((*it).enmAutostopType)
+ {
+ case AutostopType_SaveState:
+ {
+ rc = autostartSaveVMState(console);
+ break;
+ }
+ case AutostopType_PowerOff:
+ {
+ CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
+
+ rc = showProgress(progress);
+ CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine"));
+ break;
+ }
+ case AutostopType_AcpiShutdown:
+ {
+ BOOL fGuestEnteredACPI = false;
+ CHECK_ERROR_BREAK(console, GetGuestEnteredACPIMode(&fGuestEnteredACPI));
+ if (fGuestEnteredACPI && enmMachineState == MachineState_Running)
+ {
+ CHECK_ERROR_BREAK(console, PowerButton());
+
+ autostartSvcLogInfo("Waiting for VM \"%ls\" to power off...\n", (*it).strId.raw());
- AssertMsgFailed(("Not implemented yet!\n"));
+ do
+ {
+ RTThreadSleep(1000);
+ CHECK_ERROR_BREAK(machine, COMGETTER(State)(&enmMachineState));
+ } while (enmMachineState == MachineState_Running);
+ }
+ else
+ {
+ /* Use save state instead and log this to the console. */
+ autostartSvcLogWarning("The guest of VM \"%ls\" does not support ACPI shutdown or is currently paused, saving state...\n",
+ (*it).strId.raw());
+ rc = autostartSaveVMState(console);
+ }
+ break;
+ }
+ default:
+ autostartSvcLogWarning("Unknown autostop type for VM \"%ls\"\n", (*it).strId.raw());
+ }
+ g_pSession->UnlockMachine();
+ }
+ }
+ }
+ }
return rcExit;
}