[prev in list] [next in list] [prev in thread] [next in thread]
List: clamav-devel
Subject: [Clamav-devel] win32 services patch
From: Mark Weaver <mark-clist () npsl ! co ! uk>
Date: 2010-07-31 16:03:41
Message-ID: 4C54495D.8050405 () npsl ! co ! uk
[Download RAW message or body]
The attached patch adds support for running clamd & freshclam as Windows
services. freshclam/clamd --install will install the service.
["service.patch" (text/x-diff)]
Index: freshclam/freshclam.c
===================================================================
--- freshclam/freshclam.c (revision 1255)
+++ freshclam/freshclam.c (working copy)
@@ -55,6 +55,12 @@
#include "shared/output.h"
#include "shared/misc.h"
+#ifdef _WIN32
+#include "shared/w32_service.h"
+w32_service g_service;
+static HANDLE stopEvent;
+#endif
+
#include "execute.h"
#include "manager.h"
#include "mirman.h"
@@ -65,6 +71,20 @@
static short foreground = 1;
char updtmpdir[512];
+#ifdef _WIN32
+static BOOL WINAPI CtrlHandler(DWORD dwCtrlType)
+{
+ switch (dwCtrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ terminate = 1;
+ SetEvent(stopEvent);
+ return TRUE;
+ }
+ return FALSE;
+}
+#else
static void sighandler(int sig) {
switch(sig) {
@@ -101,6 +121,7 @@
return;
}
+#endif
static void writepid(const char *pidfile)
{
@@ -140,6 +161,10 @@
mprintf(" --pid=FILE -p FILE save daemon's pid in FILE\n");
mprintf(" --user=USER -u USER run as USER\n");
#endif
+#ifdef _WIN32
+ mprintf(" --install install windows service\n");
+ mprintf(" --uninstall uninstall windows service\n");
+#endif
mprintf(" --no-dns force old non-DNS verification \
method\n");
mprintf(" --checks=#n -c #n number of checks per day, 1 <= \
n <= 50\n");
mprintf(" --datadir=DIRECTORY download new databases into \
DIRECTORY\n"); @@ -198,7 +223,11 @@
return ret;
}
+#ifdef _WIN32
+int normal_main(int argc, char **argv)
+#else
int main(int argc, char **argv)
+#endif
{
int ret = 52, retcl;
const char *dbdir, *cfgfile, *arg = NULL, *pidfile = NULL;
@@ -235,6 +264,19 @@
return 0;
}
+#ifdef _WIN32
+ if (optget(opts, "install")->enabled) {
+ w32_service_install(&g_service);
+ optfree(opts);
+ return 0;
+ }
+ if (optget(opts, "uninstall")->enabled) {
+ w32_service_uninstall(&g_service);
+ optfree(opts);
+ return 0;
+ }
+#endif
+
/* parse the config file */
cfgfile = optget(opts, "config-file")->strarg;
pt = strdup(cfgfile);
@@ -387,7 +429,8 @@
*updtmpdir = 0;
#ifdef _WIN32
- signal(SIGINT, sighandler);
+ SetConsoleCtrlHandler(CtrlHandler, TRUE);
+ stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
#else
memset(&sigact, 0, sizeof(struct sigaction));
sigact.sa_handler = sighandler;
@@ -421,17 +464,19 @@
bigsleep = 24 * 3600 / checks;
-#ifndef _WIN32
if(!optget(opts, "Foreground")->enabled) {
+#ifdef _WIN32
+ g_service.update_scm(&g_service, SERVICE_RUNNING, 0, 1000);
+#else
if(daemonize() == -1) {
logg("!daemonize() failed\n");
optfree(opts);
return 70; /* FIXME */
}
+#endif
foreground = 0;
mprintf_disabled = 1;
}
-#endif
if((opt = optget(opts, "PidFile"))->enabled) {
pidfile = opt->strarg;
@@ -467,7 +512,7 @@
#endif
#ifdef _WIN32
- sleep(bigsleep);
+ WaitForSingleObject(stopEvent, bigsleep * 1000);
#else
time(&wakeup);
wakeup += bigsleep;
@@ -519,5 +564,62 @@
optfree(opts);
+#ifdef _WIN32
+ CloseHandle(stopEvent);
+#endif
+
return(ret);
}
+
+#ifdef _WIN32
+
+static int w32_service_main(w32_service *s, DWORD argc, LPTSTR *argv)
+{
+ DWORD i;
+ char **argv2;
+
+ /* Need to force a -d in for freshclam */
+ argv2 = (char **)malloc(sizeof(char *) * (argc + 2));
+ if (!argv2) {
+ return ERROR_OUTOFMEMORY;
+ }
+ for (i = 0; i < argc; ++i) {
+ argv2[i] = argv[i];
+ }
+ argv2[argc++] = "-d";
+ (void)normal_main(argc, argv2);
+ free(argv2);
+ return 0;
+}
+
+static void w32_service_stop(w32_service *s)
+{
+ s->update_scm(s, SERVICE_STOP_PENDING, 0, 60000);
+ terminate = 1;
+ SetEvent(stopEvent);
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ if (!w32_service_create(&g_service)) {
+ fprintf(stderr, "Failed to create a win32 service object\n");
+ return 56;
+ }
+ g_service.name = "freshclam";
+ g_service.display_name = "Clam AntiVirus Update Service";
+ g_service.description = "Automatically keeps the virus scanning database up to \
date, downloading new versions as they become available."; + g_service.main_fn = \
w32_service_main; + g_service.stop = w32_service_stop;
+
+ for (i = 1; i < argc; ++i) {
+ if (strcasecmp(argv[i], "--service") == 0) {
+ w32_services_start();
+ return 0;
+ }
+ }
+ return normal_main((int)argc, argv);
+}
+
+#endif
Index: shared/w32_service.h
===================================================================
--- shared/w32_service.h (revision 0)
+++ shared/w32_service.h (revision 0)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2001-2010 Mark Weaver <mark@npsl.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __W32_SERVICE_H
+#define __W32_SERVICE_H
+
+/**
+ * Win32 service wrapper (adapted from OW32)
+ */
+typedef struct w32_service_s
+{
+ /* Service information */
+ /* At a minimum you need to set the name & display_name */
+ LPCTSTR name;
+ LPCTSTR display_name;
+ LPCTSTR description;
+ DWORD desired_access;
+ DWORD service_type;
+ DWORD start_type;
+ DWORD error_control;
+ LPCTSTR binary_path_name;
+ LPCTSTR load_order_group;
+ LPCTSTR dependencies;
+ LPCTSTR start_name;
+ LPCTSTR password;
+
+ /* Main function for service (can be overridden if desired) */
+ DWORD (*main_fn)(struct w32_service_s *s, DWORD argc, LPTSTR *argv);
+
+ /* Service status handle, in case you want to do something */
+ /* special the UpdateSCM doesn't cover. */
+ SERVICE_STATUS_HANDLE service_status;
+
+ /* Helper to update the SCM */
+ void (*update_scm)(struct w32_service_s *s, DWORD state, DWORD check_point, DWORD \
wait_hint); +
+ /* The service handler, override for custom control notifications */
+ /* Call the base handler (w32_service_handler) to dispatch to stop, pause, etc.. */
+ void (*handler)(struct w32_service_s *s, DWORD fdwControl);
+
+ /* Called when the stop signal is received */
+ void (*stop)(struct w32_service_s *s);
+ /* Called on pause */
+ void (*pause)(struct w32_service_s *s);
+ /* Called on continue */
+ void (*continue_)(struct w32_service_s *s);
+ /* Called on system shutdown */
+ void (*shutdown)(struct w32_service_s *s);
+ /* Called on interrogate, defaults to "running" */
+ void (*interrogate)(struct w32_service_s *s);
+} w32_service;
+
+/** Create a service with default options */
+int w32_service_create(w32_service *s);
+/** Install a service */
+void w32_service_install(w32_service *s);
+/** Uninstall a service */
+void w32_service_uninstall(w32_service *s);
+/** Start all services in this process */
+int w32_services_start();
+
+#endif /* __W32_SERVICE_H */
Property changes on: shared\w32_service.h
___________________________________________________________________
Added: svn:eol-style
+ native
Index: shared/optparser.c
===================================================================
--- shared/optparser.c (revision 1255)
+++ shared/optparser.c (working copy)
@@ -120,6 +120,12 @@
{ NULL, "non-default", 'n', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMCONF, "", \
"" },
{ NULL, "generate-config", 'g', TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMCONF, \
"", "" },
+#ifdef _WIN32
+ /* options for windows services */
+ { NULL, "install", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | \
OPT_CLAMD, "", "" }, + { NULL, "uninstall", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, \
OPT_FRESHCLAM | OPT_CLAMD, "", "" }, +#endif
+
{ NULL, "force-interpreter", 'f', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMBC, \
"Force using the interpreter instead of the JIT", "" },
{ NULL, "trust-bytecode", 't', TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMBC, \
"Trust loaded bytecode (default yes)", ""},
{ NULL, "bytecode-trust-all", 't', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, \
OPT_CLAMSCAN, "Trust loaded bytecode (default: only if signed)", ""},
Index: shared/w32_service.c
===================================================================
--- shared/w32_service.c (revision 0)
+++ shared/w32_service.c (revision 0)
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) 2001-2010 Mark Weaver <mark@npsl.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tchar.h>
+#include "w32_service.h"
+
+static void w32_service_stop(w32_service *s);
+static void w32_service_pause(w32_service *s);
+static void w32_service_shutdown(w32_service *s);
+static void w32_service_continue(w32_service *s);
+static void w32_service_interrogate(w32_service *s);
+static LPTSTR GetErrorMessage(DWORD dwErr);
+static void ReportError(LPCTSTR lpPrefix, DWORD dwErr);
+static void w32_service_handler(w32_service *s, DWORD fdwControl);
+static void w32_service_update_scm(w32_service *s, DWORD state, DWORD check_point, \
DWORD wait_hint); +static DWORD w32_service_main(w32_service *s, DWORD argc, LPTSTR \
*argv); +static void WINAPI w32_api_service_main(DWORD dwArgc, LPTSTR* lpszArgv);
+static void WINAPI w32_api_service_handler(DWORD fdwControl);
+
+extern w32_service g_service;
+
+/**
+ * Make a service object
+ */
+int w32_service_create(w32_service *s)
+{
+ s->name = NULL;
+ s->display_name = NULL;
+ s->description = NULL;
+ s->desired_access = STANDARD_RIGHTS_REQUIRED;
+ s->service_type = SERVICE_WIN32_OWN_PROCESS;
+ s->start_type = SERVICE_AUTO_START;
+ s->error_control = SERVICE_ERROR_NORMAL;
+ s->binary_path_name = NULL;
+ s->load_order_group = NULL;
+ s->dependencies = NULL;
+ s->start_name = NULL;
+ s->password = NULL;
+ s->stop = w32_service_stop;
+ s->pause = w32_service_pause;
+ s->continue_ = w32_service_continue;
+ s->shutdown = w32_service_shutdown;
+ s->interrogate = w32_service_interrogate;
+ s->handler = w32_service_handler;
+ s->main_fn = w32_service_main;
+ s->update_scm = w32_service_update_scm;
+ return 1;
+}
+
+static void w32_service_stop(w32_service *s)
+{
+ s;
+}
+
+static void w32_service_shutdown(w32_service *s)
+{
+ s;
+}
+
+static void w32_service_pause(w32_service *s)
+{
+ s;
+}
+
+static void w32_service_continue(w32_service *s)
+{
+ s;
+}
+
+static void w32_service_interrogate(w32_service *s)
+{
+ s->update_scm(s, SERVICE_RUNNING, 0, 1000);
+}
+
+static DWORD w32_service_main(w32_service *s, DWORD argc, LPTSTR *argv)
+{
+ s;
+ argc;
+ argv;
+ return 0;
+}
+
+static LPTSTR GetErrorMessage(DWORD dwErr)
+{
+ LPVOID lpBuffer;
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, /* \
flags */ + 0, /* source (if hmodule/string) */
+ dwErr, /* message id */
+ 0, /* lang id */
+ (LPTSTR)&lpBuffer, /* output buffer */
+ 0, /* max char count */
+ NULL) == 0) /* args */
+ return NULL;
+ return (LPTSTR)lpBuffer;
+}
+
+static void ReportError(LPCTSTR lpPrefix, DWORD dwErr)
+{
+ LPTSTR msg = GetErrorMessage(dwErr);
+ if (msg == NULL) {
+ _ftprintf(stderr, _T("%s, error code = %d\n"), lpPrefix, dwErr);
+ } else {
+ _ftprintf(stderr, _T("%s: %s\n"), lpPrefix, msg);
+ if (msg) LocalFree(msg);
+ }
+}
+
+void w32_service_install(w32_service *s)
+{
+ TCHAR path[MAX_PATH];
+ SC_HANDLE hSM;
+ SC_HANDLE hService;
+ TCHAR EventLogKeyName[MAX_PATH];
+ HKEY hk;
+ LONG lErr;
+ DWORD dwData;
+ HMODULE hADVAPI;
+
+ hSM = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE);
+ if (hSM == NULL) {
+ ReportError(_T("OpenSCManager"),GetLastError());
+ return;
+ }
+
+ if (!s->binary_path_name)
+ {
+ TCHAR module_path[MAX_PATH];
+ if (!GetModuleFileName(NULL, module_path, MAX_PATH))
+ {
+ ReportError(_T("GetModuleFileName"),GetLastError());
+ CloseServiceHandle(hSM);
+ return;
+ }
+ _sntprintf(path, MAX_PATH, _T("%s --service"), module_path);
+ path[MAX_PATH - 1] = _T('\0');
+ }
+
+ hService = CreateService(
+ hSM, /* service manager */
+ s->name, /* net stop name */
+ s->display_name, /* friendly name */
+ SERVICE_CHANGE_CONFIG|s->desired_access, /* default access to \
interrogate/start/stop */ + s->service_type, /* this process runs only 1 service \
*/ + s->start_type, /* start on boot */
+ s->error_control, /* log error/display message box */
+ s->binary_path_name ? s->binary_path_name : path, /* module path */
+ s->load_order_group, /* load order group */
+ NULL, /* load order tag */
+ s->dependencies, /* dependencies */
+ s->start_name, /* run under local system account */
+ s->password /* no password */
+ );
+ if (!hService) {
+
+ /* If the service already exists, then try and update the settings to
+ the new ones */
+ if (GetLastError() == ERROR_SERVICE_EXISTS)
+ {
+ hService = OpenService(hSM, s->name, SERVICE_ALL_ACCESS);
+ if (!hService)
+ {
+ ReportError(_T("The service exists, but could not be opened to update the \
settings"),GetLastError()); + }
+ else
+ {
+ BOOL bRet;
+ DWORD dwBytesNeeded;
+ LPBYTE pServiceConfig = (LPBYTE)LocalAlloc(LPTR, \
sizeof(QUERY_SERVICE_CONFIG)+1024); +
+ if (!pServiceConfig)
+ {
+ ReportError(_T("Out of memory"),GetLastError());
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hSM);
+ return;
+ }
+ dwBytesNeeded = 0;
+ bRet = QueryServiceConfig(hService, (LPQUERY_SERVICE_CONFIG)pServiceConfig,
+ sizeof(QUERY_SERVICE_CONFIG), &dwBytesNeeded);
+ if (!bRet)
+ {
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ ReportError(_T("QueryServiceConfig failed"),GetLastError());
+ else
+ {
+ LocalFree(pServiceConfig);
+ pServiceConfig = (LPBYTE)LocalAlloc(LPTR, dwBytesNeeded);
+ if (!pServiceConfig)
+ {
+ ReportError(_T("Out of memory"),GetLastError());
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hSM);
+ return;
+ }
+ }
+ bRet = QueryServiceConfig(hService, (LPQUERY_SERVICE_CONFIG)pServiceConfig,
+ dwBytesNeeded, &dwBytesNeeded);
+ }
+
+ if (bRet)
+ {
+ LPQUERY_SERVICE_CONFIG pTheConfig = (LPQUERY_SERVICE_CONFIG)pServiceConfig;
+
+ if (!ChangeServiceConfig(hService, s->service_type, pTheConfig->dwStartType, \
s->error_control, + s->binary_path_name ? s->binary_path_name : path, \
s->load_order_group, NULL, + s->dependencies, s->start_name, s->password, \
s->display_name)) + {
+ ReportError(_T("The service exists, but the configuration could not be \
updated"),GetLastError()); + }
+ }
+ if (pServiceConfig)
+ LocalFree(pServiceConfig);
+ }
+ }
+ else
+ {
+ ReportError(_T("CreateService failed"),GetLastError());
+ }
+ }
+
+ /* Set the long description if possible (NT5+) */
+ hADVAPI = LoadLibrary(_T("advapi32.dll"));
+ if (hADVAPI)
+ {
+ typedef BOOL (WINAPI *ChangeServiceConfig2_fn)(SC_HANDLE hService, DWORD \
dwInfoLevel, LPVOID lpInfo); + ChangeServiceConfig2_fn pChangeServiceConfig2;
+ SERVICE_DESCRIPTION desc;
+
+
+ pChangeServiceConfig2 = (ChangeServiceConfig2_fn)GetProcAddress(hADVAPI,
+#ifdef _UNICODE
+ "ChangeServiceConfig2W"
+#else
+ "ChangeServiceConfig2A"
+#endif
+ );
+
+ if (pChangeServiceConfig2)
+ {
+ desc.lpDescription = _tcsdup(s->description ? s->description : "");
+ if (desc.lpDescription == NULL)
+ {
+ ReportError(_T("Couldn't copy description string"), ERROR_OUTOFMEMORY);
+ /* continue anyway */
+ }
+ else
+ {
+ if (!pChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &desc))
+ {
+ ReportError(_T("ChangeServiceConfig2 failed, ignoring"), GetLastError());
+ }
+ free(desc.lpDescription);
+ }
+ }
+ FreeLibrary(hADVAPI);
+ }
+
+ CloseServiceHandle(hSM);
+ CloseServiceHandle(hService);
+
+ _sntprintf(EventLogKeyName, MAX_PATH, \
_T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"), s->name); \
+ EventLogKeyName[MAX_PATH - 1] = _T('\0'); +
+ /* register the app as an event source */
+ if ((lErr=RegCreateKey(HKEY_LOCAL_MACHINE,
+ EventLogKeyName,
+ &hk)) != ERROR_SUCCESS) {
+ ReportError(_T("RegCreateKey for event source"),lErr);
+ return;
+ }
+
+ /* set the name of the message file */
+ if ((lErr=RegSetValueEx(hk, _T("EventMessageFile"), 0, REG_EXPAND_SZ,
+ (const BYTE *)(s->binary_path_name ? s->binary_path_name : path),
+ (DWORD)((_tcslen(path)+1)*sizeof(TCHAR)))) != ERROR_SUCCESS)
+ {
+ ReportError(_T("RegSetValueEx for EventMessageFile"),lErr);
+ RegCloseKey(hk);
+ return;
+ }
+
+ /* set the supported event types in the TypesSupported value */
+ dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
+ if ((lErr=RegSetValueEx(hk, _T("TypesSupported"), 0, REG_DWORD, (LPBYTE)&dwData, \
sizeof(DWORD))) != + ERROR_SUCCESS) {
+ ReportError(_T("RegSetValueEx for TypesSupported"),lErr);
+ RegCloseKey(hk);
+ return;
+ }
+ RegCloseKey(hk);
+}
+
+void w32_service_uninstall(w32_service *s)
+{
+ SC_HANDLE hSM;
+ SC_HANDLE hService;
+ LONG lErr;
+ TCHAR EventLogKeyName[MAX_PATH];
+
+ hSM = OpenSCManager(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
+ if (hSM == NULL) {
+ ReportError(_T("OpenSCManager for deletion"),GetLastError());
+ return;
+ }
+ hService = OpenService(hSM, s->name, STANDARD_RIGHTS_REQUIRED);
+ if (hService == NULL) {
+ ReportError(_T("OpenService for deletion"),GetLastError());
+ CloseServiceHandle(hSM);
+ return;
+ }
+ if (!DeleteService(hService)) {
+ ReportError(_T("DeleteService"),GetLastError());
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hSM);
+ return;
+ }
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hSM);
+
+ /* work out the name of the event log key */
+ _sntprintf(EventLogKeyName, MAX_PATH, \
_T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"), s->name); \
+ EventLogKeyName[MAX_PATH - 1] = _T('\0'); +
+ /* delete registry key for event source */
+ if ((lErr=RegDeleteKey(HKEY_LOCAL_MACHINE, EventLogKeyName)) != ERROR_SUCCESS) {
+ ReportError(_T("RegDeleteKey for event viewer source"),lErr);
+ return;
+ }
+}
+
+int w32_services_start()
+{
+ int ret = 0;
+ SERVICE_TABLE_ENTRY dispatchTable[2] = {0};
+
+ /* Check the service is registered */
+ if (!g_service.name)
+ goto err;
+
+ /* Make a dispatch table. Need to copy service names (broken API?) */
+ dispatchTable[0].lpServiceName = _tcsdup(g_service.name);
+ if (dispatchTable[0].lpServiceName == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ goto err;
+ }
+ dispatchTable[0].lpServiceProc = w32_api_service_main;
+
+ dispatchTable[1].lpServiceName = NULL;
+ dispatchTable[1].lpServiceProc = NULL;
+
+ /* Kick them off */
+ if (StartServiceCtrlDispatcher(dispatchTable))
+ ret = 1;
+
+err:
+ free(dispatchTable[0].lpServiceName);
+
+ if (!ret) {
+ ReportError(_T("Starting services failed"), GetLastError());
+ }
+ return ret;
+}
+
+/*
+ * Tell the Service Control Manager the state of the service
+ */
+static void w32_service_update_scm(w32_service *s, DWORD state, DWORD check_point, \
DWORD wait_hint) +{
+ SERVICE_STATUS ss;
+
+ if (s->service_status)
+ {
+ memset(&ss, 0, sizeof(SERVICE_STATUS));
+ ss.dwServiceType = s->service_type;
+ ss.dwCurrentState = state;
+ ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ ss.dwCheckPoint = check_point;
+ ss.dwServiceSpecificExitCode = 0;
+ ss.dwWin32ExitCode = NO_ERROR;
+ ss.dwWaitHint = wait_hint;
+
+ if (!SetServiceStatus(s->service_status, &ss))
+ {
+ ss.dwCurrentState = SERVICE_STOPPED;
+ SetServiceStatus(s->service_status, &ss);
+ }
+ }
+}
+
+static void w32_service_handler(w32_service *s, DWORD fdwControl)
+{
+ switch (fdwControl) {
+ case SERVICE_CONTROL_STOP:
+ s->stop(s);
+ break;
+
+ case SERVICE_CONTROL_PAUSE:
+ s->pause(s);
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ s->continue_(s);
+ break;
+
+ case SERVICE_CONTROL_SHUTDOWN:
+ s->shutdown(s);
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ s->interrogate(s);
+ break;
+ }
+}
+
+
+/* Win32 callbacks */
+static void WINAPI w32_api_service_handler(DWORD fdwControl)
+{
+ w32_service *s = &g_service;
+ s->handler(s, fdwControl);
+}
+
+static void WINAPI w32_api_service_main(DWORD argc, LPTSTR* argv)
+{
+ w32_service *s = &g_service;
+
+ /* Register the callback */
+ s->service_status = RegisterServiceCtrlHandler(s->name, w32_api_service_handler);
+
+ /* Initialise the status object */
+ if (s->service_status)
+ {
+ SERVICE_STATUS ss;
+
+ memset(&ss, 0, sizeof(SERVICE_STATUS));
+ ss.dwServiceType = s->service_type;
+ ss.dwCurrentState = SERVICE_START_PENDING;
+ ss.dwControlsAccepted = 0;
+ ss.dwCheckPoint = 0;
+ ss.dwServiceSpecificExitCode = 0;
+ ss.dwWin32ExitCode = 0;
+ ss.dwWaitHint = 60000;
+
+ (void)SetServiceStatus(s->service_status, &ss);
+ ss.dwWin32ExitCode = s->main_fn(s, argc, argv);
+ ss.dwWaitHint = 0;
+ ss.dwCurrentState = SERVICE_STOPPED;
+ (void)SetServiceStatus(s->service_status, &ss);
+ }
+}
Property changes on: shared\w32_service.c
___________________________________________________________________
Added: svn:eol-style
+ native
Index: clamd/server-th.c
===================================================================
--- clamd/server-th.c (revision 1255)
+++ clamd/server-th.c (working copy)
@@ -692,10 +692,10 @@
struct sigaction sigact;
sigset_t sigset;
struct rlimit rlim;
+ char buff[BUFFSIZE + 1];
#endif
mode_t old_umask;
const struct optstruct *opt;
- char buff[BUFFSIZE + 1];
pid_t mainpid;
int idletimeout;
unsigned long long val;
@@ -1064,10 +1064,7 @@
cl_engine_free(engine);
return 1;
}
-#ifdef _WIN32
- event_wake_accept = CreateEvent(NULL, TRUE, FALSE, NULL);
- event_wake_recv = CreateEvent(NULL, TRUE, FALSE, NULL);
-#else
+#ifndef _WIN32
if (pipe(acceptdata.syncpipe_wake_recv) == -1 ||
(pipe(acceptdata.syncpipe_wake_accept) == -1)) {
@@ -1340,10 +1337,7 @@
pthread_join(accept_th, NULL);
fds_free(fds);
-#ifdef _WIN32
- CloseHandle(event_wake_accept);
- CloseHandle(event_wake_recv);
-#else
+#ifndef _WIN32
close(acceptdata.syncpipe_wake_accept[1]);
close(acceptdata.syncpipe_wake_recv[1]);
#endif
Index: clamd/clamd.c
===================================================================
--- clamd/clamd.c (revision 1255)
+++ clamd/clamd.c (working copy)
@@ -68,6 +68,11 @@
#include "others.h"
#include "shared.h"
+#ifdef _WIN32
+#include "shared/w32_service.h"
+w32_service g_service;
+#endif
+
short debug_mode = 0, logok = 0;
short foreground = 0;
@@ -82,6 +87,10 @@
printf(" --version -V Show version number.\n");
printf(" --debug Enable debug mode.\n");
printf(" --config-file=FILE -c FILE Read configuration from \
FILE.\n\n"); +#ifdef _WIN32
+ printf(" --install Install windows service.\n");
+ printf(" --uninstall Uninstall windows service.\n");
+#endif
}
static struct optstruct *opts;
@@ -100,7 +109,11 @@
}
}
+#ifdef _WIN32
+int normal_main(int argc, char **argv)
+#else
int main(int argc, char **argv)
+#endif
{
static struct cl_engine *engine = NULL;
const struct optstruct *opt;
@@ -140,6 +153,19 @@
return 0;
}
+#ifdef _WIN32
+ if (optget(opts, "install")->enabled) {
+ w32_service_install(&g_service);
+ optfree(opts);
+ return 0;
+ }
+ if (optget(opts, "uninstall")->enabled) {
+ w32_service_uninstall(&g_service);
+ optfree(opts);
+ return 0;
+ }
+#endif
+
if(optget(opts, "debug")->enabled) {
#if defined(C_LINUX)
/* njh@bandsman.co.uk: create a dump if needed */
@@ -516,6 +542,7 @@
nlsockets++;
}
+#endif
/* fork into background */
if(!optget(opts, "Foreground")->enabled) {
@@ -527,11 +554,15 @@
#endif
gengine = engine;
atexit(free_engine);
+#ifndef _WIN32
if(daemonize() == -1) {
logg("!daemonize() failed\n");
ret = 1;
break;
}
+#else
+ g_service.update_scm(&g_service, SERVICE_RUNNING, 0, 1000);
+#endif
gengine = NULL;
#ifdef C_BSD
for(ret=0;ret<nlsockets;ret++) {
@@ -544,7 +575,6 @@
} else
foreground = 1;
-#endif
ret = recvloop_th(lsockets, nlsockets, engine, dboptions, opts);
@@ -571,3 +601,73 @@
return ret;
}
+
+#ifdef _WIN32
+
+extern void *event_wake_recv;
+extern void *event_wake_accept;
+
+BOOL WINAPI CtrlHandler(DWORD dwCtrlType)
+{
+ switch (dwCtrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ progexit = 1;
+ if (!SetEvent(event_wake_recv)) {
+ logg("$Failed to wake recv thread with %lu\n", GetLastError());
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int w32_service_main(w32_service *s, DWORD argc, LPTSTR *argv)
+{
+ return normal_main(argc, argv);
+}
+
+static void w32_service_stop(w32_service *s)
+{
+ s->update_scm(s, SERVICE_STOP_PENDING, 0, 60000);
+ progexit = 1;
+ SetEvent(event_wake_recv);
+}
+
+int main(int argc, char **argv)
+{
+ int i, ret;
+
+ event_wake_recv = CreateEvent(NULL, TRUE, FALSE, NULL);
+ event_wake_accept = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!event_wake_recv || !event_wake_accept) {
+ if (event_wake_accept) CloseHandle(event_wake_accept);
+ if (event_wake_recv) CloseHandle(event_wake_recv);
+ fprintf(stderr, "Failed to create an event with %lu\n", GetLastError());
+ return 56;
+ }
+ SetConsoleCtrlHandler(CtrlHandler, TRUE);
+
+ if (!w32_service_create(&g_service)) {
+ fprintf(stderr, "Failed to create a win32 service object\n");
+ return 56;
+ }
+ g_service.name = "clamd";
+ g_service.display_name = "Clam AntiVirus Scanner Service";
+ g_service.description = "Provides virus scanning services for the local \
machine."; + g_service.main_fn = w32_service_main;
+ g_service.stop = w32_service_stop;
+
+ for (i = 1; i < argc; ++i) {
+ if (strcasecmp(argv[i], "--service") == 0) {
+ w32_services_start();
+ return 0;
+ }
+ }
+
+ ret = normal_main((int)argc, argv);
+ CloseHandle(event_wake_recv);
+ CloseHandle(event_wake_accept);
+ return ret;
+}
+#endif
Property changes on: win32
___________________________________________________________________
Added: svn:ignore
+ build
Index: win32/freshclam.vcproj
===================================================================
--- win32/freshclam.vcproj (revision 1255)
+++ win32/freshclam.vcproj (working copy)
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
- Keyword="Win32Proj"
+ ProjectType="Visual C++"
+ Version="9.00"
Name="freshclam"
ProjectGUID="{CEA52DD8-0418-42AD-B640-F33CC7C600CE}"
- ProjectType="Visual C++"
RootNamespace="freshclam"
+ Keyword="Win32Proj"
TargetFrameworkVersion="196613"
- Version="9,00"
>
<Platforms>
<Platform
@@ -17,11 +17,11 @@
</ToolFiles>
<Configurations>
<Configuration
- CharacterSet="2"
- ConfigurationType="1"
- IntermediateDirectory="$(SolutionDir)build\$(ProjectName)\$(ConfigurationName)"
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)build\$(ProjectName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -39,18 +39,18 @@
Name="VCMIDLTool"
/>
<Tool
- AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)..\l \
ibclamav";"$(SolutionDir)compat";"$(SolutionDir)3rdparty\zlib" \
;;"$(SolutionDir)3rdparty\pthreads";"$(SolutionDir)3rdparty\bzip2";"$(SolutionDir)..""
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- DisableSpecificWarnings="4996;4244;4018;4090;4333;4101;4146;4102"
- MinimalRebuild="true"
Name="VCCLCompilerTool"
Optimization="0"
+ AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)..\l \
ibclamav";"$(SolutionDir)compat";"$(SolutionDir)3rdparty\zlib" \
;;"$(SolutionDir)3rdparty\pthreads";"$(SolutionDir)3rdparty\bzip2";"$(SolutionDir)..""
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_BIND_TO_CURRENT_VCLIBS_VERSION=1"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ DisableSpecificWarnings="4996;4244;4018;4090;4333;4101;4146;4102"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -62,10 +62,10 @@
Name="VCPreLinkEventTool"
/>
<Tool
+ Name="VCLinkerTool"
AdditionalDependencies="dnsapi.lib"
+ LinkIncremental="1"
GenerateDebugInformation="true"
- LinkIncremental="1"
- Name="VCLinkerTool"
SubSystem="1"
TargetMachine="1"
/>
@@ -92,11 +92,11 @@
/>
</Configuration>
<Configuration
- CharacterSet="2"
- ConfigurationType="1"
- IntermediateDirectory="$(SolutionDir)build\$(ProjectName)\$(ConfigurationName)"
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)build\$(ProjectName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
@@ -115,19 +115,19 @@
Name="VCMIDLTool"
/>
<Tool
- AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)..\l \
ibclamav";"$(SolutionDir)compat";"$(SolutionDir)3rdparty\zlib" \
;;"$(SolutionDir)3rdparty\pthreads";"$(SolutionDir)3rdparty\bzip2";"$(SolutionDir)..""
- BufferSecurityCheck="false"
- CompileAs="1"
- DebugInformationFormat="3"
- DisableSpecificWarnings="4996;4244;4018;4090;4333;4101;4146;4102"
- EnableFunctionLevelLinking="true"
- EnableIntrinsicFunctions="true"
Name="VCCLCompilerTool"
Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)..\l \
ibclamav";"$(SolutionDir)compat";"$(SolutionDir)3rdparty\zlib" \
;;"$(SolutionDir)3rdparty\pthreads";"$(SolutionDir)3rdparty\bzip2";"$(SolutionDir)..""
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_BIND_TO_CURRENT_VCLIBS_VERSION=1"
RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ DisableSpecificWarnings="4996;4244;4018;4090;4333;4101;4146;4102"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -139,13 +139,13 @@
Name="VCPreLinkEventTool"
/>
<Tool
+ Name="VCLinkerTool"
AdditionalDependencies="dnsapi.lib"
- EnableCOMDATFolding="2"
+ LinkIncremental="1"
GenerateDebugInformation="true"
- LinkIncremental="1"
- Name="VCLinkerTool"
+ SubSystem="1"
OptimizeReferences="2"
- SubSystem="1"
+ EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
@@ -175,8 +175,8 @@
</References>
<Files>
<Filter
+ Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- Name="Source Files"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
@@ -226,6 +226,10 @@
RelativePath="..\shared\tar.c"
>
</File>
+ <File
+ RelativePath="..\shared\w32_service.c"
+ >
+ </File>
</Filter>
<Filter
Name="compat"
@@ -241,14 +245,14 @@
</Filter>
</Filter>
<Filter
+ Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
- Name="Header Files"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
+ Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
- Name="Resource Files"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
Index: win32/platform.h
===================================================================
--- win32/platform.h (revision 1255)
+++ win32/platform.h (working copy)
@@ -53,7 +53,7 @@
#define closesocket w32_closesocket
#define getservbyname w32_getservbyname
#define getaddrinfo w32_getaddrinfo
-#define gai_strerror w32_strerror
+//#define gai_strerror w32_strerror
#define freeaddrinfo w32_freeaddrinfo
#define inet_ntop w32_inet_ntop
#define gethostbyname w32_gethostbyname
Index: win32/clamd.vcproj
===================================================================
--- win32/clamd.vcproj (revision 1255)
+++ win32/clamd.vcproj (working copy)
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
- Keyword="Win32Proj"
+ ProjectType="Visual C++"
+ Version="9.00"
Name="clamd"
ProjectGUID="{B3CA73CF-E71E-42F3-95DE-43797A86C798}"
- ProjectType="Visual C++"
RootNamespace="clamd"
+ Keyword="Win32Proj"
TargetFrameworkVersion="196613"
- Version="9,00"
>
<Platforms>
<Platform
@@ -17,11 +17,11 @@
</ToolFiles>
<Configurations>
<Configuration
- CharacterSet="2"
- ConfigurationType="1"
- IntermediateDirectory="$(SolutionDir)build\$(ProjectName)\$(ConfigurationName)"
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)build\$(ProjectName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
@@ -39,18 +39,18 @@
Name="VCMIDLTool"
/>
<Tool
- AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)..\l \
ibclamav";"$(SolutionDir)compat";"$(SolutionDir)3rdparty\zlib" \
;;"$(SolutionDir)3rdparty\pthreads";"$(SolutionDir)3rdparty\bzip2";"$(SolutionDir)..""
- BasicRuntimeChecks="3"
- CompileAs="1"
- DebugInformationFormat="3"
- DisableSpecificWarnings="4996;4244;4090;4018"
- MinimalRebuild="true"
Name="VCCLCompilerTool"
Optimization="0"
+ AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)..\l \
ibclamav";"$(SolutionDir)compat";"$(SolutionDir)3rdparty\zlib" \
;;"$(SolutionDir)3rdparty\pthreads";"$(SolutionDir)3rdparty\bzip2";"$(SolutionDir)..""
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_BIND_TO_CURRENT_VCLIBS_VERSION=1"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ DisableSpecificWarnings="4996;4244;4090;4018"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -62,9 +62,9 @@
Name="VCPreLinkEventTool"
/>
<Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
GenerateDebugInformation="true"
- LinkIncremental="1"
- Name="VCLinkerTool"
SubSystem="1"
TargetMachine="1"
/>
@@ -91,11 +91,11 @@
/>
</Configuration>
<Configuration
- CharacterSet="2"
- ConfigurationType="1"
- IntermediateDirectory="$(SolutionDir)build\$(ProjectName)\$(ConfigurationName)"
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)build\$(ProjectName)\$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
@@ -114,18 +114,18 @@
Name="VCMIDLTool"
/>
<Tool
- AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)..\l \
ibclamav";"$(SolutionDir)compat";"$(SolutionDir)3rdparty\zlib" \
;;"$(SolutionDir)3rdparty\pthreads";"$(SolutionDir)3rdparty\bzip2";"$(SolutionDir)..""
- CompileAs="1"
- DebugInformationFormat="3"
- DisableSpecificWarnings="4996;4244;4090;4018"
- EnableFunctionLevelLinking="true"
- EnableIntrinsicFunctions="true"
Name="VCCLCompilerTool"
Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)..\l \
ibclamav";"$(SolutionDir)compat";"$(SolutionDir)3rdparty\zlib" \
;;"$(SolutionDir)3rdparty\pthreads";"$(SolutionDir)3rdparty\bzip2";"$(SolutionDir)..""
PreprocessorDefinitions="WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_BIND_TO_CURRENT_VCLIBS_VERSION=1"
RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ DisableSpecificWarnings="4996;4244;4090;4018"
/>
<Tool
Name="VCManagedResourceCompilerTool"
@@ -137,12 +137,12 @@
Name="VCPreLinkEventTool"
/>
<Tool
- EnableCOMDATFolding="2"
+ Name="VCLinkerTool"
+ LinkIncremental="1"
GenerateDebugInformation="true"
- LinkIncremental="1"
- Name="VCLinkerTool"
+ SubSystem="1"
OptimizeReferences="2"
- SubSystem="1"
+ EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
@@ -172,8 +172,8 @@
</References>
<Files>
<Filter
+ Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
- Name="Source Files"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
@@ -219,17 +219,21 @@
RelativePath="..\shared\output.c"
>
</File>
+ <File
+ RelativePath="..\shared\w32_service.c"
+ >
+ </File>
</Filter>
</Filter>
<Filter
+ Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
- Name="Header Files"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
+ Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
- Name="Resource Files"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
_______________________________________________
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic