~ubuntu-branches/ubuntu/precise/nagios-plugins/precise-proposed

« back to all changes in this revision

Viewing changes to plugins/check_procs.c

  • Committer: Bazaar Package Importer
  • Author(s): Guido Trotter
  • Date: 2004-06-15 15:37:48 UTC
  • Revision ID: james.westby@ubuntu.com-20040615153748-pq7702qdzghqfcns
Tags: upstream-1.3.1.0
ImportĀ upstreamĀ versionĀ 1.3.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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: check_procs.c,v 1.9.2.1 2003/04/12 00:02:15 tonvoon Exp $
 
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
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\
 
46
processes\n"
 
47
 
 
48
#include "config.h"
 
49
#include <pwd.h>
 
50
#include "common.h"
 
51
#include "popen.h"
 
52
#include "utils.h"
 
53
 
 
54
int process_arguments (int, char **);
 
55
int validate_arguments (void);
 
56
void print_usage (void);
 
57
void print_help (void);
 
58
 
 
59
int wmax = -1;
 
60
int cmax = -1;
 
61
int wmin = -1;
 
62
int cmin = -1;
 
63
 
 
64
int options = 0; /* bitmask of filter criteria to test against */
 
65
#define ALL 1
 
66
#define STAT 2
 
67
#define PPID 4
 
68
#define USER 8
 
69
#define PROG 16
 
70
#define ARGS 32
 
71
 
 
72
int verbose = FALSE;
 
73
int uid;
 
74
int ppid;
 
75
char *statopts = "";
 
76
char *prog = "";
 
77
char *args = "";
 
78
char *fmt = "";
 
79
char tmp[MAX_INPUT_BUFFER];
 
80
const char *zombie = "Z";
 
81
 
 
82
int
 
83
main (int argc, char **argv)
 
84
{
 
85
        char input_buffer[MAX_INPUT_BUFFER];
 
86
 
 
87
        int procuid = 0;
 
88
        int procppid = 0;
 
89
        char procstat[8];
 
90
        char procprog[MAX_INPUT_BUFFER];
 
91
        char *procargs;
 
92
 
 
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 */
 
98
 
 
99
        int result = STATE_UNKNOWN;
 
100
 
 
101
        if (process_arguments (argc, argv) == ERROR)
 
102
                usage ("Unable to parse command line\n");
 
103
 
 
104
        /* run the command */
 
105
        if (verbose)
 
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;
 
111
        }
 
112
 
 
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);
 
116
 
 
117
        fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
 
118
 
 
119
        while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
 
120
#ifdef USE_PS_VARS
 
121
                cols = sscanf (input_buffer, PS_FORMAT, PS_VARLIST);
 
122
#else
 
123
                cols = sscanf (input_buffer, PS_FORMAT, procstat, &procuid, 
 
124
                                                        &procppid, &pos, procprog);
 
125
#endif
 
126
                /* Zombie processes do not give a procprog command */
 
127
                if ( cols == 3 && strstr(procstat, zombie) ) {
 
128
                        strcpy(procprog, "");
 
129
                        cols = 4;
 
130
                }
 
131
                if ( cols >= 4 ) {
 
132
                        resultsum = 0;
 
133
                        asprintf (&procargs, "%s", input_buffer + pos);
 
134
                        strip (procargs);
 
135
                        if ((options & STAT) && (strstr (statopts, procstat)))
 
136
                                resultsum |= STAT;
 
137
                        if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL))
 
138
                                resultsum |= ARGS;
 
139
                        if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0))
 
140
                                resultsum |= PROG;
 
141
                        if ((options & PPID) && (procppid == ppid))
 
142
                                resultsum |= PPID;
 
143
                        if ((options & USER) && (procuid == uid))
 
144
                                resultsum |= USER;
 
145
#ifdef DEBUG1
 
146
                        if (procargs == NULL)
 
147
                                printf ("%d %d %d %s %s\n", procs, procuid, procppid, procstat,
 
148
                                                                procprog);
 
149
                        else
 
150
                                printf ("%d %d %d %s %s %s\n", procs, procuid, procppid, procstat,
 
151
                                                                procprog, procargs);
 
152
#endif
 
153
                        if (strcmp (procprog, progname) == 0)
 
154
                                continue;
 
155
                        found++;
 
156
 
 
157
                        if (options == resultsum)
 
158
                                procs++;
 
159
                } 
 
160
                /* This should not happen */
 
161
                else if (verbose) {
 
162
                        printf("Not parseable: %s", input_buffer);
 
163
                }
 
164
        }
 
165
 
 
166
        /* If we get anything on STDERR, at least set warning */
 
167
        while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
 
168
                if (verbose)
 
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;
 
174
                }
 
175
                        printf ("System call sent warnings to stderr\n");
 
176
        }
 
177
        
 
178
/*      if (result == STATE_UNKNOWN || result == STATE_WARNING)
 
179
                printf ("System call sent warnings to stderr\n");
 
180
*/
 
181
        (void) fclose (child_stderr);
 
182
 
 
183
        /* close the pipe */
 
184
        if (spclose (child_process)) {
 
185
                printf ("System call returned nonzero status\n");
 
186
                if ( !(result == STATE_CRITICAL) ) {
 
187
                        return STATE_WARNING;
 
188
                }
 
189
                else {
 
190
                        return result ;
 
191
                }
 
192
        }
 
193
 
 
194
        if (options == ALL)
 
195
                procs = found;
 
196
 
 
197
        if (found == 0) {                                                       /* no process lines parsed so return STATE_UNKNOWN */
 
198
                printf ("Unable to read output\n");
 
199
 
 
200
                return result;
 
201
        }
 
202
 
 
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))
 
210
                printf ("%d ", uid);
 
211
 
 
212
        if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
 
213
                if (result == STATE_UNKNOWN)
 
214
                        result = STATE_OK;
 
215
                printf (fmt, "OK", procs);
 
216
                return result;
 
217
        }
 
218
        else if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
 
219
                if (procs > cmax && procs < cmin) {
 
220
                        printf (fmt, "CRITICAL", procs);
 
221
                        return STATE_CRITICAL;
 
222
                }
 
223
        }
 
224
        else if (cmax >= 0 && procs > cmax) {
 
225
                printf (fmt, "CRITICAL", procs);
 
226
                return STATE_CRITICAL;
 
227
        }
 
228
        else if (cmin >= 0 && procs < cmin) {
 
229
                printf (fmt, "CRITICAL", procs);
 
230
                return STATE_CRITICAL;
 
231
        }
 
232
 
 
233
        if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
 
234
                if (procs > wmax && procs < wmin) {
 
235
                        printf (fmt, "CRITICAL", procs);
 
236
                        return STATE_CRITICAL;
 
237
                }
 
238
        }
 
239
        else if (wmax >= 0 && procs > wmax) {
 
240
                printf (fmt, "WARNING", procs);
 
241
                if ( !(result == STATE_CRITICAL) ) {
 
242
                        return STATE_WARNING;
 
243
                }
 
244
                else {
 
245
                        return result ;
 
246
                }
 
247
                /*return max (result, STATE_WARNING); */
 
248
        }
 
249
        else if (wmin >= 0 && procs < wmin) {
 
250
                printf (fmt, "WARNING", procs);
 
251
                if ( !(result == STATE_CRITICAL) ) {
 
252
                        return STATE_WARNING;
 
253
                }
 
254
                else {
 
255
                        return result ;
 
256
                }
 
257
                /*return max (result, STATE_WARNING); */
 
258
        }
 
259
 
 
260
        printf (fmt, "OK", procs);
 
261
        if ( result == STATE_UNKNOWN ) {
 
262
                result = STATE_OK;
 
263
        }
 
264
        return result;
 
265
}
 
266
 
 
267
/* process command-line arguments */
 
268
int
 
269
process_arguments (int argc, char **argv)
 
270
{
 
271
        int c = 1;
 
272
        char *user;
 
273
        struct passwd *pw;
 
274
#ifdef HAVE_GETOPT_H
 
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'},
 
287
                {0, 0, 0, 0}
 
288
        };
 
289
#endif
 
290
 
 
291
        for (c = 1; c < argc; c++)
 
292
                if (strcmp ("-to", argv[c]) == 0)
 
293
                        strcpy (argv[c], "-t");
 
294
 
 
295
        while (1) {
 
296
#ifdef HAVE_GETOPT_H
 
297
                c =     getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:", long_options, &option_index);
 
298
#else
 
299
                c = getopt (argc, argv, "Vvht:c:w:p:s:u:C:a:");
 
300
#endif
 
301
                if (c == -1 || c == EOF)
 
302
                        break;
 
303
 
 
304
                switch (c) {
 
305
                case '?':                                                                       /* help */
 
306
                        print_usage ();
 
307
                        exit (STATE_UNKNOWN);
 
308
                case 'h':                                                                       /* help */
 
309
                        print_help ();
 
310
                        exit (STATE_OK);
 
311
                case 'V':                                                                       /* version */
 
312
                        print_revision (progname, REVISION);
 
313
                        exit (STATE_OK);
 
314
                case 't':                                                                       /* timeout period */
 
315
                        if (!is_integer (optarg)) {
 
316
                                printf ("%s: Timeout Interval must be an integer!\n\n",
 
317
                                        progname);
 
318
                                print_usage ();
 
319
                                exit (STATE_UNKNOWN);
 
320
                        }
 
321
                        timeout_interval = atoi (optarg);
 
322
                        break;
 
323
                case 'c':                                                                       /* critical threshold */
 
324
                        if (is_integer (optarg)) {
 
325
                                cmax = atoi (optarg);
 
326
                                break;
 
327
                        }
 
328
                        else if (sscanf (optarg, ":%d", &cmax) == 1) {
 
329
                                break;
 
330
                        }
 
331
                        else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2) {
 
332
                                break;
 
333
                        }
 
334
                        else if (sscanf (optarg, "%d:", &cmin) == 1) {
 
335
                                break;
 
336
                        }
 
337
                        else {
 
338
                                printf ("%s: Critical Process Count must be an integer!\n\n",
 
339
                                        progname);
 
340
                                print_usage ();
 
341
                                exit (STATE_UNKNOWN);
 
342
                        }
 
343
                case 'w':                                                                       /* warning time threshold */
 
344
                        if (is_integer (optarg)) {
 
345
                                wmax = atoi (optarg);
 
346
                                break;
 
347
                        }
 
348
                        else if (sscanf (optarg, ":%d", &wmax) == 1) {
 
349
                                break;
 
350
                        }
 
351
                        else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2) {
 
352
                                break;
 
353
                        }
 
354
                        else if (sscanf (optarg, "%d:", &wmin) == 1) {
 
355
                                break;
 
356
                        }
 
357
                        else {
 
358
                                printf ("%s: Warning Process Count must be an integer!\n\n",
 
359
                                        progname);
 
360
                                print_usage ();
 
361
                                exit (STATE_UNKNOWN);
 
362
                        }
 
363
                case 'p':                                                                       /* process id */
 
364
                        if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
 
365
                                asprintf (&fmt, "%s%sPPID = %d", fmt, (options ? ", " : ""), ppid);
 
366
                                options |= PPID;
 
367
                                break;
 
368
                        }
 
369
                        printf ("%s: Parent Process ID must be an integer!\n\n",
 
370
                                progname);
 
371
                        print_usage ();
 
372
                        exit (STATE_UNKNOWN);
 
373
                case 's':                                                                       /* status */
 
374
                        asprintf (&statopts, "%s", optarg);
 
375
                        asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
 
376
                        options |= STAT;
 
377
                        break;
 
378
                case 'u':                                                                       /* user or user id */
 
379
                        if (is_integer (optarg)) {
 
380
                                uid = atoi (optarg);
 
381
                                pw = getpwuid ((uid_t) uid);
 
382
                                /*  check to be sure user exists */
 
383
                                if (pw == NULL) {
 
384
                                        printf ("UID %d was not found\n", uid);
 
385
                                        print_usage ();
 
386
                                        exit (STATE_UNKNOWN);
 
387
                                }
 
388
                        }
 
389
                        else {
 
390
                                pw = getpwnam (optarg);
 
391
                                /*  check to be sure user exists */
 
392
                                if (pw == NULL) {
 
393
                                        printf ("User name %s was not found\n", optarg);
 
394
                                        print_usage ();
 
395
                                        exit (STATE_UNKNOWN);
 
396
                                }
 
397
                                /*  then get uid */
 
398
                                uid = pw->pw_uid;
 
399
                        }
 
400
                        user = pw->pw_name;
 
401
                        asprintf (&fmt, "%s%sUID = %d (%s)", fmt, (options ? ", " : ""),
 
402
                                  uid, user);
 
403
                        options |= USER;
 
404
                        break;
 
405
                case 'C':                                                                       /* command */
 
406
                        asprintf (&prog, "%s", optarg);
 
407
                        asprintf (&fmt, "%s%scommand name %s", fmt, (options ? ", " : ""),
 
408
                                  prog);
 
409
                        options |= PROG;
 
410
                        break;
 
411
                case 'a':                                                                       /* args (full path name with args) */
 
412
                        asprintf (&args, "%s", optarg);
 
413
                        asprintf (&fmt, "%s%sargs %s", fmt, (options ? ", " : ""), args);
 
414
                        options |= ARGS;
 
415
                        break;
 
416
                case 'v':                                                                       /* command */
 
417
                        verbose = TRUE;
 
418
                        break;
 
419
                }
 
420
        }
 
421
 
 
422
        c = optind;
 
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);
 
430
                options |= STAT;
 
431
        }
 
432
 
 
433
        return validate_arguments ();
 
434
}
 
435
 
 
436
 
 
437
int
 
438
validate_arguments ()
 
439
{
 
440
 
 
441
if (wmax >= 0 && wmin == -1)
 
442
                wmin = 0;
 
443
        if (cmax >= 0 && cmin == -1)
 
444
                cmin = 0;
 
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);
 
448
                        return ERROR;
 
449
                }
 
450
                if (cmin > wmin && wmin != -1) {
 
451
                        printf ("wmin (%d) cannot be less than cmin (%d)\n", wmin, cmin);
 
452
                        return ERROR;
 
453
                }
 
454
        }
 
455
 
 
456
/*      if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { */
 
457
/*              printf ("At least one threshold must be set\n"); */
 
458
/*              return ERROR; */
 
459
/*      } */
 
460
 
 
461
        if (options == 0) {
 
462
                options = 1;
 
463
                asprintf (&fmt, "%%s - %%d processes running\n");
 
464
        }
 
465
        else {
 
466
                asprintf (&fmt, "%%s - %%d processes running with %s\n", fmt);
 
467
        }
 
468
 
 
469
        return options;
 
470
}
 
471
 
 
472
 
 
473
void
 
474
print_help (void)
 
475
{
 
476
        print_revision (progname, REVISION);
 
477
        printf
 
478
                ("Copyright (c) %s %s <%s>\n\n%s\n",
 
479
                 COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
 
480
        print_usage ();
 
481
        printf
 
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"
 
492
                 " -p, --ppid=PPID\n"
 
493
                 "    Only scan for children of the parent process ID indicated.\n"
 
494
                 " -u, --user=USER\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"
 
502
 
 
503
                 "count is inside the specified range\n");}
 
504
 
 
505
 
 
506
void
 
507
print_usage (void)
 
508
{
 
509
        printf
 
510
                ("Usage:\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");
 
514
}