diff options
Diffstat (limited to 'plugins/check_procs.c')
-rw-r--r-- | plugins/check_procs.c | 190 |
1 files changed, 97 insertions, 93 deletions
diff --git a/plugins/check_procs.c b/plugins/check_procs.c index 2f2dcc5..d09bd8b 100644 --- a/plugins/check_procs.c +++ b/plugins/check_procs.c | |||
@@ -42,18 +42,21 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net"; | |||
42 | #include "regex.h" | 42 | #include "regex.h" |
43 | 43 | ||
44 | #include <pwd.h> | 44 | #include <pwd.h> |
45 | #include <errno.h> | ||
46 | |||
47 | #ifdef HAVE_SYS_STAT_H | ||
48 | #include <sys/stat.h> | ||
49 | #endif | ||
45 | 50 | ||
46 | int process_arguments (int, char **); | 51 | int process_arguments (int, char **); |
47 | int validate_arguments (void); | 52 | int validate_arguments (void); |
48 | int check_thresholds (int); | ||
49 | int convert_to_seconds (char *); | 53 | int convert_to_seconds (char *); |
50 | void print_help (void); | 54 | void print_help (void); |
51 | void print_usage (void); | 55 | void print_usage (void); |
52 | 56 | ||
53 | int wmax = -1; | 57 | char *warning_range = NULL; |
54 | int cmax = -1; | 58 | char *critical_range = NULL; |
55 | int wmin = -1; | 59 | thresholds *procs_thresholds = NULL; |
56 | int cmin = -1; | ||
57 | 60 | ||
58 | int options = 0; /* bitmask of filter criteria to test against */ | 61 | int options = 0; /* bitmask of filter criteria to test against */ |
59 | #define ALL 1 | 62 | #define ALL 1 |
@@ -67,6 +70,10 @@ int options = 0; /* bitmask of filter criteria to test against */ | |||
67 | #define PCPU 256 | 70 | #define PCPU 256 |
68 | #define ELAPSED 512 | 71 | #define ELAPSED 512 |
69 | #define EREG_ARGS 1024 | 72 | #define EREG_ARGS 1024 |
73 | |||
74 | #define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads: | ||
75 | ppid of procs are compared to pid of this proc*/ | ||
76 | |||
70 | /* Different metrics */ | 77 | /* Different metrics */ |
71 | char *metric_name; | 78 | char *metric_name; |
72 | enum metric { | 79 | enum metric { |
@@ -92,9 +99,21 @@ regex_t re_args; | |||
92 | char *fmt; | 99 | char *fmt; |
93 | char *fails; | 100 | char *fails; |
94 | char tmp[MAX_INPUT_BUFFER]; | 101 | char tmp[MAX_INPUT_BUFFER]; |
102 | int kthread_filter = 0; | ||
103 | int usepid = 0; /* whether to test for pid or /proc/pid/exe */ | ||
95 | 104 | ||
96 | FILE *ps_input = NULL; | 105 | FILE *ps_input = NULL; |
97 | 106 | ||
107 | static int | ||
108 | stat_exe (const pid_t pid, struct stat *buf) { | ||
109 | char *path; | ||
110 | int ret; | ||
111 | xasprintf(&path, "/proc/%d/exe", pid); | ||
112 | ret = stat(path, buf); | ||
113 | free(path); | ||
114 | return ret; | ||
115 | } | ||
116 | |||
98 | 117 | ||
99 | int | 118 | int |
100 | main (int argc, char **argv) | 119 | main (int argc, char **argv) |
@@ -104,9 +123,13 @@ main (int argc, char **argv) | |||
104 | char *procprog; | 123 | char *procprog; |
105 | 124 | ||
106 | pid_t mypid = 0; | 125 | pid_t mypid = 0; |
126 | struct stat statbuf; | ||
127 | dev_t mydev = 0; | ||
128 | ino_t myino = 0; | ||
107 | int procuid = 0; | 129 | int procuid = 0; |
108 | pid_t procpid = 0; | 130 | pid_t procpid = 0; |
109 | pid_t procppid = 0; | 131 | pid_t procppid = 0; |
132 | pid_t kthread_ppid = 0; | ||
110 | int procvsz = 0; | 133 | int procvsz = 0; |
111 | int procrss = 0; | 134 | int procrss = 0; |
112 | int procseconds = 0; | 135 | int procseconds = 0; |
@@ -127,6 +150,7 @@ main (int argc, char **argv) | |||
127 | int crit = 0; /* number of processes in crit state */ | 150 | int crit = 0; /* number of processes in crit state */ |
128 | int i = 0, j = 0; | 151 | int i = 0, j = 0; |
129 | int result = STATE_UNKNOWN; | 152 | int result = STATE_UNKNOWN; |
153 | int ret; | ||
130 | output chld_out, chld_err; | 154 | output chld_out, chld_err; |
131 | 155 | ||
132 | setlocale (LC_ALL, ""); | 156 | setlocale (LC_ALL, ""); |
@@ -146,8 +170,16 @@ main (int argc, char **argv) | |||
146 | if (process_arguments (argc, argv) == ERROR) | 170 | if (process_arguments (argc, argv) == ERROR) |
147 | usage4 (_("Could not parse arguments")); | 171 | usage4 (_("Could not parse arguments")); |
148 | 172 | ||
149 | /* get our pid */ | 173 | /* find ourself */ |
150 | mypid = getpid(); | 174 | mypid = getpid(); |
175 | if (usepid || stat_exe(mypid, &statbuf) == -1) { | ||
176 | /* usepid might have been set by -T */ | ||
177 | usepid = 1; | ||
178 | } else { | ||
179 | usepid = 0; | ||
180 | mydev = statbuf.st_dev; | ||
181 | myino = statbuf.st_ino; | ||
182 | } | ||
151 | 183 | ||
152 | /* Set signal handling and alarm timeout */ | 184 | /* Set signal handling and alarm timeout */ |
153 | if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { | 185 | if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { |
@@ -202,7 +234,28 @@ main (int argc, char **argv) | |||
202 | procetime, procprog, procargs); | 234 | procetime, procprog, procargs); |
203 | 235 | ||
204 | /* Ignore self */ | 236 | /* Ignore self */ |
205 | if (mypid == procpid) continue; | 237 | if ((usepid && mypid == procpid) || |
238 | (!usepid && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino) || | ||
239 | (ret == -1 && errno == ENOENT))) { | ||
240 | if (verbose >= 3) | ||
241 | printf("not considering - is myself or gone\n"); | ||
242 | continue; | ||
243 | } | ||
244 | |||
245 | /* filter kernel threads (childs of KTHREAD_PARENT)*/ | ||
246 | /* TODO adapt for other OSes than GNU/Linux | ||
247 | sorry for not doing that, but I've no other OSes to test :-( */ | ||
248 | if (kthread_filter == 1) { | ||
249 | /* get pid KTHREAD_PARENT */ | ||
250 | if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) ) | ||
251 | kthread_ppid = procpid; | ||
252 | |||
253 | if (kthread_ppid == procppid) { | ||
254 | if (verbose >= 2) | ||
255 | printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs); | ||
256 | continue; | ||
257 | } | ||
258 | } | ||
206 | 259 | ||
207 | if ((options & STAT) && (strstr (statopts, procstat))) | 260 | if ((options & STAT) && (strstr (statopts, procstat))) |
208 | resultsum |= STAT; | 261 | resultsum |= STAT; |
@@ -238,14 +291,14 @@ main (int argc, char **argv) | |||
238 | } | 291 | } |
239 | 292 | ||
240 | if (metric == METRIC_VSZ) | 293 | if (metric == METRIC_VSZ) |
241 | i = check_thresholds (procvsz); | 294 | i = get_status ((double)procvsz, procs_thresholds); |
242 | else if (metric == METRIC_RSS) | 295 | else if (metric == METRIC_RSS) |
243 | i = check_thresholds (procrss); | 296 | i = get_status ((double)procrss, procs_thresholds); |
244 | /* TODO? float thresholds for --metric=CPU */ | 297 | /* TODO? float thresholds for --metric=CPU */ |
245 | else if (metric == METRIC_CPU) | 298 | else if (metric == METRIC_CPU) |
246 | i = check_thresholds ((int)procpcpu); | 299 | i = get_status (procpcpu, procs_thresholds); |
247 | else if (metric == METRIC_ELAPSED) | 300 | else if (metric == METRIC_ELAPSED) |
248 | i = check_thresholds (procseconds); | 301 | i = get_status ((double)procseconds, procs_thresholds); |
249 | 302 | ||
250 | if (metric != METRIC_PROCS) { | 303 | if (metric != METRIC_PROCS) { |
251 | if (i == STATE_WARNING) { | 304 | if (i == STATE_WARNING) { |
@@ -276,7 +329,7 @@ main (int argc, char **argv) | |||
276 | 329 | ||
277 | /* Needed if procs found, but none match filter */ | 330 | /* Needed if procs found, but none match filter */ |
278 | if ( metric == METRIC_PROCS ) { | 331 | if ( metric == METRIC_PROCS ) { |
279 | result = max_state (result, check_thresholds (procs) ); | 332 | result = max_state (result, get_status ((double)procs, procs_thresholds) ); |
280 | } | 333 | } |
281 | 334 | ||
282 | if ( result == STATE_OK ) { | 335 | if ( result == STATE_OK ) { |
@@ -301,6 +354,13 @@ main (int argc, char **argv) | |||
301 | if ( verbose >= 1 && strcmp(fails,"") ) | 354 | if ( verbose >= 1 && strcmp(fails,"") ) |
302 | printf (" [%s]", fails); | 355 | printf (" [%s]", fails); |
303 | 356 | ||
357 | if (metric == METRIC_PROCS) | ||
358 | printf (" | procs=%d;%s;%s;0;", procs, | ||
359 | warning_range ? warning_range : "", | ||
360 | critical_range ? critical_range : ""); | ||
361 | else | ||
362 | printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit); | ||
363 | |||
304 | printf ("\n"); | 364 | printf ("\n"); |
305 | return result; | 365 | return result; |
306 | } | 366 | } |
@@ -327,6 +387,7 @@ process_arguments (int argc, char **argv) | |||
327 | {"timeout", required_argument, 0, 't'}, | 387 | {"timeout", required_argument, 0, 't'}, |
328 | {"status", required_argument, 0, 's'}, | 388 | {"status", required_argument, 0, 's'}, |
329 | {"ppid", required_argument, 0, 'p'}, | 389 | {"ppid", required_argument, 0, 'p'}, |
390 | {"user", required_argument, 0, 'u'}, | ||
330 | {"command", required_argument, 0, 'C'}, | 391 | {"command", required_argument, 0, 'C'}, |
331 | {"vsz", required_argument, 0, 'z'}, | 392 | {"vsz", required_argument, 0, 'z'}, |
332 | {"rss", required_argument, 0, 'r'}, | 393 | {"rss", required_argument, 0, 'r'}, |
@@ -338,6 +399,8 @@ process_arguments (int argc, char **argv) | |||
338 | {"verbose", no_argument, 0, 'v'}, | 399 | {"verbose", no_argument, 0, 'v'}, |
339 | {"ereg-argument-array", required_argument, 0, CHAR_MAX+1}, | 400 | {"ereg-argument-array", required_argument, 0, CHAR_MAX+1}, |
340 | {"input-file", required_argument, 0, CHAR_MAX+2}, | 401 | {"input-file", required_argument, 0, CHAR_MAX+2}, |
402 | {"no-kthreads", required_argument, 0, 'k'}, | ||
403 | {"traditional-filter", no_argument, 0, 'T'}, | ||
341 | {0, 0, 0, 0} | 404 | {0, 0, 0, 0} |
342 | }; | 405 | }; |
343 | 406 | ||
@@ -346,7 +409,7 @@ process_arguments (int argc, char **argv) | |||
346 | strcpy (argv[c], "-t"); | 409 | strcpy (argv[c], "-t"); |
347 | 410 | ||
348 | while (1) { | 411 | while (1) { |
349 | c = getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:z:r:m:P:", | 412 | c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T", |
350 | longopts, &option); | 413 | longopts, &option); |
351 | 414 | ||
352 | if (c == -1 || c == EOF) | 415 | if (c == -1 || c == EOF) |
@@ -368,28 +431,10 @@ process_arguments (int argc, char **argv) | |||
368 | timeout_interval = atoi (optarg); | 431 | timeout_interval = atoi (optarg); |
369 | break; | 432 | break; |
370 | case 'c': /* critical threshold */ | 433 | case 'c': /* critical threshold */ |
371 | if (is_integer (optarg)) | 434 | critical_range = optarg; |
372 | cmax = atoi (optarg); | ||
373 | else if (sscanf (optarg, ":%d", &cmax) == 1) | ||
374 | break; | ||
375 | else if (sscanf (optarg, "%d:%d", &cmin, &cmax) == 2) | ||
376 | break; | ||
377 | else if (sscanf (optarg, "%d:", &cmin) == 1) | ||
378 | break; | ||
379 | else | ||
380 | usage4 (_("Critical Process Count must be an integer!")); | ||
381 | break; | 435 | break; |
382 | case 'w': /* warning threshold */ | 436 | case 'w': /* warning threshold */ |
383 | if (is_integer (optarg)) | 437 | warning_range = optarg; |
384 | wmax = atoi (optarg); | ||
385 | else if (sscanf (optarg, ":%d", &wmax) == 1) | ||
386 | break; | ||
387 | else if (sscanf (optarg, "%d:%d", &wmin, &wmax) == 2) | ||
388 | break; | ||
389 | else if (sscanf (optarg, "%d:", &wmin) == 1) | ||
390 | break; | ||
391 | else | ||
392 | usage4 (_("Warning Process Count must be an integer!")); | ||
393 | break; | 438 | break; |
394 | case 'p': /* process id */ | 439 | case 'p': /* process id */ |
395 | if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { | 440 | if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { |
@@ -508,9 +553,15 @@ process_arguments (int argc, char **argv) | |||
508 | } | 553 | } |
509 | 554 | ||
510 | usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); | 555 | usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); |
556 | case 'k': /* linux kernel thread filter */ | ||
557 | kthread_filter = 1; | ||
558 | break; | ||
511 | case 'v': /* command */ | 559 | case 'v': /* command */ |
512 | verbose++; | 560 | verbose++; |
513 | break; | 561 | break; |
562 | case 'T': | ||
563 | usepid = 1; | ||
564 | break; | ||
514 | case CHAR_MAX+2: | 565 | case CHAR_MAX+2: |
515 | input_filename = optarg; | 566 | input_filename = optarg; |
516 | break; | 567 | break; |
@@ -518,16 +569,19 @@ process_arguments (int argc, char **argv) | |||
518 | } | 569 | } |
519 | 570 | ||
520 | c = optind; | 571 | c = optind; |
521 | if (wmax == -1 && argv[c]) | 572 | if ((! warning_range) && argv[c]) |
522 | wmax = atoi (argv[c++]); | 573 | warning_range = argv[c++]; |
523 | if (cmax == -1 && argv[c]) | 574 | if ((! critical_range) && argv[c]) |
524 | cmax = atoi (argv[c++]); | 575 | critical_range = argv[c++]; |
525 | if (statopts == NULL && argv[c]) { | 576 | if (statopts == NULL && argv[c]) { |
526 | xasprintf (&statopts, "%s", argv[c++]); | 577 | xasprintf (&statopts, "%s", argv[c++]); |
527 | xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); | 578 | xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); |
528 | options |= STAT; | 579 | options |= STAT; |
529 | } | 580 | } |
530 | 581 | ||
582 | /* this will abort in case of invalid ranges */ | ||
583 | set_thresholds (&procs_thresholds, warning_range, critical_range); | ||
584 | |||
531 | return validate_arguments (); | 585 | return validate_arguments (); |
532 | } | 586 | } |
533 | 587 | ||
@@ -536,27 +590,6 @@ process_arguments (int argc, char **argv) | |||
536 | int | 590 | int |
537 | validate_arguments () | 591 | validate_arguments () |
538 | { | 592 | { |
539 | |||
540 | if (wmax >= 0 && wmin == -1) | ||
541 | wmin = 0; | ||
542 | if (cmax >= 0 && cmin == -1) | ||
543 | cmin = 0; | ||
544 | if (wmax >= wmin && cmax >= cmin) { /* standard ranges */ | ||
545 | if (wmax > cmax && cmax != -1) { | ||
546 | printf (_("wmax (%d) cannot be greater than cmax (%d)\n"), wmax, cmax); | ||
547 | return ERROR; | ||
548 | } | ||
549 | if (cmin > wmin && wmin != -1) { | ||
550 | printf (_("wmin (%d) cannot be less than cmin (%d)\n"), wmin, cmin); | ||
551 | return ERROR; | ||
552 | } | ||
553 | } | ||
554 | |||
555 | /* if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { */ | ||
556 | /* printf ("At least one threshold must be set\n"); */ | ||
557 | /* return ERROR; */ | ||
558 | /* } */ | ||
559 | |||
560 | if (options == 0) | 593 | if (options == 0) |
561 | options = ALL; | 594 | options = ALL; |
562 | 595 | ||
@@ -579,40 +612,6 @@ validate_arguments () | |||
579 | } | 612 | } |
580 | 613 | ||
581 | 614 | ||
582 | |||
583 | /* Check thresholds against value */ | ||
584 | int | ||
585 | check_thresholds (int value) | ||
586 | { | ||
587 | if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) { | ||
588 | return OK; | ||
589 | } | ||
590 | else if (cmax >= 0 && cmin >= 0 && cmax < cmin) { | ||
591 | if (value > cmax && value < cmin) | ||
592 | return STATE_CRITICAL; | ||
593 | } | ||
594 | else if (cmax >= 0 && value > cmax) { | ||
595 | return STATE_CRITICAL; | ||
596 | } | ||
597 | else if (cmin >= 0 && value < cmin) { | ||
598 | return STATE_CRITICAL; | ||
599 | } | ||
600 | |||
601 | if (wmax >= 0 && wmin >= 0 && wmax < wmin) { | ||
602 | if (value > wmax && value < wmin) { | ||
603 | return STATE_WARNING; | ||
604 | } | ||
605 | } | ||
606 | else if (wmax >= 0 && value > wmax) { | ||
607 | return STATE_WARNING; | ||
608 | } | ||
609 | else if (wmin >= 0 && value < wmin) { | ||
610 | return STATE_WARNING; | ||
611 | } | ||
612 | return STATE_OK; | ||
613 | } | ||
614 | |||
615 | |||
616 | /* convert the elapsed time to seconds */ | 615 | /* convert the elapsed time to seconds */ |
617 | int | 616 | int |
618 | convert_to_seconds(char *etime) { | 617 | convert_to_seconds(char *etime) { |
@@ -713,6 +712,9 @@ print_help (void) | |||
713 | printf (" %s\n", "-v, --verbose"); | 712 | printf (" %s\n", "-v, --verbose"); |
714 | printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); | 713 | printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); |
715 | 714 | ||
715 | printf (" %s\n", "-T, --traditional"); | ||
716 | printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe")); | ||
717 | |||
716 | printf ("\n"); | 718 | printf ("\n"); |
717 | printf ("%s\n", "Filters:"); | 719 | printf ("%s\n", "Filters:"); |
718 | printf (" %s\n", "-s, --state=STATUSFLAGS"); | 720 | printf (" %s\n", "-s, --state=STATUSFLAGS"); |
@@ -735,6 +737,8 @@ print_help (void) | |||
735 | printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); | 737 | printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); |
736 | printf (" %s\n", "-C, --command=COMMAND"); | 738 | printf (" %s\n", "-C, --command=COMMAND"); |
737 | printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); | 739 | printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); |
740 | printf (" %s\n", "-k, --no-kthreads"); | ||
741 | printf (" %s\n", _("Only scan for non kernel threads (works on Linux only).")); | ||
738 | 742 | ||
739 | printf(_("\n\ | 743 | printf(_("\n\ |
740 | RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\ | 744 | RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\ |
@@ -769,5 +773,5 @@ print_usage (void) | |||
769 | printf ("%s\n", _("Usage:")); | 773 | printf ("%s\n", _("Usage:")); |
770 | printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname); | 774 | printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname); |
771 | printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n"); | 775 | printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n"); |
772 | printf (" [-C command] [-t timeout] [-v]\n"); | 776 | printf (" [-C command] [-k] [-t timeout] [-v]\n"); |
773 | } | 777 | } |