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