Code

fixes for using POSIX return codes
[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 #include "config.h"
38 #include <pwd.h>
39 #include "common.h"
40 #include "popen.h"
41 #include "utils.h"
43 int process_arguments (int, char **);
44 int call_getopt (int, char **);
45 int validate_arguments (void);
46 void print_usage (void);
47 void print_help (char *);
49 int wmax = -1;
50 int cmax = -1;
51 int wmin = -1;
52 int cmin = -1;
54 int options = 0;
55 #define ALL 1
56 #define STAT 2
57 #define PPID 4
58 #define USER 8
59 #define PROG 16
60 #define ARGS 32
62 int verbose = FALSE;
63 int uid;
64 int ppid;
65 char *statopts = NULL;
66 char *prog = NULL;
67 char *args = NULL;
68 char *format = NULL;
69 char tmp[MAX_INPUT_BUFFER];
71 int
72 main (int argc, char **argv)
73 {
74         char input_buffer[MAX_INPUT_BUFFER];
76         int procuid = 0;
77         int procppid = 0;
78         char procstat[8];
79         char procprog[MAX_INPUT_BUFFER];
80         char *procargs;
82         int resultsum = 0;
83         int found = 0;
84         int procs = 0;
85         int pos;
87         int result = STATE_UNKNOWN;
89         procargs = malloc (MAX_INPUT_BUFFER);
91         if (process_arguments (argc, argv) == ERROR)
92                 usage ("Unable to parse command line\n");
94         /* run the command */
95         if (verbose)
96                 printf ("%s\n", PS_COMMAND);
97         child_process = spopen (PS_COMMAND);
98         if (child_process == NULL) {
99                 printf ("Could not open pipe: %s\n", PS_COMMAND);
100                 return STATE_UNKNOWN;
101         }
103         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
104         if (child_stderr == NULL)
105                 printf ("Could not open stderr for %s\n", PS_COMMAND);
107         fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
109         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
110                 if (
111 #ifdef USE_PS_VARS
112                                  sscanf (input_buffer, PS_FORMAT, PS_VARLIST) >= 4
113 #else
114                                  sscanf (input_buffer, PS_FORMAT, procstat, &procuid, &procppid, &pos,
115                                                                  procprog) >= 4
116 #endif
117                         ) {
118                         found++;
119                         resultsum = 0;
120                         procargs = strcpy (procargs, &input_buffer[pos]);
121                         strip (procargs);
122                         if ((options & STAT) && (strstr (statopts, procstat)))
123                                 resultsum |= STAT;
124                         if ((options & ARGS) && (strstr (procargs, args) == procargs))
125                                 resultsum |= ARGS;
126                         if ((options & PROG) && (strcmp (prog, procprog) == 0))
127                                 resultsum |= PROG;
128                         if ((options & PPID) && (procppid == ppid))
129                                 resultsum |= PPID;
130                         if ((options & USER) && (procuid == uid))
131                                 resultsum |= USER;
132 #ifdef DEBUG1
133                         if (procargs == NULL)
134                                 printf ("%d %d %d %s %s\n", procs, procuid, procppid, procstat,
135                                                                 procprog);
136                         else
137                                 printf ("%d %d %d %s %s %s\n", procs, procuid, procppid, procstat,
138                                                                 procprog, procargs);
139 #endif
140                         if (options == resultsum)
141                                 procs++;
142                 }
143         }
145         /* If we get anything on STDERR, at least set warning */
146         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
147                 if (verbose)
148                         printf ("STDERR: %s", input_buffer);
149                 /*Cannot use max() any more as STATE_UNKNOWN is gt STATE_CRITICAL 
150                 result = max (result, STATE_WARNING); */
151                 if ( !(result == STATE_CRITICAL) ) {
152                         result = STATE_WARNING;
153                 }
154                         printf ("System call sent warnings to stderr\n");
155         }
156         
157 /*      if (result == STATE_UNKNOWN || result == STATE_WARNING)
158                 printf ("System call sent warnings to stderr\n");
159 */
160         (void) fclose (child_stderr);
162         /* close the pipe */
163         if (spclose (child_process)) {
164                 printf ("System call returned nonzero status\n");
165                 if ( !(result == STATE_CRITICAL) ) {
166                         return STATE_WARNING;
167                 }
168                 else {
169                         return result ;
170                 }
171         }
173         if (options == ALL)
174                 procs = found;
176         if (found == 0) {                                                       /* no process lines parsed so return STATE_UNKNOWN */
177                 printf ("Unable to read output\n");
179                 return result;
180         }
182         if (verbose && (options & STAT))
183                 printf ("%s ", statopts);
184         if (verbose && (options & PROG))
185                 printf ("%s ", prog);
186         if (verbose && (options & PPID))
187                 printf ("%d ", ppid);
188         if (verbose && (options & USER))
189                 printf ("%d ", uid);
191         if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
192                 if (procs > cmax && procs < cmin) {
193                         printf (format, "CRITICAL", procs);
194                         return STATE_CRITICAL;
195                 }
196         }
197         else if (cmax >= 0 && procs > cmax) {
198                 printf (format, "CRITICAL", procs);
199                 return STATE_CRITICAL;
200         }
201         else if (cmin >= 0 && procs < cmin) {
202                 printf (format, "CRITICAL", procs);
203                 return STATE_CRITICAL;
204         }
206         if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
207                 if (procs > wmax && procs < wmin) {
208                         printf (format, "CRITICAL", procs);
209                         return STATE_CRITICAL;
210                 }
211         }
212         else if (wmax >= 0 && procs > wmax) {
213                 printf (format, "WARNING", procs);
214                 if ( !(result == STATE_CRITICAL) ) {
215                         return STATE_WARNING;
216                 }
217                 else {
218                         return result ;
219                 }
220                 /*return max (result, STATE_WARNING); */
221         }
222         else if (wmin >= 0 && procs < wmin) {
223                 printf (format, "WARNING", procs);
224                 if ( !(result == STATE_CRITICAL) ) {
225                         return STATE_WARNING;
226                 }
227                 else {
228                         return result ;
229                 }
230                 /*return max (result, STATE_WARNING); */
231         }
233         printf (format, "OK", procs);
234         if ( result == STATE_UNKNOWN ) {
235                 result = STATE_OK;
236         }
237         return result;
240 /* process command-line arguments */
241 int
242 process_arguments (int argc, char **argv)
244         int c;
246         if (argc < 2)
247                 return ERROR;
249         for (c = 1; c < argc; c++)
250                 if (strcmp ("-to", argv[c]) == 0)
251                         strcpy (argv[c], "-t");
253         c = 0;
254         while (c += (call_getopt (argc - c, &argv[c]))) {
255                 if (argc <= c)
256                         break;
257                 if (wmax == -1)
258                         wmax = atoi (argv[c]);
259                 else if (cmax == -1)
260                         cmax = atoi (argv[c]);
261                 else if (statopts == NULL) {
262                         statopts = strscpy (statopts, argv[c]);
263                         format =
264                                 strscat (format,
265                                                                  ssprintf (NULL, "%sSTATE = %s", (options ? ", " : ""),
266                                                                                                          statopts));
267                         options |= STAT;
268                 }
269         }
271         return validate_arguments ();
274 int
275 call_getopt (int argc, char **argv)
277         int c, i = 1;
278         char *user;
279         struct passwd *pw;
280 #ifdef HAVE_GETOPT_H
281         int option_index = 0;
282         static struct option long_options[] = {
283                 {"warning", required_argument, 0, 'w'},
284                 {"critical", required_argument, 0, 'c'},
285                 {"timeout", required_argument, 0, 't'},
286                 {"status", required_argument, 0, 's'},
287                 {"ppid", required_argument, 0, 'p'},
288                 {"command", required_argument, 0, 'C'},
289                 {"argument-array", required_argument, 0, 'a'},
290                 {"help", no_argument, 0, 'h'},
291                 {"version", no_argument, 0, 'V'},
292                 {"verbose", no_argument, 0, 'v'},
293                 {0, 0, 0, 0}
294         };
295 #endif
297         while (1) {
298 #ifdef HAVE_GETOPT_H
299                 c =
300                         getopt_long (argc, argv, "+Vvht:c:w:p:s:u:C:a:", long_options,
301                                                                          &option_index);
302 #else
303                 c = getopt (argc, argv, "+Vvht:c:w:p:s:u:C:a:");
304 #endif
306                 if (c == EOF)
307                         break;
309                 i++;
310                 switch (c) {
311                 case 't':
312                 case 'c':
313                 case 'w':
314                 case 'p':
315                 case 's':
316                 case 'a':
317                 case 'u':
318                 case 'C':
319                         i++;
320                 }
322                 switch (c) {
323                 case '?':                                                                       /* help */
324                         print_usage ();
325                         exit (STATE_UNKNOWN);
326                 case 'h':                                                                       /* help */
327                         print_help (my_basename (argv[0]));
328                         exit (STATE_OK);
329                 case 'V':                                                                       /* version */
330                         print_revision (my_basename (argv[0]), "$Revision$");
331                         exit (STATE_OK);
332                 case 't':                                                                       /* timeout period */
333                         if (!is_integer (optarg)) {
334                                 printf ("%s: Timeout Interval must be an integer!\n\n",
335                                                                 my_basename (argv[0]));
336                                 print_usage ();
337                                 exit (STATE_UNKNOWN);
338                         }
339                         timeout_interval = atoi (optarg);
340                         break;
341                 case 'c':                                                                       /* critical threshold */
342                         if (is_integer (optarg)) {
343                                 cmax = atoi (optarg);
344                                 break;
345                         }
346                         else if (sscanf (optarg, ":%d", &cmax) == 1) {
347                                 break;
348                         }
349                         else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2) {
350                                 break;
351                         }
352                         else if (sscanf (optarg, "%d:", &cmin) == 1) {
353                                 break;
354                         }
355                         else {
356                                 printf ("%s: Critical Process Count must be an integer!\n\n",
357                                                                 my_basename (argv[0]));
358                                 print_usage ();
359                                 exit (STATE_UNKNOWN);
360                         }
361                 case 'w':                                                                       /* warning time threshold */
362                         if (is_integer (optarg)) {
363                                 wmax = atoi (optarg);
364                                 break;
365                         }
366                         else if (sscanf (optarg, ":%d", &wmax) == 1) {
367                                 break;
368                         }
369                         else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2) {
370                                 break;
371                         }
372                         else if (sscanf (optarg, "%d:", &wmin) == 1) {
373                                 break;
374                         }
375                         else {
376                                 printf ("%s: Warning Process Count must be an integer!\n\n",
377                                                                 my_basename (argv[0]));
378                                 print_usage ();
379                                 exit (STATE_UNKNOWN);
380                         }
381                 case 'p':                                                                       /* process id */
382                         if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
383                                 format =
384                                         strscat (format,
385                                                                          ssprintf (NULL, "%sPPID = %d", (options ? ", " : ""),
386                                                                                                                  ppid));
387                                 options |= PPID;
388                                 break;
389                         }
390                         printf ("%s: Parent Process ID must be an integer!\n\n",
391                                                         my_basename (argv[0]));
392                         print_usage ();
393                         exit (STATE_UNKNOWN);
394                 case 's':                                                                       /* status */
395                         statopts = strscpy (statopts, optarg);
396                         format =
397                                 strscat (format,
398                                                                  ssprintf (NULL, "%sSTATE = %s", (options ? ", " : ""),
399                                                                                                          statopts));
400                         options |= STAT;
401                         break;
402                 case 'u':                                                                       /* user or user id */
403                         if (is_integer (optarg)) {
404                                 uid = atoi (optarg);
405                                 pw = getpwuid ((uid_t) uid);
406                                 /*  check to be sure user exists */
407                                 if (pw == NULL) {
408                                         printf ("UID %d was not found\n", uid);
409                                         print_usage ();
410                                         exit (STATE_UNKNOWN);
411                                 }
412                         }
413                         else {
414                                 pw = getpwnam (optarg);
415                                 /*  check to be sure user exists */
416                                 if (pw == NULL) {
417                                         printf ("User name %s was not found\n", optarg);
418                                         print_usage ();
419                                         exit (STATE_UNKNOWN);
420                                 }
421                                 /*  then get uid */
422                                 uid = pw->pw_uid;
423                         }
424                         user = pw->pw_name;
425                         format =
426                                 strscat (format,
427                                                                  ssprintf (NULL, "%sUID = %d (%s)", (options ? ", " : ""),
428                                                                                                          uid, user));
429                         options |= USER;
430                         break;
431                 case 'C':                                                                       /* command */
432                         prog = strscpy (prog, optarg);
433                         format =
434                                 strscat (format,
435                                                                  ssprintf (NULL, "%scommand name %s", (options ? ", " : ""),
436                                                                                                          prog));
437                         options |= PROG;
438                         break;
439                 case 'a':                                                                       /* args (full path name with args) */
440                         args = strscpy (args, optarg);
441                         format =
442                                 strscat (format,
443                                                                  ssprintf (NULL, "%sargs %s", (options ? ", " : ""), args));
444                         options |= ARGS;
445                         break;
446                 case 'v':                                                                       /* command */
447                         verbose = TRUE;
448                         break;
449                 }
450         }
451         return i;
455 int
456 validate_arguments ()
459         if (wmax >= 0 && wmin == -1)
460                 wmin = 0;
461         if (cmax >= 0 && cmin == -1)
462                 cmin = 0;
463         if (wmax >= wmin && cmax >= cmin) {     /* standard ranges */
464                 if (wmax > cmax && cmax != -1) {
465                         printf ("wmax (%d) cannot be greater than cmax (%d)\n", wmax, cmax);
466                         return ERROR;
467                 }
468                 if (cmin > wmin && wmin != -1) {
469                         printf ("wmin (%d) cannot be less than cmin (%d)\n", wmin, cmin);
470                         return ERROR;
471                 }
472         }
474         if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
475                 printf ("At least one threshold must be set\n");
476                 return ERROR;
477         }
479         if (options == 0) {
480                 options = 1;
481                 format = ssprintf (format, "%%s - %%d processes running\n");
482         }
483         else {
484                 format =
485                         ssprintf (format, "%%s - %%d processes running with %s\n", format);
486         }
488         return options;
492 void
493 print_help (char *cmd)
495         print_revision (cmd, "$Revision$");
496         printf
497                 ("Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)\n\n"
498                  "This plugin checks the number of currently running processes and\n"
499                  "generates WARNING or CRITICAL states if the process count is outside\n"
500                  "the specified threshold ranges. The process count can be filtered by\n"
501                  "process owner, parent process PID, current state (e.g., 'Z'), or may\n"
502                  "be the total number of running processes\n\n");
503         print_usage ();
504         printf
505                 ("\nRequired Arguments:\n"
506                  " -w, --warning=RANGE\n"
507                  "    generate warning state if process count is outside this range\n"
508                  " -c, --critical=RANGE\n"
509                  "    generate critical state if process count is outside this range\n\n"
510                  "Optional Filters:\n"
511                  " -s, --state=STATUSFLAGS\n"
512                  "    Only scan for processes that have, in the output of `ps`, one or\n"
513                  "    more of the status flags you specify (for example R, Z, S, RS,\n"
514                  "    RSZDT, plus others based on the output of your 'ps' command).\n"
515                  " -p, --ppid=PPID\n"
516                  "    Only scan for children of the parent process ID indicated.\n"
517                  " -u, --user=USER\n"
518                  "    Only scan for proceses with user name or ID indicated.\n"
519                  " -a, --argument-array=STRING\n"
520                  "    Only scan for ARGS that match up to the length of the given STRING\n"
521                  " -C, --command=COMMAND\n"
522                  "    Only scan for exact matches to the named COMMAND.\n\n"
523                  "RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n"
524                  "specified 'max:min', a warning status will be generated if the\n"
526                  "count is inside the specified range\n");}
529 void
530 print_usage (void)
532         printf
533                 ("Usage:\n"
534                  " check_procs -w <range> -c <range> [-s state] [-p ppid] [-u user]\n"
535                  "             [-a argument-array] [-C command]\n"
536                  " check_procs --version\n" " check_procs --help\n");