VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp@ 106061

Last change on this file since 106061 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.5 KB
Line 
1/* $Id: MachineLaunchVMCommonWorker.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VirtualBox Main - VM process launcher helper for VBoxSVC & VBoxSDS.
4 */
5
6/*
7 * Copyright (C) 2011-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <iprt/dir.h>
33#include <iprt/env.h>
34#include <iprt/err.h>
35#include <iprt/file.h>
36#include <iprt/log.h>
37#include <iprt/path.h>
38#include <iprt/process.h>
39#include "MachineLaunchVMCommonWorker.h"
40
41
42/*********************************************************************************************************************************
43* Defined Constants And Macros *
44*********************************************************************************************************************************/
45#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
46# define HOSTSUFF_EXE ".exe"
47#else
48# define HOSTSUFF_EXE ""
49#endif
50
51
52/**
53 * Launch a VM process.
54 *
55 * The function starts the new VM process. It is a caller's responsibility
56 * to make any checks before and after calling the function.
57 * The function is a part of both VBoxSVC and VBoxSDS, so any calls to IVirtualBox
58 * and IMachine interfaces are performed using the client API.
59 *
60 * @returns VBox status code.
61 * @retval VINF_SUCCESS when new VM process started.
62 * @retval VERR_INVALID_PARAMETER when either aMachine is not Machine interface
63 * or invalid aFrontend is specified. Hmm. Come to think of it, it
64 * could also be returned in some other cases, especially if the code
65 * is buggy, so I wouldn't rely on any exact meaning here!
66 * @retval VERR_INTERNAL_ERROR when something wrong.
67 *
68 * @param aNameOrId The Machine name or id interface the VM will start for.
69 * @param aComment The comment for new VM process.
70 * @param aFrontend The desired frontend for started VM.
71 * @param aEnvironmentChanges Additional environment variables in the putenv style
72 * (VAR=VAL for setting, VAR for unsetting) for new VM process.
73 * @param aExtraArg Extra argument for the VM process. Ignored if
74 * empty string.
75 * @param aFilename Start new VM using specified filename. Only filename
76 * without path is allowed. Default filename is used if
77 * empty.
78 * @param aFlags Flags for RTProcCreateEx functions family if
79 * required (RTPROC_FLAGS_XXX).
80 * @param aExtraData Additional data for RTProcCreateX functions family
81 * if required. Content is defined by the flags.
82 * @param aPid The PID of created process is returned here
83 */
84int MachineLaunchVMCommonWorker(const Utf8Str &aNameOrId,
85 const Utf8Str &aComment,
86 const Utf8Str &aFrontend,
87 const std::vector<com::Utf8Str> &aEnvironmentChanges,
88 const Utf8Str &aExtraArg,
89 const Utf8Str &aFilename,
90 uint32_t aFlags,
91 void *aExtraData,
92 RTPROCESS &aPid)
93{
94 NOREF(aNameOrId);
95 NOREF(aComment);
96 NOREF(aFlags);
97 NOREF(aExtraData);
98 NOREF(aExtraArg);
99 NOREF(aFilename);
100
101 /* Get the path to the executable directory w/ trailing slash: */
102 char szPath[RTPATH_MAX];
103 int vrc = RTPathAppPrivateArch(szPath, sizeof(szPath));
104 AssertRCReturn(vrc, vrc);
105 size_t cbBufLeft = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
106 AssertReturn(cbBufLeft > 0, VERR_FILENAME_TOO_LONG);
107 char *pszNamePart = &szPath[cbBufLeft]; NOREF(pszNamePart);
108 cbBufLeft = sizeof(szPath) - cbBufLeft;
109
110 /* The process started when launching a VM with separate UI/VM processes is always
111 * the UI process, i.e. needs special handling as it won't claim the session. */
112 bool fSeparate = aFrontend.endsWith("separate", Utf8Str::CaseInsensitive); NOREF(fSeparate);
113
114 aPid = NIL_RTPROCESS;
115
116 RTENV hEnv = RTENV_DEFAULT;
117 if (!aEnvironmentChanges.empty())
118 {
119#ifdef IN_VBOXSVC
120 /* VBoxSVC: clone the current environment */
121 vrc = RTEnvClone(&hEnv, RTENV_DEFAULT);
122#else
123 /* VBoxSDS: Create a change record environment since RTProcCreateEx has to
124 build the final environment from the profile of the VBoxSDS caller. */
125 aFlags |= RTPROC_FLAGS_ENV_CHANGE_RECORD;
126 vrc = RTEnvCreateChangeRecord(&hEnv);
127#endif
128 AssertRCReturn(vrc, vrc);
129
130 /* Apply the specified environment changes. */
131 for (std::vector<com::Utf8Str>::const_iterator itEnv = aEnvironmentChanges.begin();
132 itEnv != aEnvironmentChanges.end();
133 ++itEnv)
134 {
135 vrc = RTEnvPutEx(hEnv, itEnv->c_str());
136 AssertRCReturnStmt(vrc, RTEnvDestroy(hEnv), vrc);
137 }
138 }
139
140#ifdef VBOX_WITH_QTGUI
141 if ( !aFrontend.compare("gui", Utf8Str::CaseInsensitive)
142 || !aFrontend.compare("GUI/Qt", Utf8Str::CaseInsensitive)
143 || !aFrontend.compare("separate", Utf8Str::CaseInsensitive)
144 || !aFrontend.compare("gui/separate", Utf8Str::CaseInsensitive)
145 || !aFrontend.compare("GUI/Qt/separate", Utf8Str::CaseInsensitive))
146 {
147# ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
148
149# define OSX_APP_NAME "VirtualBoxVM"
150# define OSX_APP_PATH_FMT "/Resources/%s.app/Contents/MacOS/VirtualBoxVM"
151# define OSX_APP_PATH_WITH_NAME "/Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM"
152
153 /* Modify the base path so that we don't need to use ".." below. */
154 RTPathStripTrailingSlash(szPath);
155 RTPathStripFilename(szPath);
156 cbBufLeft = strlen(szPath);
157 pszNamePart = &szPath[cbBufLeft]; Assert(!*pszNamePart);
158 cbBufLeft = sizeof(szPath) - cbBufLeft;
159
160 if (aFilename.isNotEmpty() && strpbrk(aFilename.c_str(), "./\\:") == NULL)
161 {
162 ssize_t cch = RTStrPrintf2(pszNamePart, cbBufLeft, OSX_APP_PATH_FMT, aFilename.c_str());
163 AssertReturn(cch > 0, VERR_FILENAME_TOO_LONG);
164 /* there is a race, but people using this deserve the failure */
165 if (!RTFileExists(szPath))
166 *pszNamePart = '\0';
167 }
168 if (!*pszNamePart)
169 {
170 vrc = RTStrCopy(pszNamePart, cbBufLeft, OSX_APP_PATH_WITH_NAME);
171 AssertRCReturn(vrc, vrc);
172 }
173# else
174 static const char s_szVirtualBox_exe[] = "VirtualBoxVM" HOSTSUFF_EXE;
175 vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVirtualBox_exe);
176 AssertRCReturn(vrc, vrc);
177# endif
178
179 const char *apszArgs[] =
180 {
181 szPath,
182 "--comment", aComment.c_str(),
183 "--startvm", aNameOrId.c_str(),
184 "--no-startvm-errormsgbox",
185 NULL, /* For "--separate". */
186 NULL, /* For "--sup-startup-log". */
187 NULL
188 };
189 unsigned iArg = 6;
190 if (fSeparate)
191 apszArgs[iArg++] = "--separate";
192 if (aExtraArg.isNotEmpty())
193 apszArgs[iArg++] = aExtraArg.c_str();
194
195 vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid);
196 }
197#else /* !VBOX_WITH_QTGUI */
198 if (0)
199 ;
200#endif /* VBOX_WITH_QTGUI */
201
202 else
203
204#ifdef VBOX_WITH_VBOXSDL
205 if ( !aFrontend.compare("sdl", Utf8Str::CaseInsensitive)
206 || !aFrontend.compare("GUI/SDL", Utf8Str::CaseInsensitive)
207 || !aFrontend.compare("sdl/separate", Utf8Str::CaseInsensitive)
208 || !aFrontend.compare("GUI/SDL/separate", Utf8Str::CaseInsensitive))
209 {
210 static const char s_szVBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE;
211 vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVBoxSDL_exe);
212 AssertRCReturn(vrc, vrc);
213
214 const char *apszArgs[] =
215 {
216 szPath,
217 "--comment", aComment.c_str(),
218 "--startvm", aNameOrId.c_str(),
219 NULL, /* For "--separate". */
220 NULL, /* For "--sup-startup-log". */
221 NULL
222 };
223 unsigned iArg = 5;
224 if (fSeparate)
225 apszArgs[iArg++] = "--separate";
226 if (aExtraArg.isNotEmpty())
227 apszArgs[iArg++] = aExtraArg.c_str();
228
229 vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid);
230 }
231#else /* !VBOX_WITH_VBOXSDL */
232 if (0)
233 ;
234#endif /* !VBOX_WITH_VBOXSDL */
235
236 else
237
238#ifdef VBOX_WITH_HEADLESS
239 if ( !aFrontend.compare("headless", Utf8Str::CaseInsensitive)
240 || !aFrontend.compare("capture", Utf8Str::CaseInsensitive)
241 || !aFrontend.compare("vrdp", Utf8Str::CaseInsensitive) /* Deprecated. Same as headless. */
242 )
243 {
244 /* On pre-4.0 the "headless" type was used for passing "--vrdp off" to VBoxHeadless to let it work in OSE,
245 * which did not contain VRDP server. In VBox 4.0 the remote desktop server (VRDE) is optional,
246 * and a VM works even if the server has not been installed.
247 * So in 4.0 the "headless" behavior remains the same for default VBox installations.
248 * Only if a VRDE has been installed and the VM enables it, the "headless" will work
249 * differently in 4.0 and 3.x.
250 */
251 static const char s_szVBoxHeadless_exe[] = "VBoxHeadless" HOSTSUFF_EXE;
252 vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVBoxHeadless_exe);
253 AssertRCReturn(vrc, vrc);
254
255 const char *apszArgs[] =
256 {
257 szPath,
258 "--comment", aComment.c_str(),
259 "--startvm", aNameOrId.c_str(),
260 "--vrde", "config",
261 NULL, /* For "--capture". */
262 NULL, /* For "--sup-startup-log". */
263 NULL
264 };
265 unsigned iArg = 7;
266 if (!aFrontend.compare("capture", Utf8Str::CaseInsensitive))
267 apszArgs[iArg++] = "--capture";
268 if (aExtraArg.isNotEmpty())
269 apszArgs[iArg++] = aExtraArg.c_str();
270
271# ifdef RT_OS_WINDOWS
272 aFlags |= RTPROC_FLAGS_NO_WINDOW;
273# endif
274 vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid);
275 }
276#else /* !VBOX_WITH_HEADLESS */
277 if (0)
278 ;
279#endif /* !VBOX_WITH_HEADLESS */
280 else
281 vrc = VERR_INVALID_PARAMETER;
282
283 RTEnvDestroy(hEnv);
284
285 if (RT_FAILURE(vrc))
286 return vrc;
287
288 return VINF_SUCCESS;
289}
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