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