Code

initial merging of ae's np_runcmd code into selected plugins.
[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         /* procetime is unused in most configurations, but may be in PS_VAR_LIST
59          * so it must be here in spite of it producing compiler warnings */
60         char procetime[MAX_INPUT_BUFFER];
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                 printf (_("CRITICAL - Cannot open status log for reading!\n"));
89                 return STATE_CRITICAL;
90         }
92         /* get the date/time of the last item updated in the log */
93         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
94                 temp_ptr = strtok (input_buffer, "]");
95                 temp_entry_time =
96                         (temp_ptr == NULL) ? 0L : strtoul (temp_ptr + 1, NULL, 10);
97                 if (temp_entry_time > latest_entry_time)
98                         latest_entry_time = temp_entry_time;
99         }
100         fclose (fp);
102         if (verbose >= 2)
103                 printf(_("command: %s\n"), PS_COMMAND);
105         /* run the command to check for the Nagios process.. */
106         if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0)
107                 result = STATE_WARNING;
109         /* count the number of matching Nagios processes... */
110         for(i = 0; i < chld_out.lines; i++) {
111                 cols = sscanf (chld_out.line[i], PS_FORMAT, PS_VARLIST);
112                 /* Zombie processes do not give a procprog command */
113                 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
114                         cols = expected_cols;
115                         /* Set some value for procargs for the strip command further below
116                          * Seen to be a problem on some Solaris 7 and 8 systems */
117                         chld_out.line[i][pos] = '\n';
118                         chld_out.line[i][pos+1] = 0x0;
119                 }
120                 if ( cols >= expected_cols ) {
121                         asprintf (&procargs, "%s", chld_out.line[i] + pos);
122                         strip (procargs);
124                         /* Some ps return full pathname for command. This removes path */
125                         temp_string = strtok ((char *)procprog, "/");
126                         while (temp_string) {
127                                 strcpy(procprog, temp_string);
128                                 temp_string = strtok (NULL, "/");
129                         }
131                         /* May get empty procargs */
132                         if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) {
133                                 proc_entries++;
134                                 if (verbose >= 2) {
135                                         printf (_("Found process: %s %s\n"), procprog, procargs);
136                                 }
137                         }
138                 }
139         }
141         /* If we get anything on stderr, at least set warning */
142         if(chld_err.buflen)
143                 result = max_state (result, STATE_WARNING);
145         /* reset the alarm handler */
146         alarm (0);
148         if (proc_entries == 0) {
149                 printf (_("Could not locate a running Nagios process!\n"));
150                 return STATE_CRITICAL;
151         }
153         result = STATE_OK;
155         time (&current_time);
156         if ((int)(current_time - latest_entry_time) > (expire_minutes * 60))
157                 result = STATE_WARNING;
159         printf
160                 (_("Nagios %s: located %d process%s, status log updated %d second%s ago\n"),
161                  (result == STATE_OK) ? "ok" : "problem", proc_entries,
162                  (proc_entries == 1) ? "" : "es",
163                  (int) (current_time - latest_entry_time),
164                  ((int) (current_time - latest_entry_time) == 1) ? "" : "s");
166         return result;
171 /* process command-line arguments */
172 int
173 process_arguments (int argc, char **argv)
175         int c;
177         int option = 0;
178         static struct option longopts[] = {
179                 {"filename", required_argument, 0, 'F'},
180                 {"expires", required_argument, 0, 'e'},
181                 {"command", required_argument, 0, 'C'},
182                 {"version", no_argument, 0, 'V'},
183                 {"help", no_argument, 0, 'h'},
184                 {"verbose", no_argument, 0, 'v'},
185                 {0, 0, 0, 0}
186         };
188         if (argc < 2)
189                 return ERROR;
191         if (!is_option (argv[1])) {
192                 status_log = argv[1];
193                 if (is_intnonneg (argv[2]))
194                         expire_minutes = atoi (argv[2]);
195                 else
196                         die (STATE_UNKNOWN,
197                                                                  _("Expiration time must be an integer (seconds)\n"));
198                 process_string = argv[3];
199                 return OK;
200         }
202         while (1) {
203                 c = getopt_long (argc, argv, "+hVvF:C:e:", longopts, &option);
205                 if (c == -1 || c == EOF || c == 1)
206                         break;
208                 switch (c) {
209                 case 'h':                                                                       /* help */
210                         print_help ();
211                         exit (STATE_OK);
212                 case 'V':                                                                       /* version */
213                         print_revision (progname, revision);
214                         exit (STATE_OK);
215                 case 'F':                                                                       /* status log */
216                         status_log = optarg;
217                         break;
218                 case 'C':                                                                       /* command */
219                         process_string = optarg;
220                         break;
221                 case 'e':                                                                       /* expiry time */
222                         if (is_intnonneg (optarg))
223                                 expire_minutes = atoi (optarg);
224                         else
225                                 die (STATE_UNKNOWN,
226                                      _("Expiration time must be an integer (seconds)\n"));
227                         break;
228                 case 'v':
229                         verbose++;
230                         break;
231                 default:                                                                        /* print short usage_va statement if args not parsable */
232                         usage_va(_("Unknown argument - %s"), optarg);
233                 }
234         }
237         if (status_log == NULL)
238                 die (STATE_UNKNOWN, _("You must provide the status_log\n"));
240         if (process_string == NULL)
241                 die (STATE_UNKNOWN, _("You must provide a process string\n"));
243         return OK;
248 void
249 print_help (void)
251         print_revision (progname, revision);
253         printf (_(COPYRIGHT), copyright, email);
255         printf (_("\
256 This plugin checks the status of the Nagios process on the local\n\
257 machine. The plugin will check to make sure the Nagios status log is no older\n\
258 than the number of minutes specified by the expires option. It also\n\
259 checks the process table for a process matching the command argument.\n\n"));
261         print_usage ();
263         printf (_(UT_HELP_VRSN));
265         printf (_("\
266  -F, --filename=FILE\n\
267    Name of the log file to check\n\
268  -e, --expires=INTEGER\n\
269    Minutes aging after which logfile is considered stale\n\
270  -C, --command=STRING\n\
271    Substring to search for in process arguments\n"));
273         printf (_("\
274 Example:\n\
275    ./check_nagios -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios\n"));
280 void
281 print_usage (void)
283         printf ("\
284 Usage: %s -F <status log file> -e <expire_minutes> -C <process_string>\n", progname);