VBoxService.cpp revision 1bf88a54387e004678654cf5158075f59e3be168
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/* $Id$ */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/** @file
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * VBoxService - Guest Additions Service Skeleton.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/*
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Copyright (C) 2007-2009 Sun Microsystems, Inc.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * available from http://www.virtualbox.org. This file is free software;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * you can redistribute it and/or modify it under the terms of the GNU
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * General Public License (GPL) as published by the Free Software
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * additional information or have any questions.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/*******************************************************************************
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync* Header Files *
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync*******************************************************************************/
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** @todo LOG_GROUP*/
a55af63ead2dcca370bfc0dfe49771d9dcc61b93vboxsync#ifndef _MSC_VER
e0778e583cb4a0bdc9bcc48f5957e00a01108388vboxsync# include <unistd.h>
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#endif
a55af63ead2dcca370bfc0dfe49771d9dcc61b93vboxsync#include <errno.h>
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#include <iprt/thread.h>
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#include <iprt/string.h>
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync#include <iprt/stream.h>
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync#include <iprt/initterm.h>
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync#include <iprt/asm.h>
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync#include <iprt/path.h>
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync#include <VBox/log.h>
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync#include <VBox/VBoxGuestLib.h>
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync#include "VBoxServiceInternal.h"
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/*******************************************************************************
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync* Global Variables *
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync*******************************************************************************/
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** The program name (derived from argv[0]). */
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsyncchar *g_pszProgName = (char *)"";
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** The current verbosity level. */
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsyncint g_cVerbosity = 0;
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** The default service interval (the -i | --interval) option). */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncuint32_t g_DefaultInterval = 0;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/** Shutdown the main thread. (later, for signals.) */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncbool volatile g_fShutdown;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/**
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * The details of the services that has been compiled in.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncstatic struct
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync{
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** Pointer to the service descriptor. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync PCVBOXSERVICE pDesc;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** The worker thread. NIL_RTTHREAD if it's the main thread. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTTHREAD Thread;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** Shutdown indicator. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync bool volatile fShutdown;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** Indicator set by the service thread exiting. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync bool volatile fStopped;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** Whether the service was started or not. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync bool fStarted;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** Whether the service is enabled or not. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync bool fEnabled;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync} g_aServices[] =
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync{
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#ifdef VBOXSERVICE_CONTROL
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync { &g_Control, NIL_RTTHREAD, false, false, false, true },
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#ifdef VBOXSERVICE_TIMESYNC
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync { &g_TimeSync, NIL_RTTHREAD, false, false, false, true },
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync#endif
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync#ifdef VBOXSERVICE_CLIPBOARD
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync { &g_Clipboard, NIL_RTTHREAD, false, false, false, true },
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#ifdef VBOXSERVICE_VMINFO
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync { &g_VMInfo, NIL_RTTHREAD, false, false, false, true },
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#ifdef VBOXSERVICE_EXEC
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync { &g_Exec, NIL_RTTHREAD, false, false, false, true },
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync};
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/**
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Displays the program usage message.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @returns 1.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncstatic int VBoxServiceUsage(void)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync{
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf("usage: %s [-f|--foreground] [-v|--verbose] [-i|--interval <seconds>]\n"
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync " [--disable-<service>] [--enable-<service>] [-h|-?|--help]\n", g_pszProgName);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync#ifdef RT_OS_WINDOWS
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf(" [-r|--register] [-u|--unregister]\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf(" %s\n", g_aServices[j].pDesc->pszUsage);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf("\n"
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync "Options:\n"
7bf07b1592dfaab1a4fb6d497fd0ff1302fb7585vboxsync " -i | --interval The default interval.\n"
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync " -f | --foreground Don't daemonzie the program. For debugging.\n"
7c1f498692cd2393f8ba68cb62be482495106f93vboxsync " -v | --verbose Increment the verbosity level. For debugging.\n"
ffb14f6b8aefea7399c4bf70faab4c9fc26e6cd5vboxsync " -h | -? | --help Show this message and exit with status 1.\n"
7c1f498692cd2393f8ba68cb62be482495106f93vboxsync );
ffb14f6b8aefea7399c4bf70faab4c9fc26e6cd5vboxsync#ifdef RT_OS_WINDOWS
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf(" -r | --register Installs the service.\n"
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync " -u | --unregister Uninstall service.\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf("\n"
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync "Service specific options:\n");
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf(" --enable-%-10s Enables the %s service. (default)\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf(" --disable-%-9s Disables the %s service.\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf("%s", g_aServices[j].pDesc->pszOptions);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync }
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf("\n"
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync " Copyright (C) 2009 Sun Microsystems, Inc.\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return 1;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync}
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync/**
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Displays a syntax error message.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @returns 1
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pszFormat The message text.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param ... Format arguments.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync */
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsyncint VBoxServiceSyntax(const char *pszFormat, ...)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync{
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync RTStrmPrintf(g_pStdErr, "%s: syntax error: ", g_pszProgName);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync va_list va;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync va_start(va, pszFormat);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTStrmPrintfV(g_pStdErr, pszFormat, va);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync va_end(va);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return 1;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync}
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync/**
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Displays an error message.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync *
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @returns 1
4cf22805d13f50eef86e917f2c7106fe5198a2d8vboxsync * @param pszFormat The message text.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @param ... Format arguments.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync */
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsyncint VBoxServiceError(const char *pszFormat, ...)
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync{
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgName);
9dfcf62b7a5a289684d46ee55f6042d49509daecvboxsync
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync va_list va;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync va_start(va, pszFormat);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync RTStrmPrintfV(g_pStdErr, pszFormat, va);
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync va_end(va);
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync va_start(va, pszFormat);
3a0bc95d0adf57baefd303e94b8f1b7b31a8f080vboxsync LogRel(("%s: Error: %N", g_pszProgName, pszFormat, &va));
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync va_end(va);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync return 1;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync}
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync/**
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Displays a verbose message.
7bf07b1592dfaab1a4fb6d497fd0ff1302fb7585vboxsync *
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @returns 1
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pszFormat The message text.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @param ... Format arguments.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsyncvoid VBoxServiceVerbose(int iLevel, const char *pszFormat, ...)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync{
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync if (iLevel <= g_cVerbosity)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
9bb98d54790a98dad0ad6d9bdc5d319b6fdf0bffvboxsync RTStrmPrintf(g_pStdOut, "%s: ", g_pszProgName);
9bb98d54790a98dad0ad6d9bdc5d319b6fdf0bffvboxsync va_list va;
9bb98d54790a98dad0ad6d9bdc5d319b6fdf0bffvboxsync va_start(va, pszFormat);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTStrmPrintfV(g_pStdOut, pszFormat, va);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync va_end(va);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync va_start(va, pszFormat);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync LogRel(("%s: %N", g_pszProgName, pszFormat, &va));
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync va_end(va);
629e8f58c569e4c51a98284c41754fd9f0b973f8vboxsync }
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync}
7c1f498692cd2393f8ba68cb62be482495106f93vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync/**
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Gets a 32-bit value argument.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync *
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @returns 0 on success, non-zero exit code on error.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @param argc The argument count.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @param argv The argument vector
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * @param psz Where in *pi to start looking for the value argument.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @param pi Where to find and perhaps update the argument index.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pu32 Where to store the 32-bit value.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @param u32Min The minimum value.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param u32Max The maximum value.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncint VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync{
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (*psz == ':' || *psz == '=')
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync psz++;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (!*psz)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (*pi + 1 >= argc)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceSyntax("Missing value for the '%s' argument\n", argv[*pi]);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync psz = argv[++*pi];
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync }
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync char *pszNext;
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync int rc = RTStrToUInt32Ex(psz, &pszNext, 0, pu32);
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync if (RT_FAILURE(rc) || *pszNext)
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync return VBoxServiceSyntax("Failed to convert interval '%s' to a number.\n", psz);
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync if (*pu32 < u32Min || *pu32 > u32Max)
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync return VBoxServiceSyntax("The timesync interval of %RU32 secconds is out of range [%RU32..%RU32].\n",
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *pu32, u32Min, u32Max);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return 0;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync}
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/**
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * The service thread.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @returns Whatever the worker function returns.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param ThreadSelf My thread handle.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pvUser The service index.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncstatic DECLCALLBACK(int) VBoxServiceThread(RTTHREAD ThreadSelf, void *pvUser)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync{
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync const unsigned i = (uintptr_t)pvUser;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync int rc = g_aServices[i].pDesc->pfnWorker(&g_aServices[i].fShutdown);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync ASMAtomicXchgBool(&g_aServices[i].fShutdown, true);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync RTThreadUserSignal(ThreadSelf);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync return rc;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync}
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsyncunsigned VBoxServiceGetStartedServices(void)
432d08d68b9683d01880890d475a4cadd84b69cevboxsync{
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync unsigned iMain = ~0U;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync if (g_aServices[j].fEnabled)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync iMain = j;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync break;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync }
4114dcbc0414579cc42b66f4f7bd464a37672af7vboxsync
f106b549ead77cab51ff1e2c116060aaabb90d5evboxsync return iMain; /* Return the index of the main service (must always come last!). */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync}
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync
ad9e5a61fea617d40d07390ff1737277d6aef869vboxsync/**
ad9e5a61fea617d40d07390ff1737277d6aef869vboxsync * Starts the service.
ad9e5a61fea617d40d07390ff1737277d6aef869vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @returns VBox status code, errors are fully bitched.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param iMain The index of the service that belongs to the main
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync * thread. Pass ~0U if none does.
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync */
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsyncint VBoxServiceStartServices(unsigned iMain)
be6a25d1b25b8692d8c035b0549e5258c6986dc5vboxsync{
be6a25d1b25b8692d8c035b0549e5258c6986dc5vboxsync int rc;
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync /*
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync * Initialize the services.
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync */
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync VBoxServiceVerbose(2, "Initializing services ...\n");
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync if (g_aServices[j].fEnabled)
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync {
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync rc = g_aServices[j].pDesc->pfnInit();
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync if (RT_FAILURE(rc))
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync {
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync VBoxServiceError("Service '%s' failed to initialize: %Rrc\n",
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync g_aServices[j].pDesc->pszName, rc);
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync return rc;
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync }
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync }
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /*
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Start the service(s).
251867ef7a8ad4e0d583f4ff4dbdce6071387e26vboxsync */
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync VBoxServiceVerbose(2, "Starting services ...\n");
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync rc = VINF_SUCCESS;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
251867ef7a8ad4e0d583f4ff4dbdce6071387e26vboxsync {
251867ef7a8ad4e0d583f4ff4dbdce6071387e26vboxsync if ( !g_aServices[j].fEnabled
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync || j == iMain)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync continue;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceVerbose(2, "Starting service '%s' ...\n", g_aServices[j].pDesc->pszName);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync rc = RTThreadCreate(&g_aServices[j].Thread, VBoxServiceThread, (void *)(uintptr_t)j, 0,
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_aServices[j].pDesc->pszName);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (RT_FAILURE(rc))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceError("RTThreadCreate failed, rc=%Rrc\n", rc);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync break;
000d3a358f1072f58336eaea956b19888b123e49vboxsync }
a1a2e3f1c3ca7d6190c90ff67b7995b50b258794vboxsync g_aServices[j].fStarted = true;
a1a2e3f1c3ca7d6190c90ff67b7995b50b258794vboxsync
b6957a412c94dd85c0e5f9e201bb715c4b685f2fvboxsync /* wait for the thread to initialize */
a1a2e3f1c3ca7d6190c90ff67b7995b50b258794vboxsync RTThreadUserWait(g_aServices[j].Thread, 60 * 1000);
a1a2e3f1c3ca7d6190c90ff67b7995b50b258794vboxsync if (g_aServices[j].fShutdown)
b6957a412c94dd85c0e5f9e201bb715c4b685f2fvboxsync rc = VERR_GENERAL_FAILURE;
a1a2e3f1c3ca7d6190c90ff67b7995b50b258794vboxsync }
a1a2e3f1c3ca7d6190c90ff67b7995b50b258794vboxsync if (RT_SUCCESS(rc))
be6a25d1b25b8692d8c035b0549e5258c6986dc5vboxsync {
be6a25d1b25b8692d8c035b0549e5258c6986dc5vboxsync /* The final service runs in the main thread. */
a1a2e3f1c3ca7d6190c90ff67b7995b50b258794vboxsync VBoxServiceVerbose(1, "Starting '%s' in the main thread\n", g_aServices[iMain].pDesc->pszName);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync rc = g_aServices[iMain].pDesc->pfnWorker(&g_fShutdown);
9d3628862c2a985acccba6c4cc72684efc6c28dbvboxsync if (rc != VINF_SUCCESS) /* Only complain if service returned an error. Otherwise the service is a one-timer. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceError("Service '%s' stopped unexpected; rc=%Rrc\n", g_aServices[iMain].pDesc->pszName, rc);
432d08d68b9683d01880890d475a4cadd84b69cevboxsync }
432d08d68b9683d01880890d475a4cadd84b69cevboxsync }
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
4114dcbc0414579cc42b66f4f7bd464a37672af7vboxsync /* Should never get here. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return rc;
4114dcbc0414579cc42b66f4f7bd464a37672af7vboxsync}
8e0f079384d0e8445e59e4660763bdce27b42dd9vboxsync
8e0f079384d0e8445e59e4660763bdce27b42dd9vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/**
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Stops and terminates the services.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * This should be called even when VBoxServiceStartServices fails so it can
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * clean up anything that we succeeded in starting.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncint VBoxServiceStopServices(void)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync{
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync int rc = VINF_SUCCESS;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync ASMAtomicXchgBool(&g_aServices[j].fShutdown, true);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (g_aServices[j].fStarted)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync g_aServices[j].pDesc->pfnStop();
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (g_aServices[j].fEnabled)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
a55af63ead2dcca370bfc0dfe49771d9dcc61b93vboxsync if (g_aServices[j].Thread != NIL_RTTHREAD)
3d7b51bd4d6fdb130637f3160fe6a5816f1babe3vboxsync {
3d7b51bd4d6fdb130637f3160fe6a5816f1babe3vboxsync int rc = RTThreadWait(g_aServices[j].Thread, 30*1000, NULL);
18cbdecd71d504221768c44a14b6eecbed66c252vboxsync if (RT_FAILURE(rc))
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync VBoxServiceError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync }
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync g_aServices[j].pDesc->pfnTerm();
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync }
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceVerbose(2, "Stopping services returned: rc=%Rrc\n", rc);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return rc;
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync}
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsyncint main(int argc, char **argv)
6a3efac09015e76c24ba7e9eb7436c82891bb2c8vboxsync{
6a3efac09015e76c24ba7e9eb7436c82891bb2c8vboxsync int rc = VINF_SUCCESS;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /*
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Init globals and such.
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTR3Init();
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync g_pszProgName = RTPathFilename(argv[0]);
6a3efac09015e76c24ba7e9eb7436c82891bb2c8vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync rc = g_aServices[j].pDesc->pfnPreInit();
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (RT_FAILURE(rc))
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync return VBoxServiceError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync#ifdef RT_OS_WINDOWS
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Make sure only one instance of VBoxService runs at a time. Create a global mutex for that.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync HANDLE hMutexAppRunning = CreateMutex (NULL, FALSE, VBOXSERVICE_NAME);
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync if ( hMutexAppRunning != NULL
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync && GetLastError() == ERROR_ALREADY_EXISTS)
80626cd34607c5dbf3f0af51b32396ce58bf493bvboxsync {
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync VBoxServiceError("%s is already running! Terminating.", g_pszProgName);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Close the mutex for this application instance. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync CloseHandle(hMutexAppRunning);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync hMutexAppRunning = NULL;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync }
2294b1479e3fb6f4e9c9550b3e15f3d3a3f1fc24vboxsync#endif
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync
b306a397b157898e6f769f640b0dfdffbf8beec7vboxsync /*
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Parse the arguments.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync bool fDaemonize = true;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync bool fDaemonzied = false;
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync for (int i = 1; i < argc; i++)
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync const char *psz = argv[i];
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (*psz != '-')
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceSyntax("Unknown argument '%s'\n", psz);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync psz++;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* translate long argument to short */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (*psz == '-')
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync psz++;
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync size_t cch = strlen(psz);
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync#define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \
78dfd747e1837f5de0bc5625c39dff4b98e3d4d4vboxsync && !memcmp(psz, strconst, sizeof(strconst) - 1) )
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync if (MATCHES("foreground"))
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync psz = "f";
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync else if (MATCHES("verbose"))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync psz = "v";
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync else if (MATCHES("help"))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync psz = "h";
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync else if (MATCHES("interval"))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync psz = "i";
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#ifdef RT_OS_WINDOWS
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync else if (MATCHES("register"))
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync psz = "r";
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync else if (MATCHES("unregister"))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync psz = "u";
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync else if (MATCHES("daemonized"))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync fDaemonzied = true;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync continue;
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync }
78dfd747e1837f5de0bc5625c39dff4b98e3d4d4vboxsync else
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync {
70f7b6ff8dc13303a70e552dd7003aa672e985a2vboxsync bool fFound = false;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (cch > sizeof("enable-") && !memcmp(psz, "enable-", sizeof("enable-") - 1))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync g_aServices[j].fEnabled = true;
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync if (cch > sizeof("disable-") && !memcmp(psz, "disable-", sizeof("disable-") - 1))
78dfd747e1837f5de0bc5625c39dff4b98e3d4d4vboxsync for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync g_aServices[j].fEnabled = false;
78dfd747e1837f5de0bc5625c39dff4b98e3d4d4vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (!fFound)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync fFound = rc == 0;
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync if (fFound)
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync break;
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync if (rc != -1)
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync return rc;
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync }
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync if (!fFound)
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync return VBoxServiceSyntax("Unknown option '%s'\n", argv[i]);
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync continue;
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync }
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#undef MATCHES
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync }
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* handle the string of short options. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync do
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync switch (*psz)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync case 'i':
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync rc = VBoxServiceArgUInt32(argc, argv, psz + 1, &i,
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (rc)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return rc;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync psz = NULL;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync break;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync case 'f':
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync fDaemonize = false;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync break;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync case 'v':
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync g_cVerbosity++;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync break;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync case 'h':
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync case '?':
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceUsage();
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#ifdef RT_OS_WINDOWS
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync case 'r':
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceWinInstall();
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync case 'u':
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync return VBoxServiceWinUninstall();
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync#endif
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync default:
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync {
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync bool fFound = false;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync {
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync fFound = rc == 0;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (fFound)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync break;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (rc != -1)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return rc;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync }
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (!fFound)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync return VBoxServiceSyntax("Unknown option '%c' (%s)\n", *psz, argv[i]);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync break;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync }
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync }
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync } while (psz && *++psz);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync }
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync /*
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Check that at least one service is enabled.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync */
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync unsigned iMain = VBoxServiceGetStartedServices();
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync if (iMain == ~0U)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync return VBoxServiceSyntax("At least one service must be enabled.\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /*
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Connect to the kernel part before daemonizing so we can fail
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * and complain if there is some kind of problem.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceVerbose(2, "Calling VbgR3Init()\n");
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync rc = VbglR3Init();
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (RT_FAILURE(rc))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceError("VbglR3Init failed with rc=%Rrc.\n", rc);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceVerbose(0, "Started. Verbose level = %d\n", g_cVerbosity);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /*
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Daemonize if requested.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (fDaemonize && !fDaemonzied)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#ifdef RT_OS_WINDOWS
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** @todo Should do something like VBoxSVC here, OR automatically re-register
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * the service and start it. Involving VbglR3Daemonize isn't an option
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * here.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync *
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Also, the idea here, IIRC, was to map the sub service to windows
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * services. The todo below is for mimicking windows services on
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * non-windows systems. Not sure if this is doable or not, but in anycase
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * this code can be moved into -win.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync *
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * You should return when StartServiceCtrlDispatcher, btw., not
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * continue.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceVerbose(2, "Starting service dispatcher ...\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (!StartServiceCtrlDispatcher(&g_aServiceTable[0]))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceError("StartServiceCtrlDispatcher: %u\n", GetLastError());
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* Service now lives in the control dispatcher registered above. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#else
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceVerbose(1, "Daemonizing...\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync if (RT_FAILURE(rc))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceError("Daemon failed: %Rrc\n", rc);
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync /* in-child */
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync }
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync#ifdef RT_OS_WINDOWS
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync else
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync {
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* Run the app just like a console one if not daemonized. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#endif
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** @todo Make the main thread responsive to signal so it can shutdown/restart the threads on non-SIGKILL signals. */
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync /*
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Start the service, enter the main threads run loop and stop them again when it returns.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync rc = VBoxServiceStartServices(iMain);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceStopServices();
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync#ifdef RT_OS_WINDOWS
7bf07b1592dfaab1a4fb6d497fd0ff1302fb7585vboxsync }
ec9dc23c50665e8603e1be5a9b6b6fd4c4d949d4vboxsync#endif
ec9dc23c50665e8603e1be5a9b6b6fd4c4d949d4vboxsync
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync#ifdef RT_OS_WINDOWS
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync /*
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync * Release instance mutex if we got it.
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync */
ec9dc23c50665e8603e1be5a9b6b6fd4c4d949d4vboxsync if (hMutexAppRunning != NULL)
410216171f7f7033678589acb6e342303978c918vboxsync {
ec9dc23c50665e8603e1be5a9b6b6fd4c4d949d4vboxsync ::CloseHandle(hMutexAppRunning);
ec9dc23c50665e8603e1be5a9b6b6fd4c4d949d4vboxsync hMutexAppRunning = NULL;
ec9dc23c50665e8603e1be5a9b6b6fd4c4d949d4vboxsync }
ec9dc23c50665e8603e1be5a9b6b6fd4c4d949d4vboxsync#endif
ec9dc23c50665e8603e1be5a9b6b6fd4c4d949d4vboxsync
d1fcf24d24368926be13484524a9e378070a9157vboxsync VBoxServiceVerbose(0, "Ended.\n");
d1fcf24d24368926be13484524a9e378070a9157vboxsync return RT_SUCCESS(rc) ? 0 : 1;
d1fcf24d24368926be13484524a9e378070a9157vboxsync}
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync
7bf07b1592dfaab1a4fb6d497fd0ff1302fb7585vboxsync