1 /******************************************************************************
2 *
3 * CHECK_NAGIOS.C
4 *
5 * Program: Nagios process plugin for Nagios
6 * License: GPL
7 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
8 *
9 * $Id$
10 *
11 * License Information:
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 *****************************************************************************/
29 #include "common.h"
30 #include "popen.h"
31 #include "utils.h"
33 const char *progname = "check_nagios";
35 int process_arguments (int, char **);
36 void print_usage (void);
37 void print_help (void);
39 char *status_log = NULL;
40 char *process_string = NULL;
41 int expire_minutes = 0;
43 int verbose = 0;
45 int
46 main (int argc, char **argv)
47 {
48 int result = STATE_UNKNOWN;
49 char input_buffer[MAX_INPUT_BUFFER];
50 unsigned long latest_entry_time = 0L;
51 unsigned long temp_entry_time = 0L;
52 int proc_entries = 0;
53 time_t current_time;
54 char *temp_ptr;
55 FILE *fp;
56 int procuid = 0;
57 int procppid = 0;
58 int procvsz = 0;
59 int procrss = 0;
60 float procpcpu = 0;
61 char procstat[8];
62 char procprog[MAX_INPUT_BUFFER];
63 char *procargs;
64 int pos, cols;
66 if (process_arguments (argc, argv) == ERROR)
67 usage ("Could not parse arguments\n");
69 /* Set signal handling and alarm */
70 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
71 printf ("Cannot catch SIGALRM");
72 return STATE_UNKNOWN;
73 }
75 /* handle timeouts gracefully... */
76 alarm (timeout_interval);
78 /* open the status log */
79 fp = fopen (status_log, "r");
80 if (fp == NULL) {
81 printf ("Error: Cannot open status log for reading!\n");
82 return STATE_CRITICAL;
83 }
85 /* get the date/time of the last item updated in the log */
86 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
87 temp_ptr = strtok (input_buffer, "]");
88 temp_entry_time =
89 (temp_ptr == NULL) ? 0L : strtoul (temp_ptr + 1, NULL, 10);
90 if (temp_entry_time > latest_entry_time)
91 latest_entry_time = temp_entry_time;
92 }
93 fclose (fp);
95 /* run the command to check for the Nagios process.. */
96 child_process = spopen (PS_COMMAND);
97 if (child_process == NULL) {
98 printf ("Could not open pipe: %s\n", PS_COMMAND);
99 return STATE_UNKNOWN;
100 }
102 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
103 if (child_stderr == NULL) {
104 printf ("Could not open stderr for %s\n", PS_COMMAND);
105 }
107 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
109 /* count the number of matching Nagios processes... */
110 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
111 cols = sscanf (input_buffer, PS_FORMAT, PS_VARLIST);
112 if ( cols >= 6 ) {
113 asprintf (&procargs, "%s", input_buffer + pos);
114 strip (procargs);
116 if (!strstr(procargs, argv[0]) && strstr(procargs, process_string)) {
117 proc_entries++;
118 if (verbose)
119 printf ("Found process: %s\n", procargs);
120 }
121 }
122 }
124 /* If we get anything on stderr, at least set warning */
125 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
126 result = max_state (result, STATE_WARNING);
128 /* close stderr */
129 (void) fclose (child_stderr);
131 /* close the pipe */
132 if (spclose (child_process))
133 result = max_state (result, STATE_WARNING);
135 /* reset the alarm handler */
136 alarm (0);
138 if (proc_entries == 0) {
139 printf ("Could not locate a running Nagios process!\n");
140 return STATE_CRITICAL;
141 }
143 result = STATE_OK;
145 time (¤t_time);
146 if ((current_time - latest_entry_time) > (expire_minutes * 60))
147 result = STATE_WARNING;
149 printf
150 ("Nagios %s: located %d process%s, status log updated %d second%s ago\n",
151 (result == STATE_OK) ? "ok" : "problem", proc_entries,
152 (proc_entries == 1) ? "" : "es",
153 (int) (current_time - latest_entry_time),
154 ((int) (current_time - latest_entry_time) == 1) ? "" : "s");
156 return result;
157 }
163 /* process command-line arguments */
164 int
165 process_arguments (int argc, char **argv)
166 {
167 int c;
169 int option_index = 0;
170 static struct option long_options[] = {
171 {"filename", required_argument, 0, 'F'},
172 {"expires", required_argument, 0, 'e'},
173 {"command", required_argument, 0, 'C'},
174 {"version", no_argument, 0, 'V'},
175 {"help", no_argument, 0, 'h'},
176 {"verbose", no_argument, 0, 'v'},
177 {0, 0, 0, 0}
178 };
180 if (argc < 2)
181 return ERROR;
183 if (!is_option (argv[1])) {
184 status_log = argv[1];
185 if (is_intnonneg (argv[2]))
186 expire_minutes = atoi (argv[2]);
187 else
188 terminate (STATE_UNKNOWN,
189 "Expiration time must be an integer (seconds)\nType '%s -h' for additional help\n",
190 progname);
191 process_string = argv[3];
192 return OK;
193 }
195 while (1) {
196 c = getopt_long (argc, argv, "+hVvF:C:e:", long_options, &option_index);
198 if (c == -1 || c == EOF || c == 1)
199 break;
201 switch (c) {
202 case '?': /* print short usage statement if args not parsable */
203 printf ("%s: Unknown argument: %c\n\n", progname, optopt);
204 print_usage ();
205 exit (STATE_UNKNOWN);
206 case 'h': /* help */
207 print_help ();
208 exit (STATE_OK);
209 case 'V': /* version */
210 print_revision (progname, "$Revision$");
211 exit (STATE_OK);
212 case 'F': /* status log */
213 status_log = optarg;
214 break;
215 case 'C': /* command */
216 process_string = optarg;
217 break;
218 case 'e': /* expiry time */
219 if (is_intnonneg (optarg))
220 expire_minutes = atoi (optarg);
221 else
222 terminate (STATE_UNKNOWN,
223 "Expiration time must be an integer (seconds)\nType '%s -h' for additional help\n",
224 progname);
225 break;
226 case 'v':
227 verbose++;
228 break;
229 }
230 }
233 if (status_log == NULL)
234 terminate (STATE_UNKNOWN,
235 "You must provide the status_log\nType '%s -h' for additional help\n",
236 progname);
237 else if (process_string == NULL)
238 terminate (STATE_UNKNOWN,
239 "You must provide a process string\nType '%s -h' for additional help\n",
240 progname);
242 return OK;
243 }
249 void
250 print_usage (void)
251 {
252 printf
253 ("Usage: %s -F <status log file> -e <expire_minutes> -C <process_string>\n",
254 progname);
255 }
261 void
262 print_help (void)
263 {
264 print_revision (progname, "$Revision$");
265 printf
266 ("Copyright (c) 2000 Ethan Galstad/Karl DeBisschop\n\n"
267 "This plugin attempts to check the status of the Nagios process on the local\n"
268 "machine. The plugin will check to make sure the Nagios status log is no older\n"
269 "than the number of minutes specified by the <expire_minutes> option. It also\n"
270 "uses the /bin/ps command to check for a process matching whatever you specify\n"
271 "by the <process_string> argument.\n");
272 print_usage ();
273 printf
274 ("\nOptions:\n"
275 "-F, --filename=FILE\n"
276 " Name of the log file to check\n"
277 "-e, --expires=INTEGER\n"
278 " Seconds aging afterwhich logfile is condsidered stale\n"
279 "-C, --command=STRING\n"
280 " Command to search for in process table\n"
281 "-h, --help\n"
282 " Print this help screen\n"
283 "-V, --version\n"
284 " Print version information\n\n"
285 "Example:\n"
286 " ./check_nagios -F /usr/local/nagios/var/status.log -e 5 -C /usr/local/nagios/bin/nagios\n");
287 }