Refactoring: Moved check parameters from unsorted.py to dedicated modules (CMK-1393)
[check_mk.git] / bin / mkevent.cc
blobe743c8ec111efb1c8a04ac85fd7872cb4b5a1da7
1 // +------------------------------------------------------------------+
2 // | ____ _ _ __ __ _ __ |
3 // | / ___| |__ ___ ___| | __ | \/ | |/ / |
4 // | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
5 // | | |___| | | | __/ (__| < | | | | . \ |
6 // | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
7 // | |
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>
26 #include <fcntl.h>
27 #include <netinet/in.h>
28 #include <sys/socket.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <cctype>
32 #include <cerrno>
33 #include <cstdio>
34 #include <cstdlib>
35 #include <cstring>
36 #include <ctime>
37 #include <iostream>
38 #include <string>
40 /* Methods for specified the path to the pipe of
41 mkeventd:
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
50 find pipe itself
52 4. Uses hardcoded path /var/run/mkeventd.pipe.
56 int file_exists(const std::string &path) {
57 struct stat st;
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);
64 return dest + len;
67 char *append_int(long n, char *dest) {
68 static char digits[] = "0123456789";
69 char buf[32];
70 buf[31] = 0;
71 char *b = buf + 31;
72 do {
73 *(--b) = digits[n % 10];
74 } while ((n /= 10) > 0);
75 return append_str(b, dest);
78 int main(int argc, char **argv) {
79 if (argc < 2) {
80 std::cerr << "Usage: mkevent [-P PIPE] 'Text of the messsage'"
81 << std::endl;
82 exit(1);
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];
90 argc -= 2;
91 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 */
105 char message[8192];
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]);
112 remote = argv[3];
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) {
123 sl_text = argv[10];
125 if (contact[0] == '$' && argc > 11) {
126 contact = argv[11];
129 int sl = atoi(sl_text);
130 if (contact[0] == '$') {
131 contact = "";
134 int priority;
135 if (state == 0) {
136 priority = 5;
137 } else {
138 if (service[0] == 0) {
139 state += 1; // shift host states in order to map service states
141 if (state == 1) {
142 priority = 4; // warn
143 } else if (state == 3) {
144 priority = 3; // map UNKNOWN/UNREAD to err
145 } else {
146 priority = 2; // CRIT/DOWN goes to crit
150 char *w = message;
151 *w++ = '<';
152 w = append_int((static_cast<long>(facility) << 3) + priority, w);
153 *w++ = '>';
154 *w++ = '@';
155 w = append_int(time(nullptr), w);
156 *w++ = ';';
157 w = append_int(sl, w);
158 *w++ = ';';
159 w = append_str(contact, w);
160 *w++ = ';';
161 *w++ = ' ';
162 w = append_str(hostname, w);
163 *w++ = ' ';
164 w = append_str(service[0] != 0 ? service : "HOST", w);
165 *w++ = ':';
166 *w++ = ' ';
167 w = append_str(text, w);
168 *w = 0;
169 } else {
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. */
175 int fd;
176 if (file_exists(path_to_pipe) == 0 && remote[0] != 0) {
177 if (isdigit(remote[0]) == 0) {
178 std::cerr
179 << "ERROR: Please specify the remote host as IPv4 address, not '"
180 << remote << "'" << std::endl;
181 exit(1);
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),
191 sizeof(servaddr));
192 } else {
193 fd = open(path_to_pipe.c_str(), O_WRONLY);
194 if (fd < 0) {
195 int errno_saved = errno;
196 std::cerr << "Cannot open event pipe '" << path_to_pipe
197 << "': " << strerror(errno_saved) << std::endl;
198 exit(1);
200 // TODO(sp) Handle errors and partial writes.
201 if (write(fd, message, strlen(message)) < 0 || write(fd, "\n", 1) < 0) {
204 close(fd);
205 return 0;