VBoxService.cpp revision 1bf88a54387e004678654cf5158075f59e3be168
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * VBoxService - Guest Additions Service Skeleton.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Copyright (C) 2007-2009 Sun Microsystems, Inc.
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 * 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.
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/*******************************************************************************
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync* Header Files *
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync*******************************************************************************/
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** @todo LOG_GROUP*/
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/*******************************************************************************
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync* Global Variables *
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync*******************************************************************************/
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** The program name (derived from argv[0]). */
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** The current verbosity level. */
b0ad0bbadf3a5b5258acda1bfe16f0ad8bee5ff0vboxsync/** The default service interval (the -i | --interval) option). */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync/** Shutdown the main thread. (later, for signals.) */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncbool volatile g_fShutdown;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * The details of the services that has been compiled in.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncstatic struct
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** Pointer to the service descriptor. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** The worker thread. NIL_RTTHREAD if it's the main 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 /** Whether the service is enabled or not. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync { &g_Control, NIL_RTTHREAD, false, false, false, true },
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync { &g_TimeSync, NIL_RTTHREAD, false, false, false, true },
a2d9f81753c129b5e3bbe3769627dcd25a3724bdvboxsync { &g_Clipboard, NIL_RTTHREAD, false, false, false, true },
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync { &g_VMInfo, NIL_RTTHREAD, false, false, false, true },
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync { &g_Exec, NIL_RTTHREAD, false, false, false, true },
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Displays the program usage message.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @returns 1.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncstatic int VBoxServiceUsage(void)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf("usage: %s [-f|--foreground] [-v|--verbose] [-i|--interval <seconds>]\n"
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync " [--disable-<service>] [--enable-<service>] [-h|-?|--help]\n", g_pszProgName);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
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"
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync RTPrintf(" -r | --register Installs the service.\n"
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync " -u | --unregister Uninstall service.\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync "Service specific options:\n");
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
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 " Copyright (C) 2009 Sun Microsystems, Inc.\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Displays a syntax error message.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @returns 1
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pszFormat The message text.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param ... Format arguments.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync RTStrmPrintf(g_pStdErr, "%s: syntax error: ", g_pszProgName);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Displays an error message.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @returns 1
4cf22805d13f50eef86e917f2c7106fe5198a2d8vboxsync * @param pszFormat The message text.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @param ... Format arguments.
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgName);
3a0bc95d0adf57baefd303e94b8f1b7b31a8f080vboxsync LogRel(("%s: Error: %N", g_pszProgName, pszFormat, &va));
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Displays a verbose message.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @returns 1
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pszFormat The message text.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * @param ... Format arguments.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsyncvoid VBoxServiceVerbose(int iLevel, const char *pszFormat, ...)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Gets a 32-bit value argument.
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.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncint VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceSyntax("Missing value for the '%s' argument\n", argv[*pi]);
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync return VBoxServiceSyntax("Failed to convert interval '%s' to a number.\n", psz);
5704a317c3b6bdf4b59f6a6ebe45d443296b1995vboxsync return VBoxServiceSyntax("The timesync interval of %RU32 secconds is out of range [%RU32..%RU32].\n",
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * The service thread.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @returns Whatever the worker function returns.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param ThreadSelf My thread handle.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param pvUser The service index.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsyncstatic DECLCALLBACK(int) VBoxServiceThread(RTTHREAD ThreadSelf, void *pvUser)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync int rc = g_aServices[i].pDesc->pfnWorker(&g_aServices[i].fShutdown);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync ASMAtomicXchgBool(&g_aServices[i].fShutdown, true);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync unsigned iMain = ~0U;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
f106b549ead77cab51ff1e2c116060aaabb90d5evboxsync return iMain; /* Return the index of the main service (must always come last!). */
ad9e5a61fea617d40d07390ff1737277d6aef869vboxsync * Starts the service.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @returns VBox status code, errors are fully bitched.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * @param iMain The index of the service that belongs to the main
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync * thread. Pass ~0U if none does.
b8c2e8ba48bd659fa09a06770a7cedfae977d73bvboxsync * Initialize the services.
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync VBoxServiceVerbose(2, "Initializing services ...\n");
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
1e289ac7f0c5324ef5712727fc61b2a322eb2e1avboxsync VBoxServiceError("Service '%s' failed to initialize: %Rrc\n",
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Start the service(s).
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
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 VBoxServiceError("RTThreadCreate failed, rc=%Rrc\n", rc);
b6957a412c94dd85c0e5f9e201bb715c4b685f2fvboxsync /* wait for the thread to initialize */
a1a2e3f1c3ca7d6190c90ff67b7995b50b258794vboxsync RTThreadUserWait(g_aServices[j].Thread, 60 * 1000);
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 VBoxServiceError("Service '%s' stopped unexpected; rc=%Rrc\n", g_aServices[iMain].pDesc->pszName, rc);
4114dcbc0414579cc42b66f4f7bd464a37672af7vboxsync /* Should never get here. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Stops and terminates the services.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * This should be called even when VBoxServiceStartServices fails so it can
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * clean up anything that we succeeded in starting.
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 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
3d7b51bd4d6fdb130637f3160fe6a5816f1babe3vboxsync int rc = RTThreadWait(g_aServices[j].Thread, 30*1000, NULL);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync VBoxServiceError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceVerbose(2, "Stopping services returned: rc=%Rrc\n", rc);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Init globals and such.
6a3efac09015e76c24ba7e9eb7436c82891bb2c8vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
a425b5e790c27d6a1a2cf738802e9034f0764a00vboxsync return VBoxServiceError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName);
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);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync VBoxServiceError("%s is already running! Terminating.", g_pszProgName);
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync /* Close the mutex for this application instance. */
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync * Parse the arguments.
bddad5eeab93a98d4ea571ccdf016531bb4318advboxsync bool fDaemonzied = false;
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceSyntax("Unknown argument '%s'\n", psz);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* translate long argument to short */
47699a0c42ead32866009e0d91bfb349490feaf9vboxsync#define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \
70f7b6ff8dc13303a70e552dd7003aa672e985a2vboxsync bool fFound = false;
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)))
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)))
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
ac2b2ae448fe887af9a3269e40afff11ebb1f9d3vboxsync return VBoxServiceSyntax("Unknown option '%s'\n", argv[i]);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* handle the string of short options. */
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync bool fFound = false;
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync return VBoxServiceSyntax("Unknown option '%c' (%s)\n", *psz, argv[i]);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Check that at least one service is enabled.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync return VBoxServiceSyntax("At least one service must be enabled.\n");
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * Connect to the kernel part before daemonizing so we can fail
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync * and complain if there is some kind of problem.
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceError("VbglR3Init failed with rc=%Rrc.\n", rc);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync VBoxServiceVerbose(0, "Started. Verbose level = %d\n", g_cVerbosity);
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Daemonize if requested.
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 * 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.
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * You should return when StartServiceCtrlDispatcher, btw., not
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * continue.
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 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */);
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync return VBoxServiceError("Daemon failed: %Rrc\n", rc);
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync /* in-child */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /* Run the app just like a console one if not daemonized. */
2711c80499bbd95e3da4a6cd2dffd9f81a5dce98vboxsync /** @todo Make the main thread responsive to signal so it can shutdown/restart the threads on non-SIGKILL signals. */
d40a840eecf0146eee47c14edaef7ace1ddfb5a6vboxsync * Start the service, enter the main threads run loop and stop them again when it returns.
3dd53c06fd54914761cf550503f02fce1ed5a815vboxsync * Release instance mutex if we got it.