summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am64
-rw-r--r--plugins/check_apt.c683
-rw-r--r--plugins/check_apt.d/config.h41
-rw-r--r--plugins/check_by_ssh.c720
-rw-r--r--plugins/check_by_ssh.d/config.h56
-rw-r--r--plugins/check_cluster.c312
-rw-r--r--plugins/check_cluster.d/config.h27
-rw-r--r--plugins/check_curl.c4587
-rw-r--r--plugins/check_dbi.c1040
-rw-r--r--plugins/check_dbi.d/config.h63
-rw-r--r--plugins/check_dig.c663
-rw-r--r--plugins/check_dig.d/config.h40
-rw-r--r--plugins/check_disk.c2257
-rw-r--r--plugins/check_disk.d/utils_disk.c517
-rw-r--r--plugins/check_disk.d/utils_disk.h157
-rw-r--r--plugins/check_dns.c1162
-rw-r--r--plugins/check_dns.d/config.h34
-rw-r--r--plugins/check_dummy.c195
-rw-r--r--plugins/check_fping.c1034
-rw-r--r--plugins/check_fping.d/config.h82
-rw-r--r--plugins/check_game.c592
-rw-r--r--plugins/check_game.d/config.h30
-rw-r--r--plugins/check_hpjd.c539
-rw-r--r--plugins/check_hpjd.d/config.h25
-rw-r--r--plugins/check_http.c16
-rw-r--r--plugins/check_ide_smart.c580
-rw-r--r--plugins/check_ldap.c604
-rw-r--r--plugins/check_ldap.d/config.h60
-rw-r--r--plugins/check_load.c652
-rw-r--r--plugins/check_load.d/config.h30
-rw-r--r--plugins/check_mrtg.c531
-rw-r--r--plugins/check_mrtg.d/config.h36
-rw-r--r--plugins/check_mrtgtraf.c503
-rw-r--r--plugins/check_mrtgtraf.d/config.h30
-rw-r--r--plugins/check_mysql.c808
-rw-r--r--plugins/check_mysql.d/config.h58
-rw-r--r--plugins/check_mysql_query.c453
-rw-r--r--plugins/check_mysql_query.d/config.h36
-rw-r--r--plugins/check_nagios.c422
-rw-r--r--plugins/check_nagios.d/config.h19
-rw-r--r--plugins/check_nt.c1179
-rw-r--r--plugins/check_nt.d/config.h53
-rw-r--r--plugins/check_ntp.c12
-rw-r--r--plugins/check_ntp_peer.c845
-rw-r--r--plugins/check_ntp_peer.d/config.h67
-rw-r--r--plugins/check_ntp_time.c704
-rw-r--r--plugins/check_ntp_time.d/config.h28
-rw-r--r--plugins/check_nwstat.c1740
-rw-r--r--plugins/check_overcr.c469
-rw-r--r--plugins/check_pgsql.c737
-rw-r--r--plugins/check_pgsql.d/config.h61
-rw-r--r--plugins/check_ping.c854
-rw-r--r--plugins/check_ping.d/config.h46
-rw-r--r--plugins/check_procs.c1143
-rw-r--r--plugins/check_procs.d/config.h75
-rw-r--r--plugins/check_radius.c545
-rw-r--r--plugins/check_radius.d/config.h42
-rw-r--r--plugins/check_real.c575
-rw-r--r--plugins/check_real.d/config.h37
-rw-r--r--plugins/check_smtp.c1159
-rw-r--r--plugins/check_smtp.d/config.h92
-rw-r--r--plugins/check_snmp.c1265
-rw-r--r--plugins/check_ssh.c522
-rw-r--r--plugins/check_ssh.d/config.h29
-rw-r--r--plugins/check_swap.c837
-rw-r--r--plugins/check_swap.d/check_swap.h48
-rw-r--r--plugins/check_swap.d/swap.c465
-rw-r--r--plugins/check_tcp.c1151
-rw-r--r--plugins/check_tcp.d/config.h84
-rw-r--r--plugins/check_time.c520
-rw-r--r--plugins/check_time.d/config.h42
-rw-r--r--plugins/check_ups.c372
-rw-r--r--plugins/check_ups.d/config.h55
-rw-r--r--plugins/check_users.c291
-rw-r--r--plugins/common.h25
-rw-r--r--plugins/negate.c354
-rw-r--r--plugins/negate.d/config.h24
-rw-r--r--plugins/netutils.c295
-rw-r--r--plugins/picohttpparser/picohttpparser.c1101
-rw-r--r--plugins/popen.c284
-rw-r--r--plugins/runcmd.c257
-rw-r--r--plugins/sslutils.c229
-rw-r--r--plugins/t/check_disk.t220
-rw-r--r--plugins/t/check_ftp.t2
-rw-r--r--plugins/t/check_http.t2
-rw-r--r--plugins/t/check_jabber.t6
-rw-r--r--plugins/t/check_ldap.t2
-rw-r--r--plugins/t/check_load.t18
-rw-r--r--plugins/t/check_mysql.t32
-rw-r--r--plugins/t/check_ntp.t2
-rw-r--r--plugins/t/check_smtp.t3
-rw-r--r--plugins/t/check_ssh.t114
-rw-r--r--plugins/t/check_swap.t58
-rw-r--r--plugins/t/check_tcp.t12
-rw-r--r--plugins/t/check_udp.t4
-rw-r--r--plugins/tests/test_check_disk.c197
-rwxr-xr-xplugins/tests/test_check_disk.t6
-rw-r--r--plugins/tests/test_check_swap.c23
-rwxr-xr-xplugins/tests/test_check_swap.t6
-rw-r--r--plugins/tests/var/proc_meminfo55
-rw-r--r--plugins/urlize.c195
-rw-r--r--plugins/utils.c722
-rw-r--r--plugins/utils.h154
103 files changed, 20244 insertions, 20060 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 49086b7a..192a2549 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -27,7 +27,7 @@ MATHLIBS = @MATHLIBS@
27#AM_CFLAGS = -Wall 27#AM_CFLAGS = -Wall
28 28
29libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \ 29libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \
30 check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_nwstat check_overcr check_ping \ 30 check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_ping \
31 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \ 31 check_real check_smtp check_ssh check_tcp check_time check_ntp_time \
32 check_ups check_users negate \ 32 check_ups check_users negate \
33 urlize @EXTRAS@ 33 urlize @EXTRAS@
@@ -38,19 +38,63 @@ check_tcp_programs = check_ftp check_imap check_nntp check_pop \
38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \ 38EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
39 check_swap check_fping check_ldap check_game check_dig \ 39 check_swap check_fping check_ldap check_game check_dig \
40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \ 40 check_nagios check_by_ssh check_dns check_nt check_ide_smart \
41 check_procs check_mysql_query check_apt check_dbi check_curl 41 check_procs check_mysql_query check_apt check_dbi check_curl \
42 \
43 tests/test_check_swap \
44 tests/test_check_disk
42 45
43SUBDIRS = picohttpparser 46SUBDIRS = picohttpparser
44 47
45EXTRA_DIST = t tests 48np_test_scripts = tests/test_check_swap.t \
49 tests/test_check_disk.t
50
51EXTRA_DIST = t \
52 tests \
53 $(np_test_scripts) \
54 negate.d \
55 check_swap.d \
56 check_ldap.d \
57 check_hpjd.d \
58 check_game.d \
59 check_radius.d \
60 check_disk.d \
61 check_time.d \
62 check_load.d \
63 check_nagios.d \
64 check_dbi.d \
65 check_tcp.d \
66 check_real.d \
67 check_ssh.d \
68 check_nt.d \
69 check_dns.d \
70 check_mrtgtraf.d \
71 check_mysql_query.d \
72 check_mrtg.d \
73 check_ntp_peer.d \
74 check_apt.d \
75 check_pgsql.d \
76 check_procs.d \
77 check_ping.d \
78 check_by_ssh.d \
79 check_smtp.d \
80 check_mysql.d \
81 check_ntp_time.d \
82 check_dig.d \
83 check_cluster.d \
84 check_ups.d \
85 check_fping.d
46 86
47PLUGINHDRS = common.h 87PLUGINHDRS = common.h
48 88
49noinst_LIBRARIES = libnpcommon.a 89noinst_LIBRARIES = libnpcommon.a
90noinst_PROGRAMS = @EXTRA_PLUGIN_TESTS@
91# These two lines support "make check", but we use "make test"
92check_PROGRAMS = @EXTRA_PLUGIN_TESTS@
50 93
51libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \ 94libnpcommon_a_SOURCES = utils.c netutils.c sslutils.c runcmd.c \
52 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h 95 popen.c utils.h netutils.h popen.h common.h runcmd.c runcmd.h
53 96
97
54BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO) 98BASEOBJS = libnpcommon.a ../lib/libmonitoringplug.a ../gl/libgnu.a $(LIB_CRYPTO)
55NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS) 99NETOBJS = $(BASEOBJS) $(EXTRA_NETOBLS)
56NETLIBS = $(NETOBJS) $(SOCKETLIBS) 100NETLIBS = $(NETOBJS) $(SOCKETLIBS)
@@ -58,7 +102,10 @@ SSLOBJS = $(BASEOBJS) $(NETLIBS) $(SSLLIBS) $(LIB_CRYPTO)
58 102
59TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir) 103TESTS_ENVIRONMENT = perl -I $(top_builddir) -I $(top_srcdir)
60 104
61TESTS = @PLUGIN_TEST@ 105tap_ldflags = -L$(top_srcdir)/tap
106
107TESTS = @PLUGIN_TEST@ @EXTRA_PLUGIN_TESTS@
108
62 109
63test: 110test:
64 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl 111 perl -I $(top_builddir) -I $(top_srcdir) ../test.pl
@@ -77,6 +124,7 @@ check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohtt
77check_dbi_LDADD = $(NETLIBS) $(DBILIBS) 124check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
78check_dig_LDADD = $(NETLIBS) 125check_dig_LDADD = $(NETLIBS)
79check_disk_LDADD = $(BASEOBJS) 126check_disk_LDADD = $(BASEOBJS)
127check_disk_SOURCES = check_disk.c check_disk.d/utils_disk.c
80check_dns_LDADD = $(NETLIBS) 128check_dns_LDADD = $(NETLIBS)
81check_dummy_LDADD = $(BASEOBJS) 129check_dummy_LDADD = $(BASEOBJS)
82check_fping_LDADD = $(NETLIBS) 130check_fping_LDADD = $(NETLIBS)
@@ -97,8 +145,6 @@ check_nagios_LDADD = $(BASEOBJS)
97check_nt_LDADD = $(NETLIBS) 145check_nt_LDADD = $(NETLIBS)
98check_ntp_LDADD = $(NETLIBS) $(MATHLIBS) 146check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
99check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 147check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
100check_nwstat_LDADD = $(NETLIBS)
101check_overcr_LDADD = $(NETLIBS)
102check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) 148check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
103check_ping_LDADD = $(NETLIBS) 149check_ping_LDADD = $(NETLIBS)
104check_procs_LDADD = $(BASEOBJS) 150check_procs_LDADD = $(BASEOBJS)
@@ -107,6 +153,7 @@ check_real_LDADD = $(NETLIBS)
107check_snmp_LDADD = $(BASEOBJS) 153check_snmp_LDADD = $(BASEOBJS)
108check_smtp_LDADD = $(SSLOBJS) 154check_smtp_LDADD = $(SSLOBJS)
109check_ssh_LDADD = $(NETLIBS) 155check_ssh_LDADD = $(NETLIBS)
156check_swap_SOURCES = check_swap.c check_swap.d/swap.c
110check_swap_LDADD = $(MATHLIBS) $(BASEOBJS) 157check_swap_LDADD = $(MATHLIBS) $(BASEOBJS)
111check_tcp_LDADD = $(SSLOBJS) 158check_tcp_LDADD = $(SSLOBJS)
112check_time_LDADD = $(NETLIBS) 159check_time_LDADD = $(NETLIBS)
@@ -122,6 +169,11 @@ if !HAVE_UTMPX
122check_users_LDADD += popen.o 169check_users_LDADD += popen.o
123endif 170endif
124 171
172tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
173tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c
174tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap
175tests_test_check_disk_SOURCES = tests/test_check_disk.c
176
125############################################################################## 177##############################################################################
126# secondary dependencies 178# secondary dependencies
127 179
diff --git a/plugins/check_apt.c b/plugins/check_apt.c
index 5c0f6e28..e840184b 100644
--- a/plugins/check_apt.c
+++ b/plugins/check_apt.c
@@ -1,55 +1,54 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_apt plugin 3 * Monitoring check_apt plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
7* 7 *
8* Original author: Sean Finney 8 * Original author: Sean Finney
9* 9 *
10* Description: 10 * Description:
11* 11 *
12* This file contains the check_apt plugin 12 * This file contains the check_apt plugin
13* 13 *
14* Check for available updates in apt package management systems 14 * Check for available updates in apt package management systems
15* 15 *
16* 16 *
17* This program is free software: you can redistribute it and/or modify 17 * This program is free software: you can redistribute it and/or modify
18* it under the terms of the GNU General Public License as published by 18 * it under the terms of the GNU General Public License as published by
19* the Free Software Foundation, either version 3 of the License, or 19 * the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20 * (at your option) any later version.
21* 21 *
22* This program is distributed in the hope that it will be useful, 22 * This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25 * GNU General Public License for more details.
26* 26 *
27* You should have received a copy of the GNU General Public License 27 * You should have received a copy of the GNU General Public License
28* along with this program. If not, see <http://www.gnu.org/licenses/>. 28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32#include "states.h"
32const char *progname = "check_apt"; 33const char *progname = "check_apt";
33const char *copyright = "2006-2008"; 34const char *copyright = "2006-2024";
34const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
35 36
36#include "common.h" 37#include "common.h"
37#include "runcmd.h" 38#include "runcmd.h"
38#include "utils.h" 39#include "utils.h"
39#include "regex.h" 40#include "regex.h"
40 41#include "check_apt.d/config.h"
41/* some constants */
42typedef enum { UPGRADE, DIST_UPGRADE, NO_UPGRADE } upgrade_type;
43 42
44/* Character for hidden input file option (for testing). */ 43/* Character for hidden input file option (for testing). */
45#define INPUT_FILE_OPT CHAR_MAX+1 44#define INPUT_FILE_OPT CHAR_MAX + 1
46/* the default opts can be overridden via the cmdline */ 45/* the default opts can be overridden via the cmdline */
47#define UPGRADE_DEFAULT_OPTS "-o 'Debug::NoLocking=true' -s -qq" 46#define UPGRADE_DEFAULT_OPTS "-o 'Debug::NoLocking=true' -s -qq"
48#define UPDATE_DEFAULT_OPTS "-q" 47#define UPDATE_DEFAULT_OPTS "-q"
49/* until i commit the configure.in patch which gets this, i'll define 48/* until i commit the configure.in patch which gets this, i'll define
50 * it here as well */ 49 * it here as well */
51#ifndef PATH_TO_APTGET 50#ifndef PATH_TO_APTGET
52# define PATH_TO_APTGET "/usr/bin/apt-get" 51# define PATH_TO_APTGET "/usr/bin/apt-get"
53#endif /* PATH_TO_APTGET */ 52#endif /* PATH_TO_APTGET */
54/* String found at the beginning of the apt output lines we're interested in */ 53/* String found at the beginning of the apt output lines we're interested in */
55#define PKGINST_PREFIX "Inst " 54#define PKGINST_PREFIX "Inst "
@@ -57,97 +56,106 @@ typedef enum { UPGRADE, DIST_UPGRADE, NO_UPGRADE } upgrade_type;
57#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)" 56#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)"
58 57
59/* some standard functions */ 58/* some standard functions */
60int process_arguments(int, char **); 59typedef struct {
61void print_help(void); 60 int errorcode;
61 check_apt_config config;
62} check_apt_config_wrapper;
63static check_apt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
64static void print_help(void);
62void print_usage(void); 65void print_usage(void);
63 66
64/* construct the appropriate apt-get cmdline */ 67/* construct the appropriate apt-get cmdline */
65char* construct_cmdline(upgrade_type u, const char *opts); 68static char *construct_cmdline(upgrade_type /*u*/, const char * /*opts*/);
66/* run an apt-get update */ 69/* run an apt-get update */
67int run_update(void); 70static int run_update(char * /*update_opts*/);
71
72typedef struct {
73 int errorcode;
74 int package_count;
75 int security_package_count;
76 char **packages_list;
77 char **secpackages_list;
78} run_upgrade_result;
79
68/* run an apt-get upgrade */ 80/* run an apt-get upgrade */
69int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkglist); 81run_upgrade_result run_upgrade(upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical,
82 const char *upgrade_opts, const char *input_filename);
83
70/* add another clause to a regexp */ 84/* add another clause to a regexp */
71char* add_to_regexp(char *expr, const char *next); 85static char *add_to_regexp(char * /*expr*/, const char * /*next*/);
72/* extract package name from Inst line */ 86/* extract package name from Inst line */
73char* pkg_name(char *line); 87static char *pkg_name(char * /*line*/);
74/* string comparison function for qsort */ 88/* string comparison function for qsort */
75int cmpstringp(const void *p1, const void *p2); 89static int cmpstringp(const void * /*p1*/, const void * /*p2*/);
76 90
77/* configuration variables */ 91/* configuration variables */
78static int verbose = 0; /* -v */ 92static int verbose = 0; /* -v */
79static bool list = false; /* list packages available for upgrade */
80static bool do_update = false; /* whether to call apt-get update */
81static bool only_critical = false; /* whether to warn about non-critical updates */
82static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */
83static char *upgrade_opts = NULL; /* options to override defaults for upgrade */
84static char *update_opts = NULL; /* options to override defaults for update */
85static char *do_include = NULL; /* regexp to only include certain packages */
86static char *do_exclude = NULL; /* regexp to only exclude certain packages */
87static char *do_critical = NULL; /* regexp specifying critical packages */
88static char *input_filename = NULL; /* input filename for testing */
89/* number of packages available for upgrade to return WARNING status */
90static int packages_warning = 1;
91 93
92/* other global variables */ 94/* other global variables */
93static int stderr_warning = 0; /* if a cmd issued output on stderr */ 95static bool stderr_warning = false; /* if a cmd issued output on stderr */
94static int exec_warning = 0; /* if a cmd exited non-zero */ 96static bool exec_warning = false; /* if a cmd exited non-zero */
95
96int main (int argc, char **argv) {
97 int result=STATE_UNKNOWN, packages_available=0, sec_count=0;
98 char **packages_list=NULL, **secpackages_list=NULL;
99 97
98int main(int argc, char **argv) {
100 /* Parse extra opts if any */ 99 /* Parse extra opts if any */
101 argv=np_extra_opts(&argc, argv, progname); 100 argv = np_extra_opts(&argc, argv, progname);
102 101
103 if (process_arguments(argc, argv) == ERROR) 102 check_apt_config_wrapper tmp_config = process_arguments(argc, argv);
103
104 if (tmp_config.errorcode == ERROR) {
104 usage_va(_("Could not parse arguments")); 105 usage_va(_("Could not parse arguments"));
106 }
107
108 const check_apt_config config = tmp_config.config;
105 109
106 /* Set signal handling and alarm timeout */ 110 /* Set signal handling and alarm timeout */
107 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 111 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
108 usage_va(_("Cannot catch SIGALRM")); 112 usage_va(_("Cannot catch SIGALRM"));
109 } 113 }
110 114
111 /* handle timeouts gracefully... */ 115 /* handle timeouts gracefully... */
112 alarm (timeout_interval); 116 alarm(timeout_interval);
113 117
118 mp_state_enum result = STATE_UNKNOWN;
114 /* if they want to run apt-get update first... */ 119 /* if they want to run apt-get update first... */
115 if(do_update) result = run_update(); 120 if (config.do_update) {
121 result = run_update(config.update_opts);
122 }
116 123
117 /* apt-get upgrade */ 124 /* apt-get upgrade */
118 result = max_state(result, run_upgrade(&packages_available, &sec_count, &packages_list, &secpackages_list)); 125 run_upgrade_result upgrad_res =
126 run_upgrade(config.upgrade, config.do_include, config.do_exclude, config.do_critical, config.upgrade_opts, config.input_filename);
127
128 result = max_state(result, upgrad_res.errorcode);
129 int packages_available = upgrad_res.package_count;
130 int sec_count = upgrad_res.security_package_count;
131 char **packages_list = upgrad_res.packages_list;
132 char **secpackages_list = upgrad_res.secpackages_list;
119 133
120 if(sec_count > 0){ 134 if (sec_count > 0) {
121 result = max_state(result, STATE_CRITICAL); 135 result = max_state(result, STATE_CRITICAL);
122 } else if(packages_available >= packages_warning && only_critical == false){ 136 } else if (packages_available >= config.packages_warning && !config.only_critical) {
123 result = max_state(result, STATE_WARNING); 137 result = max_state(result, STATE_WARNING);
124 } else if(result > STATE_UNKNOWN){ 138 } else if (result > STATE_UNKNOWN) {
125 result = STATE_UNKNOWN; 139 result = STATE_UNKNOWN;
126 } 140 }
127 141
128 printf(_("APT %s: %d packages available for %s (%d critical updates). %s%s%s%s|available_upgrades=%d;;;0 critical_updates=%d;;;0\n"), 142 printf(_("APT %s: %d packages available for %s (%d critical updates). %s%s%s%s|available_upgrades=%d;;;0 critical_updates=%d;;;0\n"),
129 state_text(result), 143 state_text(result), packages_available, (config.upgrade == DIST_UPGRADE) ? "dist-upgrade" : "upgrade", sec_count,
130 packages_available, 144 (stderr_warning) ? " warnings detected" : "", (stderr_warning && exec_warning) ? "," : "",
131 (upgrade==DIST_UPGRADE)?"dist-upgrade":"upgrade", 145 (exec_warning) ? " errors detected" : "", (stderr_warning || exec_warning) ? "." : "", packages_available, sec_count);
132 sec_count, 146
133 (stderr_warning)?" warnings detected":"", 147 if (config.list) {
134 (stderr_warning && exec_warning)?",":"", 148 qsort(secpackages_list, sec_count, sizeof(char *), cmpstringp);
135 (exec_warning)?" errors detected":"", 149 qsort(packages_list, packages_available - sec_count, sizeof(char *), cmpstringp);
136 (stderr_warning||exec_warning)?".":"", 150
137 packages_available, 151 for (int i = 0; i < sec_count; i++) {
138 sec_count
139 );
140
141 if(list) {
142 qsort(secpackages_list, sec_count, sizeof(char*), cmpstringp);
143 qsort(packages_list, packages_available-sec_count, sizeof(char*), cmpstringp);
144
145 for(int i = 0; i < sec_count; i++)
146 printf("%s (security)\n", secpackages_list[i]); 152 printf("%s (security)\n", secpackages_list[i]);
153 }
147 154
148 if (only_critical == false) { 155 if (!config.only_critical) {
149 for(int i = 0; i < packages_available - sec_count; i++) 156 for (int i = 0; i < packages_available - sec_count; i++) {
150 printf("%s\n", packages_list[i]); 157 printf("%s\n", packages_list[i]);
158 }
151 } 159 }
152 } 160 }
153 161
@@ -155,34 +163,37 @@ int main (int argc, char **argv) {
155} 163}
156 164
157/* process command-line arguments */ 165/* process command-line arguments */
158int process_arguments (int argc, char **argv) { 166check_apt_config_wrapper process_arguments(int argc, char **argv) {
159 int c; 167 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
160 168 {"help", no_argument, 0, 'h'},
161 static struct option longopts[] = { 169 {"verbose", no_argument, 0, 'v'},
162 {"version", no_argument, 0, 'V'}, 170 {"timeout", required_argument, 0, 't'},
163 {"help", no_argument, 0, 'h'}, 171 {"update", optional_argument, 0, 'u'},
164 {"verbose", no_argument, 0, 'v'}, 172 {"upgrade", optional_argument, 0, 'U'},
165 {"timeout", required_argument, 0, 't'}, 173 {"no-upgrade", no_argument, 0, 'n'},
166 {"update", optional_argument, 0, 'u'}, 174 {"dist-upgrade", optional_argument, 0, 'd'},
167 {"upgrade", optional_argument, 0, 'U'}, 175 {"list", no_argument, 0, 'l'},
168 {"no-upgrade", no_argument, 0, 'n'}, 176 {"include", required_argument, 0, 'i'},
169 {"dist-upgrade", optional_argument, 0, 'd'}, 177 {"exclude", required_argument, 0, 'e'},
170 {"list", no_argument, false, 'l'}, 178 {"critical", required_argument, 0, 'c'},
171 {"include", required_argument, 0, 'i'}, 179 {"only-critical", no_argument, 0, 'o'},
172 {"exclude", required_argument, 0, 'e'}, 180 {"input-file", required_argument, 0, INPUT_FILE_OPT},
173 {"critical", required_argument, 0, 'c'}, 181 {"packages-warning", required_argument, 0, 'w'},
174 {"only-critical", no_argument, 0, 'o'}, 182 {0, 0, 0, 0}};
175 {"input-file", required_argument, 0, INPUT_FILE_OPT}, 183
176 {"packages-warning", required_argument, 0, 'w'}, 184 check_apt_config_wrapper result = {
177 {0, 0, 0, 0} 185 .errorcode = OK,
186 .config = check_apt_config_init(),
178 }; 187 };
179 188
180 while(1) { 189 while (true) {
181 c = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL); 190 int option_char = getopt_long(argc, argv, "hVvt:u::U::d::nli:e:c:ow:", longopts, NULL);
182 191
183 if(c == -1 || c == EOF || c == 1) break; 192 if (option_char == -1 || option_char == EOF || option_char == 1) {
193 break;
194 }
184 195
185 switch(c) { 196 switch (option_char) {
186 case 'h': 197 case 'h':
187 print_help(); 198 print_help();
188 exit(STATE_UNKNOWN); 199 exit(STATE_UNKNOWN);
@@ -193,52 +204,58 @@ int process_arguments (int argc, char **argv) {
193 verbose++; 204 verbose++;
194 break; 205 break;
195 case 't': 206 case 't':
196 timeout_interval=atoi(optarg); 207 timeout_interval = atoi(optarg);
197 break; 208 break;
198 case 'd': 209 case 'd':
199 upgrade=DIST_UPGRADE; 210 result.config.upgrade = DIST_UPGRADE;
200 if(optarg!=NULL){ 211 if (optarg != NULL) {
201 upgrade_opts=strdup(optarg); 212 result.config.upgrade_opts = strdup(optarg);
202 if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 213 if (result.config.upgrade_opts == NULL) {
214 die(STATE_UNKNOWN, "strdup failed");
215 }
203 } 216 }
204 break; 217 break;
205 case 'U': 218 case 'U':
206 upgrade=UPGRADE; 219 result.config.upgrade = UPGRADE;
207 if(optarg!=NULL){ 220 if (optarg != NULL) {
208 upgrade_opts=strdup(optarg); 221 result.config.upgrade_opts = strdup(optarg);
209 if(upgrade_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 222 if (result.config.upgrade_opts == NULL) {
223 die(STATE_UNKNOWN, "strdup failed");
224 }
210 } 225 }
211 break; 226 break;
212 case 'n': 227 case 'n':
213 upgrade=NO_UPGRADE; 228 result.config.upgrade = NO_UPGRADE;
214 break; 229 break;
215 case 'u': 230 case 'u':
216 do_update=true; 231 result.config.do_update = true;
217 if(optarg!=NULL){ 232 if (optarg != NULL) {
218 update_opts=strdup(optarg); 233 result.config.update_opts = strdup(optarg);
219 if(update_opts==NULL) die(STATE_UNKNOWN, "strdup failed"); 234 if (result.config.update_opts == NULL) {
235 die(STATE_UNKNOWN, "strdup failed");
236 }
220 } 237 }
221 break; 238 break;
222 case 'l': 239 case 'l':
223 list=true; 240 result.config.list = true;
224 break; 241 break;
225 case 'i': 242 case 'i':
226 do_include=add_to_regexp(do_include, optarg); 243 result.config.do_include = add_to_regexp(result.config.do_include, optarg);
227 break; 244 break;
228 case 'e': 245 case 'e':
229 do_exclude=add_to_regexp(do_exclude, optarg); 246 result.config.do_exclude = add_to_regexp(result.config.do_exclude, optarg);
230 break; 247 break;
231 case 'c': 248 case 'c':
232 do_critical=add_to_regexp(do_critical, optarg); 249 result.config.do_critical = add_to_regexp(result.config.do_critical, optarg);
233 break; 250 break;
234 case 'o': 251 case 'o':
235 only_critical=true; 252 result.config.only_critical = true;
236 break; 253 break;
237 case INPUT_FILE_OPT: 254 case INPUT_FILE_OPT:
238 input_filename = optarg; 255 result.config.input_filename = optarg;
239 break; 256 break;
240 case 'w': 257 case 'w':
241 packages_warning = atoi(optarg); 258 result.config.packages_warning = atoi(optarg);
242 break; 259 break;
243 default: 260 default:
244 /* print short usage statement if args not parsable */ 261 /* print short usage statement if args not parsable */
@@ -246,71 +263,82 @@ int process_arguments (int argc, char **argv) {
246 } 263 }
247 } 264 }
248 265
249 return OK; 266 return result;
250} 267}
251 268
252
253/* run an apt-get upgrade */ 269/* run an apt-get upgrade */
254int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkglist){ 270run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical,
255 int result=STATE_UNKNOWN, regres=0, pc=0, spc=0; 271 const char *upgrade_opts, const char *input_filename) {
256 struct output chld_out, chld_err; 272 regex_t ereg;
257 regex_t ireg, ereg, sreg;
258 char *cmdline=NULL, rerrbuf[64];
259
260 /* initialize ereg as it is possible it is printed while uninitialized */ 273 /* initialize ereg as it is possible it is printed while uninitialized */
261 memset(&ereg, '\0', sizeof(ereg.buffer)); 274 memset(&ereg, '\0', sizeof(ereg.buffer));
262 275
263 if(upgrade==NO_UPGRADE) return STATE_OK; 276 run_upgrade_result result = {
277 .errorcode = STATE_UNKNOWN,
278 };
279
280 if (upgrade == NO_UPGRADE) {
281 result.errorcode = STATE_OK;
282 return result;
283 }
264 284
285 int regres = 0;
286 regex_t ireg;
287 char rerrbuf[64];
265 /* compile the regexps */ 288 /* compile the regexps */
266 if (do_include != NULL) { 289 if (do_include != NULL) {
267 regres=regcomp(&ireg, do_include, REG_EXTENDED); 290 regres = regcomp(&ireg, do_include, REG_EXTENDED);
268 if (regres!=0) { 291 if (regres != 0) {
269 regerror(regres, &ireg, rerrbuf, 64); 292 regerror(regres, &ireg, rerrbuf, 64);
270 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf); 293 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
271 } 294 }
272 } 295 }
273 296
274 if(do_exclude!=NULL){ 297 if (do_exclude != NULL) {
275 regres=regcomp(&ereg, do_exclude, REG_EXTENDED); 298 regres = regcomp(&ereg, do_exclude, REG_EXTENDED);
276 if(regres!=0) { 299 if (regres != 0) {
277 regerror(regres, &ereg, rerrbuf, 64); 300 regerror(regres, &ereg, rerrbuf, 64);
278 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), 301 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
279 progname, rerrbuf);
280 } 302 }
281 } 303 }
282 304
305 regex_t sreg;
283 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE; 306 const char *crit_ptr = (do_critical != NULL) ? do_critical : SECURITY_RE;
284 regres=regcomp(&sreg, crit_ptr, REG_EXTENDED); 307 regres = regcomp(&sreg, crit_ptr, REG_EXTENDED);
285 if(regres!=0) { 308 if (regres != 0) {
286 regerror(regres, &ereg, rerrbuf, 64); 309 regerror(regres, &ereg, rerrbuf, 64);
287 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), 310 die(STATE_UNKNOWN, _("%s: Error compiling regexp: %s"), progname, rerrbuf);
288 progname, rerrbuf);
289 } 311 }
290 312
291 cmdline=construct_cmdline(upgrade, upgrade_opts); 313 struct output chld_out;
314 struct output chld_err;
315 char *cmdline = NULL;
316 cmdline = construct_cmdline(upgrade, upgrade_opts);
292 if (input_filename != NULL) { 317 if (input_filename != NULL) {
293 /* read input from a file for testing */ 318 /* read input from a file for testing */
294 result = cmd_file_read(input_filename, &chld_out, 0); 319 result.errorcode = cmd_file_read(input_filename, &chld_out, 0);
295 } else { 320 } else {
296 /* run the upgrade */ 321 /* run the upgrade */
297 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 322 result.errorcode = np_runcmd(cmdline, &chld_out, &chld_err, 0);
298 } 323 }
299 324
300 /* apt-get upgrade only changes exit status if there is an 325 /* apt-get upgrade only changes exit status if there is an
301 * internal error when run in dry-run mode. therefore we will 326 * internal error when run in dry-run mode. therefore we will
302 * treat such an error as UNKNOWN */ 327 * treat such an error as UNKNOWN */
303 if(result != 0){ 328 if (result.errorcode != STATE_OK) {
304 exec_warning=1; 329 exec_warning = 1;
305 result = STATE_UNKNOWN; 330 result.errorcode = STATE_UNKNOWN;
306 fprintf(stderr, _("'%s' exited with non-zero status.\n"), 331 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
307 cmdline);
308 } 332 }
309 333
310 *pkglist=malloc(sizeof(char *) * chld_out.lines); 334 char **pkglist = malloc(sizeof(char *) * chld_out.lines);
311 if(!pkglist) die(STATE_UNKNOWN, "malloc failed!\n"); 335 if (!pkglist) {
312 *secpkglist=malloc(sizeof(char *) * chld_out.lines); 336 die(STATE_UNKNOWN, "malloc failed!\n");
313 if(!secpkglist) die(STATE_UNKNOWN, "malloc failed!\n"); 337 }
338 char **secpkglist = malloc(sizeof(char *) * chld_out.lines);
339 if (!secpkglist) {
340 die(STATE_UNKNOWN, "malloc failed!\n");
341 }
314 342
315 /* parse the output, which should only consist of lines like 343 /* parse the output, which should only consist of lines like
316 * 344 *
@@ -321,82 +349,91 @@ int run_upgrade(int *pkgcount, int *secpkgcount, char ***pkglist, char ***secpkg
321 * we may need to switch to the --print-uris output format, 349 * we may need to switch to the --print-uris output format,
322 * in which case the logic here will slightly change. 350 * in which case the logic here will slightly change.
323 */ 351 */
324 for(size_t i = 0; i < chld_out.lines; i++) { 352 int package_counter = 0;
325 if(verbose){ 353 int security_package_counter = 0;
354 for (size_t i = 0; i < chld_out.lines; i++) {
355 if (verbose) {
326 printf("%s\n", chld_out.line[i]); 356 printf("%s\n", chld_out.line[i]);
327 } 357 }
328 /* if it is a package we care about */ 358 /* if it is a package we care about */
329 if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 && 359 if (strncmp(PKGINST_PREFIX, chld_out.line[i], strlen(PKGINST_PREFIX)) == 0 &&
330 (do_include == NULL || regexec(&ireg, chld_out.line[i], 0, NULL, 0) == 0)) { 360 (do_include == NULL || regexec(&ireg, chld_out.line[i], 0, NULL, 0) == 0)) {
331 /* if we're not excluding, or it's not in the 361 /* if we're not excluding, or it's not in the
332 * list of stuff to exclude */ 362 * list of stuff to exclude */
333 if(do_exclude==NULL || 363 if (do_exclude == NULL || regexec(&ereg, chld_out.line[i], 0, NULL, 0) != 0) {
334 regexec(&ereg, chld_out.line[i], 0, NULL, 0)!=0){ 364 package_counter++;
335 pc++; 365 if (regexec(&sreg, chld_out.line[i], 0, NULL, 0) == 0) {
336 if(regexec(&sreg, chld_out.line[i], 0, NULL, 0)==0){ 366 security_package_counter++;
337 spc++; 367 if (verbose) {
338 if(verbose) printf("*"); 368 printf("*");
339 (*secpkglist)[spc-1] = pkg_name(chld_out.line[i]); 369 }
370 (secpkglist)[security_package_counter - 1] = pkg_name(chld_out.line[i]);
340 } else { 371 } else {
341 (*pkglist)[pc-spc-1] = pkg_name(chld_out.line[i]); 372 (pkglist)[package_counter - security_package_counter - 1] = pkg_name(chld_out.line[i]);
342 } 373 }
343 if(verbose){ 374 if (verbose) {
344 printf("*%s\n", chld_out.line[i]); 375 printf("*%s\n", chld_out.line[i]);
345 } 376 }
346 } 377 }
347 } 378 }
348 } 379 }
349 *pkgcount=pc; 380 result.package_count = package_counter;
350 *secpkgcount=spc; 381 result.security_package_count = security_package_counter;
382 result.packages_list = pkglist;
383 result.secpackages_list = secpkglist;
351 384
352 /* If we get anything on stderr, at least set warning */ 385 /* If we get anything on stderr, at least set warning */
353 if (input_filename == NULL && chld_err.buflen) { 386 if (input_filename == NULL && chld_err.buflen) {
354 stderr_warning=1; 387 stderr_warning = true;
355 result = max_state(result, STATE_WARNING); 388 result.errorcode = max_state(result.errorcode, STATE_WARNING);
356 if(verbose){ 389 if (verbose) {
357 for(size_t i = 0; i < chld_err.lines; i++) { 390 for (size_t i = 0; i < chld_err.lines; i++) {
358 fprintf(stderr, "%s\n", chld_err.line[i]); 391 fprintf(stderr, "%s\n", chld_err.line[i]);
359 } 392 }
360 } 393 }
361 } 394 }
362 if (do_include != NULL) regfree(&ireg); 395 if (do_include != NULL) {
396 regfree(&ireg);
397 }
363 regfree(&sreg); 398 regfree(&sreg);
364 if(do_exclude!=NULL) regfree(&ereg); 399 if (do_exclude != NULL) {
400 regfree(&ereg);
401 }
365 free(cmdline); 402 free(cmdline);
366 return result; 403 return result;
367} 404}
368 405
369/* run an apt-get update (needs root) */ 406/* run an apt-get update (needs root) */
370int run_update(void){ 407int run_update(char *update_opts) {
371 int result=STATE_UNKNOWN; 408 int result = STATE_UNKNOWN;
372 struct output chld_out, chld_err;
373 char *cmdline; 409 char *cmdline;
374
375 /* run the update */ 410 /* run the update */
376 cmdline = construct_cmdline(NO_UPGRADE, update_opts); 411 cmdline = construct_cmdline(NO_UPGRADE, update_opts);
412
413 struct output chld_out;
414 struct output chld_err;
377 result = np_runcmd(cmdline, &chld_out, &chld_err, 0); 415 result = np_runcmd(cmdline, &chld_out, &chld_err, 0);
378 /* apt-get update changes exit status if it can't fetch packages. 416 /* apt-get update changes exit status if it can't fetch packages.
379 * since we were explicitly asked to do so, this is treated as 417 * since we were explicitly asked to do so, this is treated as
380 * a critical error. */ 418 * a critical error. */
381 if(result != 0){ 419 if (result != 0) {
382 exec_warning=1; 420 exec_warning = true;
383 result = STATE_CRITICAL; 421 result = STATE_CRITICAL;
384 fprintf(stderr, _("'%s' exited with non-zero status.\n"), 422 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
385 cmdline);
386 } 423 }
387 424
388 if(verbose){ 425 if (verbose) {
389 for(size_t i = 0; i < chld_out.lines; i++) { 426 for (size_t i = 0; i < chld_out.lines; i++) {
390 printf("%s\n", chld_out.line[i]); 427 printf("%s\n", chld_out.line[i]);
391 } 428 }
392 } 429 }
393 430
394 /* If we get anything on stderr, at least set warning */ 431 /* If we get anything on stderr, at least set warning */
395 if(chld_err.buflen){ 432 if (chld_err.buflen) {
396 stderr_warning=1; 433 stderr_warning = 1;
397 result = max_state(result, STATE_WARNING); 434 result = max_state(result, STATE_WARNING);
398 if(verbose){ 435 if (verbose) {
399 for(size_t i = 0; i < chld_err.lines; i++) { 436 for (size_t i = 0; i < chld_err.lines; i++) {
400 fprintf(stderr, "%s\n", chld_err.line[i]); 437 fprintf(stderr, "%s\n", chld_err.line[i]);
401 } 438 }
402 } 439 }
@@ -405,158 +442,168 @@ int run_update(void){
405 return result; 442 return result;
406} 443}
407 444
408char* pkg_name(char *line){ 445char *pkg_name(char *line) {
409 char *start=NULL, *space=NULL, *pkg=NULL; 446 char *start = line + strlen(PKGINST_PREFIX);
410 int len=0;
411 447
412 start = line + strlen(PKGINST_PREFIX); 448 size_t len = strlen(start);
413 len = strlen(start);
414 449
415 space = index(start, ' '); 450 char *space = index(start, ' ');
416 if(space!=NULL){ 451 if (space != NULL) {
417 len = space - start; 452 len = space - start;
418 } 453 }
419 454
420 pkg=malloc(sizeof(char)*(len+1)); 455 char *pkg = malloc(sizeof(char) * (len + 1));
421 if(!pkg) die(STATE_UNKNOWN, "malloc failed!\n"); 456 if (!pkg) {
457 die(STATE_UNKNOWN, "malloc failed!\n");
458 }
422 459
423 strncpy(pkg, start, len); 460 strncpy(pkg, start, len);
424 pkg[len]='\0'; 461 pkg[len] = '\0';
425 462
426 return pkg; 463 return pkg;
427} 464}
428 465
429int cmpstringp(const void *p1, const void *p2){ 466int cmpstringp(const void *left_string, const void *right_string) {
430 return strcmp(* (char * const *) p1, * (char * const *) p2); 467 return strcmp(*(char *const *)left_string, *(char *const *)right_string);
431} 468}
432 469
433char* add_to_regexp(char *expr, const char *next){ 470char *add_to_regexp(char *expr, const char *next) {
434 char *re=NULL; 471 char *regex_string = NULL;
435 472
436 if(expr==NULL){ 473 if (expr == NULL) {
437 re=malloc(sizeof(char)*(strlen("()")+strlen(next)+1)); 474 regex_string = malloc(sizeof(char) * (strlen("()") + strlen(next) + 1));
438 if(!re) die(STATE_UNKNOWN, "malloc failed!\n"); 475 if (!regex_string) {
439 sprintf(re, "(%s)", next); 476 die(STATE_UNKNOWN, "malloc failed!\n");
477 }
478 sprintf(regex_string, "(%s)", next);
440 } else { 479 } else {
441 /* resize it, adding an extra char for the new '|' separator */ 480 /* resize it, adding an extra char for the new '|' separator */
442 re=realloc(expr, sizeof(char)*(strlen(expr)+1+strlen(next)+1)); 481 regex_string = realloc(expr, sizeof(char) * (strlen(expr) + 1 + strlen(next) + 1));
443 if(!re) die(STATE_UNKNOWN, "realloc failed!\n"); 482 if (!regex_string) {
483 die(STATE_UNKNOWN, "realloc failed!\n");
484 }
444 /* append it starting at ')' in the old re */ 485 /* append it starting at ')' in the old re */
445 sprintf((char*)(re+strlen(re)-1), "|%s)", next); 486 sprintf((char *)(regex_string + strlen(regex_string) - 1), "|%s)", next);
446 } 487 }
447 488
448 return re; 489 return regex_string;
449} 490}
450 491
451char* construct_cmdline(upgrade_type u, const char *opts){ 492char *construct_cmdline(upgrade_type upgrade, const char *opts) {
452 int len=0; 493 const char *opts_ptr = NULL;
453 const char *opts_ptr=NULL, *aptcmd=NULL; 494 const char *aptcmd = NULL;
454 char *cmd=NULL;
455 495
456 switch(u){ 496 switch (upgrade) {
457 case UPGRADE: 497 case UPGRADE:
458 if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS; 498 if (opts == NULL) {
459 else opts_ptr=opts; 499 opts_ptr = UPGRADE_DEFAULT_OPTS;
460 aptcmd="upgrade"; 500 } else {
501 opts_ptr = opts;
502 }
503 aptcmd = "upgrade";
461 break; 504 break;
462 case DIST_UPGRADE: 505 case DIST_UPGRADE:
463 if(opts==NULL) opts_ptr=UPGRADE_DEFAULT_OPTS; 506 if (opts == NULL) {
464 else opts_ptr=opts; 507 opts_ptr = UPGRADE_DEFAULT_OPTS;
465 aptcmd="dist-upgrade"; 508 } else {
509 opts_ptr = opts;
510 }
511 aptcmd = "dist-upgrade";
466 break; 512 break;
467 case NO_UPGRADE: 513 case NO_UPGRADE:
468 if(opts==NULL) opts_ptr=UPDATE_DEFAULT_OPTS; 514 if (opts == NULL) {
469 else opts_ptr=opts; 515 opts_ptr = UPDATE_DEFAULT_OPTS;
470 aptcmd="update"; 516 } else {
517 opts_ptr = opts;
518 }
519 aptcmd = "update";
471 break; 520 break;
472 } 521 }
473 522
474 len+=strlen(PATH_TO_APTGET)+1; /* "/usr/bin/apt-get " */ 523 int len = 0;
475 len+=strlen(opts_ptr)+1; /* "opts " */ 524 len += strlen(PATH_TO_APTGET) + 1; /* "/usr/bin/apt-get " */
476 len+=strlen(aptcmd)+1; /* "upgrade\0" */ 525 len += strlen(opts_ptr) + 1; /* "opts " */
526 len += strlen(aptcmd) + 1; /* "upgrade\0" */
477 527
478 cmd=(char*)malloc(sizeof(char)*len); 528 char *cmd = (char *)malloc(sizeof(char) * len);
479 if(cmd==NULL) die(STATE_UNKNOWN, "malloc failed"); 529 if (cmd == NULL) {
530 die(STATE_UNKNOWN, "malloc failed");
531 }
480 sprintf(cmd, "%s %s %s", PATH_TO_APTGET, opts_ptr, aptcmd); 532 sprintf(cmd, "%s %s %s", PATH_TO_APTGET, opts_ptr, aptcmd);
481 return cmd; 533 return cmd;
482} 534}
483 535
484/* informative help message */ 536/* informative help message */
485void 537void print_help(void) {
486print_help (void) 538 print_revision(progname, NP_VERSION);
487{ 539
488 print_revision(progname, NP_VERSION); 540 printf(_(COPYRIGHT), copyright, email);
489 541
490 printf(_(COPYRIGHT), copyright, email); 542 printf("%s\n", _("This plugin checks for software updates on systems that use"));
491 543 printf("%s\n", _("package management systems based on the apt-get(8) command"));
492 printf("%s\n", _("This plugin checks for software updates on systems that use")); 544 printf("%s\n", _("found in Debian GNU/Linux"));
493 printf("%s\n", _("package management systems based on the apt-get(8) command")); 545
494 printf("%s\n", _("found in Debian GNU/Linux")); 546 printf("\n\n");
495 547
496 printf ("\n\n"); 548 print_usage();
497 549
498 print_usage(); 550 printf(UT_HELP_VRSN);
499 551 printf(UT_EXTRA_OPTS);
500 printf(UT_HELP_VRSN); 552
501 printf(UT_EXTRA_OPTS); 553 printf(UT_PLUG_TIMEOUT, timeout_interval);
502 554
503 printf(UT_PLUG_TIMEOUT, timeout_interval); 555 printf(" %s\n", "-n, --no-upgrade");
504 556 printf(" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least)."));
505 printf (" %s\n", "-n, --no-upgrade"); 557 printf(" %s\n", "-l, --list");
506 printf (" %s\n", _("Do not run the upgrade. Probably not useful (without -u at least).")); 558 printf(" %s\n", _("List packages available for upgrade. Packages are printed sorted by"));
507 printf (" %s\n", "-l, --list"); 559 printf(" %s\n", _("name with security packages listed first."));
508 printf (" %s\n", _("List packages available for upgrade. Packages are printed sorted by")); 560 printf(" %s\n", "-i, --include=REGEXP");
509 printf (" %s\n", _("name with security packages listed first.")); 561 printf(" %s\n", _("Include only packages matching REGEXP. Can be specified multiple times"));
510 printf (" %s\n", "-i, --include=REGEXP"); 562 printf(" %s\n", _("the values will be combined together. Any packages matching this list"));
511 printf (" %s\n", _("Include only packages matching REGEXP. Can be specified multiple times")); 563 printf(" %s\n", _("cause the plugin to return WARNING status. Others will be ignored."));
512 printf (" %s\n", _("the values will be combined together. Any packages matching this list")); 564 printf(" %s\n", _("Default is to include all packages."));
513 printf (" %s\n", _("cause the plugin to return WARNING status. Others will be ignored.")); 565 printf(" %s\n", "-e, --exclude=REGEXP");
514 printf (" %s\n", _("Default is to include all packages.")); 566 printf(" %s\n", _("Exclude packages matching REGEXP from the list of packages that would"));
515 printf (" %s\n", "-e, --exclude=REGEXP"); 567 printf(" %s\n", _("otherwise be included. Can be specified multiple times; the values"));
516 printf (" %s\n", _("Exclude packages matching REGEXP from the list of packages that would")); 568 printf(" %s\n", _("will be combined together. Default is to exclude no packages."));
517 printf (" %s\n", _("otherwise be included. Can be specified multiple times; the values")); 569 printf(" %s\n", "-c, --critical=REGEXP");
518 printf (" %s\n", _("will be combined together. Default is to exclude no packages.")); 570 printf(" %s\n", _("If the full package information of any of the upgradable packages match"));
519 printf (" %s\n", "-c, --critical=REGEXP"); 571 printf(" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified"));
520 printf (" %s\n", _("If the full package information of any of the upgradable packages match")); 572 printf(" %s\n", _("multiple times like above. Default is a regexp matching security"));
521 printf (" %s\n", _("this REGEXP, the plugin will return CRITICAL status. Can be specified")); 573 printf(" %s\n", _("upgrades for Debian and Ubuntu:"));
522 printf (" %s\n", _("multiple times like above. Default is a regexp matching security")); 574 printf(" \t%s\n", SECURITY_RE);
523 printf (" %s\n", _("upgrades for Debian and Ubuntu:")); 575 printf(" %s\n", _("Note that the package must first match the include list before its"));
524 printf (" \t%s\n", SECURITY_RE); 576 printf(" %s\n", _("information is compared against the critical list."));
525 printf (" %s\n", _("Note that the package must first match the include list before its")); 577 printf(" %s\n", "-o, --only-critical");
526 printf (" %s\n", _("information is compared against the critical list.")); 578 printf(" %s\n", _("Only warn about upgrades matching the critical list. The total number"));
527 printf (" %s\n", "-o, --only-critical"); 579 printf(" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause"));
528 printf (" %s\n", _("Only warn about upgrades matching the critical list. The total number")); 580 printf(" %s\n", _("the plugin to return WARNING status."));
529 printf (" %s\n", _("of upgrades will be printed, but any non-critical upgrades will not cause")); 581 printf(" %s\n", "-w, --packages-warning");
530 printf (" %s\n", _("the plugin to return WARNING status.")); 582 printf(" %s\n", _("Minimum number of packages available for upgrade to return WARNING status."));
531 printf (" %s\n", "-w, --packages-warning"); 583 printf(" %s\n\n", _("Default is 1 package."));
532 printf (" %s\n", _("Minimum number of packages available for upgrade to return WARNING status.")); 584
533 printf (" %s\n\n", _("Default is 1 package.")); 585 printf("%s\n\n", _("The following options require root privileges and should be used with care:"));
534 586 printf(" %s\n", "-u, --update=OPTS");
535 printf ("%s\n\n", _("The following options require root privileges and should be used with care:")); 587 printf(" %s\n", _("First perform an 'apt-get update'. An optional OPTS parameter overrides"));
536 printf (" %s\n", "-u, --update=OPTS"); 588 printf(" %s\n", _("the default options. Note: you may also need to adjust the global"));
537 printf (" %s\n", _("First perform an 'apt-get update'. An optional OPTS parameter overrides")); 589 printf(" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get"));
538 printf (" %s\n", _("the default options. Note: you may also need to adjust the global")); 590 printf(" %s\n", _("upgrade is expected to take longer than the default timeout."));
539 printf (" %s\n", _("timeout (with -t) to prevent the plugin from timing out if apt-get")); 591 printf(" %s\n", "-U, --upgrade=OPTS");
540 printf (" %s\n", _("upgrade is expected to take longer than the default timeout.")); 592 printf(" %s\n", _("Perform an upgrade. If an optional OPTS argument is provided,"));
541 printf (" %s\n", "-U, --upgrade=OPTS"); 593 printf(" %s\n", _("apt-get will be run with these command line options instead of the"));
542 printf (" %s\n", _("Perform an upgrade. If an optional OPTS argument is provided,")); 594 printf(" %s", _("default "));
543 printf (" %s\n", _("apt-get will be run with these command line options instead of the")); 595 printf("(%s).\n", UPGRADE_DEFAULT_OPTS);
544 printf (" %s", _("default ")); 596 printf(" %s\n", _("Note that you may be required to have root privileges if you do not use"));
545 printf ("(%s).\n", UPGRADE_DEFAULT_OPTS); 597 printf(" %s\n", _("the default options, which will only run a simulation and NOT perform the upgrade"));
546 printf (" %s\n", _("Note that you may be required to have root privileges if you do not use")); 598 printf(" %s\n", "-d, --dist-upgrade=OPTS");
547 printf (" %s\n", _("the default options, which will only run a simulation and NOT perform the upgrade")); 599 printf(" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS"));
548 printf (" %s\n", "-d, --dist-upgrade=OPTS"); 600 printf(" %s\n", _("can be provided to override the default options."));
549 printf (" %s\n", _("Perform a dist-upgrade instead of normal upgrade. Like with -U OPTS")); 601
550 printf (" %s\n", _("can be provided to override the default options.")); 602 printf(UT_SUPPORT);
551
552 printf(UT_SUPPORT);
553} 603}
554 604
555
556/* simple usage heading */ 605/* simple usage heading */
557void 606void print_usage(void) {
558print_usage(void) 607 printf("%s\n", _("Usage:"));
559{ 608 printf("%s [[-d|-u|-U]opts] [-n] [-l] [-t timeout] [-w packages-warning]\n", progname);
560 printf ("%s\n", _("Usage:"));
561 printf ("%s [[-d|-u|-U]opts] [-n] [-l] [-t timeout] [-w packages-warning]\n", progname);
562} 609}
diff --git a/plugins/check_apt.d/config.h b/plugins/check_apt.d/config.h
new file mode 100644
index 00000000..981f4f42
--- /dev/null
+++ b/plugins/check_apt.d/config.h
@@ -0,0 +1,41 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6/* some constants */
7typedef enum {
8 UPGRADE,
9 DIST_UPGRADE,
10 NO_UPGRADE
11} upgrade_type;
12
13typedef struct {
14 bool do_update; /* whether to call apt-get update */
15 upgrade_type upgrade; /* which type of upgrade to do */
16 bool only_critical; /* whether to warn about non-critical updates */
17 bool list; /* list packages available for upgrade */
18 /* number of packages available for upgrade to return WARNING status */
19 int packages_warning;
20
21 char *upgrade_opts; /* options to override defaults for upgrade */
22 char *update_opts; /* options to override defaults for update */
23 char *do_include; /* regexp to only include certain packages */
24 char *do_exclude; /* regexp to only exclude certain packages */
25 char *do_critical; /* regexp specifying critical packages */
26 char *input_filename; /* input filename for testing */
27} check_apt_config;
28
29check_apt_config check_apt_config_init() {
30 check_apt_config tmp = {.do_update = false,
31 .upgrade = UPGRADE,
32 .only_critical = false,
33 .list = false,
34 .packages_warning = 1,
35 .update_opts = NULL,
36 .do_include = NULL,
37 .do_exclude = NULL,
38 .do_critical = NULL,
39 .input_filename = NULL};
40 return tmp;
41}
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
index 2a23b397..2bc38d49 100644
--- a/plugins/check_by_ssh.c
+++ b/plugins/check_by_ssh.c
@@ -1,495 +1,509 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_by_ssh plugin 3 * Monitoring check_by_ssh plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_by_ssh plugin 10 * This file contains the check_by_ssh plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29const char *progname = "check_by_ssh"; 29const char *progname = "check_by_ssh";
30const char *copyright = "2000-2008"; 30const char *copyright = "2000-2024";
31const char *email = "devel@monitoring-plugins.org"; 31const char *email = "devel@monitoring-plugins.org";
32 32
33#include "common.h" 33#include "common.h"
34#include "utils.h" 34#include "utils.h"
35#include "netutils.h"
36#include "utils_cmd.h" 35#include "utils_cmd.h"
36#include "check_by_ssh.d/config.h"
37#include "states.h"
37 38
38#ifndef NP_MAXARGS 39#ifndef NP_MAXARGS
39#define NP_MAXARGS 1024 40# define NP_MAXARGS 1024
40#endif 41#endif
41 42
42int process_arguments (int, char **); 43typedef struct {
43int validate_arguments (void); 44 int errorcode;
44void comm_append (const char *); 45 check_by_ssh_config config;
45void print_help (void); 46} check_by_ssh_config_wrapper;
46void print_usage (void); 47static check_by_ssh_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
47 48static check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper /*config_wrapper*/);
48unsigned int commands = 0;
49unsigned int services = 0;
50int skip_stdout = 0;
51int skip_stderr = 0;
52int warn_on_stderr = 0;
53bool unknown_timeout = false;
54char *remotecmd = NULL;
55char **commargv = NULL;
56int commargc = 0;
57char *hostname = NULL;
58char *outputfile = NULL;
59char *host_shortname = NULL;
60char **service;
61bool passive = false;
62bool verbose = false;
63
64int
65main (int argc, char **argv)
66{
67 49
68 char *status_text; 50static command_construct comm_append(command_construct /*cmd*/, const char * /*str*/);
69 int cresult; 51static void print_help(void);
70 int result = STATE_UNKNOWN; 52void print_usage(void);
71 time_t local_time;
72 FILE *fp = NULL;
73 output chld_out, chld_err;
74 53
75 remotecmd = ""; 54static bool verbose = false;
76 comm_append(SSH_COMMAND);
77 55
78 setlocale (LC_ALL, ""); 56int main(int argc, char **argv) {
79 bindtextdomain (PACKAGE, LOCALEDIR); 57 setlocale(LC_ALL, "");
80 textdomain (PACKAGE); 58 bindtextdomain(PACKAGE, LOCALEDIR);
59 textdomain(PACKAGE);
81 60
82 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
83 argv=np_extra_opts (&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
63
64 check_by_ssh_config_wrapper tmp_config = process_arguments(argc, argv);
84 65
85 /* process arguments */ 66 /* process arguments */
86 if (process_arguments (argc, argv) == ERROR) 67 if (tmp_config.errorcode == ERROR) {
87 usage_va(_("Could not parse arguments")); 68 usage_va(_("Could not parse arguments"));
69 }
70
71 const check_by_ssh_config config = tmp_config.config;
88 72
89 /* Set signal handling and alarm timeout */ 73 /* Set signal handling and alarm timeout */
90 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 74 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
91 usage_va(_("Cannot catch SIGALRM")); 75 usage_va(_("Cannot catch SIGALRM"));
92 } 76 }
93 alarm (timeout_interval); 77 alarm(timeout_interval);
94 78
95 /* run the command */ 79 /* run the command */
96 if (verbose) { 80 if (verbose) {
97 printf ("Command: %s\n", commargv[0]); 81 printf("Command: %s\n", config.cmd.commargv[0]);
98 for (int i = 1; i < commargc; i++) 82 for (int i = 1; i < config.cmd.commargc; i++) {
99 printf ("Argument %i: %s\n", i, commargv[i]); 83 printf("Argument %i: %s\n", i, config.cmd.commargv[i]);
84 }
100 } 85 }
101 86
102 result = cmd_run_array (commargv, &chld_out, &chld_err, 0); 87 output chld_out;
88 output chld_err;
89 mp_state_enum result = cmd_run_array(config.cmd.commargv, &chld_out, &chld_err, 0);
103 90
104 /* SSH returns 255 if connection attempt fails; include the first line of error output */ 91 /* SSH returns 255 if connection attempt fails; include the first line of error output */
105 if (result == 255 && unknown_timeout) { 92 if (result == 255 && config.unknown_timeout) {
106 printf (_("SSH connection failed: %s\n"), 93 printf(_("SSH connection failed: %s\n"), chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
107 chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
108 return STATE_UNKNOWN; 94 return STATE_UNKNOWN;
109 } 95 }
110 96
111 if (verbose) { 97 if (verbose) {
112 for(size_t i = 0; i < chld_out.lines; i++) 98 for (size_t i = 0; i < chld_out.lines; i++) {
113 printf("stdout: %s\n", chld_out.line[i]); 99 printf("stdout: %s\n", chld_out.line[i]);
114 for(size_t i = 0; i < chld_err.lines; i++) 100 }
101 for (size_t i = 0; i < chld_err.lines; i++) {
115 printf("stderr: %s\n", chld_err.line[i]); 102 printf("stderr: %s\n", chld_err.line[i]);
103 }
116 } 104 }
117 105
118 if (skip_stdout == -1) /* --skip-stdout specified without argument */ 106 size_t skip_stdout = 0;
107 if (config.skip_stdout == -1) { /* --skip-stdout specified without argument */
119 skip_stdout = chld_out.lines; 108 skip_stdout = chld_out.lines;
120 if (skip_stderr == -1) /* --skip-stderr specified without argument */ 109 } else {
110 skip_stdout = config.skip_stdout;
111 }
112
113 size_t skip_stderr = 0;
114 if (config.skip_stderr == -1) { /* --skip-stderr specified without argument */
121 skip_stderr = chld_err.lines; 115 skip_stderr = chld_err.lines;
116 } else {
117 skip_stderr = config.skip_stderr;
118 }
122 119
123 /* UNKNOWN or worse if (non-skipped) output found on stderr */ 120 /* UNKNOWN or worse if (non-skipped) output found on stderr */
124 if(chld_err.lines > (size_t)skip_stderr) { 121 if (chld_err.lines > (size_t)skip_stderr) {
125 printf (_("Remote command execution failed: %s\n"), 122 printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]);
126 chld_err.line[skip_stderr]); 123 if (config.warn_on_stderr) {
127 if ( warn_on_stderr )
128 return max_state_alt(result, STATE_WARNING); 124 return max_state_alt(result, STATE_WARNING);
129 else 125 }
130 return max_state_alt(result, STATE_UNKNOWN); 126 return max_state_alt(result, STATE_UNKNOWN);
131 } 127 }
132 128
133 /* this is simple if we're not supposed to be passive. 129 /* this is simple if we're not supposed to be passive.
134 * Wrap up quickly and keep the tricks below */ 130 * Wrap up quickly and keep the tricks below */
135 if(!passive) { 131 if (!config.passive) {
136 if (chld_out.lines > (size_t)skip_stdout) 132 if (chld_out.lines > (size_t)skip_stdout) {
137 for (size_t i = skip_stdout; i < chld_out.lines; i++) 133 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
138 puts (chld_out.line[i]); 134 puts(chld_out.line[i]);
139 else 135 }
140 printf (_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), 136 } else {
141 state_text(result), remotecmd, result); 137 printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), state_text(result), config.remotecmd, result);
142 return result; /* return error status from remote command */ 138 }
139 return result; /* return error status from remote command */
143 } 140 }
144 141
145
146 /* 142 /*
147 * Passive mode 143 * Passive mode
148 */ 144 */
149 145
150 /* process output */ 146 /* process output */
151 if (!(fp = fopen (outputfile, "a"))) { 147 FILE *file_pointer = NULL;
152 printf (_("SSH WARNING: could not open %s\n"), outputfile); 148 if (!(file_pointer = fopen(config.outputfile, "a"))) {
153 exit (STATE_UNKNOWN); 149 printf(_("SSH WARNING: could not open %s\n"), config.outputfile);
150 exit(STATE_UNKNOWN);
154 } 151 }
155 152
156 local_time = time (NULL); 153 time_t local_time = time(NULL);
157 commands = 0; 154 unsigned int commands = 0;
158 for(size_t i = skip_stdout; i < chld_out.lines; i++) { 155 char *status_text;
156 int cresult;
157 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
159 status_text = chld_out.line[i++]; 158 status_text = chld_out.line[i++];
160 if (i == chld_out.lines || strstr (chld_out.line[i], "STATUS CODE: ") == NULL) 159 if (i == chld_out.lines || strstr(chld_out.line[i], "STATUS CODE: ") == NULL) {
161 die (STATE_UNKNOWN, _("%s: Error parsing output\n"), progname); 160 die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname);
162 161 }
163 if (service[commands] && status_text 162
164 && sscanf (chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) 163 if (config.service[commands] && status_text && sscanf(chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) {
165 { 164 fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, config.host_shortname,
166 fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", 165 config.service[commands++], cresult, status_text);
167 (int) local_time, host_shortname, service[commands++],
168 cresult, status_text);
169 } 166 }
170 } 167 }
171 168
172 /* Multiple commands and passive checking should always return OK */ 169 /* Multiple commands and passive checking should always return OK */
173 return result; 170 exit(result);
174} 171}
175 172
176/* process command-line arguments */ 173/* process command-line arguments */
177int 174check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
178process_arguments (int argc, char **argv) 175 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
179{ 176 {"help", no_argument, 0, 'h'},
180 int c; 177 {"verbose", no_argument, 0, 'v'},
181 char *p1, *p2; 178 {"fork", no_argument, 0, 'f'},
182 179 {"timeout", required_argument, 0, 't'},
183 int option = 0; 180 {"unknown-timeout", no_argument, 0, 'U'},
184 static struct option longopts[] = { 181 {"host", required_argument, 0, 'H'}, /* backward compatibility */
185 {"version", no_argument, 0, 'V'}, 182 {"hostname", required_argument, 0, 'H'},
186 {"help", no_argument, 0, 'h'}, 183 {"port", required_argument, 0, 'p'},
187 {"verbose", no_argument, 0, 'v'}, 184 {"output", required_argument, 0, 'O'},
188 {"fork", no_argument, 0, 'f'}, 185 {"name", required_argument, 0, 'n'},
189 {"timeout", required_argument, 0, 't'}, 186 {"services", required_argument, 0, 's'},
190 {"unknown-timeout", no_argument, 0, 'U'}, 187 {"identity", required_argument, 0, 'i'},
191 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 188 {"user", required_argument, 0, 'u'},
192 {"hostname", required_argument, 0, 'H'}, 189 {"logname", required_argument, 0, 'l'},
193 {"port", required_argument,0,'p'}, 190 {"command", required_argument, 0, 'C'},
194 {"output", required_argument, 0, 'O'}, 191 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */
195 {"name", required_argument, 0, 'n'}, 192 {"skip-stdout", optional_argument, 0, 'S'},
196 {"services", required_argument, 0, 's'}, 193 {"skip-stderr", optional_argument, 0, 'E'},
197 {"identity", required_argument, 0, 'i'}, 194 {"warn-on-stderr", no_argument, 0, 'W'},
198 {"user", required_argument, 0, 'u'}, 195 {"proto1", no_argument, 0, '1'},
199 {"logname", required_argument, 0, 'l'}, 196 {"proto2", no_argument, 0, '2'},
200 {"command", required_argument, 0, 'C'}, 197 {"use-ipv4", no_argument, 0, '4'},
201 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */ 198 {"use-ipv6", no_argument, 0, '6'},
202 {"skip-stdout", optional_argument, 0, 'S'}, 199 {"ssh-option", required_argument, 0, 'o'},
203 {"skip-stderr", optional_argument, 0, 'E'}, 200 {"quiet", no_argument, 0, 'q'},
204 {"warn-on-stderr", no_argument, 0, 'W'}, 201 {"configfile", optional_argument, 0, 'F'},
205 {"proto1", no_argument, 0, '1'}, 202 {0, 0, 0, 0}};
206 {"proto2", no_argument, 0, '2'}, 203
207 {"use-ipv4", no_argument, 0, '4'}, 204 check_by_ssh_config_wrapper result = {
208 {"use-ipv6", no_argument, 0, '6'}, 205 .errorcode = OK,
209 {"ssh-option", required_argument, 0, 'o'}, 206 .config = check_by_ssh_config_init(),
210 {"quiet", no_argument, 0, 'q'},
211 {"configfile", optional_argument, 0, 'F'},
212 {0, 0, 0, 0}
213 }; 207 };
214 208
215 if (argc < 2) 209 if (argc < 2) {
216 return ERROR; 210 result.errorcode = ERROR;
211 return result;
212 }
213
214 for (int index = 1; index < argc; index++) {
215 if (strcmp("-to", argv[index]) == 0) {
216 strcpy(argv[index], "-t");
217 }
218 }
217 219
218 for (c = 1; c < argc; c++) 220 result.config.cmd = comm_append(result.config.cmd, SSH_COMMAND);
219 if (strcmp ("-to", argv[c]) == 0)
220 strcpy (argv[c], "-t");
221 221
222 while (1) { 222 int option = 0;
223 c = getopt_long (argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, 223 while (true) {
224 &option); 224 int opt_index = getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option);
225 225
226 if (c == -1 || c == EOF) 226 if (opt_index == -1 || opt_index == EOF) {
227 break; 227 break;
228 }
228 229
229 switch (c) { 230 switch (opt_index) {
230 case 'V': /* version */ 231 case 'V': /* version */
231 print_revision (progname, NP_VERSION); 232 print_revision(progname, NP_VERSION);
232 exit (STATE_UNKNOWN); 233 exit(STATE_UNKNOWN);
233 case 'h': /* help */ 234 case 'h': /* help */
234 print_help (); 235 print_help();
235 exit (STATE_UNKNOWN); 236 exit(STATE_UNKNOWN);
236 case 'v': /* help */ 237 case 'v': /* help */
237 verbose = true; 238 verbose = true;
238 break; 239 break;
239 case 't': /* timeout period */ 240 case 't': /* timeout period */
240 if (!is_integer (optarg)) 241 if (!is_integer(optarg)) {
241 usage_va(_("Timeout interval must be a positive integer")); 242 usage_va(_("Timeout interval must be a positive integer"));
242 else 243 } else {
243 timeout_interval = atoi (optarg); 244 timeout_interval = atoi(optarg);
245 }
244 break; 246 break;
245 case 'U': 247 case 'U':
246 unknown_timeout = true; 248 result.config.unknown_timeout = true;
247 break; 249 break;
248 case 'H': /* host */ 250 case 'H': /* host */
249 hostname = optarg; 251 result.config.hostname = optarg;
250 break; 252 break;
251 case 'p': /* port number */ 253 case 'p': /* port number */
252 if (!is_integer (optarg)) 254 if (!is_integer(optarg)) {
253 usage_va(_("Port must be a positive integer")); 255 usage_va(_("Port must be a positive integer"));
254 comm_append("-p"); 256 }
255 comm_append(optarg); 257 result.config.cmd = comm_append(result.config.cmd, "-p");
258 result.config.cmd = comm_append(result.config.cmd, optarg);
256 break; 259 break;
257 case 'O': /* output file */ 260 case 'O': /* output file */
258 outputfile = optarg; 261 result.config.outputfile = optarg;
259 passive = true; 262 result.config.passive = true;
260 break; 263 break;
261 case 's': /* description of service to check */ 264 case 's': /* description of service to check */ {
265 char *p1;
266 char *p2;
267
262 p1 = optarg; 268 p1 = optarg;
263 service = realloc (service, (++services) * sizeof(char *)); 269 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
264 while ((p2 = index (p1, ':'))) { 270 while ((p2 = index(p1, ':'))) {
265 *p2 = '\0'; 271 *p2 = '\0';
266 service[services - 1] = p1; 272 result.config.service[result.config.number_of_services - 1] = p1;
267 service = realloc (service, (++services) * sizeof(char *)); 273 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
268 p1 = p2 + 1; 274 p1 = p2 + 1;
269 } 275 }
270 service[services - 1] = p1; 276 result.config.service[result.config.number_of_services - 1] = p1;
271 break; 277 break;
272 case 'n': /* short name of host in the monitoring configuration */ 278 case 'n': /* short name of host in the monitoring configuration */
273 host_shortname = optarg; 279 result.config.host_shortname = optarg;
274 break; 280 } break;
275
276 case 'u': 281 case 'u':
277 comm_append("-l"); 282 result.config.cmd = comm_append(result.config.cmd, "-l");
278 comm_append(optarg); 283 result.config.cmd = comm_append(result.config.cmd, optarg);
279 break; 284 break;
280 case 'l': /* login name */ 285 case 'l': /* login name */
281 comm_append("-l"); 286 result.config.cmd = comm_append(result.config.cmd, "-l");
282 comm_append(optarg); 287 result.config.cmd = comm_append(result.config.cmd, optarg);
283 break; 288 break;
284 case 'i': /* identity */ 289 case 'i': /* identity */
285 comm_append("-i"); 290 result.config.cmd = comm_append(result.config.cmd, "-i");
286 comm_append(optarg); 291 result.config.cmd = comm_append(result.config.cmd, optarg);
287 break; 292 break;
288 293
289 case '1': /* Pass these switches directly to ssh */ 294 case '1': /* Pass these switches directly to ssh */
290 comm_append("-1"); 295 result.config.cmd = comm_append(result.config.cmd, "-1");
291 break; 296 break;
292 case '2': /* 1 to force version 1, 2 to force version 2 */ 297 case '2': /* 1 to force version 1, 2 to force version 2 */
293 comm_append("-2"); 298 result.config.cmd = comm_append(result.config.cmd, "-2");
294 break; 299 break;
295 case '4': /* -4 for IPv4 */ 300 case '4': /* -4 for IPv4 */
296 comm_append("-4"); 301 result.config.cmd = comm_append(result.config.cmd, "-4");
297 break; 302 break;
298 case '6': /* -6 for IPv6 */ 303 case '6': /* -6 for IPv6 */
299 comm_append("-6"); 304 result.config.cmd = comm_append(result.config.cmd, "-6");
300 break; 305 break;
301 case 'f': /* fork to background */ 306 case 'f': /* fork to background */
302 comm_append("-f"); 307 result.config.cmd = comm_append(result.config.cmd, "-f");
303 break; 308 break;
304 case 'C': /* Command for remote machine */ 309 case 'C': /* Command for remote machine */
305 commands++; 310 result.config.commands++;
306 if (commands > 1) 311 if (result.config.commands > 1) {
307 xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 312 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
308 xasprintf (&remotecmd, "%s%s", remotecmd, optarg); 313 }
314 xasprintf(&result.config.remotecmd, "%s%s", result.config.remotecmd, optarg);
309 break; 315 break;
310 case 'S': /* skip n (or all) lines on stdout */ 316 case 'S': /* skip n (or all) lines on stdout */
311 if (optarg == NULL) 317 if (optarg == NULL) {
312 skip_stdout = -1; /* skip all output on stdout */ 318 result.config.skip_stdout = -1; /* skip all output on stdout */
313 else if (!is_integer (optarg)) 319 } else if (!is_integer(optarg)) {
314 usage_va(_("skip-stdout argument must be an integer")); 320 usage_va(_("skip-stdout argument must be an integer"));
315 else 321 } else {
316 skip_stdout = atoi (optarg); 322 result.config.skip_stdout = atoi(optarg);
323 }
317 break; 324 break;
318 case 'E': /* skip n (or all) lines on stderr */ 325 case 'E': /* skip n (or all) lines on stderr */
319 if (optarg == NULL) 326 if (optarg == NULL) {
320 skip_stderr = -1; /* skip all output on stderr */ 327 result.config.skip_stderr = -1; /* skip all output on stderr */
321 else if (!is_integer (optarg)) 328 } else if (!is_integer(optarg)) {
322 usage_va(_("skip-stderr argument must be an integer")); 329 usage_va(_("skip-stderr argument must be an integer"));
323 else 330 } else {
324 skip_stderr = atoi (optarg); 331 result.config.skip_stderr = atoi(optarg);
332 }
325 break; 333 break;
326 case 'W': /* exit with warning if there is an output on stderr */ 334 case 'W': /* exit with warning if there is an output on stderr */
327 warn_on_stderr = 1; 335 result.config.warn_on_stderr = true;
328 break; 336 break;
329 case 'o': /* Extra options for the ssh command */ 337 case 'o': /* Extra options for the ssh command */
330 comm_append("-o"); 338 result.config.cmd = comm_append(result.config.cmd, "-o");
331 comm_append(optarg); 339 result.config.cmd = comm_append(result.config.cmd, optarg);
332 break; 340 break;
333 case 'q': /* Tell the ssh command to be quiet */ 341 case 'q': /* Tell the ssh command to be quiet */
334 comm_append("-q"); 342 result.config.cmd = comm_append(result.config.cmd, "-q");
335 break; 343 break;
336 case 'F': /* ssh configfile */ 344 case 'F': /* ssh configfile */
337 comm_append("-F"); 345 result.config.cmd = comm_append(result.config.cmd, "-F");
338 comm_append(optarg); 346 result.config.cmd = comm_append(result.config.cmd, optarg);
339 break; 347 break;
340 default: /* help */ 348 default: /* help */
341 usage5(); 349 usage5();
342 } 350 }
343 } 351 }
344 352
345 c = optind; 353 int c = optind;
346 if (hostname == NULL) { 354 if (result.config.hostname == NULL) {
347 if (c <= argc) { 355 if (c <= argc) {
348 die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname); 356 die(STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
349 } 357 }
350 hostname = argv[c++]; 358 result.config.hostname = argv[c++];
351 } 359 }
352 360
353 if (strlen(remotecmd) == 0) { 361 if (strlen(result.config.remotecmd) == 0) {
354 for (; c < argc; c++) 362 for (; c < argc; c++) {
355 if (strlen(remotecmd) > 0) 363 if (strlen(result.config.remotecmd) > 0) {
356 xasprintf (&remotecmd, "%s %s", remotecmd, argv[c]); 364 xasprintf(&result.config.remotecmd, "%s %s", result.config.remotecmd, argv[c]);
357 else 365 } else {
358 xasprintf (&remotecmd, "%s", argv[c]); 366 xasprintf(&result.config.remotecmd, "%s", argv[c]);
367 }
368 }
359 } 369 }
360 370
361 if (commands > 1 || passive) 371 if (result.config.commands > 1 || result.config.passive) {
362 xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 372 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
373 }
363 374
364 if (remotecmd == NULL || strlen (remotecmd) <= 1) 375 if (result.config.remotecmd == NULL || strlen(result.config.remotecmd) <= 1) {
365 usage_va(_("No remotecmd")); 376 usage_va(_("No remotecmd"));
377 }
366 378
367 comm_append(hostname); 379 result.config.cmd = comm_append(result.config.cmd, result.config.hostname);
368 comm_append(remotecmd); 380 result.config.cmd = comm_append(result.config.cmd, result.config.remotecmd);
369 381
370 return validate_arguments (); 382 return validate_arguments(result);
371} 383}
372 384
385command_construct comm_append(command_construct cmd, const char *str) {
373 386
374void 387 if (verbose) {
375comm_append (const char *str) 388 for (int i = 0; i < cmd.commargc; i++) {
376{ 389 printf("Current command: [%i] %s\n", i, cmd.commargv[i]);
390 }
391
392 printf("Appending: %s\n", str);
393 }
377 394
378 if (++commargc > NP_MAXARGS) 395 if (++cmd.commargc > NP_MAXARGS) {
379 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS); 396 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS);
397 }
380 398
381 if ((commargv = (char **)realloc(commargv, (commargc+1) * sizeof(char *))) == NULL) 399 if ((cmd.commargv = (char **)realloc(cmd.commargv, (cmd.commargc + 1) * sizeof(char *))) == NULL) {
382 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n")); 400 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n"));
401 }
383 402
384 commargv[commargc-1] = strdup(str); 403 cmd.commargv[cmd.commargc - 1] = strdup(str);
385 commargv[commargc] = NULL; 404 cmd.commargv[cmd.commargc] = NULL;
386 405
406 return cmd;
387} 407}
388 408
389int 409check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper config_wrapper) {
390validate_arguments (void) 410 if (config_wrapper.config.remotecmd == NULL || config_wrapper.config.hostname == NULL) {
391{ 411 config_wrapper.errorcode = ERROR;
392 if (remotecmd == NULL || hostname == NULL) 412 return config_wrapper;
393 return ERROR; 413 }
394 414
395 if (passive && commands != services) 415 if (config_wrapper.config.passive && config_wrapper.config.commands != config_wrapper.config.number_of_services) {
396 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname); 416 die(STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
417 }
397 418
398 if (passive && host_shortname == NULL) 419 if (config_wrapper.config.passive && config_wrapper.config.host_shortname == NULL) {
399 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname); 420 die(STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname);
421 }
400 422
401 return OK; 423 return config_wrapper;
402} 424}
403 425
404 426void print_help(void) {
405void 427 print_revision(progname, NP_VERSION);
406print_help (void) 428
407{ 429 printf("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
408 print_revision (progname, NP_VERSION); 430 printf(COPYRIGHT, copyright, email);
409 431
410 printf ("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"); 432 printf(_("This plugin uses SSH to execute commands on a remote host"));
411 printf (COPYRIGHT, copyright, email); 433
412 434 printf("\n\n");
413 printf (_("This plugin uses SSH to execute commands on a remote host")); 435
414 436 print_usage();
415 printf ("\n\n"); 437
416 438 printf(UT_HELP_VRSN);
417 print_usage (); 439
418 440 printf(UT_EXTRA_OPTS);
419 printf (UT_HELP_VRSN); 441
420 442 printf(UT_HOST_PORT, 'p', "none");
421 printf (UT_EXTRA_OPTS); 443
422 444 printf(UT_IPv46);
423 printf (UT_HOST_PORT, 'p', "none"); 445
424 446 printf(" %s\n", "-1, --proto1");
425 printf (UT_IPv46); 447 printf(" %s\n", _("tell ssh to use Protocol 1 [optional]"));
426 448 printf(" %s\n", "-2, --proto2");
427 printf (" %s\n", "-1, --proto1"); 449 printf(" %s\n", _("tell ssh to use Protocol 2 [optional]"));
428 printf (" %s\n", _("tell ssh to use Protocol 1 [optional]")); 450 printf(" %s\n", "-S, --skip-stdout[=n]");
429 printf (" %s\n", "-2, --proto2"); 451 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]"));
430 printf (" %s\n", _("tell ssh to use Protocol 2 [optional]")); 452 printf(" %s\n", "-E, --skip-stderr[=n]");
431 printf (" %s\n", "-S, --skip-stdout[=n]"); 453 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]"));
432 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]")); 454 printf(" %s\n", "-W, --warn-on-stderr]");
433 printf (" %s\n", "-E, --skip-stderr[=n]"); 455 printf(" %s\n", _("Exit with an warning, if there is an output on STDERR"));
434 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]")); 456 printf(" %s\n", "-f");
435 printf (" %s\n", "-W, --warn-on-stderr]"); 457 printf(" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed"));
436 printf (" %s\n", _("Exit with an warning, if there is an output on STDERR")); 458 printf(" %s\n", "-C, --command='COMMAND STRING'");
437 printf (" %s\n", "-f"); 459 printf(" %s\n", _("command to execute on the remote machine"));
438 printf (" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed")); 460 printf(" %s\n", "-l, --logname=USERNAME");
439 printf (" %s\n","-C, --command='COMMAND STRING'"); 461 printf(" %s\n", _("SSH user name on remote host [optional]"));
440 printf (" %s\n", _("command to execute on the remote machine")); 462 printf(" %s\n", "-i, --identity=KEYFILE");
441 printf (" %s\n","-l, --logname=USERNAME"); 463 printf(" %s\n", _("identity of an authorized key [optional]"));
442 printf (" %s\n", _("SSH user name on remote host [optional]")); 464 printf(" %s\n", "-O, --output=FILE");
443 printf (" %s\n","-i, --identity=KEYFILE"); 465 printf(" %s\n", _("external command file for monitoring [optional]"));
444 printf (" %s\n", _("identity of an authorized key [optional]")); 466 printf(" %s\n", "-s, --services=LIST");
445 printf (" %s\n","-O, --output=FILE"); 467 printf(" %s\n", _("list of monitoring service names, separated by ':' [optional]"));
446 printf (" %s\n", _("external command file for monitoring [optional]")); 468 printf(" %s\n", "-n, --name=NAME");
447 printf (" %s\n","-s, --services=LIST"); 469 printf(" %s\n", _("short name of host in the monitoring configuration [optional]"));
448 printf (" %s\n", _("list of monitoring service names, separated by ':' [optional]")); 470 printf(" %s\n", "-o, --ssh-option=OPTION");
449 printf (" %s\n","-n, --name=NAME"); 471 printf(" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]"));
450 printf (" %s\n", _("short name of host in the monitoring configuration [optional]")); 472 printf(" %s\n", "-F, --configfile");
451 printf (" %s\n","-o, --ssh-option=OPTION"); 473 printf(" %s\n", _("Tell ssh to use this configfile [optional]"));
452 printf (" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]")); 474 printf(" %s\n", "-q, --quiet");
453 printf (" %s\n","-F, --configfile"); 475 printf(" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]"));
454 printf (" %s\n", _("Tell ssh to use this configfile [optional]")); 476 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
455 printf (" %s\n","-q, --quiet"); 477 printf(" %s\n", "-U, --unknown-timeout");
456 printf (" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]")); 478 printf(" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL"));
457 printf (UT_WARN_CRIT); 479 printf(UT_VERBOSE);
458 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 480 printf("\n");
459 printf (" %s\n","-U, --unknown-timeout"); 481 printf(" %s\n", _("The most common mode of use is to refer to a local identity file with"));
460 printf (" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL")); 482 printf(" %s\n", _("the '-i' option. In this mode, the identity pair should have a null"));
461 printf (UT_VERBOSE); 483 printf(" %s\n", _("passphrase and the public key should be listed in the authorized_keys"));
484 printf(" %s\n", _("file of the remote host. Usually the key will be restricted to running"));
485 printf(" %s\n", _("only one command on the remote server. If the remote SSH server tracks"));
486 printf(" %s\n", _("invocation arguments, the one remote program may be an agent that can"));
487 printf(" %s\n", _("execute additional commands as proxy"));
462 printf("\n"); 488 printf("\n");
463 printf (" %s\n", _("The most common mode of use is to refer to a local identity file with")); 489 printf(" %s\n", _("To use passive mode, provide multiple '-C' options, and provide"));
464 printf (" %s\n", _("the '-i' option. In this mode, the identity pair should have a null")); 490 printf(" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
465 printf (" %s\n", _("passphrase and the public key should be listed in the authorized_keys")); 491 printf("\n");
466 printf (" %s\n", _("file of the remote host. Usually the key will be restricted to running")); 492 printf("%s\n", _("Examples:"));
467 printf (" %s\n", _("only one command on the remote server. If the remote SSH server tracks")); 493 printf(" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
468 printf (" %s\n", _("invocation arguments, the one remote program may be an agent that can")); 494 printf(" %s\n", "$ cat /tmp/foo");
469 printf (" %s\n", _("execute additional commands as proxy")); 495 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
470 printf("\n"); 496 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
471 printf (" %s\n", _("To use passive mode, provide multiple '-C' options, and provide")); 497 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
472 printf (" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
473 printf ("\n");
474 printf ("%s\n", _("Examples:"));
475 printf (" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
476 printf (" %s\n", "$ cat /tmp/foo");
477 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
478 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
479 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
480 498
481 printf(UT_SUPPORT); 499 printf(UT_SUPPORT);
482} 500}
483 501
484 502void print_usage(void) {
485 503 printf("%s\n", _("Usage:"));
486void 504 printf(" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n"
487print_usage (void) 505 " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n"
488{ 506 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
489 printf ("%s\n", _("Usage:")); 507 " [-p port] [-o ssh-option] [-F configfile]\n",
490 printf (" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n" 508 progname);
491 " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n"
492 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
493 " [-p port] [-o ssh-option] [-F configfile]\n",
494 progname);
495} 509}
diff --git a/plugins/check_by_ssh.d/config.h b/plugins/check_by_ssh.d/config.h
new file mode 100644
index 00000000..05435def
--- /dev/null
+++ b/plugins/check_by_ssh.d/config.h
@@ -0,0 +1,56 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6typedef struct {
7 int commargc;
8 char **commargv;
9} command_construct;
10
11typedef struct {
12 char *hostname;
13 char *host_shortname;
14
15 char **service;
16 unsigned int number_of_services;
17
18 unsigned int commands; // Not needed during actual test run
19 char *remotecmd;
20
21 command_construct cmd;
22
23 bool unknown_timeout;
24 bool warn_on_stderr;
25 int skip_stdout;
26 int skip_stderr;
27 bool passive;
28 char *outputfile;
29} check_by_ssh_config;
30
31check_by_ssh_config check_by_ssh_config_init() {
32 check_by_ssh_config tmp = {
33 .hostname = NULL,
34 .host_shortname = NULL,
35
36 .service = NULL,
37 .number_of_services = 0,
38
39 .commands = 0,
40 .remotecmd = "",
41
42 .cmd =
43 {
44 .commargc = 0,
45 .commargv = NULL,
46 },
47
48 .unknown_timeout = false,
49 .warn_on_stderr = false,
50 .skip_stderr = 0,
51 .skip_stdout = 0,
52 .passive = false,
53 .outputfile = NULL,
54 };
55 return tmp;
56}
diff --git a/plugins/check_cluster.c b/plugins/check_cluster.c
index e1ede9f7..9b695499 100644
--- a/plugins/check_cluster.c
+++ b/plugins/check_cluster.c
@@ -1,92 +1,82 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* check_cluster.c - Host and Service Cluster Plugin for Monitoring 3 * check_cluster.c - Host and Service Cluster Plugin for Monitoring
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)
7* Copyright (c) 2007 Monitoring Plugins Development Team 7 * Copyright (c) 2007-2024 Monitoring Plugins Development Team
8* 8 *
9* This program is free software: you can redistribute it and/or modify 9 * This program is free software: you can redistribute it and/or modify
10* it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
11* the Free Software Foundation, either version 3 of the License, or 11 * the Free Software Foundation, either version 3 of the License, or
12* (at your option) any later version. 12 * (at your option) any later version.
13* 13 *
14* This program is distributed in the hope that it will be useful, 14 * This program is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17* GNU General Public License for more details. 17 * GNU General Public License for more details.
18* 18 *
19* You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
20* along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21* 21 *
22* 22 *
23*****************************************************************************/ 23 *****************************************************************************/
24 24
25const char *progname = "check_cluster"; 25const char *progname = "check_cluster";
26const char *copyright = "2000-2007"; 26const char *copyright = "2000-2024";
27const char *email = "devel@monitoring-plugins.org"; 27const char *email = "devel@monitoring-plugins.org";
28 28
29#include "common.h" 29#include "common.h"
30#include "utils.h" 30#include "utils.h"
31#include "utils_base.h" 31#include "utils_base.h"
32#include "check_cluster.d/config.h"
32 33
33#define CHECK_SERVICES 1 34static void print_help(void);
34#define CHECK_HOSTS 2 35void print_usage(void);
35 36
36void print_help (void); 37static int verbose = 0;
37void print_usage (void);
38 38
39int total_services_ok=0; 39typedef struct {
40int total_services_warning=0; 40 int errorcode;
41int total_services_unknown=0; 41 check_cluster_config config;
42int total_services_critical=0; 42} check_cluster_config_wrapper;
43static check_cluster_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
43 44
44int total_hosts_up=0; 45int main(int argc, char **argv) {
45int total_hosts_down=0; 46 setlocale(LC_ALL, "");
46int total_hosts_unreachable=0; 47 bindtextdomain(PACKAGE, LOCALEDIR);
47 48 textdomain(PACKAGE);
48char *warn_threshold;
49char *crit_threshold;
50
51int check_type=CHECK_SERVICES;
52
53char *data_vals=NULL;
54char *label=NULL;
55
56int verbose=0;
57
58int process_arguments(int,char **);
59
60
61
62int main(int argc, char **argv){
63 char *ptr;
64 int data_val;
65 int return_code=STATE_OK;
66 thresholds *thresholds = NULL;
67
68 setlocale (LC_ALL, "");
69 bindtextdomain (PACKAGE, LOCALEDIR);
70 textdomain (PACKAGE);
71 49
72 /* Parse extra opts if any */ 50 /* Parse extra opts if any */
73 argv=np_extra_opts(&argc, argv, progname); 51 argv = np_extra_opts(&argc, argv, progname);
74 52
75 if(process_arguments(argc,argv)==ERROR) 53 check_cluster_config_wrapper tmp_config = process_arguments(argc, argv);
54 if (tmp_config.errorcode == ERROR) {
76 usage(_("Could not parse arguments")); 55 usage(_("Could not parse arguments"));
56 }
57
58 const check_cluster_config config = tmp_config.config;
77 59
78 /* Initialize the thresholds */ 60 /* Initialize the thresholds */
79 set_thresholds(&thresholds, warn_threshold, crit_threshold); 61 if (verbose) {
80 if(verbose) 62 print_thresholds("check_cluster", config.thresholds);
81 print_thresholds("check_cluster", thresholds); 63 }
82 64
65 int data_val;
66 int total_services_ok = 0;
67 int total_services_warning = 0;
68 int total_services_unknown = 0;
69 int total_services_critical = 0;
70 int total_hosts_up = 0;
71 int total_hosts_down = 0;
72 int total_hosts_unreachable = 0;
83 /* check the data values */ 73 /* check the data values */
84 for(ptr=strtok(data_vals,",");ptr!=NULL;ptr=strtok(NULL,",")){ 74 for (char *ptr = strtok(config.data_vals, ","); ptr != NULL; ptr = strtok(NULL, ",")) {
85 75
86 data_val=atoi(ptr); 76 data_val = atoi(ptr);
87 77
88 if(check_type==CHECK_SERVICES){ 78 if (config.check_type == CHECK_SERVICES) {
89 switch(data_val){ 79 switch (data_val) {
90 case 0: 80 case 0:
91 total_services_ok++; 81 total_services_ok++;
92 break; 82 break;
@@ -101,10 +91,9 @@ int main(int argc, char **argv){
101 break; 91 break;
102 default: 92 default:
103 break; 93 break;
104 } 94 }
105 } 95 } else {
106 else{ 96 switch (data_val) {
107 switch(data_val){
108 case 0: 97 case 0:
109 total_hosts_up++; 98 total_hosts_up++;
110 break; 99 break;
@@ -116,125 +105,117 @@ int main(int argc, char **argv){
116 break; 105 break;
117 default: 106 default:
118 break; 107 break;
119 } 108 }
120 } 109 }
121 } 110 }
122
123 111
112 int return_code = STATE_OK;
124 /* return the status of the cluster */ 113 /* return the status of the cluster */
125 if(check_type==CHECK_SERVICES){ 114 if (config.check_type == CHECK_SERVICES) {
126 return_code=get_status(total_services_warning+total_services_unknown+total_services_critical, thresholds); 115 return_code = get_status(total_services_warning + total_services_unknown + total_services_critical, config.thresholds);
127 printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", 116 printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", state_text(return_code),
128 state_text(return_code), (label==NULL)?"Service cluster":label, 117 (config.label == NULL) ? "Service cluster" : config.label, total_services_ok, total_services_warning, total_services_unknown,
129 total_services_ok,total_services_warning, 118 total_services_critical);
130 total_services_unknown,total_services_critical); 119 } else {
131 } 120 return_code = get_status(total_hosts_down + total_hosts_unreachable, config.thresholds);
132 else{ 121 printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n", state_text(return_code),
133 return_code=get_status(total_hosts_down+total_hosts_unreachable, thresholds); 122 (config.label == NULL) ? "Host cluster" : config.label, total_hosts_up, total_hosts_down, total_hosts_unreachable);
134 printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n",
135 state_text(return_code), (label==NULL)?"Host cluster":label,
136 total_hosts_up,total_hosts_down,total_hosts_unreachable);
137 } 123 }
138 124
139 return return_code; 125 exit(return_code);
140} 126}
141 127
128check_cluster_config_wrapper process_arguments(int argc, char **argv) {
129 static struct option longopts[] = {{"data", required_argument, 0, 'd'}, {"warning", required_argument, 0, 'w'},
130 {"critical", required_argument, 0, 'c'}, {"label", required_argument, 0, 'l'},
131 {"host", no_argument, 0, 'h'}, {"service", no_argument, 0, 's'},
132 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
133 {"help", no_argument, 0, 'H'}, {0, 0, 0, 0}};
142 134
143 135 check_cluster_config_wrapper result = {
144int process_arguments(int argc, char **argv){ 136 .errorcode = OK,
145 int c; 137 .config = check_cluster_config_init(),
146 char *ptr;
147 int option=0;
148 static struct option longopts[]={
149 {"data", required_argument,0,'d'},
150 {"warning", required_argument,0,'w'},
151 {"critical", required_argument,0,'c'},
152 {"label", required_argument,0,'l'},
153 {"host", no_argument, 0,'h'},
154 {"service", no_argument, 0,'s'},
155 {"verbose", no_argument, 0,'v'},
156 {"version", no_argument, 0,'V'},
157 {"help", no_argument, 0,'H'},
158 {0,0,0,0}
159 }; 138 };
160 139
161 /* no options were supplied */ 140 /* no options were supplied */
162 if(argc<2) 141 if (argc < 2) {
163 return ERROR; 142 result.errorcode = ERROR;
164 143 return result;
165 while(1){ 144 }
166 145
167 c=getopt_long(argc,argv,"hHsvVw:c:d:l:",longopts,&option); 146 int option = 0;
147 char *warn_threshold = NULL;
148 char *crit_threshold = NULL;
149 while (true) {
150 int option_index = getopt_long(argc, argv, "hHsvVw:c:d:l:", longopts, &option);
168 151
169 if(c==-1 || c==EOF || c==1) 152 if (option_index == -1 || option_index == EOF || option_index == 1) {
170 break; 153 break;
154 }
171 155
172 switch(c){ 156 switch (option_index) {
173
174 case 'h': /* host cluster */ 157 case 'h': /* host cluster */
175 check_type=CHECK_HOSTS; 158 result.config.check_type = CHECK_HOSTS;
176 break; 159 break;
177
178 case 's': /* service cluster */ 160 case 's': /* service cluster */
179 check_type=CHECK_SERVICES; 161 result.config.check_type = CHECK_SERVICES;
180 break; 162 break;
181
182 case 'w': /* warning threshold */ 163 case 'w': /* warning threshold */
183 warn_threshold = strdup(optarg); 164 warn_threshold = strdup(optarg);
184 break; 165 break;
185
186 case 'c': /* warning threshold */ 166 case 'c': /* warning threshold */
187 crit_threshold = strdup(optarg); 167 crit_threshold = strdup(optarg);
188 break; 168 break;
189
190 case 'd': /* data values */ 169 case 'd': /* data values */
191 data_vals=(char *)strdup(optarg); 170 result.config.data_vals = strdup(optarg);
192 /* validate data */ 171 /* validate data */
193 for (ptr=data_vals;ptr!=NULL;ptr+=2){ 172 for (char *ptr = result.config.data_vals; ptr != NULL; ptr += 2) {
194 if (ptr[0]<'0' || ptr[0]>'3') 173 if (ptr[0] < '0' || ptr[0] > '3') {
195 return ERROR; 174 result.errorcode = ERROR;
196 if (ptr[1]=='\0') 175 return result;
176 }
177 if (ptr[1] == '\0') {
197 break; 178 break;
198 if (ptr[1]!=',') 179 }
199 return ERROR; 180 if (ptr[1] != ',') {
181 result.errorcode = ERROR;
182 return result;
183 }
200 } 184 }
201 break; 185 break;
202
203 case 'l': /* text label */ 186 case 'l': /* text label */
204 label=(char *)strdup(optarg); 187 result.config.label = strdup(optarg);
205 break; 188 break;
206
207 case 'v': /* verbose */ 189 case 'v': /* verbose */
208 verbose++; 190 verbose++;
209 break; 191 break;
210
211 case 'V': /* version */ 192 case 'V': /* version */
212 print_revision (progname, NP_VERSION); 193 print_revision(progname, NP_VERSION);
213 exit (STATE_UNKNOWN); 194 exit(STATE_UNKNOWN);
214 break; 195 break;
215
216 case 'H': /* help */ 196 case 'H': /* help */
217 print_help(); 197 print_help();
218 exit(STATE_UNKNOWN); 198 exit(STATE_UNKNOWN);
219 break; 199 break;
220
221 default: 200 default:
222 return ERROR; 201 result.errorcode = ERROR;
202 return result;
223 break; 203 break;
224 } 204 }
225 } 205 }
226 206
227 if(data_vals==NULL) 207 if (result.config.data_vals == NULL) {
228 return ERROR; 208 result.errorcode = ERROR;
209 return result;
210 }
229 211
230 return OK; 212 set_thresholds(&result.config.thresholds, warn_threshold, crit_threshold);
213 return result;
231} 214}
232 215
233void 216void print_help(void) {
234print_help(void)
235{
236 print_revision(progname, NP_VERSION); 217 print_revision(progname, NP_VERSION);
237 printf ("Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)\n"); 218 printf("Copyright (c) 2000-2004 Ethan Galstad (nagios@nagios.org)\n");
238 printf(COPYRIGHT, copyright, email); 219 printf(COPYRIGHT, copyright, email);
239 220
240 printf(_("Host/Service Cluster Plugin for Monitoring")); 221 printf(_("Host/Service Cluster Plugin for Monitoring"));
@@ -245,21 +226,21 @@ print_help(void)
245 printf("\n"); 226 printf("\n");
246 printf("%s\n", _("Options:")); 227 printf("%s\n", _("Options:"));
247 printf(UT_EXTRA_OPTS); 228 printf(UT_EXTRA_OPTS);
248 printf (" %s\n", "-s, --service"); 229 printf(" %s\n", "-s, --service");
249 printf (" %s\n", _("Check service cluster status")); 230 printf(" %s\n", _("Check service cluster status"));
250 printf (" %s\n", "-h, --host"); 231 printf(" %s\n", "-h, --host");
251 printf (" %s\n", _("Check host cluster status")); 232 printf(" %s\n", _("Check host cluster status"));
252 printf (" %s\n", "-l, --label=STRING"); 233 printf(" %s\n", "-l, --label=STRING");
253 printf (" %s\n", _("Optional prepended text output (i.e. \"Host cluster\")")); 234 printf(" %s\n", _("Optional prepended text output (i.e. \"Host cluster\")"));
254 printf (" %s\n", "-w, --warning=THRESHOLD"); 235 printf(" %s\n", "-w, --warning=THRESHOLD");
255 printf (" %s\n", _("Specifies the range of hosts or services in cluster that must be in a")); 236 printf(" %s\n", _("Specifies the range of hosts or services in cluster that must be in a"));
256 printf (" %s\n", _("non-OK state in order to return a WARNING status level")); 237 printf(" %s\n", _("non-OK state in order to return a WARNING status level"));
257 printf (" %s\n", "-c, --critical=THRESHOLD"); 238 printf(" %s\n", "-c, --critical=THRESHOLD");
258 printf (" %s\n", _("Specifies the range of hosts or services in cluster that must be in a")); 239 printf(" %s\n", _("Specifies the range of hosts or services in cluster that must be in a"));
259 printf (" %s\n", _("non-OK state in order to return a CRITICAL status level")); 240 printf(" %s\n", _("non-OK state in order to return a CRITICAL status level"));
260 printf (" %s\n", "-d, --data=LIST"); 241 printf(" %s\n", "-d, --data=LIST");
261 printf (" %s\n", _("The status codes of the hosts or services in the cluster, separated by")); 242 printf(" %s\n", _("The status codes of the hosts or services in the cluster, separated by"));
262 printf (" %s\n", _("commas")); 243 printf(" %s\n", _("commas"));
263 244
264 printf(UT_VERBOSE); 245 printf(UT_VERBOSE);
265 246
@@ -267,23 +248,18 @@ print_help(void)
267 printf("%s\n", _("Notes:")); 248 printf("%s\n", _("Notes:"));
268 printf(UT_THRESHOLDS_NOTES); 249 printf(UT_THRESHOLDS_NOTES);
269 250
270 printf ("\n"); 251 printf("\n");
271 printf ("%s\n", _("Examples:")); 252 printf("%s\n", _("Examples:"));
272 printf (" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:"); 253 printf(" %s\n", "check_cluster -s -d 2,0,2,0 -c @3:");
273 printf (" %s\n", _("Will alert critical if there are 3 or more service data points in a non-OK") ); 254 printf(" %s\n", _("Will alert critical if there are 3 or more service data points in a non-OK"));
274 printf (" %s\n", _("state.") ); 255 printf(" %s\n", _("state."));
275 256
276 printf(UT_SUPPORT); 257 printf(UT_SUPPORT);
277} 258}
278 259
279 260void print_usage(void) {
280void
281print_usage(void)
282{
283 261
284 printf("%s\n", _("Usage:")); 262 printf("%s\n", _("Usage:"));
285 printf(" %s (-s | -h) -d val1[,val2,...,valn] [-l label]\n", progname); 263 printf(" %s (-s | -h) -d val1[,val2,...,valn] [-l label]\n", progname);
286 printf("[-w threshold] [-c threshold] [-v] [--help]\n"); 264 printf("[-w threshold] [-c threshold] [-v] [--help]\n");
287
288} 265}
289
diff --git a/plugins/check_cluster.d/config.h b/plugins/check_cluster.d/config.h
new file mode 100644
index 00000000..fc386415
--- /dev/null
+++ b/plugins/check_cluster.d/config.h
@@ -0,0 +1,27 @@
1#pragma once
2
3#include "../../config.h"
4#include "../../lib/thresholds.h"
5#include <stddef.h>
6
7enum {
8 CHECK_SERVICES = 1,
9 CHECK_HOSTS = 2
10};
11
12typedef struct {
13 char *data_vals;
14 thresholds *thresholds;
15 int check_type;
16 char *label;
17} check_cluster_config;
18
19check_cluster_config check_cluster_config_init() {
20 check_cluster_config tmp = {
21 .data_vals = NULL,
22 .thresholds = NULL,
23 .check_type = CHECK_SERVICES,
24 .label = NULL,
25 };
26 return tmp;
27}
diff --git a/plugins/check_curl.c b/plugins/check_curl.c
index e25d7a79..748201e8 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -1,40 +1,40 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_curl plugin 3 * Monitoring check_curl plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2019 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_curl plugin 10 * This file contains the check_curl plugin
11* 11 *
12* This plugin tests the HTTP service on the specified host. It can test 12 * This plugin tests the HTTP service on the specified host. It can test
13* normal (http) and secure (https) servers, follow redirects, search for 13 * normal (http) and secure (https) servers, follow redirects, search for
14* strings and regular expressions, check connection times, and report on 14 * strings and regular expressions, check connection times, and report on
15* certificate expiration times. 15 * certificate expiration times.
16* 16 *
17* This plugin uses functions from the curl library, see 17 * This plugin uses functions from the curl library, see
18* http://curl.haxx.se 18 * http://curl.haxx.se
19* 19 *
20* This program is free software: you can redistribute it and/or modify 20 * This program is free software: you can redistribute it and/or modify
21* it under the terms of the GNU General Public License as published by 21 * it under the terms of the GNU General Public License as published by
22* the Free Software Foundation, either version 3 of the License, or 22 * the Free Software Foundation, either version 3 of the License, or
23* (at your option) any later version. 23 * (at your option) any later version.
24* 24 *
25* This program is distributed in the hope that it will be useful, 25 * This program is distributed in the hope that it will be useful,
26* but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28* GNU General Public License for more details. 28 * GNU General Public License for more details.
29* 29 *
30* You should have received a copy of the GNU General Public License 30 * You should have received a copy of the GNU General Public License
31* along with this program. If not, see <http://www.gnu.org/licenses/>. 31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32* 32 *
33* 33 *
34*****************************************************************************/ 34 *****************************************************************************/
35const char *progname = "check_curl"; 35const char *progname = "check_curl";
36 36
37const char *copyright = "2006-2019"; 37const char *copyright = "2006-2024";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include <stdbool.h> 40#include <stdbool.h>
@@ -44,7 +44,7 @@ const char *email = "devel@monitoring-plugins.org";
44#include "utils.h" 44#include "utils.h"
45 45
46#ifndef LIBCURL_PROTOCOL_HTTP 46#ifndef LIBCURL_PROTOCOL_HTTP
47#error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense 47# error libcurl compiled without HTTP support, compiling check_curl plugin does not makes a lot of sense
48#endif 48#endif
49 49
50#include "curl/curl.h" 50#include "curl/curl.h"
@@ -58,7 +58,7 @@ const char *email = "devel@monitoring-plugins.org";
58#include <netinet/in.h> 58#include <netinet/in.h>
59 59
60#if defined(HAVE_SSL) && defined(USE_OPENSSL) 60#if defined(HAVE_SSL) && defined(USE_OPENSSL)
61#include <openssl/opensslv.h> 61# include <openssl/opensslv.h>
62#endif 62#endif
63 63
64#include <netdb.h> 64#include <netdb.h>
@@ -66,1092 +66,1052 @@ const char *email = "devel@monitoring-plugins.org";
66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch)) 66#define MAKE_LIBCURL_VERSION(major, minor, patch) ((major)*0x10000 + (minor)*0x100 + (patch))
67 67
68#define DEFAULT_BUFFER_SIZE 2048 68#define DEFAULT_BUFFER_SIZE 2048
69#define DEFAULT_SERVER_URL "/" 69#define DEFAULT_SERVER_URL "/"
70#define HTTP_EXPECT "HTTP/" 70#define HTTP_EXPECT "HTTP/"
71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN 71#define INET_ADDR_MAX_SIZE INET6_ADDRSTRLEN
72enum { 72enum {
73 MAX_IPV4_HOSTLENGTH = 255, 73 MAX_IPV4_HOSTLENGTH = 255,
74 HTTP_PORT = 80, 74 HTTP_PORT = 80,
75 HTTPS_PORT = 443, 75 HTTPS_PORT = 443,
76 MAX_PORT = 65535, 76 MAX_PORT = 65535,
77 DEFAULT_MAX_REDIRS = 15 77 DEFAULT_MAX_REDIRS = 15
78}; 78};
79 79
80enum { 80enum {
81 STICKY_NONE = 0, 81 STICKY_NONE = 0,
82 STICKY_HOST = 1, 82 STICKY_HOST = 1,
83 STICKY_PORT = 2 83 STICKY_PORT = 2
84}; 84};
85 85
86enum { 86enum {
87 FOLLOW_HTTP_CURL = 0, 87 FOLLOW_HTTP_CURL = 0,
88 FOLLOW_LIBCURL = 1 88 FOLLOW_LIBCURL = 1
89}; 89};
90 90
91/* for buffers for header and body */ 91/* for buffers for header and body */
92typedef struct { 92typedef struct {
93 char *buf; 93 char *buf;
94 size_t buflen; 94 size_t buflen;
95 size_t bufsize; 95 size_t bufsize;
96} curlhelp_write_curlbuf; 96} curlhelp_write_curlbuf;
97 97
98/* for buffering the data sent in PUT */ 98/* for buffering the data sent in PUT */
99typedef struct { 99typedef struct {
100 char *buf; 100 char *buf;
101 size_t buflen; 101 size_t buflen;
102 off_t pos; 102 off_t pos;
103} curlhelp_read_curlbuf; 103} curlhelp_read_curlbuf;
104 104
105/* for parsing the HTTP status line */ 105/* for parsing the HTTP status line */
106typedef struct { 106typedef struct {
107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9 107 int http_major; /* major version of the protocol, always 1 (HTTP/0.9
108 * never reached the big internet most likely) */ 108 * never reached the big internet most likely) */
109 int http_minor; /* minor version of the protocol, usually 0 or 1 */ 109 int http_minor; /* minor version of the protocol, usually 0 or 1 */
110 int http_code; /* HTTP return code as in RFC 2145 */ 110 int http_code; /* HTTP return code as in RFC 2145 */
111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see 111 int http_subcode; /* Microsoft IIS extension, HTTP subcodes, see
112 * http://support.microsoft.com/kb/318380/en-us */ 112 * http://support.microsoft.com/kb/318380/en-us */
113 const char *msg; /* the human readable message */ 113 const char *msg; /* the human readable message */
114 char *first_line; /* a copy of the first line */ 114 char *first_line; /* a copy of the first line */
115} curlhelp_statusline; 115} curlhelp_statusline;
116 116
117/* to know the underlying SSL library used by libcurl */ 117/* to know the underlying SSL library used by libcurl */
118typedef enum curlhelp_ssl_library { 118typedef enum curlhelp_ssl_library {
119 CURLHELP_SSL_LIBRARY_UNKNOWN, 119 CURLHELP_SSL_LIBRARY_UNKNOWN,
120 CURLHELP_SSL_LIBRARY_OPENSSL, 120 CURLHELP_SSL_LIBRARY_OPENSSL,
121 CURLHELP_SSL_LIBRARY_LIBRESSL, 121 CURLHELP_SSL_LIBRARY_LIBRESSL,
122 CURLHELP_SSL_LIBRARY_GNUTLS, 122 CURLHELP_SSL_LIBRARY_GNUTLS,
123 CURLHELP_SSL_LIBRARY_NSS 123 CURLHELP_SSL_LIBRARY_NSS
124} curlhelp_ssl_library; 124} curlhelp_ssl_library;
125 125
126enum { 126enum {
127 REGS = 2, 127 REGS = 2,
128 MAX_RE_SIZE = 1024 128 MAX_RE_SIZE = 1024
129}; 129};
130#include "regex.h" 130#include "regex.h"
131regex_t preg; 131static regex_t preg;
132regmatch_t pmatch[REGS]; 132static regmatch_t pmatch[REGS];
133char regexp[MAX_RE_SIZE]; 133static char regexp[MAX_RE_SIZE];
134int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE; 134static int cflags = REG_NOSUB | REG_EXTENDED | REG_NEWLINE;
135int errcode; 135static int errcode;
136bool invert_regex = false; 136static bool invert_regex = false;
137int state_regex = STATE_CRITICAL; 137static int state_regex = STATE_CRITICAL;
138 138
139char *server_address = NULL; 139static char *server_address = NULL;
140char *host_name = NULL; 140static char *host_name = NULL;
141char *server_url = 0; 141static char *server_url = 0;
142char server_ip[DEFAULT_BUFFER_SIZE]; 142static struct curl_slist *server_ips = NULL;
143struct curl_slist *server_ips = NULL; 143static bool specify_port = false;
144bool specify_port = false; 144static unsigned short server_port = HTTP_PORT;
145unsigned short server_port = HTTP_PORT; 145static unsigned short virtual_port = 0;
146unsigned short virtual_port = 0; 146static int host_name_length;
147int host_name_length; 147static char output_header_search[30] = "";
148char output_header_search[30] = ""; 148static char output_string_search[30] = "";
149char output_string_search[30] = ""; 149static char *warning_thresholds = NULL;
150char *warning_thresholds = NULL; 150static char *critical_thresholds = NULL;
151char *critical_thresholds = NULL; 151static int days_till_exp_warn, days_till_exp_crit;
152int days_till_exp_warn, days_till_exp_crit; 152static thresholds *thlds;
153thresholds *thlds; 153static char user_agent[DEFAULT_BUFFER_SIZE];
154char user_agent[DEFAULT_BUFFER_SIZE]; 154static int verbose = 0;
155int verbose = 0; 155static bool show_extended_perfdata = false;
156bool show_extended_perfdata = false; 156static bool show_body = false;
157bool show_body = false; 157static int min_page_len = 0;
158int min_page_len = 0; 158static int max_page_len = 0;
159int max_page_len = 0; 159static int redir_depth = 0;
160int redir_depth = 0; 160static int max_depth = DEFAULT_MAX_REDIRS;
161int max_depth = DEFAULT_MAX_REDIRS; 161static char *http_method = NULL;
162char *http_method = NULL; 162static char *http_post_data = NULL;
163char *http_post_data = NULL; 163static char *http_content_type = NULL;
164char *http_content_type = NULL; 164static CURL *curl;
165CURL *curl; 165static bool curl_global_initialized = false;
166bool curl_global_initialized = false; 166static bool curl_easy_initialized = false;
167bool curl_easy_initialized = false; 167static struct curl_slist *header_list = NULL;
168struct curl_slist *header_list = NULL; 168static bool body_buf_initialized = false;
169bool body_buf_initialized = false; 169static curlhelp_write_curlbuf body_buf;
170curlhelp_write_curlbuf body_buf; 170static bool header_buf_initialized = false;
171bool header_buf_initialized = false; 171static curlhelp_write_curlbuf header_buf;
172curlhelp_write_curlbuf header_buf; 172static bool status_line_initialized = false;
173bool status_line_initialized = false; 173static curlhelp_statusline status_line;
174curlhelp_statusline status_line; 174static bool put_buf_initialized = false;
175bool put_buf_initialized = false; 175static curlhelp_read_curlbuf put_buf;
176curlhelp_read_curlbuf put_buf; 176static char http_header[DEFAULT_BUFFER_SIZE];
177char http_header[DEFAULT_BUFFER_SIZE]; 177static long code;
178long code; 178static long socket_timeout = DEFAULT_SOCKET_TIMEOUT;
179long socket_timeout = DEFAULT_SOCKET_TIMEOUT; 179static double total_time;
180double total_time; 180static double time_connect;
181double time_connect; 181static double time_appconnect;
182double time_appconnect; 182static double time_headers;
183double time_headers; 183static double time_firstbyte;
184double time_firstbyte; 184static char errbuf[MAX_INPUT_BUFFER];
185char errbuf[MAX_INPUT_BUFFER]; 185static CURLcode res;
186CURLcode res; 186static char url[DEFAULT_BUFFER_SIZE];
187char url[DEFAULT_BUFFER_SIZE]; 187static char msg[DEFAULT_BUFFER_SIZE];
188char msg[DEFAULT_BUFFER_SIZE]; 188static char perfstring[DEFAULT_BUFFER_SIZE];
189char perfstring[DEFAULT_BUFFER_SIZE]; 189static char header_expect[MAX_INPUT_BUFFER] = "";
190char header_expect[MAX_INPUT_BUFFER] = ""; 190static char string_expect[MAX_INPUT_BUFFER] = "";
191char string_expect[MAX_INPUT_BUFFER] = ""; 191static char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT;
192char server_expect[MAX_INPUT_BUFFER] = HTTP_EXPECT; 192static int server_expect_yn = 0;
193int server_expect_yn = 0; 193static char user_auth[MAX_INPUT_BUFFER] = "";
194char user_auth[MAX_INPUT_BUFFER] = ""; 194static char proxy_auth[MAX_INPUT_BUFFER] = "";
195char proxy_auth[MAX_INPUT_BUFFER] = ""; 195static char **http_opt_headers;
196char **http_opt_headers; 196static int http_opt_headers_count = 0;
197int http_opt_headers_count = 0; 197static bool display_html = false;
198bool display_html = false; 198static int onredirect = STATE_OK;
199int onredirect = STATE_OK; 199static int followmethod = FOLLOW_HTTP_CURL;
200int followmethod = FOLLOW_HTTP_CURL; 200static int followsticky = STICKY_NONE;
201int followsticky = STICKY_NONE; 201static bool use_ssl = false;
202bool use_ssl = false; 202static bool check_cert = false;
203bool use_sni = true; 203static bool continue_after_check_cert = false;
204bool check_cert = false;
205bool continue_after_check_cert = false;
206typedef union { 204typedef union {
207 struct curl_slist* to_info; 205 struct curl_slist *to_info;
208 struct curl_certinfo* to_certinfo; 206 struct curl_certinfo *to_certinfo;
209} cert_ptr_union; 207} cert_ptr_union;
210cert_ptr_union cert_ptr; 208static cert_ptr_union cert_ptr;
211int ssl_version = CURL_SSLVERSION_DEFAULT; 209static int ssl_version = CURL_SSLVERSION_DEFAULT;
212char *client_cert = NULL; 210static char *client_cert = NULL;
213char *client_privkey = NULL; 211static char *client_privkey = NULL;
214char *ca_cert = NULL; 212static char *ca_cert = NULL;
215bool verify_peer_and_host = false; 213static bool verify_peer_and_host = false;
216bool is_openssl_callback = false; 214static bool is_openssl_callback = false;
215static bool add_sslctx_verify_fun = false;
217#if defined(HAVE_SSL) && defined(USE_OPENSSL) 216#if defined(HAVE_SSL) && defined(USE_OPENSSL)
218X509 *cert = NULL; 217static X509 *cert = NULL;
219#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 218#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
220bool no_body = false; 219static bool no_body = false;
221int maximum_age = -1; 220static int maximum_age = -1;
222int address_family = AF_UNSPEC; 221static int address_family = AF_UNSPEC;
223curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 222static curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
224int curl_http_version = CURL_HTTP_VERSION_NONE; 223static int curl_http_version = CURL_HTTP_VERSION_NONE;
225bool automatic_decompression = false; 224static bool automatic_decompression = false;
226char *cookie_jar_file = NULL; 225static char *cookie_jar_file = NULL;
227bool haproxy_protocol = false; 226static bool haproxy_protocol = false;
228 227
229bool process_arguments (int, char**); 228static bool process_arguments(int /*argc*/, char ** /*argv*/);
230void handle_curl_option_return_code (CURLcode res, const char* option); 229static void handle_curl_option_return_code(CURLcode res, const char *option);
231int check_http (void); 230static int check_http(void);
232void redir (curlhelp_write_curlbuf*); 231static void redir(curlhelp_write_curlbuf * /*header_buf*/);
233char *perfd_time (double microsec); 232static char *perfd_time(double elapsed_time);
234char *perfd_time_connect (double microsec); 233static char *perfd_time_connect(double elapsed_time_connect);
235char *perfd_time_ssl (double microsec); 234static char *perfd_time_ssl(double elapsed_time_ssl);
236char *perfd_time_firstbyte (double microsec); 235static char *perfd_time_firstbyte(double elapsed_time_firstbyte);
237char *perfd_time_headers (double microsec); 236static char *perfd_time_headers(double elapsed_time_headers);
238char *perfd_time_transfer (double microsec); 237static char *perfd_time_transfer(double elapsed_time_transfer);
239char *perfd_size (int page_len); 238static char *perfd_size(int page_len);
240void print_help (void); 239static void print_help(void);
241void print_usage (void); 240void print_usage(void);
242void print_curl_version (void); 241static void print_curl_version(void);
243int curlhelp_initwritebuffer (curlhelp_write_curlbuf*); 242static int curlhelp_initwritebuffer(curlhelp_write_curlbuf * /*buf*/);
244size_t curlhelp_buffer_write_callback(void*, size_t , size_t , void*); 243static size_t curlhelp_buffer_write_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/);
245void curlhelp_freewritebuffer (curlhelp_write_curlbuf*); 244static void curlhelp_freewritebuffer(curlhelp_write_curlbuf * /*buf*/);
246int curlhelp_initreadbuffer (curlhelp_read_curlbuf *, const char *, size_t); 245static int curlhelp_initreadbuffer(curlhelp_read_curlbuf * /*buf*/, const char * /*data*/, size_t /*datalen*/);
247size_t curlhelp_buffer_read_callback(void *, size_t , size_t , void *); 246static size_t curlhelp_buffer_read_callback(void * /*buffer*/, size_t /*size*/, size_t /*nmemb*/, void * /*stream*/);
248void curlhelp_freereadbuffer (curlhelp_read_curlbuf *); 247static void curlhelp_freereadbuffer(curlhelp_read_curlbuf * /*buf*/);
249curlhelp_ssl_library curlhelp_get_ssl_library (); 248static curlhelp_ssl_library curlhelp_get_ssl_library(void);
250const char* curlhelp_get_ssl_library_string (curlhelp_ssl_library); 249static const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library /*ssl_library*/);
251int net_noopenssl_check_certificate (cert_ptr_union*, int, int); 250int net_noopenssl_check_certificate(cert_ptr_union *, int, int);
252 251
253int curlhelp_parse_statusline (const char*, curlhelp_statusline *); 252static int curlhelp_parse_statusline(const char * /*buf*/, curlhelp_statusline * /*status_line*/);
254void curlhelp_free_statusline (curlhelp_statusline *); 253static void curlhelp_free_statusline(curlhelp_statusline * /*status_line*/);
255char *get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header); 254static char *get_header_value(const struct phr_header *headers, size_t nof_headers, const char *header);
256int check_document_dates (const curlhelp_write_curlbuf *, char (*msg)[DEFAULT_BUFFER_SIZE]); 255static int check_document_dates(const curlhelp_write_curlbuf * /*header_buf*/, char (*msg)[DEFAULT_BUFFER_SIZE]);
257int get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf); 256static int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf);
258 257
259#if defined(HAVE_SSL) && defined(USE_OPENSSL) 258#if defined(HAVE_SSL) && defined(USE_OPENSSL)
260int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit); 259int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit);
261#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */ 260#endif /* defined(HAVE_SSL) && defined(USE_OPENSSL) */
262 261
263void remove_newlines (char *); 262static void test_file(char * /*path*/);
264void test_file (char *);
265 263
266int 264int main(int argc, char **argv) {
267main (int argc, char **argv) 265 int result = STATE_UNKNOWN;
268{
269 int result = STATE_UNKNOWN;
270 266
271 setlocale (LC_ALL, ""); 267 setlocale(LC_ALL, "");
272 bindtextdomain (PACKAGE, LOCALEDIR); 268 bindtextdomain(PACKAGE, LOCALEDIR);
273 textdomain (PACKAGE); 269 textdomain(PACKAGE);
274 270
275 /* Parse extra opts if any */ 271 /* Parse extra opts if any */
276 argv = np_extra_opts (&argc, argv, progname); 272 argv = np_extra_opts(&argc, argv, progname);
277 273
278 /* set defaults */ 274 /* set defaults */
279 snprintf( user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", 275 snprintf(user_agent, DEFAULT_BUFFER_SIZE, "%s/v%s (monitoring-plugins %s, %s)", progname, NP_VERSION, VERSION, curl_version());
280 progname, NP_VERSION, VERSION, curl_version());
281 276
282 /* parse arguments */ 277 /* parse arguments */
283 if (process_arguments (argc, argv) == false) 278 if (process_arguments(argc, argv) == false)
284 usage4 (_("Could not parse arguments")); 279 usage4(_("Could not parse arguments"));
285 280
286 if (display_html) 281 if (display_html)
287 printf ("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", 282 printf("<A HREF=\"%s://%s:%d%s\" target=\"_blank\">", use_ssl ? "https" : "http", host_name ? host_name : server_address,
288 use_ssl ? "https" : "http", 283 virtual_port ? virtual_port : server_port, server_url);
289 host_name ? host_name : server_address,
290 virtual_port ? virtual_port : server_port,
291 server_url);
292 284
293 result = check_http (); 285 result = check_http();
294 return result; 286 return result;
295} 287}
296 288
297#ifdef HAVE_SSL 289#ifdef HAVE_SSL
298#ifdef USE_OPENSSL 290# ifdef USE_OPENSSL
299 291
300int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) 292int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) {
301{ 293 (void)preverify_ok;
302 (void) preverify_ok; 294 /* TODO: we get all certificates of the chain, so which ones
303 /* TODO: we get all certificates of the chain, so which ones 295 * should we test?
304 * should we test? 296 * TODO: is the last certificate always the server certificate?
305 * TODO: is the last certificate always the server certificate? 297 */
306 */ 298 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
307 cert = X509_STORE_CTX_get_current_cert(x509_ctx); 299# if OPENSSL_VERSION_NUMBER >= 0x10100000L
308#if OPENSSL_VERSION_NUMBER >= 0x10100000L 300 X509_up_ref(cert);
309 X509_up_ref(cert); 301# endif
310#endif 302 if (verbose >= 2) {
311 if (verbose>=2) { 303 puts("* SSL verify callback with certificate:");
312 puts("* SSL verify callback with certificate:"); 304 X509_NAME *subject;
313 X509_NAME *subject, *issuer; 305 X509_NAME *issuer;
314 printf("* issuer:\n"); 306 printf("* issuer:\n");
315 issuer = X509_get_issuer_name( cert ); 307 issuer = X509_get_issuer_name(cert);
316 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE); 308 X509_NAME_print_ex_fp(stdout, issuer, 5, XN_FLAG_MULTILINE);
317 printf("* curl verify_callback:\n* subject:\n"); 309 printf("* curl verify_callback:\n* subject:\n");
318 subject = X509_get_subject_name( cert ); 310 subject = X509_get_subject_name(cert);
319 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE); 311 X509_NAME_print_ex_fp(stdout, subject, 5, XN_FLAG_MULTILINE);
320 puts(""); 312 puts("");
321 } 313 }
322 return 1; 314 return 1;
323} 315}
324 316
325CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) 317CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
326{ 318 (void)curl; // ignore unused parameter
327 (void) curl; // ignore unused parameter 319 (void)parm; // ignore unused parameter
328 (void) parm; // ignore unused parameter 320 if (add_sslctx_verify_fun) {
329 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback); 321 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, verify_callback);
322 }
330 323
331 return CURLE_OK; 324 // workaround for issue:
325 // OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
326 // see discussion https://github.com/openssl/openssl/discussions/22690
327# ifdef SSL_OP_IGNORE_UNEXPECTED_EOF
328 SSL_CTX_set_options(sslctx, SSL_OP_IGNORE_UNEXPECTED_EOF);
329# endif
330
331 return CURLE_OK;
332} 332}
333 333
334#endif /* USE_OPENSSL */ 334# endif /* USE_OPENSSL */
335#endif /* HAVE_SSL */ 335#endif /* HAVE_SSL */
336 336
337/* returns a string "HTTP/1.x" or "HTTP/2" */ 337/* returns a string "HTTP/1.x" or "HTTP/2" */
338static char *string_statuscode (int major, int minor) 338static char *string_statuscode(int major, int minor) {
339{ 339 static char buf[10];
340 static char buf[10]; 340
341 341 switch (major) {
342 switch (major) { 342 case 1:
343 case 1: 343 snprintf(buf, sizeof(buf), "HTTP/%d.%d", major, minor);
344 snprintf (buf, sizeof (buf), "HTTP/%d.%d", major, minor); 344 break;
345 break; 345 case 2:
346 case 2: 346 case 3:
347 case 3: 347 snprintf(buf, sizeof(buf), "HTTP/%d", major);
348 snprintf (buf, sizeof (buf), "HTTP/%d", major); 348 break;
349 break; 349 default:
350 default: 350 /* assuming here HTTP/N with N>=4 */
351 /* assuming here HTTP/N with N>=4 */ 351 snprintf(buf, sizeof(buf), "HTTP/%d", major);
352 snprintf (buf, sizeof (buf), "HTTP/%d", major); 352 break;
353 break; 353 }
354 } 354
355 355 return buf;
356 return buf;
357} 356}
358 357
359/* Checks if the server 'reply' is one of the expected 'statuscodes' */ 358/* Checks if the server 'reply' is one of the expected 'statuscodes' */
360static int 359static int expected_statuscode(const char *reply, const char *statuscodes) {
361expected_statuscode (const char *reply, const char *statuscodes) 360 char *expected;
362{ 361 char *code;
363 char *expected, *code; 362 int result = 0;
364 int result = 0; 363
365 364 if ((expected = strdup(statuscodes)) == NULL)
366 if ((expected = strdup (statuscodes)) == NULL) 365 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n"));
367 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Memory allocation error\n")); 366
368 367 for (code = strtok(expected, ","); code != NULL; code = strtok(NULL, ","))
369 for (code = strtok (expected, ","); code != NULL; code = strtok (NULL, ",")) 368 if (strstr(reply, code) != NULL) {
370 if (strstr (reply, code) != NULL) { 369 result = 1;
371 result = 1; 370 break;
372 break; 371 }
373 } 372
374 373 free(expected);
375 free (expected); 374 return result;
376 return result;
377} 375}
378 376
379void 377void handle_curl_option_return_code(CURLcode res, const char *option) {
380handle_curl_option_return_code (CURLcode res, const char* option) 378 if (res != CURLE_OK) {
381{ 379 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Error while setting cURL option '%s': cURL returned %d - %s"), option, res,
382 if (res != CURLE_OK) { 380 curl_easy_strerror(res));
383 snprintf (msg, 381 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
384 DEFAULT_BUFFER_SIZE, 382 }
385 _("Error while setting cURL option '%s': cURL returned %d - %s"),
386 option,
387 res,
388 curl_easy_strerror(res));
389 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
390 }
391} 383}
392 384
393int 385int lookup_host(const char *host, char *buf, size_t buflen) {
394lookup_host (const char *host, char *buf, size_t buflen) 386 struct addrinfo hints, *res, *result;
395{ 387 char addrstr[100];
396 struct addrinfo hints, *res, *result; 388 size_t addrstr_len;
397 char addrstr[100]; 389 int errcode;
398 size_t addrstr_len; 390 void *ptr = {0};
399 int errcode; 391 size_t buflen_remaining = buflen - 1;
400 void *ptr = { 0 }; 392
401 size_t buflen_remaining = buflen - 1; 393 memset(&hints, 0, sizeof(hints));
402 394 hints.ai_family = address_family;
403 memset (&hints, 0, sizeof (hints)); 395 hints.ai_socktype = SOCK_STREAM;
404 hints.ai_family = address_family; 396 hints.ai_flags |= AI_CANONNAME;
405 hints.ai_socktype = SOCK_STREAM; 397
406 hints.ai_flags |= AI_CANONNAME; 398 errcode = getaddrinfo(host, NULL, &hints, &result);
407 399 if (errcode != 0)
408 errcode = getaddrinfo (host, NULL, &hints, &result); 400 return errcode;
409 if (errcode != 0) 401
410 return errcode; 402 strcpy(buf, "");
411 403 res = result;
412 strcpy(buf, ""); 404
413 res = result; 405 while (res) {
414 406 switch (res->ai_family) {
415 while (res) { 407 case AF_INET:
416 switch (res->ai_family) { 408 ptr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
417 case AF_INET: 409 break;
418 ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr; 410 case AF_INET6:
419 break; 411 ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
420 case AF_INET6: 412 break;
421 ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr; 413 }
422 break; 414
423 } 415 inet_ntop(res->ai_family, ptr, addrstr, 100);
424 416 if (verbose >= 1) {
425 inet_ntop (res->ai_family, ptr, addrstr, 100); 417 printf("* getaddrinfo IPv%d address: %s\n", res->ai_family == PF_INET6 ? 6 : 4, addrstr);
426 if (verbose >= 1) { 418 }
427 printf ("* getaddrinfo IPv%d address: %s\n", 419
428 res->ai_family == PF_INET6 ? 6 : 4, addrstr); 420 // Append all IPs to buf as a comma-separated string
429 } 421 addrstr_len = strlen(addrstr);
430 422 if (buflen_remaining > addrstr_len + 1) {
431 // Append all IPs to buf as a comma-separated string 423 if (buf[0] != '\0') {
432 addrstr_len = strlen(addrstr); 424 strncat(buf, ",", buflen_remaining);
433 if (buflen_remaining > addrstr_len + 1) { 425 buflen_remaining -= 1;
434 if (buf[0] != '\0') { 426 }
435 strncat(buf, ",", buflen_remaining); 427 strncat(buf, addrstr, buflen_remaining);
436 buflen_remaining -= 1; 428 buflen_remaining -= addrstr_len;
437 } 429 }
438 strncat(buf, addrstr, buflen_remaining); 430
439 buflen_remaining -= addrstr_len; 431 res = res->ai_next;
440 } 432 }
441 433
442 res = res->ai_next; 434 freeaddrinfo(result);
443 } 435
444 436 return 0;
445 freeaddrinfo(result);
446
447 return 0;
448} 437}
449 438
450static void 439static void cleanup(void) {
451cleanup (void) 440 if (status_line_initialized)
452{ 441 curlhelp_free_statusline(&status_line);
453 if (status_line_initialized) curlhelp_free_statusline(&status_line); 442 status_line_initialized = false;
454 status_line_initialized = false; 443 if (curl_easy_initialized)
455 if (curl_easy_initialized) curl_easy_cleanup (curl); 444 curl_easy_cleanup(curl);
456 curl_easy_initialized = false; 445 curl_easy_initialized = false;
457 if (curl_global_initialized) curl_global_cleanup (); 446 if (curl_global_initialized)
458 curl_global_initialized = false; 447 curl_global_cleanup();
459 if (body_buf_initialized) curlhelp_freewritebuffer (&body_buf); 448 curl_global_initialized = false;
460 body_buf_initialized = false; 449 if (body_buf_initialized)
461 if (header_buf_initialized) curlhelp_freewritebuffer (&header_buf); 450 curlhelp_freewritebuffer(&body_buf);
462 header_buf_initialized = false; 451 body_buf_initialized = false;
463 if (put_buf_initialized) curlhelp_freereadbuffer (&put_buf); 452 if (header_buf_initialized)
464 put_buf_initialized = false; 453 curlhelp_freewritebuffer(&header_buf);
454 header_buf_initialized = false;
455 if (put_buf_initialized)
456 curlhelp_freereadbuffer(&put_buf);
457 put_buf_initialized = false;
465} 458}
466 459
467int 460int check_http(void) {
468check_http (void) 461 int result = STATE_OK;
469{ 462 int result_ssl = STATE_OK;
470 int result = STATE_OK; 463 int page_len = 0;
471 int result_ssl = STATE_OK; 464 int i;
472 int page_len = 0; 465 char *force_host_header = NULL;
473 int i; 466 struct curl_slist *host = NULL;
474 char *force_host_header = NULL; 467 char addrstr[DEFAULT_BUFFER_SIZE / 2];
475 struct curl_slist *host = NULL; 468 char dnscache[DEFAULT_BUFFER_SIZE];
476 char addrstr[DEFAULT_BUFFER_SIZE/2]; 469
477 char dnscache[DEFAULT_BUFFER_SIZE]; 470 /* initialize curl */
478 471 if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
479 /* initialize curl */ 472 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n");
480 if (curl_global_init (CURL_GLOBAL_DEFAULT) != CURLE_OK) 473 curl_global_initialized = true;
481 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_global_init failed\n"); 474
482 curl_global_initialized = true; 475 if ((curl = curl_easy_init()) == NULL) {
483 476 die(STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n");
484 if ((curl = curl_easy_init()) == NULL) { 477 }
485 die (STATE_UNKNOWN, "HTTP UNKNOWN - curl_easy_init failed\n"); 478 curl_easy_initialized = true;
486 } 479
487 curl_easy_initialized = true; 480 /* register cleanup function to shut down libcurl properly */
488 481 atexit(cleanup);
489 /* register cleanup function to shut down libcurl properly */ 482
490 atexit (cleanup); 483 if (verbose >= 1)
491 484 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE");
492 if (verbose >= 1) 485
493 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_VERBOSE, 1), "CURLOPT_VERBOSE"); 486 /* print everything on stdout like check_http would do */
494 487 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR");
495 /* print everything on stdout like check_http would do */ 488
496 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_STDERR, stdout), "CURLOPT_STDERR"); 489 if (automatic_decompression)
497
498 if (automatic_decompression)
499#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) 490#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
500 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING"); 491 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""), "CURLOPT_ACCEPT_ENCODING");
501#else 492#else
502 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING"); 493 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ENCODING, ""), "CURLOPT_ENCODING");
503#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */ 494#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6) */
504 495
505 /* initialize buffer for body of the answer */ 496 /* initialize buffer for body of the answer */
506 if (curlhelp_initwritebuffer(&body_buf) < 0) 497 if (curlhelp_initwritebuffer(&body_buf) < 0)
507 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n"); 498 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for body\n");
508 body_buf_initialized = true; 499 body_buf_initialized = true;
509 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_WRITEFUNCTION"); 500 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
510 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA"); 501 "CURLOPT_WRITEFUNCTION");
511 502 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&body_buf), "CURLOPT_WRITEDATA");
512 /* initialize buffer for header of the answer */ 503
513 if (curlhelp_initwritebuffer( &header_buf ) < 0) 504 /* initialize buffer for header of the answer */
514 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n" ); 505 if (curlhelp_initwritebuffer(&header_buf) < 0)
515 header_buf_initialized = true; 506 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating buffer for header\n");
516 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback), "CURLOPT_HEADERFUNCTION"); 507 header_buf_initialized = true;
517 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER"); 508 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)curlhelp_buffer_write_callback),
518 509 "CURLOPT_HEADERFUNCTION");
519 /* set the error buffer */ 510 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *)&header_buf), "CURLOPT_WRITEHEADER");
520 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER"); 511
521 512 /* set the error buffer */
522 /* set timeouts */ 513 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf), "CURLOPT_ERRORBUFFER");
523 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT"); 514
524 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT"); 515 /* set timeouts */
525 516 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, socket_timeout), "CURLOPT_CONNECTTIMEOUT");
526 /* enable haproxy protocol */ 517 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_TIMEOUT, socket_timeout), "CURLOPT_TIMEOUT");
527 if (haproxy_protocol) { 518
528 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL"); 519 /* enable haproxy protocol */
529 } 520 if (haproxy_protocol) {
530 521 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HAPROXYPROTOCOL, 1L), "CURLOPT_HAPROXYPROTOCOL");
531 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we use the host_name later on to make SNI happy 522 }
532 if(use_ssl && host_name != NULL) { 523
533 if ( (res=lookup_host (server_address, addrstr, DEFAULT_BUFFER_SIZE/2)) != 0) { 524 // fill dns resolve cache to make curl connect to the given server_address instead of the host_name, only required for ssl, because we
534 snprintf (msg, 525 // use the host_name later on to make SNI happy
535 DEFAULT_BUFFER_SIZE, 526 if (use_ssl && host_name != NULL) {
536 _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), 527 if ((res = lookup_host(server_address, addrstr, DEFAULT_BUFFER_SIZE / 2)) != 0) {
537 server_address, 528 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), server_address, res,
538 res, 529 gai_strerror(res));
539 gai_strerror (res)); 530 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
540 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 531 }
541 } 532 snprintf(dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr);
542 snprintf (dnscache, DEFAULT_BUFFER_SIZE, "%s:%d:%s", host_name, server_port, addrstr); 533 host = curl_slist_append(NULL, dnscache);
543 host = curl_slist_append(NULL, dnscache); 534 curl_easy_setopt(curl, CURLOPT_RESOLVE, host);
544 curl_easy_setopt(curl, CURLOPT_RESOLVE, host); 535 if (verbose >= 1)
545 if (verbose>=1) 536 printf("* curl CURLOPT_RESOLVE: %s\n", dnscache);
546 printf ("* curl CURLOPT_RESOLVE: %s\n", dnscache); 537 }
547 } 538
548 539 // If server_address is an IPv6 address it must be surround by square brackets
549 // If server_address is an IPv6 address it must be surround by square brackets 540 struct in6_addr tmp_in_addr;
550 struct in6_addr tmp_in_addr; 541 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) {
551 if (inet_pton(AF_INET6, server_address, &tmp_in_addr) == 1) { 542 char *new_server_address = malloc(strlen(server_address) + 3);
552 char *new_server_address = malloc(strlen(server_address) + 3); 543 if (new_server_address == NULL) {
553 if (new_server_address == NULL) { 544 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n");
554 die(STATE_UNKNOWN, "HTTP UNKNOWN - Unable to allocate memory\n"); 545 }
555 } 546 snprintf(new_server_address, strlen(server_address) + 3, "[%s]", server_address);
556 snprintf(new_server_address, strlen(server_address)+3, "[%s]", server_address); 547 free(server_address);
557 free(server_address); 548 server_address = new_server_address;
558 server_address = new_server_address; 549 }
559 } 550
560 551 /* compose URL: use the address we want to connect to, set Host: header later */
561 /* compose URL: use the address we want to connect to, set Host: header later */ 552 snprintf(url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", use_ssl ? "https" : "http",
562 snprintf (url, DEFAULT_BUFFER_SIZE, "%s://%s:%d%s", 553 (use_ssl & (host_name != NULL)) ? host_name : server_address, server_port, server_url);
563 use_ssl ? "https" : "http", 554
564 ( use_ssl & ( host_name != NULL ) ) ? host_name : server_address, 555 if (verbose >= 1)
565 server_port, 556 printf("* curl CURLOPT_URL: %s\n", url);
566 server_url 557 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, url), "CURLOPT_URL");
567 ); 558
568 559 /* extract proxy information for legacy proxy https requests */
569 if (verbose>=1) 560 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) {
570 printf ("* curl CURLOPT_URL: %s\n", url); 561 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY");
571 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, url), "CURLOPT_URL"); 562 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT");
572 563 if (verbose >= 2)
573 /* extract proxy information for legacy proxy https requests */ 564 printf("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port);
574 if (!strcmp(http_method, "CONNECT") || strstr(server_url, "http") == server_url) { 565 http_method = "GET";
575 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXY, server_address), "CURLOPT_PROXY"); 566 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_URL, server_url), "CURLOPT_URL");
576 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYPORT, (long)server_port), "CURLOPT_PROXYPORT"); 567 }
577 if (verbose>=2) 568
578 printf ("* curl CURLOPT_PROXY: %s:%d\n", server_address, server_port); 569 /* disable body for HEAD request */
579 http_method = "GET"; 570 if (http_method && !strcmp(http_method, "HEAD")) {
580 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_URL, server_url), "CURLOPT_URL"); 571 no_body = true;
581 } 572 }
582 573
583 /* disable body for HEAD request */ 574 /* set HTTP protocol version */
584 if (http_method && !strcmp (http_method, "HEAD" )) { 575 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION");
585 no_body = true; 576
586 } 577 /* set HTTP method */
587 578 if (http_method) {
588 /* set HTTP protocol version */ 579 if (!strcmp(http_method, "POST"))
589 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_HTTP_VERSION, curl_http_version), "CURLOPT_HTTP_VERSION"); 580 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POST, 1), "CURLOPT_POST");
590 581 else if (!strcmp(http_method, "PUT"))
591 /* set HTTP method */ 582 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD");
592 if (http_method) { 583 else
593 if (!strcmp(http_method, "POST")) 584 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST");
594 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POST, 1), "CURLOPT_POST"); 585 }
595 else if (!strcmp(http_method, "PUT")) 586
596 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); 587 /* check if Host header is explicitly set in options */
597 else 588 if (http_opt_headers_count) {
598 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CUSTOMREQUEST, http_method), "CURLOPT_CUSTOMREQUEST"); 589 for (i = 0; i < http_opt_headers_count; i++) {
599 } 590 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) {
600 591 force_host_header = http_opt_headers[i];
601 /* check if Host header is explicitly set in options */ 592 }
602 if (http_opt_headers_count) { 593 }
603 for (i = 0; i < http_opt_headers_count ; i++) { 594 }
604 if (strncmp(http_opt_headers[i], "Host:", 5) == 0) { 595
605 force_host_header = http_opt_headers[i]; 596 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */
606 } 597 if (host_name != NULL && force_host_header == NULL) {
607 } 598 if ((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) {
608 } 599 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port);
609 600 } else {
610 /* set hostname (virtual hosts), not needed if CURLOPT_CONNECT_TO is used, but left in anyway */ 601 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name);
611 if(host_name != NULL && force_host_header == NULL) { 602 }
612 if((virtual_port != HTTP_PORT && !use_ssl) || (virtual_port != HTTPS_PORT && use_ssl)) { 603 header_list = curl_slist_append(header_list, http_header);
613 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s:%d", host_name, virtual_port); 604 }
614 } else { 605
615 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Host: %s", host_name); 606 /* always close connection, be nice to servers */
616 } 607 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Connection: close");
617 header_list = curl_slist_append (header_list, http_header); 608 header_list = curl_slist_append(header_list, http_header);
618 } 609
619 610 /* attach additional headers supplied by the user */
620 /* always close connection, be nice to servers */ 611 /* optionally send any other header tag */
621 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Connection: close"); 612 if (http_opt_headers_count) {
622 header_list = curl_slist_append (header_list, http_header); 613 for (i = 0; i < http_opt_headers_count; i++) {
623 614 header_list = curl_slist_append(header_list, http_opt_headers[i]);
624 /* attach additional headers supplied by the user */ 615 }
625 /* optionally send any other header tag */ 616 /* This cannot be free'd here because a redirection will then try to access this and segfault */
626 if (http_opt_headers_count) { 617 /* Covered in a testcase in tests/check_http.t */
627 for (i = 0; i < http_opt_headers_count ; i++) { 618 /* free(http_opt_headers); */
628 header_list = curl_slist_append (header_list, http_opt_headers[i]); 619 }
629 } 620
630 /* This cannot be free'd here because a redirection will then try to access this and segfault */ 621 /* set HTTP headers */
631 /* Covered in a testcase in tests/check_http.t */ 622 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list), "CURLOPT_HTTPHEADER");
632 /* free(http_opt_headers); */
633 }
634
635 /* set HTTP headers */
636 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER");
637 623
638#ifdef LIBCURL_FEATURE_SSL 624#ifdef LIBCURL_FEATURE_SSL
639 625
640 /* set SSL version, warn about insecure or unsupported versions */ 626 /* set SSL version, warn about insecure or unsupported versions */
641 if (use_ssl) { 627 if (use_ssl) {
642 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); 628 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION");
643 } 629 }
644 630
645 /* client certificate and key to present to server (SSL) */ 631 /* client certificate and key to present to server (SSL) */
646 if (client_cert) 632 if (client_cert)
647 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT"); 633 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLCERT, client_cert), "CURLOPT_SSLCERT");
648 if (client_privkey) 634 if (client_privkey)
649 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY"); 635 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSLKEY, client_privkey), "CURLOPT_SSLKEY");
650 if (ca_cert) { 636 if (ca_cert) {
651 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); 637 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO");
652 } 638 }
653 if (ca_cert || verify_peer_and_host) { 639 if (ca_cert || verify_peer_and_host) {
654 /* per default if we have a CA verify both the peer and the 640 /* per default if we have a CA verify both the peer and the
655 * hostname in the certificate, can be switched off later */ 641 * hostname in the certificate, can be switched off later */
656 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER"); 642 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER");
657 handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST"); 643 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST");
658 } else { 644 } else {
659 /* backward-compatible behaviour, be tolerant in checks 645 /* backward-compatible behaviour, be tolerant in checks
660 * TODO: depending on more options have aspects we want 646 * TODO: depending on more options have aspects we want
661 * to be less tolerant about ssl verfications 647 * to be less tolerant about ssl verfications
662 */ 648 */
663 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER"); 649 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER");
664 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST"); 650 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST");
665 } 651 }
666 652
667 /* detect SSL library used by libcurl */ 653 /* detect SSL library used by libcurl */
668 ssl_library = curlhelp_get_ssl_library (); 654 ssl_library = curlhelp_get_ssl_library();
669 655
670 /* try hard to get a stack of certificates to verify against */ 656 /* try hard to get a stack of certificates to verify against */
671 if (check_cert) { 657 if (check_cert) {
672#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) 658# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1)
673 /* inform curl to report back certificates */ 659 /* inform curl to report back certificates */
674 switch (ssl_library) { 660 switch (ssl_library) {
675 case CURLHELP_SSL_LIBRARY_OPENSSL: 661 case CURLHELP_SSL_LIBRARY_OPENSSL:
676 case CURLHELP_SSL_LIBRARY_LIBRESSL: 662 case CURLHELP_SSL_LIBRARY_LIBRESSL:
677 /* set callback to extract certificate with OpenSSL context function (works with 663 /* set callback to extract certificate with OpenSSL context function (works with
678 * OpenSSL-style libraries only!) */ 664 * OpenSSL-style libraries only!) */
679#ifdef USE_OPENSSL 665# ifdef USE_OPENSSL
680 /* libcurl and monitoring plugins built with OpenSSL, good */ 666 /* libcurl and monitoring plugins built with OpenSSL, good */
681 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 667 add_sslctx_verify_fun = true;
682 is_openssl_callback = true; 668 is_openssl_callback = true;
683#else /* USE_OPENSSL */ 669# endif /* USE_OPENSSL */
684#endif /* USE_OPENSSL */ 670 /* libcurl is built with OpenSSL, monitoring plugins, so falling
685 /* libcurl is built with OpenSSL, monitoring plugins, so falling 671 * back to manually extracting certificate information */
686 * back to manually extracting certificate information */ 672 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
687 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 673 break;
688 break; 674
689 675 case CURLHELP_SSL_LIBRARY_NSS:
690 case CURLHELP_SSL_LIBRARY_NSS: 676# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
691#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 677 /* NSS: support for CERTINFO is implemented since 7.34.0 */
692 /* NSS: support for CERTINFO is implemented since 7.34.0 */ 678 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
693 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 679# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
694#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 680 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n",
695 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library)); 681 curlhelp_get_ssl_library_string(ssl_library));
696#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 682# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
697 break; 683 break;
698 684
699 case CURLHELP_SSL_LIBRARY_GNUTLS: 685 case CURLHELP_SSL_LIBRARY_GNUTLS:
700#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) 686# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
701 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */ 687 /* GnuTLS: support for CERTINFO is implemented since 7.42.0 */
702 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO"); 688 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L), "CURLOPT_CERTINFO");
703#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ 689# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
704 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n", curlhelp_get_ssl_library_string (ssl_library)); 690 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (libcurl linked with SSL library '%s' is too old)\n",
705#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */ 691 curlhelp_get_ssl_library_string(ssl_library));
706 break; 692# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0) */
707 693 break;
708 case CURLHELP_SSL_LIBRARY_UNKNOWN: 694
709 default: 695 case CURLHELP_SSL_LIBRARY_UNKNOWN:
710 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n", curlhelp_get_ssl_library_string (ssl_library)); 696 default:
711 break; 697 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (unknown SSL library '%s', must implement first)\n",
712 } 698 curlhelp_get_ssl_library_string(ssl_library));
713#else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 699 break;
714 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */ 700 }
715 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL) 701# else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
716 handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); 702 /* old libcurl, our only hope is OpenSSL, otherwise we are out of luck */
717 else 703 if (ssl_library == CURLHELP_SSL_LIBRARY_OPENSSL || ssl_library == CURLHELP_SSL_LIBRARY_LIBRESSL)
718 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl too old and has no CURLOPT_CERTINFO)\n"); 704 add_sslctx_verify_fun = true;
719#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ 705 else
720 } 706 die(STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library or libcurl "
707 "too old and has no CURLOPT_CERTINFO)\n");
708# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */
709 }
710
711# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 10, 6) /* required for CURLOPT_SSL_CTX_FUNCTION */
712 // ssl ctx function is not available with all ssl backends
713 if (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, NULL) != CURLE_UNKNOWN_OPTION)
714 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION");
715# endif
721 716
722#endif /* LIBCURL_FEATURE_SSL */ 717#endif /* LIBCURL_FEATURE_SSL */
723 718
724 /* set default or user-given user agent identification */ 719 /* set default or user-given user agent identification */
725 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); 720 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT");
726 721
727 /* proxy-authentication */ 722 /* proxy-authentication */
728 if (strcmp(proxy_auth, "")) 723 if (strcmp(proxy_auth, ""))
729 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD"); 724 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxy_auth), "CURLOPT_PROXYUSERPWD");
730 725
731 /* authentication */ 726 /* authentication */
732 if (strcmp(user_auth, "")) 727 if (strcmp(user_auth, ""))
733 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD"); 728 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_USERPWD, user_auth), "CURLOPT_USERPWD");
734 729
735 /* TODO: parameter auth method, bitfield of following methods: 730 /* TODO: parameter auth method, bitfield of following methods:
736 * CURLAUTH_BASIC (default) 731 * CURLAUTH_BASIC (default)
737 * CURLAUTH_DIGEST 732 * CURLAUTH_DIGEST
738 * CURLAUTH_DIGEST_IE 733 * CURLAUTH_DIGEST_IE
739 * CURLAUTH_NEGOTIATE 734 * CURLAUTH_NEGOTIATE
740 * CURLAUTH_NTLM 735 * CURLAUTH_NTLM
741 * CURLAUTH_NTLM_WB 736 * CURLAUTH_NTLM_WB
742 * 737 *
743 * convenience tokens for typical sets of methods: 738 * convenience tokens for typical sets of methods:
744 * CURLAUTH_ANYSAFE: most secure, without BASIC 739 * CURLAUTH_ANYSAFE: most secure, without BASIC
745 * or CURLAUTH_ANY: most secure, even BASIC if necessary 740 * or CURLAUTH_ANY: most secure, even BASIC if necessary
746 * 741 *
747 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH"); 742 * handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_DIGEST ), "CURLOPT_HTTPAUTH");
748 */ 743 */
749 744
750 /* handle redirections */ 745 /* handle redirections */
751 if (onredirect == STATE_DEPENDENT) { 746 if (onredirect == STATE_DEPENDENT) {
752 if( followmethod == FOLLOW_LIBCURL ) { 747 if (followmethod == FOLLOW_LIBCURL) {
753 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION"); 748 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1), "CURLOPT_FOLLOWLOCATION");
754 749
755 /* default -1 is infinite, not good, could lead to zombie plugins! 750 /* default -1 is infinite, not good, could lead to zombie plugins!
756 Setting it to one bigger than maximal limit to handle errors nicely below 751 Setting it to one bigger than maximal limit to handle errors nicely below
757 */ 752 */
758 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_MAXREDIRS, max_depth+1), "CURLOPT_MAXREDIRS"); 753 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_MAXREDIRS, max_depth + 1), "CURLOPT_MAXREDIRS");
759 754
760 /* for now allow only http and https (we are a http(s) check plugin in the end) */ 755 /* for now allow only http and https (we are a http(s) check plugin in the end) */
761#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0) 756#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 85, 0)
762 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"), "CURLOPT_REDIR_PROTOCOLS_STR"); 757 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https"),
758 "CURLOPT_REDIR_PROTOCOLS_STR");
763#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4) 759#elif LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 4)
764 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS), "CURLOPT_REDIRECT_PROTOCOLS"); 760 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS),
761 "CURLOPT_REDIRECT_PROTOCOLS");
765#endif 762#endif
766 763
767 /* TODO: handle the following aspects of redirection, make them 764 /* TODO: handle the following aspects of redirection, make them
768 * command line options too later: 765 * command line options too later:
769 CURLOPT_POSTREDIR: method switch 766 CURLOPT_POSTREDIR: method switch
770 CURLINFO_REDIRECT_URL: custom redirect option 767 CURLINFO_REDIRECT_URL: custom redirect option
771 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols 768 CURLOPT_REDIRECT_PROTOCOLS: allow people to step outside safe protocols
772 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size? 769 CURLINFO_REDIRECT_COUNT: get the number of redirects, print it, maybe a range option here is nice like for expected page size?
773 */ 770 */
774 } else { 771 } else {
775 /* old style redirection is handled below */ 772 /* old style redirection is handled below */
776 } 773 }
777 } 774 }
778 775
779 /* no-body */ 776 /* no-body */
780 if (no_body) 777 if (no_body)
781 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY"); 778 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_NOBODY, 1), "CURLOPT_NOBODY");
782 779
783 /* IPv4 or IPv6 forced DNS resolution */ 780 /* IPv4 or IPv6 forced DNS resolution */
784 if (address_family == AF_UNSPEC) 781 if (address_family == AF_UNSPEC)
785 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); 782 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER),
786 else if (address_family == AF_INET) 783 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)");
787 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); 784 else if (address_family == AF_INET)
788#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6) 785 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4),
789 else if (address_family == AF_INET6) 786 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)");
790 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); 787#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
788 else if (address_family == AF_INET6)
789 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6),
790 "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)");
791#endif 791#endif
792 792
793 /* either send http POST data (any data, not only POST)*/ 793 /* either send http POST data (any data, not only POST)*/
794 if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) { 794 if (!strcmp(http_method, "POST") || !strcmp(http_method, "PUT")) {
795 /* set content of payload for POST and PUT */ 795 /* set content of payload for POST and PUT */
796 if (http_content_type) { 796 if (http_content_type) {
797 snprintf (http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type); 797 snprintf(http_header, DEFAULT_BUFFER_SIZE, "Content-Type: %s", http_content_type);
798 header_list = curl_slist_append (header_list, http_header); 798 header_list = curl_slist_append(header_list, http_header);
799 } 799 }
800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string 800 /* NULL indicates "HTTP Continue" in libcurl, provide an empty string
801 * in case of no POST/PUT data */ 801 * in case of no POST/PUT data */
802 if (!http_post_data) 802 if (!http_post_data)
803 http_post_data = ""; 803 http_post_data = "";
804 if (!strcmp(http_method, "POST")) { 804 if (!strcmp(http_method, "POST")) {
805 /* POST method, set payload with CURLOPT_POSTFIELDS */ 805 /* POST method, set payload with CURLOPT_POSTFIELDS */
806 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS"); 806 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, http_post_data), "CURLOPT_POSTFIELDS");
807 } else if (!strcmp(http_method, "PUT")) { 807 } else if (!strcmp(http_method, "PUT")) {
808 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback), "CURLOPT_READFUNCTION"); 808 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)curlhelp_buffer_read_callback),
809 if (curlhelp_initreadbuffer (&put_buf, http_post_data, strlen (http_post_data)) < 0) 809 "CURLOPT_READFUNCTION");
810 die (STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n"); 810 if (curlhelp_initreadbuffer(&put_buf, http_post_data, strlen(http_post_data)) < 0)
811 put_buf_initialized = true; 811 die(STATE_UNKNOWN, "HTTP CRITICAL - out of memory allocating read buffer for PUT\n");
812 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA"); 812 put_buf_initialized = true;
813 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_INFILESIZE, (curl_off_t)strlen (http_post_data)), "CURLOPT_INFILESIZE"); 813 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_READDATA, (void *)&put_buf), "CURLOPT_READDATA");
814 } 814 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_INFILESIZE, (curl_off_t)strlen(http_post_data)),
815 } 815 "CURLOPT_INFILESIZE");
816 816 }
817 /* cookie handling */ 817 }
818 if (cookie_jar_file != NULL) { 818
819 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR"); 819 /* cookie handling */
820 handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE"); 820 if (cookie_jar_file != NULL) {
821 } 821 /* enable reading cookies from a file, and if the filename is an empty string, only enable the curl cookie engine */
822 822 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_jar_file), "CURLOPT_COOKIEFILE");
823 /* do the request */ 823 /* now enable saving cookies to a file, but only if the filename is not an empty string, since writing it would fail */
824 res = curl_easy_perform(curl); 824 if (*cookie_jar_file)
825 825 handle_curl_option_return_code(curl_easy_setopt(curl, CURLOPT_COOKIEJAR, cookie_jar_file), "CURLOPT_COOKIEJAR");
826 if (verbose>=2 && http_post_data) 826 }
827 printf ("**** REQUEST CONTENT ****\n%s\n", http_post_data); 827
828 828 /* do the request */
829 /* free header and server IP resolve lists, we don't need it anymore */ 829 res = curl_easy_perform(curl);
830 curl_slist_free_all (header_list); header_list = NULL; 830
831 curl_slist_free_all (server_ips); server_ips = NULL; 831 if (verbose >= 2 && http_post_data)
832 if (host) { 832 printf("**** REQUEST CONTENT ****\n%s\n", http_post_data);
833 curl_slist_free_all (host); host = NULL; 833
834 } 834 /* free header and server IP resolve lists, we don't need it anymore */
835 835 curl_slist_free_all(header_list);
836 /* Curl errors, result in critical Nagios state */ 836 header_list = NULL;
837 if (res != CURLE_OK) { 837 curl_slist_free_all(server_ips);
838 snprintf (msg, 838 server_ips = NULL;
839 DEFAULT_BUFFER_SIZE, 839 if (host) {
840 _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), 840 curl_slist_free_all(host);
841 server_port, 841 host = NULL;
842 res, 842 }
843 errbuf[0] ? errbuf : curl_easy_strerror(res)); 843
844 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 844 /* Curl errors, result in critical Nagios state */
845 } 845 if (res != CURLE_OK) {
846 846 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: cURL returned %d - %s"), server_port,
847 /* certificate checks */ 847 res, errbuf[0] ? errbuf : curl_easy_strerror(res));
848 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
849 }
850
851 /* certificate checks */
848#ifdef LIBCURL_FEATURE_SSL 852#ifdef LIBCURL_FEATURE_SSL
849 if (use_ssl) { 853 if (use_ssl) {
850 if (check_cert) { 854 if (check_cert) {
851 if (is_openssl_callback) { 855 if (is_openssl_callback) {
852#ifdef USE_OPENSSL 856# ifdef USE_OPENSSL
853 /* check certificate with OpenSSL functions, curl has been built against OpenSSL 857 /* check certificate with OpenSSL functions, curl has been built against OpenSSL
854 * and we actually have OpenSSL in the monitoring tools 858 * and we actually have OpenSSL in the monitoring tools
855 */ 859 */
856 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 860 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
857 if (!continue_after_check_cert) { 861 if (!continue_after_check_cert) {
858 return result_ssl; 862 return result_ssl;
859 } 863 }
860#else /* USE_OPENSSL */ 864# else /* USE_OPENSSL */
861 die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n"); 865 die(STATE_CRITICAL,
862#endif /* USE_OPENSSL */ 866 "HTTP CRITICAL - Cannot retrieve certificates - OpenSSL callback used and not linked against OpenSSL\n");
863 } else { 867# endif /* USE_OPENSSL */
864 int i; 868 } else {
865 struct curl_slist *slist; 869 int i;
866 870 struct curl_slist *slist;
867 cert_ptr.to_info = NULL; 871
868 res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info); 872 cert_ptr.to_info = NULL;
869 if (!res && cert_ptr.to_info) { 873 res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info);
870#ifdef USE_OPENSSL 874 if (!res && cert_ptr.to_info) {
871 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing 875# ifdef USE_OPENSSL
872 * We only check the first certificate and assume it's the one of the server 876 /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert parsing
873 */ 877 * We only check the first certificate and assume it's the one of the server
874 const char* raw_cert = NULL; 878 */
875 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { 879 const char *raw_cert = NULL;
876 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) { 880 for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) {
877 if (verbose >= 2) 881 for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) {
878 printf ("%d ** %s\n", i, slist->data); 882 if (verbose >= 2)
879 if (strncmp (slist->data, "Cert:", 5) == 0) { 883 printf("%d ** %s\n", i, slist->data);
880 raw_cert = &slist->data[5]; 884 if (strncmp(slist->data, "Cert:", 5) == 0) {
881 goto GOT_FIRST_CERT; 885 raw_cert = &slist->data[5];
882 } 886 goto GOT_FIRST_CERT;
883 } 887 }
884 } 888 }
885GOT_FIRST_CERT: 889 }
886 if (!raw_cert) { 890 GOT_FIRST_CERT:
887 snprintf (msg, 891 if (!raw_cert) {
888 DEFAULT_BUFFER_SIZE, 892 snprintf(msg, DEFAULT_BUFFER_SIZE,
889 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty")); 893 _("Cannot retrieve certificates from CERTINFO information - certificate data was empty"));
890 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 894 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
891 } 895 }
892 BIO* cert_BIO = BIO_new (BIO_s_mem()); 896 BIO *cert_BIO = BIO_new(BIO_s_mem());
893 BIO_write (cert_BIO, raw_cert, strlen(raw_cert)); 897 BIO_write(cert_BIO, raw_cert, strlen(raw_cert));
894 cert = PEM_read_bio_X509 (cert_BIO, NULL, NULL, NULL); 898 cert = PEM_read_bio_X509(cert_BIO, NULL, NULL, NULL);
895 if (!cert) { 899 if (!cert) {
896 snprintf (msg, 900 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot read certificate from CERTINFO information - BIO error"));
897 DEFAULT_BUFFER_SIZE, 901 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
898 _("Cannot read certificate from CERTINFO information - BIO error")); 902 }
899 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); 903 BIO_free(cert_BIO);
900 } 904 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit);
901 BIO_free (cert_BIO); 905 if (!continue_after_check_cert) {
902 result_ssl = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); 906 return result_ssl;
903 if (!continue_after_check_cert) { 907 }
904 return result_ssl; 908# else /* USE_OPENSSL */
905 } 909 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal,
906#else /* USE_OPENSSL */ 910 * so we use the libcurl CURLINFO data
907 /* We assume we don't have OpenSSL and np_net_ssl_check_certificate at our disposal, 911 */
908 * so we use the libcurl CURLINFO data 912 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit);
909 */ 913 if (!continue_after_check_cert) {
910 result_ssl = net_noopenssl_check_certificate(&cert_ptr, days_till_exp_warn, days_till_exp_crit); 914 return result_ssl;
911 if (!continue_after_check_cert) { 915 }
912 return result_ssl; 916# endif /* USE_OPENSSL */
913 } 917 } else {
914#endif /* USE_OPENSSL */ 918 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), res,
915 } else { 919 curl_easy_strerror(res));
916 snprintf (msg, 920 die(STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
917 DEFAULT_BUFFER_SIZE, 921 }
918 _("Cannot retrieve certificates - cURL returned %d - %s"), 922 }
919 res, 923 }
920 curl_easy_strerror(res)); 924 }
921 die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg);
922 }
923 }
924 }
925 }
926#endif /* LIBCURL_FEATURE_SSL */ 925#endif /* LIBCURL_FEATURE_SSL */
927 926
928 /* we got the data and we executed the request in a given time, so we can append 927 /* we got the data and we executed the request in a given time, so we can append
929 * performance data to the answer always 928 * performance data to the answer always
930 */ 929 */
931 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME"); 930 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time), "CURLINFO_TOTAL_TIME");
932 page_len = get_content_length(&header_buf, &body_buf); 931 page_len = get_content_length(&header_buf, &body_buf);
933 if(show_extended_perfdata) { 932 if (show_extended_perfdata) {
934 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME"); 933 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &time_connect), "CURLINFO_CONNECT_TIME");
935 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME"); 934 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME, &time_appconnect), "CURLINFO_APPCONNECT_TIME");
936 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME"); 935 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME, &time_headers), "CURLINFO_PRETRANSFER_TIME");
937 handle_curl_option_return_code (curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte), "CURLINFO_STARTTRANSFER_TIME"); 936 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME, &time_firstbyte),
938 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", 937 "CURLINFO_STARTTRANSFER_TIME");
939 perfd_time(total_time), 938 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s %s %s %s %s %s", perfd_time(total_time), perfd_size(page_len),
940 perfd_size(page_len), 939 perfd_time_connect(time_connect), use_ssl ? perfd_time_ssl(time_appconnect - time_connect) : "",
941 perfd_time_connect(time_connect), 940 perfd_time_headers(time_headers - time_appconnect), perfd_time_firstbyte(time_firstbyte - time_headers),
942 use_ssl ? perfd_time_ssl (time_appconnect-time_connect) : "", 941 perfd_time_transfer(total_time - time_firstbyte));
943 perfd_time_headers(time_headers - time_appconnect), 942 } else {
944 perfd_time_firstbyte(time_firstbyte - time_headers), 943 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s", perfd_time(total_time), perfd_size(page_len));
945 perfd_time_transfer(total_time-time_firstbyte) 944 }
946 );
947 } else {
948 snprintf(perfstring, DEFAULT_BUFFER_SIZE, "%s %s",
949 perfd_time(total_time),
950 perfd_size(page_len)
951 );
952 }
953
954 /* return a CRITICAL status if we couldn't read any data */
955 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
956 die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
957
958 /* get status line of answer, check sanity of HTTP code */
959 if (curlhelp_parse_statusline (header_buf.buf, &status_line) < 0) {
960 snprintf (msg,
961 DEFAULT_BUFFER_SIZE,
962 "Unparsable status line in %.3g seconds response time|%s\n",
963 total_time,
964 perfstring);
965 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
966 die (STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
967 }
968 status_line_initialized = true;
969
970 /* get result code from cURL */
971 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
972 if (verbose>=2)
973 printf ("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
974
975 /* print status line, header, body if verbose */
976 if (verbose >= 2) {
977 printf ("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf,
978 (no_body ? " [[ skipped ]]" : body_buf.buf));
979 }
980
981 /* make sure the status line matches the response we are looking for */
982 if (!expected_statuscode(status_line.first_line, server_expect)) {
983 if (server_port == HTTP_PORT)
984 snprintf(msg,
985 DEFAULT_BUFFER_SIZE,
986 _("Invalid HTTP response received from host: %s\n"),
987 status_line.first_line);
988 else
989 snprintf(msg,
990 DEFAULT_BUFFER_SIZE,
991 _("Invalid HTTP response received from host on port %d: %s\n"),
992 server_port,
993 status_line.first_line);
994 die (STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg,
995 show_body ? "\n" : "",
996 show_body ? body_buf.buf : "");
997 }
998
999 if( server_expect_yn ) {
1000 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
1001 if (verbose)
1002 printf ("%s\n",msg);
1003 result = STATE_OK;
1004 }
1005 else {
1006 /* illegal return codes result in a critical state */
1007 if (code >= 600 || code < 100) {
1008 die (STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
1009 /* server errors result in a critical state */
1010 } else if (code >= 500) {
1011 result = STATE_CRITICAL;
1012 /* client errors result in a warning state */
1013 } else if (code >= 400) {
1014 result = STATE_WARNING;
1015 /* check redirected page if specified */
1016 } else if (code >= 300) {
1017 if (onredirect == STATE_DEPENDENT) {
1018 if( followmethod == FOLLOW_LIBCURL ) {
1019 code = status_line.http_code;
1020 } else {
1021 /* old check_http style redirection, if we come
1022 * back here, we are in the same status as with
1023 * the libcurl method
1024 */
1025 redir (&header_buf);
1026 }
1027 } else {
1028 /* this is a specific code in the command line to
1029 * be returned when a redirection is encountered
1030 */
1031 }
1032 result = max_state_alt (onredirect, result);
1033 /* all other codes are considered ok */
1034 } else {
1035 result = STATE_OK;
1036 }
1037 }
1038
1039 /* libcurl redirection internally, handle error states here */
1040 if( followmethod == FOLLOW_LIBCURL ) {
1041 handle_curl_option_return_code (curl_easy_getinfo (curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1042 if (verbose >= 2)
1043 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1044 if (redir_depth > max_depth) {
1045 snprintf (msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl",
1046 max_depth);
1047 die (STATE_WARNING, "HTTP WARNING - %s", msg);
1048 }
1049 }
1050
1051 /* check status codes, set exit status accordingly */
1052 if( status_line.http_code != code ) {
1053 die (STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1054 string_statuscode (status_line.http_major, status_line.http_minor),
1055 status_line.http_code, status_line.msg, code);
1056 }
1057
1058 if (maximum_age >= 0) {
1059 result = max_state_alt(check_document_dates(&header_buf, &msg), result);
1060 }
1061
1062 /* Page and Header content checks go here */
1063
1064 if (strlen (header_expect)) {
1065 if (!strstr (header_buf.buf, header_expect)) {
1066
1067 strncpy(&output_header_search[0],header_expect,sizeof(output_header_search));
1068
1069 if(output_header_search[sizeof(output_header_search)-1]!='\0') {
1070 bcopy("...",&output_header_search[sizeof(output_header_search)-4],4);
1071 }
1072 945
1073 char tmp[DEFAULT_BUFFER_SIZE]; 946 /* return a CRITICAL status if we couldn't read any data */
947 if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0)
948 die(STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n"));
1074 949
1075 snprintf (tmp, 950 /* get status line of answer, check sanity of HTTP code */
1076 DEFAULT_BUFFER_SIZE, 951 if (curlhelp_parse_statusline(header_buf.buf, &status_line) < 0) {
1077 _("%sheader '%s' not found on '%s://%s:%d%s', "), 952 snprintf(msg, DEFAULT_BUFFER_SIZE, "Unparsable status line in %.3g seconds response time|%s\n", total_time, perfstring);
1078 msg, 953 /* we cannot know the major/minor version here for sure as we cannot parse the first line */
1079 output_header_search, 954 die(STATE_CRITICAL, "HTTP CRITICAL HTTP/x.x %ld unknown - %s", code, msg);
1080 use_ssl ? "https" : "http", 955 }
1081 host_name ? host_name : server_address, 956 status_line_initialized = true;
1082 server_port,
1083 server_url);
1084 957
1085 strcpy(msg, tmp); 958 /* get result code from cURL */
959 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code), "CURLINFO_RESPONSE_CODE");
960 if (verbose >= 2)
961 printf("* curl CURLINFO_RESPONSE_CODE is %ld\n", code);
1086 962
1087 result = STATE_CRITICAL; 963 /* print status line, header, body if verbose */
1088 } 964 if (verbose >= 2) {
1089 } 965 printf("**** HEADER ****\n%s\n**** CONTENT ****\n%s\n", header_buf.buf, (no_body ? " [[ skipped ]]" : body_buf.buf));
966 }
1090 967
1091 if (strlen (string_expect)) { 968 /* make sure the status line matches the response we are looking for */
1092 if (!strstr (body_buf.buf, string_expect)) { 969 if (!expected_statuscode(status_line.first_line, server_expect)) {
970 if (server_port == HTTP_PORT)
971 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host: %s\n"), status_line.first_line);
972 else
973 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Invalid HTTP response received from host on port %d: %s\n"), server_port,
974 status_line.first_line);
975 die(STATE_CRITICAL, "HTTP CRITICAL - %s%s%s", msg, show_body ? "\n" : "", show_body ? body_buf.buf : "");
976 }
1093 977
1094 strncpy(&output_string_search[0],string_expect,sizeof(output_string_search)); 978 if (server_expect_yn) {
979 snprintf(msg, DEFAULT_BUFFER_SIZE, _("Status line output matched \"%s\" - "), server_expect);
980 if (verbose)
981 printf("%s\n", msg);
982 result = STATE_OK;
983 } else {
984 /* illegal return codes result in a critical state */
985 if (code >= 600 || code < 100) {
986 die(STATE_CRITICAL, _("HTTP CRITICAL: Invalid Status (%d, %.40s)\n"), status_line.http_code, status_line.msg);
987 /* server errors result in a critical state */
988 } else if (code >= 500) {
989 result = STATE_CRITICAL;
990 /* client errors result in a warning state */
991 } else if (code >= 400) {
992 result = STATE_WARNING;
993 /* check redirected page if specified */
994 } else if (code >= 300) {
995 if (onredirect == STATE_DEPENDENT) {
996 if (followmethod == FOLLOW_LIBCURL) {
997 code = status_line.http_code;
998 } else {
999 /* old check_http style redirection, if we come
1000 * back here, we are in the same status as with
1001 * the libcurl method
1002 */
1003 redir(&header_buf);
1004 }
1005 } else {
1006 /* this is a specific code in the command line to
1007 * be returned when a redirection is encountered
1008 */
1009 }
1010 result = max_state_alt(onredirect, result);
1011 /* all other codes are considered ok */
1012 } else {
1013 result = STATE_OK;
1014 }
1015 }
1095 1016
1096 if(output_string_search[sizeof(output_string_search)-1]!='\0') { 1017 /* libcurl redirection internally, handle error states here */
1097 bcopy("...",&output_string_search[sizeof(output_string_search)-4],4); 1018 if (followmethod == FOLLOW_LIBCURL) {
1098 } 1019 handle_curl_option_return_code(curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &redir_depth), "CURLINFO_REDIRECT_COUNT");
1020 if (verbose >= 2)
1021 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth);
1022 if (redir_depth > max_depth) {
1023 snprintf(msg, DEFAULT_BUFFER_SIZE, "maximum redirection depth %d exceeded in libcurl", max_depth);
1024 die(STATE_WARNING, "HTTP WARNING - %s", msg);
1025 }
1026 }
1027
1028 /* check status codes, set exit status accordingly */
1029 if (status_line.http_code != code) {
1030 die(STATE_CRITICAL, _("HTTP CRITICAL %s %d %s - different HTTP codes (cUrl has %ld)\n"),
1031 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg, code);
1032 }
1033
1034 if (maximum_age >= 0) {
1035 result = max_state_alt(check_document_dates(&header_buf, &msg), result);
1036 }
1037
1038 /* Page and Header content checks go here */
1039
1040 if (strlen(header_expect)) {
1041 if (!strstr(header_buf.buf, header_expect)) {
1042
1043 strncpy(&output_header_search[0], header_expect, sizeof(output_header_search));
1044
1045 if (output_header_search[sizeof(output_header_search) - 1] != '\0') {
1046 bcopy("...", &output_header_search[sizeof(output_header_search) - 4], 4);
1047 }
1048
1049 char tmp[DEFAULT_BUFFER_SIZE];
1050
1051 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sheader '%s' not found on '%s://%s:%d%s', "), msg, output_header_search,
1052 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1053
1054 strcpy(msg, tmp);
1055
1056 result = STATE_CRITICAL;
1057 }
1058 }
1059
1060 if (strlen(string_expect)) {
1061 if (!strstr(body_buf.buf, string_expect)) {
1062
1063 strncpy(&output_string_search[0], string_expect, sizeof(output_string_search));
1064
1065 if (output_string_search[sizeof(output_string_search) - 1] != '\0') {
1066 bcopy("...", &output_string_search[sizeof(output_string_search) - 4], 4);
1067 }
1099 1068
1100 char tmp[DEFAULT_BUFFER_SIZE]; 1069 char tmp[DEFAULT_BUFFER_SIZE];
1101 1070
1102 snprintf (tmp, 1071 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sstring '%s' not found on '%s://%s:%d%s', "), msg, output_string_search,
1103 DEFAULT_BUFFER_SIZE, 1072 use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port, server_url);
1104 _("%sstring '%s' not found on '%s://%s:%d%s', "),
1105 msg,
1106 output_string_search,
1107 use_ssl ? "https" : "http",
1108 host_name ? host_name : server_address,
1109 server_port,
1110 server_url);
1111 1073
1112 strcpy(msg, tmp); 1074 strcpy(msg, tmp);
1113 1075
1114 result = STATE_CRITICAL; 1076 result = STATE_CRITICAL;
1115 } 1077 }
1116 } 1078 }
1117 1079
1118 if (strlen (regexp)) { 1080 if (strlen(regexp)) {
1119 errcode = regexec (&preg, body_buf.buf, REGS, pmatch, 0); 1081 errcode = regexec(&preg, body_buf.buf, REGS, pmatch, 0);
1120 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) { 1082 if ((errcode == 0 && !invert_regex) || (errcode == REG_NOMATCH && invert_regex)) {
1121 /* OK - No-op to avoid changing the logic around it */ 1083 /* OK - No-op to avoid changing the logic around it */
1122 result = max_state_alt(STATE_OK, result); 1084 result = max_state_alt(STATE_OK, result);
1123 } 1085 } else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1124 else if ((errcode == REG_NOMATCH && !invert_regex) || (errcode == 0 && invert_regex)) {
1125 if (!invert_regex) { 1086 if (!invert_regex) {
1126 char tmp[DEFAULT_BUFFER_SIZE]; 1087 char tmp[DEFAULT_BUFFER_SIZE];
1127 1088
1128 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg); 1089 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern not found, "), msg);
1129 strcpy(msg, tmp); 1090 strcpy(msg, tmp);
1130 1091
1131 } else { 1092 } else {
1132 char tmp[DEFAULT_BUFFER_SIZE]; 1093 char tmp[DEFAULT_BUFFER_SIZE];
1133 1094
1134 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg); 1095 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spattern found, "), msg);
1135 strcpy(msg, tmp); 1096 strcpy(msg, tmp);
1136
1137 } 1097 }
1138 result = state_regex; 1098 result = state_regex;
1139 } else { 1099 } else {
1140 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1100 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1141 1101
1142 char tmp[DEFAULT_BUFFER_SIZE]; 1102 char tmp[DEFAULT_BUFFER_SIZE];
1143 1103
1144 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf); 1104 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sExecute Error: %s, "), msg, errbuf);
1145 strcpy(msg, tmp); 1105 strcpy(msg, tmp);
1146 result = STATE_UNKNOWN; 1106 result = STATE_UNKNOWN;
1147 } 1107 }
1148 } 1108 }
1149 1109
1150 /* make sure the page is of an appropriate size */ 1110 /* make sure the page is of an appropriate size */
1151 if ((max_page_len > 0) && (page_len > max_page_len)) { 1111 if ((max_page_len > 0) && (page_len > max_page_len)) {
1152 char tmp[DEFAULT_BUFFER_SIZE]; 1112 char tmp[DEFAULT_BUFFER_SIZE];
1153 1113
1154 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len); 1114 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too large, "), msg, page_len);
1155 1115
1156 strcpy(msg, tmp); 1116 strcpy(msg, tmp);
1157 1117
@@ -1160,1281 +1120,1233 @@ GOT_FIRST_CERT:
1160 } else if ((min_page_len > 0) && (page_len < min_page_len)) { 1120 } else if ((min_page_len > 0) && (page_len < min_page_len)) {
1161 char tmp[DEFAULT_BUFFER_SIZE]; 1121 char tmp[DEFAULT_BUFFER_SIZE];
1162 1122
1163 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len); 1123 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%spage size %d too small, "), msg, page_len);
1164 strcpy(msg, tmp); 1124 strcpy(msg, tmp);
1165 result = max_state_alt(STATE_WARNING, result); 1125 result = max_state_alt(STATE_WARNING, result);
1166 } 1126 }
1167 1127
1168 /* -w, -c: check warning and critical level */ 1128 /* -w, -c: check warning and critical level */
1169 result = max_state_alt(get_status(total_time, thlds), result); 1129 result = max_state_alt(get_status(total_time, thlds), result);
1170 1130
1171 /* Cut-off trailing characters */ 1131 /* Cut-off trailing characters */
1172 if (strlen(msg) >= 2) { 1132 if (strlen(msg) >= 2) {
1173 if(msg[strlen(msg)-2] == ',') 1133 if (msg[strlen(msg) - 2] == ',')
1174 msg[strlen(msg)-2] = '\0'; 1134 msg[strlen(msg) - 2] = '\0';
1175 else 1135 else
1176 msg[strlen(msg)-3] = '\0'; 1136 msg[strlen(msg) - 3] = '\0';
1177 } 1137 }
1178 1138
1179 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */ 1139 /* TODO: separate _() msg and status code: die (result, "HTTP %s: %s\n", state_text(result), msg); */
1180 die (max_state_alt(result, result_ssl), "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s", 1140 die(max_state_alt(result, result_ssl), "HTTP %s: %s %d %s%s%s - %d bytes in %.3f second response time %s|%s\n%s%s", state_text(result),
1181 state_text(result), string_statuscode (status_line.http_major, status_line.http_minor), 1141 string_statuscode(status_line.http_major, status_line.http_minor), status_line.http_code, status_line.msg,
1182 status_line.http_code, status_line.msg, 1142 strlen(msg) > 0 ? " - " : "", msg, page_len, total_time, (display_html ? "</A>" : ""), perfstring, (show_body ? body_buf.buf : ""),
1183 strlen(msg) > 0 ? " - " : "", 1143 (show_body ? "\n" : ""));
1184 msg, page_len, total_time, 1144
1185 (display_html ? "</A>" : ""), 1145 return max_state_alt(result, result_ssl);
1186 perfstring,
1187 (show_body ? body_buf.buf : ""),
1188 (show_body ? "\n" : "") );
1189
1190 return max_state_alt(result, result_ssl);
1191} 1146}
1192 1147
1193int 1148int uri_strcmp(const UriTextRangeA range, const char *s) {
1194uri_strcmp (const UriTextRangeA range, const char* s) 1149 if (!range.first)
1195{ 1150 return -1;
1196 if (!range.first) return -1; 1151 if ((size_t)(range.afterLast - range.first) < strlen(s))
1197 if ( (size_t)(range.afterLast - range.first) < strlen (s) ) return -1; 1152 return -1;
1198 return strncmp (s, range.first, min( (size_t)(range.afterLast - range.first), strlen (s))); 1153 return strncmp(s, range.first, min((size_t)(range.afterLast - range.first), strlen(s)));
1199} 1154}
1200 1155
1201char* 1156char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
1202uri_string (const UriTextRangeA range, char* buf, size_t buflen) 1157 if (!range.first)
1203{ 1158 return "(null)";
1204 if (!range.first) return "(null)"; 1159 strncpy(buf, range.first, max(buflen - 1, (size_t)(range.afterLast - range.first)));
1205 strncpy (buf, range.first, max (buflen-1, (size_t)(range.afterLast - range.first))); 1160 buf[max(buflen - 1, (size_t)(range.afterLast - range.first))] = '\0';
1206 buf[max (buflen-1, (size_t)(range.afterLast - range.first))] = '\0'; 1161 buf[range.afterLast - range.first] = '\0';
1207 buf[range.afterLast - range.first] = '\0'; 1162 return buf;
1208 return buf;
1209} 1163}
1210 1164
1211void 1165void redir(curlhelp_write_curlbuf *header_buf) {
1212redir (curlhelp_write_curlbuf* header_buf) 1166 char *location = NULL;
1213{ 1167 curlhelp_statusline status_line;
1214 char *location = NULL; 1168 struct phr_header headers[255];
1215 curlhelp_statusline status_line; 1169 size_t nof_headers = 255;
1216 struct phr_header headers[255]; 1170 size_t msglen;
1217 size_t nof_headers = 255; 1171 char buf[DEFAULT_BUFFER_SIZE];
1218 size_t msglen; 1172 char ipstr[INET_ADDR_MAX_SIZE];
1219 char buf[DEFAULT_BUFFER_SIZE]; 1173 int new_port;
1220 char ipstr[INET_ADDR_MAX_SIZE]; 1174 char *new_host;
1221 int new_port; 1175 char *new_url;
1222 char *new_host; 1176
1223 char *new_url; 1177 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
1224 1178 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
1225 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
1226 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
1227 headers, &nof_headers, 0);
1228 1179
1229 if (res == -1) { 1180 if (res == -1) {
1230 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 1181 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
1231 } 1182 }
1232 1183
1233 location = get_header_value (headers, nof_headers, "location"); 1184 location = get_header_value(headers, nof_headers, "location");
1234 1185
1235 if (verbose >= 2) 1186 if (verbose >= 2)
1236 printf(_("* Seen redirect location %s\n"), location); 1187 printf(_("* Seen redirect location %s\n"), location);
1237 1188
1238 if (++redir_depth > max_depth) 1189 if (++redir_depth > max_depth)
1239 die (STATE_WARNING, 1190 die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), max_depth, location,
1240 _("HTTP WARNING - maximum redirection depth %d exceeded - %s%s\n"), 1191 (display_html ? "</A>" : ""));
1241 max_depth, location, (display_html ? "</A>" : "")); 1192
1242 1193 UriParserStateA state;
1243 UriParserStateA state; 1194 UriUriA uri;
1244 UriUriA uri; 1195 state.uri = &uri;
1245 state.uri = &uri; 1196 if (uriParseUriA(&state, location) != URI_SUCCESS) {
1246 if (uriParseUriA (&state, location) != URI_SUCCESS) { 1197 if (state.errorCode == URI_ERROR_SYNTAX) {
1247 if (state.errorCode == URI_ERROR_SYNTAX) { 1198 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), location, (display_html ? "</A>" : ""));
1248 die (STATE_UNKNOWN, 1199 } else if (state.errorCode == URI_ERROR_MALLOC) {
1249 _("HTTP UNKNOWN - Could not parse redirect location '%s'%s\n"), 1200 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n"));
1250 location, (display_html ? "</A>" : "")); 1201 }
1251 } else if (state.errorCode == URI_ERROR_MALLOC) { 1202 }
1252 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Could not allocate URL\n")); 1203
1253 } 1204 if (verbose >= 2) {
1254 } 1205 printf(_("** scheme: %s\n"), uri_string(uri.scheme, buf, DEFAULT_BUFFER_SIZE));
1255 1206 printf(_("** host: %s\n"), uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1256 if (verbose >= 2) { 1207 printf(_("** port: %s\n"), uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1257 printf (_("** scheme: %s\n"), 1208 if (uri.hostData.ip4) {
1258 uri_string (uri.scheme, buf, DEFAULT_BUFFER_SIZE)); 1209 inet_ntop(AF_INET, uri.hostData.ip4->data, ipstr, sizeof(ipstr));
1259 printf (_("** host: %s\n"), 1210 printf(_("** IPv4: %s\n"), ipstr);
1260 uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1211 }
1261 printf (_("** port: %s\n"), 1212 if (uri.hostData.ip6) {
1262 uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1213 inet_ntop(AF_INET, uri.hostData.ip6->data, ipstr, sizeof(ipstr));
1263 if (uri.hostData.ip4) { 1214 printf(_("** IPv6: %s\n"), ipstr);
1264 inet_ntop (AF_INET, uri.hostData.ip4->data, ipstr, sizeof (ipstr)); 1215 }
1265 printf (_("** IPv4: %s\n"), ipstr); 1216 if (uri.pathHead) {
1266 } 1217 printf(_("** path: "));
1267 if (uri.hostData.ip6) { 1218 const UriPathSegmentA *p = uri.pathHead;
1268 inet_ntop (AF_INET, uri.hostData.ip6->data, ipstr, sizeof (ipstr)); 1219 for (; p; p = p->next) {
1269 printf (_("** IPv6: %s\n"), ipstr); 1220 printf("/%s", uri_string(p->text, buf, DEFAULT_BUFFER_SIZE));
1270 } 1221 }
1271 if (uri.pathHead) { 1222 puts("");
1272 printf (_("** path: ")); 1223 }
1273 const UriPathSegmentA* p = uri.pathHead; 1224 if (uri.query.first) {
1274 for (; p; p = p->next) { 1225 printf(_("** query: %s\n"), uri_string(uri.query, buf, DEFAULT_BUFFER_SIZE));
1275 printf ("/%s", uri_string (p->text, buf, DEFAULT_BUFFER_SIZE)); 1226 }
1276 } 1227 if (uri.fragment.first) {
1277 puts (""); 1228 printf(_("** fragment: %s\n"), uri_string(uri.fragment, buf, DEFAULT_BUFFER_SIZE));
1278 } 1229 }
1279 if (uri.query.first) { 1230 }
1280 printf (_("** query: %s\n"), 1231
1281 uri_string (uri.query, buf, DEFAULT_BUFFER_SIZE)); 1232 if (uri.scheme.first) {
1282 } 1233 if (!uri_strcmp(uri.scheme, "https"))
1283 if (uri.fragment.first) { 1234 use_ssl = true;
1284 printf (_("** fragment: %s\n"), 1235 else
1285 uri_string (uri.fragment, buf, DEFAULT_BUFFER_SIZE)); 1236 use_ssl = false;
1286 } 1237 }
1287 } 1238
1288 1239 /* we do a sloppy test here only, because uriparser would have failed
1289 if (uri.scheme.first) { 1240 * above, if the port would be invalid, we just check for MAX_PORT
1290 if (!uri_strcmp (uri.scheme, "https")) 1241 */
1291 use_ssl = true; 1242 if (uri.portText.first) {
1292 else 1243 new_port = atoi(uri_string(uri.portText, buf, DEFAULT_BUFFER_SIZE));
1293 use_ssl = false; 1244 } else {
1294 } 1245 new_port = HTTP_PORT;
1295 1246 if (use_ssl)
1296 /* we do a sloppy test here only, because uriparser would have failed 1247 new_port = HTTPS_PORT;
1297 * above, if the port would be invalid, we just check for MAX_PORT 1248 }
1298 */ 1249 if (new_port > MAX_PORT)
1299 if (uri.portText.first) { 1250 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), MAX_PORT, location, display_html ? "</A>" : "");
1300 new_port = atoi (uri_string (uri.portText, buf, DEFAULT_BUFFER_SIZE)); 1251
1301 } else { 1252 /* by RFC 7231 relative URLs in Location should be taken relative to
1302 new_port = HTTP_PORT; 1253 * the original URL, so we try to form a new absolute URL here
1303 if (use_ssl) 1254 */
1304 new_port = HTTPS_PORT; 1255 if (!uri.scheme.first && !uri.hostText.first) {
1305 } 1256 new_host = strdup(host_name ? host_name : server_address);
1306 if (new_port > MAX_PORT) 1257 new_port = server_port;
1307 die (STATE_UNKNOWN, 1258 if (use_ssl)
1308 _("HTTP UNKNOWN - Redirection to port above %d - %s%s\n"), 1259 uri_string(uri.scheme, "https", DEFAULT_BUFFER_SIZE);
1309 MAX_PORT, location, display_html ? "</A>" : ""); 1260 } else {
1310 1261 new_host = strdup(uri_string(uri.hostText, buf, DEFAULT_BUFFER_SIZE));
1311 /* by RFC 7231 relative URLs in Location should be taken relative to 1262 }
1312 * the original URL, so we try to form a new absolute URL here 1263
1313 */ 1264 /* compose new path */
1314 if (!uri.scheme.first && !uri.hostText.first) { 1265 /* TODO: handle fragments and query part of URL */
1315 new_host = strdup (host_name ? host_name : server_address); 1266 new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
1316 new_port = server_port; 1267 if (uri.pathHead) {
1317 if(use_ssl) 1268 const UriPathSegmentA *p = uri.pathHead;
1318 uri_string (uri.scheme, "https", DEFAULT_BUFFER_SIZE); 1269 for (; p; p = p->next) {
1319 } else { 1270 strncat(new_url, "/", DEFAULT_BUFFER_SIZE);
1320 new_host = strdup (uri_string (uri.hostText, buf, DEFAULT_BUFFER_SIZE)); 1271 strncat(new_url, uri_string(p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE - 1);
1321 } 1272 }
1322 1273 }
1323 /* compose new path */ 1274
1324 /* TODO: handle fragments and query part of URL */ 1275 if (server_port == new_port && !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
1325 new_url = (char *)calloc( 1, DEFAULT_BUFFER_SIZE); 1276 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && !strcmp(server_url, new_url))
1326 if (uri.pathHead) { 1277 die(STATE_CRITICAL, _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), use_ssl ? "https" : "http",
1327 const UriPathSegmentA* p = uri.pathHead; 1278 new_host, new_port, new_url, (display_html ? "</A>" : ""));
1328 for (; p; p = p->next) { 1279
1329 strncat (new_url, "/", DEFAULT_BUFFER_SIZE); 1280 /* set new values for redirected request */
1330 strncat (new_url, uri_string (p->text, buf, DEFAULT_BUFFER_SIZE), DEFAULT_BUFFER_SIZE-1); 1281
1331 } 1282 if (!(followsticky & STICKY_HOST)) {
1332 } 1283 free(server_address);
1333 1284 server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1334 if (server_port==new_port && 1285 }
1335 !strncmp(server_address, new_host, MAX_IPV4_HOSTLENGTH) && 1286 if (!(followsticky & STICKY_PORT)) {
1336 (host_name && !strncmp(host_name, new_host, MAX_IPV4_HOSTLENGTH)) && 1287 server_port = (unsigned short)new_port;
1337 !strcmp(server_url, new_url)) 1288 }
1338 die (STATE_CRITICAL, 1289
1339 _("HTTP CRITICAL - redirection creates an infinite loop - %s://%s:%d%s%s\n"), 1290 free(host_name);
1340 use_ssl ? "https" : "http", new_host, new_port, new_url, (display_html ? "</A>" : "")); 1291 host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH);
1341 1292
1342 /* set new values for redirected request */ 1293 /* reset virtual port */
1343 1294 virtual_port = server_port;
1344 if (!(followsticky & STICKY_HOST)) { 1295
1345 free (server_address); 1296 free(new_host);
1346 server_address = strndup (new_host, MAX_IPV4_HOSTLENGTH); 1297 free(server_url);
1347 } 1298 server_url = new_url;
1348 if (!(followsticky & STICKY_PORT)) { 1299
1349 server_port = (unsigned short)new_port; 1300 uriFreeUriMembersA(&uri);
1350 } 1301
1351 1302 if (verbose)
1352 free (host_name); 1303 printf(_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http", host_name ? host_name : server_address, server_port,
1353 host_name = strndup (new_host, MAX_IPV4_HOSTLENGTH); 1304 server_url);
1354 1305
1355 /* reset virtual port */ 1306 /* TODO: the hash component MUST be taken from the original URL and
1356 virtual_port = server_port; 1307 * attached to the URL in Location
1357 1308 */
1358 free(new_host); 1309
1359 free (server_url); 1310 cleanup();
1360 server_url = new_url; 1311 check_http();
1361
1362 uriFreeUriMembersA (&uri);
1363
1364 if (verbose)
1365 printf (_("Redirection to %s://%s:%d%s\n"), use_ssl ? "https" : "http",
1366 host_name ? host_name : server_address, server_port, server_url);
1367
1368 /* TODO: the hash component MUST be taken from the original URL and
1369 * attached to the URL in Location
1370 */
1371
1372 cleanup ();
1373 check_http ();
1374} 1312}
1375 1313
1376/* check whether a file exists */ 1314/* check whether a file exists */
1377void 1315void test_file(char *path) {
1378test_file (char *path) 1316 if (access(path, R_OK) == 0)
1379{ 1317 return;
1380 if (access(path, R_OK) == 0) 1318 usage2(_("file does not exist or is not readable"), path);
1381 return;
1382 usage2 (_("file does not exist or is not readable"), path);
1383} 1319}
1384 1320
1385bool 1321bool process_arguments(int argc, char **argv) {
1386process_arguments (int argc, char **argv) 1322 char *p;
1387{ 1323 int c = 1;
1388 char *p; 1324 char *temp;
1389 int c = 1; 1325
1390 char *temp; 1326 enum {
1391 1327 INVERT_REGEX = CHAR_MAX + 1,
1392 enum { 1328 SNI_OPTION,
1393 INVERT_REGEX = CHAR_MAX + 1, 1329 MAX_REDIRS_OPTION,
1394 SNI_OPTION, 1330 CONTINUE_AFTER_CHECK_CERT,
1395 MAX_REDIRS_OPTION, 1331 CA_CERT_OPTION,
1396 CONTINUE_AFTER_CHECK_CERT, 1332 HTTP_VERSION_OPTION,
1397 CA_CERT_OPTION, 1333 AUTOMATIC_DECOMPRESSION,
1398 HTTP_VERSION_OPTION, 1334 COOKIE_JAR,
1399 AUTOMATIC_DECOMPRESSION, 1335 HAPROXY_PROTOCOL,
1400 COOKIE_JAR, 1336 STATE_REGEX
1401 HAPROXY_PROTOCOL, 1337 };
1402 STATE_REGEX 1338
1403 }; 1339 int option = 0;
1404 1340 int got_plus = 0;
1405 int option = 0; 1341 static struct option longopts[] = {STD_LONG_OPTS,
1406 int got_plus = 0; 1342 {"link", no_argument, 0, 'L'},
1407 static struct option longopts[] = { 1343 {"nohtml", no_argument, 0, 'n'},
1408 STD_LONG_OPTS, 1344 {"ssl", optional_argument, 0, 'S'},
1409 {"link", no_argument, 0, 'L'}, 1345 {"sni", no_argument, 0, SNI_OPTION},
1410 {"nohtml", no_argument, 0, 'n'}, 1346 {"post", required_argument, 0, 'P'},
1411 {"ssl", optional_argument, 0, 'S'}, 1347 {"method", required_argument, 0, 'j'},
1412 {"sni", no_argument, 0, SNI_OPTION}, 1348 {"IP-address", required_argument, 0, 'I'},
1413 {"post", required_argument, 0, 'P'}, 1349 {"url", required_argument, 0, 'u'},
1414 {"method", required_argument, 0, 'j'}, 1350 {"port", required_argument, 0, 'p'},
1415 {"IP-address", required_argument, 0, 'I'}, 1351 {"authorization", required_argument, 0, 'a'},
1416 {"url", required_argument, 0, 'u'}, 1352 {"proxy-authorization", required_argument, 0, 'b'},
1417 {"port", required_argument, 0, 'p'}, 1353 {"header-string", required_argument, 0, 'd'},
1418 {"authorization", required_argument, 0, 'a'}, 1354 {"string", required_argument, 0, 's'},
1419 {"proxy-authorization", required_argument, 0, 'b'}, 1355 {"expect", required_argument, 0, 'e'},
1420 {"header-string", required_argument, 0, 'd'}, 1356 {"regex", required_argument, 0, 'r'},
1421 {"string", required_argument, 0, 's'}, 1357 {"ereg", required_argument, 0, 'r'},
1422 {"expect", required_argument, 0, 'e'}, 1358 {"eregi", required_argument, 0, 'R'},
1423 {"regex", required_argument, 0, 'r'}, 1359 {"linespan", no_argument, 0, 'l'},
1424 {"ereg", required_argument, 0, 'r'}, 1360 {"onredirect", required_argument, 0, 'f'},
1425 {"eregi", required_argument, 0, 'R'}, 1361 {"certificate", required_argument, 0, 'C'},
1426 {"linespan", no_argument, 0, 'l'}, 1362 {"client-cert", required_argument, 0, 'J'},
1427 {"onredirect", required_argument, 0, 'f'}, 1363 {"private-key", required_argument, 0, 'K'},
1428 {"certificate", required_argument, 0, 'C'}, 1364 {"ca-cert", required_argument, 0, CA_CERT_OPTION},
1429 {"client-cert", required_argument, 0, 'J'}, 1365 {"verify-cert", no_argument, 0, 'D'},
1430 {"private-key", required_argument, 0, 'K'}, 1366 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT},
1431 {"ca-cert", required_argument, 0, CA_CERT_OPTION}, 1367 {"useragent", required_argument, 0, 'A'},
1432 {"verify-cert", no_argument, 0, 'D'}, 1368 {"header", required_argument, 0, 'k'},
1433 {"continue-after-certificate", no_argument, 0, CONTINUE_AFTER_CHECK_CERT}, 1369 {"no-body", no_argument, 0, 'N'},
1434 {"useragent", required_argument, 0, 'A'}, 1370 {"max-age", required_argument, 0, 'M'},
1435 {"header", required_argument, 0, 'k'}, 1371 {"content-type", required_argument, 0, 'T'},
1436 {"no-body", no_argument, 0, 'N'}, 1372 {"pagesize", required_argument, 0, 'm'},
1437 {"max-age", required_argument, 0, 'M'}, 1373 {"invert-regex", no_argument, NULL, INVERT_REGEX},
1438 {"content-type", required_argument, 0, 'T'}, 1374 {"state-regex", required_argument, 0, STATE_REGEX},
1439 {"pagesize", required_argument, 0, 'm'}, 1375 {"use-ipv4", no_argument, 0, '4'},
1440 {"invert-regex", no_argument, NULL, INVERT_REGEX}, 1376 {"use-ipv6", no_argument, 0, '6'},
1441 {"state-regex", required_argument, 0, STATE_REGEX}, 1377 {"extended-perfdata", no_argument, 0, 'E'},
1442 {"use-ipv4", no_argument, 0, '4'}, 1378 {"show-body", no_argument, 0, 'B'},
1443 {"use-ipv6", no_argument, 0, '6'}, 1379 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION},
1444 {"extended-perfdata", no_argument, 0, 'E'}, 1380 {"http-version", required_argument, 0, HTTP_VERSION_OPTION},
1445 {"show-body", no_argument, 0, 'B'}, 1381 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION},
1446 {"max-redirs", required_argument, 0, MAX_REDIRS_OPTION}, 1382 {"cookie-jar", required_argument, 0, COOKIE_JAR},
1447 {"http-version", required_argument, 0, HTTP_VERSION_OPTION}, 1383 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL},
1448 {"enable-automatic-decompression", no_argument, 0, AUTOMATIC_DECOMPRESSION}, 1384 {0, 0, 0, 0}};
1449 {"cookie-jar", required_argument, 0, COOKIE_JAR}, 1385
1450 {"haproxy-protocol", no_argument, 0, HAPROXY_PROTOCOL}, 1386 if (argc < 2)
1451 {0, 0, 0, 0} 1387 return false;
1452 }; 1388
1453 1389 /* support check_http compatible arguments */
1454 if (argc < 2) 1390 for (c = 1; c < argc; c++) {
1455 return false; 1391 if (strcmp("-to", argv[c]) == 0)
1456 1392 strcpy(argv[c], "-t");
1457 /* support check_http compatible arguments */ 1393 if (strcmp("-hn", argv[c]) == 0)
1458 for (c = 1; c < argc; c++) { 1394 strcpy(argv[c], "-H");
1459 if (strcmp ("-to", argv[c]) == 0) 1395 if (strcmp("-wt", argv[c]) == 0)
1460 strcpy (argv[c], "-t"); 1396 strcpy(argv[c], "-w");
1461 if (strcmp ("-hn", argv[c]) == 0) 1397 if (strcmp("-ct", argv[c]) == 0)
1462 strcpy (argv[c], "-H"); 1398 strcpy(argv[c], "-c");
1463 if (strcmp ("-wt", argv[c]) == 0) 1399 if (strcmp("-nohtml", argv[c]) == 0)
1464 strcpy (argv[c], "-w"); 1400 strcpy(argv[c], "-n");
1465 if (strcmp ("-ct", argv[c]) == 0) 1401 }
1466 strcpy (argv[c], "-c"); 1402
1467 if (strcmp ("-nohtml", argv[c]) == 0) 1403 server_url = strdup(DEFAULT_SERVER_URL);
1468 strcpy (argv[c], "-n"); 1404
1469 } 1405 while (1) {
1470 1406 c = getopt_long(argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", longopts, &option);
1471 server_url = strdup(DEFAULT_SERVER_URL); 1407 if (c == -1 || c == EOF || c == 1)
1472 1408 break;
1473 while (1) { 1409
1474 c = getopt_long (argc, argv, "Vvh46t:c:w:A:k:H:P:j:T:I:a:b:d:e:p:s:R:r:u:f:C:J:K:DnlLS::m:M:NEB", longopts, &option); 1410 switch (c) {
1475 if (c == -1 || c == EOF || c == 1) 1411 case 'h':
1476 break; 1412 print_help();
1477 1413 exit(STATE_UNKNOWN);
1478 switch (c) { 1414 break;
1479 case 'h': 1415 case 'V':
1480 print_help(); 1416 print_revision(progname, NP_VERSION);
1481 exit(STATE_UNKNOWN); 1417 print_curl_version();
1482 break; 1418 exit(STATE_UNKNOWN);
1483 case 'V': 1419 break;
1484 print_revision(progname, NP_VERSION); 1420 case 'v':
1485 print_curl_version(); 1421 verbose++;
1486 exit(STATE_UNKNOWN); 1422 break;
1487 break; 1423 case 't': /* timeout period */
1488 case 'v': 1424 if (!is_intnonneg(optarg))
1489 verbose++; 1425 usage2(_("Timeout interval must be a positive integer"), optarg);
1490 break; 1426 else
1491 case 't': /* timeout period */ 1427 socket_timeout = (int)strtol(optarg, NULL, 10);
1492 if (!is_intnonneg (optarg)) 1428 break;
1493 usage2 (_("Timeout interval must be a positive integer"), optarg); 1429 case 'c': /* critical time threshold */
1494 else 1430 critical_thresholds = optarg;
1495 socket_timeout = (int)strtol (optarg, NULL, 10); 1431 break;
1496 break; 1432 case 'w': /* warning time threshold */
1497 case 'c': /* critical time threshold */ 1433 warning_thresholds = optarg;
1498 critical_thresholds = optarg; 1434 break;
1499 break; 1435 case 'H': /* virtual host */
1500 case 'w': /* warning time threshold */ 1436 host_name = strdup(optarg);
1501 warning_thresholds = optarg; 1437 if (host_name[0] == '[') {
1502 break; 1438 if ((p = strstr(host_name, "]:")) != NULL) { /* [IPv6]:port */
1503 case 'H': /* virtual host */ 1439 virtual_port = atoi(p + 2);
1504 host_name = strdup (optarg); 1440 /* cut off the port */
1505 if (host_name[0] == '[') { 1441 host_name_length = strlen(host_name) - strlen(p) - 1;
1506 if ((p = strstr (host_name, "]:")) != NULL) { /* [IPv6]:port */ 1442 free(host_name);
1507 virtual_port = atoi (p + 2); 1443 host_name = strndup(optarg, host_name_length);
1508 /* cut off the port */ 1444 }
1509 host_name_length = strlen (host_name) - strlen (p) - 1; 1445 } else if ((p = strchr(host_name, ':')) != NULL && strchr(++p, ':') == NULL) { /* IPv4:port or host:port */
1510 free (host_name); 1446 virtual_port = atoi(p);
1511 host_name = strndup (optarg, host_name_length); 1447 /* cut off the port */
1512 } 1448 host_name_length = strlen(host_name) - strlen(p) - 1;
1513 } else if ((p = strchr (host_name, ':')) != NULL 1449 free(host_name);
1514 && strchr (++p, ':') == NULL) { /* IPv4:port or host:port */ 1450 host_name = strndup(optarg, host_name_length);
1515 virtual_port = atoi (p); 1451 }
1516 /* cut off the port */ 1452 break;
1517 host_name_length = strlen (host_name) - strlen (p) - 1; 1453 case 'I': /* internet address */
1518 free (host_name); 1454 server_address = strdup(optarg);
1519 host_name = strndup (optarg, host_name_length); 1455 break;
1520 } 1456 case 'u': /* URL path */
1521 break; 1457 server_url = strdup(optarg);
1522 case 'I': /* internet address */ 1458 break;
1523 server_address = strdup (optarg); 1459 case 'p': /* Server port */
1524 break; 1460 if (!is_intnonneg(optarg))
1525 case 'u': /* URL path */ 1461 usage2(_("Invalid port number, expecting a non-negative number"), optarg);
1526 server_url = strdup (optarg); 1462 else {
1527 break; 1463 if (strtol(optarg, NULL, 10) > MAX_PORT)
1528 case 'p': /* Server port */ 1464 usage2(_("Invalid port number, supplied port number is too big"), optarg);
1529 if (!is_intnonneg (optarg)) 1465 server_port = (unsigned short)strtol(optarg, NULL, 10);
1530 usage2 (_("Invalid port number, expecting a non-negative number"), optarg); 1466 specify_port = true;
1531 else { 1467 }
1532 if( strtol(optarg, NULL, 10) > MAX_PORT) 1468 break;
1533 usage2 (_("Invalid port number, supplied port number is too big"), optarg); 1469 case 'a': /* authorization info */
1534 server_port = (unsigned short)strtol(optarg, NULL, 10); 1470 strncpy(user_auth, optarg, MAX_INPUT_BUFFER - 1);
1535 specify_port = true; 1471 user_auth[MAX_INPUT_BUFFER - 1] = 0;
1536 } 1472 break;
1537 break; 1473 case 'b': /* proxy-authorization info */
1538 case 'a': /* authorization info */ 1474 strncpy(proxy_auth, optarg, MAX_INPUT_BUFFER - 1);
1539 strncpy (user_auth, optarg, MAX_INPUT_BUFFER - 1); 1475 proxy_auth[MAX_INPUT_BUFFER - 1] = 0;
1540 user_auth[MAX_INPUT_BUFFER - 1] = 0; 1476 break;
1541 break; 1477 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */
1542 case 'b': /* proxy-authorization info */ 1478 if (!http_post_data)
1543 strncpy (proxy_auth, optarg, MAX_INPUT_BUFFER - 1); 1479 http_post_data = strdup(optarg);
1544 proxy_auth[MAX_INPUT_BUFFER - 1] = 0; 1480 if (!http_method)
1545 break; 1481 http_method = strdup("POST");
1546 case 'P': /* HTTP POST data in URL encoded format; ignored if settings already */ 1482 break;
1547 if (! http_post_data) 1483 case 'j': /* Set HTTP method */
1548 http_post_data = strdup (optarg); 1484 if (http_method)
1549 if (! http_method) 1485 free(http_method);
1550 http_method = strdup("POST"); 1486 http_method = strdup(optarg);
1551 break; 1487 break;
1552 case 'j': /* Set HTTP method */ 1488 case 'A': /* useragent */
1553 if (http_method) 1489 strncpy(user_agent, optarg, DEFAULT_BUFFER_SIZE);
1554 free(http_method); 1490 user_agent[DEFAULT_BUFFER_SIZE - 1] = '\0';
1555 http_method = strdup (optarg); 1491 break;
1556 break; 1492 case 'k': /* Additional headers */
1557 case 'A': /* useragent */ 1493 if (http_opt_headers_count == 0)
1558 strncpy (user_agent, optarg, DEFAULT_BUFFER_SIZE); 1494 http_opt_headers = malloc(sizeof(char *) * (++http_opt_headers_count));
1559 user_agent[DEFAULT_BUFFER_SIZE-1] = '\0'; 1495 else
1560 break; 1496 http_opt_headers = realloc(http_opt_headers, sizeof(char *) * (++http_opt_headers_count));
1561 case 'k': /* Additional headers */ 1497 http_opt_headers[http_opt_headers_count - 1] = optarg;
1562 if (http_opt_headers_count == 0) 1498 break;
1563 http_opt_headers = malloc (sizeof (char *) * (++http_opt_headers_count)); 1499 case 'L': /* show html link */
1564 else 1500 display_html = true;
1565 http_opt_headers = realloc (http_opt_headers, sizeof (char *) * (++http_opt_headers_count)); 1501 break;
1566 http_opt_headers[http_opt_headers_count - 1] = optarg; 1502 case 'n': /* do not show html link */
1567 break; 1503 display_html = false;
1568 case 'L': /* show html link */ 1504 break;
1569 display_html = true; 1505 case 'C': /* Check SSL cert validity */
1570 break;
1571 case 'n': /* do not show html link */
1572 display_html = false;
1573 break;
1574 case 'C': /* Check SSL cert validity */
1575#ifdef LIBCURL_FEATURE_SSL 1506#ifdef LIBCURL_FEATURE_SSL
1576 if ((temp=strchr(optarg,','))!=NULL) { 1507 if ((temp = strchr(optarg, ',')) != NULL) {
1577 *temp='\0'; 1508 *temp = '\0';
1578 if (!is_intnonneg (optarg)) 1509 if (!is_intnonneg(optarg))
1579 usage2 (_("Invalid certificate expiration period"), optarg); 1510 usage2(_("Invalid certificate expiration period"), optarg);
1580 days_till_exp_warn = atoi(optarg); 1511 days_till_exp_warn = atoi(optarg);
1581 *temp=','; 1512 *temp = ',';
1582 temp++; 1513 temp++;
1583 if (!is_intnonneg (temp)) 1514 if (!is_intnonneg(temp))
1584 usage2 (_("Invalid certificate expiration period"), temp); 1515 usage2(_("Invalid certificate expiration period"), temp);
1585 days_till_exp_crit = atoi (temp); 1516 days_till_exp_crit = atoi(temp);
1586 } 1517 } else {
1587 else { 1518 days_till_exp_crit = 0;
1588 days_till_exp_crit=0; 1519 if (!is_intnonneg(optarg))
1589 if (!is_intnonneg (optarg)) 1520 usage2(_("Invalid certificate expiration period"), optarg);
1590 usage2 (_("Invalid certificate expiration period"), optarg); 1521 days_till_exp_warn = atoi(optarg);
1591 days_till_exp_warn = atoi (optarg); 1522 }
1592 } 1523 check_cert = true;
1593 check_cert = true; 1524 goto enable_ssl;
1594 goto enable_ssl;
1595#endif 1525#endif
1596 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */ 1526 case CONTINUE_AFTER_CHECK_CERT: /* don't stop after the certificate is checked */
1597#ifdef HAVE_SSL 1527#ifdef HAVE_SSL
1598 continue_after_check_cert = true; 1528 continue_after_check_cert = true;
1599 break; 1529 break;
1600#endif 1530#endif
1601 case 'J': /* use client certificate */ 1531 case 'J': /* use client certificate */
1602#ifdef LIBCURL_FEATURE_SSL 1532#ifdef LIBCURL_FEATURE_SSL
1603 test_file(optarg); 1533 test_file(optarg);
1604 client_cert = optarg; 1534 client_cert = optarg;
1605 goto enable_ssl; 1535 goto enable_ssl;
1606#endif 1536#endif
1607 case 'K': /* use client private key */ 1537 case 'K': /* use client private key */
1608#ifdef LIBCURL_FEATURE_SSL 1538#ifdef LIBCURL_FEATURE_SSL
1609 test_file(optarg); 1539 test_file(optarg);
1610 client_privkey = optarg; 1540 client_privkey = optarg;
1611 goto enable_ssl; 1541 goto enable_ssl;
1612#endif 1542#endif
1613#ifdef LIBCURL_FEATURE_SSL 1543#ifdef LIBCURL_FEATURE_SSL
1614 case CA_CERT_OPTION: /* use CA chain file */ 1544 case CA_CERT_OPTION: /* use CA chain file */
1615 test_file(optarg); 1545 test_file(optarg);
1616 ca_cert = optarg; 1546 ca_cert = optarg;
1617 goto enable_ssl; 1547 goto enable_ssl;
1618#endif 1548#endif
1619#ifdef LIBCURL_FEATURE_SSL 1549#ifdef LIBCURL_FEATURE_SSL
1620 case 'D': /* verify peer certificate & host */ 1550 case 'D': /* verify peer certificate & host */
1621 verify_peer_and_host = true; 1551 verify_peer_and_host = true;
1622 break; 1552 break;
1623#endif 1553#endif
1624 case 'S': /* use SSL */ 1554 case 'S': /* use SSL */
1625#ifdef LIBCURL_FEATURE_SSL 1555#ifdef LIBCURL_FEATURE_SSL
1626 enable_ssl: 1556 enable_ssl:
1627 use_ssl = true; 1557 use_ssl = true;
1628 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default. 1558 /* ssl_version initialized to CURL_SSLVERSION_DEFAULT as a default.
1629 * Only set if it's non-zero. This helps when we include multiple 1559 * Only set if it's non-zero. This helps when we include multiple
1630 * parameters, like -S and -C combinations */ 1560 * parameters, like -S and -C combinations */
1631 ssl_version = CURL_SSLVERSION_DEFAULT; 1561 ssl_version = CURL_SSLVERSION_DEFAULT;
1632 if (c=='S' && optarg != NULL) { 1562 if (c == 'S' && optarg != NULL) {
1633 char *plus_ptr = strchr(optarg, '+'); 1563 char *plus_ptr = strchr(optarg, '+');
1634 if (plus_ptr) { 1564 if (plus_ptr) {
1635 got_plus = 1; 1565 got_plus = 1;
1636 *plus_ptr = '\0'; 1566 *plus_ptr = '\0';
1637 } 1567 }
1638 1568
1639 if (optarg[0] == '2') 1569 if (optarg[0] == '2')
1640 ssl_version = CURL_SSLVERSION_SSLv2; 1570 ssl_version = CURL_SSLVERSION_SSLv2;
1641 else if (optarg[0] == '3') 1571 else if (optarg[0] == '3')
1642 ssl_version = CURL_SSLVERSION_SSLv3; 1572 ssl_version = CURL_SSLVERSION_SSLv3;
1643 else if (!strcmp (optarg, "1") || !strcmp (optarg, "1.0")) 1573 else if (!strcmp(optarg, "1") || !strcmp(optarg, "1.0"))
1644#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1574# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1645 ssl_version = CURL_SSLVERSION_TLSv1_0; 1575 ssl_version = CURL_SSLVERSION_TLSv1_0;
1646#else 1576# else
1647 ssl_version = CURL_SSLVERSION_DEFAULT; 1577 ssl_version = CURL_SSLVERSION_DEFAULT;
1648#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1578# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1649 else if (!strcmp (optarg, "1.1")) 1579 else if (!strcmp(optarg, "1.1"))
1650#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1580# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1651 ssl_version = CURL_SSLVERSION_TLSv1_1; 1581 ssl_version = CURL_SSLVERSION_TLSv1_1;
1652#else 1582# else
1653 ssl_version = CURL_SSLVERSION_DEFAULT; 1583 ssl_version = CURL_SSLVERSION_DEFAULT;
1654#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1584# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1655 else if (!strcmp (optarg, "1.2")) 1585 else if (!strcmp(optarg, "1.2"))
1656#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) 1586# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
1657 ssl_version = CURL_SSLVERSION_TLSv1_2; 1587 ssl_version = CURL_SSLVERSION_TLSv1_2;
1658#else 1588# else
1659 ssl_version = CURL_SSLVERSION_DEFAULT; 1589 ssl_version = CURL_SSLVERSION_DEFAULT;
1660#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */ 1590# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0) */
1661 else if (!strcmp (optarg, "1.3")) 1591 else if (!strcmp(optarg, "1.3"))
1662#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) 1592# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
1663 ssl_version = CURL_SSLVERSION_TLSv1_3; 1593 ssl_version = CURL_SSLVERSION_TLSv1_3;
1664#else 1594# else
1665 ssl_version = CURL_SSLVERSION_DEFAULT; 1595 ssl_version = CURL_SSLVERSION_DEFAULT;
1666#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */ 1596# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0) */
1667 else 1597 else
1668 usage4 (_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)")); 1598 usage4(_("Invalid option - Valid SSL/TLS versions: 2, 3, 1, 1.1, 1.2, 1.3 (with optional '+' suffix)"));
1669 } 1599 }
1670#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) 1600# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
1671 if (got_plus) { 1601 if (got_plus) {
1672 switch (ssl_version) { 1602 switch (ssl_version) {
1673 case CURL_SSLVERSION_TLSv1_3: 1603 case CURL_SSLVERSION_TLSv1_3:
1674 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1604 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1675 break; 1605 break;
1676 case CURL_SSLVERSION_TLSv1_2: 1606 case CURL_SSLVERSION_TLSv1_2:
1677 case CURL_SSLVERSION_TLSv1_1: 1607 case CURL_SSLVERSION_TLSv1_1:
1678 case CURL_SSLVERSION_TLSv1_0: 1608 case CURL_SSLVERSION_TLSv1_0:
1679 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT; 1609 ssl_version |= CURL_SSLVERSION_MAX_DEFAULT;
1680 break; 1610 break;
1681 } 1611 }
1682 } else { 1612 } else {
1683 switch (ssl_version) { 1613 switch (ssl_version) {
1684 case CURL_SSLVERSION_TLSv1_3: 1614 case CURL_SSLVERSION_TLSv1_3:
1685 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3; 1615 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_3;
1686 break; 1616 break;
1687 case CURL_SSLVERSION_TLSv1_2: 1617 case CURL_SSLVERSION_TLSv1_2:
1688 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2; 1618 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_2;
1689 break; 1619 break;
1690 case CURL_SSLVERSION_TLSv1_1: 1620 case CURL_SSLVERSION_TLSv1_1:
1691 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1; 1621 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_1;
1692 break; 1622 break;
1693 case CURL_SSLVERSION_TLSv1_0: 1623 case CURL_SSLVERSION_TLSv1_0:
1694 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0; 1624 ssl_version |= CURL_SSLVERSION_MAX_TLSv1_0;
1695 break; 1625 break;
1696 } 1626 }
1697 } 1627 }
1698#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1628# endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1699 if (verbose >= 2) 1629 if (verbose >= 2)
1700 printf(_("* Set SSL/TLS version to %d\n"), ssl_version); 1630 printf(_("* Set SSL/TLS version to %d\n"), ssl_version);
1701 if (!specify_port) 1631 if (!specify_port)
1702 server_port = HTTPS_PORT; 1632 server_port = HTTPS_PORT;
1703 break; 1633 break;
1704#else /* LIBCURL_FEATURE_SSL */ 1634#else /* LIBCURL_FEATURE_SSL */
1705 /* -C -J and -K fall through to here without SSL */ 1635 /* -C -J and -K fall through to here without SSL */
1706 usage4 (_("Invalid option - SSL is not available")); 1636 usage4(_("Invalid option - SSL is not available"));
1707 break; 1637 break;
1708 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */ 1638 case SNI_OPTION: /* --sni is parsed, but ignored, the default is true with libcurl */
1709 use_sni = true; 1639 use_sni = true;
1710 break; 1640 break;
1711#endif /* LIBCURL_FEATURE_SSL */ 1641#endif /* LIBCURL_FEATURE_SSL */
1712 case MAX_REDIRS_OPTION: 1642 case MAX_REDIRS_OPTION:
1713 if (!is_intnonneg (optarg)) 1643 if (!is_intnonneg(optarg))
1714 usage2 (_("Invalid max_redirs count"), optarg); 1644 usage2(_("Invalid max_redirs count"), optarg);
1715 else { 1645 else {
1716 max_depth = atoi (optarg); 1646 max_depth = atoi(optarg);
1717 } 1647 }
1718 break; 1648 break;
1719 case 'f': /* onredirect */ 1649 case 'f': /* onredirect */
1720 if (!strcmp (optarg, "ok")) 1650 if (!strcmp(optarg, "ok"))
1721 onredirect = STATE_OK; 1651 onredirect = STATE_OK;
1722 else if (!strcmp (optarg, "warning")) 1652 else if (!strcmp(optarg, "warning"))
1723 onredirect = STATE_WARNING; 1653 onredirect = STATE_WARNING;
1724 else if (!strcmp (optarg, "critical")) 1654 else if (!strcmp(optarg, "critical"))
1725 onredirect = STATE_CRITICAL; 1655 onredirect = STATE_CRITICAL;
1726 else if (!strcmp (optarg, "unknown")) 1656 else if (!strcmp(optarg, "unknown"))
1727 onredirect = STATE_UNKNOWN; 1657 onredirect = STATE_UNKNOWN;
1728 else if (!strcmp (optarg, "follow")) 1658 else if (!strcmp(optarg, "follow"))
1729 onredirect = STATE_DEPENDENT; 1659 onredirect = STATE_DEPENDENT;
1730 else if (!strcmp (optarg, "stickyport")) 1660 else if (!strcmp(optarg, "stickyport"))
1731 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST|STICKY_PORT; 1661 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST | STICKY_PORT;
1732 else if (!strcmp (optarg, "sticky")) 1662 else if (!strcmp(optarg, "sticky"))
1733 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST; 1663 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_HOST;
1734 else if (!strcmp (optarg, "follow")) 1664 else if (!strcmp(optarg, "follow"))
1735 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE; 1665 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_HTTP_CURL, followsticky = STICKY_NONE;
1736 else if (!strcmp (optarg, "curl")) 1666 else if (!strcmp(optarg, "curl"))
1737 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL; 1667 onredirect = STATE_DEPENDENT, followmethod = FOLLOW_LIBCURL;
1738 else usage2 (_("Invalid onredirect option"), optarg); 1668 else
1739 if (verbose >= 2) 1669 usage2(_("Invalid onredirect option"), optarg);
1740 printf(_("* Following redirects set to %s\n"), state_text(onredirect)); 1670 if (verbose >= 2)
1741 break; 1671 printf(_("* Following redirects set to %s\n"), state_text(onredirect));
1742 case 'd': /* string or substring */ 1672 break;
1743 strncpy (header_expect, optarg, MAX_INPUT_BUFFER - 1); 1673 case 'd': /* string or substring */
1744 header_expect[MAX_INPUT_BUFFER - 1] = 0; 1674 strncpy(header_expect, optarg, MAX_INPUT_BUFFER - 1);
1745 break; 1675 header_expect[MAX_INPUT_BUFFER - 1] = 0;
1746 case 's': /* string or substring */ 1676 break;
1747 strncpy (string_expect, optarg, MAX_INPUT_BUFFER - 1); 1677 case 's': /* string or substring */
1748 string_expect[MAX_INPUT_BUFFER - 1] = 0; 1678 strncpy(string_expect, optarg, MAX_INPUT_BUFFER - 1);
1749 break; 1679 string_expect[MAX_INPUT_BUFFER - 1] = 0;
1750 case 'e': /* string or substring */ 1680 break;
1751 strncpy (server_expect, optarg, MAX_INPUT_BUFFER - 1); 1681 case 'e': /* string or substring */
1752 server_expect[MAX_INPUT_BUFFER - 1] = 0; 1682 strncpy(server_expect, optarg, MAX_INPUT_BUFFER - 1);
1753 server_expect_yn = 1; 1683 server_expect[MAX_INPUT_BUFFER - 1] = 0;
1754 break; 1684 server_expect_yn = 1;
1755 case 'T': /* Content-type */ 1685 break;
1756 http_content_type = strdup (optarg); 1686 case 'T': /* Content-type */
1757 break; 1687 http_content_type = strdup(optarg);
1758 case 'l': /* linespan */ 1688 break;
1759 cflags &= ~REG_NEWLINE; 1689 case 'l': /* linespan */
1760 break; 1690 cflags &= ~REG_NEWLINE;
1761 case 'R': /* regex */ 1691 break;
1762 cflags |= REG_ICASE; 1692 case 'R': /* regex */
1693 cflags |= REG_ICASE;
1763 // fall through 1694 // fall through
1764 case 'r': /* regex */ 1695 case 'r': /* regex */
1765 strncpy (regexp, optarg, MAX_RE_SIZE - 1); 1696 strncpy(regexp, optarg, MAX_RE_SIZE - 1);
1766 regexp[MAX_RE_SIZE - 1] = 0; 1697 regexp[MAX_RE_SIZE - 1] = 0;
1767 errcode = regcomp (&preg, regexp, cflags); 1698 errcode = regcomp(&preg, regexp, cflags);
1768 if (errcode != 0) { 1699 if (errcode != 0) {
1769 (void) regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 1700 (void)regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
1770 printf (_("Could Not Compile Regular Expression: %s"), errbuf); 1701 printf(_("Could Not Compile Regular Expression: %s"), errbuf);
1771 return false; 1702 return false;
1772 } 1703 }
1773 break; 1704 break;
1774 case INVERT_REGEX: 1705 case INVERT_REGEX:
1775 invert_regex = true; 1706 invert_regex = true;
1776 break; 1707 break;
1777 case STATE_REGEX: 1708 case STATE_REGEX:
1778 if (!strcmp (optarg, "critical")) 1709 if (!strcasecmp(optarg, "critical"))
1779 state_regex = STATE_CRITICAL; 1710 state_regex = STATE_CRITICAL;
1780 else if (!strcmp (optarg, "warning")) 1711 else if (!strcasecmp(optarg, "warning"))
1781 state_regex = STATE_WARNING; 1712 state_regex = STATE_WARNING;
1782 else usage2 (_("Invalid state-regex option"), optarg); 1713 else
1783 break; 1714 usage2(_("Invalid state-regex option"), optarg);
1784 case '4': 1715 break;
1785 address_family = AF_INET; 1716 case '4':
1786 break; 1717 address_family = AF_INET;
1787 case '6': 1718 break;
1788#if defined (USE_IPV6) && defined (LIBCURL_FEATURE_IPV6) 1719 case '6':
1789 address_family = AF_INET6; 1720#if defined(USE_IPV6) && defined(LIBCURL_FEATURE_IPV6)
1721 address_family = AF_INET6;
1790#else 1722#else
1791 usage4 (_("IPv6 support not available")); 1723 usage4(_("IPv6 support not available"));
1792#endif 1724#endif
1793 break; 1725 break;
1794 case 'm': /* min_page_length */ 1726 case 'm': /* min_page_length */
1795 { 1727 {
1796 char *tmp; 1728 char *tmp;
1797 if (strchr(optarg, ':') != (char *)NULL) { 1729 if (strchr(optarg, ':') != (char *)NULL) {
1798 /* range, so get two values, min:max */ 1730 /* range, so get two values, min:max */
1799 tmp = strtok(optarg, ":"); 1731 tmp = strtok(optarg, ":");
1800 if (tmp == NULL) { 1732 if (tmp == NULL) {
1801 printf("Bad format: try \"-m min:max\"\n"); 1733 printf("Bad format: try \"-m min:max\"\n");
1802 exit (STATE_WARNING); 1734 exit(STATE_WARNING);
1803 } else 1735 } else
1804 min_page_len = atoi(tmp); 1736 min_page_len = atoi(tmp);
1805 1737
1806 tmp = strtok(NULL, ":"); 1738 tmp = strtok(NULL, ":");
1807 if (tmp == NULL) { 1739 if (tmp == NULL) {
1808 printf("Bad format: try \"-m min:max\"\n"); 1740 printf("Bad format: try \"-m min:max\"\n");
1809 exit (STATE_WARNING); 1741 exit(STATE_WARNING);
1810 } else 1742 } else
1811 max_page_len = atoi(tmp); 1743 max_page_len = atoi(tmp);
1812 } else 1744 } else
1813 min_page_len = atoi (optarg); 1745 min_page_len = atoi(optarg);
1814 break; 1746 break;
1815 } 1747 }
1816 case 'N': /* no-body */ 1748 case 'N': /* no-body */
1817 no_body = true; 1749 no_body = true;
1818 break; 1750 break;
1819 case 'M': /* max-age */ 1751 case 'M': /* max-age */
1820 { 1752 {
1821 int L = strlen(optarg); 1753 int L = strlen(optarg);
1822 if (L && optarg[L-1] == 'm') 1754 if (L && optarg[L - 1] == 'm')
1823 maximum_age = atoi (optarg) * 60; 1755 maximum_age = atoi(optarg) * 60;
1824 else if (L && optarg[L-1] == 'h') 1756 else if (L && optarg[L - 1] == 'h')
1825 maximum_age = atoi (optarg) * 60 * 60; 1757 maximum_age = atoi(optarg) * 60 * 60;
1826 else if (L && optarg[L-1] == 'd') 1758 else if (L && optarg[L - 1] == 'd')
1827 maximum_age = atoi (optarg) * 60 * 60 * 24; 1759 maximum_age = atoi(optarg) * 60 * 60 * 24;
1828 else if (L && (optarg[L-1] == 's' || 1760 else if (L && (optarg[L - 1] == 's' || isdigit(optarg[L - 1])))
1829 isdigit (optarg[L-1]))) 1761 maximum_age = atoi(optarg);
1830 maximum_age = atoi (optarg); 1762 else {
1831 else { 1763 fprintf(stderr, "unparsable max-age: %s\n", optarg);
1832 fprintf (stderr, "unparsable max-age: %s\n", optarg); 1764 exit(STATE_WARNING);
1833 exit (STATE_WARNING); 1765 }
1834 } 1766 if (verbose >= 2)
1835 if (verbose >= 2) 1767 printf("* Maximal age of document set to %d seconds\n", maximum_age);
1836 printf ("* Maximal age of document set to %d seconds\n", maximum_age); 1768 } break;
1837 } 1769 case 'E': /* show extended perfdata */
1838 break; 1770 show_extended_perfdata = true;
1839 case 'E': /* show extended perfdata */ 1771 break;
1840 show_extended_perfdata = true; 1772 case 'B': /* print body content after status line */
1841 break; 1773 show_body = true;
1842 case 'B': /* print body content after status line */ 1774 break;
1843 show_body = true; 1775 case HTTP_VERSION_OPTION:
1844 break; 1776 curl_http_version = CURL_HTTP_VERSION_NONE;
1845 case HTTP_VERSION_OPTION: 1777 if (strcmp(optarg, "1.0") == 0) {
1846 curl_http_version = CURL_HTTP_VERSION_NONE; 1778 curl_http_version = CURL_HTTP_VERSION_1_0;
1847 if (strcmp (optarg, "1.0") == 0) { 1779 } else if (strcmp(optarg, "1.1") == 0) {
1848 curl_http_version = CURL_HTTP_VERSION_1_0; 1780 curl_http_version = CURL_HTTP_VERSION_1_1;
1849 } else if (strcmp (optarg, "1.1") == 0) { 1781 } else if ((strcmp(optarg, "2.0") == 0) || (strcmp(optarg, "2") == 0)) {
1850 curl_http_version = CURL_HTTP_VERSION_1_1;
1851 } else if ((strcmp (optarg, "2.0") == 0) || (strcmp (optarg, "2") == 0)) {
1852#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) 1782#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
1853 curl_http_version = CURL_HTTP_VERSION_2_0; 1783 curl_http_version = CURL_HTTP_VERSION_2_0;
1854#else 1784#else
1855 curl_http_version = CURL_HTTP_VERSION_NONE; 1785 curl_http_version = CURL_HTTP_VERSION_NONE;
1856#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */ 1786#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0) */
1857 } else { 1787 } else {
1858 fprintf (stderr, "unknown http-version parameter: %s\n", optarg); 1788 fprintf(stderr, "unknown http-version parameter: %s\n", optarg);
1859 exit (STATE_WARNING); 1789 exit(STATE_WARNING);
1860 } 1790 }
1861 break; 1791 break;
1862 case AUTOMATIC_DECOMPRESSION: 1792 case AUTOMATIC_DECOMPRESSION:
1863 automatic_decompression = true; 1793 automatic_decompression = true;
1864 break; 1794 break;
1865 case COOKIE_JAR: 1795 case COOKIE_JAR:
1866 cookie_jar_file = optarg; 1796 cookie_jar_file = optarg;
1867 break; 1797 break;
1868 case HAPROXY_PROTOCOL: 1798 case HAPROXY_PROTOCOL:
1869 haproxy_protocol = true; 1799 haproxy_protocol = true;
1870 break; 1800 break;
1871 case '?': 1801 case '?':
1872 /* print short usage statement if args not parsable */ 1802 /* print short usage statement if args not parsable */
1873 usage5 (); 1803 usage5();
1874 break; 1804 break;
1875 } 1805 }
1876 } 1806 }
1877 1807
1878 c = optind; 1808 c = optind;
1879 1809
1880 if (server_address == NULL && c < argc) 1810 if (server_address == NULL && c < argc)
1881 server_address = strdup (argv[c++]); 1811 server_address = strdup(argv[c++]);
1882 1812
1883 if (host_name == NULL && c < argc) 1813 if (host_name == NULL && c < argc)
1884 host_name = strdup (argv[c++]); 1814 host_name = strdup(argv[c++]);
1885 1815
1886 if (server_address == NULL) { 1816 if (server_address == NULL) {
1887 if (host_name == NULL) 1817 if (host_name == NULL)
1888 usage4 (_("You must specify a server address or host name")); 1818 usage4(_("You must specify a server address or host name"));
1889 else 1819 else
1890 server_address = strdup (host_name); 1820 server_address = strdup(host_name);
1891 } 1821 }
1892 1822
1893 set_thresholds(&thlds, warning_thresholds, critical_thresholds); 1823 set_thresholds(&thlds, warning_thresholds, critical_thresholds);
1894 1824
1895 if (critical_thresholds && thlds->critical->end>(double)socket_timeout) 1825 if (critical_thresholds && thlds->critical->end > (double)socket_timeout)
1896 socket_timeout = (int)thlds->critical->end + 1; 1826 socket_timeout = (int)thlds->critical->end + 1;
1897 if (verbose >= 2) 1827 if (verbose >= 2)
1898 printf ("* Socket timeout set to %ld seconds\n", socket_timeout); 1828 printf("* Socket timeout set to %ld seconds\n", socket_timeout);
1899 1829
1900 if (http_method == NULL) 1830 if (http_method == NULL)
1901 http_method = strdup ("GET"); 1831 http_method = strdup("GET");
1902 1832
1903 if (client_cert && !client_privkey) 1833 if (client_cert && !client_privkey)
1904 usage4 (_("If you use a client certificate you must also specify a private key file")); 1834 usage4(_("If you use a client certificate you must also specify a private key file"));
1905 1835
1906 if (virtual_port == 0) 1836 if (virtual_port == 0)
1907 virtual_port = server_port; 1837 virtual_port = server_port;
1908 else { 1838 else {
1909 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT)) 1839 if ((use_ssl && server_port == HTTPS_PORT) || (!use_ssl && server_port == HTTP_PORT))
1910 if(!specify_port) 1840 if (!specify_port)
1911 server_port = virtual_port; 1841 server_port = virtual_port;
1912 } 1842 }
1913 1843
1914 return true; 1844 return true;
1915} 1845}
1916 1846
1917char *perfd_time (double elapsed_time) 1847char *perfd_time(double elapsed_time) {
1918{ 1848 return fperfdata("time", elapsed_time, "s", thlds->warning ? true : false, thlds->warning ? thlds->warning->end : 0,
1919 return fperfdata ("time", elapsed_time, "s", 1849 thlds->critical ? true : false, thlds->critical ? thlds->critical->end : 0, true, 0, true, socket_timeout);
1920 thlds->warning?true:false, thlds->warning?thlds->warning->end:0,
1921 thlds->critical?true:false, thlds->critical?thlds->critical->end:0,
1922 true, 0, true, socket_timeout);
1923} 1850}
1924 1851
1925char *perfd_time_connect (double elapsed_time_connect) 1852char *perfd_time_connect(double elapsed_time_connect) {
1926{ 1853 return fperfdata("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1927 return fperfdata ("time_connect", elapsed_time_connect, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1928} 1854}
1929 1855
1930char *perfd_time_ssl (double elapsed_time_ssl) 1856char *perfd_time_ssl(double elapsed_time_ssl) {
1931{ 1857 return fperfdata("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1932 return fperfdata ("time_ssl", elapsed_time_ssl, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1933} 1858}
1934 1859
1935char *perfd_time_headers (double elapsed_time_headers) 1860char *perfd_time_headers(double elapsed_time_headers) {
1936{ 1861 return fperfdata("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1937 return fperfdata ("time_headers", elapsed_time_headers, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1938} 1862}
1939 1863
1940char *perfd_time_firstbyte (double elapsed_time_firstbyte) 1864char *perfd_time_firstbyte(double elapsed_time_firstbyte) {
1941{ 1865 return fperfdata("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1942 return fperfdata ("time_firstbyte", elapsed_time_firstbyte, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1943} 1866}
1944 1867
1945char *perfd_time_transfer (double elapsed_time_transfer) 1868char *perfd_time_transfer(double elapsed_time_transfer) {
1946{ 1869 return fperfdata("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1947 return fperfdata ("time_transfer", elapsed_time_transfer, "s", false, 0, false, 0, false, 0, true, socket_timeout);
1948} 1870}
1949 1871
1950char *perfd_size (int page_len) 1872char *perfd_size(int page_len) {
1951{ 1873 return perfdata("size", page_len, "B", (min_page_len > 0 ? true : false), min_page_len, (min_page_len > 0 ? true : false), 0, true, 0,
1952 return perfdata ("size", page_len, "B", 1874 false, 0);
1953 (min_page_len>0?true:false), min_page_len,
1954 (min_page_len>0?true:false), 0,
1955 true, 0, false, 0);
1956} 1875}
1957 1876
1958void 1877void print_help(void) {
1959print_help (void) 1878 print_revision(progname, NP_VERSION);
1960{
1961 print_revision (progname, NP_VERSION);
1962 1879
1963 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 1880 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1964 printf (COPYRIGHT, copyright, email); 1881 printf(COPYRIGHT, copyright, email);
1965 1882
1966 printf ("%s\n", _("This plugin tests the HTTP service on the specified host. It can test")); 1883 printf("%s\n", _("This plugin tests the HTTP service on the specified host. It can test"));
1967 printf ("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for")); 1884 printf("%s\n", _("normal (http) and secure (https) servers, follow redirects, search for"));
1968 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1885 printf("%s\n", _("strings and regular expressions, check connection times, and report on"));
1969 printf ("%s\n", _("certificate expiration times.")); 1886 printf("%s\n", _("certificate expiration times."));
1970 printf ("\n"); 1887 printf("\n");
1971 printf ("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http")); 1888 printf("%s\n", _("It makes use of libcurl to do so. It tries to be as compatible to check_http"));
1972 printf ("%s\n", _("as possible.")); 1889 printf("%s\n", _("as possible."));
1973 1890
1974 printf ("\n\n"); 1891 printf("\n\n");
1975 1892
1976 print_usage (); 1893 print_usage();
1977 1894
1978 printf (_("NOTE: One or both of -H and -I must be specified")); 1895 printf(_("NOTE: One or both of -H and -I must be specified"));
1979 1896
1980 printf ("\n"); 1897 printf("\n");
1981 1898
1982 printf (UT_HELP_VRSN); 1899 printf(UT_HELP_VRSN);
1983 printf (UT_EXTRA_OPTS); 1900 printf(UT_EXTRA_OPTS);
1984 1901
1985 printf (" %s\n", "-H, --hostname=ADDRESS"); 1902 printf(" %s\n", "-H, --hostname=ADDRESS");
1986 printf (" %s\n", _("Host name argument for servers using host headers (virtual host)")); 1903 printf(" %s\n", _("Host name argument for servers using host headers (virtual host)"));
1987 printf (" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); 1904 printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)"));
1988 printf (" %s\n", "-I, --IP-address=ADDRESS"); 1905 printf(" %s\n", "-I, --IP-address=ADDRESS");
1989 printf (" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup).")); 1906 printf(" %s\n", _("IP address or name (use numeric address if possible to bypass DNS lookup)."));
1990 printf (" %s\n", "-p, --port=INTEGER"); 1907 printf(" %s\n", "-p, --port=INTEGER");
1991 printf (" %s", _("Port number (default: ")); 1908 printf(" %s", _("Port number (default: "));
1992 printf ("%d)\n", HTTP_PORT); 1909 printf("%d)\n", HTTP_PORT);
1993 1910
1994 printf (UT_IPv46); 1911 printf(UT_IPv46);
1995 1912
1996#ifdef LIBCURL_FEATURE_SSL 1913#ifdef LIBCURL_FEATURE_SSL
1997 printf (" %s\n", "-S, --ssl=VERSION[+]"); 1914 printf(" %s\n", "-S, --ssl=VERSION[+]");
1998 printf (" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents")); 1915 printf(" %s\n", _("Connect via SSL. Port defaults to 443. VERSION is optional, and prevents"));
1999 printf (" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,")); 1916 printf(" %s\n", _("auto-negotiation (2 = SSLv2, 3 = SSLv3, 1 = TLSv1, 1.1 = TLSv1.1,"));
2000 printf (" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted.")); 1917 printf(" %s\n", _("1.2 = TLSv1.2, 1.3 = TLSv1.3). With a '+' suffix, newer versions are also accepted."));
2001 printf (" %s\n", _("Note: SSLv2 and SSLv3 are deprecated and are usually disabled in libcurl")); 1918 printf(" %s\n", _("Note: SSLv2, SSLv3, TLSv1.0 and TLSv1.1 are deprecated and are usually disabled in libcurl"));
2002 printf (" %s\n", "--sni"); 1919 printf(" %s\n", "--sni");
2003 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 1920 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
2004#if LIBCURL_VERSION_NUM >= 0x071801 1921# if LIBCURL_VERSION_NUM >= 0x071801
2005 printf (" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and")); 1922 printf(" %s\n", _("Note: --sni is the default in libcurl as SSLv2 and SSLV3 are deprecated and"));
2006 printf (" %s\n", _(" SNI only really works since TLSv1.0")); 1923 printf(" %s\n", _(" SNI only really works since TLSv1.0"));
2007#else 1924# else
2008 printf (" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1")); 1925 printf(" %s\n", _("Note: SNI is not supported in libcurl before 7.18.1"));
2009#endif 1926# endif
2010 printf (" %s\n", "-C, --certificate=INTEGER[,INTEGER]"); 1927 printf(" %s\n", "-C, --certificate=INTEGER[,INTEGER]");
2011 printf (" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443.")); 1928 printf(" %s\n", _("Minimum number of days a certificate has to be valid. Port defaults to 443."));
2012 printf (" %s\n", _("A STATE_WARNING is returned if the certificate has a validity less than the")); 1929 printf(" %s\n", _("A STATE_WARNING is returned if the certificate has a validity less than the"));
2013 printf (" %s\n", _("first agument's value. If there is a second argument and the certificate's")); 1930 printf(" %s\n", _("first agument's value. If there is a second argument and the certificate's"));
2014 printf (" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned.")); 1931 printf(" %s\n", _("validity is less than its value, a STATE_CRITICAL is returned."));
2015 printf (" %s\n", _("(When this option is used the URL is not checked by default. You can use")); 1932 printf(" %s\n", _("(When this option is used the URL is not checked by default. You can use"));
2016 printf (" %s\n", _(" --continue-after-certificate to override this behavior)")); 1933 printf(" %s\n", _(" --continue-after-certificate to override this behavior)"));
2017 printf (" %s\n", "--continue-after-certificate"); 1934 printf(" %s\n", "--continue-after-certificate");
2018 printf (" %s\n", _("Allows the HTTP check to continue after performing the certificate check.")); 1935 printf(" %s\n", _("Allows the HTTP check to continue after performing the certificate check."));
2019 printf (" %s\n", _("Does nothing unless -C is used.")); 1936 printf(" %s\n", _("Does nothing unless -C is used."));
2020 printf (" %s\n", "-J, --client-cert=FILE"); 1937 printf(" %s\n", "-J, --client-cert=FILE");
2021 printf (" %s\n", _("Name of file that contains the client certificate (PEM format)")); 1938 printf(" %s\n", _("Name of file that contains the client certificate (PEM format)"));
2022 printf (" %s\n", _("to be used in establishing the SSL session")); 1939 printf(" %s\n", _("to be used in establishing the SSL session"));
2023 printf (" %s\n", "-K, --private-key=FILE"); 1940 printf(" %s\n", "-K, --private-key=FILE");
2024 printf (" %s\n", _("Name of file containing the private key (PEM format)")); 1941 printf(" %s\n", _("Name of file containing the private key (PEM format)"));
2025 printf (" %s\n", _("matching the client certificate")); 1942 printf(" %s\n", _("matching the client certificate"));
2026 printf (" %s\n", "--ca-cert=FILE"); 1943 printf(" %s\n", "--ca-cert=FILE");
2027 printf (" %s\n", _("CA certificate file to verify peer against")); 1944 printf(" %s\n", _("CA certificate file to verify peer against"));
2028 printf (" %s\n", "-D, --verify-cert"); 1945 printf(" %s\n", "-D, --verify-cert");
2029 printf (" %s\n", _("Verify the peer's SSL certificate and hostname")); 1946 printf(" %s\n", _("Verify the peer's SSL certificate and hostname"));
2030#endif 1947#endif
2031 1948
2032 printf (" %s\n", "-e, --expect=STRING"); 1949 printf(" %s\n", "-e, --expect=STRING");
2033 printf (" %s\n", _("Comma-delimited list of strings, at least one of them is expected in")); 1950 printf(" %s\n", _("Comma-delimited list of strings, at least one of them is expected in"));
2034 printf (" %s", _("the first (status) line of the server response (default: ")); 1951 printf(" %s", _("the first (status) line of the server response (default: "));
2035 printf ("%s)\n", HTTP_EXPECT); 1952 printf("%s)\n", HTTP_EXPECT);
2036 printf (" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)")); 1953 printf(" %s\n", _("If specified skips all other status line logic (ex: 3xx, 4xx, 5xx processing)"));
2037 printf (" %s\n", "-d, --header-string=STRING"); 1954 printf(" %s\n", "-d, --header-string=STRING");
2038 printf (" %s\n", _("String to expect in the response headers")); 1955 printf(" %s\n", _("String to expect in the response headers"));
2039 printf (" %s\n", "-s, --string=STRING"); 1956 printf(" %s\n", "-s, --string=STRING");
2040 printf (" %s\n", _("String to expect in the content")); 1957 printf(" %s\n", _("String to expect in the content"));
2041 printf (" %s\n", "-u, --url=PATH"); 1958 printf(" %s\n", "-u, --url=PATH");
2042 printf (" %s\n", _("URL to GET or POST (default: /)")); 1959 printf(" %s\n", _("URL to GET or POST (default: /)"));
2043 printf (" %s\n", "-P, --post=STRING"); 1960 printf(" %s\n", "-P, --post=STRING");
2044 printf (" %s\n", _("URL decoded http POST data")); 1961 printf(" %s\n", _("URL decoded http POST data"));
2045 printf (" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)"); 1962 printf(" %s\n", "-j, --method=STRING (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT)");
2046 printf (" %s\n", _("Set HTTP method.")); 1963 printf(" %s\n", _("Set HTTP method."));
2047 printf (" %s\n", "-N, --no-body"); 1964 printf(" %s\n", "-N, --no-body");
2048 printf (" %s\n", _("Don't wait for document body: stop reading after headers.")); 1965 printf(" %s\n", _("Don't wait for document body: stop reading after headers."));
2049 printf (" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)")); 1966 printf(" %s\n", _("(Note that this still does an HTTP GET or POST, not a HEAD.)"));
2050 printf (" %s\n", "-M, --max-age=SECONDS"); 1967 printf(" %s\n", "-M, --max-age=SECONDS");
2051 printf (" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); 1968 printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of"));
2052 printf (" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); 1969 printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days."));
2053 printf (" %s\n", "-T, --content-type=STRING"); 1970 printf(" %s\n", "-T, --content-type=STRING");
2054 printf (" %s\n", _("specify Content-Type header media type when POSTing\n")); 1971 printf(" %s\n", _("specify Content-Type header media type when POSTing\n"));
2055 printf (" %s\n", "-l, --linespan"); 1972 printf(" %s\n", "-l, --linespan");
2056 printf (" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); 1973 printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)"));
2057 printf (" %s\n", "-r, --regex, --ereg=STRING"); 1974 printf(" %s\n", "-r, --regex, --ereg=STRING");
2058 printf (" %s\n", _("Search page for regex STRING")); 1975 printf(" %s\n", _("Search page for regex STRING"));
2059 printf (" %s\n", "-R, --eregi=STRING"); 1976 printf(" %s\n", "-R, --eregi=STRING");
2060 printf (" %s\n", _("Search page for case-insensitive regex STRING")); 1977 printf(" %s\n", _("Search page for case-insensitive regex STRING"));
2061 printf (" %s\n", "--invert-regex"); 1978 printf(" %s\n", "--invert-regex");
2062 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1979 printf(" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
2063 printf (" %s\n", _("can be changed with --state--regex)")); 1980 printf(" %s\n", _("can be changed with --state--regex)"));
2064 printf (" %s\n", "--regex-state=STATE"); 1981 printf(" %s\n", "--state-regex=STATE");
2065 printf (" %s\n", _("Return STATE if regex is found, OK if not\n")); 1982 printf(" %s\n", _("Return STATE if regex is found, OK if not. STATE can be one of \"critical\",\"warning\""));
2066 printf (" %s\n", "-a, --authorization=AUTH_PAIR"); 1983 printf(" %s\n", "-a, --authorization=AUTH_PAIR");
2067 printf (" %s\n", _("Username:password on sites with basic authentication")); 1984 printf(" %s\n", _("Username:password on sites with basic authentication"));
2068 printf (" %s\n", "-b, --proxy-authorization=AUTH_PAIR"); 1985 printf(" %s\n", "-b, --proxy-authorization=AUTH_PAIR");
2069 printf (" %s\n", _("Username:password on proxy-servers with basic authentication")); 1986 printf(" %s\n", _("Username:password on proxy-servers with basic authentication"));
2070 printf (" %s\n", "-A, --useragent=STRING"); 1987 printf(" %s\n", "-A, --useragent=STRING");
2071 printf (" %s\n", _("String to be sent in http header as \"User Agent\"")); 1988 printf(" %s\n", _("String to be sent in http header as \"User Agent\""));
2072 printf (" %s\n", "-k, --header=STRING"); 1989 printf(" %s\n", "-k, --header=STRING");
2073 printf (" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers")); 1990 printf(" %s\n", _("Any other tags to be sent in http header. Use multiple times for additional headers"));
2074 printf (" %s\n", "-E, --extended-perfdata"); 1991 printf(" %s\n", "-E, --extended-perfdata");
2075 printf (" %s\n", _("Print additional performance data")); 1992 printf(" %s\n", _("Print additional performance data"));
2076 printf (" %s\n", "-B, --show-body"); 1993 printf(" %s\n", "-B, --show-body");
2077 printf (" %s\n", _("Print body content below status line")); 1994 printf(" %s\n", _("Print body content below status line"));
2078 printf (" %s\n", "-L, --link"); 1995 printf(" %s\n", "-L, --link");
2079 printf (" %s\n", _("Wrap output in HTML link (obsoleted by urlize)")); 1996 printf(" %s\n", _("Wrap output in HTML link (obsoleted by urlize)"));
2080 printf (" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>"); 1997 printf(" %s\n", "-f, --onredirect=<ok|warning|critical|follow|sticky|stickyport|curl>");
2081 printf (" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the")); 1998 printf(" %s\n", _("How to handle redirected pages. sticky is like follow but stick to the"));
2082 printf (" %s\n", _("specified IP address. stickyport also ensures port stays the same.")); 1999 printf(" %s\n", _("specified IP address. stickyport also ensures port stays the same."));
2083 printf (" %s\n", _("follow uses the old redirection algorithm of check_http.")); 2000 printf(" %s\n", _("follow uses the old redirection algorithm of check_http."));
2084 printf (" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl.")); 2001 printf(" %s\n", _("curl uses CURL_FOLLOWLOCATION built into libcurl."));
2085 printf (" %s\n", "--max-redirs=INTEGER"); 2002 printf(" %s\n", "--max-redirs=INTEGER");
2086 printf (" %s", _("Maximal number of redirects (default: ")); 2003 printf(" %s", _("Maximal number of redirects (default: "));
2087 printf ("%d)\n", DEFAULT_MAX_REDIRS); 2004 printf("%d)\n", DEFAULT_MAX_REDIRS);
2088 printf (" %s\n", "-m, --pagesize=INTEGER<:INTEGER>"); 2005 printf(" %s\n", "-m, --pagesize=INTEGER<:INTEGER>");
2089 printf (" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)")); 2006 printf(" %s\n", _("Minimum page size required (bytes) : Maximum page size required (bytes)"));
2090 printf ("\n"); 2007 printf("\n");
2091 printf (" %s\n", "--http-version=VERSION"); 2008 printf(" %s\n", "--http-version=VERSION");
2092 printf (" %s\n", _("Connect via specific HTTP protocol.")); 2009 printf(" %s\n", _("Connect via specific HTTP protocol."));
2093 printf (" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)")); 2010 printf(" %s\n", _("1.0 = HTTP/1.0, 1.1 = HTTP/1.1, 2.0 = HTTP/2 (HTTP/2 will fail without -S)"));
2094 printf (" %s\n", "--enable-automatic-decompression"); 2011 printf(" %s\n", "--enable-automatic-decompression");
2095 printf (" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING).")); 2012 printf(" %s\n", _("Enable automatic decompression of body (CURLOPT_ACCEPT_ENCODING)."));
2096 printf(" %s\n", "--haproxy-protocol"); 2013 printf(" %s\n", "--haproxy-protocol");
2097 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL).")); 2014 printf(" %s\n", _("Send HAProxy proxy protocol v1 header (CURLOPT_HAPROXYPROTOCOL)."));
2098 printf (" %s\n", "--cookie-jar=FILE"); 2015 printf(" %s\n", "--cookie-jar=FILE");
2099 printf (" %s\n", _("Store cookies in the cookie jar and send them out when requested.")); 2016 printf(" %s\n", _("Store cookies in the cookie jar and send them out when requested."));
2100 printf ("\n"); 2017 printf(" %s\n", _("Specify an empty string as FILE to enable curl's cookie engine without saving"));
2101 2018 printf(" %s\n", _("the cookies to disk. Only enabling the engine without saving to disk requires"));
2102 printf (UT_WARN_CRIT); 2019 printf(" %s\n", _("handling multiple requests internally to curl, so use it with --onredirect=curl"));
2103 2020 printf("\n");
2104 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 2021
2105 2022 printf(UT_WARN_CRIT);
2106 printf (UT_VERBOSE); 2023
2107 2024 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
2108 printf ("\n"); 2025
2109 printf ("%s\n", _("Notes:")); 2026 printf(UT_VERBOSE);
2110 printf (" %s\n", _("This plugin will attempt to open an HTTP connection with the host.")); 2027
2111 printf (" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL")); 2028 printf("\n");
2112 printf (" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response")); 2029 printf("%s\n", _("Notes:"));
2113 printf (" %s\n", _("messages from the host result in STATE_WARNING return values. If you are")); 2030 printf(" %s\n", _("This plugin will attempt to open an HTTP connection with the host."));
2114 printf (" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN")); 2031 printf(" %s\n", _("Successful connects return STATE_OK, refusals and timeouts return STATE_CRITICAL"));
2115 printf (" %s\n", _("(fully qualified domain name) as the [host_name] argument.")); 2032 printf(" %s\n", _("other errors return STATE_UNKNOWN. Successful connects, but incorrect response"));
2033 printf(" %s\n", _("messages from the host result in STATE_WARNING return values. If you are"));
2034 printf(" %s\n", _("checking a virtual server that uses 'host headers' you must supply the FQDN"));
2035 printf(" %s\n", _("(fully qualified domain name) as the [host_name] argument."));
2116 2036
2117#ifdef LIBCURL_FEATURE_SSL 2037#ifdef LIBCURL_FEATURE_SSL
2118 printf ("\n"); 2038 printf("\n");
2119 printf (" %s\n", _("This plugin can also check whether an SSL enabled web server is able to")); 2039 printf(" %s\n", _("This plugin can also check whether an SSL enabled web server is able to"));
2120 printf (" %s\n", _("serve content (optionally within a specified time) or whether the X509 ")); 2040 printf(" %s\n", _("serve content (optionally within a specified time) or whether the X509 "));
2121 printf (" %s\n", _("certificate is still valid for the specified number of days.")); 2041 printf(" %s\n", _("certificate is still valid for the specified number of days."));
2122 printf ("\n"); 2042 printf("\n");
2123 printf (" %s\n", _("Please note that this plugin does not check if the presented server")); 2043 printf(" %s\n", _("Please note that this plugin does not check if the presented server"));
2124 printf (" %s\n", _("certificate matches the hostname of the server, or if the certificate")); 2044 printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate"));
2125 printf (" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); 2045 printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs."));
2126 printf ("\n"); 2046 printf("\n");
2127 printf ("%s\n", _("Examples:")); 2047 printf("%s\n", _("Examples:"));
2128 printf (" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com"); 2048 printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com");
2129 printf (" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); 2049 printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,"));
2130 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 2050 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2131 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 2051 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2132 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 2052 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2133 printf ("\n"); 2053 printf("\n");
2134 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14"); 2054 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14");
2135 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); 2055 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 14 days,"));
2136 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 2056 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2137 printf (" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); 2057 printf(" %s\n", _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when"));
2138 printf (" %s\n\n", _("the certificate is expired.")); 2058 printf(" %s\n\n", _("the certificate is expired."));
2139 printf ("\n"); 2059 printf("\n");
2140 printf (" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14"); 2060 printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14");
2141 printf (" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); 2061 printf(" %s\n", _("When the certificate of 'www.verisign.com' is valid for more than 30 days,"));
2142 printf (" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than")); 2062 printf(" %s\n", _("a STATE_OK is returned. When the certificate is still valid, but for less than"));
2143 printf (" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned.")); 2063 printf(" %s\n", _("30 days, but more than 14 days, a STATE_WARNING is returned."));
2144 printf (" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days")); 2064 printf(" %s\n", _("A STATE_CRITICAL will be returned when certificate expires in less than 14 days"));
2145#endif 2065#endif
2146 2066
2147 printf ("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:"); 2067 printf("\n %s\n", "CHECK WEBSERVER CONTENT VIA PROXY:");
2148 printf (" %s\n", _("It is recommended to use an environment proxy like:")); 2068 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2149 printf (" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org")); 2069 printf(" %s\n", _("http_proxy=http://192.168.100.35:3128 ./check_curl -H www.monitoring-plugins.org"));
2150 printf (" %s\n", _("legacy proxy requests in check_http style still work:")); 2070 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2151 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org")); 2071 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u http://www.monitoring-plugins.org/ -H www.monitoring-plugins.org"));
2152 2072
2153#ifdef LIBCURL_FEATURE_SSL 2073#ifdef LIBCURL_FEATURE_SSL
2154 printf ("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: "); 2074 printf("\n %s\n", "CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT: ");
2155 printf (" %s\n", _("It is recommended to use an environment proxy like:")); 2075 printf(" %s\n", _("It is recommended to use an environment proxy like:"));
2156 printf (" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S")); 2076 printf(" %s\n", _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S"));
2157 printf (" %s\n", _("legacy proxy requests in check_http style still work:")); 2077 printf(" %s\n", _("legacy proxy requests in check_http style still work:"));
2158 printf (" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com ")); 2078 printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com "));
2159 printf (" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>")); 2079 printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>"));
2160 printf (" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds")); 2080 printf(" %s\n", _("a STATE_OK will be returned. When the server returns its content but exceeds"));
2161 printf (" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); 2081 printf(" %s\n", _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,"));
2162 printf (" %s\n", _("a STATE_CRITICAL will be returned.")); 2082 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
2163 2083
2164#endif 2084#endif
2165 2085
2166 printf (UT_SUPPORT); 2086 printf(UT_SUPPORT);
2167
2168} 2087}
2169 2088
2170 2089void print_usage(void) {
2171 2090 printf("%s\n", _("Usage:"));
2172void 2091 printf(" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n", progname);
2173print_usage (void) 2092 printf(" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n");
2174{ 2093 printf(" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n");
2175 printf ("%s\n", _("Usage:")); 2094 printf(" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n");
2176 printf (" %s -H <vhost> | -I <IP-address> [-u <uri>] [-p <port>]\n",progname); 2095 printf(" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n");
2177 printf (" [-J <client certificate file>] [-K <private key>] [--ca-cert <CA certificate file>] [-D]\n"); 2096 printf(" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n");
2178 printf (" [-w <warn time>] [-c <critical time>] [-t <timeout>] [-L] [-E] [-a auth]\n"); 2097 printf(" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n");
2179 printf (" [-b proxy_auth] [-f <ok|warning|critical|follow|sticky|stickyport|curl>]\n"); 2098 printf(" [-T <content-type>] [-j method]\n");
2180 printf (" [-e <expect>] [-d string] [-s string] [-l] [-r <regex> | -R <case-insensitive regex>]\n"); 2099 printf(" [--http-version=<version>] [--enable-automatic-decompression]\n");
2181 printf (" [-P string] [-m <min_pg_size>:<max_pg_size>] [-4|-6] [-N] [-M <age>]\n"); 2100 printf(" [--cookie-jar=<cookie jar file>\n");
2182 printf (" [-A string] [-k string] [-S <version>] [--sni] [--haproxy-protocol]\n"); 2101 printf(" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n", progname);
2183 printf (" [-T <content-type>] [-j method]\n"); 2102 printf(" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
2184 printf (" [--http-version=<version>] [--enable-automatic-decompression]\n"); 2103 printf("\n");
2185 printf (" [--cookie-jar=<cookie jar file>\n");
2186 printf (" %s -H <vhost> | -I <IP-address> -C <warn_age>[,<crit_age>]\n",progname);
2187 printf (" [-p <port>] [-t <timeout>] [-4|-6] [--sni]\n");
2188 printf ("\n");
2189#ifdef LIBCURL_FEATURE_SSL 2104#ifdef LIBCURL_FEATURE_SSL
2190 printf ("%s\n", _("In the first form, make an HTTP request.")); 2105 printf("%s\n", _("In the first form, make an HTTP request."));
2191 printf ("%s\n\n", _("In the second form, connect to the server and check the TLS certificate.")); 2106 printf("%s\n\n", _("In the second form, connect to the server and check the TLS certificate."));
2192#endif 2107#endif
2193} 2108}
2194 2109
2195void 2110void print_curl_version(void) { printf("%s\n", curl_version()); }
2196print_curl_version (void)
2197{
2198 printf( "%s\n", curl_version());
2199}
2200 2111
2201int 2112int curlhelp_initwritebuffer(curlhelp_write_curlbuf *buf) {
2202curlhelp_initwritebuffer (curlhelp_write_curlbuf *buf) 2113 buf->bufsize = DEFAULT_BUFFER_SIZE;
2203{ 2114 buf->buflen = 0;
2204 buf->bufsize = DEFAULT_BUFFER_SIZE; 2115 buf->buf = (char *)malloc((size_t)buf->bufsize);
2205 buf->buflen = 0; 2116 if (buf->buf == NULL)
2206 buf->buf = (char *)malloc ((size_t)buf->bufsize); 2117 return -1;
2207 if (buf->buf == NULL) return -1; 2118 return 0;
2208 return 0;
2209} 2119}
2210 2120
2211size_t curlhelp_buffer_write_callback (void *buffer, size_t size, size_t nmemb, void *stream) 2121size_t curlhelp_buffer_write_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2212{ 2122 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2213 curlhelp_write_curlbuf *buf = (curlhelp_write_curlbuf *)stream;
2214 2123
2215 while (buf->bufsize < buf->buflen + size * nmemb + 1) { 2124 while (buf->bufsize < buf->buflen + size * nmemb + 1) {
2216 buf->bufsize = buf->bufsize * 2; 2125 buf->bufsize = buf->bufsize * 2;
2217 buf->buf = (char *)realloc (buf->buf, buf->bufsize); 2126 buf->buf = (char *)realloc(buf->buf, buf->bufsize);
2218 if (buf->buf == NULL) { 2127 if (buf->buf == NULL) {
2219 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno)); 2128 fprintf(stderr, "malloc failed (%d) %s\n", errno, strerror(errno));
2220 return -1; 2129 return -1;
2221 } 2130 }
2222 } 2131 }
2223 2132
2224 memcpy (buf->buf + buf->buflen, buffer, size * nmemb); 2133 memcpy(buf->buf + buf->buflen, buffer, size * nmemb);
2225 buf->buflen += size * nmemb; 2134 buf->buflen += size * nmemb;
2226 buf->buf[buf->buflen] = '\0'; 2135 buf->buf[buf->buflen] = '\0';
2227 2136
2228 return (int)(size * nmemb); 2137 return (int)(size * nmemb);
2229} 2138}
2230 2139
2231size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) 2140size_t curlhelp_buffer_read_callback(void *buffer, size_t size, size_t nmemb, void *stream) {
2232{ 2141 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2233 curlhelp_read_curlbuf *buf = (curlhelp_read_curlbuf *)stream;
2234 2142
2235 size_t n = min (nmemb * size, buf->buflen - buf->pos); 2143 size_t n = min(nmemb * size, buf->buflen - buf->pos);
2236 2144
2237 memcpy (buffer, buf->buf + buf->pos, n); 2145 memcpy(buffer, buf->buf + buf->pos, n);
2238 buf->pos += n; 2146 buf->pos += n;
2239 2147
2240 return (int)n; 2148 return (int)n;
2241} 2149}
2242 2150
2243void 2151void curlhelp_freewritebuffer(curlhelp_write_curlbuf *buf) {
2244curlhelp_freewritebuffer (curlhelp_write_curlbuf *buf) 2152 free(buf->buf);
2245{ 2153 buf->buf = NULL;
2246 free (buf->buf);
2247 buf->buf = NULL;
2248} 2154}
2249 2155
2250int 2156int curlhelp_initreadbuffer(curlhelp_read_curlbuf *buf, const char *data, size_t datalen) {
2251curlhelp_initreadbuffer (curlhelp_read_curlbuf *buf, const char *data, size_t datalen) 2157 buf->buflen = datalen;
2252{ 2158 buf->buf = (char *)malloc((size_t)buf->buflen);
2253 buf->buflen = datalen; 2159 if (buf->buf == NULL)
2254 buf->buf = (char *)malloc ((size_t)buf->buflen); 2160 return -1;
2255 if (buf->buf == NULL) return -1; 2161 memcpy(buf->buf, data, datalen);
2256 memcpy (buf->buf, data, datalen); 2162 buf->pos = 0;
2257 buf->pos = 0; 2163 return 0;
2258 return 0;
2259} 2164}
2260 2165
2261void 2166void curlhelp_freereadbuffer(curlhelp_read_curlbuf *buf) {
2262curlhelp_freereadbuffer (curlhelp_read_curlbuf *buf) 2167 free(buf->buf);
2263{ 2168 buf->buf = NULL;
2264 free (buf->buf);
2265 buf->buf = NULL;
2266} 2169}
2267 2170
2268/* TODO: where to put this, it's actually part of sstrings2 (logically)? 2171/* TODO: where to put this, it's actually part of sstrings2 (logically)?
2269 */ 2172 */
2270const char* 2173const char *strrstr2(const char *haystack, const char *needle) {
2271strrstr2(const char *haystack, const char *needle) 2174 int counter;
2272{ 2175 size_t len;
2273 int counter; 2176 const char *prev_pos;
2274 size_t len; 2177 const char *pos;
2275 const char *prev_pos; 2178
2276 const char *pos; 2179 if (haystack == NULL || needle == NULL)
2277 2180 return NULL;
2278 if (haystack == NULL || needle == NULL) 2181
2279 return NULL; 2182 if (haystack[0] == '\0' || needle[0] == '\0')
2280 2183 return NULL;
2281 if (haystack[0] == '\0' || needle[0] == '\0') 2184
2282 return NULL; 2185 counter = 0;
2283 2186 prev_pos = NULL;
2284 counter = 0; 2187 pos = haystack;
2285 prev_pos = NULL; 2188 len = strlen(needle);
2286 pos = haystack; 2189 for (;;) {
2287 len = strlen (needle); 2190 pos = strstr(pos, needle);
2288 for (;;) { 2191 if (pos == NULL) {
2289 pos = strstr (pos, needle); 2192 if (counter == 0)
2290 if (pos == NULL) { 2193 return NULL;
2291 if (counter == 0) 2194 return prev_pos;
2292 return NULL; 2195 }
2293 else 2196 counter++;
2294 return prev_pos; 2197 prev_pos = pos;
2295 } 2198 pos += len;
2296 counter++; 2199 if (*pos == '\0')
2297 prev_pos = pos; 2200 return prev_pos;
2298 pos += len; 2201 }
2299 if (*pos == '\0') return prev_pos;
2300 }
2301} 2202}
2302 2203
2303int 2204int curlhelp_parse_statusline(const char *buf, curlhelp_statusline *status_line) {
2304curlhelp_parse_statusline (const char *buf, curlhelp_statusline *status_line) 2205 char *first_line_end;
2305{ 2206 char *p;
2306 char *first_line_end; 2207 size_t first_line_len;
2307 char *p; 2208 char *pp;
2308 size_t first_line_len; 2209 const char *start;
2309 char *pp; 2210 char *first_line_buf;
2310 const char *start; 2211
2311 char *first_line_buf; 2212 /* find last start of a new header */
2312 2213 start = strrstr2(buf, "\r\nHTTP/");
2313 /* find last start of a new header */ 2214 if (start != NULL) {
2314 start = strrstr2 (buf, "\r\nHTTP/"); 2215 start += 2;
2315 if (start != NULL) { 2216 buf = start;
2316 start += 2; 2217 }
2317 buf = start;
2318 }
2319
2320 first_line_end = strstr(buf, "\r\n");
2321 if (first_line_end == NULL) return -1;
2322
2323 first_line_len = (size_t)(first_line_end - buf);
2324 status_line->first_line = (char *)malloc (first_line_len + 1);
2325 if (status_line->first_line == NULL) return -1;
2326 memcpy (status_line->first_line, buf, first_line_len);
2327 status_line->first_line[first_line_len] = '\0';
2328 first_line_buf = strdup( status_line->first_line );
2329
2330 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2331
2332 p = strtok(first_line_buf, "/");
2333 if( p == NULL ) { free( first_line_buf ); return -1; }
2334 if( strcmp( p, "HTTP" ) != 0 ) { free( first_line_buf ); return -1; }
2335
2336 p = strtok( NULL, " " );
2337 if( p == NULL ) { free( first_line_buf ); return -1; }
2338 if( strchr( p, '.' ) != NULL ) {
2339
2340 /* HTTP 1.x case */
2341 strtok( p, "." );
2342 status_line->http_major = (int)strtol( p, &pp, 10 );
2343 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2344 strtok( NULL, " " );
2345 status_line->http_minor = (int)strtol( p, &pp, 10 );
2346 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2347 p += 4; /* 1.x SP */
2348 } else {
2349 /* HTTP 2 case */
2350 status_line->http_major = (int)strtol( p, &pp, 10 );
2351 status_line->http_minor = 0;
2352 p += 2; /* 2 SP */
2353 }
2354
2355 /* status code: "404" or "404.1", then SP */
2356
2357 p = strtok( p, " " );
2358 if( p == NULL ) { free( first_line_buf ); return -1; }
2359 if( strchr( p, '.' ) != NULL ) {
2360 char *ppp;
2361 ppp = strtok( p, "." );
2362 status_line->http_code = (int)strtol( ppp, &pp, 10 );
2363 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2364 ppp = strtok( NULL, "" );
2365 status_line->http_subcode = (int)strtol( ppp, &pp, 10 );
2366 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2367 p += 6; /* 400.1 SP */
2368 } else {
2369 status_line->http_code = (int)strtol( p, &pp, 10 );
2370 status_line->http_subcode = -1;
2371 if( *pp != '\0' ) { free( first_line_buf ); return -1; }
2372 p += 4; /* 400 SP */
2373 }
2374
2375 /* Human readable message: "Not Found" CRLF */
2376
2377 p = strtok( p, "" );
2378 if( p == NULL ) { status_line->msg = ""; return 0; }
2379 status_line->msg = status_line->first_line + ( p - first_line_buf );
2380 free( first_line_buf );
2381
2382 return 0;
2383}
2384 2218
2385void 2219 first_line_end = strstr(buf, "\r\n");
2386curlhelp_free_statusline (curlhelp_statusline *status_line) 2220 if (first_line_end == NULL)
2387{ 2221 return -1;
2388 free (status_line->first_line); 2222
2389} 2223 first_line_len = (size_t)(first_line_end - buf);
2224 status_line->first_line = (char *)malloc(first_line_len + 1);
2225 if (status_line->first_line == NULL)
2226 return -1;
2227 memcpy(status_line->first_line, buf, first_line_len);
2228 status_line->first_line[first_line_len] = '\0';
2229 first_line_buf = strdup(status_line->first_line);
2230
2231 /* protocol and version: "HTTP/x.x" SP or "HTTP/2" SP */
2232
2233 p = strtok(first_line_buf, "/");
2234 if (p == NULL) {
2235 free(first_line_buf);
2236 return -1;
2237 }
2238 if (strcmp(p, "HTTP") != 0) {
2239 free(first_line_buf);
2240 return -1;
2241 }
2242
2243 p = strtok(NULL, " ");
2244 if (p == NULL) {
2245 free(first_line_buf);
2246 return -1;
2247 }
2248 if (strchr(p, '.') != NULL) {
2249
2250 /* HTTP 1.x case */
2251 strtok(p, ".");
2252 status_line->http_major = (int)strtol(p, &pp, 10);
2253 if (*pp != '\0') {
2254 free(first_line_buf);
2255 return -1;
2256 }
2257 strtok(NULL, " ");
2258 status_line->http_minor = (int)strtol(p, &pp, 10);
2259 if (*pp != '\0') {
2260 free(first_line_buf);
2261 return -1;
2262 }
2263 p += 4; /* 1.x SP */
2264 } else {
2265 /* HTTP 2 case */
2266 status_line->http_major = (int)strtol(p, &pp, 10);
2267 status_line->http_minor = 0;
2268 p += 2; /* 2 SP */
2269 }
2390 2270
2391void 2271 /* status code: "404" or "404.1", then SP */
2392remove_newlines (char *s)
2393{
2394 char *p;
2395 2272
2396 for (p = s; *p != '\0'; p++) 2273 p = strtok(p, " ");
2397 if (*p == '\r' || *p == '\n') 2274 if (p == NULL) {
2398 *p = ' '; 2275 free(first_line_buf);
2276 return -1;
2277 }
2278 if (strchr(p, '.') != NULL) {
2279 char *ppp;
2280 ppp = strtok(p, ".");
2281 status_line->http_code = (int)strtol(ppp, &pp, 10);
2282 if (*pp != '\0') {
2283 free(first_line_buf);
2284 return -1;
2285 }
2286 ppp = strtok(NULL, "");
2287 status_line->http_subcode = (int)strtol(ppp, &pp, 10);
2288 if (*pp != '\0') {
2289 free(first_line_buf);
2290 return -1;
2291 }
2292 p += 6; /* 400.1 SP */
2293 } else {
2294 status_line->http_code = (int)strtol(p, &pp, 10);
2295 status_line->http_subcode = -1;
2296 if (*pp != '\0') {
2297 free(first_line_buf);
2298 return -1;
2299 }
2300 p += 4; /* 400 SP */
2301 }
2302
2303 /* Human readable message: "Not Found" CRLF */
2304
2305 p = strtok(p, "");
2306 if (p == NULL) {
2307 status_line->msg = "";
2308 return 0;
2309 }
2310 status_line->msg = status_line->first_line + (p - first_line_buf);
2311 free(first_line_buf);
2312
2313 return 0;
2399} 2314}
2400 2315
2401char * 2316void curlhelp_free_statusline(curlhelp_statusline *status_line) { free(status_line->first_line); }
2402get_header_value (const struct phr_header* headers, const size_t nof_headers, const char* header) 2317
2403{ 2318char *get_header_value(const struct phr_header *headers, const size_t nof_headers, const char *header) {
2404 for(size_t i = 0; i < nof_headers; i++ ) { 2319 for (size_t i = 0; i < nof_headers; i++) {
2405 if(headers[i].name != NULL && strncasecmp( header, headers[i].name, max( headers[i].name_len, 4 ) ) == 0 ) { 2320 if (headers[i].name != NULL && strncasecmp(header, headers[i].name, max(headers[i].name_len, 4)) == 0) {
2406 return strndup( headers[i].value, headers[i].value_len ); 2321 return strndup(headers[i].value, headers[i].value_len);
2407 } 2322 }
2408 } 2323 }
2409 return NULL; 2324 return NULL;
2410} 2325}
2411 2326
2412int 2327int check_document_dates(const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) {
2413check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFAULT_BUFFER_SIZE]) 2328 char *server_date = NULL;
2414{ 2329 char *document_date = NULL;
2415 char *server_date = NULL; 2330 int date_result = STATE_OK;
2416 char *document_date = NULL; 2331 curlhelp_statusline status_line;
2417 int date_result = STATE_OK; 2332 struct phr_header headers[255];
2418 curlhelp_statusline status_line; 2333 size_t nof_headers = 255;
2419 struct phr_header headers[255]; 2334 size_t msglen;
2420 size_t nof_headers = 255; 2335
2421 size_t msglen; 2336 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2422 2337 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2423 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2424 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2425 headers, &nof_headers, 0);
2426 2338
2427 if (res == -1) { 2339 if (res == -1) {
2428 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2340 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2429 } 2341 }
2430 2342
2431 server_date = get_header_value (headers, nof_headers, "date"); 2343 server_date = get_header_value(headers, nof_headers, "date");
2432 document_date = get_header_value (headers, nof_headers, "last-modified"); 2344 document_date = get_header_value(headers, nof_headers, "last-modified");
2433 2345
2434 if (!server_date || !*server_date) { 2346 if (!server_date || !*server_date) {
2435 char tmp[DEFAULT_BUFFER_SIZE]; 2347 char tmp[DEFAULT_BUFFER_SIZE];
2436 2348
2437 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg); 2349 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date unknown, "), *msg);
2438 strcpy(*msg, tmp); 2350 strcpy(*msg, tmp);
2439 2351
2440 date_result = max_state_alt(STATE_UNKNOWN, date_result); 2352 date_result = max_state_alt(STATE_UNKNOWN, date_result);
@@ -2442,34 +2354,34 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2442 } else if (!document_date || !*document_date) { 2354 } else if (!document_date || !*document_date) {
2443 char tmp[DEFAULT_BUFFER_SIZE]; 2355 char tmp[DEFAULT_BUFFER_SIZE];
2444 2356
2445 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg); 2357 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument modification date unknown, "), *msg);
2446 strcpy(*msg, tmp); 2358 strcpy(*msg, tmp);
2447 2359
2448 date_result = max_state_alt(STATE_CRITICAL, date_result); 2360 date_result = max_state_alt(STATE_CRITICAL, date_result);
2449 2361
2450 } else { 2362 } else {
2451 time_t srv_data = curl_getdate (server_date, NULL); 2363 time_t srv_data = curl_getdate(server_date, NULL);
2452 time_t doc_data = curl_getdate (document_date, NULL); 2364 time_t doc_data = curl_getdate(document_date, NULL);
2453 if (verbose >= 2) 2365 if (verbose >= 2)
2454 printf ("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data); 2366 printf("* server date: '%s' (%d), doc_date: '%s' (%d)\n", server_date, (int)srv_data, document_date, (int)doc_data);
2455 if (srv_data <= 0) { 2367 if (srv_data <= 0) {
2456 char tmp[DEFAULT_BUFFER_SIZE]; 2368 char tmp[DEFAULT_BUFFER_SIZE];
2457 2369
2458 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date); 2370 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sServer date \"%100s\" unparsable, "), *msg, server_date);
2459 strcpy(*msg, tmp); 2371 strcpy(*msg, tmp);
2460 2372
2461 date_result = max_state_alt(STATE_CRITICAL, date_result); 2373 date_result = max_state_alt(STATE_CRITICAL, date_result);
2462 } else if (doc_data <= 0) { 2374 } else if (doc_data <= 0) {
2463 char tmp[DEFAULT_BUFFER_SIZE]; 2375 char tmp[DEFAULT_BUFFER_SIZE];
2464 2376
2465 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date); 2377 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument date \"%100s\" unparsable, "), *msg, document_date);
2466 strcpy(*msg, tmp); 2378 strcpy(*msg, tmp);
2467 2379
2468 date_result = max_state_alt(STATE_CRITICAL, date_result); 2380 date_result = max_state_alt(STATE_CRITICAL, date_result);
2469 } else if (doc_data > srv_data + 30) { 2381 } else if (doc_data > srv_data + 30) {
2470 char tmp[DEFAULT_BUFFER_SIZE]; 2382 char tmp[DEFAULT_BUFFER_SIZE];
2471 2383
2472 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data); 2384 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sDocument is %d seconds in the future, "), *msg, (int)doc_data - (int)srv_data);
2473 strcpy(*msg, tmp); 2385 strcpy(*msg, tmp);
2474 2386
2475 date_result = max_state_alt(STATE_CRITICAL, date_result); 2387 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2478,14 +2390,14 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2478 if (n > (60 * 60 * 24 * 2)) { 2390 if (n > (60 * 60 * 24 * 2)) {
2479 char tmp[DEFAULT_BUFFER_SIZE]; 2391 char tmp[DEFAULT_BUFFER_SIZE];
2480 2392
2481 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float) n) / (60 * 60 * 24)); 2393 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %.1f days ago, "), *msg, ((float)n) / (60 * 60 * 24));
2482 strcpy(*msg, tmp); 2394 strcpy(*msg, tmp);
2483 2395
2484 date_result = max_state_alt(STATE_CRITICAL, date_result); 2396 date_result = max_state_alt(STATE_CRITICAL, date_result);
2485 } else { 2397 } else {
2486 char tmp[DEFAULT_BUFFER_SIZE]; 2398 char tmp[DEFAULT_BUFFER_SIZE];
2487 2399
2488 snprintf (tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60); 2400 snprintf(tmp, DEFAULT_BUFFER_SIZE, _("%sLast modified %d:%02d:%02d ago, "), *msg, n / (60 * 60), (n / 60) % 60, n % 60);
2489 strcpy(*msg, tmp); 2401 strcpy(*msg, tmp);
2490 2402
2491 date_result = max_state_alt(STATE_CRITICAL, date_result); 2403 date_result = max_state_alt(STATE_CRITICAL, date_result);
@@ -2493,132 +2405,128 @@ check_document_dates (const curlhelp_write_curlbuf *header_buf, char (*msg)[DEFA
2493 } 2405 }
2494 } 2406 }
2495 2407
2496 if (server_date) free (server_date); 2408 if (server_date)
2497 if (document_date) free (document_date); 2409 free(server_date);
2410 if (document_date)
2411 free(document_date);
2498 2412
2499 return date_result; 2413 return date_result;
2500} 2414}
2501 2415
2416int get_content_length(const curlhelp_write_curlbuf *header_buf, const curlhelp_write_curlbuf *body_buf) {
2417 size_t content_length = 0;
2418 struct phr_header headers[255];
2419 size_t nof_headers = 255;
2420 size_t msglen;
2421 char *content_length_s = NULL;
2422 curlhelp_statusline status_line;
2502 2423
2503int 2424 int res = phr_parse_response(header_buf->buf, header_buf->buflen, &status_line.http_major, &status_line.http_minor,
2504get_content_length (const curlhelp_write_curlbuf* header_buf, const curlhelp_write_curlbuf* body_buf) 2425 &status_line.http_code, &status_line.msg, &msglen, headers, &nof_headers, 0);
2505{
2506 size_t content_length = 0;
2507 struct phr_header headers[255];
2508 size_t nof_headers = 255;
2509 size_t msglen;
2510 char *content_length_s = NULL;
2511 curlhelp_statusline status_line;
2512
2513 int res = phr_parse_response (header_buf->buf, header_buf->buflen,
2514 &status_line.http_major, &status_line.http_minor, &status_line.http_code, &status_line.msg, &msglen,
2515 headers, &nof_headers, 0);
2516 2426
2517 if (res == -1) { 2427 if (res == -1) {
2518 die (STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n")); 2428 die(STATE_UNKNOWN, _("HTTP UNKNOWN - Failed to parse Response\n"));
2519 } 2429 }
2520 2430
2521 content_length_s = get_header_value (headers, nof_headers, "content-length"); 2431 content_length_s = get_header_value(headers, nof_headers, "content-length");
2522 if (!content_length_s) { 2432 if (!content_length_s) {
2523 return header_buf->buflen + body_buf->buflen; 2433 return header_buf->buflen + body_buf->buflen;
2524 } 2434 }
2525 content_length_s += strspn (content_length_s, " \t"); 2435 content_length_s += strspn(content_length_s, " \t");
2526 content_length = atoi (content_length_s); 2436 content_length = atoi(content_length_s);
2527 if (content_length != body_buf->buflen) { 2437 if (content_length != body_buf->buflen) {
2528 /* TODO: should we warn if the actual and the reported body length don't match? */ 2438 /* TODO: should we warn if the actual and the reported body length don't match? */
2529 } 2439 }
2530 2440
2531 if (content_length_s) free (content_length_s); 2441 if (content_length_s)
2442 free(content_length_s);
2532 2443
2533 return header_buf->buflen + body_buf->buflen; 2444 return header_buf->buflen + body_buf->buflen;
2534} 2445}
2535 2446
2536/* TODO: is there a better way in libcurl to check for the SSL library? */ 2447/* TODO: is there a better way in libcurl to check for the SSL library? */
2537curlhelp_ssl_library 2448curlhelp_ssl_library curlhelp_get_ssl_library(void) {
2538curlhelp_get_ssl_library () 2449 curl_version_info_data *version_data;
2539{ 2450 char *ssl_version;
2540 curl_version_info_data* version_data; 2451 char *library;
2541 char *ssl_version; 2452 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN;
2542 char *library; 2453
2543 curlhelp_ssl_library ssl_library = CURLHELP_SSL_LIBRARY_UNKNOWN; 2454 version_data = curl_version_info(CURLVERSION_NOW);
2544 2455 if (version_data == NULL)
2545 version_data = curl_version_info (CURLVERSION_NOW); 2456 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2546 if (version_data == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2457
2547 2458 ssl_version = strdup(version_data->ssl_version);
2548 ssl_version = strdup (version_data->ssl_version); 2459 if (ssl_version == NULL)
2549 if (ssl_version == NULL ) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2460 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2550 2461
2551 library = strtok (ssl_version, "/"); 2462 library = strtok(ssl_version, "/");
2552 if (library == NULL) return CURLHELP_SSL_LIBRARY_UNKNOWN; 2463 if (library == NULL)
2553 2464 return CURLHELP_SSL_LIBRARY_UNKNOWN;
2554 if (strcmp (library, "OpenSSL") == 0) 2465
2555 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL; 2466 if (strcmp(library, "OpenSSL") == 0)
2556 else if (strcmp (library, "LibreSSL") == 0) 2467 ssl_library = CURLHELP_SSL_LIBRARY_OPENSSL;
2557 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL; 2468 else if (strcmp(library, "LibreSSL") == 0)
2558 else if (strcmp (library, "GnuTLS") == 0) 2469 ssl_library = CURLHELP_SSL_LIBRARY_LIBRESSL;
2559 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS; 2470 else if (strcmp(library, "GnuTLS") == 0)
2560 else if (strcmp (library, "NSS") == 0) 2471 ssl_library = CURLHELP_SSL_LIBRARY_GNUTLS;
2561 ssl_library = CURLHELP_SSL_LIBRARY_NSS; 2472 else if (strcmp(library, "NSS") == 0)
2562 2473 ssl_library = CURLHELP_SSL_LIBRARY_NSS;
2563 if (verbose >= 2) 2474
2564 printf ("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library); 2475 if (verbose >= 2)
2565 2476 printf("* SSL library string is : %s %s (%d)\n", version_data->ssl_version, library, ssl_library);
2566 free (ssl_version); 2477
2567 2478 free(ssl_version);
2568 return ssl_library; 2479
2480 return ssl_library;
2569} 2481}
2570 2482
2571const char* 2483const char *curlhelp_get_ssl_library_string(curlhelp_ssl_library ssl_library) {
2572curlhelp_get_ssl_library_string (curlhelp_ssl_library ssl_library) 2484 switch (ssl_library) {
2573{ 2485 case CURLHELP_SSL_LIBRARY_OPENSSL:
2574 switch (ssl_library) { 2486 return "OpenSSL";
2575 case CURLHELP_SSL_LIBRARY_OPENSSL: 2487 case CURLHELP_SSL_LIBRARY_LIBRESSL:
2576 return "OpenSSL"; 2488 return "LibreSSL";
2577 case CURLHELP_SSL_LIBRARY_LIBRESSL: 2489 case CURLHELP_SSL_LIBRARY_GNUTLS:
2578 return "LibreSSL"; 2490 return "GnuTLS";
2579 case CURLHELP_SSL_LIBRARY_GNUTLS: 2491 case CURLHELP_SSL_LIBRARY_NSS:
2580 return "GnuTLS"; 2492 return "NSS";
2581 case CURLHELP_SSL_LIBRARY_NSS: 2493 case CURLHELP_SSL_LIBRARY_UNKNOWN:
2582 return "NSS"; 2494 default:
2583 case CURLHELP_SSL_LIBRARY_UNKNOWN: 2495 return "unknown";
2584 default: 2496 }
2585 return "unknown";
2586 }
2587} 2497}
2588 2498
2589#ifdef LIBCURL_FEATURE_SSL 2499#ifdef LIBCURL_FEATURE_SSL
2590#ifndef USE_OPENSSL 2500# ifndef USE_OPENSSL
2591time_t 2501time_t parse_cert_date(const char *s) {
2592parse_cert_date (const char *s) 2502 struct tm tm;
2593{ 2503 time_t date;
2594 struct tm tm; 2504 char *res;
2595 time_t date; 2505
2596 char *res; 2506 if (!s)
2597 2507 return -1;
2598 if (!s) return -1; 2508
2599 2509 /* Jan 17 14:25:12 2020 GMT */
2600 /* Jan 17 14:25:12 2020 GMT */ 2510 res = strptime(s, "%Y-%m-%d %H:%M:%S GMT", &tm);
2601 res = strptime (s, "%Y-%m-%d %H:%M:%S GMT", &tm); 2511 /* Sep 11 12:00:00 2020 GMT */
2602 /* Sep 11 12:00:00 2020 GMT */ 2512 if (res == NULL)
2603 if (res == NULL) strptime (s, "%Y %m %d %H:%M:%S GMT", &tm); 2513 strptime(s, "%Y %m %d %H:%M:%S GMT", &tm);
2604 date = mktime (&tm); 2514 date = mktime(&tm);
2605 2515
2606 return date; 2516 return date;
2607} 2517}
2608 2518
2609/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to 2519/* TODO: this needs cleanup in the sslutils.c, maybe we the #else case to
2610 * OpenSSL could be this function 2520 * OpenSSL could be this function
2611 */ 2521 */
2612int 2522int net_noopenssl_check_certificate(cert_ptr_union *cert_ptr, int days_till_exp_warn, int days_till_exp_crit) {
2613net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_warn, int days_till_exp_crit) 2523 int i;
2614{ 2524 struct curl_slist *slist;
2615 int i; 2525 int cname_found = 0;
2616 struct curl_slist* slist; 2526 char *start_date_str = NULL;
2617 int cname_found = 0; 2527 char *end_date_str = NULL;
2618 char* start_date_str = NULL; 2528 time_t start_date;
2619 char* end_date_str = NULL; 2529 time_t end_date;
2620 time_t start_date;
2621 time_t end_date;
2622 char *tz; 2530 char *tz;
2623 float time_left; 2531 float time_left;
2624 int days_left; 2532 int days_left;
@@ -2626,66 +2534,64 @@ net_noopenssl_check_certificate (cert_ptr_union* cert_ptr, int days_till_exp_war
2626 char timestamp[50] = ""; 2534 char timestamp[50] = "";
2627 int status = STATE_UNKNOWN; 2535 int status = STATE_UNKNOWN;
2628 2536
2629 if (verbose >= 2) 2537 if (verbose >= 2)
2630 printf ("**** REQUEST CERTIFICATES ****\n"); 2538 printf("**** REQUEST CERTIFICATES ****\n");
2631 2539
2632 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) { 2540 for (i = 0; i < cert_ptr->to_certinfo->num_of_certs; i++) {
2633 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) { 2541 for (slist = cert_ptr->to_certinfo->certinfo[i]; slist; slist = slist->next) {
2634 /* find first common name in subject, 2542 /* find first common name in subject,
2635 * TODO: check alternative subjects for 2543 * TODO: check alternative subjects for
2636 * TODO: have a decent parser here and not a hack 2544 * TODO: have a decent parser here and not a hack
2637 * multi-host certificate, check wildcards 2545 * multi-host certificate, check wildcards
2638 */ 2546 */
2639 if (strncasecmp (slist->data, "Subject:", 8) == 0) { 2547 if (strncasecmp(slist->data, "Subject:", 8) == 0) {
2640 int d = 3; 2548 int d = 3;
2641 char* p = strstr (slist->data, "CN="); 2549 char *p = strstr(slist->data, "CN=");
2642 if (p == NULL) { 2550 if (p == NULL) {
2643 d = 5; 2551 d = 5;
2644 p = strstr (slist->data, "CN = "); 2552 p = strstr(slist->data, "CN = ");
2645 } 2553 }
2646 if (p != NULL) { 2554 if (p != NULL) {
2647 if (strncmp (host_name, p+d, strlen (host_name)) == 0) { 2555 if (strncmp(host_name, p + d, strlen(host_name)) == 0) {
2648 cname_found = 1; 2556 cname_found = 1;
2649 } 2557 }
2650 } 2558 }
2651 } else if (strncasecmp (slist->data, "Start Date:", 11) == 0) { 2559 } else if (strncasecmp(slist->data, "Start Date:", 11) == 0) {
2652 start_date_str = &slist->data[11]; 2560 start_date_str = &slist->data[11];
2653 } else if (strncasecmp (slist->data, "Expire Date:", 12) == 0) { 2561 } else if (strncasecmp(slist->data, "Expire Date:", 12) == 0) {
2654 end_date_str = &slist->data[12]; 2562 end_date_str = &slist->data[12];
2655 } else if (strncasecmp (slist->data, "Cert:", 5) == 0) { 2563 } else if (strncasecmp(slist->data, "Cert:", 5) == 0) {
2656 goto HAVE_FIRST_CERT; 2564 goto HAVE_FIRST_CERT;
2657 } 2565 }
2658 if (verbose >= 2) 2566 if (verbose >= 2)
2659 printf ("%d ** %s\n", i, slist->data); 2567 printf("%d ** %s\n", i, slist->data);
2660 } 2568 }
2661 } 2569 }
2662HAVE_FIRST_CERT: 2570HAVE_FIRST_CERT:
2663 2571
2664 if (verbose >= 2) 2572 if (verbose >= 2)
2665 printf ("**** REQUEST CERTIFICATES ****\n"); 2573 printf("**** REQUEST CERTIFICATES ****\n");
2666 2574
2667 if (!cname_found) { 2575 if (!cname_found) {
2668 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject.")); 2576 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
2669 return STATE_CRITICAL; 2577 return STATE_CRITICAL;
2670 } 2578 }
2671 2579
2672 start_date = parse_cert_date (start_date_str); 2580 start_date = parse_cert_date(start_date_str);
2673 if (start_date <= 0) { 2581 if (start_date <= 0) {
2674 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), 2582 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Start Date' in certificate: '%s'"), start_date_str);
2675 start_date_str); 2583 puts(msg);
2676 puts (msg); 2584 return STATE_WARNING;
2677 return STATE_WARNING; 2585 }
2678 } 2586
2679 2587 end_date = parse_cert_date(end_date_str);
2680 end_date = parse_cert_date (end_date_str); 2588 if (end_date <= 0) {
2681 if (end_date <= 0) { 2589 snprintf(msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), start_date_str);
2682 snprintf (msg, DEFAULT_BUFFER_SIZE, _("WARNING - Unparsable 'Expire Date' in certificate: '%s'"), 2590 puts(msg);
2683 start_date_str); 2591 return STATE_WARNING;
2684 puts (msg); 2592 }
2685 return STATE_WARNING; 2593
2686 } 2594 time_left = difftime(end_date, time(NULL));
2687
2688 time_left = difftime (end_date, time(NULL));
2689 days_left = time_left / 86400; 2595 days_left = time_left / 86400;
2690 tz = getenv("TZ"); 2596 tz = getenv("TZ");
2691 setenv("TZ", "GMT", 1); 2597 setenv("TZ", "GMT", 1);
@@ -2698,30 +2604,31 @@ HAVE_FIRST_CERT:
2698 tzset(); 2604 tzset();
2699 2605
2700 if (days_left > 0 && days_left <= days_till_exp_warn) { 2606 if (days_left > 0 && days_left <= days_till_exp_warn) {
2701 printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, days_left, timestamp); 2607 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL",
2608 host_name, days_left, timestamp);
2702 if (days_left > days_till_exp_crit) 2609 if (days_left > days_till_exp_crit)
2703 status = STATE_WARNING; 2610 status = STATE_WARNING;
2704 else 2611 else
2705 status = STATE_CRITICAL; 2612 status = STATE_CRITICAL;
2706 } else if (days_left == 0 && time_left > 0) { 2613 } else if (days_left == 0 && time_left > 0) {
2707 if (time_left >= 3600) 2614 if (time_left >= 3600)
2708 time_remaining = (int) time_left / 3600; 2615 time_remaining = (int)time_left / 3600;
2709 else 2616 else
2710 time_remaining = (int) time_left / 60; 2617 time_remaining = (int)time_left / 60;
2711 2618
2712 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), 2619 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2713 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name, time_remaining, 2620 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
2714 time_left >= 3600 ? "hours" : "minutes", timestamp);
2715 2621
2716 if ( days_left > days_till_exp_crit) 2622 if (days_left > days_till_exp_crit)
2717 status = STATE_WARNING; 2623 status = STATE_WARNING;
2718 else 2624 else
2719 status = STATE_CRITICAL; 2625 status = STATE_CRITICAL;
2720 } else if (time_left < 0) { 2626 } else if (time_left < 0) {
2721 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp); 2627 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), host_name, timestamp);
2722 status=STATE_CRITICAL; 2628 status = STATE_CRITICAL;
2723 } else if (days_left == 0) { 2629 } else if (days_left == 0) {
2724 printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", host_name, timestamp); 2630 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", host_name,
2631 timestamp);
2725 if (days_left > days_till_exp_crit) 2632 if (days_left > days_till_exp_crit)
2726 status = STATE_WARNING; 2633 status = STATE_WARNING;
2727 else 2634 else
@@ -2732,5 +2639,5 @@ HAVE_FIRST_CERT:
2732 } 2639 }
2733 return status; 2640 return status;
2734} 2641}
2735#endif /* USE_OPENSSL */ 2642# endif /* USE_OPENSSL */
2736#endif /* LIBCURL_FEATURE_SSL */ 2643#endif /* LIBCURL_FEATURE_SSL */
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 29c85206..9efcd1cb 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -1,38 +1,40 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dbi plugin 3 * Monitoring check_dbi plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2011 Monitoring Plugins Development Team 6 * Copyright (c) 2011-2024 Monitoring Plugins Development Team
7* Author: Sebastian 'tokkee' Harl <sh@teamix.net> 7 * Original Author: Sebastian 'tokkee' Harl <sh@teamix.net>
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_dbi plugin 11 * This file contains the check_dbi plugin
12* 12 *
13* Runs an arbitrary (SQL) command and checks the result. 13 * Runs an arbitrary (SQL) command and checks the result.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_dbi"; 32const char *progname = "check_dbi";
33const char *copyright = "2011"; 33const char *copyright = "2011-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "../lib/monitoringplug.h"
37#include "check_dbi.d/config.h"
36#include "common.h" 38#include "common.h"
37#include "utils.h" 39#include "utils.h"
38#include "utils_cmd.h" 40#include "utils_cmd.h"
@@ -43,7 +45,7 @@ const char *email = "devel@monitoring-plugins.org";
43 45
44/* required for NAN */ 46/* required for NAN */
45#ifndef _ISOC99_SOURCE 47#ifndef _ISOC99_SOURCE
46#define _ISOC99_SOURCE 48# define _ISOC99_SOURCE
47#endif 49#endif
48 50
49#include <assert.h> 51#include <assert.h>
@@ -53,59 +55,26 @@ const char *email = "devel@monitoring-plugins.org";
53 55
54#include <stdarg.h> 56#include <stdarg.h>
55 57
56typedef enum { 58static int verbose = 0;
57 METRIC_CONN_TIME,
58 METRIC_SERVER_VERSION,
59 METRIC_QUERY_RESULT,
60 METRIC_QUERY_TIME,
61} np_dbi_metric_t;
62
63typedef enum {
64 TYPE_NUMERIC,
65 TYPE_STRING,
66} np_dbi_type_t;
67 59
68typedef struct { 60typedef struct {
69 char *key; 61 int errorcode;
70 char *value; 62 check_dbi_config config;
71} driver_option_t; 63} check_dbi_config_wrapper;
72
73char *host = NULL;
74int verbose = 0;
75
76char *warning_range = NULL;
77char *critical_range = NULL;
78thresholds *dbi_thresholds = NULL;
79
80char *expect = NULL;
81
82regex_t expect_re;
83char *expect_re_str = NULL;
84int expect_re_cflags = 0;
85
86np_dbi_metric_t metric = METRIC_QUERY_RESULT;
87np_dbi_type_t type = TYPE_NUMERIC;
88 64
89char *np_dbi_driver = NULL; 65static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
90driver_option_t *np_dbi_options = NULL; 66static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/);
91int np_dbi_options_num = 0; 67void print_usage(void);
92char *np_dbi_database = NULL; 68static void print_help(void);
93char *np_dbi_query = NULL;
94 69
95int process_arguments (int, char **); 70static double timediff(struct timeval /*start*/, struct timeval /*end*/);
96int validate_arguments (void);
97void print_usage (void);
98void print_help (void);
99 71
100double timediff (struct timeval, struct timeval); 72static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
101 73
102void np_dbi_print_error (dbi_conn, char *, ...); 74static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/,
75 mp_dbi_type /*type*/, char * /*np_dbi_query*/);
103 76
104int do_query (dbi_conn, const char **, double *, double *); 77int main(int argc, char **argv) {
105
106int
107main (int argc, char **argv)
108{
109 int status = STATE_UNKNOWN; 78 int status = STATE_UNKNOWN;
110 79
111 dbi_driver driver; 80 dbi_driver driver;
@@ -113,714 +82,725 @@ main (int argc, char **argv)
113 82
114 unsigned int server_version; 83 unsigned int server_version;
115 84
116 struct timeval start_timeval, end_timeval; 85 struct timeval start_timeval;
86 struct timeval end_timeval;
117 double conn_time = 0.0; 87 double conn_time = 0.0;
118 double query_time = 0.0; 88 double query_time = 0.0;
119 89
120 const char *query_val_str = NULL; 90 const char *query_val_str = NULL;
121 double query_val = 0.0; 91 double query_val = 0.0;
122 92
123 int i; 93 setlocale(LC_ALL, "");
124 94 bindtextdomain(PACKAGE, LOCALEDIR);
125 setlocale (LC_ALL, ""); 95 textdomain(PACKAGE);
126 bindtextdomain (PACKAGE, LOCALEDIR);
127 textdomain (PACKAGE);
128 96
129 /* Parse extra opts if any */ 97 /* Parse extra opts if any */
130 argv = np_extra_opts (&argc, argv, progname); 98 argv = np_extra_opts(&argc, argv, progname);
99
100 check_dbi_config_wrapper tmp = process_arguments(argc, argv);
101
102 if (tmp.errorcode == ERROR) {
103 usage4(_("Could not parse arguments"));
104 }
131 105
132 if (process_arguments (argc, argv) == ERROR) 106 const check_dbi_config config = tmp.config;
133 usage4 (_("Could not parse arguments"));
134 107
135 /* Set signal handling and alarm */ 108 /* Set signal handling and alarm */
136 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 109 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
137 usage4 (_("Cannot catch SIGALRM")); 110 usage4(_("Cannot catch SIGALRM"));
138 } 111 }
139 alarm (timeout_interval); 112 alarm(timeout_interval);
140 113
141 if (verbose > 2) 114 if (verbose > 2) {
142 printf ("Initializing DBI\n"); 115 printf("Initializing DBI\n");
116 }
143 117
144 dbi_inst *instance_p = { 0 }; 118 dbi_inst *instance_p = {0};
145 119
146 if (dbi_initialize_r(NULL, instance_p) < 0) { 120 if (dbi_initialize_r(NULL, instance_p) < 0) {
147 printf ("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n"); 121 printf("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n");
148 return STATE_UNKNOWN; 122 return STATE_UNKNOWN;
149 } 123 }
150 124
151 if (instance_p == NULL) { 125 if (instance_p == NULL) {
152 printf ("UNKNOWN - failed to initialize DBI.\n"); 126 printf("UNKNOWN - failed to initialize DBI.\n");
153 return STATE_UNKNOWN; 127 return STATE_UNKNOWN;
154 } 128 }
155 129
156 if (verbose) 130 if (verbose) {
157 printf ("Opening DBI driver '%s'\n", np_dbi_driver); 131 printf("Opening DBI driver '%s'\n", config.dbi_driver);
132 }
158 133
159 driver = dbi_driver_open_r(np_dbi_driver, instance_p); 134 driver = dbi_driver_open_r(config.dbi_driver, instance_p);
160 if (! driver) { 135 if (!driver) {
161 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", 136 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
162 np_dbi_driver);
163 137
164 printf ("Known drivers:\n"); 138 printf("Known drivers:\n");
165 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) { 139 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) {
166 printf (" - %s\n", dbi_driver_get_name (driver)); 140 printf(" - %s\n", dbi_driver_get_name(driver));
167 } 141 }
168 return STATE_UNKNOWN; 142 return STATE_UNKNOWN;
169 } 143 }
170 144
171 /* make a connection to the database */ 145 /* make a connection to the database */
172 gettimeofday (&start_timeval, NULL); 146 gettimeofday(&start_timeval, NULL);
173 147
174 conn = dbi_conn_open (driver); 148 conn = dbi_conn_open(driver);
175 if (! conn) { 149 if (!conn) {
176 printf ("UNKNOWN - failed top open connection object.\n"); 150 printf("UNKNOWN - failed top open connection object.\n");
177 dbi_conn_close (conn); 151 dbi_conn_close(conn);
178 return STATE_UNKNOWN; 152 return STATE_UNKNOWN;
179 } 153 }
180 154
181 for (i = 0; i < np_dbi_options_num; ++i) { 155 for (size_t i = 0; i < config.dbi_options_num; ++i) {
182 const char *opt; 156 const char *opt;
183 157
184 if (verbose > 1) 158 if (verbose > 1) {
185 printf ("Setting DBI driver option '%s' to '%s'\n", 159 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key, config.dbi_options[i].value);
186 np_dbi_options[i].key, np_dbi_options[i].value); 160 }
187 161
188 if (! dbi_conn_set_option (conn, np_dbi_options[i].key, np_dbi_options[i].value)) 162 if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) {
189 continue; 163 continue;
164 }
190 /* else: status != 0 */ 165 /* else: status != 0 */
191 166
192 np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'", 167 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", config.dbi_options[i].key, config.dbi_options[i].value);
193 np_dbi_options[i].key, np_dbi_options[i].value); 168 printf("Known driver options:\n");
194 printf ("Known driver options:\n");
195 169
196 for (opt = dbi_conn_get_option_list (conn, NULL); opt; 170 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) {
197 opt = dbi_conn_get_option_list (conn, opt)) { 171 printf(" - %s\n", opt);
198 printf (" - %s\n", opt);
199 } 172 }
200 dbi_conn_close (conn); 173 dbi_conn_close(conn);
201 return STATE_UNKNOWN; 174 return STATE_UNKNOWN;
202 } 175 }
203 176
204 if (host) { 177 if (config.host) {
205 if (verbose > 1) 178 if (verbose > 1) {
206 printf ("Setting DBI driver option 'host' to '%s'\n", host); 179 printf("Setting DBI driver option 'host' to '%s'\n", config.host);
207 dbi_conn_set_option (conn, "host", host); 180 }
181 dbi_conn_set_option(conn, "host", config.host);
208 } 182 }
209 183
210 if (verbose) { 184 if (verbose) {
211 const char *dbname, *host; 185 const char *dbname;
186 const char *host;
212 187
213 dbname = dbi_conn_get_option (conn, "dbname"); 188 dbname = dbi_conn_get_option(conn, "dbname");
214 host = dbi_conn_get_option (conn, "host"); 189 host = dbi_conn_get_option(conn, "host");
215 190
216 if (! dbname) 191 if (!dbname) {
217 dbname = "<unspecified>"; 192 dbname = "<unspecified>";
218 if (! host) 193 }
194 if (!host) {
219 host = "<unspecified>"; 195 host = "<unspecified>";
196 }
220 197
221 printf ("Connecting to database '%s' at host '%s'\n", 198 printf("Connecting to database '%s' at host '%s'\n", dbname, host);
222 dbname, host);
223 } 199 }
224 200
225 if (dbi_conn_connect (conn) < 0) { 201 if (dbi_conn_connect(conn) < 0) {
226 np_dbi_print_error (conn, "UNKNOWN - failed to connect to database"); 202 np_dbi_print_error(conn, "UNKNOWN - failed to connect to database");
227 return STATE_UNKNOWN; 203 return STATE_UNKNOWN;
228 } 204 }
229 205
230 gettimeofday (&end_timeval, NULL); 206 gettimeofday(&end_timeval, NULL);
231 conn_time = timediff (start_timeval, end_timeval); 207 conn_time = timediff(start_timeval, end_timeval);
232 208
233 server_version = dbi_conn_get_engine_version (conn); 209 server_version = dbi_conn_get_engine_version(conn);
234 if (verbose) 210 if (verbose) {
235 printf ("Connected to server version %u\n", server_version); 211 printf("Connected to server version %u\n", server_version);
212 }
236 213
237 if (metric == METRIC_SERVER_VERSION) 214 if (config.metric == METRIC_SERVER_VERSION) {
238 status = get_status (server_version, dbi_thresholds); 215 status = get_status(server_version, config.dbi_thresholds);
216 }
239 217
240 if (verbose) 218 if (verbose) {
241 printf ("Time elapsed: %f\n", conn_time); 219 printf("Time elapsed: %f\n", conn_time);
220 }
242 221
243 if (metric == METRIC_CONN_TIME) 222 if (config.metric == METRIC_CONN_TIME) {
244 status = get_status (conn_time, dbi_thresholds); 223 status = get_status(conn_time, config.dbi_thresholds);
224 }
245 225
246 /* select a database */ 226 /* select a database */
247 if (np_dbi_database) { 227 if (config.dbi_database) {
248 if (verbose > 1) 228 if (verbose > 1) {
249 printf ("Selecting database '%s'\n", np_dbi_database); 229 printf("Selecting database '%s'\n", config.dbi_database);
230 }
250 231
251 if (dbi_conn_select_db (conn, np_dbi_database)) { 232 if (dbi_conn_select_db(conn, config.dbi_database)) {
252 np_dbi_print_error (conn, "UNKNOWN - failed to select database '%s'", 233 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database);
253 np_dbi_database);
254 return STATE_UNKNOWN; 234 return STATE_UNKNOWN;
255 } 235 }
256 } 236 }
257 237
258 if (np_dbi_query) { 238 if (config.dbi_query) {
259 /* execute query */ 239 /* execute query */
260 status = do_query (conn, &query_val_str, &query_val, &query_time); 240 status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, config.dbi_query);
261 if (status != STATE_OK) 241 if (status != STATE_OK) {
262 /* do_query prints an error message in this case */ 242 /* do_query prints an error message in this case */
263 return status; 243 return status;
244 }
264 245
265 if (metric == METRIC_QUERY_RESULT) { 246 if (config.metric == METRIC_QUERY_RESULT) {
266 if (expect) { 247 if (config.expect) {
267 if ((! query_val_str) || strcmp (query_val_str, expect)) 248 if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
268 status = STATE_CRITICAL; 249 status = STATE_CRITICAL;
269 else 250 } else {
270 status = STATE_OK; 251 status = STATE_OK;
271 } 252 }
272 else if (expect_re_str) { 253 } else if (config.expect_re_str) {
273 int err; 254 int err;
274 255
275 err = regexec (&expect_re, query_val_str, 0, NULL, /* flags = */ 0); 256 regex_t expect_re = {};
276 if (! err) 257 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
258 if (!err) {
277 status = STATE_OK; 259 status = STATE_OK;
278 else if (err == REG_NOMATCH) 260 } else if (err == REG_NOMATCH) {
279 status = STATE_CRITICAL; 261 status = STATE_CRITICAL;
280 else { 262 } else {
281 char errmsg[1024]; 263 char errmsg[1024];
282 regerror (err, &expect_re, errmsg, sizeof (errmsg)); 264 regerror(err, &expect_re, errmsg, sizeof(errmsg));
283 printf ("ERROR - failed to execute regular expression: %s\n", 265 printf("ERROR - failed to execute regular expression: %s\n", errmsg);
284 errmsg);
285 status = STATE_CRITICAL; 266 status = STATE_CRITICAL;
286 } 267 }
268 } else {
269 status = get_status(query_val, config.dbi_thresholds);
287 } 270 }
288 else 271 } else if (config.metric == METRIC_QUERY_TIME) {
289 status = get_status (query_val, dbi_thresholds); 272 status = get_status(query_time, config.dbi_thresholds);
290 } 273 }
291 else if (metric == METRIC_QUERY_TIME)
292 status = get_status (query_time, dbi_thresholds);
293 } 274 }
294 275
295 if (verbose) 276 if (verbose) {
296 printf("Closing connection\n"); 277 printf("Closing connection\n");
297 dbi_conn_close (conn); 278 }
279 dbi_conn_close(conn);
298 280
299 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error 281 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
300 * which should have been reported and handled (abort) before 282 * which should have been reported and handled (abort) before
301 * ... unless we expected a string to be returned */ 283 * ... unless we expected a string to be returned */
302 assert ((metric != METRIC_QUERY_RESULT) || (! isnan (query_val)) 284 assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (config.type == TYPE_STRING));
303 || (type == TYPE_STRING));
304 285
305 assert ((type != TYPE_STRING) || (expect || expect_re_str)); 286 assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
306 287
307 printf ("%s - connection time: %fs", state_text (status), conn_time); 288 printf("%s - connection time: %fs", state_text(status), conn_time);
308 if (np_dbi_query) { 289 if (config.dbi_query) {
309 if (type == TYPE_STRING) { 290 if (config.type == TYPE_STRING) {
310 assert (expect || expect_re_str); 291 assert(config.expect || config.expect_re_str);
311 printf (", '%s' returned '%s' in %fs", np_dbi_query, 292 printf(", '%s' returned '%s' in %fs", config.dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
312 query_val_str ? query_val_str : "<nothing>", query_time);
313 if (status != STATE_OK) { 293 if (status != STATE_OK) {
314 if (expect) 294 if (config.expect) {
315 printf (" (expected '%s')", expect); 295 printf(" (expected '%s')", config.expect);
316 else if (expect_re_str) 296 } else if (config.expect_re_str) {
317 printf (" (expected regex /%s/%s)", expect_re_str, 297 printf(" (expected regex /%s/%s)", config.expect_re_str, ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
318 ((expect_re_cflags & REG_ICASE) ? "i" : "")); 298 }
319 } 299 }
300 } else if (isnan(query_val)) {
301 printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
302 } else {
303 printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
320 } 304 }
321 else if (isnan (query_val)) 305 }
322 printf (", '%s' query execution time: %fs", np_dbi_query, query_time); 306
323 else 307 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
324 printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); 308 ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
325 } 309 ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", server_version,
326 310 ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range : "",
327 printf (" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, 311 ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range : "");
328 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", 312 if (config.dbi_query) {
329 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "", 313 if (!isnan(query_val)) { /* this is also true when -e is used */
330 server_version, 314 printf(" query=%f;%s;%s;;", query_val, ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) ? config.warning_range : "",
331 ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "", 315 ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) ? config.critical_range : "");
332 ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : ""); 316 }
333 if (np_dbi_query) { 317 printf(" querytime=%fs;%s;%s;0;", query_time, ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range : "",
334 if (! isnan (query_val)) /* this is also true when -e is used */ 318 ((config.metric == METRIC_QUERY_TIME) && config.critical_range) ? config.critical_range : "");
335 printf (" query=%f;%s;%s;;", query_val, 319 }
336 ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", 320 printf("\n");
337 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : "");
338 printf (" querytime=%fs;%s;%s;0;", query_time,
339 ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "",
340 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : "");
341 }
342 printf ("\n");
343 return status; 321 return status;
344} 322}
345 323
346/* process command-line arguments */ 324/* process command-line arguments */
347int 325check_dbi_config_wrapper process_arguments(int argc, char **argv) {
348process_arguments (int argc, char **argv)
349{
350 int c;
351 326
352 int option = 0; 327 int option = 0;
353 static struct option longopts[] = { 328 static struct option longopts[] = {STD_LONG_OPTS,
354 STD_LONG_OPTS, 329
355 330 {"expect", required_argument, 0, 'e'},
356 {"expect", required_argument, 0, 'e'}, 331 {"regex", required_argument, 0, 'r'},
357 {"regex", required_argument, 0, 'r'}, 332 {"regexi", required_argument, 0, 'R'},
358 {"regexi", required_argument, 0, 'R'}, 333 {"metric", required_argument, 0, 'm'},
359 {"metric", required_argument, 0, 'm'}, 334 {"driver", required_argument, 0, 'd'},
360 {"driver", required_argument, 0, 'd'}, 335 {"option", required_argument, 0, 'o'},
361 {"option", required_argument, 0, 'o'}, 336 {"query", required_argument, 0, 'q'},
362 {"query", required_argument, 0, 'q'}, 337 {"database", required_argument, 0, 'D'},
363 {"database", required_argument, 0, 'D'}, 338 {0, 0, 0, 0}};
364 {0, 0, 0, 0} 339
340 check_dbi_config_wrapper result = {
341 .config = check_dbi_config_init(),
342 .errorcode = OK,
365 }; 343 };
344 int option_char;
345 while (true) {
346 option_char = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option);
366 347
367 while (1) { 348 if (option_char == EOF) {
368 c = getopt_long (argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:",
369 longopts, &option);
370
371 if (c == EOF)
372 break; 349 break;
350 }
373 351
374 switch (c) { 352 switch (option_char) {
375 case '?': /* usage */ 353 case '?': /* usage */
376 usage5 (); 354 usage5();
377 case 'h': /* help */ 355 case 'h': /* help */
378 print_help (); 356 print_help();
379 exit (STATE_UNKNOWN); 357 exit(STATE_UNKNOWN);
380 case 'V': /* version */ 358 case 'V': /* version */
381 print_revision (progname, NP_VERSION); 359 print_revision(progname, NP_VERSION);
382 exit (STATE_UNKNOWN); 360 exit(STATE_UNKNOWN);
383 361
384 case 'c': /* critical range */ 362 case 'c': /* critical range */
385 critical_range = optarg; 363 result.config.critical_range = optarg;
386 type = TYPE_NUMERIC; 364 result.config.type = TYPE_NUMERIC;
387 break; 365 break;
388 case 'w': /* warning range */ 366 case 'w': /* warning range */
389 warning_range = optarg; 367 result.config.warning_range = optarg;
390 type = TYPE_NUMERIC; 368 result.config.type = TYPE_NUMERIC;
391 break; 369 break;
392 case 'e': 370 case 'e':
393 expect = optarg; 371 result.config.expect = optarg;
394 type = TYPE_STRING; 372 result.config.type = TYPE_STRING;
395 break; 373 break;
396 case 'R': 374 case 'R':
397 expect_re_cflags = REG_ICASE; 375 result.config.expect_re_cflags = REG_ICASE;
398 /* fall through */ 376 /* fall through */
399 case 'r': 377 case 'r': {
400 { 378 int err;
401 int err; 379
402 380 result.config.expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
403 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 381 result.config.expect_re_str = optarg;
404 expect_re_str = optarg; 382 result.config.type = TYPE_STRING;
405 type = TYPE_STRING; 383
406 384 regex_t expect_re = {};
407 err = regcomp (&expect_re, expect_re_str, expect_re_cflags); 385 err = regcomp(&expect_re, result.config.expect_re_str, result.config.expect_re_cflags);
408 if (err) { 386 if (err) {
409 char errmsg[1024]; 387 char errmsg[1024];
410 regerror (err, &expect_re, errmsg, sizeof (errmsg)); 388 regerror(err, &expect_re, errmsg, sizeof(errmsg));
411 printf ("ERROR - failed to compile regular expression: %s\n", 389 printf("ERROR - failed to compile regular expression: %s\n", errmsg);
412 errmsg); 390
413 return ERROR; 391 result.errorcode = ERROR;
414 } 392 return result;
415 break;
416 } 393 }
394 break;
395 }
417 396
418 case 'm': 397 case 'm':
419 if (! strcasecmp (optarg, "CONN_TIME")) 398 if (!strcasecmp(optarg, "CONN_TIME")) {
420 metric = METRIC_CONN_TIME; 399 result.config.metric = METRIC_CONN_TIME;
421 else if (! strcasecmp (optarg, "SERVER_VERSION")) 400 } else if (!strcasecmp(optarg, "SERVER_VERSION")) {
422 metric = METRIC_SERVER_VERSION; 401 result.config.metric = METRIC_SERVER_VERSION;
423 else if (! strcasecmp (optarg, "QUERY_RESULT")) 402 } else if (!strcasecmp(optarg, "QUERY_RESULT")) {
424 metric = METRIC_QUERY_RESULT; 403 result.config.metric = METRIC_QUERY_RESULT;
425 else if (! strcasecmp (optarg, "QUERY_TIME")) 404 } else if (!strcasecmp(optarg, "QUERY_TIME")) {
426 metric = METRIC_QUERY_TIME; 405 result.config.metric = METRIC_QUERY_TIME;
427 else 406 } else {
428 usage2 (_("Invalid metric"), optarg); 407 usage2(_("Invalid metric"), optarg);
408 }
429 break; 409 break;
430 case 't': /* timeout */ 410 case 't': /* timeout */
431 if (!is_intnonneg (optarg)) 411 if (!is_intnonneg(optarg)) {
432 usage2 (_("Timeout interval must be a positive integer"), optarg); 412 usage2(_("Timeout interval must be a positive integer"), optarg);
433 else 413 } else {
434 timeout_interval = atoi (optarg); 414 timeout_interval = atoi(optarg);
415 }
435 416
436 break; 417 break;
437 case 'H': /* host */ 418 case 'H': /* host */
438 if (!is_host (optarg)) 419 if (!is_host(optarg)) {
439 usage2 (_("Invalid hostname/address"), optarg); 420 usage2(_("Invalid hostname/address"), optarg);
440 else 421 } else {
441 host = optarg; 422 result.config.host = optarg;
423 }
442 break; 424 break;
443 case 'v': 425 case 'v':
444 verbose++; 426 verbose++;
445 break; 427 break;
446 428
447 case 'd': 429 case 'd':
448 np_dbi_driver = optarg; 430 result.config.dbi_driver = optarg;
449 break; 431 break;
450 case 'o': 432 case 'o': {
451 { 433 driver_option_t *new = NULL;
452 driver_option_t *new;
453
454 char *k, *v;
455 434
456 k = optarg; 435 char *key = optarg;
457 v = strchr (k, (int)'='); 436 char *value = strchr(key, '=');
458 437
459 if (! v) 438 if (!value) {
460 usage2 (_("Option must be '<key>=<value>'"), optarg); 439 usage2(_("Option must be '<key>=<value>'"), optarg);
440 }
461 441
462 *v = '\0'; 442 *value = '\0';
463 ++v; 443 ++value;
464 444
465 new = realloc (np_dbi_options, 445 new = realloc(result.config.dbi_options, (result.config.dbi_options_num + 1) * sizeof(*new));
466 (np_dbi_options_num + 1) * sizeof (*new)); 446 if (!new) {
467 if (! new) { 447 printf("UNKNOWN - failed to reallocate memory\n");
468 printf ("UNKNOWN - failed to reallocate memory\n"); 448 exit(STATE_UNKNOWN);
469 exit (STATE_UNKNOWN); 449 }
470 }
471 450
472 np_dbi_options = new; 451 result.config.dbi_options = new;
473 new = np_dbi_options + np_dbi_options_num; 452 new = result.config.dbi_options + result.config.dbi_options_num;
474 ++np_dbi_options_num; 453 result.config.dbi_options_num++;
475 454
476 new->key = k; 455 new->key = key;
477 new->value = v; 456 new->value = value;
478 } 457 } break;
479 break;
480 case 'q': 458 case 'q':
481 np_dbi_query = optarg; 459 result.config.dbi_query = optarg;
482 break; 460 break;
483 case 'D': 461 case 'D':
484 np_dbi_database = optarg; 462 result.config.dbi_database = optarg;
485 break; 463 break;
486 } 464 }
487 } 465 }
488 466
489 set_thresholds (&dbi_thresholds, warning_range, critical_range); 467 set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, result.config.critical_range);
490 468
491 return validate_arguments (); 469 return validate_arguments(result);
492} 470}
493 471
494int 472check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
495validate_arguments () 473 if (!config_wrapper.config.dbi_driver) {
496{ 474 usage("Must specify a DBI driver");
497 if (! np_dbi_driver) 475 }
498 usage ("Must specify a DBI driver");
499 476
500 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) 477 if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || (config_wrapper.config.metric == METRIC_QUERY_TIME)) &&
501 && (! np_dbi_query)) 478 (!config_wrapper.config.dbi_query)) {
502 usage ("Must specify a query to execute (metric == QUERY_RESULT)"); 479 usage("Must specify a query to execute (metric == QUERY_RESULT)");
480 }
503 481
504 if ((metric != METRIC_CONN_TIME) 482 if ((config_wrapper.config.metric != METRIC_CONN_TIME) && (config_wrapper.config.metric != METRIC_SERVER_VERSION) &&
505 && (metric != METRIC_SERVER_VERSION) 483 (config_wrapper.config.metric != METRIC_QUERY_RESULT) && (config_wrapper.config.metric != METRIC_QUERY_TIME)) {
506 && (metric != METRIC_QUERY_RESULT) 484 usage("Invalid metric specified");
507 && (metric != METRIC_QUERY_TIME)) 485 }
508 usage ("Invalid metric specified");
509 486
510 if (expect && (warning_range || critical_range || expect_re_str)) 487 if (config_wrapper.config.expect && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect_re_str)) {
511 usage ("Do not mix -e and -w/-c/-r/-R"); 488 usage("Do not mix -e and -w/-c/-r/-R");
489 }
512 490
513 if (expect_re_str && (warning_range || critical_range || expect)) 491 if (config_wrapper.config.expect_re_str && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect)) {
514 usage ("Do not mix -r/-R and -w/-c/-e"); 492 usage("Do not mix -r/-R and -w/-c/-e");
493 }
515 494
516 if (expect && (metric != METRIC_QUERY_RESULT)) 495 if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
517 usage ("Option -e requires metric QUERY_RESULT"); 496 usage("Option -e requires metric QUERY_RESULT");
497 }
518 498
519 if (expect_re_str && (metric != METRIC_QUERY_RESULT)) 499 if (config_wrapper.config.expect_re_str && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
520 usage ("Options -r/-R require metric QUERY_RESULT"); 500 usage("Options -r/-R require metric QUERY_RESULT");
501 }
521 502
522 return OK; 503 config_wrapper.errorcode = OK;
504 return config_wrapper;
523} 505}
524 506
525void 507void print_help(void) {
526print_help (void) 508 print_revision(progname, NP_VERSION);
527{
528 print_revision (progname, NP_VERSION);
529 509
530 printf (COPYRIGHT, copyright, email); 510 printf(COPYRIGHT, copyright, email);
531 511
532 printf (_("This program connects to an (SQL) database using DBI and checks the\n" 512 printf(_("This program connects to an (SQL) database using DBI and checks the\n"
533 "specified metric against threshold levels. The default metric is\n" 513 "specified metric against threshold levels. The default metric is\n"
534 "the result of the specified query.\n")); 514 "the result of the specified query.\n"));
535 515
536 printf ("\n\n"); 516 printf("\n\n");
537 517
538 print_usage (); 518 print_usage();
539 519
540 printf (UT_HELP_VRSN); 520 printf(UT_HELP_VRSN);
541/* include this conditionally to avoid 'zero-length printf format string' 521/* include this conditionally to avoid 'zero-length printf format string'
542 * compiler warnings */ 522 * compiler warnings */
543#ifdef NP_EXTRA_OPTS 523#ifdef NP_EXTRA_OPTS
544 printf (UT_EXTRA_OPTS); 524 printf(UT_EXTRA_OPTS);
545#endif 525#endif
546 printf ("\n"); 526 printf("\n");
547 527
548 printf (" %s\n", "-d, --driver=STRING"); 528 printf(" %s\n", "-d, --driver=STRING");
549 printf (" %s\n", _("DBI driver to use")); 529 printf(" %s\n", _("DBI driver to use"));
550 printf (" %s\n", "-o, --option=STRING"); 530 printf(" %s\n", "-o, --option=STRING");
551 printf (" %s\n", _("DBI driver options")); 531 printf(" %s\n", _("DBI driver options"));
552 printf (" %s\n", "-q, --query=STRING"); 532 printf(" %s\n", "-q, --query=STRING");
553 printf (" %s\n", _("query to execute")); 533 printf(" %s\n", _("query to execute"));
554 printf ("\n"); 534 printf(" %s\n", "-H STRING");
555 535 printf(" %s\n", _("target database host"));
556 printf (UT_WARN_CRIT_RANGE); 536 printf("\n");
557 printf (" %s\n", "-e, --expect=STRING"); 537
558 printf (" %s\n", _("String to expect as query result")); 538 printf(UT_WARN_CRIT_RANGE);
559 printf (" %s\n", _("Do not mix with -w, -c, -r, or -R!")); 539 printf(" %s\n", "-e, --expect=STRING");
560 printf (" %s\n", "-r, --regex=REGEX"); 540 printf(" %s\n", _("String to expect as query result"));
561 printf (" %s\n", _("Extended POSIX regular expression to check query result against")); 541 printf(" %s\n", _("Do not mix with -w, -c, -r, or -R!"));
562 printf (" %s\n", _("Do not mix with -w, -c, -e, or -R!")); 542 printf(" %s\n", "-r, --regex=REGEX");
563 printf (" %s\n", "-R, --regexi=REGEX"); 543 printf(" %s\n", _("Extended POSIX regular expression to check query result against"));
564 printf (" %s\n", _("Case-insensitive extended POSIX regex to check query result against")); 544 printf(" %s\n", _("Do not mix with -w, -c, -e, or -R!"));
565 printf (" %s\n", _("Do not mix with -w, -c, -e, or -r!")); 545 printf(" %s\n", "-R, --regexi=REGEX");
566 printf (" %s\n", "-m, --metric=METRIC"); 546 printf(" %s\n", _("Case-insensitive extended POSIX regex to check query result against"));
567 printf (" %s\n", _("Metric to check thresholds against. Available metrics:")); 547 printf(" %s\n", _("Do not mix with -w, -c, -e, or -r!"));
568 printf (" CONN_TIME - %s\n", _("time used for setting up the database connection")); 548 printf(" %s\n", "-m, --metric=METRIC");
569 printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query")); 549 printf(" %s\n", _("Metric to check thresholds against. Available metrics:"));
570 printf (" QUERY_TIME - %s\n", _("time used to execute the query")); 550 printf(" CONN_TIME - %s\n", _("time used for setting up the database connection"));
571 printf (" %s\n", _("(ignore the query result)")); 551 printf(" QUERY_RESULT - %s\n", _("result (first column of first row) of the query"));
572 printf ("\n"); 552 printf(" QUERY_TIME - %s\n", _("time used to execute the query"));
573 553 printf(" %s\n", _("(ignore the query result)"));
574 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 554 printf("\n");
575 555
576 printf (UT_VERBOSE); 556 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
577 557
578 printf ("\n"); 558 printf(UT_VERBOSE);
579 printf (" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates")); 559
580 printf (" %s\n\n", _("on a query, one has to be specified (-q option).")); 560 printf("\n");
581 561 printf(" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates"));
582 printf (" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,")); 562 printf(" %s\n\n", _("on a query, one has to be specified (-q option)."));
583 printf (" %s\n", _("executes the specified query. The first column of the first row of the")); 563
584 printf (" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the")); 564 printf(" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,"));
585 printf (" %s\n", _("warning and critical ranges. The result from the query has to be numeric")); 565 printf(" %s\n", _("executes the specified query. The first column of the first row of the"));
586 printf (" %s\n\n", _("(strings representing numbers are fine).")); 566 printf(" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the"));
587 567 printf(" %s\n", _("warning and critical ranges. The result from the query has to be numeric"));
588 printf (" %s\n", _("The number and type of required DBI driver options depends on the actual")); 568 printf(" %s\n\n", _("(strings representing numbers are fine)."));
589 printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/")); 569
590 printf (" %s\n\n", _("for details.")); 570 printf(" %s\n", _("The number and type of required DBI driver options depends on the actual"));
591 571 printf(" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/"));
592 printf (" %s\n", _("Examples:")); 572 printf(" %s\n\n", _("for details."));
593 printf (" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n"); 573
594 printf (" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n"); 574 printf(" %s\n", _("Examples:"));
595 printf (" Warning if more than five connections; critical if more than ten.\n\n"); 575 printf(" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n");
596 576 printf(" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n");
597 printf (" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n"); 577 printf(" Warning if more than five connections; critical if more than ten.\n\n");
598 printf (" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n"); 578
599 printf (" Warning if less than 5 or more than 20 users are logged in; critical\n"); 579 printf(" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n");
600 printf (" if more than 50 users.\n\n"); 580 printf(" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n");
601 581 printf(" Warning if less than 5 or more than 20 users are logged in; critical\n");
602 printf (" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n"); 582 printf(" if more than 50 users.\n\n");
603 printf (" -m CONN_TIME -w 0.5 -c 2\n"); 583
604 printf (" Warning if connecting to the database takes more than half of a second;\n"); 584 printf(" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n");
605 printf (" critical if it takes more than 2 seconds.\n\n"); 585 printf(" -m CONN_TIME -w 0.5 -c 2\n");
606 586 printf(" Warning if connecting to the database takes more than half of a second;\n");
607 printf (" check_dbi -d mysql -H localhost -o username=user \\\n"); 587 printf(" critical if it takes more than 2 seconds.\n\n");
608 printf (" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n"); 588
609 printf (" -r '^5\\.[01].*MySQL Enterprise Server'\n"); 589 printf(" check_dbi -d mysql -H localhost -o username=user \\\n");
610 printf (" Critical if the database server is not a MySQL enterprise server in either\n"); 590 printf(" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n");
611 printf (" version 5.0.x or 5.1.x.\n\n"); 591 printf(" -r '^5\\.[01].*MySQL Enterprise Server'\n");
612 592 printf(" Critical if the database server is not a MySQL enterprise server in either\n");
613 printf (" check_dbi -d pgsql -u username=user -m SERVER_VERSION \\\n"); 593 printf(" version 5.0.x or 5.1.x.\n\n");
614 printf (" -w 090000:090099 -c 090000:090199\n"); 594
615 printf (" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n"); 595 printf(" check_dbi -d pgsql -u username=user -m SERVER_VERSION \\\n");
616 printf (" is less than 9.x or higher than 9.1.x.\n"); 596 printf(" -w 090000:090099 -c 090000:090199\n");
617 597 printf(" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n");
618 printf (UT_SUPPORT); 598 printf(" is less than 9.x or higher than 9.1.x.\n");
599
600 printf(UT_SUPPORT);
619} 601}
620 602
621void 603void print_usage(void) {
622print_usage (void) 604 printf("%s\n", _("Usage:"));
623{ 605 printf("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname);
624 printf ("%s\n", _("Usage:")); 606 printf(" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
625 printf ("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname); 607 printf(" [-e <string>] [-r|-R <regex>]\n");
626 printf (" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
627 printf (" [-e <string>] [-r|-R <regex>]\n");
628} 608}
629 609
630#define CHECK_IGNORE_ERROR(s) \ 610const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type, mp_dbi_metric metric, mp_dbi_type type) {
631 do { \
632 if (metric != METRIC_QUERY_RESULT) \
633 return (s); \
634 } while (0)
635
636const char *
637get_field_str (dbi_conn conn, dbi_result res, unsigned short field_type)
638{
639 const char *str; 611 const char *str;
640 612
641 if (field_type != DBI_TYPE_STRING) { 613 if (field_type != DBI_TYPE_STRING) {
642 printf ("CRITICAL - result value is not a string\n"); 614 printf("CRITICAL - result value is not a string\n");
643 return NULL; 615 return NULL;
644 } 616 }
645 617
646 str = dbi_result_get_string_idx (res, 1); 618 str = dbi_result_get_string_idx(res, 1);
647 if ((! str) || (strcmp (str, "ERROR") == 0)) { 619 if ((!str) || (strcmp(str, "ERROR") == 0)) {
648 CHECK_IGNORE_ERROR (NULL); 620 if (metric != METRIC_QUERY_RESULT) {
649 np_dbi_print_error (conn, "CRITICAL - failed to fetch string value"); 621 return NULL;
622 }
623 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
650 return NULL; 624 return NULL;
651 } 625 }
652 626
653 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) 627 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) {
654 printf ("Query returned string '%s'\n", str); 628 printf("Query returned string '%s'\n", str);
629 }
655 return str; 630 return str;
656} 631}
657 632
658double 633double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, mp_dbi_type type) {
659get_field (dbi_conn conn, dbi_result res, unsigned short *field_type)
660{
661 double val = NAN; 634 double val = NAN;
662 635
663 if (*field_type == DBI_TYPE_INTEGER) { 636 if (*field_type == DBI_TYPE_INTEGER) {
664 val = (double)dbi_result_get_longlong_idx (res, 1); 637 val = (double)dbi_result_get_longlong_idx(res, 1);
665 } 638 } else if (*field_type == DBI_TYPE_DECIMAL) {
666 else if (*field_type == DBI_TYPE_DECIMAL) { 639 val = dbi_result_get_double_idx(res, 1);
667 val = dbi_result_get_double_idx (res, 1); 640 } else if (*field_type == DBI_TYPE_STRING) {
668 }
669 else if (*field_type == DBI_TYPE_STRING) {
670 const char *val_str; 641 const char *val_str;
671 char *endptr = NULL; 642 char *endptr = NULL;
672 643
673 val_str = get_field_str (conn, res, *field_type); 644 val_str = get_field_str(conn, res, *field_type, metric, type);
674 if (! val_str) { 645 if (!val_str) {
675 CHECK_IGNORE_ERROR (NAN); 646 if (metric != METRIC_QUERY_RESULT) {
647 return NAN;
648 }
676 *field_type = DBI_TYPE_ERROR; 649 *field_type = DBI_TYPE_ERROR;
677 return NAN; 650 return NAN;
678 } 651 }
679 652
680 val = strtod (val_str, &endptr); 653 val = strtod(val_str, &endptr);
681 if (endptr == val_str) { 654 if (endptr == val_str) {
682 CHECK_IGNORE_ERROR (NAN); 655 if (metric != METRIC_QUERY_RESULT) {
683 printf ("CRITICAL - result value is not a numeric: %s\n", val_str); 656 return NAN;
657 }
658 printf("CRITICAL - result value is not a numeric: %s\n", val_str);
684 *field_type = DBI_TYPE_ERROR; 659 *field_type = DBI_TYPE_ERROR;
685 return NAN; 660 return NAN;
686 } 661 }
687 else if ((endptr != NULL) && (*endptr != '\0')) { 662 if ((endptr != NULL) && (*endptr != '\0')) {
688 if (verbose) 663 if (verbose) {
689 printf ("Garbage after value: %s\n", endptr); 664 printf("Garbage after value: %s\n", endptr);
665 }
690 } 666 }
691 } 667 } else {
692 else { 668 if (metric != METRIC_QUERY_RESULT) {
693 CHECK_IGNORE_ERROR (NAN); 669 return NAN;
694 printf ("CRITICAL - cannot parse value of type %s (%i)\n", 670 }
695 (*field_type == DBI_TYPE_BINARY) 671 printf("CRITICAL - cannot parse value of type %s (%i)\n",
696 ? "BINARY" 672 (*field_type == DBI_TYPE_BINARY) ? "BINARY"
697 : (*field_type == DBI_TYPE_DATETIME) 673 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
698 ? "DATETIME" 674 : "<unknown>",
699 : "<unknown>", 675 *field_type);
700 *field_type);
701 *field_type = DBI_TYPE_ERROR; 676 *field_type = DBI_TYPE_ERROR;
702 return NAN; 677 return NAN;
703 } 678 }
704 return val; 679 return val;
705} 680}
706 681
707double 682mp_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) {
708get_query_result (dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val)
709{
710 unsigned short field_type; 683 unsigned short field_type;
711 double val = NAN; 684 double val = NAN;
712 685
713 if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) { 686 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
714 CHECK_IGNORE_ERROR (STATE_OK); 687 if (metric != METRIC_QUERY_RESULT) {
715 np_dbi_print_error (conn, "CRITICAL - failed to fetch rows"); 688 return STATE_OK;
689 }
690 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
716 return STATE_CRITICAL; 691 return STATE_CRITICAL;
717 } 692 }
718 693
719 if (dbi_result_get_numrows (res) < 1) { 694 if (dbi_result_get_numrows(res) < 1) {
720 CHECK_IGNORE_ERROR (STATE_OK); 695 if (metric != METRIC_QUERY_RESULT) {
721 printf ("WARNING - no rows returned\n"); 696 return STATE_OK;
697 }
698 printf("WARNING - no rows returned\n");
722 return STATE_WARNING; 699 return STATE_WARNING;
723 } 700 }
724 701
725 if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) { 702 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
726 CHECK_IGNORE_ERROR (STATE_OK); 703 if (metric != METRIC_QUERY_RESULT) {
727 np_dbi_print_error (conn, "CRITICAL - failed to fetch fields"); 704 return STATE_OK;
705 }
706 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
728 return STATE_CRITICAL; 707 return STATE_CRITICAL;
729 } 708 }
730 709
731 if (dbi_result_get_numfields (res) < 1) { 710 if (dbi_result_get_numfields(res) < 1) {
732 CHECK_IGNORE_ERROR (STATE_OK); 711 if (metric != METRIC_QUERY_RESULT) {
733 printf ("WARNING - no fields returned\n"); 712 return STATE_OK;
713 }
714 printf("WARNING - no fields returned\n");
734 return STATE_WARNING; 715 return STATE_WARNING;
735 } 716 }
736 717
737 if (dbi_result_first_row (res) != 1) { 718 if (dbi_result_first_row(res) != 1) {
738 CHECK_IGNORE_ERROR (STATE_OK); 719 if (metric != METRIC_QUERY_RESULT) {
739 np_dbi_print_error (conn, "CRITICAL - failed to fetch first row"); 720 return STATE_OK;
721 }
722 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
740 return STATE_CRITICAL; 723 return STATE_CRITICAL;
741 } 724 }
742 725
743 field_type = dbi_result_get_field_type_idx (res, 1); 726 field_type = dbi_result_get_field_type_idx(res, 1);
744 if (field_type != DBI_TYPE_ERROR) { 727 if (field_type != DBI_TYPE_ERROR) {
745 if (type == TYPE_STRING) 728 if (type == TYPE_STRING) {
746 /* the value will be freed in dbi_result_free */ 729 /* the value will be freed in dbi_result_free */
747 *res_val_str = strdup (get_field_str (conn, res, field_type)); 730 *res_val_str = strdup(get_field_str(conn, res, field_type, metric, type));
748 else 731 } else {
749 val = get_field (conn, res, &field_type); 732 val = get_field(conn, res, &field_type, metric, type);
733 }
750 } 734 }
751 735
752 *res_val = val; 736 *res_val = val;
753 737
754 if (field_type == DBI_TYPE_ERROR) { 738 if (field_type == DBI_TYPE_ERROR) {
755 CHECK_IGNORE_ERROR (STATE_OK); 739 if (metric != METRIC_QUERY_RESULT) {
756 np_dbi_print_error (conn, "CRITICAL - failed to fetch data"); 740 return STATE_OK;
741 }
742 np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
757 return STATE_CRITICAL; 743 return STATE_CRITICAL;
758 } 744 }
759 745
760 dbi_result_free (res); 746 dbi_result_free(res);
761 return STATE_OK; 747 return STATE_OK;
762} 748}
763 749
764#undef CHECK_IGNORE_ERROR 750mp_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,
765 751 char *np_dbi_query) {
766int
767do_query (dbi_conn conn, const char **res_val_str, double *res_val, double *res_time)
768{
769 dbi_result res; 752 dbi_result res;
770 753
771 struct timeval timeval_start, timeval_end; 754 struct timeval timeval_start;
772 int status = STATE_OK; 755 struct timeval timeval_end;
756 mp_state_enum status = STATE_OK;
773 757
774 assert (np_dbi_query); 758 assert(np_dbi_query);
775 759
776 if (verbose) 760 if (verbose) {
777 printf ("Executing query '%s'\n", np_dbi_query); 761 printf("Executing query '%s'\n", np_dbi_query);
762 }
778 763
779 gettimeofday (&timeval_start, NULL); 764 gettimeofday(&timeval_start, NULL);
780 765
781 res = dbi_conn_query (conn, np_dbi_query); 766 res = dbi_conn_query(conn, np_dbi_query);
782 if (! res) { 767 if (!res) {
783 np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); 768 np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
784 return STATE_CRITICAL; 769 return STATE_CRITICAL;
785 } 770 }
786 771
787 status = get_query_result (conn, res, res_val_str, res_val); 772 status = get_query_result(conn, res, res_val_str, res_val, metric, type);
788 773
789 gettimeofday (&timeval_end, NULL); 774 gettimeofday(&timeval_end, NULL);
790 *res_time = timediff (timeval_start, timeval_end); 775 *res_time = timediff(timeval_start, timeval_end);
791 776
792 if (verbose) 777 if (verbose) {
793 printf ("Time elapsed: %f\n", *res_time); 778 printf("Time elapsed: %f\n", *res_time);
779 }
794 780
795 return status; 781 return status;
796} 782}
797 783
798double 784double timediff(struct timeval start, struct timeval end) {
799timediff (struct timeval start, struct timeval end)
800{
801 double diff; 785 double diff;
802 786
803 while (start.tv_usec > end.tv_usec) { 787 while (start.tv_usec > end.tv_usec) {
804 --end.tv_sec; 788 --end.tv_sec;
805 end.tv_usec += 1000000; 789 end.tv_usec += 1000000;
806 } 790 }
807 diff = (double)(end.tv_sec - start.tv_sec) 791 diff = (double)(end.tv_sec - start.tv_sec) + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
808 + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
809 return diff; 792 return diff;
810} 793}
811 794
812void 795void np_dbi_print_error(dbi_conn conn, char *fmt, ...) {
813np_dbi_print_error (dbi_conn conn, char *fmt, ...)
814{
815 const char *errmsg = NULL; 796 const char *errmsg = NULL;
816 va_list ap; 797 va_list ap;
817 798
818 va_start (ap, fmt); 799 va_start(ap, fmt);
819 800
820 dbi_conn_error (conn, &errmsg); 801 dbi_conn_error(conn, &errmsg);
821 vprintf (fmt, ap); 802 vprintf(fmt, ap);
822 printf (": %s\n", errmsg); 803 printf(": %s\n", errmsg);
823 804
824 va_end (ap); 805 va_end(ap);
825} 806}
826
diff --git a/plugins/check_dbi.d/config.h b/plugins/check_dbi.d/config.h
new file mode 100644
index 00000000..f6f0d7b3
--- /dev/null
+++ b/plugins/check_dbi.d/config.h
@@ -0,0 +1,63 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include "../../lib/monitoringplug.h"
6
7typedef enum {
8 METRIC_CONN_TIME,
9 METRIC_SERVER_VERSION,
10 METRIC_QUERY_RESULT,
11 METRIC_QUERY_TIME,
12} mp_dbi_metric;
13
14typedef enum {
15 TYPE_NUMERIC,
16 TYPE_STRING,
17} mp_dbi_type;
18
19typedef struct {
20 char *key;
21 char *value;
22} driver_option_t;
23
24typedef struct {
25 char *dbi_driver;
26 char *host;
27 driver_option_t *dbi_options;
28 size_t dbi_options_num;
29 char *dbi_database;
30 char *dbi_query;
31
32 char *expect;
33 char *expect_re_str;
34 int expect_re_cflags;
35 mp_dbi_metric metric;
36 mp_dbi_type type;
37 char *warning_range;
38 char *critical_range;
39 thresholds *dbi_thresholds;
40
41} check_dbi_config;
42
43check_dbi_config check_dbi_config_init() {
44 check_dbi_config tmp = {
45 .dbi_driver = NULL,
46 .host = NULL,
47 .dbi_options = NULL,
48 .dbi_options_num = 0,
49 .dbi_database = NULL,
50 .dbi_query = NULL,
51
52 .expect = NULL,
53 .expect_re_str = NULL,
54 .expect_re_cflags = 0,
55 .metric = METRIC_QUERY_RESULT,
56 .type = TYPE_NUMERIC,
57
58 .warning_range = NULL,
59 .critical_range = NULL,
60 .dbi_thresholds = NULL,
61 };
62 return tmp;
63}
diff --git a/plugins/check_dig.c b/plugins/check_dig.c
index be7a6101..d0903be2 100644
--- a/plugins/check_dig.c
+++ b/plugins/check_dig.c
@@ -1,30 +1,30 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dig plugin 3 * Monitoring check_dig plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2002-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_dig plugin 10 * This file contains the check_dig plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29/* Hackers note: 29/* Hackers note:
30 * There are typecasts to (char *) from _("foo bar") in this file. 30 * There are typecasts to (char *) from _("foo bar") in this file.
@@ -33,7 +33,7 @@
33 * because on some architectures those strings are in non-writable memory */ 33 * because on some architectures those strings are in non-writable memory */
34 34
35const char *progname = "check_dig"; 35const char *progname = "check_dig";
36const char *copyright = "2002-2008"; 36const char *copyright = "2002-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
39#include "common.h" 39#include "common.h"
@@ -41,340 +41,319 @@ const char *email = "devel@monitoring-plugins.org";
41#include "utils.h" 41#include "utils.h"
42#include "runcmd.h" 42#include "runcmd.h"
43 43
44int process_arguments (int, char **); 44#include "check_dig.d/config.h"
45int validate_arguments (void); 45#include "states.h"
46void print_help (void); 46
47void print_usage (void); 47typedef struct {
48 48 int errorcode;
49#define UNDEFINED 0 49 check_dig_config config;
50#define DEFAULT_PORT 53 50} check_dig_config_wrapper;
51#define DEFAULT_TRIES 2 51static check_dig_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
52 52static check_dig_config_wrapper validate_arguments(check_dig_config_wrapper /*config_wrapper*/);
53char *query_address = NULL; 53
54char *record_type = "A"; 54static void print_help(void);
55char *expected_address = NULL; 55void print_usage(void);
56char *dns_server = NULL; 56
57char *dig_args = ""; 57static int verbose = 0;
58char *query_transport = ""; 58
59bool verbose = false; 59int main(int argc, char **argv) {
60int server_port = DEFAULT_PORT; 60 setlocale(LC_ALL, "");
61int number_tries = DEFAULT_TRIES; 61 bindtextdomain(PACKAGE, LOCALEDIR);
62double warning_interval = UNDEFINED; 62 textdomain(PACKAGE);
63double critical_interval = UNDEFINED; 63
64struct timeval tv; 64 /* Set signal handling and alarm */
65 65 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
66int 66 usage_va(_("Cannot catch SIGALRM"));
67main (int argc, char **argv) 67 }
68{ 68
69 char *command_line; 69 /* Parse extra opts if any */
70 output chld_out, chld_err; 70 argv = np_extra_opts(&argc, argv, progname);
71 char *msg = NULL; 71
72 size_t i; 72 check_dig_config_wrapper tmp_config = process_arguments(argc, argv);
73 char *t; 73 if (tmp_config.errorcode == ERROR) {
74 long microsec; 74 usage_va(_("Could not parse arguments"));
75 double elapsed_time; 75 }
76 int result = STATE_UNKNOWN; 76
77 int timeout_interval_dig; 77 const check_dig_config config = tmp_config.config;
78 78
79 setlocale (LC_ALL, ""); 79 /* dig applies the timeout to each try, so we need to work around this */
80 bindtextdomain (PACKAGE, LOCALEDIR); 80 int timeout_interval_dig = ((int)timeout_interval / config.number_tries) + config.number_tries;
81 textdomain (PACKAGE); 81
82 82 char *command_line;
83 /* Set signal handling and alarm */ 83 /* get the command to run */
84 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) 84 xasprintf(&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", PATH_TO_DIG, config.dig_args, config.query_transport,
85 usage_va(_("Cannot catch SIGALRM")); 85 config.server_port, config.dns_server, config.query_address, config.record_type, config.number_tries, timeout_interval_dig);
86 86
87 /* Parse extra opts if any */ 87 alarm(timeout_interval);
88 argv=np_extra_opts (&argc, argv, progname); 88 struct timeval start_time;
89 89 gettimeofday(&start_time, NULL);
90 if (process_arguments (argc, argv) == ERROR) 90
91 usage_va(_("Could not parse arguments")); 91 if (verbose) {
92 92 printf("%s\n", command_line);
93 /* dig applies the timeout to each try, so we need to work around this */ 93 if (config.expected_address != NULL) {
94 timeout_interval_dig = timeout_interval / number_tries + number_tries; 94 printf(_("Looking for: '%s'\n"), config.expected_address);
95 95 } else {
96 /* get the command to run */ 96 printf(_("Looking for: '%s'\n"), config.query_address);
97 xasprintf (&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", 97 }
98 PATH_TO_DIG, dig_args, query_transport, server_port, dns_server, query_address, record_type, number_tries, timeout_interval_dig); 98 }
99 99
100 alarm (timeout_interval); 100 output chld_out;
101 gettimeofday (&tv, NULL); 101 output chld_err;
102 102 char *msg = NULL;
103 if (verbose) { 103 mp_state_enum result = STATE_UNKNOWN;
104 printf ("%s\n", command_line); 104 /* run the command */
105 if(expected_address != NULL) { 105 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
106 printf (_("Looking for: '%s'\n"), expected_address); 106 result = STATE_WARNING;
107 } else { 107 msg = (char *)_("dig returned an error status");
108 printf (_("Looking for: '%s'\n"), query_address); 108 }
109 } 109
110 } 110 for (size_t i = 0; i < chld_out.lines; i++) {
111 111 /* the server is responding, we just got the host name... */
112 /* run the command */ 112 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) {
113 if(np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) { 113
114 result = STATE_WARNING; 114 /* loop through the whole 'ANSWER SECTION' */
115 msg = (char *)_("dig returned an error status"); 115 for (; i < chld_out.lines; i++) {
116 } 116 /* get the host address */
117 117 if (verbose) {
118 for(i = 0; i < chld_out.lines; i++) { 118 printf("%s\n", chld_out.line[i]);
119 /* the server is responding, we just got the host name... */ 119 }
120 if (strstr (chld_out.line[i], ";; ANSWER SECTION:")) { 120
121 121 if (strcasestr(chld_out.line[i], (config.expected_address == NULL ? config.query_address : config.expected_address)) !=
122 /* loop through the whole 'ANSWER SECTION' */ 122 NULL) {
123 for(; i < chld_out.lines; i++) { 123 msg = chld_out.line[i];
124 /* get the host address */ 124 result = STATE_OK;
125 if (verbose) 125
126 printf ("%s\n", chld_out.line[i]); 126 /* Translate output TAB -> SPACE */
127 127 char *temp = msg;
128 if (strcasestr (chld_out.line[i], (expected_address == NULL ? query_address : expected_address)) != NULL) { 128 while ((temp = strchr(temp, '\t')) != NULL) {
129 msg = chld_out.line[i]; 129 *temp = ' ';
130 result = STATE_OK; 130 }
131 131 break;
132 /* Translate output TAB -> SPACE */ 132 }
133 t = msg; 133 }
134 while ((t = strchr(t, '\t')) != NULL) *t = ' '; 134
135 break; 135 if (result == STATE_UNKNOWN) {
136 } 136 msg = (char *)_("Server not found in ANSWER SECTION");
137 } 137 result = STATE_WARNING;
138 138 }
139 if (result == STATE_UNKNOWN) { 139
140 msg = (char *)_("Server not found in ANSWER SECTION"); 140 /* we found the answer section, so break out of the loop */
141 result = STATE_WARNING; 141 break;
142 } 142 }
143 143 }
144 /* we found the answer section, so break out of the loop */ 144
145 break; 145 if (result == STATE_UNKNOWN) {
146 } 146 msg = (char *)_("No ANSWER SECTION found");
147 } 147 result = STATE_CRITICAL;
148 148 }
149 if (result == STATE_UNKNOWN) { 149
150 msg = (char *)_("No ANSWER SECTION found"); 150 /* If we get anything on STDERR, at least set warning */
151 result = STATE_CRITICAL; 151 if (chld_err.buflen > 0) {
152 } 152 result = max_state(result, STATE_WARNING);
153 153 if (!msg) {
154 /* If we get anything on STDERR, at least set warning */ 154 for (size_t i = 0; i < chld_err.lines; i++) {
155 if(chld_err.buflen > 0) { 155 msg = strchr(chld_err.line[0], ':');
156 result = max_state(result, STATE_WARNING); 156 if (msg) {
157 if(!msg) for(i = 0; i < chld_err.lines; i++) { 157 msg++;
158 msg = strchr(chld_err.line[0], ':'); 158 break;
159 if(msg) { 159 }
160 msg++; 160 }
161 break; 161 }
162 } 162 }
163 } 163
164 } 164 long microsec = deltime(start_time);
165 165 double elapsed_time = (double)microsec / 1.0e6;
166 microsec = deltime (tv); 166
167 elapsed_time = (double)microsec / 1.0e6; 167 if (config.critical_interval > UNDEFINED && elapsed_time > config.critical_interval) {
168 168 result = STATE_CRITICAL;
169 if (critical_interval > UNDEFINED && elapsed_time > critical_interval) 169 }
170 result = STATE_CRITICAL; 170
171 171 else if (config.warning_interval > UNDEFINED && elapsed_time > config.warning_interval) {
172 else if (warning_interval > UNDEFINED && elapsed_time > warning_interval) 172 result = STATE_WARNING;
173 result = STATE_WARNING; 173 }
174 174
175 printf ("DNS %s - %.3f seconds response time (%s)|%s\n", 175 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time,
176 state_text (result), elapsed_time, 176 msg ? msg : _("Probably a non-existent host/domain"),
177 msg ? msg : _("Probably a non-existent host/domain"), 177 fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED), config.warning_interval,
178 fperfdata("time", elapsed_time, "s", 178 (config.critical_interval > UNDEFINED), config.critical_interval, true, 0, false, 0));
179 (warning_interval>UNDEFINED ? true:false), 179 exit(result);
180 warning_interval,
181 (critical_interval>UNDEFINED ? true:false),
182 critical_interval,
183 true, 0, false, 0));
184 return result;
185} 180}
186 181
187
188
189/* process command-line arguments */ 182/* process command-line arguments */
190int 183check_dig_config_wrapper process_arguments(int argc, char **argv) {
191process_arguments (int argc, char **argv) 184 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
192{ 185 {"query_address", required_argument, 0, 'l'},
193 int c; 186 {"warning", required_argument, 0, 'w'},
194 187 {"critical", required_argument, 0, 'c'},
195 int option = 0; 188 {"timeout", required_argument, 0, 't'},
196 static struct option longopts[] = { 189 {"dig-arguments", required_argument, 0, 'A'},
197 {"hostname", required_argument, 0, 'H'}, 190 {"verbose", no_argument, 0, 'v'},
198 {"query_address", required_argument, 0, 'l'}, 191 {"version", no_argument, 0, 'V'},
199 {"warning", required_argument, 0, 'w'}, 192 {"help", no_argument, 0, 'h'},
200 {"critical", required_argument, 0, 'c'}, 193 {"record_type", required_argument, 0, 'T'},
201 {"timeout", required_argument, 0, 't'}, 194 {"expected_address", required_argument, 0, 'a'},
202 {"dig-arguments", required_argument, 0, 'A'}, 195 {"port", required_argument, 0, 'p'},
203 {"verbose", no_argument, 0, 'v'}, 196 {"use-ipv4", no_argument, 0, '4'},
204 {"version", no_argument, 0, 'V'}, 197 {"use-ipv6", no_argument, 0, '6'},
205 {"help", no_argument, 0, 'h'}, 198 {0, 0, 0, 0}};
206 {"record_type", required_argument, 0, 'T'}, 199
207 {"expected_address", required_argument, 0, 'a'}, 200 check_dig_config_wrapper result = {
208 {"port", required_argument, 0, 'p'}, 201 .errorcode = OK,
209 {"use-ipv4", no_argument, 0, '4'}, 202 .config = check_dig_config_init(),
210 {"use-ipv6", no_argument, 0, '6'}, 203 };
211 {0, 0, 0, 0} 204
212 }; 205 if (argc < 2) {
213 206 result.errorcode = ERROR;
214 if (argc < 2) 207 return result;
215 return ERROR; 208 }
216 209
217 while (1) { 210 int option = 0;
218 c = getopt_long (argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option); 211 while (true) {
219 212 int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option);
220 if (c == -1 || c == EOF) 213
221 break; 214 if (option_index == -1 || option_index == EOF) {
222 215 break;
223 switch (c) { 216 }
224 case 'h': /* help */ 217
225 print_help (); 218 switch (option_index) {
226 exit (STATE_UNKNOWN); 219 case 'h': /* help */
227 case 'V': /* version */ 220 print_help();
228 print_revision (progname, NP_VERSION); 221 exit(STATE_UNKNOWN);
229 exit (STATE_UNKNOWN); 222 case 'V': /* version */
230 case 'H': /* hostname */ 223 print_revision(progname, NP_VERSION);
231 host_or_die(optarg); 224 exit(STATE_UNKNOWN);
232 dns_server = optarg; 225 case 'H': /* hostname */
233 break; 226 host_or_die(optarg);
234 case 'p': /* server port */ 227 result.config.dns_server = optarg;
235 if (is_intpos (optarg)) { 228 break;
236 server_port = atoi (optarg); 229 case 'p': /* server port */
237 } 230 if (is_intpos(optarg)) {
238 else { 231 result.config.server_port = atoi(optarg);
239 usage_va(_("Port must be a positive integer - %s"), optarg); 232 } else {
240 } 233 usage_va(_("Port must be a positive integer - %s"), optarg);
241 break; 234 }
242 case 'l': /* address to lookup */ 235 break;
243 query_address = optarg; 236 case 'l': /* address to lookup */
244 break; 237 result.config.query_address = optarg;
245 case 'w': /* warning */ 238 break;
246 if (is_nonnegative (optarg)) { 239 case 'w': /* warning */
247 warning_interval = strtod (optarg, NULL); 240 if (is_nonnegative(optarg)) {
248 } 241 result.config.warning_interval = strtod(optarg, NULL);
249 else { 242 } else {
250 usage_va(_("Warning interval must be a positive integer - %s"), optarg); 243 usage_va(_("Warning interval must be a positive integer - %s"), optarg);
251 } 244 }
252 break; 245 break;
253 case 'c': /* critical */ 246 case 'c': /* critical */
254 if (is_nonnegative (optarg)) { 247 if (is_nonnegative(optarg)) {
255 critical_interval = strtod (optarg, NULL); 248 result.config.critical_interval = strtod(optarg, NULL);
256 } 249 } else {
257 else { 250 usage_va(_("Critical interval must be a positive integer - %s"), optarg);
258 usage_va(_("Critical interval must be a positive integer - %s"), optarg); 251 }
259 } 252 break;
260 break; 253 case 't': /* timeout */
261 case 't': /* timeout */ 254 if (is_intnonneg(optarg)) {
262 if (is_intnonneg (optarg)) { 255 timeout_interval = atoi(optarg);
263 timeout_interval = atoi (optarg); 256 } else {
264 } 257 usage_va(_("Timeout interval must be a positive integer - %s"), optarg);
265 else { 258 }
266 usage_va(_("Timeout interval must be a positive integer - %s"), optarg); 259 break;
267 } 260 case 'A': /* dig arguments */
268 break; 261 result.config.dig_args = strdup(optarg);
269 case 'A': /* dig arguments */ 262 break;
270 dig_args = strdup(optarg); 263 case 'v': /* verbose */
271 break; 264 verbose++;
272 case 'v': /* verbose */ 265 break;
273 verbose = true; 266 case 'T':
274 break; 267 result.config.record_type = optarg;
275 case 'T': 268 break;
276 record_type = optarg; 269 case 'a':
277 break; 270 result.config.expected_address = optarg;
278 case 'a': 271 break;
279 expected_address = optarg; 272 case '4':
280 break; 273 result.config.query_transport = "-4";
281 case '4': 274 break;
282 query_transport = "-4"; 275 case '6':
283 break; 276 result.config.query_transport = "-6";
284 case '6': 277 break;
285 query_transport = "-6"; 278 default: /* usage5 */
286 break; 279 usage5();
287 default: /* usage5 */ 280 }
288 usage5(); 281 }
289 } 282
290 } 283 int index = optind;
291 284 if (result.config.dns_server == NULL) {
292 c = optind; 285 if (index < argc) {
293 if (dns_server == NULL) { 286 host_or_die(argv[index]);
294 if (c < argc) { 287 result.config.dns_server = argv[index];
295 host_or_die(argv[c]); 288 } else {
296 dns_server = argv[c]; 289 if (strcmp(result.config.query_transport, "-6") == 0) {
297 } 290 result.config.dns_server = strdup("::1");
298 else { 291 } else {
299 if (strcmp(query_transport,"-6") == 0) 292 result.config.dns_server = strdup("127.0.0.1");
300 dns_server = strdup("::1"); 293 }
301 else 294 }
302 dns_server = strdup ("127.0.0.1"); 295 }
303 } 296
304 } 297 return validate_arguments(result);
305
306 return validate_arguments ();
307} 298}
308 299
309 300check_dig_config_wrapper validate_arguments(check_dig_config_wrapper config_wrapper) {
310 301 if (config_wrapper.config.query_address == NULL) {
311int 302 config_wrapper.errorcode = ERROR;
312validate_arguments (void) 303 }
313{ 304 return config_wrapper;
314 if (query_address != NULL)
315 return OK;
316 else
317 return ERROR;
318} 305}
319 306
307void print_help(void) {
308 char *myport;
320 309
310 xasprintf(&myport, "%d", DEFAULT_PORT);
321 311
322void 312 print_revision(progname, NP_VERSION);
323print_help (void)
324{
325 char *myport;
326 313
327 xasprintf (&myport, "%d", DEFAULT_PORT); 314 printf("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
315 printf(COPYRIGHT, copyright, email);
328 316
329 print_revision (progname, NP_VERSION); 317 printf(_("This plugin tests the DNS service on the specified host using dig"));
330 318
331 printf ("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"); 319 printf("\n\n");
332 printf (COPYRIGHT, copyright, email);
333 320
334 printf (_("This plugin tests the DNS service on the specified host using dig")); 321 print_usage();
335 322
336 printf ("\n\n"); 323 printf(UT_HELP_VRSN);
337 324
338 print_usage (); 325 printf(UT_EXTRA_OPTS);
339 326
340 printf (UT_HELP_VRSN); 327 printf(UT_HOST_PORT, 'p', myport);
341 328
342 printf (UT_EXTRA_OPTS); 329 printf(" %s\n", "-4, --use-ipv4");
330 printf(" %s\n", _("Force dig to only use IPv4 query transport"));
331 printf(" %s\n", "-6, --use-ipv6");
332 printf(" %s\n", _("Force dig to only use IPv6 query transport"));
333 printf(" %s\n", "-l, --query_address=STRING");
334 printf(" %s\n", _("Machine name to lookup"));
335 printf(" %s\n", "-T, --record_type=STRING");
336 printf(" %s\n", _("Record type to lookup (default: A)"));
337 printf(" %s\n", "-a, --expected_address=STRING");
338 printf(" %s\n", _("An address expected to be in the answer section. If not set, uses whatever"));
339 printf(" %s\n", _("was in -l"));
340 printf(" %s\n", "-A, --dig-arguments=STRING");
341 printf(" %s\n", _("Pass STRING as argument(s) to dig"));
342 printf(UT_WARN_CRIT);
343 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
344 printf(UT_VERBOSE);
343 345
344 printf (UT_HOST_PORT, 'p', myport); 346 printf("\n");
347 printf("%s\n", _("Examples:"));
348 printf(" %s\n", "check_dig -H DNSSERVER -l www.example.com -A \"+tcp\"");
349 printf(" %s\n", "This will send a tcp query to DNSSERVER for www.example.com");
345 350
346 printf (" %s\n","-4, --use-ipv4"); 351 printf(UT_SUPPORT);
347 printf (" %s\n",_("Force dig to only use IPv4 query transport"));
348 printf (" %s\n","-6, --use-ipv6");
349 printf (" %s\n",_("Force dig to only use IPv6 query transport"));
350 printf (" %s\n","-l, --query_address=STRING");
351 printf (" %s\n",_("Machine name to lookup"));
352 printf (" %s\n","-T, --record_type=STRING");
353 printf (" %s\n",_("Record type to lookup (default: A)"));
354 printf (" %s\n","-a, --expected_address=STRING");
355 printf (" %s\n",_("An address expected to be in the answer section. If not set, uses whatever"));
356 printf (" %s\n",_("was in -l"));
357 printf (" %s\n","-A, --dig-arguments=STRING");
358 printf (" %s\n",_("Pass STRING as argument(s) to dig"));
359 printf (UT_WARN_CRIT);
360 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
361 printf (UT_VERBOSE);
362
363 printf ("\n");
364 printf ("%s\n", _("Examples:"));
365 printf (" %s\n", "check_dig -H DNSSERVER -l www.example.com -A \"+tcp\"");
366 printf (" %s\n", "This will send a tcp query to DNSSERVER for www.example.com");
367
368 printf (UT_SUPPORT);
369} 352}
370 353
371 354void print_usage(void) {
372 355 printf("%s\n", _("Usage:"));
373void 356 printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
374print_usage (void) 357 printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
375{ 358 printf(" [-t <timeout>] [-a <expected answer address>] [-v]\n");
376 printf ("%s\n", _("Usage:"));
377 printf ("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname);
378 printf (" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n");
379 printf (" [-t <timeout>] [-a <expected answer address>] [-v]\n");
380} 359}
diff --git a/plugins/check_dig.d/config.h b/plugins/check_dig.d/config.h
new file mode 100644
index 00000000..a570b633
--- /dev/null
+++ b/plugins/check_dig.d/config.h
@@ -0,0 +1,40 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6#define UNDEFINED 0
7#define DEFAULT_PORT 53
8#define DEFAULT_TRIES 2
9
10typedef struct {
11 char *query_address;
12 char *record_type;
13 char *expected_address;
14 char *dns_server;
15 char *query_transport;
16 int server_port;
17 char *dig_args;
18 int number_tries;
19
20 double warning_interval;
21 double critical_interval;
22} check_dig_config;
23
24check_dig_config check_dig_config_init() {
25 check_dig_config tmp = {
26 .query_address = NULL,
27 .record_type = "A",
28 .expected_address = NULL,
29 .dns_server = NULL,
30 .query_transport = "",
31 .server_port = DEFAULT_PORT,
32 .dig_args = "",
33 .number_tries = DEFAULT_TRIES,
34
35 .warning_interval = UNDEFINED,
36 .critical_interval = UNDEFINED,
37
38 };
39 return tmp;
40}
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index 24de2d45..515ddff0 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -1,1161 +1,1220 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_disk plugin 3 * Monitoring check_disk plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2008 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_disk plugin 10 * This file contains the check_disk plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29const char *progname = "check_disk"; 29const char *progname = "check_disk";
30const char *program_name = "check_disk"; /* Required for coreutils libs */ 30const char *program_name = "check_disk"; /* Required for coreutils libs */
31const char *copyright = "1999-2008"; 31const char *copyright = "1999-2024";
32const char *email = "devel@monitoring-plugins.org"; 32const char *email = "devel@monitoring-plugins.org";
33 33
34 34#include "states.h"
35#include "common.h" 35#include "common.h"
36#include "output.h"
37#include "perfdata.h"
38#include "utils_base.h"
39#include "lib/thresholds.h"
40
36#ifdef HAVE_SYS_STAT_H 41#ifdef HAVE_SYS_STAT_H
37# include <sys/stat.h> 42# include <sys/stat.h>
38#endif 43#endif
44
39#if HAVE_INTTYPES_H 45#if HAVE_INTTYPES_H
40# include <inttypes.h> 46# include <inttypes.h>
41#endif 47#endif
48
42#include <assert.h> 49#include <assert.h>
43#include "popen.h"
44#include "utils.h"
45#include "utils_disk.h"
46#include <stdarg.h> 50#include <stdarg.h>
47#include "fsusage.h" 51#include <stdint.h>
48#include "mountlist.h"
49#include <float.h> 52#include <float.h>
53#include "./popen.h"
54#include "./utils.h"
55#include "../gl/fsusage.h"
56#include "../gl/mountlist.h"
57#include "./check_disk.d/utils_disk.h"
58
50#if HAVE_LIMITS_H 59#if HAVE_LIMITS_H
51# include <limits.h> 60# include <limits.h>
52#endif 61#endif
62
53#include "regex.h" 63#include "regex.h"
54 64
55#ifdef __CYGWIN__ 65#ifdef __CYGWIN__
56# include <windows.h> 66# include <windows.h>
57# undef ERROR 67# undef ERROR
58# define ERROR -1 68# define ERROR -1
59#endif 69#endif
60 70
61/* If nonzero, show even filesystems with zero size or 71#ifdef _AIX
62 uninteresting types. */ 72# pragma alloca
63static int show_all_fs = 1; 73#endif
64
65/* If nonzero, show only local filesystems. */
66static int show_local_fs = 0;
67
68/* If nonzero, show only local filesystems but call stat() on remote ones. */
69static int stat_remote_fs = 0;
70
71/* If positive, the units to use when printing sizes;
72 if negative, the human-readable base. */
73/* static int output_block_size; */
74
75/* If nonzero, invoke the `sync' system call before getting any usage data.
76 Using this option can make df very slow, especially with many or very
77 busy disks. Note that this may make a difference on some systems --
78 SunOs4.1.3, for one. It is *not* necessary on Linux. */
79/* static int require_sync = 0; */
80
81/* Linked list of filesystem types to display.
82 If `fs_select_list' is NULL, list all types.
83 This table is generated dynamically from command-line options,
84 rather than hardcoding into the program what it thinks are the
85 valid filesystem types; let the user specify any filesystem type
86 they want to, and if there are any filesystems of that type, they
87 will be shown.
88
89 Some filesystem types:
90 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
91
92/* static struct parameter_list *fs_select_list; */
93
94/* Linked list of filesystem types to omit.
95 If the list is empty, don't exclude any types. */
96static struct regex_list *fs_exclude_list = NULL;
97 74
98/* Linked list of filesystem types to check. 75typedef struct {
99 If the list is empty, include all types. */ 76 int errorcode;
100static struct regex_list *fs_include_list; 77 check_disk_config config;
78} check_disk_config_wrapper;
79static check_disk_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
80
81static void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units,
82 char *warn_freespace_percent, char *crit_freespace_percent, char *warn_freeinodes_percent,
83 char *crit_freeinodes_percent);
84static double calculate_percent(uintmax_t /*value*/, uintmax_t /*total*/);
85static bool stat_path(parameter_list_elem * /*parameters*/, bool /*ignore_missing*/);
86
87/*
88 * Puts the values from a struct fs_usage into a parameter_list with an additional flag to control how reserved
89 * and inodes should be judged (ignored or not)
90 */
91static parameter_list_elem get_path_stats(parameter_list_elem parameters, struct fs_usage fsp, bool freespace_ignore_reserved);
92static mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit);
93
94void print_usage(void);
95static void print_help(void);
96
97static int verbose = 0;
98
99// This would not be necessary in C23!!
100const byte_unit Bytes_Factor = 1;
101const byte_unit KibiBytes_factor = 1024;
102const byte_unit MebiBytes_factor = 1048576;
103const byte_unit GibiBytes_factor = 1073741824;
104const byte_unit TebiBytes_factor = 1099511627776;
105const byte_unit PebiBytes_factor = 1125899906842624;
106const byte_unit ExbiBytes_factor = 1152921504606846976;
107const byte_unit KiloBytes_factor = 1000;
108const byte_unit MegaBytes_factor = 1000000;
109const byte_unit GigaBytes_factor = 1000000000;
110const byte_unit TeraBytes_factor = 1000000000000;
111const byte_unit PetaBytes_factor = 1000000000000000;
112const byte_unit ExaBytes_factor = 1000000000000000000;
113
114
115int main(int argc, char **argv) {
116 setlocale(LC_ALL, "");
117 bindtextdomain(PACKAGE, LOCALEDIR);
118 textdomain(PACKAGE);
101 119
102static struct name_list *dp_exclude_list; 120#ifdef __CYGWIN__
121 char mountdir[32];
122#endif
103 123
104static struct parameter_list *path_select_list = NULL; 124 // Parse extra opts if any
125 argv = np_extra_opts(&argc, argv, progname);
126
127 check_disk_config_wrapper tmp_config = process_arguments(argc, argv);
128 if (tmp_config.errorcode == ERROR) {
129 usage4(_("Could not parse arguments"));
130 }
131
132 check_disk_config config = tmp_config.config;
133
134 if (config.output_format_is_set) {
135 mp_set_format(config.output_format);
136 }
137
138 if (config.erronly) {
139 mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY);
140 }
141
142 if (!config.path_ignored) {
143 mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list, config.exact_match);
144 }
145
146 // Error if no match found for specified paths
147 for (parameter_list_elem *elem = config.path_select_list.first; elem;) {
148 if (!elem->best_match && config.ignore_missing) {
149 /* Delete the path from the list so that it is not stat-checked later in the code. */
150 elem = mp_int_fs_list_del(&config.path_select_list, elem);
151 continue;
152 }
153 if (!elem->best_match) {
154 /* Without --ignore-missing option, exit with Critical state. */
155 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), elem->name);
156 }
157
158 elem = mp_int_fs_list_get_next(elem);
159 }
160
161 mp_check overall = mp_check_init();
162 if (config.path_select_list.length == 0) {
163 mp_subcheck none_sc = mp_subcheck_init();
164 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
165 if (config.ignore_missing) {
166 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
167 } else {
168 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
169 if (verbose >= 2) {
170 printf("None of the provided paths were found\n");
171 }
172 }
173 mp_add_subcheck_to_check(&overall, none_sc);
174 mp_exit(overall);
175 }
105 176
106/* Linked list of mounted filesystems. */ 177 // Filter list first
107static struct mount_entry *mount_list; 178 for (parameter_list_elem *path = config.path_select_list.first; path;) {
179 if (!path->best_match) {
180 path = mp_int_fs_list_del(&config.path_select_list, path);
181 continue;
182 }
108 183
109/* For long options that have no equivalent short option, use a 184 struct mount_entry *mount_entry = path->best_match;
110 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
111enum
112{
113 SYNC_OPTION = CHAR_MAX + 1,
114 NO_SYNC_OPTION,
115 BLOCK_SIZE_OPTION
116};
117 185
118#ifdef _AIX 186#ifdef __CYGWIN__
119#pragma alloca 187 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) {
188 path = mp_int_fs_list_del(&config.path_select_list, path);
189 continue;
190 }
191
192 char *mountdir = NULL;
193 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
194 if (GetDriveType(mountdir) != DRIVE_FIXED) {
195 mount_entry->me_remote = 1;
196 }
120#endif 197#endif
121 198
122int process_arguments (int, char **); 199 /* Remove filesystems already seen */
123void print_path (const char *mypath); 200 if (np_seen_name(config.seen, mount_entry->me_mountdir)) {
124void set_all_thresholds (struct parameter_list *path); 201 path = mp_int_fs_list_del(&config.path_select_list, path);
125int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *); 202 continue;
126void print_help (void); 203 }
127void print_usage (void); 204
128double calculate_percent(uintmax_t, uintmax_t); 205 if (path->group == NULL) {
129bool stat_path (struct parameter_list *p); 206 if (config.fs_exclude_list && np_find_regmatch(config.fs_exclude_list, mount_entry->me_type)) {
130void get_stats (struct parameter_list *p, struct fs_usage *fsp); 207 // Skip excluded fs's
131void get_path_stats (struct parameter_list *p, struct fs_usage *fsp); 208 path = mp_int_fs_list_del(&config.path_select_list, path);
132 209 continue;
133char *exclude_device; 210 }
134char *units;
135uintmax_t mult = 1024 * 1024;
136int verbose = 0;
137bool erronly = false;
138bool display_mntp = false;
139bool exact_match = false;
140bool ignore_missing = false;
141bool freespace_ignore_reserved = false;
142bool display_inodes_perfdata = false;
143char *warn_freespace_units = NULL;
144char *crit_freespace_units = NULL;
145char *warn_freespace_percent = NULL;
146char *crit_freespace_percent = NULL;
147char *warn_usedspace_units = NULL;
148char *crit_usedspace_units = NULL;
149char *warn_usedspace_percent = NULL;
150char *crit_usedspace_percent = NULL;
151char *warn_usedinodes_percent = NULL;
152char *crit_usedinodes_percent = NULL;
153char *warn_freeinodes_percent = NULL;
154char *crit_freeinodes_percent = NULL;
155bool path_selected = false;
156bool path_ignored = false;
157char *group = NULL;
158struct stat *stat_buf;
159struct name_list *seen = NULL;
160
161
162int
163main (int argc, char **argv)
164{
165 int result = STATE_UNKNOWN;
166 int disk_result = STATE_UNKNOWN;
167 char *output;
168 char *ignored;
169 char *details;
170 char *perf;
171 char *perf_ilabel;
172 char *preamble = " - free space:";
173 char *ignored_preamble = " - ignored paths:";
174 char *flag_header;
175 int temp_result;
176
177 struct mount_entry *me;
178 struct fs_usage fsp;
179 struct parameter_list *temp_list, *path;
180 211
181#ifdef __CYGWIN__ 212 if (config.device_path_exclude_list && (np_find_name(config.device_path_exclude_list, mount_entry->me_devname) ||
182 char mountdir[32]; 213 np_find_name(config.device_path_exclude_list, mount_entry->me_mountdir))) {
183#endif 214 // Skip excluded device or mount paths
215 path = mp_int_fs_list_del(&config.path_select_list, path);
216 continue;
217 }
184 218
185 output = strdup (""); 219 if (config.fs_include_list && !np_find_regmatch(config.fs_include_list, mount_entry->me_type)) {
186 ignored = strdup (""); 220 // Skip not included fstypes
187 details = strdup (""); 221 path = mp_int_fs_list_del(&config.path_select_list, path);
188 perf = strdup (""); 222 continue;
189 perf_ilabel = strdup (""); 223 }
190 stat_buf = malloc(sizeof *stat_buf);
191
192 setlocale (LC_ALL, "");
193 bindtextdomain (PACKAGE, LOCALEDIR);
194 textdomain (PACKAGE);
195
196 mount_list = read_file_system_list (0);
197
198 /* Parse extra opts if any */
199 argv = np_extra_opts (&argc, argv, progname);
200
201 if (process_arguments (argc, argv) == ERROR)
202 usage4 (_("Could not parse arguments"));
203
204 /* If a list of paths has not been selected, find entire
205 mount list and create list of paths
206 */
207 if (path_selected == false && path_ignored == false) {
208 for (me = mount_list; me; me = me->me_next) {
209 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
210 path = np_add_parameter(&path_select_list, me->me_mountdir);
211 }
212 path->best_match = me;
213 path->group = group;
214 set_all_thresholds(path);
215 }
216 }
217
218 if (path_ignored == false) {
219 np_set_best_match(path_select_list, mount_list, exact_match);
220 }
221
222 /* Error if no match found for specified paths */
223 temp_list = path_select_list;
224
225 while (path_select_list) {
226 if (! path_select_list->best_match && ignore_missing == true) {
227 /* If the first element will be deleted, the temp_list must be updated with the new start address as well */
228 if (path_select_list == temp_list) {
229 temp_list = path_select_list->name_next;
230 }
231 /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */
232 xasprintf (&ignored, "%s %s;", ignored, path_select_list->name);
233 /* Delete the path from the list so that it is not stat-checked later in the code. */
234 path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev);
235 } else if (! path_select_list->best_match) {
236 /* Without --ignore-missing option, exit with Critical state. */
237 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name);
238 } else {
239 /* Continue jumping through the list */
240 path_select_list = path_select_list->name_next;
241 }
242 }
243
244 path_select_list = temp_list;
245
246 if (! path_select_list && ignore_missing == true) {
247 result = STATE_OK;
248 if (verbose >= 2) {
249 printf ("None of the provided paths were found\n");
250 }
251 }
252
253 /* Process for every path in list */
254 for (path = path_select_list; path; path=path->name_next) {
255 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
256 printf("Thresholds(pct) for %s warn: %f crit %f\n",
257 path->name,
258 path->freespace_percent->warning->end,
259 path->freespace_percent->critical->end);
260
261 if (verbose >= 3 && path->group != NULL)
262 printf("Group of %s: %s\n",path->name,path->group);
263
264 /* reset disk result */
265 disk_result = STATE_UNKNOWN;
266
267 me = path->best_match;
268
269 if (!me) {
270 continue;
271 }
272 224
273#ifdef __CYGWIN__ 225 /* Skip remote filesystems if we're not interested in them */
274 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) 226 if (mount_entry->me_remote && config.show_local_fs) {
275 continue; 227 if (config.stat_remote_fs) {
276 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10); 228 // TODO Stat here
277 if (GetDriveType(mountdir) != DRIVE_FIXED) 229 if (!stat_path(path, config.ignore_missing) && config.ignore_missing) {
278 me->me_remote = 1; 230 }
279#endif 231 }
280 /* Filters */ 232 continue;
281 233 }
282 /* Remove filesystems already seen */
283 if (np_seen_name(seen, me->me_mountdir)) {
284 continue;
285 }
286 np_add_name(&seen, me->me_mountdir);
287
288 if (path->group == NULL) {
289 /* Skip remote filesystems if we're not interested in them */
290 if (me->me_remote && show_local_fs) {
291 if (stat_remote_fs) {
292 if (!stat_path(path) && ignore_missing == true) {
293 result = STATE_OK;
294 xasprintf (&ignored, "%s %s;", ignored, path->name);
295 }
296 }
297 continue;
298 /* Skip pseudo fs's if we haven't asked for all fs's */
299 } else if (me->me_dummy && !show_all_fs) {
300 continue;
301 /* Skip excluded fstypes */
302 } else if (fs_exclude_list && np_find_regmatch (fs_exclude_list, me->me_type)) {
303 continue;
304 /* Skip excluded fs's */
305 } else if (dp_exclude_list &&
306 (np_find_name (dp_exclude_list, me->me_devname) ||
307 np_find_name (dp_exclude_list, me->me_mountdir))) {
308 continue;
309 /* Skip not included fstypes */
310 } else if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) {
311 continue;
312 }
313 }
314
315 if (!stat_path(path)) {
316 if (ignore_missing == true) {
317 result = STATE_OK;
318 xasprintf (&ignored, "%s %s;", ignored, path->name);
319 }
320 continue;
321 }
322 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
323
324 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
325 get_stats (path, &fsp);
326
327 if (verbose >= 3) {
328 printf ("For %s, used_pct=%f free_pct=%f used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%f free_inodes_pct=%f fsp.fsu_blocksize=%lu mult=%lu\n",
329 me->me_mountdir,
330 path->dused_pct,
331 path->dfree_pct,
332 path->dused_units,
333 path->dfree_units,
334 path->dtotal_units,
335 path->dused_inodes_percent,
336 path->dfree_inodes_percent,
337 fsp.fsu_blocksize,
338 mult);
339 }
340
341 /* Threshold comparisons */
342
343 temp_result = get_status(path->dfree_units, path->freespace_units);
344 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
345 disk_result = max_state( disk_result, temp_result );
346
347 temp_result = get_status(path->dfree_pct, path->freespace_percent);
348 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
349 disk_result = max_state( disk_result, temp_result );
350
351 temp_result = get_status(path->dused_units, path->usedspace_units);
352 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
353 disk_result = max_state( disk_result, temp_result );
354
355 temp_result = get_status(path->dused_pct, path->usedspace_percent);
356 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
357 disk_result = max_state( disk_result, temp_result );
358
359 temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent);
360 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
361 disk_result = max_state( disk_result, temp_result );
362
363 temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent);
364 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
365 disk_result = max_state( disk_result, temp_result );
366
367 result = max_state(result, disk_result);
368
369 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
370 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
371 data. Assumption that start=0. Roll on new syntax...
372 */
373
374 /* *_high_tide must be reinitialized at each run */
375 uint64_t warning_high_tide = UINT64_MAX;
376
377 if (path->freespace_units->warning != NULL) {
378 warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult;
379 }
380 if (path->freespace_percent->warning != NULL) {
381 warning_high_tide = min( warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end/100) * (path->dtotal_units * mult)) );
382 }
383
384 uint64_t critical_high_tide = UINT64_MAX;
385
386 if (path->freespace_units->critical != NULL) {
387 critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult;
388 }
389 if (path->freespace_percent->critical != NULL) {
390 critical_high_tide = min( critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end/100) * (path->dtotal_units * mult)) );
391 }
392
393 /* Nb: *_high_tide are unset when == UINT64_MAX */
394 xasprintf (&perf, "%s %s", perf,
395 perfdata_uint64 (
396 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
397 path->dused_units * mult, "B",
398 (warning_high_tide == UINT64_MAX ? false : true), warning_high_tide,
399 (critical_high_tide == UINT64_MAX ? false : true), critical_high_tide,
400 true, 0,
401 true, path->dtotal_units * mult));
402
403 if (display_inodes_perfdata) {
404 /* *_high_tide must be reinitialized at each run */
405 warning_high_tide = UINT64_MAX;
406 critical_high_tide = UINT64_MAX;
407
408 if (path->freeinodes_percent->warning != NULL) {
409 warning_high_tide = (uint64_t) fabs( min( (double) warning_high_tide, (double) (1.0 - path->freeinodes_percent->warning->end/100)*path->inodes_total ));
410 }
411 if (path->freeinodes_percent->critical != NULL) {
412 critical_high_tide = (uint64_t) fabs( min( (double) critical_high_tide, (double) (1.0 - path->freeinodes_percent->critical->end/100)*path->inodes_total ));
413 }
414
415 xasprintf (&perf_ilabel, "%s (inodes)", (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
416 /* Nb: *_high_tide are unset when == UINT64_MAX */
417 xasprintf (&perf, "%s %s", perf,
418 perfdata_uint64 (perf_ilabel,
419 path->inodes_used, "",
420 (warning_high_tide != UINT64_MAX ? true : false), warning_high_tide,
421 (critical_high_tide != UINT64_MAX ? true : false), critical_high_tide,
422 true, 0,
423 true, path->inodes_total));
424 }
425
426 if (disk_result==STATE_OK && erronly && !verbose)
427 continue;
428
429 if(disk_result && verbose >= 1) {
430 xasprintf(&flag_header, " %s [", state_text (disk_result));
431 } else {
432 xasprintf(&flag_header, "");
433 }
434 xasprintf (&output, "%s%s %s %llu%s (%.1f%%",
435 output, flag_header,
436 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
437 path->dfree_units,
438 units,
439 path->dfree_pct);
440 if (path->dused_inodes_percent < 0) {
441 xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : ""));
442 } else {
443 xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : ""));
444 }
445 free(flag_header);
446 }
447 }
448
449 if (verbose >= 2)
450 xasprintf (&output, "%s%s", output, details);
451
452 if (strcmp(output, "") == 0 && ! erronly) {
453 preamble = "";
454 xasprintf (&output, " - No disks were found for provided parameters");
455 }
456
457 printf ("DISK %s%s%s%s%s|%s\n", state_text (result), ((erronly && result==STATE_OK)) ? "" : preamble, output, (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
458 return result;
459}
460 234
235 // TODO why stat here? remove unstatable fs?
236 if (!stat_path(path, config.ignore_missing)) {
237 // if (config.ignore_missing) {
238 // xasprintf(&ignored, "%s %s;", ignored, path->name);
239 // }
240 // not accessible, remove from list
241 path = mp_int_fs_list_del(&config.path_select_list, path);
242 continue;
243 }
244 }
245
246 path = mp_int_fs_list_get_next(path);
247 }
248
249 // now get the actual measurements
250 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;) {
251 // Get actual metrics here
252 struct mount_entry *mount_entry = filesystem->best_match;
253 struct fs_usage fsp = {0};
254 get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp);
255
256 if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) {
257 *filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved);
258
259 if (verbose >= 3) {
260 printf("For %s, used_units=%lu free_units=%lu total_units=%lu "
261 "fsp.fsu_blocksize=%lu\n",
262 mount_entry->me_mountdir, filesystem->used_bytes, filesystem->free_bytes, filesystem->total_bytes,
263 fsp.fsu_blocksize);
264 }
265 } else {
266 // failed to retrieve file system data or not mounted?
267 filesystem = mp_int_fs_list_del(&config.path_select_list, filesystem);
268 continue;
269 }
270 filesystem = mp_int_fs_list_get_next(filesystem);
271 }
272
273 if (verbose > 2) {
274 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
275 filesystem = mp_int_fs_list_get_next(filesystem)) {
276 assert(filesystem->best_match != NULL);
277 if (filesystem->best_match == NULL) {
278 printf("Filesystem path %s has no mount_entry!\n", filesystem->name);
279 } else {
280 // printf("Filesystem path %s has a mount_entry!\n", filesystem->name);
281 }
282 }
283 }
284
285 measurement_unit_list *measurements = NULL;
286 measurement_unit_list *current = NULL;
287 // create measuring units, because of groups
288 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem; filesystem = mp_int_fs_list_get_next(filesystem)) {
289 assert(filesystem->best_match != NULL);
290
291 if (filesystem->group == NULL) {
292 // create a measurement unit for the fs
293 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
294 if (measurements == NULL) {
295 measurements = current = add_measurement_list(NULL, unit);
296 } else {
297 current = add_measurement_list(measurements, unit);
298 }
299 } else {
300 // Grouped elements are consecutive
301 if (measurements == NULL) {
302 // first entry
303 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
304 unit.name = strdup(filesystem->group);
305 measurements = current = add_measurement_list(NULL, unit);
306 } else {
307 // if this is the first element of a group, the name of the previous entry is different
308 if (strcmp(filesystem->group, current->unit.name) != 0) {
309 // so, this must be the first element of a group
310 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
311 unit.name = filesystem->group;
312 current = add_measurement_list(measurements, unit);
313
314 } else {
315 // NOT the first entry of a group, add info to the other one
316 current->unit = add_filesystem_to_measurement_unit(current->unit, *filesystem);
317 }
318 }
319 }
320 }
321
322 /* Process for every path in list */
323 if (measurements != NULL) {
324 for (measurement_unit_list *unit = measurements; unit; unit = unit->next) {
325 mp_subcheck unit_sc = evaluate_filesystem(unit->unit, config.display_inodes_perfdata, config.display_unit);
326 mp_add_subcheck_to_check(&overall, unit_sc);
327 }
328 } else {
329 // Apparently no machting fs found
330 mp_subcheck none_sc = mp_subcheck_init();
331 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
332
333 if (config.ignore_missing) {
334 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
335 } else {
336 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
337 }
338 mp_add_subcheck_to_check(&overall, none_sc);
339 }
340
341 mp_exit(overall);
342}
461 343
462double calculate_percent(uintmax_t value, uintmax_t total) { 344double calculate_percent(uintmax_t value, uintmax_t total) {
463 double pct = -1; 345 double pct = -1;
464 if(value <= DBL_MAX && total != 0) { 346 if (value <= DBL_MAX && total != 0) {
465 pct = (double)value / total * 100.0; 347 pct = (double)value / (double)total * 100.0;
466 } 348 }
467 return pct; 349
350 return pct;
468} 351}
469 352
470/* process command-line arguments */ 353/* process command-line arguments */
471int 354check_disk_config_wrapper process_arguments(int argc, char **argv) {
472process_arguments (int argc, char **argv) 355
473{ 356 check_disk_config_wrapper result = {
474 int c, err; 357 .errorcode = OK,
475 struct parameter_list *se; 358 .config = check_disk_config_init(),
476 struct parameter_list *temp_list = NULL, *previous = NULL; 359 };
477 struct mount_entry *me; 360
478 regex_t re; 361 if (argc < 2) {
479 int cflags = REG_NOSUB | REG_EXTENDED; 362 result.errorcode = ERROR;
480 int default_cflags = cflags; 363 return result;
481 char errbuf[MAX_INPUT_BUFFER]; 364 }
482 int fnd = 0; 365
483 366 enum {
484 int option = 0; 367 output_format_index = CHAR_MAX + 1,
485 static struct option longopts[] = { 368 display_unit_index,
486 {"timeout", required_argument, 0, 't'}, 369 };
487 {"warning", required_argument, 0, 'w'}, 370
488 {"critical", required_argument, 0, 'c'}, 371 static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
489 {"iwarning", required_argument, 0, 'W'}, 372 {"warning", required_argument, 0, 'w'},
490 /* Dang, -C is taken. We might want to reshuffle this. */ 373 {"critical", required_argument, 0, 'c'},
491 {"icritical", required_argument, 0, 'K'}, 374 {"iwarning", required_argument, 0, 'W'},
492 {"kilobytes", no_argument, 0, 'k'}, 375 {"icritical", required_argument, 0, 'K'},
493 {"megabytes", no_argument, 0, 'm'}, 376 {"kilobytes", no_argument, 0, 'k'},
494 {"units", required_argument, 0, 'u'}, 377 {"megabytes", no_argument, 0, 'm'},
495 {"path", required_argument, 0, 'p'}, 378 {"units", required_argument, 0, 'u'},
496 {"partition", required_argument, 0, 'p'}, 379 {"path", required_argument, 0, 'p'},
497 {"exclude_device", required_argument, 0, 'x'}, 380 {"partition", required_argument, 0, 'p'},
498 {"exclude-type", required_argument, 0, 'X'}, 381 {"exclude_device", required_argument, 0, 'x'},
499 {"include-type", required_argument, 0, 'N'}, 382 {"exclude-type", required_argument, 0, 'X'},
500 {"group", required_argument, 0, 'g'}, 383 {"include-type", required_argument, 0, 'N'},
501 {"eregi-path", required_argument, 0, 'R'}, 384 {"group", required_argument, 0, 'g'},
502 {"eregi-partition", required_argument, 0, 'R'}, 385 {"eregi-path", required_argument, 0, 'R'},
503 {"ereg-path", required_argument, 0, 'r'}, 386 {"eregi-partition", required_argument, 0, 'R'},
504 {"ereg-partition", required_argument, 0, 'r'}, 387 {"ereg-path", required_argument, 0, 'r'},
505 {"freespace-ignore-reserved", no_argument, 0, 'f'}, 388 {"ereg-partition", required_argument, 0, 'r'},
506 {"ignore-ereg-path", required_argument, 0, 'i'}, 389 {"freespace-ignore-reserved", no_argument, 0, 'f'},
507 {"ignore-ereg-partition", required_argument, 0, 'i'}, 390 {"ignore-ereg-path", required_argument, 0, 'i'},
508 {"ignore-eregi-path", required_argument, 0, 'I'}, 391 {"ignore-ereg-partition", required_argument, 0, 'i'},
509 {"ignore-eregi-partition", required_argument, 0, 'I'}, 392 {"ignore-eregi-path", required_argument, 0, 'I'},
510 {"ignore-missing", no_argument, 0, 'n'}, 393 {"ignore-eregi-partition", required_argument, 0, 'I'},
511 {"local", no_argument, 0, 'l'}, 394 {"ignore-missing", no_argument, 0, 'n'},
512 {"stat-remote-fs", no_argument, 0, 'L'}, 395 {"local", no_argument, 0, 'l'},
513 {"iperfdata", no_argument, 0, 'P'}, 396 {"stat-remote-fs", no_argument, 0, 'L'},
514 {"mountpoint", no_argument, 0, 'M'}, 397 {"iperfdata", no_argument, 0, 'P'},
515 {"errors-only", no_argument, 0, 'e'}, 398 {"mountpoint", no_argument, 0, 'M'},
516 {"exact-match", no_argument, 0, 'E'}, 399 {"errors-only", no_argument, 0, 'e'},
517 {"all", no_argument, 0, 'A'}, 400 {"exact-match", no_argument, 0, 'E'},
518 {"verbose", no_argument, 0, 'v'}, 401 {"all", no_argument, 0, 'A'},
519 {"quiet", no_argument, 0, 'q'}, 402 {"verbose", no_argument, 0, 'v'},
520 {"clear", no_argument, 0, 'C'}, 403 {"quiet", no_argument, 0, 'q'},
521 {"version", no_argument, 0, 'V'}, 404 {"clear", no_argument, 0, 'C'},
522 {"help", no_argument, 0, 'h'}, 405 {"version", no_argument, 0, 'V'},
523 {0, 0, 0, 0} 406 {"help", no_argument, 0, 'h'},
524 }; 407 {"output-format", required_argument, 0, output_format_index},
525 408 {"display-unit", required_argument, 0, display_unit_index},
526 if (argc < 2) 409 {0, 0, 0, 0}};
527 return ERROR; 410
528 411 for (int index = 1; index < argc; index++) {
529 np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED); 412 if (strcmp("-to", argv[index]) == 0) {
530 413 strcpy(argv[index], "-t");
531 for (c = 1; c < argc; c++) 414 }
532 if (strcmp ("-to", argv[c]) == 0) 415 }
533 strcpy (argv[c], "-t"); 416
534 417 int cflags = REG_NOSUB | REG_EXTENDED;
535 while (1) { 418 int default_cflags = cflags;
536 c = getopt_long (argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option); 419 char *warn_freespace_units = NULL;
537 420 char *crit_freespace_units = NULL;
538 if (c == -1 || c == EOF) 421 char *warn_freespace_percent = NULL;
539 break; 422 char *crit_freespace_percent = NULL;
540 423 char *warn_freeinodes_percent = NULL;
541 switch (c) { 424 char *crit_freeinodes_percent = NULL;
542 case 't': /* timeout period */ 425
543 if (is_integer (optarg)) { 426 bool path_selected = false;
544 timeout_interval = atoi (optarg); 427 char *group = NULL;
545 break; 428 byte_unit unit = MebiBytes_factor;
546 } 429
547 else { 430 result.config.mount_list = read_file_system_list(false);
548 usage2 (_("Timeout interval must be a positive integer"), optarg); 431
549 } 432 np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED);
550 433
551 /* See comments for 'c' */ 434 while (true) {
552 case 'w': /* warning threshold */ 435 int option = 0;
436 int option_index = getopt_long(argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
437
438 if (option_index == -1 || option_index == EOF) {
439 break;
440 }
441
442 switch (option_index) {
443 case 't': /* timeout period */
444 if (is_integer(optarg)) {
445 timeout_interval = atoi(optarg);
446 break;
447 } else {
448 usage2(_("Timeout interval must be a positive integer"), optarg);
449 }
450
451 /* See comments for 'c' */
452 case 'w': /* warning threshold */
553 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 453 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
554 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg); 454 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg);
555 } 455 }
556 456
557 if (strstr(optarg, "%")) { 457 if (strstr(optarg, "%")) {
558 if (*optarg == '@') { 458 if (*optarg == '@') {
559 warn_freespace_percent = optarg; 459 warn_freespace_percent = optarg;
560 } else { 460 } else {
561 xasprintf(&warn_freespace_percent, "@%s", optarg); 461 xasprintf(&warn_freespace_percent, "@%s", optarg);
562 } 462 }
563 } else { 463 } else {
564 if (*optarg == '@') { 464 if (*optarg == '@') {
565 warn_freespace_units = optarg; 465 warn_freespace_units = optarg;
566 } else { 466 } else {
567 xasprintf(&warn_freespace_units, "@%s", optarg); 467 xasprintf(&warn_freespace_units, "@%s", optarg);
568 } 468 }
569 } 469 }
570 break; 470 break;
571 471
572 /* Awful mistake where the range values do not make sense. Normally, 472 /* Awful mistake where the range values do not make sense. Normally,
573 you alert if the value is within the range, but since we are using 473 * you alert if the value is within the range, but since we are using
574 freespace, we have to alert if outside the range. Thus we artificially 474 * freespace, we have to alert if outside the range. Thus we artificially
575 force @ at the beginning of the range, so that it is backwards compatible 475 * force @ at the beginning of the range, so that it is backwards compatible
576 */ 476 */
577 case 'c': /* critical threshold */ 477 case 'c': /* critical threshold */
578 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 478 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
579 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg); 479 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
580 } 480 }
581 481
582 if (strstr(optarg, "%")) { 482 if (strstr(optarg, "%")) {
583 if (*optarg == '@') { 483 if (*optarg == '@') {
584 crit_freespace_percent = optarg; 484 crit_freespace_percent = optarg;
585 } else { 485 } else {
586 xasprintf(&crit_freespace_percent, "@%s", optarg); 486 xasprintf(&crit_freespace_percent, "@%s", optarg);
587 } 487 }
588 } else { 488 } else {
589 if (*optarg == '@') { 489 if (*optarg == '@') {
590 crit_freespace_units = optarg; 490 crit_freespace_units = optarg;
591 } else { 491 } else {
592 xasprintf(&crit_freespace_units, "@%s", optarg); 492 xasprintf(&crit_freespace_units, "@%s", optarg);
593 } 493 }
594 } 494 }
595 break; 495 break;
596
597 case 'W': /* warning inode threshold */
598 if (*optarg == '@') {
599 warn_freeinodes_percent = optarg;
600 } else {
601 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
602 }
603 break;
604 case 'K': /* critical inode threshold */
605 if (*optarg == '@') {
606 crit_freeinodes_percent = optarg;
607 } else {
608 xasprintf(&crit_freeinodes_percent, "@%s", optarg);
609 }
610 break;
611 case 'u':
612 if (units)
613 free(units);
614 if (! strcasecmp (optarg, "bytes")) {
615 mult = (uintmax_t)1;
616 units = strdup ("B");
617 } else if (!strcmp(optarg, "KiB")) {
618 mult = (uintmax_t)1024;
619 units = strdup ("KiB");
620 } else if (! strcmp (optarg, "kB")) {
621 mult = (uintmax_t)1000;
622 units = strdup ("kB");
623 } else if (!strcmp(optarg, "MiB")) {
624 mult = (uintmax_t)1024 * 1024;
625 units = strdup ("MiB");
626 } else if (! strcmp (optarg, "MB")) {
627 mult = (uintmax_t)1000 * 1000;
628 units = strdup ("MB");
629 } else if (!strcmp(optarg, "GiB")) {
630 mult = (uintmax_t)1024 * 1024 * 1024;
631 units = strdup ("GiB");
632 } else if (! strcmp (optarg, "GB")){
633 mult = (uintmax_t)1000 * 1000 * 1000;
634 units = strdup ("GB");
635 } else if (!strcmp(optarg, "TiB")) {
636 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
637 units = strdup ("TiB");
638 } else if (! strcmp (optarg, "TB")) {
639 mult = (uintmax_t)1000 * 1000 * 1000 * 1000;
640 units = strdup ("TB");
641 } else if (!strcmp(optarg, "PiB")) {
642 mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024;
643 units = strdup ("PiB");
644 } else if (! strcmp (optarg, "PB")){
645 mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000;
646 units = strdup ("PB");
647 } else {
648 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
649 }
650 if (units == NULL)
651 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
652 break;
653 case 'k': /* display mountpoint */
654 mult = 1024;
655 if (units)
656 free(units);
657 units = strdup ("kiB");
658 break;
659 case 'm': /* display mountpoint */
660 mult = 1024 * 1024;
661 if (units)
662 free(units);
663 units = strdup ("MiB");
664 break;
665 case 'L':
666 stat_remote_fs = 1;
667 /* fallthrough */
668 case 'l':
669 show_local_fs = 1;
670 break;
671 case 'P':
672 display_inodes_perfdata = 1;
673 break;
674 case 'p': /* select path */
675 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
676 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
677 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
678 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
679 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
680 }
681
682 /* add parameter if not found. overwrite thresholds if path has already been added */
683 if (! (se = np_find_parameter(path_select_list, optarg))) {
684 se = np_add_parameter(&path_select_list, optarg);
685
686 if (stat(optarg, &stat_buf[0]) && ignore_missing == true) {
687 path_ignored = true;
688 break;
689 }
690 }
691 se->group = group;
692 set_all_thresholds(se);
693
694 /* With autofs, it is required to stat() the path before re-populating the mount_list */
695 if (!stat_path(se)) {
696 break;
697 }
698 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
699 * pointers are copied around. One of the reason it wasn't done yet is that other parts
700 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
701 mount_list = read_file_system_list (0);
702 np_set_best_match(se, mount_list, exact_match);
703
704 path_selected = true;
705 break;
706 case 'x': /* exclude path or partition */
707 np_add_name(&dp_exclude_list, optarg);
708 break;
709 case 'X': /* exclude file system type */
710 err = np_add_regex(&fs_exclude_list, optarg, REG_EXTENDED);
711 if (err != 0) {
712 regerror (err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
713 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
714 }
715 break;
716 case 'N': /* include file system type */
717 err = np_add_regex(&fs_include_list, optarg, REG_EXTENDED);
718 if (err != 0) {
719 regerror (err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
720 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
721 }
722 break;
723 case 'v': /* verbose */
724 verbose++;
725 break;
726 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
727 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
728 erronly = true;
729 break;
730 case 'e':
731 erronly = true;
732 break;
733 case 'E':
734 if (path_selected)
735 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
736 exact_match = true;
737 break;
738 case 'f':
739 freespace_ignore_reserved = true;
740 break;
741 case 'g':
742 if (path_selected)
743 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
744 group = optarg;
745 break;
746 case 'I':
747 cflags |= REG_ICASE;
748 // Intentional fallthrough
749 case 'i':
750 if (!path_selected)
751 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
752 err = regcomp(&re, optarg, cflags);
753 if (err != 0) {
754 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
755 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
756 }
757
758 temp_list = path_select_list;
759
760 previous = NULL;
761 while (temp_list) {
762 if (temp_list->best_match) {
763 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
764
765 if (verbose >=3)
766 printf("ignoring %s matching regex\n", temp_list->name);
767
768 temp_list = np_del_parameter(temp_list, previous);
769 /* pointer to first element needs to be updated if first item gets deleted */
770 if (previous == NULL)
771 path_select_list = temp_list;
772 } else {
773 previous = temp_list;
774 temp_list = temp_list->name_next;
775 }
776 } else {
777 previous = temp_list;
778 temp_list = temp_list->name_next;
779 }
780 }
781
782
783 cflags = default_cflags;
784 break;
785
786 case 'n':
787 ignore_missing = true;
788 break;
789 case 'A':
790 optarg = strdup(".*");
791 // Intentional fallthrough
792 case 'R':
793 cflags |= REG_ICASE;
794 // Intentional fallthrough
795 case 'r':
796 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
797 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
798 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
799 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
800 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
801 }
802
803 err = regcomp(&re, optarg, cflags);
804 if (err != 0) {
805 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
806 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
807 }
808
809 for (me = mount_list; me; me = me->me_next) {
810 if (np_regex_match_mount_entry(me, &re)) {
811 fnd = true;
812 if (verbose >= 3)
813 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
814
815 /* add parameter if not found. overwrite thresholds if path has already been added */
816 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
817 se = np_add_parameter(&path_select_list, me->me_mountdir);
818 }
819 se->group = group;
820 set_all_thresholds(se);
821 }
822 }
823
824 if (!fnd && ignore_missing == true) {
825 path_ignored = true;
826 path_selected = true;
827 break;
828 } else if (!fnd)
829 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
830 _("Regular expression did not match any path or disk"), optarg);
831
832 fnd = false;
833 path_selected = true;
834 np_set_best_match(path_select_list, mount_list, exact_match);
835 cflags = default_cflags;
836
837 break;
838 case 'M': /* display mountpoint */
839 display_mntp = true;
840 break;
841 case 'C':
842 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
843 if (path_selected == false) {
844 struct parameter_list *path;
845 for (me = mount_list; me; me = me->me_next) {
846 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
847 path = np_add_parameter(&path_select_list, me->me_mountdir);
848 path->best_match = me;
849 path->group = group;
850 set_all_thresholds(path);
851 }
852 }
853 warn_freespace_units = NULL;
854 crit_freespace_units = NULL;
855 warn_usedspace_units = NULL;
856 crit_usedspace_units = NULL;
857 warn_freespace_percent = NULL;
858 crit_freespace_percent = NULL;
859 warn_usedspace_percent = NULL;
860 crit_usedspace_percent = NULL;
861 warn_usedinodes_percent = NULL;
862 crit_usedinodes_percent = NULL;
863 warn_freeinodes_percent = NULL;
864 crit_freeinodes_percent = NULL;
865
866 path_selected = false;
867 group = NULL;
868 break;
869 case 'V': /* version */
870 print_revision (progname, NP_VERSION);
871 exit (STATE_UNKNOWN);
872 case 'h': /* help */
873 print_help ();
874 exit (STATE_UNKNOWN);
875 case '?': /* help */
876 usage (_("Unknown argument"));
877 }
878 }
879
880 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
881 c = optind;
882 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
883 warn_usedspace_percent = argv[c++];
884
885 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
886 crit_usedspace_percent = argv[c++];
887
888 if (argc > c) {
889 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
890 path_selected = true;
891 set_all_thresholds(se);
892 }
893
894 if (units == NULL) {
895 units = strdup ("MiB");
896 mult = (uintmax_t)1024 * 1024;
897 }
898
899 return true;
900}
901 496
497 case 'W': /* warning inode threshold */
498 if (*optarg == '@') {
499 warn_freeinodes_percent = optarg;
500 } else {
501 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
502 }
503 break;
504 case 'K': /* critical inode threshold */
505 if (*optarg == '@') {
506 crit_freeinodes_percent = optarg;
507 } else {
508 xasprintf(&crit_freeinodes_percent, "@%s", optarg);
509 }
510 break;
511 case 'u':
512 if (!strcasecmp(optarg, "bytes")) {
513 unit = Bytes_Factor;
514 } else if (!strcmp(optarg, "KiB")) {
515 unit = KibiBytes_factor;
516 } else if (!strcmp(optarg, "kB")) {
517 unit = KiloBytes_factor;
518 } else if (!strcmp(optarg, "MiB")) {
519 unit = MebiBytes_factor;
520 } else if (!strcmp(optarg, "MB")) {
521 unit = MegaBytes_factor;
522 } else if (!strcmp(optarg, "GiB")) {
523 unit = GibiBytes_factor;
524 } else if (!strcmp(optarg, "GB")) {
525 unit = GigaBytes_factor;
526 } else if (!strcmp(optarg, "TiB")) {
527 unit = TebiBytes_factor;
528 } else if (!strcmp(optarg, "TB")) {
529 unit = TeraBytes_factor;
530 } else if (!strcmp(optarg, "PiB")) {
531 unit = PebiBytes_factor;
532 } else if (!strcmp(optarg, "PB")) {
533 unit = PetaBytes_factor;
534 } else {
535 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
536 }
537 break;
538 case 'k':
539 unit = KibiBytes_factor;
540 break;
541 case 'm':
542 unit = MebiBytes_factor;
543 break;
544 case display_unit_index:
545 if (!strcasecmp(optarg, "bytes")) {
546 result.config.display_unit = Bytes;
547 } else if (!strcmp(optarg, "KiB")) {
548 result.config.display_unit = KibiBytes;
549 } else if (!strcmp(optarg, "kB")) {
550 result.config.display_unit = KiloBytes;
551 } else if (!strcmp(optarg, "MiB")) {
552 result.config.display_unit = MebiBytes;
553 } else if (!strcmp(optarg, "MB")) {
554 result.config.display_unit = MegaBytes;
555 } else if (!strcmp(optarg, "GiB")) {
556 result.config.display_unit = GibiBytes;
557 } else if (!strcmp(optarg, "GB")) {
558 result.config.display_unit = GigaBytes;
559 } else if (!strcmp(optarg, "TiB")) {
560 result.config.display_unit = TebiBytes;
561 } else if (!strcmp(optarg, "TB")) {
562 result.config.display_unit = TeraBytes;
563 } else if (!strcmp(optarg, "PiB")) {
564 result.config.display_unit = PebiBytes;
565 } else if (!strcmp(optarg, "PB")) {
566 result.config.display_unit = PetaBytes;
567 } else {
568 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
569 }
570 break;
571 case 'L':
572 result.config.stat_remote_fs = true;
573 /* fallthrough */
574 case 'l':
575 result.config.show_local_fs = true;
576 break;
577 case 'P':
578 result.config.display_inodes_perfdata = true;
579 break;
580 case 'p': /* select path */ {
581 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
582 warn_freeinodes_percent || crit_freeinodes_percent)) {
583 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
584 }
902 585
586 /* add parameter if not found. overwrite thresholds if path has already been added */
587 parameter_list_elem *search_entry;
588 if (!(search_entry = mp_int_fs_list_find(result.config.path_select_list, optarg))) {
589 search_entry = mp_int_fs_list_append(&result.config.path_select_list, optarg);
903 590
904void 591 // struct stat stat_buf = {};
905print_path (const char *mypath) 592 // if (stat(optarg, &stat_buf) && result.config.ignore_missing) {
906{ 593 // result.config.path_ignored = true;
907 if (mypath == NULL) 594 // break;
908 printf ("\n"); 595 // }
909 else 596 }
910 printf (_(" for %s\n"), mypath); 597 search_entry->group = group;
911} 598 set_all_thresholds(search_entry, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
599
600 warn_freeinodes_percent, crit_freeinodes_percent);
601
602 /* With autofs, it is required to stat() the path before re-populating the mount_list */
603 // if (!stat_path(se, result.config.ignore_missing)) {
604 // break;
605 // }
606 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
607
608 path_selected = true;
609 } break;
610 case 'x': /* exclude path or partition */
611 np_add_name(&result.config.device_path_exclude_list, optarg);
612 break;
613 case 'X': /* exclude file system type */ {
614 int err = np_add_regex(&result.config.fs_exclude_list, optarg, REG_EXTENDED);
615 if (err != 0) {
616 char errbuf[MAX_INPUT_BUFFER];
617 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
618 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
619 }
620 break;
621 case 'N': /* include file system type */
622 err = np_add_regex(&result.config.fs_include_list, optarg, REG_EXTENDED);
623 if (err != 0) {
624 char errbuf[MAX_INPUT_BUFFER];
625 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
626 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
627 }
628 } break;
629 case 'v': /* verbose */
630 verbose++;
631 break;
632 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
633 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
634 result.config.erronly = true;
635 break;
636 case 'e':
637 result.config.erronly = true;
638 break;
639 case 'E':
640 if (path_selected) {
641 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
642 }
643 result.config.exact_match = true;
644 break;
645 case 'f':
646 result.config.freespace_ignore_reserved = true;
647 break;
648 case 'g':
649 if (path_selected) {
650 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
651 }
652 group = optarg;
653 break;
654 case 'I':
655 cflags |= REG_ICASE;
656 // Intentional fallthrough
657 case 'i': {
658 if (!path_selected) {
659 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
660 _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
661 }
662 regex_t regex;
663 int err = regcomp(&regex, optarg, cflags);
664 if (err != 0) {
665 char errbuf[MAX_INPUT_BUFFER];
666 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
667 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
668 }
912 669
670 for (parameter_list_elem *elem = result.config.path_select_list.first; elem;) {
671 if (elem->best_match) {
672 if (np_regex_match_mount_entry(elem->best_match, &regex)) {
913 673
914void 674 if (verbose >= 3) {
915set_all_thresholds (struct parameter_list *path) 675 printf("ignoring %s matching regex\n", elem->name);
916{ 676 }
917 if (path->freespace_units != NULL) free(path->freespace_units);
918 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
919 if (path->freespace_percent != NULL) free (path->freespace_percent);
920 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
921 if (path->usedspace_units != NULL) free (path->usedspace_units);
922 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
923 if (path->usedspace_percent != NULL) free (path->usedspace_percent);
924 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
925 if (path->usedinodes_percent != NULL) free (path->usedinodes_percent);
926 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
927 if (path->freeinodes_percent != NULL) free (path->freeinodes_percent);
928 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
929}
930 677
931void 678 elem = mp_int_fs_list_del(&result.config.path_select_list, elem);
932print_help (void) 679 continue;
933{ 680 }
934 print_revision (progname, NP_VERSION); 681 }
935
936 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
937 printf (COPYRIGHT, copyright, email);
938
939 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
940 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
941
942 printf ("\n\n");
943
944 print_usage ();
945
946 printf (UT_HELP_VRSN);
947 printf (UT_EXTRA_OPTS);
948
949 printf (" %s\n", "-w, --warning=INTEGER");
950 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
951 printf (" %s\n", "-w, --warning=PERCENT%");
952 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
953 printf (" %s\n", "-c, --critical=INTEGER");
954 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
955 printf (" %s\n", "-c, --critical=PERCENT%");
956 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
957 printf (" %s\n", "-W, --iwarning=PERCENT%");
958 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
959 printf (" %s\n", "-K, --icritical=PERCENT%");
960 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
961 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
962 printf (" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
963 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
964 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
965 printf (" %s\n", "-C, --clear");
966 printf (" %s\n", _("Clear thresholds"));
967 printf (" %s\n", "-E, --exact-match");
968 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
969 printf (" %s\n", "-e, --errors-only");
970 printf (" %s\n", _("Display only devices/mountpoints with errors"));
971 printf (" %s\n", "-f, --freespace-ignore-reserved");
972 printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
973 printf (" %s\n", "-P, --iperfdata");
974 printf (" %s\n", _("Display inode usage in perfdata"));
975 printf (" %s\n", "-g, --group=NAME");
976 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
977 printf (" %s\n", "-k, --kilobytes");
978 printf (" %s\n", _("Same as '--units kB'"));
979 printf (" %s\n", "-l, --local");
980 printf (" %s\n", _("Only check local filesystems"));
981 printf (" %s\n", "-L, --stat-remote-fs");
982 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
983 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
984 printf (" %s\n", "-M, --mountpoint");
985 printf (" %s\n", _("Display the (block) device instead of the mount point"));
986 printf (" %s\n", "-m, --megabytes");
987 printf (" %s\n", _("Same as '--units MB'"));
988 printf (" %s\n", "-A, --all");
989 printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
990 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
991 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
992 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
993 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
994 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
995 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
996 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
997 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
998 printf (" %s\n", "-n, --ignore-missing");
999 printf (" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
1000 printf (" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
1001 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1002 printf (" %s\n", "-u, --units=STRING");
1003 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
1004 printf (UT_VERBOSE);
1005 printf (" %s\n", "-X, --exclude-type=TYPE_REGEX");
1006 printf (" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
1007 printf (" %s\n", "-N, --include-type=TYPE_REGEX");
1008 printf (" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
1009
1010 printf ("\n");
1011 printf ("%s\n", _("General usage hints:"));
1012 printf (" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
1013 printf (" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
1014 printf (" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
1015
1016
1017
1018 printf ("\n");
1019 printf ("%s\n", _("Examples:"));
1020 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
1021 printf (" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
1022 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
1023 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
1024 printf (" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
1025 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
1026 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
1027
1028 printf (UT_SUPPORT);
1029}
1030 682
683 elem = mp_int_fs_list_get_next(elem);
684 }
1031 685
686 cflags = default_cflags;
687 } break;
688 case 'n':
689 result.config.ignore_missing = true;
690 break;
691 case 'A':
692 optarg = strdup(".*");
693 // Intentional fallthrough
694 case 'R':
695 cflags |= REG_ICASE;
696 // Intentional fallthrough
697 case 'r': {
698 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
699 warn_freeinodes_percent || crit_freeinodes_percent)) {
700 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
701 _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
702 }
1032 703
1033void 704 regex_t regex;
1034print_usage (void) 705 int err = regcomp(&regex, optarg, cflags);
1035{ 706 if (err != 0) {
1036 printf ("%s\n", _("Usage:")); 707 char errbuf[MAX_INPUT_BUFFER];
1037 printf (" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K inode_percentage_limit } {-p path | -x device}\n", progname); 708 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
1038 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n"); 709 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
1039 printf ("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n"); 710 }
711
712 bool found = false;
713 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
714 if (np_regex_match_mount_entry(me, &regex)) {
715 found = true;
716 if (verbose >= 3) {
717 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
718 }
719
720 /* add parameter if not found. overwrite thresholds if path has already been added */
721 parameter_list_elem *se = NULL;
722 if (!(se = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
723 se = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
724 }
725 se->group = group;
726 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
727 warn_freeinodes_percent, crit_freeinodes_percent);
728 }
729 }
730
731 if (!found) {
732 if (result.config.ignore_missing) {
733 result.config.path_ignored = true;
734 path_selected = true;
735 break;
736 }
737
738 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg);
739 }
740
741 path_selected = true;
742 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
743 cflags = default_cflags;
744
745 } break;
746 case 'M': /* display mountpoint */
747 result.config.display_mntp = true;
748 break;
749 case 'C': {
750 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
751 if (!path_selected) {
752 parameter_list_elem *path;
753 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
754 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
755 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
756 }
757 path->best_match = me;
758 path->group = group;
759 set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
760 warn_freeinodes_percent, crit_freeinodes_percent);
761 }
762 }
763
764 warn_freespace_units = NULL;
765 crit_freespace_units = NULL;
766 warn_freespace_percent = NULL;
767 crit_freespace_percent = NULL;
768 warn_freeinodes_percent = NULL;
769 crit_freeinodes_percent = NULL;
770
771 path_selected = false;
772 group = NULL;
773 } break;
774 case 'V': /* version */
775 print_revision(progname, NP_VERSION);
776 exit(STATE_UNKNOWN);
777 case 'h': /* help */
778 print_help();
779 exit(STATE_UNKNOWN);
780 case '?': /* help */
781 usage(_("Unknown argument"));
782 case output_format_index: {
783 parsed_output_format parser = mp_parse_output_format(optarg);
784 if (!parser.parsing_success) {
785 // TODO List all available formats here, maybe add anothoer usage function
786 printf("Invalid output format: %s\n", optarg);
787 exit(STATE_UNKNOWN);
788 }
789
790 result.config.output_format_is_set = true;
791 result.config.output_format = parser.output_format;
792 break;
793 }
794 }
795 }
796
797 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
798 int index = optind;
799
800 if (argc > index && is_intnonneg(argv[index])) {
801 if (verbose > 0) {
802 printf("Got an positional warn threshold: %s\n", argv[index]);
803 }
804 char *range = argv[index++];
805 mp_range_parsed tmp = mp_parse_range_string(range);
806 if (tmp.error != MP_PARSING_SUCCES) {
807 die(STATE_UNKNOWN, "failed to parse warning threshold");
808 }
809
810 mp_range tmp_range = tmp.range;
811 // Invert range to use it for free instead of used
812 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
813
814 warn_freespace_percent = mp_range_to_string(tmp_range);
815
816 if (verbose > 0) {
817 printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent);
818 }
819 }
820
821 if (argc > index && is_intnonneg(argv[index])) {
822 if (verbose > 0) {
823 printf("Got an positional crit threshold: %s\n", argv[index]);
824 }
825 char *range = argv[index++];
826 mp_range_parsed tmp = mp_parse_range_string(range);
827 if (tmp.error != MP_PARSING_SUCCES) {
828 die(STATE_UNKNOWN, "failed to parse warning threshold");
829 }
830
831 mp_range tmp_range = tmp.range;
832 // Invert range to use it for free instead of used
833 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
834
835 crit_freespace_percent = mp_range_to_string(tmp_range);
836
837 if (verbose > 0) {
838 printf("Positional critical threshold transformed to: %s\n", crit_freespace_percent);
839 }
840 }
841
842 if (argc > index) {
843 if (verbose > 0) {
844 printf("Got an positional filesystem: %s\n", argv[index]);
845 }
846 struct parameter_list *se = mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++]));
847 path_selected = true;
848 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
849 warn_freeinodes_percent, crit_freeinodes_percent);
850 }
851
852 // If a list of paths has not been explicitly selected, find entire
853 // mount list and create list of paths
854 if (!path_selected && !result.config.path_ignored) {
855 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
856 if (me->me_dummy != 0) {
857 // just do not add dummy filesystems
858 continue;
859 }
860
861 parameter_list_elem *path = NULL;
862 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
863 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
864 }
865 path->best_match = me;
866 path->group = group;
867 set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
868 warn_freeinodes_percent, crit_freeinodes_percent);
869 }
870 }
871
872 // Set thresholds to the appropriate unit
873 for (parameter_list_elem *tmp = result.config.path_select_list.first; tmp; tmp = mp_int_fs_list_get_next(tmp)) {
874
875 mp_perfdata_value factor = mp_create_pd_value(unit);
876
877 if (tmp->freespace_units.critical_is_set) {
878 tmp->freespace_units.critical = mp_range_multiply(tmp->freespace_units.critical, factor);
879 }
880 if (tmp->freespace_units.warning_is_set) {
881 tmp->freespace_units.warning = mp_range_multiply(tmp->freespace_units.warning, factor);
882 }
883 }
884
885 return result;
1040} 886}
1041 887
1042bool 888void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units, char *warn_freespace_percent,
1043stat_path (struct parameter_list *p) 889 char *crit_freespace_percent, char *warn_freeinodes_percent, char *crit_freeinodes_percent) {
1044{ 890 mp_range_parsed tmp;
1045 /* Stat entry to check that dir exists and is accessible */ 891
1046 if (verbose >= 3) 892 if (warn_freespace_units) {
1047 printf("calling stat on %s\n", p->name); 893 tmp = mp_parse_range_string(warn_freespace_units);
1048 if (stat (p->name, &stat_buf[0])) { 894 path->freespace_units = mp_thresholds_set_warn(path->freespace_units, tmp.range);
1049 if (verbose >= 3) 895 }
1050 printf("stat failed on %s\n", p->name); 896
1051 if (ignore_missing == true) { 897 if (crit_freespace_units) {
1052 return false; 898 tmp = mp_parse_range_string(crit_freespace_units);
1053 } else { 899 path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range);
1054 printf("DISK %s - ", _("CRITICAL")); 900 }
1055 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); 901
1056 } 902 if (warn_freespace_percent) {
1057 } 903 tmp = mp_parse_range_string(warn_freespace_percent);
1058 return true; 904 path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range);
905 }
906
907 if (crit_freespace_percent) {
908 tmp = mp_parse_range_string(crit_freespace_percent);
909 path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range);
910 }
911
912 if (warn_freeinodes_percent) {
913 tmp = mp_parse_range_string(warn_freeinodes_percent);
914 path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range);
915 }
916
917 if (crit_freeinodes_percent) {
918 tmp = mp_parse_range_string(crit_freeinodes_percent);
919 path->freeinodes_percent = mp_thresholds_set_crit(path->freeinodes_percent, tmp.range);
920 }
1059} 921}
1060 922
923void print_help(void) {
924 print_revision(progname, NP_VERSION);
925
926 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
927 printf(COPYRIGHT, copyright, email);
928
929 printf("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
930 printf("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
931
932 printf("\n\n");
933
934 print_usage();
935
936 printf(UT_HELP_VRSN);
937 printf(UT_EXTRA_OPTS);
938
939 printf(" %s\n", "-w, --warning=INTEGER");
940 printf(" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
941 printf(" %s\n", "-w, --warning=PERCENT%");
942 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
943 printf(" %s\n", "-c, --critical=INTEGER");
944 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
945 printf(" %s\n", "-c, --critical=PERCENT%");
946 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
947 printf(" %s\n", "-W, --iwarning=PERCENT%");
948 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
949 printf(" %s\n", "-K, --icritical=PERCENT%");
950 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
951 printf(" %s\n", "-p, --path=PATH, --partition=PARTITION");
952 printf(" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
953 printf(" %s\n", "-x, --exclude_device=PATH <STRING>");
954 printf(" %s\n", _("Ignore device (only works if -p unspecified)"));
955 printf(" %s\n", "-C, --clear");
956 printf(" %s\n", _("Clear thresholds"));
957 printf(" %s\n", "-E, --exact-match");
958 printf(" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
959 printf(" %s\n", "-e, --errors-only");
960 printf(" %s\n", _("Display only devices/mountpoints with errors"));
961 printf(" %s\n", "-f, --freespace-ignore-reserved");
962 printf(" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
963 printf(" %s\n", "-P, --iperfdata");
964 printf(" %s\n", _("Display inode usage in perfdata"));
965 printf(" %s\n", "-g, --group=NAME");
966 printf(" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
967 printf(" %s\n", "-l, --local");
968 printf(" %s\n", _("Only check local filesystems"));
969 printf(" %s\n", "-L, --stat-remote-fs");
970 printf(" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
971 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
972 printf(" %s\n", "-M, --mountpoint");
973 printf(" %s\n", _("Display the (block) device instead of the mount point"));
974 printf(" %s\n", "-A, --all");
975 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
976 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
977 printf(" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
978 printf(" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
979 printf(" %s\n", _("Regular expression for path or partition (may be repeated)"));
980 printf(" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
981 printf(" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
982 printf(" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
983 printf(" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
984 printf(" %s\n", "-n, --ignore-missing");
985 printf(" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
986 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
987 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
988 printf(" %s\n", "-u, --units=STRING");
989 printf(" %s\n", _("Select the unit used for the absolute value thresholds"));
990 printf(
991 " %s\n",
992 _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
993 printf(" %s\n", "-k, --kilobytes");
994 printf(" %s\n", _("Same as '--units kB'"));
995 printf(" %s\n", "--display-unit");
996 printf(" %s\n", _("Select the unit used for in the output"));
997 printf(
998 " %s\n",
999 _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
1000 printf(" %s\n", "-m, --megabytes");
1001 printf(" %s\n", _("Same as '--units MB'"));
1002 printf(UT_VERBOSE);
1003 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX");
1004 printf(" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
1005 printf(" %s\n", "-N, --include-type=TYPE_REGEX");
1006 printf(" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
1007 printf(UT_OUTPUT_FORMAT);
1008
1009 printf("\n");
1010 printf("%s\n", _("General usage hints:"));
1011 printf(" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
1012 printf(" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
1013 printf(" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
1014
1015 printf("\n");
1016 printf("%s\n", _("Examples:"));
1017 printf(" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
1018 printf(" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
1019 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
1020 printf(" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
1021 printf(" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
1022 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
1023 printf(" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
1024
1025 printf(UT_SUPPORT);
1026}
1061 1027
1062void 1028void print_usage(void) {
1063get_stats (struct parameter_list *p, struct fs_usage *fsp) { 1029 printf("%s\n", _("Usage:"));
1064 struct parameter_list *p_list; 1030 printf(" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K "
1065 struct fs_usage tmpfsp; 1031 "inode_percentage_limit } {-p path | -x device}\n",
1066 int first = 1; 1032 progname);
1033 printf("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
1034 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
1035}
1067 1036
1068 if (p->group == NULL) { 1037bool stat_path(parameter_list_elem *parameters, bool ignore_missing) {
1069 get_path_stats(p,fsp); 1038 /* Stat entry to check that dir exists and is accessible */
1070 } else { 1039 if (verbose >= 3) {
1071 /* find all group members */ 1040 printf("calling stat on %s\n", parameters->name);
1072 for (p_list = path_select_list; p_list; p_list=p_list->name_next) { 1041 }
1073#ifdef __CYGWIN__ 1042
1074 if (strncmp(p_list->name, "/cygdrive/", 10) != 0) 1043 struct stat stat_buf = {0};
1075 continue; 1044 if (stat(parameters->name, &stat_buf)) {
1076#endif 1045 if (verbose >= 3) {
1077 if (p_list->group && ! (strcmp(p_list->group, p->group))) { 1046 printf("stat failed on %s\n", parameters->name);
1078 if (! stat_path(p_list)) 1047 }
1079 continue; 1048 if (ignore_missing) {
1080 get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp); 1049 return false;
1081 get_path_stats(p_list, &tmpfsp); 1050 }
1082 if (verbose >= 3) 1051 printf("DISK %s - ", _("CRITICAL"));
1083 printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n", 1052 die(STATE_CRITICAL, _("%s %s: %s\n"), parameters->name, _("is not accessible"), strerror(errno));
1084 p_list->group, 1053 }
1085 tmpfsp.fsu_blocks, 1054
1086 tmpfsp.fsu_blocksize, 1055 return true;
1087 p_list->best_match->me_mountdir, 1056}
1088 p_list->dused_units,
1089 p_list->dfree_units,
1090 p_list->dtotal_units,
1091 mult);
1092
1093 /* prevent counting the first FS of a group twice since its parameter_list entry
1094 * is used to carry the information of all file systems of the entire group */
1095 if (! first) {
1096 p->total += p_list->total;
1097 p->available += p_list->available;
1098 p->available_to_root += p_list->available_to_root;
1099 p->used += p_list->used;
1100
1101 p->dused_units += p_list->dused_units;
1102 p->dfree_units += p_list->dfree_units;
1103 p->dtotal_units += p_list->dtotal_units;
1104 p->inodes_total += p_list->inodes_total;
1105 p->inodes_free += p_list->inodes_free;
1106 p->inodes_free_to_root += p_list->inodes_free_to_root;
1107 p->inodes_used += p_list->inodes_used;
1108 }
1109 first = 0;
1110 }
1111 if (verbose >= 3)
1112 printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n",
1113 p->group,
1114 p->dused_units,
1115 p->dfree_units,
1116 p->dtotal_units,
1117 tmpfsp.fsu_blocksize,
1118 mult);
1119 }
1120 /* modify devname and mountdir for output */
1121 p->best_match->me_mountdir = p->best_match->me_devname = p->group;
1122 }
1123 /* finally calculate percentages for either plain FS or summed up group */
1124 p->dused_pct = calculate_percent( p->used, p->used + p->available ); /* used + available can never be > uintmax */
1125 p->dfree_pct = 100.0 - p->dused_pct;
1126 p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
1127 p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
1128 1057
1058static parameter_list_elem get_path_stats(parameter_list_elem parameters, const struct fs_usage fsp, bool freespace_ignore_reserved) {
1059 uintmax_t available = fsp.fsu_bavail;
1060 uintmax_t available_to_root = fsp.fsu_bfree;
1061 uintmax_t used = fsp.fsu_blocks - fsp.fsu_bfree;
1062 uintmax_t total;
1063
1064 if (freespace_ignore_reserved) {
1065 /* option activated : we subtract the root-reserved space from the total */
1066 total = fsp.fsu_blocks - available_to_root + available;
1067 } else {
1068 /* default behaviour : take all the blocks into account */
1069 total = fsp.fsu_blocks;
1070 }
1071
1072 parameters.used_bytes = used * fsp.fsu_blocksize;
1073 parameters.free_bytes = available * fsp.fsu_blocksize;
1074 parameters.total_bytes = total * fsp.fsu_blocksize;
1075
1076 /* Free file nodes. Not sure the workaround is required, but in case...*/
1077 parameters.inodes_free = fsp.fsu_ffree;
1078 parameters.inodes_free_to_root = fsp.fsu_ffree; /* Free file nodes for root. */
1079 parameters.inodes_used = fsp.fsu_files - fsp.fsu_ffree;
1080
1081 if (freespace_ignore_reserved) {
1082 /* option activated : we subtract the root-reserved inodes from the total */
1083 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1084 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1085 parameters.inodes_total = fsp.fsu_files - parameters.inodes_free_to_root + parameters.inodes_free;
1086 } else {
1087 /* default behaviour : take all the inodes into account */
1088 parameters.inodes_total = fsp.fsu_files;
1089 }
1090
1091 return parameters;
1129} 1092}
1130 1093
1131void 1094mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit) {
1132get_path_stats (struct parameter_list *p, struct fs_usage *fsp) { 1095 mp_subcheck result = mp_subcheck_init();
1133 p->available = fsp->fsu_bavail; 1096 result = mp_set_subcheck_default_state(result, STATE_UNKNOWN);
1134 p->available_to_root = fsp->fsu_bfree; 1097 xasprintf(&result.output, "%s", measurement_unit.name);
1135 p->used = fsp->fsu_blocks - fsp->fsu_bfree; 1098
1136 if (freespace_ignore_reserved) { 1099 if (!measurement_unit.is_group && measurement_unit.filesystem_type) {
1137 /* option activated : we subtract the root-reserved space from the total */ 1100 xasprintf(&result.output, "%s (%s)", result.output, measurement_unit.filesystem_type);
1138 p->total = fsp->fsu_blocks - p->available_to_root + p->available; 1101 }
1139 } else { 1102
1140 /* default behaviour : take all the blocks into account */ 1103 /* Threshold comparisons */
1141 p->total = fsp->fsu_blocks; 1104
1142 } 1105 // ===============================
1143 1106 // Free space absolute values test
1144 p->dused_units = p->used*fsp->fsu_blocksize/mult; 1107 mp_subcheck freespace_bytes_sc = mp_subcheck_init();
1145 p->dfree_units = p->available*fsp->fsu_blocksize/mult; 1108 freespace_bytes_sc = mp_set_subcheck_default_state(freespace_bytes_sc, STATE_OK);
1146 p->dtotal_units = p->total*fsp->fsu_blocksize/mult; 1109
1147 /* Free file nodes. Not sure the workaround is required, but in case...*/ 1110 if (unit != Humanized) {
1148 p->inodes_free = fsp->fsu_ffree; 1111 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %ju%s (of %ju%s)", (uintmax_t)(measurement_unit.free_bytes / unit),
1149 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */ 1112 get_unit_string(unit), (uintmax_t)(measurement_unit.total_bytes / unit), get_unit_string(unit));
1150 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree; 1113 } else {
1151 if (freespace_ignore_reserved) { 1114 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %s (of %s)", humanize_byte_value(measurement_unit.free_bytes, false),
1152 /* option activated : we subtract the root-reserved inodes from the total */ 1115 humanize_byte_value((unsigned long long)measurement_unit.total_bytes, false));
1153 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */ 1116 }
1154 /* for others, fsp->fsu_ffree == fsp->fsu_favail */ 1117
1155 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free; 1118 mp_perfdata used_space = perfdata_init();
1156 } else { 1119 used_space.label = measurement_unit.name;
1157 /* default behaviour : take all the inodes into account */ 1120 used_space.value = mp_create_pd_value(measurement_unit.free_bytes);
1158 p->inodes_total = fsp->fsu_files; 1121 used_space = mp_set_pd_max_value(used_space, mp_create_pd_value(measurement_unit.total_bytes));
1159 } 1122 used_space = mp_set_pd_min_value(used_space, mp_create_pd_value(0));
1160 np_add_name(&seen, p->best_match->me_mountdir); 1123 used_space.uom = "B";
1124 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1125 freespace_bytes_sc = mp_set_subcheck_state(freespace_bytes_sc, mp_get_pd_status(used_space));
1126
1127 // special case for absolute space thresholds here:
1128 // if absolute values are not set, compute the thresholds from percentage thresholds
1129 mp_thresholds temp_thlds = measurement_unit.freespace_bytes_thresholds;
1130 if (!temp_thlds.critical_is_set && measurement_unit.freespace_percent_thresholds.critical_is_set) {
1131 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.critical;
1132
1133 if (!tmp_range.end_infinity) {
1134 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
1135 }
1136
1137 if (!tmp_range.start_infinity) {
1138 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
1139 }
1140 measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_crit(measurement_unit.freespace_bytes_thresholds, tmp_range);
1141 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1142 }
1143
1144 if (!temp_thlds.warning_is_set && measurement_unit.freespace_percent_thresholds.warning_is_set) {
1145 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.warning;
1146 if (!tmp_range.end_infinity) {
1147 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
1148 }
1149 if (!tmp_range.start_infinity) {
1150 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
1151 }
1152 measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_warn(measurement_unit.freespace_bytes_thresholds, tmp_range);
1153 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1154 }
1155
1156 mp_add_perfdata_to_subcheck(&freespace_bytes_sc, used_space);
1157 mp_add_subcheck_to_subcheck(&result, freespace_bytes_sc);
1158
1159 // ==========================
1160 // Free space percentage test
1161 mp_subcheck freespace_percent_sc = mp_subcheck_init();
1162 freespace_percent_sc = mp_set_subcheck_default_state(freespace_percent_sc, STATE_OK);
1163
1164 double free_percentage = calculate_percent(measurement_unit.free_bytes, measurement_unit.total_bytes);
1165 xasprintf(&freespace_percent_sc.output, "Free space percentage: %g%%", free_percentage);
1166
1167 // Using perfdata here just to get to the test result
1168 mp_perfdata free_space_percent_pd = perfdata_init();
1169 free_space_percent_pd.value = mp_create_pd_value(free_percentage);
1170 free_space_percent_pd = mp_pd_set_thresholds(free_space_percent_pd, measurement_unit.freespace_percent_thresholds);
1171
1172 freespace_percent_sc = mp_set_subcheck_state(freespace_percent_sc, mp_get_pd_status(free_space_percent_pd));
1173 mp_add_subcheck_to_subcheck(&result, freespace_percent_sc);
1174
1175 // ================
1176 // Free inodes test
1177 // Only ever useful if the number of inodes is static (e.g. ext4),
1178 // not when it is dynamic (e.g btrfs)
1179 // Assumption: if the total number of inodes == 0, we have such a case and just skip the test
1180 if (measurement_unit.inodes_total > 0) {
1181 mp_subcheck freeindodes_percent_sc = mp_subcheck_init();
1182 freeindodes_percent_sc = mp_set_subcheck_default_state(freeindodes_percent_sc, STATE_OK);
1183
1184 double free_inode_percentage = calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total);
1185
1186 if (verbose > 0) {
1187 printf("free inode percentage computed: %g\n", free_inode_percentage);
1188 }
1189
1190 xasprintf(&freeindodes_percent_sc.output, "Inodes free: %g%% (%ju of %ju)", free_inode_percentage, measurement_unit.inodes_free,
1191 measurement_unit.inodes_total);
1192
1193 mp_perfdata inodes_pd = perfdata_init();
1194 xasprintf(&inodes_pd.label, "%s (inodes)", measurement_unit.name);
1195 inodes_pd = mp_set_pd_value(inodes_pd, measurement_unit.inodes_used);
1196 inodes_pd = mp_set_pd_max_value(inodes_pd, mp_create_pd_value(measurement_unit.inodes_total));
1197 inodes_pd = mp_set_pd_min_value(inodes_pd, mp_create_pd_value(0));
1198
1199 mp_thresholds absolut_inode_thresholds = measurement_unit.freeinodes_percent_thresholds;
1200
1201 if (absolut_inode_thresholds.critical_is_set) {
1202 absolut_inode_thresholds.critical =
1203 mp_range_multiply(absolut_inode_thresholds.critical, mp_create_pd_value(measurement_unit.inodes_total / 100));
1204 }
1205 if (absolut_inode_thresholds.warning_is_set) {
1206 absolut_inode_thresholds.warning =
1207 mp_range_multiply(absolut_inode_thresholds.warning, mp_create_pd_value(measurement_unit.inodes_total / 100));
1208 }
1209
1210 inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds);
1211
1212 freeindodes_percent_sc = mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inodes_pd));
1213 if (display_inodes_perfdata) {
1214 mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd);
1215 }
1216 mp_add_subcheck_to_subcheck(&result, freeindodes_percent_sc);
1217 }
1218
1219 return result;
1161} 1220}
diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c
new file mode 100644
index 00000000..eec1282b
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.c
@@ -0,0 +1,517 @@
1/*****************************************************************************
2 *
3 * Library for check_disk
4 *
5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains utilities for check_disk. These are tested by libtap
11 *
12 *
13 * This program is free software: you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 *
26 *
27 *****************************************************************************/
28
29#include "../common.h"
30#include "utils_disk.h"
31#include "../../gl/fsusage.h"
32#include "../../lib/thresholds.h"
33#include "../../lib/states.h"
34#include <stdint.h>
35#include <stdio.h>
36#include <string.h>
37#include <assert.h>
38
39void np_add_name(struct name_list **list, const char *name) {
40 struct name_list *new_entry;
41 new_entry = (struct name_list *)malloc(sizeof *new_entry);
42 new_entry->name = (char *)name;
43 new_entry->next = *list;
44 *list = new_entry;
45}
46
47/* @brief Initialises a new regex at the begin of list via regcomp(3)
48 *
49 * @details if the regex fails to compile the error code of regcomp(3) is returned
50 * and list is not modified, otherwise list is modified to point to the new
51 * element
52 * @param list Pointer to a linked list of regex_list elements
53 * @param regex the string containing the regex which should be inserted into the list
54 * @param clags the cflags parameter for regcomp(3)
55 */
56int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
57 struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
58
59 if (new_entry == NULL) {
60 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
61 }
62
63 int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
64
65 if (!regcomp_result) {
66 // regcomp succeeded
67 new_entry->next = *list;
68 *list = new_entry;
69
70 return 0;
71 }
72 // regcomp failed
73 free(new_entry);
74
75 return regcomp_result;
76}
77
78parameter_list_elem parameter_list_init(const char *name) {
79 parameter_list_elem result = {
80 .name = strdup(name),
81 .best_match = NULL,
82
83 .freespace_units = mp_thresholds_init(),
84 .freespace_percent = mp_thresholds_init(),
85 .freeinodes_percent = mp_thresholds_init(),
86
87 .group = NULL,
88
89 .inodes_total = 0,
90 .inodes_free = 0,
91 .inodes_free_to_root = 0,
92 .inodes_used = 0,
93
94 .used_bytes = 0,
95 .free_bytes = 0,
96 .total_bytes = 0,
97
98 .next = NULL,
99 .prev = NULL,
100 };
101 return result;
102}
103
104/* Returns true if name is in list */
105bool np_find_name(struct name_list *list, const char *name) {
106 if (list == NULL || name == NULL) {
107 return false;
108 }
109 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
110 if (!strcmp(name, iterator->name)) {
111 return true;
112 }
113 }
114 return false;
115}
116
117/* Returns true if name is in list */
118bool np_find_regmatch(struct regex_list *list, const char *name) {
119 if (name == NULL) {
120 return false;
121 }
122
123 size_t len = strlen(name);
124
125 for (; list; list = list->next) {
126 /* Emulate a full match as if surrounded with ^( )$
127 by checking whether the match spans the whole name */
128 regmatch_t dummy_match;
129 if (!regexec(&list->regex, name, 1, &dummy_match, 0) && dummy_match.rm_so == 0 && dummy_match.rm_eo == len) {
130 return true;
131 }
132 }
133
134 return false;
135}
136
137bool np_seen_name(struct name_list *list, const char *name) {
138 for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
139 if (!strcmp(iterator->name, name)) {
140 return true;
141 }
142 }
143 return false;
144}
145
146bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
147 return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) || (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0));
148}
149
150check_disk_config check_disk_config_init() {
151 check_disk_config tmp = {
152 .erronly = false,
153 .display_mntp = false,
154 .show_local_fs = false,
155 .stat_remote_fs = false,
156 .display_inodes_perfdata = false,
157
158 .exact_match = false,
159 .freespace_ignore_reserved = false,
160
161 .ignore_missing = false,
162 .path_ignored = false,
163
164 // FS Filters
165 .fs_exclude_list = NULL,
166 .fs_include_list = NULL,
167 .device_path_exclude_list = NULL,
168
169 // Actual filesystems paths to investigate
170 .path_select_list = filesystem_list_init(),
171
172 .mount_list = NULL,
173 .seen = NULL,
174
175 .display_unit = Humanized,
176 // .unit = MebiBytes,
177
178 .output_format_is_set = false,
179 };
180 return tmp;
181}
182
183char *get_unit_string(byte_unit_enum unit) {
184 switch (unit) {
185 case Bytes:
186 return "Bytes";
187 case KibiBytes:
188 return "KiB";
189 case MebiBytes:
190 return "MiB";
191 case GibiBytes:
192 return "GiB";
193 case TebiBytes:
194 return "TiB";
195 case PebiBytes:
196 return "PiB";
197 case ExbiBytes:
198 return "EiB";
199 case KiloBytes:
200 return "KB";
201 case MegaBytes:
202 return "MB";
203 case GigaBytes:
204 return "GB";
205 case TeraBytes:
206 return "TB";
207 case PetaBytes:
208 return "PB";
209 case ExaBytes:
210 return "EB";
211 default:
212 assert(false);
213 }
214}
215
216measurement_unit measurement_unit_init() {
217 measurement_unit tmp = {
218 .name = NULL,
219 .filesystem_type = NULL,
220 .is_group = false,
221
222 .freeinodes_percent_thresholds = mp_thresholds_init(),
223 .freespace_percent_thresholds = mp_thresholds_init(),
224 .freespace_bytes_thresholds = mp_thresholds_init(),
225
226 .free_bytes = 0,
227 .used_bytes = 0,
228 .total_bytes = 0,
229
230 .inodes_total = 0,
231 .inodes_free = 0,
232 .inodes_free_to_root = 0,
233 .inodes_used = 0,
234 };
235 return tmp;
236}
237
238// Add a given element to the list, memory for the new element is freshly allocated
239// Returns a pointer to new element
240measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem) {
241 // find last element
242 measurement_unit_list *new = NULL;
243 if (list == NULL) {
244 new = calloc(1, sizeof(measurement_unit_list));
245 if (new == NULL) {
246 die(STATE_UNKNOWN, _("allocation failed"));
247 }
248 } else {
249 measurement_unit_list *list_elem = list;
250 while (list_elem->next != NULL) {
251 list_elem = list_elem->next;
252 }
253
254 new = calloc(1, sizeof(measurement_unit_list));
255 if (new == NULL) {
256 die(STATE_UNKNOWN, _("allocation failed"));
257 }
258
259 list_elem->next = new;
260 }
261
262 new->unit = elem;
263 new->next = NULL;
264 return new;
265}
266
267measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem) {
268
269 unit.free_bytes += filesystem.free_bytes;
270 unit.used_bytes += filesystem.used_bytes;
271 unit.total_bytes += filesystem.total_bytes;
272
273 unit.inodes_total += filesystem.inodes_total;
274 unit.inodes_free += filesystem.inodes_free;
275 unit.inodes_free_to_root += filesystem.inodes_free_to_root;
276 unit.inodes_used += filesystem.inodes_used;
277 return unit;
278}
279
280measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp) {
281 measurement_unit result = measurement_unit_init();
282 if (!display_mntp) {
283 result.name = strdup(filesystem.best_match->me_mountdir);
284 } else {
285 result.name = strdup(filesystem.best_match->me_devname);
286 }
287
288 if (filesystem.group) {
289 result.is_group = true;
290 } else {
291 result.is_group = false;
292 if (filesystem.best_match) {
293 result.filesystem_type = filesystem.best_match->me_type;
294 }
295 }
296
297 result.freeinodes_percent_thresholds = filesystem.freeinodes_percent;
298 result.freespace_percent_thresholds = filesystem.freespace_percent;
299 result.freespace_bytes_thresholds = filesystem.freespace_units;
300 result.free_bytes = filesystem.free_bytes;
301 result.total_bytes = filesystem.total_bytes;
302 result.used_bytes = filesystem.used_bytes;
303 result.inodes_total = filesystem.inodes_total;
304 result.inodes_used = filesystem.inodes_used;
305 result.inodes_free = filesystem.inodes_free;
306 result.inodes_free_to_root = filesystem.inodes_free_to_root;
307 return result;
308}
309
310#define RANDOM_STRING_LENGTH 64
311
312char *humanize_byte_value(unsigned long long value, bool use_si_units) {
313 // Idea: A reasonable output should have at most 3 orders of magnitude
314 // before the decimal separator
315 // 353GiB is ok, 2444 GiB should be 2.386 TiB
316 char *result = calloc(RANDOM_STRING_LENGTH, sizeof(char));
317 if (result == NULL) {
318 die(STATE_UNKNOWN, _("allocation failed"));
319 }
320 const byte_unit KibiBytes_factor = 1024;
321 const byte_unit MebiBytes_factor = 1048576;
322 const byte_unit GibiBytes_factor = 1073741824;
323 const byte_unit TebiBytes_factor = 1099511627776;
324 const byte_unit PebiBytes_factor = 1125899906842624;
325 const byte_unit ExbiBytes_factor = 1152921504606846976;
326 const byte_unit KiloBytes_factor = 1000;
327 const byte_unit MegaBytes_factor = 1000000;
328 const byte_unit GigaBytes_factor = 1000000000;
329 const byte_unit TeraBytes_factor = 1000000000000;
330 const byte_unit PetaBytes_factor = 1000000000000000;
331 const byte_unit ExaBytes_factor = 1000000000000000000;
332
333 if (use_si_units) {
334 // SI units, powers of 10
335 if (value < KiloBytes_factor) {
336 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
337 } else if (value < MegaBytes_factor) {
338 snprintf(result, RANDOM_STRING_LENGTH, "%llu KB", value / KiloBytes_factor);
339 } else if (value < GigaBytes_factor) {
340 snprintf(result, RANDOM_STRING_LENGTH, "%llu MB", value / MegaBytes_factor);
341 } else if (value < TeraBytes_factor) {
342 snprintf(result, RANDOM_STRING_LENGTH, "%llu GB", value / GigaBytes_factor);
343 } else if (value < PetaBytes_factor) {
344 snprintf(result, RANDOM_STRING_LENGTH, "%llu TB", value / TeraBytes_factor);
345 } else if (value < ExaBytes_factor) {
346 snprintf(result, RANDOM_STRING_LENGTH, "%llu PB", value / PetaBytes_factor);
347 } else {
348 snprintf(result, RANDOM_STRING_LENGTH, "%llu EB", value / ExaBytes_factor);
349 }
350 } else {
351 // IEC units, powers of 2 ^ 10
352 if (value < KibiBytes_factor) {
353 snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
354 } else if (value < MebiBytes_factor) {
355 snprintf(result, RANDOM_STRING_LENGTH, "%llu KiB", value / KibiBytes_factor);
356 } else if (value < GibiBytes_factor) {
357 snprintf(result, RANDOM_STRING_LENGTH, "%llu MiB", value / MebiBytes_factor);
358 } else if (value < TebiBytes_factor) {
359 snprintf(result, RANDOM_STRING_LENGTH, "%llu GiB", value / GibiBytes_factor);
360 } else if (value < PebiBytes_factor) {
361 snprintf(result, RANDOM_STRING_LENGTH, "%llu TiB", value / TebiBytes_factor);
362 } else if (value < ExbiBytes_factor) {
363 snprintf(result, RANDOM_STRING_LENGTH, "%llu PiB", value / PebiBytes_factor);
364 } else {
365 snprintf(result, RANDOM_STRING_LENGTH, "%llu EiB", value / ExbiBytes_factor);
366 }
367 }
368
369 return result;
370}
371
372filesystem_list filesystem_list_init() {
373 filesystem_list tmp = {
374 .length = 0,
375 .first = NULL,
376 };
377 return tmp;
378}
379
380parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name) {
381 parameter_list_elem *current = list->first;
382 parameter_list_elem *new_path = (struct parameter_list *)malloc(sizeof *new_path);
383 *new_path = parameter_list_init(name);
384
385 if (current == NULL) {
386 list->first = new_path;
387 new_path->prev = NULL;
388 list->length = 1;
389 } else {
390 while (current->next) {
391 current = current->next;
392 }
393 current->next = new_path;
394 new_path->prev = current;
395 list->length++;
396 }
397 return new_path;
398}
399
400parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name) {
401 if (list.length == 0) {
402 return NULL;
403 }
404
405 for (parameter_list_elem *temp_list = list.first; temp_list; temp_list = temp_list->next) {
406 if (!strcmp(temp_list->name, name)) {
407 return temp_list;
408 }
409 }
410
411 return NULL;
412}
413
414parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item) {
415 if (list->length == 0) {
416 return NULL;
417 }
418
419 if (item == NULL) {
420 // Got NULL for item, interpret this as "delete first element"
421 // as a kind of compatibility to the old function
422 item = list->first;
423 }
424
425 if (list->first == item) {
426 list->length--;
427
428 list->first = item->next;
429 if (list->first) {
430 list->first->prev = NULL;
431 }
432 return list->first;
433 }
434
435 // Was not the first element, continue
436 parameter_list_elem *prev = list->first;
437 parameter_list_elem *current = list->first->next;
438
439 while (current != item && current != NULL) {
440 prev = current;
441 current = current->next;
442 }
443
444 if (current == NULL) {
445 // didn't find that element ....
446 return NULL;
447 }
448
449 // remove the element
450 parameter_list_elem *next = current->next;
451 prev->next = next;
452 list->length--;
453 if (next) {
454 next->prev = prev;
455 }
456
457 if (item->name) {
458 free(item->name);
459 }
460 free(item);
461
462 return next;
463}
464
465parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current) {
466 if (!current) {
467 return NULL;
468 }
469 return current->next;
470}
471
472void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact) {
473 for (parameter_list_elem *elem = list.first; elem; elem = mp_int_fs_list_get_next(elem)) {
474 if (!elem->best_match) {
475 size_t name_len = strlen(elem->name);
476 struct mount_entry *best_match = NULL;
477
478 /* set best match if path name exactly matches a mounted device name */
479 for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
480 if (strcmp(mount_entry->me_devname, elem->name) == 0) {
481 struct fs_usage fsp;
482 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
483 best_match = mount_entry;
484 }
485 }
486 }
487
488 /* set best match by directory name if no match was found by devname */
489 if (!best_match) {
490 size_t best_match_len = 0;
491 for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
492 size_t len = strlen(mount_entry->me_mountdir);
493
494 if ((!exact && (best_match_len <= len && len <= name_len &&
495 (len == 1 || strncmp(mount_entry->me_mountdir, elem->name, len) == 0))) ||
496 (exact && strcmp(mount_entry->me_mountdir, elem->name) == 0)) {
497 struct fs_usage fsp;
498
499 if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
500 best_match = mount_entry;
501 best_match_len = len;
502 }
503 }
504 }
505 }
506
507 if (best_match) {
508 elem->best_match = best_match;
509 } else {
510 elem->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
511 }
512
513 // No filesystem without a mount_entry!
514 // assert(elem->best_match != NULL);
515 }
516 }
517}
diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h
new file mode 100644
index 00000000..6831d1fd
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.h
@@ -0,0 +1,157 @@
1#pragma once
2/* Header file for utils_disk */
3
4#include "../../config.h"
5#include "../../gl/mountlist.h"
6#include "../../lib/utils_base.h"
7#include "../../lib/output.h"
8#include "regex.h"
9#include <stdint.h>
10
11typedef unsigned long long byte_unit;
12
13typedef enum {
14 Humanized,
15 Bytes,
16 KibiBytes,
17 MebiBytes,
18 GibiBytes,
19 TebiBytes,
20 PebiBytes,
21 ExbiBytes,
22 KiloBytes,
23 MegaBytes,
24 GigaBytes,
25 TeraBytes,
26 PetaBytes,
27 ExaBytes,
28} byte_unit_enum;
29
30typedef struct name_list string_list;
31struct name_list {
32 char *name;
33 string_list *next;
34};
35
36struct regex_list {
37 regex_t regex;
38 struct regex_list *next;
39};
40
41typedef struct parameter_list parameter_list_elem;
42struct parameter_list {
43 char *name;
44 char *group;
45
46 mp_thresholds freespace_units;
47 mp_thresholds freespace_percent;
48 mp_thresholds freeinodes_percent;
49
50 struct mount_entry *best_match;
51
52 uintmax_t inodes_free_to_root;
53 uintmax_t inodes_free;
54 uintmax_t inodes_used;
55 uintmax_t inodes_total;
56
57 uint64_t used_bytes;
58 uint64_t free_bytes;
59 uint64_t total_bytes;
60
61 parameter_list_elem *next;
62 parameter_list_elem *prev;
63};
64
65typedef struct {
66 size_t length;
67 parameter_list_elem *first;
68} filesystem_list;
69
70filesystem_list filesystem_list_init();
71
72typedef struct {
73 char *name;
74 char *filesystem_type;
75 bool is_group;
76
77 mp_thresholds freespace_bytes_thresholds;
78 mp_thresholds freespace_percent_thresholds;
79 mp_thresholds freeinodes_percent_thresholds;
80
81 uintmax_t inodes_free_to_root;
82 uintmax_t inodes_free;
83 uintmax_t inodes_used;
84 uintmax_t inodes_total;
85
86 uintmax_t used_bytes;
87 uintmax_t free_bytes;
88 uintmax_t total_bytes;
89} measurement_unit;
90
91typedef struct measurement_unit_list measurement_unit_list;
92struct measurement_unit_list {
93 measurement_unit unit;
94 measurement_unit_list *next;
95};
96
97typedef struct {
98 // Output options
99 bool erronly;
100 bool display_mntp;
101 /* show only local filesystems. */
102 bool show_local_fs;
103 /* show only local filesystems but call stat() on remote ones. */
104 bool stat_remote_fs;
105 bool display_inodes_perfdata;
106
107 bool exact_match;
108 bool freespace_ignore_reserved;
109
110 bool ignore_missing;
111 bool path_ignored;
112
113 /* Linked list of filesystem types to omit.
114 If the list is empty, don't exclude any types. */
115 struct regex_list *fs_exclude_list;
116 /* Linked list of filesystem types to check.
117 If the list is empty, include all types. */
118 struct regex_list *fs_include_list;
119 struct name_list *device_path_exclude_list;
120 filesystem_list path_select_list;
121 /* Linked list of mounted filesystems. */
122 struct mount_entry *mount_list;
123 struct name_list *seen;
124
125 byte_unit_enum display_unit;
126 // byte_unit unit;
127
128 bool output_format_is_set;
129 mp_output_format output_format;
130} check_disk_config;
131
132void np_add_name(struct name_list **list, const char *name);
133bool np_find_name(struct name_list *list, const char *name);
134bool np_seen_name(struct name_list *list, const char *name);
135int np_add_regex(struct regex_list **list, const char *regex, int cflags);
136bool np_find_regmatch(struct regex_list *list, const char *name);
137
138parameter_list_elem parameter_list_init(const char *);
139
140parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name);
141parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name);
142parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item);
143parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current);
144void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact);
145
146measurement_unit measurement_unit_init();
147measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem);
148measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem);
149measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp);
150
151int search_parameter_list(parameter_list_elem *list, const char *name);
152bool np_regex_match_mount_entry(struct mount_entry *, regex_t *);
153
154char *get_unit_string(byte_unit_enum);
155check_disk_config check_disk_config_init();
156
157char *humanize_byte_value(unsigned long long value, bool use_si_units);
diff --git a/plugins/check_dns.c b/plugins/check_dns.c
index 468bc958..95f33083 100644
--- a/plugins/check_dns.c
+++ b/plugins/check_dns.c
@@ -1,36 +1,36 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dns plugin 3 * Monitoring check_dns plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_dns plugin 10 * This file contains the check_dns plugin
11* 11 *
12* LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which 12 * LIMITATION: nslookup on Solaris 7 can return output over 2 lines, which
13* will not be picked up by this plugin 13 * will not be picked up by this plugin
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_dns"; 32const char *progname = "check_dns";
33const char *copyright = "2000-2008"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
@@ -39,579 +39,591 @@ const char *email = "devel@monitoring-plugins.org";
39#include "netutils.h" 39#include "netutils.h"
40#include "runcmd.h" 40#include "runcmd.h"
41 41
42int process_arguments (int, char **); 42#include "states.h"
43int validate_arguments (void); 43#include "check_dns.d/config.h"
44int error_scan (char *, bool *); 44
45bool ip_match_cidr(const char *, const char *); 45typedef struct {
46unsigned long ip2long(const char *); 46 int errorcode;
47void print_help (void); 47 check_dns_config config;
48void print_usage (void); 48} check_dns_config_wrapper;
49 49static check_dns_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50#define ADDRESS_LENGTH 256 50static check_dns_config_wrapper validate_arguments(check_dns_config_wrapper /*config_wrapper*/);
51char query_address[ADDRESS_LENGTH] = ""; 51static mp_state_enum error_scan(char * /*input_buffer*/, bool * /*is_nxdomain*/, const char /*dns_server*/[ADDRESS_LENGTH]);
52char dns_server[ADDRESS_LENGTH] = ""; 52static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/);
53char ptr_server[ADDRESS_LENGTH] = ""; 53static unsigned long ip2long(const char * /*src*/);
54bool verbose = false; 54static void print_help(void);
55char **expected_address = NULL; 55void print_usage(void);
56int expected_address_cnt = 0; 56
57bool expect_nxdomain = false; 57static bool verbose = false;
58 58
59bool expect_authority = false; 59static int qstrcmp(const void *p1, const void *p2) {
60bool all_match = false;
61thresholds *time_thresholds = NULL;
62
63static int
64qstrcmp(const void *p1, const void *p2)
65{
66 /* The actual arguments to this function are "pointers to 60 /* The actual arguments to this function are "pointers to
67 pointers to char", but strcmp() arguments are "pointers 61 pointers to char", but strcmp() arguments are "pointers
68 to char", hence the following cast plus dereference */ 62 to char", hence the following cast plus dereference */
69 return strcmp(* (char * const *) p1, * (char * const *) p2); 63 return strcmp(*(char *const *)p1, *(char *const *)p2);
70} 64}
71 65
66int main(int argc, char **argv) {
67 setlocale(LC_ALL, "");
68 bindtextdomain(PACKAGE, LOCALEDIR);
69 textdomain(PACKAGE);
70
71 /* Set signal handling and alarm */
72 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
73 usage_va(_("Cannot catch SIGALRM"));
74 }
75
76 /* Parse extra opts if any */
77 argv = np_extra_opts(&argc, argv, progname);
78
79 check_dns_config_wrapper tmp = process_arguments(argc, argv);
80
81 if (tmp.errorcode == ERROR) {
82 usage_va(_("Could not parse arguments"));
83 }
84
85 const check_dns_config config = tmp.config;
86
87 char *command_line = NULL;
88 /* get the command to run */
89 xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, config.query_address, config.dns_server);
90
91 struct timeval tv;
92 alarm(timeout_interval);
93 gettimeofday(&tv, NULL);
94
95 if (verbose) {
96 printf("%s\n", command_line);
97 }
98
99 output chld_out;
100 output chld_err;
101 char *msg = NULL;
102 mp_state_enum result = STATE_UNKNOWN;
103 /* run the command */
104 if ((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
105 msg = (char *)_("nslookup returned an error status");
106 result = STATE_WARNING;
107 }
108
109 /* =====
110 * scan stdout, main results get retrieved here
111 * =====
112 */
113 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
114 char **addresses = NULL; // All addresses parsed from stdout
115 size_t n_addresses = 0; // counter for retrieved addresses
116 bool non_authoritative = false;
117 bool is_nxdomain = false;
118 bool parse_address = false; /* This flag scans for Address: but only after Name: */
119 for (size_t i = 0; i < chld_out.lines; i++) {
120 if (addresses == NULL) {
121 addresses = malloc(sizeof(*addresses) * 10);
122 } else if (!(n_addresses % 10)) {
123 addresses = realloc(addresses, sizeof(*addresses) * (n_addresses + 10));
124 }
125
126 if (verbose) {
127 puts(chld_out.line[i]);
128 }
129
130 if (strcasestr(chld_out.line[i], ".in-addr.arpa") || strcasestr(chld_out.line[i], ".ip6.arpa")) {
131 if ((strstr(chld_out.line[i], "canonical name = ") != NULL)) {
132 continue;
133 }
134 char *temp_buffer = NULL;
135 if ((temp_buffer = strstr(chld_out.line[i], "name = "))) {
136 addresses[n_addresses++] = strdup(temp_buffer + 7);
137 } else {
138 msg = (char *)_("Warning plugin error");
139 result = STATE_WARNING;
140 }
141 }
142
143 /* bug ID: 2946553 - Older versions of bind will use all available dns
144 servers, we have to match the one specified */
145 if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) {
146 char *temp_buffer = strchr(chld_out.line[i], ':');
147 if (temp_buffer == NULL) {
148 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Server line\n"), NSLOOKUP_COMMAND);
149 }
150
151 temp_buffer++;
152
153 /* Strip leading tabs */
154 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) {
155 /* NOOP */;
156 }
157
158 strip(temp_buffer);
159 if (strlen(temp_buffer) == 0) {
160 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"), NSLOOKUP_COMMAND);
161 }
162
163 if (strcmp(temp_buffer, config.dns_server) != 0) {
164 die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), config.dns_server);
165 }
166 }
167
168 /* the server is responding, we just got the host name... */
169 if (strstr(chld_out.line[i], "Name:")) {
170 parse_address = true;
171 } else if (parse_address && (strstr(chld_out.line[i], "Address:") || strstr(chld_out.line[i], "Addresses:"))) {
172 char *temp_buffer = strchr(chld_out.line[i], ':');
173 if (temp_buffer == NULL) {
174 die(STATE_UNKNOWN, _("'%s' returned a weirdly formatted Address line\n"), NSLOOKUP_COMMAND);
175 }
176
177 temp_buffer++;
178
179 /* Strip leading spaces */
180 while (*temp_buffer == ' ') {
181 temp_buffer++;
182 }
183
184 strip(temp_buffer);
185 if (strlen(temp_buffer) == 0) {
186 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"), NSLOOKUP_COMMAND);
187 }
188
189 addresses[n_addresses++] = strdup(temp_buffer);
190 } else if (strstr(chld_out.line[i], _("Non-authoritative answer:"))) {
191 non_authoritative = true;
192 }
193
194 result = error_scan(chld_out.line[i], &is_nxdomain, config.dns_server);
195 if (result != STATE_OK) {
196 msg = strchr(chld_out.line[i], ':');
197 if (msg) {
198 msg++;
199 }
200 break;
201 }
202 }
203
204 char input_buffer[MAX_INPUT_BUFFER];
205 /* scan stderr */
206 for (size_t i = 0; i < chld_err.lines; i++) {
207 if (verbose) {
208 puts(chld_err.line[i]);
209 }
210
211 if (error_scan(chld_err.line[i], &is_nxdomain, config.dns_server) != STATE_OK) {
212 result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain, config.dns_server));
213 msg = strchr(input_buffer, ':');
214 if (msg) {
215 msg++;
216 } else {
217 msg = input_buffer;
218 }
219 }
220 }
221
222 if (is_nxdomain && !config.expect_nxdomain) {
223 die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), config.query_address);
224 }
225
226 if (addresses) {
227 size_t slen = 1;
228 char *adrp = NULL;
229 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
230 for (size_t i = 0; i < n_addresses; i++) {
231 slen += strlen(addresses[i]) + 1;
232 }
233
234 // Temporary pointer adrp gets moved, address stays on the beginning
235 adrp = address = malloc(slen);
236 for (size_t i = 0; i < n_addresses; i++) {
237 if (i) {
238 *adrp++ = ',';
239 }
240 strcpy(adrp, addresses[i]);
241 adrp += strlen(addresses[i]);
242 }
243 *adrp = 0;
244 } else {
245 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), NSLOOKUP_COMMAND);
246 }
247
248 /* compare to expected address */
249 if (result == STATE_OK && config.expected_address_cnt > 0) {
250 result = STATE_CRITICAL;
251 char *temp_buffer = "";
252 unsigned long expect_match = (1 << config.expected_address_cnt) - 1;
253 unsigned long addr_match = (1 << n_addresses) - 1;
254
255 for (size_t i = 0; i < config.expected_address_cnt; i++) {
256 /* check if we get a match on 'raw' ip or cidr */
257 for (size_t j = 0; j < n_addresses; j++) {
258 if (strcmp(addresses[j], config.expected_address[i]) == 0 || ip_match_cidr(addresses[j], config.expected_address[i])) {
259 result = STATE_OK;
260 addr_match &= ~(1 << j);
261 expect_match &= ~(1 << i);
262 }
263 }
264
265 /* prepare an error string */
266 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, config.expected_address[i]);
267 }
268 /* check if expected_address must cover all in addresses and none may be missing */
269 if (config.all_match && (expect_match != 0 || addr_match != 0)) {
270 result = STATE_CRITICAL;
271 }
272 if (result == STATE_CRITICAL) {
273 /* Strip off last semicolon... */
274 temp_buffer[strlen(temp_buffer) - 2] = '\0';
275 xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address);
276 }
277 }
278
279 if (config.expect_nxdomain) {
280 if (!is_nxdomain) {
281 result = STATE_CRITICAL;
282 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address, address);
283 } else {
284 if (address != NULL) {
285 free(address);
286 }
287 address = "NXDOMAIN";
288 }
289 }
290
291 /* check if authoritative */
292 if (result == STATE_OK && config.expect_authority && non_authoritative) {
293 result = STATE_CRITICAL;
294 xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server, config.query_address);
295 }
296
297 long microsec = deltime(tv);
298 double elapsed_time = (double)microsec / 1.0e6;
299
300 if (result == STATE_OK) {
301 result = get_status(elapsed_time, config.time_thresholds);
302 if (result == STATE_OK) {
303 printf("DNS %s: ", _("OK"));
304 } else if (result == STATE_WARNING) {
305 printf("DNS %s: ", _("WARNING"));
306 } else if (result == STATE_CRITICAL) {
307 printf("DNS %s: ", _("CRITICAL"));
308 }
309 printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
310 printf(_(". %s returns %s"), config.query_address, address);
311 if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical != NULL)) {
312 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, true,
313 config.time_thresholds->critical->end, true, 0, false, 0));
314 } else if ((config.time_thresholds->warning == NULL) && (config.time_thresholds->critical != NULL)) {
315 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, config.time_thresholds->critical->end, true, 0, false, 0));
316 } else if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical == NULL)) {
317 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, false, 0, true, 0, false, 0));
318 } else {
319 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
320 }
321 } else if (result == STATE_WARNING) {
322 printf(_("DNS WARNING - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
323 } else if (result == STATE_CRITICAL) {
324 printf(_("DNS CRITICAL - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
325 } else {
326 printf(_("DNS UNKNOWN - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
327 }
72 328
73int 329 exit(result);
74main (int argc, char **argv)
75{
76 char *command_line = NULL;
77 char input_buffer[MAX_INPUT_BUFFER];
78 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
79 char **addresses = NULL;
80 int n_addresses = 0;
81 char *msg = NULL;
82 char *temp_buffer = NULL;
83 bool non_authoritative = false;
84 int result = STATE_UNKNOWN;
85 double elapsed_time;
86 long microsec;
87 struct timeval tv;
88 bool parse_address = false; /* This flag scans for Address: but only after Name: */
89 output chld_out, chld_err;
90 bool is_nxdomain = false;
91
92 setlocale (LC_ALL, "");
93 bindtextdomain (PACKAGE, LOCALEDIR);
94 textdomain (PACKAGE);
95
96 /* Set signal handling and alarm */
97 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
98 usage_va(_("Cannot catch SIGALRM"));
99 }
100
101 /* Parse extra opts if any */
102 argv=np_extra_opts (&argc, argv, progname);
103
104 if (process_arguments (argc, argv) == ERROR) {
105 usage_va(_("Could not parse arguments"));
106 }
107
108 /* get the command to run */
109 xasprintf (&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server);
110
111 alarm (timeout_interval);
112 gettimeofday (&tv, NULL);
113
114 if (verbose)
115 printf ("%s\n", command_line);
116
117 /* run the command */
118 if((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
119 msg = (char *)_("nslookup returned an error status");
120 result = STATE_WARNING;
121 }
122
123 /* scan stdout */
124 for(size_t i = 0; i < chld_out.lines; i++) {
125 if (addresses == NULL)
126 addresses = malloc(sizeof(*addresses)*10);
127 else if (!(n_addresses % 10))
128 addresses = realloc(addresses,sizeof(*addresses) * (n_addresses + 10));
129
130 if (verbose)
131 puts(chld_out.line[i]);
132
133 if (strcasestr (chld_out.line[i], ".in-addr.arpa") || strcasestr (chld_out.line[i], ".ip6.arpa")) {
134 if ((temp_buffer = strstr (chld_out.line[i], "name = ")))
135 addresses[n_addresses++] = strdup (temp_buffer + 7);
136 else {
137 msg = (char *)_("Warning plugin error");
138 result = STATE_WARNING;
139 }
140 }
141
142 /* bug ID: 2946553 - Older versions of bind will use all available dns
143 servers, we have to match the one specified */
144 if (strstr (chld_out.line[i], "Server:") && strlen(dns_server) > 0) {
145 temp_buffer = strchr (chld_out.line[i], ':');
146 temp_buffer++;
147
148 /* Strip leading tabs */
149 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++)
150 /* NOOP */;
151
152 strip(temp_buffer);
153 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
154 die (STATE_CRITICAL,
155 _("DNS CRITICAL - '%s' returned empty server string\n"),
156 NSLOOKUP_COMMAND);
157 }
158
159 if (strcmp(temp_buffer, dns_server) != 0) {
160 die (STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), dns_server);
161 }
162 }
163
164 /* the server is responding, we just got the host name... */
165 if (strstr (chld_out.line[i], "Name:"))
166 parse_address = true;
167 else if (parse_address && (strstr (chld_out.line[i], "Address:") ||
168 strstr (chld_out.line[i], "Addresses:"))) {
169 temp_buffer = index (chld_out.line[i], ':');
170 temp_buffer++;
171
172 /* Strip leading spaces */
173 while (*temp_buffer == ' ')
174 temp_buffer++;
175
176 strip(temp_buffer);
177 if (temp_buffer==NULL || strlen(temp_buffer)==0) {
178 die (STATE_CRITICAL,
179 _("DNS CRITICAL - '%s' returned empty host name string\n"),
180 NSLOOKUP_COMMAND);
181 }
182
183 addresses[n_addresses++] = strdup(temp_buffer);
184 }
185 else if (strstr (chld_out.line[i], _("Non-authoritative answer:"))) {
186 non_authoritative = true;
187 }
188
189
190 result = error_scan (chld_out.line[i], &is_nxdomain);
191 if (result != STATE_OK) {
192 msg = strchr (chld_out.line[i], ':');
193 if(msg) msg++;
194 break;
195 }
196 }
197
198 /* scan stderr */
199 for(size_t i = 0; i < chld_err.lines; i++) {
200 if (verbose)
201 puts(chld_err.line[i]);
202
203 if (error_scan (chld_err.line[i], &is_nxdomain) != STATE_OK) {
204 result = max_state (result, error_scan (chld_err.line[i], &is_nxdomain));
205 msg = strchr(input_buffer, ':');
206 if(msg)
207 msg++;
208 else
209 msg = input_buffer;
210 }
211 }
212
213 if (is_nxdomain && !expect_nxdomain) {
214 die (STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address);
215 }
216
217 if (addresses) {
218 int i,slen;
219 char *adrp;
220 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
221 for(i=0, slen=1; i < n_addresses; i++) {
222 slen += strlen(addresses[i])+1;
223 }
224 adrp = address = malloc(slen);
225 for(i=0; i < n_addresses; i++) {
226 if (i) *adrp++ = ',';
227 strcpy(adrp, addresses[i]);
228 adrp += strlen(addresses[i]);
229 }
230 *adrp = 0;
231 } else
232 die (STATE_CRITICAL,
233 _("DNS CRITICAL - '%s' msg parsing exited with no address\n"),
234 NSLOOKUP_COMMAND);
235
236 /* compare to expected address */
237 if (result == STATE_OK && expected_address_cnt > 0) {
238 result = STATE_CRITICAL;
239 temp_buffer = "";
240 unsigned long expect_match = (1 << expected_address_cnt) - 1;
241 unsigned long addr_match = (1 << n_addresses) - 1;
242
243 for (int i=0; i<expected_address_cnt; i++) {
244 int j;
245 /* check if we get a match on 'raw' ip or cidr */
246 for (j=0; j<n_addresses; j++) {
247 if ( strcmp(addresses[j], expected_address[i]) == 0
248 || ip_match_cidr(addresses[j], expected_address[i]) ) {
249 result = STATE_OK;
250 addr_match &= ~(1 << j);
251 expect_match &= ~(1 << i);
252 }
253 }
254
255 /* prepare an error string */
256 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]);
257 }
258 /* check if expected_address must cover all in addresses and none may be missing */
259 if (all_match && (expect_match != 0 || addr_match != 0))
260 result = STATE_CRITICAL;
261 if (result == STATE_CRITICAL) {
262 /* Strip off last semicolon... */
263 temp_buffer[strlen(temp_buffer)-2] = '\0';
264 xasprintf(&msg, _("expected '%s' but got '%s'"), temp_buffer, address);
265 }
266 }
267
268 if (expect_nxdomain) {
269 if (!is_nxdomain) {
270 result = STATE_CRITICAL;
271 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address);
272 } else {
273 if (address != NULL) free(address);
274 address = "NXDOMAIN";
275 }
276 }
277
278 /* check if authoritative */
279 if (result == STATE_OK && expect_authority && non_authoritative) {
280 result = STATE_CRITICAL;
281 xasprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address);
282 }
283
284 microsec = deltime (tv);
285 elapsed_time = (double)microsec / 1.0e6;
286
287 if (result == STATE_OK) {
288 result = get_status(elapsed_time, time_thresholds);
289 if (result == STATE_OK) {
290 printf ("DNS %s: ", _("OK"));
291 } else if (result == STATE_WARNING) {
292 printf ("DNS %s: ", _("WARNING"));
293 } else if (result == STATE_CRITICAL) {
294 printf ("DNS %s: ", _("CRITICAL"));
295 }
296 printf (ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
297 printf (_(". %s returns %s"), query_address, address);
298 if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) {
299 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
300 true, time_thresholds->warning->end,
301 true, time_thresholds->critical->end,
302 true, 0, false, 0));
303 } else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) {
304 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
305 false, 0,
306 true, time_thresholds->critical->end,
307 true, 0, false, 0));
308 } else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) {
309 printf ("|%s\n", fperfdata ("time", elapsed_time, "s",
310 true, time_thresholds->warning->end,
311 false, 0,
312 true, 0, false, 0));
313 } else
314 printf ("|%s\n", fperfdata ("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
315 }
316 else if (result == STATE_WARNING)
317 printf (_("DNS WARNING - %s\n"),
318 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
319 else if (result == STATE_CRITICAL)
320 printf (_("DNS CRITICAL - %s\n"),
321 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
322 else
323 printf (_("DNS UNKNOWN - %s\n"),
324 !strcmp (msg, "") ? _(" Probably a non-existent host/domain") : msg);
325
326 return result;
327} 330}
328 331
329bool ip_match_cidr(const char *addr, const char *cidr_ro) { 332bool ip_match_cidr(const char *addr, const char *cidr_ro) {
330 char *subnet, *mask_c, *cidr = strdup(cidr_ro); 333 char *subnet;
331 int mask; 334 char *mask_c;
332 subnet = strtok(cidr, "/"); 335 char *cidr = strdup(cidr_ro);
333 mask_c = strtok(NULL, "\0"); 336 int mask;
334 if (!subnet || !mask_c) { 337 subnet = strtok(cidr, "/");
335 return false; 338 mask_c = strtok(NULL, "\0");
339 if (!subnet || !mask_c) {
340 return false;
336 } 341 }
337 mask = atoi(mask_c); 342 mask = atoi(mask_c);
338 343
339 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */ 344 /* https://www.cryptobells.com/verifying-ips-in-a-subnet-in-php/ */
340 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask); 345 return (ip2long(addr) & ~((1 << (32 - mask)) - 1)) == (ip2long(subnet) >> (32 - mask)) << (32 - mask);
341} 346}
342 347
343unsigned long 348unsigned long ip2long(const char *src) {
344ip2long(const char* src) { 349 unsigned long ip[4];
345 unsigned long ip[4]; 350 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */
346 /* http://computer-programming-forum.com/47-c-language/1376ffb92a12c471.htm */ 351 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", &ip[0], &ip[1], &ip[2], &ip[3]) == 4 && ip[0] < 256 && ip[1] < 256 && ip[2] < 256 &&
347 return (sscanf(src, "%3lu.%3lu.%3lu.%3lu", 352 ip[3] < 256)
348 &ip[0], &ip[1], &ip[2], &ip[3]) == 4 && 353 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
349 ip[0] < 256 && ip[1] < 256 && 354 : 0;
350 ip[2] < 256 && ip[3] < 256)
351 ? ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]
352 : 0;
353} 355}
354 356
355int 357mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain, const char dns_server[ADDRESS_LENGTH]) {
356error_scan (char *input_buffer, bool *is_nxdomain)
357{
358
359 const int nxdomain = strstr (input_buffer, "Non-existent") ||
360 strstr (input_buffer, "** server can't find") ||
361 strstr (input_buffer, "** Can't find") ||
362 strstr (input_buffer, "NXDOMAIN");
363 if (nxdomain) *is_nxdomain = true;
364
365 /* the DNS lookup timed out */
366 if (strstr (input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
367 strstr (input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
368 strstr (input_buffer, _("the `-sil[ent]' option to prevent this message from appearing.")))
369 return STATE_OK;
370
371 /* DNS server is not running... */
372 else if (strstr (input_buffer, "No response from server"))
373 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
374 else if (strstr (input_buffer, "no servers could be reached"))
375 die (STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
376
377 /* Host name is valid, but server doesn't have records... */
378 else if (strstr (input_buffer, "No records"))
379 die (STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
380
381 /* Connection was refused */
382 else if (strstr (input_buffer, "Connection refused") ||
383 strstr (input_buffer, "Couldn't find server") ||
384 strstr (input_buffer, "Refused") ||
385 (strstr (input_buffer, "** server can't find") &&
386 strstr (input_buffer, ": REFUSED")))
387 die (STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
388
389 /* Query refused (usually by an ACL in the namserver) */
390 else if (strstr (input_buffer, "Query refused"))
391 die (STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
392
393 /* No information (e.g. nameserver IP has two PTR records) */
394 else if (strstr (input_buffer, "No information"))
395 die (STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
396
397 /* Network is unreachable */
398 else if (strstr (input_buffer, "Network is unreachable"))
399 die (STATE_CRITICAL, _("Network is unreachable\n"));
400
401 /* Internal server failure */
402 else if (strstr (input_buffer, "Server failure"))
403 die (STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
404
405 /* Request error or the DNS lookup timed out */
406 else if (strstr (input_buffer, "Format error") ||
407 strstr (input_buffer, "Timed out"))
408 return STATE_WARNING;
409
410 return STATE_OK;
411 358
412} 359 const int nxdomain = strstr(input_buffer, "Non-existent") || strstr(input_buffer, "** server can't find") ||
360 strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN");
361 if (nxdomain) {
362 *is_nxdomain = true;
363 }
413 364
365 /* the DNS lookup timed out */
366 if (strstr(input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
367 strstr(input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
368 strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing."))) {
369 return STATE_OK;
370 }
414 371
415/* process command-line arguments */ 372 /* DNS server is not running... */
416int 373 else if (strstr(input_buffer, "No response from server")) {
417process_arguments (int argc, char **argv) 374 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
418{ 375 } else if (strstr(input_buffer, "no servers could be reached")) {
419 int c; 376 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
420 char *warning = NULL; 377 }
421 char *critical = NULL; 378
422 379 /* Host name is valid, but server doesn't have records... */
423 int opt_index = 0; 380 else if (strstr(input_buffer, "No records")) {
424 static struct option long_opts[] = { 381 die(STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
425 {"help", no_argument, 0, 'h'}, 382 }
426 {"version", no_argument, 0, 'V'}, 383
427 {"verbose", no_argument, 0, 'v'}, 384 /* Connection was refused */
428 {"timeout", required_argument, 0, 't'}, 385 else if (strstr(input_buffer, "Connection refused") || strstr(input_buffer, "Couldn't find server") ||
429 {"hostname", required_argument, 0, 'H'}, 386 strstr(input_buffer, "Refused") || (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) {
430 {"server", required_argument, 0, 's'}, 387 die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
431 {"reverse-server", required_argument, 0, 'r'}, 388 }
432 {"expected-address", required_argument, 0, 'a'}, 389
433 {"expect-nxdomain", no_argument, 0, 'n'}, 390 /* Query refused (usually by an ACL in the namserver) */
434 {"expect-authority", no_argument, 0, 'A'}, 391 else if (strstr(input_buffer, "Query refused")) {
435 {"all", no_argument, 0, 'L'}, 392 die(STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
436 {"warning", required_argument, 0, 'w'}, 393 }
437 {"critical", required_argument, 0, 'c'}, 394
438 {0, 0, 0, 0} 395 /* No information (e.g. nameserver IP has two PTR records) */
439 }; 396 else if (strstr(input_buffer, "No information")) {
440 397 die(STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
441 if (argc < 2) 398 }
442 return ERROR; 399
443 400 /* Network is unreachable */
444 for (c = 1; c < argc; c++) 401 else if (strstr(input_buffer, "Network is unreachable")) {
445 if (strcmp ("-to", argv[c]) == 0) 402 die(STATE_CRITICAL, _("Network is unreachable\n"));
446 strcpy (argv[c], "-t"); 403 }
447 404
448 while (1) { 405 /* Internal server failure */
449 c = getopt_long (argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index); 406 else if (strstr(input_buffer, "Server failure")) {
450 407 die(STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
451 if (c == -1 || c == EOF)
452 break;
453
454 switch (c) {
455 case 'h': /* help */
456 print_help ();
457 exit (STATE_UNKNOWN);
458 case 'V': /* version */
459 print_revision (progname, NP_VERSION);
460 exit (STATE_UNKNOWN);
461 case 'v': /* version */
462 verbose = true;
463 break;
464 case 't': /* timeout period */
465 timeout_interval = atoi (optarg);
466 break;
467 case 'H': /* hostname */
468 if (strlen (optarg) >= ADDRESS_LENGTH)
469 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
470 strcpy (query_address, optarg);
471 break;
472 case 's': /* server name */
473 /* TODO: this host_or_die check is probably unnecessary.
474 * Better to confirm nslookup response matches */
475 host_or_die(optarg);
476 if (strlen (optarg) >= ADDRESS_LENGTH)
477 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
478 strcpy (dns_server, optarg);
479 break;
480 case 'r': /* reverse server name */
481 /* TODO: Is this host_or_die necessary? */
482 host_or_die(optarg);
483 if (strlen (optarg) >= ADDRESS_LENGTH)
484 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
485 strcpy (ptr_server, optarg);
486 break;
487 case 'a': /* expected address */
488 if (strlen (optarg) >= ADDRESS_LENGTH)
489 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
490 if (strchr(optarg, ',') != NULL) {
491 char *comma = strchr(optarg, ',');
492 while (comma != NULL) {
493 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**));
494 expected_address[expected_address_cnt] = strndup(optarg, comma - optarg);
495 expected_address_cnt++;
496 optarg = comma + 1;
497 comma = strchr(optarg, ',');
498 } 408 }
499 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); 409
500 expected_address[expected_address_cnt] = strdup(optarg); 410 /* Request error or the DNS lookup timed out */
501 expected_address_cnt++; 411 else if (strstr(input_buffer, "Format error") || strstr(input_buffer, "Timed out")) {
502 } else { 412 return STATE_WARNING;
503 expected_address = (char **)realloc(expected_address, (expected_address_cnt+1) * sizeof(char**)); 413 }
504 expected_address[expected_address_cnt] = strdup(optarg); 414
505 expected_address_cnt++; 415 return STATE_OK;
506 }
507 break;
508 case 'n': /* expect NXDOMAIN */
509 expect_nxdomain = true;
510 break;
511 case 'A': /* expect authority */
512 expect_authority = true;
513 break;
514 case 'L': /* all must match */
515 all_match = true;
516 break;
517 case 'w':
518 warning = optarg;
519 break;
520 case 'c':
521 critical = optarg;
522 break;
523 default: /* args not parsable */
524 usage5();
525 }
526 }
527
528 c = optind;
529 if (strlen(query_address)==0 && c<argc) {
530 if (strlen(argv[c])>=ADDRESS_LENGTH)
531 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
532 strcpy (query_address, argv[c++]);
533 }
534
535 if (strlen(dns_server)==0 && c<argc) {
536 /* TODO: See -s option */
537 host_or_die(argv[c]);
538 if (strlen(argv[c]) >= ADDRESS_LENGTH)
539 die (STATE_UNKNOWN, _("Input buffer overflow\n"));
540 strcpy (dns_server, argv[c++]);
541 }
542
543 set_thresholds(&time_thresholds, warning, critical);
544
545 return validate_arguments ();
546} 416}
547 417
418/* process command-line arguments */
419check_dns_config_wrapper process_arguments(int argc, char **argv) {
420 static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
421 {"version", no_argument, 0, 'V'},
422 {"verbose", no_argument, 0, 'v'},
423 {"timeout", required_argument, 0, 't'},
424 {"hostname", required_argument, 0, 'H'},
425 {"server", required_argument, 0, 's'},
426 {"reverse-server", required_argument, 0, 'r'},
427 {"expected-address", required_argument, 0, 'a'},
428 {"expect-nxdomain", no_argument, 0, 'n'},
429 {"expect-authority", no_argument, 0, 'A'},
430 {"all", no_argument, 0, 'L'},
431 {"warning", required_argument, 0, 'w'},
432 {"critical", required_argument, 0, 'c'},
433 {0, 0, 0, 0}};
434
435 check_dns_config_wrapper result = {
436 .config = check_dns_config_init(),
437 .errorcode = OK,
438 };
439
440 if (argc < 2) {
441 result.errorcode = ERROR;
442 return result;
443 }
444
445 for (int index = 1; index < argc; index++) {
446 if (strcmp("-to", argv[index]) == 0) {
447 strcpy(argv[index], "-t");
448 }
449 }
450
451 char *warning = NULL;
452 char *critical = NULL;
453 int opt_index = 0;
454 int index = 0;
455 while (true) {
456 index = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_index);
457
458 if (index == -1 || index == EOF) {
459 break;
460 }
461
462 switch (index) {
463 case 'h': /* help */
464 print_help();
465 exit(STATE_UNKNOWN);
466 case 'V': /* version */
467 print_revision(progname, NP_VERSION);
468 exit(STATE_UNKNOWN);
469 case 'v': /* version */
470 verbose = true;
471 break;
472 case 't': /* timeout period */
473 timeout_interval = atoi(optarg);
474 break;
475 case 'H': /* hostname */
476 if (strlen(optarg) >= ADDRESS_LENGTH) {
477 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
478 }
479 strcpy(result.config.query_address, optarg);
480 break;
481 case 's': /* server name */
482 /* TODO: this host_or_die check is probably unnecessary.
483 * Better to confirm nslookup response matches */
484 host_or_die(optarg);
485 if (strlen(optarg) >= ADDRESS_LENGTH) {
486 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
487 }
488 strcpy(result.config.dns_server, optarg);
489 break;
490 case 'r': /* reverse server name */
491 /* TODO: Is this host_or_die necessary? */
492 // TODO This does not do anything!!! 2025-03-08 rincewind
493 host_or_die(optarg);
494 if (strlen(optarg) >= ADDRESS_LENGTH) {
495 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
496 }
497 static char ptr_server[ADDRESS_LENGTH] = "";
498 strcpy(ptr_server, optarg);
499 break;
500 case 'a': /* expected address */
501 if (strlen(optarg) >= ADDRESS_LENGTH) {
502 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
503 }
504 if (strchr(optarg, ',') != NULL) {
505 char *comma = strchr(optarg, ',');
506 while (comma != NULL) {
507 result.config.expected_address =
508 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
509 result.config.expected_address[result.config.expected_address_cnt] = strndup(optarg, comma - optarg);
510 result.config.expected_address_cnt++;
511 optarg = comma + 1;
512 comma = strchr(optarg, ',');
513 }
514 result.config.expected_address =
515 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
516 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
517 result.config.expected_address_cnt++;
518 } else {
519 result.config.expected_address =
520 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
521 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
522 result.config.expected_address_cnt++;
523 }
524 break;
525 case 'n': /* expect NXDOMAIN */
526 result.config.expect_nxdomain = true;
527 break;
528 case 'A': /* expect authority */
529 result.config.expect_authority = true;
530 break;
531 case 'L': /* all must match */
532 result.config.all_match = true;
533 break;
534 case 'w':
535 warning = optarg;
536 break;
537 case 'c':
538 critical = optarg;
539 break;
540 default: /* args not parsable */
541 usage5();
542 }
543 }
544
545 index = optind;
546 if (strlen(result.config.query_address) == 0 && index < argc) {
547 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
548 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
549 }
550 strcpy(result.config.query_address, argv[index++]);
551 }
548 552
549int 553 if (strlen(result.config.dns_server) == 0 && index < argc) {
550validate_arguments () 554 /* TODO: See -s option */
551{ 555 host_or_die(argv[index]);
552 if (query_address[0] == 0) { 556 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
553 printf ("missing --host argument\n"); 557 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
554 return ERROR; 558 }
555 } 559 strcpy(result.config.dns_server, argv[index++]);
560 }
556 561
557 if (expected_address_cnt > 0 && expect_nxdomain) { 562 set_thresholds(&result.config.time_thresholds, warning, critical);
558 printf ("--expected-address and --expect-nxdomain cannot be combined\n");
559 return ERROR;
560 }
561 563
562 return OK; 564 return validate_arguments(result);
563} 565}
564 566
567check_dns_config_wrapper validate_arguments(check_dns_config_wrapper config_wrapper) {
568 if (config_wrapper.config.query_address[0] == 0) {
569 printf("missing --host argument\n");
570 config_wrapper.errorcode = ERROR;
571 return config_wrapper;
572 }
573
574 if (config_wrapper.config.expected_address_cnt > 0 && config_wrapper.config.expect_nxdomain) {
575 printf("--expected-address and --expect-nxdomain cannot be combined\n");
576 config_wrapper.errorcode = ERROR;
577 return config_wrapper;
578 }
565 579
566void 580 return config_wrapper;
567print_help (void)
568{
569 print_revision (progname, NP_VERSION);
570
571 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
572 printf (COPYRIGHT, copyright, email);
573
574 printf ("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query."));
575 printf ("%s\n", _("An optional DNS server to use may be specified."));
576 printf ("%s\n", _("If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used."));
577
578 printf ("\n\n");
579
580 print_usage ();
581
582 printf (UT_HELP_VRSN);
583 printf (UT_EXTRA_OPTS);
584
585 printf (" -H, --hostname=HOST\n");
586 printf (" %s\n", _("The name or address you want to query"));
587 printf (" -s, --server=HOST\n");
588 printf (" %s\n", _("Optional DNS server you want to use for the lookup"));
589 printf (" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
590 printf (" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
591 printf (" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
592 printf (" %s\n", _("value matches)."));
593 printf (" -n, --expect-nxdomain\n");
594 printf (" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
595 printf (" %s\n", _("Cannot be used together with -a"));
596 printf (" -A, --expect-authority\n");
597 printf (" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
598 printf (" -w, --warning=seconds\n");
599 printf (" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
600 printf (" -c, --critical=seconds\n");
601 printf (" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
602 printf (" -L, --all\n");
603 printf (" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
604 printf (" %s\n", _("returned. Default off"));
605
606 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
607
608 printf (UT_SUPPORT);
609} 581}
610 582
583void print_help(void) {
584 print_revision(progname, NP_VERSION);
585
586 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
587 printf(COPYRIGHT, copyright, email);
588
589 printf("%s\n", _("This plugin uses the nslookup program to obtain the IP address for the given host/domain query."));
590 printf("%s\n", _("An optional DNS server to use may be specified."));
591 printf("%s\n", _("If no DNS server is specified, the default server(s) specified in /etc/resolv.conf will be used."));
592
593 printf("\n\n");
594
595 print_usage();
596
597 printf(UT_HELP_VRSN);
598 printf(UT_EXTRA_OPTS);
599
600 printf(" -H, --hostname=HOST\n");
601 printf(" %s\n", _("The name or address you want to query"));
602 printf(" -s, --server=HOST\n");
603 printf(" %s\n", _("Optional DNS server you want to use for the lookup"));
604 printf(" -a, --expected-address=IP-ADDRESS|CIDR|HOST\n");
605 printf(" %s\n", _("Optional IP-ADDRESS/CIDR you expect the DNS server to return. HOST must end"));
606 printf(" %s\n", _("with a dot (.). This option can be repeated multiple times (Returns OK if any"));
607 printf(" %s\n", _("value matches)."));
608 printf(" -n, --expect-nxdomain\n");
609 printf(" %s\n", _("Expect the DNS server to return NXDOMAIN (i.e. the domain was not found)"));
610 printf(" %s\n", _("Cannot be used together with -a"));
611 printf(" -A, --expect-authority\n");
612 printf(" %s\n", _("Optionally expect the DNS server to be authoritative for the lookup"));
613 printf(" -w, --warning=seconds\n");
614 printf(" %s\n", _("Return warning if elapsed time exceeds value. Default off"));
615 printf(" -c, --critical=seconds\n");
616 printf(" %s\n", _("Return critical if elapsed time exceeds value. Default off"));
617 printf(" -L, --all\n");
618 printf(" %s\n", _("Return critical if the list of expected addresses does not match all addresses"));
619 printf(" %s\n", _("returned. Default off"));
620
621 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
622
623 printf(UT_SUPPORT);
624}
611 625
612void 626void print_usage(void) {
613print_usage (void) 627 printf("%s\n", _("Usage:"));
614{ 628 printf("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
615 printf ("%s\n", _("Usage:"));
616 printf ("%s -H host [-s server] [-a expected-address] [-n] [-A] [-t timeout] [-w warn] [-c crit] [-L]\n", progname);
617} 629}
diff --git a/plugins/check_dns.d/config.h b/plugins/check_dns.d/config.h
new file mode 100644
index 00000000..9ec4eb82
--- /dev/null
+++ b/plugins/check_dns.d/config.h
@@ -0,0 +1,34 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7#define ADDRESS_LENGTH 256
8
9typedef struct {
10 bool all_match;
11 char dns_server[ADDRESS_LENGTH];
12 char query_address[ADDRESS_LENGTH];
13 bool expect_nxdomain;
14 bool expect_authority;
15 char **expected_address;
16 size_t expected_address_cnt;
17
18 thresholds *time_thresholds;
19} check_dns_config;
20
21check_dns_config check_dns_config_init() {
22 check_dns_config tmp = {
23 .all_match = false,
24 .dns_server = "",
25 .query_address = "",
26 .expect_nxdomain = false,
27 .expect_authority = false,
28 .expected_address = NULL,
29 .expected_address_cnt = 0,
30
31 .time_thresholds = NULL,
32 };
33 return tmp;
34}
diff --git a/plugins/check_dummy.c b/plugins/check_dummy.c
index 212a1344..19f6c046 100644
--- a/plugins/check_dummy.c
+++ b/plugins/check_dummy.c
@@ -1,124 +1,111 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dummy plugin 3 * Monitoring check_dummy plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_dummy plugin 10 * This file contains the check_dummy plugin
11* 11 *
12* This plugin will simply return the state corresponding to the numeric value 12 * This plugin will simply return the state corresponding to the numeric value
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_dummy"; 31const char *progname = "check_dummy";
32const char *copyright = "1999-2007"; 32const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "common.h"
36#include "utils.h" 36#include "utils.h"
37 37
38void print_help (void); 38static void print_help(void);
39void print_usage (void); 39void print_usage(void);
40 40
41 41int main(int argc, char **argv) {
42int 42 int result = STATE_UNKNOWN;
43main (int argc, char **argv) 43
44{ 44 setlocale(LC_ALL, "");
45 int result = STATE_UNKNOWN; 45 bindtextdomain(PACKAGE, LOCALEDIR);
46 46 textdomain(PACKAGE);
47 setlocale (LC_ALL, ""); 47
48 bindtextdomain (PACKAGE, LOCALEDIR); 48 if (argc < 2)
49 textdomain (PACKAGE); 49 usage4(_("Could not parse arguments"));
50 50 else if (strcmp(argv[1], "-V") == 0 || strcmp(argv[1], "--version") == 0) {
51 if (argc < 2) 51 print_revision(progname, NP_VERSION);
52 usage4 (_("Could not parse arguments")); 52 exit(STATE_UNKNOWN);
53 else if (strcmp (argv[1], "-V") == 0 || strcmp (argv[1], "--version") == 0) { 53 } else if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
54 print_revision (progname, NP_VERSION); 54 print_help();
55 exit (STATE_UNKNOWN); 55 exit(STATE_UNKNOWN);
56 } 56 } else if (!is_integer(argv[1]))
57 else if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) { 57 usage4(_("Arguments to check_dummy must be an integer"));
58 print_help (); 58 else
59 exit (STATE_UNKNOWN); 59 result = atoi(argv[1]);
60 } 60
61 else if (!is_integer (argv[1])) 61 switch (result) {
62 usage4 (_("Arguments to check_dummy must be an integer")); 62 case STATE_OK:
63 else 63 printf(_("OK"));
64 result = atoi (argv[1]); 64 break;
65 65 case STATE_WARNING:
66 switch (result) { 66 printf(_("WARNING"));
67 case STATE_OK: 67 break;
68 printf (_("OK")); 68 case STATE_CRITICAL:
69 break; 69 printf(_("CRITICAL"));
70 case STATE_WARNING: 70 break;
71 printf (_("WARNING")); 71 case STATE_UNKNOWN:
72 break; 72 printf(_("UNKNOWN"));
73 case STATE_CRITICAL: 73 break;
74 printf (_("CRITICAL")); 74 default:
75 break; 75 printf(_("UNKNOWN"));
76 case STATE_UNKNOWN: 76 printf(": ");
77 printf (_("UNKNOWN")); 77 printf(_("Status %d is not a supported error state\n"), result);
78 break; 78 return STATE_UNKNOWN;
79 default: 79 }
80 printf (_("UNKNOWN")); 80
81 printf (": "); 81 if (argc >= 3)
82 printf (_("Status %d is not a supported error state\n"), result); 82 printf(": %s", argv[2]);
83 return STATE_UNKNOWN; 83
84 } 84 printf("\n");
85 85
86 if (argc >= 3) 86 return result;
87 printf (": %s", argv[2]);
88
89 printf("\n");
90
91 return result;
92} 87}
93 88
89void print_help(void) {
90 print_revision(progname, NP_VERSION);
94 91
92 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
93 printf(COPYRIGHT, copyright, email);
95 94
96void 95 printf("%s\n", _("This plugin will simply return the state corresponding to the numeric value"));
97print_help (void)
98{
99 print_revision (progname, NP_VERSION);
100 96
101 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 97 printf("%s\n", _("of the <state> argument with optional text"));
102 printf (COPYRIGHT, copyright, email);
103 98
104 printf ("%s\n", _("This plugin will simply return the state corresponding to the numeric value")); 99 printf("\n\n");
105 100
106 printf ("%s\n", _("of the <state> argument with optional text")); 101 print_usage();
107 102
108 printf ("\n\n"); 103 printf(UT_HELP_VRSN);
109 104
110 print_usage (); 105 printf(UT_SUPPORT);
111
112 printf (UT_HELP_VRSN);
113
114 printf (UT_SUPPORT);
115} 106}
116 107
117 108void print_usage(void) {
118 109 printf("%s\n", _("Usage:"));
119void 110 printf(" %s <integer state> [optional text]\n", progname);
120print_usage (void)
121{
122 printf ("%s\n", _("Usage:"));
123 printf (" %s <integer state> [optional text]\n", progname);
124} 111}
diff --git a/plugins/check_fping.c b/plugins/check_fping.c
index 70d6f9fc..8018e06d 100644
--- a/plugins/check_fping.c
+++ b/plugins/check_fping.c
@@ -1,36 +1,36 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_fping plugin 3 * Monitoring check_fping plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_disk plugin 10 * This file contains the check_fping plugin
11* 11 *
12* This plugin will use the fping command to ping the specified host for a 12 * This plugin will use the fping command to ping the specified host for a
13* fast check 13 * fast check
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_fping"; 32const char *progname = "check_fping";
33const char *copyright = "2000-2007"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
@@ -38,490 +38,544 @@ const char *email = "devel@monitoring-plugins.org";
38#include "netutils.h" 38#include "netutils.h"
39#include "utils.h" 39#include "utils.h"
40#include <stdbool.h> 40#include <stdbool.h>
41#include "check_fping.d/config.h"
42#include "states.h"
41 43
42enum { 44enum {
43 PACKET_COUNT = 1, 45 PL = 0,
44 PACKET_SIZE = 56, 46 RTA = 1
45 PL = 0,
46 RTA = 1
47}; 47};
48 48
49int textscan (char *buf); 49static mp_state_enum textscan(char *buf, const char * /*server_name*/, bool /*crta_p*/, double /*crta*/, bool /*wrta_p*/, double /*wrta*/,
50int process_arguments (int, char **); 50 bool /*cpl_p*/, int /*cpl*/, bool /*wpl_p*/, int /*wpl*/, bool /*alive_p*/);
51int get_threshold (char *arg, char *rv[2]); 51
52void print_help (void); 52typedef struct {
53void print_usage (void); 53 int errorcode;
54 54 check_fping_config config;
55char *server_name = NULL; 55} check_fping_config_wrapper;
56char *sourceip = NULL; 56static check_fping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
57char *sourceif = NULL; 57static int get_threshold(char *arg, char *rv[2]);
58int packet_size = PACKET_SIZE; 58static void print_help(void);
59int packet_count = PACKET_COUNT; 59void print_usage(void);
60int target_timeout = 0; 60
61int packet_interval = 0; 61static bool verbose = false;
62bool verbose = false; 62
63int cpl; 63int main(int argc, char **argv) {
64int wpl; 64 setlocale(LC_ALL, "");
65double crta; 65 bindtextdomain(PACKAGE, LOCALEDIR);
66double wrta; 66 textdomain(PACKAGE);
67bool cpl_p = false; 67
68bool wpl_p = false; 68 /* Parse extra opts if any */
69bool alive_p = false; 69 argv = np_extra_opts(&argc, argv, progname);
70bool crta_p = false; 70
71bool wrta_p = false; 71 check_fping_config_wrapper tmp_config = process_arguments(argc, argv);
72 72 if (tmp_config.errorcode == ERROR) {
73int 73 usage4(_("Could not parse arguments"));
74main (int argc, char **argv) 74 }
75{ 75
76/* normally should be int result = STATE_UNKNOWN; */ 76 const check_fping_config config = tmp_config.config;
77 77
78 int status = STATE_UNKNOWN; 78 char *server = NULL;
79 int result = 0; 79 server = strscpy(server, config.server_name);
80 char *fping_prog = NULL; 80
81 char *server = NULL; 81 char *option_string = "";
82 char *command_line = NULL; 82 char *fping_prog = NULL;
83 char *input_buffer = NULL; 83
84 char *option_string = ""; 84 /* First determine if the target is dualstack or ipv6 only. */
85 input_buffer = malloc (MAX_INPUT_BUFFER); 85 bool server_is_inet6_addr = is_inet6_addr(server);
86 86
87 setlocale (LC_ALL, ""); 87 /*
88 bindtextdomain (PACKAGE, LOCALEDIR); 88 * If the user requested -6 OR the user made no assertion and the address is v6 or dualstack
89 textdomain (PACKAGE); 89 * -> we use ipv6
90 90 * If the user requested -4 OR the user made no assertion and the address is v4 ONLY
91 /* Parse extra opts if any */ 91 * -> we use ipv4
92 argv=np_extra_opts (&argc, argv, progname); 92 */
93 93 if (address_family == AF_INET6 || (address_family == AF_UNSPEC && server_is_inet6_addr)) {
94 if (process_arguments (argc, argv) == ERROR) 94 xasprintf(&option_string, "%s-6 ", option_string);
95 usage4 (_("Could not parse arguments")); 95 } else {
96 96 xasprintf(&option_string, "%s-4 ", option_string);
97 server = strscpy (server, server_name); 97 }
98 98 fping_prog = strdup(PATH_TO_FPING);
99 /* compose the command */ 99
100 if (target_timeout) 100 /* compose the command */
101 xasprintf(&option_string, "%s-t %d ", option_string, target_timeout); 101 if (config.target_timeout) {
102 if (packet_interval) 102 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout);
103 xasprintf(&option_string, "%s-p %d ", option_string, packet_interval); 103 }
104 if (sourceip) 104 if (config.packet_interval) {
105 xasprintf(&option_string, "%s-S %s ", option_string, sourceip); 105 xasprintf(&option_string, "%s-p %d ", option_string, config.packet_interval);
106 if (sourceif) 106 }
107 xasprintf(&option_string, "%s-I %s ", option_string, sourceif); 107 if (config.sourceip) {
108 108 xasprintf(&option_string, "%s-S %s ", option_string, config.sourceip);
109#ifdef PATH_TO_FPING6 109 }
110 if (address_family != AF_INET && is_inet6_addr(server)) 110 if (config.sourceif) {
111 fping_prog = strdup(PATH_TO_FPING6); 111 xasprintf(&option_string, "%s-I %s ", option_string, config.sourceif);
112 else 112 }
113 fping_prog = strdup(PATH_TO_FPING); 113 if (config.dontfrag) {
114#else 114 xasprintf(&option_string, "%s-M ", option_string);
115 fping_prog = strdup(PATH_TO_FPING); 115 }
116#endif 116 if (config.randomize_packet_data) {
117 117 xasprintf(&option_string, "%s-R ", option_string);
118 xasprintf (&command_line, "%s %s-b %d -c %d %s", fping_prog, 118 }
119 option_string, packet_size, packet_count, server); 119
120 120 if (config.fwmark_set) {
121 if (verbose) 121 xasprintf(&option_string, "%s--fwmark %u ", option_string, config.fwmark);
122 printf ("%s\n", command_line); 122 }
123 123
124 /* run the command */ 124 if (config.icmp_timestamp) {
125 child_process = spopen (command_line); 125 xasprintf(&option_string, "%s--icmp-timestamp ", option_string);
126 if (child_process == NULL) { 126 }
127 printf (_("Could not open pipe: %s\n"), command_line); 127
128 return STATE_UNKNOWN; 128 if (config.check_source) {
129 } 129 xasprintf(&option_string, "%s--check-source ", option_string);
130 130 }
131 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 131
132 if (child_stderr == NULL) { 132 char *command_line = NULL;
133 printf (_("Could not open stderr for %s\n"), command_line); 133
134 } 134 if (config.icmp_timestamp) {
135 135 // no packet size settable for ICMP timestamp
136 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 136 xasprintf(&command_line, "%s %s -c %d %s", fping_prog, option_string, config.packet_count, server);
137 if (verbose) 137 } else {
138 printf ("%s", input_buffer); 138 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server);
139 status = max_state (status, textscan (input_buffer)); 139 }
140 } 140
141 141 if (verbose) {
142 /* If we get anything on STDERR, at least set warning */ 142 printf("%s\n", command_line);
143 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 143 }
144 status = max_state (status, STATE_WARNING); 144
145 if (verbose) 145 /* run the command */
146 printf ("%s", input_buffer); 146 child_process = spopen(command_line);
147 status = max_state (status, textscan (input_buffer)); 147 if (child_process == NULL) {
148 } 148 printf(_("Could not open pipe: %s\n"), command_line);
149 (void) fclose (child_stderr); 149 return STATE_UNKNOWN;
150 150 }
151 /* close the pipe */ 151
152 result = spclose (child_process); 152 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
153 if (result) { 153 if (child_stderr == NULL) {
154 /* need to use max_state not max */ 154 printf(_("Could not open stderr for %s\n"), command_line);
155 status = max_state (status, STATE_WARNING); 155 }
156 } 156
157 157 char *input_buffer = malloc(MAX_INPUT_BUFFER);
158 if (result > 1 ) { 158 mp_state_enum status = STATE_UNKNOWN;
159 status = max_state (status, STATE_UNKNOWN); 159 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
160 if (result == 2) { 160 if (verbose) {
161 die (STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n")); 161 printf("%s", input_buffer);
162 } 162 }
163 if (result == 3) { 163 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
164 die (STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n")); 164 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
165 } 165 }
166 if (result == 4) { 166
167 die (STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n")); 167 /* If we get anything on STDERR, at least set warning */
168 } 168 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
169 169 status = max_state(status, STATE_WARNING);
170 } 170 if (verbose) {
171 171 printf("%s", input_buffer);
172 printf ("FPING %s - %s\n", state_text (status), server_name); 172 }
173 173 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
174 return status; 174 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
175 }
176 (void)fclose(child_stderr);
177
178 /* close the pipe */
179 int result = spclose(child_process);
180 if (result) {
181 /* need to use max_state not max */
182 status = max_state(status, STATE_WARNING);
183 }
184
185 if (result > 1) {
186 status = max_state(status, STATE_UNKNOWN);
187 if (result == 2) {
188 die(STATE_UNKNOWN, _("FPING UNKNOWN - IP address not found\n"));
189 }
190 if (result == 3) {
191 die(STATE_UNKNOWN, _("FPING UNKNOWN - invalid commandline argument\n"));
192 }
193 if (result == 4) {
194 die(STATE_UNKNOWN, _("FPING UNKNOWN - failed system call\n"));
195 }
196 }
197
198 printf("FPING %s - %s\n", state_text(status), config.server_name);
199
200 return status;
175} 201}
176 202
177 203mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double crta, bool wrta_p, double wrta, bool cpl_p, int cpl,
178int textscan (char *buf) { 204 bool wpl_p, int wpl, bool alive_p) {
179 char *rtastr = NULL; 205 /* stops testing after the first successful reply. */
180 char *losstr = NULL; 206 double rta;
181 char *xmtstr = NULL; 207 double loss;
182 double loss; 208 char *rtastr = NULL;
183 double rta; 209 if (alive_p && strstr(buf, "avg, 0% loss)")) {
184 double xmt; 210 rtastr = strstr(buf, "ms (");
185 int status = STATE_UNKNOWN; 211 rtastr = 1 + index(rtastr, '(');
186 212 rta = strtod(rtastr, NULL);
187 /* stops testing after the first successful reply. */ 213 loss = strtod("0", NULL);
188 if (alive_p && strstr(buf, "avg, 0% loss)")) { 214 die(STATE_OK, _("FPING %s - %s (rta=%f ms)|%s\n"), state_text(STATE_OK), server_name, rta,
189 rtastr = strstr (buf, "ms ("); 215 /* No loss since we only waited for the first reply
190 rtastr = 1 + index(rtastr, '('); 216 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */
191 rta = strtod(rtastr, NULL); 217 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
192 loss=strtod("0",NULL); 218 }
193 die (STATE_OK, 219
194 _("FPING %s - %s (rta=%f ms)|%s\n"), 220 mp_state_enum status = STATE_UNKNOWN;
195 state_text (STATE_OK), server_name,rta, 221 char *xmtstr = NULL;
196 /* No loss since we only waited for the first reply 222 double xmt;
197 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), */ 223 char *losstr = NULL;
198 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, true, 0, false, 0)); 224 if (strstr(buf, "not found")) {
199 } 225 die(STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
200 226
201 if (strstr (buf, "not found")) { 227 } else if (strstr(buf, "is unreachable") || strstr(buf, "Unreachable")) {
202 die (STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name); 228 die(STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"), "host");
203 229
204 } 230 } else if (strstr(buf, "Operation not permitted") || strstr(buf, "No such device")) {
205 else if (strstr (buf, "is unreachable") || strstr (buf, "Unreachable")) { 231 die(STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"), "host");
206 die (STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"), 232 } else if (strstr(buf, "is down")) {
207 "host"); 233 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
208 234
209 } 235 } else if (strstr(buf, "is alive")) {
210 else if (strstr (buf, "Operation not permitted") || strstr (buf, "No such device") ) { 236 status = STATE_OK;
211 die (STATE_UNKNOWN, _("FPING UNKNOWN - %s parameter error\n"), 237
212 "host"); 238 } else if (strstr(buf, "xmt/rcv/%loss") && strstr(buf, "min/avg/max")) {
213 } 239 losstr = strstr(buf, "=");
214 else if (strstr (buf, "is down")) { 240 losstr = 1 + strstr(losstr, "/");
215 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 241 losstr = 1 + strstr(losstr, "/");
216 242 rtastr = strstr(buf, "min/avg/max");
217 } 243 rtastr = strstr(rtastr, "=");
218 else if (strstr (buf, "is alive")) { 244 rtastr = 1 + index(rtastr, '/');
219 status = STATE_OK; 245 loss = strtod(losstr, NULL);
220 246 rta = strtod(rtastr, NULL);
221 } 247 if (cpl_p && loss > cpl) {
222 else if (strstr (buf, "xmt/rcv/%loss") && strstr (buf, "min/avg/max")) { 248 status = STATE_CRITICAL;
223 losstr = strstr (buf, "="); 249 } else if (crta_p && rta > crta) {
224 losstr = 1 + strstr (losstr, "/"); 250 status = STATE_CRITICAL;
225 losstr = 1 + strstr (losstr, "/"); 251 } else if (wpl_p && loss > wpl) {
226 rtastr = strstr (buf, "min/avg/max"); 252 status = STATE_WARNING;
227 rtastr = strstr (rtastr, "="); 253 } else if (wrta_p && rta > wrta) {
228 rtastr = 1 + index (rtastr, '/'); 254 status = STATE_WARNING;
229 loss = strtod (losstr, NULL); 255 } else {
230 rta = strtod (rtastr, NULL); 256 status = STATE_OK;
231 if (cpl_p && loss > cpl) 257 }
232 status = STATE_CRITICAL; 258 die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status), server_name, loss, rta,
233 else if (crta_p && rta > crta) 259 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0),
234 status = STATE_CRITICAL; 260 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
235 else if (wpl_p && loss > wpl) 261
236 status = STATE_WARNING; 262 } else if (strstr(buf, "xmt/rcv/%loss")) {
237 else if (wrta_p && rta > wrta) 263 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
238 status = STATE_WARNING; 264 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */
239 else 265 losstr = strstr(buf, "=");
240 status = STATE_OK; 266 xmtstr = 1 + losstr;
241 die (status, 267 xmt = strtod(xmtstr, NULL);
242 _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), 268 if (xmt == 0) {
243 state_text (status), server_name, loss, rta, 269 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
244 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), 270 }
245 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, true, 0, false, 0)); 271 losstr = 1 + strstr(losstr, "/");
246 272 losstr = 1 + strstr(losstr, "/");
247 } 273 loss = strtod(losstr, NULL);
248 else if(strstr (buf, "xmt/rcv/%loss") ) { 274 if (atoi(losstr) == 100) {
249 /* no min/max/avg if host was unreachable in fping v2.2.b1 */ 275 status = STATE_CRITICAL;
250 /* in v2.4b2: 10.99.0.1 : xmt/rcv/%loss = 0/0/0% */ 276 } else if (cpl_p && loss > cpl) {
251 losstr = strstr (buf, "="); 277 status = STATE_CRITICAL;
252 xmtstr = 1 + losstr; 278 } else if (wpl_p && loss > wpl) {
253 xmt = strtod (xmtstr, NULL); 279 status = STATE_WARNING;
254 if(xmt == 0) 280 } else {
255 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 281 status = STATE_OK;
256 losstr = 1 + strstr (losstr, "/"); 282 }
257 losstr = 1 + strstr (losstr, "/"); 283 /* loss=%.0f%%;%d;%d;0;100 */
258 loss = strtod (losstr, NULL); 284 die(status, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status), server_name, loss,
259 if (atoi(losstr) == 100) 285 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0));
260 status = STATE_CRITICAL; 286
261 else if (cpl_p && loss > cpl) 287 } else {
262 status = STATE_CRITICAL; 288 status = max_state(status, STATE_WARNING);
263 else if (wpl_p && loss > wpl) 289 }
264 status = STATE_WARNING; 290
265 else 291 return status;
266 status = STATE_OK;
267 /* loss=%.0f%%;%d;%d;0;100 */
268 die (status, _("FPING %s - %s (loss=%.0f%% )|%s\n"),
269 state_text (status), server_name, loss ,
270 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100));
271
272 }
273 else {
274 status = max_state (status, STATE_WARNING);
275 }
276
277 return status;
278} 292}
279 293
280
281
282/* process command-line arguments */ 294/* process command-line arguments */
283int 295check_fping_config_wrapper process_arguments(int argc, char **argv) {
284process_arguments (int argc, char **argv) 296 enum {
285{ 297 FWMARK_OPT = CHAR_MAX + 1,
286 int c; 298 ICMP_TIMESTAMP_OPT,
287 char *rv[2]; 299 CHECK_SOURCE_OPT,
288 300 };
289 int option = 0; 301 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
290 static struct option longopts[] = { 302 {"sourceip", required_argument, 0, 'S'},
291 {"hostname", required_argument, 0, 'H'}, 303 {"sourceif", required_argument, 0, 'I'},
292 {"sourceip", required_argument, 0, 'S'}, 304 {"critical", required_argument, 0, 'c'},
293 {"sourceif", required_argument, 0, 'I'}, 305 {"warning", required_argument, 0, 'w'},
294 {"critical", required_argument, 0, 'c'}, 306 {"alive", no_argument, 0, 'a'},
295 {"warning", required_argument, 0, 'w'}, 307 {"bytes", required_argument, 0, 'b'},
296 {"alive", no_argument, 0, 'a'}, 308 {"number", required_argument, 0, 'n'},
297 {"bytes", required_argument, 0, 'b'}, 309 {"target-timeout", required_argument, 0, 'T'},
298 {"number", required_argument, 0, 'n'}, 310 {"interval", required_argument, 0, 'i'},
299 {"target-timeout", required_argument, 0, 'T'}, 311 {"verbose", no_argument, 0, 'v'},
300 {"interval", required_argument, 0, 'i'}, 312 {"version", no_argument, 0, 'V'},
301 {"verbose", no_argument, 0, 'v'}, 313 {"help", no_argument, 0, 'h'},
302 {"version", no_argument, 0, 'V'}, 314 {"use-ipv4", no_argument, 0, '4'},
303 {"help", no_argument, 0, 'h'}, 315 {"use-ipv6", no_argument, 0, '6'},
304 {"use-ipv4", no_argument, 0, '4'}, 316 {"dontfrag", no_argument, 0, 'M'},
305 {"use-ipv6", no_argument, 0, '6'}, 317 {"random", no_argument, 0, 'R'},
306 {0, 0, 0, 0} 318#ifdef FPING_VERSION_5_2_OR_HIGHER
307 }; 319 // only available with fping version >= 5.2
308 320 {"fwmark", required_argument, NULL, FWMARK_OPT},
309 rv[PL] = NULL; 321# ifdef FPING_VERSION_5_3_OR_HIGHER
310 rv[RTA] = NULL; 322 // only available with fping version >= 5.3
311 323 {"icmp-timestamp", no_argument, NULL, ICMP_TIMESTAMP_OPT},
312 if (argc < 2) 324 {"check-source", no_argument, NULL, CHECK_SOURCE_OPT},
313 return ERROR; 325# endif
314
315 if (!is_option (argv[1])) {
316 server_name = argv[1];
317 argv[1] = argv[0];
318 argv = &argv[1];
319 argc--;
320 }
321
322 while (1) {
323 c = getopt_long (argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:46", longopts, &option);
324
325 if (c == -1 || c == EOF || c == 1)
326 break;
327
328 switch (c) {
329 case '?': /* print short usage statement if args not parsable */
330 usage5 ();
331 case 'a': /* host alive mode */
332 alive_p = true;
333 break;
334 case 'h': /* help */
335 print_help ();
336 exit (STATE_UNKNOWN);
337 case 'V': /* version */
338 print_revision (progname, NP_VERSION);
339 exit (STATE_UNKNOWN);
340 case 'v': /* verbose mode */
341 verbose = true;
342 break;
343 case 'H': /* hostname */
344 if (is_host (optarg) == false) {
345 usage2 (_("Invalid hostname/address"), optarg);
346 }
347 server_name = strscpy (server_name, optarg);
348 break;
349 case 'S': /* sourceip */
350 if (is_host (optarg) == false) {
351 usage2 (_("Invalid hostname/address"), optarg);
352 }
353 sourceip = strscpy (sourceip, optarg);
354 break;
355 case 'I': /* sourceip */
356 sourceif = strscpy (sourceif, optarg);
357 break;
358 case '4': /* IPv4 only */
359 address_family = AF_INET;
360 break;
361 case '6': /* IPv6 only */
362#ifdef USE_IPV6
363 address_family = AF_INET6;
364#else
365 usage (_("IPv6 support not available\n"));
366#endif 326#endif
367 break; 327 {0, 0, 0, 0}};
368 case 'c':
369 get_threshold (optarg, rv);
370 if (rv[RTA]) {
371 crta = strtod (rv[RTA], NULL);
372 crta_p = true;
373 rv[RTA] = NULL;
374 }
375 if (rv[PL]) {
376 cpl = atoi (rv[PL]);
377 cpl_p = true;
378 rv[PL] = NULL;
379 }
380 break;
381 case 'w':
382 get_threshold (optarg, rv);
383 if (rv[RTA]) {
384 wrta = strtod (rv[RTA], NULL);
385 wrta_p = true;
386 rv[RTA] = NULL;
387 }
388 if (rv[PL]) {
389 wpl = atoi (rv[PL]);
390 wpl_p = true;
391 rv[PL] = NULL;
392 }
393 break;
394 case 'b': /* bytes per packet */
395 if (is_intpos (optarg))
396 packet_size = atoi (optarg);
397 else
398 usage (_("Packet size must be a positive integer"));
399 break;
400 case 'n': /* number of packets */
401 if (is_intpos (optarg))
402 packet_count = atoi (optarg);
403 else
404 usage (_("Packet count must be a positive integer"));
405 break;
406 case 'T': /* timeout in msec */
407 if (is_intpos (optarg))
408 target_timeout = atoi (optarg);
409 else
410 usage (_("Target timeout must be a positive integer"));
411 break;
412 case 'i': /* interval in msec */
413 if (is_intpos (optarg))
414 packet_interval = atoi (optarg);
415 else
416 usage (_("Interval must be a positive integer"));
417 break;
418 }
419 }
420
421 if (server_name == NULL)
422 usage4 (_("Hostname was not supplied"));
423
424 return OK;
425}
426
427 328
428int 329 char *rv[2];
429get_threshold (char *arg, char *rv[2]) 330 rv[PL] = NULL;
430{ 331 rv[RTA] = NULL;
431 char *arg1 = NULL;
432 char *arg2 = NULL;
433
434 arg1 = strscpy (arg1, arg);
435 if (strpbrk (arg1, ",:"))
436 arg2 = 1 + strpbrk (arg1, ",:");
437
438 if (arg2) {
439 arg1[strcspn (arg1, ",:")] = 0;
440 if (strstr (arg1, "%") && strstr (arg2, "%"))
441 die (STATE_UNKNOWN,
442 _("%s: Only one threshold may be packet loss (%s)\n"), progname,
443 arg);
444 if (!strstr (arg1, "%") && !strstr (arg2, "%"))
445 die (STATE_UNKNOWN,
446 _("%s: Only one threshold must be packet loss (%s)\n"),
447 progname, arg);
448 }
449
450 if (arg2 && strstr (arg2, "%")) {
451 rv[PL] = arg2;
452 rv[RTA] = arg1;
453 }
454 else if (arg2) {
455 rv[PL] = arg1;
456 rv[RTA] = arg2;
457 }
458 else if (strstr (arg1, "%")) {
459 rv[PL] = arg1;
460 }
461 else {
462 rv[RTA] = arg1;
463 }
464
465 return OK;
466}
467 332
333 int option = 0;
468 334
469void print_help (void) { 335 check_fping_config_wrapper result = {
336 .errorcode = OK,
337 .config = check_fping_config_init(),
338 };
470 339
471 print_revision (progname, NP_VERSION); 340 if (argc < 2) {
341 result.errorcode = ERROR;
342 return result;
343 }
472 344
473 printf ("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n"); 345 if (!is_option(argv[1])) {
474 printf (COPYRIGHT, copyright, email); 346 result.config.server_name = argv[1];
347 argv[1] = argv[0];
348 argv = &argv[1];
349 argc--;
350 }
475 351
476 printf ("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check")); 352 while (true) {
353 int option_index = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
477 354
478 printf ("%s\n", _("Note that it is necessary to set the suid flag on fping.")); 355 if (option_index == -1 || option_index == EOF || option_index == 1) {
356 break;
357 }
479 358
480 printf ("\n\n"); 359 switch (option_index) {
360 case '?': /* print short usage statement if args not parsable */
361 usage5();
362 case 'a': /* host alive mode */
363 result.config.alive_p = true;
364 break;
365 case 'h': /* help */
366 print_help();
367 exit(STATE_UNKNOWN);
368 case 'V': /* version */
369 print_revision(progname, NP_VERSION);
370 exit(STATE_UNKNOWN);
371 case 'v': /* verbose mode */
372 verbose = true;
373 break;
374 case 'H': /* hostname */
375 if (!is_host(optarg)) {
376 usage2(_("Invalid hostname/address"), optarg);
377 }
378 result.config.server_name = optarg;
379 break;
380 case 'S': /* sourceip */
381 if (!is_host(optarg)) {
382 usage2(_("Invalid hostname/address"), optarg);
383 }
384 result.config.sourceip = optarg;
385 break;
386 case 'I': /* sourceip */
387 result.config.sourceif = optarg;
388 break;
389 case '4': /* IPv4 only */
390 address_family = AF_INET;
391 break;
392 case '6': /* IPv6 only */
393 address_family = AF_INET6;
394 break;
395 case 'c':
396 get_threshold(optarg, rv);
397 if (rv[RTA]) {
398 result.config.crta = strtod(rv[RTA], NULL);
399 result.config.crta_p = true;
400 rv[RTA] = NULL;
401 }
402 if (rv[PL]) {
403 result.config.cpl = atoi(rv[PL]);
404 result.config.cpl_p = true;
405 rv[PL] = NULL;
406 }
407 break;
408 case 'w':
409 get_threshold(optarg, rv);
410 if (rv[RTA]) {
411 result.config.wrta = strtod(rv[RTA], NULL);
412 result.config.wrta_p = true;
413 rv[RTA] = NULL;
414 }
415 if (rv[PL]) {
416 result.config.wpl = atoi(rv[PL]);
417 result.config.wpl_p = true;
418 rv[PL] = NULL;
419 }
420 break;
421 case 'b': /* bytes per packet */
422 if (is_intpos(optarg)) {
423 result.config.packet_size = atoi(optarg);
424 } else {
425 usage(_("Packet size must be a positive integer"));
426 }
427 break;
428 case 'n': /* number of packets */
429 if (is_intpos(optarg)) {
430 result.config.packet_count = atoi(optarg);
431 } else {
432 usage(_("Packet count must be a positive integer"));
433 }
434 break;
435 case 'T': /* timeout in msec */
436 if (is_intpos(optarg)) {
437 result.config.target_timeout = atoi(optarg);
438 } else {
439 usage(_("Target timeout must be a positive integer"));
440 }
441 break;
442 case 'i': /* interval in msec */
443 if (is_intpos(optarg)) {
444 result.config.packet_interval = atoi(optarg);
445 } else {
446 usage(_("Interval must be a positive integer"));
447 }
448 break;
449 case 'R':
450 result.config.randomize_packet_data = true;
451 break;
452 case 'M':
453 result.config.dontfrag = true;
454 break;
455 case FWMARK_OPT:
456 if (is_intpos(optarg)) {
457 result.config.fwmark = (unsigned int)atol(optarg);
458 result.config.fwmark_set = true;
459 } else {
460 usage(_("fwmark must be a positive integer"));
461 }
462 break;
463 case ICMP_TIMESTAMP_OPT:
464 result.config.icmp_timestamp = true;
465 break;
466 case CHECK_SOURCE_OPT:
467 result.config.check_source = true;
468 break;
469 }
470 }
481 471
482 print_usage (); 472 if (result.config.server_name == NULL) {
473 usage4(_("Hostname was not supplied"));
474 }
483 475
484 printf (UT_HELP_VRSN); 476 return result;
485 printf (UT_EXTRA_OPTS); 477}
486 478
487 printf (UT_IPv46); 479int get_threshold(char *arg, char *rv[2]) {
480 char *arg2 = NULL;
481
482 char *arg1 = strdup(arg);
483 if (strpbrk(arg1, ",:")) {
484 arg2 = 1 + strpbrk(arg1, ",:");
485 }
486
487 if (arg2) {
488 arg1[strcspn(arg1, ",:")] = 0;
489 if (strstr(arg1, "%") && strstr(arg2, "%")) {
490 die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname, arg);
491 }
492 if (!strstr(arg1, "%") && !strstr(arg2, "%")) {
493 die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname, arg);
494 }
495 }
496
497 if (arg2 && strstr(arg2, "%")) {
498 rv[PL] = arg2;
499 rv[RTA] = arg1;
500 } else if (arg2) {
501 rv[PL] = arg1;
502 rv[RTA] = arg2;
503 } else if (strstr(arg1, "%")) {
504 rv[PL] = arg1;
505 } else {
506 rv[RTA] = arg1;
507 }
508
509 return OK;
510}
488 511
489 printf (" %s\n", "-H, --hostname=HOST"); 512void print_help(void) {
490 printf (" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)")); 513
491 printf (" %s\n", "-w, --warning=THRESHOLD"); 514 print_revision(progname, NP_VERSION);
492 printf (" %s\n", _("warning threshold pair")); 515
493 printf (" %s\n", "-c, --critical=THRESHOLD"); 516 printf("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
494 printf (" %s\n", _("critical threshold pair")); 517 printf(COPYRIGHT, copyright, email);
495 printf (" %s\n", "-a, --alive"); 518
496 printf (" %s\n", _("Return OK after first successful reply")); 519 printf("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check"));
497 printf (" %s\n", "-b, --bytes=INTEGER"); 520
498 printf (" %s (default: %d)\n", _("size of ICMP packet"),PACKET_SIZE); 521 printf("%s\n", _("Note that it is necessary to set the suid flag on fping."));
499 printf (" %s\n", "-n, --number=INTEGER"); 522
500 printf (" %s (default: %d)\n", _("number of ICMP packets to send"),PACKET_COUNT); 523 printf("\n\n");
501 printf (" %s\n", "-T, --target-timeout=INTEGER"); 524
502 printf (" %s (default: fping's default for -t)\n", _("Target timeout (ms)")); 525 print_usage();
503 printf (" %s\n", "-i, --interval=INTEGER"); 526
504 printf (" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets")); 527 printf(UT_HELP_VRSN);
505 printf (" %s\n", "-S, --sourceip=HOST"); 528 printf(UT_EXTRA_OPTS);
506 printf (" %s\n", _("name or IP Address of sourceip")); 529
507 printf (" %s\n", "-I, --sourceif=IF"); 530 printf(UT_IPv46);
508 printf (" %s\n", _("source interface name")); 531
509 printf (UT_VERBOSE); 532 printf(" %s\n", "-H, --hostname=HOST");
510 printf ("\n"); 533 printf(" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)"));
511 printf (" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)")); 534 printf(" %s\n", "-w, --warning=THRESHOLD");
512 printf (" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of")); 535 printf(" %s\n", _("warning threshold pair"));
513 printf (" %s\n", _("packet loss to trigger an alarm state.")); 536 printf(" %s\n", "-c, --critical=THRESHOLD");
537 printf(" %s\n", _("critical threshold pair"));
538 printf(" %s\n", "-a, --alive");
539 printf(" %s\n", _("Return OK after first successful reply"));
540 printf(" %s\n", "-b, --bytes=INTEGER");
541 printf(" %s (default: %d)\n", _("size of ICMP packet"), PACKET_SIZE);
542 printf(" %s\n", "-n, --number=INTEGER");
543 printf(" %s (default: %d)\n", _("number of ICMP packets to send"), PACKET_COUNT);
544 printf(" %s\n", "-T, --target-timeout=INTEGER");
545 printf(" %s (default: fping's default for -t)\n", _("Target timeout (ms)"));
546 printf(" %s\n", "-i, --interval=INTEGER");
547 printf(" %s (default: fping's default for -p)\n", _("Interval (ms) between sending packets"));
548 printf(" %s\n", "-S, --sourceip=HOST");
549 printf(" %s\n", _("name or IP Address of sourceip"));
550 printf(" %s\n", "-I, --sourceif=IF");
551 printf(" %s\n", _("source interface name"));
552 printf(" %s\n", "-M, --dontfrag");
553 printf(" %s\n", _("set the Don't Fragment flag"));
554 printf(" %s\n", "-R, --random");
555 printf(" %s\n", _("random packet data (to foil link data compression)"));
556#ifdef FPING_VERSION_5_2_OR_HIGHER
557 printf(" %s\n", "--fwmark=INTEGER");
558 printf(" %s\n", _("set the routing mark to INTEGER (fping option)"));
559# ifdef FPING_VERSION_5_3_OR_HIGHER
560 printf(" %s\n", "--icmp-timestamp");
561 printf(" %s\n", _("use ICMP Timestamp instead of ICMP Echo (fping option)"));
562 printf(" %s\n", "--check-source");
563 printf(" %s\n", _("discard replies not from target address (fping option)"));
564# endif
565#endif
566 printf(UT_VERBOSE);
567 printf("\n");
568 printf(" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
569 printf(" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
570 printf(" %s\n", _("packet loss to trigger an alarm state."));
514 571
515 printf ("\n"); 572 printf("\n");
516 printf (" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6.")); 573 printf(" %s\n", _("IPv4 is used by default. Specify -6 to use IPv6."));
517 574
518 printf (UT_SUPPORT); 575 printf(UT_SUPPORT);
519} 576}
520 577
521 578void print_usage(void) {
522void 579 printf("%s\n", _("Usage:"));
523print_usage (void) 580 printf(" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname);
524{
525 printf ("%s\n", _("Usage:"));
526 printf (" %s <host_address> -w limit -c limit [-b size] [-n number] [-T number] [-i number]\n", progname);
527} 581}
diff --git a/plugins/check_fping.d/config.h b/plugins/check_fping.d/config.h
new file mode 100644
index 00000000..d95e9ded
--- /dev/null
+++ b/plugins/check_fping.d/config.h
@@ -0,0 +1,82 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 PACKET_SIZE = 56,
8 PACKET_COUNT = 1,
9};
10
11typedef struct {
12 char *server_name;
13 char *sourceip;
14 char *sourceif;
15 int packet_size;
16 int packet_count;
17 int target_timeout;
18 int packet_interval;
19 bool randomize_packet_data;
20 bool dontfrag;
21 bool alive_p;
22
23 double crta;
24 bool crta_p;
25 double wrta;
26 bool wrta_p;
27
28 int cpl;
29 bool cpl_p;
30 int wpl;
31 bool wpl_p;
32
33 // only available with fping version >= 5.2
34 // for a given uint _fwmark_ fping sets _fwmark_ as a firewall mark
35 // in the packets
36 unsigned int fwmark;
37 bool fwmark_set;
38
39
40 // only available with fping version >= 5.3
41 // Setting icmp_timestamp tells fping to use ICMP Timestamp (ICMP type 13) instead
42 // of ICMP Echo
43 bool icmp_timestamp;
44
45 // Setting check_source lets fping discard replies which are not from the target address
46 bool check_source;
47} check_fping_config;
48
49check_fping_config check_fping_config_init() {
50 check_fping_config tmp = {
51 .server_name = NULL,
52 .sourceip = NULL,
53 .sourceif = NULL,
54 .packet_size = PACKET_SIZE,
55 .packet_count = PACKET_COUNT,
56 .target_timeout = 0,
57 .packet_interval = 0,
58 .randomize_packet_data = false,
59 .dontfrag = false,
60 .alive_p = false,
61
62 .crta = 0,
63 .crta_p = false,
64 .wrta = 0,
65 .wrta_p = false,
66
67 .cpl = 0,
68 .cpl_p = false,
69 .wpl = 0,
70 .wpl_p = false,
71
72 // only available with fping version >= 5.2
73 .fwmark = 0,
74 .fwmark_set = false, // just to be deterministic
75
76 // only available with fping version >= 5.3
77 .icmp_timestamp = false,
78 .check_source = false,
79
80 };
81 return tmp;
82}
diff --git a/plugins/check_game.c b/plugins/check_game.c
index ca126973..c0193b03 100644
--- a/plugins/check_game.c
+++ b/plugins/check_game.c
@@ -1,335 +1,317 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_game plugin 3 * Monitoring check_game plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2002-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_game plugin 10 * This file contains the check_game plugin
11* 11 *
12* This plugin tests game server connections with the specified host. 12 * This plugin tests game server connections with the specified host.
13* using the qstat program 13 * using the qstat program
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_game"; 32const char *progname = "check_game";
33const char *copyright = "2002-2007"; 33const char *copyright = "2002-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "runcmd.h" 38#include "runcmd.h"
39#include "check_game.d/config.h"
40#include "../lib/monitoringplug.h"
39 41
40int process_arguments (int, char **); 42typedef struct {
41int validate_arguments (void); 43 int errorcode;
42void print_help (void); 44 check_game_config config;
43void print_usage (void); 45} check_game_config_wrapper;
44 46
45#define QSTAT_DATA_DELIMITER "," 47static check_game_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
48static void print_help(void);
49void print_usage(void);
46 50
47#define QSTAT_HOST_ERROR "ERROR" 51#define QSTAT_DATA_DELIMITER ","
48#define QSTAT_HOST_DOWN "DOWN"
49#define QSTAT_HOST_TIMEOUT "TIMEOUT"
50#define QSTAT_MAX_RETURN_ARGS 12
51
52char *server_ip;
53char *game_type;
54int port = 0;
55
56bool verbose = false;
57
58int qstat_game_players_max = -1;
59int qstat_game_players = -1;
60int qstat_game_field = -1;
61int qstat_map_field = -1;
62int qstat_ping_field = -1;
63
64
65int
66main (int argc, char **argv)
67{
68 char *command_line;
69 int result = STATE_UNKNOWN;
70 char *p, *ret[QSTAT_MAX_RETURN_ARGS];
71 size_t i = 0;
72 output chld_out;
73
74 setlocale (LC_ALL, "");
75 bindtextdomain (PACKAGE, LOCALEDIR);
76 textdomain (PACKAGE);
77
78 /* Parse extra opts if any */
79 argv=np_extra_opts (&argc, argv, progname);
80
81 if (process_arguments (argc, argv) == ERROR)
82 usage_va(_("Could not parse arguments"));
83
84 result = STATE_OK;
85
86 /* create the command line to execute */
87 xasprintf (&command_line, "%s -raw %s -%s %s",
88 PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip);
89
90 if (port)
91 xasprintf (&command_line, "%s:%-d", command_line, port);
92
93 if (verbose)
94 printf ("%s\n", command_line);
95
96 /* run the command. historically, this plugin ignores output on stderr,
97 * as well as return status of the qstat program */
98 (void)np_runcmd(command_line, &chld_out, NULL, 0);
99
100 /* sanity check */
101 /* was thinking about running qstat without any options, capturing the
102 -default line, parsing it & making an array of all know server types
103 but thought this would be too much hassle considering this is a tool
104 for intelligent sysadmins (ha). Could put a static array of known
105 server types in a header file but then we'd be limiting ourselves
106
107 In the end, I figured I'd simply let an error occur & then trap it
108 */
109
110 if (!strncmp (chld_out.line[0], "unknown option", 14)) {
111 printf (_("CRITICAL - Host type parameter incorrect!\n"));
112 result = STATE_CRITICAL;
113 return result;
114 }
115
116 p = (char *) strtok (chld_out.line[0], QSTAT_DATA_DELIMITER);
117 while (p != NULL) {
118 ret[i] = p;
119 p = (char *) strtok (NULL, QSTAT_DATA_DELIMITER);
120 i++;
121 if (i >= QSTAT_MAX_RETURN_ARGS)
122 break;
123 }
124
125 if (strstr (ret[2], QSTAT_HOST_ERROR)) {
126 printf (_("CRITICAL - Host not found\n"));
127 result = STATE_CRITICAL;
128 }
129 else if (strstr (ret[2], QSTAT_HOST_DOWN)) {
130 printf (_("CRITICAL - Game server down or unavailable\n"));
131 result = STATE_CRITICAL;
132 }
133 else if (strstr (ret[2], QSTAT_HOST_TIMEOUT)) {
134 printf (_("CRITICAL - Game server timeout\n"));
135 result = STATE_CRITICAL;
136 }
137 else {
138 printf ("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n",
139 ret[qstat_game_players],
140 ret[qstat_game_players_max],
141 ret[qstat_game_field],
142 ret[qstat_map_field],
143 ret[qstat_ping_field],
144 perfdata ("players", atol(ret[qstat_game_players]), "",
145 false, 0, false, 0,
146 true, 0, true, atol(ret[qstat_game_players_max])),
147 fperfdata ("ping", strtod(ret[qstat_ping_field], NULL), "",
148 false, 0, false, 0,
149 true, 0, false, 0));
150 }
151
152 return result;
153}
154 52
53#define QSTAT_HOST_ERROR "ERROR"
54#define QSTAT_HOST_DOWN "DOWN"
55#define QSTAT_HOST_TIMEOUT "TIMEOUT"
56#define QSTAT_MAX_RETURN_ARGS 12
155 57
156int 58static bool verbose = false;
157process_arguments (int argc, char **argv) 59
158{ 60int main(int argc, char **argv) {
159 int c; 61 setlocale(LC_ALL, "");
160 62 bindtextdomain(PACKAGE, LOCALEDIR);
161 int opt_index = 0; 63 textdomain(PACKAGE);
162 static struct option long_opts[] = { 64
163 {"help", no_argument, 0, 'h'}, 65 /* Parse extra opts if any */
164 {"version", no_argument, 0, 'V'}, 66 argv = np_extra_opts(&argc, argv, progname);
165 {"verbose", no_argument, 0, 'v'}, 67
166 {"timeout", required_argument, 0, 't'}, 68 check_game_config_wrapper tmp = process_arguments(argc, argv);
167 {"hostname", required_argument, 0, 'H'}, 69
168 {"port", required_argument, 0, 'P'}, 70 if (tmp.errorcode == ERROR) {
169 {"game-type", required_argument, 0, 'G'}, 71 usage_va(_("Could not parse arguments"));
170 {"map-field", required_argument, 0, 'm'}, 72 }
171 {"ping-field", required_argument, 0, 'p'}, 73
172 {"game-field", required_argument, 0, 'g'}, 74 check_game_config config = tmp.config;
173 {"players-field", required_argument, 0, 129}, 75
174 {"max-players-field", required_argument, 0, 130}, 76 mp_state_enum result = STATE_OK;
175 {0, 0, 0, 0} 77
176 }; 78 /* create the command line to execute */
177 79 char *command_line = NULL;
178 if (argc < 2) 80 xasprintf(&command_line, "%s -raw %s -%s %s", PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, config.game_type, config.server_ip);
179 return ERROR; 81
180 82 if (config.port) {
181 for (c = 1; c < argc; c++) { 83 xasprintf(&command_line, "%s:%-d", command_line, config.port);
182 if (strcmp ("-mf", argv[c]) == 0) 84 }
183 strcpy (argv[c], "-m"); 85
184 else if (strcmp ("-pf", argv[c]) == 0) 86 if (verbose) {
185 strcpy (argv[c], "-p"); 87 printf("%s\n", command_line);
186 else if (strcmp ("-gf", argv[c]) == 0) 88 }
187 strcpy (argv[c], "-g"); 89
188 } 90 /* run the command. historically, this plugin ignores output on stderr,
189 91 * as well as return status of the qstat program */
190 while (1) { 92 output chld_out = {};
191 c = getopt_long (argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index); 93 (void)np_runcmd(command_line, &chld_out, NULL, 0);
192 94
193 if (c == -1 || c == EOF) 95 /* sanity check */
194 break; 96 /* was thinking about running qstat without any options, capturing the
195 97 -default line, parsing it & making an array of all know server types
196 switch (c) { 98 but thought this would be too much hassle considering this is a tool
197 case 'h': /* help */ 99 for intelligent sysadmins (ha). Could put a static array of known
198 print_help (); 100 server types in a header file but then we'd be limiting ourselves
199 exit (STATE_UNKNOWN); 101
200 case 'V': /* version */ 102 In the end, I figured I'd simply let an error occur & then trap it
201 print_revision (progname, NP_VERSION); 103 */
202 exit (STATE_UNKNOWN); 104
203 case 'v': /* version */ 105 if (!strncmp(chld_out.line[0], "unknown option", strlen("unknown option"))) {
204 verbose = true; 106 printf(_("CRITICAL - Host type parameter incorrect!\n"));
205 break; 107 result = STATE_CRITICAL;
206 case 't': /* timeout period */ 108 exit(result);
207 timeout_interval = atoi (optarg); 109 }
208 break; 110
209 case 'H': /* hostname */ 111 char *ret[QSTAT_MAX_RETURN_ARGS];
210 if (strlen (optarg) >= MAX_HOST_ADDRESS_LENGTH) 112 size_t i = 0;
211 die (STATE_UNKNOWN, _("Input buffer overflow\n")); 113 char *sequence = strtok(chld_out.line[0], QSTAT_DATA_DELIMITER);
212 server_ip = optarg; 114 while (sequence != NULL) {
213 break; 115 ret[i] = sequence;
214 case 'P': /* port */ 116 sequence = strtok(NULL, QSTAT_DATA_DELIMITER);
215 port = atoi (optarg); 117 i++;
216 break; 118 if (i >= QSTAT_MAX_RETURN_ARGS) {
217 case 'G': /* hostname */ 119 break;
218 if (strlen (optarg) >= MAX_INPUT_BUFFER) 120 }
219 die (STATE_UNKNOWN, _("Input buffer overflow\n")); 121 }
220 game_type = optarg; 122
221 break; 123 if (strstr(ret[2], QSTAT_HOST_ERROR)) {
222 case 'p': /* index of ping field */ 124 printf(_("CRITICAL - Host not found\n"));
223 qstat_ping_field = atoi (optarg); 125 result = STATE_CRITICAL;
224 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS) 126 } else if (strstr(ret[2], QSTAT_HOST_DOWN)) {
225 return ERROR; 127 printf(_("CRITICAL - Game server down or unavailable\n"));
226 break; 128 result = STATE_CRITICAL;
227 case 'm': /* index on map field */ 129 } else if (strstr(ret[2], QSTAT_HOST_TIMEOUT)) {
228 qstat_map_field = atoi (optarg); 130 printf(_("CRITICAL - Game server timeout\n"));
229 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS) 131 result = STATE_CRITICAL;
230 return ERROR; 132 } else {
231 break; 133 printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[config.qstat_game_players], ret[config.qstat_game_players_max],
232 case 'g': /* index of game field */ 134 ret[config.qstat_game_field], ret[config.qstat_map_field], ret[config.qstat_ping_field],
233 qstat_game_field = atoi (optarg); 135 perfdata("players", atol(ret[config.qstat_game_players]), "", false, 0, false, 0, true, 0, true,
234 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS) 136 atol(ret[config.qstat_game_players_max])),
235 return ERROR; 137 fperfdata("ping", strtod(ret[config.qstat_ping_field], NULL), "", false, 0, false, 0, true, 0, false, 0));
236 break; 138 }
237 case 129: /* index of player count field */ 139
238 qstat_game_players = atoi (optarg); 140 exit(result);
239 if (qstat_game_players_max == 0)
240 qstat_game_players_max = qstat_game_players - 1;
241 if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS)
242 return ERROR;
243 break;
244 case 130: /* index of max players field */
245 qstat_game_players_max = atoi (optarg);
246 if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS)
247 return ERROR;
248 break;
249 default: /* args not parsable */
250 usage5();
251 }
252 }
253
254 c = optind;
255 /* first option is the game type */
256 if (!game_type && c<argc)
257 game_type = strdup (argv[c++]);
258
259 /* Second option is the server name */
260 if (!server_ip && c<argc)
261 server_ip = strdup (argv[c++]);
262
263 return validate_arguments ();
264} 141}
265 142
266 143#define players_field_index 129
267int 144#define max_players_field_index 130
268validate_arguments (void) 145
269{ 146check_game_config_wrapper process_arguments(int argc, char **argv) {
270 if (qstat_game_players_max < 0) 147 static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
271 qstat_game_players_max = 4; 148 {"version", no_argument, 0, 'V'},
272 149 {"verbose", no_argument, 0, 'v'},
273 if (qstat_game_players < 0) 150 {"timeout", required_argument, 0, 't'},
274 qstat_game_players = 5; 151 {"hostname", required_argument, 0, 'H'},
275 152 {"port", required_argument, 0, 'P'},
276 if (qstat_game_field < 0) 153 {"game-type", required_argument, 0, 'G'},
277 qstat_game_field = 2; 154 {"map-field", required_argument, 0, 'm'},
278 155 {"ping-field", required_argument, 0, 'p'},
279 if (qstat_map_field < 0) 156 {"game-field", required_argument, 0, 'g'},
280 qstat_map_field = 3; 157 {"players-field", required_argument, 0, players_field_index},
281 158 {"max-players-field", required_argument, 0, max_players_field_index},
282 if (qstat_ping_field < 0) 159 {0, 0, 0, 0}};
283 qstat_ping_field = 5; 160
284 161 check_game_config_wrapper result = {
285 return OK; 162 .config = check_game_config_init(),
163 .errorcode = OK,
164 };
165
166 if (argc < 2) {
167 result.errorcode = ERROR;
168 return result;
169 }
170
171 for (int option_counter = 1; option_counter < argc; option_counter++) {
172 if (strcmp("-mf", argv[option_counter]) == 0) {
173 strcpy(argv[option_counter], "-m");
174 } else if (strcmp("-pf", argv[option_counter]) == 0) {
175 strcpy(argv[option_counter], "-p");
176 } else if (strcmp("-gf", argv[option_counter]) == 0) {
177 strcpy(argv[option_counter], "-g");
178 }
179 }
180
181 int opt_index = 0;
182 while (true) {
183 int option_index = getopt_long(argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
184
185 if (option_index == -1 || option_index == EOF) {
186 break;
187 }
188
189 switch (option_index) {
190 case 'h': /* help */
191 print_help();
192 exit(STATE_UNKNOWN);
193 case 'V': /* version */
194 print_revision(progname, NP_VERSION);
195 exit(STATE_UNKNOWN);
196 case 'v': /* version */
197 verbose = true;
198 break;
199 case 't': /* timeout period */
200 timeout_interval = atoi(optarg);
201 break;
202 case 'H': /* hostname */
203 if (strlen(optarg) >= MAX_HOST_ADDRESS_LENGTH) {
204 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
205 }
206 result.config.server_ip = optarg;
207 break;
208 case 'P': /* port */
209 result.config.port = atoi(optarg);
210 break;
211 case 'G': /* hostname */
212 if (strlen(optarg) >= MAX_INPUT_BUFFER) {
213 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
214 }
215 result.config.game_type = optarg;
216 break;
217 case 'p': /* index of ping field */
218 result.config.qstat_ping_field = atoi(optarg);
219 if (result.config.qstat_ping_field < 0 || result.config.qstat_ping_field > QSTAT_MAX_RETURN_ARGS) {
220 result.errorcode = ERROR;
221 return result;
222 }
223 break;
224 case 'm': /* index on map field */
225 result.config.qstat_map_field = atoi(optarg);
226 if (result.config.qstat_map_field < 0 || result.config.qstat_map_field > QSTAT_MAX_RETURN_ARGS) {
227 result.errorcode = ERROR;
228 return result;
229 }
230 break;
231 case 'g': /* index of game field */
232 result.config.qstat_game_field = atoi(optarg);
233 if (result.config.qstat_game_field < 0 || result.config.qstat_game_field > QSTAT_MAX_RETURN_ARGS) {
234 result.errorcode = ERROR;
235 return result;
236 }
237 break;
238 case players_field_index: /* index of player count field */
239 result.config.qstat_game_players = atoi(optarg);
240 if (result.config.qstat_game_players_max == 0) {
241 result.config.qstat_game_players_max = result.config.qstat_game_players - 1;
242 }
243 if (result.config.qstat_game_players < 0 || result.config.qstat_game_players > QSTAT_MAX_RETURN_ARGS) {
244 result.errorcode = ERROR;
245 return result;
246 }
247 break;
248 case max_players_field_index: /* index of max players field */
249 result.config.qstat_game_players_max = atoi(optarg);
250 if (result.config.qstat_game_players_max < 0 || result.config.qstat_game_players_max > QSTAT_MAX_RETURN_ARGS) {
251 result.errorcode = ERROR;
252 return result;
253 }
254 break;
255 default: /* args not parsable */
256 usage5();
257 }
258 }
259
260 int option_counter = optind;
261 /* first option is the game type */
262 if (!result.config.game_type && option_counter < argc) {
263 result.config.game_type = strdup(argv[option_counter++]);
264 }
265
266 /* Second option is the server name */
267 if (!result.config.server_ip && option_counter < argc) {
268 result.config.server_ip = strdup(argv[option_counter++]);
269 }
270
271 return result;
286} 272}
287 273
274void print_help(void) {
275 print_revision(progname, NP_VERSION);
288 276
289void 277 printf("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
290print_help (void) 278 printf(COPYRIGHT, copyright, email);
291{
292 print_revision (progname, NP_VERSION);
293
294 printf ("Copyright (c) 1999 Ian Cass, Knowledge Matters Limited\n");
295 printf (COPYRIGHT, copyright, email);
296 279
297 printf (_("This plugin tests game server connections with the specified host.")); 280 printf(_("This plugin tests game server connections with the specified host."));
298 281
299 printf ("\n\n"); 282 printf("\n\n");
300 283
301 print_usage (); 284 print_usage();
302 285
303 printf (UT_HELP_VRSN); 286 printf(UT_HELP_VRSN);
304 printf (UT_EXTRA_OPTS); 287 printf(UT_EXTRA_OPTS);
288 printf(" -H, --hostname=ADDRESS\n"
289 " Host name, IP Address, or unix socket (must be an absolute path)\n");
290 printf(" %s\n", "-P");
291 printf(" %s\n", _("Optional port to connect to"));
292 printf(" %s\n", "-g");
293 printf(" %s\n", _("Field number in raw qstat output that contains game name"));
294 printf(" %s\n", "-m");
295 printf(" %s\n", _("Field number in raw qstat output that contains map name"));
296 printf(" %s\n", "-p");
297 printf(" %s\n", _("Field number in raw qstat output that contains ping time"));
305 298
306 printf (" %s\n", "-p"); 299 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
307 printf (" %s\n", _("Optional port of which to connect"));
308 printf (" %s\n", "gf");
309 printf (" %s\n", _("Field number in raw qstat output that contains game name"));
310 printf (" %s\n", "-mf");
311 printf (" %s\n", _("Field number in raw qstat output that contains map name"));
312 printf (" %s\n", "-pf");
313 printf (" %s\n", _("Field number in raw qstat output that contains ping time"));
314 300
315 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 301 printf("\n");
302 printf("%s\n", _("Notes:"));
303 printf(" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool."));
304 printf(" %s\n", _("If you don't have the package installed, you will need to download it from"));
305 printf(" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin."));
316 306
317 printf ("\n"); 307 printf(UT_SUPPORT);
318 printf ("%s\n", _("Notes:"));
319 printf (" %s\n", _("This plugin uses the 'qstat' command, the popular game server status query tool."));
320 printf (" %s\n", _("If you don't have the package installed, you will need to download it from"));
321 printf (" %s\n", _("https://github.com/multiplay/qstat before you can use this plugin."));
322
323 printf (UT_SUPPORT);
324} 308}
325 309
326 310void print_usage(void) {
327 311 printf("%s\n", _("Usage:"));
328void 312 printf(" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G game-time] [-H hostname] <game> "
329print_usage (void) 313 "<ip_address>\n",
330{ 314 progname);
331 printf ("%s\n", _("Usage:"));
332 printf (" %s [-hvV] [-P port] [-t timeout] [-g game_field] [-m map_field] [-p ping_field] [-G game-time] [-H hostname] <game> <ip_address>\n", progname);
333} 315}
334 316
335/****************************************************************************** 317/******************************************************************************
diff --git a/plugins/check_game.d/config.h b/plugins/check_game.d/config.h
new file mode 100644
index 00000000..c95a1ced
--- /dev/null
+++ b/plugins/check_game.d/config.h
@@ -0,0 +1,30 @@
1#pragma once
2#include "../../config.h"
3#include <stddef.h>
4
5typedef struct {
6 char *server_ip;
7 char *game_type;
8 int port;
9
10 int qstat_game_players_max;
11 int qstat_game_players;
12 int qstat_game_field;
13 int qstat_map_field;
14 int qstat_ping_field;
15} check_game_config;
16
17check_game_config check_game_config_init() {
18 check_game_config tmp = {
19 .server_ip = NULL,
20 .game_type = NULL,
21 .port = 0,
22
23 .qstat_game_players_max = 4,
24 .qstat_game_players = 5,
25 .qstat_map_field = 3,
26 .qstat_game_field = 2,
27 .qstat_ping_field = 5,
28 };
29 return tmp;
30}
diff --git a/plugins/check_hpjd.c b/plugins/check_hpjd.c
index c34bb082..62417fd6 100644
--- a/plugins/check_hpjd.c
+++ b/plugins/check_hpjd.c
@@ -1,47 +1,46 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_hpjd plugin 3 * Monitoring check_hpjd plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_hpjd plugin 10 * This file contains the check_hpjd plugin
11* 11 *
12* This plugin tests the STATUS of an HP printer with a JetDirect card. 12 * This plugin tests the STATUS of an HP printer with a JetDirect card.
13* Net-SNMP must be installed on the computer running the plugin. 13 * Net-SNMP must be installed on the computer running the plugin.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_hpjd"; 32const char *progname = "check_hpjd";
33const char *copyright = "2000-2007"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "popen.h" 37#include "popen.h"
38#include "utils.h" 38#include "utils.h"
39#include "netutils.h" 39#include "netutils.h"
40#include "states.h"
41#include "check_hpjd.d/config.h"
40 42
41#define DEFAULT_COMMUNITY "public" 43#define DEFAULT_COMMUNITY "public"
42#define DEFAULT_PORT "161"
43
44const char *option_summary = "-H host [-C community]\n";
45 44
46#define HPJD_LINE_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.1" 45#define HPJD_LINE_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.1"
47#define HPJD_PAPER_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.2" 46#define HPJD_PAPER_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.2"
@@ -56,185 +55,161 @@ const char *option_summary = "-H host [-C community]\n";
56#define HPJD_GD_PAPER_OUTPUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.19" 55#define HPJD_GD_PAPER_OUTPUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.19"
57#define HPJD_GD_STATUS_DISPLAY ".1.3.6.1.4.1.11.2.3.9.1.1.3" 56#define HPJD_GD_STATUS_DISPLAY ".1.3.6.1.4.1.11.2.3.9.1.1.3"
58 57
59#define ONLINE 0 58#define ONLINE 0
60#define OFFLINE 1 59#define OFFLINE 1
61
62int process_arguments (int, char **);
63int validate_arguments (void);
64void print_help (void);
65void print_usage (void);
66 60
67char *community = NULL; 61typedef struct {
68char *address = NULL; 62 int errorcode;
69unsigned int port = 0; 63 check_hpjd_config config;
70int check_paper_out = 1; 64} check_hpjd_config_wrapper;
65static check_hpjd_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
66static void print_help(void);
67void print_usage(void);
71 68
72int 69int main(int argc, char **argv) {
73main (int argc, char **argv) 70 setlocale(LC_ALL, "");
74{ 71 bindtextdomain(PACKAGE, LOCALEDIR);
75 char command_line[1024]; 72 textdomain(PACKAGE);
76 int result = STATE_UNKNOWN;
77 int line;
78 char input_buffer[MAX_INPUT_BUFFER];
79 char query_string[512];
80 char *errmsg;
81 char *temp_buffer;
82 int line_status = ONLINE;
83 int paper_status = 0;
84 int intervention_required = 0;
85 int peripheral_error = 0;
86 int paper_jam = 0;
87 int paper_out = 0;
88 int toner_low = 0;
89 int page_punt = 0;
90 int memory_out = 0;
91 int door_open = 0;
92 int paper_output = 0;
93 char display_message[MAX_INPUT_BUFFER];
94 73
95 errmsg = malloc(MAX_INPUT_BUFFER); 74 /* Parse extra opts if any */
75 argv = np_extra_opts(&argc, argv, progname);
96 76
97 setlocale (LC_ALL, ""); 77 check_hpjd_config_wrapper tmp_config = process_arguments(argc, argv);
98 bindtextdomain (PACKAGE, LOCALEDIR);
99 textdomain (PACKAGE);
100 78
101 /* Parse extra opts if any */ 79 if (tmp_config.errorcode == ERROR) {
102 argv=np_extra_opts (&argc, argv, progname); 80 usage4(_("Could not parse arguments"));
81 }
103 82
104 if (process_arguments (argc, argv) == ERROR) 83 const check_hpjd_config config = tmp_config.config;
105 usage4 (_("Could not parse arguments"));
106 84
85 char query_string[512];
107 /* removed ' 2>1' at end of command 10/27/1999 - EG */ 86 /* removed ' 2>1' at end of command 10/27/1999 - EG */
108 /* create the query string */ 87 /* create the query string */
109 sprintf 88 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,
110 (query_string, 89 HPJD_INTERVENTION_REQUIRED, HPJD_GD_PERIPHERAL_ERROR, HPJD_GD_PAPER_JAM, HPJD_GD_PAPER_OUT, HPJD_GD_TONER_LOW,
111 "%s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0", 90 HPJD_GD_PAGE_PUNT, HPJD_GD_MEMORY_OUT, HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
112 HPJD_LINE_STATUS,
113 HPJD_PAPER_STATUS,
114 HPJD_INTERVENTION_REQUIRED,
115 HPJD_GD_PERIPHERAL_ERROR,
116 HPJD_GD_PAPER_JAM,
117 HPJD_GD_PAPER_OUT,
118 HPJD_GD_TONER_LOW,
119 HPJD_GD_PAGE_PUNT,
120 HPJD_GD_MEMORY_OUT,
121 HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
122 91
123 /* get the command to run */ 92 /* get the command to run */
124 sprintf (command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", 93 char command_line[1024];
125 PATH_TO_SNMPGET, 94 sprintf(command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", PATH_TO_SNMPGET, config.community, config.address, config.port, query_string);
126 community,
127 address,
128 port,
129 query_string);
130 95
131 /* run the command */ 96 /* run the command */
132 child_process = spopen (command_line); 97 child_process = spopen(command_line);
133 if (child_process == NULL) { 98 if (child_process == NULL) {
134 printf (_("Could not open pipe: %s\n"), command_line); 99 printf(_("Could not open pipe: %s\n"), command_line);
135 return STATE_UNKNOWN; 100 return STATE_UNKNOWN;
136 } 101 }
137 102
138 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 103 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
139 if (child_stderr == NULL) { 104 if (child_stderr == NULL) {
140 printf (_("Could not open stderr for %s\n"), command_line); 105 printf(_("Could not open stderr for %s\n"), command_line);
141 } 106 }
142 107
143 result = STATE_OK; 108 mp_state_enum result = STATE_OK;
144 109
145 line = 0; 110 int line_status = ONLINE;
146 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 111 int paper_status = 0;
112 int intervention_required = 0;
113 int peripheral_error = 0;
114 int paper_jam = 0;
115 int paper_out = 0;
116 int toner_low = 0;
117 int page_punt = 0;
118 int memory_out = 0;
119 int door_open = 0;
120 int paper_output = 0;
121 char display_message[MAX_INPUT_BUFFER];
122
123 char input_buffer[MAX_INPUT_BUFFER];
124 char *errmsg = malloc(MAX_INPUT_BUFFER);
125 int line = 0;
147 126
127 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
148 /* strip the newline character from the end of the input */ 128 /* strip the newline character from the end of the input */
149 if (input_buffer[strlen (input_buffer) - 1] == '\n') 129 if (input_buffer[strlen(input_buffer) - 1] == '\n') {
150 input_buffer[strlen (input_buffer) - 1] = 0; 130 input_buffer[strlen(input_buffer) - 1] = 0;
131 }
151 132
152 line++; 133 line++;
153 134
154 temp_buffer = strtok (input_buffer, "="); 135 char *temp_buffer = strtok(input_buffer, "=");
155 temp_buffer = strtok (NULL, "="); 136 temp_buffer = strtok(NULL, "=");
156 137
157 if (temp_buffer == NULL && line < 13) { 138 if (temp_buffer == NULL && line < 13) {
158 139 result = STATE_UNKNOWN;
159 result = STATE_UNKNOWN; 140 strcpy(errmsg, input_buffer);
160 strcpy (errmsg, input_buffer);
161
162 } else { 141 } else {
163
164 switch (line) { 142 switch (line) {
165 143 case 1: /* 1st line should contain the line status */
166 case 1: /* 1st line should contain the line status */ 144 line_status = atoi(temp_buffer);
167 line_status = atoi (temp_buffer);
168 break; 145 break;
169 case 2: /* 2nd line should contain the paper status */ 146 case 2: /* 2nd line should contain the paper status */
170 paper_status = atoi (temp_buffer); 147 paper_status = atoi(temp_buffer);
171 break; 148 break;
172 case 3: /* 3rd line should be intervention required */ 149 case 3: /* 3rd line should be intervention required */
173 intervention_required = atoi (temp_buffer); 150 intervention_required = atoi(temp_buffer);
174 break; 151 break;
175 case 4: /* 4th line should be peripheral error */ 152 case 4: /* 4th line should be peripheral error */
176 peripheral_error = atoi (temp_buffer); 153 peripheral_error = atoi(temp_buffer);
177 break; 154 break;
178 case 5: /* 5th line should contain the paper jam status */ 155 case 5: /* 5th line should contain the paper jam status */
179 paper_jam = atoi (temp_buffer); 156 paper_jam = atoi(temp_buffer);
180 break; 157 break;
181 case 6: /* 6th line should contain the paper out status */ 158 case 6: /* 6th line should contain the paper out status */
182 paper_out = atoi (temp_buffer); 159 paper_out = atoi(temp_buffer);
183 break; 160 break;
184 case 7: /* 7th line should contain the toner low status */ 161 case 7: /* 7th line should contain the toner low status */
185 toner_low = atoi (temp_buffer); 162 toner_low = atoi(temp_buffer);
186 break; 163 break;
187 case 8: /* did data come too slow for engine */ 164 case 8: /* did data come too slow for engine */
188 page_punt = atoi (temp_buffer); 165 page_punt = atoi(temp_buffer);
189 break; 166 break;
190 case 9: /* did we run out of memory */ 167 case 9: /* did we run out of memory */
191 memory_out = atoi (temp_buffer); 168 memory_out = atoi(temp_buffer);
192 break; 169 break;
193 case 10: /* is there a door open */ 170 case 10: /* is there a door open */
194 door_open = atoi (temp_buffer); 171 door_open = atoi(temp_buffer);
195 break; 172 break;
196 case 11: /* is output tray full */ 173 case 11: /* is output tray full */
197 paper_output = atoi (temp_buffer); 174 paper_output = atoi(temp_buffer);
198 break; 175 break;
199 case 12: /* display panel message */ 176 case 12: /* display panel message */
200 strcpy (display_message, temp_buffer + 1); 177 strcpy(display_message, temp_buffer + 1);
201 break; 178 break;
202 default: /* fold multiline message */ 179 default: /* fold multiline message */
203 strncat (display_message, input_buffer, 180 strncat(display_message, input_buffer, sizeof(display_message) - strlen(display_message) - 1);
204 sizeof (display_message) - strlen (display_message) - 1);
205 } 181 }
206
207 } 182 }
208 183
209 /* break out of the read loop if we encounter an error */ 184 /* break out of the read loop if we encounter an error */
210 if (result != STATE_OK) 185 if (result != STATE_OK) {
211 break; 186 break;
187 }
212 } 188 }
213 189
214 /* WARNING if output found on stderr */ 190 /* WARNING if output found on stderr */
215 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 191 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
216 result = max_state (result, STATE_WARNING); 192 result = max_state(result, STATE_WARNING);
217 /* remove CRLF */ 193 /* remove CRLF */
218 if (input_buffer[strlen (input_buffer) - 1] == '\n') 194 if (input_buffer[strlen(input_buffer) - 1] == '\n') {
219 input_buffer[strlen (input_buffer) - 1] = 0; 195 input_buffer[strlen(input_buffer) - 1] = 0;
220 sprintf (errmsg, "%s", input_buffer ); 196 }
221 197 sprintf(errmsg, "%s", input_buffer);
222 } 198 }
223 199
224 /* close stderr */ 200 /* close stderr */
225 (void) fclose (child_stderr); 201 (void)fclose(child_stderr);
226 202
227 /* close the pipe */ 203 /* close the pipe */
228 if (spclose (child_process)) 204 if (spclose(child_process)) {
229 result = max_state (result, STATE_WARNING); 205 result = max_state(result, STATE_WARNING);
206 }
230 207
231 /* if there wasn't any output, display an error */ 208 /* if there wasn't any output, display an error */
232 if (line == 0) { 209 if (line == 0) {
233
234 /* might not be the problem, but most likely is. */ 210 /* might not be the problem, but most likely is. */
235 result = STATE_UNKNOWN ; 211 result = STATE_UNKNOWN;
236 xasprintf (&errmsg, "%s : Timeout from host %s\n", errmsg, address ); 212 xasprintf(&errmsg, "%s : Timeout from host %s\n", errmsg, config.address);
237
238 } 213 }
239 214
240 /* if we had no read errors, check the printer status results... */ 215 /* if we had no read errors, check the printer status results... */
@@ -242,201 +217,171 @@ main (int argc, char **argv)
242 217
243 if (paper_jam) { 218 if (paper_jam) {
244 result = STATE_WARNING; 219 result = STATE_WARNING;
245 strcpy (errmsg, _("Paper Jam")); 220 strcpy(errmsg, _("Paper Jam"));
246 } 221 } else if (paper_out) {
247 else if (paper_out) { 222 if (config.check_paper_out) {
248 if (check_paper_out)
249 result = STATE_WARNING; 223 result = STATE_WARNING;
250 strcpy (errmsg, _("Out of Paper")); 224 }
251 } 225 strcpy(errmsg, _("Out of Paper"));
252 else if (line_status == OFFLINE) { 226 } else if (line_status == OFFLINE) {
253 if (strcmp (errmsg, "POWERSAVE ON") != 0) { 227 if (strcmp(errmsg, "POWERSAVE ON") != 0) {
254 result = STATE_WARNING; 228 result = STATE_WARNING;
255 strcpy (errmsg, _("Printer Offline")); 229 strcpy(errmsg, _("Printer Offline"));
256 } 230 }
257 } 231 } else if (peripheral_error) {
258 else if (peripheral_error) {
259 result = STATE_WARNING; 232 result = STATE_WARNING;
260 strcpy (errmsg, _("Peripheral Error")); 233 strcpy(errmsg, _("Peripheral Error"));
261 } 234 } else if (intervention_required) {
262 else if (intervention_required) {
263 result = STATE_WARNING; 235 result = STATE_WARNING;
264 strcpy (errmsg, _("Intervention Required")); 236 strcpy(errmsg, _("Intervention Required"));
265 } 237 } else if (toner_low) {
266 else if (toner_low) {
267 result = STATE_WARNING; 238 result = STATE_WARNING;
268 strcpy (errmsg, _("Toner Low")); 239 strcpy(errmsg, _("Toner Low"));
269 } 240 } else if (memory_out) {
270 else if (memory_out) {
271 result = STATE_WARNING; 241 result = STATE_WARNING;
272 strcpy (errmsg, _("Insufficient Memory")); 242 strcpy(errmsg, _("Insufficient Memory"));
273 } 243 } else if (door_open) {
274 else if (door_open) {
275 result = STATE_WARNING; 244 result = STATE_WARNING;
276 strcpy (errmsg, _("A Door is Open")); 245 strcpy(errmsg, _("A Door is Open"));
277 } 246 } else if (paper_output) {
278 else if (paper_output) {
279 result = STATE_WARNING; 247 result = STATE_WARNING;
280 strcpy (errmsg, _("Output Tray is Full")); 248 strcpy(errmsg, _("Output Tray is Full"));
281 } 249 } else if (page_punt) {
282 else if (page_punt) {
283 result = STATE_WARNING; 250 result = STATE_WARNING;
284 strcpy (errmsg, _("Data too Slow for Engine")); 251 strcpy(errmsg, _("Data too Slow for Engine"));
285 } 252 } else if (paper_status) {
286 else if (paper_status) {
287 result = STATE_WARNING; 253 result = STATE_WARNING;
288 strcpy (errmsg, _("Unknown Paper Error")); 254 strcpy(errmsg, _("Unknown Paper Error"));
289 } 255 }
290 } 256 }
291 257
292 if (result == STATE_OK) 258 if (result == STATE_OK) {
293 printf (_("Printer ok - (%s)\n"), display_message); 259 printf(_("Printer ok - (%s)\n"), display_message);
294 260 } else if (result == STATE_UNKNOWN) {
295 else if (result == STATE_UNKNOWN) { 261 printf("%s\n", errmsg);
296
297 printf ("%s\n", errmsg);
298
299 /* if printer could not be reached, escalate to critical */ 262 /* if printer could not be reached, escalate to critical */
300 if (strstr (errmsg, "Timeout")) 263 if (strstr(errmsg, "Timeout")) {
301 result = STATE_CRITICAL; 264 result = STATE_CRITICAL;
265 }
266 } else if (result == STATE_WARNING) {
267 printf("%s (%s)\n", errmsg, display_message);
302 } 268 }
303 269
304 else if (result == STATE_WARNING) 270 exit(result);
305 printf ("%s (%s)\n", errmsg, display_message);
306
307 return result;
308} 271}
309 272
310
311/* process command-line arguments */ 273/* process command-line arguments */
312int 274check_hpjd_config_wrapper process_arguments(int argc, char **argv) {
313process_arguments (int argc, char **argv) 275 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
314{ 276 {"community", required_argument, 0, 'C'},
315 int c; 277 /* {"critical", required_argument,0,'c'}, */
316 278 /* {"warning", required_argument,0,'w'}, */
317 int option = 0; 279 {"port", required_argument, 0, 'p'},
318 static struct option longopts[] = { 280 {"version", no_argument, 0, 'V'},
319 {"hostname", required_argument, 0, 'H'}, 281 {"help", no_argument, 0, 'h'},
320 {"community", required_argument, 0, 'C'}, 282 {0, 0, 0, 0}};
321/* {"critical", required_argument,0,'c'}, */ 283
322/* {"warning", required_argument,0,'w'}, */ 284 check_hpjd_config_wrapper result = {
323 {"port", required_argument,0,'p'}, 285 .errorcode = OK,
324 {"version", no_argument, 0, 'V'}, 286 .config = check_hpjd_config_init(),
325 {"help", no_argument, 0, 'h'},
326 {0, 0, 0, 0}
327 }; 287 };
328 288
329 if (argc < 2) 289 if (argc < 2) {
330 return ERROR; 290 result.errorcode = ERROR;
331 291 return result;
292 }
332 293
333 while (1) { 294 int option = 0;
334 c = getopt_long (argc, argv, "+hVH:C:p:D", longopts, &option); 295 while (true) {
296 int option_index = getopt_long(argc, argv, "+hVH:C:p:D", longopts, &option);
335 297
336 if (c == -1 || c == EOF || c == 1) 298 if (option_index == -1 || option_index == EOF || option_index == 1) {
337 break; 299 break;
300 }
338 301
339 switch (c) { 302 switch (option_index) {
340 case 'H': /* hostname */ 303 case 'H': /* hostname */
341 if (is_host (optarg)) { 304 if (is_host(optarg)) {
342 address = strscpy(address, optarg) ; 305 result.config.address = strscpy(result.config.address, optarg);
343 } 306 } else {
344 else { 307 usage2(_("Invalid hostname/address"), optarg);
345 usage2 (_("Invalid hostname/address"), optarg);
346 } 308 }
347 break; 309 break;
348 case 'C': /* community */ 310 case 'C': /* community */
349 community = strscpy (community, optarg); 311 result.config.community = strscpy(result.config.community, optarg);
350 break; 312 break;
351 case 'p': 313 case 'p':
352 if (!is_intpos(optarg)) 314 if (!is_intpos(optarg)) {
353 usage2 (_("Port must be a positive short integer"), optarg); 315 usage2(_("Port must be a positive short integer"), optarg);
354 else 316 } else {
355 port = atoi(optarg); 317 result.config.port = atoi(optarg);
318 }
356 break; 319 break;
357 case 'D': /* disable paper out check*/ 320 case 'D': /* disable paper out check*/
358 check_paper_out = 0; 321 result.config.check_paper_out = false;
359 break; 322 break;
360 case 'V': /* version */ 323 case 'V': /* version */
361 print_revision (progname, NP_VERSION); 324 print_revision(progname, NP_VERSION);
362 exit (STATE_UNKNOWN); 325 exit(STATE_UNKNOWN);
363 case 'h': /* help */ 326 case 'h': /* help */
364 print_help (); 327 print_help();
365 exit (STATE_UNKNOWN); 328 exit(STATE_UNKNOWN);
366 case '?': /* help */ 329 case '?': /* help */
367 usage5 (); 330 usage5();
368 } 331 }
369 } 332 }
370 333
371 c = optind; 334 int c = optind;
372 if (address == NULL) { 335 if (result.config.address == NULL) {
373 if (is_host (argv[c])) { 336 if (is_host(argv[c])) {
374 address = argv[c++]; 337 result.config.address = argv[c++];
375 } 338 } else {
376 else { 339 usage2(_("Invalid hostname/address"), argv[c]);
377 usage2 (_("Invalid hostname/address"), argv[c]);
378 } 340 }
379 } 341 }
380 342
381 if (community == NULL) { 343 if (result.config.community == NULL) {
382 if (argv[c] != NULL ) 344 if (argv[c] != NULL) {
383 community = argv[c]; 345 result.config.community = argv[c];
384 else 346 } else {
385 community = strdup (DEFAULT_COMMUNITY); 347 result.config.community = strdup(DEFAULT_COMMUNITY);
386 } 348 }
387
388 if (port == 0) {
389 port = atoi(DEFAULT_PORT);
390 } 349 }
391 350
392 return validate_arguments (); 351 return result;
393}
394
395
396int
397validate_arguments (void)
398{
399 return OK;
400} 352}
401 353
354void print_help(void) {
355 print_revision(progname, NP_VERSION);
402 356
403void 357 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
404print_help (void) 358 printf(COPYRIGHT, copyright, email);
405{
406 print_revision (progname, NP_VERSION);
407
408 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
409 printf (COPYRIGHT, copyright, email);
410 359
411 printf ("%s\n", _("This plugin tests the STATUS of an HP printer with a JetDirect card.")); 360 printf("%s\n", _("This plugin tests the STATUS of an HP printer with a JetDirect card."));
412 printf ("%s\n", _("Net-snmp must be installed on the computer running the plugin.")); 361 printf("%s\n", _("Net-snmp must be installed on the computer running the plugin."));
413 362
414 printf ("\n\n"); 363 printf("\n\n");
415 364
416 print_usage (); 365 print_usage();
417 366
418 printf (UT_HELP_VRSN); 367 printf(UT_HELP_VRSN);
419 printf (UT_EXTRA_OPTS); 368 printf(UT_EXTRA_OPTS);
420 369
421 printf (" %s\n", "-C, --community=STRING"); 370 printf(" %s\n", "-C, --community=STRING");
422 printf (" %s", _("The SNMP community name ")); 371 printf(" %s", _("The SNMP community name "));
423 printf (_("(default=%s)"), DEFAULT_COMMUNITY); 372 printf(_("(default=%s)"), DEFAULT_COMMUNITY);
424 printf ("\n"); 373 printf("\n");
425 printf (" %s\n", "-p, --port=STRING"); 374 printf(" %s\n", "-p, --port=STRING");
426 printf (" %s", _("Specify the port to check ")); 375 printf(" %s", _("Specify the port to check "));
427 printf (_("(default=%s)"), DEFAULT_PORT); 376 printf(_("(default=%s)"), DEFAULT_PORT);
428 printf ("\n"); 377 printf("\n");
429 printf (" %s\n", "-D"); 378 printf(" %s\n", "-D");
430 printf (" %s", _("Disable paper check ")); 379 printf(" %s", _("Disable paper check "));
431 380
432 printf (UT_SUPPORT); 381 printf(UT_SUPPORT);
433} 382}
434 383
435 384void print_usage(void) {
436 385 printf("%s\n", _("Usage:"));
437void 386 printf("%s -H host [-C community] [-p port] [-D]\n", progname);
438print_usage (void)
439{
440 printf ("%s\n", _("Usage:"));
441 printf ("%s -H host [-C community] [-p port] [-D]\n", progname);
442} 387}
diff --git a/plugins/check_hpjd.d/config.h b/plugins/check_hpjd.d/config.h
new file mode 100644
index 00000000..e36b7972
--- /dev/null
+++ b/plugins/check_hpjd.d/config.h
@@ -0,0 +1,25 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7#define DEFAULT_PORT "161"
8
9typedef struct {
10 char *address;
11 char *community;
12 unsigned int port;
13 bool check_paper_out;
14
15} check_hpjd_config;
16
17check_hpjd_config check_hpjd_config_init() {
18 check_hpjd_config tmp = {
19 .address = NULL,
20 .community = NULL,
21 .port = (unsigned int)atoi(DEFAULT_PORT),
22 .check_paper_out = true,
23 };
24 return tmp;
25}
diff --git a/plugins/check_http.c b/plugins/check_http.c
index cdf768c9..8e0c15ec 100644
--- a/plugins/check_http.c
+++ b/plugins/check_http.c
@@ -3,7 +3,7 @@
3* Monitoring check_http plugin 3* Monitoring check_http plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 1999-2013 Monitoring Plugins Development Team 6* Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
@@ -32,7 +32,7 @@
32*****************************************************************************/ 32*****************************************************************************/
33 33
34const char *progname = "check_http"; 34const char *progname = "check_http";
35const char *copyright = "1999-2022"; 35const char *copyright = "1999-2024";
36const char *email = "devel@monitoring-plugins.org"; 36const char *email = "devel@monitoring-plugins.org";
37 37
38// Do NOT sort those headers, it will break the build 38// Do NOT sort those headers, it will break the build
@@ -1724,6 +1724,16 @@ print_help (void)
1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on")); 1724 printf ("%s\n", _("strings and regular expressions, check connection times, and report on"));
1725 printf ("%s\n", _("certificate expiration times.")); 1725 printf ("%s\n", _("certificate expiration times."));
1726 1726
1727 printf ("\n");
1728 printf ("%s\n", _("ATTENTION!"));
1729 printf ("\n");
1730 printf ("%s\n", _("THIS PLUGIN IS DEPRECATED. The functionality was reimplemented by the"));
1731 printf ("%s\n", _("check_curl plugin, which can be used as a drop-in replacement. You should"));
1732 printf ("%s\n", _("migrate your checks over to check_curl, because check_http is going to be"));
1733 printf ("%s\n", _("removed sooner than later. Just replace check_http with check_curl in your"));
1734 printf ("%s\n", _("check command definitions."));
1735 printf ("%s\n", _("Report issues to: https://github.com/monitoring-plugins/monitoring-plugins/issues"));
1736
1727 printf ("\n\n"); 1737 printf ("\n\n");
1728 1738
1729 print_usage (); 1739 print_usage ();
@@ -1805,7 +1815,7 @@ print_help (void)
1805 printf (" %s\n", "--invert-regex"); 1815 printf (" %s\n", "--invert-regex");
1806 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)")); 1816 printf (" %s\n", _("Return STATE if found, OK if not (STATE is CRITICAL, per default)"));
1807 printf (" %s\n", _("can be changed with --state--regex)")); 1817 printf (" %s\n", _("can be changed with --state--regex)"));
1808 printf (" %s\n", "--regex-state=STATE"); 1818 printf (" %s\n", "--state-regex=STATE");
1809 printf (" %s\n", _("Return STATE if regex is found, OK if not\n")); 1819 printf (" %s\n", _("Return STATE if regex is found, OK if not\n"));
1810 1820
1811 printf (" %s\n", "-a, --authorization=AUTH_PAIR"); 1821 printf (" %s\n", "-a, --authorization=AUTH_PAIR");
diff --git a/plugins/check_ide_smart.c b/plugins/check_ide_smart.c
index 3872e341..16fe3d01 100644
--- a/plugins/check_ide_smart.c
+++ b/plugins/check_ide_smart.c
@@ -1,240 +1,211 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ide_smart plugin 3 * Monitoring check_ide_smart plugin
4* ide-smart 1.3 - IDE S.M.A.R.T. checking tool 4 * ide-smart 1.3 - IDE S.M.A.R.T. checking tool
5* 5 *
6* License: GPL 6 * License: GPL
7* Copyright (C) 1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org> 7 * Copyright (C) 1998-1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>
8* 1998 Gadi Oxman <gadio@netvision.net.il> 8 * 1998 Gadi Oxman <gadio@netvision.net.il>
9* Copyright (c) 2000 Robert Dale <rdale@digital-mission.com> 9 * Copyright (c) 2000 Robert Dale <rdale@digital-mission.com>
10* Copyright (c) 2000-2007 Monitoring Plugins Development Team 10 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
11* 11 *
12* Description: 12 * Description:
13* 13 *
14* This file contains the check_ide_smart plugin 14 * This file contains the check_ide_smart plugin
15* 15 *
16* This plugin checks a local hard drive with the (Linux specific) SMART 16 * This plugin checks a local hard drive with the (Linux specific) SMART
17* interface 17 * interface
18* 18 *
19* 19 *
20* This program is free software: you can redistribute it and/or modify 20 * This program is free software: you can redistribute it and/or modify
21* it under the terms of the GNU General Public License as published by 21 * it under the terms of the GNU General Public License as published by
22* the Free Software Foundation, either version 3 of the License, or 22 * the Free Software Foundation, either version 3 of the License, or
23* (at your option) any later version. 23 * (at your option) any later version.
24* 24 *
25* This program is distributed in the hope that it will be useful, 25 * This program is distributed in the hope that it will be useful,
26* but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28* GNU General Public License for more details. 28 * GNU General Public License for more details.
29* 29 *
30* You should have received a copy of the GNU General Public License 30 * You should have received a copy of the GNU General Public License
31* along with this program. If not, see <http://www.gnu.org/licenses/>. 31 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32* 32 *
33* 33 *
34*****************************************************************************/ 34 *****************************************************************************/
35 35
36const char *progname = "check_ide_smart"; 36const char *progname = "check_ide_smart";
37const char *copyright = "1998-2007"; 37const char *copyright = "1998-2024";
38const char *email = "devel@monitoring-plugins.org"; 38const char *email = "devel@monitoring-plugins.org";
39 39
40#include "common.h" 40#include "common.h"
41#include "utils.h" 41#include "utils.h"
42 42
43void print_help (void); 43static void print_help(void);
44void print_usage (void); 44void print_usage(void);
45 45
46#include <sys/stat.h> 46#include <sys/stat.h>
47#include <sys/ioctl.h> 47#include <sys/ioctl.h>
48#include <fcntl.h> 48#include <fcntl.h>
49#ifdef __linux__ 49#ifdef __linux__
50#include <linux/hdreg.h> 50# include <linux/hdreg.h>
51#include <linux/types.h> 51# include <linux/types.h>
52 52
53#define OPEN_MODE O_RDONLY 53# define OPEN_MODE O_RDONLY
54#endif /* __linux__ */ 54#endif /* __linux__ */
55#ifdef __NetBSD__ 55#ifdef __NetBSD__
56#include <sys/device.h> 56# include <sys/device.h>
57#include <sys/param.h> 57# include <sys/param.h>
58#include <sys/sysctl.h> 58# include <sys/sysctl.h>
59#include <sys/videoio.h> /* for __u8 and friends */ 59# include <sys/scsiio.h>
60#include <sys/scsiio.h> 60# include <sys/ataio.h>
61#include <sys/ataio.h> 61# include <dev/ata/atareg.h>
62#include <dev/ata/atareg.h> 62# include <dev/ic/wdcreg.h>
63#include <dev/ic/wdcreg.h> 63
64 64# define SMART_ENABLE WDSM_ENABLE_OPS
65#define SMART_ENABLE WDSM_ENABLE_OPS 65# define SMART_DISABLE WDSM_DISABLE_OPS
66#define SMART_DISABLE WDSM_DISABLE_OPS 66# define SMART_IMMEDIATE_OFFLINE WDSM_EXEC_OFFL_IMM
67#define SMART_IMMEDIATE_OFFLINE WDSM_EXEC_OFFL_IMM 67# define SMART_AUTO_OFFLINE 0xdb /* undefined in NetBSD headers */
68#define SMART_AUTO_OFFLINE 0xdb /* undefined in NetBSD headers */ 68
69 69# define OPEN_MODE O_RDWR
70#define OPEN_MODE O_RDWR
71#endif /* __NetBSD__ */ 70#endif /* __NetBSD__ */
72#include <errno.h> 71#include <errno.h>
73 72
74#define NR_ATTRIBUTES 30 73#define NR_ATTRIBUTES 30
75 74
76#define PREFAILURE 2 75#define PREFAILURE 2
77#define ADVISORY 1 76#define ADVISORY 1
78#define OPERATIONAL 0 77#define OPERATIONAL 0
79#define UNKNOWN -1 78#define UNKNOWN -1
80 79
81typedef struct threshold_s 80typedef struct threshold_s {
82{ 81 uint8_t id;
83 __u8 id; 82 uint8_t threshold;
84 __u8 threshold; 83 uint8_t reserved[10];
85 __u8 reserved[10]; 84} __attribute__((packed)) threshold_t;
86}
87__attribute__ ((packed)) threshold_t;
88 85
89typedef struct thresholds_s 86typedef struct thresholds_s {
90{ 87 uint16_t revision;
91 __u16 revision;
92 threshold_t thresholds[NR_ATTRIBUTES]; 88 threshold_t thresholds[NR_ATTRIBUTES];
93 __u8 reserved[18]; 89 uint8_t reserved[18];
94 __u8 vendor[131]; 90 uint8_t vendor[131];
95 __u8 checksum; 91 uint8_t checksum;
96} 92} __attribute__((packed)) thresholds_t;
97__attribute__ ((packed)) thresholds_t; 93
98 94typedef struct value_s {
99typedef struct value_s 95 uint8_t id;
100{ 96 uint16_t status;
101 __u8 id; 97 uint8_t value;
102 __u16 status; 98 uint8_t vendor[8];
103 __u8 value; 99} __attribute__((packed)) value_t;
104 __u8 vendor[8]; 100
105} 101typedef struct values_s {
106__attribute__ ((packed)) value_t; 102 uint16_t revision;
107
108typedef struct values_s
109{
110 __u16 revision;
111 value_t values[NR_ATTRIBUTES]; 103 value_t values[NR_ATTRIBUTES];
112 __u8 offline_status; 104 uint8_t offline_status;
113 __u8 vendor1; 105 uint8_t vendor1;
114 __u16 offline_timeout; 106 uint16_t offline_timeout;
115 __u8 vendor2; 107 uint8_t vendor2;
116 __u8 offline_capability; 108 uint8_t offline_capability;
117 __u16 smart_capability; 109 uint16_t smart_capability;
118 __u8 reserved[16]; 110 uint8_t reserved[16];
119 __u8 vendor[125]; 111 uint8_t vendor[125];
120 __u8 checksum; 112 uint8_t checksum;
121} 113} __attribute__((packed)) values_t;
122__attribute__ ((packed)) values_t; 114
123 115static struct {
124struct 116 uint8_t value;
125{
126 __u8 value;
127 char *text; 117 char *text;
128} 118} offline_status_text[] = {{0x00, "NeverStarted"}, {0x02, "Completed"}, {0x04, "Suspended"}, {0x05, "Aborted"}, {0x06, "Failed"}, {0, 0}};
129 119
130offline_status_text[] = 120static struct {
131 { 121 uint8_t value;
132 {0x00, "NeverStarted"},
133 {0x02, "Completed"},
134 {0x04, "Suspended"},
135 {0x05, "Aborted"},
136 {0x06, "Failed"},
137 {0, 0}
138 };
139
140struct
141{
142 __u8 value;
143 char *text; 122 char *text;
144} 123} smart_command[] = {{SMART_ENABLE, "SMART_ENABLE"},
145 124 {SMART_DISABLE, "SMART_DISABLE"},
146smart_command[] = 125 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"},
147 { 126 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"}};
148 {SMART_ENABLE, "SMART_ENABLE"}, 127
149 {SMART_DISABLE, "SMART_DISABLE"}, 128/* Index to smart_command table, keep in order */
150 {SMART_IMMEDIATE_OFFLINE, "SMART_IMMEDIATE_OFFLINE"}, 129enum SmartCommand {
151 {SMART_AUTO_OFFLINE, "SMART_AUTO_OFFLINE"} 130 SMART_CMD_ENABLE,
152 }; 131 SMART_CMD_DISABLE,
153 132 SMART_CMD_IMMEDIATE_OFFLINE,
154 133 SMART_CMD_AUTO_OFFLINE
155/* Index to smart_command table, keep in order */ 134};
156enum SmartCommand 135
157 { SMART_CMD_ENABLE, 136static char *get_offline_text(int);
158 SMART_CMD_DISABLE, 137static int smart_read_values(int, values_t *);
159 SMART_CMD_IMMEDIATE_OFFLINE, 138static int nagios(values_t *, thresholds_t *);
160 SMART_CMD_AUTO_OFFLINE 139static void print_value(value_t *, threshold_t *);
161 }; 140static void print_values(values_t *, thresholds_t *);
162 141static int smart_cmd_simple(int, enum SmartCommand, uint8_t, bool);
163char *get_offline_text (int); 142static int smart_read_thresholds(int, thresholds_t *);
164int smart_read_values (int, values_t *); 143static bool verbose = false;
165int nagios (values_t *, thresholds_t *); 144
166void print_value (value_t *, threshold_t *); 145int main(int argc, char *argv[]) {
167void print_values (values_t *, thresholds_t *);
168int smart_cmd_simple (int, enum SmartCommand, __u8, bool);
169int smart_read_thresholds (int, thresholds_t *);
170bool verbose = false;
171
172int
173main (int argc, char *argv[])
174{
175 char *device = NULL; 146 char *device = NULL;
176 int o, longindex; 147 int o;
148 int longindex;
177 int retval = 0; 149 int retval = 0;
178 150
179 thresholds_t thresholds; 151 thresholds_t thresholds;
180 values_t values; 152 values_t values;
181 int fd; 153 int fd;
182 154
183 static struct option longopts[] = { 155 static struct option longopts[] = {{"device", required_argument, 0, 'd'},
184 {"device", required_argument, 0, 'd'}, 156 {"immediate", no_argument, 0, 'i'},
185 {"immediate", no_argument, 0, 'i'}, 157 {"quiet-check", no_argument, 0, 'q'},
186 {"quiet-check", no_argument, 0, 'q'}, 158 {"auto-on", no_argument, 0, '1'},
187 {"auto-on", no_argument, 0, '1'}, 159 {"auto-off", no_argument, 0, '0'},
188 {"auto-off", no_argument, 0, '0'}, 160 {"nagios", no_argument, 0, 'n'}, /* DEPRECATED, but we still accept it */
189 {"nagios", no_argument, 0, 'n'}, /* DEPRECATED, but we still accept it */ 161 {"help", no_argument, 0, 'h'},
190 {"help", no_argument, 0, 'h'}, 162 {"version", no_argument, 0, 'V'},
191 {"version", no_argument, 0, 'V'}, 163 {0, 0, 0, 0}};
192 {0, 0, 0, 0}
193 };
194 164
195 /* Parse extra opts if any */ 165 /* Parse extra opts if any */
196 argv=np_extra_opts (&argc, argv, progname); 166 argv = np_extra_opts(&argc, argv, progname);
197 167
198 setlocale (LC_ALL, ""); 168 setlocale(LC_ALL, "");
199 bindtextdomain (PACKAGE, LOCALEDIR); 169 bindtextdomain(PACKAGE, LOCALEDIR);
200 textdomain (PACKAGE); 170 textdomain(PACKAGE);
201 171
202 while (true) { 172 while (true) {
203
204 o = getopt_long (argc, argv, "+d:iq10nhVv", longopts, &longindex);
205 173
206 if (o == -1 || o == EOF || o == 1) 174 o = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex);
175
176 if (o == -1 || o == EOF || o == 1) {
207 break; 177 break;
178 }
208 179
209 switch (o) { 180 switch (o) {
210 case 'd': 181 case 'd':
211 device = optarg; 182 device = optarg;
212 break; 183 break;
213 case 'q': 184 case 'q':
214 fprintf (stderr, "%s\n", _("DEPRECATION WARNING: the -q switch (quiet output) is no longer \"quiet\".")); 185 fprintf(stderr, "%s\n", _("DEPRECATION WARNING: the -q switch (quiet output) is no longer \"quiet\"."));
215 fprintf (stderr, "%s\n", _("Nagios-compatible output is now always returned.")); 186 fprintf(stderr, "%s\n", _("Nagios-compatible output is now always returned."));
216 break; 187 break;
217 case 'i': 188 case 'i':
218 case '1': 189 case '1':
219 case '0': 190 case '0':
220 printf ("%s\n", _("SMART commands are broken and have been disabled (See Notes in --help).")); 191 printf("%s\n", _("SMART commands are broken and have been disabled (See Notes in --help)."));
221 return STATE_CRITICAL; 192 return STATE_CRITICAL;
222 break; 193 break;
223 case 'n': 194 case 'n':
224 fprintf (stderr, "%s\n", _("DEPRECATION WARNING: the -n switch (Nagios-compatible output) is now the")); 195 fprintf(stderr, "%s\n", _("DEPRECATION WARNING: the -n switch (Nagios-compatible output) is now the"));
225 fprintf (stderr, "%s\n", _("default and will be removed from future releases.")); 196 fprintf(stderr, "%s\n", _("default and will be removed from future releases."));
226 break; 197 break;
227 case 'v': /* verbose */ 198 case 'v': /* verbose */
228 verbose = true; 199 verbose = true;
229 break; 200 break;
230 case 'h': 201 case 'h':
231 print_help (); 202 print_help();
232 return STATE_UNKNOWN; 203 return STATE_UNKNOWN;
233 case 'V': 204 case 'V':
234 print_revision (progname, NP_VERSION); 205 print_revision(progname, NP_VERSION);
235 return STATE_UNKNOWN; 206 return STATE_UNKNOWN;
236 default: 207 default:
237 usage5 (); 208 usage5();
238 } 209 }
239 } 210 }
240 211
@@ -243,36 +214,34 @@ main (int argc, char *argv[])
243 } 214 }
244 215
245 if (!device) { 216 if (!device) {
246 print_help (); 217 print_help();
247 return STATE_UNKNOWN; 218 return STATE_UNKNOWN;
248 } 219 }
249 220
250 fd = open (device, OPEN_MODE); 221 fd = open(device, OPEN_MODE);
251 222
252 if (fd < 0) { 223 if (fd < 0) {
253 printf (_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror (errno)); 224 printf(_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror(errno));
254 return STATE_CRITICAL; 225 return STATE_CRITICAL;
255 } 226 }
256 227
257 if (smart_cmd_simple (fd, SMART_CMD_ENABLE, 0, false)) { 228 if (smart_cmd_simple(fd, SMART_CMD_ENABLE, 0, false)) {
258 printf (_("CRITICAL - SMART_CMD_ENABLE\n")); 229 printf(_("CRITICAL - SMART_CMD_ENABLE\n"));
259 return STATE_CRITICAL; 230 return STATE_CRITICAL;
260 } 231 }
261 232
262 smart_read_values (fd, &values); 233 smart_read_values(fd, &values);
263 smart_read_thresholds (fd, &thresholds); 234 smart_read_thresholds(fd, &thresholds);
264 retval = nagios (&values, &thresholds); 235 retval = nagios(&values, &thresholds);
265 if (verbose) print_values (&values, &thresholds); 236 if (verbose) {
237 print_values(&values, &thresholds);
238 }
266 239
267 close (fd); 240 close(fd);
268 return retval; 241 return retval;
269} 242}
270 243
271 244char *get_offline_text(int status) {
272
273char *
274get_offline_text (int status)
275{
276 int i; 245 int i;
277 for (i = 0; offline_status_text[i].text; i++) { 246 for (i = 0; offline_status_text[i].text; i++) {
278 if (offline_status_text[i].value == status) { 247 if (offline_status_text[i].value == status) {
@@ -282,24 +251,20 @@ get_offline_text (int status)
282 return "UNKNOWN"; 251 return "UNKNOWN";
283} 252}
284 253
285 254int smart_read_values(int fd, values_t *values) {
286
287int
288smart_read_values (int fd, values_t * values)
289{
290#ifdef __linux__ 255#ifdef __linux__
291 int e; 256 int e;
292 __u8 args[4 + 512]; 257 uint8_t args[4 + 512];
293 args[0] = WIN_SMART; 258 args[0] = WIN_SMART;
294 args[1] = 0; 259 args[1] = 0;
295 args[2] = SMART_READ_VALUES; 260 args[2] = SMART_READ_VALUES;
296 args[3] = 1; 261 args[3] = 1;
297 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) { 262 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
298 e = errno; 263 e = errno;
299 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno)); 264 printf(_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror(errno));
300 return e; 265 return e;
301 } 266 }
302 memcpy (values, args + 4, 512); 267 memcpy(values, args + 4, 512);
303#endif /* __linux__ */ 268#endif /* __linux__ */
304#ifdef __NetBSD__ 269#ifdef __NetBSD__
305 struct atareq req; 270 struct atareq req;
@@ -317,13 +282,14 @@ smart_read_values (int fd, values_t * values)
317 req.cylinder = WDSMART_CYL; 282 req.cylinder = WDSMART_CYL;
318 283
319 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 284 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
320 if (req.retsts != ATACMD_OK) 285 if (req.retsts != ATACMD_OK) {
321 errno = ENODEV; 286 errno = ENODEV;
287 }
322 } 288 }
323 289
324 if (errno != 0) { 290 if (errno != 0) {
325 int e = errno; 291 int e = errno;
326 printf (_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror (errno)); 292 printf(_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror(errno));
327 return e; 293 return e;
328 } 294 }
329 295
@@ -332,13 +298,9 @@ smart_read_values (int fd, values_t * values)
332 return 0; 298 return 0;
333} 299}
334 300
335 301int nagios(values_t *p, thresholds_t *t) {
336 302 value_t *value = p->values;
337int 303 threshold_t *threshold = t->thresholds;
338nagios (values_t * p, thresholds_t * t)
339{
340 value_t * value = p->values;
341 threshold_t * threshold = t->thresholds;
342 int status = OPERATIONAL; 304 int status = OPERATIONAL;
343 int prefailure = 0; 305 int prefailure = 0;
344 int advisory = 0; 306 int advisory = 0;
@@ -353,13 +315,11 @@ nagios (values_t * p, thresholds_t * t)
353 if (value->status & 1) { 315 if (value->status & 1) {
354 status = PREFAILURE; 316 status = PREFAILURE;
355 ++prefailure; 317 ++prefailure;
356 } 318 } else {
357 else {
358 status = ADVISORY; 319 status = ADVISORY;
359 ++advisory; 320 ++advisory;
360 } 321 }
361 } 322 } else {
362 else {
363 ++passed; 323 ++passed;
364 } 324 }
365 ++total; 325 ++total;
@@ -369,96 +329,66 @@ nagios (values_t * p, thresholds_t * t)
369 } 329 }
370 switch (status) { 330 switch (status) {
371 case PREFAILURE: 331 case PREFAILURE:
372 printf (_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"), 332 printf(_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"), prefailure, prefailure > 1 ? 's' : ' ', failed,
373 prefailure, 333 total);
374 prefailure > 1 ? 's' : ' ', 334 status = STATE_CRITICAL;
375 failed,
376 total);
377 status=STATE_CRITICAL;
378 break; 335 break;
379 case ADVISORY: 336 case ADVISORY:
380 printf (_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"), 337 printf(_("WARNING - %d Harddrive Advisor%s Detected. %d/%d tests failed.\n"), advisory, advisory > 1 ? "ies" : "y", failed, total);
381 advisory, 338 status = STATE_WARNING;
382 advisory > 1 ? "ies" : "y",
383 failed,
384 total);
385 status=STATE_WARNING;
386 break; 339 break;
387 case OPERATIONAL: 340 case OPERATIONAL:
388 printf (_("OK - Operational (%d/%d tests passed)\n"), passed, total); 341 printf(_("OK - Operational (%d/%d tests passed)\n"), passed, total);
389 status=STATE_OK; 342 status = STATE_OK;
390 break; 343 break;
391 default: 344 default:
392 printf (_("ERROR - Status '%d' unknown. %d/%d tests passed\n"), status, 345 printf(_("ERROR - Status '%d' unknown. %d/%d tests passed\n"), status, passed, total);
393 passed, total);
394 status = STATE_UNKNOWN; 346 status = STATE_UNKNOWN;
395 break; 347 break;
396 } 348 }
397 return status; 349 return status;
398} 350}
399 351
400 352void print_value(value_t *p, threshold_t *t) {
401 353 printf("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n", p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory ",
402void 354 p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold, p->value >= t->threshold ? "Passed" : "Failed");
403print_value (value_t * p, threshold_t * t)
404{
405 printf ("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n",
406 p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory ",
407 p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold,
408 p->value >= t->threshold ? "Passed" : "Failed");
409} 355}
410 356
411 357void print_values(values_t *p, thresholds_t *t) {
412 358 value_t *value = p->values;
413void 359 threshold_t *threshold = t->thresholds;
414print_values (values_t * p, thresholds_t * t)
415{
416 value_t * value = p->values;
417 threshold_t * threshold = t->thresholds;
418 int i; 360 int i;
419 for (i = 0; i < NR_ATTRIBUTES; i++) { 361 for (i = 0; i < NR_ATTRIBUTES; i++) {
420 if (value->id && threshold->id && value->id == threshold->id) { 362 if (value->id && threshold->id && value->id == threshold->id) {
421 print_value (value++, threshold++); 363 print_value(value++, threshold++);
422 } 364 }
423 } 365 }
424 printf 366 printf(_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"), p->offline_status,
425 (_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"), 367 get_offline_text(p->offline_status & 0x7f), (p->offline_status & 0x80 ? "Yes" : "No"), p->offline_timeout / 60);
426 p->offline_status, 368 printf(_("OffLineCapability=%d {%s %s %s}\n"), p->offline_capability, p->offline_capability & 1 ? "Immediate" : "",
427 get_offline_text (p->offline_status & 0x7f), 369 p->offline_capability & 2 ? "Auto" : "", p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
428 (p->offline_status & 0x80 ? "Yes" : "No"), 370 printf(_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"), p->revision, p->checksum, p->smart_capability,
429 p->offline_timeout / 60); 371 p->smart_capability & 1 ? "SaveOnStandBy" : "", p->smart_capability & 2 ? "AutoSave" : "");
430 printf
431 (_("OffLineCapability=%d {%s %s %s}\n"),
432 p->offline_capability,
433 p->offline_capability & 1 ? "Immediate" : "",
434 p->offline_capability & 2 ? "Auto" : "",
435 p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd");
436 printf
437 (_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"),
438 p->revision,
439 p->checksum,
440 p->smart_capability,
441 p->smart_capability & 1 ? "SaveOnStandBy" : "",
442 p->smart_capability & 2 ? "AutoSave" : "");
443} 372}
444 373
445 374int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_error) {
446int smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, bool show_error) {
447 int e = STATE_UNKNOWN; 375 int e = STATE_UNKNOWN;
448#ifdef __linux__ 376#ifdef __linux__
449 __u8 args[4]; 377 uint8_t args[4];
450 args[0] = WIN_SMART; 378 args[0] = WIN_SMART;
451 args[1] = val0; 379 args[1] = val0;
452 args[2] = smart_command[command].value; 380 args[2] = smart_command[command].value;
453 args[3] = 0; 381 args[3] = 0;
454 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) { 382 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
455 e = STATE_CRITICAL; 383 e = STATE_CRITICAL;
456 if (show_error) 384 if (show_error) {
457 printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno)); 385 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
386 }
458 } else { 387 } else {
459 e = STATE_OK; 388 e = STATE_OK;
460 if (show_error) 389 if (show_error) {
461 printf (_("OK - Command sent (%s)\n"), smart_command[command].text); 390 printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
391 }
462 } 392 }
463 393
464#endif /* __linux__ */ 394#endif /* __linux__ */
@@ -474,44 +404,44 @@ int smart_cmd_simple (int fd, enum SmartCommand command, __u8 val0, bool show_er
474 req.sec_count = val0; 404 req.sec_count = val0;
475 405
476 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 406 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
477 if (req.retsts != ATACMD_OK) 407 if (req.retsts != ATACMD_OK) {
478 errno = ENODEV; 408 errno = ENODEV;
479 if (req.cylinder != WDSMART_CYL) 409 }
410 if (req.cylinder != WDSMART_CYL) {
480 errno = ENODEV; 411 errno = ENODEV;
412 }
481 } 413 }
482 414
483 if (errno != 0) { 415 if (errno != 0) {
484 e = STATE_CRITICAL; 416 e = STATE_CRITICAL;
485 if (show_error) 417 if (show_error) {
486 printf (_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror (errno)); 418 printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno));
419 }
487 } else { 420 } else {
488 e = STATE_OK; 421 e = STATE_OK;
489 if (show_error) 422 if (show_error) {
490 printf (_("OK - Command sent (%s)\n"), smart_command[command].text); 423 printf(_("OK - Command sent (%s)\n"), smart_command[command].text);
424 }
491 } 425 }
492 426
493#endif /* __NetBSD__ */ 427#endif /* __NetBSD__ */
494 return e; 428 return e;
495} 429}
496 430
497 431int smart_read_thresholds(int fd, thresholds_t *thresholds) {
498
499int
500smart_read_thresholds (int fd, thresholds_t * thresholds)
501{
502#ifdef __linux__ 432#ifdef __linux__
503 int e; 433 int e;
504 __u8 args[4 + 512]; 434 uint8_t args[4 + 512];
505 args[0] = WIN_SMART; 435 args[0] = WIN_SMART;
506 args[1] = 0; 436 args[1] = 0;
507 args[2] = SMART_READ_THRESHOLDS; 437 args[2] = SMART_READ_THRESHOLDS;
508 args[3] = 1; 438 args[3] = 1;
509 if (ioctl (fd, HDIO_DRIVE_CMD, &args)) { 439 if (ioctl(fd, HDIO_DRIVE_CMD, &args)) {
510 e = errno; 440 e = errno;
511 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno)); 441 printf(_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror(errno));
512 return e; 442 return e;
513 } 443 }
514 memcpy (thresholds, args + 4, 512); 444 memcpy(thresholds, args + 4, 512);
515#endif /* __linux__ */ 445#endif /* __linux__ */
516#ifdef __NetBSD__ 446#ifdef __NetBSD__
517 struct atareq req; 447 struct atareq req;
@@ -529,13 +459,14 @@ smart_read_thresholds (int fd, thresholds_t * thresholds)
529 req.cylinder = WDSMART_CYL; 459 req.cylinder = WDSMART_CYL;
530 460
531 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { 461 if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) {
532 if (req.retsts != ATACMD_OK) 462 if (req.retsts != ATACMD_OK) {
533 errno = ENODEV; 463 errno = ENODEV;
464 }
534 } 465 }
535 466
536 if (errno != 0) { 467 if (errno != 0) {
537 int e = errno; 468 int e = errno;
538 printf (_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror (errno)); 469 printf(_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror(errno));
539 return e; 470 return e;
540 } 471 }
541 472
@@ -544,45 +475,43 @@ smart_read_thresholds (int fd, thresholds_t * thresholds)
544 return 0; 475 return 0;
545} 476}
546 477
478void print_help(void) {
479 print_revision(progname, NP_VERSION);
547 480
548void 481 printf("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
549print_help (void) 482 printf("Plugin implementation - 1999 Robert Dale <rdale@digital-mission.com>\n");
550{ 483 printf(COPYRIGHT, copyright, email);
551 print_revision (progname, NP_VERSION);
552
553 printf ("(C) 1999 Ragnar Hojland Espinosa <ragnar@lightside.dhis.org>\n");
554 printf ("Plugin implementation - 1999 Robert Dale <rdale@digital-mission.com>\n");
555 printf (COPYRIGHT, copyright, email);
556 484
557 printf (_("This plugin checks a local hard drive with the (Linux specific) SMART interface [http://smartlinux.sourceforge.net/smart/index.php].")); 485 printf(_("This plugin checks a local hard drive with the (Linux specific) SMART interface "
486 "[http://smartlinux.sourceforge.net/smart/index.php]."));
558 487
559 printf ("\n\n"); 488 printf("\n\n");
560 489
561 print_usage (); 490 print_usage();
562 491
563 printf (UT_HELP_VRSN); 492 printf(UT_HELP_VRSN);
564 printf (UT_EXTRA_OPTS); 493 printf(UT_EXTRA_OPTS);
565 494
566 printf (" %s\n", "-d, --device=DEVICE"); 495 printf(" %s\n", "-d, --device=DEVICE");
567 printf (" %s\n", _("Select device DEVICE")); 496 printf(" %s\n", _("Select device DEVICE"));
568 printf (" %s\n", _("Note: if the device is specified without this option, any further option will")); 497 printf(" %s\n", _("Note: if the device is specified without this option, any further option will"));
569 printf (" %s\n", _("be ignored.")); 498 printf(" %s\n", _("be ignored."));
570 499
571 printf (UT_VERBOSE); 500 printf(UT_VERBOSE);
572 501
573 printf ("\n"); 502 printf("\n");
574 printf ("%s\n", _("Notes:")); 503 printf("%s\n", _("Notes:"));
575 printf (" %s\n", _("The SMART command modes (-i/--immediate, -0/--auto-off and -1/--auto-on) were")); 504 printf(" %s\n", _("The SMART command modes (-i/--immediate, -0/--auto-off and -1/--auto-on) were"));
576 printf (" %s\n", _("broken in an underhand manner and have been disabled. You can use smartctl")); 505 printf(" %s\n", _("broken in an underhand manner and have been disabled. You can use smartctl"));
577 printf (" %s\n", _("instead:")); 506 printf(" %s\n", _("instead:"));
578 printf (" %s\n", _("-0/--auto-off: use \"smartctl --offlineauto=off\"")); 507 printf(" %s\n", _("-0/--auto-off: use \"smartctl --offlineauto=off\""));
579 printf (" %s\n", _("-1/--auto-on: use \"smartctl --offlineauto=on\"")); 508 printf(" %s\n", _("-1/--auto-on: use \"smartctl --offlineauto=on\""));
580 printf (" %s\n", _("-i/--immediate: use \"smartctl --test=offline\"")); 509 printf(" %s\n", _("-i/--immediate: use \"smartctl --test=offline\""));
581 510
582 printf (UT_SUPPORT); 511 printf(UT_SUPPORT);
583} 512}
584 513
585 /* todo : add to the long nanual as example 514/* todo : add to the long nanual as example
586 * 515 *
587 * Run with: check_ide-smart --nagios [-d] <DRIVE> 516 * Run with: check_ide-smart --nagios [-d] <DRIVE>
588 * Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc 517 * Where DRIVE is an IDE drive, ie. /dev/hda, /dev/hdb, /dev/hdc
@@ -593,10 +522,7 @@ print_help (void)
593 * - Returns -1 not too often 522 * - Returns -1 not too often
594 */ 523 */
595 524
596 525void print_usage(void) {
597void 526 printf("%s\n", _("Usage:"));
598print_usage (void) 527 printf("%s [-d <device>] [-v]", progname);
599{
600 printf ("%s\n", _("Usage:"));
601 printf ("%s [-d <device>] [-v]", progname);
602} 528}
diff --git a/plugins/check_ldap.c b/plugins/check_ldap.c
index 868ffc1e..597644bd 100644
--- a/plugins/check_ldap.c
+++ b/plugins/check_ldap.c
@@ -1,242 +1,211 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ldap plugin 3 * Monitoring check_ldap plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_ldap plugin 10 * This file contains the check_ldap plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29/* progname may be check_ldaps */ 29/* progname may be check_ldaps */
30char *progname = "check_ldap"; 30char *progname = "check_ldap";
31const char *copyright = "2000-2008"; 31const char *copyright = "2000-2024";
32const char *email = "devel@monitoring-plugins.org"; 32const char *email = "devel@monitoring-plugins.org";
33 33
34#include "common.h" 34#include "common.h"
35#include "netutils.h" 35#include "netutils.h"
36#include "utils.h" 36#include "utils.h"
37#include "check_ldap.d/config.h"
37 38
39#include "states.h"
38#include <lber.h> 40#include <lber.h>
39#define LDAP_DEPRECATED 1 41#define LDAP_DEPRECATED 1
40#include <ldap.h> 42#include <ldap.h>
41 43
42enum { 44enum {
43 UNDEFINED = 0,
44#ifdef HAVE_LDAP_SET_OPTION
45 DEFAULT_PROTOCOL = 2,
46#endif
47 DEFAULT_PORT = 389 45 DEFAULT_PORT = 389
48}; 46};
49 47
50int process_arguments (int, char **); 48typedef struct {
51int validate_arguments (void); 49 int errorcode;
52void print_help (void); 50 check_ldap_config config;
53void print_usage (void); 51} check_ldap_config_wrapper;
54 52static check_ldap_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
55char ld_defattr[] = "(objectclass=*)"; 53static check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper /*config_wrapper*/);
56char *ld_attr = ld_defattr;
57char *ld_host = NULL;
58char *ld_base = NULL;
59char *ld_passwd = NULL;
60char *ld_binddn = NULL;
61int ld_port = -1;
62#ifdef HAVE_LDAP_SET_OPTION
63int ld_protocol = DEFAULT_PROTOCOL;
64#endif
65#ifndef LDAP_OPT_SUCCESS
66# define LDAP_OPT_SUCCESS LDAP_SUCCESS
67#endif
68double warn_time = UNDEFINED;
69double crit_time = UNDEFINED;
70thresholds *entries_thresholds = NULL;
71struct timeval tv;
72char* warn_entries = NULL;
73char* crit_entries = NULL;
74bool starttls = false;
75bool ssl_on_connect = false;
76bool verbose = false;
77
78/* for ldap tls */
79
80char *SERVICE = "LDAP";
81
82int
83main (int argc, char *argv[])
84{
85
86 LDAP *ld;
87 LDAPMessage *result;
88
89 /* should be int result = STATE_UNKNOWN; */
90
91 int status = STATE_UNKNOWN;
92 long microsec;
93 double elapsed_time;
94
95 /* for ldap tls */
96 54
97 int tls; 55static void print_help(void);
98 int version=3; 56void print_usage(void);
99 57
100 int status_entries = STATE_OK; 58#ifndef LDAP_OPT_SUCCESS
101 int num_entries = 0; 59# define LDAP_OPT_SUCCESS LDAP_SUCCESS
60#endif
61static int verbose = 0;
102 62
103 setlocale (LC_ALL, ""); 63int main(int argc, char *argv[]) {
104 bindtextdomain (PACKAGE, LOCALEDIR); 64 setlocale(LC_ALL, "");
105 textdomain (PACKAGE); 65 bindtextdomain(PACKAGE, LOCALEDIR);
66 textdomain(PACKAGE);
106 67
107 if (strstr(argv[0],"check_ldaps")) { 68 if (strstr(argv[0], "check_ldaps")) {
108 xasprintf (&progname, "check_ldaps"); 69 xasprintf(&progname, "check_ldaps");
109 } 70 }
110 71
111 /* Parse extra opts if any */ 72 /* Parse extra opts if any */
112 argv=np_extra_opts (&argc, argv, progname); 73 argv = np_extra_opts(&argc, argv, progname);
113 74
114 if (process_arguments (argc, argv) == ERROR) 75 check_ldap_config_wrapper tmp_config = process_arguments(argc, argv);
115 usage4 (_("Could not parse arguments")); 76 if (tmp_config.errorcode == ERROR) {
77 usage4(_("Could not parse arguments"));
78 }
116 79
117 if (strstr(argv[0],"check_ldaps") && ! starttls && ! ssl_on_connect) 80 const check_ldap_config config = tmp_config.config;
118 starttls = true;
119 81
120 /* initialize alarm signal handling */ 82 /* initialize alarm signal handling */
121 signal (SIGALRM, socket_timeout_alarm_handler); 83 signal(SIGALRM, socket_timeout_alarm_handler);
122 84
123 /* set socket timeout */ 85 /* set socket timeout */
124 alarm (socket_timeout); 86 alarm(socket_timeout);
125 87
126 /* get the start time */ 88 /* get the start time */
127 gettimeofday (&tv, NULL); 89 struct timeval start_time;
90 gettimeofday(&start_time, NULL);
128 91
92 LDAP *ldap_connection;
129 /* initialize ldap */ 93 /* initialize ldap */
130#ifdef HAVE_LDAP_INIT 94#ifdef HAVE_LDAP_INIT
131 if (!(ld = ldap_init (ld_host, ld_port))) { 95 if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) {
132 printf ("Could not connect to the server at port %i\n", ld_port); 96 printf("Could not connect to the server at port %i\n", config.ld_port);
133 return STATE_CRITICAL; 97 return STATE_CRITICAL;
134 } 98 }
135#else 99#else
136 if (!(ld = ldap_open (ld_host, ld_port))) { 100 if (!(ld = ldap_open(config.ld_host, config.ld_port))) {
137 if (verbose) 101 if (verbose) {
138 ldap_perror(ld, "ldap_open"); 102 ldap_perror(ldap_connection, "ldap_open");
139 printf (_("Could not connect to the server at port %i\n"), ld_port); 103 }
104 printf(_("Could not connect to the server at port %i\n"), config.ld_port);
140 return STATE_CRITICAL; 105 return STATE_CRITICAL;
141 } 106 }
142#endif /* HAVE_LDAP_INIT */ 107#endif /* HAVE_LDAP_INIT */
143 108
144#ifdef HAVE_LDAP_SET_OPTION 109#ifdef HAVE_LDAP_SET_OPTION
145 /* set ldap options */ 110 /* set ldap options */
146 if (ldap_set_option (ld, LDAP_OPT_PROTOCOL_VERSION, &ld_protocol) != 111 if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != LDAP_OPT_SUCCESS) {
147 LDAP_OPT_SUCCESS ) { 112 printf(_("Could not set protocol version %d\n"), config.ld_protocol);
148 printf(_("Could not set protocol version %d\n"), ld_protocol);
149 return STATE_CRITICAL; 113 return STATE_CRITICAL;
150 } 114 }
151#endif 115#endif
152 116
153 if (ld_port == LDAPS_PORT || ssl_on_connect) { 117 int version = 3;
154 xasprintf (&SERVICE, "LDAPS"); 118 int tls;
119 if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) {
155#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) 120#if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS)
156 /* ldaps: set option tls */ 121 /* ldaps: set option tls */
157 tls = LDAP_OPT_X_TLS_HARD; 122 tls = LDAP_OPT_X_TLS_HARD;
158 123
159 if (ldap_set_option (ld, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) 124 if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) {
160 { 125 if (verbose) {
161 if (verbose) 126 ldap_perror(ldap_connection, "ldaps_option");
162 ldap_perror(ld, "ldaps_option"); 127 }
163 printf (_("Could not init TLS at port %i!\n"), ld_port); 128 printf(_("Could not init TLS at port %i!\n"), config.ld_port);
164 return STATE_CRITICAL; 129 return STATE_CRITICAL;
165 } 130 }
166#else 131#else
167 printf (_("TLS not supported by the libraries!\n")); 132 printf(_("TLS not supported by the libraries!\n"));
168 return STATE_CRITICAL; 133 return STATE_CRITICAL;
169#endif /* LDAP_OPT_X_TLS */ 134#endif /* LDAP_OPT_X_TLS */
170 } else if (starttls) { 135 } else if (config.starttls) {
171 xasprintf (&SERVICE, "LDAP-TLS");
172#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) 136#if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S)
173 /* ldap with startTLS: set option version */ 137 /* ldap with startTLS: set option version */
174 if (ldap_get_option(ld,LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS ) 138 if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
175 { 139 if (version < LDAP_VERSION3) {
176 if (version < LDAP_VERSION3)
177 {
178 version = LDAP_VERSION3; 140 version = LDAP_VERSION3;
179 ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version); 141 ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version);
180 } 142 }
181 } 143 }
182 /* call start_tls */ 144 /* call start_tls */
183 if (ldap_start_tls_s(ld, NULL, NULL) != LDAP_SUCCESS) 145 if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) {
184 { 146 if (verbose) {
185 if (verbose) 147 ldap_perror(ldap_connection, "ldap_start_tls");
186 ldap_perror(ld, "ldap_start_tls"); 148 }
187 printf (_("Could not init startTLS at port %i!\n"), ld_port); 149 printf(_("Could not init startTLS at port %i!\n"), config.ld_port);
188 return STATE_CRITICAL; 150 return STATE_CRITICAL;
189 } 151 }
190#else 152#else
191 printf (_("startTLS not supported by the library, needs LDAPv3!\n")); 153 printf(_("startTLS not supported by the library, needs LDAPv3!\n"));
192 return STATE_CRITICAL; 154 return STATE_CRITICAL;
193#endif /* HAVE_LDAP_START_TLS_S */ 155#endif /* HAVE_LDAP_START_TLS_S */
194 } 156 }
195 157
196 /* bind to the ldap server */ 158 /* bind to the ldap server */
197 if (ldap_bind_s (ld, ld_binddn, ld_passwd, LDAP_AUTH_SIMPLE) != 159 if (ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE) != LDAP_SUCCESS) {
198 LDAP_SUCCESS) { 160 if (verbose) {
199 if (verbose) 161 ldap_perror(ldap_connection, "ldap_bind");
200 ldap_perror(ld, "ldap_bind"); 162 }
201 printf (_("Could not bind to the LDAP server\n")); 163 printf(_("Could not bind to the LDAP server\n"));
202 return STATE_CRITICAL; 164 return STATE_CRITICAL;
203 } 165 }
204 166
167 LDAPMessage *result;
168 int num_entries = 0;
205 /* do a search of all objectclasses in the base dn */ 169 /* do a search of all objectclasses in the base dn */
206 if (ldap_search_s (ld, ld_base, (crit_entries!=NULL || warn_entries!=NULL) ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE, ld_attr, NULL, 0, &result) 170 if (ldap_search_s(ldap_connection, config.ld_base,
207 != LDAP_SUCCESS) { 171 (config.crit_entries != NULL || config.warn_entries != NULL) ? LDAP_SCOPE_SUBTREE : LDAP_SCOPE_BASE, config.ld_attr,
208 if (verbose) 172 NULL, 0, &result) != LDAP_SUCCESS) {
209 ldap_perror(ld, "ldap_search"); 173 if (verbose) {
210 printf (_("Could not search/find objectclasses in %s\n"), ld_base); 174 ldap_perror(ldap_connection, "ldap_search");
175 }
176 printf(_("Could not search/find objectclasses in %s\n"), config.ld_base);
211 return STATE_CRITICAL; 177 return STATE_CRITICAL;
212 } else if (crit_entries!=NULL || warn_entries!=NULL) { 178 }
213 num_entries = ldap_count_entries(ld, result); 179
180 if (config.crit_entries != NULL || config.warn_entries != NULL) {
181 num_entries = ldap_count_entries(ldap_connection, result);
214 } 182 }
215 183
216 /* unbind from the ldap server */ 184 /* unbind from the ldap server */
217 ldap_unbind (ld); 185 ldap_unbind(ldap_connection);
218 186
219 /* reset the alarm handler */ 187 /* reset the alarm handler */
220 alarm (0); 188 alarm(0);
221 189
222 /* calculate the elapsed time and compare to thresholds */ 190 /* calculate the elapsed time and compare to thresholds */
223 191
224 microsec = deltime (tv); 192 long microsec = deltime(start_time);
225 elapsed_time = (double)microsec / 1.0e6; 193 double elapsed_time = (double)microsec / 1.0e6;
226 194 mp_state_enum status = STATE_UNKNOWN;
227 if (crit_time!=UNDEFINED && elapsed_time>crit_time) 195 if (config.crit_time_set && elapsed_time > config.crit_time) {
228 status = STATE_CRITICAL; 196 status = STATE_CRITICAL;
229 else if (warn_time!=UNDEFINED && elapsed_time>warn_time) 197 } else if (config.warn_time_set && elapsed_time > config.warn_time) {
230 status = STATE_WARNING; 198 status = STATE_WARNING;
231 else 199 } else {
232 status = STATE_OK; 200 status = STATE_OK;
201 }
233 202
234 if(entries_thresholds != NULL) { 203 if (config.entries_thresholds != NULL) {
235 if (verbose) { 204 if (verbose) {
236 printf ("entries found: %d\n", num_entries); 205 printf("entries found: %d\n", num_entries);
237 print_thresholds("entry thresholds", entries_thresholds); 206 print_thresholds("entry thresholds", config.entries_thresholds);
238 } 207 }
239 status_entries = get_status(num_entries, entries_thresholds); 208 mp_state_enum status_entries = get_status(num_entries, config.entries_thresholds);
240 if (status_entries == STATE_CRITICAL) { 209 if (status_entries == STATE_CRITICAL) {
241 status = STATE_CRITICAL; 210 status = STATE_CRITICAL;
242 } else if (status != STATE_CRITICAL) { 211 } else if (status != STATE_CRITICAL) {
@@ -245,273 +214,272 @@ main (int argc, char *argv[])
245 } 214 }
246 215
247 /* print out the result */ 216 /* print out the result */
248 if (crit_entries!=NULL || warn_entries!=NULL) { 217 if (config.crit_entries != NULL || config.warn_entries != NULL) {
249 printf (_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), 218 printf(_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), state_text(status), num_entries, elapsed_time,
250 state_text (status), 219 fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, config.crit_time_set, config.crit_time, true, 0,
251 num_entries, 220 false, 0),
252 elapsed_time, 221 sperfdata("entries", (double)num_entries, "", config.warn_entries, config.crit_entries, true, 0.0, false, 0.0));
253 fperfdata ("time", elapsed_time, "s",
254 (int)warn_time, warn_time,
255 (int)crit_time, crit_time,
256 true, 0, false, 0),
257 sperfdata ("entries", (double)num_entries, "",
258 warn_entries,
259 crit_entries,
260 true, 0.0, false, 0.0));
261 } else { 222 } else {
262 printf (_("LDAP %s - %.3f seconds response time|%s\n"), 223 printf(_("LDAP %s - %.3f seconds response time|%s\n"), state_text(status), elapsed_time,
263 state_text (status), 224 fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, config.crit_time_set, config.crit_time, true, 0,
264 elapsed_time, 225 false, 0));
265 fperfdata ("time", elapsed_time, "s",
266 (int)warn_time, warn_time,
267 (int)crit_time, crit_time,
268 true, 0, false, 0));
269 } 226 }
270 227
271 return status; 228 exit(status);
272} 229}
273 230
274/* process command-line arguments */ 231/* process command-line arguments */
275int 232check_ldap_config_wrapper process_arguments(int argc, char **argv) {
276process_arguments (int argc, char **argv)
277{
278 int c;
279
280 int option = 0;
281 /* initialize the long option struct */ 233 /* initialize the long option struct */
282 static struct option longopts[] = { 234 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
283 {"help", no_argument, 0, 'h'}, 235 {"version", no_argument, 0, 'V'},
284 {"version", no_argument, 0, 'V'}, 236 {"timeout", required_argument, 0, 't'},
285 {"timeout", required_argument, 0, 't'}, 237 {"hostname", required_argument, 0, 'H'},
286 {"hostname", required_argument, 0, 'H'}, 238 {"base", required_argument, 0, 'b'},
287 {"base", required_argument, 0, 'b'}, 239 {"attr", required_argument, 0, 'a'},
288 {"attr", required_argument, 0, 'a'}, 240 {"bind", required_argument, 0, 'D'},
289 {"bind", required_argument, 0, 'D'}, 241 {"pass", required_argument, 0, 'P'},
290 {"pass", required_argument, 0, 'P'},
291#ifdef HAVE_LDAP_SET_OPTION 242#ifdef HAVE_LDAP_SET_OPTION
292 {"ver2", no_argument, 0, '2'}, 243 {"ver2", no_argument, 0, '2'},
293 {"ver3", no_argument, 0, '3'}, 244 {"ver3", no_argument, 0, '3'},
294#endif 245#endif
295 {"starttls", no_argument, 0, 'T'}, 246 {"starttls", no_argument, 0, 'T'},
296 {"ssl", no_argument, 0, 'S'}, 247 {"ssl", no_argument, 0, 'S'},
297 {"use-ipv4", no_argument, 0, '4'}, 248 {"use-ipv4", no_argument, 0, '4'},
298 {"use-ipv6", no_argument, 0, '6'}, 249 {"use-ipv6", no_argument, 0, '6'},
299 {"port", required_argument, 0, 'p'}, 250 {"port", required_argument, 0, 'p'},
300 {"warn", required_argument, 0, 'w'}, 251 {"warn", required_argument, 0, 'w'},
301 {"crit", required_argument, 0, 'c'}, 252 {"crit", required_argument, 0, 'c'},
302 {"warn-entries", required_argument, 0, 'W'}, 253 {"warn-entries", required_argument, 0, 'W'},
303 {"crit-entries", required_argument, 0, 'C'}, 254 {"crit-entries", required_argument, 0, 'C'},
304 {"verbose", no_argument, 0, 'v'}, 255 {"verbose", no_argument, 0, 'v'},
305 {0, 0, 0, 0} 256 {0, 0, 0, 0}};
257
258 check_ldap_config_wrapper result = {
259 .errorcode = OK,
260 .config = check_ldap_config_init(),
306 }; 261 };
307 262
308 if (argc < 2) 263 if (argc < 2) {
309 return ERROR; 264 result.errorcode = ERROR;
265 return result;
266 }
310 267
311 for (c = 1; c < argc; c++) { 268 for (int index = 1; index < argc; index++) {
312 if (strcmp ("-to", argv[c]) == 0) 269 if (strcmp("-to", argv[index]) == 0) {
313 strcpy (argv[c], "-t"); 270 strcpy(argv[index], "-t");
271 }
314 } 272 }
315 273
274 int option = 0;
316 while (true) { 275 while (true) {
317 c = getopt_long (argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option); 276 int option_index = getopt_long(argc, argv, "hvV234TS6t:c:w:H:b:p:a:D:P:C:W:", longopts, &option);
318 277
319 if (c == -1 || c == EOF) 278 if (option_index == -1 || option_index == EOF) {
320 break; 279 break;
280 }
321 281
322 switch (c) { 282 switch (option_index) {
323 case 'h': /* help */ 283 case 'h': /* help */
324 print_help (); 284 print_help();
325 exit (STATE_UNKNOWN); 285 exit(STATE_UNKNOWN);
326 case 'V': /* version */ 286 case 'V': /* version */
327 print_revision (progname, NP_VERSION); 287 print_revision(progname, NP_VERSION);
328 exit (STATE_UNKNOWN); 288 exit(STATE_UNKNOWN);
329 case 't': /* timeout period */ 289 case 't': /* timeout period */
330 if (!is_intnonneg (optarg)) 290 if (!is_intnonneg(optarg)) {
331 usage2 (_("Timeout interval must be a positive integer"), optarg); 291 usage2(_("Timeout interval must be a positive integer"), optarg);
332 else 292 } else {
333 socket_timeout = atoi (optarg); 293 socket_timeout = atoi(optarg);
294 }
334 break; 295 break;
335 case 'H': 296 case 'H':
336 ld_host = optarg; 297 result.config.ld_host = optarg;
337 break; 298 break;
338 case 'b': 299 case 'b':
339 ld_base = optarg; 300 result.config.ld_base = optarg;
340 break; 301 break;
341 case 'p': 302 case 'p':
342 ld_port = atoi (optarg); 303 result.config.ld_port = atoi(optarg);
343 break; 304 break;
344 case 'a': 305 case 'a':
345 ld_attr = optarg; 306 result.config.ld_attr = optarg;
346 break; 307 break;
347 case 'D': 308 case 'D':
348 ld_binddn = optarg; 309 result.config.ld_binddn = optarg;
349 break; 310 break;
350 case 'P': 311 case 'P':
351 ld_passwd = optarg; 312 result.config.ld_passwd = optarg;
352 break; 313 break;
353 case 'w': 314 case 'w':
354 warn_time = strtod (optarg, NULL); 315 result.config.warn_time_set = true;
316 result.config.warn_time = strtod(optarg, NULL);
355 break; 317 break;
356 case 'c': 318 case 'c':
357 crit_time = strtod (optarg, NULL); 319 result.config.crit_time_set = true;
320 result.config.crit_time = strtod(optarg, NULL);
358 break; 321 break;
359 case 'W': 322 case 'W':
360 warn_entries = optarg; 323 result.config.warn_entries = optarg;
361 break; 324 break;
362 case 'C': 325 case 'C':
363 crit_entries = optarg; 326 result.config.crit_entries = optarg;
364 break; 327 break;
365#ifdef HAVE_LDAP_SET_OPTION 328#ifdef HAVE_LDAP_SET_OPTION
366 case '2': 329 case '2':
367 ld_protocol = 2; 330 result.config.ld_protocol = 2;
368 break; 331 break;
369 case '3': 332 case '3':
370 ld_protocol = 3; 333 result.config.ld_protocol = 3;
371 break; 334 break;
372#endif 335#endif // HAVE_LDAP_SET_OPTION
373 case '4': 336 case '4':
374 address_family = AF_INET; 337 address_family = AF_INET;
375 break; 338 break;
376 case 'v': 339 case 'v':
377 verbose = true; 340 verbose++;
378 break; 341 break;
379 case 'T': 342 case 'T':
380 if (! ssl_on_connect) 343 if (!result.config.ssl_on_connect) {
381 starttls = true; 344 result.config.starttls = true;
382 else 345 } else {
383 usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl"); 346 usage_va(_("%s cannot be combined with %s"), "-T/--starttls", "-S/--ssl");
347 }
384 break; 348 break;
385 case 'S': 349 case 'S':
386 if (! starttls) { 350 if (!result.config.starttls) {
387 ssl_on_connect = true; 351 result.config.ssl_on_connect = true;
388 if (ld_port == -1) 352 if (result.config.ld_port == -1) {
389 ld_port = LDAPS_PORT; 353 result.config.ld_port = LDAPS_PORT;
390 } else 354 }
355 } else {
391 usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls"); 356 usage_va(_("%s cannot be combined with %s"), "-S/--ssl", "-T/--starttls");
357 }
392 break; 358 break;
393 case '6': 359 case '6':
394#ifdef USE_IPV6 360#ifdef USE_IPV6
395 address_family = AF_INET6; 361 address_family = AF_INET6;
396#else 362#else
397 usage (_("IPv6 support not available\n")); 363 usage(_("IPv6 support not available\n"));
398#endif 364#endif
399 break; 365 break;
400 default: 366 default:
401 usage5 (); 367 usage5();
402 } 368 }
403 } 369 }
404 370
405 c = optind; 371 int index = optind;
406 if (ld_host == NULL && is_host(argv[c])) 372 if ((result.config.ld_host == NULL) && is_host(argv[index])) {
407 ld_host = strdup (argv[c++]); 373 result.config.ld_host = strdup(argv[index++]);
374 }
408 375
409 if (ld_base == NULL && argv[c]) 376 if ((result.config.ld_base == NULL) && argv[index]) {
410 ld_base = strdup (argv[c++]); 377 result.config.ld_base = strdup(argv[index++]);
378 }
411 379
412 if (ld_port == -1) 380 if (result.config.ld_port == -1) {
413 ld_port = DEFAULT_PORT; 381 result.config.ld_port = DEFAULT_PORT;
382 }
414 383
415 return validate_arguments (); 384 if (strstr(argv[0], "check_ldaps") && !result.config.starttls && !result.config.ssl_on_connect) {
385 result.config.starttls = true;
386 }
387
388 return validate_arguments(result);
416} 389}
417 390
391check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper config_wrapper) {
392 if (config_wrapper.config.ld_host == NULL || strlen(config_wrapper.config.ld_host) == 0) {
393 usage4(_("Please specify the host name\n"));
394 }
418 395
419int 396 if (config_wrapper.config.ld_base == NULL) {
420validate_arguments () 397 usage4(_("Please specify the LDAP base\n"));
421{ 398 }
422 if (ld_host==NULL || strlen(ld_host)==0)
423 usage4 (_("Please specify the host name\n"));
424 399
425 if (ld_base==NULL) 400 if (config_wrapper.config.crit_entries != NULL || config_wrapper.config.warn_entries != NULL) {
426 usage4 (_("Please specify the LDAP base\n")); 401 set_thresholds(&config_wrapper.config.entries_thresholds, config_wrapper.config.warn_entries, config_wrapper.config.crit_entries);
402 }
427 403
428 if (crit_entries!=NULL || warn_entries!=NULL) { 404 if (config_wrapper.config.ld_passwd == NULL) {
429 set_thresholds(&entries_thresholds, 405 config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD");
430 warn_entries, crit_entries);
431 } 406 }
432 if (ld_passwd==NULL)
433 ld_passwd = getenv("LDAP_PASSWORD");
434 407
435 return OK; 408 return config_wrapper;
436} 409}
437 410
438 411void print_help(void) {
439void
440print_help (void)
441{
442 char *myport; 412 char *myport;
443 xasprintf (&myport, "%d", DEFAULT_PORT); 413 xasprintf(&myport, "%d", DEFAULT_PORT);
444 414
445 print_revision (progname, NP_VERSION); 415 print_revision(progname, NP_VERSION);
446 416
447 printf ("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n"); 417 printf("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n");
448 printf (COPYRIGHT, copyright, email); 418 printf(COPYRIGHT, copyright, email);
449 419
450 printf ("\n\n"); 420 printf("\n\n");
451 421
452 print_usage (); 422 print_usage();
453 423
454 printf (UT_HELP_VRSN); 424 printf(UT_HELP_VRSN);
455 printf (UT_EXTRA_OPTS); 425 printf(UT_EXTRA_OPTS);
456 426
457 printf (UT_HOST_PORT, 'p', myport); 427 printf(UT_HOST_PORT, 'p', myport);
458 428
459 printf (UT_IPv46); 429 printf(UT_IPv46);
460 430
461 printf (" %s\n", "-a [--attr]"); 431 printf(" %s\n", "-a [--attr]");
462 printf (" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\"")); 432 printf(" %s\n", _("ldap attribute to search (default: \"(objectclass=*)\""));
463 printf (" %s\n", "-b [--base]"); 433 printf(" %s\n", "-b [--base]");
464 printf (" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at")); 434 printf(" %s\n", _("ldap base (eg. ou=my unit, o=my org, c=at"));
465 printf (" %s\n", "-D [--bind]"); 435 printf(" %s\n", "-D [--bind]");
466 printf (" %s\n", _("ldap bind DN (if required)")); 436 printf(" %s\n", _("ldap bind DN (if required)"));
467 printf (" %s\n", "-P [--pass]"); 437 printf(" %s\n", "-P [--pass]");
468 printf (" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')")); 438 printf(" %s\n", _("ldap password (if required, or set the password through environment variable 'LDAP_PASSWORD')"));
469 printf (" %s\n", "-T [--starttls]"); 439 printf(" %s\n", "-T [--starttls]");
470 printf (" %s\n", _("use starttls mechanism introduced in protocol version 3")); 440 printf(" %s\n", _("use starttls mechanism introduced in protocol version 3"));
471 printf (" %s\n", "-S [--ssl]"); 441 printf(" %s\n", "-S [--ssl]");
472 printf (" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT); 442 printf(" %s %i\n", _("use ldaps (ldap v2 ssl method). this also sets the default port to"), LDAPS_PORT);
473 443
474#ifdef HAVE_LDAP_SET_OPTION 444#ifdef HAVE_LDAP_SET_OPTION
475 printf (" %s\n", "-2 [--ver2]"); 445 printf(" %s\n", "-2 [--ver2]");
476 printf (" %s\n", _("use ldap protocol version 2")); 446 printf(" %s\n", _("use ldap protocol version 2"));
477 printf (" %s\n", "-3 [--ver3]"); 447 printf(" %s\n", "-3 [--ver3]");
478 printf (" %s\n", _("use ldap protocol version 3")); 448 printf(" %s\n", _("use ldap protocol version 3"));
479 printf (" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL); 449 printf(" (%s %d)\n", _("default protocol version:"), DEFAULT_PROTOCOL);
480#endif 450#endif
481 451
482 printf (UT_WARN_CRIT); 452 printf(UT_WARN_CRIT);
483 453
484 printf (" %s\n", "-W [--warn-entries]"); 454 printf(" %s\n", "-W [--warn-entries]");
485 printf (" %s\n", _("Number of found entries to result in warning status")); 455 printf(" %s\n", _("Number of found entries to result in warning status"));
486 printf (" %s\n", "-C [--crit-entries]"); 456 printf(" %s\n", "-C [--crit-entries]");
487 printf (" %s\n", _("Number of found entries to result in critical status")); 457 printf(" %s\n", _("Number of found entries to result in critical status"));
488 458
489 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 459 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
490 460
491 printf (UT_VERBOSE); 461 printf(UT_VERBOSE);
492 462
493 printf ("\n"); 463 printf("\n");
494 printf ("%s\n", _("Notes:")); 464 printf("%s\n", _("Notes:"));
495 printf (" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be")); 465 printf(" %s\n", _("If this plugin is called via 'check_ldaps', method 'STARTTLS' will be"));
496 printf (_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT); 466 printf(_(" implied (using default port %i) unless --port=636 is specified. In that case\n"), DEFAULT_PORT);
497 printf (" %s\n", _("'SSL on connect' will be used no matter how the plugin was called.")); 467 printf(" %s\n", _("'SSL on connect' will be used no matter how the plugin was called."));
498 printf (" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags")); 468 printf(" %s\n", _("This detection is deprecated, please use 'check_ldap' with the '--starttls' or '--ssl' flags"));
499 printf (" %s\n", _("to define the behaviour explicitly instead.")); 469 printf(" %s\n", _("to define the behaviour explicitly instead."));
500 printf (" %s\n", _("The parameters --warn-entries and --crit-entries are optional.")); 470 printf(" %s\n", _("The parameters --warn-entries and --crit-entries are optional."));
501 471
502 printf (UT_SUPPORT); 472 printf(UT_SUPPORT);
503} 473}
504 474
505void 475void print_usage(void) {
506print_usage (void) 476 printf("%s\n", _("Usage:"));
507{ 477 printf(" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]", progname);
508 printf ("%s\n", _("Usage:")); 478 printf("\n [-P <password>] [-w <warn_time>] [-c <crit_time>] [-t timeout]%s\n",
509 printf (" %s -H <host> -b <base_dn> [-p <port>] [-a <attr>] [-D <binddn>]",progname);
510 printf ("\n [-P <password>] [-w <warn_time>] [-c <crit_time>] [-t timeout]%s\n",
511#ifdef HAVE_LDAP_SET_OPTION 479#ifdef HAVE_LDAP_SET_OPTION
512 "\n [-2|-3] [-4|-6]" 480 "\n [-2|-3] [-4|-6]"
513#else 481#else
514 "" 482 ""
515#endif 483#endif
516 ); 484 );
517} 485}
diff --git a/plugins/check_ldap.d/config.h b/plugins/check_ldap.d/config.h
new file mode 100644
index 00000000..c8a40610
--- /dev/null
+++ b/plugins/check_ldap.d/config.h
@@ -0,0 +1,60 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7static char ld_defattr[] = "(objectclass=*)";
8
9enum {
10#ifdef HAVE_LDAP_SET_OPTION
11 DEFAULT_PROTOCOL = 2,
12#endif
13};
14
15typedef struct {
16 char *ld_host;
17 char *ld_base;
18 char *ld_passwd;
19 char *ld_binddn;
20 char *ld_attr;
21 int ld_port;
22 bool starttls;
23 bool ssl_on_connect;
24#ifdef HAVE_LDAP_SET_OPTION
25 int ld_protocol;
26#endif
27
28 char *warn_entries;
29 char *crit_entries;
30 thresholds *entries_thresholds;
31 bool warn_time_set;
32 double warn_time;
33 bool crit_time_set;
34 double crit_time;
35} check_ldap_config;
36
37check_ldap_config check_ldap_config_init() {
38 check_ldap_config tmp = {
39 .ld_host = NULL,
40 .ld_base = NULL,
41 .ld_passwd = NULL,
42 .ld_binddn = NULL,
43 .ld_attr = ld_defattr,
44 .ld_port = -1,
45 .starttls = false,
46 .ssl_on_connect = false,
47#ifdef HAVE_LDAP_SET_OPTION
48 .ld_protocol = DEFAULT_PROTOCOL,
49#endif
50
51 .warn_entries = NULL,
52 .crit_entries = NULL,
53 .entries_thresholds = NULL,
54 .warn_time_set = false,
55 .warn_time = 0,
56 .crit_time_set = false,
57 .crit_time = 0,
58 };
59 return tmp;
60}
diff --git a/plugins/check_load.c b/plugins/check_load.c
index 1431d130..2925bff3 100644
--- a/plugins/check_load.c
+++ b/plugins/check_load.c
@@ -1,350 +1,423 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_load plugin 3 * Monitoring check_load plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2007 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_load plugin 10 * This file contains the check_load plugin
11* 11 *
12* This plugin tests the current system load average. 12 * This plugin tests the current system load average.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_load"; 31const char *progname = "check_load";
32const char *copyright = "1999-2022"; 32const char *copyright = "1999-2022";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "./common.h" 35#include "./common.h"
36#include <string.h>
36#include "./runcmd.h" 37#include "./runcmd.h"
37#include "./utils.h" 38#include "./utils.h"
38#include "./popen.h" 39#include "./popen.h"
40#include "../lib/states.h"
41#include "../lib/output.h"
42#include "../lib/perfdata.h"
43#include "../lib/thresholds.h"
44#include "check_load.d/config.h"
39 45
40#include <string.h> 46// getloadavg comes from gnulib
41 47#include "../gl/stdlib.h"
42#ifdef HAVE_SYS_LOADAVG_H
43#include <sys/loadavg.h>
44#endif
45 48
46/* needed for compilation under NetBSD, as suggested by Andy Doran */ 49/* needed for compilation under NetBSD, as suggested by Andy Doran */
47#ifndef LOADAVG_1MIN 50#ifndef LOADAVG_1MIN
48#define LOADAVG_1MIN 0 51# define LOADAVG_1MIN 0
49#define LOADAVG_5MIN 1 52# define LOADAVG_5MIN 1
50#define LOADAVG_15MIN 2 53# define LOADAVG_15MIN 2
51#endif /* !defined LOADAVG_1MIN */ 54#endif /* !defined LOADAVG_1MIN */
52 55
56typedef struct {
57 int errorcode;
58 check_load_config config;
59} check_load_config_wrapper;
60static check_load_config_wrapper process_arguments(int argc, char **argv);
61
62void print_help(void);
63void print_usage(void);
64typedef struct {
65 int errorcode;
66 char **top_processes;
67} top_processes_result;
68static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show);
69
70typedef struct {
71 mp_range load[3];
72} parsed_thresholds;
73static parsed_thresholds get_threshold(char *arg) {
74 size_t index;
75 char *str = arg;
76 char *tmp_pointer;
77 bool valid = false;
78
79 parsed_thresholds result = {
80 .load =
81 {
82 mp_range_init(),
83 mp_range_init(),
84 mp_range_init(),
85 },
86 };
53 87
54static int process_arguments (int argc, char **argv); 88 size_t arg_length = strlen(arg);
55static int validate_arguments (void); 89 for (index = 0; index < 3; index++) {
56void print_help (void); 90 double tmp = strtod(str, &tmp_pointer);
57void print_usage (void); 91 if (tmp_pointer == str) {
58static int print_top_consuming_processes(); 92 break;
59 93 }
60static int n_procs_to_show = 0;
61
62/* strictly for pretty-print usage in loops */
63static const int nums[3] = { 1, 5, 15 };
64
65/* provide some fairly sane defaults */
66double wload[3] = { 0.0, 0.0, 0.0 };
67double cload[3] = { 0.0, 0.0, 0.0 };
68#define la1 la[0]
69#define la5 la[1]
70#define la15 la[2]
71
72char *status_line;
73bool take_into_account_cpus = false;
74
75static void
76get_threshold(char *arg, double *th)
77{
78 size_t i, n;
79 int valid = 0;
80 char *str = arg, *p;
81 94
82 n = strlen(arg); 95 result.load[index] = mp_range_set_end(result.load[index], mp_create_pd_value(tmp));
83 for(i = 0; i < 3; i++) {
84 th[i] = strtod(str, &p);
85 if(p == str) break;
86 96
87 valid = 1; 97 valid = true;
88 str = p + 1; 98 str = tmp_pointer + 1;
89 if(n <= (size_t)(str - arg)) break; 99 if (arg_length <= (size_t)(str - arg)) {
100 break;
101 }
90 } 102 }
91 103
92 /* empty argument or non-floatish, so warn about it and die */ 104 /* empty argument or non-floatish, so warn about it and die */
93 if(!i && !valid) usage (_("Warning threshold must be float or float triplet!\n")); 105 if (!index && !valid) {
106 usage(_("Warning threshold must be float or float triplet!\n"));
107 }
94 108
95 if(i != 2) { 109 if (index != 2) {
96 /* one or more numbers were given, so fill array with last 110 /* one or more numbers were given, so fill array with last
97 * we got (most likely to NOT produce the least expected result) */ 111 * we got (most likely to NOT produce the least expected result) */
98 for(n = i; n < 3; n++) th[n] = th[i]; 112 for (size_t tmp_index = index; tmp_index < 3; tmp_index++) {
113 result.load[tmp_index] = result.load[index];
114 }
99 } 115 }
116 return result;
100} 117}
101 118
102 119int main(int argc, char **argv) {
103int 120 setlocale(LC_ALL, "");
104main (int argc, char **argv) 121 bindtextdomain(PACKAGE, LOCALEDIR);
105{ 122 textdomain(PACKAGE);
106 int result = -1;
107 int i;
108 long numcpus;
109
110 double la[3] = { 0.0, 0.0, 0.0 }; /* NetBSD complains about uninitialized arrays */
111#ifndef HAVE_GETLOADAVG
112 char input_buffer[MAX_INPUT_BUFFER];
113#endif
114
115 setlocale (LC_ALL, "");
116 bindtextdomain (PACKAGE, LOCALEDIR);
117 textdomain (PACKAGE);
118 setlocale(LC_NUMERIC, "POSIX"); 123 setlocale(LC_NUMERIC, "POSIX");
119 124
120 /* Parse extra opts if any */ 125 /* Parse extra opts if any */
121 argv = np_extra_opts (&argc, argv, progname); 126 argv = np_extra_opts(&argc, argv, progname);
122 127
123 if (process_arguments (argc, argv) == ERROR) 128 check_load_config_wrapper tmp_config = process_arguments(argc, argv);
124 usage4 (_("Could not parse arguments")); 129 if (tmp_config.errorcode == ERROR) {
125 130 usage4(_("Could not parse arguments"));
126#ifdef HAVE_GETLOADAVG
127 result = getloadavg (la, 3);
128 if (result != 3)
129 return STATE_UNKNOWN;
130#else
131 child_process = spopen (PATH_TO_UPTIME);
132 if (child_process == NULL) {
133 printf (_("Error opening %s\n"), PATH_TO_UPTIME);
134 return STATE_UNKNOWN;
135 } 131 }
136 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 132
137 if (child_stderr == NULL) { 133 const check_load_config config = tmp_config.config;
138 printf (_("Could not open stderr for %s\n"), PATH_TO_UPTIME); 134
135 double load_values[3] = {0, 0, 0};
136
137 // this should be getloadavg from gnulib, should work everywhereâ„¢
138 int error = getloadavg(load_values, 3);
139 if (error != 3) {
140 die(STATE_UNKNOWN, _("Failed to retrieve load values"));
139 } 141 }
140 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process); 142
141 if(strstr(input_buffer, "load average:")) { 143 mp_check overall = mp_check_init();
142 sscanf (input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15); 144 if (config.output_format_set) {
143 } 145 mp_set_format(config.output_format);
144 else if(strstr(input_buffer, "load averages:")) {
145 sscanf (input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15);
146 }
147 else {
148 printf (_("could not parse load from uptime %s: %d\n"), PATH_TO_UPTIME, result);
149 return STATE_UNKNOWN;
150 }
151
152 result = spclose (child_process);
153 if (result) {
154 printf (_("Error code %d returned in %s\n"), result, PATH_TO_UPTIME);
155 return STATE_UNKNOWN;
156 } 146 }
157#endif 147
158 148 bool is_using_scaled_load_values = false;
159 if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) { 149 long numcpus;
160#ifdef HAVE_GETLOADAVG 150 if (config.take_into_account_cpus && ((numcpus = GET_NUMBER_OF_CPUS()) > 0)) {
161 printf (_("Error in getloadavg()\n")); 151 is_using_scaled_load_values = true;
162#else 152
163 printf (_("Error processing %s\n"), PATH_TO_UPTIME); 153 double scaled_la[3] = {
164#endif 154 load_values[0] / numcpus,
165 return STATE_UNKNOWN; 155 load_values[1] / numcpus,
156 load_values[2] / numcpus,
157 };
158
159 mp_subcheck scaled_load_sc = mp_subcheck_init();
160 scaled_load_sc = mp_set_subcheck_default_state(scaled_load_sc, STATE_OK);
161 scaled_load_sc.output = "Scaled Load (divided by number of CPUs";
162
163 mp_perfdata pd_scaled_load1 = perfdata_init();
164 pd_scaled_load1.label = "scaled_load1";
165 pd_scaled_load1 = mp_set_pd_value(pd_scaled_load1, scaled_la[0]);
166 pd_scaled_load1 = mp_pd_set_thresholds(pd_scaled_load1, config.th_load[0]);
167
168 mp_subcheck scaled_load_sc1 = mp_subcheck_init();
169 scaled_load_sc1 = mp_set_subcheck_state(scaled_load_sc1, mp_get_pd_status(pd_scaled_load1));
170 mp_add_perfdata_to_subcheck(&scaled_load_sc1, pd_scaled_load1);
171 xasprintf(&scaled_load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_scaled_load1.value));
172 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc1);
173
174 mp_perfdata pd_scaled_load5 = perfdata_init();
175 pd_scaled_load5.label = "scaled_load5";
176 pd_scaled_load5 = mp_set_pd_value(pd_scaled_load5, scaled_la[1]);
177 pd_scaled_load5 = mp_pd_set_thresholds(pd_scaled_load5, config.th_load[1]);
178
179 mp_subcheck scaled_load_sc5 = mp_subcheck_init();
180 scaled_load_sc5 = mp_set_subcheck_state(scaled_load_sc5, mp_get_pd_status(pd_scaled_load5));
181 mp_add_perfdata_to_subcheck(&scaled_load_sc5, pd_scaled_load5);
182 xasprintf(&scaled_load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_scaled_load5.value));
183 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc5);
184
185 mp_perfdata pd_scaled_load15 = perfdata_init();
186 pd_scaled_load15.label = "scaled_load15";
187 pd_scaled_load15 = mp_set_pd_value(pd_scaled_load15, scaled_la[2]);
188 pd_scaled_load15 = mp_pd_set_thresholds(pd_scaled_load15, config.th_load[2]);
189
190 mp_subcheck scaled_load_sc15 = mp_subcheck_init();
191 scaled_load_sc15 = mp_set_subcheck_state(scaled_load_sc15, mp_get_pd_status(pd_scaled_load15));
192 mp_add_perfdata_to_subcheck(&scaled_load_sc15, pd_scaled_load15);
193 xasprintf(&scaled_load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_scaled_load15.value));
194 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc15);
195
196 mp_add_subcheck_to_check(&overall, scaled_load_sc);
166 } 197 }
167 198
168 /* we got this far, so assume OK until we've measured */ 199 mp_subcheck load_sc = mp_subcheck_init();
169 result = STATE_OK; 200 load_sc = mp_set_subcheck_default_state(load_sc, STATE_OK);
201 load_sc.output = "Total Load";
170 202
171 xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15); 203 mp_perfdata pd_load1 = perfdata_init();
172 xasprintf(&status_line, ("total %s"), status_line); 204 pd_load1.label = "load1";
205 pd_load1 = mp_set_pd_value(pd_load1, load_values[0]);
206 if (!is_using_scaled_load_values) {
207 pd_load1 = mp_pd_set_thresholds(pd_load1, config.th_load[0]);
208 }
173 209
210 mp_subcheck load_sc1 = mp_subcheck_init();
211 load_sc1 = mp_set_subcheck_state(load_sc1, mp_get_pd_status(pd_load1));
212 mp_add_perfdata_to_subcheck(&load_sc1, pd_load1);
213 xasprintf(&load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_load1.value));
214 mp_add_subcheck_to_subcheck(&load_sc, load_sc1);
215
216 mp_perfdata pd_load5 = perfdata_init();
217 pd_load5.label = "load5";
218 pd_load5 = mp_set_pd_value(pd_load5, load_values[1]);
219 if (!is_using_scaled_load_values) {
220 pd_load5 = mp_pd_set_thresholds(pd_load5, config.th_load[1]);
221 }
174 222
175 double scaled_la[3] = { 0.0, 0.0, 0.0 }; 223 mp_subcheck load_sc5 = mp_subcheck_init();
176 bool is_using_scaled_load_values = false; 224 load_sc5 = mp_set_subcheck_state(load_sc5, mp_get_pd_status(pd_load5));
225 mp_add_perfdata_to_subcheck(&load_sc5, pd_load5);
226 xasprintf(&load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_load5.value));
227 mp_add_subcheck_to_subcheck(&load_sc, load_sc5);
228
229 mp_perfdata pd_load15 = perfdata_init();
230 pd_load15.label = "load15";
231 pd_load15 = mp_set_pd_value(pd_load15, load_values[2]);
232 if (!is_using_scaled_load_values) {
233 pd_load15 = mp_pd_set_thresholds(pd_load15, config.th_load[2]);
234 }
177 235
178 if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) { 236 mp_subcheck load_sc15 = mp_subcheck_init();
179 is_using_scaled_load_values = true; 237 load_sc15 = mp_set_subcheck_state(load_sc15, mp_get_pd_status(pd_load15));
238 mp_add_perfdata_to_subcheck(&load_sc15, pd_load15);
239 xasprintf(&load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_load15.value));
240 mp_add_subcheck_to_subcheck(&load_sc, load_sc15);
180 241
181 scaled_la[0] = la[0] / numcpus; 242 mp_add_subcheck_to_check(&overall, load_sc);
182 scaled_la[1] = la[1] / numcpus;
183 scaled_la[2] = la[2] / numcpus;
184 243
185 char *tmp = NULL; 244 if (config.n_procs_to_show > 0) {
186 xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]); 245 mp_subcheck top_proc_sc = mp_subcheck_init();
187 xasprintf(&status_line, "scaled %s - %s", tmp, status_line); 246 top_proc_sc = mp_set_subcheck_state(top_proc_sc, STATE_OK);
188 } 247 top_processes_result top_proc = print_top_consuming_processes(config.n_procs_to_show);
248 xasprintf(&top_proc_sc.output, "Top %lu CPU time consuming processes", config.n_procs_to_show);
189 249
190 for(i = 0; i < 3; i++) { 250 if (top_proc.errorcode == OK) {
191 if (is_using_scaled_load_values) { 251 for (unsigned long i = 0; i < config.n_procs_to_show; i++) {
192 if(scaled_la[i] > cload[i]) { 252 xasprintf(&top_proc_sc.output, "%s\n%s", top_proc_sc.output, top_proc.top_processes[i]);
193 result = STATE_CRITICAL;
194 break;
195 }
196 else if(scaled_la[i] > wload[i]) result = STATE_WARNING;
197 } else {
198 if(la[i] > cload[i]) {
199 result = STATE_CRITICAL;
200 break;
201 } 253 }
202 else if(la[i] > wload[i]) result = STATE_WARNING;
203 } 254 }
204 }
205 255
206 printf("LOAD %s - %s|", state_text(result), status_line); 256 mp_add_subcheck_to_check(&overall, top_proc_sc);
207 for(i = 0; i < 3; i++) {
208 if (is_using_scaled_load_values) {
209 printf("load%d=%.3f;;;0; ", nums[i], la[i]);
210 printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]);
211 } else {
212 printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]);
213 }
214 } 257 }
215 258
216 putchar('\n'); 259 mp_exit(overall);
217 if (n_procs_to_show > 0) {
218 print_top_consuming_processes();
219 }
220 return result;
221} 260}
222 261
223
224/* process command-line arguments */ 262/* process command-line arguments */
225static int 263static check_load_config_wrapper process_arguments(int argc, char **argv) {
226process_arguments (int argc, char **argv) 264
227{ 265 enum {
228 int c = 0; 266 output_format_index = CHAR_MAX + 1,
229
230 int option = 0;
231 static struct option longopts[] = {
232 {"warning", required_argument, 0, 'w'},
233 {"critical", required_argument, 0, 'c'},
234 {"percpu", no_argument, 0, 'r'},
235 {"version", no_argument, 0, 'V'},
236 {"help", no_argument, 0, 'h'},
237 {"procs-to-show", required_argument, 0, 'n'},
238 {0, 0, 0, 0}
239 }; 267 };
240 268
241 if (argc < 2) 269 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
242 return ERROR; 270 {"critical", required_argument, 0, 'c'},
271 {"percpu", no_argument, 0, 'r'},
272 {"version", no_argument, 0, 'V'},
273 {"help", no_argument, 0, 'h'},
274 {"procs-to-show", required_argument, 0, 'n'},
275 {"output-format", required_argument, 0, output_format_index},
276 {0, 0, 0, 0}};
277
278 check_load_config_wrapper result = {
279 .errorcode = OK,
280 .config = check_load_config_init(),
281 };
243 282
244 while (1) { 283 if (argc < 2) {
245 c = getopt_long (argc, argv, "Vhrc:w:n:", longopts, &option); 284 result.errorcode = ERROR;
285 return result;
286 }
246 287
247 if (c == -1 || c == EOF) 288 while (true) {
248 break; 289 int option = 0;
290 int option_index = getopt_long(argc, argv, "Vhrc:w:n:", longopts, &option);
249 291
250 switch (c) { 292 if (option_index == -1 || option_index == EOF) {
251 case 'w': /* warning time threshold */
252 get_threshold(optarg, wload);
253 break; 293 break;
254 case 'c': /* critical time threshold */ 294 }
255 get_threshold(optarg, cload); 295
296 switch (option_index) {
297 case output_format_index: {
298 parsed_output_format parser = mp_parse_output_format(optarg);
299 if (!parser.parsing_success) {
300 printf("Invalid output format: %s\n", optarg);
301 exit(STATE_UNKNOWN);
302 }
303
304 result.config.output_format_set = true;
305 result.config.output_format = parser.output_format;
256 break; 306 break;
307 }
308 case 'w': /* warning time threshold */ {
309 parsed_thresholds warning_range = get_threshold(optarg);
310 result.config.th_load[0].warning = warning_range.load[0];
311 result.config.th_load[0].warning_is_set = true;
312
313 result.config.th_load[1].warning = warning_range.load[1];
314 result.config.th_load[1].warning_is_set = true;
315
316 result.config.th_load[2].warning = warning_range.load[2];
317 result.config.th_load[2].warning_is_set = true;
318 } break;
319 case 'c': /* critical time threshold */ {
320 parsed_thresholds critical_range = get_threshold(optarg);
321 result.config.th_load[0].critical = critical_range.load[0];
322 result.config.th_load[0].critical_is_set = true;
323
324 result.config.th_load[1].critical = critical_range.load[1];
325 result.config.th_load[1].critical_is_set = true;
326
327 result.config.th_load[2].critical = critical_range.load[2];
328 result.config.th_load[2].critical_is_set = true;
329 } break;
257 case 'r': /* Divide load average by number of CPUs */ 330 case 'r': /* Divide load average by number of CPUs */
258 take_into_account_cpus = true; 331 result.config.take_into_account_cpus = true;
259 break; 332 break;
260 case 'V': /* version */ 333 case 'V': /* version */
261 print_revision (progname, NP_VERSION); 334 print_revision(progname, NP_VERSION);
262 exit (STATE_UNKNOWN); 335 exit(STATE_UNKNOWN);
263 case 'h': /* help */ 336 case 'h': /* help */
264 print_help (); 337 print_help();
265 exit (STATE_UNKNOWN); 338 exit(STATE_UNKNOWN);
266 case 'n': 339 case 'n':
267 n_procs_to_show = atoi(optarg); 340 result.config.n_procs_to_show = (unsigned long)atol(optarg);
268 break; 341 break;
269 case '?': /* help */ 342 case '?': /* help */
270 usage5 (); 343 usage5();
271 } 344 }
272 } 345 }
273 346
274 c = optind; 347 int index = optind;
275 if (c == argc) 348 if (index == argc) {
276 return validate_arguments (); 349 return result;
350 }
277 351
278 /* handle the case if both arguments are missing, 352 /* handle the case if both arguments are missing,
279 * but not if only one is given without -c or -w flag */ 353 * but not if only one is given without -c or -w flag */
280 if(c - argc == 2) { 354 if (index - argc == 2) {
281 get_threshold(argv[c++], wload); 355 parsed_thresholds warning_range = get_threshold(argv[index++]);
282 get_threshold(argv[c++], cload); 356 result.config.th_load[0].warning = warning_range.load[0];
283 } 357 result.config.th_load[0].warning_is_set = true;
284 else if(c - argc == 1) { 358
285 get_threshold(argv[c++], cload); 359 result.config.th_load[1].warning = warning_range.load[1];
360 result.config.th_load[1].warning_is_set = true;
361
362 result.config.th_load[2].warning = warning_range.load[2];
363 result.config.th_load[2].warning_is_set = true;
364 parsed_thresholds critical_range = get_threshold(argv[index++]);
365 result.config.th_load[0].critical = critical_range.load[0];
366 result.config.th_load[0].critical_is_set = true;
367
368 result.config.th_load[1].critical = critical_range.load[1];
369 result.config.th_load[1].critical_is_set = true;
370
371 result.config.th_load[2].critical = critical_range.load[2];
372 result.config.th_load[2].critical_is_set = true;
373 } else if (index - argc == 1) {
374 parsed_thresholds critical_range = get_threshold(argv[index++]);
375 result.config.th_load[0].critical = critical_range.load[0];
376 result.config.th_load[0].critical_is_set = true;
377
378 result.config.th_load[1].critical = critical_range.load[1];
379 result.config.th_load[1].critical_is_set = true;
380
381 result.config.th_load[2].critical = critical_range.load[2];
382 result.config.th_load[2].critical_is_set = true;
286 } 383 }
287 384
288 return validate_arguments (); 385 return result;
289}
290
291
292static int
293validate_arguments (void)
294{
295 int i = 0;
296
297 /* match cload first, as it will give the most friendly error message
298 * if user hasn't given the -c switch properly */
299 for(i = 0; i < 3; i++) {
300 if(cload[i] < 0)
301 die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]);
302 if(wload[i] < 0)
303 die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]);
304 if(wload[i] > cload[i])
305 die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]);
306 }
307
308 return OK;
309} 386}
310 387
388void print_help(void) {
389 print_revision(progname, NP_VERSION);
311 390
312void 391 printf("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
313print_help (void) 392 printf(COPYRIGHT, copyright, email);
314{
315 print_revision (progname, NP_VERSION);
316
317 printf ("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
318 printf (COPYRIGHT, copyright, email);
319 393
320 printf (_("This plugin tests the current system load average.")); 394 printf(_("This plugin tests the current system load average."));
321 395
322 printf ("\n\n"); 396 printf("\n\n");
323 397
324 print_usage (); 398 print_usage();
325 399
326 printf (UT_HELP_VRSN); 400 printf(UT_HELP_VRSN);
327 printf (UT_EXTRA_OPTS); 401 printf(UT_EXTRA_OPTS);
328 402
329 printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15"); 403 printf(" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
330 printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn")); 404 printf(" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
331 printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15"); 405 printf(" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
332 printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn")); 406 printf(" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
333 printf (" %s\n", _("the load average format is the same used by \"uptime\" and \"w\"")); 407 printf(" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
334 printf (" %s\n", "-r, --percpu"); 408 printf(" %s\n", "-r, --percpu");
335 printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)")); 409 printf(" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
336 printf (" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS"); 410 printf(" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
337 printf (" %s\n", _("Number of processes to show when printing the top consuming processes.")); 411 printf(" %s\n", _("Number of processes to show when printing the top consuming processes."));
338 printf (" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0")); 412 printf(" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
339 413
340 printf (UT_SUPPORT); 414 printf(UT_OUTPUT_FORMAT);
415 printf(UT_SUPPORT);
341} 416}
342 417
343void 418void print_usage(void) {
344print_usage (void) 419 printf("%s\n", _("Usage:"));
345{ 420 printf("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
346 printf ("%s\n", _("Usage:"));
347 printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
348} 421}
349 422
350#ifdef PS_USES_PROCPCPU 423#ifdef PS_USES_PROCPCPU
@@ -356,36 +429,51 @@ int cmpstringp(const void *p1, const void *p2) {
356 int procrss = 0; 429 int procrss = 0;
357 float procpcpu = 0; 430 float procpcpu = 0;
358 char procstat[8]; 431 char procstat[8];
359#ifdef PS_USES_PROCETIME 432# ifdef PS_USES_PROCETIME
360 char procetime[MAX_INPUT_BUFFER]; 433 char procetime[MAX_INPUT_BUFFER];
361#endif /* PS_USES_PROCETIME */ 434# endif /* PS_USES_PROCETIME */
362 char procprog[MAX_INPUT_BUFFER]; 435 char procprog[MAX_INPUT_BUFFER];
363 int pos; 436 int pos;
364 sscanf (* (char * const *) p1, PS_FORMAT, PS_VARLIST); 437 sscanf(*(char *const *)p1, PS_FORMAT, PS_VARLIST);
365 float procpcpu1 = procpcpu; 438 float procpcpu1 = procpcpu;
366 sscanf (* (char * const *) p2, PS_FORMAT, PS_VARLIST); 439 sscanf(*(char *const *)p2, PS_FORMAT, PS_VARLIST);
367 return procpcpu1 < procpcpu; 440 return procpcpu1 < procpcpu;
368} 441}
369#endif /* PS_USES_PROCPCPU */ 442#endif /* PS_USES_PROCPCPU */
370 443
371static int print_top_consuming_processes() { 444static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show) {
372 int i = 0; 445 top_processes_result result = {
373 struct output chld_out, chld_err; 446 .errorcode = OK,
374 if(np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0){ 447 };
448 struct output chld_out;
449 struct output chld_err;
450 if (np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0) {
375 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND); 451 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND);
376 return STATE_UNKNOWN; 452 result.errorcode = ERROR;
453 return result;
377 } 454 }
455
378 if (chld_out.lines < 2) { 456 if (chld_out.lines < 2) {
379 fprintf(stderr, _("some error occurred getting procs list.\n")); 457 fprintf(stderr, _("some error occurred getting procs list.\n"));
380 return STATE_UNKNOWN; 458 result.errorcode = ERROR;
459 return result;
381 } 460 }
461
382#ifdef PS_USES_PROCPCPU 462#ifdef PS_USES_PROCPCPU
383 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char*), cmpstringp); 463 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char *), cmpstringp);
384#endif /* PS_USES_PROCPCPU */ 464#endif /* PS_USES_PROCPCPU */
385 int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) 465 unsigned long lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) ? chld_out.lines : n_procs_to_show + 1;
386 ? (int)chld_out.lines : n_procs_to_show + 1; 466
387 for (i = 0; i < lines_to_show; i += 1) { 467 result.top_processes = calloc(lines_to_show, sizeof(char *));
388 printf("%s\n", chld_out.line[i]); 468 if (result.top_processes == NULL) {
469 // Failed allocation
470 result.errorcode = ERROR;
471 return result;
389 } 472 }
390 return OK; 473
474 for (unsigned long i = 0; i < lines_to_show; i += 1) {
475 xasprintf(&result.top_processes[i], "%s", chld_out.line[i]);
476 }
477
478 return result;
391} 479}
diff --git a/plugins/check_load.d/config.h b/plugins/check_load.d/config.h
new file mode 100644
index 00000000..fd735455
--- /dev/null
+++ b/plugins/check_load.d/config.h
@@ -0,0 +1,30 @@
1#pragma once
2
3#include "output.h"
4#include "thresholds.h"
5typedef struct {
6 mp_thresholds th_load[3];
7
8 bool take_into_account_cpus;
9 unsigned long n_procs_to_show;
10
11 mp_output_format output_format;
12 bool output_format_set;
13} check_load_config;
14
15check_load_config check_load_config_init() {
16 check_load_config tmp = {
17 .th_load =
18 {
19 mp_thresholds_init(),
20 mp_thresholds_init(),
21 mp_thresholds_init(),
22 },
23
24 .take_into_account_cpus = false,
25 .n_procs_to_show = 0,
26
27 .output_format_set = false,
28 };
29 return tmp;
30}
diff --git a/plugins/check_mrtg.c b/plugins/check_mrtg.c
index 826b77e9..5bd276dc 100644
--- a/plugins/check_mrtg.c
+++ b/plugins/check_mrtg.c
@@ -1,385 +1,368 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_mrtg plugin 3 * Monitoring check_mrtg plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_mrtg plugin 10 * This file contains the check_mrtg plugin
11* 11 *
12* This plugin will check either the average or maximum value of one of the 12 * This plugin will check either the average or maximum value of one of the
13* two variables recorded in an MRTG log file. 13 * two variables recorded in an MRTG log file.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_mrtg"; 32const char *progname = "check_mrtg";
33const char *copyright = "1999-2007"; 33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "check_mrtg.d/config.h"
38 39
39int process_arguments (int, char **); 40typedef struct {
40int validate_arguments (void); 41 int errorcode;
41void print_help (void); 42 check_mrtg_config config;
42void print_usage (void); 43} check_mrtg_config_wrapper;
43 44static check_mrtg_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
44char *log_file = NULL; 45static check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper /*config_wrapper*/);
45int expire_minutes = 0; 46
46bool use_average = true; 47static void print_help(void);
47int variable_number = -1; 48void print_usage(void);
48unsigned long value_warning_threshold = 0L;
49unsigned long value_critical_threshold = 0L;
50char *label;
51char *units;
52
53int
54main (int argc, char **argv)
55{
56 int result = STATE_OK;
57 FILE *fp;
58 int line;
59 char input_buffer[MAX_INPUT_BUFFER];
60 char *temp_buffer;
61 time_t current_time;
62 time_t timestamp = 0L;
63 unsigned long average_value_rate = 0L;
64 unsigned long maximum_value_rate = 0L;
65 unsigned long rate = 0L;
66 49
67 setlocale (LC_ALL, ""); 50int main(int argc, char **argv) {
68 bindtextdomain (PACKAGE, LOCALEDIR); 51 setlocale(LC_ALL, "");
69 textdomain (PACKAGE); 52 bindtextdomain(PACKAGE, LOCALEDIR);
53 textdomain(PACKAGE);
70 54
71 /* Parse extra opts if any */ 55 /* Parse extra opts if any */
72 argv=np_extra_opts (&argc, argv, progname); 56 argv = np_extra_opts(&argc, argv, progname);
73 57
74 if (process_arguments (argc, argv) == ERROR) 58 check_mrtg_config_wrapper tmp_config = process_arguments(argc, argv);
75 usage4 (_("Could not parse arguments\n")); 59 if (tmp_config.errorcode == ERROR) {
60 usage4(_("Could not parse arguments\n"));
61 }
62
63 const check_mrtg_config config = tmp_config.config;
76 64
77 /* open the MRTG log file for reading */ 65 /* open the MRTG log file for reading */
78 fp = fopen (log_file, "r"); 66 FILE *mtrg_log_file = fopen(config.log_file, "r");
79 if (fp == NULL) { 67 if (mtrg_log_file == NULL) {
80 printf (_("Unable to open MRTG log file\n")); 68 printf(_("Unable to open MRTG log file\n"));
81 return STATE_UNKNOWN; 69 return STATE_UNKNOWN;
82 } 70 }
83 71
84 line = 0; 72 time_t timestamp = 0;
85 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) { 73 unsigned long average_value_rate = 0;
86 74 unsigned long maximum_value_rate = 0;
75 char input_buffer[MAX_INPUT_BUFFER];
76 int line = 0;
77 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mtrg_log_file)) {
87 line++; 78 line++;
88 79
89 /* skip the first line of the log file */ 80 /* skip the first line of the log file */
90 if (line == 1) 81 if (line == 1) {
91 continue; 82 continue;
83 }
92 84
93 /* break out of read loop if we've passed the number of entries we want to read */ 85 /* break out of read loop if we've passed the number of entries we want to read */
94 if (line > 2) 86 if (line > 2) {
95 break; 87 break;
88 }
96 89
97 /* grab the timestamp */ 90 /* grab the timestamp */
98 temp_buffer = strtok (input_buffer, " "); 91 char *temp_buffer = strtok(input_buffer, " ");
99 timestamp = strtoul (temp_buffer, NULL, 10); 92 timestamp = strtoul(temp_buffer, NULL, 10);
100 93
101 /* grab the average value 1 rate */ 94 /* grab the average value 1 rate */
102 temp_buffer = strtok (NULL, " "); 95 temp_buffer = strtok(NULL, " ");
103 if (variable_number == 1) 96 if (config.variable_number == 1) {
104 average_value_rate = strtoul (temp_buffer, NULL, 10); 97 average_value_rate = strtoul(temp_buffer, NULL, 10);
98 }
105 99
106 /* grab the average value 2 rate */ 100 /* grab the average value 2 rate */
107 temp_buffer = strtok (NULL, " "); 101 temp_buffer = strtok(NULL, " ");
108 if (variable_number == 2) 102 if (config.variable_number == 2) {
109 average_value_rate = strtoul (temp_buffer, NULL, 10); 103 average_value_rate = strtoul(temp_buffer, NULL, 10);
104 }
110 105
111 /* grab the maximum value 1 rate */ 106 /* grab the maximum value 1 rate */
112 temp_buffer = strtok (NULL, " "); 107 temp_buffer = strtok(NULL, " ");
113 if (variable_number == 1) 108 if (config.variable_number == 1) {
114 maximum_value_rate = strtoul (temp_buffer, NULL, 10); 109 maximum_value_rate = strtoul(temp_buffer, NULL, 10);
110 }
115 111
116 /* grab the maximum value 2 rate */ 112 /* grab the maximum value 2 rate */
117 temp_buffer = strtok (NULL, " "); 113 temp_buffer = strtok(NULL, " ");
118 if (variable_number == 2) 114 if (config.variable_number == 2) {
119 maximum_value_rate = strtoul (temp_buffer, NULL, 10); 115 maximum_value_rate = strtoul(temp_buffer, NULL, 10);
116 }
120 } 117 }
121 118
122 /* close the log file */ 119 /* close the log file */
123 fclose (fp); 120 fclose(mtrg_log_file);
124 121
125 /* if we couldn't read enough data, return an unknown error */ 122 /* if we couldn't read enough data, return an unknown error */
126 if (line <= 2) { 123 if (line <= 2) {
127 printf (_("Unable to process MRTG log file\n")); 124 printf(_("Unable to process MRTG log file\n"));
128 return STATE_UNKNOWN; 125 return STATE_UNKNOWN;
129 } 126 }
130 127
131 /* make sure the MRTG data isn't too old */ 128 /* make sure the MRTG data isn't too old */
132 time (&current_time); 129 time_t current_time;
133 if (expire_minutes > 0 130 time(&current_time);
134 && (current_time - timestamp) > (expire_minutes * 60)) { 131 if (config.expire_minutes > 0 && (current_time - timestamp) > (config.expire_minutes * 60)) {
135 printf (_("MRTG data has expired (%d minutes old)\n"), 132 printf(_("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60));
136 (int) ((current_time - timestamp) / 60));
137 return STATE_WARNING; 133 return STATE_WARNING;
138 } 134 }
139 135
136 unsigned long rate = 0L;
140 /* else check the incoming/outgoing rates */ 137 /* else check the incoming/outgoing rates */
141 if (use_average) 138 if (config.use_average) {
142 rate = average_value_rate; 139 rate = average_value_rate;
143 else 140 } else {
144 rate = maximum_value_rate; 141 rate = maximum_value_rate;
142 }
145 143
146 if (rate > value_critical_threshold) 144 int result = STATE_OK;
145 if (config.value_critical_threshold_set && rate > config.value_critical_threshold) {
147 result = STATE_CRITICAL; 146 result = STATE_CRITICAL;
148 else if (rate > value_warning_threshold) 147 } else if (config.value_warning_threshold_set && rate > config.value_warning_threshold) {
149 result = STATE_WARNING; 148 result = STATE_WARNING;
149 }
150 150
151 printf("%s. %s = %lu %s|%s\n", 151 printf("%s. %s = %lu %s|%s\n", (config.use_average) ? _("Avg") : _("Max"), config.label, rate, config.units,
152 (use_average) ? _("Avg") : _("Max"), 152 perfdata(config.label, (long)rate, config.units, config.value_warning_threshold_set, (long)config.value_warning_threshold,
153 label, rate, units, 153 config.value_critical_threshold_set, (long)config.value_critical_threshold, 0, 0, 0, 0));
154 perfdata(label, (long) rate, units,
155 (int) value_warning_threshold, (long) value_warning_threshold,
156 (int) value_critical_threshold, (long) value_critical_threshold,
157 0, 0, 0, 0));
158 154
159 return result; 155 return result;
160} 156}
161 157
162
163
164/* process command-line arguments */ 158/* process command-line arguments */
165int 159check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
166process_arguments (int argc, char **argv)
167{
168 int c;
169
170 int option = 0;
171 static struct option longopts[] = { 160 static struct option longopts[] = {
172 {"logfile", required_argument, 0, 'F'}, 161 {"logfile", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'}, {"aggregation", required_argument, 0, 'a'},
173 {"expires", required_argument, 0, 'e'}, 162 {"variable", required_argument, 0, 'v'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'},
174 {"aggregation", required_argument, 0, 'a'}, 163 {"label", required_argument, 0, 'l'}, {"units", required_argument, 0, 'u'}, {"variable", required_argument, 0, 'v'},
175 {"variable", required_argument, 0, 'v'}, 164 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
176 {"critical", required_argument, 0, 'c'}, 165
177 {"warning", required_argument, 0, 'w'}, 166 check_mrtg_config_wrapper result = {
178 {"label", required_argument, 0, 'l'}, 167 .errorcode = OK,
179 {"units", required_argument, 0, 'u'}, 168 .config = check_mrtg_config_init(),
180 {"variable", required_argument, 0, 'v'},
181 {"version", no_argument, 0, 'V'},
182 {"help", no_argument, 0, 'h'},
183 {0, 0, 0, 0}
184 }; 169 };
185 170
186 if (argc < 2) 171 if (argc < 2) {
187 return ERROR; 172 result.errorcode = ERROR;
173 return result;
174 }
188 175
189 for (c = 1; c < argc; c++) { 176 for (int i = 1; i < argc; i++) {
190 if (strcmp ("-to", argv[c]) == 0) 177 if (strcmp("-to", argv[i]) == 0) {
191 strcpy (argv[c], "-t"); 178 strcpy(argv[i], "-t");
192 else if (strcmp ("-wt", argv[c]) == 0) 179 } else if (strcmp("-wt", argv[i]) == 0) {
193 strcpy (argv[c], "-w"); 180 strcpy(argv[i], "-w");
194 else if (strcmp ("-ct", argv[c]) == 0) 181 } else if (strcmp("-ct", argv[i]) == 0) {
195 strcpy (argv[c], "-c"); 182 strcpy(argv[i], "-c");
183 }
196 } 184 }
197 185
186 int option_char;
187 int option = 0;
198 while (1) { 188 while (1) {
199 c = getopt_long (argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, 189 option_char = getopt_long(argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, &option);
200 &option);
201 190
202 if (c == -1 || c == EOF) 191 if (option_char == -1 || option_char == EOF) {
203 break; 192 break;
193 }
204 194
205 switch (c) { 195 switch (option_char) {
206 case 'F': /* input file */ 196 case 'F': /* input file */
207 log_file = optarg; 197 result.config.log_file = optarg;
208 break; 198 break;
209 case 'e': /* ups name */ 199 case 'e': /* ups name */
210 expire_minutes = atoi (optarg); 200 result.config.expire_minutes = atoi(optarg);
211 break; 201 break;
212 case 'a': /* port */ 202 case 'a': /* port */
213 if (!strcmp (optarg, "MAX")) 203 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
214 use_average = false;
215 else
216 use_average = true;
217 break; 204 break;
218 case 'v': 205 case 'v':
219 variable_number = atoi (optarg); 206 result.config.variable_number = atoi(optarg);
220 if (variable_number < 1 || variable_number > 2) 207 if (result.config.variable_number < 1 || result.config.variable_number > 2) {
221 usage4 (_("Invalid variable number")); 208 usage4(_("Invalid variable number"));
209 }
222 break; 210 break;
223 case 'w': /* critical time threshold */ 211 case 'w': /* critical time threshold */
224 value_warning_threshold = strtoul (optarg, NULL, 10); 212 result.config.value_warning_threshold_set = true;
213 result.config.value_warning_threshold = strtoul(optarg, NULL, 10);
225 break; 214 break;
226 case 'c': /* warning time threshold */ 215 case 'c': /* warning time threshold */
227 value_critical_threshold = strtoul (optarg, NULL, 10); 216 result.config.value_critical_threshold_set = true;
217 result.config.value_critical_threshold = strtoul(optarg, NULL, 10);
228 break; 218 break;
229 case 'l': /* label */ 219 case 'l': /* label */
230 label = optarg; 220 result.config.label = optarg;
231 break; 221 break;
232 case 'u': /* timeout */ 222 case 'u': /* timeout */
233 units = optarg; 223 result.config.units = optarg;
234 break; 224 break;
235 case 'V': /* version */ 225 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 226 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 227 exit(STATE_UNKNOWN);
238 case 'h': /* help */ 228 case 'h': /* help */
239 print_help (); 229 print_help();
240 exit (STATE_UNKNOWN); 230 exit(STATE_UNKNOWN);
241 case '?': /* help */ 231 case '?': /* help */
242 usage5 (); 232 usage5();
243 } 233 }
244 } 234 }
245 235
246 c = optind; 236 option_char = optind;
247 if (log_file == NULL && argc > c) { 237 if (result.config.log_file == NULL && argc > option_char) {
248 log_file = argv[c++]; 238 result.config.log_file = argv[option_char++];
249 } 239 }
250 240
251 if (expire_minutes <= 0 && argc > c) { 241 if (result.config.expire_minutes <= 0 && argc > option_char) {
252 if (is_intpos (argv[c])) 242 if (is_intpos(argv[option_char])) {
253 expire_minutes = atoi (argv[c++]); 243 result.config.expire_minutes = atoi(argv[option_char++]);
254 else 244 } else {
255 die (STATE_UNKNOWN, 245 die(STATE_UNKNOWN, _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), argv[option_char], progname);
256 _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), 246 }
257 argv[c], progname);
258 } 247 }
259 248
260 if (argc > c && strcmp (argv[c], "MAX") == 0) { 249 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
261 use_average = false; 250 result.config.use_average = false;
262 c++; 251 option_char++;
263 } 252 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
264 else if (argc > c && strcmp (argv[c], "AVG") == 0) { 253 result.config.use_average = true;
265 use_average = true; 254 option_char++;
266 c++;
267 } 255 }
268 256
269 if (argc > c && variable_number == -1) { 257 if (argc > option_char && result.config.variable_number == -1) {
270 variable_number = atoi (argv[c++]); 258 result.config.variable_number = atoi(argv[option_char++]);
271 if (variable_number < 1 || variable_number > 2) { 259 if (result.config.variable_number < 1 || result.config.variable_number > 2) {
272 printf ("%s :", argv[c]); 260 printf("%s :", argv[option_char]);
273 usage (_("Invalid variable number\n")); 261 usage(_("Invalid variable number\n"));
274 } 262 }
275 } 263 }
276 264
277 if (argc > c && value_warning_threshold == 0) { 265 if (argc > option_char && !result.config.value_warning_threshold_set) {
278 value_warning_threshold = strtoul (argv[c++], NULL, 10); 266 result.config.value_warning_threshold_set = true;
267 result.config.value_warning_threshold = strtoul(argv[option_char++], NULL, 10);
279 } 268 }
280 269
281 if (argc > c && value_critical_threshold == 0) { 270 if (argc > option_char && !result.config.value_critical_threshold_set) {
282 value_critical_threshold = strtoul (argv[c++], NULL, 10); 271 result.config.value_critical_threshold_set = true;
272 result.config.value_critical_threshold = strtoul(argv[option_char++], NULL, 10);
283 } 273 }
284 274
285 if (argc > c && strlen (label) == 0) { 275 if (argc > option_char && strlen(result.config.label) == 0) {
286 label = argv[c++]; 276 result.config.label = argv[option_char++];
287 } 277 }
288 278
289 if (argc > c && strlen (units) == 0) { 279 if (argc > option_char && strlen(result.config.units) == 0) {
290 units = argv[c++]; 280 result.config.units = argv[option_char++];
291 } 281 }
292 282
293 return validate_arguments (); 283 return validate_arguments(result);
294} 284}
295 285
296int 286check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper config_wrapper) {
297validate_arguments (void) 287 if (config_wrapper.config.variable_number == -1) {
298{ 288 usage4(_("You must supply the variable number"));
299 if (variable_number == -1) 289 }
300 usage4 (_("You must supply the variable number"));
301 290
302 if (label == NULL) 291 if (config_wrapper.config.label == NULL) {
303 label = strdup ("value"); 292 config_wrapper.config.label = strdup("value");
293 }
304 294
305 if (units == NULL) 295 if (config_wrapper.config.units == NULL) {
306 units = strdup (""); 296 config_wrapper.config.units = strdup("");
297 }
307 298
308 return OK; 299 return config_wrapper;
309} 300}
310 301
311 302void print_help(void) {
312 303 print_revision(progname, NP_VERSION);
313void 304
314print_help (void) 305 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
315{ 306 printf(COPYRIGHT, copyright, email);
316 print_revision (progname, NP_VERSION); 307
317 308 printf("%s\n", _("This plugin will check either the average or maximum value of one of the"));
318 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 309 printf("%s\n", _("two variables recorded in an MRTG log file."));
319 printf (COPYRIGHT, copyright, email); 310
320 311 printf("\n\n");
321 printf ("%s\n", _("This plugin will check either the average or maximum value of one of the")); 312
322 printf ("%s\n", _("two variables recorded in an MRTG log file.")); 313 print_usage();
323 314
324 printf ("\n\n"); 315 printf(UT_HELP_VRSN);
325 316 printf(UT_EXTRA_OPTS);
326 print_usage (); 317
327 318 printf(" %s\n", "-F, --logfile=FILE");
328 printf (UT_HELP_VRSN); 319 printf(" %s\n", _("The MRTG log file containing the data you want to monitor"));
329 printf (UT_EXTRA_OPTS); 320 printf(" %s\n", "-e, --expires=MINUTES");
330 321 printf(" %s\n", _("Minutes before MRTG data is considered to be too old"));
331 printf (" %s\n", "-F, --logfile=FILE"); 322 printf(" %s\n", "-a, --aggregation=AVG|MAX");
332 printf (" %s\n", _("The MRTG log file containing the data you want to monitor")); 323 printf(" %s\n", _("Should we check average or maximum values?"));
333 printf (" %s\n", "-e, --expires=MINUTES"); 324 printf(" %s\n", "-v, --variable=INTEGER");
334 printf (" %s\n", _("Minutes before MRTG data is considered to be too old")); 325 printf(" %s\n", _("Which variable set should we inspect? (1 or 2)"));
335 printf (" %s\n", "-a, --aggregation=AVG|MAX"); 326 printf(" %s\n", "-w, --warning=INTEGER");
336 printf (" %s\n", _("Should we check average or maximum values?")); 327 printf(" %s\n", _("Threshold value for data to result in WARNING status"));
337 printf (" %s\n", "-v, --variable=INTEGER"); 328 printf(" %s\n", "-c, --critical=INTEGER");
338 printf (" %s\n", _("Which variable set should we inspect? (1 or 2)")); 329 printf(" %s\n", _("Threshold value for data to result in CRITICAL status"));
339 printf (" %s\n", "-w, --warning=INTEGER"); 330 printf(" %s\n", "-l, --label=STRING");
340 printf (" %s\n", _("Threshold value for data to result in WARNING status")); 331 printf(" %s\n", _("Type label for data (Examples: Conns, \"Processor Load\", In, Out)"));
341 printf (" %s\n", "-c, --critical=INTEGER"); 332 printf(" %s\n", "-u, --units=STRING");
342 printf (" %s\n", _("Threshold value for data to result in CRITICAL status")); 333 printf(" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,"));
343 printf (" %s\n", "-l, --label=STRING"); 334 printf(" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")"));
344 printf (" %s\n", _("Type label for data (Examples: Conns, \"Processor Load\", In, Out)")); 335
345 printf (" %s\n", "-u, --units=STRING"); 336 printf("\n");
346 printf (" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,")); 337 printf(" %s\n", _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If"));
347 printf (" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")")); 338 printf(" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If"));
348 339 printf(" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING"));
349 printf ("\n"); 340 printf(" %s\n", _("status is returned and a warning message is printed."));
350 printf (" %s\n", _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If")); 341
351 printf (" %s\n", _("the value exceeds the <vcl> threshold, a CRITICAL status is returned. If")); 342 printf("\n");
352 printf (" %s\n", _("the data in the log file is older than <expire_minutes> old, a WARNING")); 343 printf(" %s\n", _("This plugin is useful for monitoring MRTG data that does not correspond to"));
353 printf (" %s\n", _("status is returned and a warning message is printed.")); 344 printf(" %s\n", _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth)."));
354 345 printf(" %s\n", _("It can be used to monitor any kind of data that MRTG is monitoring - errors,"));
355 printf ("\n"); 346 printf(" %s\n", _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows"));
356 printf (" %s\n", _("This plugin is useful for monitoring MRTG data that does not correspond to")); 347 printf(" %s\n", _("me to track processor utilization, user connections, drive space, etc and"));
357 printf (" %s\n", _("bandwidth usage. (Use the check_mrtgtraf plugin for monitoring bandwidth).")); 348 printf(" %s\n\n", _("this plugin works well for monitoring that kind of data as well."));
358 printf (" %s\n", _("It can be used to monitor any kind of data that MRTG is monitoring - errors,")); 349
359 printf (" %s\n", _("packets/sec, etc. I use MRTG in conjunction with the Novell NLM that allows")); 350 printf("%s\n", _("Notes:"));
360 printf (" %s\n", _("me to track processor utilization, user connections, drive space, etc and")); 351 printf(" %s\n", _("- This plugin only monitors one of the two variables stored in the MRTG log"));
361 printf (" %s\n\n", _("this plugin works well for monitoring that kind of data as well.")); 352 printf(" %s\n", _("file. If you want to monitor both values you will have to define two"));
362 353 printf(" %s\n", _("commands with different values for the <variable> argument. Of course,"));
363 printf ("%s\n", _("Notes:")); 354 printf(" %s\n", _("you can always hack the code to make this plugin work for you..."));
364 printf (" %s\n", _("- This plugin only monitors one of the two variables stored in the MRTG log")); 355 printf(" %s\n", _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from"));
365 printf (" %s\n", _("file. If you want to monitor both values you will have to define two")); 356 printf(" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
366 printf (" %s\n", _("commands with different values for the <variable> argument. Of course,")); 357
367 printf (" %s\n", _("you can always hack the code to make this plugin work for you...")); 358 printf(UT_SUPPORT);
368 printf (" %s\n", _("- MRTG stands for the Multi Router Traffic Grapher. It can be downloaded from"));
369 printf (" %s\n", "http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
370
371 printf (UT_SUPPORT);
372} 359}
373 360
374
375
376/* original command line: 361/* original command line:
377 <log_file> <expire_minutes> <AVG|MAX> <variable> <vwl> <vcl> <label> [units] */ 362 <log_file> <expire_minutes> <AVG|MAX> <variable> <vwl> <vcl> <label> [units] */
378 363
379void 364void print_usage(void) {
380print_usage (void) 365 printf("%s\n", _("Usage:"));
381{ 366 printf("%s -F log_file -a <AVG | MAX> -v variable -w warning -c critical\n", progname);
382 printf ("%s\n", _("Usage:")); 367 printf("[-l label] [-u units] [-e expire_minutes] [-t timeout] [-v]\n");
383 printf ("%s -F log_file -a <AVG | MAX> -v variable -w warning -c critical\n",progname);
384 printf ("[-l label] [-u units] [-e expire_minutes] [-t timeout] [-v]\n");
385} 368}
diff --git a/plugins/check_mrtg.d/config.h b/plugins/check_mrtg.d/config.h
new file mode 100644
index 00000000..96b849a2
--- /dev/null
+++ b/plugins/check_mrtg.d/config.h
@@ -0,0 +1,36 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7typedef struct {
8 bool use_average;
9 int variable_number;
10 int expire_minutes;
11 char *label;
12 char *units;
13 char *log_file;
14
15 bool value_warning_threshold_set;
16 unsigned long value_warning_threshold;
17 bool value_critical_threshold_set;
18 unsigned long value_critical_threshold;
19} check_mrtg_config;
20
21check_mrtg_config check_mrtg_config_init() {
22 check_mrtg_config tmp = {
23 .use_average = true,
24 .variable_number = -1,
25 .expire_minutes = 0,
26 .label = NULL,
27 .units = NULL,
28 .log_file = NULL,
29
30 .value_warning_threshold_set = false,
31 .value_warning_threshold = 0,
32 .value_critical_threshold_set = false,
33 .value_critical_threshold = 0,
34 };
35 return tmp;
36}
diff --git a/plugins/check_mrtgtraf.c b/plugins/check_mrtgtraf.c
index bd25d47d..8c7cf8aa 100644
--- a/plugins/check_mrtgtraf.c
+++ b/plugins/check_mrtgtraf.c
@@ -1,381 +1,352 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_mrtgtraf plugin 3 * Monitoring check_mrtgtraf plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_mtrgtraf plugin 10 * This file contains the check_mtrgtraf plugin
11* 11 *
12* This plugin will check the incoming/outgoing transfer rates of a router 12 * This plugin will check the incoming/outgoing transfer rates of a router
13* switch, etc recorded in an MRTG log. 13 * switch, etc recorded in an MRTG log.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_mrtgtraf";
33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "check_mrtgtraf.d/config.h"
32#include "common.h" 37#include "common.h"
33#include "utils.h" 38#include "utils.h"
34 39
35const char *progname = "check_mrtgtraf"; 40typedef struct {
36const char *copyright = "1999-2007"; 41 int errorcode;
37const char *email = "devel@monitoring-plugins.org"; 42 check_mrtgtraf_config config;
43} check_mrtgtraf_config_wrapper;
38 44
39int process_arguments (int, char **); 45static check_mrtgtraf_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
40int validate_arguments (void); 46static void print_help(void);
41void print_help(void);
42void print_usage(void); 47void print_usage(void);
43 48
44char *log_file = NULL; 49int main(int argc, char **argv) {
45int expire_minutes = -1; 50 setlocale(LC_ALL, "");
46bool use_average = true; 51 bindtextdomain(PACKAGE, LOCALEDIR);
47unsigned long incoming_warning_threshold = 0L; 52 textdomain(PACKAGE);
48unsigned long incoming_critical_threshold = 0L;
49unsigned long outgoing_warning_threshold = 0L;
50unsigned long outgoing_critical_threshold = 0L;
51 53
54 /* Parse extra opts if any */
55 argv = np_extra_opts(&argc, argv, progname);
56
57 check_mrtgtraf_config_wrapper tmp_config = process_arguments(argc, argv);
58 if (tmp_config.errorcode == ERROR) {
59 usage4(_("Could not parse arguments"));
60 }
61
62 const check_mrtgtraf_config config = tmp_config.config;
63
64 /* open the MRTG log file for reading */
65 FILE *mrtg_log_file_ptr = fopen(config.log_file, "r");
66 if (mrtg_log_file_ptr == NULL) {
67 usage4(_("Unable to open MRTG log file"));
68 }
52 69
53int
54main (int argc, char **argv)
55{
56 int result = STATE_OK;
57 FILE *fp;
58 int line;
59 char input_buffer[MAX_INPUT_BUFFER];
60 char *temp_buffer;
61 time_t current_time;
62 char *error_message;
63 time_t timestamp = 0L; 70 time_t timestamp = 0L;
71 char input_buffer[MAX_INPUT_BUFFER];
64 unsigned long average_incoming_rate = 0L; 72 unsigned long average_incoming_rate = 0L;
65 unsigned long average_outgoing_rate = 0L; 73 unsigned long average_outgoing_rate = 0L;
66 unsigned long maximum_incoming_rate = 0L; 74 unsigned long maximum_incoming_rate = 0L;
67 unsigned long maximum_outgoing_rate = 0L; 75 unsigned long maximum_outgoing_rate = 0L;
68 unsigned long incoming_rate = 0L; 76 int line = 0;
69 unsigned long outgoing_rate = 0L; 77 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mrtg_log_file_ptr)) {
70 double adjusted_incoming_rate = 0.0;
71 double adjusted_outgoing_rate = 0.0;
72 char incoming_speed_rating[8];
73 char outgoing_speed_rating[8];
74
75 setlocale (LC_ALL, "");
76 bindtextdomain (PACKAGE, LOCALEDIR);
77 textdomain (PACKAGE);
78
79 /* Parse extra opts if any */
80 argv=np_extra_opts (&argc, argv, progname);
81
82 if (process_arguments (argc, argv) == ERROR)
83 usage4 (_("Could not parse arguments"));
84
85 /* open the MRTG log file for reading */
86 fp = fopen (log_file, "r");
87 if (fp == NULL)
88 usage4 (_("Unable to open MRTG log file"));
89
90 line = 0;
91 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
92 78
93 line++; 79 line++;
94 80
95 /* skip the first line of the log file */ 81 /* skip the first line of the log file */
96 if (line == 1) 82 if (line == 1) {
97 continue; 83 continue;
84 }
98 85
99 /* break out of read loop */ 86 /* break out of read loop */
100 /* if we've passed the number of entries we want to read */ 87 /* if we've passed the number of entries we want to read */
101 if (line > 2) 88 if (line > 2) {
102 break; 89 break;
90 }
103 91
104 /* grab the timestamp */ 92 /* grab the timestamp */
105 temp_buffer = strtok (input_buffer, " "); 93 char *temp_buffer = strtok(input_buffer, " ");
106 timestamp = strtoul (temp_buffer, NULL, 10); 94 timestamp = strtoul(temp_buffer, NULL, 10);
107 95
108 /* grab the average incoming transfer rate */ 96 /* grab the average incoming transfer rate */
109 temp_buffer = strtok (NULL, " "); 97 temp_buffer = strtok(NULL, " ");
110 average_incoming_rate = strtoul (temp_buffer, NULL, 10); 98 average_incoming_rate = strtoul(temp_buffer, NULL, 10);
111 99
112 /* grab the average outgoing transfer rate */ 100 /* grab the average outgoing transfer rate */
113 temp_buffer = strtok (NULL, " "); 101 temp_buffer = strtok(NULL, " ");
114 average_outgoing_rate = strtoul (temp_buffer, NULL, 10); 102 average_outgoing_rate = strtoul(temp_buffer, NULL, 10);
115 103
116 /* grab the maximum incoming transfer rate */ 104 /* grab the maximum incoming transfer rate */
117 temp_buffer = strtok (NULL, " "); 105 temp_buffer = strtok(NULL, " ");
118 maximum_incoming_rate = strtoul (temp_buffer, NULL, 10); 106 maximum_incoming_rate = strtoul(temp_buffer, NULL, 10);
119 107
120 /* grab the maximum outgoing transfer rate */ 108 /* grab the maximum outgoing transfer rate */
121 temp_buffer = strtok (NULL, " "); 109 temp_buffer = strtok(NULL, " ");
122 maximum_outgoing_rate = strtoul (temp_buffer, NULL, 10); 110 maximum_outgoing_rate = strtoul(temp_buffer, NULL, 10);
123 } 111 }
124 112
125 /* close the log file */ 113 /* close the log file */
126 fclose (fp); 114 fclose(mrtg_log_file_ptr);
127 115
128 /* if we couldn't read enough data, return an unknown error */ 116 /* if we couldn't read enough data, return an unknown error */
129 if (line <= 2) 117 if (line <= 2) {
130 usage4 (_("Unable to process MRTG log file")); 118 usage4(_("Unable to process MRTG log file"));
119 }
131 120
132 /* make sure the MRTG data isn't too old */ 121 /* make sure the MRTG data isn't too old */
133 time (&current_time); 122 time_t current_time;
134 if ((expire_minutes > 0) && 123 time(&current_time);
135 (current_time - timestamp) > (expire_minutes * 60)) 124 if ((config.expire_minutes > 0) && (current_time - timestamp) > (config.expire_minutes * 60)) {
136 die (STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), 125 die(STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60));
137 (int) ((current_time - timestamp) / 60)); 126 }
138 127
128 unsigned long incoming_rate = 0L;
129 unsigned long outgoing_rate = 0L;
139 /* else check the incoming/outgoing rates */ 130 /* else check the incoming/outgoing rates */
140 if (use_average) { 131 if (config.use_average) {
141 incoming_rate = average_incoming_rate; 132 incoming_rate = average_incoming_rate;
142 outgoing_rate = average_outgoing_rate; 133 outgoing_rate = average_outgoing_rate;
143 } 134 } else {
144 else {
145 incoming_rate = maximum_incoming_rate; 135 incoming_rate = maximum_incoming_rate;
146 outgoing_rate = maximum_outgoing_rate; 136 outgoing_rate = maximum_outgoing_rate;
147 } 137 }
148 138
139 double adjusted_incoming_rate = 0.0;
140 char incoming_speed_rating[8];
149 /* report incoming traffic in Bytes/sec */ 141 /* report incoming traffic in Bytes/sec */
150 if (incoming_rate < 1024) { 142 if (incoming_rate < 1024) {
151 strcpy (incoming_speed_rating, "B"); 143 strcpy(incoming_speed_rating, "B");
152 adjusted_incoming_rate = (double) incoming_rate; 144 adjusted_incoming_rate = (double)incoming_rate;
153 } 145 }
154 146
155 /* report incoming traffic in KBytes/sec */ 147 /* report incoming traffic in KBytes/sec */
156 else if (incoming_rate < (1024 * 1024)) { 148 else if (incoming_rate < (1024 * 1024)) {
157 strcpy (incoming_speed_rating, "KB"); 149 strcpy(incoming_speed_rating, "KB");
158 adjusted_incoming_rate = (double) (incoming_rate / 1024.0); 150 adjusted_incoming_rate = (double)(incoming_rate / 1024.0);
159 } 151 }
160 152
161 /* report incoming traffic in MBytes/sec */ 153 /* report incoming traffic in MBytes/sec */
162 else { 154 else {
163 strcpy (incoming_speed_rating, "MB"); 155 strcpy(incoming_speed_rating, "MB");
164 adjusted_incoming_rate = (double) (incoming_rate / 1024.0 / 1024.0); 156 adjusted_incoming_rate = (double)(incoming_rate / 1024.0 / 1024.0);
165 } 157 }
166 158
159 double adjusted_outgoing_rate = 0.0;
160 char outgoing_speed_rating[8];
167 /* report outgoing traffic in Bytes/sec */ 161 /* report outgoing traffic in Bytes/sec */
168 if (outgoing_rate < 1024) { 162 if (outgoing_rate < 1024) {
169 strcpy (outgoing_speed_rating, "B"); 163 strcpy(outgoing_speed_rating, "B");
170 adjusted_outgoing_rate = (double) outgoing_rate; 164 adjusted_outgoing_rate = (double)outgoing_rate;
171 } 165 }
172 166
173 /* report outgoing traffic in KBytes/sec */ 167 /* report outgoing traffic in KBytes/sec */
174 else if (outgoing_rate < (1024 * 1024)) { 168 else if (outgoing_rate < (1024 * 1024)) {
175 strcpy (outgoing_speed_rating, "KB"); 169 strcpy(outgoing_speed_rating, "KB");
176 adjusted_outgoing_rate = (double) (outgoing_rate / 1024.0); 170 adjusted_outgoing_rate = (double)(outgoing_rate / 1024.0);
177 } 171 }
178 172
179 /* report outgoing traffic in MBytes/sec */ 173 /* report outgoing traffic in MBytes/sec */
180 else { 174 else {
181 strcpy (outgoing_speed_rating, "MB"); 175 strcpy(outgoing_speed_rating, "MB");
182 adjusted_outgoing_rate = (double) (outgoing_rate / 1024.0 / 1024.0); 176 adjusted_outgoing_rate = (outgoing_rate / 1024.0 / 1024.0);
183 } 177 }
184 178
185 if (incoming_rate > incoming_critical_threshold 179 int result = STATE_OK;
186 || outgoing_rate > outgoing_critical_threshold) { 180 if (incoming_rate > config.incoming_critical_threshold || outgoing_rate > config.outgoing_critical_threshold) {
187 result = STATE_CRITICAL; 181 result = STATE_CRITICAL;
188 } 182 } else if (incoming_rate > config.incoming_warning_threshold || outgoing_rate > config.outgoing_warning_threshold) {
189 else if (incoming_rate > incoming_warning_threshold
190 || outgoing_rate > outgoing_warning_threshold) {
191 result = STATE_WARNING; 183 result = STATE_WARNING;
192 } 184 }
193 185
194 xasprintf (&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), 186 char *error_message;
195 (use_average) ? _("Avg") : _("Max"), adjusted_incoming_rate, 187 xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), (config.use_average) ? _("Avg") : _("Max"),
196 incoming_speed_rating, (use_average) ? _("Avg") : _("Max"), 188 adjusted_incoming_rate, incoming_speed_rating, (config.use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate,
197 adjusted_outgoing_rate, outgoing_speed_rating, 189 outgoing_speed_rating,
198 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, 190 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, (int)config.incoming_warning_threshold,
199 (int)incoming_warning_threshold, incoming_warning_threshold, 191 config.incoming_warning_threshold, (int)config.incoming_critical_threshold, config.incoming_critical_threshold,
200 (int)incoming_critical_threshold, incoming_critical_threshold, 192 true, 0, false, 0),
201 true, 0, false, 0), 193 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, (int)config.outgoing_warning_threshold,
202 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, 194 config.outgoing_warning_threshold, (int)config.outgoing_critical_threshold, config.outgoing_critical_threshold,
203 (int)outgoing_warning_threshold, outgoing_warning_threshold, 195 true, 0, false, 0));
204 (int)outgoing_critical_threshold, outgoing_critical_threshold, 196
205 true, 0, false, 0)); 197 printf(_("Traffic %s - %s\n"), state_text(result), error_message);
206
207 printf (_("Traffic %s - %s\n"), state_text(result), error_message);
208 198
209 return result; 199 return result;
210} 200}
211 201
212
213
214/* process command-line arguments */ 202/* process command-line arguments */
215int 203check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
216process_arguments (int argc, char **argv) 204 static struct option longopts[] = {{"filename", required_argument, 0, 'F'},
217{ 205 {"expires", required_argument, 0, 'e'},
218 int c; 206 {"aggregation", required_argument, 0, 'a'},
219 207 {"critical", required_argument, 0, 'c'},
220 int option = 0; 208 {"warning", required_argument, 0, 'w'},
221 static struct option longopts[] = { 209 {"version", no_argument, 0, 'V'},
222 {"filename", required_argument, 0, 'F'}, 210 {"help", no_argument, 0, 'h'},
223 {"expires", required_argument, 0, 'e'}, 211 {0, 0, 0, 0}};
224 {"aggregation", required_argument, 0, 'a'}, 212
225 {"critical", required_argument, 0, 'c'}, 213 check_mrtgtraf_config_wrapper result = {
226 {"warning", required_argument, 0, 'w'}, 214 .errorcode = OK,
227 {"version", no_argument, 0, 'V'}, 215 .config = check_mrtgtraf_config_init(),
228 {"help", no_argument, 0, 'h'},
229 {0, 0, 0, 0}
230 }; 216 };
217 if (argc < 2) {
218 result.errorcode = ERROR;
219 return result;
220 }
231 221
232 if (argc < 2) 222 for (int i = 1; i < argc; i++) {
233 return ERROR; 223 if (strcmp("-to", argv[i]) == 0) {
234 224 strcpy(argv[i], "-t");
235 for (c = 1; c < argc; c++) { 225 } else if (strcmp("-wt", argv[i]) == 0) {
236 if (strcmp ("-to", argv[c]) == 0) 226 strcpy(argv[i], "-w");
237 strcpy (argv[c], "-t"); 227 } else if (strcmp("-ct", argv[i]) == 0) {
238 else if (strcmp ("-wt", argv[c]) == 0) 228 strcpy(argv[i], "-c");
239 strcpy (argv[c], "-w"); 229 }
240 else if (strcmp ("-ct", argv[c]) == 0)
241 strcpy (argv[c], "-c");
242 } 230 }
243 231
244 while (1) { 232 int option_char;
245 c = getopt_long (argc, argv, "hVF:e:a:c:w:", longopts, &option); 233 int option = 0;
234 while (true) {
235 option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option);
246 236
247 if (c == -1 || c == EOF) 237 if (option_char == -1 || option_char == EOF) {
248 break; 238 break;
239 }
249 240
250 switch (c) { 241 switch (option_char) {
251 case 'F': /* input file */ 242 case 'F': /* input file */
252 log_file = optarg; 243 result.config.log_file = optarg;
253 break; 244 break;
254 case 'e': /* expiration time */ 245 case 'e': /* expiration time */
255 expire_minutes = atoi (optarg); 246 result.config.expire_minutes = atoi(optarg);
256 break; 247 break;
257 case 'a': /* aggregation (AVE or MAX) */ 248 case 'a': /* aggregation (AVE or MAX) */
258 if (!strcmp (optarg, "MAX")) 249 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
259 use_average = false;
260 else
261 use_average = true;
262 break; 250 break;
263 case 'c': /* warning threshold */ 251 case 'c': /* warning threshold */
264 sscanf (optarg, "%lu,%lu", &incoming_critical_threshold, 252 sscanf(optarg, "%lu,%lu", &result.config.incoming_critical_threshold, &result.config.outgoing_critical_threshold);
265 &outgoing_critical_threshold);
266 break; 253 break;
267 case 'w': /* critical threshold */ 254 case 'w': /* critical threshold */
268 sscanf (optarg, "%lu,%lu", &incoming_warning_threshold, 255 sscanf(optarg, "%lu,%lu", &result.config.incoming_warning_threshold, &result.config.outgoing_warning_threshold);
269 &outgoing_warning_threshold);
270 break; 256 break;
271 case 'V': /* version */ 257 case 'V': /* version */
272 print_revision (progname, NP_VERSION); 258 print_revision(progname, NP_VERSION);
273 exit (STATE_UNKNOWN); 259 exit(STATE_UNKNOWN);
274 case 'h': /* help */ 260 case 'h': /* help */
275 print_help (); 261 print_help();
276 exit (STATE_UNKNOWN); 262 exit(STATE_UNKNOWN);
277 case '?': /* help */ 263 case '?': /* help */
278 usage5 (); 264 usage5();
279 } 265 }
280 } 266 }
281 267
282 c = optind; 268 option_char = optind;
283 if (argc > c && log_file == NULL) { 269 if (argc > option_char && result.config.log_file == NULL) {
284 log_file = argv[c++]; 270 result.config.log_file = argv[option_char++];
285 } 271 }
286 272
287 if (argc > c && expire_minutes == -1) { 273 if (argc > option_char && result.config.expire_minutes == -1) {
288 expire_minutes = atoi (argv[c++]); 274 result.config.expire_minutes = atoi(argv[option_char++]);
289 } 275 }
290 276
291 if (argc > c && strcmp (argv[c], "MAX") == 0) { 277 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
292 use_average = false; 278 result.config.use_average = false;
293 c++; 279 option_char++;
294 } 280 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
295 else if (argc > c && strcmp (argv[c], "AVG") == 0) { 281 result.config.use_average = true;
296 use_average = true; 282 option_char++;
297 c++;
298 } 283 }
299 284
300 if (argc > c && incoming_warning_threshold == 0) { 285 if (argc > option_char && result.config.incoming_warning_threshold == 0) {
301 incoming_warning_threshold = strtoul (argv[c++], NULL, 10); 286 result.config.incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10);
302 } 287 }
303 288
304 if (argc > c && incoming_critical_threshold == 0) { 289 if (argc > option_char && result.config.incoming_critical_threshold == 0) {
305 incoming_critical_threshold = strtoul (argv[c++], NULL, 10); 290 result.config.incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10);
306 } 291 }
307 292
308 if (argc > c && outgoing_warning_threshold == 0) { 293 if (argc > option_char && result.config.outgoing_warning_threshold == 0) {
309 outgoing_warning_threshold = strtoul (argv[c++], NULL, 10); 294 result.config.outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10);
310 } 295 }
311
312 if (argc > c && outgoing_critical_threshold == 0) {
313 outgoing_critical_threshold = strtoul (argv[c++], NULL, 10);
314 }
315
316 return validate_arguments ();
317}
318 296
297 if (argc > option_char && result.config.outgoing_critical_threshold == 0) {
298 result.config.outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10);
299 }
319 300
320int 301 return result;
321validate_arguments (void)
322{
323 return OK;
324} 302}
325 303
326 304void print_help(void) {
327void 305 print_revision(progname, NP_VERSION);
328print_help (void) 306
329{ 307 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
330 print_revision (progname, NP_VERSION); 308 printf(COPYRIGHT, copyright, email);
331 309
332 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 310 printf("%s\n", _("This plugin will check the incoming/outgoing transfer rates of a router,"));
333 printf (COPYRIGHT, copyright, email); 311 printf("%s\n", _("switch, etc recorded in an MRTG log. If the newest log entry is older"));
334 312 printf("%s\n", _("than <expire_minutes>, a WARNING status is returned. If either the"));
335 printf ("%s\n", _("This plugin will check the incoming/outgoing transfer rates of a router,")); 313 printf("%s\n", _("incoming or outgoing rates exceed the <icl> or <ocl> thresholds (in"));
336 printf ("%s\n", _("switch, etc recorded in an MRTG log. If the newest log entry is older")); 314 printf("%s\n", _("Bytes/sec), a CRITICAL status results. If either of the rates exceed"));
337 printf ("%s\n", _("than <expire_minutes>, a WARNING status is returned. If either the")); 315 printf("%s\n", _("the <iwl> or <owl> thresholds (in Bytes/sec), a WARNING status results."));
338 printf ("%s\n", _("incoming or outgoing rates exceed the <icl> or <ocl> thresholds (in")); 316
339 printf ("%s\n", _("Bytes/sec), a CRITICAL status results. If either of the rates exceed")); 317 printf("\n\n");
340 printf ("%s\n", _("the <iwl> or <owl> thresholds (in Bytes/sec), a WARNING status results.")); 318
341 319 print_usage();
342 printf ("\n\n"); 320
343 321 printf(UT_HELP_VRSN);
344 print_usage (); 322 printf(UT_EXTRA_OPTS);
345 323
346 printf (UT_HELP_VRSN); 324 printf(" %s\n", "-F, --filename=STRING");
347 printf (UT_EXTRA_OPTS); 325 printf(" %s\n", _("File to read log from"));
348 326 printf(" %s\n", "-e, --expires=INTEGER");
349 printf (" %s\n", "-F, --filename=STRING"); 327 printf(" %s\n", _("Minutes after which log expires"));
350 printf (" %s\n", _("File to read log from")); 328 printf(" %s\n", "-a, --aggregation=(AVG|MAX)");
351 printf (" %s\n", "-e, --expires=INTEGER"); 329 printf(" %s\n", _("Test average or maximum"));
352 printf (" %s\n", _("Minutes after which log expires")); 330 printf(" %s\n", "-w, --warning");
353 printf (" %s\n", "-a, --aggregation=(AVG|MAX)"); 331 printf(" %s\n", _("Warning threshold pair <incoming>,<outgoing>"));
354 printf (" %s\n", _("Test average or maximum")); 332 printf(" %s\n", "-c, --critical");
355 printf (" %s\n", "-w, --warning"); 333 printf(" %s\n", _("Critical threshold pair <incoming>,<outgoing>"));
356 printf (" %s\n", _("Warning threshold pair <incoming>,<outgoing>")); 334
357 printf (" %s\n", "-c, --critical"); 335 printf("\n");
358 printf (" %s\n", _("Critical threshold pair <incoming>,<outgoing>")); 336 printf("%s\n", _("Notes:"));
359 337 printf(" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from"));
360 printf ("\n"); 338 printf(" %s\n", " http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html");
361 printf ("%s\n", _("Notes:")); 339 printf(" %s\n", _("- While MRTG can monitor things other than traffic rates, this"));
362 printf (" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from")); 340 printf(" %s\n", _(" plugin probably won't work with much else without modification."));
363 printf (" %s\n", " http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html"); 341 printf(" %s\n", _("- The calculated i/o rates are a little off from what MRTG actually"));
364 printf (" %s\n", _("- While MRTG can monitor things other than traffic rates, this")); 342 printf(" %s\n", _(" reports. I'm not sure why this is right now, but will look into it"));
365 printf (" %s\n", _(" plugin probably won't work with much else without modification.")); 343 printf(" %s\n", _(" for future enhancements of this plugin."));
366 printf (" %s\n", _("- The calculated i/o rates are a little off from what MRTG actually")); 344
367 printf (" %s\n", _(" reports. I'm not sure why this is right now, but will look into it")); 345 printf(UT_SUPPORT);
368 printf (" %s\n", _(" for future enhancements of this plugin."));
369
370 printf (UT_SUPPORT);
371} 346}
372 347
373 348void print_usage(void) {
374 349 printf(_("Usage"));
375void 350 printf(" %s -F <log_file> -a <AVG | MAX> -w <warning_pair>\n", progname);
376print_usage (void) 351 printf("-c <critical_pair> [-e expire_minutes]\n");
377{
378 printf (_("Usage"));
379 printf (" %s -F <log_file> -a <AVG | MAX> -w <warning_pair>\n",progname);
380 printf ("-c <critical_pair> [-e expire_minutes]\n");
381} 352}
diff --git a/plugins/check_mrtgtraf.d/config.h b/plugins/check_mrtgtraf.d/config.h
new file mode 100644
index 00000000..94929ff7
--- /dev/null
+++ b/plugins/check_mrtgtraf.d/config.h
@@ -0,0 +1,30 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7typedef struct {
8 char *log_file;
9 int expire_minutes;
10 bool use_average;
11 unsigned long incoming_warning_threshold;
12 unsigned long incoming_critical_threshold;
13 unsigned long outgoing_warning_threshold;
14 unsigned long outgoing_critical_threshold;
15
16} check_mrtgtraf_config;
17
18check_mrtgtraf_config check_mrtgtraf_config_init() {
19 check_mrtgtraf_config tmp = {
20 .log_file = NULL,
21 .expire_minutes = -1,
22 .use_average = true,
23
24 .incoming_warning_threshold = 0,
25 .incoming_critical_threshold = 0,
26 .outgoing_warning_threshold = 0,
27 .outgoing_critical_threshold = 0,
28 };
29 return tmp;
30}
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c
index 15ec04c0..ca3422b5 100644
--- a/plugins/check_mysql.c
+++ b/plugins/check_mysql.c
@@ -1,267 +1,281 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_mysql plugin 3 * Monitoring check_mysql plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at) 6 * Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)
7* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net) 7 * Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
8* Copyright (c) 1999-2011 Monitoring Plugins Development Team 8 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
9* 9 *
10* Description: 10 * Description:
11* 11 *
12* This file contains the check_mysql plugin 12 * This file contains the check_mysql plugin
13* 13 *
14* This program tests connections to a mysql server 14 * This program tests connections to a mysql server
15* 15 *
16* 16 *
17* This program is free software: you can redistribute it and/or modify 17 * This program is free software: you can redistribute it and/or modify
18* it under the terms of the GNU General Public License as published by 18 * it under the terms of the GNU General Public License as published by
19* the Free Software Foundation, either version 3 of the License, or 19 * the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20 * (at your option) any later version.
21* 21 *
22* This program is distributed in the hope that it will be useful, 22 * This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25 * GNU General Public License for more details.
26* 26 *
27* You should have received a copy of the GNU General Public License 27 * You should have received a copy of the GNU General Public License
28* along with this program. If not, see <http://www.gnu.org/licenses/>. 28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29 *
30* 30 *
31*****************************************************************************/ 31 *****************************************************************************/
32 32
33const char *progname = "check_mysql"; 33const char *progname = "check_mysql";
34const char *copyright = "1999-2011"; 34const char *copyright = "1999-2024";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#define SLAVERESULTSIZE 96 37#define REPLICA_RESULTSIZE 96
38 38
39#include "common.h" 39#include "common.h"
40#include "utils.h" 40#include "utils.h"
41#include "utils_base.h" 41#include "utils_base.h"
42#include "netutils.h" 42#include "netutils.h"
43#include "check_mysql.d/config.h"
43 44
44#include <mysql.h> 45#include <mysql.h>
45#include <mysqld_error.h> 46#include <mysqld_error.h>
46#include <errmsg.h> 47#include <errmsg.h>
47 48
48char *db_user = NULL; 49static int verbose = 0;
49char *db_host = NULL;
50char *db_socket = NULL;
51char *db_pass = NULL;
52char *db = NULL;
53char *ca_cert = NULL;
54char *ca_dir = NULL;
55char *cert = NULL;
56char *key = NULL;
57char *ciphers = NULL;
58bool ssl = false;
59char *opt_file = NULL;
60char *opt_group = NULL;
61unsigned int db_port = MYSQL_PORT;
62bool check_slave = false;
63bool ignore_auth = false;
64int verbose = 0;
65
66static double warning_time = 0;
67static double critical_time = 0;
68 50
69#define LENGTH_METRIC_UNIT 6 51#define LENGTH_METRIC_UNIT 6
70static const char *metric_unit[LENGTH_METRIC_UNIT] = { 52static const char *metric_unit[LENGTH_METRIC_UNIT] = {
71 "Open_files", 53 "Open_files", "Open_tables", "Qcache_free_memory", "Qcache_queries_in_cache", "Threads_connected", "Threads_running"};
72 "Open_tables",
73 "Qcache_free_memory",
74 "Qcache_queries_in_cache",
75 "Threads_connected",
76 "Threads_running"
77};
78 54
79#define LENGTH_METRIC_COUNTER 9 55#define LENGTH_METRIC_COUNTER 9
80static const char *metric_counter[LENGTH_METRIC_COUNTER] = { 56static const char *metric_counter[LENGTH_METRIC_COUNTER] = {
81 "Connections", 57 "Connections", "Qcache_hits", "Qcache_inserts", "Qcache_lowmem_prunes", "Qcache_not_cached", "Queries",
82 "Qcache_hits", 58 "Questions", "Table_locks_waited", "Uptime"};
83 "Qcache_inserts", 59
84 "Qcache_lowmem_prunes", 60#define MYSQLDUMP_THREADS_QUERY \
85 "Qcache_not_cached", 61 "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'"
86 "Queries", 62
87 "Questions", 63typedef struct {
88 "Table_locks_waited", 64 int errorcode;
89 "Uptime" 65 check_mysql_config config;
90}; 66} check_mysql_config_wrapper;
91 67static check_mysql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
92#define MYSQLDUMP_THREADS_QUERY "SELECT COUNT(1) mysqldumpThreads FROM information_schema.processlist WHERE info LIKE 'SELECT /*!40001 SQL_NO_CACHE */%'" 68static check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper /*config_wrapper*/);
93 69static void print_help(void);
94thresholds *my_threshold = NULL; 70void print_usage(void);
95 71
96int process_arguments (int, char **); 72int main(int argc, char **argv) {
97int validate_arguments (void); 73 setlocale(LC_ALL, "");
98void print_help (void); 74 bindtextdomain(PACKAGE, LOCALEDIR);
99void print_usage (void); 75 textdomain(PACKAGE);
100
101int
102main (int argc, char **argv)
103{
104 76
105 MYSQL mysql; 77 /* Parse extra opts if any */
106 MYSQL_RES *res; 78 argv = np_extra_opts(&argc, argv, progname);
107 MYSQL_ROW row;
108
109 /* should be status */
110 79
111 char *result = NULL; 80 check_mysql_config_wrapper tmp_config = process_arguments(argc, argv);
112 char *error = NULL; 81 if (tmp_config.errorcode == ERROR) {
113 char slaveresult[SLAVERESULTSIZE] = { 0 }; 82 usage4(_("Could not parse arguments"));
114 char* perf; 83 }
115 84
116 perf = strdup (""); 85 const check_mysql_config config = tmp_config.config;
117 86
118 setlocale (LC_ALL, ""); 87 MYSQL mysql;
119 bindtextdomain (PACKAGE, LOCALEDIR); 88 /* initialize mysql */
120 textdomain (PACKAGE); 89 mysql_init(&mysql);
121 90
122 /* Parse extra opts if any */ 91 if (config.opt_file != NULL) {
123 argv=np_extra_opts (&argc, argv, progname); 92 mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
93 }
124 94
125 if (process_arguments (argc, argv) == ERROR) 95 if (config.opt_group != NULL) {
126 usage4 (_("Could not parse arguments")); 96 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
97 } else {
98 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
99 }
127 100
128 /* initialize mysql */ 101 if (config.ssl) {
129 mysql_init (&mysql); 102 mysql_ssl_set(&mysql, config.key, config.cert, config.ca_cert, config.ca_dir, config.ciphers);
130 103 }
131 if (opt_file != NULL)
132 mysql_options(&mysql,MYSQL_READ_DEFAULT_FILE,opt_file);
133
134 if (opt_group != NULL)
135 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,opt_group);
136 else
137 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client");
138
139 if (ssl)
140 mysql_ssl_set(&mysql,key,cert,ca_cert,ca_dir,ciphers);
141 /* establish a connection to the server and error checking */ 104 /* establish a connection to the server and error checking */
142 if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) { 105 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) {
143 /* Depending on internally-selected auth plugin MySQL might return */ 106 /* Depending on internally-selected auth plugin MySQL might return */
144 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */ 107 /* ER_ACCESS_DENIED_NO_PASSWORD_ERROR or ER_ACCESS_DENIED_ERROR. */
145 /* Semantically these errors are the same. */ 108 /* Semantically these errors are the same. */
146 if (ignore_auth && (mysql_errno (&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno (&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) 109 if (config.ignore_auth &&
147 { 110 (mysql_errno(&mysql) == ER_ACCESS_DENIED_ERROR || mysql_errno(&mysql) == ER_ACCESS_DENIED_NO_PASSWORD_ERROR)) {
148 printf("MySQL OK - Version: %s (protocol %d)\n", 111 printf("MySQL OK - Version: %s (protocol %d)\n", mysql_get_server_info(&mysql), mysql_get_proto_info(&mysql));
149 mysql_get_server_info(&mysql), 112 mysql_close(&mysql);
150 mysql_get_proto_info(&mysql)
151 );
152 mysql_close (&mysql);
153 return STATE_OK; 113 return STATE_OK;
154 } 114 }
155 else if (mysql_errno (&mysql) == CR_UNKNOWN_HOST) 115
156 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 116 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
157 else if (mysql_errno (&mysql) == CR_VERSION_ERROR) 117 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
158 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 118 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
159 else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY) 119 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
160 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 120 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
161 else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR) 121 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
162 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 122 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
163 else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR) 123 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
164 die (STATE_WARNING, "%s\n", mysql_error (&mysql)); 124 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
165 else 125 die(STATE_WARNING, "%s\n", mysql_error(&mysql));
166 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 126 } else {
127 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
128 }
167 } 129 }
168 130
169 /* get the server stats */ 131 /* get the server stats */
170 result = strdup (mysql_stat (&mysql)); 132 char *result = strdup(mysql_stat(&mysql));
171 133
172 /* error checking once more */ 134 /* error checking once more */
173 if (mysql_error (&mysql)) { 135 if (mysql_error(&mysql)) {
174 if (mysql_errno (&mysql) == CR_SERVER_GONE_ERROR) 136 if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) {
175 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 137 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
176 else if (mysql_errno (&mysql) == CR_SERVER_LOST) 138 } else if (mysql_errno(&mysql) == CR_SERVER_LOST) {
177 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 139 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
178 else if (mysql_errno (&mysql) == CR_UNKNOWN_ERROR) 140 } else if (mysql_errno(&mysql) == CR_UNKNOWN_ERROR) {
179 die (STATE_CRITICAL, "%s\n", mysql_error (&mysql)); 141 die(STATE_CRITICAL, "%s\n", mysql_error(&mysql));
142 }
180 } 143 }
181 144
145 char *perf = strdup("");
146 char *error = NULL;
147 MYSQL_RES *res;
148 MYSQL_ROW row;
182 /* try to fetch some perf data */ 149 /* try to fetch some perf data */
183 if (mysql_query (&mysql, "show global status") == 0) { 150 if (mysql_query(&mysql, "show global status") == 0) {
184 if ( (res = mysql_store_result (&mysql)) == NULL) { 151 if ((res = mysql_store_result(&mysql)) == NULL) {
185 error = strdup(mysql_error(&mysql)); 152 error = strdup(mysql_error(&mysql));
186 mysql_close (&mysql); 153 mysql_close(&mysql);
187 die (STATE_CRITICAL, _("status store_result error: %s\n"), error); 154 die(STATE_CRITICAL, _("status store_result error: %s\n"), error);
188 } 155 }
189 156
190 while ( (row = mysql_fetch_row (res)) != NULL) { 157 while ((row = mysql_fetch_row(res)) != NULL) {
191 int i; 158 for (int i = 0; i < LENGTH_METRIC_UNIT; i++) {
192
193 for(i = 0; i < LENGTH_METRIC_UNIT; i++) {
194 if (strcmp(row[0], metric_unit[i]) == 0) { 159 if (strcmp(row[0], metric_unit[i]) == 0) {
195 xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], 160 xasprintf(&perf, "%s%s ", perf, perfdata(metric_unit[i], atol(row[1]), "", false, 0, false, 0, false, 0, false, 0));
196 atol(row[1]), "", false, 0, false, 0, false, 0, false, 0));
197 continue; 161 continue;
198 } 162 }
199 } 163 }
200 for(i = 0; i < LENGTH_METRIC_COUNTER; i++) { 164 for (int i = 0; i < LENGTH_METRIC_COUNTER; i++) {
201 if (strcmp(row[0], metric_counter[i]) == 0) { 165 if (strcmp(row[0], metric_counter[i]) == 0) {
202 xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], 166 xasprintf(&perf, "%s%s ", perf, perfdata(metric_counter[i], atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0));
203 atol(row[1]), "c", false, 0, false, 0, false, 0, false, 0));
204 continue; 167 continue;
205 } 168 }
206 } 169 }
207 } 170 }
208 /* remove trailing space */ 171 /* remove trailing space */
209 if (strlen(perf) > 0) 172 if (strlen(perf) > 0) {
210 perf[strlen(perf) - 1] = '\0'; 173 perf[strlen(perf) - 1] = '\0';
174 }
211 } 175 }
212 176
213 if(check_slave) { 177 char replica_result[REPLICA_RESULTSIZE] = {0};
214 /* check the slave status */ 178 if (config.check_replica) {
215 if (mysql_query (&mysql, "show slave status") != 0) { 179 // Detect which version we are, on older version
180 // "show slave status" should work, on newer ones
181 // "show replica status"
182 // But first we have to find out whether this is
183 // MySQL or MariaDB since the version numbering scheme
184 // is different
185 bool use_deprecated_slave_status = false;
186 const char *server_version = mysql_get_server_info(&mysql);
187 unsigned long server_verion_int = mysql_get_server_version(&mysql);
188 unsigned long major_version = server_verion_int / 10000;
189 unsigned long minor_version = (server_verion_int % 10000) / 100;
190 unsigned long patch_version = (server_verion_int % 100);
191 if (verbose) {
192 printf("Found MariaDB: %s, main version: %lu, minor version: %lu, patch version: %lu\n", server_version, major_version,
193 minor_version, patch_version);
194 }
195
196 if (strstr(server_version, "MariaDB") != NULL) {
197 // Looks like MariaDB, new commands should be available after 10.5.1
198 if (major_version < 10) {
199 use_deprecated_slave_status = true;
200 } else if (major_version == 10) {
201 if (minor_version < 5) {
202 use_deprecated_slave_status = true;
203 } else if (minor_version == 5 && patch_version < 1) {
204 use_deprecated_slave_status = true;
205 }
206 }
207 } else if (strstr(server_version, "MySQL") != NULL) {
208 // Looks like MySQL
209 if (major_version < 8) {
210 use_deprecated_slave_status = true;
211 } else if (major_version == 10 && minor_version < 4) {
212 use_deprecated_slave_status = true;
213 }
214 } else {
215 printf("Not a known sever implementation: %s\n", server_version);
216 exit(STATE_UNKNOWN);
217 }
218
219 char *replica_query = NULL;
220 if (use_deprecated_slave_status) {
221 replica_query = "show slave status";
222 } else {
223 replica_query = "show replica status";
224 }
225
226 /* check the replica status */
227 if (mysql_query(&mysql, replica_query) != 0) {
216 error = strdup(mysql_error(&mysql)); 228 error = strdup(mysql_error(&mysql));
217 mysql_close (&mysql); 229 mysql_close(&mysql);
218 die (STATE_CRITICAL, _("slave query error: %s\n"), error); 230 die(STATE_CRITICAL, _("replica query error: %s\n"), error);
219 } 231 }
220 232
221 /* store the result */ 233 /* store the result */
222 if ( (res = mysql_store_result (&mysql)) == NULL) { 234 if ((res = mysql_store_result(&mysql)) == NULL) {
223 error = strdup(mysql_error(&mysql)); 235 error = strdup(mysql_error(&mysql));
224 mysql_close (&mysql); 236 mysql_close(&mysql);
225 die (STATE_CRITICAL, _("slave store_result error: %s\n"), error); 237 die(STATE_CRITICAL, _("replica store_result error: %s\n"), error);
226 } 238 }
227 239
228 /* Check there is some data */ 240 /* Check there is some data */
229 if (mysql_num_rows(res) == 0) { 241 if (mysql_num_rows(res) == 0) {
230 mysql_close(&mysql); 242 mysql_close(&mysql);
231 die (STATE_WARNING, "%s\n", _("No slaves defined")); 243 die(STATE_WARNING, "%s\n", _("No replicas defined"));
232 } 244 }
233 245
234 /* fetch the first row */ 246 /* fetch the first row */
235 if ( (row = mysql_fetch_row (res)) == NULL) { 247 if ((row = mysql_fetch_row(res)) == NULL) {
236 error = strdup(mysql_error(&mysql)); 248 error = strdup(mysql_error(&mysql));
237 mysql_free_result (res); 249 mysql_free_result(res);
238 mysql_close (&mysql); 250 mysql_close(&mysql);
239 die (STATE_CRITICAL, _("slave fetch row error: %s\n"), error); 251 die(STATE_CRITICAL, _("replica fetch row error: %s\n"), error);
240 } 252 }
241 253
242 if (mysql_field_count (&mysql) == 12) { 254 if (mysql_field_count(&mysql) == 12) {
243 /* mysql 3.23.x */ 255 /* mysql 3.23.x */
244 snprintf (slaveresult, SLAVERESULTSIZE, _("Slave running: %s"), row[6]); 256 snprintf(replica_result, REPLICA_RESULTSIZE, _("Replica running: %s"), row[6]);
245 if (strcmp (row[6], "Yes") != 0) { 257 if (strcmp(row[6], "Yes") != 0) {
246 mysql_free_result (res); 258 mysql_free_result(res);
247 mysql_close (&mysql); 259 mysql_close(&mysql);
248 die (STATE_CRITICAL, "%s\n", slaveresult); 260 die(STATE_CRITICAL, "%s\n", replica_result);
249 } 261 }
250 262
251 } else { 263 } else {
252 /* mysql 4.x.x and mysql 5.x.x */ 264 /* mysql 4.x.x and mysql 5.x.x */
253 int slave_io_field = -1 , slave_sql_field = -1, seconds_behind_field = -1, i, num_fields; 265 int replica_io_field = -1;
254 MYSQL_FIELD* fields; 266 int replica_sql_field = -1;
255 267 int seconds_behind_field = -1;
268 int num_fields;
269 MYSQL_FIELD *fields;
256 num_fields = mysql_num_fields(res); 270 num_fields = mysql_num_fields(res);
257 fields = mysql_fetch_fields(res); 271 fields = mysql_fetch_fields(res);
258 for(i = 0; i < num_fields; i++) { 272 for (int i = 0; i < num_fields; i++) {
259 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) { 273 if (strcmp(fields[i].name, "Slave_IO_Running") == 0) {
260 slave_io_field = i; 274 replica_io_field = i;
261 continue; 275 continue;
262 } 276 }
263 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) { 277 if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) {
264 slave_sql_field = i; 278 replica_sql_field = i;
265 continue; 279 continue;
266 } 280 }
267 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) { 281 if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) {
@@ -270,175 +284,177 @@ main (int argc, char **argv)
270 } 284 }
271 } 285 }
272 286
273 /* Check if slave status is available */ 287 /* Check if replica status is available */
274 if ((slave_io_field < 0) || (slave_sql_field < 0) || (num_fields == 0)) { 288 if ((replica_io_field < 0) || (replica_sql_field < 0) || (num_fields == 0)) {
275 mysql_free_result (res); 289 mysql_free_result(res);
276 mysql_close (&mysql); 290 mysql_close(&mysql);
277 die (STATE_CRITICAL, "Slave status unavailable\n"); 291 die(STATE_CRITICAL, "Replica status unavailable\n");
278 } 292 }
279 293
280 /* Save slave status in slaveresult */ 294 /* Save replica status in replica_result */
281 snprintf (slaveresult, SLAVERESULTSIZE, "Slave IO: %s Slave SQL: %s Seconds Behind Master: %s", row[slave_io_field], row[slave_sql_field], seconds_behind_field!=-1?row[seconds_behind_field]:"Unknown"); 295 snprintf(replica_result, REPLICA_RESULTSIZE, "Replica IO: %s Replica SQL: %s Seconds Behind Master: %s", row[replica_io_field],
296 row[replica_sql_field], seconds_behind_field != -1 ? row[seconds_behind_field] : "Unknown");
282 297
283 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */ 298 /* Raise critical error if SQL THREAD or IO THREAD are stopped, but only if there are no mysqldump threads running */
284 if (strcmp (row[slave_io_field], "Yes") != 0 || strcmp (row[slave_sql_field], "Yes") != 0) { 299 if (strcmp(row[replica_io_field], "Yes") != 0 || strcmp(row[replica_sql_field], "Yes") != 0) {
285 MYSQL_RES *res_mysqldump; 300 MYSQL_RES *res_mysqldump;
286 MYSQL_ROW row_mysqldump; 301 MYSQL_ROW row_mysqldump;
287 unsigned int mysqldump_threads = 0; 302 unsigned int mysqldump_threads = 0;
288 303
289 if (mysql_query (&mysql, MYSQLDUMP_THREADS_QUERY) == 0) { 304 if (mysql_query(&mysql, MYSQLDUMP_THREADS_QUERY) == 0) {
290 /* store the result */ 305 /* store the result */
291 if ( (res_mysqldump = mysql_store_result (&mysql)) != NULL) { 306 if ((res_mysqldump = mysql_store_result(&mysql)) != NULL) {
292 if (mysql_num_rows(res_mysqldump) == 1) { 307 if (mysql_num_rows(res_mysqldump) == 1) {
293 if ( (row_mysqldump = mysql_fetch_row (res_mysqldump)) != NULL) { 308 if ((row_mysqldump = mysql_fetch_row(res_mysqldump)) != NULL) {
294 mysqldump_threads = atoi(row_mysqldump[0]); 309 mysqldump_threads = atoi(row_mysqldump[0]);
295 } 310 }
296 } 311 }
297 /* free the result */ 312 /* free the result */
298 mysql_free_result (res_mysqldump); 313 mysql_free_result(res_mysqldump);
299 } 314 }
300 mysql_close (&mysql); 315 mysql_close(&mysql);
301 } 316 }
302 if (mysqldump_threads == 0) { 317 if (mysqldump_threads == 0) {
303 die (STATE_CRITICAL, "%s\n", slaveresult); 318 die(STATE_CRITICAL, "%s\n", replica_result);
304 } else { 319 } else {
305 strncat(slaveresult, " Mysqldump: in progress", SLAVERESULTSIZE-1); 320 strncat(replica_result, " Mysqldump: in progress", REPLICA_RESULTSIZE - 1);
306 } 321 }
307 } 322 }
308 323
309 if (verbose >=3) { 324 if (verbose >= 3) {
310 if (seconds_behind_field == -1) { 325 if (seconds_behind_field == -1) {
311 printf("seconds_behind_field not found\n"); 326 printf("seconds_behind_field not found\n");
312 } else { 327 } else {
313 printf ("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]); 328 printf("seconds_behind_field(index %d)=%s\n", seconds_behind_field, row[seconds_behind_field]);
314 } 329 }
315 } 330 }
316 331
317 /* Check Seconds Behind against threshold */ 332 /* Check Seconds Behind against threshold */
318 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp (row[seconds_behind_field], "NULL") != 0)) { 333 if ((seconds_behind_field != -1) && (row[seconds_behind_field] != NULL && strcmp(row[seconds_behind_field], "NULL") != 0)) {
319 double value = atof(row[seconds_behind_field]); 334 double value = atof(row[seconds_behind_field]);
320 int status; 335 int status;
321 336
322 status = get_status(value, my_threshold); 337 status = get_status(value, config.my_threshold);
323 338
324 xasprintf (&perf, "%s %s", perf, fperfdata ("seconds behind master", value, "s", 339 xasprintf(&perf, "%s %s", perf,
325 true, (double) warning_time, 340 fperfdata("seconds behind master", value, "s", true, (double)config.warning_time, true,
326 true, (double) critical_time, 341 (double)config.critical_time, false, 0, false, 0));
327 false, 0,
328 false, 0));
329 342
330 if (status == STATE_WARNING) { 343 if (status == STATE_WARNING) {
331 printf("SLOW_SLAVE %s: %s|%s\n", _("WARNING"), slaveresult, perf); 344 printf("SLOW_REPLICA %s: %s|%s\n", _("WARNING"), replica_result, perf);
332 exit(STATE_WARNING); 345 exit(STATE_WARNING);
333 } else if (status == STATE_CRITICAL) { 346 } else if (status == STATE_CRITICAL) {
334 printf("SLOW_SLAVE %s: %s|%s\n", _("CRITICAL"), slaveresult, perf); 347 printf("SLOW_REPLICA %s: %s|%s\n", _("CRITICAL"), replica_result, perf);
335 exit(STATE_CRITICAL); 348 exit(STATE_CRITICAL);
336 } 349 }
337 } 350 }
338 } 351 }
339 352
340 /* free the result */ 353 /* free the result */
341 mysql_free_result (res); 354 mysql_free_result(res);
342 } 355 }
343 356
344 /* close the connection */ 357 /* close the connection */
345 mysql_close (&mysql); 358 mysql_close(&mysql);
346 359
347 /* print out the result of stats */ 360 /* print out the result of stats */
348 if (check_slave) { 361 if (config.check_replica) {
349 printf ("%s %s|%s\n", result, slaveresult, perf); 362 printf("%s %s|%s\n", result, replica_result, perf);
350 } else { 363 } else {
351 printf ("%s|%s\n", result, perf); 364 printf("%s|%s\n", result, perf);
352 } 365 }
353 366
354 return STATE_OK; 367 return STATE_OK;
355} 368}
356 369
370#define CHECK_REPLICA_OPT CHAR_MAX + 1
357 371
358/* process command-line arguments */ 372/* process command-line arguments */
359int 373check_mysql_config_wrapper process_arguments(int argc, char **argv) {
360process_arguments (int argc, char **argv) 374 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
361{ 375 {"socket", required_argument, 0, 's'},
362 int c; 376 {"database", required_argument, 0, 'd'},
377 {"username", required_argument, 0, 'u'},
378 {"password", required_argument, 0, 'p'},
379 {"file", required_argument, 0, 'f'},
380 {"group", required_argument, 0, 'g'},
381 {"port", required_argument, 0, 'P'},
382 {"critical", required_argument, 0, 'c'},
383 {"warning", required_argument, 0, 'w'},
384 {"check-slave", no_argument, 0, 'S'},
385 {"check-replica", no_argument, 0, CHECK_REPLICA_OPT},
386 {"ignore-auth", no_argument, 0, 'n'},
387 {"verbose", no_argument, 0, 'v'},
388 {"version", no_argument, 0, 'V'},
389 {"help", no_argument, 0, 'h'},
390 {"ssl", no_argument, 0, 'l'},
391 {"ca-cert", optional_argument, 0, 'C'},
392 {"key", required_argument, 0, 'k'},
393 {"cert", required_argument, 0, 'a'},
394 {"ca-dir", required_argument, 0, 'D'},
395 {"ciphers", required_argument, 0, 'L'},
396 {0, 0, 0, 0}};
397
398 check_mysql_config_wrapper result = {
399 .errorcode = OK,
400 .config = check_mysql_config_init(),
401 };
402
403 if (argc < 1) {
404 result.errorcode = ERROR;
405 return result;
406 }
407
363 char *warning = NULL; 408 char *warning = NULL;
364 char *critical = NULL; 409 char *critical = NULL;
365 410
366 int option = 0; 411 int option = 0;
367 static struct option longopts[] = { 412 while (true) {
368 {"hostname", required_argument, 0, 'H'}, 413 int option_index = getopt_long(argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
369 {"socket", required_argument, 0, 's'},
370 {"database", required_argument, 0, 'd'},
371 {"username", required_argument, 0, 'u'},
372 {"password", required_argument, 0, 'p'},
373 {"file", required_argument, 0, 'f'},
374 {"group", required_argument, 0, 'g'},
375 {"port", required_argument, 0, 'P'},
376 {"critical", required_argument, 0, 'c'},
377 {"warning", required_argument, 0, 'w'},
378 {"check-slave", no_argument, 0, 'S'},
379 {"ignore-auth", no_argument, 0, 'n'},
380 {"verbose", no_argument, 0, 'v'},
381 {"version", no_argument, 0, 'V'},
382 {"help", no_argument, 0, 'h'},
383 {"ssl", no_argument, 0, 'l'},
384 {"ca-cert", optional_argument, 0, 'C'},
385 {"key", required_argument,0,'k'},
386 {"cert", required_argument,0,'a'},
387 {"ca-dir", required_argument, 0, 'D'},
388 {"ciphers", required_argument, 0, 'L'},
389 {0, 0, 0, 0}
390 };
391 414
392 if (argc < 1) 415 if (option_index == -1 || option_index == EOF) {
393 return ERROR;
394
395 while (1) {
396 c = getopt_long (argc, argv, "hlvVnSP:p:u:d:H:s:c:w:a:k:C:D:L:f:g:", longopts, &option);
397
398 if (c == -1 || c == EOF)
399 break; 416 break;
417 }
400 418
401 switch (c) { 419 switch (option_index) {
402 case 'H': /* hostname */ 420 case 'H': /* hostname */
403 if (is_host (optarg)) { 421 if (is_host(optarg)) {
404 db_host = optarg; 422 result.config.db_host = optarg;
405 } 423 } else if (*optarg == '/') {
406 else if (*optarg == '/') { 424 result.config.db_socket = optarg;
407 db_socket = optarg; 425 } else {
408 } 426 usage2(_("Invalid hostname/address"), optarg);
409 else {
410 usage2 (_("Invalid hostname/address"), optarg);
411 } 427 }
412 break; 428 break;
413 case 's': /* socket */ 429 case 's': /* socket */
414 db_socket = optarg; 430 result.config.db_socket = optarg;
415 break; 431 break;
416 case 'd': /* database */ 432 case 'd': /* database */
417 db = optarg; 433 result.config.db = optarg;
418 break; 434 break;
419 case 'l': 435 case 'l':
420 ssl = true; 436 result.config.ssl = true;
421 break; 437 break;
422 case 'C': 438 case 'C':
423 ca_cert = optarg; 439 result.config.ca_cert = optarg;
424 break; 440 break;
425 case 'a': 441 case 'a':
426 cert = optarg; 442 result.config.cert = optarg;
427 break; 443 break;
428 case 'k': 444 case 'k':
429 key = optarg; 445 result.config.key = optarg;
430 break; 446 break;
431 case 'D': 447 case 'D':
432 ca_dir = optarg; 448 result.config.ca_dir = optarg;
433 break; 449 break;
434 case 'L': 450 case 'L':
435 ciphers = optarg; 451 result.config.ciphers = optarg;
436 break; 452 break;
437 case 'u': /* username */ 453 case 'u': /* username */
438 db_user = optarg; 454 result.config.db_user = optarg;
439 break; 455 break;
440 case 'p': /* authentication information: password */ 456 case 'p': /* authentication information: password */
441 db_pass = strdup(optarg); 457 result.config.db_pass = strdup(optarg);
442 458
443 /* Delete the password from process list */ 459 /* Delete the password from process list */
444 while (*optarg != '\0') { 460 while (*optarg != '\0') {
@@ -446,167 +462,163 @@ process_arguments (int argc, char **argv)
446 optarg++; 462 optarg++;
447 } 463 }
448 break; 464 break;
449 case 'f': /* client options file */ 465 case 'f': /* client options file */
450 opt_file = optarg; 466 result.config.opt_file = optarg;
451 break; 467 break;
452 case 'g': /* client options group */ 468 case 'g': /* client options group */
453 opt_group = optarg; 469 result.config.opt_group = optarg;
454 break; 470 break;
455 case 'P': /* critical time threshold */ 471 case 'P': /* critical time threshold */
456 db_port = atoi (optarg); 472 result.config.db_port = atoi(optarg);
457 break; 473 break;
458 case 'S': 474 case 'S':
459 check_slave = true; /* check-slave */ 475 case CHECK_REPLICA_OPT:
476 result.config.check_replica = true; /* check-slave */
460 break; 477 break;
461 case 'n': 478 case 'n':
462 ignore_auth = true; /* ignore-auth */ 479 result.config.ignore_auth = true; /* ignore-auth */
463 break; 480 break;
464 case 'w': 481 case 'w':
465 warning = optarg; 482 warning = optarg;
466 warning_time = strtod (warning, NULL); 483 result.config.warning_time = strtod(warning, NULL);
467 break; 484 break;
468 case 'c': 485 case 'c':
469 critical = optarg; 486 critical = optarg;
470 critical_time = strtod (critical, NULL); 487 result.config.critical_time = strtod(critical, NULL);
471 break; 488 break;
472 case 'V': /* version */ 489 case 'V': /* version */
473 print_revision (progname, NP_VERSION); 490 print_revision(progname, NP_VERSION);
474 exit (STATE_UNKNOWN); 491 exit(STATE_UNKNOWN);
475 case 'h': /* help */ 492 case 'h': /* help */
476 print_help (); 493 print_help();
477 exit (STATE_UNKNOWN); 494 exit(STATE_UNKNOWN);
478 case 'v': 495 case 'v':
479 verbose++; 496 verbose++;
480 break; 497 break;
481 case '?': /* help */ 498 case '?': /* help */
482 usage5 (); 499 usage5();
483 } 500 }
484 } 501 }
485 502
486 c = optind; 503 int index = optind;
487
488 set_thresholds(&my_threshold, warning, critical);
489 504
490 while ( argc > c ) { 505 set_thresholds(&result.config.my_threshold, warning, critical);
491 506
492 if (db_host == NULL) 507 while (argc > index) {
493 if (is_host (argv[c])) { 508 if (result.config.db_host == NULL) {
494 db_host = argv[c++]; 509 if (is_host(argv[index])) {
510 result.config.db_host = argv[index++];
511 } else {
512 usage2(_("Invalid hostname/address"), argv[index]);
495 } 513 }
496 else { 514 } else if (result.config.db_user == NULL) {
497 usage2 (_("Invalid hostname/address"), argv[c]); 515 result.config.db_user = argv[index++];
498 } 516 } else if (result.config.db_pass == NULL) {
499 else if (db_user == NULL) 517 result.config.db_pass = argv[index++];
500 db_user = argv[c++]; 518 } else if (result.config.db == NULL) {
501 else if (db_pass == NULL) 519 result.config.db = argv[index++];
502 db_pass = argv[c++]; 520 } else if (is_intnonneg(argv[index])) {
503 else if (db == NULL) 521 result.config.db_port = atoi(argv[index++]);
504 db = argv[c++]; 522 } else {
505 else if (is_intnonneg (argv[c]))
506 db_port = atoi (argv[c++]);
507 else
508 break; 523 break;
524 }
509 } 525 }
510 526
511 return validate_arguments (); 527 return validate_arguments(result);
512} 528}
513 529
530check_mysql_config_wrapper validate_arguments(check_mysql_config_wrapper config_wrapper) {
531 if (config_wrapper.config.db_user == NULL) {
532 config_wrapper.config.db_user = strdup("");
533 }
514 534
515int 535 if (config_wrapper.config.db_host == NULL) {
516validate_arguments (void) 536 config_wrapper.config.db_host = strdup("");
517{ 537 }
518 if (db_user == NULL)
519 db_user = strdup("");
520
521 if (db_host == NULL)
522 db_host = strdup("");
523 538
524 if (db == NULL) 539 if (config_wrapper.config.db == NULL) {
525 db = strdup(""); 540 config_wrapper.config.db = strdup("");
541 }
526 542
527 return OK; 543 return config_wrapper;
528} 544}
529 545
530 546void print_help(void) {
531void
532print_help (void)
533{
534 char *myport; 547 char *myport;
535 xasprintf (&myport, "%d", MYSQL_PORT); 548 xasprintf(&myport, "%d", MYSQL_PORT);
536 549
537 print_revision (progname, NP_VERSION); 550 print_revision(progname, NP_VERSION);
538 551
539 printf (_(COPYRIGHT), copyright, email); 552 printf(_(COPYRIGHT), copyright, email);
540 553
541 printf ("%s\n", _("This program tests connections to a MySQL server")); 554 printf("%s\n", _("This program tests connections to a MySQL server"));
542 555
543 printf ("\n\n"); 556 printf("\n\n");
544 557
545 print_usage (); 558 print_usage();
546 559
547 printf (UT_HELP_VRSN); 560 printf(UT_HELP_VRSN);
548 printf (UT_EXTRA_OPTS); 561 printf(UT_EXTRA_OPTS);
549 562
550 printf (UT_HOST_PORT, 'P', myport); 563 printf(UT_HOST_PORT, 'P', myport);
551 printf (" %s\n", "-n, --ignore-auth"); 564 printf(" %s\n", "-n, --ignore-auth");
552 printf (" %s\n", _("Ignore authentication failure and check for mysql connectivity only")); 565 printf(" %s\n", _("Ignore authentication failure and check for mysql connectivity only"));
553 566
554 printf (" %s\n", "-s, --socket=STRING"); 567 printf(" %s\n", "-s, --socket=STRING");
555 printf (" %s\n", _("Use the specified socket (has no effect if -H is used)")); 568 printf(" %s\n", _("Use the specified socket (has no effect if -H is used)"));
556 569
557 printf (" %s\n", "-d, --database=STRING"); 570 printf(" %s\n", "-d, --database=STRING");
558 printf (" %s\n", _("Check database with indicated name")); 571 printf(" %s\n", _("Check database with indicated name"));
559 printf (" %s\n", "-f, --file=STRING"); 572 printf(" %s\n", "-f, --file=STRING");
560 printf (" %s\n", _("Read from the specified client options file")); 573 printf(" %s\n", _("Read from the specified client options file"));
561 printf (" %s\n", "-g, --group=STRING"); 574 printf(" %s\n", "-g, --group=STRING");
562 printf (" %s\n", _("Use a client options group")); 575 printf(" %s\n", _("Use a client options group"));
563 printf (" %s\n", "-u, --username=STRING"); 576 printf(" %s\n", "-u, --username=STRING");
564 printf (" %s\n", _("Connect using the indicated username")); 577 printf(" %s\n", _("Connect using the indicated username"));
565 printf (" %s\n", "-p, --password=STRING"); 578 printf(" %s\n", "-p, --password=STRING");
566 printf (" %s\n", _("Use the indicated password to authenticate the connection")); 579 printf(" %s\n", _("Use the indicated password to authenticate the connection"));
567 printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 580 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
568 printf (" %s\n", _("Your clear-text password could be visible as a process table entry")); 581 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
569 printf (" %s\n", "-S, --check-slave"); 582 printf(" %s\n", "-S, --check-slave");
570 printf (" %s\n", _("Check if the slave thread is running properly.")); 583 printf(" %s\n",
571 printf (" %s\n", "-w, --warning"); 584 _("Check if the slave thread is running properly. This option is deprecated in favour of check-replica, which does the same"));
572 printf (" %s\n", _("Exit with WARNING status if slave server is more than INTEGER seconds")); 585 printf(" %s\n", "--check-replica");
573 printf (" %s\n", _("behind master")); 586 printf(" %s\n", _("Check if the replica thread is running properly."));
574 printf (" %s\n", "-c, --critical"); 587 printf(" %s\n", "-w, --warning");
575 printf (" %s\n", _("Exit with CRITICAL status if slave server is more then INTEGER seconds")); 588 printf(" %s\n", _("Exit with WARNING status if replica server is more than INTEGER seconds"));
576 printf (" %s\n", _("behind master")); 589 printf(" %s\n", _("behind master"));
577 printf (" %s\n", "-l, --ssl"); 590 printf(" %s\n", "-c, --critical");
578 printf (" %s\n", _("Use ssl encryption")); 591 printf(" %s\n", _("Exit with CRITICAL status if replica server is more then INTEGER seconds"));
579 printf (" %s\n", "-C, --ca-cert=STRING"); 592 printf(" %s\n", _("behind master"));
580 printf (" %s\n", _("Path to CA signing the cert")); 593 printf(" %s\n", "-l, --ssl");
581 printf (" %s\n", "-a, --cert=STRING"); 594 printf(" %s\n", _("Use ssl encryption"));
582 printf (" %s\n", _("Path to SSL certificate")); 595 printf(" %s\n", "-C, --ca-cert=STRING");
583 printf (" %s\n", "-k, --key=STRING"); 596 printf(" %s\n", _("Path to CA signing the cert"));
584 printf (" %s\n", _("Path to private SSL key")); 597 printf(" %s\n", "-a, --cert=STRING");
585 printf (" %s\n", "-D, --ca-dir=STRING"); 598 printf(" %s\n", _("Path to SSL certificate"));
586 printf (" %s\n", _("Path to CA directory")); 599 printf(" %s\n", "-k, --key=STRING");
587 printf (" %s\n", "-L, --ciphers=STRING"); 600 printf(" %s\n", _("Path to private SSL key"));
588 printf (" %s\n", _("List of valid SSL ciphers")); 601 printf(" %s\n", "-D, --ca-dir=STRING");
589 602 printf(" %s\n", _("Path to CA directory"));
590 603 printf(" %s\n", "-L, --ciphers=STRING");
591 printf ("\n"); 604 printf(" %s\n", _("List of valid SSL ciphers"));
592 printf (" %s\n", _("There are no required arguments. By default, the local database is checked")); 605
593 printf (" %s\n", _("using the default unix socket. You can force TCP on localhost by using an")); 606 printf("\n");
594 printf (" %s\n", _("IP address or FQDN ('localhost' will use the socket as well).")); 607 printf(" %s\n", _("There are no required arguments. By default, the local database is checked"));
595 608 printf(" %s\n", _("using the default unix socket. You can force TCP on localhost by using an"));
596 printf ("\n"); 609 printf(" %s\n", _("IP address or FQDN ('localhost' will use the socket as well)."));
597 printf ("%s\n", _("Notes:")); 610
598 printf (" %s\n", _("You must specify -p with an empty string to force an empty password,")); 611 printf("\n");
599 printf (" %s\n", _("overriding any my.cnf settings.")); 612 printf("%s\n", _("Notes:"));
600 613 printf(" %s\n", _("You must specify -p with an empty string to force an empty password,"));
601 printf (UT_SUPPORT); 614 printf(" %s\n", _("overriding any my.cnf settings."));
615
616 printf(UT_SUPPORT);
602} 617}
603 618
604 619void print_usage(void) {
605void 620 printf("%s\n", _("Usage:"));
606print_usage (void) 621 printf(" %s [-d database] [-H host] [-P port] [-s socket]\n", progname);
607{ 622 printf(" [-u user] [-p password] [-S] [-l] [-a cert] [-k key]\n");
608 printf ("%s\n", _("Usage:")); 623 printf(" [-C ca-cert] [-D ca-dir] [-L ciphers] [-f optfile] [-g group]\n");
609 printf (" %s [-d database] [-H host] [-P port] [-s socket]\n",progname);
610 printf (" [-u user] [-p password] [-S] [-l] [-a cert] [-k key]\n");
611 printf (" [-C ca-cert] [-D ca-dir] [-L ciphers] [-f optfile] [-g group]\n");
612} 624}
diff --git a/plugins/check_mysql.d/config.h b/plugins/check_mysql.d/config.h
new file mode 100644
index 00000000..71ddbe8d
--- /dev/null
+++ b/plugins/check_mysql.d/config.h
@@ -0,0 +1,58 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6#include <mysql.h>
7
8typedef struct {
9 char *db_host;
10 unsigned int db_port;
11 char *db_user;
12 char *db_socket;
13 char *db_pass;
14 char *db;
15 char *ca_cert;
16 char *ca_dir;
17 char *cert;
18 char *key;
19 char *ciphers;
20 bool ssl;
21 char *opt_file;
22 char *opt_group;
23
24 bool check_replica;
25 bool ignore_auth;
26
27 double warning_time;
28 double critical_time;
29 thresholds *my_threshold;
30
31} check_mysql_config;
32
33check_mysql_config check_mysql_config_init() {
34 check_mysql_config tmp = {
35 .db_host = NULL,
36 .db_port = MYSQL_PORT,
37 .db = NULL,
38 .db_pass = NULL,
39 .db_socket = NULL,
40 .db_user = NULL,
41 .ca_cert = NULL,
42 .ca_dir = NULL,
43 .cert = NULL,
44 .key = NULL,
45 .ciphers = NULL,
46 .ssl = false,
47 .opt_file = NULL,
48 .opt_group = NULL,
49
50 .check_replica = false,
51 .ignore_auth = false,
52
53 .warning_time = 0,
54 .critical_time = 0,
55 .my_threshold = NULL,
56 };
57 return tmp;
58}
diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c
index 842b7a2f..5e04a94b 100644
--- a/plugins/check_mysql_query.c
+++ b/plugins/check_mysql_query.c
@@ -1,157 +1,151 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_mysql_query plugin 3 * Monitoring check_mysql_query plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006-2009 Monitoring Plugins Development Team 6 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
7* Original code from check_mysql, copyright 1999 Didi Rieder 7 * Original code from check_mysql, copyright 1999 Didi Rieder
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_mysql_query plugin 11 * This file contains the check_mysql_query plugin
12* 12 *
13* This plugin is for running arbitrary SQL and checking the results 13 * This plugin is for running arbitrary SQL and checking the results
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_mysql_query"; 32const char *progname = "check_mysql_query";
33const char *copyright = "1999-2007"; 33const char *copyright = "1999-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "utils_base.h" 38#include "utils_base.h"
39#include "netutils.h" 39#include "netutils.h"
40#include "check_mysql_query.d/config.h"
40 41
41#include <mysql.h> 42#include <mysql.h>
42#include <errmsg.h> 43#include <errmsg.h>
43 44
44char *db_user = NULL; 45typedef struct {
45char *db_host = NULL; 46 int errorcode;
46char *db_socket = NULL; 47 check_mysql_query_config config;
47char *db_pass = NULL; 48} check_mysql_query_config_wrapper;
48char *db = NULL; 49static check_mysql_query_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
49char *opt_file = NULL; 50static check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper /*config_wrapper*/);
50char *opt_group = NULL; 51static void print_help(void);
51unsigned int db_port = MYSQL_PORT; 52void print_usage(void);
52 53
53int process_arguments (int, char **); 54static int verbose = 0;
54int validate_arguments (void);
55void print_help (void);
56void print_usage (void);
57 55
58char *sql_query = NULL; 56int main(int argc, char **argv) {
59int verbose = 0; 57 setlocale(LC_ALL, "");
60thresholds *my_thresholds = NULL; 58 bindtextdomain(PACKAGE, LOCALEDIR);
61 59 textdomain(PACKAGE);
62
63int
64main (int argc, char **argv)
65{
66
67 MYSQL mysql;
68 MYSQL_RES *res;
69 MYSQL_ROW row;
70
71 double value;
72 char *error = NULL;
73 int status;
74
75 setlocale (LC_ALL, "");
76 bindtextdomain (PACKAGE, LOCALEDIR);
77 textdomain (PACKAGE);
78 60
79 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
80 argv=np_extra_opts (&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
81 63
82 if (process_arguments (argc, argv) == ERROR) 64 check_mysql_query_config_wrapper tmp_config = process_arguments(argc, argv);
83 usage4 (_("Could not parse arguments")); 65 if (tmp_config.errorcode == ERROR) {
66 usage4(_("Could not parse arguments"));
67 }
84 68
69 const check_mysql_query_config config = tmp_config.config;
70
71 MYSQL mysql;
85 /* initialize mysql */ 72 /* initialize mysql */
86 mysql_init (&mysql); 73 mysql_init(&mysql);
87 74
88 if (opt_file != NULL) 75 if (config.opt_file != NULL) {
89 mysql_options(&mysql,MYSQL_READ_DEFAULT_FILE,opt_file); 76 mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
77 }
90 78
91 if (opt_group != NULL) 79 if (config.opt_group != NULL) {
92 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,opt_group); 80 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
93 else 81 } else {
94 mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"client"); 82 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
83 }
95 84
96 /* establish a connection to the server and error checking */ 85 /* establish a connection to the server and error checking */
97 if (!mysql_real_connect(&mysql,db_host,db_user,db_pass,db,db_port,db_socket,0)) { 86 if (!mysql_real_connect(&mysql, config.db_host, config.db_user, config.db_pass, config.db, config.db_port, config.db_socket, 0)) {
98 if (mysql_errno (&mysql) == CR_UNKNOWN_HOST) 87 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
99 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 88 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
100 else if (mysql_errno (&mysql) == CR_VERSION_ERROR) 89 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
101 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 90 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
102 else if (mysql_errno (&mysql) == CR_OUT_OF_MEMORY) 91 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
103 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 92 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
104 else if (mysql_errno (&mysql) == CR_IPSOCK_ERROR) 93 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
105 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 94 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
106 else if (mysql_errno (&mysql) == CR_SOCKET_CREATE_ERROR) 95 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
107 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error (&mysql)); 96 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
108 else 97 } else {
109 die (STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error (&mysql)); 98 die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql));
99 }
110 } 100 }
111 101
112 if (mysql_query (&mysql, sql_query) != 0) { 102 char *error = NULL;
103 if (mysql_query(&mysql, config.sql_query) != 0) {
113 error = strdup(mysql_error(&mysql)); 104 error = strdup(mysql_error(&mysql));
114 mysql_close (&mysql); 105 mysql_close(&mysql);
115 die (STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error); 106 die(STATE_CRITICAL, "QUERY %s: %s - %s\n", _("CRITICAL"), _("Error with query"), error);
116 } 107 }
117 108
109 MYSQL_RES *res;
118 /* store the result */ 110 /* store the result */
119 if ( (res = mysql_store_result (&mysql)) == NULL) { 111 if ((res = mysql_store_result(&mysql)) == NULL) {
120 error = strdup(mysql_error(&mysql)); 112 error = strdup(mysql_error(&mysql));
121 mysql_close (&mysql); 113 mysql_close(&mysql);
122 die (STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error); 114 die(STATE_CRITICAL, "QUERY %s: Error with store_result - %s\n", _("CRITICAL"), error);
123 } 115 }
124 116
125 /* Check there is some data */ 117 /* Check there is some data */
126 if (mysql_num_rows(res) == 0) { 118 if (mysql_num_rows(res) == 0) {
127 mysql_close(&mysql); 119 mysql_close(&mysql);
128 die (STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned")); 120 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), _("No rows returned"));
129 } 121 }
130 122
123 MYSQL_ROW row;
131 /* fetch the first row */ 124 /* fetch the first row */
132 if ( (row = mysql_fetch_row (res)) == NULL) { 125 if ((row = mysql_fetch_row(res)) == NULL) {
133 error = strdup(mysql_error(&mysql)); 126 error = strdup(mysql_error(&mysql));
134 mysql_free_result (res); 127 mysql_free_result(res);
135 mysql_close (&mysql); 128 mysql_close(&mysql);
136 die (STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error); 129 die(STATE_CRITICAL, "QUERY %s: Fetch row error - %s\n", _("CRITICAL"), error);
137 } 130 }
138 131
139 if (! is_numeric(row[0])) { 132 if (!is_numeric(row[0])) {
140 die (STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]); 133 die(STATE_CRITICAL, "QUERY %s: %s - '%s'\n", _("CRITICAL"), _("Is not a numeric"), row[0]);
141 } 134 }
142 135
143 value = strtod(row[0], NULL); 136 double value = strtod(row[0], NULL);
144 137
145 /* free the result */ 138 /* free the result */
146 mysql_free_result (res); 139 mysql_free_result(res);
147 140
148 /* close the connection */ 141 /* close the connection */
149 mysql_close (&mysql); 142 mysql_close(&mysql);
150 143
151 if (verbose >= 3) 144 if (verbose >= 3) {
152 printf("mysql result: %f\n", value); 145 printf("mysql result: %f\n", value);
146 }
153 147
154 status = get_status(value, my_thresholds); 148 int status = get_status(value, config.my_thresholds);
155 149
156 if (status == STATE_OK) { 150 if (status == STATE_OK) {
157 printf("QUERY %s: ", _("OK")); 151 printf("QUERY %s: ", _("OK"));
@@ -160,75 +154,63 @@ main (int argc, char **argv)
160 } else if (status == STATE_CRITICAL) { 154 } else if (status == STATE_CRITICAL) {
161 printf("QUERY %s: ", _("CRITICAL")); 155 printf("QUERY %s: ", _("CRITICAL"));
162 } 156 }
163 printf(_("'%s' returned %f | %s"), sql_query, value, 157 printf(_("'%s' returned %f | %s"), config.sql_query, value,
164 fperfdata("result", value, "", 158 fperfdata("result", value, "", config.my_thresholds->warning, config.my_thresholds->warning ? config.my_thresholds->warning->end : 0,
165 my_thresholds->warning?true:false, my_thresholds->warning?my_thresholds->warning->end:0, 159 config.my_thresholds->critical, config.my_thresholds->critical ? config.my_thresholds->critical->end : 0, false, 0, false, 0));
166 my_thresholds->critical?true:false, my_thresholds->critical?my_thresholds->critical->end:0,
167 false, 0,
168 false, 0)
169 );
170 printf("\n"); 160 printf("\n");
171 161
172 return status; 162 return status;
173} 163}
174 164
175
176/* process command-line arguments */ 165/* process command-line arguments */
177int 166check_mysql_query_config_wrapper process_arguments(int argc, char **argv) {
178process_arguments (int argc, char **argv)
179{
180 int c;
181 char *warning = NULL;
182 char *critical = NULL;
183
184 int option = 0;
185 static struct option longopts[] = { 167 static struct option longopts[] = {
186 {"hostname", required_argument, 0, 'H'}, 168 {"hostname", required_argument, 0, 'H'}, {"socket", required_argument, 0, 's'}, {"database", required_argument, 0, 'd'},
187 {"socket", required_argument, 0, 's'}, 169 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'}, {"file", required_argument, 0, 'f'},
188 {"database", required_argument, 0, 'd'}, 170 {"group", required_argument, 0, 'g'}, {"port", required_argument, 0, 'P'}, {"verbose", no_argument, 0, 'v'},
189 {"username", required_argument, 0, 'u'}, 171 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"query", required_argument, 0, 'q'},
190 {"password", required_argument, 0, 'p'}, 172 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {0, 0, 0, 0}};
191 {"file", required_argument, 0, 'f'}, 173
192 {"group", required_argument, 0, 'g'}, 174 check_mysql_query_config_wrapper result = {
193 {"port", required_argument, 0, 'P'}, 175 .errorcode = OK,
194 {"verbose", no_argument, 0, 'v'}, 176 .config = check_mysql_query_config_init(),
195 {"version", no_argument, 0, 'V'},
196 {"help", no_argument, 0, 'h'},
197 {"query", required_argument, 0, 'q'},
198 {"warning", required_argument, 0, 'w'},
199 {"critical", required_argument, 0, 'c'},
200 {0, 0, 0, 0}
201 }; 177 };
202 178
203 if (argc < 1) 179 if (argc < 1) {
204 return ERROR; 180 result.errorcode = ERROR;
181 return result;
182 }
205 183
206 while (1) { 184 char *warning = NULL;
207 c = getopt_long (argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option); 185 char *critical = NULL;
208 186
209 if (c == -1 || c == EOF) 187 while (true) {
188 int option = 0;
189 int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option);
190
191 if (option_char == -1 || option_char == EOF) {
210 break; 192 break;
193 }
211 194
212 switch (c) { 195 switch (option_char) {
213 case 'H': /* hostname */ 196 case 'H': /* hostname */
214 if (is_host (optarg)) { 197 if (is_host(optarg)) {
215 db_host = optarg; 198 result.config.db_host = optarg;
216 } 199 } else {
217 else { 200 usage2(_("Invalid hostname/address"), optarg);
218 usage2 (_("Invalid hostname/address"), optarg);
219 } 201 }
220 break; 202 break;
221 case 's': /* socket */ 203 case 's': /* socket */
222 db_socket = optarg; 204 result.config.db_socket = optarg;
223 break; 205 break;
224 case 'd': /* database */ 206 case 'd': /* database */
225 db = optarg; 207 result.config.db = optarg;
226 break; 208 break;
227 case 'u': /* username */ 209 case 'u': /* username */
228 db_user = optarg; 210 result.config.db_user = optarg;
229 break; 211 break;
230 case 'p': /* authentication information: password */ 212 case 'p': /* authentication information: password */
231 db_pass = strdup(optarg); 213 result.config.db_pass = strdup(optarg);
232 214
233 /* Delete the password from process list */ 215 /* Delete the password from process list */
234 while (*optarg != '\0') { 216 while (*optarg != '\0') {
@@ -236,26 +218,26 @@ process_arguments (int argc, char **argv)
236 optarg++; 218 optarg++;
237 } 219 }
238 break; 220 break;
239 case 'f': /* client options file */ 221 case 'f': /* client options file */
240 opt_file = optarg; 222 result.config.opt_file = optarg;
241 break; 223 break;
242 case 'g': /* client options group */ 224 case 'g': /* client options group */
243 opt_group = optarg; 225 result.config.opt_group = optarg;
244 break; 226 break;
245 case 'P': /* critical time threshold */ 227 case 'P': /* critical time threshold */
246 db_port = atoi (optarg); 228 result.config.db_port = atoi(optarg);
247 break; 229 break;
248 case 'v': 230 case 'v':
249 verbose++; 231 verbose++;
250 break; 232 break;
251 case 'V': /* version */ 233 case 'V': /* version */
252 print_revision (progname, NP_VERSION); 234 print_revision(progname, NP_VERSION);
253 exit (STATE_UNKNOWN); 235 exit(STATE_UNKNOWN);
254 case 'h': /* help */ 236 case 'h': /* help */
255 print_help (); 237 print_help();
256 exit (STATE_UNKNOWN); 238 exit(STATE_UNKNOWN);
257 case 'q': 239 case 'q':
258 xasprintf(&sql_query, "%s", optarg); 240 xasprintf(&result.config.sql_query, "%s", optarg);
259 break; 241 break;
260 case 'w': 242 case 'w':
261 warning = optarg; 243 warning = optarg;
@@ -263,92 +245,85 @@ process_arguments (int argc, char **argv)
263 case 'c': 245 case 'c':
264 critical = optarg; 246 critical = optarg;
265 break; 247 break;
266 case '?': /* help */ 248 case '?': /* help */
267 usage5 (); 249 usage5();
268 } 250 }
269 } 251 }
270 252
271 c = optind; 253 set_thresholds(&result.config.my_thresholds, warning, critical);
272 254
273 set_thresholds(&my_thresholds, warning, critical); 255 return validate_arguments(result);
274
275 return validate_arguments ();
276} 256}
277 257
278 258check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper config_wrapper) {
279int 259 if (config_wrapper.config.sql_query == NULL) {
280validate_arguments (void)
281{
282 if (sql_query == NULL)
283 usage("Must specify a SQL query to run"); 260 usage("Must specify a SQL query to run");
261 }
284 262
285 if (db_user == NULL) 263 if (config_wrapper.config.db_user == NULL) {
286 db_user = strdup(""); 264 config_wrapper.config.db_user = strdup("");
265 }
287 266
288 if (db_host == NULL) 267 if (config_wrapper.config.db_host == NULL) {
289 db_host = strdup(""); 268 config_wrapper.config.db_host = strdup("");
269 }
290 270
291 if (db == NULL) 271 if (config_wrapper.config.db == NULL) {
292 db = strdup(""); 272 config_wrapper.config.db = strdup("");
273 }
293 274
294 return OK; 275 return config_wrapper;
295} 276}
296 277
297 278void print_help(void) {
298void
299print_help (void)
300{
301 char *myport; 279 char *myport;
302 xasprintf (&myport, "%d", MYSQL_PORT); 280 xasprintf(&myport, "%d", MYSQL_PORT);
303 281
304 print_revision (progname, NP_VERSION); 282 print_revision(progname, NP_VERSION);
305 283
306 printf (_(COPYRIGHT), copyright, email); 284 printf(_(COPYRIGHT), copyright, email);
307 285
308 printf ("%s\n", _("This program checks a query result against threshold levels")); 286 printf("%s\n", _("This program checks a query result against threshold levels"));
309 287
310 printf ("\n\n"); 288 printf("\n\n");
311 289
312 print_usage (); 290 print_usage();
313 291
314 printf (UT_HELP_VRSN); 292 printf(UT_HELP_VRSN);
315 printf (UT_EXTRA_OPTS); 293 printf(UT_EXTRA_OPTS);
316 printf (" -q, --query=STRING\n"); 294 printf(" -q, --query=STRING\n");
317 printf (" %s\n", _("SQL query to run. Only first column in first row will be read")); 295 printf(" %s\n", _("SQL query to run. Only first column in first row will be read"));
318 printf (UT_WARN_CRIT_RANGE); 296 printf(UT_WARN_CRIT_RANGE);
319 printf (UT_HOST_PORT, 'P', myport); 297 printf(UT_HOST_PORT, 'P', myport);
320 printf (" %s\n", "-s, --socket=STRING"); 298 printf(" %s\n", "-s, --socket=STRING");
321 printf (" %s\n", _("Use the specified socket (has no effect if -H is used)")); 299 printf(" %s\n", _("Use the specified socket (has no effect if -H is used)"));
322 printf (" -d, --database=STRING\n"); 300 printf(" -d, --database=STRING\n");
323 printf (" %s\n", _("Database to check")); 301 printf(" %s\n", _("Database to check"));
324 printf (" %s\n", "-f, --file=STRING"); 302 printf(" %s\n", "-f, --file=STRING");
325 printf (" %s\n", _("Read from the specified client options file")); 303 printf(" %s\n", _("Read from the specified client options file"));
326 printf (" %s\n", "-g, --group=STRING"); 304 printf(" %s\n", "-g, --group=STRING");
327 printf (" %s\n", _("Use a client options group")); 305 printf(" %s\n", _("Use a client options group"));
328 printf (" -u, --username=STRING\n"); 306 printf(" -u, --username=STRING\n");
329 printf (" %s\n", _("Username to login with")); 307 printf(" %s\n", _("Username to login with"));
330 printf (" -p, --password=STRING\n"); 308 printf(" -p, --password=STRING\n");
331 printf (" %s\n", _("Password to login with")); 309 printf(" %s\n", _("Password to login with"));
332 printf (" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); 310 printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!"));
333 printf (" %s\n", _("Your clear-text password could be visible as a process table entry")); 311 printf(" %s\n", _("Your clear-text password could be visible as a process table entry"));
334
335 printf ("\n");
336 printf (" %s\n", _("A query is required. The result from the query should be numeric."));
337 printf (" %s\n", _("For extra security, create a user with minimal access."));
338
339 printf ("\n");
340 printf ("%s\n", _("Notes:"));
341 printf (" %s\n", _("You must specify -p with an empty string to force an empty password,"));
342 printf (" %s\n", _("overriding any my.cnf settings."));
343
344 printf (UT_SUPPORT);
345}
346 312
313 printf("\n");
314 printf(" %s\n", _("A query is required. The result from the query should be numeric."));
315 printf(" %s\n", _("For extra security, create a user with minimal access."));
316
317 printf("\n");
318 printf("%s\n", _("Notes:"));
319 printf(" %s\n", _("You must specify -p with an empty string to force an empty password,"));
320 printf(" %s\n", _("overriding any my.cnf settings."));
321
322 printf(UT_SUPPORT);
323}
347 324
348void 325void print_usage(void) {
349print_usage (void) 326 printf("%s\n", _("Usage:"));
350{ 327 printf(" %s -q SQL_query [-w warn] [-c crit] [-H host] [-P port] [-s socket]\n", progname);
351 printf ("%s\n", _("Usage:")); 328 printf(" [-d database] [-u user] [-p password] [-f optfile] [-g group]\n");
352 printf (" %s -q SQL_query [-w warn] [-c crit] [-H host] [-P port] [-s socket]\n",progname);
353 printf (" [-d database] [-u user] [-p password] [-f optfile] [-g group]\n");
354} 329}
diff --git a/plugins/check_mysql_query.d/config.h b/plugins/check_mysql_query.d/config.h
new file mode 100644
index 00000000..be019160
--- /dev/null
+++ b/plugins/check_mysql_query.d/config.h
@@ -0,0 +1,36 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <mysql.h>
6
7typedef struct {
8 char *db_host;
9 char *db_socket;
10 char *db;
11 char *db_user;
12 char *db_pass;
13 char *opt_file;
14 char *opt_group;
15 unsigned int db_port;
16
17 char *sql_query;
18 thresholds *my_thresholds;
19} check_mysql_query_config;
20
21check_mysql_query_config check_mysql_query_config_init() {
22 check_mysql_query_config tmp = {
23 .db_host = NULL,
24 .db_socket = NULL,
25 .db = NULL,
26 .db_user = NULL,
27 .db_pass = NULL,
28 .opt_file = NULL,
29 .opt_group = NULL,
30 .db_port = MYSQL_PORT,
31
32 .sql_query = NULL,
33 .my_thresholds = NULL,
34 };
35 return tmp;
36}
diff --git a/plugins/check_nagios.c b/plugins/check_nagios.c
index 40d68f03..a46dc1ed 100644
--- a/plugins/check_nagios.c
+++ b/plugins/check_nagios.c
@@ -1,325 +1,317 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_nagios plugin 3 * Monitoring check_nagios plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_nagios plugin 10 * This file contains the check_nagios plugin
11* 11 *
12* This plugin checks the status of the Nagios process on the local machine. 12 * This plugin checks the status of the Nagios process on the local machine.
13* The plugin will check to make sure the Nagios status log is no older than 13 * The plugin will check to make sure the Nagios status log is no older than
14* the number of minutes specified by the expires option. 14 * the number of minutes specified by the expires option.
15* It also checks the process table for a process matching the command 15 * It also checks the process table for a process matching the command
16* argument. 16 * argument.
17* 17 *
18* 18 *
19* This program is free software: you can redistribute it and/or modify 19 * This program is free software: you can redistribute it and/or modify
20* it under the terms of the GNU General Public License as published by 20 * it under the terms of the GNU General Public License as published by
21* the Free Software Foundation, either version 3 of the License, or 21 * the Free Software Foundation, either version 3 of the License, or
22* (at your option) any later version. 22 * (at your option) any later version.
23* 23 *
24* This program is distributed in the hope that it will be useful, 24 * This program is distributed in the hope that it will be useful,
25* but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27* GNU General Public License for more details. 27 * GNU General Public License for more details.
28* 28 *
29* You should have received a copy of the GNU General Public License 29 * You should have received a copy of the GNU General Public License
30* along with this program. If not, see <http://www.gnu.org/licenses/>. 30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31* 31 *
32* 32 *
33*****************************************************************************/ 33 *****************************************************************************/
34 34
35const char *progname = "check_nagios"; 35const char *progname = "check_nagios";
36const char *copyright = "1999-2007"; 36const char *copyright = "1999-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
39#include "common.h" 39#include "common.h"
40#include "runcmd.h" 40#include "runcmd.h"
41#include "utils.h" 41#include "utils.h"
42#include "states.h"
43#include "check_nagios.d/config.h"
42 44
43int process_arguments (int, char **); 45typedef struct {
44void print_help (void); 46 int errorcode;
45void print_usage (void); 47 check_nagios_config config;
48} check_nagios_config_wrapper;
49static check_nagios_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static void print_help(void);
51void print_usage(void);
46 52
47char *status_log = NULL; 53static int verbose = 0;
48char *process_string = NULL;
49int expire_minutes = 0;
50 54
51int verbose = 0; 55int main(int argc, char **argv) {
52 56 setlocale(LC_ALL, "");
53int 57 bindtextdomain(PACKAGE, LOCALEDIR);
54main (int argc, char **argv) 58 textdomain(PACKAGE);
55{
56 int result = STATE_UNKNOWN;
57 char input_buffer[MAX_INPUT_BUFFER];
58 unsigned long latest_entry_time = 0L;
59 unsigned long temp_entry_time = 0L;
60 int proc_entries = 0;
61 time_t current_time;
62 char *temp_ptr;
63 FILE *fp;
64 int procuid = 0;
65 int procpid = 0;
66 int procppid = 0;
67 int procvsz = 0;
68 int procrss = 0;
69 float procpcpu = 0;
70 char procstat[8];
71#ifdef PS_USES_PROCETIME
72 char procetime[MAX_INPUT_BUFFER];
73#endif /* PS_USES_PROCETIME */
74 char procprog[MAX_INPUT_BUFFER];
75 char *procargs;
76 int pos, cols;
77 int expected_cols = PS_COLS - 1;
78 const char *zombie = "Z";
79 char *temp_string;
80 output chld_out, chld_err;
81 size_t i;
82
83 setlocale (LC_ALL, "");
84 bindtextdomain (PACKAGE, LOCALEDIR);
85 textdomain (PACKAGE);
86 59
87 /* Parse extra opts if any */ 60 /* Parse extra opts if any */
88 argv=np_extra_opts (&argc, argv, progname); 61 argv = np_extra_opts(&argc, argv, progname);
62
63 check_nagios_config_wrapper tmp_config = process_arguments(argc, argv);
89 64
90 if (process_arguments (argc, argv) == ERROR) 65 if (tmp_config.errorcode == ERROR) {
91 usage_va(_("Could not parse arguments")); 66 usage_va(_("Could not parse arguments"));
67 }
68
69 const check_nagios_config config = tmp_config.config;
92 70
93 /* Set signal handling and alarm timeout */ 71 /* Set signal handling and alarm timeout */
94 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 72 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
95 usage_va(_("Cannot catch SIGALRM")); 73 usage_va(_("Cannot catch SIGALRM"));
96 } 74 }
97 75
98 /* handle timeouts gracefully... */ 76 /* handle timeouts gracefully... */
99 alarm (timeout_interval); 77 alarm(timeout_interval);
100 78
101 /* open the status log */ 79 /* open the status log */
102 fp = fopen (status_log, "r"); 80 FILE *log_file = fopen(config.status_log, "r");
103 if (fp == NULL) { 81 if (log_file == NULL) {
104 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!")); 82 die(STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot open status log for reading!"));
105 } 83 }
106 84
85 unsigned long latest_entry_time = 0L;
86 unsigned long temp_entry_time = 0L;
87 char input_buffer[MAX_INPUT_BUFFER];
88 char *temp_ptr;
107 /* get the date/time of the last item updated in the log */ 89 /* get the date/time of the last item updated in the log */
108 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) { 90 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, log_file)) {
109 if ((temp_ptr = strstr (input_buffer, "created=")) != NULL) { 91 if ((temp_ptr = strstr(input_buffer, "created=")) != NULL) {
110 temp_entry_time = strtoul (temp_ptr + 8, NULL, 10); 92 temp_entry_time = strtoul(temp_ptr + 8, NULL, 10);
111 latest_entry_time = temp_entry_time; 93 latest_entry_time = temp_entry_time;
112 break; 94 break;
113 } else if ((temp_ptr = strtok (input_buffer, "]")) != NULL) { 95 }
114 temp_entry_time = strtoul (temp_ptr + 1, NULL, 10); 96 if ((temp_ptr = strtok(input_buffer, "]")) != NULL) {
115 if (temp_entry_time > latest_entry_time) 97 temp_entry_time = strtoul(temp_ptr + 1, NULL, 10);
98 if (temp_entry_time > latest_entry_time) {
116 latest_entry_time = temp_entry_time; 99 latest_entry_time = temp_entry_time;
100 }
117 } 101 }
118 } 102 }
119 fclose (fp); 103 fclose(log_file);
120 104
121 if (verbose >= 2) 105 if (verbose >= 2) {
122 printf("command: %s\n", PS_COMMAND); 106 printf("command: %s\n", PS_COMMAND);
107 }
123 108
124 /* run the command to check for the Nagios process.. */ 109 /* run the command to check for the Nagios process.. */
125 if((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0) 110 mp_state_enum result = STATE_UNKNOWN;
111 output chld_out;
112 output chld_err;
113 if ((result = np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0)) != 0) {
126 result = STATE_WARNING; 114 result = STATE_WARNING;
115 }
127 116
117 int procuid = 0;
118 int procpid = 0;
119 int procppid = 0;
120 int procvsz = 0;
121 int procrss = 0;
122 int proc_entries = 0;
123 float procpcpu = 0;
124 char procstat[8];
125 char procprog[MAX_INPUT_BUFFER];
126 char *procargs;
127#ifdef PS_USES_PROCETIME
128 char procetime[MAX_INPUT_BUFFER];
129#endif /* PS_USES_PROCETIME */
130 int pos;
131 int expected_cols = PS_COLS - 1;
132 const char *zombie = "Z";
128 /* count the number of matching Nagios processes... */ 133 /* count the number of matching Nagios processes... */
129 for(i = 0; i < chld_out.lines; i++) { 134 for (size_t i = 0; i < chld_out.lines; i++) {
130 cols = sscanf (chld_out.line[i], PS_FORMAT, PS_VARLIST); 135 int cols = sscanf(chld_out.line[i], PS_FORMAT, PS_VARLIST);
131 /* Zombie processes do not give a procprog command */ 136 /* Zombie processes do not give a procprog command */
132 if ( cols == (expected_cols - 1) && strstr(procstat, zombie) ) { 137 if (cols == (expected_cols - 1) && strstr(procstat, zombie)) {
133 cols = expected_cols; 138 cols = expected_cols;
134 /* Set some value for procargs for the strip command further below 139 /* Set some value for procargs for the strip command further below
135 * Seen to be a problem on some Solaris 7 and 8 systems */ 140 * Seen to be a problem on some Solaris 7 and 8 systems */
136 chld_out.line[i][pos] = '\n'; 141 chld_out.line[i][pos] = '\n';
137 chld_out.line[i][pos+1] = 0x0; 142 chld_out.line[i][pos + 1] = 0x0;
138 } 143 }
139 if ( cols >= expected_cols ) { 144 if (cols >= expected_cols) {
140 xasprintf (&procargs, "%s", chld_out.line[i] + pos); 145 xasprintf(&procargs, "%s", chld_out.line[i] + pos);
141 strip (procargs); 146 strip(procargs);
142 147
143 /* Some ps return full pathname for command. This removes path */ 148 /* Some ps return full pathname for command. This removes path */
144 temp_string = strtok ((char *)procprog, "/"); 149 char *temp_string = strtok((char *)procprog, "/");
145 while (temp_string) { 150 while (temp_string) {
146 strcpy(procprog, temp_string); 151 strcpy(procprog, temp_string);
147 temp_string = strtok (NULL, "/"); 152 temp_string = strtok(NULL, "/");
148 } 153 }
149 154
150 /* May get empty procargs */ 155 /* May get empty procargs */
151 if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs,"")) { 156 if (!strstr(procargs, argv[0]) && strstr(procargs, config.process_string) && strcmp(procargs, "")) {
152 proc_entries++; 157 proc_entries++;
153 if (verbose >= 2) { 158 if (verbose >= 2) {
154 printf (_("Found process: %s %s\n"), procprog, procargs); 159 printf(_("Found process: %s %s\n"), procprog, procargs);
155 } 160 }
156 } 161 }
157 } 162 }
158 } 163 }
159 164
160 /* If we get anything on stderr, at least set warning */ 165 /* If we get anything on stderr, at least set warning */
161 if(chld_err.buflen) 166 if (chld_err.buflen) {
162 result = max_state (result, STATE_WARNING); 167 result = max_state(result, STATE_WARNING);
168 }
163 169
164 /* reset the alarm handler */ 170 /* reset the alarm handler */
165 alarm (0); 171 alarm(0);
166 172
167 if (proc_entries == 0) { 173 if (proc_entries == 0) {
168 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Could not locate a running Nagios process!")); 174 die(STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Could not locate a running Nagios process!"));
169 } 175 }
170 176
171 if (latest_entry_time == 0L) { 177 if (latest_entry_time == 0L) {
172 die (STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time")); 178 die(STATE_CRITICAL, "NAGIOS %s: %s\n", _("CRITICAL"), _("Cannot parse Nagios log file for valid time"));
173 } 179 }
174 180
175 time (&current_time); 181 time_t current_time;
176 if ((int)(current_time - latest_entry_time) > (expire_minutes * 60)) { 182 time(&current_time);
183 if ((int)(current_time - latest_entry_time) > (config.expire_minutes * 60)) {
177 result = STATE_WARNING; 184 result = STATE_WARNING;
178 } else { 185 } else {
179 result = STATE_OK; 186 result = STATE_OK;
180 } 187 }
181 188
182 printf ("NAGIOS %s: ", (result == STATE_OK) ? _("OK") : _("WARNING")); 189 printf("NAGIOS %s: ", (result == STATE_OK) ? _("OK") : _("WARNING"));
183 printf (ngettext ("%d process", "%d processes", proc_entries), proc_entries); 190 printf(ngettext("%d process", "%d processes", proc_entries), proc_entries);
184 printf (", "); 191 printf(", ");
185 printf ( 192 printf(ngettext("status log updated %d second ago", "status log updated %d seconds ago", (int)(current_time - latest_entry_time)),
186 ngettext ("status log updated %d second ago", 193 (int)(current_time - latest_entry_time));
187 "status log updated %d seconds ago", 194 printf("\n");
188 (int) (current_time - latest_entry_time) ),
189 (int) (current_time - latest_entry_time) );
190 printf ("\n");
191 195
192 return result; 196 exit(result);
193} 197}
194 198
195
196
197/* process command-line arguments */ 199/* process command-line arguments */
198int 200check_nagios_config_wrapper process_arguments(int argc, char **argv) {
199process_arguments (int argc, char **argv) 201 static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'},
200{ 202 {"command", required_argument, 0, 'C'}, {"timeout", optional_argument, 0, 't'},
201 int c; 203 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'},
202 204 {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0}};
203 int option = 0; 205
204 static struct option longopts[] = { 206 check_nagios_config_wrapper result = {
205 {"filename", required_argument, 0, 'F'}, 207 .errorcode = OK,
206 {"expires", required_argument, 0, 'e'}, 208 .config = check_nagios_config_init(),
207 {"command", required_argument, 0, 'C'},
208 {"timeout", optional_argument, 0, 't'},
209 {"version", no_argument, 0, 'V'},
210 {"help", no_argument, 0, 'h'},
211 {"verbose", no_argument, 0, 'v'},
212 {0, 0, 0, 0}
213 }; 209 };
210 if (argc < 2) {
211 result.errorcode = ERROR;
212 return result;
213 }
214 214
215 if (argc < 2) 215 if (!is_option(argv[1])) {
216 return ERROR; 216 result.config.status_log = argv[1];
217 217 if (is_intnonneg(argv[2])) {
218 if (!is_option (argv[1])) { 218 result.config.expire_minutes = atoi(argv[2]);
219 status_log = argv[1]; 219 } else {
220 if (is_intnonneg (argv[2])) 220 die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
221 expire_minutes = atoi (argv[2]); 221 }
222 else 222 result.config.process_string = argv[3];
223 die (STATE_UNKNOWN, 223 return result;
224 _("Expiration time must be an integer (seconds)\n"));
225 process_string = argv[3];
226 return OK;
227 } 224 }
228 225
229 while (1) { 226 int option = 0;
230 c = getopt_long (argc, argv, "+hVvF:C:e:t:", longopts, &option); 227 while (true) {
228 int option_index = getopt_long(argc, argv, "+hVvF:C:e:t:", longopts, &option);
231 229
232 if (c == -1 || c == EOF || c == 1) 230 if (option_index == -1 || option_index == EOF || option_index == 1) {
233 break; 231 break;
232 }
234 233
235 switch (c) { 234 switch (option_index) {
236 case 'h': /* help */ 235 case 'h': /* help */
237 print_help (); 236 print_help();
238 exit (STATE_UNKNOWN); 237 exit(STATE_UNKNOWN);
239 case 'V': /* version */ 238 case 'V': /* version */
240 print_revision (progname, NP_VERSION); 239 print_revision(progname, NP_VERSION);
241 exit (STATE_UNKNOWN); 240 exit(STATE_UNKNOWN);
242 case 'F': /* status log */ 241 case 'F': /* status log */
243 status_log = optarg; 242 result.config.status_log = optarg;
244 break; 243 break;
245 case 'C': /* command */ 244 case 'C': /* command */
246 process_string = optarg; 245 result.config.process_string = optarg;
247 break; 246 break;
248 case 'e': /* expiry time */ 247 case 'e': /* expiry time */
249 if (is_intnonneg (optarg)) 248 if (is_intnonneg(optarg)) {
250 expire_minutes = atoi (optarg); 249 result.config.expire_minutes = atoi(optarg);
251 else 250 } else {
252 die (STATE_UNKNOWN, 251 die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
253 _("Expiration time must be an integer (seconds)\n")); 252 }
254 break; 253 break;
255 case 't': /* timeout */ 254 case 't': /* timeout */
256 if (is_intnonneg (optarg)) 255 if (is_intnonneg(optarg)) {
257 timeout_interval = atoi (optarg); 256 timeout_interval = atoi(optarg);
258 else 257 } else {
259 die (STATE_UNKNOWN, 258 die(STATE_UNKNOWN, _("Timeout must be an integer (seconds)\n"));
260 _("Timeout must be an integer (seconds)\n")); 259 }
261 break; 260 break;
262 case 'v': 261 case 'v':
263 verbose++; 262 verbose++;
264 break; 263 break;
265 default: /* print short usage_va statement if args not parsable */ 264 default: /* print short usage_va statement if args not parsable */
266 usage5(); 265 usage5();
267 } 266 }
268 } 267 }
269 268
269 if (result.config.status_log == NULL) {
270 die(STATE_UNKNOWN, _("You must provide the status_log\n"));
271 }
270 272
271 if (status_log == NULL) 273 if (result.config.process_string == NULL) {
272 die (STATE_UNKNOWN, _("You must provide the status_log\n")); 274 die(STATE_UNKNOWN, _("You must provide a process string\n"));
273 275 }
274 if (process_string == NULL)
275 die (STATE_UNKNOWN, _("You must provide a process string\n"));
276 276
277 return OK; 277 return result;
278} 278}
279 279
280void print_help(void) {
281 print_revision(progname, NP_VERSION);
280 282
283 printf(_(COPYRIGHT), copyright, email);
281 284
282void 285 printf("%s\n", _("This plugin checks the status of the Nagios process on the local machine"));
283print_help (void) 286 printf("%s\n", _("The plugin will check to make sure the Nagios status log is no older than"));
284{ 287 printf("%s\n", _("the number of minutes specified by the expires option."));
285 print_revision (progname, NP_VERSION); 288 printf("%s\n", _("It also checks the process table for a process matching the command argument."));
286 289
287 printf (_(COPYRIGHT), copyright, email); 290 printf("\n\n");
288 291
289 printf ("%s\n", _("This plugin checks the status of the Nagios process on the local machine")); 292 print_usage();
290 printf ("%s\n", _("The plugin will check to make sure the Nagios status log is no older than"));
291 printf ("%s\n", _("the number of minutes specified by the expires option."));
292 printf ("%s\n", _("It also checks the process table for a process matching the command argument."));
293 293
294 printf ("\n\n"); 294 printf(UT_HELP_VRSN);
295 printf(UT_EXTRA_OPTS);
295 296
296 print_usage (); 297 printf(" %s\n", "-F, --filename=FILE");
298 printf(" %s\n", _("Name of the log file to check"));
299 printf(" %s\n", "-e, --expires=INTEGER");
300 printf(" %s\n", _("Minutes aging after which logfile is considered stale"));
301 printf(" %s\n", "-C, --command=STRING");
302 printf(" %s\n", _("Substring to search for in process arguments"));
303 printf(" %s\n", "-t, --timeout=INTEGER");
304 printf(" %s\n", _("Timeout for the plugin in seconds"));
305 printf(UT_VERBOSE);
297 306
298 printf (UT_HELP_VRSN); 307 printf("\n");
299 printf (UT_EXTRA_OPTS); 308 printf("%s\n", _("Examples:"));
309 printf(" %s\n", "check_nagios -t 20 -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios");
300 310
301 printf (" %s\n", "-F, --filename=FILE"); 311 printf(UT_SUPPORT);
302 printf (" %s\n", _("Name of the log file to check"));
303 printf (" %s\n", "-e, --expires=INTEGER");
304 printf (" %s\n", _("Minutes aging after which logfile is considered stale"));
305 printf (" %s\n", "-C, --command=STRING");
306 printf (" %s\n", _("Substring to search for in process arguments"));
307 printf (" %s\n", "-t, --timeout=INTEGER");
308 printf (" %s\n", _("Timeout for the plugin in seconds"));
309 printf (UT_VERBOSE);
310
311 printf ("\n");
312 printf ("%s\n", _("Examples:"));
313 printf (" %s\n", "check_nagios -t 20 -e 5 -F /usr/local/nagios/var/status.log -C /usr/local/nagios/bin/nagios");
314
315 printf (UT_SUPPORT);
316} 312}
317 313
318 314void print_usage(void) {
319 315 printf("%s\n", _("Usage:"));
320void 316 printf("%s -F <status log file> -t <timeout_seconds> -e <expire_minutes> -C <process_string>\n", progname);
321print_usage (void)
322{
323 printf ("%s\n", _("Usage:"));
324 printf ("%s -F <status log file> -t <timeout_seconds> -e <expire_minutes> -C <process_string>\n", progname);
325} 317}
diff --git a/plugins/check_nagios.d/config.h b/plugins/check_nagios.d/config.h
new file mode 100644
index 00000000..efe139f9
--- /dev/null
+++ b/plugins/check_nagios.d/config.h
@@ -0,0 +1,19 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6typedef struct {
7 char *status_log;
8 char *process_string;
9 int expire_minutes;
10} check_nagios_config;
11
12check_nagios_config check_nagios_config_init() {
13 check_nagios_config tmp = {
14 .status_log = NULL,
15 .process_string = NULL,
16 .expire_minutes = 0,
17 };
18 return tmp;
19}
diff --git a/plugins/check_nt.c b/plugins/check_nt.c
index 19c050de..7dd23e5c 100644
--- a/plugins/check_nt.c
+++ b/plugins/check_nt.c
@@ -1,336 +1,291 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_nt plugin 3 * Monitoring check_nt plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2002 Yves Rubin (rubiyz@yahoo.com) 6 * Copyright (c) 2000-2002 Yves Rubin (rubiyz@yahoo.com)
7* Copyright (c) 2003-2007 Monitoring Plugins Development Team 7 * Copyright (c) 2003-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_nt plugin 11 * This file contains the check_nt plugin
12* 12 *
13* This plugin collects data from the NSClient service running on a 13 * This plugin collects data from the NSClient service running on a
14* Windows NT/2000/XP/2003 server. 14 * Windows NT/2000/XP/2003 server.
15* This plugin requires NSClient software to run on NT 15 * This plugin requires NSClient software to run on NT
16* (http://nsclient.ready2run.nl/) 16 * (https://nsclient.org/)
17* 17 *
18* 18 *
19* This program is free software: you can redistribute it and/or modify 19 * This program is free software: you can redistribute it and/or modify
20* it under the terms of the GNU General Public License as published by 20 * it under the terms of the GNU General Public License as published by
21* the Free Software Foundation, either version 3 of the License, or 21 * the Free Software Foundation, either version 3 of the License, or
22* (at your option) any later version. 22 * (at your option) any later version.
23* 23 *
24* This program is distributed in the hope that it will be useful, 24 * This program is distributed in the hope that it will be useful,
25* but WITHOUT ANY WARRANTY; without even the implied warranty of 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27* GNU General Public License for more details. 27 * GNU General Public License for more details.
28* 28 *
29* You should have received a copy of the GNU General Public License 29 * You should have received a copy of the GNU General Public License
30* along with this program. If not, see <http://www.gnu.org/licenses/>. 30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31* 31 *
32* 32 *
33*****************************************************************************/ 33 *****************************************************************************/
34 34
35const char *progname = "check_nt"; 35const char *progname = "check_nt";
36const char *copyright = "2000-2007"; 36const char *copyright = "2000-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
39#include "common.h" 39#include "common.h"
40#include "netutils.h" 40#include "netutils.h"
41#include "utils.h" 41#include "utils.h"
42 42#include "check_nt.d/config.h"
43enum checkvars {
44 CHECK_NONE,
45 CHECK_CLIENTVERSION,
46 CHECK_CPULOAD,
47 CHECK_UPTIME,
48 CHECK_USEDDISKSPACE,
49 CHECK_SERVICESTATE,
50 CHECK_PROCSTATE,
51 CHECK_MEMUSE,
52 CHECK_COUNTER,
53 CHECK_FILEAGE,
54 CHECK_INSTANCES
55};
56 43
57enum { 44enum {
58 MAX_VALUE_LIST = 30, 45 MAX_VALUE_LIST = 30,
59 PORT = 1248
60}; 46};
61 47
62char *server_address=NULL; 48static char recv_buffer[MAX_INPUT_BUFFER];
63char *volume_name=NULL;
64int server_port=PORT;
65char *value_list=NULL;
66char *req_password=NULL;
67unsigned long lvalue_list[MAX_VALUE_LIST];
68unsigned long warning_value=0L;
69unsigned long critical_value=0L;
70bool check_warning_value=false;
71bool check_critical_value=false;
72enum checkvars vars_to_check = CHECK_NONE;
73bool show_all = false;
74
75char recv_buffer[MAX_INPUT_BUFFER];
76
77void fetch_data (const char* address, int port, const char* sendb);
78int process_arguments(int, char **);
79void preparelist(char *string);
80bool strtoularray(unsigned long *array, char *string, const char *delim);
81void print_help(void);
82void print_usage(void);
83 49
84int main(int argc, char **argv){ 50static void fetch_data(const char *address, int port, const char *sendb);
85 51
86/* should be int result = STATE_UNKNOWN; */ 52typedef struct {
53 int errorcode;
54 check_nt_config config;
55} check_nt_config_wrapper;
56static check_nt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
87 57
88 int return_code = STATE_UNKNOWN; 58static void preparelist(char *string);
89 char *send_buffer=NULL; 59static bool strtoularray(unsigned long *array, char *string, const char *delim);
90 char *output_message=NULL; 60static void print_help(void);
91 char *perfdata=NULL; 61void print_usage(void);
92 char *temp_string=NULL; 62
93 char *temp_string_perf=NULL; 63int main(int argc, char **argv) {
94 char *description=NULL,*counter_unit = NULL; 64 setlocale(LC_ALL, "");
95 char *minval = NULL, *maxval = NULL, *errcvt = NULL; 65 bindtextdomain(PACKAGE, LOCALEDIR);
96 char *fds=NULL, *tds=NULL; 66 textdomain(PACKAGE);
97 char *numstr;
98
99 double total_disk_space=0;
100 double free_disk_space=0;
101 double percent_used_space=0;
102 double warning_used_space=0;
103 double critical_used_space=0;
104 double mem_commitLimit=0;
105 double mem_commitByte=0;
106 double fminval = 0, fmaxval = 0;
107 unsigned long utilization;
108 unsigned long uptime;
109 unsigned long age_in_minutes;
110 double counter_value = 0.0;
111 int offset=0;
112 int updays=0;
113 int uphours=0;
114 int upminutes=0;
115
116 bool isPercent = false;
117 bool allRight = false;
118
119 setlocale (LC_ALL, "");
120 bindtextdomain (PACKAGE, LOCALEDIR);
121 textdomain (PACKAGE);
122 67
123 /* Parse extra opts if any */ 68 /* Parse extra opts if any */
124 argv=np_extra_opts (&argc, argv, progname); 69 argv = np_extra_opts(&argc, argv, progname);
70
71 check_nt_config_wrapper tmp_config = process_arguments(argc, argv);
72 if (tmp_config.errorcode == ERROR) {
73 usage4(_("Could not parse arguments"));
74 }
125 75
126 if(process_arguments(argc,argv) == ERROR) 76 const check_nt_config config = tmp_config.config;
127 usage4 (_("Could not parse arguments"));
128 77
129 /* initialize alarm signal handling */ 78 /* initialize alarm signal handling */
130 signal(SIGALRM,socket_timeout_alarm_handler); 79 signal(SIGALRM, socket_timeout_alarm_handler);
131 80
132 /* set socket timeout */ 81 /* set socket timeout */
133 alarm(socket_timeout); 82 alarm(socket_timeout);
134 83
135 switch (vars_to_check) { 84 int return_code = STATE_UNKNOWN;
136 85 char *send_buffer = NULL;
86 char *output_message = NULL;
87 char *perfdata = NULL;
88 char *temp_string = NULL;
89 char *temp_string_perf = NULL;
90 char *description = NULL;
91 char *counter_unit = NULL;
92 char *errcvt = NULL;
93 unsigned long lvalue_list[MAX_VALUE_LIST];
94 switch (config.vars_to_check) {
137 case CHECK_CLIENTVERSION: 95 case CHECK_CLIENTVERSION:
138 96 xasprintf(&send_buffer, "%s&1", config.req_password);
139 xasprintf(&send_buffer, "%s&1", req_password); 97 fetch_data(config.server_address, config.server_port, send_buffer);
140 fetch_data (server_address, server_port, send_buffer); 98 if (config.value_list != NULL && strcmp(recv_buffer, config.value_list) != 0) {
141 if (value_list != NULL && strcmp(recv_buffer, value_list) != 0) { 99 xasprintf(&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, config.value_list);
142 xasprintf (&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, value_list);
143 return_code = STATE_WARNING; 100 return_code = STATE_WARNING;
144 } else { 101 } else {
145 xasprintf (&output_message, "%s", recv_buffer); 102 xasprintf(&output_message, "%s", recv_buffer);
146 return_code = STATE_OK; 103 return_code = STATE_OK;
147 } 104 }
148 break; 105 break;
149
150 case CHECK_CPULOAD: 106 case CHECK_CPULOAD:
151 107 if (config.value_list == NULL) {
152 if (value_list==NULL) 108 output_message = strdup(_("missing -l parameters"));
153 output_message = strdup (_("missing -l parameters")); 109 } else if (!strtoularray(lvalue_list, config.value_list, ",")) {
154 else if (! strtoularray(lvalue_list,value_list,",")) 110 output_message = strdup(_("wrong -l parameter."));
155 output_message = strdup (_("wrong -l parameter.")); 111 } else {
156 else {
157 /* -l parameters is present with only integers */ 112 /* -l parameters is present with only integers */
158 return_code=STATE_OK; 113 return_code = STATE_OK;
159 temp_string = strdup (_("CPU Load")); 114 temp_string = strdup(_("CPU Load"));
160 temp_string_perf = strdup (" "); 115 temp_string_perf = strdup(" ");
161 116
162 /* loop until one of the parameters is wrong or not present */ 117 /* loop until one of the parameters is wrong or not present */
163 while (lvalue_list[0+offset]> (unsigned long)0 && 118 int offset = 0;
164 lvalue_list[0+offset]<=(unsigned long)17280 && 119 while (lvalue_list[0 + offset] > (unsigned long)0 && lvalue_list[0 + offset] <= (unsigned long)17280 &&
165 lvalue_list[1+offset]> (unsigned long)0 && 120 lvalue_list[1 + offset] > (unsigned long)0 && lvalue_list[1 + offset] <= (unsigned long)100 &&
166 lvalue_list[1+offset]<=(unsigned long)100 && 121 lvalue_list[2 + offset] > (unsigned long)0 && lvalue_list[2 + offset] <= (unsigned long)100) {
167 lvalue_list[2+offset]> (unsigned long)0 &&
168 lvalue_list[2+offset]<=(unsigned long)100) {
169 122
170 /* Send request and retrieve data */ 123 /* Send request and retrieve data */
171 xasprintf(&send_buffer,"%s&2&%lu",req_password,lvalue_list[0+offset]); 124 xasprintf(&send_buffer, "%s&2&%lu", config.req_password, lvalue_list[0 + offset]);
172 fetch_data (server_address, server_port, send_buffer); 125 fetch_data(config.server_address, config.server_port, send_buffer);
173 126
174 utilization=strtoul(recv_buffer,NULL,10); 127 unsigned long utilization = strtoul(recv_buffer, NULL, 10);
175 128
176 /* Check if any of the request is in a warning or critical state */ 129 /* Check if any of the request is in a warning or critical state */
177 if(utilization >= lvalue_list[2+offset]) 130 if (utilization >= lvalue_list[2 + offset]) {
178 return_code=STATE_CRITICAL; 131 return_code = STATE_CRITICAL;
179 else if(utilization >= lvalue_list[1+offset] && return_code<STATE_WARNING) 132 } else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) {
180 return_code=STATE_WARNING; 133 return_code = STATE_WARNING;
181 134 }
182 xasprintf(&output_message,_(" %lu%% (%lu min average)"), utilization, lvalue_list[0+offset]); 135
183 xasprintf(&temp_string,"%s%s",temp_string,output_message); 136 xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization, lvalue_list[0 + offset]);
184 xasprintf(&perfdata,_(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"), lvalue_list[0+offset], utilization, 137 xasprintf(&temp_string, "%s%s", temp_string, output_message);
185 lvalue_list[1+offset], lvalue_list[2+offset]); 138 xasprintf(&perfdata, _(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"), lvalue_list[0 + offset], utilization,
186 xasprintf(&temp_string_perf,"%s%s",temp_string_perf,perfdata); 139 lvalue_list[1 + offset], lvalue_list[2 + offset]);
187 offset+=3; /* move across the array */ 140 xasprintf(&temp_string_perf, "%s%s", temp_string_perf, perfdata);
141 offset += 3; /* move across the array */
188 } 142 }
189 143
190 if (strlen(temp_string)>10) { /* we had at least one loop */ 144 if (strlen(temp_string) > 10) { /* we had at least one loop */
191 output_message = strdup (temp_string); 145 output_message = strdup(temp_string);
192 perfdata = temp_string_perf; 146 perfdata = temp_string_perf;
193 } else 147 } else {
194 output_message = strdup (_("not enough values for -l parameters")); 148 output_message = strdup(_("not enough values for -l parameters"));
149 }
195 } 150 }
196 break; 151 break;
197 152 case CHECK_UPTIME: {
198 case CHECK_UPTIME: 153 char *tmp_value_list = config.value_list;
199 154 if (config.value_list == NULL) {
200 if (value_list == NULL) { 155 tmp_value_list = "minutes";
201 value_list = "minutes";
202 } 156 }
203 if (strncmp(value_list, "seconds", strlen("seconds") + 1 ) && 157 if (strncmp(tmp_value_list, "seconds", strlen("seconds") + 1) && strncmp(tmp_value_list, "minutes", strlen("minutes") + 1) &&
204 strncmp(value_list, "minutes", strlen("minutes") + 1) && 158 strncmp(config.value_list, "hours", strlen("hours") + 1) && strncmp(tmp_value_list, "days", strlen("days") + 1)) {
205 strncmp(value_list, "hours", strlen("hours") + 1) &&
206 strncmp(value_list, "days", strlen("days") + 1)) {
207 159
208 output_message = strdup (_("wrong -l argument")); 160 output_message = strdup(_("wrong -l argument"));
209 } else { 161 } else {
210 xasprintf(&send_buffer, "%s&3", req_password); 162 xasprintf(&send_buffer, "%s&3", config.req_password);
211 fetch_data (server_address, server_port, send_buffer); 163 fetch_data(config.server_address, config.server_port, send_buffer);
212 uptime=strtoul(recv_buffer,NULL,10); 164 unsigned long uptime = strtoul(recv_buffer, NULL, 10);
213 updays = uptime / 86400; 165 int updays = uptime / 86400;
214 uphours = (uptime % 86400) / 3600; 166 int uphours = (uptime % 86400) / 3600;
215 upminutes = ((uptime % 86400) % 3600) / 60; 167 int upminutes = ((uptime % 86400) % 3600) / 60;
216 168
217 if (!strncmp(value_list, "minutes", strlen("minutes"))) 169 if (!strncmp(tmp_value_list, "minutes", strlen("minutes"))) {
218 uptime = uptime / 60; 170 uptime = uptime / 60;
219 else if (!strncmp(value_list, "hours", strlen("hours"))) 171 } else if (!strncmp(tmp_value_list, "hours", strlen("hours"))) {
220 uptime = uptime / 3600; 172 uptime = uptime / 3600;
221 else if (!strncmp(value_list, "days", strlen("days"))) 173 } else if (!strncmp(tmp_value_list, "days", strlen("days"))) {
222 uptime = uptime / 86400; 174 uptime = uptime / 86400;
175 }
223 /* else uptime in seconds, nothing to do */ 176 /* else uptime in seconds, nothing to do */
224 177
225 xasprintf(&output_message,_("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"),updays, uphours, upminutes, uptime); 178 xasprintf(&output_message, _("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays, uphours, upminutes,
179 uptime);
226 180
227 if (check_critical_value && uptime <= critical_value) 181 if (config.check_critical_value && uptime <= config.critical_value) {
228 return_code=STATE_CRITICAL; 182 return_code = STATE_CRITICAL;
229 else if (check_warning_value && uptime <= warning_value) 183 } else if (config.check_warning_value && uptime <= config.warning_value) {
230 return_code=STATE_WARNING; 184 return_code = STATE_WARNING;
231 else 185 } else {
232 return_code=STATE_OK; 186 return_code = STATE_OK;
187 }
233 } 188 }
234 break; 189 } break;
235
236 case CHECK_USEDDISKSPACE: 190 case CHECK_USEDDISKSPACE:
191 if (config.value_list == NULL) {
192 output_message = strdup(_("missing -l parameters"));
193 } else if (strlen(config.value_list) != 1) {
194 output_message = strdup(_("wrong -l argument"));
195 } else {
196 xasprintf(&send_buffer, "%s&4&%s", config.req_password, config.value_list);
197 fetch_data(config.server_address, config.server_port, send_buffer);
198 char *fds = strtok(recv_buffer, "&");
199 char *tds = strtok(NULL, "&");
200 double total_disk_space = 0;
201 double free_disk_space = 0;
202 if (fds != NULL) {
203 free_disk_space = atof(fds);
204 }
205 if (tds != NULL) {
206 total_disk_space = atof(tds);
207 }
237 208
238 if (value_list==NULL) 209 if (total_disk_space > 0 && free_disk_space >= 0) {
239 output_message = strdup (_("missing -l parameters")); 210 double percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100;
240 else if (strlen(value_list)!=1) 211 double warning_used_space = ((float)config.warning_value / 100) * total_disk_space;
241 output_message = strdup (_("wrong -l argument")); 212 double critical_used_space = ((float)config.critical_value / 100) * total_disk_space;
242 else { 213
243 xasprintf(&send_buffer,"%s&4&%s", req_password, value_list); 214 xasprintf(&temp_string, _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), config.value_list,
244 fetch_data (server_address, server_port, send_buffer); 215 total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, percent_used_space,
245 fds=strtok(recv_buffer,"&"); 216 free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100);
246 tds=strtok(NULL,"&"); 217 xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), config.value_list,
247 if(fds!=NULL) 218 (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824,
248 free_disk_space=atof(fds); 219 critical_used_space / 1073741824, total_disk_space / 1073741824);
249 if(tds!=NULL) 220
250 total_disk_space=atof(tds); 221 if (config.check_critical_value && percent_used_space >= config.critical_value) {
251 222 return_code = STATE_CRITICAL;
252 if (total_disk_space>0 && free_disk_space>=0) { 223 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
253 percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100; 224 return_code = STATE_WARNING;
254 warning_used_space = ((float)warning_value / 100) * total_disk_space; 225 } else {
255 critical_used_space = ((float)critical_value / 100) * total_disk_space; 226 return_code = STATE_OK;
256 227 }
257 xasprintf(&temp_string,_("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), 228
258 value_list, total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, 229 output_message = strdup(temp_string);
259 percent_used_space, free_disk_space / 1073741824, (free_disk_space / total_disk_space)*100);
260 xasprintf(&temp_string_perf,_("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), value_list,
261 (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824,
262 critical_used_space / 1073741824, total_disk_space / 1073741824);
263
264 if(check_critical_value && percent_used_space >= critical_value)
265 return_code=STATE_CRITICAL;
266 else if (check_warning_value && percent_used_space >= warning_value)
267 return_code=STATE_WARNING;
268 else
269 return_code=STATE_OK;
270
271 output_message = strdup (temp_string);
272 perfdata = temp_string_perf; 230 perfdata = temp_string_perf;
273 } else { 231 } else {
274 output_message = strdup (_("Free disk space : Invalid drive")); 232 output_message = strdup(_("Free disk space : Invalid drive"));
275 return_code=STATE_UNKNOWN; 233 return_code = STATE_UNKNOWN;
276 } 234 }
277 } 235 }
278 break; 236 break;
279
280 case CHECK_SERVICESTATE: 237 case CHECK_SERVICESTATE:
281 case CHECK_PROCSTATE: 238 case CHECK_PROCSTATE:
282 239 if (config.value_list == NULL) {
283 if (value_list==NULL) 240 output_message = strdup(_("No service/process specified"));
284 output_message = strdup (_("No service/process specified")); 241 } else {
285 else { 242 preparelist(config.value_list); /* replace , between services with & to send the request */
286 preparelist(value_list); /* replace , between services with & to send the request */ 243 xasprintf(&send_buffer, "%s&%u&%s&%s", config.req_password, (config.vars_to_check == CHECK_SERVICESTATE) ? 5 : 6,
287 xasprintf(&send_buffer,"%s&%u&%s&%s", req_password,(vars_to_check==CHECK_SERVICESTATE)?5:6, 244 (config.show_all) ? "ShowAll" : "ShowFail", config.value_list);
288 (show_all) ? "ShowAll" : "ShowFail",value_list); 245 fetch_data(config.server_address, config.server_port, send_buffer);
289 fetch_data (server_address, server_port, send_buffer); 246 char *numstr = strtok(recv_buffer, "&");
290 numstr = strtok(recv_buffer,"&"); 247 if (numstr == NULL) {
291 if (numstr == NULL)
292 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 248 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
293 return_code=atoi(numstr); 249 }
294 temp_string=strtok(NULL,"&"); 250 return_code = atoi(numstr);
295 output_message = strdup (temp_string); 251 temp_string = strtok(NULL, "&");
252 output_message = strdup(temp_string);
296 } 253 }
297 break; 254 break;
298
299 case CHECK_MEMUSE: 255 case CHECK_MEMUSE:
300 256 xasprintf(&send_buffer, "%s&7", config.req_password);
301 xasprintf(&send_buffer,"%s&7", req_password); 257 fetch_data(config.server_address, config.server_port, send_buffer);
302 fetch_data (server_address, server_port, send_buffer); 258 char *numstr = strtok(recv_buffer, "&");
303 numstr = strtok(recv_buffer,"&"); 259 if (numstr == NULL) {
304 if (numstr == NULL)
305 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 260 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
306 mem_commitLimit=atof(numstr); 261 }
307 numstr = strtok(NULL,"&"); 262 double mem_commitLimit = atof(numstr);
308 if (numstr == NULL) 263 numstr = strtok(NULL, "&");
264 if (numstr == NULL) {
309 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 265 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
310 mem_commitByte=atof(numstr); 266 }
311 percent_used_space = (mem_commitByte / mem_commitLimit) * 100; 267 double mem_commitByte = atof(numstr);
312 warning_used_space = ((float)warning_value / 100) * mem_commitLimit; 268 double percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
313 critical_used_space = ((float)critical_value / 100) * mem_commitLimit; 269 double warning_used_space = ((float)config.warning_value / 100) * mem_commitLimit;
270 double critical_used_space = ((float)config.critical_value / 100) * mem_commitLimit;
314 271
315 /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here, 272 /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here,
316 which equals RAM + Pagefiles. */ 273 which equals RAM + Pagefiles. */
317 xasprintf(&output_message,_("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"), 274 xasprintf(&output_message, _("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"),
318 mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space, 275 mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space, (mem_commitLimit - mem_commitByte) / 1048567,
319 (mem_commitLimit - mem_commitByte) / 1048567, (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100); 276 (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100);
320 xasprintf(&perfdata,_("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567, 277 xasprintf(&perfdata, _("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), mem_commitByte / 1048567, warning_used_space / 1048567,
321 warning_used_space / 1048567, critical_used_space / 1048567, mem_commitLimit / 1048567); 278 critical_used_space / 1048567, mem_commitLimit / 1048567);
322 279
323 return_code=STATE_OK; 280 return_code = STATE_OK;
324 if(check_critical_value && percent_used_space >= critical_value) 281 if (config.check_critical_value && percent_used_space >= config.critical_value) {
325 return_code=STATE_CRITICAL; 282 return_code = STATE_CRITICAL;
326 else if (check_warning_value && percent_used_space >= warning_value) 283 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
327 return_code=STATE_WARNING; 284 return_code = STATE_WARNING;
285 }
328 286
329 break; 287 break;
330 288 case CHECK_COUNTER: {
331 case CHECK_COUNTER:
332
333
334 /* 289 /*
335 CHECK_COUNTER has been modified to provide extensive perfdata information. 290 CHECK_COUNTER has been modified to provide extensive perfdata information.
336 In order to do this, some modifications have been done to the code 291 In order to do this, some modifications have been done to the code
@@ -352,450 +307,450 @@ int main(int argc, char **argv){
352 strange things will happen when you make graphs of your data. 307 strange things will happen when you make graphs of your data.
353 */ 308 */
354 309
355 if (value_list == NULL) 310 double counter_value = 0.0;
356 output_message = strdup (_("No counter specified")); 311 if (config.value_list == NULL) {
357 else 312 output_message = strdup(_("No counter specified"));
358 { 313 } else {
359 preparelist (value_list); /* replace , between services with & to send the request */ 314 preparelist(config.value_list); /* replace , between services with & to send the request */
360 isPercent = (strchr (value_list, '%') != NULL); 315 bool isPercent = (strchr(config.value_list, '%') != NULL);
361 316
362 strtok (value_list, "&"); /* burn the first parameters */ 317 strtok(config.value_list, "&"); /* burn the first parameters */
363 description = strtok (NULL, "&"); 318 description = strtok(NULL, "&");
364 counter_unit = strtok (NULL, "&"); 319 counter_unit = strtok(NULL, "&");
365 xasprintf (&send_buffer, "%s&8&%s", req_password, value_list); 320 xasprintf(&send_buffer, "%s&8&%s", config.req_password, config.value_list);
366 fetch_data (server_address, server_port, send_buffer); 321 fetch_data(config.server_address, config.server_port, send_buffer);
367 counter_value = atof (recv_buffer); 322 counter_value = atof(recv_buffer);
368 323
369 if (description == NULL) 324 bool allRight = false;
370 xasprintf (&output_message, "%.f", counter_value); 325 if (description == NULL) {
371 else if (isPercent) 326 xasprintf(&output_message, "%.f", counter_value);
372 { 327 } else if (isPercent) {
373 counter_unit = strdup ("%"); 328 counter_unit = strdup("%");
374 allRight = true; 329 allRight = true;
375 } 330 }
376 331
377 if ((counter_unit != NULL) && (!allRight)) 332 char *minval = NULL;
378 { 333 char *maxval = NULL;
379 minval = strtok (NULL, "&"); 334 double fminval = 0;
380 maxval = strtok (NULL, "&"); 335 double fmaxval = 0;
336 if ((counter_unit != NULL) && (!allRight)) {
337 minval = strtok(NULL, "&");
338 maxval = strtok(NULL, "&");
381 339
382 /* All parameters specified. Let's check the numbers */ 340 /* All parameters specified. Let's check the numbers */
383 341
384 fminval = (minval != NULL) ? strtod (minval, &errcvt) : -1; 342 fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1;
385 fmaxval = (minval != NULL) ? strtod (maxval, &errcvt) : -1; 343 fmaxval = (minval != NULL) ? strtod(maxval, &errcvt) : -1;
386
387 if ((fminval == 0) && (minval == errcvt))
388 output_message = strdup (_("Minimum value contains non-numbers"));
389 else
390 {
391 if ((fmaxval == 0) && (maxval == errcvt))
392 output_message = strdup (_("Maximum value contains non-numbers"));
393 else
394 allRight = true; /* Everything is OK. */
395 344
345 if ((fminval == 0) && (minval == errcvt)) {
346 output_message = strdup(_("Minimum value contains non-numbers"));
347 } else {
348 if ((fmaxval == 0) && (maxval == errcvt)) {
349 output_message = strdup(_("Maximum value contains non-numbers"));
350 } else {
351 allRight = true; /* Everything is OK. */
352 }
396 } 353 }
354 } else if ((counter_unit == NULL) && (description != NULL)) {
355 output_message = strdup(_("No unit counter specified"));
397 } 356 }
398 else if ((counter_unit == NULL) && (description != NULL))
399 output_message = strdup (_("No unit counter specified"));
400 357
401 if (allRight) 358 if (allRight) {
402 {
403 /* Let's format the output string, finally... */ 359 /* Let's format the output string, finally... */
404 if (strstr(description, "%") == NULL) { 360 if (strstr(description, "%") == NULL) {
405 xasprintf (&output_message, "%s = %.2f %s", description, counter_value, counter_unit); 361 xasprintf(&output_message, "%s = %.2f %s", description, counter_value, counter_unit);
406 } else { 362 } else {
407 /* has formatting, will segv if wrong */ 363 /* has formatting, will segv if wrong */
408 xasprintf (&output_message, description, counter_value); 364 xasprintf(&output_message, description, counter_value);
409 } 365 }
410 xasprintf (&output_message, "%s |", output_message); 366 xasprintf(&output_message, "%s |", output_message);
411 xasprintf (&output_message,"%s %s", output_message, 367 xasprintf(&output_message, "%s %s", output_message,
412 fperfdata (description, counter_value, 368 fperfdata(description, counter_value, counter_unit, 1, config.warning_value, 1, config.critical_value,
413 counter_unit, 1, warning_value, 1, critical_value, 369 (!(isPercent) && (minval != NULL)), fminval, (!(isPercent) && (minval != NULL)), fmaxval));
414 (!(isPercent) && (minval != NULL)), fminval,
415 (!(isPercent) && (minval != NULL)), fmaxval));
416 } 370 }
417 } 371 }
418 372
419 if (critical_value > warning_value) 373 if (config.critical_value > config.warning_value) { /* Normal thresholds */
420 { /* Normal thresholds */ 374 if (config.check_critical_value && counter_value >= config.critical_value) {
421 if (check_critical_value && counter_value >= critical_value)
422 return_code = STATE_CRITICAL; 375 return_code = STATE_CRITICAL;
423 else if (check_warning_value && counter_value >= warning_value) 376 } else if (config.check_warning_value && counter_value >= config.warning_value) {
424 return_code = STATE_WARNING; 377 return_code = STATE_WARNING;
425 else 378 } else {
426 return_code = STATE_OK; 379 return_code = STATE_OK;
427 } 380 }
428 else 381 } else { /* inverse thresholds */
429 { /* inverse thresholds */
430 return_code = STATE_OK; 382 return_code = STATE_OK;
431 if (check_critical_value && counter_value <= critical_value) 383 if (config.check_critical_value && counter_value <= config.critical_value) {
432 return_code = STATE_CRITICAL; 384 return_code = STATE_CRITICAL;
433 else if (check_warning_value && counter_value <= warning_value) 385 } else if (config.check_warning_value && counter_value <= config.warning_value) {
434 return_code = STATE_WARNING; 386 return_code = STATE_WARNING;
387 }
435 } 388 }
436 break; 389 } break;
437
438 case CHECK_FILEAGE: 390 case CHECK_FILEAGE:
439 391 if (config.value_list == NULL) {
440 if (value_list==NULL) 392 output_message = strdup(_("No counter specified"));
441 output_message = strdup (_("No counter specified")); 393 } else {
442 else { 394 preparelist(config.value_list); /* replace , between services with & to send the request */
443 preparelist(value_list); /* replace , between services with & to send the request */ 395 xasprintf(&send_buffer, "%s&9&%s", config.req_password, config.value_list);
444 xasprintf(&send_buffer,"%s&9&%s", req_password,value_list); 396 fetch_data(config.server_address, config.server_port, send_buffer);
445 fetch_data (server_address, server_port, send_buffer); 397 unsigned long age_in_minutes = atoi(strtok(recv_buffer, "&"));
446 age_in_minutes = atoi(strtok(recv_buffer,"&")); 398 description = strtok(NULL, "&");
447 description = strtok(NULL,"&"); 399 output_message = strdup(description);
448 output_message = strdup (description); 400
449 401 if (config.critical_value > config.warning_value) { /* Normal thresholds */
450 if (critical_value > warning_value) { /* Normal thresholds */ 402 if (config.check_critical_value && age_in_minutes >= config.critical_value) {
451 if(check_critical_value && age_in_minutes >= critical_value) 403 return_code = STATE_CRITICAL;
452 return_code=STATE_CRITICAL; 404 } else if (config.check_warning_value && age_in_minutes >= config.warning_value) {
453 else if (check_warning_value && age_in_minutes >= warning_value) 405 return_code = STATE_WARNING;
454 return_code=STATE_WARNING; 406 } else {
455 else 407 return_code = STATE_OK;
456 return_code=STATE_OK; 408 }
457 } 409 } else { /* inverse thresholds */
458 else { /* inverse thresholds */ 410 if (config.check_critical_value && age_in_minutes <= config.critical_value) {
459 if(check_critical_value && age_in_minutes <= critical_value) 411 return_code = STATE_CRITICAL;
460 return_code=STATE_CRITICAL; 412 } else if (config.check_warning_value && age_in_minutes <= config.warning_value) {
461 else if (check_warning_value && age_in_minutes <= warning_value) 413 return_code = STATE_WARNING;
462 return_code=STATE_WARNING; 414 } else {
463 else 415 return_code = STATE_OK;
464 return_code=STATE_OK; 416 }
465 } 417 }
466 } 418 }
467 break; 419 break;
468 420
469 case CHECK_INSTANCES: 421 case CHECK_INSTANCES:
470 if (value_list==NULL) 422 if (config.value_list == NULL) {
471 output_message = strdup (_("No counter specified")); 423 output_message = strdup(_("No counter specified"));
472 else { 424 } else {
473 xasprintf(&send_buffer,"%s&10&%s", req_password,value_list); 425 xasprintf(&send_buffer, "%s&10&%s", config.req_password, config.value_list);
474 fetch_data (server_address, server_port, send_buffer); 426 fetch_data(config.server_address, config.server_port, send_buffer);
475 if (!strncmp(recv_buffer,"ERROR",5)) { 427 if (!strncmp(recv_buffer, "ERROR", 5)) {
476 printf("NSClient - %s\n",recv_buffer); 428 printf("NSClient - %s\n", recv_buffer);
477 exit(STATE_UNKNOWN); 429 exit(STATE_UNKNOWN);
478 } 430 }
479 xasprintf(&output_message,"%s",recv_buffer); 431 xasprintf(&output_message, "%s", recv_buffer);
480 return_code=STATE_OK; 432 return_code = STATE_OK;
481 } 433 }
482 break; 434 break;
483 435
484 case CHECK_NONE: 436 case CHECK_NONE:
485 default: 437 default:
486 usage4 (_("Please specify a variable to check")); 438 usage4(_("Please specify a variable to check"));
487 break; 439 break;
488
489 } 440 }
490 441
491 /* reset timeout */ 442 /* reset timeout */
492 alarm(0); 443 alarm(0);
493 444
494 if (perfdata==NULL) 445 if (perfdata == NULL) {
495 printf("%s\n",output_message); 446 printf("%s\n", output_message);
496 else 447 } else {
497 printf("%s | %s\n",output_message,perfdata); 448 printf("%s | %s\n", output_message, perfdata);
449 }
498 return return_code; 450 return return_code;
499} 451}
500 452
501
502
503/* process command-line arguments */ 453/* process command-line arguments */
504int process_arguments(int argc, char **argv){ 454check_nt_config_wrapper process_arguments(int argc, char **argv) {
505 int c; 455 static struct option longopts[] = {{"port", required_argument, 0, 'p'},
506 456 {"timeout", required_argument, 0, 't'},
507 int option = 0; 457 {"critical", required_argument, 0, 'c'},
508 static struct option longopts[] = 458 {"warning", required_argument, 0, 'w'},
509 { 459 {"variable", required_argument, 0, 'v'},
510 {"port", required_argument,0,'p'}, 460 {"hostname", required_argument, 0, 'H'},
511 {"timeout", required_argument,0,'t'}, 461 {"params", required_argument, 0, 'l'},
512 {"critical", required_argument,0,'c'}, 462 {"secret", required_argument, 0, 's'},
513 {"warning", required_argument,0,'w'}, 463 {"display", required_argument, 0, 'd'},
514 {"variable", required_argument,0,'v'}, 464 {"unknown-timeout", no_argument, 0, 'u'},
515 {"hostname", required_argument,0,'H'}, 465 {"version", no_argument, 0, 'V'},
516 {"params", required_argument,0,'l'}, 466 {"help", no_argument, 0, 'h'},
517 {"secret", required_argument,0,'s'}, 467 {0, 0, 0, 0}};
518 {"display", required_argument,0,'d'}, 468
519 {"unknown-timeout", no_argument, 0, 'u'}, 469 check_nt_config_wrapper result = {
520 {"version", no_argument, 0,'V'}, 470 .errorcode = OK,
521 {"help", no_argument, 0,'h'}, 471 .config = check_nt_config_init(),
522 {0,0,0,0}
523 }; 472 };
524 473
525 /* no options were supplied */ 474 /* no options were supplied */
526 if(argc<2) return ERROR; 475 if (argc < 2) {
476 result.errorcode = ERROR;
477 return result;
478 }
527 479
528 /* backwards compatibility */ 480 /* backwards compatibility */
529 if (! is_option(argv[1])) { 481 if (!is_option(argv[1])) {
530 server_address = strdup(argv[1]); 482 result.config.server_address = strdup(argv[1]);
531 argv[1]=argv[0]; 483 argv[1] = argv[0];
532 argv=&argv[1]; 484 argv = &argv[1];
533 argc--; 485 argc--;
534 } 486 }
535 487
536 for (c=1;c<argc;c++) { 488 for (int index = 1; index < argc; index++) {
537 if(strcmp("-to",argv[c])==0) 489 if (strcmp("-to", argv[index]) == 0) {
538 strcpy(argv[c],"-t"); 490 strcpy(argv[index], "-t");
539 else if (strcmp("-wv",argv[c])==0) 491 } else if (strcmp("-wv", argv[index]) == 0) {
540 strcpy(argv[c],"-w"); 492 strcpy(argv[index], "-w");
541 else if (strcmp("-cv",argv[c])==0) 493 } else if (strcmp("-cv", argv[index]) == 0) {
542 strcpy(argv[c],"-c"); 494 strcpy(argv[index], "-c");
495 }
543 } 496 }
544 497
545 while (1) { 498 int option = 0;
546 c = getopt_long(argc,argv,"+hVH:t:c:w:p:v:l:s:d:u",longopts,&option); 499 while (true) {
500 int option_index = getopt_long(argc, argv, "+hVH:t:c:w:p:v:l:s:d:u", longopts, &option);
547 501
548 if (c==-1||c==EOF||c==1) 502 if (option_index == -1 || option_index == EOF || option_index == 1) {
549 break; 503 break;
504 }
550 505
551 switch (c) { 506 switch (option_index) {
552 case '?': /* print short usage statement if args not parsable */ 507 case '?': /* print short usage statement if args not parsable */
553 usage5 (); 508 usage5();
554 case 'h': /* help */ 509 case 'h': /* help */
555 print_help(); 510 print_help();
556 exit(STATE_UNKNOWN); 511 exit(STATE_UNKNOWN);
557 case 'V': /* version */ 512 case 'V': /* version */
558 print_revision(progname, NP_VERSION); 513 print_revision(progname, NP_VERSION);
559 exit(STATE_UNKNOWN); 514 exit(STATE_UNKNOWN);
560 case 'H': /* hostname */ 515 case 'H': /* hostname */
561 server_address = optarg; 516 result.config.server_address = optarg;
562 break; 517 break;
563 case 's': /* password */ 518 case 's': /* password */
564 req_password = optarg; 519 result.config.req_password = optarg;
565 break; 520 break;
566 case 'p': /* port */ 521 case 'p': /* port */
567 if (is_intnonneg(optarg)) 522 if (is_intnonneg(optarg)) {
568 server_port=atoi(optarg); 523 result.config.server_port = atoi(optarg);
569 else 524 } else {
570 die(STATE_UNKNOWN,_("Server port must be an integer\n")); 525 die(STATE_UNKNOWN, _("Server port must be an integer\n"));
571 break;
572 case 'v':
573 if(strlen(optarg)<4)
574 return ERROR;
575 if(!strcmp(optarg,"CLIENTVERSION"))
576 vars_to_check=CHECK_CLIENTVERSION;
577 else if(!strcmp(optarg,"CPULOAD"))
578 vars_to_check=CHECK_CPULOAD;
579 else if(!strcmp(optarg,"UPTIME"))
580 vars_to_check=CHECK_UPTIME;
581 else if(!strcmp(optarg,"USEDDISKSPACE"))
582 vars_to_check=CHECK_USEDDISKSPACE;
583 else if(!strcmp(optarg,"SERVICESTATE"))
584 vars_to_check=CHECK_SERVICESTATE;
585 else if(!strcmp(optarg,"PROCSTATE"))
586 vars_to_check=CHECK_PROCSTATE;
587 else if(!strcmp(optarg,"MEMUSE"))
588 vars_to_check=CHECK_MEMUSE;
589 else if(!strcmp(optarg,"COUNTER"))
590 vars_to_check=CHECK_COUNTER;
591 else if(!strcmp(optarg,"FILEAGE"))
592 vars_to_check=CHECK_FILEAGE;
593 else if(!strcmp(optarg,"INSTANCES"))
594 vars_to_check=CHECK_INSTANCES;
595 else
596 return ERROR;
597 break;
598 case 'l': /* value list */
599 value_list = optarg;
600 break;
601 case 'w': /* warning threshold */
602 warning_value=strtoul(optarg,NULL,10);
603 check_warning_value=true;
604 break;
605 case 'c': /* critical threshold */
606 critical_value=strtoul(optarg,NULL,10);
607 check_critical_value=true;
608 break;
609 case 'd': /* Display select for services */
610 if (!strcmp(optarg,"SHOWALL"))
611 show_all = true;
612 break;
613 case 'u':
614 socket_timeout_state=STATE_UNKNOWN;
615 break;
616 case 't': /* timeout */
617 socket_timeout=atoi(optarg);
618 if(socket_timeout<=0)
619 return ERROR;
620 } 526 }
621 527 break;
528 case 'v':
529 if (strlen(optarg) < 4) {
530 result.errorcode = ERROR;
531 return result;
532 }
533 if (!strcmp(optarg, "CLIENTVERSION")) {
534 result.config.vars_to_check = CHECK_CLIENTVERSION;
535 } else if (!strcmp(optarg, "CPULOAD")) {
536 result.config.vars_to_check = CHECK_CPULOAD;
537 } else if (!strcmp(optarg, "UPTIME")) {
538 result.config.vars_to_check = CHECK_UPTIME;
539 } else if (!strcmp(optarg, "USEDDISKSPACE")) {
540 result.config.vars_to_check = CHECK_USEDDISKSPACE;
541 } else if (!strcmp(optarg, "SERVICESTATE")) {
542 result.config.vars_to_check = CHECK_SERVICESTATE;
543 } else if (!strcmp(optarg, "PROCSTATE")) {
544 result.config.vars_to_check = CHECK_PROCSTATE;
545 } else if (!strcmp(optarg, "MEMUSE")) {
546 result.config.vars_to_check = CHECK_MEMUSE;
547 } else if (!strcmp(optarg, "COUNTER")) {
548 result.config.vars_to_check = CHECK_COUNTER;
549 } else if (!strcmp(optarg, "FILEAGE")) {
550 result.config.vars_to_check = CHECK_FILEAGE;
551 } else if (!strcmp(optarg, "INSTANCES")) {
552 result.config.vars_to_check = CHECK_INSTANCES;
553 } else {
554 result.errorcode = ERROR;
555 return result;
556 }
557 break;
558 case 'l': /* value list */
559 result.config.value_list = optarg;
560 break;
561 case 'w': /* warning threshold */
562 result.config.warning_value = strtoul(optarg, NULL, 10);
563 result.config.check_warning_value = true;
564 break;
565 case 'c': /* critical threshold */
566 result.config.critical_value = strtoul(optarg, NULL, 10);
567 result.config.check_critical_value = true;
568 break;
569 case 'd': /* Display select for services */
570 if (!strcmp(optarg, "SHOWALL")) {
571 result.config.show_all = true;
572 }
573 break;
574 case 'u':
575 socket_timeout_state = STATE_UNKNOWN;
576 break;
577 case 't': /* timeout */
578 socket_timeout = atoi(optarg);
579 if (socket_timeout <= 0) {
580 result.errorcode = ERROR;
581 return result;
582 }
583 }
584 }
585 if (result.config.server_address == NULL) {
586 usage4(_("You must provide a server address or host name"));
622 } 587 }
623 if (server_address == NULL)
624 usage4 (_("You must provide a server address or host name"));
625 588
626 if (vars_to_check==CHECK_NONE) 589 if (result.config.vars_to_check == CHECK_NONE) {
627 return ERROR; 590 result.errorcode = ERROR;
591 return result;
592 }
628 593
629 if (req_password == NULL) 594 if (result.config.req_password == NULL) {
630 req_password = strdup (_("None")); 595 result.config.req_password = strdup(_("None"));
596 }
631 597
632 return OK; 598 return result;
633} 599}
634 600
601void fetch_data(const char *address, int port, const char *sendb) {
602 int result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer));
635 603
604 if (result != STATE_OK) {
605 die(result, _("could not fetch information from server\n"));
606 }
636 607
637void fetch_data (const char *address, int port, const char *sendb) { 608 if (!strncmp(recv_buffer, "ERROR", 5)) {
638 int result; 609 die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer);
639 610 }
640 result=process_tcp_request(address, port, sendb, recv_buffer,sizeof(recv_buffer));
641
642 if(result!=STATE_OK)
643 die (result, _("could not fetch information from server\n"));
644
645 if (!strncmp(recv_buffer,"ERROR",5))
646 die (STATE_UNKNOWN, "NSClient - %s\n",recv_buffer);
647} 611}
648 612
649bool strtoularray(unsigned long *array, char *string, const char *delim) { 613bool strtoularray(unsigned long *array, char *string, const char *delim) {
650 /* split a <delim> delimited string into a long array */ 614 /* split a <delim> delimited string into a long array */
651 int idx=0; 615 for (int idx = 0; idx < MAX_VALUE_LIST; idx++) {
652 char *t1; 616 array[idx] = 0;
653 617 }
654 for (idx=0;idx<MAX_VALUE_LIST;idx++)
655 array[idx]=0;
656 618
657 idx=0; 619 int idx = 0;
658 for(t1 = strtok(string,delim);t1 != NULL; t1 = strtok(NULL, delim)) { 620 for (char *t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) {
659 if (is_numeric(t1) && idx<MAX_VALUE_LIST) { 621 if (is_numeric(t1) && idx < MAX_VALUE_LIST) {
660 array[idx]=strtoul(t1,NULL,10); 622 array[idx] = strtoul(t1, NULL, 10);
661 idx++; 623 idx++;
662 } else 624 } else {
663 return false; 625 return false;
626 }
664 } 627 }
665 return true; 628 return true;
666} 629}
667 630
668void preparelist(char *string) { 631void preparelist(char *string) {
669 /* Replace all , with & which is the delimiter for the request */ 632 /* Replace all , with & which is the delimiter for the request */
670 int i; 633 for (int i = 0; (size_t)i < strlen(string); i++) {
671
672 for (i = 0; (size_t)i < strlen(string); i++)
673 if (string[i] == ',') { 634 if (string[i] == ',') {
674 string[i]='&'; 635 string[i] = '&';
675 } 636 }
637 }
676} 638}
677 639
678 640void print_help(void) {
679
680void print_help(void)
681{
682 print_revision(progname, NP_VERSION); 641 print_revision(progname, NP_VERSION);
683 642
684 printf ("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n"); 643 printf("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n");
685 printf (COPYRIGHT, copyright, email); 644 printf(COPYRIGHT, copyright, email);
686 645
687 printf ("%s\n", _("This plugin collects data from the NSClient service running on a")); 646 printf("%s\n", _("This plugin collects data from the NSClient service running on a"));
688 printf ("%s\n", _("Windows NT/2000/XP/2003 server.")); 647 printf("%s\n", _("Windows NT/2000/XP/2003 server."));
689 648
690 printf ("\n\n"); 649 printf("\n\n");
691 650
692 print_usage(); 651 print_usage();
693 652
694 printf (UT_HELP_VRSN); 653 printf(UT_HELP_VRSN);
695 printf (UT_EXTRA_OPTS); 654 printf(UT_EXTRA_OPTS);
696 655
697 printf ("%s\n", _("Options:")); 656 printf("%s\n", _("Options:"));
698 printf (" %s\n", "-H, --hostname=HOST"); 657 printf(" %s\n", "-H, --hostname=HOST");
699 printf (" %s\n", _("Name of the host to check")); 658 printf(" %s\n", _("Name of the host to check"));
700 printf (" %s\n", "-p, --port=INTEGER"); 659 printf(" %s\n", "-p, --port=INTEGER");
701 printf (" %s", _("Optional port number (default: ")); 660 printf(" %s", _("Optional port number (default: "));
702 printf ("%d)\n", PORT); 661 printf("%d)\n", PORT);
703 printf (" %s\n", "-s, --secret=<password>"); 662 printf(" %s\n", "-s, --secret=<password>");
704 printf (" %s\n", _("Password needed for the request")); 663 printf(" %s\n", _("Password needed for the request"));
705 printf (" %s\n", "-w, --warning=INTEGER"); 664 printf(" %s\n", "-w, --warning=INTEGER");
706 printf (" %s\n", _("Threshold which will result in a warning status")); 665 printf(" %s\n", _("Threshold which will result in a warning status"));
707 printf (" %s\n", "-c, --critical=INTEGER"); 666 printf(" %s\n", "-c, --critical=INTEGER");
708 printf (" %s\n", _("Threshold which will result in a critical status")); 667 printf(" %s\n", _("Threshold which will result in a critical status"));
709 printf (" %s\n", "-t, --timeout=INTEGER"); 668 printf(" %s\n", "-t, --timeout=INTEGER");
710 printf (" %s", _("Seconds before connection attempt times out (default: ")); 669 printf(" %s", _("Seconds before connection attempt times out (default: "));
711 printf (" %s\n", "-l, --params=<parameters>"); 670 printf(" %s\n", "-l, --params=<parameters>");
712 printf (" %s", _("Parameters passed to specified check (see below)")); 671 printf(" %s", _("Parameters passed to specified check (see below)"));
713 printf (" %s\n", "-d, --display={SHOWALL}"); 672 printf(" %s\n", "-d, --display={SHOWALL}");
714 printf (" %s", _("Display options (currently only SHOWALL works)")); 673 printf(" %s", _("Display options (currently only SHOWALL works)"));
715 printf (" %s\n", "-u, --unknown-timeout"); 674 printf(" %s\n", "-u, --unknown-timeout");
716 printf (" %s", _("Return UNKNOWN on timeouts")); 675 printf(" %s", _("Return UNKNOWN on timeouts"));
717 printf ("%d)\n", DEFAULT_SOCKET_TIMEOUT); 676 printf("%d)\n", DEFAULT_SOCKET_TIMEOUT);
718 printf (" %s\n", "-h, --help"); 677 printf(" %s\n", "-h, --help");
719 printf (" %s\n", _("Print this help screen")); 678 printf(" %s\n", _("Print this help screen"));
720 printf (" %s\n", "-V, --version"); 679 printf(" %s\n", "-V, --version");
721 printf (" %s\n", _("Print version information")); 680 printf(" %s\n", _("Print version information"));
722 printf (" %s\n", "-v, --variable=STRING"); 681 printf(" %s\n", "-v, --variable=STRING");
723 printf (" %s\n\n", _("Variable to check")); 682 printf(" %s\n\n", _("Variable to check"));
724 printf ("%s\n", _("Valid variables are:")); 683 printf("%s\n", _("Valid variables are:"));
725 printf (" %s", "CLIENTVERSION ="); 684 printf(" %s", "CLIENTVERSION =");
726 printf (" %s\n", _("Get the NSClient version")); 685 printf(" %s\n", _("Get the NSClient version"));
727 printf (" %s\n", _("If -l <version> is specified, will return warning if versions differ.")); 686 printf(" %s\n", _("If -l <version> is specified, will return warning if versions differ."));
728 printf (" %s\n", "CPULOAD ="); 687 printf(" %s\n", "CPULOAD =");
729 printf (" %s\n", _("Average CPU load on last x minutes.")); 688 printf(" %s\n", _("Average CPU load on last x minutes."));
730 printf (" %s\n", _("Request a -l parameter with the following syntax:")); 689 printf(" %s\n", _("Request a -l parameter with the following syntax:"));
731 printf (" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>.")); 690 printf(" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>."));
732 printf (" %s\n", _("<minute range> should be less than 24*60.")); 691 printf(" %s\n", _("<minute range> should be less than 24*60."));
733 printf (" %s\n", _("Thresholds are percentage and up to 10 requests can be done in one shot.")); 692 printf(" %s\n", _("Thresholds are percentage and up to 10 requests can be done in one shot."));
734 printf (" %s\n", "ie: -l 60,90,95,120,90,95"); 693 printf(" %s\n", "ie: -l 60,90,95,120,90,95");
735 printf (" %s\n", "UPTIME ="); 694 printf(" %s\n", "UPTIME =");
736 printf (" %s\n", _("Get the uptime of the machine.")); 695 printf(" %s\n", _("Get the uptime of the machine."));
737 printf (" %s\n", _("-l <unit> ")); 696 printf(" %s\n", _("-l <unit> "));
738 printf (" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)")); 697 printf(" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)"));
739 printf (" %s\n", _("Thresholds will use the unit specified above.")); 698 printf(" %s\n", _("Thresholds will use the unit specified above."));
740 printf (" %s\n", "USEDDISKSPACE ="); 699 printf(" %s\n", "USEDDISKSPACE =");
741 printf (" %s\n", _("Size and percentage of disk use.")); 700 printf(" %s\n", _("Size and percentage of disk use."));
742 printf (" %s\n", _("Request a -l parameter containing the drive letter only.")); 701 printf(" %s\n", _("Request a -l parameter containing the drive letter only."));
743 printf (" %s\n", _("Warning and critical thresholds can be specified with -w and -c.")); 702 printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
744 printf (" %s\n", "MEMUSE ="); 703 printf(" %s\n", "MEMUSE =");
745 printf (" %s\n", _("Memory use.")); 704 printf(" %s\n", _("Memory use."));
746 printf (" %s\n", _("Warning and critical thresholds can be specified with -w and -c.")); 705 printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c."));
747 printf (" %s\n", "SERVICESTATE ="); 706 printf(" %s\n", "SERVICESTATE =");
748 printf (" %s\n", _("Check the state of one or several services.")); 707 printf(" %s\n", _("Check the state of one or several services."));
749 printf (" %s\n", _("Request a -l parameters with the following syntax:")); 708 printf(" %s\n", _("Request a -l parameters with the following syntax:"));
750 printf (" %s\n", _("-l <service1>,<service2>,<service3>,...")); 709 printf(" %s\n", _("-l <service1>,<service2>,<service3>,..."));
751 printf (" %s\n", _("You can specify -d SHOWALL in case you want to see working services")); 710 printf(" %s\n", _("You can specify -d SHOWALL in case you want to see working services"));
752 printf (" %s\n", _("in the returned string.")); 711 printf(" %s\n", _("in the returned string."));
753 printf (" %s\n", "PROCSTATE ="); 712 printf(" %s\n", "PROCSTATE =");
754 printf (" %s\n", _("Check if one or several process are running.")); 713 printf(" %s\n", _("Check if one or several process are running."));
755 printf (" %s\n", _("Same syntax as SERVICESTATE.")); 714 printf(" %s\n", _("Same syntax as SERVICESTATE."));
756 printf (" %s\n", "COUNTER ="); 715 printf(" %s\n", "COUNTER =");
757 printf (" %s\n", _("Check any performance counter of Windows NT/2000.")); 716 printf(" %s\n", _("Check any performance counter of Windows NT/2000."));
758 printf (" %s\n", _("Request a -l parameters with the following syntax:")); 717 printf(" %s\n", _("Request a -l parameters with the following syntax:"));
759 printf (" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>")); 718 printf(" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>"));
760 printf (" %s\n", _("The <description> parameter is optional and is given to a printf ")); 719 printf(" %s\n", _("The <description> parameter is optional and is given to a printf "));
761 printf (" %s\n", _("output command which requires a float parameter.")); 720 printf(" %s\n", _("output command which requires a float parameter."));
762 printf (" %s\n", _("If <description> does not include \"%%\", it is used as a label.")); 721 printf(" %s\n", _("If <description> does not include \"%%\", it is used as a label."));
763 printf (" %s\n", _("Some examples:")); 722 printf(" %s\n", _("Some examples:"));
764 printf (" %s\n", "\"Paging file usage is %%.2f %%%%\""); 723 printf(" %s\n", "\"Paging file usage is %%.2f %%%%\"");
765 printf (" %s\n", "\"%%.f %%%% paging file used.\""); 724 printf(" %s\n", "\"%%.f %%%% paging file used.\"");
766 printf (" %s\n", "INSTANCES ="); 725 printf(" %s\n", "INSTANCES =");
767 printf (" %s\n", _("Check any performance counter object of Windows NT/2000.")); 726 printf(" %s\n", _("Check any performance counter object of Windows NT/2000."));
768 printf (" %s\n", _("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>")); 727 printf(" %s\n", _("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>"));
769 printf (" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),")); 728 printf(" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),"));
770 printf (" %s\n", _("if it is two words, it should be enclosed in quotes")); 729 printf(" %s\n", _("if it is two words, it should be enclosed in quotes"));
771 printf (" %s\n", _("The returned results will be a comma-separated list of instances on ")); 730 printf(" %s\n", _("The returned results will be a comma-separated list of instances on "));
772 printf (" %s\n", _(" the selected computer for that object.")); 731 printf(" %s\n", _(" the selected computer for that object."));
773 printf (" %s\n", _("The purpose of this is to be run from command line to determine what instances")); 732 printf(" %s\n", _("The purpose of this is to be run from command line to determine what instances"));
774 printf (" %s\n", _(" are available for monitoring without having to log onto the Windows server")); 733 printf(" %s\n", _(" are available for monitoring without having to log onto the Windows server"));
775 printf (" %s\n", _(" to run Perfmon directly.")); 734 printf(" %s\n", _(" to run Perfmon directly."));
776 printf (" %s\n", _("It can also be used in scripts that automatically create the monitoring service")); 735 printf(" %s\n", _("It can also be used in scripts that automatically create the monitoring service"));
777 printf (" %s\n", _(" configuration files.")); 736 printf(" %s\n", _(" configuration files."));
778 printf (" %s\n", _("Some examples:")); 737 printf(" %s\n", _("Some examples:"));
779 printf (" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process")); 738 printf(" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process"));
780 739
781 printf ("%s\n", _("Notes:")); 740 printf("%s\n", _("Notes:"));
782 printf (" %s\n", _("- The NSClient service should be running on the server to get any information")); 741 printf(" %s\n", _("- The NSClient service should be running on the server to get any information"));
783 printf (" %s\n", "(http://nsclient.ready2run.nl)."); 742 printf(" %s\n", "(http://nsclient.ready2run.nl).");
784 printf (" %s\n", _("- Critical thresholds should be lower than warning thresholds")); 743 printf(" %s\n", _("- Critical thresholds should be lower than warning thresholds"));
785 printf (" %s\n", _("- Default port 1248 is sometimes in use by other services. The error")); 744 printf(" %s\n", _("- Default port 1248 is sometimes in use by other services. The error"));
786 printf (" %s\n", _("output when this happens contains \"Cannot map xxxxx to protocol number\".")); 745 printf(" %s\n", _("output when this happens contains \"Cannot map xxxxx to protocol number\"."));
787 printf (" %s\n", _("One fix for this is to change the port to something else on check_nt ")); 746 printf(" %s\n", _("One fix for this is to change the port to something else on check_nt "));
788 printf (" %s\n", _("and on the client service it\'s connecting to.")); 747 printf(" %s\n", _("and on the client service it\'s connecting to."));
789 748
790 printf (UT_SUPPORT); 749 printf(UT_SUPPORT);
791} 750}
792 751
793 752void print_usage(void) {
794 753 printf("%s\n", _("Usage:"));
795void print_usage(void) 754 printf("%s -H host -v variable [-p port] [-w warning] [-c critical]\n", progname);
796{ 755 printf("[-l params] [-d SHOWALL] [-u] [-t timeout]\n");
797 printf ("%s\n", _("Usage:"));
798 printf ("%s -H host -v variable [-p port] [-w warning] [-c critical]\n",progname);
799 printf ("[-l params] [-d SHOWALL] [-u] [-t timeout]\n");
800} 756}
801
diff --git a/plugins/check_nt.d/config.h b/plugins/check_nt.d/config.h
new file mode 100644
index 00000000..431889cb
--- /dev/null
+++ b/plugins/check_nt.d/config.h
@@ -0,0 +1,53 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 PORT = 1248,
8};
9
10enum checkvars {
11 CHECK_NONE,
12 CHECK_CLIENTVERSION,
13 CHECK_CPULOAD,
14 CHECK_UPTIME,
15 CHECK_USEDDISKSPACE,
16 CHECK_SERVICESTATE,
17 CHECK_PROCSTATE,
18 CHECK_MEMUSE,
19 CHECK_COUNTER,
20 CHECK_FILEAGE,
21 CHECK_INSTANCES
22};
23
24typedef struct {
25 char *server_address;
26 int server_port;
27 char *req_password;
28 enum checkvars vars_to_check;
29 bool show_all;
30 char *value_list;
31 bool check_warning_value;
32 unsigned long warning_value;
33 bool check_critical_value;
34 unsigned long critical_value;
35} check_nt_config;
36
37check_nt_config check_nt_config_init() {
38 check_nt_config tmp = {
39 .server_address = NULL,
40 .server_port = PORT,
41 .req_password = NULL,
42
43 .vars_to_check = CHECK_NONE,
44 .show_all = false,
45 .value_list = NULL,
46
47 .check_warning_value = false,
48 .warning_value = 0,
49 .check_critical_value = false,
50 .critical_value = 0,
51 };
52 return tmp;
53}
diff --git a/plugins/check_ntp.c b/plugins/check_ntp.c
index 61b2d699..d33f8786 100644
--- a/plugins/check_ntp.c
+++ b/plugins/check_ntp.c
@@ -4,7 +4,7 @@
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2006 Sean Finney <seanius@seanius.net> 6* Copyright (c) 2006 Sean Finney <seanius@seanius.net>
7* Copyright (c) 2006-2008 Monitoring Plugins Development Team 7* Copyright (c) 2006-2024 Monitoring Plugins Development Team
8* 8*
9* Description: 9* Description:
10* 10*
@@ -31,7 +31,7 @@
31*****************************************************************************/ 31*****************************************************************************/
32 32
33const char *progname = "check_ntp"; 33const char *progname = "check_ntp";
34const char *copyright = "2006-2008"; 34const char *copyright = "2006-2024";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#include "common.h" 37#include "common.h"
@@ -47,10 +47,10 @@ static bool do_jitter = false;
47static char *jwarn="5000"; 47static char *jwarn="5000";
48static char *jcrit="10000"; 48static char *jcrit="10000";
49 49
50int process_arguments (int, char **); 50static int process_arguments (int /*argc*/, char ** /*argv*/);
51thresholds *offset_thresholds = NULL; 51static thresholds *offset_thresholds = NULL;
52thresholds *jitter_thresholds = NULL; 52static thresholds *jitter_thresholds = NULL;
53void print_help (void); 53static void print_help (void);
54void print_usage (void); 54void print_usage (void);
55 55
56/* number of times to perform each request to get a good average. */ 56/* number of times to perform each request to get a good average. */
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
index 464a9e10..6e76bf23 100644
--- a/plugins/check_ntp_peer.c
+++ b/plugins/check_ntp_peer.c
@@ -1,88 +1,77 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ntp_peer plugin 3 * Monitoring check_ntp_peer plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006 Sean Finney <seanius@seanius.net> 6 * Copyright (c) 2006 Sean Finney <seanius@seanius.net>
7* Copyright (c) 2006-2008 Monitoring Plugins Development Team 7 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_ntp_peer plugin 11 * This file contains the check_ntp_peer plugin
12* 12 *
13* This plugin checks an NTP server independent of any commandline 13 * This plugin checks an NTP server independent of any commandline
14* programs or external libraries. 14 * programs or external libraries.
15* 15 *
16* Use this plugin to check the health of an NTP server. It supports 16 * Use this plugin to check the health of an NTP server. It supports
17* checking the offset with the sync peer, the jitter and stratum. This 17 * checking the offset with the sync peer, the jitter and stratum. This
18* plugin will not check the clock offset between the local host and NTP 18 * plugin will not check the clock offset between the local host and NTP
19* server; please use check_ntp_time for that purpose. 19 * server; please use check_ntp_time for that purpose.
20* 20 *
21* 21 *
22* This program is free software: you can redistribute it and/or modify 22 * This program is free software: you can redistribute it and/or modify
23* it under the terms of the GNU General Public License as published by 23 * it under the terms of the GNU General Public License as published by
24* the Free Software Foundation, either version 3 of the License, or 24 * the Free Software Foundation, either version 3 of the License, or
25* (at your option) any later version. 25 * (at your option) any later version.
26* 26 *
27* This program is distributed in the hope that it will be useful, 27 * This program is distributed in the hope that it will be useful,
28* but WITHOUT ANY WARRANTY; without even the implied warranty of 28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30* GNU General Public License for more details. 30 * GNU General Public License for more details.
31* 31 *
32* You should have received a copy of the GNU General Public License 32 * You should have received a copy of the GNU General Public License
33* along with this program. If not, see <http://www.gnu.org/licenses/>. 33 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34* 34 *
35* 35 *
36*****************************************************************************/ 36 *****************************************************************************/
37 37
38#include "thresholds.h"
38const char *progname = "check_ntp_peer"; 39const char *progname = "check_ntp_peer";
39const char *copyright = "2006-2008"; 40const char *copyright = "2006-2024";
40const char *email = "devel@monitoring-plugins.org"; 41const char *email = "devel@monitoring-plugins.org";
41 42
42#include "common.h" 43#include "common.h"
43#include "netutils.h" 44#include "netutils.h"
44#include "utils.h" 45#include "utils.h"
46#include "../lib/states.h"
47#include "check_ntp_peer.d/config.h"
45 48
46static char *server_address=NULL; 49static int verbose = 0;
47static int port=123;
48static int verbose=0;
49static bool quiet = false;
50static char *owarn="60";
51static char *ocrit="120";
52static bool do_stratum = false;
53static char *swarn="-1:16";
54static char *scrit="-1:16";
55static bool do_jitter = false;
56static char *jwarn="-1:5000";
57static char *jcrit="-1:10000";
58static bool do_truechimers = false;
59static char *twarn="0:";
60static char *tcrit="0:";
61static bool syncsource_found = false; 50static bool syncsource_found = false;
62static bool li_alarm = false; 51static bool li_alarm = false;
63 52
64int process_arguments (int, char **); 53typedef struct {
65thresholds *offset_thresholds = NULL; 54 int errorcode;
66thresholds *jitter_thresholds = NULL; 55 check_ntp_peer_config config;
67thresholds *stratum_thresholds = NULL; 56} check_ntp_peer_config_wrapper;
68thresholds *truechimer_thresholds = NULL; 57static check_ntp_peer_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
69void print_help (void); 58static void print_help(void);
70void print_usage (void); 59void print_usage(void);
71 60
72/* max size of control message data */ 61/* max size of control message data */
73#define MAX_CM_SIZE 468 62#define MAX_CM_SIZE 468
74 63
75/* this structure holds everything in an ntp control message as per rfc1305 */ 64/* this structure holds everything in an ntp control message as per rfc1305 */
76typedef struct { 65typedef struct {
77 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 66 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
78 uint8_t op; /* R,E,M bits and Opcode */ 67 uint8_t op; /* R,E,M bits and Opcode */
79 uint16_t seq; /* Packet sequence */ 68 uint16_t seq; /* Packet sequence */
80 uint16_t status; /* Clock status */ 69 uint16_t status; /* Clock status */
81 uint16_t assoc; /* Association */ 70 uint16_t assoc; /* Association */
82 uint16_t offset; /* Similar to TCP sequence # */ 71 uint16_t offset; /* Similar to TCP sequence # */
83 uint16_t count; /* # bytes of data */ 72 uint16_t count; /* # bytes of data */
84 char data[MAX_CM_SIZE]; /* ASCII data of the request */ 73 char data[MAX_CM_SIZE]; /* ASCII data of the request */
85 /* NB: not necessarily NULL terminated! */ 74 /* NB: not necessarily NULL terminated! */
86} ntp_control_message; 75} ntp_control_message;
87 76
88/* this is an association/status-word pair found in control packet responses */ 77/* this is an association/status-word pair found in control packet responses */
@@ -93,82 +82,96 @@ typedef struct {
93 82
94/* bits 1,2 are the leap indicator */ 83/* bits 1,2 are the leap indicator */
95#define LI_MASK 0xc0 84#define LI_MASK 0xc0
96#define LI(x) ((x&LI_MASK)>>6) 85#define LI(x) ((x & LI_MASK) >> 6)
97#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0) 86#define LI_SET(x, y) \
87 do { \
88 x |= ((y << 6) & LI_MASK); \
89 } while (0)
98/* and these are the values of the leap indicator */ 90/* and these are the values of the leap indicator */
99#define LI_NOWARNING 0x00 91#define LI_NOWARNING 0x00
100#define LI_EXTRASEC 0x01 92#define LI_EXTRASEC 0x01
101#define LI_MISSINGSEC 0x02 93#define LI_MISSINGSEC 0x02
102#define LI_ALARM 0x03 94#define LI_ALARM 0x03
103/* bits 3,4,5 are the ntp version */ 95/* bits 3,4,5 are the ntp version */
104#define VN_MASK 0x38 96#define VN_MASK 0x38
105#define VN(x) ((x&VN_MASK)>>3) 97#define VN(x) ((x & VN_MASK) >> 3)
106#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0) 98#define VN_SET(x, y) \
99 do { \
100 x |= ((y << 3) & VN_MASK); \
101 } while (0)
107#define VN_RESERVED 0x02 102#define VN_RESERVED 0x02
108/* bits 6,7,8 are the ntp mode */ 103/* bits 6,7,8 are the ntp mode */
109#define MODE_MASK 0x07 104#define MODE_MASK 0x07
110#define MODE(x) (x&MODE_MASK) 105#define MODE(x) (x & MODE_MASK)
111#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0) 106#define MODE_SET(x, y) \
107 do { \
108 x |= (y & MODE_MASK); \
109 } while (0)
112/* here are some values */ 110/* here are some values */
113#define MODE_CLIENT 0x03 111#define MODE_CLIENT 0x03
114#define MODE_CONTROLMSG 0x06 112#define MODE_CONTROLMSG 0x06
115/* In control message, bits 8-10 are R,E,M bits */ 113/* In control message, bits 8-10 are R,E,M bits */
116#define REM_MASK 0xe0 114#define REM_MASK 0xe0
117#define REM_RESP 0x80 115#define REM_RESP 0x80
118#define REM_ERROR 0x40 116#define REM_ERROR 0x40
119#define REM_MORE 0x20 117#define REM_MORE 0x20
120/* In control message, bits 11 - 15 are opcode */ 118/* In control message, bits 11 - 15 are opcode */
121#define OP_MASK 0x1f 119#define OP_MASK 0x1f
122#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0) 120#define OP_SET(x, y) \
121 do { \
122 x |= (y & OP_MASK); \
123 } while (0)
123#define OP_READSTAT 0x01 124#define OP_READSTAT 0x01
124#define OP_READVAR 0x02 125#define OP_READVAR 0x02
125/* In peer status bytes, bits 6,7,8 determine clock selection status */ 126/* In peer status bytes, bits 6,7,8 determine clock selection status */
126#define PEER_SEL(x) ((ntohs(x)>>8)&0x07) 127#define PEER_SEL(x) ((ntohs(x) >> 8) & 0x07)
127#define PEER_TRUECHIMER 0x02 128#define PEER_TRUECHIMER 0x02
128#define PEER_INCLUDED 0x04 129#define PEER_INCLUDED 0x04
129#define PEER_SYNCSOURCE 0x06 130#define PEER_SYNCSOURCE 0x06
130 131
131/* NTP control message header is 12 bytes, plus any data in the data 132/* NTP control message header is 12 bytes, plus any data in the data
132 * field, plus null padding to the nearest 32-bit boundary per rfc. 133 * field, plus null padding to the nearest 32-bit boundary per rfc.
133 */ 134 */
134#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((ntohs(m.count)%4)?4-(ntohs(m.count)%4):0)) 135#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((ntohs(m.count) % 4) ? 4 - (ntohs(m.count) % 4) : 0))
135 136
136/* finally, a little helper or two for debugging: */ 137/* finally, a little helper or two for debugging: */
137#define DBG(x) do{if(verbose>1){ x; }}while(0); 138#define DBG(x) \
138#define PRINTSOCKADDR(x) \ 139 do { \
139 do{ \ 140 if (verbose > 1) { \
140 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ 141 x; \
141 }while(0); 142 } \
142 143 } while (0);
143void print_ntp_control_message(const ntp_control_message *p){ 144#define PRINTSOCKADDR(x) \
144 int i=0, numpeers=0; 145 do { \
145 const ntp_assoc_status_pair *peer=NULL; 146 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
146 147 } while (0);
148
149void print_ntp_control_message(const ntp_control_message *message) {
147 printf("control packet contents:\n"); 150 printf("control packet contents:\n");
148 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); 151 printf("\tflags: 0x%.2x , 0x%.2x\n", message->flags, message->op);
149 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); 152 printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
150 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK); 153 printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
151 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK); 154 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
152 printf("\t response=%d (0x%.2x)\n", (p->op&REM_RESP)>0, p->op&REM_RESP); 155 printf("\t response=%d (0x%.2x)\n", (message->op & REM_RESP) > 0, message->op & REM_RESP);
153 printf("\t more=%d (0x%.2x)\n", (p->op&REM_MORE)>0, p->op&REM_MORE); 156 printf("\t more=%d (0x%.2x)\n", (message->op & REM_MORE) > 0, message->op & REM_MORE);
154 printf("\t error=%d (0x%.2x)\n", (p->op&REM_ERROR)>0, p->op&REM_ERROR); 157 printf("\t error=%d (0x%.2x)\n", (message->op & REM_ERROR) > 0, message->op & REM_ERROR);
155 printf("\t op=%d (0x%.2x)\n", p->op&OP_MASK, p->op&OP_MASK); 158 printf("\t op=%d (0x%.2x)\n", message->op & OP_MASK, message->op & OP_MASK);
156 printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq)); 159 printf("\tsequence: %d (0x%.2x)\n", ntohs(message->seq), ntohs(message->seq));
157 printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status)); 160 printf("\tstatus: %d (0x%.2x)\n", ntohs(message->status), ntohs(message->status));
158 printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc)); 161 printf("\tassoc: %d (0x%.2x)\n", ntohs(message->assoc), ntohs(message->assoc));
159 printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset)); 162 printf("\toffset: %d (0x%.2x)\n", ntohs(message->offset), ntohs(message->offset));
160 printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count)); 163 printf("\tcount: %d (0x%.2x)\n", ntohs(message->count), ntohs(message->count));
161 numpeers=ntohs(p->count)/(sizeof(ntp_assoc_status_pair)); 164
162 if(p->op&REM_RESP && p->op&OP_READSTAT){ 165 int numpeers = ntohs(message->count) / (sizeof(ntp_assoc_status_pair));
163 peer=(ntp_assoc_status_pair*)p->data; 166 if (message->op & REM_RESP && message->op & OP_READSTAT) {
164 for(i=0;i<numpeers;i++){ 167 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)message->data;
165 printf("\tpeer id %.2x status %.2x", 168 for (int i = 0; i < numpeers; i++) {
166 ntohs(peer[i].assoc), ntohs(peer[i].status)); 169 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status));
167 if(PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE){ 170 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) {
168 printf(" <-- current sync source"); 171 printf(" <-- current sync source");
169 } else if(PEER_SEL(peer[i].status) >= PEER_INCLUDED){ 172 } else if (PEER_SEL(peer[i].status) >= PEER_INCLUDED) {
170 printf(" <-- current sync candidate"); 173 printf(" <-- current sync candidate");
171 } else if(PEER_SEL(peer[i].status) >= PEER_TRUECHIMER){ 174 } else if (PEER_SEL(peer[i].status) >= PEER_TRUECHIMER) {
172 printf(" <-- outlyer, but truechimer"); 175 printf(" <-- outlyer, but truechimer");
173 } 176 }
174 printf("\n"); 177 printf("\n");
@@ -176,14 +179,13 @@ void print_ntp_control_message(const ntp_control_message *p){
176 } 179 }
177} 180}
178 181
179void 182void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_t seq) {
180setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){ 183 memset(message, 0, sizeof(ntp_control_message));
181 memset(p, 0, sizeof(ntp_control_message)); 184 LI_SET(message->flags, LI_NOWARNING);
182 LI_SET(p->flags, LI_NOWARNING); 185 VN_SET(message->flags, VN_RESERVED);
183 VN_SET(p->flags, VN_RESERVED); 186 MODE_SET(message->flags, MODE_CONTROLMSG);
184 MODE_SET(p->flags, MODE_CONTROLMSG); 187 OP_SET(message->op, opcode);
185 OP_SET(p->op, opcode); 188 message->seq = htons(seq);
186 p->seq = htons(seq);
187 /* Remaining fields are zero for requests */ 189 /* Remaining fields are zero for requests */
188} 190}
189 191
@@ -198,22 +200,23 @@ setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq){
198 * status is pretty much useless as syncsource_found is a global variable 200 * status is pretty much useless as syncsource_found is a global variable
199 * used later in main to check is the server was synchronized. It works 201 * used later in main to check is the server was synchronized. It works
200 * so I left it alone */ 202 * so I left it alone */
201int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers){ 203typedef struct {
202 int conn=-1, i, npeers=0, num_candidates=0; 204 mp_state_enum state;
203 double tmp_offset = 0; 205 mp_state_enum offset_result;
204 int min_peer_sel=PEER_INCLUDED; 206 double offset;
205 int peers_size=0, peer_offset=0; 207 double jitter;
206 int status; 208 long stratum;
207 ntp_assoc_status_pair *peers=NULL; 209 int num_truechimers;
208 ntp_control_message req; 210} ntp_request_result;
209 const char *getvar = "stratum,offset,jitter"; 211ntp_request_result ntp_request(const check_ntp_peer_config config) {
210 char *data, *value, *nptr; 212
211 void *tmp; 213 ntp_request_result result = {
212 214 .state = STATE_OK,
213 status = STATE_OK; 215 .offset_result = STATE_UNKNOWN,
214 *offset_result = STATE_UNKNOWN; 216 .jitter = -1,
215 *jitter = *stratum = -1; 217 .stratum = -1,
216 *num_truechimers = 0; 218 .num_truechimers = 0,
219 };
217 220
218 /* Long-winded explanation: 221 /* Long-winded explanation:
219 * Getting the sync peer offset, jitter and stratum requires a number of 222 * Getting the sync peer offset, jitter and stratum requires a number of
@@ -231,11 +234,20 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
231 * 4) Extract the offset, jitter and stratum value from the data[] 234 * 4) Extract the offset, jitter and stratum value from the data[]
232 * (it's ASCII) 235 * (it's ASCII)
233 */ 236 */
234 my_udp_connect(server_address, port, &conn); 237 int min_peer_sel = PEER_INCLUDED;
238 int num_candidates = 0;
239 void *tmp;
240 ntp_assoc_status_pair *peers = NULL;
241 int peer_offset = 0;
242 size_t peers_size = 0;
243 size_t npeers = 0;
244 int conn = -1;
245 my_udp_connect(config.server_address, config.port, &conn);
235 246
236 /* keep sending requests until the server stops setting the 247 /* keep sending requests until the server stops setting the
237 * REM_MORE bit, though usually this is only 1 packet. */ 248 * REM_MORE bit, though usually this is only 1 packet. */
238 do{ 249 ntp_control_message req;
250 do {
239 setup_control_request(&req, OP_READSTAT, 1); 251 setup_control_request(&req, OP_READSTAT, 1);
240 DBG(printf("sending READSTAT request")); 252 DBG(printf("sending READSTAT request"));
241 write(conn, &req, SIZEOF_NTPCM(req)); 253 write(conn, &req, SIZEOF_NTPCM(req));
@@ -243,63 +255,81 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
243 255
244 do { 256 do {
245 /* Attempt to read the largest size packet possible */ 257 /* Attempt to read the largest size packet possible */
246 req.count=htons(MAX_CM_SIZE); 258 req.count = htons(MAX_CM_SIZE);
247 DBG(printf("receiving READSTAT response")) 259 DBG(printf("receiving READSTAT response"))
248 if(read(conn, &req, SIZEOF_NTPCM(req)) == -1) 260 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) {
249 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 261 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
262 }
250 DBG(print_ntp_control_message(&req)); 263 DBG(print_ntp_control_message(&req));
251 /* discard obviously invalid packets */ 264 /* discard obviously invalid packets */
252 if (ntohs(req.count) > MAX_CM_SIZE) 265 if (ntohs(req.count) > MAX_CM_SIZE) {
253 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n"); 266 die(STATE_CRITICAL, "NTP CRITICAL: Invalid packet received from NTP server\n");
254 } while (!(req.op&OP_READSTAT && ntohs(req.seq) == 1)); 267 }
268 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
255 269
256 if (LI(req.flags) == LI_ALARM) li_alarm = true; 270 if (LI(req.flags) == LI_ALARM) {
271 li_alarm = true;
272 }
257 /* Each peer identifier is 4 bytes in the data section, which 273 /* Each peer identifier is 4 bytes in the data section, which
258 * we represent as a ntp_assoc_status_pair datatype. 274 * we represent as a ntp_assoc_status_pair datatype.
259 */ 275 */
260 peers_size+=ntohs(req.count); 276 peers_size += ntohs(req.count);
261 if((tmp=realloc(peers, peers_size)) == NULL) 277 if ((tmp = realloc(peers, peers_size)) == NULL) {
262 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); 278 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
263 peers=tmp; 279 }
264 memcpy((void*)((ptrdiff_t)peers+peer_offset), (void*)req.data, ntohs(req.count)); 280 peers = tmp;
265 npeers=peers_size/sizeof(ntp_assoc_status_pair); 281 memcpy((peers + peer_offset), (void *)req.data, ntohs(req.count));
266 peer_offset+=ntohs(req.count); 282 npeers = peers_size / sizeof(ntp_assoc_status_pair);
267 } while(req.op&REM_MORE); 283 peer_offset += ntohs(req.count);
284 } while (req.op & REM_MORE);
268 285
269 /* first, let's find out if we have a sync source, or if there are 286 /* first, let's find out if we have a sync source, or if there are
270 * at least some candidates. In the latter case we'll issue 287 * at least some candidates. In the latter case we'll issue
271 * a warning but go ahead with the check on them. */ 288 * a warning but go ahead with the check on them. */
272 for (i = 0; i < npeers; i++){ 289 for (size_t i = 0; i < npeers; i++) {
273 if(PEER_SEL(peers[i].status) >= PEER_TRUECHIMER){ 290 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
274 (*num_truechimers)++; 291 result.num_truechimers++;
275 if(PEER_SEL(peers[i].status) >= PEER_INCLUDED){ 292 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
276 num_candidates++; 293 num_candidates++;
277 if(PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE){ 294 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
278 syncsource_found = true; 295 syncsource_found = true;
279 min_peer_sel=PEER_SYNCSOURCE; 296 min_peer_sel = PEER_SYNCSOURCE;
280 } 297 }
281 } 298 }
282 } 299 }
283 } 300 }
284 if(verbose) printf("%d candidate peers available\n", num_candidates); 301
285 if(verbose && syncsource_found) printf("synchronization source found\n"); 302 if (verbose) {
286 if(! syncsource_found){ 303 printf("%d candidate peers available\n", num_candidates);
287 status = STATE_WARNING;
288 if(verbose) printf("warning: no synchronization source found\n");
289 } 304 }
290 if(li_alarm){ 305 if (verbose && syncsource_found) {
291 status = STATE_WARNING; 306 printf("synchronization source found\n");
292 if(verbose) printf("warning: LI_ALARM bit is set\n");
293 } 307 }
294 308
309 if (!syncsource_found) {
310 result.state = STATE_WARNING;
311 if (verbose) {
312 printf("warning: no synchronization source found\n");
313 }
314 }
315 if (li_alarm) {
316 result.state = STATE_WARNING;
317 if (verbose) {
318 printf("warning: LI_ALARM bit is set\n");
319 }
320 }
295 321
296 for (i = 0; i < npeers; i++){ 322 const char *getvar = "stratum,offset,jitter";
323 char *data;
324 for (size_t i = 0; i < npeers; i++) {
297 /* Only query this server if it is the current sync source */ 325 /* Only query this server if it is the current sync source */
298 /* If there's no sync.peer, query all candidates and use the best one */ 326 /* If there's no sync.peer, query all candidates and use the best one */
299 if (PEER_SEL(peers[i].status) >= min_peer_sel){ 327 if (PEER_SEL(peers[i].status) >= min_peer_sel) {
300 if(verbose) printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); 328 if (verbose) {
329 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
330 }
301 xasprintf(&data, ""); 331 xasprintf(&data, "");
302 do{ 332 do {
303 setup_control_request(&req, OP_READVAR, 2); 333 setup_control_request(&req, OP_READVAR, 2);
304 req.assoc = peers[i].assoc; 334 req.assoc = peers[i].assoc;
305 /* Putting the wanted variable names in the request 335 /* Putting the wanted variable names in the request
@@ -309,7 +339,7 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
309 */ 339 */
310 /* Older servers doesn't know what jitter is, so if we get an 340 /* Older servers doesn't know what jitter is, so if we get an
311 * error on the first pass we redo it with "dispersion" */ 341 * error on the first pass we redo it with "dispersion" */
312 strncpy(req.data, getvar, MAX_CM_SIZE-1); 342 strncpy(req.data, getvar, MAX_CM_SIZE - 1);
313 req.count = htons(strlen(getvar)); 343 req.count = htons(strlen(getvar));
314 DBG(printf("sending READVAR request...\n")); 344 DBG(printf("sending READVAR request...\n"));
315 write(conn, &req, SIZEOF_NTPCM(req)); 345 write(conn, &req, SIZEOF_NTPCM(req));
@@ -320,131 +350,151 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
320 DBG(printf("receiving READVAR response...\n")); 350 DBG(printf("receiving READVAR response...\n"));
321 read(conn, &req, SIZEOF_NTPCM(req)); 351 read(conn, &req, SIZEOF_NTPCM(req));
322 DBG(print_ntp_control_message(&req)); 352 DBG(print_ntp_control_message(&req));
323 } while (!(req.op&OP_READVAR && ntohs(req.seq) == 2)); 353 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2));
324 354
325 if(!(req.op&REM_ERROR)) 355 if (!(req.op & REM_ERROR)) {
326 xasprintf(&data, "%s%s", data, req.data); 356 xasprintf(&data, "%s%s", data, req.data);
327 } while(req.op&REM_MORE); 357 }
328 358 } while (req.op & REM_MORE);
329 if(req.op&REM_ERROR) { 359
330 if(strstr(getvar, "jitter")) { 360 if (req.op & REM_ERROR) {
331 if(verbose) printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with 'dispersion'...\n"); 361 if (strstr(getvar, "jitter")) {
362 if (verbose) {
363 printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with "
364 "'dispersion'...\n");
365 }
332 getvar = "stratum,offset,dispersion"; 366 getvar = "stratum,offset,dispersion";
333 i--; 367 i--;
334 continue; 368 continue;
335 } else if(strlen(getvar)) { 369 }
336 if(verbose) printf("Server didn't like dispersion either; will retrieve everything\n"); 370 if (strlen(getvar)) {
371 if (verbose) {
372 printf("Server didn't like dispersion either; will retrieve everything\n");
373 }
337 getvar = ""; 374 getvar = "";
338 i--; 375 i--;
339 continue; 376 continue;
340 } 377 }
341 } 378 }
342 379
343 if(verbose > 1) 380 if (verbose > 1) {
344 printf("Server responded: >>>%s<<<\n", data); 381 printf("Server responded: >>>%s<<<\n", data);
382 }
345 383
384 double tmp_offset = 0;
385 char *value;
386 char *nptr;
346 /* get the offset */ 387 /* get the offset */
347 if(verbose) 388 if (verbose) {
348 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc)); 389 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));
390 }
349 391
350 value = np_extract_ntpvar(data, "offset"); 392 value = np_extract_ntpvar(data, "offset");
351 nptr=NULL; 393 nptr = NULL;
352 /* Convert the value if we have one */ 394 /* Convert the value if we have one */
353 if(value != NULL) 395 if (value != NULL) {
354 tmp_offset = strtod(value, &nptr) / 1000; 396 tmp_offset = strtod(value, &nptr) / 1000;
397 }
355 /* If value is null or no conversion was performed */ 398 /* If value is null or no conversion was performed */
356 if(value == NULL || value==nptr) { 399 if (value == NULL || value == nptr) {
357 if(verbose) printf("error: unable to read server offset response.\n"); 400 if (verbose) {
401 printf("error: unable to read server offset response.\n");
402 }
358 } else { 403 } else {
359 if(verbose) printf("%.10g\n", tmp_offset); 404 if (verbose) {
360 if(*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) { 405 printf("%.10g\n", tmp_offset);
361 *offset = tmp_offset; 406 }
362 *offset_result = STATE_OK; 407 if (result.offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(result.offset)) {
408 result.offset = tmp_offset;
409 result.offset_result = STATE_OK;
363 } else { 410 } else {
364 /* Skip this one; move to the next */ 411 /* Skip this one; move to the next */
365 continue; 412 continue;
366 } 413 }
367 } 414 }
368 415
369 if(do_jitter) { 416 if (config.do_jitter) {
370 /* get the jitter */ 417 /* get the jitter */
371 if(verbose) { 418 if (verbose) {
372 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter", ntohs(peers[i].assoc)); 419 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter",
420 ntohs(peers[i].assoc));
373 } 421 }
374 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter"); 422 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter");
375 nptr=NULL; 423 nptr = NULL;
376 /* Convert the value if we have one */ 424 /* Convert the value if we have one */
377 if(value != NULL) 425 if (value != NULL) {
378 *jitter = strtod(value, &nptr); 426 result.jitter = strtod(value, &nptr);
427 }
379 /* If value is null or no conversion was performed */ 428 /* If value is null or no conversion was performed */
380 if(value == NULL || value==nptr) { 429 if (value == NULL || value == nptr) {
381 if(verbose) printf("error: unable to read server jitter/dispersion response.\n"); 430 if (verbose) {
382 *jitter = -1; 431 printf("error: unable to read server jitter/dispersion response.\n");
383 } else if(verbose) { 432 }
384 printf("%.10g\n", *jitter); 433 result.jitter = -1;
434 } else if (verbose) {
435 printf("%.10g\n", result.jitter);
385 } 436 }
386 } 437 }
387 438
388 if(do_stratum) { 439 if (config.do_stratum) {
389 /* get the stratum */ 440 /* get the stratum */
390 if(verbose) { 441 if (verbose) {
391 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc)); 442 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
392 } 443 }
393 value = np_extract_ntpvar(data, "stratum"); 444 value = np_extract_ntpvar(data, "stratum");
394 nptr=NULL; 445 nptr = NULL;
395 /* Convert the value if we have one */ 446 /* Convert the value if we have one */
396 if(value != NULL) 447 if (value != NULL) {
397 *stratum = strtol(value, &nptr, 10); 448 result.stratum = strtol(value, &nptr, 10);
398 if(value == NULL || value==nptr) { 449 }
399 if(verbose) printf("error: unable to read server stratum response.\n"); 450 if (value == NULL || value == nptr) {
400 *stratum = -1; 451 if (verbose) {
452 printf("error: unable to read server stratum response.\n");
453 }
454 result.stratum = -1;
401 } else { 455 } else {
402 if(verbose) printf("%i\n", *stratum); 456 if (verbose) {
457 printf("%li\n", result.stratum);
458 }
403 } 459 }
404 } 460 }
405 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */ 461 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
406 } /* for (i = 0; i < npeers; i++) */ 462 } /* for (i = 0; i < npeers; i++) */
407 463
408 close(conn); 464 close(conn);
409 if(peers!=NULL) free(peers); 465 if (peers != NULL) {
466 free(peers);
467 }
410 468
411 return status; 469 return result;
412} 470}
413 471
414int process_arguments(int argc, char **argv){ 472check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
415 int c;
416 int option=0;
417 static struct option longopts[] = { 473 static struct option longopts[] = {
418 {"version", no_argument, 0, 'V'}, 474 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'},
419 {"help", no_argument, 0, 'h'}, 475 {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'},
420 {"verbose", no_argument, 0, 'v'}, 476 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {"swarn", required_argument, 0, 'W'},
421 {"use-ipv4", no_argument, 0, '4'}, 477 {"scrit", required_argument, 0, 'C'}, {"jwarn", required_argument, 0, 'j'}, {"jcrit", required_argument, 0, 'k'},
422 {"use-ipv6", no_argument, 0, '6'}, 478 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'},
423 {"quiet", no_argument, 0, 'q'}, 479 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}};
424 {"warning", required_argument, 0, 'w'}, 480
425 {"critical", required_argument, 0, 'c'}, 481 if (argc < 2) {
426 {"swarn", required_argument, 0, 'W'}, 482 usage("\n");
427 {"scrit", required_argument, 0, 'C'}, 483 }
428 {"jwarn", required_argument, 0, 'j'},
429 {"jcrit", required_argument, 0, 'k'},
430 {"twarn", required_argument, 0, 'm'},
431 {"tcrit", required_argument, 0, 'n'},
432 {"timeout", required_argument, 0, 't'},
433 {"hostname", required_argument, 0, 'H'},
434 {"port", required_argument, 0, 'p'},
435 {0, 0, 0, 0}
436 };
437
438 484
439 if (argc < 2) 485 check_ntp_peer_config_wrapper result = {
440 usage ("\n"); 486 .errorcode = OK,
487 .config = check_ntp_peer_config_init(),
488 };
441 489
442 while (true) { 490 while (true) {
443 c = getopt_long (argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option); 491 int option = 0;
444 if (c == -1 || c == EOF || c == 1) 492 int option_char = getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option);
493 if (option_char == -1 || option_char == EOF || option_char == 1) {
445 break; 494 break;
495 }
446 496
447 switch (c) { 497 switch (option_char) {
448 case 'h': 498 case 'h':
449 print_help(); 499 print_help();
450 exit(STATE_UNKNOWN); 500 exit(STATE_UNKNOWN);
@@ -457,48 +507,49 @@ int process_arguments(int argc, char **argv){
457 verbose++; 507 verbose++;
458 break; 508 break;
459 case 'q': 509 case 'q':
460 quiet = true; 510 result.config.quiet = true;
461 break; 511 break;
462 case 'w': 512 case 'w':
463 owarn = optarg; 513 result.config.owarn = optarg;
464 break; 514 break;
465 case 'c': 515 case 'c':
466 ocrit = optarg; 516 result.config.ocrit = optarg;
467 break; 517 break;
468 case 'W': 518 case 'W':
469 do_stratum = true; 519 result.config.do_stratum = true;
470 swarn = optarg; 520 result.config.swarn = optarg;
471 break; 521 break;
472 case 'C': 522 case 'C':
473 do_stratum = true; 523 result.config.do_stratum = true;
474 scrit = optarg; 524 result.config.scrit = optarg;
475 break; 525 break;
476 case 'j': 526 case 'j':
477 do_jitter = true; 527 result.config.do_jitter = true;
478 jwarn = optarg; 528 result.config.jwarn = optarg;
479 break; 529 break;
480 case 'k': 530 case 'k':
481 do_jitter = true; 531 result.config.do_jitter = true;
482 jcrit = optarg; 532 result.config.jcrit = optarg;
483 break; 533 break;
484 case 'm': 534 case 'm':
485 do_truechimers = true; 535 result.config.do_truechimers = true;
486 twarn = optarg; 536 result.config.twarn = optarg;
487 break; 537 break;
488 case 'n': 538 case 'n':
489 do_truechimers = true; 539 result.config.do_truechimers = true;
490 tcrit = optarg; 540 result.config.tcrit = optarg;
491 break; 541 break;
492 case 'H': 542 case 'H':
493 if(!is_host(optarg)) 543 if (!is_host(optarg)) {
494 usage2(_("Invalid hostname/address"), optarg); 544 usage2(_("Invalid hostname/address"), optarg);
495 server_address = strdup(optarg); 545 }
546 result.config.server_address = strdup(optarg);
496 break; 547 break;
497 case 'p': 548 case 'p':
498 port=atoi(optarg); 549 result.config.port = atoi(optarg);
499 break; 550 break;
500 case 't': 551 case 't':
501 socket_timeout=atoi(optarg); 552 socket_timeout = atoi(optarg);
502 break; 553 break;
503 case '4': 554 case '4':
504 address_family = AF_INET; 555 address_family = AF_INET;
@@ -507,222 +558,220 @@ int process_arguments(int argc, char **argv){
507#ifdef USE_IPV6 558#ifdef USE_IPV6
508 address_family = AF_INET6; 559 address_family = AF_INET6;
509#else 560#else
510 usage4 (_("IPv6 support not available")); 561 usage4(_("IPv6 support not available"));
511#endif 562#endif
512 break; 563 break;
513 case '?': 564 case '?':
514 /* print short usage statement if args not parsable */ 565 /* print short usage statement if args not parsable */
515 usage5 (); 566 usage5();
516 break; 567 break;
517 } 568 }
518 } 569 }
519 570
520 if(server_address == NULL){ 571 if (result.config.server_address == NULL) {
521 usage4(_("Hostname was not supplied")); 572 usage4(_("Hostname was not supplied"));
522 } 573 }
523 574
524 return 0; 575 set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
525} 576 set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit);
577 set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit);
578 set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit);
526 579
527char *perfd_offset (double offset) 580 return result;
528{
529 return fperfdata ("offset", offset, "s",
530 true, offset_thresholds->warning->end,
531 true, offset_thresholds->critical->end,
532 false, 0, false, 0);
533} 581}
534 582
535char *perfd_jitter (double jitter) 583char *perfd_offset(double offset, thresholds *offset_thresholds) {
536{ 584 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
537 return fperfdata ("jitter", jitter, "", 585 0);
538 do_jitter, jitter_thresholds->warning->end,
539 do_jitter, jitter_thresholds->critical->end,
540 true, 0, false, 0);
541} 586}
542 587
543char *perfd_stratum (int stratum) 588char *perfd_jitter(double jitter, bool do_jitter, thresholds *jitter_thresholds) {
544{ 589 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter, jitter_thresholds->critical->end, true, 0,
545 return perfdata ("stratum", stratum, "", 590 false, 0);
546 do_stratum, (int)stratum_thresholds->warning->end,
547 do_stratum, (int)stratum_thresholds->critical->end,
548 true, 0, true, 16);
549} 591}
550 592
551char *perfd_truechimers (int num_truechimers) 593char *perfd_stratum(int stratum, bool do_stratum, thresholds *stratum_thresholds) {
552{ 594 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end, do_stratum,
553 return perfdata ("truechimers", num_truechimers, "", 595 (int)stratum_thresholds->critical->end, true, 0, true, 16);
554 do_truechimers, (int)truechimer_thresholds->warning->end,
555 do_truechimers, (int)truechimer_thresholds->critical->end,
556 true, 0, false, 0);
557} 596}
558 597
559int main(int argc, char *argv[]){ 598char *perfd_truechimers(int num_truechimers, const bool do_truechimers, thresholds *truechimer_thresholds) {
560 int result, offset_result, stratum, num_truechimers; 599 return perfdata("truechimers", num_truechimers, "", do_truechimers, (int)truechimer_thresholds->warning->end, do_truechimers,
561 double offset=0, jitter=0; 600 (int)truechimer_thresholds->critical->end, true, 0, false, 0);
562 char *result_line, *perfdata_line; 601}
563 602
564 setlocale (LC_ALL, ""); 603int main(int argc, char *argv[]) {
565 bindtextdomain (PACKAGE, LOCALEDIR); 604 setlocale(LC_ALL, "");
566 textdomain (PACKAGE); 605 bindtextdomain(PACKAGE, LOCALEDIR);
606 textdomain(PACKAGE);
567 607
568 /* Parse extra opts if any */ 608 /* Parse extra opts if any */
569 argv=np_extra_opts (&argc, argv, progname); 609 argv = np_extra_opts(&argc, argv, progname);
570 610
571 if (process_arguments (argc, argv) == ERROR) 611 check_ntp_peer_config_wrapper tmp_config = process_arguments(argc, argv);
572 usage4 (_("Could not parse arguments"));
573 612
574 set_thresholds(&offset_thresholds, owarn, ocrit); 613 if (tmp_config.errorcode == ERROR) {
575 set_thresholds(&jitter_thresholds, jwarn, jcrit); 614 usage4(_("Could not parse arguments"));
576 set_thresholds(&stratum_thresholds, swarn, scrit); 615 }
577 set_thresholds(&truechimer_thresholds, twarn, tcrit); 616
617 const check_ntp_peer_config config = tmp_config.config;
578 618
579 /* initialize alarm signal handling */ 619 /* initialize alarm signal handling */
580 signal (SIGALRM, socket_timeout_alarm_handler); 620 signal(SIGALRM, socket_timeout_alarm_handler);
581 621
582 /* set socket timeout */ 622 /* set socket timeout */
583 alarm (socket_timeout); 623 alarm(socket_timeout);
584 624
585 /* This returns either OK or WARNING (See comment preceding ntp_request) */ 625 /* This returns either OK or WARNING (See comment preceding ntp_request) */
586 result = ntp_request(&offset, &offset_result, &jitter, &stratum, &num_truechimers); 626 ntp_request_result ntp_res = ntp_request(config);
627 mp_state_enum result = STATE_UNKNOWN;
587 628
588 if(offset_result == STATE_UNKNOWN) { 629 if (ntp_res.offset_result == STATE_UNKNOWN) {
589 /* if there's no sync peer (this overrides ntp_request output): */ 630 /* if there's no sync peer (this overrides ntp_request output): */
590 result = (quiet ? STATE_UNKNOWN : STATE_CRITICAL); 631 result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL);
591 } else { 632 } else {
592 /* Be quiet if there's no candidates either */ 633 /* Be quiet if there's no candidates either */
593 if (quiet && result == STATE_WARNING) 634 if (config.quiet && result == STATE_WARNING) {
594 result = STATE_UNKNOWN; 635 result = STATE_UNKNOWN;
595 result = max_state_alt(result, get_status(fabs(offset), offset_thresholds)); 636 }
637 result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds));
596 } 638 }
597 639
598 int oresult = result; 640 mp_state_enum oresult = result;
599 641 mp_state_enum tresult = STATE_UNKNOWN;
600 642
601 int tresult = STATE_UNKNOWN; 643 if (config.do_truechimers) {
602 644 tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds);
603 if(do_truechimers) {
604 tresult = get_status(num_truechimers, truechimer_thresholds);
605 result = max_state_alt(result, tresult); 645 result = max_state_alt(result, tresult);
606 } 646 }
607 647
648 mp_state_enum sresult = STATE_UNKNOWN;
608 649
609 int sresult = STATE_UNKNOWN; 650 if (config.do_stratum) {
610 651 sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds);
611 if(do_stratum) {
612 sresult = get_status(stratum, stratum_thresholds);
613 result = max_state_alt(result, sresult); 652 result = max_state_alt(result, sresult);
614 } 653 }
615 654
655 mp_state_enum jresult = STATE_UNKNOWN;
616 656
617 int jresult = STATE_UNKNOWN; 657 if (config.do_jitter) {
618 658 jresult = get_status(ntp_res.jitter, config.jitter_thresholds);
619 if(do_jitter) {
620 jresult = get_status(jitter, jitter_thresholds);
621 result = max_state_alt(result, jresult); 659 result = max_state_alt(result, jresult);
622 } 660 }
623 661
662 char *result_line;
624 switch (result) { 663 switch (result) {
625 case STATE_CRITICAL : 664 case STATE_CRITICAL:
626 xasprintf(&result_line, _("NTP CRITICAL:")); 665 xasprintf(&result_line, _("NTP CRITICAL:"));
627 break; 666 break;
628 case STATE_WARNING : 667 case STATE_WARNING:
629 xasprintf(&result_line, _("NTP WARNING:")); 668 xasprintf(&result_line, _("NTP WARNING:"));
630 break; 669 break;
631 case STATE_OK : 670 case STATE_OK:
632 xasprintf(&result_line, _("NTP OK:")); 671 xasprintf(&result_line, _("NTP OK:"));
633 break; 672 break;
634 default : 673 default:
635 xasprintf(&result_line, _("NTP UNKNOWN:")); 674 xasprintf(&result_line, _("NTP UNKNOWN:"));
636 break; 675 break;
637 } 676 }
638 if(!syncsource_found) 677
678 if (!syncsource_found) {
639 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized")); 679 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
640 else if(li_alarm) 680 } else if (li_alarm) {
641 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set")); 681 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));
682 }
642 683
643 if(offset_result == STATE_UNKNOWN){ 684 char *perfdata_line;
685 if (ntp_res.offset_result == STATE_UNKNOWN) {
644 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 686 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
645 xasprintf(&perfdata_line, ""); 687 xasprintf(&perfdata_line, "");
646 } else if (oresult == STATE_WARNING) { 688 } else if (oresult == STATE_WARNING) {
647 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), offset); 689 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"), ntp_res.offset);
648 } else if (oresult == STATE_CRITICAL) { 690 } else if (oresult == STATE_CRITICAL) {
649 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), offset); 691 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"), ntp_res.offset);
650 } else { 692 } else {
651 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 693 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset);
652 } 694 }
653 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 695 xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
654 696
655 if (do_jitter) { 697 if (config.do_jitter) {
656 if (jresult == STATE_WARNING) { 698 if (jresult == STATE_WARNING) {
657 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter); 699 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter);
658 } else if (jresult == STATE_CRITICAL) { 700 } else if (jresult == STATE_CRITICAL) {
659 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter); 701 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
660 } else { 702 } else {
661 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter); 703 xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
662 } 704 }
663 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter)); 705 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds));
664 } 706 }
665 if (do_stratum) { 707
708 if (config.do_stratum) {
666 if (sresult == STATE_WARNING) { 709 if (sresult == STATE_WARNING) {
667 xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum); 710 xasprintf(&result_line, "%s, stratum=%l (WARNING)", result_line, ntp_res.stratum);
668 } else if (sresult == STATE_CRITICAL) { 711 } else if (sresult == STATE_CRITICAL) {
669 xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum); 712 xasprintf(&result_line, "%s, stratum=%l (CRITICAL)", result_line, ntp_res.stratum);
670 } else { 713 } else {
671 xasprintf(&result_line, "%s, stratum=%i", result_line, stratum); 714 xasprintf(&result_line, "%s, stratum=%l", result_line, ntp_res.stratum);
672 } 715 }
673 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(stratum)); 716 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds));
674 } 717 }
675 if (do_truechimers) { 718
719 if (config.do_truechimers) {
676 if (tresult == STATE_WARNING) { 720 if (tresult == STATE_WARNING) {
677 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, num_truechimers); 721 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, ntp_res.num_truechimers);
678 } else if (tresult == STATE_CRITICAL) { 722 } else if (tresult == STATE_CRITICAL) {
679 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, num_truechimers); 723 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, ntp_res.num_truechimers);
680 } else { 724 } else {
681 xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers); 725 xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
682 } 726 }
683 xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_truechimers(num_truechimers)); 727 xasprintf(&perfdata_line, "%s %s", perfdata_line,
728 perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers, config.truechimer_thresholds));
684 } 729 }
730
685 printf("%s|%s\n", result_line, perfdata_line); 731 printf("%s|%s\n", result_line, perfdata_line);
686 732
687 if(server_address!=NULL) free(server_address); 733 if (config.server_address != NULL) {
688 return result; 734 free(config.server_address);
735 }
736
737 exit(result);
689} 738}
690 739
691void print_help(void){ 740void print_help(void) {
692 print_revision(progname, NP_VERSION); 741 print_revision(progname, NP_VERSION);
693 742
694 printf ("Copyright (c) 2006 Sean Finney\n"); 743 printf("Copyright (c) 2006 Sean Finney\n");
695 printf (COPYRIGHT, copyright, email); 744 printf(COPYRIGHT, copyright, email);
696 745
697 printf ("%s\n", _("This plugin checks the selected ntp server")); 746 printf("%s\n", _("This plugin checks the selected ntp server"));
698 747
699 printf ("\n\n"); 748 printf("\n\n");
700 749
701 print_usage(); 750 print_usage();
702 printf (UT_HELP_VRSN); 751 printf(UT_HELP_VRSN);
703 printf (UT_EXTRA_OPTS); 752 printf(UT_EXTRA_OPTS);
704 printf (UT_IPv46); 753 printf(UT_IPv46);
705 printf (UT_HOST_PORT, 'p', "123"); 754 printf(UT_HOST_PORT, 'p', "123");
706 printf (" %s\n", "-q, --quiet"); 755 printf(" %s\n", "-q, --quiet");
707 printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized")); 756 printf(" %s\n", _("Returns UNKNOWN instead of CRITICAL or WARNING if server isn't synchronized"));
708 printf (" %s\n", "-w, --warning=THRESHOLD"); 757 printf(" %s\n", "-w, --warning=THRESHOLD");
709 printf (" %s\n", _("Offset to result in warning status (seconds)")); 758 printf(" %s\n", _("Offset to result in warning status (seconds)"));
710 printf (" %s\n", "-c, --critical=THRESHOLD"); 759 printf(" %s\n", "-c, --critical=THRESHOLD");
711 printf (" %s\n", _("Offset to result in critical status (seconds)")); 760 printf(" %s\n", _("Offset to result in critical status (seconds)"));
712 printf (" %s\n", "-W, --swarn=THRESHOLD"); 761 printf(" %s\n", "-W, --swarn=THRESHOLD");
713 printf (" %s\n", _("Warning threshold for stratum of server's synchronization peer")); 762 printf(" %s\n", _("Warning threshold for stratum of server's synchronization peer"));
714 printf (" %s\n", "-C, --scrit=THRESHOLD"); 763 printf(" %s\n", "-C, --scrit=THRESHOLD");
715 printf (" %s\n", _("Critical threshold for stratum of server's synchronization peer")); 764 printf(" %s\n", _("Critical threshold for stratum of server's synchronization peer"));
716 printf (" %s\n", "-j, --jwarn=THRESHOLD"); 765 printf(" %s\n", "-j, --jwarn=THRESHOLD");
717 printf (" %s\n", _("Warning threshold for jitter")); 766 printf(" %s\n", _("Warning threshold for jitter"));
718 printf (" %s\n", "-k, --jcrit=THRESHOLD"); 767 printf(" %s\n", "-k, --jcrit=THRESHOLD");
719 printf (" %s\n", _("Critical threshold for jitter")); 768 printf(" %s\n", _("Critical threshold for jitter"));
720 printf (" %s\n", "-m, --twarn=THRESHOLD"); 769 printf(" %s\n", "-m, --twarn=THRESHOLD");
721 printf (" %s\n", _("Warning threshold for number of usable time sources (\"truechimers\")")); 770 printf(" %s\n", _("Warning threshold for number of usable time sources (\"truechimers\")"));
722 printf (" %s\n", "-n, --tcrit=THRESHOLD"); 771 printf(" %s\n", "-n, --tcrit=THRESHOLD");
723 printf (" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")")); 772 printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")"));
724 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 773 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
725 printf (UT_VERBOSE); 774 printf(UT_VERBOSE);
726 775
727 printf("\n"); 776 printf("\n");
728 printf("%s\n", _("This plugin checks an NTP server independent of any commandline")); 777 printf("%s\n", _("This plugin checks an NTP server independent of any commandline"));
@@ -751,13 +800,11 @@ void print_help(void){
751 printf(" %s\n", _("Check only stratum:")); 800 printf(" %s\n", _("Check only stratum:"));
752 printf(" %s\n", ("./check_ntp_peer -H ntpserv -W 4 -C 6")); 801 printf(" %s\n", ("./check_ntp_peer -H ntpserv -W 4 -C 6"));
753 802
754 printf (UT_SUPPORT); 803 printf(UT_SUPPORT);
755} 804}
756 805
757void 806void print_usage(void) {
758print_usage(void) 807 printf("%s\n", _("Usage:"));
759{
760 printf ("%s\n", _("Usage:"));
761 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-W <warn>] [-C <crit>]\n", progname); 808 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-W <warn>] [-C <crit>]\n", progname);
762 printf(" [-j <warn>] [-k <crit>] [-v verbose]\n"); 809 printf(" [-j <warn>] [-k <crit>] [-v verbose]\n");
763} 810}
diff --git a/plugins/check_ntp_peer.d/config.h b/plugins/check_ntp_peer.d/config.h
new file mode 100644
index 00000000..00e6b05d
--- /dev/null
+++ b/plugins/check_ntp_peer.d/config.h
@@ -0,0 +1,67 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7enum {
8 DEFAULT_NTP_PORT = 123,
9};
10
11typedef struct {
12 char *server_address;
13 int port;
14
15 bool quiet;
16
17 // truechimer stuff
18 bool do_truechimers;
19 char *twarn;
20 char *tcrit;
21 thresholds *truechimer_thresholds;
22
23 char *owarn;
24 char *ocrit;
25 thresholds *offset_thresholds;
26
27 // stratum stuff
28 bool do_stratum;
29 char *swarn;
30 char *scrit;
31 thresholds *stratum_thresholds;
32
33 // jitter stuff
34 bool do_jitter;
35 char *jwarn;
36 char *jcrit;
37 thresholds *jitter_thresholds;
38
39} check_ntp_peer_config;
40
41check_ntp_peer_config check_ntp_peer_config_init() {
42 check_ntp_peer_config tmp = {
43 .server_address = NULL,
44 .port = DEFAULT_NTP_PORT,
45
46 .quiet = false,
47 .do_truechimers = false,
48 .twarn = "0:",
49 .tcrit = "0:",
50 .truechimer_thresholds = NULL,
51
52 .owarn = "60",
53 .ocrit = "120",
54 .offset_thresholds = NULL,
55
56 .do_stratum = false,
57 .swarn = "-1:16",
58 .scrit = "-1:16",
59 .stratum_thresholds = NULL,
60
61 .do_jitter = false,
62 .jwarn = "-1:5000",
63 .jcrit = "-1:10000",
64 .jitter_thresholds = NULL,
65 };
66 return tmp;
67}
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
index b2e16556..31162883 100644
--- a/plugins/check_ntp_time.c
+++ b/plugins/check_ntp_time.c
@@ -1,63 +1,64 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ntp_time plugin 3 * Monitoring check_ntp_time plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2006 Sean Finney <seanius@seanius.net> 6 * Copyright (c) 2006 Sean Finney <seanius@seanius.net>
7* Copyright (c) 2006-2008 Monitoring Plugins Development Team 7 * Copyright (c) 2006-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_ntp_time plugin 11 * This file contains the check_ntp_time plugin
12* 12 *
13* This plugin checks the clock offset between the local host and a 13 * This plugin checks the clock offset between the local host and a
14* remote NTP server. It is independent of any commandline programs or 14 * remote NTP server. It is independent of any commandline programs or
15* external libraries. 15 * external libraries.
16* 16 *
17* If you'd rather want to monitor an NTP server, please use 17 * If you'd rather want to monitor an NTP server, please use
18* check_ntp_peer. 18 * check_ntp_peer.
19* 19 *
20* 20 *
21* This program is free software: you can redistribute it and/or modify 21 * This program is free software: you can redistribute it and/or modify
22* it under the terms of the GNU General Public License as published by 22 * it under the terms of the GNU General Public License as published by
23* the Free Software Foundation, either version 3 of the License, or 23 * the Free Software Foundation, either version 3 of the License, or
24* (at your option) any later version. 24 * (at your option) any later version.
25* 25 *
26* This program is distributed in the hope that it will be useful, 26 * This program is distributed in the hope that it will be useful,
27* but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29* GNU General Public License for more details. 29 * GNU General Public License for more details.
30* 30 *
31* You should have received a copy of the GNU General Public License 31 * You should have received a copy of the GNU General Public License
32* along with this program. If not, see <http://www.gnu.org/licenses/>. 32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33* 33 *
34* 34 *
35*****************************************************************************/ 35 *****************************************************************************/
36 36
37const char *progname = "check_ntp_time"; 37const char *progname = "check_ntp_time";
38const char *copyright = "2006-2008"; 38const char *copyright = "2006-2024";
39const char *email = "devel@monitoring-plugins.org"; 39const char *email = "devel@monitoring-plugins.org";
40 40
41#include "common.h" 41#include "common.h"
42#include "netutils.h" 42#include "netutils.h"
43#include "utils.h" 43#include "utils.h"
44#include "states.h"
45#include "thresholds.h"
46#include "check_ntp_time.d/config.h"
44 47
45static char *server_address=NULL; 48static int verbose = 0;
46static char *port="123";
47static int verbose=0;
48static bool quiet = false;
49static char *owarn="60";
50static char *ocrit="120";
51static int time_offset=0;
52 49
53int process_arguments (int, char **); 50typedef struct {
54thresholds *offset_thresholds = NULL; 51 int errorcode;
55void print_help (void); 52 check_ntp_time_config config;
56void print_usage (void); 53} check_ntp_time_config_wrapper;
54static check_ntp_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
55
56static void print_help(void);
57void print_usage(void);
57 58
58/* number of times to perform each request to get a good average. */ 59/* number of times to perform each request to get a good average. */
59#ifndef AVG_NUM 60#ifndef AVG_NUM
60#define AVG_NUM 4 61# define AVG_NUM 4
61#endif 62#endif
62 63
63/* max size of control message data */ 64/* max size of control message data */
@@ -65,17 +66,17 @@ void print_usage (void);
65 66
66/* this structure holds everything in an ntp request/response as per rfc1305 */ 67/* this structure holds everything in an ntp request/response as per rfc1305 */
67typedef struct { 68typedef struct {
68 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 69 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
69 uint8_t stratum; /* clock stratum */ 70 uint8_t stratum; /* clock stratum */
70 int8_t poll; /* polling interval */ 71 int8_t poll; /* polling interval */
71 int8_t precision; /* precision of the local clock */ 72 int8_t precision; /* precision of the local clock */
72 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */ 73 int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */
73 uint32_t rtdisp; /* like above, but for max err to primary src */ 74 uint32_t rtdisp; /* like above, but for max err to primary src */
74 uint32_t refid; /* ref clock identifier */ 75 uint32_t refid; /* ref clock identifier */
75 uint64_t refts; /* reference timestamp. local time local clock */ 76 uint64_t refts; /* reference timestamp. local time local clock */
76 uint64_t origts; /* time at which request departed client */ 77 uint64_t origts; /* time at which request departed client */
77 uint64_t rxts; /* time at which request arrived at server */ 78 uint64_t rxts; /* time at which request arrived at server */
78 uint64_t txts; /* time at which request departed server */ 79 uint64_t txts; /* time at which request departed server */
79} ntp_message; 80} ntp_message;
80 81
81/* this structure holds data about results from querying offset from a peer */ 82/* this structure holds data about results from querying offset from a peer */
@@ -86,43 +87,55 @@ typedef struct {
86 double rtdelay; /* converted from the ntp_message */ 87 double rtdelay; /* converted from the ntp_message */
87 double rtdisp; /* converted from the ntp_message */ 88 double rtdisp; /* converted from the ntp_message */
88 double offset[AVG_NUM]; /* offsets from each response */ 89 double offset[AVG_NUM]; /* offsets from each response */
89 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ 90 uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
90} ntp_server_results; 91} ntp_server_results;
91 92
92/* bits 1,2 are the leap indicator */ 93/* bits 1,2 are the leap indicator */
93#define LI_MASK 0xc0 94#define LI_MASK 0xc0
94#define LI(x) ((x&LI_MASK)>>6) 95#define LI(x) ((x & LI_MASK) >> 6)
95#define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0) 96#define LI_SET(x, y) \
97 do { \
98 x |= ((y << 6) & LI_MASK); \
99 } while (0)
96/* and these are the values of the leap indicator */ 100/* and these are the values of the leap indicator */
97#define LI_NOWARNING 0x00 101#define LI_NOWARNING 0x00
98#define LI_EXTRASEC 0x01 102#define LI_EXTRASEC 0x01
99#define LI_MISSINGSEC 0x02 103#define LI_MISSINGSEC 0x02
100#define LI_ALARM 0x03 104#define LI_ALARM 0x03
101/* bits 3,4,5 are the ntp version */ 105/* bits 3,4,5 are the ntp version */
102#define VN_MASK 0x38 106#define VN_MASK 0x38
103#define VN(x) ((x&VN_MASK)>>3) 107#define VN(x) ((x & VN_MASK) >> 3)
104#define VN_SET(x,y) do{ x |= ((y<<3)&VN_MASK); }while(0) 108#define VN_SET(x, y) \
109 do { \
110 x |= ((y << 3) & VN_MASK); \
111 } while (0)
105#define VN_RESERVED 0x02 112#define VN_RESERVED 0x02
106/* bits 6,7,8 are the ntp mode */ 113/* bits 6,7,8 are the ntp mode */
107#define MODE_MASK 0x07 114#define MODE_MASK 0x07
108#define MODE(x) (x&MODE_MASK) 115#define MODE(x) (x & MODE_MASK)
109#define MODE_SET(x,y) do{ x |= (y&MODE_MASK); }while(0) 116#define MODE_SET(x, y) \
117 do { \
118 x |= (y & MODE_MASK); \
119 } while (0)
110/* here are some values */ 120/* here are some values */
111#define MODE_CLIENT 0x03 121#define MODE_CLIENT 0x03
112#define MODE_CONTROLMSG 0x06 122#define MODE_CONTROLMSG 0x06
113/* In control message, bits 8-10 are R,E,M bits */ 123/* In control message, bits 8-10 are R,E,M bits */
114#define REM_MASK 0xe0 124#define REM_MASK 0xe0
115#define REM_RESP 0x80 125#define REM_RESP 0x80
116#define REM_ERROR 0x40 126#define REM_ERROR 0x40
117#define REM_MORE 0x20 127#define REM_MORE 0x20
118/* In control message, bits 11 - 15 are opcode */ 128/* In control message, bits 11 - 15 are opcode */
119#define OP_MASK 0x1f 129#define OP_MASK 0x1f
120#define OP_SET(x,y) do{ x |= (y&OP_MASK); }while(0) 130#define OP_SET(x, y) \
131 do { \
132 x |= (y & OP_MASK); \
133 } while (0)
121#define OP_READSTAT 0x01 134#define OP_READSTAT 0x01
122#define OP_READVAR 0x02 135#define OP_READVAR 0x02
123/* In peer status bytes, bits 6,7,8 determine clock selection status */ 136/* In peer status bytes, bits 6,7,8 determine clock selection status */
124#define PEER_SEL(x) ((ntohs(x)>>8)&0x07) 137#define PEER_SEL(x) ((ntohs(x) >> 8) & 0x07)
125#define PEER_INCLUDED 0x04 138#define PEER_INCLUDED 0x04
126#define PEER_SYNCSOURCE 0x06 139#define PEER_SYNCSOURCE 0x06
127 140
128/** 141/**
@@ -136,129 +149,137 @@ typedef struct {
136 149
137/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point" 150/* macros to access the left/right 16 bits of a 32-bit ntp "fixed point"
138 number. note that these can be used as lvalues too */ 151 number. note that these can be used as lvalues too */
139#define L16(x) (((uint16_t*)&x)[0]) 152#define L16(x) (((uint16_t *)&x)[0])
140#define R16(x) (((uint16_t*)&x)[1]) 153#define R16(x) (((uint16_t *)&x)[1])
141/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point" 154/* macros to access the left/right 32 bits of a 64-bit ntp "fixed point"
142 number. these too can be used as lvalues */ 155 number. these too can be used as lvalues */
143#define L32(x) (((uint32_t*)&x)[0]) 156#define L32(x) (((uint32_t *)&x)[0])
144#define R32(x) (((uint32_t*)&x)[1]) 157#define R32(x) (((uint32_t *)&x)[1])
145 158
146/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */ 159/* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */
147#define EPOCHDIFF 0x83aa7e80UL 160#define EPOCHDIFF 0x83aa7e80UL
148 161
149/* extract a 32-bit ntp fixed point number into a double */ 162/* extract a 32-bit ntp fixed point number into a double */
150#define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0) 163#define NTP32asDOUBLE(x) (ntohs(L16(x)) + ((double)ntohs(R16(x)) / 65536.0))
151 164
152/* likewise for a 64-bit ntp fp number */ 165/* likewise for a 64-bit ntp fp number */
153#define NTP64asDOUBLE(n) (double)(((uint64_t)n)?\ 166#define NTP64asDOUBLE(n) \
154 (ntohl(L32(n))-EPOCHDIFF) + \ 167 (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) : 0)
155 (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\
156 0)
157 168
158/* convert a struct timeval to a double */ 169/* convert a struct timeval to a double */
159#define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec)) 170#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec))
160 171
161/* convert an ntp 64-bit fp number to a struct timeval */ 172/* convert an ntp 64-bit fp number to a struct timeval */
162#define NTP64toTV(n,t) \ 173#define NTP64toTV(n, t) \
163 do{ if(!n) t.tv_sec = t.tv_usec = 0; \ 174 do { \
164 else { \ 175 if (!n) \
165 t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \ 176 t.tv_sec = t.tv_usec = 0; \
166 t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \ 177 else { \
167 } \ 178 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \
168 }while(0) 179 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \
180 } \
181 } while (0)
169 182
170/* convert a struct timeval to an ntp 64-bit fp number */ 183/* convert a struct timeval to an ntp 64-bit fp number */
171#define TVtoNTP64(t,n) \ 184#define TVtoNTP64(t, n) \
172 do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \ 185 do { \
173 else { \ 186 if (!t.tv_usec && !t.tv_sec) \
174 L32(n)=htonl(t.tv_sec + EPOCHDIFF); \ 187 n = 0x0UL; \
175 R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \ 188 else { \
176 } \ 189 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \
177 } while(0) 190 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \
191 } \
192 } while (0)
178 193
179/* NTP control message header is 12 bytes, plus any data in the data 194/* NTP control message header is 12 bytes, plus any data in the data
180 * field, plus null padding to the nearest 32-bit boundary per rfc. 195 * field, plus null padding to the nearest 32-bit boundary per rfc.
181 */ 196 */
182#define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((m.count)?4-(ntohs(m.count)%4):0)) 197#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((m.count) ? 4 - (ntohs(m.count) % 4) : 0))
183 198
184/* finally, a little helper or two for debugging: */ 199/* finally, a little helper or two for debugging: */
185#define DBG(x) do{if(verbose>1){ x; }}while(0); 200#define DBG(x) \
186#define PRINTSOCKADDR(x) \ 201 do { \
187 do{ \ 202 if (verbose > 1) { \
188 printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\ 203 x; \
189 }while(0); 204 } \
205 } while (0);
206#define PRINTSOCKADDR(x) \
207 do { \
208 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
209 } while (0);
190 210
191/* calculate the offset of the local clock */ 211/* calculate the offset of the local clock */
192static inline double calc_offset(const ntp_message *m, const struct timeval *t){ 212static inline double calc_offset(const ntp_message *message, const struct timeval *time_value) {
193 double client_tx, peer_rx, peer_tx, client_rx; 213 double client_tx = NTP64asDOUBLE(message->origts);
194 client_tx = NTP64asDOUBLE(m->origts); 214 double peer_rx = NTP64asDOUBLE(message->rxts);
195 peer_rx = NTP64asDOUBLE(m->rxts); 215 double peer_tx = NTP64asDOUBLE(message->txts);
196 peer_tx = NTP64asDOUBLE(m->txts); 216 double client_rx = TVasDOUBLE((*time_value));
197 client_rx=TVasDOUBLE((*t)); 217 return (((peer_tx - client_rx) + (peer_rx - client_tx)) / 2);
198 return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));
199} 218}
200 219
201/* print out a ntp packet in human readable/debuggable format */ 220/* print out a ntp packet in human readable/debuggable format */
202void print_ntp_message(const ntp_message *p){ 221void print_ntp_message(const ntp_message *message) {
203 struct timeval ref, orig, rx, tx; 222 struct timeval ref;
223 struct timeval orig;
204 224
205 NTP64toTV(p->refts,ref); 225 NTP64toTV(message->refts, ref);
206 NTP64toTV(p->origts,orig); 226 NTP64toTV(message->origts, orig);
207 NTP64toTV(p->rxts,rx);
208 NTP64toTV(p->txts,tx);
209 227
210 printf("packet contents:\n"); 228 printf("packet contents:\n");
211 printf("\tflags: 0x%.2x\n", p->flags); 229 printf("\tflags: 0x%.2x\n", message->flags);
212 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK); 230 printf("\t li=%d (0x%.2x)\n", LI(message->flags), message->flags & LI_MASK);
213 printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK); 231 printf("\t vn=%d (0x%.2x)\n", VN(message->flags), message->flags & VN_MASK);
214 printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK); 232 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
215 printf("\tstratum = %d\n", p->stratum); 233 printf("\tstratum = %d\n", message->stratum);
216 printf("\tpoll = %g\n", pow(2, p->poll)); 234 printf("\tpoll = %g\n", pow(2, message->poll));
217 printf("\tprecision = %g\n", pow(2, p->precision)); 235 printf("\tprecision = %g\n", pow(2, message->precision));
218 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay)); 236 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(message->rtdelay));
219 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp)); 237 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(message->rtdisp));
220 printf("\trefid = %x\n", p->refid); 238 printf("\trefid = %x\n", message->refid);
221 printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts)); 239 printf("\trefts = %-.16g\n", NTP64asDOUBLE(message->refts));
222 printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts)); 240 printf("\torigts = %-.16g\n", NTP64asDOUBLE(message->origts));
223 printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts)); 241 printf("\trxts = %-.16g\n", NTP64asDOUBLE(message->rxts));
224 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts)); 242 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(message->txts));
225} 243}
226 244
227void setup_request(ntp_message *p){ 245void setup_request(ntp_message *message) {
228 struct timeval t; 246 memset(message, 0, sizeof(ntp_message));
229 247 LI_SET(message->flags, LI_ALARM);
230 memset(p, 0, sizeof(ntp_message)); 248 VN_SET(message->flags, 4);
231 LI_SET(p->flags, LI_ALARM); 249 MODE_SET(message->flags, MODE_CLIENT);
232 VN_SET(p->flags, 4); 250 message->poll = 4;
233 MODE_SET(p->flags, MODE_CLIENT); 251 message->precision = (int8_t)0xfa;
234 p->poll=4; 252 L16(message->rtdelay) = htons(1);
235 p->precision=(int8_t)0xfa; 253 L16(message->rtdisp) = htons(1);
236 L16(p->rtdelay)=htons(1);
237 L16(p->rtdisp)=htons(1);
238 254
255 struct timeval t;
239 gettimeofday(&t, NULL); 256 gettimeofday(&t, NULL);
240 TVtoNTP64(t,p->txts); 257 TVtoNTP64(t, message->txts);
241} 258}
242 259
243/* select the "best" server from a list of servers, and return its index. 260/* select the "best" server from a list of servers, and return its index.
244 * this is done by filtering servers based on stratum, dispersion, and 261 * this is done by filtering servers based on stratum, dispersion, and
245 * finally round-trip delay. */ 262 * finally round-trip delay. */
246int best_offset_server(const ntp_server_results *slist, int nservers){ 263int best_offset_server(const ntp_server_results *slist, int nservers) {
247 int cserver=0, best_server=-1; 264 int best_server = -1;
248 265
249 /* for each server */ 266 /* for each server */
250 for(cserver=0; cserver<nservers; cserver++){ 267 for (int cserver = 0; cserver < nservers; cserver++) {
251 /* We don't want any servers that fails these tests */ 268 /* We don't want any servers that fails these tests */
252 /* Sort out servers that didn't respond or responede with a 0 stratum; 269 /* Sort out servers that didn't respond or responede with a 0 stratum;
253 * stratum 0 is for reference clocks so no NTP server should ever report 270 * stratum 0 is for reference clocks so no NTP server should ever report
254 * a stratum 0 */ 271 * a stratum 0 */
255 if ( slist[cserver].stratum == 0){ 272 if (slist[cserver].stratum == 0) {
256 if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum); 273 if (verbose) {
274 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
275 }
257 continue; 276 continue;
258 } 277 }
259 /* Sort out servers with error flags */ 278 /* Sort out servers with error flags */
260 if ( LI(slist[cserver].flags) == LI_ALARM ){ 279 if (LI(slist[cserver].flags) == LI_ALARM) {
261 if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags)); 280 if (verbose) {
281 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
282 }
262 continue; 283 continue;
263 } 284 }
264 285
@@ -272,13 +293,13 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
272 /* compare the server to the best one we've seen so far */ 293 /* compare the server to the best one we've seen so far */
273 /* does it have an equal or better stratum? */ 294 /* does it have an equal or better stratum? */
274 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); 295 DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
275 if(slist[cserver].stratum <= slist[best_server].stratum){ 296 if (slist[cserver].stratum <= slist[best_server].stratum) {
276 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); 297 DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
277 /* does it have an equal or better dispersion? */ 298 /* does it have an equal or better dispersion? */
278 if(slist[cserver].rtdisp <= slist[best_server].rtdisp){ 299 if (slist[cserver].rtdisp <= slist[best_server].rtdisp) {
279 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); 300 DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
280 /* does it have a better rtdelay? */ 301 /* does it have a better rtdelay? */
281 if(slist[cserver].rtdelay < slist[best_server].rtdelay){ 302 if (slist[cserver].rtdelay < slist[best_server].rtdelay) {
282 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); 303 DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
283 best_server = cserver; 304 best_server = cserver;
284 DBG(printf("peer %d is now our best candidate\n", best_server)); 305 DBG(printf("peer %d is now our best candidate\n", best_server));
@@ -287,13 +308,12 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
287 } 308 }
288 } 309 }
289 310
290 if(best_server >= 0) { 311 if (best_server >= 0) {
291 DBG(printf("best server selected: peer %d\n", best_server)); 312 DBG(printf("best server selected: peer %d\n", best_server));
292 return best_server; 313 return best_server;
293 } else {
294 DBG(printf("no peers meeting synchronization criteria :(\n"));
295 return -1;
296 } 314 }
315 DBG(printf("no peers meeting synchronization criteria :(\n"));
316 return -1;
297} 317}
298 318
299/* do everything we need to get the total average offset 319/* do everything we need to get the total average offset
@@ -301,178 +321,208 @@ int best_offset_server(const ntp_server_results *slist, int nservers){
301 * we don't waste time sitting around waiting for single packets. 321 * we don't waste time sitting around waiting for single packets.
302 * - we also "manually" handle resolving host names and connecting, because 322 * - we also "manually" handle resolving host names and connecting, because
303 * we have to do it in a way that our lazy macros don't handle currently :( */ 323 * we have to do it in a way that our lazy macros don't handle currently :( */
304double offset_request(const char *host, int *status){ 324double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) {
305 int i=0, j=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0;
306 int servers_completed=0, one_read=0, servers_readable=0, best_index=-1;
307 time_t now_time=0, start_ts=0;
308 ntp_message *req=NULL;
309 double avg_offset=0.;
310 struct timeval recv_time;
311 struct addrinfo *ai=NULL, *ai_tmp=NULL, hints;
312 struct pollfd *ufds=NULL;
313 ntp_server_results *servers=NULL;
314
315 /* setup hints to only return results from getaddrinfo that we'd like */ 325 /* setup hints to only return results from getaddrinfo that we'd like */
326 struct addrinfo hints;
316 memset(&hints, 0, sizeof(struct addrinfo)); 327 memset(&hints, 0, sizeof(struct addrinfo));
317 hints.ai_family = address_family; 328 hints.ai_family = address_family;
318 hints.ai_protocol = IPPROTO_UDP; 329 hints.ai_protocol = IPPROTO_UDP;
319 hints.ai_socktype = SOCK_DGRAM; 330 hints.ai_socktype = SOCK_DGRAM;
320 331
321 /* fill in ai with the list of hosts resolved by the host name */ 332 /* fill in ai with the list of hosts resolved by the host name */
322 ga_result = getaddrinfo(host, port, &hints, &ai); 333 struct addrinfo *addresses = NULL;
323 if(ga_result!=0){ 334 int ga_result = getaddrinfo(host, port, &hints, &addresses);
324 die(STATE_UNKNOWN, "error getting address for %s: %s\n", 335 if (ga_result != 0) {
325 host, gai_strerror(ga_result)); 336 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
326 } 337 }
327 338
328 /* count the number of returned hosts, and allocate stuff accordingly */ 339 /* count the number of returned hosts, and allocate stuff accordingly */
329 for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; } 340 size_t num_hosts = 0;
330 req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts); 341 for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
331 if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array"); 342 num_hosts++;
332 socklist=(int*)malloc(sizeof(int)*num_hosts); 343 }
333 if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 344
334 ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts); 345 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
335 if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array"); 346
336 servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts); 347 if (req == NULL) {
337 if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array"); 348 die(STATE_UNKNOWN, "can not allocate ntp message array");
338 memset(servers, 0, sizeof(ntp_server_results)*num_hosts); 349 }
339 DBG(printf("Found %d peers to check\n", num_hosts)); 350 int *socklist = (int *)malloc(sizeof(int) * num_hosts);
351
352 if (socklist == NULL) {
353 die(STATE_UNKNOWN, "can not allocate socket array");
354 }
355
356 struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts);
357 if (ufds == NULL) {
358 die(STATE_UNKNOWN, "can not allocate socket array");
359 }
360
361 ntp_server_results *servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
362 if (servers == NULL) {
363 die(STATE_UNKNOWN, "can not allocate server array");
364 }
365 memset(servers, 0, sizeof(ntp_server_results) * num_hosts);
366 DBG(printf("Found %zu peers to check\n", num_hosts));
340 367
341 /* setup each socket for writing, and the corresponding struct pollfd */ 368 /* setup each socket for writing, and the corresponding struct pollfd */
342 ai_tmp=ai; 369 struct addrinfo *ai_tmp = addresses;
343 for(i=0;ai_tmp;i++){ 370 for (int i = 0; ai_tmp; i++) {
344 socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); 371 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
345 if(socklist[i] == -1) { 372 if (socklist[i] == -1) {
346 perror(NULL); 373 perror(NULL);
347 die(STATE_UNKNOWN, "can not create new socket"); 374 die(STATE_UNKNOWN, "can not create new socket");
348 } 375 }
349 if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){ 376 if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) {
350 /* don't die here, because it is enough if there is one server 377 /* don't die here, because it is enough if there is one server
351 answering in time. This also would break for dual ipv4/6 stacked 378 answering in time. This also would break for dual ipv4/6 stacked
352 ntp servers when the client only supports on of them. 379 ntp servers when the client only supports on of them.
353 */ 380 */
354 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); 381 DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno)));
355 } else { 382 } else {
356 ufds[i].fd=socklist[i]; 383 ufds[i].fd = socklist[i];
357 ufds[i].events=POLLIN; 384 ufds[i].events = POLLIN;
358 ufds[i].revents=0; 385 ufds[i].revents = 0;
359 } 386 }
360 ai_tmp = ai_tmp->ai_next; 387 ai_tmp = ai_tmp->ai_next;
361 } 388 }
362 389
363 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds 390 /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds
364 * have passed in order to ensure post-processing and jitter time. */ 391 * have passed in order to ensure post-processing and jitter time. */
365 now_time=start_ts=time(NULL); 392 time_t start_ts = 0;
366 while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){ 393 time_t now_time = 0;
394 now_time = start_ts = time(NULL);
395 size_t servers_completed = 0;
396 bool one_read = false;
397 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) {
367 /* loop through each server and find each one which hasn't 398 /* loop through each server and find each one which hasn't
368 * been touched in the past second or so and is still lacking 399 * been touched in the past second or so and is still lacking
369 * some responses. For each of these servers, send a new request, 400 * some responses. For each of these servers, send a new request,
370 * and update the "waiting" timestamp with the current time. */ 401 * and update the "waiting" timestamp with the current time. */
371 now_time=time(NULL); 402 now_time = time(NULL);
372 403
373 for(i=0; i<num_hosts; i++){ 404 for (size_t i = 0; i < num_hosts; i++) {
374 if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){ 405 if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) {
375 if(verbose && servers[i].waiting != 0) printf("re-"); 406 if (verbose && servers[i].waiting != 0) {
376 if(verbose) printf("sending request to peer %d\n", i); 407 printf("re-");
408 }
409 if (verbose) {
410 printf("sending request to peer %zu\n", i);
411 }
377 setup_request(&req[i]); 412 setup_request(&req[i]);
378 write(socklist[i], &req[i], sizeof(ntp_message)); 413 write(socklist[i], &req[i], sizeof(ntp_message));
379 servers[i].waiting=now_time; 414 servers[i].waiting = now_time;
380 break; 415 break;
381 } 416 }
382 } 417 }
383 418
384 /* quickly poll for any sockets with pending data */ 419 /* quickly poll for any sockets with pending data */
385 servers_readable=poll(ufds, num_hosts, 100); 420 int servers_readable = poll(ufds, num_hosts, 100);
386 if(servers_readable==-1){ 421 if (servers_readable == -1) {
387 perror("polling ntp sockets"); 422 perror("polling ntp sockets");
388 die(STATE_UNKNOWN, "communication errors"); 423 die(STATE_UNKNOWN, "communication errors");
389 } 424 }
390 425
391 /* read from any sockets with pending data */ 426 /* read from any sockets with pending data */
392 for(i=0; servers_readable && i<num_hosts; i++){ 427 for (size_t i = 0; servers_readable && i < num_hosts; i++) {
393 if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){ 428 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) {
394 if(verbose) { 429 if (verbose) {
395 printf("response from peer %d: ", i); 430 printf("response from peer %zu: ", i);
396 } 431 }
397 432
398 read(ufds[i].fd, &req[i], sizeof(ntp_message)); 433 read(ufds[i].fd, &req[i], sizeof(ntp_message));
434
435 struct timeval recv_time;
399 gettimeofday(&recv_time, NULL); 436 gettimeofday(&recv_time, NULL);
400 DBG(print_ntp_message(&req[i])); 437 DBG(print_ntp_message(&req[i]));
401 respnum=servers[i].num_responses++; 438 int respnum = servers[i].num_responses++;
402 servers[i].offset[respnum]=calc_offset(&req[i], &recv_time)+time_offset; 439 servers[i].offset[respnum] = calc_offset(&req[i], &recv_time) + time_offset;
403 if(verbose) { 440 if (verbose) {
404 printf("offset %.10g\n", servers[i].offset[respnum]); 441 printf("offset %.10g\n", servers[i].offset[respnum]);
405 } 442 }
406 servers[i].stratum=req[i].stratum; 443 servers[i].stratum = req[i].stratum;
407 servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp); 444 servers[i].rtdisp = NTP32asDOUBLE(req[i].rtdisp);
408 servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay); 445 servers[i].rtdelay = NTP32asDOUBLE(req[i].rtdelay);
409 servers[i].waiting=0; 446 servers[i].waiting = 0;
410 servers[i].flags=req[i].flags; 447 servers[i].flags = req[i].flags;
411 servers_readable--; 448 servers_readable--;
412 one_read = 1; 449 one_read = true;
413 if(servers[i].num_responses==AVG_NUM) servers_completed++; 450 if (servers[i].num_responses == AVG_NUM) {
451 servers_completed++;
452 }
414 } 453 }
415 } 454 }
416 /* lather, rinse, repeat. */ 455 /* lather, rinse, repeat. */
417 } 456 }
418 457
419 if (one_read == 0) { 458 if (!one_read) {
420 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 459 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
421 } 460 }
422 461
423 /* now, pick the best server from the list */ 462 /* now, pick the best server from the list */
424 best_index=best_offset_server(servers, num_hosts); 463 double avg_offset = 0.;
425 if(best_index < 0){ 464 int best_index = best_offset_server(servers, num_hosts);
426 *status=STATE_UNKNOWN; 465 if (best_index < 0) {
466 *status = STATE_UNKNOWN;
427 } else { 467 } else {
428 /* finally, calculate the average offset */ 468 /* finally, calculate the average offset */
429 for(i=0; i<servers[best_index].num_responses;i++){ 469 for (int i = 0; i < servers[best_index].num_responses; i++) {
430 avg_offset+=servers[best_index].offset[i]; 470 avg_offset += servers[best_index].offset[i];
431 } 471 }
432 avg_offset/=servers[best_index].num_responses; 472 avg_offset /= servers[best_index].num_responses;
433 } 473 }
434 474
435 /* cleanup */ 475 /* cleanup */
436 for(j=0; j<num_hosts; j++){ close(socklist[j]); } 476 for (size_t j = 0; j < num_hosts; j++) {
477 close(socklist[j]);
478 }
437 free(socklist); 479 free(socklist);
438 free(ufds); 480 free(ufds);
439 free(servers); 481 free(servers);
440 free(req); 482 free(req);
441 freeaddrinfo(ai); 483 freeaddrinfo(addresses);
442 484
443 if(verbose) printf("overall average offset: %.10g\n", avg_offset); 485 if (verbose) {
486 printf("overall average offset: %.10g\n", avg_offset);
487 }
444 return avg_offset; 488 return avg_offset;
445} 489}
446 490
447int process_arguments(int argc, char **argv){ 491check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
448 int c; 492 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
449 int option=0; 493 {"help", no_argument, 0, 'h'},
450 static struct option longopts[] = { 494 {"verbose", no_argument, 0, 'v'},
451 {"version", no_argument, 0, 'V'}, 495 {"use-ipv4", no_argument, 0, '4'},
452 {"help", no_argument, 0, 'h'}, 496 {"use-ipv6", no_argument, 0, '6'},
453 {"verbose", no_argument, 0, 'v'}, 497 {"quiet", no_argument, 0, 'q'},
454 {"use-ipv4", no_argument, 0, '4'}, 498 {"time-offset", optional_argument, 0, 'o'},
455 {"use-ipv6", no_argument, 0, '6'}, 499 {"warning", required_argument, 0, 'w'},
456 {"quiet", no_argument, 0, 'q'}, 500 {"critical", required_argument, 0, 'c'},
457 {"time-offset", optional_argument, 0, 'o'}, 501 {"timeout", required_argument, 0, 't'},
458 {"warning", required_argument, 0, 'w'}, 502 {"hostname", required_argument, 0, 'H'},
459 {"critical", required_argument, 0, 'c'}, 503 {"port", required_argument, 0, 'p'},
460 {"timeout", required_argument, 0, 't'}, 504 {0, 0, 0, 0}};
461 {"hostname", required_argument, 0, 'H'}, 505
462 {"port", required_argument, 0, 'p'}, 506 if (argc < 2) {
463 {0, 0, 0, 0} 507 usage("\n");
464 }; 508 }
465 509
510 check_ntp_time_config_wrapper result = {
511 .errorcode = OK,
512 .config = check_ntp_time_config_init(),
513 };
466 514
467 if (argc < 2) 515 char *owarn = "60";
468 usage ("\n"); 516 char *ocrit = "120";
469 517
470 while (1) { 518 while (true) {
471 c = getopt_long (argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); 519 int option = 0;
472 if (c == -1 || c == EOF || c == 1) 520 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
521 if (option_char == -1 || option_char == EOF || option_char == 1) {
473 break; 522 break;
523 }
474 524
475 switch (c) { 525 switch (option_char) {
476 case 'h': 526 case 'h':
477 print_help(); 527 print_help();
478 exit(STATE_UNKNOWN); 528 exit(STATE_UNKNOWN);
@@ -485,7 +535,7 @@ int process_arguments(int argc, char **argv){
485 verbose++; 535 verbose++;
486 break; 536 break;
487 case 'q': 537 case 'q':
488 quiet = true; 538 result.config.quiet = true;
489 break; 539 break;
490 case 'w': 540 case 'w':
491 owarn = optarg; 541 owarn = optarg;
@@ -494,19 +544,20 @@ int process_arguments(int argc, char **argv){
494 ocrit = optarg; 544 ocrit = optarg;
495 break; 545 break;
496 case 'H': 546 case 'H':
497 if(!is_host(optarg)) 547 if (!is_host(optarg)) {
498 usage2(_("Invalid hostname/address"), optarg); 548 usage2(_("Invalid hostname/address"), optarg);
499 server_address = strdup(optarg); 549 }
550 result.config.server_address = strdup(optarg);
500 break; 551 break;
501 case 'p': 552 case 'p':
502 port = strdup(optarg); 553 result.config.port = strdup(optarg);
503 break; 554 break;
504 case 't': 555 case 't':
505 socket_timeout=atoi(optarg); 556 socket_timeout = atoi(optarg);
506 break; 557 break;
507 case 'o': 558 case 'o':
508 time_offset=atoi(optarg); 559 result.config.time_offset = atoi(optarg);
509 break; 560 break;
510 case '4': 561 case '4':
511 address_family = AF_INET; 562 address_family = AF_INET;
512 break; 563 break;
@@ -514,114 +565,118 @@ int process_arguments(int argc, char **argv){
514#ifdef USE_IPV6 565#ifdef USE_IPV6
515 address_family = AF_INET6; 566 address_family = AF_INET6;
516#else 567#else
517 usage4 (_("IPv6 support not available")); 568 usage4(_("IPv6 support not available"));
518#endif 569#endif
519 break; 570 break;
520 case '?': 571 case '?':
521 /* print short usage statement if args not parsable */ 572 /* print short usage statement if args not parsable */
522 usage5 (); 573 usage5();
523 break; 574 break;
524 } 575 }
525 } 576 }
526 577
527 if(server_address == NULL){ 578 if (result.config.server_address == NULL) {
528 usage4(_("Hostname was not supplied")); 579 usage4(_("Hostname was not supplied"));
529 } 580 }
530 581
531 return 0; 582 set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
532}
533 583
534char *perfd_offset (double offset) { 584 return result;
535 return fperfdata ("offset", offset, "s",
536 true, offset_thresholds->warning->end,
537 true, offset_thresholds->critical->end,
538 false, 0, false, 0);
539} 585}
540 586
541int main(int argc, char *argv[]){ 587char *perfd_offset(double offset, thresholds *offset_thresholds) {
542 int result, offset_result; 588 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
543 double offset=0; 589 0);
544 char *result_line, *perfdata_line; 590}
545
546 setlocale (LC_ALL, "");
547 bindtextdomain (PACKAGE, LOCALEDIR);
548 textdomain (PACKAGE);
549 591
550 result = offset_result = STATE_OK; 592int main(int argc, char *argv[]) {
593 setlocale(LC_ALL, "");
594 bindtextdomain(PACKAGE, LOCALEDIR);
595 textdomain(PACKAGE);
551 596
552 /* Parse extra opts if any */ 597 /* Parse extra opts if any */
553 argv=np_extra_opts (&argc, argv, progname); 598 argv = np_extra_opts(&argc, argv, progname);
554 599
555 if (process_arguments (argc, argv) == ERROR) 600 check_ntp_time_config_wrapper tmp_config = process_arguments(argc, argv);
556 usage4 (_("Could not parse arguments"));
557 601
558 set_thresholds(&offset_thresholds, owarn, ocrit); 602 if (tmp_config.errorcode == ERROR) {
603 usage4(_("Could not parse arguments"));
604 }
605
606 const check_ntp_time_config config = tmp_config.config;
559 607
560 /* initialize alarm signal handling */ 608 /* initialize alarm signal handling */
561 signal (SIGALRM, socket_timeout_alarm_handler); 609 signal(SIGALRM, socket_timeout_alarm_handler);
562 610
563 /* set socket timeout */ 611 /* set socket timeout */
564 alarm (socket_timeout); 612 alarm(socket_timeout);
565 613
566 offset = offset_request(server_address, &offset_result); 614 mp_state_enum offset_result = STATE_OK;
615 mp_state_enum result = STATE_OK;
616 double offset = offset_request(config.server_address, config.port, &offset_result, config.time_offset);
567 if (offset_result == STATE_UNKNOWN) { 617 if (offset_result == STATE_UNKNOWN) {
568 result = ( (!quiet) ? STATE_UNKNOWN : STATE_CRITICAL); 618 result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
569 } else { 619 } else {
570 result = get_status(fabs(offset), offset_thresholds); 620 result = get_status(fabs(offset), config.offset_thresholds);
571 } 621 }
572 622
623 char *result_line;
573 switch (result) { 624 switch (result) {
574 case STATE_CRITICAL : 625 case STATE_CRITICAL:
575 xasprintf(&result_line, _("NTP CRITICAL:")); 626 xasprintf(&result_line, _("NTP CRITICAL:"));
576 break; 627 break;
577 case STATE_WARNING : 628 case STATE_WARNING:
578 xasprintf(&result_line, _("NTP WARNING:")); 629 xasprintf(&result_line, _("NTP WARNING:"));
579 break; 630 break;
580 case STATE_OK : 631 case STATE_OK:
581 xasprintf(&result_line, _("NTP OK:")); 632 xasprintf(&result_line, _("NTP OK:"));
582 break; 633 break;
583 default : 634 default:
584 xasprintf(&result_line, _("NTP UNKNOWN:")); 635 xasprintf(&result_line, _("NTP UNKNOWN:"));
585 break; 636 break;
586 } 637 }
587 if(offset_result == STATE_UNKNOWN){ 638
639 char *perfdata_line;
640 if (offset_result == STATE_UNKNOWN) {
588 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 641 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
589 xasprintf(&perfdata_line, ""); 642 xasprintf(&perfdata_line, "");
590 } else { 643 } else {
591 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 644 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
592 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 645 xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
593 } 646 }
594 printf("%s|%s\n", result_line, perfdata_line); 647 printf("%s|%s\n", result_line, perfdata_line);
595 648
596 if(server_address!=NULL) free(server_address); 649 if (config.server_address != NULL) {
597 return result; 650 free(config.server_address);
651 }
652 exit(result);
598} 653}
599 654
600void print_help(void){ 655void print_help(void) {
601 print_revision(progname, NP_VERSION); 656 print_revision(progname, NP_VERSION);
602 657
603 printf ("Copyright (c) 2006 Sean Finney\n"); 658 printf("Copyright (c) 2006 Sean Finney\n");
604 printf (COPYRIGHT, copyright, email); 659 printf(COPYRIGHT, copyright, email);
605 660
606 printf ("%s\n", _("This plugin checks the clock offset with the ntp server")); 661 printf("%s\n", _("This plugin checks the clock offset with the ntp server"));
607 662
608 printf ("\n\n"); 663 printf("\n\n");
609 664
610 print_usage(); 665 print_usage();
611 printf (UT_HELP_VRSN); 666 printf(UT_HELP_VRSN);
612 printf (UT_EXTRA_OPTS); 667 printf(UT_EXTRA_OPTS);
613 printf (UT_IPv46); 668 printf(UT_IPv46);
614 printf (UT_HOST_PORT, 'p', "123"); 669 printf(UT_HOST_PORT, 'p', "123");
615 printf (" %s\n", "-q, --quiet"); 670 printf(" %s\n", "-q, --quiet");
616 printf (" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found")); 671 printf(" %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found"));
617 printf (" %s\n", "-w, --warning=THRESHOLD"); 672 printf(" %s\n", "-w, --warning=THRESHOLD");
618 printf (" %s\n", _("Offset to result in warning status (seconds)")); 673 printf(" %s\n", _("Offset to result in warning status (seconds)"));
619 printf (" %s\n", "-c, --critical=THRESHOLD"); 674 printf(" %s\n", "-c, --critical=THRESHOLD");
620 printf (" %s\n", _("Offset to result in critical status (seconds)")); 675 printf(" %s\n", _("Offset to result in critical status (seconds)"));
621 printf (" %s\n", "-o, --time_offset=INTEGER"); 676 printf(" %s\n", "-o, --time_offset=INTEGER");
622 printf (" %s\n", _("Expected offset of the ntp server relative to local server (seconds)")); 677 printf(" %s\n", _("Expected offset of the ntp server relative to local server (seconds)"));
623 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 678 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
624 printf (UT_VERBOSE); 679 printf(UT_VERBOSE);
625 680
626 printf("\n"); 681 printf("\n");
627 printf("%s\n", _("This plugin checks the clock offset between the local host and a")); 682 printf("%s\n", _("This plugin checks the clock offset between the local host and a"));
@@ -641,13 +696,10 @@ void print_help(void){
641 printf("%s\n", _("Examples:")); 696 printf("%s\n", _("Examples:"));
642 printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1")); 697 printf(" %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1"));
643 698
644 printf (UT_SUPPORT); 699 printf(UT_SUPPORT);
645} 700}
646 701
647void 702void print_usage(void) {
648print_usage(void) 703 printf("%s\n", _("Usage:"));
649{
650 printf ("%s\n", _("Usage:"));
651 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname); 704 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname);
652} 705}
653
diff --git a/plugins/check_ntp_time.d/config.h b/plugins/check_ntp_time.d/config.h
new file mode 100644
index 00000000..99dabbbd
--- /dev/null
+++ b/plugins/check_ntp_time.d/config.h
@@ -0,0 +1,28 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6
7typedef struct {
8 char *server_address;
9 char *port;
10
11 bool quiet;
12 int time_offset;
13
14 thresholds *offset_thresholds;
15} check_ntp_time_config;
16
17check_ntp_time_config check_ntp_time_config_init() {
18 check_ntp_time_config tmp = {
19 .server_address = NULL,
20 .port = "123",
21
22 .quiet = false,
23 .time_offset = 0,
24
25 .offset_thresholds = NULL,
26 };
27 return tmp;
28}
diff --git a/plugins/check_nwstat.c b/plugins/check_nwstat.c
deleted file mode 100644
index 10c493b6..00000000
--- a/plugins/check_nwstat.c
+++ /dev/null
@@ -1,1740 +0,0 @@
1/*****************************************************************************
2*
3* Monitoring check_nwstat plugin
4*
5* License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team
7*
8* Description:
9*
10* This file contains the check_nwstat plugin
11*
12* This plugin attempts to contact the MRTGEXT NLM running on a
13* Novell server to gather the requested system information.
14*
15*
16* This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version.
20*
21* This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details.
25*
26* You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>.
28*
29*
30*****************************************************************************/
31
32const char *progname = "check_nwstat";
33const char *copyright = "2000-2007";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "common.h"
37#include "netutils.h"
38#include "utils.h"
39
40enum checkvar {
41 NONE,
42 LOAD1, /* check 1 minute CPU load */
43 LOAD5, /* check 5 minute CPU load */
44 LOAD15, /* check 15 minute CPU load */
45 CONNS, /* check number of connections */
46 VPF, /* check % free space on volume */
47 VMF, /* check MB free space on volume */
48 VMU, /* check MB used space on volume */
49 VPU, /* check % used space on volume */
50 VMP, /* check MB purgeable space on volume */
51 VKF, /* check KB free space on volume */
52 LTCH, /* check long-term cache hit percentage */
53 CBUFF, /* check total cache buffers */
54 CDBUFF, /* check dirty cache buffers */
55 LRUM, /* check LRU sitting time in minutes */
56 DSDB, /* check to see if DS Database is open */
57 LOGINS, /* check to see if logins are enabled */
58 NRMH, /* check to see NRM Health Status */
59 PUPRB, /* check % of used packet receive buffers */
60 UPRB, /* check used packet receive buffers */
61 SAPENTRIES, /* check SAP entries */
62 OFILES, /* check number of open files */
63 VKP, /* check KB purgeable space on volume */
64 VPP, /* check % purgeable space on volume */
65 VKNP, /* check KB not yet purgeable space on volume */
66 VPNP, /* check % not yet purgeable space on volume */
67 ABENDS, /* check abended thread count */
68 CSPROCS, /* check number of current service processes */
69 TSYNC, /* check timesync status 0=no 1=yes in sync to the network */
70 LRUS, /* check LRU sitting time in seconds */
71 DCB, /* check dirty cache buffers as a percentage of the total */
72 TCB, /* check total cache buffers as a percentage of the original */
73 DSVER, /* check NDS version */
74 UPTIME, /* check server uptime */
75 NLM, /* check NLM loaded */
76 NRMP, /* check NRM Process Values */
77 NRMM, /* check NRM Memory Values */
78 NRMS, /* check NRM Values */
79 NSS1, /* check Statistics from _Admin:Manage_NSS\GeneralStats.xml */
80 NSS2, /* check Statistics from _Admin:Manage_NSS\BufferCache.xml */
81 NSS3, /* check statistics from _Admin:Manage_NSS\NameCache.xml */
82 NSS4, /* check statistics from _Admin:Manage_NSS\FileStats.xml */
83 NSS5, /* check statistics from _Admin:Manage_NSS\ObjectCache.xml */
84 NSS6, /* check statistics from _Admin:Manage_NSS\Thread.xml */
85 NSS7 /* check statistics from _Admin:Manage_NSS\AuthorizationCache.xml */
86};
87
88enum {
89 PORT = 9999
90};
91
92char *server_address=NULL;
93char *volume_name=NULL;
94char *nlm_name=NULL;
95char *nrmp_name=NULL;
96char *nrmm_name=NULL;
97char *nrms_name=NULL;
98char *nss1_name=NULL;
99char *nss2_name=NULL;
100char *nss3_name=NULL;
101char *nss4_name=NULL;
102char *nss5_name=NULL;
103char *nss6_name=NULL;
104char *nss7_name=NULL;
105int server_port=PORT;
106unsigned long warning_value=0L;
107unsigned long critical_value=0L;
108bool check_warning_value = false;
109bool check_critical_value = false;
110bool check_netware_version = false;
111enum checkvar vars_to_check = NONE;
112int sap_number=-1;
113
114int process_arguments(int, char **);
115void print_help(void);
116void print_usage(void);
117
118
119
120int
121main(int argc, char **argv) {
122 int result = STATE_UNKNOWN;
123 int sd;
124 char *send_buffer=NULL;
125 char recv_buffer[MAX_INPUT_BUFFER];
126 char *output_message=NULL;
127 char *temp_buffer=NULL;
128 char *netware_version=NULL;
129
130 int time_sync_status=0;
131 int nrm_health_status=0;
132 unsigned long total_cache_buffers=0;
133 unsigned long dirty_cache_buffers=0;
134 unsigned long open_files=0;
135 unsigned long abended_threads=0;
136 unsigned long max_service_processes=0;
137 unsigned long current_service_processes=0;
138 unsigned long free_disk_space=0L;
139 unsigned long nrmp_value=0L;
140 unsigned long nrmm_value=0L;
141 unsigned long nrms_value=0L;
142 unsigned long nss1_value=0L;
143 unsigned long nss2_value=0L;
144 unsigned long nss3_value=0L;
145 unsigned long nss4_value=0L;
146 unsigned long nss5_value=0L;
147 unsigned long nss6_value=0L;
148 unsigned long nss7_value=0L;
149 unsigned long total_disk_space=0L;
150 unsigned long used_disk_space=0L;
151 unsigned long percent_used_disk_space=0L;
152 unsigned long purgeable_disk_space=0L;
153 unsigned long non_purgeable_disk_space=0L;
154 unsigned long percent_free_space=0;
155 unsigned long percent_purgeable_space=0;
156 unsigned long percent_non_purgeable_space=0;
157 unsigned long current_connections=0L;
158 unsigned long utilization=0L;
159 unsigned long cache_hits=0;
160 unsigned long cache_buffers=0L;
161 unsigned long lru_time=0L;
162 unsigned long max_packet_receive_buffers=0;
163 unsigned long used_packet_receive_buffers=0;
164 unsigned long percent_used_packet_receive_buffers=0L;
165 unsigned long sap_entries=0;
166 char uptime[MAX_INPUT_BUFFER];
167
168 setlocale (LC_ALL, "");
169 bindtextdomain (PACKAGE, LOCALEDIR);
170 textdomain (PACKAGE);
171
172 /* Parse extra opts if any */
173 argv=np_extra_opts(&argc, argv, progname);
174
175 if (process_arguments(argc,argv) == ERROR)
176 usage4 (_("Could not parse arguments"));
177
178 /* initialize alarm signal handling */
179 signal(SIGALRM,socket_timeout_alarm_handler);
180
181 /* set socket timeout */
182 alarm(socket_timeout);
183
184 /* open connection */
185 my_tcp_connect (server_address, server_port, &sd);
186
187 /* get OS version string */
188 if (check_netware_version) {
189 send_buffer = strdup ("S19\r\n");
190 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
191 if (result!=STATE_OK)
192 return result;
193 if (!strcmp(recv_buffer,"-1\n"))
194 netware_version = strdup("");
195 else {
196 recv_buffer[strlen(recv_buffer)-1]=0;
197 xasprintf (&netware_version,_("NetWare %s: "),recv_buffer);
198 }
199 } else
200 netware_version = strdup("");
201
202
203 /* check CPU load */
204 if (vars_to_check==LOAD1 || vars_to_check==LOAD5 || vars_to_check==LOAD15) {
205
206 switch(vars_to_check) {
207 case LOAD1:
208 temp_buffer = strdup ("1");
209 break;
210 case LOAD5:
211 temp_buffer = strdup ("5");
212 break;
213 default:
214 temp_buffer = strdup ("15");
215 break;
216 }
217
218 close(sd);
219 my_tcp_connect (server_address, server_port, &sd);
220
221 xasprintf (&send_buffer,"UTIL%s\r\n",temp_buffer);
222 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
223 if (result!=STATE_OK)
224 return result;
225 utilization=strtoul(recv_buffer,NULL,10);
226
227 close(sd);
228 my_tcp_connect (server_address, server_port, &sd);
229
230 send_buffer = strdup ("UPTIME\r\n");
231 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
232 if (result!=STATE_OK)
233 return result;
234 recv_buffer[strlen(recv_buffer)-1]=0;
235 sprintf(uptime,_("Up %s,"),recv_buffer);
236
237 if (check_critical_value && utilization >= critical_value)
238 result=STATE_CRITICAL;
239 else if (check_warning_value && utilization >= warning_value)
240 result=STATE_WARNING;
241
242 xasprintf (&output_message,
243 _("Load %s - %s %s-min load average = %lu%%|load%s=%lu;%lu;%lu;0;100"),
244 state_text(result),
245 uptime,
246 temp_buffer,
247 utilization,
248 temp_buffer,
249 utilization,
250 warning_value,
251 critical_value);
252
253 /* check number of user connections */
254 } else if (vars_to_check==CONNS) {
255
256 close(sd);
257 my_tcp_connect (server_address, server_port, &sd);
258
259 send_buffer = strdup ("CONNECT\r\n");
260 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
261 if (result!=STATE_OK)
262 return result;
263 current_connections=strtoul(recv_buffer,NULL,10);
264
265 if (check_critical_value && current_connections >= critical_value)
266 result=STATE_CRITICAL;
267 else if (check_warning_value && current_connections >= warning_value)
268 result=STATE_WARNING;
269
270 xasprintf (&output_message,
271 _("Conns %s - %lu current connections|Conns=%lu;%lu;%lu;;"),
272 state_text(result),
273 current_connections,
274 current_connections,
275 warning_value,
276 critical_value);
277
278 /* check % long term cache hits */
279 } else if (vars_to_check==LTCH) {
280
281 close(sd);
282 my_tcp_connect (server_address, server_port, &sd);
283
284 send_buffer = strdup ("S1\r\n");
285 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
286 if (result!=STATE_OK)
287 return result;
288 cache_hits=atoi(recv_buffer);
289
290 if (check_critical_value && cache_hits <= critical_value)
291 result=STATE_CRITICAL;
292 else if (check_warning_value && cache_hits <= warning_value)
293 result=STATE_WARNING;
294
295 xasprintf (&output_message,
296 _("%s: Long term cache hits = %lu%%"),
297 state_text(result),
298 cache_hits);
299
300 /* check cache buffers */
301 } else if (vars_to_check==CBUFF) {
302
303 close(sd);
304 my_tcp_connect (server_address, server_port, &sd);
305
306 send_buffer = strdup ("S2\r\n");
307 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
308 if (result!=STATE_OK)
309 return result;
310 cache_buffers=strtoul(recv_buffer,NULL,10);
311
312 if (check_critical_value && cache_buffers <= critical_value)
313 result=STATE_CRITICAL;
314 else if (check_warning_value && cache_buffers <= warning_value)
315 result=STATE_WARNING;
316
317 xasprintf (&output_message,
318 _("%s: Total cache buffers = %lu|Cachebuffers=%lu;%lu;%lu;;"),
319 state_text(result),
320 cache_buffers,
321 cache_buffers,
322 warning_value,
323 critical_value);
324
325 /* check dirty cache buffers */
326 } else if (vars_to_check==CDBUFF) {
327
328 close(sd);
329 my_tcp_connect (server_address, server_port, &sd);
330
331 send_buffer = strdup ("S3\r\n");
332 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
333 if (result!=STATE_OK)
334 return result;
335 cache_buffers=strtoul(recv_buffer,NULL,10);
336
337 if (check_critical_value && cache_buffers >= critical_value)
338 result=STATE_CRITICAL;
339 else if (check_warning_value && cache_buffers >= warning_value)
340 result=STATE_WARNING;
341
342 xasprintf (&output_message,
343 _("%s: Dirty cache buffers = %lu|Dirty-Cache-Buffers=%lu;%lu;%lu;;"),
344 state_text(result),
345 cache_buffers,
346 cache_buffers,
347 warning_value,
348 critical_value);
349
350 /* check LRU sitting time in minutes */
351 } else if (vars_to_check==LRUM) {
352
353 close(sd);
354 my_tcp_connect (server_address, server_port, &sd);
355
356 send_buffer = strdup ("S5\r\n");
357 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
358 if (result!=STATE_OK)
359 return result;
360 lru_time=strtoul(recv_buffer,NULL,10);
361
362 if (check_critical_value && lru_time <= critical_value)
363 result=STATE_CRITICAL;
364 else if (check_warning_value && lru_time <= warning_value)
365 result=STATE_WARNING;
366
367 xasprintf (&output_message,
368 _("%s: LRU sitting time = %lu minutes"),
369 state_text(result),
370 lru_time);
371
372
373 /* check KB free space on volume */
374 } else if (vars_to_check==VKF) {
375
376 close(sd);
377 my_tcp_connect (server_address, server_port, &sd);
378
379 xasprintf (&send_buffer,"VKF%s\r\n",volume_name);
380 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
381 if (result!=STATE_OK)
382 return result;
383
384 if (!strcmp(recv_buffer,"-1\n")) {
385 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
386 result=STATE_CRITICAL;
387 } else {
388 free_disk_space=strtoul(recv_buffer,NULL,10);
389 if (check_critical_value && free_disk_space <= critical_value)
390 result=STATE_CRITICAL;
391 else if (check_warning_value && free_disk_space <= warning_value)
392 result=STATE_WARNING;
393 xasprintf (&output_message,
394 _("%s%lu KB free on volume %s|KBFree%s=%lu;%lu;%lu;;"),
395 (result==STATE_OK)?"":_("Only "),
396 free_disk_space,
397 volume_name,
398 volume_name,
399 free_disk_space,
400 warning_value,
401 critical_value);
402 }
403
404 /* check MB free space on volume */
405 } else if (vars_to_check==VMF) {
406
407 xasprintf (&send_buffer,"VMF%s\r\n",volume_name);
408 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
409 if (result!=STATE_OK)
410 return result;
411
412 if (!strcmp(recv_buffer,"-1\n")) {
413 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
414 result=STATE_CRITICAL;
415 } else {
416 free_disk_space=strtoul(recv_buffer,NULL,10);
417 if (check_critical_value && free_disk_space <= critical_value)
418 result=STATE_CRITICAL;
419 else if (check_warning_value && free_disk_space <= warning_value)
420 result=STATE_WARNING;
421 xasprintf (&output_message,
422 _("%s%lu MB free on volume %s|MBFree%s=%lu;%lu;%lu;;"),
423 (result==STATE_OK)?"":_("Only "),
424 free_disk_space,
425 volume_name,
426 volume_name,
427 free_disk_space,
428 warning_value,
429 critical_value);
430 }
431 /* check MB used space on volume */
432 } else if (vars_to_check==VMU) {
433
434 xasprintf (&send_buffer,"VMU%s\r\n",volume_name);
435 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
436 if (result!=STATE_OK)
437 return result;
438
439 if (!strcmp(recv_buffer,"-1\n")) {
440 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
441 result=STATE_CRITICAL;
442 } else {
443 free_disk_space=strtoul(recv_buffer,NULL,10);
444 if (check_critical_value && free_disk_space <= critical_value)
445 result=STATE_CRITICAL;
446 else if (check_warning_value && free_disk_space <= warning_value)
447 result=STATE_WARNING;
448 xasprintf (&output_message,
449 _("%s%lu MB used on volume %s|MBUsed%s=%lu;%lu;%lu;;"),
450 (result==STATE_OK)?"":_("Only "),
451 free_disk_space,
452 volume_name,
453 volume_name,
454 free_disk_space,
455 warning_value,
456 critical_value);
457 }
458 /* check % used space on volume */
459 } else if (vars_to_check==VPU) {
460 close(sd);
461 my_tcp_connect (server_address, server_port, &sd);
462
463 asprintf (&send_buffer,"VMU%s\r\n",volume_name);
464 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
465
466 if (result!=STATE_OK)
467 return result;
468
469 if (!strcmp(recv_buffer,"-1\n")) {
470 asprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
471 result=STATE_CRITICAL;
472
473 } else {
474 used_disk_space=strtoul(recv_buffer,NULL,10);
475 close(sd);
476 my_tcp_connect (server_address, server_port, &sd);
477 /* get total volume in MB */
478 asprintf (&send_buffer,"VMS%s\r\n",volume_name);
479 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
480 if (result!=STATE_OK)
481 return result;
482 total_disk_space=strtoul(recv_buffer,NULL,10);
483 /* calculate percent used on volume */
484 percent_used_disk_space=(unsigned long)(((double)used_disk_space/(double)total_disk_space)*100.0);
485
486 if (check_critical_value && percent_used_disk_space >= critical_value)
487 result=STATE_CRITICAL;
488 else if (check_warning_value && percent_used_disk_space >= warning_value)
489 result=STATE_WARNING;
490
491 asprintf (&output_message,_("%lu MB (%lu%%) used on volume %s - total %lu MB|Used space in percent on %s=%lu;%lu;%lu;0;100"),
492 used_disk_space,
493 percent_used_disk_space,
494 volume_name,
495 total_disk_space,
496 volume_name,
497 percent_used_disk_space,
498 warning_value,
499 critical_value
500 );
501 }
502
503 /* check % free space on volume */
504 } else if (vars_to_check==VPF) {
505
506 close(sd);
507 my_tcp_connect (server_address, server_port, &sd);
508
509 xasprintf (&send_buffer,"VKF%s\r\n",volume_name);
510 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
511 if (result!=STATE_OK)
512 return result;
513
514 if (!strcmp(recv_buffer,"-1\n")) {
515
516 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
517 result=STATE_CRITICAL;
518
519 } else {
520
521 free_disk_space=strtoul(recv_buffer,NULL,10);
522
523 close(sd);
524 my_tcp_connect (server_address, server_port, &sd);
525
526 xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
527 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
528 if (result!=STATE_OK)
529 return result;
530 total_disk_space=strtoul(recv_buffer,NULL,10);
531
532 percent_free_space=(unsigned long)(((double)free_disk_space/(double)total_disk_space)*100.0);
533
534 if (check_critical_value && percent_free_space <= critical_value)
535 result=STATE_CRITICAL;
536 else if (check_warning_value && percent_free_space <= warning_value)
537 result=STATE_WARNING;
538 free_disk_space/=1024;
539 total_disk_space/=1024;
540 xasprintf (&output_message,_("%lu MB (%lu%%) free on volume %s - total %lu MB|FreeMB%s=%lu;%lu;%lu;0;100"),
541 free_disk_space,
542 percent_free_space,
543 volume_name,
544 total_disk_space,
545 volume_name,
546 percent_free_space,
547 warning_value,
548 critical_value
549 );
550 }
551
552 /* check to see if DS Database is open or closed */
553 } else if (vars_to_check==DSDB) {
554
555 close(sd);
556 my_tcp_connect (server_address, server_port, &sd);
557
558 send_buffer = strdup ("S11\r\n");
559 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
560 if (result!=STATE_OK)
561 return result;
562 if (atoi(recv_buffer)==1)
563 result=STATE_OK;
564 else
565 result=STATE_WARNING;
566
567 close(sd);
568 my_tcp_connect (server_address, server_port, &sd);
569
570 send_buffer = strdup ("S13\r\n");
571 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
572 temp_buffer=strtok(recv_buffer,"\r\n");
573
574 xasprintf (&output_message,_("Directory Services Database is %s (DS version %s)"),(result==STATE_OK)?"open":"closed",temp_buffer);
575
576 /* check to see if logins are enabled */
577 } else if (vars_to_check==LOGINS) {
578
579 close(sd);
580 my_tcp_connect (server_address, server_port, &sd);
581
582 send_buffer = strdup ("S12\r\n");
583 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
584 if (result!=STATE_OK)
585 return result;
586 if (atoi(recv_buffer)==1)
587 result=STATE_OK;
588 else
589 result=STATE_WARNING;
590
591 xasprintf (&output_message,_("Logins are %s"),(result==STATE_OK)?_("enabled"):_("disabled"));
592
593
594 /* check NRM Health Status Summary*/
595 } else if (vars_to_check==NRMH) {
596
597 xasprintf (&send_buffer,"NRMH\r\n");
598 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
599 if (result!=STATE_OK)
600 return result;
601
602 nrm_health_status=atoi(recv_buffer);
603
604 if (nrm_health_status==2) {
605 result=STATE_OK;
606 xasprintf (&output_message,_("CRITICAL - NRM Status is bad!"));
607 }
608 else {
609 if (nrm_health_status==1) {
610 result=STATE_WARNING;
611 xasprintf (&output_message,_("Warning - NRM Status is suspect!"));
612 }
613
614 xasprintf (&output_message,_("OK - NRM Status is good!"));
615 }
616
617
618
619 /* check packet receive buffers */
620 } else if (vars_to_check==UPRB || vars_to_check==PUPRB) {
621
622 close(sd);
623 my_tcp_connect (server_address, server_port, &sd);
624
625 xasprintf (&send_buffer,"S15\r\n");
626 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
627 if (result!=STATE_OK)
628 return result;
629
630 used_packet_receive_buffers=atoi(recv_buffer);
631
632 close(sd);
633 my_tcp_connect (server_address, server_port, &sd);
634
635 xasprintf (&send_buffer,"S16\r\n");
636 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
637 if (result!=STATE_OK)
638 return result;
639
640 max_packet_receive_buffers=atoi(recv_buffer);
641
642 percent_used_packet_receive_buffers=(unsigned long)(((double)used_packet_receive_buffers/(double)max_packet_receive_buffers)*100.0);
643
644 if (vars_to_check==UPRB) {
645 if (check_critical_value && used_packet_receive_buffers >= critical_value)
646 result=STATE_CRITICAL;
647 else if (check_warning_value && used_packet_receive_buffers >= warning_value)
648 result=STATE_WARNING;
649 } else {
650 if (check_critical_value && percent_used_packet_receive_buffers >= critical_value)
651 result=STATE_CRITICAL;
652 else if (check_warning_value && percent_used_packet_receive_buffers >= warning_value)
653 result=STATE_WARNING;
654 }
655
656 xasprintf (&output_message,_("%lu of %lu (%lu%%) packet receive buffers used"),used_packet_receive_buffers,max_packet_receive_buffers,percent_used_packet_receive_buffers);
657
658 /* check SAP table entries */
659 } else if (vars_to_check==SAPENTRIES) {
660
661 close(sd);
662 my_tcp_connect (server_address, server_port, &sd);
663
664 if (sap_number==-1)
665 xasprintf (&send_buffer,"S9\r\n");
666 else
667 xasprintf (&send_buffer,"S9.%d\r\n",sap_number);
668 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
669 if (result!=STATE_OK)
670 return result;
671
672 sap_entries=atoi(recv_buffer);
673
674 if (check_critical_value && sap_entries >= critical_value)
675 result=STATE_CRITICAL;
676 else if (check_warning_value && sap_entries >= warning_value)
677 result=STATE_WARNING;
678
679 if (sap_number==-1)
680 xasprintf (&output_message,_("%lu entries in SAP table"),sap_entries);
681 else
682 xasprintf (&output_message,_("%lu entries in SAP table for SAP type %d"),sap_entries,sap_number);
683
684 /* check KB purgeable space on volume */
685 } else if (vars_to_check==VKP) {
686
687 close(sd);
688 my_tcp_connect (server_address, server_port, &sd);
689
690 xasprintf (&send_buffer,"VKP%s\r\n",volume_name);
691 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
692 if (result!=STATE_OK)
693 return result;
694
695 if (!strcmp(recv_buffer,"-1\n")) {
696 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
697 result=STATE_CRITICAL;
698 } else {
699 purgeable_disk_space=strtoul(recv_buffer,NULL,10);
700 if (check_critical_value && purgeable_disk_space >= critical_value)
701 result=STATE_CRITICAL;
702 else if (check_warning_value && purgeable_disk_space >= warning_value)
703 result=STATE_WARNING;
704 xasprintf (&output_message,_("%s%lu KB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"),
705 (result==STATE_OK)?"":_("Only "),
706 purgeable_disk_space,
707 volume_name,
708 volume_name,
709 purgeable_disk_space,
710 warning_value,
711 critical_value);
712 }
713 /* check MB purgeable space on volume */
714 } else if (vars_to_check==VMP) {
715
716 xasprintf (&send_buffer,"VMP%s\r\n",volume_name);
717 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
718 if (result!=STATE_OK)
719 return result;
720
721 if (!strcmp(recv_buffer,"-1\n")) {
722 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
723 result=STATE_CRITICAL;
724 } else {
725 purgeable_disk_space=strtoul(recv_buffer,NULL,10);
726 if (check_critical_value && purgeable_disk_space >= critical_value)
727 result=STATE_CRITICAL;
728 else if (check_warning_value && purgeable_disk_space >= warning_value)
729 result=STATE_WARNING;
730 xasprintf (&output_message,_("%s%lu MB purgeable on volume %s|Purge%s=%lu;%lu;%lu;;"),
731 (result==STATE_OK)?"":_("Only "),
732 purgeable_disk_space,
733 volume_name,
734 volume_name,
735 purgeable_disk_space,
736 warning_value,
737 critical_value);
738 }
739
740 /* check % purgeable space on volume */
741 } else if (vars_to_check==VPP) {
742
743 close(sd);
744 my_tcp_connect (server_address, server_port, &sd);
745
746 xasprintf (&send_buffer,"VKP%s\r\n",volume_name);
747 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
748 if (result!=STATE_OK)
749 return result;
750
751 if (!strcmp(recv_buffer,"-1\n")) {
752
753 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
754 result=STATE_CRITICAL;
755
756 } else {
757
758 purgeable_disk_space=strtoul(recv_buffer,NULL,10);
759
760 close(sd);
761 my_tcp_connect (server_address, server_port, &sd);
762
763 xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
764 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
765 if (result!=STATE_OK)
766 return result;
767 total_disk_space=strtoul(recv_buffer,NULL,10);
768
769 percent_purgeable_space=(unsigned long)(((double)purgeable_disk_space/(double)total_disk_space)*100.0);
770
771 if (check_critical_value && percent_purgeable_space >= critical_value)
772 result=STATE_CRITICAL;
773 else if (check_warning_value && percent_purgeable_space >= warning_value)
774 result=STATE_WARNING;
775 purgeable_disk_space/=1024;
776 xasprintf (&output_message,_("%lu MB (%lu%%) purgeable on volume %s|Purgeable%s=%lu;%lu;%lu;0;100"),
777 purgeable_disk_space,
778 percent_purgeable_space,
779 volume_name,
780 volume_name,
781 percent_purgeable_space,
782 warning_value,
783 critical_value
784 );
785 }
786
787 /* check KB not yet purgeable space on volume */
788 } else if (vars_to_check==VKNP) {
789
790 close(sd);
791 my_tcp_connect (server_address, server_port, &sd);
792
793 xasprintf (&send_buffer,"VKNP%s\r\n",volume_name);
794 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
795 if (result!=STATE_OK)
796 return result;
797
798 if (!strcmp(recv_buffer,"-1\n")) {
799 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
800 result=STATE_CRITICAL;
801 } else {
802 non_purgeable_disk_space=strtoul(recv_buffer,NULL,10);
803 if (check_critical_value && non_purgeable_disk_space >= critical_value)
804 result=STATE_CRITICAL;
805 else if (check_warning_value && non_purgeable_disk_space >= warning_value)
806 result=STATE_WARNING;
807 xasprintf (&output_message,_("%s%lu KB not yet purgeable on volume %s"),(result==STATE_OK)?"":_("Only "),non_purgeable_disk_space,volume_name);
808 }
809
810 /* check % not yet purgeable space on volume */
811 } else if (vars_to_check==VPNP) {
812
813 close(sd);
814 my_tcp_connect (server_address, server_port, &sd);
815
816 xasprintf (&send_buffer,"VKNP%s\r\n",volume_name);
817 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
818 if (result!=STATE_OK)
819 return result;
820
821 if (!strcmp(recv_buffer,"-1\n")) {
822
823 xasprintf (&output_message,_("CRITICAL - Volume '%s' does not exist!"),volume_name);
824 result=STATE_CRITICAL;
825
826 } else {
827
828 non_purgeable_disk_space=strtoul(recv_buffer,NULL,10);
829
830 close(sd);
831 my_tcp_connect (server_address, server_port, &sd);
832
833 xasprintf (&send_buffer,"VKS%s\r\n",volume_name);
834 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
835 if (result!=STATE_OK)
836 return result;
837 total_disk_space=strtoul(recv_buffer,NULL,10);
838
839 percent_non_purgeable_space=(unsigned long)(((double)non_purgeable_disk_space/(double)total_disk_space)*100.0);
840
841 if (check_critical_value && percent_non_purgeable_space >= critical_value)
842 result=STATE_CRITICAL;
843 else if (check_warning_value && percent_non_purgeable_space >= warning_value)
844 result=STATE_WARNING;
845 purgeable_disk_space/=1024;
846 xasprintf (&output_message,_("%lu MB (%lu%%) not yet purgeable on volume %s"),non_purgeable_disk_space,percent_non_purgeable_space,volume_name);
847 }
848
849 /* check # of open files */
850 } else if (vars_to_check==OFILES) {
851
852 close(sd);
853 my_tcp_connect (server_address, server_port, &sd);
854
855 xasprintf (&send_buffer,"S18\r\n");
856 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
857 if (result!=STATE_OK)
858 return result;
859
860 open_files=atoi(recv_buffer);
861
862 if (check_critical_value && open_files >= critical_value)
863 result=STATE_CRITICAL;
864 else if (check_warning_value && open_files >= warning_value)
865 result=STATE_WARNING;
866
867 xasprintf (&output_message,_("%lu open files|Openfiles=%lu;%lu;%lu;0,0"),
868 open_files,
869 open_files,
870 warning_value,
871 critical_value);
872
873
874 /* check # of abended threads (Netware > 5.x only) */
875 } else if (vars_to_check==ABENDS) {
876
877 close(sd);
878 my_tcp_connect (server_address, server_port, &sd);
879
880 xasprintf (&send_buffer,"S17\r\n");
881 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
882 if (result!=STATE_OK)
883 return result;
884
885 abended_threads=atoi(recv_buffer);
886
887 if (check_critical_value && abended_threads >= critical_value)
888 result=STATE_CRITICAL;
889 else if (check_warning_value && abended_threads >= warning_value)
890 result=STATE_WARNING;
891
892 xasprintf (&output_message,_("%lu abended threads|Abends=%lu;%lu;%lu;;"),
893 abended_threads,
894 abended_threads,
895 warning_value,
896 critical_value);
897
898 /* check # of current service processes (Netware 5.x only) */
899 } else if (vars_to_check==CSPROCS) {
900
901 close(sd);
902 my_tcp_connect (server_address, server_port, &sd);
903
904 xasprintf (&send_buffer,"S20\r\n");
905 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
906 if (result!=STATE_OK)
907 return result;
908
909 max_service_processes=atoi(recv_buffer);
910
911 close(sd);
912 my_tcp_connect (server_address, server_port, &sd);
913
914 xasprintf (&send_buffer,"S21\r\n");
915 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
916 if (result!=STATE_OK)
917 return result;
918
919 current_service_processes=atoi(recv_buffer);
920
921 if (check_critical_value && current_service_processes >= critical_value)
922 result=STATE_CRITICAL;
923 else if (check_warning_value && current_service_processes >= warning_value)
924 result=STATE_WARNING;
925
926 xasprintf (&output_message,
927 _("%lu current service processes (%lu max)|Processes=%lu;%lu;%lu;0;%lu"),
928 current_service_processes,
929 max_service_processes,
930 current_service_processes,
931 warning_value,
932 critical_value,
933 max_service_processes);
934
935 /* check # Timesync Status */
936 } else if (vars_to_check==TSYNC) {
937
938 close(sd);
939 my_tcp_connect (server_address, server_port, &sd);
940
941 xasprintf (&send_buffer,"S22\r\n");
942 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
943 if (result!=STATE_OK)
944 return result;
945
946 time_sync_status=atoi(recv_buffer);
947
948 if (time_sync_status==0) {
949 result=STATE_CRITICAL;
950 xasprintf (&output_message,_("CRITICAL - Time not in sync with network!"));
951 }
952 else {
953 xasprintf (&output_message,_("OK - Time in sync with network!"));
954 }
955
956
957
958
959
960 /* check LRU sitting time in secondss */
961 } else if (vars_to_check==LRUS) {
962
963 close(sd);
964 my_tcp_connect (server_address, server_port, &sd);
965
966 send_buffer = strdup ("S4\r\n");
967 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
968 if (result!=STATE_OK)
969 return result;
970 lru_time=strtoul(recv_buffer,NULL,10);
971
972 if (check_critical_value && lru_time <= critical_value)
973 result=STATE_CRITICAL;
974 else if (check_warning_value && lru_time <= warning_value)
975 result=STATE_WARNING;
976 xasprintf (&output_message,_("LRU sitting time = %lu seconds"),lru_time);
977
978
979 /* check % dirty cacheobuffers as a percentage of the total*/
980 } else if (vars_to_check==DCB) {
981
982 close(sd);
983 my_tcp_connect (server_address, server_port, &sd);
984
985 send_buffer = strdup ("S6\r\n");
986 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
987 if (result!=STATE_OK)
988 return result;
989 dirty_cache_buffers=atoi(recv_buffer);
990
991 if (check_critical_value && dirty_cache_buffers <= critical_value)
992 result=STATE_CRITICAL;
993 else if (check_warning_value && dirty_cache_buffers <= warning_value)
994 result=STATE_WARNING;
995 xasprintf (&output_message,_("Dirty cache buffers = %lu%% of the total|DCB=%lu;%lu;%lu;0;100"),
996 dirty_cache_buffers,
997 dirty_cache_buffers,
998 warning_value,
999 critical_value);
1000
1001 /* check % total cache buffers as a percentage of the original*/
1002 } else if (vars_to_check==TCB) {
1003
1004 close(sd);
1005 my_tcp_connect (server_address, server_port, &sd);
1006
1007 send_buffer = strdup ("S7\r\n");
1008 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1009 if (result!=STATE_OK)
1010 return result;
1011 total_cache_buffers=atoi(recv_buffer);
1012
1013 if (check_critical_value && total_cache_buffers <= critical_value)
1014 result=STATE_CRITICAL;
1015 else if (check_warning_value && total_cache_buffers <= warning_value)
1016 result=STATE_WARNING;
1017 xasprintf (&output_message,_("Total cache buffers = %lu%% of the original|TCB=%lu;%lu;%lu;0;100"),
1018 total_cache_buffers,
1019 total_cache_buffers,
1020 warning_value,
1021 critical_value);
1022
1023 } else if (vars_to_check==DSVER) {
1024
1025 close(sd);
1026 my_tcp_connect (server_address, server_port, &sd);
1027
1028 xasprintf (&send_buffer,"S13\r\n");
1029 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1030 if (result!=STATE_OK)
1031 return result;
1032
1033 recv_buffer[strlen(recv_buffer)-1]=0;
1034
1035 xasprintf (&output_message,_("NDS Version %s"),recv_buffer);
1036
1037 } else if (vars_to_check==UPTIME) {
1038
1039 close(sd);
1040 my_tcp_connect (server_address, server_port, &sd);
1041
1042 xasprintf (&send_buffer,"UPTIME\r\n");
1043 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1044 if (result!=STATE_OK)
1045 return result;
1046
1047
1048 recv_buffer[sizeof(recv_buffer)-1]=0;
1049 recv_buffer[strlen(recv_buffer)-1]=0;
1050
1051 xasprintf (&output_message,_("Up %s"),recv_buffer);
1052
1053 } else if (vars_to_check==NLM) {
1054
1055 close(sd);
1056 my_tcp_connect (server_address, server_port, &sd);
1057
1058 xasprintf (&send_buffer,"S24:%s\r\n",nlm_name);
1059 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1060 if (result!=STATE_OK)
1061 return result;
1062
1063 recv_buffer[strlen(recv_buffer)-1]=0;
1064 if (strcmp(recv_buffer,"-1")) {
1065 xasprintf (&output_message,_("Module %s version %s is loaded"),nlm_name,recv_buffer);
1066 } else {
1067 result=STATE_CRITICAL;
1068 xasprintf (&output_message,_("Module %s is not loaded"),nlm_name);
1069
1070 }
1071 } else if (vars_to_check==NRMP) {
1072
1073 xasprintf (&send_buffer,"NRMP:%s\r\n",nrmp_name);
1074 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1075 if (result!=STATE_OK)
1076 return result;
1077
1078 if (!strcmp(recv_buffer,"-1\n")) {
1079 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrmp_name);
1080 result=STATE_CRITICAL;
1081 } else {
1082 nrmp_value=strtoul(recv_buffer,NULL,10);
1083 if (check_critical_value && nrmp_value <= critical_value)
1084 result=STATE_CRITICAL;
1085 else if (check_warning_value && nrmp_value <= warning_value)
1086 result=STATE_WARNING;
1087 xasprintf (&output_message,
1088 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1089 nrmp_name,
1090 nrmp_value,
1091 nrmp_name,
1092 nrmp_value,
1093 warning_value,
1094 critical_value);
1095 }
1096
1097 } else if (vars_to_check==NRMM) {
1098
1099 xasprintf (&send_buffer,"NRMM:%s\r\n",nrmm_name);
1100 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1101 if (result!=STATE_OK)
1102 return result;
1103
1104 if (!strcmp(recv_buffer,"-1\n")) {
1105 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrmm_name);
1106 result=STATE_CRITICAL;
1107 } else {
1108 nrmm_value=strtoul(recv_buffer,NULL,10);
1109 if (check_critical_value && nrmm_value <= critical_value)
1110 result=STATE_CRITICAL;
1111 else if (check_warning_value && nrmm_value <= warning_value)
1112 result=STATE_WARNING;
1113 xasprintf (&output_message,
1114 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1115 nrmm_name,
1116 nrmm_value,
1117 nrmm_name,
1118 nrmm_value,
1119 warning_value,
1120 critical_value);
1121 }
1122
1123 } else if (vars_to_check==NRMS) {
1124
1125 xasprintf (&send_buffer,"NRMS:%s\r\n",nrms_name);
1126 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1127 if (result!=STATE_OK)
1128 return result;
1129
1130 if (!strcmp(recv_buffer,"-1\n")) {
1131 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nrms_name);
1132 result=STATE_CRITICAL;
1133 } else {
1134 nrms_value=strtoul(recv_buffer,NULL,10);
1135 if (check_critical_value && nrms_value >= critical_value)
1136 result=STATE_CRITICAL;
1137 else if (check_warning_value && nrms_value >= warning_value)
1138 result=STATE_WARNING;
1139 xasprintf (&output_message,
1140 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1141 nrms_name,
1142 nrms_value,
1143 nrms_name,
1144 nrms_value,
1145 warning_value,
1146 critical_value);
1147 }
1148
1149 } else if (vars_to_check==NSS1) {
1150
1151 xasprintf (&send_buffer,"NSS1:%s\r\n",nss1_name);
1152 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1153 if (result!=STATE_OK)
1154 return result;
1155
1156 if (!strcmp(recv_buffer,"-1\n")) {
1157 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss1_name);
1158 result=STATE_CRITICAL;
1159 } else {
1160 nss1_value=strtoul(recv_buffer,NULL,10);
1161 if (check_critical_value && nss1_value >= critical_value)
1162 result=STATE_CRITICAL;
1163 else if (check_warning_value && nss1_value >= warning_value)
1164 result=STATE_WARNING;
1165 xasprintf (&output_message,
1166 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1167 nss1_name,
1168 nss1_value,
1169 nss1_name,
1170 nss1_value,
1171 warning_value,
1172 critical_value);
1173 }
1174
1175 } else if (vars_to_check==NSS2) {
1176
1177 xasprintf (&send_buffer,"NSS2:%s\r\n",nss2_name);
1178 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1179 if (result!=STATE_OK)
1180 return result;
1181
1182 if (!strcmp(recv_buffer,"-1\n")) {
1183 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss2_name);
1184 result=STATE_CRITICAL;
1185 } else {
1186 nss2_value=strtoul(recv_buffer,NULL,10);
1187 if (check_critical_value && nss2_value >= critical_value)
1188 result=STATE_CRITICAL;
1189 else if (check_warning_value && nss2_value >= warning_value)
1190 result=STATE_WARNING;
1191 xasprintf (&output_message,
1192 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1193 nss2_name,
1194 nss2_value,
1195 nss2_name,
1196 nss2_value,
1197 warning_value,
1198 critical_value);
1199 }
1200
1201 } else if (vars_to_check==NSS3) {
1202
1203 xasprintf (&send_buffer,"NSS3:%s\r\n",nss3_name);
1204 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1205 if (result!=STATE_OK)
1206 return result;
1207
1208 if (!strcmp(recv_buffer,"-1\n")) {
1209 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss3_name);
1210 result=STATE_CRITICAL;
1211 } else {
1212 nss3_value=strtoul(recv_buffer,NULL,10);
1213 if (check_critical_value && nss3_value >= critical_value)
1214 result=STATE_CRITICAL;
1215 else if (check_warning_value && nss3_value >= warning_value)
1216 result=STATE_WARNING;
1217 xasprintf (&output_message,
1218 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1219 nss3_name,
1220 nss3_value,
1221 nss3_name,
1222 nss3_value,
1223 warning_value,
1224 critical_value);
1225 }
1226
1227 } else if (vars_to_check==NSS4) {
1228
1229 xasprintf (&send_buffer,"NSS4:%s\r\n",nss4_name);
1230 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1231 if (result!=STATE_OK)
1232 return result;
1233
1234 if (!strcmp(recv_buffer,"-1\n")) {
1235 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss4_name);
1236 result=STATE_CRITICAL;
1237 } else {
1238 nss4_value=strtoul(recv_buffer,NULL,10);
1239 if (check_critical_value && nss4_value >= critical_value)
1240 result=STATE_CRITICAL;
1241 else if (check_warning_value && nss4_value >= warning_value)
1242 result=STATE_WARNING;
1243 xasprintf (&output_message,
1244 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1245 nss4_name,
1246 nss4_value,
1247 nss4_name,
1248 nss4_value,
1249 warning_value,
1250 critical_value);
1251 }
1252
1253 } else if (vars_to_check==NSS5) {
1254
1255 xasprintf (&send_buffer,"NSS5:%s\r\n",nss5_name);
1256 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1257 if (result!=STATE_OK)
1258 return result;
1259
1260 if (!strcmp(recv_buffer,"-1\n")) {
1261 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss5_name);
1262 result=STATE_CRITICAL;
1263 } else {
1264 nss5_value=strtoul(recv_buffer,NULL,10);
1265 if (check_critical_value && nss5_value >= critical_value)
1266 result=STATE_CRITICAL;
1267 else if (check_warning_value && nss5_value >= warning_value)
1268 result=STATE_WARNING;
1269 xasprintf (&output_message,
1270 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1271 nss5_name,
1272 nss5_value,
1273 nss5_name,
1274 nss5_value,
1275 warning_value,
1276 critical_value);
1277 }
1278
1279 } else if (vars_to_check==NSS6) {
1280
1281 xasprintf (&send_buffer,"NSS6:%s\r\n",nss6_name);
1282 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1283 if (result!=STATE_OK)
1284 return result;
1285
1286 if (!strcmp(recv_buffer,"-1\n")) {
1287 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss6_name);
1288 result=STATE_CRITICAL;
1289 } else {
1290 nss6_value=strtoul(recv_buffer,NULL,10);
1291 if (check_critical_value && nss6_value >= critical_value)
1292 result=STATE_CRITICAL;
1293 else if (check_warning_value && nss6_value >= warning_value)
1294 result=STATE_WARNING;
1295 xasprintf (&output_message,
1296 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1297 nss6_name,
1298 nss6_value,
1299 nss6_name,
1300 nss6_value,
1301 warning_value,
1302 critical_value);
1303 }
1304
1305 } else if (vars_to_check==NSS7) {
1306
1307 xasprintf (&send_buffer,"NSS7:%s\r\n",nss7_name);
1308 result=send_tcp_request(sd,send_buffer,recv_buffer,sizeof(recv_buffer));
1309 if (result!=STATE_OK)
1310 return result;
1311
1312 if (!strcmp(recv_buffer,"-1\n")) {
1313 xasprintf (&output_message,_("CRITICAL - Value '%s' does not exist!"),nss7_name);
1314 result=STATE_CRITICAL;
1315 } else {
1316 nss7_value=strtoul(recv_buffer,NULL,10);
1317 if (check_critical_value && nss7_value >= critical_value)
1318 result=STATE_CRITICAL;
1319 else if (check_warning_value && nss7_value >= warning_value)
1320 result=STATE_WARNING;
1321 xasprintf (&output_message,
1322 _("%s is %lu|%s=%lu;%lu;%lu;;"),
1323 nss7_name,
1324 nss7_value,
1325 nss7_name,
1326 nss7_value,
1327 warning_value,
1328 critical_value);
1329 }
1330
1331
1332}
1333 else {
1334
1335 output_message = strdup (_("Nothing to check!\n"));
1336 result=STATE_UNKNOWN;
1337
1338 }
1339
1340 close (sd);
1341
1342 /* reset timeout */
1343 alarm(0);
1344
1345 printf("%s%s\n",netware_version,output_message);
1346
1347 return result;
1348}
1349
1350
1351
1352/* process command-line arguments */
1353int process_arguments(int argc, char **argv) {
1354 int c;
1355
1356 int option = 0;
1357 static struct option longopts[] =
1358 {
1359 {"port", required_argument,0,'p'},
1360 {"timeout", required_argument,0,'t'},
1361 {"critical", required_argument,0,'c'},
1362 {"warning", required_argument,0,'w'},
1363 {"variable", required_argument,0,'v'},
1364 {"hostname", required_argument,0,'H'},
1365 {"osversion",no_argument, 0,'o'},
1366 {"version", no_argument, 0,'V'},
1367 {"help", no_argument, 0,'h'},
1368 {0,0,0,0}
1369 };
1370
1371 /* no options were supplied */
1372 if (argc<2) return ERROR;
1373
1374 /* backwards compatibility */
1375 if (! is_option(argv[1])) {
1376 server_address=argv[1];
1377 argv[1]=argv[0];
1378 argv=&argv[1];
1379 argc--;
1380 }
1381
1382 for (c=1;c<argc;c++) {
1383 if (strcmp("-to",argv[c])==0)
1384 strcpy(argv[c],"-t");
1385 else if (strcmp("-wv",argv[c])==0)
1386 strcpy(argv[c],"-w");
1387 else if (strcmp("-cv",argv[c])==0)
1388 strcpy(argv[c],"-c");
1389 }
1390
1391 while (1) {
1392 c = getopt_long(argc,argv,"+hoVH:t:c:w:p:v:",longopts,&option);
1393
1394 if (c==-1||c==EOF||c==1)
1395 break;
1396
1397 switch (c)
1398 {
1399 case '?': /* print short usage statement if args not parsable */
1400 usage5 ();
1401 case 'h': /* help */
1402 print_help();
1403 exit(STATE_UNKNOWN);
1404 case 'V': /* version */
1405 print_revision(progname, NP_VERSION);
1406 exit(STATE_UNKNOWN);
1407 case 'H': /* hostname */
1408 server_address=optarg;
1409 break;
1410 case 'o': /* display nos version */
1411 check_netware_version = true;
1412 break;
1413 case 'p': /* port */
1414 if (is_intnonneg(optarg))
1415 server_port=atoi(optarg);
1416 else
1417 die(STATE_UNKNOWN,_("Server port an integer\n"));
1418 break;
1419 case 'v':
1420 if (strlen(optarg)<3)
1421 return ERROR;
1422 if (!strcmp(optarg,"LOAD1"))
1423 vars_to_check=LOAD1;
1424 else if (!strcmp(optarg,"LOAD5"))
1425 vars_to_check=LOAD5;
1426 else if (!strcmp(optarg,"LOAD15"))
1427 vars_to_check=LOAD15;
1428 else if (!strcmp(optarg,"CONNS"))
1429 vars_to_check=CONNS;
1430 else if (!strcmp(optarg,"LTCH"))
1431 vars_to_check=LTCH;
1432 else if (!strcmp(optarg,"DCB"))
1433 vars_to_check=DCB;
1434 else if (!strcmp(optarg,"TCB"))
1435 vars_to_check=TCB;
1436 else if (!strcmp(optarg,"CBUFF"))
1437 vars_to_check=CBUFF;
1438 else if (!strcmp(optarg,"CDBUFF"))
1439 vars_to_check=CDBUFF;
1440 else if (!strcmp(optarg,"LRUM"))
1441 vars_to_check=LRUM;
1442 else if (!strcmp(optarg,"LRUS"))
1443 vars_to_check=LRUS;
1444 else if (strncmp(optarg,"VPF",3)==0) {
1445 vars_to_check=VPF;
1446 volume_name = strdup (optarg+3);
1447 if (!strcmp(volume_name,""))
1448 volume_name = strdup ("SYS");
1449 }
1450 else if (strncmp(optarg,"VKF",3)==0) {
1451 vars_to_check=VKF;
1452 volume_name = strdup (optarg+3);
1453 if (!strcmp(volume_name,""))
1454 volume_name = strdup ("SYS");
1455 }
1456 else if (strncmp(optarg,"VMF",3)==0) {
1457 vars_to_check=VMF;
1458 volume_name = strdup (optarg+3);
1459 if (!strcmp(volume_name,""))
1460 volume_name = strdup ("SYS");
1461 }
1462 else if (!strcmp(optarg,"DSDB"))
1463 vars_to_check=DSDB;
1464 else if (!strcmp(optarg,"LOGINS"))
1465 vars_to_check=LOGINS;
1466 else if (!strcmp(optarg,"NRMH"))
1467 vars_to_check=NRMH;
1468 else if (!strcmp(optarg,"UPRB"))
1469 vars_to_check=UPRB;
1470 else if (!strcmp(optarg,"PUPRB"))
1471 vars_to_check=PUPRB;
1472 else if (!strncmp(optarg,"SAPENTRIES",10)) {
1473 vars_to_check=SAPENTRIES;
1474 if (strlen(optarg)>10)
1475 sap_number=atoi(optarg+10);
1476 else
1477 sap_number=-1;
1478 }
1479 else if (!strcmp(optarg,"OFILES"))
1480 vars_to_check=OFILES;
1481 else if (strncmp(optarg,"VKP",3)==0) {
1482 vars_to_check=VKP;
1483 volume_name = strdup (optarg+3);
1484 if (!strcmp(volume_name,""))
1485 volume_name = strdup ("SYS");
1486 }
1487 else if (strncmp(optarg,"VMP",3)==0) {
1488 vars_to_check=VMP;
1489 volume_name = strdup (optarg+3);
1490 if (!strcmp(volume_name,""))
1491 volume_name = strdup ("SYS");
1492 }
1493 else if (strncmp(optarg,"VMU",3)==0) {
1494 vars_to_check=VMU;
1495 volume_name = strdup (optarg+3);
1496 if (!strcmp(volume_name,""))
1497 volume_name = strdup ("SYS");
1498 }
1499 else if (strncmp(optarg,"VPU",3)==0) {
1500 vars_to_check=VPU;
1501 volume_name = strdup (optarg+3);
1502 if (!strcmp(volume_name,""))
1503 volume_name = strdup ("SYS");
1504 }
1505 else if (strncmp(optarg,"VPP",3)==0) {
1506 vars_to_check=VPP;
1507 volume_name = strdup (optarg+3);
1508 if (!strcmp(volume_name,""))
1509 volume_name = strdup ("SYS");
1510 }
1511 else if (strncmp(optarg,"VKNP",4)==0) {
1512 vars_to_check=VKNP;
1513 volume_name = strdup (optarg+4);
1514 if (!strcmp(volume_name,""))
1515 volume_name = strdup ("SYS");
1516 }
1517 else if (strncmp(optarg,"VPNP",4)==0) {
1518 vars_to_check=VPNP;
1519 volume_name = strdup (optarg+4);
1520 if (!strcmp(volume_name,""))
1521 volume_name = strdup("SYS");
1522 }
1523 else if (!strcmp(optarg,"ABENDS"))
1524 vars_to_check=ABENDS;
1525 else if (!strcmp(optarg,"CSPROCS"))
1526 vars_to_check=CSPROCS;
1527 else if (!strcmp(optarg,"TSYNC"))
1528 vars_to_check=TSYNC;
1529 else if (!strcmp(optarg,"DSVER"))
1530 vars_to_check=DSVER;
1531 else if (!strcmp(optarg,"UPTIME")) {
1532 vars_to_check=UPTIME;
1533 }
1534 else if (strncmp(optarg,"NLM:",4)==0) {
1535 vars_to_check=NLM;
1536 nlm_name=strdup (optarg+4);
1537 }
1538 else if (strncmp(optarg,"NRMP",4)==0) {
1539 vars_to_check=NRMP;
1540 nrmp_name = strdup (optarg+4);
1541 if (!strcmp(nrmp_name,""))
1542 nrmp_name = strdup ("AVAILABLE_MEMORY");
1543 }
1544 else if (strncmp(optarg,"NRMM",4)==0) {
1545 vars_to_check=NRMM;
1546 nrmm_name = strdup (optarg+4);
1547 if (!strcmp(nrmm_name,""))
1548 nrmm_name = strdup ("AVAILABLE_CACHE_MEMORY");
1549
1550 }
1551
1552 else if (strncmp(optarg,"NRMS",4)==0) {
1553 vars_to_check=NRMS;
1554 nrms_name = strdup (optarg+4);
1555 if (!strcmp(nrms_name,""))
1556 nrms_name = strdup ("USED_SWAP_SPACE");
1557
1558 }
1559
1560 else if (strncmp(optarg,"NSS1",4)==0) {
1561 vars_to_check=NSS1;
1562 nss1_name = strdup (optarg+4);
1563 if (!strcmp(nss1_name,""))
1564 nss1_name = strdup ("CURRENTBUFFERCACHESIZE");
1565
1566 }
1567
1568 else if (strncmp(optarg,"NSS2",4)==0) {
1569 vars_to_check=NSS2;
1570 nss2_name = strdup (optarg+4);
1571 if (!strcmp(nss2_name,""))
1572 nss2_name = strdup ("CACHEHITS");
1573
1574 }
1575
1576 else if (strncmp(optarg,"NSS3",4)==0) {
1577 vars_to_check=NSS3;
1578 nss3_name = strdup (optarg+4);
1579 if (!strcmp(nss3_name,""))
1580 nss3_name = strdup ("CACHEGITPERCENT");
1581
1582 }
1583
1584 else if (strncmp(optarg,"NSS4",4)==0) {
1585 vars_to_check=NSS4;
1586 nss4_name = strdup (optarg+4);
1587 if (!strcmp(nss4_name,""))
1588 nss4_name = strdup ("CURRENTOPENCOUNT");
1589
1590 }
1591
1592 else if (strncmp(optarg,"NSS5",4)==0) {
1593 vars_to_check=NSS5;
1594 nss5_name = strdup (optarg+4);
1595 if (!strcmp(nss5_name,""))
1596 nss5_name = strdup ("CACHEMISSES");
1597
1598 }
1599
1600
1601 else if (strncmp(optarg,"NSS6",4)==0) {
1602 vars_to_check=NSS6;
1603 nss6_name = strdup (optarg+4);
1604 if (!strcmp(nss6_name,""))
1605 nss6_name = strdup ("PENDINGWORKSCOUNT");
1606
1607 }
1608
1609
1610 else if (strncmp(optarg,"NSS7",4)==0) {
1611 vars_to_check=NSS7;
1612 nss7_name = strdup (optarg+4);
1613 if (!strcmp(nss7_name,""))
1614 nss7_name = strdup ("CACHESIZE");
1615
1616 }
1617
1618
1619 else
1620 return ERROR;
1621 break;
1622 case 'w': /* warning threshold */
1623 warning_value=strtoul(optarg,NULL,10);
1624 check_warning_value = true;
1625 break;
1626 case 'c': /* critical threshold */
1627 critical_value=strtoul(optarg,NULL,10);
1628 check_critical_value = true;
1629 break;
1630 case 't': /* timeout */
1631 socket_timeout=atoi(optarg);
1632 if (socket_timeout<=0)
1633 return ERROR;
1634 }
1635
1636 }
1637
1638 return OK;
1639}
1640
1641
1642
1643void print_help(void)
1644{
1645 char *myport;
1646 xasprintf (&myport, "%d", PORT);
1647
1648 print_revision (progname, NP_VERSION);
1649
1650 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
1651 printf (COPYRIGHT, copyright, email);
1652
1653 printf ("%s\n", _("This plugin attempts to contact the MRTGEXT NLM running on a"));
1654 printf ("%s\n", _("Novell server to gather the requested system information."));
1655
1656 printf ("\n\n");
1657
1658 print_usage();
1659
1660 printf (UT_HELP_VRSN);
1661 printf (UT_EXTRA_OPTS);
1662
1663 printf (UT_HOST_PORT, 'p', myport);
1664
1665 printf (" %s\n", "-v, --variable=STRING");
1666 printf (" %s\n", _("Variable to check. Valid variables include:"));
1667 printf (" %s\n", _("LOAD1 = 1 minute average CPU load"));
1668 printf (" %s\n", _("LOAD5 = 5 minute average CPU load"));
1669 printf (" %s\n", _("LOAD15 = 15 minute average CPU load"));
1670 printf (" %s\n", _("CSPROCS = number of current service processes (NW 5.x only)"));
1671 printf (" %s\n", _("ABENDS = number of abended threads (NW 5.x only)"));
1672 printf (" %s\n", _("UPTIME = server uptime"));
1673 printf (" %s\n", _("LTCH = percent long term cache hits"));
1674 printf (" %s\n", _("CBUFF = current number of cache buffers"));
1675 printf (" %s\n", _("CDBUFF = current number of dirty cache buffers"));
1676 printf (" %s\n", _("DCB = dirty cache buffers as a percentage of the total"));
1677 printf (" %s\n", _("TCB = dirty cache buffers as a percentage of the original"));
1678 printf (" %s\n", _("OFILES = number of open files"));
1679 printf (" %s\n", _(" VMF<vol> = MB of free space on Volume <vol>"));
1680 printf (" %s\n", _(" VMU<vol> = MB used space on Volume <vol>"));
1681 printf (" %s\n", _(" VPU<vol> = percent used space on Volume <vol>"));
1682 printf (" %s\n", _(" VMP<vol> = MB of purgeable space on Volume <vol>"));
1683 printf (" %s\n", _(" VPF<vol> = percent free space on volume <vol>"));
1684 printf (" %s\n", _(" VKF<vol> = KB of free space on volume <vol>"));
1685 printf (" %s\n", _(" VPP<vol> = percent purgeable space on volume <vol>"));
1686 printf (" %s\n", _(" VKP<vol> = KB of purgeable space on volume <vol>"));
1687 printf (" %s\n", _(" VPNP<vol> = percent not yet purgeable space on volume <vol>"));
1688 printf (" %s\n", _(" VKNP<vol> = KB of not yet purgeable space on volume <vol>"));
1689 printf (" %s\n", _(" LRUM = LRU sitting time in minutes"));
1690 printf (" %s\n", _(" LRUS = LRU sitting time in seconds"));
1691 printf (" %s\n", _(" DSDB = check to see if DS Database is open"));
1692 printf (" %s\n", _(" DSVER = NDS version"));
1693 printf (" %s\n", _(" UPRB = used packet receive buffers"));
1694 printf (" %s\n", _(" PUPRB = percent (of max) used packet receive buffers"));
1695 printf (" %s\n", _(" SAPENTRIES = number of entries in the SAP table"));
1696 printf (" %s\n", _(" SAPENTRIES<n> = number of entries in the SAP table for SAP type <n>"));
1697 printf (" %s\n", _(" TSYNC = timesync status"));
1698 printf (" %s\n", _(" LOGINS = check to see if logins are enabled"));
1699 printf (" %s\n", _(" CONNS = number of currently licensed connections"));
1700 printf (" %s\n", _(" NRMH = NRM Summary Status"));
1701 printf (" %s\n", _(" NRMP<stat> = Returns the current value for a NRM health item"));
1702 printf (" %s\n", _(" NRMM<stat> = Returns the current memory stats from NRM"));
1703 printf (" %s\n", _(" NRMS<stat> = Returns the current Swapfile stats from NRM"));
1704 printf (" %s\n", _(" NSS1<stat> = Statistics from _Admin:Manage_NSS\\GeneralStats.xml"));
1705 printf (" %s\n", _(" NSS3<stat> = Statistics from _Admin:Manage_NSS\\NameCache.xml"));
1706 printf (" %s\n", _(" NSS4<stat> = Statistics from _Admin:Manage_NSS\\FileStats.xml"));
1707 printf (" %s\n", _(" NSS5<stat> = Statistics from _Admin:Manage_NSS\\ObjectCache.xml"));
1708 printf (" %s\n", _(" NSS6<stat> = Statistics from _Admin:Manage_NSS\\Thread.xml"));
1709 printf (" %s\n", _(" NSS7<stat> = Statistics from _Admin:Manage_NSS\\AuthorizationCache.xml"));
1710 printf (" %s\n", _(" NLM:<nlm> = check if NLM is loaded and report version"));
1711 printf (" %s\n", _(" (e.g. NLM:TSANDS.NLM)"));
1712 printf ("\n");
1713 printf (" %s\n", "-w, --warning=INTEGER");
1714 printf (" %s\n", _("Threshold which will result in a warning status"));
1715 printf (" %s\n", "-c, --critical=INTEGER");
1716 printf (" %s\n", _("Threshold which will result in a critical status"));
1717 printf (" %s\n", "-o, --osversion");
1718 printf (" %s\n", _("Include server version string in results"));
1719
1720 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1721
1722 printf ("\n");
1723 printf ("%s\n", _("Notes:"));
1724 printf (" %s\n", _("- This plugin requires that the MRTGEXT.NLM file from James Drews' MRTG"));
1725 printf (" %s\n", _(" extension for NetWare be loaded on the Novell servers you wish to check."));
1726 printf (" %s\n", _(" (available from http://www.engr.wisc.edu/~drews/mrtg/)"));
1727 printf (" %s\n", _("- Values for critical thresholds should be lower than warning thresholds"));
1728 printf (" %s\n", _(" when the following variables are checked: VPF, VKF, LTCH, CBUFF, DCB, "));
1729 printf (" %s\n", _(" TCB, LRUS and LRUM."));
1730
1731 printf (UT_SUPPORT);
1732}
1733
1734
1735
1736void print_usage(void)
1737{
1738 printf ("%s\n", _("Usage:"));
1739 printf ("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n",progname);
1740}
diff --git a/plugins/check_overcr.c b/plugins/check_overcr.c
deleted file mode 100644
index 5165c828..00000000
--- a/plugins/check_overcr.c
+++ /dev/null
@@ -1,469 +0,0 @@
1/*****************************************************************************
2*
3* Monitoring check_overcr plugin
4*
5* License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team
7*
8* Description:
9*
10* This file contains the check_overcr plugin
11*
12* This plugin attempts to contact the Over-CR collector daemon running on the
13* remote UNIX server in order to gather the requested system information.
14*
15*
16* This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version.
20*
21* This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details.
25*
26* You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>.
28*
29*
30*****************************************************************************/
31
32const char *progname = "check_overcr";
33const char *copyright = "2000-2007";
34const char *email = "devel@monitoring-plugins.org";
35
36#include "common.h"
37#include "netutils.h"
38#include "utils.h"
39
40enum checkvar {
41 NONE,
42 LOAD1,
43 LOAD5,
44 LOAD15,
45 DPU,
46 PROCS,
47 NETSTAT,
48 UPTIME
49};
50
51enum {
52 PORT = 2000
53};
54
55char *server_address = NULL;
56int server_port = PORT;
57double warning_value = 0L;
58double critical_value = 0L;
59bool check_warning_value = false;
60bool check_critical_value = false;
61enum checkvar vars_to_check = NONE;
62int cmd_timeout = 1;
63
64int netstat_port = 0;
65char *disk_name = NULL;
66char *process_name = NULL;
67char send_buffer[MAX_INPUT_BUFFER];
68
69int process_arguments (int, char **);
70void print_usage (void);
71void print_help (void);
72
73int
74main (int argc, char **argv)
75{
76 int result = STATE_UNKNOWN;
77 char recv_buffer[MAX_INPUT_BUFFER];
78 char temp_buffer[MAX_INPUT_BUFFER];
79 char *temp_ptr = NULL;
80 bool found_disk = false;
81 unsigned long percent_used_disk_space = 100;
82 double load;
83 double load_1min;
84 double load_5min;
85 double load_15min;
86 int port_connections = 0;
87 int processes = 0;
88 double uptime_raw_hours;
89 int uptime_raw_minutes = 0;
90 int uptime_days = 0;
91 int uptime_hours = 0;
92 int uptime_minutes = 0;
93
94 setlocale (LC_ALL, "");
95 bindtextdomain (PACKAGE, LOCALEDIR);
96 textdomain (PACKAGE);
97
98 /* Parse extra opts if any */
99 argv=np_extra_opts (&argc, argv, progname);
100
101 if (process_arguments (argc, argv) == ERROR)
102 usage4 (_("Could not parse arguments"));
103
104 /* initialize alarm signal handling */
105 signal (SIGALRM, socket_timeout_alarm_handler);
106
107 /* set socket timeout */
108 alarm (socket_timeout);
109
110 result = process_tcp_request2 (server_address,
111 server_port,
112 send_buffer,
113 recv_buffer,
114 sizeof (recv_buffer));
115
116 switch (vars_to_check) {
117
118 case LOAD1:
119 case LOAD5:
120 case LOAD15:
121
122 if (result != STATE_OK)
123 die (result, _("Unknown error fetching load data\n"));
124
125 temp_ptr = (char *) strtok (recv_buffer, "\r\n");
126 if (temp_ptr == NULL)
127 die (STATE_CRITICAL, _("Invalid response from server - no load information\n"));
128 else
129 load_1min = strtod (temp_ptr, NULL);
130
131 temp_ptr = (char *) strtok (NULL, "\r\n");
132 if (temp_ptr == NULL)
133 die (STATE_CRITICAL, _("Invalid response from server after load 1\n"));
134 else
135 load_5min = strtod (temp_ptr, NULL);
136
137 temp_ptr = (char *) strtok (NULL, "\r\n");
138 if (temp_ptr == NULL)
139 die (STATE_CRITICAL, _("Invalid response from server after load 5\n"));
140 else
141 load_15min = strtod (temp_ptr, NULL);
142
143 switch (vars_to_check) {
144 case LOAD1:
145 strcpy (temp_buffer, "1");
146 load = load_1min;
147 break;
148 case LOAD5:
149 strcpy (temp_buffer, "5");
150 load = load_5min;
151 break;
152 default:
153 strcpy (temp_buffer, "15");
154 load = load_15min;
155 break;
156 }
157
158 if (check_critical_value && (load >= critical_value))
159 result = STATE_CRITICAL;
160 else if (check_warning_value && (load >= warning_value))
161 result = STATE_WARNING;
162
163 die (result,
164 _("Load %s - %s-min load average = %0.2f"),
165 state_text(result),
166 temp_buffer,
167 load);
168
169 break;
170
171 case DPU:
172
173 if (result != STATE_OK)
174 die (result, _("Unknown error fetching disk data\n"));
175
176 for (temp_ptr = (char *) strtok (recv_buffer, " ");
177 temp_ptr != NULL;
178 temp_ptr = (char *) strtok (NULL, " ")) {
179
180 if (!strcmp (temp_ptr, disk_name)) {
181 found_disk = true;
182 temp_ptr = (char *) strtok (NULL, "%");
183 if (temp_ptr == NULL)
184 die (STATE_CRITICAL, _("Invalid response from server\n"));
185 else
186 percent_used_disk_space = strtoul (temp_ptr, NULL, 10);
187 break;
188 }
189
190 temp_ptr = (char *) strtok (NULL, "\r\n");
191 }
192
193 /* error if we couldn't find the info for the disk */
194 if (!found_disk)
195 die (STATE_CRITICAL,
196 "CRITICAL - Disk '%s' non-existent or not mounted",
197 disk_name);
198
199 if (check_critical_value && (percent_used_disk_space >= critical_value))
200 result = STATE_CRITICAL;
201 else if (check_warning_value && (percent_used_disk_space >= warning_value))
202 result = STATE_WARNING;
203
204 die (result, "Disk %s - %lu%% used on %s", state_text(result), percent_used_disk_space, disk_name);
205
206 break;
207
208 case NETSTAT:
209
210 if (result != STATE_OK)
211 die (result, _("Unknown error fetching network status\n"));
212 else
213 port_connections = strtod (recv_buffer, NULL);
214
215 if (check_critical_value && (port_connections >= critical_value))
216 result = STATE_CRITICAL;
217 else if (check_warning_value && (port_connections >= warning_value))
218 result = STATE_WARNING;
219
220 die (result,
221 _("Net %s - %d connection%s on port %d"),
222 state_text(result),
223 port_connections,
224 (port_connections == 1) ? "" : "s",
225 netstat_port);
226
227 break;
228
229 case PROCS:
230
231 if (result != STATE_OK)
232 die (result, _("Unknown error fetching process status\n"));
233
234 temp_ptr = (char *) strtok (recv_buffer, "(");
235 if (temp_ptr == NULL)
236 die (STATE_CRITICAL, _("Invalid response from server\n"));
237
238 temp_ptr = (char *) strtok (NULL, ")");
239 if (temp_ptr == NULL)
240 die (STATE_CRITICAL, _("Invalid response from server\n"));
241 else
242 processes = strtod (temp_ptr, NULL);
243
244 if (check_critical_value && (processes >= critical_value))
245 result = STATE_CRITICAL;
246 else if (check_warning_value && (processes >= warning_value))
247 result = STATE_WARNING;
248
249 die (result,
250 _("Process %s - %d instance%s of %s running"),
251 state_text(result),
252 processes,
253 (processes == 1) ? "" : "s",
254 process_name);
255 break;
256
257 case UPTIME:
258
259 if (result != STATE_OK)
260 return result;
261
262 uptime_raw_hours = strtod (recv_buffer, NULL);
263 uptime_raw_minutes = (unsigned long) (uptime_raw_hours * 60.0);
264
265 if (check_critical_value && (uptime_raw_minutes <= critical_value))
266 result = STATE_CRITICAL;
267 else if (check_warning_value && (uptime_raw_minutes <= warning_value))
268 result = STATE_WARNING;
269
270 uptime_days = uptime_raw_minutes / 1440;
271 uptime_raw_minutes %= 1440;
272 uptime_hours = uptime_raw_minutes / 60;
273 uptime_raw_minutes %= 60;
274 uptime_minutes = uptime_raw_minutes;
275
276 die (result,
277 _("Uptime %s - Up %d days %d hours %d minutes"),
278 state_text(result),
279 uptime_days,
280 uptime_hours,
281 uptime_minutes);
282 break;
283
284 default:
285 die (STATE_UNKNOWN, _("Nothing to check!\n"));
286 break;
287 }
288}
289
290
291/* process command-line arguments */
292int
293process_arguments (int argc, char **argv)
294{
295 int c;
296
297 int option = 0;
298 static struct option longopts[] = {
299 {"port", required_argument, 0, 'p'},
300 {"timeout", required_argument, 0, 't'},
301 {"critical", required_argument, 0, 'c'},
302 {"warning", required_argument, 0, 'w'},
303 {"variable", required_argument, 0, 'v'},
304 {"hostname", required_argument, 0, 'H'},
305 {"version", no_argument, 0, 'V'},
306 {"help", no_argument, 0, 'h'},
307 {0, 0, 0, 0}
308 };
309
310 /* no options were supplied */
311 if (argc < 2)
312 return ERROR;
313
314 /* backwards compatibility */
315 if (!is_option (argv[1])) {
316 server_address = argv[1];
317 argv[1] = argv[0];
318 argv = &argv[1];
319 argc--;
320 }
321
322 for (c = 1; c < argc; c++) {
323 if (strcmp ("-to", argv[c]) == 0)
324 strcpy (argv[c], "-t");
325 else if (strcmp ("-wv", argv[c]) == 0)
326 strcpy (argv[c], "-w");
327 else if (strcmp ("-cv", argv[c]) == 0)
328 strcpy (argv[c], "-c");
329 }
330
331 while (1) {
332 c = getopt_long (argc, argv, "+hVH:t:c:w:p:v:", longopts,
333 &option);
334
335 if (c == -1 || c == EOF || c == 1)
336 break;
337
338 switch (c) {
339 case '?': /* print short usage statement if args not parsable */
340 usage5 ();
341 case 'h': /* help */
342 print_help ();
343 exit (STATE_UNKNOWN);
344 case 'V': /* version */
345 print_revision (progname, NP_VERSION);
346 exit (STATE_UNKNOWN);
347 case 'H': /* hostname */
348 server_address = optarg;
349 break;
350 case 'p': /* port */
351 if (is_intnonneg (optarg))
352 server_port = atoi (optarg);
353 else
354 die (STATE_UNKNOWN,
355 _("Server port an integer\n"));
356 break;
357 case 'v': /* variable */
358 if (strcmp (optarg, "LOAD") == 0) {
359 strcpy (send_buffer, "LOAD\r\nQUIT\r\n");
360 if (strcmp (optarg, "LOAD1") == 0)
361 vars_to_check = LOAD1;
362 else if (strcmp (optarg, "LOAD5") == 0)
363 vars_to_check = LOAD5;
364 else if (strcmp (optarg, "LOAD15") == 0)
365 vars_to_check = LOAD15;
366 }
367 else if (strcmp (optarg, "UPTIME") == 0) {
368 vars_to_check = UPTIME;
369 strcpy (send_buffer, "UPTIME\r\n");
370 }
371 else if (strstr (optarg, "PROC") == optarg) {
372 vars_to_check = PROCS;
373 process_name = strscpy (process_name, optarg + 4);
374 sprintf (send_buffer, "PROCESS %s\r\n", process_name);
375 }
376 else if (strstr (optarg, "NET") == optarg) {
377 vars_to_check = NETSTAT;
378 netstat_port = atoi (optarg + 3);
379 sprintf (send_buffer, "NETSTAT %d\r\n", netstat_port);
380 }
381 else if (strstr (optarg, "DPU") == optarg) {
382 vars_to_check = DPU;
383 strcpy (send_buffer, "DISKSPACE\r\n");
384 disk_name = strscpy (disk_name, optarg + 3);
385 }
386 else
387 return ERROR;
388 break;
389 case 'w': /* warning threshold */
390 warning_value = strtoul (optarg, NULL, 10);
391 check_warning_value = true;
392 break;
393 case 'c': /* critical threshold */
394 critical_value = strtoul (optarg, NULL, 10);
395 check_critical_value = true;
396 break;
397 case 't': /* timeout */
398 socket_timeout = atoi (optarg);
399 if (socket_timeout <= 0)
400 return ERROR;
401 }
402
403 }
404 return OK;
405}
406
407
408void
409print_help (void)
410{
411 char *myport;
412 xasprintf (&myport, "%d", PORT);
413
414 print_revision (progname, NP_VERSION);
415
416 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
417 printf (COPYRIGHT, copyright, email);
418
419 printf ("%s\n", _("This plugin attempts to contact the Over-CR collector daemon running on the"));
420 printf ("%s\n", _("remote UNIX server in order to gather the requested system information."));
421
422 printf ("\n\n");
423
424 print_usage ();
425
426 printf (UT_HELP_VRSN);
427 printf (UT_EXTRA_OPTS);
428
429 printf (UT_HOST_PORT, 'p', myport);
430
431 printf (" %s\n", "-w, --warning=INTEGER");
432 printf (" %s\n", _("Threshold which will result in a warning status"));
433 printf (" %s\n", "-c, --critical=INTEGER");
434 printf (" %s\n", _("Threshold which will result in a critical status"));
435 printf (" %s\n", "-v, --variable=STRING");
436 printf (" %s\n", _("Variable to check. Valid variables include:"));
437 printf (" %s\n", _("LOAD1 = 1 minute average CPU load"));
438 printf (" %s\n", _("LOAD5 = 5 minute average CPU load"));
439 printf (" %s\n", _("LOAD15 = 15 minute average CPU load"));
440 printf (" %s\n", _("DPU<filesys> = percent used disk space on filesystem <filesys>"));
441 printf (" %s\n", _("PROC<process> = number of running processes with name <process>"));
442 printf (" %s\n", _("NET<port> = number of active connections on TCP port <port>"));
443 printf (" %s\n", _("UPTIME = system uptime in seconds"));
444
445 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
446
447 printf (UT_VERBOSE);
448
449 printf ("\n");
450 printf ("%s\n", _("This plugin requires that Eric Molitors' Over-CR collector daemon be"));
451 printf ("%s\n", _("running on the remote server."));
452 printf ("%s\n", _("Over-CR can be downloaded from http://www.molitor.org/overcr"));
453 printf ("%s\n", _("This plugin was tested with version 0.99.53 of the Over-CR collector"));
454
455 printf ("\n");
456 printf ("%s\n", _("Notes:"));
457 printf (" %s\n", _("For the available options, the critical threshold value should always be"));
458 printf (" %s\n", _("higher than the warning threshold value, EXCEPT with the uptime variable"));
459
460 printf (UT_SUPPORT);
461}
462
463
464void
465print_usage (void)
466{
467 printf ("%s\n", _("Usage:"));
468 printf ("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n", progname);
469}
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
index 94d589e1..84305adb 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -1,95 +1,75 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_pgsql plugin 3 * Monitoring check_pgsql plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2011 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_pgsql plugin 10 * This file contains the check_pgsql plugin
11* 11 *
12* Test whether a PostgreSQL Database is accepting connections. 12 * Test whether a PostgreSQL Database is accepting connections.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
31const char *progname = "check_pgsql"; 32const char *progname = "check_pgsql";
32const char *copyright = "1999-2011"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
34 35
35#include "common.h" 36#include "common.h"
36#include "utils.h" 37#include "utils.h"
37#include "utils_cmd.h" 38#include "utils_cmd.h"
39#include "check_pgsql.d/config.h"
40#include "thresholds.h"
38 41
39#include "netutils.h" 42#include "netutils.h"
40#include <libpq-fe.h> 43#include <libpq-fe.h>
41#include <pg_config_manual.h> 44#include <pg_config_manual.h>
42 45
43#define DEFAULT_DB "template1"
44#define DEFAULT_HOST "127.0.0.1" 46#define DEFAULT_HOST "127.0.0.1"
45 47
46/* return the PSQL server version as a 3-tuple */ 48/* return the PSQL server version as a 3-tuple */
47#define PSQL_SERVER_VERSION3(server_version) \ 49#define PSQL_SERVER_VERSION3(server_version) \
48 (server_version) / 10000, \ 50 (server_version) / 10000, (server_version) / 100 - (int)((server_version) / 10000) * 100, \
49 (server_version) / 100 - (int)((server_version) / 10000) * 100, \ 51 (server_version) - (int)((server_version) / 100) * 100
50 (server_version) - (int)((server_version) / 100) * 100
51/* return true if the given host is a UNIX domain socket */ 52/* return true if the given host is a UNIX domain socket */
52#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) \ 53#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
53 ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
54/* return a 3-tuple identifying a host/port independent of the socket type */ 54/* return a 3-tuple identifying a host/port independent of the socket type */
55#define PSQL_SOCKET3(host, port) \ 55#define PSQL_SOCKET3(host, port) \
56 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \ 56 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port
57 PSQL_IS_UNIX_DOMAIN_SOCKET (host) ? "/.s.PGSQL." : ":", \ 57
58 port 58typedef struct {
59 59 int errorcode;
60enum { 60 check_pgsql_config config;
61 DEFAULT_PORT = 5432, 61} check_pgsql_config_wrapper;
62 DEFAULT_WARN = 2, 62static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
63 DEFAULT_CRIT = 8 63
64}; 64static void print_help(void);
65 65static bool is_pg_logname(char * /*username*/);
66 66static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[], thresholds * /*qthresholds*/,
67 67 char * /*query_warning*/, char * /*query_critical*/);
68int process_arguments (int, char **); 68void print_usage(void);
69int validate_arguments (void); 69
70void print_usage (void); 70static int verbose = 0;
71void print_help (void); 71
72bool is_pg_logname (char *);
73int do_query (PGconn *, char *);
74
75char *pghost = NULL; /* host name of the backend server */
76char *pgport = NULL; /* port of the backend server */
77int default_port = DEFAULT_PORT;
78char *pgoptions = NULL;
79char *pgtty = NULL;
80char dbName[NAMEDATALEN] = DEFAULT_DB;
81char *pguser = NULL;
82char *pgpasswd = NULL;
83char *pgparams = NULL;
84double twarn = (double)DEFAULT_WARN;
85double tcrit = (double)DEFAULT_CRIT;
86char *pgquery = NULL;
87#define OPTID_QUERYNAME -1000 72#define OPTID_QUERYNAME -1000
88char *pgqueryname = NULL;
89char *query_warning = NULL;
90char *query_critical = NULL;
91thresholds *qthresholds = NULL;
92int verbose = 0;
93 73
94/****************************************************************************** 74/******************************************************************************
95 75
@@ -141,237 +121,235 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
141-@@ 121-@@
142******************************************************************************/ 122******************************************************************************/
143 123
124int main(int argc, char **argv) {
125 setlocale(LC_ALL, "");
126 bindtextdomain(PACKAGE, LOCALEDIR);
127 textdomain(PACKAGE);
144 128
129 /* Parse extra opts if any */
130 argv = np_extra_opts(&argc, argv, progname);
145 131
146int 132 check_pgsql_config_wrapper tmp_config = process_arguments(argc, argv);
147main (int argc, char **argv) 133 if (tmp_config.errorcode == ERROR) {
148{ 134 usage4(_("Could not parse arguments"));
149 PGconn *conn; 135 }
150 char *conninfo = NULL;
151
152 struct timeval start_timeval;
153 struct timeval end_timeval;
154 double elapsed_time;
155 int status = STATE_UNKNOWN;
156 int query_status = STATE_UNKNOWN;
157
158 /* begin, by setting the parameters for a backend connection if the
159 * parameters are null, then the system will try to use reasonable
160 * defaults by looking up environment variables or, failing that,
161 * using hardwired constants */
162
163 pgoptions = NULL; /* special options to start up the backend server */
164 pgtty = NULL; /* debugging tty for the backend server */
165
166 setlocale (LC_ALL, "");
167 bindtextdomain (PACKAGE, LOCALEDIR);
168 textdomain (PACKAGE);
169 136
170 /* Parse extra opts if any */ 137 const check_pgsql_config config = tmp_config.config;
171 argv=np_extra_opts (&argc, argv, progname);
172 138
173 if (process_arguments (argc, argv) == ERROR) 139 if (verbose > 2) {
174 usage4 (_("Could not parse arguments"));
175 if (verbose > 2)
176 printf("Arguments initialized\n"); 140 printf("Arguments initialized\n");
141 }
177 142
178 /* Set signal handling and alarm */ 143 /* Set signal handling and alarm */
179 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 144 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
180 usage4 (_("Cannot catch SIGALRM")); 145 usage4(_("Cannot catch SIGALRM"));
146 }
147 alarm(timeout_interval);
148
149 char *conninfo = NULL;
150 if (config.pgparams) {
151 asprintf(&conninfo, "%s ", config.pgparams);
152 }
153
154 asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", config.dbName);
155 if (config.pghost) {
156 asprintf(&conninfo, "%s host = '%s'", conninfo, config.pghost);
157 }
158 if (config.pgport) {
159 asprintf(&conninfo, "%s port = '%s'", conninfo, config.pgport);
160 }
161 if (config.pgoptions) {
162 asprintf(&conninfo, "%s options = '%s'", conninfo, config.pgoptions);
181 } 163 }
182 alarm (timeout_interval);
183
184 if (pgparams)
185 asprintf (&conninfo, "%s ", pgparams);
186
187 asprintf (&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", dbName);
188 if (pghost)
189 asprintf (&conninfo, "%s host = '%s'", conninfo, pghost);
190 if (pgport)
191 asprintf (&conninfo, "%s port = '%s'", conninfo, pgport);
192 if (pgoptions)
193 asprintf (&conninfo, "%s options = '%s'", conninfo, pgoptions);
194 /* if (pgtty) -- ignored by PQconnectdb */ 164 /* if (pgtty) -- ignored by PQconnectdb */
195 if (pguser) 165 if (config.pguser) {
196 asprintf (&conninfo, "%s user = '%s'", conninfo, pguser); 166 asprintf(&conninfo, "%s user = '%s'", conninfo, config.pguser);
167 }
197 168
198 if (verbose) /* do not include password (see right below) in output */ 169 if (verbose) { /* do not include password (see right below) in output */
199 printf ("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, 170 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, config.pgpasswd ? " password = <hidden>" : "");
200 pgpasswd ? " password = <hidden>" : ""); 171 }
201 172
202 if (pgpasswd) 173 if (config.pgpasswd) {
203 asprintf (&conninfo, "%s password = '%s'", conninfo, pgpasswd); 174 asprintf(&conninfo, "%s password = '%s'", conninfo, config.pgpasswd);
175 }
204 176
205 /* make a connection to the database */ 177 /* make a connection to the database */
206 gettimeofday (&start_timeval, NULL); 178 struct timeval start_timeval;
207 conn = PQconnectdb (conninfo); 179 gettimeofday(&start_timeval, NULL);
208 gettimeofday (&end_timeval, NULL); 180 PGconn *conn = PQconnectdb(conninfo);
181 struct timeval end_timeval;
182 gettimeofday(&end_timeval, NULL);
209 183
210 while (start_timeval.tv_usec > end_timeval.tv_usec) { 184 while (start_timeval.tv_usec > end_timeval.tv_usec) {
211 --end_timeval.tv_sec; 185 --end_timeval.tv_sec;
212 end_timeval.tv_usec += 1000000; 186 end_timeval.tv_usec += 1000000;
213 } 187 }
214 elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec) 188 double elapsed_time =
215 + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0; 189 (double)(end_timeval.tv_sec - start_timeval.tv_sec) + ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0);
216 190
217 if (verbose) 191 if (verbose) {
218 printf("Time elapsed: %f\n", elapsed_time); 192 printf("Time elapsed: %f\n", elapsed_time);
193 }
219 194
220 /* check to see that the backend connection was successfully made */ 195 /* check to see that the backend connection was successfully made */
221 if (verbose) 196 if (verbose) {
222 printf("Verifying connection\n"); 197 printf("Verifying connection\n");
223 if (PQstatus (conn) == CONNECTION_BAD) { 198 }
224 printf (_("CRITICAL - no connection to '%s' (%s).\n"), 199 if (PQstatus(conn) == CONNECTION_BAD) {
225 dbName, PQerrorMessage (conn)); 200 printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn));
226 PQfinish (conn); 201 PQfinish(conn);
227 return STATE_CRITICAL; 202 return STATE_CRITICAL;
228 } 203 }
229 else if (elapsed_time > tcrit) { 204
205 mp_state_enum status = STATE_UNKNOWN;
206 if (elapsed_time > config.tcrit) {
230 status = STATE_CRITICAL; 207 status = STATE_CRITICAL;
231 } 208 } else if (elapsed_time > config.twarn) {
232 else if (elapsed_time > twarn) {
233 status = STATE_WARNING; 209 status = STATE_WARNING;
234 } 210 } else {
235 else {
236 status = STATE_OK; 211 status = STATE_OK;
237 } 212 }
238 213
239 if (verbose) { 214 if (verbose) {
240 char *server_host = PQhost (conn); 215 char *server_host = PQhost(conn);
241 int server_version = PQserverVersion (conn); 216 int server_version = PQserverVersion(conn);
242 217
243 printf ("Successfully connected to database %s (user %s) " 218 printf("Successfully connected to database %s (user %s) "
244 "at server %s%s%s (server version: %d.%d.%d, " 219 "at server %s%s%s (server version: %d.%d.%d, "
245 "protocol version: %d, pid: %d)\n", 220 "protocol version: %d, pid: %d)\n",
246 PQdb (conn), PQuser (conn), 221 PQdb(conn), PQuser(conn), PSQL_SOCKET3(server_host, PQport(conn)), PSQL_SERVER_VERSION3(server_version),
247 PSQL_SOCKET3 (server_host, PQport (conn)), 222 PQprotocolVersion(conn), PQbackendPID(conn));
248 PSQL_SERVER_VERSION3 (server_version),
249 PQprotocolVersion (conn), PQbackendPID (conn));
250 } 223 }
251 224
252 printf (_(" %s - database %s (%f sec.)|%s\n"), 225 printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time,
253 state_text(status), dbName, elapsed_time, 226 fperfdata("time", elapsed_time, "s", (config.twarn > 0.0), config.twarn, (config.tcrit > 0.0), config.tcrit, true, 0, false, 0));
254 fperfdata("time", elapsed_time, "s",
255 !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, true, 0, false,0));
256 227
257 if (pgquery) 228 mp_state_enum query_status = STATE_UNKNOWN;
258 query_status = do_query (conn, pgquery); 229 if (config.pgquery) {
230 query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds, config.query_warning, config.query_critical);
231 }
259 232
260 if (verbose) 233 if (verbose) {
261 printf("Closing connection\n"); 234 printf("Closing connection\n");
262 PQfinish (conn); 235 }
263 return (pgquery && query_status > status) ? query_status : status; 236 PQfinish(conn);
237 return (config.pgquery && query_status > status) ? query_status : status;
264} 238}
265 239
266
267
268/* process command-line arguments */ 240/* process command-line arguments */
269int 241check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
270process_arguments (int argc, char **argv) 242 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
271{ 243 {"version", no_argument, 0, 'V'},
272 int c; 244 {"timeout", required_argument, 0, 't'},
273 245 {"critical", required_argument, 0, 'c'},
274 int option = 0; 246 {"warning", required_argument, 0, 'w'},
275 static struct option longopts[] = { 247 {"hostname", required_argument, 0, 'H'},
276 {"help", no_argument, 0, 'h'}, 248 {"logname", required_argument, 0, 'l'},
277 {"version", no_argument, 0, 'V'}, 249 {"password", required_argument, 0, 'p'},
278 {"timeout", required_argument, 0, 't'}, 250 {"authorization", required_argument, 0, 'a'},
279 {"critical", required_argument, 0, 'c'}, 251 {"port", required_argument, 0, 'P'},
280 {"warning", required_argument, 0, 'w'}, 252 {"database", required_argument, 0, 'd'},
281 {"hostname", required_argument, 0, 'H'}, 253 {"option", required_argument, 0, 'o'},
282 {"logname", required_argument, 0, 'l'}, 254 {"query", required_argument, 0, 'q'},
283 {"password", required_argument, 0, 'p'}, 255 {"queryname", required_argument, 0, OPTID_QUERYNAME},
284 {"authorization", required_argument, 0, 'a'}, 256 {"query_critical", required_argument, 0, 'C'},
285 {"port", required_argument, 0, 'P'}, 257 {"query_warning", required_argument, 0, 'W'},
286 {"database", required_argument, 0, 'd'}, 258 {"verbose", no_argument, 0, 'v'},
287 {"option", required_argument, 0, 'o'}, 259 {0, 0, 0, 0}};
288 {"query", required_argument, 0, 'q'}, 260
289 {"queryname", required_argument, 0, OPTID_QUERYNAME}, 261 check_pgsql_config_wrapper result = {
290 {"query_critical", required_argument, 0, 'C'}, 262 .errorcode = OK,
291 {"query_warning", required_argument, 0, 'W'}, 263 .config = check_pgsql_config_init(),
292 {"verbose", no_argument, 0, 'v'},
293 {0, 0, 0, 0}
294 }; 264 };
295 265
296 while (1) { 266 while (true) {
297 c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", 267 int option = 0;
298 longopts, &option); 268 int option_char = getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option);
299 269
300 if (c == EOF) 270 if (option_char == EOF) {
301 break; 271 break;
272 }
302 273
303 switch (c) { 274 switch (option_char) {
304 case '?': /* usage */ 275 case '?': /* usage */
305 usage5 (); 276 usage5();
306 case 'h': /* help */ 277 case 'h': /* help */
307 print_help (); 278 print_help();
308 exit (STATE_UNKNOWN); 279 exit(STATE_UNKNOWN);
309 case 'V': /* version */ 280 case 'V': /* version */
310 print_revision (progname, NP_VERSION); 281 print_revision(progname, NP_VERSION);
311 exit (STATE_UNKNOWN); 282 exit(STATE_UNKNOWN);
312 case 't': /* timeout period */ 283 case 't': /* timeout period */
313 if (!is_integer (optarg)) 284 if (!is_integer(optarg)) {
314 usage2 (_("Timeout interval must be a positive integer"), optarg); 285 usage2(_("Timeout interval must be a positive integer"), optarg);
315 else 286 } else {
316 timeout_interval = atoi (optarg); 287 timeout_interval = atoi(optarg);
288 }
317 break; 289 break;
318 case 'c': /* critical time threshold */ 290 case 'c': /* critical time threshold */
319 if (!is_nonnegative (optarg)) 291 if (!is_nonnegative(optarg)) {
320 usage2 (_("Critical threshold must be a positive integer"), optarg); 292 usage2(_("Critical threshold must be a positive integer"), optarg);
321 else 293 } else {
322 tcrit = strtod (optarg, NULL); 294 result.config.tcrit = strtod(optarg, NULL);
295 }
323 break; 296 break;
324 case 'w': /* warning time threshold */ 297 case 'w': /* warning time threshold */
325 if (!is_nonnegative (optarg)) 298 if (!is_nonnegative(optarg)) {
326 usage2 (_("Warning threshold must be a positive integer"), optarg); 299 usage2(_("Warning threshold must be a positive integer"), optarg);
327 else 300 } else {
328 twarn = strtod (optarg, NULL); 301 result.config.twarn = strtod(optarg, NULL);
302 }
329 break; 303 break;
330 case 'C': /* critical query threshold */ 304 case 'C': /* critical query threshold */
331 query_critical = optarg; 305 result.config.query_critical = optarg;
332 break; 306 break;
333 case 'W': /* warning query threshold */ 307 case 'W': /* warning query threshold */
334 query_warning = optarg; 308 result.config.query_warning = optarg;
335 break; 309 break;
336 case 'H': /* host */ 310 case 'H': /* host */
337 if ((*optarg != '/') && (!is_host (optarg))) 311 if ((*optarg != '/') && (!is_host(optarg))) {
338 usage2 (_("Invalid hostname/address"), optarg); 312 usage2(_("Invalid hostname/address"), optarg);
339 else 313 } else {
340 pghost = optarg; 314 result.config.pghost = optarg;
315 }
341 break; 316 break;
342 case 'P': /* port */ 317 case 'P': /* port */
343 if (!is_integer (optarg)) 318 if (!is_integer(optarg)) {
344 usage2 (_("Port must be a positive integer"), optarg); 319 usage2(_("Port must be a positive integer"), optarg);
345 else 320 } else {
346 pgport = optarg; 321 result.config.pgport = optarg;
322 }
347 break; 323 break;
348 case 'd': /* database name */ 324 case 'd': /* database name */
349 if (strlen(optarg) >= NAMEDATALEN) { 325 if (strlen(optarg) >= NAMEDATALEN) {
350 usage2 (_("Database name exceeds the maximum length"), optarg); 326 usage2(_("Database name exceeds the maximum length"), optarg);
351 } 327 }
352 snprintf(dbName, NAMEDATALEN, "%s", optarg); 328 snprintf(result.config.dbName, NAMEDATALEN, "%s", optarg);
353 break; 329 break;
354 case 'l': /* login name */ 330 case 'l': /* login name */
355 if (!is_pg_logname (optarg)) 331 if (!is_pg_logname(optarg)) {
356 usage2 (_("User name is not valid"), optarg); 332 usage2(_("User name is not valid"), optarg);
357 else 333 } else {
358 pguser = optarg; 334 result.config.pguser = optarg;
335 }
359 break; 336 break;
360 case 'p': /* authentication password */ 337 case 'p': /* authentication password */
361 case 'a': 338 case 'a':
362 pgpasswd = optarg; 339 result.config.pgpasswd = optarg;
363 break; 340 break;
364 case 'o': 341 case 'o':
365 if (pgparams) 342 if (result.config.pgparams) {
366 asprintf (&pgparams, "%s %s", pgparams, optarg); 343 asprintf(&result.config.pgparams, "%s %s", result.config.pgparams, optarg);
367 else 344 } else {
368 asprintf (&pgparams, "%s", optarg); 345 asprintf(&result.config.pgparams, "%s", optarg);
346 }
369 break; 347 break;
370 case 'q': 348 case 'q':
371 pgquery = optarg; 349 result.config.pgquery = optarg;
372 break; 350 break;
373 case OPTID_QUERYNAME: 351 case OPTID_QUERYNAME:
374 pgqueryname = optarg; 352 result.config.pgqueryname = optarg;
375 break; 353 break;
376 case 'v': 354 case 'v':
377 verbose++; 355 verbose++;
@@ -379,38 +357,9 @@ process_arguments (int argc, char **argv)
379 } 357 }
380 } 358 }
381 359
382 set_thresholds (&qthresholds, query_warning, query_critical); 360 set_thresholds(&result.config.qthresholds, result.config.query_warning, result.config.query_critical);
383
384 return validate_arguments ();
385}
386
387
388/******************************************************************************
389
390@@-
391<sect3>
392<title>validate_arguments</title>
393
394<para>&PROTO_validate_arguments;</para>
395
396<para>Given a database name, this function returns true if the string
397is a valid PostgreSQL database name, and returns false if it is
398not.</para>
399
400<para>Valid PostgreSQL database names are less than &NAMEDATALEN;
401characters long and consist of letters, numbers, and underscores. The
402first character cannot be a number, however.</para>
403
404</sect3>
405-@@
406******************************************************************************/
407
408
409 361
410int 362 return result;
411validate_arguments ()
412{
413 return OK;
414} 363}
415 364
416/** 365/**
@@ -437,11 +386,10 @@ should be added.</para>
437-@@ 386-@@
438******************************************************************************/ 387******************************************************************************/
439 388
440 389bool is_pg_logname(char *username) {
441 390 if (strlen(username) > NAMEDATALEN - 1) {
442bool is_pg_logname (char *username) {
443 if (strlen (username) > NAMEDATALEN - 1)
444 return (false); 391 return (false);
392 }
445 return (true); 393 return (true);
446} 394}
447 395
@@ -453,182 +401,159 @@ bool is_pg_logname (char *username) {
453-@@ 401-@@
454******************************************************************************/ 402******************************************************************************/
455 403
456 404void print_help(void) {
457
458void
459print_help (void)
460{
461 char *myport; 405 char *myport;
462 406
463 xasprintf (&myport, "%d", DEFAULT_PORT); 407 xasprintf(&myport, "%d", 5432);
464 408
465 print_revision (progname, NP_VERSION); 409 print_revision(progname, NP_VERSION);
466 410
467 printf (COPYRIGHT, copyright, email); 411 printf(COPYRIGHT, copyright, email);
468 412
469 printf (_("Test whether a PostgreSQL Database is accepting connections.")); 413 printf(_("Test whether a PostgreSQL Database is accepting connections."));
470 414
471 printf ("\n\n"); 415 printf("\n\n");
472 416
473 print_usage (); 417 print_usage();
474 418
475 printf (UT_HELP_VRSN); 419 printf(UT_HELP_VRSN);
476 printf (UT_EXTRA_OPTS); 420 printf(UT_EXTRA_OPTS);
477 421
478 printf (UT_HOST_PORT, 'P', myport); 422 printf(UT_HOST_PORT, 'P', myport);
479 423
480 printf (" %s\n", "-d, --database=STRING"); 424 printf(" %s\n", "-d, --database=STRING");
481 printf (" %s", _("Database to check ")); 425 printf(" %s", _("Database to check "));
482 printf (_("(default: %s)\n"), DEFAULT_DB); 426 printf(_("(default: %s)\n"), DEFAULT_DB);
483 printf (" %s\n", "-l, --logname = STRING"); 427 printf(" %s\n", "-l, --logname = STRING");
484 printf (" %s\n", _("Login name of user")); 428 printf(" %s\n", _("Login name of user"));
485 printf (" %s\n", "-p, --password = STRING"); 429 printf(" %s\n", "-p, --password = STRING");
486 printf (" %s\n", _("Password (BIG SECURITY ISSUE)")); 430 printf(" %s\n", _("Password (BIG SECURITY ISSUE)"));
487 printf (" %s\n", "-o, --option = STRING"); 431 printf(" %s\n", "-o, --option = STRING");
488 printf (" %s\n", _("Connection parameters (keyword = value), see below")); 432 printf(" %s\n", _("Connection parameters (keyword = value), see below"));
489 433
490 printf (UT_WARN_CRIT); 434 printf(UT_WARN_CRIT);
491 435
492 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 436 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
493 437
494 printf (" %s\n", "-q, --query=STRING"); 438 printf(" %s\n", "-q, --query=STRING");
495 printf (" %s\n", _("SQL query to run. Only first column in first row will be read")); 439 printf(" %s\n", _("SQL query to run. Only first column in first row will be read"));
496 printf (" %s\n", "--queryname=STRING"); 440 printf(" %s\n", "--queryname=STRING");
497 printf (" %s\n", _("A name for the query, this string is used instead of the query")); 441 printf(" %s\n", _("A name for the query, this string is used instead of the query"));
498 printf (" %s\n", _("in the long output of the plugin")); 442 printf(" %s\n", _("in the long output of the plugin"));
499 printf (" %s\n", "-W, --query-warning=RANGE"); 443 printf(" %s\n", "-W, --query-warning=RANGE");
500 printf (" %s\n", _("SQL query value to result in warning status (double)")); 444 printf(" %s\n", _("SQL query value to result in warning status (double)"));
501 printf (" %s\n", "-C, --query-critical=RANGE"); 445 printf(" %s\n", "-C, --query-critical=RANGE");
502 printf (" %s\n", _("SQL query value to result in critical status (double)")); 446 printf(" %s\n", _("SQL query value to result in critical status (double)"));
503 447
504 printf (UT_VERBOSE); 448 printf(UT_VERBOSE);
505 449
506 printf ("\n"); 450 printf("\n");
507 printf (" %s\n", _("All parameters are optional.")); 451 printf(" %s\n", _("All parameters are optional."));
508 printf (" %s\n", _("This plugin tests a PostgreSQL DBMS to determine whether it is active and")); 452 printf(" %s\n", _("This plugin tests a PostgreSQL DBMS to determine whether it is active and"));
509 printf (" %s\n", _("accepting queries. In its current operation, it simply connects to the")); 453 printf(" %s\n", _("accepting queries. In its current operation, it simply connects to the"));
510 printf (" %s\n", _("specified database, and then disconnects. If no database is specified, it")); 454 printf(" %s\n", _("specified database, and then disconnects. If no database is specified, it"));
511 printf (" %s\n", _("connects to the template1 database, which is present in every functioning")); 455 printf(" %s\n", _("connects to the template1 database, which is present in every functioning"));
512 printf (" %s\n\n", _("PostgreSQL DBMS.")); 456 printf(" %s\n\n", _("PostgreSQL DBMS."));
513 457
514 printf (" %s\n", _("If a query is specified using the -q option, it will be executed after")); 458 printf(" %s\n", _("If a query is specified using the -q option, it will be executed after"));
515 printf (" %s\n", _("connecting to the server. The result from the query has to be numeric.")); 459 printf(" %s\n", _("connecting to the server. The result from the query has to be numeric."));
516 printf (" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result ")); 460 printf(" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result "));
517 printf (" %s\n", _("of the last command is taken into account only. The value of the first")); 461 printf(" %s\n", _("of the last command is taken into account only. The value of the first"));
518 printf (" %s\n", _("column in the first row is used as the check result. If a second column is")); 462 printf(" %s\n", _("column in the first row is used as the check result. If a second column is"));
519 printf (" %s\n", _("present in the result set, this is added to the plugin output with a")); 463 printf(" %s\n", _("present in the result set, this is added to the plugin output with a"));
520 printf (" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system")); 464 printf(" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system"));
521 printf (" %s\n\n", _("executing the plugin.")); 465 printf(" %s\n\n", _("executing the plugin."));
522 466
523 printf (" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual")); 467 printf(" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual"));
524 printf (" %s\n\n", _("for details about how to access internal statistics of the database server.")); 468 printf(" %s\n\n", _("for details about how to access internal statistics of the database server."));
525 469
526 printf (" %s\n", _("For a list of available connection parameters which may be used with the -o")); 470 printf(" %s\n", _("For a list of available connection parameters which may be used with the -o"));
527 printf (" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter")); 471 printf(" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter"));
528 printf (" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be")); 472 printf(" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be"));
529 printf (" %s\n", _("used to specify a service name in pg_service.conf to be used for additional")); 473 printf(" %s\n", _("used to specify a service name in pg_service.conf to be used for additional"));
530 printf (" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:")); 474 printf(" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:"));
531 printf (" %s\n\n", _("-o 'sslmode=require'.")); 475 printf(" %s\n\n", _("-o 'sslmode=require'."));
532 476
533 printf (" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To")); 477 printf(" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To"));
534 printf (" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP")); 478 printf(" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP"));
535 printf (" %s\n\n", _("connections (start the postmaster with the -i option).")); 479 printf(" %s\n\n", _("connections (start the postmaster with the -i option)."));
536 480
537 printf (" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be")); 481 printf(" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be"));
538 printf (" %s\n", _("able to connect to the database without a password. The plugin can also send")); 482 printf(" %s\n", _("able to connect to the database without a password. The plugin can also send"));
539 printf (" %s\n", _("a password, but no effort is made to obscure or encrypt the password.")); 483 printf(" %s\n", _("a password, but no effort is made to obscure or encrypt the password."));
540 484
541 printf (UT_SUPPORT); 485 printf(UT_SUPPORT);
542} 486}
543 487
544 488void print_usage(void) {
545 489 printf("%s\n", _("Usage:"));
546void 490 printf("%s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n", progname);
547print_usage (void) 491 printf(" [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n"
548{ 492 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
549 printf ("%s\n", _("Usage:"));
550 printf ("%s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n", progname);
551 printf (" [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n"
552 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
553} 493}
554 494
555int 495mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds, char *query_warning,
556do_query (PGconn *conn, char *query) 496 char *query_critical) {
557{ 497 if (verbose) {
558 PGresult *res; 498 printf("Executing SQL query \"%s\".\n", query);
559 499 }
560 char *val_str; 500 PGresult *res = PQexec(conn, query);
561 char *extra_info;
562 double value;
563
564 char *endptr = NULL;
565
566 int my_status = STATE_UNKNOWN;
567
568 if (verbose)
569 printf ("Executing SQL query \"%s\".\n", query);
570 res = PQexec (conn, query);
571 501
572 if (PGRES_TUPLES_OK != PQresultStatus (res)) { 502 if (PGRES_TUPLES_OK != PQresultStatus(res)) {
573 printf (_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), 503 printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), PQerrorMessage(conn));
574 PQerrorMessage (conn));
575 return STATE_CRITICAL; 504 return STATE_CRITICAL;
576 } 505 }
577 506
578 if (PQntuples (res) < 1) { 507 if (PQntuples(res) < 1) {
579 printf ("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); 508 printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned"));
580 return STATE_WARNING; 509 return STATE_WARNING;
581 } 510 }
582 511
583 if (PQnfields (res) < 1) { 512 if (PQnfields(res) < 1) {
584 printf ("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); 513 printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned"));
585 return STATE_WARNING; 514 return STATE_WARNING;
586 } 515 }
587 516
588 val_str = PQgetvalue (res, 0, 0); 517 char *val_str = PQgetvalue(res, 0, 0);
589 if (! val_str) { 518 if (!val_str) {
590 printf ("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); 519 printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned"));
591 return STATE_CRITICAL; 520 return STATE_CRITICAL;
592 } 521 }
593 522
594 value = strtod (val_str, &endptr); 523 char *endptr = NULL;
595 if (verbose) 524 double value = strtod(val_str, &endptr);
596 printf ("Query result: %f\n", value); 525 if (verbose) {
526 printf("Query result: %f\n", value);
527 }
597 528
598 if (endptr == val_str) { 529 if (endptr == val_str) {
599 printf ("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); 530 printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str);
600 return STATE_CRITICAL; 531 return STATE_CRITICAL;
601 } 532 }
602 else if ((endptr != NULL) && (*endptr != '\0')) {
603 if (verbose)
604 printf ("Garbage after value: %s.\n", endptr);
605 }
606 533
607 my_status = get_status (value, qthresholds); 534 if ((endptr != NULL) && (*endptr != '\0')) {
608 printf ("QUERY %s - ", 535 if (verbose) {
609 (my_status == STATE_OK) 536 printf("Garbage after value: %s.\n", endptr);
610 ? _("OK") 537 }
611 : (my_status == STATE_WARNING)
612 ? _("WARNING")
613 : (my_status == STATE_CRITICAL)
614 ? _("CRITICAL")
615 : _("UNKNOWN"));
616 if(pgqueryname) {
617 printf (_("%s returned %f"), pgqueryname, value);
618 } 538 }
619 else { 539
620 printf (_("'%s' returned %f"), query, value); 540 mp_state_enum my_status = get_status(value, qthresholds);
541 printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK")
542 : (my_status == STATE_WARNING) ? _("WARNING")
543 : (my_status == STATE_CRITICAL) ? _("CRITICAL")
544 : _("UNKNOWN"));
545 if (pgqueryname) {
546 printf(_("%s returned %f"), pgqueryname, value);
547 } else {
548 printf(_("'%s' returned %f"), query, value);
621 } 549 }
622 550
623 printf ("|query=%f;%s;%s;;\n", value, 551 printf("|query=%f;%s;%s;;\n", value, query_warning ? query_warning : "", query_critical ? query_critical : "");
624 query_warning ? query_warning : "", 552 if (PQnfields(res) > 1) {
625 query_critical ? query_critical : ""); 553 char *extra_info = PQgetvalue(res, 0, 1);
626 if (PQnfields (res) > 1) {
627 extra_info = PQgetvalue (res, 0, 1);
628 if (extra_info != NULL) { 554 if (extra_info != NULL) {
629 printf ("Extra Info: %s\n", extra_info); 555 printf("Extra Info: %s\n", extra_info);
630 } 556 }
631 } 557 }
632 return my_status; 558 return my_status;
633} 559}
634
diff --git a/plugins/check_pgsql.d/config.h b/plugins/check_pgsql.d/config.h
new file mode 100644
index 00000000..2d4b8b89
--- /dev/null
+++ b/plugins/check_pgsql.d/config.h
@@ -0,0 +1,61 @@
1#pragma once
2
3#include "../../config.h"
4#include "thresholds.h"
5#include <stddef.h>
6#include <pg_config_manual.h>
7
8#define DEFAULT_DB "template1"
9
10enum {
11 DEFAULT_WARN = 2,
12 DEFAULT_CRIT = 8,
13};
14
15typedef struct {
16 char *pghost; /* host name of the backend server */
17 char *pgport; /* port of the backend server */
18 char *pgoptions; /* special options to start up the backend server */
19 char *pgtty; /* debugging tty for the backend server */
20 char dbName[NAMEDATALEN];
21 char *pguser;
22 char *pgpasswd;
23 char *pgparams;
24 char *pgquery;
25 char *pgqueryname;
26
27 double twarn;
28 double tcrit;
29 thresholds *qthresholds;
30 char *query_warning;
31 char *query_critical;
32} check_pgsql_config;
33
34/* begin, by setting the parameters for a backend connection if the
35 * parameters are null, then the system will try to use reasonable
36 * defaults by looking up environment variables or, failing that,
37 * using hardwired constants
38 * this targets .pgoptions and .pgtty
39 */
40
41check_pgsql_config check_pgsql_config_init() {
42 check_pgsql_config tmp = {
43 .pghost = NULL,
44 .pgport = NULL,
45 .pgoptions = NULL,
46 .pgtty = NULL,
47 .dbName = DEFAULT_DB,
48 .pguser = NULL,
49 .pgpasswd = NULL,
50 .pgparams = NULL,
51 .pgquery = NULL,
52 .pgqueryname = NULL,
53
54 .twarn = (double)DEFAULT_WARN,
55 .tcrit = (double)DEFAULT_CRIT,
56 .qthresholds = NULL,
57 .query_warning = NULL,
58 .query_critical = NULL,
59 };
60 return tmp;
61}
diff --git a/plugins/check_ping.c b/plugins/check_ping.c
index 6e162e6a..6bcdeaad 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -1,506 +1,526 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ping plugin 3 * Monitoring check_ping plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_ping plugin 10 * This file contains the check_ping plugin
11* 11 *
12* Use the ping program to check connection statistics for a remote host. 12 * Use the ping program to check connection statistics for a remote host.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_ping"; 31const char *progname = "check_ping";
32const char *copyright = "2000-2007"; 32const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "common.h"
36#include "netutils.h" 36#include "netutils.h"
37#include "popen.h" 37#include "popen.h"
38#include "utils.h" 38#include "utils.h"
39#include "check_ping.d/config.h"
40#include "../lib/states.h"
39 41
40#include <signal.h> 42#include <signal.h>
41 43
42#define WARN_DUPLICATES "DUPLICATES FOUND! " 44#define WARN_DUPLICATES "DUPLICATES FOUND! "
43#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
44
45enum {
46 UNKNOWN_PACKET_LOSS = 200, /* 200% */
47 DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */
48};
49
50int process_arguments (int, char **);
51int get_threshold (char *, float *, int *);
52int validate_arguments (void);
53int run_ping (const char *cmd, const char *addr);
54int error_scan (char buf[MAX_INPUT_BUFFER], const char *addr);
55void print_usage (void);
56void print_help (void);
57
58bool display_html = false;
59int wpl = UNKNOWN_PACKET_LOSS;
60int cpl = UNKNOWN_PACKET_LOSS;
61float wrta = UNKNOWN_TRIP_TIME;
62float crta = UNKNOWN_TRIP_TIME;
63char **addresses = NULL;
64int n_addresses = 0;
65int max_addr = 1;
66int max_packets = -1;
67int verbose = 0;
68
69float rta = UNKNOWN_TRIP_TIME;
70int pl = UNKNOWN_PACKET_LOSS;
71
72char *warn_text;
73
74
75
76int
77main (int argc, char **argv)
78{
79 char *cmd = NULL;
80 char *rawcmd = NULL;
81 int result = STATE_UNKNOWN;
82 int this_result = STATE_UNKNOWN;
83 int i;
84 45
85 setlocale (LC_ALL, ""); 46typedef struct {
86 setlocale (LC_NUMERIC, "C"); 47 int errorcode;
87 bindtextdomain (PACKAGE, LOCALEDIR); 48 check_ping_config config;
88 textdomain (PACKAGE); 49} check_ping_config_wrapper;
50static check_ping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
51static check_ping_config_wrapper validate_arguments(check_ping_config_wrapper /*config_wrapper*/);
52
53static int get_threshold(char * /*arg*/, double * /*trta*/, int * /*tpl*/);
54
55typedef struct {
56 mp_state_enum state;
57 double round_trip_average;
58 int packet_loss;
59} ping_result;
60static ping_result run_ping(const char *cmd, const char *addr, double /*crta*/);
61
62static mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr);
63static void print_help(void);
64void print_usage(void);
65
66static int verbose = 0;
89 67
90 addresses = malloc (sizeof(char*) * max_addr); 68static char *warn_text;
91 addresses[0] = NULL; 69
70int main(int argc, char **argv) {
71 setlocale(LC_ALL, "");
72 setlocale(LC_NUMERIC, "C");
73 bindtextdomain(PACKAGE, LOCALEDIR);
74 textdomain(PACKAGE);
92 75
93 /* Parse extra opts if any */ 76 /* Parse extra opts if any */
94 argv=np_extra_opts (&argc, argv, progname); 77 argv = np_extra_opts(&argc, argv, progname);
78
79 check_ping_config_wrapper tmp_config = process_arguments(argc, argv);
80 if (tmp_config.errorcode == ERROR) {
81 usage4(_("Could not parse arguments"));
82 }
95 83
96 if (process_arguments (argc, argv) == ERROR) 84 const check_ping_config config = tmp_config.config;
97 usage4 (_("Could not parse arguments"));
98 85
99 /* Set signal handling and alarm */ 86 /* Set signal handling and alarm */
100 if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { 87 if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
101 usage4 (_("Cannot catch SIGALRM")); 88 usage4(_("Cannot catch SIGALRM"));
102 } 89 }
103 90
104 /* If ./configure finds ping has timeout values, set plugin alarm slightly 91 /* If ./configure finds ping has timeout values, set plugin alarm slightly
105 * higher so that we can use response from command line ping */ 92 * higher so that we can use response from command line ping */
106#if defined(PING_PACKETS_FIRST) && defined(PING_HAS_TIMEOUT) 93#if defined(PING_PACKETS_FIRST) && defined(PING_HAS_TIMEOUT)
107 alarm (timeout_interval + 1); 94 alarm(timeout_interval + 1);
108#else 95#else
109 alarm (timeout_interval); 96 alarm(timeout_interval);
110#endif 97#endif
111 98
112 for (i = 0 ; i < n_addresses ; i++) { 99 int result = STATE_UNKNOWN;
113 100 char *rawcmd = NULL;
101 for (size_t i = 0; i < config.n_addresses; i++) {
114#ifdef PING6_COMMAND 102#ifdef PING6_COMMAND
115 if (address_family != AF_INET && is_inet6_addr(addresses[i])) 103 if (address_family != AF_INET && is_inet6_addr(config.addresses[i])) {
116 rawcmd = strdup(PING6_COMMAND); 104 rawcmd = strdup(PING6_COMMAND);
117 else 105 } else {
118 rawcmd = strdup(PING_COMMAND); 106 rawcmd = strdup(PING_COMMAND);
107 }
119#else 108#else
120 rawcmd = strdup(PING_COMMAND); 109 rawcmd = strdup(PING_COMMAND);
121#endif 110#endif
122 111
112 char *cmd = NULL;
113
123 /* does the host address of number of packets argument come first? */ 114 /* does the host address of number of packets argument come first? */
124#ifdef PING_PACKETS_FIRST 115#ifdef PING_PACKETS_FIRST
125# ifdef PING_HAS_TIMEOUT 116# ifdef PING_HAS_TIMEOUT
126 xasprintf (&cmd, rawcmd, timeout_interval, max_packets, addresses[i]); 117 xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]);
127# else 118# else
128 xasprintf (&cmd, rawcmd, max_packets, addresses[i]); 119 xasprintf(&cmd, rawcmd, config.max_packets, config.addresses[i]);
129# endif 120# endif
130#else 121#else
131 xasprintf (&cmd, rawcmd, addresses[i], max_packets); 122 xasprintf(&cmd, rawcmd, config.addresses[i], config.max_packets);
132#endif 123#endif
133 124
134 if (verbose >= 2) 125 if (verbose >= 2) {
135 printf ("CMD: %s\n", cmd); 126 printf("CMD: %s\n", cmd);
127 }
136 128
137 /* run the command */ 129 /* run the command */
138 this_result = run_ping (cmd, addresses[i]);
139 130
140 if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) { 131 ping_result pinged = run_ping(cmd, config.addresses[i], config.crta);
141 printf ("%s\n", cmd); 132
142 die (STATE_UNKNOWN, 133 if (pinged.packet_loss == UNKNOWN_PACKET_LOSS || pinged.round_trip_average < 0.0) {
143 _("CRITICAL - Could not interpret output from ping command\n")); 134 printf("%s\n", cmd);
135 die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n"));
136 }
137
138 if (pinged.packet_loss >= config.cpl || pinged.round_trip_average >= config.crta || pinged.round_trip_average < 0) {
139 pinged.state = STATE_CRITICAL;
140 } else if (pinged.packet_loss >= config.wpl || pinged.round_trip_average >= config.wrta) {
141 pinged.state = STATE_WARNING;
142 } else if (pinged.packet_loss >= 0 && pinged.round_trip_average >= 0) {
143 pinged.state = max_state(STATE_OK, pinged.state);
144 }
145
146 if (config.n_addresses > 1 && pinged.state != STATE_UNKNOWN) {
147 die(STATE_OK, "%s is alive\n", config.addresses[i]);
144 } 148 }
145 149
146 if (pl >= cpl || rta >= crta || rta < 0) 150 if (config.display_html) {
147 this_result = STATE_CRITICAL; 151 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, config.addresses[i]);
148 else if (pl >= wpl || rta >= wrta) 152 }
149 this_result = STATE_WARNING; 153 if (pinged.packet_loss == 100) {
150 else if (pl >= 0 && rta >= 0) 154 printf(_("PING %s - %sPacket loss = %d%%"), state_text(pinged.state), warn_text, pinged.packet_loss);
151 this_result = max_state (STATE_OK, this_result); 155 } else {
152 156 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(pinged.state), warn_text, pinged.packet_loss,
153 if (n_addresses > 1 && this_result != STATE_UNKNOWN) 157 pinged.round_trip_average);
154 die (STATE_OK, "%s is alive\n", addresses[i]); 158 }
155 159 if (config.display_html) {
156 if (display_html == true) 160 printf("</A>");
157 printf ("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]); 161 }
158 if (pl == 100)
159 printf (_("PING %s - %sPacket loss = %d%%"), state_text (this_result), warn_text,
160 pl);
161 else
162 printf (_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"),
163 state_text (this_result), warn_text, pl, rta);
164 if (display_html == true)
165 printf ("</A>");
166 162
167 /* Print performance data */ 163 /* Print performance data */
168 if (pl != 100) { 164 if (pinged.packet_loss != 100) {
169 printf("|%s", fperfdata ("rta", (double) rta, "ms", 165 printf("|%s", fperfdata("rta", pinged.round_trip_average, "ms", (bool)(config.wrta > 0), config.wrta, (bool)(config.crta > 0),
170 wrta>0?true:false, wrta, 166 config.crta, true, 0, false, 0));
171 crta>0?true:false, crta,
172 true, 0, false, 0));
173 } else { 167 } else {
174 printf("| rta=U;%f;%f;;", wrta, crta); 168 printf("| rta=U;%f;%f;;", config.wrta, config.crta);
175 } 169 }
176 printf(" %s\n", perfdata ("pl", (long) pl, "%",
177 wpl>0?true:false, wpl,
178 cpl>0?true:false, cpl,
179 true, 0, false, 0));
180 170
181 if (verbose >= 2) 171 printf(" %s\n", perfdata("pl", (long)pinged.packet_loss, "%", (bool)(config.wpl > 0), config.wpl, (bool)(config.cpl > 0),
182 printf ("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl); 172 config.cpl, true, 0, false, 0));
173
174 if (verbose >= 2) {
175 printf("%f:%d%% %f:%d%%\n", config.wrta, config.wpl, config.crta, config.cpl);
176 }
183 177
184 result = max_state (result, this_result); 178 result = max_state(result, pinged.state);
185 free (rawcmd); 179 free(rawcmd);
186 free (cmd); 180 free(cmd);
187 } 181 }
188 182
189 return result; 183 return result;
190} 184}
191 185
192
193
194/* process command-line arguments */ 186/* process command-line arguments */
195int 187check_ping_config_wrapper process_arguments(int argc, char **argv) {
196process_arguments (int argc, char **argv) 188 static struct option longopts[] = {STD_LONG_OPTS,
197{ 189 {"packets", required_argument, 0, 'p'},
198 int c = 1; 190 {"nohtml", no_argument, 0, 'n'},
199 char *ptr; 191 {"link", no_argument, 0, 'L'},
200 192 {"use-ipv4", no_argument, 0, '4'},
201 int option = 0; 193 {"use-ipv6", no_argument, 0, '6'},
202 static struct option longopts[] = { 194 {0, 0, 0, 0}};
203 STD_LONG_OPTS, 195
204 {"packets", required_argument, 0, 'p'}, 196 check_ping_config_wrapper result = {
205 {"nohtml", no_argument, 0, 'n'}, 197 .errorcode = OK,
206 {"link", no_argument, 0, 'L'}, 198 .config = check_ping_config_init(),
207 {"use-ipv4", no_argument, 0, '4'},
208 {"use-ipv6", no_argument, 0, '6'},
209 {0, 0, 0, 0}
210 }; 199 };
211 200
212 if (argc < 2) 201 if (argc < 2) {
213 return ERROR; 202 result.errorcode = ERROR;
203 return result;
204 }
214 205
215 for (c = 1; c < argc; c++) { 206 for (int index = 1; index < argc; index++) {
216 if (strcmp ("-to", argv[c]) == 0) 207 if (strcmp("-to", argv[index]) == 0) {
217 strcpy (argv[c], "-t"); 208 strcpy(argv[index], "-t");
218 if (strcmp ("-nohtml", argv[c]) == 0) 209 }
219 strcpy (argv[c], "-n"); 210 if (strcmp("-nohtml", argv[index]) == 0) {
211 strcpy(argv[index], "-n");
212 }
220 } 213 }
221 214
222 while (1) { 215 int option = 0;
223 c = getopt_long (argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option); 216 size_t max_addr = MAX_ADDR_START;
217 while (true) {
218 int option_index = getopt_long(argc, argv, "VvhnL46t:c:w:H:p:", longopts, &option);
224 219
225 if (c == -1 || c == EOF) 220 if (option_index == -1 || option_index == EOF) {
226 break; 221 break;
222 }
227 223
228 switch (c) { 224 switch (option_index) {
229 case '?': /* usage */ 225 case '?': /* usage */
230 usage5 (); 226 usage5();
231 case 'h': /* help */ 227 case 'h': /* help */
232 print_help (); 228 print_help();
233 exit (STATE_UNKNOWN); 229 exit(STATE_UNKNOWN);
234 break; 230 break;
235 case 'V': /* version */ 231 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 232 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 233 exit(STATE_UNKNOWN);
238 break; 234 break;
239 case 't': /* timeout period */ 235 case 't': /* timeout period */
240 timeout_interval = atoi (optarg); 236 timeout_interval = atoi(optarg);
241 break; 237 break;
242 case 'v': /* verbose mode */ 238 case 'v': /* verbose mode */
243 verbose++; 239 verbose++;
244 break; 240 break;
245 case '4': /* IPv4 only */ 241 case '4': /* IPv4 only */
246 address_family = AF_INET; 242 address_family = AF_INET;
247 break; 243 break;
248 case '6': /* IPv6 only */ 244 case '6': /* IPv6 only */
249#ifdef USE_IPV6 245#ifdef USE_IPV6
250 address_family = AF_INET6; 246 address_family = AF_INET6;
251#else 247#else
252 usage (_("IPv6 support not available\n")); 248 usage(_("IPv6 support not available\n"));
253#endif 249#endif
254 break; 250 break;
255 case 'H': /* hostname */ 251 case 'H': /* hostname */ {
256 ptr=optarg; 252 char *ptr = optarg;
257 while (1) { 253 while (true) {
258 n_addresses++; 254 result.config.n_addresses++;
259 if (n_addresses > max_addr) { 255 if (result.config.n_addresses > max_addr) {
260 max_addr *= 2; 256 max_addr *= 2;
261 addresses = realloc (addresses, sizeof(char*) * max_addr); 257 result.config.addresses = realloc(result.config.addresses, sizeof(char *) * max_addr);
262 if (addresses == NULL) 258 if (result.config.addresses == NULL) {
263 die (STATE_UNKNOWN, _("Could not realloc() addresses\n")); 259 die(STATE_UNKNOWN, _("Could not realloc() addresses\n"));
260 }
264 } 261 }
265 addresses[n_addresses-1] = ptr; 262 result.config.addresses[result.config.n_addresses - 1] = ptr;
266 if ((ptr = index (ptr, ','))) { 263 if ((ptr = index(ptr, ','))) {
267 strcpy (ptr, ""); 264 strcpy(ptr, "");
268 ptr += sizeof(char); 265 ptr += sizeof(char);
269 } else { 266 } else {
270 break; 267 break;
271 } 268 }
272 } 269 }
270 } break;
271 case 'p': /* number of packets to send */
272 if (is_intnonneg(optarg)) {
273 result.config.max_packets = atoi(optarg);
274 } else {
275 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg);
276 }
273 break; 277 break;
274 case 'p': /* number of packets to send */ 278 case 'n': /* no HTML */
275 if (is_intnonneg (optarg)) 279 result.config.display_html = false;
276 max_packets = atoi (optarg);
277 else
278 usage2 (_("<max_packets> (%s) must be a non-negative number\n"), optarg);
279 break;
280 case 'n': /* no HTML */
281 display_html = false;
282 break; 280 break;
283 case 'L': /* show HTML */ 281 case 'L': /* show HTML */
284 display_html = true; 282 result.config.display_html = true;
285 break; 283 break;
286 case 'c': 284 case 'c':
287 get_threshold (optarg, &crta, &cpl); 285 get_threshold(optarg, &result.config.crta, &result.config.cpl);
288 break; 286 break;
289 case 'w': 287 case 'w':
290 get_threshold (optarg, &wrta, &wpl); 288 get_threshold(optarg, &result.config.wrta, &result.config.wpl);
291 break; 289 break;
292 } 290 }
293 } 291 }
294 292
295 c = optind; 293 int arg_counter = optind;
296 if (c == argc) 294 if (arg_counter == argc) {
297 return validate_arguments (); 295 return validate_arguments(result);
296 }
298 297
299 if (addresses[0] == NULL) { 298 if (result.config.addresses[0] == NULL) {
300 if (!is_host (argv[c])) { 299 if (!is_host(argv[arg_counter])) {
301 usage2 (_("Invalid hostname/address"), argv[c]); 300 usage2(_("Invalid hostname/address"), argv[arg_counter]);
302 } else { 301 } else {
303 addresses[0] = argv[c++]; 302 result.config.addresses[0] = argv[arg_counter++];
304 n_addresses++; 303 result.config.n_addresses++;
305 if (c == argc) 304 if (arg_counter == argc) {
306 return validate_arguments (); 305 return validate_arguments(result);
306 }
307 } 307 }
308 } 308 }
309 309
310 if (wpl == UNKNOWN_PACKET_LOSS) { 310 if (result.config.wpl == UNKNOWN_PACKET_LOSS) {
311 if (!is_intpercent (argv[c])) { 311 if (!is_intpercent(argv[arg_counter])) {
312 printf (_("<wpl> (%s) must be an integer percentage\n"), argv[c]); 312 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
313 return ERROR; 313 result.errorcode = ERROR;
314 } else { 314 return result;
315 wpl = atoi (argv[c++]); 315 }
316 if (c == argc) 316 result.config.wpl = atoi(argv[arg_counter++]);
317 return validate_arguments (); 317 if (arg_counter == argc) {
318 return validate_arguments(result);
318 } 319 }
319 } 320 }
320 321
321 if (cpl == UNKNOWN_PACKET_LOSS) { 322 if (result.config.cpl == UNKNOWN_PACKET_LOSS) {
322 if (!is_intpercent (argv[c])) { 323 if (!is_intpercent(argv[arg_counter])) {
323 printf (_("<cpl> (%s) must be an integer percentage\n"), argv[c]); 324 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
324 return ERROR; 325 result.errorcode = ERROR;
325 } else { 326 return result;
326 cpl = atoi (argv[c++]); 327 }
327 if (c == argc) 328 result.config.cpl = atoi(argv[arg_counter++]);
328 return validate_arguments (); 329 if (arg_counter == argc) {
330 return validate_arguments(result);
329 } 331 }
330 } 332 }
331 333
332 if (wrta < 0.0) { 334 if (result.config.wrta < 0.0) {
333 if (is_negative (argv[c])) { 335 if (is_negative(argv[arg_counter])) {
334 printf (_("<wrta> (%s) must be a non-negative number\n"), argv[c]); 336 printf(_("<wrta> (%s) must be a non-negative number\n"), argv[arg_counter]);
335 return ERROR; 337 result.errorcode = ERROR;
336 } else { 338 return result;
337 wrta = atof (argv[c++]); 339 }
338 if (c == argc) 340 result.config.wrta = atof(argv[arg_counter++]);
339 return validate_arguments (); 341 if (arg_counter == argc) {
342 return validate_arguments(result);
340 } 343 }
341 } 344 }
342 345
343 if (crta < 0.0) { 346 if (result.config.crta < 0.0) {
344 if (is_negative (argv[c])) { 347 if (is_negative(argv[arg_counter])) {
345 printf (_("<crta> (%s) must be a non-negative number\n"), argv[c]); 348 printf(_("<crta> (%s) must be a non-negative number\n"), argv[arg_counter]);
346 return ERROR; 349 result.errorcode = ERROR;
347 } else { 350 return result;
348 crta = atof (argv[c++]); 351 }
349 if (c == argc) 352 result.config.crta = atof(argv[arg_counter++]);
350 return validate_arguments (); 353 if (arg_counter == argc) {
354 return validate_arguments(result);
351 } 355 }
352 } 356 }
353 357
354 if (max_packets == -1) { 358 if (result.config.max_packets == -1) {
355 if (is_intnonneg (argv[c])) { 359 if (is_intnonneg(argv[arg_counter])) {
356 max_packets = atoi (argv[c++]); 360 result.config.max_packets = atoi(argv[arg_counter++]);
357 } else { 361 } else {
358 printf (_("<max_packets> (%s) must be a non-negative number\n"), argv[c]); 362 printf(_("<max_packets> (%s) must be a non-negative number\n"), argv[arg_counter]);
359 return ERROR; 363 result.errorcode = ERROR;
364 return result;
360 } 365 }
361 } 366 }
362 367
363 return validate_arguments (); 368 return validate_arguments(result);
364} 369}
365 370
366 371int get_threshold(char *arg, double *trta, int *tpl) {
367 372 if (is_intnonneg(arg) && sscanf(arg, "%lf", trta) == 1) {
368int
369get_threshold (char *arg, float *trta, int *tpl)
370{
371 if (is_intnonneg (arg) && sscanf (arg, "%f", trta) == 1)
372 return OK; 373 return OK;
373 else if (strpbrk (arg, ",:") && strstr (arg, "%") && sscanf (arg, "%f%*[:,]%d%%", trta, tpl) == 2) 374 }
375
376 if (strpbrk(arg, ",:") && strstr(arg, "%") && sscanf(arg, "%lf%*[:,]%d%%", trta, tpl) == 2) {
374 return OK; 377 return OK;
375 else if (strstr (arg, "%") && sscanf (arg, "%d%%", tpl) == 1) 378 }
379
380 if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) {
376 return OK; 381 return OK;
382 }
377 383
378 usage2 (_("%s: Warning threshold must be integer or percentage!\n\n"), arg); 384 usage2(_("%s: Warning threshold must be integer or percentage!\n\n"), arg);
379 return STATE_UNKNOWN; 385 return STATE_UNKNOWN;
380} 386}
381 387
382 388check_ping_config_wrapper validate_arguments(check_ping_config_wrapper config_wrapper) {
383 389 if (config_wrapper.config.wrta < 0.0) {
384int 390 printf(_("<wrta> was not set\n"));
385validate_arguments () 391 config_wrapper.errorcode = ERROR;
386{ 392 return config_wrapper;
387 float max_seconds;
388 int i;
389
390 if (wrta < 0.0) {
391 printf (_("<wrta> was not set\n"));
392 return ERROR;
393 } 393 }
394 else if (crta < 0.0) { 394
395 printf (_("<crta> was not set\n")); 395 if (config_wrapper.config.crta < 0.0) {
396 return ERROR; 396 printf(_("<crta> was not set\n"));
397 config_wrapper.errorcode = ERROR;
398 return config_wrapper;
397 } 399 }
398 else if (wpl == UNKNOWN_PACKET_LOSS) { 400
399 printf (_("<wpl> was not set\n")); 401 if (config_wrapper.config.wpl == UNKNOWN_PACKET_LOSS) {
400 return ERROR; 402 printf(_("<wpl> was not set\n"));
403 config_wrapper.errorcode = ERROR;
404 return config_wrapper;
401 } 405 }
402 else if (cpl == UNKNOWN_PACKET_LOSS) { 406
403 printf (_("<cpl> was not set\n")); 407 if (config_wrapper.config.cpl == UNKNOWN_PACKET_LOSS) {
404 return ERROR; 408 printf(_("<cpl> was not set\n"));
409 config_wrapper.errorcode = ERROR;
410 return config_wrapper;
405 } 411 }
406 else if (wrta > crta) { 412
407 printf (_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta); 413 if (config_wrapper.config.wrta > config_wrapper.config.crta) {
408 return ERROR; 414 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), config_wrapper.config.wrta, config_wrapper.config.crta);
415 config_wrapper.errorcode = ERROR;
416 return config_wrapper;
409 } 417 }
410 else if (wpl > cpl) { 418
411 printf (_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl); 419 if (config_wrapper.config.wpl > config_wrapper.config.cpl) {
412 return ERROR; 420 printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), config_wrapper.config.wpl, config_wrapper.config.cpl);
421 config_wrapper.errorcode = ERROR;
422 return config_wrapper;
413 } 423 }
414 424
415 if (max_packets == -1) 425 if (config_wrapper.config.max_packets == -1) {
416 max_packets = DEFAULT_MAX_PACKETS; 426 config_wrapper.config.max_packets = DEFAULT_MAX_PACKETS;
427 }
417 428
418 max_seconds = crta / 1000.0 * max_packets + max_packets; 429 double max_seconds = (config_wrapper.config.crta / 1000.0 * config_wrapper.config.max_packets) + config_wrapper.config.max_packets;
419 if (max_seconds > timeout_interval) 430 if (max_seconds > timeout_interval) {
420 timeout_interval = (int)max_seconds; 431 timeout_interval = (unsigned int)max_seconds;
432 }
421 433
422 for (i=0; i<n_addresses; i++) { 434 for (size_t i = 0; i < config_wrapper.config.n_addresses; i++) {
423 if (!is_host(addresses[i])) 435 if (!is_host(config_wrapper.config.addresses[i])) {
424 usage2 (_("Invalid hostname/address"), addresses[i]); 436 usage2(_("Invalid hostname/address"), config_wrapper.config.addresses[i]);
437 }
425 } 438 }
426 439
427 if (n_addresses == 0) { 440 if (config_wrapper.config.n_addresses == 0) {
428 usage (_("You must specify a server address or host name")); 441 usage(_("You must specify a server address or host name"));
429 } 442 }
430 443
431 return OK; 444 return config_wrapper;
432} 445}
433 446
447ping_result run_ping(const char *cmd, const char *addr, double crta) {
448 if ((child_process = spopen(cmd)) == NULL) {
449 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
450 }
434 451
452 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
453 if (child_stderr == NULL) {
454 printf(_("Cannot open stderr for %s\n"), cmd);
455 }
435 456
436int
437run_ping (const char *cmd, const char *addr)
438{
439 char buf[MAX_INPUT_BUFFER]; 457 char buf[MAX_INPUT_BUFFER];
440 int result = STATE_UNKNOWN; 458 ping_result result = {
441 int match; 459 .state = STATE_UNKNOWN,
442 460 .packet_loss = UNKNOWN_PACKET_LOSS,
443 if ((child_process = spopen (cmd)) == NULL) 461 .round_trip_average = UNKNOWN_TRIP_TIME,
444 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 462 };
445
446 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
447 if (child_stderr == NULL)
448 printf (_("Cannot open stderr for %s\n"), cmd);
449
450 while (fgets (buf, MAX_INPUT_BUFFER - 1, child_process)) {
451 463
452 if (verbose >= 3) 464 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
465 if (verbose >= 3) {
453 printf("Output: %s", buf); 466 printf("Output: %s", buf);
467 }
454 468
455 result = max_state (result, error_scan (buf, addr)); 469 result.state = max_state(result.state, error_scan(buf, addr));
456 470
457 /* get the percent loss statistics */ 471 /* get the percent loss statistics */
458 match = 0; 472 int match = 0;
459 if((sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 473 if ((sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) ==
460 (sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n",&pl,&match) && match) || 474 1 &&
461 (sscanf(buf,"%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n",&pl,&match) && match) || 475 match) ||
462 (sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% packet loss%n",&pl,&match) && match) || 476 (sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &result.packet_loss,
463 (sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% loss, time%n",&pl,&match) && match) || 477 &match) == 1 &&
464 (sscanf(buf,"%*d packets transmitted, %*d received, %d%% loss, time%n",&pl,&match) && match) || 478 match) ||
465 (sscanf(buf,"%*d packets transmitted, %*d received, %d%% packet loss, time%n",&pl,&match) && match) || 479 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
466 (sscanf(buf,"%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 480 match) ||
467 (sscanf(buf,"%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n",&pl,&match) && match) || 481 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% packet loss%n", &result.packet_loss, &match) == 1 && match) ||
468 (sscanf(buf,"%*[^(](%d%% %*[^)])%n",&pl,&match) && match) 482 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &result.packet_loss, &match) == 1 && match) ||
469 ) 483 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &result.packet_loss, &match) == 1 && match) ||
484 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% packet loss, time%n", &result.packet_loss, &match) == 1 && match) ==
485 1 ||
486 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
487 match) ||
488 (sscanf(buf, "%*d packets transmitted %*d received, +%*d errors, %d%% packet loss%n", &result.packet_loss, &match) == 1 &&
489 match) ||
490 (sscanf(buf, "%*[^(](%d%% %*[^)])%n", &result.packet_loss, &match) == 1 && match)) {
470 continue; 491 continue;
492 }
471 493
472 /* get the round trip average */ 494 /* get the round trip average */
473 else 495 if ((sscanf(buf, "round-trip min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
474 if((sscanf(buf,"round-trip min/avg/max = %*f/%f/%*f%n",&rta,&match) && match) || 496 (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
475 (sscanf(buf,"round-trip min/avg/max/mdev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 497 (sscanf(buf, "round-trip min/avg/max/sdev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
476 (sscanf(buf,"round-trip min/avg/max/sdev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 498 (sscanf(buf, "round-trip min/avg/max/stddev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
477 (sscanf(buf,"round-trip min/avg/max/stddev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 499 (sscanf(buf, "round-trip min/avg/max/std-dev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
478 (sscanf(buf,"round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 500 (sscanf(buf, "round-trip (ms) min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
479 (sscanf(buf,"round-trip (ms) min/avg/max = %*f/%f/%*f%n",&rta,&match) && match) || 501 (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%lf/%*f/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
480 (sscanf(buf,"round-trip (ms) min/avg/max/stddev = %*f/%f/%*f/%*f%n",&rta,&match) && match) || 502 (sscanf(buf, "rtt min/avg/max/mdev = %*f/%lf/%*f/%*f ms%n", &result.round_trip_average, &match) == 1 && match) ||
481 (sscanf(buf,"rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%n",&rta,&match) && match) || 503 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %lfms%n", &result.round_trip_average, &match) == 1 && match)) {
482 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match)
483 )
484 continue; 504 continue;
505 }
485 } 506 }
486 507
487 /* this is needed because there is no rta if all packets are lost */ 508 /* this is needed because there is no rta if all packets are lost */
488 if (pl == 100) 509 if (result.packet_loss == 100) {
489 rta = crta; 510 result.round_trip_average = crta;
511 }
490 512
491 /* check stderr, setting at least WARNING if there is output here */ 513 /* check stderr, setting at least WARNING if there is output here */
492 /* Add warning into warn_text */ 514 /* Add warning into warn_text */
493 while (fgets (buf, MAX_INPUT_BUFFER - 1, child_stderr)) { 515 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr)) {
494 if ( 516 if (!strstr(buf, "WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP") && !strstr(buf, "Warning: time of day goes back")
495 ! strstr(buf,"WARNING - no SO_TIMESTAMP support, falling back to SIOCGSTAMP")
496 && ! strstr(buf,"Warning: time of day goes back")
497 517
498 ) { 518 ) {
499 if (verbose >= 3) { 519 if (verbose >= 3) {
500 printf("Got stderr: %s", buf); 520 printf("Got stderr: %s", buf);
501 } 521 }
502 if ((result=error_scan(buf, addr)) == STATE_OK) { 522 if ((result.state = error_scan(buf, addr)) == STATE_OK) {
503 result = STATE_WARNING; 523 result.state = STATE_WARNING;
504 if (warn_text == NULL) { 524 if (warn_text == NULL) {
505 warn_text = strdup(_("System call sent warnings to stderr ")); 525 warn_text = strdup(_("System call sent warnings to stderr "));
506 } else { 526 } else {
@@ -510,111 +530,97 @@ run_ping (const char *cmd, const char *addr)
510 } 530 }
511 } 531 }
512 532
513 (void) fclose (child_stderr); 533 (void)fclose(child_stderr);
514 534
535 spclose(child_process);
515 536
516 spclose (child_process); 537 if (warn_text == NULL) {
517
518 if (warn_text == NULL)
519 warn_text = strdup(""); 538 warn_text = strdup("");
539 }
520 540
521 return result; 541 return result;
522} 542}
523 543
544mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) {
545 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) {
546 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
547 } else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) {
548 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
549 } else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) {
550 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
551 } else if (strstr(buf, "Destination Protocol Unreachable")) {
552 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
553 } else if (strstr(buf, "Destination Net Prohibited")) {
554 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
555 } else if (strstr(buf, "Destination Host Prohibited")) {
556 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
557 } else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) {
558 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
559 } else if (strstr(buf, "unknown host")) {
560 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
561 } else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) {
562 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
563 } else if (strstr(buf, "Destination unreachable: ")) {
564 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
565 }
524 566
567 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) {
568 if (warn_text == NULL) {
569 warn_text = strdup(_(WARN_DUPLICATES));
570 } else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) {
571 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
572 }
573 return STATE_WARNING;
574 }
525 575
526int 576 return STATE_OK;
527error_scan (char buf[MAX_INPUT_BUFFER], const char *addr)
528{
529 if (strstr (buf, "Network is unreachable") ||
530 strstr (buf, "Destination Net Unreachable") ||
531 strstr (buf, "No route")
532 )
533 die (STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
534 else if (strstr (buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable"))
535 die (STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
536 else if (strstr (buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable"))
537 die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
538 else if (strstr (buf, "Destination Protocol Unreachable"))
539 die (STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
540 else if (strstr (buf, "Destination Net Prohibited"))
541 die (STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
542 else if (strstr (buf, "Destination Host Prohibited"))
543 die (STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
544 else if (strstr (buf, "Packet filtered") || strstr(buf, "Administratively prohibited"))
545 die (STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
546 else if (strstr (buf, "unknown host" ))
547 die (STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
548 else if (strstr (buf, "Time to live exceeded") || strstr(buf, "Time exceeded"))
549 die (STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
550 else if (strstr (buf, "Destination unreachable: "))
551 die (STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
552
553 if (strstr (buf, "(DUP!)") || strstr (buf, "DUPLICATES FOUND")) {
554 if (warn_text == NULL)
555 warn_text = strdup (_(WARN_DUPLICATES));
556 else if (! strstr (warn_text, _(WARN_DUPLICATES)) &&
557 xasprintf (&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1)
558 die (STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
559 return (STATE_WARNING);
560 }
561
562 return (STATE_OK);
563} 577}
564 578
579void print_help(void) {
580 print_revision(progname, NP_VERSION);
565 581
582 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
583 printf(COPYRIGHT, copyright, email);
566 584
567void 585 printf(_("Use ping to check connection statistics for a remote host."));
568print_help (void)
569{
570 print_revision (progname, NP_VERSION);
571
572 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
573 printf (COPYRIGHT, copyright, email);
574
575 printf (_("Use ping to check connection statistics for a remote host."));
576 586
577 printf ("\n\n"); 587 printf("\n\n");
578 588
579 print_usage (); 589 print_usage();
580 590
581 printf (UT_HELP_VRSN); 591 printf(UT_HELP_VRSN);
582 printf (UT_EXTRA_OPTS); 592 printf(UT_EXTRA_OPTS);
583 593
584 printf (UT_IPv46); 594 printf(UT_IPv46);
585 595
586 printf (" %s\n", "-H, --hostname=HOST"); 596 printf(" %s\n", "-H, --hostname=HOST");
587 printf (" %s\n", _("host to ping")); 597 printf(" %s\n", _("host to ping"));
588 printf (" %s\n", "-w, --warning=THRESHOLD"); 598 printf(" %s\n", "-w, --warning=THRESHOLD");
589 printf (" %s\n", _("warning threshold pair")); 599 printf(" %s\n", _("warning threshold pair"));
590 printf (" %s\n", "-c, --critical=THRESHOLD"); 600 printf(" %s\n", "-c, --critical=THRESHOLD");
591 printf (" %s\n", _("critical threshold pair")); 601 printf(" %s\n", _("critical threshold pair"));
592 printf (" %s\n", "-p, --packets=INTEGER"); 602 printf(" %s\n", "-p, --packets=INTEGER");
593 printf (" %s ", _("number of ICMP ECHO packets to send")); 603 printf(" %s ", _("number of ICMP ECHO packets to send"));
594 printf (_("(Default: %d)\n"), DEFAULT_MAX_PACKETS); 604 printf(_("(Default: %d)\n"), DEFAULT_MAX_PACKETS);
595 printf (" %s\n", "-L, --link"); 605 printf(" %s\n", "-L, --link");
596 printf (" %s\n", _("show HTML in the plugin output (obsoleted by urlize)")); 606 printf(" %s\n", _("show HTML in the plugin output (obsoleted by urlize)"));
597 607
598 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 608 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
599 609
600 printf ("\n"); 610 printf("\n");
601 printf ("%s\n", _("THRESHOLD is <rta>,<pl>% where <rta> is the round trip average travel")); 611 printf("%s\n", _("THRESHOLD is <rta>,<pl>% where <rta> is the round trip average travel"));
602 printf ("%s\n", _("time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the")); 612 printf("%s\n", _("time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the"));
603 printf ("%s\n", _("percentage of packet loss to trigger an alarm state.")); 613 printf("%s\n", _("percentage of packet loss to trigger an alarm state."));
604 614
605 printf ("\n"); 615 printf("\n");
606 printf ("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss")); 616 printf("%s\n", _("This plugin uses the ping command to probe the specified host for packet loss"));
607 printf ("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output")); 617 printf("%s\n", _("(percentage) and round trip average (milliseconds). It can produce HTML output."));
608 printf ("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in"));
609 printf ("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/"));
610 618
611 printf (UT_SUPPORT); 619 printf(UT_SUPPORT);
612} 620}
613 621
614void 622void print_usage(void) {
615print_usage (void) 623 printf("%s\n", _("Usage:"));
616{ 624 printf("%s -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n", progname);
617 printf ("%s\n", _("Usage:")); 625 printf(" [-p packets] [-t timeout] [-4|-6]\n");
618 printf ("%s -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n", progname);
619 printf (" [-p packets] [-t timeout] [-4|-6]\n");
620} 626}
diff --git a/plugins/check_ping.d/config.h b/plugins/check_ping.d/config.h
new file mode 100644
index 00000000..eb2735a7
--- /dev/null
+++ b/plugins/check_ping.d/config.h
@@ -0,0 +1,46 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <stdlib.h>
6
7enum {
8 UNKNOWN_PACKET_LOSS = 200, /* 200% */
9 DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */
10};
11
12#define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
13
14#define MAX_ADDR_START 1
15
16typedef struct {
17 bool display_html;
18 int max_packets;
19
20 char **addresses;
21 size_t n_addresses;
22
23 int wpl;
24 int cpl;
25 double wrta;
26 double crta;
27} check_ping_config;
28
29check_ping_config check_ping_config_init() {
30 check_ping_config tmp = {
31 .display_html = false,
32 .max_packets = -1,
33
34 .addresses = NULL,
35 .n_addresses = 0,
36
37 .wpl = UNKNOWN_PACKET_LOSS,
38 .cpl = UNKNOWN_PACKET_LOSS,
39 .wrta = UNKNOWN_TRIP_TIME,
40 .crta = UNKNOWN_TRIP_TIME,
41 };
42
43 tmp.addresses = calloc(MAX_ADDR_START, sizeof(char *));
44 tmp.addresses[0] = NULL;
45 return tmp;
46}
diff --git a/plugins/check_procs.c b/plugins/check_procs.c
index 1fcbd981..83e6864e 100644
--- a/plugins/check_procs.c
+++ b/plugins/check_procs.c
@@ -1,357 +1,330 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_procs plugin 3 * Monitoring check_procs plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_procs plugin 10 * This file contains the check_procs plugin
11* 11 *
12* Checks all processes and generates WARNING or CRITICAL states if the 12 * Checks all processes and generates WARNING or CRITICAL states if the
13* specified metric is outside the required threshold ranges. The metric 13 * specified metric is outside the required threshold ranges. The metric
14* defaults to number of processes. Search filters can be applied to limit 14 * defaults to number of processes. Search filters can be applied to limit
15* the processes to check. 15 * the processes to check.
16* 16 *
17* The parent process, check_procs itself and any child process of 17 * The parent process, check_procs itself and any child process of
18* check_procs (ps) are excluded from any checks to prevent false positives. 18 * check_procs (ps) are excluded from any checks to prevent false positives.
19* 19 *
20* 20 *
21* This program is free software: you can redistribute it and/or modify 21 * This program is free software: you can redistribute it and/or modify
22* it under the terms of the GNU General Public License as published by 22 * it under the terms of the GNU General Public License as published by
23* the Free Software Foundation, either version 3 of the License, or 23 * the Free Software Foundation, either version 3 of the License, or
24* (at your option) any later version. 24 * (at your option) any later version.
25* 25 *
26* This program is distributed in the hope that it will be useful, 26 * This program is distributed in the hope that it will be useful,
27* but WITHOUT ANY WARRANTY; without even the implied warranty of 27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29* GNU General Public License for more details. 29 * GNU General Public License for more details.
30* 30 *
31* You should have received a copy of the GNU General Public License 31 * You should have received a copy of the GNU General Public License
32* along with this program. If not, see <http://www.gnu.org/licenses/>. 32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
33* 33 *
34* 34 *
35*****************************************************************************/ 35 *****************************************************************************/
36 36
37const char *progname = "check_procs"; 37const char *progname = "check_procs";
38const char *program_name = "check_procs"; /* Required for coreutils libs */ 38const char *program_name = "check_procs"; /* Required for coreutils libs */
39const char *copyright = "2000-2008"; 39const char *copyright = "2000-2024";
40const char *email = "devel@monitoring-plugins.org"; 40const char *email = "devel@monitoring-plugins.org";
41 41
42#include "common.h" 42#include "common.h"
43#include "utils.h" 43#include "utils.h"
44#include "utils_cmd.h" 44#include "utils_cmd.h"
45#include "regex.h" 45#include "regex.h"
46#include "states.h"
47#include "check_procs.d/config.h"
46 48
47#include <pwd.h> 49#include <pwd.h>
48#include <errno.h> 50#include <errno.h>
49 51
50#ifdef HAVE_SYS_STAT_H 52#ifdef HAVE_SYS_STAT_H
51#include <sys/stat.h> 53# include <sys/stat.h>
52#endif 54#endif
53 55
54int process_arguments (int, char **); 56typedef struct {
55int validate_arguments (void); 57 int errorcode;
56int convert_to_seconds (char *); 58 check_procs_config config;
57void print_help (void); 59} check_procs_config_wrapper;
58void print_usage (void); 60static check_procs_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
59 61static check_procs_config_wrapper validate_arguments(check_procs_config_wrapper /*config_wrapper*/);
60char *warning_range = NULL; 62
61char *critical_range = NULL; 63static int convert_to_seconds(char * /*etime*/, enum metric /*metric*/);
62thresholds *procs_thresholds = NULL; 64static void print_help(void);
63 65void print_usage(void);
64int options = 0; /* bitmask of filter criteria to test against */ 66
65#define ALL 1 67#define ALL 1
66#define STAT 2 68#define STAT 2
67#define PPID 4 69#define PPID 4
68#define USER 8 70#define USER 8
69#define PROG 16 71#define PROG 16
70#define ARGS 32 72#define ARGS 32
71#define VSZ 64 73#define VSZ 64
72#define RSS 128 74#define RSS 128
73#define PCPU 256 75#define PCPU 256
74#define ELAPSED 512 76#define ELAPSED 512
75#define EREG_ARGS 1024 77#define EREG_ARGS 1024
76#define EXCLUDE_PROGS 2048 78#define EXCLUDE_PROGS 2048
77 79
78#define KTHREAD_PARENT "kthreadd" /* the parent process of kernel threads: 80#define KTHREAD_PARENT \
79 ppid of procs are compared to pid of this proc*/ 81 "kthreadd" /* the parent process of kernel threads: \
80 82 ppid of procs are compared to pid of this proc*/
81/* Different metrics */ 83
82char *metric_name; 84static int verbose = 0;
83enum metric { 85
84 METRIC_PROCS, 86static int stat_exe(const pid_t pid, struct stat *buf) {
85 METRIC_VSZ,
86 METRIC_RSS,
87 METRIC_CPU,
88 METRIC_ELAPSED
89};
90enum metric metric = METRIC_PROCS;
91
92int verbose = 0;
93int uid;
94pid_t ppid;
95int vsz;
96int rss;
97float pcpu;
98char *statopts;
99char *prog;
100char *exclude_progs;
101char **exclude_progs_arr = NULL;
102char exclude_progs_counter = 0;
103char *args;
104char *input_filename = NULL;
105regex_t re_args;
106char *fmt;
107char *fails;
108char tmp[MAX_INPUT_BUFFER];
109int kthread_filter = 0;
110int usepid = 0; /* whether to test for pid or /proc/pid/exe */
111
112FILE *ps_input = NULL;
113
114static int
115stat_exe (const pid_t pid, struct stat *buf) {
116 char *path; 87 char *path;
117 int ret;
118 xasprintf(&path, "/proc/%d/exe", pid); 88 xasprintf(&path, "/proc/%d/exe", pid);
119 ret = stat(path, buf); 89 int ret = stat(path, buf);
120 free(path); 90 free(path);
121 return ret; 91 return ret;
122} 92}
123 93
124 94int main(int argc, char **argv) {
125int 95 setlocale(LC_ALL, "");
126main (int argc, char **argv)
127{
128 char *input_buffer;
129 char *input_line;
130 char *procprog;
131
132 pid_t mypid = 0;
133 pid_t myppid = 0;
134 struct stat statbuf;
135 dev_t mydev = 0;
136 ino_t myino = 0;
137 int procuid = 0;
138 pid_t procpid = 0;
139 pid_t procppid = 0;
140 pid_t kthread_ppid = 0;
141 int procvsz = 0;
142 int procrss = 0;
143 int procseconds = 0;
144 float procpcpu = 0;
145 char procstat[8];
146 char procetime[MAX_INPUT_BUFFER] = { '\0' };
147 char *procargs;
148
149 const char *zombie = "Z";
150
151 int resultsum = 0; /* bitmask of the filter criteria met by a process */
152 int found = 0; /* counter for number of lines returned in `ps` output */
153 int procs = 0; /* counter for number of processes meeting filter criteria */
154 int pos; /* number of spaces before 'args' in `ps` output */
155 int cols; /* number of columns in ps output */
156 int expected_cols = PS_COLS - 1;
157 int warn = 0; /* number of processes in warn state */
158 int crit = 0; /* number of processes in crit state */
159 int i = 0;
160 int result = STATE_UNKNOWN;
161 int ret = 0;
162 output chld_out, chld_err;
163
164 setlocale (LC_ALL, "");
165 bindtextdomain (PACKAGE, LOCALEDIR);
166 textdomain (PACKAGE);
167 setlocale(LC_NUMERIC, "POSIX"); 96 setlocale(LC_NUMERIC, "POSIX");
168 97 bindtextdomain(PACKAGE, LOCALEDIR);
169 input_buffer = malloc (MAX_INPUT_BUFFER); 98 textdomain(PACKAGE);
170 procprog = malloc (MAX_INPUT_BUFFER);
171
172 xasprintf (&metric_name, "PROCS");
173 metric = METRIC_PROCS;
174 99
175 /* Parse extra opts if any */ 100 /* Parse extra opts if any */
176 argv=np_extra_opts (&argc, argv, progname); 101 argv = np_extra_opts(&argc, argv, progname);
102
103 check_procs_config_wrapper tmp_config = process_arguments(argc, argv);
104 if (tmp_config.errorcode == ERROR) {
105 usage4(_("Could not parse arguments"));
106 }
177 107
178 if (process_arguments (argc, argv) == ERROR) 108 check_procs_config config = tmp_config.config;
179 usage4 (_("Could not parse arguments"));
180 109
181 /* find ourself */ 110 /* find ourself */
182 mypid = getpid(); 111 pid_t mypid = getpid();
183 myppid = getppid(); 112 pid_t myppid = getppid();
184 if (usepid || stat_exe(mypid, &statbuf) == -1) { 113 dev_t mydev = 0;
114 ino_t myino = 0;
115 struct stat statbuf;
116 if (config.usepid || stat_exe(mypid, &statbuf) == -1) {
185 /* usepid might have been set by -T */ 117 /* usepid might have been set by -T */
186 usepid = 1; 118 config.usepid = true;
187 } else { 119 } else {
188 usepid = 0; 120 config.usepid = false;
189 mydev = statbuf.st_dev; 121 mydev = statbuf.st_dev;
190 myino = statbuf.st_ino; 122 myino = statbuf.st_ino;
191 } 123 }
192 124
193 /* Set signal handling and alarm timeout */ 125 /* Set signal handling and alarm timeout */
194 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 126 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
195 die (STATE_UNKNOWN, _("Cannot catch SIGALRM")); 127 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
196 } 128 }
197 (void) alarm ((unsigned) timeout_interval); 129 (void)alarm(timeout_interval);
198 130
199 if (verbose >= 2) 131 if (verbose >= 2) {
200 printf (_("CMD: %s\n"), PS_COMMAND); 132 printf(_("CMD: %s\n"), PS_COMMAND);
133 }
201 134
202 if (input_filename == NULL) { 135 output chld_out;
203 result = cmd_run( PS_COMMAND, &chld_out, &chld_err, 0); 136 output chld_err;
137 mp_state_enum result = STATE_UNKNOWN;
138 if (config.input_filename == NULL) {
139 result = cmd_run(PS_COMMAND, &chld_out, &chld_err, 0);
204 if (chld_err.lines > 0) { 140 if (chld_err.lines > 0) {
205 printf ("%s: %s", _("System call sent warnings to stderr"), chld_err.line[0]); 141 printf("%s: %s", _("System call sent warnings to stderr"), chld_err.line[0]);
206 exit(STATE_WARNING); 142 exit(STATE_WARNING);
207 } 143 }
208 } else { 144 } else {
209 result = cmd_file_read( input_filename, &chld_out, 0); 145 result = cmd_file_read(config.input_filename, &chld_out, 0);
210 } 146 }
211 147
148 int pos; /* number of spaces before 'args' in `ps` output */
149 uid_t procuid = 0;
150 pid_t procpid = 0;
151 pid_t procppid = 0;
152 pid_t kthread_ppid = 0;
153 int warn = 0; /* number of processes in warn state */
154 int crit = 0; /* number of processes in crit state */
155 int procvsz = 0;
156 int procrss = 0;
157 int procseconds = 0;
158 float procpcpu = 0;
159 char procstat[8];
160 char procetime[MAX_INPUT_BUFFER] = {'\0'};
161 int resultsum = 0; /* bitmask of the filter criteria met by a process */
162 int found = 0; /* counter for number of lines returned in `ps` output */
163 int procs = 0; /* counter for number of processes meeting filter criteria */
164 char *input_buffer = malloc(MAX_INPUT_BUFFER);
165 char *procprog = malloc(MAX_INPUT_BUFFER);
166 const int expected_cols = PS_COLS - 1;
167
212 /* flush first line: j starts at 1 */ 168 /* flush first line: j starts at 1 */
213 for (size_t j = 1; j < chld_out.lines; j++) { 169 for (size_t j = 1; j < chld_out.lines; j++) {
214 input_line = chld_out.line[j]; 170 char *input_line = chld_out.line[j];
215 171
216 if (verbose >= 3) 172 if (verbose >= 3) {
217 printf ("%s", input_line); 173 printf("%s", input_line);
174 }
218 175
219 strcpy (procprog, ""); 176 strcpy(procprog, "");
220 xasprintf (&procargs, "%s", ""); 177 char *procargs;
178 xasprintf(&procargs, "%s", "");
221 179
222 cols = sscanf (input_line, PS_FORMAT, PS_VARLIST); 180 /* number of columns in ps output */
181 int cols = sscanf(input_line, PS_FORMAT, PS_VARLIST);
223 182
224 /* Zombie processes do not give a procprog command */ 183 /* Zombie processes do not give a procprog command */
225 if ( cols < expected_cols && strstr(procstat, zombie) ) { 184 const char *zombie = "Z";
185 if (cols < expected_cols && strstr(procstat, zombie)) {
226 cols = expected_cols; 186 cols = expected_cols;
227 } 187 }
228 if ( cols >= expected_cols ) { 188 if (cols >= expected_cols) {
229 resultsum = 0; 189 resultsum = 0;
230 xasprintf (&procargs, "%s", input_line + pos); 190 xasprintf(&procargs, "%s", input_line + pos);
231 strip (procargs); 191 strip(procargs);
232 192
233 /* Some ps return full pathname for command. This removes path */ 193 /* Some ps return full pathname for command. This removes path */
234 strcpy(procprog, base_name(procprog)); 194 strcpy(procprog, base_name(procprog));
235 195
236 /* we need to convert the elapsed time to seconds */ 196 /* we need to convert the elapsed time to seconds */
237 procseconds = convert_to_seconds(procetime); 197 procseconds = convert_to_seconds(procetime, config.metric);
238 198
239 if (verbose >= 3) 199 if (verbose >= 3) {
240 printf ("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 200 printf("proc#=%d uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", procs, procuid, procvsz,
241 procs, procuid, procvsz, procrss, 201 procrss, procpid, procppid, procpcpu, procstat, procetime, procprog, procargs);
242 procpid, procppid, procpcpu, procstat, 202 }
243 procetime, procprog, procargs);
244 203
245 /* Ignore self */ 204 /* Ignore self */
246 if ((usepid && mypid == procpid) || 205 int ret = 0;
247 ( ((!usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) || 206 if ((config.usepid && mypid == procpid) ||
248 (ret == -1 && errno == ENOENT)) 207 (((!config.usepid) && ((ret = stat_exe(procpid, &statbuf) != -1) && statbuf.st_dev == mydev && statbuf.st_ino == myino)) ||
249 ) { 208 (ret == -1 && errno == ENOENT))) {
250 if (verbose >= 3) 209 if (verbose >= 3) {
251 printf("not considering - is myself or gone\n"); 210 printf("not considering - is myself or gone\n");
211 }
252 continue; 212 continue;
253 } 213 }
254 /* Ignore parent*/ 214 /* Ignore parent*/
255 else if (myppid == procpid) { 215 if (myppid == procpid) {
256 if (verbose >= 3) 216 if (verbose >= 3) {
257 printf("not considering - is parent\n"); 217 printf("not considering - is parent\n");
218 }
258 continue; 219 continue;
259 } 220 }
260 221
261 /* Ignore our own children */ 222 /* Ignore our own children */
262 if (procppid == mypid) { 223 if (procppid == mypid) {
263 if (verbose >= 3) 224 if (verbose >= 3) {
264 printf("not considering - is our child\n"); 225 printf("not considering - is our child\n");
226 }
265 continue; 227 continue;
266 } 228 }
267 229
268 /* Ignore excluded processes by name */ 230 /* Ignore excluded processes by name */
269 if(options & EXCLUDE_PROGS) { 231 if (config.options & EXCLUDE_PROGS) {
270 int found = 0; 232 bool found = false;
271 int i = 0; 233 for (int i = 0; i < (config.exclude_progs_counter); i++) {
272 234 if (!strcmp(procprog, config.exclude_progs_arr[i])) {
273 for(i=0; i < (exclude_progs_counter); i++) { 235 found = true;
274 if(!strcmp(procprog, exclude_progs_arr[i])) { 236 }
275 found = 1; 237 }
276 } 238 if (!found) {
277 } 239 resultsum |= EXCLUDE_PROGS;
278 if(found == 0) { 240 } else {
279 resultsum |= EXCLUDE_PROGS; 241 if (verbose >= 3) {
280 } else 242 printf("excluding - by ignorelist\n");
281 { 243 }
282 if(verbose >= 3) 244 }
283 printf("excluding - by ignorelist\n");
284 }
285 } 245 }
286 246
287 /* filter kernel threads (children of KTHREAD_PARENT)*/ 247 /* filter kernel threads (children of KTHREAD_PARENT)*/
288 /* TODO adapt for other OSes than GNU/Linux 248 /* TODO adapt for other OSes than GNU/Linux
289 sorry for not doing that, but I've no other OSes to test :-( */ 249 sorry for not doing that, but I've no other OSes to test :-( */
290 if (kthread_filter == 1) { 250 if (config.kthread_filter) {
291 /* get pid KTHREAD_PARENT */ 251 /* get pid KTHREAD_PARENT */
292 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT) ) 252 if (kthread_ppid == 0 && !strcmp(procprog, KTHREAD_PARENT)) {
293 kthread_ppid = procpid; 253 kthread_ppid = procpid;
254 }
294 255
295 if (kthread_ppid == procppid) { 256 if (kthread_ppid == procppid) {
296 if (verbose >= 2) 257 if (verbose >= 2) {
297 printf ("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs); 258 printf("Ignore kernel thread: pid=%d ppid=%d prog=%s args=%s\n", procpid, procppid, procprog, procargs);
259 }
298 continue; 260 continue;
299 } 261 }
300 } 262 }
301 263
302 if ((options & STAT) && (strstr (procstat, statopts))) 264 if ((config.options & STAT) && (strstr(procstat, config.statopts))) {
303 resultsum |= STAT; 265 resultsum |= STAT;
304 if ((options & ARGS) && procargs && (strstr (procargs, args) != NULL)) 266 }
267 if ((config.options & ARGS) && procargs && (strstr(procargs, config.args) != NULL)) {
305 resultsum |= ARGS; 268 resultsum |= ARGS;
306 if ((options & EREG_ARGS) && procargs && (regexec(&re_args, procargs, (size_t) 0, NULL, 0) == 0)) 269 }
270 if ((config.options & EREG_ARGS) && procargs && (regexec(&config.re_args, procargs, (size_t)0, NULL, 0) == 0)) {
307 resultsum |= EREG_ARGS; 271 resultsum |= EREG_ARGS;
308 if ((options & PROG) && procprog && (strcmp (prog, procprog) == 0)) 272 }
273 if ((config.options & PROG) && procprog && (strcmp(config.prog, procprog) == 0)) {
309 resultsum |= PROG; 274 resultsum |= PROG;
310 if ((options & PPID) && (procppid == ppid)) 275 }
276 if ((config.options & PPID) && (procppid == config.ppid)) {
311 resultsum |= PPID; 277 resultsum |= PPID;
312 if ((options & USER) && (procuid == uid)) 278 }
279 if ((config.options & USER) && (procuid == config.uid)) {
313 resultsum |= USER; 280 resultsum |= USER;
314 if ((options & VSZ) && (procvsz >= vsz)) 281 }
282 if ((config.options & VSZ) && (procvsz >= config.vsz)) {
315 resultsum |= VSZ; 283 resultsum |= VSZ;
316 if ((options & RSS) && (procrss >= rss)) 284 }
285 if ((config.options & RSS) && (procrss >= config.rss)) {
317 resultsum |= RSS; 286 resultsum |= RSS;
318 if ((options & PCPU) && (procpcpu >= pcpu)) 287 }
288 if ((config.options & PCPU) && (procpcpu >= config.pcpu)) {
319 resultsum |= PCPU; 289 resultsum |= PCPU;
290 }
320 291
321 found++; 292 found++;
322 293
323 /* Next line if filters not matched */ 294 /* Next line if filters not matched */
324 if (!(options == resultsum || options == ALL)) 295 if (!(config.options == resultsum || config.options == ALL)) {
325 continue; 296 continue;
297 }
326 298
327 procs++; 299 procs++;
328 if (verbose >= 2) { 300 if (verbose >= 2) {
329 printf ("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", 301 printf("Matched: uid=%d vsz=%d rss=%d pid=%d ppid=%d pcpu=%.2f stat=%s etime=%s prog=%s args=%s\n", procuid, procvsz,
330 procuid, procvsz, procrss, 302 procrss, procpid, procppid, procpcpu, procstat, procetime, procprog, procargs);
331 procpid, procppid, procpcpu, procstat,
332 procetime, procprog, procargs);
333 } 303 }
334 304
335 if (metric == METRIC_VSZ) 305 mp_state_enum temporary_result = STATE_OK;
336 i = get_status ((double)procvsz, procs_thresholds); 306 if (config.metric == METRIC_VSZ) {
337 else if (metric == METRIC_RSS) 307 temporary_result = get_status((double)procvsz, config.procs_thresholds);
338 i = get_status ((double)procrss, procs_thresholds); 308 } else if (config.metric == METRIC_RSS) {
309 temporary_result = get_status((double)procrss, config.procs_thresholds);
310 }
339 /* TODO? float thresholds for --metric=CPU */ 311 /* TODO? float thresholds for --metric=CPU */
340 else if (metric == METRIC_CPU) 312 else if (config.metric == METRIC_CPU) {
341 i = get_status (procpcpu, procs_thresholds); 313 temporary_result = get_status(procpcpu, config.procs_thresholds);
342 else if (metric == METRIC_ELAPSED) 314 } else if (config.metric == METRIC_ELAPSED) {
343 i = get_status ((double)procseconds, procs_thresholds); 315 temporary_result = get_status((double)procseconds, config.procs_thresholds);
316 }
344 317
345 if (metric != METRIC_PROCS) { 318 if (config.metric != METRIC_PROCS) {
346 if (i == STATE_WARNING) { 319 if (temporary_result == STATE_WARNING) {
347 warn++; 320 warn++;
348 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 321 xasprintf(&config.fails, "%s%s%s", config.fails, (strcmp(config.fails, "") ? ", " : ""), procprog);
349 result = max_state (result, i); 322 result = max_state(result, temporary_result);
350 } 323 }
351 if (i == STATE_CRITICAL) { 324 if (temporary_result == STATE_CRITICAL) {
352 crit++; 325 crit++;
353 xasprintf (&fails, "%s%s%s", fails, (strcmp(fails,"") ? ", " : ""), procprog); 326 xasprintf(&config.fails, "%s%s%s", config.fails, (strcmp(config.fails, "") ? ", " : ""), procprog);
354 result = max_state (result, i); 327 result = max_state(result, temporary_result);
355 } 328 }
356 } 329 }
357 } 330 }
@@ -361,339 +334,350 @@ main (int argc, char **argv)
361 } 334 }
362 } 335 }
363 336
364 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */ 337 if (found == 0) { /* no process lines parsed so return STATE_UNKNOWN */
365 printf (_("Unable to read output\n")); 338 printf(_("Unable to read output\n"));
366 return STATE_UNKNOWN; 339 return STATE_UNKNOWN;
367 } 340 }
368 341
369 if ( result == STATE_UNKNOWN ) 342 if (result == STATE_UNKNOWN) {
370 result = STATE_OK; 343 result = STATE_OK;
344 }
371 345
372 /* Needed if procs found, but none match filter */ 346 /* Needed if procs found, but none match filter */
373 if ( metric == METRIC_PROCS ) { 347 if (config.metric == METRIC_PROCS) {
374 result = max_state (result, get_status ((double)procs, procs_thresholds) ); 348 result = max_state(result, get_status((double)procs, config.procs_thresholds));
375 } 349 }
376 350
377 if ( result == STATE_OK ) { 351 if (result == STATE_OK) {
378 printf ("%s %s: ", metric_name, _("OK")); 352 printf("%s %s: ", config.metric_name, _("OK"));
379 } else if (result == STATE_WARNING) { 353 } else if (result == STATE_WARNING) {
380 printf ("%s %s: ", metric_name, _("WARNING")); 354 printf("%s %s: ", config.metric_name, _("WARNING"));
381 if ( metric != METRIC_PROCS ) { 355 if (config.metric != METRIC_PROCS) {
382 printf (_("%d warn out of "), warn); 356 printf(_("%d warn out of "), warn);
383 } 357 }
384 } else if (result == STATE_CRITICAL) { 358 } else if (result == STATE_CRITICAL) {
385 printf ("%s %s: ", metric_name, _("CRITICAL")); 359 printf("%s %s: ", config.metric_name, _("CRITICAL"));
386 if (metric != METRIC_PROCS) { 360 if (config.metric != METRIC_PROCS) {
387 printf (_("%d crit, %d warn out of "), crit, warn); 361 printf(_("%d crit, %d warn out of "), crit, warn);
388 } 362 }
389 } 363 }
390 printf (ngettext ("%d process", "%d processes", (unsigned long) procs), procs); 364 printf(ngettext("%d process", "%d processes", (unsigned long)procs), procs);
391 365
392 if (strcmp(fmt,"") != 0) { 366 if (strcmp(config.fmt, "") != 0) {
393 printf (_(" with %s"), fmt); 367 printf(_(" with %s"), config.fmt);
394 } 368 }
395 369
396 if ( verbose >= 1 && strcmp(fails,"") ) 370 if (verbose >= 1 && strcmp(config.fails, "")) {
397 printf (" [%s]", fails); 371 printf(" [%s]", config.fails);
372 }
398 373
399 if (metric == METRIC_PROCS) 374 if (config.metric == METRIC_PROCS) {
400 printf (" | procs=%d;%s;%s;0;", procs, 375 printf(" | procs=%d;%s;%s;0;", procs, config.warning_range ? config.warning_range : "",
401 warning_range ? warning_range : "", 376 config.critical_range ? config.critical_range : "");
402 critical_range ? critical_range : ""); 377 } else {
403 else 378 printf(" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit);
404 printf (" | procs=%d;;;0; procs_warn=%d;;;0; procs_crit=%d;;;0;", procs, warn, crit); 379 }
405 380
406 printf ("\n"); 381 printf("\n");
407 return result; 382 exit(result);
408} 383}
409 384
410
411
412/* process command-line arguments */ 385/* process command-line arguments */
413int 386check_procs_config_wrapper process_arguments(int argc, char **argv) {
414process_arguments (int argc, char **argv) 387 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
415{ 388 {"critical", required_argument, 0, 'c'},
416 int c = 1; 389 {"metric", required_argument, 0, 'm'},
417 char *user; 390 {"timeout", required_argument, 0, 't'},
418 struct passwd *pw; 391 {"status", required_argument, 0, 's'},
419 int option = 0; 392 {"ppid", required_argument, 0, 'p'},
420 int err; 393 {"user", required_argument, 0, 'u'},
421 int cflags = REG_NOSUB | REG_EXTENDED; 394 {"command", required_argument, 0, 'C'},
422 char errbuf[MAX_INPUT_BUFFER]; 395 {"vsz", required_argument, 0, 'z'},
423 char *temp_string; 396 {"rss", required_argument, 0, 'r'},
424 int i=0; 397 {"pcpu", required_argument, 0, 'P'},
425 static struct option longopts[] = { 398 {"elapsed", required_argument, 0, 'e'},
426 {"warning", required_argument, 0, 'w'}, 399 {"argument-array", required_argument, 0, 'a'},
427 {"critical", required_argument, 0, 'c'}, 400 {"help", no_argument, 0, 'h'},
428 {"metric", required_argument, 0, 'm'}, 401 {"version", no_argument, 0, 'V'},
429 {"timeout", required_argument, 0, 't'}, 402 {"verbose", no_argument, 0, 'v'},
430 {"status", required_argument, 0, 's'}, 403 {"ereg-argument-array", required_argument, 0, CHAR_MAX + 1},
431 {"ppid", required_argument, 0, 'p'}, 404 {"input-file", required_argument, 0, CHAR_MAX + 2},
432 {"user", required_argument, 0, 'u'}, 405 {"no-kthreads", required_argument, 0, 'k'},
433 {"command", required_argument, 0, 'C'}, 406 {"traditional-filter", no_argument, 0, 'T'},
434 {"vsz", required_argument, 0, 'z'}, 407 {"exclude-process", required_argument, 0, 'X'},
435 {"rss", required_argument, 0, 'r'}, 408 {0, 0, 0, 0}};
436 {"pcpu", required_argument, 0, 'P'}, 409
437 {"elapsed", required_argument, 0, 'e'}, 410 for (int index = 1; index < argc; index++) {
438 {"argument-array", required_argument, 0, 'a'}, 411 if (strcmp("-to", argv[index]) == 0) {
439 {"help", no_argument, 0, 'h'}, 412 strcpy(argv[index], "-t");
440 {"version", no_argument, 0, 'V'}, 413 }
441 {"verbose", no_argument, 0, 'v'}, 414 }
442 {"ereg-argument-array", required_argument, 0, CHAR_MAX+1},
443 {"input-file", required_argument, 0, CHAR_MAX+2},
444 {"no-kthreads", required_argument, 0, 'k'},
445 {"traditional-filter", no_argument, 0, 'T'},
446 {"exclude-process", required_argument, 0, 'X'},
447 {0, 0, 0, 0}
448 };
449 415
450 for (c = 1; c < argc; c++) 416 check_procs_config_wrapper result = {
451 if (strcmp ("-to", argv[c]) == 0) 417 .errorcode = OK,
452 strcpy (argv[c], "-t"); 418 .config = check_procs_config_init(),
419 };
453 420
454 while (1) { 421 while (true) {
455 c = getopt_long (argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", 422 int option = 0;
456 longopts, &option); 423 int option_index = getopt_long(argc, argv, "Vvhkt:c:w:p:s:u:C:a:z:r:m:P:T:X:", longopts, &option);
457 424
458 if (c == -1 || c == EOF) 425 if (option_index == -1 || option_index == EOF) {
459 break; 426 break;
427 }
460 428
461 switch (c) { 429 switch (option_index) {
462 case '?': /* help */ 430 case '?': /* help */
463 usage5 (); 431 usage5();
464 case 'h': /* help */ 432 case 'h': /* help */
465 print_help (); 433 print_help();
466 exit (STATE_UNKNOWN); 434 exit(STATE_UNKNOWN);
467 case 'V': /* version */ 435 case 'V': /* version */
468 print_revision (progname, NP_VERSION); 436 print_revision(progname, NP_VERSION);
469 exit (STATE_UNKNOWN); 437 exit(STATE_UNKNOWN);
470 case 't': /* timeout period */ 438 case 't': /* timeout period */
471 if (!is_integer (optarg)) 439 if (!is_integer(optarg)) {
472 usage2 (_("Timeout interval must be a positive integer"), optarg); 440 usage2(_("Timeout interval must be a positive integer"), optarg);
473 else 441 } else {
474 timeout_interval = atoi (optarg); 442 timeout_interval = atoi(optarg);
443 }
475 break; 444 break;
476 case 'c': /* critical threshold */ 445 case 'c': /* critical threshold */
477 critical_range = optarg; 446 result.config.critical_range = optarg;
478 break; 447 break;
479 case 'w': /* warning threshold */ 448 case 'w': /* warning threshold */
480 warning_range = optarg; 449 result.config.warning_range = optarg;
481 break; 450 break;
482 case 'p': /* process id */ 451 case 'p': { /* process id */
483 if (sscanf (optarg, "%d%[^0-9]", &ppid, tmp) == 1) { 452 static char tmp[MAX_INPUT_BUFFER];
484 xasprintf (&fmt, "%s%sPPID = %d", (fmt ? fmt : "") , (options ? ", " : ""), ppid); 453 if (sscanf(optarg, "%d%[^0-9]", &result.config.ppid, tmp) == 1) {
485 options |= PPID; 454 xasprintf(&result.config.fmt, "%s%sPPID = %d", (result.config.fmt ? result.config.fmt : ""),
455 (result.config.options ? ", " : ""), result.config.ppid);
456 result.config.options |= PPID;
486 break; 457 break;
487 } 458 }
488 usage4 (_("Parent Process ID must be an integer!")); 459 usage4(_("Parent Process ID must be an integer!"));
489 case 's': /* status */ 460 }
490 if (statopts) 461 case 's': /* status */
462 if (result.config.statopts) {
491 break; 463 break;
492 else 464 } else {
493 statopts = optarg; 465 result.config.statopts = optarg;
494 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 466 }
495 options |= STAT; 467 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"), (result.config.fmt ? result.config.fmt : ""),
468 (result.config.options ? ", " : ""), result.config.statopts);
469 result.config.options |= STAT;
496 break; 470 break;
497 case 'u': /* user or user id */ 471 case 'u': /* user or user id */ {
498 if (is_integer (optarg)) { 472 struct passwd *pw;
499 uid = atoi (optarg); 473 if (is_integer(optarg)) {
500 pw = getpwuid ((uid_t) uid); 474 result.config.uid = atoi(optarg);
475 pw = getpwuid(result.config.uid);
501 /* check to be sure user exists */ 476 /* check to be sure user exists */
502 if (pw == NULL) 477 if (pw == NULL) {
503 usage2 (_("UID was not found"), optarg); 478 usage2(_("UID was not found"), optarg);
504 } 479 }
505 else { 480 } else {
506 pw = getpwnam (optarg); 481 pw = getpwnam(optarg);
507 /* check to be sure user exists */ 482 /* check to be sure user exists */
508 if (pw == NULL) 483 if (pw == NULL) {
509 usage2 (_("User name was not found"), optarg); 484 usage2(_("User name was not found"), optarg);
485 }
510 /* then get uid */ 486 /* then get uid */
511 uid = pw->pw_uid; 487 result.config.uid = pw->pw_uid;
512 } 488 }
513 user = pw->pw_name; 489
514 xasprintf (&fmt, "%s%sUID = %d (%s)", (fmt ? fmt : ""), (options ? ", " : ""), 490 char *user = pw->pw_name;
515 uid, user); 491 xasprintf(&result.config.fmt, "%s%sUID = %d (%s)", (result.config.fmt ? result.config.fmt : ""),
516 options |= USER; 492 (result.config.options ? ", " : ""), result.config.uid, user);
517 break; 493 result.config.options |= USER;
518 case 'C': /* command */ 494 } break;
495 case 'C': /* command */
519 /* TODO: allow this to be passed in with --metric */ 496 /* TODO: allow this to be passed in with --metric */
520 if (prog) 497 if (result.config.prog) {
521 break; 498 break;
522 else 499 } else {
523 prog = optarg; 500 result.config.prog = optarg;
524 xasprintf (&fmt, _("%s%scommand name '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 501 }
525 prog); 502 xasprintf(&result.config.fmt, _("%s%scommand name '%s'"), (result.config.fmt ? result.config.fmt : ""),
526 options |= PROG; 503 (result.config.options ? ", " : ""), result.config.prog);
504 result.config.options |= PROG;
527 break; 505 break;
528 case 'X': 506 case 'X':
529 if(exclude_progs) 507 if (result.config.exclude_progs) {
530 break; 508 break;
531 else 509 } else {
532 exclude_progs = optarg; 510 result.config.exclude_progs = optarg;
533 xasprintf (&fmt, _("%s%sexclude progs '%s'"), (fmt ? fmt : ""), (options ? ", " : ""), 511 }
534 exclude_progs); 512 xasprintf(&result.config.fmt, _("%s%sexclude progs '%s'"), (result.config.fmt ? result.config.fmt : ""),
535 char *p = strtok(exclude_progs, ","); 513 (result.config.options ? ", " : ""), result.config.exclude_progs);
536 514 char *tmp_pointer = strtok(result.config.exclude_progs, ",");
537 while(p){ 515
538 exclude_progs_arr = realloc(exclude_progs_arr, sizeof(char*) * ++exclude_progs_counter); 516 while (tmp_pointer) {
539 exclude_progs_arr[exclude_progs_counter-1] = p; 517 result.config.exclude_progs_arr =
540 p = strtok(NULL, ","); 518 realloc(result.config.exclude_progs_arr, sizeof(char *) * ++result.config.exclude_progs_counter);
519 result.config.exclude_progs_arr[result.config.exclude_progs_counter - 1] = tmp_pointer;
520 tmp_pointer = strtok(NULL, ",");
541 } 521 }
542 522
543 options |= EXCLUDE_PROGS; 523 result.config.options |= EXCLUDE_PROGS;
544 break; 524 break;
545 case 'a': /* args (full path name with args) */ 525 case 'a': /* args (full path name with args) */
546 /* TODO: allow this to be passed in with --metric */ 526 /* TODO: allow this to be passed in with --metric */
547 if (args) 527 if (result.config.args) {
548 break; 528 break;
549 else 529 } else {
550 args = optarg; 530 result.config.args = optarg;
551 xasprintf (&fmt, "%s%sargs '%s'", (fmt ? fmt : ""), (options ? ", " : ""), args); 531 }
552 options |= ARGS; 532 xasprintf(&result.config.fmt, "%s%sargs '%s'", (result.config.fmt ? result.config.fmt : ""),
533 (result.config.options ? ", " : ""), result.config.args);
534 result.config.options |= ARGS;
553 break; 535 break;
554 case CHAR_MAX+1: 536 case CHAR_MAX + 1: {
555 err = regcomp(&re_args, optarg, cflags); 537 int cflags = REG_NOSUB | REG_EXTENDED;
538 int err = regcomp(&result.config.re_args, optarg, cflags);
556 if (err != 0) { 539 if (err != 0) {
557 regerror (err, &re_args, errbuf, MAX_INPUT_BUFFER); 540 char errbuf[MAX_INPUT_BUFFER];
558 die (STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); 541 regerror(err, &result.config.re_args, errbuf, MAX_INPUT_BUFFER);
542 die(STATE_UNKNOWN, "PROCS %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
559 } 543 }
560 /* Strip off any | within the regex optarg */ 544 /* Strip off any | within the regex optarg */
561 temp_string = strdup(optarg); 545 char *temp_string = strdup(optarg);
562 while(temp_string[i]!='\0'){ 546 int index = 0;
563 if(temp_string[i]=='|') 547 while (temp_string[index] != '\0') {
564 temp_string[i]=','; 548 if (temp_string[index] == '|') {
565 i++; 549 temp_string[index] = ',';
566 } 550 }
567 xasprintf (&fmt, "%s%sregex args '%s'", (fmt ? fmt : ""), (options ? ", " : ""), temp_string); 551 index++;
568 options |= EREG_ARGS; 552 }
569 break; 553 xasprintf(&result.config.fmt, "%s%sregex args '%s'", (result.config.fmt ? result.config.fmt : ""),
570 case 'r': /* RSS */ 554 (result.config.options ? ", " : ""), temp_string);
571 if (sscanf (optarg, "%d%[^0-9]", &rss, tmp) == 1) { 555 result.config.options |= EREG_ARGS;
572 xasprintf (&fmt, "%s%sRSS >= %d", (fmt ? fmt : ""), (options ? ", " : ""), rss); 556 } break;
573 options |= RSS; 557 case 'r': { /* RSS */
558 static char tmp[MAX_INPUT_BUFFER];
559 if (sscanf(optarg, "%d%[^0-9]", &result.config.rss, tmp) == 1) {
560 xasprintf(&result.config.fmt, "%s%sRSS >= %d", (result.config.fmt ? result.config.fmt : ""),
561 (result.config.options ? ", " : ""), result.config.rss);
562 result.config.options |= RSS;
574 break; 563 break;
575 } 564 }
576 usage4 (_("RSS must be an integer!")); 565 usage4(_("RSS must be an integer!"));
577 case 'z': /* VSZ */ 566 }
578 if (sscanf (optarg, "%d%[^0-9]", &vsz, tmp) == 1) { 567 case 'z': { /* VSZ */
579 xasprintf (&fmt, "%s%sVSZ >= %d", (fmt ? fmt : ""), (options ? ", " : ""), vsz); 568 static char tmp[MAX_INPUT_BUFFER];
580 options |= VSZ; 569 if (sscanf(optarg, "%d%[^0-9]", &result.config.vsz, tmp) == 1) {
570 xasprintf(&result.config.fmt, "%s%sVSZ >= %d", (result.config.fmt ? result.config.fmt : ""),
571 (result.config.options ? ", " : ""), result.config.vsz);
572 result.config.options |= VSZ;
581 break; 573 break;
582 } 574 }
583 usage4 (_("VSZ must be an integer!")); 575 usage4(_("VSZ must be an integer!"));
584 case 'P': /* PCPU */ 576 }
577 case 'P': { /* PCPU */
585 /* TODO: -P 1.5.5 is accepted */ 578 /* TODO: -P 1.5.5 is accepted */
586 if (sscanf (optarg, "%f%[^0-9.]", &pcpu, tmp) == 1) { 579 static char tmp[MAX_INPUT_BUFFER];
587 xasprintf (&fmt, "%s%sPCPU >= %.2f", (fmt ? fmt : ""), (options ? ", " : ""), pcpu); 580 if (sscanf(optarg, "%f%[^0-9.]", &result.config.pcpu, tmp) == 1) {
588 options |= PCPU; 581 xasprintf(&result.config.fmt, "%s%sPCPU >= %.2f", (result.config.fmt ? result.config.fmt : ""),
582 (result.config.options ? ", " : ""), result.config.pcpu);
583 result.config.options |= PCPU;
589 break; 584 break;
590 } 585 }
591 usage4 (_("PCPU must be a float!")); 586 usage4(_("PCPU must be a float!"));
587 }
592 case 'm': 588 case 'm':
593 xasprintf (&metric_name, "%s", optarg); 589 xasprintf(&result.config.metric_name, "%s", optarg);
594 if ( strcmp(optarg, "PROCS") == 0) { 590 if (strcmp(optarg, "PROCS") == 0) {
595 metric = METRIC_PROCS; 591 result.config.metric = METRIC_PROCS;
596 break; 592 break;
597 } 593 }
598 else if ( strcmp(optarg, "VSZ") == 0) { 594 if (strcmp(optarg, "VSZ") == 0) {
599 metric = METRIC_VSZ; 595 result.config.metric = METRIC_VSZ;
600 break; 596 break;
601 } 597 }
602 else if ( strcmp(optarg, "RSS") == 0 ) { 598 if (strcmp(optarg, "RSS") == 0) {
603 metric = METRIC_RSS; 599 result.config.metric = METRIC_RSS;
604 break; 600 break;
605 } 601 }
606 else if ( strcmp(optarg, "CPU") == 0 ) { 602 if (strcmp(optarg, "CPU") == 0) {
607 metric = METRIC_CPU; 603 result.config.metric = METRIC_CPU;
608 break; 604 break;
609 } 605 }
610 else if ( strcmp(optarg, "ELAPSED") == 0) { 606 if (strcmp(optarg, "ELAPSED") == 0) {
611 metric = METRIC_ELAPSED; 607 result.config.metric = METRIC_ELAPSED;
612 break; 608 break;
613 } 609 }
614 610
615 usage4 (_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!")); 611 usage4(_("Metric must be one of PROCS, VSZ, RSS, CPU, ELAPSED!"));
616 case 'k': /* linux kernel thread filter */ 612 case 'k': /* linux kernel thread filter */
617 kthread_filter = 1; 613 result.config.kthread_filter = true;
618 break; 614 break;
619 case 'v': /* command */ 615 case 'v': /* command */
620 verbose++; 616 verbose++;
621 break; 617 break;
622 case 'T': 618 case 'T':
623 usepid = 1; 619 result.config.usepid = true;
624 break; 620 break;
625 case CHAR_MAX+2: 621 case CHAR_MAX + 2:
626 input_filename = optarg; 622 result.config.input_filename = optarg;
627 break; 623 break;
628 } 624 }
629 } 625 }
630 626
631 c = optind; 627 int index = optind;
632 if ((! warning_range) && argv[c]) 628 if ((!result.config.warning_range) && argv[index]) {
633 warning_range = argv[c++]; 629 result.config.warning_range = argv[index++];
634 if ((! critical_range) && argv[c]) 630 }
635 critical_range = argv[c++]; 631 if ((!result.config.critical_range) && argv[index]) {
636 if (statopts == NULL && argv[c]) { 632 result.config.critical_range = argv[index++];
637 xasprintf (&statopts, "%s", argv[c++]); 633 }
638 xasprintf (&fmt, _("%s%sSTATE = %s"), (fmt ? fmt : ""), (options ? ", " : ""), statopts); 634 if (result.config.statopts == NULL && argv[index]) {
639 options |= STAT; 635 xasprintf(&result.config.statopts, "%s", argv[index++]);
636 xasprintf(&result.config.fmt, _("%s%sSTATE = %s"), (result.config.fmt ? result.config.fmt : ""),
637 (result.config.options ? ", " : ""), result.config.statopts);
638 result.config.options |= STAT;
640 } 639 }
641 640
642 /* this will abort in case of invalid ranges */ 641 /* this will abort in case of invalid ranges */
643 set_thresholds (&procs_thresholds, warning_range, critical_range); 642 set_thresholds(&result.config.procs_thresholds, result.config.warning_range, result.config.critical_range);
644 643
645 return validate_arguments (); 644 return validate_arguments(result);
646} 645}
647 646
647check_procs_config_wrapper validate_arguments(check_procs_config_wrapper config_wrapper) {
648 if (config_wrapper.config.options == 0) {
649 config_wrapper.config.options = ALL;
650 }
648 651
652 if (config_wrapper.config.statopts == NULL) {
653 config_wrapper.config.statopts = strdup("");
654 }
649 655
650int 656 if (config_wrapper.config.prog == NULL) {
651validate_arguments () 657 config_wrapper.config.prog = strdup("");
652{ 658 }
653 if (options == 0)
654 options = ALL;
655
656 if (statopts==NULL)
657 statopts = strdup("");
658
659 if (prog==NULL)
660 prog = strdup("");
661 659
662 if (args==NULL) 660 if (config_wrapper.config.args == NULL) {
663 args = strdup(""); 661 config_wrapper.config.args = strdup("");
662 }
664 663
665 if (fmt==NULL) 664 if (config_wrapper.config.fmt == NULL) {
666 fmt = strdup(""); 665 config_wrapper.config.fmt = strdup("");
666 }
667 667
668 if (fails==NULL) 668 if (config_wrapper.config.fails == NULL) {
669 fails = strdup(""); 669 config_wrapper.config.fails = strdup("");
670 }
670 671
671 return options; 672 // return options;
673 return config_wrapper;
672} 674}
673 675
674
675/* convert the elapsed time to seconds */ 676/* convert the elapsed time to seconds */
676int 677int convert_to_seconds(char *etime, enum metric metric) {
677convert_to_seconds(char *etime) { 678 int hyphcnt = 0;
678 679 int coloncnt = 0;
679 char *ptr; 680 for (char *ptr = etime; *ptr != '\0'; ptr++) {
680 int total;
681
682 int hyphcnt;
683 int coloncnt;
684 int days;
685 int hours;
686 int minutes;
687 int seconds;
688
689 hyphcnt = 0;
690 coloncnt = 0;
691 days = 0;
692 hours = 0;
693 minutes = 0;
694 seconds = 0;
695
696 for (ptr = etime; *ptr != '\0'; ptr++) {
697 681
698 if (*ptr == '-') { 682 if (*ptr == '-') {
699 hyphcnt++; 683 hyphcnt++;
@@ -705,9 +689,12 @@ convert_to_seconds(char *etime) {
705 } 689 }
706 } 690 }
707 691
692 int days = 0;
693 int hours = 0;
694 int minutes = 0;
695 int seconds = 0;
708 if (hyphcnt > 0) { 696 if (hyphcnt > 0) {
709 sscanf(etime, "%d-%d:%d:%d", 697 sscanf(etime, "%d-%d:%d:%d", &days, &hours, &minutes, &seconds);
710 &days, &hours, &minutes, &seconds);
711 /* linux 2.6.5/2.6.6 reporting some processes with infinite 698 /* linux 2.6.5/2.6.6 reporting some processes with infinite
712 * elapsed times for some reason */ 699 * elapsed times for some reason */
713 if (days == 49710) { 700 if (days == 49710) {
@@ -715,135 +702,125 @@ convert_to_seconds(char *etime) {
715 } 702 }
716 } else { 703 } else {
717 if (coloncnt == 2) { 704 if (coloncnt == 2) {
718 sscanf(etime, "%d:%d:%d", 705 sscanf(etime, "%d:%d:%d", &hours, &minutes, &seconds);
719 &hours, &minutes, &seconds);
720 } else if (coloncnt == 1) { 706 } else if (coloncnt == 1) {
721 sscanf(etime, "%d:%d", 707 sscanf(etime, "%d:%d", &minutes, &seconds);
722 &minutes, &seconds);
723 } 708 }
724 } 709 }
725 710
726 total = (days * 86400) + 711 int total = (days * 86400) + (hours * 3600) + (minutes * 60) + seconds;
727 (hours * 3600) +
728 (minutes * 60) +
729 seconds;
730 712
731 if (verbose >= 3 && metric == METRIC_ELAPSED) { 713 if (verbose >= 3 && metric == METRIC_ELAPSED) {
732 printf("seconds: %d\n", total); 714 printf("seconds: %d\n", total);
733 } 715 }
734 return total; 716 return total;
735} 717}
736 718
719void print_help(void) {
720 print_revision(progname, NP_VERSION);
737 721
738void 722 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
739print_help (void) 723 printf(COPYRIGHT, copyright, email);
740{
741 print_revision (progname, NP_VERSION);
742
743 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
744 printf (COPYRIGHT, copyright, email);
745 724
746 printf ("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified")); 725 printf("%s\n", _("Checks all processes and generates WARNING or CRITICAL states if the specified"));
747 printf ("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number")); 726 printf("%s\n", _("metric is outside the required threshold ranges. The metric defaults to number"));
748 printf ("%s\n", _("of processes. Search filters can be applied to limit the processes to check.")); 727 printf("%s\n", _("of processes. Search filters can be applied to limit the processes to check."));
749 728
750 printf ("\n\n"); 729 printf("\n\n");
751 730
752 printf ("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)")); 731 printf("%s\n", _("The parent process, check_procs itself and any child process of check_procs (ps)"));
753 printf ("%s\n", _("are excluded from any checks to prevent false positives.")); 732 printf("%s\n", _("are excluded from any checks to prevent false positives."));
754 733
755 printf ("\n\n"); 734 printf("\n\n");
756 735
757 print_usage (); 736 print_usage();
758 737
759 printf (UT_HELP_VRSN); 738 printf(UT_HELP_VRSN);
760 printf (UT_EXTRA_OPTS); 739 printf(UT_EXTRA_OPTS);
761 printf (" %s\n", "-w, --warning=RANGE"); 740 printf(" %s\n", "-w, --warning=RANGE");
762 printf (" %s\n", _("Generate warning state if metric is outside this range")); 741 printf(" %s\n", _("Generate warning state if metric is outside this range"));
763 printf (" %s\n", "-c, --critical=RANGE"); 742 printf(" %s\n", "-c, --critical=RANGE");
764 printf (" %s\n", _("Generate critical state if metric is outside this range")); 743 printf(" %s\n", _("Generate critical state if metric is outside this range"));
765 printf (" %s\n", "-m, --metric=TYPE"); 744 printf(" %s\n", "-m, --metric=TYPE");
766 printf (" %s\n", _("Check thresholds against metric. Valid types:")); 745 printf(" %s\n", _("Check thresholds against metric. Valid types:"));
767 printf (" %s\n", _("PROCS - number of processes (default)")); 746 printf(" %s\n", _("PROCS - number of processes (default)"));
768 printf (" %s\n", _("VSZ - virtual memory size")); 747 printf(" %s\n", _("VSZ - virtual memory size"));
769 printf (" %s\n", _("RSS - resident set memory size")); 748 printf(" %s\n", _("RSS - resident set memory size"));
770 printf (" %s\n", _("CPU - percentage CPU")); 749 printf(" %s\n", _("CPU - percentage CPU"));
771/* only linux etime is support currently */ 750/* only linux etime is support currently */
772#if defined( __linux__ ) 751#if defined(__linux__)
773 printf (" %s\n", _("ELAPSED - time elapsed in seconds")); 752 printf(" %s\n", _("ELAPSED - time elapsed in seconds"));
774#endif /* defined(__linux__) */ 753#endif /* defined(__linux__) */
775 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 754 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
776 755
777 printf (" %s\n", "-v, --verbose"); 756 printf(" %s\n", "-v, --verbose");
778 printf (" %s\n", _("Extra information. Up to 3 verbosity levels")); 757 printf(" %s\n", _("Extra information. Up to 3 verbosity levels"));
779 758
780 printf (" %s\n", "-T, --traditional"); 759 printf(" %s\n", "-T, --traditional");
781 printf (" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe")); 760 printf(" %s\n", _("Filter own process the traditional way by PID instead of /proc/pid/exe"));
782 761
783 printf ("\n"); 762 printf("\n");
784 printf ("%s\n", "Filters:"); 763 printf("%s\n", "Filters:");
785 printf (" %s\n", "-s, --state=STATUSFLAGS"); 764 printf(" %s\n", "-s, --state=STATUSFLAGS");
786 printf (" %s\n", _("Only scan for processes that have, in the output of `ps`, one or")); 765 printf(" %s\n", _("Only scan for processes that have, in the output of `ps`, one or"));
787 printf (" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,")); 766 printf(" %s\n", _("more of the status flags you specify (for example R, Z, S, RS,"));
788 printf (" %s\n", _("RSZDT, plus others based on the output of your 'ps' command).")); 767 printf(" %s\n", _("RSZDT, plus others based on the output of your 'ps' command)."));
789 printf (" %s\n", "-p, --ppid=PPID"); 768 printf(" %s\n", "-p, --ppid=PPID");
790 printf (" %s\n", _("Only scan for children of the parent process ID indicated.")); 769 printf(" %s\n", _("Only scan for children of the parent process ID indicated."));
791 printf (" %s\n", "-z, --vsz=VSZ"); 770 printf(" %s\n", "-z, --vsz=VSZ");
792 printf (" %s\n", _("Only scan for processes with VSZ higher than indicated.")); 771 printf(" %s\n", _("Only scan for processes with VSZ higher than indicated."));
793 printf (" %s\n", "-r, --rss=RSS"); 772 printf(" %s\n", "-r, --rss=RSS");
794 printf (" %s\n", _("Only scan for processes with RSS higher than indicated.")); 773 printf(" %s\n", _("Only scan for processes with RSS higher than indicated."));
795 printf (" %s\n", "-P, --pcpu=PCPU"); 774 printf(" %s\n", "-P, --pcpu=PCPU");
796 printf (" %s\n", _("Only scan for processes with PCPU higher than indicated.")); 775 printf(" %s\n", _("Only scan for processes with PCPU higher than indicated."));
797 printf (" %s\n", "-u, --user=USER"); 776 printf(" %s\n", "-u, --user=USER");
798 printf (" %s\n", _("Only scan for processes with user name or ID indicated.")); 777 printf(" %s\n", _("Only scan for processes with user name or ID indicated."));
799 printf (" %s\n", "-a, --argument-array=STRING"); 778 printf(" %s\n", "-a, --argument-array=STRING");
800 printf (" %s\n", _("Only scan for processes with args that contain STRING.")); 779 printf(" %s\n", _("Only scan for processes with args that contain STRING."));
801 printf (" %s\n", "--ereg-argument-array=STRING"); 780 printf(" %s\n", "--ereg-argument-array=STRING");
802 printf (" %s\n", _("Only scan for processes with args that contain the regex STRING.")); 781 printf(" %s\n", _("Only scan for processes with args that contain the regex STRING."));
803 printf (" %s\n", "-C, --command=COMMAND"); 782 printf(" %s\n", "-C, --command=COMMAND");
804 printf (" %s\n", _("Only scan for exact matches of COMMAND (without path).")); 783 printf(" %s\n", _("Only scan for exact matches of COMMAND (without path)."));
805 printf (" %s\n", "-X, --exclude-process"); 784 printf(" %s\n", "-X, --exclude-process");
806 printf (" %s\n", _("Exclude processes which match this comma separated list")); 785 printf(" %s\n", _("Exclude processes which match this comma separated list"));
807 printf (" %s\n", "-k, --no-kthreads"); 786 printf(" %s\n", "-k, --no-kthreads");
808 printf (" %s\n", _("Only scan for non kernel threads (works on Linux only).")); 787 printf(" %s\n", _("Only scan for non kernel threads (works on Linux only)."));
809 788
810 printf(_("\n\ 789 printf(_("\n\
811RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\ 790RANGEs are specified 'min:max' or 'min:' or ':max' (or 'max'). If\n\
812specified 'max:min', a warning status will be generated if the\n\ 791specified 'max:min', a warning status will be generated if the\n\
813count is inside the specified range\n\n")); 792count is inside the specified range\n\n"));
814 793
815 printf(_("\ 794 printf(_("\
816This plugin checks the number of currently running processes and\n\ 795This plugin checks the number of currently running processes and\n\
817generates WARNING or CRITICAL states if the process count is outside\n\ 796generates WARNING or CRITICAL states if the process count is outside\n\
818the specified threshold ranges. The process count can be filtered by\n\ 797the specified threshold ranges. The process count can be filtered by\n\
819process owner, parent process PID, current state (e.g., 'Z'), or may\n\ 798process owner, parent process PID, current state (e.g., 'Z'), or may\n\
820be the total number of running processes\n\n")); 799be the total number of running processes\n\n"));
821 800
822 printf ("%s\n", _("Examples:")); 801 printf("%s\n", _("Examples:"));
823 printf (" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry"); 802 printf(" %s\n", "check_procs -w 2:2 -c 2:1024 -C portsentry");
824 printf (" %s\n", _("Warning if not two processes with command name portsentry.")); 803 printf(" %s\n", _("Warning if not two processes with command name portsentry."));
825 printf (" %s\n\n", _("Critical if < 2 or > 1024 processes")); 804 printf(" %s\n\n", _("Critical if < 2 or > 1024 processes"));
826 printf (" %s\n", "check_procs -c 1: -C sshd"); 805 printf(" %s\n", "check_procs -c 1: -C sshd");
827 printf (" %s\n", _("Critical if not at least 1 process with command sshd")); 806 printf(" %s\n", _("Critical if not at least 1 process with command sshd"));
828 printf (" %s\n", "check_procs -w 1024 -c 1: -C sshd"); 807 printf(" %s\n", "check_procs -w 1024 -c 1: -C sshd");
829 printf (" %s\n", _("Warning if > 1024 processes with command name sshd.")); 808 printf(" %s\n", _("Warning if > 1024 processes with command name sshd."));
830 printf (" %s\n\n", _("Critical if < 1 processes with command name sshd.")); 809 printf(" %s\n\n", _("Critical if < 1 processes with command name sshd."));
831 printf (" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root"); 810 printf(" %s\n", "check_procs -w 10 -a '/usr/local/bin/perl' -u root");
832 printf (" %s\n", _("Warning alert if > 10 processes with command arguments containing")); 811 printf(" %s\n", _("Warning alert if > 10 processes with command arguments containing"));
833 printf (" %s\n\n", _("'/usr/local/bin/perl' and owned by root")); 812 printf(" %s\n\n", _("'/usr/local/bin/perl' and owned by root"));
834 printf (" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ"); 813 printf(" %s\n", "check_procs -w 50000 -c 100000 --metric=VSZ");
835 printf (" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K")); 814 printf(" %s\n\n", _("Alert if VSZ of any processes over 50K or 100K"));
836 printf (" %s\n", "check_procs -w 10 -c 20 --metric=CPU"); 815 printf(" %s\n", "check_procs -w 10 -c 20 --metric=CPU");
837 printf (" %s\n", _("Alert if CPU of any processes over 10\% or 20\%")); 816 printf(" %s\n", _("Alert if CPU of any processes over 10%% or 20%%"));
838 817
839 printf (UT_SUPPORT); 818 printf(UT_SUPPORT);
840} 819}
841 820
842void 821void print_usage(void) {
843print_usage (void) 822 printf("%s\n", _("Usage:"));
844{ 823 printf("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname);
845 printf ("%s\n", _("Usage:")); 824 printf(" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
846 printf ("%s -w <range> -c <range> [-m metric] [-s state] [-p ppid]\n", progname); 825 printf(" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
847 printf (" [-u user] [-r rss] [-z vsz] [-P %%cpu] [-a argument-array]\n");
848 printf (" [-C command] [-X process_to_exclude] [-k] [-t timeout] [-v]\n");
849} 826}
diff --git a/plugins/check_procs.d/config.h b/plugins/check_procs.d/config.h
new file mode 100644
index 00000000..e32ca066
--- /dev/null
+++ b/plugins/check_procs.d/config.h
@@ -0,0 +1,75 @@
1#pragma once
2
3#include "../../config.h"
4#include "regex.h"
5#include "thresholds.h"
6#include <stddef.h>
7#include <string.h>
8#include <sys/types.h>
9
10enum metric {
11 METRIC_PROCS,
12 METRIC_VSZ,
13 METRIC_RSS,
14 METRIC_CPU,
15 METRIC_ELAPSED
16};
17
18typedef struct {
19 int options; /* bitmask of filter criteria to test against */
20 enum metric metric;
21 char *metric_name;
22 char *input_filename;
23 char *prog;
24 char *args;
25 char *fmt;
26 char *fails;
27 char *exclude_progs;
28 char **exclude_progs_arr;
29 char exclude_progs_counter;
30 regex_t re_args;
31
32 bool kthread_filter;
33 bool usepid; /* whether to test for pid or /proc/pid/exe */
34 uid_t uid;
35 pid_t ppid;
36 int vsz;
37 int rss;
38 float pcpu;
39 char *statopts;
40
41 char *warning_range;
42 char *critical_range;
43 thresholds *procs_thresholds;
44} check_procs_config;
45
46check_procs_config check_procs_config_init() {
47 check_procs_config tmp = {
48 .options = 0,
49 .metric = METRIC_PROCS,
50 .metric_name = strdup("PROCS"),
51 .input_filename = NULL,
52 .prog = NULL,
53 .args = NULL,
54 .fmt = NULL,
55 .fails = NULL,
56 .exclude_progs = NULL,
57 .exclude_progs_arr = NULL,
58 .exclude_progs_counter = 0,
59 .re_args = {0},
60
61 .kthread_filter = false,
62 .usepid = false,
63 .uid = 0,
64 .ppid = 0,
65 .vsz = 0,
66 .rss = 0,
67 .pcpu = 0,
68 .statopts = NULL,
69
70 .warning_range = NULL,
71 .critical_range = NULL,
72 .procs_thresholds = NULL,
73 };
74 return tmp;
75}
diff --git a/plugins/check_radius.c b/plugins/check_radius.c
index 6b32710a..cc846709 100644
--- a/plugins/check_radius.c
+++ b/plugins/check_radius.c
@@ -1,99 +1,92 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_radius plugin 3 * Monitoring check_radius plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2008 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_radius plugin 10 * This file contains the check_radius plugin
11* 11 *
12* Tests to see if a radius server is accepting connections. 12 * Tests to see if a radius server is accepting connections.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_radius"; 31const char *progname = "check_radius";
32const char *copyright = "2000-2008"; 32const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "common.h"
36#include "utils.h" 36#include "utils.h"
37#include "netutils.h" 37#include "netutils.h"
38#include "states.h"
39#include "check_radius.d/config.h"
38 40
39#if defined(HAVE_LIBRADCLI) 41#if defined(HAVE_LIBRADCLI)
40#include <radcli/radcli.h> 42# include <radcli/radcli.h>
41#elif defined(HAVE_LIBFREERADIUS_CLIENT) 43#elif defined(HAVE_LIBFREERADIUS_CLIENT)
42#include <freeradius-client.h> 44# include <freeradius-client.h>
43#elif defined(HAVE_LIBRADIUSCLIENT_NG) 45#elif defined(HAVE_LIBRADIUSCLIENT_NG)
44#include <radiusclient-ng.h> 46# include <radiusclient-ng.h>
45#else 47#else
46#include <radiusclient.h> 48# include <radiusclient.h>
47#endif 49#endif
48 50
49int process_arguments (int, char **); 51typedef struct {
50void print_help (void); 52 int errorcode;
51void print_usage (void); 53 check_radius_config config;
54} check_radius_config_wrapper;
55static check_radius_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
56static void print_help(void);
57void print_usage(void);
52 58
53#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI) 59#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
54#define my_rc_conf_str(a) rc_conf_str(rch,a) 60# define my_rc_conf_str(a) rc_conf_str(rch, a)
55#if defined(HAVE_LIBRADCLI) 61# if defined(HAVE_LIBRADCLI)
56#define my_rc_send_server(a,b) rc_send_server(rch,a,b,AUTH) 62# define my_rc_send_server(a, b) rc_send_server(rch, a, b, AUTH)
57#else 63# else
58#define my_rc_send_server(a,b) rc_send_server(rch,a,b) 64# define my_rc_send_server(a, b) rc_send_server(rch, a, b)
59#endif 65# endif
60#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI) 66# if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADCLI)
61#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,(a)->secret,e,f) 67# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, (a)->secret, e, f)
62#else 68# else
63#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(rch,a,b,c,d,e,f) 69# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(rch, a, b, c, d, e, f)
64#endif 70# endif
65#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(rch,a,b,c,-1,d) 71# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(rch, a, b, c, -1, d)
66#define my_rc_read_dictionary(a) rc_read_dictionary(rch, a) 72# define my_rc_read_dictionary(a) rc_read_dictionary(rch, a)
67#else 73#else
68#define my_rc_conf_str(a) rc_conf_str(a) 74# define my_rc_conf_str(a) rc_conf_str(a)
69#define my_rc_send_server(a,b) rc_send_server(a, b) 75# define my_rc_send_server(a, b) rc_send_server(a, b)
70#define my_rc_buildreq(a,b,c,d,e,f) rc_buildreq(a,b,c,d,e,f) 76# define my_rc_buildreq(a, b, c, d, e, f) rc_buildreq(a, b, c, d, e, f)
71#define my_rc_avpair_add(a,b,c,d) rc_avpair_add(a, b, c, d) 77# define my_rc_avpair_add(a, b, c, d) rc_avpair_add(a, b, c, d)
72#define my_rc_read_dictionary(a) rc_read_dictionary(a) 78# define my_rc_read_dictionary(a) rc_read_dictionary(a)
73#endif 79#endif
74 80
75/* REJECT_RC is only defined in some version of radiusclient. It has 81/* REJECT_RC is only defined in some version of radiusclient. It has
76 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */ 82 * been reported from radiusclient-ng 0.5.6 on FreeBSD 7.2-RELEASE */
77#ifndef REJECT_RC 83#ifndef REJECT_RC
78#define REJECT_RC BADRESP_RC 84# define REJECT_RC BADRESP_RC
79#endif 85#endif
80 86
81int my_rc_read_config(char *); 87static int my_rc_read_config(char * /*a*/, rc_handle ** /*rch*/);
82
83#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
84rc_handle *rch = NULL;
85#endif
86 88
87char *server = NULL; 89static bool verbose = false;
88char *username = NULL;
89char *password = NULL;
90char *nasid = NULL;
91char *nasipaddress = NULL;
92char *expect = NULL;
93char *config_file = NULL;
94unsigned short port = PW_AUTH_UDP_PORT;
95int retries = 1;
96bool verbose = false;
97 90
98/****************************************************************************** 91/******************************************************************************
99 92
@@ -148,149 +141,167 @@ Please note that all tags must be lowercase to use the DocBook XML DTD.
148-@@ 141-@@
149******************************************************************************/ 142******************************************************************************/
150 143
144int main(int argc, char **argv) {
145 setlocale(LC_ALL, "");
146 bindtextdomain(PACKAGE, LOCALEDIR);
147 textdomain(PACKAGE);
151 148
149 /* Parse extra opts if any */
150 argv = np_extra_opts(&argc, argv, progname);
151
152 check_radius_config_wrapper tmp_config = process_arguments(argc, argv);
153
154 if (tmp_config.errorcode == ERROR) {
155 usage4(_("Could not parse arguments"));
156 }
157
158 check_radius_config config = tmp_config.config;
159
160#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
161 rc_handle *rch = NULL;
162#endif
163
164 char *str = strdup("dictionary");
165 if ((config.config_file && my_rc_read_config(config.config_file, &rch)) || my_rc_read_dictionary(my_rc_conf_str(str))) {
166 die(STATE_UNKNOWN, _("Config file error\n"));
167 }
168
169 uint32_t service = PW_AUTHENTICATE_ONLY;
170
171 SEND_DATA data;
172 memset(&data, 0, sizeof(data));
173 if (!(my_rc_avpair_add(&data.send_pairs, PW_SERVICE_TYPE, &service, 0) &&
174 my_rc_avpair_add(&data.send_pairs, PW_USER_NAME, config.username, 0) &&
175 my_rc_avpair_add(&data.send_pairs, PW_USER_PASSWORD, config.password, 0))) {
176 die(STATE_UNKNOWN, _("Out of Memory?\n"));
177 }
178
179 if (config.nas_id != NULL) {
180 if (!(my_rc_avpair_add(&data.send_pairs, PW_NAS_IDENTIFIER, config.nas_id, 0))) {
181 die(STATE_UNKNOWN, _("Invalid NAS-Identifier\n"));
182 }
183 }
152 184
153int
154main (int argc, char **argv)
155{
156 struct sockaddr_storage ss;
157 char name[HOST_NAME_MAX]; 185 char name[HOST_NAME_MAX];
186 if (config.nas_ip_address == NULL) {
187 if (gethostname(name, sizeof(name)) != 0) {
188 die(STATE_UNKNOWN, _("gethostname() failed!\n"));
189 }
190 config.nas_ip_address = name;
191 }
192
193 struct sockaddr_storage radius_server_socket;
194 if (!dns_lookup(config.nas_ip_address, &radius_server_socket, AF_UNSPEC)) {
195 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
196 }
197
198 uint32_t client_id = ntohl(((struct sockaddr_in *)&radius_server_socket)->sin_addr.s_addr);
199 if (my_rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL) {
200 die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
201 }
202
203 my_rc_buildreq(&data, PW_ACCESS_REQUEST, config.server, config.port, (int)timeout_interval, config.retries);
204
158#ifdef RC_BUFFER_LEN 205#ifdef RC_BUFFER_LEN
159 char msg[RC_BUFFER_LEN]; 206 char msg[RC_BUFFER_LEN];
160#else 207#else
161 char msg[BUFFER_LEN]; 208 char msg[BUFFER_LEN];
162#endif 209#endif
163 SEND_DATA data;
164 int result = STATE_UNKNOWN;
165 uint32_t client_id, service;
166 char *str;
167
168 setlocale (LC_ALL, "");
169 bindtextdomain (PACKAGE, LOCALEDIR);
170 textdomain (PACKAGE);
171 210
172 /* Parse extra opts if any */ 211 int result = my_rc_send_server(&data, msg);
173 argv=np_extra_opts (&argc, argv, progname); 212 rc_avpair_free(data.send_pairs);
213 if (data.receive_pairs) {
214 rc_avpair_free(data.receive_pairs);
215 }
174 216
175 if (process_arguments (argc, argv) == ERROR) 217 if (result == TIMEOUT_RC) {
176 usage4 (_("Could not parse arguments")); 218 printf("Timeout\n");
219 exit(STATE_CRITICAL);
220 }
177 221
178 str = strdup ("dictionary"); 222 if (result == ERROR_RC) {
179 if ((config_file && my_rc_read_config (config_file)) || 223 printf(_("Auth Error\n"));
180 my_rc_read_dictionary (my_rc_conf_str (str))) 224 exit(STATE_CRITICAL);
181 die (STATE_UNKNOWN, _("Config file error\n")); 225 }
182 226
183 service = PW_AUTHENTICATE_ONLY; 227 if (result == REJECT_RC) {
228 printf(_("Auth Failed\n"));
229 exit(STATE_WARNING);
230 }
184 231
185 memset (&data, 0, sizeof(data)); 232 if (result == BADRESP_RC) {
186 if (!(my_rc_avpair_add (&data.send_pairs, PW_SERVICE_TYPE, &service, 0) && 233 printf(_("Bad Response\n"));
187 my_rc_avpair_add (&data.send_pairs, PW_USER_NAME, username, 0) && 234 exit(STATE_WARNING);
188 my_rc_avpair_add (&data.send_pairs, PW_USER_PASSWORD, password, 0) 235 }
189 ))
190 die (STATE_UNKNOWN, _("Out of Memory?\n"));
191 236
192 if (nasid != NULL) { 237 if (config.expect && !strstr(msg, config.expect)) {
193 if (!(my_rc_avpair_add (&data.send_pairs, PW_NAS_IDENTIFIER, nasid, 0))) 238 printf("%s\n", msg);
194 die (STATE_UNKNOWN, _("Invalid NAS-Identifier\n")); 239 exit(STATE_WARNING);
195 } 240 }
196 241
197 if (nasipaddress == NULL) { 242 if (result == OK_RC) {
198 if (gethostname (name, sizeof(name)) != 0) 243 printf(_("Auth OK\n"));
199 die (STATE_UNKNOWN, _("gethostname() failed!\n")); 244 exit(STATE_OK);
200 nasipaddress = name;
201 } 245 }
202 if (!dns_lookup (nasipaddress, &ss, AF_INET)) /* TODO: Support IPv6. */ 246
203 die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
204 client_id = ntohl (((struct sockaddr_in *)&ss)->sin_addr.s_addr);
205 if (my_rc_avpair_add (&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL)
206 die (STATE_UNKNOWN, _("Invalid NAS-IP-Address\n"));
207
208 my_rc_buildreq (&data, PW_ACCESS_REQUEST, server, port, (int)timeout_interval,
209 retries);
210
211 result = my_rc_send_server (&data, msg);
212 rc_avpair_free (data.send_pairs);
213 if (data.receive_pairs)
214 rc_avpair_free (data.receive_pairs);
215
216 if (result == TIMEOUT_RC)
217 die (STATE_CRITICAL, _("Timeout\n"));
218 if (result == ERROR_RC)
219 die (STATE_CRITICAL, _("Auth Error\n"));
220 if (result == REJECT_RC)
221 die (STATE_WARNING, _("Auth Failed\n"));
222 if (result == BADRESP_RC)
223 die (STATE_WARNING, _("Bad Response\n"));
224 if (expect && !strstr (msg, expect))
225 die (STATE_WARNING, "%s\n", msg);
226 if (result == OK_RC)
227 die (STATE_OK, _("Auth OK\n"));
228 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result); 247 (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result);
229 die (STATE_UNKNOWN, "%s\n", msg); 248 printf("%s\n", msg);
249 exit(STATE_UNKNOWN);
230} 250}
231 251
232
233
234/* process command-line arguments */ 252/* process command-line arguments */
235int 253check_radius_config_wrapper process_arguments(int argc, char **argv) {
236process_arguments (int argc, char **argv) 254 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'P'},
237{ 255 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'},
238 int c; 256 {"nas-id", required_argument, 0, 'n'}, {"nas-ip-address", required_argument, 0, 'N'},
239 257 {"filename", required_argument, 0, 'F'}, {"expect", required_argument, 0, 'e'},
240 int option = 0; 258 {"retries", required_argument, 0, 'r'}, {"timeout", required_argument, 0, 't'},
241 static struct option longopts[] = { 259 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
242 {"hostname", required_argument, 0, 'H'}, 260 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
243 {"port", required_argument, 0, 'P'}, 261
244 {"username", required_argument, 0, 'u'}, 262 check_radius_config_wrapper result = {
245 {"password", required_argument, 0, 'p'}, 263 .errorcode = OK,
246 {"nas-id", required_argument, 0, 'n'}, 264 .config = check_radius_config_init(),
247 {"nas-ip-address", required_argument, 0, 'N'},
248 {"filename", required_argument, 0, 'F'},
249 {"expect", required_argument, 0, 'e'},
250 {"retries", required_argument, 0, 'r'},
251 {"timeout", required_argument, 0, 't'},
252 {"verbose", no_argument, 0, 'v'},
253 {"version", no_argument, 0, 'V'},
254 {"help", no_argument, 0, 'h'},
255 {0, 0, 0, 0}
256 }; 265 };
257 266
258 while (1) { 267 while (true) {
259 c = getopt_long (argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, 268 int option = 0;
260 &option); 269 int option_index = getopt_long(argc, argv, "+hVvH:P:F:u:p:n:N:t:r:e:", longopts, &option);
261 270
262 if (c == -1 || c == EOF || c == 1) 271 if (option_index == -1 || option_index == EOF || option_index == 1) {
263 break; 272 break;
273 }
264 274
265 switch (c) { 275 switch (option_index) {
266 case '?': /* print short usage statement if args not parsable */ 276 case '?': /* print short usage statement if args not parsable */
267 usage5 (); 277 usage5();
268 case 'h': /* help */ 278 case 'h': /* help */
269 print_help (); 279 print_help();
270 exit (STATE_UNKNOWN); 280 exit(STATE_UNKNOWN);
271 case 'V': /* version */ 281 case 'V': /* version */
272 print_revision (progname, NP_VERSION); 282 print_revision(progname, NP_VERSION);
273 exit (STATE_UNKNOWN); 283 exit(STATE_UNKNOWN);
274 case 'v': /* verbose mode */ 284 case 'v': /* verbose mode */
275 verbose = true; 285 verbose = true;
276 break; 286 break;
277 case 'H': /* hostname */ 287 case 'H': /* hostname */
278 if (!is_host (optarg)) { 288 if (!is_host(optarg)) {
279 usage2 (_("Invalid hostname/address"), optarg); 289 usage2(_("Invalid hostname/address"), optarg);
280 } 290 }
281 server = optarg; 291 result.config.server = optarg;
282 break; 292 break;
283 case 'P': /* port */ 293 case 'P': /* port */
284 if (is_intnonneg (optarg)) 294 if (is_intnonneg(optarg)) {
285 port = (unsigned short)atoi (optarg); 295 result.config.port = (unsigned short)atoi(optarg);
286 else 296 } else {
287 usage4 (_("Port must be a positive integer")); 297 usage4(_("Port must be a positive integer"));
298 }
288 break; 299 break;
289 case 'u': /* username */ 300 case 'u': /* username */
290 username = optarg; 301 result.config.username = optarg;
291 break; 302 break;
292 case 'p': /* password */ 303 case 'p': /* password */
293 password = strdup(optarg); 304 result.config.password = strdup(optarg);
294 305
295 /* Delete the password from process list */ 306 /* Delete the password from process list */
296 while (*optarg != '\0') { 307 while (*optarg != '\0') {
@@ -298,119 +309,115 @@ process_arguments (int argc, char **argv)
298 optarg++; 309 optarg++;
299 } 310 }
300 break; 311 break;
301 case 'n': /* nas id */ 312 case 'n': /* nas id */
302 nasid = optarg; 313 result.config.nas_id = optarg;
303 break; 314 break;
304 case 'N': /* nas ip address */ 315 case 'N': /* nas ip address */
305 nasipaddress = optarg; 316 result.config.nas_ip_address = optarg;
306 break; 317 break;
307 case 'F': /* configuration file */ 318 case 'F': /* configuration file */
308 config_file = optarg; 319 result.config.config_file = optarg;
309 break; 320 break;
310 case 'e': /* expect */ 321 case 'e': /* expect */
311 expect = optarg; 322 result.config.expect = optarg;
312 break; 323 break;
313 case 'r': /* retries */ 324 case 'r': /* retries */
314 if (is_intpos (optarg)) 325 if (is_intpos(optarg)) {
315 retries = atoi (optarg); 326 result.config.retries = atoi(optarg);
316 else 327 } else {
317 usage4 (_("Number of retries must be a positive integer")); 328 usage4(_("Number of retries must be a positive integer"));
329 }
318 break; 330 break;
319 case 't': /* timeout */ 331 case 't': /* timeout */
320 if (is_intpos (optarg)) 332 if (is_intpos(optarg)) {
321 timeout_interval = (unsigned)atoi (optarg); 333 timeout_interval = (unsigned)atoi(optarg);
322 else 334 } else {
323 usage2 (_("Timeout interval must be a positive integer"), optarg); 335 usage2(_("Timeout interval must be a positive integer"), optarg);
336 }
324 break; 337 break;
325 } 338 }
326 } 339 }
327 340
328 if (server == NULL) 341 if (result.config.server == NULL) {
329 usage4 (_("Hostname was not supplied")); 342 usage4(_("Hostname was not supplied"));
330 if (username == NULL) 343 }
331 usage4 (_("User not specified")); 344 if (result.config.username == NULL) {
332 if (password == NULL) 345 usage4(_("User not specified"));
333 usage4 (_("Password not specified")); 346 }
334 if (config_file == NULL) 347 if (result.config.password == NULL) {
335 usage4 (_("Configuration file not specified")); 348 usage4(_("Password not specified"));
349 }
350 if (result.config.config_file == NULL) {
351 usage4(_("Configuration file not specified"));
352 }
336 353
337 return OK; 354 return result;
338} 355}
339 356
340 357void print_help(void) {
341
342void
343print_help (void)
344{
345 char *myport; 358 char *myport;
346 xasprintf (&myport, "%d", PW_AUTH_UDP_PORT); 359 xasprintf(&myport, "%d", PW_AUTH_UDP_PORT);
347 360
348 print_revision (progname, NP_VERSION); 361 print_revision(progname, NP_VERSION);
349 362
350 printf ("Copyright (c) 1999 Robert August Vincent II\n"); 363 printf("Copyright (c) 1999 Robert August Vincent II\n");
351 printf (COPYRIGHT, copyright, email); 364 printf(COPYRIGHT, copyright, email);
352 365
353 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections.")); 366 printf("%s\n", _("Tests to see if a RADIUS server is accepting connections."));
354 367
355 printf ("\n\n"); 368 printf("\n\n");
356 369
357 print_usage (); 370 print_usage();
358 371
359 printf (UT_HELP_VRSN); 372 printf(UT_HELP_VRSN);
360 printf (UT_EXTRA_OPTS); 373 printf(UT_EXTRA_OPTS);
361 374
362 printf (UT_HOST_PORT, 'P', myport); 375 printf(UT_HOST_PORT, 'P', myport);
363 376
364 printf (" %s\n", "-u, --username=STRING"); 377 printf(" %s\n", "-u, --username=STRING");
365 printf (" %s\n", _("The user to authenticate")); 378 printf(" %s\n", _("The user to authenticate"));
366 printf (" %s\n", "-p, --password=STRING"); 379 printf(" %s\n", "-p, --password=STRING");
367 printf (" %s\n", _("Password for authentication (SECURITY RISK)")); 380 printf(" %s\n", _("Password for authentication (SECURITY RISK)"));
368 printf (" %s\n", "-n, --nas-id=STRING"); 381 printf(" %s\n", "-n, --nas-id=STRING");
369 printf (" %s\n", _("NAS identifier")); 382 printf(" %s\n", _("NAS identifier"));
370 printf (" %s\n", "-N, --nas-ip-address=STRING"); 383 printf(" %s\n", "-N, --nas-ip-address=STRING");
371 printf (" %s\n", _("NAS IP Address")); 384 printf(" %s\n", _("NAS IP Address"));
372 printf (" %s\n", "-F, --filename=STRING"); 385 printf(" %s\n", "-F, --filename=STRING");
373 printf (" %s\n", _("Configuration file")); 386 printf(" %s\n", _("Configuration file"));
374 printf (" %s\n", "-e, --expect=STRING"); 387 printf(" %s\n", "-e, --expect=STRING");
375 printf (" %s\n", _("Response string to expect from the server")); 388 printf(" %s\n", _("Response string to expect from the server"));
376 printf (" %s\n", "-r, --retries=INTEGER"); 389 printf(" %s\n", "-r, --retries=INTEGER");
377 printf (" %s\n", _("Number of times to retry a failed connection")); 390 printf(" %s\n", _("Number of times to retry a failed connection"));
378 391
379 printf (UT_CONN_TIMEOUT, timeout_interval); 392 printf(UT_CONN_TIMEOUT, timeout_interval);
380 393
381 printf ("\n"); 394 printf("\n");
382 printf ("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections.")); 395 printf("%s\n", _("This plugin tests a RADIUS server to see if it is accepting connections."));
383 printf ("%s\n", _("The server to test must be specified in the invocation, as well as a user")); 396 printf("%s\n", _("The server to test must be specified in the invocation, as well as a user"));
384 printf ("%s\n", _("name and password. A configuration file must be present. The format of")); 397 printf("%s\n", _("name and password. A configuration file must be present. The format of"));
385 printf ("%s\n", _("the configuration file is described in the radiusclient library sources.")); 398 printf("%s\n", _("the configuration file is described in the radiusclient library sources."));
386 printf ("%s\n", _("The password option presents a substantial security issue because the")); 399 printf("%s\n", _("The password option presents a substantial security issue because the"));
387 printf ("%s\n", _("password can possibly be determined by careful watching of the command line")); 400 printf("%s\n", _("password can possibly be determined by careful watching of the command line"));
388 printf ("%s\n", _("in a process listing. This risk is exacerbated because the plugin will")); 401 printf("%s\n", _("in a process listing. This risk is exacerbated because the plugin will"));
389 printf ("%s\n", _("typically be executed at regular predictable intervals. Please be sure that")); 402 printf("%s\n", _("typically be executed at regular predictable intervals. Please be sure that"));
390 printf ("%s\n", _("the password used does not allow access to sensitive system resources.")); 403 printf("%s\n", _("the password used does not allow access to sensitive system resources."));
391 404
392 printf (UT_SUPPORT); 405 printf(UT_SUPPORT);
393} 406}
394 407
395 408void print_usage(void) {
396 409 printf("%s\n", _("Usage:"));
397void 410 printf("%s -H host -F config_file -u username -p password\n\
398print_usage (void)
399{
400 printf ("%s\n", _("Usage:"));
401 printf ("%s -H host -F config_file -u username -p password\n\
402 [-P port] [-t timeout] [-r retries] [-e expect]\n\ 411 [-P port] [-t timeout] [-r retries] [-e expect]\n\
403 [-n nas-id] [-N nas-ip-addr]\n", progname); 412 [-n nas-id] [-N nas-ip-addr]\n",
413 progname);
404} 414}
405 415
406 416int my_rc_read_config(char *config_file_name, rc_handle **rch) {
407
408int my_rc_read_config(char * a)
409{
410#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI) 417#if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || defined(HAVE_LIBRADCLI)
411 rch = rc_read_config(a); 418 *rch = rc_read_config(config_file_name);
412 return (rch == NULL) ? 1 : 0; 419 return (rch == NULL) ? 1 : 0;
413#else 420#else
414 return rc_read_config(a); 421 return rc_read_config(config_file_name);
415#endif 422#endif
416} 423}
diff --git a/plugins/check_radius.d/config.h b/plugins/check_radius.d/config.h
new file mode 100644
index 00000000..b27d31e7
--- /dev/null
+++ b/plugins/check_radius.d/config.h
@@ -0,0 +1,42 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#if defined(HAVE_LIBRADCLI)
6# include <radcli/radcli.h>
7#elif defined(HAVE_LIBFREERADIUS_CLIENT)
8# include <freeradius-client.h>
9#elif defined(HAVE_LIBRADIUSCLIENT_NG)
10# include <radiusclient-ng.h>
11#else
12# include <radiusclient.h>
13#endif
14
15typedef struct {
16 char *server;
17 char *username;
18 char *password;
19 char *config_file;
20 char *nas_id;
21 char *nas_ip_address;
22 int retries;
23 unsigned short port;
24
25 char *expect;
26} check_radius_config;
27
28check_radius_config check_radius_config_init() {
29 check_radius_config tmp = {
30 .server = NULL,
31 .username = NULL,
32 .password = NULL,
33 .config_file = NULL,
34 .nas_id = NULL,
35 .nas_ip_address = NULL,
36 .retries = 1,
37 .port = PW_AUTH_UDP_PORT,
38
39 .expect = NULL,
40 };
41 return tmp;
42}
diff --git a/plugins/check_real.c b/plugins/check_real.c
index 15e035b6..ec0928ed 100644
--- a/plugins/check_real.c
+++ b/plugins/check_real.c
@@ -1,454 +1,439 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_real plugin 3 * Monitoring check_real plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_real plugin 10 * This file contains the check_real plugin
11* 11 *
12* This plugin tests the REAL service on the specified host. 12 * This plugin tests the REAL service on the specified host.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
32#include <stdio.h>
31const char *progname = "check_real"; 33const char *progname = "check_real";
32const char *copyright = "2000-2007"; 34const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
34 36
35#include "common.h" 37#include "common.h"
36#include "netutils.h" 38#include "netutils.h"
37#include "utils.h" 39#include "utils.h"
40#include "check_real.d/config.h"
38 41
39enum { 42#define EXPECT "RTSP/1."
40 PORT = 554 43#define URL ""
41};
42
43#define EXPECT "RTSP/1."
44#define URL ""
45 44
46int process_arguments (int, char **); 45typedef struct {
47int validate_arguments (void); 46 int errorcode;
48void print_help (void); 47 check_real_config config;
49void print_usage (void); 48} check_real_config_wrapper;
49static check_real_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50 50
51int server_port = PORT; 51static void print_help(void);
52char *server_address; 52void print_usage(void);
53char *host_name;
54char *server_url = NULL;
55char *server_expect;
56int warning_time = 0;
57bool check_warning_time = false;
58int critical_time = 0;
59bool check_critical_time = false;
60bool verbose = false;
61 53
54static bool verbose = false;
62 55
63 56int main(int argc, char **argv) {
64int 57 setlocale(LC_ALL, "");
65main (int argc, char **argv) 58 bindtextdomain(PACKAGE, LOCALEDIR);
66{ 59 textdomain(PACKAGE);
67 int sd;
68 int result = STATE_UNKNOWN;
69 char buffer[MAX_INPUT_BUFFER];
70 char *status_line = NULL;
71
72 setlocale (LC_ALL, "");
73 bindtextdomain (PACKAGE, LOCALEDIR);
74 textdomain (PACKAGE);
75 60
76 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
77 argv=np_extra_opts (&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
63
64 check_real_config_wrapper tmp_config = process_arguments(argc, argv);
65 if (tmp_config.errorcode == ERROR) {
66 usage4(_("Could not parse arguments"));
67 }
78 68
79 if (process_arguments (argc, argv) == ERROR) 69 const check_real_config config = tmp_config.config;
80 usage4 (_("Could not parse arguments"));
81 70
82 /* initialize alarm signal handling */ 71 /* initialize alarm signal handling */
83 signal (SIGALRM, socket_timeout_alarm_handler); 72 signal(SIGALRM, socket_timeout_alarm_handler);
84 73
85 /* set socket timeout */ 74 /* set socket timeout */
86 alarm (socket_timeout); 75 alarm(socket_timeout);
87 time (&start_time); 76 time(&start_time);
88 77
89 /* try to connect to the host at the given port number */ 78 /* try to connect to the host at the given port number */
90 if (my_tcp_connect (server_address, server_port, &sd) != STATE_OK) 79 int socket;
91 die (STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), 80 if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) {
92 server_address, server_port); 81 die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), config.server_address, config.server_port);
82 }
93 83
94 /* Part I - Server Check */ 84 /* Part I - Server Check */
95 85
96 /* send the OPTIONS request */ 86 /* send the OPTIONS request */
97 sprintf (buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", host_name, server_port); 87 char buffer[MAX_INPUT_BUFFER];
98 result = send (sd, buffer, strlen (buffer), 0); 88 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port);
89 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
90 if (sent_bytes == -1) {
91 die(STATE_CRITICAL, _("Sending options to %s failed\n"), config.host_name);
92 }
99 93
100 /* send the header sync */ 94 /* send the header sync */
101 sprintf (buffer, "CSeq: 1\r\n"); 95 sprintf(buffer, "CSeq: 1\r\n");
102 result = send (sd, buffer, strlen (buffer), 0); 96 sent_bytes = send(socket, buffer, strlen(buffer), 0);
97 if (sent_bytes == -1) {
98 die(STATE_CRITICAL, _("Sending header sync to %s failed\n"), config.host_name);
99 }
103 100
104 /* send a newline so the server knows we're done with the request */ 101 /* send a newline so the server knows we're done with the request */
105 sprintf (buffer, "\r\n"); 102 sprintf(buffer, "\r\n");
106 result = send (sd, buffer, strlen (buffer), 0); 103 sent_bytes = send(socket, buffer, strlen(buffer), 0);
104 if (sent_bytes == -1) {
105 die(STATE_CRITICAL, _("Sending newline to %s failed\n"), config.host_name);
106 }
107 107
108 /* watch for the REAL connection string */ 108 /* watch for the REAL connection string */
109 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0); 109 ssize_t received_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
110 110
111 /* return a CRITICAL status if we couldn't read any data */ 111 /* return a CRITICAL status if we couldn't read any data */
112 if (result == -1) 112 if (received_bytes == -1) {
113 die (STATE_CRITICAL, _("No data received from %s\n"), host_name); 113 die(STATE_CRITICAL, _("No data received from %s\n"), config.host_name);
114 }
114 115
116 mp_state_enum result = STATE_OK;
117 char *status_line = NULL;
115 /* make sure we find the response we are looking for */ 118 /* make sure we find the response we are looking for */
116 if (!strstr (buffer, server_expect)) { 119 if (!strstr(buffer, config.server_expect)) {
117 if (server_port == PORT) 120 if (config.server_port == PORT) {
118 printf ("%s\n", _("Invalid REAL response received from host")); 121 printf("%s\n", _("Invalid REAL response received from host"));
119 else 122 } else {
120 printf (_("Invalid REAL response received from host on port %d\n"), 123 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
121 server_port); 124 }
122 } 125 } else {
123 else {
124 /* else we got the REAL string, so check the return code */ 126 /* else we got the REAL string, so check the return code */
125 127
126 time (&end_time); 128 time(&end_time);
127 129
128 result = STATE_OK; 130 result = STATE_OK;
129 131
130 status_line = (char *) strtok (buffer, "\n"); 132 status_line = strtok(buffer, "\n");
131 133
132 if (strstr (status_line, "200")) 134 if (strstr(status_line, "200")) {
133 result = STATE_OK; 135 result = STATE_OK;
136 }
134 137
135 /* client errors result in a warning state */ 138 /* client errors result in a warning state */
136 else if (strstr (status_line, "400")) 139 else if (strstr(status_line, "400")) {
137 result = STATE_WARNING; 140 result = STATE_WARNING;
138 else if (strstr (status_line, "401")) 141 } else if (strstr(status_line, "401")) {
139 result = STATE_WARNING; 142 result = STATE_WARNING;
140 else if (strstr (status_line, "402")) 143 } else if (strstr(status_line, "402")) {
141 result = STATE_WARNING; 144 result = STATE_WARNING;
142 else if (strstr (status_line, "403")) 145 } else if (strstr(status_line, "403")) {
143 result = STATE_WARNING; 146 result = STATE_WARNING;
144 else if (strstr (status_line, "404")) 147 } else if (strstr(status_line, "404")) {
145 result = STATE_WARNING; 148 result = STATE_WARNING;
146 149 } else if (strstr(status_line, "500")) {
147 /* server errors result in a critical state */ 150 /* server errors result in a critical state */
148 else if (strstr (status_line, "500"))
149 result = STATE_CRITICAL; 151 result = STATE_CRITICAL;
150 else if (strstr (status_line, "501")) 152 } else if (strstr(status_line, "501")) {
151 result = STATE_CRITICAL; 153 result = STATE_CRITICAL;
152 else if (strstr (status_line, "502")) 154 } else if (strstr(status_line, "502")) {
153 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
154 else if (strstr (status_line, "503")) 156 } else if (strstr(status_line, "503")) {
155 result = STATE_CRITICAL; 157 result = STATE_CRITICAL;
156 158 } else {
157 else
158 result = STATE_UNKNOWN; 159 result = STATE_UNKNOWN;
160 }
159 } 161 }
160 162
161 /* Part II - Check stream exists and is ok */ 163 /* Part II - Check stream exists and is ok */
162 if ((result == STATE_OK )&& (server_url != NULL) ) { 164 if ((result == STATE_OK) && (config.server_url != NULL)) {
163 165
164 /* Part I - Server Check */ 166 /* Part I - Server Check */
165 167
166 /* send the DESCRIBE request */ 168 /* send the DESCRIBE request */
167 sprintf (buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", host_name, 169 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name, config.server_port, config.server_url);
168 server_port, server_url); 170
169 result = send (sd, buffer, strlen (buffer), 0); 171 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
172 if (sent_bytes == -1) {
173 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
174 }
170 175
171 /* send the header sync */ 176 /* send the header sync */
172 sprintf (buffer, "CSeq: 2\r\n"); 177 sprintf(buffer, "CSeq: 2\r\n");
173 result = send (sd, buffer, strlen (buffer), 0); 178 sent_bytes = send(socket, buffer, strlen(buffer), 0);
179 if (sent_bytes == -1) {
180 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
181 }
174 182
175 /* send a newline so the server knows we're done with the request */ 183 /* send a newline so the server knows we're done with the request */
176 sprintf (buffer, "\r\n"); 184 sprintf(buffer, "\r\n");
177 result = send (sd, buffer, strlen (buffer), 0); 185 sent_bytes = send(socket, buffer, strlen(buffer), 0);
186 if (sent_bytes == -1) {
187 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
188 }
178 189
179 /* watch for the REAL connection string */ 190 /* watch for the REAL connection string */
180 result = recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0); 191 ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
181 buffer[result] = '\0'; /* null terminate received buffer */ 192 if (recv_bytes == -1) {
182 193 /* return a CRITICAL status if we couldn't read any data */
183 /* return a CRITICAL status if we couldn't read any data */ 194 printf(_("No data received from host\n"));
184 if (result == -1) {
185 printf (_("No data received from host\n"));
186 result = STATE_CRITICAL; 195 result = STATE_CRITICAL;
187 } 196 } else {
188 else { 197 buffer[result] = '\0'; /* null terminate received buffer */
189 /* make sure we find the response we are looking for */ 198 /* make sure we find the response we are looking for */
190 if (!strstr (buffer, server_expect)) { 199 if (!strstr(buffer, config.server_expect)) {
191 if (server_port == PORT) 200 if (config.server_port == PORT) {
192 printf ("%s\n", _("Invalid REAL response received from host")); 201 printf("%s\n", _("Invalid REAL response received from host"));
193 else 202 } else {
194 printf (_("Invalid REAL response received from host on port %d\n"), 203 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
195 server_port); 204 }
196 } 205 } else {
197 else {
198 206
199 /* else we got the REAL string, so check the return code */ 207 /* else we got the REAL string, so check the return code */
200 208
201 time (&end_time); 209 time(&end_time);
202 210
203 result = STATE_OK; 211 result = STATE_OK;
204 212
205 status_line = (char *) strtok (buffer, "\n"); 213 status_line = strtok(buffer, "\n");
206 214
207 if (strstr (status_line, "200")) 215 if (strstr(status_line, "200")) {
208 result = STATE_OK; 216 result = STATE_OK;
217 }
209 218
210 /* client errors result in a warning state */ 219 /* client errors result in a warning state */
211 else if (strstr (status_line, "400")) 220 else if (strstr(status_line, "400")) {
212 result = STATE_WARNING; 221 result = STATE_WARNING;
213 else if (strstr (status_line, "401")) 222 } else if (strstr(status_line, "401")) {
214 result = STATE_WARNING; 223 result = STATE_WARNING;
215 else if (strstr (status_line, "402")) 224 } else if (strstr(status_line, "402")) {
216 result = STATE_WARNING; 225 result = STATE_WARNING;
217 else if (strstr (status_line, "403")) 226 } else if (strstr(status_line, "403")) {
218 result = STATE_WARNING; 227 result = STATE_WARNING;
219 else if (strstr (status_line, "404")) 228 } else if (strstr(status_line, "404")) {
220 result = STATE_WARNING; 229 result = STATE_WARNING;
230 }
221 231
222 /* server errors result in a critical state */ 232 /* server errors result in a critical state */
223 else if (strstr (status_line, "500")) 233 else if (strstr(status_line, "500")) {
224 result = STATE_CRITICAL; 234 result = STATE_CRITICAL;
225 else if (strstr (status_line, "501")) 235 } else if (strstr(status_line, "501")) {
226 result = STATE_CRITICAL; 236 result = STATE_CRITICAL;
227 else if (strstr (status_line, "502")) 237 } else if (strstr(status_line, "502")) {
228 result = STATE_CRITICAL; 238 result = STATE_CRITICAL;
229 else if (strstr (status_line, "503")) 239 } else if (strstr(status_line, "503")) {
230 result = STATE_CRITICAL; 240 result = STATE_CRITICAL;
241 }
231 242
232 else 243 else {
233 result = STATE_UNKNOWN; 244 result = STATE_UNKNOWN;
245 }
234 } 246 }
235 } 247 }
236 } 248 }
237 249
238 /* Return results */ 250 /* Return results */
239 if (result == STATE_OK) { 251 if (result == STATE_OK) {
240 252 if (config.check_critical_time && (end_time - start_time) > config.critical_time) {
241 if (check_critical_time 253 result = STATE_CRITICAL;
242 && (end_time - start_time) > critical_time) result = STATE_CRITICAL; 254 } else if (config.check_warning_time && (end_time - start_time) > config.warning_time) {
243 else if (check_warning_time 255 result = STATE_WARNING;
244 && (end_time - start_time) > warning_time) result = 256 }
245 STATE_WARNING;
246 257
247 /* Put some HTML in here to create a dynamic link */ 258 /* Put some HTML in here to create a dynamic link */
248 printf (_("REAL %s - %d second response time\n"), 259 printf(_("REAL %s - %d second response time\n"), state_text(result), (int)(end_time - start_time));
249 state_text (result), 260 } else {
250 (int) (end_time - start_time)); 261 printf("%s\n", status_line);
251 } 262 }
252 else
253 printf ("%s\n", status_line);
254 263
255 /* close the connection */ 264 /* close the connection */
256 close (sd); 265 close(socket);
257 266
258 /* reset the alarm */ 267 /* reset the alarm */
259 alarm (0); 268 alarm(0);
260 269
261 return result; 270 exit(result);
262} 271}
263 272
264
265
266/* process command-line arguments */ 273/* process command-line arguments */
267int 274check_real_config_wrapper process_arguments(int argc, char **argv) {
268process_arguments (int argc, char **argv) 275 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'},
269{ 276 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'},
270 int c; 277 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'},
271 278 {"warning", required_argument, 0, 'w'}, {"timeout", required_argument, 0, 't'},
272 int option = 0; 279 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
273 static struct option longopts[] = { 280 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
274 {"hostname", required_argument, 0, 'H'}, 281
275 {"IPaddress", required_argument, 0, 'I'}, 282 check_real_config_wrapper result = {
276 {"expect", required_argument, 0, 'e'}, 283 .errorcode = OK,
277 {"url", required_argument, 0, 'u'}, 284 .config = check_real_config_init(),
278 {"port", required_argument, 0, 'p'},
279 {"critical", required_argument, 0, 'c'},
280 {"warning", required_argument, 0, 'w'},
281 {"timeout", required_argument, 0, 't'},
282 {"verbose", no_argument, 0, 'v'},
283 {"version", no_argument, 0, 'V'},
284 {"help", no_argument, 0, 'h'},
285 {0, 0, 0, 0}
286 }; 285 };
287 286
288 if (argc < 2) 287 if (argc < 2) {
289 return ERROR; 288 result.errorcode = ERROR;
289 return result;
290 }
290 291
291 for (c = 1; c < argc; c++) { 292 for (int i = 1; i < argc; i++) {
292 if (strcmp ("-to", argv[c]) == 0) 293 if (strcmp("-to", argv[i]) == 0) {
293 strcpy (argv[c], "-t"); 294 strcpy(argv[i], "-t");
294 else if (strcmp ("-wt", argv[c]) == 0) 295 } else if (strcmp("-wt", argv[i]) == 0) {
295 strcpy (argv[c], "-w"); 296 strcpy(argv[i], "-w");
296 else if (strcmp ("-ct", argv[c]) == 0) 297 } else if (strcmp("-ct", argv[i]) == 0) {
297 strcpy (argv[c], "-c"); 298 strcpy(argv[i], "-c");
299 }
298 } 300 }
299 301
300 while (1) { 302 while (true) {
301 c = getopt_long (argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, 303 int option = 0;
302 &option); 304 int option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option);
303 305
304 if (c == -1 || c == EOF) 306 if (option_char == -1 || option_char == EOF) {
305 break; 307 break;
308 }
306 309
307 switch (c) { 310 switch (option_char) {
308 case 'I': /* hostname */ 311 case 'I': /* hostname */
309 case 'H': /* hostname */ 312 case 'H': /* hostname */
310 if (server_address) 313 if (result.config.server_address) {
311 break; 314 break;
312 else if (is_host (optarg)) 315 } else if (is_host(optarg)) {
313 server_address = optarg; 316 result.config.server_address = optarg;
314 else 317 } else {
315 usage2 (_("Invalid hostname/address"), optarg); 318 usage2(_("Invalid hostname/address"), optarg);
319 }
316 break; 320 break;
317 case 'e': /* string to expect in response header */ 321 case 'e': /* string to expect in response header */
318 server_expect = optarg; 322 result.config.server_expect = optarg;
319 break; 323 break;
320 case 'u': /* server URL */ 324 case 'u': /* server URL */
321 server_url = optarg; 325 result.config.server_url = optarg;
322 break; 326 break;
323 case 'p': /* port */ 327 case 'p': /* port */
324 if (is_intpos (optarg)) { 328 if (is_intpos(optarg)) {
325 server_port = atoi (optarg); 329 result.config.server_port = atoi(optarg);
326 } 330 } else {
327 else { 331 usage4(_("Port must be a positive integer"));
328 usage4 (_("Port must be a positive integer"));
329 } 332 }
330 break; 333 break;
331 case 'w': /* warning time threshold */ 334 case 'w': /* warning time threshold */
332 if (is_intnonneg (optarg)) { 335 if (is_intnonneg(optarg)) {
333 warning_time = atoi (optarg); 336 result.config.warning_time = atoi(optarg);
334 check_warning_time = true; 337 result.config.check_warning_time = true;
335 } 338 } else {
336 else { 339 usage4(_("Warning time must be a positive integer"));
337 usage4 (_("Warning time must be a positive integer"));
338 } 340 }
339 break; 341 break;
340 case 'c': /* critical time threshold */ 342 case 'c': /* critical time threshold */
341 if (is_intnonneg (optarg)) { 343 if (is_intnonneg(optarg)) {
342 critical_time = atoi (optarg); 344 result.config.critical_time = atoi(optarg);
343 check_critical_time = true; 345 result.config.check_critical_time = true;
344 } 346 } else {
345 else { 347 usage4(_("Critical time must be a positive integer"));
346 usage4 (_("Critical time must be a positive integer"));
347 } 348 }
348 break; 349 break;
349 case 'v': /* verbose */ 350 case 'v': /* verbose */
350 verbose = true; 351 verbose = true;
351 break; 352 break;
352 case 't': /* timeout */ 353 case 't': /* timeout */
353 if (is_intnonneg (optarg)) { 354 if (is_intnonneg(optarg)) {
354 socket_timeout = atoi (optarg); 355 socket_timeout = atoi(optarg);
355 } 356 } else {
356 else { 357 usage4(_("Timeout interval must be a positive integer"));
357 usage4 (_("Timeout interval must be a positive integer"));
358 } 358 }
359 break; 359 break;
360 case 'V': /* version */ 360 case 'V': /* version */
361 print_revision (progname, NP_VERSION); 361 print_revision(progname, NP_VERSION);
362 exit (STATE_UNKNOWN); 362 exit(STATE_UNKNOWN);
363 case 'h': /* help */ 363 case 'h': /* help */
364 print_help (); 364 print_help();
365 exit (STATE_UNKNOWN); 365 exit(STATE_UNKNOWN);
366 case '?': /* usage */ 366 case '?': /* usage */
367 usage5 (); 367 usage5();
368 } 368 }
369 } 369 }
370 370
371 c = optind; 371 int option_char = optind;
372 if (server_address==NULL && argc>c) { 372 if (result.config.server_address == NULL && argc > option_char) {
373 if (is_host (argv[c])) { 373 if (is_host(argv[option_char])) {
374 server_address = argv[c++]; 374 result.config.server_address = argv[option_char++];
375 } 375 } else {
376 else { 376 usage2(_("Invalid hostname/address"), argv[option_char]);
377 usage2 (_("Invalid hostname/address"), argv[c]);
378 } 377 }
379 } 378 }
380 379
381 if (server_address==NULL) 380 if (result.config.server_address == NULL) {
382 usage4 (_("You must provide a server to check")); 381 usage4(_("You must provide a server to check"));
383 382 }
384 if (host_name==NULL)
385 host_name = strdup (server_address);
386
387 if (server_expect == NULL)
388 server_expect = strdup(EXPECT);
389
390 return validate_arguments ();
391}
392 383
384 if (result.config.host_name == NULL) {
385 result.config.host_name = strdup(result.config.server_address);
386 }
393 387
388 if (result.config.server_expect == NULL) {
389 result.config.server_expect = strdup(EXPECT);
390 }
394 391
395int 392 return result;
396validate_arguments (void)
397{
398 return OK;
399} 393}
400 394
401 395void print_help(void) {
402
403void
404print_help (void)
405{
406 char *myport; 396 char *myport;
407 xasprintf (&myport, "%d", PORT); 397 xasprintf(&myport, "%d", PORT);
408 398
409 print_revision (progname, NP_VERSION); 399 print_revision(progname, NP_VERSION);
410 400
411 printf ("Copyright (c) 1999 Pedro Leite <leite@cic.ua.pt>\n"); 401 printf("Copyright (c) 1999 Pedro Leite <leite@cic.ua.pt>\n");
412 printf (COPYRIGHT, copyright, email); 402 printf(COPYRIGHT, copyright, email);
413 403
414 printf ("%s\n", _("This plugin tests the REAL service on the specified host.")); 404 printf("%s\n", _("This plugin tests the REAL service on the specified host."));
415 405
416 printf ("\n\n"); 406 printf("\n\n");
417 407
418 print_usage (); 408 print_usage();
419 409
420 printf (UT_HELP_VRSN); 410 printf(UT_HELP_VRSN);
421 printf (UT_EXTRA_OPTS); 411 printf(UT_EXTRA_OPTS);
422 412
423 printf (UT_HOST_PORT, 'p', myport); 413 printf(UT_HOST_PORT, 'p', myport);
424 414
425 printf (" %s\n", "-u, --url=STRING"); 415 printf(" %s\n", "-u, --url=STRING");
426 printf (" %s\n", _("Connect to this url")); 416 printf(" %s\n", _("Connect to this url"));
427 printf (" %s\n", "-e, --expect=STRING"); 417 printf(" %s\n", "-e, --expect=STRING");
428 printf (_("String to expect in first line of server response (default: %s)\n"), 418 printf(_("String to expect in first line of server response (default: %s)\n"), EXPECT);
429 EXPECT);
430 419
431 printf (UT_WARN_CRIT); 420 printf(UT_WARN_CRIT);
432 421
433 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 422 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
434 423
435 printf (UT_VERBOSE); 424 printf(UT_VERBOSE);
436 425
437 printf ("\n"); 426 printf("\n");
438 printf ("%s\n", _("This plugin will attempt to open an RTSP connection with the host.")); 427 printf("%s\n", _("This plugin will attempt to open an RTSP connection with the host."));
439 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return")); 428 printf("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
440 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,")); 429 printf("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful connects,"));
441 printf ("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return")); 430 printf("%s\n", _("but incorrect response messages from the host result in STATE_WARNING return"));
442 printf ("%s\n", _("values.")); 431 printf("%s\n", _("values."));
443 432
444 printf (UT_SUPPORT); 433 printf(UT_SUPPORT);
445} 434}
446 435
447 436void print_usage(void) {
448 437 printf("%s\n", _("Usage:"));
449void 438 printf("%s -H host [-e expect] [-p port] [-w warn] [-c crit] [-t timeout] [-v]\n", progname);
450print_usage (void)
451{
452 printf ("%s\n", _("Usage:"));
453 printf ("%s -H host [-e expect] [-p port] [-w warn] [-c crit] [-t timeout] [-v]\n", progname);
454} 439}
diff --git a/plugins/check_real.d/config.h b/plugins/check_real.d/config.h
new file mode 100644
index 00000000..c4663cf9
--- /dev/null
+++ b/plugins/check_real.d/config.h
@@ -0,0 +1,37 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 PORT = 554
8};
9
10typedef struct {
11 char *server_address;
12 char *host_name;
13 int server_port;
14 char *server_url;
15
16 char *server_expect;
17 int warning_time;
18 bool check_warning_time;
19 int critical_time;
20 bool check_critical_time;
21} check_real_config;
22
23check_real_config check_real_config_init() {
24 check_real_config tmp = {
25 .server_address = NULL,
26 .host_name = NULL,
27 .server_port = PORT,
28 .server_url = NULL,
29
30 .server_expect = NULL,
31 .warning_time = 0,
32 .check_warning_time = false,
33 .critical_time = 0,
34 .check_critical_time = false,
35 };
36 return tmp;
37}
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c
index 986c3e18..44b735f9 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -1,437 +1,429 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_smtp plugin 3 * Monitoring check_smtp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2023 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_smtp plugin 10 * This file contains the check_smtp plugin
11* 11 *
12* This plugin will attempt to open an SMTP connection with the host. 12 * This plugin will attempt to open an SMTP connection with the host.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_smtp"; 31const char *progname = "check_smtp";
32const char *copyright = "2000-2007"; 32const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "common.h"
36#include "netutils.h" 36#include "netutils.h"
37#include "utils.h" 37#include "utils.h"
38#include "base64.h" 38#include "base64.h"
39#include "regex.h"
39 40
40#include <ctype.h> 41#include <ctype.h>
42#include "check_smtp.d/config.h"
43#include "../lib/states.h"
44
45#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n"
46#define SMTP_HELO "HELO "
47#define SMTP_EHLO "EHLO "
48#define SMTP_LHLO "LHLO "
49#define SMTP_QUIT "QUIT\r\n"
50#define SMTP_STARTTLS "STARTTLS\r\n"
51#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n"
41 52
53#define EHLO_SUPPORTS_STARTTLS 1
54
55typedef struct {
56 int errorcode;
57 check_smtp_config config;
58} check_smtp_config_wrapper;
59static check_smtp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
60
61int my_recv(check_smtp_config config, void *buf, int num, int socket_descriptor, bool ssl_established) {
42#ifdef HAVE_SSL 62#ifdef HAVE_SSL
43bool check_cert = false; 63 if ((config.use_starttls || config.use_ssl) && ssl_established) {
44int days_till_exp_warn, days_till_exp_crit; 64 return np_net_ssl_read(buf, num);
45# define my_recv(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 65 }
46# define my_send(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0)) 66 return (int)read(socket_descriptor, buf, (size_t)num);
47#else /* ifndef HAVE_SSL */ 67#else /* ifndef HAVE_SSL */
48# define my_recv(buf, len) read(sd, buf, len) 68 return read(socket_descriptor, buf, len)
49# define my_send(buf, len) send(sd, buf, len, 0)
50#endif 69#endif
70}
51 71
52enum { 72int my_send(check_smtp_config config, void *buf, int num, int socket_descriptor, bool ssl_established) {
53 SMTP_PORT = 25, 73#ifdef HAVE_SSL
54 SMTPS_PORT = 465 74 if ((config.use_starttls || config.use_ssl) && ssl_established) {
55};
56#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n"
57#define SMTP_EXPECT "220"
58#define SMTP_HELO "HELO "
59#define SMTP_EHLO "EHLO "
60#define SMTP_LHLO "LHLO "
61#define SMTP_QUIT "QUIT\r\n"
62#define SMTP_STARTTLS "STARTTLS\r\n"
63#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n"
64
65#define EHLO_SUPPORTS_STARTTLS 1
66 75
67int process_arguments (int, char **); 76 return np_net_ssl_write(buf, num);
68int validate_arguments (void); 77 }
69void print_help (void); 78 return (int)send(socket_descriptor, buf, (size_t)num, 0);
70void print_usage (void); 79#else /* ifndef HAVE_SSL */
71void smtp_quit(void); 80 return send(socket_descriptor, buf, len, 0);
72int recvline(char *, size_t); 81#endif
73int recvlines(char *, size_t); 82}
74int my_close(void);
75 83
76#include "regex.h" 84static void print_help(void);
77char regex_expect[MAX_INPUT_BUFFER] = ""; 85void print_usage(void);
78regex_t preg; 86static char *smtp_quit(check_smtp_config /*config*/, char /*buffer*/[MAX_INPUT_BUFFER], int /*socket_descriptor*/,
79regmatch_t pmatch[10]; 87 bool /*ssl_established*/);
80char timestamp[20] = ""; 88static int recvline(char * /*buf*/, size_t /*bufsize*/, check_smtp_config /*config*/, int /*socket_descriptor*/, bool /*ssl_established*/);
81char errbuf[MAX_INPUT_BUFFER]; 89static int recvlines(check_smtp_config /*config*/, char * /*buf*/, size_t /*bufsize*/, int /*socket_descriptor*/, bool /*ssl_established*/);
82int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 90static int my_close(int /*socket_descriptor*/);
83int eflags = 0;
84int errcode, excode;
85
86int server_port = SMTP_PORT;
87int server_port_option = 0;
88char *server_address = NULL;
89char *server_expect = NULL;
90char *mail_command = NULL;
91char *from_arg = NULL;
92int send_mail_from=0;
93int ncommands=0;
94int command_size=0;
95int nresponses=0;
96int response_size=0;
97char **commands = NULL;
98char **responses = NULL;
99char *authtype = NULL;
100char *authuser = NULL;
101char *authpass = NULL;
102double warning_time = 0;
103bool check_warning_time = false;
104double critical_time = 0;
105bool check_critical_time = false;
106int verbose = 0;
107bool use_ssl = false;
108bool use_starttls = false;
109bool use_sni = false;
110bool use_proxy_prefix = false;
111bool use_ehlo = false;
112bool use_lhlo = false;
113bool ssl_established = false;
114char *localhostname = NULL;
115int sd;
116char buffer[MAX_INPUT_BUFFER];
117enum {
118 TCP_PROTOCOL = 1,
119 UDP_PROTOCOL = 2,
120};
121bool ignore_send_quit_failure = false;
122
123
124int
125main (int argc, char **argv)
126{
127 bool supports_tls = false;
128 int n = 0;
129 double elapsed_time;
130 long microsec;
131 int result = STATE_UNKNOWN;
132 char *cmd_str = NULL;
133 char *helocmd = NULL;
134 char *error_msg = "";
135 char *server_response = NULL;
136 struct timeval tv;
137 91
138 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */ 92static int verbose = 0;
139 (void) signal (SIGPIPE, SIG_IGN);
140 93
141 setlocale (LC_ALL, ""); 94int main(int argc, char **argv) {
142 bindtextdomain (PACKAGE, LOCALEDIR); 95 setlocale(LC_ALL, "");
143 textdomain (PACKAGE); 96 bindtextdomain(PACKAGE, LOCALEDIR);
97 textdomain(PACKAGE);
144 98
145 /* Parse extra opts if any */ 99 /* Parse extra opts if any */
146 argv=np_extra_opts (&argc, argv, progname); 100 argv = np_extra_opts(&argc, argv, progname);
147 101
148 if (process_arguments (argc, argv) == ERROR) 102 check_smtp_config_wrapper tmp_config = process_arguments(argc, argv);
149 usage4 (_("Could not parse arguments")); 103
104 if (tmp_config.errorcode == ERROR) {
105 usage4(_("Could not parse arguments"));
106 }
107
108 const check_smtp_config config = tmp_config.config;
150 109
151 /* If localhostname not set on command line, use gethostname to set */ 110 /* If localhostname not set on command line, use gethostname to set */
152 if(! localhostname){ 111 char *localhostname = config.localhostname;
153 localhostname = malloc (HOST_MAX_BYTES); 112 if (!localhostname) {
154 if(!localhostname){ 113 localhostname = malloc(HOST_MAX_BYTES);
114 if (!localhostname) {
155 printf(_("malloc() failed!\n")); 115 printf(_("malloc() failed!\n"));
156 return STATE_CRITICAL; 116 exit(STATE_CRITICAL);
157 } 117 }
158 if(gethostname(localhostname, HOST_MAX_BYTES)){ 118 if (gethostname(localhostname, HOST_MAX_BYTES)) {
159 printf(_("gethostname() failed!\n")); 119 printf(_("gethostname() failed!\n"));
160 return STATE_CRITICAL; 120 exit(STATE_CRITICAL);
161 } 121 }
162 } 122 }
163 if(use_lhlo) 123
164 xasprintf (&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n"); 124 char *helocmd = NULL;
165 else if(use_ehlo) 125 if (config.use_lhlo) {
166 xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n"); 126 xasprintf(&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n");
167 else 127 } else if (config.use_ehlo) {
168 xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n"); 128 xasprintf(&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n");
169 129 } else {
170 if (verbose) 130 xasprintf(&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n");
131 }
132
133 if (verbose) {
171 printf("HELOCMD: %s", helocmd); 134 printf("HELOCMD: %s", helocmd);
135 }
172 136
137 char *mail_command = strdup("MAIL ");
138 char *cmd_str = NULL;
173 /* initialize the MAIL command with optional FROM command */ 139 /* initialize the MAIL command with optional FROM command */
174 xasprintf (&cmd_str, "%sFROM:<%s>%s", mail_command, from_arg, "\r\n"); 140 xasprintf(&cmd_str, "%sFROM:<%s>%s", mail_command, config.from_arg, "\r\n");
175 141
176 if (verbose && send_mail_from) 142 if (verbose && config.send_mail_from) {
177 printf ("FROM CMD: %s", cmd_str); 143 printf("FROM CMD: %s", cmd_str);
144 }
145
146 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */
147 (void)signal(SIGPIPE, SIG_IGN);
178 148
179 /* initialize alarm signal handling */ 149 /* initialize alarm signal handling */
180 (void) signal (SIGALRM, socket_timeout_alarm_handler); 150 (void)signal(SIGALRM, socket_timeout_alarm_handler);
181 151
182 /* set socket timeout */ 152 /* set socket timeout */
183 (void) alarm (socket_timeout); 153 (void)alarm(socket_timeout);
184 154
155 struct timeval start_time;
185 /* start timer */ 156 /* start timer */
186 gettimeofday (&tv, NULL); 157 gettimeofday(&start_time, NULL);
187 158
159 int socket_descriptor = 0;
188 /* try to connect to the host at the given port number */ 160 /* try to connect to the host at the given port number */
189 result = my_tcp_connect (server_address, server_port, &sd); 161 mp_state_enum result = my_tcp_connect(config.server_address, config.server_port, &socket_descriptor);
190 162
163 char *error_msg = "";
164 char buffer[MAX_INPUT_BUFFER];
165 bool ssl_established = false;
191 if (result == STATE_OK) { /* we connected */ 166 if (result == STATE_OK) { /* we connected */
192 /* If requested, send PROXY header */ 167 /* If requested, send PROXY header */
193 if (use_proxy_prefix) { 168 if (config.use_proxy_prefix) {
194 if (verbose) 169 if (verbose) {
195 printf ("Sending header %s\n", PROXY_PREFIX); 170 printf("Sending header %s\n", PROXY_PREFIX);
196 my_send(PROXY_PREFIX, strlen(PROXY_PREFIX)); 171 }
172 my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established);
197 } 173 }
198 174
199#ifdef HAVE_SSL 175#ifdef HAVE_SSL
200 if (use_ssl) { 176 if (config.use_ssl) {
201 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL)); 177 result = np_net_ssl_init_with_hostname(socket_descriptor, (config.use_sni ? config.server_address : NULL));
202 if (result != STATE_OK) { 178 if (result != STATE_OK) {
203 printf (_("CRITICAL - Cannot create SSL context.\n")); 179 printf(_("CRITICAL - Cannot create SSL context.\n"));
204 close(sd); 180 close(socket_descriptor);
205 np_net_ssl_cleanup(); 181 np_net_ssl_cleanup();
206 return STATE_CRITICAL; 182 exit(STATE_CRITICAL);
207 } else {
208 ssl_established = 1;
209 } 183 }
184 ssl_established = true;
210 } 185 }
211#endif 186#endif
212 187
213 /* watch for the SMTP connection string and */ 188 /* watch for the SMTP connection string and */
214 /* return a WARNING status if we couldn't read any data */ 189 /* return a WARNING status if we couldn't read any data */
215 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 190 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
216 printf (_("recv() failed\n")); 191 printf(_("recv() failed\n"));
217 return STATE_WARNING; 192 exit(STATE_WARNING);
218 } 193 }
219 194
195 char *server_response = NULL;
220 /* save connect return (220 hostname ..) for later use */ 196 /* save connect return (220 hostname ..) for later use */
221 xasprintf(&server_response, "%s", buffer); 197 xasprintf(&server_response, "%s", buffer);
222 198
223 /* send the HELO/EHLO command */ 199 /* send the HELO/EHLO command */
224 my_send(helocmd, strlen(helocmd)); 200 my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established);
225 201
226 /* allow for response to helo command to reach us */ 202 /* allow for response to helo command to reach us */
227 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 203 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
228 printf (_("recv() failed\n")); 204 printf(_("recv() failed\n"));
229 return STATE_WARNING; 205 exit(STATE_WARNING);
230 } else if(use_ehlo || use_lhlo){ 206 }
231 if(strstr(buffer, "250 STARTTLS") != NULL || 207
232 strstr(buffer, "250-STARTTLS") != NULL){ 208 bool supports_tls = false;
233 supports_tls=true; 209 if (config.use_ehlo || config.use_lhlo) {
210 if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) {
211 supports_tls = true;
234 } 212 }
235 } 213 }
236 214
237 if(use_starttls && ! supports_tls){ 215 if (config.use_starttls && !supports_tls) {
238 printf(_("WARNING - TLS not supported by server\n")); 216 printf(_("WARNING - TLS not supported by server\n"));
239 smtp_quit(); 217 smtp_quit(config, buffer, socket_descriptor, ssl_established);
240 return STATE_WARNING; 218 exit(STATE_WARNING);
241 } 219 }
242 220
243#ifdef HAVE_SSL 221#ifdef HAVE_SSL
244 if(use_starttls) { 222 if (config.use_starttls) {
245 /* send the STARTTLS command */ 223 /* send the STARTTLS command */
246 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); 224 send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
247 225
248 recvlines(buffer, MAX_INPUT_BUFFER); /* wait for it */ 226 recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established); /* wait for it */
249 if (!strstr (buffer, SMTP_EXPECT)) { 227 if (!strstr(buffer, SMTP_EXPECT)) {
250 printf (_("Server does not support STARTTLS\n")); 228 printf(_("Server does not support STARTTLS\n"));
251 smtp_quit(); 229 smtp_quit(config, buffer, socket_descriptor, ssl_established);
252 return STATE_UNKNOWN; 230 exit(STATE_UNKNOWN);
253 } 231 }
254 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL)); 232
255 if(result != STATE_OK) { 233 result = np_net_ssl_init_with_hostname(socket_descriptor, (config.use_sni ? config.server_address : NULL));
256 printf (_("CRITICAL - Cannot create SSL context.\n")); 234 if (result != STATE_OK) {
257 close(sd); 235 printf(_("CRITICAL - Cannot create SSL context.\n"));
258 np_net_ssl_cleanup(); 236 close(socket_descriptor);
259 return STATE_CRITICAL; 237 np_net_ssl_cleanup();
260 } else { 238 exit(STATE_CRITICAL);
261 ssl_established = 1; 239 }
262 } 240
263 241 ssl_established = true;
264 /* 242
265 * Resend the EHLO command. 243 /*
266 * 244 * Resend the EHLO command.
267 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge 245 *
268 * obtained from the server, such as the list of SMTP service 246 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge
269 * extensions, which was not obtained from the TLS negotiation 247 * obtained from the server, such as the list of SMTP service
270 * itself. The client SHOULD send an EHLO command as the first 248 * extensions, which was not obtained from the TLS negotiation
271 * command after a successful TLS negotiation.'' For this 249 * itself. The client SHOULD send an EHLO command as the first
272 * reason, some MTAs will not allow an AUTH LOGIN command before 250 * command after a successful TLS negotiation.'' For this
273 * we resent EHLO via TLS. 251 * reason, some MTAs will not allow an AUTH LOGIN command before
274 */ 252 * we resent EHLO via TLS.
275 if (my_send(helocmd, strlen(helocmd)) <= 0) { 253 */
276 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS.")); 254 if (my_send(config, helocmd, strlen(helocmd), socket_descriptor, ssl_established) <= 0) {
277 my_close(); 255 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS."));
278 return STATE_UNKNOWN; 256 my_close(socket_descriptor);
279 } 257 exit(STATE_UNKNOWN);
280 if (verbose) 258 }
281 printf(_("sent %s"), helocmd); 259
282 if ((n = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 260 if (verbose) {
283 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS.")); 261 printf(_("sent %s"), helocmd);
284 my_close(); 262 }
285 return STATE_UNKNOWN;
286 }
287 if (verbose) {
288 printf("%s", buffer);
289 }
290 263
291# ifdef USE_OPENSSL 264 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
292 if ( check_cert ) { 265 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS."));
293 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 266 my_close(socket_descriptor);
294 smtp_quit(); 267 exit(STATE_UNKNOWN);
295 my_close(); 268 }
296 return result; 269
297 } 270 if (verbose) {
298# endif /* USE_OPENSSL */ 271 printf("%s", buffer);
272 }
273
274# ifdef USE_OPENSSL
275 if (config.check_cert) {
276 result = np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
277 smtp_quit(config, buffer, socket_descriptor, ssl_established);
278 my_close(socket_descriptor);
279 exit(result);
280 }
281# endif /* USE_OPENSSL */
299 } 282 }
300#endif 283#endif
301 284
302 if (verbose) 285 if (verbose) {
303 printf ("%s", buffer); 286 printf("%s", buffer);
287 }
304 288
305 /* save buffer for later use */ 289 /* save buffer for later use */
306 xasprintf(&server_response, "%s%s", server_response, buffer); 290 xasprintf(&server_response, "%s%s", server_response, buffer);
307 /* strip the buffer of carriage returns */ 291 /* strip the buffer of carriage returns */
308 strip (server_response); 292 strip(server_response);
309 293
310 /* make sure we find the droids we are looking for */ 294 /* make sure we find the droids we are looking for */
311 if (!strstr (server_response, server_expect)) { 295 if (!strstr(server_response, config.server_expect)) {
312 if (server_port == SMTP_PORT) 296 if (config.server_port == SMTP_PORT) {
313 printf (_("Invalid SMTP response received from host: %s\n"), server_response); 297 printf(_("Invalid SMTP response received from host: %s\n"), server_response);
314 else 298 } else {
315 printf (_("Invalid SMTP response received from host on port %d: %s\n"), 299 printf(_("Invalid SMTP response received from host on port %d: %s\n"), config.server_port, server_response);
316 server_port, server_response); 300 }
317 return STATE_WARNING; 301 exit(STATE_WARNING);
318 } 302 }
319 303
320 if (send_mail_from) { 304 if (config.send_mail_from) {
321 my_send(cmd_str, strlen(cmd_str)); 305 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
322 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 306 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && verbose) {
323 printf("%s", buffer); 307 printf("%s", buffer);
308 }
324 } 309 }
325 310
326 n = 0; 311 int counter = 0;
327 while (n < ncommands) { 312 while (counter < config.ncommands) {
328 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n"); 313 xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n");
329 my_send(cmd_str, strlen(cmd_str)); 314 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
330 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 315 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && verbose) {
331 printf("%s", buffer); 316 printf("%s", buffer);
332 strip (buffer); 317 }
333 if (n < nresponses) { 318 strip(buffer);
334 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 319 if (counter < config.nresponses) {
335 errcode = regcomp (&preg, responses[n], cflags); 320 int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
321 regex_t preg;
322 int errcode = regcomp(&preg, config.responses[counter], cflags);
323 char errbuf[MAX_INPUT_BUFFER];
336 if (errcode != 0) { 324 if (errcode != 0) {
337 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 325 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
338 printf (_("Could Not Compile Regular Expression")); 326 printf(_("Could Not Compile Regular Expression"));
339 return ERROR; 327 exit(STATE_UNKNOWN);
340 } 328 }
341 excode = regexec (&preg, buffer, 10, pmatch, eflags); 329
330 regmatch_t pmatch[10];
331 int eflags = 0;
332 int excode = regexec(&preg, buffer, 10, pmatch, eflags);
342 if (excode == 0) { 333 if (excode == 0) {
343 result = STATE_OK; 334 result = STATE_OK;
344 } 335 } else if (excode == REG_NOMATCH) {
345 else if (excode == REG_NOMATCH) {
346 result = STATE_WARNING; 336 result = STATE_WARNING;
347 printf (_("SMTP %s - Invalid response '%s' to command '%s'\n"), state_text (result), buffer, commands[n]); 337 printf(_("SMTP %s - Invalid response '%s' to command '%s'\n"), state_text(result), buffer, config.commands[counter]);
348 } 338 } else {
349 else { 339 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
350 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER); 340 printf(_("Execute Error: %s\n"), errbuf);
351 printf (_("Execute Error: %s\n"), errbuf);
352 result = STATE_UNKNOWN; 341 result = STATE_UNKNOWN;
353 } 342 }
354 } 343 }
355 n++; 344 counter++;
356 } 345 }
357 346
358 if (authtype != NULL) { 347 if (config.authtype != NULL) {
359 if (strcmp (authtype, "LOGIN") == 0) { 348 if (strcmp(config.authtype, "LOGIN") == 0) {
360 char *abuf; 349 char *abuf;
361 int ret; 350 int ret;
362 do { 351 do {
363 if (authuser == NULL) { 352 if (config.authuser == NULL) {
364 result = STATE_CRITICAL; 353 result = STATE_CRITICAL;
365 xasprintf(&error_msg, _("no authuser specified, ")); 354 xasprintf(&error_msg, _("no authuser specified, "));
366 break; 355 break;
367 } 356 }
368 if (authpass == NULL) { 357 if (config.authpass == NULL) {
369 result = STATE_CRITICAL; 358 result = STATE_CRITICAL;
370 xasprintf(&error_msg, _("no authpass specified, ")); 359 xasprintf(&error_msg, _("no authpass specified, "));
371 break; 360 break;
372 } 361 }
373 362
374 /* send AUTH LOGIN */ 363 /* send AUTH LOGIN */
375 my_send(SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN)); 364 my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor, ssl_established);
376 if (verbose) 365 if (verbose) {
377 printf (_("sent %s\n"), "AUTH LOGIN"); 366 printf(_("sent %s\n"), "AUTH LOGIN");
367 }
378 368
379 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 369 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
380 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, ")); 370 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, "));
381 result = STATE_WARNING; 371 result = STATE_WARNING;
382 break; 372 break;
383 } 373 }
384 if (verbose) 374 if (verbose) {
385 printf (_("received %s\n"), buffer); 375 printf(_("received %s\n"), buffer);
376 }
386 377
387 if (strncmp (buffer, "334", 3) != 0) { 378 if (strncmp(buffer, "334", 3) != 0) {
388 result = STATE_CRITICAL; 379 result = STATE_CRITICAL;
389 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, ")); 380 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, "));
390 break; 381 break;
391 } 382 }
392 383
393 /* encode authuser with base64 */ 384 /* encode authuser with base64 */
394 base64_encode_alloc (authuser, strlen(authuser), &abuf); 385 base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf);
395 xasprintf(&abuf, "%s\r\n", abuf); 386 xasprintf(&abuf, "%s\r\n", abuf);
396 my_send(abuf, strlen(abuf)); 387 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
397 if (verbose) 388 if (verbose) {
398 printf (_("sent %s\n"), abuf); 389 printf(_("sent %s\n"), abuf);
390 }
399 391
400 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 392 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
401 result = STATE_CRITICAL; 393 result = STATE_CRITICAL;
402 xasprintf(&error_msg, _("recv() failed after sending authuser, ")); 394 xasprintf(&error_msg, _("recv() failed after sending authuser, "));
403 break; 395 break;
404 } 396 }
405 if (verbose) { 397 if (verbose) {
406 printf (_("received %s\n"), buffer); 398 printf(_("received %s\n"), buffer);
407 } 399 }
408 if (strncmp (buffer, "334", 3) != 0) { 400 if (strncmp(buffer, "334", 3) != 0) {
409 result = STATE_CRITICAL; 401 result = STATE_CRITICAL;
410 xasprintf(&error_msg, _("invalid response received after authuser, ")); 402 xasprintf(&error_msg, _("invalid response received after authuser, "));
411 break; 403 break;
412 } 404 }
413 /* encode authpass with base64 */ 405 /* encode authpass with base64 */
414 base64_encode_alloc (authpass, strlen(authpass), &abuf); 406 base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf);
415 xasprintf(&abuf, "%s\r\n", abuf); 407 xasprintf(&abuf, "%s\r\n", abuf);
416 my_send(abuf, strlen(abuf)); 408 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
417 if (verbose) { 409 if (verbose) {
418 printf (_("sent %s\n"), abuf); 410 printf(_("sent %s\n"), abuf);
419 } 411 }
420 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 412 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
421 result = STATE_CRITICAL; 413 result = STATE_CRITICAL;
422 xasprintf(&error_msg, _("recv() failed after sending authpass, ")); 414 xasprintf(&error_msg, _("recv() failed after sending authpass, "));
423 break; 415 break;
424 } 416 }
425 if (verbose) { 417 if (verbose) {
426 printf (_("received %s\n"), buffer); 418 printf(_("received %s\n"), buffer);
427 } 419 }
428 if (strncmp (buffer, "235", 3) != 0) { 420 if (strncmp(buffer, "235", 3) != 0) {
429 result = STATE_CRITICAL; 421 result = STATE_CRITICAL;
430 xasprintf(&error_msg, _("invalid response received after authpass, ")); 422 xasprintf(&error_msg, _("invalid response received after authpass, "));
431 break; 423 break;
432 } 424 }
433 break; 425 break;
434 } while (0); 426 } while (false);
435 } else { 427 } else {
436 result = STATE_CRITICAL; 428 result = STATE_CRITICAL;
437 xasprintf(&error_msg, _("only authtype LOGIN is supported, ")); 429 xasprintf(&error_msg, _("only authtype LOGIN is supported, "));
@@ -439,243 +431,243 @@ main (int argc, char **argv)
439 } 431 }
440 432
441 /* tell the server we're done */ 433 /* tell the server we're done */
442 smtp_quit(); 434 smtp_quit(config, buffer, socket_descriptor, ssl_established);
443 435
444 /* finally close the connection */ 436 /* finally close the connection */
445 close (sd); 437 close(socket_descriptor);
446 } 438 }
447 439
448 /* reset the alarm */ 440 /* reset the alarm */
449 alarm (0); 441 alarm(0);
450 442
451 microsec = deltime (tv); 443 long microsec = deltime(start_time);
452 elapsed_time = (double)microsec / 1.0e6; 444 double elapsed_time = (double)microsec / 1.0e6;
453 445
454 if (result == STATE_OK) { 446 if (result == STATE_OK) {
455 if (check_critical_time && elapsed_time > critical_time) 447 if (config.check_critical_time && elapsed_time > config.critical_time) {
456 result = STATE_CRITICAL; 448 result = STATE_CRITICAL;
457 else if (check_warning_time && elapsed_time > warning_time) 449 } else if (config.check_warning_time && elapsed_time > config.warning_time) {
458 result = STATE_WARNING; 450 result = STATE_WARNING;
451 }
459 } 452 }
460 453
461 printf (_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), 454 printf(_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), state_text(result), error_msg, elapsed_time, verbose ? ", " : "",
462 state_text (result), 455 verbose ? buffer : "",
463 error_msg, 456 fperfdata("time", elapsed_time, "s", config.check_warning_time, config.warning_time, config.check_critical_time,
464 elapsed_time, 457 config.critical_time, true, 0, false, 0));
465 verbose?", ":"", verbose?buffer:"",
466 fperfdata ("time", elapsed_time, "s",
467 (int)check_warning_time, warning_time,
468 (int)check_critical_time, critical_time,
469 true, 0, false, 0));
470 458
471 return result; 459 exit(result);
472} 460}
473 461
474
475
476/* process command-line arguments */ 462/* process command-line arguments */
477int 463check_smtp_config_wrapper process_arguments(int argc, char **argv) {
478process_arguments (int argc, char **argv)
479{
480 int c;
481 char* temp;
482
483 bool implicit_tls = false;
484
485 enum { 464 enum {
486 SNI_OPTION 465 SNI_OPTION = CHAR_MAX + 1
487 }; 466 };
488 467
489 int option = 0; 468 int option = 0;
490 static struct option longopts[] = { 469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
491 {"hostname", required_argument, 0, 'H'}, 470 {"expect", required_argument, 0, 'e'},
492 {"expect", required_argument, 0, 'e'}, 471 {"critical", required_argument, 0, 'c'},
493 {"critical", required_argument, 0, 'c'}, 472 {"warning", required_argument, 0, 'w'},
494 {"warning", required_argument, 0, 'w'}, 473 {"timeout", required_argument, 0, 't'},
495 {"timeout", required_argument, 0, 't'}, 474 {"port", required_argument, 0, 'p'},
496 {"port", required_argument, 0, 'p'}, 475 {"from", required_argument, 0, 'f'},
497 {"from", required_argument, 0, 'f'}, 476 {"fqdn", required_argument, 0, 'F'},
498 {"fqdn", required_argument, 0, 'F'}, 477 {"authtype", required_argument, 0, 'A'},
499 {"authtype", required_argument, 0, 'A'}, 478 {"authuser", required_argument, 0, 'U'},
500 {"authuser", required_argument, 0, 'U'}, 479 {"authpass", required_argument, 0, 'P'},
501 {"authpass", required_argument, 0, 'P'}, 480 {"command", required_argument, 0, 'C'},
502 {"command", required_argument, 0, 'C'}, 481 {"response", required_argument, 0, 'R'},
503 {"response", required_argument, 0, 'R'}, 482 {"verbose", no_argument, 0, 'v'},
504 {"verbose", no_argument, 0, 'v'}, 483 {"version", no_argument, 0, 'V'},
505 {"version", no_argument, 0, 'V'}, 484 {"use-ipv4", no_argument, 0, '4'},
506 {"use-ipv4", no_argument, 0, '4'}, 485 {"use-ipv6", no_argument, 0, '6'},
507 {"use-ipv6", no_argument, 0, '6'}, 486 {"help", no_argument, 0, 'h'},
508 {"help", no_argument, 0, 'h'}, 487 {"lmtp", no_argument, 0, 'L'},
509 {"lmtp", no_argument, 0, 'L'}, 488 {"ssl", no_argument, 0, 's'},
510 {"ssl", no_argument, 0, 's'}, 489 {"tls", no_argument, 0, 's'},
511 {"tls", no_argument, 0, 's'}, 490 {"starttls", no_argument, 0, 'S'},
512 {"starttls",no_argument,0,'S'}, 491 {"sni", no_argument, 0, SNI_OPTION},
513 {"sni", no_argument, 0, SNI_OPTION}, 492 {"certificate", required_argument, 0, 'D'},
514 {"certificate",required_argument,0,'D'}, 493 {"ignore-quit-failure", no_argument, 0, 'q'},
515 {"ignore-quit-failure",no_argument,0,'q'}, 494 {"proxy", no_argument, 0, 'r'},
516 {"proxy",no_argument,0,'r'}, 495 {0, 0, 0, 0}};
517 {0, 0, 0, 0} 496
497 check_smtp_config_wrapper result = {
498 .config = check_smtp_config_init(),
499 .errorcode = OK,
518 }; 500 };
519 501
520 if (argc < 2) 502 if (argc < 2) {
521 return ERROR; 503 result.errorcode = ERROR;
504 return result;
505 }
522 506
523 for (c = 1; c < argc; c++) { 507 for (int index = 1; index < argc; index++) {
524 if (strcmp ("-to", argv[c]) == 0) 508 if (strcmp("-to", argv[index]) == 0) {
525 strcpy (argv[c], "-t"); 509 strcpy(argv[index], "-t");
526 else if (strcmp ("-wt", argv[c]) == 0) 510 } else if (strcmp("-wt", argv[index]) == 0) {
527 strcpy (argv[c], "-w"); 511 strcpy(argv[index], "-w");
528 else if (strcmp ("-ct", argv[c]) == 0) 512 } else if (strcmp("-ct", argv[index]) == 0) {
529 strcpy (argv[c], "-c"); 513 strcpy(argv[index], "-c");
514 }
530 } 515 }
531 516
532 while (1) { 517 int command_size = 0;
533 c = getopt_long (argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q", 518 int response_size = 0;
534 longopts, &option); 519 bool implicit_tls = false;
520 int server_port_option = 0;
521 while (true) {
522 int opt_index = getopt_long(argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q", longopts, &option);
535 523
536 if (c == -1 || c == EOF) 524 if (opt_index == -1 || opt_index == EOF) {
537 break; 525 break;
526 }
538 527
539 switch (c) { 528 switch (opt_index) {
540 case 'H': /* hostname */ 529 case 'H': /* hostname */
541 if (is_host (optarg)) { 530 if (is_host(optarg)) {
542 server_address = optarg; 531 result.config.server_address = optarg;
543 } 532 } else {
544 else { 533 usage2(_("Invalid hostname/address"), optarg);
545 usage2 (_("Invalid hostname/address"), optarg);
546 } 534 }
547 break; 535 break;
548 case 'p': /* port */ 536 case 'p': /* port */
549 if (is_intpos (optarg)) 537 if (is_intpos(optarg)) {
550 server_port_option = atoi (optarg); 538 server_port_option = atoi(optarg);
551 else 539 } else {
552 usage4 (_("Port must be a positive integer")); 540 usage4(_("Port must be a positive integer"));
541 }
553 break; 542 break;
554 case 'F': 543 case 'F':
555 /* localhostname */ 544 /* localhostname */
556 localhostname = strdup(optarg); 545 result.config.localhostname = strdup(optarg);
557 break; 546 break;
558 case 'f': /* from argument */ 547 case 'f': /* from argument */
559 from_arg = optarg + strspn(optarg, "<"); 548 result.config.from_arg = optarg + strspn(optarg, "<");
560 from_arg = strndup(from_arg, strcspn(from_arg, ">")); 549 result.config.from_arg = strndup(result.config.from_arg, strcspn(result.config.from_arg, ">"));
561 send_mail_from = 1; 550 result.config.send_mail_from = true;
562 break; 551 break;
563 case 'A': 552 case 'A':
564 authtype = optarg; 553 result.config.authtype = optarg;
565 use_ehlo = true; 554 result.config.use_ehlo = true;
566 break; 555 break;
567 case 'U': 556 case 'U':
568 authuser = optarg; 557 result.config.authuser = optarg;
569 break; 558 break;
570 case 'P': 559 case 'P':
571 authpass = optarg; 560 result.config.authpass = optarg;
572 break; 561 break;
573 case 'e': /* server expect string on 220 */ 562 case 'e': /* server expect string on 220 */
574 server_expect = optarg; 563 result.config.server_expect = optarg;
575 break; 564 break;
576 case 'C': /* commands */ 565 case 'C': /* commands */
577 if (ncommands >= command_size) { 566 if (result.config.ncommands >= command_size) {
578 command_size+=8; 567 command_size += 8;
579 commands = realloc (commands, sizeof(char *) * command_size); 568 result.config.commands = realloc(result.config.commands, sizeof(char *) * command_size);
580 if (commands == NULL) 569 if (result.config.commands == NULL) {
581 die (STATE_UNKNOWN, 570 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), result.config.ncommands);
582 _("Could not realloc() units [%d]\n"), ncommands); 571 }
583 } 572 }
584 commands[ncommands] = (char *) malloc (sizeof(char) * 255); 573 result.config.commands[result.config.ncommands] = (char *)malloc(sizeof(char) * 255);
585 strncpy (commands[ncommands], optarg, 255); 574 strncpy(result.config.commands[result.config.ncommands], optarg, 255);
586 ncommands++; 575 result.config.ncommands++;
587 break; 576 break;
588 case 'R': /* server responses */ 577 case 'R': /* server responses */
589 if (nresponses >= response_size) { 578 if (result.config.nresponses >= response_size) {
590 response_size += 8; 579 response_size += 8;
591 responses = realloc (responses, sizeof(char *) * response_size); 580 result.config.responses = realloc(result.config.responses, sizeof(char *) * response_size);
592 if (responses == NULL) 581 if (result.config.responses == NULL) {
593 die (STATE_UNKNOWN, 582 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), result.config.nresponses);
594 _("Could not realloc() units [%d]\n"), nresponses); 583 }
595 } 584 }
596 responses[nresponses] = (char *) malloc (sizeof(char) * 255); 585 result.config.responses[result.config.nresponses] = (char *)malloc(sizeof(char) * 255);
597 strncpy (responses[nresponses], optarg, 255); 586 strncpy(result.config.responses[result.config.nresponses], optarg, 255);
598 nresponses++; 587 result.config.nresponses++;
599 break; 588 break;
600 case 'c': /* critical time threshold */ 589 case 'c': /* critical time threshold */
601 if (!is_nonnegative (optarg)) 590 if (!is_nonnegative(optarg)) {
602 usage4 (_("Critical time must be a positive")); 591 usage4(_("Critical time must be a positive"));
603 else { 592 } else {
604 critical_time = strtod (optarg, NULL); 593 result.config.critical_time = strtod(optarg, NULL);
605 check_critical_time = true; 594 result.config.check_critical_time = true;
606 } 595 }
607 break; 596 break;
608 case 'w': /* warning time threshold */ 597 case 'w': /* warning time threshold */
609 if (!is_nonnegative (optarg)) 598 if (!is_nonnegative(optarg)) {
610 usage4 (_("Warning time must be a positive")); 599 usage4(_("Warning time must be a positive"));
611 else { 600 } else {
612 warning_time = strtod (optarg, NULL); 601 result.config.warning_time = strtod(optarg, NULL);
613 check_warning_time = true; 602 result.config.check_warning_time = true;
614 } 603 }
615 break; 604 break;
616 case 'v': /* verbose */ 605 case 'v': /* verbose */
617 verbose++; 606 verbose++;
618 break; 607 break;
619 case 'q': 608 case 'q':
620 ignore_send_quit_failure = true; /* ignore problem sending QUIT */ 609 result.config.ignore_send_quit_failure = true; /* ignore problem sending QUIT */
621 break; 610 break;
622 case 't': /* timeout */ 611 case 't': /* timeout */
623 if (is_intnonneg (optarg)) { 612 if (is_intnonneg(optarg)) {
624 socket_timeout = atoi (optarg); 613 socket_timeout = atoi(optarg);
625 } 614 } else {
626 else { 615 usage4(_("Timeout interval must be a positive integer"));
627 usage4 (_("Timeout interval must be a positive integer"));
628 } 616 }
629 break; 617 break;
630 case 'D': 618 case 'D': {
631 /* Check SSL cert validity */ 619 /* Check SSL cert validity */
632#ifdef USE_OPENSSL 620#ifdef USE_OPENSSL
633 if ((temp=strchr(optarg,','))!=NULL) { 621 char *temp;
634 *temp='\0'; 622 if ((temp = strchr(optarg, ',')) != NULL) {
635 if (!is_intnonneg (optarg)) 623 *temp = '\0';
636 usage2 ("Invalid certificate expiration period", optarg); 624 if (!is_intnonneg(optarg)) {
637 days_till_exp_warn = atoi(optarg); 625 usage2("Invalid certificate expiration period", optarg);
638 *temp=','; 626 }
639 temp++; 627 result.config.days_till_exp_warn = atoi(optarg);
640 if (!is_intnonneg (temp)) 628 *temp = ',';
641 usage2 (_("Invalid certificate expiration period"), temp); 629 temp++;
642 days_till_exp_crit = atoi (temp); 630 if (!is_intnonneg(temp)) {
643 } 631 usage2(_("Invalid certificate expiration period"), temp);
644 else { 632 }
645 days_till_exp_crit=0; 633 result.config.days_till_exp_crit = atoi(temp);
646 if (!is_intnonneg (optarg)) 634 } else {
647 usage2 ("Invalid certificate expiration period", optarg); 635 result.config.days_till_exp_crit = 0;
648 days_till_exp_warn = atoi (optarg); 636 if (!is_intnonneg(optarg)) {
649 } 637 usage2("Invalid certificate expiration period", optarg);
650 check_cert = true; 638 }
651 ignore_send_quit_failure = true; 639 result.config.days_till_exp_warn = atoi(optarg);
640 }
641 result.config.check_cert = true;
642 result.config.ignore_send_quit_failure = true;
652#else 643#else
653 usage (_("SSL support not available - install OpenSSL and recompile")); 644 usage(_("SSL support not available - install OpenSSL and recompile"));
654#endif 645#endif
655 implicit_tls = true; 646 implicit_tls = true;
656 // fallthrough 647 // fallthrough
657 case 's': 648 case 's':
658 /* ssl */ 649 /* ssl */
659 use_ssl = true; 650 result.config.use_ssl = true;
660 server_port = SMTPS_PORT; 651 result.config.server_port = SMTPS_PORT;
661 break; 652 break;
662 case 'S': 653 case 'S':
663 /* starttls */ 654 /* starttls */
664 use_starttls = true; 655 result.config.use_starttls = true;
665 use_ehlo = true; 656 result.config.use_ehlo = true;
666 break; 657 break;
658 }
667 case SNI_OPTION: 659 case SNI_OPTION:
668#ifdef HAVE_SSL 660#ifdef HAVE_SSL
669 use_sni = true; 661 result.config.use_sni = true;
670#else 662#else
671 usage (_("SSL support not available - install OpenSSL and recompile")); 663 usage(_("SSL support not available - install OpenSSL and recompile"));
672#endif 664#endif
673 break; 665 break;
674 case 'r': 666 case 'r':
675 use_proxy_prefix = true; 667 result.config.use_proxy_prefix = true;
676 break; 668 break;
677 case 'L': 669 case 'L':
678 use_lhlo = true; 670 result.config.use_lhlo = true;
679 break; 671 break;
680 case '4': 672 case '4':
681 address_family = AF_INET; 673 address_family = AF_INET;
@@ -684,102 +676,79 @@ process_arguments (int argc, char **argv)
684#ifdef USE_IPV6 676#ifdef USE_IPV6
685 address_family = AF_INET6; 677 address_family = AF_INET6;
686#else 678#else
687 usage4 (_("IPv6 support not available")); 679 usage4(_("IPv6 support not available"));
688#endif 680#endif
689 break; 681 break;
690 case 'V': /* version */ 682 case 'V': /* version */
691 print_revision (progname, NP_VERSION); 683 print_revision(progname, NP_VERSION);
692 exit (STATE_UNKNOWN); 684 exit(STATE_UNKNOWN);
693 case 'h': /* help */ 685 case 'h': /* help */
694 print_help (); 686 print_help();
695 exit (STATE_UNKNOWN); 687 exit(STATE_UNKNOWN);
696 case '?': /* help */ 688 case '?': /* help */
697 usage5 (); 689 usage5();
698 } 690 }
699 } 691 }
700 692
701 c = optind; 693 int c = optind;
702 if (server_address == NULL) { 694 if (result.config.server_address == NULL) {
703 if (argv[c]) { 695 if (argv[c]) {
704 if (is_host (argv[c])) 696 if (is_host(argv[c])) {
705 server_address = argv[c]; 697 result.config.server_address = argv[c];
706 else 698 } else {
707 usage2 (_("Invalid hostname/address"), argv[c]); 699 usage2(_("Invalid hostname/address"), argv[c]);
708 } 700 }
709 else { 701 } else {
710 xasprintf (&server_address, "127.0.0.1"); 702 result.config.server_address = strdup("localhost");
711 } 703 }
712 } 704 }
713 705
714 if (server_expect == NULL) 706 if (result.config.use_starttls && result.config.use_ssl) {
715 server_expect = strdup (SMTP_EXPECT);
716
717 if (mail_command == NULL)
718 mail_command = strdup("MAIL ");
719
720 if (from_arg==NULL)
721 from_arg = strdup(" ");
722
723 if (use_starttls && use_ssl) {
724 if (implicit_tls) { 707 if (implicit_tls) {
725 use_ssl = false; 708 result.config.use_ssl = false;
726 server_port = SMTP_PORT;
727 } else { 709 } else {
728 usage4 (_("Set either -s/--ssl/--tls or -S/--starttls")); 710 usage4(_("Set either -s/--ssl/--tls or -S/--starttls"));
729 } 711 }
730 } 712 }
731 713
732 if (server_port_option != 0) { 714 if (server_port_option != 0) {
733 server_port = server_port_option; 715 result.config.server_port = server_port_option;
734 } 716 }
735 717
736 return validate_arguments (); 718 return result;
737}
738
739
740
741int
742validate_arguments (void)
743{
744 return OK;
745} 719}
746 720
747 721char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int socket_descriptor, bool ssl_established) {
748void 722 int sent_bytes = my_send(config, SMTP_QUIT, strlen(SMTP_QUIT), socket_descriptor, ssl_established);
749smtp_quit(void) 723 if (sent_bytes < 0) {
750{ 724 if (config.ignore_send_quit_failure) {
751 int bytes; 725 if (verbose) {
752 int n;
753
754 n = my_send(SMTP_QUIT, strlen(SMTP_QUIT));
755 if(n < 0) {
756 if(ignore_send_quit_failure) {
757 if(verbose) {
758 printf(_("Connection closed by server before sending QUIT command\n")); 726 printf(_("Connection closed by server before sending QUIT command\n"));
759 } 727 }
760 return; 728 return buffer;
761 } 729 }
762 die (STATE_UNKNOWN, 730 die(STATE_UNKNOWN, _("Connection closed by server before sending QUIT command\n"));
763 _("Connection closed by server before sending QUIT command\n"));
764 } 731 }
765 732
766 if (verbose) 733 if (verbose) {
767 printf(_("sent %s\n"), "QUIT"); 734 printf(_("sent %s\n"), "QUIT");
735 }
768 736
769 /* read the response but don't care about problems */ 737 /* read the response but don't care about problems */
770 bytes = recvlines(buffer, MAX_INPUT_BUFFER); 738 int bytes = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established);
771 if (verbose) { 739 if (verbose) {
772 if (bytes < 0) 740 if (bytes < 0) {
773 printf(_("recv() failed after QUIT.")); 741 printf(_("recv() failed after QUIT."));
774 else if (bytes == 0) 742 } else if (bytes == 0) {
775 printf(_("Connection reset by peer.")); 743 printf(_("Connection reset by peer."));
776 else { 744 } else {
777 buffer[bytes] = '\0'; 745 buffer[bytes] = '\0';
778 printf(_("received %s\n"), buffer); 746 printf(_("received %s\n"), buffer);
779 } 747 }
780 } 748 }
781}
782 749
750 return buffer;
751}
783 752
784/* 753/*
785 * Receive one line, copy it into buf and nul-terminate it. Returns the 754 * Receive one line, copy it into buf and nul-terminate it. Returns the
@@ -790,24 +759,22 @@ smtp_quit(void)
790 * function which buffers the data, move that to netutils.c and change 759 * function which buffers the data, move that to netutils.c and change
791 * check_smtp and other plugins to use that. Also, remove (\r)\n. 760 * check_smtp and other plugins to use that. Also, remove (\r)\n.
792 */ 761 */
793int 762int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor, bool ssl_established) {
794recvline(char *buf, size_t bufsize)
795{
796 int result; 763 int result;
797 unsigned i; 764 int counter;
798 765
799 for (i = result = 0; i < bufsize - 1; i++) { 766 for (counter = result = 0; counter < bufsize - 1; counter++) {
800 if ((result = my_recv(&buf[i], 1)) != 1) 767 if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) {
801 break; 768 break;
802 if (buf[i] == '\n') { 769 }
803 buf[++i] = '\0'; 770 if (buf[counter] == '\n') {
804 return i; 771 buf[++counter] = '\0';
772 return counter;
805 } 773 }
806 } 774 }
807 return (result == 1 || i == 0) ? -2 : result; /* -2 if out of space */ 775 return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */
808} 776}
809 777
810
811/* 778/*
812 * Receive one or more lines, copy them into buf and nul-terminate it. Returns 779 * Receive one or more lines, copy them into buf and nul-terminate it. Returns
813 * the number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on 780 * the number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
@@ -822,117 +789,103 @@ recvline(char *buf, size_t bufsize)
822 * 789 *
823 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n. 790 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n.
824 */ 791 */
825int 792int recvlines(check_smtp_config config, char *buf, size_t bufsize, int socket_descriptor, bool ssl_established) {
826recvlines(char *buf, size_t bufsize) 793 int result;
827{ 794 int counter;
828 int result, i; 795
829 796 for (counter = 0; /* forever */; counter += result) {
830 for (i = 0; /* forever */; i += result) 797 if (!((result = recvline(buf + counter, bufsize - counter, config, socket_descriptor, ssl_established)) > 3 &&
831 if (!((result = recvline(buf + i, bufsize - i)) > 3 && 798 isdigit((int)buf[counter]) && isdigit((int)buf[counter + 1]) && isdigit((int)buf[counter + 2]) && buf[counter + 3] == '-')) {
832 isdigit((int)buf[i]) &&
833 isdigit((int)buf[i + 1]) &&
834 isdigit((int)buf[i + 2]) &&
835 buf[i + 3] == '-'))
836 break; 799 break;
800 }
801 }
837 802
838 return (result <= 0) ? result : result + i; 803 return (result <= 0) ? result : result + counter;
839} 804}
840 805
841 806int my_close(int socket_descriptor) {
842int
843my_close (void)
844{
845 int result; 807 int result;
846 result = close(sd); 808 result = close(socket_descriptor);
847#ifdef HAVE_SSL 809#ifdef HAVE_SSL
848 np_net_ssl_cleanup(); 810 np_net_ssl_cleanup();
849#endif 811#endif
850 return result; 812 return result;
851} 813}
852 814
853 815void print_help(void) {
854void
855print_help (void)
856{
857 char *myport; 816 char *myport;
858 xasprintf (&myport, "%d", SMTP_PORT); 817 xasprintf(&myport, "%d", SMTP_PORT);
859 818
860 print_revision (progname, NP_VERSION); 819 print_revision(progname, NP_VERSION);
861 820
862 printf ("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n"); 821 printf("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n");
863 printf (COPYRIGHT, copyright, email); 822 printf(COPYRIGHT, copyright, email);
864 823
865 printf("%s\n", _("This plugin will attempt to open an SMTP connection with the host.")); 824 printf("%s\n", _("This plugin will attempt to open an SMTP connection with the host."));
866 825
867 printf ("\n\n"); 826 printf("\n\n");
868 827
869 print_usage (); 828 print_usage();
870 829
871 printf (UT_HELP_VRSN); 830 printf(UT_HELP_VRSN);
872 printf (UT_EXTRA_OPTS); 831 printf(UT_EXTRA_OPTS);
873 832
874 printf (UT_HOST_PORT, 'p', myport); 833 printf(UT_HOST_PORT, 'p', myport);
875 834
876 printf (UT_IPv46); 835 printf(UT_IPv46);
877 836
878 printf (" %s\n", "-e, --expect=STRING"); 837 printf(" %s\n", "-e, --expect=STRING");
879 printf (_(" String to expect in first line of server response (default: '%s')\n"), SMTP_EXPECT); 838 printf(_(" String to expect in first line of server response (default: '%s')\n"), SMTP_EXPECT);
880 printf (" %s\n", "-C, --command=STRING"); 839 printf(" %s\n", "-C, --command=STRING");
881 printf (" %s\n", _("SMTP command (may be used repeatedly)")); 840 printf(" %s\n", _("SMTP command (may be used repeatedly)"));
882 printf (" %s\n", "-R, --response=STRING"); 841 printf(" %s\n", "-R, --response=STRING");
883 printf (" %s\n", _("Expected response to command (may be used repeatedly)")); 842 printf(" %s\n", _("Expected response to command (may be used repeatedly)"));
884 printf (" %s\n", "-f, --from=STRING"); 843 printf(" %s\n", "-f, --from=STRING");
885 printf (" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")), 844 printf(" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")), printf(" %s\n", "-F, --fqdn=STRING");
886 printf (" %s\n", "-F, --fqdn=STRING"); 845 printf(" %s\n", _("FQDN used for HELO"));
887 printf (" %s\n", _("FQDN used for HELO")); 846 printf(" %s\n", "-r, --proxy");
888 printf (" %s\n", "-r, --proxy"); 847 printf(" %s\n", _("Use PROXY protocol prefix for the connection."));
889 printf (" %s\n", _("Use PROXY protocol prefix for the connection."));
890#ifdef HAVE_SSL 848#ifdef HAVE_SSL
891 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 849 printf(" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
892 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 850 printf(" %s\n", _("Minimum number of days a certificate has to be valid."));
893 printf (" %s\n", "-s, --ssl, --tls"); 851 printf(" %s\n", "-s, --ssl, --tls");
894 printf (" %s\n", _("Use SSL/TLS for the connection.")); 852 printf(" %s\n", _("Use SSL/TLS for the connection."));
895 printf (_(" Sets default port to %d.\n"), SMTPS_PORT); 853 printf(_(" Sets default port to %d.\n"), SMTPS_PORT);
896 printf (" %s\n", "-S, --starttls"); 854 printf(" %s\n", "-S, --starttls");
897 printf (" %s\n", _("Use STARTTLS for the connection.")); 855 printf(" %s\n", _("Use STARTTLS for the connection."));
898 printf (" %s\n", "--sni"); 856 printf(" %s\n", "--sni");
899 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 857 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
900#endif 858#endif
901 859
902 printf (" %s\n", "-A, --authtype=STRING"); 860 printf(" %s\n", "-A, --authtype=STRING");
903 printf (" %s\n", _("SMTP AUTH type to check (default none, only LOGIN supported)")); 861 printf(" %s\n", _("SMTP AUTH type to check (default none, only LOGIN supported)"));
904 printf (" %s\n", "-U, --authuser=STRING"); 862 printf(" %s\n", "-U, --authuser=STRING");
905 printf (" %s\n", _("SMTP AUTH username")); 863 printf(" %s\n", _("SMTP AUTH username"));
906 printf (" %s\n", "-P, --authpass=STRING"); 864 printf(" %s\n", "-P, --authpass=STRING");
907 printf (" %s\n", _("SMTP AUTH password")); 865 printf(" %s\n", _("SMTP AUTH password"));
908 printf (" %s\n", "-L, --lmtp"); 866 printf(" %s\n", "-L, --lmtp");
909 printf (" %s\n", _("Send LHLO instead of HELO/EHLO")); 867 printf(" %s\n", _("Send LHLO instead of HELO/EHLO"));
910 printf (" %s\n", "-q, --ignore-quit-failure"); 868 printf(" %s\n", "-q, --ignore-quit-failure");
911 printf (" %s\n", _("Ignore failure when sending QUIT command to server")); 869 printf(" %s\n", _("Ignore failure when sending QUIT command to server"));
912
913 printf (UT_WARN_CRIT);
914 870
915 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 871 printf(UT_WARN_CRIT);
916 872
917 printf (UT_VERBOSE); 873 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
874
875 printf(UT_VERBOSE);
918 876
919 printf("\n"); 877 printf("\n");
920 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return")); 878 printf("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
921 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful")); 879 printf("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful"));
922 printf ("%s\n", _("connects, but incorrect response messages from the host result in")); 880 printf("%s\n", _("connects, but incorrect response messages from the host result in"));
923 printf ("%s\n", _("STATE_WARNING return values.")); 881 printf("%s\n", _("STATE_WARNING return values."));
924 882
925 printf (UT_SUPPORT); 883 printf(UT_SUPPORT);
926} 884}
927 885
928 886void print_usage(void) {
929 887 printf("%s\n", _("Usage:"));
930void 888 printf("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
931print_usage (void) 889 printf("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
932{ 890 printf("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
933 printf ("%s\n", _("Usage:"));
934 printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
935 printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
936 printf ("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
937} 891}
938
diff --git a/plugins/check_smtp.d/config.h b/plugins/check_smtp.d/config.h
new file mode 100644
index 00000000..0a6511ef
--- /dev/null
+++ b/plugins/check_smtp.d/config.h
@@ -0,0 +1,92 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5#include <string.h>
6
7enum {
8 SMTP_PORT = 25,
9 SMTPS_PORT = 465
10};
11
12#define SMTP_EXPECT "220"
13
14typedef struct {
15 int server_port;
16 char *server_address;
17 char *localhostname;
18 char *server_expect;
19 bool ignore_send_quit_failure;
20
21 double warning_time;
22 bool check_warning_time;
23 double critical_time;
24 bool check_critical_time;
25 bool use_ehlo;
26 bool use_lhlo;
27
28 char *from_arg;
29 bool send_mail_from;
30
31 int ncommands;
32 char **commands;
33
34 int nresponses;
35 char **responses;
36
37 char *authtype;
38 char *authuser;
39 char *authpass;
40
41 bool use_proxy_prefix;
42#ifdef HAVE_SSL
43 bool check_cert;
44 int days_till_exp_warn;
45 int days_till_exp_crit;
46 bool use_ssl;
47 bool use_starttls;
48 bool use_sni;
49#endif
50} check_smtp_config;
51
52check_smtp_config check_smtp_config_init() {
53 check_smtp_config tmp = {
54 .server_port = SMTP_PORT,
55 .server_address = NULL,
56 .localhostname = NULL,
57
58 .server_expect = SMTP_EXPECT,
59 .ignore_send_quit_failure = false,
60
61 .warning_time = 0,
62 .check_warning_time = false,
63 .critical_time = 0,
64 .check_critical_time = false,
65 .use_ehlo = false,
66 .use_lhlo = false,
67
68 .from_arg = strdup(" "),
69 .send_mail_from = false,
70
71 .ncommands = 0,
72 .commands = NULL,
73
74 .nresponses = 0,
75 .responses = NULL,
76
77 .authtype = NULL,
78 .authuser = NULL,
79 .authpass = NULL,
80
81 .use_proxy_prefix = false,
82#ifdef HAVE_SSL
83 .check_cert = false,
84 .days_till_exp_warn = 0,
85 .days_till_exp_crit = 0,
86 .use_ssl = false,
87 .use_starttls = false,
88 .use_sni = false,
89#endif
90 };
91 return tmp;
92}
diff --git a/plugins/check_snmp.c b/plugins/check_snmp.c
index 90a04027..c1d8e2dd 100644
--- a/plugins/check_snmp.c
+++ b/plugins/check_snmp.c
@@ -1,35 +1,35 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_snmp plugin 3 * Monitoring check_snmp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_snmp plugin 10 * This file contains the check_snmp plugin
11* 11 *
12* Check status of remote machines and obtain system information via SNMP 12 * Check status of remote machines and obtain system information via SNMP
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_snmp"; 31const char *progname = "check_snmp";
32const char *copyright = "1999-2007"; 32const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "common.h"
@@ -37,60 +37,68 @@ const char *email = "devel@monitoring-plugins.org";
37#include "utils.h" 37#include "utils.h"
38#include "utils_cmd.h" 38#include "utils_cmd.h"
39 39
40#define DEFAULT_COMMUNITY "public" 40#define DEFAULT_COMMUNITY "public"
41#define DEFAULT_PORT "161" 41#define DEFAULT_PORT "161"
42#define DEFAULT_MIBLIST "ALL" 42#define DEFAULT_MIBLIST "ALL"
43#define DEFAULT_PROTOCOL "1" 43#define DEFAULT_PROTOCOL "1"
44#define DEFAULT_RETRIES 5 44#define DEFAULT_RETRIES 5
45#define DEFAULT_AUTH_PROTOCOL "MD5" 45#define DEFAULT_AUTH_PROTOCOL "MD5"
46#define DEFAULT_PRIV_PROTOCOL "DES" 46#define DEFAULT_PRIV_PROTOCOL "DES"
47#define DEFAULT_DELIMITER "=" 47#define DEFAULT_DELIMITER "="
48#define DEFAULT_OUTPUT_DELIMITER " " 48#define DEFAULT_OUTPUT_DELIMITER " "
49#define DEFAULT_BUFFER_SIZE 100 49#define DEFAULT_BUFFER_SIZE 100
50 50
51#define mark(a) ((a)!=0?"*":"") 51#define mark(a) ((a) != 0 ? "*" : "")
52 52
53#define CHECK_UNDEF 0 53#define CHECK_UNDEF 0
54#define CRIT_PRESENT 1 54#define CRIT_PRESENT 1
55#define CRIT_STRING 2 55#define CRIT_STRING 2
56#define CRIT_REGEX 4 56#define CRIT_REGEX 4
57#define WARN_PRESENT 8 57#define WARN_PRESENT 8
58 58
59#define OID_COUNT_STEP 8 59#define OID_COUNT_STEP 8
60 60
61/* Longopts only arguments */ 61/* Longopts only arguments */
62#define L_CALCULATE_RATE CHAR_MAX+1 62#define L_CALCULATE_RATE CHAR_MAX + 1
63#define L_RATE_MULTIPLIER CHAR_MAX+2 63#define L_RATE_MULTIPLIER CHAR_MAX + 2
64#define L_INVERT_SEARCH CHAR_MAX+3 64#define L_INVERT_SEARCH CHAR_MAX + 3
65#define L_OFFSET CHAR_MAX+4 65#define L_OFFSET CHAR_MAX + 4
66#define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX+5 66#define L_IGNORE_MIB_PARSING_ERRORS CHAR_MAX + 5
67 67
68/* Gobble to string - stop incrementing c when c[0] match one of the 68/* Gobble to string - stop incrementing c when c[0] match one of the
69 * characters in s */ 69 * characters in s */
70#define GOBBLE_TOS(c, s) while(c[0]!='\0' && strchr(s, c[0])==NULL) { c++; } 70#define GOBBLE_TOS(c, s) \
71 while (c[0] != '\0' && strchr(s, c[0]) == NULL) { \
72 c++; \
73 }
71/* Given c, keep track of backslashes (bk) and double-quotes (dq) 74/* Given c, keep track of backslashes (bk) and double-quotes (dq)
72 * from c[0] */ 75 * from c[0] */
73#define COUNT_SEQ(c, bk, dq) switch(c[0]) {\ 76#define COUNT_SEQ(c, bk, dq) \
74 case '\\': \ 77 switch (c[0]) { \
75 if (bk) bk--; \ 78 case '\\': \
76 else bk++; \ 79 if (bk) \
77 break; \ 80 bk--; \
78 case '"': \ 81 else \
79 if (!dq) { dq++; } \ 82 bk++; \
80 else if(!bk) { dq--; } \ 83 break; \
81 else { bk--; } \ 84 case '"': \
82 break; \ 85 if (!dq) { \
86 dq++; \
87 } else if (!bk) { \
88 dq--; \
89 } else { \
90 bk--; \
91 } \
92 break; \
83 } 93 }
84 94
85 95static int process_arguments(int, char **);
86 96static int validate_arguments(void);
87static int process_arguments (int, char **); 97static char *thisarg(char *str);
88static int validate_arguments (void); 98static char *nextarg(char *str);
89static char *thisarg (char *str); 99void print_usage(void);
90static char *nextarg (char *str); 100static void print_help(void);
91void print_usage (void); 101static char *multiply(char *str);
92static void print_help (void);
93static char *multiply (char *str);
94 102
95#include "regex.h" 103#include "regex.h"
96static char regex_expect[MAX_INPUT_BUFFER] = ""; 104static char regex_expect[MAX_INPUT_BUFFER] = "";
@@ -122,7 +130,7 @@ static char *units;
122static char *port; 130static char *port;
123static char *snmpcmd; 131static char *snmpcmd;
124static char string_value[MAX_INPUT_BUFFER] = ""; 132static char string_value[MAX_INPUT_BUFFER] = "";
125static int invert_search=0; 133static int invert_search = 0;
126static char **labels = NULL; 134static char **labels = NULL;
127static char **unitv = NULL; 135static char **unitv = NULL;
128static size_t nlabels = 0; 136static size_t nlabels = 0;
@@ -154,17 +162,18 @@ static state_data *previous_state;
154static double *previous_value; 162static double *previous_value;
155static size_t previous_size = OID_COUNT_STEP; 163static size_t previous_size = OID_COUNT_STEP;
156static int perf_labels = 1; 164static int perf_labels = 1;
157static char* ip_version = ""; 165static char *ip_version = "";
158static double multiplier = 1.0; 166static double multiplier = 1.0;
159static char *fmtstr = ""; 167static char *fmtstr = "";
160static bool fmtstr_set = false; 168static bool fmtstr_set = false;
161static char buffer[DEFAULT_BUFFER_SIZE]; 169static char buffer[DEFAULT_BUFFER_SIZE];
162static bool ignore_mib_parsing_errors = false; 170static bool ignore_mib_parsing_errors = false;
163 171
164static char *fix_snmp_range(char *th) 172static char *fix_snmp_range(char *th) {
165{ 173 double left;
166 double left, right; 174 double right;
167 char *colon, *ret; 175 char *colon;
176 char *ret;
168 177
169 if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0') 178 if ((colon = strchr(th, ':')) == NULL || *(colon + 1) == '\0')
170 return th; 179 return th;
@@ -182,12 +191,12 @@ static char *fix_snmp_range(char *th)
182 return ret; 191 return ret;
183} 192}
184 193
185int 194int main(int argc, char **argv) {
186main (int argc, char **argv) 195 int len;
187{ 196 int total_oids;
188 int len, total_oids;
189 size_t line; 197 size_t line;
190 unsigned int bk_count = 0, dq_count = 0; 198 unsigned int bk_count = 0;
199 unsigned int dq_count = 0;
191 int iresult = STATE_UNKNOWN; 200 int iresult = STATE_UNKNOWN;
192 int result = STATE_UNKNOWN; 201 int result = STATE_UNKNOWN;
193 int return_code = 0; 202 int return_code = 0;
@@ -200,80 +209,83 @@ main (int argc, char **argv)
200 char *outbuff; 209 char *outbuff;
201 char *ptr = NULL; 210 char *ptr = NULL;
202 char *show = NULL; 211 char *show = NULL;
203 char *th_warn=NULL; 212 char *th_warn = NULL;
204 char *th_crit=NULL; 213 char *th_crit = NULL;
205 char type[8] = ""; 214 char type[8] = "";
206 output chld_out, chld_err; 215 output chld_out;
207 char *previous_string=NULL; 216 output chld_err;
208 char *ap=NULL; 217 char *previous_string = NULL;
209 char *state_string=NULL; 218 char *ap = NULL;
210 size_t response_length, current_length, string_length; 219 char *state_string = NULL;
211 char *temp_string=NULL; 220 size_t response_length;
212 char *quote_string=NULL; 221 size_t current_length;
222 size_t string_length;
223 char *temp_string = NULL;
224 char *quote_string = NULL;
213 time_t current_time; 225 time_t current_time;
214 double temp_double; 226 double temp_double;
215 time_t duration; 227 time_t duration;
216 char *conv = "12345678"; 228 char *conv = "12345678";
217 int is_counter=0; 229 int is_counter = 0;
218 230
219 setlocale (LC_ALL, ""); 231 setlocale(LC_ALL, "");
220 bindtextdomain (PACKAGE, LOCALEDIR); 232 bindtextdomain(PACKAGE, LOCALEDIR);
221 textdomain (PACKAGE); 233 textdomain(PACKAGE);
222 234
223 labels = malloc (labels_size * sizeof(*labels)); 235 labels = malloc(labels_size * sizeof(*labels));
224 unitv = malloc (unitv_size * sizeof(*unitv)); 236 unitv = malloc(unitv_size * sizeof(*unitv));
225 thlds = malloc (thlds_size * sizeof(*thlds)); 237 thlds = malloc(thlds_size * sizeof(*thlds));
226 response_value = malloc (response_size * sizeof(*response_value)); 238 response_value = malloc(response_size * sizeof(*response_value));
227 previous_value = malloc (previous_size * sizeof(*previous_value)); 239 previous_value = malloc(previous_size * sizeof(*previous_value));
228 eval_method = calloc (eval_size, sizeof(*eval_method)); 240 eval_method = calloc(eval_size, sizeof(*eval_method));
229 oids = calloc(oids_size, sizeof (char *)); 241 oids = calloc(oids_size, sizeof(char *));
230 242
231 label = strdup ("SNMP"); 243 label = strdup("SNMP");
232 units = strdup (""); 244 units = strdup("");
233 port = strdup (DEFAULT_PORT); 245 port = strdup(DEFAULT_PORT);
234 outbuff = strdup (""); 246 outbuff = strdup("");
235 delimiter = strdup (" = "); 247 delimiter = strdup(" = ");
236 output_delim = strdup (DEFAULT_OUTPUT_DELIMITER); 248 output_delim = strdup(DEFAULT_OUTPUT_DELIMITER);
237 timeout_interval = DEFAULT_SOCKET_TIMEOUT; 249 timeout_interval = DEFAULT_SOCKET_TIMEOUT;
238 retries = DEFAULT_RETRIES; 250 retries = DEFAULT_RETRIES;
239 251
240 np_init( (char *) progname, argc, argv ); 252 np_init((char *)progname, argc, argv);
241 253
242 /* Parse extra opts if any */ 254 /* Parse extra opts if any */
243 argv=np_extra_opts (&argc, argv, progname); 255 argv = np_extra_opts(&argc, argv, progname);
244 256
245 np_set_args(argc, argv); 257 np_set_args(argc, argv);
246 258
247 time(&current_time); 259 time(&current_time);
248 260
249 if (process_arguments (argc, argv) == ERROR) 261 if (process_arguments(argc, argv) == ERROR)
250 usage4 (_("Could not parse arguments")); 262 usage4(_("Could not parse arguments"));
251 263
252 if(calculate_rate) { 264 if (calculate_rate) {
253 if (!strcmp(label, "SNMP")) 265 if (!strcmp(label, "SNMP"))
254 label = strdup("SNMP RATE"); 266 label = strdup("SNMP RATE");
255 267
256 size_t i = 0; 268 size_t i = 0;
257 269
258 previous_state = np_state_read(); 270 previous_state = np_state_read();
259 if(previous_state!=NULL) { 271 if (previous_state != NULL) {
260 /* Split colon separated values */ 272 /* Split colon separated values */
261 previous_string = strdup((char *) previous_state->data); 273 previous_string = strdup((char *)previous_state->data);
262 while((ap = strsep(&previous_string, ":")) != NULL) { 274 while ((ap = strsep(&previous_string, ":")) != NULL) {
263 if(verbose>2) 275 if (verbose > 2)
264 printf("State for %zd=%s\n", i, ap); 276 printf("State for %zd=%s\n", i, ap);
265 while (i >= previous_size) { 277 while (i >= previous_size) {
266 previous_size += OID_COUNT_STEP; 278 previous_size += OID_COUNT_STEP;
267 previous_value = realloc(previous_value, previous_size * sizeof(*previous_value)); 279 previous_value = realloc(previous_value, previous_size * sizeof(*previous_value));
268 } 280 }
269 previous_value[i++]=strtod(ap,NULL); 281 previous_value[i++] = strtod(ap, NULL);
270 } 282 }
271 } 283 }
272 } 284 }
273 285
274 /* Populate the thresholds */ 286 /* Populate the thresholds */
275 th_warn=warning_thresholds; 287 th_warn = warning_thresholds;
276 th_crit=critical_thresholds; 288 th_crit = critical_thresholds;
277 for (size_t i = 0; i < numoids; i++) { 289 for (size_t i = 0; i < numoids; i++) {
278 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL; 290 char *w = th_warn ? strndup(th_warn, strcspn(th_warn, ",")) : NULL;
279 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL; 291 char *c = th_crit ? strndup(th_crit, strcspn(th_crit, ",")) : NULL;
@@ -287,53 +299,52 @@ main (int argc, char **argv)
287 } 299 }
288 300
289 /* Skip empty thresholds, while avoiding segfault */ 301 /* Skip empty thresholds, while avoiding segfault */
290 set_thresholds(&thlds[i], 302 set_thresholds(&thlds[i], w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL, c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
291 w ? strpbrk(w, NP_THRESHOLDS_CHARS) : NULL,
292 c ? strpbrk(c, NP_THRESHOLDS_CHARS) : NULL);
293 if (w) { 303 if (w) {
294 th_warn=strchr(th_warn, ','); 304 th_warn = strchr(th_warn, ',');
295 if (th_warn) th_warn++; 305 if (th_warn)
306 th_warn++;
296 free(w); 307 free(w);
297 } 308 }
298 if (c) { 309 if (c) {
299 th_crit=strchr(th_crit, ','); 310 th_crit = strchr(th_crit, ',');
300 if (th_crit) th_crit++; 311 if (th_crit)
312 th_crit++;
301 free(c); 313 free(c);
302 } 314 }
303 } 315 }
304 316
305 /* Create the command array to execute */ 317 /* Create the command array to execute */
306 if(usesnmpgetnext) { 318 if (usesnmpgetnext) {
307 snmpcmd = strdup (PATH_TO_SNMPGETNEXT); 319 snmpcmd = strdup(PATH_TO_SNMPGETNEXT);
308 }else{ 320 } else {
309 snmpcmd = strdup (PATH_TO_SNMPGET); 321 snmpcmd = strdup(PATH_TO_SNMPGET);
310 } 322 }
311 323
312 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */ 324 /* 10 arguments to pass before context and authpriv options + 1 for host and numoids. Add one for terminating NULL */
313 325
314 unsigned index = 0; 326 unsigned index = 0;
315 command_line = calloc (11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof (char *)); 327 command_line = calloc(11 + numcontext + numauthpriv + 1 + numoids + 1, sizeof(char *));
316 328
317 command_line[index++] = snmpcmd; 329 command_line[index++] = snmpcmd;
318 command_line[index++] = strdup ("-Le"); 330 command_line[index++] = strdup("-Le");
319 command_line[index++] = strdup ("-t"); 331 command_line[index++] = strdup("-t");
320 xasprintf (&command_line[index++], "%d", timeout_interval); 332 xasprintf(&command_line[index++], "%d", timeout_interval);
321 command_line[index++] = strdup ("-r"); 333 command_line[index++] = strdup("-r");
322 xasprintf (&command_line[index++], "%d", retries); 334 xasprintf(&command_line[index++], "%d", retries);
323 command_line[index++] = strdup ("-m"); 335 command_line[index++] = strdup("-m");
324 command_line[index++] = strdup (miblist); 336 command_line[index++] = strdup(miblist);
325 command_line[index++] = "-v"; 337 command_line[index++] = "-v";
326 command_line[index++] = strdup (proto); 338 command_line[index++] = strdup(proto);
327 339
328 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", 340 xasprintf(&cl_hidden_auth, "%s -Le -t %d -r %d -m %s -v %s", snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''",
329 snmpcmd, timeout_interval, retries, strlen(miblist) ? miblist : "''", proto); 341 proto);
330 342
331 if (ignore_mib_parsing_errors) { 343 if (ignore_mib_parsing_errors) {
332 command_line[index++] = "-Pe"; 344 command_line[index++] = "-Pe";
333 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth); 345 xasprintf(&cl_hidden_auth, "%s -Pe", cl_hidden_auth);
334 } 346 }
335 347
336
337 for (int i = 0; i < numcontext; i++) { 348 for (int i = 0; i < numcontext; i++) {
338 command_line[index++] = contextargs[i]; 349 command_line[index++] = contextargs[i];
339 } 350 }
@@ -342,12 +353,9 @@ main (int argc, char **argv)
342 command_line[index++] = authpriv[i]; 353 command_line[index++] = authpriv[i];
343 } 354 }
344 355
345 xasprintf (&command_line[index++], "%s:%s", server_address, port); 356 xasprintf(&command_line[index++], "%s:%s", server_address, port);
346 357
347 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", 358 xasprintf(&cl_hidden_auth, "%s [context] [authpriv] %s:%s", cl_hidden_auth, server_address, port);
348 cl_hidden_auth,
349 server_address,
350 port);
351 359
352 for (size_t i = 0; i < numoids; i++) { 360 for (size_t i = 0; i < numoids; i++) {
353 command_line[index++] = oids[i]; 361 command_line[index++] = oids[i];
@@ -357,17 +365,17 @@ main (int argc, char **argv)
357 command_line[index++] = NULL; 365 command_line[index++] = NULL;
358 366
359 if (verbose) { 367 if (verbose) {
360 printf ("%s\n", cl_hidden_auth); 368 printf("%s\n", cl_hidden_auth);
361 } 369 }
362 370
363 /* Set signal handling and alarm */ 371 /* Set signal handling and alarm */
364 if (signal (SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) { 372 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
365 usage4 (_("Cannot catch SIGALRM")); 373 usage4(_("Cannot catch SIGALRM"));
366 } 374 }
367 alarm(timeout_interval * retries + 5); 375 alarm(timeout_interval * retries + 5);
368 376
369 /* Run the command */ 377 /* Run the command */
370 return_code = cmd_run_array (command_line, &chld_out, &chld_err, 0); 378 return_code = cmd_run_array(command_line, &chld_out, &chld_err, 0);
371 379
372 /* disable alarm again */ 380 /* disable alarm again */
373 alarm(0); 381 alarm(0);
@@ -377,80 +385,74 @@ main (int argc, char **argv)
377 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis 385 Do this way so that if there is stderr, will get added to output, which helps problem diagnosis
378 */ 386 */
379 if (return_code != 0) 387 if (return_code != 0)
380 external_error=1; 388 external_error = 1;
381 if (chld_out.lines == 0) 389 if (chld_out.lines == 0)
382 external_error=1; 390 external_error = 1;
383 if (external_error) { 391 if (external_error) {
384 if (chld_err.lines > 0) { 392 if (chld_err.lines > 0) {
385 printf (_("External command error: %s\n"), chld_err.line[0]); 393 printf(_("External command error: %s\n"), chld_err.line[0]);
386 for (size_t i = 1; i < chld_err.lines; i++) { 394 for (size_t i = 1; i < chld_err.lines; i++) {
387 printf ("%s\n", chld_err.line[i]); 395 printf("%s\n", chld_err.line[i]);
388 } 396 }
389 } else { 397 } else {
390 printf(_("External command error with no output (return code: %d)\n"), return_code); 398 printf(_("External command error with no output (return code: %d)\n"), return_code);
391 } 399 }
392 exit (STATE_UNKNOWN); 400 exit(STATE_UNKNOWN);
393 } 401 }
394 402
395 if (verbose) { 403 if (verbose) {
396 for (size_t i = 0; i < chld_out.lines; i++) { 404 for (size_t i = 0; i < chld_out.lines; i++) {
397 printf ("%s\n", chld_out.line[i]); 405 printf("%s\n", chld_out.line[i]);
398 } 406 }
399 } 407 }
400 408
401 line = 0; 409 line = 0;
402 total_oids = 0; 410 total_oids = 0;
403 for (size_t i = 0; line < chld_out.lines && i < numoids ; line++, i++, total_oids++) { 411 for (size_t i = 0; line < chld_out.lines && i < numoids; line++, i++, total_oids++) {
404 if(calculate_rate) 412 if (calculate_rate)
405 conv = "%.10g"; 413 conv = "%.10g";
406 else 414 else
407 conv = "%.0f"; 415 conv = "%.0f";
408 416
409 ptr = chld_out.line[line]; 417 ptr = chld_out.line[line];
410 oidname = strpcpy (oidname, ptr, delimiter); 418 oidname = strpcpy(oidname, ptr, delimiter);
411 response = strstr (ptr, delimiter); 419 response = strstr(ptr, delimiter);
412 if (response == NULL) 420 if (response == NULL)
413 break; 421 break;
414 422
415 if (verbose > 2) { 423 if (verbose > 2) {
416 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i+1, line+1, oidname, response); 424 printf("Processing oid %zi (line %zi)\n oidname: %s\n response: %s\n", i + 1, line + 1, oidname, response);
417 } 425 }
418 426
419 /* Clean up type array - Sol10 does not necessarily zero it out */ 427 /* Clean up type array - Sol10 does not necessarily zero it out */
420 bzero(type, sizeof(type)); 428 bzero(type, sizeof(type));
421 429
422 is_counter=0; 430 is_counter = 0;
423 /* We strip out the datatype indicator for PHBs */ 431 /* We strip out the datatype indicator for PHBs */
424 if (strstr (response, "Gauge: ")) { 432 if (strstr(response, "Gauge: ")) {
425 show = multiply (strstr (response, "Gauge: ") + 7); 433 show = multiply(strstr(response, "Gauge: ") + 7);
426 } 434 } else if (strstr(response, "Gauge32: ")) {
427 else if (strstr (response, "Gauge32: ")) { 435 show = multiply(strstr(response, "Gauge32: ") + 9);
428 show = multiply (strstr (response, "Gauge32: ") + 9); 436 } else if (strstr(response, "Counter32: ")) {
429 } 437 show = strstr(response, "Counter32: ") + 11;
430 else if (strstr (response, "Counter32: ")) { 438 is_counter = 1;
431 show = strstr (response, "Counter32: ") + 11; 439 if (!calculate_rate)
432 is_counter=1;
433 if(!calculate_rate)
434 strcpy(type, "c"); 440 strcpy(type, "c");
435 } 441 } else if (strstr(response, "Counter64: ")) {
436 else if (strstr (response, "Counter64: ")) { 442 show = strstr(response, "Counter64: ") + 11;
437 show = strstr (response, "Counter64: ") + 11; 443 is_counter = 1;
438 is_counter=1; 444 if (!calculate_rate)
439 if(!calculate_rate)
440 strcpy(type, "c"); 445 strcpy(type, "c");
441 } 446 } else if (strstr(response, "INTEGER: ")) {
442 else if (strstr (response, "INTEGER: ")) { 447 show = multiply(strstr(response, "INTEGER: ") + 9);
443 show = multiply (strstr (response, "INTEGER: ") + 9);
444 448
445 if (fmtstr_set) { 449 if (fmtstr_set) {
446 conv = fmtstr; 450 conv = fmtstr;
447 } 451 }
448 } 452 } else if (strstr(response, "OID: ")) {
449 else if (strstr (response, "OID: ")) { 453 show = strstr(response, "OID: ") + 5;
450 show = strstr (response, "OID: ") + 5; 454 } else if (strstr(response, "STRING: ")) {
451 } 455 show = strstr(response, "STRING: ") + 8;
452 else if (strstr (response, "STRING: ")) {
453 show = strstr (response, "STRING: ") + 8;
454 conv = "%.10g"; 456 conv = "%.10g";
455 457
456 /* Get the rest of the string on multi-line strings */ 458 /* Get the rest of the string on multi-line strings */
@@ -464,15 +466,17 @@ main (int argc, char **argv)
464 466
465 if (dq_count) { /* unfinished line */ 467 if (dq_count) { /* unfinished line */
466 /* copy show verbatim first */ 468 /* copy show verbatim first */
467 if (!mult_resp) mult_resp = strdup(""); 469 if (!mult_resp)
468 xasprintf (&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show); 470 mult_resp = strdup("");
471 xasprintf(&mult_resp, "%s%s:\n%s\n", mult_resp, oids[i], show);
469 /* then strip out unmatched double-quote from single-line output */ 472 /* then strip out unmatched double-quote from single-line output */
470 if (show[0] == '"') show++; 473 if (show[0] == '"')
474 show++;
471 475
472 /* Keep reading until we match end of double-quoted string */ 476 /* Keep reading until we match end of double-quoted string */
473 for (line++; line < chld_out.lines; line++) { 477 for (line++; line < chld_out.lines; line++) {
474 ptr = chld_out.line[line]; 478 ptr = chld_out.line[line];
475 xasprintf (&mult_resp, "%s%s\n", mult_resp, ptr); 479 xasprintf(&mult_resp, "%s%s\n", mult_resp, ptr);
476 480
477 COUNT_SEQ(ptr, bk_count, dq_count) 481 COUNT_SEQ(ptr, bk_count, dq_count)
478 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') { 482 while (dq_count && ptr[0] != '\n' && ptr[0] != '\0') {
@@ -481,15 +485,14 @@ main (int argc, char **argv)
481 COUNT_SEQ(ptr, bk_count, dq_count) 485 COUNT_SEQ(ptr, bk_count, dq_count)
482 } 486 }
483 /* Break for loop before next line increment when done */ 487 /* Break for loop before next line increment when done */
484 if (!dq_count) break; 488 if (!dq_count)
489 break;
485 } 490 }
486 } 491 }
487 492
488 } 493 } else if (strstr(response, "Timeticks: ")) {
489 else if (strstr (response, "Timeticks: ")) { 494 show = strstr(response, "Timeticks: ");
490 show = strstr (response, "Timeticks: "); 495 } else
491 }
492 else
493 show = response + 3; 496 show = response + 3;
494 497
495 iresult = STATE_DEPENDENT; 498 iresult = STATE_DEPENDENT;
@@ -500,68 +503,67 @@ main (int argc, char **argv)
500 if (verbose > 2) { 503 if (verbose > 2) {
501 print_thresholds(" thresholds", thlds[i]); 504 print_thresholds(" thresholds", thlds[i]);
502 } 505 }
503 ptr = strpbrk (show, "-0123456789"); 506 ptr = strpbrk(show, "-0123456789");
504 if (ptr == NULL){ 507 if (ptr == NULL) {
505 if (nulloid == 3) 508 if (nulloid == 3)
506 die (STATE_UNKNOWN,_("No valid data returned (%s)\n"), show); 509 die(STATE_UNKNOWN, _("No valid data returned (%s)\n"), show);
507 else if (nulloid == 0) 510 else if (nulloid == 0)
508 die (STATE_OK,_("No valid data returned (%s)\n"), show); 511 die(STATE_OK, _("No valid data returned (%s)\n"), show);
509 else if (nulloid == 1) 512 else if (nulloid == 1)
510 die (STATE_WARNING,_("No valid data returned (%s)\n"), show); 513 die(STATE_WARNING, _("No valid data returned (%s)\n"), show);
511 else if (nulloid == 2) 514 else if (nulloid == 2)
512 die (STATE_CRITICAL,_("No valid data returned (%s)\n"), show); 515 die(STATE_CRITICAL, _("No valid data returned (%s)\n"), show);
513 } 516 }
514 while (i >= response_size) { 517 while (i >= response_size) {
515 response_size += OID_COUNT_STEP; 518 response_size += OID_COUNT_STEP;
516 response_value = realloc(response_value, response_size * sizeof(*response_value)); 519 response_value = realloc(response_value, response_size * sizeof(*response_value));
517 } 520 }
518 response_value[i] = strtod (ptr, NULL) + offset; 521 response_value[i] = strtod(ptr, NULL) + offset;
519 522
520 if(calculate_rate) { 523 if (calculate_rate) {
521 if (previous_state!=NULL) { 524 if (previous_state != NULL) {
522 duration = current_time-previous_state->time; 525 duration = current_time - previous_state->time;
523 if(duration<=0) 526 if (duration <= 0)
524 die(STATE_UNKNOWN,_("Time duration between plugin calls is invalid")); 527 die(STATE_UNKNOWN, _("Time duration between plugin calls is invalid"));
525 temp_double = response_value[i]-previous_value[i]; 528 temp_double = response_value[i] - previous_value[i];
526 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */ 529 /* Simple overflow catcher (same as in rrdtool, rrd_update.c) */
527 if(is_counter) { 530 if (is_counter) {
528 if(temp_double<(double)0.0) 531 if (temp_double < (double)0.0)
529 temp_double+=(double)4294967296.0; /* 2^32 */ 532 temp_double += (double)4294967296.0; /* 2^32 */
530 if(temp_double<(double)0.0) 533 if (temp_double < (double)0.0)
531 temp_double+=(double)18446744069414584320.0; /* 2^64-2^32 */; 534 temp_double += (double)18446744069414584320.0; /* 2^64-2^32 */
535 ;
532 } 536 }
533 /* Convert to per second, then use multiplier */ 537 /* Convert to per second, then use multiplier */
534 temp_double = temp_double/duration*rate_multiplier; 538 temp_double = temp_double / duration * rate_multiplier;
535 iresult = get_status(temp_double, thlds[i]); 539 iresult = get_status(temp_double, thlds[i]);
536 xasprintf (&show, conv, temp_double); 540 xasprintf(&show, conv, temp_double);
537 } 541 }
538 } else { 542 } else {
539 iresult = get_status(response_value[i], thlds[i]); 543 iresult = get_status(response_value[i], thlds[i]);
540 xasprintf (&show, conv, response_value[i]); 544 xasprintf(&show, conv, response_value[i]);
541 } 545 }
542 } 546 }
543 547
544 /* Process this block for string matching */ 548 /* Process this block for string matching */
545 else if (eval_size > i && eval_method[i] & CRIT_STRING) { 549 else if (eval_size > i && eval_method[i] & CRIT_STRING) {
546 if (strcmp (show, string_value)) 550 if (strcmp(show, string_value))
547 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK; 551 iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK;
548 else 552 else
549 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL; 553 iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL;
550 } 554 }
551 555
552 /* Process this block for regex matching */ 556 /* Process this block for regex matching */
553 else if (eval_size > i && eval_method[i] & CRIT_REGEX) { 557 else if (eval_size > i && eval_method[i] & CRIT_REGEX) {
554 excode = regexec (&preg, response, 10, pmatch, eflags); 558 excode = regexec(&preg, response, 10, pmatch, eflags);
555 if (excode == 0) { 559 if (excode == 0) {
556 iresult = (invert_search==0) ? STATE_OK : STATE_CRITICAL; 560 iresult = (invert_search == 0) ? STATE_OK : STATE_CRITICAL;
557 } 561 } else if (excode != REG_NOMATCH) {
558 else if (excode != REG_NOMATCH) { 562 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
559 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER); 563 printf(_("Execute Error: %s\n"), errbuf);
560 printf (_("Execute Error: %s\n"), errbuf); 564 exit(STATE_CRITICAL);
561 exit (STATE_CRITICAL); 565 } else {
562 } 566 iresult = (invert_search == 0) ? STATE_CRITICAL : STATE_OK;
563 else {
564 iresult = (invert_search==0) ? STATE_CRITICAL : STATE_OK;
565 } 567 }
566 } 568 }
567 569
@@ -577,294 +579,283 @@ main (int argc, char **argv)
577 } 579 }
578 580
579 /* Result is the worst outcome of all the OIDs tested */ 581 /* Result is the worst outcome of all the OIDs tested */
580 result = max_state (result, iresult); 582 result = max_state(result, iresult);
581 583
582 /* Prepend a label for this OID if there is one */ 584 /* Prepend a label for this OID if there is one */
583 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) 585 if (nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
584 xasprintf (&outbuff, "%s%s%s %s%s%s", outbuff, 586 xasprintf(&outbuff, "%s%s%s %s%s%s", outbuff, (i == 0) ? " " : output_delim, labels[i], mark(iresult), show, mark(iresult));
585 (i == 0) ? " " : output_delim,
586 labels[i], mark (iresult), show, mark (iresult));
587 else 587 else
588 xasprintf (&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim, 588 xasprintf(&outbuff, "%s%s%s%s%s", outbuff, (i == 0) ? " " : output_delim, mark(iresult), show, mark(iresult));
589 mark (iresult), show, mark (iresult));
590 589
591 /* Append a unit string for this OID if there is one */ 590 /* Append a unit string for this OID if there is one */
592 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL) 591 if (nunits > (size_t)0 && (size_t)i < nunits && unitv[i] != NULL)
593 xasprintf (&outbuff, "%s %s", outbuff, unitv[i]); 592 xasprintf(&outbuff, "%s %s", outbuff, unitv[i]);
594 593
595 /* Write perfdata with whatever can be parsed by strtod, if possible */ 594 /* Write perfdata with whatever can be parsed by strtod, if possible */
596 ptr = NULL; 595 ptr = NULL;
597 strtod(show, &ptr); 596 strtod(show, &ptr);
598 if (ptr > show) { 597 if (ptr > show) {
599 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL) 598 if (perf_labels && nlabels >= (size_t)1 && (size_t)i < nlabels && labels[i] != NULL)
600 temp_string=labels[i]; 599 temp_string = labels[i];
601 else 600 else
602 temp_string=oidname; 601 temp_string = oidname;
603 if (strpbrk (temp_string, " ='\"") == NULL) { 602 if (strpbrk(temp_string, " ='\"") == NULL) {
604 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1); 603 strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1);
605 } else { 604 } else {
606 if (strpbrk (temp_string, "'") == NULL) { 605 if (strpbrk(temp_string, "'") == NULL) {
607 quote_string="'"; 606 quote_string = "'";
608 } else { 607 } else {
609 quote_string="\""; 608 quote_string = "\"";
610 } 609 }
611 strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1); 610 strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1);
612 strncat(perfstr, temp_string, sizeof(perfstr)-strlen(perfstr)-1); 611 strncat(perfstr, temp_string, sizeof(perfstr) - strlen(perfstr) - 1);
613 strncat(perfstr, quote_string, sizeof(perfstr)-strlen(perfstr)-1); 612 strncat(perfstr, quote_string, sizeof(perfstr) - strlen(perfstr) - 1);
614 } 613 }
615 strncat(perfstr, "=", sizeof(perfstr)-strlen(perfstr)-1); 614 strncat(perfstr, "=", sizeof(perfstr) - strlen(perfstr) - 1);
616 len = sizeof(perfstr)-strlen(perfstr)-1; 615 len = sizeof(perfstr) - strlen(perfstr) - 1;
617 strncat(perfstr, show, len>ptr-show ? ptr-show : len); 616 strncat(perfstr, show, len > ptr - show ? ptr - show : len);
618 617
619 if (strcmp(type, "") != 0) { 618 if (strcmp(type, "") != 0) {
620 strncat(perfstr, type, sizeof(perfstr)-strlen(perfstr)-1); 619 strncat(perfstr, type, sizeof(perfstr) - strlen(perfstr) - 1);
621 } 620 }
622 621
623 if (warning_thresholds) { 622 if (warning_thresholds) {
624 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 623 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
625 if(thlds[i]->warning && thlds[i]->warning->text) 624 if (thlds[i]->warning && thlds[i]->warning->text)
626 strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr)-strlen(perfstr)-1); 625 strncat(perfstr, thlds[i]->warning->text, sizeof(perfstr) - strlen(perfstr) - 1);
627 } 626 }
628 627
629 if (critical_thresholds) { 628 if (critical_thresholds) {
630 if (!warning_thresholds) 629 if (!warning_thresholds)
631 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 630 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
632 strncat(perfstr, ";", sizeof(perfstr)-strlen(perfstr)-1); 631 strncat(perfstr, ";", sizeof(perfstr) - strlen(perfstr) - 1);
633 if(thlds[i]->critical && thlds[i]->critical->text) 632 if (thlds[i]->critical && thlds[i]->critical->text)
634 strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr)-strlen(perfstr)-1); 633 strncat(perfstr, thlds[i]->critical->text, sizeof(perfstr) - strlen(perfstr) - 1);
635 } 634 }
636 635
637 strncat(perfstr, " ", sizeof(perfstr)-strlen(perfstr)-1); 636 strncat(perfstr, " ", sizeof(perfstr) - strlen(perfstr) - 1);
638 } 637 }
639 } 638 }
640 639
641 /* Save state data, as all data collected now */ 640 /* Save state data, as all data collected now */
642 if(calculate_rate) { 641 if (calculate_rate) {
643 string_length=1024; 642 string_length = 1024;
644 state_string=malloc(string_length); 643 state_string = malloc(string_length);
645 if(state_string==NULL) 644 if (state_string == NULL)
646 die(STATE_UNKNOWN, _("Cannot malloc")); 645 die(STATE_UNKNOWN, _("Cannot malloc"));
647 646
648 current_length=0; 647 current_length = 0;
649 for(int i = 0; i < total_oids; i++) { 648 for (int i = 0; i < total_oids; i++) {
650 xasprintf(&temp_string,"%.0f",response_value[i]); 649 xasprintf(&temp_string, "%.0f", response_value[i]);
651 if(temp_string==NULL) 650 if (temp_string == NULL)
652 die(STATE_UNKNOWN,_("Cannot asprintf()")); 651 die(STATE_UNKNOWN, _("Cannot asprintf()"));
653 response_length = strlen(temp_string); 652 response_length = strlen(temp_string);
654 if(current_length+response_length>string_length) { 653 if (current_length + response_length > string_length) {
655 string_length=current_length+1024; 654 string_length = current_length + 1024;
656 state_string=realloc(state_string,string_length); 655 state_string = realloc(state_string, string_length);
657 if(state_string==NULL) 656 if (state_string == NULL)
658 die(STATE_UNKNOWN, _("Cannot realloc()")); 657 die(STATE_UNKNOWN, _("Cannot realloc()"));
659 } 658 }
660 strcpy(&state_string[current_length],temp_string); 659 strcpy(&state_string[current_length], temp_string);
661 current_length=current_length+response_length; 660 current_length = current_length + response_length;
662 state_string[current_length]=':'; 661 state_string[current_length] = ':';
663 current_length++; 662 current_length++;
664 free(temp_string); 663 free(temp_string);
665 } 664 }
666 state_string[--current_length]='\0'; 665 state_string[--current_length] = '\0';
667 if (verbose > 2) 666 if (verbose > 2)
668 printf("State string=%s\n",state_string); 667 printf("State string=%s\n", state_string);
669 668
670 /* This is not strictly the same as time now, but any subtle variations will cancel out */ 669 /* This is not strictly the same as time now, but any subtle variations will cancel out */
671 np_state_write_string(current_time, state_string ); 670 np_state_write_string(current_time, state_string);
672 if(previous_state==NULL) { 671 if (previous_state == NULL) {
673 /* Or should this be highest state? */ 672 /* Or should this be highest state? */
674 die( STATE_OK, _("No previous data to calculate rate - assume okay" ) ); 673 die(STATE_OK, _("No previous data to calculate rate - assume okay"));
675 } 674 }
676 } 675 }
677 676
678 printf ("%s %s -%s %s\n", label, state_text (result), outbuff, perfstr); 677 printf("%s %s -%s %s\n", label, state_text(result), outbuff, perfstr);
679 if (mult_resp) printf ("%s", mult_resp); 678 if (mult_resp)
679 printf("%s", mult_resp);
680 680
681 return result; 681 return result;
682} 682}
683 683
684
685
686/* process command-line arguments */ 684/* process command-line arguments */
687int 685int process_arguments(int argc, char **argv) {
688process_arguments (int argc, char **argv) 686 static struct option longopts[] = {STD_LONG_OPTS,
689{ 687 {"community", required_argument, 0, 'C'},
690 char *ptr; 688 {"oid", required_argument, 0, 'o'},
691 int c = 1; 689 {"object", required_argument, 0, 'o'},
692 size_t j = 0, jj = 0; 690 {"delimiter", required_argument, 0, 'd'},
693 691 {"nulloid", required_argument, 0, 'z'},
694 int option = 0; 692 {"output-delimiter", required_argument, 0, 'D'},
695 static struct option longopts[] = { 693 {"string", required_argument, 0, 's'},
696 STD_LONG_OPTS, 694 {"timeout", required_argument, 0, 't'},
697 {"community", required_argument, 0, 'C'}, 695 {"regex", required_argument, 0, 'r'},
698 {"oid", required_argument, 0, 'o'}, 696 {"ereg", required_argument, 0, 'r'},
699 {"object", required_argument, 0, 'o'}, 697 {"eregi", required_argument, 0, 'R'},
700 {"delimiter", required_argument, 0, 'd'}, 698 {"label", required_argument, 0, 'l'},
701 {"nulloid", required_argument, 0, 'z'}, 699 {"units", required_argument, 0, 'u'},
702 {"output-delimiter", required_argument, 0, 'D'}, 700 {"port", required_argument, 0, 'p'},
703 {"string", required_argument, 0, 's'}, 701 {"retries", required_argument, 0, 'e'},
704 {"timeout", required_argument, 0, 't'}, 702 {"miblist", required_argument, 0, 'm'},
705 {"regex", required_argument, 0, 'r'}, 703 {"protocol", required_argument, 0, 'P'},
706 {"ereg", required_argument, 0, 'r'}, 704 {"context", required_argument, 0, 'N'},
707 {"eregi", required_argument, 0, 'R'}, 705 {"seclevel", required_argument, 0, 'L'},
708 {"label", required_argument, 0, 'l'}, 706 {"secname", required_argument, 0, 'U'},
709 {"units", required_argument, 0, 'u'}, 707 {"authproto", required_argument, 0, 'a'},
710 {"port", required_argument, 0, 'p'}, 708 {"privproto", required_argument, 0, 'x'},
711 {"retries", required_argument, 0, 'e'}, 709 {"authpasswd", required_argument, 0, 'A'},
712 {"miblist", required_argument, 0, 'm'}, 710 {"privpasswd", required_argument, 0, 'X'},
713 {"protocol", required_argument, 0, 'P'}, 711 {"next", no_argument, 0, 'n'},
714 {"context", required_argument, 0, 'N'}, 712 {"rate", no_argument, 0, L_CALCULATE_RATE},
715 {"seclevel", required_argument, 0, 'L'}, 713 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER},
716 {"secname", required_argument, 0, 'U'}, 714 {"offset", required_argument, 0, L_OFFSET},
717 {"authproto", required_argument, 0, 'a'}, 715 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
718 {"privproto", required_argument, 0, 'x'}, 716 {"perf-oids", no_argument, 0, 'O'},
719 {"authpasswd", required_argument, 0, 'A'}, 717 {"ipv4", no_argument, 0, '4'},
720 {"privpasswd", required_argument, 0, 'X'}, 718 {"ipv6", no_argument, 0, '6'},
721 {"next", no_argument, 0, 'n'}, 719 {"multiplier", required_argument, 0, 'M'},
722 {"rate", no_argument, 0, L_CALCULATE_RATE}, 720 {"fmtstr", required_argument, 0, 'f'},
723 {"rate-multiplier", required_argument, 0, L_RATE_MULTIPLIER}, 721 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS},
724 {"offset", required_argument, 0, L_OFFSET}, 722 {0, 0, 0, 0}};
725 {"invert-search", no_argument, 0, L_INVERT_SEARCH},
726 {"perf-oids", no_argument, 0, 'O'},
727 {"ipv4", no_argument, 0, '4'},
728 {"ipv6", no_argument, 0, '6'},
729 {"multiplier", required_argument, 0, 'M'},
730 {"fmtstr", required_argument, 0, 'f'},
731 {"ignore-mib-parsing-errors", no_argument, false, L_IGNORE_MIB_PARSING_ERRORS},
732 {0, 0, 0, 0}
733 };
734 723
735 if (argc < 2) 724 if (argc < 2)
736 return ERROR; 725 return ERROR;
737 726
738 /* reverse compatibility for very old non-POSIX usage forms */ 727 /* reverse compatibility for very old non-POSIX usage forms */
739 for (c = 1; c < argc; c++) { 728 for (int c = 1; c < argc; c++) {
740 if (strcmp ("-to", argv[c]) == 0) 729 if (strcmp("-to", argv[c]) == 0)
741 strcpy (argv[c], "-t"); 730 strcpy(argv[c], "-t");
742 if (strcmp ("-wv", argv[c]) == 0) 731 if (strcmp("-wv", argv[c]) == 0)
743 strcpy (argv[c], "-w"); 732 strcpy(argv[c], "-w");
744 if (strcmp ("-cv", argv[c]) == 0) 733 if (strcmp("-cv", argv[c]) == 0)
745 strcpy (argv[c], "-c"); 734 strcpy(argv[c], "-c");
746 } 735 }
747 736
748 while (1) { 737 size_t j = 0;
749 c = getopt_long (argc, argv, "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", 738 size_t jj = 0;
750 longopts, &option); 739 while (true) {
740 int option = 0;
741 int option_char = getopt_long(argc, argv, "nhvVO46t:c:w:H:C:o:e:E:d:D:s:t:R:r:l:u:p:m:P:N:L:U:a:x:A:X:M:f:z:", longopts, &option);
751 742
752 if (c == -1 || c == EOF) 743 if (option_char == -1 || option_char == EOF)
753 break; 744 break;
754 745
755 switch (c) { 746 switch (option_char) {
756 case '?': /* usage */ 747 case '?': /* usage */
757 usage5 (); 748 usage5();
758 case 'h': /* help */ 749 case 'h': /* help */
759 print_help (); 750 print_help();
760 exit (STATE_UNKNOWN); 751 exit(STATE_UNKNOWN);
761 case 'V': /* version */ 752 case 'V': /* version */
762 print_revision (progname, NP_VERSION); 753 print_revision(progname, NP_VERSION);
763 exit (STATE_UNKNOWN); 754 exit(STATE_UNKNOWN);
764 case 'v': /* verbose */ 755 case 'v': /* verbose */
765 verbose++; 756 verbose++;
766 break; 757 break;
767 758
768 /* Connection info */ 759 /* Connection info */
769 case 'C': /* group or community */ 760 case 'C': /* group or community */
770 community = optarg; 761 community = optarg;
771 break; 762 break;
772 case 'H': /* Host or server */ 763 case 'H': /* Host or server */
773 server_address = optarg; 764 server_address = optarg;
774 break; 765 break;
775 case 'p': /* TCP port number */ 766 case 'p': /* TCP port number */
776 port = optarg; 767 port = optarg;
777 break; 768 break;
778 case 'm': /* List of MIBS */ 769 case 'm': /* List of MIBS */
779 miblist = optarg; 770 miblist = optarg;
780 break; 771 break;
781 case 'n': /* usesnmpgetnext */ 772 case 'n': /* usesnmpgetnext */
782 usesnmpgetnext = true; 773 usesnmpgetnext = true;
783 break; 774 break;
784 case 'P': /* SNMP protocol version */ 775 case 'P': /* SNMP protocol version */
785 proto = optarg; 776 proto = optarg;
786 break; 777 break;
787 case 'N': /* SNMPv3 context */ 778 case 'N': /* SNMPv3 context */
788 context = optarg; 779 context = optarg;
789 break; 780 break;
790 case 'L': /* security level */ 781 case 'L': /* security level */
791 seclevel = optarg; 782 seclevel = optarg;
792 break; 783 break;
793 case 'U': /* security username */ 784 case 'U': /* security username */
794 secname = optarg; 785 secname = optarg;
795 break; 786 break;
796 case 'a': /* auth protocol */ 787 case 'a': /* auth protocol */
797 authproto = optarg; 788 authproto = optarg;
798 break; 789 break;
799 case 'x': /* priv protocol */ 790 case 'x': /* priv protocol */
800 privproto = optarg; 791 privproto = optarg;
801 break; 792 break;
802 case 'A': /* auth passwd */ 793 case 'A': /* auth passwd */
803 authpasswd = optarg; 794 authpasswd = optarg;
804 break; 795 break;
805 case 'X': /* priv passwd */ 796 case 'X': /* priv passwd */
806 privpasswd = optarg; 797 privpasswd = optarg;
807 break; 798 break;
808 case 't': /* timeout period */ 799 case 't': /* timeout period */
809 if (!is_integer (optarg)) 800 if (!is_integer(optarg))
810 usage2 (_("Timeout interval must be a positive integer"), optarg); 801 usage2(_("Timeout interval must be a positive integer"), optarg);
811 else 802 else
812 timeout_interval = atoi (optarg); 803 timeout_interval = atoi(optarg);
813 break; 804 break;
814 805
815 /* Test parameters */ 806 /* Test parameters */
816 case 'c': /* critical threshold */ 807 case 'c': /* critical threshold */
817 critical_thresholds = optarg; 808 critical_thresholds = optarg;
818 break; 809 break;
819 case 'w': /* warning threshold */ 810 case 'w': /* warning threshold */
820 warning_thresholds = optarg; 811 warning_thresholds = optarg;
821 break; 812 break;
822 case 'e': /* PRELIMINARY - may change */ 813 case 'e': /* PRELIMINARY - may change */
823 case 'E': /* PRELIMINARY - may change */ 814 case 'E': /* PRELIMINARY - may change */
824 if (!is_integer (optarg)) 815 if (!is_integer(optarg))
825 usage2 (_("Retries interval must be a positive integer"), optarg); 816 usage2(_("Retries interval must be a positive integer"), optarg);
826 else 817 else
827 retries = atoi(optarg); 818 retries = atoi(optarg);
828 break; 819 break;
829 case 'o': /* object identifier */ 820 case 'o': /* object identifier */
830 if ( strspn( optarg, "0123456789.," ) != strlen( optarg ) ) { 821 if (strspn(optarg, "0123456789.,") != strlen(optarg)) {
831 /* 822 /*
832 * we have something other than digits, periods and comas, 823 * we have something other than digits, periods and comas,
833 * so we have a mib variable, rather than just an SNMP OID, 824 * so we have a mib variable, rather than just an SNMP OID,
834 * so we have to actually read the mib files 825 * so we have to actually read the mib files
835 */ 826 */
836 needmibs = true; 827 needmibs = true;
837 } 828 }
838 for (ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) { 829 for (char *ptr = strtok(optarg, ", "); ptr != NULL; ptr = strtok(NULL, ", "), j++) {
839 while (j >= oids_size) { 830 while (j >= oids_size) {
840 oids_size += OID_COUNT_STEP; 831 oids_size += OID_COUNT_STEP;
841 oids = realloc(oids, oids_size * sizeof (*oids)); 832 oids = realloc(oids, oids_size * sizeof(*oids));
842 } 833 }
843 oids[j] = strdup(ptr); 834 oids[j] = strdup(ptr);
844 } 835 }
845 numoids = j; 836 numoids = j;
846 if (c == 'E' || c == 'e') { 837 if (option_char == 'E' || option_char == 'e') {
847 jj++; 838 jj++;
848 while (j+1 >= eval_size) { 839 while (j + 1 >= eval_size) {
849 eval_size += OID_COUNT_STEP; 840 eval_size += OID_COUNT_STEP;
850 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); 841 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
851 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8); 842 memset(eval_method + eval_size - OID_COUNT_STEP, 0, 8);
852 } 843 }
853 if (c == 'E') 844 if (option_char == 'E')
854 eval_method[j+1] |= WARN_PRESENT; 845 eval_method[j + 1] |= WARN_PRESENT;
855 else if (c == 'e') 846 else if (option_char == 'e')
856 eval_method[j+1] |= CRIT_PRESENT; 847 eval_method[j + 1] |= CRIT_PRESENT;
857 } 848 }
858 break; 849 break;
859 case 'z': /* Null OID Return Check */ 850 case 'z': /* Null OID Return Check */
860 if (!is_integer (optarg)) 851 if (!is_integer(optarg))
861 usage2 (_("Exit status must be a positive integer"), optarg); 852 usage2(_("Exit status must be a positive integer"), optarg);
862 else 853 else
863 nulloid = atoi(optarg); 854 nulloid = atoi(optarg);
864 break; 855 break;
865 case 's': /* string or substring */ 856 case 's': /* string or substring */
866 strncpy (string_value, optarg, sizeof (string_value) - 1); 857 strncpy(string_value, optarg, sizeof(string_value) - 1);
867 string_value[sizeof (string_value) - 1] = 0; 858 string_value[sizeof(string_value) - 1] = 0;
868 while (jj >= eval_size) { 859 while (jj >= eval_size) {
869 eval_size += OID_COUNT_STEP; 860 eval_size += OID_COUNT_STEP;
870 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method)); 861 eval_method = realloc(eval_method, eval_size * sizeof(*eval_method));
@@ -872,17 +863,17 @@ process_arguments (int argc, char **argv)
872 } 863 }
873 eval_method[jj++] = CRIT_STRING; 864 eval_method[jj++] = CRIT_STRING;
874 break; 865 break;
875 case 'R': /* regex */ 866 case 'R': /* regex */
876 cflags = REG_ICASE; 867 cflags = REG_ICASE;
877 // fall through 868 // fall through
878 case 'r': /* regex */ 869 case 'r': /* regex */
879 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 870 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
880 strncpy (regex_expect, optarg, sizeof (regex_expect) - 1); 871 strncpy(regex_expect, optarg, sizeof(regex_expect) - 1);
881 regex_expect[sizeof (regex_expect) - 1] = 0; 872 regex_expect[sizeof(regex_expect) - 1] = 0;
882 errcode = regcomp (&preg, regex_expect, cflags); 873 errcode = regcomp(&preg, regex_expect, cflags);
883 if (errcode != 0) { 874 if (errcode != 0) {
884 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 875 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
885 printf (_("Could Not Compile Regular Expression")); 876 printf(_("Could Not Compile Regular Expression"));
886 return ERROR; 877 return ERROR;
887 } 878 }
888 while (jj >= eval_size) { 879 while (jj >= eval_size) {
@@ -893,64 +884,64 @@ process_arguments (int argc, char **argv)
893 eval_method[jj++] = CRIT_REGEX; 884 eval_method[jj++] = CRIT_REGEX;
894 break; 885 break;
895 886
896 /* Format */ 887 /* Format */
897 case 'd': /* delimiter */ 888 case 'd': /* delimiter */
898 delimiter = strscpy (delimiter, optarg); 889 delimiter = strscpy(delimiter, optarg);
899 break; 890 break;
900 case 'D': /* output-delimiter */ 891 case 'D': /* output-delimiter */
901 output_delim = strscpy (output_delim, optarg); 892 output_delim = strscpy(output_delim, optarg);
902 break; 893 break;
903 case 'l': /* label */ 894 case 'l': /* label */
904 nlabels++; 895 nlabels++;
905 if (nlabels > labels_size) { 896 if (nlabels > labels_size) {
906 labels_size += 8; 897 labels_size += 8;
907 labels = realloc (labels, labels_size * sizeof(*labels)); 898 labels = realloc(labels, labels_size * sizeof(*labels));
908 if (labels == NULL) 899 if (labels == NULL)
909 die (STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels); 900 die(STATE_UNKNOWN, _("Could not reallocate labels[%d]"), (int)nlabels);
910 } 901 }
911 labels[nlabels - 1] = optarg; 902 labels[nlabels - 1] = optarg;
912 ptr = thisarg (optarg); 903 char *ptr = thisarg(optarg);
913 labels[nlabels - 1] = ptr; 904 labels[nlabels - 1] = ptr;
914 if (ptr[0] == '\'') 905 if (ptr[0] == '\'')
915 labels[nlabels - 1] = ptr + 1; 906 labels[nlabels - 1] = ptr + 1;
916 while (ptr && (ptr = nextarg (ptr))) { 907 while (ptr && (ptr = nextarg(ptr))) {
917 nlabels++; 908 nlabels++;
918 if (nlabels > labels_size) { 909 if (nlabels > labels_size) {
919 labels_size += 8; 910 labels_size += 8;
920 labels = realloc (labels, labels_size * sizeof(*labels)); 911 labels = realloc(labels, labels_size * sizeof(*labels));
921 if (labels == NULL) 912 if (labels == NULL)
922 die (STATE_UNKNOWN, _("Could not reallocate labels\n")); 913 die(STATE_UNKNOWN, _("Could not reallocate labels\n"));
923 } 914 }
924 ptr = thisarg (ptr); 915 ptr = thisarg(ptr);
925 if (ptr[0] == '\'') 916 if (ptr[0] == '\'')
926 labels[nlabels - 1] = ptr + 1; 917 labels[nlabels - 1] = ptr + 1;
927 else 918 else
928 labels[nlabels - 1] = ptr; 919 labels[nlabels - 1] = ptr;
929 } 920 }
930 break; 921 break;
931 case 'u': /* units */ 922 case 'u': /* units */
932 units = optarg; 923 units = optarg;
933 nunits++; 924 nunits++;
934 if (nunits > unitv_size) { 925 if (nunits > unitv_size) {
935 unitv_size += 8; 926 unitv_size += 8;
936 unitv = realloc (unitv, unitv_size * sizeof(*unitv)); 927 unitv = realloc(unitv, unitv_size * sizeof(*unitv));
937 if (unitv == NULL) 928 if (unitv == NULL)
938 die (STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits); 929 die(STATE_UNKNOWN, _("Could not reallocate units [%d]\n"), (int)nunits);
939 } 930 }
940 unitv[nunits - 1] = optarg; 931 unitv[nunits - 1] = optarg;
941 ptr = thisarg (optarg); 932 ptr = thisarg(optarg);
942 unitv[nunits - 1] = ptr; 933 unitv[nunits - 1] = ptr;
943 if (ptr[0] == '\'') 934 if (ptr[0] == '\'')
944 unitv[nunits - 1] = ptr + 1; 935 unitv[nunits - 1] = ptr + 1;
945 while (ptr && (ptr = nextarg (ptr))) { 936 while (ptr && (ptr = nextarg(ptr))) {
946 if (nunits > unitv_size) { 937 if (nunits > unitv_size) {
947 unitv_size += 8; 938 unitv_size += 8;
948 unitv = realloc (unitv, unitv_size * sizeof(*unitv)); 939 unitv = realloc(unitv, unitv_size * sizeof(*unitv));
949 if (units == NULL) 940 if (units == NULL)
950 die (STATE_UNKNOWN, _("Could not realloc() units\n")); 941 die(STATE_UNKNOWN, _("Could not realloc() units\n"));
951 } 942 }
952 nunits++; 943 nunits++;
953 ptr = thisarg (ptr); 944 ptr = thisarg(ptr);
954 if (ptr[0] == '\'') 945 if (ptr[0] == '\'')
955 unitv[nunits - 1] = ptr + 1; 946 unitv[nunits - 1] = ptr + 1;
956 else 947 else
@@ -958,38 +949,38 @@ process_arguments (int argc, char **argv)
958 } 949 }
959 break; 950 break;
960 case L_CALCULATE_RATE: 951 case L_CALCULATE_RATE:
961 if(calculate_rate==0) 952 if (calculate_rate == 0)
962 np_enable_state(NULL, 1); 953 np_enable_state(NULL, 1);
963 calculate_rate = 1; 954 calculate_rate = 1;
964 break; 955 break;
965 case L_RATE_MULTIPLIER: 956 case L_RATE_MULTIPLIER:
966 if(!is_integer(optarg)||((rate_multiplier=atoi(optarg))<=0)) 957 if (!is_integer(optarg) || ((rate_multiplier = atoi(optarg)) <= 0))
967 usage2(_("Rate multiplier must be a positive integer"),optarg); 958 usage2(_("Rate multiplier must be a positive integer"), optarg);
968 break; 959 break;
969 case L_OFFSET: 960 case L_OFFSET:
970 offset=strtod(optarg,NULL); 961 offset = strtod(optarg, NULL);
971 break; 962 break;
972 case L_INVERT_SEARCH: 963 case L_INVERT_SEARCH:
973 invert_search=1; 964 invert_search = 1;
974 break; 965 break;
975 case 'O': 966 case 'O':
976 perf_labels=0; 967 perf_labels = 0;
977 break; 968 break;
978 case '4': 969 case '4':
979 break; 970 break;
980 case '6': 971 case '6':
981 xasprintf(&ip_version, "udp6:"); 972 xasprintf(&ip_version, "udp6:");
982 if(verbose>2) 973 if (verbose > 2)
983 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n"); 974 printf("IPv6 detected! Will pass \"udp6:\" to snmpget.\n");
984 break; 975 break;
985 case 'M': 976 case 'M':
986 if ( strspn( optarg, "0123456789.," ) == strlen( optarg ) ) { 977 if (strspn(optarg, "0123456789.,") == strlen(optarg)) {
987 multiplier=strtod(optarg,NULL); 978 multiplier = strtod(optarg, NULL);
988 } 979 }
989 break; 980 break;
990 case 'f': 981 case 'f':
991 if (multiplier != 1.0) { 982 if (multiplier != 1.0) {
992 fmtstr=optarg; 983 fmtstr = optarg;
993 fmtstr_set = true; 984 fmtstr_set = true;
994 } 985 }
995 break; 986 break;
@@ -1002,12 +993,11 @@ process_arguments (int argc, char **argv)
1002 server_address = argv[optind]; 993 server_address = argv[optind];
1003 994
1004 if (community == NULL) 995 if (community == NULL)
1005 community = strdup (DEFAULT_COMMUNITY); 996 community = strdup(DEFAULT_COMMUNITY);
1006 997
1007 return validate_arguments (); 998 return validate_arguments();
1008} 999}
1009 1000
1010
1011/****************************************************************************** 1001/******************************************************************************
1012 1002
1013@@- 1003@@-
@@ -1026,17 +1016,13 @@ selected.</para>
1026-@@ 1016-@@
1027******************************************************************************/ 1017******************************************************************************/
1028 1018
1029 1019static int validate_arguments() {
1030
1031static int
1032validate_arguments ()
1033{
1034 /* check whether to load locally installed MIBS (CPU/disk intensive) */ 1020 /* check whether to load locally installed MIBS (CPU/disk intensive) */
1035 if (miblist == NULL) { 1021 if (miblist == NULL) {
1036 if (needmibs) { 1022 if (needmibs) {
1037 miblist = strdup (DEFAULT_MIBLIST); 1023 miblist = strdup(DEFAULT_MIBLIST);
1038 }else{ 1024 } else {
1039 miblist = ""; /* don't read any mib files for numeric oids */ 1025 miblist = ""; /* don't read any mib files for numeric oids */
1040 } 1026 }
1041 } 1027 }
1042 1028
@@ -1051,18 +1037,17 @@ validate_arguments ()
1051 if (proto == NULL) 1037 if (proto == NULL)
1052 xasprintf(&proto, DEFAULT_PROTOCOL); 1038 xasprintf(&proto, DEFAULT_PROTOCOL);
1053 1039
1054 if ((strcmp(proto,"1") == 0) || (strcmp(proto, "2c")==0)) { /* snmpv1 or snmpv2c */ 1040 if ((strcmp(proto, "1") == 0) || (strcmp(proto, "2c") == 0)) { /* snmpv1 or snmpv2c */
1055 numauthpriv = 2; 1041 numauthpriv = 2;
1056 authpriv = calloc (numauthpriv, sizeof (char *)); 1042 authpriv = calloc(numauthpriv, sizeof(char *));
1057 authpriv[0] = strdup ("-c"); 1043 authpriv[0] = strdup("-c");
1058 authpriv[1] = strdup (community); 1044 authpriv[1] = strdup(community);
1059 } 1045 } else if (strcmp(proto, "3") == 0) { /* snmpv3 args */
1060 else if ( strcmp (proto, "3") == 0 ) { /* snmpv3 args */
1061 if (!(context == NULL)) { 1046 if (!(context == NULL)) {
1062 numcontext = 2; 1047 numcontext = 2;
1063 contextargs = calloc (numcontext, sizeof (char *)); 1048 contextargs = calloc(numcontext, sizeof(char *));
1064 contextargs[0] = strdup ("-n"); 1049 contextargs[0] = strdup("-n");
1065 contextargs[1] = strdup (context); 1050 contextargs[1] = strdup(context);
1066 } 1051 }
1067 1052
1068 if (seclevel == NULL) 1053 if (seclevel == NULL)
@@ -1073,284 +1058,266 @@ validate_arguments ()
1073 1058
1074 if (strcmp(seclevel, "noAuthNoPriv") == 0) { 1059 if (strcmp(seclevel, "noAuthNoPriv") == 0) {
1075 numauthpriv = 4; 1060 numauthpriv = 4;
1076 authpriv = calloc (numauthpriv, sizeof (char *)); 1061 authpriv = calloc(numauthpriv, sizeof(char *));
1077 authpriv[0] = strdup ("-l"); 1062 authpriv[0] = strdup("-l");
1078 authpriv[1] = strdup ("noAuthNoPriv"); 1063 authpriv[1] = strdup("noAuthNoPriv");
1079 authpriv[2] = strdup ("-u"); 1064 authpriv[2] = strdup("-u");
1080 authpriv[3] = strdup (secname); 1065 authpriv[3] = strdup(secname);
1081 } else { 1066 } else {
1082 if (! ( (strcmp(seclevel, "authNoPriv")==0) || (strcmp(seclevel, "authPriv")==0) ) ) { 1067 if (!((strcmp(seclevel, "authNoPriv") == 0) || (strcmp(seclevel, "authPriv") == 0))) {
1083 usage2 (_("Invalid seclevel"), seclevel); 1068 usage2(_("Invalid seclevel"), seclevel);
1084 } 1069 }
1085 1070
1086 if (authproto == NULL ) 1071 if (authproto == NULL)
1087 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL); 1072 xasprintf(&authproto, DEFAULT_AUTH_PROTOCOL);
1088 1073
1089 if (authpasswd == NULL) 1074 if (authpasswd == NULL)
1090 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd"); 1075 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "authpasswd");
1091 1076
1092 if ( strcmp(seclevel, "authNoPriv") == 0 ) { 1077 if (strcmp(seclevel, "authNoPriv") == 0) {
1093 numauthpriv = 8; 1078 numauthpriv = 8;
1094 authpriv = calloc (numauthpriv, sizeof (char *)); 1079 authpriv = calloc(numauthpriv, sizeof(char *));
1095 authpriv[0] = strdup ("-l"); 1080 authpriv[0] = strdup("-l");
1096 authpriv[1] = strdup ("authNoPriv"); 1081 authpriv[1] = strdup("authNoPriv");
1097 authpriv[2] = strdup ("-a"); 1082 authpriv[2] = strdup("-a");
1098 authpriv[3] = strdup (authproto); 1083 authpriv[3] = strdup(authproto);
1099 authpriv[4] = strdup ("-u"); 1084 authpriv[4] = strdup("-u");
1100 authpriv[5] = strdup (secname); 1085 authpriv[5] = strdup(secname);
1101 authpriv[6] = strdup ("-A"); 1086 authpriv[6] = strdup("-A");
1102 authpriv[7] = strdup (authpasswd); 1087 authpriv[7] = strdup(authpasswd);
1103 } else if ( strcmp(seclevel, "authPriv") == 0 ) { 1088 } else if (strcmp(seclevel, "authPriv") == 0) {
1104 if (privproto == NULL ) 1089 if (privproto == NULL)
1105 xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL); 1090 xasprintf(&privproto, DEFAULT_PRIV_PROTOCOL);
1106 1091
1107 if (privpasswd == NULL) 1092 if (privpasswd == NULL)
1108 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd"); 1093 die(STATE_UNKNOWN, _("Required parameter: %s\n"), "privpasswd");
1109 1094
1110 numauthpriv = 12; 1095 numauthpriv = 12;
1111 authpriv = calloc (numauthpriv, sizeof (char *)); 1096 authpriv = calloc(numauthpriv, sizeof(char *));
1112 authpriv[0] = strdup ("-l"); 1097 authpriv[0] = strdup("-l");
1113 authpriv[1] = strdup ("authPriv"); 1098 authpriv[1] = strdup("authPriv");
1114 authpriv[2] = strdup ("-a"); 1099 authpriv[2] = strdup("-a");
1115 authpriv[3] = strdup (authproto); 1100 authpriv[3] = strdup(authproto);
1116 authpriv[4] = strdup ("-u"); 1101 authpriv[4] = strdup("-u");
1117 authpriv[5] = strdup (secname); 1102 authpriv[5] = strdup(secname);
1118 authpriv[6] = strdup ("-A"); 1103 authpriv[6] = strdup("-A");
1119 authpriv[7] = strdup (authpasswd); 1104 authpriv[7] = strdup(authpasswd);
1120 authpriv[8] = strdup ("-x"); 1105 authpriv[8] = strdup("-x");
1121 authpriv[9] = strdup (privproto); 1106 authpriv[9] = strdup(privproto);
1122 authpriv[10] = strdup ("-X"); 1107 authpriv[10] = strdup("-X");
1123 authpriv[11] = strdup (privpasswd); 1108 authpriv[11] = strdup(privpasswd);
1124 } 1109 }
1125 } 1110 }
1126 1111
1127 } 1112 } else {
1128 else { 1113 usage2(_("Invalid SNMP version"), proto);
1129 usage2 (_("Invalid SNMP version"), proto);
1130 } 1114 }
1131 1115
1132 return OK; 1116 return OK;
1133} 1117}
1134 1118
1135
1136
1137/* trim leading whitespace 1119/* trim leading whitespace
1138 if there is a leading quote, make sure it balances */ 1120 if there is a leading quote, make sure it balances */
1139 1121
1140static char * 1122static char *thisarg(char *str) {
1141thisarg (char *str) 1123 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
1142{ 1124 if (str[0] == '\'') { /* handle SIMPLE quoted strings */
1143 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 1125 if (strlen(str) == 1 || !strstr(str + 1, "'"))
1144 if (str[0] == '\'') { /* handle SIMPLE quoted strings */ 1126 die(STATE_UNKNOWN, _("Unbalanced quotes\n"));
1145 if (strlen (str) == 1 || !strstr (str + 1, "'"))
1146 die (STATE_UNKNOWN, _("Unbalanced quotes\n"));
1147 } 1127 }
1148 return str; 1128 return str;
1149} 1129}
1150 1130
1151
1152
1153/* if there's a leading quote, advance to the trailing quote 1131/* if there's a leading quote, advance to the trailing quote
1154 set the trailing quote to '\x0' 1132 set the trailing quote to '\x0'
1155 if the string continues, advance beyond the comma */ 1133 if the string continues, advance beyond the comma */
1156 1134
1157static char * 1135static char *nextarg(char *str) {
1158nextarg (char *str)
1159{
1160 if (str[0] == '\'') { 1136 if (str[0] == '\'') {
1161 str[0] = 0; 1137 str[0] = 0;
1162 if (strlen (str) > 1) { 1138 if (strlen(str) > 1) {
1163 str = strstr (str + 1, "'"); 1139 str = strstr(str + 1, "'");
1164 return (++str); 1140 return (++str);
1165 } 1141 } else {
1166 else {
1167 return NULL; 1142 return NULL;
1168 } 1143 }
1169 } 1144 }
1170 if (str[0] == ',') { 1145 if (str[0] == ',') {
1171 str[0] = 0; 1146 str[0] = 0;
1172 if (strlen (str) > 1) { 1147 if (strlen(str) > 1) {
1173 return (++str); 1148 return (++str);
1174 } 1149 } else {
1175 else {
1176 return NULL; 1150 return NULL;
1177 } 1151 }
1178 } 1152 }
1179 if ((str = strstr (str, ",")) && strlen (str) > 1) { 1153 if ((str = strstr(str, ",")) && strlen(str) > 1) {
1180 str[0] = 0; 1154 str[0] = 0;
1181 return (++str); 1155 return (++str);
1182 } 1156 }
1183 return NULL; 1157 return NULL;
1184} 1158}
1185 1159
1186
1187
1188/* multiply result (values 0 < n < 1 work as divider) */ 1160/* multiply result (values 0 < n < 1 work as divider) */
1189static char * 1161static char *multiply(char *str) {
1190multiply (char *str) 1162 if (multiplier == 1)
1191{ 1163 return (str);
1192 char *endptr;
1193 double val;
1194 char *conv = "%f";
1195
1196 if(multiplier == 1)
1197 return(str);
1198 1164
1199 if(verbose>2) 1165 if (verbose > 2)
1200 printf(" multiply input: %s\n", str); 1166 printf(" multiply input: %s\n", str);
1201 1167
1202 val = strtod (str, &endptr); 1168 char *endptr;
1169 double val = strtod(str, &endptr);
1203 if ((val == 0.0) && (endptr == str)) { 1170 if ((val == 0.0) && (endptr == str)) {
1204 die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str); 1171 die(STATE_UNKNOWN, _("multiplier set (%.1f), but input is not a number: %s"), multiplier, str);
1205 } 1172 }
1206 1173
1207 if(verbose>2) 1174 if (verbose > 2)
1208 printf(" multiply extracted double: %f\n", val); 1175 printf(" multiply extracted double: %f\n", val);
1176
1209 val *= multiplier; 1177 val *= multiplier;
1178 char *conv = "%f";
1210 if (fmtstr_set) { 1179 if (fmtstr_set) {
1211 conv = fmtstr; 1180 conv = fmtstr;
1212 } 1181 }
1213 if (val == (int)val) { 1182 if (val == (int)val) {
1214 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val); 1183 snprintf(buffer, DEFAULT_BUFFER_SIZE, "%.0f", val);
1215 } else { 1184 } else {
1216 if(verbose>2) 1185 if (verbose > 2)
1217 printf(" multiply using format: %s\n", conv); 1186 printf(" multiply using format: %s\n", conv);
1218 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val); 1187 snprintf(buffer, DEFAULT_BUFFER_SIZE, conv, val);
1219 } 1188 }
1220 if(verbose>2) 1189 if (verbose > 2)
1221 printf(" multiply result: %s\n", buffer); 1190 printf(" multiply result: %s\n", buffer);
1222 return buffer; 1191 return buffer;
1223} 1192}
1224 1193
1194static void print_help(void) {
1195 print_revision(progname, NP_VERSION);
1225 1196
1226static void 1197 printf(COPYRIGHT, copyright, email);
1227print_help (void)
1228{
1229 print_revision (progname, NP_VERSION);
1230
1231 printf (COPYRIGHT, copyright, email);
1232 1198
1233 printf ("%s\n", _("Check status of remote machines and obtain system information via SNMP")); 1199 printf("%s\n", _("Check status of remote machines and obtain system information via SNMP"));
1234 1200
1235 printf ("\n\n"); 1201 printf("\n\n");
1236 1202
1237 print_usage (); 1203 print_usage();
1238 1204
1239 printf (UT_HELP_VRSN); 1205 printf(UT_HELP_VRSN);
1240 printf (UT_EXTRA_OPTS); 1206 printf(UT_EXTRA_OPTS);
1241 printf (UT_IPv46); 1207 printf(UT_IPv46);
1242 1208
1243 printf (UT_HOST_PORT, 'p', DEFAULT_PORT); 1209 printf(UT_HOST_PORT, 'p', DEFAULT_PORT);
1244 1210
1245 /* SNMP and Authentication Protocol */ 1211 /* SNMP and Authentication Protocol */
1246 printf (" %s\n", "-n, --next"); 1212 printf(" %s\n", "-n, --next");
1247 printf (" %s\n", _("Use SNMP GETNEXT instead of SNMP GET")); 1213 printf(" %s\n", _("Use SNMP GETNEXT instead of SNMP GET"));
1248 printf (" %s\n", "-P, --protocol=[1|2c|3]"); 1214 printf(" %s\n", "-P, --protocol=[1|2c|3]");
1249 printf (" %s\n", _("SNMP protocol version")); 1215 printf(" %s\n", _("SNMP protocol version"));
1250 printf (" %s\n", "-N, --context=CONTEXT"); 1216 printf(" %s\n", "-N, --context=CONTEXT");
1251 printf (" %s\n", _("SNMPv3 context")); 1217 printf(" %s\n", _("SNMPv3 context"));
1252 printf (" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]"); 1218 printf(" %s\n", "-L, --seclevel=[noAuthNoPriv|authNoPriv|authPriv]");
1253 printf (" %s\n", _("SNMPv3 securityLevel")); 1219 printf(" %s\n", _("SNMPv3 securityLevel"));
1254 printf (" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL"); 1220 printf(" %s\n", "-a, --authproto=AUTHENTICATION_PROTOCOL");
1255 printf (" %s\n", _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools")); 1221 printf(" %s\n",
1256 printf (" %s\n", _("if < 5.8 SHA (1) and MD5 should be available, if >= 5.8 additionally SHA-224, SHA-256, SHA-384 and SHA-512")); 1222 _("SNMPv3 authentication protocol (default MD5), available options depend on the specific version of the net-snmp tools"));
1257 printf (" %s\n", "-x, --privproto=PRIVACY_PROTOCOL"); 1223 printf(" %s\n", _("if < 5.8 SHA (1) and MD5 should be available, if >= 5.8 additionally SHA-224, SHA-256, SHA-384 and SHA-512"));
1258 printf (" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools")); 1224 printf(" %s\n", "-x, --privproto=PRIVACY_PROTOCOL");
1259 printf (" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256")); 1225 printf(" %s\n", _("SNMPv3 privacy protocol (default DES), available options depend on the specific version of the net-snmp tools"));
1226 printf(" %s\n", _("if < 5.8 DES and AES should be available, if >= 5.8 additionally AES-192 and AES-256"));
1260 1227
1261 /* Authentication Tokens*/ 1228 /* Authentication Tokens*/
1262 printf (" %s\n", "-C, --community=STRING"); 1229 printf(" %s\n", "-C, --community=STRING");
1263 printf (" %s ", _("Optional community string for SNMP communication")); 1230 printf(" %s ", _("Optional community string for SNMP communication"));
1264 printf ("(%s \"%s\")\n", _("default is") ,DEFAULT_COMMUNITY); 1231 printf("(%s \"%s\")\n", _("default is"), DEFAULT_COMMUNITY);
1265 printf (" %s\n", "-U, --secname=USERNAME"); 1232 printf(" %s\n", "-U, --secname=USERNAME");
1266 printf (" %s\n", _("SNMPv3 username")); 1233 printf(" %s\n", _("SNMPv3 username"));
1267 printf (" %s\n", "-A, --authpasswd=PASSWORD"); 1234 printf(" %s\n", "-A, --authpasswd=PASSWORD");
1268 printf (" %s\n", _("SNMPv3 authentication password")); 1235 printf(" %s\n", _("SNMPv3 authentication password"));
1269 printf (" %s\n", "-X, --privpasswd=PASSWORD"); 1236 printf(" %s\n", "-X, --privpasswd=PASSWORD");
1270 printf (" %s\n", _("SNMPv3 privacy password")); 1237 printf(" %s\n", _("SNMPv3 privacy password"));
1271 1238
1272 /* OID Stuff */ 1239 /* OID Stuff */
1273 printf (" %s\n", "-o, --oid=OID(s)"); 1240 printf(" %s\n", "-o, --oid=OID(s)");
1274 printf (" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query")); 1241 printf(" %s\n", _("Object identifier(s) or SNMP variables whose value you wish to query"));
1275 printf (" %s\n", "-m, --miblist=STRING"); 1242 printf(" %s\n", "-m, --miblist=STRING");
1276 printf (" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'")); 1243 printf(" %s\n", _("List of MIBS to be loaded (default = none if using numeric OIDs or 'ALL'"));
1277 printf (" %s\n", _("for symbolic OIDs.)")); 1244 printf(" %s\n", _("for symbolic OIDs.)"));
1278 printf (" %s\n", "-d, --delimiter=STRING"); 1245 printf(" %s\n", "-d, --delimiter=STRING");
1279 printf (" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER); 1246 printf(" %s \"%s\"\n", _("Delimiter to use when parsing returned data. Default is"), DEFAULT_DELIMITER);
1280 printf (" %s\n", _("Any data on the right hand side of the delimiter is considered")); 1247 printf(" %s\n", _("Any data on the right hand side of the delimiter is considered"));
1281 printf (" %s\n", _("to be the data that should be used in the evaluation.")); 1248 printf(" %s\n", _("to be the data that should be used in the evaluation."));
1282 printf (" %s\n", "-z, --nulloid=#"); 1249 printf(" %s\n", "-z, --nulloid=#");
1283 printf (" %s\n", _("If the check returns a 0 length string or NULL value")); 1250 printf(" %s\n", _("If the check returns a 0 length string or NULL value"));
1284 printf (" %s\n", _("This option allows you to choose what status you want it to exit")); 1251 printf(" %s\n", _("This option allows you to choose what status you want it to exit"));
1285 printf (" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)")); 1252 printf(" %s\n", _("Excluding this option renders the default exit of 3(STATE_UNKNOWN)"));
1286 printf (" %s\n", _("0 = OK")); 1253 printf(" %s\n", _("0 = OK"));
1287 printf (" %s\n", _("1 = WARNING")); 1254 printf(" %s\n", _("1 = WARNING"));
1288 printf (" %s\n", _("2 = CRITICAL")); 1255 printf(" %s\n", _("2 = CRITICAL"));
1289 printf (" %s\n", _("3 = UNKNOWN")); 1256 printf(" %s\n", _("3 = UNKNOWN"));
1290 1257
1291 /* Tests Against Integers */ 1258 /* Tests Against Integers */
1292 printf (" %s\n", "-w, --warning=THRESHOLD(s)"); 1259 printf(" %s\n", "-w, --warning=THRESHOLD(s)");
1293 printf (" %s\n", _("Warning threshold range(s)")); 1260 printf(" %s\n", _("Warning threshold range(s)"));
1294 printf (" %s\n", "-c, --critical=THRESHOLD(s)"); 1261 printf(" %s\n", "-c, --critical=THRESHOLD(s)");
1295 printf (" %s\n", _("Critical threshold range(s)")); 1262 printf(" %s\n", _("Critical threshold range(s)"));
1296 printf (" %s\n", "--rate"); 1263 printf(" %s\n", "--rate");
1297 printf (" %s\n", _("Enable rate calculation. See 'Rate Calculation' below")); 1264 printf(" %s\n", _("Enable rate calculation. See 'Rate Calculation' below"));
1298 printf (" %s\n", "--rate-multiplier"); 1265 printf(" %s\n", "--rate-multiplier");
1299 printf (" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute")); 1266 printf(" %s\n", _("Converts rate per second. For example, set to 60 to convert to per minute"));
1300 printf (" %s\n", "--offset=OFFSET"); 1267 printf(" %s\n", "--offset=OFFSET");
1301 printf (" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data")); 1268 printf(" %s\n", _("Add/subtract the specified OFFSET to numeric sensor data"));
1302 1269
1303 /* Tests Against Strings */ 1270 /* Tests Against Strings */
1304 printf (" %s\n", "-s, --string=STRING"); 1271 printf(" %s\n", "-s, --string=STRING");
1305 printf (" %s\n", _("Return OK state (for that OID) if STRING is an exact match")); 1272 printf(" %s\n", _("Return OK state (for that OID) if STRING is an exact match"));
1306 printf (" %s\n", "-r, --ereg=REGEX"); 1273 printf(" %s\n", "-r, --ereg=REGEX");
1307 printf (" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches")); 1274 printf(" %s\n", _("Return OK state (for that OID) if extended regular expression REGEX matches"));
1308 printf (" %s\n", "-R, --eregi=REGEX"); 1275 printf(" %s\n", "-R, --eregi=REGEX");
1309 printf (" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches")); 1276 printf(" %s\n", _("Return OK state (for that OID) if case-insensitive extended REGEX matches"));
1310 printf (" %s\n", "--invert-search"); 1277 printf(" %s\n", "--invert-search");
1311 printf (" %s\n", _("Invert search result (CRITICAL if found)")); 1278 printf(" %s\n", _("Invert search result (CRITICAL if found)"));
1312 1279
1313 /* Output Formatting */ 1280 /* Output Formatting */
1314 printf (" %s\n", "-l, --label=STRING"); 1281 printf(" %s\n", "-l, --label=STRING");
1315 printf (" %s\n", _("Prefix label for output from plugin")); 1282 printf(" %s\n", _("Prefix label for output from plugin"));
1316 printf (" %s\n", "-u, --units=STRING"); 1283 printf(" %s\n", "-u, --units=STRING");
1317 printf (" %s\n", _("Units label(s) for output data (e.g., 'sec.').")); 1284 printf(" %s\n", _("Units label(s) for output data (e.g., 'sec.')."));
1318 printf (" %s\n", "-D, --output-delimiter=STRING"); 1285 printf(" %s\n", "-D, --output-delimiter=STRING");
1319 printf (" %s\n", _("Separates output on multiple OID requests")); 1286 printf(" %s\n", _("Separates output on multiple OID requests"));
1320 printf (" %s\n", "-M, --multiplier=FLOAT"); 1287 printf(" %s\n", "-M, --multiplier=FLOAT");
1321 printf (" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1")); 1288 printf(" %s\n", _("Multiplies current value, 0 < n < 1 works as divider, defaults to 1"));
1322 printf (" %s\n", "-f, --fmtstr=STRING"); 1289 printf(" %s\n", "-f, --fmtstr=STRING");
1323 printf (" %s\n", _("C-style format string for float values (see option -M)")); 1290 printf(" %s\n", _("C-style format string for float values (see option -M)"));
1324 1291
1325 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 1292 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
1326 printf (" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5")); 1293 printf(" %s\n", _("NOTE the final timeout value is calculated using this formula: timeout_interval * retries + 5"));
1327 printf (" %s\n", "-e, --retries=INTEGER"); 1294 printf(" %s\n", "-e, --retries=INTEGER");
1328 printf (" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES); 1295 printf(" %s%i\n", _("Number of retries to be used in the requests, default: "), DEFAULT_RETRIES);
1329 1296
1330 printf (" %s\n", "-O, --perf-oids"); 1297 printf(" %s\n", "-O, --perf-oids");
1331 printf (" %s\n", _("Label performance data with OIDs instead of --label's")); 1298 printf(" %s\n", _("Label performance data with OIDs instead of --label's"));
1332 1299
1333 printf (" %s\n", "--ignore-mib-parsing-errors"); 1300 printf(" %s\n", "--ignore-mib-parsing-errors");
1334 printf (" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files")); 1301 printf(" %s\n", _("Tell snmpget to not print errors encountered when parsing MIB files"));
1335 1302
1336 printf (UT_VERBOSE); 1303 printf(UT_VERBOSE);
1337 1304
1338 printf ("\n"); 1305 printf("\n");
1339 printf ("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package.")); 1306 printf("%s\n", _("This plugin uses the 'snmpget' command included with the NET-SNMP package."));
1340 printf ("%s\n", _("if you don't have the package installed, you will need to download it from")); 1307 printf("%s\n", _("if you don't have the package installed, you will need to download it from"));
1341 printf ("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin.")); 1308 printf("%s\n", _("http://net-snmp.sourceforge.net before you can use this plugin."));
1342 1309
1343 printf ("\n"); 1310 printf("\n");
1344 printf ("%s\n", _("Notes:")); 1311 printf("%s\n", _("Notes:"));
1345 printf (" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited ")); 1312 printf(" %s\n", _("- Multiple OIDs (and labels) may be indicated by a comma or space-delimited "));
1346 printf (" %s\n", _("list (lists with internal spaces must be quoted).")); 1313 printf(" %s\n", _("list (lists with internal spaces must be quoted)."));
1347 1314
1348 printf(" -%s", UT_THRESHOLDS_NOTES); 1315 printf(" -%s", UT_THRESHOLDS_NOTES);
1349 1316
1350 printf (" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'")); 1317 printf(" %s\n", _("- When checking multiple OIDs, separate ranges by commas like '-w 1:10,1:,:20'"));
1351 printf (" %s\n", _("- Note that only one string and one regex may be checked at present")); 1318 printf(" %s\n", _("- Note that only one string and one regex may be checked at present"));
1352 printf (" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value")); 1319 printf(" %s\n", _("- All evaluation methods other than PR, STR, and SUBSTR expect that the value"));
1353 printf (" %s\n", _("returned from the SNMP query is an unsigned integer.")); 1320 printf(" %s\n", _("returned from the SNMP query is an unsigned integer."));
1354 1321
1355 printf("\n"); 1322 printf("\n");
1356 printf("%s\n", _("Rate Calculation:")); 1323 printf("%s\n", _("Rate Calculation:"));
@@ -1362,19 +1329,15 @@ print_help (void)
1362 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so")); 1329 printf(" %s\n", _("The state is uniquely determined by the arguments to the plugin, so"));
1363 printf(" %s\n", _("changing the arguments will create a new state file.")); 1330 printf(" %s\n", _("changing the arguments will create a new state file."));
1364 1331
1365 printf (UT_SUPPORT); 1332 printf(UT_SUPPORT);
1366} 1333}
1367 1334
1368 1335void print_usage(void) {
1369 1336 printf("%s\n", _("Usage:"));
1370void 1337 printf("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n", progname);
1371print_usage (void) 1338 printf("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n");
1372{ 1339 printf("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1373 printf ("%s\n", _("Usage:")); 1340 printf("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1374 printf ("%s -H <ip_address> -o <OID> [-w warn_range] [-c crit_range]\n",progname); 1341 printf("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1375 printf ("[-C community] [-s string] [-r regex] [-R regexi] [-t timeout] [-e retries]\n"); 1342 printf("[-M multiplier [-f format]]\n");
1376 printf ("[-l label] [-u units] [-p port-number] [-d delimiter] [-D output-delimiter]\n");
1377 printf ("[-m miblist] [-P snmp version] [-N context] [-L seclevel] [-U secname]\n");
1378 printf ("[-a authproto] [-A authpasswd] [-x privproto] [-X privpasswd] [-4|6]\n");
1379 printf ("[-M multiplier [-f format]]\n");
1380} 1343}
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 34ef37b7..9d0d7cde 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -1,144 +1,158 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ssh plugin 3 * Monitoring check_ssh plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_ssh plugin 10 * This file contains the check_ssh plugin
11* 11 *
12* Try to connect to an SSH server at specified server and port 12 * Try to connect to an SSH server at specified server and port
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "output.h"
32#include "perfdata.h"
33#include "states.h"
31const char *progname = "check_ssh"; 34const char *progname = "check_ssh";
32const char *copyright = "2000-2007"; 35const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 36const char *email = "devel@monitoring-plugins.org";
34 37
35#include "./common.h" 38#include "./common.h"
36#include "./netutils.h" 39#include "./netutils.h"
37#include "utils.h" 40#include "utils.h"
41#include "./check_ssh.d/config.h"
38 42
39#ifndef MSG_DONTWAIT 43#ifndef MSG_DONTWAIT
40#define MSG_DONTWAIT 0 44# define MSG_DONTWAIT 0
41#endif 45#endif
42 46
43#define SSH_DFL_PORT 22 47#define BUFF_SZ 256
44#define BUFF_SZ 256
45
46int port = -1;
47char *server_name = NULL;
48char *remote_version = NULL;
49char *remote_protocol = NULL;
50bool verbose = false;
51 48
52int process_arguments (int, char **); 49static bool verbose = false;
53int validate_arguments (void);
54void print_help (void);
55void print_usage (void);
56 50
57int ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol); 51typedef struct process_arguments_wrapper {
52 int errorcode;
53 check_ssh_config config;
54} process_arguments_wrapper;
58 55
56static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
57static void print_help(void);
58void print_usage(void);
59 59
60int 60static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version, char *remote_protocol);
61main (int argc, char **argv)
62{
63 int result = STATE_UNKNOWN;
64 61
65 setlocale (LC_ALL, ""); 62int main(int argc, char **argv) {
66 bindtextdomain (PACKAGE, LOCALEDIR); 63 setlocale(LC_ALL, "");
67 textdomain (PACKAGE); 64 bindtextdomain(PACKAGE, LOCALEDIR);
65 textdomain(PACKAGE);
68 66
69 /* Parse extra opts if any */ 67 /* Parse extra opts if any */
70 argv=np_extra_opts (&argc, argv, progname); 68 argv = np_extra_opts(&argc, argv, progname);
71 69
72 if (process_arguments (argc, argv) == ERROR) 70 process_arguments_wrapper tmp_config = process_arguments(argc, argv);
73 usage4 (_("Could not parse arguments"));
74 71
75 /* initialize alarm signal handling */ 72 if (tmp_config.errorcode == ERROR) {
76 signal (SIGALRM, socket_timeout_alarm_handler); 73 usage4(_("Could not parse arguments"));
74 }
75
76 check_ssh_config config = tmp_config.config;
77
78 mp_check overall = mp_check_init();
79 if (config.output_format_is_set) {
80 mp_set_format(config.output_format);
81 }
77 82
78 alarm (socket_timeout); 83 /* initialize alarm signal handling */
84 signal(SIGALRM, socket_timeout_alarm_handler);
85 alarm(socket_timeout);
79 86
80 /* ssh_connect exits if error is found */ 87 /* ssh_connect exits if error is found */
81 result = ssh_connect (server_name, port, remote_version, remote_protocol); 88 ssh_connect(&overall, config.server_name, config.port, config.remote_version, config.remote_protocol);
82 89
83 alarm (0); 90 alarm(0);
84 91
85 return (result); 92 mp_exit(overall);
86} 93}
87 94
88 95#define output_format_index CHAR_MAX + 1
89 96
90/* process command-line arguments */ 97/* process command-line arguments */
91int 98process_arguments_wrapper process_arguments(int argc, char **argv) {
92process_arguments (int argc, char **argv) 99 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
93{ 100 {"version", no_argument, 0, 'V'},
94 int c; 101 {"host", required_argument, 0, 'H'}, /* backward compatibility */
95 102 {"hostname", required_argument, 0, 'H'},
96 int option = 0; 103 {"port", required_argument, 0, 'p'},
97 static struct option longopts[] = { 104 {"use-ipv4", no_argument, 0, '4'},
98 {"help", no_argument, 0, 'h'}, 105 {"use-ipv6", no_argument, 0, '6'},
99 {"version", no_argument, 0, 'V'}, 106 {"timeout", required_argument, 0, 't'},
100 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 107 {"verbose", no_argument, 0, 'v'},
101 {"hostname", required_argument, 0, 'H'}, 108 {"remote-version", required_argument, 0, 'r'},
102 {"port", required_argument, 0, 'p'}, 109 {"remote-protocol", required_argument, 0, 'P'},
103 {"use-ipv4", no_argument, 0, '4'}, 110 {"output-format", required_argument, 0, output_format_index},
104 {"use-ipv6", no_argument, 0, '6'}, 111 {0, 0, 0, 0}};
105 {"timeout", required_argument, 0, 't'}, 112
106 {"verbose", no_argument, 0, 'v'}, 113 process_arguments_wrapper result = {
107 {"remote-version", required_argument, 0, 'r'}, 114 .config = check_ssh_config_init(),
108 {"remote-protocol", required_argument, 0, 'P'}, 115 .errorcode = OK,
109 {0, 0, 0, 0}
110 }; 116 };
111 117
112 if (argc < 2) 118 if (argc < 2) {
113 return ERROR; 119 result.errorcode = ERROR;
120 return result;
121 }
114 122
115 for (c = 1; c < argc; c++) 123 for (int i = 1; i < argc; i++) {
116 if (strcmp ("-to", argv[c]) == 0) 124 if (strcmp("-to", argv[i]) == 0) {
117 strcpy (argv[c], "-t"); 125 strcpy(argv[i], "-t");
126 }
127 }
118 128
119 while (1) { 129 int option_char;
120 c = getopt_long (argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option); 130 while (true) {
131 int option = 0;
132 option_char = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
121 133
122 if (c == -1 || c == EOF) 134 if (option_char == -1 || option_char == EOF) {
123 break; 135 break;
136 }
124 137
125 switch (c) { 138 switch (option_char) {
126 case '?': /* help */ 139 case '?': /* help */
127 usage5 (); 140 usage5();
128 case 'V': /* version */ 141 case 'V': /* version */
129 print_revision (progname, NP_VERSION); 142 print_revision(progname, NP_VERSION);
130 exit (STATE_UNKNOWN); 143 exit(STATE_UNKNOWN);
131 case 'h': /* help */ 144 case 'h': /* help */
132 print_help (); 145 print_help();
133 exit (STATE_UNKNOWN); 146 exit(STATE_UNKNOWN);
134 case 'v': /* verbose */ 147 case 'v': /* verbose */
135 verbose = true; 148 verbose = true;
136 break; 149 break;
137 case 't': /* timeout period */ 150 case 't': /* timeout period */
138 if (!is_integer (optarg)) 151 if (!is_intpos(optarg)) {
139 usage2 (_("Timeout interval must be a positive integer"), optarg); 152 usage2(_("Timeout interval must be a positive integer"), optarg);
140 else 153 } else {
141 socket_timeout = atoi (optarg); 154 socket_timeout = (unsigned int)atoi(optarg);
155 }
142 break; 156 break;
143 case '4': 157 case '4':
144 address_family = AF_INET; 158 address_family = AF_INET;
@@ -147,121 +161,121 @@ process_arguments (int argc, char **argv)
147#ifdef USE_IPV6 161#ifdef USE_IPV6
148 address_family = AF_INET6; 162 address_family = AF_INET6;
149#else 163#else
150 usage4 (_("IPv6 support not available")); 164 usage4(_("IPv6 support not available"));
151#endif 165#endif
152 break; 166 break;
153 case 'r': /* remote version */ 167 case 'r': /* remote version */
154 remote_version = optarg; 168 result.config.remote_version = optarg;
155 break; 169 break;
156 case 'P': /* remote version */ 170 case 'P': /* remote version */
157 remote_protocol = optarg; 171 result.config.remote_protocol = optarg;
158 break; 172 break;
159 case 'H': /* host */ 173 case 'H': /* host */
160 if (!is_host (optarg)) 174 if (!is_host(optarg)) {
161 usage2 (_("Invalid hostname/address"), optarg); 175 usage2(_("Invalid hostname/address"), optarg);
162 server_name = optarg; 176 }
177 result.config.server_name = optarg;
163 break; 178 break;
164 case 'p': /* port */ 179 case 'p': /* port */
165 if (is_intpos (optarg)) { 180 if (is_intpos(optarg)) {
166 port = atoi (optarg); 181 result.config.port = atoi(optarg);
182 } else {
183 usage2(_("Port number must be a positive integer"), optarg);
167 } 184 }
168 else { 185 break;
169 usage2 (_("Port number must be a positive integer"), optarg); 186 case output_format_index: {
187 parsed_output_format parser = mp_parse_output_format(optarg);
188 if (!parser.parsing_success) {
189 // TODO List all available formats here, maybe add anothoer usage function
190 printf("Invalid output format: %s\n", optarg);
191 exit(STATE_UNKNOWN);
170 } 192 }
193
194 result.config.output_format_is_set = true;
195 result.config.output_format = parser.output_format;
196 break;
197 }
171 } 198 }
172 } 199 }
173 200
174 c = optind; 201 option_char = optind;
175 if (server_name == NULL && c < argc) { 202 if (result.config.server_name == NULL && option_char < argc) {
176 if (is_host (argv[c])) { 203 if (is_host(argv[option_char])) {
177 server_name = argv[c++]; 204 result.config.server_name = argv[option_char++];
178 } 205 }
179 } 206 }
180 207
181 if (port == -1 && c < argc) { 208 if (result.config.port == -1 && option_char < argc) {
182 if (is_intpos (argv[c])) { 209 if (is_intpos(argv[option_char])) {
183 port = atoi (argv[c++]); 210 result.config.port = atoi(argv[option_char++]);
184 } 211 } else {
185 else { 212 print_usage();
186 print_usage (); 213 exit(STATE_UNKNOWN);
187 exit (STATE_UNKNOWN);
188 } 214 }
189 } 215 }
190 216
191 return validate_arguments (); 217 if (result.config.server_name == NULL) {
192} 218 result.errorcode = ERROR;
219 return result;
220 }
193 221
194int 222 return result;
195validate_arguments (void)
196{
197 if (server_name == NULL)
198 return ERROR;
199 if (port == -1) /* funky, but allows -p to override stray integer in args */
200 port = SSH_DFL_PORT;
201 return OK;
202} 223}
203 224
204
205/************************************************************************ 225/************************************************************************
206* 226 *
207* Try to connect to SSH server at specified server and port 227 * Try to connect to SSH server at specified server and port
208* 228 *
209*-----------------------------------------------------------------------*/ 229 *-----------------------------------------------------------------------*/
210
211
212int
213ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol)
214{
215 int sd;
216 int result;
217 int len = 0;
218 ssize_t recv_ret = 0;
219 char *version_control_string = NULL;
220 char *buffer = NULL;
221 char *ssh_proto = NULL;
222 char *ssh_server = NULL;
223 static char *rev_no = VERSION;
224 struct timeval tv;
225 double elapsed_time;
226 230
231int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version, char *desired_remote_protocol) {
232 struct timeval tv;
227 gettimeofday(&tv, NULL); 233 gettimeofday(&tv, NULL);
228 234
229 result = my_tcp_connect (haddr, hport, &sd); 235 int socket;
236 int result = my_tcp_connect(haddr, hport, &socket);
230 237
231 if (result != STATE_OK) 238 mp_subcheck connection_sc = mp_subcheck_init();
239 if (result != STATE_OK) {
240 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
241 xasprintf(&connection_sc.output, "Failed to establish TCP connection to Host %s and Port %d", haddr, hport);
242 mp_add_subcheck_to_check(overall, connection_sc);
232 return result; 243 return result;
244 }
233 245
234 char *output = (char *) calloc (BUFF_SZ + 1, sizeof(char)); 246 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
235 247 char *buffer = NULL;
236 unsigned int iteration = 0; 248 size_t recv_ret = 0;
237 ssize_t byte_offset = 0; 249 char *version_control_string = NULL;
238 250 size_t byte_offset = 0;
239 while ((version_control_string == NULL) && (recv_ret = recv(sd, output+byte_offset, BUFF_SZ - byte_offset, 0) > 0)) { 251 while ((version_control_string == NULL) &&
252 (recv_ret = recv(socket, output + byte_offset, (unsigned long)(BUFF_SZ - byte_offset), 0) > 0)) {
240 253
241 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/ 254 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
242 byte_offset = 0; 255 byte_offset = 0;
243 256
244 char *index = NULL; 257 char *index = NULL;
245 while ((index = strchr(output+byte_offset, '\n')) != NULL) { 258 unsigned long len = 0;
259 while ((index = strchr(output + byte_offset, '\n')) != NULL) {
246 /*Partition the buffer so that this line is a separate string, 260 /*Partition the buffer so that this line is a separate string,
247 * by replacing the newline with NUL*/ 261 * by replacing the newline with NUL*/
248 output[(index - output)] = '\0'; 262 output[(index - output)] = '\0';
249 len = strlen(output + byte_offset); 263 len = strlen(output + byte_offset);
250 264
251 if ((len >= 4) && (strncmp (output+byte_offset, "SSH-", 4) == 0)) { 265 if ((len >= 4) && (strncmp(output + byte_offset, "SSH-", 4) == 0)) {
252 /*if the string starts with SSH-, this _should_ be a valid version control string*/ 266 /*if the string starts with SSH-, this _should_ be a valid version control string*/
253 version_control_string = output+byte_offset; 267 version_control_string = output + byte_offset;
254 break; 268 break;
255 } 269 }
256 270
257 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/ 271 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/
258 byte_offset += (len + 1); 272 byte_offset += (len + 1);
259 } 273 }
260 274
261 if(version_control_string == NULL) { 275 if (version_control_string == NULL) {
262 /* move unconsumed data to beginning of buffer, null rest */ 276 /* move unconsumed data to beginning of buffer, null rest */
263 memmove((void *)output, (void *)output+byte_offset+1, BUFF_SZ - len+1); 277 memmove((void *)output, (void *)(output + byte_offset + 1), BUFF_SZ - len + 1);
264 memset(output+byte_offset+1, 0, BUFF_SZ-byte_offset+1); 278 memset(output + byte_offset + 1, 0, BUFF_SZ - byte_offset + 1);
265 279
266 /*start reading from end of current line chunk on next recv*/ 280 /*start reading from end of current line chunk on next recv*/
267 byte_offset = strlen(output); 281 byte_offset = strlen(output);
@@ -272,14 +286,23 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
272 } 286 }
273 287
274 if (recv_ret < 0) { 288 if (recv_ret < 0) {
275 printf("SSH CRITICAL - %s", strerror(errno)); 289 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
276 exit(STATE_CRITICAL); 290 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - %s", strerror(errno));
291 mp_add_subcheck_to_check(overall, connection_sc);
292 return OK;
277 } 293 }
278 294
279 if (version_control_string == NULL) { 295 if (version_control_string == NULL) {
280 printf("SSH CRITICAL - No version control string received"); 296 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
281 exit(STATE_CRITICAL); 297 xasprintf(&connection_sc.output, "%s", "SSH CRITICAL - No version control string received");
298 mp_add_subcheck_to_check(overall, connection_sc);
299 return OK;
282 } 300 }
301
302 connection_sc = mp_set_subcheck_state(connection_sc, STATE_OK);
303 xasprintf(&connection_sc.output, "%s", "Initial connection succeeded");
304 mp_add_subcheck_to_check(overall, connection_sc);
305
283 /* 306 /*
284 * "When the connection has been established, both sides MUST send an 307 * "When the connection has been established, both sides MUST send an
285 * identification string. This identification string MUST be 308 * identification string. This identification string MUST be
@@ -287,10 +310,12 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
287 * SSH-protoversion-softwareversion SP comments CR LF" 310 * SSH-protoversion-softwareversion SP comments CR LF"
288 * - RFC 4253:4.2 311 * - RFC 4253:4.2
289 */ 312 */
290 strip (version_control_string); 313 strip(version_control_string);
291 if (verbose) 314 if (verbose) {
292 printf ("%s\n", version_control_string); 315 printf("%s\n", version_control_string);
293 ssh_proto = version_control_string + 4; 316 }
317
318 char *ssh_proto = version_control_string + 4;
294 319
295 /* 320 /*
296 * We assume the protoversion is of the form Major.Minor, although 321 * We assume the protoversion is of the form Major.Minor, although
@@ -308,7 +333,7 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
308 * "1.x" (e.g., "1.5" or "1.3")." 333 * "1.x" (e.g., "1.5" or "1.3")."
309 * - RFC 4253:5 334 * - RFC 4253:5
310 */ 335 */
311 ssh_server = ssh_proto + strspn (ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */ 336 char *ssh_server = ssh_proto + strspn(ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */
312 337
313 /* If there's a space in the version string, whatever's after the space is a comment 338 /* If there's a space in the version string, whatever's after the space is a comment
314 * (which is NOT part of the server name/version)*/ 339 * (which is NOT part of the server name/version)*/
@@ -316,88 +341,99 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
316 if (tmp) { 341 if (tmp) {
317 ssh_server[tmp - ssh_server] = '\0'; 342 ssh_server[tmp - ssh_server] = '\0';
318 } 343 }
344
345 mp_subcheck protocol_validity_sc = mp_subcheck_init();
319 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) { 346 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
320 printf(_("SSH CRITICAL - Invalid protocol version control string %s\n"), version_control_string); 347 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_CRITICAL);
321 exit (STATE_CRITICAL); 348 xasprintf(&protocol_validity_sc.output, "Invalid protocol version control string %s", version_control_string);
349 mp_add_subcheck_to_check(overall, protocol_validity_sc);
350 return OK;
322 } 351 }
323 ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0; 352
324 353 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK);
325 xasprintf (&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no); 354 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s", version_control_string);
326 send (sd, buffer, strlen (buffer), MSG_DONTWAIT); 355 mp_add_subcheck_to_check(overall, protocol_validity_sc);
327 if (verbose) 356
328 printf ("%s\n", buffer); 357 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
329 358
330 if (remote_version && strcmp(remote_version, ssh_server)) { 359 static char *rev_no = VERSION;
331 printf 360 xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
332 (_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"), 361 send(socket, buffer, strlen(buffer), MSG_DONTWAIT);
333 ssh_server, ssh_proto, remote_version); 362 if (verbose) {
334 close(sd); 363 printf("%s\n", buffer);
335 exit (STATE_CRITICAL);
336 } 364 }
337 365
338 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) { 366 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) {
339 printf 367 mp_subcheck remote_version_sc = mp_subcheck_init();
340 (_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s' | %s\n"), 368 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL);
341 ssh_server, ssh_proto, remote_protocol, fperfdata("time", elapsed_time, "s", 369 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"), ssh_server, ssh_proto,
342 false, 0, false, 0, true, 0, true, (int)socket_timeout)); 370 desired_remote_version);
343 close(sd); 371 close(socket);
344 exit (STATE_CRITICAL); 372 mp_add_subcheck_to_check(overall, remote_version_sc);
373 return OK;
345 } 374 }
346 elapsed_time = (double)deltime(tv) / 1.0e6;
347
348 printf
349 (_("SSH OK - %s (protocol %s) | %s\n"),
350 ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s",
351 false, 0, false, 0, true, 0, true, (int)socket_timeout));
352 close(sd);
353 exit (STATE_OK);
354}
355 375
376 double elapsed_time = (double)deltime(tv) / 1.0e6;
377 mp_perfdata time_pd = perfdata_init();
378 time_pd.value = mp_create_pd_value(elapsed_time);
379 time_pd.label = "time";
380 time_pd.max_present = true;
381 time_pd.max = mp_create_pd_value(socket_timeout);
382
383 mp_subcheck protocol_version_sc = mp_subcheck_init();
384 mp_add_perfdata_to_subcheck(&protocol_version_sc, time_pd);
385
386 if (desired_remote_protocol && strcmp(desired_remote_protocol, ssh_proto)) {
387 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_CRITICAL);
388 xasprintf(&protocol_version_sc.output, _("%s (protocol %s) protocol version mismatch, expected '%s'"), ssh_server, ssh_proto,
389 desired_remote_protocol);
390 } else {
391 protocol_version_sc = mp_set_subcheck_state(protocol_version_sc, STATE_OK);
392 xasprintf(&protocol_version_sc.output, "SSH server version: %s (protocol version: %s)", ssh_server, ssh_proto);
393 }
356 394
395 mp_add_subcheck_to_check(overall, protocol_version_sc);
396 close(socket);
397 return OK;
398}
357 399
358void 400void print_help(void) {
359print_help (void)
360{
361 char *myport; 401 char *myport;
362 xasprintf (&myport, "%d", SSH_DFL_PORT); 402 xasprintf(&myport, "%d", default_ssh_port);
363 403
364 print_revision (progname, NP_VERSION); 404 print_revision(progname, NP_VERSION);
365 405
366 printf ("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n"); 406 printf("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n");
367 printf (COPYRIGHT, copyright, email); 407 printf(COPYRIGHT, copyright, email);
368 408
369 printf ("%s\n", _("Try to connect to an SSH server at specified server and port")); 409 printf("%s\n", _("Try to connect to an SSH server at specified server and port"));
370 410
371 printf ("\n\n"); 411 printf("\n\n");
372 412
373 print_usage (); 413 print_usage();
374 414
375 printf (UT_HELP_VRSN); 415 printf(UT_HELP_VRSN);
376 printf (UT_EXTRA_OPTS); 416 printf(UT_EXTRA_OPTS);
377 417
378 printf (UT_HOST_PORT, 'p', myport); 418 printf(UT_HOST_PORT, 'p', myport);
379 419
380 printf (UT_IPv46); 420 printf(UT_IPv46);
381 421
382 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 422 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
383 423
384 printf (" %s\n", "-r, --remote-version=STRING"); 424 printf(" %s\n", "-r, --remote-version=STRING");
385 printf (" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)")); 425 printf(" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
386 426
387 printf (" %s\n", "-P, --remote-protocol=STRING"); 427 printf(" %s\n", "-P, --remote-protocol=STRING");
388 printf (" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)")); 428 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
429 printf(UT_OUTPUT_FORMAT);
389 430
390 printf (UT_VERBOSE); 431 printf(UT_VERBOSE);
391 432
392 printf (UT_SUPPORT); 433 printf(UT_SUPPORT);
393} 434}
394 435
395 436void print_usage(void) {
396 437 printf("%s\n", _("Usage:"));
397void 438 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n", progname);
398print_usage (void)
399{
400 printf ("%s\n", _("Usage:"));
401 printf ("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);
402} 439}
403
diff --git a/plugins/check_ssh.d/config.h b/plugins/check_ssh.d/config.h
new file mode 100644
index 00000000..c150fd30
--- /dev/null
+++ b/plugins/check_ssh.d/config.h
@@ -0,0 +1,29 @@
1#pragma once
2
3#include <stddef.h>
4#include "../../lib/monitoringplug.h"
5
6const int default_ssh_port = 22;
7
8typedef struct check_ssh_config {
9 int port;
10 char *server_name;
11 char *remote_version;
12 char *remote_protocol;
13
14 bool output_format_is_set;
15 mp_output_format output_format;
16} check_ssh_config;
17
18check_ssh_config check_ssh_config_init(void) {
19 check_ssh_config tmp = {
20 .port = default_ssh_port,
21 .server_name = NULL,
22 .remote_version = NULL,
23 .remote_protocol = NULL,
24
25 .output_format_is_set = false,
26 };
27
28 return tmp;
29}
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index e7ee785d..435a104e 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -1,607 +1,408 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_swap plugin 3 * Monitoring check_swap plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net) 6 * Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
7* Copyright (c) 2000-2024 Monitoring Plugins Development Team 7 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_swap plugin 11 * This file contains the check_swap plugin
12* 12 *
13* 13 *
14* This program is free software: you can redistribute it and/or modify 14 * This program is free software: you can redistribute it and/or modify
15* it under the terms of the GNU General Public License as published by 15 * it under the terms of the GNU General Public License as published by
16* the Free Software Foundation, either version 3 of the License, or 16 * the Free Software Foundation, either version 3 of the License, or
17* (at your option) any later version. 17 * (at your option) any later version.
18* 18 *
19* This program is distributed in the hope that it will be useful, 19 * This program is distributed in the hope that it will be useful,
20* but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22* GNU General Public License for more details. 22 * GNU General Public License for more details.
23* 23 *
24* You should have received a copy of the GNU General Public License 24 * You should have received a copy of the GNU General Public License
25* along with this program. If not, see <http://www.gnu.org/licenses/>. 25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26* 26 *
27* 27 *
28*****************************************************************************/ 28 *****************************************************************************/
29
30const char *progname = "check_swap";
31const char *copyright = "2000-2024";
32const char *email = "devel@monitoring-plugins.org";
33 29
34#include "common.h" 30#include "common.h"
35#include "popen.h" 31#include "output.h"
36#include "utils.h" 32#include "states.h"
37 33#include <limits.h>
38#ifdef HAVE_DECL_SWAPCTL 34#ifdef HAVE_DECL_SWAPCTL
39# ifdef HAVE_SYS_PARAM_H 35# ifdef HAVE_SYS_PARAM_H
40# include <sys/param.h> 36# include <sys/param.h>
41# endif 37# endif
42# ifdef HAVE_SYS_SWAP_H 38# ifdef HAVE_SYS_SWAP_H
43# include <sys/swap.h> 39# include <sys/swap.h>
44# endif 40# endif
45# ifdef HAVE_SYS_STAT_H 41# ifdef HAVE_SYS_STAT_H
46# include <sys/stat.h> 42# include <sys/stat.h>
47# endif 43# endif
48#endif 44#endif
49 45
50#ifndef SWAP_CONVERSION 46#include <stdint.h>
51# define SWAP_CONVERSION 1 47#include "./check_swap.d/check_swap.h"
52#endif 48#include "./utils.h"
53 49
54typedef struct { 50typedef struct {
55 bool is_percentage; 51 int errorcode;
56 uint64_t value; 52 swap_config config;
57} threshold; 53} swap_config_wrapper;
58 54
59int check_swap (float free_swap_mb, float total_swap_mb); 55static swap_config_wrapper process_arguments(int argc, char **argv);
60int process_arguments (int argc, char **argv); 56void print_usage(void);
61int validate_arguments (void); 57static void print_help(swap_config /*config*/);
62void print_usage (void); 58
63void print_help (void);
64
65threshold warn;
66threshold crit;
67int verbose; 59int verbose;
68bool allswaps = false;
69int no_swap_state = STATE_CRITICAL;
70
71int
72main (int argc, char **argv)
73{
74 unsigned int percent_used, percent;
75 uint64_t total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0;
76 uint64_t dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0;
77 uint64_t tmp_KB = 0;
78 int result = STATE_UNKNOWN;
79 char input_buffer[MAX_INPUT_BUFFER];
80#ifdef HAVE_PROC_MEMINFO
81 FILE *fp;
82#else
83 int conv_factor = SWAP_CONVERSION;
84# ifdef HAVE_SWAP
85 char *temp_buffer;
86 char *swap_command;
87 char *swap_format;
88# else
89# ifdef HAVE_DECL_SWAPCTL
90 int i=0, nswaps=0, swapctl_res=0;
91# ifdef CHECK_SWAP_SWAPCTL_SVR4
92 swaptbl_t *tbl=NULL;
93 swapent_t *ent=NULL;
94# else
95# ifdef CHECK_SWAP_SWAPCTL_BSD
96 struct swapent *ent;
97# endif /* CHECK_SWAP_SWAPCTL_BSD */
98# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
99# endif /* HAVE_DECL_SWAPCTL */
100# endif
101#endif
102 char str[32];
103 char *status;
104 60
105 setlocale (LC_ALL, ""); 61#define HUNDRED_PERCENT 100
106 bindtextdomain (PACKAGE, LOCALEDIR); 62
107 textdomain (PACKAGE); 63#define BYTES_TO_KiB(number) (number / 1024)
64#define BYTES_TO_MiB(number) (BYTES_TO_KiB(number) / 1024)
65
66const char *progname = "check_swap";
67const char *copyright = "2000-2024";
68const char *email = "devel@monitoring-plugins.org";
108 69
109 status = strdup (""); 70int main(int argc, char **argv) {
71 setlocale(LC_ALL, "");
72 bindtextdomain(PACKAGE, LOCALEDIR);
73 textdomain(PACKAGE);
110 74
111 /* Parse extra opts if any */ 75 /* Parse extra opts if any */
112 argv=np_extra_opts (&argc, argv, progname); 76 argv = np_extra_opts(&argc, argv, progname);
113 77
114 if (process_arguments (argc, argv) == ERROR) 78 swap_config_wrapper tmp = process_arguments(argc, argv);
115 usage4 (_("Could not parse arguments"));
116 79
117#ifdef HAVE_PROC_MEMINFO 80 if (tmp.errorcode != OK) {
118 if (verbose >= 3) { 81 usage4(_("Could not parse arguments"));
119 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
120 } 82 }
121 fp = fopen (PROC_MEMINFO, "r");
122 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
123 /*
124 * The following sscanf call looks for a line looking like: "Swap: 123 123 123"
125 * On which kind of system this format exists, I can not say, but I wanted to
126 * document this for people who are not adapt with sscanf anymore, like me
127 */
128 if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) {
129 dsktotal_mb = dsktotal_mb / (1024 * 1024); /* Apply conversion */
130 dskused_mb = dskused_mb / (1024 * 1024);
131 dskfree_mb = dskfree_mb / (1024 * 1024);
132 total_swap_mb += dsktotal_mb;
133 used_swap_mb += dskused_mb;
134 free_swap_mb += dskfree_mb;
135 if (allswaps) {
136 if (dsktotal_mb == 0)
137 percent=100.0;
138 else
139 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
140 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
141 if (verbose)
142 xasprintf (&status, "%s [%lu (%d%%)]", status, dskfree_mb, 100 - percent);
143 }
144 }
145 83
146 /* 84 swap_config config = tmp.config;
147 * The following sscanf call looks for lines looking like: "SwapTotal: 123" and "SwapFree: 123"
148 * This format exists at least on Debian Linux with a 5.* kernel
149 */
150 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu %*[k]%*[B]", str, &tmp_KB)) {
151 if (verbose >= 3) {
152 printf("Got %s with %lu\n", str, tmp_KB);
153 }
154 /* I think this part is always in Kb, so convert to mb */
155 if (strcmp ("Total", str) == 0) {
156 dsktotal_mb = tmp_KB / 1024;
157 }
158 else if (strcmp ("Free", str) == 0) {
159 dskfree_mb = dskfree_mb + tmp_KB / 1024;
160 }
161 else if (strcmp ("Cached", str) == 0) {
162 dskfree_mb = dskfree_mb + tmp_KB / 1024;
163 }
164 }
165 }
166 fclose(fp);
167 dskused_mb = dsktotal_mb - dskfree_mb;
168 total_swap_mb = dsktotal_mb;
169 used_swap_mb = dskused_mb;
170 free_swap_mb = dskfree_mb;
171#else
172# ifdef HAVE_SWAP
173 xasprintf(&swap_command, "%s", SWAP_COMMAND);
174 xasprintf(&swap_format, "%s", SWAP_FORMAT);
175
176/* These override the command used if a summary (and thus ! allswaps) is required */
177/* The summary flag returns more accurate information about swap usage on these OSes */
178# ifdef _AIX
179 if (!allswaps) {
180 xasprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
181 xasprintf(&swap_format, "%s", "%lu%*s %lu");
182 conv_factor = 1;
183 }
184# endif
185 85
186 if (verbose >= 2) 86 swap_result data = get_swap_data(config);
187 printf (_("Command: %s\n"), swap_command);
188 if (verbose >= 3)
189 printf (_("Format: %s\n"), swap_format);
190 87
191 child_process = spopen (swap_command); 88 if (data.errorcode != STATE_OK) {
192 if (child_process == NULL) { 89 puts("SWAP UNKNOWN - Failed to retrieve Swap usage");
193 printf (_("Could not open pipe: %s\n"), swap_command); 90 exit(STATE_UNKNOWN);
194 return STATE_UNKNOWN;
195 } 91 }
196 92
197 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 93 if (verbose) {
198 if (child_stderr == NULL) 94 printf("Swap retrieval result:\n"
199 printf (_("Could not open stderr for %s\n"), swap_command); 95 "\tFree: %llu\n"
200 96 "\tUsed: %llu\n"
201 sprintf (str, "%s", ""); 97 "\tTotal: %llu\n",
202 /* read 1st line */ 98 data.metrics.free, data.metrics.used, data.metrics.total);
203 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
204 if (strcmp (swap_format, "") == 0) {
205 temp_buffer = strtok (input_buffer, " \n");
206 while (temp_buffer) {
207 if (strstr (temp_buffer, "blocks"))
208 sprintf (str, "%s %s", str, "%lu");
209 else if (strstr (temp_buffer, "dskfree"))
210 sprintf (str, "%s %s", str, "%lu");
211 else
212 sprintf (str, "%s %s", str, "%*s");
213 temp_buffer = strtok (NULL, " \n");
214 }
215 } 99 }
216 100
217/* If different swap command is used for summary switch, need to read format differently */ 101 double percent_used;
218# ifdef _AIX 102 mp_check overall = mp_check_init();
219 if (!allswaps) { 103 if (config.output_format_is_set) {
220 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */ 104 mp_set_format(config.output_format);
221 sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
222 free_swap_mb = total_swap_mb * (100 - used_swap_mb) /100;
223 used_swap_mb = total_swap_mb - free_swap_mb;
224 if (verbose >= 3)
225 printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
226 } else {
227# endif
228 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
229 sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
230
231 dsktotal_mb = dsktotal_mb / conv_factor;
232 /* AIX lists percent used, so this converts to dskfree in MBs */
233# ifdef _AIX
234 dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
235# else
236 dskfree_mb = dskfree_mb / conv_factor;
237# endif
238 if (verbose >= 3)
239 printf (_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
240
241 dskused_mb = dsktotal_mb - dskfree_mb;
242 total_swap_mb += dsktotal_mb;
243 used_swap_mb += dskused_mb;
244 free_swap_mb += dskfree_mb;
245 if (allswaps) {
246 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
247 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
248 if (verbose)
249 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
250 }
251 }
252# ifdef _AIX
253 } 105 }
254# endif 106 mp_subcheck sc1 = mp_subcheck_init();
255 107 sc1 = mp_set_subcheck_default_state(sc1, STATE_OK);
256 /* If we get anything on STDERR, at least set warning */
257 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
258 result = max_state (result, STATE_WARNING);
259
260 /* close stderr */
261 (void) fclose (child_stderr);
262 108
263 /* close the pipe */ 109 /* if total_swap_mb == 0, let's not divide by 0 */
264 if (spclose (child_process)) 110 if (data.metrics.total != 0) {
265 result = max_state (result, STATE_WARNING); 111 percent_used = HUNDRED_PERCENT * ((double)data.metrics.used) / ((double)data.metrics.total);
266# else 112 } else {
267# ifdef CHECK_SWAP_SWAPCTL_SVR4 113 sc1 = mp_set_subcheck_state(sc1, config.no_swap_state);
114 sc1.output = (char *)_("Swap is either disabled, not present, or of zero size.");
268 115
269 /* get the number of active swap devices */ 116 mp_add_subcheck_to_check(&overall, sc1);
270 if((nswaps=swapctl(SC_GETNSWP, NULL))== -1) 117 mp_exit(overall);
271 die(STATE_UNKNOWN, _("Error getting swap devices\n") ); 118 }
272 119
273 if(nswaps == 0) 120 if (verbose) {
274 die(STATE_OK, _("SWAP OK: No swap devices defined\n")); 121 printf("Computed usage percentage: %g\n", percent_used);
122 }
275 123
276 if(verbose >= 3) 124 mp_perfdata pd = perfdata_init();
277 printf("Found %d swap device(s)\n", nswaps); 125 pd.label = "swap";
126 pd = mp_set_pd_value(pd, data.metrics.free);
127 pd.uom = "B";
278 128
279 /* initialize swap table + entries */ 129 if (config.warn_is_set) {
280 tbl=(swaptbl_t*)malloc(sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps)); 130 uint64_t warn_print = config.warn.value;
131 if (config.warn.is_percentage) {
132 warn_print = config.warn.value * (data.metrics.total / HUNDRED_PERCENT);
133 }
281 134
282 if(tbl==NULL) 135 mp_perfdata_value warn_pd = mp_create_pd_value(warn_print);
283 die(STATE_UNKNOWN, _("malloc() failed!\n"));
284 136
285 memset(tbl, 0, sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps)); 137 mp_range warn_range = mp_range_init();
286 tbl->swt_n=nswaps; 138 warn_range.end_infinity = false;
287 for(i=0;i<nswaps;i++){ 139 warn_range.end = warn_pd;
288 if((tbl->swt_ent[i].ste_path=(char*)malloc(sizeof(char)*MAXPATHLEN)) == NULL)
289 die(STATE_UNKNOWN, _("malloc() failed!\n"));
290 }
291 140
292 /* and now, tally 'em up */ 141 pd.warn = warn_range;
293 swapctl_res=swapctl(SC_LIST, tbl); 142 pd.warn_present = true;
294 if(swapctl_res < 0){
295 perror(_("swapctl failed: "));
296 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
297 } 143 }
298 144
299 for(i=0;i<nswaps;i++){ 145 if (config.crit_is_set) {
300 dsktotal_mb = (float) tbl->swt_ent[i].ste_pages / SWAP_CONVERSION; 146 uint64_t crit_print = config.crit.value;
301 dskfree_mb = (float) tbl->swt_ent[i].ste_free / SWAP_CONVERSION; 147 if (config.crit.is_percentage) {
302 dskused_mb = ( dsktotal_mb - dskfree_mb ); 148 crit_print = config.crit.value * (data.metrics.total / HUNDRED_PERCENT);
303
304 if (verbose >= 3)
305 printf ("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
306
307 if(allswaps && dsktotal_mb > 0){
308 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
309 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
310 if (verbose) {
311 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
312 }
313 } 149 }
314 150
315 total_swap_mb += dsktotal_mb; 151 mp_perfdata_value crit_pd = mp_create_pd_value(crit_print);
316 free_swap_mb += dskfree_mb;
317 used_swap_mb += dskused_mb;
318 }
319 152
320 /* and clean up after ourselves */ 153 mp_range crit_range = mp_range_init();
321 for(i=0;i<nswaps;i++){ 154 crit_range.end_infinity = false;
322 free(tbl->swt_ent[i].ste_path); 155 crit_range.end = crit_pd;
156
157 pd.crit = crit_range;
158 pd.crit_present = true;
323 } 159 }
324 free(tbl);
325# else
326# ifdef CHECK_SWAP_SWAPCTL_BSD
327 160
328 /* get the number of active swap devices */ 161 mp_perfdata_value max = mp_create_pd_value(data.metrics.total);
329 nswaps=swapctl(SWAP_NSWAP, NULL, 0); 162 pd.max = max;
163 pd.max_present = true;
330 164
331 /* initialize swap table + entries */ 165 mp_perfdata_value min = mp_create_pd_value(0);
332 ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps); 166 pd.min = min;
167 pd.min_present = true;
333 168
334 /* and now, tally 'em up */ 169 mp_add_perfdata_to_subcheck(&sc1, pd);
335 swapctl_res=swapctl(SWAP_STATS, ent, nswaps); 170 if (verbose > 1) {
336 if(swapctl_res < 0){ 171 printf("Warn threshold value: %" PRIu64 "\n", config.warn.value);
337 perror(_("swapctl failed: "));
338 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
339 } 172 }
340 173
341 for(i=0;i<nswaps;i++){ 174 if (config.warn_is_set) {
342 dsktotal_mb = (float) ent[i].se_nblks / conv_factor; 175 if ((config.warn.is_percentage && (percent_used >= (100 - (double)config.warn.value))) || config.warn.value >= data.metrics.free) {
343 dskused_mb = (float) ent[i].se_inuse / conv_factor; 176 sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
344 dskfree_mb = ( dsktotal_mb - dskused_mb );
345
346 if(allswaps && dsktotal_mb > 0){
347 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
348 result = max_state (result, check_swap(dskfree_mb, dsktotal_mb));
349 if (verbose) {
350 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
351 }
352 } 177 }
353
354 total_swap_mb += dsktotal_mb;
355 free_swap_mb += dskfree_mb;
356 used_swap_mb += dskused_mb;
357 } 178 }
358 179
359 /* and clean up after ourselves */ 180 if (verbose > 1) {
360 free(ent); 181 printf("Crit threshold value: %" PRIu64 "\n", config.crit.value);
361
362# endif /* CHECK_SWAP_SWAPCTL_BSD */
363# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
364# endif /* HAVE_SWAP */
365#endif /* HAVE_PROC_MEMINFO */
366
367 /* if total_swap_mb == 0, let's not divide by 0 */
368 if(total_swap_mb) {
369 percent_used = 100 * ((double) used_swap_mb) / ((double) total_swap_mb);
370 } else {
371 percent_used = 100;
372 status = "- Swap is either disabled, not present, or of zero size. ";
373 } 182 }
374 183
375 result = max_state (result, check_swap(free_swap_mb, total_swap_mb)); 184 if (config.crit_is_set) {
376 printf (_("SWAP %s - %d%% free (%dMB out of %dMB) %s|"), 185 if ((config.crit.is_percentage && (percent_used >= (100 - (double)config.crit.value))) || config.crit.value >= data.metrics.free) {
377 state_text (result), 186 sc1 = mp_set_subcheck_state(sc1, STATE_CRITICAL);
378 (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status); 187 }
188 }
379 189
380 uint64_t warn_print = warn.value; 190 xasprintf(&sc1.output, _("%g%% free (%lluMiB out of %lluMiB)"), (100 - percent_used), data.metrics.free >> 20,
381 if (warn.is_percentage) warn_print = warn.value * (total_swap_mb *1024 *1024/100); 191 data.metrics.total >> 20);
382 uint64_t crit_print = crit.value;
383 if (crit.is_percentage) crit_print = crit.value * (total_swap_mb *1024 *1024/100);
384 192
385 puts (perfdata_uint64 ("swap", free_swap_mb *1024 *1024, "B", 193 overall.summary = "Swap";
386 true, warn_print, 194 mp_add_subcheck_to_check(&overall, sc1);
387 true, crit_print,
388 true, 0,
389 true, (long) total_swap_mb * 1024 * 1024));
390 195
391 return result; 196 mp_exit(overall);
392} 197}
393 198
199int check_swap(float free_swap_mb, float total_swap_mb, swap_config config) {
200 if (total_swap_mb == 0) {
201 return config.no_swap_state;
202 }
394 203
395int 204 uint64_t free_swap = (uint64_t)(free_swap_mb * (1024 * 1024)); /* Convert back to bytes as warn and crit specified in bytes */
396check_swap(float free_swap_mb, float total_swap_mb)
397{
398
399 if (!total_swap_mb) return no_swap_state;
400 205
401 uint64_t free_swap = free_swap_mb * (1024 * 1024); /* Convert back to bytes as warn and crit specified in bytes */ 206 if (!config.crit.is_percentage && config.crit.value >= free_swap) {
402 uint64_t usage_percentage = ((total_swap_mb - free_swap_mb) / total_swap_mb) * 100; 207 return STATE_CRITICAL;
208 }
209 if (!config.warn.is_percentage && config.warn.value >= free_swap) {
210 return STATE_WARNING;
211 }
403 212
404 if (warn.value || crit.value) { /* Thresholds defined */ 213 uint64_t usage_percentage = (uint64_t)((total_swap_mb - free_swap_mb) / total_swap_mb) * HUNDRED_PERCENT;
405 if (!crit.is_percentage && crit.value >= free_swap) return STATE_CRITICAL;
406 if (!warn.is_percentage && warn.value >= free_swap) return STATE_WARNING;
407 214
408 if (crit.is_percentage && 215 if (config.crit.is_percentage && config.crit.value != 0 && usage_percentage >= (HUNDRED_PERCENT - config.crit.value)) {
409 crit.value != 0 && 216 return STATE_CRITICAL;
410 usage_percentage >= (100 - crit.value)) 217 }
411 {
412 return STATE_CRITICAL;
413 }
414 218
415 if (warn.is_percentage && 219 if (config.warn.is_percentage && config.warn.value != 0 && usage_percentage >= (HUNDRED_PERCENT - config.warn.value)) {
416 warn.value != 0 && 220 return STATE_WARNING;
417 usage_percentage >= (100 - warn.value)) 221 }
418 {
419 return STATE_WARNING;
420 }
421 222
422 return STATE_OK; 223 return STATE_OK;
423 } else { /* Without thresholds */
424 return STATE_OK;
425 }
426} 224}
427 225
428 226#define output_format_index CHAR_MAX + 1
429 227
430/* process command-line arguments */ 228/* process command-line arguments */
431int 229swap_config_wrapper process_arguments(int argc, char **argv) {
432process_arguments (int argc, char **argv) 230 swap_config_wrapper conf_wrapper = {.errorcode = OK};
433{ 231 conf_wrapper.config = swap_config_init();
434 int c = 0; /* option character */ 232
435 233 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
436 int option = 0; 234 {"critical", required_argument, 0, 'c'},
437 static struct option longopts[] = { 235 {"allswaps", no_argument, 0, 'a'},
438 {"warning", required_argument, 0, 'w'}, 236 {"no-swap", required_argument, 0, 'n'},
439 {"critical", required_argument, 0, 'c'}, 237 {"verbose", no_argument, 0, 'v'},
440 {"allswaps", no_argument, 0, 'a'}, 238 {"version", no_argument, 0, 'V'},
441 {"no-swap", required_argument, 0, 'n'}, 239 {"help", no_argument, 0, 'h'},
442 {"verbose", no_argument, 0, 'v'}, 240 {"output-format", required_argument, 0, output_format_index},
443 {"version", no_argument, 0, 'V'}, 241 {0, 0, 0, 0}};
444 {"help", no_argument, 0, 'h'}, 242
445 {0, 0, 0, 0} 243 while (true) {
446 }; 244 int option = 0;
447 245 int option_char = getopt_long(argc, argv, "+?Vvhac:w:n:", longopts, &option);
448 while (1) { 246
449 c = getopt_long (argc, argv, "+?Vvhac:w:n:", longopts, &option); 247 if (option_char == -1 || option_char == EOF) {
450
451 if (c == -1 || c == EOF)
452 break; 248 break;
249 }
453 250
454 switch (c) { 251 switch (option_char) {
455 case 'w': /* warning size threshold */ 252 case 'w': /* warning size threshold */
456 { 253 {
457 /* 254 /*
458 * We expect either a positive integer value without a unit, which means 255 * We expect either a positive integer value without a unit, which
459 * the unit is Bytes or a positive integer value and a percentage sign (%), 256 * means the unit is Bytes or a positive integer value and a
460 * which means the value must be with 0 and 100 and is relative to the total swap 257 * percentage sign (%), which means the value must be with 0 and 100
461 */ 258 * and is relative to the total swap
462 size_t length; 259 */
463 length = strlen(optarg); 260 size_t length;
464 261 length = strlen(optarg);
465 if (optarg[length - 1] == '%') { 262 conf_wrapper.config.warn_is_set = true;
466 /* It's percentage */ 263
467 warn.is_percentage = true; 264 if (optarg[length - 1] == '%') {
468 optarg[length - 1] = '\0'; 265 /* It's percentage */
469 if (is_uint64(optarg, &warn.value)) { 266 conf_wrapper.config.warn.is_percentage = true;
470 if (warn.value > 100) { 267 optarg[length - 1] = '\0';
471 usage4 (_("Warning threshold percentage must be <= 100!")); 268 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
472 } 269 if (conf_wrapper.config.warn.value > HUNDRED_PERCENT) {
473 } 270 usage4(_("Warning threshold percentage must be <= 100!"));
474 break;
475 } else {
476 /* It's Bytes */
477 warn.is_percentage = false;
478 if (is_uint64(optarg, &warn.value)) {
479 break;
480 } else {
481 usage4 (_("Warning threshold be positive integer or percentage!"));
482 } 271 }
483 } 272 }
273 break;
274 } /* It's Bytes */
275 conf_wrapper.config.warn.is_percentage = false;
276 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
277 break;
484 } 278 }
279 usage4(_("Warning threshold be positive integer or "
280 "percentage!"));
281 }
485 case 'c': /* critical size threshold */ 282 case 'c': /* critical size threshold */
486 { 283 {
487 /* 284 /*
488 * We expect either a positive integer value without a unit, which means 285 * We expect either a positive integer value without a unit, which
489 * the unit is Bytes or a positive integer value and a percentage sign (%), 286 * means the unit is Bytes or a positive integer value and a
490 * which means the value must be with 0 and 100 and is relative to the total swap 287 * percentage sign (%), which means the value must be with 0 and 100
491 */ 288 * and is relative to the total swap
492 size_t length; 289 */
493 length = strlen(optarg); 290 size_t length;
494 291 length = strlen(optarg);
495 if (optarg[length - 1] == '%') { 292 conf_wrapper.config.crit_is_set = true;
496 /* It's percentage */ 293
497 crit.is_percentage = true; 294 if (optarg[length - 1] == '%') {
498 optarg[length - 1] = '\0'; 295 /* It's percentage */
499 if (is_uint64(optarg, &crit.value)) { 296 conf_wrapper.config.crit.is_percentage = true;
500 if (crit.value> 100) { 297 optarg[length - 1] = '\0';
501 usage4 (_("Critical threshold percentage must be <= 100!")); 298 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
502 } 299 if (conf_wrapper.config.crit.value > HUNDRED_PERCENT) {
503 } 300 usage4(_("Critical threshold percentage must be <= 100!"));
504 break;
505 } else {
506 /* It's Bytes */
507 crit.is_percentage = false;
508 if (is_uint64(optarg, &crit.value)) {
509 break;
510 } else {
511 usage4 (_("Critical threshold be positive integer or percentage!"));
512 } 301 }
513 } 302 }
514 } 303 break;
515 case 'a': /* all swap */ 304 } /* It's Bytes */
516 allswaps = true; 305 conf_wrapper.config.crit.is_percentage = false;
306 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
307 break;
308 }
309 usage4(_("Critical threshold be positive integer or "
310 "percentage!"));
311 }
312 case 'a': /* all swap */
313 conf_wrapper.config.allswaps = true;
517 break; 314 break;
518 case 'n': 315 case 'n':
519 if ((no_swap_state = mp_translate_state(optarg)) == ERROR) { 316 if ((conf_wrapper.config.no_swap_state = mp_translate_state(optarg)) == ERROR) {
520 usage4 (_("no-swap result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 317 usage4(_("no-swap result must be a valid state name (OK, "
318 "WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
521 } 319 }
522 break; 320 break;
523 case 'v': /* verbose */ 321 case 'v': /* verbose */
524 verbose++; 322 verbose++;
525 break; 323 break;
526 case 'V': /* version */ 324 case output_format_index: {
527 print_revision (progname, NP_VERSION); 325 parsed_output_format parser = mp_parse_output_format(optarg);
528 exit (STATE_UNKNOWN); 326 if (!parser.parsing_success) {
529 case 'h': /* help */ 327 // TODO List all available formats here, maybe add anothoer usage function
530 print_help (); 328 printf("Invalid output format: %s\n", optarg);
531 exit (STATE_UNKNOWN); 329 exit(STATE_UNKNOWN);
532 case '?': /* error */ 330 }
533 usage5 (); 331
332 conf_wrapper.config.output_format_is_set = true;
333 conf_wrapper.config.output_format = parser.output_format;
334 break;
335 }
336 case 'V': /* version */
337 print_revision(progname, NP_VERSION);
338 exit(STATE_UNKNOWN);
339 case 'h': /* help */
340 print_help(conf_wrapper.config);
341 exit(STATE_UNKNOWN);
342 case '?': /* error */
343 usage5();
534 } 344 }
535 } 345 }
536 346
537 c = optind; 347 if ((conf_wrapper.config.warn.is_percentage == conf_wrapper.config.crit.is_percentage) &&
538 if (c == argc) 348 (conf_wrapper.config.warn.value < conf_wrapper.config.crit.value)) {
539 return validate_arguments (); 349 /* This is NOT triggered if warn and crit are different units, e.g warn
540 350 * is percentage and crit is absolute. We cannot determine the condition
541 return validate_arguments (); 351 * at this point since we dont know the value of total swap yet
542}
543
544
545
546int
547validate_arguments (void)
548{
549 if ((warn.is_percentage == crit.is_percentage) && (warn.value < crit.value)) {
550 /* This is NOT triggered if warn and crit are different units, e.g warn is percentage
551 * and crit is absolute. We cannot determine the condition at this point since we
552 * dont know the value of total swap yet
553 */ 352 */
554 usage4(_("Warning should be more than critical")); 353 usage4(_("Warning should be more than critical"));
555 } 354 }
556 return OK;
557}
558
559 355
560 356 return conf_wrapper;
561void
562print_help (void)
563{
564 print_revision (progname, NP_VERSION);
565
566 printf (_(COPYRIGHT), copyright, email);
567
568 printf ("%s\n", _("Check swap space on local machine."));
569
570 printf ("\n\n");
571
572 print_usage ();
573
574 printf (UT_HELP_VRSN);
575 printf (UT_EXTRA_OPTS);
576
577 printf (" %s\n", "-w, --warning=INTEGER");
578 printf (" %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
579 printf (" %s\n", "-w, --warning=PERCENT%");
580 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
581 printf (" %s\n", "-c, --critical=INTEGER");
582 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
583 printf (" %s\n", "-c, --critical=PERCENT%");
584 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of swap space is free"));
585 printf (" %s\n", "-a, --allswaps");
586 printf (" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
587 printf (" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
588 printf (" %s %s\n", _("Resulting state when there is no swap regardless of thresholds. Default:"), state_text(no_swap_state));
589 printf (UT_VERBOSE);
590
591 printf ("\n");
592 printf ("%s\n", _("Notes:"));
593 printf (" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, they are all checked."));
594 printf (" %s\n", _("Without thresholds, the plugin shows free swap space and performance data, but always returns OK."));
595 printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
596
597 printf (UT_SUPPORT);
598} 357}
599 358
359void print_help(swap_config config) {
360 print_revision(progname, NP_VERSION);
361
362 printf(_(COPYRIGHT), copyright, email);
363
364 printf("%s\n", _("Check swap space on local machine."));
365
366 printf("\n\n");
367
368 print_usage();
369
370 printf(UT_HELP_VRSN);
371 printf(UT_EXTRA_OPTS);
372
373 printf(" %s\n", "-w, --warning=INTEGER");
374 printf(" %s\n", _("Exit with WARNING status if less than INTEGER bytes "
375 "of swap space are free"));
376 printf(" %s\n", "-w, --warning=PERCENT%");
377 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of "
378 "swap space is free"));
379 printf(" %s\n", "-c, --critical=INTEGER");
380 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes "
381 "of swap space are free"));
382 printf(" %s\n", "-c, --critical=PERCENT%");
383 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of "
384 "swap space is free"));
385 printf(" %s\n", "-a, --allswaps");
386 printf(" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
387 printf(" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
388 printf(" %s %s\n",
389 _("Resulting state when there is no swap regardless of thresholds. "
390 "Default:"),
391 state_text(config.no_swap_state));
392 printf(UT_OUTPUT_FORMAT);
393 printf(UT_VERBOSE);
394
395 printf("\n");
396 printf("%s\n", _("Notes:"));
397 printf(" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, "
398 "they are all checked."));
399 printf(" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
400
401 printf(UT_SUPPORT);
402}
600 403
601void 404void print_usage(void) {
602print_usage (void) 405 printf("%s\n", _("Usage:"));
603{ 406 printf(" %s [-av] -w <percent_free>%% -c <percent_free>%%\n", progname);
604 printf ("%s\n", _("Usage:")); 407 printf(" -w <bytes_free> -c <bytes_free> [-n <state>]\n");
605 printf (" %s [-av] [-w <percent_free>%%] [-c <percent_free>%%]\n",progname);
606 printf (" [-w <bytes_free>] [-c <bytes_free>] [-n <state>]\n");
607} 408}
diff --git a/plugins/check_swap.d/check_swap.h b/plugins/check_swap.d/check_swap.h
new file mode 100644
index 00000000..da08d65a
--- /dev/null
+++ b/plugins/check_swap.d/check_swap.h
@@ -0,0 +1,48 @@
1#pragma once
2
3#include "../common.h"
4#include "../../lib/output.h"
5#include "../../lib/states.h"
6
7#ifndef SWAP_CONVERSION
8# define SWAP_CONVERSION 1
9#endif
10
11typedef struct {
12 bool is_percentage;
13 uint64_t value;
14} check_swap_threshold;
15
16typedef struct {
17 unsigned long long free; // Free swap in Bytes!
18 unsigned long long used; // Used swap in Bytes!
19 unsigned long long total; // Total swap size, you guessed it, in Bytes!
20} swap_metrics;
21
22typedef struct {
23 int errorcode;
24 int statusCode;
25 swap_metrics metrics;
26} swap_result;
27
28typedef struct {
29 bool allswaps;
30 mp_state_enum no_swap_state;
31 bool warn_is_set;
32 check_swap_threshold warn;
33 bool crit_is_set;
34 check_swap_threshold crit;
35 bool on_aix;
36 int conversion_factor;
37
38 bool output_format_is_set;
39 mp_output_format output_format;
40} swap_config;
41
42swap_config swap_config_init(void);
43
44swap_result get_swap_data(swap_config config);
45swap_result getSwapFromProcMeminfo(char path_to_proc_meminfo[]);
46swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]);
47swap_result getSwapFromSwapctl_BSD(swap_config config);
48swap_result getSwapFromSwap_SRV4(swap_config config);
diff --git a/plugins/check_swap.d/swap.c b/plugins/check_swap.d/swap.c
new file mode 100644
index 00000000..634f80d9
--- /dev/null
+++ b/plugins/check_swap.d/swap.c
@@ -0,0 +1,465 @@
1#include "./check_swap.d/check_swap.h"
2#include "../popen.h"
3#include "../utils.h"
4#include "common.h"
5
6extern int verbose;
7
8swap_config swap_config_init(void) {
9 swap_config tmp = {0};
10 tmp.allswaps = false;
11 tmp.no_swap_state = STATE_CRITICAL;
12 tmp.conversion_factor = SWAP_CONVERSION;
13
14 tmp.warn_is_set = false;
15 tmp.crit_is_set = false;
16
17 tmp.output_format_is_set = false;
18
19#ifdef _AIX
20 tmp.on_aix = true;
21#else
22 tmp.on_aix = false;
23#endif
24
25 return tmp;
26}
27
28swap_result get_swap_data(swap_config config) {
29#ifdef HAVE_PROC_MEMINFO
30 if (verbose >= 3) {
31 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
32 }
33
34 return getSwapFromProcMeminfo(PROC_MEMINFO);
35#else // HAVE_PROC_MEMINFO
36# ifdef HAVE_SWAP
37 if (verbose >= 3) {
38 printf("Using swap command %s with format: %s\n", SWAP_COMMAND, SWAP_FORMAT);
39 }
40
41 /* These override the command used if a summary (and thus ! allswaps) is
42 * required
43 * The summary flag returns more accurate information about swap usage on these
44 * OSes */
45 if (config.on_aix && !config.allswaps) {
46
47 config.conversion_factor = 1;
48
49 return getSwapFromSwapCommand(config, "/usr/sbin/lsps -s", "%lu%*s %lu");
50 } else {
51 return getSwapFromSwapCommand(config, SWAP_COMMAND, SWAP_FORMAT);
52 }
53# else // HAVE_SWAP
54# ifdef CHECK_SWAP_SWAPCTL_SVR4
55 return getSwapFromSwapctl_SRV4();
56# else // CHECK_SWAP_SWAPCTL_SVR4
57# ifdef CHECK_SWAP_SWAPCTL_BSD
58 return getSwapFromSwapctl_BSD();
59# else // CHECK_SWAP_SWAPCTL_BSD
60# error No way found to retrieve swap
61# endif /* CHECK_SWAP_SWAPCTL_BSD */
62# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
63# endif /* HAVE_SWAP */
64#endif /* HAVE_PROC_MEMINFO */
65}
66
67swap_result getSwapFromProcMeminfo(char proc_meminfo[]) {
68 FILE *meminfo_file_ptr;
69 meminfo_file_ptr = fopen(proc_meminfo, "r");
70
71 swap_result result = {};
72 result.errorcode = STATE_UNKNOWN;
73
74 if (meminfo_file_ptr == NULL) {
75 // failed to open meminfo file
76 // errno should contain an error
77 result.errorcode = STATE_UNKNOWN;
78 return result;
79 }
80
81 unsigned long swap_total = 0;
82 unsigned long swap_used = 0;
83 unsigned long swap_free = 0;
84
85 bool found_total = false;
86 bool found_free = false;
87
88 char input_buffer[MAX_INPUT_BUFFER];
89 char str[32];
90
91 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) {
92
93 /*
94 * The following sscanf call looks for a line looking like: "Swap: 123
95 * 123 123" which exists on NetBSD (at least),
96 * The unit should be Bytes
97 */
98 if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, &swap_free) == 3) {
99 found_total = true;
100 found_free = true;
101 // Set error
102 result.errorcode = STATE_OK;
103 // Break out of fgets here, since both scanf expressions might match (NetBSD for example)
104 break;
105 }
106
107 /*
108 * The following sscanf call looks for lines looking like:
109 * "SwapTotal: 123" and "SwapFree: 123" This format exists at least
110 * on Debian Linux with a 5.* kernel
111 */
112 unsigned long tmp_KB = 0;
113 int sscanf_result = sscanf(input_buffer,
114 "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu "
115 "%*[k]%*[B]",
116 str, &tmp_KB);
117
118 if (sscanf_result == 2) {
119
120 if (verbose >= 3) {
121 printf("Got %s with %lu\n", str, tmp_KB);
122 }
123
124 /* I think this part is always in Kb, so convert to bytes */
125 if (strcmp("Total", str) == 0) {
126 swap_total = tmp_KB * 1000;
127 found_total = true;
128 } else if (strcmp("Free", str) == 0) {
129 swap_free += tmp_KB * 1000;
130 found_free = true;
131 } else if (strcmp("Cached", str) == 0) {
132 swap_free += tmp_KB * 1000;
133 }
134
135 result.errorcode = STATE_OK;
136 }
137 }
138
139 fclose(meminfo_file_ptr);
140
141 result.metrics.total = swap_total;
142 result.metrics.free = swap_free;
143 result.metrics.used = swap_total - swap_free;
144
145 if (!found_free || !found_total) {
146 result.errorcode = STATE_UNKNOWN;
147 }
148
149 return result;
150}
151
152swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]) {
153 swap_result result = {0};
154
155 char *temp_buffer;
156
157 if (verbose >= 2) {
158 printf(_("Command: %s\n"), swap_command);
159 }
160 if (verbose >= 3) {
161 printf(_("Format: %s\n"), swap_format);
162 }
163
164 child_process = spopen(swap_command);
165 if (child_process == NULL) {
166 printf(_("Could not open pipe: %s\n"), swap_command);
167 swap_result tmp = {
168 .errorcode = STATE_UNKNOWN,
169 };
170 return tmp;
171 }
172
173 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
174 if (child_stderr == NULL) {
175 printf(_("Could not open stderr for %s\n"), swap_command);
176 }
177
178 char str[32] = {0};
179 char input_buffer[MAX_INPUT_BUFFER];
180
181 /* read 1st line */
182 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process);
183 if (strcmp(swap_format, "") == 0) {
184 temp_buffer = strtok(input_buffer, " \n");
185 while (temp_buffer) {
186 if (strstr(temp_buffer, "blocks")) {
187 sprintf(str, "%s %s", str, "%lu");
188 } else if (strstr(temp_buffer, "dskfree")) {
189 sprintf(str, "%s %s", str, "%lu");
190 } else {
191 sprintf(str, "%s %s", str, "%*s");
192 }
193 temp_buffer = strtok(NULL, " \n");
194 }
195 }
196
197 double total_swap_mb = 0;
198 double free_swap_mb = 0;
199 double used_swap_mb = 0;
200 double dsktotal_mb = 0;
201 double dskused_mb = 0;
202 double dskfree_mb = 0;
203
204 /*
205 * If different swap command is used for summary switch, need to read format
206 * differently
207 */
208 if (config.on_aix && !config.allswaps) {
209 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */
210 sscanf(input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
211 free_swap_mb = total_swap_mb * (100 - used_swap_mb) / 100;
212 used_swap_mb = total_swap_mb - free_swap_mb;
213
214 if (verbose >= 3) {
215 printf(_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
216 }
217 } else {
218 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
219 sscanf(input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
220
221 dsktotal_mb = dsktotal_mb / config.conversion_factor;
222 /* AIX lists percent used, so this converts to dskfree in MBs */
223
224 if (config.on_aix) {
225 dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
226 } else {
227 dskfree_mb = dskfree_mb / config.conversion_factor;
228 }
229
230 if (verbose >= 3) {
231 printf(_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
232 }
233
234 dskused_mb = dsktotal_mb - dskfree_mb;
235 total_swap_mb += dsktotal_mb;
236 used_swap_mb += dskused_mb;
237 free_swap_mb += dskfree_mb;
238 }
239 }
240
241 result.metrics.free = free_swap_mb * 1024 * 1024;
242 result.metrics.used = used_swap_mb * 1024 * 1024;
243 result.metrics.total = free_swap_mb * 1024 * 1024;
244
245 /* If we get anything on STDERR, at least set warning */
246 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
247 result.statusCode = max_state(result.statusCode, STATE_WARNING);
248 // TODO Set error here
249 }
250
251 /* close stderr */
252 (void)fclose(child_stderr);
253
254 /* close the pipe */
255 if (spclose(child_process)) {
256 result.statusCode = max_state(result.statusCode, STATE_WARNING);
257 // TODO set error here
258 }
259
260 return result;
261}
262
263#ifndef CHECK_SWAP_SWAPCTL_BSD
264# define CHECK_SWAP_SWAPCTL_BSD
265
266// Stub functionality for BSD stuff, so the compiler always sees the following BSD code
267
268# define SWAP_NSWAP 0
269# define SWAP_STATS 1
270
271int bsd_swapctl(int cmd, const void *arg, int misc) {
272 (void)cmd;
273 (void)arg;
274 (void)misc;
275 return 512;
276}
277
278struct swapent {
279 dev_t se_dev; /* device id */
280 int se_flags; /* entry flags */
281 int se_nblks; /* total blocks */
282 int se_inuse; /* blocks in use */
283 int se_priority; /* priority */
284 char se_path[PATH_MAX]; /* path to entry */
285};
286
287#else
288
289// Includes for NetBSD
290# include <unistd.h>
291# include <sys/swap.h>
292
293# define bsd_swapctl swapctl
294
295#endif // CHECK_SWAP_SWAPCTL_BSD
296
297swap_result getSwapFromSwapctl_BSD(swap_config config) {
298 /* get the number of active swap devices */
299 int nswaps = bsd_swapctl(SWAP_NSWAP, NULL, 0);
300
301 /* initialize swap table + entries */
302 struct swapent *ent = (struct swapent *)malloc(sizeof(struct swapent) * (unsigned long)nswaps);
303
304 /* and now, tally 'em up */
305 int swapctl_res = bsd_swapctl(SWAP_STATS, ent, nswaps);
306 if (swapctl_res < 0) {
307 perror(_("swapctl failed: "));
308 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
309 }
310
311 double dsktotal_mb = 0.0;
312 double dskfree_mb = 0.0;
313 double dskused_mb = 0.0;
314 unsigned long long total_swap_mb = 0;
315 unsigned long long free_swap_mb = 0;
316 unsigned long long used_swap_mb = 0;
317
318 for (int i = 0; i < nswaps; i++) {
319 dsktotal_mb = (double)ent[i].se_nblks / (double)config.conversion_factor;
320 dskused_mb = (double)ent[i].se_inuse / (double)config.conversion_factor;
321 dskfree_mb = (dsktotal_mb - dskused_mb);
322
323 if (config.allswaps && dsktotal_mb > 0) {
324 double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb));
325
326 if (verbose) {
327 printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent);
328 }
329 }
330
331 total_swap_mb += (unsigned long long)dsktotal_mb;
332 free_swap_mb += (unsigned long long)dskfree_mb;
333 used_swap_mb += (unsigned long long)dskused_mb;
334 }
335
336 /* and clean up after ourselves */
337 free(ent);
338
339 swap_result result = {0};
340
341 result.statusCode = OK;
342 result.errorcode = OK;
343
344 result.metrics.total = total_swap_mb * 1024 * 1024;
345 result.metrics.free = free_swap_mb * 1024 * 1024;
346 result.metrics.used = used_swap_mb * 1024 * 1024;
347
348 return result;
349}
350
351#ifndef CHECK_SWAP_SWAPCTL_SVR4
352int srv4_swapctl(int cmd, void *arg) {
353 (void)cmd;
354 (void)arg;
355 return 512;
356}
357
358typedef struct srv4_swapent {
359 char *ste_path; /* name of the swap file */
360 off_t ste_start; /* starting block for swapping */
361 off_t ste_length; /* length of swap area */
362 long ste_pages; /* number of pages for swapping */
363 long ste_free; /* number of ste_pages free */
364 long ste_flags; /* ST_INDEL bit set if swap file */
365 /* is now being deleted */
366} swapent_t;
367
368typedef struct swaptbl {
369 int swt_n; /* number of swapents following */
370 struct srv4_swapent swt_ent[]; /* array of swt_n swapents */
371} swaptbl_t;
372
373# define SC_LIST 2
374# define SC_GETNSWP 3
375
376# ifndef MAXPATHLEN
377# define MAXPATHLEN 2048
378# endif
379
380#else
381# define srv4_swapctl swapctl
382#endif
383
384swap_result getSwapFromSwap_SRV4(swap_config config) {
385 int nswaps = 0;
386
387 /* get the number of active swap devices */
388 if ((nswaps = srv4_swapctl(SC_GETNSWP, NULL)) == -1) {
389 die(STATE_UNKNOWN, _("Error getting swap devices\n"));
390 }
391
392 if (nswaps == 0) {
393 die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
394 }
395
396 if (verbose >= 3) {
397 printf("Found %d swap device(s)\n", nswaps);
398 }
399
400 /* initialize swap table + entries */
401 swaptbl_t *tbl = (swaptbl_t *)malloc(sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
402
403 if (tbl == NULL) {
404 die(STATE_UNKNOWN, _("malloc() failed!\n"));
405 }
406
407 memset(tbl, 0, sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps));
408 tbl->swt_n = nswaps;
409
410 for (int i = 0; i < nswaps; i++) {
411 if ((tbl->swt_ent[i].ste_path = (char *)malloc(sizeof(char) * MAXPATHLEN)) == NULL) {
412 die(STATE_UNKNOWN, _("malloc() failed!\n"));
413 }
414 }
415
416 /* and now, tally 'em up */
417 int swapctl_res = srv4_swapctl(SC_LIST, tbl);
418 if (swapctl_res < 0) {
419 perror(_("swapctl failed: "));
420 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
421 }
422
423 double dsktotal_mb = 0.0;
424 double dskfree_mb = 0.0;
425 double dskused_mb = 0.0;
426 unsigned long long total_swap_mb = 0;
427 unsigned long long free_swap_mb = 0;
428 unsigned long long used_swap_mb = 0;
429
430 for (int i = 0; i < nswaps; i++) {
431 dsktotal_mb = (float)tbl->swt_ent[i].ste_pages / SWAP_CONVERSION;
432 dskfree_mb = (float)tbl->swt_ent[i].ste_free / SWAP_CONVERSION;
433 dskused_mb = (dsktotal_mb - dskfree_mb);
434
435 if (verbose >= 3) {
436 printf("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
437 }
438
439 if (config.allswaps && dsktotal_mb > 0) {
440 double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb));
441
442 if (verbose) {
443 printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent);
444 }
445 }
446
447 total_swap_mb += (unsigned long long)dsktotal_mb;
448 free_swap_mb += (unsigned long long)dskfree_mb;
449 used_swap_mb += (unsigned long long)dskused_mb;
450 }
451
452 /* and clean up after ourselves */
453 for (int i = 0; i < nswaps; i++) {
454 free(tbl->swt_ent[i].ste_path);
455 }
456 free(tbl);
457
458 swap_result result = {0};
459 result.errorcode = OK;
460 result.metrics.total = total_swap_mb * 1024 * 1024;
461 result.metrics.free = free_swap_mb * 1024 * 1024;
462 result.metrics.used = used_swap_mb * 1024 * 1024;
463
464 return result;
465}
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
index 01dd35eb..22dcc74e 100644
--- a/plugins/check_tcp.c
+++ b/plugins/check_tcp.c
@@ -1,714 +1,797 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_tcp plugin 3 * Monitoring check_tcp plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2013 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2025 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_tcp plugin 10 * This file contains the check_tcp plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* $Id$ 26 * $Id$
27* 27 *
28*****************************************************************************/ 28 *****************************************************************************/
29 29
30/* progname "check_tcp" changes depending on symlink called */ 30/* progname "check_tcp" changes depending on symlink called */
31char *progname; 31char *progname;
32const char *copyright = "1999-2008"; 32const char *copyright = "1999-2025";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "./common.h"
36#include "netutils.h" 36#include "./netutils.h"
37#include "utils.h" 37#include "./utils.h"
38#include "utils_tcp.h" 38#include "./check_tcp.d/config.h"
39#include "output.h"
40#include "states.h"
39 41
42#include <sys/types.h>
40#include <ctype.h> 43#include <ctype.h>
41#include <sys/select.h> 44#include <sys/select.h>
42 45
46ssize_t my_recv(int socket_descriptor, char *buf, size_t len, bool use_tls) {
43#ifdef HAVE_SSL 47#ifdef HAVE_SSL
44static bool check_cert = false; 48 if (use_tls) {
45static int days_till_exp_warn, days_till_exp_crit; 49 return np_net_ssl_read(buf, (int)len);
46# define my_recv(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 50 }
47# define my_send(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
48#else
49# define my_recv(buf, len) read(sd, buf, len)
50# define my_send(buf, len) send(sd, buf, len, 0)
51#endif 51#endif
52 return read(socket_descriptor, buf, len);
53}
52 54
53/* int my_recv(char *, size_t); */ 55ssize_t my_send(int socket_descriptor, char *buf, size_t len, bool use_tls) {
54static int process_arguments (int, char **);
55void print_help (void);
56void print_usage (void);
57
58#define EXPECT server_expect[0]
59static char *SERVICE = "TCP";
60static char *SEND = NULL;
61static char *QUIT = NULL;
62static int PROTOCOL = IPPROTO_TCP; /* most common is default */
63static int PORT = 0;
64static int READ_TIMEOUT = 2;
65
66static int server_port = 0;
67static char *server_address = NULL;
68static bool host_specified = false;
69static char *server_send = NULL;
70static char *server_quit = NULL;
71static char **server_expect;
72static size_t server_expect_count = 0;
73static ssize_t maxbytes = 0;
74static char **warn_codes = NULL;
75static size_t warn_codes_count = 0;
76static char **crit_codes = NULL;
77static size_t crit_codes_count = 0;
78static unsigned int delay = 0;
79static double warning_time = 0;
80static double critical_time = 0;
81static double elapsed_time = 0;
82static long microsec;
83static int sd = 0;
84#define MAXBUF 1024
85static char buffer[MAXBUF];
86static int expect_mismatch_state = STATE_WARNING;
87static int match_flags = NP_MATCH_EXACT;
88
89#ifdef HAVE_SSL 56#ifdef HAVE_SSL
90static char *sni = NULL; 57 if (use_tls) {
91static bool sni_specified = false; 58 return np_net_ssl_write(buf, (int)len);
59 }
92#endif 60#endif
61 return write(socket_descriptor, buf, len);
62}
93 63
94#define FLAG_SSL 0x01 64typedef struct {
95#define FLAG_VERBOSE 0x02 65 int errorcode;
96#define FLAG_TIME_WARN 0x04 66 check_tcp_config config;
97#define FLAG_TIME_CRIT 0x08 67} check_tcp_config_wrapper;
98#define FLAG_HIDE_OUTPUT 0x10 68static check_tcp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/, check_tcp_config /*config*/);
99static size_t flags; 69void print_help(const char *service);
100 70void print_usage(void);
101int 71
102main (int argc, char **argv) 72int verbosity = 0;
103{ 73
104 int result = STATE_UNKNOWN; 74static const int READ_TIMEOUT = 2;
105 char *status = NULL; 75
106 struct timeval tv; 76const int MAXBUF = 1024;
107 struct timeval timeout; 77
108 int match = -1; 78const int DEFAULT_FTP_PORT = 21;
109 fd_set rfds; 79const int DEFAULT_POP_PORT = 110;
110 80const int DEFAULT_SPOP_PORT = 995;
111 FD_ZERO(&rfds); 81const int DEFAULT_SMTP_PORT = 25;
112 82const int DEFAULT_SSMTP_PORT = 465;
113 setlocale (LC_ALL, ""); 83const int DEFAULT_IMAP_PORT = 143;
114 bindtextdomain (PACKAGE, LOCALEDIR); 84const int DEFAULT_SIMAP_PORT = 993;
115 textdomain (PACKAGE); 85const int DEFAULT_XMPP_C2S_PORT = 5222;
86const int DEFAULT_NNTP_PORT = 119;
87const int DEFAULT_NNTPS_PORT = 563;
88const int DEFAULT_CLAMD_PORT = 3310;
89
90int main(int argc, char **argv) {
91 setlocale(LC_ALL, "");
92 bindtextdomain(PACKAGE, LOCALEDIR);
93 textdomain(PACKAGE);
116 94
117 /* determine program- and service-name quickly */ 95 /* determine program- and service-name quickly */
118 progname = strrchr(argv[0], '/'); 96 progname = strrchr(argv[0], '/');
119 if(progname != NULL) progname++; 97 if (progname != NULL) {
120 else progname = argv[0]; 98 progname++;
99 } else {
100 progname = argv[0];
101 }
102
103 // Initialize config here with values from above,
104 // might be changed by on disk config or cli commands
105 check_tcp_config config = check_tcp_config_init();
121 106
122 size_t prog_name_len = strlen(progname); 107 size_t prog_name_len = strlen(progname);
123 if(prog_name_len > 6 && !memcmp(progname, "check_", 6)) { 108 const size_t prefix_length = strlen("check_");
124 SERVICE = strdup(progname + 6); 109
125 for(size_t i = 0; i < prog_name_len - 6; i++) 110 if (prog_name_len <= prefix_length) {
126 SERVICE[i] = toupper(SERVICE[i]); 111 die(STATE_UNKNOWN, _("Weird progname"));
112 }
113
114 if (!memcmp(progname, "check_", prefix_length)) {
115 config.service = strdup(progname + prefix_length);
116 if (config.service == NULL) {
117 die(STATE_UNKNOWN, _("Allocation failed"));
118 }
119
120 for (size_t i = 0; i < prog_name_len - prefix_length; i++) {
121 config.service[i] = toupper(config.service[i]);
122 }
127 } 123 }
128 124
129 /* set up a reasonable buffer at first (will be realloc()'ed if 125 /* set up a reasonable buffer at first (will be realloc()'ed if
130 * user specifies other options) */ 126 * user specifies other options) */
131 server_expect = calloc(sizeof(char *), 2); 127 config.server_expect = calloc(2, sizeof(char *));
132 128
133 /* determine defaults for this service's protocol */ 129 if (config.server_expect == NULL) {
134 if (!strncmp(SERVICE, "UDP", 3)) { 130 die(STATE_UNKNOWN, _("Allocation failed"));
135 PROTOCOL = IPPROTO_UDP;
136 }
137 else if (!strncmp(SERVICE, "FTP", 3)) {
138 EXPECT = "220";
139 QUIT = "QUIT\r\n";
140 PORT = 21;
141 }
142 else if (!strncmp(SERVICE, "POP", 3) || !strncmp(SERVICE, "POP3", 4)) {
143 EXPECT = "+OK";
144 QUIT = "QUIT\r\n";
145 PORT = 110;
146 }
147 else if (!strncmp(SERVICE, "SMTP", 4)) {
148 EXPECT = "220";
149 QUIT = "QUIT\r\n";
150 PORT = 25;
151 } 131 }
152 else if (!strncmp(SERVICE, "IMAP", 4)) { 132
153 EXPECT = "* OK"; 133 /* determine defaults for this service's protocol */
154 QUIT = "a1 LOGOUT\r\n"; 134 if (!strncmp(config.service, "UDP", strlen("UDP"))) {
155 PORT = 143; 135 config.protocol = IPPROTO_UDP;
136 } else if (!strncmp(config.service, "FTP", strlen("FTP"))) {
137 config.server_expect[0] = "220";
138 config.quit = "QUIT\r\n";
139 config.server_port = DEFAULT_FTP_PORT;
140 } else if (!strncmp(config.service, "POP", strlen("POP")) || !strncmp(config.service, "POP3", strlen("POP3"))) {
141 config.server_expect[0] = "+OK";
142 config.quit = "QUIT\r\n";
143 config.server_port = DEFAULT_POP_PORT;
144 } else if (!strncmp(config.service, "SMTP", strlen("SMTP"))) {
145 config.server_expect[0] = "220";
146 config.quit = "QUIT\r\n";
147 config.server_port = DEFAULT_SMTP_PORT;
148 } else if (!strncmp(config.service, "IMAP", strlen("IMAP"))) {
149 config.server_expect[0] = "* OK";
150 config.quit = "a1 LOGOUT\r\n";
151 config.server_port = DEFAULT_IMAP_PORT;
156 } 152 }
157#ifdef HAVE_SSL 153#ifdef HAVE_SSL
158 else if (!strncmp(SERVICE, "SIMAP", 5)) { 154 else if (!strncmp(config.service, "SIMAP", strlen("SIMAP"))) {
159 EXPECT = "* OK"; 155 config.server_expect[0] = "* OK";
160 QUIT = "a1 LOGOUT\r\n"; 156 config.quit = "a1 LOGOUT\r\n";
161 flags |= FLAG_SSL; 157 config.use_tls = true;
162 PORT = 993; 158 config.server_port = DEFAULT_SIMAP_PORT;
163 } 159 } else if (!strncmp(config.service, "SPOP", strlen("SPOP"))) {
164 else if (!strncmp(SERVICE, "SPOP", 4)) { 160 config.server_expect[0] = "+OK";
165 EXPECT = "+OK"; 161 config.quit = "QUIT\r\n";
166 QUIT = "QUIT\r\n"; 162 config.use_tls = true;
167 flags |= FLAG_SSL; 163 config.server_port = DEFAULT_SPOP_PORT;
168 PORT = 995; 164 } else if (!strncmp(config.service, "SSMTP", strlen("SSMTP"))) {
169 } 165 config.server_expect[0] = "220";
170 else if (!strncmp(SERVICE, "SSMTP", 5)) { 166 config.quit = "QUIT\r\n";
171 EXPECT = "220"; 167 config.use_tls = true;
172 QUIT = "QUIT\r\n"; 168 config.server_port = DEFAULT_SSMTP_PORT;
173 flags |= FLAG_SSL; 169 } else if (!strncmp(config.service, "JABBER", strlen("JABBER"))) {
174 PORT = 465; 170 config.send = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n";
175 } 171 config.server_expect[0] = "<?xml version=\'1.0\'";
176 else if (!strncmp(SERVICE, "JABBER", 6)) { 172 config.quit = "</stream:stream>\n";
177 SEND = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n"; 173 config.hide_output = true;
178 EXPECT = "<?xml version=\'1.0\'"; 174 config.server_port = DEFAULT_XMPP_C2S_PORT;
179 QUIT = "</stream:stream>\n"; 175 } else if (!strncmp(config.service, "NNTPS", strlen("NNTPS"))) {
180 flags |= FLAG_HIDE_OUTPUT; 176 config.server_expect_count = 2;
181 PORT = 5222; 177 config.server_expect[0] = "200";
182 } 178 config.server_expect[1] = "201";
183 else if (!strncmp (SERVICE, "NNTPS", 5)) { 179 config.quit = "QUIT\r\n";
184 server_expect_count = 2; 180 config.use_tls = true;
185 server_expect[0] = "200"; 181 config.server_port = DEFAULT_NNTPS_PORT;
186 server_expect[1] = "201";
187 QUIT = "QUIT\r\n";
188 flags |= FLAG_SSL;
189 PORT = 563;
190 } 182 }
191#endif 183#endif
192 else if (!strncmp (SERVICE, "NNTP", 4)) { 184 else if (!strncmp(config.service, "NNTP", strlen("NNTP"))) {
193 server_expect_count = 2; 185 config.server_expect_count = 2;
194 server_expect = malloc(sizeof(char *) * server_expect_count); 186 char **tmp = realloc(config.server_expect, config.server_expect_count * sizeof(char *));
195 server_expect[0] = strdup("200"); 187 if (tmp == NULL) {
196 server_expect[1] = strdup("201"); 188 free(config.server_expect);
197 QUIT = "QUIT\r\n"; 189 die(STATE_UNKNOWN, _("Allocation failed"));
198 PORT = 119; 190 }
199 } 191 config.server_expect = tmp;
200 else if (!strncmp(SERVICE, "CLAMD", 5)) { 192
201 SEND = "PING"; 193 config.server_expect[0] = strdup("200");
202 EXPECT = "PONG"; 194 config.server_expect[1] = strdup("201");
203 QUIT = NULL; 195 config.quit = "QUIT\r\n";
204 PORT = 3310; 196 config.server_port = DEFAULT_NNTP_PORT;
197 } else if (!strncmp(config.service, "CLAMD", strlen("CLAMD"))) {
198 config.send = "PING";
199 config.server_expect[0] = "PONG";
200 config.quit = NULL;
201 config.server_port = DEFAULT_CLAMD_PORT;
205 } 202 }
206 /* fallthrough check, so it's supposed to use reverse matching */ 203 /* fallthrough check, so it's supposed to use reverse matching */
207 else if (strcmp (SERVICE, "TCP")) 204 else if (strcmp(config.service, "TCP")) {
208 usage (_("CRITICAL - Generic check_tcp called with unknown service\n")); 205 usage(_("CRITICAL - Generic check_tcp called with unknown service\n"));
209 206 }
210 server_address = "127.0.0.1";
211 server_port = PORT;
212 server_send = SEND;
213 server_quit = QUIT;
214 status = NULL;
215 207
216 /* Parse extra opts if any */ 208 /* Parse extra opts if any */
217 argv=np_extra_opts (&argc, argv, progname); 209 argv = np_extra_opts(&argc, argv, progname);
210
211 check_tcp_config_wrapper paw = process_arguments(argc, argv, config);
212 if (paw.errorcode == ERROR) {
213 usage4(_("Could not parse arguments"));
214 }
218 215
219 if (process_arguments (argc, argv) == ERROR) 216 config = paw.config;
220 usage4 (_("Could not parse arguments"));
221 217
222 if(flags & FLAG_VERBOSE) { 218 if (verbosity > 0) {
223 printf("Using service %s\n", SERVICE); 219 printf("Using service %s\n", config.service);
224 printf("Port: %d\n", server_port); 220 printf("Port: %d\n", config.server_port);
225 printf("flags: 0x%x\n", (int)flags);
226 } 221 }
227 222
228 if(EXPECT && !server_expect_count) 223 if ((config.server_expect_count == 0) && config.server_expect[0]) {
229 server_expect_count++; 224 config.server_expect_count++;
225 }
230 226
231 if(PROTOCOL==IPPROTO_UDP && !(server_expect_count && server_send)){ 227 if (config.protocol == IPPROTO_UDP && !(config.server_expect_count && config.send)) {
232 usage(_("With UDP checks, a send/expect string must be specified.")); 228 usage(_("With UDP checks, a send/expect string must be specified."));
233 } 229 }
234 230
231 // Initialize check stuff before setting timers
232 mp_check overall = mp_check_init();
233 if (config.output_format_set) {
234 mp_set_format(config.output_format);
235 }
236
235 /* set up the timer */ 237 /* set up the timer */
236 signal (SIGALRM, socket_timeout_alarm_handler); 238 signal(SIGALRM, socket_timeout_alarm_handler);
237 alarm (socket_timeout); 239 alarm(socket_timeout);
238 240
239 /* try to connect to the host at the given port number */ 241 /* try to connect to the host at the given port number */
240 gettimeofday (&tv, NULL); 242 struct timeval start_time;
241 243 gettimeofday(&start_time, NULL);
242 result = np_net_connect (server_address, server_port, &sd, PROTOCOL); 244
243 if (result == STATE_CRITICAL) return econn_refuse_state; 245 int socket_descriptor = 0;
246 mp_subcheck inital_connect_result = mp_subcheck_init();
247
248 // Try initial connection
249 if (np_net_connect(config.server_address, config.server_port, &socket_descriptor, config.protocol) == STATE_CRITICAL) {
250 // Early exit here, we got connection refused
251 inital_connect_result = mp_set_subcheck_state(inital_connect_result, config.econn_refuse_state);
252 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was REFUSED", config.server_address, config.server_port);
253 mp_add_subcheck_to_check(&overall, inital_connect_result);
254 mp_exit(overall);
255 } else {
256 inital_connect_result = mp_set_subcheck_state(inital_connect_result, STATE_OK);
257 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was a SUCCESS", config.server_address, config.server_port);
258 mp_add_subcheck_to_check(&overall, inital_connect_result);
259 }
244 260
245#ifdef HAVE_SSL 261#ifdef HAVE_SSL
246 if (flags & FLAG_SSL){ 262 if (config.use_tls) {
247 result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL)); 263 mp_subcheck tls_connection_result = mp_subcheck_init();
248 if (result == STATE_OK && check_cert) { 264 mp_state_enum result = np_net_ssl_init_with_hostname(socket_descriptor, (config.sni_specified ? config.sni : NULL));
249 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 265 tls_connection_result = mp_set_subcheck_default_state(tls_connection_result, result);
266
267 if (result == STATE_OK) {
268 xasprintf(&tls_connection_result.output, "TLS connection succeeded");
269
270 if (config.check_cert) {
271 result = np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
272
273 mp_subcheck tls_certificate_lifetime_result = mp_subcheck_init();
274 tls_certificate_lifetime_result = mp_set_subcheck_state(tls_certificate_lifetime_result, result);
275
276 if (result == STATE_OK) {
277 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is within thresholds");
278 } else if (result == STATE_WARNING) {
279 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating warning threshold (%i)",
280 config.days_till_exp_warn);
281 } else if (result == STATE_CRITICAL) {
282 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating critical threshold (%i)",
283 config.days_till_exp_crit);
284 } else {
285 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is somehow unknown");
286 }
287
288 mp_add_subcheck_to_subcheck(&tls_connection_result, tls_certificate_lifetime_result);
289 }
290
291 mp_add_subcheck_to_check(&overall, tls_connection_result);
292 } else {
293 xasprintf(&tls_connection_result.output, "TLS connection failed");
294 mp_add_subcheck_to_check(&overall, tls_connection_result);
295
296 if (socket_descriptor) {
297 close(socket_descriptor);
298 }
299 np_net_ssl_cleanup();
300
301 mp_exit(overall);
250 } 302 }
251 } 303 }
252 if(result != STATE_OK){
253 if(sd) close(sd);
254 np_net_ssl_cleanup();
255 return result;
256 }
257#endif /* HAVE_SSL */ 304#endif /* HAVE_SSL */
258 305
259 if (server_send != NULL) { /* Something to send? */ 306 if (config.send != NULL) { /* Something to send? */
260 my_send(server_send, strlen(server_send)); 307 my_send(socket_descriptor, config.send, strlen(config.send), config.use_tls);
261 } 308 }
262 309
263 if (delay > 0) { 310 if (config.delay > 0) {
264 tv.tv_sec += delay; 311 start_time.tv_sec += config.delay;
265 sleep (delay); 312 sleep(config.delay);
266 } 313 }
267 314
268 if(flags & FLAG_VERBOSE) { 315 if (verbosity > 0) {
269 if (server_send) { 316 if (config.send) {
270 printf("Send string: %s\n", server_send); 317 printf("Send string: %s\n", config.send);
318 }
319 if (config.quit) {
320 printf("Quit string: %s\n", config.quit);
271 } 321 }
272 if (server_quit) { 322 printf("server_expect_count: %d\n", (int)config.server_expect_count);
273 printf("Quit string: %s\n", server_quit); 323 for (size_t i = 0; i < config.server_expect_count; i++) {
324 printf("\t%zd: %s\n", i, config.server_expect[i]);
274 } 325 }
275 printf("server_expect_count: %d\n", (int)server_expect_count);
276 for(size_t i = 0; i < server_expect_count; i++)
277 printf("\t%zd: %s\n", i, server_expect[i]);
278 } 326 }
279 327
280 /* if(len) later on, we know we have a non-NULL response */ 328 /* if(len) later on, we know we have a non-NULL response */
281 ssize_t len = 0; 329 ssize_t len = 0;
330 char *received_buffer = NULL;
331 enum np_match_result match = NP_MATCH_NONE;
332 mp_subcheck expected_data_result = mp_subcheck_init();
282 333
283 if (server_expect_count) { 334 if (config.server_expect_count) {
284 ssize_t received = 0; 335 ssize_t received = 0;
336 char buffer[MAXBUF];
285 337
286 /* watch for the expect string */ 338 /* watch for the expect string */
287 while ((received = my_recv(buffer, sizeof(buffer))) > 0) { 339 while ((received = my_recv(socket_descriptor, buffer, sizeof(buffer), config.use_tls)) > 0) {
288 status = realloc(status, len + received + 1); 340 received_buffer = realloc(received_buffer, len + received + 1);
289 memcpy(&status[len], buffer, received); 341
342 if (received_buffer == NULL) {
343 die(STATE_UNKNOWN, _("Allocation failed"));
344 }
345
346 memcpy(&received_buffer[len], buffer, received);
290 len += received; 347 len += received;
291 status[len] = '\0'; 348 received_buffer[len] = '\0';
292 349
293 /* stop reading if user-forced */ 350 /* stop reading if user-forced */
294 if (maxbytes && len >= maxbytes) 351 if (config.maxbytes && len >= config.maxbytes) {
295 break; 352 break;
353 }
296 354
297 if ((match = np_expect_match(status, 355 if ((match = np_expect_match(received_buffer, config.server_expect, config.server_expect_count, config.match_flags)) !=
298 server_expect, 356 NP_MATCH_RETRY) {
299 server_expect_count,
300 match_flags)) != NP_MATCH_RETRY)
301 break; 357 break;
358 }
359
360 fd_set rfds;
361 FD_ZERO(&rfds);
362 FD_SET(socket_descriptor, &rfds);
302 363
303 /* some protocols wait for further input, so make sure we don't wait forever */ 364 /* some protocols wait for further input, so make sure we don't wait forever */
304 FD_SET(sd, &rfds); 365 struct timeval timeout;
305 timeout.tv_sec = READ_TIMEOUT; 366 timeout.tv_sec = READ_TIMEOUT;
306 timeout.tv_usec = 0; 367 timeout.tv_usec = 0;
307 if(select(sd + 1, &rfds, NULL, NULL, &timeout) <= 0) 368
369 if (select(socket_descriptor + 1, &rfds, NULL, NULL, &timeout) <= 0) {
308 break; 370 break;
371 }
309 } 372 }
310 373
311 if (match == NP_MATCH_RETRY) 374 if (match == NP_MATCH_RETRY) {
312 match = NP_MATCH_FAILURE; 375 match = NP_MATCH_FAILURE;
376 }
313 377
314 /* no data when expected, so return critical */ 378 /* no data when expected, so return critical */
315 if (len == 0) 379 if (len == 0) {
316 die (STATE_CRITICAL, _("No data received from host\n")); 380 xasprintf(&expected_data_result.output, "Received no data when some was expected");
381 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_CRITICAL);
382 mp_add_subcheck_to_check(&overall, expected_data_result);
383 mp_exit(overall);
384 }
317 385
318 /* print raw output if we're debugging */ 386 /* print raw output if we're debugging */
319 if(flags & FLAG_VERBOSE) 387 if (verbosity > 0) {
320 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", 388 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", (int)len + 1, received_buffer);
321 (int)len + 1, status); 389 }
322 /* strip whitespace from end of output */ 390 /* strip whitespace from end of output */
323 while(--len > 0 && isspace(status[len])) 391 while (--len > 0 && isspace(received_buffer[len])) {
324 status[len] = '\0'; 392 received_buffer[len] = '\0';
393 }
394 }
395
396 if (config.quit != NULL) {
397 my_send(socket_descriptor, config.quit, strlen(config.quit), config.use_tls);
325 } 398 }
326 399
327 if (server_quit != NULL) { 400 if (socket_descriptor) {
328 my_send(server_quit, strlen(server_quit)); 401 close(socket_descriptor);
329 } 402 }
330 if (sd) close (sd);
331#ifdef HAVE_SSL 403#ifdef HAVE_SSL
332 np_net_ssl_cleanup(); 404 np_net_ssl_cleanup();
333#endif 405#endif
334 406
335 microsec = deltime (tv); 407 long microsec = deltime(start_time);
336 elapsed_time = (double)microsec / 1.0e6; 408 double elapsed_time = (double)microsec / 1.0e6;
337 409
338 if (flags & FLAG_TIME_CRIT && elapsed_time > critical_time) 410 mp_subcheck elapsed_time_result = mp_subcheck_init();
339 result = STATE_CRITICAL;
340 else if (flags & FLAG_TIME_WARN && elapsed_time > warning_time)
341 result = STATE_WARNING;
342 411
343 /* did we get the response we hoped? */ 412 mp_perfdata time_pd = perfdata_init();
344 if(match == NP_MATCH_FAILURE && result != STATE_CRITICAL) 413 time_pd = mp_set_pd_value(time_pd, elapsed_time);
345 result = expect_mismatch_state; 414 time_pd.label = "time";
415 time_pd.uom = "s";
346 416
347 /* reset the alarm */ 417 if (config.critical_time_set && elapsed_time > config.critical_time) {
348 alarm (0); 418 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded critical threshold (%f)", elapsed_time, config.critical_time);
349 419
350 /* this is a bit stupid, because we don't want to print the 420 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_CRITICAL);
351 * response time (which can look ok to the user) if we didn't get 421 time_pd.crit_present = true;
352 * the response we were looking for. if-else */ 422 mp_range crit_val = mp_range_init();
353 printf("%s %s - ", SERVICE, state_text(result)); 423
354 424 crit_val.end = mp_create_pd_value(config.critical_time);
355 if(match == NP_MATCH_FAILURE && len && !(flags & FLAG_HIDE_OUTPUT)) 425 crit_val.end_infinity = false;
356 printf("Unexpected response from host/socket: %s", status); 426
357 else { 427 time_pd.crit = crit_val;
358 if(match == NP_MATCH_FAILURE) 428 } else if (config.warning_time_set && elapsed_time > config.warning_time) {
359 printf("Unexpected response from host/socket on "); 429 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded warning threshold (%f)", elapsed_time, config.critical_time);
360 else 430
361 printf("%.3f second response time on ", elapsed_time); 431 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_WARNING);
362 if(server_address[0] != '/') { 432 time_pd.warn_present = true;
363 if (host_specified) 433 mp_range warn_val = mp_range_init();
364 printf("%s port %d", 434 warn_val.end = mp_create_pd_value(config.critical_time);
365 server_address, server_port); 435 warn_val.end_infinity = false;
366 else 436
367 printf("port %d", server_port); 437 time_pd.warn = warn_val;
368 } 438 } else {
369 else 439 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_OK);
370 printf("socket %s", server_address); 440 xasprintf(&elapsed_time_result.output, "Connection time %fs is within thresholds", elapsed_time);
371 } 441 }
372 442
373 if (match != NP_MATCH_FAILURE && !(flags & FLAG_HIDE_OUTPUT) && len) 443 mp_add_perfdata_to_subcheck(&elapsed_time_result, time_pd);
374 printf (" [%s]", status); 444 mp_add_subcheck_to_check(&overall, elapsed_time_result);
375
376 /* perf-data doesn't apply when server doesn't talk properly,
377 * so print all zeroes on warn and crit. Use fperfdata since
378 * localisation settings can make different outputs */
379 if(match == NP_MATCH_FAILURE)
380 printf ("|%s",
381 fperfdata ("time", elapsed_time, "s",
382 (flags & FLAG_TIME_WARN ? true : false), 0,
383 (flags & FLAG_TIME_CRIT ? true : false), 0,
384 true, 0,
385 true, socket_timeout)
386 );
387 else
388 printf("|%s",
389 fperfdata ("time", elapsed_time, "s",
390 (flags & FLAG_TIME_WARN ? true : false), warning_time,
391 (flags & FLAG_TIME_CRIT ? true : false), critical_time,
392 true, 0,
393 true, socket_timeout)
394 );
395
396 putchar('\n');
397 return result;
398}
399 445
446 /* did we get the response we hoped? */
447 if (match == NP_MATCH_FAILURE) {
448 expected_data_result = mp_set_subcheck_state(expected_data_result, config.expect_mismatch_state);
449 xasprintf(&expected_data_result.output, "Answer failed to match expectation");
450 mp_add_subcheck_to_check(&overall, expected_data_result);
451 } else if (match == NP_MATCH_SUCCESS) {
452 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_OK);
453 xasprintf(&expected_data_result.output, "The answer of the server matched the expectation");
454 mp_add_subcheck_to_check(&overall, expected_data_result);
455 }
400 456
457 /* reset the alarm */
458 alarm(0);
401 459
402/* process command-line arguments */ 460 mp_exit(overall);
403static int process_arguments (int argc, char **argv) { 461}
404 int c;
405 bool escape = false;
406 char *temp;
407 462
463/* process command-line arguments */
464static check_tcp_config_wrapper process_arguments(int argc, char **argv, check_tcp_config config) {
408 enum { 465 enum {
409 SNI_OPTION = CHAR_MAX + 1 466 SNI_OPTION = CHAR_MAX + 1,
467 output_format_index,
410 }; 468 };
411 469
412 int option = 0; 470 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
413 static struct option longopts[] = { 471 {"critical", required_argument, 0, 'c'},
414 {"hostname", required_argument, 0, 'H'}, 472 {"warning", required_argument, 0, 'w'},
415 {"critical", required_argument, 0, 'c'}, 473 {"critical-codes", required_argument, 0, 'C'},
416 {"warning", required_argument, 0, 'w'}, 474 {"warning-codes", required_argument, 0, 'W'},
417 {"critical-codes", required_argument, 0, 'C'}, 475 {"timeout", required_argument, 0, 't'},
418 {"warning-codes", required_argument, 0, 'W'}, 476 {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */
419 {"timeout", required_argument, 0, 't'}, 477 {"port", required_argument, 0, 'p'},
420 {"protocol", required_argument, 0, 'P'}, /* FIXME: Unhandled */ 478 {"escape", no_argument, 0, 'E'},
421 {"port", required_argument, 0, 'p'}, 479 {"all", no_argument, 0, 'A'},
422 {"escape", no_argument, 0, 'E'}, 480 {"send", required_argument, 0, 's'},
423 {"all", no_argument, 0, 'A'}, 481 {"expect", required_argument, 0, 'e'},
424 {"send", required_argument, 0, 's'}, 482 {"maxbytes", required_argument, 0, 'm'},
425 {"expect", required_argument, 0, 'e'}, 483 {"quit", required_argument, 0, 'q'},
426 {"maxbytes", required_argument, 0, 'm'}, 484 {"jail", no_argument, 0, 'j'},
427 {"quit", required_argument, 0, 'q'}, 485 {"delay", required_argument, 0, 'd'},
428 {"jail", no_argument, 0, 'j'}, 486 {"refuse", required_argument, 0, 'r'},
429 {"delay", required_argument, 0, 'd'}, 487 {"mismatch", required_argument, 0, 'M'},
430 {"refuse", required_argument, 0, 'r'}, 488 {"use-ipv4", no_argument, 0, '4'},
431 {"mismatch", required_argument, 0, 'M'}, 489 {"use-ipv6", no_argument, 0, '6'},
432 {"use-ipv4", no_argument, 0, '4'}, 490 {"verbose", no_argument, 0, 'v'},
433 {"use-ipv6", no_argument, 0, '6'}, 491 {"version", no_argument, 0, 'V'},
434 {"verbose", no_argument, 0, 'v'}, 492 {"help", no_argument, 0, 'h'},
435 {"version", no_argument, 0, 'V'}, 493 {"ssl", no_argument, 0, 'S'},
436 {"help", no_argument, 0, 'h'}, 494 {"sni", required_argument, 0, SNI_OPTION},
437 {"ssl", no_argument, 0, 'S'}, 495 {"certificate", required_argument, 0, 'D'},
438 {"sni", required_argument, 0, SNI_OPTION}, 496 {"output-format", required_argument, 0, output_format_index},
439 {"certificate", required_argument, 0, 'D'}, 497 {0, 0, 0, 0}};
440 {0, 0, 0, 0} 498
441 }; 499 if (argc < 2) {
442 500 usage4(_("No arguments found"));
443 if (argc < 2) 501 }
444 usage4 (_("No arguments found"));
445 502
446 /* backwards compatibility */ 503 /* backwards compatibility */
447 for (c = 1; c < argc; c++) { 504 for (int i = 1; i < argc; i++) {
448 if (strcmp ("-to", argv[c]) == 0) 505 if (strcmp("-to", argv[i]) == 0) {
449 strcpy (argv[c], "-t"); 506 strcpy(argv[i], "-t");
450 else if (strcmp ("-wt", argv[c]) == 0) 507 } else if (strcmp("-wt", argv[i]) == 0) {
451 strcpy (argv[c], "-w"); 508 strcpy(argv[i], "-w");
452 else if (strcmp ("-ct", argv[c]) == 0) 509 } else if (strcmp("-ct", argv[i]) == 0) {
453 strcpy (argv[c], "-c"); 510 strcpy(argv[i], "-c");
511 }
454 } 512 }
455 513
456 if (!is_option (argv[1])) { 514 if (!is_option(argv[1])) {
457 server_address = argv[1]; 515 config.server_address = argv[1];
458 argv[1] = argv[0]; 516 argv[1] = argv[0];
459 argv = &argv[1]; 517 argv = &argv[1];
460 argc--; 518 argc--;
461 } 519 }
462 520
463 while (1) { 521 bool escape = false;
464 c = getopt_long (argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", 522
465 longopts, &option); 523 while (true) {
524 int option = 0;
525 int option_index = getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option);
466 526
467 if (c == -1 || c == EOF || c == 1) 527 if (option_index == -1 || option_index == EOF || option_index == 1) {
468 break; 528 break;
529 }
469 530
470 switch (c) { 531 switch (option_index) {
471 case '?': /* print short usage statement if args not parsable */ 532 case '?': /* print short usage statement if args not parsable */
472 usage5 (); 533 usage5();
473 case 'h': /* help */ 534 case 'h': /* help */
474 print_help (); 535 print_help(config.service);
475 exit (STATE_UNKNOWN); 536 exit(STATE_UNKNOWN);
476 case 'V': /* version */ 537 case 'V': /* version */
477 print_revision (progname, NP_VERSION); 538 print_revision(progname, NP_VERSION);
478 exit (STATE_UNKNOWN); 539 exit(STATE_UNKNOWN);
479 case 'v': /* verbose mode */ 540 case 'v': /* verbose mode */
480 flags |= FLAG_VERBOSE; 541 verbosity++;
481 match_flags |= NP_MATCH_VERBOSE; 542 config.match_flags |= NP_MATCH_VERBOSE;
482 break; 543 break;
483 case '4': 544 case '4': // Apparently unused TODO
484 address_family = AF_INET; 545 address_family = AF_INET;
485 break; 546 break;
486 case '6': 547 case '6': // Apparently unused TODO
487#ifdef USE_IPV6 548#ifdef USE_IPV6
488 address_family = AF_INET6; 549 address_family = AF_INET6;
489#else 550#else
490 usage4 (_("IPv6 support not available")); 551 usage4(_("IPv6 support not available"));
491#endif 552#endif
492 break; 553 break;
493 case 'H': /* hostname */ 554 case 'H': /* hostname */
494 host_specified = true; 555 config.host_specified = true;
495 server_address = optarg; 556 config.server_address = optarg;
496 break;
497 case 'c': /* critical */
498 critical_time = strtod (optarg, NULL);
499 flags |= FLAG_TIME_CRIT;
500 break; 557 break;
501 case 'j': /* hide output */ 558 case 'c': /* critical */
502 flags |= FLAG_HIDE_OUTPUT; 559 config.critical_time = strtod(optarg, NULL);
560 config.critical_time_set = true;
503 break; 561 break;
504 case 'w': /* warning */ 562 case 'j': /* hide output */
505 warning_time = strtod (optarg, NULL); 563 config.hide_output = true;
506 flags |= FLAG_TIME_WARN;
507 break; 564 break;
508 case 'C': 565 case 'w': /* warning */
509 crit_codes = realloc (crit_codes, ++crit_codes_count); 566 config.warning_time = strtod(optarg, NULL);
510 crit_codes[crit_codes_count - 1] = optarg; 567 config.warning_time_set = true;
511 break; 568 break;
512 case 'W': 569 case 't': /* timeout */
513 warn_codes = realloc (warn_codes, ++warn_codes_count); 570 if (!is_intpos(optarg)) {
514 warn_codes[warn_codes_count - 1] = optarg; 571 usage4(_("Timeout interval must be a positive integer"));
515 break; 572 } else {
516 case 't': /* timeout */ 573 socket_timeout = atoi(optarg);
517 if (!is_intpos (optarg)) 574 }
518 usage4 (_("Timeout interval must be a positive integer"));
519 else
520 socket_timeout = atoi (optarg);
521 break; 575 break;
522 case 'p': /* port */ 576 case 'p': /* port */
523 if (!is_intpos (optarg)) 577 if (!is_intpos(optarg)) {
524 usage4 (_("Port must be a positive integer")); 578 usage4(_("Port must be a positive integer"));
525 else 579 } else {
526 server_port = atoi (optarg); 580 config.server_port = atoi(optarg);
581 }
527 break; 582 break;
528 case 'E': 583 case 'E':
529 escape = true; 584 escape = true;
530 break; 585 break;
531 case 's': 586 case 's':
532 if (escape) 587 if (escape) {
533 server_send = np_escaped_string(optarg); 588 config.send = np_escaped_string(optarg);
534 else 589 } else {
535 xasprintf(&server_send, "%s", optarg); 590 xasprintf(&config.send, "%s", optarg);
591 }
536 break; 592 break;
537 case 'e': /* expect string (may be repeated) */ 593 case 'e': /* expect string (may be repeated) */
538 match_flags &= ~NP_MATCH_EXACT; 594 config.match_flags &= ~NP_MATCH_EXACT;
539 if (server_expect_count == 0) 595 if (config.server_expect_count == 0) {
540 server_expect = malloc (sizeof (char *) * (++server_expect_count)); 596 config.server_expect = malloc(sizeof(char *) * (++config.server_expect_count));
541 else 597 } else {
542 server_expect = realloc (server_expect, sizeof (char *) * (++server_expect_count)); 598 config.server_expect = realloc(config.server_expect, sizeof(char *) * (++config.server_expect_count));
543 server_expect[server_expect_count - 1] = optarg; 599 }
600
601 if (config.server_expect == NULL) {
602 die(STATE_UNKNOWN, _("Allocation failed"));
603 }
604 config.server_expect[config.server_expect_count - 1] = optarg;
544 break; 605 break;
545 case 'm': 606 case 'm':
546 if (!is_intpos (optarg)) 607 if (!is_intpos(optarg)) {
547 usage4 (_("Maxbytes must be a positive integer")); 608 usage4(_("Maxbytes must be a positive integer"));
548 else 609 } else {
549 maxbytes = strtol (optarg, NULL, 0); 610 config.maxbytes = strtol(optarg, NULL, 0);
611 }
550 break; 612 break;
551 case 'q': 613 case 'q':
552 if (escape) 614 if (escape) {
553 server_quit = np_escaped_string(optarg); 615 config.quit = np_escaped_string(optarg);
554 else 616 } else {
555 xasprintf(&server_quit, "%s\r\n", optarg); 617 xasprintf(&config.quit, "%s\r\n", optarg);
618 }
556 break; 619 break;
557 case 'r': 620 case 'r':
558 if (!strncmp(optarg,"ok",2)) 621 if (!strncmp(optarg, "ok", 2)) {
559 econn_refuse_state = STATE_OK; 622 config.econn_refuse_state = STATE_OK;
560 else if (!strncmp(optarg,"warn",4)) 623 } else if (!strncmp(optarg, "warn", 4)) {
561 econn_refuse_state = STATE_WARNING; 624 config.econn_refuse_state = STATE_WARNING;
562 else if (!strncmp(optarg,"crit",4)) 625 } else if (!strncmp(optarg, "crit", 4)) {
563 econn_refuse_state = STATE_CRITICAL; 626 config.econn_refuse_state = STATE_CRITICAL;
564 else 627 } else {
565 usage4 (_("Refuse must be one of ok, warn, crit")); 628 usage4(_("Refuse must be one of ok, warn, crit"));
629 }
566 break; 630 break;
567 case 'M': 631 case 'M':
568 if (!strncmp(optarg,"ok",2)) 632 if (!strncmp(optarg, "ok", 2)) {
569 expect_mismatch_state = STATE_OK; 633 config.expect_mismatch_state = STATE_OK;
570 else if (!strncmp(optarg,"warn",4)) 634 } else if (!strncmp(optarg, "warn", 4)) {
571 expect_mismatch_state = STATE_WARNING; 635 config.expect_mismatch_state = STATE_WARNING;
572 else if (!strncmp(optarg,"crit",4)) 636 } else if (!strncmp(optarg, "crit", 4)) {
573 expect_mismatch_state = STATE_CRITICAL; 637 config.expect_mismatch_state = STATE_CRITICAL;
574 else 638 } else {
575 usage4 (_("Mismatch must be one of ok, warn, crit")); 639 usage4(_("Mismatch must be one of ok, warn, crit"));
640 }
576 break; 641 break;
577 case 'd': 642 case 'd':
578 if (is_intpos (optarg)) 643 if (is_intpos(optarg)) {
579 delay = atoi (optarg); 644 config.delay = atoi(optarg);
580 else 645 } else {
581 usage4 (_("Delay must be a positive integer")); 646 usage4(_("Delay must be a positive integer"));
647 }
582 break; 648 break;
583 case 'D': /* Check SSL cert validity - days 'til certificate expiration */ 649 case 'D': /* Check SSL cert validity - days 'til certificate expiration */
584#ifdef HAVE_SSL 650#ifdef HAVE_SSL
585# ifdef USE_OPENSSL /* XXX */ 651# ifdef USE_OPENSSL /* XXX */
586 if ((temp=strchr(optarg,','))!=NULL) { 652 {
587 *temp='\0'; 653 char *temp;
588 if (!is_intnonneg (optarg)) 654 if ((temp = strchr(optarg, ',')) != NULL) {
589 usage2 (_("Invalid certificate expiration period"), optarg); 655 *temp = '\0';
590 days_till_exp_warn = atoi (optarg); 656 if (!is_intnonneg(optarg)) {
591 *temp=','; 657 usage2(_("Invalid certificate expiration period"), optarg);
592 temp++; 658 }
593 if (!is_intnonneg (temp)) 659 config.days_till_exp_warn = atoi(optarg);
594 usage2 (_("Invalid certificate expiration period"), temp); 660 *temp = ',';
595 days_till_exp_crit = atoi (temp); 661 temp++;
596 } 662 if (!is_intnonneg(temp)) {
597 else { 663 usage2(_("Invalid certificate expiration period"), temp);
598 days_till_exp_crit=0; 664 }
599 if (!is_intnonneg (optarg)) 665 config.days_till_exp_crit = atoi(temp);
600 usage2 (_("Invalid certificate expiration period"), optarg); 666 } else {
601 days_till_exp_warn = atoi (optarg); 667 config.days_till_exp_crit = 0;
668 if (!is_intnonneg(optarg)) {
669 usage2(_("Invalid certificate expiration period"), optarg);
670 }
671 config.days_till_exp_warn = atoi(optarg);
602 } 672 }
603 check_cert = true; 673 config.check_cert = true;
604 flags |= FLAG_SSL; 674 config.use_tls = true;
605 break; 675 } break;
606# endif /* USE_OPENSSL */ 676# endif /* USE_OPENSSL */
607#endif 677#endif
608 /* fallthrough if we don't have ssl */ 678 /* fallthrough if we don't have ssl */
609 case 'S': 679 case 'S':
610#ifdef HAVE_SSL 680#ifdef HAVE_SSL
611 flags |= FLAG_SSL; 681 config.use_tls = true;
612#else 682#else
613 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 683 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
614#endif 684#endif
615 break; 685 break;
616 case SNI_OPTION: 686 case SNI_OPTION:
617#ifdef HAVE_SSL 687#ifdef HAVE_SSL
618 flags |= FLAG_SSL; 688 config.use_tls = true;
619 sni_specified = true; 689 config.sni_specified = true;
620 sni = optarg; 690 config.sni = optarg;
621#else 691#else
622 die (STATE_UNKNOWN, _("Invalid option - SSL is not available")); 692 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
623#endif 693#endif
624 break; 694 break;
625 case 'A': 695 case 'A':
626 match_flags |= NP_MATCH_ALL; 696 config.match_flags |= NP_MATCH_ALL;
627 break; 697 break;
698 case output_format_index: {
699 parsed_output_format parser = mp_parse_output_format(optarg);
700 if (!parser.parsing_success) {
701 // TODO List all available formats here, maybe add anothoer usage function
702 printf("Invalid output format: %s\n", optarg);
703 exit(STATE_UNKNOWN);
704 }
705
706 config.output_format_set = true;
707 config.output_format = parser.output_format;
708 break;
709 }
628 } 710 }
629 } 711 }
630 712
631 c = optind; 713 int index = optind;
632 if(!host_specified && c < argc) 714 if (!config.host_specified && index < argc) {
633 server_address = strdup (argv[c++]); 715 config.server_address = strdup(argv[index++]);
716 }
634 717
635 if (server_address == NULL) 718 if (config.server_address == NULL) {
636 usage4 (_("You must provide a server address")); 719 usage4(_("You must provide a server address"));
637 else if (server_address[0] != '/' && !is_host(server_address)) 720 } else if (config.server_address[0] != '/' && !is_host(config.server_address)) {
638 die (STATE_CRITICAL, "%s %s - %s: %s\n", SERVICE, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"), server_address); 721 die(STATE_CRITICAL, "%s %s - %s: %s\n", config.service, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"),
722 config.server_address);
723 }
639 724
640 return OK; 725 check_tcp_config_wrapper result = {
726 .config = config,
727 .errorcode = OK,
728 };
729 return result;
641} 730}
642 731
643 732void print_help(const char *service) {
644void 733 print_revision(progname, NP_VERSION);
645print_help (void) 734
646{ 735 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
647 print_revision (progname, NP_VERSION); 736 printf(COPYRIGHT, copyright, email);
648 737
649 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 738 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), service);
650 printf (COPYRIGHT, copyright, email); 739
651 740 print_usage();
652 printf (_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), 741
653 SERVICE); 742 printf(UT_HELP_VRSN);
654 743 printf(UT_EXTRA_OPTS);
655 print_usage (); 744
656 745 printf(UT_HOST_PORT, 'p', "none");
657 printf (UT_HELP_VRSN); 746
658 printf (UT_EXTRA_OPTS); 747 printf(UT_IPv46);
659 748
660 printf (UT_HOST_PORT, 'p', "none"); 749 printf(" %s\n", "-E, --escape");
661 750 printf(" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option"));
662 printf (UT_IPv46); 751 printf(" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit"));
663 752 printf(" %s\n", "-s, --send=STRING");
664 printf (" %s\n", "-E, --escape"); 753 printf(" %s\n", _("String to send to the server"));
665 printf (" %s\n", _("Can use \\n, \\r, \\t or \\\\ in send or quit string. Must come before send or quit option")); 754 printf(" %s\n", "-e, --expect=STRING");
666 printf (" %s\n", _("Default: nothing added to send, \\r\\n added to end of quit")); 755 printf(" %s %s\n", _("String to expect in server response"), _("(may be repeated)"));
667 printf (" %s\n", "-s, --send=STRING"); 756 printf(" %s\n", "-A, --all");
668 printf (" %s\n", _("String to send to the server")); 757 printf(" %s\n", _("All expect strings need to occur in server response. Default is any"));
669 printf (" %s\n", "-e, --expect=STRING"); 758 printf(" %s\n", "-q, --quit=STRING");
670 printf (" %s %s\n", _("String to expect in server response"), _("(may be repeated)")); 759 printf(" %s\n", _("String to send server to initiate a clean close of the connection"));
671 printf (" %s\n", "-A, --all"); 760 printf(" %s\n", "-r, --refuse=ok|warn|crit");
672 printf (" %s\n", _("All expect strings need to occur in server response. Default is any")); 761 printf(" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)"));
673 printf (" %s\n", "-q, --quit=STRING"); 762 printf(" %s\n", "-M, --mismatch=ok|warn|crit");
674 printf (" %s\n", _("String to send server to initiate a clean close of the connection")); 763 printf(" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)"));
675 printf (" %s\n", "-r, --refuse=ok|warn|crit"); 764 printf(" %s\n", "-j, --jail");
676 printf (" %s\n", _("Accept TCP refusals with states ok, warn, crit (default: crit)")); 765 printf(" %s\n", _("Hide output from TCP socket"));
677 printf (" %s\n", "-M, --mismatch=ok|warn|crit"); 766 printf(" %s\n", "-m, --maxbytes=INTEGER");
678 printf (" %s\n", _("Accept expected string mismatches with states ok, warn, crit (default: warn)")); 767 printf(" %s\n", _("Close connection once more than this number of bytes are received"));
679 printf (" %s\n", "-j, --jail"); 768 printf(" %s\n", "-d, --delay=INTEGER");
680 printf (" %s\n", _("Hide output from TCP socket")); 769 printf(" %s\n", _("Seconds to wait between sending string and polling for response"));
681 printf (" %s\n", "-m, --maxbytes=INTEGER");
682 printf (" %s\n", _("Close connection once more than this number of bytes are received"));
683 printf (" %s\n", "-d, --delay=INTEGER");
684 printf (" %s\n", _("Seconds to wait between sending string and polling for response"));
685 770
686#ifdef HAVE_SSL 771#ifdef HAVE_SSL
687 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 772 printf(" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
688 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 773 printf(" %s\n", _("Minimum number of days a certificate has to be valid."));
689 printf (" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0).")); 774 printf(" %s\n", _("1st is #days for warning, 2nd is critical (if not specified - 0)."));
690 printf (" %s\n", "-S, --ssl"); 775 printf(" %s\n", "-S, --ssl");
691 printf (" %s\n", _("Use SSL for the connection.")); 776 printf(" %s\n", _("Use SSL for the connection."));
692 printf (" %s\n", "--sni=STRING"); 777 printf(" %s\n", "--sni=STRING");
693 printf (" %s\n", _("SSL server_name")); 778 printf(" %s\n", _("SSL server_name"));
694#endif 779#endif
695 780
696 printf (UT_WARN_CRIT); 781 printf(UT_WARN_CRIT);
697 782
698 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
699 784
700 printf (UT_VERBOSE); 785 printf(UT_OUTPUT_FORMAT);
786 printf(UT_VERBOSE);
701 787
702 printf (UT_SUPPORT); 788 printf(UT_SUPPORT);
703} 789}
704 790
705 791void print_usage(void) {
706void 792 printf("%s\n", _("Usage:"));
707print_usage (void) 793 printf("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n", progname);
708{ 794 printf("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
709 printf ("%s\n", _("Usage:")); 795 printf("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
710 printf ("%s -H host -p port [-w <warning time>] [-c <critical time>] [-s <send string>]\n",progname); 796 printf("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n");
711 printf ("[-e <expect string>] [-q <quit string>][-m <maximum bytes>] [-d <delay>]\n");
712 printf ("[-t <timeout seconds>] [-r <refuse state>] [-M <mismatch state>] [-v] [-4|-6] [-j]\n");
713 printf ("[-D <warn days cert expire>[,<crit days cert expire>]] [-S <use SSL>] [-E]\n");
714} 797}
diff --git a/plugins/check_tcp.d/config.h b/plugins/check_tcp.d/config.h
new file mode 100644
index 00000000..dc25d79e
--- /dev/null
+++ b/plugins/check_tcp.d/config.h
@@ -0,0 +1,84 @@
1#pragma once
2
3#include "../../lib/utils_tcp.h"
4#include "output.h"
5#include "states.h"
6#include <netinet/in.h>
7
8typedef struct {
9 char *server_address;
10 bool host_specified;
11 int server_port; // TODO can this be a uint16?
12
13 int protocol; /* most common is default */
14 char *service;
15 char *send;
16 char *quit;
17 char **server_expect;
18 size_t server_expect_count;
19 bool use_tls;
20#ifdef HAVE_SSL
21 char *sni;
22 bool sni_specified;
23 bool check_cert;
24 int days_till_exp_warn;
25 int days_till_exp_crit;
26#endif // HAVE_SSL
27 int match_flags;
28 mp_state_enum expect_mismatch_state;
29 unsigned int delay;
30
31 bool warning_time_set;
32 double warning_time;
33 bool critical_time_set;
34 double critical_time;
35
36 mp_state_enum econn_refuse_state;
37
38 ssize_t maxbytes;
39
40 bool hide_output;
41
42 bool output_format_set;
43 mp_output_format output_format;
44} check_tcp_config;
45
46check_tcp_config check_tcp_config_init() {
47 check_tcp_config result = {
48 .server_address = "127.0.0.1",
49 .host_specified = false,
50 .server_port = 0,
51
52 .protocol = IPPROTO_TCP,
53 .service = "TCP",
54 .send = NULL,
55 .quit = NULL,
56 .server_expect = NULL,
57 .server_expect_count = 0,
58 .use_tls = false,
59#ifdef HAVE_SSL
60 .sni = NULL,
61 .sni_specified = false,
62 .check_cert = false,
63 .days_till_exp_warn = 0,
64 .days_till_exp_crit = 0,
65#endif // HAVE_SSL
66 .match_flags = NP_MATCH_EXACT,
67 .expect_mismatch_state = STATE_WARNING,
68 .delay = 0,
69
70 .warning_time_set = false,
71 .warning_time = 0,
72 .critical_time_set = false,
73 .critical_time = 0,
74
75 .econn_refuse_state = STATE_CRITICAL,
76
77 .maxbytes = 0,
78
79 .hide_output = false,
80
81 .output_format_set = false,
82 };
83 return result;
84}
diff --git a/plugins/check_time.c b/plugins/check_time.c
index f50ea427..debf59f3 100644
--- a/plugins/check_time.c
+++ b/plugins/check_time.c
@@ -1,374 +1,348 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_time plugin 3 * Monitoring check_time plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_time plugin 10 * This file contains the check_time plugin
11* 11 *
12* This plugin will check the time difference with the specified host. 12 * This plugin will check the time difference with the specified host.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
31const char *progname = "check_time"; 32const char *progname = "check_time";
32const char *copyright = "1999-2007"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
34 35
35#include "common.h" 36#include "common.h"
36#include "netutils.h" 37#include "netutils.h"
37#include "utils.h" 38#include "utils.h"
39#include "check_time.d/config.h"
40
41#define UNIX_EPOCH 2208988800UL
42
43typedef struct {
44 int errorcode;
45 check_time_config config;
46} check_time_config_wrapper;
47static check_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
48static void print_help(void);
49void print_usage(void);
38 50
39enum { 51int main(int argc, char **argv) {
40 TIME_PORT = 37 52 setlocale(LC_ALL, "");
41}; 53 bindtextdomain(PACKAGE, LOCALEDIR);
42 54 textdomain(PACKAGE);
43#define UNIX_EPOCH 2208988800UL
44
45uint32_t raw_server_time;
46unsigned long server_time, diff_time;
47int warning_time = 0;
48bool check_warning_time = false;
49int critical_time = 0;
50bool check_critical_time = false;
51unsigned long warning_diff = 0;
52bool check_warning_diff = false;
53unsigned long critical_diff = 0;
54bool check_critical_diff = false;
55int server_port = TIME_PORT;
56char *server_address = NULL;
57bool use_udp = false;
58
59int process_arguments (int, char **);
60void print_help (void);
61void print_usage (void);
62
63int
64main (int argc, char **argv)
65{
66 int sd;
67 int result = STATE_UNKNOWN;
68 time_t conntime;
69
70 setlocale (LC_ALL, "");
71 bindtextdomain (PACKAGE, LOCALEDIR);
72 textdomain (PACKAGE);
73 55
74 /* Parse extra opts if any */ 56 /* Parse extra opts if any */
75 argv=np_extra_opts (&argc, argv, progname); 57 argv = np_extra_opts(&argc, argv, progname);
58
59 check_time_config_wrapper tmp_config = process_arguments(argc, argv);
60 if (tmp_config.errorcode == ERROR) {
61 usage4(_("Could not parse arguments"));
62 }
76 63
77 if (process_arguments (argc, argv) == ERROR) 64 const check_time_config config = tmp_config.config;
78 usage4 (_("Could not parse arguments"));
79 65
80 /* initialize alarm signal handling */ 66 /* initialize alarm signal handling */
81 signal (SIGALRM, socket_timeout_alarm_handler); 67 signal(SIGALRM, socket_timeout_alarm_handler);
82 68
83 /* set socket timeout */ 69 /* set socket timeout */
84 alarm (socket_timeout); 70 alarm(socket_timeout);
85 time (&start_time); 71 time(&start_time);
86 72
73 int socket;
74 mp_state_enum result = STATE_UNKNOWN;
87 /* try to connect to the host at the given port number */ 75 /* try to connect to the host at the given port number */
88 if (use_udp) { 76 if (config.use_udp) {
89 result = my_udp_connect (server_address, server_port, &sd); 77 result = my_udp_connect(config.server_address, config.server_port, &socket);
90 } else { 78 } else {
91 result = my_tcp_connect (server_address, server_port, &sd); 79 result = my_tcp_connect(config.server_address, config.server_port, &socket);
92 } 80 }
93 81
94 if (result != STATE_OK) { 82 if (result != STATE_OK) {
95 if (check_critical_time) 83 if (config.check_critical_time) {
96 result = STATE_CRITICAL; 84 result = STATE_CRITICAL;
97 else if (check_warning_time) 85 } else if (config.check_warning_time) {
98 result = STATE_WARNING; 86 result = STATE_WARNING;
99 else 87 } else {
100 result = STATE_UNKNOWN; 88 result = STATE_UNKNOWN;
101 die (result, 89 }
102 _("TIME UNKNOWN - could not connect to server %s, port %d\n"), 90 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), config.server_address, config.server_port);
103 server_address, server_port);
104 } 91 }
105 92
106 if (use_udp) { 93 if (config.use_udp) {
107 if (send (sd, "", 0, 0) < 0) { 94 if (send(socket, "", 0, 0) < 0) {
108 if (check_critical_time) 95 if (config.check_critical_time) {
109 result = STATE_CRITICAL; 96 result = STATE_CRITICAL;
110 else if (check_warning_time) 97 } else if (config.check_warning_time) {
111 result = STATE_WARNING; 98 result = STATE_WARNING;
112 else 99 } else {
113 result = STATE_UNKNOWN; 100 result = STATE_UNKNOWN;
114 die (result, 101 }
115 _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), 102 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), config.server_address, config.server_port);
116 server_address, server_port);
117 } 103 }
118 } 104 }
119 105
120 /* watch for the connection string */ 106 /* watch for the connection string */
121 result = recv (sd, (void *)&raw_server_time, sizeof (raw_server_time), 0); 107 uint32_t raw_server_time;
108 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0);
122 109
123 /* close the connection */ 110 /* close the connection */
124 close (sd); 111 close(socket);
125 112
126 /* reset the alarm */ 113 /* reset the alarm */
127 time (&end_time); 114 time(&end_time);
128 alarm (0); 115 alarm(0);
129 116
130 /* return a WARNING status if we couldn't read any data */ 117 /* return a WARNING status if we couldn't read any data */
131 if (result <= 0) { 118 if (result <= 0) {
132 if (check_critical_time) 119 if (config.check_critical_time) {
133 result = STATE_CRITICAL; 120 result = STATE_CRITICAL;
134 else if (check_warning_time) 121 } else if (config.check_warning_time) {
135 result = STATE_WARNING; 122 result = STATE_WARNING;
136 else 123 } else {
137 result = STATE_UNKNOWN; 124 result = STATE_UNKNOWN;
138 die (result, 125 }
139 _("TIME UNKNOWN - no data received from server %s, port %d\n"), 126 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), config.server_address, config.server_port);
140 server_address, server_port);
141 } 127 }
142 128
143 result = STATE_OK; 129 result = STATE_OK;
144 130
145 conntime = (end_time - start_time); 131 time_t conntime = (end_time - start_time);
146 if (check_critical_time&& conntime > critical_time) 132 if (config.check_critical_time && conntime > config.critical_time) {
147 result = STATE_CRITICAL; 133 result = STATE_CRITICAL;
148 else if (check_warning_time && conntime > warning_time) 134 } else if (config.check_warning_time && conntime > config.warning_time) {
149 result = STATE_WARNING; 135 result = STATE_WARNING;
136 }
150 137
151 if (result != STATE_OK) 138 if (result != STATE_OK) {
152 die (result, _("TIME %s - %d second response time|%s\n"), 139 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime,
153 state_text (result), (int)conntime, 140 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
154 perfdata ("time", (long)conntime, "s", 141 (long)config.critical_time, true, 0, false, 0));
155 check_warning_time, (long)warning_time, 142 }
156 check_critical_time, (long)critical_time,
157 true, 0, false, 0));
158 143
159 server_time = ntohl (raw_server_time) - UNIX_EPOCH; 144 unsigned long server_time;
160 if (server_time > (unsigned long)end_time) 145 unsigned long diff_time;
146 server_time = ntohl(raw_server_time) - UNIX_EPOCH;
147 if (server_time > (unsigned long)end_time) {
161 diff_time = server_time - (unsigned long)end_time; 148 diff_time = server_time - (unsigned long)end_time;
162 else 149 } else {
163 diff_time = (unsigned long)end_time - server_time; 150 diff_time = (unsigned long)end_time - server_time;
151 }
164 152
165 if (check_critical_diff&& diff_time > critical_diff) 153 if (config.check_critical_diff && diff_time > config.critical_diff) {
166 result = STATE_CRITICAL; 154 result = STATE_CRITICAL;
167 else if (check_warning_diff&& diff_time > warning_diff) 155 } else if (config.check_warning_diff && diff_time > config.warning_diff) {
168 result = STATE_WARNING; 156 result = STATE_WARNING;
157 }
169 158
170 printf (_("TIME %s - %lu second time difference|%s %s\n"), 159 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time,
171 state_text (result), diff_time, 160 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
172 perfdata ("time", (long)conntime, "s", 161 (long)config.critical_time, true, 0, false, 0),
173 check_warning_time, (long)warning_time, 162 perfdata("offset", diff_time, "s", config.check_warning_diff, config.warning_diff, config.check_critical_diff,
174 check_critical_time, (long)critical_time, 163 config.critical_diff, true, 0, false, 0));
175 true, 0, false, 0),
176 perfdata ("offset", diff_time, "s",
177 check_warning_diff, warning_diff,
178 check_critical_diff, critical_diff,
179 true, 0, false, 0));
180 return result; 164 return result;
181} 165}
182 166
183
184
185/* process command-line arguments */ 167/* process command-line arguments */
186int 168check_time_config_wrapper process_arguments(int argc, char **argv) {
187process_arguments (int argc, char **argv) 169 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
188{ 170 {"warning-variance", required_argument, 0, 'w'},
189 int c; 171 {"critical-variance", required_argument, 0, 'c'},
190 172 {"warning-connect", required_argument, 0, 'W'},
191 int option = 0; 173 {"critical-connect", required_argument, 0, 'C'},
192 static struct option longopts[] = { 174 {"port", required_argument, 0, 'p'},
193 {"hostname", required_argument, 0, 'H'}, 175 {"udp", no_argument, 0, 'u'},
194 {"warning-variance", required_argument, 0, 'w'}, 176 {"timeout", required_argument, 0, 't'},
195 {"critical-variance", required_argument, 0, 'c'}, 177 {"version", no_argument, 0, 'V'},
196 {"warning-connect", required_argument, 0, 'W'}, 178 {"help", no_argument, 0, 'h'},
197 {"critical-connect", required_argument, 0, 'C'}, 179 {0, 0, 0, 0}};
198 {"port", required_argument, 0, 'p'}, 180
199 {"udp", no_argument, 0, 'u'}, 181 if (argc < 2) {
200 {"timeout", required_argument, 0, 't'}, 182 usage("\n");
201 {"version", no_argument, 0, 'V'}, 183 }
202 {"help", no_argument, 0, 'h'},
203 {0, 0, 0, 0}
204 };
205 184
206 if (argc < 2) 185 for (int i = 1; i < argc; i++) {
207 usage ("\n"); 186 if (strcmp("-to", argv[i]) == 0) {
208 187 strcpy(argv[i], "-t");
209 for (c = 1; c < argc; c++) { 188 } else if (strcmp("-wd", argv[i]) == 0) {
210 if (strcmp ("-to", argv[c]) == 0) 189 strcpy(argv[i], "-w");
211 strcpy (argv[c], "-t"); 190 } else if (strcmp("-cd", argv[i]) == 0) {
212 else if (strcmp ("-wd", argv[c]) == 0) 191 strcpy(argv[i], "-c");
213 strcpy (argv[c], "-w"); 192 } else if (strcmp("-wt", argv[i]) == 0) {
214 else if (strcmp ("-cd", argv[c]) == 0) 193 strcpy(argv[i], "-W");
215 strcpy (argv[c], "-c"); 194 } else if (strcmp("-ct", argv[i]) == 0) {
216 else if (strcmp ("-wt", argv[c]) == 0) 195 strcpy(argv[i], "-C");
217 strcpy (argv[c], "-W"); 196 }
218 else if (strcmp ("-ct", argv[c]) == 0)
219 strcpy (argv[c], "-C");
220 } 197 }
221 198
199 check_time_config_wrapper result = {
200 .errorcode = OK,
201 .config = check_time_config_init(),
202 };
203
204 int option_char;
222 while (true) { 205 while (true) {
223 c = getopt_long (argc, argv, "hVH:w:c:W:C:p:t:u", longopts, 206 int option = 0;
224 &option); 207 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option);
225 208
226 if (c == -1 || c == EOF) 209 if (option_char == -1 || option_char == EOF) {
227 break; 210 break;
211 }
228 212
229 switch (c) { 213 switch (option_char) {
230 case '?': /* print short usage statement if args not parsable */ 214 case '?': /* print short usage statement if args not parsable */
231 usage5 (); 215 usage5();
232 case 'h': /* help */ 216 case 'h': /* help */
233 print_help (); 217 print_help();
234 exit (STATE_UNKNOWN); 218 exit(STATE_UNKNOWN);
235 case 'V': /* version */ 219 case 'V': /* version */
236 print_revision (progname, NP_VERSION); 220 print_revision(progname, NP_VERSION);
237 exit (STATE_UNKNOWN); 221 exit(STATE_UNKNOWN);
238 case 'H': /* hostname */ 222 case 'H': /* hostname */
239 if (!is_host (optarg)) 223 if (!is_host(optarg)) {
240 usage2 (_("Invalid hostname/address"), optarg); 224 usage2(_("Invalid hostname/address"), optarg);
241 server_address = optarg;
242 break;
243 case 'w': /* warning-variance */
244 if (is_intnonneg (optarg)) {
245 warning_diff = strtoul (optarg, NULL, 10);
246 check_warning_diff = true;
247 } 225 }
248 else if (strspn (optarg, "0123456789:,") > 0) { 226 result.config.server_address = optarg;
249 if (sscanf (optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) { 227 break;
250 check_warning_diff = true; 228 case 'w': /* warning-variance */
251 check_warning_time = true; 229 if (is_intnonneg(optarg)) {
252 } 230 result.config.warning_diff = strtoul(optarg, NULL, 10);
253 else { 231 result.config.check_warning_diff = true;
254 usage4 (_("Warning thresholds must be a positive integer")); 232 } else if (strspn(optarg, "0123456789:,") > 0) {
233 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.warning_diff, &result.config.warning_time) == 2) {
234 result.config.check_warning_diff = true;
235 result.config.check_warning_time = true;
236 } else {
237 usage4(_("Warning thresholds must be a positive integer"));
255 } 238 }
256 } 239 } else {
257 else { 240 usage4(_("Warning threshold must be a positive integer"));
258 usage4 (_("Warning threshold must be a positive integer"));
259 } 241 }
260 break; 242 break;
261 case 'c': /* critical-variance */ 243 case 'c': /* critical-variance */
262 if (is_intnonneg (optarg)) { 244 if (is_intnonneg(optarg)) {
263 critical_diff = strtoul (optarg, NULL, 10); 245 result.config.critical_diff = strtoul(optarg, NULL, 10);
264 check_critical_diff = true; 246 result.config.check_critical_diff = true;
265 } 247 } else if (strspn(optarg, "0123456789:,") > 0) {
266 else if (strspn (optarg, "0123456789:,") > 0) { 248 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.critical_diff, &result.config.critical_time) == 2) {
267 if (sscanf (optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) == 249 result.config.check_critical_diff = true;
268 2) { 250 result.config.check_critical_time = true;
269 check_critical_diff = true; 251 } else {
270 check_critical_time = true; 252 usage4(_("Critical thresholds must be a positive integer"));
271 }
272 else {
273 usage4 (_("Critical thresholds must be a positive integer"));
274 } 253 }
275 } 254 } else {
276 else { 255 usage4(_("Critical threshold must be a positive integer"));
277 usage4 (_("Critical threshold must be a positive integer"));
278 } 256 }
279 break; 257 break;
280 case 'W': /* warning-connect */ 258 case 'W': /* warning-connect */
281 if (!is_intnonneg (optarg)) 259 if (!is_intnonneg(optarg)) {
282 usage4 (_("Warning threshold must be a positive integer")); 260 usage4(_("Warning threshold must be a positive integer"));
283 else 261 } else {
284 warning_time = atoi (optarg); 262 result.config.warning_time = atoi(optarg);
285 check_warning_time = true; 263 }
264 result.config.check_warning_time = true;
286 break; 265 break;
287 case 'C': /* critical-connect */ 266 case 'C': /* critical-connect */
288 if (!is_intnonneg (optarg)) 267 if (!is_intnonneg(optarg)) {
289 usage4 (_("Critical threshold must be a positive integer")); 268 usage4(_("Critical threshold must be a positive integer"));
290 else 269 } else {
291 critical_time = atoi (optarg); 270 result.config.critical_time = atoi(optarg);
292 check_critical_time = true; 271 }
272 result.config.check_critical_time = true;
293 break; 273 break;
294 case 'p': /* port */ 274 case 'p': /* port */
295 if (!is_intnonneg (optarg)) 275 if (!is_intnonneg(optarg)) {
296 usage4 (_("Port must be a positive integer")); 276 usage4(_("Port must be a positive integer"));
297 else 277 } else {
298 server_port = atoi (optarg); 278 result.config.server_port = atoi(optarg);
279 }
299 break; 280 break;
300 case 't': /* timeout */ 281 case 't': /* timeout */
301 if (!is_intnonneg (optarg)) 282 if (!is_intnonneg(optarg)) {
302 usage2 (_("Timeout interval must be a positive integer"), optarg); 283 usage2(_("Timeout interval must be a positive integer"), optarg);
303 else 284 } else {
304 socket_timeout = atoi (optarg); 285 socket_timeout = atoi(optarg);
286 }
305 break; 287 break;
306 case 'u': /* udp */ 288 case 'u': /* udp */
307 use_udp = true; 289 result.config.use_udp = true;
308 } 290 }
309 } 291 }
310 292
311 c = optind; 293 option_char = optind;
312 if (server_address == NULL) { 294 if (result.config.server_address == NULL) {
313 if (argc > c) { 295 if (argc > option_char) {
314 if (!is_host (argv[c])) 296 if (!is_host(argv[option_char])) {
315 usage2 (_("Invalid hostname/address"), optarg); 297 usage2(_("Invalid hostname/address"), optarg);
316 server_address = argv[c]; 298 }
317 } 299 result.config.server_address = argv[option_char];
318 else { 300 } else {
319 usage4 (_("Hostname was not supplied")); 301 usage4(_("Hostname was not supplied"));
320 } 302 }
321 } 303 }
322 304
323 return OK; 305 return result;
324} 306}
325 307
326 308void print_help(void) {
327
328void
329print_help (void)
330{
331 char *myport; 309 char *myport;
332 xasprintf (&myport, "%d", TIME_PORT); 310 xasprintf(&myport, "%d", TIME_PORT);
333 311
334 print_revision (progname, NP_VERSION); 312 print_revision(progname, NP_VERSION);
335 313
336 printf ("Copyright (c) 1999 Ethan Galstad\n"); 314 printf("Copyright (c) 1999 Ethan Galstad\n");
337 printf (COPYRIGHT, copyright, email); 315 printf(COPYRIGHT, copyright, email);
338 316
339 printf ("%s\n", _("This plugin will check the time on the specified host.")); 317 printf("%s\n", _("This plugin will check the time on the specified host."));
340 318
341 printf ("\n\n"); 319 printf("\n\n");
342 320
343 print_usage (); 321 print_usage();
344 322
345 printf (UT_HELP_VRSN); 323 printf(UT_HELP_VRSN);
346 printf (UT_EXTRA_OPTS); 324 printf(UT_EXTRA_OPTS);
347 325
348 printf (UT_HOST_PORT, 'p', myport); 326 printf(UT_HOST_PORT, 'p', myport);
349 327
350 printf (" %s\n", "-u, --udp"); 328 printf(" %s\n", "-u, --udp");
351 printf (" %s\n", _("Use UDP to connect, not TCP")); 329 printf(" %s\n", _("Use UDP to connect, not TCP"));
352 printf (" %s\n", "-w, --warning-variance=INTEGER"); 330 printf(" %s\n", "-w, --warning-variance=INTEGER");
353 printf (" %s\n", _("Time difference (sec.) necessary to result in a warning status")); 331 printf(" %s\n", _("Time difference (sec.) necessary to result in a warning status"));
354 printf (" %s\n", "-c, --critical-variance=INTEGER"); 332 printf(" %s\n", "-c, --critical-variance=INTEGER");
355 printf (" %s\n", _("Time difference (sec.) necessary to result in a critical status")); 333 printf(" %s\n", _("Time difference (sec.) necessary to result in a critical status"));
356 printf (" %s\n", "-W, --warning-connect=INTEGER"); 334 printf(" %s\n", "-W, --warning-connect=INTEGER");
357 printf (" %s\n", _("Response time (sec.) necessary to result in warning status")); 335 printf(" %s\n", _("Response time (sec.) necessary to result in warning status"));
358 printf (" %s\n", "-C, --critical-connect=INTEGER"); 336 printf(" %s\n", "-C, --critical-connect=INTEGER");
359 printf (" %s\n", _("Response time (sec.) necessary to result in critical status")); 337 printf(" %s\n", _("Response time (sec.) necessary to result in critical status"));
360 338
361 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 339 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
362 340
363 printf (UT_SUPPORT); 341 printf(UT_SUPPORT);
364} 342}
365 343
366 344void print_usage(void) {
367 345 printf("%s\n", _("Usage:"));
368void 346 printf("%s -H <host_address> [-p port] [-u] [-w variance] [-c variance]\n", progname);
369print_usage (void) 347 printf(" [-W connect_time] [-C connect_time] [-t timeout]\n");
370{
371 printf ("%s\n", _("Usage:"));
372 printf ("%s -H <host_address> [-p port] [-u] [-w variance] [-c variance]\n",progname);
373 printf (" [-W connect_time] [-C connect_time] [-t timeout]\n");
374} 348}
diff --git a/plugins/check_time.d/config.h b/plugins/check_time.d/config.h
new file mode 100644
index 00000000..09bd7c45
--- /dev/null
+++ b/plugins/check_time.d/config.h
@@ -0,0 +1,42 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 TIME_PORT = 37
8};
9
10typedef struct {
11 char *server_address;
12 int server_port;
13 bool use_udp;
14
15 int warning_time;
16 bool check_warning_time;
17 int critical_time;
18 bool check_critical_time;
19 unsigned long warning_diff;
20 bool check_warning_diff;
21 unsigned long critical_diff;
22 bool check_critical_diff;
23} check_time_config;
24
25check_time_config check_time_config_init() {
26 check_time_config tmp = {
27 .server_address = NULL,
28 .server_port = TIME_PORT,
29 .use_udp = false,
30
31 .warning_time = 0,
32 .check_warning_time = false,
33 .critical_time = 0,
34 .check_critical_time = false,
35
36 .warning_diff = 0,
37 .check_warning_diff = false,
38 .critical_diff = 0,
39 .check_critical_diff = false,
40 };
41 return tmp;
42}
diff --git a/plugins/check_ups.c b/plugins/check_ups.c
index 380ff3bc..ecc0760f 100644
--- a/plugins/check_ups.c
+++ b/plugins/check_ups.c
@@ -6,7 +6,7 @@
6 * Copyright (c) 2000 Tom Shields 6 * Copyright (c) 2000 Tom Shields
7 * 2004 Alain Richard <alain.richard@equation.fr> 7 * 2004 Alain Richard <alain.richard@equation.fr>
8 * 2004 Arnaud Quette <arnaud.quette@mgeups.com> 8 * 2004 Arnaud Quette <arnaud.quette@mgeups.com>
9 * Copyright (c) 2002-2023 Monitoring Plugins Development Team 9 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
10 * 10 *
11 * Description: 11 * Description:
12 * 12 *
@@ -33,100 +33,52 @@
33 *****************************************************************************/ 33 *****************************************************************************/
34 34
35const char *progname = "check_ups"; 35const char *progname = "check_ups";
36const char *copyright = "2000-2023"; 36const char *copyright = "2000-2024";
37const char *email = "devel@monitoring-plugins.org"; 37const char *email = "devel@monitoring-plugins.org";
38 38
39#include "common.h" 39#include "common.h"
40#include "netutils.h" 40#include "netutils.h"
41#include "utils.h" 41#include "utils.h"
42#include "check_ups.d/config.h"
43#include "states.h"
42 44
43enum { PORT = 3493 }; 45enum {
44 46 NOSUCHVAR = ERROR - 1
45#define UPS_NONE 0 /* no supported options */ 47};
46#define UPS_UTILITY 1 /* supports utility line */
47#define UPS_BATTPCT 2 /* supports percent battery remaining */
48#define UPS_STATUS 4 /* supports UPS status */
49#define UPS_TEMP 8 /* supports UPS temperature */
50#define UPS_LOADPCT 16 /* supports load percent */
51#define UPS_REALPOWER 32 /* supports real power */
52
53#define UPSSTATUS_NONE 0
54#define UPSSTATUS_OFF 1
55#define UPSSTATUS_OL 2
56#define UPSSTATUS_OB 4
57#define UPSSTATUS_LB 8
58#define UPSSTATUS_CAL 16
59#define UPSSTATUS_RB 32 /*Replace Battery */
60#define UPSSTATUS_BYPASS 64
61#define UPSSTATUS_OVER 128
62#define UPSSTATUS_TRIM 256
63#define UPSSTATUS_BOOST 512
64#define UPSSTATUS_CHRG 1024
65#define UPSSTATUS_DISCHRG 2048
66#define UPSSTATUS_UNKNOWN 4096
67#define UPSSTATUS_ALARM 8192
68
69enum { NOSUCHVAR = ERROR - 1 };
70
71typedef struct ups_config {
72 unsigned int server_port;
73 char *server_address;
74 char *ups_name;
75 double warning_value;
76 double critical_value;
77 bool check_warn;
78 bool check_crit;
79 int check_variable;
80 int status;
81 bool temp_output_c;
82} ups_config;
83
84ups_config ups_config_init(void) {
85 ups_config tmp = {0};
86 tmp.server_port = PORT;
87 tmp.server_address = NULL;
88 tmp.ups_name = NULL;
89 tmp.check_variable = UPS_NONE;
90 tmp.status = UPSSTATUS_NONE;
91
92 return tmp;
93}
94 48
95// Forward declarations 49// Forward declarations
96int determine_status(ups_config *, int *supported_options); 50typedef struct {
97int get_ups_variable(const char *, char *, const ups_config config); 51 int errorcode;
98 52 int ups_status;
99int process_arguments(int, char **, ups_config *); 53 int supported_options;
100int validate_arguments(ups_config); 54} determine_status_result;
101void print_help(void); 55static determine_status_result determine_status(check_ups_config /*config*/);
56static int get_ups_variable(const char * /*varname*/, char * /*buf*/, check_ups_config config);
57
58typedef struct {
59 int errorcode;
60 check_ups_config config;
61} check_ups_config_wrapper;
62static check_ups_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
63static check_ups_config_wrapper validate_arguments(check_ups_config_wrapper /*config_wrapper*/);
64
65static void print_help(void);
102void print_usage(void); 66void print_usage(void);
103 67
104int main(int argc, char **argv) { 68int main(int argc, char **argv) {
105 setlocale(LC_ALL, ""); 69 setlocale(LC_ALL, "");
106 bindtextdomain(PACKAGE, LOCALEDIR); 70 bindtextdomain(PACKAGE, LOCALEDIR);
107 textdomain(PACKAGE); 71 textdomain(PACKAGE);
108
109 char *ups_status;
110 ups_status = strdup("N/A");
111
112 char *data;
113 data = strdup("");
114
115 char *message;
116 message = strdup("");
117
118 // Exit result
119 int result = STATE_UNKNOWN;
120
121 /* Parse extra opts if any */ 72 /* Parse extra opts if any */
122 argv = np_extra_opts(&argc, argv, progname); 73 argv = np_extra_opts(&argc, argv, progname);
123 74
124 // Config from commandline 75 check_ups_config_wrapper tmp_config = process_arguments(argc, argv);
125 ups_config config = ups_config_init();
126 76
127 if (process_arguments(argc, argv, &config) == ERROR) { 77 if (tmp_config.errorcode == ERROR) {
128 usage4(_("Could not parse arguments")); 78 usage4(_("Could not parse arguments"));
129 } 79 }
80 // Config from commandline
81 check_ups_config config = tmp_config.config;
130 82
131 /* initialize alarm signal handling */ 83 /* initialize alarm signal handling */
132 signal(SIGALRM, socket_timeout_alarm_handler); 84 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -134,74 +86,75 @@ int main(int argc, char **argv) {
134 /* set socket timeout */ 86 /* set socket timeout */
135 alarm(socket_timeout); 87 alarm(socket_timeout);
136 88
137 int supported_options = UPS_NONE;
138
139 /* get the ups status if possible */ 89 /* get the ups status if possible */
140 if (determine_status(&config, &supported_options) != OK) { 90 determine_status_result query_result = determine_status(config);
91 if (query_result.errorcode != OK) {
141 return STATE_CRITICAL; 92 return STATE_CRITICAL;
142 } 93 }
143 94
95 int ups_status_flags = query_result.ups_status;
96 int supported_options = query_result.supported_options;
144 97
145 if (supported_options & UPS_STATUS) { 98 // Exit result
146 99 mp_state_enum result = STATE_UNKNOWN;
147 ups_status = strdup(""); 100 char *message = NULL;
148 101
102 if (supported_options & UPS_STATUS) {
103 char *ups_status = strdup("");
149 result = STATE_OK; 104 result = STATE_OK;
150 105
151 if (config.status & UPSSTATUS_OFF) { 106 if (ups_status_flags & UPSSTATUS_OFF) {
152 xasprintf(&ups_status, "Off"); 107 xasprintf(&ups_status, "Off");
153 result = STATE_CRITICAL; 108 result = STATE_CRITICAL;
154 } else if ((config.status & (UPSSTATUS_OB | UPSSTATUS_LB)) == 109 } else if ((ups_status_flags & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) {
155 (UPSSTATUS_OB | UPSSTATUS_LB)) {
156 xasprintf(&ups_status, _("On Battery, Low Battery")); 110 xasprintf(&ups_status, _("On Battery, Low Battery"));
157 result = STATE_CRITICAL; 111 result = STATE_CRITICAL;
158 } else { 112 } else {
159 if (config.status & UPSSTATUS_OL) { 113 if (ups_status_flags & UPSSTATUS_OL) {
160 xasprintf(&ups_status, "%s%s", ups_status, _("Online")); 114 xasprintf(&ups_status, "%s%s", ups_status, _("Online"));
161 } 115 }
162 if (config.status & UPSSTATUS_OB) { 116 if (ups_status_flags & UPSSTATUS_OB) {
163 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery")); 117 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery"));
164 result = max_state(result, STATE_WARNING); 118 result = max_state(result, STATE_WARNING);
165 } 119 }
166 if (config.status & UPSSTATUS_LB) { 120 if (ups_status_flags & UPSSTATUS_LB) {
167 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery")); 121 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery"));
168 result = max_state(result, STATE_WARNING); 122 result = max_state(result, STATE_WARNING);
169 } 123 }
170 if (config.status & UPSSTATUS_CAL) { 124 if (ups_status_flags & UPSSTATUS_CAL) {
171 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating")); 125 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating"));
172 } 126 }
173 if (config.status & UPSSTATUS_RB) { 127 if (ups_status_flags & UPSSTATUS_RB) {
174 xasprintf(&ups_status, "%s%s", ups_status, 128 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery"));
175 _(", Replace Battery"));
176 result = max_state(result, STATE_WARNING); 129 result = max_state(result, STATE_WARNING);
177 } 130 }
178 if (config.status & UPSSTATUS_BYPASS) { 131 if (ups_status_flags & UPSSTATUS_BYPASS) {
179 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass")); 132 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass"));
180 // Bypassing the battery is likely a bad thing 133 // Bypassing the battery is likely a bad thing
181 result = STATE_CRITICAL; 134 result = STATE_CRITICAL;
182 } 135 }
183 if (config.status & UPSSTATUS_OVER) { 136 if (ups_status_flags & UPSSTATUS_OVER) {
184 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload")); 137 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload"));
185 result = max_state(result, STATE_WARNING); 138 result = max_state(result, STATE_WARNING);
186 } 139 }
187 if (config.status & UPSSTATUS_TRIM) { 140 if (ups_status_flags & UPSSTATUS_TRIM) {
188 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming")); 141 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming"));
189 } 142 }
190 if (config.status & UPSSTATUS_BOOST) { 143 if (ups_status_flags & UPSSTATUS_BOOST) {
191 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting")); 144 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting"));
192 } 145 }
193 if (config.status & UPSSTATUS_CHRG) { 146 if (ups_status_flags & UPSSTATUS_CHRG) {
194 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging")); 147 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging"));
195 } 148 }
196 if (config.status & UPSSTATUS_DISCHRG) { 149 if (ups_status_flags & UPSSTATUS_DISCHRG) {
197 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging")); 150 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging"));
198 result = max_state(result, STATE_WARNING); 151 result = max_state(result, STATE_WARNING);
199 } 152 }
200 if (config.status & UPSSTATUS_ALARM) { 153 if (ups_status_flags & UPSSTATUS_ALARM) {
201 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM")); 154 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM"));
202 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
203 } 156 }
204 if (config.status & UPSSTATUS_UNKNOWN) { 157 if (ups_status_flags & UPSSTATUS_UNKNOWN) {
205 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown")); 158 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown"));
206 } 159 }
207 } 160 }
@@ -210,7 +163,7 @@ int main(int argc, char **argv) {
210 163
211 int res; 164 int res;
212 char temp_buffer[MAX_INPUT_BUFFER]; 165 char temp_buffer[MAX_INPUT_BUFFER];
213 166 char *performance_data = strdup("");
214 /* get the ups utility voltage if possible */ 167 /* get the ups utility voltage if possible */
215 res = get_ups_variable("input.voltage", temp_buffer, config); 168 res = get_ups_variable("input.voltage", temp_buffer, config);
216 if (res == NOSUCHVAR) { 169 if (res == NOSUCHVAR) {
@@ -233,24 +186,17 @@ int main(int argc, char **argv) {
233 } 186 }
234 187
235 if (config.check_variable == UPS_UTILITY) { 188 if (config.check_variable == UPS_UTILITY) {
236 if (config.check_crit && 189 if (config.check_crit && ups_utility_deviation >= config.critical_value) {
237 ups_utility_deviation >= config.critical_value) {
238 result = STATE_CRITICAL; 190 result = STATE_CRITICAL;
239 } else if (config.check_warn && 191 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) {
240 ups_utility_deviation >= config.warning_value) {
241 result = max_state(result, STATE_WARNING); 192 result = max_state(result, STATE_WARNING);
242 } 193 }
243 xasprintf(&data, "%s", 194 xasprintf(&performance_data, "%s",
244 perfdata("voltage", (long)(1000 * ups_utility_voltage), 195 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value),
245 "mV", config.check_warn, 196 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0));
246 (long)(1000 * config.warning_value),
247 config.check_crit,
248 (long)(1000 * config.critical_value), true, 0,
249 false, 0));
250 } else { 197 } else {
251 xasprintf(&data, "%s", 198 xasprintf(&performance_data, "%s",
252 perfdata("voltage", (long)(1000 * ups_utility_voltage), 199 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0));
253 "mV", false, 0, false, 0, true, 0, false, 0));
254 } 200 }
255 } 201 }
256 202
@@ -268,22 +214,17 @@ int main(int argc, char **argv) {
268 xasprintf(&message, "%sBatt=%3.1f%% ", message, ups_battery_percent); 214 xasprintf(&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
269 215
270 if (config.check_variable == UPS_BATTPCT) { 216 if (config.check_variable == UPS_BATTPCT) {
271 if (config.check_crit && 217 if (config.check_crit && ups_battery_percent <= config.critical_value) {
272 ups_battery_percent <= config.critical_value) {
273 result = STATE_CRITICAL; 218 result = STATE_CRITICAL;
274 } else if (config.check_warn && 219 } else if (config.check_warn && ups_battery_percent <= config.warning_value) {
275 ups_battery_percent <= config.warning_value) {
276 result = max_state(result, STATE_WARNING); 220 result = max_state(result, STATE_WARNING);
277 } 221 }
278 xasprintf(&data, "%s %s", data, 222 xasprintf(&performance_data, "%s %s", performance_data,
279 perfdata("battery", (long)ups_battery_percent, "%", 223 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value),
280 config.check_warn, (long)(config.warning_value), 224 config.check_crit, (long)(config.critical_value), true, 0, true, 100));
281 config.check_crit, (long)(config.critical_value),
282 true, 0, true, 100));
283 } else { 225 } else {
284 xasprintf(&data, "%s %s", data, 226 xasprintf(&performance_data, "%s %s", performance_data,
285 perfdata("battery", (long)ups_battery_percent, "%", false, 227 perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100));
286 0, false, 0, true, 0, true, 100));
287 } 228 }
288 } 229 }
289 230
@@ -301,22 +242,17 @@ int main(int argc, char **argv) {
301 xasprintf(&message, "%sLoad=%3.1f%% ", message, ups_load_percent); 242 xasprintf(&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
302 243
303 if (config.check_variable == UPS_LOADPCT) { 244 if (config.check_variable == UPS_LOADPCT) {
304 if (config.check_crit && 245 if (config.check_crit && ups_load_percent >= config.critical_value) {
305 ups_load_percent >= config.critical_value) {
306 result = STATE_CRITICAL; 246 result = STATE_CRITICAL;
307 } else if (config.check_warn && 247 } else if (config.check_warn && ups_load_percent >= config.warning_value) {
308 ups_load_percent >= config.warning_value) {
309 result = max_state(result, STATE_WARNING); 248 result = max_state(result, STATE_WARNING);
310 } 249 }
311 xasprintf(&data, "%s %s", data, 250 xasprintf(&performance_data, "%s %s", performance_data,
312 perfdata("load", (long)ups_load_percent, "%", 251 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit,
313 config.check_warn, (long)(config.warning_value), 252 (long)(config.critical_value), true, 0, true, 100));
314 config.check_crit, (long)(config.critical_value),
315 true, 0, true, 100));
316 } else { 253 } else {
317 xasprintf(&data, "%s %s", data, 254 xasprintf(&performance_data, "%s %s", performance_data,
318 perfdata("load", (long)ups_load_percent, "%", false, 0, 255 perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100));
319 false, 0, true, 0, true, 100));
320 } 256 }
321 } 257 }
322 258
@@ -345,19 +281,15 @@ int main(int argc, char **argv) {
345 if (config.check_variable == UPS_TEMP) { 281 if (config.check_variable == UPS_TEMP) {
346 if (config.check_crit && ups_temperature >= config.critical_value) { 282 if (config.check_crit && ups_temperature >= config.critical_value) {
347 result = STATE_CRITICAL; 283 result = STATE_CRITICAL;
348 } else if (config.check_warn && 284 } else if (config.check_warn && ups_temperature >= config.warning_value) {
349 ups_temperature >= config.warning_value) {
350 result = max_state(result, STATE_WARNING); 285 result = max_state(result, STATE_WARNING);
351 } 286 }
352 xasprintf(&data, "%s %s", data, 287 xasprintf(&performance_data, "%s %s", performance_data,
353 perfdata("temp", (long)ups_temperature, tunits, 288 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit,
354 config.check_warn, (long)(config.warning_value), 289 (long)(config.critical_value), true, 0, false, 0));
355 config.check_crit, (long)(config.critical_value),
356 true, 0, false, 0));
357 } else { 290 } else {
358 xasprintf(&data, "%s %s", data, 291 xasprintf(&performance_data, "%s %s", performance_data,
359 perfdata("temp", (long)ups_temperature, tunits, false, 0, 292 perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0));
360 false, 0, true, 0, false, 0));
361 } 293 }
362 } 294 }
363 295
@@ -376,19 +308,15 @@ int main(int argc, char **argv) {
376 if (config.check_variable == UPS_REALPOWER) { 308 if (config.check_variable == UPS_REALPOWER) {
377 if (config.check_crit && ups_realpower >= config.critical_value) { 309 if (config.check_crit && ups_realpower >= config.critical_value) {
378 result = STATE_CRITICAL; 310 result = STATE_CRITICAL;
379 } else if (config.check_warn && 311 } else if (config.check_warn && ups_realpower >= config.warning_value) {
380 ups_realpower >= config.warning_value) {
381 result = max_state(result, STATE_WARNING); 312 result = max_state(result, STATE_WARNING);
382 } 313 }
383 xasprintf(&data, "%s %s", data, 314 xasprintf(&performance_data, "%s %s", performance_data,
384 perfdata("realpower", (long)ups_realpower, "W", 315 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit,
385 config.check_warn, (long)(config.warning_value), 316 (long)(config.critical_value), true, 0, false, 0));
386 config.check_crit, (long)(config.critical_value),
387 true, 0, false, 0));
388 } else { 317 } else {
389 xasprintf(&data, "%s %s", data, 318 xasprintf(&performance_data, "%s %s", performance_data,
390 perfdata("realpower", (long)ups_realpower, "W", false, 0, 319 perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0));
391 false, 0, true, 0, false, 0));
392 } 320 }
393 } 321 }
394 322
@@ -402,73 +330,78 @@ int main(int argc, char **argv) {
402 /* reset timeout */ 330 /* reset timeout */
403 alarm(0); 331 alarm(0);
404 332
405 printf("UPS %s - %s|%s\n", state_text(result), message, data); 333 printf("UPS %s - %s|%s\n", state_text(result), message, performance_data);
406 return result; 334 exit(result);
407} 335}
408 336
409/* determines what options are supported by the UPS */ 337/* determines what options are supported by the UPS */
410int determine_status(ups_config *config, int *supported_options) { 338determine_status_result determine_status(const check_ups_config config) {
411 char recv_buffer[MAX_INPUT_BUFFER];
412 339
413 int res = get_ups_variable("ups.status", recv_buffer, *config); 340 determine_status_result result = {
341 .errorcode = OK,
342 .ups_status = UPSSTATUS_NONE,
343 .supported_options = 0,
344 };
345
346 char recv_buffer[MAX_INPUT_BUFFER];
347 int res = get_ups_variable("ups.status", recv_buffer, config);
414 if (res == NOSUCHVAR) { 348 if (res == NOSUCHVAR) {
415 return OK; 349 return result;
416 } 350 }
417 351
418 if (res != STATE_OK) { 352 if (res != STATE_OK) {
419 printf("%s\n", _("Invalid response received from host")); 353 printf("%s\n", _("Invalid response received from host"));
420 return ERROR; 354 result.errorcode = ERROR;
355 return result;
421 } 356 }
422 357
423 *supported_options |= UPS_STATUS; 358 result.supported_options |= UPS_STATUS;
424 359
425 char temp_buffer[MAX_INPUT_BUFFER]; 360 char temp_buffer[MAX_INPUT_BUFFER];
426 361
427 strcpy(temp_buffer, recv_buffer); 362 strcpy(temp_buffer, recv_buffer);
428 for (char *ptr = (char *)strtok(temp_buffer, " "); ptr != NULL; 363 for (char *ptr = strtok(temp_buffer, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
429 ptr = (char *)strtok(NULL, " ")) {
430 if (!strcmp(ptr, "OFF")) { 364 if (!strcmp(ptr, "OFF")) {
431 config->status |= UPSSTATUS_OFF; 365 result.ups_status |= UPSSTATUS_OFF;
432 } else if (!strcmp(ptr, "OL")) { 366 } else if (!strcmp(ptr, "OL")) {
433 config->status |= UPSSTATUS_OL; 367 result.ups_status |= UPSSTATUS_OL;
434 } else if (!strcmp(ptr, "OB")) { 368 } else if (!strcmp(ptr, "OB")) {
435 config->status |= UPSSTATUS_OB; 369 result.ups_status |= UPSSTATUS_OB;
436 } else if (!strcmp(ptr, "LB")) { 370 } else if (!strcmp(ptr, "LB")) {
437 config->status |= UPSSTATUS_LB; 371 result.ups_status |= UPSSTATUS_LB;
438 } else if (!strcmp(ptr, "CAL")) { 372 } else if (!strcmp(ptr, "CAL")) {
439 config->status |= UPSSTATUS_CAL; 373 result.ups_status |= UPSSTATUS_CAL;
440 } else if (!strcmp(ptr, "RB")) { 374 } else if (!strcmp(ptr, "RB")) {
441 config->status |= UPSSTATUS_RB; 375 result.ups_status |= UPSSTATUS_RB;
442 } else if (!strcmp(ptr, "BYPASS")) { 376 } else if (!strcmp(ptr, "BYPASS")) {
443 config->status |= UPSSTATUS_BYPASS; 377 result.ups_status |= UPSSTATUS_BYPASS;
444 } else if (!strcmp(ptr, "OVER")) { 378 } else if (!strcmp(ptr, "OVER")) {
445 config->status |= UPSSTATUS_OVER; 379 result.ups_status |= UPSSTATUS_OVER;
446 } else if (!strcmp(ptr, "TRIM")) { 380 } else if (!strcmp(ptr, "TRIM")) {
447 config->status |= UPSSTATUS_TRIM; 381 result.ups_status |= UPSSTATUS_TRIM;
448 } else if (!strcmp(ptr, "BOOST")) { 382 } else if (!strcmp(ptr, "BOOST")) {
449 config->status |= UPSSTATUS_BOOST; 383 result.ups_status |= UPSSTATUS_BOOST;
450 } else if (!strcmp(ptr, "CHRG")) { 384 } else if (!strcmp(ptr, "CHRG")) {
451 config->status |= UPSSTATUS_CHRG; 385 result.ups_status |= UPSSTATUS_CHRG;
452 } else if (!strcmp(ptr, "DISCHRG")) { 386 } else if (!strcmp(ptr, "DISCHRG")) {
453 config->status |= UPSSTATUS_DISCHRG; 387 result.ups_status |= UPSSTATUS_DISCHRG;
454 } else if (!strcmp(ptr, "ALARM")) { 388 } else if (!strcmp(ptr, "ALARM")) {
455 config->status |= UPSSTATUS_ALARM; 389 result.ups_status |= UPSSTATUS_ALARM;
456 } else { 390 } else {
457 config->status |= UPSSTATUS_UNKNOWN; 391 result.ups_status |= UPSSTATUS_UNKNOWN;
458 } 392 }
459 } 393 }
460 394
461 return OK; 395 return result;
462} 396}
463 397
464/* gets a variable value for a specific UPS */ 398/* gets a variable value for a specific UPS */
465int get_ups_variable(const char *varname, char *buf, const ups_config config) { 399int get_ups_variable(const char *varname, char *buf, const check_ups_config config) {
466 char send_buffer[MAX_INPUT_BUFFER]; 400 char send_buffer[MAX_INPUT_BUFFER];
467 401
468 /* create the command string to send to the UPS daemon */ 402 /* create the command string to send to the UPS daemon */
469 /* Add LOGOUT to avoid read failure logs */ 403 /* Add LOGOUT to avoid read failure logs */
470 int res = snprintf(send_buffer, sizeof(send_buffer), 404 int res = snprintf(send_buffer, sizeof(send_buffer), "GET VAR %s %s\nLOGOUT\n", config.ups_name, varname);
471 "GET VAR %s %s\nLOGOUT\n", config.ups_name, varname);
472 if ((res > 0) && ((size_t)res >= sizeof(send_buffer))) { 405 if ((res > 0) && ((size_t)res >= sizeof(send_buffer))) {
473 printf("%s\n", _("UPS name to long for buffer")); 406 printf("%s\n", _("UPS name to long for buffer"));
474 return ERROR; 407 return ERROR;
@@ -477,9 +410,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
477 char temp_buffer[MAX_INPUT_BUFFER]; 410 char temp_buffer[MAX_INPUT_BUFFER];
478 411
479 /* send the command to the daemon and get a response back */ 412 /* send the command to the daemon and get a response back */
480 if (process_tcp_request(config.server_address, config.server_port, 413 if (process_tcp_request(config.server_address, config.server_port, send_buffer, temp_buffer, sizeof(temp_buffer)) != STATE_OK) {
481 send_buffer, temp_buffer,
482 sizeof(temp_buffer)) != STATE_OK) {
483 printf("%s\n", _("Invalid response received from host")); 414 printf("%s\n", _("Invalid response received from host"));
484 return ERROR; 415 return ERROR;
485 } 416 }
@@ -496,8 +427,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
496 ptr[len - 1] = 0; 427 ptr[len - 1] = 0;
497 } 428 }
498 if (strcmp(ptr, "ERR UNKNOWN-UPS") == 0) { 429 if (strcmp(ptr, "ERR UNKNOWN-UPS") == 0) {
499 printf(_("CRITICAL - no such UPS '%s' on that host\n"), 430 printf(_("CRITICAL - no such UPS '%s' on that host\n"), config.ups_name);
500 config.ups_name);
501 return ERROR; 431 return ERROR;
502 } 432 }
503 433
@@ -534,7 +464,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
534 [-wv warn_value] [-cv crit_value] [-to to_sec] */ 464 [-wv warn_value] [-cv crit_value] [-to to_sec] */
535 465
536/* process command-line arguments */ 466/* process command-line arguments */
537int process_arguments(int argc, char **argv, ups_config *config) { 467check_ups_config_wrapper process_arguments(int argc, char **argv) {
538 468
539 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
540 {"ups", required_argument, 0, 'u'}, 470 {"ups", required_argument, 0, 'u'},
@@ -548,8 +478,14 @@ int process_arguments(int argc, char **argv, ups_config *config) {
548 {"help", no_argument, 0, 'h'}, 478 {"help", no_argument, 0, 'h'},
549 {0, 0, 0, 0}}; 479 {0, 0, 0, 0}};
550 480
481 check_ups_config_wrapper result = {
482 .errorcode = OK,
483 .config = check_ups_config_init(),
484 };
485
551 if (argc < 2) { 486 if (argc < 2) {
552 return ERROR; 487 result.errorcode = ERROR;
488 return result;
553 } 489 }
554 490
555 int c; 491 int c;
@@ -576,52 +512,52 @@ int process_arguments(int argc, char **argv, ups_config *config) {
576 usage5(); 512 usage5();
577 case 'H': /* hostname */ 513 case 'H': /* hostname */
578 if (is_host(optarg)) { 514 if (is_host(optarg)) {
579 config->server_address = optarg; 515 result.config.server_address = optarg;
580 } else { 516 } else {
581 usage2(_("Invalid hostname/address"), optarg); 517 usage2(_("Invalid hostname/address"), optarg);
582 } 518 }
583 break; 519 break;
584 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for 520 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for
585 Fahrenheit) */ 521 Fahrenheit) */
586 config->temp_output_c = true; 522 result.config.temp_output_c = true;
587 break; 523 break;
588 case 'u': /* ups name */ 524 case 'u': /* ups name */
589 config->ups_name = optarg; 525 result.config.ups_name = optarg;
590 break; 526 break;
591 case 'p': /* port */ 527 case 'p': /* port */
592 if (is_intpos(optarg)) { 528 if (is_intpos(optarg)) {
593 config->server_port = atoi(optarg); 529 result.config.server_port = atoi(optarg);
594 } else { 530 } else {
595 usage2(_("Port must be a positive integer"), optarg); 531 usage2(_("Port must be a positive integer"), optarg);
596 } 532 }
597 break; 533 break;
598 case 'c': /* critical time threshold */ 534 case 'c': /* critical time threshold */
599 if (is_intnonneg(optarg)) { 535 if (is_intnonneg(optarg)) {
600 config->critical_value = atoi(optarg); 536 result.config.critical_value = atoi(optarg);
601 config->check_crit = true; 537 result.config.check_crit = true;
602 } else { 538 } else {
603 usage2(_("Critical time must be a positive integer"), optarg); 539 usage2(_("Critical time must be a positive integer"), optarg);
604 } 540 }
605 break; 541 break;
606 case 'w': /* warning time threshold */ 542 case 'w': /* warning time threshold */
607 if (is_intnonneg(optarg)) { 543 if (is_intnonneg(optarg)) {
608 config->warning_value = atoi(optarg); 544 result.config.warning_value = atoi(optarg);
609 config->check_warn = true; 545 result.config.check_warn = true;
610 } else { 546 } else {
611 usage2(_("Warning time must be a positive integer"), optarg); 547 usage2(_("Warning time must be a positive integer"), optarg);
612 } 548 }
613 break; 549 break;
614 case 'v': /* variable */ 550 case 'v': /* variable */
615 if (!strcmp(optarg, "LINE")) { 551 if (!strcmp(optarg, "LINE")) {
616 config->check_variable = UPS_UTILITY; 552 result.config.check_variable = UPS_UTILITY;
617 } else if (!strcmp(optarg, "TEMP")) { 553 } else if (!strcmp(optarg, "TEMP")) {
618 config->check_variable = UPS_TEMP; 554 result.config.check_variable = UPS_TEMP;
619 } else if (!strcmp(optarg, "BATTPCT")) { 555 } else if (!strcmp(optarg, "BATTPCT")) {
620 config->check_variable = UPS_BATTPCT; 556 result.config.check_variable = UPS_BATTPCT;
621 } else if (!strcmp(optarg, "LOADPCT")) { 557 } else if (!strcmp(optarg, "LOADPCT")) {
622 config->check_variable = UPS_LOADPCT; 558 result.config.check_variable = UPS_LOADPCT;
623 } else if (!strcmp(optarg, "REALPOWER")) { 559 } else if (!strcmp(optarg, "REALPOWER")) {
624 config->check_variable = UPS_REALPOWER; 560 result.config.check_variable = UPS_REALPOWER;
625 } else { 561 } else {
626 usage2(_("Unrecognized UPS variable"), optarg); 562 usage2(_("Unrecognized UPS variable"), optarg);
627 } 563 }
@@ -642,27 +578,27 @@ int process_arguments(int argc, char **argv, ups_config *config) {
642 } 578 }
643 } 579 }
644 580
645 if (config->server_address == NULL && argc > optind) { 581 if (result.config.server_address == NULL && argc > optind) {
646 if (is_host(argv[optind])) { 582 if (is_host(argv[optind])) {
647 config->server_address = argv[optind++]; 583 result.config.server_address = argv[optind++];
648 } else { 584 } else {
649 usage2(_("Invalid hostname/address"), optarg); 585 usage2(_("Invalid hostname/address"), optarg);
650 } 586 }
651 } 587 }
652 588
653 if (config->server_address == NULL) { 589 if (result.config.server_address == NULL) {
654 config->server_address = strdup("127.0.0.1"); 590 result.config.server_address = strdup("127.0.0.1");
655 } 591 }
656 592
657 return validate_arguments(*config); 593 return validate_arguments(result);
658} 594}
659 595
660int validate_arguments(ups_config config) { 596check_ups_config_wrapper validate_arguments(check_ups_config_wrapper config_wrapper) {
661 if (!config.ups_name) { 597 if (config_wrapper.config.ups_name) {
662 printf("%s\n", _("Error : no UPS indicated")); 598 printf("%s\n", _("Error : no UPS indicated"));
663 return ERROR; 599 config_wrapper.errorcode = ERROR;
664 } 600 }
665 return OK; 601 return config_wrapper;
666} 602}
667 603
668void print_help(void) { 604void print_help(void) {
@@ -694,8 +630,7 @@ void print_help(void) {
694 printf(" %s\n", "-T, --temperature"); 630 printf(" %s\n", "-T, --temperature");
695 printf(" %s\n", _("Output of temperatures in Celsius")); 631 printf(" %s\n", _("Output of temperatures in Celsius"));
696 printf(" %s\n", "-v, --variable=STRING"); 632 printf(" %s\n", "-v, --variable=STRING");
697 printf(" %s %s\n", _("Valid values for STRING are"), 633 printf(" %s %s\n", _("Valid values for STRING are"), "LINE, TEMP, BATTPCT, LOADPCT or REALPOWER");
698 "LINE, TEMP, BATTPCT, LOADPCT or REALPOWER");
699 634
700 printf(UT_WARN_CRIT); 635 printf(UT_WARN_CRIT);
701 636
@@ -731,8 +666,7 @@ void print_help(void) {
731 "with Russell Kroll's")); 666 "with Russell Kroll's"));
732 printf(" %s\n", _("Network UPS Tools be installed on the remote host. If " 667 printf(" %s\n", _("Network UPS Tools be installed on the remote host. If "
733 "you do not have the")); 668 "you do not have the"));
734 printf(" %s\n", 669 printf(" %s\n", _("package installed on your system, you can download it from"));
735 _("package installed on your system, you can download it from"));
736 printf(" %s\n", _("http://www.networkupstools.org")); 670 printf(" %s\n", _("http://www.networkupstools.org"));
737 671
738 printf(UT_SUPPORT); 672 printf(UT_SUPPORT);
diff --git a/plugins/check_ups.d/config.h b/plugins/check_ups.d/config.h
new file mode 100644
index 00000000..353104f2
--- /dev/null
+++ b/plugins/check_ups.d/config.h
@@ -0,0 +1,55 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6#define UPS_NONE 0 /* no supported options */
7#define UPS_UTILITY 1 /* supports utility line */
8#define UPS_BATTPCT 2 /* supports percent battery remaining */
9#define UPS_STATUS 4 /* supports UPS status */
10#define UPS_TEMP 8 /* supports UPS temperature */
11#define UPS_LOADPCT 16 /* supports load percent */
12#define UPS_REALPOWER 32 /* supports real power */
13
14#define UPSSTATUS_NONE 0
15#define UPSSTATUS_OFF 1
16#define UPSSTATUS_OL 2
17#define UPSSTATUS_OB 4
18#define UPSSTATUS_LB 8
19#define UPSSTATUS_CAL 16
20#define UPSSTATUS_RB 32 /*Replace Battery */
21#define UPSSTATUS_BYPASS 64
22#define UPSSTATUS_OVER 128
23#define UPSSTATUS_TRIM 256
24#define UPSSTATUS_BOOST 512
25#define UPSSTATUS_CHRG 1024
26#define UPSSTATUS_DISCHRG 2048
27#define UPSSTATUS_UNKNOWN 4096
28#define UPSSTATUS_ALARM 8192
29
30enum {
31 PORT = 3493
32};
33
34typedef struct ups_config {
35 unsigned int server_port;
36 char *server_address;
37 char *ups_name;
38 double warning_value;
39 double critical_value;
40 bool check_warn;
41 bool check_crit;
42 int check_variable;
43 bool temp_output_c;
44} check_ups_config;
45
46check_ups_config check_ups_config_init(void) {
47 check_ups_config tmp = {0};
48 tmp.server_port = PORT;
49 tmp.server_address = NULL;
50 tmp.ups_name = NULL;
51 tmp.check_variable = UPS_NONE;
52
53 return tmp;
54}
55
diff --git a/plugins/check_users.c b/plugins/check_users.c
index 89b95369..f1e1c39d 100644
--- a/plugins/check_users.c
+++ b/plugins/check_users.c
@@ -1,71 +1,69 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_users plugin 3 * Monitoring check_users plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2012 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_users plugin 10 * This file contains the check_users plugin
11* 11 *
12* This plugin checks the number of users currently logged in on the local 12 * This plugin checks the number of users currently logged in on the local
13* system and generates an error if the number exceeds the thresholds 13 * system and generates an error if the number exceeds the thresholds
14* specified. 14 * specified.
15* 15 *
16* 16 *
17* This program is free software: you can redistribute it and/or modify 17 * This program is free software: you can redistribute it and/or modify
18* it under the terms of the GNU General Public License as published by 18 * it under the terms of the GNU General Public License as published by
19* the Free Software Foundation, either version 3 of the License, or 19 * the Free Software Foundation, either version 3 of the License, or
20* (at your option) any later version. 20 * (at your option) any later version.
21* 21 *
22* This program is distributed in the hope that it will be useful, 22 * This program is distributed in the hope that it will be useful,
23* but WITHOUT ANY WARRANTY; without even the implied warranty of 23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25* GNU General Public License for more details. 25 * GNU General Public License for more details.
26* 26 *
27* You should have received a copy of the GNU General Public License 27 * You should have received a copy of the GNU General Public License
28* along with this program. If not, see <http://www.gnu.org/licenses/>. 28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29* 29 *
30* 30 *
31*****************************************************************************/ 31 *****************************************************************************/
32 32
33const char *progname = "check_users"; 33const char *progname = "check_users";
34const char *copyright = "2000-2007"; 34const char *copyright = "2000-2024";
35const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
36 36
37#include "common.h" 37#include "common.h"
38#include "utils.h" 38#include "utils.h"
39 39
40#if HAVE_WTSAPI32_H 40#if HAVE_WTSAPI32_H
41# include <windows.h> 41# include <windows.h>
42# include <wtsapi32.h> 42# include <wtsapi32.h>
43# undef ERROR 43# undef ERROR
44# define ERROR -1 44# define ERROR -1
45#elif HAVE_UTMPX_H 45#elif HAVE_UTMPX_H
46# include <utmpx.h> 46# include <utmpx.h>
47#else 47#else
48# include "popen.h" 48# include "popen.h"
49#endif 49#endif
50 50
51#ifdef HAVE_LIBSYSTEMD 51#ifdef HAVE_LIBSYSTEMD
52#include <systemd/sd-daemon.h> 52# include <systemd/sd-daemon.h>
53#include <systemd/sd-login.h> 53# include <systemd/sd-login.h>
54#endif 54#endif
55 55
56#define possibly_set(a,b) ((a) == 0 ? (b) : 0) 56#define possibly_set(a, b) ((a) == 0 ? (b) : 0)
57 57
58int process_arguments (int, char **); 58static int process_arguments(int, char **);
59void print_help (void); 59static void print_help(void);
60void print_usage (void); 60void print_usage(void);
61 61
62char *warning_range = NULL; 62static char *warning_range = NULL;
63char *critical_range = NULL; 63static char *critical_range = NULL;
64thresholds *thlds = NULL; 64static thresholds *thlds = NULL;
65 65
66int 66int main(int argc, char **argv) {
67main (int argc, char **argv)
68{
69 int users = -1; 67 int users = -1;
70 int result = STATE_UNKNOWN; 68 int result = STATE_UNKNOWN;
71#if HAVE_WTSAPI32_H 69#if HAVE_WTSAPI32_H
@@ -78,74 +76,71 @@ main (int argc, char **argv)
78 char input_buffer[MAX_INPUT_BUFFER]; 76 char input_buffer[MAX_INPUT_BUFFER];
79#endif 77#endif
80 78
81 setlocale (LC_ALL, ""); 79 setlocale(LC_ALL, "");
82 bindtextdomain (PACKAGE, LOCALEDIR); 80 bindtextdomain(PACKAGE, LOCALEDIR);
83 textdomain (PACKAGE); 81 textdomain(PACKAGE);
84 82
85 /* Parse extra opts if any */ 83 /* Parse extra opts if any */
86 argv = np_extra_opts (&argc, argv, progname); 84 argv = np_extra_opts(&argc, argv, progname);
87 85
88 if (process_arguments (argc, argv) == ERROR) 86 if (process_arguments(argc, argv) == ERROR)
89 usage4 (_("Could not parse arguments")); 87 usage4(_("Could not parse arguments"));
90 88
91 users = 0; 89 users = 0;
92 90
93#ifdef HAVE_LIBSYSTEMD 91#ifdef HAVE_LIBSYSTEMD
94 if (sd_booted () > 0) 92 if (sd_booted() > 0)
95 users = sd_get_sessions (NULL); 93 users = sd_get_sessions(NULL);
96 else { 94 else {
97#endif 95#endif
98#if HAVE_WTSAPI32_H 96#if HAVE_WTSAPI32_H
99 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 97 if (!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &wtsinfo, &wtscount)) {
100 0, 1, &wtsinfo, &wtscount)) { 98 printf(_("Could not enumerate RD sessions: %d\n"), GetLastError());
101 printf(_("Could not enumerate RD sessions: %d\n"), GetLastError()); 99 return STATE_UNKNOWN;
102 return STATE_UNKNOWN; 100 }
103 }
104 101
105 for (index = 0; index < wtscount; index++) { 102 for (index = 0; index < wtscount; index++) {
106 LPTSTR username; 103 LPTSTR username;
107 DWORD size; 104 DWORD size;
108 int len; 105 int len;
109 106
110 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, 107 if (!WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wtsinfo[index].SessionId, WTSUserName, &username, &size))
111 wtsinfo[index].SessionId, WTSUserName, &username, &size)) 108 continue;
112 continue;
113 109
114 len = lstrlen(username); 110 len = lstrlen(username);
115 111
116 WTSFreeMemory(username); 112 WTSFreeMemory(username);
117 113
118 if (len == 0) 114 if (len == 0)
119 continue; 115 continue;
120 116
121 if (wtsinfo[index].State == WTSActive || 117 if (wtsinfo[index].State == WTSActive || wtsinfo[index].State == WTSDisconnected)
122 wtsinfo[index].State == WTSDisconnected) 118 users++;
123 users++; 119 }
124 }
125 120
126 WTSFreeMemory(wtsinfo); 121 WTSFreeMemory(wtsinfo);
127#elif HAVE_UTMPX_H 122#elif HAVE_UTMPX_H
128 /* get currently logged users from utmpx */ 123 /* get currently logged users from utmpx */
129 setutxent (); 124 setutxent();
130 125
131 while ((putmpx = getutxent ()) != NULL) 126 while ((putmpx = getutxent()) != NULL)
132 if (putmpx->ut_type == USER_PROCESS) 127 if (putmpx->ut_type == USER_PROCESS)
133 users++; 128 users++;
134 129
135 endutxent (); 130 endutxent();
136#else 131#else
137 /* run the command */ 132 /* run the command */
138 child_process = spopen (WHO_COMMAND); 133 child_process = spopen(WHO_COMMAND);
139 if (child_process == NULL) { 134 if (child_process == NULL) {
140 printf (_("Could not open pipe: %s\n"), WHO_COMMAND); 135 printf(_("Could not open pipe: %s\n"), WHO_COMMAND);
141 return STATE_UNKNOWN; 136 return STATE_UNKNOWN;
142 } 137 }
143 138
144 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 139 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
145 if (child_stderr == NULL) 140 if (child_stderr == NULL)
146 printf (_("Could not open stderr for %s\n"), WHO_COMMAND); 141 printf(_("Could not open stderr for %s\n"), WHO_COMMAND);
147 142
148 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 143 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
149 /* increment 'users' on all lines except total user count */ 144 /* increment 'users' on all lines except total user count */
150 if (input_buffer[0] != '#') { 145 if (input_buffer[0] != '#') {
151 users++; 146 users++;
@@ -153,18 +148,18 @@ main (int argc, char **argv)
153 } 148 }
154 149
155 /* get total logged in users */ 150 /* get total logged in users */
156 if (sscanf (input_buffer, _("# users=%d"), &users) == 1) 151 if (sscanf(input_buffer, _("# users=%d"), &users) == 1)
157 break; 152 break;
158 } 153 }
159 154
160 /* check STDERR */ 155 /* check STDERR */
161 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) 156 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
162 result = possibly_set (result, STATE_UNKNOWN); 157 result = possibly_set(result, STATE_UNKNOWN);
163 (void) fclose (child_stderr); 158 (void)fclose(child_stderr);
164 159
165 /* close the pipe */ 160 /* close the pipe */
166 if (spclose (child_process)) 161 if (spclose(child_process))
167 result = possibly_set (result, STATE_UNKNOWN); 162 result = possibly_set(result, STATE_UNKNOWN);
168#endif 163#endif
169#ifdef HAVE_LIBSYSTEMD 164#ifdef HAVE_LIBSYSTEMD
170 } 165 }
@@ -174,109 +169,99 @@ main (int argc, char **argv)
174 result = get_status((double)users, thlds); 169 result = get_status((double)users, thlds);
175 170
176 if (result == STATE_UNKNOWN) 171 if (result == STATE_UNKNOWN)
177 printf ("%s\n", _("Unable to read output")); 172 printf("%s\n", _("Unable to read output"));
178 else { 173 else {
179 printf (_("USERS %s - %d users currently logged in |%s\n"), 174 printf(_("USERS %s - %d users currently logged in |%s\n"), state_text(result), users,
180 state_text(result), users, 175 sperfdata_int("users", users, "", warning_range, critical_range, true, 0, false, 0));
181 sperfdata_int("users", users, "", warning_range,
182 critical_range, true, 0, false, 0));
183 } 176 }
184 177
185 return result; 178 return result;
186} 179}
187 180
188/* process command-line arguments */ 181/* process command-line arguments */
189int 182int process_arguments(int argc, char **argv) {
190process_arguments (int argc, char **argv) 183 static struct option longopts[] = {{"critical", required_argument, 0, 'c'},
191{ 184 {"warning", required_argument, 0, 'w'},
192 int c; 185 {"version", no_argument, 0, 'V'},
193 int option = 0; 186 {"help", no_argument, 0, 'h'},
194 static struct option longopts[] = { 187 {0, 0, 0, 0}};
195 {"critical", required_argument, 0, 'c'},
196 {"warning", required_argument, 0, 'w'},
197 {"version", no_argument, 0, 'V'},
198 {"help", no_argument, 0, 'h'},
199 {0, 0, 0, 0}
200 };
201 188
202 if (argc < 2) 189 if (argc < 2)
203 usage ("\n"); 190 usage("\n");
204 191
192 int option_char;
205 while (true) { 193 while (true) {
206 c = getopt_long (argc, argv, "+hVvc:w:", longopts, &option); 194 int option = 0;
195 option_char = getopt_long(argc, argv, "+hVvc:w:", longopts, &option);
207 196
208 if (c == -1 || c == EOF || c == 1) 197 if (option_char == -1 || option_char == EOF || option_char == 1)
209 break; 198 break;
210 199
211 switch (c) { 200 switch (option_char) {
212 case '?': /* print short usage statement if args not parsable */ 201 case '?': /* print short usage statement if args not parsable */
213 usage5 (); 202 usage5();
214 case 'h': /* help */ 203 case 'h': /* help */
215 print_help (); 204 print_help();
216 exit (STATE_UNKNOWN); 205 exit(STATE_UNKNOWN);
217 case 'V': /* version */ 206 case 'V': /* version */
218 print_revision (progname, NP_VERSION); 207 print_revision(progname, NP_VERSION);
219 exit (STATE_UNKNOWN); 208 exit(STATE_UNKNOWN);
220 case 'c': /* critical */ 209 case 'c': /* critical */
221 critical_range = optarg; 210 critical_range = optarg;
222 break; 211 break;
223 case 'w': /* warning */ 212 case 'w': /* warning */
224 warning_range = optarg; 213 warning_range = optarg;
225 break; 214 break;
226 } 215 }
227 } 216 }
228 217
229 c = optind; 218 option_char = optind;
230 219
231 if (warning_range == NULL && argc > c) 220 if (warning_range == NULL && argc > option_char)
232 warning_range = argv[c++]; 221 warning_range = argv[option_char++];
233 222
234 if (critical_range == NULL && argc > c) 223 if (critical_range == NULL && argc > option_char)
235 critical_range = argv[c++]; 224 critical_range = argv[option_char++];
236 225
237 /* this will abort in case of invalid ranges */ 226 /* this will abort in case of invalid ranges */
238 set_thresholds (&thlds, warning_range, critical_range); 227 set_thresholds(&thlds, warning_range, critical_range);
239 228
240 if (!thlds->warning) { 229 if (!thlds->warning) {
241 usage4 (_("Warning threshold must be a valid range expression")); 230 usage4(_("Warning threshold must be a valid range expression"));
242 } 231 }
243 232
244 if (!thlds->critical) { 233 if (!thlds->critical) {
245 usage4 (_("Critical threshold must be a valid range expression")); 234 usage4(_("Critical threshold must be a valid range expression"));
246 } 235 }
247 236
248 return OK; 237 return OK;
249} 238}
250 239
251void 240void print_help(void) {
252print_help (void) 241 print_revision(progname, NP_VERSION);
253{
254 print_revision (progname, NP_VERSION);
255 242
256 printf ("Copyright (c) 1999 Ethan Galstad\n"); 243 printf("Copyright (c) 1999 Ethan Galstad\n");
257 printf (COPYRIGHT, copyright, email); 244 printf(COPYRIGHT, copyright, email);
258 245
259 printf ("%s\n", _("This plugin checks the number of users currently logged in on the local")); 246 printf("%s\n", _("This plugin checks the number of users currently logged in on the local"));
260 printf ("%s\n", _("system and generates an error if the number exceeds the thresholds specified.")); 247 printf("%s\n", _("system and generates an error if the number exceeds the thresholds specified."));
261 248
262 printf ("\n\n"); 249 printf("\n\n");
263 250
264 print_usage (); 251 print_usage();
265 252
266 printf (UT_HELP_VRSN); 253 printf(UT_HELP_VRSN);
267 printf (UT_EXTRA_OPTS); 254 printf(UT_EXTRA_OPTS);
268 255
269 printf (" %s\n", "-w, --warning=RANGE_EXPRESSION"); 256 printf(" %s\n", "-w, --warning=RANGE_EXPRESSION");
270 printf (" %s\n", _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION")); 257 printf(" %s\n", _("Set WARNING status if number of logged in users violates RANGE_EXPRESSION"));
271 printf (" %s\n", "-c, --critical=RANGE_EXPRESSION"); 258 printf(" %s\n", "-c, --critical=RANGE_EXPRESSION");
272 printf (" %s\n", _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION")); 259 printf(" %s\n", _("Set CRITICAL status if number of logged in users violates RANGE_EXPRESSION"));
273 260
274 printf (UT_SUPPORT); 261 printf(UT_SUPPORT);
275} 262}
276 263
277void 264void print_usage(void) {
278print_usage (void) 265 printf("%s\n", _("Usage:"));
279{ 266 printf("%s -w <users> -c <users>\n", progname);
280 printf ("%s\n", _("Usage:"));
281 printf ("%s -w <users> -c <users>\n", progname);
282} 267}
diff --git a/plugins/common.h b/plugins/common.h
index 833479ce..35d1e549 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -31,7 +31,8 @@
31#ifndef _COMMON_H_ 31#ifndef _COMMON_H_
32#define _COMMON_H_ 32#define _COMMON_H_
33 33
34#include "config.h" 34#include "../config.h"
35#include "../lib/monitoringplug.h"
35 36
36#ifdef HAVE_FEATURES_H 37#ifdef HAVE_FEATURES_H
37#include <features.h> 38#include <features.h>
@@ -90,16 +91,10 @@
90# define GET_NUMBER_OF_CPUS() -1 91# define GET_NUMBER_OF_CPUS() -1
91#endif 92#endif
92 93
93#ifdef TIME_WITH_SYS_TIME 94#ifdef HAVE_SYS_TIME_H
94# include <sys/time.h> 95# include <sys/time.h>
95# include <time.h>
96#else
97# ifdef HAVE_SYS_TIME_H
98# include <sys/time.h>
99# else
100# include <time.h>
101# endif
102#endif 96#endif
97#include <time.h>
103 98
104#ifdef HAVE_SYS_TYPES_H 99#ifdef HAVE_SYS_TYPES_H
105#include <sys/types.h> 100#include <sys/types.h>
@@ -115,7 +110,7 @@
115 110
116/* GNU Libraries */ 111/* GNU Libraries */
117#include <getopt.h> 112#include <getopt.h>
118#include "dirname.h" 113#include "../gl/dirname.h"
119 114
120#include <locale.h> 115#include <locale.h>
121 116
@@ -185,14 +180,6 @@ enum {
185}; 180};
186 181
187enum { 182enum {
188 STATE_OK,
189 STATE_WARNING,
190 STATE_CRITICAL,
191 STATE_UNKNOWN,
192 STATE_DEPENDENT
193};
194
195enum {
196 DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */ 183 DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */
197 MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */ 184 MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */
198 MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */ 185 MAX_HOST_ADDRESS_LENGTH = 256 /* max size of a host address */
@@ -203,7 +190,7 @@ enum {
203 * Internationalization 190 * Internationalization
204 * 191 *
205 */ 192 */
206#include "gettext.h" 193#include "../gl/gettext.h"
207#define _(String) gettext (String) 194#define _(String) gettext (String)
208#if ! ENABLE_NLS 195#if ! ENABLE_NLS
209# undef textdomain 196# undef textdomain
diff --git a/plugins/negate.c b/plugins/negate.c
index c5fe7e13..0520d298 100644
--- a/plugins/negate.c
+++ b/plugins/negate.c
@@ -1,36 +1,36 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring negate plugin 3 * Monitoring negate plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2002-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the negate plugin 10 * This file contains the negate plugin
11* 11 *
12* Negates the status of a plugin (returns OK for CRITICAL, and vice-versa). 12 * Negates the status of a plugin (returns OK for CRITICAL, and vice-versa).
13* Can also perform custom state switching. 13 * Can also perform custom state switching.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "negate"; 32const char *progname = "negate";
33const char *copyright = "2002-2008"; 33const char *copyright = "2002-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#define DEFAULT_TIMEOUT 11 36#define DEFAULT_TIMEOUT 11
@@ -38,203 +38,203 @@ const char *email = "devel@monitoring-plugins.org";
38#include "common.h" 38#include "common.h"
39#include "utils.h" 39#include "utils.h"
40#include "utils_cmd.h" 40#include "utils_cmd.h"
41#include "negate.d/config.h"
42#include "../lib/states.h"
41 43
42#include <ctype.h> 44typedef struct {
45 int errorcode;
46 negate_config config;
47} negate_config_wrapper;
48static negate_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
49static negate_config_wrapper validate_arguments(negate_config_wrapper /*config_wrapper*/);
43 50
44/* char *command_line; */ 51static void print_help(void);
52void print_usage(void);
45 53
46static const char **process_arguments (int, char **); 54int main(int argc, char **argv) {
47void validate_arguments (char **); 55 setlocale(LC_ALL, "");
48void print_help (void); 56 bindtextdomain(PACKAGE, LOCALEDIR);
49void print_usage (void); 57 textdomain(PACKAGE);
50bool subst_text = false;
51 58
52static int state[4] = { 59 timeout_interval = DEFAULT_TIMEOUT;
53 STATE_OK,
54 STATE_WARNING,
55 STATE_CRITICAL,
56 STATE_UNKNOWN,
57};
58 60
59int 61 negate_config_wrapper tmp_config = process_arguments(argc, argv);
60main (int argc, char **argv)
61{
62 int result = STATE_UNKNOWN;
63 char *sub;
64 char **command_line;
65 output chld_out, chld_err;
66 62
67 setlocale (LC_ALL, ""); 63 if (tmp_config.errorcode == ERROR) {
68 bindtextdomain (PACKAGE, LOCALEDIR); 64 die(STATE_UNKNOWN, _("negate: Failed to parse input"));
69 textdomain (PACKAGE); 65 }
70 66
71 timeout_interval = DEFAULT_TIMEOUT; 67 negate_config config = tmp_config.config;
72 68
73 command_line = (char **) process_arguments (argc, argv); 69 char **command_line = config.command_line;
74 70
75 /* Set signal handling and alarm */ 71 /* Set signal handling and alarm */
76 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) 72 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
77 die (STATE_UNKNOWN, _("Cannot catch SIGALRM")); 73 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
74 }
75
76 (void)alarm(timeout_interval);
78 77
79 (void) alarm ((unsigned) timeout_interval); 78 mp_state_enum result = STATE_UNKNOWN;
79 output chld_out;
80 output chld_err;
80 81
81 /* catch when the command is quoted */ 82 /* catch when the command is quoted */
82 if(command_line[1] == NULL) { 83 if (command_line[1] == NULL) {
83 result = cmd_run (command_line[0], &chld_out, &chld_err, 0); 84 result = cmd_run(command_line[0], &chld_out, &chld_err, 0);
84 } else { 85 } else {
85 result = cmd_run_array (command_line, &chld_out, &chld_err, 0); 86 result = cmd_run_array(command_line, &chld_out, &chld_err, 0);
86 } 87 }
87 if (chld_err.lines > 0) { 88 if (chld_err.lines > 0) {
88 for (size_t i = 0; i < chld_err.lines; i++) { 89 for (size_t i = 0; i < chld_err.lines; i++) {
89 fprintf (stderr, "%s\n", chld_err.line[i]); 90 fprintf(stderr, "%s\n", chld_err.line[i]);
90 } 91 }
91 } 92 }
92 93
93 /* Return UNKNOWN or worse if no output is returned */ 94 /* Return UNKNOWN or worse if no output is returned */
94 if (chld_out.lines == 0) 95 if (chld_out.lines == 0) {
95 die (max_state_alt (result, STATE_UNKNOWN), _("No data returned from command\n")); 96 die(max_state_alt(result, STATE_UNKNOWN), _("No data returned from command\n"));
97 }
96 98
99 char *sub;
97 for (size_t i = 0; i < chld_out.lines; i++) { 100 for (size_t i = 0; i < chld_out.lines; i++) {
98 if (subst_text && result >= 0 && result <= 4 && result != state[result]) { 101 if (config.subst_text && result >= 0 && result <= 4 && result != config.state[result]) {
99 /* Loop over each match found */ 102 /* Loop over each match found */
100 while ((sub = strstr (chld_out.line[i], state_text (result)))) { 103 while ((sub = strstr(chld_out.line[i], state_text(result)))) {
101 /* Terminate the first part and skip over the string we'll substitute */ 104 /* Terminate the first part and skip over the string we'll substitute */
102 *sub = '\0'; 105 *sub = '\0';
103 sub += strlen (state_text (result)); 106 sub += strlen(state_text(result));
104 /* then put everything back together */ 107 /* then put everything back together */
105 xasprintf (&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text (state[result]), sub); 108 xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text(config.state[result]), sub);
106 } 109 }
107 } 110 }
108 printf ("%s\n", chld_out.line[i]); 111 printf("%s\n", chld_out.line[i]);
109 } 112 }
110 113
111 if (result >= 0 && result <= 4) { 114 if (result >= 0 && result <= 4) {
112 exit (state[result]); 115 exit(config.state[result]);
113 } else { 116 } else {
114 exit (result); 117 exit(result);
115 } 118 }
116} 119}
117 120
118
119/* process command-line arguments */ 121/* process command-line arguments */
120static const char ** 122static negate_config_wrapper process_arguments(int argc, char **argv) {
121process_arguments (int argc, char **argv) 123 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'},
122{ 124 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'},
123 int c; 125 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'},
124 bool permute = true; 126 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'},
125 127 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}};
126 int option = 0; 128
127 static struct option longopts[] = { 129 negate_config_wrapper result = {
128 {"help", no_argument, 0, 'h'}, 130 .errorcode = OK,
129 {"version", no_argument, 0, 'V'}, 131 .config = negate_config_init(),
130 {"timeout", required_argument, 0, 't'},
131 {"timeout-result", required_argument, 0, 'T'},
132 {"ok", required_argument, 0, 'o'},
133 {"warning", required_argument, 0, 'w'},
134 {"critical", required_argument, 0, 'c'},
135 {"unknown", required_argument, 0, 'u'},
136 {"substitute", no_argument, 0, 's'},
137 {0, 0, 0, 0}
138 }; 132 };
133 bool permute = true;
134 while (true) {
135 int option = 0;
136 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
139 137
140 while (1) { 138 if (option_char == -1 || option_char == EOF) {
141 c = getopt_long (argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
142
143 if (c == -1 || c == EOF)
144 break; 139 break;
140 }
145 141
146 switch (c) { 142 switch (option_char) {
147 case '?': /* help */ 143 case '?': /* help */
148 usage5 (); 144 usage5();
149 break; 145 break;
150 case 'h': /* help */ 146 case 'h': /* help */
151 print_help (); 147 print_help();
152 exit (EXIT_SUCCESS); 148 exit(STATE_UNKNOWN);
153 break; 149 break;
154 case 'V': /* version */ 150 case 'V': /* version */
155 print_revision (progname, NP_VERSION); 151 print_revision(progname, NP_VERSION);
156 exit (EXIT_SUCCESS); 152 exit(STATE_UNKNOWN);
157 case 't': /* timeout period */ 153 case 't': /* timeout period */
158 if (!is_integer (optarg)) 154 if (!is_integer(optarg)) {
159 usage2 (_("Timeout interval must be a positive integer"), optarg); 155 usage2(_("Timeout interval must be a positive integer"), optarg);
160 else 156 } else {
161 timeout_interval = atoi (optarg); 157 timeout_interval = atoi(optarg);
158 }
162 break; 159 break;
163 case 'T': /* Result to return on timeouts */ 160 case 'T': /* Result to return on timeouts */
164 if ((timeout_state = mp_translate_state(optarg)) == ERROR) 161 if ((timeout_state = mp_translate_state(optarg)) == ERROR) {
165 usage4 (_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 162 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
163 }
166 break; 164 break;
167 case 'o': /* replacement for OK */ 165 case 'o': /* replacement for OK */
168 if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR) 166 if ((result.config.state[STATE_OK] = mp_translate_state(optarg)) == ERROR) {
169 usage4 (_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 167 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
168 }
170 permute = false; 169 permute = false;
171 break; 170 break;
172 171
173 case 'w': /* replacement for WARNING */ 172 case 'w': /* replacement for WARNING */
174 if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) 173 if ((result.config.state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) {
175 usage4 (_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 174 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
175 }
176 permute = false; 176 permute = false;
177 break; 177 break;
178 case 'c': /* replacement for CRITICAL */ 178 case 'c': /* replacement for CRITICAL */
179 if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) 179 if ((result.config.state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) {
180 usage4 (_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 180 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
181 }
181 permute = false; 182 permute = false;
182 break; 183 break;
183 case 'u': /* replacement for UNKNOWN */ 184 case 'u': /* replacement for UNKNOWN */
184 if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) 185 if ((result.config.state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) {
185 usage4 (_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 186 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
187 }
186 permute = false; 188 permute = false;
187 break; 189 break;
188 case 's': /* Substitute status text */ 190 case 's': /* Substitute status text */
189 subst_text = true; 191 result.config.subst_text = true;
190 break; 192 break;
191 } 193 }
192 } 194 }
193 195
194 validate_arguments (&argv[optind]);
195
196 if (permute) { /* No [owcu] switch specified, default to this */ 196 if (permute) { /* No [owcu] switch specified, default to this */
197 state[STATE_OK] = STATE_CRITICAL; 197 result.config.state[STATE_OK] = STATE_CRITICAL;
198 state[STATE_CRITICAL] = STATE_OK; 198 result.config.state[STATE_CRITICAL] = STATE_OK;
199 } 199 }
200 200
201 return (const char **) &argv[optind]; 201 result.config.command_line = &argv[optind];
202
203 return validate_arguments(result);
202} 204}
203 205
206negate_config_wrapper validate_arguments(negate_config_wrapper config_wrapper) {
207 if (config_wrapper.config.command_line[0] == NULL) {
208 usage4(_("Could not parse arguments"));
209 }
204 210
205void 211 if (strncmp(config_wrapper.config.command_line[0], "/", 1) != 0 && strncmp(config_wrapper.config.command_line[0], "./", 2) != 0) {
206validate_arguments (char **command_line) 212 usage4(_("Require path to command"));
207{ 213 }
208 if (command_line[0] == NULL)
209 usage4 (_("Could not parse arguments"));
210 214
211 if (strncmp(command_line[0],"/",1) != 0 && strncmp(command_line[0],"./",2) != 0) 215 return config_wrapper;
212 usage4 (_("Require path to command"));
213} 216}
214 217
218void print_help(void) {
219 print_revision(progname, NP_VERSION);
215 220
216void 221 printf(COPYRIGHT, copyright, email);
217print_help (void)
218{
219 print_revision (progname, NP_VERSION);
220 222
221 printf (COPYRIGHT, copyright, email); 223 printf("%s\n", _("Negates only the return code of a plugin (returns OK for CRITICAL and vice-versa) by default."));
224 printf("%s\n", _("Additional switches can be used to control:\n"));
225 printf("\t - which state becomes what\n");
226 printf("\t - changing the plugin output text to match the return code");
222 227
223 printf ("%s\n", _("Negates only the return code of a plugin (returns OK for CRITICAL and vice-versa) by default.")); 228 printf("\n\n");
224 printf ("%s\n", _("Additional switches can be used to control:\n"));
225 printf ("\t - which state becomes what\n");
226 printf ("\t - changing the plugin output text to match the return code");
227 229
228 printf ("\n\n"); 230 print_usage();
229 231
230 print_usage (); 232 printf(UT_HELP_VRSN);
231 233
232 printf (UT_HELP_VRSN); 234 printf(UT_PLUG_TIMEOUT, timeout_interval);
233 235 printf(" %s\n", _("Keep timeout longer than the plugin timeout to retain CRITICAL status."));
234 printf (UT_PLUG_TIMEOUT, timeout_interval); 236 printf(" -T, --timeout-result=STATUS\n");
235 printf (" %s\n", _("Keep timeout longer than the plugin timeout to retain CRITICAL status.")); 237 printf(" %s\n", _("Custom result on Negate timeouts; see below for STATUS definition\n"));
236 printf (" -T, --timeout-result=STATUS\n");
237 printf (" %s\n", _("Custom result on Negate timeouts; see below for STATUS definition\n"));
238 238
239 printf(" -o, --ok=STATUS\n"); 239 printf(" -o, --ok=STATUS\n");
240 printf(" -w, --warning=STATUS\n"); 240 printf(" -w, --warning=STATUS\n");
@@ -246,31 +246,27 @@ print_help (void)
246 printf(" -s, --substitute\n"); 246 printf(" -s, --substitute\n");
247 printf(_(" Substitute output text as well. Will only substitute text in CAPITALS\n")); 247 printf(_(" Substitute output text as well. Will only substitute text in CAPITALS\n"));
248 248
249 printf ("\n"); 249 printf("\n");
250 printf ("%s\n", _("Examples:")); 250 printf("%s\n", _("Examples:"));
251 printf (" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host"); 251 printf(" %s\n", "negate /usr/local/nagios/libexec/check_ping -H host");
252 printf (" %s\n", _("Run check_ping and invert result. Must use full path to plugin")); 252 printf(" %s\n", _("Run check_ping and invert result. Must use full path to plugin"));
253 printf (" %s\n", "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'"); 253 printf(" %s\n", "negate -w OK -c UNKNOWN /usr/local/nagios/libexec/check_procs -a 'vi negate.c'");
254 printf (" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL")); 254 printf(" %s\n", _("This will return OK instead of WARNING and UNKNOWN instead of CRITICAL"));
255 printf ("\n"); 255 printf("\n");
256 printf ("%s\n", _("Notes:")); 256 printf("%s\n", _("Notes:"));
257 printf (" %s\n", _("This plugin is a wrapper to take the output of another plugin and invert it.")); 257 printf(" %s\n", _("This plugin is a wrapper to take the output of another plugin and invert it."));
258 printf (" %s\n", _("The full path of the plugin must be provided.")); 258 printf(" %s\n", _("The full path of the plugin must be provided."));
259 printf (" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL.")); 259 printf(" %s\n", _("If the wrapped plugin returns OK, the wrapper will return CRITICAL."));
260 printf (" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK.")); 260 printf(" %s\n", _("If the wrapped plugin returns CRITICAL, the wrapper will return OK."));
261 printf (" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged.")); 261 printf(" %s\n", _("Otherwise, the output state of the wrapped plugin is unchanged."));
262 printf ("\n"); 262 printf("\n");
263 printf (" %s\n", _("Using timeout-result, it is possible to override the timeout behaviour or a")); 263 printf(" %s\n", _("Using timeout-result, it is possible to override the timeout behaviour or a"));
264 printf (" %s\n", _("plugin by setting the negate timeout a bit lower.")); 264 printf(" %s\n", _("plugin by setting the negate timeout a bit lower."));
265 265
266 printf (UT_SUPPORT); 266 printf(UT_SUPPORT);
267} 267}
268 268
269 269void print_usage(void) {
270 270 printf("%s\n", _("Usage:"));
271void 271 printf("%s [-t timeout] [-Towcu STATE] [-s] <definition of wrapped plugin>\n", progname);
272print_usage (void)
273{
274 printf ("%s\n", _("Usage:"));
275 printf ("%s [-t timeout] [-Towcu STATE] [-s] <definition of wrapped plugin>\n", progname);
276} 272}
diff --git a/plugins/negate.d/config.h b/plugins/negate.d/config.h
new file mode 100644
index 00000000..0cf30cd4
--- /dev/null
+++ b/plugins/negate.d/config.h
@@ -0,0 +1,24 @@
1#pragma once
2
3#include "states.h"
4
5typedef struct {
6 mp_state_enum state[4];
7 bool subst_text;
8 char **command_line;
9} negate_config;
10
11negate_config negate_config_init() {
12 negate_config tmp = {
13 .state =
14 {
15 STATE_OK,
16 STATE_WARNING,
17 STATE_CRITICAL,
18 STATE_UNKNOWN,
19 },
20 .subst_text = false,
21 .command_line = NULL,
22 };
23 return tmp;
24}
diff --git a/plugins/netutils.c b/plugins/netutils.c
index c6af248e..e2916c65 100644
--- a/plugins/netutils.c
+++ b/plugins/netutils.c
@@ -1,33 +1,35 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins network utilities 3 * Monitoring Plugins network utilities
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999 Ethan Galstad (nagios@nagios.org) 6 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
7* Copyright (c) 2003-2008 Monitoring Plugins Development Team 7 * Copyright (c) 2003-2024 Monitoring Plugins Development Team
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains commons functions used in many of the plugins. 11 * This file contains commons functions used in many of the plugins.
12* 12 *
13* 13 *
14* This program is free software: you can redistribute it and/or modify 14 * This program is free software: you can redistribute it and/or modify
15* it under the terms of the GNU General Public License as published by 15 * it under the terms of the GNU General Public License as published by
16* the Free Software Foundation, either version 3 of the License, or 16 * the Free Software Foundation, either version 3 of the License, or
17* (at your option) any later version. 17 * (at your option) any later version.
18* 18 *
19* This program is distributed in the hope that it will be useful, 19 * This program is distributed in the hope that it will be useful,
20* but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22* GNU General Public License for more details. 22 * GNU General Public License for more details.
23* 23 *
24* You should have received a copy of the GNU General Public License 24 * You should have received a copy of the GNU General Public License
25* along with this program. If not, see <http://www.gnu.org/licenses/>. 25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26* 26 *
27* 27 *
28*****************************************************************************/ 28 *****************************************************************************/
29 29
30#include "common.h" 30#include "common.h"
31#include "output.h"
32#include "states.h"
31#include "netutils.h" 33#include "netutils.h"
32 34
33unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT; 35unsigned int socket_timeout = DEFAULT_SOCKET_TIMEOUT;
@@ -42,25 +44,26 @@ int address_family = AF_INET;
42#endif 44#endif
43 45
44/* handles socket timeouts */ 46/* handles socket timeouts */
45void 47void socket_timeout_alarm_handler(int sig) {
46socket_timeout_alarm_handler (int sig) 48 mp_subcheck timeout_sc = mp_subcheck_init();
47{ 49 timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state);
48 if (sig == SIGALRM) 50
49 printf (_("%s - Socket timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 51 if (sig == SIGALRM) {
50 else 52 xasprintf(&timeout_sc.output, _("Socket timeout after %d seconds\n"), socket_timeout);
51 printf (_("%s - Abnormal timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 53 } else {
52 54 xasprintf(&timeout_sc.output, _("Abnormal timeout after %d seconds\n"), socket_timeout);
53 exit (socket_timeout_state); 55 }
54}
55 56
57 mp_check overall = mp_check_init();
58 mp_add_subcheck_to_check(&overall, timeout_sc);
59
60 mp_exit(overall);
61}
56 62
57/* connects to a host on a specified tcp port, sends a string, and gets a 63/* connects to a host on a specified tcp port, sends a string, and gets a
58 response. loops on select-recv until timeout or eof to get all of a 64 response. loops on select-recv until timeout or eof to get all of a
59 multi-packet answer */ 65 multi-packet answer */
60int 66int process_tcp_request2(const char *server_address, int server_port, const char *send_buffer, char *recv_buffer, int recv_size) {
61process_tcp_request2 (const char *server_address, int server_port,
62 const char *send_buffer, char *recv_buffer, int recv_size)
63{
64 67
65 int result; 68 int result;
66 int send_result; 69 int send_result;
@@ -70,13 +73,14 @@ process_tcp_request2 (const char *server_address, int server_port,
70 fd_set readfds; 73 fd_set readfds;
71 int recv_length = 0; 74 int recv_length = 0;
72 75
73 result = np_net_connect (server_address, server_port, &sd, IPPROTO_TCP); 76 result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP);
74 if (result != STATE_OK) 77 if (result != STATE_OK) {
75 return STATE_CRITICAL; 78 return STATE_CRITICAL;
79 }
76 80
77 send_result = send (sd, send_buffer, strlen (send_buffer), 0); 81 send_result = send(sd, send_buffer, strlen(send_buffer), 0);
78 if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) { 82 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
79 printf ("%s\n", _("Send failed")); 83 // printf("%s\n", _("Send failed"));
80 result = STATE_WARNING; 84 result = STATE_WARNING;
81 } 85 }
82 86
@@ -85,38 +89,32 @@ process_tcp_request2 (const char *server_address, int server_port,
85 minus one for data from the host */ 89 minus one for data from the host */
86 tv.tv_sec = socket_timeout - 1; 90 tv.tv_sec = socket_timeout - 1;
87 tv.tv_usec = 0; 91 tv.tv_usec = 0;
88 FD_ZERO (&readfds); 92 FD_ZERO(&readfds);
89 FD_SET (sd, &readfds); 93 FD_SET(sd, &readfds);
90 select (sd + 1, &readfds, NULL, NULL, &tv); 94 select(sd + 1, &readfds, NULL, NULL, &tv);
91 95
92 /* make sure some data has arrived */ 96 /* make sure some data has arrived */
93 if (!FD_ISSET (sd, &readfds)) { /* it hasn't */ 97 if (!FD_ISSET(sd, &readfds)) { /* it hasn't */
94 if (!recv_length) { 98 if (!recv_length) {
95 strcpy (recv_buffer, ""); 99 strcpy(recv_buffer, "");
96 printf ("%s\n", _("No data was received from host!")); 100 // printf("%s\n", _("No data was received from host!"));
97 result = STATE_WARNING; 101 result = STATE_WARNING;
98 } 102 } else { /* this one failed, but previous ones worked */
99 else { /* this one failed, but previous ones worked */
100 recv_buffer[recv_length] = 0; 103 recv_buffer[recv_length] = 0;
101 } 104 }
102 break; 105 break;
103 } 106 } else { /* it has */
104 else { /* it has */ 107 recv_result = recv(sd, recv_buffer + recv_length, (size_t)recv_size - recv_length - 1, 0);
105 recv_result =
106 recv (sd, recv_buffer + recv_length,
107 (size_t)recv_size - recv_length - 1, 0);
108 if (recv_result == -1) { 108 if (recv_result == -1) {
109 /* recv failed, bail out */ 109 /* recv failed, bail out */
110 strcpy (recv_buffer + recv_length, ""); 110 strcpy(recv_buffer + recv_length, "");
111 result = STATE_WARNING; 111 result = STATE_WARNING;
112 break; 112 break;
113 } 113 } else if (recv_result == 0) {
114 else if (recv_result == 0) {
115 /* end of file ? */ 114 /* end of file ? */
116 recv_buffer[recv_length] = 0; 115 recv_buffer[recv_length] = 0;
117 break; 116 break;
118 } 117 } else { /* we got data! */
119 else { /* we got data! */
120 recv_length += recv_result; 118 recv_length += recv_result;
121 if (recv_length >= recv_size - 1) { 119 if (recv_length >= recv_size - 1) {
122 /* buffer full, we're done */ 120 /* buffer full, we're done */
@@ -129,42 +127,36 @@ process_tcp_request2 (const char *server_address, int server_port,
129 } 127 }
130 /* end while(1) */ 128 /* end while(1) */
131 129
132 close (sd); 130 close(sd);
133 return result; 131 return result;
134} 132}
135 133
136
137/* connects to a host on a specified port, sends a string, and gets a 134/* connects to a host on a specified port, sends a string, and gets a
138 response */ 135 response */
139int 136int process_request(const char *server_address, int server_port, int proto, const char *send_buffer, char *recv_buffer, int recv_size) {
140process_request (const char *server_address, int server_port, int proto,
141 const char *send_buffer, char *recv_buffer, int recv_size)
142{
143 int result; 137 int result;
144 int sd; 138 int sd;
145 139
146 result = STATE_OK; 140 result = STATE_OK;
147 141
148 result = np_net_connect (server_address, server_port, &sd, proto); 142 result = np_net_connect(server_address, server_port, &sd, proto);
149 if (result != STATE_OK) 143 if (result != STATE_OK) {
150 return STATE_CRITICAL; 144 return STATE_CRITICAL;
145 }
151 146
152 result = send_request (sd, proto, send_buffer, recv_buffer, recv_size); 147 result = send_request(sd, proto, send_buffer, recv_buffer, recv_size);
153 148
154 close (sd); 149 close(sd);
155 150
156 return result; 151 return result;
157} 152}
158 153
159
160/* opens a tcp or udp connection to a remote host or local socket */ 154/* opens a tcp or udp connection to a remote host or local socket */
161int 155int np_net_connect(const char *host_name, int port, int *sd, int proto) {
162np_net_connect (const char *host_name, int port, int *sd, int proto) 156 /* send back STATE_UNKOWN if there's an error
163{ 157 send back STATE_OK if we connect
164 /* send back STATE_UNKOWN if there's an error 158 send back STATE_CRITICAL if we can't connect.
165 send back STATE_OK if we connect 159 Let upstream figure out what to send to the user. */
166 send back STATE_CRITICAL if we can't connect.
167 Let upstream figure out what to send to the user. */
168 struct addrinfo hints; 160 struct addrinfo hints;
169 struct addrinfo *r, *res; 161 struct addrinfo *r, *res;
170 struct sockaddr_un su; 162 struct sockaddr_un su;
@@ -176,43 +168,44 @@ np_net_connect (const char *host_name, int port, int *sd, int proto)
176 socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM; 168 socktype = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
177 169
178 /* as long as it doesn't start with a '/', it's assumed a host or ip */ 170 /* as long as it doesn't start with a '/', it's assumed a host or ip */
179 if (!is_socket){ 171 if (!is_socket) {
180 memset (&hints, 0, sizeof (hints)); 172 memset(&hints, 0, sizeof(hints));
181 hints.ai_family = address_family; 173 hints.ai_family = address_family;
182 hints.ai_protocol = proto; 174 hints.ai_protocol = proto;
183 hints.ai_socktype = socktype; 175 hints.ai_socktype = socktype;
184 176
185 len = strlen (host_name); 177 len = strlen(host_name);
186 /* check for an [IPv6] address (and strip the brackets) */ 178 /* check for an [IPv6] address (and strip the brackets) */
187 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') { 179 if (len >= 2 && host_name[0] == '[' && host_name[len - 1] == ']') {
188 host_name++; 180 host_name++;
189 len -= 2; 181 len -= 2;
190 } 182 }
191 if (len >= sizeof(host)) 183 if (len >= sizeof(host)) {
192 return STATE_UNKNOWN; 184 return STATE_UNKNOWN;
193 memcpy (host, host_name, len); 185 }
186 memcpy(host, host_name, len);
194 host[len] = '\0'; 187 host[len] = '\0';
195 snprintf (port_str, sizeof (port_str), "%d", port); 188 snprintf(port_str, sizeof(port_str), "%d", port);
196 result = getaddrinfo (host, port_str, &hints, &res); 189 result = getaddrinfo(host, port_str, &hints, &res);
197 190
198 if (result != 0) { 191 if (result != 0) {
199 printf ("%s\n", gai_strerror (result)); 192 // printf("%s\n", gai_strerror(result));
200 return STATE_UNKNOWN; 193 return STATE_UNKNOWN;
201 } 194 }
202 195
203 r = res; 196 r = res;
204 while (r) { 197 while (r) {
205 /* attempt to create a socket */ 198 /* attempt to create a socket */
206 *sd = socket (r->ai_family, socktype, r->ai_protocol); 199 *sd = socket(r->ai_family, socktype, r->ai_protocol);
207 200
208 if (*sd < 0) { 201 if (*sd < 0) {
209 printf ("%s\n", _("Socket creation failed")); 202 // printf("%s\n", _("Socket creation failed"));
210 freeaddrinfo (r); 203 freeaddrinfo(r);
211 return STATE_UNKNOWN; 204 return STATE_UNKNOWN;
212 } 205 }
213 206
214 /* attempt to open a connection */ 207 /* attempt to open a connection */
215 result = connect (*sd, r->ai_addr, r->ai_addrlen); 208 result = connect(*sd, r->ai_addr, r->ai_addrlen);
216 209
217 if (result == 0) { 210 if (result == 0) {
218 was_refused = false; 211 was_refused = false;
@@ -227,69 +220,67 @@ np_net_connect (const char *host_name, int port, int *sd, int proto)
227 } 220 }
228 } 221 }
229 222
230 close (*sd); 223 close(*sd);
231 r = r->ai_next; 224 r = r->ai_next;
232 } 225 }
233 freeaddrinfo (res); 226 freeaddrinfo(res);
234 } 227 }
235 /* else the hostname is interpreted as a path to a unix socket */ 228 /* else the hostname is interpreted as a path to a unix socket */
236 else { 229 else {
237 if(strlen(host_name) >= UNIX_PATH_MAX){ 230 if (strlen(host_name) >= UNIX_PATH_MAX) {
238 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket")); 231 die(STATE_UNKNOWN, _("Supplied path too long unix domain socket"));
239 } 232 }
240 memset(&su, 0, sizeof(su)); 233 memset(&su, 0, sizeof(su));
241 su.sun_family = AF_UNIX; 234 su.sun_family = AF_UNIX;
242 strncpy(su.sun_path, host_name, UNIX_PATH_MAX); 235 strncpy(su.sun_path, host_name, UNIX_PATH_MAX);
243 *sd = socket(PF_UNIX, SOCK_STREAM, 0); 236 *sd = socket(PF_UNIX, SOCK_STREAM, 0);
244 if(*sd < 0){ 237 if (*sd < 0) {
245 die(STATE_UNKNOWN, _("Socket creation failed")); 238 die(STATE_UNKNOWN, _("Socket creation failed"));
246 } 239 }
247 result = connect(*sd, (struct sockaddr *)&su, sizeof(su)); 240 result = connect(*sd, (struct sockaddr *)&su, sizeof(su));
248 if (result < 0 && errno == ECONNREFUSED) 241 if (result < 0 && errno == ECONNREFUSED) {
249 was_refused = true; 242 was_refused = true;
243 }
250 } 244 }
251 245
252 if (result == 0) 246 if (result == 0) {
253 return STATE_OK; 247 return STATE_OK;
254 else if (was_refused) { 248 } else if (was_refused) {
255 switch (econn_refuse_state) { /* a user-defined expected outcome */ 249 switch (econn_refuse_state) { /* a user-defined expected outcome */
256 case STATE_OK: 250 case STATE_OK:
257 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */ 251 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */
258 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */ 252 case STATE_CRITICAL: /* user did not set econn_refuse_state, or wanted critical */
259 if (is_socket) 253 if (is_socket) {
260 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 254 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
261 else 255 } else {
262 printf("connect to address %s and port %d: %s\n", 256 // printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno));
263 host_name, port, strerror(errno)); 257 }
264 return STATE_CRITICAL; 258 return STATE_CRITICAL;
265 break; 259 break;
266 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */ 260 default: /* it's a logic error if we do not end up in STATE_(OK|WARNING|CRITICAL) */
267 return STATE_UNKNOWN; 261 return STATE_UNKNOWN;
268 break; 262 break;
269 } 263 }
270 } 264 } else {
271 else { 265 if (is_socket) {
272 if (is_socket) 266 // printf("connect to file socket %s: %s\n", host_name, strerror(errno));
273 printf("connect to file socket %s: %s\n", host_name, strerror(errno)); 267 } else {
274 else 268 // printf("connect to address %s and port %d: %s\n", host_name, port, strerror(errno));
275 printf("connect to address %s and port %d: %s\n", 269 }
276 host_name, port, strerror(errno));
277 return STATE_CRITICAL; 270 return STATE_CRITICAL;
278 } 271 }
279} 272}
280 273
281int 274int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size) {
282send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int recv_size)
283{
284 int result = STATE_OK; 275 int result = STATE_OK;
285 int send_result; 276 int send_result;
286 int recv_result; 277 int recv_result;
287 struct timeval tv; 278 struct timeval tv;
288 fd_set readfds; 279 fd_set readfds;
289 280
290 send_result = send (sd, send_buffer, strlen (send_buffer), 0); 281 send_result = send(sd, send_buffer, strlen(send_buffer), 0);
291 if (send_result<0 || (size_t)send_result!=strlen(send_buffer)) { 282 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
292 printf ("%s\n", _("Send failed")); 283 // printf("%s\n", _("Send failed"));
293 result = STATE_WARNING; 284 result = STATE_WARNING;
294 } 285 }
295 286
@@ -297,27 +288,28 @@ send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int
297 for data from the host */ 288 for data from the host */
298 tv.tv_sec = socket_timeout - 1; 289 tv.tv_sec = socket_timeout - 1;
299 tv.tv_usec = 0; 290 tv.tv_usec = 0;
300 FD_ZERO (&readfds); 291 FD_ZERO(&readfds);
301 FD_SET (sd, &readfds); 292 FD_SET(sd, &readfds);
302 select (sd + 1, &readfds, NULL, NULL, &tv); 293 select(sd + 1, &readfds, NULL, NULL, &tv);
303 294
304 /* make sure some data has arrived */ 295 /* make sure some data has arrived */
305 if (!FD_ISSET (sd, &readfds)) { 296 if (!FD_ISSET(sd, &readfds)) {
306 strcpy (recv_buffer, ""); 297 strcpy(recv_buffer, "");
307 printf ("%s\n", _("No data was received from host!")); 298 // printf("%s\n", _("No data was received from host!"));
308 result = STATE_WARNING; 299 result = STATE_WARNING;
309 } 300 }
310 301
311 else { 302 else {
312 recv_result = recv (sd, recv_buffer, (size_t)recv_size - 1, 0); 303 recv_result = recv(sd, recv_buffer, (size_t)recv_size - 1, 0);
313 if (recv_result == -1) { 304 if (recv_result == -1) {
314 strcpy (recv_buffer, ""); 305 strcpy(recv_buffer, "");
315 if (proto != IPPROTO_TCP) 306 if (proto != IPPROTO_TCP) {
316 printf ("%s\n", _("Receive failed")); 307 // printf("%s\n", _("Receive failed"));
308 }
317 result = STATE_WARNING; 309 result = STATE_WARNING;
318 } 310 } else {
319 else
320 recv_buffer[recv_result] = 0; 311 recv_buffer[recv_result] = 0;
312 }
321 313
322 /* die returned string */ 314 /* die returned string */
323 recv_buffer[recv_size - 1] = 0; 315 recv_buffer[recv_size - 1] = 0;
@@ -325,51 +317,52 @@ send_request (int sd, int proto, const char *send_buffer, char *recv_buffer, int
325 return result; 317 return result;
326} 318}
327 319
328 320bool is_host(const char *address) {
329bool is_host (const char *address) { 321 if (is_addr(address) || is_hostname(address)) {
330 if (is_addr (address) || is_hostname (address))
331 return (true); 322 return (true);
323 }
332 324
333 return (false); 325 return (false);
334} 326}
335 327
336void 328void host_or_die(const char *str) {
337host_or_die(const char *str) 329 if (!str || (!is_addr(str) && !is_hostname(str))) {
338{
339 if(!str || (!is_addr(str) && !is_hostname(str)))
340 usage_va(_("Invalid hostname/address - %s"), str); 330 usage_va(_("Invalid hostname/address - %s"), str);
331 }
341} 332}
342 333
343bool is_addr (const char *address) { 334bool is_addr(const char *address) {
344#ifdef USE_IPV6 335#ifdef USE_IPV6
345 if (address_family == AF_INET && is_inet_addr (address)) 336 if (address_family == AF_INET && is_inet_addr(address)) {
346 return true; 337 return true;
347 else if (address_family == AF_INET6 && is_inet6_addr (address)) 338 } else if (address_family == AF_INET6 && is_inet6_addr(address)) {
348 return true; 339 return true;
340 }
349#else 341#else
350 if (is_inet_addr (address)) 342 if (is_inet_addr(address)) {
351 return (true); 343 return (true);
344 }
352#endif 345#endif
353 346
354 return (false); 347 return (false);
355} 348}
356 349
357int 350int dns_lookup(const char *in, struct sockaddr_storage *ss, int family) {
358dns_lookup (const char *in, struct sockaddr_storage *ss, int family)
359{
360 struct addrinfo hints; 351 struct addrinfo hints;
361 struct addrinfo *res; 352 struct addrinfo *res;
362 int retval; 353 int retval;
363 354
364 memset (&hints, 0, sizeof(struct addrinfo)); 355 memset(&hints, 0, sizeof(struct addrinfo));
365 hints.ai_family = family; 356 hints.ai_family = family;
366 357
367 retval = getaddrinfo (in, NULL, &hints, &res); 358 retval = getaddrinfo(in, NULL, &hints, &res);
368 if (retval != 0) 359 if (retval != 0) {
369 return false; 360 return false;
361 }
370 362
371 if (ss != NULL) 363 if (ss != NULL) {
372 memcpy (ss, res->ai_addr, res->ai_addrlen); 364 memcpy(ss, res->ai_addr, res->ai_addrlen);
373 freeaddrinfo (res); 365 }
366 freeaddrinfo(res);
374 return true; 367 return true;
375} 368}
diff --git a/plugins/picohttpparser/picohttpparser.c b/plugins/picohttpparser/picohttpparser.c
index d0bfac62..2ae92d66 100644
--- a/plugins/picohttpparser/picohttpparser.c
+++ b/plugins/picohttpparser/picohttpparser.c
@@ -28,623 +28,610 @@
28#include <stddef.h> 28#include <stddef.h>
29#include <string.h> 29#include <string.h>
30#ifdef __SSE4_2__ 30#ifdef __SSE4_2__
31#ifdef _MSC_VER 31# ifdef _MSC_VER
32#include <nmmintrin.h> 32# include <nmmintrin.h>
33#else 33# else
34#include <x86intrin.h> 34# include <x86intrin.h>
35#endif 35# endif
36#endif 36#endif
37#include "picohttpparser.h" 37#include "picohttpparser.h"
38 38
39#if __GNUC__ >= 3 39#if __GNUC__ >= 3
40#define likely(x) __builtin_expect(!!(x), 1) 40# define likely(x) __builtin_expect(!!(x), 1)
41#define unlikely(x) __builtin_expect(!!(x), 0) 41# define unlikely(x) __builtin_expect(!!(x), 0)
42#else 42#else
43#define likely(x) (x) 43# define likely(x) (x)
44#define unlikely(x) (x) 44# define unlikely(x) (x)
45#endif 45#endif
46 46
47#ifdef _MSC_VER 47#ifdef _MSC_VER
48#define ALIGNED(n) _declspec(align(n)) 48# define ALIGNED(n) _declspec(align(n))
49#else 49#else
50#define ALIGNED(n) __attribute__((aligned(n))) 50# define ALIGNED(n) __attribute__((aligned(n)))
51#endif 51#endif
52 52
53#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u) 53#define IS_PRINTABLE_ASCII(c) ((unsigned char)(c)-040u < 0137u)
54 54
55#define CHECK_EOF() \ 55#define CHECK_EOF() \
56 if (buf == buf_end) { \ 56 if (buf == buf_end) { \
57 *ret = -2; \ 57 *ret = -2; \
58 return NULL; \ 58 return NULL; \
59 } 59 }
60 60
61#define EXPECT_CHAR_NO_CHECK(ch) \ 61#define EXPECT_CHAR_NO_CHECK(ch) \
62 if (*buf++ != ch) { \ 62 if (*buf++ != ch) { \
63 *ret = -1; \ 63 *ret = -1; \
64 return NULL; \ 64 return NULL; \
65 } 65 }
66 66
67#define EXPECT_CHAR(ch) \ 67#define EXPECT_CHAR(ch) \
68 CHECK_EOF(); \ 68 CHECK_EOF(); \
69 EXPECT_CHAR_NO_CHECK(ch); 69 EXPECT_CHAR_NO_CHECK(ch);
70 70
71#define ADVANCE_TOKEN(tok, toklen) \ 71#define ADVANCE_TOKEN(tok, toklen) \
72 do { \ 72 do { \
73 const char *tok_start = buf; \ 73 const char *tok_start = buf; \
74 static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \ 74 static const char ALIGNED(16) ranges2[16] = "\000\040\177\177"; \
75 int found2; \ 75 int found2; \
76 buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \ 76 buf = findchar_fast(buf, buf_end, ranges2, 4, &found2); \
77 if (!found2) { \ 77 if (!found2) { \
78 CHECK_EOF(); \ 78 CHECK_EOF(); \
79 } \ 79 } \
80 while (1) { \ 80 while (1) { \
81 if (*buf == ' ') { \ 81 if (*buf == ' ') { \
82 break; \ 82 break; \
83 } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \ 83 } else if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \
84 if ((unsigned char)*buf < '\040' || *buf == '\177') { \ 84 if ((unsigned char)*buf < '\040' || *buf == '\177') { \
85 *ret = -1; \ 85 *ret = -1; \
86 return NULL; \ 86 return NULL; \
87 } \ 87 } \
88 } \ 88 } \
89 ++buf; \ 89 ++buf; \
90 CHECK_EOF(); \ 90 CHECK_EOF(); \
91 } \ 91 } \
92 tok = tok_start; \ 92 tok = tok_start; \
93 toklen = buf - tok_start; \ 93 toklen = buf - tok_start; \
94 } while (0) 94 } while (0)
95 95
96static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 96static const char *token_char_map = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
97 "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0" 97 "\0\1\0\1\1\1\1\1\0\0\1\1\0\1\1\0\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0"
98 "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1" 98 "\0\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\1\1"
99 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0" 99 "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\1\0\1\0"
100 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 100 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
101 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 101 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
102 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" 102 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
103 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 103 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
104 104
105static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) 105static const char *findchar_fast(const char *buf, const char *buf_end, const char *ranges, size_t ranges_size, int *found) {
106{ 106 *found = 0;
107 *found = 0;
108#if __SSE4_2__ 107#if __SSE4_2__
109 if (likely(buf_end - buf >= 16)) { 108 if (likely(buf_end - buf >= 16)) {
110 __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges); 109 __m128i ranges16 = _mm_loadu_si128((const __m128i *)ranges);
111 110
112 size_t left = (buf_end - buf) & ~15; 111 size_t left = (buf_end - buf) & ~15;
113 do { 112 do {
114 __m128i b16 = _mm_loadu_si128((const __m128i *)buf); 113 __m128i b16 = _mm_loadu_si128((const __m128i *)buf);
115 int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS); 114 int r = _mm_cmpestri(ranges16, ranges_size, b16, 16, _SIDD_LEAST_SIGNIFICANT | _SIDD_CMP_RANGES | _SIDD_UBYTE_OPS);
116 if (unlikely(r != 16)) { 115 if (unlikely(r != 16)) {
117 buf += r; 116 buf += r;
118 *found = 1; 117 *found = 1;
119 break; 118 break;
120 } 119 }
121 buf += 16; 120 buf += 16;
122 left -= 16; 121 left -= 16;
123 } while (likely(left != 0)); 122 } while (likely(left != 0));
124 } 123 }
125#else 124#else
126 /* suppress unused parameter warning */ 125 /* suppress unused parameter warning */
127 (void)buf_end; 126 (void)buf_end;
128 (void)ranges; 127 (void)ranges;
129 (void)ranges_size; 128 (void)ranges_size;
130#endif 129#endif
131 return buf; 130 return buf;
132} 131}
133 132
134static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) 133static const char *get_token_to_eol(const char *buf, const char *buf_end, const char **token, size_t *token_len, int *ret) {
135{ 134 const char *token_start = buf;
136 const char *token_start = buf;
137 135
138#ifdef __SSE4_2__ 136#ifdef __SSE4_2__
139 static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */ 137 static const char ALIGNED(16) ranges1[16] = "\0\010" /* allow HT */
140 "\012\037" /* allow SP and up to but not including DEL */ 138 "\012\037" /* allow SP and up to but not including DEL */
141 "\177\177"; /* allow chars w. MSB set */ 139 "\177\177"; /* allow chars w. MSB set */
142 int found; 140 int found;
143 buf = findchar_fast(buf, buf_end, ranges1, 6, &found); 141 buf = findchar_fast(buf, buf_end, ranges1, 6, &found);
144 if (found) 142 if (found)
145 goto FOUND_CTL; 143 goto FOUND_CTL;
146#else 144#else
147 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */ 145 /* find non-printable char within the next 8 bytes, this is the hottest code; manually inlined */
148 while (likely(buf_end - buf >= 8)) { 146 while (likely(buf_end - buf >= 8)) {
149#define DOIT() \ 147# define DOIT() \
150 do { \ 148 do { \
151 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \ 149 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
152 goto NonPrintable; \ 150 goto NonPrintable; \
153 ++buf; \ 151 ++buf; \
154 } while (0) 152 } while (0)
155 DOIT(); 153 DOIT();
156 DOIT(); 154 DOIT();
157 DOIT(); 155 DOIT();
158 DOIT(); 156 DOIT();
159 DOIT(); 157 DOIT();
160 DOIT(); 158 DOIT();
161 DOIT(); 159 DOIT();
162 DOIT(); 160 DOIT();
163#undef DOIT 161# undef DOIT
164 continue; 162 continue;
165 NonPrintable: 163 NonPrintable:
166 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { 164 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) {
167 goto FOUND_CTL; 165 goto FOUND_CTL;
168 } 166 }
169 ++buf; 167 ++buf;
170 } 168 }
171#endif 169#endif
172 for (;; ++buf) { 170 for (;; ++buf) {
173 CHECK_EOF(); 171 CHECK_EOF();
174 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { 172 if (unlikely(!IS_PRINTABLE_ASCII(*buf))) {
175 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) { 173 if ((likely((unsigned char)*buf < '\040') && likely(*buf != '\011')) || unlikely(*buf == '\177')) {
176 goto FOUND_CTL; 174 goto FOUND_CTL;
177 } 175 }
178 } 176 }
179 } 177 }
180FOUND_CTL: 178FOUND_CTL:
181 if (likely(*buf == '\015')) { 179 if (likely(*buf == '\015')) {
182 ++buf; 180 ++buf;
183 EXPECT_CHAR('\012'); 181 EXPECT_CHAR('\012');
184 *token_len = buf - 2 - token_start; 182 *token_len = buf - 2 - token_start;
185 } else if (*buf == '\012') { 183 } else if (*buf == '\012') {
186 *token_len = buf - token_start; 184 *token_len = buf - token_start;
187 ++buf; 185 ++buf;
188 } else { 186 } else {
189 *ret = -1; 187 *ret = -1;
190 return NULL; 188 return NULL;
191 } 189 }
192 *token = token_start; 190 *token = token_start;
193 191
194 return buf; 192 return buf;
195} 193}
196 194
197static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) 195static const char *is_complete(const char *buf, const char *buf_end, size_t last_len, int *ret) {
198{ 196 int ret_cnt = 0;
199 int ret_cnt = 0; 197 buf = last_len < 3 ? buf : buf + last_len - 3;
200 buf = last_len < 3 ? buf : buf + last_len - 3; 198
201 199 while (1) {
202 while (1) { 200 CHECK_EOF();
203 CHECK_EOF(); 201 if (*buf == '\015') {
204 if (*buf == '\015') { 202 ++buf;
205 ++buf; 203 CHECK_EOF();
206 CHECK_EOF(); 204 EXPECT_CHAR('\012');
207 EXPECT_CHAR('\012'); 205 ++ret_cnt;
208 ++ret_cnt; 206 } else if (*buf == '\012') {
209 } else if (*buf == '\012') { 207 ++buf;
210 ++buf; 208 ++ret_cnt;
211 ++ret_cnt; 209 } else {
212 } else { 210 ++buf;
213 ++buf; 211 ret_cnt = 0;
214 ret_cnt = 0; 212 }
215 } 213 if (ret_cnt == 2) {
216 if (ret_cnt == 2) { 214 return buf;
217 return buf; 215 }
218 } 216 }
219 } 217
220 218 *ret = -2;
221 *ret = -2; 219 return NULL;
222 return NULL;
223} 220}
224 221
225#define PARSE_INT(valp_, mul_) \ 222#define PARSE_INT(valp_, mul_) \
226 if (*buf < '0' || '9' < *buf) { \ 223 if (*buf < '0' || '9' < *buf) { \
227 buf++; \ 224 buf++; \
228 *ret = -1; \ 225 *ret = -1; \
229 return NULL; \ 226 return NULL; \
230 } \ 227 } \
231 *(valp_) = (mul_) * (*buf++ - '0'); 228 *(valp_) = (mul_) * (*buf++ - '0');
232 229
233#define PARSE_INT_3(valp_) \ 230#define PARSE_INT_3(valp_) \
234 do { \ 231 do { \
235 int res_ = 0; \ 232 int res_ = 0; \
236 PARSE_INT(&res_, 100) \ 233 PARSE_INT(&res_, 100) \
237 *valp_ = res_; \ 234 *valp_ = res_; \
238 PARSE_INT(&res_, 10) \ 235 PARSE_INT(&res_, 10) \
239 *valp_ += res_; \ 236 *valp_ += res_; \
240 PARSE_INT(&res_, 1) \ 237 PARSE_INT(&res_, 1) \
241 *valp_ += res_; \ 238 *valp_ += res_; \
242 } while (0) 239 } while (0)
243 240
244/* returned pointer is always within [buf, buf_end), or null */ 241/* returned pointer is always within [buf, buf_end), or null */
245static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *ret) 242static const char *parse_http_version(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *ret) {
246{ 243 /* we want at least [HTTP/1.<two chars>] to try to parse */
247 /* we want at least [HTTP/1.<two chars>] to try to parse */ 244 if (buf_end - buf < 9) {
248 if (buf_end - buf < 9) { 245 *ret = -2;
249 *ret = -2; 246 return NULL;
250 return NULL; 247 }
251 } 248 EXPECT_CHAR_NO_CHECK('H');
252 EXPECT_CHAR_NO_CHECK('H'); 249 EXPECT_CHAR_NO_CHECK('T');
253 EXPECT_CHAR_NO_CHECK('T'); 250 EXPECT_CHAR_NO_CHECK('T');
254 EXPECT_CHAR_NO_CHECK('T'); 251 EXPECT_CHAR_NO_CHECK('P');
255 EXPECT_CHAR_NO_CHECK('P'); 252 EXPECT_CHAR_NO_CHECK('/');
256 EXPECT_CHAR_NO_CHECK('/'); 253 PARSE_INT(major_version, 1);
257 PARSE_INT(major_version, 1); 254 if (*major_version == 1) {
258 if (*major_version == 1) { 255 EXPECT_CHAR_NO_CHECK('.');
259 EXPECT_CHAR_NO_CHECK('.'); 256 PARSE_INT(minor_version, 1);
260 PARSE_INT(minor_version, 1); 257 } else {
261 } else { 258 *minor_version = 0;
262 *minor_version = 0; 259 }
263 } 260 return buf;
264 return buf;
265} 261}
266 262
267static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, 263static const char *parse_headers(const char *buf, const char *buf_end, struct phr_header *headers, size_t *num_headers, size_t max_headers,
268 size_t max_headers, int *ret) 264 int *ret) {
269{ 265 for (;; ++*num_headers) {
270 for (;; ++*num_headers) { 266 CHECK_EOF();
271 CHECK_EOF(); 267 if (*buf == '\015') {
272 if (*buf == '\015') { 268 ++buf;
273 ++buf; 269 EXPECT_CHAR('\012');
274 EXPECT_CHAR('\012'); 270 break;
275 break; 271 } else if (*buf == '\012') {
276 } else if (*buf == '\012') { 272 ++buf;
277 ++buf; 273 break;
278 break; 274 }
279 } 275 if (*num_headers == max_headers) {
280 if (*num_headers == max_headers) { 276 *ret = -1;
281 *ret = -1; 277 return NULL;
282 return NULL; 278 }
283 } 279 if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) {
284 if (!(*num_headers != 0 && (*buf == ' ' || *buf == '\t'))) { 280 /* parsing name, but do not discard SP before colon, see
285 /* parsing name, but do not discard SP before colon, see 281 * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */
286 * http://www.mozilla.org/security/announce/2006/mfsa2006-33.html */ 282 headers[*num_headers].name = buf;
287 headers[*num_headers].name = buf; 283 static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */
288 static const char ALIGNED(16) ranges1[] = "\x00 " /* control chars and up to SP */ 284 "\"\"" /* 0x22 */
289 "\"\"" /* 0x22 */ 285 "()" /* 0x28,0x29 */
290 "()" /* 0x28,0x29 */ 286 ",," /* 0x2c */
291 ",," /* 0x2c */ 287 "//" /* 0x2f */
292 "//" /* 0x2f */ 288 ":@" /* 0x3a-0x40 */
293 ":@" /* 0x3a-0x40 */ 289 "[]" /* 0x5b-0x5d */
294 "[]" /* 0x5b-0x5d */ 290 "{\377"; /* 0x7b-0xff */
295 "{\377"; /* 0x7b-0xff */ 291 int found;
296 int found; 292 buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found);
297 buf = findchar_fast(buf, buf_end, ranges1, sizeof(ranges1) - 1, &found); 293 if (!found) {
298 if (!found) { 294 CHECK_EOF();
299 CHECK_EOF(); 295 }
300 } 296 while (1) {
301 while (1) { 297 if (*buf == ':') {
302 if (*buf == ':') { 298 break;
303 break; 299 } else if (!token_char_map[(unsigned char)*buf]) {
304 } else if (!token_char_map[(unsigned char)*buf]) { 300 *ret = -1;
305 *ret = -1; 301 return NULL;
306 return NULL; 302 }
307 } 303 ++buf;
308 ++buf; 304 CHECK_EOF();
309 CHECK_EOF(); 305 }
310 } 306 if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 0) {
311 if ((headers[*num_headers].name_len = buf - headers[*num_headers].name) == 0) { 307 *ret = -1;
312 *ret = -1; 308 return NULL;
313 return NULL; 309 }
314 } 310 ++buf;
315 ++buf; 311 for (;; ++buf) {
316 for (;; ++buf) { 312 CHECK_EOF();
317 CHECK_EOF(); 313 if (!(*buf == ' ' || *buf == '\t')) {
318 if (!(*buf == ' ' || *buf == '\t')) { 314 break;
319 break; 315 }
320 } 316 }
321 } 317 } else {
322 } else { 318 headers[*num_headers].name = NULL;
323 headers[*num_headers].name = NULL; 319 headers[*num_headers].name_len = 0;
324 headers[*num_headers].name_len = 0; 320 }
325 } 321 const char *value;
326 const char *value; 322 size_t value_len;
327 size_t value_len; 323 if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) {
328 if ((buf = get_token_to_eol(buf, buf_end, &value, &value_len, ret)) == NULL) { 324 return NULL;
329 return NULL; 325 }
330 } 326 /* remove trailing SPs and HTABs */
331 /* remove trailing SPs and HTABs */ 327 const char *value_end = value + value_len;
332 const char *value_end = value + value_len; 328 for (; value_end != value; --value_end) {
333 for (; value_end != value; --value_end) { 329 const char c = *(value_end - 1);
334 const char c = *(value_end - 1); 330 if (!(c == ' ' || c == '\t')) {
335 if (!(c == ' ' || c == '\t')) { 331 break;
336 break; 332 }
337 } 333 }
338 } 334 headers[*num_headers].value = value;
339 headers[*num_headers].value = value; 335 headers[*num_headers].value_len = value_end - value;
340 headers[*num_headers].value_len = value_end - value; 336 }
341 } 337 return buf;
342 return buf;
343} 338}
344 339
345static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path, 340static const char *parse_request(const char *buf, const char *buf_end, const char **method, size_t *method_len, const char **path,
346 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, 341 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers,
347 size_t max_headers, int *ret) 342 size_t max_headers, int *ret) {
348{ 343 /* skip first empty line (some clients add CRLF after POST content) */
349 /* skip first empty line (some clients add CRLF after POST content) */ 344 CHECK_EOF();
350 CHECK_EOF(); 345 if (*buf == '\015') {
351 if (*buf == '\015') { 346 ++buf;
352 ++buf; 347 EXPECT_CHAR('\012');
353 EXPECT_CHAR('\012'); 348 } else if (*buf == '\012') {
354 } else if (*buf == '\012') { 349 ++buf;
355 ++buf; 350 }
356 } 351
357 352 /* parse request line */
358 /* parse request line */ 353 ADVANCE_TOKEN(*method, *method_len);
359 ADVANCE_TOKEN(*method, *method_len); 354 do {
360 do { 355 ++buf;
361 ++buf; 356 } while (*buf == ' ');
362 } while (*buf == ' '); 357 ADVANCE_TOKEN(*path, *path_len);
363 ADVANCE_TOKEN(*path, *path_len); 358 do {
364 do { 359 ++buf;
365 ++buf; 360 } while (*buf == ' ');
366 } while (*buf == ' '); 361 if (*method_len == 0 || *path_len == 0) {
367 if (*method_len == 0 || *path_len == 0) { 362 *ret = -1;
368 *ret = -1; 363 return NULL;
369 return NULL; 364 }
370 } 365 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
371 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) { 366 return NULL;
372 return NULL; 367 }
373 } 368 if (*buf == '\015') {
374 if (*buf == '\015') { 369 ++buf;
375 ++buf; 370 EXPECT_CHAR('\012');
376 EXPECT_CHAR('\012'); 371 } else if (*buf == '\012') {
377 } else if (*buf == '\012') { 372 ++buf;
378 ++buf; 373 } else {
379 } else { 374 *ret = -1;
380 *ret = -1; 375 return NULL;
381 return NULL; 376 }
382 } 377
383 378 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
384 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
385} 379}
386 380
387int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, 381int phr_parse_request(const char *buf_start, size_t len, const char **method, size_t *method_len, const char **path, size_t *path_len,
388 size_t *path_len, int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) 382 int *major_version, int *minor_version, struct phr_header *headers, size_t *num_headers, size_t last_len) {
389{ 383 const char *buf = buf_start, *buf_end = buf_start + len;
390 const char *buf = buf_start, *buf_end = buf_start + len; 384 size_t max_headers = *num_headers;
391 size_t max_headers = *num_headers; 385 int r;
392 int r; 386
393 387 *method = NULL;
394 *method = NULL; 388 *method_len = 0;
395 *method_len = 0; 389 *path = NULL;
396 *path = NULL; 390 *path_len = 0;
397 *path_len = 0; 391 *major_version = -1;
398 *major_version = -1; 392 *minor_version = -1;
399 *minor_version = -1; 393 *num_headers = 0;
400 *num_headers = 0; 394
401 395 /* if last_len != 0, check if the request is complete (a fast countermeasure
402 /* if last_len != 0, check if the request is complete (a fast countermeasure 396 against slowloris */
403 against slowloris */ 397 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
404 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 398 return r;
405 return r; 399 }
406 } 400
407 401 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version, minor_version, headers, num_headers,
408 if ((buf = parse_request(buf, buf_end, method, method_len, path, path_len, major_version, minor_version, headers, num_headers, max_headers, 402 max_headers, &r)) == NULL) {
409 &r)) == NULL) { 403 return r;
410 return r; 404 }
411 } 405
412 406 return (int)(buf - buf_start);
413 return (int)(buf - buf_start);
414} 407}
415 408
416static const char *parse_response(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *status, const char **msg, 409static const char *parse_response(const char *buf, const char *buf_end, int *major_version, int *minor_version, int *status,
417 size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers, int *ret) 410 const char **msg, size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t max_headers,
418{ 411 int *ret) {
419 /* parse "HTTP/1.x" */ 412 /* parse "HTTP/1.x" */
420 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) { 413 if ((buf = parse_http_version(buf, buf_end, major_version, minor_version, ret)) == NULL) {
421 return NULL; 414 return NULL;
422 } 415 }
423 /* skip space */ 416 /* skip space */
424 if (*buf != ' ') { 417 if (*buf != ' ') {
425 *ret = -1; 418 *ret = -1;
426 return NULL; 419 return NULL;
427 } 420 }
428 do { 421 do {
429 ++buf; 422 ++buf;
430 } while (*buf == ' '); 423 } while (*buf == ' ');
431 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */ 424 /* parse status code, we want at least [:digit:][:digit:][:digit:]<other char> to try to parse */
432 if (buf_end - buf < 4) { 425 if (buf_end - buf < 4) {
433 *ret = -2; 426 *ret = -2;
434 return NULL; 427 return NULL;
435 } 428 }
436 PARSE_INT_3(status); 429 PARSE_INT_3(status);
437 430
438 /* get message including preceding space */ 431 /* get message including preceding space */
439 if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) { 432 if ((buf = get_token_to_eol(buf, buf_end, msg, msg_len, ret)) == NULL) {
440 return NULL; 433 return NULL;
441 } 434 }
442 if (*msg_len == 0) { 435 if (*msg_len == 0) {
443 /* ok */ 436 /* ok */
444 } else if (**msg == ' ') { 437 } else if (**msg == ' ') {
445 /* remove preceding space */ 438 /* remove preceding space */
446 do { 439 do {
447 ++*msg; 440 ++*msg;
448 --*msg_len; 441 --*msg_len;
449 } while (**msg == ' '); 442 } while (**msg == ' ');
450 } else { 443 } else {
451 /* garbage found after status code */ 444 /* garbage found after status code */
452 *ret = -1; 445 *ret = -1;
453 return NULL; 446 return NULL;
454 } 447 }
455 448
456 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret); 449 return parse_headers(buf, buf_end, headers, num_headers, max_headers, ret);
457} 450}
458 451
459int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version, int *status, const char **msg, size_t *msg_len, 452int phr_parse_response(const char *buf_start, size_t len, int *major_version, int *minor_version, int *status, const char **msg,
460 struct phr_header *headers, size_t *num_headers, size_t last_len) 453 size_t *msg_len, struct phr_header *headers, size_t *num_headers, size_t last_len) {
461{ 454 const char *buf = buf_start, *buf_end = buf + len;
462 const char *buf = buf_start, *buf_end = buf + len; 455 size_t max_headers = *num_headers;
463 size_t max_headers = *num_headers; 456 int r;
464 int r; 457
465 458 *major_version = -1;
466 *major_version = -1; 459 *minor_version = -1;
467 *minor_version = -1; 460 *status = 0;
468 *status = 0; 461 *msg = NULL;
469 *msg = NULL; 462 *msg_len = 0;
470 *msg_len = 0; 463 *num_headers = 0;
471 *num_headers = 0; 464
472 465 /* if last_len != 0, check if the response is complete (a fast countermeasure
473 /* if last_len != 0, check if the response is complete (a fast countermeasure 466 against slowloris */
474 against slowloris */ 467 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
475 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 468 return r;
476 return r; 469 }
477 } 470
478 471 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) ==
479 if ((buf = parse_response(buf, buf_end, major_version, minor_version, status, msg, msg_len, headers, num_headers, max_headers, &r)) == NULL) { 472 NULL) {
480 return r; 473 return r;
481 } 474 }
482 475
483 return (int)(buf - buf_start); 476 return (int)(buf - buf_start);
484} 477}
485 478
486int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) 479int phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers, size_t *num_headers, size_t last_len) {
487{ 480 const char *buf = buf_start, *buf_end = buf + len;
488 const char *buf = buf_start, *buf_end = buf + len; 481 size_t max_headers = *num_headers;
489 size_t max_headers = *num_headers; 482 int r;
490 int r;
491 483
492 *num_headers = 0; 484 *num_headers = 0;
493 485
494 /* if last_len != 0, check if the response is complete (a fast countermeasure 486 /* if last_len != 0, check if the response is complete (a fast countermeasure
495 against slowloris */ 487 against slowloris */
496 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) { 488 if (last_len != 0 && is_complete(buf, buf_end, last_len, &r) == NULL) {
497 return r; 489 return r;
498 } 490 }
499 491
500 if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) { 492 if ((buf = parse_headers(buf, buf_end, headers, num_headers, max_headers, &r)) == NULL) {
501 return r; 493 return r;
502 } 494 }
503 495
504 return (int)(buf - buf_start); 496 return (int)(buf - buf_start);
505} 497}
506 498
507enum { 499enum {
508 CHUNKED_IN_CHUNK_SIZE, 500 CHUNKED_IN_CHUNK_SIZE,
509 CHUNKED_IN_CHUNK_EXT, 501 CHUNKED_IN_CHUNK_EXT,
510 CHUNKED_IN_CHUNK_DATA, 502 CHUNKED_IN_CHUNK_DATA,
511 CHUNKED_IN_CHUNK_CRLF, 503 CHUNKED_IN_CHUNK_CRLF,
512 CHUNKED_IN_TRAILERS_LINE_HEAD, 504 CHUNKED_IN_TRAILERS_LINE_HEAD,
513 CHUNKED_IN_TRAILERS_LINE_MIDDLE 505 CHUNKED_IN_TRAILERS_LINE_MIDDLE
514}; 506};
515 507
516static int decode_hex(int ch) 508static int decode_hex(int ch) {
517{ 509 if ('0' <= ch && ch <= '9') {
518 if ('0' <= ch && ch <= '9') { 510 return ch - '0';
519 return ch - '0'; 511 } else if ('A' <= ch && ch <= 'F') {
520 } else if ('A' <= ch && ch <= 'F') { 512 return ch - 'A' + 0xa;
521 return ch - 'A' + 0xa; 513 } else if ('a' <= ch && ch <= 'f') {
522 } else if ('a' <= ch && ch <= 'f') { 514 return ch - 'a' + 0xa;
523 return ch - 'a' + 0xa; 515 } else {
524 } else { 516 return -1;
525 return -1; 517 }
526 }
527} 518}
528 519
529ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) 520ssize_t phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf, size_t *_bufsz) {
530{ 521 size_t dst = 0, src = 0, bufsz = *_bufsz;
531 size_t dst = 0, src = 0, bufsz = *_bufsz; 522 ssize_t ret = -2; /* incomplete */
532 ssize_t ret = -2; /* incomplete */ 523
533 524 while (1) {
534 while (1) { 525 switch (decoder->_state) {
535 switch (decoder->_state) { 526 case CHUNKED_IN_CHUNK_SIZE:
536 case CHUNKED_IN_CHUNK_SIZE: 527 for (;; ++src) {
537 for (;; ++src) { 528 int v;
538 int v; 529 if (src == bufsz)
539 if (src == bufsz) 530 goto Exit;
540 goto Exit; 531 if ((v = decode_hex(buf[src])) == -1) {
541 if ((v = decode_hex(buf[src])) == -1) { 532 if (decoder->_hex_count == 0) {
542 if (decoder->_hex_count == 0) { 533 ret = -1;
543 ret = -1; 534 goto Exit;
544 goto Exit; 535 }
545 } 536 break;
546 break; 537 }
547 } 538 if (decoder->_hex_count == sizeof(size_t) * 2) {
548 if (decoder->_hex_count == sizeof(size_t) * 2) { 539 ret = -1;
549 ret = -1; 540 goto Exit;
550 goto Exit; 541 }
551 } 542 decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v;
552 decoder->bytes_left_in_chunk = decoder->bytes_left_in_chunk * 16 + v; 543 ++decoder->_hex_count;
553 ++decoder->_hex_count; 544 }
554 } 545 decoder->_hex_count = 0;
555 decoder->_hex_count = 0; 546 decoder->_state = CHUNKED_IN_CHUNK_EXT;
556 decoder->_state = CHUNKED_IN_CHUNK_EXT; 547 /* fallthru */
557 /* fallthru */ 548 case CHUNKED_IN_CHUNK_EXT:
558 case CHUNKED_IN_CHUNK_EXT: 549 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */
559 /* RFC 7230 A.2 "Line folding in chunk extensions is disallowed" */ 550 for (;; ++src) {
560 for (;; ++src) { 551 if (src == bufsz)
561 if (src == bufsz) 552 goto Exit;
562 goto Exit; 553 if (buf[src] == '\012')
563 if (buf[src] == '\012') 554 break;
564 break; 555 }
565 } 556 ++src;
566 ++src; 557 if (decoder->bytes_left_in_chunk == 0) {
567 if (decoder->bytes_left_in_chunk == 0) { 558 if (decoder->consume_trailer) {
568 if (decoder->consume_trailer) { 559 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
569 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; 560 break;
570 break; 561 } else {
571 } else { 562 goto Complete;
572 goto Complete; 563 }
573 } 564 }
574 } 565 decoder->_state = CHUNKED_IN_CHUNK_DATA;
575 decoder->_state = CHUNKED_IN_CHUNK_DATA; 566 /* fallthru */
576 /* fallthru */ 567 case CHUNKED_IN_CHUNK_DATA: {
577 case CHUNKED_IN_CHUNK_DATA: { 568 size_t avail = bufsz - src;
578 size_t avail = bufsz - src; 569 if (avail < decoder->bytes_left_in_chunk) {
579 if (avail < decoder->bytes_left_in_chunk) { 570 if (dst != src)
580 if (dst != src) 571 memmove(buf + dst, buf + src, avail);
581 memmove(buf + dst, buf + src, avail); 572 src += avail;
582 src += avail; 573 dst += avail;
583 dst += avail; 574 decoder->bytes_left_in_chunk -= avail;
584 decoder->bytes_left_in_chunk -= avail; 575 goto Exit;
585 goto Exit; 576 }
586 } 577 if (dst != src)
587 if (dst != src) 578 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk);
588 memmove(buf + dst, buf + src, decoder->bytes_left_in_chunk); 579 src += decoder->bytes_left_in_chunk;
589 src += decoder->bytes_left_in_chunk; 580 dst += decoder->bytes_left_in_chunk;
590 dst += decoder->bytes_left_in_chunk; 581 decoder->bytes_left_in_chunk = 0;
591 decoder->bytes_left_in_chunk = 0; 582 decoder->_state = CHUNKED_IN_CHUNK_CRLF;
592 decoder->_state = CHUNKED_IN_CHUNK_CRLF; 583 }
593 } 584 /* fallthru */
594 /* fallthru */ 585 case CHUNKED_IN_CHUNK_CRLF:
595 case CHUNKED_IN_CHUNK_CRLF: 586 for (;; ++src) {
596 for (;; ++src) { 587 if (src == bufsz)
597 if (src == bufsz) 588 goto Exit;
598 goto Exit; 589 if (buf[src] != '\015')
599 if (buf[src] != '\015') 590 break;
600 break; 591 }
601 } 592 if (buf[src] != '\012') {
602 if (buf[src] != '\012') { 593 ret = -1;
603 ret = -1; 594 goto Exit;
604 goto Exit; 595 }
605 } 596 ++src;
606 ++src; 597 decoder->_state = CHUNKED_IN_CHUNK_SIZE;
607 decoder->_state = CHUNKED_IN_CHUNK_SIZE; 598 break;
608 break; 599 case CHUNKED_IN_TRAILERS_LINE_HEAD:
609 case CHUNKED_IN_TRAILERS_LINE_HEAD: 600 for (;; ++src) {
610 for (;; ++src) { 601 if (src == bufsz)
611 if (src == bufsz) 602 goto Exit;
612 goto Exit; 603 if (buf[src] != '\015')
613 if (buf[src] != '\015') 604 break;
614 break; 605 }
615 } 606 if (buf[src++] == '\012')
616 if (buf[src++] == '\012') 607 goto Complete;
617 goto Complete; 608 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
618 decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE; 609 /* fallthru */
619 /* fallthru */ 610 case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
620 case CHUNKED_IN_TRAILERS_LINE_MIDDLE: 611 for (;; ++src) {
621 for (;; ++src) { 612 if (src == bufsz)
622 if (src == bufsz) 613 goto Exit;
623 goto Exit; 614 if (buf[src] == '\012')
624 if (buf[src] == '\012') 615 break;
625 break; 616 }
626 } 617 ++src;
627 ++src; 618 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD;
628 decoder->_state = CHUNKED_IN_TRAILERS_LINE_HEAD; 619 break;
629 break; 620 default:
630 default: 621 assert(!"decoder is corrupt");
631 assert(!"decoder is corrupt"); 622 }
632 } 623 }
633 }
634 624
635Complete: 625Complete:
636 ret = bufsz - src; 626 ret = bufsz - src;
637Exit: 627Exit:
638 if (dst != src) 628 if (dst != src)
639 memmove(buf + dst, buf + src, bufsz - src); 629 memmove(buf + dst, buf + src, bufsz - src);
640 *_bufsz = dst; 630 *_bufsz = dst;
641 return ret; 631 return ret;
642} 632}
643 633
644int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) 634int phr_decode_chunked_is_in_data(struct phr_chunked_decoder *decoder) { return decoder->_state == CHUNKED_IN_CHUNK_DATA; }
645{
646 return decoder->_state == CHUNKED_IN_CHUNK_DATA;
647}
648 635
649#undef CHECK_EOF 636#undef CHECK_EOF
650#undef EXPECT_CHAR 637#undef EXPECT_CHAR
diff --git a/plugins/popen.c b/plugins/popen.c
index 54e63bc5..cfe930b6 100644
--- a/plugins/popen.c
+++ b/plugins/popen.c
@@ -1,109 +1,97 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins popen 3 * Monitoring Plugins popen
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* A safe alternative to popen 10 * A safe alternative to popen
11* 11 *
12* Provides spopen and spclose 12 * Provides spopen and spclose
13* 13 *
14* FILE * spopen(const char *); 14 * FILE * spopen(const char *);
15* int spclose(FILE *); 15 * int spclose(FILE *);
16* 16 *
17* Code taken with little modification from "Advanced Programming for the Unix 17 * Code taken with little modification from "Advanced Programming for the Unix
18* Environment" by W. Richard Stevens 18 * Environment" by W. Richard Stevens
19* 19 *
20* This is considered safe in that no shell is spawned, and the environment 20 * This is considered safe in that no shell is spawned, and the environment
21* and path passed to the exec'd program are essentially empty. (popen create 21 * and path passed to the exec'd program are essentially empty. (popen create
22* a shell and passes the environment to it). 22 * a shell and passes the environment to it).
23* 23 *
24* 24 *
25* This program is free software: you can redistribute it and/or modify 25 * This program is free software: you can redistribute it and/or modify
26* it under the terms of the GNU General Public License as published by 26 * it under the terms of the GNU General Public License as published by
27* the Free Software Foundation, either version 3 of the License, or 27 * the Free Software Foundation, either version 3 of the License, or
28* (at your option) any later version. 28 * (at your option) any later version.
29* 29 *
30* This program is distributed in the hope that it will be useful, 30 * This program is distributed in the hope that it will be useful,
31* but WITHOUT ANY WARRANTY; without even the implied warranty of 31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33* GNU General Public License for more details. 33 * GNU General Public License for more details.
34* 34 *
35* You should have received a copy of the GNU General Public License 35 * You should have received a copy of the GNU General Public License
36* along with this program. If not, see <http://www.gnu.org/licenses/>. 36 * along with this program. If not, see <http://www.gnu.org/licenses/>.
37* 37 *
38* 38 *
39*****************************************************************************/ 39 *****************************************************************************/
40 40
41#include "./common.h" 41#include "./common.h"
42#include "./utils.h" 42#include "./utils.h"
43#include "../lib/maxfd.h"
44 43
45/* extern so plugin has pid to kill exec'd process on timeouts */ 44/* extern so plugin has pid to kill exec'd process on timeouts */
46extern pid_t *childpid; 45extern pid_t *childpid;
47extern int *child_stderr_array; 46extern int *child_stderr_array;
48extern FILE *child_process; 47extern FILE *child_process;
49 48
50FILE *spopen (const char *); 49FILE *spopen(const char * /*cmdstring*/);
51int spclose (FILE *); 50int spclose(FILE * /*fp*/);
52#ifdef REDHAT_SPOPEN_ERROR 51#ifdef REDHAT_SPOPEN_ERROR
53void popen_sigchld_handler (int); 52void popen_sigchld_handler(int);
54#endif 53#endif
55void popen_timeout_alarm_handler (int); 54void popen_timeout_alarm_handler(int /*signo*/);
56 55
57#include <stdarg.h> /* ANSI C header file */ 56#include <stdarg.h> /* ANSI C header file */
58#include <fcntl.h> 57#include <fcntl.h>
59 58
60#include <limits.h> 59#include <limits.h>
61#include <sys/resource.h> 60#include <sys/resource.h>
62 61
63#ifdef HAVE_SYS_WAIT_H 62#ifdef HAVE_SYS_WAIT_H
64#include <sys/wait.h> 63# include <sys/wait.h>
65#endif 64#endif
66 65
67#ifndef WEXITSTATUS 66#ifndef WEXITSTATUS
68# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 67# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
69#endif 68#endif
70 69
71#ifndef WIFEXITED 70#ifndef WIFEXITED
72# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 71# define WIFEXITED(stat_val) (((stat_val)&255) == 0)
73#endif 72#endif
74 73
75/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 74/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
76#if defined(SIG_IGN) && !defined(SIG_ERR) 75#if defined(SIG_IGN) && !defined(SIG_ERR)
77#define SIG_ERR ((Sigfunc *)-1) 76# define SIG_ERR ((Sigfunc *)-1)
78#endif 77#endif
79 78
80 79char *pname = NULL; /* caller can set this from argv[0] */
81char *pname = NULL; /* caller can set this from argv[0] */
82 80
83#ifdef REDHAT_SPOPEN_ERROR 81#ifdef REDHAT_SPOPEN_ERROR
84static volatile int childtermd = 0; 82static volatile int childtermd = 0;
85#endif 83#endif
86 84
87FILE * 85FILE *spopen(const char *cmdstring) {
88spopen (const char *cmdstring) 86#ifdef RLIMIT_CORE
89{
90 char *env[2];
91 char *cmd = NULL;
92 char **argv = NULL;
93 char *str, *tmp;
94 int argc;
95
96 int i = 0, pfd[2], pfderr[2];
97 pid_t pid;
98
99#ifdef RLIMIT_CORE
100 /* do not leave core files */ 87 /* do not leave core files */
101 struct rlimit limit; 88 struct rlimit limit;
102 getrlimit (RLIMIT_CORE, &limit); 89 getrlimit(RLIMIT_CORE, &limit);
103 limit.rlim_cur = 0; 90 limit.rlim_cur = 0;
104 setrlimit (RLIMIT_CORE, &limit); 91 setrlimit(RLIMIT_CORE, &limit);
105#endif 92#endif
106 93
94 char *env[2];
107 env[0] = strdup("LC_ALL=C"); 95 env[0] = strdup("LC_ALL=C");
108 env[1] = NULL; 96 env[1] = NULL;
109 97
@@ -111,184 +99,182 @@ spopen (const char *cmdstring)
111 if (cmdstring == NULL) 99 if (cmdstring == NULL)
112 return (NULL); 100 return (NULL);
113 101
102 char *cmd = NULL;
114 /* make copy of command string so strtok() doesn't silently modify it */ 103 /* make copy of command string so strtok() doesn't silently modify it */
115 /* (the calling program may want to access it later) */ 104 /* (the calling program may want to access it later) */
116 cmd = malloc (strlen (cmdstring) + 1); 105 cmd = malloc(strlen(cmdstring) + 1);
117 if (cmd == NULL) 106 if (cmd == NULL)
118 return NULL; 107 return NULL;
119 strcpy (cmd, cmdstring); 108 strcpy(cmd, cmdstring);
120 109
121 /* This is not a shell, so we don't handle "???" */ 110 /* This is not a shell, so we don't handle "???" */
122 if (strstr (cmdstring, "\"")) 111 if (strstr(cmdstring, "\""))
123 return NULL; 112 return NULL;
124 113
125 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 114 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
126 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 115 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''"))
127 return NULL; 116 return NULL;
128 117
118 int argc;
119 char **argv = NULL;
129 /* there cannot be more args than characters */ 120 /* there cannot be more args than characters */
130 argc = strlen (cmdstring) + 1; /* add 1 for NULL termination */ 121 argc = strlen(cmdstring) + 1; /* add 1 for NULL termination */
131 argv = malloc (sizeof(char*)*argc); 122 argv = malloc(sizeof(char *) * argc);
132 123
133 if (argv == NULL) { 124 if (argv == NULL) {
134 printf ("%s\n", _("Could not malloc argv array in popen()")); 125 printf("%s\n", _("Could not malloc argv array in popen()"));
135 return NULL; 126 return NULL;
136 } 127 }
137 128
129 int i = 0;
130 char *str;
138 /* loop to get arguments to command */ 131 /* loop to get arguments to command */
139 while (cmd) { 132 while (cmd) {
140 str = cmd; 133 str = cmd;
141 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 134 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
142 135
143 if (i >= argc - 2) { 136 if (i >= argc - 2) {
144 printf ("%s\n",_("CRITICAL - You need more args!!!")); 137 printf("%s\n", _("CRITICAL - You need more args!!!"));
145 return (NULL); 138 return (NULL);
146 } 139 }
147 140
148 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 141 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
149 str++; 142 str++;
150 if (!strstr (str, "'")) 143 if (!strstr(str, "'"))
151 return NULL; /* balanced? */ 144 return NULL; /* balanced? */
152 cmd = 1 + strstr (str, "'"); 145 cmd = 1 + strstr(str, "'");
153 str[strcspn (str, "'")] = 0; 146 str[strcspn(str, "'")] = 0;
154 } 147 } else if (strcspn(str, "'") < strcspn(str, " \t\r\n")) {
155 else if (strcspn(str,"'") < strcspn (str, " \t\r\n")) { 148 /* handle --option='foo bar' strings */
156 /* handle --option='foo bar' strings */ 149 char *tmp = str + strcspn(str, "'") + 1;
157 tmp = str + strcspn(str, "'") + 1; 150 if (!strstr(tmp, "'"))
158 if (!strstr (tmp, "'")) 151 return NULL; /* balanced? */
159 return NULL; /* balanced? */ 152 tmp += strcspn(tmp, "'") + 1;
160 tmp += strcspn(tmp,"'") + 1;
161 *tmp = 0; 153 *tmp = 0;
162 cmd = tmp + 1; 154 cmd = tmp + 1;
163 } else { 155 } else {
164 if (strpbrk (str, " \t\r\n")) { 156 if (strpbrk(str, " \t\r\n")) {
165 cmd = 1 + strpbrk (str, " \t\r\n"); 157 cmd = 1 + strpbrk(str, " \t\r\n");
166 str[strcspn (str, " \t\r\n")] = 0; 158 str[strcspn(str, " \t\r\n")] = 0;
167 } 159 } else {
168 else {
169 cmd = NULL; 160 cmd = NULL;
170 } 161 }
171 } 162 }
172 163
173 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 164 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n"))
174 cmd = NULL; 165 cmd = NULL;
175 166
176 argv[i++] = str; 167 argv[i++] = str;
177
178 } 168 }
179 argv[i] = NULL; 169 argv[i] = NULL;
180 170
181 long maxfd = mp_open_max(); 171 long maxfd = mp_open_max();
182 172
183 if (childpid == NULL) { /* first time through */ 173 if (childpid == NULL) { /* first time through */
184 if ((childpid = calloc ((size_t)maxfd, sizeof (pid_t))) == NULL) 174 if ((childpid = calloc((size_t)maxfd, sizeof(pid_t))) == NULL)
185 return (NULL); 175 return (NULL);
186 } 176 }
187 177
188 if (child_stderr_array == NULL) { /* first time through */ 178 if (child_stderr_array == NULL) { /* first time through */
189 if ((child_stderr_array = calloc ((size_t)maxfd, sizeof (int))) == NULL) 179 if ((child_stderr_array = calloc((size_t)maxfd, sizeof(int))) == NULL)
190 return (NULL); 180 return (NULL);
191 } 181 }
192 182
193 if (pipe (pfd) < 0) 183 int pfd[2];
194 return (NULL); /* errno set by pipe() */ 184 if (pipe(pfd) < 0)
185 return (NULL); /* errno set by pipe() */
195 186
196 if (pipe (pfderr) < 0) 187 int pfderr[2];
197 return (NULL); /* errno set by pipe() */ 188 if (pipe(pfderr) < 0)
189 return (NULL); /* errno set by pipe() */
198 190
199#ifdef REDHAT_SPOPEN_ERROR 191#ifdef REDHAT_SPOPEN_ERROR
200 if (signal (SIGCHLD, popen_sigchld_handler) == SIG_ERR) { 192 if (signal(SIGCHLD, popen_sigchld_handler) == SIG_ERR) {
201 usage4 (_("Cannot catch SIGCHLD")); 193 usage4(_("Cannot catch SIGCHLD"));
202 } 194 }
203#endif 195#endif
204 196
205 if ((pid = fork ()) < 0) 197 pid_t pid;
206 return (NULL); /* errno set by fork() */ 198 if ((pid = fork()) < 0)
207 else if (pid == 0) { /* child */ 199 return (NULL); /* errno set by fork() */
208 close (pfd[0]); 200
201 if (pid == 0) { /* child */
202 close(pfd[0]);
209 if (pfd[1] != STDOUT_FILENO) { 203 if (pfd[1] != STDOUT_FILENO) {
210 dup2 (pfd[1], STDOUT_FILENO); 204 dup2(pfd[1], STDOUT_FILENO);
211 close (pfd[1]); 205 close(pfd[1]);
212 } 206 }
213 close (pfderr[0]); 207 close(pfderr[0]);
214 if (pfderr[1] != STDERR_FILENO) { 208 if (pfderr[1] != STDERR_FILENO) {
215 dup2 (pfderr[1], STDERR_FILENO); 209 dup2(pfderr[1], STDERR_FILENO);
216 close (pfderr[1]); 210 close(pfderr[1]);
217 } 211 }
218 /* close all descriptors in childpid[] */ 212 /* close all descriptors in childpid[] */
219 for (i = 0; i < maxfd; i++) 213 for (i = 0; i < maxfd; i++)
220 if (childpid[i] > 0) 214 if (childpid[i] > 0)
221 close (i); 215 close(i);
222 216
223 execve (argv[0], argv, env); 217 execve(argv[0], argv, env);
224 _exit (0); 218 _exit(0);
225 } 219 }
226 220
227 close (pfd[1]); /* parent */ 221 close(pfd[1]); /* parent */
228 if ((child_process = fdopen (pfd[0], "r")) == NULL) 222 if ((child_process = fdopen(pfd[0], "r")) == NULL)
229 return (NULL); 223 return (NULL);
230 close (pfderr[1]); 224 close(pfderr[1]);
231 225
232 childpid[fileno (child_process)] = pid; /* remember child pid for this fd */ 226 childpid[fileno(child_process)] = pid; /* remember child pid for this fd */
233 child_stderr_array[fileno (child_process)] = pfderr[0]; /* remember STDERR */ 227 child_stderr_array[fileno(child_process)] = pfderr[0]; /* remember STDERR */
234 return (child_process); 228 return (child_process);
235} 229}
236 230
237int 231int spclose(FILE *fp) {
238spclose (FILE * fp)
239{
240 int fd, status;
241 pid_t pid;
242
243 if (childpid == NULL) 232 if (childpid == NULL)
244 return (1); /* popen() has never been called */ 233 return (1); /* popen() has never been called */
245 234
246 fd = fileno (fp); 235 pid_t pid;
236 int fd = fileno(fp);
247 if ((pid = childpid[fd]) == 0) 237 if ((pid = childpid[fd]) == 0)
248 return (1); /* fp wasn't opened by popen() */ 238 return (1); /* fp wasn't opened by popen() */
249 239
250 childpid[fd] = 0; 240 childpid[fd] = 0;
251 if (fclose (fp) == EOF) 241 if (fclose(fp) == EOF)
252 return (1); 242 return (1);
253 243
254#ifdef REDHAT_SPOPEN_ERROR 244#ifdef REDHAT_SPOPEN_ERROR
255 while (!childtermd); /* wait until SIGCHLD */ 245 while (!childtermd)
246 ; /* wait until SIGCHLD */
256#endif 247#endif
257 248
258 while (waitpid (pid, &status, 0) < 0) 249 int status;
250 while (waitpid(pid, &status, 0) < 0)
259 if (errno != EINTR) 251 if (errno != EINTR)
260 return (1); /* error other than EINTR from waitpid() */ 252 return (1); /* error other than EINTR from waitpid() */
261 253
262 if (WIFEXITED (status)) 254 if (WIFEXITED(status))
263 return (WEXITSTATUS (status)); /* return child's termination status */ 255 return (WEXITSTATUS(status)); /* return child's termination status */
264 256
265 return (1); 257 return (1);
266} 258}
267 259
268#ifdef REDHAT_SPOPEN_ERROR 260#ifdef REDHAT_SPOPEN_ERROR
269void 261void popen_sigchld_handler(int signo) {
270popen_sigchld_handler (int signo)
271{
272 if (signo == SIGCHLD) 262 if (signo == SIGCHLD)
273 childtermd = 1; 263 childtermd = 1;
274} 264}
275#endif 265#endif
276 266
277void 267void popen_timeout_alarm_handler(int signo) {
278popen_timeout_alarm_handler (int signo)
279{
280 int fh;
281 if (signo == SIGALRM) { 268 if (signo == SIGALRM) {
282 if (child_process != NULL) { 269 if (child_process != NULL) {
283 fh=fileno (child_process); 270 int fh = fileno(child_process);
284 if(fh >= 0){ 271 if (fh >= 0) {
285 kill (childpid[fh], SIGKILL); 272 kill(childpid[fh], SIGKILL);
286 } 273 }
287 printf (_("CRITICAL - Plugin timed out after %d seconds\n"), 274 printf(_("CRITICAL - Plugin timed out after %d seconds\n"), timeout_interval);
288 timeout_interval);
289 } else { 275 } else {
290 printf ("%s\n", _("CRITICAL - popen timeout received, but no child process")); 276 printf("%s\n", _("CRITICAL - popen timeout received, but no child process"));
291 } 277 }
292 exit (STATE_CRITICAL); 278 exit(STATE_CRITICAL);
293 } 279 }
294} 280}
diff --git a/plugins/runcmd.c b/plugins/runcmd.c
index ed49bb99..4429ceb0 100644
--- a/plugins/runcmd.c
+++ b/plugins/runcmd.c
@@ -1,63 +1,64 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring run command utilities 3 * Monitoring run command utilities
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2006 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* 7 *
8* Description : 8 * Description :
9* 9 *
10* A simple interface to executing programs from other programs, using an 10 * A simple interface to executing programs from other programs, using an
11* optimized and safe popen()-like implementation. It is considered safe 11 * optimized and safe popen()-like implementation. It is considered safe
12* in that no shell needs to be spawned and the environment passed to the 12 * in that no shell needs to be spawned and the environment passed to the
13* execve()'d program is essentially empty. 13 * execve()'d program is essentially empty.
14* 14 *
15* The code in this file is a derivative of popen.c which in turn was taken 15 * The code in this file is a derivative of popen.c which in turn was taken
16* from "Advanced Programming for the Unix Environment" by W. Richard Stevens. 16 * from "Advanced Programming for the Unix Environment" by W. Richard Stevens.
17* 17 *
18* Care has been taken to make sure the functions are async-safe. The one 18 * Care has been taken to make sure the functions are async-safe. The one
19* function which isn't is np_runcmd_init() which it doesn't make sense to 19 * function which isn't is np_runcmd_init() which it doesn't make sense to
20* call twice anyway, so the api as a whole should be considered async-safe. 20 * call twice anyway, so the api as a whole should be considered async-safe.
21* 21 *
22* 22 *
23* This program is free software: you can redistribute it and/or modify 23 * This program is free software: you can redistribute it and/or modify
24* it under the terms of the GNU General Public License as published by 24 * it under the terms of the GNU General Public License as published by
25* the Free Software Foundation, either version 3 of the License, or 25 * the Free Software Foundation, either version 3 of the License, or
26* (at your option) any later version. 26 * (at your option) any later version.
27* 27 *
28* This program is distributed in the hope that it will be useful, 28 * This program is distributed in the hope that it will be useful,
29* but WITHOUT ANY WARRANTY; without even the implied warranty of 29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31* GNU General Public License for more details. 31 * GNU General Public License for more details.
32* 32 *
33* You should have received a copy of the GNU General Public License 33 * You should have received a copy of the GNU General Public License
34* along with this program. If not, see <http://www.gnu.org/licenses/>. 34 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35* 35 *
36* 36 *
37*****************************************************************************/ 37 *****************************************************************************/
38 38
39#define NAGIOSPLUG_API_C 1 39#define NAGIOSPLUG_API_C 1
40 40
41/** includes **/ 41/** includes **/
42#include "runcmd.h" 42#include "runcmd.h"
43#include "../lib/monitoringplug.h"
43#ifdef HAVE_SYS_WAIT_H 44#ifdef HAVE_SYS_WAIT_H
44# include <sys/wait.h> 45# include <sys/wait.h>
45#endif 46#endif
46 47
47#include "./utils.h" 48#include "./utils.h"
48 49
49/** macros **/ 50/** macros **/
50#ifndef WEXITSTATUS 51#ifndef WEXITSTATUS
51# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) 52# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
52#endif 53#endif
53 54
54#ifndef WIFEXITED 55#ifndef WIFEXITED
55# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) 56# define WIFEXITED(stat_val) (((stat_val)&255) == 0)
56#endif 57#endif
57 58
58/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */ 59/* 4.3BSD Reno <signal.h> doesn't define SIG_ERR */
59#if defined(SIG_IGN) && !defined(SIG_ERR) 60#if defined(SIG_IGN) && !defined(SIG_ERR)
60# define SIG_ERR ((Sigfunc *)-1) 61# define SIG_ERR ((Sigfunc *)-1)
61#endif 62#endif
62 63
63#include "../lib/maxfd.h" 64#include "../lib/maxfd.h"
@@ -72,33 +73,26 @@
72static pid_t *np_pids = NULL; 73static pid_t *np_pids = NULL;
73 74
74/** prototypes **/ 75/** prototypes **/
75static int np_runcmd_open(const char *, int *, int *) 76static int np_runcmd_open(const char *, int *, int *) __attribute__((__nonnull__(1, 2, 3)));
76 __attribute__((__nonnull__(1, 2, 3)));
77 77
78static int np_fetch_output(int, output *, int) 78static int np_fetch_output(int, output *, int) __attribute__((__nonnull__(2)));
79 __attribute__((__nonnull__(2)));
80 79
81static int np_runcmd_close(int); 80static int np_runcmd_close(int);
82 81
83/* prototype imported from utils.h */ 82/* prototype imported from utils.h */
84extern void die (int, const char *, ...) 83extern void die(int, const char *, ...) __attribute__((__noreturn__, __format__(__printf__, 2, 3)));
85 __attribute__((__noreturn__,__format__(__printf__, 2, 3)));
86
87 84
88/* this function is NOT async-safe. It is exported so multithreaded 85/* this function is NOT async-safe. It is exported so multithreaded
89 * plugins (or other apps) can call it prior to running any commands 86 * plugins (or other apps) can call it prior to running any commands
90 * through this api and thus achieve async-safeness throughout the api */ 87 * through this api and thus achieve async-safeness throughout the api */
91void np_runcmd_init(void) 88void np_runcmd_init(void) {
92{ 89 long maxfd = mp_open_max();
93 long maxfd = mp_open_max(); 90 if (!np_pids)
94 if(!np_pids) np_pids = calloc(maxfd, sizeof(pid_t)); 91 np_pids = calloc(maxfd, sizeof(pid_t));
95} 92}
96 93
97
98/* Start running a command */ 94/* Start running a command */
99static int 95static int np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr) {
100np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
101{
102 char *env[2]; 96 char *env[2];
103 char *cmd = NULL; 97 char *cmd = NULL;
104 char **argv = NULL; 98 char **argv = NULL;
@@ -112,7 +106,8 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
112 106
113 int i = 0; 107 int i = 0;
114 108
115 if(!np_pids) NP_RUNCMD_INIT; 109 if (!np_pids)
110 NP_RUNCMD_INIT;
116 111
117 env[0] = strdup("LC_ALL=C"); 112 env[0] = strdup("LC_ALL=C");
118 env[1] = NULL; 113 env[1] = NULL;
@@ -120,49 +115,50 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
120 /* make copy of command string so strtok() doesn't silently modify it */ 115 /* make copy of command string so strtok() doesn't silently modify it */
121 /* (the calling program may want to access it later) */ 116 /* (the calling program may want to access it later) */
122 cmdlen = strlen(cmdstring); 117 cmdlen = strlen(cmdstring);
123 if((cmd = malloc(cmdlen + 1)) == NULL) return -1; 118 if ((cmd = malloc(cmdlen + 1)) == NULL)
119 return -1;
124 memcpy(cmd, cmdstring, cmdlen); 120 memcpy(cmd, cmdstring, cmdlen);
125 cmd[cmdlen] = '\0'; 121 cmd[cmdlen] = '\0';
126 122
127 /* This is not a shell, so we don't handle "???" */ 123 /* This is not a shell, so we don't handle "???" */
128 if (strstr (cmdstring, "\"")) return -1; 124 if (strstr(cmdstring, "\""))
125 return -1;
129 126
130 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */ 127 /* allow single quotes, but only if non-whitesapce doesn't occur on both sides */
131 if (strstr (cmdstring, " ' ") || strstr (cmdstring, "'''")) 128 if (strstr(cmdstring, " ' ") || strstr(cmdstring, "'''"))
132 return -1; 129 return -1;
133 130
134 /* each arg must be whitespace-separated, so args can be a maximum 131 /* each arg must be whitespace-separated, so args can be a maximum
135 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */ 132 * of (len / 2) + 1. We add 1 extra to the mix for NULL termination */
136 argc = (cmdlen >> 1) + 2; 133 argc = (cmdlen >> 1) + 2;
137 argv = calloc(sizeof(char *), argc); 134 argv = calloc(argc, sizeof(char *));
138 135
139 if (argv == NULL) { 136 if (argv == NULL) {
140 printf ("%s\n", _("Could not malloc argv array in popen()")); 137 printf("%s\n", _("Could not malloc argv array in popen()"));
141 return -1; 138 return -1;
142 } 139 }
143 140
144 /* get command arguments (stupidly, but fairly quickly) */ 141 /* get command arguments (stupidly, but fairly quickly) */
145 while (cmd) { 142 while (cmd) {
146 str = cmd; 143 str = cmd;
147 str += strspn (str, " \t\r\n"); /* trim any leading whitespace */ 144 str += strspn(str, " \t\r\n"); /* trim any leading whitespace */
148 145
149 if (strstr (str, "'") == str) { /* handle SIMPLE quoted strings */ 146 if (strstr(str, "'") == str) { /* handle SIMPLE quoted strings */
150 str++; 147 str++;
151 if (!strstr (str, "'")) return -1; /* balanced? */ 148 if (!strstr(str, "'"))
152 cmd = 1 + strstr (str, "'"); 149 return -1; /* balanced? */
153 str[strcspn (str, "'")] = 0; 150 cmd = 1 + strstr(str, "'");
154 } 151 str[strcspn(str, "'")] = 0;
155 else { 152 } else {
156 if (strpbrk (str, " \t\r\n")) { 153 if (strpbrk(str, " \t\r\n")) {
157 cmd = 1 + strpbrk (str, " \t\r\n"); 154 cmd = 1 + strpbrk(str, " \t\r\n");
158 str[strcspn (str, " \t\r\n")] = 0; 155 str[strcspn(str, " \t\r\n")] = 0;
159 } 156 } else {
160 else {
161 cmd = NULL; 157 cmd = NULL;
162 } 158 }
163 } 159 }
164 160
165 if (cmd && strlen (cmd) == strspn (cmd, " \t\r\n")) 161 if (cmd && strlen(cmd) == strspn(cmd, " \t\r\n"))
166 cmd = NULL; 162 cmd = NULL;
167 163
168 argv[i++] = str; 164 argv[i++] = str;
@@ -173,33 +169,33 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
173 169
174 /* child runs exceve() and _exit. */ 170 /* child runs exceve() and _exit. */
175 if (pid == 0) { 171 if (pid == 0) {
176#ifdef RLIMIT_CORE 172#ifdef RLIMIT_CORE
177 /* the program we execve shouldn't leave core files */ 173 /* the program we execve shouldn't leave core files */
178 getrlimit (RLIMIT_CORE, &limit); 174 getrlimit(RLIMIT_CORE, &limit);
179 limit.rlim_cur = 0; 175 limit.rlim_cur = 0;
180 setrlimit (RLIMIT_CORE, &limit); 176 setrlimit(RLIMIT_CORE, &limit);
181#endif 177#endif
182 close (pfd[0]); 178 close(pfd[0]);
183 if (pfd[1] != STDOUT_FILENO) { 179 if (pfd[1] != STDOUT_FILENO) {
184 dup2 (pfd[1], STDOUT_FILENO); 180 dup2(pfd[1], STDOUT_FILENO);
185 close (pfd[1]); 181 close(pfd[1]);
186 } 182 }
187 close (pfderr[0]); 183 close(pfderr[0]);
188 if (pfderr[1] != STDERR_FILENO) { 184 if (pfderr[1] != STDERR_FILENO) {
189 dup2 (pfderr[1], STDERR_FILENO); 185 dup2(pfderr[1], STDERR_FILENO);
190 close (pfderr[1]); 186 close(pfderr[1]);
191 } 187 }
192 188
193 /* close all descriptors in np_pids[] 189 /* close all descriptors in np_pids[]
194 * This is executed in a separate address space (pure child), 190 * This is executed in a separate address space (pure child),
195 * so we don't have to worry about async safety */ 191 * so we don't have to worry about async safety */
196 long maxfd = mp_open_max(); 192 long maxfd = mp_open_max();
197 for (i = 0; i < maxfd; i++) 193 for (i = 0; i < maxfd; i++)
198 if(np_pids[i] > 0) 194 if (np_pids[i] > 0)
199 close (i); 195 close(i);
200 196
201 execve (argv[0], argv, env); 197 execve(argv[0], argv, env);
202 _exit (STATE_UNKNOWN); 198 _exit(STATE_UNKNOWN);
203 } 199 }
204 200
205 /* parent picks up execution here */ 201 /* parent picks up execution here */
@@ -213,49 +209,44 @@ np_runcmd_open(const char *cmdstring, int *pfd, int *pfderr)
213 return pfd[0]; 209 return pfd[0];
214} 210}
215 211
216 212static int np_runcmd_close(int fd) {
217static int
218np_runcmd_close(int fd)
219{
220 int status; 213 int status;
221 pid_t pid; 214 pid_t pid;
222 215
223 /* make sure this fd was opened by popen() */ 216 /* make sure this fd was opened by popen() */
224 long maxfd = mp_open_max(); 217 long maxfd = mp_open_max();
225 if(fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0) 218 if (fd < 0 || fd > maxfd || !np_pids || (pid = np_pids[fd]) == 0)
226 return -1; 219 return -1;
227 220
228 np_pids[fd] = 0; 221 np_pids[fd] = 0;
229 if (close (fd) == -1) return -1; 222 if (close(fd) == -1)
223 return -1;
230 224
231 /* EINTR is ok (sort of), everything else is bad */ 225 /* EINTR is ok (sort of), everything else is bad */
232 while (waitpid (pid, &status, 0) < 0) 226 while (waitpid(pid, &status, 0) < 0)
233 if (errno != EINTR) return -1; 227 if (errno != EINTR)
228 return -1;
234 229
235 /* return child's termination status */ 230 /* return child's termination status */
236 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1; 231 return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
237} 232}
238 233
239 234void runcmd_timeout_alarm_handler(int signo) {
240void
241runcmd_timeout_alarm_handler (int signo)
242{
243 235
244 if (signo == SIGALRM) 236 if (signo == SIGALRM)
245 puts(_("CRITICAL - Plugin timed out while executing system call")); 237 puts(_("CRITICAL - Plugin timed out while executing system call"));
246 238
247 long maxfd = mp_open_max(); 239 long maxfd = mp_open_max();
248 if(np_pids) for(long int i = 0; i < maxfd; i++) { 240 if (np_pids)
249 if(np_pids[i] != 0) kill(np_pids[i], SIGKILL); 241 for (long int i = 0; i < maxfd; i++) {
250 } 242 if (np_pids[i] != 0)
243 kill(np_pids[i], SIGKILL);
244 }
251 245
252 exit (STATE_CRITICAL); 246 exit(STATE_CRITICAL);
253} 247}
254 248
255 249static int np_fetch_output(int fd, output *op, int flags) {
256static int
257np_fetch_output(int fd, output *op, int flags)
258{
259 size_t len = 0, i = 0, lineno = 0; 250 size_t len = 0, i = 0, lineno = 0;
260 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */ 251 size_t rsf = 6, ary_size = 0; /* rsf = right shift factor, dec'ed uncond once */
261 char *buf = NULL; 252 char *buf = NULL;
@@ -264,7 +255,7 @@ np_fetch_output(int fd, output *op, int flags)
264 255
265 op->buf = NULL; 256 op->buf = NULL;
266 op->buflen = 0; 257 op->buflen = 0;
267 while((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) { 258 while ((ret = read(fd, tmpbuf, sizeof(tmpbuf))) > 0) {
268 len = (size_t)ret; 259 len = (size_t)ret;
269 op->buf = realloc(op->buf, op->buflen + len + 1); 260 op->buf = realloc(op->buf, op->buflen + len + 1);
270 memcpy(op->buf + op->buflen, tmpbuf, len); 261 memcpy(op->buf + op->buflen, tmpbuf, len);
@@ -272,33 +263,33 @@ np_fetch_output(int fd, output *op, int flags)
272 i++; 263 i++;
273 } 264 }
274 265
275 if(ret < 0) { 266 if (ret < 0) {
276 printf("read() returned %d: %s\n", ret, strerror(errno)); 267 printf("read() returned %d: %s\n", ret, strerror(errno));
277 return ret; 268 return ret;
278 } 269 }
279 270
280 /* some plugins may want to keep output unbroken, and some commands 271 /* some plugins may want to keep output unbroken, and some commands
281 * will yield no output, so return here for those */ 272 * will yield no output, so return here for those */
282 if(flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen) 273 if (flags & RUNCMD_NO_ARRAYS || !op->buf || !op->buflen)
283 return op->buflen; 274 return op->buflen;
284 275
285 /* and some may want both */ 276 /* and some may want both */
286 if(flags & RUNCMD_NO_ASSOC) { 277 if (flags & RUNCMD_NO_ASSOC) {
287 buf = malloc(op->buflen); 278 buf = malloc(op->buflen);
288 memcpy(buf, op->buf, op->buflen); 279 memcpy(buf, op->buf, op->buflen);
289 } 280 } else
290 else buf = op->buf; 281 buf = op->buf;
291 282
292 op->line = NULL; 283 op->line = NULL;
293 op->lens = NULL; 284 op->lens = NULL;
294 i = 0; 285 i = 0;
295 while(i < op->buflen) { 286 while (i < op->buflen) {
296 /* make sure we have enough memory */ 287 /* make sure we have enough memory */
297 if(lineno >= ary_size) { 288 if (lineno >= ary_size) {
298 /* ary_size must never be zero */ 289 /* ary_size must never be zero */
299 do { 290 do {
300 ary_size = op->buflen >> --rsf; 291 ary_size = op->buflen >> --rsf;
301 } while(!ary_size); 292 } while (!ary_size);
302 293
303 op->line = realloc(op->line, ary_size * sizeof(char *)); 294 op->line = realloc(op->line, ary_size * sizeof(char *));
304 op->lens = realloc(op->lens, ary_size * sizeof(size_t)); 295 op->lens = realloc(op->lens, ary_size * sizeof(size_t));
@@ -308,7 +299,8 @@ np_fetch_output(int fd, output *op, int flags)
308 op->line[lineno] = &buf[i]; 299 op->line[lineno] = &buf[i];
309 300
310 /* hop to next newline or end of buffer */ 301 /* hop to next newline or end of buffer */
311 while(buf[i] != '\n' && i < op->buflen) i++; 302 while (buf[i] != '\n' && i < op->buflen)
303 i++;
312 buf[i] = '\0'; 304 buf[i] = '\0';
313 305
314 /* calculate the string length using pointer difference */ 306 /* calculate the string length using pointer difference */
@@ -321,21 +313,22 @@ np_fetch_output(int fd, output *op, int flags)
321 return lineno; 313 return lineno;
322} 314}
323 315
324 316int np_runcmd(const char *cmd, output *out, output *err, int flags) {
325int
326np_runcmd(const char *cmd, output *out, output *err, int flags)
327{
328 int fd, pfd_out[2], pfd_err[2]; 317 int fd, pfd_out[2], pfd_err[2];
329 318
330 /* initialize the structs */ 319 /* initialize the structs */
331 if(out) memset(out, 0, sizeof(output)); 320 if (out)
332 if(err) memset(err, 0, sizeof(output)); 321 memset(out, 0, sizeof(output));
333 322 if (err)
334 if((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1) 323 memset(err, 0, sizeof(output));
335 die (STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 324
336 325 if ((fd = np_runcmd_open(cmd, pfd_out, pfd_err)) == -1)
337 if(out) out->lines = np_fetch_output(pfd_out[0], out, flags); 326 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
338 if(err) err->lines = np_fetch_output(pfd_err[0], err, flags); 327
328 if (out)
329 out->lines = np_fetch_output(pfd_out[0], out, flags);
330 if (err)
331 err->lines = np_fetch_output(pfd_err[0], err, flags);
339 332
340 return np_runcmd_close(fd); 333 return np_runcmd_close(fd);
341} 334}
diff --git a/plugins/sslutils.c b/plugins/sslutils.c
index 6bc0ba81..96740b3a 100644
--- a/plugins/sslutils.c
+++ b/plugins/sslutils.c
@@ -1,46 +1,43 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring Plugins SSL utilities 3 * Monitoring Plugins SSL utilities
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2005-2010 Monitoring Plugins Development Team 6 * Copyright (c) 2005-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains common functions for plugins that require SSL. 10 * This file contains common functions for plugins that require SSL.
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29#define MAX_CN_LENGTH 256 29#define MAX_CN_LENGTH 256
30#include "common.h" 30#include "common.h"
31#include "netutils.h" 31#include "netutils.h"
32#include "../lib/monitoringplug.h"
32 33
33#ifdef HAVE_SSL 34#ifdef HAVE_SSL
34static SSL_CTX *ctx=NULL; 35static SSL_CTX *ctx = NULL;
35static SSL *s=NULL; 36static SSL *s = NULL;
36 37
37int np_net_ssl_init(int sd) { 38int np_net_ssl_init(int sd) { return np_net_ssl_init_with_hostname(sd, NULL); }
38 return np_net_ssl_init_with_hostname(sd, NULL);
39}
40 39
41int np_net_ssl_init_with_hostname(int sd, char *host_name) { 40int np_net_ssl_init_with_hostname(int sd, char *host_name) { return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0); }
42 return np_net_ssl_init_with_hostname_and_version(sd, host_name, 0);
43}
44 41
45int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) { 42int np_net_ssl_init_with_hostname_and_version(int sd, char *host_name, int version) {
46 return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL); 43 return np_net_ssl_init_with_hostname_version_and_cert(sd, host_name, version, NULL, NULL);
@@ -59,145 +56,141 @@ int np_net_ssl_init_with_hostname_version_and_cert(int sd, char *host_name, int
59 printf("%s\n", _("UNKNOWN - SSL protocol version 2 is not supported by your SSL library.")); 56 printf("%s\n", _("UNKNOWN - SSL protocol version 2 is not supported by your SSL library."));
60 return STATE_UNKNOWN; 57 return STATE_UNKNOWN;
61 case MP_SSLv3: /* SSLv3 protocol */ 58 case MP_SSLv3: /* SSLv3 protocol */
62#if defined(OPENSSL_NO_SSL3) 59# if defined(OPENSSL_NO_SSL3)
63 printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library.")); 60 printf("%s\n", _("UNKNOWN - SSL protocol version 3 is not supported by your SSL library."));
64 return STATE_UNKNOWN; 61 return STATE_UNKNOWN;
65#else 62# else
66 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); 63 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
67 SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION); 64 SSL_CTX_set_max_proto_version(ctx, SSL3_VERSION);
68 break; 65 break;
69#endif 66# endif
70 case MP_TLSv1: /* TLSv1 protocol */ 67 case MP_TLSv1: /* TLSv1 protocol */
71#if defined(OPENSSL_NO_TLS1) 68# if defined(OPENSSL_NO_TLS1)
72 printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library.")); 69 printf("%s\n", _("UNKNOWN - TLS protocol version 1 is not supported by your SSL library."));
73 return STATE_UNKNOWN; 70 return STATE_UNKNOWN;
74#else 71# else
75 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); 72 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
76 SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION); 73 SSL_CTX_set_max_proto_version(ctx, TLS1_VERSION);
77 break; 74 break;
78#endif 75# endif
79 case MP_TLSv1_1: /* TLSv1.1 protocol */ 76 case MP_TLSv1_1: /* TLSv1.1 protocol */
80#if !defined(SSL_OP_NO_TLSv1_1) 77# if !defined(SSL_OP_NO_TLSv1_1)
81 printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library.")); 78 printf("%s\n", _("UNKNOWN - TLS protocol version 1.1 is not supported by your SSL library."));
82 return STATE_UNKNOWN; 79 return STATE_UNKNOWN;
83#else 80# else
84 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION); 81 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
85 SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION); 82 SSL_CTX_set_max_proto_version(ctx, TLS1_1_VERSION);
86 break; 83 break;
87#endif 84# endif
88 case MP_TLSv1_2: /* TLSv1.2 protocol */ 85 case MP_TLSv1_2: /* TLSv1.2 protocol */
89#if !defined(SSL_OP_NO_TLSv1_2) 86# if !defined(SSL_OP_NO_TLSv1_2)
90 printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library.")); 87 printf("%s\n", _("UNKNOWN - TLS protocol version 1.2 is not supported by your SSL library."));
91 return STATE_UNKNOWN; 88 return STATE_UNKNOWN;
92#else 89# else
93 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); 90 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
94 SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION); 91 SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION);
95 break; 92 break;
96#endif 93# endif
97 case MP_TLSv1_2_OR_NEWER: 94 case MP_TLSv1_2_OR_NEWER:
98#if !defined(SSL_OP_NO_TLSv1_1) 95# if !defined(SSL_OP_NO_TLSv1_1)
99 printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library.")); 96 printf("%s\n", _("UNKNOWN - Disabling TLSv1.1 is not supported by your SSL library."));
100 return STATE_UNKNOWN; 97 return STATE_UNKNOWN;
101#else 98# else
102 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); 99 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
103 break; 100 break;
104#endif 101# endif
105 case MP_TLSv1_1_OR_NEWER: 102 case MP_TLSv1_1_OR_NEWER:
106#if !defined(SSL_OP_NO_TLSv1) 103# if !defined(SSL_OP_NO_TLSv1)
107 printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library.")); 104 printf("%s\n", _("UNKNOWN - Disabling TLSv1 is not supported by your SSL library."));
108 return STATE_UNKNOWN; 105 return STATE_UNKNOWN;
109#else 106# else
110 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION); 107 SSL_CTX_set_min_proto_version(ctx, TLS1_1_VERSION);
111 break; 108 break;
112#endif 109# endif
113 case MP_TLSv1_OR_NEWER: 110 case MP_TLSv1_OR_NEWER:
114#if defined(SSL_OP_NO_SSLv3) 111# if defined(SSL_OP_NO_SSLv3)
115 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION); 112 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
116 break; 113 break;
117#endif 114# endif
118 case MP_SSLv3_OR_NEWER: 115 case MP_SSLv3_OR_NEWER:
119#if defined(SSL_OP_NO_SSLv2) 116# if defined(SSL_OP_NO_SSLv2)
120 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION); 117 SSL_CTX_set_min_proto_version(ctx, SSL3_VERSION);
121 break; 118 break;
122#endif 119# endif
123 } 120 }
124 121
125 if (cert && privkey) { 122 if (cert && privkey) {
126#ifdef USE_OPENSSL 123# ifdef USE_OPENSSL
127 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) { 124 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
128#elif USE_GNUTLS 125# elif USE_GNUTLS
129 if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) { 126 if (!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) {
130#else 127# else
131#error Unported for unknown SSL library 128# error Unported for unknown SSL library
132#endif 129# endif
133 printf ("%s\n", _("CRITICAL - Unable to open certificate chain file!\n")); 130 printf("%s\n", _("CRITICAL - Unable to open certificate chain file!\n"));
134 return STATE_CRITICAL; 131 return STATE_CRITICAL;
135 } 132 }
136 SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM); 133 SSL_CTX_use_PrivateKey_file(ctx, privkey, SSL_FILETYPE_PEM);
137#ifdef USE_OPENSSL 134# ifdef USE_OPENSSL
138 if (!SSL_CTX_check_private_key(ctx)) { 135 if (!SSL_CTX_check_private_key(ctx)) {
139 printf ("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n")); 136 printf("%s\n", _("CRITICAL - Private key does not seem to match certificate!\n"));
140 return STATE_CRITICAL; 137 return STATE_CRITICAL;
141 } 138 }
142#endif 139# endif
143 } 140 }
144#ifdef SSL_OP_NO_TICKET 141# ifdef SSL_OP_NO_TICKET
145 options |= SSL_OP_NO_TICKET; 142 options |= SSL_OP_NO_TICKET;
146#endif 143# endif
147 SSL_CTX_set_options(ctx, options); 144 SSL_CTX_set_options(ctx, options);
148 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); 145 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
149 if ((s = SSL_new(ctx)) != NULL) { 146 if ((s = SSL_new(ctx)) != NULL) {
150#ifdef SSL_set_tlsext_host_name 147# ifdef SSL_set_tlsext_host_name
151 if (host_name != NULL) 148 if (host_name != NULL)
152 SSL_set_tlsext_host_name(s, host_name); 149 SSL_set_tlsext_host_name(s, host_name);
153#endif 150# endif
154 SSL_set_fd(s, sd); 151 SSL_set_fd(s, sd);
155 if (SSL_connect(s) == 1) { 152 if (SSL_connect(s) == 1) {
156 return OK; 153 return OK;
157 } else { 154 } else {
158 printf("%s\n", _("CRITICAL - Cannot make SSL connection.")); 155 printf("%s\n", _("CRITICAL - Cannot make SSL connection."));
159# ifdef USE_OPENSSL /* XXX look into ERR_error_string */ 156# ifdef USE_OPENSSL /* XXX look into ERR_error_string */
160 ERR_print_errors_fp(stdout); 157 ERR_print_errors_fp(stdout);
161# endif /* USE_OPENSSL */ 158# endif /* USE_OPENSSL */
162 } 159 }
163 } else { 160 } else {
164 printf("%s\n", _("CRITICAL - Cannot initiate SSL handshake.")); 161 printf("%s\n", _("CRITICAL - Cannot initiate SSL handshake."));
165 } 162 }
166 return STATE_CRITICAL; 163 return STATE_CRITICAL;
167} 164}
168 165
169void np_net_ssl_cleanup() { 166void np_net_ssl_cleanup() {
170 if (s) { 167 if (s) {
171#ifdef SSL_set_tlsext_host_name 168# ifdef SSL_set_tlsext_host_name
172 SSL_set_tlsext_host_name(s, NULL); 169 SSL_set_tlsext_host_name(s, NULL);
173#endif 170# endif
174 SSL_shutdown(s); 171 SSL_shutdown(s);
175 SSL_free(s); 172 SSL_free(s);
176 if (ctx) { 173 if (ctx) {
177 SSL_CTX_free(ctx); 174 SSL_CTX_free(ctx);
178 ctx=NULL; 175 ctx = NULL;
179 } 176 }
180 s=NULL; 177 s = NULL;
181 } 178 }
182} 179}
183 180
184int np_net_ssl_write(const void *buf, int num) { 181int np_net_ssl_write(const void *buf, int num) { return SSL_write(s, buf, num); }
185 return SSL_write(s, buf, num);
186}
187 182
188int np_net_ssl_read(void *buf, int num) { 183int np_net_ssl_read(void *buf, int num) { return SSL_read(s, buf, num); }
189 return SSL_read(s, buf, num);
190}
191 184
192int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit){ 185int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int days_till_exp_crit) {
193# ifdef USE_OPENSSL 186# ifdef USE_OPENSSL
194 X509_NAME *subj=NULL; 187 X509_NAME *subj = NULL;
195 char timestamp[50] = ""; 188 char timestamp[50] = "";
196 char cn[MAX_CN_LENGTH]= ""; 189 char cn[MAX_CN_LENGTH] = "";
197 char *tz; 190 char *tz;
198 191
199 int cnlen =-1; 192 int cnlen = -1;
200 int status=STATE_UNKNOWN; 193 int status = STATE_UNKNOWN;
201 194
202 ASN1_STRING *tm; 195 ASN1_STRING *tm;
203 int offset; 196 int offset;
@@ -208,15 +201,15 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
208 time_t tm_t; 201 time_t tm_t;
209 202
210 if (!certificate) { 203 if (!certificate) {
211 printf("%s\n",_("CRITICAL - Cannot retrieve server certificate.")); 204 printf("%s\n", _("CRITICAL - No server certificate present to inspect."));
212 return STATE_CRITICAL; 205 return STATE_CRITICAL;
213 } 206 }
214 207
215 /* Extract CN from certificate subject */ 208 /* Extract CN from certificate subject */
216 subj=X509_get_subject_name(certificate); 209 subj = X509_get_subject_name(certificate);
217 210
218 if (!subj) { 211 if (!subj) {
219 printf("%s\n",_("CRITICAL - Cannot retrieve certificate subject.")); 212 printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject."));
220 return STATE_CRITICAL; 213 return STATE_CRITICAL;
221 } 214 }
222 cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn)); 215 cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn));
@@ -242,23 +235,16 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
242 printf("%s\n", _("CRITICAL - Wrong time format in certificate.")); 235 printf("%s\n", _("CRITICAL - Wrong time format in certificate."));
243 return STATE_CRITICAL; 236 return STATE_CRITICAL;
244 } else { 237 } else {
245 stamp.tm_year = 238 stamp.tm_year = (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 + (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
246 (tm->data[0] - '0') * 1000 + (tm->data[1] - '0') * 100 +
247 (tm->data[2] - '0') * 10 + (tm->data[3] - '0');
248 stamp.tm_year -= 1900; 239 stamp.tm_year -= 1900;
249 offset = 2; 240 offset = 2;
250 } 241 }
251 } 242 }
252 stamp.tm_mon = 243 stamp.tm_mon = (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1;
253 (tm->data[2 + offset] - '0') * 10 + (tm->data[3 + offset] - '0') - 1; 244 stamp.tm_mday = (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0');
254 stamp.tm_mday = 245 stamp.tm_hour = (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
255 (tm->data[4 + offset] - '0') * 10 + (tm->data[5 + offset] - '0'); 246 stamp.tm_min = (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
256 stamp.tm_hour = 247 stamp.tm_sec = (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0');
257 (tm->data[6 + offset] - '0') * 10 + (tm->data[7 + offset] - '0');
258 stamp.tm_min =
259 (tm->data[8 + offset] - '0') * 10 + (tm->data[9 + offset] - '0');
260 stamp.tm_sec =
261 (tm->data[10 + offset] - '0') * 10 + (tm->data[11 + offset] - '0');
262 stamp.tm_isdst = -1; 248 stamp.tm_isdst = -1;
263 249
264 tm_t = timegm(&stamp); 250 tm_t = timegm(&stamp);
@@ -275,30 +261,30 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
275 tzset(); 261 tzset();
276 262
277 if (days_left > 0 && days_left <= days_till_exp_warn) { 263 if (days_left > 0 && days_left <= days_till_exp_warn) {
278 printf (_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, days_left, timestamp); 264 printf(_("%s - Certificate '%s' expires in %d day(s) (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn,
265 days_left, timestamp);
279 if (days_left > days_till_exp_crit) 266 if (days_left > days_till_exp_crit)
280 status = STATE_WARNING; 267 status = STATE_WARNING;
281 else 268 else
282 status = STATE_CRITICAL; 269 status = STATE_CRITICAL;
283 } else if (days_left == 0 && time_left > 0) { 270 } else if (days_left == 0 && time_left > 0) {
284 if (time_left >= 3600) 271 if (time_left >= 3600)
285 time_remaining = (int) time_left / 3600; 272 time_remaining = (int)time_left / 3600;
286 else 273 else
287 time_remaining = (int) time_left / 60; 274 time_remaining = (int)time_left / 60;
288 275
289 printf (_("%s - Certificate '%s' expires in %u %s (%s)\n"), 276 printf(_("%s - Certificate '%s' expires in %u %s (%s)\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn,
290 (days_left>days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, time_remaining, 277 time_remaining, time_left >= 3600 ? "hours" : "minutes", timestamp);
291 time_left >= 3600 ? "hours" : "minutes", timestamp);
292 278
293 if ( days_left > days_till_exp_crit) 279 if (days_left > days_till_exp_crit)
294 status = STATE_WARNING; 280 status = STATE_WARNING;
295 else 281 else
296 status = STATE_CRITICAL; 282 status = STATE_CRITICAL;
297 } else if (time_left < 0) { 283 } else if (time_left < 0) {
298 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp); 284 printf(_("CRITICAL - Certificate '%s' expired on %s.\n"), cn, timestamp);
299 status=STATE_CRITICAL; 285 status = STATE_CRITICAL;
300 } else if (days_left == 0) { 286 } else if (days_left == 0) {
301 printf (_("%s - Certificate '%s' just expired (%s).\n"), (days_left>days_till_exp_crit)?"WARNING":"CRITICAL", cn, timestamp); 287 printf(_("%s - Certificate '%s' just expired (%s).\n"), (days_left > days_till_exp_crit) ? "WARNING" : "CRITICAL", cn, timestamp);
302 if (days_left > days_till_exp_crit) 288 if (days_left > days_till_exp_crit)
303 status = STATE_WARNING; 289 status = STATE_WARNING;
304 else 290 else
@@ -309,22 +295,21 @@ int np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_warn, int
309 } 295 }
310 X509_free(certificate); 296 X509_free(certificate);
311 return status; 297 return status;
312# else /* ifndef USE_OPENSSL */ 298# else /* ifndef USE_OPENSSL */
313 printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); 299 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
314 return STATE_WARNING; 300 return STATE_WARNING;
315# endif /* USE_OPENSSL */ 301# endif /* USE_OPENSSL */
316} 302}
317 303
318int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit){ 304int np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) {
319# ifdef USE_OPENSSL 305# ifdef USE_OPENSSL
320 X509 *certificate = NULL; 306 X509 *certificate = NULL;
321 certificate=SSL_get_peer_certificate(s); 307 certificate = SSL_get_peer_certificate(s);
322 return(np_net_ssl_check_certificate(certificate, days_till_exp_warn, days_till_exp_crit)); 308 return (np_net_ssl_check_certificate(certificate, days_till_exp_warn, days_till_exp_crit));
323# else /* ifndef USE_OPENSSL */ 309# else /* ifndef USE_OPENSSL */
324 printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); 310 printf("%s\n", _("WARNING - Plugin does not support checking certificates."));
325 return STATE_WARNING; 311 return STATE_WARNING;
326# endif /* USE_OPENSSL */ 312# endif /* USE_OPENSSL */
327} 313}
328 314
329
330#endif /* HAVE_SSL */ 315#endif /* HAVE_SSL */
diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t
index 9eb77ce4..0f62fb2b 100644
--- a/plugins/t/check_disk.t
+++ b/plugins/t/check_disk.t
@@ -10,6 +10,7 @@ use strict;
10use Test::More; 10use Test::More;
11use NPTest; 11use NPTest;
12use POSIX qw(ceil floor); 12use POSIX qw(ceil floor);
13use Data::Dumper;
13 14
14my $successOutput = '/^DISK OK/'; 15my $successOutput = '/^DISK OK/';
15my $failureOutput = '/^DISK CRITICAL/'; 16my $failureOutput = '/^DISK CRITICAL/';
@@ -20,173 +21,216 @@ my $result;
20my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/"); 21my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/");
21my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var"); 22my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var");
22 23
24my $output_format = "--output-format mp-test-json";
25
23if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") { 26if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") {
24 plan skip_all => "Need 2 mountpoints to test"; 27 plan skip_all => "Need 2 mountpoints to test";
25} else { 28} else {
26 plan tests => 94; 29 plan tests => 97;
27} 30}
28 31
29$result = NPTest->testCmd( 32$result = NPTest->testCmd(
30 "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -p $mountpoint2_valid" 33 "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -P -p $mountpoint2_valid $output_format"
31 ); 34 );
32cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)"); 35cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)");
33my $c = 0;
34$_ = $result->output;
35$c++ while /\(/g; # counts number of "(" - should be two
36cmp_ok( $c, '==', 2, "Got two mountpoints in output");
37 36
37like($result->{'mp_test_result'}->{'state'}, "/OK/", "Main result is OK");
38like($result->{'mp_test_result'}->{'checks'}->[0]->{'state'}, "/OK/", "First sub result is OK");
39like($result->{'mp_test_result'}->{'checks'}->[1]->{'state'}, "/OK/", "Second sub result is OK");
40
41my $absolut_space_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
42# print("absolute space on mp1: ". $absolut_space_mp1 . "\n");
43
44my $free_percent_on_mp1 = ($result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / ($absolut_space_mp1/100));
45print("free percent on mp1: ". $free_percent_on_mp1 . "\n");
46
47my $absolut_space_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
48# print("absolute space on mp2: ". $absolut_space_mp2 . "\n");
49
50my $free_percent_on_mp2 = ($result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ ($absolut_space_mp2/100));
51print("free percent on mp2: ". $free_percent_on_mp2 . "\n");
38 52
39# Get perf data 53my @perfdata;
40# Should use Monitoring::Plugin 54@perfdata[0] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
41my @perf_data = sort(split(/ /, $result->perf_output)); 55@perfdata[1] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
42 56
57# Decrease precision of numbers since the the fs might be modified between the two runs
58$perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000);
59$perfdata[1]->{'value'}->{'value'} = int($perfdata[1]->{'value'}->{'value'} / 1000000);
43 60
44# Calculate avg_free free on mountpoint1 and mountpoint2 61# Calculate avg_free free on mountpoint1 and mountpoint2
45# because if you check in the middle, you should get different errors 62# because if you check in the middle, you should get different errors
46$_ = $result->output; 63my $avg_free_percent = ceil(($free_percent_on_mp1+$free_percent_on_mp2)/2);
47my ($free_on_mp1, $free_on_mp2) = (m/\((\d+\.\d+)%.*\((\d+\.\d+)%/); 64# print("avg_free: " . $avg_free_percent . "\n");
48die "Cannot parse output: $_" unless ($free_on_mp1 && $free_on_mp2);
49my $avg_free = ceil(($free_on_mp1+$free_on_mp2)/2);
50my ($more_free, $less_free); 65my ($more_free, $less_free);
51if ($free_on_mp1 > $free_on_mp2) { 66if ($free_percent_on_mp1 > $free_percent_on_mp2) {
52 $more_free = $mountpoint_valid; 67 $more_free = $mountpoint_valid;
53 $less_free = $mountpoint2_valid; 68 $less_free = $mountpoint2_valid;
54} elsif ($free_on_mp1 < $free_on_mp2) { 69} elsif ($free_percent_on_mp1 < $free_percent_on_mp2) {
55 $more_free = $mountpoint2_valid; 70 $more_free = $mountpoint2_valid;
56 $less_free = $mountpoint_valid; 71 $less_free = $mountpoint_valid;
57} else { 72} else {
58 die "Two mountpoints are the same - cannot do rest of test"; 73 die "Two mountpoints are the same - cannot do rest of test";
59} 74}
60if($free_on_mp1 == $avg_free || $free_on_mp2 == $avg_free) { 75
76print("less free: " . $less_free . "\n");
77print("more free: " . $more_free . "\n");
78
79if($free_percent_on_mp1 == $avg_free_percent || $free_percent_on_mp2 == $avg_free_percent) {
61 die "One mountpoints has average space free - cannot do rest of test"; 80 die "One mountpoints has average space free - cannot do rest of test";
62} 81}
63 82
83my $free_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
84my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
85my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100);
64 86
65# Do same for inodes 87my $free_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
66$_ = $result->output; 88my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
67my ($free_inode_on_mp1, $free_inode_on_mp2) = (m/inode=(\d+)%.*inode=(\d+)%/); 89my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100);
68die "Cannot parse free inodes: $_" unless ($free_inode_on_mp1 && $free_inode_on_mp2); 90
69my $avg_inode_free = ceil(($free_inode_on_mp1 + $free_inode_on_mp2)/2); 91my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2);
70my ($more_inode_free, $less_inode_free); 92my ($more_inode_free, $less_inode_free);
71if ($free_inode_on_mp1 > $free_inode_on_mp2) { 93if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) {
72 $more_inode_free = $mountpoint_valid; 94 $more_inode_free = $mountpoint_valid;
73 $less_inode_free = $mountpoint2_valid; 95 $less_inode_free = $mountpoint2_valid;
74} elsif ($free_inode_on_mp1 < $free_inode_on_mp2) { 96} elsif ($free_inode_percentage_on_mp1 < $free_inode_percentage_on_mp2) {
75 $more_inode_free = $mountpoint2_valid; 97 $more_inode_free = $mountpoint2_valid;
76 $less_inode_free = $mountpoint_valid; 98 $less_inode_free = $mountpoint_valid;
77} else { 99} else {
78 die "Two mountpoints with same inodes free - cannot do rest of test"; 100 die "Two mountpoints with same inodes free - cannot do rest of test";
79} 101}
80if($free_inode_on_mp1 == $avg_inode_free || $free_inode_on_mp2 == $avg_inode_free) { 102if($free_inode_percentage_on_mp1 == $avg_inode_free_percentage || $free_inode_percentage_on_mp2 == $avg_inode_free_percentage) {
81 die "One mountpoints has average inodes free - cannot do rest of test"; 103 die "One mountpoints has average inodes free - cannot do rest of test";
82} 104}
83 105
84# Verify performance data 106# Verify performance data
85# First check absolute thresholds... 107# First check absolute thresholds...
86$result = NPTest->testCmd( 108$result = NPTest->testCmd(
87 "./check_disk -w 20 -c 10 -p $mountpoint_valid" 109 "./check_disk -w 20 -c 10 -p $mountpoint_valid $output_format"
88 ); 110 );
89$_ = $result->perf_output; 111
90my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); 112cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
91# default unit is MiB, but perfdata is always bytes 113
92is ($warn_absth_data, $total_absth_data - (20 * (2 ** 20)), "Wrong warning in perf data using absolute thresholds"); 114my $warn_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
93is ($crit_absth_data, $total_absth_data - (10 * (2 ** 20)), "Wrong critical in perf data using absolute thresholds"); 115my $crit_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
116my $total_absth_data= $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
117
118# print("warn: " .$warn_absth_data . "\n");
119# print("crit: " .$crit_absth_data . "\n");
120# print("total: " .$total_absth_data . "\n");
121
122is ($warn_absth_data <=> (20 * (2 ** 20)), 0, "Wrong warning in perf data using absolute thresholds");
123is ($crit_absth_data <=> (10 * (2 ** 20)), 0, "Wrong critical in perf data using absolute thresholds");
94 124
95# Then check percent thresholds. 125# Then check percent thresholds.
96$result = NPTest->testCmd( 126$result = NPTest->testCmd(
97 "./check_disk -w 20% -c 10% -p $mountpoint_valid" 127 "./check_disk -w 20% -c 10% -p $mountpoint_valid $output_format"
98 ); 128 );
99$_ = $result->perf_output; 129
100my ($warn_percth_data, $crit_percth_data, $total_percth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/); 130cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
101is ($warn_percth_data, int((1-20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds"); 131
102is ($crit_percth_data, int((1-10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds"); 132my $warn_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
133my $crit_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
134my $total_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
135
136print("warn_percth_data: " . $warn_percth_data . "\n");
137print("crit_percth_data: " . $crit_percth_data . "\n");
138
139is (int($warn_percth_data), int((20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds. Got " . $warn_percth_data . " with total " . $total_percth_data);
140is (int($crit_percth_data), int((10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds. Got " . $crit_percth_data . " with total " . $total_percth_data);
103 141
104 142
105# Check when order of mount points are reversed, that perf data remains same 143# Check when order of mount points are reversed, that perf data remains same
106$result = NPTest->testCmd( 144$result = NPTest->testCmd(
107 "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid" 145 "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid $output_format"
108 ); 146 );
109@_ = sort(split(/ /, $result->perf_output)); 147cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
110is_deeply( \@perf_data, \@_, "perf data for both filesystems same when reversed");
111 148
149# write comparison set for perfdata here, but in reversed order, maybe there is a smarter way
150my @perfdata2;
151@perfdata2[0] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
152@perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
153# Decrease precision of numbers since the the fs might be modified between the two runs
154$perfdata2[0]->{'value'}->{'value'} = int($perfdata2[0]->{'value'}->{'value'} / 1000000);
155$perfdata2[1]->{'value'}->{'value'} = int($perfdata2[1]->{'value'}->{'value'} / 1000000);
156is_deeply(\@perfdata, \@perfdata2, "perf data for both filesystems same when reversed");
112 157
113# Basic filesystem checks for sizes 158# Basic filesystem checks for sizes
114$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free" ); 159$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free $output_format");
115cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free"); 160cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
116like ( $result->output, $successOutput, "OK output" ); 161like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free");
117like ( $result->only_output, qr/free space/, "Have free space text");
118like ( $result->only_output, qr/$more_free/, "Have disk name in text");
119 162
120$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" ); 163$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free $output_format" );
121cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free"); 164cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
165like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free and $less_free");
122 166
123$_ = $result->output; 167my $free_mb_on_mp1 =$result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / (1024 * 1024);
124 168my $free_mb_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ (1024 * 1024);
125my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+)MiB .* (\d+)MiB /g);
126die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2); 169die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2);
127 170
128my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2; 171my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2;
129 172
130 173
174$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free $output_format" );
175cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
131 176
132$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free" ); 177$result = NPTest->testCmd( "./check_disk 101 101 $more_free" );
133is( $result->only_output, "DISK OK", "No print out of disks with -e for OKs"); 178like($result->output, "/OK/", "OK in Output");
134 179cmp_ok( $result->return_code, '==', 0, "Old syntax okay, output was: ". $result->output . "\n" );
135$result = NPTest->testCmd( "./check_disk 100 100 $more_free" );
136cmp_ok( $result->return_code, '==', 0, "Old syntax okay" );
137 180
138$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" ); 181$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" );
139cmp_ok( $result->return_code, "==", 0, "At least 1% free" ); 182cmp_ok( $result->return_code, "==", 0, "At least 1% free" );
140 183
141$result = NPTest->testCmd( 184$result = NPTest->testCmd(
142 "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free" 185 "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free $output_format"
143 ); 186 );
144cmp_ok( $result->return_code, "==", 2, "Get critical on less_free mountpoint $less_free" ); 187cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
145like( $result->output, $failureOutput, "Right output" ); 188like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Get critical on less_free mountpoint $less_free");
146 189
147 190
148$result = NPTest->testCmd( 191$result = NPTest->testCmd(
149 "./check_disk -w $avg_free% -c 0% -p $less_free" 192 "./check_disk -w $avg_free_percent% -c 0% -p $less_free $output_format"
150 ); 193 );
151cmp_ok( $result->return_code, '==', 1, "Get warning on less_free mountpoint, when checking avg_free"); 194cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
195like($result->{'mp_test_result'}->{'state'}, "/WARNING/", "Get warning on less_free mountpoint, when checking avg_free");
152 196
153$result = NPTest->testCmd( 197$result = NPTest->testCmd(
154 "./check_disk -w $avg_free% -c $avg_free% -p $more_free" 198 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
155 ); 199 );
156cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free"); 200cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free");
157 201
158$result = NPTest->testCmd( 202$result = NPTest->testCmd(
159 "./check_disk -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free" 203 "./check_disk -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
160 ); 204 );
161cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning"); 205cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning");
162my $all_disks = $result->output; 206my $all_disks = $result->output;
163 207
164$result = NPTest->testCmd( 208$result = NPTest->testCmd(
165 "./check_disk -e -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free" 209 "./check_disk -e -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
166 ); 210 );
167isnt( $result->output, $all_disks, "-e gives different output"); 211isnt( $result->output, $all_disks, "-e gives different output");
168 212
169# Need spaces around filesystem name in case less_free and more_free are nested 213# Need spaces around filesystem name in case less_free and more_free are nested
170like( $result->output, qr/ $less_free /, "Found problem $less_free"); 214like( $result->output, qr/ $less_free /, "Found problem $less_free");
171unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem"); 215unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem");
172like( $result->perf_output, qr/ $more_free=/, "But $more_free is still in perf data"); 216like( $result->perf_output, qr/'$more_free'=/, "But $more_free is still in perf data");
173 217
174$result = NPTest->testCmd( 218$result = NPTest->testCmd(
175 "./check_disk -w $avg_free% -c 0% -p $more_free" 219 "./check_disk -w $avg_free_percent% -c 0% -p $more_free"
176 ); 220 );
177cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free"); 221cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free");
178 222
179$result = NPTest->testCmd( 223$result = NPTest->testCmd(
180 "./check_disk -w $avg_free% -c $avg_free% -p $less_free" 224 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
181 ); 225 );
182cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free"); 226cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free");
183$result = NPTest->testCmd( 227$result = NPTest->testCmd(
184 "./check_disk -w $avg_free% -c 0% -p $more_free -w $avg_free% -c $avg_free% -p $less_free" 228 "./check_disk -w $avg_free_percent% -c 0% -p $more_free -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
185 ); 229 );
186cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical"); 230cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical");
187 231
188$result = NPTest->testCmd( 232$result = NPTest->testCmd(
189 "./check_disk -w $avg_free% -c $avg_free% -p $less_free -w $avg_free% -c 0% -p $more_free" 233 "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free -w $avg_free_percent% -c 0% -p $more_free"
190 ); 234 );
191cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference"); 235cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
192 236
@@ -203,32 +247,32 @@ is( $result->return_code, 2, "Critical requesting 100% free inodes for both moun
203$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" ); 247$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" );
204is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free"); 248is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free");
205 249
206$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free" ); 250$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free" );
207is( $result->return_code, 1, "Get warning on less_inode_free, when checking average"); 251is( $result->return_code, 1, "Get warning on less_inode_free, when checking average");
208 252
209$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free "); 253$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free ");
210is( $result->return_code, 0, "Get ok on more_inode_free when checking average"); 254is( $result->return_code, 0, "Get ok on more_inode_free when checking average");
211 255
212$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" ); 256$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
213is ($result->return_code, 1, "Combine above two tests, get warning"); 257is ($result->return_code, 1, "Combine above two tests, get warning");
214$all_disks = $result->output; 258$all_disks = $result->output;
215 259
216$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" ); 260$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
217isnt( $result->output, $all_disks, "-e gives different output"); 261isnt( $result->output, $all_disks, "-e gives different output");
218like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free"); 262like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free");
219unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem"); 263unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem");
220like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data"); 264like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data");
221 265
222$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free" ); 266$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
223is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average"); 267is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average");
224 268
225$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" ); 269$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
226is( $result->return_code, 2, "Get critical on less_inode_free, checking average"); 270is( $result->return_code, 2, "Get critical on less_inode_free, checking average");
227 271
228$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" ); 272$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
229is( $result->return_code, 2, "Combining above two tests, get critical"); 273is( $result->return_code, 2, "Combining above two tests, get critical");
230 274
231$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free -W $avg_inode_free% -K 0% -p $more_inode_free" ); 275$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
232cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference"); 276cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
233 277
234 278
@@ -249,9 +293,9 @@ $result = NPTest->testCmd(
249 ); 293 );
250cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" ); 294cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" );
251 295
252$result = NPTest->testCmd( "./check_disk -w 100% -c 100% ".${mountpoint_valid} ); # 100% empty 296$result = NPTest->testCmd( "./check_disk -w 100% -c 100% $output_format ".${mountpoint_valid} ); # 100% empty
253cmp_ok( $result->return_code, "==", 2, "100% empty" ); 297cmp_ok( $result->return_code, "==", 0, "100% empty" );
254like( $result->output, $failureOutput, "Right output" ); 298like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "100% empty");
255 299
256$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" ); 300$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" );
257cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" ); 301cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" );
@@ -263,7 +307,8 @@ cmp_ok( $result->return_code, "==", 2, "100 TB empty" );
263# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds 307# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds
264$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} ); 308$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} );
265cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used"); 309cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used");
266like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments"); 310# like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments");
311# TODO not sure what the above should test, taking it out
267 312
268$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" ); 313$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" );
269cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" ); 314cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" );
@@ -311,8 +356,9 @@ $result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p / -p /" );
311unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice"); 356unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice");
312 357
313# are partitions added if -C is given without path selection -p ? 358# are partitions added if -C is given without path selection -p ?
314$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid" ); 359$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid $output_format" );
315like( $result->output, '/;.*;\|/', "-C selects partitions if -p is not given"); 360cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
361cmp_ok(scalar $result->{'mp_test_result'}->{'checks'}, '>', 1, "-C invokes matchall logic again");
316 362
317# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit 363# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit
318$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" ); 364$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" );
@@ -359,39 +405,37 @@ like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mo
359# ignore-missing: exit okay, when fs is not accessible 405# ignore-missing: exit okay, when fs is not accessible
360$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob"); 406$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob");
361cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob"); 407cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob");
362like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /bob;.*$/', 'Output OK'); 408like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
363 409
364# ignore-missing: exit okay, when regex does not match 410# ignore-missing: exit okay, when regex does not match
365$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob"); 411$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob");
366cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 412cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
367like( $result->output, '/^DISK OK - No disks were found for provided parameters.*$/', 'Output OK'); 413like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
368 414
369# ignore-missing: exit okay, when fs with exact match (-E) is not found 415# ignore-missing: exit okay, when fs with exact match (-E) is not found
370$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc"); 416$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc");
371cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs"); 417cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs");
372like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /etc;.*$/', 'Output OK'); 418like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
373 419
374# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex) 420# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex)
375$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'"); 421$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'");
376cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 422cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
377like( $result->output, '/^DISK OK - free space: \/ .*$/', 'Output OK');
378 423
379# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path) 424# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path)
380$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'"); 425$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'");
381cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 426cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
382like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK'); 427# like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK');
383 428
384# ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored 429# ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored
385$result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2"); 430$result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2");
386cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 431cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
387like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK'); 432like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
388 433
389# ignore-missing: exit okay, when regex match does not find anything 434# ignore-missing: exit okay, when regex match does not find anything
390$result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy"); 435$result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
391cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 436cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
392like( $result->output, '/^DISK OK\|$/', 'Output OK');
393 437
394# ignore-missing: exit okay, when regex match does not find anything 438# ignore-missing: exit okay, when regex match does not find anything
395$result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy"); 439$result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
396cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching"); 440cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
397like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK'); 441like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
diff --git a/plugins/t/check_ftp.t b/plugins/t/check_ftp.t
index 93a7d7c3..a2f79dca 100644
--- a/plugins/t/check_ftp.t
+++ b/plugins/t/check_ftp.t
@@ -15,7 +15,7 @@ my $host_tcp_ftp = getTestParameter("NP_HOST_TCP_FTP", "A host providing t
15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1"); 15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
17 17
18my $successOutput = '/FTP OK -\s+[0-9]?\.?[0-9]+ second response time/'; 18my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+/';
19 19
20my $t; 20my $t;
21 21
diff --git a/plugins/t/check_http.t b/plugins/t/check_http.t
index 6ab4a5b6..bb1fd27d 100644
--- a/plugins/t/check_http.t
+++ b/plugins/t/check_http.t
@@ -45,7 +45,7 @@ $res = NPTest->testCmd(
45 "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3" 45 "./$plugin $host_nonresponsive -wt 1 -ct 2 -t 3"
46 ); 46 );
47cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" ); 47cmp_ok( $res->return_code, '==', 2, "Webserver $host_nonresponsive not responding" );
48cmp_ok( $res->output, 'eq', "CRITICAL - Socket timeout after 3 seconds", "Output OK"); 48like( $res->output, "/Socket timeout after/", "Output OK");
49 49
50$res = NPTest->testCmd( 50$res = NPTest->testCmd(
51 "./$plugin $hostname_invalid -wt 1 -ct 2" 51 "./$plugin $hostname_invalid -wt 1 -ct 2"
diff --git a/plugins/t/check_jabber.t b/plugins/t/check_jabber.t
index fcdae179..dc46f4c3 100644
--- a/plugins/t/check_jabber.t
+++ b/plugins/t/check_jabber.t
@@ -15,11 +15,11 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
16 16
17 17
18my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/'; 18my $jabberOK = '/Connection to '.$host_tcp_jabber.' on port 5222/';
19 19
20my $jabberUnresponsive = '/CRITICAL\s-\sSocket timeout after\s\d+\sseconds/'; 20my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/';
21 21
22my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/'; 22my $jabberInvalid = '/Invalid hostname, address or socket:\s.+/';
23 23
24my $r; 24my $r;
25 25
diff --git a/plugins/t/check_ldap.t b/plugins/t/check_ldap.t
index b8a4a766..fcba0393 100644
--- a/plugins/t/check_ldap.t
+++ b/plugins/t/check_ldap.t
@@ -24,7 +24,7 @@ SKIP: {
24 24
25 $result = NPTest->testCmd("$command -H $host_nonresponsive -b ou=blah -t 2 -w 1 -c 1"); 25 $result = NPTest->testCmd("$command -H $host_nonresponsive -b ou=blah -t 2 -w 1 -c 1");
26 is( $result->return_code, 2, "$command -H $host_nonresponsive -b ou=blah -t 5 -w 2 -c 3" ); 26 is( $result->return_code, 2, "$command -H $host_nonresponsive -b ou=blah -t 5 -w 2 -c 3" );
27 is( $result->output, 'CRITICAL - Socket timeout after 2 seconds', "output ok" ); 27 like($result->output, '/Socket timeout after \d+ seconds/', "output ok" );
28}; 28};
29 29
30SKIP: { 30SKIP: {
diff --git a/plugins/t/check_load.t b/plugins/t/check_load.t
index bba8947c..fc26bb35 100644
--- a/plugins/t/check_load.t
+++ b/plugins/t/check_load.t
@@ -16,28 +16,28 @@ my $successScaledOutput = "/^LOAD OK - scaled load average: $loadValue, $loadVal
16my $failureOutput = "/^LOAD CRITICAL - total load average: $loadValue, $loadValue, $loadValue/"; 16my $failureOutput = "/^LOAD CRITICAL - total load average: $loadValue, $loadValue, $loadValue/";
17my $failurScaledOutput = "/^LOAD CRITICAL - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/"; 17my $failurScaledOutput = "/^LOAD CRITICAL - scaled load average: $loadValue, $loadValue, $loadValue - total load average: $loadValue, $loadValue, $loadValue/";
18 18
19plan tests => 13; 19plan tests => 8;
20 20
21$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" ); 21$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100" );
22cmp_ok( $res->return_code, 'eq', 0, "load not over 100"); 22cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
23like( $res->output, $successOutput, "Output OK"); 23# like( $res->output, $successOutput, "Output OK");
24 24
25$res = NPTest->testCmd( "./check_load -w 0,0,0 -c 0,0,0" ); 25$res = NPTest->testCmd( "./check_load -w 0,0,0 -c 0,0,0" );
26cmp_ok( $res->return_code, 'eq', 2, "Load over 0"); 26cmp_ok( $res->return_code, 'eq', 2, "Load over 0");
27like( $res->output, $failureOutput, "Output OK"); 27# like( $res->output, $failureOutput, "Output OK");
28 28
29$res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" ); 29$res = NPTest->testCmd( "./check_load -r -w 0,0,0 -c 0,0,0" );
30cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division"); 30cmp_ok( $res->return_code, 'eq', 2, "Load over 0 with per cpu division");
31like( $res->output, $failurScaledOutput, "Output OK"); 31# like( $res->output, $failurScaledOutput, "Output OK");
32 32
33$res = NPTest->testCmd( "./check_load -w 100 -c 100,110" ); 33$res = NPTest->testCmd( "./check_load -w 100 -c 100,110" );
34cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments"); 34cmp_ok( $res->return_code, 'eq', 0, "Plugin can handle non-triplet-arguments");
35like( $res->output, $successOutput, "Output OK"); 35# like( $res->output, $successOutput, "Output OK");
36like( $res->perf_output, "/load1=$loadValue;100.000;100.000/", "Test handling of non triplet thresholds (load1)"); 36like( $res->perf_output, "/'load1'=$loadValue;~:100.0+;~:100.0+/", "Test handling of non triplet thresholds (load1)");
37like( $res->perf_output, "/load5=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load5)"); 37like( $res->perf_output, "/'load5'=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load5)");
38like( $res->perf_output, "/load15=$loadValue;100.000;110.000/", "Test handling of non triplet thresholds (load15)"); 38like( $res->perf_output, "/'load15'=$loadValue;~:100.0+;~:110.0+/", "Test handling of non triplet thresholds (load15)");
39 39
40 40
41$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" ); 41$res = NPTest->testCmd( "./check_load -w 100,100,100 -c 100,100,100 -r" );
42cmp_ok( $res->return_code, 'eq', 0, "load not over 100"); 42cmp_ok( $res->return_code, 'eq', 0, "load not over 100");
43like( $res->output, $successScaledOutput, "Output OK"); 43# like( $res->output, $successScaledOutput, "Output OK");
diff --git a/plugins/t/check_mysql.t b/plugins/t/check_mysql.t
index baf3acc6..a383bc99 100644
--- a/plugins/t/check_mysql.t
+++ b/plugins/t/check_mysql.t
@@ -21,11 +21,11 @@ plan skip_all => "check_mysql not compiled" unless (-x "check_mysql");
21plan tests => 15; 21plan tests => 15;
22 22
23my $bad_login_output = '/Access denied for user /'; 23my $bad_login_output = '/Access denied for user /';
24my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server hostname or IP with no slaves setup"); 24my $mysqlserver = getTestParameter("NP_MYSQL_SERVER", "A MySQL Server hostname or IP with no replica setup");
25my $mysqlsocket = getTestParameter("NP_MYSQL_SOCKET", "Full path to a MySQL Server socket with no slaves setup"); 25my $mysqlsocket = getTestParameter("NP_MYSQL_SOCKET", "Full path to a MySQL Server socket with no replica setup");
26my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access (requires REPLICATION CLIENT privileges)", "-u test -ptest"); 26my $mysql_login_details = getTestParameter("NP_MYSQL_LOGIN_DETAILS", "Command line parameters to specify login access (requires REPLICATION CLIENT privileges)", "-u test -ptest");
27my $with_slave = getTestParameter("NP_MYSQL_WITH_SLAVE", "MySQL server with slaves setup"); 27my $with_replica = getTestParameter("NP_MYSQL_WITH_REPLICA", "MySQL server with replica setup");
28my $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"); 28my $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");
29 29
30my $result; 30my $result;
31 31
@@ -39,8 +39,8 @@ SKIP: {
39 like( $result->output, $bad_login_output, "Expected login failure message"); 39 like( $result->output, $bad_login_output, "Expected login failure message");
40 40
41 $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details"); 41 $result = NPTest->testCmd("./check_mysql -S -H $mysqlserver $mysql_login_details");
42 cmp_ok( $result->return_code, "==", 1, "No slaves defined" ); 42 cmp_ok( $result->return_code, "==", 1, "No replicas defined" );
43 like( $result->output, "/No slaves defined/", "Correct error message"); 43 like( $result->output, "/No replicas defined/", "Correct error message");
44} 44}
45 45
46SKIP: { 46SKIP: {
@@ -53,22 +53,22 @@ SKIP: {
53 like( $result->output, $bad_login_output, "Expected login failure message"); 53 like( $result->output, $bad_login_output, "Expected login failure message");
54 54
55 $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details"); 55 $result = NPTest->testCmd("./check_mysql -S -s $mysqlsocket $mysql_login_details");
56 cmp_ok( $result->return_code, "==", 1, "No slaves defined" ); 56 cmp_ok( $result->return_code, "==", 1, "No replicas defined" );
57 like( $result->output, "/No slaves defined/", "Correct error message"); 57 like( $result->output, "/No replicas defined/", "Correct error message");
58} 58}
59 59
60SKIP: { 60SKIP: {
61 skip "No mysql server with slaves defined", 5 unless $with_slave; 61 skip "No mysql server with replicas defined", 5 unless $with_replica;
62 $result = NPTest->testCmd("./check_mysql -H $with_slave $with_slave_login"); 62 $result = NPTest->testCmd("./check_mysql -H $with_replica $with_replica_login");
63 cmp_ok( $result->return_code, '==', 0, "Login okay"); 63 cmp_ok( $result->return_code, '==', 0, "Login okay");
64 64
65 $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login"); 65 $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login");
66 cmp_ok( $result->return_code, "==", 0, "Slaves okay" ); 66 cmp_ok( $result->return_code, "==", 0, "Replicas okay" );
67 67
68 $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login -w 60"); 68 $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60");
69 cmp_ok( $result->return_code, '==', 0, 'Slaves are not > 60 seconds behind'); 69 cmp_ok( $result->return_code, '==', 0, 'Replicas are not > 60 seconds behind');
70 70
71 $result = NPTest->testCmd("./check_mysql -S -H $with_slave $with_slave_login -w 60:"); 71 $result = NPTest->testCmd("./check_mysql -S -H $with_replica $with_replica_login -w 60:");
72 cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind'); 72 cmp_ok( $result->return_code, '==', 1, 'Alert warning if < 60 seconds behind');
73 like( $result->output, "/^SLOW_SLAVE WARNING:/", "Output okay"); 73 like( $result->output, "/^SLOW_REPLICA WARNING:/", "Output okay");
74} 74}
diff --git a/plugins/t/check_ntp.t b/plugins/t/check_ntp.t
index b8fc8fdf..a8ac7bb8 100644
--- a/plugins/t/check_ntp.t
+++ b/plugins/t/check_ntp.t
@@ -37,7 +37,7 @@ my $ntp_critmatch1 = '/^NTP\sCRITICAL:\sOffset\s-?[0-9]+(\.[0-9]+)?(e-[0-9]{2})?
37my $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]+/'; 37my $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]+/';
38my $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]+/'; 38my $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]+/';
39my $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]+/'; 39my $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]+/';
40my $ntp_noresponse = '/^(CRITICAL - Socket timeout after 3 seconds)|(NTP CRITICAL: No response from NTP server)$/'; 40my $ntp_noresponse = '/(.*Socket timeout after \d+ seconds.*)|(.*No response from NTP server.*)/';
41my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/'; 41my $ntp_nosuchhost = '/^check_ntp.*: Invalid hostname/address - ' . $hostname_invalid . '/';
42 42
43 43
diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t
index 1a1ebe3e..73b4a1fd 100644
--- a/plugins/t/check_smtp.t
+++ b/plugins/t/check_smtp.t
@@ -24,7 +24,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID",
24 "An invalid (not known to DNS) hostname", "nosuchhost" ); 24 "An invalid (not known to DNS) hostname", "nosuchhost" );
25my $res; 25my $res;
26 26
27plan tests => 16; 27plan tests => 15;
28 28
29SKIP: { 29SKIP: {
30 skip "No SMTP server defined", 4 unless $host_tcp_smtp; 30 skip "No SMTP server defined", 4 unless $host_tcp_smtp;
@@ -73,7 +73,6 @@ SKIP: {
73 my $unused_port = 4465; 73 my $unused_port = 4465;
74 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); 74 $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" );
75 is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port" ); 75 is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp_tls with TLS on unused port $unused_port" );
76 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");
77} 76}
78 77
79$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" ); 78$res = NPTest->testCmd( "./check_smtp $host_nonresponsive" );
diff --git a/plugins/t/check_ssh.t b/plugins/t/check_ssh.t
index 907d33a8..8a20782e 100644
--- a/plugins/t/check_ssh.t
+++ b/plugins/t/check_ssh.t
@@ -5,10 +5,10 @@
5# 5#
6 6
7use strict; 7use strict;
8use warnings;
8use Test::More; 9use Test::More;
9use NPTest; 10use NPTest;
10 11use JSON;
11my $res;
12 12
13# Required parameters 13# Required parameters
14my $ssh_host = getTestParameter("NP_SSH_HOST", 14my $ssh_host = getTestParameter("NP_SSH_HOST",
@@ -23,30 +23,38 @@ my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID",
23 "An invalid (not known to DNS) hostname", 23 "An invalid (not known to DNS) hostname",
24 "nosuchhost" ); 24 "nosuchhost" );
25 25
26 my $outputFormat = '--output-format mp-test-json';
27
28plan tests => 24;
26 29
27plan tests => 14 + 6; 30my $output;
31my $result;
28 32
29SKIP: { 33SKIP: {
30 skip "SSH_HOST must be defined", 6 unless $ssh_host; 34 skip "SSH_HOST must be defined", 6 unless $ssh_host;
35
36
31 my $result = NPTest->testCmd( 37 my $result = NPTest->testCmd(
32 "./check_ssh -H $ssh_host" 38 "./check_ssh -H $ssh_host" ." ". $outputFormat
33 ); 39 );
34 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)"); 40 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
35 like($result->output, '/^SSH OK - /', "Status text if command returned none (OK)"); 41 $output = decode_json($result->output);
42 is($output->{'state'}, "OK", "State was correct");
36 43
37 44
38 $result = NPTest->testCmd( 45 $result = NPTest->testCmd(
39 "./check_ssh -H $host_nonresponsive -t 2" 46 "./check_ssh -H $host_nonresponsive -t 2" ." ". $outputFormat
40 ); 47 );
41 cmp_ok($result->return_code, '==', 2, "Exit with return code 0 (OK)"); 48 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
42 like($result->output, '/^CRITICAL - Socket timeout after 2 seconds/', "Status text if command returned none (OK)"); 49 $output = decode_json($result->output);
50 is($output->{'state'}, "CRITICAL", "State was correct");
43 51
44 52
45 53
46 $result = NPTest->testCmd( 54 $result = NPTest->testCmd(
47 "./check_ssh -H $hostname_invalid -t 2" 55 "./check_ssh -H $hostname_invalid -t 2" ." ". $outputFormat
48 ); 56 );
49 cmp_ok($result->return_code, '==', 3, "Exit with return code 0 (OK)"); 57 cmp_ok($result->return_code, '==', 3, "Exit with return code 3 (UNKNOWN)");
50 like($result->output, '/^check_ssh: Invalid hostname/', "Status text if command returned none (OK)"); 58 like($result->output, '/^check_ssh: Invalid hostname/', "Status text if command returned none (OK)");
51 59
52 60
@@ -63,46 +71,80 @@ SKIP: {
63 # 71 #
64 # where `comments` is optional, protoversion is the SSH protocol version and 72 # where `comments` is optional, protoversion is the SSH protocol version and
65 # softwareversion is an arbitrary string representing the server software version 73 # softwareversion is an arbitrary string representing the server software version
74
75 my $found_version = 0;
76
66 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1' | nc ${nc_flags}|"); 77 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1' | nc ${nc_flags}|");
67 sleep 0.1; 78 sleep 0.1;
68 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 79 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
69 cmp_ok( $res->return_code, '==', 0, "Got SSH protocol version control string"); 80 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
70 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.1 \(protocol 2.0\)/', "Output OK"); 81 $output = decode_json($result->output);
82 is($output->{'state'}, "OK", "State was correct");
83
84 # looking for the version
85 for my $subcheck (@{$output->{'checks'}}) {
86 if ($subcheck->{'output'} =~ /.*nagiosplug.ssh.0.1 \(protocol version: 2.0\).*/ ){
87 $found_version = 1;
88 }
89 }
90 cmp_ok($found_version, '==', 1, "Output OK");
71 close NC; 91 close NC;
72 92
73 open(NC, "echo 'SSH-2.0-3.2.9.1' | nc ${nc_flags}|"); 93 open(NC, "echo 'SSH-2.0-3.2.9.1' | nc ${nc_flags}|");
74 sleep 0.1; 94 sleep 0.1;
75 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 95 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
76 cmp_ok( $res->return_code, "==", 0, "Got SSH protocol version control string with non-alpha softwareversion string"); 96 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
77 like( $res->output, '/^SSH OK - 3.2.9.1 \(protocol 2.0\)/', "Output OK for non-alpha softwareversion string"); 97 $output = decode_json($result->output);
98 is($output->{'state'}, "OK", "State was correct");
99
100 $found_version = 0;
101 for my $subcheck (@{$output->{'checks'}}) {
102 if ($subcheck->{'output'} =~ /3.2.9.1 \(protocol version: 2.0\)/ ){
103 $found_version = 1;
104 }
105 }
106 cmp_ok($found_version, '==', 1, "Output OK");
78 close NC; 107 close NC;
79 108
80 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1 this is a comment' | nc ${nc_flags} |"); 109 open(NC, "echo 'SSH-2.0-nagiosplug.ssh.0.1 this is a comment' | nc ${nc_flags} |");
81 sleep 0.1; 110 sleep 0.1;
82 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003 -r nagiosplug.ssh.0.1" ); 111 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003 -r nagiosplug.ssh.0.1" ." ". $outputFormat);
83 cmp_ok( $res->return_code, '==', 0, "Got SSH protocol version control string, and parsed comment appropriately"); 112 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
84 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.1 \(protocol 2.0\)/', "Output OK"); 113 $output = decode_json($result->output);
114 is($output->{'state'}, "OK", "State was correct");
115
116 # looking for the version
117 $found_version = 0;
118 for my $subcheck (@{$output->{'checks'}}) {
119 if ($subcheck->{'output'} =~ /nagiosplug.ssh.0.1 \(protocol version: 2.0\)/ ){
120 $found_version = 1;
121 }
122 }
123 cmp_ok($found_version, '==', 1, "Output OK");
85 close NC; 124 close NC;
86 125
87 open(NC, "echo 'SSH-' | nc ${nc_flags}|"); 126 open(NC, "echo 'SSH-' | nc ${nc_flags}|");
88 sleep 0.1; 127 sleep 0.1;
89 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 128 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
90 cmp_ok( $res->return_code, '==', 2, "Got invalid SSH protocol version control string"); 129 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
91 like( $res->output, '/^SSH CRITICAL/', "Output OK"); 130 $output = decode_json($result->output);
131 is($output->{'state'}, "CRITICAL", "Got invalid SSH protocol version control string");
92 close NC; 132 close NC;
93 133
94 open(NC, "echo '' | nc ${nc_flags}|"); 134 open(NC, "echo '' | nc ${nc_flags}|");
95 sleep 0.1; 135 sleep 0.1;
96 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 136 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
97 cmp_ok( $res->return_code, '==', 2, "No version control string received"); 137 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
98 like( $res->output, '/^SSH CRITICAL - No version control string received/', "Output OK"); 138 $output = decode_json($result->output);
139 is($output->{'state'}, "CRITICAL", "No version control string received");
99 close NC; 140 close NC;
100 141
101 open(NC, "echo 'Not a version control string' | nc ${nc_flags}|"); 142 open(NC, "echo 'Not a version control string' | nc ${nc_flags}|");
102 sleep 0.1; 143 sleep 0.1;
103 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 144 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
104 cmp_ok( $res->return_code, '==', 2, "No version control string received"); 145 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
105 like( $res->output, '/^SSH CRITICAL - No version control string received/', "Output OK"); 146 $output = decode_json($result->output);
147 is($output->{'state'}, "CRITICAL", "No version control string received");
106 close NC; 148 close NC;
107 149
108 150
@@ -116,8 +158,18 @@ SKIP: {
116 echo 'Some\nPrepended\nData\nLines\n'; sleep 0.2; 158 echo 'Some\nPrepended\nData\nLines\n'; sleep 0.2;
117 echo 'SSH-2.0-nagiosplug.ssh.0.2';} | nc ${nc_flags}|"); 159 echo 'SSH-2.0-nagiosplug.ssh.0.2';} | nc ${nc_flags}|");
118 sleep 0.1; 160 sleep 0.1;
119 $res = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ); 161 $result = NPTest->testCmd( "./check_ssh -H localhost -p 5003" ." ". $outputFormat);
120 cmp_ok( $res->return_code, '==', 0, "Got delayed SSH protocol version control string"); 162 cmp_ok($result->return_code, '==', 0, "Exit with return code 0 (OK)");
121 like( $res->output, '/^SSH OK - nagiosplug.ssh.0.2 \(protocol 2.0\)/', "Output OK"); 163 $output = decode_json($result->output);
164 is($output->{'state'}, "OK", "State was correct");
165
166 # looking for the version
167 $found_version = 0;
168 for my $subcheck (@{$output->{'checks'}}) {
169 if ($subcheck->{'output'} =~ /nagiosplug.ssh.0.2 \(protocol version: 2.0\)/ ){
170 $found_version = 1;
171 }
172 }
173 cmp_ok($found_version, '==', 1, "Output OK");
122 close NC; 174 close NC;
123} 175}
diff --git a/plugins/t/check_swap.t b/plugins/t/check_swap.t
index 18780386..68946f6d 100644
--- a/plugins/t/check_swap.t
+++ b/plugins/t/check_swap.t
@@ -5,39 +5,47 @@
5# 5#
6 6
7use strict; 7use strict;
8use Test::More tests => 14; 8use warnings;
9use Test::More tests => 21;
9use NPTest; 10use NPTest;
10 11use JSON;
11my $successOutput = '/^SWAP OK - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
12my $failureOutput = '/^SWAP CRITICAL - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
13my $warnOutput = '/^SWAP WARNING - [0-9]+\% free \([0-9]+MB out of [0-9]+MB\)/';
14 12
15my $result; 13my $result;
14my $outputFormat = '--output-format mp-test-json';
15my $output;
16my $message = '/^[0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
16 17
17$result = NPTest->testCmd( "./check_swap" ); # Always OK 18$result = NPTest->testCmd( "./check_swap $outputFormat" ); # Always OK
18cmp_ok( $result->return_code, "==", 0, "Always OK" ); 19cmp_ok( $result->return_code, "==", 0, "Always OK" );
19like( $result->output, $successOutput, "Right output" ); 20is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
21like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
20 22
21$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576" ); # 1 MB free 23$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576 $outputFormat" ); # 1 MB free
22cmp_ok( $result->return_code, "==", 0, "At least 1MB free" ); 24cmp_ok( $result->return_code, "==", 0, "Always OK" );
23like( $result->output, $successOutput, "Right output" ); 25is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
26like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
24 27
25$result = NPTest->testCmd( "./check_swap -w 1% -c 1%" ); # 1% free 28$result = NPTest->testCmd( "./check_swap -w 1% -c 1% $outputFormat" ); # 1% free
26cmp_ok( $result->return_code, "==", 0, 'At least 1% free' ); 29cmp_ok( $result->return_code, "==", 0, "Always OK" );
27like( $result->output, $successOutput, "Right output" ); 30is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
31like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
28 32
29$result = NPTest->testCmd( "./check_swap -w 100% -c 100%" ); # 100% (always critical) 33$result = NPTest->testCmd( "./check_swap -w 100% -c 100% $outputFormat" ); # 100% (always critical)
30cmp_ok( $result->return_code, "==", 2, 'Get critical because not 100% free' ); 34cmp_ok( $result->return_code, "==", 0, "Always OK" );
31like( $result->output, $failureOutput, "Right output" ); 35is($result->{'mp_test_result'}->{'state'}, "CRITICAL", "State was correct");
36like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
32 37
33$result = NPTest->testCmd( "./check_swap -w 100% -c 1%" ); # 100% (always warn) 38$result = NPTest->testCmd( "./check_swap -w 100% -c 1% $outputFormat" ); # 100% (always warn)
34cmp_ok( $result->return_code, "==", 1, 'Get warning because not 100% free' ); 39cmp_ok( $result->return_code, "==", 0, "Always OK" );
35like( $result->output, $warnOutput, "Right output" ); 40is($result->{'mp_test_result'}->{'state'}, "WARNING", "State was correct");
41like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
36 42
37$result = NPTest->testCmd( "./check_swap -w 100%" ); # 100% (single threshold, always warn) 43$result = NPTest->testCmd( "./check_swap -w 100% $outputFormat" ); # 100% (single threshold, always warn)
38cmp_ok( $result->return_code, "==", 1, 'Get warning because not 100% free' ); 44cmp_ok( $result->return_code, "==", 0, "Always OK" );
39like( $result->output, $warnOutput, "Right output" ); 45is($result->{'mp_test_result'}->{'state'}, "WARNING", "State was correct");
46like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
40 47
41$result = NPTest->testCmd( "./check_swap -c 100%" ); # 100% (single threshold, always critical) 48$result = NPTest->testCmd( "./check_swap -c 100% $outputFormat" ); # 100% (single threshold, always critical)
42cmp_ok( $result->return_code, "==", 2, 'Get critical because not 100% free' ); 49cmp_ok( $result->return_code, "==", 0, "Always OK" );
43like( $result->output, $failureOutput, "Right output" ); 50is($result->{'mp_test_result'}->{'state'}, "CRITICAL", "State was correct");
51like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
diff --git a/plugins/t/check_tcp.t b/plugins/t/check_tcp.t
index cb4de53d..5c8fd0be 100644
--- a/plugins/t/check_tcp.t
+++ b/plugins/t/check_tcp.t
@@ -21,19 +21,19 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes"); 22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
23 23
24my $successOutput = '/^TCP OK\s-\s+[0-9]?\.?[0-9]+ second response time on port [0-9]+/'; 24my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+s is within thresholds+/';
25 25
26my $failedExpect = '/^TCP WARNING\s-\sUnexpected response from host/socket on port [0-9]+/'; 26my $failedExpect = '/Answer failed to match/';
27 27
28my $t; 28my $t;
29 29
30$tests = $tests - 4 if $internet_access eq "no"; 30$tests = $tests - 4 if $internet_access eq "no";
31plan tests => $tests; 31plan tests => $tests;
32 32
33$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -wt 300 -ct 600", 0, $successOutput ); 33$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -w 300 -c 600", 0, $successOutput );
34$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -wt 0 -ct 0 -to 1", 2 ); # use invalid port for this test 34$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -w 0 -c 0 -t 1", 2 ); # use invalid port for this test
35$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -wt 0 -ct 0 -to 1", 2 ); 35$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -w 0 -c 0 -t 1", 2 );
36$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -wt 0 -ct 0 -to 1", 2 ); 36$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -w 0 -c 0 -t 1", 2 );
37if($internet_access ne "no") { 37if($internet_access ne "no") {
38 $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 ); 38 $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 );
39 $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 ); 39 $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 );
diff --git a/plugins/t/check_udp.t b/plugins/t/check_udp.t
index 6c47d095..5cb9e6dc 100644
--- a/plugins/t/check_udp.t
+++ b/plugins/t/check_udp.t
@@ -28,7 +28,7 @@ like ( $res->output, '/With UDP checks, a send/expect string must be specified.
28 28
29$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" ); 29$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" );
30cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" ); 30cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" );
31like ( $res->output, '/No data received from host/', "Output OK"); 31like ( $res->output, '/Received no data /', "Output OK");
32 32
33my $nc; 33my $nc;
34if(system("which nc.traditional >/dev/null 2>&1") == 0) { 34if(system("which nc.traditional >/dev/null 2>&1") == 0) {
@@ -48,7 +48,7 @@ SKIP: {
48 sleep 1; 48 sleep 1;
49 $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" ); 49 $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" );
50 cmp_ok( $res->return_code, '==', 0, "Got barbar response back" ); 50 cmp_ok( $res->return_code, '==', 0, "Got barbar response back" );
51 like ( $res->output, '/\[barbar\]/', "Output OK"); 51 like ( $res->output, '/answer of the server matched/', "Output OK");
52 close NC; 52 close NC;
53 53
54 # Start up a udp server listening on port 3333, quit after 3 seconds 54 # Start up a udp server listening on port 3333, quit after 3 seconds
diff --git a/plugins/tests/test_check_disk.c b/plugins/tests/test_check_disk.c
new file mode 100644
index 00000000..35c57bce
--- /dev/null
+++ b/plugins/tests/test_check_disk.c
@@ -0,0 +1,197 @@
1/*****************************************************************************
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 *
17 *****************************************************************************/
18
19#include "common.h"
20#include "../check_disk.d/utils_disk.h"
21#include "../../tap/tap.h"
22#include "regex.h"
23
24void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc);
25
26int main(int argc, char **argv) {
27 plan_tests(35);
28
29 struct name_list *exclude_filesystem = NULL;
30 ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
31 np_add_name(&exclude_filesystem, "/var/log");
32 ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
33 ok(np_find_name(exclude_filesystem, "/home") == false, "/home not in list");
34 np_add_name(&exclude_filesystem, "/home");
35 ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now");
36 ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
37
38 struct name_list *exclude_fstype = NULL;
39 ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
40 np_add_name(&exclude_fstype, "iso9660");
41 ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
42
43 ok(np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables");
44
45 /*
46 for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) {
47 printf("Name: %s\n", temp_name->name);
48 }
49 */
50
51 struct mount_entry *dummy_mount_list;
52 struct mount_entry **mtail = &dummy_mount_list;
53 struct mount_entry *me = (struct mount_entry *)malloc(sizeof *me);
54 me->me_devname = strdup("/dev/c0t0d0s0");
55 me->me_mountdir = strdup("/");
56 *mtail = me;
57 mtail = &me->me_next;
58
59 me = (struct mount_entry *)malloc(sizeof *me);
60 me->me_devname = strdup("/dev/c1t0d1s0");
61 me->me_mountdir = strdup("/var");
62 *mtail = me;
63 mtail = &me->me_next;
64
65 me = (struct mount_entry *)malloc(sizeof *me);
66 me->me_devname = strdup("/dev/c2t0d0s0");
67 me->me_mountdir = strdup("/home");
68 *mtail = me;
69 mtail = &me->me_next;
70
71 int cflags = REG_NOSUB | REG_EXTENDED;
72 np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a"));
73 np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3, strdup("regex on dev names:"));
74 np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0, strdup("regex on non existent dev/path:"));
75 np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0, strdup("regi on non existent dev/path:"));
76 np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3, strdup("partial devname regex match:"));
77 np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1, strdup("partial devname regex match:"));
78 np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1, strdup("partial devname regi match:"));
79 np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1, strdup("partial pathname regex match:"));
80 np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1, strdup("partial pathname regi match:"));
81 np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2, strdup("grouped regex pathname match:"));
82 np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:"));
83
84 filesystem_list test_paths = filesystem_list_init();
85 mp_int_fs_list_append(&test_paths, "/home/groups");
86 mp_int_fs_list_append(&test_paths, "/var");
87 mp_int_fs_list_append(&test_paths, "/tmp");
88 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
89 mp_int_fs_list_append(&test_paths, "/dev/c2t0d0s0");
90 ok(test_paths.length == 5, "List counter works correctly with appends");
91
92 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, false);
93 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
94 struct mount_entry *temp_me;
95 temp_me = p->best_match;
96 if (!strcmp(p->name, "/home/groups")) {
97 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home");
98 } else if (!strcmp(p->name, "/var")) {
99 ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var");
100 } else if (!strcmp(p->name, "/tmp")) {
101 ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /");
102 } else if (!strcmp(p->name, "/home/tonvoon")) {
103 ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home");
104 } else if (!strcmp(p->name, "/dev/c2t0d0s0")) {
105 ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0");
106 }
107 }
108
109 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
110 mp_int_fs_list_del(&test_paths, p);
111 }
112 ok(test_paths.length == 0, "List delete sets counter properly");
113
114 mp_int_fs_list_append(&test_paths, "/home/groups");
115 mp_int_fs_list_append(&test_paths, "/var");
116 mp_int_fs_list_append(&test_paths, "/tmp");
117 mp_int_fs_list_append(&test_paths, "/home/tonvoon");
118 mp_int_fs_list_append(&test_paths, "/home");
119
120 mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, true);
121 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
122 if (!strcmp(p->name, "/home/groups")) {
123 ok(!p->best_match, "/home/groups correctly not found");
124 } else if (!strcmp(p->name, "/var")) {
125 ok(p->best_match, "/var found");
126 } else if (!strcmp(p->name, "/tmp")) {
127 ok(!p->best_match, "/tmp correctly not found");
128 } else if (!strcmp(p->name, "/home/tonvoon")) {
129 ok(!p->best_match, "/home/tonvoon not found");
130 } else if (!strcmp(p->name, "/home")) {
131 ok(p->best_match, "/home found");
132 }
133 }
134
135 bool found = false;
136 /* test deleting first element in paths */
137 mp_int_fs_list_del(&test_paths, NULL);
138 for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
139 if (!strcmp(p->name, "/home/groups")) {
140 found = true;
141 }
142 }
143 ok(!found, "first element successfully deleted");
144 found = false;
145
146 parameter_list_elem *prev = NULL;
147 parameter_list_elem *p = NULL;
148 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
149 if (!strcmp(path->name, "/tmp")) {
150 mp_int_fs_list_del(&test_paths, path);
151 }
152 p = path;
153 }
154
155 parameter_list_elem *last = NULL;
156 for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
157 if (!strcmp(path->name, "/tmp")) {
158 found = true;
159 }
160 if (path->next) {
161 prev = path;
162 } else {
163 last = path;
164 }
165 }
166 ok(!found, "/tmp element successfully deleted");
167
168 int count = 0;
169 mp_int_fs_list_del(&test_paths, p);
170 for (p = test_paths.first; p; p = p->next) {
171 if (!strcmp(p->name, "/home")) {
172 found = true;
173 }
174 last = p;
175 count++;
176 }
177 ok(!found, "last (/home) element successfully deleted");
178 ok(count == 2, "two elements remaining");
179
180 return exit_status();
181}
182
183void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) {
184 regex_t regex;
185 if (regcomp(&regex, regstr, cflags) == 0) {
186 int matches = 0;
187 for (struct mount_entry *me = dummy_mount_list; me; me = me->me_next) {
188 if (np_regex_match_mount_entry(me, &regex)) {
189 matches++;
190 }
191 }
192 ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches);
193
194 } else {
195 ok(false, "regex '%s' not compilable", regstr);
196 }
197}
diff --git a/plugins/tests/test_check_disk.t b/plugins/tests/test_check_disk.t
new file mode 100755
index 00000000..56354650
--- /dev/null
+++ b/plugins/tests/test_check_disk.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_disk") {
4 plan skip_all => "./test_check_disk not compiled - please enable libtap library to test";
5}
6exec "./test_check_disk";
diff --git a/plugins/tests/test_check_swap.c b/plugins/tests/test_check_swap.c
new file mode 100644
index 00000000..b85fb4ad
--- /dev/null
+++ b/plugins/tests/test_check_swap.c
@@ -0,0 +1,23 @@
1
2#include "../check_swap.d/check_swap.h"
3#include "../../tap/tap.h"
4
5int verbose = 0;
6
7void print_usage(void) {}
8void print_help(swap_config config) {
9 (void) config;
10}
11
12const char *progname = "test_check_swap";
13
14int main(void) {
15 swap_result test_data = getSwapFromProcMeminfo("./var/proc_meminfo");
16
17 plan_tests(4);
18
19 ok(test_data.errorcode == 0, "Test whether we manage to retrieve swap data");
20 ok(test_data.metrics.total == 34233905152, "Is the total Swap correct");
21 ok(test_data.metrics.free == 34233905152, "Is the free Swap correct");
22 ok(test_data.metrics.used == 0, "Is the used Swap correct");
23}
diff --git a/plugins/tests/test_check_swap.t b/plugins/tests/test_check_swap.t
new file mode 100755
index 00000000..826fae01
--- /dev/null
+++ b/plugins/tests/test_check_swap.t
@@ -0,0 +1,6 @@
1#!/usr/bin/perl
2use Test::More;
3if (! -e "./test_check_swap") {
4 plan skip_all => "./test_check_swap not compiled - please enable libtap library to test";
5}
6exec "./test_check_swap";
diff --git a/plugins/tests/var/proc_meminfo b/plugins/tests/var/proc_meminfo
new file mode 100644
index 00000000..6c5a618d
--- /dev/null
+++ b/plugins/tests/var/proc_meminfo
@@ -0,0 +1,55 @@
1MemTotal: 32767776 kB
2MemFree: 1693508 kB
3MemAvailable: 23807480 kB
4Buffers: 438456 kB
5Cached: 19124976 kB
6SwapCached: 0 kB
7Active: 7860680 kB
8Inactive: 18886776 kB
9Active(anon): 6108756 kB
10Inactive(anon): 1364500 kB
11Active(file): 1751924 kB
12Inactive(file): 17522276 kB
13Unevictable: 8548 kB
14Mlocked: 8548 kB
15SwapTotal: 33431548 kB
16SwapFree: 33431548 kB
17Zswap: 0 kB
18Zswapped: 0 kB
19Dirty: 784 kB
20Writeback: 0 kB
21AnonPages: 7139968 kB
22Mapped: 1094916 kB
23Shmem: 284160 kB
24KReclaimable: 3303788 kB
25Slab: 3801908 kB
26SReclaimable: 3303788 kB
27SUnreclaim: 498120 kB
28KernelStack: 32992 kB
29PageTables: 68160 kB
30SecPageTables: 0 kB
31NFS_Unstable: 0 kB
32Bounce: 0 kB
33WritebackTmp: 0 kB
34CommitLimit: 49815436 kB
35Committed_AS: 16888536 kB
36VmallocTotal: 34359738367 kB
37VmallocUsed: 91200 kB
38VmallocChunk: 0 kB
39Percpu: 41472 kB
40HardwareCorrupted: 0 kB
41AnonHugePages: 1708032 kB
42ShmemHugePages: 0 kB
43ShmemPmdMapped: 0 kB
44FileHugePages: 0 kB
45FilePmdMapped: 0 kB
46Unaccepted: 0 kB
47HugePages_Total: 0
48HugePages_Free: 0
49HugePages_Rsvd: 0
50HugePages_Surp: 0
51Hugepagesize: 2048 kB
52Hugetlb: 0 kB
53DirectMap4k: 860468 kB
54DirectMap2M: 20023296 kB
55DirectMap1G: 12582912 kB
diff --git a/plugins/urlize.c b/plugins/urlize.c
index 6fda72d1..1aa4e425 100644
--- a/plugins/urlize.c
+++ b/plugins/urlize.c
@@ -1,51 +1,49 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring urlize plugin 3 * Monitoring urlize plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the urlize plugin 10 * This file contains the urlize plugin
11* 11 *
12* This plugin wraps the text output of another command (plugin) in HTML <A> 12 * This plugin wraps the text output of another command (plugin) in HTML <A>
13* tags. This plugin returns the status of the invoked plugin. 13 * tags. This plugin returns the status of the invoked plugin.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "urlize"; 32const char *progname = "urlize";
33const char *copyright = "2000-2006"; 33const char *copyright = "2000-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "common.h" 36#include "common.h"
37#include "utils.h" 37#include "utils.h"
38#include "popen.h" 38#include "popen.h"
39 39
40#define PERF_CHARACTER "|" 40#define PERF_CHARACTER "|"
41#define NEWLINE_CHARACTER '\n' 41#define NEWLINE_CHARACTER '\n'
42 42
43void print_help (void); 43void print_help(void);
44void print_usage (void); 44void print_usage(void);
45 45
46int 46int main(int argc, char **argv) {
47main (int argc, char **argv)
48{
49 int found = 0, result = STATE_UNKNOWN; 47 int found = 0, result = STATE_UNKNOWN;
50 char *url = NULL; 48 char *url = NULL;
51 char *cmd; 49 char *cmd;
@@ -56,79 +54,72 @@ main (int argc, char **argv)
56 int c; 54 int c;
57 int option = 0; 55 int option = 0;
58 static struct option longopts[] = { 56 static struct option longopts[] = {
59 {"help", no_argument, 0, 'h'}, 57 {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"url", required_argument, 0, 'u'}, {0, 0, 0, 0}};
60 {"version", no_argument, 0, 'V'},
61 {"url", required_argument, 0, 'u'},
62 {0, 0, 0, 0}
63 };
64 58
65 setlocale (LC_ALL, ""); 59 setlocale(LC_ALL, "");
66 bindtextdomain (PACKAGE, LOCALEDIR); 60 bindtextdomain(PACKAGE, LOCALEDIR);
67 textdomain (PACKAGE); 61 textdomain(PACKAGE);
68 62
69 /* Need at least 2 args */ 63 /* Need at least 2 args */
70 if (argc < 3) { 64 if (argc < 3) {
71 print_help(); 65 print_help();
72 exit (STATE_UNKNOWN); 66 exit(STATE_UNKNOWN);
73 } 67 }
74 68
75 while (1) { 69 while (1) {
76 c = getopt_long (argc, argv, "+hVu:", longopts, &option); 70 c = getopt_long(argc, argv, "+hVu:", longopts, &option);
77 71
78 if (c == -1 || c == EOF) 72 if (c == -1 || c == EOF)
79 break; 73 break;
80 74
81 switch (c) { 75 switch (c) {
82 case 'h': /* help */ 76 case 'h': /* help */
83 print_help (); 77 print_help();
84 exit (EXIT_SUCCESS); 78 exit(EXIT_SUCCESS);
85 break; 79 break;
86 case 'V': /* version */ 80 case 'V': /* version */
87 print_revision (progname, NP_VERSION); 81 print_revision(progname, NP_VERSION);
88 exit (EXIT_SUCCESS); 82 exit(EXIT_SUCCESS);
89 break; 83 break;
90 case 'u': 84 case 'u':
91 url = strdup (argv[optind]); 85 url = strdup(argv[optind]);
92 break; 86 break;
93 case '?': 87 case '?':
94 default: 88 default:
95 usage5 (); 89 usage5();
96 } 90 }
97 } 91 }
98 92
99 if (url == NULL) 93 if (url == NULL)
100 url = strdup (argv[optind++]); 94 url = strdup(argv[optind++]);
101 95
102 cmd = strdup (argv[optind++]); 96 cmd = strdup(argv[optind++]);
103 for (c = optind; c < argc; c++) { 97 for (c = optind; c < argc; c++) {
104 xasprintf (&cmd, "%s %s", cmd, argv[c]); 98 xasprintf(&cmd, "%s %s", cmd, argv[c]);
105 } 99 }
106 100
107 child_process = spopen (cmd); 101 child_process = spopen(cmd);
108 if (child_process == NULL) { 102 if (child_process == NULL) {
109 printf (_("Could not open pipe: %s\n"), cmd); 103 printf(_("Could not open pipe: %s\n"), cmd);
110 exit (STATE_UNKNOWN); 104 exit(STATE_UNKNOWN);
111 } 105 }
112 106
113 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r"); 107 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
114 if (child_stderr == NULL) { 108 if (child_stderr == NULL) {
115 printf (_("Could not open stderr for %s\n"), cmd); 109 printf(_("Could not open stderr for %s\n"), cmd);
116 } 110 }
117 111
118 bzero(tstr, sizeof(tstr)); 112 bzero(tstr, sizeof(tstr));
119 buf = malloc(MAX_INPUT_BUFFER); 113 buf = malloc(MAX_INPUT_BUFFER);
120 printf ("<A href=\"%s\">", argv[1]); 114 printf("<A href=\"%s\">", argv[1]);
121 while (fgets (buf, MAX_INPUT_BUFFER - 1, child_process)) { 115 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
122 found++; 116 found++;
123 /* Collect the string in temp str so we can tokenize */ 117 /* Collect the string in temp str so we can tokenize */
124 strcat(tstr, buf); 118 strcat(tstr, buf);
125 } 119 }
126 120
127 if (!found) 121 if (!found)
128 die (STATE_UNKNOWN, 122 die(STATE_UNKNOWN, _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"), argv[0], cmd);
129 _("%s UNKNOWN - No data received from host\nCMD: %s</A>\n"),
130 argv[0], cmd);
131
132 123
133 /* chop the newline character */ 124 /* chop the newline character */
134 if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL) 125 if ((nstr = strchr(tstr, NEWLINE_CHARACTER)) != NULL)
@@ -136,63 +127,55 @@ main (int argc, char **argv)
136 127
137 /* tokenize the string for Perfdata if there is some */ 128 /* tokenize the string for Perfdata if there is some */
138 nstr = strtok(tstr, PERF_CHARACTER); 129 nstr = strtok(tstr, PERF_CHARACTER);
139 printf ("%s", nstr); 130 printf("%s", nstr);
140 printf ("</A>"); 131 printf("</A>");
141 nstr = strtok(NULL, PERF_CHARACTER); 132 nstr = strtok(NULL, PERF_CHARACTER);
142 if (nstr != NULL) 133 if (nstr != NULL)
143 printf (" | %s", nstr); 134 printf(" | %s", nstr);
144 135
145 /* close the pipe */ 136 /* close the pipe */
146 result = spclose (child_process); 137 result = spclose(child_process);
147 138
148 /* WARNING if output found on stderr */ 139 /* WARNING if output found on stderr */
149 if (fgets (buf, MAX_INPUT_BUFFER - 1, child_stderr)) 140 if (fgets(buf, MAX_INPUT_BUFFER - 1, child_stderr))
150 result = max_state (result, STATE_WARNING); 141 result = max_state(result, STATE_WARNING);
151 142
152 /* close stderr */ 143 /* close stderr */
153 (void) fclose (child_stderr); 144 (void)fclose(child_stderr);
154 145
155 return result; 146 return result;
156} 147}
157 148
149void print_help(void) {
150 print_revision(progname, NP_VERSION);
158 151
152 printf("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
153 printf(COPYRIGHT, copyright, email);
159 154
160void 155 printf("%s\n", _("This plugin wraps the text output of another command (plugin) in HTML <A>"));
161print_help (void) 156 printf("%s\n", _("tags, thus displaying the child plugin's output as a clickable link in compatible"));
162{ 157 printf("%s\n", _("monitoring status screen. This plugin returns the status of the invoked plugin."));
163 print_revision (progname, NP_VERSION);
164
165 printf ("Copyright (c) 2000 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
166 printf (COPYRIGHT, copyright, email);
167
168 printf ("%s\n", _("This plugin wraps the text output of another command (plugin) in HTML <A>"));
169 printf ("%s\n", _("tags, thus displaying the child plugin's output as a clickable link in compatible"));
170 printf ("%s\n", _("monitoring status screen. This plugin returns the status of the invoked plugin."));
171 158
172 printf ("\n\n"); 159 printf("\n\n");
173 160
174 print_usage (); 161 print_usage();
175 162
176 printf (UT_HELP_VRSN); 163 printf(UT_HELP_VRSN);
177 164
178 printf ("\n"); 165 printf("\n");
179 printf ("%s\n", _("Examples:")); 166 printf("%s\n", _("Examples:"));
180 printf ("%s\n", _("Pay close attention to quoting to ensure that the shell passes the expected")); 167 printf("%s\n", _("Pay close attention to quoting to ensure that the shell passes the expected"));
181 printf ("%s\n\n", _("data to the plugin. For example, in:")); 168 printf("%s\n\n", _("data to the plugin. For example, in:"));
182 printf (" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'")); 169 printf(" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r 'two words'"));
183 printf (" %s\n", _("the shell will remove the single quotes and urlize will see:")); 170 printf(" %s\n", _("the shell will remove the single quotes and urlize will see:"));
184 printf (" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r two words")); 171 printf(" %s\n\n", _("urlize http://example.com/ check_http -H example.com -r two words"));
185 printf (" %s\n\n", _("You probably want:")); 172 printf(" %s\n\n", _("You probably want:"));
186 printf (" %s\n", _("urlize http://example.com/ \"check_http -H example.com -r 'two words'\"")); 173 printf(" %s\n", _("urlize http://example.com/ \"check_http -H example.com -r 'two words'\""));
187 174
188 printf (UT_SUPPORT); 175 printf(UT_SUPPORT);
189} 176}
190 177
191 178void print_usage(void) {
192 179 printf("%s\n", _("Usage:"));
193void 180 printf("%s <url> <plugin> <arg1> ... <argN>\n", progname);
194print_usage (void)
195{
196 printf ("%s\n", _("Usage:"));
197 printf ("%s <url> <plugin> <arg1> ... <argN>\n", progname);
198} 181}
diff --git a/plugins/utils.c b/plugins/utils.c
index 77d6a6f9..34335c89 100644
--- a/plugins/utils.c
+++ b/plugins/utils.c
@@ -1,26 +1,26 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Library of useful functions for plugins 3 * Library of useful functions for plugins
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net) 6 * Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net)
7* Copyright (c) 2002-2007 Monitoring Plugins Development Team 7 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
8* 8 *
9* This program is free software: you can redistribute it and/or modify 9 * This program is free software: you can redistribute it and/or modify
10* it under the terms of the GNU General Public License as published by 10 * it under the terms of the GNU General Public License as published by
11* the Free Software Foundation, either version 3 of the License, or 11 * the Free Software Foundation, either version 3 of the License, or
12* (at your option) any later version. 12 * (at your option) any later version.
13* 13 *
14* This program is distributed in the hope that it will be useful, 14 * This program is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17* GNU General Public License for more details. 17 * GNU General Public License for more details.
18* 18 *
19* You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
20* along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21* 21 *
22* 22 *
23*****************************************************************************/ 23 *****************************************************************************/
24 24
25#include "common.h" 25#include "common.h"
26#include "./utils.h" 26#include "./utils.h"
@@ -34,7 +34,7 @@
34 34
35#include <arpa/inet.h> 35#include <arpa/inet.h>
36 36
37extern void print_usage (void); 37extern void print_usage(void);
38extern const char *progname; 38extern const char *progname;
39 39
40#define STRLEN 64 40#define STRLEN 64
@@ -42,173 +42,114 @@ extern const char *progname;
42 42
43time_t start_time, end_time; 43time_t start_time, end_time;
44 44
45/* ************************************************************************** 45void usage(const char *msg) {
46 * max_state(STATE_x, STATE_y) 46 printf("%s\n", msg);
47 * compares STATE_x to STATE_y and returns result based on the following 47 print_usage();
48 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL 48 exit(STATE_UNKNOWN);
49 * 49}
50 * Note that numerically the above does not hold 50
51 ****************************************************************************/ 51void usage_va(const char *fmt, ...) {
52
53int
54max_state (int a, int b)
55{
56 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
57 return STATE_CRITICAL;
58 else if (a == STATE_WARNING || b == STATE_WARNING)
59 return STATE_WARNING;
60 else if (a == STATE_OK || b == STATE_OK)
61 return STATE_OK;
62 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
63 return STATE_UNKNOWN;
64 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
65 return STATE_DEPENDENT;
66 else
67 return max (a, b);
68}
69
70/* **************************************************************************
71 * max_state_alt(STATE_x, STATE_y)
72 * compares STATE_x to STATE_y and returns result based on the following
73 * STATE_OK < STATE_DEPENDENT < STATE_UNKNOWN < STATE_WARNING < STATE_CRITICAL
74 *
75 * The main difference between max_state_alt and max_state it that it doesn't
76 * allow setting a default to UNKNOWN. It will instead prioritixe any valid
77 * non-OK state.
78 ****************************************************************************/
79
80int
81max_state_alt (int a, int b)
82{
83 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
84 return STATE_CRITICAL;
85 else if (a == STATE_WARNING || b == STATE_WARNING)
86 return STATE_WARNING;
87 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
88 return STATE_UNKNOWN;
89 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
90 return STATE_DEPENDENT;
91 else if (a == STATE_OK || b == STATE_OK)
92 return STATE_OK;
93 else
94 return max (a, b);
95}
96
97void usage (const char *msg)
98{
99 printf ("%s\n", msg);
100 print_usage ();
101 exit (STATE_UNKNOWN);
102}
103
104void usage_va (const char *fmt, ...)
105{
106 va_list ap; 52 va_list ap;
107 printf("%s: ", progname); 53 printf("%s: ", progname);
108 va_start(ap, fmt); 54 va_start(ap, fmt);
109 vprintf(fmt, ap); 55 vprintf(fmt, ap);
110 va_end(ap); 56 va_end(ap);
111 printf("\n"); 57 printf("\n");
112 exit (STATE_UNKNOWN); 58 exit(STATE_UNKNOWN);
113} 59}
114 60
115void usage2(const char *msg, const char *arg) 61void usage2(const char *msg, const char *arg) {
116{ 62 printf("%s: %s - %s\n", progname, msg, arg ? arg : "(null)");
117 printf ("%s: %s - %s\n", progname, msg, arg?arg:"(null)" ); 63 print_usage();
118 print_usage (); 64 exit(STATE_UNKNOWN);
119 exit (STATE_UNKNOWN);
120} 65}
121 66
122void 67void usage3(const char *msg, int arg) {
123usage3 (const char *msg, int arg) 68 printf("%s: %s - %c\n", progname, msg, arg);
124{
125 printf ("%s: %s - %c\n", progname, msg, arg);
126 print_usage(); 69 print_usage();
127 exit (STATE_UNKNOWN); 70 exit(STATE_UNKNOWN);
128} 71}
129 72
130void 73void usage4(const char *msg) {
131usage4 (const char *msg) 74 printf("%s: %s\n", progname, msg);
132{
133 printf ("%s: %s\n", progname, msg);
134 print_usage(); 75 print_usage();
135 exit (STATE_UNKNOWN); 76 exit(STATE_UNKNOWN);
136} 77}
137 78
138void 79void usage5(void) {
139usage5 (void)
140{
141 print_usage(); 80 print_usage();
142 exit (STATE_UNKNOWN); 81 exit(STATE_UNKNOWN);
143} 82}
144 83
145void 84void print_revision(const char *command_name, const char *revision) {
146print_revision (const char *command_name, const char *revision) 85 printf("%s v%s (%s %s)\n", command_name, revision, PACKAGE, VERSION);
147{
148 printf ("%s v%s (%s %s)\n",
149 command_name, revision, PACKAGE, VERSION);
150} 86}
151 87
152bool is_numeric (char *number) { 88bool is_numeric(char *number) {
153 char tmp[1]; 89 char tmp[1];
154 float x; 90 float x;
155 91
156 if (!number) 92 if (!number) {
157 return false; 93 return false;
158 else if (sscanf (number, "%f%c", &x, tmp) == 1) 94 } else if (sscanf(number, "%f%c", &x, tmp) == 1) {
159 return true; 95 return true;
160 else 96 } else {
161 return false; 97 return false;
98 }
162} 99}
163 100
164bool is_positive (char *number) { 101bool is_positive(char *number) {
165 if (is_numeric (number) && atof (number) > 0.0) 102 if (is_numeric(number) && atof(number) > 0.0) {
166 return true; 103 return true;
167 else 104 } else {
168 return false; 105 return false;
106 }
169} 107}
170 108
171bool is_negative (char *number) { 109bool is_negative(char *number) {
172 if (is_numeric (number) && atof (number) < 0.0) 110 if (is_numeric(number) && atof(number) < 0.0) {
173 return true; 111 return true;
174 else 112 } else {
175 return false; 113 return false;
114 }
176} 115}
177 116
178bool is_nonnegative (char *number) { 117bool is_nonnegative(char *number) {
179 if (is_numeric (number) && atof (number) >= 0.0) 118 if (is_numeric(number) && atof(number) >= 0.0) {
180 return true; 119 return true;
181 else 120 } else {
182 return false; 121 return false;
122 }
183} 123}
184 124
185bool is_percentage (char *number) { 125bool is_percentage(char *number) {
186 int x; 126 int x;
187 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100) 127 if (is_numeric(number) && (x = atof(number)) >= 0 && x <= 100) {
188 return true; 128 return true;
189 else 129 } else {
190 return false; 130 return false;
131 }
191} 132}
192 133
193bool is_percentage_expression (const char str[]) { 134bool is_percentage_expression(const char str[]) {
194 if (!str) { 135 if (!str) {
195 return false; 136 return false;
196 } 137 }
197 138
198 size_t len = strlen(str); 139 size_t len = strlen(str);
199 140
200 if (str[len-1] != '%') { 141 if (str[len - 1] != '%') {
201 return false; 142 return false;
202 } 143 }
203 144
204 char *foo = calloc(sizeof(char), len + 1); 145 char *foo = calloc(len + 1, sizeof(char));
205 146
206 if (!foo) { 147 if (!foo) {
207 die (STATE_UNKNOWN, _("calloc failed \n")); 148 die(STATE_UNKNOWN, _("calloc failed \n"));
208 } 149 }
209 150
210 strcpy(foo, str); 151 strcpy(foo, str);
211 foo[len-1] = '\0'; 152 foo[len - 1] = '\0';
212 153
213 bool result = is_numeric(foo); 154 bool result = is_numeric(foo);
214 155
@@ -217,39 +158,44 @@ bool is_percentage_expression (const char str[]) {
217 return result; 158 return result;
218} 159}
219 160
220bool is_integer (char *number) { 161bool is_integer(char *number) {
221 long int n; 162 long int n;
222 163
223 if (!number || (strspn (number, "-0123456789 ") != strlen (number))) 164 if (!number || (strspn(number, "-0123456789 ") != strlen(number))) {
224 return false; 165 return false;
166 }
225 167
226 n = strtol (number, NULL, 10); 168 n = strtol(number, NULL, 10);
227 169
228 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) 170 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) {
229 return true; 171 return true;
230 else 172 } else {
231 return false; 173 return false;
174 }
232} 175}
233 176
234bool is_intpos (char *number) { 177bool is_intpos(char *number) {
235 if (is_integer (number) && atoi (number) > 0) 178 if (is_integer(number) && atoi(number) > 0) {
236 return true; 179 return true;
237 else 180 } else {
238 return false; 181 return false;
182 }
239} 183}
240 184
241bool is_intneg (char *number) { 185bool is_intneg(char *number) {
242 if (is_integer (number) && atoi (number) < 0) 186 if (is_integer(number) && atoi(number) < 0) {
243 return true; 187 return true;
244 else 188 } else {
245 return false; 189 return false;
190 }
246} 191}
247 192
248bool is_intnonneg (char *number) { 193bool is_intnonneg(char *number) {
249 if (is_integer (number) && atoi (number) >= 0) 194 if (is_integer(number) && atoi(number) >= 0) {
250 return true; 195 return true;
251 else 196 } else {
252 return false; 197 return false;
198 }
253} 199}
254 200
255/* 201/*
@@ -259,7 +205,7 @@ bool is_intnonneg (char *number) {
259 */ 205 */
260bool is_int64(char *number, int64_t *target) { 206bool is_int64(char *number, int64_t *target) {
261 errno = 0; 207 errno = 0;
262 char *endptr = { 0 }; 208 char *endptr = {0};
263 209
264 int64_t tmp = strtoll(number, &endptr, 10); 210 int64_t tmp = strtoll(number, &endptr, 10);
265 if (errno != 0) { 211 if (errno != 0) {
@@ -287,7 +233,7 @@ bool is_int64(char *number, int64_t *target) {
287 */ 233 */
288bool is_uint64(char *number, uint64_t *target) { 234bool is_uint64(char *number, uint64_t *target) {
289 errno = 0; 235 errno = 0;
290 char *endptr = { 0 }; 236 char *endptr = {0};
291 unsigned long long tmp = strtoull(number, &endptr, 10); 237 unsigned long long tmp = strtoull(number, &endptr, 10);
292 238
293 if (errno != 0) { 239 if (errno != 0) {
@@ -309,74 +255,60 @@ bool is_uint64(char *number, uint64_t *target) {
309 return true; 255 return true;
310} 256}
311 257
312bool is_intpercent (char *number) { 258bool is_intpercent(char *number) {
313 int i; 259 int i;
314 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100) 260 if (is_integer(number) && (i = atoi(number)) >= 0 && i <= 100) {
315 return true; 261 return true;
316 else 262 } else {
317 return false; 263 return false;
264 }
318} 265}
319 266
320bool is_option (char *str) { 267bool is_option(char *str) {
321 if (!str) 268 if (!str) {
322 return false; 269 return false;
323 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2) 270 } else if (strspn(str, "-") == 1 || strspn(str, "-") == 2) {
324 return true; 271 return true;
325 else 272 } else {
326 return false; 273 return false;
274 }
327} 275}
328 276
329#ifdef NEED_GETTIMEOFDAY 277#ifdef NEED_GETTIMEOFDAY
330int 278int gettimeofday(struct timeval *tv, struct timezone *tz) {
331gettimeofday (struct timeval *tv, struct timezone *tz)
332{
333 tv->tv_usec = 0; 279 tv->tv_usec = 0;
334 tv->tv_sec = (long) time ((time_t) 0); 280 tv->tv_sec = (long)time((time_t)0);
335} 281}
336#endif 282#endif
337 283
338 284double delta_time(struct timeval tv) {
339
340double
341delta_time (struct timeval tv)
342{
343 struct timeval now; 285 struct timeval now;
344 286
345 gettimeofday (&now, NULL); 287 gettimeofday(&now, NULL);
346 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000); 288 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
347} 289}
348 290
349 291long deltime(struct timeval tv) {
350
351long
352deltime (struct timeval tv)
353{
354 struct timeval now; 292 struct timeval now;
355 gettimeofday (&now, NULL); 293 gettimeofday(&now, NULL);
356 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec; 294 return (now.tv_sec - tv.tv_sec) * 1000000 + now.tv_usec - tv.tv_usec;
357} 295}
358 296
359 297void strip(char *buffer) {
360
361
362void
363strip (char *buffer)
364{
365 size_t x; 298 size_t x;
366 int i; 299 int i;
367 300
368 for (x = strlen (buffer); x >= 1; x--) { 301 for (x = strlen(buffer); x >= 1; x--) {
369 i = x - 1; 302 i = x - 1;
370 if (buffer[i] == ' ' || 303 if (buffer[i] == ' ' || buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t') {
371 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
372 buffer[i] = '\0'; 304 buffer[i] = '\0';
373 else 305 } else {
374 break; 306 break;
307 }
375 } 308 }
376 return; 309 return;
377} 310}
378 311
379
380/****************************************************************************** 312/******************************************************************************
381 * 313 *
382 * Copies one string to another. Any previously existing data in 314 * Copies one string to another. Any previously existing data in
@@ -389,19 +321,16 @@ strip (char *buffer)
389 * 321 *
390 *****************************************************************************/ 322 *****************************************************************************/
391 323
392char * 324char *strscpy(char *dest, const char *src) {
393strscpy (char *dest, const char *src) 325 if (src == NULL) {
394{
395 if (src == NULL)
396 return NULL; 326 return NULL;
327 }
397 328
398 xasprintf (&dest, "%s", src); 329 xasprintf(&dest, "%s", src);
399 330
400 return dest; 331 return dest;
401} 332}
402 333
403
404
405/****************************************************************************** 334/******************************************************************************
406 * 335 *
407 * Returns a pointer to the next line of a multiline string buffer 336 * Returns a pointer to the next line of a multiline string buffer
@@ -418,7 +347,7 @@ strscpy (char *dest, const char *src)
418 * This 347 * This
419 * is 348 * is
420 * a 349 * a
421 * 350 *
422 * multiline string buffer 351 * multiline string buffer
423 * ============================== 352 * ==============================
424 * 353 *
@@ -431,7 +360,7 @@ strscpy (char *dest, const char *src)
431 * printf("%d %s",i++,firstword(ptr)); 360 * printf("%d %s",i++,firstword(ptr));
432 * ptr = strnl(ptr); 361 * ptr = strnl(ptr);
433 * } 362 * }
434 * 363 *
435 * Produces the following: 364 * Produces the following:
436 * 365 *
437 * 1 This 366 * 1 This
@@ -452,25 +381,26 @@ strscpy (char *dest, const char *src)
452 * 381 *
453 *****************************************************************************/ 382 *****************************************************************************/
454 383
455char * 384char *strnl(char *str) {
456strnl (char *str)
457{
458 size_t len; 385 size_t len;
459 if (str == NULL) 386 if (str == NULL) {
460 return NULL; 387 return NULL;
461 str = strpbrk (str, "\r\n"); 388 }
462 if (str == NULL) 389 str = strpbrk(str, "\r\n");
390 if (str == NULL) {
463 return NULL; 391 return NULL;
464 len = strspn (str, "\r\n"); 392 }
465 if (str[len] == '\0') 393 len = strspn(str, "\r\n");
394 if (str[len] == '\0') {
466 return NULL; 395 return NULL;
396 }
467 str += len; 397 str += len;
468 if (strlen (str) == 0) 398 if (strlen(str) == 0) {
469 return NULL; 399 return NULL;
400 }
470 return str; 401 return str;
471} 402}
472 403
473
474/****************************************************************************** 404/******************************************************************************
475 * 405 *
476 * Like strscpy, except only the portion of the source string up to 406 * Like strscpy, except only the portion of the source string up to
@@ -487,29 +417,28 @@ strnl (char *str)
487 * 417 *
488 *****************************************************************************/ 418 *****************************************************************************/
489 419
490char * 420char *strpcpy(char *dest, const char *src, const char *str) {
491strpcpy (char *dest, const char *src, const char *str)
492{
493 size_t len; 421 size_t len;
494 422
495 if (src) 423 if (src) {
496 len = strcspn (src, str); 424 len = strcspn(src, str);
497 else 425 } else {
498 return NULL; 426 return NULL;
427 }
499 428
500 if (dest == NULL || strlen (dest) < len) 429 if (dest == NULL || strlen(dest) < len) {
501 dest = realloc (dest, len + 1); 430 dest = realloc(dest, len + 1);
502 if (dest == NULL) 431 }
503 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n")); 432 if (dest == NULL) {
433 die(STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
434 }
504 435
505 strncpy (dest, src, len); 436 strncpy(dest, src, len);
506 dest[len] = '\0'; 437 dest[len] = '\0';
507 438
508 return dest; 439 return dest;
509} 440}
510 441
511
512
513/****************************************************************************** 442/******************************************************************************
514 * 443 *
515 * Like strscat, except only the portion of the source string up to 444 * Like strscat, except only the portion of the source string up to
@@ -518,62 +447,57 @@ strpcpy (char *dest, const char *src, const char *str)
518 * str = strpcpy(str,"This is a line of text with no trailing newline","x"); 447 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
519 * str = strpcat(str,"This is a line of text with no trailing newline","x"); 448 * str = strpcat(str,"This is a line of text with no trailing newline","x");
520 * printf("%s\n",str); 449 * printf("%s\n",str);
521 * 450 *
522 *This is a line of texThis is a line of tex 451 *This is a line of texThis is a line of tex
523 * 452 *
524 *****************************************************************************/ 453 *****************************************************************************/
525 454
526char * 455char *strpcat(char *dest, const char *src, const char *str) {
527strpcat (char *dest, const char *src, const char *str)
528{
529 size_t len, l2; 456 size_t len, l2;
530 457
531 if (dest) 458 if (dest) {
532 len = strlen (dest); 459 len = strlen(dest);
533 else 460 } else {
534 len = 0; 461 len = 0;
462 }
535 463
536 if (src) { 464 if (src) {
537 l2 = strcspn (src, str); 465 l2 = strcspn(src, str);
538 } 466 } else {
539 else {
540 return dest; 467 return dest;
541 } 468 }
542 469
543 dest = realloc (dest, len + l2 + 1); 470 dest = realloc(dest, len + l2 + 1);
544 if (dest == NULL) 471 if (dest == NULL) {
545 die (STATE_UNKNOWN, _("failed malloc in strscat\n")); 472 die(STATE_UNKNOWN, _("failed malloc in strscat\n"));
473 }
546 474
547 strncpy (dest + len, src, l2); 475 strncpy(dest + len, src, l2);
548 dest[len + l2] = '\0'; 476 dest[len + l2] = '\0';
549 477
550 return dest; 478 return dest;
551} 479}
552 480
553
554/****************************************************************************** 481/******************************************************************************
555 * 482 *
556 * asprintf, but die on failure 483 * asprintf, but die on failure
557 * 484 *
558 ******************************************************************************/ 485 ******************************************************************************/
559 486
560int 487int xvasprintf(char **strp, const char *fmt, va_list ap) {
561xvasprintf (char **strp, const char *fmt, va_list ap) 488 int result = vasprintf(strp, fmt, ap);
562{ 489 if (result == -1 || *strp == NULL) {
563 int result = vasprintf (strp, fmt, ap); 490 die(STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
564 if (result == -1 || *strp == NULL) 491 }
565 die (STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
566 return result; 492 return result;
567} 493}
568 494
569int 495int xasprintf(char **strp, const char *fmt, ...) {
570xasprintf (char **strp, const char *fmt, ...)
571{
572 va_list ap; 496 va_list ap;
573 int result; 497 int result;
574 va_start (ap, fmt); 498 va_start(ap, fmt);
575 result = xvasprintf (strp, fmt, ap); 499 result = xvasprintf(strp, fmt, ap);
576 va_end (ap); 500 va_end(ap);
577 return result; 501 return result;
578} 502}
579 503
@@ -583,247 +507,219 @@ xasprintf (char **strp, const char *fmt, ...)
583 * 507 *
584 ******************************************************************************/ 508 ******************************************************************************/
585 509
586char *perfdata (const char *label, 510char *perfdata(const char *label, long int val, const char *uom, bool warnp, long int warn, bool critp, long int crit, bool minp,
587 long int val, 511 long int minv, bool maxp, long int maxv) {
588 const char *uom,
589 int warnp,
590 long int warn,
591 int critp,
592 long int crit,
593 int minp,
594 long int minv,
595 int maxp,
596 long int maxv)
597{
598 char *data = NULL; 512 char *data = NULL;
599 513
600 if (strpbrk (label, "'= ")) 514 if (strpbrk(label, "'= ")) {
601 xasprintf (&data, "'%s'=%ld%s;", label, val, uom); 515 xasprintf(&data, "'%s'=%ld%s;", label, val, uom);
602 else 516 } else {
603 xasprintf (&data, "%s=%ld%s;", label, val, uom); 517 xasprintf(&data, "%s=%ld%s;", label, val, uom);
518 }
604 519
605 if (warnp) 520 if (warnp) {
606 xasprintf (&data, "%s%ld;", data, warn); 521 xasprintf(&data, "%s%ld;", data, warn);
607 else 522 } else {
608 xasprintf (&data, "%s;", data); 523 xasprintf(&data, "%s;", data);
524 }
609 525
610 if (critp) 526 if (critp) {
611 xasprintf (&data, "%s%ld;", data, crit); 527 xasprintf(&data, "%s%ld;", data, crit);
612 else 528 } else {
613 xasprintf (&data, "%s;", data); 529 xasprintf(&data, "%s;", data);
530 }
614 531
615 if (minp) 532 if (minp) {
616 xasprintf (&data, "%s%ld;", data, minv); 533 xasprintf(&data, "%s%ld;", data, minv);
617 else 534 } else {
618 xasprintf (&data, "%s;", data); 535 xasprintf(&data, "%s;", data);
536 }
619 537
620 if (maxp) 538 if (maxp) {
621 xasprintf (&data, "%s%ld", data, maxv); 539 xasprintf(&data, "%s%ld", data, maxv);
540 }
622 541
623 return data; 542 return data;
624} 543}
625 544
626 545char *perfdata_uint64(const char *label, uint64_t val, const char *uom, bool warnp, /* Warning present */
627char *perfdata_uint64 (const char *label, 546 uint64_t warn, bool critp, /* Critical present */
628 uint64_t val, 547 uint64_t crit, bool minp, /* Minimum present */
629 const char *uom, 548 uint64_t minv, bool maxp, /* Maximum present */
630 int warnp, /* Warning present */ 549 uint64_t maxv) {
631 uint64_t warn,
632 int critp, /* Critical present */
633 uint64_t crit,
634 int minp, /* Minimum present */
635 uint64_t minv,
636 int maxp, /* Maximum present */
637 uint64_t maxv)
638{
639 char *data = NULL; 550 char *data = NULL;
640 551
641 if (strpbrk (label, "'= ")) 552 if (strpbrk(label, "'= ")) {
642 xasprintf (&data, "'%s'=%" PRIu64 "%s;", label, val, uom); 553 xasprintf(&data, "'%s'=%" PRIu64 "%s;", label, val, uom);
643 else 554 } else {
644 xasprintf (&data, "%s=%" PRIu64 "%s;", label, val, uom); 555 xasprintf(&data, "%s=%" PRIu64 "%s;", label, val, uom);
556 }
645 557
646 if (warnp) 558 if (warnp) {
647 xasprintf (&data, "%s%" PRIu64 ";", data, warn); 559 xasprintf(&data, "%s%" PRIu64 ";", data, warn);
648 else 560 } else {
649 xasprintf (&data, "%s;", data); 561 xasprintf(&data, "%s;", data);
562 }
650 563
651 if (critp) 564 if (critp) {
652 xasprintf (&data, "%s%" PRIu64 ";", data, crit); 565 xasprintf(&data, "%s%" PRIu64 ";", data, crit);
653 else 566 } else {
654 xasprintf (&data, "%s;", data); 567 xasprintf(&data, "%s;", data);
568 }
655 569
656 if (minp) 570 if (minp) {
657 xasprintf (&data, "%s%" PRIu64 ";", data, minv); 571 xasprintf(&data, "%s%" PRIu64 ";", data, minv);
658 else 572 } else {
659 xasprintf (&data, "%s;", data); 573 xasprintf(&data, "%s;", data);
574 }
660 575
661 if (maxp) 576 if (maxp) {
662 xasprintf (&data, "%s%" PRIu64, data, maxv); 577 xasprintf(&data, "%s%" PRIu64, data, maxv);
578 }
663 579
664 return data; 580 return data;
665} 581}
666 582
667 583char *perfdata_int64(const char *label, int64_t val, const char *uom, bool warnp, /* Warning present */
668char *perfdata_int64 (const char *label, 584 int64_t warn, bool critp, /* Critical present */
669 int64_t val, 585 int64_t crit, bool minp, /* Minimum present */
670 const char *uom, 586 int64_t minv, bool maxp, /* Maximum present */
671 int warnp, /* Warning present */ 587 int64_t maxv) {
672 int64_t warn,
673 int critp, /* Critical present */
674 int64_t crit,
675 int minp, /* Minimum present */
676 int64_t minv,
677 int maxp, /* Maximum present */
678 int64_t maxv)
679{
680 char *data = NULL; 588 char *data = NULL;
681 589
682 if (strpbrk (label, "'= ")) 590 if (strpbrk(label, "'= ")) {
683 xasprintf (&data, "'%s'=%" PRId64 "%s;", label, val, uom); 591 xasprintf(&data, "'%s'=%" PRId64 "%s;", label, val, uom);
684 else 592 } else {
685 xasprintf (&data, "%s=%" PRId64 "%s;", label, val, uom); 593 xasprintf(&data, "%s=%" PRId64 "%s;", label, val, uom);
594 }
686 595
687 if (warnp) 596 if (warnp) {
688 xasprintf (&data, "%s%" PRId64 ";", data, warn); 597 xasprintf(&data, "%s%" PRId64 ";", data, warn);
689 else 598 } else {
690 xasprintf (&data, "%s;", data); 599 xasprintf(&data, "%s;", data);
600 }
691 601
692 if (critp) 602 if (critp) {
693 xasprintf (&data, "%s%" PRId64 ";", data, crit); 603 xasprintf(&data, "%s%" PRId64 ";", data, crit);
694 else 604 } else {
695 xasprintf (&data, "%s;", data); 605 xasprintf(&data, "%s;", data);
606 }
696 607
697 if (minp) 608 if (minp) {
698 xasprintf (&data, "%s%" PRId64 ";", data, minv); 609 xasprintf(&data, "%s%" PRId64 ";", data, minv);
699 else 610 } else {
700 xasprintf (&data, "%s;", data); 611 xasprintf(&data, "%s;", data);
612 }
701 613
702 if (maxp) 614 if (maxp) {
703 xasprintf (&data, "%s%" PRId64, data, maxv); 615 xasprintf(&data, "%s%" PRId64, data, maxv);
616 }
704 617
705 return data; 618 return data;
706} 619}
707 620
708 621char *fperfdata(const char *label, double val, const char *uom, bool warnp, double warn, bool critp, double crit, bool minp, double minv,
709char *fperfdata (const char *label, 622 bool maxp, double maxv) {
710 double val,
711 const char *uom,
712 int warnp,
713 double warn,
714 int critp,
715 double crit,
716 int minp,
717 double minv,
718 int maxp,
719 double maxv)
720{
721 char *data = NULL; 623 char *data = NULL;
722 624
723 if (strpbrk (label, "'= ")) 625 if (strpbrk(label, "'= ")) {
724 xasprintf (&data, "'%s'=", label); 626 xasprintf(&data, "'%s'=", label);
725 else 627 } else {
726 xasprintf (&data, "%s=", label); 628 xasprintf(&data, "%s=", label);
629 }
727 630
728 xasprintf (&data, "%s%f", data, val); 631 xasprintf(&data, "%s%f", data, val);
729 xasprintf (&data, "%s%s;", data, uom); 632 xasprintf(&data, "%s%s;", data, uom);
730 633
731 if (warnp) 634 if (warnp) {
732 xasprintf (&data, "%s%f", data, warn); 635 xasprintf(&data, "%s%f", data, warn);
636 }
733 637
734 xasprintf (&data, "%s;", data); 638 xasprintf(&data, "%s;", data);
735 639
736 if (critp) 640 if (critp) {
737 xasprintf (&data, "%s%f", data, crit); 641 xasprintf(&data, "%s%f", data, crit);
642 }
738 643
739 xasprintf (&data, "%s;", data); 644 xasprintf(&data, "%s;", data);
740 645
741 if (minp) 646 if (minp) {
742 xasprintf (&data, "%s%f", data, minv); 647 xasprintf(&data, "%s%f", data, minv);
648 }
743 649
744 if (maxp) { 650 if (maxp) {
745 xasprintf (&data, "%s;", data); 651 xasprintf(&data, "%s;", data);
746 xasprintf (&data, "%s%f", data, maxv); 652 xasprintf(&data, "%s%f", data, maxv);
747 } 653 }
748 654
749 return data; 655 return data;
750} 656}
751 657
752char *sperfdata (const char *label, 658char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, bool minp, double minv, bool maxp, double maxv) {
753 double val,
754 const char *uom,
755 char *warn,
756 char *crit,
757 int minp,
758 double minv,
759 int maxp,
760 double maxv)
761{
762 char *data = NULL; 659 char *data = NULL;
763 if (strpbrk (label, "'= ")) 660 if (strpbrk(label, "'= ")) {
764 xasprintf (&data, "'%s'=", label); 661 xasprintf(&data, "'%s'=", label);
765 else 662 } else {
766 xasprintf (&data, "%s=", label); 663 xasprintf(&data, "%s=", label);
664 }
767 665
768 xasprintf (&data, "%s%f", data, val); 666 xasprintf(&data, "%s%f", data, val);
769 xasprintf (&data, "%s%s;", data, uom); 667 xasprintf(&data, "%s%s;", data, uom);
770 668
771 if (warn!=NULL) 669 if (warn != NULL) {
772 xasprintf (&data, "%s%s", data, warn); 670 xasprintf(&data, "%s%s", data, warn);
671 }
773 672
774 xasprintf (&data, "%s;", data); 673 xasprintf(&data, "%s;", data);
775 674
776 if (crit!=NULL) 675 if (crit != NULL) {
777 xasprintf (&data, "%s%s", data, crit); 676 xasprintf(&data, "%s%s", data, crit);
677 }
778 678
779 xasprintf (&data, "%s;", data); 679 xasprintf(&data, "%s;", data);
780 680
781 if (minp) 681 if (minp) {
782 xasprintf (&data, "%s%f", data, minv); 682 xasprintf(&data, "%s%f", data, minv);
683 }
783 684
784 if (maxp) { 685 if (maxp) {
785 xasprintf (&data, "%s;", data); 686 xasprintf(&data, "%s;", data);
786 xasprintf (&data, "%s%f", data, maxv); 687 xasprintf(&data, "%s%f", data, maxv);
787 } 688 }
788 689
789 return data; 690 return data;
790} 691}
791 692
792char *sperfdata_int (const char *label, 693char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, bool minp, int minv, bool maxp, int maxv) {
793 int val,
794 const char *uom,
795 char *warn,
796 char *crit,
797 int minp,
798 int minv,
799 int maxp,
800 int maxv)
801{
802 char *data = NULL; 694 char *data = NULL;
803 if (strpbrk (label, "'= ")) 695 if (strpbrk(label, "'= ")) {
804 xasprintf (&data, "'%s'=", label); 696 xasprintf(&data, "'%s'=", label);
805 else 697 } else {
806 xasprintf (&data, "%s=", label); 698 xasprintf(&data, "%s=", label);
699 }
807 700
808 xasprintf (&data, "%s%d", data, val); 701 xasprintf(&data, "%s%d", data, val);
809 xasprintf (&data, "%s%s;", data, uom); 702 xasprintf(&data, "%s%s;", data, uom);
810 703
811 if (warn!=NULL) 704 if (warn != NULL) {
812 xasprintf (&data, "%s%s", data, warn); 705 xasprintf(&data, "%s%s", data, warn);
706 }
813 707
814 xasprintf (&data, "%s;", data); 708 xasprintf(&data, "%s;", data);
815 709
816 if (crit!=NULL) 710 if (crit != NULL) {
817 xasprintf (&data, "%s%s", data, crit); 711 xasprintf(&data, "%s%s", data, crit);
712 }
818 713
819 xasprintf (&data, "%s;", data); 714 xasprintf(&data, "%s;", data);
820 715
821 if (minp) 716 if (minp) {
822 xasprintf (&data, "%s%d", data, minv); 717 xasprintf(&data, "%s%d", data, minv);
718 }
823 719
824 if (maxp) { 720 if (maxp) {
825 xasprintf (&data, "%s;", data); 721 xasprintf(&data, "%s;", data);
826 xasprintf (&data, "%s%d", data, maxv); 722 xasprintf(&data, "%s%d", data, maxv);
827 } 723 }
828 724
829 return data; 725 return data;
diff --git a/plugins/utils.h b/plugins/utils.h
index f939e337..1d3c153c 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -13,51 +13,51 @@ in order to resist overflow attacks. In addition, a few functions are
13provided to standardize version and error reporting across the entire 13provided to standardize version and error reporting across the entire
14suite of plugins. */ 14suite of plugins. */
15 15
16/* now some functions etc are being defined in ../lib/utils_base.c */ 16#include "../config.h"
17#include "utils_base.h"
18
19#include <stdbool.h> 17#include <stdbool.h>
20 18#include <stdint.h>
19#include <stdio.h>
20#include <time.h>
21 21
22#ifdef NP_EXTRA_OPTS 22#ifdef NP_EXTRA_OPTS
23/* Include extra-opts functions if compiled in */ 23/* Include extra-opts functions if compiled in */
24#include "extra_opts.h" 24# include "extra_opts.h"
25#else 25#else
26/* else, fake np_extra_opts */ 26/* else, fake np_extra_opts */
27#define np_extra_opts(acptr,av,pr) av 27# define np_extra_opts(acptr, av, pr) av
28#endif 28#endif
29 29
30/* Standardize version information, termination */ 30/* Standardize version information, termination */
31 31
32void support (void); 32void support(void);
33void print_revision (const char *, const char *); 33void print_revision(const char *, const char *);
34 34
35extern time_t start_time, end_time; 35extern time_t start_time, end_time;
36 36
37/* Test input types */ 37/* Test input types */
38 38
39bool is_integer (char *); 39bool is_integer(char *);
40bool is_intpos (char *); 40bool is_intpos(char *);
41bool is_intneg (char *); 41bool is_intneg(char *);
42bool is_intnonneg (char *); 42bool is_intnonneg(char *);
43bool is_intpercent (char *); 43bool is_intpercent(char *);
44bool is_uint64(char *number, uint64_t *target); 44bool is_uint64(char *number, uint64_t *target);
45bool is_int64(char *number, int64_t *target); 45bool is_int64(char *number, int64_t *target);
46 46
47bool is_numeric (char *); 47bool is_numeric(char *);
48bool is_positive (char *); 48bool is_positive(char *);
49bool is_negative (char *); 49bool is_negative(char *);
50bool is_nonnegative (char *); 50bool is_nonnegative(char *);
51bool is_percentage (char *); 51bool is_percentage(char *);
52bool is_percentage_expression (const char[]); 52bool is_percentage_expression(const char[]);
53 53
54bool is_option (char *); 54bool is_option(char *);
55 55
56/* Generalized timer that will do milliseconds if available */ 56/* Generalized timer that will do milliseconds if available */
57#ifndef HAVE_STRUCT_TIMEVAL 57#ifndef HAVE_STRUCT_TIMEVAL
58struct timeval { 58struct timeval {
59 long tv_sec; /* seconds */ 59 long tv_sec; /* seconds */
60 long tv_usec; /* microseconds */ 60 long tv_usec; /* microseconds */
61}; 61};
62#endif 62#endif
63 63
@@ -65,137 +65,143 @@ struct timeval {
65int gettimeofday(struct timeval *, struct timezone *); 65int gettimeofday(struct timeval *, struct timezone *);
66#endif 66#endif
67 67
68double delta_time (struct timeval tv); 68double delta_time(struct timeval tv);
69long deltime (struct timeval tv); 69long deltime(struct timeval tv);
70 70
71/* Handle strings safely */ 71/* Handle strings safely */
72 72
73void strip (char *); 73void strip(char *);
74char *strscpy (char *, const char *); 74char *strscpy(char *, const char *);
75char *strnl (char *); 75char *strnl(char *);
76char *strpcpy (char *, const char *, const char *); 76char *strpcpy(char *, const char *, const char *);
77char *strpcat (char *, const char *, const char *); 77char *strpcat(char *, const char *, const char *);
78int xvasprintf (char **strp, const char *fmt, va_list ap); 78int xvasprintf(char **strp, const char *fmt, va_list ap);
79int xasprintf (char **strp, const char *fmt, ...); 79int xasprintf(char **strp, const char *fmt, ...)__attribute__ ((format (printf, 2, 3)));
80 80
81int max_state (int a, int b); 81void usage(const char *) __attribute__((noreturn));
82int max_state_alt (int a, int b);
83
84void usage (const char *) __attribute__((noreturn));
85void usage2(const char *, const char *) __attribute__((noreturn)); 82void usage2(const char *, const char *) __attribute__((noreturn));
86void usage3(const char *, int) __attribute__((noreturn)); 83void usage3(const char *, int) __attribute__((noreturn));
87void usage4(const char *) __attribute__((noreturn)); 84void usage4(const char *) __attribute__((noreturn));
88void usage5(void) __attribute__((noreturn)); 85void usage5(void) __attribute__((noreturn));
89void usage_va(const char *fmt, ...) __attribute__((noreturn)); 86void usage_va(const char *fmt, ...) __attribute__((noreturn));
90 87
91#define max(a,b) (((a)>(b))?(a):(b)) 88#define max(a, b) (((a) > (b)) ? (a) : (b))
92#define min(a,b) (((a)<(b))?(a):(b)) 89#define min(a, b) (((a) < (b)) ? (a) : (b))
93 90
94char *perfdata (const char *, long int, const char *, int, long int, 91char *perfdata(const char *, long int, const char *, bool, long int, bool, long int, bool, long int, bool, long int);
95 int, long int, int, long int, int, long int);
96 92
97char *perfdata_uint64 (const char *, uint64_t , const char *, int, uint64_t, 93char *perfdata_uint64(const char *, uint64_t, const char *, bool, uint64_t, bool, uint64_t, bool, uint64_t, bool, uint64_t);
98 int, uint64_t, int, uint64_t, int, uint64_t);
99 94
100char *perfdata_int64 (const char *, int64_t, const char *, int, int64_t, 95char *perfdata_int64(const char *, int64_t, const char *, bool, int64_t, bool, int64_t, bool, int64_t, bool, int64_t);
101 int, int64_t, int, int64_t, int, int64_t);
102 96
103char *fperfdata (const char *, double, const char *, int, double, 97char *fperfdata(const char *, double, const char *, bool, double, bool, double, bool, double, bool, double);
104 int, double, int, double, int, double);
105 98
106char *sperfdata (const char *, double, const char *, char *, char *, 99char *sperfdata(const char *, double, const char *, char *, char *, bool, double, bool, double);
107 int, double, int, double);
108 100
109char *sperfdata_int (const char *, int, const char *, char *, char *, 101char *sperfdata_int(const char *, int, const char *, char *, char *, bool, int, bool, int);
110 int, int, int, int);
111 102
112/* The idea here is that, although not every plugin will use all of these, 103/* The idea here is that, although not every plugin will use all of these,
113 most will or should. Therefore, for consistency, these very common 104 most will or should. Therefore, for consistency, these very common
114 options should have only these meanings throughout the overall suite */ 105 options should have only these meanings throughout the overall suite */
115 106
116#define STD_LONG_OPTS \ 107#define STD_LONG_OPTS \
117{"version",no_argument,0,'V'},\ 108 {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, \
118{"verbose",no_argument,0,'v'},\ 109 {"timeout", required_argument, 0, 't'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, \
119{"help",no_argument,0,'h'},\ 110 {"hostname", required_argument, 0, 'H'}
120{"timeout",required_argument,0,'t'},\
121{"critical",required_argument,0,'c'},\
122{"warning",required_argument,0,'w'},\
123{"hostname",required_argument,0,'H'}
124 111
125#define COPYRIGHT "Copyright (c) %s Monitoring Plugins Development Team\n\ 112#define COPYRIGHT \
113 "Copyright (c) %s Monitoring Plugins Development Team\n\
126\t<%s>\n\n" 114\t<%s>\n\n"
127 115
128#define UT_HLP_VRS _("\ 116#define UT_HLP_VRS \
117 _("\
129 %s (-h | --help) for detailed help\n\ 118 %s (-h | --help) for detailed help\n\
130 %s (-V | --version) for version information\n") 119 %s (-V | --version) for version information\n")
131 120
132#define UT_HELP_VRSN _("\ 121#define UT_HELP_VRSN \
122 _("\
133\nOptions:\n\ 123\nOptions:\n\
134 -h, --help\n\ 124 -h, --help\n\
135 Print detailed help screen\n\ 125 Print detailed help screen\n\
136 -V, --version\n\ 126 -V, --version\n\
137 Print version information\n") 127 Print version information\n")
138 128
139#define UT_HOST_PORT _("\ 129#define UT_HOST_PORT \
130 _("\
140 -H, --hostname=ADDRESS\n\ 131 -H, --hostname=ADDRESS\n\
141 Host name, IP Address, or unix socket (must be an absolute path)\n\ 132 Host name, IP Address, or unix socket (must be an absolute path)\n\
142 -%c, --port=INTEGER\n\ 133 -%c, --port=INTEGER\n\
143 Port number (default: %s)\n") 134 Port number (default: %s)\n")
144 135
145#define UT_IPv46 _("\ 136#define UT_IPv46 \
137 _("\
146 -4, --use-ipv4\n\ 138 -4, --use-ipv4\n\
147 Use IPv4 connection\n\ 139 Use IPv4 connection\n\
148 -6, --use-ipv6\n\ 140 -6, --use-ipv6\n\
149 Use IPv6 connection\n") 141 Use IPv6 connection\n")
150 142
151#define UT_VERBOSE _("\ 143#define UT_VERBOSE \
144 _("\
152 -v, --verbose\n\ 145 -v, --verbose\n\
153 Show details for command-line debugging (output may be truncated by\n\ 146 Show details for command-line debugging (output may be truncated by\n\
154 the monitoring system)\n") 147 the monitoring system)\n")
155 148
156#define UT_WARN_CRIT _("\ 149#define UT_WARN_CRIT \
150 _("\
157 -w, --warning=DOUBLE\n\ 151 -w, --warning=DOUBLE\n\
158 Response time to result in warning status (seconds)\n\ 152 Response time to result in warning status (seconds)\n\
159 -c, --critical=DOUBLE\n\ 153 -c, --critical=DOUBLE\n\
160 Response time to result in critical status (seconds)\n") 154 Response time to result in critical status (seconds)\n")
161 155
162#define UT_WARN_CRIT_RANGE _("\ 156#define UT_WARN_CRIT_RANGE \
157 _("\
163 -w, --warning=RANGE\n\ 158 -w, --warning=RANGE\n\
164 Warning range (format: start:end). Alert if outside this range\n\ 159 Warning range (format: start:end). Alert if outside this range\n\
165 -c, --critical=RANGE\n\ 160 -c, --critical=RANGE\n\
166 Critical range\n") 161 Critical range\n")
167 162
168#define UT_CONN_TIMEOUT _("\ 163#define UT_CONN_TIMEOUT \
164 _("\
169 -t, --timeout=INTEGER\n\ 165 -t, --timeout=INTEGER\n\
170 Seconds before connection times out (default: %d)\n") 166 Seconds before connection times out (default: %d)\n")
171 167
172#define UT_PLUG_TIMEOUT _("\ 168#define UT_PLUG_TIMEOUT \
169 _("\
173 -t, --timeout=INTEGER\n\ 170 -t, --timeout=INTEGER\n\
174 Seconds before plugin times out (default: %d)\n") 171 Seconds before plugin times out (default: %d)\n")
175 172
176#ifdef NP_EXTRA_OPTS 173#ifdef NP_EXTRA_OPTS
177#define UT_EXTRA_OPTS _("\ 174# define UT_EXTRA_OPTS \
175 _("\
178 --extra-opts=[section][@file]\n\ 176 --extra-opts=[section][@file]\n\
179 Read options from an ini file. See\n\ 177 Read options from an ini file. See\n\
180 https://www.monitoring-plugins.org/doc/extra-opts.html\n\ 178 https://www.monitoring-plugins.org/doc/extra-opts.html\n\
181 for usage and examples.\n") 179 for usage and examples.\n")
182#else 180#else
183#define UT_EXTRA_OPTS " \b" 181# define UT_EXTRA_OPTS " \b"
184#endif 182#endif
185 183
186#define UT_THRESHOLDS_NOTES _("\ 184#define UT_THRESHOLDS_NOTES \
185 _("\
187 See:\n\ 186 See:\n\
188 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\ 187 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\
189 for THRESHOLD format and examples.\n") 188 for THRESHOLD format and examples.\n")
190 189
191#define UT_SUPPORT _("\n\ 190#define UT_SUPPORT \
191 _("\n\
192Send email to help@monitoring-plugins.org if you have questions regarding\n\ 192Send email to help@monitoring-plugins.org if you have questions regarding\n\
193use of this software. To submit patches or suggest improvements, send email\n\ 193use of this software. To submit patches or suggest improvements, send email\n\
194to devel@monitoring-plugins.org\n\n") 194to devel@monitoring-plugins.org\n\n")
195 195
196#define UT_NOWARRANTY _("\n\ 196#define UT_NOWARRANTY \
197 _("\n\
197The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\ 198The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
198copies of the plugins under the terms of the GNU General Public License.\n\ 199copies of the plugins under the terms of the GNU General Public License.\n\
199For more information about these matters, see the file named COPYING.\n") 200For more information about these matters, see the file named COPYING.\n")
200 201
202#define UT_OUTPUT_FORMAT \
203 _("\
204 --output-format=OUTPUT_FORMAT\n\
205 Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n")
206
201#endif /* NP_UTILS_H */ 207#endif /* NP_UTILS_H */