1 /* This file is part of the YAZ toolkit.
2 * Copyright (C) 1995-2008 Index Data
3 * See the file LICENSE for details.
14 #include <yaz/xmalloc.h>
17 #include <yaz/wrbuf.h>
26 int (*sc_main)(yaz_sc_t s, int argc, char **argv);
27 void (*sc_stop)(yaz_sc_t s);
28 SERVICE_STATUS_HANDLE gSvcStatusHandle;
29 SERVICE_STATUS gSvcStatus;
33 yaz_sc_t yaz_sc_create(const char *service_name, const char *display_name)
35 yaz_sc_t s = xmalloc(sizeof(*s));
37 s->service_name = xstrdup(service_name);
38 s->display_name = xstrdup(display_name);
45 s->gSvcStatusHandle = 0;
49 static void parse_args(yaz_sc_t s, int *argc_p, char ***argv_p)
52 const char *log_file = 0;
55 /* now look for the service arguments */
57 for (i = 1; i < *argc_p; i++)
59 const char *opt = (*argv_p)[i];
60 if (!strcmp(opt, "-install"))
66 else if (!strcmp(opt, "-installa"))
73 else if (!strcmp(opt, "-remove"))
79 else if (!strcmp(opt, "-run") && i < *argc_p-1)
82 const char *dir = (*argv_p)[i+1];
90 for (; i < *argc_p; i++)
91 (*argv_p)[i] = (*argv_p)[i + skip_opt];
93 /* we must have a YAZ log file to work with */
94 for (i = 1; i < *argc_p; i++)
96 const char *opt = (*argv_p)[i];
97 if (opt[0] == '-' && opt[1] == 'l')
105 else if (i < *argc_p - 1)
107 log_file = (*argv_p)[i+1];
114 yaz_log_init_file(log_file);
119 yaz_log(YLOG_FATAL, "Must specify -l logfile for service to install");
124 { /* remove -l logfile for a running service */
125 for (; i < *argc_p; i++)
126 (*argv_p)[i] = (*argv_p)[i + skip_opt];
130 VOID sc_ReportSvcStatus(yaz_sc_t s,
131 DWORD dwCurrentState,
132 DWORD dwWin32ExitCode,
135 if (s->gSvcStatusHandle)
137 static DWORD dwCheckPoint = 1;
139 // Fill in the SERVICE_STATUS structure.
141 s->gSvcStatus.dwCurrentState = dwCurrentState;
142 s->gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
143 s->gSvcStatus.dwWaitHint = dwWaitHint;
145 if (dwCurrentState == SERVICE_START_PENDING)
146 s->gSvcStatus.dwControlsAccepted = 0;
148 s->gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
150 if ( (dwCurrentState == SERVICE_RUNNING) ||
151 (dwCurrentState == SERVICE_STOPPED) )
152 s->gSvcStatus.dwCheckPoint = 0;
154 s->gSvcStatus.dwCheckPoint = dwCheckPoint++;
156 // Report the status of the service to the SCM.
157 SetServiceStatus(s->gSvcStatusHandle, &s->gSvcStatus );
161 static yaz_sc_t global_sc = 0;
163 VOID WINAPI sc_SvcCtrlHandler(DWORD dwCtrl)
167 case SERVICE_CONTROL_STOP:
168 yaz_log(YLOG_LOG, "Service %s to stop", global_sc->service_name);
169 sc_ReportSvcStatus(global_sc, SERVICE_STOP_PENDING, NO_ERROR, 0);
170 global_sc->sc_stop(global_sc);
171 sc_ReportSvcStatus(global_sc, SERVICE_STOPPED, NO_ERROR, 0);
173 case SERVICE_CONTROL_INTERROGATE:
180 static void WINAPI sc_service_main(DWORD argc, char **argv)
182 yaz_sc_t s = global_sc;
185 yaz_log(YLOG_LOG, "Service %s starting", s->service_name);
187 s->gSvcStatusHandle = RegisterServiceCtrlHandler(
188 s->service_name, sc_SvcCtrlHandler);
190 if (!s->gSvcStatusHandle)
192 yaz_log(YLOG_FATAL|YLOG_ERRNO, "RegisterServiceCtrlHandler");
196 s->gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
197 s->gSvcStatus.dwServiceSpecificExitCode = 0;
199 sc_ReportSvcStatus(s, SERVICE_START_PENDING, NO_ERROR, 3000);
201 ret_code = s->sc_main(s, argc, argv);
203 sc_ReportSvcStatus(s, SERVICE_STOPPED,
204 ret_code ? ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR, ret_code);
207 void yaz_sc_running(yaz_sc_t s)
209 sc_ReportSvcStatus(s, SERVICE_RUNNING, NO_ERROR, 0);
212 int yaz_sc_program(yaz_sc_t s, int argc, char **argv,
213 int (*sc_main)(yaz_sc_t s, int argc, char **argv),
214 void (*sc_stop)(yaz_sc_t s))
217 s->sc_main = sc_main;
218 s->sc_stop = sc_stop;
219 parse_args(s, &argc, &argv);
221 if (s->install_flag || s->remove_flag)
223 SC_HANDLE manager = OpenSCManager(NULL /* machine */,
225 SC_MANAGER_ALL_ACCESS);
228 yaz_log(YLOG_FATAL|YLOG_ERRNO, "OpenSCManager failed");
233 SC_HANDLE schService = 0;
236 WRBUF w = wrbuf_alloc();
237 char cwdstr[_MAX_PATH];
239 if (!_getcwd(cwdstr, sizeof(cwdstr)))
240 strcpy (cwdstr, ".");
242 if (GetModuleFileName(NULL, szPath, 2048) == 0)
244 yaz_log(YLOG_FATAL, "GetModuleFileName failed");
247 wrbuf_puts(w, szPath);
248 for (i = 1; i < argc; i++)
251 wrbuf_puts(w, argv[i]);
253 wrbuf_puts(w, " -run \"");
254 wrbuf_puts(w, cwdstr);
256 yaz_log(YLOG_LOG, "path: %s", wrbuf_cstr(w));
260 manager, /* SCM database */
261 TEXT(s->service_name), /* name of service */
262 TEXT(s->display_name), /* service name to display */
263 SERVICE_ALL_ACCESS, /* desired access */
264 SERVICE_WIN32_OWN_PROCESS, /* service type */
266 SERVICE_AUTO_START : SERVICE_DEMAND_START, /* start type */
267 SERVICE_ERROR_NORMAL, /* error control type */
268 wrbuf_cstr(w), /* path to service's binary */
269 NULL, /* no load ordering group */
270 NULL, /* no tag identifier */
271 NULL, /* no dependencies */
272 NULL, /* LocalSystem account */
273 NULL); /* no password */
274 if (schService == NULL)
276 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be installed",
278 CloseServiceHandle(manager);
281 yaz_log(YLOG_LOG, "Installed service %s", s->service_name);
282 CloseServiceHandle(schService);
285 else if (s->remove_flag)
287 SC_HANDLE schService = 0;
288 SERVICE_STATUS serviceStatus;
290 schService = OpenService(manager, TEXT(s->service_name), SERVICE_ALL_ACCESS);
291 if (schService == NULL)
293 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be opened",
295 CloseServiceHandle(manager);
298 /* try to stop the service */
299 if (ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus))
301 yaz_log(YLOG_LOG, "Service %s being stopped", s->service_name);
303 while (QueryServiceStatus(schService, &serviceStatus))
305 if (serviceStatus.dwCurrentState != SERVICE_STOP_PENDING)
309 if (serviceStatus.dwCurrentState != SERVICE_STOPPED)
310 yaz_log(YLOG_LOG|YLOG_FATAL, "Service failed to stop");
312 if (DeleteService(schService))
313 yaz_log(YLOG_LOG, "Service %s removed", s->service_name);
315 yaz_log(YLOG_FATAL, "Service %s could not be removed", s->service_name);
316 CloseServiceHandle(schService);
318 CloseServiceHandle(manager);
324 SERVICE_TABLE_ENTRY dt[2];
326 dt[0].lpServiceName = s->service_name;
327 dt[0].lpServiceProc = sc_service_main;
328 dt[1].lpServiceName = 0;
329 dt[1].lpServiceProc = 0;
331 if (!StartServiceCtrlDispatcher(dt))
333 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be controlled",
339 /* run the program standalone (with no service) */
340 return s->sc_main(s, argc, argv);
345 void yaz_sc_destroy(yaz_sc_t *s)
347 xfree((*s)->service_name);
348 xfree((*s)->display_name);
356 * indent-tabs-mode: nil
358 * vim: shiftwidth=4 tabstop=8 expandtab