1
/******************************************************************************
5
* Program: Process plugin for Nagios
7
* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
9
* $Id: check_procs.c,v 1.9.2.1 2003/04/12 00:02:15 tonvoon Exp $
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
19
* License Information:
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.
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.
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.
35
******************************************************************************/
37
const char *progname = "check_procs";
38
#define REVISION "$Revision: 1.9.2.1 $"
39
#define COPYRIGHT "1999-2002"
40
#define AUTHOR "Ethan Galstad"
41
#define EMAIL "nagios@nagios.org"
42
#define SUMMARY "Check the number of currently running processes and generates WARNING or\n\
43
CRITICAL states if the process count is outside the specified threshold\n\
44
ranges. The process count can be filtered by process owner, parent process\n\
45
PID, current state (e.g., 'Z'), or may be the total number of running\n\
54
int process_arguments (int, char **);
55
int validate_arguments (void);
56
void print_usage (void);
57
void print_help (void);
64
int options = 0; /* bitmask of filter criteria to test against */
79
char tmp[MAX_INPUT_BUFFER];
80
const char *zombie = "Z";
83
main (int argc, char **argv)
85
char input_buffer[MAX_INPUT_BUFFER];
90
char procprog[MAX_INPUT_BUFFER];
93
int resultsum = 0; /* bitmask of the filter criteria met by a process */
94
int found = 0; /* counter for number of lines returned in `ps` output */
95
int procs = 0; /* counter for number of processes meeting filter criteria */
96
int pos; /* number of spaces before 'args' in `ps` output */
97
int cols; /* number of columns in ps output */
99
int result = STATE_UNKNOWN;
101
if (process_arguments (argc, argv) == ERROR)
102
usage ("Unable to parse command line\n");
104
/* run the command */
106
printf ("%s\n", PS_COMMAND);
107
child_process = spopen (PS_COMMAND);
108
if (child_process == NULL) {
109
printf ("Could not open pipe: %s\n", PS_COMMAND);
110
return STATE_UNKNOWN;
113
child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
114
if (child_stderr == NULL)
115
printf ("Could not open stderr for %s\n", PS_COMMAND);
117
fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
119
while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
121
cols = sscanf (input_buffer, PS_FORMAT, PS_VARLIST);
123
cols = sscanf (input_buffer, PS_FORMAT, procstat, &procuid,
124
&procppid, &pos, procprog);
126
/* Zombie processes do not give a procprog command */
127
if ( cols == 3 && strstr(procstat, zombie) ) {
128
strcpy(procprog, "");
133
asprintf (&procargs, "%s", input_buffer + pos);
135
if ((options & STAT) && (strstr (statopts, procstat)))
137
if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL))
139
if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0))
141
if ((options & PPID) && (procppid == ppid))
143
if ((options & USER) && (procuid == uid))
146
if (procargs == NULL)
147
printf ("%d %d %d %s %s\n", procs, procuid, procppid, procstat,
150
printf ("%d %d %d %s %s %s\n", procs, procuid, procppid, procstat,
153
if (strcmp (procprog, progname) == 0)
157
if (options == resultsum)
160
/* This should not happen */
162
printf("Not parseable: %s", input_buffer);
166
/* If we get anything on STDERR, at least set warning */
167
while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
169
printf ("STDERR: %s", input_buffer);
170
/*Cannot use max() any more as STATE_UNKNOWN is gt STATE_CRITICAL
171
result = max (result, STATE_WARNING); */
172
if ( !(result == STATE_CRITICAL) ) {
173
result = STATE_WARNING;
175
printf ("System call sent warnings to stderr\n");
178
/* if (result == STATE_UNKNOWN || result == STATE_WARNING)
179
printf ("System call sent warnings to stderr\n");
181
(void) fclose (child_stderr);
184
if (spclose (child_process)) {
185
printf ("System call returned nonzero status\n");
186
if ( !(result == STATE_CRITICAL) ) {
187
return STATE_WARNING;
197
if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
198
printf ("Unable to read output\n");
203
if (verbose && (options & STAT))
204
printf ("%s ", statopts);
205
if (verbose && (options & PROG))
206
printf ("%s ", prog);
207
if (verbose && (options & PPID))
208
printf ("%d ", ppid);
209
if (verbose && (options & USER))
212
if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
213
if (result == STATE_UNKNOWN)
215
printf (fmt, "OK", procs);
218
else if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
219
if (procs > cmax && procs < cmin) {
220
printf (fmt, "CRITICAL", procs);
221
return STATE_CRITICAL;
224
else if (cmax >= 0 && procs > cmax) {
225
printf (fmt, "CRITICAL", procs);
226
return STATE_CRITICAL;
228
else if (cmin >= 0 && procs < cmin) {
229
printf (fmt, "CRITICAL", procs);
230
return STATE_CRITICAL;
233
if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
234
if (procs > wmax && procs < wmin) {
235
printf (fmt, "CRITICAL", procs);
236
return STATE_CRITICAL;
239
else if (wmax >= 0 && procs > wmax) {
240
printf (fmt, "WARNING", procs);
241
if ( !(result == STATE_CRITICAL) ) {
242
return STATE_WARNING;
247
/*return max (result, STATE_WARNING); */
249
else if (wmin >= 0 && procs < wmin) {
250
printf (fmt, "WARNING", procs);
251
if ( !(result == STATE_CRITICAL) ) {
252
return STATE_WARNING;
257
/*return max (result, STATE_WARNING); */
260
printf (fmt, "OK", procs);
261
if ( result == STATE_UNKNOWN ) {
267
/* process command-line arguments */
269
process_arguments (int argc, char **argv)
275
int option_index = 0;
276
static struct option long_options[] = {
277
{"warning", required_argument, 0, 'w'},
278
{"critical", required_argument, 0, 'c'},
279
{"timeout", required_argument, 0, 't'},
280
{"status", required_argument, 0, 's'},
281
{"ppid", required_argument, 0, 'p'},
282
{"command", required_argument, 0, 'C'},
283
{"argument-array", required_argument, 0, 'a'},
284
{"help", no_argument, 0, 'h'},
285
{"version", no_argument, 0, 'V'},
286
{"verbose", no_argument, 0, 'v'},
291
for (c = 1; c < argc; c++)
292
if (strcmp ("-to", argv[c]) == 0)
293
strcpy (argv[c], "-t");
297
c = getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:", long_options, &option_index);
299
c = getopt (argc, argv, "Vvht:c:w:p:s:u:C:a:");
301
if (c == -1 || c == EOF)
307
exit (STATE_UNKNOWN);
311
case 'V': /* version */
312
print_revision (progname, REVISION);
314
case 't': /* timeout period */
315
if (!is_integer (optarg)) {
316
printf ("%s: Timeout Interval must be an integer!\n\n",
319
exit (STATE_UNKNOWN);
321
timeout_interval = atoi (optarg);
323
case 'c': /* critical threshold */
324
if (is_integer (optarg)) {
325
cmax = atoi (optarg);
328
else if (sscanf (optarg, ":%d", &cmax) == 1) {
331
else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2) {
334
else if (sscanf (optarg, "%d:", &cmin) == 1) {
338
printf ("%s: Critical Process Count must be an integer!\n\n",
341
exit (STATE_UNKNOWN);
343
case 'w': /* warning time threshold */
344
if (is_integer (optarg)) {
345
wmax = atoi (optarg);
348
else if (sscanf (optarg, ":%d", &wmax) == 1) {
351
else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2) {
354
else if (sscanf (optarg, "%d:", &wmin) == 1) {
358
printf ("%s: Warning Process Count must be an integer!\n\n",
361
exit (STATE_UNKNOWN);
363
case 'p': /* process id */
364
if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
365
asprintf (&fmt, "%s%sPPID = %d", fmt, (options ? ", " : ""), ppid);
369
printf ("%s: Parent Process ID must be an integer!\n\n",
372
exit (STATE_UNKNOWN);
373
case 's': /* status */
374
asprintf (&statopts, "%s", optarg);
375
asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
378
case 'u': /* user or user id */
379
if (is_integer (optarg)) {
381
pw = getpwuid ((uid_t) uid);
382
/* check to be sure user exists */
384
printf ("UID %d was not found\n", uid);
386
exit (STATE_UNKNOWN);
390
pw = getpwnam (optarg);
391
/* check to be sure user exists */
393
printf ("User name %s was not found\n", optarg);
395
exit (STATE_UNKNOWN);
401
asprintf (&fmt, "%s%sUID = %d (%s)", fmt, (options ? ", " : ""),
405
case 'C': /* command */
406
asprintf (&prog, "%s", optarg);
407
asprintf (&fmt, "%s%scommand name %s", fmt, (options ? ", " : ""),
411
case 'a': /* args (full path name with args) */
412
asprintf (&args, "%s", optarg);
413
asprintf (&fmt, "%s%sargs %s", fmt, (options ? ", " : ""), args);
416
case 'v': /* command */
423
if (wmax == -1 && argv[c])
424
wmax = atoi (argv[c++]);
425
if (cmax == -1 && argv[c])
426
cmax = atoi (argv[c++]);
427
if (statopts == NULL && argv[c]) {
428
asprintf (&statopts, "%s", argv[c++]);
429
asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
433
return validate_arguments ();
438
validate_arguments ()
441
if (wmax >= 0 && wmin == -1)
443
if (cmax >= 0 && cmin == -1)
445
if (wmax >= wmin && cmax >= cmin) { /* standard ranges */
446
if (wmax > cmax && cmax != -1) {
447
printf ("wmax (%d) cannot be greater than cmax (%d)\n", wmax, cmax);
450
if (cmin > wmin && wmin != -1) {
451
printf ("wmin (%d) cannot be less than cmin (%d)\n", wmin, cmin);
456
/* if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { */
457
/* printf ("At least one threshold must be set\n"); */
463
asprintf (&fmt, "%%s - %%d processes running\n");
466
asprintf (&fmt, "%%s - %%d processes running with %s\n", fmt);
476
print_revision (progname, REVISION);
478
("Copyright (c) %s %s <%s>\n\n%s\n",
479
COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
482
("\nRequired Arguments:\n"
483
" -w, --warning=RANGE\n"
484
" generate warning state if process count is outside this range\n"
485
" -c, --critical=RANGE\n"
486
" generate critical state if process count is outside this range\n\n"
487
"Optional Filters:\n"
488
" -s, --state=STATUSFLAGS\n"
489
" Only scan for processes that have, in the output of `ps`, one or\n"
490
" more of the status flags you specify (for example R, Z, S, RS,\n"
491
" RSZDT, plus others based on the output of your 'ps' command).\n"
493
" Only scan for children of the parent process ID indicated.\n"
495
" Only scan for proceses with user name or ID indicated.\n"
496
" -a, --argument-array=STRING\n"
497
" Only scan for processes with args that contain STRING.\n"
498
" -C, --command=COMMAND\n"
499
" Only scan for exact matches to the named COMMAND.\n\n"
500
"RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n"
501
"specified 'max:min', a warning status will be generated if the\n"
503
"count is inside the specified range\n");}
511
" check_procs -w <range> -c <range> [-s state] [-p ppid] [-u user]\n"
512
" [-a argument-array] [-C command]\n"
513
" check_procs --version\n" " check_procs --help\n");