1 // Copyright (C) 2006-2009 Hendrik Baecker <andurin@process-zero.de>
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License version 2 as
5 // published by the Free Software Foundation;
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License for more details.
11 //
12 // You should have received a copy of the GNU General Public License
13 // along with this program; if not, write to the Free Software
14 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
15
16 #include "../include/config.h"
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <signal.h>
23
24 #ifdef HAVE_GETOPT_H
25 #include <getopt.h>
26 #endif
27
28 #include<unistd.h>
29 #include<sys/types.h>
30 #include<sys/socket.h>
31 #include<netinet/in.h>
32
33 #define BUFFER_SIZE 255
34 #define DEFAULT_SERVERPORT 5661 /* Ein Port der auch von 'gewhnlichen' Benutzern verwendet werden darf */
35 #define MSG_SIZE 8192 /* Die maximale Anzahl an Zeichen, die 'msg' enhalten darf */
36
37 #define OPEN 1
38 #define CLOSE 0
39
40 #define TRUE 1
41 #define FALSE 0
42
43 #define OK 0
44 #define ERROR -1
45
46 struct Nagios_Env {
47 char varname[128];
48 char varvalue[128];
49 struct Nagios_Env *next;
50 };
51
52 /* function prototypes */
53 void print_list(int, struct Nagios_Env *);
54 int parse_env(char *, struct Nagios_Env **);
55 int process_env(char *[]);
56 int open_sock();
57 int process_arguments(int, char **);
58
59 void timeout_sighandler(int);
60
61 /* variable declaration*/
62 pid_t fork(void);
63 int socket_status = CLOSE;
64 int serverport = DEFAULT_SERVERPORT;
65 int timeout = 10; /* Default time out to 10 seconds */
66 char *serverip, *datatype;
67 char msg[MSG_SIZE]; /* Buffer for sending the message to remote server */
68
main(int argc,char * argv[],char * envp[])69 int main(int argc, char *argv[], char *envp[]) {
70
71 if (process_arguments(argc, argv) == ERROR)
72 exit(ERROR);
73
74 pid_t pid;
75 int error_code = 0;
76 switch (pid = fork()) {
77 case -1:
78 /* Here pid is -1, the fork failed */
79 /* Some possible reasons are that you're */
80 /* out of process slots or virtual memory */
81 perror("The fork failed!");
82 error_code = -1;
83 break;
84
85 case 0:
86 /* pid of zero is the child */
87 signal(SIGALRM, timeout_sighandler);
88 alarm(timeout);
89 process_env(envp);
90 _exit(0);
91
92 default:
93 /* pid greater than zero is parent getting the child's pid */
94 //printf("Child's pid is %d\n",pid);
95 error_code = 0;
96 }
97 exit(error_code);
98 }
99
timeout_sighandler(int sig)100 void timeout_sighandler(int sig) {
101
102 /* force the child process to exit... */
103 fprintf(stderr, "Caught SIGALRM - timeout\n");
104 _exit(-1);
105 }
106
107 /***************************************************
108 * processing command line arguments
109 *
110 * Gets number of args and pointer reference to argv
111 ***************************************************/
process_arguments(int argc,char ** argv)112 int process_arguments(int argc, char **argv) {
113 int c;
114 int error = FALSE;
115 int test_mode = FALSE;
116 int display_license = FALSE;
117 int display_help = FALSE;
118
119 #ifdef HAVE_GETOPT_H
120 int option_index=0;
121 static struct option long_options[]= {
122 { "help",no_argument,0,'h'},
123 { "version",no_argument,0,'V'},
124 { "license",no_argument,0,'V'},
125 { "test",no_argument,0,'t'},
126 { "host",required_argument,0,'H'},
127 { "port",required_argument,0,'p'},
128 { "datatype",required_argument,0,'d'},
129 { "timeout",required_argument,0,'t'},
130 { 0,0,0,0}
131 };
132 #endif
133
134 /* make sure we have the correct number of command line arguments */
135 if (argc < 2)
136 error = TRUE;
137
138 while (1) {
139
140 #ifdef HAVE_GETOPT_H
141 c=getopt_long(argc,argv,"+hH:p:d:Vt:",long_options,&option_index);
142 #else
143 c = getopt(argc, argv, "+hH:p:d:Vt:");
144 #endif
145
146 if (c == -1 || c == EOF)
147 break;
148
149 switch (c) {
150
151 case '?': /* usage */
152 case 'h':
153 display_help = TRUE;
154 break;
155
156 case 'V': /* version */
157 display_license = TRUE;
158 break;
159
160 case 'H': /* host ip */
161 // ToDo: Check if it there
162 if (optarg != NULL) {
163 serverip = optarg;
164 } else
165 error = TRUE;
166 break;
167
168 case 'p': /* port to use */
169 // ToDo: Check for port
170 if (optarg != NULL)
171 serverport = atoi(optarg);
172 break;
173
174 case 'd': /* datatype like hostperfdata, serviceperfdata and so on */
175 if (optarg != NULL)
176 datatype = optarg;
177 else
178 error = TRUE;
179 break;
180
181 case 't': /* timeout */
182 if (optarg != NULL)
183 timeout = atoi(optarg);
184 else
185 error = TRUE;
186 break;
187
188 default:
189 break;
190 }
191
192 }
193
194 /* it makes no sense to do anything without a target host*/
195 if (serverip == NULL)
196 error = TRUE;
197
198 if (display_license == TRUE) {
199
200 printf(
201 "This program is free software; you can redistribute it and/or modify\n");
202 printf(
203 "it under the terms of the GNU General Public License version 2 as\n");
204 printf("published by the Free Software Foundation.\n\n");
205 printf(
206 "This program is distributed in the hope that it will be useful,\n");
207 printf(
208 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
209 printf(
210 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
211 printf("GNU General Public License for more details.\n\n");
212 printf(
213 "You should have received a copy of the GNU General Public License\n");
214 printf("along with this program; if not, write to the Free Software\n");
215 printf(
216 "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n\n");
217
218 exit(OK);
219 }
220
221 /* if there are no command line options (or if we encountered an error), print usage */
222 if (error == TRUE || display_help == TRUE) {
223 printf(
224 "Usage: %s -H <serverip> [-p <serverport>] -d <datatype> -t <timeout>\n",
225 argv[0]);
226 printf("\n");
227 printf("Options:\n");
228 printf("\n");
229 printf(" -H | --host Host IP Address to send data to.\n");
230 printf("\n");
231 printf(
232 " -p | --port Host Port to send data to. (Default: tcp/1500)\n");
233 printf("\n");
234 printf(
235 " -t | --timeout Timeout value to kill process (Default: 10 seconds)\n");
236 printf("\n");
237 printf(" -d | --datatype Free string what this Data stands for\n");
238 printf(
239 " like \"serviceperfdata\", \"hostperfdata\", \"eventhandler\"\n");
240 printf("\n\n");
241 printf(
242 "Visit the PNP website at http://www.pnp4nagios.org/pnp/ for bug fixes, new\n");
243 printf(
244 "releases, online documentation, FAQs, information on subscribing to\n");
245 printf("the mailing lists.\n");
246 printf("\n");
247
248 exit(ERROR);
249 }
250 return OK;
251 }
252
process_env(char * envp[])253 int process_env(char *envp[]) {
254 int count = 0;
255 int socket;
256 struct Nagios_Env *base = NULL;
257 struct Nagios_Env *ptr = NULL;
258 while (1) {
259 if (socket_status == CLOSE) {
260 socket = open_sock(serverip);
261 }
262 if (envp[count] == NULL) {
263 break;
264 }
265 parse_env(envp[count], &base);
266 count++;
267 }
268 print_list(socket, base);
269 return (0);
270 }
271
print_list(int socket,struct Nagios_Env * base)272 void print_list(int socket, struct Nagios_Env *base) {
273 struct Nagios_Env *ptr = NULL;
274 char *message, dtype[BUFFER_SIZE];
275 int message_length = sizeof(struct Nagios_Env) - sizeof(ptr->next);
276 ptr = base;
277 strcat(dtype,
278 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
279 strcat(dtype, "<NAGIOS>\n");
280 strcat(dtype, " <NAGIOS_DATATYPE>");
281 strcat(dtype, datatype);
282 strcat(dtype, "</NAGIOS_DATATYPE>\n");
283 if (send(socket, dtype, strlen(dtype), 0) == -1) {
284 fprintf(stderr, "error while sending request to server\n");
285 }
286 bzero((void *) dtype, BUFFER_SIZE);
287
288 while (ptr != NULL) {
289 if (!(message = (char *) malloc(sizeof(struct Nagios_Env)))) {
290 fprintf(stderr, "Cannot allocate memory for this message\n");
291 exit(ERROR);
292 }
293 strncat(message, " <", message_length);
294 strncat(message, ptr->varname, message_length);
295 strncat(message, ">", message_length);
296 strncat(message, ptr->varvalue, message_length);
297 strncat(message, "</", message_length);
298 strncat(message, ptr->varname, message_length);
299 strncat(message, ">\n", message_length);
300 message[message_length] = '\0';
301 if (send(socket, message, strlen(message), 0) == -1) {
302 fprintf(stderr, "error while sending request to server\n");
303 }
304 ptr = ptr->next;
305 }
306 strcat(dtype, "</NAGIOS>\n");
307 if (send(socket, dtype, strlen(dtype), 0) == -1) {
308 fprintf(stderr, "error while sending request to server\n");
309 }
310 }
311
parse_env(char * curr,struct Nagios_Env ** base)312 int parse_env(char *curr, struct Nagios_Env **base) {
313 char tmpbuf[BUFFER_SIZE];
314 char *var1;
315 char *var2;
316 struct Nagios_Env *ptr = NULL;
317 ptr = *base;
318
319 strncpy(tmpbuf, curr, BUFFER_SIZE);
320 var1 = strtok(tmpbuf, "=");
321 var2 = strtok(NULL, "");
322 if (strncmp(var1, (char *) "NAGIOS_", 7) == 0) {
323 if (var2 != NULL) {
324 if (ptr == NULL) {
325 /* create first list element */
326 ptr = (struct Nagios_Env *) malloc(sizeof(struct Nagios_Env));
327 if (ptr == NULL)
328 return ERROR;
329 *base = ptr;
330 } else {
331 /* create a new list element */
332 /* first look for the end of list */
333 while (ptr->next != NULL)
334 ptr = ptr->next;
335
336 /* neues Listenelement erzeugen */
337 ptr->next = (struct Nagios_Env *) malloc(
338 sizeof(struct Nagios_Env));
339 if (ptr->next == NULL)
340 return ERROR;
341 ptr = ptr->next;
342 }
343
344 // Building dynamic list
345 strcpy(ptr->varname, var1);
346 strcpy(ptr->varvalue, var2);
347 ptr->next = NULL;
348 }
349 }
350 bzero((void *) tmpbuf, BUFFER_SIZE);
351 return (0);
352 }
353
open_sock()354 int open_sock() {
355 int tosocket; /* the socket descriptor*/
356
357 /* description of struct sockaddr_in is mentioned in netinet/in.h */
358 struct sockaddr_in toaddr; /* store address of server here */
359
360 /* create tcp socket */
361 tosocket = socket(PF_INET, SOCK_STREAM, 0);
362 if (tosocket == -1) {
363 fprintf(stderr, "cannot open socket\n");
364 exit(1);
365 }
366
367 /* define server address */
368 toaddr.sin_family = PF_INET;
369 toaddr.sin_addr.s_addr = inet_addr(serverip);
370 toaddr.sin_port = htons(serverport);
371
372 /* connect to server */
373 if (connect(tosocket, (struct sockaddr *) &toaddr, sizeof(toaddr)) == -1) {
374 fprintf(stderr,
375 "Unable to connect to server '%s' on port %d. Exiting...\n",
376 serverip, serverport);
377 close(tosocket);
378 exit(1);
379 } else {
380 socket_status = OPEN;
381 return tosocket;
382 }
383 return -1;
384 }
385