1 /******************************************************************************
3 * Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License *
7 * as published by the Free Software Foundation; either version 2 *
8 * of the License, or (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the Free Software Foundation *
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ******************************************************************************/
20 #include "compat/externalcommandlistener.hpp"
21 #include "compat/externalcommandlistener-ti.cpp"
22 #include "icinga/externalcommandprocessor.hpp"
23 #include "base/configtype.hpp"
24 #include "base/logger.hpp"
25 #include "base/exception.hpp"
26 #include "base/application.hpp"
27 #include "base/statsfunction.hpp"
29 using namespace icinga;
31 REGISTER_TYPE(ExternalCommandListener);
33 REGISTER_STATSFUNCTION(ExternalCommandListener, &ExternalCommandListener::StatsFunc);
35 void ExternalCommandListener::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr&)
39 for (const ExternalCommandListener::Ptr& externalcommandlistener : ConfigType::GetObjectsByType<ExternalCommandListener>()) {
40 nodes.emplace_back(externalcommandlistener->GetName(), 1); //add more stats
43 status->Set("externalcommandlistener", new Dictionary(std::move(nodes)));
47 * Starts the component.
49 void ExternalCommandListener::Start(bool runtimeCreated)
51 ObjectImpl<ExternalCommandListener>::Start(runtimeCreated);
53 Log(LogInformation, "ExternalCommandListener")
54 << "'" << GetName() << "' started.";
57 m_CommandThread = std::thread(std::bind(&ExternalCommandListener::CommandPipeThread, this, GetCommandPath()));
58 m_CommandThread.detach();
63 * Stops the component.
65 void ExternalCommandListener::Stop(bool runtimeRemoved)
67 Log(LogInformation, "ExternalCommandListener")
68 << "'" << GetName() << "' stopped.";
70 ObjectImpl<ExternalCommandListener>::Stop(runtimeRemoved);
74 void ExternalCommandListener::CommandPipeThread(const String& commandPath)
76 Utility::SetThreadName("Command Pipe");
81 if (lstat(commandPath.CStr(), &statbuf) >= 0) {
82 if (S_ISFIFO(statbuf.st_mode) && access(commandPath.CStr(), R_OK) >= 0) {
85 if (unlink(commandPath.CStr()) < 0) {
86 BOOST_THROW_EXCEPTION(posix_error()
87 << boost::errinfo_api_function("unlink")
88 << boost::errinfo_errno(errno)
89 << boost::errinfo_file_name(commandPath));
94 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
96 if (!fifo_ok && mkfifo(commandPath.CStr(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) < 0) {
97 Log(LogCritical, "ExternalCommandListener")
98 << "mkfifo() for fifo path '" << commandPath << "' failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
102 /* mkfifo() uses umask to mask off some bits, which means we need to chmod() the
103 * fifo to get the right mask. */
104 if (chmod(commandPath.CStr(), mode) < 0) {
105 Log(LogCritical, "ExternalCommandListener")
106 << "chmod() on fifo '" << commandPath << "' failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
111 int fd = open(commandPath.CStr(), O_RDWR | O_NONBLOCK);
114 Log(LogCritical, "ExternalCommandListener")
115 << "open() for fifo path '" << commandPath << "' failed with error code " << errno << ", \"" << Utility::FormatErrorNumber(errno) << "\"";
119 FIFO::Ptr fifo = new FIFO();
120 Socket::Ptr sock = new Socket(fd);
121 StreamReadContext src;
124 sock->Poll(true, false);
130 rc = sock->Read(buffer, sizeof(buffer));
131 } catch (const std::exception& ex) {
132 /* We have read all data. */
136 Log(LogWarning, "ExternalCommandListener")
137 << "Cannot read from command pipe." << DiagnosticInformation(ex);
141 /* Empty pipe (EOF) */
145 fifo->Write(buffer, rc);
149 StreamReadStatus srs = fifo->ReadLine(&command, src);
151 if (srs != StatusNewItem)
155 Log(LogInformation, "ExternalCommandListener")
156 << "Executing external command: " << command;
158 ExternalCommandProcessor::Execute(command);
159 } catch (const std::exception& ex) {
160 Log(LogWarning, "ExternalCommandListener")
161 << "External command failed: " << DiagnosticInformation(ex, false);
162 Log(LogNotice, "ExternalCommandListener")
163 << "External command failed: " << DiagnosticInformation(ex, true);