more format updates
This commit is contained in:
parent
4d85ccb8ab
commit
47b4694e83
26 changed files with 6294 additions and 5279 deletions
2
.gitattributes
vendored
2
.gitattributes
vendored
|
@ -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
1
adns/.indent.pro
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
-br -ce -ts8 -kr -i8 -ut -v
|
474
adns/adns.h
474
adns/adns.h
|
@ -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
|
||||
|
|
258
adns/check.c
258
adns/check.c
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
1319
adns/event.c
1319
adns/event.c
File diff suppressed because it is too large
Load diff
529
adns/general.c
529
adns/general.c
|
@ -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);
|
||||
}
|
||||
|
|
539
adns/internal.h
539
adns/internal.h
|
@ -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 */
|
||||
|
||||
|
|
446
adns/parse.c
446
adns/parse.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
910
adns/query.c
910
adns/query.c
File diff suppressed because it is too large
Load diff
739
adns/reply.c
739
adns/reply.c
|
@ -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);
|
||||
}
|
||||
|
|
1158
adns/setup.c
1158
adns/setup.c
File diff suppressed because it is too large
Load diff
438
adns/transmit.c
438
adns/transmit.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
1533
adns/types.c
1533
adns/types.c
File diff suppressed because it is too large
Load diff
1
keeper/.indent.pro
vendored
Normal file
1
keeper/.indent.pro
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
-br -ce -ts8 -kr -i8 -ut -v
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
531
keeper/kp_get.c
531
keeper/kp_get.c
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
640
keeper/kp_set.c
640
keeper/kp_set.c
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
541
keeper/kp_util.c
541
keeper/kp_util.c
|
@ -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 */
|
||||
|
|
131
keeper/kp_util.h
131
keeper/kp_util.h
|
@ -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 */
|
||||
|
|
Reference in a new issue