Code

Fixed progname
[nagiosplug.git] / plugins / check_procs.c
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 ******************************************************************************/
37 const char *progname = "check_procs";
38 #define REVISION "$Revision$"
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"
48 #include "config.h"
49 #include <pwd.h>
50 #include "common.h"
51 #include "popen.h"
52 #include "utils.h"
54 int process_arguments (int, char **);
55 int validate_arguments (void);
56 void print_usage (void);
57 void print_help (void);
59 int wmax = -1;
60 int cmax = -1;
61 int wmin = -1;
62 int cmin = -1;
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
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];
81 int
82 main (int argc, char **argv)
83 {
84         char input_buffer[MAX_INPUT_BUFFER];
86         int procuid = 0;
87         int procppid = 0;
88         char procstat[8];
89         char procprog[MAX_INPUT_BUFFER];
90         char *procargs;
92         int resultsum = 0; /* bitmask of the filter criteria met by a process */
93         int found = 0; /* counter for number of lines returned in `ps` output */
94         int procs = 0; /* counter for number of processes meeting filter criteria */
95         int pos; /* number of spaces before 'args' in `ps` output */
97         int result = STATE_UNKNOWN;
99         if (process_arguments (argc, argv) == ERROR)
100                 usage ("Unable to parse command line\n");
102         /* run the command */
103         if (verbose)
104                 printf ("%s\n", PS_COMMAND);
105         child_process = spopen (PS_COMMAND);
106         if (child_process == NULL) {
107                 printf ("Could not open pipe: %s\n", PS_COMMAND);
108                 return STATE_UNKNOWN;
109         }
111         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
112         if (child_stderr == NULL)
113                 printf ("Could not open stderr for %s\n", PS_COMMAND);
115         fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
117         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
118                 if (
119 #ifdef USE_PS_VARS
120                                  sscanf (input_buffer, PS_FORMAT, PS_VARLIST) >= 4
121 #else
122                                  sscanf (input_buffer, PS_FORMAT, procstat, &procuid, &procppid, &pos,
123                                                                  procprog) >= 4
124 #endif
125                         ) {
126                         found++;
127                         resultsum = 0;
128                         asprintf (&procargs, "%s", input_buffer + pos);
129                         strip (procargs);
130                         if ((options & STAT) && (strstr (statopts, procstat)))
131                                 resultsum |= STAT;
132                         if ((options & ARGS) && procargs && (strstr (procargs, args) == procargs))
133                                 resultsum |= ARGS;
134                         if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0))
135                                 resultsum |= PROG;
136                         if ((options & PPID) && (procppid == ppid))
137                                 resultsum |= PPID;
138                         if ((options & USER) && (procuid == uid))
139                                 resultsum |= USER;
140 #ifdef DEBUG1
141                         if (procargs == NULL)
142                                 printf ("%d %d %d %s %s\n", procs, procuid, procppid, procstat,
143                                                                 procprog);
144                         else
145                                 printf ("%d %d %d %s %s %s\n", procs, procuid, procppid, procstat,
146                                                                 procprog, procargs);
147 #endif
148                         if (options == resultsum)
149                                 procs++;
150                 }
151         }
153         /* If we get anything on STDERR, at least set warning */
154         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
155                 if (verbose)
156                         printf ("STDERR: %s", input_buffer);
157                 /*Cannot use max() any more as STATE_UNKNOWN is gt STATE_CRITICAL 
158                 result = max (result, STATE_WARNING); */
159                 if ( !(result == STATE_CRITICAL) ) {
160                         result = STATE_WARNING;
161                 }
162                         printf ("System call sent warnings to stderr\n");
163         }
164         
165 /*      if (result == STATE_UNKNOWN || result == STATE_WARNING)
166                 printf ("System call sent warnings to stderr\n");
167 */
168         (void) fclose (child_stderr);
170         /* close the pipe */
171         if (spclose (child_process)) {
172                 printf ("System call returned nonzero status\n");
173                 if ( !(result == STATE_CRITICAL) ) {
174                         return STATE_WARNING;
175                 }
176                 else {
177                         return result ;
178                 }
179         }
181         if (options == ALL)
182                 procs = found;
184         if (found == 0) {                                                       /* no process lines parsed so return STATE_UNKNOWN */
185                 printf ("Unable to read output\n");
187                 return result;
188         }
190         if (verbose && (options & STAT))
191                 printf ("%s ", statopts);
192         if (verbose && (options & PROG))
193                 printf ("%s ", prog);
194         if (verbose && (options & PPID))
195                 printf ("%d ", ppid);
196         if (verbose && (options & USER))
197                 printf ("%d ", uid);
199         if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
200                 if (result == STATE_UNKNOWN)
201                         result = STATE_OK;
202                 printf (fmt, "OK", procs);
203                 return result;
204         }
205         else if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
206                 if (procs > cmax && procs < cmin) {
207                         printf (fmt, "CRITICAL", procs);
208                         return STATE_CRITICAL;
209                 }
210         }
211         else if (cmax >= 0 && procs > cmax) {
212                 printf (fmt, "CRITICAL", procs);
213                 return STATE_CRITICAL;
214         }
215         else if (cmin >= 0 && procs < cmin) {
216                 printf (fmt, "CRITICAL", procs);
217                 return STATE_CRITICAL;
218         }
220         if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
221                 if (procs > wmax && procs < wmin) {
222                         printf (fmt, "CRITICAL", procs);
223                         return STATE_CRITICAL;
224                 }
225         }
226         else if (wmax >= 0 && procs > wmax) {
227                 printf (fmt, "WARNING", procs);
228                 if ( !(result == STATE_CRITICAL) ) {
229                         return STATE_WARNING;
230                 }
231                 else {
232                         return result ;
233                 }
234                 /*return max (result, STATE_WARNING); */
235         }
236         else if (wmin >= 0 && procs < wmin) {
237                 printf (fmt, "WARNING", procs);
238                 if ( !(result == STATE_CRITICAL) ) {
239                         return STATE_WARNING;
240                 }
241                 else {
242                         return result ;
243                 }
244                 /*return max (result, STATE_WARNING); */
245         }
247         printf (fmt, "OK", procs);
248         if ( result == STATE_UNKNOWN ) {
249                 result = STATE_OK;
250         }
251         return result;
254 /* process command-line arguments */
255 int
256 process_arguments (int argc, char **argv)
258         int c = 1;
259         char *user;
260         struct passwd *pw;
261 #ifdef HAVE_GETOPT_H
262         int option_index = 0;
263         static struct option long_options[] = {
264                 {"warning", required_argument, 0, 'w'},
265                 {"critical", required_argument, 0, 'c'},
266                 {"timeout", required_argument, 0, 't'},
267                 {"status", required_argument, 0, 's'},
268                 {"ppid", required_argument, 0, 'p'},
269                 {"command", required_argument, 0, 'C'},
270                 {"argument-array", required_argument, 0, 'a'},
271                 {"help", no_argument, 0, 'h'},
272                 {"version", no_argument, 0, 'V'},
273                 {"verbose", no_argument, 0, 'v'},
274                 {0, 0, 0, 0}
275         };
276 #endif
278         for (c = 1; c < argc; c++)
279                 if (strcmp ("-to", argv[c]) == 0)
280                         strcpy (argv[c], "-t");
282         while (1) {
283 #ifdef HAVE_GETOPT_H
284                 c =     getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:", long_options, &option_index);
285 #else
286                 c = getopt (argc, argv, "Vvht:c:w:p:s:u:C:a:");
287 #endif
288                 if (c == -1 || c == EOF)
289                         break;
291                 switch (c) {
292                 case '?':                                                                       /* help */
293                         print_usage ();
294                         exit (STATE_UNKNOWN);
295                 case 'h':                                                                       /* help */
296                         print_help ();
297                         exit (STATE_OK);
298                 case 'V':                                                                       /* version */
299                         print_revision (progname, REVISION);
300                         exit (STATE_OK);
301                 case 't':                                                                       /* timeout period */
302                         if (!is_integer (optarg)) {
303                                 printf ("%s: Timeout Interval must be an integer!\n\n",
304                                         progname);
305                                 print_usage ();
306                                 exit (STATE_UNKNOWN);
307                         }
308                         timeout_interval = atoi (optarg);
309                         break;
310                 case 'c':                                                                       /* critical threshold */
311                         if (is_integer (optarg)) {
312                                 cmax = atoi (optarg);
313                                 break;
314                         }
315                         else if (sscanf (optarg, ":%d", &cmax) == 1) {
316                                 break;
317                         }
318                         else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2) {
319                                 break;
320                         }
321                         else if (sscanf (optarg, "%d:", &cmin) == 1) {
322                                 break;
323                         }
324                         else {
325                                 printf ("%s: Critical Process Count must be an integer!\n\n",
326                                         progname);
327                                 print_usage ();
328                                 exit (STATE_UNKNOWN);
329                         }
330                 case 'w':                                                                       /* warning time threshold */
331                         if (is_integer (optarg)) {
332                                 wmax = atoi (optarg);
333                                 break;
334                         }
335                         else if (sscanf (optarg, ":%d", &wmax) == 1) {
336                                 break;
337                         }
338                         else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2) {
339                                 break;
340                         }
341                         else if (sscanf (optarg, "%d:", &wmin) == 1) {
342                                 break;
343                         }
344                         else {
345                                 printf ("%s: Warning Process Count must be an integer!\n\n",
346                                         progname);
347                                 print_usage ();
348                                 exit (STATE_UNKNOWN);
349                         }
350                 case 'p':                                                                       /* process id */
351                         if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
352                                 asprintf (&fmt, "%s%sPPID = %d", fmt, (options ? ", " : ""), ppid);
353                                 options |= PPID;
354                                 break;
355                         }
356                         printf ("%s: Parent Process ID must be an integer!\n\n",
357                                 progname);
358                         print_usage ();
359                         exit (STATE_UNKNOWN);
360                 case 's':                                                                       /* status */
361                         asprintf (&statopts, "%s", optarg);
362                         asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
363                         options |= STAT;
364                         break;
365                 case 'u':                                                                       /* user or user id */
366                         if (is_integer (optarg)) {
367                                 uid = atoi (optarg);
368                                 pw = getpwuid ((uid_t) uid);
369                                 /*  check to be sure user exists */
370                                 if (pw == NULL) {
371                                         printf ("UID %d was not found\n", uid);
372                                         print_usage ();
373                                         exit (STATE_UNKNOWN);
374                                 }
375                         }
376                         else {
377                                 pw = getpwnam (optarg);
378                                 /*  check to be sure user exists */
379                                 if (pw == NULL) {
380                                         printf ("User name %s was not found\n", optarg);
381                                         print_usage ();
382                                         exit (STATE_UNKNOWN);
383                                 }
384                                 /*  then get uid */
385                                 uid = pw->pw_uid;
386                         }
387                         user = pw->pw_name;
388                         asprintf (&fmt, "%s%sUID = %d (%s)", fmt, (options ? ", " : ""),
389                                   uid, user);
390                         options |= USER;
391                         break;
392                 case 'C':                                                                       /* command */
393                         asprintf (&prog, "%s", optarg);
394                         asprintf (&fmt, "%s%scommand name %s", fmt, (options ? ", " : ""),
395                                   prog);
396                         options |= PROG;
397                         break;
398                 case 'a':                                                                       /* args (full path name with args) */
399                         asprintf (&args, "%s", optarg);
400                         asprintf (&fmt, "%s%sargs %s", fmt, (options ? ", " : ""), args);
401                         options |= ARGS;
402                         break;
403                 case 'v':                                                                       /* command */
404                         verbose = TRUE;
405                         break;
406                 }
407         }
409         c = optind;
410         if (wmax == -1 && argv[c])
411                 wmax = atoi (argv[c++]);
412         if (cmax == -1 && argv[c])
413                 cmax = atoi (argv[c++]);
414         if (statopts == NULL && argv[c]) {
415                 asprintf (&statopts, "%s", argv[c++]);
416                 asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
417                 options |= STAT;
418         }
420         return validate_arguments ();
424 int
425 validate_arguments ()
428 if (wmax >= 0 && wmin == -1)
429                 wmin = 0;
430         if (cmax >= 0 && cmin == -1)
431                 cmin = 0;
432         if (wmax >= wmin && cmax >= cmin) {     /* standard ranges */
433                 if (wmax > cmax && cmax != -1) {
434                         printf ("wmax (%d) cannot be greater than cmax (%d)\n", wmax, cmax);
435                         return ERROR;
436                 }
437                 if (cmin > wmin && wmin != -1) {
438                         printf ("wmin (%d) cannot be less than cmin (%d)\n", wmin, cmin);
439                         return ERROR;
440                 }
441         }
443 /*      if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { */
444 /*              printf ("At least one threshold must be set\n"); */
445 /*              return ERROR; */
446 /*      } */
448         if (options == 0) {
449                 options = 1;
450                 asprintf (&fmt, "%%s - %%d processes running\n");
451         }
452         else {
453                 asprintf (&fmt, "%%s - %%d processes running with %s\n", fmt);
454         }
456         return options;
460 void
461 print_help (void)
463         print_revision (progname, REVISION);
464         printf
465                 ("Copyright (c) %s %s <%s>\n\n%s\n",
466                  COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
467         print_usage ();
468         printf
469                 ("\nRequired Arguments:\n"
470                  " -w, --warning=RANGE\n"
471                  "    generate warning state if process count is outside this range\n"
472                  " -c, --critical=RANGE\n"
473                  "    generate critical state if process count is outside this range\n\n"
474                  "Optional Filters:\n"
475                  " -s, --state=STATUSFLAGS\n"
476                  "    Only scan for processes that have, in the output of `ps`, one or\n"
477                  "    more of the status flags you specify (for example R, Z, S, RS,\n"
478                  "    RSZDT, plus others based on the output of your 'ps' command).\n"
479                  " -p, --ppid=PPID\n"
480                  "    Only scan for children of the parent process ID indicated.\n"
481                  " -u, --user=USER\n"
482                  "    Only scan for proceses with user name or ID indicated.\n"
483                  " -a, --argument-array=STRING\n"
484                  "    Only scan for ARGS that match up to the length of the given STRING\n"
485                  " -C, --command=COMMAND\n"
486                  "    Only scan for exact matches to the named COMMAND.\n\n"
487                  "RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n"
488                  "specified 'max:min', a warning status will be generated if the\n"
490                  "count is inside the specified range\n");}
493 void
494 print_usage (void)
496         printf
497                 ("Usage:\n"
498                  " check_procs -w <range> -c <range> [-s state] [-p ppid] [-u user]\n"
499                  "             [-a argument-array] [-C command]\n"
500                  " check_procs --version\n" " check_procs --help\n");