Merge pull request #2046 from RincewindsHat/fix/format_string
[monitoring-plugins.git] / plugins / check_procs.c
blob1d78ccee423c59ea60d96e3be696194ab89bfd4f
1 /*****************************************************************************
3 * Monitoring check_procs plugin
5 * License: GPL
6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
8 * Description:
10 * This file contains the check_procs plugin
12 * Checks all processes and generates WARNING or CRITICAL states if the
13 * specified metric is outside the required threshold ranges. The metric
14 * defaults to number of processes. Search filters can be applied to limit
15 * the processes to check.
17 * The parent process, check_procs itself and any child process of
18 * check_procs (ps) are excluded from any checks to prevent false positives.
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 3 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35 *****************************************************************************/
37 const char *progname = "check_procs";
38 const char *program_name = "check_procs"; /* Required for coreutils libs */
39 const char *copyright = "2000-2024";
40 const char *email = "devel@monitoring-plugins.org";
42 #include "common.h"
43 #include "utils.h"
44 #include "utils_cmd.h"
45 #include "regex.h"
47 #include <pwd.h>
48 #include <errno.h>
50 #ifdef HAVE_SYS_STAT_H
51 #include <sys/stat.h>
52 #endif
54 static int process_arguments (int /*argc*/, char ** /*argv*/);
55 static int validate_arguments (void);
56 static int convert_to_seconds (char * /*etime*/);
57 static void print_help (void);
58 void print_usage (void);
60 static char *warning_range = NULL;
61 static char *critical_range = NULL;
62 static thresholds *procs_thresholds = NULL;
64 static 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
71 #define VSZ 64
72 #define RSS 128
73 #define PCPU 256
74 #define ELAPSED 512
75 #define EREG_ARGS 1024
76 #define EXCLUDE_PROGS 2048
78 #define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads:
79 ppid of procs are compared to pid of this proc*/
81 /* Different metrics */
82 char *metric_name;
83 enum metric {
84 METRIC_PROCS,
85 METRIC_VSZ,
86 METRIC_RSS,
87 METRIC_CPU,
88 METRIC_ELAPSED
90 enum metric metric = METRIC_PROCS;
92 static int verbose = 0;
93 static int uid;
94 static pid_t ppid;
95 static int vsz;
96 static int rss;
97 static float pcpu;
98 static char *statopts;
99 static char *prog;
100 static char *exclude_progs;
101 static char **exclude_progs_arr = NULL;
102 static char exclude_progs_counter = 0;
103 static char *args;
104 static char *input_filename = NULL;
105 static regex_t re_args;
106 static char *fmt;
107 static char *fails;
108 static char tmp[MAX_INPUT_BUFFER];
109 static int kthread_filter = 0;
110 static int usepid = 0; /* whether to test for pid or /proc/pid/exe */
112 static int
113 stat_exe (const pid_t pid, struct stat *buf) {
114 char *path;
115 int ret;
116 xasprintf(&path, "/proc/%d/exe", pid);
117 ret = stat(path, buf);
118 free(path);
119 return ret;
124 main (int argc, char **argv)
126 char *input_buffer;
127 char *input_line;
128 char *procprog;
130 pid_t mypid = 0;
131 pid_t myppid = 0;
132 struct stat statbuf;
133 dev_t mydev = 0;
134 ino_t myino = 0;
135 int procuid = 0;
136 pid_t procpid = 0;
137 pid_t procppid = 0;
138 pid_t kthread_ppid = 0;
139 int procvsz = 0;
140 int procrss = 0;
141 int procseconds = 0;
142 float procpcpu = 0;
143 char procstat[8];
144 char procetime[MAX_INPUT_BUFFER] = { '\0' };
145 char *procargs;
147 const char *zombie = "Z";
149 int resultsum = 0; /* bitmask of the filter criteria met by a process */
150 int found = 0; /* counter for number of lines returned in `ps` output */
151 int procs = 0; /* counter for number of processes meeting filter criteria */
152 int pos; /* number of spaces before 'args' in `ps` output */
153 int cols; /* number of columns in ps output */
154 int expected_cols = PS_COLS - 1;
155 int warn = 0; /* number of processes in warn state */
156 int crit = 0; /* number of processes in crit state */
157 int i = 0;
158 int result = STATE_UNKNOWN;
159 int ret = 0;
160 output chld_out, chld_err;
162 setlocale (LC_ALL, "");
163 bindtextdomain (PACKAGE, LOCALEDIR);
164 textdomain (PACKAGE);
165 setlocale(LC_NUMERIC, "POSIX");
167 input_buffer = malloc (MAX_INPUT_BUFFER);
168 procprog = malloc (MAX_INPUT_BUFFER);
170 xasprintf (&metric_name, "PROCS");
171 metric = METRIC_PROCS;
173 /* Parse extra opts if any */
174 argv=np_extra_opts (&argc, argv, progname);
176 if (process_arguments (argc, argv) == ERROR)
177 usage4 (_("Could not parse arguments"));
179 /* find ourself */
180 mypid = getpid();
181 myppid = getppid();
182 if (usepid || stat_exe(mypid, &statbuf) == -1) {
183 /* usepid might have been set by -T */
184 usepid = 1;
185 } else {
186 usepid = 0;
187 mydev = statbuf.st_dev;
188 myino = statbuf.st_ino;
191 /* Set signal handling and alarm timeout */
192 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
193 die (STATE_UNKNOWN, _("Cannot catch SIGALRM"));
195 (void) alarm ((unsigned) timeout_interval);
197 if (verbose >= 2)
198 printf (_("CMD: %s\n"), PS_COMMAND);
200 if (input_filename == NULL) {
201 result = cmd_run( PS_COMMAND, &chld_out, &chld_err, 0);
202 if (chld_err.lines > 0) {
203 printf ("%s: %s", _("System call sent warnings to stderr"), chld_err.line[0]);
204 exit(STATE_WARNING);
206 } else {
207 result = cmd_file_read( input_filename, &chld_out, 0);
210 /* flush first line: j starts at 1 */
211 for (size_t j = 1; j < chld_out.lines; j++) {
212 input_line = chld_out.line[j];
214 if (verbose >= 3)
215 printf ("%s", input_line);
217 strcpy (procprog, "");
218 xasprintf (&procargs, "%s", "");
220 cols = sscanf (input_line, PS_FORMAT, PS_VARLIST);
222 /* Zombie processes do not give a procprog command */
223 if ( cols < expected_cols && strstr(procstat, zombie) ) {
224 cols = expected_cols;
226 if ( cols >= expected_cols ) {
227 resultsum = 0;
228 xasprintf (&procargs, "%s", input_line + pos);
229 strip (procargs);
231 /* Some ps return full pathname for command. This removes path */
232 strcpy(procprog, base_name(procprog));
234 /* we need to convert the elapsed time to seconds */
235 procseconds = convert_to_seconds(procetime);
237 if (verbose >= 3)
238 printf ("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n",
239 procs, procuid, procvsz, procrss,
240 procpid, procppid, procpcpu, procstat,
241 procetime, procprog, procargs);
243 /* Ignore self */
244 if ((usepid && mypid == procpid) ||
245 ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
246 (ret == -1 && errno == ENOENT))
248 if (verbose >= 3)
249 printf("not considering - is myself or gone\n");
250 continue;
252 /* Ignore parent*/
253 else if (myppid == procpid) {
254 if (verbose >= 3)
255 printf("not considering - is parent\n");
256 continue;
259 /* Ignore our own children */
260 if (procppid == mypid) {
261 if (verbose >= 3)
262 printf("not considering - is our child\n");
263 continue;
266 /* Ignore excluded processes by name */
267 if(options & EXCLUDE_PROGS) {
268 int found = 0;
269 int i = 0;
271 for(i=0; i < (exclude_progs_counter); i++) {
272 if(!strcmp(procprog, exclude_progs_arr[i])) {
273 found = 1;
276 if(found == 0) {
277 resultsum |= EXCLUDE_PROGS;
278 } else
280 if(verbose >= 3)
281 printf("excluding - by ignorelist\n");
285 /* filter kernel threads (children of KTHREAD_PARENT)*/
286 /* TODO adapt for other OSes than GNU/Linux
287 sorry for not doing that, but I've no other OSes to test :-( */
288 if (kthread_filter == 1) {
289 /* get pid KTHREAD_PARENT */
290 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) )
291 kthread_ppid = procpid;
293 if (kthread_ppid == procppid) {
294 if (verbose >= 2)
295 printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs);
296 continue;
300 if ((options & STAT) && (strstr (procstat, statopts)))
301 resultsum |= STAT;
302 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL))
303 resultsum |= ARGS;
304 if ((options & EREG_ARGS) && procargs && (regexec(&re_args, procargs, (size_t) 0, NULL, 0) == 0))
305 resultsum |= EREG_ARGS;
306 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0))
307 resultsum |= PROG;
308 if ((options & PPID) && (procppid == ppid))
309 resultsum |= PPID;
310 if ((options & USER) && (procuid == uid))
311 resultsum |= USER;
312 if ((options & VSZ) && (procvsz >= vsz))
313 resultsum |= VSZ;
314 if ((options & RSS) && (procrss >= rss))
315 resultsum |= RSS;
316 if ((options & PCPU) && (procpcpu >= pcpu))
317 resultsum |= PCPU;
319 found++;
321 /* Next line if filters not matched */
322 if (!(options == resultsum || options == ALL))
323 continue;
325 procs++;
326 if (verbose >= 2) {
327 printf ("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n",
328 procuid, procvsz, procrss,
329 procpid, procppid, procpcpu, procstat,
330 procetime, procprog, procargs);
333 if (metric == METRIC_VSZ)
334 i = get_status ((double)procvsz, procs_thresholds);
335 else if (metric == METRIC_RSS)
336 i = get_status ((double)procrss, procs_thresholds);
337 /* TODO? float thresholds for --metric=CPU */
338 else if (metric == METRIC_CPU)
339 i = get_status (procpcpu, procs_thresholds);
340 else if (metric == METRIC_ELAPSED)
341 i = get_status ((double)procseconds, procs_thresholds);
343 if (metric != METRIC_PROCS) {
344 if (i == STATE_WARNING) {
345 warn++;
346 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
347 result = max_state (result, i);
349 if (i == STATE_CRITICAL) {
350 crit++;
351 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
352 result = max_state (result, i);
356 /* This should not happen */
357 else if (verbose) {
358 printf(_("Not parseable: %s"), input_buffer);
362 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
363 printf (_("Unable to read output\n"));
364 return STATE_UNKNOWN;
367 if ( result == STATE_UNKNOWN )
368 result = STATE_OK;
370 /* Needed if procs found, but none match filter */
371 if ( metric == METRIC_PROCS ) {
372 result = max_state (result, get_status ((double)procs, procs_thresholds) );
375 if ( result == STATE_OK ) {
376 printf ("%s %s: ", metric_name, _("OK"));
377 } else if (result == STATE_WARNING) {
378 printf ("%s %s: ", metric_name, _("WARNING"));
379 if ( metric != METRIC_PROCS ) {
380 printf (_("%d warn out of "), warn);
382 } else if (result == STATE_CRITICAL) {
383 printf ("%s %s: ", metric_name, _("CRITICAL"));
384 if (metric != METRIC_PROCS) {
385 printf (_("%d crit, %d warn out of "), crit, warn);
388 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs);
390 if (strcmp(fmt,"") != 0) {
391 printf (_(" with %s"), fmt);
394 if ( verbose >= 1 && strcmp(fails,"") )
395 printf (" [%s]", fails);
397 if (metric == METRIC_PROCS)
398 printf (" | procs=%d;%s;%s;0;", procs,
399 warning_range ? warning_range : "",
400 critical_range ? critical_range : "");
401 else
402 printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit);
404 printf ("\n");
405 return result;
410 /* process command-line arguments */
412 process_arguments (int argc, char **argv)
414 int c = 1;
415 char *user;
416 struct passwd *pw;
417 int option = 0;
418 int err;
419 int cflags = REG_NOSUB | REG_EXTENDED;
420 char errbuf[MAX_INPUT_BUFFER];
421 char *temp_string;
422 int i=0;
423 static struct option longopts[] = {
424 {"warning", required_argument, 0, 'w'},
425 {"critical", required_argument, 0, 'c'},
426 {"metric", required_argument, 0, 'm'},
427 {"timeout", required_argument, 0, 't'},
428 {"status", required_argument, 0, 's'},
429 {"ppid", required_argument, 0, 'p'},
430 {"user", required_argument, 0, 'u'},
431 {"command", required_argument, 0, 'C'},
432 {"vsz", required_argument, 0, 'z'},
433 {"rss", required_argument, 0, 'r'},
434 {"pcpu", required_argument, 0, 'P'},
435 {"elapsed", required_argument, 0, 'e'},
436 {"argument-array", required_argument, 0, 'a'},
437 {"help", no_argument, 0, 'h'},
438 {"version", no_argument, 0, 'V'},
439 {"verbose", no_argument, 0, 'v'},
440 {"ereg-argument-array", required_argument, 0, CHAR_MAX+1},
441 {"input-file", required_argument, 0, CHAR_MAX+2},
442 {"no-kthreads", required_argument, 0, 'k'},
443 {"traditional-filter", no_argument, 0, 'T'},
444 {"exclude-process", required_argument, 0, 'X'},
445 {0, 0, 0, 0}
448 for (c = 1; c < argc; c++)
449 if (strcmp ("-to", argv[c]) == 0)
450 strcpy (argv[c], "-t");
452 while (1) {
453 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:",
454 longopts, &option);
456 if (c == -1 || c == EOF)
457 break;
459 switch (c) {
460 case '?': /* help */
461 usage5 ();
462 case 'h': /* help */
463 print_help ();
464 exit (STATE_UNKNOWN);
465 case 'V': /* version */
466 print_revision (progname, NP_VERSION);
467 exit (STATE_UNKNOWN);
468 case 't': /* timeout period */
469 if (!is_integer (optarg))
470 usage2 (_("Timeout interval must be a positive integer"), optarg);
471 else
472 timeout_interval = atoi (optarg);
473 break;
474 case 'c': /* critical threshold */
475 critical_range = optarg;
476 break;
477 case 'w': /* warning threshold */
478 warning_range = optarg;
479 break;
480 case 'p': /* process id */
481 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
482 xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid);
483 options |= PPID;
484 break;
486 usage4 (_("Parent Process ID must be an integer!"));
487 case 's': /* status */
488 if (statopts)
489 break;
490 else
491 statopts = optarg;
492 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
493 options |= STAT;
494 break;
495 case 'u': /* user or user id */
496 if (is_integer (optarg)) {
497 uid = atoi (optarg);
498 pw = getpwuid ((uid_t) uid);
499 /* check to be sure user exists */
500 if (pw == NULL)
501 usage2 (_("UID was not found"), optarg);
503 else {
504 pw = getpwnam (optarg);
505 /* check to be sure user exists */
506 if (pw == NULL)
507 usage2 (_("User name was not found"), optarg);
508 /* then get uid */
509 uid = pw->pw_uid;
511 user = pw->pw_name;
512 xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""),
513 uid, user);
514 options |= USER;
515 break;
516 case 'C': /* command */
517 /* TODO: allow this to be passed in with --metric */
518 if (prog)
519 break;
520 else
521 prog = optarg;
522 xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
523 prog);
524 options |= PROG;
525 break;
526 case 'X':
527 if(exclude_progs)
528 break;
529 else
530 exclude_progs = optarg;
531 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
532 exclude_progs);
533 char *p = strtok(exclude_progs, ",");
535 while(p){
536 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter);
537 exclude_progs_arr[exclude_progs_counter-1] = p;
538 p = strtok(NULL, ",");
541 options |= EXCLUDE_PROGS;
542 break;
543 case 'a': /* args (full path name with args) */
544 /* TODO: allow this to be passed in with --metric */
545 if (args)
546 break;
547 else
548 args = optarg;
549 xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args);
550 options |= ARGS;
551 break;
552 case CHAR_MAX+1:
553 err = regcomp(&re_args, optarg, cflags);
554 if (err != 0) {
555 regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER);
556 die (STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
558 /* Strip off any | within the regex optarg */
559 temp_string = strdup(optarg);
560 while(temp_string[i]!='\0'){
561 if(temp_string[i]=='|')
562 temp_string[i]=',';
563 i++;
565 xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string);
566 options |= EREG_ARGS;
567 break;
568 case 'r': /* RSS */
569 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) {
570 xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss);
571 options |= RSS;
572 break;
574 usage4 (_("RSS must be an integer!"));
575 case 'z': /* VSZ */
576 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) {
577 xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz);
578 options |= VSZ;
579 break;
581 usage4 (_("VSZ must be an integer!"));
582 case 'P': /* PCPU */
583 /* TODO: -P 1.5.5 is accepted */
584 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) {
585 xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu);
586 options |= PCPU;
587 break;
589 usage4 (_("PCPU must be a float!"));
590 case 'm':
591 xasprintf (&metric_name, "%s", optarg);
592 if ( strcmp(optarg, "PROCS") == 0) {
593 metric = METRIC_PROCS;
594 break;
596 else if ( strcmp(optarg, "VSZ") == 0) {
597 metric = METRIC_VSZ;
598 break;
600 else if ( strcmp(optarg, "RSS") == 0 ) {
601 metric = METRIC_RSS;
602 break;
604 else if ( strcmp(optarg, "CPU") == 0 ) {
605 metric = METRIC_CPU;
606 break;
608 else if ( strcmp(optarg, "ELAPSED") == 0) {
609 metric = METRIC_ELAPSED;
610 break;
613 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
614 case 'k': /* linux kernel thread filter */
615 kthread_filter = 1;
616 break;
617 case 'v': /* command */
618 verbose++;
619 break;
620 case 'T':
621 usepid = 1;
622 break;
623 case CHAR_MAX+2:
624 input_filename = optarg;
625 break;
629 c = optind;
630 if ((! warning_range) && argv[c])
631 warning_range = argv[c++];
632 if ((! critical_range) && argv[c])
633 critical_range = argv[c++];
634 if (statopts == NULL && argv[c]) {
635 xasprintf (&statopts, "%s", argv[c++]);
636 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
637 options |= STAT;
640 /* this will abort in case of invalid ranges */
641 set_thresholds (&procs_thresholds, warning_range, critical_range);
643 return validate_arguments ();
649 validate_arguments ()
651 if (options == 0)
652 options = ALL;
654 if (statopts==NULL)
655 statopts = strdup("");
657 if (prog==NULL)
658 prog = strdup("");
660 if (args==NULL)
661 args = strdup("");
663 if (fmt==NULL)
664 fmt = strdup("");
666 if (fails==NULL)
667 fails = strdup("");
669 return options;
673 /* convert the elapsed time to seconds */
675 convert_to_seconds(char *etime) {
677 char *ptr;
678 int total;
680 int hyphcnt;
681 int coloncnt;
682 int days;
683 int hours;
684 int minutes;
685 int seconds;
687 hyphcnt = 0;
688 coloncnt = 0;
689 days = 0;
690 hours = 0;
691 minutes = 0;
692 seconds = 0;
694 for (ptr = etime; *ptr != '\0'; ptr++) {
696 if (*ptr == '-') {
697 hyphcnt++;
698 continue;
700 if (*ptr == ':') {
701 coloncnt++;
702 continue;
706 if (hyphcnt > 0) {
707 sscanf(etime, "%d-%d:%d:%d",
708 &days, &hours, &minutes, &seconds);
709 /* linux 2.6.5/2.6.6 reporting some processes with infinite
710 * elapsed times for some reason */
711 if (days == 49710) {
712 return 0;
714 } else {
715 if (coloncnt == 2) {
716 sscanf(etime, "%d:%d:%d",
717 &hours, &minutes, &seconds);
718 } else if (coloncnt == 1) {
719 sscanf(etime, "%d:%d",
720 &minutes, &seconds);
724 total = (days * 86400) +
725 (hours * 3600) +
726 (minutes * 60) +
727 seconds;
729 if (verbose >= 3 && metric == METRIC_ELAPSED) {
730 printf("seconds: %d\n", total);
732 return total;
736 void
737 print_help (void)
739 print_revision (progname, NP_VERSION);
741 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
742 printf (COPYRIGHT, copyright, email);
744 printf ("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
745 printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number"));
746 printf ("%s\n", _("of processes. Search filters can be applied to limit the processes to check."));
748 printf ("\n\n");
750 printf ("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)"));
751 printf ("%s\n", _("are excluded from any checks to prevent false positives."));
753 printf ("\n\n");
755 print_usage ();
757 printf (UT_HELP_VRSN);
758 printf (UT_EXTRA_OPTS);
759 printf (" %s\n", "-w, --warning=RANGE");
760 printf (" %s\n", _("Generate warning state if metric is outside this range"));
761 printf (" %s\n", "-c, --critical=RANGE");
762 printf (" %s\n", _("Generate critical state if metric is outside this range"));
763 printf (" %s\n", "-m, --metric=TYPE");
764 printf (" %s\n", _("Check thresholds against metric. Valid types:"));
765 printf (" %s\n", _("PROCS - number of processes (default)"));
766 printf (" %s\n", _("VSZ - virtual memory size"));
767 printf (" %s\n", _("RSS - resident set memory size"));
768 printf (" %s\n", _("CPU - percentage CPU"));
769 /* only linux etime is support currently */
770 #if defined( __linux__ )
771 printf (" %s\n", _("ELAPSED - time elapsed in seconds"));
772 #endif /* defined(__linux__) */
773 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
775 printf (" %s\n", "-v, --verbose");
776 printf (" %s\n", _("Extra information. Up to 3 verbosity levels"));
778 printf (" %s\n", "-T, --traditional");
779 printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
781 printf ("\n");
782 printf ("%s\n", "Filters:");
783 printf (" %s\n", "-s, --state=STATUSFLAGS");
784 printf (" %s\n", _("Only scan for processes that have, in the output of `ps`, one or"));
785 printf (" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,"));
786 printf (" %s\n", _("RSZDT, plus others based on the output of your 'ps' command)."));
787 printf (" %s\n", "-p, --ppid=PPID");
788 printf (" %s\n", _("Only scan for children of the parent process ID indicated."));
789 printf (" %s\n", "-z, --vsz=VSZ");
790 printf (" %s\n", _("Only scan for processes with VSZ higher than indicated."));
791 printf (" %s\n", "-r, --rss=RSS");
792 printf (" %s\n", _("Only scan for processes with RSS higher than indicated."));
793 printf (" %s\n", "-P, --pcpu=PCPU");
794 printf (" %s\n", _("Only scan for processes with PCPU higher than indicated."));
795 printf (" %s\n", "-u, --user=USER");
796 printf (" %s\n", _("Only scan for processes with user name or ID indicated."));
797 printf (" %s\n", "-a, --argument-array=STRING");
798 printf (" %s\n", _("Only scan for processes with args that contain STRING."));
799 printf (" %s\n", "--ereg-argument-array=STRING");
800 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING."));
801 printf (" %s\n", "-C, --command=COMMAND");
802 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
803 printf (" %s\n", "-X, --exclude-process");
804 printf (" %s\n", _("Exclude processes which match this comma separated list"));
805 printf (" %s\n", "-k, --no-kthreads");
806 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
808 printf(_("\n\
809 RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
810 specified 'max:min', a warning status will be generated if the\n\
811 count is inside the specified range\n\n"));
813 printf(_("\
814 This plugin checks the number of currently running processes and\n\
815 generates WARNING or CRITICAL states if the process count is outside\n\
816 the specified threshold ranges. The process count can be filtered by\n\
817 process owner, parent process PID, current state (e.g., 'Z'), or may\n\
818 be the total number of running processes\n\n"));
820 printf ("%s\n", _("Examples:"));
821 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry");
822 printf (" %s\n", _("Warning if not two processes with command name portsentry."));
823 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes"));
824 printf (" %s\n", "check_procs -c 1: -C sshd");
825 printf (" %s\n", _("Critical if not at least 1 process with command sshd"));
826 printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd");
827 printf (" %s\n", _("Warning if > 1024 processes with command name sshd."));
828 printf (" %s\n\n", _("Critical if < 1 processes with command name sshd."));
829 printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root");
830 printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing"));
831 printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
832 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ");
833 printf (" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K"));
834 printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU");
835 printf (" %s\n", _("Alert if CPU of any processes over 10%% or 20%%"));
837 printf (UT_SUPPORT);
840 void
841 print_usage (void)
843 printf ("%s\n", _("Usage:"));
844 printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
845 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
846 printf (" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");