1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2010 Index Data
3 * See the file LICENSE for details.
8 * \brief Windows Service Control
19 #include <yaz/xmalloc.h>
22 #include <yaz/wrbuf.h>
31 int (*sc_main)(yaz_sc_t s, int argc, char **argv);
32 void (*sc_stop)(yaz_sc_t s);
36 SERVICE_STATUS_HANDLE gSvcStatusHandle;
37 SERVICE_STATUS gSvcStatus;
42 yaz_sc_t yaz_sc_create(const char *service_name, const char *display_name)
44 yaz_sc_t s = (yaz_sc_t) xmalloc(sizeof(*s));
46 s->service_name = service_name ? xstrdup(service_name) : 0;
47 s->display_name = display_name ? xstrdup(display_name) : 0;
55 s->gSvcStatusHandle = 0;
61 static void parse_args(yaz_sc_t s, int *argc_p, char ***argv_p)
64 const char *log_file = 0;
67 /* now look for the service arguments */
69 for (i = 1; i < *argc_p; i++)
71 const char *opt = (*argv_p)[i];
72 if (!strcmp(opt, "-install"))
78 else if (!strcmp(opt, "-installa"))
85 else if (!strcmp(opt, "-remove"))
91 else if (!strcmp(opt, "-run") && i < *argc_p-1)
94 const char *dir = (*argv_p)[i+1];
101 *argc_p = *argc_p - skip_opt;
102 for (; i < *argc_p; i++)
103 (*argv_p)[i] = (*argv_p)[i + skip_opt];
105 /* now look for the service arguments */
106 /* we must have a YAZ log file to work with */
108 for (i = 1; i < *argc_p; i++)
110 const char *opt = (*argv_p)[i];
111 if (opt[0] == '-' && opt[1] == 'l')
119 else if (i < *argc_p - 1)
121 log_file = (*argv_p)[i+1];
128 yaz_log_init_file(log_file);
133 yaz_log(YLOG_FATAL, "Must specify -l logfile for service to install");
138 { /* remove -l logfile for a running service */
139 *argc_p = *argc_p - skip_opt;
140 for (; i < *argc_p; i++)
141 (*argv_p)[i] = (*argv_p)[i + skip_opt];
146 VOID sc_ReportSvcStatus(yaz_sc_t s,
147 DWORD dwCurrentState,
148 DWORD dwWin32ExitCode,
151 if (s->gSvcStatusHandle)
153 static DWORD dwCheckPoint = 1;
155 // Fill in the SERVICE_STATUS structure.
157 s->gSvcStatus.dwCurrentState = dwCurrentState;
158 s->gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
159 s->gSvcStatus.dwWaitHint = dwWaitHint;
161 if (dwCurrentState == SERVICE_START_PENDING)
162 s->gSvcStatus.dwControlsAccepted = 0;
164 s->gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
166 if ( (dwCurrentState == SERVICE_RUNNING) ||
167 (dwCurrentState == SERVICE_STOPPED) )
168 s->gSvcStatus.dwCheckPoint = 0;
170 s->gSvcStatus.dwCheckPoint = dwCheckPoint++;
172 // Report the status of the service to the SCM.
173 SetServiceStatus(s->gSvcStatusHandle, &s->gSvcStatus );
177 static yaz_sc_t global_sc = 0;
179 VOID WINAPI sc_SvcCtrlHandler(DWORD dwCtrl)
183 case SERVICE_CONTROL_STOP:
184 yaz_log(YLOG_LOG, "Service %s to stop", global_sc->service_name);
185 sc_ReportSvcStatus(global_sc, SERVICE_STOP_PENDING, NO_ERROR, 0);
186 global_sc->sc_stop(global_sc);
187 sc_ReportSvcStatus(global_sc, SERVICE_STOPPED, NO_ERROR, 0);
189 case SERVICE_CONTROL_INTERROGATE:
196 static void WINAPI sc_service_main(DWORD argc, char **argv)
198 yaz_sc_t s = global_sc;
201 yaz_log(YLOG_LOG, "Service %s starting", s->service_name);
203 s->gSvcStatusHandle = RegisterServiceCtrlHandler(
204 s->service_name, sc_SvcCtrlHandler);
206 if (!s->gSvcStatusHandle)
208 yaz_log(YLOG_FATAL|YLOG_ERRNO, "RegisterServiceCtrlHandler");
212 s->gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
213 s->gSvcStatus.dwServiceSpecificExitCode = 0;
215 sc_ReportSvcStatus(s, SERVICE_START_PENDING, NO_ERROR, 3000);
217 ret_code = s->sc_main(s, s->argc, s->argv);
219 sc_ReportSvcStatus(s, SERVICE_STOPPED,
220 ret_code ? ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR, ret_code);
224 void yaz_sc_running(yaz_sc_t s)
227 sc_ReportSvcStatus(s, SERVICE_RUNNING, NO_ERROR, 0);
231 int yaz_sc_program(yaz_sc_t s, int argc, char **argv,
232 int (*sc_main)(yaz_sc_t s, int argc, char **argv),
233 void (*sc_stop)(yaz_sc_t s))
236 s->sc_main = sc_main;
237 s->sc_stop = sc_stop;
239 parse_args(s, &argc, &argv);
241 if (s->install_flag || s->remove_flag)
243 SC_HANDLE manager = OpenSCManager(NULL /* machine */,
245 SC_MANAGER_ALL_ACCESS);
248 yaz_log(YLOG_FATAL|YLOG_ERRNO, "OpenSCManager failed");
253 SC_HANDLE schService = 0;
256 WRBUF w = wrbuf_alloc();
257 char cwdstr[_MAX_PATH];
259 if (!_getcwd(cwdstr, sizeof(cwdstr)))
260 strcpy (cwdstr, ".");
262 if (GetModuleFileName(NULL, szPath, 2048) == 0)
264 yaz_log(YLOG_FATAL, "GetModuleFileName failed");
267 wrbuf_puts(w, szPath);
268 for (i = 1; i < argc; i++)
271 if (strchr(argv[i], ' '))
273 wrbuf_puts(w, argv[i]);
274 if (strchr(argv[i], ' '))
277 wrbuf_puts(w, " -run \"");
278 wrbuf_puts(w, cwdstr);
280 yaz_log(YLOG_LOG, "path: %s", wrbuf_cstr(w));
284 manager, /* SCM database */
285 TEXT(s->service_name), /* name of service */
286 TEXT(s->display_name), /* service name to display */
287 SERVICE_ALL_ACCESS, /* desired access */
288 SERVICE_WIN32_OWN_PROCESS, /* service type */
290 SERVICE_AUTO_START : SERVICE_DEMAND_START, /* start type */
291 SERVICE_ERROR_NORMAL, /* error control type */
292 wrbuf_cstr(w), /* path to service's binary */
293 NULL, /* no load ordering group */
294 NULL, /* no tag identifier */
295 NULL, /* no dependencies */
296 NULL, /* LocalSystem account */
297 NULL); /* no password */
298 if (schService == NULL)
300 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be installed",
302 CloseServiceHandle(manager);
305 yaz_log(YLOG_LOG, "Installed service %s", s->service_name);
306 CloseServiceHandle(schService);
309 else if (s->remove_flag)
311 SC_HANDLE schService = 0;
312 SERVICE_STATUS serviceStatus;
314 schService = OpenService(manager, TEXT(s->service_name), SERVICE_ALL_ACCESS);
315 if (schService == NULL)
317 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be opened",
319 CloseServiceHandle(manager);
322 /* try to stop the service */
323 if (ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus))
325 yaz_log(YLOG_LOG, "Service %s being stopped", s->service_name);
327 while (QueryServiceStatus(schService, &serviceStatus))
329 if (serviceStatus.dwCurrentState != SERVICE_STOP_PENDING)
333 if (serviceStatus.dwCurrentState != SERVICE_STOPPED)
334 yaz_log(YLOG_LOG|YLOG_FATAL, "Service failed to stop");
336 if (DeleteService(schService))
337 yaz_log(YLOG_LOG, "Service %s removed", s->service_name);
339 yaz_log(YLOG_FATAL, "Service %s could not be removed", s->service_name);
340 CloseServiceHandle(schService);
342 CloseServiceHandle(manager);
348 SERVICE_TABLE_ENTRY dt[2];
350 dt[0].lpServiceName = s->service_name;
351 dt[0].lpServiceProc = sc_service_main;
352 dt[1].lpServiceName = 0;
353 dt[1].lpServiceProc = 0;
357 if (!StartServiceCtrlDispatcher(dt))
359 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be controlled",
365 /* run the program standalone (with no service) */
366 return s->sc_main(s, argc, argv);
369 void yaz_sc_destroy(yaz_sc_t *s)
371 xfree((*s)->service_name);
372 xfree((*s)->display_name);
380 * c-file-style: "Stroustrup"
381 * indent-tabs-mode: nil
383 * vim: shiftwidth=4 tabstop=8 expandtab