NetBSD/external/bsd/ntp/dist/ntpq/libntpq.c

793 lines
22 KiB
C

/* $NetBSD: libntpq.c,v 1.1.1.1 2009/12/13 16:56:28 kardel Exp $ */
/*****************************************************************************
*
* libntpq.c
*
* This is the wrapper library for ntpq, the NTP query utility.
* This library reuses the sourcecode from ntpq and exports a number
* of useful functions in a library that can be linked against applications
* that need to query the status of a running ntpd. The whole
* communcation is based on mode 6 packets.
*
****************************************************************************/
#define _LIBNTPQC
#define NO_MAIN_ALLOWED 1
/* #define BUILD_AS_LIB Already provided by the Makefile */
#include "ntpq.c"
#include "libntpq.h"
/* Function Prototypes */
int ntpq_openhost(char *);
int ntpq_closehost(void);
int ntpq_queryhost(unsigned short VARSET, unsigned short association, char *resultbuf, int maxlen);
int ntpq_stripquotes ( char *resultbuf, char *srcbuf, int datalen, int maxlen );
int ntpq_queryhost_peervars(unsigned short association, char *resultbuf, int maxlen);
int ntpq_getvar( char *resultbuf, int datalen, const char *varname, char *varvalue, int maxlen);
int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen);
int ntpq_read_associations ( unsigned short resultbuf[], int max_entries );
int ntpq_read_sysvars( char *resultbuf, int maxsize );
int ntpq_get_assoc_allvars( int associd );
int ntpq_get_sysvars( void );
int ntpq_get_assocs ( void );
int ntpq_read_assoc_peervars( int associd, char *resultbuf, int maxsize );
int ntpq_read_assoc_clockvars( int associd, char *resultbuf, int maxsize );
int ntpq_get_assoc_number ( int associd );
int ntpq_get_assoc_peervars( int associd );
int ntpq_get_assoc_clockvars( int associd );
int ntpq_get_assoc_clocktype ( int assoc_number );
const char *Version = "libntpq 0.3beta";
/* global variables used for holding snapshots of data */
char peervars[NTPQ_BUFLEN];
int peervarlen = 0;
int peervar_assoc = 0;
char clockvars[NTPQ_BUFLEN];
int clockvarlen = 0;
int clockvar_assoc = 0;
char sysvars[NTPQ_BUFLEN];
int sysvarlen = 0;
char *ntpq_resultbuffer[NTPQ_BUFLEN];
unsigned short ntpq_associations[MAXASSOC];
struct ntpq_varlist ntpq_varlist[MAXLIST];
/*****************************************************************************
*
* ntpq_stripquotes
*
* Parses a given character buffer srcbuf and removes all quoted
* characters. The resulting string is copied to the specified
* resultbuf character buffer. E.g. \" will be translated into "
*
****************************************************************************
* Parameters:
* resultbuf char* The resulting string without quoted
* characters
* srcbuf char* The buffer holding the original string
* datalen int The number of bytes stored in srcbuf
* maxlen int Max. number of bytes for resultbuf
*
* Returns:
* int number of chars that have been copied to
* resultbuf
****************************************************************************/
int ntpq_stripquotes ( char *resultbuf, char *srcbuf, int datalen, int maxlen )
{
char* tmpbuf = srcbuf;
while ( *tmpbuf != 0 )
{
if ( *tmpbuf == '\"' )
{
tmpbuf++;
continue;
}
if ( *tmpbuf == '\\' )
{
tmpbuf++;
switch ( *tmpbuf )
{
/* ignore if end of string */
case 0:
continue;
/* skip and do not copy */
case '\"': /* quotes */
case 'n': /*newline*/
case 'r': /*carriage return*/
case 'g': /*bell*/
case 't': /*tab*/
tmpbuf++;
continue;
}
}
*resultbuf++ = *tmpbuf++;
}
*resultbuf = 0;
return strlen(resultbuf);
}
/*****************************************************************************
*
* ntpq_getvar
*
* This function parses a given buffer for a variable/value pair and
* copies the value of the requested variable into the specified
* varvalue buffer.
*
* It returns the number of bytes copied or zero for an empty result
* (=no matching variable found or empty value)
*
****************************************************************************
* Parameters:
* resultbuf char* The resulting string without quoted
* characters
* datalen int The number of bytes stored in
* resultbuf
* varname char* Name of the required variable
* varvalue char* Where the value of the variable should
* be stored
* maxlen int Max. number of bytes for varvalue
*
* Returns:
* int number of chars that have been copied to
* varvalue
****************************************************************************/
int ntpq_getvar( char *resultbuf, int datalen, const char *varname, char *varvalue, int maxlen)
{
char *name;
char *value = NULL;
while (nextvar(&datalen, &resultbuf, &name, &value)) {
if ( strcmp(varname, name) == 0 ) {
ntpq_stripquotes(varvalue,value,strlen(value),maxlen);
return strlen(varvalue);
}
}
return 0;
}
/*****************************************************************************
*
* ntpq_queryhost
*
* Sends a mode 6 query packet to the current open host (see
* ntpq_openhost) and stores the requested variable set in the specified
* character buffer.
* It returns the number of bytes read or zero for an empty result
* (=no answer or empty value)
*
****************************************************************************
* Parameters:
* VARSET u_short Which variable set should be
* read (PEERVARS or CLOCKVARS)
* association int The association ID that should be read
* 0 represents the ntpd instance itself
* resultbuf char* The resulting string without quoted
* characters
* maxlen int Max. number of bytes for varvalue
*
* Returns:
* int number of bytes that have been copied to
* resultbuf
* - OR -
* 0 (zero) if no reply has been received or
* another failure occured
****************************************************************************/
int ntpq_queryhost(unsigned short VARSET, unsigned short association, char *resultbuf, int maxlen)
{
char *datap;
int res;
int dsize;
u_short rstatus;
if ( numhosts > 0 )
res = doquery(VARSET,association,0,0, (char *)0, &rstatus, &dsize, &datap);
else
return 0;
if ( ( res != 0) || ( dsize == 0 ) ) /* no data */
return 0;
if ( dsize > maxlen)
dsize = maxlen;
/* fill result resultbuf */
memcpy(resultbuf, datap, dsize);
return dsize;
}
/*****************************************************************************
*
* ntpq_openhost
*
* Sets up a connection to the ntpd instance of a specified host. Note:
* There is no real "connection" established because NTP solely works
* based on UDP.
*
****************************************************************************
* Parameters:
* hostname char* Hostname/IP of the host running ntpd
*
* Returns:
* int 1 if the host connection could be set up, i.e.
* name resolution was succesful and/or IP address
* has been validated
* - OR -
* 0 (zero) if a failure occured
****************************************************************************/
int ntpq_openhost(char *hostname)
{
if ( openhost(hostname) )
{
numhosts = 1;
} else {
numhosts = 0;
}
return numhosts;
}
/*****************************************************************************
*
* ntpq_closehost
*
* Cleans up a connection by closing the used socket. Should be called
* when no further queries are required for the currently used host.
*
****************************************************************************
* Parameters:
* - none -
*
* Returns:
* int 0 (zero) if no host has been opened before
* - OR -
* the resultcode from the closesocket function call
****************************************************************************/
int ntpq_closehost(void)
{
if ( numhosts )
return closesocket(sockfd);
return 0;
}
/*****************************************************************************
*
* ntpq_read_associations
*
* This function queries the ntp host for its associations and returns the
* number of associations found.
*
* It takes an u_short array as its first parameter, this array holds the
* IDs of the associations,
* the function will not write more entries than specified with the
* max_entries parameter.
*
* However, if more than max_entries associations were found, the return
* value of this function will reflect the real number, even if not all
* associations have been stored in the array.
*
****************************************************************************
* Parameters:
* resultbuf u_short*Array that should hold the list of
* association IDs
* maxentries int maximum number of association IDs that can
* be stored in resultbuf
*
* Returns:
* int number of association IDs stored in resultbuf
* - OR -
* 0 (zero) if a failure occured or no association has
* been returned.
****************************************************************************/
int ntpq_read_associations ( u_short resultbuf[], int max_entries )
{
int i = 0;
if (ntpq_dogetassoc()) {
if(numassoc < max_entries)
max_entries = numassoc;
for (i=0;i<max_entries;i++)
resultbuf[i] = assoc_cache[i].assid;
return numassoc;
}
return 0;
}
/*****************************************************************************
*
* ntpq_get_assocs
*
* This function reads the associations of a previously selected (with
* ntpq_openhost) NTP host into its own (global) array and returns the
* number of associations found.
*
* The obtained association IDs can be read by using the ntpq_get_assoc_id
* function.
*
****************************************************************************
* Parameters:
* - none -
*
* Returns:
* int number of association IDs stored in resultbuf
* - OR -
* 0 (zero) if a failure occured or no association has
* been returned.
****************************************************************************/
int ntpq_get_assocs ( void )
{
return ntpq_read_associations( ntpq_associations, MAXASSOC );
}
/*****************************************************************************
*
* ntpq_get_assoc_number
*
* This function returns for a given Association ID the association number
* in the internal association array, which is filled by the ntpq_get_assocs
* function.
*
****************************************************************************
* Parameters:
* associd int requested associaton ID
*
* Returns:
* int the number of the association array element that is
* representing the given association ID
* - OR -
* -1 if a failure occured or no matching association
* ID has been found
****************************************************************************/
int ntpq_get_assoc_number ( int associd )
{
int i = 0;
for (i=0;i<numassoc;i++) {
if (assoc_cache[i].assid == associd)
return i;
}
return (-1);
}
/*****************************************************************************
*
* ntpq_read_assoc_peervars
*
* This function reads the peervars variable-set of a specified association
* from a NTP host and writes it to the result buffer specified, honoring
* the maxsize limit.
*
* It returns the number of bytes written or 0 when the variable-set is
* empty or failed to read.
*
****************************************************************************
* Parameters:
* associd int requested associaton ID
* resultbuf char* character buffer where the variable set
* should be stored
* maxsize int the maximum number of bytes that can be
* written to resultbuf
*
* Returns:
* int number of chars that have been copied to
* resultbuf
* - OR -
* 0 (zero) if an error occured
****************************************************************************/
int ntpq_read_assoc_peervars( int associd, char *resultbuf, int maxsize )
{
char *datap;
int res;
int dsize;
u_short rstatus;
l_fp rec;
l_fp ts;
char value[NTPQ_BUFLEN];
res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus,
&dsize, &datap);
if (res != 0)
return 0;
get_systime(&ts);
if (dsize == 0) {
if (numhosts > 1)
(void) fprintf(stderr, "server=%s ", currenthost);
(void) fprintf(stderr,
"***No information returned for association %d\n",
associd);
return 0;
} else {
if ( dsize > maxsize )
dsize = maxsize;
memcpy(resultbuf,datap,dsize);
resultbuf[dsize]=0x0;
ntpq_getvar(resultbuf, dsize, "rec", value, sizeof (value) );
if (!decodets(value, &rec))
L_CLR(&rec);
memcpy(resultbuf,value,maxsize);
resultbuf[dsize]=0x0;
dsize=strlen(resultbuf);
}
return dsize;
}
/*****************************************************************************
*
* ntpq_read_sysvars
*
* This function reads the sysvars variable-set from a NTP host and writes it
* to the result buffer specified, honoring the maxsize limit.
*
* It returns the number of bytes written or 0 when the variable-set is empty
* or could not be read.
*
****************************************************************************
* Parameters:
* resultbuf char* character buffer where the variable set
* should be stored
* maxsize int the maximum number of bytes that can be
* written to resultbuf
*
* Returns:
* int number of chars that have been copied to
* resultbuf
* - OR -
* 0 (zero) if an error occured
****************************************************************************/
int ntpq_read_sysvars( char *resultbuf, int maxsize )
{
char *datap;
int res;
int dsize;
u_short rstatus;
res = doquery(CTL_OP_READVAR, 0, 0, 0, (char *)0, &rstatus,
&dsize, &datap);
if (res != 0)
return 0;
if (dsize == 0) {
if (numhosts > 1)
(void) fprintf(stderr, "server=%s ", currenthost);
(void) fprintf(stderr,
"***No sysvar information returned \n");
return 0;
} else {
if ( dsize > maxsize )
dsize = maxsize;
memcpy(resultbuf,datap,dsize);
}
return dsize;
}
/*****************************************************************************
* ntpq_get_assoc_allvars
*
* With this function all association variables for the specified association
* ID can be requested from a NTP host. They are stored internally and can be
* read by using the ntpq_get_peervar or ntpq_get_clockvar functions.
*
* Basically this is only a combination of the ntpq_get_assoc_peervars and
* ntpq_get_assoc_clockvars functions.
*
* It returns 1 if both variable-sets (peervars and clockvars) were
* received successfully. If one variable-set or both of them weren't
* received,
*
****************************************************************************
* Parameters:
* associd int requested associaton ID
*
* Returns:
* int nonzero if at least one variable set could be read
* - OR -
* 0 (zero) if an error occured and both variable sets
* could not be read
****************************************************************************/
int ntpq_get_assoc_allvars( int associd )
{
return ( ntpq_get_assoc_peervars ( associd ) & ntpq_get_assoc_clockvars( associd ) );
}
/*****************************************************************************
*
* ntpq_get_sysvars
*
* The system variables of a NTP host can be requested by using this function
* and afterwards using ntpq_get_sysvar to read the single variable values.
*
****************************************************************************
* Parameters:
* - none -
*
* Returns:
* int nonzero if the variable set could be read
* - OR -
* 0 (zero) if an error occured and the sysvars
* could not be read
****************************************************************************/
int ntpq_get_sysvars( void )
{
sysvarlen = ( ntpq_read_sysvars( sysvars, sizeof(sysvars )) );
if ( sysvarlen <= 0 ) {
return 0;
} else {
return 1;
}
}
/*****************************************************************************
*
* ntp_get_peervar
*
* This function uses the variable-set which was read by using
* ntp_get_peervars and searches for a variable specified with varname. If
* such a variable exists, it writes its value into
* varvalue (maxlen specifies the size of this target buffer).
*
****************************************************************************
* Parameters:
* varname char* requested variable name
* varvalue char* the buffer where the value should go into
* maxlen int maximum number of bytes that can be copied to
* varvalue
*
* Returns:
* int number of bytes copied to varvalue
* - OR -
* 0 (zero) if an error occured or the variable could
* not be found
****************************************************************************/
int ntpq_get_peervar( const char *varname, char *varvalue, int maxlen)
{
return ( ntpq_getvar(peervars,peervarlen,varname,varvalue,maxlen) );
}
/*****************************************************************************
*
* ntpq_get_assoc_peervars
*
* This function requests the peer variables of the specified association
* from a NTP host. In order to access the variable values, the function
* ntpq_get_peervar must be used.
*
****************************************************************************
* Parameters:
* associd int requested associaton ID
*
* Returns:
* int 1 (one) if the peervars have been read
* - OR -
* 0 (zero) if an error occured and the variable set
* could not be read
****************************************************************************/
int ntpq_get_assoc_peervars( int associd )
{
peervarlen = ( ntpq_read_assoc_peervars( associd, peervars, sizeof(peervars )) );
if ( peervarlen <= 0 ) {
peervar_assoc = 0;
return 0;
} else {
peervar_assoc = associd;
return 1;
}
}
/*****************************************************************************
*
* ntp_read_assoc_clockvars
*
* This function reads the clockvars variable-set of a specified association
* from a NTP host and writes it to the result buffer specified, honoring
* the maxsize limit.
*
* It returns the number of bytes written or 0 when the variable-set is
* empty or failed to read.
*
****************************************************************************
* Parameters:
* associd int requested associaton ID
* resultbuf char* character buffer where the variable set
* should be stored
* maxsize int the maximum number of bytes that can be
* written to resultbuf
*
* Returns:
* int number of chars that have been copied to
* resultbuf
* - OR -
* 0 (zero) if an error occured
****************************************************************************/
int ntpq_read_assoc_clockvars( int associd, char *resultbuf, int maxsize )
{
char *datap;
int res;
int dsize;
u_short rstatus;
res = ntpq_doquerylist(ntpq_varlist, CTL_OP_READCLOCK, associd, 0, &rstatus, &dsize, &datap);
if (res != 0)
return 0;
if (dsize == 0) {
if (numhosts > 1) /* no information returned from server */
return 0;
} else {
if ( dsize > maxsize )
dsize = maxsize;
memcpy(resultbuf,datap,dsize);
}
return dsize;
}
/*****************************************************************************
*
* ntpq_get_assoc_clocktype
*
* This function returns a clocktype value for a given association number
* (not ID!):
*
* NTP_CLOCKTYPE_UNKNOWN Unknown clock type
* NTP_CLOCKTYPE_BROADCAST Broadcast server
* NTP_CLOCKTYPE_LOCAL Local clock
* NTP_CLOCKTYPE_UNICAST Unicast server
* NTP_CLOCKTYPE_MULTICAST Multicast server
*
****************************************************************************/
int ntpq_get_assoc_clocktype ( int assoc_number )
{
int type = 0;
int i, rc = 0;
sockaddr_u dum_store;
char value[LENHOSTNAME];
char resultbuf[1024];
if ( assoc_number < 0 || assoc_number > numassoc ) {
return -1;
} else {
if ( peervar_assoc != assoc_cache[assoc_number].assid ) {
i=ntpq_read_assoc_peervars(assoc_cache[assoc_number].assid, resultbuf, sizeof(resultbuf));
if ( i <= 0 ) {
return -1;
}
rc = ntpq_getvar(resultbuf, i, "dstadr", value, LENHOSTNAME );
} else {
rc = ntpq_get_peervar("dstadr",value,LENHOSTNAME);
}
if ( rc ) {
if (decodenetnum(value, &dum_store)) {
type = ntpq_decodeaddrtype(&dum_store);
return type;
}
}
return -1;
}
return -1;
}
/*****************************************************************************
*
* ntpq_get_assoc_clockvars
*
* With this function the clock variables of the specified association are
* requested from a NTP host. This makes only sense for associations with
* the type 'l' (Local Clock) and you should check this with
* ntpq_get_assoc_clocktype for each association, before you use this function
* on it.
*
****************************************************************************
* Parameters:
* associd int requested associaton ID
*
* Returns:
* int 1 (one) if the clockvars have been read
* - OR -
* 0 (zero) if an error occured and the variable set
* could not be read
****************************************************************************/
int ntpq_get_assoc_clockvars( int associd )
{
if ( ntpq_get_assoc_clocktype(ntpq_get_assoc_number(associd)) != NTP_CLOCKTYPE_LOCAL )
return 0;
clockvarlen = ( ntpq_read_assoc_clockvars( associd, clockvars, sizeof(clockvars )) );
if ( clockvarlen <= 0 ) {
clockvar_assoc = 0;
return 0;
} else {
clockvar_assoc = associd;
return 1;
}
}