VirtualBox

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

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette