VBoxService.cpp revision 7842cc482eeee0a014c096bb5c5ed25014e4e4de
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* $Id$ */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * VBoxService - Guest Additions Service Skeleton.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2007-2014 Oracle Corporation
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
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
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/*******************************************************************************
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync* Header Files *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync*******************************************************************************/
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/** @todo LOG_GROUP*/
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#ifndef _MSC_VER
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync# include <unistd.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#endif
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include <errno.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#ifndef RT_OS_WINDOWS
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync# include <signal.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync# ifdef RT_OS_OS2
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync# define pthread_sigmask sigprocmask
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync# endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef RT_OS_FREEBSD
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync# include <pthread.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <package-generated.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include "product-generated.h"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/asm.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/buildconfig.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/initterm.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/file.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef DEBUG
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync# include <iprt/memtracker.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/message.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/path.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/process.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/semaphore.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/string.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/stream.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/system.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/thread.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <VBox/log.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include "VBoxServiceInternal.h"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOX_WITH_GUEST_CONTROL
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync# include "VBoxServiceControl.h"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*******************************************************************************
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync* Global Variables *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync*******************************************************************************/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The program name (derived from argv[0]). */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncchar *g_pszProgName = (char *)"";
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The current verbosity level. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint g_cVerbosity = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncchar g_szLogFile[RTPATH_MAX + 128] = "";
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Logging parameters. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @todo Make this configurable later. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic PRTLOGGER g_pLoggerRelease = NULL;
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#ifdef DEBUG
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCRITSECT g_csLog;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The default service interval (the -i | --interval) option). */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncuint32_t g_DefaultInterval = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef RT_OS_WINDOWS
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Signal shutdown to the Windows service thread. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic bool volatile g_fWindowsServiceShutdown;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** Event the Windows service thread waits for shutdown. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic RTSEMEVENT g_hEvtWindowsService;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * The details of the services that has been compiled in.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic struct
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Pointer to the service descriptor. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PCVBOXSERVICE pDesc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The worker thread. NIL_RTTHREAD if it's the main thread. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTTHREAD Thread;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Whether Pre-init was called. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync bool fPreInited;
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 bool fStarted;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Whether the service is enabled or not. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync bool fEnabled;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync} g_aServices[] =
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOXSERVICE_CONTROL
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_Control, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOXSERVICE_TIMESYNC
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_TimeSync, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOXSERVICE_CLIPBOARD
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_Clipboard, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOXSERVICE_VMINFO
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_VMInfo, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOXSERVICE_CPUHOTPLUG
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_CpuHotPlug, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOXSERVICE_MANAGEMENT
cf3aad827eee194a3e6e68796710074b44164371vboxsync# ifdef VBOX_WITH_MEMBALLOON
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_MemBalloon, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync# endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_VMStatistics, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#if defined(VBOXSERVICE_PAGE_SHARING)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_PageSharing, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOX_WITH_SHARED_FOLDERS
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_AutoMount, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef VBOXSERVICE_WITH_DISPLAY
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync { &g_Display, NIL_RTTHREAD, false, false, false, false, true },
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync};
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* Default call-backs for services which do not need special behaviour. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @copydoc VBOXSERVICE::pfnPreInit */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncDECLCALLBACK(int) VBoxServiceDefaultPreInit(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @copydoc VBOXSERVICE::pfnOption */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncDECLCALLBACK(int) VBoxServiceDefaultOption(const char **ppszShort, int argc,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char **argv, int *pi)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NOREF(ppszShort);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NOREF(argc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NOREF(argv);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync NOREF(pi);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return -1;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @copydoc VBOXSERVICE::pfnInit */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncDECLCALLBACK(int) VBoxServiceDefaultInit(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @copydoc VBOXSERVICE::pfnTerm */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncDECLCALLBACK(void) VBoxServiceDefaultTerm(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync * Release logger callback.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @return IPRT status code.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pLoggerRelease
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param enmPhase
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pfnLog
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic void VBoxServiceLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Some introductory information. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync static RTTIMESPEC s_TimeSpec;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char szTmp[256];
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (enmPhase == RTLOGPHASE_BEGIN)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTTimeNow(&s_TimeSpec);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync switch (enmPhase)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case RTLOGPHASE_BEGIN:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease,
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 __DATE__, __TIME__, szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* the package type is interesting for Linux distributions */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char szExecName[RTPATH_MAX];
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease,
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync "Executable: %s\n"
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync "Process ID: %u\n"
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync "Package type: %s"
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync#ifdef VBOX_OSE
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync " (OSE)"
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync#endif
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync "\n",
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync pszExecName ? pszExecName : "unknown",
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync RTProcSelf(),
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync VBOX_PACKAGE_STRING);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync break;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync }
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync case RTLOGPHASE_PREROTATE:
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync break;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync case RTLOGPHASE_POSTROTATE:
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync break;
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync case RTLOGPHASE_END:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync default:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* nothing */;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Creates the default release logger outputting to the specified file.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Pass NULL for disabled logging.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @return IPRT status code.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pszLogFile Filename for log output. Optional.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint VBoxServiceLogCreate(const char *pszLogFile)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
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#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fFlags |= RTLOGFLAGS_USECRLF;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char szError[RTPATH_MAX + 128] = "";
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = RTLogCreateEx(&g_pLoggerRelease, fFlags, "all",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef DEBUG
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "VBOXSERVICE_LOG",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "VBOXSERVICE_RELEASE_LOG",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RT_ELEMENTS(s_apszGroups), s_apszGroups,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLOGDEST_STDOUT | RTLOGDEST_USER,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync szError, sizeof(szError), pszLogFile);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* register this logger as the release logger */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLogRelSetDefaultInstance(g_pLoggerRelease);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Explicitly flush the log in case of VBOXSERVICE_RELEASE_LOG=buffered. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLogFlush(g_pLoggerRelease);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncvoid VBoxServiceLogDestroy(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Displays the program usage message.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns 1.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int vboxServiceUsage(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf("Usage:\n"
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#ifdef RT_OS_WINDOWS
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf(" [-r|--register] [-u|--unregister]\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (g_aServices[j].pDesc->pszUsage)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf("%s\n", g_aServices[j].pDesc->pszUsage);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf("\n"
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 );
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef RT_OS_WINDOWS
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf(" -r | --register Installs the service.\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " -u | --unregister Uninstall service.\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf("\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync "Service-specific options:\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
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 if (g_aServices[j].pDesc->pszOptions)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf("%s", g_aServices[j].pDesc->pszOptions);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTPrintf("\n"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync " Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return 1;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Displays an error message.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns RTEXITCODE_FAILURE.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pszFormat The message text.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param ... Format arguments.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncRTEXITCODE VBoxServiceError(const char *pszFormat, ...)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync va_list args;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync va_start(args, pszFormat);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char *psz = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTStrAPrintfV(&psz, pszFormat, args);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync va_end(args);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtr(psz);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogRel(("Error: %s", psz));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTStrFree(psz);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTEXITCODE_FAILURE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Displays a verbose message.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param iLevel Minimum log level required to display this message.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pszFormat The message text.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param ... Format arguments.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncvoid VBoxServiceVerbose(int iLevel, const char *pszFormat, ...)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (iLevel <= g_cVerbosity)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef DEBUG
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = RTCritSectEnter(&g_csLog);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync va_list args;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync va_start(args, pszFormat);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char *psz = NULL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTStrAPrintfV(&psz, pszFormat, args);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync va_end(args);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtr(psz);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogRel(("%s", psz));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTStrFree(psz);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef DEBUG
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTCritSectLeave(&g_csLog);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Reports the current VBoxService status to the host.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This makes sure that the Failed state is sticky.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @return IPRT status code.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param enmStatus Status to report to the host.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint VBoxServiceReportStatus(VBoxGuestFacilityStatus enmStatus)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * VBoxGuestFacilityStatus_Failed is sticky.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync static VBoxGuestFacilityStatus s_enmLastStatus = VBoxGuestFacilityStatus_Inactive;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(4, "Setting VBoxService status to %u\n", enmStatus);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (s_enmLastStatus != VBoxGuestFacilityStatus_Failed)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = VbglR3ReportAdditionsStatus(VBoxGuestFacilityType_VBoxService,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync enmStatus, 0 /* Flags */);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_FAILURE(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("Could not report VBoxService status (%u), rc=%Rrc\n", enmStatus, rc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync s_enmLastStatus = enmStatus;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Gets a 32-bit value argument.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @todo Get rid of this and VBoxServiceArgString() as soon as we have RTOpt handling.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
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.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (*psz == ':' || *psz == '=')
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync psz++;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!*psz)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (*pi + 1 >= argc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing value for the '%s' argument\n", argv[*pi]);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync psz = argv[++*pi];
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync char *pszNext;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = RTStrToUInt32Ex(psz, &pszNext, 0, pu32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_FAILURE(rc) || *pszNext)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Failed to convert interval '%s' to a number\n", psz);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (*pu32 < u32Min || *pu32 > u32Max)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The timesync interval of %RU32 seconds is out of range [%RU32..%RU32]\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pu32, u32Min, u32Max);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
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{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync AssertPtrReturn(cbBuf, VERR_INVALID_PARAMETER);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (*psz == ':' || *psz == '=')
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync psz++;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!*psz)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (*pi + 1 >= argc)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing string for the '%s' argument\n", argv[*pi]);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync psz = argv[++*pi];
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!RTStrPrintf(pszBuf, cbBuf, "%s", psz))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTMsgErrorExit(RTEXITCODE_FAILURE, "String for '%s' argument too big\n", argv[*pi]);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * The service thread.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns Whatever the worker function returns.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param ThreadSelf My thread handle.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @param pvUser The service index.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic DECLCALLBACK(int) vboxServiceThread(RTTHREAD ThreadSelf, void *pvUser)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync const unsigned i = (uintptr_t)pvUser;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifndef RT_OS_WINDOWS
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Block all signals for this thread. Only the main thread will handle signals.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync sigset_t signalMask;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync sigfillset(&signalMask);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = g_aServices[i].pDesc->pfnWorker(&g_aServices[i].fShutdown);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync ASMAtomicXchgBool(&g_aServices[i].fShutdown, true);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RTThreadUserSignal(ThreadSelf);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
cf3aad827eee194a3e6e68796710074b44164371vboxsync * Lazily calls the pfnPreInit method on each service.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns VBox status code, error message displayed.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic RTEXITCODE vboxServiceLazyPreInit(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!g_aServices[j].fPreInited)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = g_aServices[j].pDesc->pfnPreInit();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_FAILURE(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VBoxServiceError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName, rc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_aServices[j].fPreInited = true;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return RTEXITCODE_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Count the number of enabled services.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic unsigned vboxServiceCountEnabledServices(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync unsigned cEnabled = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned i = 0; i < RT_ELEMENTS(g_aServices); i++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync cEnabled += g_aServices[i].fEnabled;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return cEnabled;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifdef RT_OS_WINDOWS
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic BOOL WINAPI VBoxServiceConsoleControlHandler(DWORD dwCtrlType)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync bool fEventHandled = FALSE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync switch (dwCtrlType)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* User pressed CTRL+C or CTRL+BREAK or an external event was sent
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * via GenerateConsoleCtrlEvent(). */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case CTRL_BREAK_EVENT:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case CTRL_CLOSE_EVENT:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case CTRL_C_EVENT:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(2, "ControlHandler: Received break/close event\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = VBoxServiceStopServices();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync fEventHandled = TRUE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync default:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** @todo Add other events here. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_FAILURE(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("ControlHandler: Event %ld handled with error rc=%Rrc\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync dwCtrlType, rc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return fEventHandled;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif /* RT_OS_WINDOWS */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Starts the service.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * @returns VBox status code, errors are fully bitched.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint VBoxServiceStartServices(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceReportStatus(VBoxGuestFacilityStatus_Init);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Initialize the services.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(2, "Initializing services ...\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (g_aServices[j].fEnabled)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = g_aServices[j].pDesc->pfnInit();
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_FAILURE(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (rc != VERR_SERVICE_DISABLED)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("Service '%s' failed to initialize: %Rrc\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_aServices[j].pDesc->pszName, rc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceReportStatus(VBoxGuestFacilityStatus_Failed);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_aServices[j].fEnabled = false;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(0, "Service '%s' was disabled because of missing functionality\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_aServices[j].pDesc->pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Start the service(s).
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(2, "Starting services ...\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!g_aServices[j].fEnabled)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync continue;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
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 if (RT_FAILURE(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("RTThreadCreate failed, rc=%Rrc\n", rc);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync g_aServices[j].fStarted = true;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
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 if (g_aServices[j].fShutdown)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("Service '%s' failed to start!\n", g_aServices[j].pDesc->pszName);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = VERR_GENERAL_FAILURE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_SUCCESS(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceVerbose(1, "All services started.\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceError("An error occcurred while the services!\n");
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceReportStatus(VBoxGuestFacilityStatus_Failed);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/**
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Stops and terminates the services.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This should be called even when VBoxServiceStartServices fails so it can
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * clean up anything that we succeeded in starting.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncint VBoxServiceStopServices(void)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminating);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Signal all the services.
*/
for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
ASMAtomicWriteBool(&g_aServices[j].fShutdown, true);
/*
* Do the pfnStop callback on all running services.
*/
for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
if (g_aServices[j].fStarted)
{
VBoxServiceVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName);
g_aServices[j].pDesc->pfnStop();
}
VBoxServiceVerbose(3, "All stop functions for services called\n");
/*
* Wait for all the service threads to complete.
*/
int rc = VINF_SUCCESS;
for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
{
if (!g_aServices[j].fEnabled) /* Only stop services which were started before. */
continue;
if (g_aServices[j].Thread != NIL_RTTHREAD)
{
VBoxServiceVerbose(2, "Waiting for service '%s' to stop ...\n", g_aServices[j].pDesc->pszName);
int rc2 = VINF_SUCCESS;
for (int i = 0; i < 30; i++) /* Wait 30 seconds in total */
{
rc2 = RTThreadWait(g_aServices[j].Thread, 1000 /* Wait 1 second */, NULL);
if (RT_SUCCESS(rc2))
break;
#ifdef RT_OS_WINDOWS
/* Notify SCM that it takes a bit longer ... */
VBoxServiceWinSetStopPendingStatus(i + j*32);
#endif
}
if (RT_FAILURE(rc2))
{
VBoxServiceError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc2);
rc = rc2;
}
}
VBoxServiceVerbose(3, "Terminating service '%s' (%d) ...\n", g_aServices[j].pDesc->pszName, j);
g_aServices[j].pDesc->pfnTerm();
}
#ifdef RT_OS_WINDOWS
/*
* Wake up and tell the main() thread that we're shutting down (it's
* sleeping in VBoxServiceMainWait).
*/
ASMAtomicWriteBool(&g_fWindowsServiceShutdown, true);
if (g_hEvtWindowsService != NIL_RTSEMEVENT)
{
VBoxServiceVerbose(3, "Stopping the main thread...\n");
int rc2 = RTSemEventSignal(g_hEvtWindowsService);
AssertRC(rc2);
}
#endif
VBoxServiceVerbose(2, "Stopping services returning: %Rrc\n", rc);
VBoxServiceReportStatus(RT_SUCCESS(rc) ? VBoxGuestFacilityStatus_Paused : VBoxGuestFacilityStatus_Failed);
return rc;
}
/**
* Block the main thread until the service shuts down.
*/
void VBoxServiceMainWait(void)
{
int rc;
VBoxServiceReportStatus(VBoxGuestFacilityStatus_Active);
#ifdef RT_OS_WINDOWS
/*
* Wait for the semaphore to be signalled.
*/
VBoxServiceVerbose(1, "Waiting in main thread\n");
rc = RTSemEventCreate(&g_hEvtWindowsService);
AssertRC(rc);
while (!ASMAtomicReadBool(&g_fWindowsServiceShutdown))
{
rc = RTSemEventWait(g_hEvtWindowsService, RT_INDEFINITE_WAIT);
AssertRC(rc);
}
RTSemEventDestroy(g_hEvtWindowsService);
g_hEvtWindowsService = NIL_RTSEMEVENT;
#else
/*
* Wait explicitly for a HUP, INT, QUIT, ABRT or TERM signal, blocking
* all important signals.
*
* The annoying EINTR/ERESTART loop is for the benefit of Solaris where
* sigwait returns when we receive a SIGCHLD. Kind of makes sense since
*/
sigset_t signalMask;
sigemptyset(&signalMask);
sigaddset(&signalMask, SIGHUP);
sigaddset(&signalMask, SIGINT);
sigaddset(&signalMask, SIGQUIT);
sigaddset(&signalMask, SIGABRT);
sigaddset(&signalMask, SIGTERM);
pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
int iSignal;
do
{
iSignal = -1;
rc = sigwait(&signalMask, &iSignal);
}
while ( rc == EINTR
# ifdef ERESTART
|| rc == ERESTART
# endif
);
VBoxServiceVerbose(3, "VBoxServiceMainWait: Received signal %d (rc=%d)\n", iSignal, rc);
#endif /* !RT_OS_WINDOWS */
}
int main(int argc, char **argv)
{
RTEXITCODE rcExit;
/*
* Init globals and such.
*/
int rc = RTR3InitExe(argc, &argv, 0);
if (RT_FAILURE(rc))
return RTMsgInitFailure(rc);
g_pszProgName = RTPathFilename(argv[0]);
#ifdef DEBUG
rc = RTCritSectInit(&g_csLog);
AssertRC(rc);
#endif
#ifdef VBOXSERVICE_TOOLBOX
/*
* Run toolbox code before all other stuff since these things are simpler
* shell/file/text utility like programs that just happens to be inside
* VBoxService and shouldn't be subject to /dev/vboxguest, pid-files and
* global mutex restrictions.
*/
if (VBoxServiceToolboxMain(argc, argv, &rcExit))
return rcExit;
#endif
bool fUserSession = false;
#ifdef VBOX_WITH_GUEST_CONTROL
/*
* Check if we're the specially spawned VBoxService.exe process that
* handles a guest control session.
*/
if ( argc >= 2
&& !RTStrICmp(argv[1], "guestsession"))
fUserSession = true;
#endif
/*
* Connect to the kernel part before daemonizing so we can fail and
* complain if there is some kind of problem. We need to initialize the
* guest lib *before* we do the pre-init just in case one of services needs
* do to some initial stuff with it.
*/
if (fUserSession)
rc = VbglR3InitUser();
else
rc = VbglR3Init();
if (RT_FAILURE(rc))
{
if (rc == VERR_ACCESS_DENIED)
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n",
g_pszProgName);
return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc);
}
#ifdef RT_OS_WINDOWS
/*
* Check if we're the specially spawned VBoxService.exe process that
* handles page fusion. This saves an extra executable.
*/
if ( argc == 2
&& !RTStrICmp(argv[1], "pagefusion"))
return VBoxServicePageSharingInitFork();
#endif
#ifdef VBOX_WITH_GUEST_CONTROL
/*
* Check if we're the specially spawned VBoxService.exe process that
* handles a guest control session.
*/
if (fUserSession)
return VBoxServiceControlSessionForkInit(argc, argv);
#endif
/*
* Parse the arguments.
*
* Note! This code predates RTGetOpt, thus the manual parsing.
*/
bool fDaemonize = true;
bool fDaemonized = false;
for (int i = 1; i < argc; i++)
{
const char *psz = argv[i];
if (*psz != '-')
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz);
psz++;
/* translate long argument to short */
if (*psz == '-')
{
psz++;
size_t cch = strlen(psz);
#define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \
&& !memcmp(psz, strconst, sizeof(strconst) - 1) )
if (MATCHES("foreground"))
psz = "f";
else if (MATCHES("verbose"))
psz = "v";
else if (MATCHES("version"))
psz = "V";
else if (MATCHES("help"))
psz = "h";
else if (MATCHES("interval"))
psz = "i";
#ifdef RT_OS_WINDOWS
else if (MATCHES("register"))
psz = "r";
else if (MATCHES("unregister"))
psz = "u";
#endif
else if (MATCHES("logfile"))
psz = "l";
else if (MATCHES("daemonized"))
{
fDaemonized = true;
continue;
}
else
{
bool fFound = false;
if (cch > sizeof("enable-") && !memcmp(psz, RT_STR_TUPLE("enable-")))
for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
g_aServices[j].fEnabled = true;
if (cch > sizeof("disable-") && !memcmp(psz, RT_STR_TUPLE("disable-")))
for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
g_aServices[j].fEnabled = false;
if (cch > sizeof("only-") && !memcmp(psz, RT_STR_TUPLE("only-")))
for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
{
g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName);
if (g_aServices[j].fEnabled)
fFound = true;
}
if (!fFound)
{
rcExit = vboxServiceLazyPreInit();
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
{
rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
fFound = rc == VINF_SUCCESS;
if (fFound)
break;
if (rc != -1)
return rc;
}
}
if (!fFound)
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]);
continue;
}
#undef MATCHES
}
/* handle the string of short options. */
do
{
switch (*psz)
{
case 'i':
rc = VBoxServiceArgUInt32(argc, argv, psz + 1, &i,
&g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1);
if (rc)
return rc;
psz = NULL;
break;
case 'f':
fDaemonize = false;
break;
case 'v':
g_cVerbosity++;
break;
case 'V':
RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
return RTEXITCODE_SUCCESS;
case 'h':
case '?':
return vboxServiceUsage();
#ifdef RT_OS_WINDOWS
case 'r':
return VBoxServiceWinInstall();
case 'u':
return VBoxServiceWinUninstall();
#endif
case 'l':
{
rc = VBoxServiceArgString(argc, argv, psz + 1, &i,
g_szLogFile, sizeof(g_szLogFile));
if (rc)
return rc;
psz = NULL;
break;
}
default:
{
rcExit = vboxServiceLazyPreInit();
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
bool fFound = false;
for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
{
rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
fFound = rc == VINF_SUCCESS;
if (fFound)
break;
if (rc != -1)
return rc;
}
if (!fFound)
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%c' (%s)\n", *psz, argv[i]);
break;
}
}
} while (psz && *++psz);
}
/* Check that at least one service is enabled. */
if (vboxServiceCountEnabledServices() == 0)
return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n");
rc = VBoxServiceLogCreate(strlen(g_szLogFile) ? g_szLogFile : NULL);
if (RT_FAILURE(rc))
return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log \"%s\", rc=%Rrc\n",
strlen(g_szLogFile) ? g_szLogFile : "<None>", rc);
/* Call pre-init if we didn't do it already. */
rcExit = vboxServiceLazyPreInit();
if (rcExit != RTEXITCODE_SUCCESS)
return rcExit;
#ifdef RT_OS_WINDOWS
/*
* Make sure only one instance of VBoxService runs at a time. Create a
* global mutex for that.
*
* Note! The \\Global\ namespace was introduced with Win2K, thus the
* version check.
* Note! If the mutex exists CreateMutex will open it and set last error to
* ERROR_ALREADY_EXISTS.
*/
OSVERSIONINFOEX OSInfoEx;
RT_ZERO(OSInfoEx);
OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
SetLastError(NO_ERROR);
HANDLE hMutexAppRunning;
if ( GetVersionEx((LPOSVERSIONINFO)&OSInfoEx)
&& OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT
&& OSInfoEx.dwMajorVersion >= 5 /* NT 5.0 a.k.a W2K */)
hMutexAppRunning = CreateMutex(NULL, FALSE, "Global\\" VBOXSERVICE_NAME);
else
hMutexAppRunning = CreateMutex(NULL, FALSE, VBOXSERVICE_NAME);
if (hMutexAppRunning == NULL)
{
DWORD dwErr = GetLastError();
if ( dwErr == ERROR_ALREADY_EXISTS
|| dwErr == ERROR_ACCESS_DENIED)
{
VBoxServiceError("%s is already running! Terminating.\n", g_pszProgName);
return RTEXITCODE_FAILURE;
}
VBoxServiceError("CreateMutex failed with last error %u! Terminating.\n", GetLastError());
return RTEXITCODE_FAILURE;
}
#else /* !RT_OS_WINDOWS */
/** @todo Add PID file creation here? */
#endif /* !RT_OS_WINDOWS */
VBoxServiceVerbose(0, "%s r%s started. Verbose level = %d\n",
RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity);
/*
* Daemonize if requested.
*/
if (fDaemonize && !fDaemonized)
{
#ifdef RT_OS_WINDOWS
VBoxServiceVerbose(2, "Starting service dispatcher ...\n");
rcExit = VBoxServiceWinEnterCtrlDispatcher();
#else
VBoxServiceVerbose(1, "Daemonizing...\n");
rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */,
false /* fRespawn */);
if (RT_FAILURE(rc))
return VBoxServiceError("Daemon failed: %Rrc\n", rc);
/* in-child */
#endif
}
#ifdef RT_OS_WINDOWS
else
#endif
{
/*
* Windows: We're running the service as a console application now. Start the
* services, enter the main thread's run loop and stop them again
* when it returns.
*
* POSIX: This is used for both daemons and console runs. Start all services
* and return immediately.
*/
#ifdef RT_OS_WINDOWS
# ifndef RT_OS_NT4
/* Install console control handler. */
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)VBoxServiceConsoleControlHandler, TRUE /* Add handler */))
{
VBoxServiceError("Unable to add console control handler, error=%ld\n", GetLastError());
/* Just skip this error, not critical. */
}
# endif /* !RT_OS_NT4 */
#endif /* RT_OS_WINDOWS */
rc = VBoxServiceStartServices();
rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
if (RT_SUCCESS(rc))
VBoxServiceMainWait();
#ifdef RT_OS_WINDOWS
# ifndef RT_OS_NT4
/* Uninstall console control handler. */
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)NULL, FALSE /* Remove handler */))
{
VBoxServiceError("Unable to remove console control handler, error=%ld\n", GetLastError());
/* Just skip this error, not critical. */
}
# endif /* !RT_OS_NT4 */
#else /* !RT_OS_WINDOWS */
/* On Windows - since we're running as a console application - we already stopped all services
* through the console control handler. So only do the stopping of services here on other platforms
* where the break/shutdown/whatever signal was just received. */
VBoxServiceStopServices();
#endif /* RT_OS_WINDOWS */
}
VBoxServiceReportStatus(VBoxGuestFacilityStatus_Terminated);
#ifdef RT_OS_WINDOWS
/*
* Cleanup mutex.
*/
CloseHandle(hMutexAppRunning);
#endif
VBoxServiceVerbose(0, "Ended.\n");
#ifdef DEBUG
RTCritSectDelete(&g_csLog);
//RTMemTrackerDumpAllToStdOut();
#endif
VBoxServiceLogDestroy();
return rcExit;
}