Annotation of src/external/mpl/bind/dist/contrib/dlz/drivers/dlz_postgres_driver.c, Revision 1.1.1.3
1.1 christos 1: /* $NetBSD$ */
2:
3: /*
4: * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
5: *
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
9: * copies.
10: *
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.
19: *
20: * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
21: * conceived and contributed by Rob Butler.
22: *
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
26: * copies.
27: *
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.
36: */
37:
38: /*
39: * Copyright (C) 1999-2001, 2016 Internet Systems Consortium, Inc. ("ISC")
40: *
41: * This Source Code Form is subject to the terms of the Mozilla Public
42: * License, v. 2.0. If a copy of the MPL was not distributed with this
43: * file, You can obtain one at http://mozilla.org/MPL/2.0/.
44: */
45:
46: #ifdef DLZ_POSTGRES
47: #include <stdio.h>
48: #include <stdlib.h>
1.1.1.3 ! christos 49: #include <string.h>
1.1 christos 50:
51: #include <isc/mem.h>
52: #include <isc/platform.h>
53: #include <isc/print.h>
54: #include <isc/result.h>
55: #include <isc/string.h>
56: #include <isc/util.h>
57:
1.1.1.3 ! christos 58: #include <dns/log.h>
! 59: #include <dns/result.h>
! 60: #include <dns/sdlz.h>
1.1 christos 61:
62: #include <dlz/dlz_postgres_driver.h>
1.1.1.3 ! christos 63: #include <dlz/sdlz_helper.h>
! 64: #include <named/globals.h>
1.1 christos 65:
66: /* temporarily include time. */
67: #include <libpq-fe.h>
1.1.1.3 ! christos 68: #include <time.h>
1.1 christos 69:
70: static dns_sdlzimplementation_t *dlz_postgres = NULL;
71:
72: #define dbc_search_limit 30
1.1.1.3 ! christos 73: #define ALLNODES 1
! 74: #define ALLOWXFR 2
! 75: #define AUTHORITY 3
! 76: #define FINDZONE 4
! 77: #define LOOKUP 5
1.1 christos 78:
79: /*
80: * Private methods
81: */
82:
83: /* ---------------
84: * Escaping arbitrary strings to get valid SQL strings/identifiers.
85: *
86: * Replaces "\\" with "\\\\" and "'" with "''".
87: * length is the length of the buffer pointed to by
88: * from. The buffer at to must be at least 2*length + 1 characters
89: * long. A terminating NUL character is written.
90: *
91: * NOTICE!!!
92: * This function was borrowed directly from PostgreSQL's libpq.
93: * The function was originally called PQescapeString and renamed
94: * to postgres_makesafe to avoid a naming collision.
95: * PQescapeString is a new function made available in Postgres 7.2.
96: * For some reason the function is not properly exported on Win32
97: * builds making the function unavailable on Windows. Also, since
98: * this function is new it would require building this driver with
99: * the libpq 7.2. By borrowing this function the Windows problem
100: * is solved, and the dependence on libpq 7.2 is removed. Libpq is
101: * still required of course, but an older version should work now too.
102: *
103: * The copyright statements from the original file containing this
104: * function are included below:
105: * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
106: * Portions Copyright (c) 1994, Regents of the University of California
107: * ---------------
108: */
109:
110: static size_t
1.1.1.3 ! christos 111: postgres_makesafe(char *to, const char *from, size_t length) {
1.1 christos 112: const char *source = from;
1.1.1.3 ! christos 113: char *target = to;
1.1 christos 114: unsigned int remaining = length;
115:
1.1.1.3 ! christos 116: while (remaining > 0) {
! 117: switch (*source) {
1.1 christos 118: case '\\':
119: *target = '\\';
120: target++;
121: *target = '\\';
122: /* target and remaining are updated below. */
123: break;
124:
125: case '\'':
126: *target = '\'';
127: target++;
128: *target = '\'';
129: /* target and remaining are updated below. */
130: break;
131:
132: default:
133: *target = *source;
134: /* target and remaining are updated below. */
135: }
136: source++;
137: target++;
138: remaining--;
139: }
140:
141: /* Write the terminating NUL character. */
142: *target = '\0';
143:
1.1.1.3 ! christos 144: return (target - to);
1.1 christos 145: }
146:
147: /*%
148: * Properly cleans up a list of database instances.
149: * This function is only used when the driver is compiled for
150: * multithreaded operation.
151: */
152: static void
1.1.1.3 ! christos 153: postgres_destroy_dblist(db_list_t *dblist) {
1.1 christos 154: dbinstance_t *ndbi = NULL;
155: dbinstance_t *dbi = NULL;
156:
157: /* get the first DBI in the list */
158: ndbi = ISC_LIST_HEAD(*dblist);
159:
160: /* loop through the list */
161: while (ndbi != NULL) {
162: dbi = ndbi;
163: /* get the next DBI in the list */
164: ndbi = ISC_LIST_NEXT(dbi, link);
165: /* release DB connection */
1.1.1.3 ! christos 166: if (dbi->dbconn != NULL) {
! 167: PQfinish((PGconn *)dbi->dbconn);
! 168: }
1.1 christos 169: /* release all memory that comprised a DBI */
170: destroy_sqldbinstance(dbi);
171: }
172: /* release memory for the list structure */
173: isc_mem_put(named_g_mctx, dblist, sizeof(db_list_t));
174: }
175:
176: /*%
177: * Loops through the list of DB instances, attempting to lock
178: * on the mutex. If successful, the DBI is reserved for use
179: * and the thread can perform queries against the database.
180: * If the lock fails, the next one in the list is tried.
181: * looping continues until a lock is obtained, or until
182: * the list has been searched dbc_search_limit times.
183: * This function is only used when the driver is compiled for
184: * multithreaded operation.
185: */
186:
187: static dbinstance_t *
1.1.1.3 ! christos 188: postgres_find_avail_conn(db_list_t *dblist) {
1.1 christos 189: dbinstance_t *dbi = NULL;
190: dbinstance_t *head;
191: int count = 0;
192:
193: /* get top of list */
194: head = dbi = ISC_LIST_HEAD(*dblist);
195:
196: /* loop through list */
197: while (count < dbc_search_limit) {
198: /* try to lock on the mutex */
1.1.1.3 ! christos 199: if (isc_mutex_trylock(&dbi->instance_lock) == ISC_R_SUCCESS) {
! 200: return (dbi); /* success, return the DBI for use. */
! 201: }
1.1 christos 202: /* not successful, keep trying */
203: dbi = ISC_LIST_NEXT(dbi, link);
204:
205: /* check to see if we have gone to the top of the list. */
206: if (dbi == NULL) {
207: count++;
208: dbi = head;
209: }
210: }
1.1.1.3 ! christos 211: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
! 212: ISC_LOG_INFO,
1.1 christos 213: "Postgres driver unable to find available connection "
214: "after searching %d times",
215: count);
1.1.1.3 ! christos 216: return (NULL);
1.1 christos 217: }
218:
219: /*%
220: * Allocates memory for a new string, and then constructs the new
221: * string by "escaping" the input string. The new string is
222: * safe to be used in queries. This is necessary because we cannot
223: * be sure of what types of strings are passed to us, and we don't
224: * want special characters in the string causing problems.
225: */
226:
227: static char *
228: postgres_escape_string(const char *instr) {
229: char *outstr;
230: unsigned int len;
231:
1.1.1.3 ! christos 232: if (instr == NULL) {
! 233: return (NULL);
! 234: }
1.1 christos 235:
236: len = strlen(instr);
237:
1.1.1.3 ! christos 238: outstr = isc_mem_allocate(named_g_mctx, (2 * len * sizeof(char)) + 1);
1.1 christos 239:
240: postgres_makesafe(outstr, instr, len);
241: /* PQescapeString(outstr, instr, len); */
242:
1.1.1.3 ! christos 243: return (outstr);
1.1 christos 244: }
245:
246: /*%
247: * This function is the real core of the driver. Zone, record
248: * and client strings are passed in (or NULL is passed if the
249: * string is not available). The type of query we want to run
250: * is indicated by the query flag, and the dbdata object is passed
251: * passed in to. dbdata really holds either:
252: * 1) a list of database instances (in multithreaded mode) OR
253: * 2) a single database instance (in single threaded mode)
254: * The function will construct the query and obtain an available
255: * database instance (DBI). It will then run the query and hopefully
256: * obtain a result set. Postgres is nice, in that once the result
257: * set is returned, we can make the db connection available for another
258: * thread to use, while this thread continues on. So, the DBI is made
259: * available ASAP by unlocking the instance_lock after we have cleaned
260: * it up properly.
261: */
262: static isc_result_t
1.1.1.3 ! christos 263: postgres_get_resultset(const char *zone, const char *record, const char *client,
! 264: unsigned int query, void *dbdata, PGresult **rs) {
1.1 christos 265: isc_result_t result;
266: dbinstance_t *dbi = NULL;
267: char *querystring = NULL;
268: unsigned int i = 0;
269: unsigned int j = 0;
270:
271: #if 0
272: /* temporarily get a unique thread # */
1.1.1.3 ! christos 273: unsigned int dlz_thread_num = 1 +
! 274: (int) (1000.0 * rand() /
! 275: (RAND_MAX + 1.0));
! 276: #endif /* if 0 */
1.1 christos 277:
278: REQUIRE(*rs == NULL);
279:
280: #if 0
281: /* temporary logging message */
282: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
283: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
284: "%d Getting DBI", dlz_thread_num);
1.1.1.3 ! christos 285: #endif /* if 0 */
1.1 christos 286:
287: /* get db instance / connection */
288:
289: /* find an available DBI from the list */
1.1.1.3 ! christos 290: dbi = postgres_find_avail_conn((db_list_t *)dbdata);
1.1 christos 291:
292: #if 0
293: /* temporary logging message */
294: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
295: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
296: "%d Got DBI - checking query", dlz_thread_num);
1.1.1.3 ! christos 297: #endif /* if 0 */
1.1 christos 298:
299: /* if DBI is null, can't do anything else */
300: if (dbi == NULL) {
1.1.1.3 ! christos 301: return (ISC_R_FAILURE);
1.1 christos 302: }
303:
304: /* what type of query are we going to run? */
1.1.1.3 ! christos 305: switch (query) {
1.1 christos 306: case ALLNODES:
307: /*
308: * if the query was not passed in from the config file
309: * then we can't run it. return not_implemented, so
310: * it's like the code for that operation was never
311: * built into the driver.... AHHH flexibility!!!
312: */
313: if (dbi->allnodes_q == NULL) {
314: result = ISC_R_NOTIMPLEMENTED;
315: goto cleanup;
316: }
317: break;
318: case ALLOWXFR:
319: /* same as comments as ALLNODES */
320: if (dbi->allowxfr_q == NULL) {
321: result = ISC_R_NOTIMPLEMENTED;
322: goto cleanup;
323: }
324: break;
325: case AUTHORITY:
326: /* same as comments as ALLNODES */
327: if (dbi->authority_q == NULL) {
328: result = ISC_R_NOTIMPLEMENTED;
329: goto cleanup;
330: }
331: break;
332: case FINDZONE:
333: /* this is required. It's the whole point of DLZ! */
334: if (dbi->findzone_q == NULL) {
335: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
336: DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
337: "No query specified for findzone. "
338: "Findzone requires a query");
339: result = ISC_R_FAILURE;
340: goto cleanup;
341: }
342: break;
343: case LOOKUP:
344: /* this is required. It's also a major point of DLZ! */
345: if (dbi->lookup_q == NULL) {
346: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
347: DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
348: "No query specified for lookup. "
349: "Lookup requires a query");
350: result = ISC_R_FAILURE;
351: goto cleanup;
352: }
353: break;
354: default:
355: /*
356: * this should never happen. If it does, the code is
357: * screwed up!
358: */
359: UNEXPECTED_ERROR(__FILE__, __LINE__,
360: "Incorrect query flag passed to "
361: "postgres_get_resultset");
362: result = ISC_R_UNEXPECTED;
363: goto cleanup;
364: }
365:
366: #if 0
367: /* temporary logging message */
368: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
369: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
370: "%d checked query", dlz_thread_num);
1.1.1.3 ! christos 371: #endif /* if 0 */
1.1 christos 372:
373: /*
374: * was a zone string passed? If so, make it safe for use in
375: * queries.
376: */
377: if (zone != NULL) {
378: dbi->zone = postgres_escape_string(zone);
379: if (dbi->zone == NULL) {
380: result = ISC_R_NOMEMORY;
381: goto cleanup;
382: }
1.1.1.3 ! christos 383: } else { /* no string passed, set the string pointer to NULL */
1.1 christos 384: dbi->zone = NULL;
385: }
386:
387: #if 0
388: /* temporary logging message */
389: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
390: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
391: "%d did zone", dlz_thread_num);
1.1.1.3 ! christos 392: #endif /* if 0 */
1.1 christos 393:
394: /*
395: * was a record string passed? If so, make it safe for use in
396: * queries.
397: */
398: if (record != NULL) {
399: dbi->record = postgres_escape_string(record);
400: if (dbi->record == NULL) {
401: result = ISC_R_NOMEMORY;
402: goto cleanup;
403: }
1.1.1.3 ! christos 404: } else { /* no string passed, set the string pointer to NULL */
1.1 christos 405: dbi->record = NULL;
406: }
407:
408: #if 0
409: /* temporary logging message */
410: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
411: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
412: "%d did record", dlz_thread_num);
1.1.1.3 ! christos 413: #endif /* if 0 */
1.1 christos 414:
415: /*
416: * was a client string passed? If so, make it safe for use in
417: * queries.
418: */
419: if (client != NULL) {
420: dbi->client = postgres_escape_string(client);
421: if (dbi->client == NULL) {
422: result = ISC_R_NOMEMORY;
423: goto cleanup;
424: }
1.1.1.3 ! christos 425: } else { /* no string passed, set the string pointer to NULL */
1.1 christos 426: dbi->client = NULL;
427: }
428:
429: #if 0
430: /* temporary logging message */
431: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1.1.1.3 ! christos 432: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1.1 christos 433: "%d did client", dlz_thread_num);
1.1.1.3 ! christos 434: #endif /* if 0 */
1.1 christos 435:
436: /*
437: * what type of query are we going to run?
438: * this time we build the actual query to run.
439: */
1.1.1.3 ! christos 440: switch (query) {
1.1 christos 441: case ALLNODES:
442: querystring = build_querystring(named_g_mctx, dbi->allnodes_q);
443: break;
444: case ALLOWXFR:
445: querystring = build_querystring(named_g_mctx, dbi->allowxfr_q);
446: break;
447: case AUTHORITY:
448: querystring = build_querystring(named_g_mctx, dbi->authority_q);
449: break;
450: case FINDZONE:
451: querystring = build_querystring(named_g_mctx, dbi->findzone_q);
452: break;
453: case LOOKUP:
454: querystring = build_querystring(named_g_mctx, dbi->lookup_q);
455: break;
456: default:
457: /*
458: * this should never happen. If it does, the code is
459: * screwed up!
460: */
461: UNEXPECTED_ERROR(__FILE__, __LINE__,
462: "Incorrect query flag passed to "
463: "postgres_get_resultset");
464: result = ISC_R_UNEXPECTED;
465: goto cleanup;
466: }
467:
468: #if 0
469: /* temporary logging message */
470: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
471: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
472: "%d built query", dlz_thread_num);
1.1.1.3 ! christos 473: #endif /* if 0 */
1.1 christos 474:
475: /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */
1.1.1.3 ! christos 476: if (querystring == NULL) {
1.1 christos 477: result = ISC_R_NOMEMORY;
478: goto cleanup;
479: }
480:
481: #if 0
482: /* temporary logging message */
483: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
484: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
485: "%d query is '%s'", dlz_thread_num, querystring);
1.1.1.3 ! christos 486: #endif /* if 0 */
1.1 christos 487:
488: /*
489: * output the full query string during debug so we can see
490: * what lame error the query has.
491: */
1.1.1.3 ! christos 492: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
! 493: ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring);
1.1 christos 494:
495: /* attempt query up to 3 times. */
1.1.1.3 ! christos 496: for (j = 0; j < 3; j++) {
1.1 christos 497: #if 0
498: /* temporary logging message */
499: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
500: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
501: "%d executing query for %d time",
502: dlz_thread_num, j);
1.1.1.3 ! christos 503: #endif /* if 0 */
1.1 christos 504: /* try to get result set */
1.1.1.3 ! christos 505: *rs = PQexec((PGconn *)dbi->dbconn, querystring);
1.1 christos 506: result = ISC_R_SUCCESS;
507: /*
508: * if result set is null, reset DB connection, max 3
509: * attempts.
510: */
1.1.1.3 ! christos 511: for (i = 0; *rs == NULL && i < 3; i++) {
1.1 christos 512: #if 0
513: /* temporary logging message */
514: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
515: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
516: "%d resetting connection",
517: dlz_thread_num);
1.1.1.3 ! christos 518: #endif /* if 0 */
1.1 christos 519: result = ISC_R_FAILURE;
1.1.1.3 ! christos 520: PQreset((PGconn *)dbi->dbconn);
1.1 christos 521: /* connection ok, break inner loop */
1.1.1.3 ! christos 522: if (PQstatus((PGconn *)dbi->dbconn) == CONNECTION_OK) {
1.1 christos 523: break;
1.1.1.3 ! christos 524: }
1.1 christos 525: }
1.1.1.3 ! christos 526: /* result set ok, break outer loop */
1.1 christos 527: if (PQresultStatus(*rs) == PGRES_TUPLES_OK) {
528: #if 0
529: /* temporary logging message */
530: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
531: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
532: "%d rs ok", dlz_thread_num);
1.1.1.3 ! christos 533: #endif /* if 0 */
1.1 christos 534: break;
535: } else {
536: /* we got a result set object, but it's not right. */
537: #if 0
538: /* temporary logging message */
539: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
540: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
541: "%d clearing rs", dlz_thread_num);
1.1.1.3 ! christos 542: #endif /* if 0 */
! 543: PQclear(*rs); /* get rid of it */
1.1 christos 544: /* in case this was the last attempt */
545: *rs = NULL;
546: result = ISC_R_FAILURE;
547: }
548: }
549:
1.1.1.3 ! christos 550: cleanup:
1.1 christos 551: /* it's always good to cleanup after yourself */
552:
553: #if 0
554: /* temporary logging message */
555: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
556: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
557: "%d cleaning up", dlz_thread_num);
1.1.1.3 ! christos 558: #endif /* if 0 */
1.1 christos 559:
560: /* free dbi->zone string */
1.1.1.3 ! christos 561: if (dbi->zone != NULL) {
1.1 christos 562: isc_mem_free(named_g_mctx, dbi->zone);
1.1.1.3 ! christos 563: }
1.1 christos 564:
565: /* free dbi->record string */
1.1.1.3 ! christos 566: if (dbi->record != NULL) {
1.1 christos 567: isc_mem_free(named_g_mctx, dbi->record);
1.1.1.3 ! christos 568: }
1.1 christos 569:
570: /* free dbi->client string */
1.1.1.3 ! christos 571: if (dbi->client != NULL) {
1.1 christos 572: isc_mem_free(named_g_mctx, dbi->client);
1.1.1.3 ! christos 573: }
1.1 christos 574:
575: #if 0
576: /* temporary logging message */
577: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
578: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
579: "%d unlocking mutex", dlz_thread_num);
1.1.1.3 ! christos 580: #endif /* if 0 */
1.1 christos 581:
582: /* release the lock so another thread can use this dbi */
583: isc_mutex_unlock(&dbi->instance_lock);
584:
585: /* release query string */
1.1.1.3 ! christos 586: if (querystring != NULL) {
! 587: isc_mem_free(named_g_mctx, querystring);
! 588: }
1.1 christos 589:
590: #if 0
591: /* temporary logging message */
592: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
593: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
594: "%d returning", dlz_thread_num);
1.1.1.3 ! christos 595: #endif /* if 0 */
1.1 christos 596:
597: /* return result */
1.1.1.3 ! christos 598: return (result);
1.1 christos 599: }
600:
601: /*%
602: * The processing of result sets for lookup and authority are
603: * exactly the same. So that functionality has been moved
604: * into this function to minimize code.
605: */
606:
607: static isc_result_t
1.1.1.3 ! christos 608: postgres_process_rs(dns_sdlzlookup_t *lookup, PGresult *rs) {
1.1 christos 609: isc_result_t result;
610: unsigned int i;
611: unsigned int rows;
612: unsigned int fields;
613: unsigned int j;
614: unsigned int len;
615: char *tmpString;
616: char *endp;
617: int ttl;
618:
619: rows = PQntuples(rs); /* how many rows in result set */
1.1.1.3 ! christos 620: fields = PQnfields(rs); /* how many columns in result set */
! 621: for (i = 0; i < rows; i++) {
! 622: switch (fields) {
1.1 christos 623: case 1:
624: /*
625: * one column in rs, it's the data field. use
626: * default type of A record, and default TTL
627: * of 86400
628: */
629: result = dns_sdlz_putrr(lookup, "a", 86400,
630: PQgetvalue(rs, i, 0));
631: break;
632: case 2:
633: /* two columns, data field, and data type.
634: * use default TTL of 86400.
635: */
636: result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 0),
637: 86400, PQgetvalue(rs, i, 1));
638: break;
639: case 3:
640: /* three columns, all data no defaults.
641: * convert text to int, make sure it worked
642: * right.
643: */
644: ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
645: if (*endp != '\0' || ttl < 0) {
646: isc_log_write(dns_lctx,
647: DNS_LOGCATEGORY_DATABASE,
648: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
649: "Postgres driver ttl must be "
650: "a positive number");
651: }
652: result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 1),
653: ttl, PQgetvalue(rs, i, 2));
654: break;
655: default:
1.1.1.3 ! christos 656: /*
1.1 christos 657: * more than 3 fields, concatenate the last
658: * ones together. figure out how long to make
659: * string
660: */
1.1.1.3 ! christos 661: for (j = 2, len = 0; j < fields; j++) {
1.1 christos 662: len += strlen(PQgetvalue(rs, i, j)) + 1;
663: }
664: /*
665: * allocate string memory, allow for NULL to
666: * term string
667: */
668: tmpString = isc_mem_allocate(named_g_mctx, len + 1);
669: /* copy field to tmpString */
670: strcpy(tmpString, PQgetvalue(rs, i, 2));
671: /*
672: * concat the rest of fields together, space
673: * between each one.
674: */
1.1.1.3 ! christos 675: for (j = 3; j < fields; j++) {
1.1 christos 676: strcat(tmpString, " ");
677: strcat(tmpString, PQgetvalue(rs, i, j));
678: }
679: /* convert text to int, make sure it worked right */
680: ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
681: if (*endp != '\0' || ttl < 0) {
682: isc_log_write(dns_lctx,
683: DNS_LOGCATEGORY_DATABASE,
684: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
685: "Postgres driver ttl must be "
1.1.1.3 ! christos 686: "a positive number");
1.1 christos 687: }
688: /* ok, now tell Bind about it. */
689: result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 1),
690: ttl, tmpString);
691: /* done, get rid of this thing. */
692: isc_mem_free(named_g_mctx, tmpString);
693: }
694: /* I sure hope we were successful */
695: if (result != ISC_R_SUCCESS) {
696: /* nope, get rid of the Result set, and log a msg */
697: PQclear(rs);
698: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
699: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
700: "dns_sdlz_putrr returned error. "
701: "Error code was: %s",
702: isc_result_totext(result));
703: return (ISC_R_FAILURE);
704: }
705: }
706:
707: /* free result set memory */
708: PQclear(rs);
709:
710: /* if we did return results, we are successful */
1.1.1.3 ! christos 711: if (rows > 0) {
1.1 christos 712: return (ISC_R_SUCCESS);
1.1.1.3 ! christos 713: }
1.1 christos 714:
715: /* empty result set, no data found */
716: return (ISC_R_NOTFOUND);
717: }
718:
719: /*
720: * SDLZ interface methods
721: */
722:
723: /*% determine if the zone is supported by (in) the database */
724:
725: static isc_result_t
726: postgres_findzone(void *driverarg, void *dbdata, const char *name,
727: dns_clientinfomethods_t *methods,
1.1.1.3 ! christos 728: dns_clientinfo_t *clientinfo) {
1.1 christos 729: isc_result_t result;
730: PGresult *rs = NULL;
731: unsigned int rows;
732:
733: UNUSED(driverarg);
734: UNUSED(methods);
735: UNUSED(clientinfo);
736:
737: /* run the query and get the result set from the database. */
1.1.1.3 ! christos 738: result = postgres_get_resultset(name, NULL, NULL, FINDZONE, dbdata,
! 739: &rs);
1.1 christos 740: /* if we didn't get a result set, log an err msg. */
741: if (result != ISC_R_SUCCESS) {
1.1.1.3 ! christos 742: if (rs != NULL) {
1.1 christos 743: PQclear(rs);
1.1.1.3 ! christos 744: }
1.1 christos 745: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
746: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
747: "Postgres driver unable to return "
748: "result set for findzone query");
749: return (ISC_R_FAILURE);
750: }
751: /* count how many rows in result set */
752: rows = PQntuples(rs);
753: /* get rid of result set, we are done with it. */
754: PQclear(rs);
755:
756: /* if we returned any rows, zone is supported. */
1.1.1.3 ! christos 757: if (rows > 0) {
1.1 christos 758: return (ISC_R_SUCCESS);
1.1.1.3 ! christos 759: }
1.1 christos 760:
761: /* no rows returned, zone is not supported. */
762: return (ISC_R_NOTFOUND);
763: }
764:
765: /*% Determine if the client is allowed to perform a zone transfer */
766: static isc_result_t
767: postgres_allowzonexfr(void *driverarg, void *dbdata, const char *name,
1.1.1.3 ! christos 768: const char *client) {
1.1 christos 769: isc_result_t result;
770: PGresult *rs = NULL;
771: unsigned int rows;
772: UNUSED(driverarg);
773:
774: /* first check if the zone is supported by the database. */
775: result = postgres_findzone(driverarg, dbdata, name, NULL, NULL);
1.1.1.3 ! christos 776: if (result != ISC_R_SUCCESS) {
1.1 christos 777: return (ISC_R_NOTFOUND);
1.1.1.3 ! christos 778: }
1.1 christos 779:
780: /*
781: * if we get to this point we know the zone is supported by
782: * the database the only questions now are is the zone
783: * transfer is allowed for this client and did the config file
784: * have an allow zone xfr query.
785: *
786: * Run our query, and get a result set from the database.
787: */
1.1.1.3 ! christos 788: result = postgres_get_resultset(name, NULL, client, ALLOWXFR, dbdata,
! 789: &rs);
1.1 christos 790: /* if we get "not implemented", send it along. */
1.1.1.3 ! christos 791: if (result == ISC_R_NOTIMPLEMENTED) {
! 792: return (result);
! 793: }
1.1 christos 794: /* if we didn't get a result set, log an err msg. */
795: if (result != ISC_R_SUCCESS) {
1.1.1.3 ! christos 796: if (rs != NULL) {
1.1 christos 797: PQclear(rs);
1.1.1.3 ! christos 798: }
1.1 christos 799: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
800: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
801: "Postgres driver unable to return "
802: "result set for allow xfr query");
803: return (ISC_R_FAILURE);
804: }
805: /* count how many rows in result set */
806: rows = PQntuples(rs);
807: /* get rid of result set, we are done with it. */
808: PQclear(rs);
809:
810: /* if we returned any rows, zone xfr is allowed. */
1.1.1.3 ! christos 811: if (rows > 0) {
1.1 christos 812: return (ISC_R_SUCCESS);
1.1.1.3 ! christos 813: }
1.1 christos 814:
815: /* no rows returned, zone xfr not allowed */
816: return (ISC_R_NOPERM);
817: }
818:
819: /*%
820: * If the client is allowed to perform a zone transfer, the next order of
821: * business is to get all the nodes in the zone, so bind can respond to the
822: * query.
823: */
824: static isc_result_t
825: postgres_allnodes(const char *zone, void *driverarg, void *dbdata,
1.1.1.3 ! christos 826: dns_sdlzallnodes_t *allnodes) {
1.1 christos 827: isc_result_t result;
828: PGresult *rs = NULL;
829: unsigned int i;
830: unsigned int rows;
831: unsigned int fields;
832: unsigned int j;
833: unsigned int len;
834: char *tmpString;
835: char *endp;
836: int ttl;
837:
838: UNUSED(driverarg);
839:
840: /* run the query and get the result set from the database. */
1.1.1.3 ! christos 841: result = postgres_get_resultset(zone, NULL, NULL, ALLNODES, dbdata,
! 842: &rs);
1.1 christos 843: /* if we get "not implemented", send it along */
1.1.1.3 ! christos 844: if (result == ISC_R_NOTIMPLEMENTED) {
! 845: return (result);
! 846: }
1.1 christos 847: /* if we didn't get a result set, log an err msg. */
848: if (result != ISC_R_SUCCESS) {
1.1.1.3 ! christos 849: if (rs != NULL) {
1.1 christos 850: PQclear(rs);
1.1.1.3 ! christos 851: }
1.1 christos 852: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
853: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
854: "Postgres driver unable to return "
855: "result set for all nodes query");
856: return (ISC_R_FAILURE);
857: }
858:
859: rows = PQntuples(rs); /* how many rows in result set */
1.1.1.3 ! christos 860: fields = PQnfields(rs); /* how many columns in result set */
! 861: for (i = 0; i < rows; i++) {
! 862: if (fields < 4) { /* gotta have at least 4 columns */
1.1 christos 863: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
864: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
865: "Postgres driver too few fields "
866: "returned by all nodes query");
867: }
868: /* convert text to int, make sure it worked right */
869: ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10);
870: if (*endp != '\0' || ttl < 0) {
871: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
872: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
873: "Postgres driver ttl must be "
1.1.1.3 ! christos 874: "a positive number");
1.1 christos 875: }
876: if (fields == 4) {
877: /* tell Bind about it. */
878: result = dns_sdlz_putnamedrr(allnodes,
879: PQgetvalue(rs, i, 2),
1.1.1.3 ! christos 880: PQgetvalue(rs, i, 1), ttl,
1.1 christos 881: PQgetvalue(rs, i, 3));
882: } else {
883: /*
884: * more than 4 fields, concatonat the last
885: * ones together. figure out how long to make
886: * string
887: */
1.1.1.3 ! christos 888: for (j = 3, len = 0; j < fields; j++) {
1.1 christos 889: len += strlen(PQgetvalue(rs, i, j)) + 1;
890: }
891: /* allocate memory, allow for NULL to term string */
892: tmpString = isc_mem_allocate(named_g_mctx, len + 1);
893: /* copy this field to tmpString */
894: strcpy(tmpString, PQgetvalue(rs, i, 3));
1.1.1.3 ! christos 895: /* concatenate the rest, with spaces between */
! 896: for (j = 4; j < fields; j++) {
1.1 christos 897: strcat(tmpString, " ");
898: strcat(tmpString, PQgetvalue(rs, i, j));
899: }
900: /* tell Bind about it. */
1.1.1.3 ! christos 901: result = dns_sdlz_putnamedrr(
! 902: allnodes, PQgetvalue(rs, i, 2),
! 903: PQgetvalue(rs, i, 1), ttl, tmpString);
1.1 christos 904: isc_mem_free(named_g_mctx, tmpString);
905: }
906: /* if we weren't successful, log err msg */
907: if (result != ISC_R_SUCCESS) {
908: PQclear(rs);
909: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
910: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
911: "dns_sdlz_putnamedrr returned error. "
912: "Error code was: %s",
913: isc_result_totext(result));
914: return (ISC_R_FAILURE);
915: }
916: }
917:
918: /* free result set memory */
919: PQclear(rs);
920:
921: /* if we did return results, we are successful */
1.1.1.3 ! christos 922: if (rows > 0) {
1.1 christos 923: return (ISC_R_SUCCESS);
1.1.1.3 ! christos 924: }
1.1 christos 925:
926: /* empty result set, no data found */
927: return (ISC_R_NOTFOUND);
928: }
929:
930: /*%
931: * if the lookup function does not return SOA or NS records for the zone,
932: * use this function to get that information for Bind.
933: */
934:
935: static isc_result_t
936: postgres_authority(const char *zone, void *driverarg, void *dbdata,
1.1.1.3 ! christos 937: dns_sdlzlookup_t *lookup) {
1.1 christos 938: isc_result_t result;
939: PGresult *rs = NULL;
940:
941: UNUSED(driverarg);
942:
943: /* run the query and get the result set from the database. */
1.1.1.3 ! christos 944: result = postgres_get_resultset(zone, NULL, NULL, AUTHORITY, dbdata,
! 945: &rs);
1.1 christos 946: /* if we get "not implemented", send it along */
1.1.1.3 ! christos 947: if (result == ISC_R_NOTIMPLEMENTED) {
! 948: return (result);
! 949: }
1.1 christos 950: /* if we didn't get a result set, log an err msg. */
951: if (result != ISC_R_SUCCESS) {
1.1.1.3 ! christos 952: if (rs != NULL) {
1.1 christos 953: PQclear(rs);
1.1.1.3 ! christos 954: }
1.1 christos 955: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
956: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
957: "Postgres driver unable to return "
958: "result set for authority query");
959: return (ISC_R_FAILURE);
960: }
961: /*
962: * lookup and authority result sets are processed in the same
963: * manner postgres_process_rs does the job for both
964: * functions.
965: */
1.1.1.3 ! christos 966: return (postgres_process_rs(lookup, rs));
1.1 christos 967: }
968:
969: /*% if zone is supported, lookup up a (or multiple) record(s) in it */
970: static isc_result_t
971: postgres_lookup(const char *zone, const char *name, void *driverarg,
972: void *dbdata, dns_sdlzlookup_t *lookup,
1.1.1.3 ! christos 973: dns_clientinfomethods_t *methods,
! 974: dns_clientinfo_t *clientinfo) {
1.1 christos 975: isc_result_t result;
976: PGresult *rs = NULL;
977:
978: UNUSED(driverarg);
979: UNUSED(methods);
980: UNUSED(clientinfo);
981:
982: /* run the query and get the result set from the database. */
983: result = postgres_get_resultset(zone, name, NULL, LOOKUP, dbdata, &rs);
984: /* if we didn't get a result set, log an err msg. */
985: if (result != ISC_R_SUCCESS) {
1.1.1.3 ! christos 986: if (rs != NULL) {
1.1 christos 987: PQclear(rs);
1.1.1.3 ! christos 988: }
1.1 christos 989: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
990: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
991: "Postgres driver unable to "
992: "return result set for lookup query");
993: return (ISC_R_FAILURE);
994: }
995: /*
996: * lookup and authority result sets are processed in the same
997: * manner postgres_process_rs does the job for both functions.
998: */
1.1.1.3 ! christos 999: return (postgres_process_rs(lookup, rs));
1.1 christos 1000: }
1001:
1002: /*%
1003: * create an instance of the driver. Remember, only 1 copy of the driver's
1004: * code is ever loaded, the driver has to remember which context it's
1005: * operating in. This is done via use of the dbdata argument which is
1006: * passed into all query functions.
1007: */
1008: static isc_result_t
1009: postgres_create(const char *dlzname, unsigned int argc, char *argv[],
1.1.1.3 ! christos 1010: void *driverarg, void **dbdata) {
1.1 christos 1011: isc_result_t result;
1012: dbinstance_t *dbi = NULL;
1013: unsigned int j;
1014:
1015: /* if multi-threaded, we need a few extra variables. */
1016: int dbcount;
1017: db_list_t *dblist = NULL;
1018: int i;
1019: char *endp;
1020:
1021: UNUSED(driverarg);
1022: UNUSED(dlzname);
1023:
1.1.1.3 ! christos 1024: /* seed random # generator */
! 1025: srand((unsigned)time(NULL));
1.1 christos 1026:
1027: /* if debugging, let user know we are multithreaded. */
1.1.1.3 ! christos 1028: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
! 1029: ISC_LOG_DEBUG(1),
1.1 christos 1030: "Postgres driver running multithreaded");
1031:
1032: /* verify we have at least 5 arg's passed to the driver */
1033: if (argc < 5) {
1034: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1035: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1036: "Postgres driver requires at least "
1037: "4 command line args.");
1038: return (ISC_R_FAILURE);
1039: }
1040:
1041: /* no more than 8 arg's should be passed to the driver */
1042: if (argc > 8) {
1043: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1044: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1045: "Postgres driver cannot accept more than "
1046: "7 command line args.");
1047: return (ISC_R_FAILURE);
1048: }
1049:
1050: /* multithreaded build can have multiple DB connections */
1051:
1052: /* check how many db connections we should create */
1053: dbcount = strtol(argv[1], &endp, 10);
1054: if (*endp != '\0' || dbcount < 0) {
1055: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1056: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1057: "Postgres driver database connection count "
1058: "must be positive.");
1059: return (ISC_R_FAILURE);
1060: }
1061:
1062: /* allocate memory for database connection list */
1063: dblist = isc_mem_get(named_g_mctx, sizeof(db_list_t));
1064:
1065: /* initialize DB connection list */
1066: ISC_LIST_INIT(*dblist);
1067:
1068: /*
1069: * create the appropriate number of database instances (DBI)
1070: * append each new DBI to the end of the list
1071: */
1.1.1.3 ! christos 1072: for (i = 0; i < dbcount; i++) {
1.1 christos 1073: /* how many queries were passed in from config file? */
1.1.1.3 ! christos 1074: switch (argc) {
1.1 christos 1075: case 5:
1076: result = build_sqldbinstance(named_g_mctx, NULL, NULL,
1077: NULL, argv[3], argv[4],
1078: NULL, &dbi);
1079: break;
1080: case 6:
1081: result = build_sqldbinstance(named_g_mctx, NULL, NULL,
1082: argv[5], argv[3], argv[4],
1083: NULL, &dbi);
1084: break;
1085: case 7:
1.1.1.3 ! christos 1086: result = build_sqldbinstance(named_g_mctx, argv[6],
! 1087: NULL, argv[5], argv[3],
! 1088: argv[4], NULL, &dbi);
1.1 christos 1089: break;
1090: case 8:
1091: result = build_sqldbinstance(named_g_mctx, argv[6],
1092: argv[7], argv[5], argv[3],
1093: argv[4], NULL, &dbi);
1094: break;
1095: default:
1096: /* not really needed, should shut up compiler. */
1097: result = ISC_R_FAILURE;
1098: }
1099:
1100: if (result == ISC_R_SUCCESS) {
1101: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1102: DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
1103: "Postgres driver created database "
1104: "instance object.");
1105: } else { /* unsuccessful?, log err msg and cleanup. */
1106: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1107: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1108: "Postgres driver could not create "
1109: "database instance object.");
1110: goto cleanup;
1111: }
1112:
1113: /* when multithreaded, build a list of DBI's */
1114: ISC_LINK_INIT(dbi, link);
1115: ISC_LIST_APPEND(*dblist, dbi, link);
1116:
1117: /* create and set db connection */
1118: dbi->dbconn = PQconnectdb(argv[2]);
1119: /*
1120: * if db connection cannot be created, log err msg and
1121: * cleanup.
1122: */
1123: if (dbi->dbconn == NULL) {
1124: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1125: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1126: "Postgres driver could not allocate "
1127: "memory for database connection");
1128: goto cleanup;
1129: }
1130:
1131: /* if we cannot connect the first time, try 3 more times. */
1132: for (j = 0;
1.1.1.3 ! christos 1133: PQstatus((PGconn *)dbi->dbconn) != CONNECTION_OK && j < 3;
1.1 christos 1134: j++)
1.1.1.3 ! christos 1135: PQreset((PGconn *)dbi->dbconn);
1.1 christos 1136:
1137: /*
1138: * if multi threaded, let user know which connection
1139: * failed. user could be attempting to create 10 db
1140: * connections and for some reason the db backend only
1141: * allows 9
1142: */
1.1.1.3 ! christos 1143: if (PQstatus((PGconn *)dbi->dbconn) != CONNECTION_OK) {
1.1 christos 1144: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1145: DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
1146: "Postgres driver failed to create "
1147: "database connection number %u "
1148: "after 4 attempts",
1149: i + 1);
1150: goto cleanup;
1151: }
1152:
1153: /* set DBI = null for next loop through. */
1154: dbi = NULL;
1.1.1.3 ! christos 1155: } /* end for loop */
1.1 christos 1156:
1.1.1.3 ! christos 1157: /* set dbdata to the list we created. */
1.1 christos 1158: *dbdata = dblist;
1159:
1160: /* hey, we got through all of that ok, return success. */
1.1.1.3 ! christos 1161: return (ISC_R_SUCCESS);
1.1 christos 1162:
1.1.1.3 ! christos 1163: cleanup:
1.1 christos 1164:
1165: /*
1166: * if multithreaded, we could fail because only 1 connection
1167: * couldn't be made. We should cleanup the other successful
1168: * connections properly.
1169: */
1170: postgres_destroy_dblist(dblist);
1171:
1.1.1.3 ! christos 1172: return (ISC_R_FAILURE);
1.1 christos 1173: }
1174:
1175: /*%
1176: * destroy an instance of the driver. Remember, only 1 copy of the driver's
1177: * code is ever loaded, the driver has to remember which context it's
1178: * operating in. This is done via use of the dbdata argument.
1179: * so we really only need to clean it up since we are not using driverarg.
1180: */
1181: static void
1.1.1.3 ! christos 1182: postgres_destroy(void *driverarg, void *dbdata) {
1.1 christos 1183: UNUSED(driverarg);
1184: /* cleanup the list of DBI's */
1.1.1.3 ! christos 1185: postgres_destroy_dblist((db_list_t *)dbdata);
1.1 christos 1186: }
1187:
1188: /* pointers to all our runtime methods. */
1189: /* this is used during driver registration */
1190: /* i.e. in dlz_postgres_init below. */
1191: static dns_sdlzmethods_t dlz_postgres_methods = {
1192: postgres_create,
1193: postgres_destroy,
1194: postgres_findzone,
1195: postgres_lookup,
1196: postgres_authority,
1197: postgres_allnodes,
1198: postgres_allowzonexfr,
1199: NULL,
1200: NULL,
1201: NULL,
1202: NULL,
1203: NULL,
1204: NULL,
1205: NULL,
1206: };
1207:
1208: /*%
1209: * Wrapper around dns_sdlzregister().
1210: */
1211: isc_result_t
1212: dlz_postgres_init(void) {
1213: isc_result_t result;
1214:
1215: /*
1216: * Write debugging message to log
1217: */
1.1.1.3 ! christos 1218: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
! 1219: ISC_LOG_DEBUG(2), "Registering DLZ postgres driver.");
1.1 christos 1220:
1221: /*
1222: * Driver is always threadsafe. When multithreaded all
1223: * functions use multithreaded code. When not multithreaded,
1224: * all functions can only be entered once, but only 1 thread
1225: * of operation is available in Bind. So everything is still
1226: * threadsafe.
1227: */
1228: result = dns_sdlzregister("postgres", &dlz_postgres_methods, NULL,
1229: DNS_SDLZFLAG_RELATIVEOWNER |
1.1.1.3 ! christos 1230: DNS_SDLZFLAG_RELATIVERDATA |
! 1231: DNS_SDLZFLAG_THREADSAFE,
1.1 christos 1232: named_g_mctx, &dlz_postgres);
1233: /* if we can't register the driver, there are big problems. */
1234: if (result != ISC_R_SUCCESS) {
1235: UNEXPECTED_ERROR(__FILE__, __LINE__,
1236: "dns_sdlzregister() failed: %s",
1237: isc_result_totext(result));
1238: result = ISC_R_UNEXPECTED;
1239: }
1240:
1.1.1.3 ! christos 1241: return (result);
1.1 christos 1242: }
1243:
1244: /*%
1245: * Wrapper around dns_sdlzunregister().
1246: */
1247: void
1248: dlz_postgres_clear(void) {
1249: /*
1250: * Write debugging message to log
1251: */
1.1.1.3 ! christos 1252: isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
! 1253: ISC_LOG_DEBUG(2), "Unregistering DLZ postgres driver.");
1.1 christos 1254:
1255: /* unregister the driver. */
1.1.1.3 ! christos 1256: if (dlz_postgres != NULL) {
1.1 christos 1257: dns_sdlzunregister(&dlz_postgres);
1.1.1.3 ! christos 1258: }
1.1 christos 1259: }
1260:
1.1.1.3 ! christos 1261: #endif /* ifdef DLZ_POSTGRES */
CVSweb <webmaster@jp.NetBSD.org>