VBoxServiceExec.cpp revision f65e6cba3e74ffd3dc9e6053828dcc82b367e8de
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/* $Id$ */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** @file
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * VBoxServiceExec - In-VM Command Execution Service.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** @todo r=bird: Why is this called VMExec while the filename is VBoxServiceExec.cpp? See VMInfo... */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** @todo r=bird: Use svn-ps.[sh|cmd] -a when adding new files, please. Then the EOLs and $Id$ won't be messed up all the time. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/*
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Copyright (C) 2009 Sun Microsystems, Inc.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick *
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * This file is part of VirtualBox Open Source Edition (OSE), as
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * available from http://www.virtualbox.org. This file is free software;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * you can redistribute it and/or modify it under the terms of the GNU
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * General Public License (GPL) as published by the Free Software
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Foundation, in version 2 as it comes in the "COPYING" file of the
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick *
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Clara, CA 95054 USA or visit http://www.sun.com if you need
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * additional information or have any questions.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
45818ee124adeaaf947698996b4f4c722afc6d1fMatthew Ahrens
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/*******************************************************************************
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick* Header Files *
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick*******************************************************************************/
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <iprt/assert.h>
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <iprt/env.h>
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <iprt/file.h>
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <iprt/mem.h>
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <iprt/process.h>
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <iprt/string.h>
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <iprt/semaphore.h>
bbfd46c40e81c7d954cec28db66453ec5ab44613Jeff Bonwick#include <iprt/thread.h>
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <VBox/version.h>
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include <VBox/VBoxGuestLib.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include "VBoxServiceInternal.h"
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#include "VBoxServiceUtils.h"
837b568b3a2559f8c9b9403f95104271a85d129eGeorge Wilson#ifdef VBOX_WITH_GUEST_PROPS
837b568b3a2559f8c9b9403f95104271a85d129eGeorge Wilson# include <VBox/HostServices/GuestPropertySvc.h>
837b568b3a2559f8c9b9403f95104271a85d129eGeorge Wilson#endif
837b568b3a2559f8c9b9403f95104271a85d129eGeorge Wilson
837b568b3a2559f8c9b9403f95104271a85d129eGeorge Wilson
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/*******************************************************************************
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick* Global Variables *
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick*******************************************************************************/
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** The vminfo interval (millseconds). */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickuint32_t g_VMExecInterval = 0;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** The semaphore we're blocking on. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickstatic RTSEMEVENTMULTI g_VMExecEvent = NIL_RTSEMEVENTMULTI;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** The guest property service client ID. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickstatic uint32_t g_VMExecGuestPropSvcClientID = 0;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** The maximum of arguments a command can have. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#define EXEC_MAX_ARGS 32
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** @copydoc VBOXSERVICE::pfnPreInit */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickstatic DECLCALLBACK(int) VBoxServiceExecPreInit(void)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick{
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick return VINF_SUCCESS;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick}
45818ee124adeaaf947698996b4f4c722afc6d1fMatthew Ahrens
45818ee124adeaaf947698996b4f4c722afc6d1fMatthew Ahrens
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** @copydoc VBOXSERVICE::pfnOption */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickstatic DECLCALLBACK(int) VBoxServiceExecOption(const char **ppszShort, int argc, char **argv, int *pi)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick{
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick int rc = -1;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (ppszShort)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* no short options */;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick else if (!strcmp(argv[*pi], "--vmexec-interval"))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = VBoxServiceArgUInt32(argc, argv, "", pi, &g_VMExecInterval, 1, UINT32_MAX - 1);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick return rc;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick}
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** @copydoc VBOXSERVICE::pfnInit */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickstatic DECLCALLBACK(int) VBoxServiceExecInit(void)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick{
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /*
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * If not specified, find the right interval default.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Then create the event sem to block on.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (!g_VMExecInterval)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick g_VMExecInterval = g_DefaultInterval * 1000;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (!g_VMExecInterval)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick g_VMExecInterval = 10 * 1000;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick int rc = RTSemEventMultiCreate(&g_VMExecEvent);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick AssertRCReturn(rc, rc);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = VbglR3GuestPropConnect(&g_VMExecGuestPropSvcClientID);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_SUCCESS(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(3, "Property Service Client ID: %#x\n", g_VMExecGuestPropSvcClientID);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick else
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceError("Failed to connect to the guest property service! Error: %Rrc\n", rc);
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson RTSemEventMultiDestroy(g_VMExecEvent);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick g_VMExecEvent = NIL_RTSEMEVENTMULTI;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick return rc;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick}
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson/**
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson * Validates flags for executable guest properties.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick *
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * @returns boolean.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * @retval true on success.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * @retval false if not valid.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick *
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * @param pszFlags Pointer to flags to be checked.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickbool VBoxServiceExecValidateFlags(char* pszFlags)
43466aae47bfcd2ad9bf501faec8e75c08095e4fMax Grossman{
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (pszFlags == NULL)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick return false;
43466aae47bfcd2ad9bf501faec8e75c08095e4fMax Grossman
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if ( (NULL != RTStrStr(pszFlags, "TRANSIENT"))
43466aae47bfcd2ad9bf501faec8e75c08095e4fMax Grossman && (NULL != RTStrStr(pszFlags, "RDONLYGUEST")))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson return true;
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson }
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson return false;
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson}
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson/** @copydoc VBOXSERVICE::pfnWorker */
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George WilsonDECLCALLBACK(int) VBoxServiceExecWorker(bool volatile *pfShutdown)
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson{
43466aae47bfcd2ad9bf501faec8e75c08095e4fMax Grossman using namespace guestProp;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick int rc = VINF_SUCCESS;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /*
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Tell the control thread that it can continue
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * spawning services.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson RTThreadUserSignal(RTThreadSelf());
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson Assert(g_VMExecGuestPropSvcClientID > 0);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /*
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Execution loop.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#ifdef FULL_FEATURED_EXEC
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick uint64_t u64TimestampPrev = UINT64_MAX;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#endif
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson bool fSysprepDone = false;
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson for (;;)
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson {
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson /*
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson * The thread at the moment does nothing but checking for one specific guest property
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson * for triggering a hard coded sysprep command with parameters given by the host. This
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson * feature was required by the VDI guys.
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson *
30f608a433ef7b19cb4981bba0a0f7ccd7c92d03George Wilson * Later this thread could become a general host->guest executor (remote shell?).
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (!fSysprepDone)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick uint32_t cbBuf = MAX_VALUE_LEN + MAX_FLAGS_LEN + 1024;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* Get arguments. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /** @todo r=bird: How exactly does this work wrt. enabled/disabled? In
be6fd75a69ae679453d9cda5bff3326111e6d1caMatthew Ahrens * ConsoleImpl2.cpp it's now always set to "", which means it will
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * always be executed. So, if someone adds a bogus
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * c:\\sysprep\\sysprep.exe to their system and install the latest
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * additions this will be executed everytime the system starts now - if
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * I understand the code correctly. Is this intentional? */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick void* pvSysprepCmd = RTMemAllocZ(cbBuf);
c7cd242109c82107ec2e50013369e92be9d77702George Wilson char* pszSysprepCmdValue = NULL;
c7cd242109c82107ec2e50013369e92be9d77702George Wilson uint64_t u64SysprepCmdTimestamp = 0;
c7cd242109c82107ec2e50013369e92be9d77702George Wilson char* pszSysprepCmdFlags = NULL;
c7cd242109c82107ec2e50013369e92be9d77702George Wilson#ifdef SYSPREP_WITH_CMD
c7cd242109c82107ec2e50013369e92be9d77702George Wilson /* Get sysprep properties. */
c7cd242109c82107ec2e50013369e92be9d77702George Wilson if (RT_SUCCESS(rc))
c7cd242109c82107ec2e50013369e92be9d77702George Wilson {
c7cd242109c82107ec2e50013369e92be9d77702George Wilson rc = VbglR3GuestPropRead(g_VMExecGuestPropSvcClientID, "/VirtualBox/HostGuest/SysprepCmd",
c7cd242109c82107ec2e50013369e92be9d77702George Wilson pvSysprepCmd, cbBuf,
c7cd242109c82107ec2e50013369e92be9d77702George Wilson &pszSysprepCmdValue, &u64SysprepCmdTimestamp, &pszSysprepCmdFlags, NULL);
c7cd242109c82107ec2e50013369e92be9d77702George Wilson if (RT_FAILURE(rc))
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (rc == VERR_NOT_FOUND)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(2, "Sysprep cmd guest property not found\n");
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick else
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceError("Sysprep cmd guest property: Error = %Rrc\n", rc);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick else
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick !VBoxServiceExecValidateFlags(pszSysprepCmdFlags) ? rc = rc : rc = VERR_ACCESS_DENIED;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_SUCCESS(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RTStrNLen(pszSysprepCmdValue, _MAX_PATH) <= 0)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = VERR_NOT_FOUND;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(2, "Sysprep cmd guest property: %Rrc\n", rc);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#else
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* Choose sysprep image based on OS version. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick char szSysprepCmd[_MAX_PATH] = "c:\\sysprep\\sysprep.exe";
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick OSVERSIONINFOEX OSInfoEx;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick memset(&OSInfoEx, '\0', sizeof(OSInfoEx));
bbfd46c40e81c7d954cec28db66453ec5ab44613Jeff Bonwick OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (GetVersionEx((LPOSVERSIONINFO) &OSInfoEx))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (OSInfoEx.dwMajorVersion >= 6) /* Use built-in sysprep on Vista or later. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick RTStrPrintf(szSysprepCmd, sizeof(szSysprepCmd), "%s\\system32\\sysprep\\sysprep.exe", RTEnvGet("windir"));
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pszSysprepCmdValue = szSysprepCmd;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#endif
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick void* pvSysprepArgs = RTMemAllocZ(cbBuf);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick char* pszSysprepArgsValue = NULL;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick uint64_t u64SysprepArgsTimestamp = 0;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick char* pszSysprepArgsFlags = NULL;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_SUCCESS(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pvSysprepArgs = RTMemAllocZ(cbBuf);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick char szVal[] = "/VirtualBox/HostGuest/SysprepArgs";
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick char *pTmp = NULL;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = RTStrCurrentCPToUtf8(&pTmp, szVal);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = VbglR3GuestPropRead(g_VMExecGuestPropSvcClientID, pTmp,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pvSysprepArgs, cbBuf,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick &pszSysprepArgsValue, &u64SysprepArgsTimestamp, &pszSysprepArgsFlags, NULL);
be6fd75a69ae679453d9cda5bff3326111e6d1caMatthew Ahrens RTStrFree(pTmp);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_FAILURE(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (rc == VERR_NOT_FOUND)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(2, "Sysprep argument guest property not found\n");
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick else
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceError("Sysprep argument guest property: Error = %Rrc\n", rc);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick else
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick !VBoxServiceExecValidateFlags(pszSysprepArgsFlags) ? rc = rc : rc = VERR_ACCESS_DENIED;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_SUCCESS(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RTStrNLen(pszSysprepArgsValue, EXEC_MAX_ARGS) <= 0)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = VERR_NOT_FOUND;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(2, "Sysprep argument guest property: %Rrc\n", rc);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if ( RT_SUCCESS(rc)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick && !RTFileExists(pszSysprepCmdValue))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceError("Sysprep executable not found! Search path=%s\n", pszSysprepCmdValue);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = VERR_FILE_NOT_FOUND;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_SUCCESS(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick RTPROCESS pid;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* Construct arguments list. */
bbfd46c40e81c7d954cec28db66453ec5ab44613Jeff Bonwick /** @todo would be handy to have such a function in IPRT. */
bbfd46c40e81c7d954cec28db66453ec5ab44613Jeff Bonwick int16_t index = 0;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick char* pszArg = pszSysprepArgsValue;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick const char* pArgs[EXEC_MAX_ARGS]; /* Do we have a #define in IPRT for max args? */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(3, "Sysprep argument value: %s\n", pszSysprepArgsValue);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pArgs[index++] = pszSysprepCmdValue; /* Store image name as first argument. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick while ( (pszArg != NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling && (*pszArg != NULL))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick char* pCurArg = (char*)RTMemAllocZ(_MAX_PATH);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick int arg = 0;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick while ( (*pszArg != ' ')
bbfd46c40e81c7d954cec28db66453ec5ab44613Jeff Bonwick && (*pszArg != NULL))
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pCurArg[arg++] = *pszArg;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pszArg++;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pszArg++; /* Skip leading space. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(3, "Sysprep argument %d = %s\n", index, pCurArg);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pArgs[index++] = pCurArg;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick pArgs[index] = NULL;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* Execute ... */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(3, "Executing sysprep ...\n");
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = RTProcCreate(pszSysprepCmdValue, pArgs, RTENV_DEFAULT, 0, &pid);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_SUCCESS(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick RTPROCSTATUS Status;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = RTProcWait(pid, RTPROCWAIT_FLAGS_BLOCK, &Status);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceVerbose(3, "Sysprep returned: %d\n", Status.iStatus);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_SUCCESS(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if ( Status.iStatus == 0
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick && Status.enmReason == RTPROCEXITREASON_NORMAL)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick fSysprepDone = true; /* We're done, no need to repeat the sysprep exec. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* Set return value so the host knows what happend. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = VboxServiceWritePropInt(g_VMExecGuestPropSvcClientID, "HostGuest/SysprepRet", Status.iStatus);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (RT_FAILURE(rc))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceError("Failed to write SysprepRet: rc=%Rrc\n", rc);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* Destroy argument list (all but the first and last arg, it's just a pointer). */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick for (int i=1; i<index-1; i++)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick RTMemFree((void*)pArgs[i]);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#ifdef FULL_FEATURED_EXEC
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick 1. Read the command - value, timestamp and flags.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick 2. Check that the flags indicates that the guest cannot write to it and that it's transient.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick 3. Check if the timestamp changed.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick 4. Get the arguments and other stuff.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick 5. Execute it. This may involve grabbing the output (stderr and/or stdout) and pushing into
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick values afterwards. It may also entail redirecting input to a file containing text from a guest prop value.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick 6. Set the result values (there will be three, one IPRT style one for everything up to
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick and including RTProcWait and two that mirrors Status.iStatus and Status.enmReason (stringified)).
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#endif
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
bbfd46c40e81c7d954cec28db66453ec5ab44613Jeff Bonwick /*
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * Block for a while.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick *
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * The event semaphore takes care of ignoring interruptions and it
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * allows us to implement service wakeup later.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (*pfShutdown)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick break;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#ifdef FULL_FEATURED_EXEC
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick Wait for changes to the command value. If that fails for some reason other than timeout / interrupt, fall back on the semaphore.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#else
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick int rc2 = RTSemEventMultiWait(g_VMExecEvent, g_VMExecInterval);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#endif
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (*pfShutdown)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick break;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick {
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick rc = rc2;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick break;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick }
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick RTSemEventMultiDestroy(g_VMExecEvent);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick g_VMExecEvent = NIL_RTSEMEVENTMULTI;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick return rc;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick}
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** @copydoc VBOXSERVICE::pfnStop */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickstatic DECLCALLBACK(void) VBoxServiceExecStop(void)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick{
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /** @todo Later, figure what to do if we're in RTProcWait(). it's a very
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * annoying call since doesn't support timeouts in the posix world. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick RTSemEventMultiSignal(g_VMExecEvent);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#ifdef FULL_FEATURED_EXEC
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick Interrupts waits.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick#endif
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick}
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/** @copydoc VBOXSERVICE::pfnTerm */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwickstatic DECLCALLBACK(void) VBoxServiceExecTerm(void)
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick{
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* Nothing here yet. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VbglR3GuestPropDisconnect(g_VMExecGuestPropSvcClientID);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick g_VMExecGuestPropSvcClientID = 0;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick RTSemEventMultiDestroy(g_VMExecEvent);
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick g_VMExecEvent = NIL_RTSEMEVENTMULTI;
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick}
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick/**
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick * The 'vminfo' service description.
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick */
b24ab6762772a3f6a89393947930c7fa61306783Jeff BonwickVBOXSERVICE g_VMExec =
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick{
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* pszName. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick "vmexec",
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* pszDescription. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick "Virtual Machine Remote Execution",
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* pszUsage. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick "[--vmexec-interval <ms>]"
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick ,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* pszOptions. */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick " --vmexec-interval Specifies the interval at which to check for new\n"
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick " remote execution commands. The default is 10000 ms.\n"
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick ,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick /* methods */
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceExecPreInit,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceExecOption,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceExecInit,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceExecWorker,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceExecStop,
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick VBoxServiceExecTerm
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick};
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick
b24ab6762772a3f6a89393947930c7fa61306783Jeff Bonwick