00001
00002
00003
00004
00005
00011 #ifdef WIN32
00012 #include <windows.h>
00013 #include <tchar.h>
00014 #include <direct.h>
00015 #endif
00016
00017 #include <stdio.h>
00018 #include <string.h>
00019 #include <yaz/xmalloc.h>
00020 #include <yaz/log.h>
00021 #include <yaz/sc.h>
00022 #include <yaz/wrbuf.h>
00023
00024 struct sc_s {
00025 int install_flag;
00026 int start_flag;
00027 int remove_flag;
00028 int run_flag;
00029 char *service_name;
00030 char *display_name;
00031 int (*sc_main)(yaz_sc_t s, int argc, char **argv);
00032 void (*sc_stop)(yaz_sc_t s);
00033 int argc;
00034 char **argv;
00035 #ifdef WIN32
00036 SERVICE_STATUS_HANDLE gSvcStatusHandle;
00037 SERVICE_STATUS gSvcStatus;
00038 #endif
00039 };
00040
00041
00042 yaz_sc_t yaz_sc_create(const char *service_name, const char *display_name)
00043 {
00044 yaz_sc_t s = (yaz_sc_t) xmalloc(sizeof(*s));
00045
00046 s->service_name = service_name ? xstrdup(service_name) : 0;
00047 s->display_name = display_name ? xstrdup(display_name) : 0;
00048 s->install_flag = 0;
00049 s->start_flag = 0;
00050 s->remove_flag = 0;
00051 s->run_flag = 0;
00052 s->sc_main = 0;
00053 s->sc_stop = 0;
00054 #ifdef WIN32
00055 s->gSvcStatusHandle = 0;
00056 #endif
00057 return s;
00058 }
00059
00060 #ifdef WIN32
00061 static void parse_args(yaz_sc_t s, int *argc_p, char ***argv_p)
00062 {
00063 int skip_opt = 0;
00064 const char *log_file = 0;
00065 int i;
00066
00067
00068 skip_opt = 0;
00069 for (i = 1; i < *argc_p; i++)
00070 {
00071 const char *opt = (*argv_p)[i];
00072 if (!strcmp(opt, "-install"))
00073 {
00074 s->install_flag = 1;
00075 skip_opt = 1;
00076 break;
00077 }
00078 else if (!strcmp(opt, "-installa"))
00079 {
00080 s->install_flag = 1;
00081 s->start_flag = 1;
00082 skip_opt = 1;
00083 break;
00084 }
00085 else if (!strcmp(opt, "-remove"))
00086 {
00087 s->remove_flag = 1;
00088 skip_opt = 1;
00089 break;
00090 }
00091 else if (!strcmp(opt, "-run") && i < *argc_p-1)
00092 {
00093
00094 const char *dir = (*argv_p)[i+1];
00095 s->run_flag = 1;
00096 chdir(dir);
00097 skip_opt = 2;
00098 break;
00099 }
00100 }
00101 *argc_p = *argc_p - skip_opt;
00102 for (; i < *argc_p; i++)
00103 (*argv_p)[i] = (*argv_p)[i + skip_opt];
00104
00105
00106
00107 skip_opt = 0;
00108 for (i = 1; i < *argc_p; i++)
00109 {
00110 const char *opt = (*argv_p)[i];
00111 if (opt[0] == '-' && opt[1] == 'l')
00112 {
00113 if (opt[2])
00114 {
00115 log_file = opt+2;
00116 skip_opt = 1;
00117 break;
00118 }
00119 else if (i < *argc_p - 1)
00120 {
00121 log_file = (*argv_p)[i+1];
00122 skip_opt = 2;
00123 break;
00124 }
00125 }
00126 }
00127 if (log_file)
00128 yaz_log_init_file(log_file);
00129 else
00130 {
00131 if (s->install_flag)
00132 {
00133 yaz_log(YLOG_FATAL, "Must specify -l logfile for service to install");
00134 exit(1);
00135 }
00136 }
00137 if (s->run_flag)
00138 {
00139 *argc_p = *argc_p - skip_opt;
00140 for (; i < *argc_p; i++)
00141 (*argv_p)[i] = (*argv_p)[i + skip_opt];
00142
00143 }
00144 }
00145
00146 VOID sc_ReportSvcStatus(yaz_sc_t s,
00147 DWORD dwCurrentState,
00148 DWORD dwWin32ExitCode,
00149 DWORD dwWaitHint)
00150 {
00151 if (s->gSvcStatusHandle)
00152 {
00153 static DWORD dwCheckPoint = 1;
00154
00155
00156
00157 s->gSvcStatus.dwCurrentState = dwCurrentState;
00158 s->gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
00159 s->gSvcStatus.dwWaitHint = dwWaitHint;
00160
00161 if (dwCurrentState == SERVICE_START_PENDING)
00162 s->gSvcStatus.dwControlsAccepted = 0;
00163 else
00164 s->gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
00165
00166 if ( (dwCurrentState == SERVICE_RUNNING) ||
00167 (dwCurrentState == SERVICE_STOPPED) )
00168 s->gSvcStatus.dwCheckPoint = 0;
00169 else
00170 s->gSvcStatus.dwCheckPoint = dwCheckPoint++;
00171
00172
00173 SetServiceStatus(s->gSvcStatusHandle, &s->gSvcStatus );
00174 }
00175 }
00176
00177 static yaz_sc_t global_sc = 0;
00178
00179 VOID WINAPI sc_SvcCtrlHandler(DWORD dwCtrl)
00180 {
00181 switch(dwCtrl)
00182 {
00183 case SERVICE_CONTROL_STOP:
00184 yaz_log(YLOG_LOG, "Service %s to stop", global_sc->service_name);
00185 sc_ReportSvcStatus(global_sc, SERVICE_STOP_PENDING, NO_ERROR, 0);
00186 global_sc->sc_stop(global_sc);
00187 sc_ReportSvcStatus(global_sc, SERVICE_STOPPED, NO_ERROR, 0);
00188 return;
00189 case SERVICE_CONTROL_INTERROGATE:
00190 break;
00191 default:
00192 break;
00193 }
00194 }
00195
00196 static void WINAPI sc_service_main(DWORD argc, char **argv)
00197 {
00198 yaz_sc_t s = global_sc;
00199 int ret_code;
00200
00201 yaz_log(YLOG_LOG, "Service %s starting", s->service_name);
00202
00203 s->gSvcStatusHandle = RegisterServiceCtrlHandler(
00204 s->service_name, sc_SvcCtrlHandler);
00205
00206 if (!s->gSvcStatusHandle)
00207 {
00208 yaz_log(YLOG_FATAL|YLOG_ERRNO, "RegisterServiceCtrlHandler");
00209 return;
00210 }
00211
00212 s->gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
00213 s->gSvcStatus.dwServiceSpecificExitCode = 0;
00214
00215 sc_ReportSvcStatus(s, SERVICE_START_PENDING, NO_ERROR, 3000);
00216
00217 ret_code = s->sc_main(s, s->argc, s->argv);
00218
00219 sc_ReportSvcStatus(s, SERVICE_STOPPED,
00220 ret_code ? ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR, ret_code);
00221 }
00222 #endif
00223
00224 void yaz_sc_running(yaz_sc_t s)
00225 {
00226 #ifdef WIN32
00227 sc_ReportSvcStatus(s, SERVICE_RUNNING, NO_ERROR, 0);
00228 #endif
00229 }
00230
00231 int yaz_sc_program(yaz_sc_t s, int argc, char **argv,
00232 int (*sc_main)(yaz_sc_t s, int argc, char **argv),
00233 void (*sc_stop)(yaz_sc_t s))
00234
00235 {
00236 s->sc_main = sc_main;
00237 s->sc_stop = sc_stop;
00238 #ifdef WIN32
00239 parse_args(s, &argc, &argv);
00240
00241 if (s->install_flag || s->remove_flag)
00242 {
00243 SC_HANDLE manager = OpenSCManager(NULL ,
00244 NULL ,
00245 SC_MANAGER_ALL_ACCESS);
00246 if (manager == NULL)
00247 {
00248 yaz_log(YLOG_FATAL|YLOG_ERRNO, "OpenSCManager failed");
00249 exit(1);
00250 }
00251 if (s->install_flag)
00252 {
00253 SC_HANDLE schService = 0;
00254 TCHAR szPath[2048];
00255 int i;
00256 WRBUF w = wrbuf_alloc();
00257 char cwdstr[_MAX_PATH];
00258
00259 if (!_getcwd(cwdstr, sizeof(cwdstr)))
00260 strcpy (cwdstr, ".");
00261
00262 if (GetModuleFileName(NULL, szPath, 2048) == 0)
00263 {
00264 yaz_log(YLOG_FATAL, "GetModuleFileName failed");
00265 exit(1);
00266 }
00267 wrbuf_puts(w, szPath);
00268 for (i = 1; i < argc; i++)
00269 {
00270 wrbuf_puts(w, " ");
00271 if (strchr(argv[i], ' '))
00272 wrbuf_puts(w, "\"");
00273 wrbuf_puts(w, argv[i]);
00274 if (strchr(argv[i], ' '))
00275 wrbuf_puts(w, "\"");
00276 }
00277 wrbuf_puts(w, " -run \"");
00278 wrbuf_puts(w, cwdstr);
00279 wrbuf_puts(w, "\"");
00280 yaz_log(YLOG_LOG, "path: %s", wrbuf_cstr(w));
00281
00282 schService =
00283 CreateService(
00284 manager,
00285 TEXT(s->service_name),
00286 TEXT(s->display_name),
00287 SERVICE_ALL_ACCESS,
00288 SERVICE_WIN32_OWN_PROCESS,
00289 s->start_flag ?
00290 SERVICE_AUTO_START : SERVICE_DEMAND_START,
00291 SERVICE_ERROR_NORMAL,
00292 wrbuf_cstr(w),
00293 NULL,
00294 NULL,
00295 NULL,
00296 NULL,
00297 NULL);
00298 if (schService == NULL)
00299 {
00300 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be installed",
00301 s->service_name);
00302 CloseServiceHandle(manager);
00303 exit(1);
00304 }
00305 yaz_log(YLOG_LOG, "Installed service %s", s->service_name);
00306 CloseServiceHandle(schService);
00307 wrbuf_destroy(w);
00308 }
00309 else if (s->remove_flag)
00310 {
00311 SC_HANDLE schService = 0;
00312 SERVICE_STATUS serviceStatus;
00313
00314 schService = OpenService(manager, TEXT(s->service_name), SERVICE_ALL_ACCESS);
00315 if (schService == NULL)
00316 {
00317 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be opened",
00318 s->service_name);
00319 CloseServiceHandle(manager);
00320 exit(1);
00321 }
00322
00323 if (ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus))
00324 {
00325 yaz_log(YLOG_LOG, "Service %s being stopped", s->service_name);
00326 Sleep(1000);
00327 while (QueryServiceStatus(schService, &serviceStatus))
00328 {
00329 if (serviceStatus.dwCurrentState != SERVICE_STOP_PENDING)
00330 break;
00331 Sleep( 1000 );
00332 }
00333 if (serviceStatus.dwCurrentState != SERVICE_STOPPED)
00334 yaz_log(YLOG_LOG|YLOG_FATAL, "Service failed to stop");
00335 }
00336 if (DeleteService(schService))
00337 yaz_log(YLOG_LOG, "Service %s removed", s->service_name);
00338 else
00339 yaz_log(YLOG_FATAL, "Service %s could not be removed", s->service_name);
00340 CloseServiceHandle(schService);
00341 }
00342 CloseServiceHandle(manager);
00343 exit(0);
00344 }
00345 global_sc = s;
00346 if (s->run_flag)
00347 {
00348 SERVICE_TABLE_ENTRY dt[2];
00349
00350 dt[0].lpServiceName = s->service_name;
00351 dt[0].lpServiceProc = sc_service_main;
00352 dt[1].lpServiceName = 0;
00353 dt[1].lpServiceProc = 0;
00354
00355 s->argc = argc;
00356 s->argv = argv;
00357 if (!StartServiceCtrlDispatcher(dt))
00358 {
00359 yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be controlled",
00360 s->service_name);
00361 }
00362 return 0;
00363 }
00364 #endif
00365
00366 return s->sc_main(s, argc, argv);
00367 }
00368
00369 void yaz_sc_destroy(yaz_sc_t *s)
00370 {
00371 xfree((*s)->service_name);
00372 xfree((*s)->display_name);
00373 xfree(*s);
00374 *s = 0;
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385