aboutsummaryrefslogtreecommitdiff
path: root/plugins/check_procs.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_procs.c')
-rw-r--r--plugins/check_procs.c510
1 files changed, 510 insertions, 0 deletions
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
new file mode 100644
index 00000000..c66d33de
--- /dev/null
+++ b/plugins/check_procs.c
@@ -0,0 +1,510 @@
+/******************************************************************************
+*
+* CHECK_PROCS.C
+*
+* Program: Process plugin for Nagios
+* License: GPL
+* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
+*
+* $Id$
+*
+* Description:
+*
+* This plugin checks the number of currently running processes and
+* generates WARNING or CRITICAL states if the process count is outside
+* the specified threshold ranges. The process count can be filtered by
+* process owner, parent process PID, current state (e.g., 'Z'), or may
+* be the total number of running processes
+*
+* License Information:
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+******************************************************************************/
+
+#include "config.h"
+#include <pwd.h>
+#include "common.h"
+#include "popen.h"
+#include "utils.h"
+
+int process_arguments (int, char **);
+int call_getopt (int, char **);
+int validate_arguments (void);
+void print_usage (void);
+void print_help (char *);
+
+int wmax = -1;
+int cmax = -1;
+int wmin = -1;
+int cmin = -1;
+
+int options = 0;
+#define ALL 1
+#define STAT 2
+#define PPID 4
+#define USER 8
+#define PROG 16
+#define ARGS 32
+
+int verbose = FALSE;
+int uid;
+int ppid;
+char *statopts = NULL;
+char *prog = NULL;
+char *args = NULL;
+char *format = NULL;
+char tmp[MAX_INPUT_BUFFER];
+
+int
+main (int argc, char **argv)
+{
+ char input_buffer[MAX_INPUT_BUFFER];
+
+ int procuid = 0;
+ int procppid = 0;
+ char procstat[8];
+ char procprog[MAX_INPUT_BUFFER];
+ char *procargs;
+
+ int resultsum = 0;
+ int found = 0;
+ int procs = 0;
+ int pos;
+
+ int result = STATE_UNKNOWN;
+
+ procargs = malloc (MAX_INPUT_BUFFER);
+
+ if (process_arguments (argc, argv) == ERROR)
+ usage ("Unable to parse command line\n");
+
+ /* run the command */
+ if (verbose)
+ printf ("%s\n", PS_COMMAND);
+ child_process = spopen (PS_COMMAND);
+ if (child_process == NULL) {
+ printf ("Could not open pipe: %s\n", PS_COMMAND);
+ return STATE_UNKNOWN;
+ }
+
+ child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
+ if (child_stderr == NULL)
+ printf ("Could not open stderr for %s\n", PS_COMMAND);
+
+ fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
+
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
+ if (
+#ifdef USE_PS_VARS
+ sscanf (input_buffer, PS_FORMAT, PS_VARLIST) >= 4
+#else
+ sscanf (input_buffer, PS_FORMAT, procstat, &procuid, &procppid, &pos,
+ procprog) >= 4
+#endif
+ ) {
+ found++;
+ resultsum = 0;
+ procargs = strcpy (procargs, &input_buffer[pos]);
+ strip (procargs);
+ if ((options & STAT) && (strstr (statopts, procstat)))
+ resultsum |= STAT;
+ if ((options & ARGS) && (strstr (procargs, args) == procargs))
+ resultsum |= ARGS;
+ if ((options & PROG) && (strcmp (prog, procprog) == 0))
+ resultsum |= PROG;
+ if ((options & PPID) && (procppid == ppid))
+ resultsum |= PPID;
+ if ((options & USER) && (procuid == uid))
+ resultsum |= USER;
+#ifdef DEBUG1
+ if (procargs == NULL)
+ printf ("%d %d %d %s %s\n", procs, procuid, procppid, procstat,
+ procprog);
+ else
+ printf ("%d %d %d %s %s %s\n", procs, procuid, procppid, procstat,
+ procprog, procargs);
+#endif
+ if (options == resultsum)
+ procs++;
+ }
+ }
+
+ /* If we get anything on STDERR, at least set warning */
+ while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
+ if (verbose)
+ printf ("%s", input_buffer);
+ result = max (result, STATE_WARNING);
+ }
+ if (result > STATE_OK)
+ printf ("System call sent warnings to stderr\n");
+
+ (void) fclose (child_stderr);
+
+ /* close the pipe */
+ if (spclose (child_process)) {
+ printf ("System call returned nonzero status\n");
+ return max (result, STATE_WARNING);
+ }
+
+ if (options == ALL)
+ procs = found;
+
+ if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
+ printf ("Unable to read output\n");
+ return max (result, STATE_UNKNOWN);
+ }
+
+ if (verbose && (options & STAT))
+ printf ("%s ", statopts);
+ if (verbose && (options & PROG))
+ printf ("%s ", prog);
+ if (verbose && (options & PPID))
+ printf ("%d ", ppid);
+ if (verbose && (options & USER))
+ printf ("%d ", uid);
+
+ if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
+ if (procs > cmax && procs < cmin) {
+ printf (format, "CRITICAL", procs);
+ return STATE_CRITICAL;
+ }
+ }
+ else if (cmax >= 0 && procs > cmax) {
+ printf (format, "CRITICAL", procs);
+ return STATE_CRITICAL;
+ }
+ else if (cmin >= 0 && procs < cmin) {
+ printf (format, "CRITICAL", procs);
+ return STATE_CRITICAL;
+ }
+
+ if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
+ if (procs > wmax && procs < wmin) {
+ printf (format, "CRITICAL", procs);
+ return STATE_CRITICAL;
+ }
+ }
+ else if (wmax >= 0 && procs > wmax) {
+ printf (format, "WARNING", procs);
+ return max (result, STATE_WARNING);
+ }
+ else if (wmin >= 0 && procs < wmin) {
+ printf (format, "WARNING", procs);
+ return max (result, STATE_WARNING);
+ }
+
+ printf (format, "OK", procs);
+ return max (result, STATE_OK);
+}
+
+/* process command-line arguments */
+int
+process_arguments (int argc, char **argv)
+{
+ int c;
+
+ if (argc < 2)
+ return ERROR;
+
+ for (c = 1; c < argc; c++)
+ if (strcmp ("-to", argv[c]) == 0)
+ strcpy (argv[c], "-t");
+
+ c = 0;
+ while (c += (call_getopt (argc - c, &argv[c]))) {
+ if (argc <= c)
+ break;
+ if (wmax == -1)
+ wmax = atoi (argv[c]);
+ else if (cmax == -1)
+ cmax = atoi (argv[c]);
+ else if (statopts == NULL) {
+ statopts = strscpy (statopts, argv[c]);
+ format =
+ strscat (format,
+ ssprintf (NULL, "%sSTATE = %s", (options ? ", " : ""),
+ statopts));
+ options |= STAT;
+ }
+ }
+
+ return validate_arguments ();
+}
+
+int
+call_getopt (int argc, char **argv)
+{
+ int c, i = 1;
+ char *user;
+ struct passwd *pw;
+#ifdef HAVE_GETOPT_H
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"warning", required_argument, 0, 'w'},
+ {"critical", required_argument, 0, 'c'},
+ {"timeout", required_argument, 0, 't'},
+ {"status", required_argument, 0, 's'},
+ {"ppid", required_argument, 0, 'p'},
+ {"command", required_argument, 0, 'C'},
+ {"argument-array", required_argument, 0, 'a'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+#endif
+
+ while (1) {
+#ifdef HAVE_GETOPT_H
+ c =
+ getopt_long (argc, argv, "+Vvht:c:w:p:s:u:C:a:", long_options,
+ &option_index);
+#else
+ c = getopt (argc, argv, "+Vvht:c:w:p:s:u:C:a:");
+#endif
+
+ if (c == EOF)
+ break;
+
+ i++;
+ switch (c) {
+ case 't':
+ case 'c':
+ case 'w':
+ case 'p':
+ case 's':
+ case 'a':
+ case 'u':
+ case 'C':
+ i++;
+ }
+
+ switch (c) {
+ case '?': /* help */
+ print_usage ();
+ exit (STATE_UNKNOWN);
+ case 'h': /* help */
+ print_help (my_basename (argv[0]));
+ exit (STATE_OK);
+ case 'V': /* version */
+ print_revision (my_basename (argv[0]), "$Revision$");
+ exit (STATE_OK);
+ case 't': /* timeout period */
+ if (!is_integer (optarg)) {
+ printf ("%s: Timeout Interval must be an integer!\n\n",
+ my_basename (argv[0]));
+ print_usage ();
+ exit (STATE_UNKNOWN);
+ }
+ timeout_interval = atoi (optarg);
+ break;
+ case 'c': /* critical threshold */
+ if (is_integer (optarg)) {
+ cmax = atoi (optarg);
+ break;
+ }
+ else if (sscanf (optarg, ":%d", &cmax) == 1) {
+ break;
+ }
+ else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2) {
+ break;
+ }
+ else if (sscanf (optarg, "%d:", &cmin) == 1) {
+ break;
+ }
+ else {
+ printf ("%s: Critical Process Count must be an integer!\n\n",
+ my_basename (argv[0]));
+ print_usage ();
+ exit (STATE_UNKNOWN);
+ }
+ case 'w': /* warning time threshold */
+ if (is_integer (optarg)) {
+ wmax = atoi (optarg);
+ break;
+ }
+ else if (sscanf (optarg, ":%d", &wmax) == 1) {
+ break;
+ }
+ else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2) {
+ break;
+ }
+ else if (sscanf (optarg, "%d:", &wmin) == 1) {
+ break;
+ }
+ else {
+ printf ("%s: Warning Process Count must be an integer!\n\n",
+ my_basename (argv[0]));
+ print_usage ();
+ exit (STATE_UNKNOWN);
+ }
+ case 'p': /* process id */
+ if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
+ format =
+ strscat (format,
+ ssprintf (NULL, "%sPPID = %d", (options ? ", " : ""),
+ ppid));
+ options |= PPID;
+ break;
+ }
+ printf ("%s: Parent Process ID must be an integer!\n\n",
+ my_basename (argv[0]));
+ print_usage ();
+ exit (STATE_UNKNOWN);
+ case 's': /* status */
+ statopts = strscpy (statopts, optarg);
+ format =
+ strscat (format,
+ ssprintf (NULL, "%sSTATE = %s", (options ? ", " : ""),
+ statopts));
+ options |= STAT;
+ break;
+ case 'u': /* user or user id */
+ if (is_integer (optarg)) {
+ uid = atoi (optarg);
+ pw = getpwuid ((uid_t) uid);
+ /* check to be sure user exists */
+ if (pw == NULL) {
+ printf ("UID %d was not found\n", uid);
+ print_usage ();
+ exit (STATE_UNKNOWN);
+ }
+ }
+ else {
+ pw = getpwnam (optarg);
+ /* check to be sure user exists */
+ if (pw == NULL) {
+ printf ("User name %s was not found\n", optarg);
+ print_usage ();
+ exit (STATE_UNKNOWN);
+ }
+ /* then get uid */
+ uid = pw->pw_uid;
+ }
+ user = pw->pw_name;
+ format =
+ strscat (format,
+ ssprintf (NULL, "%sUID = %d (%s)", (options ? ", " : ""),
+ uid, user));
+ options |= USER;
+ break;
+ case 'C': /* command */
+ prog = strscpy (prog, optarg);
+ format =
+ strscat (format,
+ ssprintf (NULL, "%scommand name %s", (options ? ", " : ""),
+ prog));
+ options |= PROG;
+ break;
+ case 'a': /* args (full path name with args) */
+ args = strscpy (args, optarg);
+ format =
+ strscat (format,
+ ssprintf (NULL, "%sargs %s", (options ? ", " : ""), args));
+ options |= ARGS;
+ break;
+ case 'v': /* command */
+ verbose = TRUE;
+ break;
+ }
+ }
+ return i;
+}
+
+
+int
+validate_arguments ()
+{
+
+ if (wmax >= 0 && wmin == -1)
+ wmin = 0;
+ if (cmax >= 0 && cmin == -1)
+ cmin = 0;
+ if (wmax >= wmin && cmax >= cmin) { /* standard ranges */
+ if (wmax > cmax && cmax != -1) {
+ printf ("wmax (%d) cannot be greater than cmax (%d)\n", wmax, cmax);
+ return ERROR;
+ }
+ if (cmin > wmin && wmin != -1) {
+ printf ("wmin (%d) cannot be less than cmin (%d)\n", wmin, cmin);
+ return ERROR;
+ }
+ }
+
+ if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
+ printf ("At least one threshold must be set\n");
+ return ERROR;
+ }
+
+ if (options == 0) {
+ options = 1;
+ format = ssprintf (format, "%%s - %%d processes running\n");
+ }
+ else {
+ format =
+ ssprintf (format, "%%s - %%d processes running with %s\n", format);
+ }
+
+ return options;
+}
+
+
+void
+print_help (char *cmd)
+{
+ print_revision (cmd, "$Revision$");
+ printf
+ ("Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)\n\n"
+ "This plugin checks the number of currently running processes and\n"
+ "generates WARNING or CRITICAL states if the process count is outside\n"
+ "the specified threshold ranges. The process count can be filtered by\n"
+ "process owner, parent process PID, current state (e.g., 'Z'), or may\n"
+ "be the total number of running processes\n\n");
+ print_usage ();
+ printf
+ ("\nRequired Arguments:\n"
+ " -w, --warning=RANGE\n"
+ " generate warning state if process count is outside this range\n"
+ " -c, --critical=RANGE\n"
+ " generate critical state if process count is outside this range\n\n"
+ "Optional Filters:\n"
+ " -s, --state=STATUSFLAGS\n"
+ " Only scan for processes that have, in the output of `ps`, one or\n"
+ " more of the status flags you specify (for example R, Z, S, RS,\n"
+ " RSZDT, plus others based on the output of your 'ps' command).\n"
+ " -p, --ppid=PPID\n"
+ " Only scan for children of the parent process ID indicated.\n"
+ " -u, --user=USER\n"
+ " Only scan for proceses with user name or ID indicated.\n"
+ " -a, --argument-array=STRING\n"
+ " Only scan for ARGS that match up to the length of the given STRING\n"
+ " -C, --command=COMMAND\n"
+ " Only scan for exact matches to the named COMMAND.\n\n"
+ "RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n"
+ "specified 'max:min', a warning status will be generated if the\n"
+
+ "count is inside the specified range\n");}
+
+
+void
+print_usage (void)
+{
+ printf
+ ("Usage:\n"
+ " check_procs -w <range> -c <range> [-s state] [-p ppid] [-u user]\n"
+ " [-a argument-array] [-C command]\n"
+ " check_procs --version\n" " check_procs --help\n");
+}