1 /*****************************************************************************
2 *
3 * Monitoring check_nagios plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2007 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_nagios plugin
11 *
12 * This plugin checks the status of the Nagios process on the local machine.
13 * The plugin will check to make sure the Nagios status log is no older than
14 * the number of minutes specified by the expires option.
15 * It also checks the process table for a process matching the command
16 * argument.
17 *
18 *
19 * This program is free software: you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation, either version 3 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
31 *
32 *
33 *****************************************************************************/
34 
35 const char *progname = "check_nagios";
36 const char *copyright = "1999-2007";
37 const char *email = "devel@monitoring-plugins.org";
38 
39 #include "common.h"
40 #include "runcmd.h"
41 #include "utils.h"
42 
43 int process_arguments (int, char **);
44 void print_help (void);
45 void print_usage (void);
46 
47 char *status_log = NULL;
48 char *process_string = NULL;
49 int expire_minutes = 0;
50 
51 int verbose = 0;
52 
53 int
main(int argc,char ** argv)54 main (int argc, char **argv)
55 {
56 	int result = STATE_UNKNOWN;
57 	char input_buffer[MAX_INPUT_BUFFER];
58 	unsigned long latest_entry_time = 0L;
59 	unsigned long temp_entry_time = 0L;
60 	int proc_entries = 0;
61 	time_t current_time;
62 	char *temp_ptr;
63 	FILE *fp;
64 	int procuid = 0;
65 	int procpid = 0;
66 	int procppid = 0;
67 	int procjid = 0;
68 	int procvsz = 0;
69 	int procrss = 0;
70 	float procpcpu = 0;
71 	char procstat[8];
72 #ifdef PS_USES_PROCETIME
73 	char procetime[MAX_INPUT_BUFFER];
74 #endif /* PS_USES_PROCETIME */
75 	char procprog[MAX_INPUT_BUFFER];
76 	char *procargs;
77 	int pos, cols;
78 	int expected_cols = PS_COLS - 1;
79 	const char *zombie = "Z";
80 	char *temp_string;
81 	output chld_out, chld_err;
82 	size_t i;
83 
84 	setlocale (LC_ALL, ""); setlocale(LC_NUMERIC, "C");
85 	bindtextdomain (PACKAGE, LOCALEDIR);
86 	textdomain (PACKAGE);
87 
88 	/* Parse extra opts if any */
89 	argv=np_extra_opts (&argc, argv, progname);
90 
91 	if (process_arguments (argc, argv) == ERROR)
92 		usage_va(_("Could not parse arguments"));
93 
94 	/* Set signal handling and alarm timeout */
95 	if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
96 		usage_va(_("Cannot catch SIGALRM"));
97 	}
98 
99 	/* handle timeouts gracefully... */
100 	alarm (timeout_interval);
101 
102 	/* open the status log */
103 	fp = fopen (status_log, "r");
104 	if (fp == NULL) {
105 		die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!"));
106 	}
107 
108 	/* get the date/time of the last item updated in the log */
109 	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
110 		if ((temp_ptr = strstr (input_buffer, "created=")) != NULL) {
111 			temp_entry_time = strtoul (temp_ptr + 8, NULL, 10);
112 			latest_entry_time = temp_entry_time;
113 			break;
114 		} else if ((temp_ptr = strtok (input_buffer, "]")) != NULL) {
115 			temp_entry_time = strtoul (temp_ptr + 1, NULL, 10);
116 			if (temp_entry_time > latest_entry_time)
117 				latest_entry_time = temp_entry_time;
118 		}
119 	}
120 	fclose (fp);
121 
122 	if (verbose >= 2)
123 		printf("command: %s\n", PS_COMMAND);
124 
125 	/* run the command to check for the Nagios process.. */
126 	if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0)
127 		result = STATE_WARNING;
128 
129 	/* count the number of matching Nagios processes... */
130 	for(i = 0; i < chld_out.lines; i++) {
131 		cols = sscanf (chld_out.line[i], PS_FORMAT, PS_VARLIST);
132 		/* Zombie processes do not give a procprog command */
133 		if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) {
134 			cols = expected_cols;
135 			/* Set some value for procargs for the strip command further below
136 			 * Seen to be a problem on some Solaris 7 and 8 systems */
137 			chld_out.line[i][pos] = '\n';
138 			chld_out.line[i][pos+1] = 0x0;
139 		}
140 		if ( cols >= expected_cols ) {
141 			xasprintf (&procargs, "%s", chld_out.line[i] + pos);
142 			strip (procargs);
143 
144 			/* Some ps return full pathname for command. This removes path */
145 			temp_string = strtok ((char *)procprog, "/");
146 			while (temp_string) {
147 				strcpy(procprog, temp_string);
148 				temp_string = strtok (NULL, "/");
149 			}
150 
151 			/* May get empty procargs */
152 			if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) {
153 				proc_entries++;
154 				if (verbose >= 2) {
155 					printf (_("Found process: %s %s\n"), procprog, procargs);
156 				}
157 			}
158 		}
159 	}
160 
161 	/* If we get anything on stderr, at least set warning */
162 	if(chld_err.buflen)
163 		result = max_state (result, STATE_WARNING);
164 
165 	/* reset the alarm handler */
166 	alarm (0);
167 
168 	if (proc_entries == 0) {
169 		die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Could not locate a running Nagios process!"));
170 	}
171 
172 	if (latest_entry_time == 0L) {
173 		die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time"));
174 	}
175 
176 	time (&current_time);
177 	if ((int)(current_time - latest_entry_time) > (expire_minutes * 60)) {
178 		result = STATE_WARNING;
179 	} else {
180 		result = STATE_OK;
181 	}
182 
183 	printf ("NAGIOS %s: ", (result == STATE_OK) ? _("OK") : _("WARNING"));
184 	printf (ngettext ("%d process", "%d processes", proc_entries), proc_entries);
185 	printf (", ");
186 	printf (
187 	  ngettext ("status log updated %d second ago",
188 	    "status log updated %d seconds ago",
189 	    (int) (current_time - latest_entry_time) ),
190 	    (int) (current_time - latest_entry_time) );
191 	printf ("\n");
192 
193 	return result;
194 }
195 
196 
197 
198 /* process command-line arguments */
199 int
process_arguments(int argc,char ** argv)200 process_arguments (int argc, char **argv)
201 {
202 	int c;
203 
204 	int option = 0;
205 	static struct option longopts[] = {
206 		{"filename", required_argument, 0, 'F'},
207 		{"expires", required_argument, 0, 'e'},
208 		{"command", required_argument, 0, 'C'},
209 		{"timeout", optional_argument, 0, 't'},
210 		{"version", no_argument, 0, 'V'},
211 		{"help", no_argument, 0, 'h'},
212 		{"verbose", no_argument, 0, 'v'},
213 		{0, 0, 0, 0}
214 	};
215 
216 	if (argc < 2)
217 		return ERROR;
218 
219 	if (!is_option (argv[1])) {
220 		status_log = argv[1];
221 		if (is_intnonneg (argv[2]))
222 			expire_minutes = atoi (argv[2]);
223 		else
224 			die (STATE_UNKNOWN,
225 								 _("Expiration time must be an integer (seconds)\n"));
226 		process_string = argv[3];
227 		return OK;
228 	}
229 
230 	while (1) {
231 		c = getopt_long (argc, argv, "+hVvF:C:e:t:", longopts, &option);
232 
233 		if (c == -1 || c == EOF || c == 1)
234 			break;
235 
236 		switch (c) {
237 		case 'h':									/* help */
238 			print_help ();
239 			exit (STATE_UNKNOWN);
240 		case 'V':									/* version */
241 			print_revision (progname, NP_VERSION);
242 			exit (STATE_UNKNOWN);
243 		case 'F':									/* status log */
244 			status_log = optarg;
245 			break;
246 		case 'C':									/* command */
247 			process_string = optarg;
248 			break;
249 		case 'e':									/* expiry time */
250 			if (is_intnonneg (optarg))
251 				expire_minutes = atoi (optarg);
252 			else
253 				die (STATE_UNKNOWN,
254 				     _("Expiration time must be an integer (seconds)\n"));
255 			break;
256 		case 't':									/* timeout */
257 			if (is_intnonneg (optarg))
258 				timeout_interval = atoi (optarg);
259 			else
260 				die (STATE_UNKNOWN,
261 				     _("Timeout must be an integer (seconds)\n"));
262 			break;
263 		case 'v':
264 			verbose++;
265 			break;
266 		default:									/* print short usage_va statement if args not parsable */
267 			usage5();
268 		}
269 	}
270 
271 
272 	if (status_log == NULL)
273 		die (STATE_UNKNOWN, _("You must provide the status_log\n"));
274 
275 	if (process_string == NULL)
276 		die (STATE_UNKNOWN, _("You must provide a process string\n"));
277 
278 	return OK;
279 }
280 
281 
282 
283 void
print_help(void)284 print_help (void)
285 {
286 	print_revision (progname, NP_VERSION);
287 
288 	printf (_(COPYRIGHT), copyright, email);
289 
290 	printf ("%s\n", _("This plugin checks the status of the Nagios process on the local machine"));
291   printf ("%s\n", _("The plugin will check to make sure the Nagios status log is no older than"));
292   printf ("%s\n", _("the number of minutes specified by the expires option."));
293   printf ("%s\n", _("It also checks the process table for a process matching the command argument."));
294 
295   printf ("\n\n");
296 
297 	print_usage ();
298 
299 	printf (UT_HELP_VRSN);
300 	printf (UT_EXTRA_OPTS);
301 
302 	printf (" %s\n", "-F, --filename=FILE");
303   printf ("    %s\n", _("Name of the log file to check"));
304   printf (" %s\n", "-e, --expires=INTEGER");
305   printf ("    %s\n", _("Minutes aging after which logfile is considered stale"));
306   printf (" %s\n", "-C, --command=STRING");
307   printf ("    %s\n", _("Substring to search for in process arguments"));
308   printf (" %s\n", "-t, --timeout=INTEGER");
309   printf ("    %s\n", _("Timeout for the plugin in seconds"));
310   printf (UT_VERBOSE);
311 
312   printf ("\n");
313   printf ("%s\n", _("Examples:"));
314   printf (" %s\n", "check_nagios -t 20 -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios");
315 
316   printf (UT_SUPPORT);
317 }
318 
319 
320 
321 void
print_usage(void)322 print_usage (void)
323 {
324   printf ("%s\n", _("Usage:"));
325 	printf ("%s -F <status log file> -t <timeout_seconds> -e <expire_minutes> -C <process_string>\n", progname);
326 }
327