Skip to content

Commit 9594c33

Browse files
committed
Run as service
1 parent 531a5b3 commit 9594c33

File tree

2 files changed

+154
-1
lines changed

2 files changed

+154
-1
lines changed

Makefile.am

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ lib_LTLIBRARIES = \
113113
if BUILD_WIN32
114114
# TODO: Build all executables on Windows as well.
115115
sbin_PROGRAMS = \
116-
collectd
116+
collectd \
117+
collectd_svc
117118

118119
bin_PROGRAMS =
119120
else
@@ -286,6 +287,16 @@ collectd_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
286287
collectd_LDADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
287288
endif
288289

290+
if BUILD_WIN32
291+
collectd_svc_SOURCES = \
292+
src/daemon/collectd_svc.c \
293+
src/daemon/collectd.c \
294+
src/daemon/collectd.h
295+
collectd_svc_CFLAGS = $(AM_CFLAGS)
296+
collectd_svc_CPPFLAGS = $(AM_CPPFLAGS)
297+
collectd_svc_LDFLAGS = -export-dynamic
298+
collectd_svc_LDADD = libcollectd.la -lkernel32 -ladvapi32
299+
endif
289300

290301
collectdmon_SOURCES = src/collectdmon.c
291302

src/daemon/collectd_svc.c

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#include "collectd.h"
2+
#include <windows.h>
3+
#include <tchar.h>
4+
5+
#undef __CRT__NO_INLINE
6+
#include <strsafe.h>
7+
#define __CRT__NO_INLINE
8+
9+
#define SVC_ERROR 1
10+
11+
SERVICE_STATUS gSvcStatus;
12+
SERVICE_STATUS_HANDLE gSvcStatusHandle;
13+
14+
void WINAPI SvcCtrlHandler(DWORD);
15+
void WINAPI SvcMain(DWORD, LPTSTR *);
16+
17+
void ReportSvcStatus(DWORD, DWORD, DWORD);
18+
void SvcReportEvent(LPTSTR);
19+
20+
void __cdecl _tmain(int argc, TCHAR *argv[]) {
21+
SERVICE_TABLE_ENTRY DispatchTable[] = {
22+
{PACKAGE_NAME, (LPSERVICE_MAIN_FUNCTION)SvcMain}, {NULL, NULL}};
23+
24+
if (!StartServiceCtrlDispatcher(DispatchTable)) {
25+
SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
26+
}
27+
}
28+
29+
int init(int argc, char **argv) {
30+
WORD wVersionRequested;
31+
WSADATA wsaData;
32+
int err;
33+
wVersionRequested = MAKEWORD(2, 2);
34+
35+
err = WSAStartup(wVersionRequested, &wsaData);
36+
if (err != 0) {
37+
printf("WSAStartup failed with error: %d\n", err);
38+
SvcReportEvent(TEXT("WSAStartup"));
39+
return 1;
40+
}
41+
42+
struct cmdline_config config = init_config(argc, argv);
43+
return run_loop(config.test_readall);
44+
}
45+
46+
void WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv) {
47+
gSvcStatusHandle = RegisterServiceCtrlHandler(PACKAGE_NAME, SvcCtrlHandler);
48+
49+
if (!gSvcStatusHandle) {
50+
SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
51+
return;
52+
}
53+
54+
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
55+
gSvcStatus.dwServiceSpecificExitCode = 0;
56+
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
57+
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
58+
int err = init((int)dwArgc, (char**)lpszArgv);
59+
ReportSvcStatus(SERVICE_STOPPED, err, 0);
60+
return;
61+
}
62+
63+
/**
64+
* Sets the current service status and reports it to the SCM.
65+
* dwCurrentState - The current state (see SERVICE_STATUS)
66+
* dwWin32ExitCode - The system error code
67+
* dwWaitHint - Estimated time for pending operation,
68+
* in milliseconds
69+
*/
70+
void ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
71+
DWORD dwWaitHint) {
72+
static DWORD dwCheckPoint = 1;
73+
74+
gSvcStatus.dwCurrentState = dwCurrentState;
75+
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
76+
gSvcStatus.dwWaitHint = dwWaitHint;
77+
78+
if (dwCurrentState == SERVICE_START_PENDING)
79+
gSvcStatus.dwControlsAccepted = 0;
80+
else
81+
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
82+
83+
if ((dwCurrentState == SERVICE_RUNNING) ||
84+
(dwCurrentState == SERVICE_STOPPED))
85+
gSvcStatus.dwCheckPoint = 0;
86+
else
87+
gSvcStatus.dwCheckPoint = dwCheckPoint++;
88+
89+
SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
90+
}
91+
92+
/**
93+
* Called by SCM whenever a control code is sent to the service
94+
* using the ControlService function.
95+
* dwCtrl - control code
96+
*/
97+
void WINAPI SvcCtrlHandler(DWORD dwCtrl) {
98+
switch (dwCtrl) {
99+
case SERVICE_CONTROL_STOP:
100+
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
101+
stop_collectd();
102+
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
103+
return;
104+
case SERVICE_CONTROL_INTERROGATE:
105+
break;
106+
default:
107+
break;
108+
}
109+
}
110+
111+
/**
112+
* Logs messages to the event log. The service must
113+
* have an entry in the Application event log.
114+
* szFunction - name of function that failed
115+
*/
116+
VOID SvcReportEvent(LPTSTR szFunction) {
117+
HANDLE hEventSource;
118+
LPCTSTR lpszStrings[2];
119+
TCHAR Buffer[80];
120+
121+
hEventSource = RegisterEventSource(NULL, PACKAGE_NAME);
122+
123+
if (NULL != hEventSource) {
124+
StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction,
125+
GetLastError());
126+
127+
lpszStrings[0] = PACKAGE_NAME;
128+
lpszStrings[1] = Buffer;
129+
130+
ReportEvent(hEventSource, // event log handle
131+
EVENTLOG_ERROR_TYPE, // event type
132+
0, // event category
133+
SVC_ERROR, // event identifier
134+
NULL, // no security identifier
135+
2, // size of lpszStrings array
136+
0, // no binary data
137+
lpszStrings, // array of strings
138+
NULL); // no binary data
139+
140+
DeregisterEventSource(hEventSource);
141+
}
142+
}

0 commit comments

Comments
 (0)