summaryrefslogtreecommitdiffstats
path: root/plugins/check_ntp_time.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_ntp_time.c')
-rw-r--r--plugins/check_ntp_time.c299
1 files changed, 164 insertions, 135 deletions
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
index 703b69df..ad69b804 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
@@ -92,9 +93,9 @@ typedef struct {
92/* bits 1,2 are the leap indicator */ 93/* bits 1,2 are the leap indicator */
93#define LI_MASK 0xc0 94#define LI_MASK 0xc0
94#define LI(x) ((x & LI_MASK) >> 6) 95#define LI(x) ((x & LI_MASK) >> 6)
95#define LI_SET(x, y) \ 96#define LI_SET(x, y) \
96 do { \ 97 do { \
97 x |= ((y << 6) & LI_MASK); \ 98 x |= ((y << 6) & LI_MASK); \
98 } while (0) 99 } while (0)
99/* and these are the values of the leap indicator */ 100/* and these are the values of the leap indicator */
100#define LI_NOWARNING 0x00 101#define LI_NOWARNING 0x00
@@ -104,17 +105,17 @@ typedef struct {
104/* bits 3,4,5 are the ntp version */ 105/* bits 3,4,5 are the ntp version */
105#define VN_MASK 0x38 106#define VN_MASK 0x38
106#define VN(x) ((x & VN_MASK) >> 3) 107#define VN(x) ((x & VN_MASK) >> 3)
107#define VN_SET(x, y) \ 108#define VN_SET(x, y) \
108 do { \ 109 do { \
109 x |= ((y << 3) & VN_MASK); \ 110 x |= ((y << 3) & VN_MASK); \
110 } while (0) 111 } while (0)
111#define VN_RESERVED 0x02 112#define VN_RESERVED 0x02
112/* bits 6,7,8 are the ntp mode */ 113/* bits 6,7,8 are the ntp mode */
113#define MODE_MASK 0x07 114#define MODE_MASK 0x07
114#define MODE(x) (x & MODE_MASK) 115#define MODE(x) (x & MODE_MASK)
115#define MODE_SET(x, y) \ 116#define MODE_SET(x, y) \
116 do { \ 117 do { \
117 x |= (y & MODE_MASK); \ 118 x |= (y & MODE_MASK); \
118 } while (0) 119 } while (0)
119/* here are some values */ 120/* here are some values */
120#define MODE_CLIENT 0x03 121#define MODE_CLIENT 0x03
@@ -126,9 +127,9 @@ typedef struct {
126#define REM_MORE 0x20 127#define REM_MORE 0x20
127/* In control message, bits 11 - 15 are opcode */ 128/* In control message, bits 11 - 15 are opcode */
128#define OP_MASK 0x1f 129#define OP_MASK 0x1f
129#define OP_SET(x, y) \ 130#define OP_SET(x, y) \
130 do { \ 131 do { \
131 x |= (y & OP_MASK); \ 132 x |= (y & OP_MASK); \
132 } while (0) 133 } while (0)
133#define OP_READSTAT 0x01 134#define OP_READSTAT 0x01
134#define OP_READVAR 0x02 135#define OP_READVAR 0x02
@@ -159,35 +160,37 @@ 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) \
166 (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) : 0) 167 (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + \
168 (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) \
169 : 0)
167 170
168/* convert a struct timeval to a double */ 171/* convert a struct timeval to a double */
169#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec)) 172#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec))
170 173
171/* convert an ntp 64-bit fp number to a struct timeval */ 174/* convert an ntp 64-bit fp number to a struct timeval */
172#define NTP64toTV(n, t) \ 175#define NTP64toTV(n, t) \
173 do { \ 176 do { \
174 if (!n) \ 177 if (!n) \
175 t.tv_sec = t.tv_usec = 0; \ 178 t.tv_sec = t.tv_usec = 0; \
176 else { \ 179 else { \
177 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \ 180 t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \
178 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \ 181 t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \
179 } \ 182 } \
180 } while (0) 183 } while (0)
181 184
182/* convert a struct timeval to an ntp 64-bit fp number */ 185/* convert a struct timeval to an ntp 64-bit fp number */
183#define TVtoNTP64(t, n) \ 186#define TVtoNTP64(t, n) \
184 do { \ 187 do { \
185 if (!t.tv_usec && !t.tv_sec) \ 188 if (!t.tv_usec && !t.tv_sec) \
186 n = 0x0UL; \ 189 n = 0x0UL; \
187 else { \ 190 else { \
188 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \ 191 L32(n) = htonl(t.tv_sec + EPOCHDIFF); \
189 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \ 192 R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \
190 } \ 193 } \
191 } while (0) 194 } while (0)
192 195
193/* NTP control message header is 12 bytes, plus any data in the data 196/* NTP control message header is 12 bytes, plus any data in the data
@@ -196,68 +199,64 @@ typedef struct {
196#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((m.count) ? 4 - (ntohs(m.count) % 4) : 0)) 199#define SIZEOF_NTPCM(m) (12 + ntohs(m.count) + ((m.count) ? 4 - (ntohs(m.count) % 4) : 0))
197 200
198/* finally, a little helper or two for debugging: */ 201/* finally, a little helper or two for debugging: */
199#define DBG(x) \ 202#define DBG(x) \
200 do { \ 203 do { \
201 if (verbose > 1) { \ 204 if (verbose > 1) { \
202 x; \ 205 x; \
203 } \ 206 } \
204 } while (0); 207 } while (0);
205#define PRINTSOCKADDR(x) \ 208#define PRINTSOCKADDR(x) \
206 do { \ 209 do { \
207 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \ 210 printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \
208 } while (0); 211 } while (0);
209 212
210/* calculate the offset of the local clock */ 213/* calculate the offset of the local clock */
211static inline double calc_offset(const ntp_message *m, const struct timeval *t) { 214static inline double calc_offset(const ntp_message *message, const struct timeval *time_value) {
212 double client_tx = NTP64asDOUBLE(m->origts); 215 double client_tx = NTP64asDOUBLE(message->origts);
213 double peer_rx = NTP64asDOUBLE(m->rxts); 216 double peer_rx = NTP64asDOUBLE(message->rxts);
214 double peer_tx = NTP64asDOUBLE(m->txts); 217 double peer_tx = NTP64asDOUBLE(message->txts);
215 double client_rx = TVasDOUBLE((*t)); 218 double client_rx = TVasDOUBLE((*time_value));
216 return (.5 * ((peer_tx - client_rx) + (peer_rx - client_tx))); 219 return (((peer_tx - client_rx) + (peer_rx - client_tx)) / 2);
217} 220}
218 221
219/* print out a ntp packet in human readable/debuggable format */ 222/* print out a ntp packet in human readable/debuggable format */
220void print_ntp_message(const ntp_message *p) { 223void print_ntp_message(const ntp_message *message) {
221 struct timeval ref; 224 struct timeval ref;
222 struct timeval orig; 225 struct timeval orig;
223 struct timeval rx;
224 struct timeval tx;
225 226
226 NTP64toTV(p->refts, ref); 227 NTP64toTV(message->refts, ref);
227 NTP64toTV(p->origts, orig); 228 NTP64toTV(message->origts, orig);
228 NTP64toTV(p->rxts, rx);
229 NTP64toTV(p->txts, tx);
230 229
231 printf("packet contents:\n"); 230 printf("packet contents:\n");
232 printf("\tflags: 0x%.2x\n", p->flags); 231 printf("\tflags: 0x%.2x\n", message->flags);
233 printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK); 232 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); 233 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); 234 printf("\t mode=%d (0x%.2x)\n", MODE(message->flags), message->flags & MODE_MASK);
236 printf("\tstratum = %d\n", p->stratum); 235 printf("\tstratum = %d\n", message->stratum);
237 printf("\tpoll = %g\n", pow(2, p->poll)); 236 printf("\tpoll = %g\n", pow(2, message->poll));
238 printf("\tprecision = %g\n", pow(2, p->precision)); 237 printf("\tprecision = %g\n", pow(2, message->precision));
239 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay)); 238 printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(message->rtdelay));
240 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp)); 239 printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(message->rtdisp));
241 printf("\trefid = %x\n", p->refid); 240 printf("\trefid = %x\n", message->refid);
242 printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts)); 241 printf("\trefts = %-.16g\n", NTP64asDOUBLE(message->refts));
243 printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts)); 242 printf("\torigts = %-.16g\n", NTP64asDOUBLE(message->origts));
244 printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts)); 243 printf("\trxts = %-.16g\n", NTP64asDOUBLE(message->rxts));
245 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts)); 244 printf("\ttxts = %-.16g\n", NTP64asDOUBLE(message->txts));
246} 245}
247 246
248void setup_request(ntp_message *p) { 247void setup_request(ntp_message *message) {
249 memset(p, 0, sizeof(ntp_message)); 248 memset(message, 0, sizeof(ntp_message));
250 LI_SET(p->flags, LI_ALARM); 249 LI_SET(message->flags, LI_ALARM);
251 VN_SET(p->flags, 4); 250 VN_SET(message->flags, 4);
252 MODE_SET(p->flags, MODE_CLIENT); 251 MODE_SET(message->flags, MODE_CLIENT);
253 p->poll = 4; 252 message->poll = 4;
254 p->precision = (int8_t)0xfa; 253 message->precision = (int8_t)0xfa;
255 L16(p->rtdelay) = htons(1); 254 L16(message->rtdelay) = htons(1);
256 L16(p->rtdisp) = htons(1); 255 L16(message->rtdisp) = htons(1);
257 256
258 struct timeval t; 257 struct timeval t;
259 gettimeofday(&t, NULL); 258 gettimeofday(&t, NULL);
260 TVtoNTP64(t, p->txts); 259 TVtoNTP64(t, message->txts);
261} 260}
262 261
263/* select the "best" server from a list of servers, and return its index. 262/* select the "best" server from a list of servers, and return its index.
@@ -273,14 +272,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 272 * stratum 0 is for reference clocks so no NTP server should ever report
274 * a stratum 0 */ 273 * a stratum 0 */
275 if (slist[cserver].stratum == 0) { 274 if (slist[cserver].stratum == 0) {
276 if (verbose) 275 if (verbose) {
277 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum); 276 printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
277 }
278 continue; 278 continue;
279 } 279 }
280 /* Sort out servers with error flags */ 280 /* Sort out servers with error flags */
281 if (LI(slist[cserver].flags) == LI_ALARM) { 281 if (LI(slist[cserver].flags) == LI_ALARM) {
282 if (verbose) 282 if (verbose) {
283 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags)); 283 printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
284 }
284 continue; 285 continue;
285 } 286 }
286 287
@@ -322,7 +323,7 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
322 * we don't waste time sitting around waiting for single packets. 323 * we don't waste time sitting around waiting for single packets.
323 * - we also "manually" handle resolving host names and connecting, because 324 * - 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 :( */ 325 * we have to do it in a way that our lazy macros don't handle currently :( */
325double offset_request(const char *host, int *status) { 326double 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 */ 327 /* setup hints to only return results from getaddrinfo that we'd like */
327 struct addrinfo hints; 328 struct addrinfo hints;
328 memset(&hints, 0, sizeof(struct addrinfo)); 329 memset(&hints, 0, sizeof(struct addrinfo));
@@ -331,39 +332,44 @@ double offset_request(const char *host, int *status) {
331 hints.ai_socktype = SOCK_DGRAM; 332 hints.ai_socktype = SOCK_DGRAM;
332 333
333 /* fill in ai with the list of hosts resolved by the host name */ 334 /* fill in ai with the list of hosts resolved by the host name */
334 struct addrinfo *ai = NULL; 335 struct addrinfo *addresses = NULL;
335 int ga_result = getaddrinfo(host, port, &hints, &ai); 336 int ga_result = getaddrinfo(host, port, &hints, &addresses);
336 if (ga_result != 0) { 337 if (ga_result != 0) {
337 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); 338 die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result));
338 } 339 }
339 340
340 /* count the number of returned hosts, and allocate stuff accordingly */ 341 /* count the number of returned hosts, and allocate stuff accordingly */
341 int num_hosts = 0; 342 size_t num_hosts = 0;
342 for (struct addrinfo *ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { 343 for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) {
343 num_hosts++; 344 num_hosts++;
344 } 345 }
345 346
346 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); 347 ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts);
347 348
348 if (req == NULL) 349 if (req == NULL) {
349 die(STATE_UNKNOWN, "can not allocate ntp message array"); 350 die(STATE_UNKNOWN, "can not allocate ntp message array");
351 }
350 int *socklist = (int *)malloc(sizeof(int) * num_hosts); 352 int *socklist = (int *)malloc(sizeof(int) * num_hosts);
351 353
352 if (socklist == NULL) 354 if (socklist == NULL) {
353 die(STATE_UNKNOWN, "can not allocate socket array"); 355 die(STATE_UNKNOWN, "can not allocate socket array");
356 }
354 357
355 struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts); 358 struct pollfd *ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts);
356 if (ufds == NULL) 359 if (ufds == NULL) {
357 die(STATE_UNKNOWN, "can not allocate socket array"); 360 die(STATE_UNKNOWN, "can not allocate socket array");
361 }
358 362
359 ntp_server_results *servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts); 363 ntp_server_results *servers =
360 if (servers == NULL) 364 (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts);
365 if (servers == NULL) {
361 die(STATE_UNKNOWN, "can not allocate server array"); 366 die(STATE_UNKNOWN, "can not allocate server array");
367 }
362 memset(servers, 0, sizeof(ntp_server_results) * num_hosts); 368 memset(servers, 0, sizeof(ntp_server_results) * num_hosts);
363 DBG(printf("Found %d peers to check\n", num_hosts)); 369 DBG(printf("Found %zu peers to check\n", num_hosts));
364 370
365 /* setup each socket for writing, and the corresponding struct pollfd */ 371 /* setup each socket for writing, and the corresponding struct pollfd */
366 struct addrinfo *ai_tmp = ai; 372 struct addrinfo *ai_tmp = addresses;
367 for (int i = 0; ai_tmp; i++) { 373 for (int i = 0; ai_tmp; i++) {
368 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); 374 socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
369 if (socklist[i] == -1) { 375 if (socklist[i] == -1) {
@@ -389,7 +395,7 @@ double offset_request(const char *host, int *status) {
389 time_t start_ts = 0; 395 time_t start_ts = 0;
390 time_t now_time = 0; 396 time_t now_time = 0;
391 now_time = start_ts = time(NULL); 397 now_time = start_ts = time(NULL);
392 int servers_completed = 0; 398 size_t servers_completed = 0;
393 bool one_read = false; 399 bool one_read = false;
394 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) { 400 while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) {
395 /* loop through each server and find each one which hasn't 401 /* loop through each server and find each one which hasn't
@@ -398,12 +404,14 @@ double offset_request(const char *host, int *status) {
398 * and update the "waiting" timestamp with the current time. */ 404 * and update the "waiting" timestamp with the current time. */
399 now_time = time(NULL); 405 now_time = time(NULL);
400 406
401 for (int i = 0; i < num_hosts; i++) { 407 for (size_t i = 0; i < num_hosts; i++) {
402 if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) { 408 if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) {
403 if (verbose && servers[i].waiting != 0) 409 if (verbose && servers[i].waiting != 0) {
404 printf("re-"); 410 printf("re-");
405 if (verbose) 411 }
406 printf("sending request to peer %d\n", i); 412 if (verbose) {
413 printf("sending request to peer %zu\n", i);
414 }
407 setup_request(&req[i]); 415 setup_request(&req[i]);
408 write(socklist[i], &req[i], sizeof(ntp_message)); 416 write(socklist[i], &req[i], sizeof(ntp_message));
409 servers[i].waiting = now_time; 417 servers[i].waiting = now_time;
@@ -419,10 +427,10 @@ double offset_request(const char *host, int *status) {
419 } 427 }
420 428
421 /* read from any sockets with pending data */ 429 /* read from any sockets with pending data */
422 for (int i = 0; servers_readable && i < num_hosts; i++) { 430 for (size_t i = 0; servers_readable && i < num_hosts; i++) {
423 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) { 431 if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) {
424 if (verbose) { 432 if (verbose) {
425 printf("response from peer %d: ", i); 433 printf("response from peer %zu: ", i);
426 } 434 }
427 435
428 read(ufds[i].fd, &req[i], sizeof(ntp_message)); 436 read(ufds[i].fd, &req[i], sizeof(ntp_message));
@@ -442,14 +450,15 @@ double offset_request(const char *host, int *status) {
442 servers[i].flags = req[i].flags; 450 servers[i].flags = req[i].flags;
443 servers_readable--; 451 servers_readable--;
444 one_read = true; 452 one_read = true;
445 if (servers[i].num_responses == AVG_NUM) 453 if (servers[i].num_responses == AVG_NUM) {
446 servers_completed++; 454 servers_completed++;
455 }
447 } 456 }
448 } 457 }
449 /* lather, rinse, repeat. */ 458 /* lather, rinse, repeat. */
450 } 459 }
451 460
452 if (one_read == false) { 461 if (!one_read) {
453 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); 462 die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
454 } 463 }
455 464
@@ -467,21 +476,22 @@ double offset_request(const char *host, int *status) {
467 } 476 }
468 477
469 /* cleanup */ 478 /* cleanup */
470 for (int j = 0; j < num_hosts; j++) { 479 for (size_t j = 0; j < num_hosts; j++) {
471 close(socklist[j]); 480 close(socklist[j]);
472 } 481 }
473 free(socklist); 482 free(socklist);
474 free(ufds); 483 free(ufds);
475 free(servers); 484 free(servers);
476 free(req); 485 free(req);
477 freeaddrinfo(ai); 486 freeaddrinfo(addresses);
478 487
479 if (verbose) 488 if (verbose) {
480 printf("overall average offset: %.10g\n", avg_offset); 489 printf("overall average offset: %.10g\n", avg_offset);
490 }
481 return avg_offset; 491 return avg_offset;
482} 492}
483 493
484int process_arguments(int argc, char **argv) { 494check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
485 static struct option longopts[] = {{"version", no_argument, 0, 'V'}, 495 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
486 {"help", no_argument, 0, 'h'}, 496 {"help", no_argument, 0, 'h'},
487 {"verbose", no_argument, 0, 'v'}, 497 {"verbose", no_argument, 0, 'v'},
@@ -496,14 +506,24 @@ int process_arguments(int argc, char **argv) {
496 {"port", required_argument, 0, 'p'}, 506 {"port", required_argument, 0, 'p'},
497 {0, 0, 0, 0}}; 507 {0, 0, 0, 0}};
498 508
499 if (argc < 2) 509 if (argc < 2) {
500 usage("\n"); 510 usage("\n");
511 }
512
513 check_ntp_time_config_wrapper result = {
514 .errorcode = OK,
515 .config = check_ntp_time_config_init(),
516 };
517
518 char *owarn = "60";
519 char *ocrit = "120";
501 520
502 while (true) { 521 while (true) {
503 int option = 0; 522 int option = 0;
504 int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option); 523 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) 524 if (option_char == -1 || option_char == EOF || option_char == 1) {
506 break; 525 break;
526 }
507 527
508 switch (option_char) { 528 switch (option_char) {
509 case 'h': 529 case 'h':
@@ -518,7 +538,7 @@ int process_arguments(int argc, char **argv) {
518 verbose++; 538 verbose++;
519 break; 539 break;
520 case 'q': 540 case 'q':
521 quiet = true; 541 result.config.quiet = true;
522 break; 542 break;
523 case 'w': 543 case 'w':
524 owarn = optarg; 544 owarn = optarg;
@@ -527,18 +547,19 @@ int process_arguments(int argc, char **argv) {
527 ocrit = optarg; 547 ocrit = optarg;
528 break; 548 break;
529 case 'H': 549 case 'H':
530 if (!is_host(optarg)) 550 if (!is_host(optarg)) {
531 usage2(_("Invalid hostname/address"), optarg); 551 usage2(_("Invalid hostname/address"), optarg);
532 server_address = strdup(optarg); 552 }
553 result.config.server_address = strdup(optarg);
533 break; 554 break;
534 case 'p': 555 case 'p':
535 port = strdup(optarg); 556 result.config.port = strdup(optarg);
536 break; 557 break;
537 case 't': 558 case 't':
538 socket_timeout = atoi(optarg); 559 socket_timeout = atoi(optarg);
539 break; 560 break;
540 case 'o': 561 case 'o':
541 time_offset = atoi(optarg); 562 result.config.time_offset = atoi(optarg);
542 break; 563 break;
543 case '4': 564 case '4':
544 address_family = AF_INET; 565 address_family = AF_INET;
@@ -557,16 +578,18 @@ int process_arguments(int argc, char **argv) {
557 } 578 }
558 } 579 }
559 580
560 if (server_address == NULL) { 581 if (result.config.server_address == NULL) {
561 usage4(_("Hostname was not supplied")); 582 usage4(_("Hostname was not supplied"));
562 } 583 }
563 584
564 return 0; 585 set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
586
587 return result;
565} 588}
566 589
567char *perfd_offset(double offset) { 590char *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, 591 return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true,
569 0); 592 offset_thresholds->critical->end, false, 0, false, 0);
570} 593}
571 594
572int main(int argc, char *argv[]) { 595int main(int argc, char *argv[]) {
@@ -577,10 +600,13 @@ int main(int argc, char *argv[]) {
577 /* Parse extra opts if any */ 600 /* Parse extra opts if any */
578 argv = np_extra_opts(&argc, argv, progname); 601 argv = np_extra_opts(&argc, argv, progname);
579 602
580 if (process_arguments(argc, argv) == ERROR) 603 check_ntp_time_config_wrapper tmp_config = process_arguments(argc, argv);
604
605 if (tmp_config.errorcode == ERROR) {
581 usage4(_("Could not parse arguments")); 606 usage4(_("Could not parse arguments"));
607 }
582 608
583 set_thresholds(&offset_thresholds, owarn, ocrit); 609 const check_ntp_time_config config = tmp_config.config;
584 610
585 /* initialize alarm signal handling */ 611 /* initialize alarm signal handling */
586 signal(SIGALRM, socket_timeout_alarm_handler); 612 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -588,13 +614,14 @@ int main(int argc, char *argv[]) {
588 /* set socket timeout */ 614 /* set socket timeout */
589 alarm(socket_timeout); 615 alarm(socket_timeout);
590 616
591 int offset_result = STATE_OK; 617 mp_state_enum offset_result = STATE_OK;
592 int result = STATE_OK; 618 mp_state_enum result = STATE_OK;
593 double offset = offset_request(server_address, &offset_result); 619 double offset =
620 offset_request(config.server_address, config.port, &offset_result, config.time_offset);
594 if (offset_result == STATE_UNKNOWN) { 621 if (offset_result == STATE_UNKNOWN) {
595 result = ((!quiet) ? STATE_UNKNOWN : STATE_CRITICAL); 622 result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
596 } else { 623 } else {
597 result = get_status(fabs(offset), offset_thresholds); 624 result = get_status(fabs(offset), config.offset_thresholds);
598 } 625 }
599 626
600 char *result_line; 627 char *result_line;
@@ -619,13 +646,14 @@ int main(int argc, char *argv[]) {
619 xasprintf(&perfdata_line, ""); 646 xasprintf(&perfdata_line, "");
620 } else { 647 } else {
621 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); 648 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
622 xasprintf(&perfdata_line, "%s", perfd_offset(offset)); 649 xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
623 } 650 }
624 printf("%s|%s\n", result_line, perfdata_line); 651 printf("%s|%s\n", result_line, perfdata_line);
625 652
626 if (server_address != NULL) 653 if (config.server_address != NULL) {
627 free(server_address); 654 free(config.server_address);
628 return result; 655 }
656 exit(result);
629} 657}
630 658
631void print_help(void) { 659void print_help(void) {
@@ -677,5 +705,6 @@ void print_help(void) {
677 705
678void print_usage(void) { 706void print_usage(void) {
679 printf("%s\n", _("Usage:")); 707 printf("%s\n", _("Usage:"));
680 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n", progname); 708 printf(" %s -H <host> [-4|-6] [-w <warn>] [-c <crit>] [-v verbose] [-o <time offset>]\n",
709 progname);
681} 710}