1 /* $NetBSD: dlz_sqlite3_dynamic.c,v 1.1.1.3 2014/12/10 03:34:31 christos Exp $ */
4 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the
8 * above copyright notice and this permission notice appear in all
11 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
12 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
13 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
18 * USE OR PERFORMANCE OF THIS SOFTWARE.
20 * The development of Dynamically Loadable Zones (DLZ) for BIND 9 was
21 * conceived and contributed by Rob Butler.
23 * Permission to use, copy, modify, and distribute this software for any
24 * purpose with or without fee is hereby granted, provided that the
25 * above copyright notice and this permission notice appear in all
28 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
29 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35 * USE OR PERFORMANCE OF THIS SOFTWARE.
39 * Copyright (C) 1999-2001 Internet Software Consortium.
40 * Copyright (C) 2013-2014 Internet Systems Consortium.
42 * Permission to use, copy, modify, and distribute this software for any
43 * purpose with or without fee is hereby granted, provided that the above
44 * copyright notice and this permission notice appear in all copies.
46 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
47 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
49 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
50 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
51 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
52 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
53 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
57 * This provides the externally loadable SQLitee DLZ module, without
58 * update support. Based in part on SQLite code contributed by Tim Tessier.
67 #include <dlz_minimal.h>
70 #include <dlz_pthread.h>
74 #define dbc_search_limit 30
82 #define safeGet(in) in == NULL ? "" : in
85 * Structure to hold everthing needed by this "instance" of the SQLite3
86 * module remember, the module code is only loaded once, but may have
87 * many separate instances.
91 db_list_t
*db
; /*%< handle to a list of DB */
94 dbinstance_t
*db
; /*%< handle to DB */
99 /* Helper functions from the dlz_dlopen driver */
101 dns_sdlz_putrr_t
*putrr
;
102 dns_sdlz_putnamedrr_t
*putnamedrr
;
103 dns_dlz_writeablezone_t
*writeable_zone
;
104 } sqlite3_instance_t
;
110 char **pazResult
; /* Result of the query */
111 unsigned int pnRow
; /* Number of result rows */
112 unsigned int pnColumn
; /* Number of result columns */
113 unsigned int curRow
; /* Current row */
114 char *pzErrmsg
; /* Error message */
117 /* forward references */
119 dlz_findzonedb(void *dbdata
, const char *name
,
120 dns_clientinfomethods_t
*methods
,
121 dns_clientinfo_t
*clientinfo
);
124 dlz_destroy(void *dbdata
);
127 b9_add_helper(sqlite3_instance_t
*db
, const char *helper_name
, void *ptr
);
134 sqlite3_destroy(dbinstance_t
*db
) {
135 /* release DB connection */
136 if (db
->dbconn
!= NULL
)
137 sqlite3_close((sqlite3
*) db
->dbconn
);
140 /* destroy DB instance */
141 destroy_dbinstance(db
);
146 * Properly cleans up a list of database instances.
147 * This function is only used when the module is compiled for
148 * multithreaded operation.
151 sqlite3_destroy_dblist(db_list_t
*dblist
) {
152 dbinstance_t
*ndbi
= NULL
;
153 dbinstance_t
*dbi
= NULL
;
155 ndbi
= DLZ_LIST_HEAD(*dblist
);
156 while (ndbi
!= NULL
) {
158 ndbi
= DLZ_LIST_NEXT(dbi
, link
);
160 sqlite3_destroy(dbi
);
163 /* release memory for the list structure */
168 * Loops through the list of DB instances, attempting to lock
169 * on the mutex. If successful, the DBI is reserved for use
170 * and the thread can perform queries against the database.
171 * If the lock fails, the next one in the list is tried.
172 * looping continues until a lock is obtained, or until
173 * the list has been searched dbc_search_limit times.
174 * This function is only used when the module is compiled for
175 * multithreaded operation.
177 static dbinstance_t
*
178 sqlite3_find_avail(sqlite3_instance_t
*sqlite3
) {
179 dbinstance_t
*dbi
= NULL
, *head
;
182 /* get top of list */
183 head
= dbi
= DLZ_LIST_HEAD(*(sqlite3
->db
));
185 /* loop through list */
186 while (count
< dbc_search_limit
) {
187 /* try to lock on the mutex */
188 if (dlz_mutex_trylock(&dbi
->lock
) == 0)
189 return (dbi
); /* success, return the DBI for use. */
191 /* not successful, keep trying */
192 dbi
= DLZ_LIST_NEXT(dbi
, link
);
194 /* check to see if we have gone to the top of the list. */
201 sqlite3
->log(ISC_LOG_INFO
,
202 "SQLite3 module: unable to find available connection "
203 "after searching %d times", count
);
206 #endif /* PTHREADS */
209 * Allocates memory for a new string, and then constructs the new
210 * string by "escaping" the input string. The new string is
211 * safe to be used in queries. This is necessary because we cannot
212 * be sure of what types of strings are passed to us, and we don't
213 * want special characters in the string causing problems.
216 escape_string(const char *instr
) {
220 unsigned int tlen
= 0;
221 unsigned int atlen
= 0;
227 atlen
= (2 * len
* sizeof(char)) + 1;
228 outstr
= malloc(atlen
);
233 for (i
= 0; i
< len
; i
++) {
234 if (tlen
> atlen
|| instr
[i
] == '\0')
237 if (instr
[i
] == '\'') {
251 * This function is the real core of the module. Zone, record
252 * and client strings are passed in (or NULL is passed if the
253 * string is not available). The type of query we want to run
254 * is indicated by the query flag, and the dbdata object is passed
255 * passed in too. dbdata really holds a single database instance.
256 * The function will construct and run the query, hopefully getting
260 sqlite3_get_resultset(const char *zone
, const char *record
,
261 const char *client
, unsigned int query
,
262 void *dbdata
, sqlite3_res_t
**rsp
)
265 dbinstance_t
*dbi
= NULL
;
266 sqlite3_instance_t
*db
= (sqlite3_instance_t
*)dbdata
;
267 char *querystring
= NULL
;
268 sqlite3_res_t
*rs
= NULL
;
273 if ((query
== COUNTZONE
&& rsp
!= NULL
) ||
274 (query
!= COUNTZONE
&& (rsp
== NULL
|| *rsp
!= NULL
)))
276 db
->log(ISC_LOG_DEBUG(2), "Invalid result set pointer.");
277 result
= ISC_R_FAILURE
;
282 /* find an available DBI from the list */
283 dbi
= sqlite3_find_avail(db
);
286 * only 1 DBI - no need to lock instance lock either
287 * only 1 thread in the whole process, no possible contention.
289 dbi
= (dbinstance_t
*)(db
->db
);
290 #endif /* PTHREADS */
293 result
= ISC_R_FAILURE
;
297 /* what type of query are we going to run? */
300 if (dbi
->allnodes_q
== NULL
) {
301 result
= ISC_R_NOTIMPLEMENTED
;
306 if (dbi
->allowxfr_q
== NULL
) {
307 result
= ISC_R_NOTIMPLEMENTED
;
312 if (dbi
->authority_q
== NULL
) {
313 result
= ISC_R_NOTIMPLEMENTED
;
318 if (dbi
->findzone_q
== NULL
) {
319 db
->log(ISC_LOG_DEBUG(2),
320 "No query specified for findzone. "
321 "Findzone requires a query");
322 result
= ISC_R_FAILURE
;
327 if (dbi
->countzone_q
== NULL
) {
328 result
= ISC_R_NOTIMPLEMENTED
;
333 if (dbi
->lookup_q
== NULL
) {
334 db
->log(ISC_LOG_DEBUG(2),
335 "No query specified for lookup. "
336 "Lookup requires a query");
337 result
= ISC_R_FAILURE
;
342 db
->log(ISC_LOG_ERROR
,
343 "Incorrect query flag passed to "
344 "sqlite3_get_resultset");
345 result
= ISC_R_UNEXPECTED
;
351 if (dbi
->zone
!= NULL
)
354 dbi
->zone
= escape_string(zone
);
355 if (dbi
->zone
== NULL
) {
356 result
= ISC_R_NOMEMORY
;
362 if (record
!= NULL
) {
363 if (dbi
->record
!= NULL
)
366 dbi
->record
= escape_string(record
);
367 if (dbi
->record
== NULL
) {
368 result
= ISC_R_NOMEMORY
;
374 if (client
!= NULL
) {
375 if (dbi
->client
!= NULL
)
378 dbi
->client
= escape_string(client
);
379 if (dbi
->client
== NULL
) {
380 result
= ISC_R_NOMEMORY
;
387 * what type of query are we going to run? this time we build
388 * the actual query to run.
392 querystring
= build_querystring(dbi
->allnodes_q
);
395 querystring
= build_querystring(dbi
->allowxfr_q
);
398 querystring
= build_querystring(dbi
->authority_q
);
401 querystring
= build_querystring(dbi
->findzone_q
);
404 querystring
= build_querystring(dbi
->countzone_q
);
407 querystring
= build_querystring(dbi
->lookup_q
);
410 db
->log(ISC_LOG_ERROR
,
411 "Incorrect query flag passed to "
412 "sqlite3_get_resultset");
413 result
= ISC_R_UNEXPECTED
;
417 if (querystring
== NULL
) {
418 result
= ISC_R_NOMEMORY
;
422 /* output the full query string when debugging */
423 db
->log(ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring
);
425 rs
= malloc(sizeof(sqlite3_res_t
));
427 db
->log(ISC_LOG_ERROR
, "Failed to allocate result set");
428 result
= ISC_R_NOMEMORY
;
431 memset(rs
, 0, sizeof(sqlite3_res_t
));
433 qres
= sqlite3_get_table(dbi
->dbconn
, querystring
, &rs
->pazResult
,
434 &rs
->pnRow
, &rs
->pnColumn
, &rs
->pzErrmsg
);
435 if (qres
!= SQLITE_OK
) {
436 db
->log(ISC_LOG_DEBUG(1), "SQLite3 query failed; %s",
437 rs
->pzErrmsg
!= NULL
? rs
->pzErrmsg
: "unknown error");
438 sqlite3_free(rs
->pzErrmsg
);
440 result
= ISC_R_FAILURE
;
444 result
= ISC_R_SUCCESS
;
445 if (query
== COUNTZONE
) {
446 sqlite3_free_table(rs
->pazResult
);
448 result
= ISC_R_FAILURE
;
455 return (ISC_R_FAILURE
);
457 if (dbi
->zone
!= NULL
) {
461 if (dbi
->record
!= NULL
) {
465 if (dbi
->client
!= NULL
) {
470 /* release the lock so another thread can use this dbi */
471 (void) dlz_mutex_unlock(&dbi
->lock
);
473 if (querystring
!= NULL
)
480 * The processing of result sets for lookup and authority are
481 * exactly the same. So that functionality has been moved
482 * into this function to minimize code.
486 sqlite3_fetch_row(sqlite3_res_t
*rs
) {
487 char **retval
= NULL
;
489 if (rs
->pnRow
> 0U && rs
->curRow
< rs
->pnRow
) {
490 int index
= (rs
->curRow
+ 1) * rs
->pnColumn
;
491 retval
= &rs
->pazResult
[index
];
499 sqlite3_num_fields(sqlite3_res_t
*rs
) {
500 unsigned int retval
= 0;
502 retval
= rs
->pnColumn
;
507 sqlite3_num_rows(sqlite3_res_t
*rs
) {
508 unsigned int retval
= 0;
515 sqlite3_free_result(sqlite3_res_t
*rs
) {
517 sqlite3_free_table(rs
->pazResult
);
523 sqlite3_process_rs(sqlite3_instance_t
*db
, dns_sdlzlookup_t
*lookup
,
526 isc_result_t result
= ISC_R_NOTFOUND
;
534 row
= sqlite3_fetch_row(rs
); /* get a row from the result set */
535 fields
= sqlite3_num_fields(rs
); /* how many columns in result set */
536 while (row
!= NULL
) {
537 unsigned int len
= 0;
542 * one column in rs, it's the data field. use
543 * default type of A record, and default TTL
546 result
= db
->putrr(lookup
, "a", 86400, safeGet(row
[0]));
550 * two columns, data field, and data type.
551 * use default TTL of 86400.
553 result
= db
->putrr(lookup
, safeGet(row
[0]), 86400,
558 * three columns, all data no defaults.
559 * convert text to int, make sure it worked
562 ttl
= strtol(safeGet(row
[0]), &endp
, 10);
563 if (*endp
!= '\0' || ttl
< 0) {
564 db
->log(ISC_LOG_ERROR
,
565 "SQLite3 module: TTL must be "
567 return (ISC_R_FAILURE
);
570 result
= db
->putrr(lookup
, safeGet(row
[1]), ttl
,
575 * more than 3 fields, concatenate the last
576 * ones together. figure out how long to make
579 for (j
= 2; j
< fields
; j
++)
580 len
+= strlen(safeGet(row
[j
])) + 1;
583 * allocate string memory, allow for NULL to
586 tmpString
= malloc(len
+ 1);
587 if (tmpString
== NULL
) {
588 db
->log(ISC_LOG_ERROR
,
589 "SQLite3 module: unable to allocate "
590 "memory for temporary string");
591 sqlite3_free_result(rs
);
592 return (ISC_R_FAILURE
);
595 strcpy(tmpString
, safeGet(row
[2]));
596 for (j
= 3; j
< fields
; j
++) {
597 strcat(tmpString
, " ");
598 strcat(tmpString
, safeGet(row
[j
]));
601 ttl
= strtol(safeGet(row
[0]), &endp
, 10);
602 if (*endp
!= '\0' || ttl
< 0) {
603 db
->log(ISC_LOG_ERROR
,
604 "SQLite3 module: TTL must be "
606 return (ISC_R_FAILURE
);
609 result
= db
->putrr(lookup
, safeGet(row
[1]),
614 if (result
!= ISC_R_SUCCESS
) {
615 sqlite3_free_result(rs
);
616 db
->log(ISC_LOG_ERROR
,
617 "putrr returned error: %d", result
);
618 return (ISC_R_FAILURE
);
621 row
= sqlite3_fetch_row(rs
);
624 sqlite3_free_result(rs
);
632 /*% determine if the zone is supported by (in) the database */
634 dlz_findzonedb(void *dbdata
, const char *name
,
635 dns_clientinfomethods_t
*methods
,
636 dns_clientinfo_t
*clientinfo
)
639 sqlite3_res_t
*rs
= NULL
;
641 sqlite3_instance_t
*db
= (sqlite3_instance_t
*)dbdata
;
646 result
= sqlite3_get_resultset(name
, NULL
, NULL
, FINDZONE
, dbdata
, &rs
);
647 if (result
!= ISC_R_SUCCESS
|| rs
== NULL
) {
649 sqlite3_free_result(rs
);
651 db
->log(ISC_LOG_ERROR
,
652 "SQLite3 module: unable to return "
653 "result set for FINDZONE query");
655 return (ISC_R_FAILURE
);
659 * if we returned any rows, the zone is supported.
661 rows
= sqlite3_num_rows(rs
);
662 sqlite3_free_result(rs
);
664 sqlite3_get_resultset(name
, NULL
, NULL
, COUNTZONE
,
666 return (ISC_R_SUCCESS
);
669 return (ISC_R_NOTFOUND
);
672 /*% Determine if the client is allowed to perform a zone transfer */
674 dlz_allowzonexfr(void *dbdata
, const char *name
, const char *client
) {
676 sqlite3_instance_t
*db
= (sqlite3_instance_t
*)dbdata
;
677 sqlite3_res_t
*rs
= NULL
;
680 /* first check if the zone is supported by the database. */
681 result
= dlz_findzonedb(dbdata
, name
, NULL
, NULL
);
682 if (result
!= ISC_R_SUCCESS
)
683 return (ISC_R_NOTFOUND
);
686 * if we get to this point we know the zone is supported by
687 * the database the only questions now are is the zone
688 * transfer is allowed for this client and did the config file
689 * have an allow zone xfr query.
691 result
= sqlite3_get_resultset(name
, NULL
, client
, ALLOWXFR
,
693 if (result
== ISC_R_NOTIMPLEMENTED
)
696 if (result
!= ISC_R_SUCCESS
|| rs
== NULL
) {
698 sqlite3_free_result(rs
);
699 db
->log(ISC_LOG_ERROR
,
700 "SQLite3 module: unable to return "
701 "result set for ALLOWXFR query");
702 return (ISC_R_FAILURE
);
706 * count how many rows in result set; if we returned any,
707 * zone xfr is allowed.
709 rows
= sqlite3_num_rows(rs
);
710 sqlite3_free_result(rs
);
712 return (ISC_R_SUCCESS
);
714 return (ISC_R_NOPERM
);
718 * If the client is allowed to perform a zone transfer, the next order of
719 * business is to get all the nodes in the zone, so bind can respond to the
723 dlz_allnodes(const char *zone
, void *dbdata
, dns_sdlzallnodes_t
*allnodes
) {
725 sqlite3_instance_t
*db
= (sqlite3_instance_t
*)dbdata
;
726 sqlite3_res_t
*rs
= NULL
;
734 result
= sqlite3_get_resultset(zone
, NULL
, NULL
, ALLNODES
, dbdata
, &rs
);
735 if (result
== ISC_R_NOTIMPLEMENTED
)
738 /* if we didn't get a result set, log an err msg. */
739 if (result
!= ISC_R_SUCCESS
) {
740 db
->log(ISC_LOG_ERROR
,
741 "SQLite3 module: unable to return "
742 "result set for all nodes query");
746 result
= ISC_R_NOTFOUND
;
748 fields
= sqlite3_num_fields(rs
);
749 row
= sqlite3_fetch_row(rs
);
750 while (row
!= NULL
) {
752 db
->log(ISC_LOG_ERROR
,
753 "SQLite3 module: too few fields returned "
754 "by ALLNODES query");
755 result
= ISC_R_FAILURE
;
759 ttl
= strtol(safeGet(row
[0]), &endp
, 10);
760 if (*endp
!= '\0' || ttl
< 0) {
761 db
->log(ISC_LOG_ERROR
,
762 "SQLite3 module: TTL must be "
764 result
= ISC_R_FAILURE
;
769 result
= db
->putnamedrr(allnodes
, safeGet(row
[2]),
770 safeGet(row
[1]), ttl
,
773 unsigned int len
= 0;
776 * more than 4 fields, concatenate the last
779 for (j
= 3; j
< fields
; j
++)
780 len
+= strlen(safeGet(row
[j
])) + 1;
782 tmpString
= malloc(len
+ 1);
783 if (tmpString
== NULL
) {
784 db
->log(ISC_LOG_ERROR
,
785 "SQLite3 module: unable to allocate "
786 "memory for temporary string");
787 result
= ISC_R_FAILURE
;
791 strcpy(tmpString
, safeGet(row
[3]));
792 for (j
= 4; j
< fields
; j
++) {
793 strcat(tmpString
, " ");
794 strcat(tmpString
, safeGet(row
[j
]));
797 result
= db
->putnamedrr(allnodes
, safeGet(row
[2]),
803 if (result
!= ISC_R_SUCCESS
) {
804 db
->log(ISC_LOG_ERROR
,
805 "putnamedrr returned error: %s", result
);
806 result
= ISC_R_FAILURE
;
810 row
= sqlite3_fetch_row(rs
);
815 sqlite3_free_result(rs
);
821 * If the lookup function does not return SOA or NS records for the zone,
822 * use this function to get that information for named.
825 dlz_authority(const char *zone
, void *dbdata
, dns_sdlzlookup_t
*lookup
) {
827 sqlite3_res_t
*rs
= NULL
;
828 sqlite3_instance_t
*db
= (sqlite3_instance_t
*) dbdata
;
830 result
= sqlite3_get_resultset(zone
, NULL
, NULL
, AUTHORITY
,
832 if (result
== ISC_R_NOTIMPLEMENTED
)
835 if (result
!= ISC_R_SUCCESS
) {
837 sqlite3_free_result(rs
);
838 db
->log(ISC_LOG_ERROR
,
839 "SQLite3 module: unable to return "
840 "result set for AUTHORITY query");
841 return (ISC_R_FAILURE
);
845 * lookup and authority result sets are processed in the same
846 * manner: sqlite3_process_rs does the job for both functions.
848 return (sqlite3_process_rs(db
, lookup
, rs
));
851 /*% If zone is supported, lookup up a (or multiple) record(s) in it */
853 dlz_lookup(const char *zone
, const char *name
,
854 void *dbdata
, dns_sdlzlookup_t
*lookup
,
855 dns_clientinfomethods_t
*methods
,
856 dns_clientinfo_t
*clientinfo
)
859 sqlite3_res_t
*rs
= NULL
;
860 sqlite3_instance_t
*db
= (sqlite3_instance_t
*) dbdata
;
865 result
= sqlite3_get_resultset(zone
, name
, NULL
, LOOKUP
, dbdata
, &rs
);
867 /* if we didn't get a result set, log an err msg. */
868 if (result
!= ISC_R_SUCCESS
) {
870 sqlite3_free_result(rs
);
871 db
->log(ISC_LOG_ERROR
,
872 "SQLite3 module: unable to return "
873 "result set for LOOKUP query");
874 return (ISC_R_FAILURE
);
878 * lookup and authority result sets are processed in the same
879 * manner: sqlite3_process_rs does the job for both functions.
881 return (sqlite3_process_rs(db
, lookup
, rs
));
885 * Create an instance of the module.
888 dlz_create(const char *dlzname
, unsigned int argc
, char *argv
[],
891 isc_result_t result
= ISC_R_FAILURE
;
892 sqlite3_instance_t
*s3
= NULL
;
893 dbinstance_t
*dbi
= NULL
;
897 const char *helper_name
;
898 #if SQLITE3_VERSION_ID >= 50000
899 my_bool auto_reconnect
= 1;
904 #endif /* PTHREADS */
909 /* allocate memory for SQLite3 instance */
910 s3
= calloc(1, sizeof(sqlite3_instance_t
));
912 return (ISC_R_NOMEMORY
);
913 memset(s3
, 0, sizeof(sqlite3_instance_t
));
915 /* Fill in the helper functions */
916 va_start(ap
, dbdata
);
917 while ((helper_name
= va_arg(ap
, const char*)) != NULL
)
918 b9_add_helper(s3
, helper_name
, va_arg(ap
, void*));
922 /* if debugging, let user know we are multithreaded. */
923 s3
->log(ISC_LOG_DEBUG(1), "SQLite3 module: running multithreaded");
925 /* if debugging, let user know we are single threaded. */
926 s3
->log(ISC_LOG_DEBUG(1), "SQLite3 module: running single threaded");
927 #endif /* PTHREADS */
929 /* verify we have at least 4 arg's passed to the module */
931 s3
->log(ISC_LOG_ERROR
,
932 "SQLite3 module requires "
933 "at least 4 command line args.");
934 return (ISC_R_FAILURE
);
937 /* no more than 8 arg's should be passed to the module */
939 s3
->log(ISC_LOG_ERROR
,
940 "SQLite3 module cannot accept "
941 "more than 8 command line args.");
942 return (ISC_R_FAILURE
);
945 /* get db name - required */
946 s3
->dbname
= get_parameter_value(argv
[1], "dbname=");
947 if (s3
->dbname
== NULL
) {
948 s3
->log(ISC_LOG_ERROR
,
949 "SQLite3 module requires a dbname parameter.");
950 result
= ISC_R_FAILURE
;
955 /* multithreaded build can have multiple DB connections */
956 tmp
= get_parameter_value(argv
[1], "threads=");
960 dbcount
= strtol(tmp
, &endp
, 10);
961 if (*endp
!= '\0' || dbcount
< 1) {
962 s3
->log(ISC_LOG_ERROR
,
963 "SQLite3 module: database connection count "
964 "must be positive.");
966 result
= ISC_R_FAILURE
;
972 /* allocate memory for database connection list */
973 s3
->db
= calloc(1, sizeof(db_list_t
));
974 if (s3
->db
== NULL
) {
975 result
= ISC_R_NOMEMORY
;
979 /* initialize DB connection list */
980 DLZ_LIST_INIT(*(s3
->db
));
983 * create the appropriate number of database instances (DBI)
984 * append each new DBI to the end of the list
986 for (i
= 0; i
< dbcount
; i
++) {
987 #endif /* PTHREADS */
990 result
= build_dbinstance(NULL
, NULL
, NULL
,
991 argv
[2], argv
[3], NULL
,
995 result
= build_dbinstance(NULL
, NULL
, argv
[4],
996 argv
[2], argv
[3], NULL
,
1000 result
= build_dbinstance(argv
[5], NULL
, argv
[4],
1001 argv
[2], argv
[3], NULL
,
1005 result
= build_dbinstance(argv
[5], argv
[6], argv
[4],
1006 argv
[2], argv
[3], NULL
,
1010 result
= build_dbinstance(argv
[5], argv
[6], argv
[4],
1011 argv
[2], argv
[3], argv
[7],
1015 result
= ISC_R_FAILURE
;
1019 if (result
!= ISC_R_SUCCESS
) {
1020 s3
->log(ISC_LOG_ERROR
,
1021 "SQLite3 module: could not create "
1022 "database instance object.");
1023 result
= ISC_R_FAILURE
;
1027 /* create and set db connection */
1028 ret
= sqlite3_initialize();
1029 if (ret
!= SQLITE_OK
) {
1030 s3
->log(ISC_LOG_ERROR
,
1031 "SQLite3 module: could not "
1032 "initialize database object.");
1033 result
= ISC_R_FAILURE
;
1037 ret
= sqlite3_open(s3
->dbname
, &dbc
);
1038 if (ret
!= SQLITE_OK
) {
1039 s3
->log(ISC_LOG_ERROR
,
1040 "SQLite3 module: could not "
1041 "open '%s'.", s3
->dbname
);
1042 result
= ISC_R_FAILURE
;
1047 /* when multithreaded, build a list of DBI's */
1048 DLZ_LINK_INIT(dbi
, link
);
1049 DLZ_LIST_APPEND(*(s3
->db
), dbi
, link
);
1052 * when single threaded, hold onto the one connection
1061 /* set DBI = null for next loop through. */
1064 #endif /* PTHREADS */
1067 return (ISC_R_SUCCESS
);
1076 * Destroy the module.
1079 dlz_destroy(void *dbdata
) {
1080 sqlite3_instance_t
*db
= (sqlite3_instance_t
*)dbdata
;
1082 /* cleanup the list of DBI's */
1084 sqlite3_destroy_dblist((db_list_t
*)(db
->db
));
1085 #else /* PTHREADS */
1086 sqlite3_destroy(db
);
1087 #endif /* PTHREADS */
1089 if (db
->dbname
!= NULL
)
1094 * Return the version of the API
1097 dlz_version(unsigned int *flags
) {
1098 *flags
|= (DNS_SDLZFLAG_RELATIVEOWNER
|
1099 DNS_SDLZFLAG_RELATIVERDATA
|
1100 DNS_SDLZFLAG_THREADSAFE
);
1101 return (DLZ_DLOPEN_VERSION
);
1105 * Register a helper function from the bind9 dlz_dlopen driver
1108 b9_add_helper(sqlite3_instance_t
*db
, const char *helper_name
, void *ptr
) {
1109 if (strcmp(helper_name
, "log") == 0)
1110 db
->log
= (log_t
*)ptr
;
1111 if (strcmp(helper_name
, "putrr") == 0)
1112 db
->putrr
= (dns_sdlz_putrr_t
*)ptr
;
1113 if (strcmp(helper_name
, "putnamedrr") == 0)
1114 db
->putnamedrr
= (dns_sdlz_putnamedrr_t
*)ptr
;
1115 if (strcmp(helper_name
, "writeable_zone") == 0)
1116 db
->writeable_zone
= (dns_dlz_writeablezone_t
*)ptr
;