No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / contrib / sdb / tcl / tcldb.c
blobc0cda60b417099ad3e26db33fc405d5272336709
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004, 2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: tcldb.c,v 1.10 2007/06/19 23:47:10 tbox Exp */
23 * A simple database driver that calls a Tcl procedure to define
24 * the contents of the DNS namespace. The procedure is loaded
25 * from the file lookup.tcl; look at the comments there for
26 * more information.
29 #include <config.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/stat.h>
36 #include <isc/mem.h>
37 #include <isc/print.h>
38 #include <isc/result.h>
39 #include <isc/util.h>
41 #include <dns/log.h>
42 #include <dns/sdb.h>
44 #include <named/globals.h>
46 #include <tcl.h>
48 #include <tcldb.h>
50 #define CHECK(op) \
51 do { result = (op); \
52 if (result != ISC_R_SUCCESS) return (result); \
53 } while (0)
55 typedef struct tcldb_driver {
56 isc_mem_t *mctx;
57 Tcl_Interp *interp;
58 } tcldb_driver_t;
60 static tcldb_driver_t *the_driver = NULL;
62 static dns_sdbimplementation_t *tcldb = NULL;
64 static isc_result_t
65 tcldb_driver_create(isc_mem_t *mctx, tcldb_driver_t **driverp) {
66 int tclres;
67 isc_result_t result = ISC_R_SUCCESS;
68 tcldb_driver_t *driver = isc_mem_get(mctx, sizeof(tcldb_driver_t));
69 if (driver == NULL)
70 return (ISC_R_NOMEMORY);
71 driver->mctx = mctx;
72 driver->interp = Tcl_CreateInterp();
74 tclres = Tcl_EvalFile(driver->interp, (char *) "lookup.tcl");
75 if (tclres != TCL_OK) {
76 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
77 DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
78 "initializing tcldb: "
79 "loading 'lookup.tcl' failed: %s",
80 driver->interp->result);
81 result = ISC_R_FAILURE;
82 goto cleanup;
84 *driverp = driver;
85 return (ISC_R_SUCCESS);
87 cleanup:
88 isc_mem_put(mctx, driver, sizeof(tcldb_driver_t));
89 return (result);
93 static void
94 tcldb_driver_destroy(tcldb_driver_t **driverp) {
95 tcldb_driver_t *driver = *driverp;
96 Tcl_DeleteInterp(driver->interp);
97 isc_mem_put(driver->mctx, driver, sizeof(tcldb_driver_t));
101 * Perform a lookup, by invoking the Tcl procedure "lookup".
103 static isc_result_t
104 tcldb_lookup(const char *zone, const char *name, void *dbdata,
105 dns_sdblookup_t *lookup)
107 isc_result_t result = ISC_R_SUCCESS;
108 int tclres;
109 int rrc; /* RR count */
110 char **rrv; /* RR vector */
111 int i;
112 char *cmdv[3];
113 char *cmd;
115 tcldb_driver_t *driver = (tcldb_driver_t *) dbdata;
117 cmdv[0] = "lookup";
118 cmdv[1] = zone;
119 cmdv[2] = name;
120 cmd = Tcl_Merge(3, cmdv);
121 tclres = Tcl_Eval(driver->interp, cmd);
122 Tcl_Free(cmd);
124 if (tclres != TCL_OK) {
125 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
126 DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
127 "zone '%s': tcl lookup function failed: %s",
128 zone, driver->interp->result);
129 return (ISC_R_FAILURE);
132 if (strcmp(driver->interp->result, "NXDOMAIN") == 0) {
133 result = ISC_R_NOTFOUND;
134 goto fail;
137 tclres = Tcl_SplitList(driver->interp, driver->interp->result,
138 &rrc, &rrv);
139 if (tclres != TCL_OK)
140 goto malformed;
142 for (i = 0; i < rrc; i++) {
143 isc_result_t tmpres;
144 int fieldc; /* Field count */
145 char **fieldv; /* Field vector */
146 tclres = Tcl_SplitList(driver->interp, rrv[i],
147 &fieldc, &fieldv);
148 if (tclres != TCL_OK) {
149 tmpres = ISC_R_FAILURE;
150 goto failrr;
152 if (fieldc != 3)
153 goto malformed;
154 tmpres = dns_sdb_putrr(lookup, fieldv[0], atoi(fieldv[1]),
155 fieldv[2]);
156 Tcl_Free((char *) fieldv);
157 failrr:
158 if (tmpres != ISC_R_SUCCESS)
159 result = tmpres;
161 Tcl_Free((char *) rrv);
162 if (result == ISC_R_SUCCESS)
163 return (result);
165 malformed:
166 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
167 DNS_LOGMODULE_SDB, ISC_LOG_ERROR,
168 "zone '%s': "
169 "malformed return value from tcl lookup function: %s",
170 zone, driver->interp->result);
171 result = ISC_R_FAILURE;
172 fail:
173 return (result);
177 * Set up per-zone state. In our case, the database arguments of the
178 * zone are collected into a Tcl list and assigned to an element of
179 * the global array "dbargs".
181 static isc_result_t
182 tcldb_create(const char *zone, int argc, char **argv,
183 void *driverdata, void **dbdata)
185 tcldb_driver_t *driver = (tcldb_driver_t *) driverdata;
187 char *list = Tcl_Merge(argc, argv);
189 Tcl_SetVar2(driver->interp, (char *) "dbargs", (char *) zone, list, 0);
191 Tcl_Free(list);
193 *dbdata = driverdata;
195 return (ISC_R_SUCCESS);
199 * This driver does not support zone transfer, so allnodes() is NULL.
201 static dns_sdbmethods_t tcldb_methods = {
202 tcldb_lookup,
203 NULL, /* authority */
204 NULL, /* allnodes */
205 tcldb_create,
206 NULL /* destroy */
210 * Initialize the tcldb driver.
212 isc_result_t
213 tcldb_init(void) {
214 isc_result_t result;
215 int flags = DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA;
217 result = tcldb_driver_create(ns_g_mctx, &the_driver);
218 if (result != ISC_R_SUCCESS)
219 return (result);
221 return (dns_sdb_register("tcl", &tcldb_methods, the_driver, flags,
222 ns_g_mctx, &tcldb));
226 * Wrapper around dns_sdb_unregister().
228 void
229 tcldb_clear(void) {
230 if (tcldb != NULL)
231 dns_sdb_unregister(&tcldb);
232 if (the_driver != NULL)
233 tcldb_driver_destroy(&the_driver);