Code

089ff669702a96bb0d0a2b297f3ba7a9e9fb3a2b
[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 "popen.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         char procetime[MAX_INPUT_BUFFER];
59         char procprog[MAX_INPUT_BUFFER];
60         char *procargs;
61         int pos, cols;
62         int expected_cols = PS_COLS - 1;
63         const char *zombie = "Z";
64         char *temp_string;
66         setlocale (LC_ALL, "");
67         bindtextdomain (PACKAGE, LOCALEDIR);
68         textdomain (PACKAGE);
70         if (process_arguments (argc, argv) == ERROR)
71                 usage4 (_("Could not parse arguments"));
73         /* Set signal handling and alarm timeout */
74         if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
75                 usage4 (_("Cannot catch SIGALRM"));
76         }
78         /* handle timeouts gracefully... */
79         alarm (timeout_interval);
81         /* open the status log */
82         fp = fopen (status_log, "r");
83         if (fp == NULL) {
84                 printf (_("CRITICAL - Cannot open status log for reading!\n"));
85                 return STATE_CRITICAL;
86         }
88         /* get the date/time of the last item updated in the log */
89         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
90                 temp_ptr = strtok (input_buffer, "]");
91                 temp_entry_time =
92                         (temp_ptr == NULL) ? 0L : strtoul (temp_ptr + 1, NULL, 10);
93                 if (temp_entry_time > latest_entry_time)
94                         latest_entry_time = temp_entry_time;
95         }
96         fclose (fp);
98         if (verbose >= 2)
99                 printf(_("command: %s\n"), PS_COMMAND);
101         /* run the command to check for the Nagios process.. */
102         child_process = spopen (PS_COMMAND);
103         if (child_process == NULL) {
104                 printf (_("Could not open pipe: %s\n"), PS_COMMAND);
105                 return STATE_UNKNOWN;
106         }
108         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
109         if (child_stderr == NULL) {
110                 printf (_("Could not open stderr for %s\n"), PS_COMMAND);
111         }
113         fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
115         /* count the number of matching Nagios processes... */
116         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
117                 cols = sscanf (input_buffer, PS_FORMAT, PS_VARLIST);
118                 /* Zombie processes do not give a procprog command */
119                 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
120                         cols = expected_cols;
121                         /* Set some value for procargs for the strip command further below
122                         Seen to be a problem on some Solaris 7 and 8 systems */
123                         input_buffer[pos] = '\n';
124                         input_buffer[pos+1] = 0x0;
125                 }
126                 if ( cols >= expected_cols ) {
127                         asprintf (&procargs, "%s", input_buffer + pos);
128                         strip (procargs);
129                         
130                         /* Some ps return full pathname for command. This removes path */
131                         temp_string = strtok ((char *)procprog, "/");
132                         while (temp_string) {
133                                 strcpy(procprog, temp_string);
134                                 temp_string = strtok (NULL, "/");
135                         }
137                         /* May get empty procargs */
138                         if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) {
139                                 proc_entries++;
140                                 if (verbose >= 2) {
141                                         printf (_("Found process: %s %s\n"), procprog, procargs);
142                                 }
143                         }
144                 }
145         }
147         /* If we get anything on stderr, at least set warning */
148         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
149                 result = max_state (result, STATE_WARNING);
151         /* close stderr */
152         (void) fclose (child_stderr);
154         /* close the pipe */
155         if (spclose (child_process))
156                 result = max_state (result, STATE_WARNING);
158         /* reset the alarm handler */
159         alarm (0);
161         if (proc_entries == 0) {
162                 printf (_("Could not locate a running Nagios process!\n"));
163                 return STATE_CRITICAL;
164         }
166         result = STATE_OK;
168         time (&current_time);
169         if ((int)(current_time - latest_entry_time) > (expire_minutes * 60))
170                 result = STATE_WARNING;
172         printf
173                 (_("Nagios %s: located %d process%s, status log updated %d second%s ago\n"),
174                  (result == STATE_OK) ? "ok" : "problem", proc_entries,
175                  (proc_entries == 1) ? "" : "es",
176                  (int) (current_time - latest_entry_time),
177                  ((int) (current_time - latest_entry_time) == 1) ? "" : "s");
179         return result;
184 /* process command-line arguments */
185 int
186 process_arguments (int argc, char **argv)
188         int c;
190         int option = 0;
191         static struct option longopts[] = {
192                 {"filename", required_argument, 0, 'F'},
193                 {"expires", required_argument, 0, 'e'},
194                 {"command", required_argument, 0, 'C'},
195                 {"version", no_argument, 0, 'V'},
196                 {"help", no_argument, 0, 'h'},
197                 {"verbose", no_argument, 0, 'v'},
198                 {0, 0, 0, 0}
199         };
201         if (argc < 2)
202                 return ERROR;
204         if (!is_option (argv[1])) {
205                 status_log = argv[1];
206                 if (is_intnonneg (argv[2]))
207                         expire_minutes = atoi (argv[2]);
208                 else
209                         die (STATE_UNKNOWN,
210                                                                  _("Expiration time must be an integer (seconds)\n"));
211                 process_string = argv[3];
212                 return OK;
213         }
215         while (1) {
216                 c = getopt_long (argc, argv, "+hVvF:C:e:", longopts, &option);
218                 if (c == -1 || c == EOF || c == 1)
219                         break;
221                 switch (c) {
222                 case '?':                                                                       /* print short usage statement if args not parsable */
223                         usage2 (_("Unknown argument"), optarg);
224                 case 'h':                                                                       /* help */
225                         print_help ();
226                         exit (STATE_OK);
227                 case 'V':                                                                       /* version */
228                         print_revision (progname, revision);
229                         exit (STATE_OK);
230                 case 'F':                                                                       /* status log */
231                         status_log = optarg;
232                         break;
233                 case 'C':                                                                       /* command */
234                         process_string = optarg;
235                         break;
236                 case 'e':                                                                       /* expiry time */
237                         if (is_intnonneg (optarg))
238                                 expire_minutes = atoi (optarg);
239                         else
240                                 die (STATE_UNKNOWN,
241                                      _("Expiration time must be an integer (seconds)\n"));
242                         break;
243                 case 'v':
244                         verbose++;
245                         break;
246                 }
247         }
250         if (status_log == NULL)
251                 die (STATE_UNKNOWN,
252                      _("You must provide the status_log\n"));
253         else if (process_string == NULL)
254                 die (STATE_UNKNOWN,
255                                                          _("You must provide a process string\n"));
257         return OK;
262 void
263 print_help (void)
265         print_revision (progname, revision);
267         printf (_(COPYRIGHT), copyright, email);
269         printf (_("\
270 This plugin checks the status of the Nagios process on the local\n\
271 machine. The plugin will check to make sure the Nagios status log is no older\n\
272 than the number of minutes specified by the expires option. It also\n\
273 checks the process table for a process matching the command argument.\n\n"));
275         print_usage ();
277         printf (_(UT_HELP_VRSN));
279         printf (_("\
280  -F, --filename=FILE\n\
281    Name of the log file to check\n\
282  -e, --expires=INTEGER\n\
283    Minutes aging after which logfile is considered stale\n\
284  -C, --command=STRING\n\
285    Substring to search for in process arguments\n"));
287         printf (_("\
288 Example:\n\
289    ./check_nagios -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios\n"));
294 void
295 print_usage (void)
297         printf ("\
298 Usage: %s -F <status log file> -e <expire_minutes> -C <process_string>\n", progname);