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$
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);
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 (¤t_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;
180 }
184 /* process command-line arguments */
185 int
186 process_arguments (int argc, char **argv)
187 {
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;
258 }
262 void
263 print_help (void)
264 {
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"));
290 }
294 void
295 print_usage (void)
296 {
297 printf ("\
298 Usage: %s -F <status log file> -e <expire_minutes> -C <process_string>\n", progname);
299 }