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 "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 #ifdef PS_USES_PROCETIME
59 char procetime[MAX_INPUT_BUFFER];
60 #endif /* PS_USES_PROCETIME */
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 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!"));
89 }
91 /* get the date/time of the last item updated in the log */
92 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
93 if ((temp_ptr = strstr (input_buffer, "created=")) != NULL) {
94 temp_entry_time = strtoul (temp_ptr + 8, NULL, 10);
95 latest_entry_time = temp_entry_time;
96 break;
97 } else if ((temp_ptr = strtok (input_buffer, "]")) != NULL) {
98 temp_entry_time = strtoul (temp_ptr + 1, NULL, 10);
99 if (temp_entry_time > latest_entry_time)
100 latest_entry_time = temp_entry_time;
101 }
102 }
103 fclose (fp);
105 if (verbose >= 2)
106 printf("command: %s\n", PS_COMMAND);
108 /* run the command to check for the Nagios process.. */
109 if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0)
110 result = STATE_WARNING;
112 /* count the number of matching Nagios processes... */
113 for(i = 0; i < chld_out.lines; i++) {
114 cols = sscanf (chld_out.line[i], 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 chld_out.line[i][pos] = '\n';
121 chld_out.line[i][pos+1] = 0x0;
122 }
123 if ( cols >= expected_cols ) {
124 asprintf (&procargs, "%s", chld_out.line[i] + 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(procargs, 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 if(chld_err.buflen)
146 result = max_state (result, STATE_WARNING);
148 /* reset the alarm handler */
149 alarm (0);
151 if (proc_entries == 0) {
152 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Could not locate a running Nagios process!"));
153 }
155 if (latest_entry_time == 0L) {
156 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time"));
157 }
159 time (¤t_time);
160 if ((int)(current_time - latest_entry_time) > (expire_minutes * 60)) {
161 result = STATE_WARNING;
162 } else {
163 result = STATE_OK;
164 }
166 printf ("NAGIOS %s: ", (result == STATE_OK) ? _("OK") : _("WARNING"));
167 printf (ngettext ("%d process", "%d processes", proc_entries), proc_entries);
168 printf (", ");
169 printf (
170 ngettext ("status log updated %d second ago",
171 "status log updated %d seconds ago",
172 (int) (current_time - latest_entry_time) ),
173 (int) (current_time - latest_entry_time) );
174 printf ("\n");
176 return result;
177 }
181 /* process command-line arguments */
182 int
183 process_arguments (int argc, char **argv)
184 {
185 int c;
187 int option = 0;
188 static struct option longopts[] = {
189 {"filename", required_argument, 0, 'F'},
190 {"expires", required_argument, 0, 'e'},
191 {"command", required_argument, 0, 'C'},
192 {"version", no_argument, 0, 'V'},
193 {"help", no_argument, 0, 'h'},
194 {"verbose", no_argument, 0, 'v'},
195 {0, 0, 0, 0}
196 };
198 if (argc < 2)
199 return ERROR;
201 if (!is_option (argv[1])) {
202 status_log = argv[1];
203 if (is_intnonneg (argv[2]))
204 expire_minutes = atoi (argv[2]);
205 else
206 die (STATE_UNKNOWN,
207 _("Expiration time must be an integer (seconds)\n"));
208 process_string = argv[3];
209 return OK;
210 }
212 while (1) {
213 c = getopt_long (argc, argv, "+hVvF:C:e:", longopts, &option);
215 if (c == -1 || c == EOF || c == 1)
216 break;
218 switch (c) {
219 case 'h': /* help */
220 print_help ();
221 exit (STATE_OK);
222 case 'V': /* version */
223 print_revision (progname, revision);
224 exit (STATE_OK);
225 case 'F': /* status log */
226 status_log = optarg;
227 break;
228 case 'C': /* command */
229 process_string = optarg;
230 break;
231 case 'e': /* expiry time */
232 if (is_intnonneg (optarg))
233 expire_minutes = atoi (optarg);
234 else
235 die (STATE_UNKNOWN,
236 _("Expiration time must be an integer (seconds)\n"));
237 break;
238 case 'v':
239 verbose++;
240 break;
241 default: /* print short usage_va statement if args not parsable */
242 usage_va(_("Unknown argument - %s"), optarg);
243 }
244 }
247 if (status_log == NULL)
248 die (STATE_UNKNOWN, _("You must provide the status_log\n"));
250 if (process_string == NULL)
251 die (STATE_UNKNOWN, _("You must provide a process string\n"));
253 return OK;
254 }
258 void
259 print_help (void)
260 {
261 print_revision (progname, revision);
263 printf (_(COPYRIGHT), copyright, email);
265 printf (_("\
266 This plugin checks the status of the Nagios process on the local\n\
267 machine. The plugin will check to make sure the Nagios status log is no older\n\
268 than the number of minutes specified by the expires option. It also\n\
269 checks the process table for a process matching the command argument.\n\n"));
271 print_usage ();
273 printf (_(UT_HELP_VRSN));
275 printf (_("\
276 -F, --filename=FILE\n\
277 Name of the log file to check\n\
278 -e, --expires=INTEGER\n\
279 Minutes aging after which logfile is considered stale\n\
280 -C, --command=STRING\n\
281 Substring to search for in process arguments\n"));
283 printf (_("\
284 Example:\n\
285 ./check_nagios -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios\n"));
286 }
290 void
291 print_usage (void)
292 {
293 printf ("\
294 Usage: %s -F <status log file> -e <expire_minutes> -C <process_string>\n", progname);
295 }