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
ntservice_init(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
ntservice_shutdown(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
ntservice_isservice(void)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
ServiceControl(DWORD dwCtrlCode)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 */
UpdateSCM(DWORD state)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 */
main(int argc,char * argv[])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