more format updates

This commit is contained in:
fishwaldo 2003-06-13 14:44:37 +00:00
parent 4d85ccb8ab
commit 47b4694e83
26 changed files with 6294 additions and 5279 deletions

2
.gitattributes vendored
View file

@ -18,6 +18,7 @@
/Unreal.h -text
/acconfig.h -text
/aclocal.m4 -text
adns/.indent.pro -text
adns/Makefile -text
adns/adns.h -text
adns/check.c -text
@ -131,6 +132,7 @@ doc/read-userman -text
/ircd.c -text
/ircd.h -text
/keeper.c -text
keeper/.indent.pro -text
keeper/Makefile -text
keeper/keeper.h -text
keeper/kp_cache.c -text

1
adns/.indent.pro vendored Normal file
View file

@ -0,0 +1 @@
-br -ce -ts8 -kr -i8 -ut -v

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: adns.h,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
** $Id: adns.h,v 1.3 2003/06/13 14:44:35 fishwaldo Exp $
*/
/*
@ -74,7 +74,7 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
* $Id: adns.h,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
* $Id: adns.h,v 1.3 2003/06/13 14:44:35 fishwaldo Exp $
*/
#ifndef ADNS_H_INCLUDED
@ -89,73 +89,72 @@
#include <unistd.h>
#ifdef __cplusplus
extern "C" { /* I really dislike this - iwj. */
extern "C" { /* I really dislike this - iwj. */
#endif
/* All struct in_addr anywhere in adns are in NETWORK byte order. */
typedef struct adns__state *adns_state;
typedef struct adns__query *adns_query;
typedef struct adns__state *adns_state;
typedef struct adns__query *adns_query;
typedef enum {
adns_if_noenv= 0x0001, /* do not look at environment */
adns_if_noerrprint= 0x0002, /* never print output to stderr (_debug overrides) */
adns_if_noserverwarn= 0x0004, /* do not warn to stderr about duff nameservers etc */
adns_if_debug= 0x0008, /* enable all output to stderr plus debug msgs */
adns_if_logpid= 0x0080, /* include pid in diagnostic output */
adns_if_noautosys= 0x0010, /* do not make syscalls at every opportunity */
adns_if_eintr= 0x0020, /* allow _wait and _synchronous to return EINTR */
adns_if_nosigpipe= 0x0040, /* applic has SIGPIPE set to SIG_IGN, do not protect */
adns_if_checkc_entex= 0x0100, /* do consistency checks on entry/exit to adns funcs */
adns_if_checkc_freq= 0x0300 /* do consistency checks very frequently (slow!) */
} adns_initflags;
typedef enum {
adns_if_noenv = 0x0001, /* do not look at environment */
adns_if_noerrprint = 0x0002, /* never print output to stderr (_debug overrides) */
adns_if_noserverwarn = 0x0004, /* do not warn to stderr about duff nameservers etc */
adns_if_debug = 0x0008, /* enable all output to stderr plus debug msgs */
adns_if_logpid = 0x0080, /* include pid in diagnostic output */
adns_if_noautosys = 0x0010, /* do not make syscalls at every opportunity */
adns_if_eintr = 0x0020, /* allow _wait and _synchronous to return EINTR */
adns_if_nosigpipe = 0x0040, /* applic has SIGPIPE set to SIG_IGN, do not protect */
adns_if_checkc_entex = 0x0100, /* do consistency checks on entry/exit to adns funcs */
adns_if_checkc_freq = 0x0300 /* do consistency checks very frequently (slow!) */
} adns_initflags;
typedef enum {
adns_qf_search= 0x00000001, /* use the searchlist */
adns_qf_usevc= 0x00000002, /* use a virtual circuit (TCP connection) */
adns_qf_owner= 0x00000004, /* fill in the owner field in the answer */
adns_qf_quoteok_query= 0x00000010, /* allow special chars in query domain */
adns_qf_quoteok_cname= 0x00000000, /* allow ... in CNAME we go via - now default */
adns_qf_quoteok_anshost= 0x00000040, /* allow ... in things supposed to be hostnames */
adns_qf_quotefail_cname= 0x00000080, /* refuse if quote-req chars in CNAME we go via */
adns_qf_cname_loose= 0x00000100, /* allow refs to CNAMEs - without, get _s_cname */
adns_qf_cname_forbid= 0x00000200, /* don't follow CNAMEs, instead give _s_cname */
adns__qf_internalmask= 0x0ff00000
} adns_queryflags;
typedef enum {
adns_qf_search = 0x00000001, /* use the searchlist */
adns_qf_usevc = 0x00000002, /* use a virtual circuit (TCP connection) */
adns_qf_owner = 0x00000004, /* fill in the owner field in the answer */
adns_qf_quoteok_query = 0x00000010, /* allow special chars in query domain */
adns_qf_quoteok_cname = 0x00000000, /* allow ... in CNAME we go via - now default */
adns_qf_quoteok_anshost = 0x00000040, /* allow ... in things supposed to be hostnames */
adns_qf_quotefail_cname = 0x00000080, /* refuse if quote-req chars in CNAME we go via */
adns_qf_cname_loose = 0x00000100, /* allow refs to CNAMEs - without, get _s_cname */
adns_qf_cname_forbid = 0x00000200, /* don't follow CNAMEs, instead give _s_cname */
adns__qf_internalmask = 0x0ff00000
} adns_queryflags;
typedef enum {
adns__rrt_typemask= 0x0ffff,
adns__qtf_deref= 0x10000, /* dereference domains and perhaps produce extra data */
adns__qtf_mail822= 0x20000, /* make mailboxes be in RFC822 rcpt field format */
adns_r_none= 0,
adns_r_a= 1,
adns_r_ns_raw= 2,
adns_r_ns= adns_r_ns_raw|adns__qtf_deref,
adns_r_cname= 5,
adns_r_soa_raw= 6,
adns_r_soa= adns_r_soa_raw|adns__qtf_mail822,
adns_r_ptr_raw= 12,
adns_r_ptr= adns_r_ptr_raw|adns__qtf_deref,
adns_r_hinfo= 13,
adns_r_mx_raw= 15,
adns_r_mx= adns_r_mx_raw|adns__qtf_deref,
adns_r_txt= 16,
adns_r_rp_raw= 17,
adns_r_rp= adns_r_rp_raw|adns__qtf_mail822,
typedef enum {
adns__rrt_typemask = 0x0ffff,
adns__qtf_deref = 0x10000, /* dereference domains and perhaps produce extra data */
adns__qtf_mail822 = 0x20000, /* make mailboxes be in RFC822 rcpt field format */
adns_r_addr= adns_r_a|adns__qtf_deref
} adns_rrtype;
adns_r_none = 0,
adns_r_a = 1,
adns_r_ns_raw = 2,
adns_r_ns = adns_r_ns_raw | adns__qtf_deref,
adns_r_cname = 5,
adns_r_soa_raw = 6,
adns_r_soa = adns_r_soa_raw | adns__qtf_mail822,
adns_r_ptr_raw = 12,
adns_r_ptr = adns_r_ptr_raw | adns__qtf_deref,
adns_r_hinfo = 13,
adns_r_mx_raw = 15,
adns_r_mx = adns_r_mx_raw | adns__qtf_deref,
adns_r_txt = 16,
adns_r_rp_raw = 17,
adns_r_rp = adns_r_rp_raw | adns__qtf_mail822,
adns_r_addr = adns_r_a | adns__qtf_deref
} adns_rrtype;
/*
* In queries without qf_quoteok_*, all domains must have standard
@ -225,123 +224,122 @@ typedef enum {
* case.
*/
typedef enum {
adns_s_ok,
typedef enum {
adns_s_ok,
/* locally induced errors */
adns_s_nomemory,
adns_s_unknownrrtype,
adns_s_systemfail,
/* locally induced errors */
adns_s_nomemory,
adns_s_unknownrrtype,
adns_s_systemfail,
adns_s_max_localfail= 29,
/* remotely induced errors, detected locally */
adns_s_timeout,
adns_s_allservfail,
adns_s_norecurse,
adns_s_invalidresponse,
adns_s_unknownformat,
adns_s_max_localfail = 29,
adns_s_max_remotefail= 59,
/* remotely induced errors, reported by remote server to us */
adns_s_rcodeservfail,
adns_s_rcodeformaterror,
adns_s_rcodenotimplemented,
adns_s_rcoderefused,
adns_s_rcodeunknown,
/* remotely induced errors, detected locally */
adns_s_timeout,
adns_s_allservfail,
adns_s_norecurse,
adns_s_invalidresponse,
adns_s_unknownformat,
adns_s_max_tempfail= 99,
adns_s_max_remotefail = 59,
/* remote configuration errors */
adns_s_inconsistent, /* PTR gives domain whose A does not exist and match */
adns_s_prohibitedcname, /* CNAME found where eg A expected (not if _qf_loosecname) */
adns_s_answerdomaininvalid,
adns_s_answerdomaintoolong,
adns_s_invaliddata,
adns_s_max_misconfig= 199,
/* remotely induced errors, reported by remote server to us */
adns_s_rcodeservfail,
adns_s_rcodeformaterror,
adns_s_rcodenotimplemented,
adns_s_rcoderefused,
adns_s_rcodeunknown,
/* permanent problems with the query */
adns_s_querydomainwrong,
adns_s_querydomaininvalid,
adns_s_querydomaintoolong,
adns_s_max_misquery= 299,
adns_s_max_tempfail = 99,
/* permanent errors */
adns_s_nxdomain,
adns_s_nodata,
/* remote configuration errors */
adns_s_inconsistent, /* PTR gives domain whose A does not exist and match */
adns_s_prohibitedcname, /* CNAME found where eg A expected (not if _qf_loosecname) */
adns_s_answerdomaininvalid,
adns_s_answerdomaintoolong,
adns_s_invaliddata,
adns_s_max_permfail= 499
} adns_status;
adns_s_max_misconfig = 199,
typedef struct {
int len;
union {
struct sockaddr sa;
struct sockaddr_in inet;
} addr;
} adns_rr_addr;
/* permanent problems with the query */
adns_s_querydomainwrong,
adns_s_querydomaininvalid,
adns_s_querydomaintoolong,
typedef struct {
char *host;
adns_status astatus;
int naddrs; /* temp fail => -1, perm fail => 0, s_ok => >0 */
adns_rr_addr *addrs;
} adns_rr_hostaddr;
adns_s_max_misquery = 299,
typedef struct {
char *(array[2]);
} adns_rr_strpair;
/* permanent errors */
adns_s_nxdomain,
adns_s_nodata,
typedef struct {
int i;
adns_rr_hostaddr ha;
} adns_rr_inthostaddr;
adns_s_max_permfail = 499
} adns_status;
typedef struct {
/* Used both for mx_raw, in which case i is the preference and str the domain,
* and for txt, in which case each entry has i for the `text' length,
* and str for the data (which will have had an extra nul appended
* so that if it was plain text it is now a null-terminated string).
*/
int i;
char *str;
} adns_rr_intstr;
typedef struct {
int len;
union {
struct sockaddr sa;
struct sockaddr_in inet;
} addr;
} adns_rr_addr;
typedef struct {
adns_rr_intstr array[2];
} adns_rr_intstrpair;
typedef struct {
char *host;
adns_status astatus;
int naddrs; /* temp fail => -1, perm fail => 0, s_ok => >0 */
adns_rr_addr *addrs;
} adns_rr_hostaddr;
typedef struct {
char *mname, *rname;
unsigned long serial, refresh, retry, expire, minimum;
} adns_rr_soa;
typedef struct {
char *(array[2]);
} adns_rr_strpair;
typedef struct {
adns_status status;
char *cname; /* always NULL if query was for CNAME records */
char *owner; /* only set if requested in query flags, and may be 0 on error anyway */
adns_rrtype type; /* guaranteed to be same as in query */
time_t expires; /* expiry time, defined only if _s_ok, nxdomain or nodata. NOT TTL! */
int nrrs, rrsz; /* nrrs is 0 if an error occurs */
union {
void *untyped;
unsigned char *bytes;
char *(*str); /* ns_raw, cname, ptr, ptr_raw */
adns_rr_intstr *(*manyistr); /* txt (list of strings ends with i=-1, str=0) */
adns_rr_addr *addr; /* addr */
struct in_addr *inaddr; /* a */
adns_rr_hostaddr *hostaddr; /* ns */
adns_rr_intstrpair *intstrpair; /* hinfo */
adns_rr_strpair *strpair; /* rp, rp_raw */
adns_rr_inthostaddr *inthostaddr; /* mx */
adns_rr_intstr *intstr; /* mx_raw */
adns_rr_soa *soa; /* soa, soa_raw */
} rrs;
} adns_answer;
typedef struct {
int i;
adns_rr_hostaddr ha;
} adns_rr_inthostaddr;
typedef struct {
/* Used both for mx_raw, in which case i is the preference and str the domain,
* and for txt, in which case each entry has i for the `text' length,
* and str for the data (which will have had an extra nul appended
* so that if it was plain text it is now a null-terminated string).
*/
int i;
char *str;
} adns_rr_intstr;
typedef struct {
adns_rr_intstr array[2];
} adns_rr_intstrpair;
typedef struct {
char *mname, *rname;
unsigned long serial, refresh, retry, expire, minimum;
} adns_rr_soa;
typedef struct {
adns_status status;
char *cname; /* always NULL if query was for CNAME records */
char *owner; /* only set if requested in query flags, and may be 0 on error anyway */
adns_rrtype type; /* guaranteed to be same as in query */
time_t expires; /* expiry time, defined only if _s_ok, nxdomain or nodata. NOT TTL! */
int nrrs, rrsz; /* nrrs is 0 if an error occurs */
union {
void *untyped;
unsigned char *bytes;
char *(*str); /* ns_raw, cname, ptr, ptr_raw */
adns_rr_intstr *(*manyistr); /* txt (list of strings ends with i=-1, str=0) */
adns_rr_addr *addr; /* addr */
struct in_addr *inaddr; /* a */
adns_rr_hostaddr *hostaddr; /* ns */
adns_rr_intstrpair *intstrpair; /* hinfo */
adns_rr_strpair *strpair; /* rp, rp_raw */
adns_rr_inthostaddr *inthostaddr; /* mx */
adns_rr_intstr *intstr; /* mx_raw */
adns_rr_soa *soa; /* soa, soa_raw */
} rrs;
} adns_answer;
/* Memory management:
* adns_state and adns_query are actually pointers to malloc'd state;
@ -376,11 +374,12 @@ typedef struct {
* requested.
*/
int adns_init(adns_state *newstate_r, adns_initflags flags,
FILE *diagfile /*0=>stderr*/);
int adns_init(adns_state * newstate_r, adns_initflags flags,
FILE * diagfile /*0=>stderr */ );
int adns_init_strcfg(adns_state *newstate_r, adns_initflags flags,
FILE *diagfile /*0=>discard*/, const char *configtext);
int adns_init_strcfg(adns_state * newstate_r, adns_initflags flags,
FILE * diagfile /*0=>discard */ ,
const char *configtext);
/* Configuration:
* adns_init reads /etc/resolv.conf, which is expected to be (broadly
@ -482,43 +481,39 @@ int adns_init_strcfg(adns_state *newstate_r, adns_initflags flags,
* line in resolv.conf.
*/
int adns_synchronous(adns_state ads,
const char *owner,
adns_rrtype type,
adns_queryflags flags,
adns_answer **answer_r);
int adns_synchronous(adns_state ads,
const char *owner,
adns_rrtype type,
adns_queryflags flags,
adns_answer ** answer_r);
/* NB: if you set adns_if_noautosys then _submit and _check do not
* make any system calls; you must use some of the asynch-io event
* processing functions to actually get things to happen.
*/
int adns_submit(adns_state ads,
const char *owner,
adns_rrtype type,
adns_queryflags flags,
void *context,
adns_query *query_r);
int adns_submit(adns_state ads,
const char *owner,
adns_rrtype type,
adns_queryflags flags,
void *context, adns_query * query_r);
/* The owner should be quoted in master file format. */
int adns_check(adns_state ads,
adns_query *query_io,
adns_answer **answer_r,
void **context_r);
int adns_check(adns_state ads,
adns_query * query_io,
adns_answer ** answer_r, void **context_r);
int adns_wait(adns_state ads,
adns_query *query_io,
adns_answer **answer_r,
void **context_r);
int adns_wait(adns_state ads,
adns_query * query_io,
adns_answer ** answer_r, void **context_r);
/* same as adns_wait but uses poll(2) internally */
int adns_wait_poll(adns_state ads,
adns_query *query_io,
adns_answer **answer_r,
void **context_r);
int adns_wait_poll(adns_state ads,
adns_query * query_io,
adns_answer ** answer_r, void **context_r);
void adns_cancel(adns_query query);
void adns_cancel(adns_query query);
/* The adns_query you get back from _submit is valid (ie, can be
* legitimately passed into adns functions) until it is returned by
@ -532,37 +527,36 @@ void adns_cancel(adns_query query);
* query type.
*/
int adns_submit_reverse(adns_state ads,
const struct sockaddr *addr,
adns_rrtype type,
adns_queryflags flags,
void *context,
adns_query *query_r);
int adns_submit_reverse(adns_state ads,
const struct sockaddr *addr,
adns_rrtype type,
adns_queryflags flags,
void *context, adns_query * query_r);
/* type must be _r_ptr or _r_ptr_raw. _qf_search is ignored.
* addr->sa_family must be AF_INET or you get ENOSYS.
*/
int adns_submit_reverse_any(adns_state ads,
const struct sockaddr *addr,
const char *rzone,
adns_rrtype type,
adns_queryflags flags,
void *context,
adns_query *query_r);
int adns_submit_reverse_any(adns_state ads,
const struct sockaddr *addr,
const char *rzone,
adns_rrtype type,
adns_queryflags flags,
void *context, adns_query * query_r);
/* For RBL-style reverse `zone's; look up
* <reversed-address>.<zone>
* Any type is allowed. _qf_search is ignored.
* addr->sa_family must be AF_INET or you get ENOSYS.
*/
void adns_finish(adns_state ads);
void adns_finish(adns_state ads);
/* You may call this even if you have queries outstanding;
* they will be cancelled.
*/
void adns_forallqueries_begin(adns_state ads);
adns_query adns_forallqueries_next(adns_state ads, void **context_r);
void adns_forallqueries_begin(adns_state ads);
adns_query adns_forallqueries_next(adns_state ads,
void **context_r);
/* Iterator functions, which you can use to loop over the outstanding
* (submitted but not yet successfuly checked/waited) queries.
*
@ -578,7 +572,7 @@ adns_query adns_forallqueries_next(adns_state ads, void **context_r);
* context_r may be 0. *context_r may not be set when _next returns 0.
*/
void adns_checkconsistency(adns_state ads, adns_query qu);
void adns_checkconsistency(adns_state ads, adns_query qu);
/* Checks the consistency of adns's internal data structures.
* If any error is found, the program will abort().
* You may pass 0 for qu; if you pass non-null then additional checks
@ -610,16 +604,19 @@ void adns_checkconsistency(adns_state ads, adns_query qu);
* blocking, or you may not have an up-to-date list of it's fds.
*/
int adns_processany(adns_state ads);
int adns_processany(adns_state ads);
/* Gives adns flow-of-control for a bit. This will never block, and
* can be used with any threading/asynch-io model. If some error
* occurred which might cause an event loop to spin then the errno
* value is returned.
*/
int adns_processreadable(adns_state ads, int fd, const struct timeval *now);
int adns_processwriteable(adns_state ads, int fd, const struct timeval *now);
int adns_processexceptional(adns_state ads, int fd, const struct timeval *now);
int adns_processreadable(adns_state ads, int fd,
const struct timeval *now);
int adns_processwriteable(adns_state ads, int fd,
const struct timeval *now);
int adns_processexceptional(adns_state ads, int fd,
const struct timeval *now);
/* Gives adns flow-of-control so that it can process incoming data
* from, or send outgoing data via, fd. Very like _processany. If it
* returns zero then fd will no longer be readable or writeable
@ -638,7 +635,8 @@ int adns_processexceptional(adns_state ads, int fd, const struct timeval *now);
* then the errno value is returned.
*/
void adns_processtimeouts(adns_state ads, const struct timeval *now);
void adns_processtimeouts(adns_state ads,
const struct timeval *now);
/* Gives adns flow-of-control so that it can process any timeouts
* which might have happened. Very like _processreadable/writeable.
*
@ -646,9 +644,9 @@ void adns_processtimeouts(adns_state ads, const struct timeval *now);
* obtained from gettimeofday.
*/
void adns_firsttimeout(adns_state ads,
struct timeval **tv_mod, struct timeval *tv_buf,
struct timeval now);
void adns_firsttimeout(adns_state ads,
struct timeval **tv_mod,
struct timeval *tv_buf, struct timeval now);
/* Asks adns when it would first like the opportunity to time
* something out. now must be the current time, from gettimeofday.
*
@ -665,7 +663,7 @@ void adns_firsttimeout(adns_state ads,
* is using. It always succeeds and never blocks.
*/
void adns_globalsystemfailure(adns_state ads);
void adns_globalsystemfailure(adns_state ads);
/* If serious problem(s) happen which globally affect your ability to
* interact properly with adns, or adns's ability to function
* properly, you or adns can call this function.
@ -684,10 +682,11 @@ void adns_globalsystemfailure(adns_state ads);
* Entrypoints for select-loop based asynch io:
*/
void adns_beforeselect(adns_state ads, int *maxfd, fd_set *readfds,
fd_set *writefds, fd_set *exceptfds,
struct timeval **tv_mod, struct timeval *tv_buf,
const struct timeval *now);
void adns_beforeselect(adns_state ads, int *maxfd,
fd_set * readfds, fd_set * writefds,
fd_set * exceptfds, struct timeval **tv_mod,
struct timeval *tv_buf,
const struct timeval *now);
/* Find out file descriptors adns is interested in, and when it would
* like the opportunity to time something out. If you do not plan to
* block then tv_mod may be 0. Otherwise, tv_mod and tv_buf are as
@ -700,9 +699,11 @@ void adns_beforeselect(adns_state ads, int *maxfd, fd_set *readfds,
* finishes in _beforeselect.
*/
void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
const fd_set *writefds, const fd_set *exceptfds,
const struct timeval *now);
void adns_afterselect(adns_state ads, int maxfd,
const fd_set * readfds,
const fd_set * writefds,
const fd_set * exceptfds,
const struct timeval *now);
/* Gives adns flow-of-control for a bit; intended for use after
* select. This is just a fancy way of calling adns_processreadable/
* writeable/timeouts as appropriate, as if select had returned the
@ -727,15 +728,16 @@ void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds,
* Entrypoints for poll-loop based asynch io:
*/
struct pollfd;
struct pollfd;
/* In case your system doesn't have it or you forgot to include
* <sys/poll.h>, to stop the following declarations from causing
* problems. If your system doesn't have poll then the following
* entrypoints will not be defined in libadns. Sorry !
*/
int adns_beforepoll(adns_state ads, struct pollfd *fds, int *nfds_io, int *timeout_io,
const struct timeval *now);
int adns_beforepoll(adns_state ads, struct pollfd *fds,
int *nfds_io, int *timeout_io,
const struct timeval *now);
/* Finds out which fd's adns is interested in, and when it would like
* to be able to time things out. This is in a form suitable for use
* with poll(2).
@ -786,18 +788,18 @@ int adns_beforepoll(adns_state ads, struct pollfd *fds, int *nfds_io, int *timeo
* require more space than this.
*/
void adns_afterpoll(adns_state ads, const struct pollfd *fds, int nfds,
const struct timeval *now);
void adns_afterpoll(adns_state ads, const struct pollfd *fds,
int nfds, const struct timeval *now);
/* Gives adns flow-of-control for a bit; intended for use after
* poll(2). fds and nfds should be the results from poll(). pollfd
* structs mentioning fds not belonging to adns will be ignored.
*/
adns_status adns_rr_info(adns_rrtype type,
const char **rrtname_r, const char **fmtname_r,
int *len_r,
const void *datap, char **data_r);
adns_status adns_rr_info(adns_rrtype type,
const char **rrtname_r,
const char **fmtname_r, int *len_r,
const void *datap, char **data_r);
/*
* Get information about a query type, or convert reply data to a
* textual form. type must be specified, and the official name of the
@ -854,9 +856,9 @@ adns_status adns_rr_info(adns_rrtype type,
* dns2.spong.dyn.ml.org timeout "DNS query timed out" ?
*/
const char *adns_strerror(adns_status st);
const char *adns_errabbrev(adns_status st);
const char *adns_errtypeabbrev(adns_status st);
const char *adns_strerror(adns_status st);
const char *adns_errabbrev(adns_status st);
const char *adns_errtypeabbrev(adns_status st);
/* Like strerror but for adns_status values. adns_errabbrev returns
* the abbreviation of the error - eg, for adns_s_timeout it returns
* "timeout". adns_errtypeabbrev returns the abbreviation of the
@ -866,6 +868,6 @@ const char *adns_errtypeabbrev(adns_status st);
*/
#ifdef __cplusplus
} /* end of extern "C" */
} /* end of extern "C" */
#endif
#endif

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: check.c,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
** $Id: check.c,v 1.3 2003/06/13 14:44:35 fishwaldo Exp $
*/
/*
* check.c
@ -49,8 +49,9 @@
#include "internal.h"
#include <stdlib.h>
void adns_checkconsistency(adns_state ads, adns_query qu) {
adns__consistency(ads,qu,cc_user);
void adns_checkconsistency(adns_state ads, adns_query qu)
{
adns__consistency(ads, qu, cc_user);
}
#define DLIST_CHECK(list, nodevar, part, body) \
@ -73,149 +74,158 @@ void adns_checkconsistency(adns_state ads, adns_query qu) {
} \
} while(0)
static void checkc_query_alloc(adns_state ads, adns_query qu) {
allocnode *an;
static void checkc_query_alloc(adns_state ads, adns_query qu)
{
allocnode *an;
DLIST_CHECK(qu->allocations, an, , {
});
DLIST_CHECK(qu->allocations, an,, {
});
}
static void checkc_query(adns_state ads, adns_query qu) {
adns_query child;
static void checkc_query(adns_state ads, adns_query qu)
{
adns_query child;
assert(qu->udpnextserver < ads->nservers);
assert(!(qu->udpsent & (~0UL << ads->nservers)));
assert(qu->search_pos <= ads->nsearchlist);
if (qu->parent) DLIST_ASSERTON(qu, child, qu->parent->children, siblings.);
assert(qu->udpnextserver < ads->nservers);
assert(!(qu->udpsent & (~0UL << ads->nservers)));
assert(qu->search_pos <= ads->nsearchlist);
if (qu->parent)
DLIST_ASSERTON(qu, child, qu->parent->children, siblings.);
}
static void checkc_notcpbuf(adns_state ads) {
assert(!ads->tcpsend.used);
assert(!ads->tcprecv.used);
assert(!ads->tcprecv_skip);
static void checkc_notcpbuf(adns_state ads)
{
assert(!ads->tcpsend.used);
assert(!ads->tcprecv.used);
assert(!ads->tcprecv_skip);
}
static void checkc_global(adns_state ads) {
int i;
assert(ads->udpsocket >= 0);
static void checkc_global(adns_state ads)
{
int i;
for (i=0; i<ads->nsortlist; i++)
assert(!(ads->sortlist[i].base.s_addr & ~ads->sortlist[i].mask.s_addr));
assert(ads->udpsocket >= 0);
assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers);
switch (ads->tcpstate) {
case server_connecting:
assert(ads->tcpsocket >= 0);
checkc_notcpbuf(ads);
break;
case server_disconnected:
case server_broken:
assert(ads->tcpsocket == -1);
checkc_notcpbuf(ads);
break;
case server_ok:
assert(ads->tcpsocket >= 0);
assert(ads->tcprecv_skip <= ads->tcprecv.used);
break;
default:
assert(!"ads->tcpstate value");
}
for (i = 0; i < ads->nsortlist; i++)
assert(!
(ads->sortlist[i].base.s_addr & ~ads->sortlist[i].
mask.s_addr));
assert(ads->searchlist || !ads->nsearchlist);
assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers);
switch (ads->tcpstate) {
case server_connecting:
assert(ads->tcpsocket >= 0);
checkc_notcpbuf(ads);
break;
case server_disconnected:
case server_broken:
assert(ads->tcpsocket == -1);
checkc_notcpbuf(ads);
break;
case server_ok:
assert(ads->tcpsocket >= 0);
assert(ads->tcprecv_skip <= ads->tcprecv.used);
break;
default:
assert(!"ads->tcpstate value");
}
assert(ads->searchlist || !ads->nsearchlist);
}
static void checkc_queue_udpw(adns_state ads) {
adns_query qu;
DLIST_CHECK(ads->udpw, qu, , {
assert(qu->state==query_tosend);
assert(qu->retries <= UDPMAXRETRIES);
assert(qu->udpsent);
assert(!qu->children.head && !qu->children.tail);
checkc_query(ads,qu);
checkc_query_alloc(ads,qu);
});
static void checkc_queue_udpw(adns_state ads)
{
adns_query qu;
DLIST_CHECK(ads->udpw, qu,, {
assert(qu->state == query_tosend);
assert(qu->retries <= UDPMAXRETRIES);
assert(qu->udpsent);
assert(!qu->children.head && !qu->children.tail);
checkc_query(ads, qu); checkc_query_alloc(ads, qu);});
}
static void checkc_queue_tcpw(adns_state ads) {
adns_query qu;
DLIST_CHECK(ads->tcpw, qu, , {
assert(qu->state==query_tcpw);
assert(!qu->children.head && !qu->children.tail);
assert(qu->retries <= ads->nservers+1);
checkc_query(ads,qu);
checkc_query_alloc(ads,qu);
});
static void checkc_queue_tcpw(adns_state ads)
{
adns_query qu;
DLIST_CHECK(ads->tcpw, qu,, {
assert(qu->state == query_tcpw);
assert(!qu->children.head && !qu->children.tail);
assert(qu->retries <= ads->nservers + 1);
checkc_query(ads, qu); checkc_query_alloc(ads, qu);});
}
static void checkc_queue_childw(adns_state ads) {
adns_query parent, child;
static void checkc_queue_childw(adns_state ads)
{
adns_query parent, child;
DLIST_CHECK(ads->childw, parent, , {
assert(parent->state == query_childw);
assert(parent->children.head);
DLIST_CHECK(parent->children, child, siblings., {
assert(child->parent == parent);
assert(child->state != query_done);
});
checkc_query(ads,parent);
checkc_query_alloc(ads,parent);
});
DLIST_CHECK(ads->childw, parent,, {
assert(parent->state == query_childw);
assert(parent->children.head);
DLIST_CHECK(parent->children, child, siblings., {
assert(child->parent == parent);
assert(child->state != query_done);});
checkc_query(ads, parent);
checkc_query_alloc(ads, parent);});
}
static void checkc_queue_output(adns_state ads) {
adns_query qu;
DLIST_CHECK(ads->output, qu, , {
assert(qu->state == query_done);
assert(!qu->children.head && !qu->children.tail);
assert(!qu->parent);
assert(!qu->allocations.head && !qu->allocations.tail);
checkc_query(ads,qu);
});
static void checkc_queue_output(adns_state ads)
{
adns_query qu;
DLIST_CHECK(ads->output, qu,, {
assert(qu->state == query_done);
assert(!qu->children.head && !qu->children.tail);
assert(!qu->parent);
assert(!qu->allocations.head && !qu->allocations.tail);
checkc_query(ads, qu);});
}
void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc) {
adns_query search;
switch (cc) {
case cc_user:
break;
case cc_entex:
if (!(ads->iflags & adns_if_checkc_entex)) return;
break;
case cc_freq:
if ((ads->iflags & adns_if_checkc_freq) != adns_if_checkc_freq) return;
break;
default:
abort();
}
void adns__consistency(adns_state ads, adns_query qu,
consistency_checks cc)
{
adns_query search;
checkc_global(ads);
checkc_queue_udpw(ads);
checkc_queue_tcpw(ads);
checkc_queue_childw(ads);
checkc_queue_output(ads);
switch (cc) {
case cc_user:
break;
case cc_entex:
if (!(ads->iflags & adns_if_checkc_entex))
return;
break;
case cc_freq:
if ((ads->iflags & adns_if_checkc_freq) !=
adns_if_checkc_freq)
return;
break;
default:
abort();
}
if (qu) {
switch (qu->state) {
case query_tosend:
DLIST_ASSERTON(qu, search, ads->udpw, );
break;
case query_tcpw:
DLIST_ASSERTON(qu, search, ads->tcpw, );
break;
case query_childw:
DLIST_ASSERTON(qu, search, ads->childw, );
break;
case query_done:
DLIST_ASSERTON(qu, search, ads->output, );
break;
default:
assert(!"specific query state");
}
}
checkc_global(ads);
checkc_queue_udpw(ads);
checkc_queue_tcpw(ads);
checkc_queue_childw(ads);
checkc_queue_output(ads);
if (qu) {
switch (qu->state) {
case query_tosend:
DLIST_ASSERTON(qu, search, ads->udpw,);
break;
case query_tcpw:
DLIST_ASSERTON(qu, search, ads->tcpw,);
break;
case query_childw:
DLIST_ASSERTON(qu, search, ads->childw,);
break;
case query_done:
DLIST_ASSERTON(qu, search, ads->output,);
break;
default:
assert(!"specific query state");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: general.c,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
** $Id: general.c,v 1.3 2003/06/13 14:44:36 fishwaldo Exp $
*/
/*
* general.c
@ -61,322 +61,385 @@
/* Core diagnostic functions */
void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
int serv, adns_query qu, const char *fmt, va_list al) {
const char *bef, *aft;
vbuf vb;
if (!ads->diagfile ||
(!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))))
return;
int serv, adns_query qu, const char *fmt, va_list al)
{
const char *bef, *aft;
vbuf vb;
if (ads->iflags & adns_if_logpid) {
fprintf(ads->diagfile,"adns%s [%ld]: ",pfx,(long)getpid());
} else {
fprintf(ads->diagfile,"adns%s: ",pfx);
}
if (!ads->diagfile ||
(!(ads->iflags & adns_if_debug)
&& (!prevent || (ads->iflags & prevent))))
return;
vfprintf(ads->diagfile,fmt,al);
if (ads->iflags & adns_if_logpid) {
fprintf(ads->diagfile, "adns%s [%ld]: ", pfx,
(long) getpid());
} else {
fprintf(ads->diagfile, "adns%s: ", pfx);
}
bef= " (";
aft= "\n";
vfprintf(ads->diagfile, fmt, al);
if (qu && qu->query_dgram) {
adns__vbuf_init(&vb);
fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
bef,
adns__diag_domain(qu->ads,-1,0, &vb,
qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
qu->typei ? qu->typei->rrtname : "<unknown>");
if (qu->typei && qu->typei->fmtname)
fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
bef=", "; aft=")\n";
adns__vbuf_free(&vb);
}
if (serv>=0) {
fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
bef=", "; aft=")\n";
}
bef = " (";
aft = "\n";
fputs(aft,ads->diagfile);
if (qu && qu->query_dgram) {
adns__vbuf_init(&vb);
fprintf(ads->diagfile, "%sQNAME=%s, QTYPE=%s",
bef,
adns__diag_domain(qu->ads, -1, 0, &vb,
qu->query_dgram, qu->query_dglen,
DNS_HDRSIZE),
qu->typei ? qu->typei->rrtname : "<unknown>");
if (qu->typei && qu->typei->fmtname)
fprintf(ads->diagfile, "(%s)", qu->typei->fmtname);
bef = ", ";
aft = ")\n";
adns__vbuf_free(&vb);
}
if (serv >= 0) {
fprintf(ads->diagfile, "%sNS=%s", bef,
inet_ntoa(ads->servers[serv].addr));
bef = ", ";
aft = ")\n";
}
fputs(aft, ads->diagfile);
}
void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
va_list al;
void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt,
...)
{
va_list al;
va_start(al,fmt);
adns__vdiag(ads," debug",0,serv,qu,fmt,al);
va_end(al);
va_start(al, fmt);
adns__vdiag(ads, " debug", 0, serv, qu, fmt, al);
va_end(al);
}
void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
va_list al;
void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt,
...)
{
va_list al;
va_start(al,fmt);
adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
va_end(al);
va_start(al, fmt);
adns__vdiag(ads, " warning",
adns_if_noerrprint | adns_if_noserverwarn, serv, qu,
fmt, al);
va_end(al);
}
void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
va_list al;
void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt,
...)
{
va_list al;
va_start(al,fmt);
adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
va_end(al);
va_start(al, fmt);
adns__vdiag(ads, "", adns_if_noerrprint, serv, qu, fmt, al);
va_end(al);
}
/* vbuf functions */
void adns__vbuf_init(vbuf *vb) {
vb->used= vb->avail= 0; vb->buf= 0;
void adns__vbuf_init(vbuf * vb)
{
vb->used = vb->avail = 0;
vb->buf = 0;
}
int adns__vbuf_ensure(vbuf *vb, int want) {
void *nb;
if (vb->avail >= want) return 1;
nb= realloc(vb->buf,want); if (!nb) return 0;
vb->buf= nb;
vb->avail= want;
return 1;
}
void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
memcpy(vb->buf+vb->used,data,len);
vb->used+= len;
int adns__vbuf_ensure(vbuf * vb, int want)
{
void *nb;
if (vb->avail >= want)
return 1;
nb = realloc(vb->buf, want);
if (!nb)
return 0;
vb->buf = nb;
vb->avail = want;
return 1;
}
int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
int newlen;
void *nb;
newlen= vb->used+len;
if (vb->avail < newlen) {
if (newlen<20) newlen= 20;
newlen <<= 1;
nb= realloc(vb->buf,newlen);
if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
if (!nb) return 0;
vb->buf= nb;
vb->avail= newlen;
}
adns__vbuf_appendq(vb,data,len);
return 1;
void adns__vbuf_appendq(vbuf * vb, const byte * data, int len)
{
memcpy(vb->buf + vb->used, data, len);
vb->used += len;
}
int adns__vbuf_appendstr(vbuf *vb, const char *data) {
int l;
l= strlen(data);
return adns__vbuf_append(vb,data,l);
int adns__vbuf_append(vbuf * vb, const byte * data, int len)
{
int newlen;
void *nb;
newlen = vb->used + len;
if (vb->avail < newlen) {
if (newlen < 20)
newlen = 20;
newlen <<= 1;
nb = realloc(vb->buf, newlen);
if (!nb) {
newlen = vb->used + len;
nb = realloc(vb->buf, newlen);
}
if (!nb)
return 0;
vb->buf = nb;
vb->avail = newlen;
}
adns__vbuf_appendq(vb, data, len);
return 1;
}
void adns__vbuf_free(vbuf *vb) {
free(vb->buf);
adns__vbuf_init(vb);
int adns__vbuf_appendstr(vbuf * vb, const char *data)
{
int l;
l = strlen(data);
return adns__vbuf_append(vb, data, l);
}
void adns__vbuf_free(vbuf * vb)
{
free(vb->buf);
adns__vbuf_init(vb);
}
/* Additional diagnostic functions */
const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
vbuf *vb, const byte *dgram, int dglen, int cbyte) {
adns_status st;
vbuf * vb, const byte * dgram, int dglen,
int cbyte)
{
adns_status st;
st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
if (st == adns_s_nomemory) {
return "<cannot report domain... out of memory>";
}
if (st) {
vb->used= 0;
if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
adns__vbuf_appendstr(vb,adns_strerror(st)) &&
adns__vbuf_appendstr(vb,">") &&
adns__vbuf_append(vb,"",1))) {
return "<cannot report bad format... out of memory>";
}
}
if (!vb->used) {
adns__vbuf_appendstr(vb,"<truncated ...>");
adns__vbuf_append(vb,"",1);
}
return vb->buf;
st = adns__parse_domain(ads, serv, qu, vb, pdf_quoteok, dgram,
dglen, &cbyte, dglen);
if (st == adns_s_nomemory) {
return "<cannot report domain... out of memory>";
}
if (st) {
vb->used = 0;
if (!(adns__vbuf_appendstr(vb, "<bad format... ") &&
adns__vbuf_appendstr(vb, adns_strerror(st)) &&
adns__vbuf_appendstr(vb, ">") &&
adns__vbuf_append(vb, "", 1))) {
return
"<cannot report bad format... out of memory>";
}
}
if (!vb->used) {
adns__vbuf_appendstr(vb, "<truncated ...>");
adns__vbuf_append(vb, "", 1);
}
return vb->buf;
}
adns_status adns_rr_info(adns_rrtype type,
const char **rrtname_r, const char **fmtname_r,
int *len_r,
const void *datap, char **data_r) {
const typeinfo *typei;
vbuf vb;
adns_status st;
int *len_r, const void *datap, char **data_r)
{
const typeinfo *typei;
vbuf vb;
adns_status st;
typei= adns__findtype(type);
if (!typei) return adns_s_unknownrrtype;
typei = adns__findtype(type);
if (!typei)
return adns_s_unknownrrtype;
if (rrtname_r) *rrtname_r= typei->rrtname;
if (fmtname_r) *fmtname_r= typei->fmtname;
if (len_r) *len_r= typei->rrsz;
if (rrtname_r)
*rrtname_r = typei->rrtname;
if (fmtname_r)
*fmtname_r = typei->fmtname;
if (len_r)
*len_r = typei->rrsz;
if (!datap) return adns_s_ok;
adns__vbuf_init(&vb);
st= typei->convstring(&vb,datap);
if (st) goto x_freevb;
if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
assert(strlen(vb.buf) == vb.used-1);
*data_r= realloc(vb.buf,vb.used);
if (!*data_r) *data_r= vb.buf;
return adns_s_ok;
if (!datap)
return adns_s_ok;
x_freevb:
adns__vbuf_free(&vb);
return st;
adns__vbuf_init(&vb);
st = typei->convstring(&vb, datap);
if (st)
goto x_freevb;
if (!adns__vbuf_append(&vb, "", 1)) {
st = adns_s_nomemory;
goto x_freevb;
}
assert(strlen(vb.buf) == vb.used - 1);
*data_r = realloc(vb.buf, vb.used);
if (!*data_r)
*data_r = vb.buf;
return adns_s_ok;
x_freevb:
adns__vbuf_free(&vb);
return st;
}
#define SINFO(n,s) { adns_s_##n, #n, s }
static const struct sinfo {
adns_status st;
const char *abbrev;
const char *string;
} sinfos[]= {
SINFO( ok, "OK" ),
SINFO( nomemory, "Out of memory" ),
SINFO( unknownrrtype, "Query not implemented in DNS library" ),
SINFO( systemfail, "General resolver or system failure" ),
SINFO( timeout, "DNS query timed out" ),
SINFO( allservfail, "All nameservers failed" ),
SINFO( norecurse, "Recursion denied by nameserver" ),
SINFO( invalidresponse, "Nameserver sent bad response" ),
SINFO( unknownformat, "Nameserver used unknown format" ),
SINFO( rcodeservfail, "Nameserver reports failure" ),
SINFO( rcodeformaterror, "Query not understood by nameserver" ),
SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
SINFO( rcoderefused, "Query refused by nameserver" ),
SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
SINFO( inconsistent, "Inconsistent resource records in DNS" ),
SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
SINFO( answerdomaintoolong, "Found overly-long domain name" ),
SINFO( invaliddata, "Found invalid DNS data" ),
SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
SINFO( querydomaintoolong, "Domain name or component is too long" ),
SINFO( nxdomain, "No such domain" ),
SINFO( nodata, "No such data" )
adns_status st;
const char *abbrev;
const char *string;
} sinfos[] = {
SINFO(ok, "OK"),
SINFO(nomemory, "Out of memory"),
SINFO(unknownrrtype, "Query not implemented in DNS library"),
SINFO(systemfail, "General resolver or system failure"),
SINFO(timeout, "DNS query timed out"),
SINFO(allservfail, "All nameservers failed"),
SINFO(norecurse, "Recursion denied by nameserver"),
SINFO(invalidresponse, "Nameserver sent bad response"),
SINFO(unknownformat, "Nameserver used unknown format"),
SINFO(rcodeservfail, "Nameserver reports failure"),
SINFO(rcodeformaterror, "Query not understood by nameserver"),
SINFO(rcodenotimplemented,
"Query not implemented by nameserver"),
SINFO(rcoderefused, "Query refused by nameserver"),
SINFO(rcodeunknown, "Nameserver sent unknown response code"),
SINFO(inconsistent, "Inconsistent resource records in DNS"),
SINFO(prohibitedcname,
"DNS alias found where canonical name wanted"),
SINFO(answerdomaininvalid,
"Found syntactically invalid domain name"),
SINFO(answerdomaintoolong, "Found overly-long domain name"),
SINFO(invaliddata, "Found invalid DNS data"),
SINFO(querydomainwrong,
"Domain invalid for particular DNS query type"),
SINFO(querydomaininvalid,
"Domain name is syntactically invalid"),
SINFO(querydomaintoolong,
"Domain name or component is too long"), SINFO(nxdomain,
"No such domain"),
SINFO(nodata, "No such data")
};
static int si_compar(const void *key, const void *elem) {
const adns_status *st= key;
const struct sinfo *si= elem;
static int si_compar(const void *key, const void *elem)
{
const adns_status *st = key;
const struct sinfo *si = elem;
return *st < si->st ? -1 : *st > si->st ? 1 : 0;
return *st < si->st ? -1 : *st > si->st ? 1 : 0;
}
static const struct sinfo *findsinfo(adns_status st) {
return bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*sinfos),sizeof(*sinfos),si_compar);
static const struct sinfo *findsinfo(adns_status st)
{
return bsearch(&st, sinfos, sizeof(sinfos) / sizeof(*sinfos),
sizeof(*sinfos), si_compar);
}
const char *adns_strerror(adns_status st) {
const struct sinfo *si;
const char *adns_strerror(adns_status st)
{
const struct sinfo *si;
si= findsinfo(st);
return si->string;
si = findsinfo(st);
return si->string;
}
const char *adns_errabbrev(adns_status st) {
const struct sinfo *si;
const char *adns_errabbrev(adns_status st)
{
const struct sinfo *si;
si= findsinfo(st);
return si->abbrev;
si = findsinfo(st);
return si->abbrev;
}
#define STINFO(max) { adns_s_max_##max, #max }
static const struct stinfo {
adns_status stmax;
const char *abbrev;
} stinfos[]= {
{ adns_s_ok, "ok" },
STINFO( localfail ),
STINFO( remotefail ),
STINFO( tempfail ),
STINFO( misconfig ),
STINFO( misquery ),
STINFO( permfail )
adns_status stmax;
const char *abbrev;
} stinfos[] = {
{
adns_s_ok, "ok"},
STINFO(localfail),
STINFO(remotefail),
STINFO(tempfail),
STINFO(misconfig), STINFO(misquery), STINFO(permfail)
};
static int sti_compar(const void *key, const void *elem) {
const adns_status *st= key;
const struct stinfo *sti= elem;
static int sti_compar(const void *key, const void *elem)
{
const adns_status *st = key;
const struct stinfo *sti = elem;
adns_status here, min, max;
adns_status here, min, max;
here= *st;
min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
max= sti->stmax;
return here < min ? -1 : here > max ? 1 : 0;
here = *st;
min = (sti == stinfos) ? 0 : sti[-1].stmax + 1;
max = sti->stmax;
return here < min ? -1 : here > max ? 1 : 0;
}
const char *adns_errtypeabbrev(adns_status st) {
const struct stinfo *sti;
const char *adns_errtypeabbrev(adns_status st)
{
const struct stinfo *sti;
sti= bsearch(&st,stinfos,sizeof(stinfos)/sizeof(*stinfos),sizeof(*stinfos),sti_compar);
return sti->abbrev;
sti =
bsearch(&st, stinfos, sizeof(stinfos) / sizeof(*stinfos),
sizeof(*stinfos), sti_compar);
return sti->abbrev;
}
void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
int (*needswap)(void *context, const void *a, const void *b),
void *context) {
byte *data= array;
int i, place;
int (*needswap) (void *context, const void *a,
const void *b), void *context)
{
byte *data = array;
int i, place;
for (i=0; i<nobjs; i++) {
for (place= i;
place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
place--);
if (place != i) {
memcpy(tempbuf, data + i*sz, sz);
memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
memcpy(data + place*sz, tempbuf, sz);
}
}
for (i = 0; i < nobjs; i++) {
for (place = i;
place > 0
&& needswap(context, data + (place - 1) * sz,
data + i * sz); place--);
if (place != i) {
memcpy(tempbuf, data + i * sz, sz);
memmove(data + (place + 1) * sz, data + place * sz,
(i - place) * sz);
memcpy(data + place * sz, tempbuf, sz);
}
}
}
/* SIGPIPE protection. */
void adns__sigpipe_protect(adns_state ads) {
sigset_t toblock;
struct sigaction sa;
int r;
void adns__sigpipe_protect(adns_state ads)
{
sigset_t toblock;
struct sigaction sa;
int r;
if (ads->iflags & adns_if_nosigpipe) return;
if (ads->iflags & adns_if_nosigpipe)
return;
sigfillset(&toblock);
sigdelset(&toblock,SIGPIPE);
sigfillset(&toblock);
sigdelset(&toblock, SIGPIPE);
sa.sa_handler= SIG_IGN;
sigfillset(&sa.sa_mask);
sa.sa_flags= 0;
r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
sa.sa_handler = SIG_IGN;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0;
r = sigprocmask(SIG_SETMASK, &toblock, &ads->stdsigmask);
assert(!r);
r = sigaction(SIGPIPE, &sa, &ads->stdsigpipe);
assert(!r);
}
void adns__sigpipe_unprotect(adns_state ads) {
int r;
void adns__sigpipe_unprotect(adns_state ads)
{
int r;
if (ads->iflags & adns_if_nosigpipe) return;
if (ads->iflags & adns_if_nosigpipe)
return;
r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
r = sigaction(SIGPIPE, &ads->stdsigpipe, 0);
assert(!r);
r = sigprocmask(SIG_SETMASK, &ads->stdsigmask, 0);
assert(!r);
}

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: internal.h,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
** $Id: internal.h,v 1.3 2003/06/13 14:44:36 fishwaldo Exp $
*/
/*
* internal.h
@ -80,7 +80,7 @@ typedef unsigned char byte;
#define TCPWAITMS 30000
#define TCPCONNMS 14000
#define TCPIDLEMS 30000
#define MAXTTLBELIEVE (7*86400) /* any TTL > 7 days is capped */
#define MAXTTLBELIEVE (7*86400) /* any TTL > 7 days is capped */
#define DNS_PORT 53
#define DNS_MAXUDP 512
@ -95,246 +95,257 @@ typedef unsigned char byte;
#define MAX_POLLFDS ADNS_POLLFDS_RECOMMENDED
typedef enum {
cc_user,
cc_entex,
cc_freq
cc_user,
cc_entex,
cc_freq
} consistency_checks;
typedef enum {
rcode_noerror,
rcode_formaterror,
rcode_servfail,
rcode_nxdomain,
rcode_notimp,
rcode_refused
rcode_noerror,
rcode_formaterror,
rcode_servfail,
rcode_nxdomain,
rcode_notimp,
rcode_refused
} dns_rcode;
/* Shared data structures */
typedef union {
adns_status status;
char *cp;
adns_rrtype type;
int i;
struct in_addr ia;
unsigned long ul;
adns_status status;
char *cp;
adns_rrtype type;
int i;
struct in_addr ia;
unsigned long ul;
} rr_align;
typedef struct {
int used, avail;
byte *buf;
int used, avail;
byte *buf;
} vbuf;
typedef struct {
adns_state ads;
adns_query qu;
int serv;
const byte *dgram;
int dglen, nsstart, nscount, arcount;
struct timeval now;
adns_state ads;
adns_query qu;
int serv;
const byte *dgram;
int dglen, nsstart, nscount, arcount;
struct timeval now;
} parseinfo;
typedef struct {
adns_rrtype type;
const char *rrtname;
const char *fmtname;
int rrsz;
adns_rrtype type;
const char *rrtname;
const char *fmtname;
int rrsz;
void (*makefinal)(adns_query qu, void *data);
/* Change memory management of *data.
* Previously, used alloc_interim, now use alloc_final.
*/
void (*makefinal) (adns_query qu, void *data);
/* Change memory management of *data.
* Previously, used alloc_interim, now use alloc_final.
*/
adns_status (*convstring)(vbuf *vb, const void *data);
/* Converts the RR data to a string representation in vbuf.
* vbuf will be appended to (it must have been initialised),
* and will not be null-terminated by convstring.
*/
adns_status(*convstring) (vbuf * vb, const void *data);
/* Converts the RR data to a string representation in vbuf.
* vbuf will be appended to (it must have been initialised),
* and will not be null-terminated by convstring.
*/
adns_status (*parse)(const parseinfo *pai, int cbyte, int max, void *store_r);
/* Parse one RR, in dgram of length dglen, starting at cbyte and
* extending until at most max.
*
* The RR should be stored at *store_r, of length qu->typei->rrsz.
*
* If there is an overrun which might indicate truncation, it should set
* *rdstart to -1; otherwise it may set it to anything else positive.
*
* nsstart is the offset of the authority section.
*/
adns_status(*parse) (const parseinfo * pai, int cbyte, int max,
void *store_r);
/* Parse one RR, in dgram of length dglen, starting at cbyte and
* extending until at most max.
*
* The RR should be stored at *store_r, of length qu->typei->rrsz.
*
* If there is an overrun which might indicate truncation, it should set
* *rdstart to -1; otherwise it may set it to anything else positive.
*
* nsstart is the offset of the authority section.
*/
int (*diff_needswap)(adns_state ads, const void *datap_a, const void *datap_b);
/* Returns !0 if RR a should be strictly after RR b in the sort order,
* 0 otherwise. Must not fail.
*/
int (*diff_needswap) (adns_state ads, const void *datap_a,
const void *datap_b);
/* Returns !0 if RR a should be strictly after RR b in the sort order,
* 0 otherwise. Must not fail.
*/
} typeinfo;
typedef struct allocnode {
struct allocnode *next, *back;
struct allocnode *next, *back;
} allocnode;
union maxalign {
byte d[1];
struct in_addr ia;
long l;
void *p;
void (*fp)(void);
union maxalign *up;
byte d[1];
struct in_addr ia;
long l;
void *p;
void (*fp) (void);
union maxalign *up;
} data;
typedef struct {
void *ext;
void (*callback)(adns_query parent, adns_query child);
union {
adns_rr_addr ptr_parent_addr;
adns_rr_hostaddr *hostaddr;
} info;
void *ext;
void (*callback) (adns_query parent, adns_query child);
union {
adns_rr_addr ptr_parent_addr;
adns_rr_hostaddr *hostaddr;
} info;
} qcontext;
struct adns__query {
adns_state ads;
enum { query_tosend, query_tcpw, query_childw, query_done } state;
adns_query back, next, parent;
struct { adns_query head, tail; } children;
struct { adns_query back, next; } siblings;
struct { allocnode *head, *tail; } allocations;
int interim_allocd, preserved_allocd;
void *final_allocspace;
adns_state ads;
enum { query_tosend, query_tcpw, query_childw, query_done } state;
adns_query back, next, parent;
struct {
adns_query head, tail;
} children;
struct {
adns_query back, next;
} siblings;
struct {
allocnode *head, *tail;
} allocations;
int interim_allocd, preserved_allocd;
void *final_allocspace;
const typeinfo *typei;
byte *query_dgram;
int query_dglen;
const typeinfo *typei;
byte *query_dgram;
int query_dglen;
vbuf vb;
/* General-purpose messing-about buffer.
* Wherever a `big' interface is crossed, this may be corrupted/changed
* unless otherwise specified.
*/
vbuf vb;
/* General-purpose messing-about buffer.
* Wherever a `big' interface is crossed, this may be corrupted/changed
* unless otherwise specified.
*/
adns_answer *answer;
/* This is allocated when a query is submitted, to avoid being unable
* to relate errors to queries if we run out of memory. During
* query processing status, rrs is 0. cname is set if
* we found a cname (this corresponds to cname_dgram in the query
* structure). type is set from the word go. nrrs and rrs
* are set together, when we find how many rrs there are.
* owner is set during querying unless we're doing searchlist,
* in which case it is set only when we find an answer.
*/
adns_answer *answer;
/* This is allocated when a query is submitted, to avoid being unable
* to relate errors to queries if we run out of memory. During
* query processing status, rrs is 0. cname is set if
* we found a cname (this corresponds to cname_dgram in the query
* structure). type is set from the word go. nrrs and rrs
* are set together, when we find how many rrs there are.
* owner is set during querying unless we're doing searchlist,
* in which case it is set only when we find an answer.
*/
byte *cname_dgram;
int cname_dglen, cname_begin;
/* If non-0, has been allocated using . */
byte *cname_dgram;
int cname_dglen, cname_begin;
/* If non-0, has been allocated using . */
vbuf search_vb;
int search_origlen, search_pos, search_doneabs;
/* Used by the searching algorithm. The query domain in textual form
* is copied into the vbuf, and _origlen set to its length. Then
* we walk the searchlist, if we want to. _pos says where we are
* (next entry to try), and _doneabs says whether we've done the
* absolute query yet (0=not yet, 1=done, -1=must do straight away,
* but not done yet). If flags doesn't have adns_qf_search then
* the vbuf is initialised but empty and everything else is zero.
*/
vbuf search_vb;
int search_origlen, search_pos, search_doneabs;
/* Used by the searching algorithm. The query domain in textual form
* is copied into the vbuf, and _origlen set to its length. Then
* we walk the searchlist, if we want to. _pos says where we are
* (next entry to try), and _doneabs says whether we've done the
* absolute query yet (0=not yet, 1=done, -1=must do straight away,
* but not done yet). If flags doesn't have adns_qf_search then
* the vbuf is initialised but empty and everything else is zero.
*/
int id, flags, retries;
int udpnextserver;
unsigned long udpsent; /* bitmap indexed by server */
struct timeval timeout;
time_t expires; /* Earliest expiry time of any record we used. */
int id, flags, retries;
int udpnextserver;
unsigned long udpsent; /* bitmap indexed by server */
struct timeval timeout;
time_t expires; /* Earliest expiry time of any record we used. */
qcontext ctx;
qcontext ctx;
/* Possible states:
*
* state Queue child id nextudpserver udpsent tcpfailed
*
* tosend NONE null >=0 0 zero zero
* tosend udpw null >=0 any nonzero zero
* tosend NONE null >=0 any nonzero zero
*
* tcpw tcpw null >=0 irrelevant any any
*
* child childw set >=0 irrelevant irrelevant irrelevant
* child NONE null >=0 irrelevant irrelevant irrelevant
* done output null -1 irrelevant irrelevant irrelevant
*
* Queries are only not on a queue when they are actually being processed.
* Queries in state tcpw/tcpw have been sent (or are in the to-send buffer)
* iff the tcp connection is in state server_ok.
*
* +------------------------+
* START -----> | tosend/NONE |
* +------------------------+
* / |\ \
* too big for UDP / UDP timeout \ \ send via UDP
* send via TCP / more retries \ \
* when conn'd / desired \ \
* | | |
* v | v
* +-----------+ +-------------+
* | tcpw/tcpw | ________ | tosend/udpw |
* +-----------+ \ +-------------+
* | | | UDP timeout | |
* | | | no more | |
* | | | retries | |
* \ | TCP died | desired | |
* \ \ no more | | |
* \ \ servers | TCP / |
* \ \ to try | timeout / |
* got \ \ v |_ | got
* reply \ _| +------------------+ / reply
* \ | done/output FAIL | /
* \ +------------------+ /
* \ /
* _| |_
* (..... got reply ....)
* / \
* need child query/ies / \ no child query
* / \
* |_ _|
* +---------------+ +----------------+
* | childw/childw | ----------------> | done/output OK |
* +---------------+ children done +----------------+
*/
/* Possible states:
*
* state Queue child id nextudpserver udpsent tcpfailed
*
* tosend NONE null >=0 0 zero zero
* tosend udpw null >=0 any nonzero zero
* tosend NONE null >=0 any nonzero zero
*
* tcpw tcpw null >=0 irrelevant any any
*
* child childw set >=0 irrelevant irrelevant irrelevant
* child NONE null >=0 irrelevant irrelevant irrelevant
* done output null -1 irrelevant irrelevant irrelevant
*
* Queries are only not on a queue when they are actually being processed.
* Queries in state tcpw/tcpw have been sent (or are in the to-send buffer)
* iff the tcp connection is in state server_ok.
*
* +------------------------+
* START -----> | tosend/NONE |
* +------------------------+
* / |\ \
* too big for UDP / UDP timeout \ \ send via UDP
* send via TCP / more retries \ \
* when conn'd / desired \ \
* | | |
* v | v
* +-----------+ +-------------+
* | tcpw/tcpw | ________ | tosend/udpw |
* +-----------+ \ +-------------+
* | | | UDP timeout | |
* | | | no more | |
* | | | retries | |
* \ | TCP died | desired | |
* \ \ no more | | |
* \ \ servers | TCP / |
* \ \ to try | timeout / |
* got \ \ v |_ | got
* reply \ _| +------------------+ / reply
* \ | done/output FAIL | /
* \ +------------------+ /
* \ /
* _| |_
* (..... got reply ....)
* / \
* need child query/ies / \ no child query
* / \
* |_ _|
* +---------------+ +----------------+
* | childw/childw | ----------------> | done/output OK |
* +---------------+ children done +----------------+
*/
};
struct query_queue { adns_query head, tail; };
struct query_queue {
adns_query head, tail;
};
struct adns__state {
adns_initflags iflags;
FILE *diagfile;
int configerrno;
struct query_queue udpw, tcpw, childw, output;
adns_query forallnext;
int nextid, udpsocket, tcpsocket;
vbuf tcpsend, tcprecv;
int nservers, nsortlist, nsearchlist, searchndots, tcpserver, tcprecv_skip;
enum adns__tcpstate {
server_disconnected, server_connecting,
server_ok, server_broken
} tcpstate;
struct timeval tcptimeout;
/* This will have tv_sec==0 if it is not valid. It will always be
* valid if tcpstate _connecting. When _ok, it will be nonzero if
* we are idle (ie, tcpw queue is empty), in which case it is the
* absolute time when we will close the connection.
*/
struct sigaction stdsigpipe;
sigset_t stdsigmask;
struct pollfd pollfds_buf[MAX_POLLFDS];
struct server {
struct in_addr addr;
} servers[MAXSERVERS];
struct sortlist {
struct in_addr base, mask;
} sortlist[MAXSORTLIST];
char **searchlist;
adns_initflags iflags;
FILE *diagfile;
int configerrno;
struct query_queue udpw, tcpw, childw, output;
adns_query forallnext;
int nextid, udpsocket, tcpsocket;
vbuf tcpsend, tcprecv;
int nservers, nsortlist, nsearchlist, searchndots, tcpserver,
tcprecv_skip;
enum adns__tcpstate {
server_disconnected, server_connecting,
server_ok, server_broken
} tcpstate;
struct timeval tcptimeout;
/* This will have tv_sec==0 if it is not valid. It will always be
* valid if tcpstate _connecting. When _ok, it will be nonzero if
* we are idle (ie, tcpw queue is empty), in which case it is the
* absolute time when we will close the connection.
*/
struct sigaction stdsigpipe;
sigset_t stdsigmask;
struct pollfd pollfds_buf[MAX_POLLFDS];
struct server {
struct in_addr addr;
} servers[MAXSERVERS];
struct sortlist {
struct in_addr base, mask;
} sortlist[MAXSORTLIST];
char **searchlist;
};
/* From setup.c: */
int adns__setnonblock(adns_state ads, int fd); /* => errno value */
int adns__setnonblock(adns_state ads, int fd); /* => errno value */
/* From general.c: */
@ -342,22 +353,23 @@ void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
int serv, adns_query qu, const char *fmt, va_list al);
void adns__debug(adns_state ads, int serv, adns_query qu,
const char *fmt, ...) PRINTFFORMAT(4,5);
const char *fmt, ...) PRINTFFORMAT(4, 5);
void adns__warn(adns_state ads, int serv, adns_query qu,
const char *fmt, ...) PRINTFFORMAT(4,5);
const char *fmt, ...) PRINTFFORMAT(4, 5);
void adns__diag(adns_state ads, int serv, adns_query qu,
const char *fmt, ...) PRINTFFORMAT(4,5);
const char *fmt, ...) PRINTFFORMAT(4, 5);
int adns__vbuf_ensure(vbuf *vb, int want);
int adns__vbuf_appendstr(vbuf *vb, const char *data); /* does not include nul */
int adns__vbuf_append(vbuf *vb, const byte *data, int len);
int adns__vbuf_ensure(vbuf * vb, int want);
int adns__vbuf_appendstr(vbuf * vb, const char *data); /* does not include nul */
int adns__vbuf_append(vbuf * vb, const byte * data, int len);
/* 1=>success, 0=>realloc failed */
void adns__vbuf_appendq(vbuf *vb, const byte *data, int len);
void adns__vbuf_init(vbuf *vb);
void adns__vbuf_free(vbuf *vb);
void adns__vbuf_appendq(vbuf * vb, const byte * data, int len);
void adns__vbuf_init(vbuf * vb);
void adns__vbuf_free(vbuf * vb);
const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
vbuf *vb, const byte *dgram, int dglen, int cbyte);
vbuf * vb, const byte * dgram, int dglen,
int cbyte);
/* Unpicks a domain in a datagram and returns a string suitable for
* printing it as. Never fails - if an error occurs, it will
* return some kind of string describing the error.
@ -370,8 +382,8 @@ const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
*/
void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
int (*needswap)(void *context, const void *a, const void *b),
void *context);
int (*needswap) (void *context, const void *a,
const void *b), void *context);
/* Does an insertion sort of array which must contain nobjs objects
* each sz bytes long. tempbuf must point to a buffer at least
* sz bytes long. needswap should return !0 if a>b (strictly, ie
@ -389,15 +401,16 @@ void adns__sigpipe_unprotect(adns_state);
/* From transmit.c: */
adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
adns_status adns__mkquery(adns_state ads, vbuf * vb, int *id_r,
const char *owner, int ol,
const typeinfo *typei, adns_queryflags flags);
const typeinfo * typei, adns_queryflags flags);
/* Assembles a query packet in vb. A new id is allocated and returned.
*/
adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
const byte *qd_dgram, int qd_dglen, int qd_begin,
adns_rrtype type, adns_queryflags flags);
adns_status adns__mkquery_frdgram(adns_state ads, vbuf * vb, int *id_r,
const byte * qd_dgram, int qd_dglen,
int qd_begin, adns_rrtype type,
adns_queryflags flags);
/* Same as adns__mkquery, but takes the owner domain from an existing datagram.
* That domain must be correct and untruncated.
*/
@ -420,10 +433,11 @@ void adns__query_send(adns_query qu, struct timeval now);
/* From query.c: */
adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
const typeinfo *typei, vbuf *qumsg_vb, int id,
adns_queryflags flags, struct timeval now,
const qcontext *ctx);
adns_status adns__internal_submit(adns_state ads, adns_query * query_r,
const typeinfo * typei, vbuf * qumsg_vb,
int id, adns_queryflags flags,
struct timeval now,
const qcontext * ctx);
/* Submits a query (for internal use, called during external submits).
*
* The new query is returned in *query_r, or we return adns_s_nomemory.
@ -482,7 +496,8 @@ void *adns__alloc_preserved(adns_query qu, size_t sz);
* answer->cname and answer->owner are _preserved.
*/
void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz);
void adns__transfer_interim(adns_query from, adns_query to, void *block,
size_t sz);
/* Transfers an interim allocation from one query to another, so that
* the `to' query will have room for the data when we get to makefinal
* and so that the free will happen when the `to' query is freed
@ -522,7 +537,7 @@ void adns__query_fail(adns_query qu, adns_status stat);
/* From reply.c: */
void adns__procdgram(adns_state ads, const byte *dgram, int len,
void adns__procdgram(adns_state ads, const byte * dgram, int len,
int serv, int viatcp, struct timeval now);
/* This function is allowed to cause new datagrams to be constructed
* and sent, or even new queries to be started. However,
@ -540,17 +555,17 @@ const typeinfo *adns__findtype(adns_rrtype type);
/* From parse.c: */
typedef struct {
adns_state ads;
adns_query qu;
int serv;
const byte *dgram;
int dglen, max, cbyte, namelen;
int *dmend_r;
adns_state ads;
adns_query qu;
int serv;
const byte *dgram;
int dglen, max, cbyte, namelen;
int *dmend_r;
} findlabel_state;
void adns__findlabel_start(findlabel_state *fls, adns_state ads,
void adns__findlabel_start(findlabel_state * fls, adns_state ads,
int serv, adns_query qu,
const byte *dgram, int dglen, int max,
const byte * dgram, int dglen, int max,
int dmbegin, int *dmend_rlater);
/* Finds labels in a domain in a datagram.
*
@ -559,7 +574,8 @@ void adns__findlabel_start(findlabel_state *fls, adns_state ads,
* serv may be -1, qu may be null - they are for error reporting.
*/
adns_status adns__findlabel_next(findlabel_state *fls, int *lablen_r, int *labstart_r);
adns_status adns__findlabel_next(findlabel_state * fls, int *lablen_r,
int *labstart_r);
/* Then, call this one repeatedly.
*
* It will return adns_s_ok if all is well, and tell you the length
@ -585,12 +601,13 @@ adns_status adns__findlabel_next(findlabel_state *fls, int *lablen_r, int *labst
*/
typedef enum {
pdf_quoteok= 0x001
pdf_quoteok = 0x001
} parsedomain_flags;
adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu,
vbuf *vb, parsedomain_flags flags,
const byte *dgram, int dglen, int *cbyte_io, int max);
vbuf * vb, parsedomain_flags flags,
const byte * dgram, int dglen,
int *cbyte_io, int max);
/* vb must already have been initialised; it will be reset if necessary.
* If there is truncation, vb->used will be set to 0; otherwise
* (if there is no error) vb will be null-terminated.
@ -599,9 +616,10 @@ adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu,
* serv may be -1 and qu may be 0 - they are used for error reporting only.
*/
adns_status adns__parse_domain_more(findlabel_state *fls, adns_state ads,
adns_query qu, vbuf *vb, parsedomain_flags flags,
const byte *dgram);
adns_status adns__parse_domain_more(findlabel_state * fls, adns_state ads,
adns_query qu, vbuf * vb,
parsedomain_flags flags,
const byte * dgram);
/* Like adns__parse_domain, but you pass it a pre-initialised findlabel_state,
* for continuing an existing domain or some such of some kind. Also, unlike
* _parse_domain, the domain data will be appended to vb, rather than replacing
@ -609,7 +627,7 @@ adns_status adns__parse_domain_more(findlabel_state *fls, adns_state ads,
*/
adns_status adns__findrr(adns_query qu, int serv,
const byte *dgram, int dglen, int *cbyte_io,
const byte * dgram, int dglen, int *cbyte_io,
int *type_r, int *class_r, unsigned long *ttl_r,
int *rdlen_r, int *rdstart_r,
int *ownermatchedquery_r);
@ -638,10 +656,11 @@ adns_status adns__findrr(adns_query qu, int serv,
*/
adns_status adns__findrr_anychk(adns_query qu, int serv,
const byte *dgram, int dglen, int *cbyte_io,
int *type_r, int *class_r, unsigned long *ttl_r,
int *rdlen_r, int *rdstart_r,
const byte *eo_dgram, int eo_dglen, int eo_cbyte,
const byte * dgram, int dglen,
int *cbyte_io, int *type_r, int *class_r,
unsigned long *ttl_r, int *rdlen_r,
int *rdstart_r, const byte * eo_dgram,
int eo_dglen, int eo_cbyte,
int *eo_matched_r);
/* Like adns__findrr_checked, except that the datagram and
* owner to compare with can be specified explicitly.
@ -657,12 +676,13 @@ adns_status adns__findrr_anychk(adns_query qu, int serv,
* untruncated.
*/
void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now);
void adns__update_expires(adns_query qu, unsigned long ttl,
struct timeval now);
/* Updates the `expires' field in the query, so that it doesn't exceed
* now + ttl.
*/
int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len);
int vbuf__append_quoted1035(vbuf * vb, const byte * buf, int len);
/* From event.c: */
@ -683,13 +703,12 @@ void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,
int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]);
void adns__fdevents(adns_state ads,
const struct pollfd *pollfds, int npollfds,
int maxfd, const fd_set *readfds,
const fd_set *writefds, const fd_set *exceptfds,
int maxfd, const fd_set * readfds,
const fd_set * writefds, const fd_set * exceptfds,
struct timeval now, int *r_r);
int adns__internal_check(adns_state ads,
adns_query *query_io,
adns_answer **answer,
void **context_r);
adns_query * query_io,
adns_answer ** answer, void **context_r);
void adns__timeouts(adns_state ads, int act,
struct timeval **tv_io, struct timeval *tvbuf,
@ -700,21 +719,37 @@ void adns__timeouts(adns_state ads, int act,
/* From check.c: */
void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc);
void adns__consistency(adns_state ads, adns_query qu,
consistency_checks cc);
/* Useful static inline functions: */
static inline int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; }
static inline int ctype_digit(int c) { return c>='0' && c<='9'; }
static inline int ctype_alpha(int c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
static inline int ctype_whitespace(int c)
{
return c == ' ' || c == '\n' || c == '\t';
}
static inline int ctype_822special(int c) { return strchr("()<>@,;:\\\".[]",c) != 0; }
static inline int ctype_domainunquoted(int c) {
return ctype_alpha(c) || ctype_digit(c) || (strchr("-_/+",c) != 0);
static inline int ctype_digit(int c)
{
return c >= '0' && c <= '9';
}
static inline int ctype_alpha(int c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
static inline int ctype_822special(int c)
{
return strchr("()<>@,;:\\\".[]", c) != 0;
}
static inline int ctype_domainunquoted(int c)
{
return ctype_alpha(c) || ctype_digit(c)
|| (strchr("-_/+", c) != 0);
}
static inline int errno_resources(int e) { return e==ENOMEM || e==ENOBUFS; }
static inline int errno_resources(int e)
{
return e == ENOMEM || e == ENOBUFS;
}
/* Useful macros */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: parse.c,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
** $Id: parse.c,v 1.3 2003/06/13 14:44:36 fishwaldo Exp $
*/
/*
* parse.c
@ -49,220 +49,284 @@
#include "internal.h"
int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len) {
char qbuf[10];
int i, ch;
while (len) {
qbuf[0]= 0;
for (i=0; i<len; i++) {
ch= buf[i];
if (ch <= ' ' || ch >= 127) {
sprintf(qbuf,"\\%03o",ch);
break;
} else if (!ctype_domainunquoted(ch)) {
sprintf(qbuf,"\\%c",ch);
break;
}
}
if (!adns__vbuf_append(vb,buf,i) || !adns__vbuf_append(vb,qbuf,strlen(qbuf)))
return 0;
if (i<len) i++;
buf+= i;
len-= i;
}
return 1;
int vbuf__append_quoted1035(vbuf * vb, const byte * buf, int len)
{
char qbuf[10];
int i, ch;
while (len) {
qbuf[0] = 0;
for (i = 0; i < len; i++) {
ch = buf[i];
if (ch <= ' ' || ch >= 127) {
sprintf(qbuf, "\\%03o", ch);
break;
} else if (!ctype_domainunquoted(ch)) {
sprintf(qbuf, "\\%c", ch);
break;
}
}
if (!adns__vbuf_append(vb, buf, i)
|| !adns__vbuf_append(vb, qbuf, strlen(qbuf)))
return 0;
if (i < len)
i++;
buf += i;
len -= i;
}
return 1;
}
void adns__findlabel_start(findlabel_state *fls, adns_state ads,
void adns__findlabel_start(findlabel_state * fls, adns_state ads,
int serv, adns_query qu,
const byte *dgram, int dglen, int max,
int dmbegin, int *dmend_rlater) {
fls->ads= ads;
fls->qu= qu;
fls->serv= serv;
fls->dgram= dgram;
fls->dglen= dglen;
fls->max= max;
fls->cbyte= dmbegin;
fls->namelen= 0;
fls->dmend_r= dmend_rlater;
const byte * dgram, int dglen, int max,
int dmbegin, int *dmend_rlater)
{
fls->ads = ads;
fls->qu = qu;
fls->serv = serv;
fls->dgram = dgram;
fls->dglen = dglen;
fls->max = max;
fls->cbyte = dmbegin;
fls->namelen = 0;
fls->dmend_r = dmend_rlater;
}
adns_status adns__findlabel_next(findlabel_state *fls,
int *lablen_r, int *labstart_r) {
int lablen, jumpto;
const char *dgram;
adns_status adns__findlabel_next(findlabel_state * fls,
int *lablen_r, int *labstart_r)
{
int lablen, jumpto;
const char *dgram;
dgram= fls->dgram;
for (;;) {
if (fls->cbyte >= fls->dglen) goto x_truncated;
if (fls->cbyte >= fls->max) goto x_badresponse;
GET_B(fls->cbyte,lablen);
if (!(lablen & 0x0c0)) break;
if ((lablen & 0x0c0) != 0x0c0) return adns_s_unknownformat;
if (fls->cbyte >= fls->dglen) goto x_truncated;
if (fls->cbyte >= fls->max) goto x_badresponse;
GET_B(fls->cbyte,jumpto);
jumpto |= (lablen&0x3f)<<8;
if (fls->dmend_r) *(fls->dmend_r)= fls->cbyte;
fls->cbyte= jumpto;
fls->dmend_r= 0; fls->max= fls->dglen+1;
}
if (labstart_r) *labstart_r= fls->cbyte;
if (lablen) {
if (fls->namelen) fls->namelen++;
fls->namelen+= lablen;
if (fls->namelen > DNS_MAXDOMAIN) return adns_s_answerdomaintoolong;
fls->cbyte+= lablen;
if (fls->cbyte > fls->dglen) goto x_truncated;
if (fls->cbyte > fls->max) goto x_badresponse;
} else {
if (fls->dmend_r) *(fls->dmend_r)= fls->cbyte;
}
*lablen_r= lablen;
return adns_s_ok;
dgram = fls->dgram;
for (;;) {
if (fls->cbyte >= fls->dglen)
goto x_truncated;
if (fls->cbyte >= fls->max)
goto x_badresponse;
GET_B(fls->cbyte, lablen);
if (!(lablen & 0x0c0))
break;
if ((lablen & 0x0c0) != 0x0c0)
return adns_s_unknownformat;
if (fls->cbyte >= fls->dglen)
goto x_truncated;
if (fls->cbyte >= fls->max)
goto x_badresponse;
GET_B(fls->cbyte, jumpto);
jumpto |= (lablen & 0x3f) << 8;
if (fls->dmend_r)
*(fls->dmend_r) = fls->cbyte;
fls->cbyte = jumpto;
fls->dmend_r = 0;
fls->max = fls->dglen + 1;
}
if (labstart_r)
*labstart_r = fls->cbyte;
if (lablen) {
if (fls->namelen)
fls->namelen++;
fls->namelen += lablen;
if (fls->namelen > DNS_MAXDOMAIN)
return adns_s_answerdomaintoolong;
fls->cbyte += lablen;
if (fls->cbyte > fls->dglen)
goto x_truncated;
if (fls->cbyte > fls->max)
goto x_badresponse;
} else {
if (fls->dmend_r)
*(fls->dmend_r) = fls->cbyte;
}
*lablen_r = lablen;
return adns_s_ok;
x_truncated:
*lablen_r= -1;
return adns_s_ok;
x_truncated:
*lablen_r = -1;
return adns_s_ok;
x_badresponse:
adns__diag(fls->ads,fls->serv,fls->qu,"label in domain runs beyond end of domain");
return adns_s_invalidresponse;
x_badresponse:
adns__diag(fls->ads, fls->serv, fls->qu,
"label in domain runs beyond end of domain");
return adns_s_invalidresponse;
}
adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu,
vbuf *vb, adns_queryflags flags,
const byte *dgram, int dglen, int *cbyte_io, int max) {
findlabel_state fls;
adns__findlabel_start(&fls,ads, serv,qu, dgram,dglen,max, *cbyte_io,cbyte_io);
vb->used= 0;
return adns__parse_domain_more(&fls,ads,qu, vb,flags,dgram);
vbuf * vb, adns_queryflags flags,
const byte * dgram, int dglen,
int *cbyte_io, int max)
{
findlabel_state fls;
adns__findlabel_start(&fls, ads, serv, qu, dgram, dglen, max,
*cbyte_io, cbyte_io);
vb->used = 0;
return adns__parse_domain_more(&fls, ads, qu, vb, flags, dgram);
}
adns_status adns__parse_domain_more(findlabel_state *fls, adns_state ads,
adns_query qu, vbuf *vb, parsedomain_flags flags,
const byte *dgram) {
int lablen, labstart, i, ch, first;
adns_status st;
adns_status adns__parse_domain_more(findlabel_state * fls, adns_state ads,
adns_query qu, vbuf * vb,
parsedomain_flags flags,
const byte * dgram)
{
int lablen, labstart, i, ch, first;
adns_status st;
first= 1;
for (;;) {
st= adns__findlabel_next(fls,&lablen,&labstart);
if (st) return st;
if (lablen<0) { vb->used=0; return adns_s_ok; }
if (!lablen) break;
if (first) {
first= 0;
} else {
if (!adns__vbuf_append(vb,".",1)) return adns_s_nomemory;
}
if (flags & pdf_quoteok) {
if (!vbuf__append_quoted1035(vb,dgram+labstart,lablen))
return adns_s_nomemory;
} else {
ch= dgram[labstart];
if (!ctype_alpha(ch) && !ctype_digit(ch)) return adns_s_answerdomaininvalid;
for (i= labstart+1; i<labstart+lablen; i++) {
ch= dgram[i];
if (ch != '-' && !ctype_alpha(ch) && !ctype_digit(ch))
return adns_s_answerdomaininvalid;
}
if (!adns__vbuf_append(vb,dgram+labstart,lablen))
return adns_s_nomemory;
}
}
if (!adns__vbuf_append(vb,"",1)) return adns_s_nomemory;
return adns_s_ok;
first = 1;
for (;;) {
st = adns__findlabel_next(fls, &lablen, &labstart);
if (st)
return st;
if (lablen < 0) {
vb->used = 0;
return adns_s_ok;
}
if (!lablen)
break;
if (first) {
first = 0;
} else {
if (!adns__vbuf_append(vb, ".", 1))
return adns_s_nomemory;
}
if (flags & pdf_quoteok) {
if (!vbuf__append_quoted1035
(vb, dgram + labstart, lablen))
return adns_s_nomemory;
} else {
ch = dgram[labstart];
if (!ctype_alpha(ch) && !ctype_digit(ch))
return adns_s_answerdomaininvalid;
for (i = labstart + 1; i < labstart + lablen; i++) {
ch = dgram[i];
if (ch != '-' && !ctype_alpha(ch)
&& !ctype_digit(ch))
return adns_s_answerdomaininvalid;
}
if (!adns__vbuf_append
(vb, dgram + labstart, lablen))
return adns_s_nomemory;
}
}
if (!adns__vbuf_append(vb, "", 1))
return adns_s_nomemory;
return adns_s_ok;
}
adns_status adns__findrr_anychk(adns_query qu, int serv,
const byte *dgram, int dglen, int *cbyte_io,
int *type_r, int *class_r, unsigned long *ttl_r,
int *rdlen_r, int *rdstart_r,
const byte *eo_dgram, int eo_dglen, int eo_cbyte,
int *eo_matched_r) {
findlabel_state fls, eo_fls;
int cbyte;
int tmp, rdlen, mismatch;
unsigned long ttl;
int lablen, labstart, ch;
int eo_lablen, eo_labstart, eo_ch;
adns_status st;
const byte * dgram, int dglen,
int *cbyte_io, int *type_r, int *class_r,
unsigned long *ttl_r, int *rdlen_r,
int *rdstart_r, const byte * eo_dgram,
int eo_dglen, int eo_cbyte,
int *eo_matched_r)
{
findlabel_state fls, eo_fls;
int cbyte;
cbyte= *cbyte_io;
int tmp, rdlen, mismatch;
unsigned long ttl;
int lablen, labstart, ch;
int eo_lablen, eo_labstart, eo_ch;
adns_status st;
adns__findlabel_start(&fls,qu->ads, serv,qu, dgram,dglen,dglen,cbyte,&cbyte);
if (eo_dgram) {
adns__findlabel_start(&eo_fls,qu->ads, -1,0, eo_dgram,eo_dglen,eo_dglen,eo_cbyte,0);
mismatch= 0;
} else {
mismatch= 1;
}
for (;;) {
st= adns__findlabel_next(&fls,&lablen,&labstart);
if (st) return st;
if (lablen<0) goto x_truncated;
cbyte = *cbyte_io;
if (!mismatch) {
st= adns__findlabel_next(&eo_fls,&eo_lablen,&eo_labstart);
assert(!st); assert(eo_lablen>=0);
if (lablen != eo_lablen) mismatch= 1;
while (!mismatch && eo_lablen-- > 0) {
ch= dgram[labstart++]; if (ctype_alpha(ch)) ch &= ~32;
eo_ch= eo_dgram[eo_labstart++]; if (ctype_alpha(eo_ch)) eo_ch &= ~32;
if (ch != eo_ch) mismatch= 1;
}
}
if (!lablen) break;
}
if (eo_matched_r) *eo_matched_r= !mismatch;
if (cbyte+10>dglen) goto x_truncated;
GET_W(cbyte,tmp); *type_r= tmp;
GET_W(cbyte,tmp); *class_r= tmp;
adns__findlabel_start(&fls, qu->ads, serv, qu, dgram, dglen, dglen,
cbyte, &cbyte);
if (eo_dgram) {
adns__findlabel_start(&eo_fls, qu->ads, -1, 0, eo_dgram,
eo_dglen, eo_dglen, eo_cbyte, 0);
mismatch = 0;
} else {
mismatch = 1;
}
GET_L(cbyte,ttl);
if (ttl > MAXTTLBELIEVE) ttl= MAXTTLBELIEVE;
*ttl_r= ttl;
GET_W(cbyte,rdlen); if (rdlen_r) *rdlen_r= rdlen;
if (rdstart_r) *rdstart_r= cbyte;
cbyte+= rdlen;
if (cbyte>dglen) goto x_truncated;
*cbyte_io= cbyte;
return adns_s_ok;
for (;;) {
st = adns__findlabel_next(&fls, &lablen, &labstart);
if (st)
return st;
if (lablen < 0)
goto x_truncated;
x_truncated:
*type_r= -1;
return 0;
if (!mismatch) {
st = adns__findlabel_next(&eo_fls, &eo_lablen,
&eo_labstart);
assert(!st);
assert(eo_lablen >= 0);
if (lablen != eo_lablen)
mismatch = 1;
while (!mismatch && eo_lablen-- > 0) {
ch = dgram[labstart++];
if (ctype_alpha(ch))
ch &= ~32;
eo_ch = eo_dgram[eo_labstart++];
if (ctype_alpha(eo_ch))
eo_ch &= ~32;
if (ch != eo_ch)
mismatch = 1;
}
}
if (!lablen)
break;
}
if (eo_matched_r)
*eo_matched_r = !mismatch;
if (cbyte + 10 > dglen)
goto x_truncated;
GET_W(cbyte, tmp);
*type_r = tmp;
GET_W(cbyte, tmp);
*class_r = tmp;
GET_L(cbyte, ttl);
if (ttl > MAXTTLBELIEVE)
ttl = MAXTTLBELIEVE;
*ttl_r = ttl;
GET_W(cbyte, rdlen);
if (rdlen_r)
*rdlen_r = rdlen;
if (rdstart_r)
*rdstart_r = cbyte;
cbyte += rdlen;
if (cbyte > dglen)
goto x_truncated;
*cbyte_io = cbyte;
return adns_s_ok;
x_truncated:
*type_r = -1;
return 0;
}
adns_status adns__findrr(adns_query qu, int serv,
const byte *dgram, int dglen, int *cbyte_io,
const byte * dgram, int dglen, int *cbyte_io,
int *type_r, int *class_r, unsigned long *ttl_r,
int *rdlen_r, int *rdstart_r,
int *ownermatchedquery_r) {
if (!ownermatchedquery_r) {
return adns__findrr_anychk(qu,serv,
dgram,dglen,cbyte_io,
type_r,class_r,ttl_r,rdlen_r,rdstart_r,
0,0,0, 0);
} else if (!qu->cname_dgram) {
return adns__findrr_anychk(qu,serv,
dgram,dglen,cbyte_io,
type_r,class_r,ttl_r,rdlen_r,rdstart_r,
qu->query_dgram,qu->query_dglen,DNS_HDRSIZE,
ownermatchedquery_r);
} else {
return adns__findrr_anychk(qu,serv,
dgram,dglen,cbyte_io,
type_r,class_r,ttl_r,rdlen_r,rdstart_r,
qu->cname_dgram,qu->cname_dglen,qu->cname_begin,
ownermatchedquery_r);
}
int *ownermatchedquery_r)
{
if (!ownermatchedquery_r) {
return adns__findrr_anychk(qu, serv,
dgram, dglen, cbyte_io,
type_r, class_r, ttl_r, rdlen_r,
rdstart_r, 0, 0, 0, 0);
} else if (!qu->cname_dgram) {
return adns__findrr_anychk(qu, serv,
dgram, dglen, cbyte_io,
type_r, class_r, ttl_r, rdlen_r,
rdstart_r, qu->query_dgram,
qu->query_dglen, DNS_HDRSIZE,
ownermatchedquery_r);
} else {
return adns__findrr_anychk(qu, serv,
dgram, dglen, cbyte_io,
type_r, class_r, ttl_r, rdlen_r,
rdstart_r, qu->cname_dgram,
qu->cname_dglen,
qu->cname_begin,
ownermatchedquery_r);
}
}

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: reply.c,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
** $Id: reply.c,v 1.3 2003/06/13 14:44:36 fishwaldo Exp $
*/
/*
* reply.c
@ -50,343 +50,448 @@
#include <stdlib.h>
#include "internal.h"
void adns__procdgram(adns_state ads, const byte *dgram, int dglen,
int serv, int viatcp, struct timeval now) {
int cbyte, rrstart, wantedrrs, rri, foundsoa, foundns, cname_here;
int id, f1, f2, qdcount, ancount, nscount, arcount;
int flg_ra, flg_rd, flg_tc, flg_qr, opcode;
int rrtype, rrclass, rdlength, rdstart;
int anstart, nsstart, arstart;
int ownermatched, l, nrrs;
unsigned long ttl, soattl;
const typeinfo *typei;
adns_query qu, nqu;
dns_rcode rcode;
adns_status st;
vbuf tempvb;
byte *newquery, *rrsdata;
parseinfo pai;
if (dglen<DNS_HDRSIZE) {
adns__diag(ads,serv,0,"received datagram too short for message header (%d)",dglen);
return;
}
cbyte= 0;
GET_W(cbyte,id);
GET_B(cbyte,f1);
GET_B(cbyte,f2);
GET_W(cbyte,qdcount);
GET_W(cbyte,ancount);
GET_W(cbyte,nscount);
GET_W(cbyte,arcount);
assert(cbyte == DNS_HDRSIZE);
flg_qr= f1&0x80;
opcode= (f1&0x78)>>3;
flg_tc= f1&0x02;
flg_rd= f1&0x01;
flg_ra= f2&0x80;
rcode= (f2&0x0f);
void adns__procdgram(adns_state ads, const byte * dgram, int dglen,
int serv, int viatcp, struct timeval now)
{
int cbyte, rrstart, wantedrrs, rri, foundsoa, foundns, cname_here;
int id, f1, f2, qdcount, ancount, nscount, arcount;
int flg_ra, flg_rd, flg_tc, flg_qr, opcode;
int rrtype, rrclass, rdlength, rdstart;
int anstart, nsstart, arstart;
int ownermatched, l, nrrs;
unsigned long ttl, soattl;
const typeinfo *typei;
adns_query qu, nqu;
dns_rcode rcode;
adns_status st;
vbuf tempvb;
byte *newquery, *rrsdata;
parseinfo pai;
cname_here= 0;
if (!flg_qr) {
adns__diag(ads,serv,0,"server sent us a query, not a response");
return;
}
if (opcode) {
adns__diag(ads,serv,0,"server sent us unknown opcode %d (wanted 0=QUERY)",opcode);
return;
}
if (dglen < DNS_HDRSIZE) {
adns__diag(ads, serv, 0,
"received datagram too short for message header (%d)",
dglen);
return;
}
cbyte = 0;
GET_W(cbyte, id);
GET_B(cbyte, f1);
GET_B(cbyte, f2);
GET_W(cbyte, qdcount);
GET_W(cbyte, ancount);
GET_W(cbyte, nscount);
GET_W(cbyte, arcount);
assert(cbyte == DNS_HDRSIZE);
qu= 0;
/* See if we can find the relevant query, or leave qu=0 otherwise ... */
flg_qr = f1 & 0x80;
opcode = (f1 & 0x78) >> 3;
flg_tc = f1 & 0x02;
flg_rd = f1 & 0x01;
flg_ra = f2 & 0x80;
rcode = (f2 & 0x0f);
if (qdcount == 1) {
for (qu= viatcp ? ads->tcpw.head : ads->udpw.head; qu; qu= nqu) {
nqu= qu->next;
if (qu->id != id) continue;
if (dglen < qu->query_dglen) continue;
if (memcmp(qu->query_dgram+DNS_HDRSIZE,
dgram+DNS_HDRSIZE,
qu->query_dglen-DNS_HDRSIZE))
continue;
if (viatcp) {
assert(qu->state == query_tcpw);
} else {
assert(qu->state == query_tosend);
if (!(qu->udpsent & (1<<serv))) continue;
}
break;
}
if (qu) {
/* We're definitely going to do something with this query now */
if (viatcp) LIST_UNLINK(ads->tcpw,qu);
else LIST_UNLINK(ads->udpw,qu);
}
}
/* If we're going to ignore the packet, we return as soon as we have
* failed the query (if any) and printed the warning message (if
* any).
*/
switch (rcode) {
case rcode_noerror:
case rcode_nxdomain:
break;
case rcode_formaterror:
adns__warn(ads,serv,qu,"server cannot understand our query (Format Error)");
if (qu) adns__query_fail(qu,adns_s_rcodeformaterror);
return;
case rcode_servfail:
if (qu) adns__query_fail(qu,adns_s_rcodeservfail);
else adns__debug(ads,serv,qu,"server failure on unidentifiable query");
return;
case rcode_notimp:
adns__warn(ads,serv,qu,"server claims not to implement our query");
if (qu) adns__query_fail(qu,adns_s_rcodenotimplemented);
return;
case rcode_refused:
adns__debug(ads,serv,qu,"server refused our query");
if (qu) adns__query_fail(qu,adns_s_rcoderefused);
return;
default:
adns__warn(ads,serv,qu,"server gave unknown response code %d",rcode);
if (qu) adns__query_fail(qu,adns_s_rcodeunknown);
return;
}
cname_here = 0;
if (!qu) {
if (!qdcount) {
adns__diag(ads,serv,0,"server sent reply without quoting our question");
} else if (qdcount>1) {
adns__diag(ads,serv,0,"server claimed to answer %d questions with one message",
qdcount);
} else if (ads->iflags & adns_if_debug) {
adns__vbuf_init(&tempvb);
adns__debug(ads,serv,0,"reply not found, id %02x, query owner %s",
id, adns__diag_domain(ads,serv,0,&tempvb,dgram,dglen,DNS_HDRSIZE));
adns__vbuf_free(&tempvb);
}
return;
}
if (!flg_qr) {
adns__diag(ads, serv, 0,
"server sent us a query, not a response");
return;
}
if (opcode) {
adns__diag(ads, serv, 0,
"server sent us unknown opcode %d (wanted 0=QUERY)",
opcode);
return;
}
/* We're definitely going to do something with this packet and this query now. */
anstart= qu->query_dglen;
arstart= -1;
qu = 0;
/* See if we can find the relevant query, or leave qu=0 otherwise ... */
/* Now, take a look at the answer section, and see if it is complete.
* If it has any CNAMEs we stuff them in the answer.
*/
wantedrrs= 0;
cbyte= anstart;
for (rri= 0; rri<ancount; rri++) {
rrstart= cbyte;
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
&rrtype,&rrclass,&ttl, &rdlength,&rdstart,
&ownermatched);
if (st) { adns__query_fail(qu,st); return; }
if (rrtype == -1) goto x_truncated;
if (qdcount == 1) {
for (qu = viatcp ? ads->tcpw.head : ads->udpw.head; qu;
qu = nqu) {
nqu = qu->next;
if (qu->id != id)
continue;
if (dglen < qu->query_dglen)
continue;
if (memcmp(qu->query_dgram + DNS_HDRSIZE,
dgram + DNS_HDRSIZE,
qu->query_dglen - DNS_HDRSIZE))
continue;
if (viatcp) {
assert(qu->state == query_tcpw);
} else {
assert(qu->state == query_tosend);
if (!(qu->udpsent & (1 << serv)))
continue;
}
break;
}
if (qu) {
/* We're definitely going to do something with this query now */
if (viatcp)
LIST_UNLINK(ads->tcpw, qu);
else
LIST_UNLINK(ads->udpw, qu);
}
}
if (rrclass != DNS_CLASS_IN) {
adns__diag(ads,serv,qu,"ignoring answer RR with wrong class %d (expected IN=%d)",
rrclass,DNS_CLASS_IN);
continue;
}
if (!ownermatched) {
if (ads->iflags & adns_if_debug) {
adns__debug(ads,serv,qu,"ignoring RR with an unexpected owner %s",
adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rrstart));
}
continue;
}
if (rrtype == adns_r_cname &&
(qu->typei->type & adns__rrt_typemask) != adns_r_cname) {
if (qu->flags & adns_qf_cname_forbid) {
adns__query_fail(qu,adns_s_prohibitedcname);
return;
} else if (qu->cname_dgram) { /* Ignore second and subsequent CNAME(s) */
adns__debug(ads,serv,qu,"allegedly canonical name %s is actually alias for %s",
qu->answer->cname,
adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rdstart));
adns__query_fail(qu,adns_s_prohibitedcname);
return;
} else if (wantedrrs) { /* Ignore CNAME(s) after RR(s). */
adns__debug(ads,serv,qu,"ignoring CNAME (to %s) coexisting with RR",
adns__diag_domain(ads,serv,qu, &qu->vb, dgram,dglen,rdstart));
} else {
qu->cname_begin= rdstart;
qu->cname_dglen= dglen;
st= adns__parse_domain(ads,serv,qu, &qu->vb,
qu->flags & adns_qf_quotefail_cname ? 0 : pdf_quoteok,
dgram,dglen, &rdstart,rdstart+rdlength);
if (!qu->vb.used) goto x_truncated;
if (st) { adns__query_fail(qu,st); return; }
l= strlen(qu->vb.buf)+1;
qu->answer->cname= adns__alloc_preserved(qu,l);
if (!qu->answer->cname) { adns__query_fail(qu,adns_s_nomemory); return; }
qu->cname_dgram= adns__alloc_mine(qu,dglen);
memcpy(qu->cname_dgram,dgram,dglen);
memcpy(qu->answer->cname,qu->vb.buf,l);
cname_here= 1;
adns__update_expires(qu,ttl,now);
/* If we find the answer section truncated after this point we restart
* the query at the CNAME; if beforehand then we obviously have to use
* TCP. If there is no truncation we can use the whole answer if
* it contains the relevant info.
/* If we're going to ignore the packet, we return as soon as we have
* failed the query (if any) and printed the warning message (if
* any).
*/
}
} else if (rrtype == (qu->typei->type & adns__rrt_typemask)) {
wantedrrs++;
} else {
adns__debug(ads,serv,qu,"ignoring answer RR with irrelevant type %d",rrtype);
}
}
switch (rcode) {
case rcode_noerror:
case rcode_nxdomain:
break;
case rcode_formaterror:
adns__warn(ads, serv, qu,
"server cannot understand our query (Format Error)");
if (qu)
adns__query_fail(qu, adns_s_rcodeformaterror);
return;
case rcode_servfail:
if (qu)
adns__query_fail(qu, adns_s_rcodeservfail);
else
adns__debug(ads, serv, qu,
"server failure on unidentifiable query");
return;
case rcode_notimp:
adns__warn(ads, serv, qu,
"server claims not to implement our query");
if (qu)
adns__query_fail(qu, adns_s_rcodenotimplemented);
return;
case rcode_refused:
adns__debug(ads, serv, qu, "server refused our query");
if (qu)
adns__query_fail(qu, adns_s_rcoderefused);
return;
default:
adns__warn(ads, serv, qu,
"server gave unknown response code %d", rcode);
if (qu)
adns__query_fail(qu, adns_s_rcodeunknown);
return;
}
/* We defer handling truncated responses here, in case there was a CNAME
* which we could use.
*/
if (flg_tc) goto x_truncated;
nsstart= cbyte;
if (!qu) {
if (!qdcount) {
adns__diag(ads, serv, 0,
"server sent reply without quoting our question");
} else if (qdcount > 1) {
adns__diag(ads, serv, 0,
"server claimed to answer %d questions with one message",
qdcount);
} else if (ads->iflags & adns_if_debug) {
adns__vbuf_init(&tempvb);
adns__debug(ads, serv, 0,
"reply not found, id %02x, query owner %s",
id, adns__diag_domain(ads, serv, 0,
&tempvb, dgram,
dglen,
DNS_HDRSIZE));
adns__vbuf_free(&tempvb);
}
return;
}
if (!wantedrrs) {
/* Oops, NODATA or NXDOMAIN or perhaps a referral (which would be a problem) */
/* We're definitely going to do something with this packet and this query now. */
/* RFC2308: NODATA has _either_ a SOA _or_ _no_ NS records in authority section */
foundsoa= 0; soattl= 0; foundns= 0;
for (rri= 0; rri<nscount; rri++) {
rrstart= cbyte;
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
&rrtype,&rrclass,&ttl, &rdlength,&rdstart, 0);
if (st) { adns__query_fail(qu,st); return; }
if (rrtype==-1) goto x_truncated;
if (rrclass != DNS_CLASS_IN) {
adns__diag(ads,serv,qu,
"ignoring authority RR with wrong class %d (expected IN=%d)",
rrclass,DNS_CLASS_IN);
continue;
}
if (rrtype == adns_r_soa_raw) { foundsoa= 1; soattl= ttl; break; }
else if (rrtype == adns_r_ns_raw) { foundns= 1; }
}
if (rcode == rcode_nxdomain) {
/* We still wanted to look for the SOA so we could find the TTL. */
adns__update_expires(qu,soattl,now);
anstart = qu->query_dglen;
arstart = -1;
if (qu->flags & adns_qf_search) {
adns__search_next(ads,qu,now);
} else {
adns__query_fail(qu,adns_s_nxdomain);
}
return;
}
/* Now, take a look at the answer section, and see if it is complete.
* If it has any CNAMEs we stuff them in the answer.
*/
wantedrrs = 0;
cbyte = anstart;
for (rri = 0; rri < ancount; rri++) {
rrstart = cbyte;
st = adns__findrr(qu, serv, dgram, dglen, &cbyte,
&rrtype, &rrclass, &ttl, &rdlength,
&rdstart, &ownermatched);
if (st) {
adns__query_fail(qu, st);
return;
}
if (rrtype == -1)
goto x_truncated;
if (foundsoa || !foundns) {
/* Aha ! A NODATA response, good. */
adns__update_expires(qu,soattl,now);
adns__query_fail(qu,adns_s_nodata);
return;
}
if (rrclass != DNS_CLASS_IN) {
adns__diag(ads, serv, qu,
"ignoring answer RR with wrong class %d (expected IN=%d)",
rrclass, DNS_CLASS_IN);
continue;
}
if (!ownermatched) {
if (ads->iflags & adns_if_debug) {
adns__debug(ads, serv, qu,
"ignoring RR with an unexpected owner %s",
adns__diag_domain(ads, serv,
qu, &qu->vb,
dgram, dglen,
rrstart));
}
continue;
}
if (rrtype == adns_r_cname &&
(qu->typei->type & adns__rrt_typemask) !=
adns_r_cname) {
if (qu->flags & adns_qf_cname_forbid) {
adns__query_fail(qu,
adns_s_prohibitedcname);
return;
} else if (qu->cname_dgram) { /* Ignore second and subsequent CNAME(s) */
adns__debug(ads, serv, qu,
"allegedly canonical name %s is actually alias for %s",
qu->answer->cname,
adns__diag_domain(ads, serv,
qu, &qu->vb,
dgram, dglen,
rdstart));
adns__query_fail(qu,
adns_s_prohibitedcname);
return;
} else if (wantedrrs) { /* Ignore CNAME(s) after RR(s). */
adns__debug(ads, serv, qu,
"ignoring CNAME (to %s) coexisting with RR",
adns__diag_domain(ads, serv,
qu, &qu->vb,
dgram, dglen,
rdstart));
} else {
qu->cname_begin = rdstart;
qu->cname_dglen = dglen;
st = adns__parse_domain(ads, serv, qu,
&qu->vb,
qu->
flags &
adns_qf_quotefail_cname
? 0 : pdf_quoteok,
dgram, dglen,
&rdstart,
rdstart +
rdlength);
if (!qu->vb.used)
goto x_truncated;
if (st) {
adns__query_fail(qu, st);
return;
}
l = strlen(qu->vb.buf) + 1;
qu->answer->cname =
adns__alloc_preserved(qu, l);
if (!qu->answer->cname) {
adns__query_fail(qu,
adns_s_nomemory);
return;
}
/* Now what ? No relevant answers, no SOA, and at least some NS's.
* Looks like a referral. Just one last chance ... if we came across
* a CNAME in this datagram then we should probably do our own CNAME
* lookup now in the hope that we won't get a referral again.
*/
if (cname_here) goto x_restartquery;
qu->cname_dgram =
adns__alloc_mine(qu, dglen);
memcpy(qu->cname_dgram, dgram, dglen);
/* Bloody hell, I thought we asked for recursion ? */
if (!flg_ra) {
adns__diag(ads,serv,qu,"server is not willing to do recursive lookups for us");
adns__query_fail(qu,adns_s_norecurse);
} else {
if (!flg_rd)
adns__diag(ads,serv,qu,"server thinks we didn't ask for recursive lookup");
else
adns__debug(ads,serv,qu,"server claims to do recursion, but gave us a referral");
adns__query_fail(qu,adns_s_invalidresponse);
}
return;
}
memcpy(qu->answer->cname, qu->vb.buf, l);
cname_here = 1;
adns__update_expires(qu, ttl, now);
/* If we find the answer section truncated after this point we restart
* the query at the CNAME; if beforehand then we obviously have to use
* TCP. If there is no truncation we can use the whole answer if
* it contains the relevant info.
*/
}
} else if (rrtype ==
(qu->typei->type & adns__rrt_typemask)) {
wantedrrs++;
} else {
adns__debug(ads, serv, qu,
"ignoring answer RR with irrelevant type %d",
rrtype);
}
}
/* Now, we have some RRs which we wanted. */
/* We defer handling truncated responses here, in case there was a CNAME
* which we could use.
*/
if (flg_tc)
goto x_truncated;
qu->answer->rrs.untyped= adns__alloc_interim(qu,qu->typei->rrsz*wantedrrs);
if (!qu->answer->rrs.untyped) { adns__query_fail(qu,adns_s_nomemory); return; }
nsstart = cbyte;
typei= qu->typei;
cbyte= anstart;
rrsdata= qu->answer->rrs.bytes;
if (!wantedrrs) {
/* Oops, NODATA or NXDOMAIN or perhaps a referral (which would be a problem) */
pai.ads= qu->ads;
pai.qu= qu;
pai.serv= serv;
pai.dgram= dgram;
pai.dglen= dglen;
pai.nsstart= nsstart;
pai.nscount= nscount;
pai.arcount= arcount;
pai.now= now;
/* RFC2308: NODATA has _either_ a SOA _or_ _no_ NS records in authority section */
foundsoa = 0;
soattl = 0;
foundns = 0;
for (rri = 0; rri < nscount; rri++) {
rrstart = cbyte;
st = adns__findrr(qu, serv, dgram, dglen, &cbyte,
&rrtype, &rrclass, &ttl,
&rdlength, &rdstart, 0);
if (st) {
adns__query_fail(qu, st);
return;
}
if (rrtype == -1)
goto x_truncated;
if (rrclass != DNS_CLASS_IN) {
adns__diag(ads, serv, qu,
"ignoring authority RR with wrong class %d (expected IN=%d)",
rrclass, DNS_CLASS_IN);
continue;
}
if (rrtype == adns_r_soa_raw) {
foundsoa = 1;
soattl = ttl;
break;
} else if (rrtype == adns_r_ns_raw) {
foundns = 1;
}
}
for (rri=0, nrrs=0; rri<ancount; rri++) {
st= adns__findrr(qu,serv, dgram,dglen,&cbyte,
&rrtype,&rrclass,&ttl, &rdlength,&rdstart,
&ownermatched);
assert(!st); assert(rrtype != -1);
if (rrclass != DNS_CLASS_IN ||
rrtype != (qu->typei->type & adns__rrt_typemask) ||
!ownermatched)
continue;
adns__update_expires(qu,ttl,now);
st= typei->parse(&pai, rdstart,rdstart+rdlength, rrsdata+nrrs*typei->rrsz);
if (st) { adns__query_fail(qu,st); return; }
if (rdstart==-1) goto x_truncated;
nrrs++;
}
assert(nrrs==wantedrrs);
qu->answer->nrrs= nrrs;
if (rcode == rcode_nxdomain) {
/* We still wanted to look for the SOA so we could find the TTL. */
adns__update_expires(qu, soattl, now);
/* This may have generated some child queries ... */
if (qu->children.head) {
qu->state= query_childw;
LIST_LINK_TAIL(ads->childw,qu);
return;
}
adns__query_done(qu);
return;
if (qu->flags & adns_qf_search) {
adns__search_next(ads, qu, now);
} else {
adns__query_fail(qu, adns_s_nxdomain);
}
return;
}
x_truncated:
if (!flg_tc) {
adns__diag(ads,serv,qu,"server sent datagram which points outside itself");
adns__query_fail(qu,adns_s_invalidresponse);
return;
}
qu->flags |= adns_qf_usevc;
x_restartquery:
if (qu->cname_dgram) {
st= adns__mkquery_frdgram(qu->ads,&qu->vb,&qu->id,
qu->cname_dgram, qu->cname_dglen, qu->cname_begin,
qu->typei->type, qu->flags);
if (st) { adns__query_fail(qu,st); return; }
newquery= realloc(qu->query_dgram,qu->vb.used);
if (!newquery) { adns__query_fail(qu,adns_s_nomemory); return; }
qu->query_dgram= newquery;
qu->query_dglen= qu->vb.used;
memcpy(newquery,qu->vb.buf,qu->vb.used);
}
if (qu->state == query_tcpw) qu->state= query_tosend;
qu->retries= 0;
adns__reset_preserved(qu);
adns__query_send(qu,now);
if (foundsoa || !foundns) {
/* Aha ! A NODATA response, good. */
adns__update_expires(qu, soattl, now);
adns__query_fail(qu, adns_s_nodata);
return;
}
/* Now what ? No relevant answers, no SOA, and at least some NS's.
* Looks like a referral. Just one last chance ... if we came across
* a CNAME in this datagram then we should probably do our own CNAME
* lookup now in the hope that we won't get a referral again.
*/
if (cname_here)
goto x_restartquery;
/* Bloody hell, I thought we asked for recursion ? */
if (!flg_ra) {
adns__diag(ads, serv, qu,
"server is not willing to do recursive lookups for us");
adns__query_fail(qu, adns_s_norecurse);
} else {
if (!flg_rd)
adns__diag(ads, serv, qu,
"server thinks we didn't ask for recursive lookup");
else
adns__debug(ads, serv, qu,
"server claims to do recursion, but gave us a referral");
adns__query_fail(qu, adns_s_invalidresponse);
}
return;
}
/* Now, we have some RRs which we wanted. */
qu->answer->rrs.untyped =
adns__alloc_interim(qu, qu->typei->rrsz * wantedrrs);
if (!qu->answer->rrs.untyped) {
adns__query_fail(qu, adns_s_nomemory);
return;
}
typei = qu->typei;
cbyte = anstart;
rrsdata = qu->answer->rrs.bytes;
pai.ads = qu->ads;
pai.qu = qu;
pai.serv = serv;
pai.dgram = dgram;
pai.dglen = dglen;
pai.nsstart = nsstart;
pai.nscount = nscount;
pai.arcount = arcount;
pai.now = now;
for (rri = 0, nrrs = 0; rri < ancount; rri++) {
st = adns__findrr(qu, serv, dgram, dglen, &cbyte,
&rrtype, &rrclass, &ttl, &rdlength,
&rdstart, &ownermatched);
assert(!st);
assert(rrtype != -1);
if (rrclass != DNS_CLASS_IN ||
rrtype != (qu->typei->type & adns__rrt_typemask) ||
!ownermatched)
continue;
adns__update_expires(qu, ttl, now);
st = typei->parse(&pai, rdstart, rdstart + rdlength,
rrsdata + nrrs * typei->rrsz);
if (st) {
adns__query_fail(qu, st);
return;
}
if (rdstart == -1)
goto x_truncated;
nrrs++;
}
assert(nrrs == wantedrrs);
qu->answer->nrrs = nrrs;
/* This may have generated some child queries ... */
if (qu->children.head) {
qu->state = query_childw;
LIST_LINK_TAIL(ads->childw, qu);
return;
}
adns__query_done(qu);
return;
x_truncated:
if (!flg_tc) {
adns__diag(ads, serv, qu,
"server sent datagram which points outside itself");
adns__query_fail(qu, adns_s_invalidresponse);
return;
}
qu->flags |= adns_qf_usevc;
x_restartquery:
if (qu->cname_dgram) {
st = adns__mkquery_frdgram(qu->ads, &qu->vb, &qu->id,
qu->cname_dgram,
qu->cname_dglen,
qu->cname_begin,
qu->typei->type, qu->flags);
if (st) {
adns__query_fail(qu, st);
return;
}
newquery = realloc(qu->query_dgram, qu->vb.used);
if (!newquery) {
adns__query_fail(qu, adns_s_nomemory);
return;
}
qu->query_dgram = newquery;
qu->query_dglen = qu->vb.used;
memcpy(newquery, qu->vb.buf, qu->vb.used);
}
if (qu->state == query_tcpw)
qu->state = query_tosend;
qu->retries = 0;
adns__reset_preserved(qu);
adns__query_send(qu, now);
}

File diff suppressed because it is too large Load diff

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: transmit.c,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
** $Id: transmit.c,v 1.3 2003/06/13 14:44:36 fishwaldo Exp $
*/
/*
* transmit.c
@ -61,221 +61,269 @@
#define MKQUERY_ADDW(w) (MKQUERY_ADDB(((w)>>8)&0x0ff), MKQUERY_ADDB((w)&0x0ff))
#define MKQUERY_STOP(vb) ((vb)->used= rqp-(vb)->buf)
static adns_status mkquery_header(adns_state ads, vbuf *vb, int *id_r, int qdlen) {
int id;
byte *rqp;
if (!adns__vbuf_ensure(vb,DNS_HDRSIZE+qdlen+4)) return adns_s_nomemory;
static adns_status mkquery_header(adns_state ads, vbuf * vb, int *id_r,
int qdlen)
{
int id;
byte *rqp;
vb->used= 0;
MKQUERY_START(vb);
*id_r= id= (ads->nextid++) & 0x0ffff;
MKQUERY_ADDW(id);
MKQUERY_ADDB(0x01); /* QR=Q(0), OPCODE=QUERY(0000), !AA, !TC, RD */
MKQUERY_ADDB(0x00); /* !RA, Z=000, RCODE=NOERROR(0000) */
MKQUERY_ADDW(1); /* QDCOUNT=1 */
MKQUERY_ADDW(0); /* ANCOUNT=0 */
MKQUERY_ADDW(0); /* NSCOUNT=0 */
MKQUERY_ADDW(0); /* ARCOUNT=0 */
if (!adns__vbuf_ensure(vb, DNS_HDRSIZE + qdlen + 4))
return adns_s_nomemory;
MKQUERY_STOP(vb);
return adns_s_ok;
vb->used = 0;
MKQUERY_START(vb);
*id_r = id = (ads->nextid++) & 0x0ffff;
MKQUERY_ADDW(id);
MKQUERY_ADDB(0x01); /* QR=Q(0), OPCODE=QUERY(0000), !AA, !TC, RD */
MKQUERY_ADDB(0x00); /* !RA, Z=000, RCODE=NOERROR(0000) */
MKQUERY_ADDW(1); /* QDCOUNT=1 */
MKQUERY_ADDW(0); /* ANCOUNT=0 */
MKQUERY_ADDW(0); /* NSCOUNT=0 */
MKQUERY_ADDW(0); /* ARCOUNT=0 */
MKQUERY_STOP(vb);
return adns_s_ok;
}
static adns_status mkquery_footer(vbuf *vb, adns_rrtype type) {
byte *rqp;
static adns_status mkquery_footer(vbuf * vb, adns_rrtype type)
{
byte *rqp;
MKQUERY_START(vb);
MKQUERY_ADDW(type & adns__rrt_typemask); /* QTYPE */
MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */
MKQUERY_STOP(vb);
assert(vb->used <= vb->avail);
return adns_s_ok;
MKQUERY_START(vb);
MKQUERY_ADDW(type & adns__rrt_typemask); /* QTYPE */
MKQUERY_ADDW(DNS_CLASS_IN); /* QCLASS=IN */
MKQUERY_STOP(vb);
assert(vb->used <= vb->avail);
return adns_s_ok;
}
adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
adns_status adns__mkquery(adns_state ads, vbuf * vb, int *id_r,
const char *owner, int ol,
const typeinfo *typei, adns_queryflags flags) {
int ll, c, nbytes;
byte label[255], *rqp;
const char *p, *pe;
adns_status st;
const typeinfo * typei, adns_queryflags flags)
{
int ll, c, nbytes;
byte label[255], *rqp;
const char *p, *pe;
adns_status st;
st= mkquery_header(ads,vb,id_r,ol+2); if (st) return st;
MKQUERY_START(vb);
st = mkquery_header(ads, vb, id_r, ol + 2);
if (st)
return st;
p= owner; pe= owner+ol;
nbytes= 0;
while (p!=pe) {
ll= 0;
while (p!=pe && (c= *p++)!='.') {
if (c=='\\') {
if (!(flags & adns_qf_quoteok_query)) return adns_s_querydomaininvalid;
if (ctype_digit(p[0])) {
if (ctype_digit(p[1]) && ctype_digit(p[2])) {
c= (*p++ - '0')*100 + (*p++ - '0')*10 + (*p++ - '0');
if (c >= 256) return adns_s_querydomaininvalid;
} else {
return adns_s_querydomaininvalid;
}
} else if (!(c= *p++)) {
return adns_s_querydomaininvalid;
MKQUERY_START(vb);
p = owner;
pe = owner + ol;
nbytes = 0;
while (p != pe) {
ll = 0;
while (p != pe && (c = *p++) != '.') {
if (c == '\\') {
if (!(flags & adns_qf_quoteok_query))
return adns_s_querydomaininvalid;
if (ctype_digit(p[0])) {
if (ctype_digit(p[1])
&& ctype_digit(p[2])) {
c = (*p++ - '0') * 100 +
(*p++ - '0') * 10 +
(*p++ - '0');
if (c >= 256)
return
adns_s_querydomaininvalid;
} else {
return
adns_s_querydomaininvalid;
}
} else if (!(c = *p++)) {
return adns_s_querydomaininvalid;
}
}
if (!(flags & adns_qf_quoteok_query)) {
if (c == '-') {
if (!ll)
return
adns_s_querydomaininvalid;
} else if (!ctype_alpha(c)
&& !ctype_digit(c)) {
return adns_s_querydomaininvalid;
}
}
if (ll == sizeof(label))
return adns_s_querydomaininvalid;
label[ll++] = c;
}
if (!ll)
return adns_s_querydomaininvalid;
if (ll > DNS_MAXLABEL)
return adns_s_querydomaintoolong;
nbytes += ll + 1;
if (nbytes >= DNS_MAXDOMAIN)
return adns_s_querydomaintoolong;
MKQUERY_ADDB(ll);
memcpy(rqp, label, ll);
rqp += ll;
}
}
if (!(flags & adns_qf_quoteok_query)) {
if (c == '-') {
if (!ll) return adns_s_querydomaininvalid;
} else if (!ctype_alpha(c) && !ctype_digit(c)) {
return adns_s_querydomaininvalid;
MKQUERY_ADDB(0);
MKQUERY_STOP(vb);
st = mkquery_footer(vb, typei->type);
return adns_s_ok;
}
adns_status adns__mkquery_frdgram(adns_state ads, vbuf * vb, int *id_r,
const byte * qd_dgram, int qd_dglen,
int qd_begin, adns_rrtype type,
adns_queryflags flags)
{
byte *rqp;
findlabel_state fls;
int lablen, labstart;
adns_status st;
st = mkquery_header(ads, vb, id_r, qd_dglen);
if (st)
return st;
MKQUERY_START(vb);
adns__findlabel_start(&fls, ads, -1, 0, qd_dgram, qd_dglen,
qd_dglen, qd_begin, 0);
for (;;) {
st = adns__findlabel_next(&fls, &lablen, &labstart);
assert(!st);
if (!lablen)
break;
assert(lablen < 255);
MKQUERY_ADDB(lablen);
memcpy(rqp, qd_dgram + labstart, lablen);
rqp += lablen;
}
}
if (ll == sizeof(label)) return adns_s_querydomaininvalid;
label[ll++]= c;
}
if (!ll) return adns_s_querydomaininvalid;
if (ll > DNS_MAXLABEL) return adns_s_querydomaintoolong;
nbytes+= ll+1;
if (nbytes >= DNS_MAXDOMAIN) return adns_s_querydomaintoolong;
MKQUERY_ADDB(ll);
memcpy(rqp,label,ll); rqp+= ll;
}
MKQUERY_ADDB(0);
MKQUERY_ADDB(0);
MKQUERY_STOP(vb);
st= mkquery_footer(vb,typei->type);
return adns_s_ok;
MKQUERY_STOP(vb);
st = mkquery_footer(vb, type);
return adns_s_ok;
}
adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
const byte *qd_dgram, int qd_dglen, int qd_begin,
adns_rrtype type, adns_queryflags flags) {
byte *rqp;
findlabel_state fls;
int lablen, labstart;
adns_status st;
void adns__querysend_tcp(adns_query qu, struct timeval now)
{
byte length[2];
struct iovec iov[2];
int wr, r;
adns_state ads;
st= mkquery_header(ads,vb,id_r,qd_dglen); if (st) return st;
if (qu->ads->tcpstate != server_ok)
return;
MKQUERY_START(vb);
assert(qu->state == query_tcpw);
adns__findlabel_start(&fls,ads,-1,0,qd_dgram,qd_dglen,qd_dglen,qd_begin,0);
for (;;) {
st= adns__findlabel_next(&fls,&lablen,&labstart); assert(!st);
if (!lablen) break;
assert(lablen<255);
MKQUERY_ADDB(lablen);
memcpy(rqp,qd_dgram+labstart,lablen);
rqp+= lablen;
}
MKQUERY_ADDB(0);
length[0] = (qu->query_dglen & 0x0ff00U) >> 8;
length[1] = (qu->query_dglen & 0x0ff);
MKQUERY_STOP(vb);
st= mkquery_footer(vb,type);
return adns_s_ok;
ads = qu->ads;
if (!adns__vbuf_ensure
(&ads->tcpsend, ads->tcpsend.used + qu->query_dglen + 2))
return;
qu->retries++;
/* Reset idle timeout. */
ads->tcptimeout.tv_sec = ads->tcptimeout.tv_usec = 0;
if (ads->tcpsend.used) {
wr = 0;
} else {
iov[0].iov_base = length;
iov[0].iov_len = 2;
iov[1].iov_base = qu->query_dgram;
iov[1].iov_len = qu->query_dglen;
adns__sigpipe_protect(qu->ads);
wr = writev(qu->ads->tcpsocket, iov, 2);
adns__sigpipe_unprotect(qu->ads);
if (wr < 0) {
if (!
(errno == EAGAIN || errno == EINTR
|| errno == ENOSPC || errno == ENOBUFS
|| errno == ENOMEM)) {
adns__tcp_broken(ads, "write",
strerror(errno));
return;
}
wr = 0;
}
}
if (wr < 2) {
r = adns__vbuf_append(&ads->tcpsend, length, 2 - wr);
assert(r);
wr = 0;
} else {
wr -= 2;
}
if (wr < qu->query_dglen) {
r = adns__vbuf_append(&ads->tcpsend, qu->query_dgram + wr,
qu->query_dglen - wr);
assert(r);
}
}
void adns__querysend_tcp(adns_query qu, struct timeval now) {
byte length[2];
struct iovec iov[2];
int wr, r;
adns_state ads;
if (qu->ads->tcpstate != server_ok) return;
assert(qu->state == query_tcpw);
length[0]= (qu->query_dglen&0x0ff00U) >>8;
length[1]= (qu->query_dglen&0x0ff);
ads= qu->ads;
if (!adns__vbuf_ensure(&ads->tcpsend,ads->tcpsend.used+qu->query_dglen+2)) return;
qu->retries++;
/* Reset idle timeout. */
ads->tcptimeout.tv_sec= ads->tcptimeout.tv_usec= 0;
if (ads->tcpsend.used) {
wr= 0;
} else {
iov[0].iov_base= length;
iov[0].iov_len= 2;
iov[1].iov_base= qu->query_dgram;
iov[1].iov_len= qu->query_dglen;
adns__sigpipe_protect(qu->ads);
wr= writev(qu->ads->tcpsocket,iov,2);
adns__sigpipe_unprotect(qu->ads);
if (wr < 0) {
if (!(errno == EAGAIN || errno == EINTR || errno == ENOSPC ||
errno == ENOBUFS || errno == ENOMEM)) {
adns__tcp_broken(ads,"write",strerror(errno));
return;
}
wr= 0;
}
}
if (wr<2) {
r= adns__vbuf_append(&ads->tcpsend,length,2-wr); assert(r);
wr= 0;
} else {
wr-= 2;
}
if (wr<qu->query_dglen) {
r= adns__vbuf_append(&ads->tcpsend,qu->query_dgram+wr,qu->query_dglen-wr); assert(r);
}
static void query_usetcp(adns_query qu, struct timeval now)
{
qu->state = query_tcpw;
qu->timeout = now;
timevaladd(&qu->timeout, TCPWAITMS);
LIST_LINK_TAIL(qu->ads->tcpw, qu);
adns__querysend_tcp(qu, now);
adns__tcp_tryconnect(qu->ads, now);
}
static void query_usetcp(adns_query qu, struct timeval now) {
qu->state= query_tcpw;
qu->timeout= now;
timevaladd(&qu->timeout,TCPWAITMS);
LIST_LINK_TAIL(qu->ads->tcpw,qu);
adns__querysend_tcp(qu,now);
adns__tcp_tryconnect(qu->ads,now);
}
void adns__query_send(adns_query qu, struct timeval now) {
struct sockaddr_in servaddr;
int serv, r;
adns_state ads;
assert(qu->state == query_tosend);
if ((qu->flags & adns_qf_usevc) || (qu->query_dglen > DNS_MAXUDP)) {
query_usetcp(qu,now);
return;
}
if (qu->retries >= UDPMAXRETRIES) {
adns__query_fail(qu,adns_s_timeout);
return;
}
serv= qu->udpnextserver;
memset(&servaddr,0,sizeof(servaddr));
ads= qu->ads;
servaddr.sin_family= AF_INET;
servaddr.sin_addr= ads->servers[serv].addr;
servaddr.sin_port= htons(DNS_PORT);
r= sendto(ads->udpsocket,qu->query_dgram,qu->query_dglen,0,
(const struct sockaddr*)&servaddr,sizeof(servaddr));
if (r<0 && errno == EMSGSIZE) { qu->retries= 0; query_usetcp(qu,now); return; }
if (r<0 && errno != EAGAIN) adns__warn(ads,serv,0,"sendto failed: %s",strerror(errno));
qu->timeout= now;
timevaladd(&qu->timeout,UDPRETRYMS);
qu->udpsent |= (1<<serv);
qu->udpnextserver= (serv+1)%ads->nservers;
qu->retries++;
LIST_LINK_TAIL(ads->udpw,qu);
void adns__query_send(adns_query qu, struct timeval now)
{
struct sockaddr_in servaddr;
int serv, r;
adns_state ads;
assert(qu->state == query_tosend);
if ((qu->flags & adns_qf_usevc) || (qu->query_dglen > DNS_MAXUDP)) {
query_usetcp(qu, now);
return;
}
if (qu->retries >= UDPMAXRETRIES) {
adns__query_fail(qu, adns_s_timeout);
return;
}
serv = qu->udpnextserver;
memset(&servaddr, 0, sizeof(servaddr));
ads = qu->ads;
servaddr.sin_family = AF_INET;
servaddr.sin_addr = ads->servers[serv].addr;
servaddr.sin_port = htons(DNS_PORT);
r = sendto(ads->udpsocket, qu->query_dgram, qu->query_dglen, 0,
(const struct sockaddr *) &servaddr, sizeof(servaddr));
if (r < 0 && errno == EMSGSIZE) {
qu->retries = 0;
query_usetcp(qu, now);
return;
}
if (r < 0 && errno != EAGAIN)
adns__warn(ads, serv, 0, "sendto failed: %s",
strerror(errno));
qu->timeout = now;
timevaladd(&qu->timeout, UDPRETRYMS);
qu->udpsent |= (1 << serv);
qu->udpnextserver = (serv + 1) % ads->nservers;
qu->retries++;
LIST_LINK_TAIL(ads->udpw, qu);
}

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: tvarith.h,v 1.2 2003/05/26 09:18:29 fishwaldo Exp $
** $Id: tvarith.h,v 1.3 2003/06/13 14:44:36 fishwaldo Exp $
*/
/*
* tvarith.h
@ -50,14 +50,18 @@
#ifndef ADNS_TVARITH_H_INCLUDED
#define ADNS_TVARITH_H_INCLUDED
static inline void timevaladd(struct timeval *tv_io, long ms) {
struct timeval tmp;
assert(ms>=0);
tmp= *tv_io;
tmp.tv_usec += (ms%1000)*1000;
tmp.tv_sec += ms/1000;
if (tmp.tv_usec >= 1000000) { tmp.tv_sec++; tmp.tv_usec -= 1000000; }
*tv_io= tmp;
static inline void timevaladd(struct timeval *tv_io, long ms)
{
struct timeval tmp;
assert(ms >= 0);
tmp = *tv_io;
tmp.tv_usec += (ms % 1000) * 1000;
tmp.tv_sec += ms / 1000;
if (tmp.tv_usec >= 1000000) {
tmp.tv_sec++;
tmp.tv_usec -= 1000000;
}
*tv_io = tmp;
}
#endif

File diff suppressed because it is too large Load diff

1
keeper/.indent.pro vendored Normal file
View file

@ -0,0 +1 @@
-br -ce -ts8 -kr -i8 -ut -v

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: keeper.h,v 1.2 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: keeper.h,v 1.3 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -46,22 +46,22 @@
#define _KEEPER_H
typedef enum {
KPVAL_UNKNOWN = -1,
KPVAL_DIR,
KPVAL_DATA,
KPVAL_STRING,
KPVAL_INT,
KPVAL_FLOAT
KPVAL_UNKNOWN = -1,
KPVAL_DIR,
KPVAL_DATA,
KPVAL_STRING,
KPVAL_INT,
KPVAL_FLOAT
} kpval_t;
typedef enum {
KPERR_OK, /* OK */
KPERR_NOKEY, /* Key does not exist */
KPERR_NOACCES, /* Access denied */
KPERR_BADKEY, /* Bad key */
KPERR_BADTYPE, /* Bad type */
KPERR_BADDB, /* Bad database */
KPERR_NOSPACE /* Not enough resources */
KPERR_OK, /* OK */
KPERR_NOKEY, /* Key does not exist */
KPERR_NOACCES, /* Access denied */
KPERR_BADKEY, /* Bad key */
KPERR_BADTYPE, /* Bad type */
KPERR_BADDB, /* Bad database */
KPERR_NOSPACE /* Not enough resources */
} kperr_t;
#ifdef __cplusplus
@ -71,52 +71,55 @@ extern "C" {
/* ==== Basic functions ==== */
/* Get functions */
int kp_get_string (const char *keypath, char **stringp);
int kp_get_int (const char *keypath, int *intp);
int kp_get_float (const char *keypath, double *floatp);
int kp_get_data (const char *keypath, void **datap, unsigned int *lenp);
int kp_get_dir (const char *keypath, char ***keysp, unsigned int *nump);
int kp_get_string(const char *keypath, char **stringp);
int kp_get_int(const char *keypath, int *intp);
int kp_get_float(const char *keypath, double *floatp);
int kp_get_data(const char *keypath, void **datap,
unsigned int *lenp);
int kp_get_dir(const char *keypath, char ***keysp,
unsigned int *nump);
/* Set functions */
int kp_set_string (const char *keypath, const char *string);
int kp_set_int (const char *keypath, int intval);
int kp_set_float (const char *keypath, double floatval);
int kp_set_data (const char *keypath, const void *data, unsigned int len);
int kp_set_string(const char *keypath, const char *string);
int kp_set_int(const char *keypath, int intval);
int kp_set_float(const char *keypath, double floatval);
int kp_set_data(const char *keypath, const void *data,
unsigned int len);
/* Misc functions */
int kp_remove (const char *keypath);
int kp_flush (void);
int kp_get_type (const char *keypath, kpval_t *typep);
char *kp_strerror (int kperr);
int kp_remove(const char *keypath);
int kp_flush(void);
int kp_get_type(const char *keypath, kpval_t * typep);
char *kp_strerror(int kperr);
/* ==== Utility functions ==== */
/* Directory utils */
typedef struct _KPDIR KPDIR;
typedef struct _KPDIR KPDIR;
#define KP_P(kpdir, subkey) kp_dir_getpath(kpdir, subkey)
KPDIR *kp_dir_open (const char *keypath);
const char *kp_dir_getpath (KPDIR *kpdir, const char *subkey);
void kp_dir_close (KPDIR *kpdir);
KPDIR *kp_dir_open(const char *keypath);
const char *kp_dir_getpath(KPDIR * kpdir, const char *subkey);
void kp_dir_close(KPDIR * kpdir);
/* Enum utils */
int kp_get_enum (const char *keypath, const char *names[], int *valp);
int kp_set_enum (const char *keypath, const char *names[], int val);
int kp_get_enum(const char *keypath, const char *names[],
int *valp);
int kp_set_enum(const char *keypath, const char *names[], int val);
int kp_get_bool (const char *keypath, int *boolp);
int kp_set_bool (const char *keypath, int boolval);
int kp_get_bool(const char *keypath, int *boolp);
int kp_set_bool(const char *keypath, int boolval);
/* Sort keys in alphabetical order */
void kp_sort_keys (char **keys, unsigned int numkeys);
void kp_sort_keys(char **keys, unsigned int numkeys);
/* Do a function on all subkeys*/
typedef int (*kp_func) (const char *key, void *user_data);
int kp_recursive_do(const char *key, kp_func func, int stop_on_err,
void *user_data);
typedef int (*kp_func) (const char *key, void *user_data);
int kp_recursive_do(const char *key, kp_func func, int stop_on_err,
void *user_data);
#ifdef __cplusplus
}
#endif
#endif /* _KEEPER_H */
#endif /* _KEEPER_H */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_cache.c,v 1.3 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_cache.c,v 1.4 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -51,13 +51,13 @@
/* One physical file's cached data */
typedef struct _kp_fil {
kp_path kpp;
kp_key *keys;
int dirty;
time_t modif;
time_t use;
time_t check;
struct _kp_fil *next;
kp_path kpp;
kp_key *keys;
int dirty;
time_t modif;
time_t use;
time_t check;
struct _kp_fil *next;
} kp_fil;
/* The cache */
@ -66,82 +66,82 @@ static kp_fil *kp_cachef = NULL;
/* -------------------------------------------------------------------------
* Free a key list
* ------------------------------------------------------------------------- */
static void kp_free_keys(kp_key *k)
static void kp_free_keys(kp_key * k)
{
kp_key *nextk;
kp_key *nextk;
while(k != NULL) {
nextk = k->next;
kp_value_destroy(k);
free(k);
k = nextk;
}
while (k != NULL) {
nextk = k->next;
kp_value_destroy(k);
free(k);
k = nextk;
}
}
/* -------------------------------------------------------------------------
* If the file is in the cache, return it, otherwise return NULL
* ------------------------------------------------------------------------- */
static kp_fil *kp_get_cached_file(kp_path *kpp)
static kp_fil *kp_get_cached_file(kp_path * kpp)
{
kp_fil *fil;
char *path = kpp->path;
kp_fil *fil;
char *path = kpp->path;
for(fil = kp_cachef; fil != NULL; fil = fil->next)
if(strcmp(fil->kpp.path, path) == 0)
break;
for (fil = kp_cachef; fil != NULL; fil = fil->next)
if (strcmp(fil->kpp.path, path) == 0)
break;
return fil;
return fil;
}
/* -------------------------------------------------------------------------
* Create a new chaced file, and insert it into the cache
* ------------------------------------------------------------------------- */
static kp_fil *kp_new_cached_file(kp_path *kpp)
static kp_fil *kp_new_cached_file(kp_path * kpp)
{
kp_fil *fil;
kp_fil *fil;
fil = (kp_fil *) malloc_check(sizeof(kp_fil));
fil->kpp.path = strdup_check(kpp->path);
fil->kpp.dbindex = kpp->dbindex;
fil->keys = NULL;
fil->dirty = 0;
fil->modif = 0;
fil->use = 0;
fil->check = 0;
fil->next = kp_cachef;
kp_cachef = fil;
fil = (kp_fil *) malloc_check(sizeof(kp_fil));
fil->kpp.path = strdup_check(kpp->path);
fil->kpp.dbindex = kpp->dbindex;
fil->keys = NULL;
fil->dirty = 0;
fil->modif = 0;
fil->use = 0;
fil->check = 0;
fil->next = kp_cachef;
kp_cachef = fil;
return fil;
return fil;
}
/* -------------------------------------------------------------------------
* Free data associated with a cached file
* ------------------------------------------------------------------------- */
static void kp_free_file(kp_fil *fil)
static void kp_free_file(kp_fil * fil)
{
free(fil->kpp.path);
kp_free_keys(fil->keys);
free(fil);
free(fil->kpp.path);
kp_free_keys(fil->keys);
free(fil);
}
/* -------------------------------------------------------------------------
* Remove a file from a cache and free it
* ------------------------------------------------------------------------- */
static void kp_remove_file_from_cache(kp_fil *rfil)
static void kp_remove_file_from_cache(kp_fil * rfil)
{
kp_fil **filp;
kp_fil **filp;
for(filp = &kp_cachef; *filp != NULL; filp = &(*filp)->next) {
if(*filp == rfil) {
*filp = rfil->next;
kp_free_file(rfil);
return;
}
}
for (filp = &kp_cachef; *filp != NULL; filp = &(*filp)->next) {
if (*filp == rfil) {
*filp = rfil->next;
kp_free_file(rfil);
return;
}
}
/* Should never happen */
fprintf(stderr, "keeper: Internal Error: Corrupted cache data\n");
abort();
/* Should never happen */
fprintf(stderr, "keeper: Internal Error: Corrupted cache data\n");
abort();
}
#ifdef ALLOC_CHECK
@ -150,8 +150,8 @@ static void kp_remove_file_from_cache(kp_fil *rfil)
* ------------------------------------------------------------------------- */
void _kp_clear_cache(void)
{
while(kp_cachef != NULL)
kp_remove_file_from_cache(kp_cachef);
while (kp_cachef != NULL)
kp_remove_file_from_cache(kp_cachef);
}
#endif
@ -160,54 +160,54 @@ void _kp_clear_cache(void)
* ------------------------------------------------------------------------- */
static void kp_clean_up_cache(time_t now)
{
kp_fil **filp;
kp_fil *fil;
time_t expire;
kp_fil **filp;
kp_fil *fil;
time_t expire;
expire = now - 10;
expire = now - 10;
for(filp = &kp_cachef; *filp != NULL;) {
fil = *filp;
if(fil->use < expire && !fil->dirty) {
*filp = fil->next;
kp_free_file(fil);
}
else
filp = &(*filp)->next;
}
for (filp = &kp_cachef; *filp != NULL;) {
fil = *filp;
if (fil->use < expire && !fil->dirty) {
*filp = fil->next;
kp_free_file(fil);
} else
filp = &(*filp)->next;
}
}
/* -------------------------------------------------------------------------
* If the key is in the cached file, return it, otherwise return NULL
* ------------------------------------------------------------------------- */
static kp_key *kp_get_cached_key(kp_fil *fil, const char *name)
static kp_key *kp_get_cached_key(kp_fil * fil, const char *name)
{
kp_key *key;
kp_key *key;
for(key = fil->keys; key != NULL; key = key->next)
if(strcmp(key->name, name) == 0)
break;
for (key = fil->keys; key != NULL; key = key->next)
if (strcmp(key->name, name) == 0)
break;
return key;
return key;
}
/* -------------------------------------------------------------------------
* Find a key in a cached file. If it exists return it. If there exists a
* subkey of it, or it is a subkey of one, then return an error
* ------------------------------------------------------------------------- */
static int kp_check_insert(kp_fil *fil, char *name, kp_key **keyretp)
static int kp_check_insert(kp_fil * fil, char *name, kp_key ** keyretp)
{
kp_key *key;
kp_key *key;
for(key = fil->keys; key != NULL; key = key->next) {
if(strcmp(key->name, name) == 0)
break;
if(kp_is_subkey(name, key->name) || kp_is_subkey(key->name, name))
return KPERR_BADKEY;
}
for (key = fil->keys; key != NULL; key = key->next) {
if (strcmp(key->name, name) == 0)
break;
if (kp_is_subkey(name, key->name)
|| kp_is_subkey(key->name, name))
return KPERR_BADKEY;
}
*keyretp = key;
return 0;
*keyretp = key;
return 0;
}
/* -------------------------------------------------------------------------
@ -215,309 +215,308 @@ static int kp_check_insert(kp_fil *fil, char *name, kp_key **keyretp)
* was outdated, then it reads it into the cache. If the path was refering
* to a directory, then it returns this in the *isdirp flag.
* ------------------------------------------------------------------------- */
static int kp_get_file(kp_path *kpp, kp_fil **fp, int *isdirp)
static int kp_get_file(kp_path * kpp, kp_fil ** fp, int *isdirp)
{
kp_fil *fil;
int res;
struct stat stbuf;
time_t now;
kp_fil *fil;
int res;
struct stat stbuf;
time_t now;
*fp = NULL;
*isdirp = 0;
*fp = NULL;
*isdirp = 0;
fil = kp_get_cached_file(kpp);
now = time(NULL);
fil = kp_get_cached_file(kpp);
now = time(NULL);
/* This check-magic is needed, because stat()-ing nonexistent
files on NFS seems to be very expensive on some (Solaris)
architectures */
/* This check-magic is needed, because stat()-ing nonexistent
files on NFS seems to be very expensive on some (Solaris)
architectures */
/* If the file was checked less then one second ago, then we
believe it hasn't changed. */
/* If the file was checked less then one second ago, then we
believe it hasn't changed. */
/* FIXME: even if the file is dirty, the non-dirty keys should be
updated from a changed file. This is not very important
though. */
/* FIXME: even if the file is dirty, the non-dirty keys should be
updated from a changed file. This is not very important
though. */
if(fil != NULL && !fil->dirty && now != fil->check) {
res = stat(kpp->path, &stbuf);
if (fil != NULL && !fil->dirty && now != fil->check) {
res = stat(kpp->path, &stbuf);
if(fil->keys == NULL && res == -1 && errno == ENOENT)
fil->check = now;
else if(res == -1 || !S_ISREG(stbuf.st_mode) ||
stbuf.st_mtime != fil->modif) {
kp_remove_file_from_cache(fil);
fil = NULL;
}
else
fil->check = now;
}
if (fil->keys == NULL && res == -1 && errno == ENOENT)
fil->check = now;
else if (res == -1 || !S_ISREG(stbuf.st_mode) ||
stbuf.st_mtime != fil->modif) {
kp_remove_file_from_cache(fil);
fil = NULL;
} else
fil->check = now;
}
if(fil != NULL)
fil->use = now;
else {
kp_key *keys = NULL;
if (fil != NULL)
fil->use = now;
else {
kp_key *keys = NULL;
/* Clean up old cached files */
kp_clean_up_cache(now);
/* Clean up old cached files */
kp_clean_up_cache(now);
res = stat(kpp->path, &stbuf);
if(res != 0)
res = _kp_errno_to_kperr(errno);
else if(!S_ISREG(stbuf.st_mode)) {
res = KPERR_BADKEY;
if(S_ISDIR(stbuf.st_mode))
*isdirp = 1;
}
else {
res = _kp_read_file(kpp->path, &keys);
if(res == 0) {
res = stat(kpp->path, &stbuf);
if(res == -1) {
kp_free_keys(keys);
res = _kp_errno_to_kperr(errno);
}
}
}
res = stat(kpp->path, &stbuf);
if (res != 0)
res = _kp_errno_to_kperr(errno);
else if (!S_ISREG(stbuf.st_mode)) {
res = KPERR_BADKEY;
if (S_ISDIR(stbuf.st_mode))
*isdirp = 1;
} else {
res = _kp_read_file(kpp->path, &keys);
if (res == 0) {
res = stat(kpp->path, &stbuf);
if (res == -1) {
kp_free_keys(keys);
res = _kp_errno_to_kperr(errno);
}
}
}
/* We cache nonexistent files also */
if(res != 0 && res != KPERR_NOKEY)
return res;
/* We cache nonexistent files also */
if (res != 0 && res != KPERR_NOKEY)
return res;
fil = kp_new_cached_file(kpp);
now = time(NULL);
fil = kp_new_cached_file(kpp);
now = time(NULL);
fil->use = now;
fil->check = now;
fil->use = now;
fil->check = now;
if(res == 0) {
fil->keys = keys;
fil->modif = stbuf.st_mtime;
}
}
*fp = fil;
if (res == 0) {
fil->keys = keys;
fil->modif = stbuf.st_mtime;
}
}
*fp = fil;
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Set a key in the cache. If it exists overwrite it, if not, then create
* it. Removed (negative) keys are also inserted into the cache.
* ------------------------------------------------------------------------- */
int _kp_cache_set(kp_path *kpp, kp_key *ck)
int _kp_cache_set(kp_path * kpp, kp_key * ck)
{
kp_fil *fil;
kp_key *key;
int res;
int isdir;
kp_fil *fil;
kp_key *key;
int res;
int isdir;
res = kp_get_file(kpp, &fil, &isdir);
if(res != 0)
return res;
res = kp_get_file(kpp, &fil, &isdir);
if (res != 0)
return res;
if((ck->flags & KPFL_REMOVED) != 0) {
key = kp_get_cached_key(fil, ck->name);
if ((ck->flags & KPFL_REMOVED) != 0) {
key = kp_get_cached_key(fil, ck->name);
if(key == NULL)
return KPERR_NOKEY;
}
if (key == NULL)
return KPERR_NOKEY;
}
if(!(ck->flags & KPFL_REMOVED)) {
res = kp_check_insert(fil, ck->name, &key);
if(res != 0)
return res;
}
if (!(ck->flags & KPFL_REMOVED)) {
res = kp_check_insert(fil, ck->name, &key);
if (res != 0)
return res;
}
fil->dirty = 1;
fil->dirty = 1;
if(key != NULL)
kp_value_destroy(key);
else {
key = (kp_key *) malloc_check(sizeof(kp_key));
key->next = fil->keys;
fil->keys = key;
}
if (key != NULL)
kp_value_destroy(key);
else {
key = (kp_key *) malloc_check(sizeof(kp_key));
key->next = fil->keys;
fil->keys = key;
}
key->type = ck->type;
key->len = ck->len;
key->data = ck->data;
key->name = ck->name;
key->flags = ck->flags;
key->flags |= KPFL_DIRTY;
key->type = ck->type;
key->len = ck->len;
key->data = ck->data;
key->name = ck->name;
key->flags = ck->flags;
key->flags |= KPFL_DIRTY;
/* Data is MOVED to key, not COPIED */
ck->data = NULL;
ck->name = NULL;
/* Data is MOVED to key, not COPIED */
ck->data = NULL;
ck->name = NULL;
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Get the value of a key from a given section
* ------------------------------------------------------------------------- */
int _kp_cache_get(kp_path *kpp, const char *keyname, kpval_t type, kp_key *ck)
int _kp_cache_get(kp_path * kpp, const char *keyname, kpval_t type,
kp_key * ck)
{
kp_fil *fil;
kp_key *key;
int res;
int isdir;
kp_fil *fil;
kp_key *key;
int res;
int isdir;
res = kp_get_file(kpp, &fil, &isdir);
if(res != 0)
return res;
res = kp_get_file(kpp, &fil, &isdir);
if (res != 0)
return res;
key = kp_get_cached_key(fil, keyname);
key = kp_get_cached_key(fil, keyname);
if(key == NULL || key->flags & KPFL_REMOVED)
return KPERR_NOKEY;
if (key == NULL || key->flags & KPFL_REMOVED)
return KPERR_NOKEY;
if(key->flags & KPFL_BADDB)
return KPERR_BADDB;
if (key->flags & KPFL_BADDB)
return KPERR_BADDB;
if(type != KPVAL_UNKNOWN && key->type != type)
return KPERR_BADTYPE;
if (type != KPVAL_UNKNOWN && key->type != type)
return KPERR_BADTYPE;
/* Data is COPIED */
kp_value_new(ck, key->type, key->len, key->data);
/* Data is COPIED */
kp_value_new(ck, key->type, key->len, key->data);
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Get the type of a key from a given section
* ------------------------------------------------------------------------- */
int _kp_cache_get_type(kp_path *kpp, char *keyname, int iskeyfile,
kpval_t *tp)
int _kp_cache_get_type(kp_path * kpp, char *keyname, int iskeyfile,
kpval_t * tp)
{
kp_fil *fil;
kp_key *key;
int res;
unsigned int keynamelen;
int isdir;
kp_fil *fil;
kp_key *key;
int res;
unsigned int keynamelen;
int isdir;
res = kp_get_file(kpp, &fil, &isdir);
if(isdir) {
if(iskeyfile)
return KPERR_BADKEY;
else {
*tp = KPVAL_DIR;
return 0;
}
}
if(res != 0)
return res;
res = kp_get_file(kpp, &fil, &isdir);
if (isdir) {
if (iskeyfile)
return KPERR_BADKEY;
else {
*tp = KPVAL_DIR;
return 0;
}
}
if (res != 0)
return res;
if(fil->keys == NULL)
return KPERR_NOKEY;
if (fil->keys == NULL)
return KPERR_NOKEY;
keynamelen = strlen(keyname);
keynamelen = strlen(keyname);
for(key = fil->keys; key != NULL; key = key->next) {
if(strcmp(key->name, keyname) == 0) {
for (key = fil->keys; key != NULL; key = key->next) {
if (strcmp(key->name, keyname) == 0) {
if(key->flags & KPFL_REMOVED)
return KPERR_NOKEY;
if (key->flags & KPFL_REMOVED)
return KPERR_NOKEY;
if(key->flags & KPFL_BADDB)
return KPERR_BADDB;
if (key->flags & KPFL_BADDB)
return KPERR_BADDB;
if(iskeyfile && keynamelen == 0)
return KPERR_BADKEY;
if (iskeyfile && keynamelen == 0)
return KPERR_BADKEY;
*tp = key->type;
return 0;
}
if(!(key->flags & KPFL_REMOVED)) {
if(keynamelen == 0) {
if(!iskeyfile)
return KPERR_BADKEY;
*tp = key->type;
return 0;
}
if (!(key->flags & KPFL_REMOVED)) {
if (keynamelen == 0) {
if (!iskeyfile)
return KPERR_BADKEY;
*tp = KPVAL_DIR;
return 0;
}
if(strncmp(key->name, keyname, keynamelen) == 0 &&
key->name[keynamelen] == '/') {
*tp = KPVAL_DIR;
return 0;
}
}
}
*tp = KPVAL_DIR;
return 0;
}
if (strncmp(key->name, keyname, keynamelen) == 0 &&
key->name[keynamelen] == '/') {
*tp = KPVAL_DIR;
return 0;
}
}
}
return KPERR_NOKEY;
return KPERR_NOKEY;
}
/* -------------------------------------------------------------------------
* Collect the subkeys of a given key in a file
* ------------------------------------------------------------------------- */
static int kp_get_subkeys_file(kp_path *kpp, const char *keyname,
struct key_array *keys)
static int kp_get_subkeys_file(kp_path * kpp, const char *keyname,
struct key_array *keys)
{
kp_fil *fil;
kp_key *key;
int res;
unsigned int keynamelen;
int found;
char *s;
char *ent;
int isdir;
kp_fil *fil;
kp_key *key;
int res;
unsigned int keynamelen;
int found;
char *s;
char *ent;
int isdir;
res = kp_get_file(kpp, &fil, &isdir);
if(res != 0)
return res;
res = kp_get_file(kpp, &fil, &isdir);
if (res != 0)
return res;
if(fil->keys == NULL)
return KPERR_NOKEY;
if (fil->keys == NULL)
return KPERR_NOKEY;
keynamelen = strlen(keyname);
keynamelen = strlen(keyname);
found = 0;
for(key = fil->keys; key != NULL; key = key->next) {
if((key->flags & KPFL_REMOVED) != 0)
continue;
found = 0;
for (key = fil->keys; key != NULL; key = key->next) {
if ((key->flags & KPFL_REMOVED) != 0)
continue;
if(keynamelen == 0 ||
(strlen(key->name) > keynamelen && key->name[keynamelen] == '/' &&
strncmp(key->name, keyname, keynamelen) == 0)) {
if (keynamelen == 0 ||
(strlen(key->name) > keynamelen
&& key->name[keynamelen] == '/'
&& strncmp(key->name, keyname, keynamelen) == 0)) {
s = key->name + keynamelen;
if(*s == '/')
s++;
s = key->name + keynamelen;
if (*s == '/')
s++;
ent = strdup_check(s);
s = ent;
while(*s && *s != '/' )
s++;
ent = strdup_check(s);
s = ent;
while (*s && *s != '/')
s++;
*s = '\0';
*s = '\0';
_kp_add_subkey_check(keys, ent);
free(ent);
_kp_add_subkey_check(keys, ent);
free(ent);
found = 1;
}
}
found = 1;
}
}
if(!found)
return KPERR_NOKEY;
if (!found)
return KPERR_NOKEY;
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Get the subkeys of a given key, from a directory or from a file
* ------------------------------------------------------------------------- */
int _kp_cache_get_subkeys(kp_path *kpp, const char *keypath, int iskeyfile,
struct key_array *keys)
int _kp_cache_get_subkeys(kp_path * kpp, const char *keypath,
int iskeyfile, struct key_array *keys)
{
int res;
int res;
if(!iskeyfile) {
res = _kp_get_subkeys_dir(kpp->path, keys);
}
else
res = kp_get_subkeys_file(kpp, keypath, keys);
if (!iskeyfile) {
res = _kp_get_subkeys_dir(kpp->path, keys);
} else
res = kp_get_subkeys_file(kpp, keypath, keys);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -525,25 +524,25 @@ int _kp_cache_get_subkeys(kp_path *kpp, const char *keypath, int iskeyfile,
* ------------------------------------------------------------------------- */
int _kp_cache_flush()
{
int res;
int finalres = 0;
kp_fil *fil;
int res;
int finalres = 0;
kp_fil *fil;
for(fil = kp_cachef; fil != NULL; fil = fil->next) {
if(fil->dirty) {
res = _kp_write_file(&fil->kpp, fil->keys);
for (fil = kp_cachef; fil != NULL; fil = fil->next) {
if (fil->dirty) {
res = _kp_write_file(&fil->kpp, fil->keys);
/* The return value of the flush will be the value of the
last error that occured */
/* The return value of the flush will be the value of the
last error that occured */
if(res != 0)
finalres = res;
if (res != 0)
finalres = res;
fil->dirty = 0;
}
}
fil->dirty = 0;
}
}
return finalres;
return finalres;
}
/* End of kp_cache.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_dir.c,v 1.2 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_dir.c,v 1.3 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -47,50 +47,50 @@
/* Structure containing the key path of the opened directory, and
the last returned subkey path. This structure is opaque to the user */
struct _KPDIR {
char *basepath;
char *retpath;
char *basepath;
char *retpath;
};
/* -------------------------------------------------------------------------
* Open a key directory
* ------------------------------------------------------------------------- */
KPDIR * kp_dir_open (const char *keypath)
KPDIR *kp_dir_open(const char *keypath)
{
KPDIR *kpdir;
KPDIR *kpdir;
kpdir = (KPDIR *) malloc_check(sizeof(KPDIR));
kpdir->basepath = strdup_check(keypath);
kpdir->retpath = NULL;
kpdir = (KPDIR *) malloc_check(sizeof(KPDIR));
kpdir->basepath = strdup_check(keypath);
kpdir->retpath = NULL;
return kpdir;
return kpdir;
}
/* -------------------------------------------------------------------------
* Append the subkey name to the base diretory, and return it. Free
* the previously used return string.
* ------------------------------------------------------------------------- */
const char * kp_dir_getpath (KPDIR *kpdir, const char *subkey)
const char *kp_dir_getpath(KPDIR * kpdir, const char *subkey)
{
if(kpdir != NULL) {
free(kpdir->retpath);
kpdir->retpath = (char *) malloc_check(strlen(kpdir->basepath)+1
+strlen(subkey)+1);
sprintf(kpdir->retpath, "%s/%s", kpdir->basepath, subkey);
if (kpdir != NULL) {
free(kpdir->retpath);
kpdir->retpath =
(char *) malloc_check(strlen(kpdir->basepath) + 1 +
strlen(subkey) + 1);
sprintf(kpdir->retpath, "%s/%s", kpdir->basepath, subkey);
return kpdir->retpath;
}
else
return subkey;
return kpdir->retpath;
} else
return subkey;
}
/* -------------------------------------------------------------------------
* Free all allocated space in this KPDIR structure
* ------------------------------------------------------------------------- */
void kp_dir_close (KPDIR *kpdir)
void kp_dir_close(KPDIR * kpdir)
{
free(kpdir->retpath);
free(kpdir->basepath);
free(kpdir);
free(kpdir->retpath);
free(kpdir->basepath);
free(kpdir);
}
/* End of kp_dir.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_enum.c,v 1.2 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_enum.c,v 1.3 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -50,25 +50,25 @@
* ------------------------------------------------------------------------- */
int kp_get_enum(const char *keypath, const char *names[], int *valp)
{
int res;
int i;
char *str = NULL;
int res;
int i;
char *str = NULL;
res = kp_get_string(keypath, &str);
if(res != 0)
return res;
res = kp_get_string(keypath, &str);
if (res != 0)
return res;
for(i = 0; names[i] != NULL; i++) {
if(strcmp(str, names[i]) == 0) {
*valp = i;
free(str);
return 0;
}
}
for (i = 0; names[i] != NULL; i++) {
if (strcmp(str, names[i]) == 0) {
*valp = i;
free(str);
return 0;
}
}
free(str);
free(str);
return KPERR_BADTYPE;
return KPERR_BADTYPE;
}
/* -------------------------------------------------------------------------
@ -76,15 +76,15 @@ int kp_get_enum(const char *keypath, const char *names[], int *valp)
* ------------------------------------------------------------------------- */
int kp_set_enum(const char *keypath, const char *names[], int val)
{
int i;
int i;
if(val >= 0) {
for(i = 0; names[i] != NULL; i++)
if(i == val)
return kp_set_string(keypath, names[val]);
}
if (val >= 0) {
for (i = 0; names[i] != NULL; i++)
if (i == val)
return kp_set_string(keypath, names[val]);
}
return KPERR_BADTYPE;
return KPERR_BADTYPE;
}
static const char *kp_boolnames[] = { "FALSE", "TRUE", NULL };
@ -94,7 +94,7 @@ static const char *kp_boolnames[] = { "FALSE", "TRUE", NULL };
* ------------------------------------------------------------------------- */
int kp_get_bool(const char *keypath, int *boolp)
{
return kp_get_enum(keypath, kp_boolnames, boolp);
return kp_get_enum(keypath, kp_boolnames, boolp);
}
/* -------------------------------------------------------------------------
@ -102,7 +102,7 @@ int kp_get_bool(const char *keypath, int *boolp)
* ------------------------------------------------------------------------- */
int kp_set_bool(const char *keypath, int boolval)
{
return kp_set_enum(keypath, kp_boolnames, boolval ? 1 : 0);
return kp_set_enum(keypath, kp_boolnames, boolval ? 1 : 0);
}
/* End of kp_enum.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_get.c,v 1.2 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_get.c,v 1.3 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -54,293 +54,292 @@
* ------------------------------------------------------------------------- */
static kpval_t kp_type_from_code(int c)
{
switch(c) {
case 'D':
return KPVAL_DATA;
switch (c) {
case 'D':
return KPVAL_DATA;
case 'S':
return KPVAL_STRING;
case 'S':
return KPVAL_STRING;
case 'I':
return KPVAL_INT;
case 'I':
return KPVAL_INT;
case 'F':
return KPVAL_FLOAT;
case 'F':
return KPVAL_FLOAT;
default:
return KPVAL_UNKNOWN;
}
default:
return KPVAL_UNKNOWN;
}
}
/* -------------------------------------------------------------------------
* Decode the data type
* ------------------------------------------------------------------------- */
static int kp_decode_data(const char *buf, kp_key *ck)
static int kp_decode_data(const char *buf, kp_key * ck)
{
unsigned int len;
unsigned int i;
const char *s;
int val;
unsigned int len;
unsigned int i;
const char *s;
int val;
len = 0;
s = buf;
while(*s) {
if(!isxdigit((int) *s))
return -1;
s++;
if(!isxdigit((int) *s))
return -1;
s++;
len = 0;
s = buf;
while (*s) {
if (!isxdigit((int) *s))
return -1;
s++;
if (!isxdigit((int) *s))
return -1;
s++;
if(*s) {
if(*s != ' ')
return -1;
s++;
}
if (*s) {
if (*s != ' ')
return -1;
s++;
}
len++;
}
len++;
}
kp_value_new(ck, KPVAL_DATA, len, NULL);
kp_value_new(ck, KPVAL_DATA, len, NULL);
for(i = 0; i < len; i++) {
val = (int) strtol(buf + (i * 3), NULL, 16);
((unsigned char *) ck->data)[i] = val;
}
for (i = 0; i < len; i++) {
val = (int) strtol(buf + (i * 3), NULL, 16);
((unsigned char *) ck->data)[i] = val;
}
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Decode the escaped representation of the string
* ------------------------------------------------------------------------- */
static int kp_decode_string(const char *buf, kp_key *ck)
static int kp_decode_string(const char *buf, kp_key * ck)
{
unsigned int len;
int i;
const char *s;
int val;
unsigned int len;
int i;
const char *s;
int val;
len = 0;
s = buf;
if(*s++ != '"')
return -1;
len = 0;
s = buf;
if (*s++ != '"')
return -1;
while(*s && *s != '"') {
if(*s == '\\') {
s++;
while (*s && *s != '"') {
if (*s == '\\') {
s++;
switch(*s) {
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '\\':
case '"':
break;
switch (*s) {
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
case 'v':
case '\\':
case '"':
break;
default:
if(*s >= '0' && *s < '4') {
s++;
if(*s < '0' || *s >= '8')
return -1;
s++;
if(*s < '0' || *s >= '8')
return -1;
}
else
return -1;
}
}
s++;
default:
if (*s >= '0' && *s < '4') {
s++;
if (*s < '0' || *s >= '8')
return -1;
s++;
if (*s < '0' || *s >= '8')
return -1;
} else
return -1;
}
}
s++;
len++;
}
len++;
}
if(*s != '"')
return -1;
if (*s != '"')
return -1;
kp_value_new(ck, KPVAL_STRING, len, NULL);
kp_value_new(ck, KPVAL_STRING, len, NULL);
s = buf + 1;
for(i = 0; *s != '"'; i++) {
if(*s != '\\')
val = *s;
else {
s++;
s = buf + 1;
for (i = 0; *s != '"'; i++) {
if (*s != '\\')
val = *s;
else {
s++;
switch(*s) {
case 'b':
val = '\b';
break;
switch (*s) {
case 'b':
val = '\b';
break;
case 'f':
val = '\f';
break;
case 'f':
val = '\f';
break;
case 'n':
val = '\n';
break;
case 'n':
val = '\n';
break;
case 'r':
val = '\r';
break;
case 'r':
val = '\r';
break;
case 't':
val = '\t';
break;
case 't':
val = '\t';
break;
case 'v':
val = '\v';
break;
case 'v':
val = '\v';
break;
case '\\':
val = '\\';
break;
case '\\':
val = '\\';
break;
case '"':
val = '"';
break;
case '"':
val = '"';
break;
default:
val = (*s - '0') << 6;
s++;
val += (*s - '0') << 3;
s++;
val += (*s - '0');
}
}
s++;
default:
val = (*s - '0') << 6;
s++;
val += (*s - '0') << 3;
s++;
val += (*s - '0');
}
}
s++;
((unsigned char *) ck->data)[i] = val;
}
((unsigned char *) ck->data)[i] = val;
}
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Decode the string representation of an integer type
* ------------------------------------------------------------------------- */
static int kp_decode_int(const char *buf, kp_key *ck)
static int kp_decode_int(const char *buf, kp_key * ck)
{
int val;
char *end;
int val;
char *end;
val = (int) strtol(buf, &end, 10);
if(end == buf)
return -1;
val = (int) strtol(buf, &end, 10);
if (end == buf)
return -1;
kp_value_new(ck, KPVAL_INT, sizeof(int), &val);
kp_value_new(ck, KPVAL_INT, sizeof(int), &val);
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Decode the string representation of a float type
* ------------------------------------------------------------------------- */
static int kp_decode_float(const char *buf, kp_key *ck)
static int kp_decode_float(const char *buf, kp_key * ck)
{
double val;
char *end;
double val;
char *end;
val = strtod(buf, &end);
if(end == buf)
return -1;
val = strtod(buf, &end);
if (end == buf)
return -1;
kp_value_new(ck, KPVAL_FLOAT, sizeof(double), &val);
kp_value_new(ck, KPVAL_FLOAT, sizeof(double), &val);
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Decode the string representation to the type and value of the key
* ------------------------------------------------------------------------- */
static int kp_decode_value(const char *buf, kp_key *ck)
static int kp_decode_value(const char *buf, kp_key * ck)
{
int res;
kpval_t type;
int res;
kpval_t type;
if(strlen(buf) < 2)
return -1;
if (strlen(buf) < 2)
return -1;
if(buf[1] != SEP2)
return -1;
if (buf[1] != SEP2)
return -1;
type = kp_type_from_code(buf[0]);
type = kp_type_from_code(buf[0]);
switch(type) {
case KPVAL_DATA:
res = kp_decode_data(buf+2, ck);
break;
switch (type) {
case KPVAL_DATA:
res = kp_decode_data(buf + 2, ck);
break;
case KPVAL_STRING:
res = kp_decode_string(buf+2, ck);
break;
case KPVAL_STRING:
res = kp_decode_string(buf + 2, ck);
break;
case KPVAL_INT:
res = kp_decode_int(buf+2, ck);
break;
case KPVAL_INT:
res = kp_decode_int(buf + 2, ck);
break;
case KPVAL_FLOAT:
res = kp_decode_float(buf+2, ck);
break;
case KPVAL_FLOAT:
res = kp_decode_float(buf + 2, ck);
break;
default:
res = -1;
}
default:
res = -1;
}
return res;
return res;
}
/* -------------------------------------------------------------------------
* Read a database file, and insert the keys into the key list
* ------------------------------------------------------------------------- */
int _kp_read_file(char *path, kp_key **ksp)
int _kp_read_file(char *path, kp_key ** ksp)
{
FILE *fp;
char *buf, *value;
int res;
int finished;
kp_key *keys = *ksp;
kp_key ck;
FILE *fp;
char *buf, *value;
int res;
int finished;
kp_key *keys = *ksp;
kp_key ck;
fp = fopen(path, "r");
if(fp == NULL)
return _kp_errno_to_kperr(errno);
fp = fopen(path, "r");
if (fp == NULL)
return _kp_errno_to_kperr(errno);
finished = 0;
do {
buf = _kp_get_line(fp, &value);
if(buf == NULL)
finished = 1;
else {
kp_key *newkey;
/* FIXME: check key for uniqueness, etc...*/
res = kp_decode_value(value, &ck);
if(res != 0) {
kp_value_new(&ck, KPVAL_UNKNOWN, 0, NULL);
ck.flags |= KPFL_BADDB;
}
newkey = (kp_key *) malloc_check(sizeof(kp_key));
*newkey = ck;
newkey->name = strdup_check(buf);
newkey->next = keys;
keys = newkey;
}
free(buf);
} while(!finished);
finished = 0;
do {
buf = _kp_get_line(fp, &value);
if (buf == NULL)
finished = 1;
else {
kp_key *newkey;
fclose(fp);
*ksp = keys;
/* FIXME: check key for uniqueness, etc... */
return 0;
res = kp_decode_value(value, &ck);
if (res != 0) {
kp_value_new(&ck, KPVAL_UNKNOWN, 0, NULL);
ck.flags |= KPFL_BADDB;
}
newkey = (kp_key *) malloc_check(sizeof(kp_key));
*newkey = ck;
newkey->name = strdup_check(buf);
newkey->next = keys;
keys = newkey;
}
free(buf);
} while (!finished);
fclose(fp);
*ksp = keys;
return 0;
}
/* -------------------------------------------------------------------------
@ -348,30 +347,30 @@ int _kp_read_file(char *path, kp_key **ksp)
* ------------------------------------------------------------------------- */
static int kp_is_singleval(const char *path)
{
FILE *fp;
char *buf, *value;
int is_singleval;
FILE *fp;
char *buf, *value;
int is_singleval;
fp = fopen(path, "r");
if(fp == NULL)
is_singleval = 0;
else {
buf = _kp_get_line(fp, &value);
if(buf == NULL)
is_singleval = 0;
else {
if(buf[0] != '\0')
is_singleval = 0;
else
is_singleval = 1;
free(buf);
}
fclose(fp);
}
return is_singleval;
fp = fopen(path, "r");
if (fp == NULL)
is_singleval = 0;
else {
buf = _kp_get_line(fp, &value);
if (buf == NULL)
is_singleval = 0;
else {
if (buf[0] != '\0')
is_singleval = 0;
else
is_singleval = 1;
free(buf);
}
fclose(fp);
}
return is_singleval;
}
/* -------------------------------------------------------------------------
@ -382,47 +381,59 @@ static int kp_is_singleval(const char *path)
* ------------------------------------------------------------------------- */
int _kp_get_subkeys_dir(char *path, struct key_array *keys)
{
DIR *dirp;
struct dirent *dirent;
struct stat stbuf;
char *fullpath;
int res;
DIR *dirp;
struct dirent *dirent;
struct stat stbuf;
char *fullpath;
int res;
dirp = opendir(path);
if(dirp == NULL)
return _kp_errno_to_kperr(errno);
dirp = opendir(path);
if (dirp == NULL)
return _kp_errno_to_kperr(errno);
do {
dirent = readdir(dirp);
if(dirent != NULL && strcmp(dirent->d_name, ".") != 0 &&
strcmp(dirent->d_name, "..") != 0 &&
dirent->d_name[0] != ':') {
do {
dirent = readdir(dirp);
if (dirent != NULL && strcmp(dirent->d_name, ".") != 0 &&
strcmp(dirent->d_name, "..") != 0 &&
dirent->d_name[0] != ':') {
fullpath = (char *) malloc_check(strlen(path)+1+
strlen(dirent->d_name)+1);
sprintf(fullpath, "%s/%s", path, dirent->d_name);
fullpath = (char *) malloc_check(strlen(path) + 1 +
strlen(dirent->
d_name) +
1);
sprintf(fullpath, "%s/%s", path, dirent->d_name);
res = stat(fullpath, &stbuf);
if(res == 0) {
if(S_ISDIR(stbuf.st_mode))
_kp_add_subkey_check(keys, dirent->d_name);
else if(S_ISREG(stbuf.st_mode) && kp_is_singleval(fullpath))
_kp_add_subkey_check(keys, dirent->d_name);
else {
char *realname;
realname = (char *) malloc_check(strlen(dirent->d_name)+2);
sprintf(realname, "%s:", dirent->d_name);
_kp_add_subkey_check(keys, realname);
free(realname);
}
}
free(fullpath);
}
} while(dirent != NULL);
res = stat(fullpath, &stbuf);
if (res == 0) {
if (S_ISDIR(stbuf.st_mode))
_kp_add_subkey_check(keys,
dirent->
d_name);
else if (S_ISREG(stbuf.st_mode)
&& kp_is_singleval(fullpath))
_kp_add_subkey_check(keys,
dirent->
d_name);
else {
char *realname;
realname = (char *)
malloc_check(strlen
(dirent->d_name) +
2);
sprintf(realname, "%s:",
dirent->d_name);
_kp_add_subkey_check(keys,
realname);
free(realname);
}
}
free(fullpath);
}
} while (dirent != NULL);
closedir(dirp);
closedir(dirp);
return 0;
return 0;
}
/* End of kp_get.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_iface.c,v 1.3 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_iface.c,v 1.4 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -53,84 +53,87 @@
* ------------------------------------------------------------------------- */
static int kp_check_path(const char *keypath)
{
int seglen, segbeg;
int i;
int colonfound;
int seglen, segbeg;
int i;
int colonfound;
/* Check for the following:
- only one / per segment
- : only appears once, and only at end or before /
- path does not contain . or .. segments
- path does not contain non printable characters
- path does not end with /
*/
/* Check for the following:
- only one / per segment
- : only appears once, and only at end or before /
- path does not contain . or .. segments
- path does not contain non printable characters
- path does not end with /
*/
colonfound = 0;
segbeg = 0;
i = 0;
do {
if((keypath[i] > 0 && keypath[i] < 32) || keypath[i] == 127)
return KPERR_BADKEY;
colonfound = 0;
segbeg = 0;
i = 0;
do {
if ((keypath[i] > 0 && keypath[i] < 32)
|| keypath[i] == 127)
return KPERR_BADKEY;
if(keypath[i] == '/' || keypath[i] == ':' || keypath[i] == '\0') {
seglen = i - segbeg;
if (keypath[i] == '/' || keypath[i] == ':'
|| keypath[i] == '\0') {
seglen = i - segbeg;
if(keypath[i] == ':') {
if(colonfound)
return KPERR_BADKEY;
if (keypath[i] == ':') {
if (colonfound)
return KPERR_BADKEY;
if(keypath[i+1] != '/' && keypath[i+1] != '\0')
return KPERR_BADKEY;
if (keypath[i + 1] != '/'
&& keypath[i + 1] != '\0')
return KPERR_BADKEY;
colonfound = 1;
i++;
}
if(i > 0) {
if(seglen == 0)
return KPERR_BADKEY;
if(seglen == 1 && keypath[segbeg] == '.')
return KPERR_BADKEY;
if(seglen == 2 && keypath[segbeg] == '.' &&
keypath[segbeg+1] == '.')
return KPERR_BADKEY;
}
segbeg = i + 1;
}
colonfound = 1;
i++;
}
if (i > 0) {
if (seglen == 0)
return KPERR_BADKEY;
if (seglen == 1 && keypath[segbeg] == '.')
return KPERR_BADKEY;
if (seglen == 2 && keypath[segbeg] == '.'
&& keypath[segbeg + 1] == '.')
return KPERR_BADKEY;
}
segbeg = i + 1;
}
} while(keypath[i++]);
} while (keypath[i++]);
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Get the value of the key, iterate through the sections
* ------------------------------------------------------------------------- */
static int kp_get(const char *keypath, kp_key *ck, kpval_t type)
static int kp_get(const char *keypath, kp_key * ck, kpval_t type)
{
kp_path kpp;
char *keyname;
int iskeyfile;
int res;
kp_path kpp;
char *keyname;
int iskeyfile;
int res;
res = kp_check_path(keypath);
if(res != 0)
return res;
res = kp_check_path(keypath);
if (res != 0)
return res;
do {
res = _kp_get_path(keypath, &kpp, &keyname, &iskeyfile);
if(res != 0)
return res;
do {
res = _kp_get_path(keypath, &kpp, &keyname, &iskeyfile);
if (res != 0)
return res;
if(iskeyfile && !keyname[0])
res = KPERR_BADKEY;
else {
res = _kp_cache_get(&kpp, keyname, type, ck);
}
free(kpp.path);
keypath ++;
} while(res == KPERR_NOKEY);
if (iskeyfile && !keyname[0])
res = KPERR_BADKEY;
else {
res = _kp_cache_get(&kpp, keyname, type, ck);
}
free(kpp.path);
keypath++;
} while (res == KPERR_NOKEY);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -138,19 +141,19 @@ static int kp_get(const char *keypath, kp_key *ck, kpval_t type)
* ------------------------------------------------------------------------- */
int kp_get_string(const char *keypath, char **stringp)
{
int res;
kp_key ck;
int res;
kp_key ck;
res = kp_get(keypath, &ck, KPVAL_STRING);
if(res != 0)
return res;
res = kp_get(keypath, &ck, KPVAL_STRING);
if (res != 0)
return res;
*stringp = (char *) malloc_check(ck.len + 1);
memcpy(*stringp, ck.data, ck.len);
(*stringp)[ck.len] = '\0';
kp_value_destroy(&ck);
*stringp = (char *) malloc_check(ck.len + 1);
memcpy(*stringp, ck.data, ck.len);
(*stringp)[ck.len] = '\0';
kp_value_destroy(&ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -158,17 +161,17 @@ int kp_get_string(const char *keypath, char **stringp)
* ------------------------------------------------------------------------- */
int kp_get_int(const char *keypath, int *intp)
{
int res;
kp_key ck;
int res;
kp_key ck;
res = kp_get(keypath, &ck, KPVAL_INT);
if(res != 0)
return res;
res = kp_get(keypath, &ck, KPVAL_INT);
if (res != 0)
return res;
*intp = *((int *)ck.data);
kp_value_destroy(&ck);
*intp = *((int *) ck.data);
kp_value_destroy(&ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -176,17 +179,17 @@ int kp_get_int(const char *keypath, int *intp)
* ------------------------------------------------------------------------- */
int kp_get_float(const char *keypath, double *floatp)
{
int res;
kp_key ck;
int res;
kp_key ck;
res = kp_get(keypath, &ck, KPVAL_FLOAT);
if(res != 0)
return res;
res = kp_get(keypath, &ck, KPVAL_FLOAT);
if (res != 0)
return res;
*floatp = *((double *)ck.data);
kp_value_destroy(&ck);
*floatp = *((double *) ck.data);
kp_value_destroy(&ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -194,19 +197,19 @@ int kp_get_float(const char *keypath, double *floatp)
* ------------------------------------------------------------------------- */
int kp_get_data(const char *keypath, void **datap, unsigned int *lenp)
{
int res;
kp_key ck;
int res;
kp_key ck;
res = kp_get(keypath, &ck, KPVAL_DATA);
if(res != 0)
return res;
res = kp_get(keypath, &ck, KPVAL_DATA);
if (res != 0)
return res;
*datap = malloc_check(ck.len);
memcpy(*datap, ck.data, ck.len);
*lenp = ck.len;
kp_value_destroy(&ck);
*datap = malloc_check(ck.len);
memcpy(*datap, ck.data, ck.len);
*lenp = ck.len;
kp_value_destroy(&ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -214,22 +217,22 @@ int kp_get_data(const char *keypath, void **datap, unsigned int *lenp)
* ------------------------------------------------------------------------- */
static void kp_combine_strings(struct key_array *keys)
{
char *s;
int strsize;
char **kp;
char *s;
int strsize;
char **kp;
s = ((char *) keys->array) + (sizeof(char *) * (keys->num + 1));
s = ((char *) keys->array) + (sizeof(char *) * (keys->num + 1));
for(kp = keys->array; *kp != NULL; kp++) {
strsize = strlen(*kp) + 1;
strsize = ROUND_TO(strsize, 8);
for (kp = keys->array; *kp != NULL; kp++) {
strsize = strlen(*kp) + 1;
strsize = ROUND_TO(strsize, 8);
strcpy(s, *kp);
free(*kp);
*kp = s;
strcpy(s, *kp);
free(*kp);
*kp = s;
s += strsize;
}
s += strsize;
}
}
/* -------------------------------------------------------------------------
@ -237,12 +240,12 @@ static void kp_combine_strings(struct key_array *keys)
* ------------------------------------------------------------------------- */
static void kp_free_keyarray(struct key_array *keys)
{
char **kp;
char **kp;
for(kp = keys->array; *kp != NULL; kp++)
free(*kp);
for (kp = keys->array; *kp != NULL; kp++)
free(*kp);
free(keys->array);
free(keys->array);
}
/* -------------------------------------------------------------------------
@ -250,25 +253,26 @@ static void kp_free_keyarray(struct key_array *keys)
* ------------------------------------------------------------------------- */
static int kp_get_subkeys(const char *keypath, struct key_array *keys)
{
kp_path kpp;
char *keyname;
int iskeyfile;
int res;
kp_path kpp;
char *keyname;
int iskeyfile;
int res;
res = kp_check_path(keypath);
if(res != 0)
return res;
res = kp_check_path(keypath);
if (res != 0)
return res;
while(keypath[0] != '\0' && keypath[0] != '/') {
res = _kp_get_path(keypath, &kpp, &keyname, &iskeyfile);
if(res == 0) {
_kp_cache_get_subkeys(&kpp, keyname, iskeyfile, keys);
free(kpp.path);
}
keypath ++;
}
while (keypath[0] != '\0' && keypath[0] != '/') {
res = _kp_get_path(keypath, &kpp, &keyname, &iskeyfile);
if (res == 0) {
_kp_cache_get_subkeys(&kpp, keyname, iskeyfile,
keys);
free(kpp.path);
}
keypath++;
}
return 0;
return 0;
}
/* -------------------------------------------------------------------------
@ -276,81 +280,80 @@ static int kp_get_subkeys(const char *keypath, struct key_array *keys)
* ------------------------------------------------------------------------- */
int kp_get_dir(const char *keypath, char ***keysp, unsigned int *nump)
{
int res;
struct key_array keys;
int res;
struct key_array keys;
keys.array = (char **) malloc_check(sizeof(char *));
keys.array[0] = NULL;
keys.num = 0;
keys.strsize = 0;
keys.array = (char **) malloc_check(sizeof(char *));
keys.array[0] = NULL;
keys.num = 0;
keys.strsize = 0;
res = kp_get_subkeys(keypath, &keys);
if(res == 0) {
kp_combine_strings(&keys);
*keysp = keys.array;
if(nump != NULL)
*nump = keys.num;
}
else
kp_free_keyarray(&keys);
res = kp_get_subkeys(keypath, &keys);
if (res == 0) {
kp_combine_strings(&keys);
*keysp = keys.array;
if (nump != NULL)
*nump = keys.num;
} else
kp_free_keyarray(&keys);
return res;
return res;
}
/* -------------------------------------------------------------------------
* Get the type of a key, iterate through the sections
* ------------------------------------------------------------------------- */
int kp_get_type(const char *keypath, kpval_t *typep)
int kp_get_type(const char *keypath, kpval_t * typep)
{
kp_path kpp;
char *keyname;
int iskeyfile;
int res;
kp_path kpp;
char *keyname;
int iskeyfile;
int res;
res = kp_check_path(keypath);
if(res != 0)
return res;
res = kp_check_path(keypath);
if (res != 0)
return res;
do {
res = _kp_get_path(keypath, &kpp, &keyname, &iskeyfile);
if(res != 0)
return res;
do {
res = _kp_get_path(keypath, &kpp, &keyname, &iskeyfile);
if (res != 0)
return res;
res = _kp_cache_get_type(&kpp, keyname, iskeyfile, typep);
free(kpp.path);
keypath ++;
} while(res == KPERR_NOKEY);
res = _kp_cache_get_type(&kpp, keyname, iskeyfile, typep);
free(kpp.path);
keypath++;
} while (res == KPERR_NOKEY);
return res;
return res;
}
/* -------------------------------------------------------------------------
* Set the value of the key, only the first section is set
* ------------------------------------------------------------------------- */
static int kp_set(const char *keypath, kp_key *ck)
static int kp_set(const char *keypath, kp_key * ck)
{
kp_path kpp;
char *keyname;
int res;
int iskeyfile;
kp_path kpp;
char *keyname;
int res;
int iskeyfile;
res = kp_check_path(keypath);
if(res != 0)
return res;
res = kp_check_path(keypath);
if (res != 0)
return res;
res = _kp_get_path(keypath, &kpp, &keyname, &iskeyfile);
if(res != 0)
return res;
res = _kp_get_path(keypath, &kpp, &keyname, &iskeyfile);
if (res != 0)
return res;
if(iskeyfile && !keyname[0])
res = KPERR_BADKEY;
else {
ck->name = strdup_check(keyname);
res = _kp_cache_set(&kpp, ck);
}
free(kpp.path);
if (iskeyfile && !keyname[0])
res = KPERR_BADKEY;
else {
ck->name = strdup_check(keyname);
res = _kp_cache_set(&kpp, ck);
}
free(kpp.path);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -358,17 +361,17 @@ static int kp_set(const char *keypath, kp_key *ck)
* ------------------------------------------------------------------------- */
int kp_set_string(const char *keypath, const char *string)
{
int res;
kp_key ck;
unsigned int len;
int res;
kp_key ck;
unsigned int len;
len = strlen(string);
kp_value_new(&ck, KPVAL_STRING, len, string);
len = strlen(string);
kp_value_new(&ck, KPVAL_STRING, len, string);
res = kp_set(keypath, &ck);
kp_value_destroy(&ck);
res = kp_set(keypath, &ck);
kp_value_destroy(&ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -376,17 +379,17 @@ int kp_set_string(const char *keypath, const char *string)
* ------------------------------------------------------------------------- */
int kp_set_int(const char *keypath, int intval)
{
int res;
kp_key ck;
unsigned int len;
int res;
kp_key ck;
unsigned int len;
len = sizeof(int);
kp_value_new(&ck, KPVAL_INT, len, &intval);
len = sizeof(int);
kp_value_new(&ck, KPVAL_INT, len, &intval);
res = kp_set(keypath, &ck);
kp_value_destroy(&ck);
res = kp_set(keypath, &ck);
kp_value_destroy(&ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -394,17 +397,17 @@ int kp_set_int(const char *keypath, int intval)
* ------------------------------------------------------------------------- */
int kp_set_float(const char *keypath, double floatval)
{
int res;
kp_key ck;
unsigned int len;
int res;
kp_key ck;
unsigned int len;
len = sizeof(double);
kp_value_new(&ck, KPVAL_FLOAT, len, &floatval);
len = sizeof(double);
kp_value_new(&ck, KPVAL_FLOAT, len, &floatval);
res = kp_set(keypath, &ck);
kp_value_destroy(&ck);
res = kp_set(keypath, &ck);
kp_value_destroy(&ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -412,15 +415,15 @@ int kp_set_float(const char *keypath, double floatval)
* ------------------------------------------------------------------------- */
int kp_set_data(const char *keypath, const void *data, unsigned int len)
{
int res;
kp_key ck;
int res;
kp_key ck;
kp_value_new(&ck, KPVAL_DATA, len, data);
kp_value_new(&ck, KPVAL_DATA, len, data);
res = kp_set(keypath, &ck);
kp_value_destroy(&ck);
res = kp_set(keypath, &ck);
kp_value_destroy(&ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -428,14 +431,14 @@ int kp_set_data(const char *keypath, const void *data, unsigned int len)
* ------------------------------------------------------------------------- */
int kp_remove(const char *keypath)
{
int res;
kp_key ck;
int res;
kp_key ck;
kp_value_new(&ck, KPVAL_UNKNOWN, 0, NULL);
ck.flags |= KPFL_REMOVED;
res = kp_set(keypath, &ck);
kp_value_new(&ck, KPVAL_UNKNOWN, 0, NULL);
ck.flags |= KPFL_REMOVED;
res = kp_set(keypath, &ck);
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -443,11 +446,11 @@ int kp_remove(const char *keypath)
* ------------------------------------------------------------------------- */
int kp_flush()
{
int res;
int res;
res = _kp_cache_flush();
res = _kp_cache_flush();
return res;
return res;
}
/* -------------------------------------------------------------------------
@ -455,25 +458,25 @@ int kp_flush()
* ------------------------------------------------------------------------- */
char *kp_strerror(int kperr)
{
switch(kperr) {
case KPERR_OK:
return "OK";
case KPERR_NOKEY:
return "Key does not exist";
case KPERR_NOACCES:
return "Access denied";
case KPERR_BADKEY:
return "Bad key";
case KPERR_BADTYPE:
return "Bad type";
case KPERR_BADDB:
return "Bad database";
case KPERR_NOSPACE:
return "Not enough resources";
switch (kperr) {
case KPERR_OK:
return "OK";
case KPERR_NOKEY:
return "Key does not exist";
case KPERR_NOACCES:
return "Access denied";
case KPERR_BADKEY:
return "Bad key";
case KPERR_BADTYPE:
return "Bad type";
case KPERR_BADDB:
return "Bad database";
case KPERR_NOSPACE:
return "Not enough resources";
default:
return NULL;
}
default:
return NULL;
}
}
/* End of kp_iface.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_recur.c,v 1.2 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_recur.c,v 1.3 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -52,44 +52,44 @@
* then the last error encountered is retured.
* ------------------------------------------------------------------------- */
int kp_recursive_do(const char *key, kp_func func, int stop_on_err,
void *user_data)
void *user_data)
{
kpval_t type;
int res;
int finalres;
kpval_t type;
int res;
int finalres;
res = kp_get_type(key, &type);
if(res != 0)
return res;
res = kp_get_type(key, &type);
if (res != 0)
return res;
finalres = 0;
if(type != KPVAL_DIR) {
finalres = (*func) (key, user_data);
}
else {
char **keys;
char **kp;
KPDIR *dir;
finalres = 0;
if (type != KPVAL_DIR) {
finalres = (*func) (key, user_data);
} else {
char **keys;
char **kp;
KPDIR *dir;
res = kp_get_dir(key, &keys, NULL);
if(res != 0)
return res;
res = kp_get_dir(key, &keys, NULL);
if (res != 0)
return res;
dir = kp_dir_open(key);
for(kp = keys; *kp != NULL; kp++) {
res = kp_recursive_do(KP_P(dir, *kp), func, stop_on_err,
user_data);
if(res != 0) {
finalres = res;
if(stop_on_err)
break;
}
}
kp_dir_close(dir);
free(keys);
}
dir = kp_dir_open(key);
for (kp = keys; *kp != NULL; kp++) {
res =
kp_recursive_do(KP_P(dir, *kp), func,
stop_on_err, user_data);
if (res != 0) {
finalres = res;
if (stop_on_err)
break;
}
}
kp_dir_close(dir);
free(keys);
}
return finalres;
return finalres;
}
/* End of kp_recur.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_set.c,v 1.2 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_set.c,v 1.3 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -53,206 +53,206 @@
/* -------------------------------------------------------------------------
* Code data (character array) to a string
* ------------------------------------------------------------------------- */
static char *kp_code_data(kp_key *ck)
static char *kp_code_data(kp_key * ck)
{
char *buf, *ds;
int i;
int val;
char *buf, *ds;
int i;
int val;
buf = (char *) malloc_check(ck->len * 3 + 64);
ds = buf;
buf = (char *) malloc_check(ck->len * 3 + 64);
ds = buf;
*ds++ = 'D';
*ds++ = SEP2;
for(i = 0; i < (int) ck->len; i++) {
if(i != 0)
*ds++ = ' ';
val = ((unsigned char *)ck->data)[i];
sprintf(ds, "%02x", val);
ds += 2;
}
*ds = '\0';
*ds++ = 'D';
*ds++ = SEP2;
for (i = 0; i < (int) ck->len; i++) {
if (i != 0)
*ds++ = ' ';
val = ((unsigned char *) ck->data)[i];
sprintf(ds, "%02x", val);
ds += 2;
}
*ds = '\0';
return buf;
return buf;
}
/* -------------------------------------------------------------------------
* Code arbitary string to an escaped representation
* ------------------------------------------------------------------------- */
static char *kp_code_string(kp_key *ck)
static char *kp_code_string(kp_key * ck)
{
char *buf, *ds;
unsigned char *os;
int i;
char *buf, *ds;
unsigned char *os;
int i;
buf = (char *) malloc_check(ck->len * 4 + 64);
ds = buf;
*ds++ = 'S';
*ds++ = SEP2;
*ds++ = '"';
buf = (char *) malloc_check(ck->len * 4 + 64);
ds = buf;
*ds++ = 'S';
*ds++ = SEP2;
*ds++ = '"';
os = (unsigned char *) ck->data;
os = (unsigned char *) ck->data;
for(i = 0; i < (int) ck->len; i++) {
switch(os[i]) {
case '\b':
*ds++ = '\\';
*ds++ = 'b';
break;
for (i = 0; i < (int) ck->len; i++) {
switch (os[i]) {
case '\b':
*ds++ = '\\';
*ds++ = 'b';
break;
case '\f':
*ds++ = '\\';
*ds++ = 'f';
break;
case '\f':
*ds++ = '\\';
*ds++ = 'f';
break;
case '\n':
*ds++ = '\\';
*ds++ = 'n';
break;
case '\n':
*ds++ = '\\';
*ds++ = 'n';
break;
case '\r':
*ds++ = '\\';
*ds++ = 'r';
break;
case '\r':
*ds++ = '\\';
*ds++ = 'r';
break;
case '\t':
*ds++ = '\\';
*ds++ = 't';
break;
case '\t':
*ds++ = '\\';
*ds++ = 't';
break;
case '\v':
*ds++ = '\\';
*ds++ = 'v';
break;
case '\v':
*ds++ = '\\';
*ds++ = 'v';
break;
case '\\':
*ds++ = '\\';
*ds++ = '\\';
break;
case '\\':
*ds++ = '\\';
*ds++ = '\\';
break;
case '"':
*ds++ = '\\';
*ds++ = '"';
break;
case '"':
*ds++ = '\\';
*ds++ = '"';
break;
default:
if(os[i] < 32 || os[i] >= 127) {
*ds++ = '\\';
*ds++ = '0' + ((os[i] >> 6) & 3);
*ds++ = '0' + ((os[i] >> 3) & 7);
*ds++ = '0' + (os[i] & 7);
}
else
*ds++ = os[i];
}
}
default:
if (os[i] < 32 || os[i] >= 127) {
*ds++ = '\\';
*ds++ = '0' + ((os[i] >> 6) & 3);
*ds++ = '0' + ((os[i] >> 3) & 7);
*ds++ = '0' + (os[i] & 7);
} else
*ds++ = os[i];
}
}
*ds++ = '"';
*ds = '\0';
return buf;
*ds++ = '"';
*ds = '\0';
return buf;
}
/* -------------------------------------------------------------------------
* Return the string representation of an integer
* ------------------------------------------------------------------------- */
static char *kp_code_int(kp_key *ck)
static char *kp_code_int(kp_key * ck)
{
char *buf, *ds;
int val;
char *buf, *ds;
int val;
buf = (char *) malloc_check(64);
ds = buf;
*ds++ = 'I';
*ds++ = SEP2;
buf = (char *) malloc_check(64);
ds = buf;
*ds++ = 'I';
*ds++ = SEP2;
val = *(int *)ck->data;
sprintf(ds, "%i", val);
val = *(int *) ck->data;
sprintf(ds, "%i", val);
return buf;
return buf;
}
/* -------------------------------------------------------------------------
* Return the string representation of a float
* ------------------------------------------------------------------------- */
static char *kp_code_float(kp_key *ck)
static char *kp_code_float(kp_key * ck)
{
char *buf, *ds;
double val;
char *buf, *ds;
double val;
buf = (char *) malloc_check(64);
ds = buf;
*ds++ = 'F';
*ds++ = SEP2;
buf = (char *) malloc_check(64);
ds = buf;
*ds++ = 'F';
*ds++ = SEP2;
val = *(double *)ck->data;
sprintf(ds, "%.20g", val);
val = *(double *) ck->data;
sprintf(ds, "%.20g", val);
return buf;
return buf;
}
/* -------------------------------------------------------------------------
* Code a value to a string depending on it's type
* ------------------------------------------------------------------------- */
static char *kp_code_value(kp_key *ck)
static char *kp_code_value(kp_key * ck)
{
char *buf;
char *buf;
switch(ck->type) {
case KPVAL_DATA:
buf = kp_code_data(ck);
break;
switch (ck->type) {
case KPVAL_DATA:
buf = kp_code_data(ck);
break;
case KPVAL_STRING:
buf = kp_code_string(ck);
break;
case KPVAL_STRING:
buf = kp_code_string(ck);
break;
case KPVAL_INT:
buf = kp_code_int(ck);
break;
case KPVAL_INT:
buf = kp_code_int(ck);
break;
case KPVAL_FLOAT:
buf = kp_code_float(ck);
break;
case KPVAL_FLOAT:
buf = kp_code_float(ck);
break;
default:
/* Internal error */
fprintf(stderr, "keeper: Internal Error: Illegal type: %i\n",
ck->type);
abort();
}
default:
/* Internal error */
fprintf(stderr,
"keeper: Internal Error: Illegal type: %i\n",
ck->type);
abort();
}
return buf;
return buf;
}
/* -------------------------------------------------------------------------
* Remove empty directories in a path
* ------------------------------------------------------------------------- */
static void kp_delete_path(kp_path *kpp)
static void kp_delete_path(kp_path * kpp)
{
char *ipath;
int res;
int i;
int ibeg = _kp_get_ibeg(kpp->dbindex);
char *ipath;
int res;
int i;
int ibeg = _kp_get_ibeg(kpp->dbindex);
ipath = strdup_check(kpp->path);
ipath = strdup_check(kpp->path);
i = strlen(ipath) - 1;
while(1) {
while(i >= 0 && ipath[i] != '/')
i--;
while(i >= 0 && ipath[i] == '/')
i--;
i = strlen(ipath) - 1;
while (1) {
while (i >= 0 && ipath[i] != '/')
i--;
while (i >= 0 && ipath[i] == '/')
i--;
if(i < ibeg)
break;
if (i < ibeg)
break;
ipath[i+1] = '\0';
res = rmdir(ipath);
if(res == -1)
break;
}
free(ipath);
ipath[i + 1] = '\0';
res = rmdir(ipath);
if (res == -1)
break;
}
free(ipath);
}
/* -------------------------------------------------------------------------
@ -260,195 +260,194 @@ static void kp_delete_path(kp_path *kpp)
* ------------------------------------------------------------------------- */
static int kp_get_cmode(const char *path, int isdir)
{
int lastchar;
int pathlen;
int lastchar;
int pathlen;
pathlen = strlen(path);
if(pathlen == 0)
return 0;
pathlen = strlen(path);
if (pathlen == 0)
return 0;
lastchar = path[pathlen-1];
lastchar = path[pathlen - 1];
if(lastchar == '-') {
if(isdir)
return 0700;
else
return 0600;
}
else {
if(isdir)
return 0755;
else
return 0644;
}
if (lastchar == '-') {
if (isdir)
return 0700;
else
return 0600;
} else {
if (isdir)
return 0755;
else
return 0644;
}
}
/* -------------------------------------------------------------------------
* Create the nonexistent directories in a path
* ------------------------------------------------------------------------- */
static int kp_create_path(kp_path *kpp)
static int kp_create_path(kp_path * kpp)
{
char *ipath;
int res;
int i;
struct stat stbuf;
int cmode;
int ibeg = _kp_get_ibeg(kpp->dbindex);
char *ipath;
int res;
int i;
struct stat stbuf;
int cmode;
int ibeg = _kp_get_ibeg(kpp->dbindex);
ipath = strdup_check(kpp->path);
ipath = strdup_check(kpp->path);
i = strlen(ipath) - 1;
while(1) {
if(i < ibeg) {
res = KPERR_NOKEY;
break;
}
i = strlen(ipath) - 1;
while (1) {
if (i < ibeg) {
res = KPERR_NOKEY;
break;
}
while(i >= 0 && ipath[i] != '/')
i--;
while(i >= 0 && ipath[i] == '/')
i--;
while (i >= 0 && ipath[i] != '/')
i--;
while (i >= 0 && ipath[i] == '/')
i--;
if(i < 0) {
res = KPERR_BADKEY;
break;
}
if (i < 0) {
res = KPERR_BADKEY;
break;
}
ipath[i+1] = '\0';
res = stat(ipath, &stbuf);
ipath[i+1] = '/';
ipath[i + 1] = '\0';
res = stat(ipath, &stbuf);
ipath[i + 1] = '/';
if(res == -1 && errno != ENOENT) {
res = _kp_errno_to_kperr(errno);
break;
}
else if(res == 0) {
if(!S_ISDIR(stbuf.st_mode)) {
res = KPERR_BADKEY;
break;
}
if (res == -1 && errno != ENOENT) {
res = _kp_errno_to_kperr(errno);
break;
} else if (res == 0) {
if (!S_ISDIR(stbuf.st_mode)) {
res = KPERR_BADKEY;
break;
}
res = 0;
break;
}
}
res = 0;
break;
}
}
if(res != 0) {
free(ipath);
return res;
}
if (res != 0) {
free(ipath);
return res;
}
i++;
while(1) {
while(ipath[i] == '/')
i++;
i++;
while (1) {
while (ipath[i] == '/')
i++;
while(ipath[i] && ipath[i] != '/')
i++;
while (ipath[i] && ipath[i] != '/')
i++;
if(!ipath[i]) {
res = 0;
break;
}
if (!ipath[i]) {
res = 0;
break;
}
ipath[i] = '\0';
cmode = kp_get_cmode(ipath, 1);
res = mkdir(ipath, cmode);
ipath[i] = '/';
ipath[i] = '\0';
cmode = kp_get_cmode(ipath, 1);
res = mkdir(ipath, cmode);
ipath[i] = '/';
if(res == -1) {
res = _kp_errno_to_kperr(errno);
break;
}
}
if (res == -1) {
res = _kp_errno_to_kperr(errno);
break;
}
}
free(ipath);
free(ipath);
return res;
return res;
}
/* -------------------------------------------------------------------------
* Check if a key-name can be found in the key list
* ------------------------------------------------------------------------- */
static int kp_keys_match(char *buf, kp_key *keys)
static int kp_keys_match(char *buf, kp_key * keys)
{
kp_key *k;
kp_key *k;
for(k = keys; k != NULL; k = k->next) {
if(k->flags & KPFL_DIRTY) {
if(strcmp(buf, k->name) == 0)
return 1;
if(!(k->flags & KPFL_REMOVED) &&
(kp_is_subkey(buf, k->name) ||
kp_is_subkey(k->name, buf))) {
for (k = keys; k != NULL; k = k->next) {
if (k->flags & KPFL_DIRTY) {
if (strcmp(buf, k->name) == 0)
return 1;
if (!(k->flags & KPFL_REMOVED) &&
(kp_is_subkey(buf, k->name) ||
kp_is_subkey(k->name, buf))) {
/* This key cannot be set. */
k->flags &= ~KPFL_DIRTY;
}
}
}
return 0;
/* This key cannot be set. */
k->flags &= ~KPFL_DIRTY;
}
}
}
return 0;
}
/* -------------------------------------------------------------------------
* Copy entries from the old database file to the temporary file, excluding
* those which are found in the key list
* ------------------------------------------------------------------------- */
static int kp_remove_keys(kp_path *kpp, FILE *tmpfp, kp_key *keys, int *emptyp)
static int kp_remove_keys(kp_path * kpp, FILE * tmpfp, kp_key * keys,
int *emptyp)
{
FILE *fp;
char *buf, *value;
int finished;
int empty;
FILE *fp;
char *buf, *value;
int finished;
int empty;
fp = fopen(kpp->path, "r");
if(fp == NULL)
return _kp_errno_to_kperr(errno);
fp = fopen(kpp->path, "r");
if (fp == NULL)
return _kp_errno_to_kperr(errno);
empty = 1;
finished = 0;
do {
buf = _kp_get_line(fp, &value);
if(buf == NULL)
finished = 1;
else if(!kp_keys_match(buf, keys)) {
fprintf(tmpfp, "%s%c%s\n", buf, SEP1, value);
empty = 0;
}
free(buf);
} while(!finished);
empty = 1;
finished = 0;
do {
buf = _kp_get_line(fp, &value);
if (buf == NULL)
finished = 1;
else if (!kp_keys_match(buf, keys)) {
fprintf(tmpfp, "%s%c%s\n", buf, SEP1, value);
empty = 0;
}
free(buf);
} while (!finished);
fclose(fp);
fclose(fp);
*emptyp = empty;
*emptyp = empty;
return 0;
return 0;
}
/* -------------------------------------------------------------------------
* Write entries to the file for all keys in the key list
* ------------------------------------------------------------------------- */
static void kp_write_keys(FILE *fp, kp_key *keys, int *emptyp)
static void kp_write_keys(FILE * fp, kp_key * keys, int *emptyp)
{
kp_key *k;
char *buf;
kp_key *k;
char *buf;
for(k = keys; k != NULL; k = k->next) {
if(k->flags & KPFL_DIRTY) {
if(!(k->flags & KPFL_REMOVED)) {
*emptyp = 0;
for (k = keys; k != NULL; k = k->next) {
if (k->flags & KPFL_DIRTY) {
if (!(k->flags & KPFL_REMOVED)) {
*emptyp = 0;
buf = kp_code_value(k);
fprintf(fp, "%s%c%s\n", k->name, SEP1, buf);
free(buf);
}
buf = kp_code_value(k);
fprintf(fp, "%s%c%s\n", k->name, SEP1,
buf);
free(buf);
}
k->flags &= ~KPFL_DIRTY;
}
}
k->flags &= ~KPFL_DIRTY;
}
}
}
/* -------------------------------------------------------------------------
@ -457,63 +456,62 @@ static void kp_write_keys(FILE *fp, kp_key *keys, int *emptyp)
* missing directories. If at the end the file becomes empty, it is
* deleted, and all empty directories above it are also deleted.
* ------------------------------------------------------------------------- */
int _kp_write_file(kp_path *kpp, kp_key *keys)
int _kp_write_file(kp_path * kpp, kp_key * keys)
{
FILE *tmpfp;
struct stat stbuf;
int res;
char *tmppath;
int empty = 1;
int delpath = 0;
int fd;
int cmode;
FILE *tmpfp;
struct stat stbuf;
int res;
char *tmppath;
int empty = 1;
int delpath = 0;
int fd;
int cmode;
tmppath = _kp_get_tmpfile(kpp->dbindex);
tmppath = _kp_get_tmpfile(kpp->dbindex);
tmpfp = NULL;
cmode = kp_get_cmode(kpp->path, 0);
fd = open(tmppath, O_CREAT|O_WRONLY|O_TRUNC, cmode);
if(fd != -1)
tmpfp = fdopen(fd, "w");
tmpfp = NULL;
cmode = kp_get_cmode(kpp->path, 0);
fd = open(tmppath, O_CREAT | O_WRONLY | O_TRUNC, cmode);
if (fd != -1)
tmpfp = fdopen(fd, "w");
if(tmpfp == NULL)
res = _kp_errno_to_kperr(errno);
else {
fprintf(tmpfp, "# KP 1.0\n");
if (tmpfp == NULL)
res = _kp_errno_to_kperr(errno);
else {
fprintf(tmpfp, "# KP 1.0\n");
res = stat(kpp->path, &stbuf);
if(res == -1 && errno == ENOENT)
res = kp_create_path(kpp);
else
res = kp_remove_keys(kpp, tmpfp, keys, &empty);
res = stat(kpp->path, &stbuf);
if (res == -1 && errno == ENOENT)
res = kp_create_path(kpp);
else
res = kp_remove_keys(kpp, tmpfp, keys, &empty);
if(res != 0)
fclose(tmpfp);
else {
kp_write_keys(tmpfp, keys, &empty);
fclose(tmpfp);
if (res != 0)
fclose(tmpfp);
else {
kp_write_keys(tmpfp, keys, &empty);
fclose(tmpfp);
if(empty) {
res = unlink(kpp->path);
if(res == -1)
res = _kp_errno_to_kperr(errno);
else
delpath = 1;
}
else {
res = rename(tmppath, kpp->path);
if(res != 0)
res = _kp_errno_to_kperr(errno);
}
}
unlink(tmppath);
}
free(tmppath);
if (empty) {
res = unlink(kpp->path);
if (res == -1)
res = _kp_errno_to_kperr(errno);
else
delpath = 1;
} else {
res = rename(tmppath, kpp->path);
if (res != 0)
res = _kp_errno_to_kperr(errno);
}
}
unlink(tmppath);
}
free(tmppath);
if(delpath)
kp_delete_path(kpp);
if (delpath)
kp_delete_path(kpp);
return res;
return res;
}
/* End of kp_set.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_sort.c,v 1.2 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_sort.c,v 1.3 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -51,10 +51,10 @@
* ------------------------------------------------------------------------- */
static int kp_string_compare(const void *ptr1, const void *ptr2)
{
const char **s1 = (const char **) ptr1;
const char **s2 = (const char **) ptr2;
const char **s1 = (const char **) ptr1;
const char **s2 = (const char **) ptr2;
return strcmp(*s1, *s2);
return strcmp(*s1, *s2);
}
/* -------------------------------------------------------------------------
@ -62,7 +62,7 @@ static int kp_string_compare(const void *ptr1, const void *ptr2)
* ------------------------------------------------------------------------- */
void kp_sort_keys(char **keys, unsigned int numkeys)
{
qsort(keys, numkeys, sizeof(char *), kp_string_compare);
qsort(keys, numkeys, sizeof(char *), kp_string_compare);
}
/* End of kp_sort.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_util.c,v 1.5 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_util.c,v 1.6 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -57,11 +57,11 @@ static volatile int kp_local_inited = 0;
/* Index for the different sections */
enum {
KPDB_GLOBAL,
KPDB_LOCAL,
KPDB_USER,
KPDB_GLOBAL,
KPDB_LOCAL,
KPDB_USER,
KPDB_NUMDBS
KPDB_NUMDBS
};
/* String containing the temporary file name (not the path) */
@ -70,27 +70,27 @@ static char *kp_tmpname = NULL;
/* String array containing the base path of the different sections */
static char *kp_basedirs[KPDB_NUMDBS];
#define GLOBALDIR "kpconf" /* Default global database path */
#define LOCALDIR "kpdata" /* Local database path */
#define USERSUBDIR "kplang" /* Default user database dir */
#define LOCKFILE ":lock:" /* Lock file name */
#define GLOBALDIR "kpconf" /* Default global database path */
#define LOCALDIR "kpdata" /* Local database path */
#define USERSUBDIR "kplang" /* Default user database dir */
#define LOCKFILE ":lock:" /* Lock file name */
/* -------------------------------------------------------------------------
* Initialize the kp_tmpname variable with a unique hostname/pid string
* ------------------------------------------------------------------------- */
static void kp_init_tmpname()
{
const char *hostname;
unsigned int pid;
const char *hostname;
unsigned int pid;
hostname = getenv("HOST");
if(hostname == NULL)
hostname = "localhost";
hostname = getenv("HOST");
if (hostname == NULL)
hostname = "localhost";
pid = getpid();
pid = getpid();
kp_tmpname = (char *) malloc_check(strlen(hostname) + 64);
sprintf(kp_tmpname, ":tmp.%s.%u:", hostname, pid);
kp_tmpname = (char *) malloc_check(strlen(hostname) + 64);
sprintf(kp_tmpname, ":tmp.%s.%u:", hostname, pid);
}
/* -------------------------------------------------------------------------
@ -98,13 +98,13 @@ static void kp_init_tmpname()
* ------------------------------------------------------------------------- */
static char *kp_init_localdb(void)
{
char *basedir;
char *basedir;
basedir = (char *) malloc_check(strlen(LOCALDIR) + 2);
sprintf(basedir, "%s/", LOCALDIR);
mkdir(basedir, 0755);
basedir = (char *) malloc_check(strlen(LOCALDIR) + 2);
sprintf(basedir, "%s/", LOCALDIR);
mkdir(basedir, 0755);
return basedir;
return basedir;
}
/* -------------------------------------------------------------------------
@ -113,29 +113,28 @@ static char *kp_init_localdb(void)
static char *kp_init_userdb(void)
{
#if 0
const char *homeval;
char *userdir;
char *basedir;
userdir = getenv("KEEPER_USERDIR");
if(userdir != 0) {
basedir = (char *) malloc_check(strlen(userdir) + 2);
sprintf(basedir, "%s/", userdir);
}
else {
homeval = getenv("HOME");
if(homeval == NULL)
homeval = "";
/* FIXME: where to find home, if $HOME is not set? */
const char *homeval;
char *userdir;
char *basedir;
userdir = getenv("KEEPER_USERDIR");
if (userdir != 0) {
basedir = (char *) malloc_check(strlen(userdir) + 2);
sprintf(basedir, "%s/", userdir);
} else {
homeval = getenv("HOME");
if (homeval == NULL)
homeval = "";
/* FIXME: where to find home, if $HOME is not set? */
basedir = (char *) malloc_check(strlen(homeval) + 1 +
strlen(USERSUBDIR) + 2);
sprintf(basedir, "%s/%s/", homeval, USERSUBDIR);
}
mkdir(basedir, 0755);
basedir = (char *) malloc_check(strlen(homeval) + 1 +
strlen(USERSUBDIR) + 2);
sprintf(basedir, "%s/%s/", homeval, USERSUBDIR);
}
mkdir(basedir, 0755);
return basedir;
return basedir;
#endif
return USERSUBDIR;
return USERSUBDIR;
}
/* -------------------------------------------------------------------------
@ -143,24 +142,24 @@ static char *kp_init_userdb(void)
* ------------------------------------------------------------------------- */
static char *kp_init_globaldb(void)
{
char *basedir;
char *globaldir;
char *basedir;
char *globaldir;
/* Be careful. This is a recursion */
/* Be careful. This is a recursion */
#if 0
globaldir = NULL;
kp_get_string("l/keeper/globaldir", &globaldir);
if(globaldir == NULL)
globaldir = NULL;
kp_get_string("l/keeper/globaldir", &globaldir);
if (globaldir == NULL)
#endif
globaldir = strdup_check(GLOBALDIR);
globaldir = strdup_check(GLOBALDIR);
basedir = (char *) malloc_check(strlen(globaldir) + 2);
sprintf(basedir, "%s/", globaldir);
free(globaldir);
basedir = (char *) malloc_check(strlen(globaldir) + 2);
sprintf(basedir, "%s/", globaldir);
free(globaldir);
mkdir(basedir, 0755);
mkdir(basedir, 0755);
return basedir;
return basedir;
}
/* -------------------------------------------------------------------------
@ -168,22 +167,22 @@ static char *kp_init_globaldb(void)
* ------------------------------------------------------------------------- */
static void kp_init(int dbindex)
{
if(kp_inited)
return;
if (kp_inited)
return;
/* This is because of the recursion caused by having to read the local
database, before the global can be initialized */
if(kp_local_inited && dbindex == KPDB_LOCAL)
return;
/* This is because of the recursion caused by having to read the local
database, before the global can be initialized */
if (kp_local_inited && dbindex == KPDB_LOCAL)
return;
if(!kp_inited) {
kp_init_tmpname();
kp_basedirs[KPDB_LOCAL] = kp_init_localdb();
kp_local_inited = 1;
kp_basedirs[KPDB_USER] = kp_init_userdb();
kp_basedirs[KPDB_GLOBAL] = kp_init_globaldb();
kp_inited = 1;
}
if (!kp_inited) {
kp_init_tmpname();
kp_basedirs[KPDB_LOCAL] = kp_init_localdb();
kp_local_inited = 1;
kp_basedirs[KPDB_USER] = kp_init_userdb();
kp_basedirs[KPDB_GLOBAL] = kp_init_globaldb();
kp_inited = 1;
}
}
#ifdef ALLOC_CHECK
@ -192,12 +191,12 @@ static void kp_init(int dbindex)
* ------------------------------------------------------------------------- */
void _kp_exit()
{
free(kp_tmpname);
free(kp_basedirs[KPDB_LOCAL]);
free(kp_basedirs[KPDB_USER]);
free(kp_basedirs[KPDB_GLOBAL]);
free(kp_tmpname);
free(kp_basedirs[KPDB_LOCAL]);
free(kp_basedirs[KPDB_USER]);
free(kp_basedirs[KPDB_GLOBAL]);
_kp_clear_cache();
_kp_clear_cache();
}
#endif
@ -206,33 +205,34 @@ void _kp_exit()
/* -------------------------------------------------------------------------
* Read a line of arbitary length. On end of file return NULL
* ------------------------------------------------------------------------- */
static char *kp_read_line(FILE *fp)
static char *kp_read_line(FILE * fp)
{
char buf[READ_BUF_SIZE];
char *line = NULL;
int eol;
unsigned int linelen, buflen;
char buf[READ_BUF_SIZE];
char *line = NULL;
int eol;
unsigned int linelen, buflen;
eol = 0;
linelen = 0;
do {
if(fgets(buf, READ_BUF_SIZE, fp) == NULL)
return line;
eol = 0;
linelen = 0;
do {
if (fgets(buf, READ_BUF_SIZE, fp) == NULL)
return line;
buflen = strlen(buf);
if(buflen > 0 && buf[buflen - 1] == '\n') {
buf[buflen - 1] = '\0';
buflen --;
eol = 1;
}
buflen = strlen(buf);
if (buflen > 0 && buf[buflen - 1] == '\n') {
buf[buflen - 1] = '\0';
buflen--;
eol = 1;
}
line = (char *) check_ptr(realloc(line, linelen + buflen + 1));
line = (char *)
check_ptr(realloc(line, linelen + buflen + 1));
strcpy(line + linelen, buf);
linelen += buflen;
} while(!eol);
strcpy(line + linelen, buf);
linelen += buflen;
} while (!eol);
return line;
return line;
}
/* -------------------------------------------------------------------------
@ -240,100 +240,100 @@ static char *kp_read_line(FILE *fp)
* and the value of the key is returned in *valuep. On end of file it
* returns NULL
* ------------------------------------------------------------------------- */
char *_kp_get_line(FILE *fp, char **valuep)
char *_kp_get_line(FILE * fp, char **valuep)
{
char *buf, *s;
int found;
char *buf, *s;
int found;
found = 0;
do {
buf = kp_read_line(fp);
if(buf == NULL)
return NULL;
found = 0;
do {
buf = kp_read_line(fp);
if (buf == NULL)
return NULL;
for(s = buf; *s && *s != SEP1; s++);
if(*s)
found = 1;
else
free(buf);
} while(!found);
for (s = buf; *s && *s != SEP1; s++);
if (*s)
found = 1;
else
free(buf);
} while (!found);
*s = '\0';
*valuep = s + 1;
*s = '\0';
*valuep = s + 1;
return buf;
return buf;
}
/* -------------------------------------------------------------------------
* Split the key path into a section, a file path, and a key name.
* If the path contained a colon, *iskeyfile is set to 1
* ------------------------------------------------------------------------- */
int _kp_get_path(const char *keypath, kp_path *kpp, char **keynamep,
int *iskeyfile)
int _kp_get_path(const char *keypath, kp_path * kpp, char **keynamep,
int *iskeyfile)
{
char *path;
char *basedir;
int dbindex;
int ibeg;
int i;
char *path;
char *basedir;
int dbindex;
int ibeg;
int i;
switch(keypath[0]) {
case 'g':
dbindex = KPDB_GLOBAL;
break;
switch (keypath[0]) {
case 'g':
dbindex = KPDB_GLOBAL;
break;
case 'l':
dbindex = KPDB_LOCAL;
break;
case 'l':
dbindex = KPDB_LOCAL;
break;
case 'u':
dbindex = KPDB_USER;
break;
case 'u':
dbindex = KPDB_USER;
break;
default:
return KPERR_NOKEY;
}
default:
return KPERR_NOKEY;
}
/* Skip over the rest of the database selection chars */
keypath++;
while(*keypath && *keypath != '/')
keypath++;
/* Skip over the rest of the database selection chars */
keypath++;
while (*keypath && *keypath != '/')
keypath++;
if(*keypath)
keypath++;
if (*keypath)
keypath++;
kp_init(dbindex);
kp_init(dbindex);
basedir = kp_basedirs[dbindex];
kpp->dbindex = dbindex;
basedir = kp_basedirs[dbindex];
kpp->dbindex = dbindex;
ibeg = strlen(basedir);
ibeg = strlen(basedir);
path = (char *) malloc_check(ibeg + strlen(keypath) + 1);
sprintf(path, "%s%s", basedir, keypath);
path = (char *) malloc_check(ibeg + strlen(keypath) + 1);
sprintf(path, "%s%s", basedir, keypath);
i = ibeg;
for(; path[i]; i++) {
if(path[i] == ':') {
if(path[i+1] == '/')
*keynamep = &path[i + 2];
else
*keynamep = &path[i + 1];
i = ibeg;
for (; path[i]; i++) {
if (path[i] == ':') {
if (path[i + 1] == '/')
*keynamep = &path[i + 2];
else
*keynamep = &path[i + 1];
path[i] = '\0';
kpp->path = path;
if(iskeyfile != NULL)
*iskeyfile = 1;
return 0;
}
}
path[i] = '\0';
kpp->path = path;
if (iskeyfile != NULL)
*iskeyfile = 1;
return 0;
}
}
kpp->path = path;
*keynamep = &path[i];
if(iskeyfile != NULL)
*iskeyfile = 0;
kpp->path = path;
*keynamep = &path[i];
if (iskeyfile != NULL)
*iskeyfile = 0;
return 0;
return 0;
}
/* -------------------------------------------------------------------------
@ -343,55 +343,56 @@ int _kp_get_path(const char *keypath, kp_path *kpp, char **keynamep,
* ------------------------------------------------------------------------- */
int _kp_lock_file(int dbindex, int iswrite)
{
#if 0 /* not needed for Neo? */
struct flock flock;
int res;
char *basedir;
char *lockfile;
int lockfd;
int mode;
#if 0 /* not needed for Neo? */
struct flock flock;
int res;
char *basedir;
char *lockfile;
int lockfd;
int mode;
basedir = kp_basedirs[dbindex];
lockfile = (char *) malloc_check(strlen(basedir) + strlen(LOCKFILE) + 1);
sprintf(lockfile, "%s%s", basedir, LOCKFILE);
basedir = kp_basedirs[dbindex];
lockfile =
(char *) malloc_check(strlen(basedir) + strlen(LOCKFILE) + 1);
sprintf(lockfile, "%s%s", basedir, LOCKFILE);
if(iswrite)
mode = O_RDWR;
else
mode = O_RDONLY;
if (iswrite)
mode = O_RDWR;
else
mode = O_RDONLY;
lockfd = open(lockfile, O_CREAT | mode, 0644);
free(lockfile);
if(lockfd == -1) {
/* Silently return if lockfile creation fails */
return -1;
}
fcntl(lockfd, F_SETFD, FD_CLOEXEC);
lockfd = open(lockfile, O_CREAT | mode, 0644);
free(lockfile);
if (lockfd == -1) {
/* Silently return if lockfile creation fails */
return -1;
}
fcntl(lockfd, F_SETFD, FD_CLOEXEC);
memset(&flock, 0, sizeof(flock));
memset(&flock, 0, sizeof(flock));
if(iswrite)
flock.l_type = F_WRLCK;
else
flock.l_type = F_RDLCK;
if (iswrite)
flock.l_type = F_WRLCK;
else
flock.l_type = F_RDLCK;
flock.l_whence = 0;
flock.l_start = 0;
flock.l_len = 0;
flock.l_whence = 0;
flock.l_start = 0;
flock.l_len = 0;
do {
res = fcntl(lockfd, F_SETLKW, &flock);
}
while(res == -1 && errno == EINTR);
do {
res = fcntl(lockfd, F_SETLKW, &flock);
}
while (res == -1 && errno == EINTR);
if(res == -1 && errno == EDEADLK) {
fprintf(stderr, "keeper: Internal Error: Deadlock\n");
abort();
}
if (res == -1 && errno == EDEADLK) {
fprintf(stderr, "keeper: Internal Error: Deadlock\n");
abort();
}
return lockfd;
return lockfd;
#endif
return -1;
return -1;
}
/* -------------------------------------------------------------------------
@ -399,18 +400,18 @@ int _kp_lock_file(int dbindex, int iswrite)
* ------------------------------------------------------------------------- */
void _kp_unlock_file(int lockfd)
{
#if 0 /* not needed for Neo? */
struct flock flock;
#if 0 /* not needed for Neo? */
struct flock flock;
memset(&flock, 0, sizeof(flock));
memset(&flock, 0, sizeof(flock));
flock.l_type = F_UNLCK;
flock.l_whence = 0;
flock.l_start = 0;
flock.l_len = 0;
flock.l_type = F_UNLCK;
flock.l_whence = 0;
flock.l_start = 0;
flock.l_len = 0;
fcntl(lockfd, F_SETLK, &flock);
close(lockfd);
fcntl(lockfd, F_SETLK, &flock);
close(lockfd);
#endif
}
@ -419,7 +420,7 @@ void _kp_unlock_file(int lockfd)
* ------------------------------------------------------------------------- */
int _kp_get_ibeg(int dbindex)
{
return strlen(kp_basedirs[dbindex]);
return strlen(kp_basedirs[dbindex]);
}
/* -------------------------------------------------------------------------
@ -427,14 +428,16 @@ int _kp_get_ibeg(int dbindex)
* ------------------------------------------------------------------------- */
char *_kp_get_tmpfile(int dbindex)
{
char *basedir;
char *filename;
char *basedir;
char *filename;
basedir = kp_basedirs[dbindex];
filename = (char *) malloc_check(strlen(basedir) + strlen(kp_tmpname) + 1);
sprintf(filename, "%s%s", basedir, kp_tmpname);
basedir = kp_basedirs[dbindex];
filename =
(char *) malloc_check(strlen(basedir) + strlen(kp_tmpname) +
1);
sprintf(filename, "%s%s", basedir, kp_tmpname);
return filename;
return filename;
}
/* -------------------------------------------------------------------------
@ -442,34 +445,35 @@ char *_kp_get_tmpfile(int dbindex)
* ------------------------------------------------------------------------- */
int _kp_errno_to_kperr(int en)
{
switch(en) {
case ENAMETOOLONG:
case EISDIR:
case ENOTDIR:
case ENOTEMPTY:
return KPERR_BADKEY;
switch (en) {
case ENAMETOOLONG:
case EISDIR:
case ENOTDIR:
case ENOTEMPTY:
return KPERR_BADKEY;
case EACCES:
case EROFS:
case EPERM:
return KPERR_NOACCES;
case EACCES:
case EROFS:
case EPERM:
return KPERR_NOACCES;
case ENOENT:
return KPERR_NOKEY;
case ENOENT:
return KPERR_NOKEY;
case EMFILE:
case ENFILE:
case ENOMEM:
case ENOSPC:
return KPERR_NOSPACE;
case EMFILE:
case ENFILE:
case ENOMEM:
case ENOSPC:
return KPERR_NOSPACE;
case EFAULT:
fprintf(stderr, "keeper: Internal Error: Function retured EFAULT\n");
abort();
case EFAULT:
fprintf(stderr,
"keeper: Internal Error: Function retured EFAULT\n");
abort();
default:
return KPERR_BADDB;
}
default:
return KPERR_BADDB;
}
}
/* -------------------------------------------------------------------------
@ -479,22 +483,23 @@ int _kp_errno_to_kperr(int en)
* ------------------------------------------------------------------------- */
static void kp_add_subkey(struct key_array *keys, char *name)
{
char *namedup;
int strsize;
char *namedup;
int strsize;
strsize = strlen(name) + 1;
strsize = ROUND_TO(strsize, 8);
keys->strsize += strsize;
strsize = strlen(name) + 1;
strsize = ROUND_TO(strsize, 8);
keys->strsize += strsize;
keys->num ++;
keys->array = (char **)
check_ptr(realloc(keys->array,
(keys->num + 1) * sizeof(char *) + keys->strsize));
keys->num++;
keys->array = (char **)
check_ptr(realloc(keys->array,
(keys->num + 1) * sizeof(char *) +
keys->strsize));
namedup = strdup_check(name);
namedup = strdup_check(name);
keys->array[keys->num - 1] = namedup;
keys->array[keys->num] = NULL;
keys->array[keys->num - 1] = namedup;
keys->array[keys->num] = NULL;
}
/* -------------------------------------------------------------------------
@ -502,24 +507,24 @@ static void kp_add_subkey(struct key_array *keys, char *name)
* ------------------------------------------------------------------------- */
void _kp_add_subkey_check(struct key_array *keys, char *name)
{
char **kp;
unsigned int namelen;
char *s;
char **kp;
unsigned int namelen;
char *s;
namelen = strlen(name);
s = strchr(name, ':');
if(s != NULL) {
if(s[1] != '\0')
return;
namelen --;
}
namelen = strlen(name);
s = strchr(name, ':');
if (s != NULL) {
if (s[1] != '\0')
return;
namelen--;
}
for(kp = keys->array; *kp != NULL; kp++) {
if(strncmp(*kp, name, namelen) == 0 &&
((*kp)[namelen] == '\0' || (*kp)[namelen] == ':'))
return;
}
kp_add_subkey(keys, name);
for (kp = keys->array; *kp != NULL; kp++) {
if (strncmp(*kp, name, namelen) == 0 &&
((*kp)[namelen] == '\0' || (*kp)[namelen] == ':'))
return;
}
kp_add_subkey(keys, name);
}
/* End of kp_util.c */

View file

@ -18,7 +18,7 @@
** USA
**
** NeoStats CVS Identification
** $Id: kp_util.h,v 1.3 2003/05/26 09:18:30 fishwaldo Exp $
** $Id: kp_util.h,v 1.4 2003/06/13 14:44:37 fishwaldo Exp $
*/
/*
* KEEPER: A configuration reading and writing library
@ -57,7 +57,7 @@
#ifdef ALLOC_CHECK
extern void *_iamalloc(size_t size, int id);
extern void *_iarealloc(void *ptr, size_t size, int id);
extern void _iafree(void *ptr, int id);
extern void _iafree(void *ptr, int id);
#define malloc(size) _iamalloc(size, 4)
#define free(ptr) _iafree(ptr, 4)
#define realloc(ptr, size) _iarealloc(ptr, size, 4)
@ -70,32 +70,32 @@ extern void _iafree(void *ptr, int id);
/* Key list element used to store keys in the cache */
typedef struct _kp_key {
kpval_t type;
unsigned int len;
void *data;
kpval_t type;
unsigned int len;
void *data;
char *name;
int flags;
struct _kp_key *next;
char *name;
int flags;
struct _kp_key *next;
} kp_key;
/* Path of a database file, and the section that it belongs to */
typedef struct {
char *path;
int dbindex;
char *path;
int dbindex;
} kp_path;
/* Key name array used to collect subkeys in a key directory */
struct key_array {
char **array;
unsigned int num;
unsigned int strsize;
char **array;
unsigned int num;
unsigned int strsize;
};
/* Flags for cached keys */
#define KPFL_DIRTY (1 << 0) /* key was modified */
#define KPFL_REMOVED (1 << 1) /* key was removed (negative) */
#define KPFL_BADDB (1 << 2) /* database contained an error for this key */
#define KPFL_DIRTY (1 << 0) /* key was modified */
#define KPFL_REMOVED (1 << 1) /* key was removed (negative) */
#define KPFL_BADDB (1 << 2) /* database contained an error for this key */
/* -------------------------------------------------------------------------
* This function check if an allocation was successful. If not it aborts
@ -106,11 +106,11 @@ struct key_array {
* ------------------------------------------------------------------------- */
static inline void *check_ptr(void *ptr)
{
if(ptr == NULL) {
fprintf(stderr, "keeper: Out of Memory!\n");
abort();
}
return ptr;
if (ptr == NULL) {
fprintf(stderr, "keeper: Out of Memory!\n");
abort();
}
return ptr;
}
/* -------------------------------------------------------------------------
@ -118,7 +118,7 @@ static inline void *check_ptr(void *ptr)
* ------------------------------------------------------------------------- */
static inline void *malloc_check(size_t size)
{
return check_ptr(malloc(size ? size : 1));
return check_ptr(malloc(size ? size : 1));
}
/* -------------------------------------------------------------------------
@ -126,40 +126,40 @@ static inline void *malloc_check(size_t size)
* ------------------------------------------------------------------------- */
static inline char *strdup_check(const char *s)
{
return strcpy((char *) check_ptr(malloc(strlen(s) + 1)), s);
return strcpy((char *) check_ptr(malloc(strlen(s) + 1)), s);
}
/* -------------------------------------------------------------------------
* Create a new key list element, and allocate space for the value data
* ------------------------------------------------------------------------- */
static inline void kp_value_new(kp_key *ck, kpval_t type,
unsigned int len, const void *data)
static inline void kp_value_new(kp_key * ck, kpval_t type,
unsigned int len, const void *data)
{
ck->type = type;
ck->len = len;
if(type != KPVAL_UNKNOWN)
ck->data = malloc_check(ck->len+1);
else
ck->data = NULL;
ck->type = type;
ck->len = len;
if (type != KPVAL_UNKNOWN)
ck->data = malloc_check(ck->len + 1);
else
ck->data = NULL;
ck->flags = 0;
ck->name = NULL;
ck->next = NULL;
ck->flags = 0;
ck->name = NULL;
ck->next = NULL;
if(data != NULL)
memcpy(ck->data, data, ck->len);
if (data != NULL)
memcpy(ck->data, data, ck->len);
}
/* -------------------------------------------------------------------------
* Free allocated data in the key list element. Doesn't free the element
* itself
* ------------------------------------------------------------------------- */
static inline void kp_value_destroy(kp_key *ck)
static inline void kp_value_destroy(kp_key * ck)
{
if(ck->data != NULL)
free(ck->data);
if(ck->name != NULL)
free(ck->name);
if (ck->data != NULL)
free(ck->data);
if (ck->name != NULL)
free(ck->name);
}
/* -------------------------------------------------------------------------
@ -168,38 +168,37 @@ static inline void kp_value_destroy(kp_key *ck)
* ------------------------------------------------------------------------- */
static inline int kp_is_subkey(char *key, char *subkey)
{
unsigned int keylen = strlen(key);
unsigned int keylen = strlen(key);
if(keylen == 0)
return 1;
if (keylen == 0)
return 1;
if(strlen(subkey) > keylen &&
strncmp(subkey, key, keylen) == 0 &&
subkey[keylen] == '/')
return 1;
if (strlen(subkey) > keylen &&
strncmp(subkey, key, keylen) == 0 && subkey[keylen] == '/')
return 1;
return 0;
return 0;
}
/* Internal functions that are used across modules */
extern kpval_t _kp_type_from_code(int c);
extern int _kp_get_path(const char *keypath, kp_path *kpp, char **keynamep,
int *iskeyfile);
extern int _kp_errno_to_kperr(int en);
extern char *_kp_get_line(FILE *fp, char **valuep);
extern int _kp_get_ibeg(int dbindex);
extern int _kp_get_path(const char *keypath, kp_path * kpp,
char **keynamep, int *iskeyfile);
extern int _kp_errno_to_kperr(int en);
extern char *_kp_get_line(FILE * fp, char **valuep);
extern int _kp_get_ibeg(int dbindex);
extern char *_kp_get_tmpfile(int dbindex);
extern void _kp_add_subkey_check(struct key_array *keys, char *name);
extern int _kp_read_file(char *path, kp_key **ksp);
extern int _kp_get_subkeys_dir(char *path, struct key_array *keys);
extern int _kp_write_file(kp_path *kpp, kp_key *keys);
extern int _kp_cache_get(kp_path *kpp, const char *keyname, kpval_t type,
kp_key *ck);
extern int _kp_cache_get_type(kp_path *kpp, char *keyname, int iskeyfile,
kpval_t *tp);
extern int _kp_cache_get_subkeys(kp_path *kpp, const char *keypath,
int iskeyfile, struct key_array *keys);
extern int _kp_cache_set(kp_path *kpp, kp_key *ck);
extern int _kp_cache_flush(void);
extern void _kp_add_subkey_check(struct key_array *keys, char *name);
extern int _kp_read_file(char *path, kp_key ** ksp);
extern int _kp_get_subkeys_dir(char *path, struct key_array *keys);
extern int _kp_write_file(kp_path * kpp, kp_key * keys);
extern int _kp_cache_get(kp_path * kpp, const char *keyname, kpval_t type,
kp_key * ck);
extern int _kp_cache_get_type(kp_path * kpp, char *keyname, int iskeyfile,
kpval_t * tp);
extern int _kp_cache_get_subkeys(kp_path * kpp, const char *keypath,
int iskeyfile, struct key_array *keys);
extern int _kp_cache_set(kp_path * kpp, kp_key * ck);
extern int _kp_cache_flush(void);
/* End of kp_util.h */