Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / ntpq / libntpq.c
blob2dda42227dd3d6b5efe750a1350c4d8b7460cbc1
1 /* $NetBSD$ */
3 /*****************************************************************************
5 * libntpq.c
7 * This is the wrapper library for ntpq, the NTP query utility.
8 * This library reuses the sourcecode from ntpq and exports a number
9 * of useful functions in a library that can be linked against applications
10 * that need to query the status of a running ntpd. The whole
11 * communcation is based on mode 6 packets.
13 ****************************************************************************/
14 #define _LIBNTPQC
15 #define NO_MAIN_ALLOWED 1
16 /* #define BUILD_AS_LIB Already provided by the Makefile */
18 #include "ntpq.c"
19 #include "libntpq.h"
21 /* Function Prototypes */
22 int ntpq_openhost(char *);
23 int ntpq_closehost(void);
24 int ntpq_queryhost(unsigned short VARSET, unsigned short association, char *resultbuf, int maxlen);
25 int ntpq_stripquotes ( char *resultbuf, char *srcbuf, int datalen, int maxlen );
26 int ntpq_queryhost_peervars(unsigned short association, char *resultbuf, int maxlen);
27 int ntpq_getvar( char *resultbuf, int datalen, const char *varname, char *varvalue, int maxlen);
28 int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen);
29 int ntpq_read_associations ( unsigned short resultbuf[], int max_entries );
30 int ntpq_read_sysvars( char *resultbuf, int maxsize );
31 int ntpq_get_assoc_allvars( int associd );
32 int ntpq_get_sysvars( void );
33 int ntpq_get_assocs ( void );
34 int ntpq_read_assoc_peervars( int associd, char *resultbuf, int maxsize );
35 int ntpq_read_assoc_clockvars( int associd, char *resultbuf, int maxsize );
36 int ntpq_get_assoc_number ( int associd );
37 int ntpq_get_assoc_peervars( int associd );
38 int ntpq_get_assoc_clockvars( int associd );
39 int ntpq_get_assoc_clocktype ( int assoc_number );
42 const char *Version = "libntpq 0.3beta";
44 /* global variables used for holding snapshots of data */
45 char peervars[NTPQ_BUFLEN];
46 int peervarlen = 0;
47 int peervar_assoc = 0;
48 char clockvars[NTPQ_BUFLEN];
49 int clockvarlen = 0;
50 int clockvar_assoc = 0;
51 char sysvars[NTPQ_BUFLEN];
52 int sysvarlen = 0;
53 char *ntpq_resultbuffer[NTPQ_BUFLEN];
54 unsigned short ntpq_associations[MAXASSOC];
56 struct ntpq_varlist ntpq_varlist[MAXLIST];
58 /*****************************************************************************
60 * ntpq_stripquotes
62 * Parses a given character buffer srcbuf and removes all quoted
63 * characters. The resulting string is copied to the specified
64 * resultbuf character buffer. E.g. \" will be translated into "
66 ****************************************************************************
67 * Parameters:
68 * resultbuf char* The resulting string without quoted
69 * characters
70 * srcbuf char* The buffer holding the original string
71 * datalen int The number of bytes stored in srcbuf
72 * maxlen int Max. number of bytes for resultbuf
74 * Returns:
75 * int number of chars that have been copied to
76 * resultbuf
77 ****************************************************************************/
79 int ntpq_stripquotes ( char *resultbuf, char *srcbuf, int datalen, int maxlen )
81 char* tmpbuf = srcbuf;
83 while ( *tmpbuf != 0 )
85 if ( *tmpbuf == '\"' )
87 tmpbuf++;
88 continue;
91 if ( *tmpbuf == '\\' )
93 tmpbuf++;
94 switch ( *tmpbuf )
96 /* ignore if end of string */
97 case 0:
98 continue;
99 /* skip and do not copy */
100 case '\"': /* quotes */
101 case 'n': /*newline*/
102 case 'r': /*carriage return*/
103 case 'g': /*bell*/
104 case 't': /*tab*/
105 tmpbuf++;
106 continue;
110 *resultbuf++ = *tmpbuf++;
114 *resultbuf = 0;
115 return strlen(resultbuf);
119 /*****************************************************************************
121 * ntpq_getvar
123 * This function parses a given buffer for a variable/value pair and
124 * copies the value of the requested variable into the specified
125 * varvalue buffer.
127 * It returns the number of bytes copied or zero for an empty result
128 * (=no matching variable found or empty value)
130 ****************************************************************************
131 * Parameters:
132 * resultbuf char* The resulting string without quoted
133 * characters
134 * datalen int The number of bytes stored in
135 * resultbuf
136 * varname char* Name of the required variable
137 * varvalue char* Where the value of the variable should
138 * be stored
139 * maxlen int Max. number of bytes for varvalue
141 * Returns:
142 * int number of chars that have been copied to
143 * varvalue
144 ****************************************************************************/
146 int ntpq_getvar( char *resultbuf, int datalen, const char *varname, char *varvalue, int maxlen)
148 char *name;
149 char *value = NULL;
151 while (nextvar(&datalen, &resultbuf, &name, &value)) {
153 if ( strcmp(varname, name) == 0 ) {
154 ntpq_stripquotes(varvalue,value,strlen(value),maxlen);
155 return strlen(varvalue);
159 return 0;
163 /*****************************************************************************
165 * ntpq_queryhost
167 * Sends a mode 6 query packet to the current open host (see
168 * ntpq_openhost) and stores the requested variable set in the specified
169 * character buffer.
170 * It returns the number of bytes read or zero for an empty result
171 * (=no answer or empty value)
173 ****************************************************************************
174 * Parameters:
175 * VARSET u_short Which variable set should be
176 * read (PEERVARS or CLOCKVARS)
177 * association int The association ID that should be read
178 * 0 represents the ntpd instance itself
179 * resultbuf char* The resulting string without quoted
180 * characters
181 * maxlen int Max. number of bytes for varvalue
183 * Returns:
184 * int number of bytes that have been copied to
185 * resultbuf
186 * - OR -
187 * 0 (zero) if no reply has been received or
188 * another failure occured
189 ****************************************************************************/
191 int ntpq_queryhost(unsigned short VARSET, unsigned short association, char *resultbuf, int maxlen)
193 char *datap;
194 int res;
195 int dsize;
196 u_short rstatus;
198 if ( numhosts > 0 )
199 res = doquery(VARSET,association,0,0, (char *)0, &rstatus, &dsize, &datap);
200 else
201 return 0;
203 if ( ( res != 0) || ( dsize == 0 ) ) /* no data */
204 return 0;
206 if ( dsize > maxlen)
207 dsize = maxlen;
210 /* fill result resultbuf */
211 memcpy(resultbuf, datap, dsize);
213 return dsize;
218 /*****************************************************************************
220 * ntpq_openhost
222 * Sets up a connection to the ntpd instance of a specified host. Note:
223 * There is no real "connection" established because NTP solely works
224 * based on UDP.
226 ****************************************************************************
227 * Parameters:
228 * hostname char* Hostname/IP of the host running ntpd
230 * Returns:
231 * int 1 if the host connection could be set up, i.e.
232 * name resolution was succesful and/or IP address
233 * has been validated
234 * - OR -
235 * 0 (zero) if a failure occured
236 ****************************************************************************/
238 int ntpq_openhost(char *hostname)
240 if ( openhost(hostname) )
242 numhosts = 1;
243 } else {
244 numhosts = 0;
247 return numhosts;
252 /*****************************************************************************
254 * ntpq_closehost
256 * Cleans up a connection by closing the used socket. Should be called
257 * when no further queries are required for the currently used host.
259 ****************************************************************************
260 * Parameters:
261 * - none -
263 * Returns:
264 * int 0 (zero) if no host has been opened before
265 * - OR -
266 * the resultcode from the closesocket function call
267 ****************************************************************************/
269 int ntpq_closehost(void)
271 if ( numhosts )
272 return closesocket(sockfd);
274 return 0;
278 /*****************************************************************************
280 * ntpq_read_associations
282 * This function queries the ntp host for its associations and returns the
283 * number of associations found.
285 * It takes an u_short array as its first parameter, this array holds the
286 * IDs of the associations,
287 * the function will not write more entries than specified with the
288 * max_entries parameter.
290 * However, if more than max_entries associations were found, the return
291 * value of this function will reflect the real number, even if not all
292 * associations have been stored in the array.
294 ****************************************************************************
295 * Parameters:
296 * resultbuf u_short*Array that should hold the list of
297 * association IDs
298 * maxentries int maximum number of association IDs that can
299 * be stored in resultbuf
301 * Returns:
302 * int number of association IDs stored in resultbuf
303 * - OR -
304 * 0 (zero) if a failure occured or no association has
305 * been returned.
306 ****************************************************************************/
308 int ntpq_read_associations ( u_short resultbuf[], int max_entries )
310 int i = 0;
312 if (ntpq_dogetassoc()) {
314 if(numassoc < max_entries)
315 max_entries = numassoc;
317 for (i=0;i<max_entries;i++)
318 resultbuf[i] = assoc_cache[i].assid;
320 return numassoc;
323 return 0;
329 /*****************************************************************************
331 * ntpq_get_assocs
333 * This function reads the associations of a previously selected (with
334 * ntpq_openhost) NTP host into its own (global) array and returns the
335 * number of associations found.
337 * The obtained association IDs can be read by using the ntpq_get_assoc_id
338 * function.
340 ****************************************************************************
341 * Parameters:
342 * - none -
344 * Returns:
345 * int number of association IDs stored in resultbuf
346 * - OR -
347 * 0 (zero) if a failure occured or no association has
348 * been returned.
349 ****************************************************************************/
351 int ntpq_get_assocs ( void )
353 return ntpq_read_associations( ntpq_associations, MAXASSOC );
357 /*****************************************************************************
359 * ntpq_get_assoc_number
361 * This function returns for a given Association ID the association number
362 * in the internal association array, which is filled by the ntpq_get_assocs
363 * function.
365 ****************************************************************************
366 * Parameters:
367 * associd int requested associaton ID
369 * Returns:
370 * int the number of the association array element that is
371 * representing the given association ID
372 * - OR -
373 * -1 if a failure occured or no matching association
374 * ID has been found
375 ****************************************************************************/
377 int ntpq_get_assoc_number ( int associd )
379 int i = 0;
381 for (i=0;i<numassoc;i++) {
382 if (assoc_cache[i].assid == associd)
383 return i;
386 return (-1);
391 /*****************************************************************************
393 * ntpq_read_assoc_peervars
395 * This function reads the peervars variable-set of a specified association
396 * from a NTP host and writes it to the result buffer specified, honoring
397 * the maxsize limit.
399 * It returns the number of bytes written or 0 when the variable-set is
400 * empty or failed to read.
402 ****************************************************************************
403 * Parameters:
404 * associd int requested associaton ID
405 * resultbuf char* character buffer where the variable set
406 * should be stored
407 * maxsize int the maximum number of bytes that can be
408 * written to resultbuf
410 * Returns:
411 * int number of chars that have been copied to
412 * resultbuf
413 * - OR -
414 * 0 (zero) if an error occured
415 ****************************************************************************/
417 int ntpq_read_assoc_peervars( int associd, char *resultbuf, int maxsize )
420 char *datap;
421 int res;
422 int dsize;
423 u_short rstatus;
424 l_fp rec;
425 l_fp ts;
426 char value[NTPQ_BUFLEN];
429 res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus,
430 &dsize, &datap);
432 if (res != 0)
433 return 0;
435 get_systime(&ts);
437 if (dsize == 0) {
438 if (numhosts > 1)
439 (void) fprintf(stderr, "server=%s ", currenthost);
440 (void) fprintf(stderr,
441 "***No information returned for association %d\n",
442 associd);
443 return 0;
444 } else {
445 if ( dsize > maxsize )
446 dsize = maxsize;
448 memcpy(resultbuf,datap,dsize);
449 resultbuf[dsize]=0x0;
451 ntpq_getvar(resultbuf, dsize, "rec", value, sizeof (value) );
453 if (!decodets(value, &rec))
454 L_CLR(&rec);
456 memcpy(resultbuf,value,maxsize);
457 resultbuf[dsize]=0x0;
458 dsize=strlen(resultbuf);
462 return dsize;
469 /*****************************************************************************
471 * ntpq_read_sysvars
473 * This function reads the sysvars variable-set from a NTP host and writes it
474 * to the result buffer specified, honoring the maxsize limit.
476 * It returns the number of bytes written or 0 when the variable-set is empty
477 * or could not be read.
479 ****************************************************************************
480 * Parameters:
481 * resultbuf char* character buffer where the variable set
482 * should be stored
483 * maxsize int the maximum number of bytes that can be
484 * written to resultbuf
486 * Returns:
487 * int number of chars that have been copied to
488 * resultbuf
489 * - OR -
490 * 0 (zero) if an error occured
491 ****************************************************************************/
492 int ntpq_read_sysvars( char *resultbuf, int maxsize )
495 char *datap;
496 int res;
497 int dsize;
498 u_short rstatus;
500 res = doquery(CTL_OP_READVAR, 0, 0, 0, (char *)0, &rstatus,
501 &dsize, &datap);
503 if (res != 0)
504 return 0;
506 if (dsize == 0) {
507 if (numhosts > 1)
508 (void) fprintf(stderr, "server=%s ", currenthost);
509 (void) fprintf(stderr,
510 "***No sysvar information returned \n");
511 return 0;
512 } else {
513 if ( dsize > maxsize )
514 dsize = maxsize;
516 memcpy(resultbuf,datap,dsize);
519 return dsize;
524 /*****************************************************************************
525 * ntpq_get_assoc_allvars
527 * With this function all association variables for the specified association
528 * ID can be requested from a NTP host. They are stored internally and can be
529 * read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
531 * Basically this is only a combination of the ntpq_get_assoc_peervars and
532 * ntpq_get_assoc_clockvars functions.
534 * It returns 1 if both variable-sets (peervars and clockvars) were
535 * received successfully. If one variable-set or both of them weren't
536 * received,
538 ****************************************************************************
539 * Parameters:
540 * associd int requested associaton ID
542 * Returns:
543 * int nonzero if at least one variable set could be read
544 * - OR -
545 * 0 (zero) if an error occured and both variable sets
546 * could not be read
547 ****************************************************************************/
548 int ntpq_get_assoc_allvars( int associd )
550 return ( ntpq_get_assoc_peervars ( associd ) & ntpq_get_assoc_clockvars( associd ) );
556 /*****************************************************************************
558 * ntpq_get_sysvars
560 * The system variables of a NTP host can be requested by using this function
561 * and afterwards using ntpq_get_sysvar to read the single variable values.
563 ****************************************************************************
564 * Parameters:
565 * - none -
567 * Returns:
568 * int nonzero if the variable set could be read
569 * - OR -
570 * 0 (zero) if an error occured and the sysvars
571 * could not be read
572 ****************************************************************************/
573 int ntpq_get_sysvars( void )
575 sysvarlen = ( ntpq_read_sysvars( sysvars, sizeof(sysvars )) );
576 if ( sysvarlen <= 0 ) {
577 return 0;
578 } else {
579 return 1;
584 /*****************************************************************************
586 * ntp_get_peervar
588 * This function uses the variable-set which was read by using
589 * ntp_get_peervars and searches for a variable specified with varname. If
590 * such a variable exists, it writes its value into
591 * varvalue (maxlen specifies the size of this target buffer).
593 ****************************************************************************
594 * Parameters:
595 * varname char* requested variable name
596 * varvalue char* the buffer where the value should go into
597 * maxlen int maximum number of bytes that can be copied to
598 * varvalue
600 * Returns:
601 * int number of bytes copied to varvalue
602 * - OR -
603 * 0 (zero) if an error occured or the variable could
604 * not be found
605 ****************************************************************************/
606 int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen)
608 return ( ntpq_getvar(peervars,peervarlen,varname,varvalue,maxlen) );
613 /*****************************************************************************
615 * ntpq_get_assoc_peervars
617 * This function requests the peer variables of the specified association
618 * from a NTP host. In order to access the variable values, the function
619 * ntpq_get_peervar must be used.
621 ****************************************************************************
622 * Parameters:
623 * associd int requested associaton ID
625 * Returns:
626 * int 1 (one) if the peervars have been read
627 * - OR -
628 * 0 (zero) if an error occured and the variable set
629 * could not be read
630 ****************************************************************************/
631 int ntpq_get_assoc_peervars( int associd )
633 peervarlen = ( ntpq_read_assoc_peervars( associd, peervars, sizeof(peervars )) );
634 if ( peervarlen <= 0 ) {
635 peervar_assoc = 0;
636 return 0;
637 } else {
638 peervar_assoc = associd;
639 return 1;
644 /*****************************************************************************
646 * ntp_read_assoc_clockvars
648 * This function reads the clockvars variable-set of a specified association
649 * from a NTP host and writes it to the result buffer specified, honoring
650 * the maxsize limit.
652 * It returns the number of bytes written or 0 when the variable-set is
653 * empty or failed to read.
655 ****************************************************************************
656 * Parameters:
657 * associd int requested associaton ID
658 * resultbuf char* character buffer where the variable set
659 * should be stored
660 * maxsize int the maximum number of bytes that can be
661 * written to resultbuf
663 * Returns:
664 * int number of chars that have been copied to
665 * resultbuf
666 * - OR -
667 * 0 (zero) if an error occured
668 ****************************************************************************/
670 int ntpq_read_assoc_clockvars( int associd, char *resultbuf, int maxsize )
673 char *datap;
674 int res;
675 int dsize;
676 u_short rstatus;
678 res = ntpq_doquerylist(ntpq_varlist, CTL_OP_READCLOCK, associd, 0, &rstatus, &dsize, &datap);
680 if (res != 0)
681 return 0;
683 if (dsize == 0) {
684 if (numhosts > 1) /* no information returned from server */
685 return 0;
686 } else {
687 if ( dsize > maxsize )
688 dsize = maxsize;
690 memcpy(resultbuf,datap,dsize);
693 return dsize;
698 /*****************************************************************************
700 * ntpq_get_assoc_clocktype
702 * This function returns a clocktype value for a given association number
703 * (not ID!):
705 * NTP_CLOCKTYPE_UNKNOWN Unknown clock type
706 * NTP_CLOCKTYPE_BROADCAST Broadcast server
707 * NTP_CLOCKTYPE_LOCAL Local clock
708 * NTP_CLOCKTYPE_UNICAST Unicast server
709 * NTP_CLOCKTYPE_MULTICAST Multicast server
711 ****************************************************************************/
712 int ntpq_get_assoc_clocktype ( int assoc_number )
714 int type = 0;
715 int i, rc = 0;
716 sockaddr_u dum_store;
717 char value[LENHOSTNAME];
718 char resultbuf[1024];
721 if ( assoc_number < 0 || assoc_number > numassoc ) {
722 return -1;
723 } else {
724 if ( peervar_assoc != assoc_cache[assoc_number].assid ) {
726 i=ntpq_read_assoc_peervars(assoc_cache[assoc_number].assid, resultbuf, sizeof(resultbuf));
727 if ( i <= 0 ) {
728 return -1;
731 rc = ntpq_getvar(resultbuf, i, "dstadr", value, LENHOSTNAME );
734 } else {
736 rc = ntpq_get_peervar("dstadr",value,LENHOSTNAME);
740 if ( rc ) {
741 if (decodenetnum(value, &dum_store)) {
742 type = ntpq_decodeaddrtype(&dum_store);
743 return type;
747 return -1;
750 return -1;
756 /*****************************************************************************
758 * ntpq_get_assoc_clockvars
760 * With this function the clock variables of the specified association are
761 * requested from a NTP host. This makes only sense for associations with
762 * the type 'l' (Local Clock) and you should check this with
763 * ntpq_get_assoc_clocktype for each association, before you use this function
764 * on it.
766 ****************************************************************************
767 * Parameters:
768 * associd int requested associaton ID
770 * Returns:
771 * int 1 (one) if the clockvars have been read
772 * - OR -
773 * 0 (zero) if an error occured and the variable set
774 * could not be read
775 ****************************************************************************/
776 int ntpq_get_assoc_clockvars( int associd )
779 if ( ntpq_get_assoc_clocktype(ntpq_get_assoc_number(associd)) != NTP_CLOCKTYPE_LOCAL )
780 return 0;
782 clockvarlen = ( ntpq_read_assoc_clockvars( associd, clockvars, sizeof(clockvars )) );
783 if ( clockvarlen <= 0 ) {
784 clockvar_assoc = 0;
785 return 0;
786 } else {
787 clockvar_assoc = associd;
788 return 1;