From: Adam Dickmeiss Date: Tue, 22 Apr 2008 08:54:49 +0000 (+0200) Subject: Implemented new Windows Service wrapper (sc). X-Git-Tag: v3.0.30~46 X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=commitdiff_plain;h=540056f9cf1a3304b253db09eba899cc6763466d Implemented new Windows Service wrapper (sc). --- diff --git a/include/yaz/sc.h b/include/yaz/sc.h new file mode 100644 index 0000000..1889e1d --- /dev/null +++ b/include/yaz/sc.h @@ -0,0 +1,60 @@ +/* This file is part of the YAZ toolkit. + * Copyright (C) 1995-2008 Index Data. + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Index Data nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \file sc.h + * \brief Header for Windows Service Control stuff + */ + + +#include + +YAZ_BEGIN_CDECL + +typedef struct sc_s *yaz_sc_t; + +YAZ_EXPORT yaz_sc_t yaz_sc_create(const char *service_name, + const char *display_name); + +YAZ_EXPORT void yaz_sc_running(yaz_sc_t s); + +YAZ_EXPORT int yaz_sc_program(yaz_sc_t s, int argc, char **argv, + int (*sc_main)(yaz_sc_t s, int argc, char **argv), + void (*sc_stop)(yaz_sc_t s)); + +YAZ_EXPORT void yaz_sc_destroy(yaz_sc_t *s); + +YAZ_END_CDECL + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/src/sc.c b/src/sc.c new file mode 100644 index 0000000..7102fa8 --- /dev/null +++ b/src/sc.c @@ -0,0 +1,360 @@ +/* This file is part of the YAZ toolkit. + * Copyright (C) 1995-2008 Index Data + * See the file LICENSE for details. + */ + +#ifdef WIN32 +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +struct sc_s { + int install_flag; + int start_flag; + int remove_flag; + int run_flag; + char *service_name; + char *display_name; + int (*sc_main)(yaz_sc_t s, int argc, char **argv); + void (*sc_stop)(yaz_sc_t s); + SERVICE_STATUS_HANDLE gSvcStatusHandle; + SERVICE_STATUS gSvcStatus; +}; + + +yaz_sc_t yaz_sc_create(const char *service_name, const char *display_name) +{ + yaz_sc_t s = xmalloc(sizeof(*s)); + + s->service_name = xstrdup(service_name); + s->display_name = xstrdup(display_name); + s->install_flag = 0; + s->start_flag = 0; + s->remove_flag = 0; + s->run_flag = 0; + s->sc_main = 0; + s->sc_stop = 0; + s->gSvcStatusHandle = 0; + return s; +} + +static void parse_args(yaz_sc_t s, int *argc_p, char ***argv_p) +{ + int skip_opt = 0; + const char *log_file = 0; + int i; + + /* now look for the service arguments */ + skip_opt = 0; + for (i = 1; i < *argc_p; i++) + { + const char *opt = (*argv_p)[i]; + if (!strcmp(opt, "-install")) + { + s->install_flag = 1; + skip_opt = 1; + break; + } + else if (!strcmp(opt, "-installa")) + { + s->install_flag = 1; + s->start_flag = 1; + skip_opt = 1; + break; + } + else if (!strcmp(opt, "-remove")) + { + s->remove_flag = 1; + skip_opt = 1; + break; + } + else if (!strcmp(opt, "-run") && i < *argc_p-1) + { + /* -run dir */ + const char *dir = (*argv_p)[i+1]; + s->run_flag = 1; + chdir(dir); + skip_opt = 2; + break; + } + } + *argc_p -= skip_opt; + for (; i < *argc_p; i++) + (*argv_p)[i] = (*argv_p)[i + skip_opt]; + + /* we must have a YAZ log file to work with */ + for (i = 1; i < *argc_p; i++) + { + const char *opt = (*argv_p)[i]; + if (opt[0] == '-' && opt[1] == 'l') + { + if (opt[2]) + { + log_file = opt+2; + skip_opt = 1; + break; + } + else if (i < *argc_p - 1) + { + log_file = (*argv_p)[i+1]; + skip_opt = 2; + break; + } + } + } + if (log_file) + yaz_log_init_file(log_file); + else + { + if (s->install_flag) + { + yaz_log(YLOG_FATAL, "Must specify -l logfile for service to install"); + exit(1); + } + } + if (s->run_flag) + { /* remove -l logfile for a running service */ + for (; i < *argc_p; i++) + (*argv_p)[i] = (*argv_p)[i + skip_opt]; + } +} + +VOID sc_ReportSvcStatus(yaz_sc_t s, + DWORD dwCurrentState, + DWORD dwWin32ExitCode, + DWORD dwWaitHint) +{ + if (s->gSvcStatusHandle) + { + static DWORD dwCheckPoint = 1; + + // Fill in the SERVICE_STATUS structure. + + s->gSvcStatus.dwCurrentState = dwCurrentState; + s->gSvcStatus.dwWin32ExitCode = dwWin32ExitCode; + s->gSvcStatus.dwWaitHint = dwWaitHint; + + if (dwCurrentState == SERVICE_START_PENDING) + s->gSvcStatus.dwControlsAccepted = 0; + else + s->gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + if ( (dwCurrentState == SERVICE_RUNNING) || + (dwCurrentState == SERVICE_STOPPED) ) + s->gSvcStatus.dwCheckPoint = 0; + else + s->gSvcStatus.dwCheckPoint = dwCheckPoint++; + + // Report the status of the service to the SCM. + SetServiceStatus(s->gSvcStatusHandle, &s->gSvcStatus ); + } +} + +static yaz_sc_t global_sc = 0; + +VOID WINAPI sc_SvcCtrlHandler(DWORD dwCtrl) +{ + switch(dwCtrl) + { + case SERVICE_CONTROL_STOP: + yaz_log(YLOG_LOG, "Service %s to stop", global_sc->service_name); + sc_ReportSvcStatus(global_sc, SERVICE_STOP_PENDING, NO_ERROR, 0); + global_sc->sc_stop(global_sc); + sc_ReportSvcStatus(global_sc, SERVICE_STOPPED, NO_ERROR, 0); + return; + case SERVICE_CONTROL_INTERROGATE: + break; + default: + break; + } +} + +static void WINAPI sc_service_main(DWORD argc, char **argv) +{ + yaz_sc_t s = global_sc; + int ret_code; + + yaz_log(YLOG_LOG, "Service %s starting", s->service_name); + + s->gSvcStatusHandle = RegisterServiceCtrlHandler( + s->service_name, sc_SvcCtrlHandler); + + if (!s->gSvcStatusHandle) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "RegisterServiceCtrlHandler"); + return; + } + + s->gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + s->gSvcStatus.dwServiceSpecificExitCode = 0; + + sc_ReportSvcStatus(s, SERVICE_START_PENDING, NO_ERROR, 3000); + + ret_code = s->sc_main(s, argc, argv); + + sc_ReportSvcStatus(s, SERVICE_STOPPED, + ret_code ? ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR, ret_code); +} + +void yaz_sc_running(yaz_sc_t s) +{ + sc_ReportSvcStatus(s, SERVICE_RUNNING, NO_ERROR, 0); +} + +int yaz_sc_program(yaz_sc_t s, int argc, char **argv, + int (*sc_main)(yaz_sc_t s, int argc, char **argv), + void (*sc_stop)(yaz_sc_t s)) + +{ + s->sc_main = sc_main; + s->sc_stop = sc_stop; + parse_args(s, &argc, &argv); + + if (s->install_flag || s->remove_flag) + { + SC_HANDLE manager = OpenSCManager(NULL /* machine */, + NULL /* database */, + SC_MANAGER_ALL_ACCESS); + if (manager == NULL) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "OpenSCManager failed"); + exit(1); + } + if (s->install_flag) + { + SC_HANDLE schService = 0; + TCHAR szPath[2048]; + int i; + WRBUF w = wrbuf_alloc(); + char cwdstr[_MAX_PATH]; + + if (!_getcwd(cwdstr, sizeof(cwdstr))) + strcpy (cwdstr, "."); + + if (GetModuleFileName(NULL, szPath, 2048) == 0) + { + yaz_log(YLOG_FATAL, "GetModuleFileName failed"); + exit(1); + } + wrbuf_puts(w, szPath); + for (i = 1; i < argc; i++) + { + wrbuf_puts(w, " "); + wrbuf_puts(w, argv[i]); + } + wrbuf_puts(w, " -run \""); + wrbuf_puts(w, cwdstr); + wrbuf_puts(w, "\""); + yaz_log(YLOG_LOG, "path: %s", wrbuf_cstr(w)); + + schService = + CreateService( + manager, /* SCM database */ + TEXT(s->service_name), /* name of service */ + TEXT(s->display_name), /* service name to display */ + SERVICE_ALL_ACCESS, /* desired access */ + SERVICE_WIN32_OWN_PROCESS, /* service type */ + s->start_flag ? + SERVICE_AUTO_START : SERVICE_DEMAND_START, /* start type */ + SERVICE_ERROR_NORMAL, /* error control type */ + wrbuf_cstr(w), /* path to service's binary */ + NULL, /* no load ordering group */ + NULL, /* no tag identifier */ + NULL, /* no dependencies */ + NULL, /* LocalSystem account */ + NULL); /* no password */ + if (schService == NULL) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be installed", + s->service_name); + CloseServiceHandle(manager); + exit(1); + } + yaz_log(YLOG_LOG, "Installed service %s", s->service_name); + CloseServiceHandle(schService); + wrbuf_destroy(w); + } + else if (s->remove_flag) + { + SC_HANDLE schService = 0; + SERVICE_STATUS serviceStatus; + + schService = OpenService(manager, TEXT(s->service_name), SERVICE_ALL_ACCESS); + if (schService == NULL) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be opened", + s->service_name); + CloseServiceHandle(manager); + exit(1); + } + /* try to stop the service */ + if (ControlService(schService, SERVICE_CONTROL_STOP, &serviceStatus)) + { + yaz_log(YLOG_LOG, "Service %s being stopped", s->service_name); + Sleep(1000); + while (QueryServiceStatus(schService, &serviceStatus)) + { + if (serviceStatus.dwCurrentState != SERVICE_STOP_PENDING) + break; + Sleep( 1000 ); + } + if (serviceStatus.dwCurrentState != SERVICE_STOPPED) + yaz_log(YLOG_LOG|YLOG_FATAL, "Service failed to stop"); + } + if (DeleteService(schService)) + yaz_log(YLOG_LOG, "Service %s removed", s->service_name); + else + yaz_log(YLOG_FATAL, "Service %s could not be removed", s->service_name); + CloseServiceHandle(schService); + } + CloseServiceHandle(manager); + exit(0); + } + global_sc = s; + if (s->run_flag) + { + SERVICE_TABLE_ENTRY dt[2]; + + dt[0].lpServiceName = s->service_name; + dt[0].lpServiceProc = sc_service_main; + dt[1].lpServiceName = 0; + dt[1].lpServiceProc = 0; + + if (!StartServiceCtrlDispatcher(dt)) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "Service %s could not be controlled", + s->service_name); + } + } + else + { + /* run the program standalone (with no service) */ + return s->sc_main(s, argc, argv); + } + return 0; +} + +void yaz_sc_destroy(yaz_sc_t *s) +{ + xfree((*s)->service_name); + xfree((*s)->display_name); + xfree(*s); + *s = 0; +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/src/sc_test.c b/src/sc_test.c new file mode 100644 index 0000000..025baab --- /dev/null +++ b/src/sc_test.c @@ -0,0 +1,58 @@ +/* This file is part of the YAZ toolkit. + * Copyright (C) 1995-2008 Index Data + * See the file LICENSE for details. + */ + +#ifdef WIN32 +#include +#include +#include +#endif + +#include +#include +#include +#include +#include + +HANDLE default_stop_event = NULL; +static void default_sc_stop(yaz_sc_t s) +{ + SetEvent(default_stop_event); +} + +static int default_sc_main(yaz_sc_t s, int argc, char **argv) +{ + default_stop_event = CreateEvent( + NULL, // default security attributes + TRUE, // manual reset event + FALSE, // not signaled + NULL); // no name + + if (default_stop_event == NULL) + { + return 1; + } + yaz_sc_running(s); + WaitForSingleObject(default_stop_event, INFINITE); + return 0; +} + + +int main(int argc, char **argv) +{ + yaz_sc_t s = yaz_sc_create("yaz_sc_test", "YAZ Service Control Test"); + + yaz_sc_program(s, argc, argv, default_sc_main, default_sc_stop); + + yaz_sc_destroy(&s); + exit(0); +} +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ + diff --git a/src/service.c b/src/service.c deleted file mode 100644 index ac938dd..0000000 --- a/src/service.c +++ /dev/null @@ -1,472 +0,0 @@ -/* This file is part of the YAZ toolkit. - * Copyright (C) 1995-2008 Index Data - * See the file LICENSE for details. - */ - -/** - * \file service.c - * \brief Implements NT service handling for GFS. - */ - -#ifdef WIN32 - -#include -#include -#include -#include - -#include "service.h" - -static AppService *pService = NULL; -static BOOL bRunAsService = TRUE; -static void *pAppHandle = NULL; - -/* Private functions to this module */ -void Service_Create(LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies, int argc, char **argv); -void Service_Delete(); -void Service_Initialize(); -BOOL NotifyServiceController(); -BOOL UpdateServiceStatus(DWORD Status); -void FailServiceStart(DWORD Win32Code, DWORD PrivateCode); -void CmdInstallService(int argc, char *argv[], BOOL bAutoStart); -void CmdRemoveService(); -LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize); -BOOL CheckServiceArguments(int argc, char *argv[]); - -/* Callback functions for thee service manager */ -void WINAPI ServiceMain(DWORD argc, LPTSTR argv[]); -void WINAPI ServiceControlHandler(DWORD fdwControl); - -/* Function to handle Ctrl + C etc... */ -BOOL EventHandlerRoutine(DWORD dwCtrlType); - -void Service_Create(LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies, int argc, char **argv) -{ - pService = malloc(sizeof(AppService)); - pService->pAppName = pAppName; - pService->pServiceName = pServiceName; - pService->pServiceDisplayName = pServiceDisplayName; - pService->pDependancies = pDependancies; - pService->hService = 0; - pService->ServiceTable[0].lpServiceName = pServiceName; - pService->ServiceTable[0].lpServiceProc = ServiceMain; - pService->ServiceTable[1].lpServiceName = NULL; - pService->ServiceTable[1].lpServiceProc = NULL; - pService->argc = argc; - pService->argv = argv; -} - -void Service_Delete() -{ - if (pService != NULL) - { - /* Mark the service as stopping */ - UpdateServiceStatus(SERVICE_STOP_PENDING); - - /* Stop the service */ - StopAppService(pAppHandle); - - /* Service has now stopped */ - UpdateServiceStatus(SERVICE_STOPPED); - - /* Free the memory */ - free(pService); - pService = NULL; - } -} - -void Service_Initialize() -{ - if (pService != NULL) - { - /* Register ourselves with the control dispatcher */ - StartServiceCtrlDispatcher(pService->ServiceTable); - } -} - -void WINAPI ServiceMain(DWORD argc, LPTSTR argv[]) -{ - if (pService != NULL) - { - if (NotifyServiceController()) - { - /* Set the status to pending */ - UpdateServiceStatus(SERVICE_START_PENDING); - - /* Lets attempt to start the service */ - if (StartAppService(pAppHandle, pService->argc, pService->argv)) - { - /* Service is now up and running */ - UpdateServiceStatus(SERVICE_RUNNING); - - /* Lets wait for our clients */ - RunAppService(pAppHandle); - } - else - { - FailServiceStart(GetLastError(), 0); - Service_Delete(); - } - } - } -} - -BOOL NotifyServiceController() -{ - if (pService == NULL) - { - return(FALSE); - } - else - { - if (bRunAsService) - { - pService->ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - pService->ServiceStatus.dwCurrentState = SERVICE_STOPPED; - pService->ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; - pService->ServiceStatus.dwWin32ExitCode = 0; - pService->ServiceStatus.dwServiceSpecificExitCode = 0; - pService->ServiceStatus.dwCheckPoint = 0; - pService->ServiceStatus.dwWaitHint = 0; - pService->hService = RegisterServiceCtrlHandler(pService->pServiceName, ServiceControlHandler); - - if (pService->hService) - UpdateServiceStatus(SERVICE_START_PENDING); - else - return(FALSE); - } - return(TRUE); - } -} - -void WINAPI ServiceControlHandler(DWORD fdwControl) -{ - if (pService != NULL) - { - switch (fdwControl) - { - case SERVICE_CONTROL_STOP: - /* Update the service status to be pending */ - Service_Delete(); - break; - - case SERVICE_CONTROL_INTERROGATE: - UpdateServiceStatus(pService->ServiceStatus.dwCurrentState); - break; - - default: - break; - } - } -} - -BOOL UpdateServiceStatus(DWORD Status) -{ - if (pService != NULL) - { - if (pService->hService) - { - pService->ServiceStatus.dwCurrentState = Status; - if ((Status == SERVICE_START_PENDING) || (Status == SERVICE_STOP_PENDING)) - { - pService->ServiceStatus.dwCheckPoint ++; - pService->ServiceStatus.dwWaitHint = 5000; /* 5 sec.*/ - } - else - { - pService->ServiceStatus.dwCheckPoint = 0; - pService->ServiceStatus.dwWaitHint = 0; - } - - return(SetServiceStatus(pService->hService, &pService->ServiceStatus)); - } - } - - return(FALSE); -} - -void FailServiceStart(DWORD Win32Code, DWORD PrivateCode) -{ - if (pService != NULL) - { - pService->ServiceStatus.dwWin32ExitCode = Win32Code; - pService->ServiceStatus.dwServiceSpecificExitCode = PrivateCode; - UpdateServiceStatus(SERVICE_STOPPED); - } -} - -void CmdInstallService(int argc, char *argv[], BOOL bAutoStart) -{ - if (pService != NULL) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - TCHAR szPath[2048]; - - if (GetModuleFileName(NULL, szPath, 512) == 0) - { - _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(pService->pServiceDisplayName), GetLastErrorText(pService->szErr, 256)); - } - else - { - int i; - char cwdstr[_MAX_PATH]; - - if (!_getcwd(cwdstr, sizeof(cwdstr))) - strcpy (cwdstr, "."); - - strcat (szPath, TEXT(" -runservice \"")); - strcat (szPath, cwdstr); - strcat (szPath, "\""); - - for (i = 1; i < argc; i++) - { - /* We will add the given command line arguments to the command */ - /* We are not interested in the install and remove options */ - if ((strcmp("-install", argv[i]) != 0) && - (strcmp("-installa", argv[i]) != 0) && - (strcmp("-remove", argv[i]) != 0)) - { - strcat(szPath, TEXT(" ")); - strcat(szPath, argv[i]); - } - } - - schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ - NULL, /* database (NULL == default) */ - SC_MANAGER_ALL_ACCESS); /* access required */ - if (schSCManager) - { - schService = CreateService(schSCManager, /* SCManager database */ - TEXT(pService->pServiceName), /* name of service */ - TEXT(pService->pServiceDisplayName), /* name to display */ - SERVICE_ALL_ACCESS, /* desired access */ - SERVICE_WIN32_OWN_PROCESS, /* service type */ - bAutoStart ? SERVICE_AUTO_START : - SERVICE_DEMAND_START, /* start type */ - SERVICE_ERROR_NORMAL, /* error control type */ - szPath, /* service's binary */ - NULL, /* no load ordering group */ - NULL, /* no tag identifier */ - TEXT(pService->pDependancies), /* dependencies */ - NULL, /* LocalSystem account */ - NULL); /* no password */ - - if (schService) - { - _tprintf(TEXT("%s installed.\n"), TEXT(pService->pServiceDisplayName)); - CloseServiceHandle(schService); - } - else - { - _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(pService->szErr, 256)); - } - - CloseServiceHandle(schSCManager); - } - else - _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(pService->szErr,256)); - } - } -} - -void CmdRemoveService() -{ - if (pService != NULL) - { - SC_HANDLE schService; - SC_HANDLE schSCManager; - - schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ - NULL, /* database (NULL == default) */ - SC_MANAGER_ALL_ACCESS); /* access required */ - if (schSCManager) - { - schService = OpenService(schSCManager, TEXT(pService->pServiceName), SERVICE_ALL_ACCESS); - - if (schService) - { - /* try to stop the service */ - if (ControlService(schService, SERVICE_CONTROL_STOP, &pService->ServiceStatus)) - { - _tprintf(TEXT("Stopping %s."), TEXT(pService->pServiceDisplayName)); - Sleep(1000); - - while (QueryServiceStatus(schService, &pService->ServiceStatus)) - { - if (pService->ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING) - { - _tprintf(TEXT(".")); - Sleep( 1000 ); - } - else - break; - } - - if (pService->ServiceStatus.dwCurrentState == SERVICE_STOPPED) - _tprintf(TEXT("\n%s stopped.\n"), TEXT(pService->pServiceDisplayName)); - else - _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(pService->pServiceDisplayName)); - - } - - /* now remove the service */ - if(DeleteService(schService)) - _tprintf(TEXT("%s removed.\n"), TEXT(pService->pServiceDisplayName)); - else - _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(pService->szErr,256)); - - CloseServiceHandle(schService); - } - else - _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(pService->szErr,256)); - - CloseServiceHandle(schSCManager); - } - else - _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(pService->szErr,256)); - } -} - -LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize) -{ - DWORD dwRet; - LPTSTR lpszTemp = NULL; - - dwRet = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY, - NULL, - GetLastError(), - LANG_NEUTRAL, - (LPTSTR)&lpszTemp, - 0, - NULL); - - /* supplied buffer is not long enough */ - if (!dwRet || ((long)dwSize < (long)dwRet + 14)) - lpszBuf[0] = TEXT('\0'); - else - { - lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); /* remove cr and newline character */ - _stprintf(lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError()); - } - - if (lpszTemp) - LocalFree((HLOCAL)lpszTemp); - - return(lpszBuf); -} - -BOOL CheckServiceArguments(int argc, char *argv[]) -{ - int i; - - /* Lets process the arguments */ - for (i = 1; i < argc; i++) - { - if (stricmp("-install", argv[i]) == 0) - { - /* They want to install the service */ - CmdInstallService(argc, argv, FALSE); - - /* We don't carry on, after we have installed the service */ - return(FALSE); - } - else if (stricmp("-installa", argv[i]) == 0) - { - /* They want to install the service */ - CmdInstallService(argc, argv, TRUE); - - /* We don't carry on, after we have installed the service */ - return(FALSE); - } - else if (stricmp("-remove", argv[i]) == 0) - { - /* Here they want to remove it */ - CmdRemoveService(); - - /* We don't carry on, after we have removed the service */ - return(FALSE); - } - else if (stricmp ("-runservice", argv[i]) == 0) - { - /* We can carry on, if we reached here */ - chdir(argv[i+1]); - argv[i] = ""; - argv[i+1] = ""; - return(TRUE); - } - } - bRunAsService = FALSE; - return(TRUE); -} - -BOOL SetupService(int argc, char *argv[], void *pHandle, LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies) -{ - BOOL bDeleteService = TRUE; - BOOL bResult = FALSE; - - /* Save the handle for later use */ - pAppHandle = pHandle; - - /* Create our service class */ - Service_Create(pAppName, pServiceName, pServiceDisplayName, pDependancies, argc, argv); - - if (CheckServiceArguments(argc, argv)) - { - if (bRunAsService) - { - /* No need to set the console control handler, as the service manager handles all this for us */ - Service_Initialize(); - bDeleteService = FALSE; - } - else - { - /* Set the console control handler for exiting the program */ - SetConsoleCtrlHandler((PHANDLER_ROUTINE)EventHandlerRoutine, TRUE); - - /* Now do the main work */ - ServiceMain(argc, argv); - } - - /* We have been successful initializing, so let the caller know */ - bResult = TRUE; - } - - if (bDeleteService) - { - /* Finished with the service now */ - Service_Delete(); - } - return(bResult); -} - -BOOL EventHandlerRoutine(DWORD dwCtrlType) -{ - /* This routine dosn't seem to get called all the time, Why ??? */ - switch (dwCtrlType) - { - case CTRL_C_EVENT: /* A CTRL+C signal was received, either from keyboard input or from a signal generated by the GenerateConsoleCtrlEvent function.*/ - case CTRL_BREAK_EVENT: /* A CTRL+BREAK signal was received, either from keyboard input or from a signal generated by GenerateConsoleCtrlEvent.*/ - case CTRL_CLOSE_EVENT: /* A signal that the system sends to all processes attached to a console when the user closes the console (either by choosing the Close command from the console window's System menu, or by choosing the End Task command from the Task List).*/ - case CTRL_LOGOFF_EVENT: /* A signal that the system sends to all console processes when a user is logging off. This signal does not indicate which user is logging off, so no assumptions can be made.*/ - case CTRL_SHUTDOWN_EVENT: /* A signal that the system sends to all console processes when the system */ - /* We are basically shutting down, so call Service_Delete */ - Service_Delete(); - return(FALSE); - break; - - default: - /* we are not handling this one, so return FALSE */ - return(FALSE); - } -} -#endif -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * End: - * vim: shiftwidth=4 tabstop=8 expandtab - */ - diff --git a/src/service.h b/src/service.h deleted file mode 100644 index 6cc5543..0000000 --- a/src/service.h +++ /dev/null @@ -1,76 +0,0 @@ -/* This file is part of the YAZ toolkit. - * Copyright (C) 1995-2008 Index Data. - * All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Index Data nor the names of its contributors - * may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/** - * \file service.h - * \brief Header for NT service handling. - */ - -#ifndef SERVICE_INCLUDED -#define SERVICE_INCLUDED - -#ifdef WIN32 - -#include - -typedef struct _Service -{ - LPTSTR pAppName; - LPTSTR pServiceName; - LPTSTR pServiceDisplayName; - LPTSTR pDependancies; - TCHAR szErr[256]; - SERVICE_STATUS_HANDLE hService; - SERVICE_STATUS ServiceStatus; - SERVICE_TABLE_ENTRY ServiceTable[2]; - int argc; - char **argv; -} AppService; - -/* Called by the app to initialize the service */ -BOOL SetupService(int argc, char *argv[], void *pHandle, LPTSTR pAppName, LPTSTR pServiceName, LPTSTR pServiceDisplayName, LPTSTR pDependancies); - -#endif /* WIN32 */ - -/* Functions that must be in the main application */ -/* Initializes the app */ -int StartAppService(void *pHandle, int argc, char **argv); - -/* Now we wait for any connections */ -void RunAppService(void *pHandle); - -/* Time to tidyup and stop the service */ -void StopAppService(void *pHandle); - -#endif -/* - * Local variables: - * c-basic-offset: 4 - * indent-tabs-mode: nil - * End: - * vim: shiftwidth=4 tabstop=8 expandtab - */ - diff --git a/src/statserv.c b/src/statserv.c index b20b670..fafff6b 100644 --- a/src/statserv.c +++ b/src/statserv.c @@ -12,12 +12,15 @@ #include #include #include + #ifdef WIN32 #include #include #include -#include "service.h" #endif + +#include + #if HAVE_SYS_TYPES_H #include #endif @@ -399,7 +402,7 @@ static void xml_config_read(void) if (!strcmp((const char *) ptr->name, "host")) { gfs->host = nmem_dup_xml_content(gfs_nmem, - ptr->children); + ptr->children); } else if (!strcmp((const char *) ptr->name, "config")) { @@ -626,7 +629,7 @@ static void ThreadList_Initialize() /* Initialize the critical Sections */ InitializeCriticalSection(&Thread_CritSect); - /* Set the first thraed */ + /* Set the first thraed */ pFirstThread = NULL; /* we have been initialized */ @@ -1131,7 +1134,7 @@ static int add_listener(char *where, int listen_id) return -1; } if (!(lst = iochan_create(cs_fileno(l), listener, EVENT_INPUT | - EVENT_EXCEPT, listen_id))) + EVENT_EXCEPT, listen_id))) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create IOCHAN-type"); cs_close (l); @@ -1477,86 +1480,43 @@ int check_options(int argc, char **argv) fprintf(stderr, "Usage: %s [ -a -v " " -l -u -c -t " " -k -d -p -C certfile" - " -ziDST1 -m -w ... ]\n", me); + " -ziDST1 -m -w ... ]\n", me); return 1; } } return 0; } -#ifdef WIN32 -typedef struct _Args -{ - char **argv; - int argc; -} Args; - -static Args ArgDetails; - -/* name of the executable */ -#define SZAPPNAME "server" - -/* list of service dependencies - "dep1\0dep2\0\0" */ -#define SZDEPENDENCIES "" - -int statserv_main(int argc, char **argv, - bend_initresult *(*bend_init)(bend_initrequest *r), - void (*bend_close)(void *handle)) +void statserv_sc_stop(yaz_sc_t s) { - struct statserv_options_block *cb = &control_block; - cb->bend_init = bend_init; - cb->bend_close = bend_close; - - /* Lets setup the Arg structure */ - ArgDetails.argc = argc; - ArgDetails.argv = argv; - - /* Now setup the service with the service controller */ - SetupService(argc, argv, &ArgDetails, SZAPPNAME, - cb->service_name, /* internal service name */ - cb->service_display_name, /* displayed name */ - SZDEPENDENCIES); - return 0; -} - -int StartAppService(void *pHandle, int argc, char **argv) -{ - /* Initializes the App */ - return 1; + statserv_closedown(); + statserv_reset(); } -void RunAppService(void *pHandle) +int statserv_sc_main(yaz_sc_t s, int argc, char **argv) { - Args *pArgs = (Args *)pHandle; - - /* Starts the app running */ - statserv_start(pArgs->argc, pArgs->argv); + yaz_sc_running(s); + return statserv_start(argc, argv); } -void StopAppService(void *pHandle) -{ - /* Stops the app */ - statserv_closedown(); - statserv_reset(); -} -/* WIN32 */ -#else -/* UNIX */ int statserv_main(int argc, char **argv, bend_initresult *(*bend_init)(bend_initrequest *r), void (*bend_close)(void *handle)) { int ret; + struct statserv_options_block *cb = &control_block; - control_block.bend_init = bend_init; - control_block.bend_close = bend_close; + yaz_sc_t s = yaz_sc_create(cb->service_name, + cb->service_display_name); - ret = statserv_start (argc, argv); - statserv_closedown (); - statserv_reset(); + cb->bend_init = bend_init; + cb->bend_close = bend_close; + + ret = yaz_sc_program(s, argc, argv, statserv_sc_main, statserv_sc_stop); + yaz_sc_destroy(&s); return ret; } -#endif + /* * Local variables: * c-basic-offset: 4 diff --git a/win/makefile b/win/makefile index bf8216e..ecfce48 100644 --- a/win/makefile +++ b/win/makefile @@ -43,7 +43,7 @@ BISON=bison default: all -all: dirs generate dll client ztest yazicu zoomsh utilprog testprog iconv icu libxml2 libxslt +all: dirs generate dll sc_test client ztest yazicu zoomsh utilprog testprog iconv icu libxml2 libxslt NSIS="c:\program files\nsis\makensis.exe" HHC="c:\program files\html help workshop\hhc.exe" @@ -108,6 +108,7 @@ CLIENT=$(BINDIR)\yaz-client.exe YAZ_ICU=$(BINDIR)\yaz-icu.exe ZOOMSH=$(BINDIR)\zoomsh.exe ZTEST=$(BINDIR)\yaz-ztest.exe +SC_TEST=$(BINDIR)\sc_test.exe ZOOMTST1=$(BINDIR)\zoomtst1.exe ZOOMTST2=$(BINDIR)\zoomtst2.exe @@ -132,6 +133,8 @@ dll: dirs generate $(YAZ_DLL) client: dirs generate $(CLIENT) ztest: dirs generate $(ZTEST) +sc_test: $(SC_TEST) + zoomsh: $(ZOOMSH) $(ZOOMTST1) $(ZOOMTST2) $(ZOOMTST3) \ $(ZOOMTST4) $(ZOOMTST5) $(ZOOMTST6) $(ZOOMTST7) $(ZOOMTST8) $(ZOOMTST9) \ $(ZOOMTST10) @@ -331,6 +334,9 @@ ZTEST_OBJS= \ $(OBJDIR)\read-grs.obj \ $(OBJDIR)\ztest.obj +SC_TEST_OBJS = \ + $(OBJDIR)\sc_test.obj + YAZ_ZOOMSH_OBJS = \ $(OBJDIR)\zoomsh.obj @@ -374,7 +380,6 @@ MISC_OBJS= \ $(OBJDIR)\oid_std.obj \ $(OBJDIR)\eventl.obj \ $(OBJDIR)\requestq.obj \ - $(OBJDIR)\service.obj \ $(OBJDIR)\seshigh.obj \ $(OBJDIR)\statserv.obj \ $(OBJDIR)\tcpdchk.obj \ @@ -487,7 +492,8 @@ MISC_OBJS= \ $(OBJDIR)\iconv_encode_iso_8859_1.obj \ $(OBJDIR)\iconv_encode_marc8.obj \ $(OBJDIR)\iconv_decode_marc8.obj \ - $(OBJDIR)\iconv_encode_wchar.obj + $(OBJDIR)\iconv_encode_wchar.obj \ + $(OBJDIR)\sc.obj Z3950_OBJS= \ $(OBJDIR)\z-date.obj\ @@ -818,6 +824,10 @@ $(YAZ_ICU) : "$(BINDIR)" $(YAZ_ICU_OBJS) $(YAZ_ICU_DLL) $(MT) -manifest $@.manifest -outputresource:$@;1 +$(SC_TEST) : "$(BINDIR)" $(SC_TEST_OBJS) $(YAZ_DLL) + $(LINK_PROGRAM) $(SC_TEST_OBJS) /out:$@ + $(MT) -manifest $@.manifest -outputresource:$@;1 + $(ZOOMSH) : "$(BINDIR)" $(YAZ_ZOOMSH_OBJS) $(YAZ_DLL) $(LINK_PROGRAM) $(YAZ_ZOOMSH_OBJS) /out:$@ $(MT) -manifest $@.manifest -outputresource:$@;1