VBoxService.cpp revision e60b397fc7f34482960cc63f63db84d6a02226d1
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * VBoxService - Guest Additions Service Skeleton.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Copyright (C) 2007 innotek GmbH
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * available from http://www.virtualbox.org. This file is free software;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * you can redistribute it and/or modify it under the terms of the GNU
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * General Public License (GPL) as published by the Free Software
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/*******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Header Files *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync*******************************************************************************/
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/*******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Global Variables *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync*******************************************************************************/
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** The program name (derived from argv[0]). */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** The current verbosity level. */
881b5ff6bc55e1fb0f4ef42f9782ccec79c0a138vboxsync/** The default service interval (the -i | --interval) option). */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** Shutdown the main thread. (later, for signals) */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncbool volatile g_fShutdown;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * The details of the services that has been compiled in.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic struct
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** Pointer to the service descriptor. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** The worker thread. NIL_RTTHREAD if it's the main thread. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** Shutdown indicator. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync bool volatile fShutdown;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** Indicator set by the service thread exiting. */
9621896680fea9b2078823e8ef2e64cec5bf2da0vboxsync bool volatile fStopped;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** Whether the service was started or not. */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /** Whether the service is enabled or not. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync { &g_Control, NIL_RTTHREAD, false, false, false, true },
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync { &g_TimeSync, NIL_RTTHREAD, false, false, false, true },
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync { &g_Clipboard, NIL_RTTHREAD, false, false, false, true },
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Displays the program usage message.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns 1.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic int VBoxServiceUsage(void)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTPrintf("usage: %s [-f|--foreground] [-v|--verbose] [-i|--interval <seconds>]\n"
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync " [--disable-<service>] [--enable-<service>] [-h|-?|--help]\n", g_pszProgName);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync "Options:\n"
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync " -f | --foreground Don't daemonzie the program. For debugging.\n"
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync " -v | --verbose Increment the verbosity level. For debugging.\n"
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync " -i | --interval The default interval.\n"
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync " -h | -? | --help Show this message and exit with status 1.\n");
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTPrintf(" --enable-%-10s Enables the %s service. (default)\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTPrintf(" --disable-%-9s Disables the %s service.\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync " Copyright (C) 2008 Sun Microsystems, Inc.\n");
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Displays a syntax error message.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns 1
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync * @param pszFormat The message text.
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync * @param ... Format arguments.
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync RTStrmPrintf(g_pStdErr, "%s: syntax error: ", g_pszProgName);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Displays an error message.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns 1
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pszFormat The message text.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param ... Format arguments.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgName);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Displays a verbose message.
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync * @returns 1
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pszFormat The message text.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param ... Format arguments.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncvoid VBoxServiceVerbose(int iLevel, const char *pszFormat, ...)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Gets a 32-bit value argument.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns 0 on success, non-zero exit code on error.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param argc The argument count.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param argv The argument vector
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param psz Where in *pi to start looking for the value argument.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pi Where to find and perhaps update the argument index.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pu32 Where to store the 32-bit value.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param u32Min The minimum value.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param u32Max The maximum value.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncint VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceSyntax("Missing value for the '%s' argument\n", argv[*pi]);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceSyntax("Failed to convert interval '%s' to a number.\n", psz);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceSyntax("The timesync interval of %RU32 secconds is out of range [%RU32..%RU32].\n",
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * The service thread.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns Whatever the worker function returns.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param ThreadSelf My thread handle.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pvUser The service index.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic DECLCALLBACK(int) VBoxServiceThread(RTTHREAD ThreadSelf, void *pvUser)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync int rc = g_aServices[i].pDesc->pfnWorker(&g_aServices[i].fShutdown);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync ASMAtomicXchgBool(&g_aServices[i].fShutdown, true);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Init globals and such.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Parse the arguments.
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync bool fDaemonzied = false;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceSyntax("Unknown argument '%s'\n", psz);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /* translate long argument to short */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync bool fFound = false;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (cch > sizeof("enable-") && !memcmp(psz, "enable-", sizeof("enable-") - 1))
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (cch > sizeof("disable-") && !memcmp(psz, "disable-", sizeof("disable-") - 1))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync return VBoxServiceSyntax("Unknown option '%s'\n", argv[i]);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /* handle the string of short options. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync bool fFound = false;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceSyntax("Unknown option '%c' (%s)\n", *psz, argv[i]);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Check that at least one service is enabled.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync unsigned iMain = ~0U;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceSyntax("At least one service must be enabled.\n");
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Connect to the kernel part before daemonizing so we can fail
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * and complain if there is some kind of problem.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceError("VbglR3Init failed with rc=%Rrc.\n", rc);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Daemonize if requested.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VBoxServiceError("daemon failed: %Rrc\n", rc);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /* in-child */
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync/** @todo Make the main thread responsive to signal so it can shutdown/restart the threads on non-SIGKILL signals. */
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync * Initialize the services.
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
|| j == iMain)
VBoxServiceError("service '%s' stopped unexpected; rc=%Rrc\n", g_aServices[iMain].pDesc->pszName, rc);