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 ******************************************************************************/
19 const char *progname = "check_nagios";
20 const char *revision = "$Revision$";
21 const char *copyright = "1999-2003";
22 const char *email = "nagiosplug-devel@lists.sourceforge.net";
24 #include "common.h"
25 #include "popen.h"
26 #include "utils.h"
28 int process_arguments (int, char **);
29 void print_help (void);
30 void print_usage (void);
32 char *status_log = NULL;
33 char *process_string = NULL;
34 int expire_minutes = 0;
36 int verbose = 0;
38 int
39 main (int argc, char **argv)
40 {
41 int result = STATE_UNKNOWN;
42 char input_buffer[MAX_INPUT_BUFFER];
43 unsigned long latest_entry_time = 0L;
44 unsigned long temp_entry_time = 0L;
45 int proc_entries = 0;
46 time_t current_time;
47 char *temp_ptr;
48 FILE *fp;
49 int procuid = 0;
50 int procppid = 0;
51 int procvsz = 0;
52 int procrss = 0;
53 float procpcpu = 0;
54 char procstat[8];
55 char procprog[MAX_INPUT_BUFFER];
56 char *procargs;
57 int pos, cols;
58 int expected_cols = PS_COLS - 1;
59 const char *zombie = "Z";
60 char *temp_string;
62 setlocale (LC_ALL, "");
63 bindtextdomain (PACKAGE, LOCALEDIR);
64 textdomain (PACKAGE);
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 if (verbose >= 2)
96 printf("command: %s\n", PS_COMMAND);
98 /* run the command to check for the Nagios process.. */
99 child_process = spopen (PS_COMMAND);
100 if (child_process == NULL) {
101 printf (_("Could not open pipe: %s\n"), PS_COMMAND);
102 return STATE_UNKNOWN;
103 }
105 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
106 if (child_stderr == NULL) {
107 printf (_("Could not open stderr for %s\n"), PS_COMMAND);
108 }
110 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
112 /* count the number of matching Nagios processes... */
113 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
114 cols = sscanf (input_buffer, PS_FORMAT, PS_VARLIST);
115 /* Zombie processes do not give a procprog command */
116 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
117 cols = expected_cols;
118 /* Set some value for procargs for the strip command further below
119 Seen to be a problem on some Solaris 7 and 8 systems */
120 input_buffer[pos] = '\n';
121 input_buffer[pos+1] = 0x0;
122 }
123 if ( cols >= expected_cols ) {
124 asprintf (&procargs, "%s", input_buffer + pos);
125 strip (procargs);
127 /* Some ps return full pathname for command. This removes path */
128 temp_string = strtok ((char *)procprog, "/");
129 while (temp_string) {
130 strcpy(procprog, temp_string);
131 temp_string = strtok (NULL, "/");
132 }
134 /* May get empty procargs */
135 if (!strstr(procargs, argv[0]) && strstr(procprog, process_string) && strcmp(procargs,"")) {
136 proc_entries++;
137 if (verbose >= 2) {
138 printf (_("Found process: %s %s\n"), procprog, procargs);
139 }
140 }
141 }
142 }
144 /* If we get anything on stderr, at least set warning */
145 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
146 result = max_state (result, STATE_WARNING);
148 /* close stderr */
149 (void) fclose (child_stderr);
151 /* close the pipe */
152 if (spclose (child_process))
153 result = max_state (result, STATE_WARNING);
155 /* reset the alarm handler */
156 alarm (0);
158 if (proc_entries == 0) {
159 printf (_("Could not locate a running Nagios process!\n"));
160 return STATE_CRITICAL;
161 }
163 result = STATE_OK;
165 time (¤t_time);
166 if ((int)(current_time - latest_entry_time) > (expire_minutes * 60))
167 result = STATE_WARNING;
169 printf
170 (_("Nagios %s: located %d process%s, status log updated %d second%s ago\n"),
171 (result == STATE_OK) ? "ok" : "problem", proc_entries,
172 (proc_entries == 1) ? "" : "es",
173 (int) (current_time - latest_entry_time),
174 ((int) (current_time - latest_entry_time) == 1) ? "" : "s");
176 return result;
177 }
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)\nType '%s -h' for additional help\n"),
210 progname);
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 printf (_("%s: Unknown argument: %c\n\n"), progname, optopt);
224 print_usage ();
225 exit (STATE_UNKNOWN);
226 case 'h': /* help */
227 print_help ();
228 exit (STATE_OK);
229 case 'V': /* version */
230 print_revision (progname, "$Revision$");
231 exit (STATE_OK);
232 case 'F': /* status log */
233 status_log = optarg;
234 break;
235 case 'C': /* command */
236 process_string = optarg;
237 break;
238 case 'e': /* expiry time */
239 if (is_intnonneg (optarg))
240 expire_minutes = atoi (optarg);
241 else
242 die (STATE_UNKNOWN,
243 _("Expiration time must be an integer (seconds)\nType '%s -h' for additional help\n"),
244 progname);
245 break;
246 case 'v':
247 verbose++;
248 break;
249 }
250 }
253 if (status_log == NULL)
254 die (STATE_UNKNOWN,
255 _("You must provide the status_log\nType '%s -h' for additional help\n"),
256 progname);
257 else if (process_string == NULL)
258 die (STATE_UNKNOWN,
259 _("You must provide a process string\nType '%s -h' for additional help\n"),
260 progname);
262 return OK;
263 }
269 \f
270 void
271 print_help (void)
272 {
273 print_revision (progname, revision);
275 printf (_(COPYRIGHT), copyright, email);
277 printf (_("\
278 This plugin attempts to check the status of the Nagios process on the local\n\
279 machine. The plugin will check to make sure the Nagios status log is no older\n\
280 than the number of minutes specified by the <expire_minutes> option. It also\n\
281 uses the /bin/ps command to check for a process matching whatever you specify\n\
282 by the <process_string> argument.\n"));
284 print_usage ();
286 printf (_(UT_HELP_VRSN));
288 printf (_("\
289 -F, --filename=FILE\n\
290 Name of the log file to check\n\
291 -e, --expires=INTEGER\n\
292 Seconds aging afterwhich logfile is condsidered stale\n\
293 -C, --command=STRING\n\
294 Command to search for in process table\n"));
296 printf (_("\
297 Example:\n\
298 ./check_nagios -e 5 \\\
299 -F /usr/local/nagios/var/status.log \\\
300 -C /usr/local/nagios/bin/nagios\n"));
301 }
306 void
307 print_usage (void)
308 {
309 printf (_("\
310 Usage: %s -F <status log file> -e <expire_minutes> -C <process_string>\n"),
311 progname);
312 }