/*
* Copyright (C) 1999-2002, 2004, 2006, 2007, 2009, 2011, 2013-2017 Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* $Id: ntservice.c,v 1.16 2011/01/13 08:50:29 tbox Exp $ */
#include <config.h>
#include <stdio.h>
#include <isc/app.h>
#include <isc/commandline.h>
#include <isc/log.h>
#include <isc/print.h>
#include <isc/string.h>
#include <named/globals.h>
#include <named/ntservice.h>
#include <named/main.h>
#include <named/server.h>
/* Handle to SCM for updating service status */
static SERVICE_STATUS_HANDLE hServiceStatus = 0;
static BOOL foreground = FALSE;
static char ConsoleTitle[128];
/*
* Forward declarations
*/
void ServiceControl(DWORD dwCtrlCode);
int bindmain(int, char *[]); /* From main.c */
/*
* Initialize the Service by registering it.
*/
void
ntservice_init(void) {
if (!foreground) {
/* Register handler with the SCM */
hServiceStatus = RegisterServiceCtrlHandler(BIND_SERVICE_NAME,
(LPHANDLER_FUNCTION)ServiceControl);
if (!hServiceStatus) {
ns_main_earlyfatal(
"could not register service control handler");
UpdateSCM(SERVICE_STOPPED);
exit(1);
}
UpdateSCM(SERVICE_RUNNING);
} else {
strlcpy(ConsoleTitle, "BIND Version ", sizeof(ConsoleTitle));
strlcat(ConsoleTitle, VERSION, sizeof(ConsoleTitle));
SetConsoleTitle(ConsoleTitle);
}
}
void
ntservice_shutdown(void) {
UpdateSCM(SERVICE_STOPPED);
}
/*
* Routine to check if this is a service or a foreground program
*/
BOOL
ntservice_isservice(void) {
return(!foreground);
}
/*
* ServiceControl(): Handles requests from the SCM and passes them on
* to named.
*/
void
ServiceControl(DWORD dwCtrlCode) {
/* Handle the requested control code */
switch(dwCtrlCode) {
case SERVICE_CONTROL_INTERROGATE:
UpdateSCM(0);
break;
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
ns_server_flushonshutdown(ns_g_server, ISC_TRUE);
isc_app_shutdown();
UpdateSCM(SERVICE_STOPPED);
break;
default:
break;
}
}
/*
* Tell the Service Control Manager the state of the service.
*/
void UpdateSCM(DWORD state) {
SERVICE_STATUS ss;
static DWORD dwState = SERVICE_STOPPED;
if (hServiceStatus) {
if (state)
dwState = state;
memset(&ss, 0, sizeof(SERVICE_STATUS));
ss.dwServiceType |= SERVICE_WIN32_OWN_PROCESS;
ss.dwCurrentState = dwState;
ss.dwControlsAccepted = SERVICE_ACCEPT_STOP |
SERVICE_ACCEPT_SHUTDOWN;
ss.dwCheckPoint = 0;
ss.dwServiceSpecificExitCode = 0;
ss.dwWin32ExitCode = NO_ERROR;
ss.dwWaitHint = dwState == SERVICE_STOP_PENDING ? 10000 : 1000;
if (!SetServiceStatus(hServiceStatus, &ss)) {
ss.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus(hServiceStatus, &ss);
}
}
}
/* unhook main */
#undef main
/*
* This is the entry point for the executable
* We can now call bindmain() explicitly or via StartServiceCtrlDispatcher()
* as we need to.
*/
int main(int argc, char *argv[])
{
int rc, ch;
/* Command line users should put -f in the options. */
isc_commandline_errprint = ISC_FALSE;
while ((ch = isc_commandline_parse(argc, argv, NS_MAIN_ARGS)) != -1) {
switch (ch) {
case 'f':
case 'g':
case 'v':
case 'V':
foreground = TRUE;
break;
default:
break;
}
}
isc_commandline_reset = ISC_TRUE;
if (foreground) {
/* run in console window */
exit(bindmain(argc, argv));
} else {
/* Start up as service */
char *SERVICE_NAME = BIND_SERVICE_NAME;
SERVICE_TABLE_ENTRY dispatchTable[] = {
{ TEXT(SERVICE_NAME),
(LPSERVICE_MAIN_FUNCTION)bindmain },
{ NULL, NULL }
};
rc = StartServiceCtrlDispatcher(dispatchTable);
if (!rc) {
fprintf(stderr,
"Use -f to run from the command line.\n");
/* will be 1063 when launched as a console app */
exit(GetLastError());
}
}
exit(0);
}