VirtualBox

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

Last change on this file since 94725 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: 6.3 KB
Line 
1/* $Id: VBoxAutostartStart.cpp 93115 2022-01-01 11:31:46Z 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
36using namespace com;
37
38/**
39 * VM list entry.
40 */
41typedef struct AUTOSTARTVM
42{
43 /** ID of the VM to start. */
44 Bstr strId;
45 /** Startup delay of the VM. */
46 ULONG uStartupDelay;
47} AUTOSTARTVM;
48
49static DECLCALLBACK(bool) autostartVMCmp(const AUTOSTARTVM &vm1, const AUTOSTARTVM &vm2)
50{
51 return vm1.uStartupDelay <= vm2.uStartupDelay;
52}
53
54DECLHIDDEN(RTEXITCODE) autostartStartMain(PCFGAST pCfgAst)
55{
56 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
57 int vrc = VINF_SUCCESS;
58 std::list<AUTOSTARTVM> listVM;
59 uint32_t uStartupDelay = 0;
60
61 pCfgAst = autostartConfigAstGetByName(pCfgAst, "startup_delay");
62 if (pCfgAst)
63 {
64 if (pCfgAst->enmType == CFGASTNODETYPE_KEYVALUE)
65 {
66 vrc = RTStrToUInt32Full(pCfgAst->u.KeyValue.aszValue, 10, &uStartupDelay);
67 if (RT_FAILURE(vrc))
68 return RTMsgErrorExit(RTEXITCODE_FAILURE, "'startup_delay' must be an unsigned number");
69 }
70 }
71
72 if (uStartupDelay)
73 {
74 autostartSvcLogVerbose("Delay starting for %d seconds ...\n", uStartupDelay);
75 vrc = RTThreadSleep(uStartupDelay * 1000);
76 }
77
78 if (vrc == VERR_INTERRUPTED)
79 return RTEXITCODE_SUCCESS;
80
81 /*
82 * Build a list of all VMs we need to autostart first, apply the overrides
83 * from the configuration and start the VMs afterwards.
84 */
85 com::SafeIfaceArray<IMachine> machines;
86 HRESULT rc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
87 if (SUCCEEDED(rc))
88 {
89 /*
90 * Iterate through the collection
91 */
92 for (size_t i = 0; i < machines.size(); ++i)
93 {
94 if (machines[i])
95 {
96 BOOL fAccessible;
97 CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
98 if (!fAccessible)
99 continue;
100
101 BOOL fAutostart;
102 CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostartEnabled)(&fAutostart));
103 if (fAutostart)
104 {
105 AUTOSTARTVM autostartVM;
106
107 CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(autostartVM.strId.asOutParam()));
108 CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostartDelay)(&autostartVM.uStartupDelay));
109
110 listVM.push_back(autostartVM);
111 }
112 }
113 }
114
115 /**
116 * @todo r=uwe I'm not reindenting this whole burnt offering
117 * to mistinterpreted Dijkstra's "single exit" commandment
118 * just to add this log, hence a bit of duplicate logic here.
119 */
120 if (SUCCEEDED(rc) && listVM.empty())
121 LogRel(("No VMs configured for autostart\n"));
122
123 if ( SUCCEEDED(rc)
124 && !listVM.empty())
125 {
126 ULONG uDelayCurr = 0;
127
128 /* Sort by startup delay and apply base override. */
129 listVM.sort(autostartVMCmp);
130
131 std::list<AUTOSTARTVM>::iterator it;
132 for (it = listVM.begin(); it != listVM.end(); ++it)
133 {
134 ComPtr<IMachine> machine;
135 ComPtr<IProgress> progress;
136
137 if ((*it).uStartupDelay > uDelayCurr)
138 {
139 autostartSvcLogVerbose("Delay starting of the next VMs for %d seconds ...\n",
140 (*it).uStartupDelay - uDelayCurr);
141 RTThreadSleep(((*it).uStartupDelay - uDelayCurr) * 1000);
142 uDelayCurr = (*it).uStartupDelay;
143 }
144
145 CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(),
146 machine.asOutParam()));
147
148 CHECK_ERROR_BREAK(machine, LaunchVMProcess(g_pSession, Bstr("headless").raw(),
149 ComSafeArrayNullInParam(), progress.asOutParam()));
150 if (SUCCEEDED(rc) && !progress.isNull())
151 {
152 autostartSvcLogVerbose("Waiting for VM \"%ls\" to power on...\n", (*it).strId.raw());
153 CHECK_ERROR(progress, WaitForCompletion(-1));
154 if (SUCCEEDED(rc))
155 {
156 BOOL completed = true;
157 CHECK_ERROR(progress, COMGETTER(Completed)(&completed));
158 if (SUCCEEDED(rc))
159 {
160 ASSERT(completed);
161
162 LONG iRc;
163 CHECK_ERROR(progress, COMGETTER(ResultCode)(&iRc));
164 if (SUCCEEDED(rc))
165 {
166 if (FAILED(iRc))
167 {
168 ProgressErrorInfo info(progress);
169 com::GluePrintErrorInfo(info);
170 }
171 else
172 autostartSvcLogVerbose("VM \"%ls\" has been successfully started.\n", (*it).strId.raw());
173 }
174 }
175 }
176 }
177 SessionState_T enmSessionState;
178 CHECK_ERROR(g_pSession, COMGETTER(State)(&enmSessionState));
179 if (SUCCEEDED(rc) && enmSessionState == SessionState_Locked)
180 g_pSession->UnlockMachine();
181 }
182 }
183 }
184
185 return rcExit;
186}
187
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