Code

Initial revision
[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 ("%s", input_buffer);
149                 result = max (result, STATE_WARNING);
150         }
151         if (result > STATE_OK)
152                 printf ("System call sent warnings to stderr\n");
154         (void) fclose (child_stderr);
156         /* close the pipe */
157         if (spclose (child_process)) {
158                 printf ("System call returned nonzero status\n");
159                 return max (result, STATE_WARNING);
160         }
162         if (options == ALL)
163                 procs = found;
165         if (found == 0) {                                                       /* no process lines parsed so return STATE_UNKNOWN */
166                 printf ("Unable to read output\n");
167                 return max (result, STATE_UNKNOWN);
168         }
170         if (verbose && (options & STAT))
171                 printf ("%s ", statopts);
172         if (verbose && (options & PROG))
173                 printf ("%s ", prog);
174         if (verbose && (options & PPID))
175                 printf ("%d ", ppid);
176         if (verbose && (options & USER))
177                 printf ("%d ", uid);
179         if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
180                 if (procs > cmax && procs < cmin) {
181                         printf (format, "CRITICAL", procs);
182                         return STATE_CRITICAL;
183                 }
184         }
185         else if (cmax >= 0 && procs > cmax) {
186                 printf (format, "CRITICAL", procs);
187                 return STATE_CRITICAL;
188         }
189         else if (cmin >= 0 && procs < cmin) {
190                 printf (format, "CRITICAL", procs);
191                 return STATE_CRITICAL;
192         }
194         if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
195                 if (procs > wmax && procs < wmin) {
196                         printf (format, "CRITICAL", procs);
197                         return STATE_CRITICAL;
198                 }
199         }
200         else if (wmax >= 0 && procs > wmax) {
201                 printf (format, "WARNING", procs);
202                 return max (result, STATE_WARNING);
203         }
204         else if (wmin >= 0 && procs < wmin) {
205                 printf (format, "WARNING", procs);
206                 return max (result, STATE_WARNING);
207         }
209         printf (format, "OK", procs);
210         return max (result, STATE_OK);
213 /* process command-line arguments */
214 int
215 process_arguments (int argc, char **argv)
217         int c;
219         if (argc < 2)
220                 return ERROR;
222         for (c = 1; c < argc; c++)
223                 if (strcmp ("-to", argv[c]) == 0)
224                         strcpy (argv[c], "-t");
226         c = 0;
227         while (c += (call_getopt (argc - c, &argv[c]))) {
228                 if (argc <= c)
229                         break;
230                 if (wmax == -1)
231                         wmax = atoi (argv[c]);
232                 else if (cmax == -1)
233                         cmax = atoi (argv[c]);
234                 else if (statopts == NULL) {
235                         statopts = strscpy (statopts, argv[c]);
236                         format =
237                                 strscat (format,
238                                                                  ssprintf (NULL, "%sSTATE = %s", (options ? ", " : ""),
239                                                                                                          statopts));
240                         options |= STAT;
241                 }
242         }
244         return validate_arguments ();
247 int
248 call_getopt (int argc, char **argv)
250         int c, i = 1;
251         char *user;
252         struct passwd *pw;
253 #ifdef HAVE_GETOPT_H
254         int option_index = 0;
255         static struct option long_options[] = {
256                 {"warning", required_argument, 0, 'w'},
257                 {"critical", required_argument, 0, 'c'},
258                 {"timeout", required_argument, 0, 't'},
259                 {"status", required_argument, 0, 's'},
260                 {"ppid", required_argument, 0, 'p'},
261                 {"command", required_argument, 0, 'C'},
262                 {"argument-array", required_argument, 0, 'a'},
263                 {"help", no_argument, 0, 'h'},
264                 {"version", no_argument, 0, 'V'},
265                 {"verbose", no_argument, 0, 'v'},
266                 {0, 0, 0, 0}
267         };
268 #endif
270         while (1) {
271 #ifdef HAVE_GETOPT_H
272                 c =
273                         getopt_long (argc, argv, "+Vvht:c:w:p:s:u:C:a:", long_options,
274                                                                          &option_index);
275 #else
276                 c = getopt (argc, argv, "+Vvht:c:w:p:s:u:C:a:");
277 #endif
279                 if (c == EOF)
280                         break;
282                 i++;
283                 switch (c) {
284                 case 't':
285                 case 'c':
286                 case 'w':
287                 case 'p':
288                 case 's':
289                 case 'a':
290                 case 'u':
291                 case 'C':
292                         i++;
293                 }
295                 switch (c) {
296                 case '?':                                                                       /* help */
297                         print_usage ();
298                         exit (STATE_UNKNOWN);
299                 case 'h':                                                                       /* help */
300                         print_help (my_basename (argv[0]));
301                         exit (STATE_OK);
302                 case 'V':                                                                       /* version */
303                         print_revision (my_basename (argv[0]), "$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                                 format =
357                                         strscat (format,
358                                                                          ssprintf (NULL, "%sPPID = %d", (options ? ", " : ""),
359                                                                                                                  ppid));
360                                 options |= PPID;
361                                 break;
362                         }
363                         printf ("%s: Parent Process ID must be an integer!\n\n",
364                                                         my_basename (argv[0]));
365                         print_usage ();
366                         exit (STATE_UNKNOWN);
367                 case 's':                                                                       /* status */
368                         statopts = strscpy (statopts, optarg);
369                         format =
370                                 strscat (format,
371                                                                  ssprintf (NULL, "%sSTATE = %s", (options ? ", " : ""),
372                                                                                                          statopts));
373                         options |= STAT;
374                         break;
375                 case 'u':                                                                       /* user or user id */
376                         if (is_integer (optarg)) {
377                                 uid = atoi (optarg);
378                                 pw = getpwuid ((uid_t) uid);
379                                 /*  check to be sure user exists */
380                                 if (pw == NULL) {
381                                         printf ("UID %d was not found\n", uid);
382                                         print_usage ();
383                                         exit (STATE_UNKNOWN);
384                                 }
385                         }
386                         else {
387                                 pw = getpwnam (optarg);
388                                 /*  check to be sure user exists */
389                                 if (pw == NULL) {
390                                         printf ("User name %s was not found\n", optarg);
391                                         print_usage ();
392                                         exit (STATE_UNKNOWN);
393                                 }
394                                 /*  then get uid */
395                                 uid = pw->pw_uid;
396                         }
397                         user = pw->pw_name;
398                         format =
399                                 strscat (format,
400                                                                  ssprintf (NULL, "%sUID = %d (%s)", (options ? ", " : ""),
401                                                                                                          uid, user));
402                         options |= USER;
403                         break;
404                 case 'C':                                                                       /* command */
405                         prog = strscpy (prog, optarg);
406                         format =
407                                 strscat (format,
408                                                                  ssprintf (NULL, "%scommand name %s", (options ? ", " : ""),
409                                                                                                          prog));
410                         options |= PROG;
411                         break;
412                 case 'a':                                                                       /* args (full path name with args) */
413                         args = strscpy (args, optarg);
414                         format =
415                                 strscat (format,
416                                                                  ssprintf (NULL, "%sargs %s", (options ? ", " : ""), args));
417                         options |= ARGS;
418                         break;
419                 case 'v':                                                                       /* command */
420                         verbose = TRUE;
421                         break;
422                 }
423         }
424         return i;
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                 format = ssprintf (format, "%%s - %%d processes running\n");
455         }
456         else {
457                 format =
458                         ssprintf (format, "%%s - %%d processes running with %s\n", format);
459         }
461         return options;
465 void
466 print_help (char *cmd)
468         print_revision (cmd, "$Revision$");
469         printf
470                 ("Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)\n\n"
471                  "This plugin checks the number of currently running processes and\n"
472                  "generates WARNING or CRITICAL states if the process count is outside\n"
473                  "the specified threshold ranges. The process count can be filtered by\n"
474                  "process owner, parent process PID, current state (e.g., 'Z'), or may\n"
475                  "be the total number of running processes\n\n");
476         print_usage ();
477         printf
478                 ("\nRequired Arguments:\n"
479                  " -w, --warning=RANGE\n"
480                  "    generate warning state if process count is outside this range\n"
481                  " -c, --critical=RANGE\n"
482                  "    generate critical state if process count is outside this range\n\n"
483                  "Optional Filters:\n"
484                  " -s, --state=STATUSFLAGS\n"
485                  "    Only scan for processes that have, in the output of `ps`, one or\n"
486                  "    more of the status flags you specify (for example R, Z, S, RS,\n"
487                  "    RSZDT, plus others based on the output of your 'ps' command).\n"
488                  " -p, --ppid=PPID\n"
489                  "    Only scan for children of the parent process ID indicated.\n"
490                  " -u, --user=USER\n"
491                  "    Only scan for proceses with user name or ID indicated.\n"
492                  " -a, --argument-array=STRING\n"
493                  "    Only scan for ARGS that match up to the length of the given STRING\n"
494                  " -C, --command=COMMAND\n"
495                  "    Only scan for exact matches to the named COMMAND.\n\n"
496                  "RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n"
497                  "specified 'max:min', a warning status will be generated if the\n"
499                  "count is inside the specified range\n");}
502 void
503 print_usage (void)
505         printf
506                 ("Usage:\n"
507                  " check_procs -w <range> -c <range> [-s state] [-p ppid] [-u user]\n"
508                  "             [-a argument-array] [-C command]\n"
509                  " check_procs --version\n" " check_procs --help\n");