1 /* $NetBSD: ntservice.c,v 1.6 2014/12/10 04:37:52 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2004, 2006, 2007, 2009, 2011, 2013, 2014 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/commandline.h> 27 #include <isc/log.h> 28 29 #include <named/globals.h> 30 #include <named/ntservice.h> 31 #include <named/main.h> 32 #include <named/server.h> 33 34 /* Handle to SCM for updating service status */ 35 static SERVICE_STATUS_HANDLE hServiceStatus = 0; 36 static BOOL foreground = FALSE; 37 static char ConsoleTitle[128]; 38 39 /* 40 * Forward declarations 41 */ 42 void ServiceControl(DWORD dwCtrlCode); 43 int bindmain(int, char *[]); /* From main.c */ 44 45 /* 46 * Initialize the Service by registering it. 47 */ 48 void 49 ntservice_init(void) { 50 if (!foreground) { 51 /* Register handler with the SCM */ 52 hServiceStatus = RegisterServiceCtrlHandler(BIND_SERVICE_NAME, 53 (LPHANDLER_FUNCTION)ServiceControl); 54 if (!hServiceStatus) { 55 ns_main_earlyfatal( 56 "could not register service control handler"); 57 UpdateSCM(SERVICE_STOPPED); 58 exit(1); 59 } 60 UpdateSCM(SERVICE_RUNNING); 61 } else { 62 strcpy(ConsoleTitle, "BIND Version "); 63 strcat(ConsoleTitle, VERSION); 64 SetConsoleTitle(ConsoleTitle); 65 } 66 } 67 68 void 69 ntservice_shutdown(void) { 70 UpdateSCM(SERVICE_STOPPED); 71 } 72 /* 73 * Routine to check if this is a service or a foreground program 74 */ 75 BOOL 76 ntservice_isservice(void) { 77 return(!foreground); 78 } 79 /* 80 * ServiceControl(): Handles requests from the SCM and passes them on 81 * to named. 82 */ 83 void 84 ServiceControl(DWORD dwCtrlCode) { 85 /* Handle the requested control code */ 86 switch(dwCtrlCode) { 87 case SERVICE_CONTROL_INTERROGATE: 88 UpdateSCM(0); 89 break; 90 91 case SERVICE_CONTROL_SHUTDOWN: 92 case SERVICE_CONTROL_STOP: 93 ns_server_flushonshutdown(ns_g_server, ISC_TRUE); 94 isc_app_shutdown(); 95 UpdateSCM(SERVICE_STOPPED); 96 break; 97 default: 98 break; 99 } 100 } 101 102 /* 103 * Tell the Service Control Manager the state of the service. 104 */ 105 void UpdateSCM(DWORD state) { 106 SERVICE_STATUS ss; 107 static DWORD dwState = SERVICE_STOPPED; 108 109 if (hServiceStatus) { 110 if (state) 111 dwState = state; 112 113 memset(&ss, 0, sizeof(SERVICE_STATUS)); 114 ss.dwServiceType |= SERVICE_WIN32_OWN_PROCESS; 115 ss.dwCurrentState = dwState; 116 ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | 117 SERVICE_ACCEPT_SHUTDOWN; 118 ss.dwCheckPoint = 0; 119 ss.dwServiceSpecificExitCode = 0; 120 ss.dwWin32ExitCode = NO_ERROR; 121 ss.dwWaitHint = dwState == SERVICE_STOP_PENDING ? 10000 : 1000; 122 123 if (!SetServiceStatus(hServiceStatus, &ss)) { 124 ss.dwCurrentState = SERVICE_STOPPED; 125 SetServiceStatus(hServiceStatus, &ss); 126 } 127 } 128 } 129 130 /* unhook main */ 131 132 #undef main 133 134 /* 135 * This is the entry point for the executable 136 * We can now call bindmain() explicitly or via StartServiceCtrlDispatcher() 137 * as we need to. 138 */ 139 int main(int argc, char *argv[]) 140 { 141 int rc, ch; 142 143 /* Command line users should put -f in the options. */ 144 isc_commandline_errprint = ISC_FALSE; 145 while ((ch = isc_commandline_parse(argc, argv, 146 "46c:C:d:D:E:fFgi:lm:n:N:p:P:" 147 "sS:t:T:U:u:vVx:")) != -1) { 148 switch (ch) { 149 case 'f': 150 case 'g': 151 case 'v': 152 case 'V': 153 foreground = TRUE; 154 break; 155 default: 156 break; 157 } 158 } 159 isc_commandline_reset = ISC_TRUE; 160 161 if (foreground) { 162 /* run in console window */ 163 exit(bindmain(argc, argv)); 164 } else { 165 /* Start up as service */ 166 char *SERVICE_NAME = BIND_SERVICE_NAME; 167 168 SERVICE_TABLE_ENTRY dispatchTable[] = { 169 { TEXT(SERVICE_NAME), 170 (LPSERVICE_MAIN_FUNCTION)bindmain }, 171 { NULL, NULL } 172 }; 173 174 rc = StartServiceCtrlDispatcher(dispatchTable); 175 if (!rc) { 176 fprintf(stderr, 177 "Use -f to run from the command line.\n"); 178 /* will be 1063 when launched as a console app */ 179 exit(GetLastError()); 180 } 181 } 182 exit(0); 183 } 184