From e30d3c56912b91d6e9ec7cfbb64de84d0d2c4049 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Thu, 13 Jun 2013 12:05:24 +0200 Subject: [PATCH] Implement command timeouts. Fixes #2723 --- lib/base/process-unix.cpp | 36 ++++++++++++++++++++++----- lib/base/process.cpp | 12 ++++++++- lib/base/process.h | 5 ++++ lib/icinga/icinga-type.conf | 3 ++- lib/icinga/pluginchecktask.cpp | 5 ++++ lib/icinga/plugineventtask.cpp | 5 ++++ lib/icinga/pluginnotificationtask.cpp | 5 ++++ 7 files changed, 63 insertions(+), 8 deletions(-) diff --git a/lib/base/process-unix.cpp b/lib/base/process-unix.cpp index 1b90a9eb6..d8b11f0bd 100644 --- a/lib/base/process-unix.cpp +++ b/lib/base/process-unix.cpp @@ -32,6 +32,7 @@ #ifndef _WIN32 #include +#include using namespace icinga; @@ -158,13 +159,36 @@ ProcessResult Process::Run(void) std::ostringstream outputStream; + pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + pfd.revents = 0; + for (;;) { - int rc = read(fd, buffer, sizeof(buffer)); + int rc1, timeout; - if (rc <= 0) - break; + timeout = 0; - outputStream.write(buffer, rc); + if (m_Timeout != 0) { + timeout = m_Timeout - (Utility::GetTime() - result.ExecutionStart); + + if (timeout < 0) { + outputStream << ""; + kill(m_Pid, SIGKILL); + break; + } + } + + rc1 = poll(&pfd, 1, timeout * 1000); + + if (rc1 > 0) { + int rc2 = read(fd, buffer, sizeof(buffer)); + + if (rc2 <= 0) + break; + + outputStream.write(buffer, rc2); + } } String output = outputStream.str(); @@ -183,8 +207,8 @@ ProcessResult Process::Run(void) exitcode = WEXITSTATUS(status); } else if (WIFSIGNALED(status)) { std::ostringstream outputbuf; - outputbuf << "Process was terminated by signal " << WTERMSIG(status); - output = outputbuf.str(); + outputbuf << ""; + output = output + outputbuf.str(); exitcode = 128; } else { exitcode = 128; diff --git a/lib/base/process.cpp b/lib/base/process.cpp index 009311b47..e2f990421 100644 --- a/lib/base/process.cpp +++ b/lib/base/process.cpp @@ -26,7 +26,7 @@ using namespace icinga; Process::Process(const std::vector& arguments, const Dictionary::Ptr& extraEnvironment) - : m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment) + : m_Arguments(arguments), m_ExtraEnvironment(extraEnvironment), m_Timeout(600) { } std::vector Process::SplitCommand(const Value& command) @@ -54,3 +54,13 @@ std::vector Process::SplitCommand(const Value& command) #endif return args; } + +void Process::SetTimeout(double timeout) +{ + m_Timeout = timeout; +} + +double Process::GetTimeout(void) const +{ + return m_Timeout; +} diff --git a/lib/base/process.h b/lib/base/process.h index 8b0ac1c23..1587752a6 100644 --- a/lib/base/process.h +++ b/lib/base/process.h @@ -61,6 +61,9 @@ public: Process(const std::vector& arguments, const Dictionary::Ptr& extraEnvironment = Dictionary::Ptr()); + void SetTimeout(double timeout); + double GetTimeout(void) const; + ProcessResult Run(void); static std::vector SplitCommand(const Value& command); @@ -68,6 +71,8 @@ private: std::vector m_Arguments; Dictionary::Ptr m_ExtraEnvironment; + double m_Timeout; + #ifndef _WIN32 pid_t m_Pid; diff --git a/lib/icinga/icinga-type.conf b/lib/icinga/icinga-type.conf index 1e0c3fb3b..32d674979 100644 --- a/lib/icinga/icinga-type.conf +++ b/lib/icinga/icinga-type.conf @@ -316,7 +316,8 @@ type Command { }, %attribute dictionary "macros" { %attribute string "*" - } + }, + %attribute number "timeout" /* } */ } diff --git a/lib/icinga/pluginchecktask.cpp b/lib/icinga/pluginchecktask.cpp index f1dc932f1..987d39cd2 100644 --- a/lib/icinga/pluginchecktask.cpp +++ b/lib/icinga/pluginchecktask.cpp @@ -67,6 +67,11 @@ Dictionary::Ptr PluginCheckTask::ScriptFunc(const Service::Ptr& service) Process::Ptr process = boost::make_shared(Process::SplitCommand(command), envMacros); + Value timeout = commandObj->Get("timeout"); + + if (!timeout.IsEmpty()) + process->SetTimeout(timeout); + ProcessResult pr = process->Run(); String output = pr.Output; diff --git a/lib/icinga/plugineventtask.cpp b/lib/icinga/plugineventtask.cpp index 54cafcdf3..bb7110062 100644 --- a/lib/icinga/plugineventtask.cpp +++ b/lib/icinga/plugineventtask.cpp @@ -65,5 +65,10 @@ void PluginEventTask::ScriptFunc(const Service::Ptr& service) Process::Ptr process = boost::make_shared(Process::SplitCommand(command), envMacros); + Value timeout = commandObj->Get("timeout"); + + if (!timeout.IsEmpty()) + process->SetTimeout(timeout); + process->Run(); } diff --git a/lib/icinga/pluginnotificationtask.cpp b/lib/icinga/pluginnotificationtask.cpp index 7e4084270..63f893bd7 100644 --- a/lib/icinga/pluginnotificationtask.cpp +++ b/lib/icinga/pluginnotificationtask.cpp @@ -78,6 +78,11 @@ void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification, c Process::Ptr process = boost::make_shared(Process::SplitCommand(command), envMacros); + Value timeout = commandObj->Get("timeout"); + + if (!timeout.IsEmpty()) + process->SetTimeout(timeout); + ProcessResult pr = process->Run(); if (pr.ExitStatus != 0) {