⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 service.c

📁 This is Win32 Service wrapper for SVN. Source is included, and its in the public domain.
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
	SVNService modifications written by Magnus Norddahl.

	Disclaimer: Yes this code is so ugly (that I added, not the original Craig Link stuff)
	that it may burn down your PC and kill your cat! But what can I say.. its C, and all
	I got is the platform SDK here. Bit violations of TCHAR stuff (dont use the _TEXT things
	always, some hardcoded widechar) and some strings should be defined in header file.

*/
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 1993-1997  Microsoft Corporation.  All Rights Reserved.
//
//  MODULE:   service.c
//
//  PURPOSE:  Implements functions required by all services
//            windows.
//
//  FUNCTIONS:
//    main(int argc, char **argv);
//    service_ctrl(DWORD dwCtrlCode);
//    service_main(DWORD dwArgc, LPTSTR *lpszArgv);
//    CmdInstallService(int argc, char **argv);
//    CmdRemoveService();
//    CmdDebugService(int argc, char **argv);
//    ControlHandler ( DWORD dwCtrlType );
//    GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
//
//  COMMENTS:
//
//  AUTHOR: Craig Link - Microsoft Developer Support
//

// shut up! 
#pragma warning(disable:4115)
#pragma warning(disable:4127)
#pragma warning(disable:4706)

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <tchar.h>
#include <time.h>
#include <crtdbg.h>

#include "service.h"
#include "log_messages.h"

// internal variables
SERVICE_STATUS          ssStatus;       // current status of the service
SERVICE_STATUS_HANDLE   sshStatusHandle;
DWORD                   dwErr = 0;
BOOL                    bDebug = FALSE;
TCHAR                   szErr[256];

// internal function prototypes
VOID WINAPI service_ctrl(DWORD dwCtrlCode);
VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
VOID CmdInstallService(int argc, char **argv);
VOID CmdSetupService(int argc, char **argv);
VOID CmdRemoveService();
VOID CmdDebugService(int argc, char **argv);
BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );

//
//  FUNCTION: main
//
//  PURPOSE: entrypoint for service
//
//  PARAMETERS:
//    argc - number of command line arguments
//    argv - array of command line arguments
//
//  RETURN VALUE:
//    none
//
//  COMMENTS:
//    main() either performs the command line task, or
//    call StartServiceCtrlDispatcher to register the
//    main service thread.  When the this call returns,
//    the service has stopped, so exit.
//
void _CRTAPI1 main(int argc, char **argv)
{
    SERVICE_TABLE_ENTRY dispatchTable[] =
    {
        { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main },
        { NULL, NULL }
    };

    if ( (argc > 1) &&
         ((*argv[1] == '-') || (*argv[1] == '/')) )
    {
        if ( _stricmp( "install", argv[1]+1 ) == 0 )
        {
            CmdInstallService(argc-2, argv+2);
        }
        else if ( _stricmp( "remove", argv[1]+1 ) == 0 )
        {
            CmdRemoveService();
        }
        else if ( _stricmp( "setup", argv[1]+1 ) == 0 )
        {
            CmdSetupService(argc-2, argv+2);
        }
        else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
        {
            bDebug = TRUE;
            CmdDebugService(argc, argv);
        }
        else
        {
            goto dispatch;
        }
		_CrtDumpMemoryLeaks();
        exit(0);
    }

    // if it doesn't match any of the above parameters
    // the service control manager may be starting the service
    // so we must call StartServiceCtrlDispatcher
    dispatch:
        // this is just to be friendly
        printf( "%s -install <svnserve params> to install the service\n", SZAPPNAME );
        printf( "%s -remove                    to remove the service\n", SZAPPNAME );
        printf( "%s -setup <svnserve params>   to change command line parameters for svnserve\n", SZAPPNAME );
        printf( "%s -debug                     to run as a console app for debugging\n", SZAPPNAME );
        printf( "\nStartServiceCtrlDispatcher being called.\n" );
        printf( "This may take several seconds.  Please wait.\n" );

        if (!StartServiceCtrlDispatcher(dispatchTable))
            AddToMessageLog(Event_Service, TEXT("StartServiceCtrlDispatcher failed."), EVENTLOG_ERROR_TYPE);
}



//
//  FUNCTION: service_main
//
//  PURPOSE: To perform actual initialization of the service
//
//  PARAMETERS:
//    dwArgc   - number of command line arguments
//    lpszArgv - array of command line arguments
//
//  RETURN VALUE:
//    none
//
//  COMMENTS:
//    This routine performs the service initialization and then calls
//    the user defined ServiceStart() routine to perform majority
//    of the work.
//
void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
{

    // register our service control handler:
    //
    sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);

    if (!sshStatusHandle)
        goto cleanup;

    // SERVICE_STATUS members that don't change in example
    //
    ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    ssStatus.dwServiceSpecificExitCode = 0;


    // report the status to the service control manager.
    //
    if (!ReportStatusToSCMgr(
        SERVICE_START_PENDING, // service state
        NO_ERROR,              // exit code
        3000))                 // wait hint
        goto cleanup;


    ServiceStart( dwArgc, lpszArgv );

cleanup:

    // try to report the stopped status to the service control manager.
    //
    if (sshStatusHandle)
        (VOID)ReportStatusToSCMgr(
                            SERVICE_STOPPED,
                            dwErr,
                            0);

    return;
}



//
//  FUNCTION: service_ctrl
//
//  PURPOSE: This function is called by the SCM whenever
//           ControlService() is called on this service.
//
//  PARAMETERS:
//    dwCtrlCode - type of control requested
//
//  RETURN VALUE:
//    none
//
//  COMMENTS:
//
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
{
    // Handle the requested control code.
    //
    switch(dwCtrlCode)
    {
        // Stop the service.
        //
        // SERVICE_STOP_PENDING should be reported before
        // setting the Stop Event - hServerStopEvent - in
        // ServiceStop().  This avoids a race condition
        // which may result in a 1053 - The Service did not respond...
        // error.
        case SERVICE_CONTROL_STOP:
            ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
            ServiceStop();
            return;

        // Update the service status.
        //
        case SERVICE_CONTROL_INTERROGATE:
            break;

        // invalid control code
        //
        default:
            break;

    }

    ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
}



//
//  FUNCTION: ReportStatusToSCMgr()
//
//  PURPOSE: Sets the current status of the service and
//           reports it to the Service Control Manager
//
//  PARAMETERS:
//    dwCurrentState - the state of the service
//    dwWin32ExitCode - error code to report
//    dwWaitHint - worst case estimate to next checkpoint
//
//  RETURN VALUE:
//    TRUE  - success
//    FALSE - failure
//
//  COMMENTS:
//
BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
                         DWORD dwWin32ExitCode,
                         DWORD dwWaitHint)
{
    static DWORD dwCheckPoint = 1;
    BOOL fResult = TRUE;


    if ( !bDebug ) // when debugging we don't report to the SCM
    {
        if (dwCurrentState == SERVICE_START_PENDING)
            ssStatus.dwControlsAccepted = 0;
        else
            ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

        ssStatus.dwCurrentState = dwCurrentState;
        ssStatus.dwWin32ExitCode = dwWin32ExitCode;
        ssStatus.dwWaitHint = dwWaitHint;

        if ( ( dwCurrentState == SERVICE_RUNNING ) ||
             ( dwCurrentState == SERVICE_STOPPED ) )
            ssStatus.dwCheckPoint = 0;
        else
            ssStatus.dwCheckPoint = dwCheckPoint++;


        // Report the status of the service to the service control manager.
        //
        if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) {
            AddToMessageLog(Event_Service, TEXT("SetServiceStatus"), EVENTLOG_ERROR_TYPE);
        }
    }
    return fResult;
}


// Debug level defaults at zero:
static int debug_level = 0;
static FILE *debug_file = NULL;


//
//  FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
//
//  PURPOSE: Allows any thread to log an error message
//
//  PARAMETERS:
//    eventID - Event ID.
//    lpszMsg - text for message
//
//  RETURN VALUE:
//    none
//
//  COMMENTS:
//
static char buffer[1024];
VOID AddToMessageLog(int eventID, LPCTSTR lpszMsg, int error_type)
{
    HANDLE  hEventSource;
    LPTSTR  lpszStrings[2];
	time_t ltime;
	char date[128];
	int i, len;

	if (debug_file != NULL)
	{
		time(&ltime);
		strcpy(date, ctime(&ltime));
		date[strlen(date)-1] = 0;

		sprintf(buffer, "%s: %s\n", date, lpszMsg);

		len = strlen(buffer);
		for (i=0; i<len-1; i++)
		{
			if (buffer[i] == '\n') buffer[i] = '\t';
			if (buffer[i] == '\r') buffer[i] = '\n';
		}

		fwrite(buffer, strlen(buffer), 1, debug_file);
		fflush(debug_file);
	}

    if ( !bDebug && eventID != Event_Debug )
    {
		if (debug_file != NULL) return;
        dwErr = GetLastError();

        // Use event logging to log the error.
        //
        hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));

        lpszStrings[0] = (LPTSTR) lpszMsg;

        if (hEventSource != NULL) {
            ReportEvent(hEventSource, // handle of event source
                (WORD) error_type/*EVENTLOG_ERROR_TYPE*/,  // event type
                0,                    // event category
                eventID,              // event ID
                NULL,                 // current user's SID
                1,                    // strings in lpszStrings
                0,                    // no bytes of raw data
                lpszStrings,          // array of error strings
                NULL);                // no raw data

            (VOID) DeregisterEventSource(hEventSource);
        }
    }
	else
	{
		printf("MessageLog (Event ID %d): %s\r\n", eventID, lpszMsg);
	}
}

//
//  FUNCTION: AddDebug(int debuglevel, LPTSTR lpszMsg)
//
//  PURPOSE: Write debug information if the error level allows it.
//
//  PARAMETERS:
//    debuglevel - level this debug information belong to.
//    lpszMsg - text for message
//
//  RETURN VALUE:
//    none
//
void _AddDebug(int level, LPTSTR lpszMsg)
{
	if (level > debug_level) return;

	AddToMessageLog(Event_Debug, lpszMsg, EVENTLOG_INFORMATION_TYPE);
}
//////////////////////////////////////////////////////////////////////////////

//
//  FUNCTION: SetDebugLevel(int debuglevel)
//
//  PURPOSE: Changes the debug level at which things are written to the event log.
//
//  PARAMETERS:
//    debuglevel - New debug level to use.
//
//  RETURN VALUE:
//    none
//
void SetDebugLevel(int new_level)
{
	debug_level = new_level;
}
//////////////////////////////////////////////////////////////////////////////

//
//  FUNCTION: LogToFile(const char *filename)
//
//  PURPOSE: Changes all logging to be sent to file.
//
//  PARAMETERS:
//    filename - Log filename.
//
//  RETURN VALUE:
//    none
//
void LogToFile(const char *filename)
{
	if (debug_file != NULL) fclose(debug_file);

	debug_file = fopen(filename, "a+t");
	if (debug_file == NULL) debug_file = fopen(filename, "wt");
}
//////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
//
//  The following code handles service installation and removal
//


//
//  FUNCTION: CmdInstallService()
//

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -