Imported Upstream version 1.4.16+git20130902

This commit is contained in:
Jan Wagner 2013-11-26 23:59:47 +01:00
parent e76be63abf
commit e70fb8c051
517 changed files with 44015 additions and 43295 deletions

View file

@ -42,18 +42,21 @@ const char *email = "nagiosplug-devel@lists.sourceforge.net";
#include "regex.h"
#include <pwd.h>
#include <errno.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
int process_arguments (int, char **);
int validate_arguments (void);
int check_thresholds (int);
int convert_to_seconds (char *);
void print_help (void);
void print_usage (void);
int wmax = -1;
int cmax = -1;
int wmin = -1;
int cmin = -1;
char *warning_range = NULL;
char *critical_range = NULL;
thresholds *procs_thresholds = NULL;
int options = 0; /* bitmask of filter criteria to test against */
#define ALL 1
@ -67,6 +70,10 @@ int options = 0; /* bitmask of filter criteria to test against */
#define PCPU 256
#define ELAPSED 512
#define EREG_ARGS 1024
#define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads:
ppid of procs are compared to pid of this proc*/
/* Different metrics */
char *metric_name;
enum metric {
@ -92,9 +99,21 @@ regex_t re_args;
char *fmt;
char *fails;
char tmp[MAX_INPUT_BUFFER];
int kthread_filter = 0;
int usepid = 0; /* whether to test for pid or /proc/pid/exe */
FILE *ps_input = NULL;
static int
stat_exe (const pid_t pid, struct stat *buf) {
char *path;
int ret;
xasprintf(&path, "/proc/%d/exe", pid);
ret = stat(path, buf);
free(path);
return ret;
}
int
main (int argc, char **argv)
@ -104,9 +123,13 @@ main (int argc, char **argv)
char *procprog;
pid_t mypid = 0;
struct stat statbuf;
dev_t mydev = 0;
ino_t myino = 0;
int procuid = 0;
pid_t procpid = 0;
pid_t procppid = 0;
pid_t kthread_ppid = 0;
int procvsz = 0;
int procrss = 0;
int procseconds = 0;
@ -127,6 +150,7 @@ main (int argc, char **argv)
int crit = 0; /* number of processes in crit state */
int i = 0, j = 0;
int result = STATE_UNKNOWN;
int ret;
output chld_out, chld_err;
setlocale (LC_ALL, "");
@ -137,7 +161,7 @@ main (int argc, char **argv)
input_buffer = malloc (MAX_INPUT_BUFFER);
procprog = malloc (MAX_INPUT_BUFFER);
asprintf (&metric_name, "PROCS");
xasprintf (&metric_name, "PROCS");
metric = METRIC_PROCS;
/* Parse extra opts if any */
@ -146,8 +170,16 @@ main (int argc, char **argv)
if (process_arguments (argc, argv) == ERROR)
usage4 (_("Could not parse arguments"));
/* get our pid */
/* find ourself */
mypid = getpid();
if (usepid || stat_exe(mypid, &statbuf) == -1) {
/* usepid might have been set by -T */
usepid = 1;
} else {
usepid = 0;
mydev = statbuf.st_dev;
myino = statbuf.st_ino;
}
/* Set signal handling and alarm timeout */
if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
@ -176,7 +208,7 @@ main (int argc, char **argv)
printf ("%s", input_line);
strcpy (procprog, "");
asprintf (&procargs, "%s", "");
xasprintf (&procargs, "%s", "");
cols = sscanf (input_line, PS_FORMAT, PS_VARLIST);
@ -186,7 +218,7 @@ main (int argc, char **argv)
}
if ( cols >= expected_cols ) {
resultsum = 0;
asprintf (&procargs, "%s", input_line + pos);
xasprintf (&procargs, "%s", input_line + pos);
strip (procargs);
/* Some ps return full pathname for command. This removes path */
@ -202,7 +234,28 @@ main (int argc, char **argv)
procetime, procprog, procargs);
/* Ignore self */
if (mypid == procpid) continue;
if ((usepid && mypid == procpid) ||
(!usepid && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino) ||
(ret == -1 && errno == ENOENT))) {
if (verbose >= 3)
printf("not considering - is myself or gone\n");
continue;
}
/* filter kernel threads (childs of KTHREAD_PARENT)*/
/* TODO adapt for other OSes than GNU/Linux
sorry for not doing that, but I've no other OSes to test :-( */
if (kthread_filter == 1) {
/* get pid KTHREAD_PARENT */
if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) )
kthread_ppid = procpid;
if (kthread_ppid == procppid) {
if (verbose >= 2)
printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs);
continue;
}
}
if ((options & STAT) && (strstr (statopts, procstat)))
resultsum |= STAT;
@ -238,24 +291,24 @@ main (int argc, char **argv)
}
if (metric == METRIC_VSZ)
i = check_thresholds (procvsz);
i = get_status ((double)procvsz, procs_thresholds);
else if (metric == METRIC_RSS)
i = check_thresholds (procrss);
i = get_status ((double)procrss, procs_thresholds);
/* TODO? float thresholds for --metric=CPU */
else if (metric == METRIC_CPU)
i = check_thresholds ((int)procpcpu);
i = get_status (procpcpu, procs_thresholds);
else if (metric == METRIC_ELAPSED)
i = check_thresholds (procseconds);
i = get_status ((double)procseconds, procs_thresholds);
if (metric != METRIC_PROCS) {
if (i == STATE_WARNING) {
warn++;
asprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
result = max_state (result, i);
}
if (i == STATE_CRITICAL) {
crit++;
asprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog);
result = max_state (result, i);
}
}
@ -276,7 +329,7 @@ main (int argc, char **argv)
/* Needed if procs found, but none match filter */
if ( metric == METRIC_PROCS ) {
result = max_state (result, check_thresholds (procs) );
result = max_state (result, get_status ((double)procs, procs_thresholds) );
}
if ( result == STATE_OK ) {
@ -301,6 +354,13 @@ main (int argc, char **argv)
if ( verbose >= 1 && strcmp(fails,"") )
printf (" [%s]", fails);
if (metric == METRIC_PROCS)
printf (" | procs=%d;%s;%s;0;", procs,
warning_range ? warning_range : "",
critical_range ? critical_range : "");
else
printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit);
printf ("\n");
return result;
}
@ -327,6 +387,7 @@ process_arguments (int argc, char **argv)
{"timeout", required_argument, 0, 't'},
{"status", required_argument, 0, 's'},
{"ppid", required_argument, 0, 'p'},
{"user", required_argument, 0, 'u'},
{"command", required_argument, 0, 'C'},
{"vsz", required_argument, 0, 'z'},
{"rss", required_argument, 0, 'r'},
@ -338,6 +399,8 @@ process_arguments (int argc, char **argv)
{"verbose", no_argument, 0, 'v'},
{"ereg-argument-array", required_argument, 0, CHAR_MAX+1},
{"input-file", required_argument, 0, CHAR_MAX+2},
{"no-kthreads", required_argument, 0, 'k'},
{"traditional-filter", no_argument, 0, 'T'},
{0, 0, 0, 0}
};
@ -346,7 +409,7 @@ process_arguments (int argc, char **argv)
strcpy (argv[c], "-t");
while (1) {
c = getopt_long (argc, argv, "Vvht:c:w:p:s:u:C:a:z:r:m:P:",
c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T",
longopts, &option);
if (c == -1 || c == EOF)
@ -368,32 +431,14 @@ process_arguments (int argc, char **argv)
timeout_interval = atoi (optarg);
break;
case 'c': /* critical threshold */
if (is_integer (optarg))
cmax = atoi (optarg);
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
usage4 (_("Critical Process Count must be an integer!"));
critical_range = optarg;
break;
case 'w': /* warning threshold */
if (is_integer (optarg))
wmax = atoi (optarg);
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
usage4 (_("Warning Process Count must be an integer!"));
warning_range = optarg;
break;
case 'p': /* process id */
if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) {
asprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid);
xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid);
options |= PPID;
break;
}
@ -403,7 +448,7 @@ process_arguments (int argc, char **argv)
break;
else
statopts = optarg;
asprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
options |= STAT;
break;
case 'u': /* user or user id */
@ -423,7 +468,7 @@ process_arguments (int argc, char **argv)
uid = pw->pw_uid;
}
user = pw->pw_name;
asprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""),
xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""),
uid, user);
options |= USER;
break;
@ -433,7 +478,7 @@ process_arguments (int argc, char **argv)
break;
else
prog = optarg;
asprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""),
prog);
options |= PROG;
break;
@ -443,7 +488,7 @@ process_arguments (int argc, char **argv)
break;
else
args = optarg;
asprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args);
xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args);
options |= ARGS;
break;
case CHAR_MAX+1:
@ -459,19 +504,19 @@ process_arguments (int argc, char **argv)
temp_string[i]=',';
i++;
}
asprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string);
xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string);
options |= EREG_ARGS;
break;
case 'r': /* RSS */
if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) {
asprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss);
xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss);
options |= RSS;
break;
}
usage4 (_("RSS must be an integer!"));
case 'z': /* VSZ */
if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) {
asprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz);
xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz);
options |= VSZ;
break;
}
@ -479,13 +524,13 @@ process_arguments (int argc, char **argv)
case 'P': /* PCPU */
/* TODO: -P 1.5.5 is accepted */
if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) {
asprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu);
xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu);
options |= PCPU;
break;
}
usage4 (_("PCPU must be a float!"));
case 'm':
asprintf (&metric_name, "%s", optarg);
xasprintf (&metric_name, "%s", optarg);
if ( strcmp(optarg, "PROCS") == 0) {
metric = METRIC_PROCS;
break;
@ -508,9 +553,15 @@ process_arguments (int argc, char **argv)
}
usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
case 'k': /* linux kernel thread filter */
kthread_filter = 1;
break;
case 'v': /* command */
verbose++;
break;
case 'T':
usepid = 1;
break;
case CHAR_MAX+2:
input_filename = optarg;
break;
@ -518,16 +569,19 @@ process_arguments (int argc, char **argv)
}
c = optind;
if (wmax == -1 && argv[c])
wmax = atoi (argv[c++]);
if (cmax == -1 && argv[c])
cmax = atoi (argv[c++]);
if ((! warning_range) && argv[c])
warning_range = argv[c++];
if ((! critical_range) && argv[c])
critical_range = argv[c++];
if (statopts == NULL && argv[c]) {
asprintf (&statopts, "%s", argv[c++]);
asprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
xasprintf (&statopts, "%s", argv[c++]);
xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts);
options |= STAT;
}
/* this will abort in case of invalid ranges */
set_thresholds (&procs_thresholds, warning_range, critical_range);
return validate_arguments ();
}
@ -536,27 +590,6 @@ process_arguments (int argc, char **argv)
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 = ALL;
@ -579,40 +612,6 @@ validate_arguments ()
}
/* Check thresholds against value */
int
check_thresholds (int value)
{
if (wmax == -1 && cmax == -1 && wmin == -1 && cmin == -1) {
return OK;
}
else if (cmax >= 0 && cmin >= 0 && cmax < cmin) {
if (value > cmax && value < cmin)
return STATE_CRITICAL;
}
else if (cmax >= 0 && value > cmax) {
return STATE_CRITICAL;
}
else if (cmin >= 0 && value < cmin) {
return STATE_CRITICAL;
}
if (wmax >= 0 && wmin >= 0 && wmax < wmin) {
if (value > wmax && value < wmin) {
return STATE_WARNING;
}
}
else if (wmax >= 0 && value > wmax) {
return STATE_WARNING;
}
else if (wmin >= 0 && value < wmin) {
return STATE_WARNING;
}
return STATE_OK;
}
/* convert the elapsed time to seconds */
int
convert_to_seconds(char *etime) {
@ -713,6 +712,9 @@ print_help (void)
printf (" %s\n", "-v, --verbose");
printf (" %s\n", _("Extra information. Up to 3 verbosity levels"));
printf (" %s\n", "-T, --traditional");
printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
printf ("\n");
printf ("%s\n", "Filters:");
printf (" %s\n", "-s, --state=STATUSFLAGS");
@ -735,6 +737,8 @@ print_help (void)
printf (" %s\n", _("Only scan for processes with args that contain the regex STRING."));
printf (" %s\n", "-C, --command=COMMAND");
printf (" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
printf (" %s\n", "-k, --no-kthreads");
printf (" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
printf(_("\n\
RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
@ -769,5 +773,5 @@ print_usage (void)
printf ("%s\n", _("Usage:"));
printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
printf (" [-C command] [-t timeout] [-v]\n");
printf (" [-C command] [-k] [-t timeout] [-v]\n");
}