1/* $NetBSD: ntservice.c,v 1.2.6.1 2012/06/05 21:15:50 bouyer Exp $ */ 2 3/* 4 * Copyright (C) 2004, 2006, 2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC") 5 * Copyright (C) 1999-2002 Internet Software Consortium. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20/* Id: ntservice.c,v 1.16 2011/01/13 08:50:29 tbox Exp */ 21 22#include <config.h> 23#include <stdio.h> 24 25#include <isc/app.h> 26#include <isc/log.h> 27 28#include <named/globals.h> 29#include <named/ntservice.h> 30#include <named/main.h> 31#include <named/server.h> 32 33/* Handle to SCM for updating service status */ 34static SERVICE_STATUS_HANDLE hServiceStatus = 0; 35static BOOL foreground = FALSE; 36static char ConsoleTitle[128]; 37 38/* 39 * Forward declarations 40 */ 41void ServiceControl(DWORD dwCtrlCode); 42void GetArgs(int *, char ***, char ***); 43int main(int, char *[], char *[]); /* From ns_main.c */ 44 45/* 46 * Here we change the entry point for the executable to bindmain() from main() 47 * This allows us to invoke as a service or from the command line easily. 48 */ 49#pragma comment(linker, "/entry:bindmain") 50 51/* 52 * This is the entry point for the executable 53 * We can now call main() explicitly or via StartServiceCtrlDispatcher() 54 * as we need to. 55 */ 56int bindmain() 57{ 58 int rc, 59 i = 1; 60 61 int argc; 62 char **envp, **argv; 63 64 /* 65 * We changed the entry point function, so we must initialize argv, 66 * etc. ourselves. Ick. 67 */ 68 GetArgs(&argc, &argv, &envp); 69 70 /* Command line users should put -f in the options. */ 71 /* XXXMPA should use isc_commandline_parse() here. */ 72 while (argv[i]) { 73 if (!strcmp(argv[i], "-f") || 74 !strcmp(argv[i], "-g") || 75 !strcmp(argv[i], "-v") || 76 !strcmp(argv[i], "-V")) { 77 foreground = TRUE; 78 break; 79 } 80 i++; 81 } 82 83 if (foreground) { 84 /* run in console window */ 85 exit(main(argc, argv, envp)); 86 } else { 87 /* Start up as service */ 88 char *SERVICE_NAME = BIND_SERVICE_NAME; 89 90 SERVICE_TABLE_ENTRY dispatchTable[] = { 91 { TEXT(SERVICE_NAME), (LPSERVICE_MAIN_FUNCTION)main }, 92 { NULL, NULL } 93 }; 94 95 rc = StartServiceCtrlDispatcher(dispatchTable); 96 if (!rc) { 97 fprintf(stderr, "Use -f to run from the command line.\n"); 98 exit(GetLastError()); 99 } 100 } 101 exit(0); 102} 103 104/* 105 * Initialize the Service by registering it. 106 */ 107void 108ntservice_init() { 109 if (!foreground) { 110 /* Register handler with the SCM */ 111 hServiceStatus = RegisterServiceCtrlHandler(BIND_SERVICE_NAME, 112 (LPHANDLER_FUNCTION)ServiceControl); 113 if (!hServiceStatus) { 114 ns_main_earlyfatal( 115 "could not register service control handler"); 116 UpdateSCM(SERVICE_STOPPED); 117 exit(1); 118 } 119 UpdateSCM(SERVICE_RUNNING); 120 } else { 121 strcpy(ConsoleTitle, "BIND Version "); 122 strcat(ConsoleTitle, VERSION); 123 SetConsoleTitle(ConsoleTitle); 124 } 125} 126 127void 128ntservice_shutdown() { 129 UpdateSCM(SERVICE_STOPPED); 130} 131/* 132 * Routine to check if this is a service or a foreground program 133 */ 134BOOL 135ntservice_isservice() { 136 return(!foreground); 137} 138/* 139 * ServiceControl(): Handles requests from the SCM and passes them on 140 * to named. 141 */ 142void 143ServiceControl(DWORD dwCtrlCode) { 144 /* Handle the requested control code */ 145 switch(dwCtrlCode) { 146 case SERVICE_CONTROL_INTERROGATE: 147 UpdateSCM(0); 148 break; 149 150 case SERVICE_CONTROL_SHUTDOWN: 151 case SERVICE_CONTROL_STOP: 152 ns_server_flushonshutdown(ns_g_server, ISC_TRUE); 153 isc_app_shutdown(); 154 UpdateSCM(SERVICE_STOPPED); 155 break; 156 default: 157 break; 158 } 159} 160 161/* 162 * Tell the Service Control Manager the state of the service. 163 */ 164void UpdateSCM(DWORD state) { 165 SERVICE_STATUS ss; 166 static DWORD dwState = SERVICE_STOPPED; 167 168 if (hServiceStatus) { 169 if (state) 170 dwState = state; 171 172 memset(&ss, 0, sizeof(SERVICE_STATUS)); 173 ss.dwServiceType |= SERVICE_WIN32_OWN_PROCESS; 174 ss.dwCurrentState = dwState; 175 ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | 176 SERVICE_ACCEPT_SHUTDOWN; 177 ss.dwCheckPoint = 0; 178 ss.dwServiceSpecificExitCode = 0; 179 ss.dwWin32ExitCode = NO_ERROR; 180 ss.dwWaitHint = dwState == SERVICE_STOP_PENDING ? 10000 : 1000; 181 182 if (!SetServiceStatus(hServiceStatus, &ss)) { 183 ss.dwCurrentState = SERVICE_STOPPED; 184 SetServiceStatus(hServiceStatus, &ss); 185 } 186 } 187} 188 189/* 190 * C-runtime stuff used to initialize the app and 191 * get argv, argc, envp. 192 */ 193 194typedef struct 195{ 196 int newmode; 197} _startupinfo; 198 199_CRTIMP void __cdecl __set_app_type(int); 200_CRTIMP void __cdecl __getmainargs(int *, char ***, char ***, int, 201 _startupinfo *); 202void __cdecl _setargv(void); 203 204#ifdef _M_IX86 205/* Pentium FDIV adjustment */ 206extern int _adjust_fdiv; 207extern int * _imp___adjust_fdiv; 208/* Floating point precision */ 209extern void _setdefaultprecision(); 210#endif 211 212extern int _newmode; /* malloc new() handler mode */ 213extern int _dowildcard; /* passed to __getmainargs() */ 214 215typedef void (__cdecl *_PVFV)(void); 216extern void __cdecl _initterm(_PVFV *, _PVFV *); 217extern _PVFV *__onexitbegin; 218extern _PVFV *__onexitend; 219extern _CRTIMP char **__initenv; 220 221/* 222 * Do the work that mainCRTStartup() would normally do 223 */ 224void GetArgs(int *argc, char ***argv, char ***envp) 225{ 226 _startupinfo startinfo; 227 228 /* 229 * Set the app type to Console (check CRT/SRC/INTERNAL.H: 230 * \#define _CONSOLE_APP 1) 231 */ 232 __set_app_type(1); 233 234 /* Mark this module as an EXE file */ 235 __onexitbegin = __onexitend = (_PVFV *)(-1); 236 237 startinfo.newmode = _newmode; 238 __getmainargs(argc, argv, envp, _dowildcard, &startinfo); 239 __initenv = *envp; 240 241#ifdef _M_IX86 242 _adjust_fdiv = * _imp___adjust_fdiv; 243 _setdefaultprecision(); 244#endif 245} 246