📄 service.c
字号:
/*
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(<ime);
strcpy(date, ctime(<ime));
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 + -