summaryrefslogtreecommitdiffstats
path: root/plugins/check_procs.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_procs.c')
-rw-r--r--plugins/check_procs.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
new file mode 100644
index 00000000..c66d33de
--- /dev/null
+++ b/plugins/check_procs.c
@@ -0,0 +1,510 @@
1/******************************************************************************
2*
3* CHECK_PROCS.C
4*
5* Program: Process plugin for Nagios
6* License: GPL
7* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
8*
9* $Id$
10*
11* Description:
12*
13* This plugin checks the number of currently running processes and
14* generates WARNING or CRITICAL states if the process count is outside
15* the specified threshold ranges. The process count can be filtered by
16* process owner, parent process PID, current state (e.g., 'Z'), or may
17* be the total number of running processes
18*
19* License Information:
20*
21* This program is free software; you can redistribute it and/or modify
22* it under the terms of the GNU General Public License as published by
23* the Free Software Foundation; either version 2 of the License, or
24* (at your option) any later version.
25*
26* This program is distributed in the hope that it will be useful, but
27* WITHOUT ANY WARRANTY; without even the implied warranty of
28* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29* General Public License for more details.
30*
31* You should have received a copy of the GNU General Public License
32* along with this program; if not, write to the Free Software
33* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34*
35******************************************************************************/
36
37#include "config.h"
38#include <pwd.h>
39#include "common.h"
40#include "popen.h"
41#include "utils.h"
42
43int process_arguments (int, char **);
44int call_getopt (int, char **);
45int validate_arguments (void);
46void print_usage (void);
47void print_help (char *);
48
49int wmax = -1;
50int cmax = -1;
51int wmin = -1;
52int cmin = -1;
53
54int options = 0;
55#define ALL 1
56#define STAT 2
57#define PPID 4
58#define USER 8
59#define PROG 16
60#define ARGS 32
61
62int verbose = FALSE;
63int uid;
64int ppid;
65char *statopts = NULL;
66char *prog = NULL;
67char *args = NULL;
68char *format = NULL;
69char tmp[MAX_INPUT_BUFFER];
70
71int
72main (int argc, char **argv)
73{
74 char input_buffer[MAX_INPUT_BUFFER];
75
76 int procuid = 0;
77 int procppid = 0;
78 char procstat[8];
79 char procprog[MAX_INPUT_BUFFER];
80 char *procargs;
81
82 int resultsum = 0;
83 int found = 0;
84 int procs = 0;
85 int pos;
86
87 int result = STATE_UNKNOWN;
88
89 procargs = malloc (MAX_INPUT_BUFFER);
90
91 if (process_arguments (argc, argv) == ERROR)
92 usage ("Unable to parse command line\n");
93
94 /* run the command */
95 if (verbose)
96 printf ("%s\n", PS_COMMAND);
97 child_process = spopen (PS_COMMAND);
98 if (child_process == NULL) {
99 printf ("Could not open pipe: %s\n", PS_COMMAND);
100 return STATE_UNKNOWN;
101 }
102
103 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
104 if (child_stderr == NULL)
105 printf ("Could not open stderr for %s\n", PS_COMMAND);
106
107 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
108
109 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
110 if (
111#ifdef USE_PS_VARS
112 sscanf (input_buffer, PS_FORMAT, PS_VARLIST) >= 4
113#else
114 sscanf (input_buffer, PS_FORMAT, procstat, &procuid, &procppid, &pos,
115 procprog) >= 4
116#endif
117 ) {
118 found++;
119 resultsum = 0;
120 procargs = strcpy (procargs, &input_buffer[pos]);
121 strip (procargs);
122 if ((options & STAT) && (strstr (statopts, procstat)))
123 resultsum |= STAT;
124 if ((options & ARGS) && (strstr (procargs, args) == procargs))
125 resultsum |= ARGS;
126 if ((options & PROG) && (strcmp (prog, procprog) == 0))
127 resultsum |= PROG;
128 if ((options & PPID) && (procppid == ppid))
129 resultsum |= PPID;
130 if ((options & USER) && (procuid == uid))
131 resultsum |= USER;
132#ifdef DEBUG1
133 if (procargs == NULL)
134 printf ("%d %d %d %s %s\n", procs, procuid, procppid, procstat,
135 procprog);
136 else
137 printf ("%d %d %d %s %s %s\n", procs, procuid, procppid, procstat,
138 procprog, procargs);
139#endif
140 if (options == resultsum)
141 procs++;
142 }
143 }
144
145 /* If we get anything on STDERR, at least set warning */
146 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
147 if (verbose)
148 printf ("%s", input_buffer);
149 result = max (result, STATE_WARNING);
150 }
151 if (result > STATE_OK)
152 printf ("System call sent warnings to stderr\n");
153
154 (void) fclose (child_stderr);
155
156 /* close the pipe */
157 if (spclose (child_process)) {
158 printf ("System call returned nonzero status\n");
159 return max (result, STATE_WARNING);
160 }
161
162 if (options == ALL)
163 procs = found;
164
165 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
166 printf ("Unable to read output\n");
167 return max (result, STATE_UNKNOWN);
168 }
169
170 if (verbose && (options & STAT))
171 printf ("%s ", statopts);
172 if (verbose && (options & PROG))
173 printf ("%s ", prog);
174 if (verbose && (options & PPID))
175 printf ("%d ", ppid);
176 if (verbose && (options & USER))
177 printf ("%d ", uid);
178
179 if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
180 if (procs > cmax && procs < cmin) {
181 printf (format, "CRITICAL", procs);
182 return STATE_CRITICAL;
183 }
184 }
185 else if (cmax >= 0 && procs > cmax) {
186 printf (format, "CRITICAL", procs);
187 return STATE_CRITICAL;
188 }
189 else if (cmin >= 0 && procs < cmin) {
190 printf (format, "CRITICAL", procs);
191 return STATE_CRITICAL;
192 }
193
194 if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
195 if (procs > wmax && procs < wmin) {
196 printf (format, "CRITICAL", procs);
197 return STATE_CRITICAL;
198 }
199 }
200 else if (wmax >= 0 && procs > wmax) {
201 printf (format, "WARNING", procs);
202 return max (result, STATE_WARNING);
203 }
204 else if (wmin >= 0 && procs < wmin) {
205 printf (format, "WARNING", procs);
206 return max (result, STATE_WARNING);
207 }
208
209 printf (format, "OK", procs);
210 return max (result, STATE_OK);
211}
212
213/* process command-line arguments */
214int
215process_arguments (int argc, char **argv)
216{
217 int c;
218
219 if (argc < 2)
220 return ERROR;
221
222 for (c = 1; c < argc; c++)
223 if (strcmp ("-to", argv[c]) == 0)
224 strcpy (argv[c], "-t");
225
226 c = 0;
227 while (c += (call_getopt (argc - c, &argv[c]))) {
228 if (argc <= c)
229 break;
230 if (wmax == -1)
231 wmax = atoi (argv[c]);
232 else if (cmax == -1)
233 cmax = atoi (argv[c]);
234 else if (statopts == NULL) {
235 statopts = strscpy (statopts, argv[c]);
236 format =
237 strscat (format,
238 ssprintf (NULL, "%sSTATE = %s", (options ? ", " : ""),
239 statopts));
240 options |= STAT;
241 }
242 }
243
244 return validate_arguments ();
245}
246
247int
248call_getopt (int argc, char **argv)
249{
250 int c, i = 1;
251 char *user;
252 struct passwd *pw;
253#ifdef HAVE_GETOPT_H
254 int option_index = 0;
255 static struct option long_options[] = {
256 {"warning", required_argument, 0, 'w'},
257 {"critical", required_argument, 0, 'c'},
258 {"timeout", required_argument, 0, 't'},
259 {"status", required_argument, 0, 's'},
260 {"ppid", required_argument, 0, 'p'},
261 {"command", required_argument, 0, 'C'},
262 {"argument-array", required_argument, 0, 'a'},
263 {"help", no_argument, 0, 'h'},
264 {"version", no_argument, 0, 'V'},
265 {"verbose", no_argument, 0, 'v'},
266 {0, 0, 0, 0}
267 };
268#endif
269
270 while (1) {
271#ifdef HAVE_GETOPT_H
272 c =
273 getopt_long (argc, argv, "+Vvht:c:w:p:s:u:C:a:", long_options,
274 &option_index);
275#else
276 c = getopt (argc, argv, "+Vvht:c:w:p:s:u:C:a:");
277#endif
278
279 if (c == EOF)
280 break;
281
282 i++;
283 switch (c) {
284 case 't':
285 case 'c':
286 case 'w':
287 case 'p':
288 case 's':
289 case 'a':
290 case 'u':
291 case 'C':
292 i++;
293 }
294
295 switch (c) {
296 case '?': /* help */
297 print_usage ();
298 exit (STATE_UNKNOWN);
299 case 'h': /* help */
300 print_help (my_basename (argv[0]));
301 exit (STATE_OK);
302 case 'V': /* version */
303 print_revision (my_basename (argv[0]), "$Revision$");
304 exit (STATE_OK);
305 case 't': /* timeout period */
306 if (!is_integer (optarg)) {
307 printf ("%s: Timeout Interval must be an integer!\n\n",
308 my_basename (argv[0]));
309 print_usage ();
310 exit (STATE_UNKNOWN);
311 }
312 timeout_interval = atoi (optarg);
313 break;
314 case 'c': /* critical threshold */
315 if (is_integer (optarg)) {
316 cmax = atoi (optarg);
317 break;
318 }
319 else if (sscanf (optarg, ":%d", &cmax) == 1) {
320 break;
321 }
322 else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2) {
323 break;
324 }
325 else if (sscanf (optarg, "%d:", &cmin) == 1) {
326 break;
327 }
328 else {
329 printf ("%s: Critical Process Count must be an integer!\n\n",
330 my_basename (argv[0]));
331 print_usage ();
332 exit (STATE_UNKNOWN);
333 }
334 case 'w': /* warning time threshold */
335 if (is_integer (optarg)) {
336 wmax = atoi (optarg);
337 break;
338 }
339 else if (sscanf (optarg, ":%d", &wmax) == 1) {
340 break;
341 }
342 else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2) {
343 break;
344 }
345 else if (sscanf (optarg, "%d:", &wmin) == 1) {
346 break;
347 }
348 else {
349 printf ("%s: Warning Process Count must be an integer!\n\n",
350 my_basename (argv[0]));
351 print_usage ();
352 exit (STATE_UNKNOWN);
353 }
354 case 'p': /* process id */
355 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
356 format =
357 strscat (format,
358 ssprintf (NULL, "%sPPID = %d", (options ? ", " : ""),
359 ppid));
360 options |= PPID;
361 break;
362 }
363 printf ("%s: Parent Process ID must be an integer!\n\n",
364 my_basename (argv[0]));
365 print_usage ();
366 exit (STATE_UNKNOWN);
367 case 's': /* status */
368 statopts = strscpy (statopts, optarg);
369 format =
370 strscat (format,
371 ssprintf (NULL, "%sSTATE = %s", (options ? ", " : ""),
372 statopts));
373 options |= STAT;
374 break;
375 case 'u': /* user or user id */
376 if (is_integer (optarg)) {
377 uid = atoi (optarg);
378 pw = getpwuid ((uid_t) uid);
379 /* check to be sure user exists */
380 if (pw == NULL) {
381 printf ("UID %d was not found\n", uid);
382 print_usage ();
383 exit (STATE_UNKNOWN);
384 }
385 }
386 else {
387 pw = getpwnam (optarg);
388 /* check to be sure user exists */
389 if (pw == NULL) {
390 printf ("User name %s was not found\n", optarg);
391 print_usage ();
392 exit (STATE_UNKNOWN);
393 }
394 /* then get uid */
395 uid = pw->pw_uid;
396 }
397 user = pw->pw_name;
398 format =
399 strscat (format,
400 ssprintf (NULL, "%sUID = %d (%s)", (options ? ", " : ""),
401 uid, user));
402 options |= USER;
403 break;
404 case 'C': /* command */
405 prog = strscpy (prog, optarg);
406 format =
407 strscat (format,
408 ssprintf (NULL, "%scommand name %s", (options ? ", " : ""),
409 prog));
410 options |= PROG;
411 break;
412 case 'a': /* args (full path name with args) */
413 args = strscpy (args, optarg);
414 format =
415 strscat (format,
416 ssprintf (NULL, "%sargs %s", (options ? ", " : ""), args));
417 options |= ARGS;
418 break;
419 case 'v': /* command */
420 verbose = TRUE;
421 break;
422 }
423 }
424 return i;
425}
426
427
428int
429validate_arguments ()
430{
431
432 if (wmax >= 0 && wmin == -1)
433 wmin = 0;
434 if (cmax >= 0 && cmin == -1)
435 cmin = 0;
436 if (wmax >= wmin && cmax >= cmin) { /* standard ranges */
437 if (wmax > cmax && cmax != -1) {
438 printf ("wmax (%d) cannot be greater than cmax (%d)\n", wmax, cmax);
439 return ERROR;
440 }
441 if (cmin > wmin && wmin != -1) {
442 printf ("wmin (%d) cannot be less than cmin (%d)\n", wmin, cmin);
443 return ERROR;
444 }
445 }
446
447 if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
448 printf ("At least one threshold must be set\n");
449 return ERROR;
450 }
451
452 if (options == 0) {
453 options = 1;
454 format = ssprintf (format, "%%s - %%d processes running\n");
455 }
456 else {
457 format =
458 ssprintf (format, "%%s - %%d processes running with %s\n", format);
459 }
460
461 return options;
462}
463
464
465void
466print_help (char *cmd)
467{
468 print_revision (cmd, "$Revision$");
469 printf
470 ("Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)\n\n"
471 "This plugin checks the number of currently running processes and\n"
472 "generates WARNING or CRITICAL states if the process count is outside\n"
473 "the specified threshold ranges. The process count can be filtered by\n"
474 "process owner, parent process PID, current state (e.g., 'Z'), or may\n"
475 "be the total number of running processes\n\n");
476 print_usage ();
477 printf
478 ("\nRequired Arguments:\n"
479 " -w, --warning=RANGE\n"
480 " generate warning state if process count is outside this range\n"
481 " -c, --critical=RANGE\n"
482 " generate critical state if process count is outside this range\n\n"
483 "Optional Filters:\n"
484 " -s, --state=STATUSFLAGS\n"
485 " Only scan for processes that have, in the output of `ps`, one or\n"
486 " more of the status flags you specify (for example R, Z, S, RS,\n"
487 " RSZDT, plus others based on the output of your 'ps' command).\n"
488 " -p, --ppid=PPID\n"
489 " Only scan for children of the parent process ID indicated.\n"
490 " -u, --user=USER\n"
491 " Only scan for proceses with user name or ID indicated.\n"
492 " -a, --argument-array=STRING\n"
493 " Only scan for ARGS that match up to the length of the given STRING\n"
494 " -C, --command=COMMAND\n"
495 " Only scan for exact matches to the named COMMAND.\n\n"
496 "RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n"
497 "specified 'max:min', a warning status will be generated if the\n"
498
499 "count is inside the specified range\n");}
500
501
502void
503print_usage (void)
504{
505 printf
506 ("Usage:\n"
507 " check_procs -w <range> -c <range> [-s state] [-p ppid] [-u user]\n"
508 " [-a argument-array] [-C command]\n"
509 " check_procs --version\n" " check_procs --help\n");
510}