Implemented new Windows Service wrapper (sc).
authorAdam Dickmeiss <adam@indexdata.dk>
Tue, 22 Apr 2008 08:54:49 +0000 (10:54 +0200)
committerAdam Dickmeiss <adam@indexdata.dk>
Tue, 22 Apr 2008 08:54:49 +0000 (10:54 +0200)
include/yaz/sc.h [new file with mode: 0644]
src/sc.c [new file with mode: 0644]
src/sc_test.c [new file with mode: 0644]
src/service.c [deleted file]
src/service.h [deleted file]
src/statserv.c
win/makefile

diff --git a/include/yaz/sc.h b/include/yaz/sc.h
new file mode 100644 (file)
index 0000000..1889e1d
--- /dev/null
@@ -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/yconfig.h>
+
+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 (file)
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 <windows.h>
+#include <tchar.h>
+#include <direct.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <yaz/xmalloc.h>
+#include <yaz/log.h>
+#include <yaz/sc.h>
+#include <yaz/wrbuf.h>
+
+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);\r
+                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 (file)
index 0000000..025baab
--- /dev/null
@@ -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 <windows.h>
+#include <tchar.h>
+#include <direct.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <yaz/xmalloc.h>
+#include <yaz/log.h>
+#include <yaz/sc.h>
+
+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 (file)
index ac938dd..0000000
+++ /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 <windows.h>
-#include <stdio.h>
-#include <tchar.h>
-#include <direct.h>
-
-#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 (file)
index 6cc5543..0000000
+++ /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 <windows.h>
-
-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
- */
-
index b20b670..fafff6b 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+
 #ifdef WIN32
 #include <process.h>
 #include <winsock.h>
 #include <direct.h>
-#include "service.h"
 #endif
+
+#include <yaz/sc.h>
+
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #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 <pdufile> -v <loglevel>"
                     " -l <logfile> -u <user> -c <config> -t <minutes>"
                     " -k <kilobytes> -d <daemon> -p <pidfile> -C certfile"
-                        " -ziDST1 -m <time-format> -w <directory> <listener-addr>... ]\n", me);
+                    " -ziDST1 -m <time-format> -w <directory> <listener-addr>... ]\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
index bf8216e..ecfce48 100644 (file)
@@ -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