Code

Remove getopt_long checks
[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];
80 const char *zombie = "Z";
82 int
83 main (int argc, char **argv)
84 {
85         char input_buffer[MAX_INPUT_BUFFER];
87         int procuid = 0;
88         int procppid = 0;
89         char procstat[8];
90         char procprog[MAX_INPUT_BUFFER];
91         char *procargs;
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 */
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         }
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)) {
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                         found++;
133                         resultsum = 0;
134                         asprintf (&procargs, "%s", input_buffer + pos);
135                         strip (procargs);
136                         if ((options & STAT) && (strstr (statopts, procstat)))
137                                 resultsum |= STAT;
138                         if ((options & ARGS) && procargs && (strstr (procargs, args) == procargs))
139                                 resultsum |= ARGS;
140                         if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0))
141                                 resultsum |= PROG;
142                         if ((options & PPID) && (procppid == ppid))
143                                 resultsum |= PPID;
144                         if ((options & USER) && (procuid == uid))
145                                 resultsum |= USER;
146 #ifdef DEBUG1
147                         if (procargs == NULL)
148                                 printf ("%d %d %d %s %s\n", procs, procuid, procppid, procstat,
149                                                                 procprog);
150                         else
151                                 printf ("%d %d %d %s %s %s\n", procs, procuid, procppid, procstat,
152                                                                 procprog, procargs);
153 #endif
154                         if (options == resultsum)
155                                 procs++;
156                 } 
157                 /* This should not happen */
158                 else if (verbose) {
159                         printf("Not parseable: %s", input_buffer);
160                 }
161         }
163         /* If we get anything on STDERR, at least set warning */
164         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
165                 if (verbose)
166                         printf ("STDERR: %s", input_buffer);
167                 /*Cannot use max() any more as STATE_UNKNOWN is gt STATE_CRITICAL 
168                 result = max (result, STATE_WARNING); */
169                 if ( !(result == STATE_CRITICAL) ) {
170                         result = STATE_WARNING;
171                 }
172                         printf ("System call sent warnings to stderr\n");
173         }
174         
175 /*      if (result == STATE_UNKNOWN || result == STATE_WARNING)
176                 printf ("System call sent warnings to stderr\n");
177 */
178         (void) fclose (child_stderr);
180         /* close the pipe */
181         if (spclose (child_process)) {
182                 printf ("System call returned nonzero status\n");
183                 if ( !(result == STATE_CRITICAL) ) {
184                         return STATE_WARNING;
185                 }
186                 else {
187                         return result ;
188                 }
189         }
191         if (options == ALL)
192                 procs = found;
194         if (found == 0) {                                                       /* no process lines parsed so return STATE_UNKNOWN */
195                 printf ("Unable to read output\n");
197                 return result;
198         }
200         if (verbose && (options & STAT))
201                 printf ("%s ", statopts);
202         if (verbose && (options & PROG))
203                 printf ("%s ", prog);
204         if (verbose && (options & PPID))
205                 printf ("%d ", ppid);
206         if (verbose && (options & USER))
207                 printf ("%d ", uid);
209         if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
210                 if (result == STATE_UNKNOWN)
211                         result = STATE_OK;
212                 printf (fmt, "OK", procs);
213                 return result;
214         }
215         else if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
216                 if (procs > cmax && procs < cmin) {
217                         printf (fmt, "CRITICAL", procs);
218                         return STATE_CRITICAL;
219                 }
220         }
221         else if (cmax >= 0 && procs > cmax) {
222                 printf (fmt, "CRITICAL", procs);
223                 return STATE_CRITICAL;
224         }
225         else if (cmin >= 0 && procs < cmin) {
226                 printf (fmt, "CRITICAL", procs);
227                 return STATE_CRITICAL;
228         }
230         if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
231                 if (procs > wmax && procs < wmin) {
232                         printf (fmt, "CRITICAL", procs);
233                         return STATE_CRITICAL;
234                 }
235         }
236         else if (wmax >= 0 && procs > wmax) {
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         }
246         else if (wmin >= 0 && procs < wmin) {
247                 printf (fmt, "WARNING", procs);
248                 if ( !(result == STATE_CRITICAL) ) {
249                         return STATE_WARNING;
250                 }
251                 else {
252                         return result ;
253                 }
254                 /*return max (result, STATE_WARNING); */
255         }
257         printf (fmt, "OK", procs);
258         if ( result == STATE_UNKNOWN ) {
259                 result = STATE_OK;
260         }
261         return result;
264 /* process command-line arguments */
265 int
266 process_arguments (int argc, char **argv)
268         int c = 1;
269         char *user;
270         struct passwd *pw;
271         int option_index = 0;
272         static struct option long_options[] = {
273                 {"warning", required_argument, 0, 'w'},
274                 {"critical", required_argument, 0, 'c'},
275                 {"timeout", required_argument, 0, 't'},
276                 {"status", required_argument, 0, 's'},
277                 {"ppid", required_argument, 0, 'p'},
278                 {"command", required_argument, 0, 'C'},
279                 {"argument-array", required_argument, 0, 'a'},
280                 {"help", no_argument, 0, 'h'},
281                 {"version", no_argument, 0, 'V'},
282                 {"verbose", no_argument, 0, 'v'},
283                 {0, 0, 0, 0}
284         };
286         for (c = 1; c < argc; c++)
287                 if (strcmp ("-to", argv[c]) == 0)
288                         strcpy (argv[c], "-t");
290         while (1) {
291                 c = getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:", long_options, &option_index);
293                 if (c == -1 || c == EOF)
294                         break;
296                 switch (c) {
297                 case '?':                                                                       /* help */
298                         print_usage ();
299                         exit (STATE_UNKNOWN);
300                 case 'h':                                                                       /* help */
301                         print_help ();
302                         exit (STATE_OK);
303                 case 'V':                                                                       /* version */
304                         print_revision (progname, REVISION);
305                         exit (STATE_OK);
306                 case 't':                                                                       /* timeout period */
307                         if (!is_integer (optarg)) {
308                                 printf ("%s: Timeout Interval must be an integer!\n\n",
309                                         progname);
310                                 print_usage ();
311                                 exit (STATE_UNKNOWN);
312                         }
313                         timeout_interval = atoi (optarg);
314                         break;
315                 case 'c':                                                                       /* critical threshold */
316                         if (is_integer (optarg)) {
317                                 cmax = atoi (optarg);
318                                 break;
319                         }
320                         else if (sscanf (optarg, ":%d", &cmax) == 1) {
321                                 break;
322                         }
323                         else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2) {
324                                 break;
325                         }
326                         else if (sscanf (optarg, "%d:", &cmin) == 1) {
327                                 break;
328                         }
329                         else {
330                                 printf ("%s: Critical Process Count must be an integer!\n\n",
331                                         progname);
332                                 print_usage ();
333                                 exit (STATE_UNKNOWN);
334                         }
335                 case 'w':                                                                       /* warning time threshold */
336                         if (is_integer (optarg)) {
337                                 wmax = atoi (optarg);
338                                 break;
339                         }
340                         else if (sscanf (optarg, ":%d", &wmax) == 1) {
341                                 break;
342                         }
343                         else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2) {
344                                 break;
345                         }
346                         else if (sscanf (optarg, "%d:", &wmin) == 1) {
347                                 break;
348                         }
349                         else {
350                                 printf ("%s: Warning Process Count must be an integer!\n\n",
351                                         progname);
352                                 print_usage ();
353                                 exit (STATE_UNKNOWN);
354                         }
355                 case 'p':                                                                       /* process id */
356                         if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
357                                 asprintf (&fmt, "%s%sPPID = %d", fmt, (options ? ", " : ""), ppid);
358                                 options |= PPID;
359                                 break;
360                         }
361                         printf ("%s: Parent Process ID must be an integer!\n\n",
362                                 progname);
363                         print_usage ();
364                         exit (STATE_UNKNOWN);
365                 case 's':                                                                       /* status */
366                         asprintf (&statopts, "%s", optarg);
367                         asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
368                         options |= STAT;
369                         break;
370                 case 'u':                                                                       /* user or user id */
371                         if (is_integer (optarg)) {
372                                 uid = atoi (optarg);
373                                 pw = getpwuid ((uid_t) uid);
374                                 /*  check to be sure user exists */
375                                 if (pw == NULL) {
376                                         printf ("UID %d was not found\n", uid);
377                                         print_usage ();
378                                         exit (STATE_UNKNOWN);
379                                 }
380                         }
381                         else {
382                                 pw = getpwnam (optarg);
383                                 /*  check to be sure user exists */
384                                 if (pw == NULL) {
385                                         printf ("User name %s was not found\n", optarg);
386                                         print_usage ();
387                                         exit (STATE_UNKNOWN);
388                                 }
389                                 /*  then get uid */
390                                 uid = pw->pw_uid;
391                         }
392                         user = pw->pw_name;
393                         asprintf (&fmt, "%s%sUID = %d (%s)", fmt, (options ? ", " : ""),
394                                   uid, user);
395                         options |= USER;
396                         break;
397                 case 'C':                                                                       /* command */
398                         asprintf (&prog, "%s", optarg);
399                         asprintf (&fmt, "%s%scommand name %s", fmt, (options ? ", " : ""),
400                                   prog);
401                         options |= PROG;
402                         break;
403                 case 'a':                                                                       /* args (full path name with args) */
404                         asprintf (&args, "%s", optarg);
405                         asprintf (&fmt, "%s%sargs %s", fmt, (options ? ", " : ""), args);
406                         options |= ARGS;
407                         break;
408                 case 'v':                                                                       /* command */
409                         verbose = TRUE;
410                         break;
411                 }
412         }
414         c = optind;
415         if (wmax == -1 && argv[c])
416                 wmax = atoi (argv[c++]);
417         if (cmax == -1 && argv[c])
418                 cmax = atoi (argv[c++]);
419         if (statopts == NULL && argv[c]) {
420                 asprintf (&statopts, "%s", argv[c++]);
421                 asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
422                 options |= STAT;
423         }
425         return validate_arguments ();
429 int
430 validate_arguments ()
433 if (wmax >= 0 && wmin == -1)
434                 wmin = 0;
435         if (cmax >= 0 && cmin == -1)
436                 cmin = 0;
437         if (wmax >= wmin && cmax >= cmin) {     /* standard ranges */
438                 if (wmax > cmax && cmax != -1) {
439                         printf ("wmax (%d) cannot be greater than cmax (%d)\n", wmax, cmax);
440                         return ERROR;
441                 }
442                 if (cmin > wmin && wmin != -1) {
443                         printf ("wmin (%d) cannot be less than cmin (%d)\n", wmin, cmin);
444                         return ERROR;
445                 }
446         }
448 /*      if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { */
449 /*              printf ("At least one threshold must be set\n"); */
450 /*              return ERROR; */
451 /*      } */
453         if (options == 0) {
454                 options = 1;
455                 asprintf (&fmt, "%%s - %%d processes running\n");
456         }
457         else {
458                 asprintf (&fmt, "%%s - %%d processes running with %s\n", fmt);
459         }
461         return options;
465 void
466 print_help (void)
468         print_revision (progname, REVISION);
469         printf
470                 ("Copyright (c) %s %s <%s>\n\n%s\n",
471                  COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
472         print_usage ();
473         printf
474                 ("\nRequired Arguments:\n"
475                  " -w, --warning=RANGE\n"
476                  "    generate warning state if process count is outside this range\n"
477                  " -c, --critical=RANGE\n"
478                  "    generate critical state if process count is outside this range\n\n"
479                  "Optional Filters:\n"
480                  " -s, --state=STATUSFLAGS\n"
481                  "    Only scan for processes that have, in the output of `ps`, one or\n"
482                  "    more of the status flags you specify (for example R, Z, S, RS,\n"
483                  "    RSZDT, plus others based on the output of your 'ps' command).\n"
484                  " -p, --ppid=PPID\n"
485                  "    Only scan for children of the parent process ID indicated.\n"
486                  " -u, --user=USER\n"
487                  "    Only scan for proceses with user name or ID indicated.\n"
488                  " -a, --argument-array=STRING\n"
489                  "    Only scan for ARGS that match up to the length of the given STRING\n"
490                  " -C, --command=COMMAND\n"
491                  "    Only scan for exact matches to the named COMMAND.\n\n"
492                  "RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n"
493                  "specified 'max:min', a warning status will be generated if the\n"
495                  "count is inside the specified range\n");}
498 void
499 print_usage (void)
501         printf
502                 ("Usage:\n"
503                  " check_procs -w <range> -c <range> [-s state] [-p ppid] [-u user]\n"
504                  "             [-a argument-array] [-C command]\n"
505                  " check_procs --version\n" " check_procs --help\n");