summaryrefslogtreecommitdiff
path: root/src/win32ctl/services/pcp-services.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/win32ctl/services/pcp-services.c')
-rw-r--r--src/win32ctl/services/pcp-services.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/win32ctl/services/pcp-services.c b/src/win32ctl/services/pcp-services.c
new file mode 100644
index 0000000..7164fde
--- /dev/null
+++ b/src/win32ctl/services/pcp-services.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2008-2009 Aconex. All Rights Reserved.
+ *
+ * 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.
+ */
+#include "pmapi.h"
+#include "impl.h"
+#include <wtypes.h>
+#include <winnt.h>
+#include <winsvc.h>
+#include <winuser.h>
+
+typedef enum {
+ PCP_SERVICE_COLLECTORS = 0,
+ PCP_SERVICE_INFERENCE = 1,
+ PCP_SERVICE_PROXY = 2,
+ NUM_SERVICES
+} PCPSERVICE;
+
+VOID WINAPI pcpCollectorsSetup(DWORD, LPTSTR *);
+VOID WINAPI pcpInferenceSetup(DWORD, LPTSTR *);
+VOID WINAPI pcpProxySetup(DWORD, LPTSTR *);
+DWORD WINAPI pcpCollectorsDispatch(DWORD, DWORD, LPVOID, LPVOID);
+DWORD WINAPI pcpInferenceDispatch(DWORD, DWORD, LPVOID, LPVOID);
+DWORD WINAPI pcpProxyDispatch(DWORD, DWORD, LPVOID, LPVOID);
+
+typedef VOID WINAPI (*SETUPFUNC)(DWORD, LPTSTR *);
+typedef DWORD WINAPI (*DISPATCHFUNC)(DWORD, DWORD, LPVOID, LPVOID);
+
+struct {
+ TCHAR * name;
+ TCHAR * script;
+ HANDLE stopEvent;
+ SERVICE_STATUS status;
+ SERVICE_STATUS_HANDLE statusHandle;
+ SETUPFUNC setup;
+ DISPATCHFUNC dispatch;
+} services[3] = {
+ { .name = "PCP Collector Processes",
+ .script = "pcp",
+ .setup = pcpCollectorsSetup,
+ .dispatch = pcpCollectorsDispatch,
+ },
+ { .name = "PCP Inference Engines",
+ .script = "pmie",
+ .setup = pcpInferenceSetup,
+ .dispatch = pcpInferenceDispatch,
+ },
+ { .name = "PCP Collector Proxy",
+ .script = "pmproxy",
+ .setup = pcpProxySetup,
+ .dispatch = pcpProxyDispatch,
+ },
+};
+
+static char pcpdir[MAXPATHLEN+16]; /* PCP_DIR environment variable */
+static char pcpconf[MAXPATHLEN+16]; /* PCP_CONF string for putenv */
+static char pcpdirenv[MAXPATHLEN+16]; /* PCP_DIR string for putenv */
+
+int
+pcpScript(const char *name, const char *action)
+{
+ char s[MAXPATHLEN];
+ snprintf(s, sizeof(s), "%s\\bin\\sh.exe /etc/%s %s", pcpdir, name, action);
+ return system(s);
+}
+
+VOID
+pcpSetServiceState(PCPSERVICE s, DWORD state, DWORD code, DWORD waitHint)
+{
+ services[s].status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
+ services[s].status.dwCurrentState = state;
+ services[s].status.dwWin32ExitCode = code;
+ services[s].status.dwWaitHint = waitHint;
+
+ if (state == SERVICE_START_PENDING)
+ services[s].status.dwControlsAccepted = 0;
+ else
+ services[s].status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+
+ if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED))
+ services[s].status.dwCheckPoint = 0;
+ else
+ services[s].status.dwCheckPoint++;
+
+ /* Report the status of the service to the SCM. */
+ SetServiceStatus(services[s].statusHandle, &services[s].status);
+}
+
+VOID
+pcpServiceMain(DWORD argc, LPTSTR *argv, PCPSERVICE s)
+{
+ char *default_basedirs[] = { "C:\\Glider", "C:\\MSYS" };
+ char *default_service = "pcp";
+ char *service = NULL, *basedir = NULL;
+ int i;
+
+ if (argc > 1) { /* first argument is service name */
+ service = argv[1];
+ for (i = 0; i < NUM_SERVICES; i++)
+ if (strcmp(service, services[i].name) == 0)
+ break;
+ if (i == NUM_SERVICES)
+ return; /* unknown service requested - bail out */
+ }
+ if (service == NULL)
+ service = default_service;
+
+ if (argc > 2) /* second argument is PCP_DIR */
+ basedir = argv[2];
+ else if ((basedir = getenv("PCP_DIR")) == NULL) {
+ for (i = 0; i < 3; i++)
+ if (access(default_basedirs[i], R_OK) == 0) {
+ basedir = default_basedirs[i];
+ break;
+ }
+ }
+ if (!basedir || access(basedir, R_OK) != 0)
+ return; /* stuffed up if we have no PCP_DIR - bail out */
+
+ snprintf(pcpdir, sizeof(pcpdir), "%s", basedir);
+ snprintf(pcpconf, sizeof(pcpconf), "PCP_CONF=%s\\etc\\pcp.conf", pcpdir);
+ snprintf(pcpdirenv, sizeof(pcpdirenv), "PCP_DIR=%s", pcpdir);
+ putenv(pcpconf);
+ putenv(pcpdirenv);
+
+ services[s].statusHandle = RegisterServiceCtrlHandlerEx(
+ services[s].name, services[s].dispatch, NULL);
+ if (!services[s].statusHandle)
+ return;
+
+ pcpSetServiceState(s, SERVICE_START_PENDING, NO_ERROR, 0);
+
+ /*
+ * Create an event. The control handler function signals
+ * this event when it receives the stop control code.
+ */
+ services[s].stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (!services[s].stopEvent) {
+ pcpSetServiceState(s, SERVICE_STOPPED, NO_ERROR, 0);
+ return;
+ }
+
+ /*
+ * Go, go, go... run the start script for this service.
+ */
+ if (pcpScript(services[s].script, "start") != 0) {
+ pcpSetServiceState(s, SERVICE_STOPPED, NO_ERROR, 0);
+ return;
+ }
+
+ pcpSetServiceState(s, SERVICE_RUNNING, NO_ERROR, 0);
+
+ /* Check whether to stop the service. */
+ WaitForSingleObject(services[s].stopEvent, INFINITE);
+
+ /* ServiceState already set to SERVICE_STOP_PENDING */
+ pcpScript(services[s].script, "stop");
+
+ pcpSetServiceState(s, SERVICE_STOPPED, NO_ERROR, 0);
+}
+
+VOID WINAPI
+pcpCollectorsSetup(DWORD argc, LPTSTR *argv)
+{
+ pcpServiceMain(argc, argv, PCP_SERVICE_COLLECTORS);
+}
+
+VOID WINAPI
+pcpInferenceSetup(DWORD argc, LPTSTR *argv)
+{
+ pcpServiceMain(argc, argv, PCP_SERVICE_INFERENCE);
+}
+
+VOID WINAPI
+pcpProxySetup(DWORD argc, LPTSTR *argv)
+{
+ pcpServiceMain(argc, argv, PCP_SERVICE_PROXY);
+}
+
+DWORD
+pcpServiceHandler(DWORD dwControl, DWORD dwEventType,
+ LPVOID lpEventData, LPVOID lpContext, PCPSERVICE s)
+{
+ switch(dwControl) {
+ case SERVICE_CONTROL_STOP:
+ services[s].status.dwCurrentState = SERVICE_STOP_PENDING;
+ SetServiceStatus(services[s].statusHandle, &services[s].status);
+ SetEvent(services[s].stopEvent);
+ return NO_ERROR;
+
+ default:
+ break;
+ }
+
+ /* Send current status (done for most request types) */
+ SetServiceStatus(services[s].statusHandle, &services[s].status);
+ return NO_ERROR;
+}
+
+DWORD WINAPI
+pcpCollectorsDispatch(DWORD ctrl, DWORD type, LPVOID data, LPVOID ctxt)
+{
+ return pcpServiceHandler(ctrl, type, data, ctxt, PCP_SERVICE_COLLECTORS);
+}
+
+DWORD WINAPI
+pcpInferenceDispatch(DWORD ctrl, DWORD type, LPVOID data, LPVOID ctxt)
+{
+ return pcpServiceHandler(ctrl, type, data, ctxt, PCP_SERVICE_INFERENCE);
+}
+
+DWORD WINAPI
+pcpProxyDispatch(DWORD ctrl, DWORD type, LPVOID data, LPVOID ctxt)
+{
+ return pcpServiceHandler(ctrl, type, data, ctxt, PCP_SERVICE_PROXY);
+}
+
+int
+main(int argc, char **argv)
+{
+ SERVICE_TABLE_ENTRY dispatchTable[2];
+
+ __pmSetProgname(argv[0]);
+
+ /* setup dispatch table and sentinel */
+ dispatchTable[0].lpServiceName = services[0].name;
+ dispatchTable[0].lpServiceProc = services[0].setup;
+ dispatchTable[1].lpServiceName = NULL;
+ dispatchTable[1].lpServiceProc = NULL;
+
+ if (!StartServiceCtrlDispatcher(dispatchTable)) {
+ DWORD c = GetLastError();
+ fprintf(stderr, "%s: cannot dispatch services (%ld)\n", pmProgname, c);
+ if (c == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
+ fprintf(stderr, "%s: run as service, not on console\n", pmProgname);
+ return 1;
+ }
+ return 0;
+}