VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStart.cpp@ 96316

Last change on this file since 96316 was 95140, checked in by vboxsync, 2 years ago

Frontends + Main: Adjust to the new rules wrt. to rc -> hrc,vrc usage. This also fixes quite a few bugs wrt shadow variables, wrong return values and output error translations / exit codes. Also see @todos added. ​​bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.6 KB
Line 
1/* $Id: VBoxAutostartStart.cpp 95140 2022-05-31 09:11:39Z vboxsync $ */
2/** @file
3 * VBoxAutostart - VirtualBox Autostart service, start machines during system boot.
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/errcore.h>
26#include <iprt/log.h>
27#include <iprt/message.h>
28#include <iprt/stream.h>
29#include <iprt/thread.h>
30
31#include <algorithm>
32#include <list>
33
34#include "VBoxAutostart.h"
35
36extern unsigned g_cVerbosity;
37
38using namespace com;
39
40/**
41 * VM list entry.
42 */
43typedef struct AUTOSTARTVM
44{
45 /** ID of the VM to start. */
46 Bstr strId;
47 /** Startup delay of the VM. */
48 ULONG uStartupDelay;
49} AUTOSTARTVM;
50
51static DECLCALLBACK(bool) autostartVMCmp(const AUTOSTARTVM &vm1, const AUTOSTARTVM &vm2)
52{
53 return vm1.uStartupDelay <= vm2.uStartupDelay;
54}
55
56DECLHIDDEN(int) autostartStartMain(PCFGAST pCfgAst)
57{
58 int vrc = VINF_SUCCESS;
59 std::list<AUTOSTARTVM> listVM;
60 uint32_t uStartupDelay = 0;
61
62 autostartSvcLogVerbose(1, "Starting machines ...\n");
63
64 pCfgAst = autostartConfigAstGetByName(pCfgAst, "startup_delay");
65 if (pCfgAst)
66 {
67 if (pCfgAst->enmType == CFGASTNODETYPE_KEYVALUE)
68 {
69 vrc = RTStrToUInt32Full(pCfgAst->u.KeyValue.aszValue, 10, &uStartupDelay);
70 if (RT_FAILURE(vrc))
71 return autostartSvcLogErrorRc(vrc, "'startup_delay' must be an unsigned number");
72 }
73 }
74
75 if (uStartupDelay)
76 {
77 autostartSvcLogVerbose(1, "Delaying start for %RU32 seconds ...\n", uStartupDelay);
78 vrc = RTThreadSleep(uStartupDelay * 1000);
79 }
80
81 if (vrc == VERR_INTERRUPTED)
82 return VINF_SUCCESS;
83
84 /*
85 * Build a list of all VMs we need to autostart first, apply the overrides
86 * from the configuration and start the VMs afterwards.
87 */
88 com::SafeIfaceArray<IMachine> machines;
89 HRESULT hrc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
90 if (SUCCEEDED(hrc))
91 {
92 /*
93 * Iterate through the collection
94 */
95 for (size_t i = 0; i < machines.size(); ++i)
96 {
97 if (machines[i])
98 {
99 Bstr strName;
100 CHECK_ERROR_BREAK(machines[i], COMGETTER(Name)(strName.asOutParam()));
101
102 BOOL fAccessible;
103 CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
104 if (!fAccessible)
105 {
106 autostartSvcLogVerbose(1, "Machine '%ls' is not accessible, skipping\n", strName.raw());
107 continue;
108 }
109
110 AUTOSTARTVM autostartVM;
111
112 BOOL fAutostart;
113 CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostartEnabled)(&fAutostart));
114 if (fAutostart)
115 {
116 CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(autostartVM.strId.asOutParam()));
117 CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostartDelay)(&autostartVM.uStartupDelay));
118
119 listVM.push_back(autostartVM);
120 }
121
122 autostartSvcLogVerbose(1, "Machine '%ls': Autostart is %s (startup delay is %RU32 seconds)\n",
123 strName.raw(), fAutostart ? "enabled" : "disabled",
124 fAutostart ? autostartVM.uStartupDelay : 0);
125 }
126 }
127
128 /**
129 * @todo r=uwe I'm not reindenting this whole burnt offering
130 * to mistinterpreted Dijkstra's "single exit" commandment
131 * just to add this log, hence a bit of duplicate logic here.
132 */
133 if (SUCCEEDED(hrc))
134 {
135 if (machines.size() == 0)
136 autostartSvcLogWarning("No virtual machines found.\n"
137 "This either could be a configuration problem (access rights), "
138 "or there are no VMs configured yet.");
139 else if (listVM.empty())
140 autostartSvcLogWarning("No virtual machines configured for autostart.\n"
141 "Please consult the manual about how to enable auto starting VMs.\n");
142 }
143 else
144 autostartSvcLogError("Enumerating virtual machines failed with %Rhrc\n", hrc);
145
146 if ( SUCCEEDED(hrc)
147 && !listVM.empty())
148 {
149 ULONG uDelayCur = 0;
150
151 /* Sort by startup delay and apply base override. */
152 listVM.sort(autostartVMCmp);
153
154 std::list<AUTOSTARTVM>::iterator it;
155 for (it = listVM.begin(); it != listVM.end(); ++it)
156 {
157 ComPtr<IMachine> machine;
158 ComPtr<IProgress> progress;
159
160 CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(), machine.asOutParam()));
161
162 Bstr strName;
163 CHECK_ERROR_BREAK(machine, COMGETTER(Name)(strName.asOutParam()));
164
165 if ((*it).uStartupDelay > uDelayCur)
166 {
167 autostartSvcLogVerbose(1, "Waiting for %ul seconds before starting machine '%s' ...\n",
168 (*it).uStartupDelay - uDelayCur, strName.raw());
169 RTThreadSleep(((*it).uStartupDelay - uDelayCur) * 1000);
170 uDelayCur = (*it).uStartupDelay;
171 }
172
173 CHECK_ERROR_BREAK(machine, LaunchVMProcess(g_pSession, Bstr("headless").raw(),
174 ComSafeArrayNullInParam(), progress.asOutParam()));
175 if (SUCCEEDED(hrc) && !progress.isNull())
176 {
177 autostartSvcLogVerbose(1, "Waiting for machine '%ls' to power on ...\n", strName.raw());
178 CHECK_ERROR(progress, WaitForCompletion(-1));
179 if (SUCCEEDED(hrc))
180 {
181 BOOL completed = true;
182 CHECK_ERROR(progress, COMGETTER(Completed)(&completed));
183 if (SUCCEEDED(hrc))
184 {
185 ASSERT(completed);
186
187 LONG iRc;
188 CHECK_ERROR(progress, COMGETTER(ResultCode)(&iRc));
189 if (SUCCEEDED(hrc))
190 {
191 if (FAILED(iRc))
192 {
193 ProgressErrorInfo info(progress);
194 com::GluePrintErrorInfo(info);
195 }
196 else
197 autostartSvcLogVerbose(1, "Machine '%ls' has been successfully started.\n", strName.raw());
198 }
199 }
200 }
201 }
202 SessionState_T enmSessionState;
203 CHECK_ERROR(g_pSession, COMGETTER(State)(&enmSessionState));
204 if (SUCCEEDED(hrc) && enmSessionState == SessionState_Locked)
205 g_pSession->UnlockMachine();
206 }
207 }
208 }
209
210 return vrc;
211}
212
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