mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-25 02:03:03 +01:00
352 lines
7.9 KiB
C++
352 lines
7.9 KiB
C++
/*
|
|
* PROGRAM: Guardian CNTL function.
|
|
* MODULE: cntl_guard.c
|
|
* DESCRIPTION: Windows NT service control panel interface
|
|
*
|
|
* The contents of this file are subject to the Interbase Public
|
|
* License Version 1.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy
|
|
* of the License at http://www.Inprise.com/IPL.html
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code was created by Inprise Corporation
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
* Copyright (C) Inprise Corporation.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include "../jrd/ib_stdio.h"
|
|
#include "../jrd/common.h"
|
|
#include "../iscguard/cntlg_proto.h"
|
|
#include "../remote/remote.h"
|
|
#include "../utilities/install/install_nt.h"
|
|
#include "../jrd/thd.h"
|
|
#include "../jrd/isc_proto.h"
|
|
#include "../jrd/gds_proto.h"
|
|
#include "../jrd/sch_proto.h"
|
|
#include "../jrd/thd_proto.h"
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#ifdef WIN_NT
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
typedef struct thread {
|
|
thread* thread_next;
|
|
HANDLE thread_handle;
|
|
} *THREAD;
|
|
|
|
static void control_thread(DWORD);
|
|
static void parse_switch(TEXT *, int *);
|
|
static USHORT report_status(DWORD, DWORD, DWORD, DWORD);
|
|
|
|
static DWORD current_state;
|
|
static void (*main_handler) ();
|
|
static SERVICE_STATUS_HANDLE service_handle;
|
|
static TEXT *service_name;
|
|
static HANDLE stop_event_handle;
|
|
#ifdef NOT_USED_OR_REPLACED
|
|
static MUTX_T thread_mutex[1];
|
|
static THREAD threads;
|
|
#endif
|
|
|
|
|
|
void CNTL_init( void (*handler) (), TEXT * name)
|
|
{
|
|
/**************************************
|
|
*
|
|
* C N T L _ i n i t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
**************************************/
|
|
|
|
main_handler = handler;
|
|
service_name = name;
|
|
}
|
|
|
|
|
|
void CNTL_main_thread( SLONG argc, SCHAR * argv[])
|
|
{
|
|
/**************************************
|
|
*
|
|
* C N T L _ m a i n _ t h r e a d
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
**************************************/
|
|
int flag;
|
|
TEXT *p;
|
|
DWORD last_error = 0;
|
|
DWORD temp;
|
|
int status;
|
|
|
|
service_handle = RegisterServiceCtrlHandler(service_name,
|
|
(LPHANDLER_FUNCTION)
|
|
control_thread);
|
|
if (!service_handle)
|
|
return;
|
|
|
|
// THD_mutex_init (thread_mutex);
|
|
|
|
#if (defined SUPERCLIENT || defined SUPERSERVER)
|
|
flag = SRVR_multi_client;
|
|
#else
|
|
flag = 0;
|
|
#endif
|
|
|
|
/* Parse the command line looking for any additional arguments. */
|
|
|
|
argv++;
|
|
|
|
while (--argc) {
|
|
p = *argv++;
|
|
if (*p++ = '-')
|
|
parse_switch(p, &flag);
|
|
}
|
|
|
|
/* start everything, and wait here for ever, or at
|
|
* least until we get the stop event indicating that
|
|
* the service is stoping. */
|
|
|
|
status = 1;
|
|
if (report_status(SERVICE_START_PENDING, NO_ERROR, 1, 3000) &&
|
|
(stop_event_handle = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL &&
|
|
report_status(SERVICE_START_PENDING, NO_ERROR, 2, 3000) &&
|
|
!gds__thread_start(reinterpret_cast < FPTR_INT_VOID_PTR >
|
|
(main_handler), (void *) flag, 0, 0, 0)
|
|
&& report_status(SERVICE_RUNNING, NO_ERROR, 0, 0)) {
|
|
status = 0;
|
|
temp = WaitForSingleObject(stop_event_handle, INFINITE);
|
|
}
|
|
|
|
if (temp == WAIT_FAILED || status)
|
|
last_error = GetLastError();
|
|
|
|
if (stop_event_handle)
|
|
CloseHandle(stop_event_handle);
|
|
|
|
/* ONce we are stopped, we will tell the server to
|
|
* do the same. We could not do this in the control_thread
|
|
* since the Services Control Manager is single threaded,
|
|
* and thus can only process one request at the time. */
|
|
{
|
|
SERVICE_STATUS status_info;
|
|
SC_HANDLE hScManager = 0, hService = 0;
|
|
hScManager =
|
|
OpenSCManager(NULL, NULL, GENERIC_READ);
|
|
hService = OpenService(hScManager, REMOTE_SERVICE,
|
|
GENERIC_READ | GENERIC_EXECUTE);
|
|
ControlService(hService, SERVICE_CONTROL_STOP, &status_info);
|
|
CloseServiceHandle(hScManager);
|
|
CloseServiceHandle(hService);
|
|
}
|
|
|
|
report_status(SERVICE_STOPPED, last_error, 0, 0);
|
|
|
|
// THD_mutex_destroy (thread_mutex);
|
|
}
|
|
|
|
void CNTL_shutdown_service( TEXT * message)
|
|
{
|
|
/**************************************
|
|
*
|
|
* C N T L _ s h u t d o w n _ s e r v i c e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
**************************************/
|
|
char *strings[2];
|
|
char buffer[256];
|
|
HANDLE event_source;
|
|
|
|
sprintf(buffer, "%s error: %lu", service_name, GetLastError());
|
|
|
|
event_source = RegisterEventSource(NULL, service_name);
|
|
if (event_source) {
|
|
strings[0] = buffer;
|
|
strings[1] = message;
|
|
ReportEvent(event_source,
|
|
EVENTLOG_ERROR_TYPE,
|
|
0,
|
|
0,
|
|
NULL, 2, 0, const_cast < const char **>(strings), NULL);
|
|
DeregisterEventSource(event_source);
|
|
}
|
|
|
|
if (stop_event_handle)
|
|
SetEvent(stop_event_handle);
|
|
}
|
|
|
|
|
|
void CNTL_stop_service( TEXT * service)
|
|
{
|
|
/**************************************
|
|
*
|
|
* C N T L _ s t o p _ s e r v i c e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* This function is called to stop the service.
|
|
*
|
|
*
|
|
**************************************/
|
|
|
|
SERVICE_STATUS status_info;
|
|
SC_HANDLE servicemgr_handle;
|
|
SC_HANDLE service_handle;
|
|
|
|
servicemgr_handle = OpenSCManager(NULL, NULL, GENERIC_READ);
|
|
if (servicemgr_handle == NULL) {
|
|
// return error
|
|
int error = GetLastError();
|
|
gds__log("SC manager error %d", error);
|
|
return;
|
|
}
|
|
|
|
service_handle =
|
|
OpenService(servicemgr_handle, service_name,
|
|
GENERIC_READ | GENERIC_EXECUTE);
|
|
|
|
if (service_handle == NULL) {
|
|
// return error
|
|
int error = GetLastError();
|
|
gds__log("open services error %d", error);
|
|
return;
|
|
}
|
|
else {
|
|
if (!ControlService
|
|
(service_handle, SERVICE_CONTROL_STOP, &status_info)) {
|
|
// return error
|
|
int error = GetLastError();
|
|
gds__log("Control services error %d", error);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void control_thread( DWORD action)
|
|
{
|
|
/**************************************
|
|
*
|
|
* c o n t r o l _ t h r e a d
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Process a service control request.
|
|
*
|
|
**************************************/
|
|
DWORD state;
|
|
state = SERVICE_RUNNING;
|
|
|
|
switch (action) {
|
|
case SERVICE_CONTROL_STOP:
|
|
report_status(SERVICE_STOP_PENDING, NO_ERROR, 1, 3000);
|
|
SetEvent(stop_event_handle);
|
|
return;
|
|
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
report_status(state, NO_ERROR, 0, 0);
|
|
}
|
|
|
|
|
|
static void parse_switch( TEXT * switches, int *flag)
|
|
{
|
|
/**************************************
|
|
*
|
|
* p a r s e _ s w i t c h
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
**************************************/
|
|
TEXT c;
|
|
|
|
while (c = *switches++)
|
|
switch (UPPER(c)) {
|
|
case 'B':
|
|
*flag |= SRVR_high_priority;
|
|
break;
|
|
|
|
case 'I':
|
|
*flag |= SRVR_inet;
|
|
break;
|
|
|
|
case 'R':
|
|
*flag &= ~SRVR_high_priority;
|
|
break;
|
|
|
|
case 'W':
|
|
*flag |= SRVR_wnet;
|
|
break;
|
|
}
|
|
|
|
#if (defined SUPERCLIENT || defined SUPERSERVER)
|
|
*flag |= SRVR_multi_client;
|
|
#else
|
|
*flag &= ~SRVR_multi_client;
|
|
#endif
|
|
}
|
|
|
|
|
|
static USHORT report_status(
|
|
DWORD state,
|
|
DWORD exit_code, DWORD checkpoint, DWORD hint)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r e p o r t _ s t a t u s
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Report our status to the control manager.
|
|
*
|
|
**************************************/
|
|
SERVICE_STATUS status;
|
|
USHORT ret;
|
|
|
|
status.dwServiceType =
|
|
(SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS);
|
|
status.dwServiceSpecificExitCode = 0;
|
|
|
|
if (state == SERVICE_START_PENDING)
|
|
status.dwControlsAccepted = 0;
|
|
else
|
|
status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
|
|
|
status.dwCurrentState = current_state = state;
|
|
status.dwWin32ExitCode = exit_code;
|
|
status.dwCheckPoint = checkpoint;
|
|
status.dwWaitHint = hint;
|
|
|
|
if (!(ret = SetServiceStatus(service_handle, &status)))
|
|
CNTL_shutdown_service("SetServiceStatus");
|
|
|
|
return ret;
|
|
}
|