summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-03-13 00:48:00 +0100
committerLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-03-13 00:48:00 +0100
commit54a099ed6d4ae57835095083aa825462eb03f369 (patch)
treecf7af5c49f0c8ebc5574b0efc1af3871f1717357 /plugins
parent89df16e7503539c2b0da7e95375b470559bb94ec (diff)
parent02acc76edc5c646af90a6168df61c711aa3d11d6 (diff)
downloadmonitoring-plugins-54a099ed6d4ae57835095083aa825462eb03f369.tar.gz
Merge branch 'master' into refactor/check_tcp
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am35
-rw-r--r--plugins/check_apt.c151
-rw-r--r--plugins/check_apt.d/config.h41
-rw-r--r--plugins/check_by_ssh.c265
-rw-r--r--plugins/check_by_ssh.d/config.h56
-rw-r--r--plugins/check_cluster.c149
-rw-r--r--plugins/check_cluster.d/config.h27
-rw-r--r--plugins/check_dbi.c445
-rw-r--r--plugins/check_dbi.d/config.h63
-rw-r--r--plugins/check_dig.c183
-rw-r--r--plugins/check_dig.d/config.h40
-rw-r--r--plugins/check_dns.c373
-rw-r--r--plugins/check_dns.d/config.h34
-rw-r--r--plugins/check_fping.c284
-rw-r--r--plugins/check_fping.d/config.h58
-rw-r--r--plugins/check_game.c229
-rw-r--r--plugins/check_game.d/config.h30
-rw-r--r--plugins/check_hpjd.c174
-rw-r--r--plugins/check_hpjd.d/config.h25
-rw-r--r--plugins/check_ldap.c602
-rw-r--r--plugins/check_ldap.d/config.h60
-rw-r--r--plugins/check_mrtg.c177
-rw-r--r--plugins/check_mrtg.d/config.h36
-rw-r--r--plugins/check_mrtgtraf.c134
-rw-r--r--plugins/check_mrtgtraf.d/config.h30
-rw-r--r--plugins/check_mysql.c804
-rw-r--r--plugins/check_mysql.d/config.h58
-rw-r--r--plugins/check_mysql_query.c127
-rw-r--r--plugins/check_mysql_query.d/config.h36
-rw-r--r--plugins/check_nagios.c168
-rw-r--r--plugins/check_nagios.d/config.h19
-rw-r--r--plugins/check_nt.c527
-rw-r--r--plugins/check_nt.d/config.h53
-rw-r--r--plugins/check_ntp_peer.c385
-rw-r--r--plugins/check_ntp_peer.d/config.h67
-rw-r--r--plugins/check_ntp_time.c210
-rw-r--r--plugins/check_ntp_time.d/config.h28
-rw-r--r--plugins/check_overcr.c417
-rw-r--r--plugins/check_pgsql.c216
-rw-r--r--plugins/check_pgsql.d/config.h61
-rw-r--r--plugins/check_ping.c529
-rw-r--r--plugins/check_ping.d/config.h46
-rw-r--r--plugins/check_radius.c541
-rw-r--r--plugins/check_radius.d/config.h42
-rw-r--r--plugins/check_real.c245
-rw-r--r--plugins/check_real.d/config.h37
-rw-r--r--plugins/check_smtp.c1153
-rw-r--r--plugins/check_smtp.d/config.h92
-rw-r--r--plugins/check_ssh.c210
-rw-r--r--plugins/check_ssh.d/config.h29
-rw-r--r--plugins/check_swap.c2
-rw-r--r--plugins/check_time.c191
-rw-r--r--plugins/check_time.d/config.h42
-rw-r--r--plugins/check_ups.c274
-rw-r--r--plugins/check_ups.d/config.h55
-rw-r--r--plugins/negate.c96
-rw-r--r--plugins/negate.d/config.h24
-rw-r--r--plugins/netutils.c71
-rw-r--r--plugins/t/check_http.t2
-rw-r--r--plugins/t/check_jabber.t2
-rw-r--r--plugins/t/check_ldap.t2
-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.t35
-rw-r--r--plugins/utils.c243
-rw-r--r--plugins/utils.h141
68 files changed, 6218 insertions, 4914 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index d43c1971..9e4924c3 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_nwstat 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@
@@ -46,7 +46,37 @@ SUBDIRS = picohttpparser
46 46
47np_test_scripts = tests/test_check_swap.t 47np_test_scripts = tests/test_check_swap.t
48 48
49EXTRA_DIST = t tests $(np_test_scripts) check_swap.d 49EXTRA_DIST = t \
50 tests \
51 $(np_test_scripts) \
52 negate.d \
53 check_swap.d \
54 check_ldap.d \
55 check_hpjd.d \
56 check_game.d \
57 check_radius.d \
58 check_time.d \
59 check_nagios.d \
60 check_dbi.d \
61 check_real.d \
62 check_ssh.d \
63 check_nt.d \
64 check_dns.d \
65 check_mrtgtraf.d \
66 check_mysql_query.d \
67 check_mrtg.d \
68 check_ntp_peer.d \
69 check_apt.d \
70 check_pgsql.d \
71 check_ping.d \
72 check_by_ssh.d \
73 check_smtp.d \
74 check_mysql.d \
75 check_ntp_time.d \
76 check_dig.d \
77 check_cluster.d \
78 check_ups.d \
79 check_fping.d
50 80
51PLUGINHDRS = common.h 81PLUGINHDRS = common.h
52 82
@@ -109,7 +139,6 @@ check_nt_LDADD = $(NETLIBS)
109check_ntp_LDADD = $(NETLIBS) $(MATHLIBS) 139check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
110check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 140check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
111check_nwstat_LDADD = $(NETLIBS) 141check_nwstat_LDADD = $(NETLIBS)
112check_overcr_LDADD = $(NETLIBS)
113check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) 142check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
114check_ping_LDADD = $(NETLIBS) 143check_ping_LDADD = $(NETLIBS)
115check_procs_LDADD = $(BASEOBJS) 144check_procs_LDADD = $(BASEOBJS)
diff --git a/plugins/check_apt.c b/plugins/check_apt.c
index 1eda45dd..e840184b 100644
--- a/plugins/check_apt.c
+++ b/plugins/check_apt.c
@@ -29,6 +29,7 @@
29 * 29 *
30 *****************************************************************************/ 30 *****************************************************************************/
31 31
32#include "states.h"
32const char *progname = "check_apt"; 33const char *progname = "check_apt";
33const char *copyright = "2006-2024"; 34const char *copyright = "2006-2024";
34const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
@@ -37,13 +38,7 @@ const char *email = "devel@monitoring-plugins.org";
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 {
43 UPGRADE,
44 DIST_UPGRADE,
45 NO_UPGRADE
46} upgrade_type;
47 42
48/* Character for hidden input file option (for testing). */ 43/* Character for hidden input file option (for testing). */
49#define INPUT_FILE_OPT CHAR_MAX + 1 44#define INPUT_FILE_OPT CHAR_MAX + 1
@@ -61,14 +56,18 @@ typedef enum {
61#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)" 56#define SECURITY_RE "^[^\\(]*\\(.* (Debian-Security:|Ubuntu:[^/]*/[^-]*-security)"
62 57
63/* some standard functions */ 58/* some standard functions */
64static int process_arguments(int /*argc*/, char ** /*argv*/); 59typedef struct {
60 int errorcode;
61 check_apt_config config;
62} check_apt_config_wrapper;
63static check_apt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
65static void print_help(void); 64static void print_help(void);
66void print_usage(void); 65void print_usage(void);
67 66
68/* construct the appropriate apt-get cmdline */ 67/* construct the appropriate apt-get cmdline */
69static char *construct_cmdline(upgrade_type u, const char *opts); 68static char *construct_cmdline(upgrade_type /*u*/, const char * /*opts*/);
70/* run an apt-get update */ 69/* run an apt-get update */
71static int run_update(void); 70static int run_update(char * /*update_opts*/);
72 71
73typedef struct { 72typedef struct {
74 int errorcode; 73 int errorcode;
@@ -79,42 +78,35 @@ typedef struct {
79} run_upgrade_result; 78} run_upgrade_result;
80 79
81/* run an apt-get upgrade */ 80/* run an apt-get upgrade */
82static run_upgrade_result run_upgrade(void); 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 83
84/* add another clause to a regexp */ 84/* add another clause to a regexp */
85static char *add_to_regexp(char *expr, const char *next); 85static char *add_to_regexp(char * /*expr*/, const char * /*next*/);
86/* extract package name from Inst line */ 86/* extract package name from Inst line */
87static char *pkg_name(char *line); 87static char *pkg_name(char * /*line*/);
88/* string comparison function for qsort */ 88/* string comparison function for qsort */
89static int cmpstringp(const void *p1, const void *p2); 89static int cmpstringp(const void * /*p1*/, const void * /*p2*/);
90 90
91/* configuration variables */ 91/* configuration variables */
92static int verbose = 0; /* -v */ 92static int verbose = 0; /* -v */
93static bool list = false; /* list packages available for upgrade */
94static bool do_update = false; /* whether to call apt-get update */
95static bool only_critical = false; /* whether to warn about non-critical updates */
96static upgrade_type upgrade = UPGRADE; /* which type of upgrade to do */
97static char *upgrade_opts = NULL; /* options to override defaults for upgrade */
98static char *update_opts = NULL; /* options to override defaults for update */
99static char *do_include = NULL; /* regexp to only include certain packages */
100static char *do_exclude = NULL; /* regexp to only exclude certain packages */
101static char *do_critical = NULL; /* regexp specifying critical packages */
102static char *input_filename = NULL; /* input filename for testing */
103/* number of packages available for upgrade to return WARNING status */
104static int packages_warning = 1;
105 93
106/* other global variables */ 94/* other global variables */
107static int stderr_warning = 0; /* if a cmd issued output on stderr */ 95static bool stderr_warning = false; /* if a cmd issued output on stderr */
108static int exec_warning = 0; /* if a cmd exited non-zero */ 96static bool exec_warning = false; /* if a cmd exited non-zero */
109 97
110int main(int argc, char **argv) { 98int main(int argc, char **argv) {
111 /* Parse extra opts if any */ 99 /* Parse extra opts if any */
112 argv = np_extra_opts(&argc, argv, progname); 100 argv = np_extra_opts(&argc, argv, progname);
113 101
114 if (process_arguments(argc, argv) == ERROR) { 102 check_apt_config_wrapper tmp_config = process_arguments(argc, argv);
103
104 if (tmp_config.errorcode == ERROR) {
115 usage_va(_("Could not parse arguments")); 105 usage_va(_("Could not parse arguments"));
116 } 106 }
117 107
108 const check_apt_config config = tmp_config.config;
109
118 /* Set signal handling and alarm timeout */ 110 /* Set signal handling and alarm timeout */
119 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 111 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
120 usage_va(_("Cannot catch SIGALRM")); 112 usage_va(_("Cannot catch SIGALRM"));
@@ -123,14 +115,15 @@ int main(int argc, char **argv) {
123 /* handle timeouts gracefully... */ 115 /* handle timeouts gracefully... */
124 alarm(timeout_interval); 116 alarm(timeout_interval);
125 117
126 int result = STATE_UNKNOWN; 118 mp_state_enum result = STATE_UNKNOWN;
127 /* if they want to run apt-get update first... */ 119 /* if they want to run apt-get update first... */
128 if (do_update) { 120 if (config.do_update) {
129 result = run_update(); 121 result = run_update(config.update_opts);
130 } 122 }
131 123
132 /* apt-get upgrade */ 124 /* apt-get upgrade */
133 run_upgrade_result upgrad_res = run_upgrade(); 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);
134 127
135 result = max_state(result, upgrad_res.errorcode); 128 result = max_state(result, upgrad_res.errorcode);
136 int packages_available = upgrad_res.package_count; 129 int packages_available = upgrad_res.package_count;
@@ -140,18 +133,18 @@ int main(int argc, char **argv) {
140 133
141 if (sec_count > 0) { 134 if (sec_count > 0) {
142 result = max_state(result, STATE_CRITICAL); 135 result = max_state(result, STATE_CRITICAL);
143 } else if (packages_available >= packages_warning && only_critical == false) { 136 } else if (packages_available >= config.packages_warning && !config.only_critical) {
144 result = max_state(result, STATE_WARNING); 137 result = max_state(result, STATE_WARNING);
145 } else if (result > STATE_UNKNOWN) { 138 } else if (result > STATE_UNKNOWN) {
146 result = STATE_UNKNOWN; 139 result = STATE_UNKNOWN;
147 } 140 }
148 141
149 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"),
150 state_text(result), packages_available, (upgrade == DIST_UPGRADE) ? "dist-upgrade" : "upgrade", sec_count, 143 state_text(result), packages_available, (config.upgrade == DIST_UPGRADE) ? "dist-upgrade" : "upgrade", sec_count,
151 (stderr_warning) ? " warnings detected" : "", (stderr_warning && exec_warning) ? "," : "", 144 (stderr_warning) ? " warnings detected" : "", (stderr_warning && exec_warning) ? "," : "",
152 (exec_warning) ? " errors detected" : "", (stderr_warning || exec_warning) ? "." : "", packages_available, sec_count); 145 (exec_warning) ? " errors detected" : "", (stderr_warning || exec_warning) ? "." : "", packages_available, sec_count);
153 146
154 if (list) { 147 if (config.list) {
155 qsort(secpackages_list, sec_count, sizeof(char *), cmpstringp); 148 qsort(secpackages_list, sec_count, sizeof(char *), cmpstringp);
156 qsort(packages_list, packages_available - sec_count, sizeof(char *), cmpstringp); 149 qsort(packages_list, packages_available - sec_count, sizeof(char *), cmpstringp);
157 150
@@ -159,7 +152,7 @@ int main(int argc, char **argv) {
159 printf("%s (security)\n", secpackages_list[i]); 152 printf("%s (security)\n", secpackages_list[i]);
160 } 153 }
161 154
162 if (only_critical == false) { 155 if (!config.only_critical) {
163 for (int i = 0; i < packages_available - sec_count; i++) { 156 for (int i = 0; i < packages_available - sec_count; i++) {
164 printf("%s\n", packages_list[i]); 157 printf("%s\n", packages_list[i]);
165 } 158 }
@@ -170,7 +163,7 @@ int main(int argc, char **argv) {
170} 163}
171 164
172/* process command-line arguments */ 165/* process command-line arguments */
173int process_arguments(int argc, char **argv) { 166check_apt_config_wrapper process_arguments(int argc, char **argv) {
174 static struct option longopts[] = {{"version", no_argument, 0, 'V'}, 167 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
175 {"help", no_argument, 0, 'h'}, 168 {"help", no_argument, 0, 'h'},
176 {"verbose", no_argument, 0, 'v'}, 169 {"verbose", no_argument, 0, 'v'},
@@ -179,7 +172,7 @@ int process_arguments(int argc, char **argv) {
179 {"upgrade", optional_argument, 0, 'U'}, 172 {"upgrade", optional_argument, 0, 'U'},
180 {"no-upgrade", no_argument, 0, 'n'}, 173 {"no-upgrade", no_argument, 0, 'n'},
181 {"dist-upgrade", optional_argument, 0, 'd'}, 174 {"dist-upgrade", optional_argument, 0, 'd'},
182 {"list", no_argument, false, 'l'}, 175 {"list", no_argument, 0, 'l'},
183 {"include", required_argument, 0, 'i'}, 176 {"include", required_argument, 0, 'i'},
184 {"exclude", required_argument, 0, 'e'}, 177 {"exclude", required_argument, 0, 'e'},
185 {"critical", required_argument, 0, 'c'}, 178 {"critical", required_argument, 0, 'c'},
@@ -188,6 +181,11 @@ int process_arguments(int argc, char **argv) {
188 {"packages-warning", required_argument, 0, 'w'}, 181 {"packages-warning", required_argument, 0, 'w'},
189 {0, 0, 0, 0}}; 182 {0, 0, 0, 0}};
190 183
184 check_apt_config_wrapper result = {
185 .errorcode = OK,
186 .config = check_apt_config_init(),
187 };
188
191 while (true) { 189 while (true) {
192 int option_char = 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);
193 191
@@ -209,55 +207,55 @@ int process_arguments(int argc, char **argv) {
209 timeout_interval = atoi(optarg); 207 timeout_interval = atoi(optarg);
210 break; 208 break;
211 case 'd': 209 case 'd':
212 upgrade = DIST_UPGRADE; 210 result.config.upgrade = DIST_UPGRADE;
213 if (optarg != NULL) { 211 if (optarg != NULL) {
214 upgrade_opts = strdup(optarg); 212 result.config.upgrade_opts = strdup(optarg);
215 if (upgrade_opts == NULL) { 213 if (result.config.upgrade_opts == NULL) {
216 die(STATE_UNKNOWN, "strdup failed"); 214 die(STATE_UNKNOWN, "strdup failed");
217 } 215 }
218 } 216 }
219 break; 217 break;
220 case 'U': 218 case 'U':
221 upgrade = UPGRADE; 219 result.config.upgrade = UPGRADE;
222 if (optarg != NULL) { 220 if (optarg != NULL) {
223 upgrade_opts = strdup(optarg); 221 result.config.upgrade_opts = strdup(optarg);
224 if (upgrade_opts == NULL) { 222 if (result.config.upgrade_opts == NULL) {
225 die(STATE_UNKNOWN, "strdup failed"); 223 die(STATE_UNKNOWN, "strdup failed");
226 } 224 }
227 } 225 }
228 break; 226 break;
229 case 'n': 227 case 'n':
230 upgrade = NO_UPGRADE; 228 result.config.upgrade = NO_UPGRADE;
231 break; 229 break;
232 case 'u': 230 case 'u':
233 do_update = true; 231 result.config.do_update = true;
234 if (optarg != NULL) { 232 if (optarg != NULL) {
235 update_opts = strdup(optarg); 233 result.config.update_opts = strdup(optarg);
236 if (update_opts == NULL) { 234 if (result.config.update_opts == NULL) {
237 die(STATE_UNKNOWN, "strdup failed"); 235 die(STATE_UNKNOWN, "strdup failed");
238 } 236 }
239 } 237 }
240 break; 238 break;
241 case 'l': 239 case 'l':
242 list = true; 240 result.config.list = true;
243 break; 241 break;
244 case 'i': 242 case 'i':
245 do_include = add_to_regexp(do_include, optarg); 243 result.config.do_include = add_to_regexp(result.config.do_include, optarg);
246 break; 244 break;
247 case 'e': 245 case 'e':
248 do_exclude = add_to_regexp(do_exclude, optarg); 246 result.config.do_exclude = add_to_regexp(result.config.do_exclude, optarg);
249 break; 247 break;
250 case 'c': 248 case 'c':
251 do_critical = add_to_regexp(do_critical, optarg); 249 result.config.do_critical = add_to_regexp(result.config.do_critical, optarg);
252 break; 250 break;
253 case 'o': 251 case 'o':
254 only_critical = true; 252 result.config.only_critical = true;
255 break; 253 break;
256 case INPUT_FILE_OPT: 254 case INPUT_FILE_OPT:
257 input_filename = optarg; 255 result.config.input_filename = optarg;
258 break; 256 break;
259 case 'w': 257 case 'w':
260 packages_warning = atoi(optarg); 258 result.config.packages_warning = atoi(optarg);
261 break; 259 break;
262 default: 260 default:
263 /* print short usage statement if args not parsable */ 261 /* print short usage statement if args not parsable */
@@ -265,11 +263,12 @@ int process_arguments(int argc, char **argv) {
265 } 263 }
266 } 264 }
267 265
268 return OK; 266 return result;
269} 267}
270 268
271/* run an apt-get upgrade */ 269/* run an apt-get upgrade */
272run_upgrade_result run_upgrade(void) { 270run_upgrade_result run_upgrade(const upgrade_type upgrade, const char *do_include, const char *do_exclude, const char *do_critical,
271 const char *upgrade_opts, const char *input_filename) {
273 regex_t ereg; 272 regex_t ereg;
274 /* initialize ereg as it is possible it is printed while uninitialized */ 273 /* initialize ereg as it is possible it is printed while uninitialized */
275 memset(&ereg, '\0', sizeof(ereg.buffer)); 274 memset(&ereg, '\0', sizeof(ereg.buffer));
@@ -332,7 +331,7 @@ run_upgrade_result run_upgrade(void) {
332 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline); 331 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
333 } 332 }
334 333
335 char **pkglist = malloc(sizeof(char *) * chld_out.lines); 334 char **pkglist = malloc(sizeof(char *) * chld_out.lines);
336 if (!pkglist) { 335 if (!pkglist) {
337 die(STATE_UNKNOWN, "malloc failed!\n"); 336 die(STATE_UNKNOWN, "malloc failed!\n");
338 } 337 }
@@ -385,7 +384,7 @@ run_upgrade_result run_upgrade(void) {
385 384
386 /* If we get anything on stderr, at least set warning */ 385 /* If we get anything on stderr, at least set warning */
387 if (input_filename == NULL && chld_err.buflen) { 386 if (input_filename == NULL && chld_err.buflen) {
388 stderr_warning = 1; 387 stderr_warning = true;
389 result.errorcode = max_state(result.errorcode, STATE_WARNING); 388 result.errorcode = max_state(result.errorcode, STATE_WARNING);
390 if (verbose) { 389 if (verbose) {
391 for (size_t i = 0; i < chld_err.lines; i++) { 390 for (size_t i = 0; i < chld_err.lines; i++) {
@@ -405,7 +404,7 @@ run_upgrade_result run_upgrade(void) {
405} 404}
406 405
407/* run an apt-get update (needs root) */ 406/* run an apt-get update (needs root) */
408int run_update(void) { 407int run_update(char *update_opts) {
409 int result = STATE_UNKNOWN; 408 int result = STATE_UNKNOWN;
410 char *cmdline; 409 char *cmdline;
411 /* run the update */ 410 /* run the update */
@@ -418,7 +417,7 @@ int run_update(void) {
418 * 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
419 * a critical error. */ 418 * a critical error. */
420 if (result != 0) { 419 if (result != 0) {
421 exec_warning = 1; 420 exec_warning = true;
422 result = STATE_CRITICAL; 421 result = STATE_CRITICAL;
423 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline); 422 fprintf(stderr, _("'%s' exited with non-zero status.\n"), cmdline);
424 } 423 }
@@ -446,7 +445,7 @@ int run_update(void) {
446char *pkg_name(char *line) { 445char *pkg_name(char *line) {
447 char *start = line + strlen(PKGINST_PREFIX); 446 char *start = line + strlen(PKGINST_PREFIX);
448 447
449 int len = strlen(start); 448 size_t len = strlen(start);
450 449
451 char *space = index(start, ' '); 450 char *space = index(start, ' ');
452 if (space != NULL) { 451 if (space != NULL) {
@@ -464,35 +463,37 @@ char *pkg_name(char *line) {
464 return pkg; 463 return pkg;
465} 464}
466 465
467int cmpstringp(const void *p1, const void *p2) { return strcmp(*(char *const *)p1, *(char *const *)p2); } 466int cmpstringp(const void *left_string, const void *right_string) {
467 return strcmp(*(char *const *)left_string, *(char *const *)right_string);
468}
468 469
469char *add_to_regexp(char *expr, const char *next) { 470char *add_to_regexp(char *expr, const char *next) {
470 char *re = NULL; 471 char *regex_string = NULL;
471 472
472 if (expr == NULL) { 473 if (expr == NULL) {
473 re = malloc(sizeof(char) * (strlen("()") + strlen(next) + 1)); 474 regex_string = malloc(sizeof(char) * (strlen("()") + strlen(next) + 1));
474 if (!re) { 475 if (!regex_string) {
475 die(STATE_UNKNOWN, "malloc failed!\n"); 476 die(STATE_UNKNOWN, "malloc failed!\n");
476 } 477 }
477 sprintf(re, "(%s)", next); 478 sprintf(regex_string, "(%s)", next);
478 } else { 479 } else {
479 /* resize it, adding an extra char for the new '|' separator */ 480 /* resize it, adding an extra char for the new '|' separator */
480 re = realloc(expr, sizeof(char) * (strlen(expr) + 1 + strlen(next) + 1)); 481 regex_string = realloc(expr, sizeof(char) * (strlen(expr) + 1 + strlen(next) + 1));
481 if (!re) { 482 if (!regex_string) {
482 die(STATE_UNKNOWN, "realloc failed!\n"); 483 die(STATE_UNKNOWN, "realloc failed!\n");
483 } 484 }
484 /* append it starting at ')' in the old re */ 485 /* append it starting at ')' in the old re */
485 sprintf((char *)(re + strlen(re) - 1), "|%s)", next); 486 sprintf((char *)(regex_string + strlen(regex_string) - 1), "|%s)", next);
486 } 487 }
487 488
488 return re; 489 return regex_string;
489} 490}
490 491
491char *construct_cmdline(upgrade_type u, const char *opts) { 492char *construct_cmdline(upgrade_type upgrade, const char *opts) {
492 const char *opts_ptr = NULL; 493 const char *opts_ptr = NULL;
493 const char *aptcmd = NULL; 494 const char *aptcmd = NULL;
494 495
495 switch (u) { 496 switch (upgrade) {
496 case UPGRADE: 497 case UPGRADE:
497 if (opts == NULL) { 498 if (opts == NULL) {
498 opts_ptr = UPGRADE_DEFAULT_OPTS; 499 opts_ptr = UPGRADE_DEFAULT_OPTS;
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 2ac7805d..2bc38d49 100644
--- a/plugins/check_by_ssh.c
+++ b/plugins/check_by_ssh.c
@@ -32,48 +32,28 @@ const 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
42static int process_arguments(int /*argc*/, char ** /*argv*/); 43typedef struct {
43static int validate_arguments(void); 44 int errorcode;
44static void comm_append(const char * /*str*/); 45 check_by_ssh_config config;
46} check_by_ssh_config_wrapper;
47static check_by_ssh_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
48static check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper /*config_wrapper*/);
49
50static command_construct comm_append(command_construct /*cmd*/, const char * /*str*/);
45static void print_help(void); 51static void print_help(void);
46void print_usage(void); 52void print_usage(void);
47 53
48static unsigned int commands = 0;
49static unsigned int services = 0;
50static int skip_stdout = 0;
51static int skip_stderr = 0;
52static int warn_on_stderr = 0;
53static bool unknown_timeout = false;
54static char *remotecmd = NULL;
55static char **commargv = NULL;
56static int commargc = 0;
57static char *hostname = NULL;
58static char *outputfile = NULL;
59static char *host_shortname = NULL;
60static char **service;
61static bool passive = false;
62static bool verbose = false; 54static bool verbose = false;
63 55
64int main(int argc, char **argv) { 56int main(int argc, char **argv) {
65
66 char *status_text;
67 int cresult;
68 int result = STATE_UNKNOWN;
69 time_t local_time;
70 FILE *file_pointer = NULL;
71 output chld_out;
72 output chld_err;
73
74 remotecmd = "";
75 comm_append(SSH_COMMAND);
76
77 setlocale(LC_ALL, ""); 57 setlocale(LC_ALL, "");
78 bindtextdomain(PACKAGE, LOCALEDIR); 58 bindtextdomain(PACKAGE, LOCALEDIR);
79 textdomain(PACKAGE); 59 textdomain(PACKAGE);
@@ -81,11 +61,15 @@ int main(int argc, char **argv) {
81 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
82 argv = np_extra_opts(&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
83 63
64 check_by_ssh_config_wrapper tmp_config = process_arguments(argc, argv);
65
84 /* process arguments */ 66 /* process arguments */
85 if (process_arguments(argc, argv) == ERROR) { 67 if (tmp_config.errorcode == ERROR) {
86 usage_va(_("Could not parse arguments")); 68 usage_va(_("Could not parse arguments"));
87 } 69 }
88 70
71 const check_by_ssh_config config = tmp_config.config;
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"));
@@ -94,16 +78,18 @@ int main(int argc, char **argv) {
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]);
100 } 84 }
101 } 85 }
102 86
103 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);
104 90
105 /* 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 */
106 if (result == 255 && unknown_timeout) { 92 if (result == 255 && config.unknown_timeout) {
107 printf(_("SSH connection failed: %s\n"), chld_err.lines > 0 ? chld_err.line[0] : "(no error output)"); 93 printf(_("SSH connection failed: %s\n"), chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
108 return STATE_UNKNOWN; 94 return STATE_UNKNOWN;
109 } 95 }
@@ -117,17 +103,24 @@ int main(int argc, char **argv) {
117 } 103 }
118 } 104 }
119 105
120 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 */
121 skip_stdout = chld_out.lines; 108 skip_stdout = chld_out.lines;
109 } else {
110 skip_stdout = config.skip_stdout;
122 } 111 }
123 if (skip_stderr == -1) { /* --skip-stderr specified without argument */ 112
113 size_t skip_stderr = 0;
114 if (config.skip_stderr == -1) { /* --skip-stderr specified without argument */
124 skip_stderr = chld_err.lines; 115 skip_stderr = chld_err.lines;
116 } else {
117 skip_stderr = config.skip_stderr;
125 } 118 }
126 119
127 /* UNKNOWN or worse if (non-skipped) output found on stderr */ 120 /* UNKNOWN or worse if (non-skipped) output found on stderr */
128 if (chld_err.lines > (size_t)skip_stderr) { 121 if (chld_err.lines > (size_t)skip_stderr) {
129 printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]); 122 printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]);
130 if (warn_on_stderr) { 123 if (config.warn_on_stderr) {
131 return max_state_alt(result, STATE_WARNING); 124 return max_state_alt(result, STATE_WARNING);
132 } 125 }
133 return max_state_alt(result, STATE_UNKNOWN); 126 return max_state_alt(result, STATE_UNKNOWN);
@@ -135,13 +128,13 @@ int main(int argc, char **argv) {
135 128
136 /* this is simple if we're not supposed to be passive. 129 /* this is simple if we're not supposed to be passive.
137 * Wrap up quickly and keep the tricks below */ 130 * Wrap up quickly and keep the tricks below */
138 if (!passive) { 131 if (!config.passive) {
139 if (chld_out.lines > (size_t)skip_stdout) { 132 if (chld_out.lines > (size_t)skip_stdout) {
140 for (size_t i = skip_stdout; i < chld_out.lines; i++) { 133 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
141 puts(chld_out.line[i]); 134 puts(chld_out.line[i]);
142 } 135 }
143 } else { 136 } else {
144 printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), state_text(result), remotecmd, result); 137 printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), state_text(result), config.remotecmd, result);
145 } 138 }
146 return result; /* return error status from remote command */ 139 return result; /* return error status from remote command */
147 } 140 }
@@ -151,36 +144,34 @@ int main(int argc, char **argv) {
151 */ 144 */
152 145
153 /* process output */ 146 /* process output */
154 if (!(file_pointer = fopen(outputfile, "a"))) { 147 FILE *file_pointer = NULL;
155 printf(_("SSH WARNING: could not open %s\n"), outputfile); 148 if (!(file_pointer = fopen(config.outputfile, "a"))) {
149 printf(_("SSH WARNING: could not open %s\n"), config.outputfile);
156 exit(STATE_UNKNOWN); 150 exit(STATE_UNKNOWN);
157 } 151 }
158 152
159 local_time = time(NULL); 153 time_t local_time = time(NULL);
160 commands = 0; 154 unsigned int commands = 0;
155 char *status_text;
156 int cresult;
161 for (size_t i = skip_stdout; i < chld_out.lines; i++) { 157 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
162 status_text = chld_out.line[i++]; 158 status_text = chld_out.line[i++];
163 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) {
164 die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname); 160 die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname);
165 } 161 }
166 162
167 if (service[commands] && status_text && 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) {
168 fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, host_shortname, service[commands++], 164 fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, config.host_shortname,
169 cresult, status_text); 165 config.service[commands++], cresult, status_text);
170 } 166 }
171 } 167 }
172 168
173 /* Multiple commands and passive checking should always return OK */ 169 /* Multiple commands and passive checking should always return OK */
174 return result; 170 exit(result);
175} 171}
176 172
177/* process command-line arguments */ 173/* process command-line arguments */
178int process_arguments(int argc, char **argv) { 174check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
179 int c;
180 char *p1;
181 char *p2;
182
183 int option = 0;
184 static struct option longopts[] = {{"version", no_argument, 0, 'V'}, 175 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
185 {"help", no_argument, 0, 'h'}, 176 {"help", no_argument, 0, 'h'},
186 {"verbose", no_argument, 0, 'v'}, 177 {"verbose", no_argument, 0, 'v'},
@@ -210,24 +201,33 @@ int process_arguments(int argc, char **argv) {
210 {"configfile", optional_argument, 0, 'F'}, 201 {"configfile", optional_argument, 0, 'F'},
211 {0, 0, 0, 0}}; 202 {0, 0, 0, 0}};
212 203
204 check_by_ssh_config_wrapper result = {
205 .errorcode = OK,
206 .config = check_by_ssh_config_init(),
207 };
208
213 if (argc < 2) { 209 if (argc < 2) {
214 return ERROR; 210 result.errorcode = ERROR;
211 return result;
215 } 212 }
216 213
217 for (c = 1; c < argc; c++) { 214 for (int index = 1; index < argc; index++) {
218 if (strcmp("-to", argv[c]) == 0) { 215 if (strcmp("-to", argv[index]) == 0) {
219 strcpy(argv[c], "-t"); 216 strcpy(argv[index], "-t");
220 } 217 }
221 } 218 }
222 219
223 while (1) { 220 result.config.cmd = comm_append(result.config.cmd, SSH_COMMAND);
224 c = getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option);
225 221
226 if (c == -1 || c == EOF) { 222 int option = 0;
223 while (true) {
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
226 if (opt_index == -1 || opt_index == EOF) {
227 break; 227 break;
228 } 228 }
229 229
230 switch (c) { 230 switch (opt_index) {
231 case 'V': /* version */ 231 case 'V': /* version */
232 print_revision(progname, NP_VERSION); 232 print_revision(progname, NP_VERSION);
233 exit(STATE_UNKNOWN); 233 exit(STATE_UNKNOWN);
@@ -245,169 +245,182 @@ int process_arguments(int argc, char **argv) {
245 } 245 }
246 break; 246 break;
247 case 'U': 247 case 'U':
248 unknown_timeout = true; 248 result.config.unknown_timeout = true;
249 break; 249 break;
250 case 'H': /* host */ 250 case 'H': /* host */
251 hostname = optarg; 251 result.config.hostname = optarg;
252 break; 252 break;
253 case 'p': /* port number */ 253 case 'p': /* port number */
254 if (!is_integer(optarg)) { 254 if (!is_integer(optarg)) {
255 usage_va(_("Port must be a positive integer")); 255 usage_va(_("Port must be a positive integer"));
256 } 256 }
257 comm_append("-p"); 257 result.config.cmd = comm_append(result.config.cmd, "-p");
258 comm_append(optarg); 258 result.config.cmd = comm_append(result.config.cmd, optarg);
259 break; 259 break;
260 case 'O': /* output file */ 260 case 'O': /* output file */
261 outputfile = optarg; 261 result.config.outputfile = optarg;
262 passive = true; 262 result.config.passive = true;
263 break; 263 break;
264 case 's': /* description of service to check */ 264 case 's': /* description of service to check */ {
265 char *p1;
266 char *p2;
267
265 p1 = optarg; 268 p1 = optarg;
266 service = realloc(service, (++services) * sizeof(char *)); 269 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
267 while ((p2 = index(p1, ':'))) { 270 while ((p2 = index(p1, ':'))) {
268 *p2 = '\0'; 271 *p2 = '\0';
269 service[services - 1] = p1; 272 result.config.service[result.config.number_of_services - 1] = p1;
270 service = realloc(service, (++services) * sizeof(char *)); 273 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
271 p1 = p2 + 1; 274 p1 = p2 + 1;
272 } 275 }
273 service[services - 1] = p1; 276 result.config.service[result.config.number_of_services - 1] = p1;
274 break; 277 break;
275 case 'n': /* short name of host in the monitoring configuration */ 278 case 'n': /* short name of host in the monitoring configuration */
276 host_shortname = optarg; 279 result.config.host_shortname = optarg;
277 break; 280 } break;
278
279 case 'u': 281 case 'u':
280 comm_append("-l"); 282 result.config.cmd = comm_append(result.config.cmd, "-l");
281 comm_append(optarg); 283 result.config.cmd = comm_append(result.config.cmd, optarg);
282 break; 284 break;
283 case 'l': /* login name */ 285 case 'l': /* login name */
284 comm_append("-l"); 286 result.config.cmd = comm_append(result.config.cmd, "-l");
285 comm_append(optarg); 287 result.config.cmd = comm_append(result.config.cmd, optarg);
286 break; 288 break;
287 case 'i': /* identity */ 289 case 'i': /* identity */
288 comm_append("-i"); 290 result.config.cmd = comm_append(result.config.cmd, "-i");
289 comm_append(optarg); 291 result.config.cmd = comm_append(result.config.cmd, optarg);
290 break; 292 break;
291 293
292 case '1': /* Pass these switches directly to ssh */ 294 case '1': /* Pass these switches directly to ssh */
293 comm_append("-1"); 295 result.config.cmd = comm_append(result.config.cmd, "-1");
294 break; 296 break;
295 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 */
296 comm_append("-2"); 298 result.config.cmd = comm_append(result.config.cmd, "-2");
297 break; 299 break;
298 case '4': /* -4 for IPv4 */ 300 case '4': /* -4 for IPv4 */
299 comm_append("-4"); 301 result.config.cmd = comm_append(result.config.cmd, "-4");
300 break; 302 break;
301 case '6': /* -6 for IPv6 */ 303 case '6': /* -6 for IPv6 */
302 comm_append("-6"); 304 result.config.cmd = comm_append(result.config.cmd, "-6");
303 break; 305 break;
304 case 'f': /* fork to background */ 306 case 'f': /* fork to background */
305 comm_append("-f"); 307 result.config.cmd = comm_append(result.config.cmd, "-f");
306 break; 308 break;
307 case 'C': /* Command for remote machine */ 309 case 'C': /* Command for remote machine */
308 commands++; 310 result.config.commands++;
309 if (commands > 1) { 311 if (result.config.commands > 1) {
310 xasprintf(&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 312 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
311 } 313 }
312 xasprintf(&remotecmd, "%s%s", remotecmd, optarg); 314 xasprintf(&result.config.remotecmd, "%s%s", result.config.remotecmd, optarg);
313 break; 315 break;
314 case 'S': /* skip n (or all) lines on stdout */ 316 case 'S': /* skip n (or all) lines on stdout */
315 if (optarg == NULL) { 317 if (optarg == NULL) {
316 skip_stdout = -1; /* skip all output on stdout */ 318 result.config.skip_stdout = -1; /* skip all output on stdout */
317 } else if (!is_integer(optarg)) { 319 } else if (!is_integer(optarg)) {
318 usage_va(_("skip-stdout argument must be an integer")); 320 usage_va(_("skip-stdout argument must be an integer"));
319 } else { 321 } else {
320 skip_stdout = atoi(optarg); 322 result.config.skip_stdout = atoi(optarg);
321 } 323 }
322 break; 324 break;
323 case 'E': /* skip n (or all) lines on stderr */ 325 case 'E': /* skip n (or all) lines on stderr */
324 if (optarg == NULL) { 326 if (optarg == NULL) {
325 skip_stderr = -1; /* skip all output on stderr */ 327 result.config.skip_stderr = -1; /* skip all output on stderr */
326 } else if (!is_integer(optarg)) { 328 } else if (!is_integer(optarg)) {
327 usage_va(_("skip-stderr argument must be an integer")); 329 usage_va(_("skip-stderr argument must be an integer"));
328 } else { 330 } else {
329 skip_stderr = atoi(optarg); 331 result.config.skip_stderr = atoi(optarg);
330 } 332 }
331 break; 333 break;
332 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 */
333 warn_on_stderr = 1; 335 result.config.warn_on_stderr = true;
334 break; 336 break;
335 case 'o': /* Extra options for the ssh command */ 337 case 'o': /* Extra options for the ssh command */
336 comm_append("-o"); 338 result.config.cmd = comm_append(result.config.cmd, "-o");
337 comm_append(optarg); 339 result.config.cmd = comm_append(result.config.cmd, optarg);
338 break; 340 break;
339 case 'q': /* Tell the ssh command to be quiet */ 341 case 'q': /* Tell the ssh command to be quiet */
340 comm_append("-q"); 342 result.config.cmd = comm_append(result.config.cmd, "-q");
341 break; 343 break;
342 case 'F': /* ssh configfile */ 344 case 'F': /* ssh configfile */
343 comm_append("-F"); 345 result.config.cmd = comm_append(result.config.cmd, "-F");
344 comm_append(optarg); 346 result.config.cmd = comm_append(result.config.cmd, optarg);
345 break; 347 break;
346 default: /* help */ 348 default: /* help */
347 usage5(); 349 usage5();
348 } 350 }
349 } 351 }
350 352
351 c = optind; 353 int c = optind;
352 if (hostname == NULL) { 354 if (result.config.hostname == NULL) {
353 if (c <= argc) { 355 if (c <= argc) {
354 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);
355 } 357 }
356 hostname = argv[c++]; 358 result.config.hostname = argv[c++];
357 } 359 }
358 360
359 if (strlen(remotecmd) == 0) { 361 if (strlen(result.config.remotecmd) == 0) {
360 for (; c < argc; c++) { 362 for (; c < argc; c++) {
361 if (strlen(remotecmd) > 0) { 363 if (strlen(result.config.remotecmd) > 0) {
362 xasprintf(&remotecmd, "%s %s", remotecmd, argv[c]); 364 xasprintf(&result.config.remotecmd, "%s %s", result.config.remotecmd, argv[c]);
363 } else { 365 } else {
364 xasprintf(&remotecmd, "%s", argv[c]); 366 xasprintf(&result.config.remotecmd, "%s", argv[c]);
365 } 367 }
366 } 368 }
367 } 369 }
368 370
369 if (commands > 1 || passive) { 371 if (result.config.commands > 1 || result.config.passive) {
370 xasprintf(&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 372 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
371 } 373 }
372 374
373 if (remotecmd == NULL || strlen(remotecmd) <= 1) { 375 if (result.config.remotecmd == NULL || strlen(result.config.remotecmd) <= 1) {
374 usage_va(_("No remotecmd")); 376 usage_va(_("No remotecmd"));
375 } 377 }
376 378
377 comm_append(hostname); 379 result.config.cmd = comm_append(result.config.cmd, result.config.hostname);
378 comm_append(remotecmd); 380 result.config.cmd = comm_append(result.config.cmd, result.config.remotecmd);
379 381
380 return validate_arguments(); 382 return validate_arguments(result);
381} 383}
382 384
383void comm_append(const char *str) { 385command_construct comm_append(command_construct cmd, const char *str) {
386
387 if (verbose) {
388 for (int i = 0; i < cmd.commargc; i++) {
389 printf("Current command: [%i] %s\n", i, cmd.commargv[i]);
390 }
384 391
385 if (++commargc > NP_MAXARGS) { 392 printf("Appending: %s\n", str);
393 }
394
395 if (++cmd.commargc > NP_MAXARGS) {
386 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);
387 } 397 }
388 398
389 if ((commargv = (char **)realloc(commargv, (commargc + 1) * sizeof(char *))) == NULL) { 399 if ((cmd.commargv = (char **)realloc(cmd.commargv, (cmd.commargc + 1) * sizeof(char *))) == NULL) {
390 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n")); 400 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n"));
391 } 401 }
392 402
393 commargv[commargc - 1] = strdup(str); 403 cmd.commargv[cmd.commargc - 1] = strdup(str);
394 commargv[commargc] = NULL; 404 cmd.commargv[cmd.commargc] = NULL;
405
406 return cmd;
395} 407}
396 408
397int validate_arguments(void) { 409check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper config_wrapper) {
398 if (remotecmd == NULL || hostname == NULL) { 410 if (config_wrapper.config.remotecmd == NULL || config_wrapper.config.hostname == NULL) {
399 return ERROR; 411 config_wrapper.errorcode = ERROR;
412 return config_wrapper;
400 } 413 }
401 414
402 if (passive && commands != services) { 415 if (config_wrapper.config.passive && config_wrapper.config.commands != config_wrapper.config.number_of_services) {
403 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);
404 } 417 }
405 418
406 if (passive && host_shortname == NULL) { 419 if (config_wrapper.config.passive && config_wrapper.config.host_shortname == NULL) {
407 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);
408 } 421 }
409 422
410 return OK; 423 return config_wrapper;
411} 424}
412 425
413void print_help(void) { 426void print_help(void) {
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 b40c38c7..9b695499 100644
--- a/plugins/check_cluster.c
+++ b/plugins/check_cluster.c
@@ -29,42 +29,20 @@ const char *email = "devel@monitoring-plugins.org";
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 32#include "check_cluster.d/config.h"
33enum {
34 CHECK_SERVICES = 1,
35 CHECK_HOSTS = 2
36};
37 33
38static void print_help(void); 34static void print_help(void);
39void print_usage(void); 35void print_usage(void);
40 36
41static int total_services_ok = 0;
42static int total_services_warning = 0;
43static int total_services_unknown = 0;
44static int total_services_critical = 0;
45
46static int total_hosts_up = 0;
47static int total_hosts_down = 0;
48static int total_hosts_unreachable = 0;
49
50static char *warn_threshold;
51static char *crit_threshold;
52
53static int check_type = CHECK_SERVICES;
54
55static char *data_vals = NULL;
56static char *label = NULL;
57
58static int verbose = 0; 37static int verbose = 0;
59 38
60static int process_arguments(int /*argc*/, char ** /*argv*/); 39typedef struct {
40 int errorcode;
41 check_cluster_config config;
42} check_cluster_config_wrapper;
43static check_cluster_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
61 44
62int main(int argc, char **argv) { 45int 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, ""); 46 setlocale(LC_ALL, "");
69 bindtextdomain(PACKAGE, LOCALEDIR); 47 bindtextdomain(PACKAGE, LOCALEDIR);
70 textdomain(PACKAGE); 48 textdomain(PACKAGE);
@@ -72,20 +50,32 @@ int main(int argc, char **argv) {
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++;
@@ -119,101 +109,108 @@ int main(int argc, char **argv) {
119 } 109 }
120 } 110 }
121 111
112 int return_code = STATE_OK;
122 /* return the status of the cluster */ 113 /* return the status of the cluster */
123 if (check_type == CHECK_SERVICES) { 114 if (config.check_type == CHECK_SERVICES) {
124 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);
125 printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", state_text(return_code), 116 printf("CLUSTER %s: %s: %d ok, %d warning, %d unknown, %d critical\n", state_text(return_code),
126 (label == NULL) ? "Service cluster" : label, total_services_ok, total_services_warning, total_services_unknown, 117 (config.label == NULL) ? "Service cluster" : config.label, total_services_ok, total_services_warning, total_services_unknown,
127 total_services_critical); 118 total_services_critical);
128 } else { 119 } else {
129 return_code = get_status(total_hosts_down + total_hosts_unreachable, thresholds); 120 return_code = get_status(total_hosts_down + total_hosts_unreachable, config.thresholds);
130 printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n", state_text(return_code), (label == NULL) ? "Host cluster" : label, 121 printf("CLUSTER %s: %s: %d up, %d down, %d unreachable\n", state_text(return_code),
131 total_hosts_up, total_hosts_down, total_hosts_unreachable); 122 (config.label == NULL) ? "Host cluster" : config.label, total_hosts_up, total_hosts_down, total_hosts_unreachable);
132 } 123 }
133 124
134 return return_code; 125 exit(return_code);
135} 126}
136 127
137int process_arguments(int argc, char **argv) { 128check_cluster_config_wrapper process_arguments(int argc, char **argv) {
138 int c;
139 char *ptr;
140 int option = 0;
141 static struct option longopts[] = {{"data", required_argument, 0, 'd'}, {"warning", required_argument, 0, 'w'}, 129 static struct option longopts[] = {{"data", required_argument, 0, 'd'}, {"warning", required_argument, 0, 'w'},
142 {"critical", required_argument, 0, 'c'}, {"label", required_argument, 0, 'l'}, 130 {"critical", required_argument, 0, 'c'}, {"label", required_argument, 0, 'l'},
143 {"host", no_argument, 0, 'h'}, {"service", no_argument, 0, 's'}, 131 {"host", no_argument, 0, 'h'}, {"service", no_argument, 0, 's'},
144 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, 132 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
145 {"help", no_argument, 0, 'H'}, {0, 0, 0, 0}}; 133 {"help", no_argument, 0, 'H'}, {0, 0, 0, 0}};
146 134
147 /* no options were supplied */ 135 check_cluster_config_wrapper result = {
148 if (argc < 2) 136 .errorcode = OK,
149 return ERROR; 137 .config = check_cluster_config_init(),
138 };
150 139
151 while (1) { 140 /* no options were supplied */
141 if (argc < 2) {
142 result.errorcode = ERROR;
143 return result;
144 }
152 145
153 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);
154 151
155 if (c == -1 || c == EOF || c == 1) 152 if (option_index == -1 || option_index == EOF || option_index == 1) {
156 break; 153 break;
154 }
157 155
158 switch (c) { 156 switch (option_index) {
159
160 case 'h': /* host cluster */ 157 case 'h': /* host cluster */
161 check_type = CHECK_HOSTS; 158 result.config.check_type = CHECK_HOSTS;
162 break; 159 break;
163
164 case 's': /* service cluster */ 160 case 's': /* service cluster */
165 check_type = CHECK_SERVICES; 161 result.config.check_type = CHECK_SERVICES;
166 break; 162 break;
167
168 case 'w': /* warning threshold */ 163 case 'w': /* warning threshold */
169 warn_threshold = strdup(optarg); 164 warn_threshold = strdup(optarg);
170 break; 165 break;
171
172 case 'c': /* warning threshold */ 166 case 'c': /* warning threshold */
173 crit_threshold = strdup(optarg); 167 crit_threshold = strdup(optarg);
174 break; 168 break;
175
176 case 'd': /* data values */ 169 case 'd': /* data values */
177 data_vals = (char *)strdup(optarg); 170 result.config.data_vals = strdup(optarg);
178 /* validate data */ 171 /* validate data */
179 for (ptr = data_vals; ptr != NULL; ptr += 2) { 172 for (char *ptr = result.config.data_vals; ptr != NULL; ptr += 2) {
180 if (ptr[0] < '0' || ptr[0] > '3') 173 if (ptr[0] < '0' || ptr[0] > '3') {
181 return ERROR; 174 result.errorcode = ERROR;
182 if (ptr[1] == '\0') 175 return result;
176 }
177 if (ptr[1] == '\0') {
183 break; 178 break;
184 if (ptr[1] != ',') 179 }
185 return ERROR; 180 if (ptr[1] != ',') {
181 result.errorcode = ERROR;
182 return result;
183 }
186 } 184 }
187 break; 185 break;
188
189 case 'l': /* text label */ 186 case 'l': /* text label */
190 label = (char *)strdup(optarg); 187 result.config.label = strdup(optarg);
191 break; 188 break;
192
193 case 'v': /* verbose */ 189 case 'v': /* verbose */
194 verbose++; 190 verbose++;
195 break; 191 break;
196
197 case 'V': /* version */ 192 case 'V': /* version */
198 print_revision(progname, NP_VERSION); 193 print_revision(progname, NP_VERSION);
199 exit(STATE_UNKNOWN); 194 exit(STATE_UNKNOWN);
200 break; 195 break;
201
202 case 'H': /* help */ 196 case 'H': /* help */
203 print_help(); 197 print_help();
204 exit(STATE_UNKNOWN); 198 exit(STATE_UNKNOWN);
205 break; 199 break;
206
207 default: 200 default:
208 return ERROR; 201 result.errorcode = ERROR;
202 return result;
209 break; 203 break;
210 } 204 }
211 } 205 }
212 206
213 if (data_vals == NULL) 207 if (result.config.data_vals == NULL) {
214 return ERROR; 208 result.errorcode = ERROR;
209 return result;
210 }
215 211
216 return OK; 212 set_thresholds(&result.config.thresholds, warn_threshold, crit_threshold);
213 return result;
217} 214}
218 215
219void print_help(void) { 216void print_help(void) {
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_dbi.c b/plugins/check_dbi.c
index 96575672..9efcd1cb 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -33,6 +33,8 @@ const char *progname = "check_dbi";
33const char *copyright = "2011-2024"; 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"
@@ -53,55 +55,24 @@ const char *email = "devel@monitoring-plugins.org";
53 55
54#include <stdarg.h> 56#include <stdarg.h>
55 57
56typedef enum {
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
68typedef struct {
69 char *key;
70 char *value;
71} driver_option_t;
72
73static char *host = NULL;
74static int verbose = 0; 58static int verbose = 0;
75 59
76static char *warning_range = NULL; 60typedef struct {
77static char *critical_range = NULL; 61 int errorcode;
78static thresholds *dbi_thresholds = NULL; 62 check_dbi_config config;
79 63} check_dbi_config_wrapper;
80static char *expect = NULL;
81
82static regex_t expect_re;
83static char *expect_re_str = NULL;
84static int expect_re_cflags = 0;
85
86static np_dbi_metric_t metric = METRIC_QUERY_RESULT;
87static np_dbi_type_t type = TYPE_NUMERIC;
88
89static char *np_dbi_driver = NULL;
90static driver_option_t *np_dbi_options = NULL;
91static int np_dbi_options_num = 0;
92static char *np_dbi_database = NULL;
93static char *np_dbi_query = NULL;
94 64
95static int process_arguments(int, char **); 65static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
96static int validate_arguments(void); 66static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/);
97void print_usage(void); 67void print_usage(void);
98static void print_help(void); 68static void print_help(void);
99 69
100static double timediff(struct timeval, struct timeval); 70static double timediff(struct timeval /*start*/, struct timeval /*end*/);
101 71
102static void np_dbi_print_error(dbi_conn, char *, ...); 72static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
103 73
104static int do_query(dbi_conn, const char **, double *, double *); 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*/);
105 76
106int main(int argc, char **argv) { 77int main(int argc, char **argv) {
107 int status = STATE_UNKNOWN; 78 int status = STATE_UNKNOWN;
@@ -119,8 +90,6 @@ int main(int argc, char **argv) {
119 const char *query_val_str = NULL; 90 const char *query_val_str = NULL;
120 double query_val = 0.0; 91 double query_val = 0.0;
121 92
122 int i;
123
124 setlocale(LC_ALL, ""); 93 setlocale(LC_ALL, "");
125 bindtextdomain(PACKAGE, LOCALEDIR); 94 bindtextdomain(PACKAGE, LOCALEDIR);
126 textdomain(PACKAGE); 95 textdomain(PACKAGE);
@@ -128,8 +97,13 @@ int main(int argc, char **argv) {
128 /* Parse extra opts if any */ 97 /* Parse extra opts if any */
129 argv = np_extra_opts(&argc, argv, progname); 98 argv = np_extra_opts(&argc, argv, progname);
130 99
131 if (process_arguments(argc, argv) == ERROR) 100 check_dbi_config_wrapper tmp = process_arguments(argc, argv);
101
102 if (tmp.errorcode == ERROR) {
132 usage4(_("Could not parse arguments")); 103 usage4(_("Could not parse arguments"));
104 }
105
106 const check_dbi_config config = tmp.config;
133 107
134 /* Set signal handling and alarm */ 108 /* Set signal handling and alarm */
135 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 109 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
@@ -137,8 +111,9 @@ int main(int argc, char **argv) {
137 } 111 }
138 alarm(timeout_interval); 112 alarm(timeout_interval);
139 113
140 if (verbose > 2) 114 if (verbose > 2) {
141 printf("Initializing DBI\n"); 115 printf("Initializing DBI\n");
116 }
142 117
143 dbi_inst *instance_p = {0}; 118 dbi_inst *instance_p = {0};
144 119
@@ -152,12 +127,13 @@ int main(int argc, char **argv) {
152 return STATE_UNKNOWN; 127 return STATE_UNKNOWN;
153 } 128 }
154 129
155 if (verbose) 130 if (verbose) {
156 printf("Opening DBI driver '%s'\n", np_dbi_driver); 131 printf("Opening DBI driver '%s'\n", config.dbi_driver);
132 }
157 133
158 driver = dbi_driver_open_r(np_dbi_driver, instance_p); 134 driver = dbi_driver_open_r(config.dbi_driver, instance_p);
159 if (!driver) { 135 if (!driver) {
160 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", np_dbi_driver); 136 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
161 137
162 printf("Known drivers:\n"); 138 printf("Known drivers:\n");
163 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)) {
@@ -176,17 +152,19 @@ int main(int argc, char **argv) {
176 return STATE_UNKNOWN; 152 return STATE_UNKNOWN;
177 } 153 }
178 154
179 for (i = 0; i < np_dbi_options_num; ++i) { 155 for (size_t i = 0; i < config.dbi_options_num; ++i) {
180 const char *opt; 156 const char *opt;
181 157
182 if (verbose > 1) 158 if (verbose > 1) {
183 printf("Setting DBI driver option '%s' to '%s'\n", np_dbi_options[i].key, np_dbi_options[i].value); 159 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key, config.dbi_options[i].value);
160 }
184 161
185 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)) {
186 continue; 163 continue;
164 }
187 /* else: status != 0 */ 165 /* else: status != 0 */
188 166
189 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", np_dbi_options[i].key, np_dbi_options[i].value); 167 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", config.dbi_options[i].key, config.dbi_options[i].value);
190 printf("Known driver options:\n"); 168 printf("Known driver options:\n");
191 169
192 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) { 170 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) {
@@ -196,10 +174,11 @@ int main(int argc, char **argv) {
196 return STATE_UNKNOWN; 174 return STATE_UNKNOWN;
197 } 175 }
198 176
199 if (host) { 177 if (config.host) {
200 if (verbose > 1) 178 if (verbose > 1) {
201 printf("Setting DBI driver option 'host' to '%s'\n", host); 179 printf("Setting DBI driver option 'host' to '%s'\n", config.host);
202 dbi_conn_set_option(conn, "host", host); 180 }
181 dbi_conn_set_option(conn, "host", config.host);
203 } 182 }
204 183
205 if (verbose) { 184 if (verbose) {
@@ -209,10 +188,12 @@ int main(int argc, char **argv) {
209 dbname = dbi_conn_get_option(conn, "dbname"); 188 dbname = dbi_conn_get_option(conn, "dbname");
210 host = dbi_conn_get_option(conn, "host"); 189 host = dbi_conn_get_option(conn, "host");
211 190
212 if (!dbname) 191 if (!dbname) {
213 dbname = "<unspecified>"; 192 dbname = "<unspecified>";
214 if (!host) 193 }
194 if (!host) {
215 host = "<unspecified>"; 195 host = "<unspecified>";
196 }
216 197
217 printf("Connecting to database '%s' at host '%s'\n", dbname, host); 198 printf("Connecting to database '%s' at host '%s'\n", dbname, host);
218 } 199 }
@@ -226,109 +207,122 @@ int main(int argc, char **argv) {
226 conn_time = timediff(start_timeval, end_timeval); 207 conn_time = timediff(start_timeval, end_timeval);
227 208
228 server_version = dbi_conn_get_engine_version(conn); 209 server_version = dbi_conn_get_engine_version(conn);
229 if (verbose) 210 if (verbose) {
230 printf("Connected to server version %u\n", server_version); 211 printf("Connected to server version %u\n", server_version);
212 }
231 213
232 if (metric == METRIC_SERVER_VERSION) 214 if (config.metric == METRIC_SERVER_VERSION) {
233 status = get_status(server_version, dbi_thresholds); 215 status = get_status(server_version, config.dbi_thresholds);
216 }
234 217
235 if (verbose) 218 if (verbose) {
236 printf("Time elapsed: %f\n", conn_time); 219 printf("Time elapsed: %f\n", conn_time);
220 }
237 221
238 if (metric == METRIC_CONN_TIME) 222 if (config.metric == METRIC_CONN_TIME) {
239 status = get_status(conn_time, dbi_thresholds); 223 status = get_status(conn_time, config.dbi_thresholds);
224 }
240 225
241 /* select a database */ 226 /* select a database */
242 if (np_dbi_database) { 227 if (config.dbi_database) {
243 if (verbose > 1) 228 if (verbose > 1) {
244 printf("Selecting database '%s'\n", np_dbi_database); 229 printf("Selecting database '%s'\n", config.dbi_database);
230 }
245 231
246 if (dbi_conn_select_db(conn, np_dbi_database)) { 232 if (dbi_conn_select_db(conn, config.dbi_database)) {
247 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", np_dbi_database); 233 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database);
248 return STATE_UNKNOWN; 234 return STATE_UNKNOWN;
249 } 235 }
250 } 236 }
251 237
252 if (np_dbi_query) { 238 if (config.dbi_query) {
253 /* execute query */ 239 /* execute query */
254 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);
255 if (status != STATE_OK) 241 if (status != STATE_OK) {
256 /* do_query prints an error message in this case */ 242 /* do_query prints an error message in this case */
257 return status; 243 return status;
244 }
258 245
259 if (metric == METRIC_QUERY_RESULT) { 246 if (config.metric == METRIC_QUERY_RESULT) {
260 if (expect) { 247 if (config.expect) {
261 if ((!query_val_str) || strcmp(query_val_str, expect)) 248 if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
262 status = STATE_CRITICAL; 249 status = STATE_CRITICAL;
263 else 250 } else {
264 status = STATE_OK; 251 status = STATE_OK;
265 } else if (expect_re_str) { 252 }
253 } else if (config.expect_re_str) {
266 int err; 254 int err;
267 255
256 regex_t expect_re = {};
268 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0); 257 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
269 if (!err) 258 if (!err) {
270 status = STATE_OK; 259 status = STATE_OK;
271 else if (err == REG_NOMATCH) 260 } else if (err == REG_NOMATCH) {
272 status = STATE_CRITICAL; 261 status = STATE_CRITICAL;
273 else { 262 } else {
274 char errmsg[1024]; 263 char errmsg[1024];
275 regerror(err, &expect_re, errmsg, sizeof(errmsg)); 264 regerror(err, &expect_re, errmsg, sizeof(errmsg));
276 printf("ERROR - failed to execute regular expression: %s\n", errmsg); 265 printf("ERROR - failed to execute regular expression: %s\n", errmsg);
277 status = STATE_CRITICAL; 266 status = STATE_CRITICAL;
278 } 267 }
279 } else 268 } else {
280 status = get_status(query_val, dbi_thresholds); 269 status = get_status(query_val, config.dbi_thresholds);
281 } else if (metric == METRIC_QUERY_TIME) 270 }
282 status = get_status(query_time, dbi_thresholds); 271 } else if (config.metric == METRIC_QUERY_TIME) {
272 status = get_status(query_time, config.dbi_thresholds);
273 }
283 } 274 }
284 275
285 if (verbose) 276 if (verbose) {
286 printf("Closing connection\n"); 277 printf("Closing connection\n");
278 }
287 dbi_conn_close(conn); 279 dbi_conn_close(conn);
288 280
289 /* 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
290 * which should have been reported and handled (abort) before 282 * which should have been reported and handled (abort) before
291 * ... unless we expected a string to be returned */ 283 * ... unless we expected a string to be returned */
292 assert((metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (type == TYPE_STRING)); 284 assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (config.type == TYPE_STRING));
293 285
294 assert((type != TYPE_STRING) || (expect || expect_re_str)); 286 assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
295 287
296 printf("%s - connection time: %fs", state_text(status), conn_time); 288 printf("%s - connection time: %fs", state_text(status), conn_time);
297 if (np_dbi_query) { 289 if (config.dbi_query) {
298 if (type == TYPE_STRING) { 290 if (config.type == TYPE_STRING) {
299 assert(expect || expect_re_str); 291 assert(config.expect || config.expect_re_str);
300 printf(", '%s' returned '%s' in %fs", np_dbi_query, query_val_str ? query_val_str : "<nothing>", query_time); 292 printf(", '%s' returned '%s' in %fs", config.dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
301 if (status != STATE_OK) { 293 if (status != STATE_OK) {
302 if (expect) 294 if (config.expect) {
303 printf(" (expected '%s')", expect); 295 printf(" (expected '%s')", config.expect);
304 else if (expect_re_str) 296 } else if (config.expect_re_str) {
305 printf(" (expected regex /%s/%s)", expect_re_str, ((expect_re_cflags & REG_ICASE) ? "i" : "")); 297 printf(" (expected regex /%s/%s)", config.expect_re_str, ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
298 }
306 } 299 }
307 } else if (isnan(query_val)) 300 } else if (isnan(query_val)) {
308 printf(", '%s' query execution time: %fs", np_dbi_query, query_time); 301 printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
309 else 302 } else {
310 printf(", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); 303 printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
304 }
311 } 305 }
312 306
313 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, 307 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
314 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", 308 ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
315 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "", server_version, 309 ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", server_version,
316 ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "", 310 ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range : "",
317 ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : ""); 311 ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range : "");
318 if (np_dbi_query) { 312 if (config.dbi_query) {
319 if (!isnan(query_val)) /* this is also true when -e is used */ 313 if (!isnan(query_val)) { /* this is also true when -e is used */
320 printf(" query=%f;%s;%s;;", query_val, ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", 314 printf(" query=%f;%s;%s;;", query_val, ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) ? config.warning_range : "",
321 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : ""); 315 ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) ? config.critical_range : "");
322 printf(" querytime=%fs;%s;%s;0;", query_time, ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "", 316 }
323 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : ""); 317 printf(" querytime=%fs;%s;%s;0;", query_time, ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range : "",
318 ((config.metric == METRIC_QUERY_TIME) && config.critical_range) ? config.critical_range : "");
324 } 319 }
325 printf("\n"); 320 printf("\n");
326 return status; 321 return status;
327} 322}
328 323
329/* process command-line arguments */ 324/* process command-line arguments */
330int process_arguments(int argc, char **argv) { 325check_dbi_config_wrapper process_arguments(int argc, char **argv) {
331 int c;
332 326
333 int option = 0; 327 int option = 0;
334 static struct option longopts[] = {STD_LONG_OPTS, 328 static struct option longopts[] = {STD_LONG_OPTS,
@@ -343,13 +337,19 @@ int process_arguments(int argc, char **argv) {
343 {"database", required_argument, 0, 'D'}, 337 {"database", required_argument, 0, 'D'},
344 {0, 0, 0, 0}}; 338 {0, 0, 0, 0}};
345 339
346 while (1) { 340 check_dbi_config_wrapper result = {
347 c = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option); 341 .config = check_dbi_config_init(),
342 .errorcode = OK,
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);
348 347
349 if (c == EOF) 348 if (option_char == EOF) {
350 break; 349 break;
350 }
351 351
352 switch (c) { 352 switch (option_char) {
353 case '?': /* usage */ 353 case '?': /* usage */
354 usage5(); 354 usage5();
355 case 'h': /* help */ 355 case 'h': /* help */
@@ -360,135 +360,148 @@ int process_arguments(int argc, char **argv) {
360 exit(STATE_UNKNOWN); 360 exit(STATE_UNKNOWN);
361 361
362 case 'c': /* critical range */ 362 case 'c': /* critical range */
363 critical_range = optarg; 363 result.config.critical_range = optarg;
364 type = TYPE_NUMERIC; 364 result.config.type = TYPE_NUMERIC;
365 break; 365 break;
366 case 'w': /* warning range */ 366 case 'w': /* warning range */
367 warning_range = optarg; 367 result.config.warning_range = optarg;
368 type = TYPE_NUMERIC; 368 result.config.type = TYPE_NUMERIC;
369 break; 369 break;
370 case 'e': 370 case 'e':
371 expect = optarg; 371 result.config.expect = optarg;
372 type = TYPE_STRING; 372 result.config.type = TYPE_STRING;
373 break; 373 break;
374 case 'R': 374 case 'R':
375 expect_re_cflags = REG_ICASE; 375 result.config.expect_re_cflags = REG_ICASE;
376 /* fall through */ 376 /* fall through */
377 case 'r': { 377 case 'r': {
378 int err; 378 int err;
379 379
380 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 380 result.config.expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
381 expect_re_str = optarg; 381 result.config.expect_re_str = optarg;
382 type = TYPE_STRING; 382 result.config.type = TYPE_STRING;
383 383
384 err = regcomp(&expect_re, expect_re_str, expect_re_cflags); 384 regex_t expect_re = {};
385 err = regcomp(&expect_re, result.config.expect_re_str, result.config.expect_re_cflags);
385 if (err) { 386 if (err) {
386 char errmsg[1024]; 387 char errmsg[1024];
387 regerror(err, &expect_re, errmsg, sizeof(errmsg)); 388 regerror(err, &expect_re, errmsg, sizeof(errmsg));
388 printf("ERROR - failed to compile regular expression: %s\n", errmsg); 389 printf("ERROR - failed to compile regular expression: %s\n", errmsg);
389 return ERROR; 390
391 result.errorcode = ERROR;
392 return result;
390 } 393 }
391 break; 394 break;
392 } 395 }
393 396
394 case 'm': 397 case 'm':
395 if (!strcasecmp(optarg, "CONN_TIME")) 398 if (!strcasecmp(optarg, "CONN_TIME")) {
396 metric = METRIC_CONN_TIME; 399 result.config.metric = METRIC_CONN_TIME;
397 else if (!strcasecmp(optarg, "SERVER_VERSION")) 400 } else if (!strcasecmp(optarg, "SERVER_VERSION")) {
398 metric = METRIC_SERVER_VERSION; 401 result.config.metric = METRIC_SERVER_VERSION;
399 else if (!strcasecmp(optarg, "QUERY_RESULT")) 402 } else if (!strcasecmp(optarg, "QUERY_RESULT")) {
400 metric = METRIC_QUERY_RESULT; 403 result.config.metric = METRIC_QUERY_RESULT;
401 else if (!strcasecmp(optarg, "QUERY_TIME")) 404 } else if (!strcasecmp(optarg, "QUERY_TIME")) {
402 metric = METRIC_QUERY_TIME; 405 result.config.metric = METRIC_QUERY_TIME;
403 else 406 } else {
404 usage2(_("Invalid metric"), optarg); 407 usage2(_("Invalid metric"), optarg);
408 }
405 break; 409 break;
406 case 't': /* timeout */ 410 case 't': /* timeout */
407 if (!is_intnonneg(optarg)) 411 if (!is_intnonneg(optarg)) {
408 usage2(_("Timeout interval must be a positive integer"), optarg); 412 usage2(_("Timeout interval must be a positive integer"), optarg);
409 else 413 } else {
410 timeout_interval = atoi(optarg); 414 timeout_interval = atoi(optarg);
415 }
411 416
412 break; 417 break;
413 case 'H': /* host */ 418 case 'H': /* host */
414 if (!is_host(optarg)) 419 if (!is_host(optarg)) {
415 usage2(_("Invalid hostname/address"), optarg); 420 usage2(_("Invalid hostname/address"), optarg);
416 else 421 } else {
417 host = optarg; 422 result.config.host = optarg;
423 }
418 break; 424 break;
419 case 'v': 425 case 'v':
420 verbose++; 426 verbose++;
421 break; 427 break;
422 428
423 case 'd': 429 case 'd':
424 np_dbi_driver = optarg; 430 result.config.dbi_driver = optarg;
425 break; 431 break;
426 case 'o': { 432 case 'o': {
427 driver_option_t *new; 433 driver_option_t *new = NULL;
428
429 char *k;
430 char *v;
431 434
432 k = optarg; 435 char *key = optarg;
433 v = strchr(k, (int)'='); 436 char *value = strchr(key, '=');
434 437
435 if (!v) 438 if (!value) {
436 usage2(_("Option must be '<key>=<value>'"), optarg); 439 usage2(_("Option must be '<key>=<value>'"), optarg);
440 }
437 441
438 *v = '\0'; 442 *value = '\0';
439 ++v; 443 ++value;
440 444
441 new = realloc(np_dbi_options, (np_dbi_options_num + 1) * sizeof(*new)); 445 new = realloc(result.config.dbi_options, (result.config.dbi_options_num + 1) * sizeof(*new));
442 if (!new) { 446 if (!new) {
443 printf("UNKNOWN - failed to reallocate memory\n"); 447 printf("UNKNOWN - failed to reallocate memory\n");
444 exit(STATE_UNKNOWN); 448 exit(STATE_UNKNOWN);
445 } 449 }
446 450
447 np_dbi_options = new; 451 result.config.dbi_options = new;
448 new = np_dbi_options + np_dbi_options_num; 452 new = result.config.dbi_options + result.config.dbi_options_num;
449 ++np_dbi_options_num; 453 result.config.dbi_options_num++;
450 454
451 new->key = k; 455 new->key = key;
452 new->value = v; 456 new->value = value;
453 } break; 457 } break;
454 case 'q': 458 case 'q':
455 np_dbi_query = optarg; 459 result.config.dbi_query = optarg;
456 break; 460 break;
457 case 'D': 461 case 'D':
458 np_dbi_database = optarg; 462 result.config.dbi_database = optarg;
459 break; 463 break;
460 } 464 }
461 } 465 }
462 466
463 set_thresholds(&dbi_thresholds, warning_range, critical_range); 467 set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, result.config.critical_range);
464 468
465 return validate_arguments(); 469 return validate_arguments(result);
466} 470}
467 471
468int validate_arguments(void) { 472check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
469 if (!np_dbi_driver) 473 if (!config_wrapper.config.dbi_driver) {
470 usage("Must specify a DBI driver"); 474 usage("Must specify a DBI driver");
475 }
471 476
472 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) && (!np_dbi_query)) 477 if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || (config_wrapper.config.metric == METRIC_QUERY_TIME)) &&
478 (!config_wrapper.config.dbi_query)) {
473 usage("Must specify a query to execute (metric == QUERY_RESULT)"); 479 usage("Must specify a query to execute (metric == QUERY_RESULT)");
480 }
474 481
475 if ((metric != METRIC_CONN_TIME) && (metric != METRIC_SERVER_VERSION) && (metric != METRIC_QUERY_RESULT) && 482 if ((config_wrapper.config.metric != METRIC_CONN_TIME) && (config_wrapper.config.metric != METRIC_SERVER_VERSION) &&
476 (metric != METRIC_QUERY_TIME)) 483 (config_wrapper.config.metric != METRIC_QUERY_RESULT) && (config_wrapper.config.metric != METRIC_QUERY_TIME)) {
477 usage("Invalid metric specified"); 484 usage("Invalid metric specified");
485 }
478 486
479 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)) {
480 usage("Do not mix -e and -w/-c/-r/-R"); 488 usage("Do not mix -e and -w/-c/-r/-R");
489 }
481 490
482 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)) {
483 usage("Do not mix -r/-R and -w/-c/-e"); 492 usage("Do not mix -r/-R and -w/-c/-e");
493 }
484 494
485 if (expect && (metric != METRIC_QUERY_RESULT)) 495 if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
486 usage("Option -e requires metric QUERY_RESULT"); 496 usage("Option -e requires metric QUERY_RESULT");
497 }
487 498
488 if (expect_re_str && (metric != METRIC_QUERY_RESULT)) 499 if (config_wrapper.config.expect_re_str && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
489 usage("Options -r/-R require metric QUERY_RESULT"); 500 usage("Options -r/-R require metric QUERY_RESULT");
501 }
490 502
491 return OK; 503 config_wrapper.errorcode = OK;
504 return config_wrapper;
492} 505}
493 506
494void print_help(void) { 507void print_help(void) {
@@ -518,6 +531,8 @@ void print_help(void) {
518 printf(" %s\n", _("DBI driver options")); 531 printf(" %s\n", _("DBI driver options"));
519 printf(" %s\n", "-q, --query=STRING"); 532 printf(" %s\n", "-q, --query=STRING");
520 printf(" %s\n", _("query to execute")); 533 printf(" %s\n", _("query to execute"));
534 printf(" %s\n", "-H STRING");
535 printf(" %s\n", _("target database host"));
521 printf("\n"); 536 printf("\n");
522 537
523 printf(UT_WARN_CRIT_RANGE); 538 printf(UT_WARN_CRIT_RANGE);
@@ -592,13 +607,7 @@ void print_usage(void) {
592 printf(" [-e <string>] [-r|-R <regex>]\n"); 607 printf(" [-e <string>] [-r|-R <regex>]\n");
593} 608}
594 609
595#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) {
596 do { \
597 if (metric != METRIC_QUERY_RESULT) \
598 return (s); \
599 } while (0)
600
601const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type) {
602 const char *str; 611 const char *str;
603 612
604 if (field_type != DBI_TYPE_STRING) { 613 if (field_type != DBI_TYPE_STRING) {
@@ -608,17 +617,20 @@ const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_ty
608 617
609 str = dbi_result_get_string_idx(res, 1); 618 str = dbi_result_get_string_idx(res, 1);
610 if ((!str) || (strcmp(str, "ERROR") == 0)) { 619 if ((!str) || (strcmp(str, "ERROR") == 0)) {
611 CHECK_IGNORE_ERROR(NULL); 620 if (metric != METRIC_QUERY_RESULT) {
621 return NULL;
622 }
612 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value"); 623 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
613 return NULL; 624 return NULL;
614 } 625 }
615 626
616 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) 627 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) {
617 printf("Query returned string '%s'\n", str); 628 printf("Query returned string '%s'\n", str);
629 }
618 return str; 630 return str;
619} 631}
620 632
621double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) { 633double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, mp_dbi_type type) {
622 double val = NAN; 634 double val = NAN;
623 635
624 if (*field_type == DBI_TYPE_INTEGER) { 636 if (*field_type == DBI_TYPE_INTEGER) {
@@ -629,26 +641,33 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
629 const char *val_str; 641 const char *val_str;
630 char *endptr = NULL; 642 char *endptr = NULL;
631 643
632 val_str = get_field_str(conn, res, *field_type); 644 val_str = get_field_str(conn, res, *field_type, metric, type);
633 if (!val_str) { 645 if (!val_str) {
634 CHECK_IGNORE_ERROR(NAN); 646 if (metric != METRIC_QUERY_RESULT) {
647 return NAN;
648 }
635 *field_type = DBI_TYPE_ERROR; 649 *field_type = DBI_TYPE_ERROR;
636 return NAN; 650 return NAN;
637 } 651 }
638 652
639 val = strtod(val_str, &endptr); 653 val = strtod(val_str, &endptr);
640 if (endptr == val_str) { 654 if (endptr == val_str) {
641 CHECK_IGNORE_ERROR(NAN); 655 if (metric != METRIC_QUERY_RESULT) {
656 return NAN;
657 }
642 printf("CRITICAL - result value is not a numeric: %s\n", val_str); 658 printf("CRITICAL - result value is not a numeric: %s\n", val_str);
643 *field_type = DBI_TYPE_ERROR; 659 *field_type = DBI_TYPE_ERROR;
644 return NAN; 660 return NAN;
645 } 661 }
646 if ((endptr != NULL) && (*endptr != '\0')) { 662 if ((endptr != NULL) && (*endptr != '\0')) {
647 if (verbose) 663 if (verbose) {
648 printf("Garbage after value: %s\n", endptr); 664 printf("Garbage after value: %s\n", endptr);
665 }
649 } 666 }
650 } else { 667 } else {
651 CHECK_IGNORE_ERROR(NAN); 668 if (metric != METRIC_QUERY_RESULT) {
669 return NAN;
670 }
652 printf("CRITICAL - cannot parse value of type %s (%i)\n", 671 printf("CRITICAL - cannot parse value of type %s (%i)\n",
653 (*field_type == DBI_TYPE_BINARY) ? "BINARY" 672 (*field_type == DBI_TYPE_BINARY) ? "BINARY"
654 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME" 673 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
@@ -660,53 +679,66 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
660 return val; 679 return val;
661} 680}
662 681
663double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val) { 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) {
664 unsigned short field_type; 683 unsigned short field_type;
665 double val = NAN; 684 double val = NAN;
666 685
667 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) { 686 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
668 CHECK_IGNORE_ERROR(STATE_OK); 687 if (metric != METRIC_QUERY_RESULT) {
688 return STATE_OK;
689 }
669 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows"); 690 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
670 return STATE_CRITICAL; 691 return STATE_CRITICAL;
671 } 692 }
672 693
673 if (dbi_result_get_numrows(res) < 1) { 694 if (dbi_result_get_numrows(res) < 1) {
674 CHECK_IGNORE_ERROR(STATE_OK); 695 if (metric != METRIC_QUERY_RESULT) {
696 return STATE_OK;
697 }
675 printf("WARNING - no rows returned\n"); 698 printf("WARNING - no rows returned\n");
676 return STATE_WARNING; 699 return STATE_WARNING;
677 } 700 }
678 701
679 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) { 702 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
680 CHECK_IGNORE_ERROR(STATE_OK); 703 if (metric != METRIC_QUERY_RESULT) {
704 return STATE_OK;
705 }
681 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields"); 706 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
682 return STATE_CRITICAL; 707 return STATE_CRITICAL;
683 } 708 }
684 709
685 if (dbi_result_get_numfields(res) < 1) { 710 if (dbi_result_get_numfields(res) < 1) {
686 CHECK_IGNORE_ERROR(STATE_OK); 711 if (metric != METRIC_QUERY_RESULT) {
712 return STATE_OK;
713 }
687 printf("WARNING - no fields returned\n"); 714 printf("WARNING - no fields returned\n");
688 return STATE_WARNING; 715 return STATE_WARNING;
689 } 716 }
690 717
691 if (dbi_result_first_row(res) != 1) { 718 if (dbi_result_first_row(res) != 1) {
692 CHECK_IGNORE_ERROR(STATE_OK); 719 if (metric != METRIC_QUERY_RESULT) {
720 return STATE_OK;
721 }
693 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row"); 722 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
694 return STATE_CRITICAL; 723 return STATE_CRITICAL;
695 } 724 }
696 725
697 field_type = dbi_result_get_field_type_idx(res, 1); 726 field_type = dbi_result_get_field_type_idx(res, 1);
698 if (field_type != DBI_TYPE_ERROR) { 727 if (field_type != DBI_TYPE_ERROR) {
699 if (type == TYPE_STRING) 728 if (type == TYPE_STRING) {
700 /* the value will be freed in dbi_result_free */ 729 /* the value will be freed in dbi_result_free */
701 *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));
702 else 731 } else {
703 val = get_field(conn, res, &field_type); 732 val = get_field(conn, res, &field_type, metric, type);
733 }
704 } 734 }
705 735
706 *res_val = val; 736 *res_val = val;
707 737
708 if (field_type == DBI_TYPE_ERROR) { 738 if (field_type == DBI_TYPE_ERROR) {
709 CHECK_IGNORE_ERROR(STATE_OK); 739 if (metric != METRIC_QUERY_RESULT) {
740 return STATE_OK;
741 }
710 np_dbi_print_error(conn, "CRITICAL - failed to fetch data"); 742 np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
711 return STATE_CRITICAL; 743 return STATE_CRITICAL;
712 } 744 }
@@ -715,19 +747,19 @@ double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str,
715 return STATE_OK; 747 return STATE_OK;
716} 748}
717 749
718#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,
719 751 char *np_dbi_query) {
720int do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time) {
721 dbi_result res; 752 dbi_result res;
722 753
723 struct timeval timeval_start; 754 struct timeval timeval_start;
724 struct timeval timeval_end; 755 struct timeval timeval_end;
725 int status = STATE_OK; 756 mp_state_enum status = STATE_OK;
726 757
727 assert(np_dbi_query); 758 assert(np_dbi_query);
728 759
729 if (verbose) 760 if (verbose) {
730 printf("Executing query '%s'\n", np_dbi_query); 761 printf("Executing query '%s'\n", np_dbi_query);
762 }
731 763
732 gettimeofday(&timeval_start, NULL); 764 gettimeofday(&timeval_start, NULL);
733 765
@@ -737,13 +769,14 @@ int do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *r
737 return STATE_CRITICAL; 769 return STATE_CRITICAL;
738 } 770 }
739 771
740 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);
741 773
742 gettimeofday(&timeval_end, NULL); 774 gettimeofday(&timeval_end, NULL);
743 *res_time = timediff(timeval_start, timeval_end); 775 *res_time = timediff(timeval_start, timeval_end);
744 776
745 if (verbose) 777 if (verbose) {
746 printf("Time elapsed: %f\n", *res_time); 778 printf("Time elapsed: %f\n", *res_time);
779 }
747 780
748 return status; 781 return status;
749} 782}
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 2bbd1e05..d0903be2 100644
--- a/plugins/check_dig.c
+++ b/plugins/check_dig.c
@@ -41,97 +41,93 @@ 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
44static int process_arguments(int /*argc*/, char ** /*argv*/); 44#include "check_dig.d/config.h"
45static int validate_arguments(void); 45#include "states.h"
46
47typedef struct {
48 int errorcode;
49 check_dig_config config;
50} check_dig_config_wrapper;
51static check_dig_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
52static check_dig_config_wrapper validate_arguments(check_dig_config_wrapper /*config_wrapper*/);
53
46static void print_help(void); 54static void print_help(void);
47void print_usage(void); 55void print_usage(void);
48 56
49#define UNDEFINED 0 57static int verbose = 0;
50#define DEFAULT_PORT 53
51#define DEFAULT_TRIES 2
52
53static char *query_address = NULL;
54static char *record_type = "A";
55static char *expected_address = NULL;
56static char *dns_server = NULL;
57static char *dig_args = "";
58static char *query_transport = "";
59static bool verbose = false;
60static int server_port = DEFAULT_PORT;
61static int number_tries = DEFAULT_TRIES;
62static double warning_interval = UNDEFINED;
63static double critical_interval = UNDEFINED;
64static struct timeval tv;
65 58
66int main(int argc, char **argv) { 59int main(int argc, char **argv) {
67 char *command_line;
68 output chld_out;
69 output chld_err;
70 char *msg = NULL;
71 size_t i;
72 char *t;
73 long microsec;
74 double elapsed_time;
75 int result = STATE_UNKNOWN;
76 int timeout_interval_dig;
77
78 setlocale(LC_ALL, ""); 60 setlocale(LC_ALL, "");
79 bindtextdomain(PACKAGE, LOCALEDIR); 61 bindtextdomain(PACKAGE, LOCALEDIR);
80 textdomain(PACKAGE); 62 textdomain(PACKAGE);
81 63
82 /* Set signal handling and alarm */ 64 /* Set signal handling and alarm */
83 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) 65 if (signal(SIGALRM, runcmd_timeout_alarm_handler) == SIG_ERR) {
84 usage_va(_("Cannot catch SIGALRM")); 66 usage_va(_("Cannot catch SIGALRM"));
67 }
85 68
86 /* Parse extra opts if any */ 69 /* Parse extra opts if any */
87 argv = np_extra_opts(&argc, argv, progname); 70 argv = np_extra_opts(&argc, argv, progname);
88 71
89 if (process_arguments(argc, argv) == ERROR) 72 check_dig_config_wrapper tmp_config = process_arguments(argc, argv);
73 if (tmp_config.errorcode == ERROR) {
90 usage_va(_("Could not parse arguments")); 74 usage_va(_("Could not parse arguments"));
75 }
76
77 const check_dig_config config = tmp_config.config;
91 78
92 /* dig applies the timeout to each try, so we need to work around this */ 79 /* dig applies the timeout to each try, so we need to work around this */
93 timeout_interval_dig = timeout_interval / number_tries + number_tries; 80 int timeout_interval_dig = ((int)timeout_interval / config.number_tries) + config.number_tries;
94 81
82 char *command_line;
95 /* get the command to run */ 83 /* get the command to run */
96 xasprintf(&command_line, "%s %s %s -p %d @%s %s %s +retry=%d +time=%d", PATH_TO_DIG, dig_args, query_transport, server_port, dns_server, 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,
97 query_address, record_type, number_tries, timeout_interval_dig); 85 config.server_port, config.dns_server, config.query_address, config.record_type, config.number_tries, timeout_interval_dig);
98 86
99 alarm(timeout_interval); 87 alarm(timeout_interval);
100 gettimeofday(&tv, NULL); 88 struct timeval start_time;
89 gettimeofday(&start_time, NULL);
101 90
102 if (verbose) { 91 if (verbose) {
103 printf("%s\n", command_line); 92 printf("%s\n", command_line);
104 if (expected_address != NULL) { 93 if (config.expected_address != NULL) {
105 printf(_("Looking for: '%s'\n"), expected_address); 94 printf(_("Looking for: '%s'\n"), config.expected_address);
106 } else { 95 } else {
107 printf(_("Looking for: '%s'\n"), query_address); 96 printf(_("Looking for: '%s'\n"), config.query_address);
108 } 97 }
109 } 98 }
110 99
100 output chld_out;
101 output chld_err;
102 char *msg = NULL;
103 mp_state_enum result = STATE_UNKNOWN;
111 /* run the command */ 104 /* run the command */
112 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) { 105 if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) {
113 result = STATE_WARNING; 106 result = STATE_WARNING;
114 msg = (char *)_("dig returned an error status"); 107 msg = (char *)_("dig returned an error status");
115 } 108 }
116 109
117 for (i = 0; i < chld_out.lines; i++) { 110 for (size_t i = 0; i < chld_out.lines; i++) {
118 /* the server is responding, we just got the host name... */ 111 /* the server is responding, we just got the host name... */
119 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) { 112 if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) {
120 113
121 /* loop through the whole 'ANSWER SECTION' */ 114 /* loop through the whole 'ANSWER SECTION' */
122 for (; i < chld_out.lines; i++) { 115 for (; i < chld_out.lines; i++) {
123 /* get the host address */ 116 /* get the host address */
124 if (verbose) 117 if (verbose) {
125 printf("%s\n", chld_out.line[i]); 118 printf("%s\n", chld_out.line[i]);
119 }
126 120
127 if (strcasestr(chld_out.line[i], (expected_address == NULL ? query_address : expected_address)) != NULL) { 121 if (strcasestr(chld_out.line[i], (config.expected_address == NULL ? config.query_address : config.expected_address)) !=
122 NULL) {
128 msg = chld_out.line[i]; 123 msg = chld_out.line[i];
129 result = STATE_OK; 124 result = STATE_OK;
130 125
131 /* Translate output TAB -> SPACE */ 126 /* Translate output TAB -> SPACE */
132 t = msg; 127 char *temp = msg;
133 while ((t = strchr(t, '\t')) != NULL) 128 while ((temp = strchr(temp, '\t')) != NULL) {
134 *t = ' '; 129 *temp = ' ';
130 }
135 break; 131 break;
136 } 132 }
137 } 133 }
@@ -154,37 +150,37 @@ int main(int argc, char **argv) {
154 /* If we get anything on STDERR, at least set warning */ 150 /* If we get anything on STDERR, at least set warning */
155 if (chld_err.buflen > 0) { 151 if (chld_err.buflen > 0) {
156 result = max_state(result, STATE_WARNING); 152 result = max_state(result, STATE_WARNING);
157 if (!msg) 153 if (!msg) {
158 for (i = 0; i < chld_err.lines; i++) { 154 for (size_t i = 0; i < chld_err.lines; i++) {
159 msg = strchr(chld_err.line[0], ':'); 155 msg = strchr(chld_err.line[0], ':');
160 if (msg) { 156 if (msg) {
161 msg++; 157 msg++;
162 break; 158 break;
163 } 159 }
164 } 160 }
161 }
165 } 162 }
166 163
167 microsec = deltime(tv); 164 long microsec = deltime(start_time);
168 elapsed_time = (double)microsec / 1.0e6; 165 double elapsed_time = (double)microsec / 1.0e6;
169 166
170 if (critical_interval > UNDEFINED && elapsed_time > critical_interval) 167 if (config.critical_interval > UNDEFINED && elapsed_time > config.critical_interval) {
171 result = STATE_CRITICAL; 168 result = STATE_CRITICAL;
169 }
172 170
173 else if (warning_interval > UNDEFINED && elapsed_time > warning_interval) 171 else if (config.warning_interval > UNDEFINED && elapsed_time > config.warning_interval) {
174 result = STATE_WARNING; 172 result = STATE_WARNING;
173 }
175 174
176 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time, 175 printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time,
177 msg ? msg : _("Probably a non-existent host/domain"), 176 msg ? msg : _("Probably a non-existent host/domain"),
178 fperfdata("time", elapsed_time, "s", (warning_interval > UNDEFINED ? true : false), warning_interval, 177 fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED), config.warning_interval,
179 (critical_interval > UNDEFINED ? true : false), critical_interval, true, 0, false, 0)); 178 (config.critical_interval > UNDEFINED), config.critical_interval, true, 0, false, 0));
180 return result; 179 exit(result);
181} 180}
182 181
183/* process command-line arguments */ 182/* process command-line arguments */
184int process_arguments(int argc, char **argv) { 183check_dig_config_wrapper process_arguments(int argc, char **argv) {
185 int c;
186
187 int option = 0;
188 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 184 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
189 {"query_address", required_argument, 0, 'l'}, 185 {"query_address", required_argument, 0, 'l'},
190 {"warning", required_argument, 0, 'w'}, 186 {"warning", required_argument, 0, 'w'},
@@ -201,16 +197,25 @@ int process_arguments(int argc, char **argv) {
201 {"use-ipv6", no_argument, 0, '6'}, 197 {"use-ipv6", no_argument, 0, '6'},
202 {0, 0, 0, 0}}; 198 {0, 0, 0, 0}};
203 199
204 if (argc < 2) 200 check_dig_config_wrapper result = {
205 return ERROR; 201 .errorcode = OK,
202 .config = check_dig_config_init(),
203 };
206 204
207 while (1) { 205 if (argc < 2) {
208 c = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option); 206 result.errorcode = ERROR;
207 return result;
208 }
209 209
210 if (c == -1 || c == EOF) 210 int option = 0;
211 while (true) {
212 int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option);
213
214 if (option_index == -1 || option_index == EOF) {
211 break; 215 break;
216 }
212 217
213 switch (c) { 218 switch (option_index) {
214 case 'h': /* help */ 219 case 'h': /* help */
215 print_help(); 220 print_help();
216 exit(STATE_UNKNOWN); 221 exit(STATE_UNKNOWN);
@@ -219,28 +224,28 @@ int process_arguments(int argc, char **argv) {
219 exit(STATE_UNKNOWN); 224 exit(STATE_UNKNOWN);
220 case 'H': /* hostname */ 225 case 'H': /* hostname */
221 host_or_die(optarg); 226 host_or_die(optarg);
222 dns_server = optarg; 227 result.config.dns_server = optarg;
223 break; 228 break;
224 case 'p': /* server port */ 229 case 'p': /* server port */
225 if (is_intpos(optarg)) { 230 if (is_intpos(optarg)) {
226 server_port = atoi(optarg); 231 result.config.server_port = atoi(optarg);
227 } else { 232 } else {
228 usage_va(_("Port must be a positive integer - %s"), optarg); 233 usage_va(_("Port must be a positive integer - %s"), optarg);
229 } 234 }
230 break; 235 break;
231 case 'l': /* address to lookup */ 236 case 'l': /* address to lookup */
232 query_address = optarg; 237 result.config.query_address = optarg;
233 break; 238 break;
234 case 'w': /* warning */ 239 case 'w': /* warning */
235 if (is_nonnegative(optarg)) { 240 if (is_nonnegative(optarg)) {
236 warning_interval = strtod(optarg, NULL); 241 result.config.warning_interval = strtod(optarg, NULL);
237 } else { 242 } else {
238 usage_va(_("Warning interval must be a positive integer - %s"), optarg); 243 usage_va(_("Warning interval must be a positive integer - %s"), optarg);
239 } 244 }
240 break; 245 break;
241 case 'c': /* critical */ 246 case 'c': /* critical */
242 if (is_nonnegative(optarg)) { 247 if (is_nonnegative(optarg)) {
243 critical_interval = strtod(optarg, NULL); 248 result.config.critical_interval = strtod(optarg, NULL);
244 } else { 249 } else {
245 usage_va(_("Critical interval must be a positive integer - %s"), optarg); 250 usage_va(_("Critical interval must be a positive integer - %s"), optarg);
246 } 251 }
@@ -253,48 +258,50 @@ int process_arguments(int argc, char **argv) {
253 } 258 }
254 break; 259 break;
255 case 'A': /* dig arguments */ 260 case 'A': /* dig arguments */
256 dig_args = strdup(optarg); 261 result.config.dig_args = strdup(optarg);
257 break; 262 break;
258 case 'v': /* verbose */ 263 case 'v': /* verbose */
259 verbose = true; 264 verbose++;
260 break; 265 break;
261 case 'T': 266 case 'T':
262 record_type = optarg; 267 result.config.record_type = optarg;
263 break; 268 break;
264 case 'a': 269 case 'a':
265 expected_address = optarg; 270 result.config.expected_address = optarg;
266 break; 271 break;
267 case '4': 272 case '4':
268 query_transport = "-4"; 273 result.config.query_transport = "-4";
269 break; 274 break;
270 case '6': 275 case '6':
271 query_transport = "-6"; 276 result.config.query_transport = "-6";
272 break; 277 break;
273 default: /* usage5 */ 278 default: /* usage5 */
274 usage5(); 279 usage5();
275 } 280 }
276 } 281 }
277 282
278 c = optind; 283 int index = optind;
279 if (dns_server == NULL) { 284 if (result.config.dns_server == NULL) {
280 if (c < argc) { 285 if (index < argc) {
281 host_or_die(argv[c]); 286 host_or_die(argv[index]);
282 dns_server = argv[c]; 287 result.config.dns_server = argv[index];
283 } else { 288 } else {
284 if (strcmp(query_transport, "-6") == 0) 289 if (strcmp(result.config.query_transport, "-6") == 0) {
285 dns_server = strdup("::1"); 290 result.config.dns_server = strdup("::1");
286 else 291 } else {
287 dns_server = strdup("127.0.0.1"); 292 result.config.dns_server = strdup("127.0.0.1");
293 }
288 } 294 }
289 } 295 }
290 296
291 return validate_arguments(); 297 return validate_arguments(result);
292} 298}
293 299
294int validate_arguments(void) { 300check_dig_config_wrapper validate_arguments(check_dig_config_wrapper config_wrapper) {
295 if (query_address != NULL) 301 if (config_wrapper.config.query_address == NULL) {
296 return OK; 302 config_wrapper.errorcode = ERROR;
297 return ERROR; 303 }
304 return config_wrapper;
298} 305}
299 306
300void print_help(void) { 307void print_help(void) {
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_dns.c b/plugins/check_dns.c
index e1e7c00e..95f33083 100644
--- a/plugins/check_dns.c
+++ b/plugins/check_dns.c
@@ -39,26 +39,22 @@ 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
42static int process_arguments(int /*argc*/, char ** /*argv*/); 42#include "states.h"
43static int validate_arguments(void); 43#include "check_dns.d/config.h"
44static int error_scan(char * /*input_buffer*/, bool *); 44
45typedef struct {
46 int errorcode;
47 check_dns_config config;
48} check_dns_config_wrapper;
49static check_dns_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static check_dns_config_wrapper validate_arguments(check_dns_config_wrapper /*config_wrapper*/);
51static mp_state_enum error_scan(char * /*input_buffer*/, bool * /*is_nxdomain*/, const char /*dns_server*/[ADDRESS_LENGTH]);
45static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/); 52static bool ip_match_cidr(const char * /*addr*/, const char * /*cidr_ro*/);
46static unsigned long ip2long(const char * /*src*/); 53static unsigned long ip2long(const char * /*src*/);
47static void print_help(void); 54static void print_help(void);
48void print_usage(void); 55void print_usage(void);
49 56
50#define ADDRESS_LENGTH 256
51static char query_address[ADDRESS_LENGTH] = "";
52static char dns_server[ADDRESS_LENGTH] = "";
53static char ptr_server[ADDRESS_LENGTH] = "";
54static bool verbose = false; 57static bool verbose = false;
55static char **expected_address = NULL;
56static int expected_address_cnt = 0;
57static bool expect_nxdomain = false;
58
59static bool expect_authority = false;
60static bool all_match = false;
61static thresholds *time_thresholds = NULL;
62 58
63static int qstrcmp(const void *p1, const void *p2) { 59static int qstrcmp(const void *p1, const void *p2) {
64 /* The actual arguments to this function are "pointers to 60 /* The actual arguments to this function are "pointers to
@@ -68,23 +64,6 @@ static int qstrcmp(const void *p1, const void *p2) {
68} 64}
69 65
70int main(int argc, char **argv) { 66int main(int argc, char **argv) {
71 char *command_line = NULL;
72 char input_buffer[MAX_INPUT_BUFFER];
73 char *address = NULL; /* comma separated str with addrs/ptrs (sorted) */
74 char **addresses = NULL;
75 int n_addresses = 0;
76 char *msg = NULL;
77 char *temp_buffer = NULL;
78 bool non_authoritative = false;
79 int result = STATE_UNKNOWN;
80 double elapsed_time;
81 long microsec;
82 struct timeval tv;
83 bool parse_address = false; /* This flag scans for Address: but only after Name: */
84 output chld_out;
85 output chld_err;
86 bool is_nxdomain = false;
87
88 setlocale(LC_ALL, ""); 67 setlocale(LC_ALL, "");
89 bindtextdomain(PACKAGE, LOCALEDIR); 68 bindtextdomain(PACKAGE, LOCALEDIR);
90 textdomain(PACKAGE); 69 textdomain(PACKAGE);
@@ -97,39 +76,65 @@ int main(int argc, char **argv) {
97 /* Parse extra opts if any */ 76 /* Parse extra opts if any */
98 argv = np_extra_opts(&argc, argv, progname); 77 argv = np_extra_opts(&argc, argv, progname);
99 78
100 if (process_arguments(argc, argv) == ERROR) { 79 check_dns_config_wrapper tmp = process_arguments(argc, argv);
80
81 if (tmp.errorcode == ERROR) {
101 usage_va(_("Could not parse arguments")); 82 usage_va(_("Could not parse arguments"));
102 } 83 }
103 84
85 const check_dns_config config = tmp.config;
86
87 char *command_line = NULL;
104 /* get the command to run */ 88 /* get the command to run */
105 xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, query_address, dns_server); 89 xasprintf(&command_line, "%s %s %s", NSLOOKUP_COMMAND, config.query_address, config.dns_server);
106 90
91 struct timeval tv;
107 alarm(timeout_interval); 92 alarm(timeout_interval);
108 gettimeofday(&tv, NULL); 93 gettimeofday(&tv, NULL);
109 94
110 if (verbose) 95 if (verbose) {
111 printf("%s\n", command_line); 96 printf("%s\n", command_line);
97 }
112 98
99 output chld_out;
100 output chld_err;
101 char *msg = NULL;
102 mp_state_enum result = STATE_UNKNOWN;
113 /* run the command */ 103 /* run the command */
114 if ((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) { 104 if ((np_runcmd(command_line, &chld_out, &chld_err, 0)) != 0) {
115 msg = (char *)_("nslookup returned an error status"); 105 msg = (char *)_("nslookup returned an error status");
116 result = STATE_WARNING; 106 result = STATE_WARNING;
117 } 107 }
118 108
119 /* scan stdout */ 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: */
120 for (size_t i = 0; i < chld_out.lines; i++) { 119 for (size_t i = 0; i < chld_out.lines; i++) {
121 if (addresses == NULL) 120 if (addresses == NULL) {
122 addresses = malloc(sizeof(*addresses) * 10); 121 addresses = malloc(sizeof(*addresses) * 10);
123 else if (!(n_addresses % 10)) 122 } else if (!(n_addresses % 10)) {
124 addresses = realloc(addresses, sizeof(*addresses) * (n_addresses + 10)); 123 addresses = realloc(addresses, sizeof(*addresses) * (n_addresses + 10));
124 }
125 125
126 if (verbose) 126 if (verbose) {
127 puts(chld_out.line[i]); 127 puts(chld_out.line[i]);
128 }
128 129
129 if (strcasestr(chld_out.line[i], ".in-addr.arpa") || strcasestr(chld_out.line[i], ".ip6.arpa")) { 130 if (strcasestr(chld_out.line[i], ".in-addr.arpa") || strcasestr(chld_out.line[i], ".ip6.arpa")) {
130 if ((temp_buffer = strstr(chld_out.line[i], "name = "))) 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 = "))) {
131 addresses[n_addresses++] = strdup(temp_buffer + 7); 136 addresses[n_addresses++] = strdup(temp_buffer + 7);
132 else { 137 } else {
133 msg = (char *)_("Warning plugin error"); 138 msg = (char *)_("Warning plugin error");
134 result = STATE_WARNING; 139 result = STATE_WARNING;
135 } 140 }
@@ -137,37 +142,47 @@ int main(int argc, char **argv) {
137 142
138 /* bug ID: 2946553 - Older versions of bind will use all available dns 143 /* bug ID: 2946553 - Older versions of bind will use all available dns
139 servers, we have to match the one specified */ 144 servers, we have to match the one specified */
140 if (strstr(chld_out.line[i], "Server:") && strlen(dns_server) > 0) { 145 if (strstr(chld_out.line[i], "Server:") && strlen(config.dns_server) > 0) {
141 temp_buffer = strchr(chld_out.line[i], ':'); 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
142 temp_buffer++; 151 temp_buffer++;
143 152
144 /* Strip leading tabs */ 153 /* Strip leading tabs */
145 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) 154 for (; *temp_buffer != '\0' && *temp_buffer == '\t'; temp_buffer++) {
146 /* NOOP */; 155 /* NOOP */;
156 }
147 157
148 strip(temp_buffer); 158 strip(temp_buffer);
149 if (temp_buffer == NULL || strlen(temp_buffer) == 0) { 159 if (strlen(temp_buffer) == 0) {
150 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"), NSLOOKUP_COMMAND); 160 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty server string\n"), NSLOOKUP_COMMAND);
151 } 161 }
152 162
153 if (strcmp(temp_buffer, dns_server) != 0) { 163 if (strcmp(temp_buffer, config.dns_server) != 0) {
154 die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), dns_server); 164 die(STATE_CRITICAL, _("DNS CRITICAL - No response from DNS %s\n"), config.dns_server);
155 } 165 }
156 } 166 }
157 167
158 /* the server is responding, we just got the host name... */ 168 /* the server is responding, we just got the host name... */
159 if (strstr(chld_out.line[i], "Name:")) 169 if (strstr(chld_out.line[i], "Name:")) {
160 parse_address = true; 170 parse_address = true;
161 else if (parse_address && (strstr(chld_out.line[i], "Address:") || strstr(chld_out.line[i], "Addresses:"))) { 171 } else if (parse_address && (strstr(chld_out.line[i], "Address:") || strstr(chld_out.line[i], "Addresses:"))) {
162 temp_buffer = index(chld_out.line[i], ':'); 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
163 temp_buffer++; 177 temp_buffer++;
164 178
165 /* Strip leading spaces */ 179 /* Strip leading spaces */
166 while (*temp_buffer == ' ') 180 while (*temp_buffer == ' ') {
167 temp_buffer++; 181 temp_buffer++;
182 }
168 183
169 strip(temp_buffer); 184 strip(temp_buffer);
170 if (temp_buffer == NULL || strlen(temp_buffer) == 0) { 185 if (strlen(temp_buffer) == 0) {
171 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"), NSLOOKUP_COMMAND); 186 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' returned empty host name string\n"), NSLOOKUP_COMMAND);
172 } 187 }
173 188
@@ -176,65 +191,71 @@ int main(int argc, char **argv) {
176 non_authoritative = true; 191 non_authoritative = true;
177 } 192 }
178 193
179 result = error_scan(chld_out.line[i], &is_nxdomain); 194 result = error_scan(chld_out.line[i], &is_nxdomain, config.dns_server);
180 if (result != STATE_OK) { 195 if (result != STATE_OK) {
181 msg = strchr(chld_out.line[i], ':'); 196 msg = strchr(chld_out.line[i], ':');
182 if (msg) 197 if (msg) {
183 msg++; 198 msg++;
199 }
184 break; 200 break;
185 } 201 }
186 } 202 }
187 203
204 char input_buffer[MAX_INPUT_BUFFER];
188 /* scan stderr */ 205 /* scan stderr */
189 for (size_t i = 0; i < chld_err.lines; i++) { 206 for (size_t i = 0; i < chld_err.lines; i++) {
190 if (verbose) 207 if (verbose) {
191 puts(chld_err.line[i]); 208 puts(chld_err.line[i]);
209 }
192 210
193 if (error_scan(chld_err.line[i], &is_nxdomain) != STATE_OK) { 211 if (error_scan(chld_err.line[i], &is_nxdomain, config.dns_server) != STATE_OK) {
194 result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain)); 212 result = max_state(result, error_scan(chld_err.line[i], &is_nxdomain, config.dns_server));
195 msg = strchr(input_buffer, ':'); 213 msg = strchr(input_buffer, ':');
196 if (msg) 214 if (msg) {
197 msg++; 215 msg++;
198 else 216 } else {
199 msg = input_buffer; 217 msg = input_buffer;
218 }
200 } 219 }
201 } 220 }
202 221
203 if (is_nxdomain && !expect_nxdomain) { 222 if (is_nxdomain && !config.expect_nxdomain) {
204 die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), query_address); 223 die(STATE_CRITICAL, _("Domain '%s' was not found by the server\n"), config.query_address);
205 } 224 }
206 225
207 if (addresses) { 226 if (addresses) {
208 int i; 227 size_t slen = 1;
209 int slen; 228 char *adrp = NULL;
210 char *adrp;
211 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp); 229 qsort(addresses, n_addresses, sizeof(*addresses), qstrcmp);
212 for (i = 0, slen = 1; i < n_addresses; i++) { 230 for (size_t i = 0; i < n_addresses; i++) {
213 slen += strlen(addresses[i]) + 1; 231 slen += strlen(addresses[i]) + 1;
214 } 232 }
233
234 // Temporary pointer adrp gets moved, address stays on the beginning
215 adrp = address = malloc(slen); 235 adrp = address = malloc(slen);
216 for (i = 0; i < n_addresses; i++) { 236 for (size_t i = 0; i < n_addresses; i++) {
217 if (i) 237 if (i) {
218 *adrp++ = ','; 238 *adrp++ = ',';
239 }
219 strcpy(adrp, addresses[i]); 240 strcpy(adrp, addresses[i]);
220 adrp += strlen(addresses[i]); 241 adrp += strlen(addresses[i]);
221 } 242 }
222 *adrp = 0; 243 *adrp = 0;
223 } else 244 } else {
224 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), NSLOOKUP_COMMAND); 245 die(STATE_CRITICAL, _("DNS CRITICAL - '%s' msg parsing exited with no address\n"), NSLOOKUP_COMMAND);
246 }
225 247
226 /* compare to expected address */ 248 /* compare to expected address */
227 if (result == STATE_OK && expected_address_cnt > 0) { 249 if (result == STATE_OK && config.expected_address_cnt > 0) {
228 result = STATE_CRITICAL; 250 result = STATE_CRITICAL;
229 temp_buffer = ""; 251 char *temp_buffer = "";
230 unsigned long expect_match = (1 << expected_address_cnt) - 1; 252 unsigned long expect_match = (1 << config.expected_address_cnt) - 1;
231 unsigned long addr_match = (1 << n_addresses) - 1; 253 unsigned long addr_match = (1 << n_addresses) - 1;
232 254
233 for (int i = 0; i < expected_address_cnt; i++) { 255 for (size_t i = 0; i < config.expected_address_cnt; i++) {
234 int j;
235 /* check if we get a match on 'raw' ip or cidr */ 256 /* check if we get a match on 'raw' ip or cidr */
236 for (j = 0; j < n_addresses; j++) { 257 for (size_t j = 0; j < n_addresses; j++) {
237 if (strcmp(addresses[j], expected_address[i]) == 0 || ip_match_cidr(addresses[j], expected_address[i])) { 258 if (strcmp(addresses[j], config.expected_address[i]) == 0 || ip_match_cidr(addresses[j], config.expected_address[i])) {
238 result = STATE_OK; 259 result = STATE_OK;
239 addr_match &= ~(1 << j); 260 addr_match &= ~(1 << j);
240 expect_match &= ~(1 << i); 261 expect_match &= ~(1 << i);
@@ -242,11 +263,12 @@ int main(int argc, char **argv) {
242 } 263 }
243 264
244 /* prepare an error string */ 265 /* prepare an error string */
245 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, expected_address[i]); 266 xasprintf(&temp_buffer, "%s%s; ", temp_buffer, config.expected_address[i]);
246 } 267 }
247 /* check if expected_address must cover all in addresses and none may be missing */ 268 /* check if expected_address must cover all in addresses and none may be missing */
248 if (all_match && (expect_match != 0 || addr_match != 0)) 269 if (config.all_match && (expect_match != 0 || addr_match != 0)) {
249 result = STATE_CRITICAL; 270 result = STATE_CRITICAL;
271 }
250 if (result == STATE_CRITICAL) { 272 if (result == STATE_CRITICAL) {
251 /* Strip off last semicolon... */ 273 /* Strip off last semicolon... */
252 temp_buffer[strlen(temp_buffer) - 2] = '\0'; 274 temp_buffer[strlen(temp_buffer) - 2] = '\0';
@@ -254,28 +276,29 @@ int main(int argc, char **argv) {
254 } 276 }
255 } 277 }
256 278
257 if (expect_nxdomain) { 279 if (config.expect_nxdomain) {
258 if (!is_nxdomain) { 280 if (!is_nxdomain) {
259 result = STATE_CRITICAL; 281 result = STATE_CRITICAL;
260 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), query_address, address); 282 xasprintf(&msg, _("Domain '%s' was found by the server: '%s'\n"), config.query_address, address);
261 } else { 283 } else {
262 if (address != NULL) 284 if (address != NULL) {
263 free(address); 285 free(address);
286 }
264 address = "NXDOMAIN"; 287 address = "NXDOMAIN";
265 } 288 }
266 } 289 }
267 290
268 /* check if authoritative */ 291 /* check if authoritative */
269 if (result == STATE_OK && expect_authority && non_authoritative) { 292 if (result == STATE_OK && config.expect_authority && non_authoritative) {
270 result = STATE_CRITICAL; 293 result = STATE_CRITICAL;
271 xasprintf(&msg, _("server %s is not authoritative for %s"), dns_server, query_address); 294 xasprintf(&msg, _("server %s is not authoritative for %s"), config.dns_server, config.query_address);
272 } 295 }
273 296
274 microsec = deltime(tv); 297 long microsec = deltime(tv);
275 elapsed_time = (double)microsec / 1.0e6; 298 double elapsed_time = (double)microsec / 1.0e6;
276 299
277 if (result == STATE_OK) { 300 if (result == STATE_OK) {
278 result = get_status(elapsed_time, time_thresholds); 301 result = get_status(elapsed_time, config.time_thresholds);
279 if (result == STATE_OK) { 302 if (result == STATE_OK) {
280 printf("DNS %s: ", _("OK")); 303 printf("DNS %s: ", _("OK"));
281 } else if (result == STATE_WARNING) { 304 } else if (result == STATE_WARNING) {
@@ -284,24 +307,26 @@ int main(int argc, char **argv) {
284 printf("DNS %s: ", _("CRITICAL")); 307 printf("DNS %s: ", _("CRITICAL"));
285 } 308 }
286 printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time); 309 printf(ngettext("%.3f second response time", "%.3f seconds response time", elapsed_time), elapsed_time);
287 printf(_(". %s returns %s"), query_address, address); 310 printf(_(". %s returns %s"), config.query_address, address);
288 if ((time_thresholds->warning != NULL) && (time_thresholds->critical != NULL)) { 311 if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical != NULL)) {
289 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, time_thresholds->warning->end, true, time_thresholds->critical->end, 312 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, true,
290 true, 0, false, 0)); 313 config.time_thresholds->critical->end, true, 0, false, 0));
291 } else if ((time_thresholds->warning == NULL) && (time_thresholds->critical != NULL)) { 314 } else if ((config.time_thresholds->warning == NULL) && (config.time_thresholds->critical != NULL)) {
292 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, time_thresholds->critical->end, true, 0, false, 0)); 315 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, true, config.time_thresholds->critical->end, true, 0, false, 0));
293 } else if ((time_thresholds->warning != NULL) && (time_thresholds->critical == NULL)) { 316 } else if ((config.time_thresholds->warning != NULL) && (config.time_thresholds->critical == NULL)) {
294 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, time_thresholds->warning->end, false, 0, true, 0, false, 0)); 317 printf("|%s\n", fperfdata("time", elapsed_time, "s", true, config.time_thresholds->warning->end, false, 0, true, 0, false, 0));
295 } else 318 } else {
296 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0)); 319 printf("|%s\n", fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, false, 0));
297 } else if (result == STATE_WARNING) 320 }
321 } else if (result == STATE_WARNING) {
298 printf(_("DNS WARNING - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg); 322 printf(_("DNS WARNING - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
299 else if (result == STATE_CRITICAL) 323 } else if (result == STATE_CRITICAL) {
300 printf(_("DNS CRITICAL - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg); 324 printf(_("DNS CRITICAL - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
301 else 325 } else {
302 printf(_("DNS UNKNOWN - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg); 326 printf(_("DNS UNKNOWN - %s\n"), !strcmp(msg, "") ? _(" Probably a non-existent host/domain") : msg);
327 }
303 328
304 return result; 329 exit(result);
305} 330}
306 331
307bool ip_match_cidr(const char *addr, const char *cidr_ro) { 332bool ip_match_cidr(const char *addr, const char *cidr_ro) {
@@ -329,64 +354,69 @@ unsigned long ip2long(const char *src) {
329 : 0; 354 : 0;
330} 355}
331 356
332int error_scan(char *input_buffer, bool *is_nxdomain) { 357mp_state_enum error_scan(char *input_buffer, bool *is_nxdomain, const char dns_server[ADDRESS_LENGTH]) {
333 358
334 const int nxdomain = strstr(input_buffer, "Non-existent") || strstr(input_buffer, "** server can't find") || 359 const int nxdomain = strstr(input_buffer, "Non-existent") || strstr(input_buffer, "** server can't find") ||
335 strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN"); 360 strstr(input_buffer, "** Can't find") || strstr(input_buffer, "NXDOMAIN");
336 if (nxdomain) 361 if (nxdomain) {
337 *is_nxdomain = true; 362 *is_nxdomain = true;
363 }
338 364
339 /* the DNS lookup timed out */ 365 /* the DNS lookup timed out */
340 if (strstr(input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) || 366 if (strstr(input_buffer, _("Note: nslookup is deprecated and may be removed from future releases.")) ||
341 strstr(input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) || 367 strstr(input_buffer, _("Consider using the `dig' or `host' programs instead. Run nslookup with")) ||
342 strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing."))) 368 strstr(input_buffer, _("the `-sil[ent]' option to prevent this message from appearing."))) {
343 return STATE_OK; 369 return STATE_OK;
370 }
344 371
345 /* DNS server is not running... */ 372 /* DNS server is not running... */
346 else if (strstr(input_buffer, "No response from server")) 373 else if (strstr(input_buffer, "No response from server")) {
347 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server); 374 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
348 else if (strstr(input_buffer, "no servers could be reached")) 375 } else if (strstr(input_buffer, "no servers could be reached")) {
349 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server); 376 die(STATE_CRITICAL, _("No response from DNS %s\n"), dns_server);
377 }
350 378
351 /* Host name is valid, but server doesn't have records... */ 379 /* Host name is valid, but server doesn't have records... */
352 else if (strstr(input_buffer, "No records")) 380 else if (strstr(input_buffer, "No records")) {
353 die(STATE_CRITICAL, _("DNS %s has no records\n"), dns_server); 381 die(STATE_CRITICAL, _("DNS %s has no records\n"), dns_server);
382 }
354 383
355 /* Connection was refused */ 384 /* Connection was refused */
356 else if (strstr(input_buffer, "Connection refused") || strstr(input_buffer, "Couldn't find server") || 385 else if (strstr(input_buffer, "Connection refused") || strstr(input_buffer, "Couldn't find server") ||
357 strstr(input_buffer, "Refused") || (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) 386 strstr(input_buffer, "Refused") || (strstr(input_buffer, "** server can't find") && strstr(input_buffer, ": REFUSED"))) {
358 die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server); 387 die(STATE_CRITICAL, _("Connection to DNS %s was refused\n"), dns_server);
388 }
359 389
360 /* Query refused (usually by an ACL in the namserver) */ 390 /* Query refused (usually by an ACL in the namserver) */
361 else if (strstr(input_buffer, "Query refused")) 391 else if (strstr(input_buffer, "Query refused")) {
362 die(STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server); 392 die(STATE_CRITICAL, _("Query was refused by DNS server at %s\n"), dns_server);
393 }
363 394
364 /* No information (e.g. nameserver IP has two PTR records) */ 395 /* No information (e.g. nameserver IP has two PTR records) */
365 else if (strstr(input_buffer, "No information")) 396 else if (strstr(input_buffer, "No information")) {
366 die(STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server); 397 die(STATE_CRITICAL, _("No information returned by DNS server at %s\n"), dns_server);
398 }
367 399
368 /* Network is unreachable */ 400 /* Network is unreachable */
369 else if (strstr(input_buffer, "Network is unreachable")) 401 else if (strstr(input_buffer, "Network is unreachable")) {
370 die(STATE_CRITICAL, _("Network is unreachable\n")); 402 die(STATE_CRITICAL, _("Network is unreachable\n"));
403 }
371 404
372 /* Internal server failure */ 405 /* Internal server failure */
373 else if (strstr(input_buffer, "Server failure")) 406 else if (strstr(input_buffer, "Server failure")) {
374 die(STATE_CRITICAL, _("DNS failure for %s\n"), dns_server); 407 die(STATE_CRITICAL, _("DNS failure for %s\n"), dns_server);
408 }
375 409
376 /* Request error or the DNS lookup timed out */ 410 /* Request error or the DNS lookup timed out */
377 else if (strstr(input_buffer, "Format error") || strstr(input_buffer, "Timed out")) 411 else if (strstr(input_buffer, "Format error") || strstr(input_buffer, "Timed out")) {
378 return STATE_WARNING; 412 return STATE_WARNING;
413 }
379 414
380 return STATE_OK; 415 return STATE_OK;
381} 416}
382 417
383/* process command-line arguments */ 418/* process command-line arguments */
384int process_arguments(int argc, char **argv) { 419check_dns_config_wrapper process_arguments(int argc, char **argv) {
385 int c;
386 char *warning = NULL;
387 char *critical = NULL;
388
389 int opt_index = 0;
390 static struct option long_opts[] = {{"help", no_argument, 0, 'h'}, 420 static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
391 {"version", no_argument, 0, 'V'}, 421 {"version", no_argument, 0, 'V'},
392 {"verbose", no_argument, 0, 'v'}, 422 {"verbose", no_argument, 0, 'v'},
@@ -402,20 +432,34 @@ int process_arguments(int argc, char **argv) {
402 {"critical", required_argument, 0, 'c'}, 432 {"critical", required_argument, 0, 'c'},
403 {0, 0, 0, 0}}; 433 {0, 0, 0, 0}};
404 434
405 if (argc < 2) 435 check_dns_config_wrapper result = {
406 return ERROR; 436 .config = check_dns_config_init(),
437 .errorcode = OK,
438 };
407 439
408 for (c = 1; c < argc; c++) 440 if (argc < 2) {
409 if (strcmp("-to", argv[c]) == 0) 441 result.errorcode = ERROR;
410 strcpy(argv[c], "-t"); 442 return result;
443 }
411 444
412 while (1) { 445 for (int index = 1; index < argc; index++) {
413 c = getopt_long(argc, argv, "hVvALnt:H:s:r:a:w:c:", long_opts, &opt_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);
414 457
415 if (c == -1 || c == EOF) 458 if (index == -1 || index == EOF) {
416 break; 459 break;
460 }
417 461
418 switch (c) { 462 switch (index) {
419 case 'h': /* help */ 463 case 'h': /* help */
420 print_help(); 464 print_help();
421 exit(STATE_UNKNOWN); 465 exit(STATE_UNKNOWN);
@@ -429,54 +473,63 @@ int process_arguments(int argc, char **argv) {
429 timeout_interval = atoi(optarg); 473 timeout_interval = atoi(optarg);
430 break; 474 break;
431 case 'H': /* hostname */ 475 case 'H': /* hostname */
432 if (strlen(optarg) >= ADDRESS_LENGTH) 476 if (strlen(optarg) >= ADDRESS_LENGTH) {
433 die(STATE_UNKNOWN, _("Input buffer overflow\n")); 477 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
434 strcpy(query_address, optarg); 478 }
479 strcpy(result.config.query_address, optarg);
435 break; 480 break;
436 case 's': /* server name */ 481 case 's': /* server name */
437 /* TODO: this host_or_die check is probably unnecessary. 482 /* TODO: this host_or_die check is probably unnecessary.
438 * Better to confirm nslookup response matches */ 483 * Better to confirm nslookup response matches */
439 host_or_die(optarg); 484 host_or_die(optarg);
440 if (strlen(optarg) >= ADDRESS_LENGTH) 485 if (strlen(optarg) >= ADDRESS_LENGTH) {
441 die(STATE_UNKNOWN, _("Input buffer overflow\n")); 486 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
442 strcpy(dns_server, optarg); 487 }
488 strcpy(result.config.dns_server, optarg);
443 break; 489 break;
444 case 'r': /* reverse server name */ 490 case 'r': /* reverse server name */
445 /* TODO: Is this host_or_die necessary? */ 491 /* TODO: Is this host_or_die necessary? */
492 // TODO This does not do anything!!! 2025-03-08 rincewind
446 host_or_die(optarg); 493 host_or_die(optarg);
447 if (strlen(optarg) >= ADDRESS_LENGTH) 494 if (strlen(optarg) >= ADDRESS_LENGTH) {
448 die(STATE_UNKNOWN, _("Input buffer overflow\n")); 495 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
496 }
497 static char ptr_server[ADDRESS_LENGTH] = "";
449 strcpy(ptr_server, optarg); 498 strcpy(ptr_server, optarg);
450 break; 499 break;
451 case 'a': /* expected address */ 500 case 'a': /* expected address */
452 if (strlen(optarg) >= ADDRESS_LENGTH) 501 if (strlen(optarg) >= ADDRESS_LENGTH) {
453 die(STATE_UNKNOWN, _("Input buffer overflow\n")); 502 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
503 }
454 if (strchr(optarg, ',') != NULL) { 504 if (strchr(optarg, ',') != NULL) {
455 char *comma = strchr(optarg, ','); 505 char *comma = strchr(optarg, ',');
456 while (comma != NULL) { 506 while (comma != NULL) {
457 expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **)); 507 result.config.expected_address =
458 expected_address[expected_address_cnt] = strndup(optarg, comma - optarg); 508 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
459 expected_address_cnt++; 509 result.config.expected_address[result.config.expected_address_cnt] = strndup(optarg, comma - optarg);
510 result.config.expected_address_cnt++;
460 optarg = comma + 1; 511 optarg = comma + 1;
461 comma = strchr(optarg, ','); 512 comma = strchr(optarg, ',');
462 } 513 }
463 expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **)); 514 result.config.expected_address =
464 expected_address[expected_address_cnt] = strdup(optarg); 515 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
465 expected_address_cnt++; 516 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
517 result.config.expected_address_cnt++;
466 } else { 518 } else {
467 expected_address = (char **)realloc(expected_address, (expected_address_cnt + 1) * sizeof(char **)); 519 result.config.expected_address =
468 expected_address[expected_address_cnt] = strdup(optarg); 520 (char **)realloc(result.config.expected_address, (result.config.expected_address_cnt + 1) * sizeof(char **));
469 expected_address_cnt++; 521 result.config.expected_address[result.config.expected_address_cnt] = strdup(optarg);
522 result.config.expected_address_cnt++;
470 } 523 }
471 break; 524 break;
472 case 'n': /* expect NXDOMAIN */ 525 case 'n': /* expect NXDOMAIN */
473 expect_nxdomain = true; 526 result.config.expect_nxdomain = true;
474 break; 527 break;
475 case 'A': /* expect authority */ 528 case 'A': /* expect authority */
476 expect_authority = true; 529 result.config.expect_authority = true;
477 break; 530 break;
478 case 'L': /* all must match */ 531 case 'L': /* all must match */
479 all_match = true; 532 result.config.all_match = true;
480 break; 533 break;
481 case 'w': 534 case 'w':
482 warning = optarg; 535 warning = optarg;
@@ -489,38 +542,42 @@ int process_arguments(int argc, char **argv) {
489 } 542 }
490 } 543 }
491 544
492 c = optind; 545 index = optind;
493 if (strlen(query_address) == 0 && c < argc) { 546 if (strlen(result.config.query_address) == 0 && index < argc) {
494 if (strlen(argv[c]) >= ADDRESS_LENGTH) 547 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
495 die(STATE_UNKNOWN, _("Input buffer overflow\n")); 548 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
496 strcpy(query_address, argv[c++]); 549 }
550 strcpy(result.config.query_address, argv[index++]);
497 } 551 }
498 552
499 if (strlen(dns_server) == 0 && c < argc) { 553 if (strlen(result.config.dns_server) == 0 && index < argc) {
500 /* TODO: See -s option */ 554 /* TODO: See -s option */
501 host_or_die(argv[c]); 555 host_or_die(argv[index]);
502 if (strlen(argv[c]) >= ADDRESS_LENGTH) 556 if (strlen(argv[index]) >= ADDRESS_LENGTH) {
503 die(STATE_UNKNOWN, _("Input buffer overflow\n")); 557 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
504 strcpy(dns_server, argv[c++]); 558 }
559 strcpy(result.config.dns_server, argv[index++]);
505 } 560 }
506 561
507 set_thresholds(&time_thresholds, warning, critical); 562 set_thresholds(&result.config.time_thresholds, warning, critical);
508 563
509 return validate_arguments(); 564 return validate_arguments(result);
510} 565}
511 566
512int validate_arguments(void) { 567check_dns_config_wrapper validate_arguments(check_dns_config_wrapper config_wrapper) {
513 if (query_address[0] == 0) { 568 if (config_wrapper.config.query_address[0] == 0) {
514 printf("missing --host argument\n"); 569 printf("missing --host argument\n");
515 return ERROR; 570 config_wrapper.errorcode = ERROR;
571 return config_wrapper;
516 } 572 }
517 573
518 if (expected_address_cnt > 0 && expect_nxdomain) { 574 if (config_wrapper.config.expected_address_cnt > 0 && config_wrapper.config.expect_nxdomain) {
519 printf("--expected-address and --expect-nxdomain cannot be combined\n"); 575 printf("--expected-address and --expect-nxdomain cannot be combined\n");
520 return ERROR; 576 config_wrapper.errorcode = ERROR;
577 return config_wrapper;
521 } 578 }
522 579
523 return OK; 580 return config_wrapper;
524} 581}
525 582
526void print_help(void) { 583void print_help(void) {
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_fping.c b/plugins/check_fping.c
index c1d03ece..ec7abb67 100644
--- a/plugins/check_fping.c
+++ b/plugins/check_fping.c
@@ -38,52 +38,29 @@ 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,
44 PACKET_SIZE = 56,
45 PL = 0, 45 PL = 0,
46 RTA = 1 46 RTA = 1
47}; 47};
48 48
49static int textscan(char *buf); 49static mp_state_enum textscan(char *buf, const char * /*server_name*/, bool /*crta_p*/, double /*crta*/, bool /*wrta_p*/, double /*wrta*/,
50static int process_arguments(int /*argc*/, char ** /*argv*/); 50 bool /*cpl_p*/, int /*cpl*/, bool /*wpl_p*/, int /*wpl*/, bool /*alive_p*/);
51
52typedef struct {
53 int errorcode;
54 check_fping_config config;
55} check_fping_config_wrapper;
56static check_fping_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
51static int get_threshold(char *arg, char *rv[2]); 57static int get_threshold(char *arg, char *rv[2]);
52static void print_help(void); 58static void print_help(void);
53void print_usage(void); 59void print_usage(void);
54 60
55static char *server_name = NULL;
56static char *sourceip = NULL;
57static char *sourceif = NULL;
58static int packet_size = PACKET_SIZE;
59static int packet_count = PACKET_COUNT;
60static int target_timeout = 0;
61static int packet_interval = 0;
62static bool verbose = false; 61static bool verbose = false;
63static bool dontfrag = false;
64static bool randomize_packet_data = false;
65static int cpl;
66static int wpl;
67static double crta;
68static double wrta;
69static bool cpl_p = false;
70static bool wpl_p = false;
71static bool alive_p = false;
72static bool crta_p = false;
73static bool wrta_p = false;
74 62
75int main(int argc, char **argv) { 63int main(int argc, char **argv) {
76 /* normally should be int result = STATE_UNKNOWN; */
77
78 int status = STATE_UNKNOWN;
79 int result = 0;
80 char *fping_prog = NULL;
81 char *server = NULL;
82 char *command_line = NULL;
83 char *input_buffer = NULL;
84 char *option_string = "";
85 input_buffer = malloc(MAX_INPUT_BUFFER);
86
87 setlocale(LC_ALL, ""); 64 setlocale(LC_ALL, "");
88 bindtextdomain(PACKAGE, LOCALEDIR); 65 bindtextdomain(PACKAGE, LOCALEDIR);
89 textdomain(PACKAGE); 66 textdomain(PACKAGE);
@@ -91,39 +68,54 @@ int main(int argc, char **argv) {
91 /* Parse extra opts if any */ 68 /* Parse extra opts if any */
92 argv = np_extra_opts(&argc, argv, progname); 69 argv = np_extra_opts(&argc, argv, progname);
93 70
94 if (process_arguments(argc, argv) == ERROR) 71 check_fping_config_wrapper tmp_config = process_arguments(argc, argv);
72 if (tmp_config.errorcode == ERROR) {
95 usage4(_("Could not parse arguments")); 73 usage4(_("Could not parse arguments"));
74 }
96 75
97 server = strscpy(server, server_name); 76 const check_fping_config config = tmp_config.config;
98 77
78 char *server = NULL;
79 server = strscpy(server, config.server_name);
80
81 char *option_string = "";
99 /* compose the command */ 82 /* compose the command */
100 if (target_timeout) 83 if (config.target_timeout) {
101 xasprintf(&option_string, "%s-t %d ", option_string, target_timeout); 84 xasprintf(&option_string, "%s-t %d ", option_string, config.target_timeout);
102 if (packet_interval) 85 }
103 xasprintf(&option_string, "%s-p %d ", option_string, packet_interval); 86 if (config.packet_interval) {
104 if (sourceip) 87 xasprintf(&option_string, "%s-p %d ", option_string, config.packet_interval);
105 xasprintf(&option_string, "%s-S %s ", option_string, sourceip); 88 }
106 if (sourceif) 89 if (config.sourceip) {
107 xasprintf(&option_string, "%s-I %s ", option_string, sourceif); 90 xasprintf(&option_string, "%s-S %s ", option_string, config.sourceip);
108 if (dontfrag) 91 }
92 if (config.sourceif) {
93 xasprintf(&option_string, "%s-I %s ", option_string, config.sourceif);
94 }
95 if (config.dontfrag) {
109 xasprintf(&option_string, "%s-M ", option_string); 96 xasprintf(&option_string, "%s-M ", option_string);
110 if (randomize_packet_data) 97 }
98 if (config.randomize_packet_data) {
111 xasprintf(&option_string, "%s-R ", option_string); 99 xasprintf(&option_string, "%s-R ", option_string);
100 }
112 101
113 102 char *fping_prog = NULL;
114#ifdef PATH_TO_FPING6 103#ifdef PATH_TO_FPING6
115 if (address_family != AF_INET && is_inet6_addr(server)) 104 if (address_family != AF_INET && is_inet6_addr(server)) {
116 fping_prog = strdup(PATH_TO_FPING6); 105 fping_prog = strdup(PATH_TO_FPING6);
117 else 106 } else {
118 fping_prog = strdup(PATH_TO_FPING); 107 fping_prog = strdup(PATH_TO_FPING);
108 }
119#else 109#else
120 fping_prog = strdup(PATH_TO_FPING); 110 fping_prog = strdup(PATH_TO_FPING);
121#endif 111#endif
122 112
123 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, packet_size, packet_count, server); 113 char *command_line = NULL;
114 xasprintf(&command_line, "%s %s-b %d -c %d %s", fping_prog, option_string, config.packet_size, config.packet_count, server);
124 115
125 if (verbose) 116 if (verbose) {
126 printf("%s\n", command_line); 117 printf("%s\n", command_line);
118 }
127 119
128 /* run the command */ 120 /* run the command */
129 child_process = spopen(command_line); 121 child_process = spopen(command_line);
@@ -137,23 +129,29 @@ int main(int argc, char **argv) {
137 printf(_("Could not open stderr for %s\n"), command_line); 129 printf(_("Could not open stderr for %s\n"), command_line);
138 } 130 }
139 131
132 char *input_buffer = malloc(MAX_INPUT_BUFFER);
133 mp_state_enum status = STATE_UNKNOWN;
140 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 134 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
141 if (verbose) 135 if (verbose) {
142 printf("%s", input_buffer); 136 printf("%s", input_buffer);
143 status = max_state(status, textscan(input_buffer)); 137 }
138 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
139 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
144 } 140 }
145 141
146 /* If we get anything on STDERR, at least set warning */ 142 /* If we get anything on STDERR, at least set warning */
147 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 143 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
148 status = max_state(status, STATE_WARNING); 144 status = max_state(status, STATE_WARNING);
149 if (verbose) 145 if (verbose) {
150 printf("%s", input_buffer); 146 printf("%s", input_buffer);
151 status = max_state(status, textscan(input_buffer)); 147 }
148 status = max_state(status, textscan(input_buffer, config.server_name, config.crta_p, config.crta, config.wrta_p, config.wrta,
149 config.cpl_p, config.cpl, config.wpl_p, config.wpl, config.alive_p));
152 } 150 }
153 (void)fclose(child_stderr); 151 (void)fclose(child_stderr);
154 152
155 /* close the pipe */ 153 /* close the pipe */
156 result = spclose(child_process); 154 int result = spclose(child_process);
157 if (result) { 155 if (result) {
158 /* need to use max_state not max */ 156 /* need to use max_state not max */
159 status = max_state(status, STATE_WARNING); 157 status = max_state(status, STATE_WARNING);
@@ -172,21 +170,17 @@ int main(int argc, char **argv) {
172 } 170 }
173 } 171 }
174 172
175 printf("FPING %s - %s\n", state_text(status), server_name); 173 printf("FPING %s - %s\n", state_text(status), config.server_name);
176 174
177 return status; 175 return status;
178} 176}
179 177
180int textscan(char *buf) { 178mp_state_enum textscan(char *buf, const char *server_name, bool crta_p, double crta, bool wrta_p, double wrta, bool cpl_p, int cpl,
181 char *rtastr = NULL; 179 bool wpl_p, int wpl, bool alive_p) {
182 char *losstr = NULL;
183 char *xmtstr = NULL;
184 double loss;
185 double rta;
186 double xmt;
187 int status = STATE_UNKNOWN;
188
189 /* stops testing after the first successful reply. */ 180 /* stops testing after the first successful reply. */
181 double rta;
182 double loss;
183 char *rtastr = NULL;
190 if (alive_p && strstr(buf, "avg, 0% loss)")) { 184 if (alive_p && strstr(buf, "avg, 0% loss)")) {
191 rtastr = strstr(buf, "ms ("); 185 rtastr = strstr(buf, "ms (");
192 rtastr = 1 + index(rtastr, '('); 186 rtastr = 1 + index(rtastr, '(');
@@ -198,6 +192,10 @@ int textscan(char *buf) {
198 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0)); 192 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
199 } 193 }
200 194
195 mp_state_enum status = STATE_UNKNOWN;
196 char *xmtstr = NULL;
197 double xmt;
198 char *losstr = NULL;
201 if (strstr(buf, "not found")) { 199 if (strstr(buf, "not found")) {
202 die(STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name); 200 die(STATE_CRITICAL, _("FPING UNKNOWN - %s not found\n"), server_name);
203 201
@@ -221,18 +219,19 @@ int textscan(char *buf) {
221 rtastr = 1 + index(rtastr, '/'); 219 rtastr = 1 + index(rtastr, '/');
222 loss = strtod(losstr, NULL); 220 loss = strtod(losstr, NULL);
223 rta = strtod(rtastr, NULL); 221 rta = strtod(rtastr, NULL);
224 if (cpl_p && loss > cpl) 222 if (cpl_p && loss > cpl) {
225 status = STATE_CRITICAL; 223 status = STATE_CRITICAL;
226 else if (crta_p && rta > crta) 224 } else if (crta_p && rta > crta) {
227 status = STATE_CRITICAL; 225 status = STATE_CRITICAL;
228 else if (wpl_p && loss > wpl) 226 } else if (wpl_p && loss > wpl) {
229 status = STATE_WARNING; 227 status = STATE_WARNING;
230 else if (wrta_p && rta > wrta) 228 } else if (wrta_p && rta > wrta) {
231 status = STATE_WARNING; 229 status = STATE_WARNING;
232 else 230 } else {
233 status = STATE_OK; 231 status = STATE_OK;
232 }
234 die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status), server_name, loss, rta, 233 die(status, _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"), state_text(status), server_name, loss, rta,
235 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100), 234 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0),
236 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0)); 235 fperfdata("rta", rta / 1.0e3, "s", wrta_p, wrta / 1.0e3, crta_p, crta / 1.0e3, true, 0, false, 0));
237 236
238 } else if (strstr(buf, "xmt/rcv/%loss")) { 237 } else if (strstr(buf, "xmt/rcv/%loss")) {
@@ -241,22 +240,24 @@ int textscan(char *buf) {
241 losstr = strstr(buf, "="); 240 losstr = strstr(buf, "=");
242 xmtstr = 1 + losstr; 241 xmtstr = 1 + losstr;
243 xmt = strtod(xmtstr, NULL); 242 xmt = strtod(xmtstr, NULL);
244 if (xmt == 0) 243 if (xmt == 0) {
245 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name); 244 die(STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
245 }
246 losstr = 1 + strstr(losstr, "/"); 246 losstr = 1 + strstr(losstr, "/");
247 losstr = 1 + strstr(losstr, "/"); 247 losstr = 1 + strstr(losstr, "/");
248 loss = strtod(losstr, NULL); 248 loss = strtod(losstr, NULL);
249 if (atoi(losstr) == 100) 249 if (atoi(losstr) == 100) {
250 status = STATE_CRITICAL; 250 status = STATE_CRITICAL;
251 else if (cpl_p && loss > cpl) 251 } else if (cpl_p && loss > cpl) {
252 status = STATE_CRITICAL; 252 status = STATE_CRITICAL;
253 else if (wpl_p && loss > wpl) 253 } else if (wpl_p && loss > wpl) {
254 status = STATE_WARNING; 254 status = STATE_WARNING;
255 else 255 } else {
256 status = STATE_OK; 256 status = STATE_OK;
257 }
257 /* loss=%.0f%%;%d;%d;0;100 */ 258 /* loss=%.0f%%;%d;%d;0;100 */
258 die(status, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status), server_name, loss, 259 die(status, _("FPING %s - %s (loss=%.0f%% )|%s\n"), state_text(status), server_name, loss,
259 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, true, 0, true, 100)); 260 perfdata("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, false, 0, false, 0));
260 261
261 } else { 262 } else {
262 status = max_state(status, STATE_WARNING); 263 status = max_state(status, STATE_WARNING);
@@ -266,54 +267,50 @@ int textscan(char *buf) {
266} 267}
267 268
268/* process command-line arguments */ 269/* process command-line arguments */
269int process_arguments(int argc, char **argv) { 270check_fping_config_wrapper process_arguments(int argc, char **argv) {
270 int c; 271 static struct option longopts[] = {
272 {"hostname", required_argument, 0, 'H'}, {"sourceip", required_argument, 0, 'S'}, {"sourceif", required_argument, 0, 'I'},
273 {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, {"alive", no_argument, 0, 'a'},
274 {"bytes", required_argument, 0, 'b'}, {"number", required_argument, 0, 'n'}, {"target-timeout", required_argument, 0, 'T'},
275 {"interval", required_argument, 0, 'i'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
276 {"help", no_argument, 0, 'h'}, {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'},
277 {"dontfrag", no_argument, 0, 'M'}, {"random", no_argument, 0, 'R'}, {0, 0, 0, 0}};
278
271 char *rv[2]; 279 char *rv[2];
280 rv[PL] = NULL;
281 rv[RTA] = NULL;
272 282
273 int option = 0; 283 int option = 0;
274 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
275 {"sourceip", required_argument, 0, 'S'},
276 {"sourceif", required_argument, 0, 'I'},
277 {"critical", required_argument, 0, 'c'},
278 {"warning", required_argument, 0, 'w'},
279 {"alive", no_argument, 0, 'a'},
280 {"bytes", required_argument, 0, 'b'},
281 {"number", required_argument, 0, 'n'},
282 {"target-timeout", required_argument, 0, 'T'},
283 {"interval", required_argument, 0, 'i'},
284 {"verbose", no_argument, 0, 'v'},
285 {"version", no_argument, 0, 'V'},
286 {"help", no_argument, 0, 'h'},
287 {"use-ipv4", no_argument, 0, '4'},
288 {"use-ipv6", no_argument, 0, '6'},
289 {"dontfrag", no_argument, 0, 'M'},
290 {"random", no_argument, 0, 'R'},
291 {0, 0, 0, 0}};
292 284
293 rv[PL] = NULL; 285 check_fping_config_wrapper result = {
294 rv[RTA] = NULL; 286 .errorcode = OK,
287 .config = check_fping_config_init(),
288 };
295 289
296 if (argc < 2) 290 if (argc < 2) {
297 return ERROR; 291 result.errorcode = ERROR;
292 return result;
293 }
298 294
299 if (!is_option(argv[1])) { 295 if (!is_option(argv[1])) {
300 server_name = argv[1]; 296 result.config.server_name = argv[1];
301 argv[1] = argv[0]; 297 argv[1] = argv[0];
302 argv = &argv[1]; 298 argv = &argv[1];
303 argc--; 299 argc--;
304 } 300 }
305 301
306 while (1) { 302 while (1) {
307 c = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option); 303 int option_index = getopt_long(argc, argv, "+hVvaH:S:c:w:b:n:T:i:I:M:R:46", longopts, &option);
308 304
309 if (c == -1 || c == EOF || c == 1) 305 if (option_index == -1 || option_index == EOF || option_index == 1) {
310 break; 306 break;
307 }
311 308
312 switch (c) { 309 switch (option_index) {
313 case '?': /* print short usage statement if args not parsable */ 310 case '?': /* print short usage statement if args not parsable */
314 usage5(); 311 usage5();
315 case 'a': /* host alive mode */ 312 case 'a': /* host alive mode */
316 alive_p = true; 313 result.config.alive_p = true;
317 break; 314 break;
318 case 'h': /* help */ 315 case 'h': /* help */
319 print_help(); 316 print_help();
@@ -325,19 +322,19 @@ int process_arguments(int argc, char **argv) {
325 verbose = true; 322 verbose = true;
326 break; 323 break;
327 case 'H': /* hostname */ 324 case 'H': /* hostname */
328 if (is_host(optarg) == false) { 325 if (!is_host(optarg)) {
329 usage2(_("Invalid hostname/address"), optarg); 326 usage2(_("Invalid hostname/address"), optarg);
330 } 327 }
331 server_name = strscpy(server_name, optarg); 328 result.config.server_name = optarg;
332 break; 329 break;
333 case 'S': /* sourceip */ 330 case 'S': /* sourceip */
334 if (is_host(optarg) == false) { 331 if (!is_host(optarg)) {
335 usage2(_("Invalid hostname/address"), optarg); 332 usage2(_("Invalid hostname/address"), optarg);
336 } 333 }
337 sourceip = strscpy(sourceip, optarg); 334 result.config.sourceip = optarg;
338 break; 335 break;
339 case 'I': /* sourceip */ 336 case 'I': /* sourceip */
340 sourceif = strscpy(sourceif, optarg); 337 result.config.sourceif = optarg;
341 break; 338 break;
342 case '4': /* IPv4 only */ 339 case '4': /* IPv4 only */
343 address_family = AF_INET; 340 address_family = AF_INET;
@@ -352,82 +349,89 @@ int process_arguments(int argc, char **argv) {
352 case 'c': 349 case 'c':
353 get_threshold(optarg, rv); 350 get_threshold(optarg, rv);
354 if (rv[RTA]) { 351 if (rv[RTA]) {
355 crta = strtod(rv[RTA], NULL); 352 result.config.crta = strtod(rv[RTA], NULL);
356 crta_p = true; 353 result.config.crta_p = true;
357 rv[RTA] = NULL; 354 rv[RTA] = NULL;
358 } 355 }
359 if (rv[PL]) { 356 if (rv[PL]) {
360 cpl = atoi(rv[PL]); 357 result.config.cpl = atoi(rv[PL]);
361 cpl_p = true; 358 result.config.cpl_p = true;
362 rv[PL] = NULL; 359 rv[PL] = NULL;
363 } 360 }
364 break; 361 break;
365 case 'w': 362 case 'w':
366 get_threshold(optarg, rv); 363 get_threshold(optarg, rv);
367 if (rv[RTA]) { 364 if (rv[RTA]) {
368 wrta = strtod(rv[RTA], NULL); 365 result.config.wrta = strtod(rv[RTA], NULL);
369 wrta_p = true; 366 result.config.wrta_p = true;
370 rv[RTA] = NULL; 367 rv[RTA] = NULL;
371 } 368 }
372 if (rv[PL]) { 369 if (rv[PL]) {
373 wpl = atoi(rv[PL]); 370 result.config.wpl = atoi(rv[PL]);
374 wpl_p = true; 371 result.config.wpl_p = true;
375 rv[PL] = NULL; 372 rv[PL] = NULL;
376 } 373 }
377 break; 374 break;
378 case 'b': /* bytes per packet */ 375 case 'b': /* bytes per packet */
379 if (is_intpos(optarg)) 376 if (is_intpos(optarg)) {
380 packet_size = atoi(optarg); 377 result.config.packet_size = atoi(optarg);
381 else 378 } else {
382 usage(_("Packet size must be a positive integer")); 379 usage(_("Packet size must be a positive integer"));
380 }
383 break; 381 break;
384 case 'n': /* number of packets */ 382 case 'n': /* number of packets */
385 if (is_intpos(optarg)) 383 if (is_intpos(optarg)) {
386 packet_count = atoi(optarg); 384 result.config.packet_count = atoi(optarg);
387 else 385 } else {
388 usage(_("Packet count must be a positive integer")); 386 usage(_("Packet count must be a positive integer"));
387 }
389 break; 388 break;
390 case 'T': /* timeout in msec */ 389 case 'T': /* timeout in msec */
391 if (is_intpos(optarg)) 390 if (is_intpos(optarg)) {
392 target_timeout = atoi(optarg); 391 result.config.target_timeout = atoi(optarg);
393 else 392 } else {
394 usage(_("Target timeout must be a positive integer")); 393 usage(_("Target timeout must be a positive integer"));
394 }
395 break; 395 break;
396 case 'i': /* interval in msec */ 396 case 'i': /* interval in msec */
397 if (is_intpos(optarg)) 397 if (is_intpos(optarg)) {
398 packet_interval = atoi(optarg); 398 result.config.packet_interval = atoi(optarg);
399 else 399 } else {
400 usage(_("Interval must be a positive integer")); 400 usage(_("Interval must be a positive integer"));
401 }
401 break; 402 break;
402 case 'R': 403 case 'R':
403 randomize_packet_data = true; 404 result.config.randomize_packet_data = true;
404 break; 405 break;
405 case 'M': 406 case 'M':
406 dontfrag = true; 407 result.config.dontfrag = true;
407 break; 408 break;
408 } 409 }
409 } 410 }
410 411
411 if (server_name == NULL) 412 if (result.config.server_name == NULL) {
412 usage4(_("Hostname was not supplied")); 413 usage4(_("Hostname was not supplied"));
414 }
413 415
414 return OK; 416 return result;
415} 417}
416 418
417int get_threshold(char *arg, char *rv[2]) { 419int get_threshold(char *arg, char *rv[2]) {
418 char *arg1 = NULL;
419 char *arg2 = NULL; 420 char *arg2 = NULL;
420 421
421 arg1 = strscpy(arg1, arg); 422 char *arg1 = strdup(arg);
422 if (strpbrk(arg1, ",:")) 423 if (strpbrk(arg1, ",:")) {
423 arg2 = 1 + strpbrk(arg1, ",:"); 424 arg2 = 1 + strpbrk(arg1, ",:");
425 }
424 426
425 if (arg2) { 427 if (arg2) {
426 arg1[strcspn(arg1, ",:")] = 0; 428 arg1[strcspn(arg1, ",:")] = 0;
427 if (strstr(arg1, "%") && strstr(arg2, "%")) 429 if (strstr(arg1, "%") && strstr(arg2, "%")) {
428 die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname, arg); 430 die(STATE_UNKNOWN, _("%s: Only one threshold may be packet loss (%s)\n"), progname, arg);
429 if (!strstr(arg1, "%") && !strstr(arg2, "%")) 431 }
432 if (!strstr(arg1, "%") && !strstr(arg2, "%")) {
430 die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname, arg); 433 die(STATE_UNKNOWN, _("%s: Only one threshold must be packet loss (%s)\n"), progname, arg);
434 }
431 } 435 }
432 436
433 if (arg2 && strstr(arg2, "%")) { 437 if (arg2 && strstr(arg2, "%")) {
diff --git a/plugins/check_fping.d/config.h b/plugins/check_fping.d/config.h
new file mode 100644
index 00000000..a0697bf3
--- /dev/null
+++ b/plugins/check_fping.d/config.h
@@ -0,0 +1,58 @@
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} check_fping_config;
33
34check_fping_config check_fping_config_init() {
35 check_fping_config tmp = {
36 .server_name = NULL,
37 .sourceip = NULL,
38 .sourceif = NULL,
39 .packet_size = PACKET_SIZE,
40 .packet_count = PACKET_COUNT,
41 .target_timeout = 0,
42 .packet_interval = 0,
43 .randomize_packet_data = false,
44 .dontfrag = false,
45 .alive_p = false,
46
47 .crta = 0,
48 .crta_p = false,
49 .wrta = 0,
50 .wrta_p = false,
51
52 .cpl = 0,
53 .cpl_p = false,
54 .wpl = 0,
55 .wpl_p = false,
56 };
57 return tmp;
58}
diff --git a/plugins/check_game.c b/plugins/check_game.c
index 619277e7..c0193b03 100644
--- a/plugins/check_game.c
+++ b/plugins/check_game.c
@@ -36,9 +36,15 @@ const char *email = "devel@monitoring-plugins.org";
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
40static int process_arguments(int /*argc*/, char ** /*argv*/); 42typedef struct {
41static int validate_arguments(void); 43 int errorcode;
44 check_game_config config;
45} check_game_config_wrapper;
46
47static check_game_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
42static void print_help(void); 48static void print_help(void);
43void print_usage(void); 49void print_usage(void);
44 50
@@ -49,26 +55,9 @@ void print_usage(void);
49#define QSTAT_HOST_TIMEOUT "TIMEOUT" 55#define QSTAT_HOST_TIMEOUT "TIMEOUT"
50#define QSTAT_MAX_RETURN_ARGS 12 56#define QSTAT_MAX_RETURN_ARGS 12
51 57
52static char *server_ip;
53static char *game_type;
54static int port = 0;
55
56static bool verbose = false; 58static bool verbose = false;
57 59
58static int qstat_game_players_max = -1;
59static int qstat_game_players = -1;
60static int qstat_game_field = -1;
61static int qstat_map_field = -1;
62static int qstat_ping_field = -1;
63
64int main(int argc, char **argv) { 60int main(int argc, char **argv) {
65 char *command_line;
66 int result = STATE_UNKNOWN;
67 char *p;
68 char *ret[QSTAT_MAX_RETURN_ARGS];
69 size_t i = 0;
70 output chld_out;
71
72 setlocale(LC_ALL, ""); 61 setlocale(LC_ALL, "");
73 bindtextdomain(PACKAGE, LOCALEDIR); 62 bindtextdomain(PACKAGE, LOCALEDIR);
74 textdomain(PACKAGE); 63 textdomain(PACKAGE);
@@ -76,22 +65,31 @@ int main(int argc, char **argv) {
76 /* Parse extra opts if any */ 65 /* Parse extra opts if any */
77 argv = np_extra_opts(&argc, argv, progname); 66 argv = np_extra_opts(&argc, argv, progname);
78 67
79 if (process_arguments(argc, argv) == ERROR) 68 check_game_config_wrapper tmp = process_arguments(argc, argv);
69
70 if (tmp.errorcode == ERROR) {
80 usage_va(_("Could not parse arguments")); 71 usage_va(_("Could not parse arguments"));
72 }
73
74 check_game_config config = tmp.config;
81 75
82 result = STATE_OK; 76 mp_state_enum result = STATE_OK;
83 77
84 /* create the command line to execute */ 78 /* create the command line to execute */
85 xasprintf(&command_line, "%s -raw %s -%s %s", PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, game_type, server_ip); 79 char *command_line = NULL;
80 xasprintf(&command_line, "%s -raw %s -%s %s", PATH_TO_QSTAT, QSTAT_DATA_DELIMITER, config.game_type, config.server_ip);
86 81
87 if (port) 82 if (config.port) {
88 xasprintf(&command_line, "%s:%-d", command_line, port); 83 xasprintf(&command_line, "%s:%-d", command_line, config.port);
84 }
89 85
90 if (verbose) 86 if (verbose) {
91 printf("%s\n", command_line); 87 printf("%s\n", command_line);
88 }
92 89
93 /* run the command. historically, this plugin ignores output on stderr, 90 /* run the command. historically, this plugin ignores output on stderr,
94 * as well as return status of the qstat program */ 91 * as well as return status of the qstat program */
92 output chld_out = {};
95 (void)np_runcmd(command_line, &chld_out, NULL, 0); 93 (void)np_runcmd(command_line, &chld_out, NULL, 0);
96 94
97 /* sanity check */ 95 /* sanity check */
@@ -104,19 +102,22 @@ int main(int argc, char **argv) {
104 In the end, I figured I'd simply let an error occur & then trap it 102 In the end, I figured I'd simply let an error occur & then trap it
105 */ 103 */
106 104
107 if (!strncmp(chld_out.line[0], "unknown option", 14)) { 105 if (!strncmp(chld_out.line[0], "unknown option", strlen("unknown option"))) {
108 printf(_("CRITICAL - Host type parameter incorrect!\n")); 106 printf(_("CRITICAL - Host type parameter incorrect!\n"));
109 result = STATE_CRITICAL; 107 result = STATE_CRITICAL;
110 return result; 108 exit(result);
111 } 109 }
112 110
113 p = (char *)strtok(chld_out.line[0], QSTAT_DATA_DELIMITER); 111 char *ret[QSTAT_MAX_RETURN_ARGS];
114 while (p != NULL) { 112 size_t i = 0;
115 ret[i] = p; 113 char *sequence = strtok(chld_out.line[0], QSTAT_DATA_DELIMITER);
116 p = (char *)strtok(NULL, QSTAT_DATA_DELIMITER); 114 while (sequence != NULL) {
115 ret[i] = sequence;
116 sequence = strtok(NULL, QSTAT_DATA_DELIMITER);
117 i++; 117 i++;
118 if (i >= QSTAT_MAX_RETURN_ARGS) 118 if (i >= QSTAT_MAX_RETURN_ARGS) {
119 break; 119 break;
120 }
120 } 121 }
121 122
122 if (strstr(ret[2], QSTAT_HOST_ERROR)) { 123 if (strstr(ret[2], QSTAT_HOST_ERROR)) {
@@ -129,19 +130,20 @@ int main(int argc, char **argv) {
129 printf(_("CRITICAL - Game server timeout\n")); 130 printf(_("CRITICAL - Game server timeout\n"));
130 result = STATE_CRITICAL; 131 result = STATE_CRITICAL;
131 } else { 132 } else {
132 printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[qstat_game_players], ret[qstat_game_players_max], ret[qstat_game_field], 133 printf("OK: %s/%s %s (%s), Ping: %s ms|%s %s\n", ret[config.qstat_game_players], ret[config.qstat_game_players_max],
133 ret[qstat_map_field], ret[qstat_ping_field], 134 ret[config.qstat_game_field], ret[config.qstat_map_field], ret[config.qstat_ping_field],
134 perfdata("players", atol(ret[qstat_game_players]), "", false, 0, false, 0, true, 0, true, atol(ret[qstat_game_players_max])), 135 perfdata("players", atol(ret[config.qstat_game_players]), "", false, 0, false, 0, true, 0, true,
135 fperfdata("ping", strtod(ret[qstat_ping_field], NULL), "", false, 0, false, 0, true, 0, false, 0)); 136 atol(ret[config.qstat_game_players_max])),
137 fperfdata("ping", strtod(ret[config.qstat_ping_field], NULL), "", false, 0, false, 0, true, 0, false, 0));
136 } 138 }
137 139
138 return result; 140 exit(result);
139} 141}
140 142
141int process_arguments(int argc, char **argv) { 143#define players_field_index 129
142 int c; 144#define max_players_field_index 130
143 145
144 int opt_index = 0; 146check_game_config_wrapper process_arguments(int argc, char **argv) {
145 static struct option long_opts[] = {{"help", no_argument, 0, 'h'}, 147 static struct option long_opts[] = {{"help", no_argument, 0, 'h'},
146 {"version", no_argument, 0, 'V'}, 148 {"version", no_argument, 0, 'V'},
147 {"verbose", no_argument, 0, 'v'}, 149 {"verbose", no_argument, 0, 'v'},
@@ -152,29 +154,39 @@ int process_arguments(int argc, char **argv) {
152 {"map-field", required_argument, 0, 'm'}, 154 {"map-field", required_argument, 0, 'm'},
153 {"ping-field", required_argument, 0, 'p'}, 155 {"ping-field", required_argument, 0, 'p'},
154 {"game-field", required_argument, 0, 'g'}, 156 {"game-field", required_argument, 0, 'g'},
155 {"players-field", required_argument, 0, 129}, 157 {"players-field", required_argument, 0, players_field_index},
156 {"max-players-field", required_argument, 0, 130}, 158 {"max-players-field", required_argument, 0, max_players_field_index},
157 {0, 0, 0, 0}}; 159 {0, 0, 0, 0}};
158 160
159 if (argc < 2) 161 check_game_config_wrapper result = {
160 return ERROR; 162 .config = check_game_config_init(),
163 .errorcode = OK,
164 };
165
166 if (argc < 2) {
167 result.errorcode = ERROR;
168 return result;
169 }
161 170
162 for (c = 1; c < argc; c++) { 171 for (int option_counter = 1; option_counter < argc; option_counter++) {
163 if (strcmp("-mf", argv[c]) == 0) 172 if (strcmp("-mf", argv[option_counter]) == 0) {
164 strcpy(argv[c], "-m"); 173 strcpy(argv[option_counter], "-m");
165 else if (strcmp("-pf", argv[c]) == 0) 174 } else if (strcmp("-pf", argv[option_counter]) == 0) {
166 strcpy(argv[c], "-p"); 175 strcpy(argv[option_counter], "-p");
167 else if (strcmp("-gf", argv[c]) == 0) 176 } else if (strcmp("-gf", argv[option_counter]) == 0) {
168 strcpy(argv[c], "-g"); 177 strcpy(argv[option_counter], "-g");
178 }
169 } 179 }
170 180
171 while (1) { 181 int opt_index = 0;
172 c = getopt_long(argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index); 182 while (true) {
183 int option_index = getopt_long(argc, argv, "hVvt:H:P:G:g:p:m:", long_opts, &opt_index);
173 184
174 if (c == -1 || c == EOF) 185 if (option_index == -1 || option_index == EOF) {
175 break; 186 break;
187 }
176 188
177 switch (c) { 189 switch (option_index) {
178 case 'h': /* help */ 190 case 'h': /* help */
179 print_help(); 191 print_help();
180 exit(STATE_UNKNOWN); 192 exit(STATE_UNKNOWN);
@@ -188,79 +200,75 @@ int process_arguments(int argc, char **argv) {
188 timeout_interval = atoi(optarg); 200 timeout_interval = atoi(optarg);
189 break; 201 break;
190 case 'H': /* hostname */ 202 case 'H': /* hostname */
191 if (strlen(optarg) >= MAX_HOST_ADDRESS_LENGTH) 203 if (strlen(optarg) >= MAX_HOST_ADDRESS_LENGTH) {
192 die(STATE_UNKNOWN, _("Input buffer overflow\n")); 204 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
193 server_ip = optarg; 205 }
206 result.config.server_ip = optarg;
194 break; 207 break;
195 case 'P': /* port */ 208 case 'P': /* port */
196 port = atoi(optarg); 209 result.config.port = atoi(optarg);
197 break; 210 break;
198 case 'G': /* hostname */ 211 case 'G': /* hostname */
199 if (strlen(optarg) >= MAX_INPUT_BUFFER) 212 if (strlen(optarg) >= MAX_INPUT_BUFFER) {
200 die(STATE_UNKNOWN, _("Input buffer overflow\n")); 213 die(STATE_UNKNOWN, _("Input buffer overflow\n"));
201 game_type = optarg; 214 }
215 result.config.game_type = optarg;
202 break; 216 break;
203 case 'p': /* index of ping field */ 217 case 'p': /* index of ping field */
204 qstat_ping_field = atoi(optarg); 218 result.config.qstat_ping_field = atoi(optarg);
205 if (qstat_ping_field < 0 || qstat_ping_field > QSTAT_MAX_RETURN_ARGS) 219 if (result.config.qstat_ping_field < 0 || result.config.qstat_ping_field > QSTAT_MAX_RETURN_ARGS) {
206 return ERROR; 220 result.errorcode = ERROR;
221 return result;
222 }
207 break; 223 break;
208 case 'm': /* index on map field */ 224 case 'm': /* index on map field */
209 qstat_map_field = atoi(optarg); 225 result.config.qstat_map_field = atoi(optarg);
210 if (qstat_map_field < 0 || qstat_map_field > QSTAT_MAX_RETURN_ARGS) 226 if (result.config.qstat_map_field < 0 || result.config.qstat_map_field > QSTAT_MAX_RETURN_ARGS) {
211 return ERROR; 227 result.errorcode = ERROR;
228 return result;
229 }
212 break; 230 break;
213 case 'g': /* index of game field */ 231 case 'g': /* index of game field */
214 qstat_game_field = atoi(optarg); 232 result.config.qstat_game_field = atoi(optarg);
215 if (qstat_game_field < 0 || qstat_game_field > QSTAT_MAX_RETURN_ARGS) 233 if (result.config.qstat_game_field < 0 || result.config.qstat_game_field > QSTAT_MAX_RETURN_ARGS) {
216 return ERROR; 234 result.errorcode = ERROR;
235 return result;
236 }
217 break; 237 break;
218 case 129: /* index of player count field */ 238 case players_field_index: /* index of player count field */
219 qstat_game_players = atoi(optarg); 239 result.config.qstat_game_players = atoi(optarg);
220 if (qstat_game_players_max == 0) 240 if (result.config.qstat_game_players_max == 0) {
221 qstat_game_players_max = qstat_game_players - 1; 241 result.config.qstat_game_players_max = result.config.qstat_game_players - 1;
222 if (qstat_game_players < 0 || qstat_game_players > QSTAT_MAX_RETURN_ARGS) 242 }
223 return ERROR; 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 }
224 break; 247 break;
225 case 130: /* index of max players field */ 248 case max_players_field_index: /* index of max players field */
226 qstat_game_players_max = atoi(optarg); 249 result.config.qstat_game_players_max = atoi(optarg);
227 if (qstat_game_players_max < 0 || qstat_game_players_max > QSTAT_MAX_RETURN_ARGS) 250 if (result.config.qstat_game_players_max < 0 || result.config.qstat_game_players_max > QSTAT_MAX_RETURN_ARGS) {
228 return ERROR; 251 result.errorcode = ERROR;
252 return result;
253 }
229 break; 254 break;
230 default: /* args not parsable */ 255 default: /* args not parsable */
231 usage5(); 256 usage5();
232 } 257 }
233 } 258 }
234 259
235 c = optind; 260 int option_counter = optind;
236 /* first option is the game type */ 261 /* first option is the game type */
237 if (!game_type && c < argc) 262 if (!result.config.game_type && option_counter < argc) {
238 game_type = strdup(argv[c++]); 263 result.config.game_type = strdup(argv[option_counter++]);
264 }
239 265
240 /* Second option is the server name */ 266 /* Second option is the server name */
241 if (!server_ip && c < argc) 267 if (!result.config.server_ip && option_counter < argc) {
242 server_ip = strdup(argv[c++]); 268 result.config.server_ip = strdup(argv[option_counter++]);
243 269 }
244 return validate_arguments();
245}
246
247int validate_arguments(void) {
248 if (qstat_game_players_max < 0)
249 qstat_game_players_max = 4;
250
251 if (qstat_game_players < 0)
252 qstat_game_players = 5;
253
254 if (qstat_game_field < 0)
255 qstat_game_field = 2;
256
257 if (qstat_map_field < 0)
258 qstat_map_field = 3;
259
260 if (qstat_ping_field < 0)
261 qstat_ping_field = 5;
262 270
263 return OK; 271 return result;
264} 272}
265 273
266void print_help(void) { 274void print_help(void) {
@@ -277,14 +285,15 @@ void print_help(void) {
277 285
278 printf(UT_HELP_VRSN); 286 printf(UT_HELP_VRSN);
279 printf(UT_EXTRA_OPTS); 287 printf(UT_EXTRA_OPTS);
280 288 printf(" -H, --hostname=ADDRESS\n"
281 printf(" %s\n", "-p"); 289 " Host name, IP Address, or unix socket (must be an absolute path)\n");
282 printf(" %s\n", _("Optional port of which to connect")); 290 printf(" %s\n", "-P");
283 printf(" %s\n", "gf"); 291 printf(" %s\n", _("Optional port to connect to"));
292 printf(" %s\n", "-g");
284 printf(" %s\n", _("Field number in raw qstat output that contains game name")); 293 printf(" %s\n", _("Field number in raw qstat output that contains game name"));
285 printf(" %s\n", "-mf"); 294 printf(" %s\n", "-m");
286 printf(" %s\n", _("Field number in raw qstat output that contains map name")); 295 printf(" %s\n", _("Field number in raw qstat output that contains map name"));
287 printf(" %s\n", "-pf"); 296 printf(" %s\n", "-p");
288 printf(" %s\n", _("Field number in raw qstat output that contains ping time")); 297 printf(" %s\n", _("Field number in raw qstat output that contains ping time"));
289 298
290 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 299 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
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 b39bccff..62417fd6 100644
--- a/plugins/check_hpjd.c
+++ b/plugins/check_hpjd.c
@@ -37,9 +37,10 @@ const char *email = "devel@monitoring-plugins.org";
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 44
44#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"
45#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"
@@ -57,39 +58,15 @@ const char *email = "devel@monitoring-plugins.org";
57#define ONLINE 0 58#define ONLINE 0
58#define OFFLINE 1 59#define OFFLINE 1
59 60
60static int process_arguments(int /*argc*/, char ** /*argv*/); 61typedef struct {
61static int validate_arguments(void); 62 int errorcode;
63 check_hpjd_config config;
64} check_hpjd_config_wrapper;
65static check_hpjd_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
62static void print_help(void); 66static void print_help(void);
63void print_usage(void); 67void print_usage(void);
64 68
65static char *community = NULL;
66static char *address = NULL;
67static unsigned int port = 0;
68static int check_paper_out = 1;
69
70int main(int argc, char **argv) { 69int main(int argc, char **argv) {
71 char command_line[1024];
72 int result = STATE_UNKNOWN;
73 int line;
74 char input_buffer[MAX_INPUT_BUFFER];
75 char query_string[512];
76 char *errmsg;
77 char *temp_buffer;
78 int line_status = ONLINE;
79 int paper_status = 0;
80 int intervention_required = 0;
81 int peripheral_error = 0;
82 int paper_jam = 0;
83 int paper_out = 0;
84 int toner_low = 0;
85 int page_punt = 0;
86 int memory_out = 0;
87 int door_open = 0;
88 int paper_output = 0;
89 char display_message[MAX_INPUT_BUFFER];
90
91 errmsg = malloc(MAX_INPUT_BUFFER);
92
93 setlocale(LC_ALL, ""); 70 setlocale(LC_ALL, "");
94 bindtextdomain(PACKAGE, LOCALEDIR); 71 bindtextdomain(PACKAGE, LOCALEDIR);
95 textdomain(PACKAGE); 72 textdomain(PACKAGE);
@@ -97,9 +74,15 @@ int main(int argc, char **argv) {
97 /* Parse extra opts if any */ 74 /* Parse extra opts if any */
98 argv = np_extra_opts(&argc, argv, progname); 75 argv = np_extra_opts(&argc, argv, progname);
99 76
100 if (process_arguments(argc, argv) == ERROR) 77 check_hpjd_config_wrapper tmp_config = process_arguments(argc, argv);
78
79 if (tmp_config.errorcode == ERROR) {
101 usage4(_("Could not parse arguments")); 80 usage4(_("Could not parse arguments"));
81 }
82
83 const check_hpjd_config config = tmp_config.config;
102 84
85 char query_string[512];
103 /* removed ' 2>1' at end of command 10/27/1999 - EG */ 86 /* removed ' 2>1' at end of command 10/27/1999 - EG */
104 /* create the query string */ 87 /* create the query string */
105 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, 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,
@@ -107,7 +90,8 @@ int main(int argc, char **argv) {
107 HPJD_GD_PAGE_PUNT, HPJD_GD_MEMORY_OUT, HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY); 90 HPJD_GD_PAGE_PUNT, HPJD_GD_MEMORY_OUT, HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
108 91
109 /* get the command to run */ 92 /* get the command to run */
110 sprintf(command_line, "%s -OQa -m : -v 1 -c %s %s:%u %s", PATH_TO_SNMPGET, community, address, port, query_string); 93 char command_line[1024];
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);
111 95
112 /* run the command */ 96 /* run the command */
113 child_process = spopen(command_line); 97 child_process = spopen(command_line);
@@ -121,29 +105,41 @@ int main(int argc, char **argv) {
121 printf(_("Could not open stderr for %s\n"), command_line); 105 printf(_("Could not open stderr for %s\n"), command_line);
122 } 106 }
123 107
124 result = STATE_OK; 108 mp_state_enum result = STATE_OK;
125 109
126 line = 0; 110 int line_status = ONLINE;
127 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];
128 122
123 char input_buffer[MAX_INPUT_BUFFER];
124 char *errmsg = malloc(MAX_INPUT_BUFFER);
125 int line = 0;
126
127 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
129 /* strip the newline character from the end of the input */ 128 /* strip the newline character from the end of the input */
130 if (input_buffer[strlen(input_buffer) - 1] == '\n') 129 if (input_buffer[strlen(input_buffer) - 1] == '\n') {
131 input_buffer[strlen(input_buffer) - 1] = 0; 130 input_buffer[strlen(input_buffer) - 1] = 0;
131 }
132 132
133 line++; 133 line++;
134 134
135 temp_buffer = strtok(input_buffer, "="); 135 char *temp_buffer = strtok(input_buffer, "=");
136 temp_buffer = strtok(NULL, "="); 136 temp_buffer = strtok(NULL, "=");
137 137
138 if (temp_buffer == NULL && line < 13) { 138 if (temp_buffer == NULL && line < 13) {
139
140 result = STATE_UNKNOWN; 139 result = STATE_UNKNOWN;
141 strcpy(errmsg, input_buffer); 140 strcpy(errmsg, input_buffer);
142
143 } else { 141 } else {
144
145 switch (line) { 142 switch (line) {
146
147 case 1: /* 1st line should contain the line status */ 143 case 1: /* 1st line should contain the line status */
148 line_status = atoi(temp_buffer); 144 line_status = atoi(temp_buffer);
149 break; 145 break;
@@ -186,16 +182,18 @@ int main(int argc, char **argv) {
186 } 182 }
187 183
188 /* break out of the read loop if we encounter an error */ 184 /* break out of the read loop if we encounter an error */
189 if (result != STATE_OK) 185 if (result != STATE_OK) {
190 break; 186 break;
187 }
191 } 188 }
192 189
193 /* WARNING if output found on stderr */ 190 /* WARNING if output found on stderr */
194 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { 191 if (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
195 result = max_state(result, STATE_WARNING); 192 result = max_state(result, STATE_WARNING);
196 /* remove CRLF */ 193 /* remove CRLF */
197 if (input_buffer[strlen(input_buffer) - 1] == '\n') 194 if (input_buffer[strlen(input_buffer) - 1] == '\n') {
198 input_buffer[strlen(input_buffer) - 1] = 0; 195 input_buffer[strlen(input_buffer) - 1] = 0;
196 }
199 sprintf(errmsg, "%s", input_buffer); 197 sprintf(errmsg, "%s", input_buffer);
200 } 198 }
201 199
@@ -203,15 +201,15 @@ int main(int argc, char **argv) {
203 (void)fclose(child_stderr); 201 (void)fclose(child_stderr);
204 202
205 /* close the pipe */ 203 /* close the pipe */
206 if (spclose(child_process)) 204 if (spclose(child_process)) {
207 result = max_state(result, STATE_WARNING); 205 result = max_state(result, STATE_WARNING);
206 }
208 207
209 /* if there wasn't any output, display an error */ 208 /* if there wasn't any output, display an error */
210 if (line == 0) { 209 if (line == 0) {
211
212 /* might not be the problem, but most likely is. */ 210 /* might not be the problem, but most likely is. */
213 result = STATE_UNKNOWN; 211 result = STATE_UNKNOWN;
214 xasprintf(&errmsg, "%s : Timeout from host %s\n", errmsg, address); 212 xasprintf(&errmsg, "%s : Timeout from host %s\n", errmsg, config.address);
215 } 213 }
216 214
217 /* if we had no read errors, check the printer status results... */ 215 /* if we had no read errors, check the printer status results... */
@@ -221,8 +219,9 @@ int main(int argc, char **argv) {
221 result = STATE_WARNING; 219 result = STATE_WARNING;
222 strcpy(errmsg, _("Paper Jam")); 220 strcpy(errmsg, _("Paper Jam"));
223 } else if (paper_out) { 221 } else if (paper_out) {
224 if (check_paper_out) 222 if (config.check_paper_out) {
225 result = STATE_WARNING; 223 result = STATE_WARNING;
224 }
226 strcpy(errmsg, _("Out of Paper")); 225 strcpy(errmsg, _("Out of Paper"));
227 } else if (line_status == OFFLINE) { 226 } else if (line_status == OFFLINE) {
228 if (strcmp(errmsg, "POWERSAVE ON") != 0) { 227 if (strcmp(errmsg, "POWERSAVE ON") != 0) {
@@ -256,29 +255,23 @@ int main(int argc, char **argv) {
256 } 255 }
257 } 256 }
258 257
259 if (result == STATE_OK) 258 if (result == STATE_OK) {
260 printf(_("Printer ok - (%s)\n"), display_message); 259 printf(_("Printer ok - (%s)\n"), display_message);
261 260 } else if (result == STATE_UNKNOWN) {
262 else if (result == STATE_UNKNOWN) {
263
264 printf("%s\n", errmsg); 261 printf("%s\n", errmsg);
265
266 /* if printer could not be reached, escalate to critical */ 262 /* if printer could not be reached, escalate to critical */
267 if (strstr(errmsg, "Timeout")) 263 if (strstr(errmsg, "Timeout")) {
268 result = STATE_CRITICAL; 264 result = STATE_CRITICAL;
269 } 265 }
270 266 } else if (result == STATE_WARNING) {
271 else if (result == STATE_WARNING)
272 printf("%s (%s)\n", errmsg, display_message); 267 printf("%s (%s)\n", errmsg, display_message);
268 }
273 269
274 return result; 270 exit(result);
275} 271}
276 272
277/* process command-line arguments */ 273/* process command-line arguments */
278int process_arguments(int argc, char **argv) { 274check_hpjd_config_wrapper process_arguments(int argc, char **argv) {
279 int c;
280
281 int option = 0;
282 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 275 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
283 {"community", required_argument, 0, 'C'}, 276 {"community", required_argument, 0, 'C'},
284 /* {"critical", required_argument,0,'c'}, */ 277 /* {"critical", required_argument,0,'c'}, */
@@ -288,34 +281,44 @@ int process_arguments(int argc, char **argv) {
288 {"help", no_argument, 0, 'h'}, 281 {"help", no_argument, 0, 'h'},
289 {0, 0, 0, 0}}; 282 {0, 0, 0, 0}};
290 283
291 if (argc < 2) 284 check_hpjd_config_wrapper result = {
292 return ERROR; 285 .errorcode = OK,
286 .config = check_hpjd_config_init(),
287 };
288
289 if (argc < 2) {
290 result.errorcode = ERROR;
291 return result;
292 }
293 293
294 while (1) { 294 int option = 0;
295 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);
296 297
297 if (c == -1 || c == EOF || c == 1) 298 if (option_index == -1 || option_index == EOF || option_index == 1) {
298 break; 299 break;
300 }
299 301
300 switch (c) { 302 switch (option_index) {
301 case 'H': /* hostname */ 303 case 'H': /* hostname */
302 if (is_host(optarg)) { 304 if (is_host(optarg)) {
303 address = strscpy(address, optarg); 305 result.config.address = strscpy(result.config.address, optarg);
304 } else { 306 } else {
305 usage2(_("Invalid hostname/address"), optarg); 307 usage2(_("Invalid hostname/address"), optarg);
306 } 308 }
307 break; 309 break;
308 case 'C': /* community */ 310 case 'C': /* community */
309 community = strscpy(community, optarg); 311 result.config.community = strscpy(result.config.community, optarg);
310 break; 312 break;
311 case 'p': 313 case 'p':
312 if (!is_intpos(optarg)) 314 if (!is_intpos(optarg)) {
313 usage2(_("Port must be a positive short integer"), optarg); 315 usage2(_("Port must be a positive short integer"), optarg);
314 else 316 } else {
315 port = atoi(optarg); 317 result.config.port = atoi(optarg);
318 }
316 break; 319 break;
317 case 'D': /* disable paper out check*/ 320 case 'D': /* disable paper out check*/
318 check_paper_out = 0; 321 result.config.check_paper_out = false;
319 break; 322 break;
320 case 'V': /* version */ 323 case 'V': /* version */
321 print_revision(progname, NP_VERSION); 324 print_revision(progname, NP_VERSION);
@@ -328,31 +331,26 @@ int process_arguments(int argc, char **argv) {
328 } 331 }
329 } 332 }
330 333
331 c = optind; 334 int c = optind;
332 if (address == NULL) { 335 if (result.config.address == NULL) {
333 if (is_host(argv[c])) { 336 if (is_host(argv[c])) {
334 address = argv[c++]; 337 result.config.address = argv[c++];
335 } else { 338 } else {
336 usage2(_("Invalid hostname/address"), argv[c]); 339 usage2(_("Invalid hostname/address"), argv[c]);
337 } 340 }
338 } 341 }
339 342
340 if (community == NULL) { 343 if (result.config.community == NULL) {
341 if (argv[c] != NULL) 344 if (argv[c] != NULL) {
342 community = argv[c]; 345 result.config.community = argv[c];
343 else 346 } else {
344 community = strdup(DEFAULT_COMMUNITY); 347 result.config.community = strdup(DEFAULT_COMMUNITY);
345 } 348 }
346
347 if (port == 0) {
348 port = atoi(DEFAULT_PORT);
349 } 349 }
350 350
351 return validate_arguments(); 351 return result;
352} 352}
353 353
354int validate_arguments(void) { return OK; }
355
356void print_help(void) { 354void print_help(void) {
357 print_revision(progname, NP_VERSION); 355 print_revision(progname, NP_VERSION);
358 356
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_ldap.c b/plugins/check_ldap.c
index 87818da6..597644bd 100644
--- a/plugins/check_ldap.c
+++ b/plugins/check_ldap.c
@@ -1,30 +1,30 @@
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-2024 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";
@@ -34,209 +34,178 @@ const char *email = "devel@monitoring-plugins.org";
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
50static int process_arguments (int, char **); 48typedef struct {
51static int validate_arguments (void); 49 int errorcode;
52static void 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*/);
55static char ld_defattr[] = "(objectclass=*)"; 53static check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper /*config_wrapper*/);
56static char *ld_attr = ld_defattr;
57static char *ld_host = NULL;
58static char *ld_base = NULL;
59static char *ld_passwd = NULL;
60static char *ld_binddn = NULL;
61static int ld_port = -1;
62#ifdef HAVE_LDAP_SET_OPTION
63static int ld_protocol = DEFAULT_PROTOCOL;
64#endif
65#ifndef LDAP_OPT_SUCCESS
66# define LDAP_OPT_SUCCESS LDAP_SUCCESS
67#endif
68static double warn_time = UNDEFINED;
69static double crit_time = UNDEFINED;
70static thresholds *entries_thresholds = NULL;
71static struct timeval tv;
72static char* warn_entries = NULL;
73static char* crit_entries = NULL;
74static bool starttls = false;
75static bool ssl_on_connect = false;
76static bool verbose = false;
77
78/* for ldap tls */
79
80static char *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_mrtg.c b/plugins/check_mrtg.c
index 632e66fb..5bd276dc 100644
--- a/plugins/check_mrtg.c
+++ b/plugins/check_mrtg.c
@@ -35,21 +35,18 @@ const 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"
39
40typedef struct {
41 int errorcode;
42 check_mrtg_config config;
43} check_mrtg_config_wrapper;
44static check_mrtg_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
45static check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper /*config_wrapper*/);
38 46
39static int process_arguments(int /*argc*/, char ** /*argv*/);
40static int validate_arguments(void);
41static void print_help(void); 47static void print_help(void);
42void print_usage(void); 48void print_usage(void);
43 49
44static char *log_file = NULL;
45static int expire_minutes = 0;
46static bool use_average = true;
47static int variable_number = -1;
48static unsigned long value_warning_threshold = 0L;
49static unsigned long value_critical_threshold = 0L;
50static char *label;
51static char *units;
52
53int main(int argc, char **argv) { 50int main(int argc, char **argv) {
54 setlocale(LC_ALL, ""); 51 setlocale(LC_ALL, "");
55 bindtextdomain(PACKAGE, LOCALEDIR); 52 bindtextdomain(PACKAGE, LOCALEDIR);
@@ -58,32 +55,37 @@ int main(int argc, char **argv) {
58 /* Parse extra opts if any */ 55 /* Parse extra opts if any */
59 argv = np_extra_opts(&argc, argv, progname); 56 argv = np_extra_opts(&argc, argv, progname);
60 57
61 if (process_arguments(argc, argv) == ERROR) 58 check_mrtg_config_wrapper tmp_config = process_arguments(argc, argv);
59 if (tmp_config.errorcode == ERROR) {
62 usage4(_("Could not parse arguments\n")); 60 usage4(_("Could not parse arguments\n"));
61 }
62
63 const check_mrtg_config config = tmp_config.config;
63 64
64 /* open the MRTG log file for reading */ 65 /* open the MRTG log file for reading */
65 FILE *mtrg_log_file = fopen(log_file, "r"); 66 FILE *mtrg_log_file = fopen(config.log_file, "r");
66 if (mtrg_log_file == NULL) { 67 if (mtrg_log_file == NULL) {
67 printf(_("Unable to open MRTG log file\n")); 68 printf(_("Unable to open MRTG log file\n"));
68 return STATE_UNKNOWN; 69 return STATE_UNKNOWN;
69 } 70 }
70 71
71 time_t timestamp = 0L; 72 time_t timestamp = 0;
72 unsigned long average_value_rate = 0L; 73 unsigned long average_value_rate = 0;
73 unsigned long maximum_value_rate = 0L; 74 unsigned long maximum_value_rate = 0;
74 char input_buffer[MAX_INPUT_BUFFER]; 75 char input_buffer[MAX_INPUT_BUFFER];
75 int line = 0; 76 int line = 0;
76 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mtrg_log_file)) { 77 while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mtrg_log_file)) {
77
78 line++; 78 line++;
79 79
80 /* skip the first line of the log file */ 80 /* skip the first line of the log file */
81 if (line == 1) 81 if (line == 1) {
82 continue; 82 continue;
83 }
83 84
84 /* 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 */
85 if (line > 2) 86 if (line > 2) {
86 break; 87 break;
88 }
87 89
88 /* grab the timestamp */ 90 /* grab the timestamp */
89 char *temp_buffer = strtok(input_buffer, " "); 91 char *temp_buffer = strtok(input_buffer, " ");
@@ -91,23 +93,27 @@ int main(int argc, char **argv) {
91 93
92 /* grab the average value 1 rate */ 94 /* grab the average value 1 rate */
93 temp_buffer = strtok(NULL, " "); 95 temp_buffer = strtok(NULL, " ");
94 if (variable_number == 1) 96 if (config.variable_number == 1) {
95 average_value_rate = strtoul(temp_buffer, NULL, 10); 97 average_value_rate = strtoul(temp_buffer, NULL, 10);
98 }
96 99
97 /* grab the average value 2 rate */ 100 /* grab the average value 2 rate */
98 temp_buffer = strtok(NULL, " "); 101 temp_buffer = strtok(NULL, " ");
99 if (variable_number == 2) 102 if (config.variable_number == 2) {
100 average_value_rate = strtoul(temp_buffer, NULL, 10); 103 average_value_rate = strtoul(temp_buffer, NULL, 10);
104 }
101 105
102 /* grab the maximum value 1 rate */ 106 /* grab the maximum value 1 rate */
103 temp_buffer = strtok(NULL, " "); 107 temp_buffer = strtok(NULL, " ");
104 if (variable_number == 1) 108 if (config.variable_number == 1) {
105 maximum_value_rate = strtoul(temp_buffer, NULL, 10); 109 maximum_value_rate = strtoul(temp_buffer, NULL, 10);
110 }
106 111
107 /* grab the maximum value 2 rate */ 112 /* grab the maximum value 2 rate */
108 temp_buffer = strtok(NULL, " "); 113 temp_buffer = strtok(NULL, " ");
109 if (variable_number == 2) 114 if (config.variable_number == 2) {
110 maximum_value_rate = strtoul(temp_buffer, NULL, 10); 115 maximum_value_rate = strtoul(temp_buffer, NULL, 10);
116 }
111 } 117 }
112 118
113 /* close the log file */ 119 /* close the log file */
@@ -122,49 +128,59 @@ int main(int argc, char **argv) {
122 /* make sure the MRTG data isn't too old */ 128 /* make sure the MRTG data isn't too old */
123 time_t current_time; 129 time_t current_time;
124 time(&current_time); 130 time(&current_time);
125 if (expire_minutes > 0 && (current_time - timestamp) > (expire_minutes * 60)) { 131 if (config.expire_minutes > 0 && (current_time - timestamp) > (config.expire_minutes * 60)) {
126 printf(_("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60)); 132 printf(_("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60));
127 return STATE_WARNING; 133 return STATE_WARNING;
128 } 134 }
129 135
130 unsigned long rate = 0L; 136 unsigned long rate = 0L;
131 /* else check the incoming/outgoing rates */ 137 /* else check the incoming/outgoing rates */
132 if (use_average) 138 if (config.use_average) {
133 rate = average_value_rate; 139 rate = average_value_rate;
134 else 140 } else {
135 rate = maximum_value_rate; 141 rate = maximum_value_rate;
142 }
136 143
137 int result = STATE_OK; 144 int result = STATE_OK;
138 if (rate > value_critical_threshold) 145 if (config.value_critical_threshold_set && rate > config.value_critical_threshold) {
139 result = STATE_CRITICAL; 146 result = STATE_CRITICAL;
140 else if (rate > value_warning_threshold) 147 } else if (config.value_warning_threshold_set && rate > config.value_warning_threshold) {
141 result = STATE_WARNING; 148 result = STATE_WARNING;
149 }
142 150
143 printf("%s. %s = %lu %s|%s\n", (use_average) ? _("Avg") : _("Max"), label, rate, units, 151 printf("%s. %s = %lu %s|%s\n", (config.use_average) ? _("Avg") : _("Max"), config.label, rate, config.units,
144 perfdata(label, (long)rate, units, (int)value_warning_threshold, (long)value_warning_threshold, (int)value_critical_threshold, 152 perfdata(config.label, (long)rate, config.units, config.value_warning_threshold_set, (long)config.value_warning_threshold,
145 (long)value_critical_threshold, 0, 0, 0, 0)); 153 config.value_critical_threshold_set, (long)config.value_critical_threshold, 0, 0, 0, 0));
146 154
147 return result; 155 return result;
148} 156}
149 157
150/* process command-line arguments */ 158/* process command-line arguments */
151int process_arguments(int argc, char **argv) { 159check_mrtg_config_wrapper process_arguments(int argc, char **argv) {
152 static struct option longopts[] = { 160 static struct option longopts[] = {
153 {"logfile", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'}, {"aggregation", required_argument, 0, 'a'}, 161 {"logfile", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'}, {"aggregation", required_argument, 0, 'a'},
154 {"variable", required_argument, 0, 'v'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, 162 {"variable", required_argument, 0, 'v'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'},
155 {"label", required_argument, 0, 'l'}, {"units", required_argument, 0, 'u'}, {"variable", required_argument, 0, 'v'}, 163 {"label", required_argument, 0, 'l'}, {"units", required_argument, 0, 'u'}, {"variable", required_argument, 0, 'v'},
156 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; 164 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
157 165
158 if (argc < 2) 166 check_mrtg_config_wrapper result = {
159 return ERROR; 167 .errorcode = OK,
168 .config = check_mrtg_config_init(),
169 };
170
171 if (argc < 2) {
172 result.errorcode = ERROR;
173 return result;
174 }
160 175
161 for (int i = 1; i < argc; i++) { 176 for (int i = 1; i < argc; i++) {
162 if (strcmp("-to", argv[i]) == 0) 177 if (strcmp("-to", argv[i]) == 0) {
163 strcpy(argv[i], "-t"); 178 strcpy(argv[i], "-t");
164 else if (strcmp("-wt", argv[i]) == 0) 179 } else if (strcmp("-wt", argv[i]) == 0) {
165 strcpy(argv[i], "-w"); 180 strcpy(argv[i], "-w");
166 else if (strcmp("-ct", argv[i]) == 0) 181 } else if (strcmp("-ct", argv[i]) == 0) {
167 strcpy(argv[i], "-c"); 182 strcpy(argv[i], "-c");
183 }
168 } 184 }
169 185
170 int option_char; 186 int option_char;
@@ -172,38 +188,39 @@ int process_arguments(int argc, char **argv) {
172 while (1) { 188 while (1) {
173 option_char = getopt_long(argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, &option); 189 option_char = getopt_long(argc, argv, "hVF:e:a:v:c:w:l:u:", longopts, &option);
174 190
175 if (option_char == -1 || option_char == EOF) 191 if (option_char == -1 || option_char == EOF) {
176 break; 192 break;
193 }
177 194
178 switch (option_char) { 195 switch (option_char) {
179 case 'F': /* input file */ 196 case 'F': /* input file */
180 log_file = optarg; 197 result.config.log_file = optarg;
181 break; 198 break;
182 case 'e': /* ups name */ 199 case 'e': /* ups name */
183 expire_minutes = atoi(optarg); 200 result.config.expire_minutes = atoi(optarg);
184 break; 201 break;
185 case 'a': /* port */ 202 case 'a': /* port */
186 if (!strcmp(optarg, "MAX")) 203 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
187 use_average = false;
188 else
189 use_average = true;
190 break; 204 break;
191 case 'v': 205 case 'v':
192 variable_number = atoi(optarg); 206 result.config.variable_number = atoi(optarg);
193 if (variable_number < 1 || variable_number > 2) 207 if (result.config.variable_number < 1 || result.config.variable_number > 2) {
194 usage4(_("Invalid variable number")); 208 usage4(_("Invalid variable number"));
209 }
195 break; 210 break;
196 case 'w': /* critical time threshold */ 211 case 'w': /* critical time threshold */
197 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);
198 break; 214 break;
199 case 'c': /* warning time threshold */ 215 case 'c': /* warning time threshold */
200 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);
201 break; 218 break;
202 case 'l': /* label */ 219 case 'l': /* label */
203 label = optarg; 220 result.config.label = optarg;
204 break; 221 break;
205 case 'u': /* timeout */ 222 case 'u': /* timeout */
206 units = optarg; 223 result.config.units = optarg;
207 break; 224 break;
208 case 'V': /* version */ 225 case 'V': /* version */
209 print_revision(progname, NP_VERSION); 226 print_revision(progname, NP_VERSION);
@@ -217,63 +234,69 @@ int process_arguments(int argc, char **argv) {
217 } 234 }
218 235
219 option_char = optind; 236 option_char = optind;
220 if (log_file == NULL && argc > option_char) { 237 if (result.config.log_file == NULL && argc > option_char) {
221 log_file = argv[option_char++]; 238 result.config.log_file = argv[option_char++];
222 } 239 }
223 240
224 if (expire_minutes <= 0 && argc > option_char) { 241 if (result.config.expire_minutes <= 0 && argc > option_char) {
225 if (is_intpos(argv[option_char])) 242 if (is_intpos(argv[option_char])) {
226 expire_minutes = atoi(argv[option_char++]); 243 result.config.expire_minutes = atoi(argv[option_char++]);
227 else 244 } else {
228 die(STATE_UNKNOWN, _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), argv[option_char], progname); 245 die(STATE_UNKNOWN, _("%s is not a valid expiration time\nUse '%s -h' for additional help\n"), argv[option_char], progname);
246 }
229 } 247 }
230 248
231 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) { 249 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
232 use_average = false; 250 result.config.use_average = false;
233 option_char++; 251 option_char++;
234 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) { 252 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
235 use_average = true; 253 result.config.use_average = true;
236 option_char++; 254 option_char++;
237 } 255 }
238 256
239 if (argc > option_char && variable_number == -1) { 257 if (argc > option_char && result.config.variable_number == -1) {
240 variable_number = atoi(argv[option_char++]); 258 result.config.variable_number = atoi(argv[option_char++]);
241 if (variable_number < 1 || variable_number > 2) { 259 if (result.config.variable_number < 1 || result.config.variable_number > 2) {
242 printf("%s :", argv[option_char]); 260 printf("%s :", argv[option_char]);
243 usage(_("Invalid variable number\n")); 261 usage(_("Invalid variable number\n"));
244 } 262 }
245 } 263 }
246 264
247 if (argc > option_char && value_warning_threshold == 0) { 265 if (argc > option_char && !result.config.value_warning_threshold_set) {
248 value_warning_threshold = strtoul(argv[option_char++], NULL, 10); 266 result.config.value_warning_threshold_set = true;
267 result.config.value_warning_threshold = strtoul(argv[option_char++], NULL, 10);
249 } 268 }
250 269
251 if (argc > option_char && value_critical_threshold == 0) { 270 if (argc > option_char && !result.config.value_critical_threshold_set) {
252 value_critical_threshold = strtoul(argv[option_char++], NULL, 10); 271 result.config.value_critical_threshold_set = true;
272 result.config.value_critical_threshold = strtoul(argv[option_char++], NULL, 10);
253 } 273 }
254 274
255 if (argc > option_char && strlen(label) == 0) { 275 if (argc > option_char && strlen(result.config.label) == 0) {
256 label = argv[option_char++]; 276 result.config.label = argv[option_char++];
257 } 277 }
258 278
259 if (argc > option_char && strlen(units) == 0) { 279 if (argc > option_char && strlen(result.config.units) == 0) {
260 units = argv[option_char++]; 280 result.config.units = argv[option_char++];
261 } 281 }
262 282
263 return validate_arguments(); 283 return validate_arguments(result);
264} 284}
265 285
266int validate_arguments(void) { 286check_mrtg_config_wrapper validate_arguments(check_mrtg_config_wrapper config_wrapper) {
267 if (variable_number == -1) 287 if (config_wrapper.config.variable_number == -1) {
268 usage4(_("You must supply the variable number")); 288 usage4(_("You must supply the variable number"));
289 }
269 290
270 if (label == NULL) 291 if (config_wrapper.config.label == NULL) {
271 label = strdup("value"); 292 config_wrapper.config.label = strdup("value");
293 }
272 294
273 if (units == NULL) 295 if (config_wrapper.config.units == NULL) {
274 units = strdup(""); 296 config_wrapper.config.units = strdup("");
297 }
275 298
276 return OK; 299 return config_wrapper;
277} 300}
278 301
279void print_help(void) { 302void print_help(void) {
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 e5a2e2ad..8c7cf8aa 100644
--- a/plugins/check_mrtgtraf.c
+++ b/plugins/check_mrtgtraf.c
@@ -29,25 +29,23 @@
29 * 29 *
30 *****************************************************************************/ 30 *****************************************************************************/
31 31
32#include "common.h"
33#include "utils.h"
34
35const char *progname = "check_mrtgtraf"; 32const char *progname = "check_mrtgtraf";
36const char *copyright = "1999-2024"; 33const char *copyright = "1999-2024";
37const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
38 35
39static int process_arguments(int /*argc*/, char ** /*argv*/); 36#include "check_mrtgtraf.d/config.h"
37#include "common.h"
38#include "utils.h"
39
40typedef struct {
41 int errorcode;
42 check_mrtgtraf_config config;
43} check_mrtgtraf_config_wrapper;
44
45static check_mrtgtraf_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
40static void print_help(void); 46static void print_help(void);
41void print_usage(void); 47void print_usage(void);
42 48
43static char *log_file = NULL;
44static int expire_minutes = -1;
45static bool use_average = true;
46static unsigned long incoming_warning_threshold = 0L;
47static unsigned long incoming_critical_threshold = 0L;
48static unsigned long outgoing_warning_threshold = 0L;
49static unsigned long outgoing_critical_threshold = 0L;
50
51int main(int argc, char **argv) { 49int main(int argc, char **argv) {
52 setlocale(LC_ALL, ""); 50 setlocale(LC_ALL, "");
53 bindtextdomain(PACKAGE, LOCALEDIR); 51 bindtextdomain(PACKAGE, LOCALEDIR);
@@ -56,13 +54,18 @@ int main(int argc, char **argv) {
56 /* Parse extra opts if any */ 54 /* Parse extra opts if any */
57 argv = np_extra_opts(&argc, argv, progname); 55 argv = np_extra_opts(&argc, argv, progname);
58 56
59 if (process_arguments(argc, argv) == ERROR) 57 check_mrtgtraf_config_wrapper tmp_config = process_arguments(argc, argv);
58 if (tmp_config.errorcode == ERROR) {
60 usage4(_("Could not parse arguments")); 59 usage4(_("Could not parse arguments"));
60 }
61
62 const check_mrtgtraf_config config = tmp_config.config;
61 63
62 /* open the MRTG log file for reading */ 64 /* open the MRTG log file for reading */
63 FILE *mrtg_log_file_ptr = fopen(log_file, "r"); 65 FILE *mrtg_log_file_ptr = fopen(config.log_file, "r");
64 if (mrtg_log_file_ptr == NULL) 66 if (mrtg_log_file_ptr == NULL) {
65 usage4(_("Unable to open MRTG log file")); 67 usage4(_("Unable to open MRTG log file"));
68 }
66 69
67 time_t timestamp = 0L; 70 time_t timestamp = 0L;
68 char input_buffer[MAX_INPUT_BUFFER]; 71 char input_buffer[MAX_INPUT_BUFFER];
@@ -76,13 +79,15 @@ int main(int argc, char **argv) {
76 line++; 79 line++;
77 80
78 /* skip the first line of the log file */ 81 /* skip the first line of the log file */
79 if (line == 1) 82 if (line == 1) {
80 continue; 83 continue;
84 }
81 85
82 /* break out of read loop */ 86 /* break out of read loop */
83 /* 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 */
84 if (line > 2) 88 if (line > 2) {
85 break; 89 break;
90 }
86 91
87 /* grab the timestamp */ 92 /* grab the timestamp */
88 char *temp_buffer = strtok(input_buffer, " "); 93 char *temp_buffer = strtok(input_buffer, " ");
@@ -109,19 +114,21 @@ int main(int argc, char **argv) {
109 fclose(mrtg_log_file_ptr); 114 fclose(mrtg_log_file_ptr);
110 115
111 /* if we couldn't read enough data, return an unknown error */ 116 /* if we couldn't read enough data, return an unknown error */
112 if (line <= 2) 117 if (line <= 2) {
113 usage4(_("Unable to process MRTG log file")); 118 usage4(_("Unable to process MRTG log file"));
119 }
114 120
115 /* make sure the MRTG data isn't too old */ 121 /* make sure the MRTG data isn't too old */
116 time_t current_time; 122 time_t current_time;
117 time(&current_time); 123 time(&current_time);
118 if ((expire_minutes > 0) && (current_time - timestamp) > (expire_minutes * 60)) 124 if ((config.expire_minutes > 0) && (current_time - timestamp) > (config.expire_minutes * 60)) {
119 die(STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60)); 125 die(STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), (int)((current_time - timestamp) / 60));
126 }
120 127
121 unsigned long incoming_rate = 0L; 128 unsigned long incoming_rate = 0L;
122 unsigned long outgoing_rate = 0L; 129 unsigned long outgoing_rate = 0L;
123 /* else check the incoming/outgoing rates */ 130 /* else check the incoming/outgoing rates */
124 if (use_average) { 131 if (config.use_average) {
125 incoming_rate = average_incoming_rate; 132 incoming_rate = average_incoming_rate;
126 outgoing_rate = average_outgoing_rate; 133 outgoing_rate = average_outgoing_rate;
127 } else { 134 } else {
@@ -166,24 +173,26 @@ int main(int argc, char **argv) {
166 /* report outgoing traffic in MBytes/sec */ 173 /* report outgoing traffic in MBytes/sec */
167 else { 174 else {
168 strcpy(outgoing_speed_rating, "MB"); 175 strcpy(outgoing_speed_rating, "MB");
169 adjusted_outgoing_rate = (double)(outgoing_rate / 1024.0 / 1024.0); 176 adjusted_outgoing_rate = (outgoing_rate / 1024.0 / 1024.0);
170 } 177 }
171 178
172 int result = STATE_OK; 179 int result = STATE_OK;
173 if (incoming_rate > incoming_critical_threshold || outgoing_rate > outgoing_critical_threshold) { 180 if (incoming_rate > config.incoming_critical_threshold || outgoing_rate > config.outgoing_critical_threshold) {
174 result = STATE_CRITICAL; 181 result = STATE_CRITICAL;
175 } else if (incoming_rate > incoming_warning_threshold || outgoing_rate > outgoing_warning_threshold) { 182 } else if (incoming_rate > config.incoming_warning_threshold || outgoing_rate > config.outgoing_warning_threshold) {
176 result = STATE_WARNING; 183 result = STATE_WARNING;
177 } 184 }
178 185
179 char *error_message; 186 char *error_message;
180 xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), (use_average) ? _("Avg") : _("Max"), 187 xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), (config.use_average) ? _("Avg") : _("Max"),
181 adjusted_incoming_rate, incoming_speed_rating, (use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate, 188 adjusted_incoming_rate, incoming_speed_rating, (config.use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate,
182 outgoing_speed_rating, 189 outgoing_speed_rating,
183 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, (int)incoming_warning_threshold, incoming_warning_threshold, 190 fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, (int)config.incoming_warning_threshold,
184 (int)incoming_critical_threshold, incoming_critical_threshold, true, 0, false, 0), 191 config.incoming_warning_threshold, (int)config.incoming_critical_threshold, config.incoming_critical_threshold,
185 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, (int)outgoing_warning_threshold, outgoing_warning_threshold, 192 true, 0, false, 0),
186 (int)outgoing_critical_threshold, outgoing_critical_threshold, true, 0, false, 0)); 193 fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, (int)config.outgoing_warning_threshold,
194 config.outgoing_warning_threshold, (int)config.outgoing_critical_threshold, config.outgoing_critical_threshold,
195 true, 0, false, 0));
187 196
188 printf(_("Traffic %s - %s\n"), state_text(result), error_message); 197 printf(_("Traffic %s - %s\n"), state_text(result), error_message);
189 198
@@ -191,7 +200,7 @@ int main(int argc, char **argv) {
191} 200}
192 201
193/* process command-line arguments */ 202/* process command-line arguments */
194int process_arguments(int argc, char **argv) { 203check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) {
195 static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, 204 static struct option longopts[] = {{"filename", required_argument, 0, 'F'},
196 {"expires", required_argument, 0, 'e'}, 205 {"expires", required_argument, 0, 'e'},
197 {"aggregation", required_argument, 0, 'a'}, 206 {"aggregation", required_argument, 0, 'a'},
@@ -201,44 +210,49 @@ int process_arguments(int argc, char **argv) {
201 {"help", no_argument, 0, 'h'}, 210 {"help", no_argument, 0, 'h'},
202 {0, 0, 0, 0}}; 211 {0, 0, 0, 0}};
203 212
204 if (argc < 2) 213 check_mrtgtraf_config_wrapper result = {
205 return ERROR; 214 .errorcode = OK,
215 .config = check_mrtgtraf_config_init(),
216 };
217 if (argc < 2) {
218 result.errorcode = ERROR;
219 return result;
220 }
206 221
207 for (int i = 1; i < argc; i++) { 222 for (int i = 1; i < argc; i++) {
208 if (strcmp("-to", argv[i]) == 0) 223 if (strcmp("-to", argv[i]) == 0) {
209 strcpy(argv[i], "-t"); 224 strcpy(argv[i], "-t");
210 else if (strcmp("-wt", argv[i]) == 0) 225 } else if (strcmp("-wt", argv[i]) == 0) {
211 strcpy(argv[i], "-w"); 226 strcpy(argv[i], "-w");
212 else if (strcmp("-ct", argv[i]) == 0) 227 } else if (strcmp("-ct", argv[i]) == 0) {
213 strcpy(argv[i], "-c"); 228 strcpy(argv[i], "-c");
229 }
214 } 230 }
215 231
216 int option_char; 232 int option_char;
217 int option = 0; 233 int option = 0;
218 while (1) { 234 while (true) {
219 option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option); 235 option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option);
220 236
221 if (option_char == -1 || option_char == EOF) 237 if (option_char == -1 || option_char == EOF) {
222 break; 238 break;
239 }
223 240
224 switch (option_char) { 241 switch (option_char) {
225 case 'F': /* input file */ 242 case 'F': /* input file */
226 log_file = optarg; 243 result.config.log_file = optarg;
227 break; 244 break;
228 case 'e': /* expiration time */ 245 case 'e': /* expiration time */
229 expire_minutes = atoi(optarg); 246 result.config.expire_minutes = atoi(optarg);
230 break; 247 break;
231 case 'a': /* aggregation (AVE or MAX) */ 248 case 'a': /* aggregation (AVE or MAX) */
232 if (!strcmp(optarg, "MAX")) 249 result.config.use_average = (bool)(strcmp(optarg, "MAX"));
233 use_average = false;
234 else
235 use_average = true;
236 break; 250 break;
237 case 'c': /* warning threshold */ 251 case 'c': /* warning threshold */
238 sscanf(optarg, "%lu,%lu", &incoming_critical_threshold, &outgoing_critical_threshold); 252 sscanf(optarg, "%lu,%lu", &result.config.incoming_critical_threshold, &result.config.outgoing_critical_threshold);
239 break; 253 break;
240 case 'w': /* critical threshold */ 254 case 'w': /* critical threshold */
241 sscanf(optarg, "%lu,%lu", &incoming_warning_threshold, &outgoing_warning_threshold); 255 sscanf(optarg, "%lu,%lu", &result.config.incoming_warning_threshold, &result.config.outgoing_warning_threshold);
242 break; 256 break;
243 case 'V': /* version */ 257 case 'V': /* version */
244 print_revision(progname, NP_VERSION); 258 print_revision(progname, NP_VERSION);
@@ -252,39 +266,39 @@ int process_arguments(int argc, char **argv) {
252 } 266 }
253 267
254 option_char = optind; 268 option_char = optind;
255 if (argc > option_char && log_file == NULL) { 269 if (argc > option_char && result.config.log_file == NULL) {
256 log_file = argv[option_char++]; 270 result.config.log_file = argv[option_char++];
257 } 271 }
258 272
259 if (argc > option_char && expire_minutes == -1) { 273 if (argc > option_char && result.config.expire_minutes == -1) {
260 expire_minutes = atoi(argv[option_char++]); 274 result.config.expire_minutes = atoi(argv[option_char++]);
261 } 275 }
262 276
263 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) { 277 if (argc > option_char && strcmp(argv[option_char], "MAX") == 0) {
264 use_average = false; 278 result.config.use_average = false;
265 option_char++; 279 option_char++;
266 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) { 280 } else if (argc > option_char && strcmp(argv[option_char], "AVG") == 0) {
267 use_average = true; 281 result.config.use_average = true;
268 option_char++; 282 option_char++;
269 } 283 }
270 284
271 if (argc > option_char && incoming_warning_threshold == 0) { 285 if (argc > option_char && result.config.incoming_warning_threshold == 0) {
272 incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10); 286 result.config.incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10);
273 } 287 }
274 288
275 if (argc > option_char && incoming_critical_threshold == 0) { 289 if (argc > option_char && result.config.incoming_critical_threshold == 0) {
276 incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10); 290 result.config.incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10);
277 } 291 }
278 292
279 if (argc > option_char && outgoing_warning_threshold == 0) { 293 if (argc > option_char && result.config.outgoing_warning_threshold == 0) {
280 outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10); 294 result.config.outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10);
281 } 295 }
282 296
283 if (argc > option_char && outgoing_critical_threshold == 0) { 297 if (argc > option_char && result.config.outgoing_critical_threshold == 0) {
284 outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10); 298 result.config.outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10);
285 } 299 }
286 300
287 return OK; 301 return result;
288} 302}
289 303
290void print_help(void) { 304void print_help(void) {
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 8a73772d..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-2024 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-2024"; 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
48static char *db_user = NULL;
49static char *db_host = NULL;
50static char *db_socket = NULL;
51static char *db_pass = NULL;
52static char *db = NULL;
53static char *ca_cert = NULL;
54static char *ca_dir = NULL;
55static char *cert = NULL;
56static char *key = NULL;
57static char *ciphers = NULL;
58static bool ssl = false;
59static char *opt_file = NULL;
60static char *opt_group = NULL;
61static unsigned int db_port = MYSQL_PORT;
62static bool check_slave = false;
63static bool ignore_auth = false;
64static int verbose = 0; 49static int verbose = 0;
65 50
66static double warning_time = 0;
67static double critical_time = 0;
68
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);
94static thresholds *my_threshold = NULL; 70void print_usage(void);
95 71
96static int process_arguments (int, char **); 72int main(int argc, char **argv) {
97static int validate_arguments (void); 73 setlocale(LC_ALL, "");
98static void print_help (void); 74 bindtextdomain(PACKAGE, LOCALEDIR);
99void print_usage (void); 75 textdomain(PACKAGE);
100
101int
102main (int argc, char **argv)
103{
104
105 MYSQL mysql;
106 MYSQL_RES *res;
107 MYSQL_ROW row;
108 76
109 /* should be status */ 77 /* Parse extra opts if any */
78 argv = np_extra_opts(&argc, argv, progname);
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 79b6e2f4..5e04a94b 100644
--- a/plugins/check_mysql_query.c
+++ b/plugins/check_mysql_query.c
@@ -37,27 +37,21 @@ const char *email = "devel@monitoring-plugins.org";
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
44static char *db_user = NULL; 45typedef struct {
45static char *db_host = NULL; 46 int errorcode;
46static char *db_socket = NULL; 47 check_mysql_query_config config;
47static char *db_pass = NULL; 48} check_mysql_query_config_wrapper;
48static char *db = NULL; 49static check_mysql_query_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
49static char *opt_file = NULL; 50static check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper /*config_wrapper*/);
50static char *opt_group = NULL;
51static unsigned int db_port = MYSQL_PORT;
52
53static int process_arguments(int /*argc*/, char ** /*argv*/);
54static int validate_arguments(void);
55static void print_help(void); 51static void print_help(void);
56void print_usage(void); 52void print_usage(void);
57 53
58static char *sql_query = NULL;
59static int verbose = 0; 54static int verbose = 0;
60static thresholds *my_thresholds = NULL;
61 55
62int main(int argc, char **argv) { 56int main(int argc, char **argv) {
63 setlocale(LC_ALL, ""); 57 setlocale(LC_ALL, "");
@@ -67,39 +61,46 @@ int main(int argc, char **argv) {
67 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
68 argv = np_extra_opts(&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
69 63
70 if (process_arguments(argc, argv) == ERROR) 64 check_mysql_query_config_wrapper tmp_config = process_arguments(argc, argv);
65 if (tmp_config.errorcode == ERROR) {
71 usage4(_("Could not parse arguments")); 66 usage4(_("Could not parse arguments"));
67 }
68
69 const check_mysql_query_config config = tmp_config.config;
72 70
73 MYSQL mysql; 71 MYSQL mysql;
74 /* initialize mysql */ 72 /* initialize mysql */
75 mysql_init(&mysql); 73 mysql_init(&mysql);
76 74
77 if (opt_file != NULL) 75 if (config.opt_file != NULL) {
78 mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, opt_file); 76 mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, config.opt_file);
77 }
79 78
80 if (opt_group != NULL) 79 if (config.opt_group != NULL) {
81 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, opt_group); 80 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, config.opt_group);
82 else 81 } else {
83 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client"); 82 mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "client");
83 }
84 84
85 /* establish a connection to the server and error checking */ 85 /* establish a connection to the server and error checking */
86 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)) {
87 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) 87 if (mysql_errno(&mysql) == CR_UNKNOWN_HOST) {
88 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 88 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
89 else if (mysql_errno(&mysql) == CR_VERSION_ERROR) 89 } else if (mysql_errno(&mysql) == CR_VERSION_ERROR) {
90 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 90 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
91 else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) 91 } else if (mysql_errno(&mysql) == CR_OUT_OF_MEMORY) {
92 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 92 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
93 else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) 93 } else if (mysql_errno(&mysql) == CR_IPSOCK_ERROR) {
94 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 94 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
95 else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) 95 } else if (mysql_errno(&mysql) == CR_SOCKET_CREATE_ERROR) {
96 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql)); 96 die(STATE_WARNING, "QUERY %s: %s\n", _("WARNING"), mysql_error(&mysql));
97 else 97 } else {
98 die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql)); 98 die(STATE_CRITICAL, "QUERY %s: %s\n", _("CRITICAL"), mysql_error(&mysql));
99 }
99 } 100 }
100 101
101 char *error = NULL; 102 char *error = NULL;
102 if (mysql_query(&mysql, sql_query) != 0) { 103 if (mysql_query(&mysql, config.sql_query) != 0) {
103 error = strdup(mysql_error(&mysql)); 104 error = strdup(mysql_error(&mysql));
104 mysql_close(&mysql); 105 mysql_close(&mysql);
105 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);
@@ -140,10 +141,11 @@ int main(int argc, char **argv) {
140 /* close the connection */ 141 /* close the connection */
141 mysql_close(&mysql); 142 mysql_close(&mysql);
142 143
143 if (verbose >= 3) 144 if (verbose >= 3) {
144 printf("mysql result: %f\n", value); 145 printf("mysql result: %f\n", value);
146 }
145 147
146 int status = get_status(value, my_thresholds); 148 int status = get_status(value, config.my_thresholds);
147 149
148 if (status == STATE_OK) { 150 if (status == STATE_OK) {
149 printf("QUERY %s: ", _("OK")); 151 printf("QUERY %s: ", _("OK"));
@@ -152,17 +154,16 @@ int main(int argc, char **argv) {
152 } else if (status == STATE_CRITICAL) { 154 } else if (status == STATE_CRITICAL) {
153 printf("QUERY %s: ", _("CRITICAL")); 155 printf("QUERY %s: ", _("CRITICAL"));
154 } 156 }
155 printf(_("'%s' returned %f | %s"), sql_query, value, 157 printf(_("'%s' returned %f | %s"), config.sql_query, value,
156 fperfdata("result", value, "", my_thresholds->warning ? true : false, my_thresholds->warning ? my_thresholds->warning->end : 0, 158 fperfdata("result", value, "", config.my_thresholds->warning, config.my_thresholds->warning ? config.my_thresholds->warning->end : 0,
157 my_thresholds->critical ? true : false, my_thresholds->critical ? my_thresholds->critical->end : 0, false, 0, false, 159 config.my_thresholds->critical, config.my_thresholds->critical ? config.my_thresholds->critical->end : 0, false, 0, false, 0));
158 0));
159 printf("\n"); 160 printf("\n");
160 161
161 return status; 162 return status;
162} 163}
163 164
164/* process command-line arguments */ 165/* process command-line arguments */
165int process_arguments(int argc, char **argv) { 166check_mysql_query_config_wrapper process_arguments(int argc, char **argv) {
166 static struct option longopts[] = { 167 static struct option longopts[] = {
167 {"hostname", required_argument, 0, 'H'}, {"socket", required_argument, 0, 's'}, {"database", required_argument, 0, 'd'}, 168 {"hostname", required_argument, 0, 'H'}, {"socket", required_argument, 0, 's'}, {"database", required_argument, 0, 'd'},
168 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'}, {"file", required_argument, 0, 'f'}, 169 {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'}, {"file", required_argument, 0, 'f'},
@@ -170,8 +171,15 @@ int process_arguments(int argc, char **argv) {
170 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"query", required_argument, 0, 'q'}, 171 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"query", required_argument, 0, 'q'},
171 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {0, 0, 0, 0}}; 172 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, {0, 0, 0, 0}};
172 173
173 if (argc < 1) 174 check_mysql_query_config_wrapper result = {
174 return ERROR; 175 .errorcode = OK,
176 .config = check_mysql_query_config_init(),
177 };
178
179 if (argc < 1) {
180 result.errorcode = ERROR;
181 return result;
182 }
175 183
176 char *warning = NULL; 184 char *warning = NULL;
177 char *critical = NULL; 185 char *critical = NULL;
@@ -180,28 +188,29 @@ int process_arguments(int argc, char **argv) {
180 int option = 0; 188 int option = 0;
181 int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option); 189 int option_char = getopt_long(argc, argv, "hvVP:p:u:d:H:s:q:w:c:f:g:", longopts, &option);
182 190
183 if (option_char == -1 || option_char == EOF) 191 if (option_char == -1 || option_char == EOF) {
184 break; 192 break;
193 }
185 194
186 switch (option_char) { 195 switch (option_char) {
187 case 'H': /* hostname */ 196 case 'H': /* hostname */
188 if (is_host(optarg)) { 197 if (is_host(optarg)) {
189 db_host = optarg; 198 result.config.db_host = optarg;
190 } else { 199 } else {
191 usage2(_("Invalid hostname/address"), optarg); 200 usage2(_("Invalid hostname/address"), optarg);
192 } 201 }
193 break; 202 break;
194 case 's': /* socket */ 203 case 's': /* socket */
195 db_socket = optarg; 204 result.config.db_socket = optarg;
196 break; 205 break;
197 case 'd': /* database */ 206 case 'd': /* database */
198 db = optarg; 207 result.config.db = optarg;
199 break; 208 break;
200 case 'u': /* username */ 209 case 'u': /* username */
201 db_user = optarg; 210 result.config.db_user = optarg;
202 break; 211 break;
203 case 'p': /* authentication information: password */ 212 case 'p': /* authentication information: password */
204 db_pass = strdup(optarg); 213 result.config.db_pass = strdup(optarg);
205 214
206 /* Delete the password from process list */ 215 /* Delete the password from process list */
207 while (*optarg != '\0') { 216 while (*optarg != '\0') {
@@ -210,13 +219,13 @@ int process_arguments(int argc, char **argv) {
210 } 219 }
211 break; 220 break;
212 case 'f': /* client options file */ 221 case 'f': /* client options file */
213 opt_file = optarg; 222 result.config.opt_file = optarg;
214 break; 223 break;
215 case 'g': /* client options group */ 224 case 'g': /* client options group */
216 opt_group = optarg; 225 result.config.opt_group = optarg;
217 break; 226 break;
218 case 'P': /* critical time threshold */ 227 case 'P': /* critical time threshold */
219 db_port = atoi(optarg); 228 result.config.db_port = atoi(optarg);
220 break; 229 break;
221 case 'v': 230 case 'v':
222 verbose++; 231 verbose++;
@@ -228,7 +237,7 @@ int process_arguments(int argc, char **argv) {
228 print_help(); 237 print_help();
229 exit(STATE_UNKNOWN); 238 exit(STATE_UNKNOWN);
230 case 'q': 239 case 'q':
231 xasprintf(&sql_query, "%s", optarg); 240 xasprintf(&result.config.sql_query, "%s", optarg);
232 break; 241 break;
233 case 'w': 242 case 'w':
234 warning = optarg; 243 warning = optarg;
@@ -241,25 +250,29 @@ int process_arguments(int argc, char **argv) {
241 } 250 }
242 } 251 }
243 252
244 set_thresholds(&my_thresholds, warning, critical); 253 set_thresholds(&result.config.my_thresholds, warning, critical);
245 254
246 return validate_arguments(); 255 return validate_arguments(result);
247} 256}
248 257
249int validate_arguments(void) { 258check_mysql_query_config_wrapper validate_arguments(check_mysql_query_config_wrapper config_wrapper) {
250 if (sql_query == NULL) 259 if (config_wrapper.config.sql_query == NULL) {
251 usage("Must specify a SQL query to run"); 260 usage("Must specify a SQL query to run");
261 }
252 262
253 if (db_user == NULL) 263 if (config_wrapper.config.db_user == NULL) {
254 db_user = strdup(""); 264 config_wrapper.config.db_user = strdup("");
265 }
255 266
256 if (db_host == NULL) 267 if (config_wrapper.config.db_host == NULL) {
257 db_host = strdup(""); 268 config_wrapper.config.db_host = strdup("");
269 }
258 270
259 if (db == NULL) 271 if (config_wrapper.config.db == NULL) {
260 db = strdup(""); 272 config_wrapper.config.db = strdup("");
273 }
261 274
262 return OK; 275 return config_wrapper;
263} 276}
264 277
265void print_help(void) { 278void print_help(void) {
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 48629be3..a46dc1ed 100644
--- a/plugins/check_nagios.c
+++ b/plugins/check_nagios.c
@@ -39,47 +39,20 @@ const char *email = "devel@monitoring-plugins.org";
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 42#include "states.h"
43static int process_arguments(int /*argc*/, char ** /*argv*/); 43#include "check_nagios.d/config.h"
44
45typedef struct {
46 int errorcode;
47 check_nagios_config config;
48} check_nagios_config_wrapper;
49static check_nagios_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
44static void print_help(void); 50static void print_help(void);
45void print_usage(void); 51void print_usage(void);
46 52
47static char *status_log = NULL;
48static char *process_string = NULL;
49static int expire_minutes = 0;
50
51static int verbose = 0; 53static int verbose = 0;
52 54
53int main(int argc, char **argv) { 55int main(int argc, char **argv) {
54 int result = STATE_UNKNOWN;
55 char input_buffer[MAX_INPUT_BUFFER];
56 unsigned long latest_entry_time = 0L;
57 unsigned long temp_entry_time = 0L;
58 int proc_entries = 0;
59 time_t current_time;
60 char *temp_ptr;
61 FILE *fp;
62 int procuid = 0;
63 int procpid = 0;
64 int procppid = 0;
65 int procvsz = 0;
66 int procrss = 0;
67 float procpcpu = 0;
68 char procstat[8];
69#ifdef PS_USES_PROCETIME
70 char procetime[MAX_INPUT_BUFFER];
71#endif /* PS_USES_PROCETIME */
72 char procprog[MAX_INPUT_BUFFER];
73 char *procargs;
74 int pos;
75 int cols;
76 int expected_cols = PS_COLS - 1;
77 const char *zombie = "Z";
78 char *temp_string;
79 output chld_out;
80 output chld_err;
81 size_t i;
82
83 setlocale(LC_ALL, ""); 56 setlocale(LC_ALL, "");
84 bindtextdomain(PACKAGE, LOCALEDIR); 57 bindtextdomain(PACKAGE, LOCALEDIR);
85 textdomain(PACKAGE); 58 textdomain(PACKAGE);
@@ -87,8 +60,13 @@ int main(int argc, char **argv) {
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);
89 62
90 if (process_arguments(argc, argv) == ERROR) 63 check_nagios_config_wrapper tmp_config = process_arguments(argc, argv);
64
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) {
@@ -99,13 +77,17 @@ int main(int argc, char **argv) {
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;
@@ -113,22 +95,44 @@ int main(int argc, char **argv) {
113 } 95 }
114 if ((temp_ptr = strtok(input_buffer, "]")) != NULL) { 96 if ((temp_ptr = strtok(input_buffer, "]")) != NULL) {
115 temp_entry_time = strtoul(temp_ptr + 1, NULL, 10); 97 temp_entry_time = strtoul(temp_ptr + 1, NULL, 10);
116 if (temp_entry_time > latest_entry_time) 98 if (temp_entry_time > latest_entry_time) {
117 latest_entry_time = temp_entry_time; 99 latest_entry_time = temp_entry_time;
100 }
118 } 101 }
119 } 102 }
120 fclose(fp); 103 fclose(log_file);
121 104
122 if (verbose >= 2) 105 if (verbose >= 2) {
123 printf("command: %s\n", PS_COMMAND); 106 printf("command: %s\n", PS_COMMAND);
107 }
124 108
125 /* run the command to check for the Nagios process.. */ 109 /* run the command to check for the Nagios process.. */
126 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) {
127 result = STATE_WARNING; 114 result = STATE_WARNING;
115 }
128 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";
129 /* count the number of matching Nagios processes... */ 133 /* count the number of matching Nagios processes... */
130 for (i = 0; i < chld_out.lines; i++) { 134 for (size_t i = 0; i < chld_out.lines; i++) {
131 cols = sscanf(chld_out.line[i], PS_FORMAT, PS_VARLIST); 135 int cols = sscanf(chld_out.line[i], PS_FORMAT, PS_VARLIST);
132 /* Zombie processes do not give a procprog command */ 136 /* Zombie processes do not give a procprog command */
133 if (cols == (expected_cols - 1) && strstr(procstat, zombie)) { 137 if (cols == (expected_cols - 1) && strstr(procstat, zombie)) {
134 cols = expected_cols; 138 cols = expected_cols;
@@ -142,14 +146,14 @@ int main(int argc, char **argv) {
142 strip(procargs); 146 strip(procargs);
143 147
144 /* Some ps return full pathname for command. This removes path */ 148 /* Some ps return full pathname for command. This removes path */
145 temp_string = strtok((char *)procprog, "/"); 149 char *temp_string = strtok((char *)procprog, "/");
146 while (temp_string) { 150 while (temp_string) {
147 strcpy(procprog, temp_string); 151 strcpy(procprog, temp_string);
148 temp_string = strtok(NULL, "/"); 152 temp_string = strtok(NULL, "/");
149 } 153 }
150 154
151 /* May get empty procargs */ 155 /* May get empty procargs */
152 if (!strstr(procargs, argv[0]) && strstr(procargs, process_string) && strcmp(procargs, "")) { 156 if (!strstr(procargs, argv[0]) && strstr(procargs, config.process_string) && strcmp(procargs, "")) {
153 proc_entries++; 157 proc_entries++;
154 if (verbose >= 2) { 158 if (verbose >= 2) {
155 printf(_("Found process: %s %s\n"), procprog, procargs); 159 printf(_("Found process: %s %s\n"), procprog, procargs);
@@ -159,8 +163,9 @@ int main(int argc, char **argv) {
159 } 163 }
160 164
161 /* If we get anything on stderr, at least set warning */ 165 /* If we get anything on stderr, at least set warning */
162 if (chld_err.buflen) 166 if (chld_err.buflen) {
163 result = max_state(result, STATE_WARNING); 167 result = max_state(result, STATE_WARNING);
168 }
164 169
165 /* reset the alarm handler */ 170 /* reset the alarm handler */
166 alarm(0); 171 alarm(0);
@@ -173,8 +178,9 @@ int main(int argc, char **argv) {
173 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"));
174 } 179 }
175 180
181 time_t current_time;
176 time(&current_time); 182 time(&current_time);
177 if ((int)(current_time - latest_entry_time) > (expire_minutes * 60)) { 183 if ((int)(current_time - latest_entry_time) > (config.expire_minutes * 60)) {
178 result = STATE_WARNING; 184 result = STATE_WARNING;
179 } else { 185 } else {
180 result = STATE_OK; 186 result = STATE_OK;
@@ -187,39 +193,45 @@ int main(int argc, char **argv) {
187 (int)(current_time - latest_entry_time)); 193 (int)(current_time - latest_entry_time));
188 printf("\n"); 194 printf("\n");
189 195
190 return result; 196 exit(result);
191} 197}
192 198
193/* process command-line arguments */ 199/* process command-line arguments */
194int process_arguments(int argc, char **argv) { 200check_nagios_config_wrapper process_arguments(int argc, char **argv) {
195 int c;
196
197 int option = 0;
198 static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'}, 201 static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, {"expires", required_argument, 0, 'e'},
199 {"command", required_argument, 0, 'C'}, {"timeout", optional_argument, 0, 't'}, 202 {"command", required_argument, 0, 'C'}, {"timeout", optional_argument, 0, 't'},
200 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, 203 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'},
201 {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0}}; 204 {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0}};
202 205
203 if (argc < 2) 206 check_nagios_config_wrapper result = {
204 return ERROR; 207 .errorcode = OK,
208 .config = check_nagios_config_init(),
209 };
210 if (argc < 2) {
211 result.errorcode = ERROR;
212 return result;
213 }
205 214
206 if (!is_option(argv[1])) { 215 if (!is_option(argv[1])) {
207 status_log = argv[1]; 216 result.config.status_log = argv[1];
208 if (is_intnonneg(argv[2])) 217 if (is_intnonneg(argv[2])) {
209 expire_minutes = atoi(argv[2]); 218 result.config.expire_minutes = atoi(argv[2]);
210 else 219 } else {
211 die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n")); 220 die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
212 process_string = argv[3]; 221 }
213 return OK; 222 result.config.process_string = argv[3];
223 return result;
214 } 224 }
215 225
216 while (1) { 226 int option = 0;
217 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);
218 229
219 if (c == -1 || c == EOF || c == 1) 230 if (option_index == -1 || option_index == EOF || option_index == 1) {
220 break; 231 break;
232 }
221 233
222 switch (c) { 234 switch (option_index) {
223 case 'h': /* help */ 235 case 'h': /* help */
224 print_help(); 236 print_help();
225 exit(STATE_UNKNOWN); 237 exit(STATE_UNKNOWN);
@@ -227,22 +239,24 @@ int process_arguments(int argc, char **argv) {
227 print_revision(progname, NP_VERSION); 239 print_revision(progname, NP_VERSION);
228 exit(STATE_UNKNOWN); 240 exit(STATE_UNKNOWN);
229 case 'F': /* status log */ 241 case 'F': /* status log */
230 status_log = optarg; 242 result.config.status_log = optarg;
231 break; 243 break;
232 case 'C': /* command */ 244 case 'C': /* command */
233 process_string = optarg; 245 result.config.process_string = optarg;
234 break; 246 break;
235 case 'e': /* expiry time */ 247 case 'e': /* expiry time */
236 if (is_intnonneg(optarg)) 248 if (is_intnonneg(optarg)) {
237 expire_minutes = atoi(optarg); 249 result.config.expire_minutes = atoi(optarg);
238 else 250 } else {
239 die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n")); 251 die(STATE_UNKNOWN, _("Expiration time must be an integer (seconds)\n"));
252 }
240 break; 253 break;
241 case 't': /* timeout */ 254 case 't': /* timeout */
242 if (is_intnonneg(optarg)) 255 if (is_intnonneg(optarg)) {
243 timeout_interval = atoi(optarg); 256 timeout_interval = atoi(optarg);
244 else 257 } else {
245 die(STATE_UNKNOWN, _("Timeout must be an integer (seconds)\n")); 258 die(STATE_UNKNOWN, _("Timeout must be an integer (seconds)\n"));
259 }
246 break; 260 break;
247 case 'v': 261 case 'v':
248 verbose++; 262 verbose++;
@@ -252,13 +266,15 @@ int process_arguments(int argc, char **argv) {
252 } 266 }
253 } 267 }
254 268
255 if (status_log == NULL) 269 if (result.config.status_log == NULL) {
256 die(STATE_UNKNOWN, _("You must provide the status_log\n")); 270 die(STATE_UNKNOWN, _("You must provide the status_log\n"));
271 }
257 272
258 if (process_string == NULL) 273 if (result.config.process_string == NULL) {
259 die(STATE_UNKNOWN, _("You must provide a process string\n")); 274 die(STATE_UNKNOWN, _("You must provide a process string\n"));
275 }
260 276
261 return OK; 277 return result;
262} 278}
263 279
264void print_help(void) { 280void print_help(void) {
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 dec0b668..7dd23e5c 100644
--- a/plugins/check_nt.c
+++ b/plugins/check_nt.c
@@ -13,7 +13,7 @@
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
@@ -39,82 +39,28 @@ const char *email = "devel@monitoring-plugins.org";
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
62static char *server_address = NULL;
63static int server_port = PORT;
64static char *value_list = NULL;
65static char *req_password = NULL;
66static unsigned long lvalue_list[MAX_VALUE_LIST];
67static unsigned long warning_value = 0L;
68static unsigned long critical_value = 0L;
69static bool check_warning_value = false;
70static bool check_critical_value = false;
71static enum checkvars vars_to_check = CHECK_NONE;
72static bool show_all = false;
73
74static char recv_buffer[MAX_INPUT_BUFFER]; 48static char recv_buffer[MAX_INPUT_BUFFER];
75 49
76static void fetch_data(const char *address, int port, const char *sendb); 50static void fetch_data(const char *address, int port, const char *sendb);
77static int process_arguments(int /*argc*/, char ** /*argv*/); 51
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*/);
57
78static void preparelist(char *string); 58static void preparelist(char *string);
79static bool strtoularray(unsigned long *array, char *string, const char *delim); 59static bool strtoularray(unsigned long *array, char *string, const char *delim);
80static void print_help(void); 60static void print_help(void);
81void print_usage(void); 61void print_usage(void);
82 62
83int main(int argc, char **argv) { 63int main(int argc, char **argv) {
84
85 /* should be int result = STATE_UNKNOWN; */
86
87 int return_code = STATE_UNKNOWN;
88 char *send_buffer = NULL;
89 char *output_message = NULL;
90 char *perfdata = NULL;
91 char *temp_string = NULL;
92 char *temp_string_perf = NULL;
93 char *description = NULL, *counter_unit = NULL;
94 char *minval = NULL, *maxval = NULL, *errcvt = NULL;
95 char *fds = NULL, *tds = NULL;
96 char *numstr;
97
98 double total_disk_space = 0;
99 double free_disk_space = 0;
100 double percent_used_space = 0;
101 double warning_used_space = 0;
102 double critical_used_space = 0;
103 double mem_commitLimit = 0;
104 double mem_commitByte = 0;
105 double fminval = 0, fmaxval = 0;
106 unsigned long utilization;
107 unsigned long uptime;
108 unsigned long age_in_minutes;
109 double counter_value = 0.0;
110 int offset = 0;
111 int updays = 0;
112 int uphours = 0;
113 int upminutes = 0;
114
115 bool isPercent = false;
116 bool allRight = false;
117
118 setlocale(LC_ALL, ""); 64 setlocale(LC_ALL, "");
119 bindtextdomain(PACKAGE, LOCALEDIR); 65 bindtextdomain(PACKAGE, LOCALEDIR);
120 textdomain(PACKAGE); 66 textdomain(PACKAGE);
@@ -122,8 +68,12 @@ int main(int argc, char **argv) {
122 /* Parse extra opts if any */ 68 /* Parse extra opts if any */
123 argv = np_extra_opts(&argc, argv, progname); 69 argv = np_extra_opts(&argc, argv, progname);
124 70
125 if (process_arguments(argc, argv) == ERROR) 71 check_nt_config_wrapper tmp_config = process_arguments(argc, argv);
72 if (tmp_config.errorcode == ERROR) {
126 usage4(_("Could not parse arguments")); 73 usage4(_("Could not parse arguments"));
74 }
75
76 const check_nt_config config = tmp_config.config;
127 77
128 /* initialize alarm signal handling */ 78 /* initialize alarm signal handling */
129 signal(SIGALRM, socket_timeout_alarm_handler); 79 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -131,49 +81,57 @@ int main(int argc, char **argv) {
131 /* set socket timeout */ 81 /* set socket timeout */
132 alarm(socket_timeout); 82 alarm(socket_timeout);
133 83
134 switch (vars_to_check) { 84 int return_code = STATE_UNKNOWN;
135 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) {
136 case CHECK_CLIENTVERSION: 95 case CHECK_CLIENTVERSION:
137 96 xasprintf(&send_buffer, "%s&1", config.req_password);
138 xasprintf(&send_buffer, "%s&1", req_password); 97 fetch_data(config.server_address, config.server_port, send_buffer);
139 fetch_data(server_address, server_port, send_buffer); 98 if (config.value_list != NULL && strcmp(recv_buffer, config.value_list) != 0) {
140 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);
141 xasprintf(&output_message, _("Wrong client version - running: %s, required: %s"), recv_buffer, value_list);
142 return_code = STATE_WARNING; 100 return_code = STATE_WARNING;
143 } else { 101 } else {
144 xasprintf(&output_message, "%s", recv_buffer); 102 xasprintf(&output_message, "%s", recv_buffer);
145 return_code = STATE_OK; 103 return_code = STATE_OK;
146 } 104 }
147 break; 105 break;
148
149 case CHECK_CPULOAD: 106 case CHECK_CPULOAD:
150 107 if (config.value_list == NULL) {
151 if (value_list == NULL)
152 output_message = strdup(_("missing -l parameters")); 108 output_message = strdup(_("missing -l parameters"));
153 else if (!strtoularray(lvalue_list, value_list, ",")) 109 } else if (!strtoularray(lvalue_list, config.value_list, ",")) {
154 output_message = strdup(_("wrong -l parameter.")); 110 output_message = strdup(_("wrong -l parameter."));
155 else { 111 } else {
156 /* -l parameters is present with only integers */ 112 /* -l parameters is present with only integers */
157 return_code = STATE_OK; 113 return_code = STATE_OK;
158 temp_string = strdup(_("CPU Load")); 114 temp_string = strdup(_("CPU Load"));
159 temp_string_perf = strdup(" "); 115 temp_string_perf = strdup(" ");
160 116
161 /* loop until one of the parameters is wrong or not present */ 117 /* loop until one of the parameters is wrong or not present */
118 int offset = 0;
162 while (lvalue_list[0 + offset] > (unsigned long)0 && lvalue_list[0 + offset] <= (unsigned long)17280 && 119 while (lvalue_list[0 + offset] > (unsigned long)0 && lvalue_list[0 + offset] <= (unsigned long)17280 &&
163 lvalue_list[1 + offset] > (unsigned long)0 && lvalue_list[1 + offset] <= (unsigned long)100 && 120 lvalue_list[1 + offset] > (unsigned long)0 && lvalue_list[1 + offset] <= (unsigned long)100 &&
164 lvalue_list[2 + offset] > (unsigned long)0 && lvalue_list[2 + offset] <= (unsigned long)100) { 121 lvalue_list[2 + offset] > (unsigned long)0 && lvalue_list[2 + offset] <= (unsigned long)100) {
165 122
166 /* Send request and retrieve data */ 123 /* Send request and retrieve data */
167 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]);
168 fetch_data(server_address, server_port, send_buffer); 125 fetch_data(config.server_address, config.server_port, send_buffer);
169 126
170 utilization = strtoul(recv_buffer, NULL, 10); 127 unsigned long utilization = strtoul(recv_buffer, NULL, 10);
171 128
172 /* 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 */
173 if (utilization >= lvalue_list[2 + offset]) 130 if (utilization >= lvalue_list[2 + offset]) {
174 return_code = STATE_CRITICAL; 131 return_code = STATE_CRITICAL;
175 else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) 132 } else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) {
176 return_code = STATE_WARNING; 133 return_code = STATE_WARNING;
134 }
177 135
178 xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization, lvalue_list[0 + offset]); 136 xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization, lvalue_list[0 + offset]);
179 xasprintf(&temp_string, "%s%s", temp_string, output_message); 137 xasprintf(&temp_string, "%s%s", temp_string, output_message);
@@ -186,82 +144,87 @@ int main(int argc, char **argv) {
186 if (strlen(temp_string) > 10) { /* we had at least one loop */ 144 if (strlen(temp_string) > 10) { /* we had at least one loop */
187 output_message = strdup(temp_string); 145 output_message = strdup(temp_string);
188 perfdata = temp_string_perf; 146 perfdata = temp_string_perf;
189 } else 147 } else {
190 output_message = strdup(_("not enough values for -l parameters")); 148 output_message = strdup(_("not enough values for -l parameters"));
149 }
191 } 150 }
192 break; 151 break;
193 152 case CHECK_UPTIME: {
194 case CHECK_UPTIME: 153 char *tmp_value_list = config.value_list;
195 154 if (config.value_list == NULL) {
196 if (value_list == NULL) { 155 tmp_value_list = "minutes";
197 value_list = "minutes";
198 } 156 }
199 if (strncmp(value_list, "seconds", strlen("seconds") + 1) && strncmp(value_list, "minutes", strlen("minutes") + 1) && 157 if (strncmp(tmp_value_list, "seconds", strlen("seconds") + 1) && strncmp(tmp_value_list, "minutes", strlen("minutes") + 1) &&
200 strncmp(value_list, "hours", strlen("hours") + 1) && strncmp(value_list, "days", strlen("days") + 1)) { 158 strncmp(config.value_list, "hours", strlen("hours") + 1) && strncmp(tmp_value_list, "days", strlen("days") + 1)) {
201 159
202 output_message = strdup(_("wrong -l argument")); 160 output_message = strdup(_("wrong -l argument"));
203 } else { 161 } else {
204 xasprintf(&send_buffer, "%s&3", req_password); 162 xasprintf(&send_buffer, "%s&3", config.req_password);
205 fetch_data(server_address, server_port, send_buffer); 163 fetch_data(config.server_address, config.server_port, send_buffer);
206 uptime = strtoul(recv_buffer, NULL, 10); 164 unsigned long uptime = strtoul(recv_buffer, NULL, 10);
207 updays = uptime / 86400; 165 int updays = uptime / 86400;
208 uphours = (uptime % 86400) / 3600; 166 int uphours = (uptime % 86400) / 3600;
209 upminutes = ((uptime % 86400) % 3600) / 60; 167 int upminutes = ((uptime % 86400) % 3600) / 60;
210 168
211 if (!strncmp(value_list, "minutes", strlen("minutes"))) 169 if (!strncmp(tmp_value_list, "minutes", strlen("minutes"))) {
212 uptime = uptime / 60; 170 uptime = uptime / 60;
213 else if (!strncmp(value_list, "hours", strlen("hours"))) 171 } else if (!strncmp(tmp_value_list, "hours", strlen("hours"))) {
214 uptime = uptime / 3600; 172 uptime = uptime / 3600;
215 else if (!strncmp(value_list, "days", strlen("days"))) 173 } else if (!strncmp(tmp_value_list, "days", strlen("days"))) {
216 uptime = uptime / 86400; 174 uptime = uptime / 86400;
175 }
217 /* else uptime in seconds, nothing to do */ 176 /* else uptime in seconds, nothing to do */
218 177
219 xasprintf(&output_message, _("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays, uphours, upminutes, 178 xasprintf(&output_message, _("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays, uphours, upminutes,
220 uptime); 179 uptime);
221 180
222 if (check_critical_value && uptime <= critical_value) 181 if (config.check_critical_value && uptime <= config.critical_value) {
223 return_code = STATE_CRITICAL; 182 return_code = STATE_CRITICAL;
224 else if (check_warning_value && uptime <= warning_value) 183 } else if (config.check_warning_value && uptime <= config.warning_value) {
225 return_code = STATE_WARNING; 184 return_code = STATE_WARNING;
226 else 185 } else {
227 return_code = STATE_OK; 186 return_code = STATE_OK;
187 }
228 } 188 }
229 break; 189 } break;
230
231 case CHECK_USEDDISKSPACE: 190 case CHECK_USEDDISKSPACE:
232 191 if (config.value_list == NULL) {
233 if (value_list == NULL)
234 output_message = strdup(_("missing -l parameters")); 192 output_message = strdup(_("missing -l parameters"));
235 else if (strlen(value_list) != 1) 193 } else if (strlen(config.value_list) != 1) {
236 output_message = strdup(_("wrong -l argument")); 194 output_message = strdup(_("wrong -l argument"));
237 else { 195 } else {
238 xasprintf(&send_buffer, "%s&4&%s", req_password, value_list); 196 xasprintf(&send_buffer, "%s&4&%s", config.req_password, config.value_list);
239 fetch_data(server_address, server_port, send_buffer); 197 fetch_data(config.server_address, config.server_port, send_buffer);
240 fds = strtok(recv_buffer, "&"); 198 char *fds = strtok(recv_buffer, "&");
241 tds = strtok(NULL, "&"); 199 char *tds = strtok(NULL, "&");
242 if (fds != NULL) 200 double total_disk_space = 0;
201 double free_disk_space = 0;
202 if (fds != NULL) {
243 free_disk_space = atof(fds); 203 free_disk_space = atof(fds);
244 if (tds != NULL) 204 }
205 if (tds != NULL) {
245 total_disk_space = atof(tds); 206 total_disk_space = atof(tds);
207 }
246 208
247 if (total_disk_space > 0 && free_disk_space >= 0) { 209 if (total_disk_space > 0 && free_disk_space >= 0) {
248 percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100; 210 double percent_used_space = ((total_disk_space - free_disk_space) / total_disk_space) * 100;
249 warning_used_space = ((float)warning_value / 100) * total_disk_space; 211 double warning_used_space = ((float)config.warning_value / 100) * total_disk_space;
250 critical_used_space = ((float)critical_value / 100) * total_disk_space; 212 double critical_used_space = ((float)config.critical_value / 100) * total_disk_space;
251 213
252 xasprintf(&temp_string, _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), value_list, 214 xasprintf(&temp_string, _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), config.value_list,
253 total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, percent_used_space, 215 total_disk_space / 1073741824, (total_disk_space - free_disk_space) / 1073741824, percent_used_space,
254 free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100); 216 free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100);
255 xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), value_list, 217 xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), config.value_list,
256 (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824, 218 (total_disk_space - free_disk_space) / 1073741824, warning_used_space / 1073741824,
257 critical_used_space / 1073741824, total_disk_space / 1073741824); 219 critical_used_space / 1073741824, total_disk_space / 1073741824);
258 220
259 if (check_critical_value && percent_used_space >= critical_value) 221 if (config.check_critical_value && percent_used_space >= config.critical_value) {
260 return_code = STATE_CRITICAL; 222 return_code = STATE_CRITICAL;
261 else if (check_warning_value && percent_used_space >= warning_value) 223 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
262 return_code = STATE_WARNING; 224 return_code = STATE_WARNING;
263 else 225 } else {
264 return_code = STATE_OK; 226 return_code = STATE_OK;
227 }
265 228
266 output_message = strdup(temp_string); 229 output_message = strdup(temp_string);
267 perfdata = temp_string_perf; 230 perfdata = temp_string_perf;
@@ -271,41 +234,40 @@ int main(int argc, char **argv) {
271 } 234 }
272 } 235 }
273 break; 236 break;
274
275 case CHECK_SERVICESTATE: 237 case CHECK_SERVICESTATE:
276 case CHECK_PROCSTATE: 238 case CHECK_PROCSTATE:
277 239 if (config.value_list == NULL) {
278 if (value_list == NULL)
279 output_message = strdup(_("No service/process specified")); 240 output_message = strdup(_("No service/process specified"));
280 else { 241 } else {
281 preparelist(value_list); /* replace , between services with & to send the request */ 242 preparelist(config.value_list); /* replace , between services with & to send the request */
282 xasprintf(&send_buffer, "%s&%u&%s&%s", req_password, (vars_to_check == CHECK_SERVICESTATE) ? 5 : 6, 243 xasprintf(&send_buffer, "%s&%u&%s&%s", config.req_password, (config.vars_to_check == CHECK_SERVICESTATE) ? 5 : 6,
283 (show_all) ? "ShowAll" : "ShowFail", value_list); 244 (config.show_all) ? "ShowAll" : "ShowFail", config.value_list);
284 fetch_data(server_address, server_port, send_buffer); 245 fetch_data(config.server_address, config.server_port, send_buffer);
285 numstr = strtok(recv_buffer, "&"); 246 char *numstr = strtok(recv_buffer, "&");
286 if (numstr == NULL) 247 if (numstr == NULL) {
287 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 248 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
249 }
288 return_code = atoi(numstr); 250 return_code = atoi(numstr);
289 temp_string = strtok(NULL, "&"); 251 temp_string = strtok(NULL, "&");
290 output_message = strdup(temp_string); 252 output_message = strdup(temp_string);
291 } 253 }
292 break; 254 break;
293
294 case CHECK_MEMUSE: 255 case CHECK_MEMUSE:
295 256 xasprintf(&send_buffer, "%s&7", config.req_password);
296 xasprintf(&send_buffer, "%s&7", req_password); 257 fetch_data(config.server_address, config.server_port, send_buffer);
297 fetch_data(server_address, server_port, send_buffer); 258 char *numstr = strtok(recv_buffer, "&");
298 numstr = strtok(recv_buffer, "&"); 259 if (numstr == NULL) {
299 if (numstr == NULL)
300 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 260 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
301 mem_commitLimit = atof(numstr); 261 }
262 double mem_commitLimit = atof(numstr);
302 numstr = strtok(NULL, "&"); 263 numstr = strtok(NULL, "&");
303 if (numstr == NULL) 264 if (numstr == NULL) {
304 die(STATE_UNKNOWN, _("could not fetch information from server\n")); 265 die(STATE_UNKNOWN, _("could not fetch information from server\n"));
305 mem_commitByte = atof(numstr); 266 }
306 percent_used_space = (mem_commitByte / mem_commitLimit) * 100; 267 double mem_commitByte = atof(numstr);
307 warning_used_space = ((float)warning_value / 100) * mem_commitLimit; 268 double percent_used_space = (mem_commitByte / mem_commitLimit) * 100;
308 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;
309 271
310 /* 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,
311 which equals RAM + Pagefiles. */ 273 which equals RAM + Pagefiles. */
@@ -316,15 +278,14 @@ int main(int argc, char **argv) {
316 critical_used_space / 1048567, mem_commitLimit / 1048567); 278 critical_used_space / 1048567, mem_commitLimit / 1048567);
317 279
318 return_code = STATE_OK; 280 return_code = STATE_OK;
319 if (check_critical_value && percent_used_space >= critical_value) 281 if (config.check_critical_value && percent_used_space >= config.critical_value) {
320 return_code = STATE_CRITICAL; 282 return_code = STATE_CRITICAL;
321 else if (check_warning_value && percent_used_space >= warning_value) 283 } else if (config.check_warning_value && percent_used_space >= config.warning_value) {
322 return_code = STATE_WARNING; 284 return_code = STATE_WARNING;
285 }
323 286
324 break; 287 break;
325 288 case CHECK_COUNTER: {
326 case CHECK_COUNTER:
327
328 /* 289 /*
329 CHECK_COUNTER has been modified to provide extensive perfdata information. 290 CHECK_COUNTER has been modified to provide extensive perfdata information.
330 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
@@ -346,26 +307,32 @@ int main(int argc, char **argv) {
346 strange things will happen when you make graphs of your data. 307 strange things will happen when you make graphs of your data.
347 */ 308 */
348 309
349 if (value_list == NULL) 310 double counter_value = 0.0;
311 if (config.value_list == NULL) {
350 output_message = strdup(_("No counter specified")); 312 output_message = strdup(_("No counter specified"));
351 else { 313 } else {
352 preparelist(value_list); /* replace , between services with & to send the request */ 314 preparelist(config.value_list); /* replace , between services with & to send the request */
353 isPercent = (strchr(value_list, '%') != NULL); 315 bool isPercent = (strchr(config.value_list, '%') != NULL);
354 316
355 strtok(value_list, "&"); /* burn the first parameters */ 317 strtok(config.value_list, "&"); /* burn the first parameters */
356 description = strtok(NULL, "&"); 318 description = strtok(NULL, "&");
357 counter_unit = strtok(NULL, "&"); 319 counter_unit = strtok(NULL, "&");
358 xasprintf(&send_buffer, "%s&8&%s", req_password, value_list); 320 xasprintf(&send_buffer, "%s&8&%s", config.req_password, config.value_list);
359 fetch_data(server_address, server_port, send_buffer); 321 fetch_data(config.server_address, config.server_port, send_buffer);
360 counter_value = atof(recv_buffer); 322 counter_value = atof(recv_buffer);
361 323
362 if (description == NULL) 324 bool allRight = false;
325 if (description == NULL) {
363 xasprintf(&output_message, "%.f", counter_value); 326 xasprintf(&output_message, "%.f", counter_value);
364 else if (isPercent) { 327 } else if (isPercent) {
365 counter_unit = strdup("%"); 328 counter_unit = strdup("%");
366 allRight = true; 329 allRight = true;
367 } 330 }
368 331
332 char *minval = NULL;
333 char *maxval = NULL;
334 double fminval = 0;
335 double fmaxval = 0;
369 if ((counter_unit != NULL) && (!allRight)) { 336 if ((counter_unit != NULL) && (!allRight)) {
370 minval = strtok(NULL, "&"); 337 minval = strtok(NULL, "&");
371 maxval = strtok(NULL, "&"); 338 maxval = strtok(NULL, "&");
@@ -375,16 +342,18 @@ int main(int argc, char **argv) {
375 fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1; 342 fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1;
376 fmaxval = (minval != NULL) ? strtod(maxval, &errcvt) : -1; 343 fmaxval = (minval != NULL) ? strtod(maxval, &errcvt) : -1;
377 344
378 if ((fminval == 0) && (minval == errcvt)) 345 if ((fminval == 0) && (minval == errcvt)) {
379 output_message = strdup(_("Minimum value contains non-numbers")); 346 output_message = strdup(_("Minimum value contains non-numbers"));
380 else { 347 } else {
381 if ((fmaxval == 0) && (maxval == errcvt)) 348 if ((fmaxval == 0) && (maxval == errcvt)) {
382 output_message = strdup(_("Maximum value contains non-numbers")); 349 output_message = strdup(_("Maximum value contains non-numbers"));
383 else 350 } else {
384 allRight = true; /* Everything is OK. */ 351 allRight = true; /* Everything is OK. */
352 }
385 } 353 }
386 } else if ((counter_unit == NULL) && (description != NULL)) 354 } else if ((counter_unit == NULL) && (description != NULL)) {
387 output_message = strdup(_("No unit counter specified")); 355 output_message = strdup(_("No unit counter specified"));
356 }
388 357
389 if (allRight) { 358 if (allRight) {
390 /* Let's format the output string, finally... */ 359 /* Let's format the output string, finally... */
@@ -396,63 +365,65 @@ int main(int argc, char **argv) {
396 } 365 }
397 xasprintf(&output_message, "%s |", output_message); 366 xasprintf(&output_message, "%s |", output_message);
398 xasprintf(&output_message, "%s %s", output_message, 367 xasprintf(&output_message, "%s %s", output_message,
399 fperfdata(description, counter_value, counter_unit, 1, warning_value, 1, critical_value, 368 fperfdata(description, counter_value, counter_unit, 1, config.warning_value, 1, config.critical_value,
400 (!(isPercent) && (minval != NULL)), fminval, (!(isPercent) && (minval != NULL)), fmaxval)); 369 (!(isPercent) && (minval != NULL)), fminval, (!(isPercent) && (minval != NULL)), fmaxval));
401 } 370 }
402 } 371 }
403 372
404 if (critical_value > warning_value) { /* Normal thresholds */ 373 if (config.critical_value > config.warning_value) { /* Normal thresholds */
405 if (check_critical_value && counter_value >= critical_value) 374 if (config.check_critical_value && counter_value >= config.critical_value) {
406 return_code = STATE_CRITICAL; 375 return_code = STATE_CRITICAL;
407 else if (check_warning_value && counter_value >= warning_value) 376 } else if (config.check_warning_value && counter_value >= config.warning_value) {
408 return_code = STATE_WARNING; 377 return_code = STATE_WARNING;
409 else 378 } else {
410 return_code = STATE_OK; 379 return_code = STATE_OK;
380 }
411 } else { /* inverse thresholds */ 381 } else { /* inverse thresholds */
412 return_code = STATE_OK; 382 return_code = STATE_OK;
413 if (check_critical_value && counter_value <= critical_value) 383 if (config.check_critical_value && counter_value <= config.critical_value) {
414 return_code = STATE_CRITICAL; 384 return_code = STATE_CRITICAL;
415 else if (check_warning_value && counter_value <= warning_value) 385 } else if (config.check_warning_value && counter_value <= config.warning_value) {
416 return_code = STATE_WARNING; 386 return_code = STATE_WARNING;
387 }
417 } 388 }
418 break; 389 } break;
419
420 case CHECK_FILEAGE: 390 case CHECK_FILEAGE:
421 391 if (config.value_list == NULL) {
422 if (value_list == NULL)
423 output_message = strdup(_("No counter specified")); 392 output_message = strdup(_("No counter specified"));
424 else { 393 } else {
425 preparelist(value_list); /* replace , between services with & to send the request */ 394 preparelist(config.value_list); /* replace , between services with & to send the request */
426 xasprintf(&send_buffer, "%s&9&%s", req_password, value_list); 395 xasprintf(&send_buffer, "%s&9&%s", config.req_password, config.value_list);
427 fetch_data(server_address, server_port, send_buffer); 396 fetch_data(config.server_address, config.server_port, send_buffer);
428 age_in_minutes = atoi(strtok(recv_buffer, "&")); 397 unsigned long age_in_minutes = atoi(strtok(recv_buffer, "&"));
429 description = strtok(NULL, "&"); 398 description = strtok(NULL, "&");
430 output_message = strdup(description); 399 output_message = strdup(description);
431 400
432 if (critical_value > warning_value) { /* Normal thresholds */ 401 if (config.critical_value > config.warning_value) { /* Normal thresholds */
433 if (check_critical_value && age_in_minutes >= critical_value) 402 if (config.check_critical_value && age_in_minutes >= config.critical_value) {
434 return_code = STATE_CRITICAL; 403 return_code = STATE_CRITICAL;
435 else if (check_warning_value && age_in_minutes >= warning_value) 404 } else if (config.check_warning_value && age_in_minutes >= config.warning_value) {
436 return_code = STATE_WARNING; 405 return_code = STATE_WARNING;
437 else 406 } else {
438 return_code = STATE_OK; 407 return_code = STATE_OK;
408 }
439 } else { /* inverse thresholds */ 409 } else { /* inverse thresholds */
440 if (check_critical_value && age_in_minutes <= critical_value) 410 if (config.check_critical_value && age_in_minutes <= config.critical_value) {
441 return_code = STATE_CRITICAL; 411 return_code = STATE_CRITICAL;
442 else if (check_warning_value && age_in_minutes <= warning_value) 412 } else if (config.check_warning_value && age_in_minutes <= config.warning_value) {
443 return_code = STATE_WARNING; 413 return_code = STATE_WARNING;
444 else 414 } else {
445 return_code = STATE_OK; 415 return_code = STATE_OK;
416 }
446 } 417 }
447 } 418 }
448 break; 419 break;
449 420
450 case CHECK_INSTANCES: 421 case CHECK_INSTANCES:
451 if (value_list == NULL) 422 if (config.value_list == NULL) {
452 output_message = strdup(_("No counter specified")); 423 output_message = strdup(_("No counter specified"));
453 else { 424 } else {
454 xasprintf(&send_buffer, "%s&10&%s", req_password, value_list); 425 xasprintf(&send_buffer, "%s&10&%s", config.req_password, config.value_list);
455 fetch_data(server_address, server_port, send_buffer); 426 fetch_data(config.server_address, config.server_port, send_buffer);
456 if (!strncmp(recv_buffer, "ERROR", 5)) { 427 if (!strncmp(recv_buffer, "ERROR", 5)) {
457 printf("NSClient - %s\n", recv_buffer); 428 printf("NSClient - %s\n", recv_buffer);
458 exit(STATE_UNKNOWN); 429 exit(STATE_UNKNOWN);
@@ -471,18 +442,16 @@ int main(int argc, char **argv) {
471 /* reset timeout */ 442 /* reset timeout */
472 alarm(0); 443 alarm(0);
473 444
474 if (perfdata == NULL) 445 if (perfdata == NULL) {
475 printf("%s\n", output_message); 446 printf("%s\n", output_message);
476 else 447 } else {
477 printf("%s | %s\n", output_message, perfdata); 448 printf("%s | %s\n", output_message, perfdata);
449 }
478 return return_code; 450 return return_code;
479} 451}
480 452
481/* process command-line arguments */ 453/* process command-line arguments */
482int process_arguments(int argc, char **argv) { 454check_nt_config_wrapper process_arguments(int argc, char **argv) {
483 int c;
484
485 int option = 0;
486 static struct option longopts[] = {{"port", required_argument, 0, 'p'}, 455 static struct option longopts[] = {{"port", required_argument, 0, 'p'},
487 {"timeout", required_argument, 0, 't'}, 456 {"timeout", required_argument, 0, 't'},
488 {"critical", required_argument, 0, 'c'}, 457 {"critical", required_argument, 0, 'c'},
@@ -497,34 +466,44 @@ int process_arguments(int argc, char **argv) {
497 {"help", no_argument, 0, 'h'}, 466 {"help", no_argument, 0, 'h'},
498 {0, 0, 0, 0}}; 467 {0, 0, 0, 0}};
499 468
469 check_nt_config_wrapper result = {
470 .errorcode = OK,
471 .config = check_nt_config_init(),
472 };
473
500 /* no options were supplied */ 474 /* no options were supplied */
501 if (argc < 2) 475 if (argc < 2) {
502 return ERROR; 476 result.errorcode = ERROR;
477 return result;
478 }
503 479
504 /* backwards compatibility */ 480 /* backwards compatibility */
505 if (!is_option(argv[1])) { 481 if (!is_option(argv[1])) {
506 server_address = strdup(argv[1]); 482 result.config.server_address = strdup(argv[1]);
507 argv[1] = argv[0]; 483 argv[1] = argv[0];
508 argv = &argv[1]; 484 argv = &argv[1];
509 argc--; 485 argc--;
510 } 486 }
511 487
512 for (c = 1; c < argc; c++) { 488 for (int index = 1; index < argc; index++) {
513 if (strcmp("-to", argv[c]) == 0) 489 if (strcmp("-to", argv[index]) == 0) {
514 strcpy(argv[c], "-t"); 490 strcpy(argv[index], "-t");
515 else if (strcmp("-wv", argv[c]) == 0) 491 } else if (strcmp("-wv", argv[index]) == 0) {
516 strcpy(argv[c], "-w"); 492 strcpy(argv[index], "-w");
517 else if (strcmp("-cv", argv[c]) == 0) 493 } else if (strcmp("-cv", argv[index]) == 0) {
518 strcpy(argv[c], "-c"); 494 strcpy(argv[index], "-c");
495 }
519 } 496 }
520 497
521 while (1) { 498 int option = 0;
522 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);
523 501
524 if (c == -1 || c == EOF || c == 1) 502 if (option_index == -1 || option_index == EOF || option_index == 1) {
525 break; 503 break;
504 }
526 505
527 switch (c) { 506 switch (option_index) {
528 case '?': /* print short usage statement if args not parsable */ 507 case '?': /* print short usage statement if args not parsable */
529 usage5(); 508 usage5();
530 case 'h': /* help */ 509 case 'h': /* help */
@@ -534,118 +513,128 @@ int process_arguments(int argc, char **argv) {
534 print_revision(progname, NP_VERSION); 513 print_revision(progname, NP_VERSION);
535 exit(STATE_UNKNOWN); 514 exit(STATE_UNKNOWN);
536 case 'H': /* hostname */ 515 case 'H': /* hostname */
537 server_address = optarg; 516 result.config.server_address = optarg;
538 break; 517 break;
539 case 's': /* password */ 518 case 's': /* password */
540 req_password = optarg; 519 result.config.req_password = optarg;
541 break; 520 break;
542 case 'p': /* port */ 521 case 'p': /* port */
543 if (is_intnonneg(optarg)) 522 if (is_intnonneg(optarg)) {
544 server_port = atoi(optarg); 523 result.config.server_port = atoi(optarg);
545 else 524 } else {
546 die(STATE_UNKNOWN, _("Server port must be an integer\n")); 525 die(STATE_UNKNOWN, _("Server port must be an integer\n"));
526 }
547 break; 527 break;
548 case 'v': 528 case 'v':
549 if (strlen(optarg) < 4) 529 if (strlen(optarg) < 4) {
550 return ERROR; 530 result.errorcode = ERROR;
551 if (!strcmp(optarg, "CLIENTVERSION")) 531 return result;
552 vars_to_check = CHECK_CLIENTVERSION; 532 }
553 else if (!strcmp(optarg, "CPULOAD")) 533 if (!strcmp(optarg, "CLIENTVERSION")) {
554 vars_to_check = CHECK_CPULOAD; 534 result.config.vars_to_check = CHECK_CLIENTVERSION;
555 else if (!strcmp(optarg, "UPTIME")) 535 } else if (!strcmp(optarg, "CPULOAD")) {
556 vars_to_check = CHECK_UPTIME; 536 result.config.vars_to_check = CHECK_CPULOAD;
557 else if (!strcmp(optarg, "USEDDISKSPACE")) 537 } else if (!strcmp(optarg, "UPTIME")) {
558 vars_to_check = CHECK_USEDDISKSPACE; 538 result.config.vars_to_check = CHECK_UPTIME;
559 else if (!strcmp(optarg, "SERVICESTATE")) 539 } else if (!strcmp(optarg, "USEDDISKSPACE")) {
560 vars_to_check = CHECK_SERVICESTATE; 540 result.config.vars_to_check = CHECK_USEDDISKSPACE;
561 else if (!strcmp(optarg, "PROCSTATE")) 541 } else if (!strcmp(optarg, "SERVICESTATE")) {
562 vars_to_check = CHECK_PROCSTATE; 542 result.config.vars_to_check = CHECK_SERVICESTATE;
563 else if (!strcmp(optarg, "MEMUSE")) 543 } else if (!strcmp(optarg, "PROCSTATE")) {
564 vars_to_check = CHECK_MEMUSE; 544 result.config.vars_to_check = CHECK_PROCSTATE;
565 else if (!strcmp(optarg, "COUNTER")) 545 } else if (!strcmp(optarg, "MEMUSE")) {
566 vars_to_check = CHECK_COUNTER; 546 result.config.vars_to_check = CHECK_MEMUSE;
567 else if (!strcmp(optarg, "FILEAGE")) 547 } else if (!strcmp(optarg, "COUNTER")) {
568 vars_to_check = CHECK_FILEAGE; 548 result.config.vars_to_check = CHECK_COUNTER;
569 else if (!strcmp(optarg, "INSTANCES")) 549 } else if (!strcmp(optarg, "FILEAGE")) {
570 vars_to_check = CHECK_INSTANCES; 550 result.config.vars_to_check = CHECK_FILEAGE;
571 else 551 } else if (!strcmp(optarg, "INSTANCES")) {
572 return ERROR; 552 result.config.vars_to_check = CHECK_INSTANCES;
553 } else {
554 result.errorcode = ERROR;
555 return result;
556 }
573 break; 557 break;
574 case 'l': /* value list */ 558 case 'l': /* value list */
575 value_list = optarg; 559 result.config.value_list = optarg;
576 break; 560 break;
577 case 'w': /* warning threshold */ 561 case 'w': /* warning threshold */
578 warning_value = strtoul(optarg, NULL, 10); 562 result.config.warning_value = strtoul(optarg, NULL, 10);
579 check_warning_value = true; 563 result.config.check_warning_value = true;
580 break; 564 break;
581 case 'c': /* critical threshold */ 565 case 'c': /* critical threshold */
582 critical_value = strtoul(optarg, NULL, 10); 566 result.config.critical_value = strtoul(optarg, NULL, 10);
583 check_critical_value = true; 567 result.config.check_critical_value = true;
584 break; 568 break;
585 case 'd': /* Display select for services */ 569 case 'd': /* Display select for services */
586 if (!strcmp(optarg, "SHOWALL")) 570 if (!strcmp(optarg, "SHOWALL")) {
587 show_all = true; 571 result.config.show_all = true;
572 }
588 break; 573 break;
589 case 'u': 574 case 'u':
590 socket_timeout_state = STATE_UNKNOWN; 575 socket_timeout_state = STATE_UNKNOWN;
591 break; 576 break;
592 case 't': /* timeout */ 577 case 't': /* timeout */
593 socket_timeout = atoi(optarg); 578 socket_timeout = atoi(optarg);
594 if (socket_timeout <= 0) 579 if (socket_timeout <= 0) {
595 return ERROR; 580 result.errorcode = ERROR;
581 return result;
582 }
596 } 583 }
597 } 584 }
598 if (server_address == NULL) 585 if (result.config.server_address == NULL) {
599 usage4(_("You must provide a server address or host name")); 586 usage4(_("You must provide a server address or host name"));
587 }
600 588
601 if (vars_to_check == CHECK_NONE) 589 if (result.config.vars_to_check == CHECK_NONE) {
602 return ERROR; 590 result.errorcode = ERROR;
591 return result;
592 }
603 593
604 if (req_password == NULL) 594 if (result.config.req_password == NULL) {
605 req_password = strdup(_("None")); 595 result.config.req_password = strdup(_("None"));
596 }
606 597
607 return OK; 598 return result;
608} 599}
609 600
610void fetch_data(const char *address, int port, const char *sendb) { 601void fetch_data(const char *address, int port, const char *sendb) {
611 int result; 602 int result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer));
612
613 result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer));
614 603
615 if (result != STATE_OK) 604 if (result != STATE_OK) {
616 die(result, _("could not fetch information from server\n")); 605 die(result, _("could not fetch information from server\n"));
606 }
617 607
618 if (!strncmp(recv_buffer, "ERROR", 5)) 608 if (!strncmp(recv_buffer, "ERROR", 5)) {
619 die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer); 609 die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer);
610 }
620} 611}
621 612
622bool strtoularray(unsigned long *array, char *string, const char *delim) { 613bool strtoularray(unsigned long *array, char *string, const char *delim) {
623 /* split a <delim> delimited string into a long array */ 614 /* split a <delim> delimited string into a long array */
624 int idx = 0; 615 for (int idx = 0; idx < MAX_VALUE_LIST; idx++) {
625 char *t1;
626
627 for (idx = 0; idx < MAX_VALUE_LIST; idx++)
628 array[idx] = 0; 616 array[idx] = 0;
617 }
629 618
630 idx = 0; 619 int idx = 0;
631 for (t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) { 620 for (char *t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) {
632 if (is_numeric(t1) && idx < MAX_VALUE_LIST) { 621 if (is_numeric(t1) && idx < MAX_VALUE_LIST) {
633 array[idx] = strtoul(t1, NULL, 10); 622 array[idx] = strtoul(t1, NULL, 10);
634 idx++; 623 idx++;
635 } else 624 } else {
636 return false; 625 return false;
626 }
637 } 627 }
638 return true; 628 return true;
639} 629}
640 630
641void preparelist(char *string) { 631void preparelist(char *string) {
642 /* Replace all , with & which is the delimiter for the request */ 632 /* Replace all , with & which is the delimiter for the request */
643 int i; 633 for (int i = 0; (size_t)i < strlen(string); i++) {
644
645 for (i = 0; (size_t)i < strlen(string); i++)
646 if (string[i] == ',') { 634 if (string[i] == ',') {
647 string[i] = '&'; 635 string[i] = '&';
648 } 636 }
637 }
649} 638}
650 639
651void print_help(void) { 640void print_help(void) {
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_peer.c b/plugins/check_ntp_peer.c
index f99e5032..6e76bf23 100644
--- a/plugins/check_ntp_peer.c
+++ b/plugins/check_ntp_peer.c
@@ -35,6 +35,7 @@
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-2024"; 40const char *copyright = "2006-2024";
40const char *email = "devel@monitoring-plugins.org"; 41const char *email = "devel@monitoring-plugins.org";
@@ -42,30 +43,18 @@ const char *email = "devel@monitoring-plugins.org";
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;
47static int port = 123;
48static int verbose = 0; 49static 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
64static int process_arguments(int /*argc*/, char ** /*argv*/); 53typedef struct {
65static thresholds *offset_thresholds = NULL; 54 int errorcode;
66static thresholds *jitter_thresholds = NULL; 55 check_ntp_peer_config config;
67static thresholds *stratum_thresholds = NULL; 56} check_ntp_peer_config_wrapper;
68static thresholds *truechimer_thresholds = NULL; 57static check_ntp_peer_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
69static void print_help(void); 58static void print_help(void);
70void print_usage(void); 59void print_usage(void);
71 60
@@ -157,25 +146,25 @@ typedef struct {
157 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \ 146 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
158 } while (0); 147 } while (0);
159 148
160void print_ntp_control_message(const ntp_control_message *p) { 149void print_ntp_control_message(const ntp_control_message *message) {
161 printf("control packet contents:\n"); 150 printf("control packet contents:\n");
162 printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); 151 printf("\tflags: 0x%.2x , 0x%.2x\n", message->flags, message->op);
163 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);
164 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);
165 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);
166 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);
167 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);
168 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);
169 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);
170 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));
171 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));
172 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));
173 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));
174 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));
175 164
176 int numpeers = ntohs(p->count) / (sizeof(ntp_assoc_status_pair)); 165 int numpeers = ntohs(message->count) / (sizeof(ntp_assoc_status_pair));
177 if (p->op & REM_RESP && p->op & OP_READSTAT) { 166 if (message->op & REM_RESP && message->op & OP_READSTAT) {
178 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)p->data; 167 const ntp_assoc_status_pair *peer = (ntp_assoc_status_pair *)message->data;
179 for (int i = 0; i < numpeers; i++) { 168 for (int i = 0; i < numpeers; i++) {
180 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status)); 169 printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status));
181 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) { 170 if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) {
@@ -190,13 +179,13 @@ void print_ntp_control_message(const ntp_control_message *p) {
190 } 179 }
191} 180}
192 181
193void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq) { 182void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_t seq) {
194 memset(p, 0, sizeof(ntp_control_message)); 183 memset(message, 0, sizeof(ntp_control_message));
195 LI_SET(p->flags, LI_NOWARNING); 184 LI_SET(message->flags, LI_NOWARNING);
196 VN_SET(p->flags, VN_RESERVED); 185 VN_SET(message->flags, VN_RESERVED);
197 MODE_SET(p->flags, MODE_CONTROLMSG); 186 MODE_SET(message->flags, MODE_CONTROLMSG);
198 OP_SET(p->op, opcode); 187 OP_SET(message->op, opcode);
199 p->seq = htons(seq); 188 message->seq = htons(seq);
200 /* Remaining fields are zero for requests */ 189 /* Remaining fields are zero for requests */
201} 190}
202 191
@@ -211,10 +200,23 @@ void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq)
211 * 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
212 * 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
213 * so I left it alone */ 202 * so I left it alone */
214int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum, int *num_truechimers) { 203typedef struct {
215 *offset_result = STATE_UNKNOWN; 204 mp_state_enum state;
216 *jitter = *stratum = -1; 205 mp_state_enum offset_result;
217 *num_truechimers = 0; 206 double offset;
207 double jitter;
208 long stratum;
209 int num_truechimers;
210} ntp_request_result;
211ntp_request_result ntp_request(const check_ntp_peer_config config) {
212
213 ntp_request_result result = {
214 .state = STATE_OK,
215 .offset_result = STATE_UNKNOWN,
216 .jitter = -1,
217 .stratum = -1,
218 .num_truechimers = 0,
219 };
218 220
219 /* Long-winded explanation: 221 /* Long-winded explanation:
220 * 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
@@ -237,10 +239,10 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
237 void *tmp; 239 void *tmp;
238 ntp_assoc_status_pair *peers = NULL; 240 ntp_assoc_status_pair *peers = NULL;
239 int peer_offset = 0; 241 int peer_offset = 0;
240 int peers_size = 0; 242 size_t peers_size = 0;
241 int npeers = 0; 243 size_t npeers = 0;
242 int conn = -1; 244 int conn = -1;
243 my_udp_connect(server_address, port, &conn); 245 my_udp_connect(config.server_address, config.port, &conn);
244 246
245 /* keep sending requests until the server stops setting the 247 /* keep sending requests until the server stops setting the
246 * REM_MORE bit, though usually this is only 1 packet. */ 248 * REM_MORE bit, though usually this is only 1 packet. */
@@ -255,24 +257,28 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
255 /* Attempt to read the largest size packet possible */ 257 /* Attempt to read the largest size packet possible */
256 req.count = htons(MAX_CM_SIZE); 258 req.count = htons(MAX_CM_SIZE);
257 DBG(printf("receiving READSTAT response")) 259 DBG(printf("receiving READSTAT response"))
258 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) 260 if (read(conn, &req, SIZEOF_NTPCM(req)) == -1) {
259 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 261 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
262 }
260 DBG(print_ntp_control_message(&req)); 263 DBG(print_ntp_control_message(&req));
261 /* discard obviously invalid packets */ 264 /* discard obviously invalid packets */
262 if (ntohs(req.count) > MAX_CM_SIZE) 265 if (ntohs(req.count) > MAX_CM_SIZE) {
263 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");
267 }
264 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1)); 268 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
265 269
266 if (LI(req.flags) == LI_ALARM) 270 if (LI(req.flags) == LI_ALARM) {
267 li_alarm = true; 271 li_alarm = true;
272 }
268 /* Each peer identifier is 4 bytes in the data section, which 273 /* Each peer identifier is 4 bytes in the data section, which
269 * we represent as a ntp_assoc_status_pair datatype. 274 * we represent as a ntp_assoc_status_pair datatype.
270 */ 275 */
271 peers_size += ntohs(req.count); 276 peers_size += ntohs(req.count);
272 if ((tmp = realloc(peers, peers_size)) == NULL) 277 if ((tmp = realloc(peers, peers_size)) == NULL) {
273 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");
279 }
274 peers = tmp; 280 peers = tmp;
275 memcpy((void *)((ptrdiff_t)peers + peer_offset), (void *)req.data, ntohs(req.count)); 281 memcpy((peers + peer_offset), (void *)req.data, ntohs(req.count));
276 npeers = peers_size / sizeof(ntp_assoc_status_pair); 282 npeers = peers_size / sizeof(ntp_assoc_status_pair);
277 peer_offset += ntohs(req.count); 283 peer_offset += ntohs(req.count);
278 } while (req.op & REM_MORE); 284 } while (req.op & REM_MORE);
@@ -280,9 +286,9 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
280 /* 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
281 * at least some candidates. In the latter case we'll issue 287 * at least some candidates. In the latter case we'll issue
282 * a warning but go ahead with the check on them. */ 288 * a warning but go ahead with the check on them. */
283 for (int i = 0; i < npeers; i++) { 289 for (size_t i = 0; i < npeers; i++) {
284 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) { 290 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
285 (*num_truechimers)++; 291 result.num_truechimers++;
286 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) { 292 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
287 num_candidates++; 293 num_candidates++;
288 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) { 294 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
@@ -293,31 +299,35 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
293 } 299 }
294 } 300 }
295 301
296 if (verbose) 302 if (verbose) {
297 printf("%d candidate peers available\n", num_candidates); 303 printf("%d candidate peers available\n", num_candidates);
298 if (verbose && syncsource_found) 304 }
305 if (verbose && syncsource_found) {
299 printf("synchronization source found\n"); 306 printf("synchronization source found\n");
307 }
300 308
301 int status = STATE_OK;
302 if (!syncsource_found) { 309 if (!syncsource_found) {
303 status = STATE_WARNING; 310 result.state = STATE_WARNING;
304 if (verbose) 311 if (verbose) {
305 printf("warning: no synchronization source found\n"); 312 printf("warning: no synchronization source found\n");
313 }
306 } 314 }
307 if (li_alarm) { 315 if (li_alarm) {
308 status = STATE_WARNING; 316 result.state = STATE_WARNING;
309 if (verbose) 317 if (verbose) {
310 printf("warning: LI_ALARM bit is set\n"); 318 printf("warning: LI_ALARM bit is set\n");
319 }
311 } 320 }
312 321
313 const char *getvar = "stratum,offset,jitter"; 322 const char *getvar = "stratum,offset,jitter";
314 char *data; 323 char *data;
315 for (int i = 0; i < npeers; i++) { 324 for (size_t i = 0; i < npeers; i++) {
316 /* Only query this server if it is the current sync source */ 325 /* Only query this server if it is the current sync source */
317 /* 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 */
318 if (PEER_SEL(peers[i].status) >= min_peer_sel) { 327 if (PEER_SEL(peers[i].status) >= min_peer_sel) {
319 if (verbose) 328 if (verbose) {
320 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); 329 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
330 }
321 xasprintf(&data, ""); 331 xasprintf(&data, "");
322 do { 332 do {
323 setup_control_request(&req, OP_READVAR, 2); 333 setup_control_request(&req, OP_READVAR, 2);
@@ -342,60 +352,68 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
342 DBG(print_ntp_control_message(&req)); 352 DBG(print_ntp_control_message(&req));
343 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2)); 353 } while (!(req.op & OP_READVAR && ntohs(req.seq) == 2));
344 354
345 if (!(req.op & REM_ERROR)) 355 if (!(req.op & REM_ERROR)) {
346 xasprintf(&data, "%s%s", data, req.data); 356 xasprintf(&data, "%s%s", data, req.data);
357 }
347 } while (req.op & REM_MORE); 358 } while (req.op & REM_MORE);
348 359
349 if (req.op & REM_ERROR) { 360 if (req.op & REM_ERROR) {
350 if (strstr(getvar, "jitter")) { 361 if (strstr(getvar, "jitter")) {
351 if (verbose) 362 if (verbose) {
352 printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with " 363 printf("The command failed. This is usually caused by servers refusing the 'jitter'\nvariable. Restarting with "
353 "'dispersion'...\n"); 364 "'dispersion'...\n");
365 }
354 getvar = "stratum,offset,dispersion"; 366 getvar = "stratum,offset,dispersion";
355 i--; 367 i--;
356 continue; 368 continue;
357 } 369 }
358 if (strlen(getvar)) { 370 if (strlen(getvar)) {
359 if (verbose) 371 if (verbose) {
360 printf("Server didn't like dispersion either; will retrieve everything\n"); 372 printf("Server didn't like dispersion either; will retrieve everything\n");
373 }
361 getvar = ""; 374 getvar = "";
362 i--; 375 i--;
363 continue; 376 continue;
364 } 377 }
365 } 378 }
366 379
367 if (verbose > 1) 380 if (verbose > 1) {
368 printf("Server responded: >>>%s<<<\n", data); 381 printf("Server responded: >>>%s<<<\n", data);
382 }
369 383
370 double tmp_offset = 0; 384 double tmp_offset = 0;
371 char *value; 385 char *value;
372 char *nptr; 386 char *nptr;
373 /* get the offset */ 387 /* get the offset */
374 if (verbose) 388 if (verbose) {
375 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc)); 389 printf("parsing offset from peer %.2x: ", ntohs(peers[i].assoc));
390 }
376 391
377 value = np_extract_ntpvar(data, "offset"); 392 value = np_extract_ntpvar(data, "offset");
378 nptr = NULL; 393 nptr = NULL;
379 /* Convert the value if we have one */ 394 /* Convert the value if we have one */
380 if (value != NULL) 395 if (value != NULL) {
381 tmp_offset = strtod(value, &nptr) / 1000; 396 tmp_offset = strtod(value, &nptr) / 1000;
397 }
382 /* If value is null or no conversion was performed */ 398 /* If value is null or no conversion was performed */
383 if (value == NULL || value == nptr) { 399 if (value == NULL || value == nptr) {
384 if (verbose) 400 if (verbose) {
385 printf("error: unable to read server offset response.\n"); 401 printf("error: unable to read server offset response.\n");
402 }
386 } else { 403 } else {
387 if (verbose) 404 if (verbose) {
388 printf("%.10g\n", tmp_offset); 405 printf("%.10g\n", tmp_offset);
389 if (*offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(*offset)) { 406 }
390 *offset = tmp_offset; 407 if (result.offset_result == STATE_UNKNOWN || fabs(tmp_offset) < fabs(result.offset)) {
391 *offset_result = STATE_OK; 408 result.offset = tmp_offset;
409 result.offset_result = STATE_OK;
392 } else { 410 } else {
393 /* Skip this one; move to the next */ 411 /* Skip this one; move to the next */
394 continue; 412 continue;
395 } 413 }
396 } 414 }
397 415
398 if (do_jitter) { 416 if (config.do_jitter) {
399 /* get the jitter */ 417 /* get the jitter */
400 if (verbose) { 418 if (verbose) {
401 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter", 419 printf("parsing %s from peer %.2x: ", strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter",
@@ -404,19 +422,21 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
404 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter"); 422 value = np_extract_ntpvar(data, strstr(getvar, "dispersion") != NULL ? "dispersion" : "jitter");
405 nptr = NULL; 423 nptr = NULL;
406 /* Convert the value if we have one */ 424 /* Convert the value if we have one */
407 if (value != NULL) 425 if (value != NULL) {
408 *jitter = strtod(value, &nptr); 426 result.jitter = strtod(value, &nptr);
427 }
409 /* If value is null or no conversion was performed */ 428 /* If value is null or no conversion was performed */
410 if (value == NULL || value == nptr) { 429 if (value == NULL || value == nptr) {
411 if (verbose) 430 if (verbose) {
412 printf("error: unable to read server jitter/dispersion response.\n"); 431 printf("error: unable to read server jitter/dispersion response.\n");
413 *jitter = -1; 432 }
433 result.jitter = -1;
414 } else if (verbose) { 434 } else if (verbose) {
415 printf("%.10g\n", *jitter); 435 printf("%.10g\n", result.jitter);
416 } 436 }
417 } 437 }
418 438
419 if (do_stratum) { 439 if (config.do_stratum) {
420 /* get the stratum */ 440 /* get the stratum */
421 if (verbose) { 441 if (verbose) {
422 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc)); 442 printf("parsing stratum from peer %.2x: ", ntohs(peers[i].assoc));
@@ -424,28 +444,32 @@ int ntp_request(double *offset, int *offset_result, double *jitter, int *stratum
424 value = np_extract_ntpvar(data, "stratum"); 444 value = np_extract_ntpvar(data, "stratum");
425 nptr = NULL; 445 nptr = NULL;
426 /* Convert the value if we have one */ 446 /* Convert the value if we have one */
427 if (value != NULL) 447 if (value != NULL) {
428 *stratum = strtol(value, &nptr, 10); 448 result.stratum = strtol(value, &nptr, 10);
449 }
429 if (value == NULL || value == nptr) { 450 if (value == NULL || value == nptr) {
430 if (verbose) 451 if (verbose) {
431 printf("error: unable to read server stratum response.\n"); 452 printf("error: unable to read server stratum response.\n");
432 *stratum = -1; 453 }
454 result.stratum = -1;
433 } else { 455 } else {
434 if (verbose) 456 if (verbose) {
435 printf("%i\n", *stratum); 457 printf("%li\n", result.stratum);
458 }
436 } 459 }
437 } 460 }
438 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */ 461 } /* if (PEER_SEL(peers[i].status) >= min_peer_sel) */
439 } /* for (i = 0; i < npeers; i++) */ 462 } /* for (i = 0; i < npeers; i++) */
440 463
441 close(conn); 464 close(conn);
442 if (peers != NULL) 465 if (peers != NULL) {
443 free(peers); 466 free(peers);
467 }
444 468
445 return status; 469 return result;
446} 470}
447 471
448int process_arguments(int argc, char **argv) { 472check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
449 static struct option longopts[] = { 473 static struct option longopts[] = {
450 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'}, 474 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {"verbose", no_argument, 0, 'v'},
451 {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'}, 475 {"use-ipv4", no_argument, 0, '4'}, {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'},
@@ -454,14 +478,21 @@ int process_arguments(int argc, char **argv) {
454 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'}, 478 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'},
455 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}}; 479 {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}};
456 480
457 if (argc < 2) 481 if (argc < 2) {
458 usage("\n"); 482 usage("\n");
483 }
484
485 check_ntp_peer_config_wrapper result = {
486 .errorcode = OK,
487 .config = check_ntp_peer_config_init(),
488 };
459 489
460 while (true) { 490 while (true) {
461 int option = 0; 491 int option = 0;
462 int option_char = getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option); 492 int option_char = getopt_long(argc, argv, "Vhv46qw:c:W:C:j:k:m:n:t:H:p:", longopts, &option);
463 if (option_char == -1 || option_char == EOF || option_char == 1) 493 if (option_char == -1 || option_char == EOF || option_char == 1) {
464 break; 494 break;
495 }
465 496
466 switch (option_char) { 497 switch (option_char) {
467 case 'h': 498 case 'h':
@@ -476,45 +507,46 @@ int process_arguments(int argc, char **argv) {
476 verbose++; 507 verbose++;
477 break; 508 break;
478 case 'q': 509 case 'q':
479 quiet = true; 510 result.config.quiet = true;
480 break; 511 break;
481 case 'w': 512 case 'w':
482 owarn = optarg; 513 result.config.owarn = optarg;
483 break; 514 break;
484 case 'c': 515 case 'c':
485 ocrit = optarg; 516 result.config.ocrit = optarg;
486 break; 517 break;
487 case 'W': 518 case 'W':
488 do_stratum = true; 519 result.config.do_stratum = true;
489 swarn = optarg; 520 result.config.swarn = optarg;
490 break; 521 break;
491 case 'C': 522 case 'C':
492 do_stratum = true; 523 result.config.do_stratum = true;
493 scrit = optarg; 524 result.config.scrit = optarg;
494 break; 525 break;
495 case 'j': 526 case 'j':
496 do_jitter = true; 527 result.config.do_jitter = true;
497 jwarn = optarg; 528 result.config.jwarn = optarg;
498 break; 529 break;
499 case 'k': 530 case 'k':
500 do_jitter = true; 531 result.config.do_jitter = true;
501 jcrit = optarg; 532 result.config.jcrit = optarg;
502 break; 533 break;
503 case 'm': 534 case 'm':
504 do_truechimers = true; 535 result.config.do_truechimers = true;
505 twarn = optarg; 536 result.config.twarn = optarg;
506 break; 537 break;
507 case 'n': 538 case 'n':
508 do_truechimers = true; 539 result.config.do_truechimers = true;
509 tcrit = optarg; 540 result.config.tcrit = optarg;
510 break; 541 break;
511 case 'H': 542 case 'H':
512 if (!is_host(optarg)) 543 if (!is_host(optarg)) {
513 usage2(_("Invalid hostname/address"), optarg); 544 usage2(_("Invalid hostname/address"), optarg);
514 server_address = strdup(optarg); 545 }
546 result.config.server_address = strdup(optarg);
515 break; 547 break;
516 case 'p': 548 case 'p':
517 port = atoi(optarg); 549 result.config.port = atoi(optarg);
518 break; 550 break;
519 case 't': 551 case 't':
520 socket_timeout = atoi(optarg); 552 socket_timeout = atoi(optarg);
@@ -536,29 +568,34 @@ int process_arguments(int argc, char **argv) {
536 } 568 }
537 } 569 }
538 570
539 if (server_address == NULL) { 571 if (result.config.server_address == NULL) {
540 usage4(_("Hostname was not supplied")); 572 usage4(_("Hostname was not supplied"));
541 } 573 }
542 574
543 return 0; 575 set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
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);
579
580 return result;
544} 581}
545 582
546char *perfd_offset(double offset) { 583char *perfd_offset(double offset, thresholds *offset_thresholds) {
547 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false, 584 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
548 0); 585 0);
549} 586}
550 587
551char *perfd_jitter(double jitter) { 588char *perfd_jitter(double jitter, bool do_jitter, thresholds *jitter_thresholds) {
552 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter, jitter_thresholds->critical->end, true, 0, 589 return fperfdata("jitter", jitter, "", do_jitter, jitter_thresholds->warning->end, do_jitter, jitter_thresholds->critical->end, true, 0,
553 false, 0); 590 false, 0);
554} 591}
555 592
556char *perfd_stratum(int stratum) { 593char *perfd_stratum(int stratum, bool do_stratum, thresholds *stratum_thresholds) {
557 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end, do_stratum, 594 return perfdata("stratum", stratum, "", do_stratum, (int)stratum_thresholds->warning->end, do_stratum,
558 (int)stratum_thresholds->critical->end, true, 0, true, 16); 595 (int)stratum_thresholds->critical->end, true, 0, true, 16);
559} 596}
560 597
561char *perfd_truechimers(int num_truechimers) { 598char *perfd_truechimers(int num_truechimers, const bool do_truechimers, thresholds *truechimer_thresholds) {
562 return perfdata("truechimers", num_truechimers, "", do_truechimers, (int)truechimer_thresholds->warning->end, do_truechimers, 599 return perfdata("truechimers", num_truechimers, "", do_truechimers, (int)truechimer_thresholds->warning->end, do_truechimers,
563 (int)truechimer_thresholds->critical->end, true, 0, false, 0); 600 (int)truechimer_thresholds->critical->end, true, 0, false, 0);
564} 601}
@@ -571,13 +608,13 @@ int main(int argc, char *argv[]) {
571 /* Parse extra opts if any */ 608 /* Parse extra opts if any */
572 argv = np_extra_opts(&argc, argv, progname); 609 argv = np_extra_opts(&argc, argv, progname);
573 610
574 if (process_arguments(argc, argv) == ERROR) 611 check_ntp_peer_config_wrapper tmp_config = process_arguments(argc, argv);
612
613 if (tmp_config.errorcode == ERROR) {
575 usage4(_("Could not parse arguments")); 614 usage4(_("Could not parse arguments"));
615 }
576 616
577 set_thresholds(&offset_thresholds, owarn, ocrit); 617 const check_ntp_peer_config config = tmp_config.config;
578 set_thresholds(&jitter_thresholds, jwarn, jcrit);
579 set_thresholds(&stratum_thresholds, swarn, scrit);
580 set_thresholds(&truechimer_thresholds, twarn, tcrit);
581 618
582 /* initialize alarm signal handling */ 619 /* initialize alarm signal handling */
583 signal(SIGALRM, socket_timeout_alarm_handler); 620 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -585,44 +622,40 @@ int main(int argc, char *argv[]) {
585 /* set socket timeout */ 622 /* set socket timeout */
586 alarm(socket_timeout); 623 alarm(socket_timeout);
587 624
588 int offset_result;
589 int stratum;
590 int num_truechimers;
591 double offset = 0;
592 double jitter = 0;
593 /* This returns either OK or WARNING (See comment preceding ntp_request) */ 625 /* This returns either OK or WARNING (See comment preceding ntp_request) */
594 int 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;
595 628
596 if (offset_result == STATE_UNKNOWN) { 629 if (ntp_res.offset_result == STATE_UNKNOWN) {
597 /* if there's no sync peer (this overrides ntp_request output): */ 630 /* if there's no sync peer (this overrides ntp_request output): */
598 result = (quiet ? STATE_UNKNOWN : STATE_CRITICAL); 631 result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL);
599 } else { 632 } else {
600 /* Be quiet if there's no candidates either */ 633 /* Be quiet if there's no candidates either */
601 if (quiet && result == STATE_WARNING) 634 if (config.quiet && result == STATE_WARNING) {
602 result = STATE_UNKNOWN; 635 result = STATE_UNKNOWN;
603 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));
604 } 638 }
605 639
606 int oresult = result; 640 mp_state_enum oresult = result;
607 641 mp_state_enum tresult = STATE_UNKNOWN;
608 int tresult = STATE_UNKNOWN;
609 642
610 if (do_truechimers) { 643 if (config.do_truechimers) {
611 tresult = get_status(num_truechimers, truechimer_thresholds); 644 tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds);
612 result = max_state_alt(result, tresult); 645 result = max_state_alt(result, tresult);
613 } 646 }
614 647
615 int sresult = STATE_UNKNOWN; 648 mp_state_enum sresult = STATE_UNKNOWN;
616 649
617 if (do_stratum) { 650 if (config.do_stratum) {
618 sresult = get_status(stratum, stratum_thresholds); 651 sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds);
619 result = max_state_alt(result, sresult); 652 result = max_state_alt(result, sresult);
620 } 653 }
621 654
622 int jresult = STATE_UNKNOWN; 655 mp_state_enum jresult = STATE_UNKNOWN;
623 656
624 if (do_jitter) { 657 if (config.do_jitter) {
625 jresult = get_status(jitter, jitter_thresholds); 658 jresult = get_status(ntp_res.jitter, config.jitter_thresholds);
626 result = max_state_alt(result, jresult); 659 result = max_state_alt(result, jresult);
627 } 660 }
628 661
@@ -641,59 +674,67 @@ int main(int argc, char *argv[]) {
641 xasprintf(&result_line, _("NTP UNKNOWN:")); 674 xasprintf(&result_line, _("NTP UNKNOWN:"));
642 break; 675 break;
643 } 676 }
644 if (!syncsource_found) 677
678 if (!syncsource_found) {
645 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized")); 679 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
646 else if (li_alarm) 680 } else if (li_alarm) {
647 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 }
648 683
649 char *perfdata_line; 684 char *perfdata_line;
650 if (offset_result == STATE_UNKNOWN) { 685 if (ntp_res.offset_result == STATE_UNKNOWN) {
651 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 686 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
652 xasprintf(&perfdata_line, ""); 687 xasprintf(&perfdata_line, "");
653 } else if (oresult == STATE_WARNING) { 688 } else if (oresult == STATE_WARNING) {
654 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);
655 } else if (oresult == STATE_CRITICAL) { 690 } else if (oresult == STATE_CRITICAL) {
656 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);
657 } else { 692 } else {
658 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);
659 } 694 }
660 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 695 xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
661 696
662 if (do_jitter) { 697 if (config.do_jitter) {
663 if (jresult == STATE_WARNING) { 698 if (jresult == STATE_WARNING) {
664 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, jitter); 699 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter);
665 } else if (jresult == STATE_CRITICAL) { 700 } else if (jresult == STATE_CRITICAL) {
666 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, jitter); 701 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
667 } else { 702 } else {
668 xasprintf(&result_line, "%s, jitter=%f", result_line, jitter); 703 xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
669 } 704 }
670 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));
671 } 706 }
672 if (do_stratum) { 707
708 if (config.do_stratum) {
673 if (sresult == STATE_WARNING) { 709 if (sresult == STATE_WARNING) {
674 xasprintf(&result_line, "%s, stratum=%i (WARNING)", result_line, stratum); 710 xasprintf(&result_line, "%s, stratum=%l (WARNING)", result_line, ntp_res.stratum);
675 } else if (sresult == STATE_CRITICAL) { 711 } else if (sresult == STATE_CRITICAL) {
676 xasprintf(&result_line, "%s, stratum=%i (CRITICAL)", result_line, stratum); 712 xasprintf(&result_line, "%s, stratum=%l (CRITICAL)", result_line, ntp_res.stratum);
677 } else { 713 } else {
678 xasprintf(&result_line, "%s, stratum=%i", result_line, stratum); 714 xasprintf(&result_line, "%s, stratum=%l", result_line, ntp_res.stratum);
679 } 715 }
680 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));
681 } 717 }
682 if (do_truechimers) { 718
719 if (config.do_truechimers) {
683 if (tresult == STATE_WARNING) { 720 if (tresult == STATE_WARNING) {
684 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);
685 } else if (tresult == STATE_CRITICAL) { 722 } else if (tresult == STATE_CRITICAL) {
686 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);
687 } else { 724 } else {
688 xasprintf(&result_line, "%s, truechimers=%i", result_line, num_truechimers); 725 xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
689 } 726 }
690 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));
691 } 729 }
730
692 printf("%s|%s\n", result_line, perfdata_line); 731 printf("%s|%s\n", result_line, perfdata_line);
693 732
694 if (server_address != NULL) 733 if (config.server_address != NULL) {
695 free(server_address); 734 free(config.server_address);
696 return result; 735 }
736
737 exit(result);
697} 738}
698 739
699void print_help(void) { 740void print_help(void) {
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 703b69df..31162883 100644
--- a/plugins/check_ntp_time.c
+++ b/plugins/check_ntp_time.c
@@ -41,17 +41,18 @@ const char *email = "devel@monitoring-plugins.org";
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;
46static char *port = "123";
47static int verbose = 0; 48static int verbose = 0;
48static bool quiet = false;
49static char *owarn = "60";
50static char *ocrit = "120";
51static int time_offset = 0;
52 49
53static int process_arguments(int, char **); 50typedef struct {
54static thresholds *offset_thresholds = NULL; 51 int errorcode;
52 check_ntp_time_config config;
53} check_ntp_time_config_wrapper;
54static check_ntp_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
55
55static void print_help(void); 56static void print_help(void);
56void print_usage(void); 57void print_usage(void);
57 58
@@ -159,7 +160,7 @@ typedef struct {
159#define EPOCHDIFF 0x83aa7e80UL 160#define EPOCHDIFF 0x83aa7e80UL
160 161
161/* extract a 32-bit ntp fixed point number into a double */ 162/* extract a 32-bit ntp fixed point number into a double */
162#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))
163 164
164/* likewise for a 64-bit ntp fp number */ 165/* likewise for a 64-bit ntp fp number */
165#define NTP64asDOUBLE(n) \ 166#define NTP64asDOUBLE(n) \
@@ -208,56 +209,52 @@ typedef struct {
208 } while (0); 209 } while (0);
209 210
210/* calculate the offset of the local clock */ 211/* calculate the offset of the local clock */
211static 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) {
212 double client_tx = NTP64asDOUBLE(m->origts); 213 double client_tx = NTP64asDOUBLE(message->origts);
213 double peer_rx = NTP64asDOUBLE(m->rxts); 214 double peer_rx = NTP64asDOUBLE(message->rxts);
214 double peer_tx = NTP64asDOUBLE(m->txts); 215 double peer_tx = NTP64asDOUBLE(message->txts);
215 double client_rx = TVasDOUBLE((*t)); 216 double client_rx = TVasDOUBLE((*time_value));
216 return (.5 * ((peer_tx - client_rx) + (peer_rx - client_tx))); 217 return (((peer_tx - client_rx) + (peer_rx - client_tx)) / 2);
217} 218}
218 219
219/* print out a ntp packet in human readable/debuggable format */ 220/* print out a ntp packet in human readable/debuggable format */
220void print_ntp_message(const ntp_message *p) { 221void print_ntp_message(const ntp_message *message) {
221 struct timeval ref; 222 struct timeval ref;
222 struct timeval orig; 223 struct timeval orig;
223 struct timeval rx;
224 struct timeval tx;
225 224
226 NTP64toTV(p->refts, ref); 225 NTP64toTV(message->refts, ref);
227 NTP64toTV(p->origts, orig); 226 NTP64toTV(message->origts, orig);
228 NTP64toTV(p->rxts, rx);
229 NTP64toTV(p->txts, tx);
230 227
231 printf("packet contents:\n"); 228 printf("packet contents:\n");
232 printf("\tflags: 0x%.2x\n", p->flags); 229 printf("\tflags: 0x%.2x\n", message->flags);
233 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);
234 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);
235 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);
236 printf("\tstratum = %d\n", p->stratum); 233 printf("\tstratum = %d\n", message->stratum);
237 printf("\tpoll = %g\n", pow(2, p->poll)); 234 printf("\tpoll = %g\n", pow(2, message->poll));
238 printf("\tprecision = %g\n", pow(2, p->precision)); 235 printf("\tprecision = %g\n", pow(2, message->precision));
239 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay)); 236 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(message->rtdelay));
240 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp)); 237 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(message->rtdisp));
241 printf("\trefid = %x\n", p->refid); 238 printf("\trefid = %x\n", message->refid);
242 printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts)); 239 printf("\trefts = %-.16g\n", NTP64asDOUBLE(message->refts));
243 printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts)); 240 printf("\torigts = %-.16g\n", NTP64asDOUBLE(message->origts));
244 printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts)); 241 printf("\trxts = %-.16g\n", NTP64asDOUBLE(message->rxts));
245 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts)); 242 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(message->txts));
246} 243}
247 244
248void setup_request(ntp_message *p) { 245void setup_request(ntp_message *message) {
249 memset(p, 0, sizeof(ntp_message)); 246 memset(message, 0, sizeof(ntp_message));
250 LI_SET(p->flags, LI_ALARM); 247 LI_SET(message->flags, LI_ALARM);
251 VN_SET(p->flags, 4); 248 VN_SET(message->flags, 4);
252 MODE_SET(p->flags, MODE_CLIENT); 249 MODE_SET(message->flags, MODE_CLIENT);
253 p->poll = 4; 250 message->poll = 4;
254 p->precision = (int8_t)0xfa; 251 message->precision = (int8_t)0xfa;
255 L16(p->rtdelay) = htons(1); 252 L16(message->rtdelay) = htons(1);
256 L16(p->rtdisp) = htons(1); 253 L16(message->rtdisp) = htons(1);
257 254
258 struct timeval t; 255 struct timeval t;
259 gettimeofday(&t, NULL); 256 gettimeofday(&t, NULL);
260 TVtoNTP64(t, p->txts); 257 TVtoNTP64(t, message->txts);
261} 258}
262 259
263/* 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.
@@ -273,14 +270,16 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
273 * 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
274 * a stratum 0 */ 271 * a stratum 0 */
275 if (slist[cserver].stratum == 0) { 272 if (slist[cserver].stratum == 0) {
276 if (verbose) 273 if (verbose) {
277 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum); 274 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
275 }
278 continue; 276 continue;
279 } 277 }
280 /* Sort out servers with error flags */ 278 /* Sort out servers with error flags */
281 if (LI(slist[cserver].flags) == LI_ALARM) { 279 if (LI(slist[cserver].flags) == LI_ALARM) {
282 if (verbose) 280 if (verbose) {
283 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags)); 281 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
282 }
284 continue; 283 continue;
285 } 284 }
286 285
@@ -322,7 +321,7 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
322 * we don't waste time sitting around waiting for single packets. 321 * we don't waste time sitting around waiting for single packets.
323 * - we also "manually" handle resolving host names and connecting, because 322 * - we also "manually" handle resolving host names and connecting, because
324 * 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 :( */
325double offset_request(const char *host, int *status) { 324double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) {
326 /* 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 */
327 struct addrinfo hints; 326 struct addrinfo hints;
328 memset(&hints, 0, sizeof(struct addrinfo)); 327 memset(&hints, 0, sizeof(struct addrinfo));
@@ -331,39 +330,43 @@ double offset_request(const char *host, int *status) {
331 hints.ai_socktype = SOCK_DGRAM; 330 hints.ai_socktype = SOCK_DGRAM;
332 331
333 /* 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 */
334 struct addrinfo *ai = NULL; 333 struct addrinfo *addresses = NULL;
335 int ga_result = getaddrinfo(host, port, &hints, &ai); 334 int ga_result = getaddrinfo(host, port, &hints, &addresses);
336 if (ga_result != 0) { 335 if (ga_result != 0) {
337 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); 336 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
338 } 337 }
339 338
340 /* count the number of returned hosts, and allocate stuff accordingly */ 339 /* count the number of returned hosts, and allocate stuff accordingly */
341 int num_hosts = 0; 340 size_t num_hosts = 0;
342 for (struct addrinfo *ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { 341 for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
343 num_hosts++; 342 num_hosts++;
344 } 343 }
345 344
346 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); 345 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
347 346
348 if (req == NULL) 347 if (req == NULL) {
349 die(STATE_UNKNOWN, "can not allocate ntp message array"); 348 die(STATE_UNKNOWN, "can not allocate ntp message array");
349 }
350 int *socklist = (int *)malloc(sizeof(int) * num_hosts); 350 int *socklist = (int *)malloc(sizeof(int) * num_hosts);
351 351
352 if (socklist == NULL) 352 if (socklist == NULL) {
353 die(STATE_UNKNOWN, "can not allocate socket array"); 353 die(STATE_UNKNOWN, "can not allocate socket array");
354 }
354 355
355 struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts); 356 struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts);
356 if (ufds == NULL) 357 if (ufds == NULL) {
357 die(STATE_UNKNOWN, "can not allocate socket array"); 358 die(STATE_UNKNOWN, "can not allocate socket array");
359 }
358 360
359 ntp_server_results *servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts); 361 ntp_server_results *servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
360 if (servers == NULL) 362 if (servers == NULL) {
361 die(STATE_UNKNOWN, "can not allocate server array"); 363 die(STATE_UNKNOWN, "can not allocate server array");
364 }
362 memset(servers, 0, sizeof(ntp_server_results) * num_hosts); 365 memset(servers, 0, sizeof(ntp_server_results) * num_hosts);
363 DBG(printf("Found %d peers to check\n", num_hosts)); 366 DBG(printf("Found %zu peers to check\n", num_hosts));
364 367
365 /* setup each socket for writing, and the corresponding struct pollfd */ 368 /* setup each socket for writing, and the corresponding struct pollfd */
366 struct addrinfo *ai_tmp = ai; 369 struct addrinfo *ai_tmp = addresses;
367 for (int i = 0; ai_tmp; i++) { 370 for (int i = 0; ai_tmp; i++) {
368 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); 371 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
369 if (socklist[i] == -1) { 372 if (socklist[i] == -1) {
@@ -389,7 +392,7 @@ double offset_request(const char *host, int *status) {
389 time_t start_ts = 0; 392 time_t start_ts = 0;
390 time_t now_time = 0; 393 time_t now_time = 0;
391 now_time = start_ts = time(NULL); 394 now_time = start_ts = time(NULL);
392 int servers_completed = 0; 395 size_t servers_completed = 0;
393 bool one_read = false; 396 bool one_read = false;
394 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) { 397 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) {
395 /* loop through each server and find each one which hasn't 398 /* loop through each server and find each one which hasn't
@@ -398,12 +401,14 @@ double offset_request(const char *host, int *status) {
398 * and update the "waiting" timestamp with the current time. */ 401 * and update the "waiting" timestamp with the current time. */
399 now_time = time(NULL); 402 now_time = time(NULL);
400 403
401 for (int i = 0; i < num_hosts; i++) { 404 for (size_t i = 0; i < num_hosts; i++) {
402 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) {
403 if (verbose && servers[i].waiting != 0) 406 if (verbose && servers[i].waiting != 0) {
404 printf("re-"); 407 printf("re-");
405 if (verbose) 408 }
406 printf("sending request to peer %d\n", i); 409 if (verbose) {
410 printf("sending request to peer %zu\n", i);
411 }
407 setup_request(&req[i]); 412 setup_request(&req[i]);
408 write(socklist[i], &req[i], sizeof(ntp_message)); 413 write(socklist[i], &req[i], sizeof(ntp_message));
409 servers[i].waiting = now_time; 414 servers[i].waiting = now_time;
@@ -419,10 +424,10 @@ double offset_request(const char *host, int *status) {
419 } 424 }
420 425
421 /* read from any sockets with pending data */ 426 /* read from any sockets with pending data */
422 for (int i = 0; servers_readable && i < num_hosts; i++) { 427 for (size_t i = 0; servers_readable && i < num_hosts; i++) {
423 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) { 428 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) {
424 if (verbose) { 429 if (verbose) {
425 printf("response from peer %d: ", i); 430 printf("response from peer %zu: ", i);
426 } 431 }
427 432
428 read(ufds[i].fd, &req[i], sizeof(ntp_message)); 433 read(ufds[i].fd, &req[i], sizeof(ntp_message));
@@ -442,14 +447,15 @@ double offset_request(const char *host, int *status) {
442 servers[i].flags = req[i].flags; 447 servers[i].flags = req[i].flags;
443 servers_readable--; 448 servers_readable--;
444 one_read = true; 449 one_read = true;
445 if (servers[i].num_responses == AVG_NUM) 450 if (servers[i].num_responses == AVG_NUM) {
446 servers_completed++; 451 servers_completed++;
452 }
447 } 453 }
448 } 454 }
449 /* lather, rinse, repeat. */ 455 /* lather, rinse, repeat. */
450 } 456 }
451 457
452 if (one_read == false) { 458 if (!one_read) {
453 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 459 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
454 } 460 }
455 461
@@ -467,21 +473,22 @@ double offset_request(const char *host, int *status) {
467 } 473 }
468 474
469 /* cleanup */ 475 /* cleanup */
470 for (int j = 0; j < num_hosts; j++) { 476 for (size_t j = 0; j < num_hosts; j++) {
471 close(socklist[j]); 477 close(socklist[j]);
472 } 478 }
473 free(socklist); 479 free(socklist);
474 free(ufds); 480 free(ufds);
475 free(servers); 481 free(servers);
476 free(req); 482 free(req);
477 freeaddrinfo(ai); 483 freeaddrinfo(addresses);
478 484
479 if (verbose) 485 if (verbose) {
480 printf("overall average offset: %.10g\n", avg_offset); 486 printf("overall average offset: %.10g\n", avg_offset);
487 }
481 return avg_offset; 488 return avg_offset;
482} 489}
483 490
484int process_arguments(int argc, char **argv) { 491check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
485 static struct option longopts[] = {{"version", no_argument, 0, 'V'}, 492 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
486 {"help", no_argument, 0, 'h'}, 493 {"help", no_argument, 0, 'h'},
487 {"verbose", no_argument, 0, 'v'}, 494 {"verbose", no_argument, 0, 'v'},
@@ -496,14 +503,24 @@ int process_arguments(int argc, char **argv) {
496 {"port", required_argument, 0, 'p'}, 503 {"port", required_argument, 0, 'p'},
497 {0, 0, 0, 0}}; 504 {0, 0, 0, 0}};
498 505
499 if (argc < 2) 506 if (argc < 2) {
500 usage("\n"); 507 usage("\n");
508 }
509
510 check_ntp_time_config_wrapper result = {
511 .errorcode = OK,
512 .config = check_ntp_time_config_init(),
513 };
514
515 char *owarn = "60";
516 char *ocrit = "120";
501 517
502 while (true) { 518 while (true) {
503 int option = 0; 519 int option = 0;
504 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); 520 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
505 if (option_char == -1 || option_char == EOF || option_char == 1) 521 if (option_char == -1 || option_char == EOF || option_char == 1) {
506 break; 522 break;
523 }
507 524
508 switch (option_char) { 525 switch (option_char) {
509 case 'h': 526 case 'h':
@@ -518,7 +535,7 @@ int process_arguments(int argc, char **argv) {
518 verbose++; 535 verbose++;
519 break; 536 break;
520 case 'q': 537 case 'q':
521 quiet = true; 538 result.config.quiet = true;
522 break; 539 break;
523 case 'w': 540 case 'w':
524 owarn = optarg; 541 owarn = optarg;
@@ -527,18 +544,19 @@ int process_arguments(int argc, char **argv) {
527 ocrit = optarg; 544 ocrit = optarg;
528 break; 545 break;
529 case 'H': 546 case 'H':
530 if (!is_host(optarg)) 547 if (!is_host(optarg)) {
531 usage2(_("Invalid hostname/address"), optarg); 548 usage2(_("Invalid hostname/address"), optarg);
532 server_address = strdup(optarg); 549 }
550 result.config.server_address = strdup(optarg);
533 break; 551 break;
534 case 'p': 552 case 'p':
535 port = strdup(optarg); 553 result.config.port = strdup(optarg);
536 break; 554 break;
537 case 't': 555 case 't':
538 socket_timeout = atoi(optarg); 556 socket_timeout = atoi(optarg);
539 break; 557 break;
540 case 'o': 558 case 'o':
541 time_offset = atoi(optarg); 559 result.config.time_offset = atoi(optarg);
542 break; 560 break;
543 case '4': 561 case '4':
544 address_family = AF_INET; 562 address_family = AF_INET;
@@ -557,14 +575,16 @@ int process_arguments(int argc, char **argv) {
557 } 575 }
558 } 576 }
559 577
560 if (server_address == NULL) { 578 if (result.config.server_address == NULL) {
561 usage4(_("Hostname was not supplied")); 579 usage4(_("Hostname was not supplied"));
562 } 580 }
563 581
564 return 0; 582 set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
583
584 return result;
565} 585}
566 586
567char *perfd_offset(double offset) { 587char *perfd_offset(double offset, thresholds *offset_thresholds) {
568 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false, 588 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, offset_thresholds->critical->end, false, 0, false,
569 0); 589 0);
570} 590}
@@ -577,10 +597,13 @@ int main(int argc, char *argv[]) {
577 /* Parse extra opts if any */ 597 /* Parse extra opts if any */
578 argv = np_extra_opts(&argc, argv, progname); 598 argv = np_extra_opts(&argc, argv, progname);
579 599
580 if (process_arguments(argc, argv) == ERROR) 600 check_ntp_time_config_wrapper tmp_config = process_arguments(argc, argv);
601
602 if (tmp_config.errorcode == ERROR) {
581 usage4(_("Could not parse arguments")); 603 usage4(_("Could not parse arguments"));
604 }
582 605
583 set_thresholds(&offset_thresholds, owarn, ocrit); 606 const check_ntp_time_config config = tmp_config.config;
584 607
585 /* initialize alarm signal handling */ 608 /* initialize alarm signal handling */
586 signal(SIGALRM, socket_timeout_alarm_handler); 609 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -588,13 +611,13 @@ int main(int argc, char *argv[]) {
588 /* set socket timeout */ 611 /* set socket timeout */
589 alarm(socket_timeout); 612 alarm(socket_timeout);
590 613
591 int offset_result = STATE_OK; 614 mp_state_enum offset_result = STATE_OK;
592 int result = STATE_OK; 615 mp_state_enum result = STATE_OK;
593 double offset = offset_request(server_address, &offset_result); 616 double offset = offset_request(config.server_address, config.port, &offset_result, config.time_offset);
594 if (offset_result == STATE_UNKNOWN) { 617 if (offset_result == STATE_UNKNOWN) {
595 result = ((!quiet) ? STATE_UNKNOWN : STATE_CRITICAL); 618 result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
596 } else { 619 } else {
597 result = get_status(fabs(offset), offset_thresholds); 620 result = get_status(fabs(offset), config.offset_thresholds);
598 } 621 }
599 622
600 char *result_line; 623 char *result_line;
@@ -619,13 +642,14 @@ int main(int argc, char *argv[]) {
619 xasprintf(&perfdata_line, ""); 642 xasprintf(&perfdata_line, "");
620 } else { 643 } else {
621 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 644 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
622 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 645 xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
623 } 646 }
624 printf("%s|%s\n", result_line, perfdata_line); 647 printf("%s|%s\n", result_line, perfdata_line);
625 648
626 if (server_address != NULL) 649 if (config.server_address != NULL) {
627 free(server_address); 650 free(config.server_address);
628 return result; 651 }
652 exit(result);
629} 653}
630 654
631void print_help(void) { 655void print_help(void) {
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_overcr.c b/plugins/check_overcr.c
deleted file mode 100644
index 599540b7..00000000
--- a/plugins/check_overcr.c
+++ /dev/null
@@ -1,417 +0,0 @@
1/*****************************************************************************
2 *
3 * Monitoring check_overcr plugin
4 *
5 * License: GPL
6 * Copyright (c) 2000-2024 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-2024";
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
55static char *server_address = NULL;
56static int server_port = PORT;
57static double warning_value = 0L;
58static double critical_value = 0L;
59static bool check_warning_value = false;
60static bool check_critical_value = false;
61static enum checkvar vars_to_check = NONE;
62
63static int netstat_port = 0;
64static char *disk_name = NULL;
65static char *process_name = NULL;
66static char send_buffer[MAX_INPUT_BUFFER];
67
68static int process_arguments(int, char **);
69void print_usage(void);
70static void print_help(void);
71
72int main(int argc, char **argv) {
73 int result = STATE_UNKNOWN;
74 char recv_buffer[MAX_INPUT_BUFFER];
75 char temp_buffer[MAX_INPUT_BUFFER];
76 char *temp_ptr = NULL;
77 bool found_disk = false;
78 unsigned long percent_used_disk_space = 100;
79 double load;
80 double load_1min;
81 double load_5min;
82 double load_15min;
83 int port_connections = 0;
84 int processes = 0;
85 double uptime_raw_hours;
86 int uptime_raw_minutes = 0;
87 int uptime_days = 0;
88 int uptime_hours = 0;
89 int uptime_minutes = 0;
90
91 setlocale(LC_ALL, "");
92 bindtextdomain(PACKAGE, LOCALEDIR);
93 textdomain(PACKAGE);
94
95 /* Parse extra opts if any */
96 argv = np_extra_opts(&argc, argv, progname);
97
98 if (process_arguments(argc, argv) == ERROR)
99 usage4(_("Could not parse arguments"));
100
101 /* initialize alarm signal handling */
102 signal(SIGALRM, socket_timeout_alarm_handler);
103
104 /* set socket timeout */
105 alarm(socket_timeout);
106
107 result = process_tcp_request2(server_address, server_port, send_buffer, recv_buffer, sizeof(recv_buffer));
108
109 switch (vars_to_check) {
110
111 case LOAD1:
112 case LOAD5:
113 case LOAD15:
114
115 if (result != STATE_OK)
116 die(result, _("Unknown error fetching load data\n"));
117
118 temp_ptr = (char *)strtok(recv_buffer, "\r\n");
119 if (temp_ptr == NULL)
120 die(STATE_CRITICAL, _("Invalid response from server - no load information\n"));
121 else
122 load_1min = strtod(temp_ptr, NULL);
123
124 temp_ptr = (char *)strtok(NULL, "\r\n");
125 if (temp_ptr == NULL)
126 die(STATE_CRITICAL, _("Invalid response from server after load 1\n"));
127 else
128 load_5min = strtod(temp_ptr, NULL);
129
130 temp_ptr = (char *)strtok(NULL, "\r\n");
131 if (temp_ptr == NULL)
132 die(STATE_CRITICAL, _("Invalid response from server after load 5\n"));
133 else
134 load_15min = strtod(temp_ptr, NULL);
135
136 switch (vars_to_check) {
137 case LOAD1:
138 strcpy(temp_buffer, "1");
139 load = load_1min;
140 break;
141 case LOAD5:
142 strcpy(temp_buffer, "5");
143 load = load_5min;
144 break;
145 default:
146 strcpy(temp_buffer, "15");
147 load = load_15min;
148 break;
149 }
150
151 if (check_critical_value && (load >= critical_value))
152 result = STATE_CRITICAL;
153 else if (check_warning_value && (load >= warning_value))
154 result = STATE_WARNING;
155
156 die(result, _("Load %s - %s-min load average = %0.2f"), state_text(result), temp_buffer, load);
157
158 break;
159
160 case DPU:
161
162 if (result != STATE_OK)
163 die(result, _("Unknown error fetching disk data\n"));
164
165 for (temp_ptr = (char *)strtok(recv_buffer, " "); temp_ptr != NULL; temp_ptr = (char *)strtok(NULL, " ")) {
166
167 if (!strcmp(temp_ptr, disk_name)) {
168 found_disk = true;
169 temp_ptr = (char *)strtok(NULL, "%");
170 if (temp_ptr == NULL)
171 die(STATE_CRITICAL, _("Invalid response from server\n"));
172 else
173 percent_used_disk_space = strtoul(temp_ptr, NULL, 10);
174 break;
175 }
176
177 temp_ptr = (char *)strtok(NULL, "\r\n");
178 }
179
180 /* error if we couldn't find the info for the disk */
181 if (!found_disk)
182 die(STATE_CRITICAL, "CRITICAL - Disk '%s' non-existent or not mounted", disk_name);
183
184 if (check_critical_value && (percent_used_disk_space >= critical_value))
185 result = STATE_CRITICAL;
186 else if (check_warning_value && (percent_used_disk_space >= warning_value))
187 result = STATE_WARNING;
188
189 die(result, "Disk %s - %lu%% used on %s", state_text(result), percent_used_disk_space, disk_name);
190
191 break;
192
193 case NETSTAT:
194
195 if (result != STATE_OK)
196 die(result, _("Unknown error fetching network status\n"));
197 else
198 port_connections = strtod(recv_buffer, NULL);
199
200 if (check_critical_value && (port_connections >= critical_value))
201 result = STATE_CRITICAL;
202 else if (check_warning_value && (port_connections >= warning_value))
203 result = STATE_WARNING;
204
205 die(result, _("Net %s - %d connection%s on port %d"), state_text(result), port_connections, (port_connections == 1) ? "" : "s",
206 netstat_port);
207
208 break;
209
210 case PROCS:
211
212 if (result != STATE_OK)
213 die(result, _("Unknown error fetching process status\n"));
214
215 temp_ptr = (char *)strtok(recv_buffer, "(");
216 if (temp_ptr == NULL)
217 die(STATE_CRITICAL, _("Invalid response from server\n"));
218
219 temp_ptr = (char *)strtok(NULL, ")");
220 if (temp_ptr == NULL)
221 die(STATE_CRITICAL, _("Invalid response from server\n"));
222 else
223 processes = strtod(temp_ptr, NULL);
224
225 if (check_critical_value && (processes >= critical_value))
226 result = STATE_CRITICAL;
227 else if (check_warning_value && (processes >= warning_value))
228 result = STATE_WARNING;
229
230 die(result, _("Process %s - %d instance%s of %s running"), state_text(result), processes, (processes == 1) ? "" : "s",
231 process_name);
232 break;
233
234 case UPTIME:
235
236 if (result != STATE_OK)
237 return result;
238
239 uptime_raw_hours = strtod(recv_buffer, NULL);
240 uptime_raw_minutes = (unsigned long)(uptime_raw_hours * 60.0);
241
242 if (check_critical_value && (uptime_raw_minutes <= critical_value))
243 result = STATE_CRITICAL;
244 else if (check_warning_value && (uptime_raw_minutes <= warning_value))
245 result = STATE_WARNING;
246
247 uptime_days = uptime_raw_minutes / 1440;
248 uptime_raw_minutes %= 1440;
249 uptime_hours = uptime_raw_minutes / 60;
250 uptime_raw_minutes %= 60;
251 uptime_minutes = uptime_raw_minutes;
252
253 die(result, _("Uptime %s - Up %d days %d hours %d minutes"), state_text(result), uptime_days, uptime_hours, uptime_minutes);
254 break;
255
256 default:
257 die(STATE_UNKNOWN, _("Nothing to check!\n"));
258 break;
259 }
260}
261
262/* process command-line arguments */
263int process_arguments(int argc, char **argv) {
264 int c;
265
266 int option = 0;
267 static struct option longopts[] = {
268 {"port", required_argument, 0, 'p'}, {"timeout", required_argument, 0, 't'}, {"critical", required_argument, 0, 'c'},
269 {"warning", required_argument, 0, 'w'}, {"variable", required_argument, 0, 'v'}, {"hostname", required_argument, 0, 'H'},
270 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
271
272 /* no options were supplied */
273 if (argc < 2)
274 return ERROR;
275
276 /* backwards compatibility */
277 if (!is_option(argv[1])) {
278 server_address = argv[1];
279 argv[1] = argv[0];
280 argv = &argv[1];
281 argc--;
282 }
283
284 for (c = 1; c < argc; c++) {
285 if (strcmp("-to", argv[c]) == 0)
286 strcpy(argv[c], "-t");
287 else if (strcmp("-wv", argv[c]) == 0)
288 strcpy(argv[c], "-w");
289 else if (strcmp("-cv", argv[c]) == 0)
290 strcpy(argv[c], "-c");
291 }
292
293 while (1) {
294 c = getopt_long(argc, argv, "+hVH:t:c:w:p:v:", longopts, &option);
295
296 if (c == -1 || c == EOF || c == 1)
297 break;
298
299 switch (c) {
300 case '?': /* print short usage statement if args not parsable */
301 usage5();
302 case 'h': /* help */
303 print_help();
304 exit(STATE_UNKNOWN);
305 case 'V': /* version */
306 print_revision(progname, NP_VERSION);
307 exit(STATE_UNKNOWN);
308 case 'H': /* hostname */
309 server_address = optarg;
310 break;
311 case 'p': /* port */
312 if (is_intnonneg(optarg))
313 server_port = atoi(optarg);
314 else
315 die(STATE_UNKNOWN, _("Server port an integer\n"));
316 break;
317 case 'v': /* variable */
318 if (strcmp(optarg, "LOAD") == 0) {
319 strcpy(send_buffer, "LOAD\r\nQUIT\r\n");
320 if (strcmp(optarg, "LOAD1") == 0)
321 vars_to_check = LOAD1;
322 else if (strcmp(optarg, "LOAD5") == 0)
323 vars_to_check = LOAD5;
324 else if (strcmp(optarg, "LOAD15") == 0)
325 vars_to_check = LOAD15;
326 } else if (strcmp(optarg, "UPTIME") == 0) {
327 vars_to_check = UPTIME;
328 strcpy(send_buffer, "UPTIME\r\n");
329 } else if (strstr(optarg, "PROC") == optarg) {
330 vars_to_check = PROCS;
331 process_name = strscpy(process_name, optarg + 4);
332 sprintf(send_buffer, "PROCESS %s\r\n", process_name);
333 } else if (strstr(optarg, "NET") == optarg) {
334 vars_to_check = NETSTAT;
335 netstat_port = atoi(optarg + 3);
336 sprintf(send_buffer, "NETSTAT %d\r\n", netstat_port);
337 } else if (strstr(optarg, "DPU") == optarg) {
338 vars_to_check = DPU;
339 strcpy(send_buffer, "DISKSPACE\r\n");
340 disk_name = strscpy(disk_name, optarg + 3);
341 } else
342 return ERROR;
343 break;
344 case 'w': /* warning threshold */
345 warning_value = strtoul(optarg, NULL, 10);
346 check_warning_value = true;
347 break;
348 case 'c': /* critical threshold */
349 critical_value = strtoul(optarg, NULL, 10);
350 check_critical_value = true;
351 break;
352 case 't': /* timeout */
353 socket_timeout = atoi(optarg);
354 if (socket_timeout <= 0)
355 return ERROR;
356 }
357 }
358 return OK;
359}
360
361void print_help(void) {
362 char *myport;
363 xasprintf(&myport, "%d", PORT);
364
365 print_revision(progname, NP_VERSION);
366
367 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
368 printf(COPYRIGHT, copyright, email);
369
370 printf("%s\n", _("This plugin attempts to contact the Over-CR collector daemon running on the"));
371 printf("%s\n", _("remote UNIX server in order to gather the requested system information."));
372
373 printf("\n\n");
374
375 print_usage();
376
377 printf(UT_HELP_VRSN);
378 printf(UT_EXTRA_OPTS);
379
380 printf(UT_HOST_PORT, 'p', myport);
381
382 printf(" %s\n", "-w, --warning=INTEGER");
383 printf(" %s\n", _("Threshold which will result in a warning status"));
384 printf(" %s\n", "-c, --critical=INTEGER");
385 printf(" %s\n", _("Threshold which will result in a critical status"));
386 printf(" %s\n", "-v, --variable=STRING");
387 printf(" %s\n", _("Variable to check. Valid variables include:"));
388 printf(" %s\n", _("LOAD1 = 1 minute average CPU load"));
389 printf(" %s\n", _("LOAD5 = 5 minute average CPU load"));
390 printf(" %s\n", _("LOAD15 = 15 minute average CPU load"));
391 printf(" %s\n", _("DPU<filesys> = percent used disk space on filesystem <filesys>"));
392 printf(" %s\n", _("PROC<process> = number of running processes with name <process>"));
393 printf(" %s\n", _("NET<port> = number of active connections on TCP port <port>"));
394 printf(" %s\n", _("UPTIME = system uptime in seconds"));
395
396 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
397
398 printf(UT_VERBOSE);
399
400 printf("\n");
401 printf("%s\n", _("This plugin requires that Eric Molitors' Over-CR collector daemon be"));
402 printf("%s\n", _("running on the remote server."));
403 printf("%s\n", _("Over-CR can be downloaded from http://www.molitor.org/overcr"));
404 printf("%s\n", _("This plugin was tested with version 0.99.53 of the Over-CR collector"));
405
406 printf("\n");
407 printf("%s\n", _("Notes:"));
408 printf(" %s\n", _("For the available options, the critical threshold value should always be"));
409 printf(" %s\n", _("higher than the warning threshold value, EXCEPT with the uptime variable"));
410
411 printf(UT_SUPPORT);
412}
413
414void print_usage(void) {
415 printf("%s\n", _("Usage:"));
416 printf("%s -H host [-p port] [-v variable] [-w warning] [-c critical] [-t timeout]\n", progname);
417}
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
index 6613634d..84305adb 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -28,6 +28,7 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
31const char *progname = "check_pgsql"; 32const char *progname = "check_pgsql";
32const char *copyright = "1999-2024"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
@@ -35,12 +36,13 @@ const char *email = "devel@monitoring-plugins.org";
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 */
@@ -53,33 +55,18 @@ const char *email = "devel@monitoring-plugins.org";
53#define PSQL_SOCKET3(host, port) \ 55#define PSQL_SOCKET3(host, port) \
54 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port 56 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port
55 57
56enum { 58typedef struct {
57 DEFAULT_PORT = 5432, 59 int errorcode;
58 DEFAULT_WARN = 2, 60 check_pgsql_config config;
59 DEFAULT_CRIT = 8 61} check_pgsql_config_wrapper;
60}; 62static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
61 63
62static int process_arguments(int /*argc*/, char ** /*argv*/);
63static void print_help(void); 64static void print_help(void);
64static bool is_pg_logname(char * /*username*/); 65static bool is_pg_logname(char * /*username*/);
65static int do_query(PGconn * /*conn*/, char * /*query*/); 66static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[], thresholds * /*qthresholds*/,
67 char * /*query_warning*/, char * /*query_critical*/);
66void print_usage(void); 68void print_usage(void);
67 69
68static char *pghost = NULL; /* host name of the backend server */
69static char *pgport = NULL; /* port of the backend server */
70static char *pgoptions = NULL;
71static char *pgtty = NULL;
72static char dbName[NAMEDATALEN] = DEFAULT_DB;
73static char *pguser = NULL;
74static char *pgpasswd = NULL;
75static char *pgparams = NULL;
76static double twarn = (double)DEFAULT_WARN;
77static double tcrit = (double)DEFAULT_CRIT;
78static char *pgquery = NULL;
79static char *pgqueryname = NULL;
80static char *query_warning = NULL;
81static char *query_critical = NULL;
82static thresholds *qthresholds = NULL;
83static int verbose = 0; 70static int verbose = 0;
84 71
85#define OPTID_QUERYNAME -1000 72#define OPTID_QUERYNAME -1000
@@ -139,21 +126,19 @@ int main(int argc, char **argv) {
139 bindtextdomain(PACKAGE, LOCALEDIR); 126 bindtextdomain(PACKAGE, LOCALEDIR);
140 textdomain(PACKAGE); 127 textdomain(PACKAGE);
141 128
142 /* begin, by setting the parameters for a backend connection if the
143 * parameters are null, then the system will try to use reasonable
144 * defaults by looking up environment variables or, failing that,
145 * using hardwired constants */
146
147 pgoptions = NULL; /* special options to start up the backend server */
148 pgtty = NULL; /* debugging tty for the backend server */
149
150 /* Parse extra opts if any */ 129 /* Parse extra opts if any */
151 argv = np_extra_opts(&argc, argv, progname); 130 argv = np_extra_opts(&argc, argv, progname);
152 131
153 if (process_arguments(argc, argv) == ERROR) 132 check_pgsql_config_wrapper tmp_config = process_arguments(argc, argv);
133 if (tmp_config.errorcode == ERROR) {
154 usage4(_("Could not parse arguments")); 134 usage4(_("Could not parse arguments"));
155 if (verbose > 2) 135 }
136
137 const check_pgsql_config config = tmp_config.config;
138
139 if (verbose > 2) {
156 printf("Arguments initialized\n"); 140 printf("Arguments initialized\n");
141 }
157 142
158 /* Set signal handling and alarm */ 143 /* Set signal handling and alarm */
159 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 144 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
@@ -162,25 +147,32 @@ int main(int argc, char **argv) {
162 alarm(timeout_interval); 147 alarm(timeout_interval);
163 148
164 char *conninfo = NULL; 149 char *conninfo = NULL;
165 if (pgparams) 150 if (config.pgparams) {
166 asprintf(&conninfo, "%s ", pgparams); 151 asprintf(&conninfo, "%s ", config.pgparams);
167 152 }
168 asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", dbName); 153
169 if (pghost) 154 asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", config.dbName);
170 asprintf(&conninfo, "%s host = '%s'", conninfo, pghost); 155 if (config.pghost) {
171 if (pgport) 156 asprintf(&conninfo, "%s host = '%s'", conninfo, config.pghost);
172 asprintf(&conninfo, "%s port = '%s'", conninfo, pgport); 157 }
173 if (pgoptions) 158 if (config.pgport) {
174 asprintf(&conninfo, "%s options = '%s'", conninfo, pgoptions); 159 asprintf(&conninfo, "%s port = '%s'", conninfo, config.pgport);
160 }
161 if (config.pgoptions) {
162 asprintf(&conninfo, "%s options = '%s'", conninfo, config.pgoptions);
163 }
175 /* if (pgtty) -- ignored by PQconnectdb */ 164 /* if (pgtty) -- ignored by PQconnectdb */
176 if (pguser) 165 if (config.pguser) {
177 asprintf(&conninfo, "%s user = '%s'", conninfo, pguser); 166 asprintf(&conninfo, "%s user = '%s'", conninfo, config.pguser);
167 }
178 168
179 if (verbose) /* do not include password (see right below) in output */ 169 if (verbose) { /* do not include password (see right below) in output */
180 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, pgpasswd ? " password = <hidden>" : ""); 170 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, config.pgpasswd ? " password = <hidden>" : "");
171 }
181 172
182 if (pgpasswd) 173 if (config.pgpasswd) {
183 asprintf(&conninfo, "%s password = '%s'", conninfo, pgpasswd); 174 asprintf(&conninfo, "%s password = '%s'", conninfo, config.pgpasswd);
175 }
184 176
185 /* make a connection to the database */ 177 /* make a connection to the database */
186 struct timeval start_timeval; 178 struct timeval start_timeval;
@@ -194,24 +186,26 @@ int main(int argc, char **argv) {
194 end_timeval.tv_usec += 1000000; 186 end_timeval.tv_usec += 1000000;
195 } 187 }
196 double elapsed_time = 188 double elapsed_time =
197 (double)(end_timeval.tv_sec - start_timeval.tv_sec) + (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);
198 190
199 if (verbose) 191 if (verbose) {
200 printf("Time elapsed: %f\n", elapsed_time); 192 printf("Time elapsed: %f\n", elapsed_time);
193 }
201 194
202 /* check to see that the backend connection was successfully made */ 195 /* check to see that the backend connection was successfully made */
203 if (verbose) 196 if (verbose) {
204 printf("Verifying connection\n"); 197 printf("Verifying connection\n");
198 }
205 if (PQstatus(conn) == CONNECTION_BAD) { 199 if (PQstatus(conn) == CONNECTION_BAD) {
206 printf(_("CRITICAL - no connection to '%s' (%s).\n"), dbName, PQerrorMessage(conn)); 200 printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn));
207 PQfinish(conn); 201 PQfinish(conn);
208 return STATE_CRITICAL; 202 return STATE_CRITICAL;
209 } 203 }
210 204
211 int status = STATE_UNKNOWN; 205 mp_state_enum status = STATE_UNKNOWN;
212 if (elapsed_time > tcrit) { 206 if (elapsed_time > config.tcrit) {
213 status = STATE_CRITICAL; 207 status = STATE_CRITICAL;
214 } else if (elapsed_time > twarn) { 208 } else if (elapsed_time > config.twarn) {
215 status = STATE_WARNING; 209 status = STATE_WARNING;
216 } else { 210 } else {
217 status = STATE_OK; 211 status = STATE_OK;
@@ -228,21 +222,23 @@ int main(int argc, char **argv) {
228 PQprotocolVersion(conn), PQbackendPID(conn)); 222 PQprotocolVersion(conn), PQbackendPID(conn));
229 } 223 }
230 224
231 printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), dbName, elapsed_time, 225 printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time,
232 fperfdata("time", elapsed_time, "s", !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, true, 0, false, 0)); 226 fperfdata("time", elapsed_time, "s", (config.twarn > 0.0), config.twarn, (config.tcrit > 0.0), config.tcrit, true, 0, false, 0));
233 227
234 int query_status = STATE_UNKNOWN; 228 mp_state_enum query_status = STATE_UNKNOWN;
235 if (pgquery) 229 if (config.pgquery) {
236 query_status = do_query(conn, pgquery); 230 query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds, config.query_warning, config.query_critical);
231 }
237 232
238 if (verbose) 233 if (verbose) {
239 printf("Closing connection\n"); 234 printf("Closing connection\n");
235 }
240 PQfinish(conn); 236 PQfinish(conn);
241 return (pgquery && query_status > status) ? query_status : status; 237 return (config.pgquery && query_status > status) ? query_status : status;
242} 238}
243 239
244/* process command-line arguments */ 240/* process command-line arguments */
245int process_arguments(int argc, char **argv) { 241check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
246 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, 242 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
247 {"version", no_argument, 0, 'V'}, 243 {"version", no_argument, 0, 'V'},
248 {"timeout", required_argument, 0, 't'}, 244 {"timeout", required_argument, 0, 't'},
@@ -262,12 +258,18 @@ int process_arguments(int argc, char **argv) {
262 {"verbose", no_argument, 0, 'v'}, 258 {"verbose", no_argument, 0, 'v'},
263 {0, 0, 0, 0}}; 259 {0, 0, 0, 0}};
264 260
261 check_pgsql_config_wrapper result = {
262 .errorcode = OK,
263 .config = check_pgsql_config_init(),
264 };
265
265 while (true) { 266 while (true) {
266 int option = 0; 267 int option = 0;
267 int option_char = getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", 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);
268 269
269 if (option_char == EOF) 270 if (option_char == EOF) {
270 break; 271 break;
272 }
271 273
272 switch (option_char) { 274 switch (option_char) {
273 case '?': /* usage */ 275 case '?': /* usage */
@@ -279,68 +281,75 @@ int process_arguments(int argc, char **argv) {
279 print_revision(progname, NP_VERSION); 281 print_revision(progname, NP_VERSION);
280 exit(STATE_UNKNOWN); 282 exit(STATE_UNKNOWN);
281 case 't': /* timeout period */ 283 case 't': /* timeout period */
282 if (!is_integer(optarg)) 284 if (!is_integer(optarg)) {
283 usage2(_("Timeout interval must be a positive integer"), optarg); 285 usage2(_("Timeout interval must be a positive integer"), optarg);
284 else 286 } else {
285 timeout_interval = atoi(optarg); 287 timeout_interval = atoi(optarg);
288 }
286 break; 289 break;
287 case 'c': /* critical time threshold */ 290 case 'c': /* critical time threshold */
288 if (!is_nonnegative(optarg)) 291 if (!is_nonnegative(optarg)) {
289 usage2(_("Critical threshold must be a positive integer"), optarg); 292 usage2(_("Critical threshold must be a positive integer"), optarg);
290 else 293 } else {
291 tcrit = strtod(optarg, NULL); 294 result.config.tcrit = strtod(optarg, NULL);
295 }
292 break; 296 break;
293 case 'w': /* warning time threshold */ 297 case 'w': /* warning time threshold */
294 if (!is_nonnegative(optarg)) 298 if (!is_nonnegative(optarg)) {
295 usage2(_("Warning threshold must be a positive integer"), optarg); 299 usage2(_("Warning threshold must be a positive integer"), optarg);
296 else 300 } else {
297 twarn = strtod(optarg, NULL); 301 result.config.twarn = strtod(optarg, NULL);
302 }
298 break; 303 break;
299 case 'C': /* critical query threshold */ 304 case 'C': /* critical query threshold */
300 query_critical = optarg; 305 result.config.query_critical = optarg;
301 break; 306 break;
302 case 'W': /* warning query threshold */ 307 case 'W': /* warning query threshold */
303 query_warning = optarg; 308 result.config.query_warning = optarg;
304 break; 309 break;
305 case 'H': /* host */ 310 case 'H': /* host */
306 if ((*optarg != '/') && (!is_host(optarg))) 311 if ((*optarg != '/') && (!is_host(optarg))) {
307 usage2(_("Invalid hostname/address"), optarg); 312 usage2(_("Invalid hostname/address"), optarg);
308 else 313 } else {
309 pghost = optarg; 314 result.config.pghost = optarg;
315 }
310 break; 316 break;
311 case 'P': /* port */ 317 case 'P': /* port */
312 if (!is_integer(optarg)) 318 if (!is_integer(optarg)) {
313 usage2(_("Port must be a positive integer"), optarg); 319 usage2(_("Port must be a positive integer"), optarg);
314 else 320 } else {
315 pgport = optarg; 321 result.config.pgport = optarg;
322 }
316 break; 323 break;
317 case 'd': /* database name */ 324 case 'd': /* database name */
318 if (strlen(optarg) >= NAMEDATALEN) { 325 if (strlen(optarg) >= NAMEDATALEN) {
319 usage2(_("Database name exceeds the maximum length"), optarg); 326 usage2(_("Database name exceeds the maximum length"), optarg);
320 } 327 }
321 snprintf(dbName, NAMEDATALEN, "%s", optarg); 328 snprintf(result.config.dbName, NAMEDATALEN, "%s", optarg);
322 break; 329 break;
323 case 'l': /* login name */ 330 case 'l': /* login name */
324 if (!is_pg_logname(optarg)) 331 if (!is_pg_logname(optarg)) {
325 usage2(_("User name is not valid"), optarg); 332 usage2(_("User name is not valid"), optarg);
326 else 333 } else {
327 pguser = optarg; 334 result.config.pguser = optarg;
335 }
328 break; 336 break;
329 case 'p': /* authentication password */ 337 case 'p': /* authentication password */
330 case 'a': 338 case 'a':
331 pgpasswd = optarg; 339 result.config.pgpasswd = optarg;
332 break; 340 break;
333 case 'o': 341 case 'o':
334 if (pgparams) 342 if (result.config.pgparams) {
335 asprintf(&pgparams, "%s %s", pgparams, optarg); 343 asprintf(&result.config.pgparams, "%s %s", result.config.pgparams, optarg);
336 else 344 } else {
337 asprintf(&pgparams, "%s", optarg); 345 asprintf(&result.config.pgparams, "%s", optarg);
346 }
338 break; 347 break;
339 case 'q': 348 case 'q':
340 pgquery = optarg; 349 result.config.pgquery = optarg;
341 break; 350 break;
342 case OPTID_QUERYNAME: 351 case OPTID_QUERYNAME:
343 pgqueryname = optarg; 352 result.config.pgqueryname = optarg;
344 break; 353 break;
345 case 'v': 354 case 'v':
346 verbose++; 355 verbose++;
@@ -348,9 +357,9 @@ int process_arguments(int argc, char **argv) {
348 } 357 }
349 } 358 }
350 359
351 set_thresholds(&qthresholds, query_warning, query_critical); 360 set_thresholds(&result.config.qthresholds, result.config.query_warning, result.config.query_critical);
352 361
353 return OK; 362 return result;
354} 363}
355 364
356/** 365/**
@@ -378,8 +387,9 @@ should be added.</para>
378******************************************************************************/ 387******************************************************************************/
379 388
380bool is_pg_logname(char *username) { 389bool is_pg_logname(char *username) {
381 if (strlen(username) > NAMEDATALEN - 1) 390 if (strlen(username) > NAMEDATALEN - 1) {
382 return (false); 391 return (false);
392 }
383 return (true); 393 return (true);
384} 394}
385 395
@@ -394,7 +404,7 @@ bool is_pg_logname(char *username) {
394void print_help(void) { 404void print_help(void) {
395 char *myport; 405 char *myport;
396 406
397 xasprintf(&myport, "%d", DEFAULT_PORT); 407 xasprintf(&myport, "%d", 5432);
398 408
399 print_revision(progname, NP_VERSION); 409 print_revision(progname, NP_VERSION);
400 410
@@ -482,9 +492,11 @@ void print_usage(void) {
482 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n"); 492 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
483} 493}
484 494
485int do_query(PGconn *conn, char *query) { 495mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds, char *query_warning,
486 if (verbose) 496 char *query_critical) {
497 if (verbose) {
487 printf("Executing SQL query \"%s\".\n", query); 498 printf("Executing SQL query \"%s\".\n", query);
499 }
488 PGresult *res = PQexec(conn, query); 500 PGresult *res = PQexec(conn, query);
489 501
490 if (PGRES_TUPLES_OK != PQresultStatus(res)) { 502 if (PGRES_TUPLES_OK != PQresultStatus(res)) {
@@ -510,8 +522,9 @@ int do_query(PGconn *conn, char *query) {
510 522
511 char *endptr = NULL; 523 char *endptr = NULL;
512 double value = strtod(val_str, &endptr); 524 double value = strtod(val_str, &endptr);
513 if (verbose) 525 if (verbose) {
514 printf("Query result: %f\n", value); 526 printf("Query result: %f\n", value);
527 }
515 528
516 if (endptr == val_str) { 529 if (endptr == val_str) {
517 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);
@@ -519,11 +532,12 @@ int do_query(PGconn *conn, char *query) {
519 } 532 }
520 533
521 if ((endptr != NULL) && (*endptr != '\0')) { 534 if ((endptr != NULL) && (*endptr != '\0')) {
522 if (verbose) 535 if (verbose) {
523 printf("Garbage after value: %s.\n", endptr); 536 printf("Garbage after value: %s.\n", endptr);
537 }
524 } 538 }
525 539
526 int my_status = get_status(value, qthresholds); 540 mp_state_enum my_status = get_status(value, qthresholds);
527 printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK") 541 printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK")
528 : (my_status == STATE_WARNING) ? _("WARNING") 542 : (my_status == STATE_WARNING) ? _("WARNING")
529 : (my_status == STATE_CRITICAL) ? _("CRITICAL") 543 : (my_status == STATE_CRITICAL) ? _("CRITICAL")
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 4aafaf41..940b9475 100644
--- a/plugins/check_ping.c
+++ b/plugins/check_ping.c
@@ -36,61 +36,52 @@ const char *email = "devel@monitoring-plugins.org";
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 45
45enum { 46typedef struct {
46 UNKNOWN_PACKET_LOSS = 200, /* 200% */ 47 int errorcode;
47 DEFAULT_MAX_PACKETS = 5 /* default no. of ICMP ECHO packets */ 48 check_ping_config config;
48}; 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*/);
49 52
50static int process_arguments(int /*argc*/, char ** /*argv*/); 53static int get_threshold(char * /*arg*/, double * /*trta*/, int * /*tpl*/);
51static int get_threshold(char * /*arg*/, float * /*trta*/, int * /*tpl*/); 54
52static int validate_arguments(void); 55typedef struct {
53static int run_ping(const char *cmd, const char *addr); 56 mp_state_enum state;
54static int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr); 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);
55static void print_help(void); 63static void print_help(void);
56void print_usage(void); 64void print_usage(void);
57 65
58static bool display_html = false;
59static int wpl = UNKNOWN_PACKET_LOSS;
60static int cpl = UNKNOWN_PACKET_LOSS;
61static float wrta = UNKNOWN_TRIP_TIME;
62static float crta = UNKNOWN_TRIP_TIME;
63static char **addresses = NULL;
64static int n_addresses = 0;
65static int max_addr = 1;
66static int max_packets = -1;
67static int verbose = 0; 66static int verbose = 0;
68 67
69static float rta = UNKNOWN_TRIP_TIME;
70static int pl = UNKNOWN_PACKET_LOSS;
71
72static char *warn_text; 68static char *warn_text;
73 69
74int main(int argc, char **argv) { 70int main(int argc, char **argv) {
75 char *cmd = NULL;
76 char *rawcmd = NULL;
77 int result = STATE_UNKNOWN;
78 int this_result = STATE_UNKNOWN;
79 int i;
80
81 setlocale(LC_ALL, ""); 71 setlocale(LC_ALL, "");
82 setlocale(LC_NUMERIC, "C"); 72 setlocale(LC_NUMERIC, "C");
83 bindtextdomain(PACKAGE, LOCALEDIR); 73 bindtextdomain(PACKAGE, LOCALEDIR);
84 textdomain(PACKAGE); 74 textdomain(PACKAGE);
85 75
86 addresses = malloc(sizeof(char *) * max_addr);
87 addresses[0] = NULL;
88
89 /* Parse extra opts if any */ 76 /* Parse extra opts if any */
90 argv = np_extra_opts(&argc, argv, progname); 77 argv = np_extra_opts(&argc, argv, progname);
91 78
92 if (process_arguments(argc, argv) == ERROR) 79 check_ping_config_wrapper tmp_config = process_arguments(argc, argv);
80 if (tmp_config.errorcode == ERROR) {
93 usage4(_("Could not parse arguments")); 81 usage4(_("Could not parse arguments"));
82 }
83
84 const check_ping_config config = tmp_config.config;
94 85
95 /* Set signal handling and alarm */ 86 /* Set signal handling and alarm */
96 if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) { 87 if (signal(SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
@@ -105,71 +96,86 @@ int main(int argc, char **argv) {
105 alarm(timeout_interval); 96 alarm(timeout_interval);
106#endif 97#endif
107 98
108 for (i = 0; i < n_addresses; i++) { 99 int result = STATE_UNKNOWN;
109 100 char *rawcmd = NULL;
101 for (size_t i = 0; i < config.n_addresses; i++) {
110#ifdef PING6_COMMAND 102#ifdef PING6_COMMAND
111 if (address_family != AF_INET && is_inet6_addr(addresses[i])) 103 if (address_family != AF_INET && is_inet6_addr(config.addresses[i])) {
112 rawcmd = strdup(PING6_COMMAND); 104 rawcmd = strdup(PING6_COMMAND);
113 else 105 } else {
114 rawcmd = strdup(PING_COMMAND); 106 rawcmd = strdup(PING_COMMAND);
107 }
115#else 108#else
116 rawcmd = strdup(PING_COMMAND); 109 rawcmd = strdup(PING_COMMAND);
117#endif 110#endif
118 111
119 /* does the host address of number of packets argument come first? */ 112 char *cmd = NULL;
113
114 /* does the host address of number of packets argument come first? */
120#ifdef PING_PACKETS_FIRST 115#ifdef PING_PACKETS_FIRST
121# ifdef PING_HAS_TIMEOUT 116# ifdef PING_HAS_TIMEOUT
122 xasprintf(&cmd, rawcmd, timeout_interval, max_packets, addresses[i]); 117 xasprintf(&cmd, rawcmd, timeout_interval, config.max_packets, config.addresses[i]);
123# else 118# else
124 xasprintf(&cmd, rawcmd, max_packets, addresses[i]); 119 xasprintf(&cmd, rawcmd, config.max_packets, addresses[i]);
125# endif 120# endif
126#else 121#else
127 xasprintf(&cmd, rawcmd, addresses[i], max_packets); 122 xasprintf(&cmd, rawcmd, addresses[i], config.max_packets);
128#endif 123#endif
129 124
130 if (verbose >= 2) 125 if (verbose >= 2) {
131 printf("CMD: %s\n", cmd); 126 printf("CMD: %s\n", cmd);
127 }
132 128
133 /* run the command */ 129 /* run the command */
134 this_result = run_ping(cmd, addresses[i]);
135 130
136 if (pl == UNKNOWN_PACKET_LOSS || rta < 0.0) { 131 ping_result pinged = run_ping(cmd, config.addresses[i], config.crta);
132
133 if (pinged.packet_loss == UNKNOWN_PACKET_LOSS || pinged.round_trip_average < 0.0) {
137 printf("%s\n", cmd); 134 printf("%s\n", cmd);
138 die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n")); 135 die(STATE_UNKNOWN, _("CRITICAL - Could not interpret output from ping command\n"));
139 } 136 }
140 137
141 if (pl >= cpl || rta >= crta || rta < 0) 138 if (pinged.packet_loss >= config.cpl || pinged.round_trip_average >= config.crta || pinged.round_trip_average < 0) {
142 this_result = STATE_CRITICAL; 139 pinged.state = STATE_CRITICAL;
143 else if (pl >= wpl || rta >= wrta) 140 } else if (pinged.packet_loss >= config.wpl || pinged.round_trip_average >= config.wrta) {
144 this_result = STATE_WARNING; 141 pinged.state = STATE_WARNING;
145 else if (pl >= 0 && rta >= 0) 142 } else if (pinged.packet_loss >= 0 && pinged.round_trip_average >= 0) {
146 this_result = max_state(STATE_OK, this_result); 143 pinged.state = max_state(STATE_OK, pinged.state);
147 144 }
148 if (n_addresses > 1 && this_result != STATE_UNKNOWN) 145
149 die(STATE_OK, "%s is alive\n", addresses[i]); 146 if (config.n_addresses > 1 && pinged.state != STATE_UNKNOWN) {
150 147 die(STATE_OK, "%s is alive\n", config.addresses[i]);
151 if (display_html == true) 148 }
152 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]); 149
153 if (pl == 100) 150 if (config.display_html) {
154 printf(_("PING %s - %sPacket loss = %d%%"), state_text(this_result), warn_text, pl); 151 printf("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, config.addresses[i]);
155 else 152 }
156 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(this_result), warn_text, pl, rta); 153 if (pinged.packet_loss == 100) {
157 if (display_html == true) 154 printf(_("PING %s - %sPacket loss = %d%%"), state_text(pinged.state), warn_text, pinged.packet_loss);
155 } else {
156 printf(_("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms"), state_text(pinged.state), warn_text, pinged.packet_loss,
157 pinged.round_trip_average);
158 }
159 if (config.display_html) {
158 printf("</A>"); 160 printf("</A>");
161 }
159 162
160 /* Print performance data */ 163 /* Print performance data */
161 if (pl != 100) { 164 if (pinged.packet_loss != 100) {
162 printf("|%s", 165 printf("|%s", fperfdata("rta", pinged.round_trip_average, "ms", (bool)(config.wrta > 0), config.wrta, (bool)(config.crta > 0),
163 fperfdata("rta", (double)rta, "ms", wrta > 0 ? true : false, wrta, crta > 0 ? true : false, crta, true, 0, false, 0)); 166 config.crta, true, 0, false, 0));
164 } else { 167 } else {
165 printf("| rta=U;%f;%f;;", wrta, crta); 168 printf("| rta=U;%f;%f;;", config.wrta, config.crta);
166 } 169 }
167 printf(" %s\n", perfdata("pl", (long)pl, "%", wpl > 0 ? true : false, wpl, cpl > 0 ? true : false, cpl, true, 0, false, 0));
168 170
169 if (verbose >= 2) 171 printf(" %s\n", perfdata("pl", (long)pinged.packet_loss, "%", (bool)(config.wpl > 0), config.wpl, (bool)(config.cpl > 0),
170 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 }
171 177
172 result = max_state(result, this_result); 178 result = max_state(result, pinged.state);
173 free(rawcmd); 179 free(rawcmd);
174 free(cmd); 180 free(cmd);
175 } 181 }
@@ -178,11 +184,7 @@ int main(int argc, char **argv) {
178} 184}
179 185
180/* process command-line arguments */ 186/* process command-line arguments */
181int process_arguments(int argc, char **argv) { 187check_ping_config_wrapper process_arguments(int argc, char **argv) {
182 int c = 1;
183 char *ptr;
184
185 int option = 0;
186 static struct option longopts[] = {STD_LONG_OPTS, 188 static struct option longopts[] = {STD_LONG_OPTS,
187 {"packets", required_argument, 0, 'p'}, 189 {"packets", required_argument, 0, 'p'},
188 {"nohtml", no_argument, 0, 'n'}, 190 {"nohtml", no_argument, 0, 'n'},
@@ -191,23 +193,35 @@ int process_arguments(int argc, char **argv) {
191 {"use-ipv6", no_argument, 0, '6'}, 193 {"use-ipv6", no_argument, 0, '6'},
192 {0, 0, 0, 0}}; 194 {0, 0, 0, 0}};
193 195
194 if (argc < 2) 196 check_ping_config_wrapper result = {
195 return ERROR; 197 .errorcode = OK,
198 .config = check_ping_config_init(),
199 };
200
201 if (argc < 2) {
202 result.errorcode = ERROR;
203 return result;
204 }
196 205
197 for (c = 1; c < argc; c++) { 206 for (int index = 1; index < argc; index++) {
198 if (strcmp("-to", argv[c]) == 0) 207 if (strcmp("-to", argv[index]) == 0) {
199 strcpy(argv[c], "-t"); 208 strcpy(argv[index], "-t");
200 if (strcmp("-nohtml", argv[c]) == 0) 209 }
201 strcpy(argv[c], "-n"); 210 if (strcmp("-nohtml", argv[index]) == 0) {
211 strcpy(argv[index], "-n");
212 }
202 } 213 }
203 214
204 while (1) { 215 int option = 0;
205 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);
206 219
207 if (c == -1 || c == EOF) 220 if (option_index == -1 || option_index == EOF) {
208 break; 221 break;
222 }
209 223
210 switch (c) { 224 switch (option_index) {
211 case '?': /* usage */ 225 case '?': /* usage */
212 usage5(); 226 usage5();
213 case 'h': /* help */ 227 case 'h': /* help */
@@ -234,17 +248,18 @@ int process_arguments(int argc, char **argv) {
234 usage(_("IPv6 support not available\n")); 248 usage(_("IPv6 support not available\n"));
235#endif 249#endif
236 break; 250 break;
237 case 'H': /* hostname */ 251 case 'H': /* hostname */ {
238 ptr = optarg; 252 char *ptr = optarg;
239 while (1) { 253 while (true) {
240 n_addresses++; 254 result.config.n_addresses++;
241 if (n_addresses > max_addr) { 255 if (result.config.n_addresses > max_addr) {
242 max_addr *= 2; 256 max_addr *= 2;
243 addresses = realloc(addresses, sizeof(char *) * max_addr); 257 result.config.addresses = realloc(result.config.addresses, sizeof(char *) * max_addr);
244 if (addresses == NULL) 258 if (result.config.addresses == NULL) {
245 die(STATE_UNKNOWN, _("Could not realloc() addresses\n")); 259 die(STATE_UNKNOWN, _("Could not realloc() addresses\n"));
260 }
246 } 261 }
247 addresses[n_addresses - 1] = ptr; 262 result.config.addresses[result.config.n_addresses - 1] = ptr;
248 if ((ptr = index(ptr, ','))) { 263 if ((ptr = index(ptr, ','))) {
249 strcpy(ptr, ""); 264 strcpy(ptr, "");
250 ptr += sizeof(char); 265 ptr += sizeof(char);
@@ -252,203 +267,248 @@ int process_arguments(int argc, char **argv) {
252 break; 267 break;
253 } 268 }
254 } 269 }
255 break; 270 } break;
256 case 'p': /* number of packets to send */ 271 case 'p': /* number of packets to send */
257 if (is_intnonneg(optarg)) 272 if (is_intnonneg(optarg)) {
258 max_packets = atoi(optarg); 273 result.config.max_packets = atoi(optarg);
259 else 274 } else {
260 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg); 275 usage2(_("<max_packets> (%s) must be a non-negative number\n"), optarg);
276 }
261 break; 277 break;
262 case 'n': /* no HTML */ 278 case 'n': /* no HTML */
263 display_html = false; 279 result.config.display_html = false;
264 break; 280 break;
265 case 'L': /* show HTML */ 281 case 'L': /* show HTML */
266 display_html = true; 282 result.config.display_html = true;
267 break; 283 break;
268 case 'c': 284 case 'c':
269 get_threshold(optarg, &crta, &cpl); 285 get_threshold(optarg, &result.config.crta, &result.config.cpl);
270 break; 286 break;
271 case 'w': 287 case 'w':
272 get_threshold(optarg, &wrta, &wpl); 288 get_threshold(optarg, &result.config.wrta, &result.config.wpl);
273 break; 289 break;
274 } 290 }
275 } 291 }
276 292
277 c = optind; 293 int arg_counter = optind;
278 if (c == argc) 294 if (arg_counter == argc) {
279 return validate_arguments(); 295 return validate_arguments(result);
296 }
280 297
281 if (addresses[0] == NULL) { 298 if (result.config.addresses[0] == NULL) {
282 if (!is_host(argv[c])) { 299 if (!is_host(argv[arg_counter])) {
283 usage2(_("Invalid hostname/address"), argv[c]); 300 usage2(_("Invalid hostname/address"), argv[arg_counter]);
284 } else { 301 } else {
285 addresses[0] = argv[c++]; 302 result.config.addresses[0] = argv[arg_counter++];
286 n_addresses++; 303 result.config.n_addresses++;
287 if (c == argc) 304 if (arg_counter == argc) {
288 return validate_arguments(); 305 return validate_arguments(result);
306 }
289 } 307 }
290 } 308 }
291 309
292 if (wpl == UNKNOWN_PACKET_LOSS) { 310 if (result.config.wpl == UNKNOWN_PACKET_LOSS) {
293 if (!is_intpercent(argv[c])) { 311 if (!is_intpercent(argv[arg_counter])) {
294 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[c]); 312 printf(_("<wpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
295 return ERROR; 313 result.errorcode = ERROR;
296 } else { 314 return result;
297 wpl = atoi(argv[c++]); 315 }
298 if (c == argc) 316 result.config.wpl = atoi(argv[arg_counter++]);
299 return validate_arguments(); 317 if (arg_counter == argc) {
318 return validate_arguments(result);
300 } 319 }
301 } 320 }
302 321
303 if (cpl == UNKNOWN_PACKET_LOSS) { 322 if (result.config.cpl == UNKNOWN_PACKET_LOSS) {
304 if (!is_intpercent(argv[c])) { 323 if (!is_intpercent(argv[arg_counter])) {
305 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[c]); 324 printf(_("<cpl> (%s) must be an integer percentage\n"), argv[arg_counter]);
306 return ERROR; 325 result.errorcode = ERROR;
307 } else { 326 return result;
308 cpl = atoi(argv[c++]); 327 }
309 if (c == argc) 328 result.config.cpl = atoi(argv[arg_counter++]);
310 return validate_arguments(); 329 if (arg_counter == argc) {
330 return validate_arguments(result);
311 } 331 }
312 } 332 }
313 333
314 if (wrta < 0.0) { 334 if (result.config.wrta < 0.0) {
315 if (is_negative(argv[c])) { 335 if (is_negative(argv[arg_counter])) {
316 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]);
317 return ERROR; 337 result.errorcode = ERROR;
318 } else { 338 return result;
319 wrta = atof(argv[c++]); 339 }
320 if (c == argc) 340 result.config.wrta = atof(argv[arg_counter++]);
321 return validate_arguments(); 341 if (arg_counter == argc) {
342 return validate_arguments(result);
322 } 343 }
323 } 344 }
324 345
325 if (crta < 0.0) { 346 if (result.config.crta < 0.0) {
326 if (is_negative(argv[c])) { 347 if (is_negative(argv[arg_counter])) {
327 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]);
328 return ERROR; 349 result.errorcode = ERROR;
329 } else { 350 return result;
330 crta = atof(argv[c++]); 351 }
331 if (c == argc) 352 result.config.crta = atof(argv[arg_counter++]);
332 return validate_arguments(); 353 if (arg_counter == argc) {
354 return validate_arguments(result);
333 } 355 }
334 } 356 }
335 357
336 if (max_packets == -1) { 358 if (result.config.max_packets == -1) {
337 if (is_intnonneg(argv[c])) { 359 if (is_intnonneg(argv[arg_counter])) {
338 max_packets = atoi(argv[c++]); 360 result.config.max_packets = atoi(argv[arg_counter++]);
339 } else { 361 } else {
340 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]);
341 return ERROR; 363 result.errorcode = ERROR;
364 return result;
342 } 365 }
343 } 366 }
344 367
345 return validate_arguments(); 368 return validate_arguments(result);
346} 369}
347 370
348int get_threshold(char *arg, float *trta, int *tpl) { 371int get_threshold(char *arg, double *trta, int *tpl) {
349 if (is_intnonneg(arg) && sscanf(arg, "%f", trta) == 1) 372 if (is_intnonneg(arg) && sscanf(arg, "%lf", trta) == 1) {
350 return OK; 373 return OK;
351 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) {
352 return OK; 377 return OK;
353 else if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) 378 }
379
380 if (strstr(arg, "%") && sscanf(arg, "%d%%", tpl) == 1) {
354 return OK; 381 return OK;
382 }
355 383
356 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);
357 return STATE_UNKNOWN; 385 return STATE_UNKNOWN;
358} 386}
359 387
360int validate_arguments() { 388check_ping_config_wrapper validate_arguments(check_ping_config_wrapper config_wrapper) {
361 float max_seconds; 389 if (config_wrapper.config.wrta < 0.0) {
362 int i;
363
364 if (wrta < 0.0) {
365 printf(_("<wrta> was not set\n")); 390 printf(_("<wrta> was not set\n"));
366 return ERROR; 391 config_wrapper.errorcode = ERROR;
367 } else if (crta < 0.0) { 392 return config_wrapper;
393 }
394
395 if (config_wrapper.config.crta < 0.0) {
368 printf(_("<crta> was not set\n")); 396 printf(_("<crta> was not set\n"));
369 return ERROR; 397 config_wrapper.errorcode = ERROR;
370 } else if (wpl == UNKNOWN_PACKET_LOSS) { 398 return config_wrapper;
399 }
400
401 if (config_wrapper.config.wpl == UNKNOWN_PACKET_LOSS) {
371 printf(_("<wpl> was not set\n")); 402 printf(_("<wpl> was not set\n"));
372 return ERROR; 403 config_wrapper.errorcode = ERROR;
373 } else if (cpl == UNKNOWN_PACKET_LOSS) { 404 return config_wrapper;
405 }
406
407 if (config_wrapper.config.cpl == UNKNOWN_PACKET_LOSS) {
374 printf(_("<cpl> was not set\n")); 408 printf(_("<cpl> was not set\n"));
375 return ERROR; 409 config_wrapper.errorcode = ERROR;
376 } else if (wrta > crta) { 410 return config_wrapper;
377 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), wrta, crta); 411 }
378 return ERROR; 412
379 } else if (wpl > cpl) { 413 if (config_wrapper.config.wrta > config_wrapper.config.crta) {
380 printf(_("<wpl> (%d) cannot be larger than <cpl> (%d)\n"), wpl, cpl); 414 printf(_("<wrta> (%f) cannot be larger than <crta> (%f)\n"), config_wrapper.config.wrta, config_wrapper.config.crta);
381 return ERROR; 415 config_wrapper.errorcode = ERROR;
416 return config_wrapper;
382 } 417 }
383 418
384 if (max_packets == -1) 419 if (config_wrapper.config.wpl > config_wrapper.config.cpl) {
385 max_packets = DEFAULT_MAX_PACKETS; 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;
423 }
386 424
387 max_seconds = crta / 1000.0 * max_packets + max_packets; 425 if (config_wrapper.config.max_packets == -1) {
388 if (max_seconds > timeout_interval) 426 config_wrapper.config.max_packets = DEFAULT_MAX_PACKETS;
389 timeout_interval = (int)max_seconds; 427 }
390 428
391 for (i = 0; i < n_addresses; i++) { 429 double max_seconds = (config_wrapper.config.crta / 1000.0 * config_wrapper.config.max_packets) + config_wrapper.config.max_packets;
392 if (!is_host(addresses[i])) 430 if (max_seconds > timeout_interval) {
393 usage2(_("Invalid hostname/address"), addresses[i]); 431 timeout_interval = (unsigned int)max_seconds;
432 }
433
434 for (size_t i = 0; i < config_wrapper.config.n_addresses; i++) {
435 if (!is_host(config_wrapper.config.addresses[i])) {
436 usage2(_("Invalid hostname/address"), config_wrapper.config.addresses[i]);
437 }
394 } 438 }
395 439
396 if (n_addresses == 0) { 440 if (config_wrapper.config.n_addresses == 0) {
397 usage(_("You must specify a server address or host name")); 441 usage(_("You must specify a server address or host name"));
398 } 442 }
399 443
400 return OK; 444 return config_wrapper;
401} 445}
402 446
403int run_ping(const char *cmd, const char *addr) { 447ping_result run_ping(const char *cmd, const char *addr, double crta) {
404 char buf[MAX_INPUT_BUFFER]; 448 if ((child_process = spopen(cmd)) == NULL) {
405 int result = STATE_UNKNOWN;
406 int match;
407
408 if ((child_process = spopen(cmd)) == NULL)
409 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd); 449 die(STATE_UNKNOWN, _("Could not open pipe: %s\n"), cmd);
450 }
410 451
411 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r"); 452 child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r");
412 if (child_stderr == NULL) 453 if (child_stderr == NULL) {
413 printf(_("Cannot open stderr for %s\n"), cmd); 454 printf(_("Cannot open stderr for %s\n"), cmd);
455 }
414 456
415 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) { 457 char buf[MAX_INPUT_BUFFER];
458 ping_result result = {
459 .state = STATE_UNKNOWN,
460 .packet_loss = UNKNOWN_PACKET_LOSS,
461 .round_trip_average = UNKNOWN_TRIP_TIME,
462 };
416 463
417 if (verbose >= 3) 464 while (fgets(buf, MAX_INPUT_BUFFER - 1, child_process)) {
465 if (verbose >= 3) {
418 printf("Output: %s", buf); 466 printf("Output: %s", buf);
467 }
419 468
420 result = max_state(result, error_scan(buf, addr)); 469 result.state = max_state(result.state, error_scan(buf, addr));
421 470
422 /* get the percent loss statistics */ 471 /* get the percent loss statistics */
423 match = 0; 472 int match = 0;
424 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) ==
425 (sscanf(buf, "%*d packets transmitted, %*d packets received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) || 474 1 &&
426 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d duplicates, %d%% packet loss%n", &pl, &match) && match) || 475 match) ||
427 (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,
428 (sscanf(buf, "%*d packets transmitted, %*d packets received, %d%% loss, time%n", &pl, &match) && match) || 477 &match) == 1 &&
429 (sscanf(buf, "%*d packets transmitted, %*d received, %d%% loss, time%n", &pl, &match) && match) || 478 match) ||
430 (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 &&
431 (sscanf(buf, "%*d packets transmitted, %*d received, +%*d errors, %d%% packet loss%n", &pl, &match) && match) || 480 match) ||
432 (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) ||
433 (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) ||
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)) {
434 continue; 491 continue;
492 }
435 493
436 /* get the round trip average */ 494 /* get the round trip average */
437 else if ((sscanf(buf, "round-trip min/avg/max = %*f/%f/%*f%n", &rta, &match) && match) || 495 if ((sscanf(buf, "round-trip min/avg/max = %*f/%lf/%*f%n", &result.round_trip_average, &match) == 1 && match) ||
438 (sscanf(buf, "round-trip min/avg/max/mdev = %*f/%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) ||
439 (sscanf(buf, "round-trip min/avg/max/sdev = %*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) ||
440 (sscanf(buf, "round-trip min/avg/max/stddev = %*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) ||
441 (sscanf(buf, "round-trip min/avg/max/std-dev = %*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) ||
442 (sscanf(buf, "round-trip (ms) min/avg/max = %*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) ||
443 (sscanf(buf, "round-trip (ms) min/avg/max/stddev = %*f/%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) ||
444 (sscanf(buf, "rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms%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) ||
445 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %fms%n", &rta, &match) && match)) 503 (sscanf(buf, "%*[^=] = %*fms, %*[^=] = %*fms, %*[^=] = %lfms%n", &result.round_trip_average, &match) == 1 && match)) {
446 continue; 504 continue;
505 }
447 } 506 }
448 507
449 /* 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 */
450 if (pl == 100) 509 if (result.packet_loss == 100) {
451 rta = crta; 510 result.round_trip_average = crta;
511 }
452 512
453 /* check stderr, setting at least WARNING if there is output here */ 513 /* check stderr, setting at least WARNING if there is output here */
454 /* Add warning into warn_text */ 514 /* Add warning into warn_text */
@@ -459,8 +519,8 @@ int run_ping(const char *cmd, const char *addr) {
459 if (verbose >= 3) { 519 if (verbose >= 3) {
460 printf("Got stderr: %s", buf); 520 printf("Got stderr: %s", buf);
461 } 521 }
462 if ((result = error_scan(buf, addr)) == STATE_OK) { 522 if ((result.state = error_scan(buf, addr)) == STATE_OK) {
463 result = STATE_WARNING; 523 result.state = STATE_WARNING;
464 if (warn_text == NULL) { 524 if (warn_text == NULL) {
465 warn_text = strdup(_("System call sent warnings to stderr ")); 525 warn_text = strdup(_("System call sent warnings to stderr "));
466 } else { 526 } else {
@@ -474,43 +534,46 @@ int run_ping(const char *cmd, const char *addr) {
474 534
475 spclose(child_process); 535 spclose(child_process);
476 536
477 if (warn_text == NULL) 537 if (warn_text == NULL) {
478 warn_text = strdup(""); 538 warn_text = strdup("");
539 }
479 540
480 return result; 541 return result;
481} 542}
482 543
483int error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) { 544mp_state_enum error_scan(char buf[MAX_INPUT_BUFFER], const char *addr) {
484 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) 545 if (strstr(buf, "Network is unreachable") || strstr(buf, "Destination Net Unreachable") || strstr(buf, "No route")) {
485 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr); 546 die(STATE_CRITICAL, _("CRITICAL - Network Unreachable (%s)\n"), addr);
486 else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) 547 } else if (strstr(buf, "Destination Host Unreachable") || strstr(buf, "Address unreachable")) {
487 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr); 548 die(STATE_CRITICAL, _("CRITICAL - Host Unreachable (%s)\n"), addr);
488 else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) 549 } else if (strstr(buf, "Destination Port Unreachable") || strstr(buf, "Port unreachable")) {
489 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr); 550 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Port Unreachable (%s)\n"), addr);
490 else if (strstr(buf, "Destination Protocol Unreachable")) 551 } else if (strstr(buf, "Destination Protocol Unreachable")) {
491 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr); 552 die(STATE_CRITICAL, _("CRITICAL - Bogus ICMP: Protocol Unreachable (%s)\n"), addr);
492 else if (strstr(buf, "Destination Net Prohibited")) 553 } else if (strstr(buf, "Destination Net Prohibited")) {
493 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr); 554 die(STATE_CRITICAL, _("CRITICAL - Network Prohibited (%s)\n"), addr);
494 else if (strstr(buf, "Destination Host Prohibited")) 555 } else if (strstr(buf, "Destination Host Prohibited")) {
495 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr); 556 die(STATE_CRITICAL, _("CRITICAL - Host Prohibited (%s)\n"), addr);
496 else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) 557 } else if (strstr(buf, "Packet filtered") || strstr(buf, "Administratively prohibited")) {
497 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr); 558 die(STATE_CRITICAL, _("CRITICAL - Packet Filtered (%s)\n"), addr);
498 else if (strstr(buf, "unknown host")) 559 } else if (strstr(buf, "unknown host")) {
499 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr); 560 die(STATE_CRITICAL, _("CRITICAL - Host not found (%s)\n"), addr);
500 else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) 561 } else if (strstr(buf, "Time to live exceeded") || strstr(buf, "Time exceeded")) {
501 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr); 562 die(STATE_CRITICAL, _("CRITICAL - Time to live exceeded (%s)\n"), addr);
502 else if (strstr(buf, "Destination unreachable: ")) 563 } else if (strstr(buf, "Destination unreachable: ")) {
503 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr); 564 die(STATE_CRITICAL, _("CRITICAL - Destination Unreachable (%s)\n"), addr);
565 }
504 566
505 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) { 567 if (strstr(buf, "(DUP!)") || strstr(buf, "DUPLICATES FOUND")) {
506 if (warn_text == NULL) 568 if (warn_text == NULL) {
507 warn_text = strdup(_(WARN_DUPLICATES)); 569 warn_text = strdup(_(WARN_DUPLICATES));
508 else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) 570 } else if (!strstr(warn_text, _(WARN_DUPLICATES)) && xasprintf(&warn_text, "%s %s", warn_text, _(WARN_DUPLICATES)) == -1) {
509 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n")); 571 die(STATE_UNKNOWN, _("Unable to realloc warn_text\n"));
510 return (STATE_WARNING); 572 }
573 return STATE_WARNING;
511 } 574 }
512 575
513 return (STATE_OK); 576 return STATE_OK;
514} 577}
515 578
516void print_help(void) { 579void print_help(void) {
@@ -551,9 +614,7 @@ void print_help(void) {
551 614
552 printf("\n"); 615 printf("\n");
553 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"));
554 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."));
555 printf("%s\n", _("linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in"));
556 printf("%s\n", _("the contrib area of the downloads section at http://www.nagios.org/"));
557 618
558 printf(UT_SUPPORT); 619 printf(UT_SUPPORT);
559} 620}
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_radius.c b/plugins/check_radius.c
index d9ff8fa7..cc846709 100644
--- a/plugins/check_radius.c
+++ b/plugins/check_radius.c
@@ -1,32 +1,32 @@
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-2024 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-2024"; 32const char *copyright = "2000-2024";
@@ -35,64 +35,57 @@ const char *email = "devel@monitoring-plugins.org";
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
49static int process_arguments (int /*argc*/, char ** /*argv*/); 51typedef struct {
50static void 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
81static int my_rc_read_config(char * /*a*/); 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)
84static rc_handle *rch = NULL;
85#endif
86 88
87static char *server = NULL;
88static char *username = NULL;
89static char *password = NULL;
90static char *nasid = NULL;
91static char *nasipaddress = NULL;
92static char *expect = NULL;
93static char *config_file = NULL;
94static unsigned short port = PW_AUTH_UDP_PORT;
95static int retries = 1;
96static bool verbose = false; 89static bool verbose = false;
97 90
98/****************************************************************************** 91/******************************************************************************
@@ -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 369a88b1..ec0928ed 100644
--- a/plugins/check_real.c
+++ b/plugins/check_real.c
@@ -28,6 +28,8 @@
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-2024"; 34const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
@@ -35,27 +37,20 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 37#include "common.h"
36#include "netutils.h" 38#include "netutils.h"
37#include "utils.h" 39#include "utils.h"
38 40#include "check_real.d/config.h"
39enum {
40 PORT = 554
41};
42 41
43#define EXPECT "RTSP/1." 42#define EXPECT "RTSP/1."
44#define URL "" 43#define URL ""
45 44
46static int process_arguments(int, char **); 45typedef struct {
46 int errorcode;
47 check_real_config config;
48} check_real_config_wrapper;
49static check_real_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50
47static void print_help(void); 51static void print_help(void);
48void print_usage(void); 52void print_usage(void);
49 53
50static int server_port = PORT;
51static char *server_address;
52static char *host_name;
53static char *server_url = NULL;
54static char *server_expect;
55static int warning_time = 0;
56static bool check_warning_time = false;
57static int critical_time = 0;
58static bool check_critical_time = false;
59static bool verbose = false; 54static bool verbose = false;
60 55
61int main(int argc, char **argv) { 56int main(int argc, char **argv) {
@@ -66,8 +61,12 @@ int main(int argc, char **argv) {
66 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
67 argv = np_extra_opts(&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
68 63
69 if (process_arguments(argc, argv) == ERROR) 64 check_real_config_wrapper tmp_config = process_arguments(argc, argv);
65 if (tmp_config.errorcode == ERROR) {
70 usage4(_("Could not parse arguments")); 66 usage4(_("Could not parse arguments"));
67 }
68
69 const check_real_config config = tmp_config.config;
71 70
72 /* initialize alarm signal handling */ 71 /* initialize alarm signal handling */
73 signal(SIGALRM, socket_timeout_alarm_handler); 72 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -78,38 +77,51 @@ int main(int argc, char **argv) {
78 77
79 /* try to connect to the host at the given port number */ 78 /* try to connect to the host at the given port number */
80 int socket; 79 int socket;
81 if (my_tcp_connect(server_address, server_port, &socket) != STATE_OK) 80 if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) {
82 die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), server_address, server_port); 81 die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), config.server_address, config.server_port);
82 }
83 83
84 /* Part I - Server Check */ 84 /* Part I - Server Check */
85 85
86 /* send the OPTIONS request */ 86 /* send the OPTIONS request */
87 char buffer[MAX_INPUT_BUFFER]; 87 char buffer[MAX_INPUT_BUFFER];
88 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", host_name, server_port); 88 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port);
89 int result = send(socket, buffer, strlen(buffer), 0); 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 }
90 93
91 /* send the header sync */ 94 /* send the header sync */
92 sprintf(buffer, "CSeq: 1\r\n"); 95 sprintf(buffer, "CSeq: 1\r\n");
93 result = send(socket, 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 }
94 100
95 /* 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 */
96 sprintf(buffer, "\r\n"); 102 sprintf(buffer, "\r\n");
97 result = send(socket, 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 }
98 107
99 /* watch for the REAL connection string */ 108 /* watch for the REAL connection string */
100 result = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); 109 ssize_t received_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
101 110
102 /* return a CRITICAL status if we couldn't read any data */ 111 /* return a CRITICAL status if we couldn't read any data */
103 if (result == -1) 112 if (received_bytes == -1) {
104 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 }
105 115
116 mp_state_enum result = STATE_OK;
106 char *status_line = NULL; 117 char *status_line = NULL;
107 /* make sure we find the response we are looking for */ 118 /* make sure we find the response we are looking for */
108 if (!strstr(buffer, server_expect)) { 119 if (!strstr(buffer, config.server_expect)) {
109 if (server_port == PORT) 120 if (config.server_port == PORT) {
110 printf("%s\n", _("Invalid REAL response received from host")); 121 printf("%s\n", _("Invalid REAL response received from host"));
111 else 122 } else {
112 printf(_("Invalid REAL response received from host on port %d\n"), server_port); 123 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
124 }
113 } else { 125 } else {
114 /* else we got the REAL string, so check the return code */ 126 /* else we got the REAL string, so check the return code */
115 127
@@ -117,69 +129,79 @@ int main(int argc, char **argv) {
117 129
118 result = STATE_OK; 130 result = STATE_OK;
119 131
120 status_line = (char *)strtok(buffer, "\n"); 132 status_line = strtok(buffer, "\n");
121 133
122 if (strstr(status_line, "200")) 134 if (strstr(status_line, "200")) {
123 result = STATE_OK; 135 result = STATE_OK;
136 }
124 137
125 /* client errors result in a warning state */ 138 /* client errors result in a warning state */
126 else if (strstr(status_line, "400")) 139 else if (strstr(status_line, "400")) {
127 result = STATE_WARNING; 140 result = STATE_WARNING;
128 else if (strstr(status_line, "401")) 141 } else if (strstr(status_line, "401")) {
129 result = STATE_WARNING; 142 result = STATE_WARNING;
130 else if (strstr(status_line, "402")) 143 } else if (strstr(status_line, "402")) {
131 result = STATE_WARNING; 144 result = STATE_WARNING;
132 else if (strstr(status_line, "403")) 145 } else if (strstr(status_line, "403")) {
133 result = STATE_WARNING; 146 result = STATE_WARNING;
134 else if (strstr(status_line, "404")) 147 } else if (strstr(status_line, "404")) {
135 result = STATE_WARNING; 148 result = STATE_WARNING;
136 149 } else if (strstr(status_line, "500")) {
137 /* server errors result in a critical state */ 150 /* server errors result in a critical state */
138 else if (strstr(status_line, "500"))
139 result = STATE_CRITICAL; 151 result = STATE_CRITICAL;
140 else if (strstr(status_line, "501")) 152 } else if (strstr(status_line, "501")) {
141 result = STATE_CRITICAL; 153 result = STATE_CRITICAL;
142 else if (strstr(status_line, "502")) 154 } else if (strstr(status_line, "502")) {
143 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
144 else if (strstr(status_line, "503")) 156 } else if (strstr(status_line, "503")) {
145 result = STATE_CRITICAL; 157 result = STATE_CRITICAL;
146 158 } else {
147 else
148 result = STATE_UNKNOWN; 159 result = STATE_UNKNOWN;
160 }
149 } 161 }
150 162
151 /* Part II - Check stream exists and is ok */ 163 /* Part II - Check stream exists and is ok */
152 if ((result == STATE_OK) && (server_url != NULL)) { 164 if ((result == STATE_OK) && (config.server_url != NULL)) {
153 165
154 /* Part I - Server Check */ 166 /* Part I - Server Check */
155 167
156 /* send the DESCRIBE request */ 168 /* send the DESCRIBE request */
157 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", host_name, server_port, server_url); 169 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name, config.server_port, config.server_url);
158 result = send(socket, buffer, strlen(buffer), 0); 170
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 }
159 175
160 /* send the header sync */ 176 /* send the header sync */
161 sprintf(buffer, "CSeq: 2\r\n"); 177 sprintf(buffer, "CSeq: 2\r\n");
162 result = send(socket, 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 }
163 182
164 /* 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 */
165 sprintf(buffer, "\r\n"); 184 sprintf(buffer, "\r\n");
166 result = send(socket, 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 }
167 189
168 /* watch for the REAL connection string */ 190 /* watch for the REAL connection string */
169 result = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); 191 ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
170 buffer[result] = '\0'; /* null terminate received buffer */ 192 if (recv_bytes == -1) {
171 193 /* return a CRITICAL status if we couldn't read any data */
172 /* return a CRITICAL status if we couldn't read any data */
173 if (result == -1) {
174 printf(_("No data received from host\n")); 194 printf(_("No data received from host\n"));
175 result = STATE_CRITICAL; 195 result = STATE_CRITICAL;
176 } else { 196 } else {
197 buffer[result] = '\0'; /* null terminate received buffer */
177 /* make sure we find the response we are looking for */ 198 /* make sure we find the response we are looking for */
178 if (!strstr(buffer, server_expect)) { 199 if (!strstr(buffer, config.server_expect)) {
179 if (server_port == PORT) 200 if (config.server_port == PORT) {
180 printf("%s\n", _("Invalid REAL response received from host")); 201 printf("%s\n", _("Invalid REAL response received from host"));
181 else 202 } else {
182 printf(_("Invalid REAL response received from host on port %d\n"), server_port); 203 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
204 }
183 } else { 205 } else {
184 206
185 /* else we got the REAL string, so check the return code */ 207 /* else we got the REAL string, so check the return code */
@@ -188,51 +210,56 @@ int main(int argc, char **argv) {
188 210
189 result = STATE_OK; 211 result = STATE_OK;
190 212
191 status_line = (char *)strtok(buffer, "\n"); 213 status_line = strtok(buffer, "\n");
192 214
193 if (strstr(status_line, "200")) 215 if (strstr(status_line, "200")) {
194 result = STATE_OK; 216 result = STATE_OK;
217 }
195 218
196 /* client errors result in a warning state */ 219 /* client errors result in a warning state */
197 else if (strstr(status_line, "400")) 220 else if (strstr(status_line, "400")) {
198 result = STATE_WARNING; 221 result = STATE_WARNING;
199 else if (strstr(status_line, "401")) 222 } else if (strstr(status_line, "401")) {
200 result = STATE_WARNING; 223 result = STATE_WARNING;
201 else if (strstr(status_line, "402")) 224 } else if (strstr(status_line, "402")) {
202 result = STATE_WARNING; 225 result = STATE_WARNING;
203 else if (strstr(status_line, "403")) 226 } else if (strstr(status_line, "403")) {
204 result = STATE_WARNING; 227 result = STATE_WARNING;
205 else if (strstr(status_line, "404")) 228 } else if (strstr(status_line, "404")) {
206 result = STATE_WARNING; 229 result = STATE_WARNING;
230 }
207 231
208 /* server errors result in a critical state */ 232 /* server errors result in a critical state */
209 else if (strstr(status_line, "500")) 233 else if (strstr(status_line, "500")) {
210 result = STATE_CRITICAL; 234 result = STATE_CRITICAL;
211 else if (strstr(status_line, "501")) 235 } else if (strstr(status_line, "501")) {
212 result = STATE_CRITICAL; 236 result = STATE_CRITICAL;
213 else if (strstr(status_line, "502")) 237 } else if (strstr(status_line, "502")) {
214 result = STATE_CRITICAL; 238 result = STATE_CRITICAL;
215 else if (strstr(status_line, "503")) 239 } else if (strstr(status_line, "503")) {
216 result = STATE_CRITICAL; 240 result = STATE_CRITICAL;
241 }
217 242
218 else 243 else {
219 result = STATE_UNKNOWN; 244 result = STATE_UNKNOWN;
245 }
220 } 246 }
221 } 247 }
222 } 248 }
223 249
224 /* Return results */ 250 /* Return results */
225 if (result == STATE_OK) { 251 if (result == STATE_OK) {
226 252 if (config.check_critical_time && (end_time - start_time) > config.critical_time) {
227 if (check_critical_time && (end_time - start_time) > critical_time)
228 result = STATE_CRITICAL; 253 result = STATE_CRITICAL;
229 else if (check_warning_time && (end_time - start_time) > warning_time) 254 } else if (config.check_warning_time && (end_time - start_time) > config.warning_time) {
230 result = STATE_WARNING; 255 result = STATE_WARNING;
256 }
231 257
232 /* Put some HTML in here to create a dynamic link */ 258 /* Put some HTML in here to create a dynamic link */
233 printf(_("REAL %s - %d second response time\n"), state_text(result), (int)(end_time - start_time)); 259 printf(_("REAL %s - %d second response time\n"), state_text(result), (int)(end_time - start_time));
234 } else 260 } else {
235 printf("%s\n", status_line); 261 printf("%s\n", status_line);
262 }
236 263
237 /* close the connection */ 264 /* close the connection */
238 close(socket); 265 close(socket);
@@ -240,11 +267,11 @@ int main(int argc, char **argv) {
240 /* reset the alarm */ 267 /* reset the alarm */
241 alarm(0); 268 alarm(0);
242 269
243 return result; 270 exit(result);
244} 271}
245 272
246/* process command-line arguments */ 273/* process command-line arguments */
247int process_arguments(int argc, char **argv) { 274check_real_config_wrapper process_arguments(int argc, char **argv) {
248 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'}, 275 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'},
249 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'}, 276 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'},
250 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'}, 277 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'},
@@ -252,61 +279,70 @@ int process_arguments(int argc, char **argv) {
252 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, 279 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
253 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; 280 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
254 281
255 if (argc < 2) 282 check_real_config_wrapper result = {
256 return ERROR; 283 .errorcode = OK,
284 .config = check_real_config_init(),
285 };
286
287 if (argc < 2) {
288 result.errorcode = ERROR;
289 return result;
290 }
257 291
258 for (int i = 1; i < argc; i++) { 292 for (int i = 1; i < argc; i++) {
259 if (strcmp("-to", argv[i]) == 0) 293 if (strcmp("-to", argv[i]) == 0) {
260 strcpy(argv[i], "-t"); 294 strcpy(argv[i], "-t");
261 else if (strcmp("-wt", argv[i]) == 0) 295 } else if (strcmp("-wt", argv[i]) == 0) {
262 strcpy(argv[i], "-w"); 296 strcpy(argv[i], "-w");
263 else if (strcmp("-ct", argv[i]) == 0) 297 } else if (strcmp("-ct", argv[i]) == 0) {
264 strcpy(argv[i], "-c"); 298 strcpy(argv[i], "-c");
299 }
265 } 300 }
266 301
267 int option_char;
268 while (true) { 302 while (true) {
269 int option = 0; 303 int option = 0;
270 option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option); 304 int option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option);
271 305
272 if (option_char == -1 || option_char == EOF) 306 if (option_char == -1 || option_char == EOF) {
273 break; 307 break;
308 }
274 309
275 switch (option_char) { 310 switch (option_char) {
276 case 'I': /* hostname */ 311 case 'I': /* hostname */
277 case 'H': /* hostname */ 312 case 'H': /* hostname */
278 if (server_address) 313 if (result.config.server_address) {
279 break; 314 break;
280 else if (is_host(optarg)) 315 } else if (is_host(optarg)) {
281 server_address = optarg; 316 result.config.server_address = optarg;
282 else 317 } else {
283 usage2(_("Invalid hostname/address"), optarg); 318 usage2(_("Invalid hostname/address"), optarg);
319 }
284 break; 320 break;
285 case 'e': /* string to expect in response header */ 321 case 'e': /* string to expect in response header */
286 server_expect = optarg; 322 result.config.server_expect = optarg;
287 break; 323 break;
288 case 'u': /* server URL */ 324 case 'u': /* server URL */
289 server_url = optarg; 325 result.config.server_url = optarg;
290 break; 326 break;
291 case 'p': /* port */ 327 case 'p': /* port */
292 if (is_intpos(optarg)) { 328 if (is_intpos(optarg)) {
293 server_port = atoi(optarg); 329 result.config.server_port = atoi(optarg);
294 } else { 330 } else {
295 usage4(_("Port must be a positive integer")); 331 usage4(_("Port must be a positive integer"));
296 } 332 }
297 break; 333 break;
298 case 'w': /* warning time threshold */ 334 case 'w': /* warning time threshold */
299 if (is_intnonneg(optarg)) { 335 if (is_intnonneg(optarg)) {
300 warning_time = atoi(optarg); 336 result.config.warning_time = atoi(optarg);
301 check_warning_time = true; 337 result.config.check_warning_time = true;
302 } else { 338 } else {
303 usage4(_("Warning time must be a positive integer")); 339 usage4(_("Warning time must be a positive integer"));
304 } 340 }
305 break; 341 break;
306 case 'c': /* critical time threshold */ 342 case 'c': /* critical time threshold */
307 if (is_intnonneg(optarg)) { 343 if (is_intnonneg(optarg)) {
308 critical_time = atoi(optarg); 344 result.config.critical_time = atoi(optarg);
309 check_critical_time = true; 345 result.config.check_critical_time = true;
310 } else { 346 } else {
311 usage4(_("Critical time must be a positive integer")); 347 usage4(_("Critical time must be a positive integer"));
312 } 348 }
@@ -332,25 +368,28 @@ int process_arguments(int argc, char **argv) {
332 } 368 }
333 } 369 }
334 370
335 option_char = optind; 371 int option_char = optind;
336 if (server_address == NULL && argc > option_char) { 372 if (result.config.server_address == NULL && argc > option_char) {
337 if (is_host(argv[option_char])) { 373 if (is_host(argv[option_char])) {
338 server_address = argv[option_char++]; 374 result.config.server_address = argv[option_char++];
339 } else { 375 } else {
340 usage2(_("Invalid hostname/address"), argv[option_char]); 376 usage2(_("Invalid hostname/address"), argv[option_char]);
341 } 377 }
342 } 378 }
343 379
344 if (server_address == NULL) 380 if (result.config.server_address == NULL) {
345 usage4(_("You must provide a server to check")); 381 usage4(_("You must provide a server to check"));
382 }
346 383
347 if (host_name == NULL) 384 if (result.config.host_name == NULL) {
348 host_name = strdup(server_address); 385 result.config.host_name = strdup(result.config.server_address);
386 }
349 387
350 if (server_expect == NULL) 388 if (result.config.server_expect == NULL) {
351 server_expect = strdup(EXPECT); 389 result.config.server_expect = strdup(EXPECT);
390 }
352 391
353 return OK; 392 return result;
354} 393}
355 394
356void print_help(void) { 395void print_help(void) {
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 e6369e63..44b735f9 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -1,32 +1,32 @@
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-2024 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-2024"; 32const char *copyright = "2000-2024";
@@ -36,400 +36,394 @@ const char *email = "devel@monitoring-plugins.org";
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
43static bool check_cert = false; 63 if ((config.use_starttls || config.use_ssl) && ssl_established) {
44static int 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 75
65#define EHLO_SUPPORTS_STARTTLS 1 76 return np_net_ssl_write(buf, num);
77 }
78 return (int)send(socket_descriptor, buf, (size_t)num, 0);
79#else /* ifndef HAVE_SSL */
80 return send(socket_descriptor, buf, len, 0);
81#endif
82}
66 83
67static int process_arguments (int, char **); 84static void print_help(void);
68static int validate_arguments (void); 85void print_usage(void);
69static void print_help (void); 86static char *smtp_quit(check_smtp_config /*config*/, char /*buffer*/[MAX_INPUT_BUFFER], int /*socket_descriptor*/,
70void print_usage (void); 87 bool /*ssl_established*/);
71static void smtp_quit(void); 88static int recvline(char * /*buf*/, size_t /*bufsize*/, check_smtp_config /*config*/, int /*socket_descriptor*/, bool /*ssl_established*/);
72static int recvline(char *, size_t); 89static int recvlines(check_smtp_config /*config*/, char * /*buf*/, size_t /*bufsize*/, int /*socket_descriptor*/, bool /*ssl_established*/);
73static int recvlines(char *, size_t); 90static int my_close(int /*socket_descriptor*/);
74static int my_close(void);
75 91
76#include "regex.h"
77static regex_t preg;
78static regmatch_t pmatch[10];
79static char errbuf[MAX_INPUT_BUFFER];
80static int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
81static int eflags = 0;
82static int errcode, excode;
83
84static int server_port = SMTP_PORT;
85static int server_port_option = 0;
86static char *server_address = NULL;
87static char *server_expect = NULL;
88static char *mail_command = NULL;
89static char *from_arg = NULL;
90static int send_mail_from=0;
91static int ncommands=0;
92static int command_size=0;
93static int nresponses=0;
94static int response_size=0;
95static char **commands = NULL;
96static char **responses = NULL;
97static char *authtype = NULL;
98static char *authuser = NULL;
99static char *authpass = NULL;
100static double warning_time = 0;
101static bool check_warning_time = false;
102static double critical_time = 0;
103static bool check_critical_time = false;
104static int verbose = 0; 92static int verbose = 0;
105static bool use_ssl = false;
106static bool use_starttls = false;
107static bool use_sni = false;
108static bool use_proxy_prefix = false;
109static bool use_ehlo = false;
110static bool use_lhlo = false;
111static bool ssl_established = false;
112static char *localhostname = NULL;
113static int sd;
114static char buffer[MAX_INPUT_BUFFER];
115enum {
116 TCP_PROTOCOL = 1,
117 UDP_PROTOCOL = 2,
118};
119static bool ignore_send_quit_failure = false;
120
121
122int
123main (int argc, char **argv)
124{
125 bool supports_tls = false;
126 int n = 0;
127 double elapsed_time;
128 long microsec;
129 int result = STATE_UNKNOWN;
130 char *cmd_str = NULL;
131 char *helocmd = NULL;
132 char *error_msg = "";
133 char *server_response = NULL;
134 struct timeval tv;
135 93
136 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */ 94int main(int argc, char **argv) {
137 (void) signal (SIGPIPE, SIG_IGN); 95 setlocale(LC_ALL, "");
138 96 bindtextdomain(PACKAGE, LOCALEDIR);
139 setlocale (LC_ALL, ""); 97 textdomain(PACKAGE);
140 bindtextdomain (PACKAGE, LOCALEDIR);
141 textdomain (PACKAGE);
142 98
143 /* Parse extra opts if any */ 99 /* Parse extra opts if any */
144 argv=np_extra_opts (&argc, argv, progname); 100 argv = np_extra_opts(&argc, argv, progname);
145 101
146 if (process_arguments (argc, argv) == ERROR) 102 check_smtp_config_wrapper tmp_config = process_arguments(argc, argv);
147 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;
148 109
149 /* If localhostname not set on command line, use gethostname to set */ 110 /* If localhostname not set on command line, use gethostname to set */
150 if(! localhostname){ 111 char *localhostname = config.localhostname;
151 localhostname = malloc (HOST_MAX_BYTES); 112 if (!localhostname) {
152 if(!localhostname){ 113 localhostname = malloc(HOST_MAX_BYTES);
114 if (!localhostname) {
153 printf(_("malloc() failed!\n")); 115 printf(_("malloc() failed!\n"));
154 return STATE_CRITICAL; 116 exit(STATE_CRITICAL);
155 } 117 }
156 if(gethostname(localhostname, HOST_MAX_BYTES)){ 118 if (gethostname(localhostname, HOST_MAX_BYTES)) {
157 printf(_("gethostname() failed!\n")); 119 printf(_("gethostname() failed!\n"));
158 return STATE_CRITICAL; 120 exit(STATE_CRITICAL);
159 } 121 }
160 } 122 }
161 if(use_lhlo) 123
162 xasprintf (&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n"); 124 char *helocmd = NULL;
163 else if(use_ehlo) 125 if (config.use_lhlo) {
164 xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n"); 126 xasprintf(&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n");
165 else 127 } else if (config.use_ehlo) {
166 xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n"); 128 xasprintf(&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n");
167 129 } else {
168 if (verbose) 130 xasprintf(&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n");
131 }
132
133 if (verbose) {
169 printf("HELOCMD: %s", helocmd); 134 printf("HELOCMD: %s", helocmd);
135 }
170 136
137 char *mail_command = strdup("MAIL ");
138 char *cmd_str = NULL;
171 /* initialize the MAIL command with optional FROM command */ 139 /* initialize the MAIL command with optional FROM command */
172 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");
173 141
174 if (verbose && send_mail_from) 142 if (verbose && config.send_mail_from) {
175 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);
176 148
177 /* initialize alarm signal handling */ 149 /* initialize alarm signal handling */
178 (void) signal (SIGALRM, socket_timeout_alarm_handler); 150 (void)signal(SIGALRM, socket_timeout_alarm_handler);
179 151
180 /* set socket timeout */ 152 /* set socket timeout */
181 (void) alarm (socket_timeout); 153 (void)alarm(socket_timeout);
182 154
155 struct timeval start_time;
183 /* start timer */ 156 /* start timer */
184 gettimeofday (&tv, NULL); 157 gettimeofday(&start_time, NULL);
185 158
159 int socket_descriptor = 0;
186 /* try to connect to the host at the given port number */ 160 /* try to connect to the host at the given port number */
187 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);
188 162
163 char *error_msg = "";
164 char buffer[MAX_INPUT_BUFFER];
165 bool ssl_established = false;
189 if (result == STATE_OK) { /* we connected */ 166 if (result == STATE_OK) { /* we connected */
190 /* If requested, send PROXY header */ 167 /* If requested, send PROXY header */
191 if (use_proxy_prefix) { 168 if (config.use_proxy_prefix) {
192 if (verbose) 169 if (verbose) {
193 printf ("Sending header %s\n", PROXY_PREFIX); 170 printf("Sending header %s\n", PROXY_PREFIX);
194 my_send(PROXY_PREFIX, strlen(PROXY_PREFIX)); 171 }
172 my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established);
195 } 173 }
196 174
197#ifdef HAVE_SSL 175#ifdef HAVE_SSL
198 if (use_ssl) { 176 if (config.use_ssl) {
199 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));
200 if (result != STATE_OK) { 178 if (result != STATE_OK) {
201 printf (_("CRITICAL - Cannot create SSL context.\n")); 179 printf(_("CRITICAL - Cannot create SSL context.\n"));
202 close(sd); 180 close(socket_descriptor);
203 np_net_ssl_cleanup(); 181 np_net_ssl_cleanup();
204 return STATE_CRITICAL; 182 exit(STATE_CRITICAL);
205 } else {
206 ssl_established = 1;
207 } 183 }
184 ssl_established = true;
208 } 185 }
209#endif 186#endif
210 187
211 /* watch for the SMTP connection string and */ 188 /* watch for the SMTP connection string and */
212 /* return a WARNING status if we couldn't read any data */ 189 /* return a WARNING status if we couldn't read any data */
213 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 190 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
214 printf (_("recv() failed\n")); 191 printf(_("recv() failed\n"));
215 return STATE_WARNING; 192 exit(STATE_WARNING);
216 } 193 }
217 194
195 char *server_response = NULL;
218 /* save connect return (220 hostname ..) for later use */ 196 /* save connect return (220 hostname ..) for later use */
219 xasprintf(&server_response, "%s", buffer); 197 xasprintf(&server_response, "%s", buffer);
220 198
221 /* send the HELO/EHLO command */ 199 /* send the HELO/EHLO command */
222 my_send(helocmd, strlen(helocmd)); 200 my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established);
223 201
224 /* allow for response to helo command to reach us */ 202 /* allow for response to helo command to reach us */
225 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 203 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
226 printf (_("recv() failed\n")); 204 printf(_("recv() failed\n"));
227 return STATE_WARNING; 205 exit(STATE_WARNING);
228 } else if(use_ehlo || use_lhlo){ 206 }
229 if(strstr(buffer, "250 STARTTLS") != NULL || 207
230 strstr(buffer, "250-STARTTLS") != NULL){ 208 bool supports_tls = false;
231 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;
232 } 212 }
233 } 213 }
234 214
235 if(use_starttls && ! supports_tls){ 215 if (config.use_starttls && !supports_tls) {
236 printf(_("WARNING - TLS not supported by server\n")); 216 printf(_("WARNING - TLS not supported by server\n"));
237 smtp_quit(); 217 smtp_quit(config, buffer, socket_descriptor, ssl_established);
238 return STATE_WARNING; 218 exit(STATE_WARNING);
239 } 219 }
240 220
241#ifdef HAVE_SSL 221#ifdef HAVE_SSL
242 if(use_starttls) { 222 if (config.use_starttls) {
243 /* send the STARTTLS command */ 223 /* send the STARTTLS command */
244 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); 224 send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
245 225
246 recvlines(buffer, MAX_INPUT_BUFFER); /* wait for it */ 226 recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established); /* wait for it */
247 if (!strstr (buffer, SMTP_EXPECT)) { 227 if (!strstr(buffer, SMTP_EXPECT)) {
248 printf (_("Server does not support STARTTLS\n")); 228 printf(_("Server does not support STARTTLS\n"));
249 smtp_quit(); 229 smtp_quit(config, buffer, socket_descriptor, ssl_established);
250 return STATE_UNKNOWN; 230 exit(STATE_UNKNOWN);
251 } 231 }
252 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL)); 232
253 if(result != STATE_OK) { 233 result = np_net_ssl_init_with_hostname(socket_descriptor, (config.use_sni ? config.server_address : NULL));
254 printf (_("CRITICAL - Cannot create SSL context.\n")); 234 if (result != STATE_OK) {
255 close(sd); 235 printf(_("CRITICAL - Cannot create SSL context.\n"));
256 np_net_ssl_cleanup(); 236 close(socket_descriptor);
257 return STATE_CRITICAL; 237 np_net_ssl_cleanup();
258 } else { 238 exit(STATE_CRITICAL);
259 ssl_established = 1; 239 }
260 } 240
261 241 ssl_established = true;
262 /* 242
263 * Resend the EHLO command. 243 /*
264 * 244 * Resend the EHLO command.
265 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge 245 *
266 * obtained from the server, such as the list of SMTP service 246 * RFC 3207 (4.2) says: ``The client MUST discard any knowledge
267 * extensions, which was not obtained from the TLS negotiation 247 * obtained from the server, such as the list of SMTP service
268 * itself. The client SHOULD send an EHLO command as the first 248 * extensions, which was not obtained from the TLS negotiation
269 * command after a successful TLS negotiation.'' For this 249 * itself. The client SHOULD send an EHLO command as the first
270 * reason, some MTAs will not allow an AUTH LOGIN command before 250 * command after a successful TLS negotiation.'' For this
271 * we resent EHLO via TLS. 251 * reason, some MTAs will not allow an AUTH LOGIN command before
272 */ 252 * we resent EHLO via TLS.
273 if (my_send(helocmd, strlen(helocmd)) <= 0) { 253 */
274 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS.")); 254 if (my_send(config, helocmd, strlen(helocmd), socket_descriptor, ssl_established) <= 0) {
275 my_close(); 255 printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS."));
276 return STATE_UNKNOWN; 256 my_close(socket_descriptor);
277 } 257 exit(STATE_UNKNOWN);
278 if (verbose) 258 }
279 printf(_("sent %s"), helocmd); 259
280 if ((n = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 260 if (verbose) {
281 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS.")); 261 printf(_("sent %s"), helocmd);
282 my_close(); 262 }
283 return STATE_UNKNOWN;
284 }
285 if (verbose) {
286 printf("%s", buffer);
287 }
288 263
289# ifdef USE_OPENSSL 264 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) {
290 if ( check_cert ) { 265 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS."));
291 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 266 my_close(socket_descriptor);
292 smtp_quit(); 267 exit(STATE_UNKNOWN);
293 my_close(); 268 }
294 return result; 269
295 } 270 if (verbose) {
296# 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 */
297 } 282 }
298#endif 283#endif
299 284
300 if (verbose) 285 if (verbose) {
301 printf ("%s", buffer); 286 printf("%s", buffer);
287 }
302 288
303 /* save buffer for later use */ 289 /* save buffer for later use */
304 xasprintf(&server_response, "%s%s", server_response, buffer); 290 xasprintf(&server_response, "%s%s", server_response, buffer);
305 /* strip the buffer of carriage returns */ 291 /* strip the buffer of carriage returns */
306 strip (server_response); 292 strip(server_response);
307 293
308 /* make sure we find the droids we are looking for */ 294 /* make sure we find the droids we are looking for */
309 if (!strstr (server_response, server_expect)) { 295 if (!strstr(server_response, config.server_expect)) {
310 if (server_port == SMTP_PORT) 296 if (config.server_port == SMTP_PORT) {
311 printf (_("Invalid SMTP response received from host: %s\n"), server_response); 297 printf(_("Invalid SMTP response received from host: %s\n"), server_response);
312 else 298 } else {
313 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);
314 server_port, server_response); 300 }
315 return STATE_WARNING; 301 exit(STATE_WARNING);
316 } 302 }
317 303
318 if (send_mail_from) { 304 if (config.send_mail_from) {
319 my_send(cmd_str, strlen(cmd_str)); 305 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
320 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 306 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && verbose) {
321 printf("%s", buffer); 307 printf("%s", buffer);
308 }
322 } 309 }
323 310
324 n = 0; 311 int counter = 0;
325 while (n < ncommands) { 312 while (counter < config.ncommands) {
326 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n"); 313 xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n");
327 my_send(cmd_str, strlen(cmd_str)); 314 my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established);
328 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 315 if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && verbose) {
329 printf("%s", buffer); 316 printf("%s", buffer);
330 strip (buffer); 317 }
331 if (n < nresponses) { 318 strip(buffer);
332 cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 319 if (counter < config.nresponses) {
333 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];
334 if (errcode != 0) { 324 if (errcode != 0) {
335 regerror (errcode, &preg, errbuf, MAX_INPUT_BUFFER); 325 regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER);
336 printf (_("Could Not Compile Regular Expression")); 326 printf(_("Could Not Compile Regular Expression"));
337 return ERROR; 327 exit(STATE_UNKNOWN);
338 } 328 }
339 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);
340 if (excode == 0) { 333 if (excode == 0) {
341 result = STATE_OK; 334 result = STATE_OK;
342 } 335 } else if (excode == REG_NOMATCH) {
343 else if (excode == REG_NOMATCH) {
344 result = STATE_WARNING; 336 result = STATE_WARNING;
345 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]);
346 } 338 } else {
347 else { 339 regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER);
348 regerror (excode, &preg, errbuf, MAX_INPUT_BUFFER); 340 printf(_("Execute Error: %s\n"), errbuf);
349 printf (_("Execute Error: %s\n"), errbuf);
350 result = STATE_UNKNOWN; 341 result = STATE_UNKNOWN;
351 } 342 }
352 } 343 }
353 n++; 344 counter++;
354 } 345 }
355 346
356 if (authtype != NULL) { 347 if (config.authtype != NULL) {
357 if (strcmp (authtype, "LOGIN") == 0) { 348 if (strcmp(config.authtype, "LOGIN") == 0) {
358 char *abuf; 349 char *abuf;
359 int ret; 350 int ret;
360 do { 351 do {
361 if (authuser == NULL) { 352 if (config.authuser == NULL) {
362 result = STATE_CRITICAL; 353 result = STATE_CRITICAL;
363 xasprintf(&error_msg, _("no authuser specified, ")); 354 xasprintf(&error_msg, _("no authuser specified, "));
364 break; 355 break;
365 } 356 }
366 if (authpass == NULL) { 357 if (config.authpass == NULL) {
367 result = STATE_CRITICAL; 358 result = STATE_CRITICAL;
368 xasprintf(&error_msg, _("no authpass specified, ")); 359 xasprintf(&error_msg, _("no authpass specified, "));
369 break; 360 break;
370 } 361 }
371 362
372 /* send AUTH LOGIN */ 363 /* send AUTH LOGIN */
373 my_send(SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN)); 364 my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor, ssl_established);
374 if (verbose) 365 if (verbose) {
375 printf (_("sent %s\n"), "AUTH LOGIN"); 366 printf(_("sent %s\n"), "AUTH LOGIN");
367 }
376 368
377 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 369 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
378 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, ")); 370 xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, "));
379 result = STATE_WARNING; 371 result = STATE_WARNING;
380 break; 372 break;
381 } 373 }
382 if (verbose) 374 if (verbose) {
383 printf (_("received %s\n"), buffer); 375 printf(_("received %s\n"), buffer);
376 }
384 377
385 if (strncmp (buffer, "334", 3) != 0) { 378 if (strncmp(buffer, "334", 3) != 0) {
386 result = STATE_CRITICAL; 379 result = STATE_CRITICAL;
387 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, ")); 380 xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, "));
388 break; 381 break;
389 } 382 }
390 383
391 /* encode authuser with base64 */ 384 /* encode authuser with base64 */
392 base64_encode_alloc (authuser, strlen(authuser), &abuf); 385 base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf);
393 xasprintf(&abuf, "%s\r\n", abuf); 386 xasprintf(&abuf, "%s\r\n", abuf);
394 my_send(abuf, strlen(abuf)); 387 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
395 if (verbose) 388 if (verbose) {
396 printf (_("sent %s\n"), abuf); 389 printf(_("sent %s\n"), abuf);
390 }
397 391
398 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 392 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
399 result = STATE_CRITICAL; 393 result = STATE_CRITICAL;
400 xasprintf(&error_msg, _("recv() failed after sending authuser, ")); 394 xasprintf(&error_msg, _("recv() failed after sending authuser, "));
401 break; 395 break;
402 } 396 }
403 if (verbose) { 397 if (verbose) {
404 printf (_("received %s\n"), buffer); 398 printf(_("received %s\n"), buffer);
405 } 399 }
406 if (strncmp (buffer, "334", 3) != 0) { 400 if (strncmp(buffer, "334", 3) != 0) {
407 result = STATE_CRITICAL; 401 result = STATE_CRITICAL;
408 xasprintf(&error_msg, _("invalid response received after authuser, ")); 402 xasprintf(&error_msg, _("invalid response received after authuser, "));
409 break; 403 break;
410 } 404 }
411 /* encode authpass with base64 */ 405 /* encode authpass with base64 */
412 base64_encode_alloc (authpass, strlen(authpass), &abuf); 406 base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf);
413 xasprintf(&abuf, "%s\r\n", abuf); 407 xasprintf(&abuf, "%s\r\n", abuf);
414 my_send(abuf, strlen(abuf)); 408 my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established);
415 if (verbose) { 409 if (verbose) {
416 printf (_("sent %s\n"), abuf); 410 printf(_("sent %s\n"), abuf);
417 } 411 }
418 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) { 412 if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established)) <= 0) {
419 result = STATE_CRITICAL; 413 result = STATE_CRITICAL;
420 xasprintf(&error_msg, _("recv() failed after sending authpass, ")); 414 xasprintf(&error_msg, _("recv() failed after sending authpass, "));
421 break; 415 break;
422 } 416 }
423 if (verbose) { 417 if (verbose) {
424 printf (_("received %s\n"), buffer); 418 printf(_("received %s\n"), buffer);
425 } 419 }
426 if (strncmp (buffer, "235", 3) != 0) { 420 if (strncmp(buffer, "235", 3) != 0) {
427 result = STATE_CRITICAL; 421 result = STATE_CRITICAL;
428 xasprintf(&error_msg, _("invalid response received after authpass, ")); 422 xasprintf(&error_msg, _("invalid response received after authpass, "));
429 break; 423 break;
430 } 424 }
431 break; 425 break;
432 } while (0); 426 } while (false);
433 } else { 427 } else {
434 result = STATE_CRITICAL; 428 result = STATE_CRITICAL;
435 xasprintf(&error_msg, _("only authtype LOGIN is supported, ")); 429 xasprintf(&error_msg, _("only authtype LOGIN is supported, "));
@@ -437,243 +431,243 @@ main (int argc, char **argv)
437 } 431 }
438 432
439 /* tell the server we're done */ 433 /* tell the server we're done */
440 smtp_quit(); 434 smtp_quit(config, buffer, socket_descriptor, ssl_established);
441 435
442 /* finally close the connection */ 436 /* finally close the connection */
443 close (sd); 437 close(socket_descriptor);
444 } 438 }
445 439
446 /* reset the alarm */ 440 /* reset the alarm */
447 alarm (0); 441 alarm(0);
448 442
449 microsec = deltime (tv); 443 long microsec = deltime(start_time);
450 elapsed_time = (double)microsec / 1.0e6; 444 double elapsed_time = (double)microsec / 1.0e6;
451 445
452 if (result == STATE_OK) { 446 if (result == STATE_OK) {
453 if (check_critical_time && elapsed_time > critical_time) 447 if (config.check_critical_time && elapsed_time > config.critical_time) {
454 result = STATE_CRITICAL; 448 result = STATE_CRITICAL;
455 else if (check_warning_time && elapsed_time > warning_time) 449 } else if (config.check_warning_time && elapsed_time > config.warning_time) {
456 result = STATE_WARNING; 450 result = STATE_WARNING;
451 }
457 } 452 }
458 453
459 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 ? ", " : "",
460 state_text (result), 455 verbose ? buffer : "",
461 error_msg, 456 fperfdata("time", elapsed_time, "s", config.check_warning_time, config.warning_time, config.check_critical_time,
462 elapsed_time, 457 config.critical_time, true, 0, false, 0));
463 verbose?", ":"", verbose?buffer:"",
464 fperfdata ("time", elapsed_time, "s",
465 (int)check_warning_time, warning_time,
466 (int)check_critical_time, critical_time,
467 true, 0, false, 0));
468 458
469 return result; 459 exit(result);
470} 460}
471 461
472
473
474/* process command-line arguments */ 462/* process command-line arguments */
475int 463check_smtp_config_wrapper process_arguments(int argc, char **argv) {
476process_arguments (int argc, char **argv)
477{
478 int c;
479 char* temp;
480
481 bool implicit_tls = false;
482
483 enum { 464 enum {
484 SNI_OPTION 465 SNI_OPTION = CHAR_MAX + 1
485 }; 466 };
486 467
487 int option = 0; 468 int option = 0;
488 static struct option longopts[] = { 469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
489 {"hostname", required_argument, 0, 'H'}, 470 {"expect", required_argument, 0, 'e'},
490 {"expect", required_argument, 0, 'e'}, 471 {"critical", required_argument, 0, 'c'},
491 {"critical", required_argument, 0, 'c'}, 472 {"warning", required_argument, 0, 'w'},
492 {"warning", required_argument, 0, 'w'}, 473 {"timeout", required_argument, 0, 't'},
493 {"timeout", required_argument, 0, 't'}, 474 {"port", required_argument, 0, 'p'},
494 {"port", required_argument, 0, 'p'}, 475 {"from", required_argument, 0, 'f'},
495 {"from", required_argument, 0, 'f'}, 476 {"fqdn", required_argument, 0, 'F'},
496 {"fqdn", required_argument, 0, 'F'}, 477 {"authtype", required_argument, 0, 'A'},
497 {"authtype", required_argument, 0, 'A'}, 478 {"authuser", required_argument, 0, 'U'},
498 {"authuser", required_argument, 0, 'U'}, 479 {"authpass", required_argument, 0, 'P'},
499 {"authpass", required_argument, 0, 'P'}, 480 {"command", required_argument, 0, 'C'},
500 {"command", required_argument, 0, 'C'}, 481 {"response", required_argument, 0, 'R'},
501 {"response", required_argument, 0, 'R'}, 482 {"verbose", no_argument, 0, 'v'},
502 {"verbose", no_argument, 0, 'v'}, 483 {"version", no_argument, 0, 'V'},
503 {"version", no_argument, 0, 'V'}, 484 {"use-ipv4", no_argument, 0, '4'},
504 {"use-ipv4", no_argument, 0, '4'}, 485 {"use-ipv6", no_argument, 0, '6'},
505 {"use-ipv6", no_argument, 0, '6'}, 486 {"help", no_argument, 0, 'h'},
506 {"help", no_argument, 0, 'h'}, 487 {"lmtp", no_argument, 0, 'L'},
507 {"lmtp", no_argument, 0, 'L'}, 488 {"ssl", no_argument, 0, 's'},
508 {"ssl", no_argument, 0, 's'}, 489 {"tls", no_argument, 0, 's'},
509 {"tls", no_argument, 0, 's'}, 490 {"starttls", no_argument, 0, 'S'},
510 {"starttls",no_argument,0,'S'}, 491 {"sni", no_argument, 0, SNI_OPTION},
511 {"sni", no_argument, 0, SNI_OPTION}, 492 {"certificate", required_argument, 0, 'D'},
512 {"certificate",required_argument,0,'D'}, 493 {"ignore-quit-failure", no_argument, 0, 'q'},
513 {"ignore-quit-failure",no_argument,0,'q'}, 494 {"proxy", no_argument, 0, 'r'},
514 {"proxy",no_argument,0,'r'}, 495 {0, 0, 0, 0}};
515 {0, 0, 0, 0} 496
497 check_smtp_config_wrapper result = {
498 .config = check_smtp_config_init(),
499 .errorcode = OK,
516 }; 500 };
517 501
518 if (argc < 2) 502 if (argc < 2) {
519 return ERROR; 503 result.errorcode = ERROR;
504 return result;
505 }
520 506
521 for (c = 1; c < argc; c++) { 507 for (int index = 1; index < argc; index++) {
522 if (strcmp ("-to", argv[c]) == 0) 508 if (strcmp("-to", argv[index]) == 0) {
523 strcpy (argv[c], "-t"); 509 strcpy(argv[index], "-t");
524 else if (strcmp ("-wt", argv[c]) == 0) 510 } else if (strcmp("-wt", argv[index]) == 0) {
525 strcpy (argv[c], "-w"); 511 strcpy(argv[index], "-w");
526 else if (strcmp ("-ct", argv[c]) == 0) 512 } else if (strcmp("-ct", argv[index]) == 0) {
527 strcpy (argv[c], "-c"); 513 strcpy(argv[index], "-c");
514 }
528 } 515 }
529 516
530 while (1) { 517 int command_size = 0;
531 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;
532 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);
533 523
534 if (c == -1 || c == EOF) 524 if (opt_index == -1 || opt_index == EOF) {
535 break; 525 break;
526 }
536 527
537 switch (c) { 528 switch (opt_index) {
538 case 'H': /* hostname */ 529 case 'H': /* hostname */
539 if (is_host (optarg)) { 530 if (is_host(optarg)) {
540 server_address = optarg; 531 result.config.server_address = optarg;
541 } 532 } else {
542 else { 533 usage2(_("Invalid hostname/address"), optarg);
543 usage2 (_("Invalid hostname/address"), optarg);
544 } 534 }
545 break; 535 break;
546 case 'p': /* port */ 536 case 'p': /* port */
547 if (is_intpos (optarg)) 537 if (is_intpos(optarg)) {
548 server_port_option = atoi (optarg); 538 server_port_option = atoi(optarg);
549 else 539 } else {
550 usage4 (_("Port must be a positive integer")); 540 usage4(_("Port must be a positive integer"));
541 }
551 break; 542 break;
552 case 'F': 543 case 'F':
553 /* localhostname */ 544 /* localhostname */
554 localhostname = strdup(optarg); 545 result.config.localhostname = strdup(optarg);
555 break; 546 break;
556 case 'f': /* from argument */ 547 case 'f': /* from argument */
557 from_arg = optarg + strspn(optarg, "<"); 548 result.config.from_arg = optarg + strspn(optarg, "<");
558 from_arg = strndup(from_arg, strcspn(from_arg, ">")); 549 result.config.from_arg = strndup(result.config.from_arg, strcspn(result.config.from_arg, ">"));
559 send_mail_from = 1; 550 result.config.send_mail_from = true;
560 break; 551 break;
561 case 'A': 552 case 'A':
562 authtype = optarg; 553 result.config.authtype = optarg;
563 use_ehlo = true; 554 result.config.use_ehlo = true;
564 break; 555 break;
565 case 'U': 556 case 'U':
566 authuser = optarg; 557 result.config.authuser = optarg;
567 break; 558 break;
568 case 'P': 559 case 'P':
569 authpass = optarg; 560 result.config.authpass = optarg;
570 break; 561 break;
571 case 'e': /* server expect string on 220 */ 562 case 'e': /* server expect string on 220 */
572 server_expect = optarg; 563 result.config.server_expect = optarg;
573 break; 564 break;
574 case 'C': /* commands */ 565 case 'C': /* commands */
575 if (ncommands >= command_size) { 566 if (result.config.ncommands >= command_size) {
576 command_size+=8; 567 command_size += 8;
577 commands = realloc (commands, sizeof(char *) * command_size); 568 result.config.commands = realloc(result.config.commands, sizeof(char *) * command_size);
578 if (commands == NULL) 569 if (result.config.commands == NULL) {
579 die (STATE_UNKNOWN, 570 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), result.config.ncommands);
580 _("Could not realloc() units [%d]\n"), ncommands); 571 }
581 } 572 }
582 commands[ncommands] = (char *) malloc (sizeof(char) * 255); 573 result.config.commands[result.config.ncommands] = (char *)malloc(sizeof(char) * 255);
583 strncpy (commands[ncommands], optarg, 255); 574 strncpy(result.config.commands[result.config.ncommands], optarg, 255);
584 ncommands++; 575 result.config.ncommands++;
585 break; 576 break;
586 case 'R': /* server responses */ 577 case 'R': /* server responses */
587 if (nresponses >= response_size) { 578 if (result.config.nresponses >= response_size) {
588 response_size += 8; 579 response_size += 8;
589 responses = realloc (responses, sizeof(char *) * response_size); 580 result.config.responses = realloc(result.config.responses, sizeof(char *) * response_size);
590 if (responses == NULL) 581 if (result.config.responses == NULL) {
591 die (STATE_UNKNOWN, 582 die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), result.config.nresponses);
592 _("Could not realloc() units [%d]\n"), nresponses); 583 }
593 } 584 }
594 responses[nresponses] = (char *) malloc (sizeof(char) * 255); 585 result.config.responses[result.config.nresponses] = (char *)malloc(sizeof(char) * 255);
595 strncpy (responses[nresponses], optarg, 255); 586 strncpy(result.config.responses[result.config.nresponses], optarg, 255);
596 nresponses++; 587 result.config.nresponses++;
597 break; 588 break;
598 case 'c': /* critical time threshold */ 589 case 'c': /* critical time threshold */
599 if (!is_nonnegative (optarg)) 590 if (!is_nonnegative(optarg)) {
600 usage4 (_("Critical time must be a positive")); 591 usage4(_("Critical time must be a positive"));
601 else { 592 } else {
602 critical_time = strtod (optarg, NULL); 593 result.config.critical_time = strtod(optarg, NULL);
603 check_critical_time = true; 594 result.config.check_critical_time = true;
604 } 595 }
605 break; 596 break;
606 case 'w': /* warning time threshold */ 597 case 'w': /* warning time threshold */
607 if (!is_nonnegative (optarg)) 598 if (!is_nonnegative(optarg)) {
608 usage4 (_("Warning time must be a positive")); 599 usage4(_("Warning time must be a positive"));
609 else { 600 } else {
610 warning_time = strtod (optarg, NULL); 601 result.config.warning_time = strtod(optarg, NULL);
611 check_warning_time = true; 602 result.config.check_warning_time = true;
612 } 603 }
613 break; 604 break;
614 case 'v': /* verbose */ 605 case 'v': /* verbose */
615 verbose++; 606 verbose++;
616 break; 607 break;
617 case 'q': 608 case 'q':
618 ignore_send_quit_failure = true; /* ignore problem sending QUIT */ 609 result.config.ignore_send_quit_failure = true; /* ignore problem sending QUIT */
619 break; 610 break;
620 case 't': /* timeout */ 611 case 't': /* timeout */
621 if (is_intnonneg (optarg)) { 612 if (is_intnonneg(optarg)) {
622 socket_timeout = atoi (optarg); 613 socket_timeout = atoi(optarg);
623 } 614 } else {
624 else { 615 usage4(_("Timeout interval must be a positive integer"));
625 usage4 (_("Timeout interval must be a positive integer"));
626 } 616 }
627 break; 617 break;
628 case 'D': 618 case 'D': {
629 /* Check SSL cert validity */ 619 /* Check SSL cert validity */
630#ifdef USE_OPENSSL 620#ifdef USE_OPENSSL
631 if ((temp=strchr(optarg,','))!=NULL) { 621 char *temp;
632 *temp='\0'; 622 if ((temp = strchr(optarg, ',')) != NULL) {
633 if (!is_intnonneg (optarg)) 623 *temp = '\0';
634 usage2 ("Invalid certificate expiration period", optarg); 624 if (!is_intnonneg(optarg)) {
635 days_till_exp_warn = atoi(optarg); 625 usage2("Invalid certificate expiration period", optarg);
636 *temp=','; 626 }
637 temp++; 627 result.config.days_till_exp_warn = atoi(optarg);
638 if (!is_intnonneg (temp)) 628 *temp = ',';
639 usage2 (_("Invalid certificate expiration period"), temp); 629 temp++;
640 days_till_exp_crit = atoi (temp); 630 if (!is_intnonneg(temp)) {
641 } 631 usage2(_("Invalid certificate expiration period"), temp);
642 else { 632 }
643 days_till_exp_crit=0; 633 result.config.days_till_exp_crit = atoi(temp);
644 if (!is_intnonneg (optarg)) 634 } else {
645 usage2 ("Invalid certificate expiration period", optarg); 635 result.config.days_till_exp_crit = 0;
646 days_till_exp_warn = atoi (optarg); 636 if (!is_intnonneg(optarg)) {
647 } 637 usage2("Invalid certificate expiration period", optarg);
648 check_cert = true; 638 }
649 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;
650#else 643#else
651 usage (_("SSL support not available - install OpenSSL and recompile")); 644 usage(_("SSL support not available - install OpenSSL and recompile"));
652#endif 645#endif
653 implicit_tls = true; 646 implicit_tls = true;
654 // fallthrough 647 // fallthrough
655 case 's': 648 case 's':
656 /* ssl */ 649 /* ssl */
657 use_ssl = true; 650 result.config.use_ssl = true;
658 server_port = SMTPS_PORT; 651 result.config.server_port = SMTPS_PORT;
659 break; 652 break;
660 case 'S': 653 case 'S':
661 /* starttls */ 654 /* starttls */
662 use_starttls = true; 655 result.config.use_starttls = true;
663 use_ehlo = true; 656 result.config.use_ehlo = true;
664 break; 657 break;
658 }
665 case SNI_OPTION: 659 case SNI_OPTION:
666#ifdef HAVE_SSL 660#ifdef HAVE_SSL
667 use_sni = true; 661 result.config.use_sni = true;
668#else 662#else
669 usage (_("SSL support not available - install OpenSSL and recompile")); 663 usage(_("SSL support not available - install OpenSSL and recompile"));
670#endif 664#endif
671 break; 665 break;
672 case 'r': 666 case 'r':
673 use_proxy_prefix = true; 667 result.config.use_proxy_prefix = true;
674 break; 668 break;
675 case 'L': 669 case 'L':
676 use_lhlo = true; 670 result.config.use_lhlo = true;
677 break; 671 break;
678 case '4': 672 case '4':
679 address_family = AF_INET; 673 address_family = AF_INET;
@@ -682,102 +676,79 @@ process_arguments (int argc, char **argv)
682#ifdef USE_IPV6 676#ifdef USE_IPV6
683 address_family = AF_INET6; 677 address_family = AF_INET6;
684#else 678#else
685 usage4 (_("IPv6 support not available")); 679 usage4(_("IPv6 support not available"));
686#endif 680#endif
687 break; 681 break;
688 case 'V': /* version */ 682 case 'V': /* version */
689 print_revision (progname, NP_VERSION); 683 print_revision(progname, NP_VERSION);
690 exit (STATE_UNKNOWN); 684 exit(STATE_UNKNOWN);
691 case 'h': /* help */ 685 case 'h': /* help */
692 print_help (); 686 print_help();
693 exit (STATE_UNKNOWN); 687 exit(STATE_UNKNOWN);
694 case '?': /* help */ 688 case '?': /* help */
695 usage5 (); 689 usage5();
696 } 690 }
697 } 691 }
698 692
699 c = optind; 693 int c = optind;
700 if (server_address == NULL) { 694 if (result.config.server_address == NULL) {
701 if (argv[c]) { 695 if (argv[c]) {
702 if (is_host (argv[c])) 696 if (is_host(argv[c])) {
703 server_address = argv[c]; 697 result.config.server_address = argv[c];
704 else 698 } else {
705 usage2 (_("Invalid hostname/address"), argv[c]); 699 usage2(_("Invalid hostname/address"), argv[c]);
706 } 700 }
707 else { 701 } else {
708 xasprintf (&server_address, "127.0.0.1"); 702 result.config.server_address = strdup("localhost");
709 } 703 }
710 } 704 }
711 705
712 if (server_expect == NULL) 706 if (result.config.use_starttls && result.config.use_ssl) {
713 server_expect = strdup (SMTP_EXPECT);
714
715 if (mail_command == NULL)
716 mail_command = strdup("MAIL ");
717
718 if (from_arg==NULL)
719 from_arg = strdup(" ");
720
721 if (use_starttls && use_ssl) {
722 if (implicit_tls) { 707 if (implicit_tls) {
723 use_ssl = false; 708 result.config.use_ssl = false;
724 server_port = SMTP_PORT;
725 } else { 709 } else {
726 usage4 (_("Set either -s/--ssl/--tls or -S/--starttls")); 710 usage4(_("Set either -s/--ssl/--tls or -S/--starttls"));
727 } 711 }
728 } 712 }
729 713
730 if (server_port_option != 0) { 714 if (server_port_option != 0) {
731 server_port = server_port_option; 715 result.config.server_port = server_port_option;
732 } 716 }
733 717
734 return validate_arguments (); 718 return result;
735}
736
737
738
739int
740validate_arguments (void)
741{
742 return OK;
743} 719}
744 720
745 721char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int socket_descriptor, bool ssl_established) {
746void 722 int sent_bytes = my_send(config, SMTP_QUIT, strlen(SMTP_QUIT), socket_descriptor, ssl_established);
747smtp_quit(void) 723 if (sent_bytes < 0) {
748{ 724 if (config.ignore_send_quit_failure) {
749 int bytes; 725 if (verbose) {
750 int n;
751
752 n = my_send(SMTP_QUIT, strlen(SMTP_QUIT));
753 if(n < 0) {
754 if(ignore_send_quit_failure) {
755 if(verbose) {
756 printf(_("Connection closed by server before sending QUIT command\n")); 726 printf(_("Connection closed by server before sending QUIT command\n"));
757 } 727 }
758 return; 728 return buffer;
759 } 729 }
760 die (STATE_UNKNOWN, 730 die(STATE_UNKNOWN, _("Connection closed by server before sending QUIT command\n"));
761 _("Connection closed by server before sending QUIT command\n"));
762 } 731 }
763 732
764 if (verbose) 733 if (verbose) {
765 printf(_("sent %s\n"), "QUIT"); 734 printf(_("sent %s\n"), "QUIT");
735 }
766 736
767 /* read the response but don't care about problems */ 737 /* read the response but don't care about problems */
768 bytes = recvlines(buffer, MAX_INPUT_BUFFER); 738 int bytes = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established);
769 if (verbose) { 739 if (verbose) {
770 if (bytes < 0) 740 if (bytes < 0) {
771 printf(_("recv() failed after QUIT.")); 741 printf(_("recv() failed after QUIT."));
772 else if (bytes == 0) 742 } else if (bytes == 0) {
773 printf(_("Connection reset by peer.")); 743 printf(_("Connection reset by peer."));
774 else { 744 } else {
775 buffer[bytes] = '\0'; 745 buffer[bytes] = '\0';
776 printf(_("received %s\n"), buffer); 746 printf(_("received %s\n"), buffer);
777 } 747 }
778 } 748 }
779}
780 749
750 return buffer;
751}
781 752
782/* 753/*
783 * 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
@@ -788,24 +759,22 @@ smtp_quit(void)
788 * 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
789 * 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.
790 */ 761 */
791int 762int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor, bool ssl_established) {
792recvline(char *buf, size_t bufsize)
793{
794 int result; 763 int result;
795 unsigned i; 764 int counter;
796 765
797 for (i = result = 0; i < bufsize - 1; i++) { 766 for (counter = result = 0; counter < bufsize - 1; counter++) {
798 if ((result = my_recv(&buf[i], 1)) != 1) 767 if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) {
799 break; 768 break;
800 if (buf[i] == '\n') { 769 }
801 buf[++i] = '\0'; 770 if (buf[counter] == '\n') {
802 return i; 771 buf[++counter] = '\0';
772 return counter;
803 } 773 }
804 } 774 }
805 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 */
806} 776}
807 777
808
809/* 778/*
810 * 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
811 * 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
@@ -820,117 +789,103 @@ recvline(char *buf, size_t bufsize)
820 * 789 *
821 * 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.
822 */ 791 */
823int 792int recvlines(check_smtp_config config, char *buf, size_t bufsize, int socket_descriptor, bool ssl_established) {
824recvlines(char *buf, size_t bufsize) 793 int result;
825{ 794 int counter;
826 int result, i; 795
827 796 for (counter = 0; /* forever */; counter += result) {
828 for (i = 0; /* forever */; i += result) 797 if (!((result = recvline(buf + counter, bufsize - counter, config, socket_descriptor, ssl_established)) > 3 &&
829 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] == '-')) {
830 isdigit((int)buf[i]) &&
831 isdigit((int)buf[i + 1]) &&
832 isdigit((int)buf[i + 2]) &&
833 buf[i + 3] == '-'))
834 break; 799 break;
800 }
801 }
835 802
836 return (result <= 0) ? result : result + i; 803 return (result <= 0) ? result : result + counter;
837} 804}
838 805
839 806int my_close(int socket_descriptor) {
840int
841my_close (void)
842{
843 int result; 807 int result;
844 result = close(sd); 808 result = close(socket_descriptor);
845#ifdef HAVE_SSL 809#ifdef HAVE_SSL
846 np_net_ssl_cleanup(); 810 np_net_ssl_cleanup();
847#endif 811#endif
848 return result; 812 return result;
849} 813}
850 814
851 815void print_help(void) {
852void
853print_help (void)
854{
855 char *myport; 816 char *myport;
856 xasprintf (&myport, "%d", SMTP_PORT); 817 xasprintf(&myport, "%d", SMTP_PORT);
857 818
858 print_revision (progname, NP_VERSION); 819 print_revision(progname, NP_VERSION);
859 820
860 printf ("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n"); 821 printf("Copyright (c) 1999-2001 Ethan Galstad <nagios@nagios.org>\n");
861 printf (COPYRIGHT, copyright, email); 822 printf(COPYRIGHT, copyright, email);
862 823
863 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."));
864 825
865 printf ("\n\n"); 826 printf("\n\n");
866 827
867 print_usage (); 828 print_usage();
868 829
869 printf (UT_HELP_VRSN); 830 printf(UT_HELP_VRSN);
870 printf (UT_EXTRA_OPTS); 831 printf(UT_EXTRA_OPTS);
871 832
872 printf (UT_HOST_PORT, 'p', myport); 833 printf(UT_HOST_PORT, 'p', myport);
873 834
874 printf (UT_IPv46); 835 printf(UT_IPv46);
875 836
876 printf (" %s\n", "-e, --expect=STRING"); 837 printf(" %s\n", "-e, --expect=STRING");
877 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);
878 printf (" %s\n", "-C, --command=STRING"); 839 printf(" %s\n", "-C, --command=STRING");
879 printf (" %s\n", _("SMTP command (may be used repeatedly)")); 840 printf(" %s\n", _("SMTP command (may be used repeatedly)"));
880 printf (" %s\n", "-R, --response=STRING"); 841 printf(" %s\n", "-R, --response=STRING");
881 printf (" %s\n", _("Expected response to command (may be used repeatedly)")); 842 printf(" %s\n", _("Expected response to command (may be used repeatedly)"));
882 printf (" %s\n", "-f, --from=STRING"); 843 printf(" %s\n", "-f, --from=STRING");
883 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");
884 printf (" %s\n", "-F, --fqdn=STRING"); 845 printf(" %s\n", _("FQDN used for HELO"));
885 printf (" %s\n", _("FQDN used for HELO")); 846 printf(" %s\n", "-r, --proxy");
886 printf (" %s\n", "-r, --proxy"); 847 printf(" %s\n", _("Use PROXY protocol prefix for the connection."));
887 printf (" %s\n", _("Use PROXY protocol prefix for the connection."));
888#ifdef HAVE_SSL 848#ifdef HAVE_SSL
889 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 849 printf(" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
890 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."));
891 printf (" %s\n", "-s, --ssl, --tls"); 851 printf(" %s\n", "-s, --ssl, --tls");
892 printf (" %s\n", _("Use SSL/TLS for the connection.")); 852 printf(" %s\n", _("Use SSL/TLS for the connection."));
893 printf (_(" Sets default port to %d.\n"), SMTPS_PORT); 853 printf(_(" Sets default port to %d.\n"), SMTPS_PORT);
894 printf (" %s\n", "-S, --starttls"); 854 printf(" %s\n", "-S, --starttls");
895 printf (" %s\n", _("Use STARTTLS for the connection.")); 855 printf(" %s\n", _("Use STARTTLS for the connection."));
896 printf (" %s\n", "--sni"); 856 printf(" %s\n", "--sni");
897 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)")); 857 printf(" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
898#endif 858#endif
899 859
900 printf (" %s\n", "-A, --authtype=STRING"); 860 printf(" %s\n", "-A, --authtype=STRING");
901 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)"));
902 printf (" %s\n", "-U, --authuser=STRING"); 862 printf(" %s\n", "-U, --authuser=STRING");
903 printf (" %s\n", _("SMTP AUTH username")); 863 printf(" %s\n", _("SMTP AUTH username"));
904 printf (" %s\n", "-P, --authpass=STRING"); 864 printf(" %s\n", "-P, --authpass=STRING");
905 printf (" %s\n", _("SMTP AUTH password")); 865 printf(" %s\n", _("SMTP AUTH password"));
906 printf (" %s\n", "-L, --lmtp"); 866 printf(" %s\n", "-L, --lmtp");
907 printf (" %s\n", _("Send LHLO instead of HELO/EHLO")); 867 printf(" %s\n", _("Send LHLO instead of HELO/EHLO"));
908 printf (" %s\n", "-q, --ignore-quit-failure"); 868 printf(" %s\n", "-q, --ignore-quit-failure");
909 printf (" %s\n", _("Ignore failure when sending QUIT command to server")); 869 printf(" %s\n", _("Ignore failure when sending QUIT command to server"));
910
911 printf (UT_WARN_CRIT);
912 870
913 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 871 printf(UT_WARN_CRIT);
914 872
915 printf (UT_VERBOSE); 873 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
874
875 printf(UT_VERBOSE);
916 876
917 printf("\n"); 877 printf("\n");
918 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"));
919 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful")); 879 printf("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful"));
920 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"));
921 printf ("%s\n", _("STATE_WARNING return values.")); 881 printf("%s\n", _("STATE_WARNING return values."));
922 882
923 printf (UT_SUPPORT); 883 printf(UT_SUPPORT);
924} 884}
925 885
926 886void print_usage(void) {
927 887 printf("%s\n", _("Usage:"));
928void 888 printf("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
929print_usage (void) 889 printf("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
930{ 890 printf("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
931 printf ("%s\n", _("Usage:"));
932 printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
933 printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
934 printf ("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
935} 891}
936
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_ssh.c b/plugins/check_ssh.c
index 42a88cf9..9d0d7cde 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -28,6 +28,9 @@
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-2024"; 35const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 36const char *email = "devel@monitoring-plugins.org";
@@ -35,26 +38,26 @@ const char *email = "devel@monitoring-plugins.org";
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 48
46static int port = -1;
47static char *server_name = NULL;
48static char *remote_version = NULL;
49static char *remote_protocol = NULL;
50static bool verbose = false; 49static bool verbose = false;
51 50
52static int process_arguments(int /*argc*/, char ** /*argv*/); 51typedef struct process_arguments_wrapper {
53static int validate_arguments(void); 52 int errorcode;
53 check_ssh_config config;
54} process_arguments_wrapper;
55
56static process_arguments_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
54static void print_help(void); 57static void print_help(void);
55void print_usage(void); 58void print_usage(void);
56 59
57static int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_protocol); 60static int ssh_connect(mp_check *overall, char *haddr, int hport, char *remote_version, char *remote_protocol);
58 61
59int main(int argc, char **argv) { 62int main(int argc, char **argv) {
60 setlocale(LC_ALL, ""); 63 setlocale(LC_ALL, "");
@@ -64,24 +67,35 @@ int main(int argc, char **argv) {
64 /* Parse extra opts if any */ 67 /* Parse extra opts if any */
65 argv = np_extra_opts(&argc, argv, progname); 68 argv = np_extra_opts(&argc, argv, progname);
66 69
67 if (process_arguments(argc, argv) == ERROR) 70 process_arguments_wrapper tmp_config = process_arguments(argc, argv);
71
72 if (tmp_config.errorcode == ERROR) {
68 usage4(_("Could not parse arguments")); 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 }
69 82
70 /* initialize alarm signal handling */ 83 /* initialize alarm signal handling */
71 signal(SIGALRM, socket_timeout_alarm_handler); 84 signal(SIGALRM, socket_timeout_alarm_handler);
72
73 alarm(socket_timeout); 85 alarm(socket_timeout);
74 86
75 /* ssh_connect exits if error is found */ 87 /* ssh_connect exits if error is found */
76 int 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);
77 89
78 alarm(0); 90 alarm(0);
79 91
80 return (result); 92 mp_exit(overall);
81} 93}
82 94
95#define output_format_index CHAR_MAX + 1
96
83/* process command-line arguments */ 97/* process command-line arguments */
84int process_arguments(int argc, char **argv) { 98process_arguments_wrapper process_arguments(int argc, char **argv) {
85 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, 99 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
86 {"version", no_argument, 0, 'V'}, 100 {"version", no_argument, 0, 'V'},
87 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 101 {"host", required_argument, 0, 'H'}, /* backward compatibility */
@@ -93,22 +107,33 @@ int process_arguments(int argc, char **argv) {
93 {"verbose", no_argument, 0, 'v'}, 107 {"verbose", no_argument, 0, 'v'},
94 {"remote-version", required_argument, 0, 'r'}, 108 {"remote-version", required_argument, 0, 'r'},
95 {"remote-protocol", required_argument, 0, 'P'}, 109 {"remote-protocol", required_argument, 0, 'P'},
110 {"output-format", required_argument, 0, output_format_index},
96 {0, 0, 0, 0}}; 111 {0, 0, 0, 0}};
97 112
98 if (argc < 2) 113 process_arguments_wrapper result = {
99 return ERROR; 114 .config = check_ssh_config_init(),
115 .errorcode = OK,
116 };
117
118 if (argc < 2) {
119 result.errorcode = ERROR;
120 return result;
121 }
100 122
101 for (int i = 1; i < argc; i++) 123 for (int i = 1; i < argc; i++) {
102 if (strcmp("-to", argv[i]) == 0) 124 if (strcmp("-to", argv[i]) == 0) {
103 strcpy(argv[i], "-t"); 125 strcpy(argv[i], "-t");
126 }
127 }
104 128
105 int option_char; 129 int option_char;
106 while (true) { 130 while (true) {
107 int option = 0; 131 int option = 0;
108 option_char = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option); 132 option_char = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
109 133
110 if (option_char == -1 || option_char == EOF) 134 if (option_char == -1 || option_char == EOF) {
111 break; 135 break;
136 }
112 137
113 switch (option_char) { 138 switch (option_char) {
114 case '?': /* help */ 139 case '?': /* help */
@@ -123,10 +148,11 @@ int process_arguments(int argc, char **argv) {
123 verbose = true; 148 verbose = true;
124 break; 149 break;
125 case 't': /* timeout period */ 150 case 't': /* timeout period */
126 if (!is_integer(optarg)) 151 if (!is_intpos(optarg)) {
127 usage2(_("Timeout interval must be a positive integer"), optarg); 152 usage2(_("Timeout interval must be a positive integer"), optarg);
128 else 153 } else {
129 socket_timeout = atoi(optarg); 154 socket_timeout = (unsigned int)atoi(optarg);
155 }
130 break; 156 break;
131 case '4': 157 case '4':
132 address_family = AF_INET; 158 address_family = AF_INET;
@@ -139,50 +165,61 @@ int process_arguments(int argc, char **argv) {
139#endif 165#endif
140 break; 166 break;
141 case 'r': /* remote version */ 167 case 'r': /* remote version */
142 remote_version = optarg; 168 result.config.remote_version = optarg;
143 break; 169 break;
144 case 'P': /* remote version */ 170 case 'P': /* remote version */
145 remote_protocol = optarg; 171 result.config.remote_protocol = optarg;
146 break; 172 break;
147 case 'H': /* host */ 173 case 'H': /* host */
148 if (!is_host(optarg)) 174 if (!is_host(optarg)) {
149 usage2(_("Invalid hostname/address"), optarg); 175 usage2(_("Invalid hostname/address"), optarg);
150 server_name = optarg; 176 }
177 result.config.server_name = optarg;
151 break; 178 break;
152 case 'p': /* port */ 179 case 'p': /* port */
153 if (is_intpos(optarg)) { 180 if (is_intpos(optarg)) {
154 port = atoi(optarg); 181 result.config.port = atoi(optarg);
155 } else { 182 } else {
156 usage2(_("Port number must be a positive integer"), optarg); 183 usage2(_("Port number must be a positive integer"), optarg);
157 } 184 }
185 break;
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);
192 }
193
194 result.config.output_format_is_set = true;
195 result.config.output_format = parser.output_format;
196 break;
197 }
158 } 198 }
159 } 199 }
160 200
161 option_char = optind; 201 option_char = optind;
162 if (server_name == NULL && option_char < argc) { 202 if (result.config.server_name == NULL && option_char < argc) {
163 if (is_host(argv[option_char])) { 203 if (is_host(argv[option_char])) {
164 server_name = argv[option_char++]; 204 result.config.server_name = argv[option_char++];
165 } 205 }
166 } 206 }
167 207
168 if (port == -1 && option_char < argc) { 208 if (result.config.port == -1 && option_char < argc) {
169 if (is_intpos(argv[option_char])) { 209 if (is_intpos(argv[option_char])) {
170 port = atoi(argv[option_char++]); 210 result.config.port = atoi(argv[option_char++]);
171 } else { 211 } else {
172 print_usage(); 212 print_usage();
173 exit(STATE_UNKNOWN); 213 exit(STATE_UNKNOWN);
174 } 214 }
175 } 215 }
176 216
177 return validate_arguments(); 217 if (result.config.server_name == NULL) {
178} 218 result.errorcode = ERROR;
219 return result;
220 }
179 221
180int validate_arguments(void) { 222 return result;
181 if (server_name == NULL)
182 return ERROR;
183 if (port == -1) /* funky, but allows -p to override stray integer in args */
184 port = SSH_DFL_PORT;
185 return OK;
186} 223}
187 224
188/************************************************************************ 225/************************************************************************
@@ -191,28 +228,34 @@ int validate_arguments(void) {
191 * 228 *
192 *-----------------------------------------------------------------------*/ 229 *-----------------------------------------------------------------------*/
193 230
194int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_protocol) { 231int ssh_connect(mp_check *overall, char *haddr, int hport, char *desired_remote_version, char *desired_remote_protocol) {
195 struct timeval tv; 232 struct timeval tv;
196 gettimeofday(&tv, NULL); 233 gettimeofday(&tv, NULL);
197 234
198 int socket; 235 int socket;
199 int result = my_tcp_connect(haddr, hport, &socket); 236 int result = my_tcp_connect(haddr, hport, &socket);
200 237
201 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);
202 return result; 243 return result;
244 }
203 245
204 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char)); 246 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
205 char *buffer = NULL; 247 char *buffer = NULL;
206 ssize_t recv_ret = 0; 248 size_t recv_ret = 0;
207 char *version_control_string = NULL; 249 char *version_control_string = NULL;
208 ssize_t byte_offset = 0; 250 size_t byte_offset = 0;
209 while ((version_control_string == NULL) && (recv_ret = recv(socket, 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)) {
210 253
211 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*/
212 byte_offset = 0; 255 byte_offset = 0;
213 256
214 char *index = NULL; 257 char *index = NULL;
215 int len = 0; 258 unsigned long len = 0;
216 while ((index = strchr(output + byte_offset, '\n')) != NULL) { 259 while ((index = strchr(output + byte_offset, '\n')) != NULL) {
217 /*Partition the buffer so that this line is a separate string, 260 /*Partition the buffer so that this line is a separate string,
218 * by replacing the newline with NUL*/ 261 * by replacing the newline with NUL*/
@@ -243,14 +286,23 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
243 } 286 }
244 287
245 if (recv_ret < 0) { 288 if (recv_ret < 0) {
246 printf("SSH CRITICAL - %s", strerror(errno)); 289 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
247 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;
248 } 293 }
249 294
250 if (version_control_string == NULL) { 295 if (version_control_string == NULL) {
251 printf("SSH CRITICAL - No version control string received"); 296 connection_sc = mp_set_subcheck_state(connection_sc, STATE_CRITICAL);
252 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;
253 } 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
254 /* 306 /*
255 * "When the connection has been established, both sides MUST send an 307 * "When the connection has been established, both sides MUST send an
256 * identification string. This identification string MUST be 308 * identification string. This identification string MUST be
@@ -259,8 +311,9 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
259 * - RFC 4253:4.2 311 * - RFC 4253:4.2
260 */ 312 */
261 strip(version_control_string); 313 strip(version_control_string);
262 if (verbose) 314 if (verbose) {
263 printf("%s\n", version_control_string); 315 printf("%s\n", version_control_string);
316 }
264 317
265 char *ssh_proto = version_control_string + 4; 318 char *ssh_proto = version_control_string + 4;
266 319
@@ -288,41 +341,65 @@ int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_proto
288 if (tmp) { 341 if (tmp) {
289 ssh_server[tmp - ssh_server] = '\0'; 342 ssh_server[tmp - ssh_server] = '\0';
290 } 343 }
344
345 mp_subcheck protocol_validity_sc = mp_subcheck_init();
291 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) { 346 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
292 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);
293 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;
294 } 351 }
352
353 protocol_validity_sc = mp_set_subcheck_state(protocol_validity_sc, STATE_OK);
354 xasprintf(&protocol_validity_sc.output, "Valid protocol version control string %s", version_control_string);
355 mp_add_subcheck_to_check(overall, protocol_validity_sc);
356
295 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0; 357 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
296 358
297 static char *rev_no = VERSION; 359 static char *rev_no = VERSION;
298 xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no); 360 xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
299 send(socket, buffer, strlen(buffer), MSG_DONTWAIT); 361 send(socket, buffer, strlen(buffer), MSG_DONTWAIT);
300 if (verbose) 362 if (verbose) {
301 printf("%s\n", buffer); 363 printf("%s\n", buffer);
364 }
302 365
303 if (remote_version && strcmp(remote_version, ssh_server)) { 366 if (desired_remote_version && strcmp(desired_remote_version, ssh_server)) {
304 printf(_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"), ssh_server, ssh_proto, remote_version); 367 mp_subcheck remote_version_sc = mp_subcheck_init();
368 remote_version_sc = mp_set_subcheck_state(remote_version_sc, STATE_CRITICAL);
369 xasprintf(&remote_version_sc.output, _("%s (protocol %s) version mismatch, expected '%s'"), ssh_server, ssh_proto,
370 desired_remote_version);
305 close(socket); 371 close(socket);
306 exit(STATE_CRITICAL); 372 mp_add_subcheck_to_check(overall, remote_version_sc);
373 return OK;
307 } 374 }
308 375
309 double elapsed_time = (double)deltime(tv) / 1.0e6; 376 double elapsed_time = (double)deltime(tv) / 1.0e6;
310 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) { 377 mp_perfdata time_pd = perfdata_init();
311 printf(_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s' | %s\n"), ssh_server, ssh_proto, remote_protocol, 378 time_pd.value = mp_create_pd_value(elapsed_time);
312 fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, true, (int)socket_timeout)); 379 time_pd.label = "time";
313 close(socket); 380 time_pd.max_present = true;
314 exit(STATE_CRITICAL); 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);
315 } 393 }
316 394
317 printf(_("SSH OK - %s (protocol %s) | %s\n"), ssh_server, ssh_proto, 395 mp_add_subcheck_to_check(overall, protocol_version_sc);
318 fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, true, (int)socket_timeout));
319 close(socket); 396 close(socket);
320 exit(STATE_OK); 397 return OK;
321} 398}
322 399
323void print_help(void) { 400void print_help(void) {
324 char *myport; 401 char *myport;
325 xasprintf(&myport, "%d", SSH_DFL_PORT); 402 xasprintf(&myport, "%d", default_ssh_port);
326 403
327 print_revision(progname, NP_VERSION); 404 print_revision(progname, NP_VERSION);
328 405
@@ -349,6 +426,7 @@ void print_help(void) {
349 426
350 printf(" %s\n", "-P, --remote-protocol=STRING"); 427 printf(" %s\n", "-P, --remote-protocol=STRING");
351 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);
352 430
353 printf(UT_VERBOSE); 431 printf(UT_VERBOSE);
354 432
@@ -357,5 +435,5 @@ void print_help(void) {
357 435
358void print_usage(void) { 436void print_usage(void) {
359 printf("%s\n", _("Usage:")); 437 printf("%s\n", _("Usage:"));
360 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname); 438 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] --hostname <host>\n", progname);
361} 439}
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 4d3b6099..cb95949a 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -93,7 +93,7 @@ int main(int argc, char **argv) {
93 double percent_used; 93 double percent_used;
94 mp_check overall = mp_check_init(); 94 mp_check overall = mp_check_init();
95 if (config.output_format_is_set) { 95 if (config.output_format_is_set) {
96 overall.format = config.output_format; 96 mp_set_format(config.output_format);
97 } 97 }
98 mp_subcheck sc1 = mp_subcheck_init(); 98 mp_subcheck sc1 = mp_subcheck_init();
99 sc1 = mp_set_subcheck_default_state(sc1, STATE_OK); 99 sc1 = mp_set_subcheck_default_state(sc1, STATE_OK);
diff --git a/plugins/check_time.c b/plugins/check_time.c
index d1f50683..debf59f3 100644
--- a/plugins/check_time.c
+++ b/plugins/check_time.c
@@ -28,6 +28,7 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
31const char *progname = "check_time"; 32const char *progname = "check_time";
32const char *copyright = "1999-2024"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
@@ -35,28 +36,15 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 36#include "common.h"
36#include "netutils.h" 37#include "netutils.h"
37#include "utils.h" 38#include "utils.h"
38 39#include "check_time.d/config.h"
39enum {
40 TIME_PORT = 37
41};
42 40
43#define UNIX_EPOCH 2208988800UL 41#define UNIX_EPOCH 2208988800UL
44 42
45static uint32_t raw_server_time; 43typedef struct {
46static unsigned long server_time, diff_time; 44 int errorcode;
47static int warning_time = 0; 45 check_time_config config;
48static bool check_warning_time = false; 46} check_time_config_wrapper;
49static int critical_time = 0; 47static check_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static bool check_critical_time = false;
51static unsigned long warning_diff = 0;
52static bool check_warning_diff = false;
53static unsigned long critical_diff = 0;
54static bool check_critical_diff = false;
55static int server_port = TIME_PORT;
56static char *server_address = NULL;
57static bool use_udp = false;
58
59static int process_arguments(int, char **);
60static void print_help(void); 48static void print_help(void);
61void print_usage(void); 49void print_usage(void);
62 50
@@ -68,8 +56,12 @@ int main(int argc, char **argv) {
68 /* Parse extra opts if any */ 56 /* Parse extra opts if any */
69 argv = np_extra_opts(&argc, argv, progname); 57 argv = np_extra_opts(&argc, argv, progname);
70 58
71 if (process_arguments(argc, argv) == ERROR) 59 check_time_config_wrapper tmp_config = process_arguments(argc, argv);
60 if (tmp_config.errorcode == ERROR) {
72 usage4(_("Could not parse arguments")); 61 usage4(_("Could not parse arguments"));
62 }
63
64 const check_time_config config = tmp_config.config;
73 65
74 /* initialize alarm signal handling */ 66 /* initialize alarm signal handling */
75 signal(SIGALRM, socket_timeout_alarm_handler); 67 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -79,37 +71,40 @@ int main(int argc, char **argv) {
79 time(&start_time); 71 time(&start_time);
80 72
81 int socket; 73 int socket;
82 int result = STATE_UNKNOWN; 74 mp_state_enum result = STATE_UNKNOWN;
83 /* try to connect to the host at the given port number */ 75 /* try to connect to the host at the given port number */
84 if (use_udp) { 76 if (config.use_udp) {
85 result = my_udp_connect(server_address, server_port, &socket); 77 result = my_udp_connect(config.server_address, config.server_port, &socket);
86 } else { 78 } else {
87 result = my_tcp_connect(server_address, server_port, &socket); 79 result = my_tcp_connect(config.server_address, config.server_port, &socket);
88 } 80 }
89 81
90 if (result != STATE_OK) { 82 if (result != STATE_OK) {
91 if (check_critical_time) 83 if (config.check_critical_time) {
92 result = STATE_CRITICAL; 84 result = STATE_CRITICAL;
93 else if (check_warning_time) 85 } else if (config.check_warning_time) {
94 result = STATE_WARNING; 86 result = STATE_WARNING;
95 else 87 } else {
96 result = STATE_UNKNOWN; 88 result = STATE_UNKNOWN;
97 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), server_address, server_port); 89 }
90 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), config.server_address, config.server_port);
98 } 91 }
99 92
100 if (use_udp) { 93 if (config.use_udp) {
101 if (send(socket, "", 0, 0) < 0) { 94 if (send(socket, "", 0, 0) < 0) {
102 if (check_critical_time) 95 if (config.check_critical_time) {
103 result = STATE_CRITICAL; 96 result = STATE_CRITICAL;
104 else if (check_warning_time) 97 } else if (config.check_warning_time) {
105 result = STATE_WARNING; 98 result = STATE_WARNING;
106 else 99 } else {
107 result = STATE_UNKNOWN; 100 result = STATE_UNKNOWN;
108 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), server_address, server_port); 101 }
102 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), config.server_address, config.server_port);
109 } 103 }
110 } 104 }
111 105
112 /* watch for the connection string */ 106 /* watch for the connection string */
107 uint32_t raw_server_time;
113 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0); 108 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0);
114 109
115 /* close the connection */ 110 /* close the connection */
@@ -121,48 +116,56 @@ int main(int argc, char **argv) {
121 116
122 /* return a WARNING status if we couldn't read any data */ 117 /* return a WARNING status if we couldn't read any data */
123 if (result <= 0) { 118 if (result <= 0) {
124 if (check_critical_time) 119 if (config.check_critical_time) {
125 result = STATE_CRITICAL; 120 result = STATE_CRITICAL;
126 else if (check_warning_time) 121 } else if (config.check_warning_time) {
127 result = STATE_WARNING; 122 result = STATE_WARNING;
128 else 123 } else {
129 result = STATE_UNKNOWN; 124 result = STATE_UNKNOWN;
130 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), server_address, server_port); 125 }
126 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), config.server_address, config.server_port);
131 } 127 }
132 128
133 result = STATE_OK; 129 result = STATE_OK;
134 130
135 time_t conntime = (end_time - start_time); 131 time_t conntime = (end_time - start_time);
136 if (check_critical_time && conntime > critical_time) 132 if (config.check_critical_time && conntime > config.critical_time) {
137 result = STATE_CRITICAL; 133 result = STATE_CRITICAL;
138 else if (check_warning_time && conntime > warning_time) 134 } else if (config.check_warning_time && conntime > config.warning_time) {
139 result = STATE_WARNING; 135 result = STATE_WARNING;
136 }
140 137
141 if (result != STATE_OK) 138 if (result != STATE_OK) {
142 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime, 139 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime,
143 perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0, 140 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
144 false, 0)); 141 (long)config.critical_time, true, 0, false, 0));
142 }
145 143
144 unsigned long server_time;
145 unsigned long diff_time;
146 server_time = ntohl(raw_server_time) - UNIX_EPOCH; 146 server_time = ntohl(raw_server_time) - UNIX_EPOCH;
147 if (server_time > (unsigned long)end_time) 147 if (server_time > (unsigned long)end_time) {
148 diff_time = server_time - (unsigned long)end_time; 148 diff_time = server_time - (unsigned long)end_time;
149 else 149 } else {
150 diff_time = (unsigned long)end_time - server_time; 150 diff_time = (unsigned long)end_time - server_time;
151 }
151 152
152 if (check_critical_diff && diff_time > critical_diff) 153 if (config.check_critical_diff && diff_time > config.critical_diff) {
153 result = STATE_CRITICAL; 154 result = STATE_CRITICAL;
154 else if (check_warning_diff && diff_time > warning_diff) 155 } else if (config.check_warning_diff && diff_time > config.warning_diff) {
155 result = STATE_WARNING; 156 result = STATE_WARNING;
157 }
156 158
157 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time, 159 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time,
158 perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0, 160 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
159 false, 0), 161 (long)config.critical_time, true, 0, false, 0),
160 perfdata("offset", diff_time, "s", check_warning_diff, warning_diff, check_critical_diff, critical_diff, true, 0, false, 0)); 162 perfdata("offset", diff_time, "s", config.check_warning_diff, config.warning_diff, config.check_critical_diff,
163 config.critical_diff, true, 0, false, 0));
161 return result; 164 return result;
162} 165}
163 166
164/* process command-line arguments */ 167/* process command-line arguments */
165int process_arguments(int argc, char **argv) { 168check_time_config_wrapper process_arguments(int argc, char **argv) {
166 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 169 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
167 {"warning-variance", required_argument, 0, 'w'}, 170 {"warning-variance", required_argument, 0, 'w'},
168 {"critical-variance", required_argument, 0, 'c'}, 171 {"critical-variance", required_argument, 0, 'c'},
@@ -175,29 +178,37 @@ int process_arguments(int argc, char **argv) {
175 {"help", no_argument, 0, 'h'}, 178 {"help", no_argument, 0, 'h'},
176 {0, 0, 0, 0}}; 179 {0, 0, 0, 0}};
177 180
178 if (argc < 2) 181 if (argc < 2) {
179 usage("\n"); 182 usage("\n");
183 }
180 184
181 for (int i = 1; i < argc; i++) { 185 for (int i = 1; i < argc; i++) {
182 if (strcmp("-to", argv[i]) == 0) 186 if (strcmp("-to", argv[i]) == 0) {
183 strcpy(argv[i], "-t"); 187 strcpy(argv[i], "-t");
184 else if (strcmp("-wd", argv[i]) == 0) 188 } else if (strcmp("-wd", argv[i]) == 0) {
185 strcpy(argv[i], "-w"); 189 strcpy(argv[i], "-w");
186 else if (strcmp("-cd", argv[i]) == 0) 190 } else if (strcmp("-cd", argv[i]) == 0) {
187 strcpy(argv[i], "-c"); 191 strcpy(argv[i], "-c");
188 else if (strcmp("-wt", argv[i]) == 0) 192 } else if (strcmp("-wt", argv[i]) == 0) {
189 strcpy(argv[i], "-W"); 193 strcpy(argv[i], "-W");
190 else if (strcmp("-ct", argv[i]) == 0) 194 } else if (strcmp("-ct", argv[i]) == 0) {
191 strcpy(argv[i], "-C"); 195 strcpy(argv[i], "-C");
196 }
192 } 197 }
193 198
199 check_time_config_wrapper result = {
200 .errorcode = OK,
201 .config = check_time_config_init(),
202 };
203
194 int option_char; 204 int option_char;
195 while (true) { 205 while (true) {
196 int option = 0; 206 int option = 0;
197 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option); 207 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option);
198 208
199 if (option_char == -1 || option_char == EOF) 209 if (option_char == -1 || option_char == EOF) {
200 break; 210 break;
211 }
201 212
202 switch (option_char) { 213 switch (option_char) {
203 case '?': /* print short usage statement if args not parsable */ 214 case '?': /* print short usage statement if args not parsable */
@@ -209,18 +220,19 @@ int process_arguments(int argc, char **argv) {
209 print_revision(progname, NP_VERSION); 220 print_revision(progname, NP_VERSION);
210 exit(STATE_UNKNOWN); 221 exit(STATE_UNKNOWN);
211 case 'H': /* hostname */ 222 case 'H': /* hostname */
212 if (!is_host(optarg)) 223 if (!is_host(optarg)) {
213 usage2(_("Invalid hostname/address"), optarg); 224 usage2(_("Invalid hostname/address"), optarg);
214 server_address = optarg; 225 }
226 result.config.server_address = optarg;
215 break; 227 break;
216 case 'w': /* warning-variance */ 228 case 'w': /* warning-variance */
217 if (is_intnonneg(optarg)) { 229 if (is_intnonneg(optarg)) {
218 warning_diff = strtoul(optarg, NULL, 10); 230 result.config.warning_diff = strtoul(optarg, NULL, 10);
219 check_warning_diff = true; 231 result.config.check_warning_diff = true;
220 } else if (strspn(optarg, "0123456789:,") > 0) { 232 } else if (strspn(optarg, "0123456789:,") > 0) {
221 if (sscanf(optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) { 233 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.warning_diff, &result.config.warning_time) == 2) {
222 check_warning_diff = true; 234 result.config.check_warning_diff = true;
223 check_warning_time = true; 235 result.config.check_warning_time = true;
224 } else { 236 } else {
225 usage4(_("Warning thresholds must be a positive integer")); 237 usage4(_("Warning thresholds must be a positive integer"));
226 } 238 }
@@ -230,12 +242,12 @@ int process_arguments(int argc, char **argv) {
230 break; 242 break;
231 case 'c': /* critical-variance */ 243 case 'c': /* critical-variance */
232 if (is_intnonneg(optarg)) { 244 if (is_intnonneg(optarg)) {
233 critical_diff = strtoul(optarg, NULL, 10); 245 result.config.critical_diff = strtoul(optarg, NULL, 10);
234 check_critical_diff = true; 246 result.config.check_critical_diff = true;
235 } else if (strspn(optarg, "0123456789:,") > 0) { 247 } else if (strspn(optarg, "0123456789:,") > 0) {
236 if (sscanf(optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) == 2) { 248 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.critical_diff, &result.config.critical_time) == 2) {
237 check_critical_diff = true; 249 result.config.check_critical_diff = true;
238 check_critical_time = true; 250 result.config.check_critical_time = true;
239 } else { 251 } else {
240 usage4(_("Critical thresholds must be a positive integer")); 252 usage4(_("Critical thresholds must be a positive integer"));
241 } 253 }
@@ -244,48 +256,53 @@ int process_arguments(int argc, char **argv) {
244 } 256 }
245 break; 257 break;
246 case 'W': /* warning-connect */ 258 case 'W': /* warning-connect */
247 if (!is_intnonneg(optarg)) 259 if (!is_intnonneg(optarg)) {
248 usage4(_("Warning threshold must be a positive integer")); 260 usage4(_("Warning threshold must be a positive integer"));
249 else 261 } else {
250 warning_time = atoi(optarg); 262 result.config.warning_time = atoi(optarg);
251 check_warning_time = true; 263 }
264 result.config.check_warning_time = true;
252 break; 265 break;
253 case 'C': /* critical-connect */ 266 case 'C': /* critical-connect */
254 if (!is_intnonneg(optarg)) 267 if (!is_intnonneg(optarg)) {
255 usage4(_("Critical threshold must be a positive integer")); 268 usage4(_("Critical threshold must be a positive integer"));
256 else 269 } else {
257 critical_time = atoi(optarg); 270 result.config.critical_time = atoi(optarg);
258 check_critical_time = true; 271 }
272 result.config.check_critical_time = true;
259 break; 273 break;
260 case 'p': /* port */ 274 case 'p': /* port */
261 if (!is_intnonneg(optarg)) 275 if (!is_intnonneg(optarg)) {
262 usage4(_("Port must be a positive integer")); 276 usage4(_("Port must be a positive integer"));
263 else 277 } else {
264 server_port = atoi(optarg); 278 result.config.server_port = atoi(optarg);
279 }
265 break; 280 break;
266 case 't': /* timeout */ 281 case 't': /* timeout */
267 if (!is_intnonneg(optarg)) 282 if (!is_intnonneg(optarg)) {
268 usage2(_("Timeout interval must be a positive integer"), optarg); 283 usage2(_("Timeout interval must be a positive integer"), optarg);
269 else 284 } else {
270 socket_timeout = atoi(optarg); 285 socket_timeout = atoi(optarg);
286 }
271 break; 287 break;
272 case 'u': /* udp */ 288 case 'u': /* udp */
273 use_udp = true; 289 result.config.use_udp = true;
274 } 290 }
275 } 291 }
276 292
277 option_char = optind; 293 option_char = optind;
278 if (server_address == NULL) { 294 if (result.config.server_address == NULL) {
279 if (argc > option_char) { 295 if (argc > option_char) {
280 if (!is_host(argv[option_char])) 296 if (!is_host(argv[option_char])) {
281 usage2(_("Invalid hostname/address"), optarg); 297 usage2(_("Invalid hostname/address"), optarg);
282 server_address = argv[option_char]; 298 }
299 result.config.server_address = argv[option_char];
283 } else { 300 } else {
284 usage4(_("Hostname was not supplied")); 301 usage4(_("Hostname was not supplied"));
285 } 302 }
286 } 303 }
287 304
288 return OK; 305 return result;
289} 306}
290 307
291void print_help(void) { 308void print_help(void) {
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 526a29df..ecc0760f 100644
--- a/plugins/check_ups.c
+++ b/plugins/check_ups.c
@@ -39,69 +39,29 @@ const char *email = "devel@monitoring-plugins.org";
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_ups.d/config.h"
43enum { 43#include "states.h"
44 PORT = 3493
45};
46
47#define UPS_NONE 0 /* no supported options */
48#define UPS_UTILITY 1 /* supports utility line */
49#define UPS_BATTPCT 2 /* supports percent battery remaining */
50#define UPS_STATUS 4 /* supports UPS status */
51#define UPS_TEMP 8 /* supports UPS temperature */
52#define UPS_LOADPCT 16 /* supports load percent */
53#define UPS_REALPOWER 32 /* supports real power */
54
55#define UPSSTATUS_NONE 0
56#define UPSSTATUS_OFF 1
57#define UPSSTATUS_OL 2
58#define UPSSTATUS_OB 4
59#define UPSSTATUS_LB 8
60#define UPSSTATUS_CAL 16
61#define UPSSTATUS_RB 32 /*Replace Battery */
62#define UPSSTATUS_BYPASS 64
63#define UPSSTATUS_OVER 128
64#define UPSSTATUS_TRIM 256
65#define UPSSTATUS_BOOST 512
66#define UPSSTATUS_CHRG 1024
67#define UPSSTATUS_DISCHRG 2048
68#define UPSSTATUS_UNKNOWN 4096
69#define UPSSTATUS_ALARM 8192
70 44
71enum { 45enum {
72 NOSUCHVAR = ERROR - 1 46 NOSUCHVAR = ERROR - 1
73}; 47};
74 48
75typedef struct ups_config {
76 unsigned int server_port;
77 char *server_address;
78 char *ups_name;
79 double warning_value;
80 double critical_value;
81 bool check_warn;
82 bool check_crit;
83 int check_variable;
84 int status;
85 bool temp_output_c;
86} ups_config;
87
88ups_config ups_config_init(void) {
89 ups_config tmp = {0};
90 tmp.server_port = PORT;
91 tmp.server_address = NULL;
92 tmp.ups_name = NULL;
93 tmp.check_variable = UPS_NONE;
94 tmp.status = UPSSTATUS_NONE;
95
96 return tmp;
97}
98
99// Forward declarations 49// Forward declarations
100static int determine_status(ups_config * /*config*/, int *supported_options); 50typedef struct {
101static int get_ups_variable(const char * /*varname*/, char * /*buf*/, ups_config config); 51 int errorcode;
52 int ups_status;
53 int supported_options;
54} determine_status_result;
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*/);
102 64
103static int process_arguments(int /*argc*/, char ** /*argv*/, ups_config * /*config*/);
104static int validate_arguments(ups_config /*config*/);
105static void print_help(void); 65static void print_help(void);
106void print_usage(void); 66void print_usage(void);
107 67
@@ -109,28 +69,16 @@ int main(int argc, char **argv) {
109 setlocale(LC_ALL, ""); 69 setlocale(LC_ALL, "");
110 bindtextdomain(PACKAGE, LOCALEDIR); 70 bindtextdomain(PACKAGE, LOCALEDIR);
111 textdomain(PACKAGE); 71 textdomain(PACKAGE);
112
113 char *ups_status;
114 ups_status = strdup("N/A");
115
116 char *data;
117 data = strdup("");
118
119 char *message;
120 message = strdup("");
121
122 // Exit result
123 int result = STATE_UNKNOWN;
124
125 /* Parse extra opts if any */ 72 /* Parse extra opts if any */
126 argv = np_extra_opts(&argc, argv, progname); 73 argv = np_extra_opts(&argc, argv, progname);
127 74
128 // Config from commandline 75 check_ups_config_wrapper tmp_config = process_arguments(argc, argv);
129 ups_config config = ups_config_init();
130 76
131 if (process_arguments(argc, argv, &config) == ERROR) { 77 if (tmp_config.errorcode == ERROR) {
132 usage4(_("Could not parse arguments")); 78 usage4(_("Could not parse arguments"));
133 } 79 }
80 // Config from commandline
81 check_ups_config config = tmp_config.config;
134 82
135 /* initialize alarm signal handling */ 83 /* initialize alarm signal handling */
136 signal(SIGALRM, socket_timeout_alarm_handler); 84 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -138,71 +86,75 @@ int main(int argc, char **argv) {
138 /* set socket timeout */ 86 /* set socket timeout */
139 alarm(socket_timeout); 87 alarm(socket_timeout);
140 88
141 int supported_options = UPS_NONE;
142
143 /* get the ups status if possible */ 89 /* get the ups status if possible */
144 if (determine_status(&config, &supported_options) != OK) { 90 determine_status_result query_result = determine_status(config);
91 if (query_result.errorcode != OK) {
145 return STATE_CRITICAL; 92 return STATE_CRITICAL;
146 } 93 }
147 94
148 if (supported_options & UPS_STATUS) { 95 int ups_status_flags = query_result.ups_status;
96 int supported_options = query_result.supported_options;
149 97
150 ups_status = strdup(""); 98 // Exit result
99 mp_state_enum result = STATE_UNKNOWN;
100 char *message = NULL;
151 101
102 if (supported_options & UPS_STATUS) {
103 char *ups_status = strdup("");
152 result = STATE_OK; 104 result = STATE_OK;
153 105
154 if (config.status & UPSSTATUS_OFF) { 106 if (ups_status_flags & UPSSTATUS_OFF) {
155 xasprintf(&ups_status, "Off"); 107 xasprintf(&ups_status, "Off");
156 result = STATE_CRITICAL; 108 result = STATE_CRITICAL;
157 } else if ((config.status & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) { 109 } else if ((ups_status_flags & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) {
158 xasprintf(&ups_status, _("On Battery, Low Battery")); 110 xasprintf(&ups_status, _("On Battery, Low Battery"));
159 result = STATE_CRITICAL; 111 result = STATE_CRITICAL;
160 } else { 112 } else {
161 if (config.status & UPSSTATUS_OL) { 113 if (ups_status_flags & UPSSTATUS_OL) {
162 xasprintf(&ups_status, "%s%s", ups_status, _("Online")); 114 xasprintf(&ups_status, "%s%s", ups_status, _("Online"));
163 } 115 }
164 if (config.status & UPSSTATUS_OB) { 116 if (ups_status_flags & UPSSTATUS_OB) {
165 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery")); 117 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery"));
166 result = max_state(result, STATE_WARNING); 118 result = max_state(result, STATE_WARNING);
167 } 119 }
168 if (config.status & UPSSTATUS_LB) { 120 if (ups_status_flags & UPSSTATUS_LB) {
169 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery")); 121 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery"));
170 result = max_state(result, STATE_WARNING); 122 result = max_state(result, STATE_WARNING);
171 } 123 }
172 if (config.status & UPSSTATUS_CAL) { 124 if (ups_status_flags & UPSSTATUS_CAL) {
173 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating")); 125 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating"));
174 } 126 }
175 if (config.status & UPSSTATUS_RB) { 127 if (ups_status_flags & UPSSTATUS_RB) {
176 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery")); 128 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery"));
177 result = max_state(result, STATE_WARNING); 129 result = max_state(result, STATE_WARNING);
178 } 130 }
179 if (config.status & UPSSTATUS_BYPASS) { 131 if (ups_status_flags & UPSSTATUS_BYPASS) {
180 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass")); 132 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass"));
181 // Bypassing the battery is likely a bad thing 133 // Bypassing the battery is likely a bad thing
182 result = STATE_CRITICAL; 134 result = STATE_CRITICAL;
183 } 135 }
184 if (config.status & UPSSTATUS_OVER) { 136 if (ups_status_flags & UPSSTATUS_OVER) {
185 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload")); 137 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload"));
186 result = max_state(result, STATE_WARNING); 138 result = max_state(result, STATE_WARNING);
187 } 139 }
188 if (config.status & UPSSTATUS_TRIM) { 140 if (ups_status_flags & UPSSTATUS_TRIM) {
189 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming")); 141 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming"));
190 } 142 }
191 if (config.status & UPSSTATUS_BOOST) { 143 if (ups_status_flags & UPSSTATUS_BOOST) {
192 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting")); 144 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting"));
193 } 145 }
194 if (config.status & UPSSTATUS_CHRG) { 146 if (ups_status_flags & UPSSTATUS_CHRG) {
195 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging")); 147 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging"));
196 } 148 }
197 if (config.status & UPSSTATUS_DISCHRG) { 149 if (ups_status_flags & UPSSTATUS_DISCHRG) {
198 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging")); 150 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging"));
199 result = max_state(result, STATE_WARNING); 151 result = max_state(result, STATE_WARNING);
200 } 152 }
201 if (config.status & UPSSTATUS_ALARM) { 153 if (ups_status_flags & UPSSTATUS_ALARM) {
202 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM")); 154 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM"));
203 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
204 } 156 }
205 if (config.status & UPSSTATUS_UNKNOWN) { 157 if (ups_status_flags & UPSSTATUS_UNKNOWN) {
206 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown")); 158 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown"));
207 } 159 }
208 } 160 }
@@ -211,7 +163,7 @@ int main(int argc, char **argv) {
211 163
212 int res; 164 int res;
213 char temp_buffer[MAX_INPUT_BUFFER]; 165 char temp_buffer[MAX_INPUT_BUFFER];
214 166 char *performance_data = strdup("");
215 /* get the ups utility voltage if possible */ 167 /* get the ups utility voltage if possible */
216 res = get_ups_variable("input.voltage", temp_buffer, config); 168 res = get_ups_variable("input.voltage", temp_buffer, config);
217 if (res == NOSUCHVAR) { 169 if (res == NOSUCHVAR) {
@@ -239,11 +191,12 @@ int main(int argc, char **argv) {
239 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) { 191 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) {
240 result = max_state(result, STATE_WARNING); 192 result = max_state(result, STATE_WARNING);
241 } 193 }
242 xasprintf(&data, "%s", 194 xasprintf(&performance_data, "%s",
243 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value), 195 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value),
244 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0)); 196 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0));
245 } else { 197 } else {
246 xasprintf(&data, "%s", perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0)); 198 xasprintf(&performance_data, "%s",
199 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0));
247 } 200 }
248 } 201 }
249 202
@@ -266,11 +219,12 @@ int main(int argc, char **argv) {
266 } else if (config.check_warn && ups_battery_percent <= config.warning_value) { 219 } else if (config.check_warn && ups_battery_percent <= config.warning_value) {
267 result = max_state(result, STATE_WARNING); 220 result = max_state(result, STATE_WARNING);
268 } 221 }
269 xasprintf(&data, "%s %s", data, 222 xasprintf(&performance_data, "%s %s", performance_data,
270 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value), 223 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value),
271 config.check_crit, (long)(config.critical_value), true, 0, true, 100)); 224 config.check_crit, (long)(config.critical_value), true, 0, true, 100));
272 } else { 225 } else {
273 xasprintf(&data, "%s %s", data, perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100)); 226 xasprintf(&performance_data, "%s %s", performance_data,
227 perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100));
274 } 228 }
275 } 229 }
276 230
@@ -293,11 +247,12 @@ int main(int argc, char **argv) {
293 } else if (config.check_warn && ups_load_percent >= config.warning_value) { 247 } else if (config.check_warn && ups_load_percent >= config.warning_value) {
294 result = max_state(result, STATE_WARNING); 248 result = max_state(result, STATE_WARNING);
295 } 249 }
296 xasprintf(&data, "%s %s", data, 250 xasprintf(&performance_data, "%s %s", performance_data,
297 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit, 251 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit,
298 (long)(config.critical_value), true, 0, true, 100)); 252 (long)(config.critical_value), true, 0, true, 100));
299 } else { 253 } else {
300 xasprintf(&data, "%s %s", data, perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100)); 254 xasprintf(&performance_data, "%s %s", performance_data,
255 perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100));
301 } 256 }
302 } 257 }
303 258
@@ -329,11 +284,12 @@ int main(int argc, char **argv) {
329 } else if (config.check_warn && ups_temperature >= config.warning_value) { 284 } else if (config.check_warn && ups_temperature >= config.warning_value) {
330 result = max_state(result, STATE_WARNING); 285 result = max_state(result, STATE_WARNING);
331 } 286 }
332 xasprintf(&data, "%s %s", data, 287 xasprintf(&performance_data, "%s %s", performance_data,
333 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit, 288 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit,
334 (long)(config.critical_value), true, 0, false, 0)); 289 (long)(config.critical_value), true, 0, false, 0));
335 } else { 290 } else {
336 xasprintf(&data, "%s %s", data, perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0)); 291 xasprintf(&performance_data, "%s %s", performance_data,
292 perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0));
337 } 293 }
338 } 294 }
339 295
@@ -355,11 +311,12 @@ int main(int argc, char **argv) {
355 } else if (config.check_warn && ups_realpower >= config.warning_value) { 311 } else if (config.check_warn && ups_realpower >= config.warning_value) {
356 result = max_state(result, STATE_WARNING); 312 result = max_state(result, STATE_WARNING);
357 } 313 }
358 xasprintf(&data, "%s %s", data, 314 xasprintf(&performance_data, "%s %s", performance_data,
359 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit, 315 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit,
360 (long)(config.critical_value), true, 0, false, 0)); 316 (long)(config.critical_value), true, 0, false, 0));
361 } else { 317 } else {
362 xasprintf(&data, "%s %s", data, perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0)); 318 xasprintf(&performance_data, "%s %s", performance_data,
319 perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0));
363 } 320 }
364 } 321 }
365 322
@@ -373,66 +330,73 @@ int main(int argc, char **argv) {
373 /* reset timeout */ 330 /* reset timeout */
374 alarm(0); 331 alarm(0);
375 332
376 printf("UPS %s - %s|%s\n", state_text(result), message, data); 333 printf("UPS %s - %s|%s\n", state_text(result), message, performance_data);
377 return result; 334 exit(result);
378} 335}
379 336
380/* determines what options are supported by the UPS */ 337/* determines what options are supported by the UPS */
381int determine_status(ups_config *config, int *supported_options) { 338determine_status_result determine_status(const check_ups_config config) {
382 char recv_buffer[MAX_INPUT_BUFFER];
383 339
384 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);
385 if (res == NOSUCHVAR) { 348 if (res == NOSUCHVAR) {
386 return OK; 349 return result;
387 } 350 }
388 351
389 if (res != STATE_OK) { 352 if (res != STATE_OK) {
390 printf("%s\n", _("Invalid response received from host")); 353 printf("%s\n", _("Invalid response received from host"));
391 return ERROR; 354 result.errorcode = ERROR;
355 return result;
392 } 356 }
393 357
394 *supported_options |= UPS_STATUS; 358 result.supported_options |= UPS_STATUS;
395 359
396 char temp_buffer[MAX_INPUT_BUFFER]; 360 char temp_buffer[MAX_INPUT_BUFFER];
397 361
398 strcpy(temp_buffer, recv_buffer); 362 strcpy(temp_buffer, recv_buffer);
399 for (char *ptr = (char *)strtok(temp_buffer, " "); ptr != NULL; ptr = (char *)strtok(NULL, " ")) { 363 for (char *ptr = strtok(temp_buffer, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
400 if (!strcmp(ptr, "OFF")) { 364 if (!strcmp(ptr, "OFF")) {
401 config->status |= UPSSTATUS_OFF; 365 result.ups_status |= UPSSTATUS_OFF;
402 } else if (!strcmp(ptr, "OL")) { 366 } else if (!strcmp(ptr, "OL")) {
403 config->status |= UPSSTATUS_OL; 367 result.ups_status |= UPSSTATUS_OL;
404 } else if (!strcmp(ptr, "OB")) { 368 } else if (!strcmp(ptr, "OB")) {
405 config->status |= UPSSTATUS_OB; 369 result.ups_status |= UPSSTATUS_OB;
406 } else if (!strcmp(ptr, "LB")) { 370 } else if (!strcmp(ptr, "LB")) {
407 config->status |= UPSSTATUS_LB; 371 result.ups_status |= UPSSTATUS_LB;
408 } else if (!strcmp(ptr, "CAL")) { 372 } else if (!strcmp(ptr, "CAL")) {
409 config->status |= UPSSTATUS_CAL; 373 result.ups_status |= UPSSTATUS_CAL;
410 } else if (!strcmp(ptr, "RB")) { 374 } else if (!strcmp(ptr, "RB")) {
411 config->status |= UPSSTATUS_RB; 375 result.ups_status |= UPSSTATUS_RB;
412 } else if (!strcmp(ptr, "BYPASS")) { 376 } else if (!strcmp(ptr, "BYPASS")) {
413 config->status |= UPSSTATUS_BYPASS; 377 result.ups_status |= UPSSTATUS_BYPASS;
414 } else if (!strcmp(ptr, "OVER")) { 378 } else if (!strcmp(ptr, "OVER")) {
415 config->status |= UPSSTATUS_OVER; 379 result.ups_status |= UPSSTATUS_OVER;
416 } else if (!strcmp(ptr, "TRIM")) { 380 } else if (!strcmp(ptr, "TRIM")) {
417 config->status |= UPSSTATUS_TRIM; 381 result.ups_status |= UPSSTATUS_TRIM;
418 } else if (!strcmp(ptr, "BOOST")) { 382 } else if (!strcmp(ptr, "BOOST")) {
419 config->status |= UPSSTATUS_BOOST; 383 result.ups_status |= UPSSTATUS_BOOST;
420 } else if (!strcmp(ptr, "CHRG")) { 384 } else if (!strcmp(ptr, "CHRG")) {
421 config->status |= UPSSTATUS_CHRG; 385 result.ups_status |= UPSSTATUS_CHRG;
422 } else if (!strcmp(ptr, "DISCHRG")) { 386 } else if (!strcmp(ptr, "DISCHRG")) {
423 config->status |= UPSSTATUS_DISCHRG; 387 result.ups_status |= UPSSTATUS_DISCHRG;
424 } else if (!strcmp(ptr, "ALARM")) { 388 } else if (!strcmp(ptr, "ALARM")) {
425 config->status |= UPSSTATUS_ALARM; 389 result.ups_status |= UPSSTATUS_ALARM;
426 } else { 390 } else {
427 config->status |= UPSSTATUS_UNKNOWN; 391 result.ups_status |= UPSSTATUS_UNKNOWN;
428 } 392 }
429 } 393 }
430 394
431 return OK; 395 return result;
432} 396}
433 397
434/* gets a variable value for a specific UPS */ 398/* gets a variable value for a specific UPS */
435int 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) {
436 char send_buffer[MAX_INPUT_BUFFER]; 400 char send_buffer[MAX_INPUT_BUFFER];
437 401
438 /* create the command string to send to the UPS daemon */ 402 /* create the command string to send to the UPS daemon */
@@ -500,7 +464,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
500 [-wv warn_value] [-cv crit_value] [-to to_sec] */ 464 [-wv warn_value] [-cv crit_value] [-to to_sec] */
501 465
502/* process command-line arguments */ 466/* process command-line arguments */
503int process_arguments(int argc, char **argv, ups_config *config) { 467check_ups_config_wrapper process_arguments(int argc, char **argv) {
504 468
505 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
506 {"ups", required_argument, 0, 'u'}, 470 {"ups", required_argument, 0, 'u'},
@@ -514,8 +478,14 @@ int process_arguments(int argc, char **argv, ups_config *config) {
514 {"help", no_argument, 0, 'h'}, 478 {"help", no_argument, 0, 'h'},
515 {0, 0, 0, 0}}; 479 {0, 0, 0, 0}};
516 480
481 check_ups_config_wrapper result = {
482 .errorcode = OK,
483 .config = check_ups_config_init(),
484 };
485
517 if (argc < 2) { 486 if (argc < 2) {
518 return ERROR; 487 result.errorcode = ERROR;
488 return result;
519 } 489 }
520 490
521 int c; 491 int c;
@@ -542,52 +512,52 @@ int process_arguments(int argc, char **argv, ups_config *config) {
542 usage5(); 512 usage5();
543 case 'H': /* hostname */ 513 case 'H': /* hostname */
544 if (is_host(optarg)) { 514 if (is_host(optarg)) {
545 config->server_address = optarg; 515 result.config.server_address = optarg;
546 } else { 516 } else {
547 usage2(_("Invalid hostname/address"), optarg); 517 usage2(_("Invalid hostname/address"), optarg);
548 } 518 }
549 break; 519 break;
550 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
551 Fahrenheit) */ 521 Fahrenheit) */
552 config->temp_output_c = true; 522 result.config.temp_output_c = true;
553 break; 523 break;
554 case 'u': /* ups name */ 524 case 'u': /* ups name */
555 config->ups_name = optarg; 525 result.config.ups_name = optarg;
556 break; 526 break;
557 case 'p': /* port */ 527 case 'p': /* port */
558 if (is_intpos(optarg)) { 528 if (is_intpos(optarg)) {
559 config->server_port = atoi(optarg); 529 result.config.server_port = atoi(optarg);
560 } else { 530 } else {
561 usage2(_("Port must be a positive integer"), optarg); 531 usage2(_("Port must be a positive integer"), optarg);
562 } 532 }
563 break; 533 break;
564 case 'c': /* critical time threshold */ 534 case 'c': /* critical time threshold */
565 if (is_intnonneg(optarg)) { 535 if (is_intnonneg(optarg)) {
566 config->critical_value = atoi(optarg); 536 result.config.critical_value = atoi(optarg);
567 config->check_crit = true; 537 result.config.check_crit = true;
568 } else { 538 } else {
569 usage2(_("Critical time must be a positive integer"), optarg); 539 usage2(_("Critical time must be a positive integer"), optarg);
570 } 540 }
571 break; 541 break;
572 case 'w': /* warning time threshold */ 542 case 'w': /* warning time threshold */
573 if (is_intnonneg(optarg)) { 543 if (is_intnonneg(optarg)) {
574 config->warning_value = atoi(optarg); 544 result.config.warning_value = atoi(optarg);
575 config->check_warn = true; 545 result.config.check_warn = true;
576 } else { 546 } else {
577 usage2(_("Warning time must be a positive integer"), optarg); 547 usage2(_("Warning time must be a positive integer"), optarg);
578 } 548 }
579 break; 549 break;
580 case 'v': /* variable */ 550 case 'v': /* variable */
581 if (!strcmp(optarg, "LINE")) { 551 if (!strcmp(optarg, "LINE")) {
582 config->check_variable = UPS_UTILITY; 552 result.config.check_variable = UPS_UTILITY;
583 } else if (!strcmp(optarg, "TEMP")) { 553 } else if (!strcmp(optarg, "TEMP")) {
584 config->check_variable = UPS_TEMP; 554 result.config.check_variable = UPS_TEMP;
585 } else if (!strcmp(optarg, "BATTPCT")) { 555 } else if (!strcmp(optarg, "BATTPCT")) {
586 config->check_variable = UPS_BATTPCT; 556 result.config.check_variable = UPS_BATTPCT;
587 } else if (!strcmp(optarg, "LOADPCT")) { 557 } else if (!strcmp(optarg, "LOADPCT")) {
588 config->check_variable = UPS_LOADPCT; 558 result.config.check_variable = UPS_LOADPCT;
589 } else if (!strcmp(optarg, "REALPOWER")) { 559 } else if (!strcmp(optarg, "REALPOWER")) {
590 config->check_variable = UPS_REALPOWER; 560 result.config.check_variable = UPS_REALPOWER;
591 } else { 561 } else {
592 usage2(_("Unrecognized UPS variable"), optarg); 562 usage2(_("Unrecognized UPS variable"), optarg);
593 } 563 }
@@ -608,27 +578,27 @@ int process_arguments(int argc, char **argv, ups_config *config) {
608 } 578 }
609 } 579 }
610 580
611 if (config->server_address == NULL && argc > optind) { 581 if (result.config.server_address == NULL && argc > optind) {
612 if (is_host(argv[optind])) { 582 if (is_host(argv[optind])) {
613 config->server_address = argv[optind++]; 583 result.config.server_address = argv[optind++];
614 } else { 584 } else {
615 usage2(_("Invalid hostname/address"), optarg); 585 usage2(_("Invalid hostname/address"), optarg);
616 } 586 }
617 } 587 }
618 588
619 if (config->server_address == NULL) { 589 if (result.config.server_address == NULL) {
620 config->server_address = strdup("127.0.0.1"); 590 result.config.server_address = strdup("127.0.0.1");
621 } 591 }
622 592
623 return validate_arguments(*config); 593 return validate_arguments(result);
624} 594}
625 595
626int validate_arguments(ups_config config) { 596check_ups_config_wrapper validate_arguments(check_ups_config_wrapper config_wrapper) {
627 if (!config.ups_name) { 597 if (config_wrapper.config.ups_name) {
628 printf("%s\n", _("Error : no UPS indicated")); 598 printf("%s\n", _("Error : no UPS indicated"));
629 return ERROR; 599 config_wrapper.errorcode = ERROR;
630 } 600 }
631 return OK; 601 return config_wrapper;
632} 602}
633 603
634void print_help(void) { 604void print_help(void) {
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/negate.c b/plugins/negate.c
index 750c0bfb..0520d298 100644
--- a/plugins/negate.c
+++ b/plugins/negate.c
@@ -38,21 +38,18 @@ 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
44static const char **process_arguments(int /*argc*/, char ** /*argv*/);
45static void validate_arguments(char ** /*command_line*/);
46static void print_help(void); 51static void print_help(void);
47void print_usage(void); 52void print_usage(void);
48static bool subst_text = false;
49
50static int state[4] = {
51 STATE_OK,
52 STATE_WARNING,
53 STATE_CRITICAL,
54 STATE_UNKNOWN,
55};
56 53
57int main(int argc, char **argv) { 54int main(int argc, char **argv) {
58 setlocale(LC_ALL, ""); 55 setlocale(LC_ALL, "");
@@ -61,15 +58,24 @@ int main(int argc, char **argv) {
61 58
62 timeout_interval = DEFAULT_TIMEOUT; 59 timeout_interval = DEFAULT_TIMEOUT;
63 60
64 char **command_line = (char **)process_arguments(argc, argv); 61 negate_config_wrapper tmp_config = process_arguments(argc, argv);
62
63 if (tmp_config.errorcode == ERROR) {
64 die(STATE_UNKNOWN, _("negate: Failed to parse input"));
65 }
66
67 negate_config config = tmp_config.config;
68
69 char **command_line = config.command_line;
65 70
66 /* Set signal handling and alarm */ 71 /* Set signal handling and alarm */
67 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) 72 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
68 die(STATE_UNKNOWN, _("Cannot catch SIGALRM")); 73 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
74 }
69 75
70 (void)alarm((unsigned)timeout_interval); 76 (void)alarm(timeout_interval);
71 77
72 int result = STATE_UNKNOWN; 78 mp_state_enum result = STATE_UNKNOWN;
73 output chld_out; 79 output chld_out;
74 output chld_err; 80 output chld_err;
75 81
@@ -86,46 +92,52 @@ int main(int argc, char **argv) {
86 } 92 }
87 93
88 /* Return UNKNOWN or worse if no output is returned */ 94 /* Return UNKNOWN or worse if no output is returned */
89 if (chld_out.lines == 0) 95 if (chld_out.lines == 0) {
90 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 }
91 98
92 char *sub; 99 char *sub;
93 for (size_t i = 0; i < chld_out.lines; i++) { 100 for (size_t i = 0; i < chld_out.lines; i++) {
94 if (subst_text && result >= 0 && result <= 4 && result != state[result]) { 101 if (config.subst_text && result >= 0 && result <= 4 && result != config.state[result]) {
95 /* Loop over each match found */ 102 /* Loop over each match found */
96 while ((sub = strstr(chld_out.line[i], state_text(result)))) { 103 while ((sub = strstr(chld_out.line[i], state_text(result)))) {
97 /* 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 */
98 *sub = '\0'; 105 *sub = '\0';
99 sub += strlen(state_text(result)); 106 sub += strlen(state_text(result));
100 /* then put everything back together */ 107 /* then put everything back together */
101 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);
102 } 109 }
103 } 110 }
104 printf("%s\n", chld_out.line[i]); 111 printf("%s\n", chld_out.line[i]);
105 } 112 }
106 113
107 if (result >= 0 && result <= 4) { 114 if (result >= 0 && result <= 4) {
108 exit(state[result]); 115 exit(config.state[result]);
109 } else { 116 } else {
110 exit(result); 117 exit(result);
111 } 118 }
112} 119}
113 120
114/* process command-line arguments */ 121/* process command-line arguments */
115static const char **process_arguments(int argc, char **argv) { 122static negate_config_wrapper process_arguments(int argc, char **argv) {
116 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, 123 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'},
117 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'}, 124 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'},
118 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'}, 125 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'},
119 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'}, 126 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'},
120 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}}; 127 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}};
121 128
129 negate_config_wrapper result = {
130 .errorcode = OK,
131 .config = negate_config_init(),
132 };
122 bool permute = true; 133 bool permute = true;
123 while (true) { 134 while (true) {
124 int option = 0; 135 int option = 0;
125 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option); 136 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
126 137
127 if (option_char == -1 || option_char == EOF) 138 if (option_char == -1 || option_char == EOF) {
128 break; 139 break;
140 }
129 141
130 switch (option_char) { 142 switch (option_char) {
131 case '?': /* help */ 143 case '?': /* help */
@@ -139,58 +151,68 @@ static const char **process_arguments(int argc, char **argv) {
139 print_revision(progname, NP_VERSION); 151 print_revision(progname, NP_VERSION);
140 exit(STATE_UNKNOWN); 152 exit(STATE_UNKNOWN);
141 case 't': /* timeout period */ 153 case 't': /* timeout period */
142 if (!is_integer(optarg)) 154 if (!is_integer(optarg)) {
143 usage2(_("Timeout interval must be a positive integer"), optarg); 155 usage2(_("Timeout interval must be a positive integer"), optarg);
144 else 156 } else {
145 timeout_interval = atoi(optarg); 157 timeout_interval = atoi(optarg);
158 }
146 break; 159 break;
147 case 'T': /* Result to return on timeouts */ 160 case 'T': /* Result to return on timeouts */
148 if ((timeout_state = mp_translate_state(optarg)) == ERROR) 161 if ((timeout_state = mp_translate_state(optarg)) == ERROR) {
149 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 }
150 break; 164 break;
151 case 'o': /* replacement for OK */ 165 case 'o': /* replacement for OK */
152 if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR) 166 if ((result.config.state[STATE_OK] = mp_translate_state(optarg)) == ERROR) {
153 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 }
154 permute = false; 169 permute = false;
155 break; 170 break;
156 171
157 case 'w': /* replacement for WARNING */ 172 case 'w': /* replacement for WARNING */
158 if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) 173 if ((result.config.state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) {
159 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 }
160 permute = false; 176 permute = false;
161 break; 177 break;
162 case 'c': /* replacement for CRITICAL */ 178 case 'c': /* replacement for CRITICAL */
163 if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) 179 if ((result.config.state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) {
164 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 }
165 permute = false; 182 permute = false;
166 break; 183 break;
167 case 'u': /* replacement for UNKNOWN */ 184 case 'u': /* replacement for UNKNOWN */
168 if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) 185 if ((result.config.state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) {
169 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 }
170 permute = false; 188 permute = false;
171 break; 189 break;
172 case 's': /* Substitute status text */ 190 case 's': /* Substitute status text */
173 subst_text = true; 191 result.config.subst_text = true;
174 break; 192 break;
175 } 193 }
176 } 194 }
177 195
178 validate_arguments(&argv[optind]);
179
180 if (permute) { /* No [owcu] switch specified, default to this */ 196 if (permute) { /* No [owcu] switch specified, default to this */
181 state[STATE_OK] = STATE_CRITICAL; 197 result.config.state[STATE_OK] = STATE_CRITICAL;
182 state[STATE_CRITICAL] = STATE_OK; 198 result.config.state[STATE_CRITICAL] = STATE_OK;
183 } 199 }
184 200
185 return (const char **)&argv[optind]; 201 result.config.command_line = &argv[optind];
202
203 return validate_arguments(result);
186} 204}
187 205
188void validate_arguments(char **command_line) { 206negate_config_wrapper validate_arguments(negate_config_wrapper config_wrapper) {
189 if (command_line[0] == NULL) 207 if (config_wrapper.config.command_line[0] == NULL) {
190 usage4(_("Could not parse arguments")); 208 usage4(_("Could not parse arguments"));
209 }
191 210
192 if (strncmp(command_line[0], "/", 1) != 0 && strncmp(command_line[0], "./", 2) != 0) 211 if (strncmp(config_wrapper.config.command_line[0], "/", 1) != 0 && strncmp(config_wrapper.config.command_line[0], "./", 2) != 0) {
193 usage4(_("Require path to command")); 212 usage4(_("Require path to command"));
213 }
214
215 return config_wrapper;
194} 216}
195 217
196void print_help(void) { 218void print_help(void) {
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 5f118a9e..e2916c65 100644
--- a/plugins/netutils.c
+++ b/plugins/netutils.c
@@ -28,6 +28,8 @@
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;
@@ -43,12 +45,19 @@ int address_family = AF_INET;
43 45
44/* handles socket timeouts */ 46/* handles socket timeouts */
45void socket_timeout_alarm_handler(int sig) { 47void socket_timeout_alarm_handler(int sig) {
46 if (sig == SIGALRM) 48 mp_subcheck timeout_sc = mp_subcheck_init();
47 printf(_("%s - Socket timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout); 49 timeout_sc = mp_set_subcheck_state(timeout_sc, socket_timeout_state);
48 else
49 printf(_("%s - Abnormal timeout after %d seconds\n"), state_text(socket_timeout_state), socket_timeout);
50 50
51 exit(socket_timeout_state); 51 if (sig == SIGALRM) {
52 xasprintf(&timeout_sc.output, _("Socket timeout after %d seconds\n"), socket_timeout);
53 } else {
54 xasprintf(&timeout_sc.output, _("Abnormal timeout after %d seconds\n"), socket_timeout);
55 }
56
57 mp_check overall = mp_check_init();
58 mp_add_subcheck_to_check(&overall, timeout_sc);
59
60 mp_exit(overall);
52} 61}
53 62
54/* 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
@@ -65,12 +74,13 @@ int process_tcp_request2(const char *server_address, int server_port, const char
65 int recv_length = 0; 74 int recv_length = 0;
66 75
67 result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP); 76 result = np_net_connect(server_address, server_port, &sd, IPPROTO_TCP);
68 if (result != STATE_OK) 77 if (result != STATE_OK) {
69 return STATE_CRITICAL; 78 return STATE_CRITICAL;
79 }
70 80
71 send_result = send(sd, send_buffer, strlen(send_buffer), 0); 81 send_result = send(sd, send_buffer, strlen(send_buffer), 0);
72 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) { 82 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
73 printf("%s\n", _("Send failed")); 83 // printf("%s\n", _("Send failed"));
74 result = STATE_WARNING; 84 result = STATE_WARNING;
75 } 85 }
76 86
@@ -87,7 +97,7 @@ int process_tcp_request2(const char *server_address, int server_port, const char
87 if (!FD_ISSET(sd, &readfds)) { /* it hasn't */ 97 if (!FD_ISSET(sd, &readfds)) { /* it hasn't */
88 if (!recv_length) { 98 if (!recv_length) {
89 strcpy(recv_buffer, ""); 99 strcpy(recv_buffer, "");
90 printf("%s\n", _("No data was received from host!")); 100 // printf("%s\n", _("No data was received from host!"));
91 result = STATE_WARNING; 101 result = STATE_WARNING;
92 } else { /* this one failed, but previous ones worked */ 102 } else { /* this one failed, but previous ones worked */
93 recv_buffer[recv_length] = 0; 103 recv_buffer[recv_length] = 0;
@@ -130,8 +140,9 @@ int process_request(const char *server_address, int server_port, int proto, cons
130 result = STATE_OK; 140 result = STATE_OK;
131 141
132 result = np_net_connect(server_address, server_port, &sd, proto); 142 result = np_net_connect(server_address, server_port, &sd, proto);
133 if (result != STATE_OK) 143 if (result != STATE_OK) {
134 return STATE_CRITICAL; 144 return STATE_CRITICAL;
145 }
135 146
136 result = send_request(sd, proto, send_buffer, recv_buffer, recv_size); 147 result = send_request(sd, proto, send_buffer, recv_buffer, recv_size);
137 148
@@ -169,8 +180,9 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
169 host_name++; 180 host_name++;
170 len -= 2; 181 len -= 2;
171 } 182 }
172 if (len >= sizeof(host)) 183 if (len >= sizeof(host)) {
173 return STATE_UNKNOWN; 184 return STATE_UNKNOWN;
185 }
174 memcpy(host, host_name, len); 186 memcpy(host, host_name, len);
175 host[len] = '\0'; 187 host[len] = '\0';
176 snprintf(port_str, sizeof(port_str), "%d", port); 188 snprintf(port_str, sizeof(port_str), "%d", port);
@@ -226,13 +238,14 @@ int np_net_connect(const char *host_name, int port, int *sd, int proto) {
226 die(STATE_UNKNOWN, _("Socket creation failed")); 238 die(STATE_UNKNOWN, _("Socket creation failed"));
227 } 239 }
228 result = connect(*sd, (struct sockaddr *)&su, sizeof(su)); 240 result = connect(*sd, (struct sockaddr *)&su, sizeof(su));
229 if (result < 0 && errno == ECONNREFUSED) 241 if (result < 0 && errno == ECONNREFUSED) {
230 was_refused = true; 242 was_refused = true;
243 }
231 } 244 }
232 245
233 if (result == 0) 246 if (result == 0) {
234 return STATE_OK; 247 return STATE_OK;
235 else if (was_refused) { 248 } else if (was_refused) {
236 switch (econn_refuse_state) { /* a user-defined expected outcome */ 249 switch (econn_refuse_state) { /* a user-defined expected outcome */
237 case STATE_OK: 250 case STATE_OK:
238 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */ 251 case STATE_WARNING: /* user wants WARN or OK on refusal, or... */
@@ -267,7 +280,7 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
267 280
268 send_result = send(sd, send_buffer, strlen(send_buffer), 0); 281 send_result = send(sd, send_buffer, strlen(send_buffer), 0);
269 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) { 282 if (send_result < 0 || (size_t)send_result != strlen(send_buffer)) {
270 printf("%s\n", _("Send failed")); 283 // printf("%s\n", _("Send failed"));
271 result = STATE_WARNING; 284 result = STATE_WARNING;
272 } 285 }
273 286
@@ -282,7 +295,7 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
282 /* make sure some data has arrived */ 295 /* make sure some data has arrived */
283 if (!FD_ISSET(sd, &readfds)) { 296 if (!FD_ISSET(sd, &readfds)) {
284 strcpy(recv_buffer, ""); 297 strcpy(recv_buffer, "");
285 printf("%s\n", _("No data was received from host!")); 298 // printf("%s\n", _("No data was received from host!"));
286 result = STATE_WARNING; 299 result = STATE_WARNING;
287 } 300 }
288 301
@@ -290,11 +303,13 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
290 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);
291 if (recv_result == -1) { 304 if (recv_result == -1) {
292 strcpy(recv_buffer, ""); 305 strcpy(recv_buffer, "");
293 if (proto != IPPROTO_TCP) 306 if (proto != IPPROTO_TCP) {
294 printf("%s\n", _("Receive failed")); 307 // printf("%s\n", _("Receive failed"));
308 }
295 result = STATE_WARNING; 309 result = STATE_WARNING;
296 } else 310 } else {
297 recv_buffer[recv_result] = 0; 311 recv_buffer[recv_result] = 0;
312 }
298 313
299 /* die returned string */ 314 /* die returned string */
300 recv_buffer[recv_size - 1] = 0; 315 recv_buffer[recv_size - 1] = 0;
@@ -303,26 +318,30 @@ int send_request(int sd, int proto, const char *send_buffer, char *recv_buffer,
303} 318}
304 319
305bool is_host(const char *address) { 320bool is_host(const char *address) {
306 if (is_addr(address) || is_hostname(address)) 321 if (is_addr(address) || is_hostname(address)) {
307 return (true); 322 return (true);
323 }
308 324
309 return (false); 325 return (false);
310} 326}
311 327
312void host_or_die(const char *str) { 328void host_or_die(const char *str) {
313 if (!str || (!is_addr(str) && !is_hostname(str))) 329 if (!str || (!is_addr(str) && !is_hostname(str))) {
314 usage_va(_("Invalid hostname/address - %s"), str); 330 usage_va(_("Invalid hostname/address - %s"), str);
331 }
315} 332}
316 333
317bool is_addr(const char *address) { 334bool is_addr(const char *address) {
318#ifdef USE_IPV6 335#ifdef USE_IPV6
319 if (address_family == AF_INET && is_inet_addr(address)) 336 if (address_family == AF_INET && is_inet_addr(address)) {
320 return true; 337 return true;
321 else if (address_family == AF_INET6 && is_inet6_addr(address)) 338 } else if (address_family == AF_INET6 && is_inet6_addr(address)) {
322 return true; 339 return true;
340 }
323#else 341#else
324 if (is_inet_addr(address)) 342 if (is_inet_addr(address)) {
325 return (true); 343 return (true);
344 }
326#endif 345#endif
327 346
328 return (false); 347 return (false);
@@ -337,11 +356,13 @@ int dns_lookup(const char *in, struct sockaddr_storage *ss, int family) {
337 hints.ai_family = family; 356 hints.ai_family = family;
338 357
339 retval = getaddrinfo(in, NULL, &hints, &res); 358 retval = getaddrinfo(in, NULL, &hints, &res);
340 if (retval != 0) 359 if (retval != 0) {
341 return false; 360 return false;
361 }
342 362
343 if (ss != NULL) 363 if (ss != NULL) {
344 memcpy(ss, res->ai_addr, res->ai_addrlen); 364 memcpy(ss, res->ai_addr, res->ai_addrlen);
365 }
345 freeaddrinfo(res); 366 freeaddrinfo(res);
346 return true; 367 return true;
347} 368}
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..08cadcbd 100644
--- a/plugins/t/check_jabber.t
+++ b/plugins/t/check_jabber.t
@@ -17,7 +17,7 @@ my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (no
17 17
18my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/'; 18my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' 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 = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/';
23 23
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_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 7e61b766..68946f6d 100644
--- a/plugins/t/check_swap.t
+++ b/plugins/t/check_swap.t
@@ -17,42 +17,35 @@ my $message = '/^[0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
17 17
18$result = NPTest->testCmd( "./check_swap $outputFormat" ); # Always OK 18$result = NPTest->testCmd( "./check_swap $outputFormat" ); # Always OK
19cmp_ok( $result->return_code, "==", 0, "Always OK" ); 19cmp_ok( $result->return_code, "==", 0, "Always OK" );
20$output = decode_json($result->output); 20is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
21is($output->{'state'}, "OK", "State was correct"); 21like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
22like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
23 22
24$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576 $outputFormat" ); # 1 MB free 23$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576 $outputFormat" ); # 1 MB free
25cmp_ok( $result->return_code, "==", 0, "Always OK" ); 24cmp_ok( $result->return_code, "==", 0, "Always OK" );
26$output = decode_json($result->output); 25is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
27is($output->{'state'}, "OK", "State was correct"); 26like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
28like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
29 27
30$result = NPTest->testCmd( "./check_swap -w 1% -c 1% $outputFormat" ); # 1% free 28$result = NPTest->testCmd( "./check_swap -w 1% -c 1% $outputFormat" ); # 1% free
31cmp_ok( $result->return_code, "==", 0, "Always OK" ); 29cmp_ok( $result->return_code, "==", 0, "Always OK" );
32$output = decode_json($result->output); 30is($result->{'mp_test_result'}->{'state'}, "OK", "State was correct");
33is($output->{'state'}, "OK", "State was correct"); 31like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
34like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
35 32
36$result = NPTest->testCmd( "./check_swap -w 100% -c 100% $outputFormat" ); # 100% (always critical) 33$result = NPTest->testCmd( "./check_swap -w 100% -c 100% $outputFormat" ); # 100% (always critical)
37cmp_ok( $result->return_code, "==", 0, "Always OK" ); 34cmp_ok( $result->return_code, "==", 0, "Always OK" );
38$output = decode_json($result->output); 35is($result->{'mp_test_result'}->{'state'}, "CRITICAL", "State was correct");
39is($output->{'state'}, "CRITICAL", "State was correct"); 36like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
40like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
41 37
42$result = NPTest->testCmd( "./check_swap -w 100% -c 1% $outputFormat" ); # 100% (always warn) 38$result = NPTest->testCmd( "./check_swap -w 100% -c 1% $outputFormat" ); # 100% (always warn)
43cmp_ok( $result->return_code, "==", 0, "Always OK" ); 39cmp_ok( $result->return_code, "==", 0, "Always OK" );
44$output = decode_json($result->output); 40is($result->{'mp_test_result'}->{'state'}, "WARNING", "State was correct");
45is($output->{'state'}, "WARNING", "State was correct"); 41like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
46like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
47 42
48$result = NPTest->testCmd( "./check_swap -w 100% $outputFormat" ); # 100% (single threshold, always warn) 43$result = NPTest->testCmd( "./check_swap -w 100% $outputFormat" ); # 100% (single threshold, always warn)
49cmp_ok( $result->return_code, "==", 0, "Always OK" ); 44cmp_ok( $result->return_code, "==", 0, "Always OK" );
50$output = decode_json($result->output); 45is($result->{'mp_test_result'}->{'state'}, "WARNING", "State was correct");
51is($output->{'state'}, "WARNING", "State was correct"); 46like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
52like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
53 47
54$result = NPTest->testCmd( "./check_swap -c 100% $outputFormat" ); # 100% (single threshold, always critical) 48$result = NPTest->testCmd( "./check_swap -c 100% $outputFormat" ); # 100% (single threshold, always critical)
55cmp_ok( $result->return_code, "==", 0, "Always OK" ); 49cmp_ok( $result->return_code, "==", 0, "Always OK" );
56$output = decode_json($result->output); 50is($result->{'mp_test_result'}->{'state'}, "CRITICAL", "State was correct");
57is($output->{'state'}, "CRITICAL", "State was correct"); 51like($result->{'mp_test_result'}->{'checks'}->[0]->{'output'}, $message, "Output was correct");
58like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
diff --git a/plugins/utils.c b/plugins/utils.c
index 09649429..34335c89 100644
--- a/plugins/utils.c
+++ b/plugins/utils.c
@@ -89,41 +89,46 @@ bool is_numeric(char *number) {
89 char tmp[1]; 89 char tmp[1];
90 float x; 90 float x;
91 91
92 if (!number) 92 if (!number) {
93 return false; 93 return false;
94 else if (sscanf(number, "%f%c", &x, tmp) == 1) 94 } else if (sscanf(number, "%f%c", &x, tmp) == 1) {
95 return true; 95 return true;
96 else 96 } else {
97 return false; 97 return false;
98 }
98} 99}
99 100
100bool is_positive(char *number) { 101bool is_positive(char *number) {
101 if (is_numeric(number) && atof(number) > 0.0) 102 if (is_numeric(number) && atof(number) > 0.0) {
102 return true; 103 return true;
103 else 104 } else {
104 return false; 105 return false;
106 }
105} 107}
106 108
107bool is_negative(char *number) { 109bool is_negative(char *number) {
108 if (is_numeric(number) && atof(number) < 0.0) 110 if (is_numeric(number) && atof(number) < 0.0) {
109 return true; 111 return true;
110 else 112 } else {
111 return false; 113 return false;
114 }
112} 115}
113 116
114bool is_nonnegative(char *number) { 117bool is_nonnegative(char *number) {
115 if (is_numeric(number) && atof(number) >= 0.0) 118 if (is_numeric(number) && atof(number) >= 0.0) {
116 return true; 119 return true;
117 else 120 } else {
118 return false; 121 return false;
122 }
119} 123}
120 124
121bool is_percentage(char *number) { 125bool is_percentage(char *number) {
122 int x; 126 int x;
123 if (is_numeric(number) && (x = atof(number)) >= 0 && x <= 100) 127 if (is_numeric(number) && (x = atof(number)) >= 0 && x <= 100) {
124 return true; 128 return true;
125 else 129 } else {
126 return false; 130 return false;
131 }
127} 132}
128 133
129bool is_percentage_expression(const char str[]) { 134bool is_percentage_expression(const char str[]) {
@@ -156,36 +161,41 @@ bool is_percentage_expression(const char str[]) {
156bool is_integer(char *number) { 161bool is_integer(char *number) {
157 long int n; 162 long int n;
158 163
159 if (!number || (strspn(number, "-0123456789 ") != strlen(number))) 164 if (!number || (strspn(number, "-0123456789 ") != strlen(number))) {
160 return false; 165 return false;
166 }
161 167
162 n = strtol(number, NULL, 10); 168 n = strtol(number, NULL, 10);
163 169
164 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) 170 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) {
165 return true; 171 return true;
166 else 172 } else {
167 return false; 173 return false;
174 }
168} 175}
169 176
170bool is_intpos(char *number) { 177bool is_intpos(char *number) {
171 if (is_integer(number) && atoi(number) > 0) 178 if (is_integer(number) && atoi(number) > 0) {
172 return true; 179 return true;
173 else 180 } else {
174 return false; 181 return false;
182 }
175} 183}
176 184
177bool is_intneg(char *number) { 185bool is_intneg(char *number) {
178 if (is_integer(number) && atoi(number) < 0) 186 if (is_integer(number) && atoi(number) < 0) {
179 return true; 187 return true;
180 else 188 } else {
181 return false; 189 return false;
190 }
182} 191}
183 192
184bool is_intnonneg(char *number) { 193bool is_intnonneg(char *number) {
185 if (is_integer(number) && atoi(number) >= 0) 194 if (is_integer(number) && atoi(number) >= 0) {
186 return true; 195 return true;
187 else 196 } else {
188 return false; 197 return false;
198 }
189} 199}
190 200
191/* 201/*
@@ -247,19 +257,21 @@ bool is_uint64(char *number, uint64_t *target) {
247 257
248bool is_intpercent(char *number) { 258bool is_intpercent(char *number) {
249 int i; 259 int i;
250 if (is_integer(number) && (i = atoi(number)) >= 0 && i <= 100) 260 if (is_integer(number) && (i = atoi(number)) >= 0 && i <= 100) {
251 return true; 261 return true;
252 else 262 } else {
253 return false; 263 return false;
264 }
254} 265}
255 266
256bool is_option(char *str) { 267bool is_option(char *str) {
257 if (!str) 268 if (!str) {
258 return false; 269 return false;
259 else if (strspn(str, "-") == 1 || strspn(str, "-") == 2) 270 } else if (strspn(str, "-") == 1 || strspn(str, "-") == 2) {
260 return true; 271 return true;
261 else 272 } else {
262 return false; 273 return false;
274 }
263} 275}
264 276
265#ifdef NEED_GETTIMEOFDAY 277#ifdef NEED_GETTIMEOFDAY
@@ -288,10 +300,11 @@ void strip(char *buffer) {
288 300
289 for (x = strlen(buffer); x >= 1; x--) { 301 for (x = strlen(buffer); x >= 1; x--) {
290 i = x - 1; 302 i = x - 1;
291 if (buffer[i] == ' ' || buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t') 303 if (buffer[i] == ' ' || buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t') {
292 buffer[i] = '\0'; 304 buffer[i] = '\0';
293 else 305 } else {
294 break; 306 break;
307 }
295 } 308 }
296 return; 309 return;
297} 310}
@@ -309,8 +322,9 @@ void strip(char *buffer) {
309 *****************************************************************************/ 322 *****************************************************************************/
310 323
311char *strscpy(char *dest, const char *src) { 324char *strscpy(char *dest, const char *src) {
312 if (src == NULL) 325 if (src == NULL) {
313 return NULL; 326 return NULL;
327 }
314 328
315 xasprintf(&dest, "%s", src); 329 xasprintf(&dest, "%s", src);
316 330
@@ -369,17 +383,21 @@ char *strscpy(char *dest, const char *src) {
369 383
370char *strnl(char *str) { 384char *strnl(char *str) {
371 size_t len; 385 size_t len;
372 if (str == NULL) 386 if (str == NULL) {
373 return NULL; 387 return NULL;
388 }
374 str = strpbrk(str, "\r\n"); 389 str = strpbrk(str, "\r\n");
375 if (str == NULL) 390 if (str == NULL) {
376 return NULL; 391 return NULL;
392 }
377 len = strspn(str, "\r\n"); 393 len = strspn(str, "\r\n");
378 if (str[len] == '\0') 394 if (str[len] == '\0') {
379 return NULL; 395 return NULL;
396 }
380 str += len; 397 str += len;
381 if (strlen(str) == 0) 398 if (strlen(str) == 0) {
382 return NULL; 399 return NULL;
400 }
383 return str; 401 return str;
384} 402}
385 403
@@ -402,15 +420,18 @@ char *strnl(char *str) {
402char *strpcpy(char *dest, const char *src, const char *str) { 420char *strpcpy(char *dest, const char *src, const char *str) {
403 size_t len; 421 size_t len;
404 422
405 if (src) 423 if (src) {
406 len = strcspn(src, str); 424 len = strcspn(src, str);
407 else 425 } else {
408 return NULL; 426 return NULL;
427 }
409 428
410 if (dest == NULL || strlen(dest) < len) 429 if (dest == NULL || strlen(dest) < len) {
411 dest = realloc(dest, len + 1); 430 dest = realloc(dest, len + 1);
412 if (dest == NULL) 431 }
432 if (dest == NULL) {
413 die(STATE_UNKNOWN, _("failed realloc in strpcpy\n")); 433 die(STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
434 }
414 435
415 strncpy(dest, src, len); 436 strncpy(dest, src, len);
416 dest[len] = '\0'; 437 dest[len] = '\0';
@@ -434,10 +455,11 @@ char *strpcpy(char *dest, const char *src, const char *str) {
434char *strpcat(char *dest, const char *src, const char *str) { 455char *strpcat(char *dest, const char *src, const char *str) {
435 size_t len, l2; 456 size_t len, l2;
436 457
437 if (dest) 458 if (dest) {
438 len = strlen(dest); 459 len = strlen(dest);
439 else 460 } else {
440 len = 0; 461 len = 0;
462 }
441 463
442 if (src) { 464 if (src) {
443 l2 = strcspn(src, str); 465 l2 = strcspn(src, str);
@@ -446,8 +468,9 @@ char *strpcat(char *dest, const char *src, const char *str) {
446 } 468 }
447 469
448 dest = realloc(dest, len + l2 + 1); 470 dest = realloc(dest, len + l2 + 1);
449 if (dest == NULL) 471 if (dest == NULL) {
450 die(STATE_UNKNOWN, _("failed malloc in strscat\n")); 472 die(STATE_UNKNOWN, _("failed malloc in strscat\n"));
473 }
451 474
452 strncpy(dest + len, src, l2); 475 strncpy(dest + len, src, l2);
453 dest[len + l2] = '\0'; 476 dest[len + l2] = '\0';
@@ -463,8 +486,9 @@ char *strpcat(char *dest, const char *src, const char *str) {
463 486
464int xvasprintf(char **strp, const char *fmt, va_list ap) { 487int xvasprintf(char **strp, const char *fmt, va_list ap) {
465 int result = vasprintf(strp, fmt, ap); 488 int result = vasprintf(strp, fmt, ap);
466 if (result == -1 || *strp == NULL) 489 if (result == -1 || *strp == NULL) {
467 die(STATE_UNKNOWN, _("failed malloc in xvasprintf\n")); 490 die(STATE_UNKNOWN, _("failed malloc in xvasprintf\n"));
491 }
468 return result; 492 return result;
469} 493}
470 494
@@ -483,126 +507,145 @@ int xasprintf(char **strp, const char *fmt, ...) {
483 * 507 *
484 ******************************************************************************/ 508 ******************************************************************************/
485 509
486char *perfdata(const char *label, long int val, const char *uom, int warnp, long int warn, int critp, long int crit, int minp, 510char *perfdata(const char *label, long int val, const char *uom, bool warnp, long int warn, bool critp, long int crit, bool minp,
487 long int minv, int maxp, long int maxv) { 511 long int minv, bool maxp, long int maxv) {
488 char *data = NULL; 512 char *data = NULL;
489 513
490 if (strpbrk(label, "'= ")) 514 if (strpbrk(label, "'= ")) {
491 xasprintf(&data, "'%s'=%ld%s;", label, val, uom); 515 xasprintf(&data, "'%s'=%ld%s;", label, val, uom);
492 else 516 } else {
493 xasprintf(&data, "%s=%ld%s;", label, val, uom); 517 xasprintf(&data, "%s=%ld%s;", label, val, uom);
518 }
494 519
495 if (warnp) 520 if (warnp) {
496 xasprintf(&data, "%s%ld;", data, warn); 521 xasprintf(&data, "%s%ld;", data, warn);
497 else 522 } else {
498 xasprintf(&data, "%s;", data); 523 xasprintf(&data, "%s;", data);
524 }
499 525
500 if (critp) 526 if (critp) {
501 xasprintf(&data, "%s%ld;", data, crit); 527 xasprintf(&data, "%s%ld;", data, crit);
502 else 528 } else {
503 xasprintf(&data, "%s;", data); 529 xasprintf(&data, "%s;", data);
530 }
504 531
505 if (minp) 532 if (minp) {
506 xasprintf(&data, "%s%ld;", data, minv); 533 xasprintf(&data, "%s%ld;", data, minv);
507 else 534 } else {
508 xasprintf(&data, "%s;", data); 535 xasprintf(&data, "%s;", data);
536 }
509 537
510 if (maxp) 538 if (maxp) {
511 xasprintf(&data, "%s%ld", data, maxv); 539 xasprintf(&data, "%s%ld", data, maxv);
540 }
512 541
513 return data; 542 return data;
514} 543}
515 544
516char *perfdata_uint64(const char *label, uint64_t val, const char *uom, int warnp, /* Warning present */ 545char *perfdata_uint64(const char *label, uint64_t val, const char *uom, bool warnp, /* Warning present */
517 uint64_t warn, int critp, /* Critical present */ 546 uint64_t warn, bool critp, /* Critical present */
518 uint64_t crit, int minp, /* Minimum present */ 547 uint64_t crit, bool minp, /* Minimum present */
519 uint64_t minv, int maxp, /* Maximum present */ 548 uint64_t minv, bool maxp, /* Maximum present */
520 uint64_t maxv) { 549 uint64_t maxv) {
521 char *data = NULL; 550 char *data = NULL;
522 551
523 if (strpbrk(label, "'= ")) 552 if (strpbrk(label, "'= ")) {
524 xasprintf(&data, "'%s'=%" PRIu64 "%s;", label, val, uom); 553 xasprintf(&data, "'%s'=%" PRIu64 "%s;", label, val, uom);
525 else 554 } else {
526 xasprintf(&data, "%s=%" PRIu64 "%s;", label, val, uom); 555 xasprintf(&data, "%s=%" PRIu64 "%s;", label, val, uom);
556 }
527 557
528 if (warnp) 558 if (warnp) {
529 xasprintf(&data, "%s%" PRIu64 ";", data, warn); 559 xasprintf(&data, "%s%" PRIu64 ";", data, warn);
530 else 560 } else {
531 xasprintf(&data, "%s;", data); 561 xasprintf(&data, "%s;", data);
562 }
532 563
533 if (critp) 564 if (critp) {
534 xasprintf(&data, "%s%" PRIu64 ";", data, crit); 565 xasprintf(&data, "%s%" PRIu64 ";", data, crit);
535 else 566 } else {
536 xasprintf(&data, "%s;", data); 567 xasprintf(&data, "%s;", data);
568 }
537 569
538 if (minp) 570 if (minp) {
539 xasprintf(&data, "%s%" PRIu64 ";", data, minv); 571 xasprintf(&data, "%s%" PRIu64 ";", data, minv);
540 else 572 } else {
541 xasprintf(&data, "%s;", data); 573 xasprintf(&data, "%s;", data);
574 }
542 575
543 if (maxp) 576 if (maxp) {
544 xasprintf(&data, "%s%" PRIu64, data, maxv); 577 xasprintf(&data, "%s%" PRIu64, data, maxv);
578 }
545 579
546 return data; 580 return data;
547} 581}
548 582
549char *perfdata_int64(const char *label, int64_t val, const char *uom, int warnp, /* Warning present */ 583char *perfdata_int64(const char *label, int64_t val, const char *uom, bool warnp, /* Warning present */
550 int64_t warn, int critp, /* Critical present */ 584 int64_t warn, bool critp, /* Critical present */
551 int64_t crit, int minp, /* Minimum present */ 585 int64_t crit, bool minp, /* Minimum present */
552 int64_t minv, int maxp, /* Maximum present */ 586 int64_t minv, bool maxp, /* Maximum present */
553 int64_t maxv) { 587 int64_t maxv) {
554 char *data = NULL; 588 char *data = NULL;
555 589
556 if (strpbrk(label, "'= ")) 590 if (strpbrk(label, "'= ")) {
557 xasprintf(&data, "'%s'=%" PRId64 "%s;", label, val, uom); 591 xasprintf(&data, "'%s'=%" PRId64 "%s;", label, val, uom);
558 else 592 } else {
559 xasprintf(&data, "%s=%" PRId64 "%s;", label, val, uom); 593 xasprintf(&data, "%s=%" PRId64 "%s;", label, val, uom);
594 }
560 595
561 if (warnp) 596 if (warnp) {
562 xasprintf(&data, "%s%" PRId64 ";", data, warn); 597 xasprintf(&data, "%s%" PRId64 ";", data, warn);
563 else 598 } else {
564 xasprintf(&data, "%s;", data); 599 xasprintf(&data, "%s;", data);
600 }
565 601
566 if (critp) 602 if (critp) {
567 xasprintf(&data, "%s%" PRId64 ";", data, crit); 603 xasprintf(&data, "%s%" PRId64 ";", data, crit);
568 else 604 } else {
569 xasprintf(&data, "%s;", data); 605 xasprintf(&data, "%s;", data);
606 }
570 607
571 if (minp) 608 if (minp) {
572 xasprintf(&data, "%s%" PRId64 ";", data, minv); 609 xasprintf(&data, "%s%" PRId64 ";", data, minv);
573 else 610 } else {
574 xasprintf(&data, "%s;", data); 611 xasprintf(&data, "%s;", data);
612 }
575 613
576 if (maxp) 614 if (maxp) {
577 xasprintf(&data, "%s%" PRId64, data, maxv); 615 xasprintf(&data, "%s%" PRId64, data, maxv);
616 }
578 617
579 return data; 618 return data;
580} 619}
581 620
582char *fperfdata(const char *label, double val, const char *uom, int warnp, double warn, int critp, double crit, int minp, double minv, 621char *fperfdata(const char *label, double val, const char *uom, bool warnp, double warn, bool critp, double crit, bool minp, double minv,
583 int maxp, double maxv) { 622 bool maxp, double maxv) {
584 char *data = NULL; 623 char *data = NULL;
585 624
586 if (strpbrk(label, "'= ")) 625 if (strpbrk(label, "'= ")) {
587 xasprintf(&data, "'%s'=", label); 626 xasprintf(&data, "'%s'=", label);
588 else 627 } else {
589 xasprintf(&data, "%s=", label); 628 xasprintf(&data, "%s=", label);
629 }
590 630
591 xasprintf(&data, "%s%f", data, val); 631 xasprintf(&data, "%s%f", data, val);
592 xasprintf(&data, "%s%s;", data, uom); 632 xasprintf(&data, "%s%s;", data, uom);
593 633
594 if (warnp) 634 if (warnp) {
595 xasprintf(&data, "%s%f", data, warn); 635 xasprintf(&data, "%s%f", data, warn);
636 }
596 637
597 xasprintf(&data, "%s;", data); 638 xasprintf(&data, "%s;", data);
598 639
599 if (critp) 640 if (critp) {
600 xasprintf(&data, "%s%f", data, crit); 641 xasprintf(&data, "%s%f", data, crit);
642 }
601 643
602 xasprintf(&data, "%s;", data); 644 xasprintf(&data, "%s;", data);
603 645
604 if (minp) 646 if (minp) {
605 xasprintf(&data, "%s%f", data, minv); 647 xasprintf(&data, "%s%f", data, minv);
648 }
606 649
607 if (maxp) { 650 if (maxp) {
608 xasprintf(&data, "%s;", data); 651 xasprintf(&data, "%s;", data);
@@ -612,28 +655,32 @@ char *fperfdata(const char *label, double val, const char *uom, int warnp, doubl
612 return data; 655 return data;
613} 656}
614 657
615char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, int minp, double minv, int maxp, double maxv) { 658char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, bool minp, double minv, bool maxp, double maxv) {
616 char *data = NULL; 659 char *data = NULL;
617 if (strpbrk(label, "'= ")) 660 if (strpbrk(label, "'= ")) {
618 xasprintf(&data, "'%s'=", label); 661 xasprintf(&data, "'%s'=", label);
619 else 662 } else {
620 xasprintf(&data, "%s=", label); 663 xasprintf(&data, "%s=", label);
664 }
621 665
622 xasprintf(&data, "%s%f", data, val); 666 xasprintf(&data, "%s%f", data, val);
623 xasprintf(&data, "%s%s;", data, uom); 667 xasprintf(&data, "%s%s;", data, uom);
624 668
625 if (warn != NULL) 669 if (warn != NULL) {
626 xasprintf(&data, "%s%s", data, warn); 670 xasprintf(&data, "%s%s", data, warn);
671 }
627 672
628 xasprintf(&data, "%s;", data); 673 xasprintf(&data, "%s;", data);
629 674
630 if (crit != NULL) 675 if (crit != NULL) {
631 xasprintf(&data, "%s%s", data, crit); 676 xasprintf(&data, "%s%s", data, crit);
677 }
632 678
633 xasprintf(&data, "%s;", data); 679 xasprintf(&data, "%s;", data);
634 680
635 if (minp) 681 if (minp) {
636 xasprintf(&data, "%s%f", data, minv); 682 xasprintf(&data, "%s%f", data, minv);
683 }
637 684
638 if (maxp) { 685 if (maxp) {
639 xasprintf(&data, "%s;", data); 686 xasprintf(&data, "%s;", data);
@@ -643,28 +690,32 @@ char *sperfdata(const char *label, double val, const char *uom, char *warn, char
643 return data; 690 return data;
644} 691}
645 692
646char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, int minp, int minv, int maxp, int maxv) { 693char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, bool minp, int minv, bool maxp, int maxv) {
647 char *data = NULL; 694 char *data = NULL;
648 if (strpbrk(label, "'= ")) 695 if (strpbrk(label, "'= ")) {
649 xasprintf(&data, "'%s'=", label); 696 xasprintf(&data, "'%s'=", label);
650 else 697 } else {
651 xasprintf(&data, "%s=", label); 698 xasprintf(&data, "%s=", label);
699 }
652 700
653 xasprintf(&data, "%s%d", data, val); 701 xasprintf(&data, "%s%d", data, val);
654 xasprintf(&data, "%s%s;", data, uom); 702 xasprintf(&data, "%s%s;", data, uom);
655 703
656 if (warn != NULL) 704 if (warn != NULL) {
657 xasprintf(&data, "%s%s", data, warn); 705 xasprintf(&data, "%s%s", data, warn);
706 }
658 707
659 xasprintf(&data, "%s;", data); 708 xasprintf(&data, "%s;", data);
660 709
661 if (crit != NULL) 710 if (crit != NULL) {
662 xasprintf(&data, "%s%s", data, crit); 711 xasprintf(&data, "%s%s", data, crit);
712 }
663 713
664 xasprintf(&data, "%s;", data); 714 xasprintf(&data, "%s;", data);
665 715
666 if (minp) 716 if (minp) {
667 xasprintf(&data, "%s%d", data, minv); 717 xasprintf(&data, "%s%d", data, minv);
718 }
668 719
669 if (maxp) { 720 if (maxp) {
670 xasprintf(&data, "%s;", data); 721 xasprintf(&data, "%s;", data);
diff --git a/plugins/utils.h b/plugins/utils.h
index 029ae5a6..92a6c115 100644
--- a/plugins/utils.h
+++ b/plugins/utils.h
@@ -21,43 +21,43 @@ suite of plugins. */
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,142 @@ 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, ...);
80 80
81void usage (const char *) __attribute__((noreturn)); 81void usage(const char *) __attribute__((noreturn));
82void usage2(const char *, const char *) __attribute__((noreturn)); 82void usage2(const char *, const char *) __attribute__((noreturn));
83void usage3(const char *, int) __attribute__((noreturn)); 83void usage3(const char *, int) __attribute__((noreturn));
84void usage4(const char *) __attribute__((noreturn)); 84void usage4(const char *) __attribute__((noreturn));
85void usage5(void) __attribute__((noreturn)); 85void usage5(void) __attribute__((noreturn));
86void usage_va(const char *fmt, ...) __attribute__((noreturn)); 86void usage_va(const char *fmt, ...) __attribute__((noreturn));
87 87
88#define max(a,b) (((a)>(b))?(a):(b)) 88#define max(a, b) (((a) > (b)) ? (a) : (b))
89#define min(a,b) (((a)<(b))?(a):(b)) 89#define min(a, b) (((a) < (b)) ? (a) : (b))
90 90
91char *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);
92 int, long int, int, long int, int, long int);
93 92
94char *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);
95 int, uint64_t, int, uint64_t, int, uint64_t);
96 94
97char *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);
98 int, int64_t, int, int64_t, int, int64_t);
99 96
100char *fperfdata (const char *, double, const char *, int, double, 97char *fperfdata(const char *, double, const char *, bool, double, bool, double, bool, double, bool, double);
101 int, double, int, double, int, double);
102 98
103char *sperfdata (const char *, double, const char *, char *, char *, 99char *sperfdata(const char *, double, const char *, char *, char *, bool, double, bool, double);
104 int, double, int, double);
105 100
106char *sperfdata_int (const char *, int, const char *, char *, char *, 101char *sperfdata_int(const char *, int, const char *, char *, char *, bool, int, bool, int);
107 int, int, int, int);
108 102
109/* 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,
110 most will or should. Therefore, for consistency, these very common 104 most will or should. Therefore, for consistency, these very common
111 options should have only these meanings throughout the overall suite */ 105 options should have only these meanings throughout the overall suite */
112 106
113#define STD_LONG_OPTS \ 107#define STD_LONG_OPTS \
114{"version",no_argument,0,'V'},\ 108 {"version", no_argument, 0, 'V'}, {"verbose", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, \
115{"verbose",no_argument,0,'v'},\ 109 {"timeout", required_argument, 0, 't'}, {"critical", required_argument, 0, 'c'}, {"warning", required_argument, 0, 'w'}, \
116{"help",no_argument,0,'h'},\ 110 {"hostname", required_argument, 0, 'H'}
117{"timeout",required_argument,0,'t'},\
118{"critical",required_argument,0,'c'},\
119{"warning",required_argument,0,'w'},\
120{"hostname",required_argument,0,'H'}
121 111
122#define COPYRIGHT "Copyright (c) %s Monitoring Plugins Development Team\n\ 112#define COPYRIGHT \
113 "Copyright (c) %s Monitoring Plugins Development Team\n\
123\t<%s>\n\n" 114\t<%s>\n\n"
124 115
125#define UT_HLP_VRS _("\ 116#define UT_HLP_VRS \
117 _("\
126 %s (-h | --help) for detailed help\n\ 118 %s (-h | --help) for detailed help\n\
127 %s (-V | --version) for version information\n") 119 %s (-V | --version) for version information\n")
128 120
129#define UT_HELP_VRSN _("\ 121#define UT_HELP_VRSN \
122 _("\
130\nOptions:\n\ 123\nOptions:\n\
131 -h, --help\n\ 124 -h, --help\n\
132 Print detailed help screen\n\ 125 Print detailed help screen\n\
133 -V, --version\n\ 126 -V, --version\n\
134 Print version information\n") 127 Print version information\n")
135 128
136#define UT_HOST_PORT _("\ 129#define UT_HOST_PORT \
130 _("\
137 -H, --hostname=ADDRESS\n\ 131 -H, --hostname=ADDRESS\n\
138 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\
139 -%c, --port=INTEGER\n\ 133 -%c, --port=INTEGER\n\
140 Port number (default: %s)\n") 134 Port number (default: %s)\n")
141 135
142#define UT_IPv46 _("\ 136#define UT_IPv46 \
137 _("\
143 -4, --use-ipv4\n\ 138 -4, --use-ipv4\n\
144 Use IPv4 connection\n\ 139 Use IPv4 connection\n\
145 -6, --use-ipv6\n\ 140 -6, --use-ipv6\n\
146 Use IPv6 connection\n") 141 Use IPv6 connection\n")
147 142
148#define UT_VERBOSE _("\ 143#define UT_VERBOSE \
144 _("\
149 -v, --verbose\n\ 145 -v, --verbose\n\
150 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\
151 the monitoring system)\n") 147 the monitoring system)\n")
152 148
153#define UT_WARN_CRIT _("\ 149#define UT_WARN_CRIT \
150 _("\
154 -w, --warning=DOUBLE\n\ 151 -w, --warning=DOUBLE\n\
155 Response time to result in warning status (seconds)\n\ 152 Response time to result in warning status (seconds)\n\
156 -c, --critical=DOUBLE\n\ 153 -c, --critical=DOUBLE\n\
157 Response time to result in critical status (seconds)\n") 154 Response time to result in critical status (seconds)\n")
158 155
159#define UT_WARN_CRIT_RANGE _("\ 156#define UT_WARN_CRIT_RANGE \
157 _("\
160 -w, --warning=RANGE\n\ 158 -w, --warning=RANGE\n\
161 Warning range (format: start:end). Alert if outside this range\n\ 159 Warning range (format: start:end). Alert if outside this range\n\
162 -c, --critical=RANGE\n\ 160 -c, --critical=RANGE\n\
163 Critical range\n") 161 Critical range\n")
164 162
165#define UT_CONN_TIMEOUT _("\ 163#define UT_CONN_TIMEOUT \
164 _("\
166 -t, --timeout=INTEGER\n\ 165 -t, --timeout=INTEGER\n\
167 Seconds before connection times out (default: %d)\n") 166 Seconds before connection times out (default: %d)\n")
168 167
169#define UT_PLUG_TIMEOUT _("\ 168#define UT_PLUG_TIMEOUT \
169 _("\
170 -t, --timeout=INTEGER\n\ 170 -t, --timeout=INTEGER\n\
171 Seconds before plugin times out (default: %d)\n") 171 Seconds before plugin times out (default: %d)\n")
172 172
173#ifdef NP_EXTRA_OPTS 173#ifdef NP_EXTRA_OPTS
174#define UT_EXTRA_OPTS _("\ 174# define UT_EXTRA_OPTS \
175 _("\
175 --extra-opts=[section][@file]\n\ 176 --extra-opts=[section][@file]\n\
176 Read options from an ini file. See\n\ 177 Read options from an ini file. See\n\
177 https://www.monitoring-plugins.org/doc/extra-opts.html\n\ 178 https://www.monitoring-plugins.org/doc/extra-opts.html\n\
178 for usage and examples.\n") 179 for usage and examples.\n")
179#else 180#else
180#define UT_EXTRA_OPTS " \b" 181# define UT_EXTRA_OPTS " \b"
181#endif 182#endif
182 183
183#define UT_THRESHOLDS_NOTES _("\ 184#define UT_THRESHOLDS_NOTES \
185 _("\
184 See:\n\ 186 See:\n\
185 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\ 187 https://www.monitoring-plugins.org/doc/guidelines.html#THRESHOLDFORMAT\n\
186 for THRESHOLD format and examples.\n") 188 for THRESHOLD format and examples.\n")
187 189
188#define UT_SUPPORT _("\n\ 190#define UT_SUPPORT \
191 _("\n\
189Send 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\
190use 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\
191to devel@monitoring-plugins.org\n\n") 194to devel@monitoring-plugins.org\n\n")
192 195
193#define UT_NOWARRANTY _("\n\ 196#define UT_NOWARRANTY \
197 _("\n\
194The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\ 198The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
195copies 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\
196For more information about these matters, see the file named COPYING.\n") 200For more information about these matters, see the file named COPYING.\n")
197 201
198#define UT_OUTPUT_FORMAT _("\ 202#define UT_OUTPUT_FORMAT \
203 _("\
199 --output-format=OUTPUT_FORMAT\n\ 204 --output-format=OUTPUT_FORMAT\n\
200 Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n") 205 Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n")
201 206