mirror of
https://github.com/netdata/netdata.git
synced 2025-04-14 01:29:11 +00:00

* listening ipv6 sockets may be both ipv4 and ipv6, depending on the IPV6_ONLY flag * working libmnl ipv46 detection and added latency and retransmits from TCP_INFO * fix aggregations for rtt and retrans * code cleanup * code cleanup * code cleanup again * restore field renames * count namespaces * run namespaces in parallel * add libmnl to buildinfo * lock around safe_fork() * libmnl ports are in network byte order * posix spawn server for both executables and callback functions * local-sockets and network-viewer using the new spawn server * cleanup spawn servers sockets * spawn server stdin and stdout are linked to /dev/null * no need for spinlock in spawn server * empty all parameters * new spawn server is now used for plugins.d plugins * fix for environ * claiming script runs via the new spawn server * tc.plugin uses the new spawn server * analytics, buildinfo and cgroups.plugin use the new spawn server * cgroup-discovery uses the new spawn server * added ability to wait or kill spawned processes * removed old spawn server and now alert notifications use the new one * remove left-overs * hide spawn server internals; started working on windows version of the spawn server * fixes for windows * more windows work * more work on windows * added debug log to spawn server * fix compilation warnings * enable static threads on windows * running external plugins * working spawn server on windows * spawn server logs to collectoers.log * log windows last error together with errno * log updates * cleanup * decode_argv does not add an empty parameter * removed debug log * removed debug return * rework on close_range() * eliminate the need for waitid() * clear errno on the signal handler * added universal os_setproctitle() call to support FreeBSD too * os_get_pid_max() for windows and macos * isolate pids array from the rest of the code in apps.plugin so that it can be turned to a hashtable
252 lines
6.6 KiB
C++
252 lines
6.6 KiB
C++
extern "C" {
|
|
|
|
#include "daemon.h"
|
|
#include "libnetdata/libnetdata.h"
|
|
|
|
int netdata_main(int argc, char *argv[]);
|
|
void signals_handle(void);
|
|
|
|
}
|
|
|
|
#include <windows.h>
|
|
|
|
__attribute__((format(printf, 1, 2)))
|
|
static void netdata_service_log(const char *fmt, ...)
|
|
{
|
|
char path[FILENAME_MAX + 1];
|
|
snprintfz(path, FILENAME_MAX, "%s/service.log", LOG_DIR);
|
|
|
|
FILE *fp = fopen(path, "a");
|
|
if (fp == NULL) {
|
|
return;
|
|
}
|
|
|
|
SYSTEMTIME time;
|
|
GetSystemTime(&time);
|
|
fprintf(fp, "%d:%d:%d - ", time.wHour, time.wMinute, time.wSecond);
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vfprintf(fp, fmt, args);
|
|
va_end(args);
|
|
|
|
fprintf(fp, "\n");
|
|
|
|
fflush(fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
static SERVICE_STATUS_HANDLE svc_status_handle = nullptr;
|
|
static SERVICE_STATUS svc_status = {};
|
|
|
|
static HANDLE svc_stop_event_handle = nullptr;
|
|
|
|
static ND_THREAD *cleanup_thread = nullptr;
|
|
|
|
static bool ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint, DWORD dwControlsAccepted)
|
|
{
|
|
static DWORD dwCheckPoint = 1;
|
|
svc_status.dwCurrentState = dwCurrentState;
|
|
svc_status.dwWin32ExitCode = dwWin32ExitCode;
|
|
svc_status.dwWaitHint = dwWaitHint;
|
|
svc_status.dwControlsAccepted = dwControlsAccepted;
|
|
|
|
if (dwCurrentState == SERVICE_RUNNING || dwCurrentState == SERVICE_STOPPED)
|
|
{
|
|
svc_status.dwCheckPoint = 0;
|
|
}
|
|
else
|
|
{
|
|
svc_status.dwCheckPoint = dwCheckPoint++;
|
|
}
|
|
|
|
if (!SetServiceStatus(svc_status_handle, &svc_status)) {
|
|
netdata_service_log("@ReportSvcStatus: SetServiceStatusFailed (%d)", GetLastError());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static HANDLE CreateEventHandle(const char *msg)
|
|
{
|
|
HANDLE h = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
if (!h)
|
|
{
|
|
netdata_service_log(msg);
|
|
|
|
if (!ReportSvcStatus(SERVICE_STOPPED, GetLastError(), 1000, 0))
|
|
{
|
|
netdata_service_log("Failed to set service status to stopped.");
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return h;
|
|
}
|
|
|
|
static void *call_netdata_cleanup(void *arg)
|
|
{
|
|
UNUSED(arg);
|
|
|
|
// Wait until we have to stop the service
|
|
netdata_service_log("Cleanup thread waiting for stop event...");
|
|
WaitForSingleObject(svc_stop_event_handle, INFINITE);
|
|
|
|
// Stop the agent
|
|
netdata_service_log("Running netdata cleanup...");
|
|
netdata_cleanup_and_exit(0, NULL, NULL, NULL);
|
|
|
|
// Close event handle
|
|
netdata_service_log("Closing stop event handle...");
|
|
CloseHandle(svc_stop_event_handle);
|
|
|
|
// Set status to stopped
|
|
netdata_service_log("Reporting the service as stopped...");
|
|
ReportSvcStatus(SERVICE_STOPPED, 0, 0, 0);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
static void WINAPI ServiceControlHandler(DWORD controlCode)
|
|
{
|
|
switch (controlCode)
|
|
{
|
|
case SERVICE_CONTROL_STOP:
|
|
{
|
|
if (svc_status.dwCurrentState != SERVICE_RUNNING)
|
|
return;
|
|
|
|
// Set service status to stop-pending
|
|
netdata_service_log("Setting service status to stop-pending...");
|
|
if (!ReportSvcStatus(SERVICE_STOP_PENDING, 0, 5000, 0))
|
|
return;
|
|
|
|
// Create cleanup thread
|
|
netdata_service_log("Creating cleanup thread...");
|
|
char tag[NETDATA_THREAD_TAG_MAX + 1];
|
|
snprintfz(tag, NETDATA_THREAD_TAG_MAX, "%s", "CLEANUP");
|
|
cleanup_thread = nd_thread_create(tag, NETDATA_THREAD_OPTION_JOINABLE, call_netdata_cleanup, NULL);
|
|
|
|
// Signal the stop request
|
|
netdata_service_log("Signalling the cleanup thread...");
|
|
SetEvent(svc_stop_event_handle);
|
|
break;
|
|
}
|
|
case SERVICE_CONTROL_INTERROGATE:
|
|
{
|
|
ReportSvcStatus(svc_status.dwCurrentState, svc_status.dwWin32ExitCode, svc_status.dwWaitHint, svc_status.dwControlsAccepted);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void WINAPI ServiceMain(DWORD argc, LPSTR* argv)
|
|
{
|
|
UNUSED(argc);
|
|
UNUSED(argv);
|
|
|
|
// Create service status handle
|
|
netdata_service_log("Creating service status handle...");
|
|
svc_status_handle = RegisterServiceCtrlHandler("Netdata", ServiceControlHandler);
|
|
if (!svc_status_handle)
|
|
{
|
|
netdata_service_log("@ServiceMain() - RegisterServiceCtrlHandler() failed...");
|
|
return;
|
|
}
|
|
|
|
// Set status to start-pending
|
|
netdata_service_log("Setting service status to start-pending...");
|
|
svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
svc_status.dwServiceSpecificExitCode = 0;
|
|
svc_status.dwCheckPoint = 0;
|
|
if (!ReportSvcStatus(SERVICE_START_PENDING, 0, 5000, 0))
|
|
{
|
|
netdata_service_log("Failed to set service status to start pending.");
|
|
return;
|
|
}
|
|
|
|
// Create stop service event handle
|
|
netdata_service_log("Creating stop service event handle...");
|
|
svc_stop_event_handle = CreateEventHandle("Failed to create stop event handle");
|
|
if (!svc_stop_event_handle)
|
|
return;
|
|
|
|
// Set status to running
|
|
netdata_service_log("Setting service status to running...");
|
|
if (!ReportSvcStatus(SERVICE_RUNNING, 0, 5000, SERVICE_ACCEPT_STOP))
|
|
{
|
|
netdata_service_log("Failed to set service status to running.");
|
|
return;
|
|
}
|
|
|
|
// Run the agent
|
|
netdata_service_log("Running the agent...");
|
|
netdata_main(argc, argv);
|
|
|
|
netdata_service_log("Agent has been started...");
|
|
}
|
|
|
|
static bool update_path() {
|
|
const char *old_path = getenv("PATH");
|
|
|
|
if (!old_path) {
|
|
if (setenv("PATH", "/usr/bin", 1) != 0) {
|
|
netdata_service_log("Failed to set PATH to /usr/bin");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t new_path_length = strlen(old_path) + strlen("/usr/bin") + 2;
|
|
char *new_path = (char *) callocz(new_path_length, sizeof(char));
|
|
snprintfz(new_path, new_path_length, "/usr/bin:%s", old_path);
|
|
|
|
if (setenv("PATH", new_path, 1) != 0) {
|
|
netdata_service_log("Failed to add /usr/bin to PATH");
|
|
freez(new_path);
|
|
return false;
|
|
}
|
|
|
|
freez(new_path);
|
|
return true;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
bool tty = isatty(fileno(stdin)) == 1;
|
|
|
|
if (!update_path()) {
|
|
return 1;
|
|
}
|
|
|
|
if (tty)
|
|
{
|
|
int rc = netdata_main(argc, argv);
|
|
if (rc != 10)
|
|
return rc;
|
|
|
|
signals_handle();
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
SERVICE_TABLE_ENTRY serviceTable[] = {
|
|
{ strdupz("Netdata"), ServiceMain },
|
|
{ nullptr, nullptr }
|
|
};
|
|
|
|
if (!StartServiceCtrlDispatcher(serviceTable))
|
|
{
|
|
netdata_service_log("@main() - StartServiceCtrlDispatcher() failed...");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|