VBoxServiceExec.cpp revision 1bf88a54387e004678654cf5158075f59e3be168
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync/* $Id$ */
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @file
af062818b47340eef15700d2f0211576ba3506eevboxsync * VBoxServiceExec - Host-driven Command Execution.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright (C) 2009 Sun Microsystems, Inc.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
af062818b47340eef15700d2f0211576ba3506eevboxsync * available from http://www.virtualbox.org. This file is free software;
af062818b47340eef15700d2f0211576ba3506eevboxsync * you can redistribute it and/or modify it under the terms of the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsync * General Public License (GPL) as published by the Free Software
af062818b47340eef15700d2f0211576ba3506eevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
af062818b47340eef15700d2f0211576ba3506eevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
af062818b47340eef15700d2f0211576ba3506eevboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
af062818b47340eef15700d2f0211576ba3506eevboxsync * additional information or have any questions.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync/*******************************************************************************
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync* Header Files *
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync*******************************************************************************/
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync#include <iprt/assert.h>
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync#include <iprt/ctype.h>
b955672b950093ff7416d1269dd4d3b69983bd8fvboxsync#include <iprt/env.h>
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include <iprt/file.h>
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include <iprt/mem.h>
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include <iprt/path.h>
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include <iprt/param.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/process.h>
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include <iprt/string.h>
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include <iprt/semaphore.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/thread.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <VBox/version.h>
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include <VBox/VBoxGuestLib.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "VBoxServiceInternal.h"
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "VBoxServiceUtils.h"
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/*******************************************************************************
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync* Global Variables *
af062818b47340eef15700d2f0211576ba3506eevboxsync*******************************************************************************/
af062818b47340eef15700d2f0211576ba3506eevboxsync/** The vminfo interval (millseconds). */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsyncstatic uint32_t g_cMsExecInterval = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync/** The semaphore we're blocking on. */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsyncstatic RTSEMEVENTMULTI g_hExecEvent = NIL_RTSEMEVENTMULTI;
af062818b47340eef15700d2f0211576ba3506eevboxsync/** The guest property service client ID. */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic uint32_t g_uExecGuestPropSvcClientID = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic DECLCALLBACK(int) VBoxServiceExecPreInit(void)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @copydoc VBOXSERVICE::pfnOption */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic DECLCALLBACK(int) VBoxServiceExecOption(const char **ppszShort, int argc, char **argv, int *pi)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = -1;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (ppszShort)
af062818b47340eef15700d2f0211576ba3506eevboxsync /* no short options */;
af062818b47340eef15700d2f0211576ba3506eevboxsync else if (!strcmp(argv[*pi], "--exec-interval"))
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VBoxServiceArgUInt32(argc, argv, "", pi, &g_cMsExecInterval, 1, UINT32_MAX - 1);
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync}
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync/** @copydoc VBOXSERVICE::pfnInit */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsyncstatic DECLCALLBACK(int) VBoxServiceExecInit(void)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync{
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync /*
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * If not specified, find the right interval default.
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * Then create the event sem to block on.
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync if (!g_cMsExecInterval)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync g_cMsExecInterval = g_DefaultInterval * 1000;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync if (!g_cMsExecInterval)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync g_cMsExecInterval = 10 * 1000;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync int rc = RTSemEventMultiCreate(&g_hExecEvent);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync AssertRCReturn(rc, rc);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VbglR3GuestPropConnect(&g_uExecGuestPropSvcClientID);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(3, "Exec: Property Service Client ID: %#x\n", g_uExecGuestPropSvcClientID);
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: Failed to connect to the guest property service! Error: %Rrc\n", rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync RTSemEventMultiDestroy(g_hExecEvent);
af062818b47340eef15700d2f0211576ba3506eevboxsync g_hExecEvent = NIL_RTSEMEVENTMULTI;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/**
af062818b47340eef15700d2f0211576ba3506eevboxsync * Validates flags for executable guest properties.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * @returns VBox status code. Success means they are valid.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pszFlags Pointer to flags to be checked.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int VBoxServiceExecValidateFlags(const char *pszFlags)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!pszFlags)
af062818b47340eef15700d2f0211576ba3506eevboxsync return VERR_ACCESS_DENIED;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!RTStrStr(pszFlags, "TRANSIENT"))
af062818b47340eef15700d2f0211576ba3506eevboxsync return VERR_ACCESS_DENIED;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!RTStrStr(pszFlags, "RDONLYGUEST"))
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync return VERR_ACCESS_DENIED;
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/**
af062818b47340eef15700d2f0211576ba3506eevboxsync * Reads a host transient property.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * This will validate the flags to make sure it is a transient property that can
af062818b47340eef15700d2f0211576ba3506eevboxsync * only be change by the host.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * @returns VBox status code, fully bitched.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pszPropName The property name.
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * @param ppszValue Where to return the value. This is always set
af062818b47340eef15700d2f0211576ba3506eevboxsync * to NULL. Free it using RTStrFree().
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param puTimestamp Where to return the timestamp. This is only set
af062818b47340eef15700d2f0211576ba3506eevboxsync * on success. Optional.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int VBoxServiceExecReadHostProp(const char *pszPropName, char **ppszValue, uint64_t *puTimestamp)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync size_t cbBuf = _1K;
af062818b47340eef15700d2f0211576ba3506eevboxsync void *pvBuf = NULL;
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync *ppszValue = NULL;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync for (unsigned cTries = 0; cTries < 10; cTries++)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * (Re-)Allocate the buffer and try read the property.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync RTMemFree(pvBuf);
af062818b47340eef15700d2f0211576ba3506eevboxsync pvBuf = RTMemAlloc(cbBuf);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!pvBuf)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: Failed to allocate %zu bytes\n", cbBuf);
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NO_MEMORY;
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync char *pszValue;
af062818b47340eef15700d2f0211576ba3506eevboxsync char *pszFlags;
af062818b47340eef15700d2f0211576ba3506eevboxsync uint64_t uTimestamp;
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VbglR3GuestPropRead(g_uExecGuestPropSvcClientID, pszPropName,
af062818b47340eef15700d2f0211576ba3506eevboxsync pvBuf, cbBuf,
af062818b47340eef15700d2f0211576ba3506eevboxsync &pszValue, &uTimestamp, &pszFlags, NULL);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_FAILURE(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc == VERR_BUFFER_OVERFLOW)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* try again with a bigger buffer. */
af062818b47340eef15700d2f0211576ba3506eevboxsync cbBuf *= 2;
af062818b47340eef15700d2f0211576ba3506eevboxsync continue;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc == VERR_NOT_FOUND)
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(2, "Exec: %s not found\n", pszPropName);
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: Failed to query \"%s\": %Rrc\n", pszPropName, rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Validate it and set return values on success.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync rc = VBoxServiceExecValidateFlags(pszFlags);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (RT_FAILURE(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync static uint32_t s_cBitched = 0;
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (++s_cBitched < 10)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync VBoxServiceError("Exec: Flag validation failed for \"%s\": %Rrc; flags=\"%s\"\n",
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync pszPropName, rc, pszFlags);
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(2, "Exec: Read \"%s\" = \"%s\", timestamp %RU64n\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync pszPropName, pszValue, uTimestamp);
af062818b47340eef15700d2f0211576ba3506eevboxsync *ppszValue = RTStrDup(pszValue);
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync if (!*ppszValue)
ee6bcfc59fe3b0230aad85e2ef63d0402b7719b2vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: RTStrDup failed for \"%s\"\n", pszValue);
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NO_MEMORY;
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (puTimestamp)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync *puTimestamp = uTimestamp;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync break; /* done */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync }
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync RTMemFree(pvBuf);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync return rc;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync}
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync/**
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * Frees an argument vector constructed by VBoxServiceExecCreateArgV.
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync *
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * @param papszArgs The vector to free.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic void VBoxServiceExecFreeArgV(char **papszArgs)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync for (size_t i = 0; papszArgs[i]; i++)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync RTStrFree(papszArgs[i]);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync papszArgs[i] = NULL;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync RTMemFree(papszArgs);
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync/**
af062818b47340eef15700d2f0211576ba3506eevboxsync * Creates an argument vector out of an executable name and a string containing
af062818b47340eef15700d2f0211576ba3506eevboxsync * the arguments separated by spaces.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * @returns VBox status code. Not bitched.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pszExec The executable name.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param pszArgs The string containging the arguments.
af062818b47340eef15700d2f0211576ba3506eevboxsync * @param ppapszArgs Where to return the argument vector. Not set on
af062818b47340eef15700d2f0211576ba3506eevboxsync * failure. Use VBoxServiceExecFreeArgV to free.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * @todo Quoted strings. Do it unix (bourne shell) fashion.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic int VBoxServiceExecCreateArgV(const char *pszExec, const char *pszArgs, char ***ppapszArgs)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync size_t cAlloc = 1;
af062818b47340eef15700d2f0211576ba3506eevboxsync size_t cUsed = 1;
af062818b47340eef15700d2f0211576ba3506eevboxsync char **papszArgs = (char **)RTMemAlloc(sizeof(char *) * (cAlloc + 1));
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!papszArgs)
af062818b47340eef15700d2f0211576ba3506eevboxsync return VERR_NO_MEMORY;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Start by adding the executable name first.
af062818b47340eef15700d2f0211576ba3506eevboxsync * Note! We keep the papszArgs fully terminated at all times to keep cleanup simple.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = VERR_NO_MEMORY;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync papszArgs[1] = NULL;
af062818b47340eef15700d2f0211576ba3506eevboxsync papszArgs[0] = RTStrDup(pszExec);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (papszArgs[0])
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync * Parse the argument string and add any arguments found in it.
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync */
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync for (;;)
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* skip leading spaces */
af062818b47340eef15700d2f0211576ba3506eevboxsync char ch;
af062818b47340eef15700d2f0211576ba3506eevboxsync while ((ch = *pszArgs) && RT_C_IS_SPACE(ch))
af062818b47340eef15700d2f0211576ba3506eevboxsync pszArgs++;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!*pszArgs)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync *ppapszArgs = papszArgs;
af062818b47340eef15700d2f0211576ba3506eevboxsync return VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* find the of the current word. Quoting is ignored atm. */
af062818b47340eef15700d2f0211576ba3506eevboxsync char const *pszEnd = pszArgs + 1;
af062818b47340eef15700d2f0211576ba3506eevboxsync while ((ch = *pszEnd) && !RT_C_IS_SPACE(ch))
af062818b47340eef15700d2f0211576ba3506eevboxsync pszEnd++;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* resize the vector. */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (cUsed == cAlloc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync cAlloc += 10;
af062818b47340eef15700d2f0211576ba3506eevboxsync void *pvNew = RTMemRealloc(papszArgs, sizeof(char *) * (cAlloc + 1));
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!pvNew)
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync papszArgs = (char **)pvNew;
af062818b47340eef15700d2f0211576ba3506eevboxsync for (size_t i = cUsed; i <= cAlloc; i++)
af062818b47340eef15700d2f0211576ba3506eevboxsync papszArgs[i] = NULL;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* add it */
af062818b47340eef15700d2f0211576ba3506eevboxsync papszArgs[cUsed++] = RTStrDupN(pszArgs, (uintptr_t)pszEnd - (uintptr_t)pszArgs);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!papszArgs[cUsed++])
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* advance */
af062818b47340eef15700d2f0211576ba3506eevboxsync pszArgs = pszEnd;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceExecFreeArgV(papszArgs);
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @copydoc VBOXSERVICE::pfnWorker */
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLCALLBACK(int) VBoxServiceExecWorker(bool volatile *pfShutdown)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync int rcRet = VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Tell the control thread that it can continue
af062818b47340eef15700d2f0211576ba3506eevboxsync * spawning services.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync RTThreadUserSignal(RTThreadSelf());
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(g_uExecGuestPropSvcClientID > 0);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Execution loop.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * The thread at the moment does nothing but checking for one specific guest property
af062818b47340eef15700d2f0211576ba3506eevboxsync * for triggering a hard coded sysprep command with parameters given by the host. This
af062818b47340eef15700d2f0211576ba3506eevboxsync * feature was required by the VDI guys.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Later this thread could become a general host->guest executor.. there are some
af062818b47340eef15700d2f0211576ba3506eevboxsync * sketches for this in the code.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef FULL_FEATURED_EXEC
af062818b47340eef15700d2f0211576ba3506eevboxsync uint64_t u64TimestampPrev = UINT64_MAX;
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync bool fSysprepDone = false;
af062818b47340eef15700d2f0211576ba3506eevboxsync bool fBitchedAboutMissingSysPrepCmd = false;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync for (;;)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync#if 0 /** @todo r=bird: This code needs reviewing and testing before it can be enabled. */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!fSysprepDone)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Get the sysprep command and arguments.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * The sysprep executable location is either retrieved from the host
af062818b47340eef15700d2f0211576ba3506eevboxsync * or is in a hard coded location depending on the Windows version.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync char *pszSysprepExec = NULL;
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef SYSPREP_WITH_CMD
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = VBoxServiceExecReadHostProp("/VirtualBox/HostGuest/SysprepExec", &pszSysprepExec, NULL);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc) && !*pszSysprepExec)
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NOT_FOUND;
af062818b47340eef15700d2f0211576ba3506eevboxsync#else
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Predefined sys. */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync char szSysprepCmd[RTPATH_MAX] = "C:\\sysprep\\sysprep.exe";
af062818b47340eef15700d2f0211576ba3506eevboxsync OSVERSIONINFOEX OSInfoEx;
af062818b47340eef15700d2f0211576ba3506eevboxsync RT_ZERO(OSInfoEx);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
af062818b47340eef15700d2f0211576ba3506eevboxsync && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT
af062818b47340eef15700d2f0211576ba3506eevboxsync && OSInfoEx.dwMajorVersion >= 6 /* Vista */)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = RTEnvGetEx(RTENV_DEFAULT, "windir", szSysPrepCmd, sizeof(szSysPrepCmd), NULL);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = RTPathAppend(szSysPrepCmd, sizeof(szSysPrepCmd), "system32\\sysprep\\sysprep.exe");
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync pszSysprepExec = szSysprepCmd;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync char *pszSysprepArgs;
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VBoxServiceExecReadHostProp("/VirtualBox/HostGuest/SysprepArgs", &pszSysprepArgs, NULL);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc) && !*pszSysprepArgs)
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NOT_FOUND;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RTFileExists(pszSysprepExec))
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync char **papszArgs;
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VBoxServiceExecCreateArgV(pszSysprepExec, pszSysprepArgs, &papszArgs);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Execute it synchronously and store the result.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * Note that RTProcWait should never fail here and
af062818b47340eef15700d2f0211576ba3506eevboxsync * that (the host is screwed if it does though).
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(3, "Exec: Executing sysprep ...\n");
af062818b47340eef15700d2f0211576ba3506eevboxsync for (size_t i = 0; papszArgs[i]; i++)
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(3, "Exec: sysprep argv[%u]: \"%s\"\n", i, papszArgs[i]);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync RTPROCESS pid;
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = RTProcCreate(pszSysprepExec, papszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &pid);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync RTPROCSTATUS Status;
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = RTProcWait(pid, RTPROCWAIT_FLAGS_BLOCK, &Status);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync if (RT_SUCCESS(rc))
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(1, "Sysprep returned: %d (reason %d)\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync Status.iStatus, Status.enmReason);
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @todo r=bird: Figure out whether you should try re-execute sysprep if it
af062818b47340eef15700d2f0211576ba3506eevboxsync * fails or not. This is not mentioned in the defect. */
af062818b47340eef15700d2f0211576ba3506eevboxsync fSysprepDone = true; /* paranoia */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Store the result in Set return value so the host knows what happend.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VbglR3GuestPropWriteValueF(g_uExecGuestPropSvcClientID,
af062818b47340eef15700d2f0211576ba3506eevboxsync "/VirtualBox/HostGuest/SysprepRet",
af062818b47340eef15700d2f0211576ba3506eevboxsync "%d", Status.iStatus);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_FAILURE(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: Failed to write SysprepRet: rc=%Rrc\n", rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: RTProcWait failed for sysprep: %Rrc\n", rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceExecFreeArgV(papszArgs);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: VBoxServiceExecCreateArgV: %Rrc\n", rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!fBitchedAboutMissingSysPrepCmd)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: Sysprep executable not found! Search path=%s\n", pszSysprepExec);
af062818b47340eef15700d2f0211576ba3506eevboxsync fBitchedAboutMissingSysPrepCmd = true;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_FILE_NOT_FOUND;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync RTStrFree(pszSysprepArgs);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifndef SYSPREP_WITH_CMD
af062818b47340eef15700d2f0211576ba3506eevboxsync RTStrFree(pszSysprepExec);
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Only continue polling if the guest property value is empty/missing
af062818b47340eef15700d2f0211576ba3506eevboxsync * or if the sysprep command is missing.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( rc != VERR_NOT_FOUND
af062818b47340eef15700d2f0211576ba3506eevboxsync && rc != VERR_FILE_NOT_FOUND)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceVerbose(1, "Exec: Stopping sysprep processing (rc=%Rrc)\n", rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VbglR3GuestPropWriteValueF(g_uExecGuestPropSvcClientID, "/VirtualBox/HostGuest/SysprepVBoxRC", "%d", rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_FAILURE(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: Failed to write SysprepVBoxRC: rc=%Rrc\n", rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync fSysprepDone = true;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* temporarily disabled. */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef FULL_FEATURED_EXEC
af062818b47340eef15700d2f0211576ba3506eevboxsync 1. Read the command - value, timestamp and flags.
af062818b47340eef15700d2f0211576ba3506eevboxsync 2. Check that the flags indicates that the guest cannot write to it and that it's transient.
af062818b47340eef15700d2f0211576ba3506eevboxsync 3. Check if the timestamp changed.
af062818b47340eef15700d2f0211576ba3506eevboxsync 4. Get the arguments and other stuff.
af062818b47340eef15700d2f0211576ba3506eevboxsync 5. Execute it. This may involve grabbing the output (stderr and/or stdout) and pushing into
af062818b47340eef15700d2f0211576ba3506eevboxsync values afterwards. It may also entail redirecting input to a file containing text from a guest prop value.
af062818b47340eef15700d2f0211576ba3506eevboxsync 6. Set the result values (there will be three, one IPRT style one for everything up to
af062818b47340eef15700d2f0211576ba3506eevboxsync and including RTProcWait and two that mirrors Status.iStatus and Status.enmReason (stringified)).
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Block for a while.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * The event semaphore takes care of ignoring interruptions and it
af062818b47340eef15700d2f0211576ba3506eevboxsync * allows us to implement service wakeup later.
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (*pfShutdown)
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef FULL_FEATURED_EXEC
af062818b47340eef15700d2f0211576ba3506eevboxsync Wait for changes to the command value. If that fails for some reason other than timeout / interrupt, fall back on the semaphore.
af062818b47340eef15700d2f0211576ba3506eevboxsync#else
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc2 = RTSemEventMultiWait(g_hExecEvent, g_cMsExecInterval);
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync if (*pfShutdown)
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceError("Exec: Service terminating - RTSemEventMultiWait: %Rrc\n", rc2);
af062818b47340eef15700d2f0211576ba3506eevboxsync rcRet = rc2;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync RTSemEventMultiDestroy(g_hExecEvent);
af062818b47340eef15700d2f0211576ba3506eevboxsync g_hExecEvent = NIL_RTSEMEVENTMULTI;
af062818b47340eef15700d2f0211576ba3506eevboxsync return rcRet;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @copydoc VBOXSERVICE::pfnStop */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic DECLCALLBACK(void) VBoxServiceExecStop(void)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Later, figure what to do if we're in RTProcWait(). it's a very
af062818b47340eef15700d2f0211576ba3506eevboxsync * annoying call since doesn't support timeouts in the posix world. */
af062818b47340eef15700d2f0211576ba3506eevboxsync RTSemEventMultiSignal(g_hExecEvent);
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef FULL_FEATURED_EXEC
af062818b47340eef15700d2f0211576ba3506eevboxsync Interrupts waits.
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @copydoc VBOXSERVICE::pfnTerm */
af062818b47340eef15700d2f0211576ba3506eevboxsyncstatic DECLCALLBACK(void) VBoxServiceExecTerm(void)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Nothing here yet. */
af062818b47340eef15700d2f0211576ba3506eevboxsync VbglR3GuestPropDisconnect(g_uExecGuestPropSvcClientID);
af062818b47340eef15700d2f0211576ba3506eevboxsync g_uExecGuestPropSvcClientID = 0;
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync RTSemEventMultiDestroy(g_hExecEvent);
af062818b47340eef15700d2f0211576ba3506eevboxsync g_hExecEvent = NIL_RTSEMEVENTMULTI;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/**
af062818b47340eef15700d2f0211576ba3506eevboxsync * The 'vminfo' service description.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsyncVBOXSERVICE g_Exec =
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync /* pszName. */
af062818b47340eef15700d2f0211576ba3506eevboxsync "exec",
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync /* pszDescription. */
af062818b47340eef15700d2f0211576ba3506eevboxsync "Host-driven Command Execution",
af062818b47340eef15700d2f0211576ba3506eevboxsync /* pszUsage. */
af062818b47340eef15700d2f0211576ba3506eevboxsync "[--exec-interval <ms>]"
af062818b47340eef15700d2f0211576ba3506eevboxsync ,
af062818b47340eef15700d2f0211576ba3506eevboxsync /* pszOptions. */
af062818b47340eef15700d2f0211576ba3506eevboxsync " --exec-interval Specifies the interval at which to check for new\n"
af062818b47340eef15700d2f0211576ba3506eevboxsync " remote execution commands. The default is 10000 ms.\n"
af062818b47340eef15700d2f0211576ba3506eevboxsync ,
af062818b47340eef15700d2f0211576ba3506eevboxsync /* methods */
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceExecPreInit,
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceExecOption,
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceExecInit,
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceExecWorker,
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceExecStop,
af062818b47340eef15700d2f0211576ba3506eevboxsync VBoxServiceExecTerm
af062818b47340eef15700d2f0211576ba3506eevboxsync};
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync