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