Code

remove call_getopt
[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 #define PROGNAME "check_snmp"
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;
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 = NULL;
76 char *prog = NULL;
77 char *args = NULL;
78 char *fmt = NULL;
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;
93         int found = 0;
94         int procs = 0;
95         int pos;
97         int result = STATE_UNKNOWN;
99         procargs = malloc (MAX_INPUT_BUFFER);
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                 if (
121 #ifdef USE_PS_VARS
122                                  sscanf (input_buffer, PS_FORMAT, PS_VARLIST) >= 4
123 #else
124                                  sscanf (input_buffer, PS_FORMAT, procstat, &procuid, &procppid, &pos,
125                                                                  procprog) >= 4
126 #endif
127                         ) {
128                         found++;
129                         resultsum = 0;
130                         procargs = strcpy (procargs, &input_buffer[pos]);
131                         strip (procargs);
132                         if ((options & STAT) && (strstr (statopts, procstat)))
133                                 resultsum |= STAT;
134                         if ((options & ARGS) && (strstr (procargs, args) == procargs))
135                                 resultsum |= ARGS;
136                         if ((options & PROG) && (strcmp (prog, procprog) == 0))
137                                 resultsum |= PROG;
138                         if ((options & PPID) && (procppid == ppid))
139                                 resultsum |= PPID;
140                         if ((options & USER) && (procuid == uid))
141                                 resultsum |= USER;
142 #ifdef DEBUG1
143                         if (procargs == NULL)
144                                 printf ("%d %d %d %s %s\n", procs, procuid, procppid, procstat,
145                                                                 procprog);
146                         else
147                                 printf ("%d %d %d %s %s %s\n", procs, procuid, procppid, procstat,
148                                                                 procprog, procargs);
149 #endif
150                         if (options == resultsum)
151                                 procs++;
152                 }
153         }
155         /* If we get anything on STDERR, at least set warning */
156         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
157                 if (verbose)
158                         printf ("STDERR: %s", input_buffer);
159                 /*Cannot use max() any more as STATE_UNKNOWN is gt STATE_CRITICAL 
160                 result = max (result, STATE_WARNING); */
161                 if ( !(result == STATE_CRITICAL) ) {
162                         result = STATE_WARNING;
163                 }
164                         printf ("System call sent warnings to stderr\n");
165         }
166         
167 /*      if (result == STATE_UNKNOWN || result == STATE_WARNING)
168                 printf ("System call sent warnings to stderr\n");
169 */
170         (void) fclose (child_stderr);
172         /* close the pipe */
173         if (spclose (child_process)) {
174                 printf ("System call returned nonzero status\n");
175                 if ( !(result == STATE_CRITICAL) ) {
176                         return STATE_WARNING;
177                 }
178                 else {
179                         return result ;
180                 }
181         }
183         if (options == ALL)
184                 procs = found;
186         if (found == 0) {                                                       /* no process lines parsed so return STATE_UNKNOWN */
187                 printf ("Unable to read output\n");
189                 return result;
190         }
192         if (verbose && (options & STAT))
193                 printf ("%s ", statopts);
194         if (verbose && (options & PROG))
195                 printf ("%s ", prog);
196         if (verbose && (options & PPID))
197                 printf ("%d ", ppid);
198         if (verbose && (options & USER))
199                 printf ("%d ", uid);
201         if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
202                 if (result == STATE_UNKNOWN)
203                         result = STATE_OK;
204                 printf (fmt, "OK", procs);
205                 return result;
206         }
207         else if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
208                 if (procs > cmax && procs < cmin) {
209                         printf (fmt, "CRITICAL", procs);
210                         return STATE_CRITICAL;
211                 }
212         }
213         else if (cmax >= 0 && procs > cmax) {
214                 printf (fmt, "CRITICAL", procs);
215                 return STATE_CRITICAL;
216         }
217         else if (cmin >= 0 && procs < cmin) {
218                 printf (fmt, "CRITICAL", procs);
219                 return STATE_CRITICAL;
220         }
222         if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
223                 if (procs > wmax && procs < wmin) {
224                         printf (fmt, "CRITICAL", procs);
225                         return STATE_CRITICAL;
226                 }
227         }
228         else if (wmax >= 0 && procs > wmax) {
229                 printf (fmt, "WARNING", procs);
230                 if ( !(result == STATE_CRITICAL) ) {
231                         return STATE_WARNING;
232                 }
233                 else {
234                         return result ;
235                 }
236                 /*return max (result, STATE_WARNING); */
237         }
238         else if (wmin >= 0 && procs < wmin) {
239                 printf (fmt, "WARNING", procs);
240                 if ( !(result == STATE_CRITICAL) ) {
241                         return STATE_WARNING;
242                 }
243                 else {
244                         return result ;
245                 }
246                 /*return max (result, STATE_WARNING); */
247         }
249         printf (fmt, "OK", procs);
250         if ( result == STATE_UNKNOWN ) {
251                 result = STATE_OK;
252         }
253         return result;
256 /* process command-line arguments */
257 int
258 process_arguments (int argc, char **argv)
260         int c = 1;
261         char *user;
262         struct passwd *pw;
263 #ifdef HAVE_GETOPT_H
264         int option_index = 0;
265         static struct option long_options[] = {
266                 {"warning", required_argument, 0, 'w'},
267                 {"critical", required_argument, 0, 'c'},
268                 {"timeout", required_argument, 0, 't'},
269                 {"status", required_argument, 0, 's'},
270                 {"ppid", required_argument, 0, 'p'},
271                 {"command", required_argument, 0, 'C'},
272                 {"argument-array", required_argument, 0, 'a'},
273                 {"help", no_argument, 0, 'h'},
274                 {"version", no_argument, 0, 'V'},
275                 {"verbose", no_argument, 0, 'v'},
276                 {0, 0, 0, 0}
277         };
278 #endif
280         asprintf (&fmt, "");
282         for (c = 1; c < argc; c++)
283                 if (strcmp ("-to", argv[c]) == 0)
284                         strcpy (argv[c], "-t");
286         while (1) {
287 #ifdef HAVE_GETOPT_H
288                 c =     getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:", long_options, &option_index);
289 #else
290                 c = getopt (argc, argv, "Vvht:c:w:p:s:u:C:a:");
291 #endif
292                 if (c == -1 || c == EOF)
293                         break;
295                 switch (c) {
296                 case '?':                                                                       /* help */
297                         print_usage ();
298                         exit (STATE_UNKNOWN);
299                 case 'h':                                                                       /* help */
300                         print_help ();
301                         exit (STATE_OK);
302                 case 'V':                                                                       /* version */
303                         print_revision (PROGNAME, 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                                 asprintf (&fmt, "%s%sPPID = %d", (options ? ", " : ""), ppid);
357                                 options |= PPID;
358                                 break;
359                         }
360                         printf ("%s: Parent Process ID must be an integer!\n\n",
361                                 my_basename (argv[0]));
362                         print_usage ();
363                         exit (STATE_UNKNOWN);
364                 case 's':                                                                       /* status */
365                         asprintf (&statopts, "%s", optarg);
366                         asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
367                         options |= STAT;
368                         break;
369                 case 'u':                                                                       /* user or user id */
370                         if (is_integer (optarg)) {
371                                 uid = atoi (optarg);
372                                 pw = getpwuid ((uid_t) uid);
373                                 /*  check to be sure user exists */
374                                 if (pw == NULL) {
375                                         printf ("UID %d was not found\n", uid);
376                                         print_usage ();
377                                         exit (STATE_UNKNOWN);
378                                 }
379                         }
380                         else {
381                                 pw = getpwnam (optarg);
382                                 /*  check to be sure user exists */
383                                 if (pw == NULL) {
384                                         printf ("User name %s was not found\n", optarg);
385                                         print_usage ();
386                                         exit (STATE_UNKNOWN);
387                                 }
388                                 /*  then get uid */
389                                 uid = pw->pw_uid;
390                         }
391                         user = pw->pw_name;
392                         asprintf (&fmt, "%s%sUID = %d (%s)", (options ? ", " : ""), fmt,
393                                   uid, user);
394                         options |= USER;
395                         break;
396                 case 'C':                                                                       /* command */
397                         asprintf (&prog, "%s", optarg);
398                         asprintf (&fmt, "%s%scommand name %s", fmt, (options ? ", " : ""),
399                                   prog);
400                         options |= PROG;
401                         break;
402                 case 'a':                                                                       /* args (full path name with args) */
403                         asprintf (&args, "%s", optarg);
404                         asprintf (&fmt, "%s%sargs %s", fmt, (options ? ", " : ""), args);
405                         options |= ARGS;
406                         break;
407                 case 'v':                                                                       /* command */
408                         verbose = TRUE;
409                         break;
410                 }
411         }
413         c = optind;
414         if (wmax == -1 && argv[c])
415                 wmax = atoi (argv[c++]);
416         if (cmax == -1 && argv[c])
417                 cmax = atoi (argv[c++]);
418         if (statopts == NULL && argv[c]) {
419                 asprintf (&statopts, "%s", argv[c++]);
420                 asprintf (&fmt, "%s%sSTATE = %s", fmt, (options ? ", " : ""), statopts);
421                 options |= STAT;
422         }
424         return validate_arguments ();
428 int
429 validate_arguments ()
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         }
447 /*      if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { */
448 /*              printf ("At least one threshold must be set\n"); */
449 /*              return ERROR; */
450 /*      } */
452         if (options == 0) {
453                 options = 1;
454                 asprintf (&fmt, "%%s - %%d processes running\n");
455         }
456         else {
457                 asprintf (&fmt, "%%s - %%d processes running with %s\n", fmt);
458         }
460         return options;
464 void
465 print_help (void)
467         print_revision (PROGNAME, REVISION);
468         printf
469                 ("Copyright (c) %s %s <%s>\n\n%s\n",
470                  COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
471         print_usage ();
472         printf
473                 ("\nRequired Arguments:\n"
474                  " -w, --warning=RANGE\n"
475                  "    generate warning state if process count is outside this range\n"
476                  " -c, --critical=RANGE\n"
477                  "    generate critical state if process count is outside this range\n\n"
478                  "Optional Filters:\n"
479                  " -s, --state=STATUSFLAGS\n"
480                  "    Only scan for processes that have, in the output of `ps`, one or\n"
481                  "    more of the status flags you specify (for example R, Z, S, RS,\n"
482                  "    RSZDT, plus others based on the output of your 'ps' command).\n"
483                  " -p, --ppid=PPID\n"
484                  "    Only scan for children of the parent process ID indicated.\n"
485                  " -u, --user=USER\n"
486                  "    Only scan for proceses with user name or ID indicated.\n"
487                  " -a, --argument-array=STRING\n"
488                  "    Only scan for ARGS that match up to the length of the given STRING\n"
489                  " -C, --command=COMMAND\n"
490                  "    Only scan for exact matches to the named COMMAND.\n\n"
491                  "RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n"
492                  "specified 'max:min', a warning status will be generated if the\n"
494                  "count is inside the specified range\n");}
497 void
498 print_usage (void)
500         printf
501                 ("Usage:\n"
502                  " check_procs -w <range> -c <range> [-s state] [-p ppid] [-u user]\n"
503                  "             [-a argument-array] [-C command]\n"
504                  " check_procs --version\n" " check_procs --help\n");