Merge branch 'master' into refactor/check_curl

This commit is contained in:
Lorenz Kästle 2025-07-06 23:41:07 +02:00
commit 6a7c0d067f
96 changed files with 9724 additions and 8679 deletions

View file

@ -4,7 +4,7 @@ TabWidth: 4
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBraces: Attach
AlignConsecutiveMacros: true
ColumnLimit: 140
ColumnLimit: 100
IndentPPDirectives: AfterHash
SortIncludes: Never
AllowShortEnumsOnASingleLine: false

View file

@ -191,9 +191,7 @@ Requires: %{name}-nt
Requires: %{name}-ntp
Requires: %{name}-ntp_peer
Requires: %{name}-ntp_time
Requires: %{name}-nwstat
Requires: %{name}-oracle
Requires: %{name}-overcr
Requires: %{name}-pgsql
Requires: %{name}-ping
Requires: %{name}-procs
@ -703,19 +701,6 @@ Provides check_ntp_time of the Monitoring Plugins.
# check_nwstat
%package nwstat
Summary: Monitoring Plugins - check_nwstat
Requires: %{name} = %{version}-%{release}
%description nwstat
Provides check_nwstat of the Monitoring Plugins.
%files nwstat
%{plugindir}/check_nwstat
# check_oracle
%package oracle
Summary: Monitoring Plugins - check_oracle
@ -729,19 +714,6 @@ Provides check_oracle of the Monitoring Plugins.
# check_overcr
%package overcr
Summary: Monitoring Plugins - check_overcr
Requires: %{name} = %{version}-%{release}
%description overcr
Provides check_overcr of the Monitoring Plugins.
%files overcr
%{plugindir}/check_overcr
# check_pgsql
%package pgsql
Summary: Monitoring Plugins - check_pgsql

View file

@ -1,10 +1,17 @@
#!/bin/sh -e
. /etc/os-release
# workaround for really bare-bones Archlinux containers:
if [ -x "$(command -v pacman)" ]; then
pacman --noconfirm -Sy
pacman --noconfirm -S grep gawk sed
fi
if [ ${ID} == "fedora" -a ${VERSION_ID} -gt 41 ]; then
dnf install -y gawk
fi
os_release_file=
if [ -s "/etc/os-release" ]; then
os_release_file="/etc/os-release"

View file

@ -38,7 +38,7 @@ jobs:
${{ matrix.distro }} \
/bin/sh -c '${{ matrix.prepare }} && \
tools/setup && \
./configure --enable-libtap --with-ipv6=no && \
./configure --enable-libtap && \
make && \
make test && \
make dist && \

View file

@ -35,7 +35,7 @@ jobs:
${{ matrix.distro }} \
/bin/sh -c '${{ matrix.prepare }} && \
tools/setup && \
./configure --enable-libtap --with-ipv6=no && \
./configure --enable-libtap && \
make && \
make test && \
make dist && \

7
.gitignore vendored
View file

@ -114,7 +114,6 @@ NP-VERSION-FILE
/lib/tests/Makefile.in
/lib/tests/test_base64
/lib/tests/test_cmd
/lib/tests/test_disk
/lib/tests/test_tcp
/lib/tests/test_utils
/lib/tests/utils_base.Po
@ -153,6 +152,8 @@ NP-VERSION-FILE
/plugins/check_dbi
/plugins/check_dig
/plugins/check_disk
plugins/check_disk.d/.deps/
plugins/check_disk.d/.dirstamp
/plugins/check_dns
/plugins/check_dummy
/plugins/check_fping
@ -177,8 +178,6 @@ NP-VERSION-FILE
/plugins/check_ntp
/plugins/check_ntp_peer
/plugins/check_ntp_time
/plugins/check_nwstat
/plugins/check_overcr
/plugins/check_pgsql
/plugins/check_ping
/plugins/check_pop
@ -223,7 +222,7 @@ NP-VERSION-FILE
/plugins/tests/Makefile
/plugins/tests/Makefile.in
/plugins/tests/test_utils
/plugins/tests/test_disk
/plugins/tests/test_check_disk
/plugins/tests/test_check_swap
/plugins/tests/.deps
/plugins/tests/.dirstamp

View file

@ -87,10 +87,6 @@ check_ifstatus/check_ifoperstatus
- Requires Net::SNMP perl module
http://www.perl.com/CPAN/modules/by-authors/id/D/DT/DTOWN/
check_nwstat:
- Requires MRTGEXT NLM for Novell Servers
http://forge.novell.com/modules/xfmod/project/?mrtgext
check_nt:
- Requires NSClient to run on the NT server to monitor
http://nsclient.ready2run.nl/

View file

@ -181,10 +181,10 @@ fi
# Finally, define tests if we use libtap
if test "$enable_libtap" = "yes" ; then
EXTRA_TEST="test_utils test_disk test_tcp test_cmd test_base64"
EXTRA_TEST="test_utils test_tcp test_cmd test_base64"
AC_SUBST(EXTRA_TEST)
EXTRA_PLUGIN_TESTS="tests/test_check_swap"
EXTRA_PLUGIN_TESTS="tests/test_check_swap tests/test_check_disk"
AC_SUBST(EXTRA_PLUGIN_TESTS)
fi
@ -796,7 +796,7 @@ elif ps axwo 'stat comm vsz rss user uid pid ppid etime args' 2>/dev/null | \
then
ac_cv_ps_varlist="[procstat,&procuid,&procpid,&procppid,&procvsz,&procrss,&procpcpu,procetime,procprog,&pos]"
ac_cv_ps_command="$PATH_TO_PS axwo 'stat uid pid ppid vsz rss pcpu etime comm args'"
ac_cv_ps_format="%s %d %d %d %d %d %f %s %s %n"
ac_cv_ps_format="%s %u %d %d %d %d %f %s %s %n"
ac_cv_ps_cols=10
AC_MSG_RESULT([$ac_cv_ps_command])
@ -1519,21 +1519,47 @@ then
fi
AC_PATH_PROG(PATH_TO_FPING,fping)
AC_PATH_PROG(PATH_TO_FPING6,fping6)
AC_ARG_WITH(fping_command,
ACX_HELP_STRING([--with-fping-command=PATH],
[Path to fping command]), PATH_TO_FPING=$withval)
AC_ARG_WITH(fping6_command,
ACX_HELP_STRING([--with-fping6-command=PATH],
[Path to fping6 command]), PATH_TO_FPING6=$withval)
if test -n "$PATH_TO_FPING"
then
if test -n "$PATH_TO_FPING"; then
AC_DEFINE_UNQUOTED(PATH_TO_FPING,"$PATH_TO_FPING",[path to fping])
EXTRAS="$EXTRAS check_fping\$(EXEEXT)"
if test x"$with_ipv6" != xno && test -n "$PATH_TO_FPING6"; then
AC_DEFINE_UNQUOTED(PATH_TO_FPING6,"$PATH_TO_FPING6",[path to fping6])
if test -z "$($PATH_TO_FPING --version)" ; then
AC_MSG_NOTICE([failed to get version of fping])
else
FPING_MAJOR_VERSION="$($PATH_TO_FPING --version | sed 's/.*fping: Version //' | sed 's/\..*//')"
FPING_MINOR_VERSION="$($PATH_TO_FPING --version | sed 's/.*fping: Version //' | sed 's/.*\.//')"
if test $FPING_MAJOR_VERSION -eq 5 ; then
if test $FPING_MINOR_VERSION -ge 3 ; then
AC_DEFINE(FPING_VERSION_5_3_OR_HIGHER, "true", [fping is of version 5.3 or higher])
AC_MSG_NOTICE([fping is of version 5.3 or higher])
AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
AC_MSG_NOTICE([fping is of version 5.2 or higher])
elif test $FPING_MINOR_VERSION -ge 2 ; then
AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
AC_MSG_NOTICE([fping is of version 5.2 or higher])
else
AC_MSG_NOTICE([fping is of a version lower then 5.2])
fi
elif $FPING_MAJOR_VERSION > 5 ; then
AC_DEFINE(FPING_VERSION_5_2_OR_HIGHER, "true", [fping is of version 5.2 or higher])
AC_MSG_NOTICE([fping is of version 5.2 or higher])
AC_DEFINE(FPING_VERSION_5_3_OR_HIGHER, "true", [fping is of version 5.2 or higher])
AC_MSG_NOTICE([fping is of version 5.3 or higher])
fi
if test "`fping --version | sed 's/.*fping: Version //'`" = "5.2" ; then
AC_DEFINE(FPING_VERSION, "5.2", [the version of fping available])
AC_MSG_NOTICE([fping version: 5.2])
elif test "`fping --version | sed 's/.*fping: Version //'`" = "5.3"; then
AC_DEFINE(FPING_VERSION, "5.3", [the version of fping available])
AC_MSG_NOTICE([fping version: 5.3])
fi
fi
else
AC_MSG_WARN([Get fping from http://www.fping.com in order to make check_fping plugin])

View file

@ -7,10 +7,9 @@ noinst_LIBRARIES = libmonitoringplug.a
AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
-I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c
libmonitoringplug_a_SOURCES = utils_base.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c
EXTRA_DIST = utils_base.h \
utils_disk.h \
utils_tcp.h \
utils_cmd.h \
parse_ini.h \

View file

@ -13,9 +13,11 @@
// == Global variables
static mp_output_format output_format = MP_FORMAT_DEFAULT;
static mp_output_detail_level level_of_detail = MP_DETAIL_ALL;
// == Prototypes ==
static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation);
static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
unsigned int indentation);
static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
// == Implementation ==
@ -57,7 +59,9 @@ static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
* It sets useful defaults
*/
mp_check mp_check_init(void) {
mp_check check = {0};
mp_check check = {
.evaluation_function = &mp_eval_check_default,
};
return check;
}
@ -120,7 +124,8 @@ void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], const mp_perfdata
*/
int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) {
if (subcheck.output == NULL) {
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "Sub check output is NULL");
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__,
"Sub check output is NULL");
}
mp_subcheck_list *tmp = NULL;
@ -193,16 +198,33 @@ char *get_subcheck_summary(mp_check check) {
return result;
}
mp_state_enum mp_compute_subcheck_state(const mp_subcheck subcheck) {
if (subcheck.evaluation_function == NULL) {
return mp_eval_subcheck_default(subcheck);
}
return subcheck.evaluation_function(subcheck);
}
/*
* Generate the result state of a mp_subcheck object based on it's own state and it's subchecks states
* Generate the result state of a mp_subcheck object based on its own state and its subchecks
* states
*/
mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) {
if (check.state_set_explicitly) {
return check.state;
mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck) {
if (subcheck.evaluation_function != NULL) {
return subcheck.evaluation_function(subcheck);
}
mp_subcheck_list *scl = check.subchecks;
mp_state_enum result = check.default_state;
if (subcheck.state_set_explicitly) {
return subcheck.state;
}
mp_subcheck_list *scl = subcheck.subchecks;
if (scl == NULL) {
return subcheck.default_state;
}
mp_state_enum result = STATE_OK;
while (scl != NULL) {
result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
@ -212,10 +234,18 @@ mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) {
return result;
}
mp_state_enum mp_compute_check_state(const mp_check check) {
// just a safety check
if (check.evaluation_function == NULL) {
return mp_eval_check_default(check);
}
return check.evaluation_function(check);
}
/*
* Generate the result state of a mp_check object based on it's own state and it's subchecks states
*/
mp_state_enum mp_compute_check_state(const mp_check check) {
mp_state_enum mp_eval_check_default(const mp_check check) {
assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here
mp_subcheck_list *scl = check.subchecks;
@ -247,7 +277,11 @@ char *mp_fmt_output(mp_check check) {
mp_subcheck_list *subchecks = check.subchecks;
while (subchecks != NULL) {
asprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
if (level_of_detail == MP_DETAIL_ALL ||
mp_compute_subcheck_state(subchecks->subcheck) != STATE_OK) {
asprintf(&result, "%s\n%s", result,
fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
}
subchecks = subchecks->next;
}
@ -258,7 +292,8 @@ char *mp_fmt_output(mp_check check) {
if (pd_string == NULL) {
asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
} else {
asprintf(&pd_string, "%s %s", pd_string, fmt_subcheck_perfdata(subchecks->subcheck));
asprintf(&pd_string, "%s %s", pd_string,
fmt_subcheck_perfdata(subchecks->subcheck));
}
subchecks = subchecks->next;
@ -327,22 +362,55 @@ static char *generate_indentation_string(unsigned int indentation) {
/*
* Helper function to generate the output string of mp_subcheck
*/
static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation) {
static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check,
unsigned int indentation) {
char *result = NULL;
mp_subcheck_list *subchecks = NULL;
switch (output_format) {
case MP_FORMAT_MULTI_LINE:
case MP_FORMAT_MULTI_LINE: {
char *tmp_string = NULL;
if ((tmp_string = strchr(check.output, '\n')) != NULL) {
// This is a multiline string, put the correct indentation in before proceeding
char *intermediate_string = "";
bool have_residual_chars = false;
while (tmp_string != NULL) {
*tmp_string = '\0';
asprintf(&intermediate_string, "%s%s\n%s", intermediate_string,check.output, generate_indentation_string(indentation+1)); // one more indentation to make it look better
if (*(tmp_string + 1) != '\0') {
check.output = tmp_string + 1;
have_residual_chars = true;
} else {
// Null after the \n, so this is the end
have_residual_chars = false;
break;
}
tmp_string = strchr(check.output, '\n');
}
// add the rest (if any)
if (have_residual_chars) {
char *tmp = check.output;
xasprintf(&check.output, "%s\n%s%s", intermediate_string, generate_indentation_string(indentation+1), tmp);
} else {
check.output = intermediate_string;
}
}
asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)),
check.output);
subchecks = check.subchecks;
while (subchecks != NULL) {
asprintf(&result, "%s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
asprintf(&result, "%s\n%s", result,
fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
subchecks = subchecks->next;
}
return result;
}
default:
die(STATE_UNKNOWN, "Invalid format");
}
@ -539,3 +607,27 @@ parsed_output_format mp_parse_output_format(char *format_string) {
void mp_set_format(mp_output_format format) { output_format = format; }
mp_output_format mp_get_format(void) { return output_format; }
void mp_set_level_of_detail(mp_output_detail_level level) { level_of_detail = level; }
mp_output_detail_level mp_get_level_of_detail(void) { return level_of_detail; }
mp_state_enum mp_eval_ok(mp_check overall) {
(void)overall;
return STATE_OK;
}
mp_state_enum mp_eval_warning(mp_check overall) {
(void)overall;
return STATE_WARNING;
}
mp_state_enum mp_eval_critical(mp_check overall) {
(void)overall;
return STATE_CRITICAL;
}
mp_state_enum mp_eval_unknown(mp_check overall) {
(void)overall;
return STATE_UNKNOWN;
}

View file

@ -7,15 +7,21 @@
/*
* A partial check result
*/
typedef struct {
typedef struct mp_subcheck mp_subcheck;
struct mp_subcheck {
mp_state_enum state; // OK, Warning, Critical ... set explicitly
mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly
bool state_set_explicitly; // was the state set explicitly (or should it be derived from subchecks)
bool state_set_explicitly; // was the state set explicitly (or should it be derived from
// subchecks)
char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP connection to..")
pd_list *perfdata; // Performance data for this check
char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP
// connection to..")
pd_list *perfdata; // Performance data for this check
struct subcheck_list *subchecks; // subchecks deeper in the hierarchy
} mp_subcheck;
// the evaluation_functions computes the state of subcheck
mp_state_enum (*evaluation_function)(mp_subcheck);
};
/*
* A list of subchecks, used in subchecks and the main check
@ -38,8 +44,18 @@ typedef enum output_format {
/*
* Format related functions
*/
void mp_set_format(mp_output_format format);
mp_output_format mp_get_format(void);
void mp_set_format(mp_output_format format);
mp_output_format mp_get_format(void);
// Output detail level
typedef enum output_detail_level {
MP_DETAIL_ALL,
MP_DETAIL_NON_OK_ONLY,
} mp_output_detail_level;
void mp_set_level_of_detail(mp_output_detail_level level);
mp_output_detail_level mp_get_level_of_detail(void);
/*
* The main state object of a plugin. Exists only ONCE per plugin.
@ -47,10 +63,14 @@ typedef enum output_format {
* The final result is always derived from the children and the "worst" state
* in the first layer of subchecks
*/
typedef struct {
char *summary; // Overall summary, if not set a summary will be automatically generated
typedef struct mp_check mp_check;
struct mp_check {
char *summary; // Overall summary, if not set a summary will be automatically generated
mp_subcheck_list *subchecks;
} mp_check;
// the evaluation_functions computes the state of check
mp_state_enum (*evaluation_function)(mp_check);
};
mp_check mp_check_init(void);
mp_subcheck mp_subcheck_init(void);
@ -68,6 +88,13 @@ void mp_add_summary(mp_check check[static 1], char *summary);
mp_state_enum mp_compute_check_state(mp_check);
mp_state_enum mp_compute_subcheck_state(mp_subcheck);
mp_state_enum mp_eval_ok(mp_check overall);
mp_state_enum mp_eval_warning(mp_check overall);
mp_state_enum mp_eval_critical(mp_check overall);
mp_state_enum mp_eval_unknown(mp_check overall);
mp_state_enum mp_eval_check_default(mp_check check);
mp_state_enum mp_eval_subcheck_default(mp_subcheck subcheck);
typedef struct {
bool parsing_success;
mp_output_format output_format;

View file

@ -33,7 +33,7 @@ char *pd_value_to_string(const mp_perfdata_value pd) {
char *pd_to_string(mp_perfdata pd) {
assert(pd.label != NULL);
char *result = NULL;
asprintf(&result, "%s=", pd.label);
asprintf(&result, "'%s'=", pd.label);
asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
@ -257,6 +257,10 @@ mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
return pd;
}
mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) { return mp_set_pd_value_long_long(pd, (long long)value); }
mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); }
mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); }
mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); }
@ -288,6 +292,10 @@ mp_perfdata_value mp_create_pd_value_double(double value) {
mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); }
mp_perfdata_value mp_create_pd_value_char(char value) { return mp_create_pd_value_long_long((long long)value); }
mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); }
mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
@ -514,3 +522,84 @@ perfdata_value_parser_wrapper parse_pd_value(const char *input) {
}
return result;
}
mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) {
perfdata.max = value;
perfdata.max_present = true;
return perfdata;
}
mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) {
perfdata.min = value;
perfdata.min_present = true;
return perfdata;
}
double mp_get_pd_value(mp_perfdata_value value) {
assert(value.type != PD_TYPE_NONE);
switch (value.type) {
case PD_TYPE_DOUBLE:
return value.pd_double;
case PD_TYPE_INT:
return (double)value.pd_int;
case PD_TYPE_UINT:
return (double)value.pd_uint;
default:
return 0; // just to make the compiler happy
}
}
mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) {
if (left.type == right.type) {
switch (left.type) {
case PD_TYPE_DOUBLE:
left.pd_double *= right.pd_double;
return left;
case PD_TYPE_INT:
left.pd_int *= right.pd_int;
return left;
case PD_TYPE_UINT:
left.pd_uint *= right.pd_uint;
return left;
default:
// what to here?
return left;
}
}
// Different types, oh boy, just do the lazy thing for now and switch to double
switch (left.type) {
case PD_TYPE_INT:
left.pd_double = (double)left.pd_int;
left.type = PD_TYPE_DOUBLE;
break;
case PD_TYPE_UINT:
left.pd_double = (double)left.pd_uint;
left.type = PD_TYPE_DOUBLE;
break;
}
switch (right.type) {
case PD_TYPE_INT:
right.pd_double = (double)right.pd_int;
right.type = PD_TYPE_DOUBLE;
break;
case PD_TYPE_UINT:
right.pd_double = (double)right.pd_uint;
right.type = PD_TYPE_DOUBLE;
break;
}
left.pd_double *= right.pd_double;
return left;
}
mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) {
if (!range.end_infinity) {
range.end = mp_pd_value_multiply(range.end, factor);
}
if (!range.start_infinity) {
range.start = mp_pd_value_multiply(range.start, factor);
}
return range;
}

View file

@ -155,6 +155,8 @@ mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long);
_Generic((V), \
float: mp_create_pd_value_float, \
double: mp_create_pd_value_double, \
char: mp_create_pd_value_char, \
unsigned char: mp_create_pd_value_u_char, \
int: mp_create_pd_value_int, \
unsigned int: mp_create_pd_value_u_int, \
long: mp_create_pd_value_long, \
@ -164,6 +166,8 @@ mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long);
mp_perfdata_value mp_create_pd_value_float(float);
mp_perfdata_value mp_create_pd_value_double(double);
mp_perfdata_value mp_create_pd_value_char(char);
mp_perfdata_value mp_create_pd_value_u_char(unsigned char);
mp_perfdata_value mp_create_pd_value_int(int);
mp_perfdata_value mp_create_pd_value_u_int(unsigned int);
mp_perfdata_value mp_create_pd_value_long(long);
@ -171,6 +175,11 @@ mp_perfdata_value mp_create_pd_value_u_long(unsigned long);
mp_perfdata_value mp_create_pd_value_long_long(long long);
mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long);
mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value);
mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value);
double mp_get_pd_value(mp_perfdata_value value);
/*
* Free the memory used by a pd_list
*/
@ -178,6 +187,13 @@ void pd_list_free(pd_list[1]);
int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value);
// ================
// Helper functions
// ================
mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right);
mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor);
// =================
// String formatters
// =================

View file

@ -8,9 +8,9 @@ check_PROGRAMS = @EXTRA_TEST@
AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
-I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
EXTRA_PROGRAMS = test_utils test_disk test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 test_generic_output
EXTRA_PROGRAMS = test_utils test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 test_generic_output
np_test_scripts = test_base64.t test_cmd.t test_disk.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t test_generic_output.t
np_test_scripts = test_base64.t test_cmd.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t test_generic_output.t
np_test_files = config-dos.ini config-opts.ini config-tiny.ini plugin.ini plugins.ini
EXTRA_DIST = $(np_test_scripts) $(np_test_files) var
@ -29,7 +29,7 @@ AM_CFLAGS = -g -I$(top_srcdir)/lib -I$(top_srcdir)/gl $(tap_cflags)
AM_LDFLAGS = $(tap_ldflags) -ltap
LDADD = $(top_srcdir)/lib/libmonitoringplug.a $(top_srcdir)/gl/libgnu.a $(LIB_CRYPTO)
SOURCES = test_utils.c test_disk.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c test_generic_output.c
SOURCES = test_utils.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c test_generic_output.c
test: ${noinst_PROGRAMS}
perl -MTest::Harness -e '$$Test::Harness::switches=""; runtests(map {$$_ .= ".t"} @ARGV)' $(EXTRA_PROGRAMS)

View file

@ -1,6 +0,0 @@
#!/usr/bin/perl
use Test::More;
if (! -e "./test_disk") {
plan skip_all => "./test_disk not compiled - please enable libtap library to test";
}
exec "./test_disk";

View file

@ -51,9 +51,21 @@ mp_state_enum mp_get_pd_status(mp_perfdata perfdata) {
}
if (perfdata.warn_present) {
if (mp_check_range(perfdata.value, perfdata.warn)) {
return STATE_CRITICAL;
return STATE_WARNING;
}
}
return STATE_OK;
}
mp_thresholds mp_thresholds_set_warn(mp_thresholds thlds, mp_range warn) {
thlds.warning = warn;
thlds.warning_is_set = true;
return thlds;
}
mp_thresholds mp_thresholds_set_crit(mp_thresholds thlds, mp_range crit) {
thlds.critical = crit;
thlds.critical_is_set = true;
return thlds;
}

View file

@ -24,5 +24,8 @@ mp_perfdata mp_pd_set_thresholds(mp_perfdata /* pd */, mp_thresholds /* th */);
mp_state_enum mp_get_pd_status(mp_perfdata /* pd */);
mp_thresholds mp_thresholds_set_warn(mp_thresholds thlds, mp_range warn);
mp_thresholds mp_thresholds_set_crit(mp_thresholds thlds, mp_range crit);
char *fmt_threshold_warning(thresholds th);
char *fmt_threshold_critical(thresholds th);

View file

@ -225,27 +225,15 @@ bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
if (my_range.end_infinity == false && my_range.start_infinity == false) {
// range: .........|---inside---|...........
// value
if ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0)) {
is_inside = true;
} else {
is_inside = false;
}
is_inside = ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0));
} else if (my_range.start_infinity == false && my_range.end_infinity == true) {
// range: .........|---inside---------
// value
if (cmp_perfdata_value(my_range.start, value) < 0) {
is_inside = true;
} else {
is_inside = false;
}
is_inside = (cmp_perfdata_value(my_range.start, value) < 0);
} else if (my_range.start_infinity == true && my_range.end_infinity == false) {
// range: -inside--------|....................
// value
if (cmp_perfdata_value(value, my_range.end) == -1) {
is_inside = true;
} else {
is_inside = false;
}
is_inside = (cmp_perfdata_value(value, my_range.end) == -1);
} else {
// range from -inf to inf, so always inside
is_inside = true;

View file

@ -346,7 +346,7 @@ int cmd_run_array(char *const *argv, output *out, output *err, int flags) {
return _cmd_close(fd);
}
int cmd_file_read(char *filename, output *out, int flags) {
int cmd_file_read(const char *filename, output *out, int flags) {
int fd;
if (out)
memset(out, 0, sizeof(output));

View file

@ -20,7 +20,7 @@ typedef struct output output;
/** prototypes **/
int cmd_run(const char *, output *, output *, int);
int cmd_run_array(char *const *, output *, output *, int);
int cmd_file_read(char *, output *, int);
int cmd_file_read(const char *, output *, int);
/* only multi-threaded plugins need to bother with this */
void cmd_init(void);

View file

@ -1,255 +0,0 @@
/*****************************************************************************
*
* Library for check_disk
*
* License: GPL
* Copyright (c) 1999-2024 Monitoring Plugins Development Team
*
* Description:
*
* This file contains utilities for check_disk. These are tested by libtap
*
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
#include "common.h"
#include "utils_disk.h"
#include "gl/fsusage.h"
#include <string.h>
void np_add_name(struct name_list **list, const char *name) {
struct name_list *new_entry;
new_entry = (struct name_list *)malloc(sizeof *new_entry);
new_entry->name = (char *)name;
new_entry->next = *list;
*list = new_entry;
}
/* @brief Initialises a new regex at the begin of list via regcomp(3)
*
* @details if the regex fails to compile the error code of regcomp(3) is returned
* and list is not modified, otherwise list is modified to point to the new
* element
* @param list Pointer to a linked list of regex_list elements
* @param regex the string containing the regex which should be inserted into the list
* @param clags the cflags parameter for regcomp(3)
*/
int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
if (new_entry == NULL) {
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
}
int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
if (!regcomp_result) {
// regcomp succeeded
new_entry->next = *list;
*list = new_entry;
return 0;
} else {
// regcomp failed
free(new_entry);
return regcomp_result;
}
}
/* Initialises a new parameter at the end of list */
struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name) {
struct parameter_list *current = *list;
struct parameter_list *new_path;
new_path = (struct parameter_list *)malloc(sizeof *new_path);
new_path->name = (char *)malloc(strlen(name) + 1);
new_path->best_match = NULL;
new_path->name_next = NULL;
new_path->name_prev = NULL;
new_path->freespace_bytes = NULL;
new_path->freespace_units = NULL;
new_path->freespace_percent = NULL;
new_path->usedspace_bytes = NULL;
new_path->usedspace_units = NULL;
new_path->usedspace_percent = NULL;
new_path->usedinodes_percent = NULL;
new_path->freeinodes_percent = NULL;
new_path->group = NULL;
new_path->dfree_pct = -1;
new_path->dused_pct = -1;
new_path->total = 0;
new_path->available = 0;
new_path->available_to_root = 0;
new_path->used = 0;
new_path->dused_units = 0;
new_path->dfree_units = 0;
new_path->dtotal_units = 0;
new_path->inodes_total = 0;
new_path->inodes_free = 0;
new_path->inodes_free_to_root = 0;
new_path->inodes_used = 0;
new_path->dused_inodes_percent = 0;
new_path->dfree_inodes_percent = 0;
strcpy(new_path->name, name);
if (current == NULL) {
*list = new_path;
new_path->name_prev = NULL;
} else {
while (current->name_next) {
current = current->name_next;
}
current->name_next = new_path;
new_path->name_prev = current;
}
return new_path;
}
/* Delete a given parameter from list and return pointer to next element*/
struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev) {
if (item == NULL) {
return NULL;
}
struct parameter_list *next;
if (item->name_next)
next = item->name_next;
else
next = NULL;
if (next)
next->name_prev = prev;
if (prev)
prev->name_next = next;
if (item->name) {
free(item->name);
}
free(item);
return next;
}
/* returns a pointer to the struct found in the list */
struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name) {
struct parameter_list *temp_list;
for (temp_list = list; temp_list; temp_list = temp_list->name_next) {
if (!strcmp(temp_list->name, name))
return temp_list;
}
return NULL;
}
void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) {
struct parameter_list *d;
for (d = desired; d; d = d->name_next) {
if (!d->best_match) {
struct mount_entry *me;
size_t name_len = strlen(d->name);
size_t best_match_len = 0;
struct mount_entry *best_match = NULL;
struct fs_usage fsp;
/* set best match if path name exactly matches a mounted device name */
for (me = mount_list; me; me = me->me_next) {
if (strcmp(me->me_devname, d->name) == 0) {
if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
best_match = me;
}
}
}
/* set best match by directory name if no match was found by devname */
if (!best_match) {
for (me = mount_list; me; me = me->me_next) {
size_t len = strlen(me->me_mountdir);
if ((!exact &&
(best_match_len <= len && len <= name_len && (len == 1 || strncmp(me->me_mountdir, d->name, len) == 0))) ||
(exact && strcmp(me->me_mountdir, d->name) == 0)) {
if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
best_match = me;
best_match_len = len;
}
}
}
}
if (best_match) {
d->best_match = best_match;
} else {
d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
}
}
}
}
/* Returns true if name is in list */
bool np_find_name(struct name_list *list, const char *name) {
const struct name_list *n;
if (list == NULL || name == NULL) {
return false;
}
for (n = list; n; n = n->next) {
if (!strcmp(name, n->name)) {
return true;
}
}
return false;
}
/* Returns true if name is in list */
bool np_find_regmatch(struct regex_list *list, const char *name) {
int len;
regmatch_t m;
if (name == NULL) {
return false;
}
len = strlen(name);
for (; list; list = list->next) {
/* Emulate a full match as if surrounded with ^( )$
by checking whether the match spans the whole name */
if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) {
return true;
}
}
return false;
}
bool np_seen_name(struct name_list *list, const char *name) {
const struct name_list *s;
for (s = list; s; s = s->next) {
if (!strcmp(s->name, name)) {
return true;
}
}
return false;
}
bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
if (regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0 || regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0) {
return true;
}
return false;
}

View file

@ -1,48 +0,0 @@
/* Header file for utils_disk */
#include "mountlist.h"
#include "utils_base.h"
#include "regex.h"
struct name_list {
char *name;
struct name_list *next;
};
struct regex_list {
regex_t regex;
struct regex_list *next;
};
struct parameter_list {
char *name;
thresholds *freespace_bytes;
thresholds *freespace_units;
thresholds *freespace_percent;
thresholds *usedspace_bytes;
thresholds *usedspace_units;
thresholds *usedspace_percent;
thresholds *usedinodes_percent;
thresholds *freeinodes_percent;
char *group;
struct mount_entry *best_match;
struct parameter_list *name_next;
struct parameter_list *name_prev;
uintmax_t total, available, available_to_root, used, inodes_free, inodes_free_to_root, inodes_used, inodes_total;
double dfree_pct, dused_pct;
uint64_t dused_units, dfree_units, dtotal_units;
double dused_inodes_percent, dfree_inodes_percent;
};
void np_add_name(struct name_list **list, const char *name);
bool np_find_name(struct name_list *list, const char *name);
bool np_seen_name(struct name_list *list, const char *name);
int np_add_regex(struct regex_list **list, const char *regex, int cflags);
bool np_find_regmatch(struct regex_list *list, const char *name);
struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name);
struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name);
struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev);
int search_parameter_list(struct parameter_list *list, const char *name);
void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact);
bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re);

View file

@ -11,6 +11,7 @@
* server.
*/
enum np_match_result {
NP_MATCH_NONE,
NP_MATCH_FAILURE,
NP_MATCH_SUCCESS,
NP_MATCH_RETRY

View file

@ -24,7 +24,9 @@ noinst_PROGRAMS = check_dhcp check_icmp @EXTRAS_ROOT@
EXTRA_PROGRAMS = pst3
EXTRA_DIST = t pst3.c
EXTRA_DIST = t pst3.c \
check_icmp.d \
check_dhcp.d
BASEOBJS = ../plugins/utils.o ../lib/libmonitoringplug.a ../gl/libgnu.a
NETOBJS = ../plugins/netutils.o $(BASEOBJS) $(EXTRA_NETOBJS)
@ -82,6 +84,7 @@ install-exec-local: $(noinst_PROGRAMS)
# the actual targets
check_dhcp_LDADD = @LTLIBINTL@ $(NETLIBS) $(LIB_CRYPTO)
check_icmp_LDADD = @LTLIBINTL@ $(NETLIBS) $(SOCKETLIBS) $(LIB_CRYPTO)
check_icmp_SOURCES = check_icmp.c check_icmp.d/check_icmp_helpers.c
# -m64 needed at compiler and linker phase
pst3_CFLAGS = @PST3CFLAGS@
@ -89,7 +92,7 @@ pst3_LDFLAGS = @PST3CFLAGS@
# pst3 must not use monitoringplug/gnulib includes!
pst3_CPPFLAGS =
check_dhcp_DEPENDENCIES = check_dhcp.c $(NETOBJS) $(DEPLIBS)
check_dhcp_DEPENDENCIES = check_dhcp.c $(NETOBJS) $(DEPLIBS)
check_icmp_DEPENDENCIES = check_icmp.c $(NETOBJS)
clean-local:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
#pragma once
#include "../../config.h"
#include "../lib/states.h"
#include <stdbool.h>
#include <netinet/in.h>
#include "net/if.h"
#include "output.h"
typedef struct requested_server_struct {
struct in_addr server_address;
bool answered;
struct requested_server_struct *next;
} requested_server;
typedef struct check_dhcp_config {
bool unicast_mode; /* unicast mode: mimic a DHCP relay */
bool exclusive_mode; /* exclusive mode aka "rogue DHCP server detection" */
int num_of_requested_servers;
struct in_addr dhcp_ip; /* server to query (if in unicast mode) */
struct in_addr requested_address;
bool request_specific_address;
int dhcpoffer_timeout;
unsigned char *user_specified_mac;
char network_interface_name[IFNAMSIZ];
requested_server *requested_server_list;
mp_output_format output_format;
bool output_format_is_set;
} check_dhcp_config;
check_dhcp_config check_dhcp_config_init(void) {
check_dhcp_config tmp = {
.unicast_mode = false,
.exclusive_mode = false,
.num_of_requested_servers = 0,
.dhcp_ip = {0},
.requested_address = {0},
.request_specific_address = false,
.dhcpoffer_timeout = 2,
.user_specified_mac = NULL,
.network_interface_name = "eth0",
.requested_server_list = NULL,
.output_format_is_set = false,
};
return tmp;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
#include "./config.h"
#include <math.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "./check_icmp_helpers.h"
#include "../../plugins/netutils.h"
// timeout as a global variable to make it available to the timeout handler
unsigned int timeout = DEFAULT_TIMEOUT;
check_icmp_config check_icmp_config_init() {
check_icmp_config tmp = {
.modes =
{
.order_mode = false,
.mos_mode = false,
.rta_mode = false,
.pl_mode = false,
.jitter_mode = false,
.score_mode = false,
},
.min_hosts_alive = -1,
.crit = {.pl = DEFAULT_CRIT_PL,
.rta = DEFAULT_CRIT_RTA,
.jitter = 50.0,
.mos = 3.0,
.score = 70.0},
.warn = {.pl = DEFAULT_WARN_PL,
.rta = DEFAULT_WARN_RTA,
.jitter = 40.0,
.mos = 3.5,
.score = 80.0},
.ttl = DEFAULT_TTL,
.icmp_data_size = DEFAULT_PING_DATA_SIZE,
.target_interval = 0,
.number_of_packets = DEFAULT_NUMBER_OF_PACKETS,
.source_ip = NULL,
.need_v4 = false,
.need_v6 = false,
.sender_id = 0,
.mode = MODE_RTA,
.number_of_targets = 0,
.targets = NULL,
.number_of_hosts = 0,
.hosts = NULL,
.output_format_is_set = false,
};
return tmp;
}
ping_target ping_target_init() {
ping_target tmp = {
.rtmin = INFINITY,
.jitter_min = INFINITY,
.found_out_of_order_packets = false,
};
return tmp;
}
check_icmp_state check_icmp_state_init() {
check_icmp_state tmp = {.icmp_sent = 0, .icmp_lost = 0, .icmp_recv = 0, .targets_down = 0};
return tmp;
}
ping_target_create_wrapper ping_target_create(struct sockaddr_storage address) {
ping_target_create_wrapper result = {
.errorcode = OK,
};
struct sockaddr_storage *tmp_addr = &address;
/* disregard obviously stupid addresses
* (I didn't find an ipv6 equivalent to INADDR_NONE) */
if (((tmp_addr->ss_family == AF_INET &&
(((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_NONE ||
((struct sockaddr_in *)tmp_addr)->sin_addr.s_addr == INADDR_ANY))) ||
(tmp_addr->ss_family == AF_INET6 &&
(((struct sockaddr_in6 *)tmp_addr)->sin6_addr.s6_addr == in6addr_any.s6_addr))) {
result.errorcode = ERROR;
return result;
}
/* add the fresh ip */
ping_target target = ping_target_init();
/* fill out the sockaddr_storage struct */
target.address = address;
result.host = target;
return result;
}
check_icmp_target_container check_icmp_target_container_init() {
check_icmp_target_container tmp = {
.name = NULL,
.number_of_targets = 0,
.target_list = NULL,
};
return tmp;
}
unsigned int ping_target_list_append(ping_target *list, ping_target *elem) {
if (elem == NULL || list == NULL) {
return 0;
}
while (list->next != NULL) {
list = list->next;
}
list->next = elem;
unsigned int result = 1;
while (elem->next != NULL) {
result++;
elem = elem->next;
}
return result;
}

View file

@ -0,0 +1,68 @@
#pragma once
#include "../../lib/states.h"
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
typedef struct ping_target {
unsigned short id; /* id in **table, and icmp pkts */
char *msg; /* icmp error message, if any */
struct sockaddr_storage address; /* the address of this host */
struct sockaddr_storage error_addr; /* stores address of error replies */
time_t time_waited; /* total time waited, in usecs */
unsigned int icmp_sent, icmp_recv, icmp_lost; /* counters */
unsigned char icmp_type, icmp_code; /* type and code from errors */
unsigned short flags; /* control/status flags */
double rtmax; /* max rtt */
double rtmin; /* min rtt */
double jitter; /* measured jitter */
double jitter_max; /* jitter rtt maximum */
double jitter_min; /* jitter rtt minimum */
time_t last_tdiff;
unsigned int last_icmp_seq; /* Last ICMP_SEQ to check out of order pkts */
bool found_out_of_order_packets;
struct ping_target *next;
} ping_target;
ping_target ping_target_init();
typedef struct {
char *name;
ping_target *target_list;
unsigned int number_of_targets;
} check_icmp_target_container;
check_icmp_target_container check_icmp_target_container_init();
typedef struct {
unsigned int icmp_sent;
unsigned int icmp_recv;
unsigned int icmp_lost;
unsigned short targets_down;
} check_icmp_state;
check_icmp_state check_icmp_state_init();
typedef struct {
int errorcode;
ping_target host;
} ping_target_create_wrapper;
typedef struct {
int socket4;
int socket6;
} check_icmp_socket_set;
ping_target_create_wrapper ping_target_create(struct sockaddr_storage address);
unsigned int ping_target_list_append(ping_target *list, ping_target *elem);

View file

@ -0,0 +1,115 @@
#pragma once
#include "../../config.h"
#include "../../lib/states.h"
#include <stddef.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <arpa/inet.h>
#include <stdint.h>
#include "./check_icmp_helpers.h"
#include "output.h"
/* threshold structure. all values are maximum allowed, exclusive */
typedef struct {
unsigned char pl; /* max allowed packet loss in percent */
time_t rta; /* roundtrip time average, microseconds */
double jitter; /* jitter time average, microseconds */
double mos; /* MOS */
double score; /* Score */
} check_icmp_threshold;
/* the different modes of this program are as follows:
* MODE_RTA: send all packets no matter what (mimic check_icmp and check_ping)
* MODE_HOSTCHECK: Return immediately upon any sign of life
* In addition, sends packets to ALL addresses assigned
* to this host (as returned by gethostbyname() or
* gethostbyaddr() and expects one host only to be checked at
* a time. Therefore, any packet response what so ever will
* count as a sign of life, even when received outside
* crit.rta limit. Do not misspell any additional IP's.
* MODE_ALL: Requires packets from ALL requested IP to return OK (default).
* MODE_ICMP: Default Mode
*/
typedef enum {
MODE_RTA,
MODE_HOSTCHECK,
MODE_ALL,
MODE_ICMP,
} check_icmp_execution_mode;
typedef struct {
bool order_mode;
bool mos_mode;
bool rta_mode;
bool pl_mode;
bool jitter_mode;
bool score_mode;
} check_icmp_mode_switches;
typedef struct {
check_icmp_mode_switches modes;
int min_hosts_alive;
check_icmp_threshold crit;
check_icmp_threshold warn;
unsigned long ttl;
unsigned short icmp_data_size;
time_t target_interval;
unsigned short number_of_packets;
char *source_ip;
bool need_v4;
bool need_v6;
uint16_t sender_id; // PID of the main process, which is used as an ID in packets
check_icmp_execution_mode mode;
unsigned short number_of_targets;
ping_target *targets;
unsigned short number_of_hosts;
check_icmp_target_container *hosts;
mp_output_format output_format;
bool output_format_is_set;
} check_icmp_config;
check_icmp_config check_icmp_config_init();
/* the data structure */
typedef struct icmp_ping_data {
struct timeval stime; /* timestamp (saved in protocol struct as well) */
unsigned short ping_id;
} icmp_ping_data;
#define MAX_IP_PKT_SIZE 65536 /* (theoretical) max IP packet size */
#define IP_HDR_SIZE 20
#define MAX_PING_DATA (MAX_IP_PKT_SIZE - IP_HDR_SIZE - ICMP_MINLEN)
#define MIN_PING_DATA_SIZE sizeof(struct icmp_ping_data)
#define DEFAULT_PING_DATA_SIZE (MIN_PING_DATA_SIZE + 44)
/* 80 msec packet interval by default */
// DEPRECATED, remove when removing the option
#define DEFAULT_PKT_INTERVAL 80000
#define DEFAULT_TARGET_INTERVAL 0
#define DEFAULT_WARN_RTA 200000
#define DEFAULT_CRIT_RTA 500000
#define DEFAULT_WARN_PL 40
#define DEFAULT_CRIT_PL 80
#define DEFAULT_TIMEOUT 10
#define DEFAULT_TTL 64
#define DEFAULT_NUMBER_OF_PACKETS 5
#define PACKET_BACKOFF_FACTOR 1.5
#define TARGET_BACKOFF_FACTOR 1.5

View file

@ -12,14 +12,14 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
"no" );
if ($allow_sudo eq "yes" or $> == 0) {
plan tests => 6;
plan tests => 7;
} else {
plan skip_all => "Need sudo to test check_dhcp";
}
my $sudo = $> == 0 ? '' : 'sudo';
my $successOutput = '/OK: Received \d+ DHCPOFFER\(s\), \d+ of 1 requested servers responded, max lease time = \d+ sec\./';
my $failureOutput = '/CRITICAL: (No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/';
my $successOutput = '/Received \d+ DHCPOFFER(s)*, max lease time = \d+ seconds/';
my $failureOutput = '/(No DHCPOFFERs were received|Received \d+ DHCPOFFER\(s\), 0 of 1 requested servers responded, max lease time = \d+ sec\.)/';
my $invalidOutput = '/Invalid hostname/';
my $host_responsive = getTestParameter( "NP_HOST_DHCP_RESPONSIVE",
@ -34,6 +34,8 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
"An invalid (not known to DNS) hostname",
"nosuchhost" );
my $output_format = "--output-format mp-test-json";
# try to determince interface
my $interface = '';
@ -49,19 +51,21 @@ my $res;
SKIP: {
skip('need responsive test host', 2) unless $host_responsive;
$res = NPTest->testCmd(
"$sudo ./check_dhcp $interface -u -s $host_responsive"
"$sudo ./check_dhcp $interface -u -s $host_responsive $output_format"
);
is( $res->return_code, 0, "Syntax ok" );
like( $res->output, $successOutput, "Output OK" );
is( $res->return_code, 0, "with JSON test format result should always be OK" );
like( $res->{'mp_test_result'}->{'state'}, "/OK/", "Output OK" );
like( $res->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $successOutput, "Output OK" );
};
SKIP: {
skip('need nonresponsive test host', 2) unless $host_nonresponsive;
$res = NPTest->testCmd(
"$sudo ./check_dhcp $interface -u -s $host_nonresponsive"
"$sudo ./check_dhcp $interface -u -s $host_nonresponsive $output_format"
);
is( $res->return_code, 2, "Exit code - host nonresponsive" );
like( $res->output, $failureOutput, "Output OK" );
is( $res->return_code, 0, "with JSON test format result should always be OK" );
like( $res->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Exit code - host nonresponsive" );
like( $res->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $failureOutput, "Output OK" );
};
SKIP: {
@ -69,6 +73,6 @@ SKIP: {
$res = NPTest->testCmd(
"$sudo ./check_dhcp $interface -u -s $hostname_invalid"
);
is( $res->return_code, 3, "Exit code - host invalid" );
is( $res->return_code, 3, "invalid hostname/address should return UNKNOWN" );
like( $res->output, $invalidOutput, "Output OK" );
};

View file

@ -12,15 +12,12 @@ my $allow_sudo = getTestParameter( "NP_ALLOW_SUDO",
"no" );
if ($allow_sudo eq "yes" or $> == 0) {
plan tests => 40;
plan tests => 17;
} else {
plan skip_all => "Need sudo to test check_icmp";
}
my $sudo = $> == 0 ? '' : 'sudo';
my $successOutput = '/OK - .*? rta (?:[\d\.]+ms)|(?:nan), lost \d+%/';
my $failureOutput = '/(WARNING|CRITICAL) - .*? rta (?:[\d\.]+ms > [\d\.]+ms|nan)/';
my $host_responsive = getTestParameter( "NP_HOST_RESPONSIVE",
"The hostname of system responsive to network requests",
"localhost" );
@ -36,108 +33,85 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
my $res;
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -w 10000ms,100% -c 10000ms,100%"
"$sudo ./check_icmp -H $host_responsive -w 100ms,100% -c 100ms,100%"
);
is( $res->return_code, 0, "Syntax ok" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 10000ms,100%"
"$sudo ./check_icmp -H $host_responsive -w 0ms,0% -c 100ms,100%"
);
is( $res->return_code, 1, "Syntax ok, with forced warning" );
like( $res->output, $failureOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -w 0,0% -c 0,0%"
);
is( $res->return_code, 2, "Syntax ok, with forced critical" );
like( $res->output, $failureOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -t 2"
"$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100%"
);
is( $res->return_code, 2, "Timeout - host nonresponsive" );
like( $res->output, '/pl=100%/', "Error contains 'pl=100%' string (for 100% packet loss)" );
like( $res->output, '/rta=U/', "Error contains 'rta=U' string" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -w 10000ms,100% -c 10000ms,100%"
"$sudo ./check_icmp -w 100ms,100% -c 100ms,100%"
);
is( $res->return_code, 3, "No hostname" );
like( $res->output, '/No hosts to check/', "Output with appropriate error message");
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 0 -t 2"
"$sudo ./check_icmp -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 0"
);
is( $res->return_code, 0, "One host nonresponsive - zero required" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 1 -t 2"
"$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 1"
);
is( $res->return_code, 0, "One of two host nonresponsive - one required" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 10000ms,100% -c 10000ms,100% -n 1 -m 2"
"$sudo ./check_icmp -H $host_responsive -H $host_nonresponsive -w 100ms,100% -c 100ms,100% -n 1 -m 2"
);
is( $res->return_code, 2, "One of two host nonresponsive - two required" );
like( $res->output, $failureOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 10000ms,100% -c 10000ms,100% -n 1 -m 2"
"$sudo ./check_icmp -H $host_responsive -s 127.0.15.15 -w 100ms,100% -c 100ms,100% -n 1"
);
is( $res->return_code, 0, "IPv4 source_ip accepted" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -b 65507"
);
is( $res->return_code, 0, "Try max packet size" );
like( $res->output, $successOutput, "Output OK - Didn't overflow" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1 -t 2"
"$sudo ./check_icmp -H $host_responsive -R 100,100 -n 1"
);
is( $res->return_code, 0, "rta works" );
like( $res->output, $successOutput, "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1 -t 2"
"$sudo ./check_icmp -H $host_responsive -P 80,90 -n 1"
);
is( $res->return_code, 0, "pl works" );
like( $res->output, '/lost 0%/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -J 80,90 -t 2"
"$sudo ./check_icmp -H $host_responsive -J 80,90"
);
is( $res->return_code, 0, "jitter works" );
like( $res->output, '/jitter \d/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -M 4,3 -t 2"
"$sudo ./check_icmp -H $host_responsive -M 4,3"
);
is( $res->return_code, 0, "mos works" );
like( $res->output, '/MOS \d/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -S 80,70 -t 2"
"$sudo ./check_icmp -H $host_responsive -S 80,70"
);
is( $res->return_code, 0, "score works" );
like( $res->output, '/Score \d/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -O -t 2"
"$sudo ./check_icmp -H $host_responsive -O"
);
is( $res->return_code, 0, "order works" );
like( $res->output, '/Packets in order/', "Output OK" );
$res = NPTest->testCmd(
"$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100 -t 2"
"$sudo ./check_icmp -H $host_responsive -O -S 80,70 -M 4,3 -J 80,90 -P 80,90 -R 100,100"
);
is( $res->return_code, 0, "order works" );
like( $res->output, '/Packets in order/', "Output OK" );
like( $res->output, '/Score \d/', "Output OK" );
like( $res->output, '/MOS \d/', "Output OK" );
like( $res->output, '/jitter \d/', "Output OK" );
like( $res->output, '/lost 0%/', "Output OK" );
like( $res->output, $successOutput, "Output OK" );

View file

@ -27,7 +27,7 @@ MATHLIBS = @MATHLIBS@
#AM_CFLAGS = -Wall
libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \
check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_nwstat check_overcr check_ping \
check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_ping \
check_real check_smtp check_ssh check_tcp check_time check_ntp_time \
check_ups check_users negate \
urlize @EXTRAS@
@ -40,26 +40,51 @@ EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
check_nagios check_by_ssh check_dns check_nt check_ide_smart \
check_procs check_mysql_query check_apt check_dbi check_curl \
\
tests/test_check_swap
tests/test_check_swap \
tests/test_check_disk
SUBDIRS = picohttpparser
np_test_scripts = tests/test_check_swap.t
np_test_scripts = tests/test_check_swap.t \
tests/test_check_disk.t
EXTRA_DIST = t \
tests \
$(np_test_scripts) \
negate.d \
check_swap.d \
check_ldap.d \
check_hpjd.d \
check_game.d \
check_radius.d \
check_disk.d \
check_time.d \
check_load.d \
check_nagios.d \
check_dbi.d \
check_tcp.d \
check_real.d \
check_ssh.d \
check_nt.d \
check_dns.d \
check_mrtgtraf.d \
check_mysql_query.d \
check_mrtg.d \
check_ntp_peer.d \
check_apt.d \
check_pgsql.d \
check_procs.d \
check_ping.d \
check_by_ssh.d \
check_smtp.d \
check_mysql.d \
check_ntp_time.d \
check_dig.d \
check_cluster.d \
check_curl.d
check_cluster.d \
check_ups.d \
check_fping.d
PLUGINHDRS = common.h
@ -101,6 +126,7 @@ check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohtt
check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
check_dig_LDADD = $(NETLIBS)
check_disk_LDADD = $(BASEOBJS)
check_disk_SOURCES = check_disk.c check_disk.d/utils_disk.c
check_dns_LDADD = $(NETLIBS)
check_dummy_LDADD = $(BASEOBJS)
check_fping_LDADD = $(NETLIBS)
@ -121,8 +147,6 @@ check_nagios_LDADD = $(BASEOBJS)
check_nt_LDADD = $(NETLIBS)
check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
check_nwstat_LDADD = $(NETLIBS)
check_overcr_LDADD = $(NETLIBS)
check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
check_ping_LDADD = $(NETLIBS)
check_procs_LDADD = $(BASEOBJS)
@ -149,6 +173,8 @@ endif
tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c
tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap
tests_test_check_disk_SOURCES = tests/test_check_disk.c
##############################################################################
# secondary dependencies

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,517 @@
/*****************************************************************************
*
* Library for check_disk
*
* License: GPL
* Copyright (c) 1999-2024 Monitoring Plugins Development Team
*
* Description:
*
* This file contains utilities for check_disk. These are tested by libtap
*
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
#include "../common.h"
#include "utils_disk.h"
#include "../../gl/fsusage.h"
#include "../../lib/thresholds.h"
#include "../../lib/states.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
void np_add_name(struct name_list **list, const char *name) {
struct name_list *new_entry;
new_entry = (struct name_list *)malloc(sizeof *new_entry);
new_entry->name = (char *)name;
new_entry->next = *list;
*list = new_entry;
}
/* @brief Initialises a new regex at the begin of list via regcomp(3)
*
* @details if the regex fails to compile the error code of regcomp(3) is returned
* and list is not modified, otherwise list is modified to point to the new
* element
* @param list Pointer to a linked list of regex_list elements
* @param regex the string containing the regex which should be inserted into the list
* @param clags the cflags parameter for regcomp(3)
*/
int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
if (new_entry == NULL) {
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
}
int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
if (!regcomp_result) {
// regcomp succeeded
new_entry->next = *list;
*list = new_entry;
return 0;
}
// regcomp failed
free(new_entry);
return regcomp_result;
}
parameter_list_elem parameter_list_init(const char *name) {
parameter_list_elem result = {
.name = strdup(name),
.best_match = NULL,
.freespace_units = mp_thresholds_init(),
.freespace_percent = mp_thresholds_init(),
.freeinodes_percent = mp_thresholds_init(),
.group = NULL,
.inodes_total = 0,
.inodes_free = 0,
.inodes_free_to_root = 0,
.inodes_used = 0,
.used_bytes = 0,
.free_bytes = 0,
.total_bytes = 0,
.next = NULL,
.prev = NULL,
};
return result;
}
/* Returns true if name is in list */
bool np_find_name(struct name_list *list, const char *name) {
if (list == NULL || name == NULL) {
return false;
}
for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
if (!strcmp(name, iterator->name)) {
return true;
}
}
return false;
}
/* Returns true if name is in list */
bool np_find_regmatch(struct regex_list *list, const char *name) {
if (name == NULL) {
return false;
}
size_t len = strlen(name);
for (; list; list = list->next) {
/* Emulate a full match as if surrounded with ^( )$
by checking whether the match spans the whole name */
regmatch_t dummy_match;
if (!regexec(&list->regex, name, 1, &dummy_match, 0) && dummy_match.rm_so == 0 && dummy_match.rm_eo == len) {
return true;
}
}
return false;
}
bool np_seen_name(struct name_list *list, const char *name) {
for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
if (!strcmp(iterator->name, name)) {
return true;
}
}
return false;
}
bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) || (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0));
}
check_disk_config check_disk_config_init() {
check_disk_config tmp = {
.erronly = false,
.display_mntp = false,
.show_local_fs = false,
.stat_remote_fs = false,
.display_inodes_perfdata = false,
.exact_match = false,
.freespace_ignore_reserved = false,
.ignore_missing = false,
.path_ignored = false,
// FS Filters
.fs_exclude_list = NULL,
.fs_include_list = NULL,
.device_path_exclude_list = NULL,
// Actual filesystems paths to investigate
.path_select_list = filesystem_list_init(),
.mount_list = NULL,
.seen = NULL,
.display_unit = Humanized,
// .unit = MebiBytes,
.output_format_is_set = false,
};
return tmp;
}
char *get_unit_string(byte_unit_enum unit) {
switch (unit) {
case Bytes:
return "Bytes";
case KibiBytes:
return "KiB";
case MebiBytes:
return "MiB";
case GibiBytes:
return "GiB";
case TebiBytes:
return "TiB";
case PebiBytes:
return "PiB";
case ExbiBytes:
return "EiB";
case KiloBytes:
return "KB";
case MegaBytes:
return "MB";
case GigaBytes:
return "GB";
case TeraBytes:
return "TB";
case PetaBytes:
return "PB";
case ExaBytes:
return "EB";
default:
assert(false);
}
}
measurement_unit measurement_unit_init() {
measurement_unit tmp = {
.name = NULL,
.filesystem_type = NULL,
.is_group = false,
.freeinodes_percent_thresholds = mp_thresholds_init(),
.freespace_percent_thresholds = mp_thresholds_init(),
.freespace_bytes_thresholds = mp_thresholds_init(),
.free_bytes = 0,
.used_bytes = 0,
.total_bytes = 0,
.inodes_total = 0,
.inodes_free = 0,
.inodes_free_to_root = 0,
.inodes_used = 0,
};
return tmp;
}
// Add a given element to the list, memory for the new element is freshly allocated
// Returns a pointer to new element
measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem) {
// find last element
measurement_unit_list *new = NULL;
if (list == NULL) {
new = calloc(1, sizeof(measurement_unit_list));
if (new == NULL) {
die(STATE_UNKNOWN, _("allocation failed"));
}
} else {
measurement_unit_list *list_elem = list;
while (list_elem->next != NULL) {
list_elem = list_elem->next;
}
new = calloc(1, sizeof(measurement_unit_list));
if (new == NULL) {
die(STATE_UNKNOWN, _("allocation failed"));
}
list_elem->next = new;
}
new->unit = elem;
new->next = NULL;
return new;
}
measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem) {
unit.free_bytes += filesystem.free_bytes;
unit.used_bytes += filesystem.used_bytes;
unit.total_bytes += filesystem.total_bytes;
unit.inodes_total += filesystem.inodes_total;
unit.inodes_free += filesystem.inodes_free;
unit.inodes_free_to_root += filesystem.inodes_free_to_root;
unit.inodes_used += filesystem.inodes_used;
return unit;
}
measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp) {
measurement_unit result = measurement_unit_init();
if (!display_mntp) {
result.name = strdup(filesystem.best_match->me_mountdir);
} else {
result.name = strdup(filesystem.best_match->me_devname);
}
if (filesystem.group) {
result.is_group = true;
} else {
result.is_group = false;
if (filesystem.best_match) {
result.filesystem_type = filesystem.best_match->me_type;
}
}
result.freeinodes_percent_thresholds = filesystem.freeinodes_percent;
result.freespace_percent_thresholds = filesystem.freespace_percent;
result.freespace_bytes_thresholds = filesystem.freespace_units;
result.free_bytes = filesystem.free_bytes;
result.total_bytes = filesystem.total_bytes;
result.used_bytes = filesystem.used_bytes;
result.inodes_total = filesystem.inodes_total;
result.inodes_used = filesystem.inodes_used;
result.inodes_free = filesystem.inodes_free;
result.inodes_free_to_root = filesystem.inodes_free_to_root;
return result;
}
#define RANDOM_STRING_LENGTH 64
char *humanize_byte_value(unsigned long long value, bool use_si_units) {
// Idea: A reasonable output should have at most 3 orders of magnitude
// before the decimal separator
// 353GiB is ok, 2444 GiB should be 2.386 TiB
char *result = calloc(RANDOM_STRING_LENGTH, sizeof(char));
if (result == NULL) {
die(STATE_UNKNOWN, _("allocation failed"));
}
const byte_unit KibiBytes_factor = 1024;
const byte_unit MebiBytes_factor = 1048576;
const byte_unit GibiBytes_factor = 1073741824;
const byte_unit TebiBytes_factor = 1099511627776;
const byte_unit PebiBytes_factor = 1125899906842624;
const byte_unit ExbiBytes_factor = 1152921504606846976;
const byte_unit KiloBytes_factor = 1000;
const byte_unit MegaBytes_factor = 1000000;
const byte_unit GigaBytes_factor = 1000000000;
const byte_unit TeraBytes_factor = 1000000000000;
const byte_unit PetaBytes_factor = 1000000000000000;
const byte_unit ExaBytes_factor = 1000000000000000000;
if (use_si_units) {
// SI units, powers of 10
if (value < KiloBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
} else if (value < MegaBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu KB", value / KiloBytes_factor);
} else if (value < GigaBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu MB", value / MegaBytes_factor);
} else if (value < TeraBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu GB", value / GigaBytes_factor);
} else if (value < PetaBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu TB", value / TeraBytes_factor);
} else if (value < ExaBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu PB", value / PetaBytes_factor);
} else {
snprintf(result, RANDOM_STRING_LENGTH, "%llu EB", value / ExaBytes_factor);
}
} else {
// IEC units, powers of 2 ^ 10
if (value < KibiBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
} else if (value < MebiBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu KiB", value / KibiBytes_factor);
} else if (value < GibiBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu MiB", value / MebiBytes_factor);
} else if (value < TebiBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu GiB", value / GibiBytes_factor);
} else if (value < PebiBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu TiB", value / TebiBytes_factor);
} else if (value < ExbiBytes_factor) {
snprintf(result, RANDOM_STRING_LENGTH, "%llu PiB", value / PebiBytes_factor);
} else {
snprintf(result, RANDOM_STRING_LENGTH, "%llu EiB", value / ExbiBytes_factor);
}
}
return result;
}
filesystem_list filesystem_list_init() {
filesystem_list tmp = {
.length = 0,
.first = NULL,
};
return tmp;
}
parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name) {
parameter_list_elem *current = list->first;
parameter_list_elem *new_path = (struct parameter_list *)malloc(sizeof *new_path);
*new_path = parameter_list_init(name);
if (current == NULL) {
list->first = new_path;
new_path->prev = NULL;
list->length = 1;
} else {
while (current->next) {
current = current->next;
}
current->next = new_path;
new_path->prev = current;
list->length++;
}
return new_path;
}
parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name) {
if (list.length == 0) {
return NULL;
}
for (parameter_list_elem *temp_list = list.first; temp_list; temp_list = temp_list->next) {
if (!strcmp(temp_list->name, name)) {
return temp_list;
}
}
return NULL;
}
parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item) {
if (list->length == 0) {
return NULL;
}
if (item == NULL) {
// Got NULL for item, interpret this as "delete first element"
// as a kind of compatibility to the old function
item = list->first;
}
if (list->first == item) {
list->length--;
list->first = item->next;
if (list->first) {
list->first->prev = NULL;
}
return list->first;
}
// Was not the first element, continue
parameter_list_elem *prev = list->first;
parameter_list_elem *current = list->first->next;
while (current != item && current != NULL) {
prev = current;
current = current->next;
}
if (current == NULL) {
// didn't find that element ....
return NULL;
}
// remove the element
parameter_list_elem *next = current->next;
prev->next = next;
list->length--;
if (next) {
next->prev = prev;
}
if (item->name) {
free(item->name);
}
free(item);
return next;
}
parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current) {
if (!current) {
return NULL;
}
return current->next;
}
void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact) {
for (parameter_list_elem *elem = list.first; elem; elem = mp_int_fs_list_get_next(elem)) {
if (!elem->best_match) {
size_t name_len = strlen(elem->name);
struct mount_entry *best_match = NULL;
/* set best match if path name exactly matches a mounted device name */
for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
if (strcmp(mount_entry->me_devname, elem->name) == 0) {
struct fs_usage fsp;
if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
best_match = mount_entry;
}
}
}
/* set best match by directory name if no match was found by devname */
if (!best_match) {
size_t best_match_len = 0;
for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
size_t len = strlen(mount_entry->me_mountdir);
if ((!exact && (best_match_len <= len && len <= name_len &&
(len == 1 || strncmp(mount_entry->me_mountdir, elem->name, len) == 0))) ||
(exact && strcmp(mount_entry->me_mountdir, elem->name) == 0)) {
struct fs_usage fsp;
if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
best_match = mount_entry;
best_match_len = len;
}
}
}
}
if (best_match) {
elem->best_match = best_match;
} else {
elem->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
}
// No filesystem without a mount_entry!
// assert(elem->best_match != NULL);
}
}
}

View file

@ -0,0 +1,157 @@
#pragma once
/* Header file for utils_disk */
#include "../../config.h"
#include "../../gl/mountlist.h"
#include "../../lib/utils_base.h"
#include "../../lib/output.h"
#include "regex.h"
#include <stdint.h>
typedef unsigned long long byte_unit;
typedef enum {
Humanized,
Bytes,
KibiBytes,
MebiBytes,
GibiBytes,
TebiBytes,
PebiBytes,
ExbiBytes,
KiloBytes,
MegaBytes,
GigaBytes,
TeraBytes,
PetaBytes,
ExaBytes,
} byte_unit_enum;
typedef struct name_list string_list;
struct name_list {
char *name;
string_list *next;
};
struct regex_list {
regex_t regex;
struct regex_list *next;
};
typedef struct parameter_list parameter_list_elem;
struct parameter_list {
char *name;
char *group;
mp_thresholds freespace_units;
mp_thresholds freespace_percent;
mp_thresholds freeinodes_percent;
struct mount_entry *best_match;
uintmax_t inodes_free_to_root;
uintmax_t inodes_free;
uintmax_t inodes_used;
uintmax_t inodes_total;
uint64_t used_bytes;
uint64_t free_bytes;
uint64_t total_bytes;
parameter_list_elem *next;
parameter_list_elem *prev;
};
typedef struct {
size_t length;
parameter_list_elem *first;
} filesystem_list;
filesystem_list filesystem_list_init();
typedef struct {
char *name;
char *filesystem_type;
bool is_group;
mp_thresholds freespace_bytes_thresholds;
mp_thresholds freespace_percent_thresholds;
mp_thresholds freeinodes_percent_thresholds;
uintmax_t inodes_free_to_root;
uintmax_t inodes_free;
uintmax_t inodes_used;
uintmax_t inodes_total;
uintmax_t used_bytes;
uintmax_t free_bytes;
uintmax_t total_bytes;
} measurement_unit;
typedef struct measurement_unit_list measurement_unit_list;
struct measurement_unit_list {
measurement_unit unit;
measurement_unit_list *next;
};
typedef struct {
// Output options
bool erronly;
bool display_mntp;
/* show only local filesystems. */
bool show_local_fs;
/* show only local filesystems but call stat() on remote ones. */
bool stat_remote_fs;
bool display_inodes_perfdata;
bool exact_match;
bool freespace_ignore_reserved;
bool ignore_missing;
bool path_ignored;
/* Linked list of filesystem types to omit.
If the list is empty, don't exclude any types. */
struct regex_list *fs_exclude_list;
/* Linked list of filesystem types to check.
If the list is empty, include all types. */
struct regex_list *fs_include_list;
struct name_list *device_path_exclude_list;
filesystem_list path_select_list;
/* Linked list of mounted filesystems. */
struct mount_entry *mount_list;
struct name_list *seen;
byte_unit_enum display_unit;
// byte_unit unit;
bool output_format_is_set;
mp_output_format output_format;
} check_disk_config;
void np_add_name(struct name_list **list, const char *name);
bool np_find_name(struct name_list *list, const char *name);
bool np_seen_name(struct name_list *list, const char *name);
int np_add_regex(struct regex_list **list, const char *regex, int cflags);
bool np_find_regmatch(struct regex_list *list, const char *name);
parameter_list_elem parameter_list_init(const char *);
parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name);
parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name);
parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item);
parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current);
void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact);
measurement_unit measurement_unit_init();
measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem);
measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem);
measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp);
int search_parameter_list(parameter_list_elem *list, const char *name);
bool np_regex_match_mount_entry(struct mount_entry *, regex_t *);
char *get_unit_string(byte_unit_enum);
check_disk_config check_disk_config_init();
char *humanize_byte_value(unsigned long long value, bool use_si_units);

View file

@ -38,52 +38,29 @@ const char *email = "devel@monitoring-plugins.org";
#include "netutils.h"
#include "utils.h"
#include <stdbool.h>
#include "check_fping.d/config.h"
#include "states.h"
enum {
PACKET_COUNT = 1,
PACKET_SIZE = 56,
PL = 0,
RTA = 1
};
static int textscan(char *buf);
static int process_arguments(int /*argc*/, char ** /*argv*/);
static mp_state_enum textscan(char *buf, const char * /*server_name*/, bool /*crta_p*/, double /*crta*/, bool /*wrta_p*/, double /*wrta*/,
bool /*cpl_p*/, int /*cpl*/, bool /*wpl_p*/, int /*wpl*/, bool /*alive_p*/);
typedef struct {
int errorcode;
check_fping_config config;
} check_fping_config_wrapper;
static check_fping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static int get_threshold(char *arg, char *rv[2]);
static void print_help(void);
void print_usage(void);
static char *server_name = NULL;
static char *sourceip = NULL;
static char *sourceif = NULL;
static int packet_size = PACKET_SIZE;
static int packet_count = PACKET_COUNT;
static int target_timeout = 0;
static int packet_interval = 0;
static bool verbose = false;
static bool dontfrag = false;
static bool randomize_packet_data = false;
static int cpl;
static int wpl;
static double crta;
static double wrta;
static bool cpl_p = false;
static bool wpl_p = false;
static bool alive_p = false;
static bool crta_p = false;
static bool wrta_p = false;
int main(int argc, char **argv) {
/* normally should be int result = STATE_UNKNOWN; */
int status = STATE_UNKNOWN;
int result = 0;
char *fping_prog = NULL;
char *server = NULL;
char *command_line = NULL;
char *input_buffer = NULL;
char *option_string = "";
input_buffer = malloc(MAX_INPUT_BUFFER);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -91,39 +68,79 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_fping_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
server = strscpy(server, server_name);
const check_fping_config config = tmp_config.config;
char *server = NULL;
server = strscpy(server, config.server_name);
char *option_string = "";
char *fping_prog = NULL;
/* First determine if the target is dualstack or ipv6 only. */
bool server_is_inet6_addr = is_inet6_addr(server);
/*
* If the user requested -6 OR the user made no assertion and the address is v6 or dualstack
* -> we use ipv6
* If the user requested -4 OR the user made no assertion and the address is v4 ONLY
* -> we use ipv4
*/
if (address_family == AF_INET6 || (address_family == AF_UNSPEC && server_is_inet6_addr)) {
xasprintf(&option_string, "%s-6 ", option_string);
} else {
xasprintf(&option_string, "%s-4 ", option_string);
}
fping_prog = strdup(PATH_TO_FPING);
/* compose the command */
if (target_timeout)
xasprintf(&option_string, "%s-t %d ", option_string, target_timeout);
if (packet_interval)
xasprintf(&option_string, "%s-p %d ", option_string, packet_interval);
if (sourceip)
xasprintf(&option_string, "%s-S %s ", option_string, sourceip);
if (sourceif)
xasprintf(&option_string, "%s-I %s ", option_string, sourceif);
if (dontfrag)
if (config.target_timeout) {
xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout);
}
if (config.packet_interval) {
xasprintf(&option_string, "%s-p %d ", option_string, config.packet_interval);
}
if (config.sourceip) {
xasprintf(&option_string, "%s-S %s ", option_string, config.sourceip);
}
if (config.sourceif) {
xasprintf(&option_string, "%s-I %s ", option_string, config.sourceif);
}
if (config.dontfrag) {
xasprintf(&option_string, "%s-M ", option_string);
if (randomize_packet_data)
}
if (config.randomize_packet_data) {
xasprintf(&option_string, "%s-R ", option_string);
}
if (config.fwmark_set) {
xasprintf(&option_string, "%s--fwmark %u ", option_string, config.fwmark);
}
#ifdef PATH_TO_FPING6
if (address_family != AF_INET && is_inet6_addr(server))
fping_prog = strdup(PATH_TO_FPING6);
else
fping_prog = strdup(PATH_TO_FPING);
#else
fping_prog = strdup(PATH_TO_FPING);
#endif
if (config.icmp_timestamp) {
xasprintf(&option_string, "%s--icmp-timestamp ", option_string);
}
xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, packet_size, packet_count, server);
if (config.check_source) {
xasprintf(&option_string, "%s--check-source ", option_string);
}
if (verbose)
char *command_line = NULL;
if (config.icmp_timestamp) {
// no packet size settable for ICMP timestamp
xasprintf(&command_line, "%s %s -c %d %s", fping_prog, option_string, config.packet_count, server);
} else {
xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server);
}
if (verbose) {
printf("%s\n", command_line);
}
/* run the command */
child_process = spopen(command_line);
@ -137,23 +154,29 @@ int main(int argc, char **argv) {
printf(_("Could not open stderr for %s\n"), command_line);
}
char *input_buffer = malloc(MAX_INPUT_BUFFER);
mp_state_enum status = STATE_UNKNOWN;
while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
if (verbose)
if (verbose) {
printf("%s", input_buffer);
status = max_state(status, textscan(input_buffer));
}
status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
}
/* If we get anything on STDERR, at least set warning */
while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
status = max_state(status, STATE_WARNING);
if (verbose)
if (verbose) {
printf("%s", input_buffer);
status = max_state(status, textscan(input_buffer));
}
status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
}
(void)fclose(child_stderr);
/* close the pipe */
result = spclose(child_process);
int result = spclose(child_process);
if (result) {
/* need to use max_state not max */
status = max_state(status, STATE_WARNING);
@ -172,21 +195,17 @@ int main(int argc, char **argv) {
}
}
printf("FPING %s - %s\n", state_text(status), server_name);
printf("FPING %s - %s\n", state_text(status), config.server_name);
return status;
}
int textscan(char *buf) {
char *rtastr = NULL;
char *losstr = NULL;
char *xmtstr = NULL;
double loss;
double rta;
double xmt;
int status = STATE_UNKNOWN;
mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double crta, bool wrta_p, double wrta, bool cpl_p, int cpl,
bool wpl_p, int wpl, bool alive_p) {
/* stops testing after the first successful reply. */
double rta;
double loss;
char *rtastr = NULL;
if (alive_p && strstr(buf, "avg, 0% loss)")) {
rtastr = strstr(buf, "ms (");
rtastr = 1 + index(rtastr, '(');
@ -198,6 +217,10 @@ int textscan(char *buf) {
fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
}
mp_state_enum status = STATE_UNKNOWN;
char *xmtstr = NULL;
double xmt;
char *losstr = NULL;
if (strstr(buf, "not found")) {
die(STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
@ -221,18 +244,19 @@ int textscan(char *buf) {
rtastr = 1 + index(rtastr, '/');
loss = strtod(losstr, NULL);
rta = strtod(rtastr, NULL);
if (cpl_p && loss > cpl)
if (cpl_p && loss > cpl) {
status = STATE_CRITICAL;
else if (crta_p && rta > crta)
} else if (crta_p && rta > crta) {
status = STATE_CRITICAL;
else if (wpl_p && loss > wpl)
} else if (wpl_p && loss > wpl) {
status = STATE_WARNING;
else if (wrta_p && rta > wrta)
} else if (wrta_p && rta > wrta) {
status = STATE_WARNING;
else
} else {
status = STATE_OK;
}
die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status), server_name, loss, rta,
perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100),
perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0),
fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
} else if (strstr(buf, "xmt/rcv/%loss")) {
@ -241,22 +265,24 @@ int textscan(char *buf) {
losstr = strstr(buf, "=");
xmtstr = 1 + losstr;
xmt = strtod(xmtstr, NULL);
if (xmt == 0)
if (xmt == 0) {
die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
}
losstr = 1 + strstr(losstr, "/");
losstr = 1 + strstr(losstr, "/");
loss = strtod(losstr, NULL);
if (atoi(losstr) == 100)
if (atoi(losstr) == 100) {
status = STATE_CRITICAL;
else if (cpl_p && loss > cpl)
} else if (cpl_p && loss > cpl) {
status = STATE_CRITICAL;
else if (wpl_p && loss > wpl)
} else if (wpl_p && loss > wpl) {
status = STATE_WARNING;
else
} else {
status = STATE_OK;
}
/* loss=%.0f%%;%d;%d;0;100 */
die(status, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status), server_name, loss,
perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100));
perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0));
} else {
status = max_state(status, STATE_WARNING);
@ -266,11 +292,12 @@ int textscan(char *buf) {
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
char *rv[2];
int option = 0;
check_fping_config_wrapper process_arguments(int argc, char **argv) {
enum {
FWMARK_OPT = CHAR_MAX + 1,
ICMP_TIMESTAMP_OPT,
CHECK_SOURCE_OPT,
};
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
{"sourceip", required_argument, 0, 'S'},
{"sourceif", required_argument, 0, 'I'},
@ -288,32 +315,52 @@ int process_arguments(int argc, char **argv) {
{"use-ipv6", no_argument, 0, '6'},
{"dontfrag", no_argument, 0, 'M'},
{"random", no_argument, 0, 'R'},
#ifdef FPING_VERSION_5_2_OR_HIGHER
// only available with fping version >= 5.2
{"fwmark", required_argument, NULL, FWMARK_OPT},
# ifdef FPING_VERSION_5_3_OR_HIGHER
// only available with fping version >= 5.3
{"icmp-timestamp", no_argument, NULL, ICMP_TIMESTAMP_OPT},
{"check-source", no_argument, NULL, CHECK_SOURCE_OPT},
# endif
#endif
{0, 0, 0, 0}};
char *rv[2];
rv[PL] = NULL;
rv[RTA] = NULL;
if (argc < 2)
return ERROR;
int option = 0;
check_fping_config_wrapper result = {
.errorcode = OK,
.config = check_fping_config_init(),
};
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
if (!is_option(argv[1])) {
server_name = argv[1];
result.config.server_name = argv[1];
argv[1] = argv[0];
argv = &argv[1];
argc--;
}
while (1) {
c = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
while (true) {
int option_index = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
if (c == -1 || c == EOF || c == 1)
if (option_index == -1 || option_index == EOF || option_index == 1) {
break;
}
switch (c) {
switch (option_index) {
case '?': /* print short usage statement if args not parsable */
usage5();
case 'a': /* host alive mode */
alive_p = true;
result.config.alive_p = true;
break;
case 'h': /* help */
print_help();
@ -325,109 +372,126 @@ int process_arguments(int argc, char **argv) {
verbose = true;
break;
case 'H': /* hostname */
if (is_host(optarg) == false) {
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
}
server_name = strscpy(server_name, optarg);
result.config.server_name = optarg;
break;
case 'S': /* sourceip */
if (is_host(optarg) == false) {
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
}
sourceip = strscpy(sourceip, optarg);
result.config.sourceip = optarg;
break;
case 'I': /* sourceip */
sourceif = strscpy(sourceif, optarg);
result.config.sourceif = optarg;
break;
case '4': /* IPv4 only */
address_family = AF_INET;
break;
case '6': /* IPv6 only */
#ifdef USE_IPV6
address_family = AF_INET6;
#else
usage(_("IPv6 support not available\n"));
#endif
break;
case 'c':
get_threshold(optarg, rv);
if (rv[RTA]) {
crta = strtod(rv[RTA], NULL);
crta_p = true;
result.config.crta = strtod(rv[RTA], NULL);
result.config.crta_p = true;
rv[RTA] = NULL;
}
if (rv[PL]) {
cpl = atoi(rv[PL]);
cpl_p = true;
result.config.cpl = atoi(rv[PL]);
result.config.cpl_p = true;
rv[PL] = NULL;
}
break;
case 'w':
get_threshold(optarg, rv);
if (rv[RTA]) {
wrta = strtod(rv[RTA], NULL);
wrta_p = true;
result.config.wrta = strtod(rv[RTA], NULL);
result.config.wrta_p = true;
rv[RTA] = NULL;
}
if (rv[PL]) {
wpl = atoi(rv[PL]);
wpl_p = true;
result.config.wpl = atoi(rv[PL]);
result.config.wpl_p = true;
rv[PL] = NULL;
}
break;
case 'b': /* bytes per packet */
if (is_intpos(optarg))
packet_size = atoi(optarg);
else
if (is_intpos(optarg)) {
result.config.packet_size = atoi(optarg);
} else {
usage(_("Packet size must be a positive integer"));
}
break;
case 'n': /* number of packets */
if (is_intpos(optarg))
packet_count = atoi(optarg);
else
if (is_intpos(optarg)) {
result.config.packet_count = atoi(optarg);
} else {
usage(_("Packet count must be a positive integer"));
}
break;
case 'T': /* timeout in msec */
if (is_intpos(optarg))
target_timeout = atoi(optarg);
else
if (is_intpos(optarg)) {
result.config.target_timeout = atoi(optarg);
} else {
usage(_("Target timeout must be a positive integer"));
}
break;
case 'i': /* interval in msec */
if (is_intpos(optarg))
packet_interval = atoi(optarg);
else
if (is_intpos(optarg)) {
result.config.packet_interval = atoi(optarg);
} else {
usage(_("Interval must be a positive integer"));
}
break;
case 'R':
randomize_packet_data = true;
result.config.randomize_packet_data = true;
break;
case 'M':
dontfrag = true;
result.config.dontfrag = true;
break;
case FWMARK_OPT:
if (is_intpos(optarg)) {
result.config.fwmark = (unsigned int)atol(optarg);
result.config.fwmark_set = true;
} else {
usage(_("fwmark must be a positive integer"));
}
break;
case ICMP_TIMESTAMP_OPT:
result.config.icmp_timestamp = true;
break;
case CHECK_SOURCE_OPT:
result.config.check_source = true;
break;
}
}
if (server_name == NULL)
if (result.config.server_name == NULL) {
usage4(_("Hostname was not supplied"));
}
return OK;
return result;
}
int get_threshold(char *arg, char *rv[2]) {
char *arg1 = NULL;
char *arg2 = NULL;
arg1 = strscpy(arg1, arg);
if (strpbrk(arg1, ",:"))
char *arg1 = strdup(arg);
if (strpbrk(arg1, ",:")) {
arg2 = 1 + strpbrk(arg1, ",:");
}
if (arg2) {
arg1[strcspn(arg1, ",:")] = 0;
if (strstr(arg1, "%") && strstr(arg2, "%"))
if (strstr(arg1, "%") && strstr(arg2, "%")) {
die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname, arg);
if (!strstr(arg1, "%") && !strstr(arg2, "%"))
}
if (!strstr(arg1, "%") && !strstr(arg2, "%")) {
die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname, arg);
}
}
if (arg2 && strstr(arg2, "%")) {
@ -489,6 +553,16 @@ void print_help(void) {
printf(" %s\n", _("set the Don't Fragment flag"));
printf(" %s\n", "-R, --random");
printf(" %s\n", _("random packet data (to foil link data compression)"));
#ifdef FPING_VERSION_5_2_OR_HIGHER
printf(" %s\n", "--fwmark=INTEGER");
printf(" %s\n", _("set the routing mark to INTEGER (fping option)"));
# ifdef FPING_VERSION_5_3_OR_HIGHER
printf(" %s\n", "--icmp-timestamp");
printf(" %s\n", _("use ICMP Timestamp instead of ICMP Echo (fping option)"));
printf(" %s\n", "--check-source");
printf(" %s\n", _("discard replies not from target address (fping option)"));
# endif
#endif
printf(UT_VERBOSE);
printf("\n");
printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));

View file

@ -0,0 +1,82 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
enum {
PACKET_SIZE = 56,
PACKET_COUNT = 1,
};
typedef struct {
char *server_name;
char *sourceip;
char *sourceif;
int packet_size;
int packet_count;
int target_timeout;
int packet_interval;
bool randomize_packet_data;
bool dontfrag;
bool alive_p;
double crta;
bool crta_p;
double wrta;
bool wrta_p;
int cpl;
bool cpl_p;
int wpl;
bool wpl_p;
// only available with fping version >= 5.2
// for a given uint _fwmark_ fping sets _fwmark_ as a firewall mark
// in the packets
unsigned int fwmark;
bool fwmark_set;
// only available with fping version >= 5.3
// Setting icmp_timestamp tells fping to use ICMP Timestamp (ICMP type 13) instead
// of ICMP Echo
bool icmp_timestamp;
// Setting check_source lets fping discard replies which are not from the target address
bool check_source;
} check_fping_config;
check_fping_config check_fping_config_init() {
check_fping_config tmp = {
.server_name = NULL,
.sourceip = NULL,
.sourceif = NULL,
.packet_size = PACKET_SIZE,
.packet_count = PACKET_COUNT,
.target_timeout = 0,
.packet_interval = 0,
.randomize_packet_data = false,
.dontfrag = false,
.alive_p = false,
.crta = 0,
.crta_p = false,
.wrta = 0,
.wrta_p = false,
.cpl = 0,
.cpl_p = false,
.wpl = 0,
.wpl_p = false,
// only available with fping version >= 5.2
.fwmark = 0,
.fwmark_set = false, // just to be deterministic
// only available with fping version >= 5.3
.icmp_timestamp = false,
.check_source = false,
};
return tmp;
}

View file

@ -37,9 +37,10 @@ const char *email = "devel@monitoring-plugins.org";
#include "popen.h"
#include "utils.h"
#include "netutils.h"
#include "states.h"
#include "check_hpjd.d/config.h"
#define DEFAULT_COMMUNITY "public"
#define DEFAULT_PORT "161"
#define HPJD_LINE_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.1"
#define HPJD_PAPER_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.2"
@ -57,39 +58,15 @@ const char *email = "devel@monitoring-plugins.org";
#define ONLINE 0
#define OFFLINE 1
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int validate_arguments(void);
typedef struct {
int errorcode;
check_hpjd_config config;
} check_hpjd_config_wrapper;
static check_hpjd_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
static char *community = NULL;
static char *address = NULL;
static unsigned int port = 0;
static int check_paper_out = 1;
int main(int argc, char **argv) {
char command_line[1024];
int result = STATE_UNKNOWN;
int line;
char input_buffer[MAX_INPUT_BUFFER];
char query_string[512];
char *errmsg;
char *temp_buffer;
int line_status = ONLINE;
int paper_status = 0;
int intervention_required = 0;
int peripheral_error = 0;
int paper_jam = 0;
int paper_out = 0;
int toner_low = 0;
int page_punt = 0;
int memory_out = 0;
int door_open = 0;
int paper_output = 0;
char display_message[MAX_INPUT_BUFFER];
errmsg = malloc(MAX_INPUT_BUFFER);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -97,9 +74,15 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
usage4(_("Could not parse arguments"));
check_hpjd_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_hpjd_config config = tmp_config.config;
char query_string[512];
/* removed ' 2>1' at end of command 10/27/1999 - EG */
/* create the query string */
sprintf(query_string, "%s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0", HPJD_LINE_STATUS, HPJD_PAPER_STATUS,
@ -107,7 +90,8 @@ int main(int argc, char **argv) {
HPJD_GD_PAGE_PUNT, HPJD_GD_MEMORY_OUT, HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
/* get the command to run */
sprintf(command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", PATH_TO_SNMPGET, community, address, port, query_string);
char command_line[1024];
sprintf(command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", PATH_TO_SNMPGET, config.community, config.address, config.port, query_string);
/* run the command */
child_process = spopen(command_line);
@ -121,29 +105,41 @@ int main(int argc, char **argv) {
printf(_("Could not open stderr for %s\n"), command_line);
}
result = STATE_OK;
mp_state_enum result = STATE_OK;
int line_status = ONLINE;
int paper_status = 0;
int intervention_required = 0;
int peripheral_error = 0;
int paper_jam = 0;
int paper_out = 0;
int toner_low = 0;
int page_punt = 0;
int memory_out = 0;
int door_open = 0;
int paper_output = 0;
char display_message[MAX_INPUT_BUFFER];
char input_buffer[MAX_INPUT_BUFFER];
char *errmsg = malloc(MAX_INPUT_BUFFER);
int line = 0;
line = 0;
while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
/* strip the newline character from the end of the input */
if (input_buffer[strlen(input_buffer) - 1] == '\n')
if (input_buffer[strlen(input_buffer) - 1] == '\n') {
input_buffer[strlen(input_buffer) - 1] = 0;
}
line++;
temp_buffer = strtok(input_buffer, "=");
char *temp_buffer = strtok(input_buffer, "=");
temp_buffer = strtok(NULL, "=");
if (temp_buffer == NULL && line < 13) {
result = STATE_UNKNOWN;
strcpy(errmsg, input_buffer);
} else {
switch (line) {
case 1: /* 1st line should contain the line status */
line_status = atoi(temp_buffer);
break;
@ -186,16 +182,18 @@ int main(int argc, char **argv) {
}
/* break out of the read loop if we encounter an error */
if (result != STATE_OK)
if (result != STATE_OK) {
break;
}
}
/* WARNING if output found on stderr */
if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
result = max_state(result, STATE_WARNING);
/* remove CRLF */
if (input_buffer[strlen(input_buffer) - 1] == '\n')
if (input_buffer[strlen(input_buffer) - 1] == '\n') {
input_buffer[strlen(input_buffer) - 1] = 0;
}
sprintf(errmsg, "%s", input_buffer);
}
@ -203,15 +201,15 @@ int main(int argc, char **argv) {
(void)fclose(child_stderr);
/* close the pipe */
if (spclose(child_process))
if (spclose(child_process)) {
result = max_state(result, STATE_WARNING);
}
/* if there wasn't any output, display an error */
if (line == 0) {
/* might not be the problem, but most likely is. */
result = STATE_UNKNOWN;
xasprintf(&errmsg, "%s : Timeout from host %s\n", errmsg, address);
xasprintf(&errmsg, "%s : Timeout from host %s\n", errmsg, config.address);
}
/* if we had no read errors, check the printer status results... */
@ -221,8 +219,9 @@ int main(int argc, char **argv) {
result = STATE_WARNING;
strcpy(errmsg, _("Paper Jam"));
} else if (paper_out) {
if (check_paper_out)
if (config.check_paper_out) {
result = STATE_WARNING;
}
strcpy(errmsg, _("Out of Paper"));
} else if (line_status == OFFLINE) {
if (strcmp(errmsg, "POWERSAVE ON") != 0) {
@ -256,29 +255,23 @@ int main(int argc, char **argv) {
}
}
if (result == STATE_OK)
if (result == STATE_OK) {
printf(_("Printer ok - (%s)\n"), display_message);
else if (result == STATE_UNKNOWN) {
} else if (result == STATE_UNKNOWN) {
printf("%s\n", errmsg);
/* if printer could not be reached, escalate to critical */
if (strstr(errmsg, "Timeout"))
if (strstr(errmsg, "Timeout")) {
result = STATE_CRITICAL;
}
} else if (result == STATE_WARNING) {
printf("%s (%s)\n", errmsg, display_message);
}
else if (result == STATE_WARNING)
printf("%s (%s)\n", errmsg, display_message);
return result;
exit(result);
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
int option = 0;
check_hpjd_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
{"community", required_argument, 0, 'C'},
/* {"critical", required_argument,0,'c'}, */
@ -288,34 +281,44 @@ int process_arguments(int argc, char **argv) {
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
if (argc < 2)
return ERROR;
check_hpjd_config_wrapper result = {
.errorcode = OK,
.config = check_hpjd_config_init(),
};
while (1) {
c = getopt_long(argc, argv, "+hVH:C:p:D", longopts, &option);
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
if (c == -1 || c == EOF || c == 1)
int option = 0;
while (true) {
int option_index = getopt_long(argc, argv, "+hVH:C:p:D", longopts, &option);
if (option_index == -1 || option_index == EOF || option_index == 1) {
break;
}
switch (c) {
switch (option_index) {
case 'H': /* hostname */
if (is_host(optarg)) {
address = strscpy(address, optarg);
result.config.address = strscpy(result.config.address, optarg);
} else {
usage2(_("Invalid hostname/address"), optarg);
}
break;
case 'C': /* community */
community = strscpy(community, optarg);
result.config.community = strscpy(result.config.community, optarg);
break;
case 'p':
if (!is_intpos(optarg))
if (!is_intpos(optarg)) {
usage2(_("Port must be a positive short integer"), optarg);
else
port = atoi(optarg);
} else {
result.config.port = atoi(optarg);
}
break;
case 'D': /* disable paper out check*/
check_paper_out = 0;
result.config.check_paper_out = false;
break;
case 'V': /* version */
print_revision(progname, NP_VERSION);
@ -328,31 +331,26 @@ int process_arguments(int argc, char **argv) {
}
}
c = optind;
if (address == NULL) {
int c = optind;
if (result.config.address == NULL) {
if (is_host(argv[c])) {
address = argv[c++];
result.config.address = argv[c++];
} else {
usage2(_("Invalid hostname/address"), argv[c]);
}
}
if (community == NULL) {
if (argv[c] != NULL)
community = argv[c];
else
community = strdup(DEFAULT_COMMUNITY);
if (result.config.community == NULL) {
if (argv[c] != NULL) {
result.config.community = argv[c];
} else {
result.config.community = strdup(DEFAULT_COMMUNITY);
}
}
if (port == 0) {
port = atoi(DEFAULT_PORT);
}
return validate_arguments();
return result;
}
int validate_arguments(void) { return OK; }
void print_help(void) {
print_revision(progname, NP_VERSION);

View file

@ -0,0 +1,25 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#include <stdlib.h>
#define DEFAULT_PORT "161"
typedef struct {
char *address;
char *community;
unsigned int port;
bool check_paper_out;
} check_hpjd_config;
check_hpjd_config check_hpjd_config_init() {
check_hpjd_config tmp = {
.address = NULL,
.community = NULL,
.port = (unsigned int)atoi(DEFAULT_PORT),
.check_paper_out = true,
};
return tmp;
}

View file

@ -1724,6 +1724,16 @@ print_help (void)
printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
printf ("%s\n", _("certificate expiration times."));
printf ("\n");
printf ("%s\n", _("ATTENTION!"));
printf ("\n");
printf ("%s\n", _("THIS PLUGIN IS DEPRECATED. The functionality was reimplemented by the"));
printf ("%s\n", _("check_curl plugin, which can be used as a drop-in replacement. You should"));
printf ("%s\n", _("migrate your checks over to check_curl, because check_http is going to be"));
printf ("%s\n", _("removed sooner than later. Just replace check_http with check_curl in your"));
printf ("%s\n", _("check command definitions."));
printf ("%s\n", _("Report issues to: https://github.com/monitoring-plugins/monitoring-plugins/issues"));
printf ("\n\n");
print_usage ();

View file

@ -56,7 +56,6 @@ void print_usage(void);
# include <sys/device.h>
# include <sys/param.h>
# include <sys/sysctl.h>
# include <sys/videoio.h> /* for __u8 and friends */
# include <sys/scsiio.h>
# include <sys/ataio.h>
# include <dev/ata/atareg.h>
@ -79,48 +78,47 @@ void print_usage(void);
#define UNKNOWN -1
typedef struct threshold_s {
__u8 id;
__u8 threshold;
__u8 reserved[10];
uint8_t id;
uint8_t threshold;
uint8_t reserved[10];
} __attribute__((packed)) threshold_t;
typedef struct thresholds_s {
__u16 revision;
uint16_t revision;
threshold_t thresholds[NR_ATTRIBUTES];
__u8 reserved[18];
__u8 vendor[131];
__u8 checksum;
uint8_t reserved[18];
uint8_t vendor[131];
uint8_t checksum;
} __attribute__((packed)) thresholds_t;
typedef struct value_s {
__u8 id;
__u16 status;
__u8 value;
__u8 vendor[8];
uint8_t id;
uint16_t status;
uint8_t value;
uint8_t vendor[8];
} __attribute__((packed)) value_t;
typedef struct values_s {
__u16 revision;
uint16_t revision;
value_t values[NR_ATTRIBUTES];
__u8 offline_status;
__u8 vendor1;
__u16 offline_timeout;
__u8 vendor2;
__u8 offline_capability;
__u16 smart_capability;
__u8 reserved[16];
__u8 vendor[125];
__u8 checksum;
uint8_t offline_status;
uint8_t vendor1;
uint16_t offline_timeout;
uint8_t vendor2;
uint8_t offline_capability;
uint16_t smart_capability;
uint8_t reserved[16];
uint8_t vendor[125];
uint8_t checksum;
} __attribute__((packed)) values_t;
static struct {
__u8 value;
uint8_t value;
char *text;
} offline_status_text[] = {{0x00, "NeverStarted"}, {0x02, "Completed"}, {0x04, "Suspended"},
{0x05, "Aborted"}, {0x06, "Failed"}, {0, 0}};
} offline_status_text[] = {{0x00, "NeverStarted"}, {0x02, "Completed"}, {0x04, "Suspended"}, {0x05, "Aborted"}, {0x06, "Failed"}, {0, 0}};
static struct {
__u8 value;
uint8_t value;
char *text;
} smart_command[] = {{SMART_ENABLE, "SMART_ENABLE"},
{SMART_DISABLE, "SMART_DISABLE"},
@ -140,7 +138,7 @@ static int smart_read_values(int, values_t *);
static int nagios(values_t *, thresholds_t *);
static void print_value(value_t *, threshold_t *);
static void print_values(values_t *, thresholds_t *);
static int smart_cmd_simple(int, enum SmartCommand, __u8, bool);
static int smart_cmd_simple(int, enum SmartCommand, uint8_t, bool);
static int smart_read_thresholds(int, thresholds_t *);
static bool verbose = false;
@ -175,8 +173,9 @@ int main(int argc, char *argv[]) {
o = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex);
if (o == -1 || o == EOF || o == 1)
if (o == -1 || o == EOF || o == 1) {
break;
}
switch (o) {
case 'd':
@ -234,8 +233,9 @@ int main(int argc, char *argv[]) {
smart_read_values(fd, &values);
smart_read_thresholds(fd, &thresholds);
retval = nagios(&values, &thresholds);
if (verbose)
if (verbose) {
print_values(&values, &thresholds);
}
close(fd);
return retval;
@ -254,7 +254,7 @@ char *get_offline_text(int status) {
int smart_read_values(int fd, values_t *values) {
#ifdef __linux__
int e;
__u8 args[4 + 512];
uint8_t args[4 + 512];
args[0] = WIN_SMART;
args[1] = 0;
args[2] = SMART_READ_VALUES;
@ -282,8 +282,9 @@ int smart_read_values(int fd, values_t *values) {
req.cylinder = WDSMART_CYL;
if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
if (req.retsts != ATACMD_OK)
if (req.retsts != ATACMD_OK) {
errno = ENODEV;
}
}
if (errno != 0) {
@ -370,22 +371,24 @@ void print_values(values_t *p, thresholds_t *t) {
p->smart_capability & 1 ? "SaveOnStandBy" : "", p->smart_capability & 2 ? "AutoSave" : "");
}
int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_error) {
int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_error) {
int e = STATE_UNKNOWN;
#ifdef __linux__
__u8 args[4];
uint8_t args[4];
args[0] = WIN_SMART;
args[1] = val0;
args[2] = smart_command[command].value;
args[3] = 0;
if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
e = STATE_CRITICAL;
if (show_error)
if (show_error) {
printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
}
} else {
e = STATE_OK;
if (show_error)
if (show_error) {
printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
}
}
#endif /* __linux__ */
@ -401,20 +404,24 @@ int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_err
req.sec_count = val0;
if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
if (req.retsts != ATACMD_OK)
if (req.retsts != ATACMD_OK) {
errno = ENODEV;
if (req.cylinder != WDSMART_CYL)
}
if (req.cylinder != WDSMART_CYL) {
errno = ENODEV;
}
}
if (errno != 0) {
e = STATE_CRITICAL;
if (show_error)
if (show_error) {
printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
}
} else {
e = STATE_OK;
if (show_error)
if (show_error) {
printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
}
}
#endif /* __NetBSD__ */
@ -424,7 +431,7 @@ int smart_cmd_simple(int fd, enum SmartCommand command, __u8 val0, bool show_err
int smart_read_thresholds(int fd, thresholds_t *thresholds) {
#ifdef __linux__
int e;
__u8 args[4 + 512];
uint8_t args[4 + 512];
args[0] = WIN_SMART;
args[1] = 0;
args[2] = SMART_READ_THRESHOLDS;
@ -452,8 +459,9 @@ int smart_read_thresholds(int fd, thresholds_t *thresholds) {
req.cylinder = WDSMART_CYL;
if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
if (req.retsts != ATACMD_OK)
if (req.retsts != ATACMD_OK) {
errno = ENODEV;
}
}
if (errno != 0) {

View file

@ -1,30 +1,30 @@
/*****************************************************************************
*
* Monitoring check_ldap plugin
*
* License: GPL
* Copyright (c) 2000-2024 Monitoring Plugins Development Team
*
* Description:
*
* This file contains the check_ldap plugin
*
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
*
* Monitoring check_ldap plugin
*
* License: GPL
* Copyright (c) 2000-2024 Monitoring Plugins Development Team
*
* Description:
*
* This file contains the check_ldap plugin
*
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
/* progname may be check_ldaps */
char *progname = "check_ldap";
@ -34,209 +34,178 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
#include "check_ldap.d/config.h"
#include "states.h"
#include <lber.h>
#define LDAP_DEPRECATED 1
#include <ldap.h>
enum {
UNDEFINED = 0,
#ifdef HAVE_LDAP_SET_OPTION
DEFAULT_PROTOCOL = 2,
#endif
DEFAULT_PORT = 389
};
static int process_arguments (int, char **);
static int validate_arguments (void);
static void print_help (void);
void print_usage (void);
typedef struct {
int errorcode;
check_ldap_config config;
} check_ldap_config_wrapper;
static check_ldap_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper /*config_wrapper*/);
static void print_help(void);
void print_usage(void);
static char ld_defattr[] = "(objectclass=*)";
static char *ld_attr = ld_defattr;
static char *ld_host = NULL;
static char *ld_base = NULL;
static char *ld_passwd = NULL;
static char *ld_binddn = NULL;
static int ld_port = -1;
#ifdef HAVE_LDAP_SET_OPTION
static int ld_protocol = DEFAULT_PROTOCOL;
#endif
#ifndef LDAP_OPT_SUCCESS
# define LDAP_OPT_SUCCESS LDAP_SUCCESS
# define LDAP_OPT_SUCCESS LDAP_SUCCESS
#endif
static double warn_time = UNDEFINED;
static double crit_time = UNDEFINED;
static thresholds *entries_thresholds = NULL;
static struct timeval tv;
static char* warn_entries = NULL;
static char* crit_entries = NULL;
static bool starttls = false;
static bool ssl_on_connect = false;
static bool verbose = false;
static int verbose = 0;
/* for ldap tls */
int main(int argc, char *argv[]) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
static char *SERVICE = "LDAP";
int
main (int argc, char *argv[])
{
LDAP *ld;
LDAPMessage *result;
/* should be int result = STATE_UNKNOWN; */
int status = STATE_UNKNOWN;
long microsec;
double elapsed_time;
/* for ldap tls */
int tls;
int version=3;
int status_entries = STATE_OK;
int num_entries = 0;
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
if (strstr(argv[0],"check_ldaps")) {
xasprintf (&progname, "check_ldaps");
}
if (strstr(argv[0], "check_ldaps")) {
xasprintf(&progname, "check_ldaps");
}
/* Parse extra opts if any */
argv=np_extra_opts (&argc, argv, progname);
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments (argc, argv) == ERROR)
usage4 (_("Could not parse arguments"));
check_ldap_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
if (strstr(argv[0],"check_ldaps") && ! starttls && ! ssl_on_connect)
starttls = true;
const check_ldap_config config = tmp_config.config;
/* initialize alarm signal handling */
signal (SIGALRM, socket_timeout_alarm_handler);
signal(SIGALRM, socket_timeout_alarm_handler);
/* set socket timeout */
alarm (socket_timeout);
alarm(socket_timeout);
/* get the start time */
gettimeofday (&tv, NULL);
struct timeval start_time;
gettimeofday(&start_time, NULL);
LDAP *ldap_connection;
/* initialize ldap */
#ifdef HAVE_LDAP_INIT
if (!(ld = ldap_init (ld_host, ld_port))) {
printf ("Could not connect to the server at port %i\n", ld_port);
if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) {
printf("Could not connect to the server at port %i\n", config.ld_port);
return STATE_CRITICAL;
}
#else
if (!(ld = ldap_open (ld_host, ld_port))) {
if (verbose)
ldap_perror(ld, "ldap_open");
printf (_("Could not connect to the server at port %i\n"), ld_port);
if (!(ld = ldap_open(config.ld_host, config.ld_port))) {
if (verbose) {
ldap_perror(ldap_connection, "ldap_open");
}
printf(_("Could not connect to the server at port %i\n"), config.ld_port);
return STATE_CRITICAL;
}
#endif /* HAVE_LDAP_INIT */
#ifdef HAVE_LDAP_SET_OPTION
/* set ldap options */
if (ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &ld_protocol) !=
LDAP_OPT_SUCCESS ) {
printf(_("Could not set protocol version %d\n"), ld_protocol);
if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != LDAP_OPT_SUCCESS) {
printf(_("Could not set protocol version %d\n"), config.ld_protocol);
return STATE_CRITICAL;
}
#endif
if (ld_port == LDAPS_PORT || ssl_on_connect) {
xasprintf (&SERVICE, "LDAPS");
int version = 3;
int tls;
if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) {
#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
/* ldaps: set option tls */
tls = LDAP_OPT_X_TLS_HARD;
if (ldap_set_option (ld, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
{
if (verbose)
ldap_perror(ld, "ldaps_option");
printf (_("Could not init TLS at port %i!\n"), ld_port);
if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) {
if (verbose) {
ldap_perror(ldap_connection, "ldaps_option");
}
printf(_("Could not init TLS at port %i!\n"), config.ld_port);
return STATE_CRITICAL;
}
#else
printf (_("TLS not supported by the libraries!\n"));
printf(_("TLS not supported by the libraries!\n"));
return STATE_CRITICAL;
#endif /* LDAP_OPT_X_TLS */
} else if (starttls) {
xasprintf (&SERVICE, "LDAP-TLS");
} else if (config.starttls) {
#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S)
/* ldap with startTLS: set option version */
if (ldap_get_option(ld,LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS )
{
if (version < LDAP_VERSION3)
{
if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
if (version < LDAP_VERSION3) {
version = LDAP_VERSION3;
ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version);
}
}
/* call start_tls */
if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS)
{
if (verbose)
ldap_perror(ld, "ldap_start_tls");
printf (_("Could not init startTLS at port %i!\n"), ld_port);
if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) {
if (verbose) {
ldap_perror(ldap_connection, "ldap_start_tls");
}
printf(_("Could not init startTLS at port %i!\n"), config.ld_port);
return STATE_CRITICAL;
}
#else
printf (_("startTLS not supported by the library, needs LDAPv3!\n"));
printf(_("startTLS not supported by the library, needs LDAPv3!\n"));
return STATE_CRITICAL;
#endif /* HAVE_LDAP_START_TLS_S */
}
/* bind to the ldap server */
if (ldap_bind_s (ld, ld_binddn, ld_passwd, LDAP_AUTH_SIMPLE) !=
LDAP_SUCCESS) {
if (verbose)
ldap_perror(ld, "ldap_bind");
printf (_("Could not bind to the LDAP server\n"));
if (ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) {
if (verbose) {
ldap_perror(ldap_connection, "ldap_bind");
}
printf(_("Could not bind to the LDAP server\n"));
return STATE_CRITICAL;
}
LDAPMessage *result;
int num_entries = 0;
/* do a search of all objectclasses in the base dn */
if (ldap_search_s (ld, ld_base, (crit_entries!=NULL || warn_entries!=NULL) ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE, ld_attr, NULL, 0, &result)
!= LDAP_SUCCESS) {
if (verbose)
ldap_perror(ld, "ldap_search");
printf (_("Could not search/find objectclasses in %s\n"), ld_base);
if (ldap_search_s(ldap_connection, config.ld_base,
(config.crit_entries != NULL || config.warn_entries != NULL) ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE, config.ld_attr,
NULL, 0, &result) != LDAP_SUCCESS) {
if (verbose) {
ldap_perror(ldap_connection, "ldap_search");
}
printf(_("Could not search/find objectclasses in %s\n"), config.ld_base);
return STATE_CRITICAL;
} else if (crit_entries!=NULL || warn_entries!=NULL) {
num_entries = ldap_count_entries(ld, result);
}
if (config.crit_entries != NULL || config.warn_entries != NULL) {
num_entries = ldap_count_entries(ldap_connection, result);
}
/* unbind from the ldap server */
ldap_unbind (ld);
ldap_unbind(ldap_connection);
/* reset the alarm handler */
alarm (0);
alarm(0);
/* calculate the elapsed time and compare to thresholds */
microsec = deltime (tv);
elapsed_time = (double)microsec / 1.0e6;
if (crit_time!=UNDEFINED && elapsed_time>crit_time)
long microsec = deltime(start_time);
double elapsed_time = (double)microsec / 1.0e6;
mp_state_enum status = STATE_UNKNOWN;
if (config.crit_time_set && elapsed_time > config.crit_time) {
status = STATE_CRITICAL;
else if (warn_time!=UNDEFINED && elapsed_time>warn_time)
} else if (config.warn_time_set && elapsed_time > config.warn_time) {
status = STATE_WARNING;
else
} else {
status = STATE_OK;
}
if(entries_thresholds != NULL) {
if (config.entries_thresholds != NULL) {
if (verbose) {
printf ("entries found: %d\n", num_entries);
print_thresholds("entry thresholds", entries_thresholds);
printf("entries found: %d\n", num_entries);
print_thresholds("entry thresholds", config.entries_thresholds);
}
status_entries = get_status(num_entries, entries_thresholds);
mp_state_enum status_entries = get_status(num_entries, config.entries_thresholds);
if (status_entries == STATE_CRITICAL) {
status = STATE_CRITICAL;
} else if (status != STATE_CRITICAL) {
@ -245,273 +214,272 @@ main (int argc, char *argv[])
}
/* print out the result */
if (crit_entries!=NULL || warn_entries!=NULL) {
printf (_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"),
state_text (status),
num_entries,
elapsed_time,
fperfdata ("time", elapsed_time, "s",
(int)warn_time, warn_time,
(int)crit_time, crit_time,
true, 0, false, 0),
sperfdata ("entries", (double)num_entries, "",
warn_entries,
crit_entries,
true, 0.0, false, 0.0));
if (config.crit_entries != NULL || config.warn_entries != NULL) {
printf(_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), state_text(status), num_entries, elapsed_time,
fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, config.crit_time_set, config.crit_time, true, 0,
false, 0),
sperfdata("entries", (double)num_entries, "", config.warn_entries, config.crit_entries, true, 0.0, false, 0.0));
} else {
printf (_("LDAP %s - %.3f seconds response time|%s\n"),
state_text (status),
elapsed_time,
fperfdata ("time", elapsed_time, "s",
(int)warn_time, warn_time,
(int)crit_time, crit_time,
true, 0, false, 0));
printf(_("LDAP %s - %.3f seconds response time|%s\n"), state_text(status), elapsed_time,
fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, config.crit_time_set, config.crit_time, true, 0,
false, 0));
}
return status;
exit(status);
}
/* process command-line arguments */
int
process_arguments (int argc, char **argv)
{
int c;
int option = 0;
check_ldap_config_wrapper process_arguments(int argc, char **argv) {
/* initialize the long option struct */
static struct option longopts[] = {
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"timeout", required_argument, 0, 't'},
{"hostname", required_argument, 0, 'H'},
{"base", required_argument, 0, 'b'},
{"attr", required_argument, 0, 'a'},
{"bind", required_argument, 0, 'D'},
{"pass", required_argument, 0, 'P'},
static struct option longopts[] = {{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"timeout", required_argument, 0, 't'},
{"hostname", required_argument, 0, 'H'},
{"base", required_argument, 0, 'b'},
{"attr", required_argument, 0, 'a'},
{"bind", required_argument, 0, 'D'},
{"pass", required_argument, 0, 'P'},
#ifdef HAVE_LDAP_SET_OPTION
{"ver2", no_argument, 0, '2'},
{"ver3", no_argument, 0, '3'},
{"ver2", no_argument, 0, '2'},
{"ver3", no_argument, 0, '3'},
#endif
{"starttls", no_argument, 0, 'T'},
{"ssl", no_argument, 0, 'S'},
{"use-ipv4", no_argument, 0, '4'},
{"use-ipv6", no_argument, 0, '6'},
{"port", required_argument, 0, 'p'},
{"warn", required_argument, 0, 'w'},
{"crit", required_argument, 0, 'c'},
{"warn-entries", required_argument, 0, 'W'},
{"crit-entries", required_argument, 0, 'C'},
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}
{"starttls", no_argument, 0, 'T'},
{"ssl", no_argument, 0, 'S'},
{"use-ipv4", no_argument, 0, '4'},
{"use-ipv6", no_argument, 0, '6'},
{"port", required_argument, 0, 'p'},
{"warn", required_argument, 0, 'w'},
{"crit", required_argument, 0, 'c'},
{"warn-entries", required_argument, 0, 'W'},
{"crit-entries", required_argument, 0, 'C'},
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}};
check_ldap_config_wrapper result = {
.errorcode = OK,
.config = check_ldap_config_init(),
};
if (argc < 2)
return ERROR;
for (c = 1; c < argc; c++) {
if (strcmp ("-to", argv[c]) == 0)
strcpy (argv[c], "-t");
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
for (int index = 1; index < argc; index++) {
if (strcmp("-to", argv[index]) == 0) {
strcpy(argv[index], "-t");
}
}
int option = 0;
while (true) {
c = getopt_long (argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option);
int option_index = getopt_long(argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option);
if (c == -1 || c == EOF)
if (option_index == -1 || option_index == EOF) {
break;
}
switch (c) {
case 'h': /* help */
print_help ();
exit (STATE_UNKNOWN);
case 'V': /* version */
print_revision (progname, NP_VERSION);
exit (STATE_UNKNOWN);
case 't': /* timeout period */
if (!is_intnonneg (optarg))
usage2 (_("Timeout interval must be a positive integer"), optarg);
else
socket_timeout = atoi (optarg);
switch (option_index) {
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
case 'V': /* version */
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 't': /* timeout period */
if (!is_intnonneg(optarg)) {
usage2(_("Timeout interval must be a positive integer"), optarg);
} else {
socket_timeout = atoi(optarg);
}
break;
case 'H':
ld_host = optarg;
result.config.ld_host = optarg;
break;
case 'b':
ld_base = optarg;
result.config.ld_base = optarg;
break;
case 'p':
ld_port = atoi (optarg);
result.config.ld_port = atoi(optarg);
break;
case 'a':
ld_attr = optarg;
result.config.ld_attr = optarg;
break;
case 'D':
ld_binddn = optarg;
result.config.ld_binddn = optarg;
break;
case 'P':
ld_passwd = optarg;
result.config.ld_passwd = optarg;
break;
case 'w':
warn_time = strtod (optarg, NULL);
result.config.warn_time_set = true;
result.config.warn_time = strtod(optarg, NULL);
break;
case 'c':
crit_time = strtod (optarg, NULL);
result.config.crit_time_set = true;
result.config.crit_time = strtod(optarg, NULL);
break;
case 'W':
warn_entries = optarg;
result.config.warn_entries = optarg;
break;
case 'C':
crit_entries = optarg;
result.config.crit_entries = optarg;
break;
#ifdef HAVE_LDAP_SET_OPTION
case '2':
ld_protocol = 2;
result.config.ld_protocol = 2;
break;
case '3':
ld_protocol = 3;
result.config.ld_protocol = 3;
break;
#endif
#endif // HAVE_LDAP_SET_OPTION
case '4':
address_family = AF_INET;
break;
case 'v':
verbose = true;
verbose++;
break;
case 'T':
if (! ssl_on_connect)
starttls = true;
else
if (!result.config.ssl_on_connect) {
result.config.starttls = true;
} else {
usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl");
}
break;
case 'S':
if (! starttls) {
ssl_on_connect = true;
if (ld_port == -1)
ld_port = LDAPS_PORT;
} else
if (!result.config.starttls) {
result.config.ssl_on_connect = true;
if (result.config.ld_port == -1) {
result.config.ld_port = LDAPS_PORT;
}
} else {
usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls");
}
break;
case '6':
#ifdef USE_IPV6
address_family = AF_INET6;
#else
usage (_("IPv6 support not available\n"));
usage(_("IPv6 support not available\n"));
#endif
break;
default:
usage5 ();
usage5();
}
}
c = optind;
if (ld_host == NULL && is_host(argv[c]))
ld_host = strdup (argv[c++]);
if (ld_base == NULL && argv[c])
ld_base = strdup (argv[c++]);
if (ld_port == -1)
ld_port = DEFAULT_PORT;
return validate_arguments ();
}
int
validate_arguments ()
{
if (ld_host==NULL || strlen(ld_host)==0)
usage4 (_("Please specify the host name\n"));
if (ld_base==NULL)
usage4 (_("Please specify the LDAP base\n"));
if (crit_entries!=NULL || warn_entries!=NULL) {
set_thresholds(&entries_thresholds,
warn_entries, crit_entries);
int index = optind;
if ((result.config.ld_host == NULL) && is_host(argv[index])) {
result.config.ld_host = strdup(argv[index++]);
}
if (ld_passwd==NULL)
ld_passwd = getenv("LDAP_PASSWORD");
return OK;
if ((result.config.ld_base == NULL) && argv[index]) {
result.config.ld_base = strdup(argv[index++]);
}
if (result.config.ld_port == -1) {
result.config.ld_port = DEFAULT_PORT;
}
if (strstr(argv[0], "check_ldaps") && !result.config.starttls && !result.config.ssl_on_connect) {
result.config.starttls = true;
}
return validate_arguments(result);
}
check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper config_wrapper) {
if (config_wrapper.config.ld_host == NULL || strlen(config_wrapper.config.ld_host) == 0) {
usage4(_("Please specify the host name\n"));
}
void
print_help (void)
{
if (config_wrapper.config.ld_base == NULL) {
usage4(_("Please specify the LDAP base\n"));
}
if (config_wrapper.config.crit_entries != NULL || config_wrapper.config.warn_entries != NULL) {
set_thresholds(&config_wrapper.config.entries_thresholds, config_wrapper.config.warn_entries, config_wrapper.config.crit_entries);
}
if (config_wrapper.config.ld_passwd == NULL) {
config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD");
}
return config_wrapper;
}
void print_help(void) {
char *myport;
xasprintf (&myport, "%d", DEFAULT_PORT);
xasprintf(&myport, "%d", DEFAULT_PORT);
print_revision (progname, NP_VERSION);
print_revision(progname, NP_VERSION);
printf ("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n");
printf (COPYRIGHT, copyright, email);
printf("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n");
printf(COPYRIGHT, copyright, email);
printf ("\n\n");
printf("\n\n");
print_usage ();
print_usage();
printf (UT_HELP_VRSN);
printf (UT_EXTRA_OPTS);
printf(UT_HELP_VRSN);
printf(UT_EXTRA_OPTS);
printf (UT_HOST_PORT, 'p', myport);
printf(UT_HOST_PORT, 'p', myport);
printf (UT_IPv46);
printf(UT_IPv46);
printf (" %s\n", "-a [--attr]");
printf (" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\""));
printf (" %s\n", "-b [--base]");
printf (" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at"));
printf (" %s\n", "-D [--bind]");
printf (" %s\n", _("ldap bind DN (if required)"));
printf (" %s\n", "-P [--pass]");
printf (" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')"));
printf (" %s\n", "-T [--starttls]");
printf (" %s\n", _("use starttls mechanism introduced in protocol version 3"));
printf (" %s\n", "-S [--ssl]");
printf (" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT);
printf(" %s\n", "-a [--attr]");
printf(" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\""));
printf(" %s\n", "-b [--base]");
printf(" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at"));
printf(" %s\n", "-D [--bind]");
printf(" %s\n", _("ldap bind DN (if required)"));
printf(" %s\n", "-P [--pass]");
printf(" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')"));
printf(" %s\n", "-T [--starttls]");
printf(" %s\n", _("use starttls mechanism introduced in protocol version 3"));
printf(" %s\n", "-S [--ssl]");
printf(" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT);
#ifdef HAVE_LDAP_SET_OPTION
printf (" %s\n", "-2 [--ver2]");
printf (" %s\n", _("use ldap protocol version 2"));
printf (" %s\n", "-3 [--ver3]");
printf (" %s\n", _("use ldap protocol version 3"));
printf (" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL);
printf(" %s\n", "-2 [--ver2]");
printf(" %s\n", _("use ldap protocol version 2"));
printf(" %s\n", "-3 [--ver3]");
printf(" %s\n", _("use ldap protocol version 3"));
printf(" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL);
#endif
printf (UT_WARN_CRIT);
printf(UT_WARN_CRIT);
printf (" %s\n", "-W [--warn-entries]");
printf (" %s\n", _("Number of found entries to result in warning status"));
printf (" %s\n", "-C [--crit-entries]");
printf (" %s\n", _("Number of found entries to result in critical status"));
printf(" %s\n", "-W [--warn-entries]");
printf(" %s\n", _("Number of found entries to result in warning status"));
printf(" %s\n", "-C [--crit-entries]");
printf(" %s\n", _("Number of found entries to result in critical status"));
printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
printf (UT_VERBOSE);
printf(UT_VERBOSE);
printf ("\n");
printf ("%s\n", _("Notes:"));
printf (" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be"));
printf (_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT);
printf (" %s\n", _("'SSL on connect' will be used no matter how the plugin was called."));
printf (" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags"));
printf (" %s\n", _("to define the behaviour explicitly instead."));
printf (" %s\n", _("The parameters --warn-entries and --crit-entries are optional."));
printf("\n");
printf("%s\n", _("Notes:"));
printf(" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be"));
printf(_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT);
printf(" %s\n", _("'SSL on connect' will be used no matter how the plugin was called."));
printf(" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags"));
printf(" %s\n", _("to define the behaviour explicitly instead."));
printf(" %s\n", _("The parameters --warn-entries and --crit-entries are optional."));
printf (UT_SUPPORT);
printf(UT_SUPPORT);
}
void
print_usage (void)
{
printf ("%s\n", _("Usage:"));
printf (" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]",progname);
printf ("\n [-P <password>] [-w <warn_time>] [-c <crit_time>] [-t timeout]%s\n",
void print_usage(void) {
printf("%s\n", _("Usage:"));
printf(" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]", progname);
printf("\n [-P <password>] [-w <warn_time>] [-c <crit_time>] [-t timeout]%s\n",
#ifdef HAVE_LDAP_SET_OPTION
"\n [-2|-3] [-4|-6]"
"\n [-2|-3] [-4|-6]"
#else
""
""
#endif
);
);
}

View file

@ -0,0 +1,60 @@
#pragma once
#include "../../config.h"
#include "thresholds.h"
#include <stddef.h>
static char ld_defattr[] = "(objectclass=*)";
enum {
#ifdef HAVE_LDAP_SET_OPTION
DEFAULT_PROTOCOL = 2,
#endif
};
typedef struct {
char *ld_host;
char *ld_base;
char *ld_passwd;
char *ld_binddn;
char *ld_attr;
int ld_port;
bool starttls;
bool ssl_on_connect;
#ifdef HAVE_LDAP_SET_OPTION
int ld_protocol;
#endif
char *warn_entries;
char *crit_entries;
thresholds *entries_thresholds;
bool warn_time_set;
double warn_time;
bool crit_time_set;
double crit_time;
} check_ldap_config;
check_ldap_config check_ldap_config_init() {
check_ldap_config tmp = {
.ld_host = NULL,
.ld_base = NULL,
.ld_passwd = NULL,
.ld_binddn = NULL,
.ld_attr = ld_defattr,
.ld_port = -1,
.starttls = false,
.ssl_on_connect = false,
#ifdef HAVE_LDAP_SET_OPTION
.ld_protocol = DEFAULT_PROTOCOL,
#endif
.warn_entries = NULL,
.crit_entries = NULL,
.entries_thresholds = NULL,
.warn_time_set = false,
.warn_time = 0,
.crit_time_set = false,
.crit_time = 0,
};
return tmp;
}

View file

@ -1,350 +1,423 @@
/*****************************************************************************
*
* Monitoring check_load plugin
*
* License: GPL
* Copyright (c) 1999-2007 Monitoring Plugins Development Team
*
* Description:
*
* This file contains the check_load plugin
*
* This plugin tests the current system load average.
*
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
*
* Monitoring check_load plugin
*
* License: GPL
* Copyright (c) 1999-2007 Monitoring Plugins Development Team
*
* Description:
*
* This file contains the check_load plugin
*
* This plugin tests the current system load average.
*
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
const char *progname = "check_load";
const char *copyright = "1999-2022";
const char *email = "devel@monitoring-plugins.org";
#include "./common.h"
#include <string.h>
#include "./runcmd.h"
#include "./utils.h"
#include "./popen.h"
#include "../lib/states.h"
#include "../lib/output.h"
#include "../lib/perfdata.h"
#include "../lib/thresholds.h"
#include "check_load.d/config.h"
#include <string.h>
#ifdef HAVE_SYS_LOADAVG_H
#include <sys/loadavg.h>
#endif
// getloadavg comes from gnulib
#include "../gl/stdlib.h"
/* needed for compilation under NetBSD, as suggested by Andy Doran */
#ifndef LOADAVG_1MIN
#define LOADAVG_1MIN 0
#define LOADAVG_5MIN 1
#define LOADAVG_15MIN 2
# define LOADAVG_1MIN 0
# define LOADAVG_5MIN 1
# define LOADAVG_15MIN 2
#endif /* !defined LOADAVG_1MIN */
typedef struct {
int errorcode;
check_load_config config;
} check_load_config_wrapper;
static check_load_config_wrapper process_arguments(int argc, char **argv);
static int process_arguments (int argc, char **argv);
static int validate_arguments (void);
void print_help (void);
void print_usage (void);
static int print_top_consuming_processes();
void print_help(void);
void print_usage(void);
typedef struct {
int errorcode;
char **top_processes;
} top_processes_result;
static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show);
static int n_procs_to_show = 0;
typedef struct {
mp_range load[3];
} parsed_thresholds;
static parsed_thresholds get_threshold(char *arg) {
size_t index;
char *str = arg;
char *tmp_pointer;
bool valid = false;
/* strictly for pretty-print usage in loops */
static const int nums[3] = { 1, 5, 15 };
parsed_thresholds result = {
.load =
{
mp_range_init(),
mp_range_init(),
mp_range_init(),
},
};
/* provide some fairly sane defaults */
double wload[3] = { 0.0, 0.0, 0.0 };
double cload[3] = { 0.0, 0.0, 0.0 };
#define la1 la[0]
#define la5 la[1]
#define la15 la[2]
size_t arg_length = strlen(arg);
for (index = 0; index < 3; index++) {
double tmp = strtod(str, &tmp_pointer);
if (tmp_pointer == str) {
break;
}
char *status_line;
bool take_into_account_cpus = false;
result.load[index] = mp_range_set_end(result.load[index], mp_create_pd_value(tmp));
static void
get_threshold(char *arg, double *th)
{
size_t i, n;
int valid = 0;
char *str = arg, *p;
n = strlen(arg);
for(i = 0; i < 3; i++) {
th[i] = strtod(str, &p);
if(p == str) break;
valid = 1;
str = p + 1;
if(n <= (size_t)(str - arg)) break;
valid = true;
str = tmp_pointer + 1;
if (arg_length <= (size_t)(str - arg)) {
break;
}
}
/* empty argument or non-floatish, so warn about it and die */
if(!i && !valid) usage (_("Warning threshold must be float or float triplet!\n"));
if (!index && !valid) {
usage(_("Warning threshold must be float or float triplet!\n"));
}
if(i != 2) {
if (index != 2) {
/* one or more numbers were given, so fill array with last
* we got (most likely to NOT produce the least expected result) */
for(n = i; n < 3; n++) th[n] = th[i];
}
}
int
main (int argc, char **argv)
{
int result = -1;
int i;
long numcpus;
double la[3] = { 0.0, 0.0, 0.0 }; /* NetBSD complains about uninitialized arrays */
#ifndef HAVE_GETLOADAVG
char input_buffer[MAX_INPUT_BUFFER];
#endif
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
setlocale(LC_NUMERIC, "POSIX");
/* Parse extra opts if any */
argv = np_extra_opts (&argc, argv, progname);
if (process_arguments (argc, argv) == ERROR)
usage4 (_("Could not parse arguments"));
#ifdef HAVE_GETLOADAVG
result = getloadavg (la, 3);
if (result != 3)
return STATE_UNKNOWN;
#else
child_process = spopen (PATH_TO_UPTIME);
if (child_process == NULL) {
printf (_("Error opening %s\n"), PATH_TO_UPTIME);
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"), PATH_TO_UPTIME);
}
fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
if(strstr(input_buffer, "load average:")) {
sscanf (input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15);
}
else if(strstr(input_buffer, "load averages:")) {
sscanf (input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15);
}
else {
printf (_("could not parse load from uptime %s: %d\n"), PATH_TO_UPTIME, result);
return STATE_UNKNOWN;
}
result = spclose (child_process);
if (result) {
printf (_("Error code %d returned in %s\n"), result, PATH_TO_UPTIME);
return STATE_UNKNOWN;
}
#endif
if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) {
#ifdef HAVE_GETLOADAVG
printf (_("Error in getloadavg()\n"));
#else
printf (_("Error processing %s\n"), PATH_TO_UPTIME);
#endif
return STATE_UNKNOWN;
}
/* we got this far, so assume OK until we've measured */
result = STATE_OK;
xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15);
xasprintf(&status_line, ("total %s"), status_line);
double scaled_la[3] = { 0.0, 0.0, 0.0 };
bool is_using_scaled_load_values = false;
if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) {
is_using_scaled_load_values = true;
scaled_la[0] = la[0] / numcpus;
scaled_la[1] = la[1] / numcpus;
scaled_la[2] = la[2] / numcpus;
char *tmp = NULL;
xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]);
xasprintf(&status_line, "scaled %s - %s", tmp, status_line);
}
for(i = 0; i < 3; i++) {
if (is_using_scaled_load_values) {
if(scaled_la[i] > cload[i]) {
result = STATE_CRITICAL;
break;
}
else if(scaled_la[i] > wload[i]) result = STATE_WARNING;
} else {
if(la[i] > cload[i]) {
result = STATE_CRITICAL;
break;
}
else if(la[i] > wload[i]) result = STATE_WARNING;
for (size_t tmp_index = index; tmp_index < 3; tmp_index++) {
result.load[tmp_index] = result.load[index];
}
}
printf("LOAD %s - %s|", state_text(result), status_line);
for(i = 0; i < 3; i++) {
if (is_using_scaled_load_values) {
printf("load%d=%.3f;;;0; ", nums[i], la[i]);
printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]);
} else {
printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]);
}
}
putchar('\n');
if (n_procs_to_show > 0) {
print_top_consuming_processes();
}
return result;
}
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
setlocale(LC_NUMERIC, "POSIX");
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
check_load_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_load_config config = tmp_config.config;
double load_values[3] = {0, 0, 0};
// this should be getloadavg from gnulib, should work everywhere™
int error = getloadavg(load_values, 3);
if (error != 3) {
die(STATE_UNKNOWN, _("Failed to retrieve load values"));
}
mp_check overall = mp_check_init();
if (config.output_format_set) {
mp_set_format(config.output_format);
}
bool is_using_scaled_load_values = false;
long numcpus;
if (config.take_into_account_cpus && ((numcpus = GET_NUMBER_OF_CPUS()) > 0)) {
is_using_scaled_load_values = true;
double scaled_la[3] = {
load_values[0] / numcpus,
load_values[1] / numcpus,
load_values[2] / numcpus,
};
mp_subcheck scaled_load_sc = mp_subcheck_init();
scaled_load_sc = mp_set_subcheck_default_state(scaled_load_sc, STATE_OK);
scaled_load_sc.output = "Scaled Load (divided by number of CPUs";
mp_perfdata pd_scaled_load1 = perfdata_init();
pd_scaled_load1.label = "scaled_load1";
pd_scaled_load1 = mp_set_pd_value(pd_scaled_load1, scaled_la[0]);
pd_scaled_load1 = mp_pd_set_thresholds(pd_scaled_load1, config.th_load[0]);
mp_subcheck scaled_load_sc1 = mp_subcheck_init();
scaled_load_sc1 = mp_set_subcheck_state(scaled_load_sc1, mp_get_pd_status(pd_scaled_load1));
mp_add_perfdata_to_subcheck(&scaled_load_sc1, pd_scaled_load1);
xasprintf(&scaled_load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_scaled_load1.value));
mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc1);
mp_perfdata pd_scaled_load5 = perfdata_init();
pd_scaled_load5.label = "scaled_load5";
pd_scaled_load5 = mp_set_pd_value(pd_scaled_load5, scaled_la[1]);
pd_scaled_load5 = mp_pd_set_thresholds(pd_scaled_load5, config.th_load[1]);
mp_subcheck scaled_load_sc5 = mp_subcheck_init();
scaled_load_sc5 = mp_set_subcheck_state(scaled_load_sc5, mp_get_pd_status(pd_scaled_load5));
mp_add_perfdata_to_subcheck(&scaled_load_sc5, pd_scaled_load5);
xasprintf(&scaled_load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_scaled_load5.value));
mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc5);
mp_perfdata pd_scaled_load15 = perfdata_init();
pd_scaled_load15.label = "scaled_load15";
pd_scaled_load15 = mp_set_pd_value(pd_scaled_load15, scaled_la[2]);
pd_scaled_load15 = mp_pd_set_thresholds(pd_scaled_load15, config.th_load[2]);
mp_subcheck scaled_load_sc15 = mp_subcheck_init();
scaled_load_sc15 = mp_set_subcheck_state(scaled_load_sc15, mp_get_pd_status(pd_scaled_load15));
mp_add_perfdata_to_subcheck(&scaled_load_sc15, pd_scaled_load15);
xasprintf(&scaled_load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_scaled_load15.value));
mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc15);
mp_add_subcheck_to_check(&overall, scaled_load_sc);
}
mp_subcheck load_sc = mp_subcheck_init();
load_sc = mp_set_subcheck_default_state(load_sc, STATE_OK);
load_sc.output = "Total Load";
mp_perfdata pd_load1 = perfdata_init();
pd_load1.label = "load1";
pd_load1 = mp_set_pd_value(pd_load1, load_values[0]);
if (!is_using_scaled_load_values) {
pd_load1 = mp_pd_set_thresholds(pd_load1, config.th_load[0]);
}
mp_subcheck load_sc1 = mp_subcheck_init();
load_sc1 = mp_set_subcheck_state(load_sc1, mp_get_pd_status(pd_load1));
mp_add_perfdata_to_subcheck(&load_sc1, pd_load1);
xasprintf(&load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_load1.value));
mp_add_subcheck_to_subcheck(&load_sc, load_sc1);
mp_perfdata pd_load5 = perfdata_init();
pd_load5.label = "load5";
pd_load5 = mp_set_pd_value(pd_load5, load_values[1]);
if (!is_using_scaled_load_values) {
pd_load5 = mp_pd_set_thresholds(pd_load5, config.th_load[1]);
}
mp_subcheck load_sc5 = mp_subcheck_init();
load_sc5 = mp_set_subcheck_state(load_sc5, mp_get_pd_status(pd_load5));
mp_add_perfdata_to_subcheck(&load_sc5, pd_load5);
xasprintf(&load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_load5.value));
mp_add_subcheck_to_subcheck(&load_sc, load_sc5);
mp_perfdata pd_load15 = perfdata_init();
pd_load15.label = "load15";
pd_load15 = mp_set_pd_value(pd_load15, load_values[2]);
if (!is_using_scaled_load_values) {
pd_load15 = mp_pd_set_thresholds(pd_load15, config.th_load[2]);
}
mp_subcheck load_sc15 = mp_subcheck_init();
load_sc15 = mp_set_subcheck_state(load_sc15, mp_get_pd_status(pd_load15));
mp_add_perfdata_to_subcheck(&load_sc15, pd_load15);
xasprintf(&load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_load15.value));
mp_add_subcheck_to_subcheck(&load_sc, load_sc15);
mp_add_subcheck_to_check(&overall, load_sc);
if (config.n_procs_to_show > 0) {
mp_subcheck top_proc_sc = mp_subcheck_init();
top_proc_sc = mp_set_subcheck_state(top_proc_sc, STATE_OK);
top_processes_result top_proc = print_top_consuming_processes(config.n_procs_to_show);
xasprintf(&top_proc_sc.output, "Top %lu CPU time consuming processes", config.n_procs_to_show);
if (top_proc.errorcode == OK) {
for (unsigned long i = 0; i < config.n_procs_to_show; i++) {
xasprintf(&top_proc_sc.output, "%s\n%s", top_proc_sc.output, top_proc.top_processes[i]);
}
}
mp_add_subcheck_to_check(&overall, top_proc_sc);
}
mp_exit(overall);
}
/* process command-line arguments */
static int
process_arguments (int argc, char **argv)
{
int c = 0;
static check_load_config_wrapper process_arguments(int argc, char **argv) {
int option = 0;
static struct option longopts[] = {
{"warning", required_argument, 0, 'w'},
{"critical", required_argument, 0, 'c'},
{"percpu", no_argument, 0, 'r'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{"procs-to-show", required_argument, 0, 'n'},
{0, 0, 0, 0}
enum {
output_format_index = CHAR_MAX + 1,
};
if (argc < 2)
return ERROR;
static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
{"critical", required_argument, 0, 'c'},
{"percpu", no_argument, 0, 'r'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{"procs-to-show", required_argument, 0, 'n'},
{"output-format", required_argument, 0, output_format_index},
{0, 0, 0, 0}};
while (1) {
c = getopt_long (argc, argv, "Vhrc:w:n:", longopts, &option);
check_load_config_wrapper result = {
.errorcode = OK,
.config = check_load_config_init(),
};
if (c == -1 || c == EOF)
break;
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
switch (c) {
case 'w': /* warning time threshold */
get_threshold(optarg, wload);
while (true) {
int option = 0;
int option_index = getopt_long(argc, argv, "Vhrc:w:n:", longopts, &option);
if (option_index == -1 || option_index == EOF) {
break;
case 'c': /* critical time threshold */
get_threshold(optarg, cload);
}
switch (option_index) {
case output_format_index: {
parsed_output_format parser = mp_parse_output_format(optarg);
if (!parser.parsing_success) {
printf("Invalid output format: %s\n", optarg);
exit(STATE_UNKNOWN);
}
result.config.output_format_set = true;
result.config.output_format = parser.output_format;
break;
}
case 'w': /* warning time threshold */ {
parsed_thresholds warning_range = get_threshold(optarg);
result.config.th_load[0].warning = warning_range.load[0];
result.config.th_load[0].warning_is_set = true;
result.config.th_load[1].warning = warning_range.load[1];
result.config.th_load[1].warning_is_set = true;
result.config.th_load[2].warning = warning_range.load[2];
result.config.th_load[2].warning_is_set = true;
} break;
case 'c': /* critical time threshold */ {
parsed_thresholds critical_range = get_threshold(optarg);
result.config.th_load[0].critical = critical_range.load[0];
result.config.th_load[0].critical_is_set = true;
result.config.th_load[1].critical = critical_range.load[1];
result.config.th_load[1].critical_is_set = true;
result.config.th_load[2].critical = critical_range.load[2];
result.config.th_load[2].critical_is_set = true;
} break;
case 'r': /* Divide load average by number of CPUs */
take_into_account_cpus = true;
result.config.take_into_account_cpus = true;
break;
case 'V': /* version */
print_revision (progname, NP_VERSION);
exit (STATE_UNKNOWN);
case 'h': /* help */
print_help ();
exit (STATE_UNKNOWN);
case 'V': /* version */
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
case 'n':
n_procs_to_show = atoi(optarg);
result.config.n_procs_to_show = (unsigned long)atol(optarg);
break;
case '?': /* help */
usage5 ();
case '?': /* help */
usage5();
}
}
c = optind;
if (c == argc)
return validate_arguments ();
int index = optind;
if (index == argc) {
return result;
}
/* handle the case if both arguments are missing,
* but not if only one is given without -c or -w flag */
if(c - argc == 2) {
get_threshold(argv[c++], wload);
get_threshold(argv[c++], cload);
}
else if(c - argc == 1) {
get_threshold(argv[c++], cload);
if (index - argc == 2) {
parsed_thresholds warning_range = get_threshold(argv[index++]);
result.config.th_load[0].warning = warning_range.load[0];
result.config.th_load[0].warning_is_set = true;
result.config.th_load[1].warning = warning_range.load[1];
result.config.th_load[1].warning_is_set = true;
result.config.th_load[2].warning = warning_range.load[2];
result.config.th_load[2].warning_is_set = true;
parsed_thresholds critical_range = get_threshold(argv[index++]);
result.config.th_load[0].critical = critical_range.load[0];
result.config.th_load[0].critical_is_set = true;
result.config.th_load[1].critical = critical_range.load[1];
result.config.th_load[1].critical_is_set = true;
result.config.th_load[2].critical = critical_range.load[2];
result.config.th_load[2].critical_is_set = true;
} else if (index - argc == 1) {
parsed_thresholds critical_range = get_threshold(argv[index++]);
result.config.th_load[0].critical = critical_range.load[0];
result.config.th_load[0].critical_is_set = true;
result.config.th_load[1].critical = critical_range.load[1];
result.config.th_load[1].critical_is_set = true;
result.config.th_load[2].critical = critical_range.load[2];
result.config.th_load[2].critical_is_set = true;
}
return validate_arguments ();
return result;
}
void print_help(void) {
print_revision(progname, NP_VERSION);
static int
validate_arguments (void)
{
int i = 0;
printf("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
printf(COPYRIGHT, copyright, email);
/* match cload first, as it will give the most friendly error message
* if user hasn't given the -c switch properly */
for(i = 0; i < 3; i++) {
if(cload[i] < 0)
die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]);
if(wload[i] < 0)
die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]);
if(wload[i] > cload[i])
die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]);
}
printf(_("This plugin tests the current system load average."));
return OK;
printf("\n\n");
print_usage();
printf(UT_HELP_VRSN);
printf(UT_EXTRA_OPTS);
printf(" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
printf(" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
printf(" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
printf(" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
printf(" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
printf(" %s\n", "-r, --percpu");
printf(" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
printf(" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
printf(" %s\n", _("Number of processes to show when printing the top consuming processes."));
printf(" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
printf(UT_OUTPUT_FORMAT);
printf(UT_SUPPORT);
}
void
print_help (void)
{
print_revision (progname, NP_VERSION);
printf ("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
printf (COPYRIGHT, copyright, email);
printf (_("This plugin tests the current system load average."));
printf ("\n\n");
print_usage ();
printf (UT_HELP_VRSN);
printf (UT_EXTRA_OPTS);
printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
printf (" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
printf (" %s\n", "-r, --percpu");
printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
printf (" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
printf (" %s\n", _("Number of processes to show when printing the top consuming processes."));
printf (" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
printf (UT_SUPPORT);
}
void
print_usage (void)
{
printf ("%s\n", _("Usage:"));
printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
void print_usage(void) {
printf("%s\n", _("Usage:"));
printf("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
}
#ifdef PS_USES_PROCPCPU
@ -356,36 +429,51 @@ int cmpstringp(const void *p1, const void *p2) {
int procrss = 0;
float procpcpu = 0;
char procstat[8];
#ifdef PS_USES_PROCETIME
# ifdef PS_USES_PROCETIME
char procetime[MAX_INPUT_BUFFER];
#endif /* PS_USES_PROCETIME */
# endif /* PS_USES_PROCETIME */
char procprog[MAX_INPUT_BUFFER];
int pos;
sscanf (* (char * const *) p1, PS_FORMAT, PS_VARLIST);
sscanf(*(char *const *)p1, PS_FORMAT, PS_VARLIST);
float procpcpu1 = procpcpu;
sscanf (* (char * const *) p2, PS_FORMAT, PS_VARLIST);
sscanf(*(char *const *)p2, PS_FORMAT, PS_VARLIST);
return procpcpu1 < procpcpu;
}
#endif /* PS_USES_PROCPCPU */
static int print_top_consuming_processes() {
int i = 0;
struct output chld_out, chld_err;
if(np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0){
static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show) {
top_processes_result result = {
.errorcode = OK,
};
struct output chld_out;
struct output chld_err;
if (np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0) {
fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND);
return STATE_UNKNOWN;
result.errorcode = ERROR;
return result;
}
if (chld_out.lines < 2) {
fprintf(stderr, _("some error occurred getting procs list.\n"));
return STATE_UNKNOWN;
result.errorcode = ERROR;
return result;
}
#ifdef PS_USES_PROCPCPU
qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char*), cmpstringp);
qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char *), cmpstringp);
#endif /* PS_USES_PROCPCPU */
int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1)
? (int)chld_out.lines : n_procs_to_show + 1;
for (i = 0; i < lines_to_show; i += 1) {
printf("%s\n", chld_out.line[i]);
unsigned long lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) ? chld_out.lines : n_procs_to_show + 1;
result.top_processes = calloc(lines_to_show, sizeof(char *));
if (result.top_processes == NULL) {
// Failed allocation
result.errorcode = ERROR;
return result;
}
return OK;
for (unsigned long i = 0; i < lines_to_show; i += 1) {
xasprintf(&result.top_processes[i], "%s", chld_out.line[i]);
}
return result;
}

View file

@ -0,0 +1,30 @@
#pragma once
#include "output.h"
#include "thresholds.h"
typedef struct {
mp_thresholds th_load[3];
bool take_into_account_cpus;
unsigned long n_procs_to_show;
mp_output_format output_format;
bool output_format_set;
} check_load_config;
check_load_config check_load_config_init() {
check_load_config tmp = {
.th_load =
{
mp_thresholds_init(),
mp_thresholds_init(),
mp_thresholds_init(),
},
.take_into_account_cpus = false,
.n_procs_to_show = 0,
.output_format_set = false,
};
return tmp;
}

View file

@ -35,21 +35,18 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "utils.h"
#include "check_mrtg.d/config.h"
typedef struct {
int errorcode;
check_mrtg_config config;
} check_mrtg_config_wrapper;
static check_mrtg_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper /*config_wrapper*/);
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int validate_arguments(void);
static void print_help(void);
void print_usage(void);
static char *log_file = NULL;
static int expire_minutes = 0;
static bool use_average = true;
static int variable_number = -1;
static unsigned long value_warning_threshold = 0L;
static unsigned long value_critical_threshold = 0L;
static char *label;
static char *units;
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
@ -58,32 +55,37 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_mrtg_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments\n"));
}
const check_mrtg_config config = tmp_config.config;
/* open the MRTG log file for reading */
FILE *mtrg_log_file = fopen(log_file, "r");
FILE *mtrg_log_file = fopen(config.log_file, "r");
if (mtrg_log_file == NULL) {
printf(_("Unable to open MRTG log file\n"));
return STATE_UNKNOWN;
}
time_t timestamp = 0L;
unsigned long average_value_rate = 0L;
unsigned long maximum_value_rate = 0L;
time_t timestamp = 0;
unsigned long average_value_rate = 0;
unsigned long maximum_value_rate = 0;
char input_buffer[MAX_INPUT_BUFFER];
int line = 0;
while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mtrg_log_file)) {
line++;
/* skip the first line of the log file */
if (line == 1)
if (line == 1) {
continue;
}
/* break out of read loop if we've passed the number of entries we want to read */
if (line > 2)
if (line > 2) {
break;
}
/* grab the timestamp */
char *temp_buffer = strtok(input_buffer, " ");
@ -91,23 +93,27 @@ int main(int argc, char **argv) {
/* grab the average value 1 rate */
temp_buffer = strtok(NULL, " ");
if (variable_number == 1)
if (config.variable_number == 1) {
average_value_rate = strtoul(temp_buffer, NULL, 10);
}
/* grab the average value 2 rate */
temp_buffer = strtok(NULL, " ");
if (variable_number == 2)
if (config.variable_number == 2) {
average_value_rate = strtoul(temp_buffer, NULL, 10);
}
/* grab the maximum value 1 rate */
temp_buffer = strtok(NULL, " ");
if (variable_number == 1)
if (config.variable_number == 1) {
maximum_value_rate = strtoul(temp_buffer, NULL, 10);
}
/* grab the maximum value 2 rate */
temp_buffer = strtok(NULL, " ");
if (variable_number == 2)
if (config.variable_number == 2) {
maximum_value_rate = strtoul(temp_buffer, NULL, 10);
}
}
/* close the log file */
@ -122,49 +128,59 @@ int main(int argc, char **argv) {
/* make sure the MRTG data isn't too old */
time_t current_time;
time(&current_time);
if (expire_minutes > 0 && (current_time - timestamp) > (expire_minutes * 60)) {
if (config.expire_minutes > 0 && (current_time - timestamp) > (config.expire_minutes * 60)) {
printf(_("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60));
return STATE_WARNING;
}
unsigned long rate = 0L;
/* else check the incoming/outgoing rates */
if (use_average)
if (config.use_average) {
rate = average_value_rate;
else
} else {
rate = maximum_value_rate;
}
int result = STATE_OK;
if (rate > value_critical_threshold)
if (config.value_critical_threshold_set && rate > config.value_critical_threshold) {
result = STATE_CRITICAL;
else if (rate > value_warning_threshold)
} else if (config.value_warning_threshold_set && rate > config.value_warning_threshold) {
result = STATE_WARNING;
}
printf("%s. %s = %lu %s|%s\n", (use_average) ? _("Avg") : _("Max"), label, rate, units,
perfdata(label, (long)rate, units, (int)value_warning_threshold, (long)value_warning_threshold, (int)value_critical_threshold,
(long)value_critical_threshold, 0, 0, 0, 0));
printf("%s. %s = %lu %s|%s\n", (config.use_average) ? _("Avg") : _("Max"), config.label, rate, config.units,
perfdata(config.label, (long)rate, config.units, config.value_warning_threshold_set, (long)config.value_warning_threshold,
config.value_critical_threshold_set, (long)config.value_critical_threshold, 0, 0, 0, 0));
return result;
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {
{"logfile", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'}, {"aggregation", required_argument, 0, 'a'},
{"variable", required_argument, 0, 'v'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'},
{"label", required_argument, 0, 'l'}, {"units", required_argument, 0, 'u'}, {"variable", required_argument, 0, 'v'},
{"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
if (argc < 2)
return ERROR;
check_mrtg_config_wrapper result = {
.errorcode = OK,
.config = check_mrtg_config_init(),
};
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
for (int i = 1; i < argc; i++) {
if (strcmp("-to", argv[i]) == 0)
if (strcmp("-to", argv[i]) == 0) {
strcpy(argv[i], "-t");
else if (strcmp("-wt", argv[i]) == 0)
} else if (strcmp("-wt", argv[i]) == 0) {
strcpy(argv[i], "-w");
else if (strcmp("-ct", argv[i]) == 0)
} else if (strcmp("-ct", argv[i]) == 0) {
strcpy(argv[i], "-c");
}
}
int option_char;
@ -172,38 +188,39 @@ int process_arguments(int argc, char **argv) {
while (1) {
option_char = getopt_long(argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, &option);
if (option_char == -1 || option_char == EOF)
if (option_char == -1 || option_char == EOF) {
break;
}
switch (option_char) {
case 'F': /* input file */
log_file = optarg;
result.config.log_file = optarg;
break;
case 'e': /* ups name */
expire_minutes = atoi(optarg);
result.config.expire_minutes = atoi(optarg);
break;
case 'a': /* port */
if (!strcmp(optarg, "MAX"))
use_average = false;
else
use_average = true;
result.config.use_average = (bool)(strcmp(optarg, "MAX"));
break;
case 'v':
variable_number = atoi(optarg);
if (variable_number < 1 || variable_number > 2)
result.config.variable_number = atoi(optarg);
if (result.config.variable_number < 1 || result.config.variable_number > 2) {
usage4(_("Invalid variable number"));
}
break;
case 'w': /* critical time threshold */
value_warning_threshold = strtoul(optarg, NULL, 10);
result.config.value_warning_threshold_set = true;
result.config.value_warning_threshold = strtoul(optarg, NULL, 10);
break;
case 'c': /* warning time threshold */
value_critical_threshold = strtoul(optarg, NULL, 10);
result.config.value_critical_threshold_set = true;
result.config.value_critical_threshold = strtoul(optarg, NULL, 10);
break;
case 'l': /* label */
label = optarg;
result.config.label = optarg;
break;
case 'u': /* timeout */
units = optarg;
result.config.units = optarg;
break;
case 'V': /* version */
print_revision(progname, NP_VERSION);
@ -217,63 +234,69 @@ int process_arguments(int argc, char **argv) {
}
option_char = optind;
if (log_file == NULL && argc > option_char) {
log_file = argv[option_char++];
if (result.config.log_file == NULL && argc > option_char) {
result.config.log_file = argv[option_char++];
}
if (expire_minutes <= 0 && argc > option_char) {
if (is_intpos(argv[option_char]))
expire_minutes = atoi(argv[option_char++]);
else
if (result.config.expire_minutes <= 0 && argc > option_char) {
if (is_intpos(argv[option_char])) {
result.config.expire_minutes = atoi(argv[option_char++]);
} else {
die(STATE_UNKNOWN, _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), argv[option_char], progname);
}
}
if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
use_average = false;
result.config.use_average = false;
option_char++;
} else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
use_average = true;
result.config.use_average = true;
option_char++;
}
if (argc > option_char && variable_number == -1) {
variable_number = atoi(argv[option_char++]);
if (variable_number < 1 || variable_number > 2) {
if (argc > option_char && result.config.variable_number == -1) {
result.config.variable_number = atoi(argv[option_char++]);
if (result.config.variable_number < 1 || result.config.variable_number > 2) {
printf("%s :", argv[option_char]);
usage(_("Invalid variable number\n"));
}
}
if (argc > option_char && value_warning_threshold == 0) {
value_warning_threshold = strtoul(argv[option_char++], NULL, 10);
if (argc > option_char && !result.config.value_warning_threshold_set) {
result.config.value_warning_threshold_set = true;
result.config.value_warning_threshold = strtoul(argv[option_char++], NULL, 10);
}
if (argc > option_char && value_critical_threshold == 0) {
value_critical_threshold = strtoul(argv[option_char++], NULL, 10);
if (argc > option_char && !result.config.value_critical_threshold_set) {
result.config.value_critical_threshold_set = true;
result.config.value_critical_threshold = strtoul(argv[option_char++], NULL, 10);
}
if (argc > option_char && strlen(label) == 0) {
label = argv[option_char++];
if (argc > option_char && strlen(result.config.label) == 0) {
result.config.label = argv[option_char++];
}
if (argc > option_char && strlen(units) == 0) {
units = argv[option_char++];
if (argc > option_char && strlen(result.config.units) == 0) {
result.config.units = argv[option_char++];
}
return validate_arguments();
return validate_arguments(result);
}
int validate_arguments(void) {
if (variable_number == -1)
check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper config_wrapper) {
if (config_wrapper.config.variable_number == -1) {
usage4(_("You must supply the variable number"));
}
if (label == NULL)
label = strdup("value");
if (config_wrapper.config.label == NULL) {
config_wrapper.config.label = strdup("value");
}
if (units == NULL)
units = strdup("");
if (config_wrapper.config.units == NULL) {
config_wrapper.config.units = strdup("");
}
return OK;
return config_wrapper;
}
void print_help(void) {

View file

@ -0,0 +1,36 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#include <stdlib.h>
typedef struct {
bool use_average;
int variable_number;
int expire_minutes;
char *label;
char *units;
char *log_file;
bool value_warning_threshold_set;
unsigned long value_warning_threshold;
bool value_critical_threshold_set;
unsigned long value_critical_threshold;
} check_mrtg_config;
check_mrtg_config check_mrtg_config_init() {
check_mrtg_config tmp = {
.use_average = true,
.variable_number = -1,
.expire_minutes = 0,
.label = NULL,
.units = NULL,
.log_file = NULL,
.value_warning_threshold_set = false,
.value_warning_threshold = 0,
.value_critical_threshold_set = false,
.value_critical_threshold = 0,
};
return tmp;
}

View file

@ -29,25 +29,23 @@
*
*****************************************************************************/
#include "common.h"
#include "utils.h"
const char *progname = "check_mrtgtraf";
const char *copyright = "1999-2024";
const char *email = "devel@monitoring-plugins.org";
static int process_arguments(int /*argc*/, char ** /*argv*/);
#include "check_mrtgtraf.d/config.h"
#include "common.h"
#include "utils.h"
typedef struct {
int errorcode;
check_mrtgtraf_config config;
} check_mrtgtraf_config_wrapper;
static check_mrtgtraf_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
static char *log_file = NULL;
static int expire_minutes = -1;
static bool use_average = true;
static unsigned long incoming_warning_threshold = 0L;
static unsigned long incoming_critical_threshold = 0L;
static unsigned long outgoing_warning_threshold = 0L;
static unsigned long outgoing_critical_threshold = 0L;
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
@ -56,13 +54,18 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_mrtgtraf_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_mrtgtraf_config config = tmp_config.config;
/* open the MRTG log file for reading */
FILE *mrtg_log_file_ptr = fopen(log_file, "r");
if (mrtg_log_file_ptr == NULL)
FILE *mrtg_log_file_ptr = fopen(config.log_file, "r");
if (mrtg_log_file_ptr == NULL) {
usage4(_("Unable to open MRTG log file"));
}
time_t timestamp = 0L;
char input_buffer[MAX_INPUT_BUFFER];
@ -76,13 +79,15 @@ int main(int argc, char **argv) {
line++;
/* skip the first line of the log file */
if (line == 1)
if (line == 1) {
continue;
}
/* break out of read loop */
/* if we've passed the number of entries we want to read */
if (line > 2)
if (line > 2) {
break;
}
/* grab the timestamp */
char *temp_buffer = strtok(input_buffer, " ");
@ -109,19 +114,21 @@ int main(int argc, char **argv) {
fclose(mrtg_log_file_ptr);
/* if we couldn't read enough data, return an unknown error */
if (line <= 2)
if (line <= 2) {
usage4(_("Unable to process MRTG log file"));
}
/* make sure the MRTG data isn't too old */
time_t current_time;
time(&current_time);
if ((expire_minutes > 0) && (current_time - timestamp) > (expire_minutes * 60))
if ((config.expire_minutes > 0) && (current_time - timestamp) > (config.expire_minutes * 60)) {
die(STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60));
}
unsigned long incoming_rate = 0L;
unsigned long outgoing_rate = 0L;
/* else check the incoming/outgoing rates */
if (use_average) {
if (config.use_average) {
incoming_rate = average_incoming_rate;
outgoing_rate = average_outgoing_rate;
} else {
@ -166,24 +173,26 @@ int main(int argc, char **argv) {
/* report outgoing traffic in MBytes/sec */
else {
strcpy(outgoing_speed_rating, "MB");
adjusted_outgoing_rate = (double)(outgoing_rate / 1024.0 / 1024.0);
adjusted_outgoing_rate = (outgoing_rate / 1024.0 / 1024.0);
}
int result = STATE_OK;
if (incoming_rate > incoming_critical_threshold || outgoing_rate > outgoing_critical_threshold) {
if (incoming_rate > config.incoming_critical_threshold || outgoing_rate > config.outgoing_critical_threshold) {
result = STATE_CRITICAL;
} else if (incoming_rate > incoming_warning_threshold || outgoing_rate > outgoing_warning_threshold) {
} else if (incoming_rate > config.incoming_warning_threshold || outgoing_rate > config.outgoing_warning_threshold) {
result = STATE_WARNING;
}
char *error_message;
xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), (use_average) ? _("Avg") : _("Max"),
adjusted_incoming_rate, incoming_speed_rating, (use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate,
xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), (config.use_average) ? _("Avg") : _("Max"),
adjusted_incoming_rate, incoming_speed_rating, (config.use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate,
outgoing_speed_rating,
fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, (int)incoming_warning_threshold, incoming_warning_threshold,
(int)incoming_critical_threshold, incoming_critical_threshold, true, 0, false, 0),
fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, (int)outgoing_warning_threshold, outgoing_warning_threshold,
(int)outgoing_critical_threshold, outgoing_critical_threshold, true, 0, false, 0));
fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, (int)config.incoming_warning_threshold,
config.incoming_warning_threshold, (int)config.incoming_critical_threshold, config.incoming_critical_threshold,
true, 0, false, 0),
fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, (int)config.outgoing_warning_threshold,
config.outgoing_warning_threshold, (int)config.outgoing_critical_threshold, config.outgoing_critical_threshold,
true, 0, false, 0));
printf(_("Traffic %s - %s\n"), state_text(result), error_message);
@ -191,7 +200,7 @@ int main(int argc, char **argv) {
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"filename", required_argument, 0, 'F'},
{"expires", required_argument, 0, 'e'},
{"aggregation", required_argument, 0, 'a'},
@ -201,44 +210,49 @@ int process_arguments(int argc, char **argv) {
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
if (argc < 2)
return ERROR;
check_mrtgtraf_config_wrapper result = {
.errorcode = OK,
.config = check_mrtgtraf_config_init(),
};
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
for (int i = 1; i < argc; i++) {
if (strcmp("-to", argv[i]) == 0)
if (strcmp("-to", argv[i]) == 0) {
strcpy(argv[i], "-t");
else if (strcmp("-wt", argv[i]) == 0)
} else if (strcmp("-wt", argv[i]) == 0) {
strcpy(argv[i], "-w");
else if (strcmp("-ct", argv[i]) == 0)
} else if (strcmp("-ct", argv[i]) == 0) {
strcpy(argv[i], "-c");
}
}
int option_char;
int option = 0;
while (1) {
while (true) {
option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option);
if (option_char == -1 || option_char == EOF)
if (option_char == -1 || option_char == EOF) {
break;
}
switch (option_char) {
case 'F': /* input file */
log_file = optarg;
result.config.log_file = optarg;
break;
case 'e': /* expiration time */
expire_minutes = atoi(optarg);
result.config.expire_minutes = atoi(optarg);
break;
case 'a': /* aggregation (AVE or MAX) */
if (!strcmp(optarg, "MAX"))
use_average = false;
else
use_average = true;
result.config.use_average = (bool)(strcmp(optarg, "MAX"));
break;
case 'c': /* warning threshold */
sscanf(optarg, "%lu,%lu", &incoming_critical_threshold, &outgoing_critical_threshold);
sscanf(optarg, "%lu,%lu", &result.config.incoming_critical_threshold, &result.config.outgoing_critical_threshold);
break;
case 'w': /* critical threshold */
sscanf(optarg, "%lu,%lu", &incoming_warning_threshold, &outgoing_warning_threshold);
sscanf(optarg, "%lu,%lu", &result.config.incoming_warning_threshold, &result.config.outgoing_warning_threshold);
break;
case 'V': /* version */
print_revision(progname, NP_VERSION);
@ -252,39 +266,39 @@ int process_arguments(int argc, char **argv) {
}
option_char = optind;
if (argc > option_char && log_file == NULL) {
log_file = argv[option_char++];
if (argc > option_char && result.config.log_file == NULL) {
result.config.log_file = argv[option_char++];
}
if (argc > option_char && expire_minutes == -1) {
expire_minutes = atoi(argv[option_char++]);
if (argc > option_char && result.config.expire_minutes == -1) {
result.config.expire_minutes = atoi(argv[option_char++]);
}
if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
use_average = false;
result.config.use_average = false;
option_char++;
} else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
use_average = true;
result.config.use_average = true;
option_char++;
}
if (argc > option_char && incoming_warning_threshold == 0) {
incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10);
if (argc > option_char && result.config.incoming_warning_threshold == 0) {
result.config.incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10);
}
if (argc > option_char && incoming_critical_threshold == 0) {
incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10);
if (argc > option_char && result.config.incoming_critical_threshold == 0) {
result.config.incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10);
}
if (argc > option_char && outgoing_warning_threshold == 0) {
outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10);
if (argc > option_char && result.config.outgoing_warning_threshold == 0) {
result.config.outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10);
}
if (argc > option_char && outgoing_critical_threshold == 0) {
outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10);
if (argc > option_char && result.config.outgoing_critical_threshold == 0) {
result.config.outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10);
}
return OK;
return result;
}
void print_help(void) {

View file

@ -0,0 +1,30 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#include <stdlib.h>
typedef struct {
char *log_file;
int expire_minutes;
bool use_average;
unsigned long incoming_warning_threshold;
unsigned long incoming_critical_threshold;
unsigned long outgoing_warning_threshold;
unsigned long outgoing_critical_threshold;
} check_mrtgtraf_config;
check_mrtgtraf_config check_mrtgtraf_config_init() {
check_mrtgtraf_config tmp = {
.log_file = NULL,
.expire_minutes = -1,
.use_average = true,
.incoming_warning_threshold = 0,
.incoming_critical_threshold = 0,
.outgoing_warning_threshold = 0,
.outgoing_critical_threshold = 0,
};
return tmp;
}

View file

@ -40,32 +40,14 @@ const char *email = "devel@monitoring-plugins.org";
#include "utils.h"
#include "utils_base.h"
#include "netutils.h"
#include "check_mysql.d/config.h"
#include <mysql.h>
#include <mysqld_error.h>
#include <errmsg.h>
static char *db_user = NULL;
static char *db_host = NULL;
static char *db_socket = NULL;
static char *db_pass = NULL;
static char *db = NULL;
static char *ca_cert = NULL;
static char *ca_dir = NULL;
static char *cert = NULL;
static char *key = NULL;
static char *ciphers = NULL;
static bool ssl = false;
static char *opt_file = NULL;
static char *opt_group = NULL;
static unsigned int db_port = MYSQL_PORT;
static bool check_replica = false;
static bool ignore_auth = false;
static int verbose = 0;
static double warning_time = 0;
static double critical_time = 0;
#define LENGTH_METRIC_UNIT 6
static const char *metric_unit[LENGTH_METRIC_UNIT] = {
"Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", "Threads_connected", "Threads_running"};
@ -78,28 +60,16 @@ static const char *metric_counter[LENGTH_METRIC_COUNTER] = {
#define MYSQLDUMP_THREADS_QUERY \
"SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'"
static thresholds *my_threshold = NULL;
static int process_arguments(int, char **);
static int validate_arguments(void);
typedef struct {
int errorcode;
check_mysql_config config;
} check_mysql_config_wrapper;
static check_mysql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper /*config_wrapper*/);
static void print_help(void);
void print_usage(void);
int main(int argc, char **argv) {
MYSQL mysql;
MYSQL_RES *res;
MYSQL_ROW row;
/* should be status */
char *result = NULL;
char *error = NULL;
char replica_result[REPLICA_RESULTSIZE] = {0};
char *perf;
perf = strdup("");
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -107,36 +77,43 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR) {
check_mysql_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_mysql_config config = tmp_config.config;
MYSQL mysql;
/* initialize mysql */
mysql_init(&mysql);
if (opt_file != NULL) {
mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, opt_file);
if (config.opt_file != NULL) {
mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
}
if (opt_group != NULL) {
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, opt_group);
if (config.opt_group != NULL) {
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
} else {
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
}
if (ssl) {
mysql_ssl_set(&mysql, key, cert, ca_cert, ca_dir, ciphers);
if (config.ssl) {
mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, config.ciphers);
}
/* establish a connection to the server and error checking */
if (!mysql_real_connect(&mysql, db_host, db_user, db_pass, db, db_port, db_socket, 0)) {
if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) {
/* Depending on internally-selected auth plugin MySQL might return */
/* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
/* Semantically these errors are the same. */
if (ignore_auth && (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
if (config.ignore_auth &&
(mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql));
mysql_close(&mysql);
return STATE_OK;
} else if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
}
if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
die(STATE_WARNING, "%s\n", mysql_error(&mysql));
} else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
die(STATE_WARNING, "%s\n", mysql_error(&mysql));
@ -152,7 +129,7 @@ int main(int argc, char **argv) {
}
/* get the server stats */
result = strdup(mysql_stat(&mysql));
char *result = strdup(mysql_stat(&mysql));
/* error checking once more */
if (mysql_error(&mysql)) {
@ -165,6 +142,10 @@ int main(int argc, char **argv) {
}
}
char *perf = strdup("");
char *error = NULL;
MYSQL_RES *res;
MYSQL_ROW row;
/* try to fetch some perf data */
if (mysql_query(&mysql, "show global status") == 0) {
if ((res = mysql_store_result(&mysql)) == NULL) {
@ -174,15 +155,13 @@ int main(int argc, char **argv) {
}
while ((row = mysql_fetch_row(res)) != NULL) {
int i;
for (i = 0; i < LENGTH_METRIC_UNIT; i++) {
for (int i = 0; i < LENGTH_METRIC_UNIT; i++) {
if (strcmp(row[0], metric_unit[i]) == 0) {
xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false, 0, false, 0));
continue;
}
}
for (i = 0; i < LENGTH_METRIC_COUNTER; i++) {
for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) {
if (strcmp(row[0], metric_counter[i]) == 0) {
xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0));
continue;
@ -195,8 +174,8 @@ int main(int argc, char **argv) {
}
}
if (check_replica) {
char replica_result[REPLICA_RESULTSIZE] = {0};
if (config.check_replica) {
// Detect which version we are, on older version
// "show slave status" should work, on newer ones
// "show replica status"
@ -283,12 +262,14 @@ int main(int argc, char **argv) {
} else {
/* mysql 4.x.x and mysql 5.x.x */
int replica_io_field = -1, replica_sql_field = -1, seconds_behind_field = -1, i, num_fields;
int replica_io_field = -1;
int replica_sql_field = -1;
int seconds_behind_field = -1;
int num_fields;
MYSQL_FIELD *fields;
num_fields = mysql_num_fields(res);
fields = mysql_fetch_fields(res);
for (i = 0; i < num_fields; i++) {
for (int i = 0; i < num_fields; i++) {
if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
replica_io_field = i;
continue;
@ -353,11 +334,11 @@ int main(int argc, char **argv) {
double value = atof(row[seconds_behind_field]);
int status;
status = get_status(value, my_threshold);
status = get_status(value, config.my_threshold);
xasprintf(&perf, "%s %s", perf,
fperfdata("seconds behind master", value, "s", true, (double)warning_time, true, (double)critical_time, false, 0,
false, 0));
fperfdata("seconds behind master", value, "s", true, (double)config.warning_time, true,
(double)config.critical_time, false, 0, false, 0));
if (status == STATE_WARNING) {
printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf);
@ -377,7 +358,7 @@ int main(int argc, char **argv) {
mysql_close(&mysql);
/* print out the result of stats */
if (check_replica) {
if (config.check_replica) {
printf("%s %s|%s\n", result, replica_result, perf);
} else {
printf("%s|%s\n", result, perf);
@ -389,12 +370,7 @@ int main(int argc, char **argv) {
#define CHECK_REPLICA_OPT CHAR_MAX + 1
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
char *warning = NULL;
char *critical = NULL;
int option = 0;
check_mysql_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
{"socket", required_argument, 0, 's'},
{"database", required_argument, 0, 'd'},
@ -419,56 +395,66 @@ int process_arguments(int argc, char **argv) {
{"ciphers", required_argument, 0, 'L'},
{0, 0, 0, 0}};
check_mysql_config_wrapper result = {
.errorcode = OK,
.config = check_mysql_config_init(),
};
if (argc < 1) {
return ERROR;
result.errorcode = ERROR;
return result;
}
while (1) {
c = getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
char *warning = NULL;
char *critical = NULL;
if (c == -1 || c == EOF) {
int option = 0;
while (true) {
int option_index = getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
if (option_index == -1 || option_index == EOF) {
break;
}
switch (c) {
switch (option_index) {
case 'H': /* hostname */
if (is_host(optarg)) {
db_host = optarg;
result.config.db_host = optarg;
} else if (*optarg == '/') {
db_socket = optarg;
result.config.db_socket = optarg;
} else {
usage2(_("Invalid hostname/address"), optarg);
}
break;
case 's': /* socket */
db_socket = optarg;
result.config.db_socket = optarg;
break;
case 'd': /* database */
db = optarg;
result.config.db = optarg;
break;
case 'l':
ssl = true;
result.config.ssl = true;
break;
case 'C':
ca_cert = optarg;
result.config.ca_cert = optarg;
break;
case 'a':
cert = optarg;
result.config.cert = optarg;
break;
case 'k':
key = optarg;
result.config.key = optarg;
break;
case 'D':
ca_dir = optarg;
result.config.ca_dir = optarg;
break;
case 'L':
ciphers = optarg;
result.config.ciphers = optarg;
break;
case 'u': /* username */
db_user = optarg;
result.config.db_user = optarg;
break;
case 'p': /* authentication information: password */
db_pass = strdup(optarg);
result.config.db_pass = strdup(optarg);
/* Delete the password from process list */
while (*optarg != '\0') {
@ -477,28 +463,28 @@ int process_arguments(int argc, char **argv) {
}
break;
case 'f': /* client options file */
opt_file = optarg;
result.config.opt_file = optarg;
break;
case 'g': /* client options group */
opt_group = optarg;
result.config.opt_group = optarg;
break;
case 'P': /* critical time threshold */
db_port = atoi(optarg);
result.config.db_port = atoi(optarg);
break;
case 'S':
case CHECK_REPLICA_OPT:
check_replica = true; /* check-slave */
result.config.check_replica = true; /* check-slave */
break;
case 'n':
ignore_auth = true; /* ignore-auth */
result.config.ignore_auth = true; /* ignore-auth */
break;
case 'w':
warning = optarg;
warning_time = strtod(warning, NULL);
result.config.warning_time = strtod(warning, NULL);
break;
case 'c':
critical = optarg;
critical_time = strtod(critical, NULL);
result.config.critical_time = strtod(critical, NULL);
break;
case 'V': /* version */
print_revision(progname, NP_VERSION);
@ -514,48 +500,47 @@ int process_arguments(int argc, char **argv) {
}
}
c = optind;
int index = optind;
set_thresholds(&my_threshold, warning, critical);
set_thresholds(&result.config.my_threshold, warning, critical);
while (argc > c) {
if (db_host == NULL) {
if (is_host(argv[c])) {
db_host = argv[c++];
while (argc > index) {
if (result.config.db_host == NULL) {
if (is_host(argv[index])) {
result.config.db_host = argv[index++];
} else {
usage2(_("Invalid hostname/address"), argv[c]);
usage2(_("Invalid hostname/address"), argv[index]);
}
} else if (db_user == NULL) {
db_user = argv[c++];
} else if (db_pass == NULL) {
db_pass = argv[c++];
} else if (db == NULL) {
db = argv[c++];
} else if (is_intnonneg(argv[c])) {
db_port = atoi(argv[c++]);
} else if (result.config.db_user == NULL) {
result.config.db_user = argv[index++];
} else if (result.config.db_pass == NULL) {
result.config.db_pass = argv[index++];
} else if (result.config.db == NULL) {
result.config.db = argv[index++];
} else if (is_intnonneg(argv[index])) {
result.config.db_port = atoi(argv[index++]);
} else {
break;
}
}
return validate_arguments();
return validate_arguments(result);
}
int validate_arguments(void) {
if (db_user == NULL) {
db_user = strdup("");
check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper config_wrapper) {
if (config_wrapper.config.db_user == NULL) {
config_wrapper.config.db_user = strdup("");
}
if (db_host == NULL) {
db_host = strdup("");
if (config_wrapper.config.db_host == NULL) {
config_wrapper.config.db_host = strdup("");
}
if (db == NULL) {
db = strdup("");
if (config_wrapper.config.db == NULL) {
config_wrapper.config.db = strdup("");
}
return OK;
return config_wrapper;
}
void print_help(void) {

View file

@ -0,0 +1,58 @@
#pragma once
#include "../../config.h"
#include "thresholds.h"
#include <stddef.h>
#include <mysql.h>
typedef struct {
char *db_host;
unsigned int db_port;
char *db_user;
char *db_socket;
char *db_pass;
char *db;
char *ca_cert;
char *ca_dir;
char *cert;
char *key;
char *ciphers;
bool ssl;
char *opt_file;
char *opt_group;
bool check_replica;
bool ignore_auth;
double warning_time;
double critical_time;
thresholds *my_threshold;
} check_mysql_config;
check_mysql_config check_mysql_config_init() {
check_mysql_config tmp = {
.db_host = NULL,
.db_port = MYSQL_PORT,
.db = NULL,
.db_pass = NULL,
.db_socket = NULL,
.db_user = NULL,
.ca_cert = NULL,
.ca_dir = NULL,
.cert = NULL,
.key = NULL,
.ciphers = NULL,
.ssl = false,
.opt_file = NULL,
.opt_group = NULL,
.check_replica = false,
.ignore_auth = false,
.warning_time = 0,
.critical_time = 0,
.my_threshold = NULL,
};
return tmp;
}

View file

@ -37,27 +37,21 @@ const char *email = "devel@monitoring-plugins.org";
#include "utils.h"
#include "utils_base.h"
#include "netutils.h"
#include "check_mysql_query.d/config.h"
#include <mysql.h>
#include <errmsg.h>
static char *db_user = NULL;
static char *db_host = NULL;
static char *db_socket = NULL;
static char *db_pass = NULL;
static char *db = NULL;
static char *opt_file = NULL;
static char *opt_group = NULL;
static unsigned int db_port = MYSQL_PORT;
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int validate_arguments(void);
typedef struct {
int errorcode;
check_mysql_query_config config;
} check_mysql_query_config_wrapper;
static check_mysql_query_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper /*config_wrapper*/);
static void print_help(void);
void print_usage(void);
static char *sql_query = NULL;
static int verbose = 0;
static thresholds *my_thresholds = NULL;
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
@ -67,39 +61,46 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_mysql_query_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_mysql_query_config config = tmp_config.config;
MYSQL mysql;
/* initialize mysql */
mysql_init(&mysql);
if (opt_file != NULL)
mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, opt_file);
if (config.opt_file != NULL) {
mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
}
if (opt_group != NULL)
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, opt_group);
else
if (config.opt_group != NULL) {
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
} else {
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
}
/* establish a connection to the server and error checking */
if (!mysql_real_connect(&mysql, db_host, db_user, db_pass, db, db_port, db_socket, 0)) {
if (mysql_errno(&mysql) == CR_UNKNOWN_HOST)
if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) {
if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
else if (mysql_errno(&mysql) == CR_VERSION_ERROR)
} else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY)
} else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR)
} else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR)
} else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
else
} else {
die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql));
}
}
char *error = NULL;
if (mysql_query(&mysql, sql_query) != 0) {
if (mysql_query(&mysql, config.sql_query) != 0) {
error = strdup(mysql_error(&mysql));
mysql_close(&mysql);
die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error);
@ -140,10 +141,11 @@ int main(int argc, char **argv) {
/* close the connection */
mysql_close(&mysql);
if (verbose >= 3)
if (verbose >= 3) {
printf("mysql result: %f\n", value);
}
int status = get_status(value, my_thresholds);
int status = get_status(value, config.my_thresholds);
if (status == STATE_OK) {
printf("QUERY %s: ", _("OK"));
@ -152,17 +154,16 @@ int main(int argc, char **argv) {
} else if (status == STATE_CRITICAL) {
printf("QUERY %s: ", _("CRITICAL"));
}
printf(_("'%s' returned %f | %s"), sql_query, value,
fperfdata("result", value, "", my_thresholds->warning ? true : false, my_thresholds->warning ? my_thresholds->warning->end : 0,
my_thresholds->critical ? true : false, my_thresholds->critical ? my_thresholds->critical->end : 0, false, 0, false,
0));
printf(_("'%s' returned %f | %s"), config.sql_query, value,
fperfdata("result", value, "", config.my_thresholds->warning, config.my_thresholds->warning ? config.my_thresholds->warning->end : 0,
config.my_thresholds->critical, config.my_thresholds->critical ? config.my_thresholds->critical->end : 0, false, 0, false, 0));
printf("\n");
return status;
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
check_mysql_query_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {
{"hostname", required_argument, 0, 'H'}, {"socket", required_argument, 0, 's'}, {"database", required_argument, 0, 'd'},
{"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'}, {"file", required_argument, 0, 'f'},
@ -170,8 +171,15 @@ int process_arguments(int argc, char **argv) {
{"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"query", required_argument, 0, 'q'},
{"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {0, 0, 0, 0}};
if (argc < 1)
return ERROR;
check_mysql_query_config_wrapper result = {
.errorcode = OK,
.config = check_mysql_query_config_init(),
};
if (argc < 1) {
result.errorcode = ERROR;
return result;
}
char *warning = NULL;
char *critical = NULL;
@ -180,28 +188,29 @@ int process_arguments(int argc, char **argv) {
int option = 0;
int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option);
if (option_char == -1 || option_char == EOF)
if (option_char == -1 || option_char == EOF) {
break;
}
switch (option_char) {
case 'H': /* hostname */
if (is_host(optarg)) {
db_host = optarg;
result.config.db_host = optarg;
} else {
usage2(_("Invalid hostname/address"), optarg);
}
break;
case 's': /* socket */
db_socket = optarg;
result.config.db_socket = optarg;
break;
case 'd': /* database */
db = optarg;
result.config.db = optarg;
break;
case 'u': /* username */
db_user = optarg;
result.config.db_user = optarg;
break;
case 'p': /* authentication information: password */
db_pass = strdup(optarg);
result.config.db_pass = strdup(optarg);
/* Delete the password from process list */
while (*optarg != '\0') {
@ -210,13 +219,13 @@ int process_arguments(int argc, char **argv) {
}
break;
case 'f': /* client options file */
opt_file = optarg;
result.config.opt_file = optarg;
break;
case 'g': /* client options group */
opt_group = optarg;
result.config.opt_group = optarg;
break;
case 'P': /* critical time threshold */
db_port = atoi(optarg);
result.config.db_port = atoi(optarg);
break;
case 'v':
verbose++;
@ -228,7 +237,7 @@ int process_arguments(int argc, char **argv) {
print_help();
exit(STATE_UNKNOWN);
case 'q':
xasprintf(&sql_query, "%s", optarg);
xasprintf(&result.config.sql_query, "%s", optarg);
break;
case 'w':
warning = optarg;
@ -241,25 +250,29 @@ int process_arguments(int argc, char **argv) {
}
}
set_thresholds(&my_thresholds, warning, critical);
set_thresholds(&result.config.my_thresholds, warning, critical);
return validate_arguments();
return validate_arguments(result);
}
int validate_arguments(void) {
if (sql_query == NULL)
check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper config_wrapper) {
if (config_wrapper.config.sql_query == NULL) {
usage("Must specify a SQL query to run");
}
if (db_user == NULL)
db_user = strdup("");
if (config_wrapper.config.db_user == NULL) {
config_wrapper.config.db_user = strdup("");
}
if (db_host == NULL)
db_host = strdup("");
if (config_wrapper.config.db_host == NULL) {
config_wrapper.config.db_host = strdup("");
}
if (db == NULL)
db = strdup("");
if (config_wrapper.config.db == NULL) {
config_wrapper.config.db = strdup("");
}
return OK;
return config_wrapper;
}
void print_help(void) {

View file

@ -0,0 +1,36 @@
#pragma once
#include "../../config.h"
#include "thresholds.h"
#include <mysql.h>
typedef struct {
char *db_host;
char *db_socket;
char *db;
char *db_user;
char *db_pass;
char *opt_file;
char *opt_group;
unsigned int db_port;
char *sql_query;
thresholds *my_thresholds;
} check_mysql_query_config;
check_mysql_query_config check_mysql_query_config_init() {
check_mysql_query_config tmp = {
.db_host = NULL,
.db_socket = NULL,
.db = NULL,
.db_user = NULL,
.db_pass = NULL,
.opt_file = NULL,
.opt_group = NULL,
.db_port = MYSQL_PORT,
.sql_query = NULL,
.my_thresholds = NULL,
};
return tmp;
}

View file

@ -39,47 +39,20 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "runcmd.h"
#include "utils.h"
#include "states.h"
#include "check_nagios.d/config.h"
static int process_arguments(int /*argc*/, char ** /*argv*/);
typedef struct {
int errorcode;
check_nagios_config config;
} check_nagios_config_wrapper;
static check_nagios_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
static char *status_log = NULL;
static char *process_string = NULL;
static int expire_minutes = 0;
static int verbose = 0;
int main(int argc, char **argv) {
int result = STATE_UNKNOWN;
char input_buffer[MAX_INPUT_BUFFER];
unsigned long latest_entry_time = 0L;
unsigned long temp_entry_time = 0L;
int proc_entries = 0;
time_t current_time;
char *temp_ptr;
FILE *fp;
int procuid = 0;
int procpid = 0;
int procppid = 0;
int procvsz = 0;
int procrss = 0;
float procpcpu = 0;
char procstat[8];
#ifdef PS_USES_PROCETIME
char procetime[MAX_INPUT_BUFFER];
#endif /* PS_USES_PROCETIME */
char procprog[MAX_INPUT_BUFFER];
char *procargs;
int pos;
int cols;
int expected_cols = PS_COLS - 1;
const char *zombie = "Z";
char *temp_string;
output chld_out;
output chld_err;
size_t i;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -87,8 +60,13 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_nagios_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage_va(_("Could not parse arguments"));
}
const check_nagios_config config = tmp_config.config;
/* Set signal handling and alarm timeout */
if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
@ -99,13 +77,17 @@ int main(int argc, char **argv) {
alarm(timeout_interval);
/* open the status log */
fp = fopen(status_log, "r");
if (fp == NULL) {
FILE *log_file = fopen(config.status_log, "r");
if (log_file == NULL) {
die(STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!"));
}
unsigned long latest_entry_time = 0L;
unsigned long temp_entry_time = 0L;
char input_buffer[MAX_INPUT_BUFFER];
char *temp_ptr;
/* get the date/time of the last item updated in the log */
while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, log_file)) {
if ((temp_ptr = strstr(input_buffer, "created=")) != NULL) {
temp_entry_time = strtoul(temp_ptr + 8, NULL, 10);
latest_entry_time = temp_entry_time;
@ -113,22 +95,44 @@ int main(int argc, char **argv) {
}
if ((temp_ptr = strtok(input_buffer, "]")) != NULL) {
temp_entry_time = strtoul(temp_ptr + 1, NULL, 10);
if (temp_entry_time > latest_entry_time)
if (temp_entry_time > latest_entry_time) {
latest_entry_time = temp_entry_time;
}
}
}
fclose(fp);
fclose(log_file);
if (verbose >= 2)
if (verbose >= 2) {
printf("command: %s\n", PS_COMMAND);
}
/* run the command to check for the Nagios process.. */
if ((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0)
mp_state_enum result = STATE_UNKNOWN;
output chld_out;
output chld_err;
if ((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0) {
result = STATE_WARNING;
}
int procuid = 0;
int procpid = 0;
int procppid = 0;
int procvsz = 0;
int procrss = 0;
int proc_entries = 0;
float procpcpu = 0;
char procstat[8];
char procprog[MAX_INPUT_BUFFER];
char *procargs;
#ifdef PS_USES_PROCETIME
char procetime[MAX_INPUT_BUFFER];
#endif /* PS_USES_PROCETIME */
int pos;
int expected_cols = PS_COLS - 1;
const char *zombie = "Z";
/* count the number of matching Nagios processes... */
for (i = 0; i < chld_out.lines; i++) {
cols = sscanf(chld_out.line[i], PS_FORMAT, PS_VARLIST);
for (size_t i = 0; i < chld_out.lines; i++) {
int cols = sscanf(chld_out.line[i], PS_FORMAT, PS_VARLIST);
/* Zombie processes do not give a procprog command */
if (cols == (expected_cols - 1) && strstr(procstat, zombie)) {
cols = expected_cols;
@ -142,14 +146,14 @@ int main(int argc, char **argv) {
strip(procargs);
/* Some ps return full pathname for command. This removes path */
temp_string = strtok((char *)procprog, "/");
char *temp_string = strtok((char *)procprog, "/");
while (temp_string) {
strcpy(procprog, temp_string);
temp_string = strtok(NULL, "/");
}
/* May get empty procargs */
if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs, "")) {
if (!strstr(procargs, argv[0]) && strstr(procargs, config.process_string) && strcmp(procargs, "")) {
proc_entries++;
if (verbose >= 2) {
printf(_("Found process: %s %s\n"), procprog, procargs);
@ -159,8 +163,9 @@ int main(int argc, char **argv) {
}
/* If we get anything on stderr, at least set warning */
if (chld_err.buflen)
if (chld_err.buflen) {
result = max_state(result, STATE_WARNING);
}
/* reset the alarm handler */
alarm(0);
@ -173,8 +178,9 @@ int main(int argc, char **argv) {
die(STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time"));
}
time_t current_time;
time(&current_time);
if ((int)(current_time - latest_entry_time) > (expire_minutes * 60)) {
if ((int)(current_time - latest_entry_time) > (config.expire_minutes * 60)) {
result = STATE_WARNING;
} else {
result = STATE_OK;
@ -187,39 +193,45 @@ int main(int argc, char **argv) {
(int)(current_time - latest_entry_time));
printf("\n");
return result;
exit(result);
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
int option = 0;
check_nagios_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'},
{"command", required_argument, 0, 'C'}, {"timeout", optional_argument, 0, 't'},
{"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0}};
if (argc < 2)
return ERROR;
if (!is_option(argv[1])) {
status_log = argv[1];
if (is_intnonneg(argv[2]))
expire_minutes = atoi(argv[2]);
else
die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
process_string = argv[3];
return OK;
check_nagios_config_wrapper result = {
.errorcode = OK,
.config = check_nagios_config_init(),
};
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
while (1) {
c = getopt_long(argc, argv, "+hVvF:C:e:t:", longopts, &option);
if (!is_option(argv[1])) {
result.config.status_log = argv[1];
if (is_intnonneg(argv[2])) {
result.config.expire_minutes = atoi(argv[2]);
} else {
die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
}
result.config.process_string = argv[3];
return result;
}
if (c == -1 || c == EOF || c == 1)
int option = 0;
while (true) {
int option_index = getopt_long(argc, argv, "+hVvF:C:e:t:", longopts, &option);
if (option_index == -1 || option_index == EOF || option_index == 1) {
break;
}
switch (c) {
switch (option_index) {
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
@ -227,22 +239,24 @@ int process_arguments(int argc, char **argv) {
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 'F': /* status log */
status_log = optarg;
result.config.status_log = optarg;
break;
case 'C': /* command */
process_string = optarg;
result.config.process_string = optarg;
break;
case 'e': /* expiry time */
if (is_intnonneg(optarg))
expire_minutes = atoi(optarg);
else
if (is_intnonneg(optarg)) {
result.config.expire_minutes = atoi(optarg);
} else {
die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
}
break;
case 't': /* timeout */
if (is_intnonneg(optarg))
if (is_intnonneg(optarg)) {
timeout_interval = atoi(optarg);
else
} else {
die(STATE_UNKNOWN, _("Timeout must be an integer (seconds)\n"));
}
break;
case 'v':
verbose++;
@ -252,13 +266,15 @@ int process_arguments(int argc, char **argv) {
}
}
if (status_log == NULL)
if (result.config.status_log == NULL) {
die(STATE_UNKNOWN, _("You must provide the status_log\n"));
}
if (process_string == NULL)
if (result.config.process_string == NULL) {
die(STATE_UNKNOWN, _("You must provide a process string\n"));
}
return OK;
return result;
}
void print_help(void) {

View file

@ -0,0 +1,19 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
typedef struct {
char *status_log;
char *process_string;
int expire_minutes;
} check_nagios_config;
check_nagios_config check_nagios_config_init() {
check_nagios_config tmp = {
.status_log = NULL,
.process_string = NULL,
.expire_minutes = 0,
};
return tmp;
}

View file

@ -13,7 +13,7 @@
* This plugin collects data from the NSClient service running on a
* Windows NT/2000/XP/2003 server.
* This plugin requires NSClient software to run on NT
* (http://nsclient.ready2run.nl/)
* (https://nsclient.org/)
*
*
* This program is free software: you can redistribute it and/or modify
@ -39,82 +39,28 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
enum checkvars {
CHECK_NONE,
CHECK_CLIENTVERSION,
CHECK_CPULOAD,
CHECK_UPTIME,
CHECK_USEDDISKSPACE,
CHECK_SERVICESTATE,
CHECK_PROCSTATE,
CHECK_MEMUSE,
CHECK_COUNTER,
CHECK_FILEAGE,
CHECK_INSTANCES
};
#include "check_nt.d/config.h"
enum {
MAX_VALUE_LIST = 30,
PORT = 1248
};
static char *server_address = NULL;
static int server_port = PORT;
static char *value_list = NULL;
static char *req_password = NULL;
static unsigned long lvalue_list[MAX_VALUE_LIST];
static unsigned long warning_value = 0L;
static unsigned long critical_value = 0L;
static bool check_warning_value = false;
static bool check_critical_value = false;
static enum checkvars vars_to_check = CHECK_NONE;
static bool show_all = false;
static char recv_buffer[MAX_INPUT_BUFFER];
static void fetch_data(const char *address, int port, const char *sendb);
static int process_arguments(int /*argc*/, char ** /*argv*/);
typedef struct {
int errorcode;
check_nt_config config;
} check_nt_config_wrapper;
static check_nt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void preparelist(char *string);
static bool strtoularray(unsigned long *array, char *string, const char *delim);
static void print_help(void);
void print_usage(void);
int main(int argc, char **argv) {
/* should be int result = STATE_UNKNOWN; */
int return_code = STATE_UNKNOWN;
char *send_buffer = NULL;
char *output_message = NULL;
char *perfdata = NULL;
char *temp_string = NULL;
char *temp_string_perf = NULL;
char *description = NULL, *counter_unit = NULL;
char *minval = NULL, *maxval = NULL, *errcvt = NULL;
char *fds = NULL, *tds = NULL;
char *numstr;
double total_disk_space = 0;
double free_disk_space = 0;
double percent_used_space = 0;
double warning_used_space = 0;
double critical_used_space = 0;
double mem_commitLimit = 0;
double mem_commitByte = 0;
double fminval = 0, fmaxval = 0;
unsigned long utilization;
unsigned long uptime;
unsigned long age_in_minutes;
double counter_value = 0.0;
int offset = 0;
int updays = 0;
int uphours = 0;
int upminutes = 0;
bool isPercent = false;
bool allRight = false;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -122,8 +68,12 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_nt_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_nt_config config = tmp_config.config;
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
@ -131,49 +81,57 @@ int main(int argc, char **argv) {
/* set socket timeout */
alarm(socket_timeout);
switch (vars_to_check) {
int return_code = STATE_UNKNOWN;
char *send_buffer = NULL;
char *output_message = NULL;
char *perfdata = NULL;
char *temp_string = NULL;
char *temp_string_perf = NULL;
char *description = NULL;
char *counter_unit = NULL;
char *errcvt = NULL;
unsigned long lvalue_list[MAX_VALUE_LIST];
switch (config.vars_to_check) {
case CHECK_CLIENTVERSION:
xasprintf(&send_buffer, "%s&1", req_password);
fetch_data(server_address, server_port, send_buffer);
if (value_list != NULL && strcmp(recv_buffer, value_list) != 0) {
xasprintf(&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, value_list);
xasprintf(&send_buffer, "%s&1", config.req_password);
fetch_data(config.server_address, config.server_port, send_buffer);
if (config.value_list != NULL && strcmp(recv_buffer, config.value_list) != 0) {
xasprintf(&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, config.value_list);
return_code = STATE_WARNING;
} else {
xasprintf(&output_message, "%s", recv_buffer);
return_code = STATE_OK;
}
break;
case CHECK_CPULOAD:
if (value_list == NULL)
if (config.value_list == NULL) {
output_message = strdup(_("missing -l parameters"));
else if (!strtoularray(lvalue_list, value_list, ","))
} else if (!strtoularray(lvalue_list, config.value_list, ",")) {
output_message = strdup(_("wrong -l parameter."));
else {
} else {
/* -l parameters is present with only integers */
return_code = STATE_OK;
temp_string = strdup(_("CPU Load"));
temp_string_perf = strdup(" ");
/* loop until one of the parameters is wrong or not present */
int offset = 0;
while (lvalue_list[0 + offset] > (unsigned long)0 && lvalue_list[0 + offset] <= (unsigned long)17280 &&
lvalue_list[1 + offset] > (unsigned long)0 && lvalue_list[1 + offset] <= (unsigned long)100 &&
lvalue_list[2 + offset] > (unsigned long)0 && lvalue_list[2 + offset] <= (unsigned long)100) {
/* Send request and retrieve data */
xasprintf(&send_buffer, "%s&2&%lu", req_password, lvalue_list[0 + offset]);
fetch_data(server_address, server_port, send_buffer);
xasprintf(&send_buffer, "%s&2&%lu", config.req_password, lvalue_list[0 + offset]);
fetch_data(config.server_address, config.server_port, send_buffer);
utilization = strtoul(recv_buffer, NULL, 10);
unsigned long utilization = strtoul(recv_buffer, NULL, 10);
/* Check if any of the request is in a warning or critical state */
if (utilization >= lvalue_list[2 + offset])
if (utilization >= lvalue_list[2 + offset]) {
return_code = STATE_CRITICAL;
else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING)
} else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) {
return_code = STATE_WARNING;
}
xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization, lvalue_list[0 + offset]);
xasprintf(&temp_string, "%s%s", temp_string, output_message);
@ -186,82 +144,87 @@ int main(int argc, char **argv) {
if (strlen(temp_string) > 10) { /* we had at least one loop */
output_message = strdup(temp_string);
perfdata = temp_string_perf;
} else
} else {
output_message = strdup(_("not enough values for -l parameters"));
}
}
break;
case CHECK_UPTIME:
if (value_list == NULL) {
value_list = "minutes";
case CHECK_UPTIME: {
char *tmp_value_list = config.value_list;
if (config.value_list == NULL) {
tmp_value_list = "minutes";
}
if (strncmp(value_list, "seconds", strlen("seconds") + 1) && strncmp(value_list, "minutes", strlen("minutes") + 1) &&
strncmp(value_list, "hours", strlen("hours") + 1) && strncmp(value_list, "days", strlen("days") + 1)) {
if (strncmp(tmp_value_list, "seconds", strlen("seconds") + 1) && strncmp(tmp_value_list, "minutes", strlen("minutes") + 1) &&
strncmp(config.value_list, "hours", strlen("hours") + 1) && strncmp(tmp_value_list, "days", strlen("days") + 1)) {
output_message = strdup(_("wrong -l argument"));
} else {
xasprintf(&send_buffer, "%s&3", req_password);
fetch_data(server_address, server_port, send_buffer);
uptime = strtoul(recv_buffer, NULL, 10);
updays = uptime / 86400;
uphours = (uptime % 86400) / 3600;
upminutes = ((uptime % 86400) % 3600) / 60;
xasprintf(&send_buffer, "%s&3", config.req_password);
fetch_data(config.server_address, config.server_port, send_buffer);
unsigned long uptime = strtoul(recv_buffer, NULL, 10);
int updays = uptime / 86400;
int uphours = (uptime % 86400) / 3600;
int upminutes = ((uptime % 86400) % 3600) / 60;
if (!strncmp(value_list, "minutes", strlen("minutes")))
if (!strncmp(tmp_value_list, "minutes", strlen("minutes"))) {
uptime = uptime / 60;
else if (!strncmp(value_list, "hours", strlen("hours")))
} else if (!strncmp(tmp_value_list, "hours", strlen("hours"))) {
uptime = uptime / 3600;
else if (!strncmp(value_list, "days", strlen("days")))
} else if (!strncmp(tmp_value_list, "days", strlen("days"))) {
uptime = uptime / 86400;
}
/* else uptime in seconds, nothing to do */
xasprintf(&output_message, _("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays, uphours, upminutes,
uptime);
if (check_critical_value && uptime <= critical_value)
if (config.check_critical_value && uptime <= config.critical_value) {
return_code = STATE_CRITICAL;
else if (check_warning_value && uptime <= warning_value)
} else if (config.check_warning_value && uptime <= config.warning_value) {
return_code = STATE_WARNING;
else
} else {
return_code = STATE_OK;
}
}
break;
} break;
case CHECK_USEDDISKSPACE:
if (value_list == NULL)
if (config.value_list == NULL) {
output_message = strdup(_("missing -l parameters"));
else if (strlen(value_list) != 1)
} else if (strlen(config.value_list) != 1) {
output_message = strdup(_("wrong -l argument"));
else {
xasprintf(&send_buffer, "%s&4&%s", req_password, value_list);
fetch_data(server_address, server_port, send_buffer);
fds = strtok(recv_buffer, "&");
tds = strtok(NULL, "&");
if (fds != NULL)
} else {
xasprintf(&send_buffer, "%s&4&%s", config.req_password, config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
char *fds = strtok(recv_buffer, "&");
char *tds = strtok(NULL, "&");
double total_disk_space = 0;
double free_disk_space = 0;
if (fds != NULL) {
free_disk_space = atof(fds);
if (tds != NULL)
}
if (tds != NULL) {
total_disk_space = atof(tds);
}
if (total_disk_space > 0 && free_disk_space >= 0) {
percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100;
warning_used_space = ((float)warning_value / 100) * total_disk_space;
critical_used_space = ((float)critical_value / 100) * total_disk_space;
double percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100;
double warning_used_space = ((float)config.warning_value / 100) * total_disk_space;
double critical_used_space = ((float)config.critical_value / 100) * total_disk_space;
xasprintf(&temp_string, _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), value_list,
xasprintf(&temp_string, _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), config.value_list,
total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, percent_used_space,
free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100);
xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), value_list,
xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), config.value_list,
(total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824,
critical_used_space / 1073741824, total_disk_space / 1073741824);
if (check_critical_value && percent_used_space >= critical_value)
if (config.check_critical_value && percent_used_space >= config.critical_value) {
return_code = STATE_CRITICAL;
else if (check_warning_value && percent_used_space >= warning_value)
} else if (config.check_warning_value && percent_used_space >= config.warning_value) {
return_code = STATE_WARNING;
else
} else {
return_code = STATE_OK;
}
output_message = strdup(temp_string);
perfdata = temp_string_perf;
@ -271,41 +234,40 @@ int main(int argc, char **argv) {
}
}
break;
case CHECK_SERVICESTATE:
case CHECK_PROCSTATE:
if (value_list == NULL)
if (config.value_list == NULL) {
output_message = strdup(_("No service/process specified"));
else {
preparelist(value_list); /* replace , between services with & to send the request */
xasprintf(&send_buffer, "%s&%u&%s&%s", req_password, (vars_to_check == CHECK_SERVICESTATE) ? 5 : 6,
(show_all) ? "ShowAll" : "ShowFail", value_list);
fetch_data(server_address, server_port, send_buffer);
numstr = strtok(recv_buffer, "&");
if (numstr == NULL)
} else {
preparelist(config.value_list); /* replace , between services with & to send the request */
xasprintf(&send_buffer, "%s&%u&%s&%s", config.req_password, (config.vars_to_check == CHECK_SERVICESTATE) ? 5 : 6,
(config.show_all) ? "ShowAll" : "ShowFail", config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
char *numstr = strtok(recv_buffer, "&");
if (numstr == NULL) {
die(STATE_UNKNOWN, _("could not fetch information from server\n"));
}
return_code = atoi(numstr);
temp_string = strtok(NULL, "&");
output_message = strdup(temp_string);
}
break;
case CHECK_MEMUSE:
xasprintf(&send_buffer, "%s&7", req_password);
fetch_data(server_address, server_port, send_buffer);
numstr = strtok(recv_buffer, "&");
if (numstr == NULL)
xasprintf(&send_buffer, "%s&7", config.req_password);
fetch_data(config.server_address, config.server_port, send_buffer);
char *numstr = strtok(recv_buffer, "&");
if (numstr == NULL) {
die(STATE_UNKNOWN, _("could not fetch information from server\n"));
mem_commitLimit = atof(numstr);
}
double mem_commitLimit = atof(numstr);
numstr = strtok(NULL, "&");
if (numstr == NULL)
if (numstr == NULL) {
die(STATE_UNKNOWN, _("could not fetch information from server\n"));
mem_commitByte = atof(numstr);
percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
warning_used_space = ((float)warning_value / 100) * mem_commitLimit;
critical_used_space = ((float)critical_value / 100) * mem_commitLimit;
}
double mem_commitByte = atof(numstr);
double percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
double warning_used_space = ((float)config.warning_value / 100) * mem_commitLimit;
double critical_used_space = ((float)config.critical_value / 100) * mem_commitLimit;
/* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here,
which equals RAM + Pagefiles. */
@ -316,15 +278,14 @@ int main(int argc, char **argv) {
critical_used_space / 1048567, mem_commitLimit / 1048567);
return_code = STATE_OK;
if (check_critical_value && percent_used_space >= critical_value)
if (config.check_critical_value && percent_used_space >= config.critical_value) {
return_code = STATE_CRITICAL;
else if (check_warning_value && percent_used_space >= warning_value)
} else if (config.check_warning_value && percent_used_space >= config.warning_value) {
return_code = STATE_WARNING;
}
break;
case CHECK_COUNTER:
case CHECK_COUNTER: {
/*
CHECK_COUNTER has been modified to provide extensive perfdata information.
In order to do this, some modifications have been done to the code
@ -346,26 +307,32 @@ int main(int argc, char **argv) {
strange things will happen when you make graphs of your data.
*/
if (value_list == NULL)
double counter_value = 0.0;
if (config.value_list == NULL) {
output_message = strdup(_("No counter specified"));
else {
preparelist(value_list); /* replace , between services with & to send the request */
isPercent = (strchr(value_list, '%') != NULL);
} else {
preparelist(config.value_list); /* replace , between services with & to send the request */
bool isPercent = (strchr(config.value_list, '%') != NULL);
strtok(value_list, "&"); /* burn the first parameters */
strtok(config.value_list, "&"); /* burn the first parameters */
description = strtok(NULL, "&");
counter_unit = strtok(NULL, "&");
xasprintf(&send_buffer, "%s&8&%s", req_password, value_list);
fetch_data(server_address, server_port, send_buffer);
xasprintf(&send_buffer, "%s&8&%s", config.req_password, config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
counter_value = atof(recv_buffer);
if (description == NULL)
bool allRight = false;
if (description == NULL) {
xasprintf(&output_message, "%.f", counter_value);
else if (isPercent) {
} else if (isPercent) {
counter_unit = strdup("%");
allRight = true;
}
char *minval = NULL;
char *maxval = NULL;
double fminval = 0;
double fmaxval = 0;
if ((counter_unit != NULL) && (!allRight)) {
minval = strtok(NULL, "&");
maxval = strtok(NULL, "&");
@ -375,16 +342,18 @@ int main(int argc, char **argv) {
fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1;
fmaxval = (minval != NULL) ? strtod(maxval, &errcvt) : -1;
if ((fminval == 0) && (minval == errcvt))
if ((fminval == 0) && (minval == errcvt)) {
output_message = strdup(_("Minimum value contains non-numbers"));
else {
if ((fmaxval == 0) && (maxval == errcvt))
} else {
if ((fmaxval == 0) && (maxval == errcvt)) {
output_message = strdup(_("Maximum value contains non-numbers"));
else
} else {
allRight = true; /* Everything is OK. */
}
}
} else if ((counter_unit == NULL) && (description != NULL))
} else if ((counter_unit == NULL) && (description != NULL)) {
output_message = strdup(_("No unit counter specified"));
}
if (allRight) {
/* Let's format the output string, finally... */
@ -396,63 +365,65 @@ int main(int argc, char **argv) {
}
xasprintf(&output_message, "%s |", output_message);
xasprintf(&output_message, "%s %s", output_message,
fperfdata(description, counter_value, counter_unit, 1, warning_value, 1, critical_value,
fperfdata(description, counter_value, counter_unit, 1, config.warning_value, 1, config.critical_value,
(!(isPercent) && (minval != NULL)), fminval, (!(isPercent) && (minval != NULL)), fmaxval));
}
}
if (critical_value > warning_value) { /* Normal thresholds */
if (check_critical_value && counter_value >= critical_value)
if (config.critical_value > config.warning_value) { /* Normal thresholds */
if (config.check_critical_value && counter_value >= config.critical_value) {
return_code = STATE_CRITICAL;
else if (check_warning_value && counter_value >= warning_value)
} else if (config.check_warning_value && counter_value >= config.warning_value) {
return_code = STATE_WARNING;
else
} else {
return_code = STATE_OK;
}
} else { /* inverse thresholds */
return_code = STATE_OK;
if (check_critical_value && counter_value <= critical_value)
if (config.check_critical_value && counter_value <= config.critical_value) {
return_code = STATE_CRITICAL;
else if (check_warning_value && counter_value <= warning_value)
} else if (config.check_warning_value && counter_value <= config.warning_value) {
return_code = STATE_WARNING;
}
}
break;
} break;
case CHECK_FILEAGE:
if (value_list == NULL)
if (config.value_list == NULL) {
output_message = strdup(_("No counter specified"));
else {
preparelist(value_list); /* replace , between services with & to send the request */
xasprintf(&send_buffer, "%s&9&%s", req_password, value_list);
fetch_data(server_address, server_port, send_buffer);
age_in_minutes = atoi(strtok(recv_buffer, "&"));
} else {
preparelist(config.value_list); /* replace , between services with & to send the request */
xasprintf(&send_buffer, "%s&9&%s", config.req_password, config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
unsigned long age_in_minutes = atoi(strtok(recv_buffer, "&"));
description = strtok(NULL, "&");
output_message = strdup(description);
if (critical_value > warning_value) { /* Normal thresholds */
if (check_critical_value && age_in_minutes >= critical_value)
if (config.critical_value > config.warning_value) { /* Normal thresholds */
if (config.check_critical_value && age_in_minutes >= config.critical_value) {
return_code = STATE_CRITICAL;
else if (check_warning_value && age_in_minutes >= warning_value)
} else if (config.check_warning_value && age_in_minutes >= config.warning_value) {
return_code = STATE_WARNING;
else
} else {
return_code = STATE_OK;
}
} else { /* inverse thresholds */
if (check_critical_value && age_in_minutes <= critical_value)
if (config.check_critical_value && age_in_minutes <= config.critical_value) {
return_code = STATE_CRITICAL;
else if (check_warning_value && age_in_minutes <= warning_value)
} else if (config.check_warning_value && age_in_minutes <= config.warning_value) {
return_code = STATE_WARNING;
else
} else {
return_code = STATE_OK;
}
}
}
break;
case CHECK_INSTANCES:
if (value_list == NULL)
if (config.value_list == NULL) {
output_message = strdup(_("No counter specified"));
else {
xasprintf(&send_buffer, "%s&10&%s", req_password, value_list);
fetch_data(server_address, server_port, send_buffer);
} else {
xasprintf(&send_buffer, "%s&10&%s", config.req_password, config.value_list);
fetch_data(config.server_address, config.server_port, send_buffer);
if (!strncmp(recv_buffer, "ERROR", 5)) {
printf("NSClient - %s\n", recv_buffer);
exit(STATE_UNKNOWN);
@ -471,18 +442,16 @@ int main(int argc, char **argv) {
/* reset timeout */
alarm(0);
if (perfdata == NULL)
if (perfdata == NULL) {
printf("%s\n", output_message);
else
} else {
printf("%s | %s\n", output_message, perfdata);
}
return return_code;
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
int option = 0;
check_nt_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"port", required_argument, 0, 'p'},
{"timeout", required_argument, 0, 't'},
{"critical", required_argument, 0, 'c'},
@ -497,34 +466,44 @@ int process_arguments(int argc, char **argv) {
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
check_nt_config_wrapper result = {
.errorcode = OK,
.config = check_nt_config_init(),
};
/* no options were supplied */
if (argc < 2)
return ERROR;
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
/* backwards compatibility */
if (!is_option(argv[1])) {
server_address = strdup(argv[1]);
result.config.server_address = strdup(argv[1]);
argv[1] = argv[0];
argv = &argv[1];
argc--;
}
for (c = 1; c < argc; c++) {
if (strcmp("-to", argv[c]) == 0)
strcpy(argv[c], "-t");
else if (strcmp("-wv", argv[c]) == 0)
strcpy(argv[c], "-w");
else if (strcmp("-cv", argv[c]) == 0)
strcpy(argv[c], "-c");
for (int index = 1; index < argc; index++) {
if (strcmp("-to", argv[index]) == 0) {
strcpy(argv[index], "-t");
} else if (strcmp("-wv", argv[index]) == 0) {
strcpy(argv[index], "-w");
} else if (strcmp("-cv", argv[index]) == 0) {
strcpy(argv[index], "-c");
}
}
while (1) {
c = getopt_long(argc, argv, "+hVH:t:c:w:p:v:l:s:d:u", longopts, &option);
int option = 0;
while (true) {
int option_index = getopt_long(argc, argv, "+hVH:t:c:w:p:v:l:s:d:u", longopts, &option);
if (c == -1 || c == EOF || c == 1)
if (option_index == -1 || option_index == EOF || option_index == 1) {
break;
}
switch (c) {
switch (option_index) {
case '?': /* print short usage statement if args not parsable */
usage5();
case 'h': /* help */
@ -534,118 +513,128 @@ int process_arguments(int argc, char **argv) {
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 'H': /* hostname */
server_address = optarg;
result.config.server_address = optarg;
break;
case 's': /* password */
req_password = optarg;
result.config.req_password = optarg;
break;
case 'p': /* port */
if (is_intnonneg(optarg))
server_port = atoi(optarg);
else
if (is_intnonneg(optarg)) {
result.config.server_port = atoi(optarg);
} else {
die(STATE_UNKNOWN, _("Server port must be an integer\n"));
}
break;
case 'v':
if (strlen(optarg) < 4)
return ERROR;
if (!strcmp(optarg, "CLIENTVERSION"))
vars_to_check = CHECK_CLIENTVERSION;
else if (!strcmp(optarg, "CPULOAD"))
vars_to_check = CHECK_CPULOAD;
else if (!strcmp(optarg, "UPTIME"))
vars_to_check = CHECK_UPTIME;
else if (!strcmp(optarg, "USEDDISKSPACE"))
vars_to_check = CHECK_USEDDISKSPACE;
else if (!strcmp(optarg, "SERVICESTATE"))
vars_to_check = CHECK_SERVICESTATE;
else if (!strcmp(optarg, "PROCSTATE"))
vars_to_check = CHECK_PROCSTATE;
else if (!strcmp(optarg, "MEMUSE"))
vars_to_check = CHECK_MEMUSE;
else if (!strcmp(optarg, "COUNTER"))
vars_to_check = CHECK_COUNTER;
else if (!strcmp(optarg, "FILEAGE"))
vars_to_check = CHECK_FILEAGE;
else if (!strcmp(optarg, "INSTANCES"))
vars_to_check = CHECK_INSTANCES;
else
return ERROR;
if (strlen(optarg) < 4) {
result.errorcode = ERROR;
return result;
}
if (!strcmp(optarg, "CLIENTVERSION")) {
result.config.vars_to_check = CHECK_CLIENTVERSION;
} else if (!strcmp(optarg, "CPULOAD")) {
result.config.vars_to_check = CHECK_CPULOAD;
} else if (!strcmp(optarg, "UPTIME")) {
result.config.vars_to_check = CHECK_UPTIME;
} else if (!strcmp(optarg, "USEDDISKSPACE")) {
result.config.vars_to_check = CHECK_USEDDISKSPACE;
} else if (!strcmp(optarg, "SERVICESTATE")) {
result.config.vars_to_check = CHECK_SERVICESTATE;
} else if (!strcmp(optarg, "PROCSTATE")) {
result.config.vars_to_check = CHECK_PROCSTATE;
} else if (!strcmp(optarg, "MEMUSE")) {
result.config.vars_to_check = CHECK_MEMUSE;
} else if (!strcmp(optarg, "COUNTER")) {
result.config.vars_to_check = CHECK_COUNTER;
} else if (!strcmp(optarg, "FILEAGE")) {
result.config.vars_to_check = CHECK_FILEAGE;
} else if (!strcmp(optarg, "INSTANCES")) {
result.config.vars_to_check = CHECK_INSTANCES;
} else {
result.errorcode = ERROR;
return result;
}
break;
case 'l': /* value list */
value_list = optarg;
result.config.value_list = optarg;
break;
case 'w': /* warning threshold */
warning_value = strtoul(optarg, NULL, 10);
check_warning_value = true;
result.config.warning_value = strtoul(optarg, NULL, 10);
result.config.check_warning_value = true;
break;
case 'c': /* critical threshold */
critical_value = strtoul(optarg, NULL, 10);
check_critical_value = true;
result.config.critical_value = strtoul(optarg, NULL, 10);
result.config.check_critical_value = true;
break;
case 'd': /* Display select for services */
if (!strcmp(optarg, "SHOWALL"))
show_all = true;
if (!strcmp(optarg, "SHOWALL")) {
result.config.show_all = true;
}
break;
case 'u':
socket_timeout_state = STATE_UNKNOWN;
break;
case 't': /* timeout */
socket_timeout = atoi(optarg);
if (socket_timeout <= 0)
return ERROR;
if (socket_timeout <= 0) {
result.errorcode = ERROR;
return result;
}
}
}
if (server_address == NULL)
if (result.config.server_address == NULL) {
usage4(_("You must provide a server address or host name"));
}
if (vars_to_check == CHECK_NONE)
return ERROR;
if (result.config.vars_to_check == CHECK_NONE) {
result.errorcode = ERROR;
return result;
}
if (req_password == NULL)
req_password = strdup(_("None"));
if (result.config.req_password == NULL) {
result.config.req_password = strdup(_("None"));
}
return OK;
return result;
}
void fetch_data(const char *address, int port, const char *sendb) {
int result;
int result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer));
result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer));
if (result != STATE_OK)
if (result != STATE_OK) {
die(result, _("could not fetch information from server\n"));
}
if (!strncmp(recv_buffer, "ERROR", 5))
if (!strncmp(recv_buffer, "ERROR", 5)) {
die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer);
}
}
bool strtoularray(unsigned long *array, char *string, const char *delim) {
/* split a <delim> delimited string into a long array */
int idx = 0;
char *t1;
for (idx = 0; idx < MAX_VALUE_LIST; idx++)
for (int idx = 0; idx < MAX_VALUE_LIST; idx++) {
array[idx] = 0;
}
idx = 0;
for (t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) {
int idx = 0;
for (char *t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) {
if (is_numeric(t1) && idx < MAX_VALUE_LIST) {
array[idx] = strtoul(t1, NULL, 10);
idx++;
} else
} else {
return false;
}
}
return true;
}
void preparelist(char *string) {
/* Replace all , with & which is the delimiter for the request */
int i;
for (i = 0; (size_t)i < strlen(string); i++)
for (int i = 0; (size_t)i < strlen(string); i++) {
if (string[i] == ',') {
string[i] = '&';
}
}
}
void print_help(void) {

View file

@ -0,0 +1,53 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
enum {
PORT = 1248,
};
enum checkvars {
CHECK_NONE,
CHECK_CLIENTVERSION,
CHECK_CPULOAD,
CHECK_UPTIME,
CHECK_USEDDISKSPACE,
CHECK_SERVICESTATE,
CHECK_PROCSTATE,
CHECK_MEMUSE,
CHECK_COUNTER,
CHECK_FILEAGE,
CHECK_INSTANCES
};
typedef struct {
char *server_address;
int server_port;
char *req_password;
enum checkvars vars_to_check;
bool show_all;
char *value_list;
bool check_warning_value;
unsigned long warning_value;
bool check_critical_value;
unsigned long critical_value;
} check_nt_config;
check_nt_config check_nt_config_init() {
check_nt_config tmp = {
.server_address = NULL,
.server_port = PORT,
.req_password = NULL,
.vars_to_check = CHECK_NONE,
.show_all = false,
.value_list = NULL,
.check_warning_value = false,
.warning_value = 0,
.check_critical_value = false,
.critical_value = 0,
};
return tmp;
}

View file

@ -35,6 +35,7 @@
*
*****************************************************************************/
#include "thresholds.h"
const char *progname = "check_ntp_peer";
const char *copyright = "2006-2024";
const char *email = "devel@monitoring-plugins.org";
@ -42,30 +43,18 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
#include "../lib/states.h"
#include "check_ntp_peer.d/config.h"
static char *server_address = NULL;
static int port = 123;
static int verbose = 0;
static bool quiet = false;
static char *owarn = "60";
static char *ocrit = "120";
static bool do_stratum = false;
static char *swarn = "-1:16";
static char *scrit = "-1:16";
static bool do_jitter = false;
static char *jwarn = "-1:5000";
static char *jcrit = "-1:10000";
static bool do_truechimers = false;
static char *twarn = "0:";
static char *tcrit = "0:";
static bool syncsource_found = false;
static bool li_alarm = false;
static int process_arguments(int /*argc*/, char ** /*argv*/);
static thresholds *offset_thresholds = NULL;
static thresholds *jitter_thresholds = NULL;
static thresholds *stratum_thresholds = NULL;
static thresholds *truechimer_thresholds = NULL;
typedef struct {
int errorcode;
check_ntp_peer_config config;
} check_ntp_peer_config_wrapper;
static check_ntp_peer_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
@ -157,25 +146,25 @@ typedef struct {
printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
} while (0);
void print_ntp_control_message(const ntp_control_message *p) {
void print_ntp_control_message(const ntp_control_message *message) {
printf("control packet contents:\n");
printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op);
printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK);
printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags & VN_MASK);
printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags & MODE_MASK);
printf("\t response=%d (0x%.2x)\n", (p->op & REM_RESP) > 0, p->op & REM_RESP);
printf("\t more=%d (0x%.2x)\n", (p->op & REM_MORE) > 0, p->op & REM_MORE);
printf("\t error=%d (0x%.2x)\n", (p->op & REM_ERROR) > 0, p->op & REM_ERROR);
printf("\t op=%d (0x%.2x)\n", p->op & OP_MASK, p->op & OP_MASK);
printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq));
printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status));
printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc));
printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset));
printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count));
printf("\tflags: 0x%.2x , 0x%.2x\n", message->flags, message->op);
printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
printf("\t response=%d (0x%.2x)\n", (message->op & REM_RESP) > 0, message->op & REM_RESP);
printf("\t more=%d (0x%.2x)\n", (message->op & REM_MORE) > 0, message->op & REM_MORE);
printf("\t error=%d (0x%.2x)\n", (message->op & REM_ERROR) > 0, message->op & REM_ERROR);
printf("\t op=%d (0x%.2x)\n", message->op & OP_MASK, message->op & OP_MASK);
printf("\tsequence: %d (0x%.2x)\n", ntohs(message->seq), ntohs(message->seq));
printf("\tstatus: %d (0x%.2x)\n", ntohs(message->status), ntohs(message->status));
printf("\tassoc: %d (0x%.2x)\n", ntohs(message->assoc), ntohs(message->assoc));
printf("\toffset: %d (0x%.2x)\n", ntohs(message->offset), ntohs(message->offset));
printf("\tcount: %d (0x%.2x)\n", ntohs(message->count), ntohs(message->count));
int numpeers = ntohs(p->count) / (sizeof(ntp_assoc_status_pair));
if (p->op & REM_RESP && p->op & OP_READSTAT) {
const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)p->data;
int numpeers = ntohs(message->count) / (sizeof(ntp_assoc_status_pair));
if (message->op & REM_RESP && message->op & OP_READSTAT) {
const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)message->data;
for (int i = 0; i < numpeers; i++) {
printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status));
if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) {
@ -190,13 +179,13 @@ void print_ntp_control_message(const ntp_control_message *p) {
}
}
void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq) {
memset(p, 0, sizeof(ntp_control_message));
LI_SET(p->flags, LI_NOWARNING);
VN_SET(p->flags, VN_RESERVED);
MODE_SET(p->flags, MODE_CONTROLMSG);
OP_SET(p->op, opcode);
p->seq = htons(seq);
void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_t seq) {
memset(message, 0, sizeof(ntp_control_message));
LI_SET(message->flags, LI_NOWARNING);
VN_SET(message->flags, VN_RESERVED);
MODE_SET(message->flags, MODE_CONTROLMSG);
OP_SET(message->op, opcode);
message->seq = htons(seq);
/* Remaining fields are zero for requests */
}
@ -211,10 +200,23 @@ void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq)
* status is pretty much useless as syncsource_found is a global variable
* used later in main to check is the server was synchronized. It works
* so I left it alone */
int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers) {
*offset_result = STATE_UNKNOWN;
*jitter = *stratum = -1;
*num_truechimers = 0;
typedef struct {
mp_state_enum state;
mp_state_enum offset_result;
double offset;
double jitter;
long stratum;
int num_truechimers;
} ntp_request_result;
ntp_request_result ntp_request(const check_ntp_peer_config config) {
ntp_request_result result = {
.state = STATE_OK,
.offset_result = STATE_UNKNOWN,
.jitter = -1,
.stratum = -1,
.num_truechimers = 0,
};
/* Long-winded explanation:
* Getting the sync peer offset, jitter and stratum requires a number of
@ -237,10 +239,10 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
void *tmp;
ntp_assoc_status_pair *peers = NULL;
int peer_offset = 0;
int peers_size = 0;
int npeers = 0;
size_t peers_size = 0;
size_t npeers = 0;
int conn = -1;
my_udp_connect(server_address, port, &conn);
my_udp_connect(config.server_address, config.port, &conn);
/* keep sending requests until the server stops setting the
* REM_MORE bit, though usually this is only 1 packet. */
@ -255,24 +257,28 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
/* Attempt to read the largest size packet possible */
req.count = htons(MAX_CM_SIZE);
DBG(printf("receiving READSTAT response"))
if (read(conn, &req, SIZEOF_NTPCM(req)) == -1)
if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) {
die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
}
DBG(print_ntp_control_message(&req));
/* discard obviously invalid packets */
if (ntohs(req.count) > MAX_CM_SIZE)
if (ntohs(req.count) > MAX_CM_SIZE) {
die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n");
}
} while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
if (LI(req.flags) == LI_ALARM)
if (LI(req.flags) == LI_ALARM) {
li_alarm = true;
}
/* Each peer identifier is 4 bytes in the data section, which
* we represent as a ntp_assoc_status_pair datatype.
*/
peers_size += ntohs(req.count);
if ((tmp = realloc(peers, peers_size)) == NULL)
if ((tmp = realloc(peers, peers_size)) == NULL) {
free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
}
peers = tmp;
memcpy((void *)((ptrdiff_t)peers + peer_offset), (void *)req.data, ntohs(req.count));
memcpy((peers + peer_offset), (void *)req.data, ntohs(req.count));
npeers = peers_size / sizeof(ntp_assoc_status_pair);
peer_offset += ntohs(req.count);
} while (req.op & REM_MORE);
@ -280,9 +286,9 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
/* first, let's find out if we have a sync source, or if there are
* at least some candidates. In the latter case we'll issue
* a warning but go ahead with the check on them. */
for (int i = 0; i < npeers; i++) {
for (size_t i = 0; i < npeers; i++) {
if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
(*num_truechimers)++;
result.num_truechimers++;
if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
num_candidates++;
if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
@ -293,31 +299,35 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
}
}
if (verbose)
if (verbose) {
printf("%d candidate peers available\n", num_candidates);
if (verbose && syncsource_found)
}
if (verbose && syncsource_found) {
printf("synchronization source found\n");
}
int status = STATE_OK;
if (!syncsource_found) {
status = STATE_WARNING;
if (verbose)
result.state = STATE_WARNING;
if (verbose) {
printf("warning: no synchronization source found\n");
}
}
if (li_alarm) {
status = STATE_WARNING;
if (verbose)
result.state = STATE_WARNING;
if (verbose) {
printf("warning: LI_ALARM bit is set\n");
}
}
const char *getvar = "stratum,offset,jitter";
char *data;
for (int i = 0; i < npeers; i++) {
for (size_t i = 0; i < npeers; i++) {
/* Only query this server if it is the current sync source */
/* If there's no sync.peer, query all candidates and use the best one */
if (PEER_SEL(peers[i].status) >= min_peer_sel) {
if (verbose)
if (verbose) {
printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
}
xasprintf(&data, "");
do {
setup_control_request(&req, OP_READVAR, 2);
@ -342,60 +352,68 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
DBG(print_ntp_control_message(&req));
} while (!(req.op & OP_READVAR && ntohs(req.seq) == 2));
if (!(req.op & REM_ERROR))
if (!(req.op & REM_ERROR)) {
xasprintf(&data, "%s%s", data, req.data);
}
} while (req.op & REM_MORE);
if (req.op & REM_ERROR) {
if (strstr(getvar, "jitter")) {
if (verbose)
if (verbose) {
printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with "
"'dispersion'...\n");
}
getvar = "stratum,offset,dispersion";
i--;
continue;
}
if (strlen(getvar)) {
if (verbose)
if (verbose) {
printf("Server didn't like dispersion either; will retrieve everything\n");
}
getvar = "";
i--;
continue;
}
}
if (verbose > 1)
if (verbose > 1) {
printf("Server responded: >>>%s<<<\n", data);
}
double tmp_offset = 0;
char *value;
char *nptr;
/* get the offset */
if (verbose)
if (verbose) {
printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));
}
value = np_extract_ntpvar(data, "offset");
nptr = NULL;
/* Convert the value if we have one */
if (value != NULL)
if (value != NULL) {
tmp_offset = strtod(value, &nptr) / 1000;
}
/* If value is null or no conversion was performed */
if (value == NULL || value == nptr) {
if (verbose)
if (verbose) {
printf("error: unable to read server offset response.\n");
}
} else {
if (verbose)
if (verbose) {
printf("%.10g\n", tmp_offset);
if (*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) {
*offset = tmp_offset;
*offset_result = STATE_OK;
}
if (result.offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(result.offset)) {
result.offset = tmp_offset;
result.offset_result = STATE_OK;
} else {
/* Skip this one; move to the next */
continue;
}
}
if (do_jitter) {
if (config.do_jitter) {
/* get the jitter */
if (verbose) {
printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter",
@ -404,19 +422,21 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter");
nptr = NULL;
/* Convert the value if we have one */
if (value != NULL)
*jitter = strtod(value, &nptr);
if (value != NULL) {
result.jitter = strtod(value, &nptr);
}
/* If value is null or no conversion was performed */
if (value == NULL || value == nptr) {
if (verbose)
if (verbose) {
printf("error: unable to read server jitter/dispersion response.\n");
*jitter = -1;
}
result.jitter = -1;
} else if (verbose) {
printf("%.10g\n", *jitter);
printf("%.10g\n", result.jitter);
}
}
if (do_stratum) {
if (config.do_stratum) {
/* get the stratum */
if (verbose) {
printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
@ -424,28 +444,32 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
value = np_extract_ntpvar(data, "stratum");
nptr = NULL;
/* Convert the value if we have one */
if (value != NULL)
*stratum = strtol(value, &nptr, 10);
if (value != NULL) {
result.stratum = strtol(value, &nptr, 10);
}
if (value == NULL || value == nptr) {
if (verbose)
if (verbose) {
printf("error: unable to read server stratum response.\n");
*stratum = -1;
}
result.stratum = -1;
} else {
if (verbose)
printf("%i\n", *stratum);
if (verbose) {
printf("%li\n", result.stratum);
}
}
}
} /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
} /* for (i = 0; i < npeers; i++) */
} /* for (i = 0; i < npeers; i++) */
close(conn);
if (peers != NULL)
if (peers != NULL) {
free(peers);
}
return status;
return result;
}
int process_arguments(int argc, char **argv) {
check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {
{"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'},
{"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'},
@ -454,14 +478,21 @@ int process_arguments(int argc, char **argv) {
{"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'},
{"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}};
if (argc < 2)
if (argc < 2) {
usage("\n");
}
check_ntp_peer_config_wrapper result = {
.errorcode = OK,
.config = check_ntp_peer_config_init(),
};
while (true) {
int option = 0;
int option_char = getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option);
if (option_char == -1 || option_char == EOF || option_char == 1)
if (option_char == -1 || option_char == EOF || option_char == 1) {
break;
}
switch (option_char) {
case 'h':
@ -476,45 +507,46 @@ int process_arguments(int argc, char **argv) {
verbose++;
break;
case 'q':
quiet = true;
result.config.quiet = true;
break;
case 'w':
owarn = optarg;
result.config.owarn = optarg;
break;
case 'c':
ocrit = optarg;
result.config.ocrit = optarg;
break;
case 'W':
do_stratum = true;
swarn = optarg;
result.config.do_stratum = true;
result.config.swarn = optarg;
break;
case 'C':
do_stratum = true;
scrit = optarg;
result.config.do_stratum = true;
result.config.scrit = optarg;
break;
case 'j':
do_jitter = true;
jwarn = optarg;
result.config.do_jitter = true;
result.config.jwarn = optarg;
break;
case 'k':
do_jitter = true;
jcrit = optarg;
result.config.do_jitter = true;
result.config.jcrit = optarg;
break;
case 'm':
do_truechimers = true;
twarn = optarg;
result.config.do_truechimers = true;
result.config.twarn = optarg;
break;
case 'n':
do_truechimers = true;
tcrit = optarg;
result.config.do_truechimers = true;
result.config.tcrit = optarg;
break;
case 'H':
if (!is_host(optarg))
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
server_address = strdup(optarg);
}
result.config.server_address = strdup(optarg);
break;
case 'p':
port = atoi(optarg);
result.config.port = atoi(optarg);
break;
case 't':
socket_timeout = atoi(optarg);
@ -536,29 +568,34 @@ int process_arguments(int argc, char **argv) {
}
}
if (server_address == NULL) {
if (result.config.server_address == NULL) {
usage4(_("Hostname was not supplied"));
}
return 0;
set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit);
set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit);
set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit);
return result;
}
char *perfd_offset(double offset) {
char *perfd_offset(double offset, thresholds *offset_thresholds) {
return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
0);
}
char *perfd_jitter(double jitter) {
char *perfd_jitter(double jitter, bool do_jitter, thresholds *jitter_thresholds) {
return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter, jitter_thresholds->critical->end, true, 0,
false, 0);
}
char *perfd_stratum(int stratum) {
char *perfd_stratum(int stratum, bool do_stratum, thresholds *stratum_thresholds) {
return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end, do_stratum,
(int)stratum_thresholds->critical->end, true, 0, true, 16);
}
char *perfd_truechimers(int num_truechimers) {
char *perfd_truechimers(int num_truechimers, const bool do_truechimers, thresholds *truechimer_thresholds) {
return perfdata("truechimers", num_truechimers, "", do_truechimers, (int)truechimer_thresholds->warning->end, do_truechimers,
(int)truechimer_thresholds->critical->end, true, 0, false, 0);
}
@ -571,13 +608,13 @@ int main(int argc, char *argv[]) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
usage4(_("Could not parse arguments"));
check_ntp_peer_config_wrapper tmp_config = process_arguments(argc, argv);
set_thresholds(&offset_thresholds, owarn, ocrit);
set_thresholds(&jitter_thresholds, jwarn, jcrit);
set_thresholds(&stratum_thresholds, swarn, scrit);
set_thresholds(&truechimer_thresholds, twarn, tcrit);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_ntp_peer_config config = tmp_config.config;
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
@ -585,44 +622,40 @@ int main(int argc, char *argv[]) {
/* set socket timeout */
alarm(socket_timeout);
int offset_result;
int stratum;
int num_truechimers;
double offset = 0;
double jitter = 0;
/* This returns either OK or WARNING (See comment preceding ntp_request) */
int result = ntp_request(&offset, &offset_result, &jitter, &stratum, &num_truechimers);
ntp_request_result ntp_res = ntp_request(config);
mp_state_enum result = STATE_UNKNOWN;
if (offset_result == STATE_UNKNOWN) {
if (ntp_res.offset_result == STATE_UNKNOWN) {
/* if there's no sync peer (this overrides ntp_request output): */
result = (quiet ? STATE_UNKNOWN : STATE_CRITICAL);
result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL);
} else {
/* Be quiet if there's no candidates either */
if (quiet && result == STATE_WARNING)
if (config.quiet && result == STATE_WARNING) {
result = STATE_UNKNOWN;
result = max_state_alt(result, get_status(fabs(offset), offset_thresholds));
}
result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds));
}
int oresult = result;
mp_state_enum oresult = result;
mp_state_enum tresult = STATE_UNKNOWN;
int tresult = STATE_UNKNOWN;
if (do_truechimers) {
tresult = get_status(num_truechimers, truechimer_thresholds);
if (config.do_truechimers) {
tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds);
result = max_state_alt(result, tresult);
}
int sresult = STATE_UNKNOWN;
mp_state_enum sresult = STATE_UNKNOWN;
if (do_stratum) {
sresult = get_status(stratum, stratum_thresholds);
if (config.do_stratum) {
sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds);
result = max_state_alt(result, sresult);
}
int jresult = STATE_UNKNOWN;
mp_state_enum jresult = STATE_UNKNOWN;
if (do_jitter) {
jresult = get_status(jitter, jitter_thresholds);
if (config.do_jitter) {
jresult = get_status(ntp_res.jitter, config.jitter_thresholds);
result = max_state_alt(result, jresult);
}
@ -641,59 +674,67 @@ int main(int argc, char *argv[]) {
xasprintf(&result_line, _("NTP UNKNOWN:"));
break;
}
if (!syncsource_found)
if (!syncsource_found) {
xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
else if (li_alarm)
} else if (li_alarm) {
xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));
}
char *perfdata_line;
if (offset_result == STATE_UNKNOWN) {
if (ntp_res.offset_result == STATE_UNKNOWN) {
xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
xasprintf(&perfdata_line, "");
} else if (oresult == STATE_WARNING) {
xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), offset);
xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), ntp_res.offset);
} else if (oresult == STATE_CRITICAL) {
xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), offset);
xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), ntp_res.offset);
} else {
xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset);
}
xasprintf(&perfdata_line, "%s", perfd_offset(offset));
xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
if (do_jitter) {
if (config.do_jitter) {
if (jresult == STATE_WARNING) {
xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter);
xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter);
} else if (jresult == STATE_CRITICAL) {
xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter);
xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
} else {
xasprintf(&result_line, "%s, jitter=%f", result_line, jitter);
xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
}
xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter));
xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds));
}
if (do_stratum) {
if (config.do_stratum) {
if (sresult == STATE_WARNING) {
xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum);
xasprintf(&result_line, "%s, stratum=%l (WARNING)", result_line, ntp_res.stratum);
} else if (sresult == STATE_CRITICAL) {
xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum);
xasprintf(&result_line, "%s, stratum=%l (CRITICAL)", result_line, ntp_res.stratum);
} else {
xasprintf(&result_line, "%s, stratum=%i", result_line, stratum);
xasprintf(&result_line, "%s, stratum=%l", result_line, ntp_res.stratum);
}
xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum));
xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds));
}
if (do_truechimers) {
if (config.do_truechimers) {
if (tresult == STATE_WARNING) {
xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, num_truechimers);
xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, ntp_res.num_truechimers);
} else if (tresult == STATE_CRITICAL) {
xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, num_truechimers);
xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, ntp_res.num_truechimers);
} else {
xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers);
xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
}
xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers));
xasprintf(&perfdata_line, "%s %s", perfdata_line,
perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers, config.truechimer_thresholds));
}
printf("%s|%s\n", result_line, perfdata_line);
if (server_address != NULL)
free(server_address);
return result;
if (config.server_address != NULL) {
free(config.server_address);
}
exit(result);
}
void print_help(void) {

View file

@ -0,0 +1,67 @@
#pragma once
#include "../../config.h"
#include "thresholds.h"
#include <stddef.h>
enum {
DEFAULT_NTP_PORT = 123,
};
typedef struct {
char *server_address;
int port;
bool quiet;
// truechimer stuff
bool do_truechimers;
char *twarn;
char *tcrit;
thresholds *truechimer_thresholds;
char *owarn;
char *ocrit;
thresholds *offset_thresholds;
// stratum stuff
bool do_stratum;
char *swarn;
char *scrit;
thresholds *stratum_thresholds;
// jitter stuff
bool do_jitter;
char *jwarn;
char *jcrit;
thresholds *jitter_thresholds;
} check_ntp_peer_config;
check_ntp_peer_config check_ntp_peer_config_init() {
check_ntp_peer_config tmp = {
.server_address = NULL,
.port = DEFAULT_NTP_PORT,
.quiet = false,
.do_truechimers = false,
.twarn = "0:",
.tcrit = "0:",
.truechimer_thresholds = NULL,
.owarn = "60",
.ocrit = "120",
.offset_thresholds = NULL,
.do_stratum = false,
.swarn = "-1:16",
.scrit = "-1:16",
.stratum_thresholds = NULL,
.do_jitter = false,
.jwarn = "-1:5000",
.jcrit = "-1:10000",
.jitter_thresholds = NULL,
};
return tmp;
}

View file

@ -41,17 +41,18 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
#include "states.h"
#include "thresholds.h"
#include "check_ntp_time.d/config.h"
static char *server_address = NULL;
static char *port = "123";
static int verbose = 0;
static bool quiet = false;
static char *owarn = "60";
static char *ocrit = "120";
static int time_offset = 0;
static int process_arguments(int, char **);
static thresholds *offset_thresholds = NULL;
typedef struct {
int errorcode;
check_ntp_time_config config;
} check_ntp_time_config_wrapper;
static check_ntp_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
@ -159,7 +160,7 @@ typedef struct {
#define EPOCHDIFF 0x83aa7e80UL
/* extract a 32-bit ntp fixed point number into a double */
#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x)) / 65536.0)
#define NTP32asDOUBLE(x) (ntohs(L16(x)) + ((double)ntohs(R16(x)) / 65536.0))
/* likewise for a 64-bit ntp fp number */
#define NTP64asDOUBLE(n) \
@ -208,56 +209,52 @@ typedef struct {
} while (0);
/* calculate the offset of the local clock */
static inline double calc_offset(const ntp_message *m, const struct timeval *t) {
double client_tx = NTP64asDOUBLE(m->origts);
double peer_rx = NTP64asDOUBLE(m->rxts);
double peer_tx = NTP64asDOUBLE(m->txts);
double client_rx = TVasDOUBLE((*t));
return (.5 * ((peer_tx - client_rx) + (peer_rx - client_tx)));
static inline double calc_offset(const ntp_message *message, const struct timeval *time_value) {
double client_tx = NTP64asDOUBLE(message->origts);
double peer_rx = NTP64asDOUBLE(message->rxts);
double peer_tx = NTP64asDOUBLE(message->txts);
double client_rx = TVasDOUBLE((*time_value));
return (((peer_tx - client_rx) + (peer_rx - client_tx)) / 2);
}
/* print out a ntp packet in human readable/debuggable format */
void print_ntp_message(const ntp_message *p) {
void print_ntp_message(const ntp_message *message) {
struct timeval ref;
struct timeval orig;
struct timeval rx;
struct timeval tx;
NTP64toTV(p->refts, ref);
NTP64toTV(p->origts, orig);
NTP64toTV(p->rxts, rx);
NTP64toTV(p->txts, tx);
NTP64toTV(message->refts, ref);
NTP64toTV(message->origts, orig);
printf("packet contents:\n");
printf("\tflags: 0x%.2x\n", p->flags);
printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK);
printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags & VN_MASK);
printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags & MODE_MASK);
printf("\tstratum = %d\n", p->stratum);
printf("\tpoll = %g\n", pow(2, p->poll));
printf("\tprecision = %g\n", pow(2, p->precision));
printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay));
printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp));
printf("\trefid = %x\n", p->refid);
printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts));
printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts));
printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts));
printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts));
printf("\tflags: 0x%.2x\n", message->flags);
printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
printf("\tstratum = %d\n", message->stratum);
printf("\tpoll = %g\n", pow(2, message->poll));
printf("\tprecision = %g\n", pow(2, message->precision));
printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(message->rtdelay));
printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(message->rtdisp));
printf("\trefid = %x\n", message->refid);
printf("\trefts = %-.16g\n", NTP64asDOUBLE(message->refts));
printf("\torigts = %-.16g\n", NTP64asDOUBLE(message->origts));
printf("\trxts = %-.16g\n", NTP64asDOUBLE(message->rxts));
printf("\ttxts = %-.16g\n", NTP64asDOUBLE(message->txts));
}
void setup_request(ntp_message *p) {
memset(p, 0, sizeof(ntp_message));
LI_SET(p->flags, LI_ALARM);
VN_SET(p->flags, 4);
MODE_SET(p->flags, MODE_CLIENT);
p->poll = 4;
p->precision = (int8_t)0xfa;
L16(p->rtdelay) = htons(1);
L16(p->rtdisp) = htons(1);
void setup_request(ntp_message *message) {
memset(message, 0, sizeof(ntp_message));
LI_SET(message->flags, LI_ALARM);
VN_SET(message->flags, 4);
MODE_SET(message->flags, MODE_CLIENT);
message->poll = 4;
message->precision = (int8_t)0xfa;
L16(message->rtdelay) = htons(1);
L16(message->rtdisp) = htons(1);
struct timeval t;
gettimeofday(&t, NULL);
TVtoNTP64(t, p->txts);
TVtoNTP64(t, message->txts);
}
/* select the "best" server from a list of servers, and return its index.
@ -273,14 +270,16 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
* stratum 0 is for reference clocks so no NTP server should ever report
* a stratum 0 */
if (slist[cserver].stratum == 0) {
if (verbose)
if (verbose) {
printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
}
continue;
}
/* Sort out servers with error flags */
if (LI(slist[cserver].flags) == LI_ALARM) {
if (verbose)
if (verbose) {
printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
}
continue;
}
@ -322,7 +321,7 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
* we don't waste time sitting around waiting for single packets.
* - we also "manually" handle resolving host names and connecting, because
* we have to do it in a way that our lazy macros don't handle currently :( */
double offset_request(const char *host, int *status) {
double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) {
/* setup hints to only return results from getaddrinfo that we'd like */
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
@ -331,39 +330,43 @@ double offset_request(const char *host, int *status) {
hints.ai_socktype = SOCK_DGRAM;
/* fill in ai with the list of hosts resolved by the host name */
struct addrinfo *ai = NULL;
int ga_result = getaddrinfo(host, port, &hints, &ai);
struct addrinfo *addresses = NULL;
int ga_result = getaddrinfo(host, port, &hints, &addresses);
if (ga_result != 0) {
die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
}
/* count the number of returned hosts, and allocate stuff accordingly */
int num_hosts = 0;
for (struct addrinfo *ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
size_t num_hosts = 0;
for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
num_hosts++;
}
ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
if (req == NULL)
if (req == NULL) {
die(STATE_UNKNOWN, "can not allocate ntp message array");
}
int *socklist = (int *)malloc(sizeof(int) * num_hosts);
if (socklist == NULL)
if (socklist == NULL) {
die(STATE_UNKNOWN, "can not allocate socket array");
}
struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts);
if (ufds == NULL)
if (ufds == NULL) {
die(STATE_UNKNOWN, "can not allocate socket array");
}
ntp_server_results *servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
if (servers == NULL)
if (servers == NULL) {
die(STATE_UNKNOWN, "can not allocate server array");
}
memset(servers, 0, sizeof(ntp_server_results) * num_hosts);
DBG(printf("Found %d peers to check\n", num_hosts));
DBG(printf("Found %zu peers to check\n", num_hosts));
/* setup each socket for writing, and the corresponding struct pollfd */
struct addrinfo *ai_tmp = ai;
struct addrinfo *ai_tmp = addresses;
for (int i = 0; ai_tmp; i++) {
socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
if (socklist[i] == -1) {
@ -389,7 +392,7 @@ double offset_request(const char *host, int *status) {
time_t start_ts = 0;
time_t now_time = 0;
now_time = start_ts = time(NULL);
int servers_completed = 0;
size_t servers_completed = 0;
bool one_read = false;
while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) {
/* loop through each server and find each one which hasn't
@ -398,12 +401,14 @@ double offset_request(const char *host, int *status) {
* and update the "waiting" timestamp with the current time. */
now_time = time(NULL);
for (int i = 0; i < num_hosts; i++) {
for (size_t i = 0; i < num_hosts; i++) {
if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) {
if (verbose && servers[i].waiting != 0)
if (verbose && servers[i].waiting != 0) {
printf("re-");
if (verbose)
printf("sending request to peer %d\n", i);
}
if (verbose) {
printf("sending request to peer %zu\n", i);
}
setup_request(&req[i]);
write(socklist[i], &req[i], sizeof(ntp_message));
servers[i].waiting = now_time;
@ -419,10 +424,10 @@ double offset_request(const char *host, int *status) {
}
/* read from any sockets with pending data */
for (int i = 0; servers_readable && i < num_hosts; i++) {
for (size_t i = 0; servers_readable && i < num_hosts; i++) {
if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) {
if (verbose) {
printf("response from peer %d: ", i);
printf("response from peer %zu: ", i);
}
read(ufds[i].fd, &req[i], sizeof(ntp_message));
@ -442,14 +447,15 @@ double offset_request(const char *host, int *status) {
servers[i].flags = req[i].flags;
servers_readable--;
one_read = true;
if (servers[i].num_responses == AVG_NUM)
if (servers[i].num_responses == AVG_NUM) {
servers_completed++;
}
}
}
/* lather, rinse, repeat. */
}
if (one_read == false) {
if (!one_read) {
die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
}
@ -467,21 +473,22 @@ double offset_request(const char *host, int *status) {
}
/* cleanup */
for (int j = 0; j < num_hosts; j++) {
for (size_t j = 0; j < num_hosts; j++) {
close(socklist[j]);
}
free(socklist);
free(ufds);
free(servers);
free(req);
freeaddrinfo(ai);
freeaddrinfo(addresses);
if (verbose)
if (verbose) {
printf("overall average offset: %.10g\n", avg_offset);
}
return avg_offset;
}
int process_arguments(int argc, char **argv) {
check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, 'v'},
@ -496,14 +503,24 @@ int process_arguments(int argc, char **argv) {
{"port", required_argument, 0, 'p'},
{0, 0, 0, 0}};
if (argc < 2)
if (argc < 2) {
usage("\n");
}
check_ntp_time_config_wrapper result = {
.errorcode = OK,
.config = check_ntp_time_config_init(),
};
char *owarn = "60";
char *ocrit = "120";
while (true) {
int option = 0;
int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
if (option_char == -1 || option_char == EOF || option_char == 1)
if (option_char == -1 || option_char == EOF || option_char == 1) {
break;
}
switch (option_char) {
case 'h':
@ -518,7 +535,7 @@ int process_arguments(int argc, char **argv) {
verbose++;
break;
case 'q':
quiet = true;
result.config.quiet = true;
break;
case 'w':
owarn = optarg;
@ -527,18 +544,19 @@ int process_arguments(int argc, char **argv) {
ocrit = optarg;
break;
case 'H':
if (!is_host(optarg))
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
server_address = strdup(optarg);
}
result.config.server_address = strdup(optarg);
break;
case 'p':
port = strdup(optarg);
result.config.port = strdup(optarg);
break;
case 't':
socket_timeout = atoi(optarg);
break;
case 'o':
time_offset = atoi(optarg);
result.config.time_offset = atoi(optarg);
break;
case '4':
address_family = AF_INET;
@ -557,14 +575,16 @@ int process_arguments(int argc, char **argv) {
}
}
if (server_address == NULL) {
if (result.config.server_address == NULL) {
usage4(_("Hostname was not supplied"));
}
return 0;
set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
return result;
}
char *perfd_offset(double offset) {
char *perfd_offset(double offset, thresholds *offset_thresholds) {
return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
0);
}
@ -577,10 +597,13 @@ int main(int argc, char *argv[]) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
usage4(_("Could not parse arguments"));
check_ntp_time_config_wrapper tmp_config = process_arguments(argc, argv);
set_thresholds(&offset_thresholds, owarn, ocrit);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_ntp_time_config config = tmp_config.config;
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
@ -588,13 +611,13 @@ int main(int argc, char *argv[]) {
/* set socket timeout */
alarm(socket_timeout);
int offset_result = STATE_OK;
int result = STATE_OK;
double offset = offset_request(server_address, &offset_result);
mp_state_enum offset_result = STATE_OK;
mp_state_enum result = STATE_OK;
double offset = offset_request(config.server_address, config.port, &offset_result, config.time_offset);
if (offset_result == STATE_UNKNOWN) {
result = ((!quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
} else {
result = get_status(fabs(offset), offset_thresholds);
result = get_status(fabs(offset), config.offset_thresholds);
}
char *result_line;
@ -619,13 +642,14 @@ int main(int argc, char *argv[]) {
xasprintf(&perfdata_line, "");
} else {
xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
xasprintf(&perfdata_line, "%s", perfd_offset(offset));
xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
}
printf("%s|%s\n", result_line, perfdata_line);
if (server_address != NULL)
free(server_address);
return result;
if (config.server_address != NULL) {
free(config.server_address);
}
exit(result);
}
void print_help(void) {

View file

@ -0,0 +1,28 @@
#pragma once
#include "../../config.h"
#include "thresholds.h"
#include <stddef.h>
typedef struct {
char *server_address;
char *port;
bool quiet;
int time_offset;
thresholds *offset_thresholds;
} check_ntp_time_config;
check_ntp_time_config check_ntp_time_config_init() {
check_ntp_time_config tmp = {
.server_address = NULL,
.port = "123",
.quiet = false,
.time_offset = 0,
.offset_thresholds = NULL,
};
return tmp;
}

File diff suppressed because it is too large Load diff

View file

@ -1,417 +0,0 @@
/*****************************************************************************
*
* Monitoring check_overcr plugin
*
* License: GPL
* Copyright (c) 2000-2024 Monitoring Plugins Development Team
*
* Description:
*
* This file contains the check_overcr plugin
*
* This plugin attempts to contact the Over-CR collector daemon running on the
* remote UNIX server in order to gather the requested system 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
const char *progname = "check_overcr";
const char *copyright = "2000-2024";
const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
enum checkvar {
NONE,
LOAD1,
LOAD5,
LOAD15,
DPU,
PROCS,
NETSTAT,
UPTIME
};
enum {
PORT = 2000
};
static char *server_address = NULL;
static int server_port = PORT;
static double warning_value = 0L;
static double critical_value = 0L;
static bool check_warning_value = false;
static bool check_critical_value = false;
static enum checkvar vars_to_check = NONE;
static int netstat_port = 0;
static char *disk_name = NULL;
static char *process_name = NULL;
static char send_buffer[MAX_INPUT_BUFFER];
static int process_arguments(int, char **);
void print_usage(void);
static void print_help(void);
int main(int argc, char **argv) {
int result = STATE_UNKNOWN;
char recv_buffer[MAX_INPUT_BUFFER];
char temp_buffer[MAX_INPUT_BUFFER];
char *temp_ptr = NULL;
bool found_disk = false;
unsigned long percent_used_disk_space = 100;
double load;
double load_1min;
double load_5min;
double load_15min;
int port_connections = 0;
int processes = 0;
double uptime_raw_hours;
int uptime_raw_minutes = 0;
int uptime_days = 0;
int uptime_hours = 0;
int uptime_minutes = 0;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
usage4(_("Could not parse arguments"));
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
/* set socket timeout */
alarm(socket_timeout);
result = process_tcp_request2(server_address, server_port, send_buffer, recv_buffer, sizeof(recv_buffer));
switch (vars_to_check) {
case LOAD1:
case LOAD5:
case LOAD15:
if (result != STATE_OK)
die(result, _("Unknown error fetching load data\n"));
temp_ptr = (char *)strtok(recv_buffer, "\r\n");
if (temp_ptr == NULL)
die(STATE_CRITICAL, _("Invalid response from server - no load information\n"));
else
load_1min = strtod(temp_ptr, NULL);
temp_ptr = (char *)strtok(NULL, "\r\n");
if (temp_ptr == NULL)
die(STATE_CRITICAL, _("Invalid response from server after load 1\n"));
else
load_5min = strtod(temp_ptr, NULL);
temp_ptr = (char *)strtok(NULL, "\r\n");
if (temp_ptr == NULL)
die(STATE_CRITICAL, _("Invalid response from server after load 5\n"));
else
load_15min = strtod(temp_ptr, NULL);
switch (vars_to_check) {
case LOAD1:
strcpy(temp_buffer, "1");
load = load_1min;
break;
case LOAD5:
strcpy(temp_buffer, "5");
load = load_5min;
break;
default:
strcpy(temp_buffer, "15");
load = load_15min;
break;
}
if (check_critical_value && (load >= critical_value))
result = STATE_CRITICAL;
else if (check_warning_value && (load >= warning_value))
result = STATE_WARNING;
die(result, _("Load %s - %s-min load average = %0.2f"), state_text(result), temp_buffer, load);
break;
case DPU:
if (result != STATE_OK)
die(result, _("Unknown error fetching disk data\n"));
for (temp_ptr = (char *)strtok(recv_buffer, " "); temp_ptr != NULL; temp_ptr = (char *)strtok(NULL, " ")) {
if (!strcmp(temp_ptr, disk_name)) {
found_disk = true;
temp_ptr = (char *)strtok(NULL, "%");
if (temp_ptr == NULL)
die(STATE_CRITICAL, _("Invalid response from server\n"));
else
percent_used_disk_space = strtoul(temp_ptr, NULL, 10);
break;
}
temp_ptr = (char *)strtok(NULL, "\r\n");
}
/* error if we couldn't find the info for the disk */
if (!found_disk)
die(STATE_CRITICAL, "CRITICAL - Disk '%s' non-existent or not mounted", disk_name);
if (check_critical_value && (percent_used_disk_space >= critical_value))
result = STATE_CRITICAL;
else if (check_warning_value && (percent_used_disk_space >= warning_value))
result = STATE_WARNING;
die(result, "Disk %s - %lu%% used on %s", state_text(result), percent_used_disk_space, disk_name);
break;
case NETSTAT:
if (result != STATE_OK)
die(result, _("Unknown error fetching network status\n"));
else
port_connections = strtod(recv_buffer, NULL);
if (check_critical_value && (port_connections >= critical_value))
result = STATE_CRITICAL;
else if (check_warning_value && (port_connections >= warning_value))
result = STATE_WARNING;
die(result, _("Net %s - %d connection%s on port %d"), state_text(result), port_connections, (port_connections == 1) ? "" : "s",
netstat_port);
break;
case PROCS:
if (result != STATE_OK)
die(result, _("Unknown error fetching process status\n"));
temp_ptr = (char *)strtok(recv_buffer, "(");
if (temp_ptr == NULL)
die(STATE_CRITICAL, _("Invalid response from server\n"));
temp_ptr = (char *)strtok(NULL, ")");
if (temp_ptr == NULL)
die(STATE_CRITICAL, _("Invalid response from server\n"));
else
processes = strtod(temp_ptr, NULL);
if (check_critical_value && (processes >= critical_value))
result = STATE_CRITICAL;
else if (check_warning_value && (processes >= warning_value))
result = STATE_WARNING;
die(result, _("Process %s - %d instance%s of %s running"), state_text(result), processes, (processes == 1) ? "" : "s",
process_name);
break;
case UPTIME:
if (result != STATE_OK)
return result;
uptime_raw_hours = strtod(recv_buffer, NULL);
uptime_raw_minutes = (unsigned long)(uptime_raw_hours * 60.0);
if (check_critical_value && (uptime_raw_minutes <= critical_value))
result = STATE_CRITICAL;
else if (check_warning_value && (uptime_raw_minutes <= warning_value))
result = STATE_WARNING;
uptime_days = uptime_raw_minutes / 1440;
uptime_raw_minutes %= 1440;
uptime_hours = uptime_raw_minutes / 60;
uptime_raw_minutes %= 60;
uptime_minutes = uptime_raw_minutes;
die(result, _("Uptime %s - Up %d days %d hours %d minutes"), state_text(result), uptime_days, uptime_hours, uptime_minutes);
break;
default:
die(STATE_UNKNOWN, _("Nothing to check!\n"));
break;
}
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
int option = 0;
static struct option longopts[] = {
{"port", required_argument, 0, 'p'}, {"timeout", required_argument, 0, 't'}, {"critical", required_argument, 0, 'c'},
{"warning", required_argument, 0, 'w'}, {"variable", required_argument, 0, 'v'}, {"hostname", required_argument, 0, 'H'},
{"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
/* no options were supplied */
if (argc < 2)
return ERROR;
/* backwards compatibility */
if (!is_option(argv[1])) {
server_address = argv[1];
argv[1] = argv[0];
argv = &argv[1];
argc--;
}
for (c = 1; c < argc; c++) {
if (strcmp("-to", argv[c]) == 0)
strcpy(argv[c], "-t");
else if (strcmp("-wv", argv[c]) == 0)
strcpy(argv[c], "-w");
else if (strcmp("-cv", argv[c]) == 0)
strcpy(argv[c], "-c");
}
while (1) {
c = getopt_long(argc, argv, "+hVH:t:c:w:p:v:", longopts, &option);
if (c == -1 || c == EOF || c == 1)
break;
switch (c) {
case '?': /* print short usage statement if args not parsable */
usage5();
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
case 'V': /* version */
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 'H': /* hostname */
server_address = optarg;
break;
case 'p': /* port */
if (is_intnonneg(optarg))
server_port = atoi(optarg);
else
die(STATE_UNKNOWN, _("Server port an integer\n"));
break;
case 'v': /* variable */
if (strcmp(optarg, "LOAD") == 0) {
strcpy(send_buffer, "LOAD\r\nQUIT\r\n");
if (strcmp(optarg, "LOAD1") == 0)
vars_to_check = LOAD1;
else if (strcmp(optarg, "LOAD5") == 0)
vars_to_check = LOAD5;
else if (strcmp(optarg, "LOAD15") == 0)
vars_to_check = LOAD15;
} else if (strcmp(optarg, "UPTIME") == 0) {
vars_to_check = UPTIME;
strcpy(send_buffer, "UPTIME\r\n");
} else if (strstr(optarg, "PROC") == optarg) {
vars_to_check = PROCS;
process_name = strscpy(process_name, optarg + 4);
sprintf(send_buffer, "PROCESS %s\r\n", process_name);
} else if (strstr(optarg, "NET") == optarg) {
vars_to_check = NETSTAT;
netstat_port = atoi(optarg + 3);
sprintf(send_buffer, "NETSTAT %d\r\n", netstat_port);
} else if (strstr(optarg, "DPU") == optarg) {
vars_to_check = DPU;
strcpy(send_buffer, "DISKSPACE\r\n");
disk_name = strscpy(disk_name, optarg + 3);
} else
return ERROR;
break;
case 'w': /* warning threshold */
warning_value = strtoul(optarg, NULL, 10);
check_warning_value = true;
break;
case 'c': /* critical threshold */
critical_value = strtoul(optarg, NULL, 10);
check_critical_value = true;
break;
case 't': /* timeout */
socket_timeout = atoi(optarg);
if (socket_timeout <= 0)
return ERROR;
}
}
return OK;
}
void print_help(void) {
char *myport;
xasprintf(&myport, "%d", PORT);
print_revision(progname, NP_VERSION);
printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
printf(COPYRIGHT, copyright, email);
printf("%s\n", _("This plugin attempts to contact the Over-CR collector daemon running on the"));
printf("%s\n", _("remote UNIX server in order to gather the requested system information."));
printf("\n\n");
print_usage();
printf(UT_HELP_VRSN);
printf(UT_EXTRA_OPTS);
printf(UT_HOST_PORT, 'p', myport);
printf(" %s\n", "-w, --warning=INTEGER");
printf(" %s\n", _("Threshold which will result in a warning status"));
printf(" %s\n", "-c, --critical=INTEGER");
printf(" %s\n", _("Threshold which will result in a critical status"));
printf(" %s\n", "-v, --variable=STRING");
printf(" %s\n", _("Variable to check. Valid variables include:"));
printf(" %s\n", _("LOAD1 = 1 minute average CPU load"));
printf(" %s\n", _("LOAD5 = 5 minute average CPU load"));
printf(" %s\n", _("LOAD15 = 15 minute average CPU load"));
printf(" %s\n", _("DPU<filesys> = percent used disk space on filesystem <filesys>"));
printf(" %s\n", _("PROC<process> = number of running processes with name <process>"));
printf(" %s\n", _("NET<port> = number of active connections on TCP port <port>"));
printf(" %s\n", _("UPTIME = system uptime in seconds"));
printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
printf(UT_VERBOSE);
printf("\n");
printf("%s\n", _("This plugin requires that Eric Molitors' Over-CR collector daemon be"));
printf("%s\n", _("running on the remote server."));
printf("%s\n", _("Over-CR can be downloaded from http://www.molitor.org/overcr"));
printf("%s\n", _("This plugin was tested with version 0.99.53 of the Over-CR collector"));
printf("\n");
printf("%s\n", _("Notes:"));
printf(" %s\n", _("For the available options, the critical threshold value should always be"));
printf(" %s\n", _("higher than the warning threshold value, EXCEPT with the uptime variable"));
printf(UT_SUPPORT);
}
void print_usage(void) {
printf("%s\n", _("Usage:"));
printf("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n", progname);
}

View file

@ -28,6 +28,7 @@
*
*****************************************************************************/
#include "states.h"
const char *progname = "check_pgsql";
const char *copyright = "1999-2024";
const char *email = "devel@monitoring-plugins.org";
@ -35,12 +36,13 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "utils.h"
#include "utils_cmd.h"
#include "check_pgsql.d/config.h"
#include "thresholds.h"
#include "netutils.h"
#include <libpq-fe.h>
#include <pg_config_manual.h>
#define DEFAULT_DB "template1"
#define DEFAULT_HOST "127.0.0.1"
/* return the PSQL server version as a 3-tuple */
@ -53,33 +55,18 @@ const char *email = "devel@monitoring-plugins.org";
#define PSQL_SOCKET3(host, port) \
((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port
enum {
DEFAULT_PORT = 5432,
DEFAULT_WARN = 2,
DEFAULT_CRIT = 8
};
typedef struct {
int errorcode;
check_pgsql_config config;
} check_pgsql_config_wrapper;
static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static int process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
static bool is_pg_logname(char * /*username*/);
static int do_query(PGconn * /*conn*/, char * /*query*/);
static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[], thresholds * /*qthresholds*/,
char * /*query_warning*/, char * /*query_critical*/);
void print_usage(void);
static char *pghost = NULL; /* host name of the backend server */
static char *pgport = NULL; /* port of the backend server */
static char *pgoptions = NULL;
static char *pgtty = NULL;
static char dbName[NAMEDATALEN] = DEFAULT_DB;
static char *pguser = NULL;
static char *pgpasswd = NULL;
static char *pgparams = NULL;
static double twarn = (double)DEFAULT_WARN;
static double tcrit = (double)DEFAULT_CRIT;
static char *pgquery = NULL;
static char *pgqueryname = NULL;
static char *query_warning = NULL;
static char *query_critical = NULL;
static thresholds *qthresholds = NULL;
static int verbose = 0;
#define OPTID_QUERYNAME -1000
@ -139,21 +126,19 @@ int main(int argc, char **argv) {
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
/* begin, by setting the parameters for a backend connection if the
* parameters are null, then the system will try to use reasonable
* defaults by looking up environment variables or, failing that,
* using hardwired constants */
pgoptions = NULL; /* special options to start up the backend server */
pgtty = NULL; /* debugging tty for the backend server */
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_pgsql_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
if (verbose > 2)
}
const check_pgsql_config config = tmp_config.config;
if (verbose > 2) {
printf("Arguments initialized\n");
}
/* Set signal handling and alarm */
if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
@ -162,25 +147,32 @@ int main(int argc, char **argv) {
alarm(timeout_interval);
char *conninfo = NULL;
if (pgparams)
asprintf(&conninfo, "%s ", pgparams);
if (config.pgparams) {
asprintf(&conninfo, "%s ", config.pgparams);
}
asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", dbName);
if (pghost)
asprintf(&conninfo, "%s host = '%s'", conninfo, pghost);
if (pgport)
asprintf(&conninfo, "%s port = '%s'", conninfo, pgport);
if (pgoptions)
asprintf(&conninfo, "%s options = '%s'", conninfo, pgoptions);
asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", config.dbName);
if (config.pghost) {
asprintf(&conninfo, "%s host = '%s'", conninfo, config.pghost);
}
if (config.pgport) {
asprintf(&conninfo, "%s port = '%s'", conninfo, config.pgport);
}
if (config.pgoptions) {
asprintf(&conninfo, "%s options = '%s'", conninfo, config.pgoptions);
}
/* if (pgtty) -- ignored by PQconnectdb */
if (pguser)
asprintf(&conninfo, "%s user = '%s'", conninfo, pguser);
if (config.pguser) {
asprintf(&conninfo, "%s user = '%s'", conninfo, config.pguser);
}
if (verbose) /* do not include password (see right below) in output */
printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, pgpasswd ? " password = <hidden>" : "");
if (verbose) { /* do not include password (see right below) in output */
printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, config.pgpasswd ? " password = <hidden>" : "");
}
if (pgpasswd)
asprintf(&conninfo, "%s password = '%s'", conninfo, pgpasswd);
if (config.pgpasswd) {
asprintf(&conninfo, "%s password = '%s'", conninfo, config.pgpasswd);
}
/* make a connection to the database */
struct timeval start_timeval;
@ -194,24 +186,26 @@ int main(int argc, char **argv) {
end_timeval.tv_usec += 1000000;
}
double elapsed_time =
(double)(end_timeval.tv_sec - start_timeval.tv_sec) + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0;
(double)(end_timeval.tv_sec - start_timeval.tv_sec) + ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0);
if (verbose)
if (verbose) {
printf("Time elapsed: %f\n", elapsed_time);
}
/* check to see that the backend connection was successfully made */
if (verbose)
if (verbose) {
printf("Verifying connection\n");
}
if (PQstatus(conn) == CONNECTION_BAD) {
printf(_("CRITICAL - no connection to '%s' (%s).\n"), dbName, PQerrorMessage(conn));
printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn));
PQfinish(conn);
return STATE_CRITICAL;
}
int status = STATE_UNKNOWN;
if (elapsed_time > tcrit) {
mp_state_enum status = STATE_UNKNOWN;
if (elapsed_time > config.tcrit) {
status = STATE_CRITICAL;
} else if (elapsed_time > twarn) {
} else if (elapsed_time > config.twarn) {
status = STATE_WARNING;
} else {
status = STATE_OK;
@ -228,21 +222,23 @@ int main(int argc, char **argv) {
PQprotocolVersion(conn), PQbackendPID(conn));
}
printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), dbName, elapsed_time,
fperfdata("time", elapsed_time, "s", !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, true, 0, false, 0));
printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time,
fperfdata("time", elapsed_time, "s", (config.twarn > 0.0), config.twarn, (config.tcrit > 0.0), config.tcrit, true, 0, false, 0));
int query_status = STATE_UNKNOWN;
if (pgquery)
query_status = do_query(conn, pgquery);
mp_state_enum query_status = STATE_UNKNOWN;
if (config.pgquery) {
query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds, config.query_warning, config.query_critical);
}
if (verbose)
if (verbose) {
printf("Closing connection\n");
}
PQfinish(conn);
return (pgquery && query_status > status) ? query_status : status;
return (config.pgquery && query_status > status) ? query_status : status;
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"timeout", required_argument, 0, 't'},
@ -262,12 +258,18 @@ int process_arguments(int argc, char **argv) {
{"verbose", no_argument, 0, 'v'},
{0, 0, 0, 0}};
check_pgsql_config_wrapper result = {
.errorcode = OK,
.config = check_pgsql_config_init(),
};
while (true) {
int option = 0;
int option_char = getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option);
if (option_char == EOF)
if (option_char == EOF) {
break;
}
switch (option_char) {
case '?': /* usage */
@ -279,68 +281,75 @@ int process_arguments(int argc, char **argv) {
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 't': /* timeout period */
if (!is_integer(optarg))
if (!is_integer(optarg)) {
usage2(_("Timeout interval must be a positive integer"), optarg);
else
} else {
timeout_interval = atoi(optarg);
}
break;
case 'c': /* critical time threshold */
if (!is_nonnegative(optarg))
if (!is_nonnegative(optarg)) {
usage2(_("Critical threshold must be a positive integer"), optarg);
else
tcrit = strtod(optarg, NULL);
} else {
result.config.tcrit = strtod(optarg, NULL);
}
break;
case 'w': /* warning time threshold */
if (!is_nonnegative(optarg))
if (!is_nonnegative(optarg)) {
usage2(_("Warning threshold must be a positive integer"), optarg);
else
twarn = strtod(optarg, NULL);
} else {
result.config.twarn = strtod(optarg, NULL);
}
break;
case 'C': /* critical query threshold */
query_critical = optarg;
result.config.query_critical = optarg;
break;
case 'W': /* warning query threshold */
query_warning = optarg;
result.config.query_warning = optarg;
break;
case 'H': /* host */
if ((*optarg != '/') && (!is_host(optarg)))
if ((*optarg != '/') && (!is_host(optarg))) {
usage2(_("Invalid hostname/address"), optarg);
else
pghost = optarg;
} else {
result.config.pghost = optarg;
}
break;
case 'P': /* port */
if (!is_integer(optarg))
if (!is_integer(optarg)) {
usage2(_("Port must be a positive integer"), optarg);
else
pgport = optarg;
} else {
result.config.pgport = optarg;
}
break;
case 'd': /* database name */
if (strlen(optarg) >= NAMEDATALEN) {
usage2(_("Database name exceeds the maximum length"), optarg);
}
snprintf(dbName, NAMEDATALEN, "%s", optarg);
snprintf(result.config.dbName, NAMEDATALEN, "%s", optarg);
break;
case 'l': /* login name */
if (!is_pg_logname(optarg))
if (!is_pg_logname(optarg)) {
usage2(_("User name is not valid"), optarg);
else
pguser = optarg;
} else {
result.config.pguser = optarg;
}
break;
case 'p': /* authentication password */
case 'a':
pgpasswd = optarg;
result.config.pgpasswd = optarg;
break;
case 'o':
if (pgparams)
asprintf(&pgparams, "%s %s", pgparams, optarg);
else
asprintf(&pgparams, "%s", optarg);
if (result.config.pgparams) {
asprintf(&result.config.pgparams, "%s %s", result.config.pgparams, optarg);
} else {
asprintf(&result.config.pgparams, "%s", optarg);
}
break;
case 'q':
pgquery = optarg;
result.config.pgquery = optarg;
break;
case OPTID_QUERYNAME:
pgqueryname = optarg;
result.config.pgqueryname = optarg;
break;
case 'v':
verbose++;
@ -348,9 +357,9 @@ int process_arguments(int argc, char **argv) {
}
}
set_thresholds(&qthresholds, query_warning, query_critical);
set_thresholds(&result.config.qthresholds, result.config.query_warning, result.config.query_critical);
return OK;
return result;
}
/**
@ -378,8 +387,9 @@ should be added.</para>
******************************************************************************/
bool is_pg_logname(char *username) {
if (strlen(username) > NAMEDATALEN - 1)
if (strlen(username) > NAMEDATALEN - 1) {
return (false);
}
return (true);
}
@ -394,7 +404,7 @@ bool is_pg_logname(char *username) {
void print_help(void) {
char *myport;
xasprintf(&myport, "%d", DEFAULT_PORT);
xasprintf(&myport, "%d", 5432);
print_revision(progname, NP_VERSION);
@ -482,9 +492,11 @@ void print_usage(void) {
"[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
}
int do_query(PGconn *conn, char *query) {
if (verbose)
mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds, char *query_warning,
char *query_critical) {
if (verbose) {
printf("Executing SQL query \"%s\".\n", query);
}
PGresult *res = PQexec(conn, query);
if (PGRES_TUPLES_OK != PQresultStatus(res)) {
@ -510,8 +522,9 @@ int do_query(PGconn *conn, char *query) {
char *endptr = NULL;
double value = strtod(val_str, &endptr);
if (verbose)
if (verbose) {
printf("Query result: %f\n", value);
}
if (endptr == val_str) {
printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str);
@ -519,11 +532,12 @@ int do_query(PGconn *conn, char *query) {
}
if ((endptr != NULL) && (*endptr != '\0')) {
if (verbose)
if (verbose) {
printf("Garbage after value: %s.\n", endptr);
}
}
int my_status = get_status(value, qthresholds);
mp_state_enum my_status = get_status(value, qthresholds);
printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK")
: (my_status == STATE_WARNING) ? _("WARNING")
: (my_status == STATE_CRITICAL) ? _("CRITICAL")

View file

@ -0,0 +1,61 @@
#pragma once
#include "../../config.h"
#include "thresholds.h"
#include <stddef.h>
#include <pg_config_manual.h>
#define DEFAULT_DB "template1"
enum {
DEFAULT_WARN = 2,
DEFAULT_CRIT = 8,
};
typedef struct {
char *pghost; /* host name of the backend server */
char *pgport; /* port of the backend server */
char *pgoptions; /* special options to start up the backend server */
char *pgtty; /* debugging tty for the backend server */
char dbName[NAMEDATALEN];
char *pguser;
char *pgpasswd;
char *pgparams;
char *pgquery;
char *pgqueryname;
double twarn;
double tcrit;
thresholds *qthresholds;
char *query_warning;
char *query_critical;
} check_pgsql_config;
/* begin, by setting the parameters for a backend connection if the
* parameters are null, then the system will try to use reasonable
* defaults by looking up environment variables or, failing that,
* using hardwired constants
* this targets .pgoptions and .pgtty
*/
check_pgsql_config check_pgsql_config_init() {
check_pgsql_config tmp = {
.pghost = NULL,
.pgport = NULL,
.pgoptions = NULL,
.pgtty = NULL,
.dbName = DEFAULT_DB,
.pguser = NULL,
.pgpasswd = NULL,
.pgparams = NULL,
.pgquery = NULL,
.pgqueryname = NULL,
.twarn = (double)DEFAULT_WARN,
.tcrit = (double)DEFAULT_CRIT,
.qthresholds = NULL,
.query_warning = NULL,
.query_critical = NULL,
};
return tmp;
}

View file

@ -36,61 +36,52 @@ const char *email = "devel@monitoring-plugins.org";
#include "netutils.h"
#include "popen.h"
#include "utils.h"
#include "check_ping.d/config.h"
#include "../lib/states.h"
#include <signal.h>
#define WARN_DUPLICATES "DUPLICATES FOUND! "
#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
#define WARN_DUPLICATES "DUPLICATES FOUND! "
enum {
UNKNOWN_PACKET_LOSS = 200, /* 200% */
DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */
};
typedef struct {
int errorcode;
check_ping_config config;
} check_ping_config_wrapper;
static check_ping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_ping_config_wrapper validate_arguments(check_ping_config_wrapper /*config_wrapper*/);
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int get_threshold(char * /*arg*/, float * /*trta*/, int * /*tpl*/);
static int validate_arguments(void);
static int run_ping(const char *cmd, const char *addr);
static int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr);
static int get_threshold(char * /*arg*/, double * /*trta*/, int * /*tpl*/);
typedef struct {
mp_state_enum state;
double round_trip_average;
int packet_loss;
} ping_result;
static ping_result run_ping(const char *cmd, const char *addr, double /*crta*/);
static mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr);
static void print_help(void);
void print_usage(void);
static bool display_html = false;
static int wpl = UNKNOWN_PACKET_LOSS;
static int cpl = UNKNOWN_PACKET_LOSS;
static float wrta = UNKNOWN_TRIP_TIME;
static float crta = UNKNOWN_TRIP_TIME;
static char **addresses = NULL;
static int n_addresses = 0;
static int max_addr = 1;
static int max_packets = -1;
static int verbose = 0;
static float rta = UNKNOWN_TRIP_TIME;
static int pl = UNKNOWN_PACKET_LOSS;
static char *warn_text;
int main(int argc, char **argv) {
char *cmd = NULL;
char *rawcmd = NULL;
int result = STATE_UNKNOWN;
int this_result = STATE_UNKNOWN;
int i;
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
addresses = malloc(sizeof(char *) * max_addr);
addresses[0] = NULL;
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_ping_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_ping_config config = tmp_config.config;
/* Set signal handling and alarm */
if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
@ -105,71 +96,86 @@ int main(int argc, char **argv) {
alarm(timeout_interval);
#endif
for (i = 0; i < n_addresses; i++) {
int result = STATE_UNKNOWN;
char *rawcmd = NULL;
for (size_t i = 0; i < config.n_addresses; i++) {
#ifdef PING6_COMMAND
if (address_family != AF_INET && is_inet6_addr(addresses[i]))
if (address_family != AF_INET && is_inet6_addr(config.addresses[i])) {
rawcmd = strdup(PING6_COMMAND);
else
} else {
rawcmd = strdup(PING_COMMAND);
}
#else
rawcmd = strdup(PING_COMMAND);
#endif
/* does the host address of number of packets argument come first? */
char *cmd = NULL;
/* does the host address of number of packets argument come first? */
#ifdef PING_PACKETS_FIRST
# ifdef PING_HAS_TIMEOUT
xasprintf(&cmd, rawcmd, timeout_interval, max_packets, addresses[i]);
xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]);
# else
xasprintf(&cmd, rawcmd, max_packets, addresses[i]);
xasprintf(&cmd, rawcmd, config.max_packets, config.addresses[i]);
# endif
#else
xasprintf(&cmd, rawcmd, addresses[i], max_packets);
xasprintf(&cmd, rawcmd, config.addresses[i], config.max_packets);
#endif
if (verbose >= 2)
if (verbose >= 2) {
printf("CMD: %s\n", cmd);
}
/* run the command */
this_result = run_ping(cmd, addresses[i]);
if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) {
ping_result pinged = run_ping(cmd, config.addresses[i], config.crta);
if (pinged.packet_loss == UNKNOWN_PACKET_LOSS || pinged.round_trip_average < 0.0) {
printf("%s\n", cmd);
die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n"));
}
if (pl >= cpl || rta >= crta || rta < 0)
this_result = STATE_CRITICAL;
else if (pl >= wpl || rta >= wrta)
this_result = STATE_WARNING;
else if (pl >= 0 && rta >= 0)
this_result = max_state(STATE_OK, this_result);
if (pinged.packet_loss >= config.cpl || pinged.round_trip_average >= config.crta || pinged.round_trip_average < 0) {
pinged.state = STATE_CRITICAL;
} else if (pinged.packet_loss >= config.wpl || pinged.round_trip_average >= config.wrta) {
pinged.state = STATE_WARNING;
} else if (pinged.packet_loss >= 0 && pinged.round_trip_average >= 0) {
pinged.state = max_state(STATE_OK, pinged.state);
}
if (n_addresses > 1 && this_result != STATE_UNKNOWN)
die(STATE_OK, "%s is alive\n", addresses[i]);
if (config.n_addresses > 1 && pinged.state != STATE_UNKNOWN) {
die(STATE_OK, "%s is alive\n", config.addresses[i]);
}
if (display_html == true)
printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]);
if (pl == 100)
printf(_("PING %s - %sPacket loss = %d%%"), state_text(this_result), warn_text, pl);
else
printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(this_result), warn_text, pl, rta);
if (display_html == true)
if (config.display_html) {
printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, config.addresses[i]);
}
if (pinged.packet_loss == 100) {
printf(_("PING %s - %sPacket loss = %d%%"), state_text(pinged.state), warn_text, pinged.packet_loss);
} else {
printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(pinged.state), warn_text, pinged.packet_loss,
pinged.round_trip_average);
}
if (config.display_html) {
printf("</A>");
}
/* Print performance data */
if (pl != 100) {
printf("|%s",
fperfdata("rta", (double)rta, "ms", wrta > 0 ? true : false, wrta, crta > 0 ? true : false, crta, true, 0, false, 0));
if (pinged.packet_loss != 100) {
printf("|%s", fperfdata("rta", pinged.round_trip_average, "ms", (bool)(config.wrta > 0), config.wrta, (bool)(config.crta > 0),
config.crta, true, 0, false, 0));
} else {
printf("| rta=U;%f;%f;;", wrta, crta);
printf("| rta=U;%f;%f;;", config.wrta, config.crta);
}
printf(" %s\n", perfdata("pl", (long)pl, "%", wpl > 0 ? true : false, wpl, cpl > 0 ? true : false, cpl, true, 0, false, 0));
if (verbose >= 2)
printf("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl);
printf(" %s\n", perfdata("pl", (long)pinged.packet_loss, "%", (bool)(config.wpl > 0), config.wpl, (bool)(config.cpl > 0),
config.cpl, true, 0, false, 0));
result = max_state(result, this_result);
if (verbose >= 2) {
printf("%f:%d%% %f:%d%%\n", config.wrta, config.wpl, config.crta, config.cpl);
}
result = max_state(result, pinged.state);
free(rawcmd);
free(cmd);
}
@ -178,11 +184,7 @@ int main(int argc, char **argv) {
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c = 1;
char *ptr;
int option = 0;
check_ping_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {STD_LONG_OPTS,
{"packets", required_argument, 0, 'p'},
{"nohtml", no_argument, 0, 'n'},
@ -191,23 +193,35 @@ int process_arguments(int argc, char **argv) {
{"use-ipv6", no_argument, 0, '6'},
{0, 0, 0, 0}};
if (argc < 2)
return ERROR;
check_ping_config_wrapper result = {
.errorcode = OK,
.config = check_ping_config_init(),
};
for (c = 1; c < argc; c++) {
if (strcmp("-to", argv[c]) == 0)
strcpy(argv[c], "-t");
if (strcmp("-nohtml", argv[c]) == 0)
strcpy(argv[c], "-n");
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
while (1) {
c = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option);
for (int index = 1; index < argc; index++) {
if (strcmp("-to", argv[index]) == 0) {
strcpy(argv[index], "-t");
}
if (strcmp("-nohtml", argv[index]) == 0) {
strcpy(argv[index], "-n");
}
}
if (c == -1 || c == EOF)
int option = 0;
size_t max_addr = MAX_ADDR_START;
while (true) {
int option_index = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option);
if (option_index == -1 || option_index == EOF) {
break;
}
switch (c) {
switch (option_index) {
case '?': /* usage */
usage5();
case 'h': /* help */
@ -234,17 +248,18 @@ int process_arguments(int argc, char **argv) {
usage(_("IPv6 support not available\n"));
#endif
break;
case 'H': /* hostname */
ptr = optarg;
while (1) {
n_addresses++;
if (n_addresses > max_addr) {
case 'H': /* hostname */ {
char *ptr = optarg;
while (true) {
result.config.n_addresses++;
if (result.config.n_addresses > max_addr) {
max_addr *= 2;
addresses = realloc(addresses, sizeof(char *) * max_addr);
if (addresses == NULL)
result.config.addresses = realloc(result.config.addresses, sizeof(char *) * max_addr);
if (result.config.addresses == NULL) {
die(STATE_UNKNOWN, _("Could not realloc() addresses\n"));
}
}
addresses[n_addresses - 1] = ptr;
result.config.addresses[result.config.n_addresses - 1] = ptr;
if ((ptr = index(ptr, ','))) {
strcpy(ptr, "");
ptr += sizeof(char);
@ -252,203 +267,248 @@ int process_arguments(int argc, char **argv) {
break;
}
}
break;
} break;
case 'p': /* number of packets to send */
if (is_intnonneg(optarg))
max_packets = atoi(optarg);
else
if (is_intnonneg(optarg)) {
result.config.max_packets = atoi(optarg);
} else {
usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg);
}
break;
case 'n': /* no HTML */
display_html = false;
result.config.display_html = false;
break;
case 'L': /* show HTML */
display_html = true;
result.config.display_html = true;
break;
case 'c':
get_threshold(optarg, &crta, &cpl);
get_threshold(optarg, &result.config.crta, &result.config.cpl);
break;
case 'w':
get_threshold(optarg, &wrta, &wpl);
get_threshold(optarg, &result.config.wrta, &result.config.wpl);
break;
}
}
c = optind;
if (c == argc)
return validate_arguments();
int arg_counter = optind;
if (arg_counter == argc) {
return validate_arguments(result);
}
if (addresses[0] == NULL) {
if (!is_host(argv[c])) {
usage2(_("Invalid hostname/address"), argv[c]);
if (result.config.addresses[0] == NULL) {
if (!is_host(argv[arg_counter])) {
usage2(_("Invalid hostname/address"), argv[arg_counter]);
} else {
addresses[0] = argv[c++];
n_addresses++;
if (c == argc)
return validate_arguments();
result.config.addresses[0] = argv[arg_counter++];
result.config.n_addresses++;
if (arg_counter == argc) {
return validate_arguments(result);
}
}
}
if (wpl == UNKNOWN_PACKET_LOSS) {
if (!is_intpercent(argv[c])) {
printf(_("<wpl> (%s) must be an integer percentage\n"), argv[c]);
return ERROR;
} else {
wpl = atoi(argv[c++]);
if (c == argc)
return validate_arguments();
if (result.config.wpl == UNKNOWN_PACKET_LOSS) {
if (!is_intpercent(argv[arg_counter])) {
printf(_("<wpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
result.errorcode = ERROR;
return result;
}
result.config.wpl = atoi(argv[arg_counter++]);
if (arg_counter == argc) {
return validate_arguments(result);
}
}
if (cpl == UNKNOWN_PACKET_LOSS) {
if (!is_intpercent(argv[c])) {
printf(_("<cpl> (%s) must be an integer percentage\n"), argv[c]);
return ERROR;
} else {
cpl = atoi(argv[c++]);
if (c == argc)
return validate_arguments();
if (result.config.cpl == UNKNOWN_PACKET_LOSS) {
if (!is_intpercent(argv[arg_counter])) {
printf(_("<cpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
result.errorcode = ERROR;
return result;
}
result.config.cpl = atoi(argv[arg_counter++]);
if (arg_counter == argc) {
return validate_arguments(result);
}
}
if (wrta < 0.0) {
if (is_negative(argv[c])) {
printf(_("<wrta> (%s) must be a non-negative number\n"), argv[c]);
return ERROR;
} else {
wrta = atof(argv[c++]);
if (c == argc)
return validate_arguments();
if (result.config.wrta < 0.0) {
if (is_negative(argv[arg_counter])) {
printf(_("<wrta> (%s) must be a non-negative number\n"), argv[arg_counter]);
result.errorcode = ERROR;
return result;
}
result.config.wrta = atof(argv[arg_counter++]);
if (arg_counter == argc) {
return validate_arguments(result);
}
}
if (crta < 0.0) {
if (is_negative(argv[c])) {
printf(_("<crta> (%s) must be a non-negative number\n"), argv[c]);
return ERROR;
} else {
crta = atof(argv[c++]);
if (c == argc)
return validate_arguments();
if (result.config.crta < 0.0) {
if (is_negative(argv[arg_counter])) {
printf(_("<crta> (%s) must be a non-negative number\n"), argv[arg_counter]);
result.errorcode = ERROR;
return result;
}
result.config.crta = atof(argv[arg_counter++]);
if (arg_counter == argc) {
return validate_arguments(result);
}
}
if (max_packets == -1) {
if (is_intnonneg(argv[c])) {
max_packets = atoi(argv[c++]);
if (result.config.max_packets == -1) {
if (is_intnonneg(argv[arg_counter])) {
result.config.max_packets = atoi(argv[arg_counter++]);
} else {
printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[c]);
return ERROR;
printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[arg_counter]);
result.errorcode = ERROR;
return result;
}
}
return validate_arguments();
return validate_arguments(result);
}
int get_threshold(char *arg, float *trta, int *tpl) {
if (is_intnonneg(arg) && sscanf(arg, "%f", trta) == 1)
int get_threshold(char *arg, double *trta, int *tpl) {
if (is_intnonneg(arg) && sscanf(arg, "%lf", trta) == 1) {
return OK;
else if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%f%*[:,]%d%%", trta, tpl) == 2)
}
if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%lf%*[:,]%d%%", trta, tpl) == 2) {
return OK;
else if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1)
}
if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) {
return OK;
}
usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg);
return STATE_UNKNOWN;
}
int validate_arguments() {
float max_seconds;
int i;
if (wrta < 0.0) {
check_ping_config_wrapper validate_arguments(check_ping_config_wrapper config_wrapper) {
if (config_wrapper.config.wrta < 0.0) {
printf(_("<wrta> was not set\n"));
return ERROR;
} else if (crta < 0.0) {
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
if (config_wrapper.config.crta < 0.0) {
printf(_("<crta> was not set\n"));
return ERROR;
} else if (wpl == UNKNOWN_PACKET_LOSS) {
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
if (config_wrapper.config.wpl == UNKNOWN_PACKET_LOSS) {
printf(_("<wpl> was not set\n"));
return ERROR;
} else if (cpl == UNKNOWN_PACKET_LOSS) {
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
if (config_wrapper.config.cpl == UNKNOWN_PACKET_LOSS) {
printf(_("<cpl> was not set\n"));
return ERROR;
} else if (wrta > crta) {
printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta);
return ERROR;
} else if (wpl > cpl) {
printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl);
return ERROR;
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
if (max_packets == -1)
max_packets = DEFAULT_MAX_PACKETS;
max_seconds = crta / 1000.0 * max_packets + max_packets;
if (max_seconds > timeout_interval)
timeout_interval = (int)max_seconds;
for (i = 0; i < n_addresses; i++) {
if (!is_host(addresses[i]))
usage2(_("Invalid hostname/address"), addresses[i]);
if (config_wrapper.config.wrta > config_wrapper.config.crta) {
printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), config_wrapper.config.wrta, config_wrapper.config.crta);
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
if (n_addresses == 0) {
if (config_wrapper.config.wpl > config_wrapper.config.cpl) {
printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), config_wrapper.config.wpl, config_wrapper.config.cpl);
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
if (config_wrapper.config.max_packets == -1) {
config_wrapper.config.max_packets = DEFAULT_MAX_PACKETS;
}
double max_seconds = (config_wrapper.config.crta / 1000.0 * config_wrapper.config.max_packets) + config_wrapper.config.max_packets;
if (max_seconds > timeout_interval) {
timeout_interval = (unsigned int)max_seconds;
}
for (size_t i = 0; i < config_wrapper.config.n_addresses; i++) {
if (!is_host(config_wrapper.config.addresses[i])) {
usage2(_("Invalid hostname/address"), config_wrapper.config.addresses[i]);
}
}
if (config_wrapper.config.n_addresses == 0) {
usage(_("You must specify a server address or host name"));
}
return OK;
return config_wrapper;
}
int run_ping(const char *cmd, const char *addr) {
char buf[MAX_INPUT_BUFFER];
int result = STATE_UNKNOWN;
int match;
if ((child_process = spopen(cmd)) == NULL)
ping_result run_ping(const char *cmd, const char *addr, double crta) {
if ((child_process = spopen(cmd)) == NULL) {
die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
}
child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
if (child_stderr == NULL)
if (child_stderr == NULL) {
printf(_("Cannot open stderr for %s\n"), cmd);
}
char buf[MAX_INPUT_BUFFER];
ping_result result = {
.state = STATE_UNKNOWN,
.packet_loss = UNKNOWN_PACKET_LOSS,
.round_trip_average = UNKNOWN_TRIP_TIME,
};
while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
if (verbose >= 3)
if (verbose >= 3) {
printf("Output: %s", buf);
}
result = max_state(result, error_scan(buf, addr));
result.state = max_state(result.state, error_scan(buf, addr));
/* get the percent loss statistics */
match = 0;
if ((sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) ||
(sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) ||
(sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) ||
(sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", &pl, &match) && match) ||
(sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &pl, &match) && match) ||
(sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &pl, &match) && match) ||
(sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", &pl, &match) && match) ||
(sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) ||
(sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) ||
(sscanf(buf, "%*[^(](%d%% %*[^)])%n", &pl, &match) && match))
int match = 0;
if ((sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) ==
1 &&
match) ||
(sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &result.packet_loss,
&match) == 1 &&
match) ||
(sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
match) ||
(sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", &result.packet_loss, &match) == 1 && match) ||
(sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &result.packet_loss, &match) == 1 && match) ||
(sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &result.packet_loss, &match) == 1 && match) ||
(sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", &result.packet_loss, &match) == 1 && match) ==
1 ||
(sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
match) ||
(sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
match) ||
(sscanf(buf, "%*[^(](%d%% %*[^)])%n", &result.packet_loss, &match) == 1 && match)) {
continue;
}
/* get the round trip average */
else if ((sscanf(buf, "round-trip min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) ||
(sscanf(buf, "round-trip min/avg/max/mdev = %*f/%f/%*f/%*f%n", &rta, &match) && match) ||
(sscanf(buf, "round-trip min/avg/max/sdev = %*f/%f/%*f/%*f%n", &rta, &match) && match) ||
(sscanf(buf, "round-trip min/avg/max/stddev = %*f/%f/%*f/%*f%n", &rta, &match) && match) ||
(sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f%n", &rta, &match) && match) ||
(sscanf(buf, "round-trip (ms) min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) ||
(sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%f/%*f/%*f%n", &rta, &match) && match) ||
(sscanf(buf, "rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%n", &rta, &match) && match) ||
(sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match))
if ((sscanf(buf, "round-trip min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
(sscanf(buf, "round-trip min/avg/max/mdev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
(sscanf(buf, "round-trip min/avg/max/sdev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
(sscanf(buf, "round-trip min/avg/max/stddev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
(sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
(sscanf(buf, "round-trip (ms) min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
(sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
(sscanf(buf, "rtt min/avg/max/mdev = %*f/%lf/%*f/%*f ms%n", &result.round_trip_average, &match) == 1 && match) ||
(sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %lfms%n", &result.round_trip_average, &match) == 1 && match)) {
continue;
}
}
/* this is needed because there is no rta if all packets are lost */
if (pl == 100)
rta = crta;
if (result.packet_loss == 100) {
result.round_trip_average = crta;
}
/* check stderr, setting at least WARNING if there is output here */
/* Add warning into warn_text */
@ -459,8 +519,8 @@ int run_ping(const char *cmd, const char *addr) {
if (verbose >= 3) {
printf("Got stderr: %s", buf);
}
if ((result = error_scan(buf, addr)) == STATE_OK) {
result = STATE_WARNING;
if ((result.state = error_scan(buf, addr)) == STATE_OK) {
result.state = STATE_WARNING;
if (warn_text == NULL) {
warn_text = strdup(_("System call sent warnings to stderr "));
} else {
@ -474,43 +534,46 @@ int run_ping(const char *cmd, const char *addr) {
spclose(child_process);
if (warn_text == NULL)
if (warn_text == NULL) {
warn_text = strdup("");
}
return result;
}
int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) {
if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route"))
mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) {
if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) {
die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable"))
} else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) {
die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable"))
} else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) {
die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
else if (strstr(buf, "Destination Protocol Unreachable"))
} else if (strstr(buf, "Destination Protocol Unreachable")) {
die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
else if (strstr(buf, "Destination Net Prohibited"))
} else if (strstr(buf, "Destination Net Prohibited")) {
die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
else if (strstr(buf, "Destination Host Prohibited"))
} else if (strstr(buf, "Destination Host Prohibited")) {
die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited"))
} else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) {
die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
else if (strstr(buf, "unknown host"))
} else if (strstr(buf, "unknown host")) {
die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded"))
} else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) {
die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
else if (strstr(buf, "Destination unreachable: "))
} else if (strstr(buf, "Destination unreachable: ")) {
die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) {
if (warn_text == NULL)
warn_text = strdup(_(WARN_DUPLICATES));
else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1)
die(STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
return (STATE_WARNING);
}
return (STATE_OK);
if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) {
if (warn_text == NULL) {
warn_text = strdup(_(WARN_DUPLICATES));
} else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) {
die(STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
}
return STATE_WARNING;
}
return STATE_OK;
}
void print_help(void) {
@ -551,9 +614,7 @@ void print_help(void) {
printf("\n");
printf("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss"));
printf("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output"));
printf("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in"));
printf("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/"));
printf("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output."));
printf(UT_SUPPORT);
}

View file

@ -0,0 +1,46 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#include <stdlib.h>
enum {
UNKNOWN_PACKET_LOSS = 200, /* 200% */
DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */
};
#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
#define MAX_ADDR_START 1
typedef struct {
bool display_html;
int max_packets;
char **addresses;
size_t n_addresses;
int wpl;
int cpl;
double wrta;
double crta;
} check_ping_config;
check_ping_config check_ping_config_init() {
check_ping_config tmp = {
.display_html = false,
.max_packets = -1,
.addresses = NULL,
.n_addresses = 0,
.wpl = UNKNOWN_PACKET_LOSS,
.cpl = UNKNOWN_PACKET_LOSS,
.wrta = UNKNOWN_TRIP_TIME,
.crta = UNKNOWN_TRIP_TIME,
};
tmp.addresses = calloc(MAX_ADDR_START, sizeof(char *));
tmp.addresses[0] = NULL;
return tmp;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,75 @@
#pragma once
#include "../../config.h"
#include "regex.h"
#include "thresholds.h"
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
enum metric {
METRIC_PROCS,
METRIC_VSZ,
METRIC_RSS,
METRIC_CPU,
METRIC_ELAPSED
};
typedef struct {
int options; /* bitmask of filter criteria to test against */
enum metric metric;
char *metric_name;
char *input_filename;
char *prog;
char *args;
char *fmt;
char *fails;
char *exclude_progs;
char **exclude_progs_arr;
char exclude_progs_counter;
regex_t re_args;
bool kthread_filter;
bool usepid; /* whether to test for pid or /proc/pid/exe */
uid_t uid;
pid_t ppid;
int vsz;
int rss;
float pcpu;
char *statopts;
char *warning_range;
char *critical_range;
thresholds *procs_thresholds;
} check_procs_config;
check_procs_config check_procs_config_init() {
check_procs_config tmp = {
.options = 0,
.metric = METRIC_PROCS,
.metric_name = strdup("PROCS"),
.input_filename = NULL,
.prog = NULL,
.args = NULL,
.fmt = NULL,
.fails = NULL,
.exclude_progs = NULL,
.exclude_progs_arr = NULL,
.exclude_progs_counter = 0,
.re_args = {0},
.kthread_filter = false,
.usepid = false,
.uid = 0,
.ppid = 0,
.vsz = 0,
.rss = 0,
.pcpu = 0,
.statopts = NULL,
.warning_range = NULL,
.critical_range = NULL,
.procs_thresholds = NULL,
};
return tmp;
}

View file

@ -1,32 +1,32 @@
/*****************************************************************************
*
* Monitoring check_radius plugin
*
* License: GPL
* Copyright (c) 1999-2024 Monitoring Plugins Development Team
*
* Description:
*
* This file contains the check_radius plugin
*
* Tests to see if a radius server is accepting connections.
*
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
*
* Monitoring check_radius plugin
*
* License: GPL
* Copyright (c) 1999-2024 Monitoring Plugins Development Team
*
* Description:
*
* This file contains the check_radius plugin
*
* Tests to see if a radius server is accepting connections.
*
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
const char *progname = "check_radius";
const char *copyright = "2000-2024";
@ -35,64 +35,57 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "utils.h"
#include "netutils.h"
#include "states.h"
#include "check_radius.d/config.h"
#if defined(HAVE_LIBRADCLI)
#include <radcli/radcli.h>
# include <radcli/radcli.h>
#elif defined(HAVE_LIBFREERADIUS_CLIENT)
#include <freeradius-client.h>
# include <freeradius-client.h>
#elif defined(HAVE_LIBRADIUSCLIENT_NG)
#include <radiusclient-ng.h>
# include <radiusclient-ng.h>
#else
#include <radiusclient.h>
# include <radiusclient.h>
#endif
static int process_arguments (int /*argc*/, char ** /*argv*/);
static void print_help (void);
void print_usage (void);
typedef struct {
int errorcode;
check_radius_config config;
} check_radius_config_wrapper;
static check_radius_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
#define my_rc_conf_str(a) rc_conf_str(rch,a)
#if defined(HAVE_LIBRADCLI)
#define my_rc_send_server(a,b) rc_send_server(rch,a,b,AUTH)
# define my_rc_conf_str(a) rc_conf_str(rch, a)
# if defined(HAVE_LIBRADCLI)
# define my_rc_send_server(a, b) rc_send_server(rch, a, b, AUTH)
# else
# define my_rc_send_server(a, b) rc_send_server(rch, a, b)
# endif
# if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI)
# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, (a)->secret, e, f)
# else
# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, e, f)
# endif
# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(rch, a, b, c, -1, d)
# define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
#else
#define my_rc_send_server(a,b) rc_send_server(rch,a,b)
#endif
#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI)
#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,(a)->secret,e,f)
#else
#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,e,f)
#endif
#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(rch,a,b,c,-1,d)
#define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
#else
#define my_rc_conf_str(a) rc_conf_str(a)
#define my_rc_send_server(a,b) rc_send_server(a, b)
#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(a,b,c,d,e,f)
#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(a, b, c, d)
#define my_rc_read_dictionary(a) rc_read_dictionary(a)
# define my_rc_conf_str(a) rc_conf_str(a)
# define my_rc_send_server(a, b) rc_send_server(a, b)
# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(a, b, c, d, e, f)
# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(a, b, c, d)
# define my_rc_read_dictionary(a) rc_read_dictionary(a)
#endif
/* REJECT_RC is only defined in some version of radiusclient. It has
* been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */
#ifndef REJECT_RC
#define REJECT_RC BADRESP_RC
# define REJECT_RC BADRESP_RC
#endif
static int my_rc_read_config(char * /*a*/);
static int my_rc_read_config(char * /*a*/, rc_handle ** /*rch*/);
#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
static rc_handle *rch = NULL;
#endif
static char *server = NULL;
static char *username = NULL;
static char *password = NULL;
static char *nasid = NULL;
static char *nasipaddress = NULL;
static char *expect = NULL;
static char *config_file = NULL;
static unsigned short port = PW_AUTH_UDP_PORT;
static int retries = 1;
static bool verbose = false;
/******************************************************************************
@ -148,149 +141,167 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
-@@
******************************************************************************/
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
check_radius_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
check_radius_config config = tmp_config.config;
#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
rc_handle *rch = NULL;
#endif
char *str = strdup("dictionary");
if ((config.config_file && my_rc_read_config(config.config_file, &rch)) || my_rc_read_dictionary(my_rc_conf_str(str))) {
die(STATE_UNKNOWN, _("Config file error\n"));
}
uint32_t service = PW_AUTHENTICATE_ONLY;
SEND_DATA data;
memset(&data, 0, sizeof(data));
if (!(my_rc_avpair_add(&data.send_pairs, PW_SERVICE_TYPE, &service, 0) &&
my_rc_avpair_add(&data.send_pairs, PW_USER_NAME, config.username, 0) &&
my_rc_avpair_add(&data.send_pairs, PW_USER_PASSWORD, config.password, 0))) {
die(STATE_UNKNOWN, _("Out of Memory?\n"));
}
if (config.nas_id != NULL) {
if (!(my_rc_avpair_add(&data.send_pairs, PW_NAS_IDENTIFIER, config.nas_id, 0))) {
die(STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
}
}
int
main (int argc, char **argv)
{
struct sockaddr_storage ss;
char name[HOST_NAME_MAX];
if (config.nas_ip_address == NULL) {
if (gethostname(name, sizeof(name)) != 0) {
die(STATE_UNKNOWN, _("gethostname() failed!\n"));
}
config.nas_ip_address = name;
}
struct sockaddr_storage radius_server_socket;
if (!dns_lookup(config.nas_ip_address, &radius_server_socket, AF_UNSPEC)) {
die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
}
uint32_t client_id = ntohl(((struct sockaddr_in *)&radius_server_socket)->sin_addr.s_addr);
if (my_rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL) {
die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
}
my_rc_buildreq(&data, PW_ACCESS_REQUEST, config.server, config.port, (int)timeout_interval, config.retries);
#ifdef RC_BUFFER_LEN
char msg[RC_BUFFER_LEN];
#else
char msg[BUFFER_LEN];
#endif
SEND_DATA data;
int result = STATE_UNKNOWN;
uint32_t client_id, service;
char *str;
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
/* Parse extra opts if any */
argv=np_extra_opts (&argc, argv, progname);
if (process_arguments (argc, argv) == ERROR)
usage4 (_("Could not parse arguments"));
str = strdup ("dictionary");
if ((config_file && my_rc_read_config (config_file)) ||
my_rc_read_dictionary (my_rc_conf_str (str)))
die (STATE_UNKNOWN, _("Config file error\n"));
service = PW_AUTHENTICATE_ONLY;
memset (&data, 0, sizeof(data));
if (!(my_rc_avpair_add (&data.send_pairs, PW_SERVICE_TYPE, &service, 0) &&
my_rc_avpair_add (&data.send_pairs, PW_USER_NAME, username, 0) &&
my_rc_avpair_add (&data.send_pairs, PW_USER_PASSWORD, password, 0)
))
die (STATE_UNKNOWN, _("Out of Memory?\n"));
if (nasid != NULL) {
if (!(my_rc_avpair_add (&data.send_pairs, PW_NAS_IDENTIFIER, nasid, 0)))
die (STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
int result = my_rc_send_server(&data, msg);
rc_avpair_free(data.send_pairs);
if (data.receive_pairs) {
rc_avpair_free(data.receive_pairs);
}
if (nasipaddress == NULL) {
if (gethostname (name, sizeof(name)) != 0)
die (STATE_UNKNOWN, _("gethostname() failed!\n"));
nasipaddress = name;
if (result == TIMEOUT_RC) {
printf("Timeout\n");
exit(STATE_CRITICAL);
}
if (!dns_lookup (nasipaddress, &ss, AF_INET)) /* TODO: Support IPv6. */
die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
client_id = ntohl (((struct sockaddr_in *)&ss)->sin_addr.s_addr);
if (my_rc_avpair_add (&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
my_rc_buildreq (&data, PW_ACCESS_REQUEST, server, port, (int)timeout_interval,
retries);
if (result == ERROR_RC) {
printf(_("Auth Error\n"));
exit(STATE_CRITICAL);
}
result = my_rc_send_server (&data, msg);
rc_avpair_free (data.send_pairs);
if (data.receive_pairs)
rc_avpair_free (data.receive_pairs);
if (result == REJECT_RC) {
printf(_("Auth Failed\n"));
exit(STATE_WARNING);
}
if (result == BADRESP_RC) {
printf(_("Bad Response\n"));
exit(STATE_WARNING);
}
if (config.expect && !strstr(msg, config.expect)) {
printf("%s\n", msg);
exit(STATE_WARNING);
}
if (result == OK_RC) {
printf(_("Auth OK\n"));
exit(STATE_OK);
}
if (result == TIMEOUT_RC)
die (STATE_CRITICAL, _("Timeout\n"));
if (result == ERROR_RC)
die (STATE_CRITICAL, _("Auth Error\n"));
if (result == REJECT_RC)
die (STATE_WARNING, _("Auth Failed\n"));
if (result == BADRESP_RC)
die (STATE_WARNING, _("Bad Response\n"));
if (expect && !strstr (msg, expect))
die (STATE_WARNING, "%s\n", msg);
if (result == OK_RC)
die (STATE_OK, _("Auth OK\n"));
(void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result);
die (STATE_UNKNOWN, "%s\n", msg);
printf("%s\n", msg);
exit(STATE_UNKNOWN);
}
/* process command-line arguments */
int
process_arguments (int argc, char **argv)
{
int c;
check_radius_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'P'},
{"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'},
{"nas-id", required_argument, 0, 'n'}, {"nas-ip-address", required_argument, 0, 'N'},
{"filename", required_argument, 0, 'F'}, {"expect", required_argument, 0, 'e'},
{"retries", required_argument, 0, 'r'}, {"timeout", required_argument, 0, 't'},
{"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
int option = 0;
static struct option longopts[] = {
{"hostname", required_argument, 0, 'H'},
{"port", required_argument, 0, 'P'},
{"username", required_argument, 0, 'u'},
{"password", required_argument, 0, 'p'},
{"nas-id", required_argument, 0, 'n'},
{"nas-ip-address", required_argument, 0, 'N'},
{"filename", required_argument, 0, 'F'},
{"expect", required_argument, 0, 'e'},
{"retries", required_argument, 0, 'r'},
{"timeout", required_argument, 0, 't'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
check_radius_config_wrapper result = {
.errorcode = OK,
.config = check_radius_config_init(),
};
while (1) {
c = getopt_long (argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts,
&option);
while (true) {
int option = 0;
int option_index = getopt_long(argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, &option);
if (c == -1 || c == EOF || c == 1)
if (option_index == -1 || option_index == EOF || option_index == 1) {
break;
}
switch (c) {
case '?': /* print short usage statement if args not parsable */
usage5 ();
case 'h': /* help */
print_help ();
exit (STATE_UNKNOWN);
case 'V': /* version */
print_revision (progname, NP_VERSION);
exit (STATE_UNKNOWN);
case 'v': /* verbose mode */
switch (option_index) {
case '?': /* print short usage statement if args not parsable */
usage5();
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
case 'V': /* version */
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 'v': /* verbose mode */
verbose = true;
break;
case 'H': /* hostname */
if (!is_host (optarg)) {
usage2 (_("Invalid hostname/address"), optarg);
case 'H': /* hostname */
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
}
server = optarg;
result.config.server = optarg;
break;
case 'P': /* port */
if (is_intnonneg (optarg))
port = (unsigned short)atoi (optarg);
else
usage4 (_("Port must be a positive integer"));
case 'P': /* port */
if (is_intnonneg(optarg)) {
result.config.port = (unsigned short)atoi(optarg);
} else {
usage4(_("Port must be a positive integer"));
}
break;
case 'u': /* username */
username = optarg;
case 'u': /* username */
result.config.username = optarg;
break;
case 'p': /* password */
password = strdup(optarg);
case 'p': /* password */
result.config.password = strdup(optarg);
/* Delete the password from process list */
while (*optarg != '\0') {
@ -298,119 +309,115 @@ process_arguments (int argc, char **argv)
optarg++;
}
break;
case 'n': /* nas id */
nasid = optarg;
case 'n': /* nas id */
result.config.nas_id = optarg;
break;
case 'N': /* nas ip address */
nasipaddress = optarg;
case 'N': /* nas ip address */
result.config.nas_ip_address = optarg;
break;
case 'F': /* configuration file */
config_file = optarg;
case 'F': /* configuration file */
result.config.config_file = optarg;
break;
case 'e': /* expect */
expect = optarg;
case 'e': /* expect */
result.config.expect = optarg;
break;
case 'r': /* retries */
if (is_intpos (optarg))
retries = atoi (optarg);
else
usage4 (_("Number of retries must be a positive integer"));
case 'r': /* retries */
if (is_intpos(optarg)) {
result.config.retries = atoi(optarg);
} else {
usage4(_("Number of retries must be a positive integer"));
}
break;
case 't': /* timeout */
if (is_intpos (optarg))
timeout_interval = (unsigned)atoi (optarg);
else
usage2 (_("Timeout interval must be a positive integer"), optarg);
case 't': /* timeout */
if (is_intpos(optarg)) {
timeout_interval = (unsigned)atoi(optarg);
} else {
usage2(_("Timeout interval must be a positive integer"), optarg);
}
break;
}
}
if (server == NULL)
usage4 (_("Hostname was not supplied"));
if (username == NULL)
usage4 (_("User not specified"));
if (password == NULL)
usage4 (_("Password not specified"));
if (config_file == NULL)
usage4 (_("Configuration file not specified"));
if (result.config.server == NULL) {
usage4(_("Hostname was not supplied"));
}
if (result.config.username == NULL) {
usage4(_("User not specified"));
}
if (result.config.password == NULL) {
usage4(_("Password not specified"));
}
if (result.config.config_file == NULL) {
usage4(_("Configuration file not specified"));
}
return OK;
return result;
}
void
print_help (void)
{
void print_help(void) {
char *myport;
xasprintf (&myport, "%d", PW_AUTH_UDP_PORT);
xasprintf(&myport, "%d", PW_AUTH_UDP_PORT);
print_revision (progname, NP_VERSION);
print_revision(progname, NP_VERSION);
printf ("Copyright (c) 1999 Robert August Vincent II\n");
printf (COPYRIGHT, copyright, email);
printf("Copyright (c) 1999 Robert August Vincent II\n");
printf(COPYRIGHT, copyright, email);
printf("%s\n", _("Tests to see if a RADIUS server is accepting connections."));
printf ("\n\n");
printf("\n\n");
print_usage ();
print_usage();
printf (UT_HELP_VRSN);
printf (UT_EXTRA_OPTS);
printf(UT_HELP_VRSN);
printf(UT_EXTRA_OPTS);
printf (UT_HOST_PORT, 'P', myport);
printf(UT_HOST_PORT, 'P', myport);
printf (" %s\n", "-u, --username=STRING");
printf (" %s\n", _("The user to authenticate"));
printf (" %s\n", "-p, --password=STRING");
printf (" %s\n", _("Password for authentication (SECURITY RISK)"));
printf (" %s\n", "-n, --nas-id=STRING");
printf (" %s\n", _("NAS identifier"));
printf (" %s\n", "-N, --nas-ip-address=STRING");
printf (" %s\n", _("NAS IP Address"));
printf (" %s\n", "-F, --filename=STRING");
printf (" %s\n", _("Configuration file"));
printf (" %s\n", "-e, --expect=STRING");
printf (" %s\n", _("Response string to expect from the server"));
printf (" %s\n", "-r, --retries=INTEGER");
printf (" %s\n", _("Number of times to retry a failed connection"));
printf(" %s\n", "-u, --username=STRING");
printf(" %s\n", _("The user to authenticate"));
printf(" %s\n", "-p, --password=STRING");
printf(" %s\n", _("Password for authentication (SECURITY RISK)"));
printf(" %s\n", "-n, --nas-id=STRING");
printf(" %s\n", _("NAS identifier"));
printf(" %s\n", "-N, --nas-ip-address=STRING");
printf(" %s\n", _("NAS IP Address"));
printf(" %s\n", "-F, --filename=STRING");
printf(" %s\n", _("Configuration file"));
printf(" %s\n", "-e, --expect=STRING");
printf(" %s\n", _("Response string to expect from the server"));
printf(" %s\n", "-r, --retries=INTEGER");
printf(" %s\n", _("Number of times to retry a failed connection"));
printf (UT_CONN_TIMEOUT, timeout_interval);
printf(UT_CONN_TIMEOUT, timeout_interval);
printf ("\n");
printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections."));
printf ("%s\n", _("The server to test must be specified in the invocation, as well as a user"));
printf ("%s\n", _("name and password. A configuration file must be present. The format of"));
printf ("%s\n", _("the configuration file is described in the radiusclient library sources."));
printf ("%s\n", _("The password option presents a substantial security issue because the"));
printf ("%s\n", _("password can possibly be determined by careful watching of the command line"));
printf ("%s\n", _("in a process listing. This risk is exacerbated because the plugin will"));
printf ("%s\n", _("typically be executed at regular predictable intervals. Please be sure that"));
printf ("%s\n", _("the password used does not allow access to sensitive system resources."));
printf("\n");
printf("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections."));
printf("%s\n", _("The server to test must be specified in the invocation, as well as a user"));
printf("%s\n", _("name and password. A configuration file must be present. The format of"));
printf("%s\n", _("the configuration file is described in the radiusclient library sources."));
printf("%s\n", _("The password option presents a substantial security issue because the"));
printf("%s\n", _("password can possibly be determined by careful watching of the command line"));
printf("%s\n", _("in a process listing. This risk is exacerbated because the plugin will"));
printf("%s\n", _("typically be executed at regular predictable intervals. Please be sure that"));
printf("%s\n", _("the password used does not allow access to sensitive system resources."));
printf (UT_SUPPORT);
printf(UT_SUPPORT);
}
void
print_usage (void)
{
printf ("%s\n", _("Usage:"));
printf ("%s -H host -F config_file -u username -p password\n\
void print_usage(void) {
printf("%s\n", _("Usage:"));
printf("%s -H host -F config_file -u username -p password\n\
[-P port] [-t timeout] [-r retries] [-e expect]\n\
[-n nas-id] [-N nas-ip-addr]\n", progname);
[-n nas-id] [-N nas-ip-addr]\n",
progname);
}
int my_rc_read_config(char * a)
{
int my_rc_read_config(char *config_file_name, rc_handle **rch) {
#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
rch = rc_read_config(a);
*rch = rc_read_config(config_file_name);
return (rch == NULL) ? 1 : 0;
#else
return rc_read_config(a);
return rc_read_config(config_file_name);
#endif
}

View file

@ -0,0 +1,42 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#if defined(HAVE_LIBRADCLI)
# include <radcli/radcli.h>
#elif defined(HAVE_LIBFREERADIUS_CLIENT)
# include <freeradius-client.h>
#elif defined(HAVE_LIBRADIUSCLIENT_NG)
# include <radiusclient-ng.h>
#else
# include <radiusclient.h>
#endif
typedef struct {
char *server;
char *username;
char *password;
char *config_file;
char *nas_id;
char *nas_ip_address;
int retries;
unsigned short port;
char *expect;
} check_radius_config;
check_radius_config check_radius_config_init() {
check_radius_config tmp = {
.server = NULL,
.username = NULL,
.password = NULL,
.config_file = NULL,
.nas_id = NULL,
.nas_ip_address = NULL,
.retries = 1,
.port = PW_AUTH_UDP_PORT,
.expect = NULL,
};
return tmp;
}

View file

@ -28,6 +28,8 @@
*
*****************************************************************************/
#include "states.h"
#include <stdio.h>
const char *progname = "check_real";
const char *copyright = "2000-2024";
const char *email = "devel@monitoring-plugins.org";
@ -35,27 +37,20 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
enum {
PORT = 554
};
#include "check_real.d/config.h"
#define EXPECT "RTSP/1."
#define URL ""
static int process_arguments(int, char **);
typedef struct {
int errorcode;
check_real_config config;
} check_real_config_wrapper;
static check_real_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
static int server_port = PORT;
static char *server_address;
static char *host_name;
static char *server_url = NULL;
static char *server_expect;
static int warning_time = 0;
static bool check_warning_time = false;
static int critical_time = 0;
static bool check_critical_time = false;
static bool verbose = false;
int main(int argc, char **argv) {
@ -66,8 +61,12 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_real_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_real_config config = tmp_config.config;
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
@ -78,38 +77,51 @@ int main(int argc, char **argv) {
/* try to connect to the host at the given port number */
int socket;
if (my_tcp_connect(server_address, server_port, &socket) != STATE_OK)
die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), server_address, server_port);
if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) {
die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), config.server_address, config.server_port);
}
/* Part I - Server Check */
/* send the OPTIONS request */
char buffer[MAX_INPUT_BUFFER];
sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", host_name, server_port);
int result = send(socket, buffer, strlen(buffer), 0);
sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port);
ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
if (sent_bytes == -1) {
die(STATE_CRITICAL, _("Sending options to %s failed\n"), config.host_name);
}
/* send the header sync */
sprintf(buffer, "CSeq: 1\r\n");
result = send(socket, buffer, strlen(buffer), 0);
sent_bytes = send(socket, buffer, strlen(buffer), 0);
if (sent_bytes == -1) {
die(STATE_CRITICAL, _("Sending header sync to %s failed\n"), config.host_name);
}
/* send a newline so the server knows we're done with the request */
sprintf(buffer, "\r\n");
result = send(socket, buffer, strlen(buffer), 0);
sent_bytes = send(socket, buffer, strlen(buffer), 0);
if (sent_bytes == -1) {
die(STATE_CRITICAL, _("Sending newline to %s failed\n"), config.host_name);
}
/* watch for the REAL connection string */
result = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
ssize_t received_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
/* return a CRITICAL status if we couldn't read any data */
if (result == -1)
die(STATE_CRITICAL, _("No data received from %s\n"), host_name);
if (received_bytes == -1) {
die(STATE_CRITICAL, _("No data received from %s\n"), config.host_name);
}
mp_state_enum result = STATE_OK;
char *status_line = NULL;
/* make sure we find the response we are looking for */
if (!strstr(buffer, server_expect)) {
if (server_port == PORT)
if (!strstr(buffer, config.server_expect)) {
if (config.server_port == PORT) {
printf("%s\n", _("Invalid REAL response received from host"));
else
printf(_("Invalid REAL response received from host on port %d\n"), server_port);
} else {
printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
}
} else {
/* else we got the REAL string, so check the return code */
@ -117,69 +129,79 @@ int main(int argc, char **argv) {
result = STATE_OK;
status_line = (char *)strtok(buffer, "\n");
status_line = strtok(buffer, "\n");
if (strstr(status_line, "200"))
if (strstr(status_line, "200")) {
result = STATE_OK;
}
/* client errors result in a warning state */
else if (strstr(status_line, "400"))
else if (strstr(status_line, "400")) {
result = STATE_WARNING;
else if (strstr(status_line, "401"))
} else if (strstr(status_line, "401")) {
result = STATE_WARNING;
else if (strstr(status_line, "402"))
} else if (strstr(status_line, "402")) {
result = STATE_WARNING;
else if (strstr(status_line, "403"))
} else if (strstr(status_line, "403")) {
result = STATE_WARNING;
else if (strstr(status_line, "404"))
} else if (strstr(status_line, "404")) {
result = STATE_WARNING;
/* server errors result in a critical state */
else if (strstr(status_line, "500"))
} else if (strstr(status_line, "500")) {
/* server errors result in a critical state */
result = STATE_CRITICAL;
else if (strstr(status_line, "501"))
} else if (strstr(status_line, "501")) {
result = STATE_CRITICAL;
else if (strstr(status_line, "502"))
} else if (strstr(status_line, "502")) {
result = STATE_CRITICAL;
else if (strstr(status_line, "503"))
} else if (strstr(status_line, "503")) {
result = STATE_CRITICAL;
else
} else {
result = STATE_UNKNOWN;
}
}
/* Part II - Check stream exists and is ok */
if ((result == STATE_OK) && (server_url != NULL)) {
if ((result == STATE_OK) && (config.server_url != NULL)) {
/* Part I - Server Check */
/* send the DESCRIBE request */
sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", host_name, server_port, server_url);
result = send(socket, buffer, strlen(buffer), 0);
sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name, config.server_port, config.server_url);
ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
if (sent_bytes == -1) {
die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
}
/* send the header sync */
sprintf(buffer, "CSeq: 2\r\n");
result = send(socket, buffer, strlen(buffer), 0);
sent_bytes = send(socket, buffer, strlen(buffer), 0);
if (sent_bytes == -1) {
die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
}
/* send a newline so the server knows we're done with the request */
sprintf(buffer, "\r\n");
result = send(socket, buffer, strlen(buffer), 0);
sent_bytes = send(socket, buffer, strlen(buffer), 0);
if (sent_bytes == -1) {
die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
}
/* watch for the REAL connection string */
result = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
buffer[result] = '\0'; /* null terminate received buffer */
/* return a CRITICAL status if we couldn't read any data */
if (result == -1) {
ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
if (recv_bytes == -1) {
/* return a CRITICAL status if we couldn't read any data */
printf(_("No data received from host\n"));
result = STATE_CRITICAL;
} else {
buffer[result] = '\0'; /* null terminate received buffer */
/* make sure we find the response we are looking for */
if (!strstr(buffer, server_expect)) {
if (server_port == PORT)
if (!strstr(buffer, config.server_expect)) {
if (config.server_port == PORT) {
printf("%s\n", _("Invalid REAL response received from host"));
else
printf(_("Invalid REAL response received from host on port %d\n"), server_port);
} else {
printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
}
} else {
/* else we got the REAL string, so check the return code */
@ -188,51 +210,56 @@ int main(int argc, char **argv) {
result = STATE_OK;
status_line = (char *)strtok(buffer, "\n");
status_line = strtok(buffer, "\n");
if (strstr(status_line, "200"))
if (strstr(status_line, "200")) {
result = STATE_OK;
}
/* client errors result in a warning state */
else if (strstr(status_line, "400"))
else if (strstr(status_line, "400")) {
result = STATE_WARNING;
else if (strstr(status_line, "401"))
} else if (strstr(status_line, "401")) {
result = STATE_WARNING;
else if (strstr(status_line, "402"))
} else if (strstr(status_line, "402")) {
result = STATE_WARNING;
else if (strstr(status_line, "403"))
} else if (strstr(status_line, "403")) {
result = STATE_WARNING;
else if (strstr(status_line, "404"))
} else if (strstr(status_line, "404")) {
result = STATE_WARNING;
}
/* server errors result in a critical state */
else if (strstr(status_line, "500"))
else if (strstr(status_line, "500")) {
result = STATE_CRITICAL;
else if (strstr(status_line, "501"))
} else if (strstr(status_line, "501")) {
result = STATE_CRITICAL;
else if (strstr(status_line, "502"))
} else if (strstr(status_line, "502")) {
result = STATE_CRITICAL;
else if (strstr(status_line, "503"))
} else if (strstr(status_line, "503")) {
result = STATE_CRITICAL;
}
else
else {
result = STATE_UNKNOWN;
}
}
}
}
/* Return results */
if (result == STATE_OK) {
if (check_critical_time && (end_time - start_time) > critical_time)
if (config.check_critical_time && (end_time - start_time) > config.critical_time) {
result = STATE_CRITICAL;
else if (check_warning_time && (end_time - start_time) > warning_time)
} else if (config.check_warning_time && (end_time - start_time) > config.warning_time) {
result = STATE_WARNING;
}
/* Put some HTML in here to create a dynamic link */
printf(_("REAL %s - %d second response time\n"), state_text(result), (int)(end_time - start_time));
} else
} else {
printf("%s\n", status_line);
}
/* close the connection */
close(socket);
@ -240,11 +267,11 @@ int main(int argc, char **argv) {
/* reset the alarm */
alarm(0);
return result;
exit(result);
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
check_real_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'},
{"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'},
{"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'},
@ -252,61 +279,70 @@ int process_arguments(int argc, char **argv) {
{"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
if (argc < 2)
return ERROR;
check_real_config_wrapper result = {
.errorcode = OK,
.config = check_real_config_init(),
};
for (int i = 1; i < argc; i++) {
if (strcmp("-to", argv[i]) == 0)
strcpy(argv[i], "-t");
else if (strcmp("-wt", argv[i]) == 0)
strcpy(argv[i], "-w");
else if (strcmp("-ct", argv[i]) == 0)
strcpy(argv[i], "-c");
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
for (int i = 1; i < argc; i++) {
if (strcmp("-to", argv[i]) == 0) {
strcpy(argv[i], "-t");
} else if (strcmp("-wt", argv[i]) == 0) {
strcpy(argv[i], "-w");
} else if (strcmp("-ct", argv[i]) == 0) {
strcpy(argv[i], "-c");
}
}
int option_char;
while (true) {
int option = 0;
option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option);
int option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option);
if (option_char == -1 || option_char == EOF)
if (option_char == -1 || option_char == EOF) {
break;
}
switch (option_char) {
case 'I': /* hostname */
case 'H': /* hostname */
if (server_address)
if (result.config.server_address) {
break;
else if (is_host(optarg))
server_address = optarg;
else
} else if (is_host(optarg)) {
result.config.server_address = optarg;
} else {
usage2(_("Invalid hostname/address"), optarg);
}
break;
case 'e': /* string to expect in response header */
server_expect = optarg;
result.config.server_expect = optarg;
break;
case 'u': /* server URL */
server_url = optarg;
result.config.server_url = optarg;
break;
case 'p': /* port */
if (is_intpos(optarg)) {
server_port = atoi(optarg);
result.config.server_port = atoi(optarg);
} else {
usage4(_("Port must be a positive integer"));
}
break;
case 'w': /* warning time threshold */
if (is_intnonneg(optarg)) {
warning_time = atoi(optarg);
check_warning_time = true;
result.config.warning_time = atoi(optarg);
result.config.check_warning_time = true;
} else {
usage4(_("Warning time must be a positive integer"));
}
break;
case 'c': /* critical time threshold */
if (is_intnonneg(optarg)) {
critical_time = atoi(optarg);
check_critical_time = true;
result.config.critical_time = atoi(optarg);
result.config.check_critical_time = true;
} else {
usage4(_("Critical time must be a positive integer"));
}
@ -332,25 +368,28 @@ int process_arguments(int argc, char **argv) {
}
}
option_char = optind;
if (server_address == NULL && argc > option_char) {
int option_char = optind;
if (result.config.server_address == NULL && argc > option_char) {
if (is_host(argv[option_char])) {
server_address = argv[option_char++];
result.config.server_address = argv[option_char++];
} else {
usage2(_("Invalid hostname/address"), argv[option_char]);
}
}
if (server_address == NULL)
if (result.config.server_address == NULL) {
usage4(_("You must provide a server to check"));
}
if (host_name == NULL)
host_name = strdup(server_address);
if (result.config.host_name == NULL) {
result.config.host_name = strdup(result.config.server_address);
}
if (server_expect == NULL)
server_expect = strdup(EXPECT);
if (result.config.server_expect == NULL) {
result.config.server_expect = strdup(EXPECT);
}
return OK;
return result;
}
void print_help(void) {

View file

@ -0,0 +1,37 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
enum {
PORT = 554
};
typedef struct {
char *server_address;
char *host_name;
int server_port;
char *server_url;
char *server_expect;
int warning_time;
bool check_warning_time;
int critical_time;
bool check_critical_time;
} check_real_config;
check_real_config check_real_config_init() {
check_real_config tmp = {
.server_address = NULL,
.host_name = NULL,
.server_port = PORT,
.server_url = NULL,
.server_expect = NULL,
.warning_time = 0,
.check_warning_time = false,
.critical_time = 0,
.check_critical_time = false,
};
return tmp;
}

View file

@ -90,6 +90,14 @@ int main(int argc, char **argv) {
exit(STATE_UNKNOWN);
}
if (verbose) {
printf("Swap retrieval result:\n"
"\tFree: %llu\n"
"\tUsed: %llu\n"
"\tTotal: %llu\n",
data.metrics.free, data.metrics.used, data.metrics.total);
}
double percent_used;
mp_check overall = mp_check_init();
if (config.output_format_is_set) {

View file

@ -1,7 +1,8 @@
#pragma once
#include "../common.h"
#include "output.h"
#include "../../lib/output.h"
#include "../../lib/states.h"
#ifndef SWAP_CONVERSION
# define SWAP_CONVERSION 1
@ -26,7 +27,7 @@ typedef struct {
typedef struct {
bool allswaps;
int no_swap_state;
mp_state_enum no_swap_state;
bool warn_is_set;
check_swap_threshold warn;
bool crit_is_set;

View file

@ -68,7 +68,7 @@ swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
FILE *meminfo_file_ptr;
meminfo_file_ptr = fopen(proc_meminfo, "r");
swap_result result = {0};
swap_result result = {};
result.errorcode = STATE_UNKNOWN;
if (meminfo_file_ptr == NULL) {
@ -78,83 +78,71 @@ swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
return result;
}
uint64_t swap_total = 0;
uint64_t swap_used = 0;
uint64_t swap_free = 0;
unsigned long swap_total = 0;
unsigned long swap_used = 0;
unsigned long swap_free = 0;
bool found_total = false;
bool found_used = false;
bool found_free = false;
char input_buffer[MAX_INPUT_BUFFER];
char str[32];
while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) {
uint64_t tmp_KB = 0;
/*
* The following sscanf call looks for a line looking like: "Swap: 123
* 123 123" On which kind of system this format exists, I can not say,
* but I wanted to document this for people who are not adapt with
* sscanf anymore, like me
* Also the units used here are unclear and probably wrong
* 123 123" which exists on NetBSD (at least),
* The unit should be Bytes
*/
if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, &swap_free) == 3) {
result.metrics.total += swap_total;
result.metrics.used += swap_used;
result.metrics.free += swap_free;
found_total = true;
found_free = true;
found_used = true;
// Set error
result.errorcode = STATE_OK;
// Break out of fgets here, since both scanf expressions might match (NetBSD for example)
break;
}
/*
* The following sscanf call looks for lines looking like:
* "SwapTotal: 123" and "SwapFree: 123" This format exists at least
* on Debian Linux with a 5.* kernel
*/
} else {
int sscanf_result = sscanf(input_buffer,
"%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu "
"%*[k]%*[B]",
str, &tmp_KB);
/*
* The following sscanf call looks for lines looking like:
* "SwapTotal: 123" and "SwapFree: 123" This format exists at least
* on Debian Linux with a 5.* kernel
*/
unsigned long tmp_KB = 0;
int sscanf_result = sscanf(input_buffer,
"%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu "
"%*[k]%*[B]",
str, &tmp_KB);
if (sscanf_result == 2) {
if (sscanf_result == 2) {
if (verbose >= 3) {
printf("Got %s with %lu\n", str, tmp_KB);
}
/* I think this part is always in Kb, so convert to bytes */
if (strcmp("Total", str) == 0) {
swap_total = tmp_KB * 1000;
found_total = true;
} else if (strcmp("Free", str) == 0) {
swap_free = swap_free + tmp_KB * 1000;
found_free = true;
found_used = true; // No explicit used metric available
} else if (strcmp("Cached", str) == 0) {
swap_free = swap_free + tmp_KB * 1000;
found_free = true;
found_used = true; // No explicit used metric available
}
result.errorcode = STATE_OK;
if (verbose >= 3) {
printf("Got %s with %lu\n", str, tmp_KB);
}
/* I think this part is always in Kb, so convert to bytes */
if (strcmp("Total", str) == 0) {
swap_total = tmp_KB * 1000;
found_total = true;
} else if (strcmp("Free", str) == 0) {
swap_free += tmp_KB * 1000;
found_free = true;
} else if (strcmp("Cached", str) == 0) {
swap_free += tmp_KB * 1000;
}
result.errorcode = STATE_OK;
}
}
fclose(meminfo_file_ptr);
result.metrics.total = swap_total;
result.metrics.used = swap_total - swap_free;
result.metrics.free = swap_free;
result.metrics.used = swap_total - swap_free;
if (!found_free || !found_total || !found_used) {
if (!found_free || !found_total) {
result.errorcode = STATE_UNKNOWN;
}
@ -297,8 +285,14 @@ struct swapent {
};
#else
// Includes for NetBSD
# include <unistd.h>
# include <sys/swap.h>
# define bsd_swapctl swapctl
#endif
#endif // CHECK_SWAP_SWAPCTL_BSD
swap_result getSwapFromSwapctl_BSD(swap_config config) {
/* get the number of active swap devices */
@ -322,8 +316,8 @@ swap_result getSwapFromSwapctl_BSD(swap_config config) {
unsigned long long used_swap_mb = 0;
for (int i = 0; i < nswaps; i++) {
dsktotal_mb = (float)ent[i].se_nblks / (float)config.conversion_factor;
dskused_mb = (float)ent[i].se_inuse / (float)config.conversion_factor;
dsktotal_mb = (double)ent[i].se_nblks / (double)config.conversion_factor;
dskused_mb = (double)ent[i].se_inuse / (double)config.conversion_factor;
dskfree_mb = (dsktotal_mb - dskused_mb);
if (config.allswaps && dsktotal_mb > 0) {

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,84 @@
#pragma once
#include "../../lib/utils_tcp.h"
#include "output.h"
#include "states.h"
#include <netinet/in.h>
typedef struct {
char *server_address;
bool host_specified;
int server_port; // TODO can this be a uint16?
int protocol; /* most common is default */
char *service;
char *send;
char *quit;
char **server_expect;
size_t server_expect_count;
bool use_tls;
#ifdef HAVE_SSL
char *sni;
bool sni_specified;
bool check_cert;
int days_till_exp_warn;
int days_till_exp_crit;
#endif // HAVE_SSL
int match_flags;
mp_state_enum expect_mismatch_state;
unsigned int delay;
bool warning_time_set;
double warning_time;
bool critical_time_set;
double critical_time;
mp_state_enum econn_refuse_state;
ssize_t maxbytes;
bool hide_output;
bool output_format_set;
mp_output_format output_format;
} check_tcp_config;
check_tcp_config check_tcp_config_init() {
check_tcp_config result = {
.server_address = "127.0.0.1",
.host_specified = false,
.server_port = 0,
.protocol = IPPROTO_TCP,
.service = "TCP",
.send = NULL,
.quit = NULL,
.server_expect = NULL,
.server_expect_count = 0,
.use_tls = false,
#ifdef HAVE_SSL
.sni = NULL,
.sni_specified = false,
.check_cert = false,
.days_till_exp_warn = 0,
.days_till_exp_crit = 0,
#endif // HAVE_SSL
.match_flags = NP_MATCH_EXACT,
.expect_mismatch_state = STATE_WARNING,
.delay = 0,
.warning_time_set = false,
.warning_time = 0,
.critical_time_set = false,
.critical_time = 0,
.econn_refuse_state = STATE_CRITICAL,
.maxbytes = 0,
.hide_output = false,
.output_format_set = false,
};
return result;
}

View file

@ -28,6 +28,7 @@
*
*****************************************************************************/
#include "states.h"
const char *progname = "check_time";
const char *copyright = "1999-2024";
const char *email = "devel@monitoring-plugins.org";
@ -35,28 +36,15 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
enum {
TIME_PORT = 37
};
#include "check_time.d/config.h"
#define UNIX_EPOCH 2208988800UL
static uint32_t raw_server_time;
static unsigned long server_time, diff_time;
static int warning_time = 0;
static bool check_warning_time = false;
static int critical_time = 0;
static bool check_critical_time = false;
static unsigned long warning_diff = 0;
static bool check_warning_diff = false;
static unsigned long critical_diff = 0;
static bool check_critical_diff = false;
static int server_port = TIME_PORT;
static char *server_address = NULL;
static bool use_udp = false;
static int process_arguments(int, char **);
typedef struct {
int errorcode;
check_time_config config;
} check_time_config_wrapper;
static check_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
@ -68,8 +56,12 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_time_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_time_config config = tmp_config.config;
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
@ -79,37 +71,40 @@ int main(int argc, char **argv) {
time(&start_time);
int socket;
int result = STATE_UNKNOWN;
mp_state_enum result = STATE_UNKNOWN;
/* try to connect to the host at the given port number */
if (use_udp) {
result = my_udp_connect(server_address, server_port, &socket);
if (config.use_udp) {
result = my_udp_connect(config.server_address, config.server_port, &socket);
} else {
result = my_tcp_connect(server_address, server_port, &socket);
result = my_tcp_connect(config.server_address, config.server_port, &socket);
}
if (result != STATE_OK) {
if (check_critical_time)
if (config.check_critical_time) {
result = STATE_CRITICAL;
else if (check_warning_time)
} else if (config.check_warning_time) {
result = STATE_WARNING;
else
} else {
result = STATE_UNKNOWN;
die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), server_address, server_port);
}
die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), config.server_address, config.server_port);
}
if (use_udp) {
if (config.use_udp) {
if (send(socket, "", 0, 0) < 0) {
if (check_critical_time)
if (config.check_critical_time) {
result = STATE_CRITICAL;
else if (check_warning_time)
} else if (config.check_warning_time) {
result = STATE_WARNING;
else
} else {
result = STATE_UNKNOWN;
die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), server_address, server_port);
}
die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), config.server_address, config.server_port);
}
}
/* watch for the connection string */
uint32_t raw_server_time;
result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0);
/* close the connection */
@ -121,48 +116,56 @@ int main(int argc, char **argv) {
/* return a WARNING status if we couldn't read any data */
if (result <= 0) {
if (check_critical_time)
if (config.check_critical_time) {
result = STATE_CRITICAL;
else if (check_warning_time)
} else if (config.check_warning_time) {
result = STATE_WARNING;
else
} else {
result = STATE_UNKNOWN;
die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), server_address, server_port);
}
die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), config.server_address, config.server_port);
}
result = STATE_OK;
time_t conntime = (end_time - start_time);
if (check_critical_time && conntime > critical_time)
if (config.check_critical_time && conntime > config.critical_time) {
result = STATE_CRITICAL;
else if (check_warning_time && conntime > warning_time)
} else if (config.check_warning_time && conntime > config.warning_time) {
result = STATE_WARNING;
}
if (result != STATE_OK)
if (result != STATE_OK) {
die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime,
perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0,
false, 0));
perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
(long)config.critical_time, true, 0, false, 0));
}
unsigned long server_time;
unsigned long diff_time;
server_time = ntohl(raw_server_time) - UNIX_EPOCH;
if (server_time > (unsigned long)end_time)
if (server_time > (unsigned long)end_time) {
diff_time = server_time - (unsigned long)end_time;
else
} else {
diff_time = (unsigned long)end_time - server_time;
}
if (check_critical_diff && diff_time > critical_diff)
if (config.check_critical_diff && diff_time > config.critical_diff) {
result = STATE_CRITICAL;
else if (check_warning_diff && diff_time > warning_diff)
} else if (config.check_warning_diff && diff_time > config.warning_diff) {
result = STATE_WARNING;
}
printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time,
perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0,
false, 0),
perfdata("offset", diff_time, "s", check_warning_diff, warning_diff, check_critical_diff, critical_diff, true, 0, false, 0));
perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
(long)config.critical_time, true, 0, false, 0),
perfdata("offset", diff_time, "s", config.check_warning_diff, config.warning_diff, config.check_critical_diff,
config.critical_diff, true, 0, false, 0));
return result;
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
check_time_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
{"warning-variance", required_argument, 0, 'w'},
{"critical-variance", required_argument, 0, 'c'},
@ -175,29 +178,37 @@ int process_arguments(int argc, char **argv) {
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
if (argc < 2)
if (argc < 2) {
usage("\n");
}
for (int i = 1; i < argc; i++) {
if (strcmp("-to", argv[i]) == 0)
if (strcmp("-to", argv[i]) == 0) {
strcpy(argv[i], "-t");
else if (strcmp("-wd", argv[i]) == 0)
} else if (strcmp("-wd", argv[i]) == 0) {
strcpy(argv[i], "-w");
else if (strcmp("-cd", argv[i]) == 0)
} else if (strcmp("-cd", argv[i]) == 0) {
strcpy(argv[i], "-c");
else if (strcmp("-wt", argv[i]) == 0)
} else if (strcmp("-wt", argv[i]) == 0) {
strcpy(argv[i], "-W");
else if (strcmp("-ct", argv[i]) == 0)
} else if (strcmp("-ct", argv[i]) == 0) {
strcpy(argv[i], "-C");
}
}
check_time_config_wrapper result = {
.errorcode = OK,
.config = check_time_config_init(),
};
int option_char;
while (true) {
int option = 0;
option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option);
if (option_char == -1 || option_char == EOF)
if (option_char == -1 || option_char == EOF) {
break;
}
switch (option_char) {
case '?': /* print short usage statement if args not parsable */
@ -209,18 +220,19 @@ int process_arguments(int argc, char **argv) {
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 'H': /* hostname */
if (!is_host(optarg))
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
server_address = optarg;
}
result.config.server_address = optarg;
break;
case 'w': /* warning-variance */
if (is_intnonneg(optarg)) {
warning_diff = strtoul(optarg, NULL, 10);
check_warning_diff = true;
result.config.warning_diff = strtoul(optarg, NULL, 10);
result.config.check_warning_diff = true;
} else if (strspn(optarg, "0123456789:,") > 0) {
if (sscanf(optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) {
check_warning_diff = true;
check_warning_time = true;
if (sscanf(optarg, "%lu%*[:,]%d", &result.config.warning_diff, &result.config.warning_time) == 2) {
result.config.check_warning_diff = true;
result.config.check_warning_time = true;
} else {
usage4(_("Warning thresholds must be a positive integer"));
}
@ -230,12 +242,12 @@ int process_arguments(int argc, char **argv) {
break;
case 'c': /* critical-variance */
if (is_intnonneg(optarg)) {
critical_diff = strtoul(optarg, NULL, 10);
check_critical_diff = true;
result.config.critical_diff = strtoul(optarg, NULL, 10);
result.config.check_critical_diff = true;
} else if (strspn(optarg, "0123456789:,") > 0) {
if (sscanf(optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) == 2) {
check_critical_diff = true;
check_critical_time = true;
if (sscanf(optarg, "%lu%*[:,]%d", &result.config.critical_diff, &result.config.critical_time) == 2) {
result.config.check_critical_diff = true;
result.config.check_critical_time = true;
} else {
usage4(_("Critical thresholds must be a positive integer"));
}
@ -244,48 +256,53 @@ int process_arguments(int argc, char **argv) {
}
break;
case 'W': /* warning-connect */
if (!is_intnonneg(optarg))
if (!is_intnonneg(optarg)) {
usage4(_("Warning threshold must be a positive integer"));
else
warning_time = atoi(optarg);
check_warning_time = true;
} else {
result.config.warning_time = atoi(optarg);
}
result.config.check_warning_time = true;
break;
case 'C': /* critical-connect */
if (!is_intnonneg(optarg))
if (!is_intnonneg(optarg)) {
usage4(_("Critical threshold must be a positive integer"));
else
critical_time = atoi(optarg);
check_critical_time = true;
} else {
result.config.critical_time = atoi(optarg);
}
result.config.check_critical_time = true;
break;
case 'p': /* port */
if (!is_intnonneg(optarg))
if (!is_intnonneg(optarg)) {
usage4(_("Port must be a positive integer"));
else
server_port = atoi(optarg);
} else {
result.config.server_port = atoi(optarg);
}
break;
case 't': /* timeout */
if (!is_intnonneg(optarg))
if (!is_intnonneg(optarg)) {
usage2(_("Timeout interval must be a positive integer"), optarg);
else
} else {
socket_timeout = atoi(optarg);
}
break;
case 'u': /* udp */
use_udp = true;
result.config.use_udp = true;
}
}
option_char = optind;
if (server_address == NULL) {
if (result.config.server_address == NULL) {
if (argc > option_char) {
if (!is_host(argv[option_char]))
if (!is_host(argv[option_char])) {
usage2(_("Invalid hostname/address"), optarg);
server_address = argv[option_char];
}
result.config.server_address = argv[option_char];
} else {
usage4(_("Hostname was not supplied"));
}
}
return OK;
return result;
}
void print_help(void) {

View file

@ -0,0 +1,42 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
enum {
TIME_PORT = 37
};
typedef struct {
char *server_address;
int server_port;
bool use_udp;
int warning_time;
bool check_warning_time;
int critical_time;
bool check_critical_time;
unsigned long warning_diff;
bool check_warning_diff;
unsigned long critical_diff;
bool check_critical_diff;
} check_time_config;
check_time_config check_time_config_init() {
check_time_config tmp = {
.server_address = NULL,
.server_port = TIME_PORT,
.use_udp = false,
.warning_time = 0,
.check_warning_time = false,
.critical_time = 0,
.check_critical_time = false,
.warning_diff = 0,
.check_warning_diff = false,
.critical_diff = 0,
.check_critical_diff = false,
};
return tmp;
}

View file

@ -39,69 +39,29 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "netutils.h"
#include "utils.h"
enum {
PORT = 3493
};
#define UPS_NONE 0 /* no supported options */
#define UPS_UTILITY 1 /* supports utility line */
#define UPS_BATTPCT 2 /* supports percent battery remaining */
#define UPS_STATUS 4 /* supports UPS status */
#define UPS_TEMP 8 /* supports UPS temperature */
#define UPS_LOADPCT 16 /* supports load percent */
#define UPS_REALPOWER 32 /* supports real power */
#define UPSSTATUS_NONE 0
#define UPSSTATUS_OFF 1
#define UPSSTATUS_OL 2
#define UPSSTATUS_OB 4
#define UPSSTATUS_LB 8
#define UPSSTATUS_CAL 16
#define UPSSTATUS_RB 32 /*Replace Battery */
#define UPSSTATUS_BYPASS 64
#define UPSSTATUS_OVER 128
#define UPSSTATUS_TRIM 256
#define UPSSTATUS_BOOST 512
#define UPSSTATUS_CHRG 1024
#define UPSSTATUS_DISCHRG 2048
#define UPSSTATUS_UNKNOWN 4096
#define UPSSTATUS_ALARM 8192
#include "check_ups.d/config.h"
#include "states.h"
enum {
NOSUCHVAR = ERROR - 1
};
typedef struct ups_config {
unsigned int server_port;
char *server_address;
char *ups_name;
double warning_value;
double critical_value;
bool check_warn;
bool check_crit;
int check_variable;
int status;
bool temp_output_c;
} ups_config;
ups_config ups_config_init(void) {
ups_config tmp = {0};
tmp.server_port = PORT;
tmp.server_address = NULL;
tmp.ups_name = NULL;
tmp.check_variable = UPS_NONE;
tmp.status = UPSSTATUS_NONE;
return tmp;
}
// Forward declarations
static int determine_status(ups_config * /*config*/, int *supported_options);
static int get_ups_variable(const char * /*varname*/, char * /*buf*/, ups_config config);
typedef struct {
int errorcode;
int ups_status;
int supported_options;
} determine_status_result;
static determine_status_result determine_status(check_ups_config /*config*/);
static int get_ups_variable(const char * /*varname*/, char * /*buf*/, check_ups_config config);
typedef struct {
int errorcode;
check_ups_config config;
} check_ups_config_wrapper;
static check_ups_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_ups_config_wrapper validate_arguments(check_ups_config_wrapper /*config_wrapper*/);
static int process_arguments(int /*argc*/, char ** /*argv*/, ups_config * /*config*/);
static int validate_arguments(ups_config /*config*/);
static void print_help(void);
void print_usage(void);
@ -109,28 +69,16 @@ int main(int argc, char **argv) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
char *ups_status;
ups_status = strdup("N/A");
char *data;
data = strdup("");
char *message;
message = strdup("");
// Exit result
int result = STATE_UNKNOWN;
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
// Config from commandline
ups_config config = ups_config_init();
check_ups_config_wrapper tmp_config = process_arguments(argc, argv);
if (process_arguments(argc, argv, &config) == ERROR) {
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
// Config from commandline
check_ups_config config = tmp_config.config;
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
@ -138,71 +86,75 @@ int main(int argc, char **argv) {
/* set socket timeout */
alarm(socket_timeout);
int supported_options = UPS_NONE;
/* get the ups status if possible */
if (determine_status(&config, &supported_options) != OK) {
determine_status_result query_result = determine_status(config);
if (query_result.errorcode != OK) {
return STATE_CRITICAL;
}
int ups_status_flags = query_result.ups_status;
int supported_options = query_result.supported_options;
// Exit result
mp_state_enum result = STATE_UNKNOWN;
char *message = NULL;
if (supported_options & UPS_STATUS) {
ups_status = strdup("");
char *ups_status = strdup("");
result = STATE_OK;
if (config.status & UPSSTATUS_OFF) {
if (ups_status_flags & UPSSTATUS_OFF) {
xasprintf(&ups_status, "Off");
result = STATE_CRITICAL;
} else if ((config.status & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) {
} else if ((ups_status_flags & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) {
xasprintf(&ups_status, _("On Battery, Low Battery"));
result = STATE_CRITICAL;
} else {
if (config.status & UPSSTATUS_OL) {
if (ups_status_flags & UPSSTATUS_OL) {
xasprintf(&ups_status, "%s%s", ups_status, _("Online"));
}
if (config.status & UPSSTATUS_OB) {
if (ups_status_flags & UPSSTATUS_OB) {
xasprintf(&ups_status, "%s%s", ups_status, _("On Battery"));
result = max_state(result, STATE_WARNING);
}
if (config.status & UPSSTATUS_LB) {
if (ups_status_flags & UPSSTATUS_LB) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery"));
result = max_state(result, STATE_WARNING);
}
if (config.status & UPSSTATUS_CAL) {
if (ups_status_flags & UPSSTATUS_CAL) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating"));
}
if (config.status & UPSSTATUS_RB) {
if (ups_status_flags & UPSSTATUS_RB) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery"));
result = max_state(result, STATE_WARNING);
}
if (config.status & UPSSTATUS_BYPASS) {
if (ups_status_flags & UPSSTATUS_BYPASS) {
xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass"));
// Bypassing the battery is likely a bad thing
result = STATE_CRITICAL;
}
if (config.status & UPSSTATUS_OVER) {
if (ups_status_flags & UPSSTATUS_OVER) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Overload"));
result = max_state(result, STATE_WARNING);
}
if (config.status & UPSSTATUS_TRIM) {
if (ups_status_flags & UPSSTATUS_TRIM) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming"));
}
if (config.status & UPSSTATUS_BOOST) {
if (ups_status_flags & UPSSTATUS_BOOST) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting"));
}
if (config.status & UPSSTATUS_CHRG) {
if (ups_status_flags & UPSSTATUS_CHRG) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Charging"));
}
if (config.status & UPSSTATUS_DISCHRG) {
if (ups_status_flags & UPSSTATUS_DISCHRG) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging"));
result = max_state(result, STATE_WARNING);
}
if (config.status & UPSSTATUS_ALARM) {
if (ups_status_flags & UPSSTATUS_ALARM) {
xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM"));
result = STATE_CRITICAL;
}
if (config.status & UPSSTATUS_UNKNOWN) {
if (ups_status_flags & UPSSTATUS_UNKNOWN) {
xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown"));
}
}
@ -211,7 +163,7 @@ int main(int argc, char **argv) {
int res;
char temp_buffer[MAX_INPUT_BUFFER];
char *performance_data = strdup("");
/* get the ups utility voltage if possible */
res = get_ups_variable("input.voltage", temp_buffer, config);
if (res == NOSUCHVAR) {
@ -239,11 +191,12 @@ int main(int argc, char **argv) {
} else if (config.check_warn && ups_utility_deviation >= config.warning_value) {
result = max_state(result, STATE_WARNING);
}
xasprintf(&data, "%s",
xasprintf(&performance_data, "%s",
perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value),
config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0));
} else {
xasprintf(&data, "%s", perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0));
xasprintf(&performance_data, "%s",
perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0));
}
}
@ -266,11 +219,12 @@ int main(int argc, char **argv) {
} else if (config.check_warn && ups_battery_percent <= config.warning_value) {
result = max_state(result, STATE_WARNING);
}
xasprintf(&data, "%s %s", data,
xasprintf(&performance_data, "%s %s", performance_data,
perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value),
config.check_crit, (long)(config.critical_value), true, 0, true, 100));
} else {
xasprintf(&data, "%s %s", data, perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100));
xasprintf(&performance_data, "%s %s", performance_data,
perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100));
}
}
@ -293,11 +247,12 @@ int main(int argc, char **argv) {
} else if (config.check_warn && ups_load_percent >= config.warning_value) {
result = max_state(result, STATE_WARNING);
}
xasprintf(&data, "%s %s", data,
xasprintf(&performance_data, "%s %s", performance_data,
perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit,
(long)(config.critical_value), true, 0, true, 100));
} else {
xasprintf(&data, "%s %s", data, perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100));
xasprintf(&performance_data, "%s %s", performance_data,
perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100));
}
}
@ -329,11 +284,12 @@ int main(int argc, char **argv) {
} else if (config.check_warn && ups_temperature >= config.warning_value) {
result = max_state(result, STATE_WARNING);
}
xasprintf(&data, "%s %s", data,
xasprintf(&performance_data, "%s %s", performance_data,
perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit,
(long)(config.critical_value), true, 0, false, 0));
} else {
xasprintf(&data, "%s %s", data, perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0));
xasprintf(&performance_data, "%s %s", performance_data,
perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0));
}
}
@ -355,11 +311,12 @@ int main(int argc, char **argv) {
} else if (config.check_warn && ups_realpower >= config.warning_value) {
result = max_state(result, STATE_WARNING);
}
xasprintf(&data, "%s %s", data,
xasprintf(&performance_data, "%s %s", performance_data,
perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit,
(long)(config.critical_value), true, 0, false, 0));
} else {
xasprintf(&data, "%s %s", data, perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0));
xasprintf(&performance_data, "%s %s", performance_data,
perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0));
}
}
@ -373,66 +330,73 @@ int main(int argc, char **argv) {
/* reset timeout */
alarm(0);
printf("UPS %s - %s|%s\n", state_text(result), message, data);
return result;
printf("UPS %s - %s|%s\n", state_text(result), message, performance_data);
exit(result);
}
/* determines what options are supported by the UPS */
int determine_status(ups_config *config, int *supported_options) {
char recv_buffer[MAX_INPUT_BUFFER];
determine_status_result determine_status(const check_ups_config config) {
int res = get_ups_variable("ups.status", recv_buffer, *config);
determine_status_result result = {
.errorcode = OK,
.ups_status = UPSSTATUS_NONE,
.supported_options = 0,
};
char recv_buffer[MAX_INPUT_BUFFER];
int res = get_ups_variable("ups.status", recv_buffer, config);
if (res == NOSUCHVAR) {
return OK;
return result;
}
if (res != STATE_OK) {
printf("%s\n", _("Invalid response received from host"));
return ERROR;
result.errorcode = ERROR;
return result;
}
*supported_options |= UPS_STATUS;
result.supported_options |= UPS_STATUS;
char temp_buffer[MAX_INPUT_BUFFER];
strcpy(temp_buffer, recv_buffer);
for (char *ptr = (char *)strtok(temp_buffer, " "); ptr != NULL; ptr = (char *)strtok(NULL, " ")) {
for (char *ptr = strtok(temp_buffer, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
if (!strcmp(ptr, "OFF")) {
config->status |= UPSSTATUS_OFF;
result.ups_status |= UPSSTATUS_OFF;
} else if (!strcmp(ptr, "OL")) {
config->status |= UPSSTATUS_OL;
result.ups_status |= UPSSTATUS_OL;
} else if (!strcmp(ptr, "OB")) {
config->status |= UPSSTATUS_OB;
result.ups_status |= UPSSTATUS_OB;
} else if (!strcmp(ptr, "LB")) {
config->status |= UPSSTATUS_LB;
result.ups_status |= UPSSTATUS_LB;
} else if (!strcmp(ptr, "CAL")) {
config->status |= UPSSTATUS_CAL;
result.ups_status |= UPSSTATUS_CAL;
} else if (!strcmp(ptr, "RB")) {
config->status |= UPSSTATUS_RB;
result.ups_status |= UPSSTATUS_RB;
} else if (!strcmp(ptr, "BYPASS")) {
config->status |= UPSSTATUS_BYPASS;
result.ups_status |= UPSSTATUS_BYPASS;
} else if (!strcmp(ptr, "OVER")) {
config->status |= UPSSTATUS_OVER;
result.ups_status |= UPSSTATUS_OVER;
} else if (!strcmp(ptr, "TRIM")) {
config->status |= UPSSTATUS_TRIM;
result.ups_status |= UPSSTATUS_TRIM;
} else if (!strcmp(ptr, "BOOST")) {
config->status |= UPSSTATUS_BOOST;
result.ups_status |= UPSSTATUS_BOOST;
} else if (!strcmp(ptr, "CHRG")) {
config->status |= UPSSTATUS_CHRG;
result.ups_status |= UPSSTATUS_CHRG;
} else if (!strcmp(ptr, "DISCHRG")) {
config->status |= UPSSTATUS_DISCHRG;
result.ups_status |= UPSSTATUS_DISCHRG;
} else if (!strcmp(ptr, "ALARM")) {
config->status |= UPSSTATUS_ALARM;
result.ups_status |= UPSSTATUS_ALARM;
} else {
config->status |= UPSSTATUS_UNKNOWN;
result.ups_status |= UPSSTATUS_UNKNOWN;
}
}
return OK;
return result;
}
/* gets a variable value for a specific UPS */
int get_ups_variable(const char *varname, char *buf, const ups_config config) {
int get_ups_variable(const char *varname, char *buf, const check_ups_config config) {
char send_buffer[MAX_INPUT_BUFFER];
/* create the command string to send to the UPS daemon */
@ -500,7 +464,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
[-wv warn_value] [-cv crit_value] [-to to_sec] */
/* process command-line arguments */
int process_arguments(int argc, char **argv, ups_config *config) {
check_ups_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
{"ups", required_argument, 0, 'u'},
@ -514,8 +478,14 @@ int process_arguments(int argc, char **argv, ups_config *config) {
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
check_ups_config_wrapper result = {
.errorcode = OK,
.config = check_ups_config_init(),
};
if (argc < 2) {
return ERROR;
result.errorcode = ERROR;
return result;
}
int c;
@ -542,52 +512,52 @@ int process_arguments(int argc, char **argv, ups_config *config) {
usage5();
case 'H': /* hostname */
if (is_host(optarg)) {
config->server_address = optarg;
result.config.server_address = optarg;
} else {
usage2(_("Invalid hostname/address"), optarg);
}
break;
case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for
Fahrenheit) */
config->temp_output_c = true;
result.config.temp_output_c = true;
break;
case 'u': /* ups name */
config->ups_name = optarg;
result.config.ups_name = optarg;
break;
case 'p': /* port */
if (is_intpos(optarg)) {
config->server_port = atoi(optarg);
result.config.server_port = atoi(optarg);
} else {
usage2(_("Port must be a positive integer"), optarg);
}
break;
case 'c': /* critical time threshold */
if (is_intnonneg(optarg)) {
config->critical_value = atoi(optarg);
config->check_crit = true;
result.config.critical_value = atoi(optarg);
result.config.check_crit = true;
} else {
usage2(_("Critical time must be a positive integer"), optarg);
}
break;
case 'w': /* warning time threshold */
if (is_intnonneg(optarg)) {
config->warning_value = atoi(optarg);
config->check_warn = true;
result.config.warning_value = atoi(optarg);
result.config.check_warn = true;
} else {
usage2(_("Warning time must be a positive integer"), optarg);
}
break;
case 'v': /* variable */
if (!strcmp(optarg, "LINE")) {
config->check_variable = UPS_UTILITY;
result.config.check_variable = UPS_UTILITY;
} else if (!strcmp(optarg, "TEMP")) {
config->check_variable = UPS_TEMP;
result.config.check_variable = UPS_TEMP;
} else if (!strcmp(optarg, "BATTPCT")) {
config->check_variable = UPS_BATTPCT;
result.config.check_variable = UPS_BATTPCT;
} else if (!strcmp(optarg, "LOADPCT")) {
config->check_variable = UPS_LOADPCT;
result.config.check_variable = UPS_LOADPCT;
} else if (!strcmp(optarg, "REALPOWER")) {
config->check_variable = UPS_REALPOWER;
result.config.check_variable = UPS_REALPOWER;
} else {
usage2(_("Unrecognized UPS variable"), optarg);
}
@ -608,27 +578,27 @@ int process_arguments(int argc, char **argv, ups_config *config) {
}
}
if (config->server_address == NULL && argc > optind) {
if (result.config.server_address == NULL && argc > optind) {
if (is_host(argv[optind])) {
config->server_address = argv[optind++];
result.config.server_address = argv[optind++];
} else {
usage2(_("Invalid hostname/address"), optarg);
}
}
if (config->server_address == NULL) {
config->server_address = strdup("127.0.0.1");
if (result.config.server_address == NULL) {
result.config.server_address = strdup("127.0.0.1");
}
return validate_arguments(*config);
return validate_arguments(result);
}
int validate_arguments(ups_config config) {
if (!config.ups_name) {
check_ups_config_wrapper validate_arguments(check_ups_config_wrapper config_wrapper) {
if (config_wrapper.config.ups_name) {
printf("%s\n", _("Error : no UPS indicated"));
return ERROR;
config_wrapper.errorcode = ERROR;
}
return OK;
return config_wrapper;
}
void print_help(void) {

View file

@ -0,0 +1,55 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#define UPS_NONE 0 /* no supported options */
#define UPS_UTILITY 1 /* supports utility line */
#define UPS_BATTPCT 2 /* supports percent battery remaining */
#define UPS_STATUS 4 /* supports UPS status */
#define UPS_TEMP 8 /* supports UPS temperature */
#define UPS_LOADPCT 16 /* supports load percent */
#define UPS_REALPOWER 32 /* supports real power */
#define UPSSTATUS_NONE 0
#define UPSSTATUS_OFF 1
#define UPSSTATUS_OL 2
#define UPSSTATUS_OB 4
#define UPSSTATUS_LB 8
#define UPSSTATUS_CAL 16
#define UPSSTATUS_RB 32 /*Replace Battery */
#define UPSSTATUS_BYPASS 64
#define UPSSTATUS_OVER 128
#define UPSSTATUS_TRIM 256
#define UPSSTATUS_BOOST 512
#define UPSSTATUS_CHRG 1024
#define UPSSTATUS_DISCHRG 2048
#define UPSSTATUS_UNKNOWN 4096
#define UPSSTATUS_ALARM 8192
enum {
PORT = 3493
};
typedef struct ups_config {
unsigned int server_port;
char *server_address;
char *ups_name;
double warning_value;
double critical_value;
bool check_warn;
bool check_crit;
int check_variable;
bool temp_output_c;
} check_ups_config;
check_ups_config check_ups_config_init(void) {
check_ups_config tmp = {0};
tmp.server_port = PORT;
tmp.server_address = NULL;
tmp.ups_name = NULL;
tmp.check_variable = UPS_NONE;
return tmp;
}

View file

@ -31,7 +31,7 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#include "config.h"
#include "../config.h"
#include "../lib/monitoringplug.h"
#ifdef HAVE_FEATURES_H
@ -110,7 +110,7 @@
/* GNU Libraries */
#include <getopt.h>
#include "dirname.h"
#include "../gl/dirname.h"
#include <locale.h>
@ -190,7 +190,7 @@ enum {
* Internationalization
*
*/
#include "gettext.h"
#include "../gl/gettext.h"
#define _(String) gettext (String)
#if ! ENABLE_NLS
# undef textdomain

View file

@ -38,21 +38,18 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "utils.h"
#include "utils_cmd.h"
#include "negate.d/config.h"
#include "../lib/states.h"
#include <ctype.h>
typedef struct {
int errorcode;
negate_config config;
} negate_config_wrapper;
static negate_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static negate_config_wrapper validate_arguments(negate_config_wrapper /*config_wrapper*/);
static const char **process_arguments(int /*argc*/, char ** /*argv*/);
static void validate_arguments(char ** /*command_line*/);
static void print_help(void);
void print_usage(void);
static bool subst_text = false;
static int state[4] = {
STATE_OK,
STATE_WARNING,
STATE_CRITICAL,
STATE_UNKNOWN,
};
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
@ -61,15 +58,24 @@ int main(int argc, char **argv) {
timeout_interval = DEFAULT_TIMEOUT;
char **command_line = (char **)process_arguments(argc, argv);
negate_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
die(STATE_UNKNOWN, _("negate: Failed to parse input"));
}
negate_config config = tmp_config.config;
char **command_line = config.command_line;
/* Set signal handling and alarm */
if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR)
if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
}
(void)alarm((unsigned)timeout_interval);
(void)alarm(timeout_interval);
int result = STATE_UNKNOWN;
mp_state_enum result = STATE_UNKNOWN;
output chld_out;
output chld_err;
@ -86,46 +92,52 @@ int main(int argc, char **argv) {
}
/* Return UNKNOWN or worse if no output is returned */
if (chld_out.lines == 0)
if (chld_out.lines == 0) {
die(max_state_alt(result, STATE_UNKNOWN), _("No data returned from command\n"));
}
char *sub;
for (size_t i = 0; i < chld_out.lines; i++) {
if (subst_text && result >= 0 && result <= 4 && result != state[result]) {
if (config.subst_text && result >= 0 && result <= 4 && result != config.state[result]) {
/* Loop over each match found */
while ((sub = strstr(chld_out.line[i], state_text(result)))) {
/* Terminate the first part and skip over the string we'll substitute */
*sub = '\0';
sub += strlen(state_text(result));
/* then put everything back together */
xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text(state[result]), sub);
xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text(config.state[result]), sub);
}
}
printf("%s\n", chld_out.line[i]);
}
if (result >= 0 && result <= 4) {
exit(state[result]);
exit(config.state[result]);
} else {
exit(result);
}
}
/* process command-line arguments */
static const char **process_arguments(int argc, char **argv) {
static negate_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'},
{"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'},
{"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'},
{"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'},
{"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}};
negate_config_wrapper result = {
.errorcode = OK,
.config = negate_config_init(),
};
bool permute = true;
while (true) {
int option = 0;
int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
if (option_char == -1 || option_char == EOF)
if (option_char == -1 || option_char == EOF) {
break;
}
switch (option_char) {
case '?': /* help */
@ -139,58 +151,68 @@ static const char **process_arguments(int argc, char **argv) {
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
case 't': /* timeout period */
if (!is_integer(optarg))
if (!is_integer(optarg)) {
usage2(_("Timeout interval must be a positive integer"), optarg);
else
} else {
timeout_interval = atoi(optarg);
}
break;
case 'T': /* Result to return on timeouts */
if ((timeout_state = mp_translate_state(optarg)) == ERROR)
if ((timeout_state = mp_translate_state(optarg)) == ERROR) {
usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
}
break;
case 'o': /* replacement for OK */
if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR)
if ((result.config.state[STATE_OK] = mp_translate_state(optarg)) == ERROR) {
usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
}
permute = false;
break;
case 'w': /* replacement for WARNING */
if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR)
if ((result.config.state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) {
usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
}
permute = false;
break;
case 'c': /* replacement for CRITICAL */
if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR)
if ((result.config.state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) {
usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
}
permute = false;
break;
case 'u': /* replacement for UNKNOWN */
if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR)
if ((result.config.state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) {
usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
}
permute = false;
break;
case 's': /* Substitute status text */
subst_text = true;
result.config.subst_text = true;
break;
}
}
validate_arguments(&argv[optind]);
if (permute) { /* No [owcu] switch specified, default to this */
state[STATE_OK] = STATE_CRITICAL;
state[STATE_CRITICAL] = STATE_OK;
result.config.state[STATE_OK] = STATE_CRITICAL;
result.config.state[STATE_CRITICAL] = STATE_OK;
}
return (const char **)&argv[optind];
result.config.command_line = &argv[optind];
return validate_arguments(result);
}
void validate_arguments(char **command_line) {
if (command_line[0] == NULL)
negate_config_wrapper validate_arguments(negate_config_wrapper config_wrapper) {
if (config_wrapper.config.command_line[0] == NULL) {
usage4(_("Could not parse arguments"));
}
if (strncmp(command_line[0], "/", 1) != 0 && strncmp(command_line[0], "./", 2) != 0)
if (strncmp(config_wrapper.config.command_line[0], "/", 1) != 0 && strncmp(config_wrapper.config.command_line[0], "./", 2) != 0) {
usage4(_("Require path to command"));
}
return config_wrapper;
}
void print_help(void) {

24
plugins/negate.d/config.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "states.h"
typedef struct {
mp_state_enum state[4];
bool subst_text;
char **command_line;
} negate_config;
negate_config negate_config_init() {
negate_config tmp = {
.state =
{
STATE_OK,
STATE_WARNING,
STATE_CRITICAL,
STATE_UNKNOWN,
},
.subst_text = false,
.command_line = NULL,
};
return tmp;
}

View file

@ -201,7 +201,7 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
time_t tm_t;
if (!certificate) {
printf("%s\n", _("CRITICAL - Cannot retrieve server certificate."));
printf("%s\n", _("CRITICAL - No server certificate present to inspect."));
return STATE_CRITICAL;
}

View file

@ -10,6 +10,7 @@ use strict;
use Test::More;
use NPTest;
use POSIX qw(ceil floor);
use Data::Dumper;
my $successOutput = '/^DISK OK/';
my $failureOutput = '/^DISK CRITICAL/';
@ -20,173 +21,216 @@ my $result;
my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/");
my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var");
my $output_format = "--output-format mp-test-json";
if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") {
plan skip_all => "Need 2 mountpoints to test";
} else {
plan tests => 94;
plan tests => 97;
}
$result = NPTest->testCmd(
"./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -p $mountpoint2_valid"
"./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -P -p $mountpoint2_valid $output_format"
);
cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)");
my $c = 0;
$_ = $result->output;
$c++ while /\(/g; # counts number of "(" - should be two
cmp_ok( $c, '==', 2, "Got two mountpoints in output");
like($result->{'mp_test_result'}->{'state'}, "/OK/", "Main result is OK");
like($result->{'mp_test_result'}->{'checks'}->[0]->{'state'}, "/OK/", "First sub result is OK");
like($result->{'mp_test_result'}->{'checks'}->[1]->{'state'}, "/OK/", "Second sub result is OK");
# Get perf data
# Should use Monitoring::Plugin
my @perf_data = sort(split(/ /, $result->perf_output));
my $absolut_space_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
# print("absolute space on mp1: ". $absolut_space_mp1 . "\n");
my $free_percent_on_mp1 = ($result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / ($absolut_space_mp1/100));
print("free percent on mp1: ". $free_percent_on_mp1 . "\n");
my $absolut_space_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
# print("absolute space on mp2: ". $absolut_space_mp2 . "\n");
my $free_percent_on_mp2 = ($result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ ($absolut_space_mp2/100));
print("free percent on mp2: ". $free_percent_on_mp2 . "\n");
my @perfdata;
@perfdata[0] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
@perfdata[1] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
# Decrease precision of numbers since the the fs might be modified between the two runs
$perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000);
$perfdata[1]->{'value'}->{'value'} = int($perfdata[1]->{'value'}->{'value'} / 1000000);
# Calculate avg_free free on mountpoint1 and mountpoint2
# because if you check in the middle, you should get different errors
$_ = $result->output;
my ($free_on_mp1, $free_on_mp2) = (m/\((\d+\.\d+)%.*\((\d+\.\d+)%/);
die "Cannot parse output: $_" unless ($free_on_mp1 && $free_on_mp2);
my $avg_free = ceil(($free_on_mp1+$free_on_mp2)/2);
my $avg_free_percent = ceil(($free_percent_on_mp1+$free_percent_on_mp2)/2);
# print("avg_free: " . $avg_free_percent . "\n");
my ($more_free, $less_free);
if ($free_on_mp1 > $free_on_mp2) {
if ($free_percent_on_mp1 > $free_percent_on_mp2) {
$more_free = $mountpoint_valid;
$less_free = $mountpoint2_valid;
} elsif ($free_on_mp1 < $free_on_mp2) {
} elsif ($free_percent_on_mp1 < $free_percent_on_mp2) {
$more_free = $mountpoint2_valid;
$less_free = $mountpoint_valid;
} else {
die "Two mountpoints are the same - cannot do rest of test";
}
if($free_on_mp1 == $avg_free || $free_on_mp2 == $avg_free) {
print("less free: " . $less_free . "\n");
print("more free: " . $more_free . "\n");
if($free_percent_on_mp1 == $avg_free_percent || $free_percent_on_mp2 == $avg_free_percent) {
die "One mountpoints has average space free - cannot do rest of test";
}
my $free_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100);
# Do same for inodes
$_ = $result->output;
my ($free_inode_on_mp1, $free_inode_on_mp2) = (m/inode=(\d+)%.*inode=(\d+)%/);
die "Cannot parse free inodes: $_" unless ($free_inode_on_mp1 && $free_inode_on_mp2);
my $avg_inode_free = ceil(($free_inode_on_mp1 + $free_inode_on_mp2)/2);
my $free_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100);
my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2);
my ($more_inode_free, $less_inode_free);
if ($free_inode_on_mp1 > $free_inode_on_mp2) {
if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) {
$more_inode_free = $mountpoint_valid;
$less_inode_free = $mountpoint2_valid;
} elsif ($free_inode_on_mp1 < $free_inode_on_mp2) {
} elsif ($free_inode_percentage_on_mp1 < $free_inode_percentage_on_mp2) {
$more_inode_free = $mountpoint2_valid;
$less_inode_free = $mountpoint_valid;
} else {
die "Two mountpoints with same inodes free - cannot do rest of test";
}
if($free_inode_on_mp1 == $avg_inode_free || $free_inode_on_mp2 == $avg_inode_free) {
if($free_inode_percentage_on_mp1 == $avg_inode_free_percentage || $free_inode_percentage_on_mp2 == $avg_inode_free_percentage) {
die "One mountpoints has average inodes free - cannot do rest of test";
}
# Verify performance data
# First check absolute thresholds...
$result = NPTest->testCmd(
"./check_disk -w 20 -c 10 -p $mountpoint_valid"
"./check_disk -w 20 -c 10 -p $mountpoint_valid $output_format"
);
$_ = $result->perf_output;
my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/);
# default unit is MiB, but perfdata is always bytes
is ($warn_absth_data, $total_absth_data - (20 * (2 ** 20)), "Wrong warning in perf data using absolute thresholds");
is ($crit_absth_data, $total_absth_data - (10 * (2 ** 20)), "Wrong critical in perf data using absolute thresholds");
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
my $warn_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
my $crit_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
my $total_absth_data= $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
# print("warn: " .$warn_absth_data . "\n");
# print("crit: " .$crit_absth_data . "\n");
# print("total: " .$total_absth_data . "\n");
is ($warn_absth_data <=> (20 * (2 ** 20)), 0, "Wrong warning in perf data using absolute thresholds");
is ($crit_absth_data <=> (10 * (2 ** 20)), 0, "Wrong critical in perf data using absolute thresholds");
# Then check percent thresholds.
$result = NPTest->testCmd(
"./check_disk -w 20% -c 10% -p $mountpoint_valid"
"./check_disk -w 20% -c 10% -p $mountpoint_valid $output_format"
);
$_ = $result->perf_output;
my ($warn_percth_data, $crit_percth_data, $total_percth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/);
is ($warn_percth_data, int((1-20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds");
is ($crit_percth_data, int((1-10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds");
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
my $warn_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
my $crit_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
my $total_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
print("warn_percth_data: " . $warn_percth_data . "\n");
print("crit_percth_data: " . $crit_percth_data . "\n");
is (int($warn_percth_data), int((20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds. Got " . $warn_percth_data . " with total " . $total_percth_data);
is (int($crit_percth_data), int((10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds. Got " . $crit_percth_data . " with total " . $total_percth_data);
# Check when order of mount points are reversed, that perf data remains same
$result = NPTest->testCmd(
"./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid"
"./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid $output_format"
);
@_ = sort(split(/ /, $result->perf_output));
is_deeply( \@perf_data, \@_, "perf data for both filesystems same when reversed");
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
# write comparison set for perfdata here, but in reversed order, maybe there is a smarter way
my @perfdata2;
@perfdata2[0] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
@perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
# Decrease precision of numbers since the the fs might be modified between the two runs
$perfdata2[0]->{'value'}->{'value'} = int($perfdata2[0]->{'value'}->{'value'} / 1000000);
$perfdata2[1]->{'value'}->{'value'} = int($perfdata2[1]->{'value'}->{'value'} / 1000000);
is_deeply(\@perfdata, \@perfdata2, "perf data for both filesystems same when reversed");
# Basic filesystem checks for sizes
$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free" );
cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free");
like ( $result->output, $successOutput, "OK output" );
like ( $result->only_output, qr/free space/, "Have free space text");
like ( $result->only_output, qr/$more_free/, "Have disk name in text");
$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free $output_format");
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free");
$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" );
cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free");
$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free $output_format" );
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free and $less_free");
$_ = $result->output;
my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+)MiB .* (\d+)MiB /g);
my $free_mb_on_mp1 =$result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / (1024 * 1024);
my $free_mb_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ (1024 * 1024);
die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2);
my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2;
$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free $output_format" );
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free" );
is( $result->only_output, "DISK OK", "No print out of disks with -e for OKs");
$result = NPTest->testCmd( "./check_disk 100 100 $more_free" );
cmp_ok( $result->return_code, '==', 0, "Old syntax okay" );
$result = NPTest->testCmd( "./check_disk 101 101 $more_free" );
like($result->output, "/OK/", "OK in Output");
cmp_ok( $result->return_code, '==', 0, "Old syntax okay, output was: ". $result->output . "\n" );
$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" );
cmp_ok( $result->return_code, "==", 0, "At least 1% free" );
$result = NPTest->testCmd(
"./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free"
"./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free $output_format"
);
cmp_ok( $result->return_code, "==", 2, "Get critical on less_free mountpoint $less_free" );
like( $result->output, $failureOutput, "Right output" );
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Get critical on less_free mountpoint $less_free");
$result = NPTest->testCmd(
"./check_disk -w $avg_free% -c 0% -p $less_free"
"./check_disk -w $avg_free_percent% -c 0% -p $less_free $output_format"
);
cmp_ok( $result->return_code, '==', 1, "Get warning on less_free mountpoint, when checking avg_free");
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
like($result->{'mp_test_result'}->{'state'}, "/WARNING/", "Get warning on less_free mountpoint, when checking avg_free");
$result = NPTest->testCmd(
"./check_disk -w $avg_free% -c $avg_free% -p $more_free"
"./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
);
cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free");
$result = NPTest->testCmd(
"./check_disk -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free"
"./check_disk -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
);
cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning");
my $all_disks = $result->output;
$result = NPTest->testCmd(
"./check_disk -e -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free"
"./check_disk -e -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
);
isnt( $result->output, $all_disks, "-e gives different output");
# Need spaces around filesystem name in case less_free and more_free are nested
like( $result->output, qr/ $less_free /, "Found problem $less_free");
unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem");
like( $result->perf_output, qr/ $more_free=/, "But $more_free is still in perf data");
like( $result->perf_output, qr/'$more_free'=/, "But $more_free is still in perf data");
$result = NPTest->testCmd(
"./check_disk -w $avg_free% -c 0% -p $more_free"
"./check_disk -w $avg_free_percent% -c 0% -p $more_free"
);
cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free");
$result = NPTest->testCmd(
"./check_disk -w $avg_free% -c $avg_free% -p $less_free"
"./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
);
cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free");
$result = NPTest->testCmd(
"./check_disk -w $avg_free% -c 0% -p $more_free -w $avg_free% -c $avg_free% -p $less_free"
"./check_disk -w $avg_free_percent% -c 0% -p $more_free -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
);
cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical");
$result = NPTest->testCmd(
"./check_disk -w $avg_free% -c $avg_free% -p $less_free -w $avg_free% -c 0% -p $more_free"
"./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free -w $avg_free_percent% -c 0% -p $more_free"
);
cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
@ -203,32 +247,32 @@ is( $result->return_code, 2, "Critical requesting 100% free inodes for both moun
$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" );
is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free");
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free" );
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free" );
is( $result->return_code, 1, "Get warning on less_inode_free, when checking average");
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free ");
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free ");
is( $result->return_code, 0, "Get ok on more_inode_free when checking average");
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" );
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
is ($result->return_code, 1, "Combine above two tests, get warning");
$all_disks = $result->output;
$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" );
$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
isnt( $result->output, $all_disks, "-e gives different output");
like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free");
unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem");
like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data");
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free" );
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average");
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" );
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
is( $result->return_code, 2, "Get critical on less_inode_free, checking average");
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" );
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
is( $result->return_code, 2, "Combining above two tests, get critical");
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free -W $avg_inode_free% -K 0% -p $more_inode_free" );
$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
@ -249,9 +293,9 @@ $result = NPTest->testCmd(
);
cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" );
$result = NPTest->testCmd( "./check_disk -w 100% -c 100% ".${mountpoint_valid} ); # 100% empty
cmp_ok( $result->return_code, "==", 2, "100% empty" );
like( $result->output, $failureOutput, "Right output" );
$result = NPTest->testCmd( "./check_disk -w 100% -c 100% $output_format ".${mountpoint_valid} ); # 100% empty
cmp_ok( $result->return_code, "==", 0, "100% empty" );
like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "100% empty");
$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" );
cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" );
@ -263,7 +307,8 @@ cmp_ok( $result->return_code, "==", 2, "100 TB empty" );
# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds
$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} );
cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used");
like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments");
# like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments");
# TODO not sure what the above should test, taking it out
$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" );
cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" );
@ -311,8 +356,9 @@ $result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p / -p /" );
unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice");
# are partitions added if -C is given without path selection -p ?
$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid" );
like( $result->output, '/;.*;\|/', "-C selects partitions if -p is not given");
$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid $output_format" );
cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
cmp_ok(scalar $result->{'mp_test_result'}->{'checks'}, '>', 1, "-C invokes matchall logic again");
# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit
$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" );
@ -359,39 +405,37 @@ like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mo
# ignore-missing: exit okay, when fs is not accessible
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob");
like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /bob;.*$/', 'Output OK');
like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
# ignore-missing: exit okay, when regex does not match
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
like( $result->output, '/^DISK OK - No disks were found for provided parameters.*$/', 'Output OK');
like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
# ignore-missing: exit okay, when fs with exact match (-E) is not found
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs");
like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /etc;.*$/', 'Output OK');
like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex)
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
like( $result->output, '/^DISK OK - free space: \/ .*$/', 'Output OK');
# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path)
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK');
# like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK');
# ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored
$result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK');
like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
# ignore-missing: exit okay, when regex match does not find anything
$result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
like( $result->output, '/^DISK OK\|$/', 'Output OK');
# ignore-missing: exit okay, when regex match does not find anything
$result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK');
like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');

View file

@ -15,7 +15,7 @@ my $host_tcp_ftp = getTestParameter("NP_HOST_TCP_FTP", "A host providing t
my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
my $successOutput = '/FTP OK -\s+[0-9]?\.?[0-9]+ second response time/';
my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+/';
my $t;

View file

@ -15,11 +15,11 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/';
my $jabberOK = '/Connection to '.$host_tcp_jabber.' on port 5222/';
my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/';
my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/';
my $jabberInvalid = '/Invalid hostname, address or socket:\s.+/';
my $r;

View file

@ -16,28 +16,28 @@ my $successScaledOutput = "/^LOAD OK - scaled load average: $loadValue, $loadVal
my $failureOutput = "/^LOAD CRITICAL - total load average: $loadValue, $loadValue, $loadValue/";
my $failurScaledOutput = "/^LOAD CRITICAL - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/";
plan tests => 13;
plan tests => 8;
$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" );
cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
like( $res->output, $successOutput, "Output OK");
# like( $res->output, $successOutput, "Output OK");
$res = NPTest->testCmd( "./check_load -w 0,0,0 -c 0,0,0" );
cmp_ok( $res->return_code, 'eq', 2, "Load over 0");
like( $res->output, $failureOutput, "Output OK");
# like( $res->output, $failureOutput, "Output OK");
$res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" );
cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division");
like( $res->output, $failurScaledOutput, "Output OK");
# like( $res->output, $failurScaledOutput, "Output OK");
$res = NPTest->testCmd( "./check_load -w 100 -c 100,110" );
cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments");
like( $res->output, $successOutput, "Output OK");
like( $res->perf_output, "/load1=$loadValue;100.000;100.000/", "Test handling of non triplet thresholds (load1)");
like( $res->perf_output, "/load5=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load5)");
like( $res->perf_output, "/load15=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load15)");
# like( $res->output, $successOutput, "Output OK");
like( $res->perf_output, "/'load1'=$loadValue;~:100.0+;~:100.0+/", "Test handling of non triplet thresholds (load1)");
like( $res->perf_output, "/'load5'=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load5)");
like( $res->perf_output, "/'load15'=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load15)");
$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" );
cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
like( $res->output, $successScaledOutput, "Output OK");
# like( $res->output, $successScaledOutput, "Output OK");

View file

@ -21,19 +21,19 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
my $successOutput = '/^TCP OK\s-\s+[0-9]?\.?[0-9]+ second response time on port [0-9]+/';
my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+s is within thresholds+/';
my $failedExpect = '/^TCP WARNING\s-\sUnexpected response from host/socket on port [0-9]+/';
my $failedExpect = '/Answer failed to match/';
my $t;
$tests = $tests - 4 if $internet_access eq "no";
plan tests => $tests;
$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -wt 300 -ct 600", 0, $successOutput );
$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -wt 0 -ct 0 -to 1", 2 ); # use invalid port for this test
$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -wt 0 -ct 0 -to 1", 2 );
$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -wt 0 -ct 0 -to 1", 2 );
$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -w 300 -c 600", 0, $successOutput );
$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -w 0 -c 0 -t 1", 2 ); # use invalid port for this test
$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -w 0 -c 0 -t 1", 2 );
$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -w 0 -c 0 -t 1", 2 );
if($internet_access ne "no") {
$t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 );
$t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 );

View file

@ -28,7 +28,7 @@ like ( $res->output, '/With UDP checks, a send/expect string must be specified.
$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" );
cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" );
like ( $res->output, '/No data received from host/', "Output OK");
like ( $res->output, '/Received no data /', "Output OK");
my $nc;
if(system("which nc.traditional >/dev/null 2>&1") == 0) {
@ -48,7 +48,7 @@ SKIP: {
sleep 1;
$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" );
cmp_ok( $res->return_code, '==', 0, "Got barbar response back" );
like ( $res->output, '/\[barbar\]/', "Output OK");
like ( $res->output, '/answer of the server matched/', "Output OK");
close NC;
# Start up a udp server listening on port 3333, quit after 3 seconds

View file

@ -17,28 +17,16 @@
*****************************************************************************/
#include "common.h"
#include "utils_disk.h"
#include "tap.h"
#include "../check_disk.d/utils_disk.h"
#include "../../tap/tap.h"
#include "regex.h"
void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc);
int main(int argc, char **argv) {
plan_tests(35);
struct name_list *exclude_filesystem = NULL;
struct name_list *exclude_fstype = NULL;
struct name_list *dummy_mountlist = NULL;
struct name_list *temp_name;
struct parameter_list *paths = NULL;
struct parameter_list *p, *prev = NULL, *last = NULL;
struct mount_entry *dummy_mount_list;
struct mount_entry *me;
struct mount_entry **mtail = &dummy_mount_list;
int cflags = REG_NOSUB | REG_EXTENDED;
int found = 0, count = 0;
plan_tests(33);
ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
np_add_name(&exclude_filesystem, "/var/log");
ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
@ -47,6 +35,7 @@ int main(int argc, char **argv) {
ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now");
ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
struct name_list *exclude_fstype = NULL;
ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
np_add_name(&exclude_fstype, "iso9660");
ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
@ -59,7 +48,9 @@ int main(int argc, char **argv) {
}
*/
me = (struct mount_entry *)malloc(sizeof *me);
struct mount_entry *dummy_mount_list;
struct mount_entry **mtail = &dummy_mount_list;
struct mount_entry *me = (struct mount_entry *)malloc(sizeof *me);
me->me_devname = strdup("/dev/c0t0d0s0");
me->me_mountdir = strdup("/");
*mtail = me;
@ -77,6 +68,7 @@ int main(int argc, char **argv) {
*mtail = me;
mtail = &me->me_next;
int cflags = REG_NOSUB | REG_EXTENDED;
np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a"));
np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3, strdup("regex on dev names:"));
np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0, strdup("regex on non existent dev/path:"));
@ -89,14 +81,16 @@ int main(int argc, char **argv) {
np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2, strdup("grouped regex pathname match:"));
np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:"));
np_add_parameter(&paths, "/home/groups");
np_add_parameter(&paths, "/var");
np_add_parameter(&paths, "/tmp");
np_add_parameter(&paths, "/home/tonvoon");
np_add_parameter(&paths, "/dev/c2t0d0s0");
filesystem_list test_paths = filesystem_list_init();
mp_int_fs_list_append(&test_paths, "/home/groups");
mp_int_fs_list_append(&test_paths, "/var");
mp_int_fs_list_append(&test_paths, "/tmp");
mp_int_fs_list_append(&test_paths, "/home/tonvoon");
mp_int_fs_list_append(&test_paths, "/dev/c2t0d0s0");
ok(test_paths.length == 5, "List counter works correctly with appends");
np_set_best_match(paths, dummy_mount_list, false);
for (p = paths; p; p = p->name_next) {
mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, false);
for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
struct mount_entry *temp_me;
temp_me = p->best_match;
if (!strcmp(p->name, "/home/groups")) {
@ -112,15 +106,19 @@ int main(int argc, char **argv) {
}
}
paths = NULL; /* Bad boy - should free, but this is a test suite */
np_add_parameter(&paths, "/home/groups");
np_add_parameter(&paths, "/var");
np_add_parameter(&paths, "/tmp");
np_add_parameter(&paths, "/home/tonvoon");
np_add_parameter(&paths, "/home");
for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
mp_int_fs_list_del(&test_paths, p);
}
ok(test_paths.length == 0, "List delete sets counter properly");
np_set_best_match(paths, dummy_mount_list, true);
for (p = paths; p; p = p->name_next) {
mp_int_fs_list_append(&test_paths, "/home/groups");
mp_int_fs_list_append(&test_paths, "/var");
mp_int_fs_list_append(&test_paths, "/tmp");
mp_int_fs_list_append(&test_paths, "/home/tonvoon");
mp_int_fs_list_append(&test_paths, "/home");
mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, true);
for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
if (!strcmp(p->name, "/home/groups")) {
ok(!p->best_match, "/home/groups correctly not found");
} else if (!strcmp(p->name, "/var")) {
@ -134,59 +132,66 @@ int main(int argc, char **argv) {
}
}
bool found = false;
/* test deleting first element in paths */
paths = np_del_parameter(paths, NULL);
for (p = paths; p; p = p->name_next) {
if (!strcmp(p->name, "/home/groups"))
found = 1;
}
ok(found == 0, "first element successfully deleted");
found = 0;
p = paths;
while (p) {
if (!strcmp(p->name, "/tmp"))
p = np_del_parameter(p, prev);
else {
prev = p;
p = p->name_next;
mp_int_fs_list_del(&test_paths, NULL);
for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
if (!strcmp(p->name, "/home/groups")) {
found = true;
}
}
ok(!found, "first element successfully deleted");
found = false;
for (p = paths; p; p = p->name_next) {
if (!strcmp(p->name, "/tmp"))
found = 1;
if (p->name_next)
prev = p;
else
last = p;
parameter_list_elem *prev = NULL;
parameter_list_elem *p = NULL;
for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
if (!strcmp(path->name, "/tmp")) {
mp_int_fs_list_del(&test_paths, path);
}
p = path;
}
ok(found == 0, "/tmp element successfully deleted");
p = np_del_parameter(last, prev);
for (p = paths; p; p = p->name_next) {
if (!strcmp(p->name, "/home"))
found = 1;
parameter_list_elem *last = NULL;
for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
if (!strcmp(path->name, "/tmp")) {
found = true;
}
if (path->next) {
prev = path;
} else {
last = path;
}
}
ok(!found, "/tmp element successfully deleted");
int count = 0;
mp_int_fs_list_del(&test_paths, p);
for (p = test_paths.first; p; p = p->next) {
if (!strcmp(p->name, "/home")) {
found = true;
}
last = p;
count++;
}
ok(found == 0, "last (/home) element successfully deleted");
ok(!found, "last (/home) element successfully deleted");
ok(count == 2, "two elements remaining");
return exit_status();
}
void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) {
int matches = 0;
regex_t re;
struct mount_entry *me;
if (regcomp(&re, regstr, cflags) == 0) {
for (me = dummy_mount_list; me; me = me->me_next) {
if (np_regex_match_mount_entry(me, &re))
regex_t regex;
if (regcomp(&regex, regstr, cflags) == 0) {
int matches = 0;
for (struct mount_entry *me = dummy_mount_list; me; me = me->me_next) {
if (np_regex_match_mount_entry(me, &regex)) {
matches++;
}
}
ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches);
} else
} else {
ok(false, "regex '%s' not compilable", regstr);
}
}

View file

@ -0,0 +1,6 @@
#!/usr/bin/perl
use Test::More;
if (! -e "./test_check_disk") {
plan skip_all => "./test_check_disk not compiled - please enable libtap library to test";
}
exec "./test_check_disk";

View file

@ -76,7 +76,7 @@ char *strnl(char *);
char *strpcpy(char *, const char *, const char *);
char *strpcat(char *, const char *, const char *);
int xvasprintf(char **strp, const char *fmt, va_list ap);
int xasprintf(char **strp, const char *fmt, ...);
int xasprintf(char **strp, const char *fmt, ...)__attribute__ ((format (printf, 2, 3)));
void usage(const char *) __attribute__((noreturn));
void usage2(const char *, const char *) __attribute__((noreturn));