]> git.pond.sub.org Git - empserver/blob - src/lib/gen/service.c
66353772a78e0dcd5db7e992f96d95b192739306
[empserver] / src / lib / gen / service.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  service.c: Windows services support
29  * 
30  *  Known contributors to this file:
31  *     Ron Koenderink, 2004
32  */
33
34 #ifdef _WIN32
35 #include <windows.h>
36
37 #include "prototypes.h"
38 #include "service.h"
39 #include "../gen/getopt.h"
40 #include "optlist.h"
41
42
43 char *config_file = NULL;
44
45 int
46 install_service(char *program_name, char *service_name, int datadir_set)
47 {
48     char strDir[1024];
49     HANDLE schSCManager,schService;
50     LPCTSTR lpszBinaryPathName;
51     SERVICE_DESCRIPTION sdBuf;
52
53     if (strrchr(program_name,'\\') == NULL) {
54         GetCurrentDirectory(sizeof(strDir), strDir);
55         strcat(strDir, "\\");
56         strcat(strDir, program_name);
57     } else
58         strcpy(strDir, program_name);
59
60     if (datadir_set) {
61         strcat(strDir, " -D ");
62         strcat(strDir, datadir);
63     }
64     if (config_file != NULL) {
65         strcat(strDir, " -e ");
66         strcat(strDir, config_file);
67     }
68
69     if (service_name == NULL)
70         service_name = DEFAULT_SERVICE_NAME;
71     else if (service_name[0] == '\0')
72         service_name = DEFAULT_SERVICE_NAME;
73
74     schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
75
76     if (schSCManager == NULL) {
77         logerror("install_service failed to open Service Control Manager"); 
78         printf("Install service: failed to open Service Control Manager.\n"); 
79         return EXIT_FAILURE;
80     }
81
82     lpszBinaryPathName = strDir;
83
84     schService = CreateService(schSCManager,
85         service_name,
86         service_name,                   /* service name to display */
87         SERVICE_ALL_ACCESS,             /* desired access */
88         SERVICE_WIN32_OWN_PROCESS,      /* service type */
89         SERVICE_AUTO_START,             /* start type */
90         SERVICE_ERROR_NORMAL,           /* error control type */
91         lpszBinaryPathName,             /* service's binary */
92         NULL,                           /* no load ordering group */
93         NULL,                           /* no tag identifier */
94         NULL,                           /* database service dependency */
95         NULL,                           /* LocalSystem account */
96         NULL);                          /* no password */
97  
98     if (schService == NULL) {
99         logerror("install_service failed to create service %s", service_name);
100         printf("Install service: failed to create service %s.\n", service_name);
101         return EXIT_FAILURE;
102     }
103     sdBuf.lpDescription = "Server for Empire game";
104
105     if(!ChangeServiceConfig2(
106           schService,                 /* handle to service */
107           SERVICE_CONFIG_DESCRIPTION, /* change: description */
108           &sdBuf)) {                  /* value: new description */
109         logerror("install_service failed to set the description");
110         printf("Install service: failed to set the description.\n");
111     }
112
113     logerror("install_service successfully created the service %s", service_name);
114     printf("Service %s installed.\n", service_name);
115     CloseServiceHandle(schService);
116     return EXIT_SUCCESS;
117 }
118
119 int
120 remove_service(char *service_name)
121 {
122     HANDLE schSCManager;
123     SC_HANDLE hService;
124
125     if (service_name == NULL)
126         service_name = DEFAULT_SERVICE_NAME;
127     else if (service_name[0] == '\0')
128         service_name = DEFAULT_SERVICE_NAME;
129
130     schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
131
132     if (schSCManager == NULL) {
133         logerror("remove_service failed to open Service Control Manager"); 
134         printf("remove service: failed to open Service Control Manager.\n"); 
135         return EXIT_FAILURE;
136     }
137
138     hService = OpenService(schSCManager, service_name, SERVICE_ALL_ACCESS);
139
140     if (hService == NULL) {
141         logerror("remove_service failed to open service %s", service_name);
142         printf("Remove service: failed to open service %s.\n", service_name);
143         return EXIT_FAILURE;
144     }
145
146     if (DeleteService(hService) == 0) {
147         logerror("remove_service failed to remove service %s", service_name);
148         printf("Remove service: failed to remove service %s.\n", service_name); 
149         return EXIT_FAILURE;
150     }
151
152     if (CloseServiceHandle(hService) == 0) {
153         logerror("remove_service failed to close service %s", service_name); 
154         printf("Remove service: failed to close service %s.\n", service_name); 
155         return EXIT_FAILURE;
156     } else {
157         logerror("remove_service successfully removed service %s", service_name);
158         printf("Service %s removed.\n", service_name); 
159         return EXIT_SUCCESS;
160     }
161 }
162
163 static SERVICE_STATUS          service_status; 
164 static SERVICE_STATUS_HANDLE   service_status_handle; 
165
166 void WINAPI
167 service_ctrl_handler(DWORD Opcode) 
168
169     DWORD status; 
170  
171     switch(Opcode) 
172     { 
173         case SERVICE_CONTROL_PAUSE: 
174             service_status.dwCurrentState = SERVICE_PAUSED;
175             logerror("Pausing the service not supported");
176             break; 
177  
178         case SERVICE_CONTROL_CONTINUE: 
179             logerror("Continuing the service not supported");
180             service_status.dwCurrentState = SERVICE_RUNNING; 
181             break; 
182  
183         case SERVICE_CONTROL_STOP: 
184             service_status.dwWin32ExitCode = 0; 
185             service_status.dwCurrentState  = SERVICE_STOPPED; 
186             service_status.dwCheckPoint    = 0; 
187             service_status.dwWaitHint      = 0; 
188  
189             if (!SetServiceStatus (service_status_handle, 
190                 &service_status)) { 
191                 status = GetLastError(); 
192                 logerror("Error while stopping service SetServiceStatus"
193                     " error %ld", status); 
194             } 
195  
196             logerror("Service stopped"); 
197             return; 
198  
199         case SERVICE_CONTROL_INTERROGATE: 
200         /* Fall through to send current status.  */
201             break; 
202  
203         default: 
204             logerror("Unrecognized opcode %ld in ServiceCtrlHandler", 
205                 Opcode); 
206     } 
207  
208     /* Send current status. */
209     if (!SetServiceStatus (service_status_handle,  &service_status)) { 
210         status = GetLastError(); 
211         logerror("SetServiceStatus error %ld",status); 
212     } 
213     return; 
214
215
216 void WINAPI
217 service_main(DWORD argc, LPTSTR *argv)
218
219     int op;
220     s_char tbuf[256];
221     DWORD status;
222
223     optind = 1;
224     opterr = 1;
225     while ((op = getopt(argc, argv, "D:e:")) != EOF) {
226         switch (op) {
227         case 'D':
228                 datadir = optarg;
229                 break;
230         case 'e':
231                 config_file = optarg;
232                 break;
233         }
234     }  
235
236     if (config_file == NULL) {
237         sprintf(tbuf, "%s/econfig", datadir);
238         config_file = tbuf;
239     }
240
241     service_status.dwServiceType        = SERVICE_WIN32; 
242     service_status.dwCurrentState       = SERVICE_START_PENDING; 
243     service_status.dwControlsAccepted   = SERVICE_ACCEPT_STOP; 
244     service_status.dwWin32ExitCode      = 0; 
245     service_status.dwServiceSpecificExitCode = 0; 
246     service_status.dwCheckPoint         = 0; 
247     service_status.dwWaitHint           = 0; 
248  
249     service_status_handle = RegisterServiceCtrlHandler(
250         DEFAULT_SERVICE_NAME, service_ctrl_handler);
251  
252     if (service_status_handle == (SERVICE_STATUS_HANDLE)0) { 
253         logerror("RegisterServiceCtrlHandler failed %d\n", GetLastError()); 
254         return; 
255     }
256  
257     /* Initialization code goes here. */
258     start_server(0, config_file); 
259  
260     /* Initialization complete - report running status. */
261     service_status.dwCurrentState       = SERVICE_RUNNING; 
262     service_status.dwCheckPoint         = 0; 
263     service_status.dwWaitHint           = 0; 
264  
265     if (!SetServiceStatus (service_status_handle, &service_status)) { 
266         status = GetLastError();
267         logerror("SetServiceStatus error %ld\n",status);
268     }
269
270     empth_exit();
271
272 /* We should never get here.  But, just in case... */
273     close_files();
274
275     loc_NTTerm();
276
277     // This is where the service does its work.
278     logerror("Returning the Main Thread \n",0);
279     return;
280 }
281
282 int
283 service_stopped(void)
284 {
285     if (service_status.dwCurrentState == SERVICE_STOPPED)
286         return 1;
287     else
288         return 0;
289 }
290
291 #endif /* _WIN32 */