Back to index

nagios-plugins  1.4.16
check_ntp_time.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 * 
00003 * Nagios check_ntp_time plugin
00004 * 
00005 * License: GPL
00006 * Copyright (c) 2006 Sean Finney <seanius@seanius.net>
00007 * Copyright (c) 2006-2008 Nagios Plugins Development Team
00008 * 
00009 * Description:
00010 * 
00011 * This file contains the check_ntp_time plugin
00012 * 
00013 * This plugin checks the clock offset between the local host and a
00014 * remote NTP server. It is independent of any commandline programs or
00015 * external libraries.
00016 * 
00017 * If you'd rather want to monitor an NTP server, please use
00018 * check_ntp_peer.
00019 * 
00020 * 
00021 * This program is free software: you can redistribute it and/or modify
00022 * it under the terms of the GNU General Public License as published by
00023 * the Free Software Foundation, either version 3 of the License, or
00024 * (at your option) any later version.
00025 * 
00026 * This program is distributed in the hope that it will be useful,
00027 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00029 * GNU General Public License for more details.
00030 * 
00031 * You should have received a copy of the GNU General Public License
00032 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00033 * 
00034 * 
00035 *****************************************************************************/
00036 
00037 const char *progname = "check_ntp_time";
00038 const char *copyright = "2006-2008";
00039 const char *email = "nagiosplug-devel@lists.sourceforge.net";
00040 
00041 #include "common.h"
00042 #include "netutils.h"
00043 #include "utils.h"
00044 
00045 static char *server_address=NULL;
00046 static char *port="123";
00047 static int verbose=0;
00048 static int quiet=0;
00049 static char *owarn="60";
00050 static char *ocrit="120";
00051 
00052 int process_arguments (int, char **);
00053 thresholds *offset_thresholds = NULL;
00054 void print_help (void);
00055 void print_usage (void);
00056 
00057 /* number of times to perform each request to get a good average. */
00058 #define AVG_NUM 4
00059 
00060 /* max size of control message data */
00061 #define MAX_CM_SIZE 468
00062 
00063 /* this structure holds everything in an ntp request/response as per rfc1305 */
00064 typedef struct {
00065        uint8_t flags;       /* byte with leapindicator,vers,mode. see macros */
00066        uint8_t stratum;     /* clock stratum */
00067        int8_t poll;         /* polling interval */
00068        int8_t precision;    /* precision of the local clock */
00069        int32_t rtdelay;     /* total rt delay, as a fixed point num. see macros */
00070        uint32_t rtdisp;     /* like above, but for max err to primary src */
00071        uint32_t refid;      /* ref clock identifier */
00072        uint64_t refts;      /* reference timestamp.  local time local clock */
00073        uint64_t origts;     /* time at which request departed client */
00074        uint64_t rxts;       /* time at which request arrived at server */
00075        uint64_t txts;       /* time at which request departed server */
00076 } ntp_message;
00077 
00078 /* this structure holds data about results from querying offset from a peer */
00079 typedef struct {
00080        time_t waiting;         /* ts set when we started waiting for a response */
00081        int num_responses;      /* number of successfully recieved responses */
00082        uint8_t stratum;        /* copied verbatim from the ntp_message */
00083        double rtdelay;         /* converted from the ntp_message */
00084        double rtdisp;          /* converted from the ntp_message */
00085        double offset[AVG_NUM]; /* offsets from each response */
00086        uint8_t flags;       /* byte with leapindicator,vers,mode. see macros */
00087 } ntp_server_results;
00088 
00089 /* bits 1,2 are the leap indicator */
00090 #define LI_MASK 0xc0
00091 #define LI(x) ((x&LI_MASK)>>6)
00092 #define LI_SET(x,y) do{ x |= ((y<<6)&LI_MASK); }while(0)
00093 /* and these are the values of the leap indicator */
00094 #define LI_NOWARNING 0x00
00095 #define LI_EXTRASEC 0x01
00096 #define LI_MISSINGSEC 0x02
00097 #define LI_ALARM 0x03
00098 /* bits 3,4,5 are the ntp version */
00099 #define VN_MASK 0x38
00100 #define VN(x) ((x&VN_MASK)>>3)
00101 #define VN_SET(x,y)  do{ x |= ((y<<3)&VN_MASK); }while(0)
00102 #define VN_RESERVED 0x02
00103 /* bits 6,7,8 are the ntp mode */
00104 #define MODE_MASK 0x07
00105 #define MODE(x) (x&MODE_MASK)
00106 #define MODE_SET(x,y)       do{ x |= (y&MODE_MASK); }while(0)
00107 /* here are some values */
00108 #define MODE_CLIENT 0x03
00109 #define MODE_CONTROLMSG 0x06
00110 /* In control message, bits 8-10 are R,E,M bits */
00111 #define REM_MASK 0xe0
00112 #define REM_RESP 0x80
00113 #define REM_ERROR 0x40
00114 #define REM_MORE 0x20
00115 /* In control message, bits 11 - 15 are opcode */
00116 #define OP_MASK 0x1f
00117 #define OP_SET(x,y)   do{ x |= (y&OP_MASK); }while(0)
00118 #define OP_READSTAT 0x01
00119 #define OP_READVAR  0x02
00120 /* In peer status bytes, bits 6,7,8 determine clock selection status */
00121 #define PEER_SEL(x) ((ntohs(x)>>8)&0x07)
00122 #define PEER_INCLUDED 0x04
00123 #define PEER_SYNCSOURCE 0x06
00124 
00134 /* macros to access the left/right 16 bits of a 32-bit ntp "fixed point"
00135    number.  note that these can be used as lvalues too */
00136 #define L16(x) (((uint16_t*)&x)[0])
00137 #define R16(x) (((uint16_t*)&x)[1])
00138 /* macros to access the left/right 32 bits of a 64-bit ntp "fixed point"
00139    number.  these too can be used as lvalues */
00140 #define L32(x) (((uint32_t*)&x)[0])
00141 #define R32(x) (((uint32_t*)&x)[1])
00142 
00143 /* ntp wants seconds since 1/1/00, epoch is 1/1/70.  this is the difference */
00144 #define EPOCHDIFF 0x83aa7e80UL
00145 
00146 /* extract a 32-bit ntp fixed point number into a double */
00147 #define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x))/65536.0)
00148 
00149 /* likewise for a 64-bit ntp fp number */
00150 #define NTP64asDOUBLE(n) (double)(((uint64_t)n)?\
00151                          (ntohl(L32(n))-EPOCHDIFF) + \
00152                          (.00000001*(0.5+(double)(ntohl(R32(n))/42.94967296))):\
00153                          0)
00154 
00155 /* convert a struct timeval to a double */
00156 #define TVasDOUBLE(x) (double)(x.tv_sec+(0.000001*x.tv_usec))
00157 
00158 /* convert an ntp 64-bit fp number to a struct timeval */
00159 #define NTP64toTV(n,t) \
00160        do{ if(!n) t.tv_sec = t.tv_usec = 0; \
00161            else { \
00162                      t.tv_sec=ntohl(L32(n))-EPOCHDIFF; \
00163                      t.tv_usec=(int)(0.5+(double)(ntohl(R32(n))/4294.967296)); \
00164               } \
00165        }while(0)
00166 
00167 /* convert a struct timeval to an ntp 64-bit fp number */
00168 #define TVtoNTP64(t,n) \
00169        do{ if(!t.tv_usec && !t.tv_sec) n=0x0UL; \
00170               else { \
00171                      L32(n)=htonl(t.tv_sec + EPOCHDIFF); \
00172                      R32(n)=htonl((uint64_t)((4294.967296*t.tv_usec)+.5)); \
00173               } \
00174        } while(0)
00175 
00176 /* NTP control message header is 12 bytes, plus any data in the data
00177  * field, plus null padding to the nearest 32-bit boundary per rfc.
00178  */
00179 #define SIZEOF_NTPCM(m) (12+ntohs(m.count)+((m.count)?4-(ntohs(m.count)%4):0))
00180 
00181 /* finally, a little helper or two for debugging: */
00182 #define DBG(x) do{if(verbose>1){ x; }}while(0);
00183 #define PRINTSOCKADDR(x) \
00184        do{ \
00185               printf("%u.%u.%u.%u", (x>>24)&0xff, (x>>16)&0xff, (x>>8)&0xff, x&0xff);\
00186        }while(0);
00187 
00188 /* calculate the offset of the local clock */
00189 static inline double calc_offset(const ntp_message *m, const struct timeval *t){
00190        double client_tx, peer_rx, peer_tx, client_rx;
00191        client_tx = NTP64asDOUBLE(m->origts);
00192        peer_rx = NTP64asDOUBLE(m->rxts);
00193        peer_tx = NTP64asDOUBLE(m->txts);
00194        client_rx=TVasDOUBLE((*t));
00195        return (.5*((peer_tx-client_rx)+(peer_rx-client_tx)));
00196 }
00197 
00198 /* print out a ntp packet in human readable/debuggable format */
00199 void print_ntp_message(const ntp_message *p){
00200        struct timeval ref, orig, rx, tx;
00201 
00202        NTP64toTV(p->refts,ref);
00203        NTP64toTV(p->origts,orig);
00204        NTP64toTV(p->rxts,rx);
00205        NTP64toTV(p->txts,tx);
00206 
00207        printf("packet contents:\n");
00208        printf("\tflags: 0x%.2x\n", p->flags);
00209        printf("\t  li=%d (0x%.2x)\n", LI(p->flags), p->flags&LI_MASK);
00210        printf("\t  vn=%d (0x%.2x)\n", VN(p->flags), p->flags&VN_MASK);
00211        printf("\t  mode=%d (0x%.2x)\n", MODE(p->flags), p->flags&MODE_MASK);
00212        printf("\tstratum = %d\n", p->stratum);
00213        printf("\tpoll = %g\n", pow(2, p->poll));
00214        printf("\tprecision = %g\n", pow(2, p->precision));
00215        printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay));
00216        printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp));
00217        printf("\trefid = %x\n", p->refid);
00218        printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts));
00219        printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts));
00220        printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts));
00221        printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts));
00222 }
00223 
00224 void setup_request(ntp_message *p){
00225        struct timeval t;
00226 
00227        memset(p, 0, sizeof(ntp_message));
00228        LI_SET(p->flags, LI_ALARM);
00229        VN_SET(p->flags, 4);
00230        MODE_SET(p->flags, MODE_CLIENT);
00231        p->poll=4;
00232        p->precision=(int8_t)0xfa;
00233        L16(p->rtdelay)=htons(1);
00234        L16(p->rtdisp)=htons(1);
00235 
00236        gettimeofday(&t, NULL);
00237        TVtoNTP64(t,p->txts);
00238 }
00239 
00240 /* select the "best" server from a list of servers, and return its index.
00241  * this is done by filtering servers based on stratum, dispersion, and
00242  * finally round-trip delay. */
00243 int best_offset_server(const ntp_server_results *slist, int nservers){
00244        int i=0, cserver=0, best_server=-1;
00245 
00246        /* for each server */
00247        for(cserver=0; cserver<nservers; cserver++){
00248               /* We don't want any servers that fails these tests */
00249               /* Sort out servers that didn't respond or responede with a 0 stratum;
00250                * stratum 0 is for reference clocks so no NTP server should ever report
00251                * a stratum 0 */
00252               if ( slist[cserver].stratum == 0){
00253                      if (verbose) printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum);
00254                      continue;
00255               }
00256               /* Sort out servers with error flags */
00257               if ( LI(slist[cserver].flags) == LI_ALARM ){
00258                      if (verbose) printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags));
00259                      continue;
00260               }
00261 
00262               /* If we don't have a server yet, use the first one */
00263               if (best_server == -1) {
00264                      best_server = cserver;
00265                      DBG(printf("using peer %d as our first candidate\n", best_server));
00266                      continue;
00267               }
00268 
00269               /* compare the server to the best one we've seen so far */
00270               /* does it have an equal or better stratum? */
00271               DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
00272               if(slist[cserver].stratum <= slist[best_server].stratum){
00273                      DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
00274                      /* does it have an equal or better dispersion? */
00275                      if(slist[cserver].rtdisp <= slist[best_server].rtdisp){
00276                             DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
00277                             /* does it have a better rtdelay? */
00278                             if(slist[cserver].rtdelay < slist[best_server].rtdelay){
00279                                    DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
00280                                    best_server = cserver;
00281                                    DBG(printf("peer %d is now our best candidate\n", best_server));
00282                             }
00283                      }
00284               }
00285        }
00286 
00287        if(best_server >= 0) {
00288               DBG(printf("best server selected: peer %d\n", best_server));
00289               return best_server;
00290        } else {
00291               DBG(printf("no peers meeting synchronization criteria :(\n"));
00292               return -1;
00293        }
00294 }
00295 
00296 /* do everything we need to get the total average offset
00297  * - we use a certain amount of parallelization with poll() to ensure
00298  *   we don't waste time sitting around waiting for single packets.
00299  * - we also "manually" handle resolving host names and connecting, because
00300  *   we have to do it in a way that our lazy macros don't handle currently :( */
00301 double offset_request(const char *host, int *status){
00302        int i=0, j=0, ga_result=0, num_hosts=0, *socklist=NULL, respnum=0;
00303        int servers_completed=0, one_written=0, one_read=0, servers_readable=0, best_index=-1;
00304        time_t now_time=0, start_ts=0;
00305        ntp_message *req=NULL;
00306        double avg_offset=0.;
00307        struct timeval recv_time;
00308        struct addrinfo *ai=NULL, *ai_tmp=NULL, hints;
00309        struct pollfd *ufds=NULL;
00310        ntp_server_results *servers=NULL;
00311 
00312        /* setup hints to only return results from getaddrinfo that we'd like */
00313        memset(&hints, 0, sizeof(struct addrinfo));
00314        hints.ai_family = address_family;
00315        hints.ai_protocol = IPPROTO_UDP;
00316        hints.ai_socktype = SOCK_DGRAM;
00317 
00318        /* fill in ai with the list of hosts resolved by the host name */
00319        ga_result = getaddrinfo(host, port, &hints, &ai);
00320        if(ga_result!=0){
00321               die(STATE_UNKNOWN, "error getting address for %s: %s\n",
00322                   host, gai_strerror(ga_result));
00323        }
00324 
00325        /* count the number of returned hosts, and allocate stuff accordingly */
00326        for(ai_tmp=ai; ai_tmp!=NULL; ai_tmp=ai_tmp->ai_next){ num_hosts++; }
00327        req=(ntp_message*)malloc(sizeof(ntp_message)*num_hosts);
00328        if(req==NULL) die(STATE_UNKNOWN, "can not allocate ntp message array");
00329        socklist=(int*)malloc(sizeof(int)*num_hosts);
00330        if(socklist==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
00331        ufds=(struct pollfd*)malloc(sizeof(struct pollfd)*num_hosts);
00332        if(ufds==NULL) die(STATE_UNKNOWN, "can not allocate socket array");
00333        servers=(ntp_server_results*)malloc(sizeof(ntp_server_results)*num_hosts);
00334        if(servers==NULL) die(STATE_UNKNOWN, "can not allocate server array");
00335        memset(servers, 0, sizeof(ntp_server_results)*num_hosts);
00336        DBG(printf("Found %d peers to check\n", num_hosts));
00337 
00338        /* setup each socket for writing, and the corresponding struct pollfd */
00339        ai_tmp=ai;
00340        for(i=0;ai_tmp;i++){
00341               socklist[i]=socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP);
00342               if(socklist[i] == -1) {
00343                      perror(NULL);
00344                      die(STATE_UNKNOWN, "can not create new socket");
00345               }
00346               if(connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)){
00347                      die(STATE_UNKNOWN, "can't create socket connection");
00348               } else {
00349                      ufds[i].fd=socklist[i];
00350                      ufds[i].events=POLLIN;
00351                      ufds[i].revents=0;
00352               }
00353               ai_tmp = ai_tmp->ai_next;
00354        }
00355 
00356        /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds
00357         * have passed in order to ensure post-processing and jitter time. */
00358        now_time=start_ts=time(NULL);
00359        while(servers_completed<num_hosts && now_time-start_ts <= socket_timeout/2){
00360               /* loop through each server and find each one which hasn't
00361                * been touched in the past second or so and is still lacking
00362                * some responses. For each of these servers, send a new request,
00363                * and update the "waiting" timestamp with the current time. */
00364               one_written=0;
00365               now_time=time(NULL);
00366 
00367               for(i=0; i<num_hosts; i++){
00368                      if(servers[i].waiting<now_time && servers[i].num_responses<AVG_NUM){
00369                             if(verbose && servers[i].waiting != 0) printf("re-");
00370                             if(verbose) printf("sending request to peer %d\n", i);
00371                             setup_request(&req[i]);
00372                             write(socklist[i], &req[i], sizeof(ntp_message));
00373                             servers[i].waiting=now_time;
00374                             one_written=1;
00375                             break;
00376                      }
00377               }
00378 
00379               /* quickly poll for any sockets with pending data */
00380               servers_readable=poll(ufds, num_hosts, 100);
00381               if(servers_readable==-1){
00382                      perror("polling ntp sockets");
00383                      die(STATE_UNKNOWN, "communication errors");
00384               }
00385 
00386               /* read from any sockets with pending data */
00387               for(i=0; servers_readable && i<num_hosts; i++){
00388                      if(ufds[i].revents&POLLIN && servers[i].num_responses < AVG_NUM){
00389                             if(verbose) {
00390                                    printf("response from peer %d: ", i);
00391                             }
00392 
00393                             read(ufds[i].fd, &req[i], sizeof(ntp_message));
00394                             gettimeofday(&recv_time, NULL);
00395                             DBG(print_ntp_message(&req[i]));
00396                             respnum=servers[i].num_responses++;
00397                             servers[i].offset[respnum]=calc_offset(&req[i], &recv_time);
00398                             if(verbose) {
00399                                    printf("offset %.10g\n", servers[i].offset[respnum]);
00400                             }
00401                             servers[i].stratum=req[i].stratum;
00402                             servers[i].rtdisp=NTP32asDOUBLE(req[i].rtdisp);
00403                             servers[i].rtdelay=NTP32asDOUBLE(req[i].rtdelay);
00404                             servers[i].waiting=0;
00405                             servers[i].flags=req[i].flags;
00406                             servers_readable--;
00407                             one_read = 1;
00408                             if(servers[i].num_responses==AVG_NUM) servers_completed++;
00409                      }
00410               }
00411               /* lather, rinse, repeat. */
00412        }
00413 
00414        if (one_read == 0) {
00415               die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
00416        }
00417 
00418        /* now, pick the best server from the list */
00419        best_index=best_offset_server(servers, num_hosts);
00420        if(best_index < 0){
00421               *status=STATE_UNKNOWN;
00422        } else {
00423               /* finally, calculate the average offset */
00424               for(i=0; i<servers[best_index].num_responses;i++){
00425                      avg_offset+=servers[best_index].offset[j];
00426               }
00427               avg_offset/=servers[best_index].num_responses;
00428        }
00429 
00430        /* cleanup */
00431        for(j=0; j<num_hosts; j++){ close(socklist[j]); }
00432        free(socklist);
00433        free(ufds);
00434        free(servers);
00435        free(req);
00436        freeaddrinfo(ai);
00437 
00438        if(verbose) printf("overall average offset: %.10g\n", avg_offset);
00439        return avg_offset;
00440 }
00441 
00442 int process_arguments(int argc, char **argv){
00443        int c;
00444        int option=0;
00445        static struct option longopts[] = {
00446               {"version", no_argument, 0, 'V'},
00447               {"help", no_argument, 0, 'h'},
00448               {"verbose", no_argument, 0, 'v'},
00449               {"use-ipv4", no_argument, 0, '4'},
00450               {"use-ipv6", no_argument, 0, '6'},
00451               {"quiet", no_argument, 0, 'q'},
00452               {"warning", required_argument, 0, 'w'},
00453               {"critical", required_argument, 0, 'c'},
00454               {"timeout", required_argument, 0, 't'},
00455               {"hostname", required_argument, 0, 'H'},
00456               {"port", required_argument, 0, 'p'},
00457               {0, 0, 0, 0}
00458        };
00459 
00460 
00461        if (argc < 2)
00462               usage ("\n");
00463 
00464        while (1) {
00465               c = getopt_long (argc, argv, "Vhv46qw:c:t:H:p:", longopts, &option);
00466               if (c == -1 || c == EOF || c == 1)
00467                      break;
00468 
00469               switch (c) {
00470               case 'h':
00471                      print_help();
00472                      exit(STATE_OK);
00473                      break;
00474               case 'V':
00475                      print_revision(progname, NP_VERSION);
00476                      exit(STATE_OK);
00477                      break;
00478               case 'v':
00479                      verbose++;
00480                      break;
00481               case 'q':
00482                      quiet = 1;
00483                      break;
00484               case 'w':
00485                      owarn = optarg;
00486                      break;
00487               case 'c':
00488                      ocrit = optarg;
00489                      break;
00490               case 'H':
00491                      if(is_host(optarg) == FALSE)
00492                             usage2(_("Invalid hostname/address"), optarg);
00493                      server_address = strdup(optarg);
00494                      break;
00495               case 'p':
00496                      port = strdup(optarg);
00497                      break;
00498               case 't':
00499                      socket_timeout=atoi(optarg);
00500                      break;
00501               case '4':
00502                      address_family = AF_INET;
00503                      break;
00504               case '6':
00505 #ifdef USE_IPV6
00506                      address_family = AF_INET6;
00507 #else
00508                      usage4 (_("IPv6 support not available"));
00509 #endif
00510                      break;
00511               case '?':
00512                      /* print short usage statement if args not parsable */
00513                      usage5 ();
00514                      break;
00515               }
00516        }
00517 
00518        if(server_address == NULL){
00519               usage4(_("Hostname was not supplied"));
00520        }
00521 
00522        return 0;
00523 }
00524 
00525 char *perfd_offset (double offset)
00526 {
00527        return fperfdata ("offset", offset, "s",
00528               TRUE, offset_thresholds->warning->end,
00529               TRUE, offset_thresholds->critical->end,
00530               FALSE, 0, FALSE, 0);
00531 }
00532 
00533 int main(int argc, char *argv[]){
00534        int result, offset_result;
00535        double offset=0;
00536        char *result_line, *perfdata_line;
00537 
00538        setlocale (LC_ALL, "");
00539        bindtextdomain (PACKAGE, LOCALEDIR);
00540        textdomain (PACKAGE);
00541 
00542        result = offset_result = STATE_OK;
00543 
00544        /* Parse extra opts if any */
00545        argv=np_extra_opts (&argc, argv, progname);
00546 
00547        if (process_arguments (argc, argv) == ERROR)
00548               usage4 (_("Could not parse arguments"));
00549 
00550        set_thresholds(&offset_thresholds, owarn, ocrit);
00551 
00552        /* initialize alarm signal handling */
00553        signal (SIGALRM, socket_timeout_alarm_handler);
00554 
00555        /* set socket timeout */
00556        alarm (socket_timeout);
00557 
00558        offset = offset_request(server_address, &offset_result);
00559        if (offset_result == STATE_UNKNOWN) {
00560               result = (quiet == 1 ? STATE_UNKNOWN : STATE_CRITICAL);
00561        } else {
00562               result = get_status(fabs(offset), offset_thresholds);
00563        }
00564 
00565        switch (result) {
00566               case STATE_CRITICAL :
00567                      asprintf(&result_line, _("NTP CRITICAL:"));
00568                      break;
00569               case STATE_WARNING :
00570                      asprintf(&result_line, _("NTP WARNING:"));
00571                      break;
00572               case STATE_OK :
00573                      asprintf(&result_line, _("NTP OK:"));
00574                      break;
00575               default :
00576                      asprintf(&result_line, _("NTP UNKNOWN:"));
00577                      break;
00578        }
00579        if(offset_result == STATE_UNKNOWN){
00580               asprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
00581               asprintf(&perfdata_line, "");
00582        } else {
00583               asprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
00584               asprintf(&perfdata_line, "%s", perfd_offset(offset));
00585        }
00586        printf("%s|%s\n", result_line, perfdata_line);
00587 
00588        if(server_address!=NULL) free(server_address);
00589        return result;
00590 }
00591 
00592 void print_help(void){
00593        print_revision(progname, NP_VERSION);
00594 
00595        printf ("Copyright (c) 2006 Sean Finney\n");
00596        printf (COPYRIGHT, copyright, email);
00597 
00598        printf ("%s\n", _("This plugin checks the clock offset with the ntp server"));
00599 
00600        printf ("\n\n");
00601 
00602        print_usage();
00603        printf (UT_HELP_VRSN);
00604        printf (UT_EXTRA_OPTS);
00605        printf (UT_HOST_PORT, 'p', "123");
00606        printf (" %s\n", "-q, --quiet");
00607        printf ("    %s\n", _("Returns UNKNOWN instead of CRITICAL if offset cannot be found"));
00608        printf (" %s\n", "-w, --warning=THRESHOLD");
00609        printf ("    %s\n", _("Offset to result in warning status (seconds)"));
00610        printf (" %s\n", "-c, --critical=THRESHOLD");
00611        printf ("    %s\n", _("Offset to result in critical status (seconds)"));
00612        printf (UT_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
00613        printf (UT_VERBOSE);
00614 
00615        printf("\n");
00616        printf("%s\n", _("This plugin checks the clock offset between the local host and a"));
00617        printf("%s\n", _("remote NTP server. It is independent of any commandline programs or"));
00618        printf("%s\n", _("external libraries."));
00619 
00620        printf("\n");
00621        printf("%s\n", _("Notes:"));
00622        printf(" %s\n", _("If you'd rather want to monitor an NTP server, please use"));
00623        printf(" %s\n", _("check_ntp_peer."));
00624        printf("\n");
00625        printf(UT_THRESHOLDS_NOTES);
00626 
00627        printf("\n");
00628        printf("%s\n", _("Examples:"));
00629        printf("  %s\n", ("./check_ntp_time -H ntpserv -w 0.5 -c 1"));
00630 
00631        printf (UT_SUPPORT);
00632 }
00633 
00634 void
00635 print_usage(void)
00636 {
00637        printf ("%s\n", _("Usage:"));
00638        printf(" %s -H <host> [-w <warn>] [-c <crit>] [-v verbose]\n", progname);
00639 }
00640