Beispiel #1
0
/**
 * Bitch about too many arguments (after RTGetOpt stops) in the system log.
 *
 * @returns 1
 * @param   pszAction       The action name.
 * @param   argc            The argument count.
 * @param   argv            The argument vector.
 * @param   iArg            The argument index.
 */
int supSvcLogTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg)
{
    Assert(iArg < argc);
    supSvcLogError("%s - Too many arguments: %s", pszAction, argv[iArg]);
    for ( ; iArg < argc; iArg++)
        LogRel(("arg#%i: %s\n", iArg, argv[iArg]));
    return 1;
}
Beispiel #2
0
/**
 * Instantiates and starts the services.
 *
 * @returns VBox status code. Done bitching on failure.
 */
int supSvcCreateAndStartServices(void)
{
    LogFlowFuncEnter();

    /*
     * Validate that all services are in the NotCreated state.
     */
    unsigned i;
    for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
        if (g_aServices[i].enmState != kSupSvcServiceState_NotCreated)
        {
            supSvcLogError("service %s in state %d, expected state %d (NotCreated)",
                           g_aServices[i].pszName,  g_aServices[i].enmState, kSupSvcServiceState_NotCreated);
            return VERR_WRONG_ORDER;
        }

    /*
     * Create all the services, then start them.
     */
    int rc = VINF_SUCCESS;
    for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
    {
        void *pvInstance = NULL;
        int rc = g_aServices[i].pfnCreate(&pvInstance);
        if (RT_FAILURE(rc))
        {
            Log(("supSvcCreateAndStartServices: %s -> %Rrc\n", g_aServices[i].pszName, rc));
            break;
        }
        g_aServices[i].pvInstance = pvInstance;
        g_aServices[i].enmState = kSupSvcServiceState_Paused;
    }
    if (RT_SUCCESS(rc))
    {
        for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
        {
            g_aServices[i].pfnStart(g_aServices[i].pvInstance);
            g_aServices[i].enmState = kSupSvcServiceState_Running;
        }
    }
    else
    {
        /*
         * Destroy any services we managed to instantiate.
         */
        while (i-- > 0)
        {
            g_aServices[i].pfnStopAndDestroy(g_aServices[i].pvInstance, false /* fRunning */);
            g_aServices[i].pvInstance = NULL;
            g_aServices[i].enmState = kSupSvcServiceState_NotCreated;
        }
    }

    LogFlow(("supSvcCreateAndStartServices: returns %Rrc\n", rc));
    return rc;
}
Beispiel #3
0
/**
 * Handle the 'create' action.
 *
 * @returns 0 or 1.
 * @param   argc    The action argument count.
 * @param   argv    The action argument vector.
 */
static int supSvcWinRunIt(int argc, char **argv)
{
    LogFlowFuncEnter();

    /*
     * Initialize release logging.
     */
    /** @todo release logging of the system-wide service. */

    /*
     * Parse the arguments.
     */
    static const RTOPTIONDEF s_aOptions[] =
    {
        { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
    };
    int iArg = 0;
    int ch;
    RTGETOPTUNION Value;
    while ((ch = RTGetOpt(argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
        switch (ch)
        {
            default:    return supSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value);
        }
    if (iArg != argc)
        return supSvcDisplayTooManyArgsError("runit", argc, argv, iArg);

    /*
     * Register the service with the service control manager
     * and start dispatching requests from it (all done by the API).
     */
    static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] =
    {
        { SUPSVC_SERVICE_NAME, supSvcWinServiceMain },
        { NULL, NULL}
    };
    if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0]))
    {
        LogFlowFuncLeave();
        return 0; /* told to quit, so quit. */
    }

    DWORD err = GetLastError();
    switch (err)
    {
        case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
            supSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
            break;
        default:
            supSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err);
            break;
    }
    return 1;
}
Beispiel #4
0
/**
 * Checks if it's possible to stop the services.
 *
 * @returns VBox status code, done bitching on failure.
 */
int supSvcTryStopServices(void)
{
    LogFlowFuncEnter();

    /*
     * Check that the services are all created and count the running ones.
     */
    unsigned i;
    unsigned cRunning = 0;
    for (i = 0; i < RT_ELEMENTS(g_aServices); i++)
        if (g_aServices[i].enmState == kSupSvcServiceState_Running)
            cRunning++;
        else if (g_aServices[i].enmState == kSupSvcServiceState_NotCreated)
        {
            supSvcLogError("service %s in state %d (NotCreated), expected pause or running",
                           g_aServices[i].pszName,  g_aServices[i].enmState, kSupSvcServiceState_NotCreated);
            return VERR_WRONG_ORDER;
        }
    if (!cRunning)
        return VINF_SUCCESS; /* all stopped, nothing to do. */
    Assert(cRunning == RT_ELEMENTS(g_aServices)); /* all or nothing */

    /*
     * Try stop them in reverse of start order.
     */
    int rc = VINF_SUCCESS;
    i = RT_ELEMENTS(g_aServices);
    while (i-- > 0)
    {
        rc = g_aServices[i].pfnTryStop(g_aServices[i].pvInstance);
        if (RT_FAILURE(rc))
        {
            Log(("supSvcTryStopServices: %s -> %Rrc\n", g_aServices[i].pszName, rc));
            break;
        }
        g_aServices[i].enmState = kSupSvcServiceState_Paused;
    }
    if (RT_FAILURE(rc))
    {
        /* Failed, restart the ones we succeeded in stopping. */
        while (++i < RT_ELEMENTS(g_aServices))
        {
            g_aServices[i].pfnStart(g_aServices[i].pvInstance);
            g_aServices[i].enmState = kSupSvcServiceState_Running;
        }
    }
    LogFlow(("supSvcTryStopServices: returns %Rrc\n", rc));
    return rc;
}
Beispiel #5
0
/**
 * Deals with RTGetOpt failure, bitching in the system log.
 *
 * @returns 1
 * @param   pszAction       The action name.
 * @param   rc              The RTGetOpt return value.
 * @param   argc            The argument count.
 * @param   argv            The argument vector.
 * @param   iArg            The argument index.
 * @param   pValue          The value returned by RTGetOpt.
 */
int supSvcLogGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTOPTIONUNION pValue)
{
    supSvcLogError("%s - RTGetOpt failure, %Rrc (%d): %s",
                   pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>");
    return 1;
}
Beispiel #6
0
/**
 * VBoxSUPSvc main(), Windows edition.
 *
 *
 * @returns 0 on success.
 *
 * @param   argc    Number of arguments in argv.
 * @param   argv    Argument vector.
 */
int main(int argc, char **argv)
{
    /*
     * Initialize the IPRT first of all.
     */
#ifdef DEBUG_bird
    RTEnvSet("VBOX_LOG", "sup=~0");
    RTEnvSet("VBOX_LOG_DEST", "file=E:\\temp\\VBoxSupSvc.log");
    RTEnvSet("VBOX_LOG_FLAGS", "unbuffered thread msprog");
#endif
    int rc = RTR3InitExe(argc, &argv, 0);
    if (RT_FAILURE(rc))
    {
        supSvcLogError("RTR3InitExe failed with rc=%Rrc", rc);
        return 1;
    }

    /*
     * Parse the initial arguments to determine the desired action.
     */
    enum
    {
        kSupSvcAction_RunIt,

        kSupSvcAction_Create,
        kSupSvcAction_Delete,

        kSupSvcAction_Enable,
        kSupSvcAction_Disable,
        kSupSvcAction_QueryConfig,
        kSupSvcAction_QueryDescription,

        kSupSvcAction_Start,
        kSupSvcAction_Pause,
        kSupSvcAction_Continue,
        kSupSvcAction_Stop,
        kSupSvcAction_Interrogate,

        kSupSvcAction_End
    } enmAction = kSupSvcAction_RunIt;
    int iArg = 1;
    if (argc > 1)
    {
        if (    !stricmp(argv[iArg], "/RegServer")
            ||  !stricmp(argv[iArg], "install")
            ||  !stricmp(argv[iArg], "/i"))
            enmAction = kSupSvcAction_Create;
        else if (   !stricmp(argv[iArg], "/UnregServer")
                 || !stricmp(argv[iArg], "/u")
                 || !stricmp(argv[iArg], "uninstall")
                 || !stricmp(argv[iArg], "delete"))
            enmAction = kSupSvcAction_Delete;

        else if (!stricmp(argv[iArg], "enable"))
            enmAction = kSupSvcAction_Enable;
        else if (!stricmp(argv[iArg], "disable"))
            enmAction = kSupSvcAction_Disable;
        else if (!stricmp(argv[iArg], "qconfig"))
            enmAction = kSupSvcAction_QueryConfig;
        else if (!stricmp(argv[iArg], "qdescription"))
            enmAction = kSupSvcAction_QueryDescription;

        else if (   !stricmp(argv[iArg], "start")
                 || !stricmp(argv[iArg], "/t"))
            enmAction = kSupSvcAction_Start;
        else if (!stricmp(argv[iArg], "pause"))
            enmAction = kSupSvcAction_Start;
        else if (!stricmp(argv[iArg], "continue"))
            enmAction = kSupSvcAction_Continue;
        else if (!stricmp(argv[iArg], "stop"))
            enmAction = kSupSvcAction_Stop;
        else if (!stricmp(argv[iArg], "interrogate"))
            enmAction = kSupSvcAction_Interrogate;
        else if (   !stricmp(argv[iArg], "help")
                 || !stricmp(argv[iArg], "?")
                 || !stricmp(argv[iArg], "/?")
                 || !stricmp(argv[iArg], "-?")
                 || !stricmp(argv[iArg], "/h")
                 || !stricmp(argv[iArg], "-h")
                 || !stricmp(argv[iArg], "/help")
                 || !stricmp(argv[iArg], "-help")
                 || !stricmp(argv[iArg], "--help"))
            return supSvcWinShowHelp();
        else if (   !stricmp(argv[iArg], "version")
                 || !stricmp(argv[iArg], "/v")
                 || !stricmp(argv[iArg], "-v")
                 || !stricmp(argv[iArg], "/version")
                 || !stricmp(argv[iArg], "-version")
                 || !stricmp(argv[iArg], "--version"))
            return supSvcWinShowVersion(argc - iArg - 1, argv + iArg + 1);
        else
            iArg--;
        iArg++;
    }

    /*
     * Dispatch it.
     */
    switch (enmAction)
    {
        case kSupSvcAction_RunIt:
            return supSvcWinRunIt(argc - iArg, argv + iArg);

        case kSupSvcAction_Create:
            return supSvcWinCreate(argc - iArg, argv + iArg);
        case kSupSvcAction_Delete:
            return supSvcWinDelete(argc - iArg, argv + iArg);

        case kSupSvcAction_Enable:
            return supSvcWinEnable(argc - iArg, argv + iArg);
        case kSupSvcAction_Disable:
            return supSvcWinDisable(argc - iArg, argv + iArg);
        case kSupSvcAction_QueryConfig:
            return supSvcWinQueryConfig(argc - iArg, argv + iArg);
        case kSupSvcAction_QueryDescription:
            return supSvcWinQueryDescription(argc - iArg, argv + iArg);

        case kSupSvcAction_Start:
            return supSvcWinStart(argc - iArg, argv + iArg);
        case kSupSvcAction_Pause:
            return supSvcWinPause(argc - iArg, argv + iArg);
        case kSupSvcAction_Continue:
            return supSvcWinContinue(argc - iArg, argv + iArg);
        case kSupSvcAction_Stop:
            return supSvcWinStop(argc - iArg, argv + iArg);
        case kSupSvcAction_Interrogate:
            return supSvcWinInterrogate(argc - iArg, argv + iArg);

        default:
            AssertMsgFailed(("enmAction=%d\n", enmAction));
            return 1;
    }
}
Beispiel #7
0
/**
 * Windows Service Main.
 *
 * This is invoked when the service is started and should not return until
 * the service has been stopped.
 *
 * @param   cArgs           Argument count.
 * @param   papszArgs       Argument vector.
 */
static VOID WINAPI supSvcWinServiceMain(DWORD cArgs, LPSTR *papszArgs)
{
    LogFlowFuncEnter();

    /*
     * Register the control handler function for the service and report to SCM.
     */
    Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
    g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerEx(SUPSVC_SERVICE_NAME, supSvcWinServiceCtrlHandlerEx, NULL);
    if (g_hSupSvcWinCtrlHandler)
    {
        DWORD err = ERROR_GEN_FAILURE;
        if (supSvcWinSetServiceStatus(SERVICE_START_PENDING, 3000, NO_ERROR))
        {
            /*
             * Parse arguments.
             */
            static const RTOPTIONDEF s_aOptions[] =
            {
                { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
            };
            int iArg = 1; /* the first arg is the service name */
            int ch;
            int rc = 0;
            RTGETOPTUNION Value;
            while (   !rc
                   && (ch = RTGetOpt(cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), &iArg, &Value)))
                switch (ch)
                {
                    default:    rc = supSvcLogGetOptError("main", ch, cArgs, papszArgs, iArg, &Value); break;
                }
            if (iArg != cArgs)
                rc = supSvcLogTooManyArgsError("main", cArgs, papszArgs, iArg);
            if (!rc)
            {
                /*
                 * Create the event semaphore we'll be waiting on and
                 * then instantiate the actual services.
                 */
                int rc = RTSemEventMultiCreate(&g_hSupSvcWinEvent);
                if (RT_SUCCESS(rc))
                {
                    rc = supSvcCreateAndStartServices();
                    if (RT_SUCCESS(rc))
                    {
                        /*
                         * Update the status and enter the work loop.
                         *
                         * The work loop is just a dummy wait here as the services run
                         * in independent threads.
                         */
                        if (supSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
                        {
                            LogFlow(("supSvcWinServiceMain: calling RTSemEventMultiWait\n"));
                            rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
                            if (RT_SUCCESS(rc))
                            {
                                LogFlow(("supSvcWinServiceMain: woke up\n"));
                                err = NO_ERROR;
                            }
                            else
                                supSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
                        }
                        else
                        {
                            err = GetLastError();
                            supSvcLogError("SetServiceStatus failed, err=%d", err);
                        }

                        /*
                         * Destroy the service instances, stopping them if
                         * they're still running (weird failure cause).
                         */
                        supSvcStopAndDestroyServices();
                    }

                    RTSemEventMultiDestroy(g_hSupSvcWinEvent);
                    g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
                }
                else
                    supSvcLogError("RTSemEventMultiCreate failed, rc=%Rrc", rc);
            }
            /* else: bad args */
        }
        else
        {
            err = GetLastError();
            supSvcLogError("SetServiceStatus failed, err=%d", err);
        }
        supSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
    }
    else
        supSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
    LogFlowFuncLeave();
}
Beispiel #8
0
/**
 * Service control handler (extended).
 *
 * @returns Windows status (see HandlerEx).
 * @retval  NO_ERROR if handled.
 * @retval  ERROR_CALL_NOT_IMPLEMENTED if not handled.
 *
 * @param   dwControl       The control code.
 * @param   dwEventType     Event type. (specific to the control?)
 * @param   pvEventData     Event data, specific to the event.
 * @param   pvContext       The context pointer registered with the handler.
 *                          Currently not used.
 */
static DWORD WINAPI supSvcWinServiceCtrlHandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID pvEventData, LPVOID pvContext)
{
    LogFlow(("supSvcWinServiceCtrlHandlerEx: dwControl=%#x dwEventType=%#x pvEventData=%p\n",
             dwControl, dwEventType, pvEventData));

    switch (dwControl)
    {
        /*
         * Interrogate the service about it's current status.
         * MSDN says that this should just return NO_ERROR and does
         * not need to set the status again.
         */
        case SERVICE_CONTROL_INTERROGATE:
            return NO_ERROR;

        /*
         * Request to stop the service.
         */
        case SERVICE_CONTROL_STOP:
        {
            /*
             * Check if the real services can be stopped and then tell them to stop.
             */
            supSvcWinSetServiceStatus(SERVICE_STOP_PENDING, 3000, NO_ERROR);
            int rc = supSvcTryStopServices();
            if (RT_SUCCESS(rc))
            {
                /*
                 * Notify the main thread that we're done, it will wait for the
                 * real services to stop, destroy them, and finally set the windows
                 * service status to SERVICE_STOPPED and return.
                 */
                rc = RTSemEventMultiSignal(g_hSupSvcWinEvent);
                if (RT_FAILURE(rc))
                    supSvcLogError("SERVICE_CONTROL_STOP: RTSemEventMultiSignal failed, %Rrc\n", rc);
            }
            return NO_ERROR;
        }

        case SERVICE_CONTROL_PAUSE:
        case SERVICE_CONTROL_CONTINUE:
        case SERVICE_CONTROL_SHUTDOWN:
        case SERVICE_CONTROL_PARAMCHANGE:
        case SERVICE_CONTROL_NETBINDADD:
        case SERVICE_CONTROL_NETBINDREMOVE:
        case SERVICE_CONTROL_NETBINDENABLE:
        case SERVICE_CONTROL_NETBINDDISABLE:
        case SERVICE_CONTROL_DEVICEEVENT:
        case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
        case SERVICE_CONTROL_POWEREVENT:
        case SERVICE_CONTROL_SESSIONCHANGE:
#ifdef SERVICE_CONTROL_PRESHUTDOWN /* vista */
        case SERVICE_CONTROL_PRESHUTDOWN:
#endif
        default:
            return ERROR_CALL_NOT_IMPLEMENTED;
    }

    NOREF(dwEventType);
    NOREF(pvEventData);
    NOREF(pvContext);
    return NO_ERROR;
}