VirtualBox

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

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