1 // +------------------------------------------------------------------+
2 // | ____ _ _ __ __ _ __ |
3 // | / ___| |__ ___ ___| | __ | \/ | |/ / |
4 // | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
5 // | | |___| | | | __/ (__| < | | | | . \ |
6 // | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
8 // | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
9 // +------------------------------------------------------------------+
11 // This file is part of Check_MK.
12 // The official homepage is at http://mathias-kettner.de/check_mk.
14 // check_mk is free software; you can redistribute it and/or modify it
15 // under the terms of the GNU General Public License as published by
16 // the Free Software Foundation in version 2. check_mk is distributed
17 // in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
18 // out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
19 // PARTICULAR PURPOSE. See the GNU General Public License for more de-
20 // ails. You should have received a copy of the GNU General Public
21 // License along with GNU Make; see the file COPYING. If not, write
22 // to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 // Boston, MA 02110-1301 USA.
25 #include <arpa/inet.h>
27 #include <netinet/in.h>
28 #include <sys/socket.h>
40 /* Methods for specified the path to the pipe of
43 1. Run mkevent within the environment of a
44 OMD site -> will find pipe itself
46 2. Specify pipe with -P PATH before message
48 3. Run mkeventd with absolute path in a site,
49 e.g. /omd/sites/mysite/bin/mkevent -> will
52 4. Uses hardcoded path /var/run/mkeventd.pipe.
56 int file_exists(const std::string
&path
) {
58 return static_cast<int>(stat(path
.c_str(), &st
) == 0);
61 char *append_str(const char *str
, char *dest
) {
62 size_t len
= strlen(str
);
63 memcpy(dest
, str
, len
);
67 char *append_int(long n
, char *dest
) {
68 static char digits
[] = "0123456789";
73 *(--b
) = digits
[n
% 10];
74 } while ((n
/= 10) > 0);
75 return append_str(b
, dest
);
78 int main(int argc
, char **argv
) {
80 std::cerr
<< "Usage: mkevent [-P PIPE] 'Text of the messsage'"
85 std::string path_to_pipe
;
87 /* Path to pipe can be specified with -P */
88 if (argc
> 2 && (strcmp(argv
[1], "-P") == 0)) {
89 path_to_pipe
= argv
[2];
94 if (path_to_pipe
.empty()) {
95 if (const char *omd_root
= getenv("OMD_ROOT")) {
96 path_to_pipe
= std::string(omd_root
) + "/tmp/run/mkeventd/events";
97 } else if (strncmp(argv
[0], "/omd/sites/", 11) == 0) {
98 // cut off /bin/mkevent
99 path_to_pipe
= std::string(argv
[0], strlen(argv
[0]) - 12) +
100 "/tmp/run/mkeventd/events";
104 /* Nagios notification mode is triggered with option -n */
106 const char *remote
= "";
108 if (argc
> 9 && (strcmp(argv
[1], "-n") == 0)) {
109 /* Arguments: -n FACILITY REMOTE STATE HOST SERVICE MESSAGE */
110 /* SERVICE is empty for host notification */
111 int facility
= atoi(argv
[2]);
113 int state
= atoi(argv
[4]);
114 char *hostname
= argv
[5];
115 char *service
= argv
[6];
116 char *text
= argv
[7];
117 char *sl_text
= argv
[8];
118 const char *contact
= argv
[9];
120 /* If this is a service and sl/contact is unset then we use
121 the values of the host that are coming as arg 10 and 11 */
122 if (sl_text
[0] == '$' && argc
> 11) {
125 if (contact
[0] == '$' && argc
> 11) {
129 int sl
= atoi(sl_text
);
130 if (contact
[0] == '$') {
138 if (service
[0] == 0) {
139 state
+= 1; // shift host states in order to map service states
142 priority
= 4; // warn
143 } else if (state
== 3) {
144 priority
= 3; // map UNKNOWN/UNREAD to err
146 priority
= 2; // CRIT/DOWN goes to crit
152 w
= append_int((static_cast<long>(facility
) << 3) + priority
, w
);
155 w
= append_int(time(nullptr), w
);
157 w
= append_int(sl
, w
);
159 w
= append_str(contact
, w
);
162 w
= append_str(hostname
, w
);
164 w
= append_str(service
[0] != 0 ? service
: "HOST", w
);
167 w
= append_str(text
, w
);
170 strncpy(message
, argv
[1], sizeof(message
));
173 /* If we have a remote host and there is no local event Console running,
174 then we will send the message via syslog to the remote host. */
176 if (file_exists(path_to_pipe
) == 0 && remote
[0] != 0) {
177 if (isdigit(remote
[0]) == 0) {
179 << "ERROR: Please specify the remote host as IPv4 address, not '"
180 << remote
<< "'" << std::endl
;
183 fd
= socket(AF_INET
, SOCK_DGRAM
, 0);
184 struct sockaddr_in servaddr
;
185 bzero(&servaddr
, sizeof(servaddr
));
186 servaddr
.sin_family
= AF_INET
;
187 servaddr
.sin_addr
.s_addr
= inet_addr(remote
);
188 servaddr
.sin_port
= htons(514);
189 sendto(fd
, message
, strlen(message
), 0,
190 reinterpret_cast<struct sockaddr
*>(&servaddr
),
193 fd
= open(path_to_pipe
.c_str(), O_WRONLY
);
195 int errno_saved
= errno
;
196 std::cerr
<< "Cannot open event pipe '" << path_to_pipe
197 << "': " << strerror(errno_saved
) << std::endl
;
200 // TODO(sp) Handle errors and partial writes.
201 if (write(fd
, message
, strlen(message
)) < 0 || write(fd
, "\n", 1) < 0) {