Code

Support for Nagios 1 and Nagios 2 status files (Gerhard Lausser - 1296242)
[nagiosplug.git] / plugins / check_nagios.c
1 /******************************************************************************
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; either version 2 of the License, or
6  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  GNU General Public License for more details.
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  $Id$
18  
19 ******************************************************************************/
21 const char *progname = "check_nagios";
22 const char *revision = "$Revision$";
23 const char *copyright = "1999-2004";
24 const char *email = "nagiosplug-devel@lists.sourceforge.net";
26 #include "common.h"
27 #include "runcmd.h"
28 #include "utils.h"
30 int process_arguments (int, char **);
31 void print_help (void);
32 void print_usage (void);
34 char *status_log = NULL;
35 char *process_string = NULL;
36 int expire_minutes = 0;
38 int verbose = 0;
40 int
41 main (int argc, char **argv)
42 {
43         int result = STATE_UNKNOWN;
44         char input_buffer[MAX_INPUT_BUFFER];
45         unsigned long latest_entry_time = 0L;
46         unsigned long temp_entry_time = 0L;
47         int proc_entries = 0;
48         time_t current_time;
49         char *temp_ptr;
50         FILE *fp;
51         int procuid = 0;
52         int procpid = 0;
53         int procppid = 0;
54         int procvsz = 0;
55         int procrss = 0;
56         float procpcpu = 0;
57         char procstat[8];
58 #ifdef PS_USES_PROCETIME
59         char procetime[MAX_INPUT_BUFFER];
60 #endif /* PS_USES_PROCETIME */
61         char procprog[MAX_INPUT_BUFFER];
62         char *procargs;
63         int pos, cols;
64         int expected_cols = PS_COLS - 1;
65         const char *zombie = "Z";
66         char *temp_string;
67         output chld_out, chld_err;
68         size_t i;
70         setlocale (LC_ALL, "");
71         bindtextdomain (PACKAGE, LOCALEDIR);
72         textdomain (PACKAGE);
74         if (process_arguments (argc, argv) == ERROR)
75                 usage_va(_("Could not parse arguments"));
77         /* Set signal handling and alarm timeout */
78         if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
79                 usage_va(_("Cannot catch SIGALRM"));
80         }
82         /* handle timeouts gracefully... */
83         alarm (timeout_interval);
85         /* open the status log */
86         fp = fopen (status_log, "r");
87         if (fp == NULL) {
88                 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!"));
89         }
91         /* get the date/time of the last item updated in the log */
92         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
93                 if ((temp_ptr = strstr (input_buffer, "created=")) != NULL) {
94                         temp_entry_time = strtoul (temp_ptr + 8, NULL, 10);
95                         latest_entry_time = temp_entry_time;
96                         break;
97                 } else if ((temp_ptr = strtok (input_buffer, "]")) != NULL) {
98                         temp_entry_time = strtoul (temp_ptr + 1, NULL, 10);
99                         if (temp_entry_time > latest_entry_time)
100                                 latest_entry_time = temp_entry_time;
101                 }
102         }
103         fclose (fp);
105         if (verbose >= 2)
106                 printf("command: %s\n", PS_COMMAND);
108         /* run the command to check for the Nagios process.. */
109         if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0)
110                 result = STATE_WARNING;
112         /* count the number of matching Nagios processes... */
113         for(i = 0; i < chld_out.lines; i++) {
114                 cols = sscanf (chld_out.line[i], PS_FORMAT, PS_VARLIST);
115                 /* Zombie processes do not give a procprog command */
116                 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
117                         cols = expected_cols;
118                         /* Set some value for procargs for the strip command further below
119                          * Seen to be a problem on some Solaris 7 and 8 systems */
120                         chld_out.line[i][pos] = '\n';
121                         chld_out.line[i][pos+1] = 0x0;
122                 }
123                 if ( cols >= expected_cols ) {
124                         asprintf (&procargs, "%s", chld_out.line[i] + pos);
125                         strip (procargs);
127                         /* Some ps return full pathname for command. This removes path */
128                         temp_string = strtok ((char *)procprog, "/");
129                         while (temp_string) {
130                                 strcpy(procprog, temp_string);
131                                 temp_string = strtok (NULL, "/");
132                         }
134                         /* May get empty procargs */
135                         if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) {
136                                 proc_entries++;
137                                 if (verbose >= 2) {
138                                         printf (_("Found process: %s %s\n"), procprog, procargs);
139                                 }
140                         }
141                 }
142         }
144         /* If we get anything on stderr, at least set warning */
145         if(chld_err.buflen)
146                 result = max_state (result, STATE_WARNING);
148         /* reset the alarm handler */
149         alarm (0);
151         if (proc_entries == 0) {
152                 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Could not locate a running Nagios process!"));
153         }
155         if (latest_entry_time == 0L) {
156                 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time"));
157         }
159         time (&current_time);
160         if ((int)(current_time - latest_entry_time) > (expire_minutes * 60)) {
161                 result = STATE_WARNING;
162         } else {
163                 result = STATE_OK;
164         }
166         printf ("NAGIOS %s: ", (result == STATE_OK) ? _("OK") : _("WARNING"));
167         printf (ngettext ("%d process", "%d processes", proc_entries), proc_entries);
168         printf (", ");
169         printf (
170           ngettext ("status log updated %d second ago", 
171             "status log updated %d seconds ago", 
172             (int) (current_time - latest_entry_time) ),
173             (int) (current_time - latest_entry_time) );
174         printf ("\n");
176         return result;
181 /* process command-line arguments */
182 int
183 process_arguments (int argc, char **argv)
185         int c;
187         int option = 0;
188         static struct option longopts[] = {
189                 {"filename", required_argument, 0, 'F'},
190                 {"expires", required_argument, 0, 'e'},
191                 {"command", required_argument, 0, 'C'},
192                 {"version", no_argument, 0, 'V'},
193                 {"help", no_argument, 0, 'h'},
194                 {"verbose", no_argument, 0, 'v'},
195                 {0, 0, 0, 0}
196         };
198         if (argc < 2)
199                 return ERROR;
201         if (!is_option (argv[1])) {
202                 status_log = argv[1];
203                 if (is_intnonneg (argv[2]))
204                         expire_minutes = atoi (argv[2]);
205                 else
206                         die (STATE_UNKNOWN,
207                                                                  _("Expiration time must be an integer (seconds)\n"));
208                 process_string = argv[3];
209                 return OK;
210         }
212         while (1) {
213                 c = getopt_long (argc, argv, "+hVvF:C:e:", longopts, &option);
215                 if (c == -1 || c == EOF || c == 1)
216                         break;
218                 switch (c) {
219                 case 'h':                                                                       /* help */
220                         print_help ();
221                         exit (STATE_OK);
222                 case 'V':                                                                       /* version */
223                         print_revision (progname, revision);
224                         exit (STATE_OK);
225                 case 'F':                                                                       /* status log */
226                         status_log = optarg;
227                         break;
228                 case 'C':                                                                       /* command */
229                         process_string = optarg;
230                         break;
231                 case 'e':                                                                       /* expiry time */
232                         if (is_intnonneg (optarg))
233                                 expire_minutes = atoi (optarg);
234                         else
235                                 die (STATE_UNKNOWN,
236                                      _("Expiration time must be an integer (seconds)\n"));
237                         break;
238                 case 'v':
239                         verbose++;
240                         break;
241                 default:                                                                        /* print short usage_va statement if args not parsable */
242                         usage_va(_("Unknown argument - %s"), optarg);
243                 }
244         }
247         if (status_log == NULL)
248                 die (STATE_UNKNOWN, _("You must provide the status_log\n"));
250         if (process_string == NULL)
251                 die (STATE_UNKNOWN, _("You must provide a process string\n"));
253         return OK;
258 void
259 print_help (void)
261         print_revision (progname, revision);
263         printf (_(COPYRIGHT), copyright, email);
265         printf (_("\
266 This plugin checks the status of the Nagios process on the local\n\
267 machine. The plugin will check to make sure the Nagios status log is no older\n\
268 than the number of minutes specified by the expires option. It also\n\
269 checks the process table for a process matching the command argument.\n\n"));
271         print_usage ();
273         printf (_(UT_HELP_VRSN));
275         printf (_("\
276  -F, --filename=FILE\n\
277    Name of the log file to check\n\
278  -e, --expires=INTEGER\n\
279    Minutes aging after which logfile is considered stale\n\
280  -C, --command=STRING\n\
281    Substring to search for in process arguments\n"));
283         printf (_("\
284 Example:\n\
285    ./check_nagios -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios\n"));
290 void
291 print_usage (void)
293         printf ("\
294 Usage: %s -F <status log file> -e <expire_minutes> -C <process_string>\n", progname);