VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp@ 74942

Last change on this file since 74942 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1/* $Id: VBoxAutostartStop.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 * VBoxAutostart - VirtualBox Autostart service, stop machines during system shutdown.
4 */
5
6/*
7 * Copyright (C) 2012-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <VBox/com/com.h>
19#include <VBox/com/string.h>
20#include <VBox/com/Guid.h>
21#include <VBox/com/array.h>
22#include <VBox/com/ErrorInfo.h>
23#include <VBox/com/errorprint.h>
24
25#include <iprt/thread.h>
26#include <iprt/stream.h>
27#include <iprt/log.h>
28#include <iprt/assert.h>
29#include <iprt/message.h>
30
31#include <algorithm>
32#include <list>
33#include <string>
34
35#include "VBoxAutostart.h"
36
37using namespace com;
38
39/**
40 * VM list entry.
41 */
42typedef struct AUTOSTOPVM
43{
44 /** ID of the VM to start. */
45 Bstr strId;
46 /** Action to do with the VM. */
47 AutostopType_T enmAutostopType;
48} AUTOSTOPVM;
49
50static HRESULT autostartSaveVMState(ComPtr<IConsole> &console)
51{
52 HRESULT rc = S_OK;
53 ComPtr<IMachine> machine;
54 ComPtr<IProgress> progress;
55
56 do
57 {
58 /* first pause so we don't trigger a live save which needs more time/resources */
59 bool fPaused = false;
60 rc = console->Pause();
61 if (FAILED(rc))
62 {
63 bool fError = true;
64 if (rc == VBOX_E_INVALID_VM_STATE)
65 {
66 /* check if we are already paused */
67 MachineState_T machineState;
68 CHECK_ERROR_BREAK(console, COMGETTER(State)(&machineState));
69 /* the error code was lost by the previous instruction */
70 rc = VBOX_E_INVALID_VM_STATE;
71 if (machineState != MachineState_Paused)
72 {
73 RTMsgError("Machine in invalid state %d -- %s\n",
74 machineState, machineStateToName(machineState, false));
75 }
76 else
77 {
78 fError = false;
79 fPaused = true;
80 }
81 }
82 if (fError)
83 break;
84 }
85
86 CHECK_ERROR(console, COMGETTER(Machine)(machine.asOutParam()));
87 CHECK_ERROR(machine, SaveState(progress.asOutParam()));
88 if (FAILED(rc))
89 {
90 if (!fPaused)
91 console->Resume();
92 break;
93 }
94
95 rc = showProgress(progress);
96 CHECK_PROGRESS_ERROR(progress, ("Failed to save machine state"));
97 if (FAILED(rc))
98 {
99 if (!fPaused)
100 console->Resume();
101 }
102 } while (0);
103
104 return rc;
105}
106
107DECLHIDDEN(RTEXITCODE) autostartStopMain(PCFGAST pCfgAst)
108{
109 RT_NOREF(pCfgAst);
110 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
111 std::list<AUTOSTOPVM> listVM;
112
113 /*
114 * Build a list of all VMs we need to autostop first, apply the overrides
115 * from the configuration and start the VMs afterwards.
116 */
117 com::SafeIfaceArray<IMachine> machines;
118 HRESULT rc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
119 if (SUCCEEDED(rc))
120 {
121 /*
122 * Iterate through the collection and construct a list of machines
123 * we have to check.
124 */
125 for (size_t i = 0; i < machines.size(); ++i)
126 {
127 if (machines[i])
128 {
129 BOOL fAccessible;
130 CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
131 if (!fAccessible)
132 continue;
133
134 AutostopType_T enmAutostopType;
135 CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostopType)(&enmAutostopType));
136 if (enmAutostopType != AutostopType_Disabled)
137 {
138 AUTOSTOPVM autostopVM;
139
140 CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(autostopVM.strId.asOutParam()));
141 autostopVM.enmAutostopType = enmAutostopType;
142
143 listVM.push_back(autostopVM);
144 }
145 }
146 }
147
148 if ( SUCCEEDED(rc)
149 && !listVM.empty())
150 {
151 std::list<AUTOSTOPVM>::iterator it;
152 for (it = listVM.begin(); it != listVM.end(); ++it)
153 {
154 MachineState_T enmMachineState;
155 ComPtr<IMachine> machine;
156
157 CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(),
158 machine.asOutParam()));
159
160 CHECK_ERROR_BREAK(machine, COMGETTER(State)(&enmMachineState));
161
162 /* Wait until the VM changes from a transient state back. */
163 while ( enmMachineState >= MachineState_FirstTransient
164 && enmMachineState <= MachineState_LastTransient)
165 {
166 RTThreadSleep(1000);
167 CHECK_ERROR_BREAK(machine, COMGETTER(State)(&enmMachineState));
168 }
169
170 /* Only power off running machines. */
171 if ( enmMachineState == MachineState_Running
172 || enmMachineState == MachineState_Paused)
173 {
174 ComPtr<IConsole> console;
175 ComPtr<IProgress> progress;
176
177 /* open a session for the VM */
178 CHECK_ERROR_BREAK(machine, LockMachine(g_pSession, LockType_Shared));
179
180 /* get the associated console */
181 CHECK_ERROR_BREAK(g_pSession, COMGETTER(Console)(console.asOutParam()));
182
183 switch ((*it).enmAutostopType)
184 {
185 case AutostopType_SaveState:
186 {
187 rc = autostartSaveVMState(console);
188 break;
189 }
190 case AutostopType_PowerOff:
191 {
192 CHECK_ERROR_BREAK(console, PowerDown(progress.asOutParam()));
193
194 rc = showProgress(progress);
195 CHECK_PROGRESS_ERROR(progress, ("Failed to power off machine"));
196 break;
197 }
198 case AutostopType_AcpiShutdown:
199 {
200 BOOL fGuestEnteredACPI = false;
201 CHECK_ERROR_BREAK(console, GetGuestEnteredACPIMode(&fGuestEnteredACPI));
202 if (fGuestEnteredACPI && enmMachineState == MachineState_Running)
203 {
204 CHECK_ERROR_BREAK(console, PowerButton());
205
206 autostartSvcLogInfo("Waiting for VM \"%ls\" to power off...\n", (*it).strId.raw());
207
208 do
209 {
210 RTThreadSleep(1000);
211 CHECK_ERROR_BREAK(machine, COMGETTER(State)(&enmMachineState));
212 } while (enmMachineState == MachineState_Running);
213 }
214 else
215 {
216 /* Use save state instead and log this to the console. */
217 autostartSvcLogWarning("The guest of VM \"%ls\" does not support ACPI shutdown or is currently paused, saving state...\n",
218 (*it).strId.raw());
219 rc = autostartSaveVMState(console);
220 }
221 break;
222 }
223 default:
224 autostartSvcLogWarning("Unknown autostop type for VM \"%ls\"\n", (*it).strId.raw());
225 }
226 g_pSession->UnlockMachine();
227 }
228 }
229 }
230 }
231
232 return rcExit;
233}
234
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use