Merge branch 'master' into refactor/check_tcp

This commit is contained in:
Lorenz Kästle 2025-03-13 00:48:00 +01:00
commit 54a099ed6d
75 changed files with 6240 additions and 4935 deletions

View file

@ -38,8 +38,8 @@
'NP_MYSQL_LOGIN_DETAILS' => '-u root -d test',
'NP_MYSQL_SERVER' => 'localhost',
'NP_MYSQL_SOCKET' => '/var/run/mysqld/mysqld.sock',
'NP_MYSQL_WITH_SLAVE' => '',
'NP_MYSQL_WITH_SLAVE_LOGIN' => '',
'NP_MYSQL_WITH_REPLICA' => '',
'NP_MYSQL_WITH_REPLICA_LOGIN' => '',
'NP_NO_NTP_SERVICE' => 'localhost',
'NP_PORT_TCP_PROXY' => '3128',
'NP_SMB_SHARE' => '',

View file

@ -193,7 +193,6 @@ 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
@ -729,19 +728,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

@ -59,6 +59,7 @@ apt-get -y install perl \
mariadb-server \
mariadb-client \
libmariadb-dev \
libmariadb-dev-compat \
cron \
iputils-ping \
iproute2 \

1
.gitignore vendored
View file

@ -178,7 +178,6 @@ NP-VERSION-FILE
/plugins/check_ntp_peer
/plugins/check_ntp_time
/plugins/check_nwstat
/plugins/check_overcr
/plugins/check_pgsql
/plugins/check_ping
/plugins/check_pop

View file

@ -15,6 +15,8 @@ use warnings;
use Cwd;
use File::Basename;
use JSON;
use IO::File;
use Data::Dumper;
@ -617,6 +619,8 @@ sub testCmd {
chomp $output;
$object->output($output);
eval { $object->{'mp_test_result'} = decode_json($output) };
alarm(0);
my ($pkg, $file, $line) = caller(0);

View file

@ -11,6 +11,9 @@
#include "perfdata.h"
#include "states.h"
// == Global variables
static mp_output_format output_format = MP_FORMAT_DEFAULT;
// == Prototypes ==
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);
@ -55,7 +58,6 @@ static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
*/
mp_check mp_check_init(void) {
mp_check check = {0};
check.format = MP_FORMAT_DEFAULT;
return check;
}
@ -234,7 +236,7 @@ mp_state_enum mp_compute_check_state(const mp_check check) {
char *mp_fmt_output(mp_check check) {
char *result = NULL;
switch (check.format) {
switch (output_format) {
case MP_FORMAT_MULTI_LINE: {
if (check.summary == NULL) {
check.summary = get_subcheck_summary(check);
@ -482,7 +484,7 @@ void mp_print_output(mp_check check) { puts(mp_fmt_output(check)); }
*/
void mp_exit(mp_check check) {
mp_print_output(check);
if (check.format == MP_FORMAT_TEST_JSON) {
if (output_format == MP_FORMAT_TEST_JSON) {
exit(0);
}
@ -533,3 +535,7 @@ parsed_output_format mp_parse_output_format(char *format_string) {
return result;
}
void mp_set_format(mp_output_format format) { output_format = format; }
mp_output_format mp_get_format(void) { return output_format; }

View file

@ -35,6 +35,12 @@ typedef enum output_format {
#define MP_FORMAT_DEFAULT MP_FORMAT_MULTI_LINE
/*
* Format related functions
*/
void mp_set_format(mp_output_format format);
mp_output_format mp_get_format(void);
/*
* The main state object of a plugin. Exists only ONCE per plugin.
* This is the "root" of a tree of singular checks.
@ -42,7 +48,6 @@ typedef enum output_format {
* in the first layer of subchecks
*/
typedef struct {
mp_output_format format; // The output format
char *summary; // Overall summary, if not set a summary will be automatically generated
mp_subcheck_list *subchecks;
} mp_check;

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_nwstat check_ping \
check_real check_smtp check_ssh check_tcp check_time check_ntp_time \
check_ups check_users negate \
urlize @EXTRAS@
@ -46,7 +46,37 @@ SUBDIRS = picohttpparser
np_test_scripts = tests/test_check_swap.t
EXTRA_DIST = t tests $(np_test_scripts) check_swap.d
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_time.d \
check_nagios.d \
check_dbi.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_ping.d \
check_by_ssh.d \
check_smtp.d \
check_mysql.d \
check_ntp_time.d \
check_dig.d \
check_cluster.d \
check_ups.d \
check_fping.d
PLUGINHDRS = common.h
@ -109,7 +139,6 @@ 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)

View file

@ -29,6 +29,7 @@
*
*****************************************************************************/
#include "states.h"
const char *progname = "check_apt";
const char *copyright = "2006-2024";
const char *email = "devel@monitoring-plugins.org";
@ -37,13 +38,7 @@ const char *email = "devel@monitoring-plugins.org";
#include "runcmd.h"
#include "utils.h"
#include "regex.h"
/* some constants */
typedef enum {
UPGRADE,
DIST_UPGRADE,
NO_UPGRADE
} upgrade_type;
#include "check_apt.d/config.h"
/* Character for hidden input file option (for testing). */
#define INPUT_FILE_OPT CHAR_MAX + 1
@ -61,14 +56,18 @@ typedef enum {
#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)"
/* some standard functions */
static int process_arguments(int /*argc*/, char ** /*argv*/);
typedef struct {
int errorcode;
check_apt_config config;
} check_apt_config_wrapper;
static check_apt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
/* construct the appropriate apt-get cmdline */
static char *construct_cmdline(upgrade_type u, const char *opts);
static char *construct_cmdline(upgrade_type /*u*/, const char * /*opts*/);
/* run an apt-get update */
static int run_update(void);
static int run_update(char * /*update_opts*/);
typedef struct {
int errorcode;
@ -79,42 +78,35 @@ typedef struct {
} run_upgrade_result;
/* run an apt-get upgrade */
static run_upgrade_result run_upgrade(void);
run_upgrade_result run_upgrade(upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical,
const char *upgrade_opts, const char *input_filename);
/* add another clause to a regexp */
static char *add_to_regexp(char *expr, const char *next);
static char *add_to_regexp(char * /*expr*/, const char * /*next*/);
/* extract package name from Inst line */
static char *pkg_name(char *line);
static char *pkg_name(char * /*line*/);
/* string comparison function for qsort */
static int cmpstringp(const void *p1, const void *p2);
static int cmpstringp(const void * /*p1*/, const void * /*p2*/);
/* configuration variables */
static int verbose = 0; /* -v */
static bool list = false; /* list packages available for upgrade */
static bool do_update = false; /* whether to call apt-get update */
static bool only_critical = false; /* whether to warn about non-critical updates */
static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */
static char *upgrade_opts = NULL; /* options to override defaults for upgrade */
static char *update_opts = NULL; /* options to override defaults for update */
static char *do_include = NULL; /* regexp to only include certain packages */
static char *do_exclude = NULL; /* regexp to only exclude certain packages */
static char *do_critical = NULL; /* regexp specifying critical packages */
static char *input_filename = NULL; /* input filename for testing */
/* number of packages available for upgrade to return WARNING status */
static int packages_warning = 1;
static int verbose = 0; /* -v */
/* other global variables */
static int stderr_warning = 0; /* if a cmd issued output on stderr */
static int exec_warning = 0; /* if a cmd exited non-zero */
static bool stderr_warning = false; /* if a cmd issued output on stderr */
static bool exec_warning = false; /* if a cmd exited non-zero */
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_apt_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage_va(_("Could not parse arguments"));
}
const check_apt_config config = tmp_config.config;
/* Set signal handling and alarm timeout */
if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
usage_va(_("Cannot catch SIGALRM"));
@ -123,14 +115,15 @@ int main(int argc, char **argv) {
/* handle timeouts gracefully... */
alarm(timeout_interval);
int result = STATE_UNKNOWN;
mp_state_enum result = STATE_UNKNOWN;
/* if they want to run apt-get update first... */
if (do_update) {
result = run_update();
if (config.do_update) {
result = run_update(config.update_opts);
}
/* apt-get upgrade */
run_upgrade_result upgrad_res = run_upgrade();
run_upgrade_result upgrad_res =
run_upgrade(config.upgrade, config.do_include, config.do_exclude, config.do_critical, config.upgrade_opts, config.input_filename);
result = max_state(result, upgrad_res.errorcode);
int packages_available = upgrad_res.package_count;
@ -140,18 +133,18 @@ int main(int argc, char **argv) {
if (sec_count > 0) {
result = max_state(result, STATE_CRITICAL);
} else if (packages_available >= packages_warning && only_critical == false) {
} else if (packages_available >= config.packages_warning && !config.only_critical) {
result = max_state(result, STATE_WARNING);
} else if (result > STATE_UNKNOWN) {
result = STATE_UNKNOWN;
}
printf(_("APT %s: %d packages available for %s (%d critical updates). %s%s%s%s|available_upgrades=%d;;;0 critical_updates=%d;;;0\n"),
state_text(result), packages_available, (upgrade == DIST_UPGRADE) ? "dist-upgrade" : "upgrade", sec_count,
state_text(result), packages_available, (config.upgrade == DIST_UPGRADE) ? "dist-upgrade" : "upgrade", sec_count,
(stderr_warning) ? " warnings detected" : "", (stderr_warning && exec_warning) ? "," : "",
(exec_warning) ? " errors detected" : "", (stderr_warning || exec_warning) ? "." : "", packages_available, sec_count);
if (list) {
if (config.list) {
qsort(secpackages_list, sec_count, sizeof(char *), cmpstringp);
qsort(packages_list, packages_available - sec_count, sizeof(char *), cmpstringp);
@ -159,7 +152,7 @@ int main(int argc, char **argv) {
printf("%s (security)\n", secpackages_list[i]);
}
if (only_critical == false) {
if (!config.only_critical) {
for (int i = 0; i < packages_available - sec_count; i++) {
printf("%s\n", packages_list[i]);
}
@ -170,7 +163,7 @@ int main(int argc, char **argv) {
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
check_apt_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'},
@ -179,7 +172,7 @@ int process_arguments(int argc, char **argv) {
{"upgrade", optional_argument, 0, 'U'},
{"no-upgrade", no_argument, 0, 'n'},
{"dist-upgrade", optional_argument, 0, 'd'},
{"list", no_argument, false, 'l'},
{"list", no_argument, 0, 'l'},
{"include", required_argument, 0, 'i'},
{"exclude", required_argument, 0, 'e'},
{"critical", required_argument, 0, 'c'},
@ -188,6 +181,11 @@ int process_arguments(int argc, char **argv) {
{"packages-warning", required_argument, 0, 'w'},
{0, 0, 0, 0}};
check_apt_config_wrapper result = {
.errorcode = OK,
.config = check_apt_config_init(),
};
while (true) {
int option_char = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL);
@ -209,55 +207,55 @@ int process_arguments(int argc, char **argv) {
timeout_interval = atoi(optarg);
break;
case 'd':
upgrade = DIST_UPGRADE;
result.config.upgrade = DIST_UPGRADE;
if (optarg != NULL) {
upgrade_opts = strdup(optarg);
if (upgrade_opts == NULL) {
result.config.upgrade_opts = strdup(optarg);
if (result.config.upgrade_opts == NULL) {
die(STATE_UNKNOWN, "strdup failed");
}
}
break;
case 'U':
upgrade = UPGRADE;
result.config.upgrade = UPGRADE;
if (optarg != NULL) {
upgrade_opts = strdup(optarg);
if (upgrade_opts == NULL) {
result.config.upgrade_opts = strdup(optarg);
if (result.config.upgrade_opts == NULL) {
die(STATE_UNKNOWN, "strdup failed");
}
}
break;
case 'n':
upgrade = NO_UPGRADE;
result.config.upgrade = NO_UPGRADE;
break;
case 'u':
do_update = true;
result.config.do_update = true;
if (optarg != NULL) {
update_opts = strdup(optarg);
if (update_opts == NULL) {
result.config.update_opts = strdup(optarg);
if (result.config.update_opts == NULL) {
die(STATE_UNKNOWN, "strdup failed");
}
}
break;
case 'l':
list = true;
result.config.list = true;
break;
case 'i':
do_include = add_to_regexp(do_include, optarg);
result.config.do_include = add_to_regexp(result.config.do_include, optarg);
break;
case 'e':
do_exclude = add_to_regexp(do_exclude, optarg);
result.config.do_exclude = add_to_regexp(result.config.do_exclude, optarg);
break;
case 'c':
do_critical = add_to_regexp(do_critical, optarg);
result.config.do_critical = add_to_regexp(result.config.do_critical, optarg);
break;
case 'o':
only_critical = true;
result.config.only_critical = true;
break;
case INPUT_FILE_OPT:
input_filename = optarg;
result.config.input_filename = optarg;
break;
case 'w':
packages_warning = atoi(optarg);
result.config.packages_warning = atoi(optarg);
break;
default:
/* print short usage statement if args not parsable */
@ -265,11 +263,12 @@ int process_arguments(int argc, char **argv) {
}
}
return OK;
return result;
}
/* run an apt-get upgrade */
run_upgrade_result run_upgrade(void) {
run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical,
const char *upgrade_opts, const char *input_filename) {
regex_t ereg;
/* initialize ereg as it is possible it is printed while uninitialized */
memset(&ereg, '\0', sizeof(ereg.buffer));
@ -332,7 +331,7 @@ run_upgrade_result run_upgrade(void) {
fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
}
char **pkglist = malloc(sizeof(char *) * chld_out.lines);
char **pkglist = malloc(sizeof(char *) * chld_out.lines);
if (!pkglist) {
die(STATE_UNKNOWN, "malloc failed!\n");
}
@ -385,7 +384,7 @@ run_upgrade_result run_upgrade(void) {
/* If we get anything on stderr, at least set warning */
if (input_filename == NULL && chld_err.buflen) {
stderr_warning = 1;
stderr_warning = true;
result.errorcode = max_state(result.errorcode, STATE_WARNING);
if (verbose) {
for (size_t i = 0; i < chld_err.lines; i++) {
@ -405,7 +404,7 @@ run_upgrade_result run_upgrade(void) {
}
/* run an apt-get update (needs root) */
int run_update(void) {
int run_update(char *update_opts) {
int result = STATE_UNKNOWN;
char *cmdline;
/* run the update */
@ -418,7 +417,7 @@ int run_update(void) {
* since we were explicitly asked to do so, this is treated as
* a critical error. */
if (result != 0) {
exec_warning = 1;
exec_warning = true;
result = STATE_CRITICAL;
fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
}
@ -446,7 +445,7 @@ int run_update(void) {
char *pkg_name(char *line) {
char *start = line + strlen(PKGINST_PREFIX);
int len = strlen(start);
size_t len = strlen(start);
char *space = index(start, ' ');
if (space != NULL) {
@ -464,35 +463,37 @@ char *pkg_name(char *line) {
return pkg;
}
int cmpstringp(const void *p1, const void *p2) { return strcmp(*(char *const *)p1, *(char *const *)p2); }
int cmpstringp(const void *left_string, const void *right_string) {
return strcmp(*(char *const *)left_string, *(char *const *)right_string);
}
char *add_to_regexp(char *expr, const char *next) {
char *re = NULL;
char *regex_string = NULL;
if (expr == NULL) {
re = malloc(sizeof(char) * (strlen("()") + strlen(next) + 1));
if (!re) {
regex_string = malloc(sizeof(char) * (strlen("()") + strlen(next) + 1));
if (!regex_string) {
die(STATE_UNKNOWN, "malloc failed!\n");
}
sprintf(re, "(%s)", next);
sprintf(regex_string, "(%s)", next);
} else {
/* resize it, adding an extra char for the new '|' separator */
re = realloc(expr, sizeof(char) * (strlen(expr) + 1 + strlen(next) + 1));
if (!re) {
regex_string = realloc(expr, sizeof(char) * (strlen(expr) + 1 + strlen(next) + 1));
if (!regex_string) {
die(STATE_UNKNOWN, "realloc failed!\n");
}
/* append it starting at ')' in the old re */
sprintf((char *)(re + strlen(re) - 1), "|%s)", next);
sprintf((char *)(regex_string + strlen(regex_string) - 1), "|%s)", next);
}
return re;
return regex_string;
}
char *construct_cmdline(upgrade_type u, const char *opts) {
char *construct_cmdline(upgrade_type upgrade, const char *opts) {
const char *opts_ptr = NULL;
const char *aptcmd = NULL;
switch (u) {
switch (upgrade) {
case UPGRADE:
if (opts == NULL) {
opts_ptr = UPGRADE_DEFAULT_OPTS;

View file

@ -0,0 +1,41 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
/* some constants */
typedef enum {
UPGRADE,
DIST_UPGRADE,
NO_UPGRADE
} upgrade_type;
typedef struct {
bool do_update; /* whether to call apt-get update */
upgrade_type upgrade; /* which type of upgrade to do */
bool only_critical; /* whether to warn about non-critical updates */
bool list; /* list packages available for upgrade */
/* number of packages available for upgrade to return WARNING status */
int packages_warning;
char *upgrade_opts; /* options to override defaults for upgrade */
char *update_opts; /* options to override defaults for update */
char *do_include; /* regexp to only include certain packages */
char *do_exclude; /* regexp to only exclude certain packages */
char *do_critical; /* regexp specifying critical packages */
char *input_filename; /* input filename for testing */
} check_apt_config;
check_apt_config check_apt_config_init() {
check_apt_config tmp = {.do_update = false,
.upgrade = UPGRADE,
.only_critical = false,
.list = false,
.packages_warning = 1,
.update_opts = NULL,
.do_include = NULL,
.do_exclude = NULL,
.do_critical = NULL,
.input_filename = NULL};
return tmp;
}

View file

@ -32,48 +32,28 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "utils.h"
#include "netutils.h"
#include "utils_cmd.h"
#include "check_by_ssh.d/config.h"
#include "states.h"
#ifndef NP_MAXARGS
# define NP_MAXARGS 1024
#endif
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int validate_arguments(void);
static void comm_append(const char * /*str*/);
typedef struct {
int errorcode;
check_by_ssh_config config;
} check_by_ssh_config_wrapper;
static check_by_ssh_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper /*config_wrapper*/);
static command_construct comm_append(command_construct /*cmd*/, const char * /*str*/);
static void print_help(void);
void print_usage(void);
static unsigned int commands = 0;
static unsigned int services = 0;
static int skip_stdout = 0;
static int skip_stderr = 0;
static int warn_on_stderr = 0;
static bool unknown_timeout = false;
static char *remotecmd = NULL;
static char **commargv = NULL;
static int commargc = 0;
static char *hostname = NULL;
static char *outputfile = NULL;
static char *host_shortname = NULL;
static char **service;
static bool passive = false;
static bool verbose = false;
int main(int argc, char **argv) {
char *status_text;
int cresult;
int result = STATE_UNKNOWN;
time_t local_time;
FILE *file_pointer = NULL;
output chld_out;
output chld_err;
remotecmd = "";
comm_append(SSH_COMMAND);
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -81,11 +61,15 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
check_by_ssh_config_wrapper tmp_config = process_arguments(argc, argv);
/* process arguments */
if (process_arguments(argc, argv) == ERROR) {
if (tmp_config.errorcode == ERROR) {
usage_va(_("Could not parse arguments"));
}
const check_by_ssh_config config = tmp_config.config;
/* Set signal handling and alarm timeout */
if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
usage_va(_("Cannot catch SIGALRM"));
@ -94,16 +78,18 @@ int main(int argc, char **argv) {
/* run the command */
if (verbose) {
printf("Command: %s\n", commargv[0]);
for (int i = 1; i < commargc; i++) {
printf("Argument %i: %s\n", i, commargv[i]);
printf("Command: %s\n", config.cmd.commargv[0]);
for (int i = 1; i < config.cmd.commargc; i++) {
printf("Argument %i: %s\n", i, config.cmd.commargv[i]);
}
}
result = cmd_run_array(commargv, &chld_out, &chld_err, 0);
output chld_out;
output chld_err;
mp_state_enum result = cmd_run_array(config.cmd.commargv, &chld_out, &chld_err, 0);
/* SSH returns 255 if connection attempt fails; include the first line of error output */
if (result == 255 && unknown_timeout) {
if (result == 255 && config.unknown_timeout) {
printf(_("SSH connection failed: %s\n"), chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
return STATE_UNKNOWN;
}
@ -117,17 +103,24 @@ int main(int argc, char **argv) {
}
}
if (skip_stdout == -1) { /* --skip-stdout specified without argument */
size_t skip_stdout = 0;
if (config.skip_stdout == -1) { /* --skip-stdout specified without argument */
skip_stdout = chld_out.lines;
} else {
skip_stdout = config.skip_stdout;
}
if (skip_stderr == -1) { /* --skip-stderr specified without argument */
size_t skip_stderr = 0;
if (config.skip_stderr == -1) { /* --skip-stderr specified without argument */
skip_stderr = chld_err.lines;
} else {
skip_stderr = config.skip_stderr;
}
/* UNKNOWN or worse if (non-skipped) output found on stderr */
if (chld_err.lines > (size_t)skip_stderr) {
printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]);
if (warn_on_stderr) {
if (config.warn_on_stderr) {
return max_state_alt(result, STATE_WARNING);
}
return max_state_alt(result, STATE_UNKNOWN);
@ -135,13 +128,13 @@ int main(int argc, char **argv) {
/* this is simple if we're not supposed to be passive.
* Wrap up quickly and keep the tricks below */
if (!passive) {
if (!config.passive) {
if (chld_out.lines > (size_t)skip_stdout) {
for (size_t i = skip_stdout; i < chld_out.lines; i++) {
puts(chld_out.line[i]);
}
} else {
printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), state_text(result), remotecmd, result);
printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), state_text(result), config.remotecmd, result);
}
return result; /* return error status from remote command */
}
@ -151,36 +144,34 @@ int main(int argc, char **argv) {
*/
/* process output */
if (!(file_pointer = fopen(outputfile, "a"))) {
printf(_("SSH WARNING: could not open %s\n"), outputfile);
FILE *file_pointer = NULL;
if (!(file_pointer = fopen(config.outputfile, "a"))) {
printf(_("SSH WARNING: could not open %s\n"), config.outputfile);
exit(STATE_UNKNOWN);
}
local_time = time(NULL);
commands = 0;
time_t local_time = time(NULL);
unsigned int commands = 0;
char *status_text;
int cresult;
for (size_t i = skip_stdout; i < chld_out.lines; i++) {
status_text = chld_out.line[i++];
if (i == chld_out.lines || strstr(chld_out.line[i], "STATUS CODE: ") == NULL) {
die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname);
}
if (service[commands] && status_text && sscanf(chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) {
fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, host_shortname, service[commands++],
cresult, status_text);
if (config.service[commands] && status_text && sscanf(chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) {
fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, config.host_shortname,
config.service[commands++], cresult, status_text);
}
}
/* Multiple commands and passive checking should always return OK */
return result;
exit(result);
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
char *p1;
char *p2;
int option = 0;
check_by_ssh_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'},
@ -210,24 +201,33 @@ int process_arguments(int argc, char **argv) {
{"configfile", optional_argument, 0, 'F'},
{0, 0, 0, 0}};
check_by_ssh_config_wrapper result = {
.errorcode = OK,
.config = check_by_ssh_config_init(),
};
if (argc < 2) {
return ERROR;
result.errorcode = ERROR;
return result;
}
for (c = 1; c < argc; c++) {
if (strcmp("-to", argv[c]) == 0) {
strcpy(argv[c], "-t");
for (int index = 1; index < argc; index++) {
if (strcmp("-to", argv[index]) == 0) {
strcpy(argv[index], "-t");
}
}
while (1) {
c = getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option);
result.config.cmd = comm_append(result.config.cmd, SSH_COMMAND);
if (c == -1 || c == EOF) {
int option = 0;
while (true) {
int opt_index = getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option);
if (opt_index == -1 || opt_index == EOF) {
break;
}
switch (c) {
switch (opt_index) {
case 'V': /* version */
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
@ -245,169 +245,182 @@ int process_arguments(int argc, char **argv) {
}
break;
case 'U':
unknown_timeout = true;
result.config.unknown_timeout = true;
break;
case 'H': /* host */
hostname = optarg;
result.config.hostname = optarg;
break;
case 'p': /* port number */
if (!is_integer(optarg)) {
usage_va(_("Port must be a positive integer"));
}
comm_append("-p");
comm_append(optarg);
result.config.cmd = comm_append(result.config.cmd, "-p");
result.config.cmd = comm_append(result.config.cmd, optarg);
break;
case 'O': /* output file */
outputfile = optarg;
passive = true;
result.config.outputfile = optarg;
result.config.passive = true;
break;
case 's': /* description of service to check */
case 's': /* description of service to check */ {
char *p1;
char *p2;
p1 = optarg;
service = realloc(service, (++services) * sizeof(char *));
result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
while ((p2 = index(p1, ':'))) {
*p2 = '\0';
service[services - 1] = p1;
service = realloc(service, (++services) * sizeof(char *));
result.config.service[result.config.number_of_services - 1] = p1;
result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
p1 = p2 + 1;
}
service[services - 1] = p1;
result.config.service[result.config.number_of_services - 1] = p1;
break;
case 'n': /* short name of host in the monitoring configuration */
host_shortname = optarg;
break;
result.config.host_shortname = optarg;
} break;
case 'u':
comm_append("-l");
comm_append(optarg);
result.config.cmd = comm_append(result.config.cmd, "-l");
result.config.cmd = comm_append(result.config.cmd, optarg);
break;
case 'l': /* login name */
comm_append("-l");
comm_append(optarg);
result.config.cmd = comm_append(result.config.cmd, "-l");
result.config.cmd = comm_append(result.config.cmd, optarg);
break;
case 'i': /* identity */
comm_append("-i");
comm_append(optarg);
result.config.cmd = comm_append(result.config.cmd, "-i");
result.config.cmd = comm_append(result.config.cmd, optarg);
break;
case '1': /* Pass these switches directly to ssh */
comm_append("-1");
result.config.cmd = comm_append(result.config.cmd, "-1");
break;
case '2': /* 1 to force version 1, 2 to force version 2 */
comm_append("-2");
result.config.cmd = comm_append(result.config.cmd, "-2");
break;
case '4': /* -4 for IPv4 */
comm_append("-4");
result.config.cmd = comm_append(result.config.cmd, "-4");
break;
case '6': /* -6 for IPv6 */
comm_append("-6");
result.config.cmd = comm_append(result.config.cmd, "-6");
break;
case 'f': /* fork to background */
comm_append("-f");
result.config.cmd = comm_append(result.config.cmd, "-f");
break;
case 'C': /* Command for remote machine */
commands++;
if (commands > 1) {
xasprintf(&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
result.config.commands++;
if (result.config.commands > 1) {
xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
}
xasprintf(&remotecmd, "%s%s", remotecmd, optarg);
xasprintf(&result.config.remotecmd, "%s%s", result.config.remotecmd, optarg);
break;
case 'S': /* skip n (or all) lines on stdout */
if (optarg == NULL) {
skip_stdout = -1; /* skip all output on stdout */
result.config.skip_stdout = -1; /* skip all output on stdout */
} else if (!is_integer(optarg)) {
usage_va(_("skip-stdout argument must be an integer"));
} else {
skip_stdout = atoi(optarg);
result.config.skip_stdout = atoi(optarg);
}
break;
case 'E': /* skip n (or all) lines on stderr */
if (optarg == NULL) {
skip_stderr = -1; /* skip all output on stderr */
result.config.skip_stderr = -1; /* skip all output on stderr */
} else if (!is_integer(optarg)) {
usage_va(_("skip-stderr argument must be an integer"));
} else {
skip_stderr = atoi(optarg);
result.config.skip_stderr = atoi(optarg);
}
break;
case 'W': /* exit with warning if there is an output on stderr */
warn_on_stderr = 1;
result.config.warn_on_stderr = true;
break;
case 'o': /* Extra options for the ssh command */
comm_append("-o");
comm_append(optarg);
result.config.cmd = comm_append(result.config.cmd, "-o");
result.config.cmd = comm_append(result.config.cmd, optarg);
break;
case 'q': /* Tell the ssh command to be quiet */
comm_append("-q");
result.config.cmd = comm_append(result.config.cmd, "-q");
break;
case 'F': /* ssh configfile */
comm_append("-F");
comm_append(optarg);
result.config.cmd = comm_append(result.config.cmd, "-F");
result.config.cmd = comm_append(result.config.cmd, optarg);
break;
default: /* help */
usage5();
}
}
c = optind;
if (hostname == NULL) {
int c = optind;
if (result.config.hostname == NULL) {
if (c <= argc) {
die(STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
}
hostname = argv[c++];
result.config.hostname = argv[c++];
}
if (strlen(remotecmd) == 0) {
if (strlen(result.config.remotecmd) == 0) {
for (; c < argc; c++) {
if (strlen(remotecmd) > 0) {
xasprintf(&remotecmd, "%s %s", remotecmd, argv[c]);
if (strlen(result.config.remotecmd) > 0) {
xasprintf(&result.config.remotecmd, "%s %s", result.config.remotecmd, argv[c]);
} else {
xasprintf(&remotecmd, "%s", argv[c]);
xasprintf(&result.config.remotecmd, "%s", argv[c]);
}
}
}
if (commands > 1 || passive) {
xasprintf(&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
if (result.config.commands > 1 || result.config.passive) {
xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
}
if (remotecmd == NULL || strlen(remotecmd) <= 1) {
if (result.config.remotecmd == NULL || strlen(result.config.remotecmd) <= 1) {
usage_va(_("No remotecmd"));
}
comm_append(hostname);
comm_append(remotecmd);
result.config.cmd = comm_append(result.config.cmd, result.config.hostname);
result.config.cmd = comm_append(result.config.cmd, result.config.remotecmd);
return validate_arguments();
return validate_arguments(result);
}
void comm_append(const char *str) {
command_construct comm_append(command_construct cmd, const char *str) {
if (++commargc > NP_MAXARGS) {
if (verbose) {
for (int i = 0; i < cmd.commargc; i++) {
printf("Current command: [%i] %s\n", i, cmd.commargv[i]);
}
printf("Appending: %s\n", str);
}
if (++cmd.commargc > NP_MAXARGS) {
die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS);
}
if ((commargv = (char **)realloc(commargv, (commargc + 1) * sizeof(char *))) == NULL) {
if ((cmd.commargv = (char **)realloc(cmd.commargv, (cmd.commargc + 1) * sizeof(char *))) == NULL) {
die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n"));
}
commargv[commargc - 1] = strdup(str);
commargv[commargc] = NULL;
cmd.commargv[cmd.commargc - 1] = strdup(str);
cmd.commargv[cmd.commargc] = NULL;
return cmd;
}
int validate_arguments(void) {
if (remotecmd == NULL || hostname == NULL) {
return ERROR;
check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper config_wrapper) {
if (config_wrapper.config.remotecmd == NULL || config_wrapper.config.hostname == NULL) {
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
if (passive && commands != services) {
if (config_wrapper.config.passive && config_wrapper.config.commands != config_wrapper.config.number_of_services) {
die(STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
}
if (passive && host_shortname == NULL) {
if (config_wrapper.config.passive && config_wrapper.config.host_shortname == NULL) {
die(STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname);
}
return OK;
return config_wrapper;
}
void print_help(void) {

View file

@ -0,0 +1,56 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
typedef struct {
int commargc;
char **commargv;
} command_construct;
typedef struct {
char *hostname;
char *host_shortname;
char **service;
unsigned int number_of_services;
unsigned int commands; // Not needed during actual test run
char *remotecmd;
command_construct cmd;
bool unknown_timeout;
bool warn_on_stderr;
int skip_stdout;
int skip_stderr;
bool passive;
char *outputfile;
} check_by_ssh_config;
check_by_ssh_config check_by_ssh_config_init() {
check_by_ssh_config tmp = {
.hostname = NULL,
.host_shortname = NULL,
.service = NULL,
.number_of_services = 0,
.commands = 0,
.remotecmd = "",
.cmd =
{
.commargc = 0,
.commargv = NULL,
},
.unknown_timeout = false,
.warn_on_stderr = false,
.skip_stderr = 0,
.skip_stdout = 0,
.passive = false,
.outputfile = NULL,
};
return tmp;
}

View file

@ -29,42 +29,20 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "utils.h"
#include "utils_base.h"
enum {
CHECK_SERVICES = 1,
CHECK_HOSTS = 2
};
#include "check_cluster.d/config.h"
static void print_help(void);
void print_usage(void);
static int total_services_ok = 0;
static int total_services_warning = 0;
static int total_services_unknown = 0;
static int total_services_critical = 0;
static int total_hosts_up = 0;
static int total_hosts_down = 0;
static int total_hosts_unreachable = 0;
static char *warn_threshold;
static char *crit_threshold;
static int check_type = CHECK_SERVICES;
static char *data_vals = NULL;
static char *label = NULL;
static int verbose = 0;
static int process_arguments(int /*argc*/, char ** /*argv*/);
typedef struct {
int errorcode;
check_cluster_config config;
} check_cluster_config_wrapper;
static check_cluster_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
int main(int argc, char **argv) {
char *ptr;
int data_val;
int return_code = STATE_OK;
thresholds *thresholds = NULL;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -72,20 +50,32 @@ 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_cluster_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage(_("Could not parse arguments"));
}
const check_cluster_config config = tmp_config.config;
/* Initialize the thresholds */
set_thresholds(&thresholds, warn_threshold, crit_threshold);
if (verbose)
print_thresholds("check_cluster", thresholds);
if (verbose) {
print_thresholds("check_cluster", config.thresholds);
}
int data_val;
int total_services_ok = 0;
int total_services_warning = 0;
int total_services_unknown = 0;
int total_services_critical = 0;
int total_hosts_up = 0;
int total_hosts_down = 0;
int total_hosts_unreachable = 0;
/* check the data values */
for (ptr = strtok(data_vals, ","); ptr != NULL; ptr = strtok(NULL, ",")) {
for (char *ptr = strtok(config.data_vals, ","); ptr != NULL; ptr = strtok(NULL, ",")) {
data_val = atoi(ptr);
if (check_type == CHECK_SERVICES) {
if (config.check_type == CHECK_SERVICES) {
switch (data_val) {
case 0:
total_services_ok++;
@ -119,101 +109,108 @@ int main(int argc, char **argv) {
}
}
int return_code = STATE_OK;
/* return the status of the cluster */
if (check_type == CHECK_SERVICES) {
return_code = get_status(total_services_warning + total_services_unknown + total_services_critical, thresholds);
if (config.check_type == CHECK_SERVICES) {
return_code = get_status(total_services_warning + total_services_unknown + total_services_critical, config.thresholds);
printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", state_text(return_code),
(label == NULL) ? "Service cluster" : label, total_services_ok, total_services_warning, total_services_unknown,
(config.label == NULL) ? "Service cluster" : config.label, total_services_ok, total_services_warning, total_services_unknown,
total_services_critical);
} else {
return_code = get_status(total_hosts_down + total_hosts_unreachable, thresholds);
printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n", state_text(return_code), (label == NULL) ? "Host cluster" : label,
total_hosts_up, total_hosts_down, total_hosts_unreachable);
return_code = get_status(total_hosts_down + total_hosts_unreachable, config.thresholds);
printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n", state_text(return_code),
(config.label == NULL) ? "Host cluster" : config.label, total_hosts_up, total_hosts_down, total_hosts_unreachable);
}
return return_code;
exit(return_code);
}
int process_arguments(int argc, char **argv) {
int c;
char *ptr;
int option = 0;
check_cluster_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"data", required_argument, 0, 'd'}, {"warning", required_argument, 0, 'w'},
{"critical", required_argument, 0, 'c'}, {"label", required_argument, 0, 'l'},
{"host", no_argument, 0, 'h'}, {"service", no_argument, 0, 's'},
{"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'H'}, {0, 0, 0, 0}};
check_cluster_config_wrapper result = {
.errorcode = OK,
.config = check_cluster_config_init(),
};
/* no options were supplied */
if (argc < 2)
return ERROR;
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
while (1) {
int option = 0;
char *warn_threshold = NULL;
char *crit_threshold = NULL;
while (true) {
int option_index = getopt_long(argc, argv, "hHsvVw:c:d:l:", longopts, &option);
c = getopt_long(argc, argv, "hHsvVw:c:d:l:", 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 'h': /* host cluster */
check_type = CHECK_HOSTS;
result.config.check_type = CHECK_HOSTS;
break;
case 's': /* service cluster */
check_type = CHECK_SERVICES;
result.config.check_type = CHECK_SERVICES;
break;
case 'w': /* warning threshold */
warn_threshold = strdup(optarg);
break;
case 'c': /* warning threshold */
crit_threshold = strdup(optarg);
break;
case 'd': /* data values */
data_vals = (char *)strdup(optarg);
result.config.data_vals = strdup(optarg);
/* validate data */
for (ptr = data_vals; ptr != NULL; ptr += 2) {
if (ptr[0] < '0' || ptr[0] > '3')
return ERROR;
if (ptr[1] == '\0')
for (char *ptr = result.config.data_vals; ptr != NULL; ptr += 2) {
if (ptr[0] < '0' || ptr[0] > '3') {
result.errorcode = ERROR;
return result;
}
if (ptr[1] == '\0') {
break;
if (ptr[1] != ',')
return ERROR;
}
if (ptr[1] != ',') {
result.errorcode = ERROR;
return result;
}
}
break;
case 'l': /* text label */
label = (char *)strdup(optarg);
result.config.label = strdup(optarg);
break;
case 'v': /* verbose */
verbose++;
break;
case 'V': /* version */
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
break;
case 'H': /* help */
print_help();
exit(STATE_UNKNOWN);
break;
default:
return ERROR;
result.errorcode = ERROR;
return result;
break;
}
}
if (data_vals == NULL)
return ERROR;
if (result.config.data_vals == NULL) {
result.errorcode = ERROR;
return result;
}
return OK;
set_thresholds(&result.config.thresholds, warn_threshold, crit_threshold);
return result;
}
void print_help(void) {

View file

@ -0,0 +1,27 @@
#pragma once
#include "../../config.h"
#include "../../lib/thresholds.h"
#include <stddef.h>
enum {
CHECK_SERVICES = 1,
CHECK_HOSTS = 2
};
typedef struct {
char *data_vals;
thresholds *thresholds;
int check_type;
char *label;
} check_cluster_config;
check_cluster_config check_cluster_config_init() {
check_cluster_config tmp = {
.data_vals = NULL,
.thresholds = NULL,
.check_type = CHECK_SERVICES,
.label = NULL,
};
return tmp;
}

View file

@ -33,6 +33,8 @@ const char *progname = "check_dbi";
const char *copyright = "2011-2024";
const char *email = "devel@monitoring-plugins.org";
#include "../lib/monitoringplug.h"
#include "check_dbi.d/config.h"
#include "common.h"
#include "utils.h"
#include "utils_cmd.h"
@ -53,55 +55,24 @@ const char *email = "devel@monitoring-plugins.org";
#include <stdarg.h>
typedef enum {
METRIC_CONN_TIME,
METRIC_SERVER_VERSION,
METRIC_QUERY_RESULT,
METRIC_QUERY_TIME,
} np_dbi_metric_t;
typedef enum {
TYPE_NUMERIC,
TYPE_STRING,
} np_dbi_type_t;
typedef struct {
char *key;
char *value;
} driver_option_t;
static char *host = NULL;
static int verbose = 0;
static char *warning_range = NULL;
static char *critical_range = NULL;
static thresholds *dbi_thresholds = NULL;
typedef struct {
int errorcode;
check_dbi_config config;
} check_dbi_config_wrapper;
static char *expect = NULL;
static regex_t expect_re;
static char *expect_re_str = NULL;
static int expect_re_cflags = 0;
static np_dbi_metric_t metric = METRIC_QUERY_RESULT;
static np_dbi_type_t type = TYPE_NUMERIC;
static char *np_dbi_driver = NULL;
static driver_option_t *np_dbi_options = NULL;
static int np_dbi_options_num = 0;
static char *np_dbi_database = NULL;
static char *np_dbi_query = NULL;
static int process_arguments(int, char **);
static int validate_arguments(void);
static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/);
void print_usage(void);
static void print_help(void);
static double timediff(struct timeval, struct timeval);
static double timediff(struct timeval /*start*/, struct timeval /*end*/);
static void np_dbi_print_error(dbi_conn, char *, ...);
static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
static int do_query(dbi_conn, const char **, double *, double *);
static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/,
mp_dbi_type /*type*/, char * /*np_dbi_query*/);
int main(int argc, char **argv) {
int status = STATE_UNKNOWN;
@ -119,8 +90,6 @@ int main(int argc, char **argv) {
const char *query_val_str = NULL;
double query_val = 0.0;
int i;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -128,8 +97,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_dbi_config_wrapper tmp = process_arguments(argc, argv);
if (tmp.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
const check_dbi_config config = tmp.config;
/* Set signal handling and alarm */
if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
@ -137,8 +111,9 @@ int main(int argc, char **argv) {
}
alarm(timeout_interval);
if (verbose > 2)
if (verbose > 2) {
printf("Initializing DBI\n");
}
dbi_inst *instance_p = {0};
@ -152,12 +127,13 @@ int main(int argc, char **argv) {
return STATE_UNKNOWN;
}
if (verbose)
printf("Opening DBI driver '%s'\n", np_dbi_driver);
if (verbose) {
printf("Opening DBI driver '%s'\n", config.dbi_driver);
}
driver = dbi_driver_open_r(np_dbi_driver, instance_p);
driver = dbi_driver_open_r(config.dbi_driver, instance_p);
if (!driver) {
printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", np_dbi_driver);
printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
printf("Known drivers:\n");
for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) {
@ -176,17 +152,19 @@ int main(int argc, char **argv) {
return STATE_UNKNOWN;
}
for (i = 0; i < np_dbi_options_num; ++i) {
for (size_t i = 0; i < config.dbi_options_num; ++i) {
const char *opt;
if (verbose > 1)
printf("Setting DBI driver option '%s' to '%s'\n", np_dbi_options[i].key, np_dbi_options[i].value);
if (verbose > 1) {
printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key, config.dbi_options[i].value);
}
if (!dbi_conn_set_option(conn, np_dbi_options[i].key, np_dbi_options[i].value))
if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) {
continue;
}
/* else: status != 0 */
np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", np_dbi_options[i].key, np_dbi_options[i].value);
np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", config.dbi_options[i].key, config.dbi_options[i].value);
printf("Known driver options:\n");
for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) {
@ -196,10 +174,11 @@ int main(int argc, char **argv) {
return STATE_UNKNOWN;
}
if (host) {
if (verbose > 1)
printf("Setting DBI driver option 'host' to '%s'\n", host);
dbi_conn_set_option(conn, "host", host);
if (config.host) {
if (verbose > 1) {
printf("Setting DBI driver option 'host' to '%s'\n", config.host);
}
dbi_conn_set_option(conn, "host", config.host);
}
if (verbose) {
@ -209,10 +188,12 @@ int main(int argc, char **argv) {
dbname = dbi_conn_get_option(conn, "dbname");
host = dbi_conn_get_option(conn, "host");
if (!dbname)
if (!dbname) {
dbname = "<unspecified>";
if (!host)
}
if (!host) {
host = "<unspecified>";
}
printf("Connecting to database '%s' at host '%s'\n", dbname, host);
}
@ -226,109 +207,122 @@ int main(int argc, char **argv) {
conn_time = timediff(start_timeval, end_timeval);
server_version = dbi_conn_get_engine_version(conn);
if (verbose)
if (verbose) {
printf("Connected to server version %u\n", server_version);
}
if (metric == METRIC_SERVER_VERSION)
status = get_status(server_version, dbi_thresholds);
if (config.metric == METRIC_SERVER_VERSION) {
status = get_status(server_version, config.dbi_thresholds);
}
if (verbose)
if (verbose) {
printf("Time elapsed: %f\n", conn_time);
}
if (metric == METRIC_CONN_TIME)
status = get_status(conn_time, dbi_thresholds);
if (config.metric == METRIC_CONN_TIME) {
status = get_status(conn_time, config.dbi_thresholds);
}
/* select a database */
if (np_dbi_database) {
if (verbose > 1)
printf("Selecting database '%s'\n", np_dbi_database);
if (config.dbi_database) {
if (verbose > 1) {
printf("Selecting database '%s'\n", config.dbi_database);
}
if (dbi_conn_select_db(conn, np_dbi_database)) {
np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", np_dbi_database);
if (dbi_conn_select_db(conn, config.dbi_database)) {
np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database);
return STATE_UNKNOWN;
}
}
if (np_dbi_query) {
if (config.dbi_query) {
/* execute query */
status = do_query(conn, &query_val_str, &query_val, &query_time);
if (status != STATE_OK)
status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, config.dbi_query);
if (status != STATE_OK) {
/* do_query prints an error message in this case */
return status;
}
if (metric == METRIC_QUERY_RESULT) {
if (expect) {
if ((!query_val_str) || strcmp(query_val_str, expect))
if (config.metric == METRIC_QUERY_RESULT) {
if (config.expect) {
if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
status = STATE_CRITICAL;
else
} else {
status = STATE_OK;
} else if (expect_re_str) {
}
} else if (config.expect_re_str) {
int err;
regex_t expect_re = {};
err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
if (!err)
if (!err) {
status = STATE_OK;
else if (err == REG_NOMATCH)
} else if (err == REG_NOMATCH) {
status = STATE_CRITICAL;
else {
} else {
char errmsg[1024];
regerror(err, &expect_re, errmsg, sizeof(errmsg));
printf("ERROR - failed to execute regular expression: %s\n", errmsg);
status = STATE_CRITICAL;
}
} else
status = get_status(query_val, dbi_thresholds);
} else if (metric == METRIC_QUERY_TIME)
status = get_status(query_time, dbi_thresholds);
} else {
status = get_status(query_val, config.dbi_thresholds);
}
} else if (config.metric == METRIC_QUERY_TIME) {
status = get_status(query_time, config.dbi_thresholds);
}
}
if (verbose)
if (verbose) {
printf("Closing connection\n");
}
dbi_conn_close(conn);
/* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
* which should have been reported and handled (abort) before
* ... unless we expected a string to be returned */
assert((metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (type == TYPE_STRING));
assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (config.type == TYPE_STRING));
assert((type != TYPE_STRING) || (expect || expect_re_str));
assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
printf("%s - connection time: %fs", state_text(status), conn_time);
if (np_dbi_query) {
if (type == TYPE_STRING) {
assert(expect || expect_re_str);
printf(", '%s' returned '%s' in %fs", np_dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
if (config.dbi_query) {
if (config.type == TYPE_STRING) {
assert(config.expect || config.expect_re_str);
printf(", '%s' returned '%s' in %fs", config.dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
if (status != STATE_OK) {
if (expect)
printf(" (expected '%s')", expect);
else if (expect_re_str)
printf(" (expected regex /%s/%s)", expect_re_str, ((expect_re_cflags & REG_ICASE) ? "i" : ""));
if (config.expect) {
printf(" (expected '%s')", config.expect);
} else if (config.expect_re_str) {
printf(" (expected regex /%s/%s)", config.expect_re_str, ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
}
}
} else if (isnan(query_val))
printf(", '%s' query execution time: %fs", np_dbi_query, query_time);
else
printf(", '%s' returned %f in %fs", np_dbi_query, query_val, query_time);
} else if (isnan(query_val)) {
printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
} else {
printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
}
}
printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "",
((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "", server_version,
((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "",
((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : "");
if (np_dbi_query) {
if (!isnan(query_val)) /* this is also true when -e is used */
printf(" query=%f;%s;%s;;", query_val, ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "",
((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : "");
printf(" querytime=%fs;%s;%s;0;", query_time, ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "",
((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : "");
((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", server_version,
((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range : "",
((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range : "");
if (config.dbi_query) {
if (!isnan(query_val)) { /* this is also true when -e is used */
printf(" query=%f;%s;%s;;", query_val, ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) ? config.warning_range : "",
((config.metric == METRIC_QUERY_RESULT) && config.critical_range) ? config.critical_range : "");
}
printf(" querytime=%fs;%s;%s;0;", query_time, ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range : "",
((config.metric == METRIC_QUERY_TIME) && config.critical_range) ? config.critical_range : "");
}
printf("\n");
return status;
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
check_dbi_config_wrapper process_arguments(int argc, char **argv) {
int option = 0;
static struct option longopts[] = {STD_LONG_OPTS,
@ -343,13 +337,19 @@ int process_arguments(int argc, char **argv) {
{"database", required_argument, 0, 'D'},
{0, 0, 0, 0}};
while (1) {
c = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option);
check_dbi_config_wrapper result = {
.config = check_dbi_config_init(),
.errorcode = OK,
};
int option_char;
while (true) {
option_char = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option);
if (c == EOF)
if (option_char == EOF) {
break;
}
switch (c) {
switch (option_char) {
case '?': /* usage */
usage5();
case 'h': /* help */
@ -360,135 +360,148 @@ int process_arguments(int argc, char **argv) {
exit(STATE_UNKNOWN);
case 'c': /* critical range */
critical_range = optarg;
type = TYPE_NUMERIC;
result.config.critical_range = optarg;
result.config.type = TYPE_NUMERIC;
break;
case 'w': /* warning range */
warning_range = optarg;
type = TYPE_NUMERIC;
result.config.warning_range = optarg;
result.config.type = TYPE_NUMERIC;
break;
case 'e':
expect = optarg;
type = TYPE_STRING;
result.config.expect = optarg;
result.config.type = TYPE_STRING;
break;
case 'R':
expect_re_cflags = REG_ICASE;
result.config.expect_re_cflags = REG_ICASE;
/* fall through */
case 'r': {
int err;
expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
expect_re_str = optarg;
type = TYPE_STRING;
result.config.expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
result.config.expect_re_str = optarg;
result.config.type = TYPE_STRING;
err = regcomp(&expect_re, expect_re_str, expect_re_cflags);
regex_t expect_re = {};
err = regcomp(&expect_re, result.config.expect_re_str, result.config.expect_re_cflags);
if (err) {
char errmsg[1024];
regerror(err, &expect_re, errmsg, sizeof(errmsg));
printf("ERROR - failed to compile regular expression: %s\n", errmsg);
return ERROR;
result.errorcode = ERROR;
return result;
}
break;
}
case 'm':
if (!strcasecmp(optarg, "CONN_TIME"))
metric = METRIC_CONN_TIME;
else if (!strcasecmp(optarg, "SERVER_VERSION"))
metric = METRIC_SERVER_VERSION;
else if (!strcasecmp(optarg, "QUERY_RESULT"))
metric = METRIC_QUERY_RESULT;
else if (!strcasecmp(optarg, "QUERY_TIME"))
metric = METRIC_QUERY_TIME;
else
if (!strcasecmp(optarg, "CONN_TIME")) {
result.config.metric = METRIC_CONN_TIME;
} else if (!strcasecmp(optarg, "SERVER_VERSION")) {
result.config.metric = METRIC_SERVER_VERSION;
} else if (!strcasecmp(optarg, "QUERY_RESULT")) {
result.config.metric = METRIC_QUERY_RESULT;
} else if (!strcasecmp(optarg, "QUERY_TIME")) {
result.config.metric = METRIC_QUERY_TIME;
} else {
usage2(_("Invalid metric"), optarg);
}
break;
case 't': /* timeout */
if (!is_intnonneg(optarg))
if (!is_intnonneg(optarg)) {
usage2(_("Timeout interval must be a positive integer"), optarg);
else
} else {
timeout_interval = atoi(optarg);
}
break;
case 'H': /* host */
if (!is_host(optarg))
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
else
host = optarg;
} else {
result.config.host = optarg;
}
break;
case 'v':
verbose++;
break;
case 'd':
np_dbi_driver = optarg;
result.config.dbi_driver = optarg;
break;
case 'o': {
driver_option_t *new;
driver_option_t *new = NULL;
char *k;
char *v;
char *key = optarg;
char *value = strchr(key, '=');
k = optarg;
v = strchr(k, (int)'=');
if (!v)
if (!value) {
usage2(_("Option must be '<key>=<value>'"), optarg);
}
*v = '\0';
++v;
*value = '\0';
++value;
new = realloc(np_dbi_options, (np_dbi_options_num + 1) * sizeof(*new));
new = realloc(result.config.dbi_options, (result.config.dbi_options_num + 1) * sizeof(*new));
if (!new) {
printf("UNKNOWN - failed to reallocate memory\n");
exit(STATE_UNKNOWN);
}
np_dbi_options = new;
new = np_dbi_options + np_dbi_options_num;
++np_dbi_options_num;
result.config.dbi_options = new;
new = result.config.dbi_options + result.config.dbi_options_num;
result.config.dbi_options_num++;
new->key = k;
new->value = v;
new->key = key;
new->value = value;
} break;
case 'q':
np_dbi_query = optarg;
result.config.dbi_query = optarg;
break;
case 'D':
np_dbi_database = optarg;
result.config.dbi_database = optarg;
break;
}
}
set_thresholds(&dbi_thresholds, warning_range, critical_range);
set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, result.config.critical_range);
return validate_arguments();
return validate_arguments(result);
}
int validate_arguments(void) {
if (!np_dbi_driver)
check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
if (!config_wrapper.config.dbi_driver) {
usage("Must specify a DBI driver");
}
if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) && (!np_dbi_query))
if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || (config_wrapper.config.metric == METRIC_QUERY_TIME)) &&
(!config_wrapper.config.dbi_query)) {
usage("Must specify a query to execute (metric == QUERY_RESULT)");
}
if ((metric != METRIC_CONN_TIME) && (metric != METRIC_SERVER_VERSION) && (metric != METRIC_QUERY_RESULT) &&
(metric != METRIC_QUERY_TIME))
if ((config_wrapper.config.metric != METRIC_CONN_TIME) && (config_wrapper.config.metric != METRIC_SERVER_VERSION) &&
(config_wrapper.config.metric != METRIC_QUERY_RESULT) && (config_wrapper.config.metric != METRIC_QUERY_TIME)) {
usage("Invalid metric specified");
}
if (expect && (warning_range || critical_range || expect_re_str))
if (config_wrapper.config.expect && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect_re_str)) {
usage("Do not mix -e and -w/-c/-r/-R");
}
if (expect_re_str && (warning_range || critical_range || expect))
if (config_wrapper.config.expect_re_str && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect)) {
usage("Do not mix -r/-R and -w/-c/-e");
}
if (expect && (metric != METRIC_QUERY_RESULT))
if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
usage("Option -e requires metric QUERY_RESULT");
}
if (expect_re_str && (metric != METRIC_QUERY_RESULT))
if (config_wrapper.config.expect_re_str && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
usage("Options -r/-R require metric QUERY_RESULT");
}
return OK;
config_wrapper.errorcode = OK;
return config_wrapper;
}
void print_help(void) {
@ -518,6 +531,8 @@ void print_help(void) {
printf(" %s\n", _("DBI driver options"));
printf(" %s\n", "-q, --query=STRING");
printf(" %s\n", _("query to execute"));
printf(" %s\n", "-H STRING");
printf(" %s\n", _("target database host"));
printf("\n");
printf(UT_WARN_CRIT_RANGE);
@ -592,13 +607,7 @@ void print_usage(void) {
printf(" [-e <string>] [-r|-R <regex>]\n");
}
#define CHECK_IGNORE_ERROR(s) \
do { \
if (metric != METRIC_QUERY_RESULT) \
return (s); \
} while (0)
const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type) {
const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type, mp_dbi_metric metric, mp_dbi_type type) {
const char *str;
if (field_type != DBI_TYPE_STRING) {
@ -608,17 +617,20 @@ const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_ty
str = dbi_result_get_string_idx(res, 1);
if ((!str) || (strcmp(str, "ERROR") == 0)) {
CHECK_IGNORE_ERROR(NULL);
if (metric != METRIC_QUERY_RESULT) {
return NULL;
}
np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
return NULL;
}
if ((verbose && (type == TYPE_STRING)) || (verbose > 2))
if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) {
printf("Query returned string '%s'\n", str);
}
return str;
}
double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, mp_dbi_type type) {
double val = NAN;
if (*field_type == DBI_TYPE_INTEGER) {
@ -629,26 +641,33 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
const char *val_str;
char *endptr = NULL;
val_str = get_field_str(conn, res, *field_type);
val_str = get_field_str(conn, res, *field_type, metric, type);
if (!val_str) {
CHECK_IGNORE_ERROR(NAN);
if (metric != METRIC_QUERY_RESULT) {
return NAN;
}
*field_type = DBI_TYPE_ERROR;
return NAN;
}
val = strtod(val_str, &endptr);
if (endptr == val_str) {
CHECK_IGNORE_ERROR(NAN);
if (metric != METRIC_QUERY_RESULT) {
return NAN;
}
printf("CRITICAL - result value is not a numeric: %s\n", val_str);
*field_type = DBI_TYPE_ERROR;
return NAN;
}
if ((endptr != NULL) && (*endptr != '\0')) {
if (verbose)
if (verbose) {
printf("Garbage after value: %s\n", endptr);
}
}
} else {
CHECK_IGNORE_ERROR(NAN);
if (metric != METRIC_QUERY_RESULT) {
return NAN;
}
printf("CRITICAL - cannot parse value of type %s (%i)\n",
(*field_type == DBI_TYPE_BINARY) ? "BINARY"
: (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
@ -660,53 +679,66 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
return val;
}
double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val) {
mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val, mp_dbi_metric metric, mp_dbi_type type) {
unsigned short field_type;
double val = NAN;
if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
CHECK_IGNORE_ERROR(STATE_OK);
if (metric != METRIC_QUERY_RESULT) {
return STATE_OK;
}
np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
return STATE_CRITICAL;
}
if (dbi_result_get_numrows(res) < 1) {
CHECK_IGNORE_ERROR(STATE_OK);
if (metric != METRIC_QUERY_RESULT) {
return STATE_OK;
}
printf("WARNING - no rows returned\n");
return STATE_WARNING;
}
if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
CHECK_IGNORE_ERROR(STATE_OK);
if (metric != METRIC_QUERY_RESULT) {
return STATE_OK;
}
np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
return STATE_CRITICAL;
}
if (dbi_result_get_numfields(res) < 1) {
CHECK_IGNORE_ERROR(STATE_OK);
if (metric != METRIC_QUERY_RESULT) {
return STATE_OK;
}
printf("WARNING - no fields returned\n");
return STATE_WARNING;
}
if (dbi_result_first_row(res) != 1) {
CHECK_IGNORE_ERROR(STATE_OK);
if (metric != METRIC_QUERY_RESULT) {
return STATE_OK;
}
np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
return STATE_CRITICAL;
}
field_type = dbi_result_get_field_type_idx(res, 1);
if (field_type != DBI_TYPE_ERROR) {
if (type == TYPE_STRING)
if (type == TYPE_STRING) {
/* the value will be freed in dbi_result_free */
*res_val_str = strdup(get_field_str(conn, res, field_type));
else
val = get_field(conn, res, &field_type);
*res_val_str = strdup(get_field_str(conn, res, field_type, metric, type));
} else {
val = get_field(conn, res, &field_type, metric, type);
}
}
*res_val = val;
if (field_type == DBI_TYPE_ERROR) {
CHECK_IGNORE_ERROR(STATE_OK);
if (metric != METRIC_QUERY_RESULT) {
return STATE_OK;
}
np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
return STATE_CRITICAL;
}
@ -715,19 +747,19 @@ double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str,
return STATE_OK;
}
#undef CHECK_IGNORE_ERROR
int do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time) {
mp_state_enum do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time, mp_dbi_metric metric, mp_dbi_type type,
char *np_dbi_query) {
dbi_result res;
struct timeval timeval_start;
struct timeval timeval_end;
int status = STATE_OK;
mp_state_enum status = STATE_OK;
assert(np_dbi_query);
if (verbose)
if (verbose) {
printf("Executing query '%s'\n", np_dbi_query);
}
gettimeofday(&timeval_start, NULL);
@ -737,13 +769,14 @@ int do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *r
return STATE_CRITICAL;
}
status = get_query_result(conn, res, res_val_str, res_val);
status = get_query_result(conn, res, res_val_str, res_val, metric, type);
gettimeofday(&timeval_end, NULL);
*res_time = timediff(timeval_start, timeval_end);
if (verbose)
if (verbose) {
printf("Time elapsed: %f\n", *res_time);
}
return status;
}

View file

@ -0,0 +1,63 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#include "../../lib/monitoringplug.h"
typedef enum {
METRIC_CONN_TIME,
METRIC_SERVER_VERSION,
METRIC_QUERY_RESULT,
METRIC_QUERY_TIME,
} mp_dbi_metric;
typedef enum {
TYPE_NUMERIC,
TYPE_STRING,
} mp_dbi_type;
typedef struct {
char *key;
char *value;
} driver_option_t;
typedef struct {
char *dbi_driver;
char *host;
driver_option_t *dbi_options;
size_t dbi_options_num;
char *dbi_database;
char *dbi_query;
char *expect;
char *expect_re_str;
int expect_re_cflags;
mp_dbi_metric metric;
mp_dbi_type type;
char *warning_range;
char *critical_range;
thresholds *dbi_thresholds;
} check_dbi_config;
check_dbi_config check_dbi_config_init() {
check_dbi_config tmp = {
.dbi_driver = NULL,
.host = NULL,
.dbi_options = NULL,
.dbi_options_num = 0,
.dbi_database = NULL,
.dbi_query = NULL,
.expect = NULL,
.expect_re_str = NULL,
.expect_re_cflags = 0,
.metric = METRIC_QUERY_RESULT,
.type = TYPE_NUMERIC,
.warning_range = NULL,
.critical_range = NULL,
.dbi_thresholds = NULL,
};
return tmp;
}

View file

@ -41,97 +41,93 @@ const char *email = "devel@monitoring-plugins.org";
#include "utils.h"
#include "runcmd.h"
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int validate_arguments(void);
#include "check_dig.d/config.h"
#include "states.h"
typedef struct {
int errorcode;
check_dig_config config;
} check_dig_config_wrapper;
static check_dig_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_dig_config_wrapper validate_arguments(check_dig_config_wrapper /*config_wrapper*/);
static void print_help(void);
void print_usage(void);
#define UNDEFINED 0
#define DEFAULT_PORT 53
#define DEFAULT_TRIES 2
static char *query_address = NULL;
static char *record_type = "A";
static char *expected_address = NULL;
static char *dns_server = NULL;
static char *dig_args = "";
static char *query_transport = "";
static bool verbose = false;
static int server_port = DEFAULT_PORT;
static int number_tries = DEFAULT_TRIES;
static double warning_interval = UNDEFINED;
static double critical_interval = UNDEFINED;
static struct timeval tv;
static int verbose = 0;
int main(int argc, char **argv) {
char *command_line;
output chld_out;
output chld_err;
char *msg = NULL;
size_t i;
char *t;
long microsec;
double elapsed_time;
int result = STATE_UNKNOWN;
int timeout_interval_dig;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
/* Set signal handling and alarm */
if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR)
if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
usage_va(_("Cannot catch SIGALRM"));
}
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
check_dig_config_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage_va(_("Could not parse arguments"));
}
const check_dig_config config = tmp_config.config;
/* dig applies the timeout to each try, so we need to work around this */
timeout_interval_dig = timeout_interval / number_tries + number_tries;
int timeout_interval_dig = ((int)timeout_interval / config.number_tries) + config.number_tries;
char *command_line;
/* get the command to run */
xasprintf(&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", PATH_TO_DIG, dig_args, query_transport, server_port, dns_server,
query_address, record_type, number_tries, timeout_interval_dig);
xasprintf(&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", PATH_TO_DIG, config.dig_args, config.query_transport,
config.server_port, config.dns_server, config.query_address, config.record_type, config.number_tries, timeout_interval_dig);
alarm(timeout_interval);
gettimeofday(&tv, NULL);
struct timeval start_time;
gettimeofday(&start_time, NULL);
if (verbose) {
printf("%s\n", command_line);
if (expected_address != NULL) {
printf(_("Looking for: '%s'\n"), expected_address);
if (config.expected_address != NULL) {
printf(_("Looking for: '%s'\n"), config.expected_address);
} else {
printf(_("Looking for: '%s'\n"), query_address);
printf(_("Looking for: '%s'\n"), config.query_address);
}
}
output chld_out;
output chld_err;
char *msg = NULL;
mp_state_enum result = STATE_UNKNOWN;
/* run the command */
if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
result = STATE_WARNING;
msg = (char *)_("dig returned an error status");
}
for (i = 0; i < chld_out.lines; i++) {
for (size_t i = 0; i < chld_out.lines; i++) {
/* the server is responding, we just got the host name... */
if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) {
/* loop through the whole 'ANSWER SECTION' */
for (; i < chld_out.lines; i++) {
/* get the host address */
if (verbose)
if (verbose) {
printf("%s\n", chld_out.line[i]);
}
if (strcasestr(chld_out.line[i], (expected_address == NULL ? query_address : expected_address)) != NULL) {
if (strcasestr(chld_out.line[i], (config.expected_address == NULL ? config.query_address : config.expected_address)) !=
NULL) {
msg = chld_out.line[i];
result = STATE_OK;
/* Translate output TAB -> SPACE */
t = msg;
while ((t = strchr(t, '\t')) != NULL)
*t = ' ';
char *temp = msg;
while ((temp = strchr(temp, '\t')) != NULL) {
*temp = ' ';
}
break;
}
}
@ -154,37 +150,37 @@ int main(int argc, char **argv) {
/* If we get anything on STDERR, at least set warning */
if (chld_err.buflen > 0) {
result = max_state(result, STATE_WARNING);
if (!msg)
for (i = 0; i < chld_err.lines; i++) {
if (!msg) {
for (size_t i = 0; i < chld_err.lines; i++) {
msg = strchr(chld_err.line[0], ':');
if (msg) {
msg++;
break;
}
}
}
}
microsec = deltime(tv);
elapsed_time = (double)microsec / 1.0e6;
long microsec = deltime(start_time);
double elapsed_time = (double)microsec / 1.0e6;
if (critical_interval > UNDEFINED && elapsed_time > critical_interval)
if (config.critical_interval > UNDEFINED && elapsed_time > config.critical_interval) {
result = STATE_CRITICAL;
}
else if (warning_interval > UNDEFINED && elapsed_time > warning_interval)
else if (config.warning_interval > UNDEFINED && elapsed_time > config.warning_interval) {
result = STATE_WARNING;
}
printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time,
msg ? msg : _("Probably a non-existent host/domain"),
fperfdata("time", elapsed_time, "s", (warning_interval > UNDEFINED ? true : false), warning_interval,
(critical_interval > UNDEFINED ? true : false), critical_interval, true, 0, false, 0));
return result;
fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED), config.warning_interval,
(config.critical_interval > UNDEFINED), config.critical_interval, true, 0, false, 0));
exit(result);
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
int option = 0;
check_dig_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
{"query_address", required_argument, 0, 'l'},
{"warning", required_argument, 0, 'w'},
@ -201,16 +197,25 @@ int process_arguments(int argc, char **argv) {
{"use-ipv6", no_argument, 0, '6'},
{0, 0, 0, 0}};
if (argc < 2)
return ERROR;
check_dig_config_wrapper result = {
.errorcode = OK,
.config = check_dig_config_init(),
};
while (1) {
c = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option);
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
if (c == -1 || c == EOF)
int option = 0;
while (true) {
int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option);
if (option_index == -1 || option_index == EOF) {
break;
}
switch (c) {
switch (option_index) {
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
@ -219,28 +224,28 @@ int process_arguments(int argc, char **argv) {
exit(STATE_UNKNOWN);
case 'H': /* hostname */
host_or_die(optarg);
dns_server = optarg;
result.config.dns_server = optarg;
break;
case 'p': /* server port */
if (is_intpos(optarg)) {
server_port = atoi(optarg);
result.config.server_port = atoi(optarg);
} else {
usage_va(_("Port must be a positive integer - %s"), optarg);
}
break;
case 'l': /* address to lookup */
query_address = optarg;
result.config.query_address = optarg;
break;
case 'w': /* warning */
if (is_nonnegative(optarg)) {
warning_interval = strtod(optarg, NULL);
result.config.warning_interval = strtod(optarg, NULL);
} else {
usage_va(_("Warning interval must be a positive integer - %s"), optarg);
}
break;
case 'c': /* critical */
if (is_nonnegative(optarg)) {
critical_interval = strtod(optarg, NULL);
result.config.critical_interval = strtod(optarg, NULL);
} else {
usage_va(_("Critical interval must be a positive integer - %s"), optarg);
}
@ -253,48 +258,50 @@ int process_arguments(int argc, char **argv) {
}
break;
case 'A': /* dig arguments */
dig_args = strdup(optarg);
result.config.dig_args = strdup(optarg);
break;
case 'v': /* verbose */
verbose = true;
verbose++;
break;
case 'T':
record_type = optarg;
result.config.record_type = optarg;
break;
case 'a':
expected_address = optarg;
result.config.expected_address = optarg;
break;
case '4':
query_transport = "-4";
result.config.query_transport = "-4";
break;
case '6':
query_transport = "-6";
result.config.query_transport = "-6";
break;
default: /* usage5 */
usage5();
}
}
c = optind;
if (dns_server == NULL) {
if (c < argc) {
host_or_die(argv[c]);
dns_server = argv[c];
int index = optind;
if (result.config.dns_server == NULL) {
if (index < argc) {
host_or_die(argv[index]);
result.config.dns_server = argv[index];
} else {
if (strcmp(query_transport, "-6") == 0)
dns_server = strdup("::1");
else
dns_server = strdup("127.0.0.1");
if (strcmp(result.config.query_transport, "-6") == 0) {
result.config.dns_server = strdup("::1");
} else {
result.config.dns_server = strdup("127.0.0.1");
}
}
}
return validate_arguments();
return validate_arguments(result);
}
int validate_arguments(void) {
if (query_address != NULL)
return OK;
return ERROR;
check_dig_config_wrapper validate_arguments(check_dig_config_wrapper config_wrapper) {
if (config_wrapper.config.query_address == NULL) {
config_wrapper.errorcode = ERROR;
}
return config_wrapper;
}
void print_help(void) {

View file

@ -0,0 +1,40 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#define UNDEFINED 0
#define DEFAULT_PORT 53
#define DEFAULT_TRIES 2
typedef struct {
char *query_address;
char *record_type;
char *expected_address;
char *dns_server;
char *query_transport;
int server_port;
char *dig_args;
int number_tries;
double warning_interval;
double critical_interval;
} check_dig_config;
check_dig_config check_dig_config_init() {
check_dig_config tmp = {
.query_address = NULL,
.record_type = "A",
.expected_address = NULL,
.dns_server = NULL,
.query_transport = "",
.server_port = DEFAULT_PORT,
.dig_args = "",
.number_tries = DEFAULT_TRIES,
.warning_interval = UNDEFINED,
.critical_interval = UNDEFINED,
};
return tmp;
}

View file

@ -39,26 +39,22 @@ const char *email = "devel@monitoring-plugins.org";
#include "netutils.h"
#include "runcmd.h"
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int validate_arguments(void);
static int error_scan(char * /*input_buffer*/, bool *);
#include "states.h"
#include "check_dns.d/config.h"
typedef struct {
int errorcode;
check_dns_config config;
} check_dns_config_wrapper;
static check_dns_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static check_dns_config_wrapper validate_arguments(check_dns_config_wrapper /*config_wrapper*/);
static mp_state_enum error_scan(char * /*input_buffer*/, bool * /*is_nxdomain*/, const char /*dns_server*/[ADDRESS_LENGTH]);
static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/);
static unsigned long ip2long(const char * /*src*/);
static void print_help(void);
void print_usage(void);
#define ADDRESS_LENGTH 256
static char query_address[ADDRESS_LENGTH] = "";
static char dns_server[ADDRESS_LENGTH] = "";
static char ptr_server[ADDRESS_LENGTH] = "";
static bool verbose = false;
static char **expected_address = NULL;
static int expected_address_cnt = 0;
static bool expect_nxdomain = false;
static bool expect_authority = false;
static bool all_match = false;
static thresholds *time_thresholds = NULL;
static int qstrcmp(const void *p1, const void *p2) {
/* The actual arguments to this function are "pointers to
@ -68,23 +64,6 @@ static int qstrcmp(const void *p1, const void *p2) {
}
int main(int argc, char **argv) {
char *command_line = NULL;
char input_buffer[MAX_INPUT_BUFFER];
char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
char **addresses = NULL;
int n_addresses = 0;
char *msg = NULL;
char *temp_buffer = NULL;
bool non_authoritative = false;
int result = STATE_UNKNOWN;
double elapsed_time;
long microsec;
struct timeval tv;
bool parse_address = false; /* This flag scans for Address: but only after Name: */
output chld_out;
output chld_err;
bool is_nxdomain = false;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -97,39 +76,65 @@ 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_dns_config_wrapper tmp = process_arguments(argc, argv);
if (tmp.errorcode == ERROR) {
usage_va(_("Could not parse arguments"));
}
/* get the command to run */
xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server);
const check_dns_config config = tmp.config;
char *command_line = NULL;
/* get the command to run */
xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, config.query_address, config.dns_server);
struct timeval tv;
alarm(timeout_interval);
gettimeofday(&tv, NULL);
if (verbose)
if (verbose) {
printf("%s\n", command_line);
}
output chld_out;
output chld_err;
char *msg = NULL;
mp_state_enum result = STATE_UNKNOWN;
/* run the command */
if ((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
msg = (char *)_("nslookup returned an error status");
result = STATE_WARNING;
}
/* scan stdout */
/* =====
* scan stdout, main results get retrieved here
* =====
*/
char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
char **addresses = NULL; // All addresses parsed from stdout
size_t n_addresses = 0; // counter for retrieved addresses
bool non_authoritative = false;
bool is_nxdomain = false;
bool parse_address = false; /* This flag scans for Address: but only after Name: */
for (size_t i = 0; i < chld_out.lines; i++) {
if (addresses == NULL)
if (addresses == NULL) {
addresses = malloc(sizeof(*addresses) * 10);
else if (!(n_addresses % 10))
} else if (!(n_addresses % 10)) {
addresses = realloc(addresses, sizeof(*addresses) * (n_addresses + 10));
}
if (verbose)
if (verbose) {
puts(chld_out.line[i]);
}
if (strcasestr(chld_out.line[i], ".in-addr.arpa") || strcasestr(chld_out.line[i], ".ip6.arpa")) {
if ((temp_buffer = strstr(chld_out.line[i], "name = ")))
if ((strstr(chld_out.line[i], "canonical name = ") != NULL)) {
continue;
}
char *temp_buffer = NULL;
if ((temp_buffer = strstr(chld_out.line[i], "name = "))) {
addresses[n_addresses++] = strdup(temp_buffer + 7);
else {
} else {
msg = (char *)_("Warning plugin error");
result = STATE_WARNING;
}
@ -137,37 +142,47 @@ int main(int argc, char **argv) {
/* bug ID: 2946553 - Older versions of bind will use all available dns
servers, we have to match the one specified */
if (strstr(chld_out.line[i], "Server:") && strlen(dns_server) > 0) {
temp_buffer = strchr(chld_out.line[i], ':');
if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) {
char *temp_buffer = strchr(chld_out.line[i], ':');
if (temp_buffer == NULL) {
die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Server line\n"), NSLOOKUP_COMMAND);
}
temp_buffer++;
/* Strip leading tabs */
for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++)
for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) {
/* NOOP */;
}
strip(temp_buffer);
if (temp_buffer == NULL || strlen(temp_buffer) == 0) {
if (strlen(temp_buffer) == 0) {
die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"), NSLOOKUP_COMMAND);
}
if (strcmp(temp_buffer, dns_server) != 0) {
die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), dns_server);
if (strcmp(temp_buffer, config.dns_server) != 0) {
die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), config.dns_server);
}
}
/* the server is responding, we just got the host name... */
if (strstr(chld_out.line[i], "Name:"))
if (strstr(chld_out.line[i], "Name:")) {
parse_address = true;
else if (parse_address && (strstr(chld_out.line[i], "Address:") || strstr(chld_out.line[i], "Addresses:"))) {
temp_buffer = index(chld_out.line[i], ':');
} else if (parse_address && (strstr(chld_out.line[i], "Address:") || strstr(chld_out.line[i], "Addresses:"))) {
char *temp_buffer = strchr(chld_out.line[i], ':');
if (temp_buffer == NULL) {
die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Address line\n"), NSLOOKUP_COMMAND);
}
temp_buffer++;
/* Strip leading spaces */
while (*temp_buffer == ' ')
while (*temp_buffer == ' ') {
temp_buffer++;
}
strip(temp_buffer);
if (temp_buffer == NULL || strlen(temp_buffer) == 0) {
if (strlen(temp_buffer) == 0) {
die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"), NSLOOKUP_COMMAND);
}
@ -176,65 +191,71 @@ int main(int argc, char **argv) {
non_authoritative = true;
}
result = error_scan(chld_out.line[i], &is_nxdomain);
result = error_scan(chld_out.line[i], &is_nxdomain, config.dns_server);
if (result != STATE_OK) {
msg = strchr(chld_out.line[i], ':');
if (msg)
if (msg) {
msg++;
}
break;
}
}
char input_buffer[MAX_INPUT_BUFFER];
/* scan stderr */
for (size_t i = 0; i < chld_err.lines; i++) {
if (verbose)
if (verbose) {
puts(chld_err.line[i]);
}
if (error_scan(chld_err.line[i], &is_nxdomain) != STATE_OK) {
result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain));
if (error_scan(chld_err.line[i], &is_nxdomain, config.dns_server) != STATE_OK) {
result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain, config.dns_server));
msg = strchr(input_buffer, ':');
if (msg)
if (msg) {
msg++;
else
} else {
msg = input_buffer;
}
}
}
if (is_nxdomain && !expect_nxdomain) {
die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address);
if (is_nxdomain && !config.expect_nxdomain) {
die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), config.query_address);
}
if (addresses) {
int i;
int slen;
char *adrp;
size_t slen = 1;
char *adrp = NULL;
qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
for (i = 0, slen = 1; i < n_addresses; i++) {
for (size_t i = 0; i < n_addresses; i++) {
slen += strlen(addresses[i]) + 1;
}
// Temporary pointer adrp gets moved, address stays on the beginning
adrp = address = malloc(slen);
for (i = 0; i < n_addresses; i++) {
if (i)
for (size_t i = 0; i < n_addresses; i++) {
if (i) {
*adrp++ = ',';
}
strcpy(adrp, addresses[i]);
adrp += strlen(addresses[i]);
}
*adrp = 0;
} else
} else {
die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), NSLOOKUP_COMMAND);
}
/* compare to expected address */
if (result == STATE_OK && expected_address_cnt > 0) {
if (result == STATE_OK && config.expected_address_cnt > 0) {
result = STATE_CRITICAL;
temp_buffer = "";
unsigned long expect_match = (1 << expected_address_cnt) - 1;
char *temp_buffer = "";
unsigned long expect_match = (1 << config.expected_address_cnt) - 1;
unsigned long addr_match = (1 << n_addresses) - 1;
for (int i = 0; i < expected_address_cnt; i++) {
int j;
for (size_t i = 0; i < config.expected_address_cnt; i++) {
/* check if we get a match on 'raw' ip or cidr */
for (j = 0; j < n_addresses; j++) {
if (strcmp(addresses[j], expected_address[i]) == 0 || ip_match_cidr(addresses[j], expected_address[i])) {
for (size_t j = 0; j < n_addresses; j++) {
if (strcmp(addresses[j], config.expected_address[i]) == 0 || ip_match_cidr(addresses[j], config.expected_address[i])) {
result = STATE_OK;
addr_match &= ~(1 << j);
expect_match &= ~(1 << i);
@ -242,11 +263,12 @@ int main(int argc, char **argv) {
}
/* prepare an error string */
xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]);
xasprintf(&temp_buffer, "%s%s; ", temp_buffer, config.expected_address[i]);
}
/* check if expected_address must cover all in addresses and none may be missing */
if (all_match && (expect_match != 0 || addr_match != 0))
if (config.all_match && (expect_match != 0 || addr_match != 0)) {
result = STATE_CRITICAL;
}
if (result == STATE_CRITICAL) {
/* Strip off last semicolon... */
temp_buffer[strlen(temp_buffer) - 2] = '\0';
@ -254,28 +276,29 @@ int main(int argc, char **argv) {
}
}
if (expect_nxdomain) {
if (config.expect_nxdomain) {
if (!is_nxdomain) {
result = STATE_CRITICAL;
xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address);
xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address, address);
} else {
if (address != NULL)
if (address != NULL) {
free(address);
}
address = "NXDOMAIN";
}
}
/* check if authoritative */
if (result == STATE_OK && expect_authority && non_authoritative) {
if (result == STATE_OK && config.expect_authority && non_authoritative) {
result = STATE_CRITICAL;
xasprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address);
xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server, config.query_address);
}
microsec = deltime(tv);
elapsed_time = (double)microsec / 1.0e6;
long microsec = deltime(tv);
double elapsed_time = (double)microsec / 1.0e6;
if (result == STATE_OK) {
result = get_status(elapsed_time, time_thresholds);
result = get_status(elapsed_time, config.time_thresholds);
if (result == STATE_OK) {
printf("DNS %s: ", _("OK"));
} else if (result == STATE_WARNING) {
@ -284,24 +307,26 @@ int main(int argc, char **argv) {
printf("DNS %s: ", _("CRITICAL"));
}
printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
printf(_(". %s returns %s"), query_address, address);
if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) {
printf("|%s\n", fperfdata("time", elapsed_time, "s", true, time_thresholds->warning->end, true, time_thresholds->critical->end,
true, 0, false, 0));
} else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) {
printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, time_thresholds->critical->end, true, 0, false, 0));
} else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) {
printf("|%s\n", fperfdata("time", elapsed_time, "s", true, time_thresholds->warning->end, false, 0, true, 0, false, 0));
} else
printf(_(". %s returns %s"), config.query_address, address);
if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical != NULL)) {
printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, true,
config.time_thresholds->critical->end, true, 0, false, 0));
} else if ((config.time_thresholds->warning == NULL) && (config.time_thresholds->critical != NULL)) {
printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, config.time_thresholds->critical->end, true, 0, false, 0));
} else if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical == NULL)) {
printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, false, 0, true, 0, false, 0));
} else {
printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
} else if (result == STATE_WARNING)
}
} else if (result == STATE_WARNING) {
printf(_("DNS WARNING - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
else if (result == STATE_CRITICAL)
} else if (result == STATE_CRITICAL) {
printf(_("DNS CRITICAL - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
else
} else {
printf(_("DNS UNKNOWN - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
}
return result;
exit(result);
}
bool ip_match_cidr(const char *addr, const char *cidr_ro) {
@ -329,64 +354,69 @@ unsigned long ip2long(const char *src) {
: 0;
}
int error_scan(char *input_buffer, bool *is_nxdomain) {
mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain, const char dns_server[ADDRESS_LENGTH]) {
const int nxdomain = strstr(input_buffer, "Non-existent") || strstr(input_buffer, "** server can't find") ||
strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN");
if (nxdomain)
if (nxdomain) {
*is_nxdomain = true;
}
/* the DNS lookup timed out */
if (strstr(input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
strstr(input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing.")))
strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing."))) {
return STATE_OK;
}
/* DNS server is not running... */
else if (strstr(input_buffer, "No response from server"))
else if (strstr(input_buffer, "No response from server")) {
die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
else if (strstr(input_buffer, "no servers could be reached"))
} else if (strstr(input_buffer, "no servers could be reached")) {
die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
}
/* Host name is valid, but server doesn't have records... */
else if (strstr(input_buffer, "No records"))
else if (strstr(input_buffer, "No records")) {
die(STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
}
/* Connection was refused */
else if (strstr(input_buffer, "Connection refused") || strstr(input_buffer, "Couldn't find server") ||
strstr(input_buffer, "Refused") || (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED")))
strstr(input_buffer, "Refused") || (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) {
die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
}
/* Query refused (usually by an ACL in the namserver) */
else if (strstr(input_buffer, "Query refused"))
else if (strstr(input_buffer, "Query refused")) {
die(STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
}
/* No information (e.g. nameserver IP has two PTR records) */
else if (strstr(input_buffer, "No information"))
else if (strstr(input_buffer, "No information")) {
die(STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
}
/* Network is unreachable */
else if (strstr(input_buffer, "Network is unreachable"))
else if (strstr(input_buffer, "Network is unreachable")) {
die(STATE_CRITICAL, _("Network is unreachable\n"));
}
/* Internal server failure */
else if (strstr(input_buffer, "Server failure"))
else if (strstr(input_buffer, "Server failure")) {
die(STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
}
/* Request error or the DNS lookup timed out */
else if (strstr(input_buffer, "Format error") || strstr(input_buffer, "Timed out"))
else if (strstr(input_buffer, "Format error") || strstr(input_buffer, "Timed out")) {
return STATE_WARNING;
}
return STATE_OK;
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
char *warning = NULL;
char *critical = NULL;
int opt_index = 0;
check_dns_config_wrapper process_arguments(int argc, char **argv) {
static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"verbose", no_argument, 0, 'v'},
@ -402,20 +432,34 @@ int process_arguments(int argc, char **argv) {
{"critical", required_argument, 0, 'c'},
{0, 0, 0, 0}};
if (argc < 2)
return ERROR;
check_dns_config_wrapper result = {
.config = check_dns_config_init(),
.errorcode = OK,
};
for (c = 1; c < argc; c++)
if (strcmp("-to", argv[c]) == 0)
strcpy(argv[c], "-t");
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
while (1) {
c = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index);
for (int index = 1; index < argc; index++) {
if (strcmp("-to", argv[index]) == 0) {
strcpy(argv[index], "-t");
}
}
if (c == -1 || c == EOF)
char *warning = NULL;
char *critical = NULL;
int opt_index = 0;
int index = 0;
while (true) {
index = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index);
if (index == -1 || index == EOF) {
break;
}
switch (c) {
switch (index) {
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
@ -429,54 +473,63 @@ int process_arguments(int argc, char **argv) {
timeout_interval = atoi(optarg);
break;
case 'H': /* hostname */
if (strlen(optarg) >= ADDRESS_LENGTH)
if (strlen(optarg) >= ADDRESS_LENGTH) {
die(STATE_UNKNOWN, _("Input buffer overflow\n"));
strcpy(query_address, optarg);
}
strcpy(result.config.query_address, optarg);
break;
case 's': /* server name */
/* TODO: this host_or_die check is probably unnecessary.
* Better to confirm nslookup response matches */
host_or_die(optarg);
if (strlen(optarg) >= ADDRESS_LENGTH)
if (strlen(optarg) >= ADDRESS_LENGTH) {
die(STATE_UNKNOWN, _("Input buffer overflow\n"));
strcpy(dns_server, optarg);
}
strcpy(result.config.dns_server, optarg);
break;
case 'r': /* reverse server name */
/* TODO: Is this host_or_die necessary? */
// TODO This does not do anything!!! 2025-03-08 rincewind
host_or_die(optarg);
if (strlen(optarg) >= ADDRESS_LENGTH)
if (strlen(optarg) >= ADDRESS_LENGTH) {
die(STATE_UNKNOWN, _("Input buffer overflow\n"));
}
static char ptr_server[ADDRESS_LENGTH] = "";
strcpy(ptr_server, optarg);
break;
case 'a': /* expected address */
if (strlen(optarg) >= ADDRESS_LENGTH)
if (strlen(optarg) >= ADDRESS_LENGTH) {
die(STATE_UNKNOWN, _("Input buffer overflow\n"));
}
if (strchr(optarg, ',') != NULL) {
char *comma = strchr(optarg, ',');
while (comma != NULL) {
expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **));
expected_address[expected_address_cnt] = strndup(optarg, comma - optarg);
expected_address_cnt++;
result.config.expected_address =
(char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
result.config.expected_address[result.config.expected_address_cnt] = strndup(optarg, comma - optarg);
result.config.expected_address_cnt++;
optarg = comma + 1;
comma = strchr(optarg, ',');
}
expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **));
expected_address[expected_address_cnt] = strdup(optarg);
expected_address_cnt++;
result.config.expected_address =
(char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
result.config.expected_address_cnt++;
} else {
expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **));
expected_address[expected_address_cnt] = strdup(optarg);
expected_address_cnt++;
result.config.expected_address =
(char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
result.config.expected_address_cnt++;
}
break;
case 'n': /* expect NXDOMAIN */
expect_nxdomain = true;
result.config.expect_nxdomain = true;
break;
case 'A': /* expect authority */
expect_authority = true;
result.config.expect_authority = true;
break;
case 'L': /* all must match */
all_match = true;
result.config.all_match = true;
break;
case 'w':
warning = optarg;
@ -489,38 +542,42 @@ int process_arguments(int argc, char **argv) {
}
}
c = optind;
if (strlen(query_address) == 0 && c < argc) {
if (strlen(argv[c]) >= ADDRESS_LENGTH)
index = optind;
if (strlen(result.config.query_address) == 0 && index < argc) {
if (strlen(argv[index]) >= ADDRESS_LENGTH) {
die(STATE_UNKNOWN, _("Input buffer overflow\n"));
strcpy(query_address, argv[c++]);
}
strcpy(result.config.query_address, argv[index++]);
}
if (strlen(dns_server) == 0 && c < argc) {
if (strlen(result.config.dns_server) == 0 && index < argc) {
/* TODO: See -s option */
host_or_die(argv[c]);
if (strlen(argv[c]) >= ADDRESS_LENGTH)
host_or_die(argv[index]);
if (strlen(argv[index]) >= ADDRESS_LENGTH) {
die(STATE_UNKNOWN, _("Input buffer overflow\n"));
strcpy(dns_server, argv[c++]);
}
strcpy(result.config.dns_server, argv[index++]);
}
set_thresholds(&time_thresholds, warning, critical);
set_thresholds(&result.config.time_thresholds, warning, critical);
return validate_arguments();
return validate_arguments(result);
}
int validate_arguments(void) {
if (query_address[0] == 0) {
check_dns_config_wrapper validate_arguments(check_dns_config_wrapper config_wrapper) {
if (config_wrapper.config.query_address[0] == 0) {
printf("missing --host argument\n");
return ERROR;
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
if (expected_address_cnt > 0 && expect_nxdomain) {
if (config_wrapper.config.expected_address_cnt > 0 && config_wrapper.config.expect_nxdomain) {
printf("--expected-address and --expect-nxdomain cannot be combined\n");
return ERROR;
config_wrapper.errorcode = ERROR;
return config_wrapper;
}
return OK;
return config_wrapper;
}
void print_help(void) {

View file

@ -0,0 +1,34 @@
#pragma once
#include "../../config.h"
#include "thresholds.h"
#include <stddef.h>
#define ADDRESS_LENGTH 256
typedef struct {
bool all_match;
char dns_server[ADDRESS_LENGTH];
char query_address[ADDRESS_LENGTH];
bool expect_nxdomain;
bool expect_authority;
char **expected_address;
size_t expected_address_cnt;
thresholds *time_thresholds;
} check_dns_config;
check_dns_config check_dns_config_init() {
check_dns_config tmp = {
.all_match = false,
.dns_server = "",
.query_address = "",
.expect_nxdomain = false,
.expect_authority = false,
.expected_address = NULL,
.expected_address_cnt = 0,
.time_thresholds = NULL,
};
return tmp;
}

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,54 @@ 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 = "";
/* 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);
}
char *fping_prog = NULL;
#ifdef PATH_TO_FPING6
if (address_family != AF_INET && is_inet6_addr(server))
if (address_family != AF_INET && is_inet6_addr(server)) {
fping_prog = strdup(PATH_TO_FPING6);
else
} else {
fping_prog = strdup(PATH_TO_FPING);
}
#else
fping_prog = strdup(PATH_TO_FPING);
#endif
xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, packet_size, packet_count, server);
char *command_line = NULL;
xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server);
if (verbose)
if (verbose) {
printf("%s\n", command_line);
}
/* run the command */
child_process = spopen(command_line);
@ -137,23 +129,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 +170,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 +192,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 +219,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 +240,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,54 +267,50 @@ int textscan(char *buf) {
}
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
int c;
check_fping_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {
{"hostname", required_argument, 0, 'H'}, {"sourceip", required_argument, 0, 'S'}, {"sourceif", required_argument, 0, 'I'},
{"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, {"alive", no_argument, 0, 'a'},
{"bytes", required_argument, 0, 'b'}, {"number", required_argument, 0, 'n'}, {"target-timeout", required_argument, 0, 'T'},
{"interval", required_argument, 0, 'i'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'}, {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'},
{"dontfrag", no_argument, 0, 'M'}, {"random", no_argument, 0, 'R'}, {0, 0, 0, 0}};
char *rv[2];
int option = 0;
static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
{"sourceip", required_argument, 0, 'S'},
{"sourceif", required_argument, 0, 'I'},
{"critical", required_argument, 0, 'c'},
{"warning", required_argument, 0, 'w'},
{"alive", no_argument, 0, 'a'},
{"bytes", required_argument, 0, 'b'},
{"number", required_argument, 0, 'n'},
{"target-timeout", required_argument, 0, 'T'},
{"interval", required_argument, 0, 'i'},
{"verbose", no_argument, 0, 'v'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{"use-ipv4", no_argument, 0, '4'},
{"use-ipv6", no_argument, 0, '6'},
{"dontfrag", no_argument, 0, 'M'},
{"random", no_argument, 0, 'R'},
{0, 0, 0, 0}};
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);
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,19 +322,19 @@ 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;
@ -352,82 +349,89 @@ int process_arguments(int argc, char **argv) {
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;
}
}
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, "%")) {

View file

@ -0,0 +1,58 @@
#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;
} 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,
};
return tmp;
}

View file

@ -36,9 +36,15 @@ const char *email = "devel@monitoring-plugins.org";
#include "common.h"
#include "utils.h"
#include "runcmd.h"
#include "check_game.d/config.h"
#include "../lib/monitoringplug.h"
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int validate_arguments(void);
typedef struct {
int errorcode;
check_game_config config;
} check_game_config_wrapper;
static check_game_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
@ -49,26 +55,9 @@ void print_usage(void);
#define QSTAT_HOST_TIMEOUT "TIMEOUT"
#define QSTAT_MAX_RETURN_ARGS 12
static char *server_ip;
static char *game_type;
static int port = 0;
static bool verbose = false;
static int qstat_game_players_max = -1;
static int qstat_game_players = -1;
static int qstat_game_field = -1;
static int qstat_map_field = -1;
static int qstat_ping_field = -1;
int main(int argc, char **argv) {
char *command_line;
int result = STATE_UNKNOWN;
char *p;
char *ret[QSTAT_MAX_RETURN_ARGS];
size_t i = 0;
output chld_out;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
@ -76,22 +65,31 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
usage_va(_("Could not parse arguments"));
check_game_config_wrapper tmp = process_arguments(argc, argv);
result = STATE_OK;
if (tmp.errorcode == ERROR) {
usage_va(_("Could not parse arguments"));
}
check_game_config config = tmp.config;
mp_state_enum result = STATE_OK;
/* create the command line to execute */
xasprintf(&command_line, "%s -raw %s -%s %s", PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
char *command_line = NULL;
xasprintf(&command_line, "%s -raw %s -%s %s", PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, config.game_type, config.server_ip);
if (port)
xasprintf(&command_line, "%s:%-d", command_line, port);
if (config.port) {
xasprintf(&command_line, "%s:%-d", command_line, config.port);
}
if (verbose)
if (verbose) {
printf("%s\n", command_line);
}
/* run the command. historically, this plugin ignores output on stderr,
* as well as return status of the qstat program */
output chld_out = {};
(void)np_runcmd(command_line, &chld_out, NULL, 0);
/* sanity check */
@ -104,19 +102,22 @@ int main(int argc, char **argv) {
In the end, I figured I'd simply let an error occur & then trap it
*/
if (!strncmp(chld_out.line[0], "unknown option", 14)) {
if (!strncmp(chld_out.line[0], "unknown option", strlen("unknown option"))) {
printf(_("CRITICAL - Host type parameter incorrect!\n"));
result = STATE_CRITICAL;
return result;
exit(result);
}
p = (char *)strtok(chld_out.line[0], QSTAT_DATA_DELIMITER);
while (p != NULL) {
ret[i] = p;
p = (char *)strtok(NULL, QSTAT_DATA_DELIMITER);
char *ret[QSTAT_MAX_RETURN_ARGS];
size_t i = 0;
char *sequence = strtok(chld_out.line[0], QSTAT_DATA_DELIMITER);
while (sequence != NULL) {
ret[i] = sequence;
sequence = strtok(NULL, QSTAT_DATA_DELIMITER);
i++;
if (i >= QSTAT_MAX_RETURN_ARGS)
if (i >= QSTAT_MAX_RETURN_ARGS) {
break;
}
}
if (strstr(ret[2], QSTAT_HOST_ERROR)) {
@ -129,19 +130,20 @@ int main(int argc, char **argv) {
printf(_("CRITICAL - Game server timeout\n"));
result = STATE_CRITICAL;
} else {
printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[qstat_game_players], ret[qstat_game_players_max], ret[qstat_game_field],
ret[qstat_map_field], ret[qstat_ping_field],
perfdata("players", atol(ret[qstat_game_players]), "", false, 0, false, 0, true, 0, true, atol(ret[qstat_game_players_max])),
fperfdata("ping", strtod(ret[qstat_ping_field], NULL), "", false, 0, false, 0, true, 0, false, 0));
printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[config.qstat_game_players], ret[config.qstat_game_players_max],
ret[config.qstat_game_field], ret[config.qstat_map_field], ret[config.qstat_ping_field],
perfdata("players", atol(ret[config.qstat_game_players]), "", false, 0, false, 0, true, 0, true,
atol(ret[config.qstat_game_players_max])),
fperfdata("ping", strtod(ret[config.qstat_ping_field], NULL), "", false, 0, false, 0, true, 0, false, 0));
}
return result;
exit(result);
}
int process_arguments(int argc, char **argv) {
int c;
#define players_field_index 129
#define max_players_field_index 130
int opt_index = 0;
check_game_config_wrapper process_arguments(int argc, char **argv) {
static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"verbose", no_argument, 0, 'v'},
@ -152,29 +154,39 @@ int process_arguments(int argc, char **argv) {
{"map-field", required_argument, 0, 'm'},
{"ping-field", required_argument, 0, 'p'},
{"game-field", required_argument, 0, 'g'},
{"players-field", required_argument, 0, 129},
{"max-players-field", required_argument, 0, 130},
{"players-field", required_argument, 0, players_field_index},
{"max-players-field", required_argument, 0, max_players_field_index},
{0, 0, 0, 0}};
if (argc < 2)
return ERROR;
check_game_config_wrapper result = {
.config = check_game_config_init(),
.errorcode = OK,
};
for (c = 1; c < argc; c++) {
if (strcmp("-mf", argv[c]) == 0)
strcpy(argv[c], "-m");
else if (strcmp("-pf", argv[c]) == 0)
strcpy(argv[c], "-p");
else if (strcmp("-gf", argv[c]) == 0)
strcpy(argv[c], "-g");
if (argc < 2) {
result.errorcode = ERROR;
return result;
}
while (1) {
c = getopt_long(argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
for (int option_counter = 1; option_counter < argc; option_counter++) {
if (strcmp("-mf", argv[option_counter]) == 0) {
strcpy(argv[option_counter], "-m");
} else if (strcmp("-pf", argv[option_counter]) == 0) {
strcpy(argv[option_counter], "-p");
} else if (strcmp("-gf", argv[option_counter]) == 0) {
strcpy(argv[option_counter], "-g");
}
}
if (c == -1 || c == EOF)
int opt_index = 0;
while (true) {
int option_index = getopt_long(argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
if (option_index == -1 || option_index == EOF) {
break;
}
switch (c) {
switch (option_index) {
case 'h': /* help */
print_help();
exit(STATE_UNKNOWN);
@ -188,79 +200,75 @@ int process_arguments(int argc, char **argv) {
timeout_interval = atoi(optarg);
break;
case 'H': /* hostname */
if (strlen(optarg) >= MAX_HOST_ADDRESS_LENGTH)
if (strlen(optarg) >= MAX_HOST_ADDRESS_LENGTH) {
die(STATE_UNKNOWN, _("Input buffer overflow\n"));
server_ip = optarg;
}
result.config.server_ip = optarg;
break;
case 'P': /* port */
port = atoi(optarg);
result.config.port = atoi(optarg);
break;
case 'G': /* hostname */
if (strlen(optarg) >= MAX_INPUT_BUFFER)
if (strlen(optarg) >= MAX_INPUT_BUFFER) {
die(STATE_UNKNOWN, _("Input buffer overflow\n"));
game_type = optarg;
}
result.config.game_type = optarg;
break;
case 'p': /* index of ping field */
qstat_ping_field = atoi(optarg);
if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS)
return ERROR;
result.config.qstat_ping_field = atoi(optarg);
if (result.config.qstat_ping_field < 0 || result.config.qstat_ping_field > QSTAT_MAX_RETURN_ARGS) {
result.errorcode = ERROR;
return result;
}
break;
case 'm': /* index on map field */
qstat_map_field = atoi(optarg);
if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS)
return ERROR;
result.config.qstat_map_field = atoi(optarg);
if (result.config.qstat_map_field < 0 || result.config.qstat_map_field > QSTAT_MAX_RETURN_ARGS) {
result.errorcode = ERROR;
return result;
}
break;
case 'g': /* index of game field */
qstat_game_field = atoi(optarg);
if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS)
return ERROR;
result.config.qstat_game_field = atoi(optarg);
if (result.config.qstat_game_field < 0 || result.config.qstat_game_field > QSTAT_MAX_RETURN_ARGS) {
result.errorcode = ERROR;
return result;
}
break;
case 129: /* index of player count field */
qstat_game_players = atoi(optarg);
if (qstat_game_players_max == 0)
qstat_game_players_max = qstat_game_players - 1;
if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
return ERROR;
case players_field_index: /* index of player count field */
result.config.qstat_game_players = atoi(optarg);
if (result.config.qstat_game_players_max == 0) {
result.config.qstat_game_players_max = result.config.qstat_game_players - 1;
}
if (result.config.qstat_game_players < 0 || result.config.qstat_game_players > QSTAT_MAX_RETURN_ARGS) {
result.errorcode = ERROR;
return result;
}
break;
case 130: /* index of max players field */
qstat_game_players_max = atoi(optarg);
if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
return ERROR;
case max_players_field_index: /* index of max players field */
result.config.qstat_game_players_max = atoi(optarg);
if (result.config.qstat_game_players_max < 0 || result.config.qstat_game_players_max > QSTAT_MAX_RETURN_ARGS) {
result.errorcode = ERROR;
return result;
}
break;
default: /* args not parsable */
usage5();
}
}
c = optind;
int option_counter = optind;
/* first option is the game type */
if (!game_type && c < argc)
game_type = strdup(argv[c++]);
if (!result.config.game_type && option_counter < argc) {
result.config.game_type = strdup(argv[option_counter++]);
}
/* Second option is the server name */
if (!server_ip && c < argc)
server_ip = strdup(argv[c++]);
if (!result.config.server_ip && option_counter < argc) {
result.config.server_ip = strdup(argv[option_counter++]);
}
return validate_arguments();
}
int validate_arguments(void) {
if (qstat_game_players_max < 0)
qstat_game_players_max = 4;
if (qstat_game_players < 0)
qstat_game_players = 5;
if (qstat_game_field < 0)
qstat_game_field = 2;
if (qstat_map_field < 0)
qstat_map_field = 3;
if (qstat_ping_field < 0)
qstat_ping_field = 5;
return OK;
return result;
}
void print_help(void) {
@ -277,14 +285,15 @@ void print_help(void) {
printf(UT_HELP_VRSN);
printf(UT_EXTRA_OPTS);
printf(" %s\n", "-p");
printf(" %s\n", _("Optional port of which to connect"));
printf(" %s\n", "gf");
printf(" -H, --hostname=ADDRESS\n"
" Host name, IP Address, or unix socket (must be an absolute path)\n");
printf(" %s\n", "-P");
printf(" %s\n", _("Optional port to connect to"));
printf(" %s\n", "-g");
printf(" %s\n", _("Field number in raw qstat output that contains game name"));
printf(" %s\n", "-mf");
printf(" %s\n", "-m");
printf(" %s\n", _("Field number in raw qstat output that contains map name"));
printf(" %s\n", "-pf");
printf(" %s\n", "-p");
printf(" %s\n", _("Field number in raw qstat output that contains ping time"));
printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);

View file

@ -0,0 +1,30 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
typedef struct {
char *server_ip;
char *game_type;
int port;
int qstat_game_players_max;
int qstat_game_players;
int qstat_game_field;
int qstat_map_field;
int qstat_ping_field;
} check_game_config;
check_game_config check_game_config_init() {
check_game_config tmp = {
.server_ip = NULL,
.game_type = NULL,
.port = 0,
.qstat_game_players_max = 4,
.qstat_game_players = 5,
.qstat_map_field = 3,
.qstat_game_field = 2,
.qstat_ping_field = 5,
};
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

@ -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

@ -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;
}

File diff suppressed because it is too large Load diff

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;
}

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, addresses[i]);
# endif
#else
xasprintf(&cmd, rawcmd, addresses[i], max_packets);
xasprintf(&cmd, rawcmd, 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;
}

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;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
#pragma once
#include "../../config.h"
#include <stddef.h>
#include <string.h>
enum {
SMTP_PORT = 25,
SMTPS_PORT = 465
};
#define SMTP_EXPECT "220"
typedef struct {
int server_port;
char *server_address;
char *localhostname;
char *server_expect;
bool ignore_send_quit_failure;
double warning_time;
bool check_warning_time;
double critical_time;
bool check_critical_time;
bool use_ehlo;
bool use_lhlo;
char *from_arg;
bool send_mail_from;
int ncommands;
char **commands;
int nresponses;
char **responses;
char *authtype;
char *authuser;
char *authpass;
bool use_proxy_prefix;
#ifdef HAVE_SSL
bool check_cert;
int days_till_exp_warn;
int days_till_exp_crit;
bool use_ssl;
bool use_starttls;
bool use_sni;
#endif
} check_smtp_config;
check_smtp_config check_smtp_config_init() {
check_smtp_config tmp = {
.server_port = SMTP_PORT,
.server_address = NULL,
.localhostname = NULL,
.server_expect = SMTP_EXPECT,
.ignore_send_quit_failure = false,
.warning_time = 0,
.check_warning_time = false,
.critical_time = 0,
.check_critical_time = false,
.use_ehlo = false,
.use_lhlo = false,
.from_arg = strdup(" "),
.send_mail_from = false,
.ncommands = 0,
.commands = NULL,
.nresponses = 0,
.responses = NULL,
.authtype = NULL,
.authuser = NULL,
.authpass = NULL,
.use_proxy_prefix = false,
#ifdef HAVE_SSL
.check_cert = false,
.days_till_exp_warn = 0,
.days_till_exp_crit = 0,
.use_ssl = false,
.use_starttls = false,
.use_sni = false,
#endif
};
return tmp;
}

View file

@ -28,6 +28,9 @@
*
*****************************************************************************/
#include "output.h"
#include "perfdata.h"
#include "states.h"
const char *progname = "check_ssh";
const char *copyright = "2000-2024";
const char *email = "devel@monitoring-plugins.org";
@ -35,26 +38,26 @@ const char *email = "devel@monitoring-plugins.org";
#include "./common.h"
#include "./netutils.h"
#include "utils.h"
#include "./check_ssh.d/config.h"
#ifndef MSG_DONTWAIT
# define MSG_DONTWAIT 0
#endif
#define SSH_DFL_PORT 22
#define BUFF_SZ 256
#define BUFF_SZ 256
static int port = -1;
static char *server_name = NULL;
static char *remote_version = NULL;
static char *remote_protocol = NULL;
static bool verbose = false;
static int process_arguments(int /*argc*/, char ** /*argv*/);
static int validate_arguments(void);
typedef struct process_arguments_wrapper {
int errorcode;
check_ssh_config config;
} process_arguments_wrapper;
static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
static void print_help(void);
void print_usage(void);
static int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_protocol);
static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version, char *remote_protocol);
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
@ -64,24 +67,35 @@ int main(int argc, char **argv) {
/* Parse extra opts if any */
argv = np_extra_opts(&argc, argv, progname);
if (process_arguments(argc, argv) == ERROR)
process_arguments_wrapper tmp_config = process_arguments(argc, argv);
if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
}
check_ssh_config config = tmp_config.config;
mp_check overall = mp_check_init();
if (config.output_format_is_set) {
mp_set_format(config.output_format);
}
/* initialize alarm signal handling */
signal(SIGALRM, socket_timeout_alarm_handler);
alarm(socket_timeout);
/* ssh_connect exits if error is found */
int result = ssh_connect(server_name, port, remote_version, remote_protocol);
ssh_connect(&overall, config.server_name, config.port, config.remote_version, config.remote_protocol);
alarm(0);
return (result);
mp_exit(overall);
}
#define output_format_index CHAR_MAX + 1
/* process command-line arguments */
int process_arguments(int argc, char **argv) {
process_arguments_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"host", required_argument, 0, 'H'}, /* backward compatibility */
@ -93,22 +107,33 @@ int process_arguments(int argc, char **argv) {
{"verbose", no_argument, 0, 'v'},
{"remote-version", required_argument, 0, 'r'},
{"remote-protocol", required_argument, 0, 'P'},
{"output-format", required_argument, 0, output_format_index},
{0, 0, 0, 0}};
if (argc < 2)
return ERROR;
process_arguments_wrapper result = {
.config = check_ssh_config_init(),
.errorcode = OK,
};
for (int i = 1; i < argc; i++)
if (strcmp("-to", argv[i]) == 0)
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");
}
}
int option_char;
while (true) {
int option = 0;
option_char = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
if (option_char == -1 || option_char == EOF)
if (option_char == -1 || option_char == EOF) {
break;
}
switch (option_char) {
case '?': /* help */
@ -123,10 +148,11 @@ int process_arguments(int argc, char **argv) {
verbose = true;
break;
case 't': /* timeout period */
if (!is_integer(optarg))
if (!is_intpos(optarg)) {
usage2(_("Timeout interval must be a positive integer"), optarg);
else
socket_timeout = atoi(optarg);
} else {
socket_timeout = (unsigned int)atoi(optarg);
}
break;
case '4':
address_family = AF_INET;
@ -139,50 +165,61 @@ int process_arguments(int argc, char **argv) {
#endif
break;
case 'r': /* remote version */
remote_version = optarg;
result.config.remote_version = optarg;
break;
case 'P': /* remote version */
remote_protocol = optarg;
result.config.remote_protocol = optarg;
break;
case 'H': /* host */
if (!is_host(optarg))
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
server_name = optarg;
}
result.config.server_name = optarg;
break;
case 'p': /* port */
if (is_intpos(optarg)) {
port = atoi(optarg);
result.config.port = atoi(optarg);
} else {
usage2(_("Port number must be a positive integer"), optarg);
}
break;
case output_format_index: {
parsed_output_format parser = mp_parse_output_format(optarg);
if (!parser.parsing_success) {
// TODO List all available formats here, maybe add anothoer usage function
printf("Invalid output format: %s\n", optarg);
exit(STATE_UNKNOWN);
}
result.config.output_format_is_set = true;
result.config.output_format = parser.output_format;
break;
}
}
}
option_char = optind;
if (server_name == NULL && option_char < argc) {
if (result.config.server_name == NULL && option_char < argc) {
if (is_host(argv[option_char])) {
server_name = argv[option_char++];
result.config.server_name = argv[option_char++];
}
}
if (port == -1 && option_char < argc) {
if (result.config.port == -1 && option_char < argc) {
if (is_intpos(argv[option_char])) {
port = atoi(argv[option_char++]);
result.config.port = atoi(argv[option_char++]);
} else {
print_usage();
exit(STATE_UNKNOWN);
}
}
return validate_arguments();
}
if (result.config.server_name == NULL) {
result.errorcode = ERROR;
return result;
}
int validate_arguments(void) {
if (server_name == NULL)
return ERROR;
if (port == -1) /* funky, but allows -p to override stray integer in args */
port = SSH_DFL_PORT;
return OK;
return result;
}
/************************************************************************
@ -191,28 +228,34 @@ int validate_arguments(void) {
*
*-----------------------------------------------------------------------*/
int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_protocol) {
int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version, char *desired_remote_protocol) {
struct timeval tv;
gettimeofday(&tv, NULL);
int socket;
int result = my_tcp_connect(haddr, hport, &socket);
if (result != STATE_OK)
mp_subcheck connection_sc = mp_subcheck_init();
if (result != STATE_OK) {
connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
xasprintf(&connection_sc.output, "Failed to establish TCP connection to Host %s and Port %d", haddr, hport);
mp_add_subcheck_to_check(overall, connection_sc);
return result;
}
char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
char *buffer = NULL;
ssize_t recv_ret = 0;
size_t recv_ret = 0;
char *version_control_string = NULL;
ssize_t byte_offset = 0;
while ((version_control_string == NULL) && (recv_ret = recv(socket, output + byte_offset, BUFF_SZ - byte_offset, 0) > 0)) {
size_t byte_offset = 0;
while ((version_control_string == NULL) &&
(recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset), 0) > 0)) {
if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
byte_offset = 0;
char *index = NULL;
int len = 0;
unsigned long len = 0;
while ((index = strchr(output + byte_offset, '\n')) != NULL) {
/*Partition the buffer so that this line is a separate string,
* by replacing the newline with NUL*/
@ -243,14 +286,23 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
}
if (recv_ret < 0) {
printf("SSH CRITICAL - %s", strerror(errno));
exit(STATE_CRITICAL);
connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - %s", strerror(errno));
mp_add_subcheck_to_check(overall, connection_sc);
return OK;
}
if (version_control_string == NULL) {
printf("SSH CRITICAL - No version control string received");
exit(STATE_CRITICAL);
connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - No version control string received");
mp_add_subcheck_to_check(overall, connection_sc);
return OK;
}
connection_sc = mp_set_subcheck_state(connection_sc, STATE_OK);
xasprintf(&connection_sc.output, "%s", "Initial connection succeeded");
mp_add_subcheck_to_check(overall, connection_sc);
/*
* "When the connection has been established, both sides MUST send an
* identification string. This identification string MUST be
@ -259,8 +311,9 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
* - RFC 4253:4.2
*/
strip(version_control_string);
if (verbose)
if (verbose) {
printf("%s\n", version_control_string);
}
char *ssh_proto = version_control_string + 4;
@ -288,41 +341,65 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
if (tmp) {
ssh_server[tmp - ssh_server] = '\0';
}
mp_subcheck protocol_validity_sc = mp_subcheck_init();
if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
printf(_("SSH CRITICAL - Invalid protocol version control string %s\n"), version_control_string);
exit(STATE_CRITICAL);
protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL);
xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s", version_control_string);
mp_add_subcheck_to_check(overall, protocol_validity_sc);
return OK;
}
protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK);
xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s", version_control_string);
mp_add_subcheck_to_check(overall, protocol_validity_sc);
ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
static char *rev_no = VERSION;
xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
send(socket, buffer, strlen(buffer), MSG_DONTWAIT);
if (verbose)
if (verbose) {
printf("%s\n", buffer);
}
if (remote_version && strcmp(remote_version, ssh_server)) {
printf(_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"), ssh_server, ssh_proto, remote_version);
if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) {
mp_subcheck remote_version_sc = mp_subcheck_init();
remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL);
xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"), ssh_server, ssh_proto,
desired_remote_version);
close(socket);
exit(STATE_CRITICAL);
mp_add_subcheck_to_check(overall, remote_version_sc);
return OK;
}
double elapsed_time = (double)deltime(tv) / 1.0e6;
if (remote_protocol && strcmp(remote_protocol, ssh_proto)) {
printf(_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s' | %s\n"), ssh_server, ssh_proto, remote_protocol,
fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, true, (int)socket_timeout));
close(socket);
exit(STATE_CRITICAL);
mp_perfdata time_pd = perfdata_init();
time_pd.value = mp_create_pd_value(elapsed_time);
time_pd.label = "time";
time_pd.max_present = true;
time_pd.max = mp_create_pd_value(socket_timeout);
mp_subcheck protocol_version_sc = mp_subcheck_init();
mp_add_perfdata_to_subcheck(&protocol_version_sc, time_pd);
if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) {
protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_CRITICAL);
xasprintf(&protocol_version_sc.output, _("%s (protocol %s) protocol version mismatch, expected '%s'"), ssh_server, ssh_proto,
desired_remote_protocol);
} else {
protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_OK);
xasprintf(&protocol_version_sc.output, "SSH server version: %s (protocol version: %s)", ssh_server, ssh_proto);
}
printf(_("SSH OK - %s (protocol %s) | %s\n"), ssh_server, ssh_proto,
fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, true, (int)socket_timeout));
mp_add_subcheck_to_check(overall, protocol_version_sc);
close(socket);
exit(STATE_OK);
return OK;
}
void print_help(void) {
char *myport;
xasprintf(&myport, "%d", SSH_DFL_PORT);
xasprintf(&myport, "%d", default_ssh_port);
print_revision(progname, NP_VERSION);
@ -349,6 +426,7 @@ void print_help(void) {
printf(" %s\n", "-P, --remote-protocol=STRING");
printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
printf(UT_OUTPUT_FORMAT);
printf(UT_VERBOSE);
@ -357,5 +435,5 @@ void print_help(void) {
void print_usage(void) {
printf("%s\n", _("Usage:"));
printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);
printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n", progname);
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <stddef.h>
#include "../../lib/monitoringplug.h"
const int default_ssh_port = 22;
typedef struct check_ssh_config {
int port;
char *server_name;
char *remote_version;
char *remote_protocol;
bool output_format_is_set;
mp_output_format output_format;
} check_ssh_config;
check_ssh_config check_ssh_config_init(void) {
check_ssh_config tmp = {
.port = default_ssh_port,
.server_name = NULL,
.remote_version = NULL,
.remote_protocol = NULL,
.output_format_is_set = false,
};
return tmp;
}

View file

@ -93,7 +93,7 @@ int main(int argc, char **argv) {
double percent_used;
mp_check overall = mp_check_init();
if (config.output_format_is_set) {
overall.format = config.output_format;
mp_set_format(config.output_format);
}
mp_subcheck sc1 = mp_subcheck_init();
sc1 = mp_set_subcheck_default_state(sc1, STATE_OK);

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

@ -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

@ -28,6 +28,8 @@
*****************************************************************************/
#include "common.h"
#include "output.h"
#include "states.h"
#include "netutils.h"
unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
@ -43,12 +45,19 @@ int address_family = AF_INET;
/* handles socket timeouts */
void socket_timeout_alarm_handler(int sig) {
if (sig == SIGALRM)
printf(_("%s - Socket timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout);
else
printf(_("%s - Abnormal timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout);
mp_subcheck timeout_sc = mp_subcheck_init();
timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state);
exit(socket_timeout_state);
if (sig == SIGALRM) {
xasprintf(&timeout_sc.output, _("Socket timeout after %d seconds\n"), socket_timeout);
} else {
xasprintf(&timeout_sc.output, _("Abnormal timeout after %d seconds\n"), socket_timeout);
}
mp_check overall = mp_check_init();
mp_add_subcheck_to_check(&overall, timeout_sc);
mp_exit(overall);
}
/* connects to a host on a specified tcp port, sends a string, and gets a
@ -65,12 +74,13 @@ int process_tcp_request2(const char *server_address, int server_port, const char
int recv_length = 0;
result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP);
if (result != STATE_OK)
if (result != STATE_OK) {
return STATE_CRITICAL;
}
send_result = send(sd, send_buffer, strlen(send_buffer), 0);
if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
printf("%s\n", _("Send failed"));
// printf("%s\n", _("Send failed"));
result = STATE_WARNING;
}
@ -87,7 +97,7 @@ int process_tcp_request2(const char *server_address, int server_port, const char
if (!FD_ISSET(sd, &readfds)) { /* it hasn't */
if (!recv_length) {
strcpy(recv_buffer, "");
printf("%s\n", _("No data was received from host!"));
// printf("%s\n", _("No data was received from host!"));
result = STATE_WARNING;
} else { /* this one failed, but previous ones worked */
recv_buffer[recv_length] = 0;
@ -130,8 +140,9 @@ int process_request(const char *server_address, int server_port, int proto, cons
result = STATE_OK;
result = np_net_connect(server_address, server_port, &sd, proto);
if (result != STATE_OK)
if (result != STATE_OK) {
return STATE_CRITICAL;
}
result = send_request(sd, proto, send_buffer, recv_buffer, recv_size);
@ -169,8 +180,9 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
host_name++;
len -= 2;
}
if (len >= sizeof(host))
if (len >= sizeof(host)) {
return STATE_UNKNOWN;
}
memcpy(host, host_name, len);
host[len] = '\0';
snprintf(port_str, sizeof(port_str), "%d", port);
@ -226,13 +238,14 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
die(STATE_UNKNOWN, _("Socket creation failed"));
}
result = connect(*sd, (struct sockaddr *)&su, sizeof(su));
if (result < 0 && errno == ECONNREFUSED)
if (result < 0 && errno == ECONNREFUSED) {
was_refused = true;
}
}
if (result == 0)
if (result == 0) {
return STATE_OK;
else if (was_refused) {
} else if (was_refused) {
switch (econn_refuse_state) { /* a user-defined expected outcome */
case STATE_OK:
case STATE_WARNING: /* user wants WARN or OK on refusal, or... */
@ -267,7 +280,7 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
send_result = send(sd, send_buffer, strlen(send_buffer), 0);
if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
printf("%s\n", _("Send failed"));
// printf("%s\n", _("Send failed"));
result = STATE_WARNING;
}
@ -282,7 +295,7 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
/* make sure some data has arrived */
if (!FD_ISSET(sd, &readfds)) {
strcpy(recv_buffer, "");
printf("%s\n", _("No data was received from host!"));
// printf("%s\n", _("No data was received from host!"));
result = STATE_WARNING;
}
@ -290,11 +303,13 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
recv_result = recv(sd, recv_buffer, (size_t)recv_size - 1, 0);
if (recv_result == -1) {
strcpy(recv_buffer, "");
if (proto != IPPROTO_TCP)
printf("%s\n", _("Receive failed"));
if (proto != IPPROTO_TCP) {
// printf("%s\n", _("Receive failed"));
}
result = STATE_WARNING;
} else
} else {
recv_buffer[recv_result] = 0;
}
/* die returned string */
recv_buffer[recv_size - 1] = 0;
@ -303,26 +318,30 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
}
bool is_host(const char *address) {
if (is_addr(address) || is_hostname(address))
if (is_addr(address) || is_hostname(address)) {
return (true);
}
return (false);
}
void host_or_die(const char *str) {
if (!str || (!is_addr(str) && !is_hostname(str)))
if (!str || (!is_addr(str) && !is_hostname(str))) {
usage_va(_("Invalid hostname/address - %s"), str);
}
}
bool is_addr(const char *address) {
#ifdef USE_IPV6
if (address_family == AF_INET && is_inet_addr(address))
if (address_family == AF_INET && is_inet_addr(address)) {
return true;
else if (address_family == AF_INET6 && is_inet6_addr(address))
} else if (address_family == AF_INET6 && is_inet6_addr(address)) {
return true;
}
#else
if (is_inet_addr(address))
if (is_inet_addr(address)) {
return (true);
}
#endif
return (false);
@ -337,11 +356,13 @@ int dns_lookup(const char *in, struct sockaddr_storage *ss, int family) {
hints.ai_family = family;
retval = getaddrinfo(in, NULL, &hints, &res);
if (retval != 0)
if (retval != 0) {
return false;
}
if (ss != NULL)
if (ss != NULL) {
memcpy(ss, res->ai_addr, res->ai_addrlen);
}
freeaddrinfo(res);
return true;
}

View file

@ -45,7 +45,7 @@ $res = NPTest->testCmd(
"./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3"
);
cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
cmp_ok( $res->output, 'eq', "CRITICAL - Socket timeout after 3 seconds", "Output OK");
like( $res->output, "/Socket timeout after/", "Output OK");
$res = NPTest->testCmd(
"./$plugin $hostname_invalid -wt 1 -ct 2"

View file

@ -17,7 +17,7 @@ my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (no
my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/';
my $jabberUnresponsive = '/CRITICAL\s-\sSocket timeout after\s\d+\sseconds/';
my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/';
my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/';

View file

@ -24,7 +24,7 @@ SKIP: {
$result = NPTest->testCmd("$command -H $host_nonresponsive -b ou=blah -t 2 -w 1 -c 1");
is( $result->return_code, 2, "$command -H $host_nonresponsive -b ou=blah -t 5 -w 2 -c 3" );
is( $result->output, 'CRITICAL - Socket timeout after 2 seconds', "output ok" );
like($result->output, '/Socket timeout after \d+ seconds/', "output ok" );
};
SKIP: {

View file

@ -21,11 +21,11 @@ plan skip_all => "check_mysql not compiled" unless (-x "check_mysql");
plan tests => 15;
my $bad_login_output = '/Access denied for user /';
my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server hostname or IP with no slaves setup");
my $mysqlsocket = getTestParameter("NP_MYSQL_SOCKET", "Full path to a MySQL Server socket with no slaves setup");
my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server hostname or IP with no replica setup");
my $mysqlsocket = getTestParameter("NP_MYSQL_SOCKET", "Full path to a MySQL Server socket with no replica setup");
my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access (requires REPLICATION CLIENT privileges)", "-u test -ptest");
my $with_slave = getTestParameter("NP_MYSQL_WITH_SLAVE", "MySQL server with slaves setup");
my $with_slave_login = getTestParameter("NP_MYSQL_WITH_SLAVE_LOGIN", "Login details for server with slave (requires REPLICATION CLIENT privileges)", $mysql_login_details || "-u test -ptest");
my $with_replica = getTestParameter("NP_MYSQL_WITH_REPLICA", "MySQL server with replica setup");
my $with_replica_login = getTestParameter("NP_MYSQL_WITH_REPLICA_LOGIN", "Login details for server with replica (requires REPLICATION CLIENT privileges)", $mysql_login_details || "-u test -ptest");
my $result;
@ -39,8 +39,8 @@ SKIP: {
like( $result->output, $bad_login_output, "Expected login failure message");
$result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details");
cmp_ok( $result->return_code, "==", 1, "No slaves defined" );
like( $result->output, "/No slaves defined/", "Correct error message");
cmp_ok( $result->return_code, "==", 1, "No replicas defined" );
like( $result->output, "/No replicas defined/", "Correct error message");
}
SKIP: {
@ -53,22 +53,22 @@ SKIP: {
like( $result->output, $bad_login_output, "Expected login failure message");
$result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details");
cmp_ok( $result->return_code, "==", 1, "No slaves defined" );
like( $result->output, "/No slaves defined/", "Correct error message");
cmp_ok( $result->return_code, "==", 1, "No replicas defined" );
like( $result->output, "/No replicas defined/", "Correct error message");
}
SKIP: {
skip "No mysql server with slaves defined", 5 unless $with_slave;
$result = NPTest->testCmd("./check_mysql -H $with_slave $with_slave_login");
skip "No mysql server with replicas defined", 5 unless $with_replica;
$result = NPTest->testCmd("./check_mysql -H $with_replica $with_replica_login");
cmp_ok( $result->return_code, '==', 0, "Login okay");
$result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login");
cmp_ok( $result->return_code, "==", 0, "Slaves okay" );
$result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login");
cmp_ok( $result->return_code, "==", 0, "Replicas okay" );
$result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login -w 60");
cmp_ok( $result->return_code, '==', 0, 'Slaves are not > 60 seconds behind');
$result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60");
cmp_ok( $result->return_code, '==', 0, 'Replicas are not > 60 seconds behind');
$result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login -w 60:");
$result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60:");
cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind');
like( $result->output, "/^SLOW_SLAVE WARNING:/", "Output okay");
like( $result->output, "/^SLOW_REPLICA WARNING:/", "Output okay");
}

View file

@ -37,7 +37,7 @@ my $ntp_critmatch1 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?
my $ntp_okmatch2 = '/^NTP\sOK:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
my $ntp_warnmatch2 = '/^NTP\sWARNING:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+,\sstratum=[0-9]{1,2}\s\(WARNING\),\struechimers=[0-9]+/';
my $ntp_critmatch2 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?\ssecs,\sjitter=[0-9]+\.[0-9]+\s\(CRITICAL\),\sstratum=[0-9]{1,2},\struechimers=[0-9]+/';
my $ntp_noresponse = '/^(CRITICAL - Socket timeout after 3 seconds)|(NTP CRITICAL: No response from NTP server)$/';
my $ntp_noresponse = '/(.*Socket timeout after \d+ seconds.*)|(.*No response from NTP server.*)/';
my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/';

View file

@ -24,7 +24,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
"An invalid (not known to DNS) hostname", "nosuchhost" );
my $res;
plan tests => 16;
plan tests => 15;
SKIP: {
skip "No SMTP server defined", 4 unless $host_tcp_smtp;
@ -73,7 +73,6 @@ SKIP: {
my $unused_port = 4465;
$res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" );
is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port" );
like ($res->output, qr/^connect to address $host_tcp_smtp_tls and port $unused_port: Connection refused/, "Check output of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port");
}
$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" );

View file

@ -5,10 +5,10 @@
#
use strict;
use warnings;
use Test::More;
use NPTest;
my $res;
use JSON;
# Required parameters
my $ssh_host = getTestParameter("NP_SSH_HOST",
@ -23,30 +23,38 @@ my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID",
"An invalid (not known to DNS) hostname",
"nosuchhost" );
my $outputFormat = '--output-format mp-test-json';
plan tests => 14 + 6;
plan tests => 24;
my $output;
my $result;
SKIP: {
skip "SSH_HOST must be defined", 6 unless $ssh_host;
my $result = NPTest->testCmd(
"./check_ssh -H $ssh_host"
"./check_ssh -H $ssh_host" ." ". $outputFormat
);
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
like($result->output, '/^SSH OK - /', "Status text if command returned none (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "OK", "State was correct");
$result = NPTest->testCmd(
"./check_ssh -H $host_nonresponsive -t 2"
"./check_ssh -H $host_nonresponsive -t 2" ." ". $outputFormat
);
cmp_ok($result->return_code, '==', 2, "Exit with return code 0 (OK)");
like($result->output, '/^CRITICAL - Socket timeout after 2 seconds/', "Status text if command returned none (OK)");
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "CRITICAL", "State was correct");
$result = NPTest->testCmd(
"./check_ssh -H $hostname_invalid -t 2"
"./check_ssh -H $hostname_invalid -t 2" ." ". $outputFormat
);
cmp_ok($result->return_code, '==', 3, "Exit with return code 0 (OK)");
cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)");
like($result->output, '/^check_ssh: Invalid hostname/', "Status text if command returned none (OK)");
@ -63,46 +71,80 @@ SKIP: {
#
# where `comments` is optional, protoversion is the SSH protocol version and
# softwareversion is an arbitrary string representing the server software version
my $found_version = 0;
open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1' | nc ${nc_flags}|");
sleep 0.1;
$res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" );
cmp_ok( $res->return_code, '==', 0, "Got SSH protocol version control string");
like( $res->output, '/^SSH OK - nagiosplug.ssh.0.1 \(protocol 2.0\)/', "Output OK");
$result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "OK", "State was correct");
# looking for the version
for my $subcheck (@{$output->{'checks'}}) {
if ($subcheck->{'output'} =~ /.*nagiosplug.ssh.0.1 \(protocol version: 2.0\).*/ ){
$found_version = 1;
}
}
cmp_ok($found_version, '==', 1, "Output OK");
close NC;
open(NC, "echo 'SSH-2.0-3.2.9.1' | nc ${nc_flags}|");
sleep 0.1;
$res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" );
cmp_ok( $res->return_code, "==", 0, "Got SSH protocol version control string with non-alpha softwareversion string");
like( $res->output, '/^SSH OK - 3.2.9.1 \(protocol 2.0\)/', "Output OK for non-alpha softwareversion string");
$result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "OK", "State was correct");
$found_version = 0;
for my $subcheck (@{$output->{'checks'}}) {
if ($subcheck->{'output'} =~ /3.2.9.1 \(protocol version: 2.0\)/ ){
$found_version = 1;
}
}
cmp_ok($found_version, '==', 1, "Output OK");
close NC;
open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1 this is a comment' | nc ${nc_flags} |");
sleep 0.1;
$res = NPTest->testCmd( "./check_ssh -H localhost -p 5003 -r nagiosplug.ssh.0.1" );
cmp_ok( $res->return_code, '==', 0, "Got SSH protocol version control string, and parsed comment appropriately");
like( $res->output, '/^SSH OK - nagiosplug.ssh.0.1 \(protocol 2.0\)/', "Output OK");
$result = NPTest->testCmd( "./check_ssh -H localhost -p 5003 -r nagiosplug.ssh.0.1" ." ". $outputFormat);
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "OK", "State was correct");
# looking for the version
$found_version = 0;
for my $subcheck (@{$output->{'checks'}}) {
if ($subcheck->{'output'} =~ /nagiosplug.ssh.0.1 \(protocol version: 2.0\)/ ){
$found_version = 1;
}
}
cmp_ok($found_version, '==', 1, "Output OK");
close NC;
open(NC, "echo 'SSH-' | nc ${nc_flags}|");
sleep 0.1;
$res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" );
cmp_ok( $res->return_code, '==', 2, "Got invalid SSH protocol version control string");
like( $res->output, '/^SSH CRITICAL/', "Output OK");
$result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "CRITICAL", "Got invalid SSH protocol version control string");
close NC;
open(NC, "echo '' | nc ${nc_flags}|");
sleep 0.1;
$res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" );
cmp_ok( $res->return_code, '==', 2, "No version control string received");
like( $res->output, '/^SSH CRITICAL - No version control string received/', "Output OK");
$result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "CRITICAL", "No version control string received");
close NC;
open(NC, "echo 'Not a version control string' | nc ${nc_flags}|");
sleep 0.1;
$res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" );
cmp_ok( $res->return_code, '==', 2, "No version control string received");
like( $res->output, '/^SSH CRITICAL - No version control string received/', "Output OK");
$result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "CRITICAL", "No version control string received");
close NC;
@ -116,8 +158,18 @@ SKIP: {
echo 'Some\nPrepended\nData\nLines\n'; sleep 0.2;
echo 'SSH-2.0-nagiosplug.ssh.0.2';} | nc ${nc_flags}|");
sleep 0.1;
$res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" );
cmp_ok( $res->return_code, '==', 0, "Got delayed SSH protocol version control string");
like( $res->output, '/^SSH OK - nagiosplug.ssh.0.2 \(protocol 2.0\)/', "Output OK");
$result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
$output = decode_json($result->output);
is($output->{'state'}, "OK", "State was correct");
# looking for the version
$found_version = 0;
for my $subcheck (@{$output->{'checks'}}) {
if ($subcheck->{'output'} =~ /nagiosplug.ssh.0.2 \(protocol version: 2.0\)/ ){
$found_version = 1;
}
}
cmp_ok($found_version, '==', 1, "Output OK");
close NC;
}

View file

@ -17,42 +17,35 @@ my $message = '/^[0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
$result = NPTest->testCmd( "./check_swap $outputFormat" ); # Always OK
cmp_ok( $result->return_code, "==", 0, "Always OK" );
$output = decode_json($result->output);
is($output->{'state'}, "OK", "State was correct");
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576 $outputFormat" ); # 1 MB free
cmp_ok( $result->return_code, "==", 0, "Always OK" );
$output = decode_json($result->output);
is($output->{'state'}, "OK", "State was correct");
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
$result = NPTest->testCmd( "./check_swap -w 1% -c 1% $outputFormat" ); # 1% free
cmp_ok( $result->return_code, "==", 0, "Always OK" );
$output = decode_json($result->output);
is($output->{'state'}, "OK", "State was correct");
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
$result = NPTest->testCmd( "./check_swap -w 100% -c 100% $outputFormat" ); # 100% (always critical)
cmp_ok( $result->return_code, "==", 0, "Always OK" );
$output = decode_json($result->output);
is($output->{'state'}, "CRITICAL", "State was correct");
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
is($result->{'mp_test_result'}->{'state'}, "CRITICAL", "State was correct");
like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
$result = NPTest->testCmd( "./check_swap -w 100% -c 1% $outputFormat" ); # 100% (always warn)
cmp_ok( $result->return_code, "==", 0, "Always OK" );
$output = decode_json($result->output);
is($output->{'state'}, "WARNING", "State was correct");
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
is($result->{'mp_test_result'}->{'state'}, "WARNING", "State was correct");
like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
$result = NPTest->testCmd( "./check_swap -w 100% $outputFormat" ); # 100% (single threshold, always warn)
cmp_ok( $result->return_code, "==", 0, "Always OK" );
$output = decode_json($result->output);
is($output->{'state'}, "WARNING", "State was correct");
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
is($result->{'mp_test_result'}->{'state'}, "WARNING", "State was correct");
like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
$result = NPTest->testCmd( "./check_swap -c 100% $outputFormat" ); # 100% (single threshold, always critical)
cmp_ok( $result->return_code, "==", 0, "Always OK" );
$output = decode_json($result->output);
is($output->{'state'}, "CRITICAL", "State was correct");
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
is($result->{'mp_test_result'}->{'state'}, "CRITICAL", "State was correct");
like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");

View file

@ -89,41 +89,46 @@ bool is_numeric(char *number) {
char tmp[1];
float x;
if (!number)
if (!number) {
return false;
else if (sscanf(number, "%f%c", &x, tmp) == 1)
} else if (sscanf(number, "%f%c", &x, tmp) == 1) {
return true;
else
} else {
return false;
}
}
bool is_positive(char *number) {
if (is_numeric(number) && atof(number) > 0.0)
if (is_numeric(number) && atof(number) > 0.0) {
return true;
else
} else {
return false;
}
}
bool is_negative(char *number) {
if (is_numeric(number) && atof(number) < 0.0)
if (is_numeric(number) && atof(number) < 0.0) {
return true;
else
} else {
return false;
}
}
bool is_nonnegative(char *number) {
if (is_numeric(number) && atof(number) >= 0.0)
if (is_numeric(number) && atof(number) >= 0.0) {
return true;
else
} else {
return false;
}
}
bool is_percentage(char *number) {
int x;
if (is_numeric(number) && (x = atof(number)) >= 0 && x <= 100)
if (is_numeric(number) && (x = atof(number)) >= 0 && x <= 100) {
return true;
else
} else {
return false;
}
}
bool is_percentage_expression(const char str[]) {
@ -156,36 +161,41 @@ bool is_percentage_expression(const char str[]) {
bool is_integer(char *number) {
long int n;
if (!number || (strspn(number, "-0123456789 ") != strlen(number)))
if (!number || (strspn(number, "-0123456789 ") != strlen(number))) {
return false;
}
n = strtol(number, NULL, 10);
if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) {
return true;
else
} else {
return false;
}
}
bool is_intpos(char *number) {
if (is_integer(number) && atoi(number) > 0)
if (is_integer(number) && atoi(number) > 0) {
return true;
else
} else {
return false;
}
}
bool is_intneg(char *number) {
if (is_integer(number) && atoi(number) < 0)
if (is_integer(number) && atoi(number) < 0) {
return true;
else
} else {
return false;
}
}
bool is_intnonneg(char *number) {
if (is_integer(number) && atoi(number) >= 0)
if (is_integer(number) && atoi(number) >= 0) {
return true;
else
} else {
return false;
}
}
/*
@ -247,19 +257,21 @@ bool is_uint64(char *number, uint64_t *target) {
bool is_intpercent(char *number) {
int i;
if (is_integer(number) && (i = atoi(number)) >= 0 && i <= 100)
if (is_integer(number) && (i = atoi(number)) >= 0 && i <= 100) {
return true;
else
} else {
return false;
}
}
bool is_option(char *str) {
if (!str)
if (!str) {
return false;
else if (strspn(str, "-") == 1 || strspn(str, "-") == 2)
} else if (strspn(str, "-") == 1 || strspn(str, "-") == 2) {
return true;
else
} else {
return false;
}
}
#ifdef NEED_GETTIMEOFDAY
@ -288,10 +300,11 @@ void strip(char *buffer) {
for (x = strlen(buffer); x >= 1; x--) {
i = x - 1;
if (buffer[i] == ' ' || buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
if (buffer[i] == ' ' || buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t') {
buffer[i] = '\0';
else
} else {
break;
}
}
return;
}
@ -309,8 +322,9 @@ void strip(char *buffer) {
*****************************************************************************/
char *strscpy(char *dest, const char *src) {
if (src == NULL)
if (src == NULL) {
return NULL;
}
xasprintf(&dest, "%s", src);
@ -369,17 +383,21 @@ char *strscpy(char *dest, const char *src) {
char *strnl(char *str) {
size_t len;
if (str == NULL)
if (str == NULL) {
return NULL;
}
str = strpbrk(str, "\r\n");
if (str == NULL)
if (str == NULL) {
return NULL;
}
len = strspn(str, "\r\n");
if (str[len] == '\0')
if (str[len] == '\0') {
return NULL;
}
str += len;
if (strlen(str) == 0)
if (strlen(str) == 0) {
return NULL;
}
return str;
}
@ -402,15 +420,18 @@ char *strnl(char *str) {
char *strpcpy(char *dest, const char *src, const char *str) {
size_t len;
if (src)
if (src) {
len = strcspn(src, str);
else
} else {
return NULL;
}
if (dest == NULL || strlen(dest) < len)
if (dest == NULL || strlen(dest) < len) {
dest = realloc(dest, len + 1);
if (dest == NULL)
}
if (dest == NULL) {
die(STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
}
strncpy(dest, src, len);
dest[len] = '\0';
@ -434,10 +455,11 @@ char *strpcpy(char *dest, const char *src, const char *str) {
char *strpcat(char *dest, const char *src, const char *str) {
size_t len, l2;
if (dest)
if (dest) {
len = strlen(dest);
else
} else {
len = 0;
}
if (src) {
l2 = strcspn(src, str);
@ -446,8 +468,9 @@ char *strpcat(char *dest, const char *src, const char *str) {
}
dest = realloc(dest, len + l2 + 1);
if (dest == NULL)
if (dest == NULL) {
die(STATE_UNKNOWN, _("failed malloc in strscat\n"));
}
strncpy(dest + len, src, l2);
dest[len + l2] = '\0';
@ -463,8 +486,9 @@ char *strpcat(char *dest, const char *src, const char *str) {
int xvasprintf(char **strp, const char *fmt, va_list ap) {
int result = vasprintf(strp, fmt, ap);
if (result == -1 || *strp == NULL)
if (result == -1 || *strp == NULL) {
die(STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
}
return result;
}
@ -483,126 +507,145 @@ int xasprintf(char **strp, const char *fmt, ...) {
*
******************************************************************************/
char *perfdata(const char *label, long int val, const char *uom, int warnp, long int warn, int critp, long int crit, int minp,
long int minv, int maxp, long int maxv) {
char *perfdata(const char *label, long int val, const char *uom, bool warnp, long int warn, bool critp, long int crit, bool minp,
long int minv, bool maxp, long int maxv) {
char *data = NULL;
if (strpbrk(label, "'= "))
if (strpbrk(label, "'= ")) {
xasprintf(&data, "'%s'=%ld%s;", label, val, uom);
else
} else {
xasprintf(&data, "%s=%ld%s;", label, val, uom);
}
if (warnp)
if (warnp) {
xasprintf(&data, "%s%ld;", data, warn);
else
} else {
xasprintf(&data, "%s;", data);
}
if (critp)
if (critp) {
xasprintf(&data, "%s%ld;", data, crit);
else
} else {
xasprintf(&data, "%s;", data);
}
if (minp)
if (minp) {
xasprintf(&data, "%s%ld;", data, minv);
else
} else {
xasprintf(&data, "%s;", data);
}
if (maxp)
if (maxp) {
xasprintf(&data, "%s%ld", data, maxv);
}
return data;
}
char *perfdata_uint64(const char *label, uint64_t val, const char *uom, int warnp, /* Warning present */
uint64_t warn, int critp, /* Critical present */
uint64_t crit, int minp, /* Minimum present */
uint64_t minv, int maxp, /* Maximum present */
char *perfdata_uint64(const char *label, uint64_t val, const char *uom, bool warnp, /* Warning present */
uint64_t warn, bool critp, /* Critical present */
uint64_t crit, bool minp, /* Minimum present */
uint64_t minv, bool maxp, /* Maximum present */
uint64_t maxv) {
char *data = NULL;
if (strpbrk(label, "'= "))
if (strpbrk(label, "'= ")) {
xasprintf(&data, "'%s'=%" PRIu64 "%s;", label, val, uom);
else
} else {
xasprintf(&data, "%s=%" PRIu64 "%s;", label, val, uom);
}
if (warnp)
if (warnp) {
xasprintf(&data, "%s%" PRIu64 ";", data, warn);
else
} else {
xasprintf(&data, "%s;", data);
}
if (critp)
if (critp) {
xasprintf(&data, "%s%" PRIu64 ";", data, crit);
else
} else {
xasprintf(&data, "%s;", data);
}
if (minp)
if (minp) {
xasprintf(&data, "%s%" PRIu64 ";", data, minv);
else
} else {
xasprintf(&data, "%s;", data);
}
if (maxp)
if (maxp) {
xasprintf(&data, "%s%" PRIu64, data, maxv);
}
return data;
}
char *perfdata_int64(const char *label, int64_t val, const char *uom, int warnp, /* Warning present */
int64_t warn, int critp, /* Critical present */
int64_t crit, int minp, /* Minimum present */
int64_t minv, int maxp, /* Maximum present */
char *perfdata_int64(const char *label, int64_t val, const char *uom, bool warnp, /* Warning present */
int64_t warn, bool critp, /* Critical present */
int64_t crit, bool minp, /* Minimum present */
int64_t minv, bool maxp, /* Maximum present */
int64_t maxv) {
char *data = NULL;
if (strpbrk(label, "'= "))
if (strpbrk(label, "'= ")) {
xasprintf(&data, "'%s'=%" PRId64 "%s;", label, val, uom);
else
} else {
xasprintf(&data, "%s=%" PRId64 "%s;", label, val, uom);
}
if (warnp)
if (warnp) {
xasprintf(&data, "%s%" PRId64 ";", data, warn);
else
} else {
xasprintf(&data, "%s;", data);
}
if (critp)
if (critp) {
xasprintf(&data, "%s%" PRId64 ";", data, crit);
else
} else {
xasprintf(&data, "%s;", data);
}
if (minp)
if (minp) {
xasprintf(&data, "%s%" PRId64 ";", data, minv);
else
} else {
xasprintf(&data, "%s;", data);
}
if (maxp)
if (maxp) {
xasprintf(&data, "%s%" PRId64, data, maxv);
}
return data;
}
char *fperfdata(const char *label, double val, const char *uom, int warnp, double warn, int critp, double crit, int minp, double minv,
int maxp, double maxv) {
char *fperfdata(const char *label, double val, const char *uom, bool warnp, double warn, bool critp, double crit, bool minp, double minv,
bool maxp, double maxv) {
char *data = NULL;
if (strpbrk(label, "'= "))
if (strpbrk(label, "'= ")) {
xasprintf(&data, "'%s'=", label);
else
} else {
xasprintf(&data, "%s=", label);
}
xasprintf(&data, "%s%f", data, val);
xasprintf(&data, "%s%s;", data, uom);
if (warnp)
if (warnp) {
xasprintf(&data, "%s%f", data, warn);
}
xasprintf(&data, "%s;", data);
if (critp)
if (critp) {
xasprintf(&data, "%s%f", data, crit);
}
xasprintf(&data, "%s;", data);
if (minp)
if (minp) {
xasprintf(&data, "%s%f", data, minv);
}
if (maxp) {
xasprintf(&data, "%s;", data);
@ -612,28 +655,32 @@ char *fperfdata(const char *label, double val, const char *uom, int warnp, doubl
return data;
}
char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, int minp, double minv, int maxp, double maxv) {
char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, bool minp, double minv, bool maxp, double maxv) {
char *data = NULL;
if (strpbrk(label, "'= "))
if (strpbrk(label, "'= ")) {
xasprintf(&data, "'%s'=", label);
else
} else {
xasprintf(&data, "%s=", label);
}
xasprintf(&data, "%s%f", data, val);
xasprintf(&data, "%s%s;", data, uom);
if (warn != NULL)
if (warn != NULL) {
xasprintf(&data, "%s%s", data, warn);
}
xasprintf(&data, "%s;", data);
if (crit != NULL)
if (crit != NULL) {
xasprintf(&data, "%s%s", data, crit);
}
xasprintf(&data, "%s;", data);
if (minp)
if (minp) {
xasprintf(&data, "%s%f", data, minv);
}
if (maxp) {
xasprintf(&data, "%s;", data);
@ -643,28 +690,32 @@ char *sperfdata(const char *label, double val, const char *uom, char *warn, char
return data;
}
char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, int minp, int minv, int maxp, int maxv) {
char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, bool minp, int minv, bool maxp, int maxv) {
char *data = NULL;
if (strpbrk(label, "'= "))
if (strpbrk(label, "'= ")) {
xasprintf(&data, "'%s'=", label);
else
} else {
xasprintf(&data, "%s=", label);
}
xasprintf(&data, "%s%d", data, val);
xasprintf(&data, "%s%s;", data, uom);
if (warn != NULL)
if (warn != NULL) {
xasprintf(&data, "%s%s", data, warn);
}
xasprintf(&data, "%s;", data);
if (crit != NULL)
if (crit != NULL) {
xasprintf(&data, "%s%s", data, crit);
}
xasprintf(&data, "%s;", data);
if (minp)
if (minp) {
xasprintf(&data, "%s%d", data, minv);
}
if (maxp) {
xasprintf(&data, "%s;", data);

View file

@ -21,43 +21,43 @@ suite of plugins. */
#ifdef NP_EXTRA_OPTS
/* Include extra-opts functions if compiled in */
#include "extra_opts.h"
# include "extra_opts.h"
#else
/* else, fake np_extra_opts */
#define np_extra_opts(acptr,av,pr) av
# define np_extra_opts(acptr, av, pr) av
#endif
/* Standardize version information, termination */
void support (void);
void print_revision (const char *, const char *);
void support(void);
void print_revision(const char *, const char *);
extern time_t start_time, end_time;
/* Test input types */
bool is_integer (char *);
bool is_intpos (char *);
bool is_intneg (char *);
bool is_intnonneg (char *);
bool is_intpercent (char *);
bool is_integer(char *);
bool is_intpos(char *);
bool is_intneg(char *);
bool is_intnonneg(char *);
bool is_intpercent(char *);
bool is_uint64(char *number, uint64_t *target);
bool is_int64(char *number, int64_t *target);
bool is_numeric (char *);
bool is_positive (char *);
bool is_negative (char *);
bool is_nonnegative (char *);
bool is_percentage (char *);
bool is_percentage_expression (const char[]);
bool is_numeric(char *);
bool is_positive(char *);
bool is_negative(char *);
bool is_nonnegative(char *);
bool is_percentage(char *);
bool is_percentage_expression(const char[]);
bool is_option (char *);
bool is_option(char *);
/* Generalized timer that will do milliseconds if available */
#ifndef HAVE_STRUCT_TIMEVAL
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
#endif
@ -65,137 +65,142 @@ struct timeval {
int gettimeofday(struct timeval *, struct timezone *);
#endif
double delta_time (struct timeval tv);
long deltime (struct timeval tv);
double delta_time(struct timeval tv);
long deltime(struct timeval tv);
/* Handle strings safely */
void strip (char *);
char *strscpy (char *, const char *);
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, ...);
void strip(char *);
char *strscpy(char *, const char *);
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, ...);
void usage (const char *) __attribute__((noreturn));
void usage(const char *) __attribute__((noreturn));
void usage2(const char *, const char *) __attribute__((noreturn));
void usage3(const char *, int) __attribute__((noreturn));
void usage4(const char *) __attribute__((noreturn));
void usage5(void) __attribute__((noreturn));
void usage_va(const char *fmt, ...) __attribute__((noreturn));
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
char *perfdata (const char *, long int, const char *, int, long int,
int, long int, int, long int, int, long int);
char *perfdata(const char *, long int, const char *, bool, long int, bool, long int, bool, long int, bool, long int);
char *perfdata_uint64 (const char *, uint64_t , const char *, int, uint64_t,
int, uint64_t, int, uint64_t, int, uint64_t);
char *perfdata_uint64(const char *, uint64_t, const char *, bool, uint64_t, bool, uint64_t, bool, uint64_t, bool, uint64_t);
char *perfdata_int64 (const char *, int64_t, const char *, int, int64_t,
int, int64_t, int, int64_t, int, int64_t);
char *perfdata_int64(const char *, int64_t, const char *, bool, int64_t, bool, int64_t, bool, int64_t, bool, int64_t);
char *fperfdata (const char *, double, const char *, int, double,
int, double, int, double, int, double);
char *fperfdata(const char *, double, const char *, bool, double, bool, double, bool, double, bool, double);
char *sperfdata (const char *, double, const char *, char *, char *,
int, double, int, double);
char *sperfdata(const char *, double, const char *, char *, char *, bool, double, bool, double);
char *sperfdata_int (const char *, int, const char *, char *, char *,
int, int, int, int);
char *sperfdata_int(const char *, int, const char *, char *, char *, bool, int, bool, int);
/* The idea here is that, although not every plugin will use all of these,
most will or should. Therefore, for consistency, these very common
/* The idea here is that, although not every plugin will use all of these,
most will or should. Therefore, for consistency, these very common
options should have only these meanings throughout the overall suite */
#define STD_LONG_OPTS \
{"version",no_argument,0,'V'},\
{"verbose",no_argument,0,'v'},\
{"help",no_argument,0,'h'},\
{"timeout",required_argument,0,'t'},\
{"critical",required_argument,0,'c'},\
{"warning",required_argument,0,'w'},\
{"hostname",required_argument,0,'H'}
#define STD_LONG_OPTS \
{"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, \
{"timeout", required_argument, 0, 't'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, \
{"hostname", required_argument, 0, 'H'}
#define COPYRIGHT "Copyright (c) %s Monitoring Plugins Development Team\n\
#define COPYRIGHT \
"Copyright (c) %s Monitoring Plugins Development Team\n\
\t<%s>\n\n"
#define UT_HLP_VRS _("\
#define UT_HLP_VRS \
_("\
%s (-h | --help) for detailed help\n\
%s (-V | --version) for version information\n")
#define UT_HELP_VRSN _("\
#define UT_HELP_VRSN \
_("\
\nOptions:\n\
-h, --help\n\
Print detailed help screen\n\
-V, --version\n\
Print version information\n")
#define UT_HOST_PORT _("\
#define UT_HOST_PORT \
_("\
-H, --hostname=ADDRESS\n\
Host name, IP Address, or unix socket (must be an absolute path)\n\
-%c, --port=INTEGER\n\
Port number (default: %s)\n")
#define UT_IPv46 _("\
#define UT_IPv46 \
_("\
-4, --use-ipv4\n\
Use IPv4 connection\n\
-6, --use-ipv6\n\
Use IPv6 connection\n")
#define UT_VERBOSE _("\
#define UT_VERBOSE \
_("\
-v, --verbose\n\
Show details for command-line debugging (output may be truncated by\n\
the monitoring system)\n")
#define UT_WARN_CRIT _("\
#define UT_WARN_CRIT \
_("\
-w, --warning=DOUBLE\n\
Response time to result in warning status (seconds)\n\
-c, --critical=DOUBLE\n\
Response time to result in critical status (seconds)\n")
#define UT_WARN_CRIT_RANGE _("\
#define UT_WARN_CRIT_RANGE \
_("\
-w, --warning=RANGE\n\
Warning range (format: start:end). Alert if outside this range\n\
-c, --critical=RANGE\n\
Critical range\n")
#define UT_CONN_TIMEOUT _("\
#define UT_CONN_TIMEOUT \
_("\
-t, --timeout=INTEGER\n\
Seconds before connection times out (default: %d)\n")
#define UT_PLUG_TIMEOUT _("\
#define UT_PLUG_TIMEOUT \
_("\
-t, --timeout=INTEGER\n\
Seconds before plugin times out (default: %d)\n")
#ifdef NP_EXTRA_OPTS
#define UT_EXTRA_OPTS _("\
# define UT_EXTRA_OPTS \
_("\
--extra-opts=[section][@file]\n\
Read options from an ini file. See\n\
https://www.monitoring-plugins.org/doc/extra-opts.html\n\
for usage and examples.\n")
#else
#define UT_EXTRA_OPTS " \b"
# define UT_EXTRA_OPTS " \b"
#endif
#define UT_THRESHOLDS_NOTES _("\
#define UT_THRESHOLDS_NOTES \
_("\
See:\n\
https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\
for THRESHOLD format and examples.\n")
#define UT_SUPPORT _("\n\
#define UT_SUPPORT \
_("\n\
Send email to help@monitoring-plugins.org if you have questions regarding\n\
use of this software. To submit patches or suggest improvements, send email\n\
to devel@monitoring-plugins.org\n\n")
#define UT_NOWARRANTY _("\n\
#define UT_NOWARRANTY \
_("\n\
The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
copies of the plugins under the terms of the GNU General Public License.\n\
For more information about these matters, see the file named COPYING.\n")
#define UT_OUTPUT_FORMAT _("\
#define UT_OUTPUT_FORMAT \
_("\
--output-format=OUTPUT_FORMAT\n\
Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n")