/* * Copyright (C) 2004, 2006, 2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $Id: ntservice.c,v 1.16 2011-01-13 08:50:29 tbox Exp $ */ #include #include #include #include #include #include #include #include /* 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); void GetArgs(int *, char ***, char ***); int main(int, char *[], char *[]); /* From ns_main.c */ /* * Here we change the entry point for the executable to bindmain() from main() * This allows us to invoke as a service or from the command line easily. */ #pragma comment(linker, "/entry:bindmain") /* * This is the entry point for the executable * We can now call main() explicitly or via StartServiceCtrlDispatcher() * as we need to. */ int bindmain() { int rc, i = 1; int argc; char **envp, **argv; /* * We changed the entry point function, so we must initialize argv, * etc. ourselves. Ick. */ GetArgs(&argc, &argv, &envp); /* Command line users should put -f in the options. */ /* XXXMPA should use isc_commandline_parse() here. */ while (argv[i]) { if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "-g") || !strcmp(argv[i], "-v") || !strcmp(argv[i], "-V")) { foreground = TRUE; break; } i++; } if (foreground) { /* run in console window */ exit(main(argc, argv, envp)); } else { /* Start up as service */ char *SERVICE_NAME = BIND_SERVICE_NAME; SERVICE_TABLE_ENTRY dispatchTable[] = { { TEXT(SERVICE_NAME), (LPSERVICE_MAIN_FUNCTION)main }, { NULL, NULL } }; rc = StartServiceCtrlDispatcher(dispatchTable); if (!rc) { fprintf(stderr, "Use -f to run from the command line.\n"); exit(GetLastError()); } } exit(0); } /* * Initialize the Service by registering it. */ void ntservice_init() { 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 { strcpy(ConsoleTitle, "BIND Version "); strcat(ConsoleTitle, VERSION); SetConsoleTitle(ConsoleTitle); } } void ntservice_shutdown() { UpdateSCM(SERVICE_STOPPED); } /* * Routine to check if this is a service or a foreground program */ BOOL ntservice_isservice() { 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); } } } /* * C-runtime stuff used to initialize the app and * get argv, argc, envp. */ typedef struct { int newmode; } _startupinfo; _CRTIMP void __cdecl __set_app_type(int); _CRTIMP void __cdecl __getmainargs(int *, char ***, char ***, int, _startupinfo *); void __cdecl _setargv(void); #ifdef _M_IX86 /* Pentium FDIV adjustment */ extern int _adjust_fdiv; extern int * _imp___adjust_fdiv; /* Floating point precision */ extern void _setdefaultprecision(); #endif extern int _newmode; /* malloc new() handler mode */ extern int _dowildcard; /* passed to __getmainargs() */ typedef void (__cdecl *_PVFV)(void); extern void __cdecl _initterm(_PVFV *, _PVFV *); extern _PVFV *__onexitbegin; extern _PVFV *__onexitend; extern _CRTIMP char **__initenv; /* * Do the work that mainCRTStartup() would normally do */ void GetArgs(int *argc, char ***argv, char ***envp) { _startupinfo startinfo; /* * Set the app type to Console (check CRT/SRC/INTERNAL.H: * \#define _CONSOLE_APP 1) */ __set_app_type(1); /* Mark this module as an EXE file */ __onexitbegin = __onexitend = (_PVFV *)(-1); startinfo.newmode = _newmode; __getmainargs(argc, argv, envp, _dowildcard, &startinfo); __initenv = *envp; #ifdef _M_IX86 _adjust_fdiv = * _imp___adjust_fdiv; _setdefaultprecision(); #endif }