VBoxService.cpp revision 7842cc482eeee0a014c096bb5c5ed25014e4e4de
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * VBoxService - Guest Additions Service Skeleton.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2007-2014 Oracle Corporation
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * available from http://www.virtualbox.org. This file is free software;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/*******************************************************************************
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync* Header Files *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync*******************************************************************************/
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/** @todo LOG_GROUP*/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*******************************************************************************
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync* Global Variables *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync*******************************************************************************/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The program name (derived from argv[0]). */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The current verbosity level. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Logging parameters. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @todo Make this configurable later. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Critical section for (debug) logging. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The default service interval (the -i | --interval) option). */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Signal shutdown to the Windows service thread. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic bool volatile g_fWindowsServiceShutdown;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Event the Windows service thread waits for shutdown. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * The details of the services that has been compiled in.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic struct
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Pointer to the service descriptor. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The worker thread. NIL_RTTHREAD if it's the main thread. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Whether Pre-init was called. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Shutdown indicator. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync bool volatile fShutdown;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Indicator set by the service thread exiting. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync bool volatile fStopped;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Whether the service was started or not. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Whether the service is enabled or not. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_Control, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_TimeSync, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_Clipboard, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_VMInfo, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_CpuHotPlug, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_MemBalloon, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_VMStatistics, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_PageSharing, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_AutoMount, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_Display, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* Default call-backs for services which do not need special behaviour. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @copydoc VBOXSERVICE::pfnOption */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncDECLCALLBACK(int) VBoxServiceDefaultOption(const char **ppszShort, int argc,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @copydoc VBOXSERVICE::pfnInit */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @copydoc VBOXSERVICE::pfnTerm */
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync * Release logger callback.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @return IPRT status code.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pLoggerRelease
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param enmPhase
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pfnLog
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic void VBoxServiceLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Some introductory information. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "VBoxService %s r%s (verbosity: %d) %s (%s %s) release log\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "Log opened %s\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity, VBOX_BUILD_TARGET,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* the package type is interesting for Linux distributions */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync "Executable: %s\n"
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync "Process ID: %u\n"
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync "Package type: %s"
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* nothing */;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Creates the default release logger outputting to the specified file.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Pass NULL for disabled logging.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @return IPRT status code.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pszLogFile Filename for log output. Optional.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Create release logger (stdout + file). */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = RTLogCreateEx(&g_pLoggerRelease, fFlags, "all",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "VBOXSERVICE_LOG",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "VBOXSERVICE_RELEASE_LOG",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* register this logger as the release logger */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Explicitly flush the log in case of VBOXSERVICE_RELEASE_LOG=buffered. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Displays the program usage message.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns 1.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int vboxServiceUsage(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " %-12s [-f|--foreground] [-v|--verbose] [-l|--logfile <file>]\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " [-i|--interval <seconds>]\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " [--disable-<service>] [--enable-<service>]\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " [--only-<service>] [-h|-?|--help]\n", g_pszProgName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "Options:\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " -i | --interval The default interval.\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " -f | --foreground Don't daemonize the program. For debugging.\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " -l | --logfile <file> Enables logging to a file.\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " -v | --verbose Increment the verbosity level. For debugging.\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " -V | --version Show version information.\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " -h | -? | --help Show this message and exit with status 1.\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf(" -r | --register Installs the service.\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " -u | --unregister Uninstall service.\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "Service-specific options:\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf(" --enable-%-14s Enables the %s service. (default)\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf(" --disable-%-13s Disables the %s service.\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf(" --only-%-16s Only enables the %s service.\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Displays an error message.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns RTEXITCODE_FAILURE.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pszFormat The message text.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param ... Format arguments.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncRTEXITCODE VBoxServiceError(const char *pszFormat, ...)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Displays a verbose message.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param iLevel Minimum log level required to display this message.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pszFormat The message text.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param ... Format arguments.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncvoid VBoxServiceVerbose(int iLevel, const char *pszFormat, ...)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Reports the current VBoxService status to the host.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This makes sure that the Failed state is sticky.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @return IPRT status code.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param enmStatus Status to report to the host.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint VBoxServiceReportStatus(VBoxGuestFacilityStatus enmStatus)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * VBoxGuestFacilityStatus_Failed is sticky.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync static VBoxGuestFacilityStatus s_enmLastStatus = VBoxGuestFacilityStatus_Inactive;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(4, "Setting VBoxService status to %u\n", enmStatus);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (s_enmLastStatus != VBoxGuestFacilityStatus_Failed)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = VbglR3ReportAdditionsStatus(VBoxGuestFacilityType_VBoxService,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("Could not report VBoxService status (%u), rc=%Rrc\n", enmStatus, rc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Gets a 32-bit value argument.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @todo Get rid of this and VBoxServiceArgString() as soon as we have RTOpt handling.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns 0 on success, non-zero exit code on error.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param argc The argument count.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param argv The argument vector
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param psz Where in *pi to start looking for the value argument.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pi Where to find and perhaps update the argument index.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pu32 Where to store the 32-bit value.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param u32Min The minimum value.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param u32Max The maximum value.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing value for the '%s' argument\n", argv[*pi]);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Failed to convert interval '%s' to a number\n", psz);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The timesync interval of %RU32 seconds is out of range [%RU32..%RU32]\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @todo Get rid of this and VBoxServiceArgUInt32() as soon as we have RTOpt handling. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint VBoxServiceArgString(int argc, char **argv, const char *psz, int *pi, char *pszBuf, size_t cbBuf)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing string for the '%s' argument\n", argv[*pi]);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "String for '%s' argument too big\n", argv[*pi]);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * The service thread.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns Whatever the worker function returns.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param ThreadSelf My thread handle.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pvUser The service index.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic DECLCALLBACK(int) vboxServiceThread(RTTHREAD ThreadSelf, void *pvUser)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Block all signals for this thread. Only the main thread will handle signals.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = g_aServices[i].pDesc->pfnWorker(&g_aServices[i].fShutdown);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync ASMAtomicXchgBool(&g_aServices[i].fShutdown, true);
cf3aad827eee194a3e6e68796710074b44164371vboxsync * Lazily calls the pfnPreInit method on each service.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns VBox status code, error message displayed.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VBoxServiceError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName, rc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Count the number of enabled services.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic unsigned vboxServiceCountEnabledServices(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync unsigned cEnabled = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned i = 0; i < RT_ELEMENTS(g_aServices); i++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic BOOL WINAPI VBoxServiceConsoleControlHandler(DWORD dwCtrlType)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* User pressed CTRL+C or CTRL+BREAK or an external event was sent
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * via GenerateConsoleCtrlEvent(). */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(2, "ControlHandler: Received break/close event\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** @todo Add other events here. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("ControlHandler: Event %ld handled with error rc=%Rrc\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif /* RT_OS_WINDOWS */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Starts the service.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns VBox status code, errors are fully bitched.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceReportStatus(VBoxGuestFacilityStatus_Init);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Initialize the services.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(2, "Initializing services ...\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("Service '%s' failed to initialize: %Rrc\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceReportStatus(VBoxGuestFacilityStatus_Failed);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(0, "Service '%s' was disabled because of missing functionality\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Start the service(s).
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(2, "Starting service '%s' ...\n", g_aServices[j].pDesc->pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = RTThreadCreate(&g_aServices[j].Thread, vboxServiceThread, (void *)(uintptr_t)j, 0,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_aServices[j].pDesc->pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("RTThreadCreate failed, rc=%Rrc\n", rc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Wait for the thread to initialize. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** @todo There is a race between waiting and checking
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * the fShutdown flag of a thread here and processing
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * the thread's actual worker loop. If the thread decides
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * to exit the loop before we skipped the fShutdown check
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * below the service will fail to start! */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** @todo This presumably means either a one-shot service or that
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * something has gone wrong. In the second case treating it as failure
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * to start is probably right, so we need a way to signal the first
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * rather than leaving the idle thread hanging around. A flag in the
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * service description? */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTThreadUserWait(g_aServices[j].Thread, 60 * 1000);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("Service '%s' failed to start!\n", g_aServices[j].pDesc->pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("An error occcurred while the services!\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceReportStatus(VBoxGuestFacilityStatus_Failed);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Stops and terminates the services.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This should be called even when VBoxServiceStartServices fails so it can
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * clean up anything that we succeeded in starting.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminating);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Signal all the services.
VBoxServiceVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName);
#ifdef RT_OS_WINDOWS
#ifdef RT_OS_WINDOWS
VBoxServiceReportStatus(RT_SUCCESS(rc) ? VBoxGuestFacilityStatus_Paused : VBoxGuestFacilityStatus_Failed);
return rc;
void VBoxServiceMainWait(void)
int rc;
#ifdef RT_OS_WINDOWS
int iSignal;
# ifdef ERESTART
#ifdef DEBUG
#ifdef VBOXSERVICE_TOOLBOX
return rcExit;
bool fUserSession = false;
#ifdef VBOX_WITH_GUEST_CONTROL
fUserSession = true;
if (fUserSession)
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n",
#ifdef RT_OS_WINDOWS
return VBoxServicePageSharingInitFork();
#ifdef VBOX_WITH_GUEST_CONTROL
if (fUserSession)
bool fDaemonize = true;
bool fDaemonized = false;
psz++;
psz++;
#ifdef RT_OS_WINDOWS
fDaemonized = true;
bool fFound = false;
fFound = true;
if (!fFound)
return rcExit;
if (fFound)
return rc;
if (!fFound)
switch (*psz)
if (rc)
return rc;
fDaemonize = false;
g_cVerbosity++;
return RTEXITCODE_SUCCESS;
return vboxServiceUsage();
#ifdef RT_OS_WINDOWS
return VBoxServiceWinInstall();
return VBoxServiceWinUninstall();
if (rc)
return rc;
return rcExit;
bool fFound = false;
if (fFound)
return rc;
if (!fFound)
if (vboxServiceCountEnabledServices() == 0)
return rcExit;
#ifdef RT_OS_WINDOWS
return RTEXITCODE_FAILURE;
return RTEXITCODE_FAILURE;
#ifdef RT_OS_WINDOWS
#ifdef RT_OS_WINDOWS
#ifdef RT_OS_WINDOWS
# ifndef RT_OS_NT4
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)VBoxServiceConsoleControlHandler, TRUE /* Add handler */))
#ifdef RT_OS_WINDOWS
# ifndef RT_OS_NT4
#ifdef RT_OS_WINDOWS
#ifdef DEBUG
return rcExit;