From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Main/src-all/MachineLaunchVMCommonWorker.cpp | 289 +++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp (limited to 'src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp') diff --git a/src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp b/src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp new file mode 100644 index 00000000..01d7a9f3 --- /dev/null +++ b/src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp @@ -0,0 +1,289 @@ +/* $Id: MachineLaunchVMCommonWorker.cpp $ */ +/** @file + * VirtualBox Main - VM process launcher helper for VBoxSVC & VBoxSDS. + */ + +/* + * Copyright (C) 2011-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include "MachineLaunchVMCommonWorker.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) +# define HOSTSUFF_EXE ".exe" +#else +# define HOSTSUFF_EXE "" +#endif + + +/** + * Launch a VM process. + * + * The function starts the new VM process. It is a caller's responsibility + * to make any checks before and after calling the function. + * The function is a part of both VBoxSVC and VBoxSDS, so any calls to IVirtualBox + * and IMachine interfaces are performed using the client API. + * + * @returns VBox status code. + * @retval VINF_SUCCESS when new VM process started. + * @retval VERR_INVALID_PARAMETER when either aMachine is not Machine interface + * or invalid aFrontend is specified. Hmm. Come to think of it, it + * could also be returned in some other cases, especially if the code + * is buggy, so I wouldn't rely on any exact meaning here! + * @retval VERR_INTERNAL_ERROR when something wrong. + * + * @param aNameOrId The Machine name or id interface the VM will start for. + * @param aComment The comment for new VM process. + * @param aFrontend The desired frontend for started VM. + * @param aEnvironmentChanges Additional environment variables in the putenv style + * (VAR=VAL for setting, VAR for unsetting) for new VM process. + * @param aExtraArg Extra argument for the VM process. Ignored if + * empty string. + * @param aFilename Start new VM using specified filename. Only filename + * without path is allowed. Default filename is used if + * empty. + * @param aFlags Flags for RTProcCreateEx functions family if + * required (RTPROC_FLAGS_XXX). + * @param aExtraData Additional data for RTProcCreateX functions family + * if required. Content is defined by the flags. + * @param aPid The PID of created process is returned here + */ +int MachineLaunchVMCommonWorker(const Utf8Str &aNameOrId, + const Utf8Str &aComment, + const Utf8Str &aFrontend, + const std::vector &aEnvironmentChanges, + const Utf8Str &aExtraArg, + const Utf8Str &aFilename, + uint32_t aFlags, + void *aExtraData, + RTPROCESS &aPid) +{ + NOREF(aNameOrId); + NOREF(aComment); + NOREF(aFlags); + NOREF(aExtraData); + NOREF(aExtraArg); + NOREF(aFilename); + + /* Get the path to the executable directory w/ trailing slash: */ + char szPath[RTPATH_MAX]; + int vrc = RTPathAppPrivateArch(szPath, sizeof(szPath)); + AssertRCReturn(vrc, vrc); + size_t cbBufLeft = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath)); + AssertReturn(cbBufLeft > 0, VERR_FILENAME_TOO_LONG); + char *pszNamePart = &szPath[cbBufLeft]; NOREF(pszNamePart); + cbBufLeft = sizeof(szPath) - cbBufLeft; + + /* The process started when launching a VM with separate UI/VM processes is always + * the UI process, i.e. needs special handling as it won't claim the session. */ + bool fSeparate = aFrontend.endsWith("separate", Utf8Str::CaseInsensitive); NOREF(fSeparate); + + aPid = NIL_RTPROCESS; + + RTENV hEnv = RTENV_DEFAULT; + if (!aEnvironmentChanges.empty()) + { +#ifdef IN_VBOXSVC + /* VBoxSVC: clone the current environment */ + vrc = RTEnvClone(&hEnv, RTENV_DEFAULT); +#else + /* VBoxSDS: Create a change record environment since RTProcCreateEx has to + build the final environment from the profile of the VBoxSDS caller. */ + aFlags |= RTPROC_FLAGS_ENV_CHANGE_RECORD; + vrc = RTEnvCreateChangeRecord(&hEnv); +#endif + AssertRCReturn(vrc, vrc); + + /* Apply the specified environment changes. */ + for (std::vector::const_iterator itEnv = aEnvironmentChanges.begin(); + itEnv != aEnvironmentChanges.end(); + ++itEnv) + { + vrc = RTEnvPutEx(hEnv, itEnv->c_str()); + AssertRCReturnStmt(vrc, RTEnvDestroy(hEnv), vrc); + } + } + +#ifdef VBOX_WITH_QTGUI + if ( !aFrontend.compare("gui", Utf8Str::CaseInsensitive) + || !aFrontend.compare("GUI/Qt", Utf8Str::CaseInsensitive) + || !aFrontend.compare("separate", Utf8Str::CaseInsensitive) + || !aFrontend.compare("gui/separate", Utf8Str::CaseInsensitive) + || !aFrontend.compare("GUI/Qt/separate", Utf8Str::CaseInsensitive)) + { +# ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */ + +# define OSX_APP_NAME "VirtualBoxVM" +# define OSX_APP_PATH_FMT "/Resources/%s.app/Contents/MacOS/VirtualBoxVM" +# define OSX_APP_PATH_WITH_NAME "/Resources/VirtualBoxVM.app/Contents/MacOS/VirtualBoxVM" + + /* Modify the base path so that we don't need to use ".." below. */ + RTPathStripTrailingSlash(szPath); + RTPathStripFilename(szPath); + cbBufLeft = strlen(szPath); + pszNamePart = &szPath[cbBufLeft]; Assert(!*pszNamePart); + cbBufLeft = sizeof(szPath) - cbBufLeft; + + if (aFilename.isNotEmpty() && strpbrk(aFilename.c_str(), "./\\:") == NULL) + { + ssize_t cch = RTStrPrintf2(pszNamePart, cbBufLeft, OSX_APP_PATH_FMT, aFilename.c_str()); + AssertReturn(cch > 0, VERR_FILENAME_TOO_LONG); + /* there is a race, but people using this deserve the failure */ + if (!RTFileExists(szPath)) + *pszNamePart = '\0'; + } + if (!*pszNamePart) + { + vrc = RTStrCopy(pszNamePart, cbBufLeft, OSX_APP_PATH_WITH_NAME); + AssertRCReturn(vrc, vrc); + } +# else + static const char s_szVirtualBox_exe[] = "VirtualBoxVM" HOSTSUFF_EXE; + vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVirtualBox_exe); + AssertRCReturn(vrc, vrc); +# endif + + const char *apszArgs[] = + { + szPath, + "--comment", aComment.c_str(), + "--startvm", aNameOrId.c_str(), + "--no-startvm-errormsgbox", + NULL, /* For "--separate". */ + NULL, /* For "--sup-startup-log". */ + NULL + }; + unsigned iArg = 6; + if (fSeparate) + apszArgs[iArg++] = "--separate"; + if (aExtraArg.isNotEmpty()) + apszArgs[iArg++] = aExtraArg.c_str(); + + vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid); + } +#else /* !VBOX_WITH_QTGUI */ + if (0) + ; +#endif /* VBOX_WITH_QTGUI */ + + else + +#ifdef VBOX_WITH_VBOXSDL + if ( !aFrontend.compare("sdl", Utf8Str::CaseInsensitive) + || !aFrontend.compare("GUI/SDL", Utf8Str::CaseInsensitive) + || !aFrontend.compare("sdl/separate", Utf8Str::CaseInsensitive) + || !aFrontend.compare("GUI/SDL/separate", Utf8Str::CaseInsensitive)) + { + static const char s_szVBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE; + vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVBoxSDL_exe); + AssertRCReturn(vrc, vrc); + + const char *apszArgs[] = + { + szPath, + "--comment", aComment.c_str(), + "--startvm", aNameOrId.c_str(), + NULL, /* For "--separate". */ + NULL, /* For "--sup-startup-log". */ + NULL + }; + unsigned iArg = 5; + if (fSeparate) + apszArgs[iArg++] = "--separate"; + if (aExtraArg.isNotEmpty()) + apszArgs[iArg++] = aExtraArg.c_str(); + + vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid); + } +#else /* !VBOX_WITH_VBOXSDL */ + if (0) + ; +#endif /* !VBOX_WITH_VBOXSDL */ + + else + +#ifdef VBOX_WITH_HEADLESS + if ( !aFrontend.compare("headless", Utf8Str::CaseInsensitive) + || !aFrontend.compare("capture", Utf8Str::CaseInsensitive) + || !aFrontend.compare("vrdp", Utf8Str::CaseInsensitive) /* Deprecated. Same as headless. */ + ) + { + /* On pre-4.0 the "headless" type was used for passing "--vrdp off" to VBoxHeadless to let it work in OSE, + * which did not contain VRDP server. In VBox 4.0 the remote desktop server (VRDE) is optional, + * and a VM works even if the server has not been installed. + * So in 4.0 the "headless" behavior remains the same for default VBox installations. + * Only if a VRDE has been installed and the VM enables it, the "headless" will work + * differently in 4.0 and 3.x. + */ + static const char s_szVBoxHeadless_exe[] = "VBoxHeadless" HOSTSUFF_EXE; + vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVBoxHeadless_exe); + AssertRCReturn(vrc, vrc); + + const char *apszArgs[] = + { + szPath, + "--comment", aComment.c_str(), + "--startvm", aNameOrId.c_str(), + "--vrde", "config", + NULL, /* For "--capture". */ + NULL, /* For "--sup-startup-log". */ + NULL + }; + unsigned iArg = 7; + if (!aFrontend.compare("capture", Utf8Str::CaseInsensitive)) + apszArgs[iArg++] = "--capture"; + if (aExtraArg.isNotEmpty()) + apszArgs[iArg++] = aExtraArg.c_str(); + +# ifdef RT_OS_WINDOWS + aFlags |= RTPROC_FLAGS_NO_WINDOW; +# endif + vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid); + } +#else /* !VBOX_WITH_HEADLESS */ + if (0) + ; +#endif /* !VBOX_WITH_HEADLESS */ + else + vrc = VERR_INVALID_PARAMETER; + + RTEnvDestroy(hEnv); + + if (RT_FAILURE(vrc)) + return vrc; + + return VINF_SUCCESS; +} -- cgit v1.2.3