summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/monitoring-plugins.spec14
-rw-r--r--.gitignore1
-rw-r--r--plugins/Makefile.am11
-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_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_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
20 files changed, 1676 insertions, 1579 deletions
diff --git a/.github/monitoring-plugins.spec b/.github/monitoring-plugins.spec
index 5cae3e59..64ee34f2 100644
--- a/.github/monitoring-plugins.spec
+++ b/.github/monitoring-plugins.spec
@@ -193,7 +193,6 @@ Requires: %{name}-ntp_peer
193Requires: %{name}-ntp_time 193Requires: %{name}-ntp_time
194Requires: %{name}-nwstat 194Requires: %{name}-nwstat
195Requires: %{name}-oracle 195Requires: %{name}-oracle
196Requires: %{name}-overcr
197Requires: %{name}-pgsql 196Requires: %{name}-pgsql
198Requires: %{name}-ping 197Requires: %{name}-ping
199Requires: %{name}-procs 198Requires: %{name}-procs
@@ -729,19 +728,6 @@ Provides check_oracle of the Monitoring Plugins.
729 728
730 729
731 730
732# check_overcr
733%package overcr
734Summary: Monitoring Plugins - check_overcr
735Requires: %{name} = %{version}-%{release}
736
737%description overcr
738Provides check_overcr of the Monitoring Plugins.
739
740%files overcr
741%{plugindir}/check_overcr
742
743
744
745# check_pgsql 731# check_pgsql
746%package pgsql 732%package pgsql
747Summary: Monitoring Plugins - check_pgsql 733Summary: Monitoring Plugins - check_pgsql
diff --git a/.gitignore b/.gitignore
index 0efc2b66..f9cb37e4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -178,7 +178,6 @@ NP-VERSION-FILE
178/plugins/check_ntp_peer 178/plugins/check_ntp_peer
179/plugins/check_ntp_time 179/plugins/check_ntp_time
180/plugins/check_nwstat 180/plugins/check_nwstat
181/plugins/check_overcr
182/plugins/check_pgsql 181/plugins/check_pgsql
183/plugins/check_ping 182/plugins/check_ping
184/plugins/check_pop 183/plugins/check_pop
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index a6c0ba65..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@
@@ -49,25 +49,33 @@ np_test_scripts = tests/test_check_swap.t
49EXTRA_DIST = t \ 49EXTRA_DIST = t \
50 tests \ 50 tests \
51 $(np_test_scripts) \ 51 $(np_test_scripts) \
52 negate.d \
52 check_swap.d \ 53 check_swap.d \
53 check_ldap.d \ 54 check_ldap.d \
54 check_hpjd.d \ 55 check_hpjd.d \
55 check_game.d \ 56 check_game.d \
57 check_radius.d \
58 check_time.d \
56 check_nagios.d \ 59 check_nagios.d \
57 check_dbi.d \ 60 check_dbi.d \
61 check_real.d \
58 check_ssh.d \ 62 check_ssh.d \
59 check_nt.d \ 63 check_nt.d \
60 check_dns.d \ 64 check_dns.d \
61 check_mrtgtraf.d \ 65 check_mrtgtraf.d \
62 check_mysql_query.d \ 66 check_mysql_query.d \
63 check_mrtg.d \ 67 check_mrtg.d \
68 check_ntp_peer.d \
64 check_apt.d \ 69 check_apt.d \
65 check_pgsql.d \ 70 check_pgsql.d \
71 check_ping.d \
66 check_by_ssh.d \ 72 check_by_ssh.d \
67 check_smtp.d \ 73 check_smtp.d \
68 check_mysql.d \ 74 check_mysql.d \
75 check_ntp_time.d \
69 check_dig.d \ 76 check_dig.d \
70 check_cluster.d \ 77 check_cluster.d \
78 check_ups.d \
71 check_fping.d 79 check_fping.d
72 80
73PLUGINHDRS = common.h 81PLUGINHDRS = common.h
@@ -131,7 +139,6 @@ check_nt_LDADD = $(NETLIBS)
131check_ntp_LDADD = $(NETLIBS) $(MATHLIBS) 139check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
132check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 140check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
133check_nwstat_LDADD = $(NETLIBS) 141check_nwstat_LDADD = $(NETLIBS)
134check_overcr_LDADD = $(NETLIBS)
135check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) 142check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
136check_ping_LDADD = $(NETLIBS) 143check_ping_LDADD = $(NETLIBS)
137check_procs_LDADD = $(BASEOBJS) 144check_procs_LDADD = $(BASEOBJS)
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_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_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}