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 /* procetime is unused in most configurations, but may be in PS_VAR_LIST
59 * so it must be here in spite of it producing compiler warnings */
60 char procetime[MAX_INPUT_BUFFER];
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 printf (_("CRITICAL - Cannot open status log for reading!\n"));
89 return STATE_CRITICAL;
90 }
92 /* get the date/time of the last item updated in the log */
93 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
94 temp_ptr = strtok (input_buffer, "]");
95 temp_entry_time =
96 (temp_ptr == NULL) ? 0L : strtoul (temp_ptr + 1, NULL, 10);
97 if (temp_entry_time > latest_entry_time)
98 latest_entry_time = temp_entry_time;
99 }
100 fclose (fp);
102 if (verbose >= 2)
103 printf(_("command: %s\n"), PS_COMMAND);
105 /* run the command to check for the Nagios process.. */
106 if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0)
107 result = STATE_WARNING;
109 /* count the number of matching Nagios processes... */
110 for(i = 0; i < chld_out.lines; i++) {
111 cols = sscanf (chld_out.line[i], PS_FORMAT, PS_VARLIST);
112 /* Zombie processes do not give a procprog command */
113 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
114 cols = expected_cols;
115 /* Set some value for procargs for the strip command further below
116 * Seen to be a problem on some Solaris 7 and 8 systems */
117 chld_out.line[i][pos] = '\n';
118 chld_out.line[i][pos+1] = 0x0;
119 }
120 if ( cols >= expected_cols ) {
121 asprintf (&procargs, "%s", chld_out.line[i] + pos);
122 strip (procargs);
124 /* Some ps return full pathname for command. This removes path */
125 temp_string = strtok ((char *)procprog, "/");
126 while (temp_string) {
127 strcpy(procprog, temp_string);
128 temp_string = strtok (NULL, "/");
129 }
131 /* May get empty procargs */
132 if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) {
133 proc_entries++;
134 if (verbose >= 2) {
135 printf (_("Found process: %s %s\n"), procprog, procargs);
136 }
137 }
138 }
139 }
141 /* If we get anything on stderr, at least set warning */
142 if(chld_err.buflen)
143 result = max_state (result, STATE_WARNING);
145 /* reset the alarm handler */
146 alarm (0);
148 if (proc_entries == 0) {
149 printf (_("Could not locate a running Nagios process!\n"));
150 return STATE_CRITICAL;
151 }
153 result = STATE_OK;
155 time (¤t_time);
156 if ((int)(current_time - latest_entry_time) > (expire_minutes * 60))
157 result = STATE_WARNING;
159 printf
160 (_("Nagios %s: located %d process%s, status log updated %d second%s ago\n"),
161 (result == STATE_OK) ? "ok" : "problem", proc_entries,
162 (proc_entries == 1) ? "" : "es",
163 (int) (current_time - latest_entry_time),
164 ((int) (current_time - latest_entry_time) == 1) ? "" : "s");
166 return result;
167 }
171 /* process command-line arguments */
172 int
173 process_arguments (int argc, char **argv)
174 {
175 int c;
177 int option = 0;
178 static struct option longopts[] = {
179 {"filename", required_argument, 0, 'F'},
180 {"expires", required_argument, 0, 'e'},
181 {"command", required_argument, 0, 'C'},
182 {"version", no_argument, 0, 'V'},
183 {"help", no_argument, 0, 'h'},
184 {"verbose", no_argument, 0, 'v'},
185 {0, 0, 0, 0}
186 };
188 if (argc < 2)
189 return ERROR;
191 if (!is_option (argv[1])) {
192 status_log = argv[1];
193 if (is_intnonneg (argv[2]))
194 expire_minutes = atoi (argv[2]);
195 else
196 die (STATE_UNKNOWN,
197 _("Expiration time must be an integer (seconds)\n"));
198 process_string = argv[3];
199 return OK;
200 }
202 while (1) {
203 c = getopt_long (argc, argv, "+hVvF:C:e:", longopts, &option);
205 if (c == -1 || c == EOF || c == 1)
206 break;
208 switch (c) {
209 case 'h': /* help */
210 print_help ();
211 exit (STATE_OK);
212 case 'V': /* version */
213 print_revision (progname, revision);
214 exit (STATE_OK);
215 case 'F': /* status log */
216 status_log = optarg;
217 break;
218 case 'C': /* command */
219 process_string = optarg;
220 break;
221 case 'e': /* expiry time */
222 if (is_intnonneg (optarg))
223 expire_minutes = atoi (optarg);
224 else
225 die (STATE_UNKNOWN,
226 _("Expiration time must be an integer (seconds)\n"));
227 break;
228 case 'v':
229 verbose++;
230 break;
231 default: /* print short usage_va statement if args not parsable */
232 usage_va(_("Unknown argument - %s"), optarg);
233 }
234 }
237 if (status_log == NULL)
238 die (STATE_UNKNOWN, _("You must provide the status_log\n"));
240 if (process_string == NULL)
241 die (STATE_UNKNOWN, _("You must provide a process string\n"));
243 return OK;
244 }
248 void
249 print_help (void)
250 {
251 print_revision (progname, revision);
253 printf (_(COPYRIGHT), copyright, email);
255 printf (_("\
256 This plugin checks the status of the Nagios process on the local\n\
257 machine. The plugin will check to make sure the Nagios status log is no older\n\
258 than the number of minutes specified by the expires option. It also\n\
259 checks the process table for a process matching the command argument.\n\n"));
261 print_usage ();
263 printf (_(UT_HELP_VRSN));
265 printf (_("\
266 -F, --filename=FILE\n\
267 Name of the log file to check\n\
268 -e, --expires=INTEGER\n\
269 Minutes aging after which logfile is considered stale\n\
270 -C, --command=STRING\n\
271 Substring to search for in process arguments\n"));
273 printf (_("\
274 Example:\n\
275 ./check_nagios -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios\n"));
276 }
280 void
281 print_usage (void)
282 {
283 printf ("\
284 Usage: %s -F <status log file> -e <expire_minutes> -C <process_string>\n", progname);
285 }