Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / contrib / dlz / bin / dlzbdb / dlzbdb.c
blobc2ce8c09bfff07ecbe5b449fc9274d4d7a23a63e
1 /* $NetBSD: dlzbdb.c,v 1.3 2014/12/10 04:37:55 christos Exp $ */
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.
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
26 * copies.
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.
41 * Permission to use, copy, modify, and distribute this software for any
42 * purpose with or without fee is hereby granted, provided that the above
43 * copyright notice and this permission notice appear in all copies.
45 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
46 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
48 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
49 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
50 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
51 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
52 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
55 #ifdef DLZ_BDB
58 * exit codes
59 * 0 everything ok
60 * 1 error parsing command line
61 * 2 Missing, too many or invalid combination of command line parameters
62 * 3 Unable to open BDB database.
63 * 4 Unable to allocate memory for, or create lexer.
64 * 5 unable to perform BDB cursor operation
67 #include <config.h>
68 #include <stdio.h>
69 #include <string.h>
70 #include <stdlib.h>
72 #include <isc/buffer.h>
73 #include <isc/commandline.h>
74 #include <isc/formatcheck.h>
75 #include <isc/lex.h>
76 #include <isc/mem.h>
77 #include <isc/result.h>
78 #include <isc/string.h>
79 #include <isc/util.h>
81 #include <db.h>
83 /* shut up compiler warnings about no previous prototype */
85 static void
86 show_usage(void);
88 int
89 getzone(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
91 int
92 gethost(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
94 void
95 bdb_cleanup(void);
97 isc_result_t
98 bdb_opendb(DBTYPE db_type, DB **db_out, const char *db_name, int flags);
100 void
101 put_data(isc_boolean_t dns_data, char *input_key, char *input_data);
103 void
104 insert_data(void);
106 isc_result_t
107 openBDB(void);
109 isc_result_t
110 open_lexer(void);
112 void
113 close_lexer(void);
115 isc_result_t
116 bulk_write(char type, DB *database, DBC *dbcursor, DBT *bdbkey, DBT *bdbdata);
118 void
119 operation_add(void);
121 void
122 operation_bulk(void);
124 void
125 operation_listOrDelete(isc_boolean_t dlt);
129 * Maximum length of a single data line that
130 * may be inserted into database by this program.
131 * If you need to insert a line of data that is more
132 * than 10,000 characters change this definition.
135 #define max_data_len 10000
138 * BDB database names. If you want to use different
139 * database names change them here.
142 #define dlz_data "dns_data"
143 #define dlz_zone "dns_zone"
144 #define dlz_host "dns_host"
145 #define dlz_client "dns_client"
149 * Error code returned by BDB secondary index callback functions.
150 * This error is returned if the callback function could not create
151 * the secondary index for any reason.
154 #define BDBparseErr 1
156 /* A struct to hold all the relevant info about the database */
158 typedef struct bdb_instance {
159 DB_ENV *dbenv; /* BDB environment */
160 DB *data; /* dns_data database handle */
161 DBC *cursor; /* database cursor */
162 DBC *cursor2; /* second cursor used during list operation. */
163 DBC *cursor3; /* third cursor used during list operation */
164 DBC *cursor4; /* fourth cursor used during list operation */
165 DB *zone; /* zone database handle */
166 DB *host; /* host database handle */
167 DB *client; /* client database handle */
168 } bdb_instance_t;
170 /* Possible operations */
172 #define list 1 /* list data */
173 #define dele 2 /* delete data */
174 #define add 3 /* add a single piece of data */
175 #define bulk 4 /* bulk load data */
179 * quit macro is used instead of exit. quit always trys to close the lexer
180 * and the BDB database before exiting.
183 #define quit(i) close_lexer(); bdb_cleanup(); exit(i);
186 * checkOp is used to verify that only one operation (list, del, add,
187 * bulk from file, bulk from stdin) is specified on the command line.
188 * This prevents a user from specifying two operations on the command
189 * line, which would make no sense anyway.
192 #define checkOp(x) if (x != 0) {fprintf(stderr, "\nonly one operation "\
193 "(l e d a f s) may be specified\n"); quit(2);}
196 * checkParam is used to only allow a parameter to be specified once.
197 * I.E. the parameter key can only be used on the command line once.
198 * any attempt to use it twice causes an error.
201 #define checkParam(x, y) if (x != NULL) {fprintf(stderr, "\n%s may only "\
202 "be specified once\n", y); quit(2);}
205 * checkInvalidParam is used to only allow paramters which make sense for
206 * the operation selected. I.E. passing the key parameter makes no sense
207 * for the add operation, and thus it isn't allowed.
210 #define checkInvalidParam(x, y, z) if (x != NULL) {fprintf(stderr, "\n%s "\
211 "may not be specified %s\n", y, z); quit(2);}
214 * checkInvalidOption is used to only allow paramters which make sense for
215 * the operation selected - but checks boolean options.
216 * I.E. passing the "b" bare_list parameter makes no sense for the add
217 * operation, and thus it isn't allowed.
218 * if w == x then output error message "flag", "message"
221 #define checkInvalidOption(w, x, y, z) if (w == x) {fprintf(stderr, "\n%s "\
222 "may not be specified %s\n", y, z); quit(2);}
224 /* Global Variables */
226 int operation = 0; /*%< operation to perform. */
227 /*% allow new lock files or DB to be created. */
228 isc_boolean_t create_allowed = isc_boolean_false;
229 char *key = NULL; /*%< key to use in list & del operations */
231 /*% dump DB in DLZBDB bulk format */
232 isc_boolean_t list_everything = isc_boolean_false;
233 unsigned int key_val; /*%< key as unsigned int used in list & del operations */
234 char *zone = NULL; /*%< zone to use in list operations */
235 char *host = NULL; /*%< host to use in list operations */
236 char *c_zone = NULL; /*%< client zone to use in list operations */
237 char *c_ip = NULL; /*%< client IP to use in list operations */
238 char *a_data = NULL; /*%< data in add operation */
239 char *bulk_file = NULL; /*%< bulk data file to load */
240 char *db_envdir = NULL; /*%< BDB environment location */
241 char *db_file = NULL; /*%< BDB database file location. */
242 bdb_instance_t db; /* BDB instance we are operating on */
243 isc_lex_t *lexer = NULL; /*%< lexer for use to use in parsing input */
244 isc_mem_t *lex_mctx = NULL; /*%< memory context for lexer */
245 char lex_data_buf[max_data_len]; /*%< data array to use for lex_buffer below */
246 isc_buffer_t lex_buffer; /*%< buffer for lexer during add operation */
250 * Displays usage message
253 static void
254 show_usage(void) {
255 fprintf(stderr, "\n\n\
256 ---Usage:---------------------------------------------------------------------\
257 \n\n\
258 List data:\n\
259 dlzbdb -l [-k key] [-z zone] [-h host] [-c client_zone] [-i client_ip]\n\
260 BDB_environment BDB_database\n\n\
261 Delete data:\n\
262 dlzbdb -d [-k key] [-c client_zone] [-i client_ip]\n\
263 BDB_environment BDB_database\n\n\
264 Bulk load data from file:\n\
265 dlzbdb -f file_to_load BDB_environment BDB_database\n\n\
266 Bulk load data from stdin\n\
267 dlzbdb -s BDB_environment BDB_database\n\n\
268 Add data:\n\
269 dlzbdb -a \"dns data to be added\" BDB_environment BDB_database\n\n\
270 Export data:\n\
271 dlzbdb -e BDB_environment BDB_database\n\n\
272 Normally operations can only be performed on an existing database files.\n\
273 Use the -n flag with any operation to allow files to be created.\n\
274 Existing files will NOT be truncated by using the -n flag.\n\
275 The -n flag will allow a new database to be created, or allow new\n\
276 environment files to be created for an existing database.\n\n\
277 ---Format for -f & -a options:------------------------------------------------\
278 \n\n\
279 db_type zone host dns_type ttl ip\n\
280 db_type zone host dns_type ttl mx_priority mail_host\n\
281 db_type zone host dns_type ttl nm_svr resp_psn serial refresh retry expire min\
283 db_type zone client_ip\n\n\
284 ---Examples:------------------------------------------------------------------\
285 \n\n\
286 d mynm.com www A 10 127.0.0.1\n\
287 d mynm.com @ MX 10 5 mail\n\
288 d mynm.com @ SOA 10 ns1.mynm.com. root.mynm.com. 2 28800 7200 604800 86400\n\
289 c mynm.com 127.0.0.1\n\
290 c mynm.com 192.168.0.10\n\
292 quit(1);
296 /*% BDB callback to create zone secondary index */
299 getzone(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey) {
300 char *tmp;
301 char *left;
302 char *right;
303 int result=0;
305 UNUSED(dbp);
306 UNUSED(pkey);
308 /* Allocate memory to use in parsing the string */
309 tmp = right = malloc(pdata->size + 1);
311 /* verify memory was allocated */
312 if (right == NULL) {
313 result = BDBparseErr;
314 goto getzone_cleanup;
317 /* copy data string into newly allocated memory */
318 strncpy(right, pdata->data, pdata->size);
319 right[pdata->size] = '\0';
321 /* split string at the first space */
322 left = isc_string_separate(&right, " ");
324 /* copy string for "zone" secondary index */
325 skey->data = strdup(left);
326 if (skey->data == NULL) {
327 result = BDBparseErr;
328 goto getzone_cleanup;
330 /* set required values for BDB */
331 skey->size = strlen(skey->data);
332 skey->flags = DB_DBT_APPMALLOC;
334 getzone_cleanup:
336 /* cleanup memory */
337 if (tmp != NULL)
338 free(tmp);
340 return result;
344 * BDB callback to create host secondary index
348 gethost(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey) {
349 char *tmp;
350 char *left;
351 char *right;
352 int result=0;
354 UNUSED(dbp);
355 UNUSED(pkey);
357 /* allocate memory to use in parsing the string */
358 tmp = right = malloc(pdata->size + 1);
360 /* verify memory was allocated */
361 if (tmp == NULL) {
362 result = BDBparseErr;
363 goto gethost_cleanup;
366 /* copy data string into newly allocated memory */
367 strncpy(right, pdata->data, pdata->size);
368 right[pdata->size] = '\0';
370 /* we don't care about left string. */
371 /* memory of left string will be freed when tmp is freed. */
372 isc_string_separate(&right, " ");
374 /* verify right still has some characters left */
375 if (right == NULL) {
376 result = BDBparseErr;
377 goto gethost_cleanup;
380 /* get "host" from data string */
381 left = isc_string_separate(&right, " ");
382 /* copy string for "host" secondary index */
383 skey->data = strdup(left);
384 if (skey->data == NULL) {
385 result = BDBparseErr;
386 goto gethost_cleanup;
388 /* set required values for BDB */
389 skey->size = strlen(skey->data);
390 skey->flags = DB_DBT_APPMALLOC;
392 gethost_cleanup:
394 /* cleanup memory */
395 if (tmp != NULL)
396 free(tmp);
398 return result;
402 * Performs BDB cleanup. Close each database that we opened.
403 * Close environment. Set each var to NULL so we know they
404 * were closed and don't accidentally try to close them twice.
407 void
408 bdb_cleanup(void) {
410 /* close cursors */
411 if (db.cursor4 != NULL) {
412 db.cursor4->c_close(db.cursor4);
413 db.cursor4 = NULL;
416 if (db.cursor3 != NULL) {
417 db.cursor3->c_close(db.cursor3);
418 db.cursor3 = NULL;
421 if (db.cursor2 != NULL) {
422 db.cursor2->c_close(db.cursor2);
423 db.cursor2 = NULL;
426 if (db.cursor != NULL) {
427 db.cursor->c_close(db.cursor);
428 db.cursor = NULL;
431 /* close databases */
432 if (db.data != NULL) {
433 db.data->close(db.data, 0);
434 db.data = NULL;
436 if (db.host != NULL) {
437 db.host->close(db.host, 0);
438 db.host = NULL;
440 if (db.zone != NULL) {
441 db.zone->close(db.zone, 0);
442 db.zone = NULL;
444 if (db.client != NULL) {
445 db.client->close(db.client, 0);
446 db.client = NULL;
449 /* close environment */
450 if (db.dbenv != NULL) {
451 db.dbenv->close(db.dbenv, 0);
452 db.dbenv = NULL;
456 /*% Initializes, sets flags and then opens Berkeley databases. */
458 isc_result_t
459 bdb_opendb(DBTYPE db_type, DB **db_out, const char *db_name, int flags) {
461 int result;
462 int createFlag = 0;
464 /* Initialize the database. */
465 if ((result = db_create(db_out, db.dbenv, 0)) != 0) {
466 fprintf(stderr, "BDB could not initialize %s database. BDB error: %s",
467 db_name, db_strerror(result));
468 return ISC_R_FAILURE;
471 /* set database flags. */
472 if ((result = (*db_out)->set_flags(*db_out, flags)) != 0) {
473 fprintf(stderr, "BDB could not set flags for %s database. BDB error: %s",
474 db_name, db_strerror(result));
475 return ISC_R_FAILURE;
478 if (create_allowed == isc_boolean_true) {
479 createFlag = DB_CREATE;
481 /* open the database. */
482 if ((result = (*db_out)->open(*db_out, NULL, db_file, db_name, db_type,
483 createFlag, 0)) != 0) {
484 fprintf(stderr, "BDB could not open %s database in %s. BDB error: %s",
485 db_name, db_file, db_strerror(result));
486 return ISC_R_FAILURE;
489 return ISC_R_SUCCESS;
493 * parses input and adds it to the BDB database
494 * Lexer should be instantiated, and either a file or buffer opened for it.
495 * The insert_data function is used by both the add, and bulk insert
496 * operations
499 void
500 put_data(isc_boolean_t dns_data, char *input_key, char *input_data) {
502 int bdbres;
503 DBT key, data;
505 /* make sure key & data are completely empty */
506 memset(&key, 0, sizeof(key));
507 memset(&data, 0, sizeof(data));
509 /* if client data, setup key for insertion */
510 if (!dns_data && input_key != NULL) {
511 key.data = input_key;
512 key.size = strlen(input_key);
513 key.flags = 0;
515 /* always setup data for insertion */
516 data.data = input_data;
517 data.size = strlen(input_data);
518 data.flags = 0;
520 /* execute insert against appropriate database. */
521 if (dns_data) {
522 bdbres = db.data->put(db.data, NULL, &key, &data, DB_APPEND);
523 } else {
524 bdbres = db.client->put(db.client, NULL, &key, &data, 0);
527 /* if something went wrong, log error and quit */
528 if (bdbres != 0) {
529 fprintf(stderr, "BDB could not insert data. Error: %s",
530 db_strerror(bdbres));
531 quit(5);
535 void
536 insert_data(void) {
537 unsigned int opt =
538 ISC_LEXOPT_EOL | /* Want end-of-line token. */
539 ISC_LEXOPT_EOF | /* Want end-of-file token. */
540 ISC_LEXOPT_QSTRING | /* Recognize qstrings. */
541 ISC_LEXOPT_QSTRINGMULTILINE; /* Allow multiline "" strings */
543 isc_result_t result;
544 isc_token_t token; /* token from lexer */
545 isc_boolean_t loop = isc_boolean_true;
546 isc_boolean_t have_czone = isc_boolean_false;
547 char data_arr[max_data_len];
548 isc_buffer_t buf;
549 char data_arr2[max_data_len];
550 isc_buffer_t buf2;
551 char data_type = 'u'; /* u =unknown, b =bad token, d/D =DNS, c/C =client IP */
553 /* Initialize buffers */
554 isc_buffer_init(&buf, &data_arr, max_data_len);
555 isc_buffer_init(&buf2, &data_arr2, max_data_len);
557 while (loop) {
558 result = isc_lex_gettoken(lexer, opt, &token);
559 if (result != ISC_R_SUCCESS)
560 goto data_cleanup;
562 switch(token.type) {
563 case isc_tokentype_string:
564 if (data_type == 'u') {
565 /* store data_type */
566 strncpy(&data_type, token.value.as_pointer, 1);
567 /* verify data_type was specified correctly on input */
568 if (strlen(token.value.as_pointer) > 1 || (
569 data_type != 'd' && data_type != 'D' &&
570 data_type != 'c' && data_type != 'C') ) {
571 /* if not, set to 'b' so this line is ignored. */
572 data_type = 'b';
574 } else if (data_type == 'c' || data_type == 'C') {
575 if (have_czone == isc_boolean_true) {
576 isc_buffer_putstr(&buf2, token.value.as_pointer);
577 /* add string terminator to buffer */
578 isc_buffer_putmem(&buf2, "\0", 1);
579 } else {
580 isc_buffer_putstr(&buf, token.value.as_pointer);
581 /* add string terminator to buffer */
582 isc_buffer_putmem(&buf, "\0", 1);
583 have_czone = isc_boolean_true;
585 } else {
586 isc_buffer_putstr(&buf, token.value.as_pointer);
587 isc_buffer_putstr(&buf, " ");
589 break;
590 case isc_tokentype_qstring:
591 isc_buffer_putstr(&buf, "\"");
592 isc_buffer_putstr(&buf, token.value.as_pointer);
593 isc_buffer_putstr(&buf, "\" ");
594 break;
595 case isc_tokentype_eol:
596 case isc_tokentype_eof:
598 if ((data_type != 'u' && isc_buffer_usedlength(&buf) > 0) || data_type == 'b') {
599 /* perform insert operation */
600 if (data_type == 'd' || data_type == 'D') {
601 /* add string terminator to buffer */
602 isc_buffer_putmem(&buf, "\0", 1);
603 put_data(isc_boolean_true, NULL, (char *) &data_arr);
604 } else if (data_type == 'c' || data_type == 'C') {
605 put_data(isc_boolean_false, (char *) &data_arr,
606 (char *) &data_arr2);
607 } else if (data_type == 'b') {
608 fprintf(stderr, "Bad / unknown token encountered on line %lu."\
609 " Skipping line.", isc_lex_getsourceline(lexer) - 1);
610 } else {
611 fprintf(stderr, "Bad / unknown db data type encountered on " \
612 "line %lu. Skipping line\n", isc_lex_getsourceline(lexer) - 1);
616 if (token.type == isc_tokentype_eof) {
617 loop = isc_boolean_false;
620 /* reset buffer for next insert */
621 isc_buffer_clear(&buf);
622 isc_buffer_clear(&buf2);
623 have_czone = isc_boolean_false;
624 data_type ='u';
625 break;
626 default:
627 data_type = 'b';
628 break;
632 return;
634 data_cleanup:
635 /* let user know we had problems */
636 fprintf(stderr, "Unknown error processing tokens during \"add\" or " \
637 "\"bulk\" operation.\nStoped processing on line %lu.",
638 isc_lex_getsourceline(lexer));
642 isc_result_t
643 openBDB(void) {
645 int bdbres;
646 isc_result_t result;
648 /* create BDB environment */
649 /* Basically BDB allocates and assigns memory to db->dbenv */
650 bdbres = db_env_create(&db.dbenv, 0);
651 if (bdbres != 0) {
652 fprintf(stderr, "BDB environment could not be created. BDB error: %s",
653 db_strerror(bdbres));
654 result = ISC_R_FAILURE;
655 goto openBDB_cleanup;
658 /* open BDB environment */
659 if (create_allowed == isc_boolean_true) {
660 /* allowed to create new files */
661 bdbres = db.dbenv->open(db.dbenv, db_envdir,
662 DB_INIT_CDB | DB_INIT_MPOOL | DB_CREATE, 0);
663 } else { /* not allowed to create new files. */
664 bdbres = db.dbenv->open(db.dbenv, db_envdir,
665 DB_INIT_CDB | DB_INIT_MPOOL, 0);
667 if (bdbres != 0) {
668 fprintf(stderr, "BDB environment at '%s' could not be opened. BDB " \
669 "error: %s", db_envdir, db_strerror(bdbres));
670 result = ISC_R_FAILURE;
671 goto openBDB_cleanup;
674 /* open dlz_data database. */
676 result = bdb_opendb(DB_RECNO, &db.data, dlz_data, 0);
677 if (result != ISC_R_SUCCESS)
678 goto openBDB_cleanup;
680 /* open dlz_host database */
681 result = bdb_opendb(DB_BTREE, &db.host, dlz_host, DB_DUP | DB_DUPSORT);
682 if (result != ISC_R_SUCCESS)
683 goto openBDB_cleanup;
685 /* open dlz_zone database. */
686 result = bdb_opendb(DB_BTREE, &db.zone, dlz_zone, DB_DUP | DB_DUPSORT);
687 if (result != ISC_R_SUCCESS)
688 goto openBDB_cleanup;
690 /* open dlz_client database. */
691 result = bdb_opendb(DB_BTREE, &db.client, dlz_client, DB_DUP | DB_DUPSORT);
692 if (result != ISC_R_SUCCESS)
693 goto openBDB_cleanup;
695 /* associate the host secondary database with the primary database */
696 bdbres = db.data->associate(db.data, NULL, db.host, gethost, 0);
697 if (bdbres != 0) {
698 fprintf(stderr, "BDB could not associate %s database with %s. BDB "\
699 "error: %s", dlz_host, dlz_data, db_strerror(bdbres));
700 result = ISC_R_FAILURE;
701 goto openBDB_cleanup;
704 /* associate the zone secondary database with the primary database */
705 bdbres = db.data->associate(db.data, NULL, db.zone, getzone, 0);
706 if (bdbres != 0) {
707 fprintf(stderr, "BDB could not associate %s database with %s. BDB "\
708 "error: %s", dlz_zone, dlz_data, db_strerror(bdbres));
709 result = ISC_R_FAILURE;
710 goto openBDB_cleanup;
713 return result;
715 openBDB_cleanup:
717 bdb_cleanup();
718 return result;
721 /*% Create & open lexer to parse input data */
723 isc_result_t
724 open_lexer(void) {
725 isc_result_t result;
727 /* check if we already opened the lexer, if we did, return success */
728 if (lexer != NULL)
729 return ISC_R_SUCCESS;
731 /* allocate memory for lexer, and verify it was allocated */
732 result = isc_mem_create(0, 0, &lex_mctx);
733 if (result != ISC_R_SUCCESS) {
734 fprintf(stderr, "unexpected error creating lexer\n");
735 return result;
738 /* create lexer */
739 result = isc_lex_create(lex_mctx, 1500, &lexer);
740 if (result != ISC_R_SUCCESS)
741 fprintf(stderr, "unexpected error creating lexer\n");
743 /* set allowed commenting style */
744 isc_lex_setcomments(lexer, ISC_LEXCOMMENT_C | /* Allow C comments */
745 ISC_LEXCOMMENT_CPLUSPLUS | /* Allow C++ comments */
746 ISC_LEXCOMMENT_SHELL); /* Allow shellcomments */
748 isc_buffer_init(&lex_buffer, &lex_data_buf, max_data_len);
750 return result;
753 /*% Close the lexer, and cleanup memory */
755 void
756 close_lexer(void) {
758 /* If lexer is still open, close it & destroy it. */
759 if (lexer != NULL) {
760 isc_lex_close(lexer);
761 isc_lex_destroy(&lexer);
764 /* if lexer memory is still allocated, destroy it. */
765 if (lex_mctx != NULL)
766 isc_mem_destroy(&lex_mctx);
769 /*% Perform add operation */
771 void
772 operation_add(void) {
773 /* check for any parameters that are not allowed during add */
774 checkInvalidParam(key, "k", "for add operation");
775 checkInvalidParam(zone, "z", "for add operation");
776 checkInvalidParam(host, "h", "for add operation");
777 checkInvalidParam(c_zone, "c", "for add operation");
778 checkInvalidParam(c_ip, "i", "for add operation");
779 checkInvalidOption(list_everything, isc_boolean_true, "e",
780 "for add operation");
782 /* if open lexer fails it alread prints error messages. */
783 if (open_lexer() != ISC_R_SUCCESS) {
784 quit(4);
787 /* copy input data to buffer */
788 isc_buffer_putstr(&lex_buffer, a_data);
790 /* tell lexer to use buffer as input */
791 if (isc_lex_openbuffer(lexer, &lex_buffer) != ISC_R_SUCCESS) {
792 fprintf(stderr, "unexpected error opening lexer buffer");
793 quit(4);
796 /*common logic for "add" & "bulk" operations are handled by insert_data */
797 insert_data();
800 /*% Perform bulk insert operation */
802 void
803 operation_bulk(void) {
804 /* check for any parameters that are not allowed during bulk */
805 checkInvalidParam(key, "k", "for bulk load operation");
806 checkInvalidParam(zone, "z", "for bulk load operation");
807 checkInvalidParam(host, "h", "for bulk load operation");
808 checkInvalidParam(c_zone, "c", "for bulk load operation");
809 checkInvalidParam(c_ip, "i", "for bulk load operation");
810 checkInvalidOption(list_everything, isc_boolean_true, "e",
811 "for bulk load operation");
813 /* if open lexer fails it already prints error messages. */
814 if (open_lexer() != ISC_R_SUCCESS) {
815 quit(4);
818 if (bulk_file == NULL) {
819 if (isc_lex_openstream(lexer, stdin) != ISC_R_SUCCESS) {
820 fprintf(stderr, "unexpected error opening stdin by lexer.");
821 quit(4);
823 } else if (isc_lex_openfile(lexer, bulk_file) != ISC_R_SUCCESS) {
824 fprintf(stderr, "unexpected error opening %s by lexer.", bulk_file);
825 quit(4);
828 /* common logic for "add" & "bulk" operations are handled by insert_data */
829 insert_data();
832 isc_result_t
833 bulk_write(char type, DB *database, DBC *dbcursor, DBT *bdbkey, DBT *bdbdata) {
835 int bdbres;
836 db_recno_t recNum;
837 char *retkey = NULL, *retdata;
838 size_t retklen = 0, retdlen;
839 void *p;
841 /* use a 5MB buffer for the bulk dump */
842 int buffer_size = 5 * 1024 * 1024;
844 /* try to allocate a 5 MB buffer, if we fail write err msg, die. */
845 bdbdata->data = malloc(buffer_size);
846 if (bdbdata->data == NULL) {
847 fprintf(stderr,
848 "Unable to allocate 5 MB buffer for bulk database dump\n");
849 return ISC_R_FAILURE;
851 bdbdata->ulen = buffer_size;
852 bdbdata->flags = DB_DBT_USERMEM;
854 /* get a cursor, make sure it worked. */
855 bdbres = database->cursor(database, NULL, &dbcursor, 0);
856 if (bdbres != 0) {
857 fprintf(stderr, "Unexpected error. BDB Error: %s\n",db_strerror(bdbres));
858 free(bdbdata->data);
859 return ISC_R_FAILURE;
862 /* loop and dump all data */
863 for (;;) {
865 /* loop through data until DB_NOTFOUND is returned */
866 bdbres = dbcursor->c_get(dbcursor, bdbkey, bdbdata,
867 DB_MULTIPLE_KEY | DB_NEXT);
868 /* if not successful did we encounter DB_NOTFOUND, or */
869 /* have a different problem. */
870 if (bdbres != 0) {
871 if (bdbres != DB_NOTFOUND) {
872 fprintf(stderr, "Unexpected error. BDB Error: %s\n",
873 db_strerror(bdbres));
874 free(bdbdata->data);
875 return ISC_R_FAILURE;
877 /* Hit DB_NOTFOUND which means end of data. */
878 break;
879 } /* end of if (bdbres !=0) */
881 for (DB_MULTIPLE_INIT(p, bdbdata);;) {
882 if (type == 'c')
883 DB_MULTIPLE_KEY_NEXT(p, bdbdata, retkey, retklen, retdata, retdlen);
884 else
885 DB_MULTIPLE_RECNO_NEXT(p, bdbdata, recNum, retdata, retdlen);
887 if (p == NULL)
888 break;
889 if (type == 'c')
890 printf("c %.*s %.*s\n",(int)retklen, retkey,(int)retdlen, retdata);
891 else
892 printf("d %.*s\n", (int)retdlen, retdata);
893 } /* end of for (DB_MULTIPLE_INIT....) */
895 } /* end of for (;;) */
897 /* free the buffer we created earlier */
898 free(bdbdata->data);
900 return ISC_R_SUCCESS;
904 * Perform listOrDelete operation
905 * if dlt == true, delete data
906 * else list data
909 void
910 operation_listOrDelete(isc_boolean_t dlt) {
912 int bdbres = 0;
913 DBC *curList[3];
914 DBT bdbkey, bdbdata;
915 db_recno_t recno;
916 int curIndex = 0;
919 /* verify that only allowed parameters were passed. */
920 if (dlt == isc_boolean_true) {
921 checkInvalidParam(zone, "z", "for delete operation");
922 checkInvalidParam(host, "h", "for delete operation");
923 checkInvalidOption(list_everything, isc_boolean_true, "e",
924 "for delete operation");
925 checkInvalidOption(create_allowed, isc_boolean_true, "n",
926 "for delete operation");
927 } else if (key != NULL || zone != NULL || host != NULL) {
928 checkInvalidParam(c_zone, "c", "for list when k, z or h are specified");
929 checkInvalidParam(c_ip, "i", "for list when k, z, or h are specified");
930 checkInvalidOption(list_everything, isc_boolean_true, "e",
931 "for list when k, z, or h are specified");
932 checkInvalidOption(create_allowed, isc_boolean_true, "n",
933 "for list operation");
934 } else if (c_ip != NULL || c_zone != NULL) {
935 checkInvalidOption(list_everything, isc_boolean_true, "e",
936 "for list when c or i are specified");
937 checkInvalidOption(create_allowed, isc_boolean_true, "n",
938 "for list operation");
941 memset(&bdbkey, 0, sizeof(bdbkey));
942 memset(&bdbdata, 0, sizeof(bdbdata));
944 /* Dump database in "dlzbdb" bulk format */
945 if (list_everything == isc_boolean_true) {
946 if (bulk_write('c', db.client, db.cursor, &bdbkey, &bdbdata)
947 != ISC_R_SUCCESS)
948 return;
949 memset(&bdbkey, 0, sizeof(bdbkey));
950 memset(&bdbdata, 0, sizeof(bdbdata));
951 bulk_write('d', db.data, db.cursor2, &bdbkey, &bdbdata);
952 return;
953 } /* end if (list_everything) */
955 /* set NULL the 2nd and 3rd positions in curList. */
956 /* that way later when add cursors to the join list */
957 /* it is already null terminated. */
958 curList[1] = curList[2] = NULL;
960 if (key != NULL) {
961 /* make sure other parameters weren't */
962 checkInvalidParam(zone, "z", "when k is specified");
963 checkInvalidParam(host, "h", "when k is specified");
965 recno = key_val;
966 bdbkey.data = &recno;
967 bdbkey.size = sizeof(recno);
969 if (dlt == isc_boolean_true) {
970 bdbres = db.data->del(db.data, NULL, &bdbkey, 0);
971 } else {
972 bdbdata.flags = DB_DBT_REALLOC;
973 bdbres = db.data->get(db.data, NULL, &bdbkey, &bdbdata, 0);
975 if (bdbres == 0) {
976 printf("KEY | DATA\n");
977 printf("%lu | %.*s\n", *(u_long *) bdbkey.data,
978 (int)bdbdata.size, (char *)bdbdata.data);
980 } /* closes else of if (dlt == isc_boolean_true) */
981 if (bdbres == DB_NOTFOUND) {
982 printf("Key not found in database");
984 } /* closes if (key != NULL) */
986 /* if zone is passed */
987 if (zone != NULL) {
988 /* create a cursor and make sure it worked */
989 bdbres = db.zone->cursor(db.zone, NULL, &db.cursor2, 0);
990 if (bdbres != 0) {
991 fprintf(stderr, "Unexpected error. BDB Error: %s\n",
992 db_strerror(bdbres));
993 return;
996 bdbkey.data = zone;
997 bdbkey.size = strlen(zone);
998 bdbres = db.cursor2->c_get(db.cursor2, &bdbkey, &bdbdata, DB_SET);
999 if (bdbres != 0) {
1000 if (bdbres != DB_NOTFOUND) {
1001 fprintf(stderr, "Unexpected error. BDB Error: %s\n",
1002 db_strerror(bdbres));
1003 } else {
1004 printf("Zone not found in database");
1006 return;
1009 /* add cursor to cursor list for later use in join */
1010 curList[curIndex++] = db.cursor2;
1013 /* if host is passed */
1014 if (host != NULL) {
1016 /* create a cursor and make sure it worked. */
1017 bdbres = db.host->cursor(db.host, NULL, &db.cursor3, 0);
1018 if (bdbres != 0) {
1019 fprintf(stderr, "Unexpected error. BDB Error: %s\n",
1020 db_strerror(bdbres));
1021 return;
1023 bdbkey.data = host;
1024 bdbkey.size = strlen(host);
1025 bdbres = db.cursor3->c_get(db.cursor3, &bdbkey, &bdbdata, DB_SET);
1026 if (bdbres != 0) {
1027 if (bdbres != DB_NOTFOUND) {
1028 fprintf(stderr, "Unexpected error. BDB Error: %s\n",
1029 db_strerror(bdbres));
1030 } else {
1031 printf("Host not found in database");
1033 return;
1036 /* add cursor to cursor list for later use in join */
1037 curList[curIndex++] = db.cursor3;
1041 if (zone != NULL || host != NULL) {
1043 /* join any cursors */
1044 bdbres = db.data->join(db.data, curList, &db.cursor4, 0);
1045 if (bdbres != 0) {
1046 fprintf(stderr, "Unexpected error. BDB Error: %s\n",
1047 db_strerror(bdbres));
1048 return;
1051 memset(&bdbkey, 0, sizeof(bdbkey));
1052 bdbkey.flags = DB_DBT_REALLOC;
1053 memset(&bdbdata, 0, sizeof(bdbdata));
1054 bdbdata.flags = DB_DBT_REALLOC;
1056 /* print a header to explain the output */
1057 printf("KEY | DATA\n");
1058 /* loop and list all results. */
1059 while (bdbres == 0) {
1060 /* get data */
1061 bdbres = db.cursor4->c_get(db.cursor4, &bdbkey, &bdbdata, 0);
1062 /* verify call had no errors */
1063 if (bdbres != 0) {
1064 break;
1066 printf("%lu | %.*s\n", *(u_long *) bdbkey.data,
1067 (int)bdbdata.size, (char *)bdbdata.data);
1068 } /* closes while loop */
1071 if (c_ip != NULL && c_zone == NULL) {
1072 fprintf(stderr, "i may only be specified when c is also specified\n");
1073 quit(2);
1075 /* if client_zone was passed */
1076 if (c_zone != NULL) {
1078 /* create a cursor and make sure it worked. */
1079 if (dlt == isc_boolean_true) {
1080 /* open read-write cursor */
1081 bdbres = db.client->cursor(db.client, NULL, &db.cursor,
1082 DB_WRITECURSOR);
1083 } else {
1084 /* open read only cursor */
1085 bdbres = db.client->cursor(db.client, NULL, &db.cursor, 0);
1086 /* print a header to explain the output */
1087 printf("CLIENT_ZONE | CLIENT_IP\n");
1090 bdbkey.data = c_zone;
1091 bdbkey.size = strlen(c_zone);
1093 if (c_ip != NULL) {
1094 bdbdata.data = c_ip;
1095 bdbdata.size = strlen(c_ip);
1096 bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata, DB_GET_BOTH);
1097 if (bdbres == DB_NOTFOUND) {
1098 printf("Client zone & IP not found in database");
1100 } else {
1101 bdbdata.flags = DB_DBT_REALLOC;
1102 bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata, DB_SET);
1103 if (bdbres == DB_NOTFOUND) {
1104 printf("Client zone not found in database");
1108 while (bdbres == 0) {
1109 if (dlt == isc_boolean_false) {
1110 printf("%.*s | %.*s\n", (int)bdbkey.size, (char *) bdbkey.data,
1111 (int)bdbdata.size, (char *) bdbdata.data);
1112 } else {
1113 /* delete record. */
1114 bdbres = db.cursor->c_del(db.cursor, 0);
1115 if (bdbres != 0) {
1116 fprintf(stderr, "Unexpected error. BDB Error: %s\n",
1117 db_strerror(bdbres));
1118 break;
1121 if (c_ip != NULL) {
1122 break;
1124 bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata, DB_NEXT_DUP);
1125 if (bdbres != 0) {
1126 break;
1128 } /* end while loop */
1132 if (bdbres != 0 && bdbres != DB_NOTFOUND) {
1133 fprintf(stderr, "Unexpected error during list operation " \
1134 "BDB error: %s", db_strerror(bdbres));
1137 if (bdbkey.flags == DB_DBT_REALLOC && bdbkey.data != NULL) {
1138 free(bdbkey.data);
1140 if (bdbdata.flags == DB_DBT_REALLOC && bdbdata.data != NULL) {
1141 free(bdbdata.data);
1147 main(int argc, char **argv) {
1149 int ch;
1150 char *endp;
1152 /* there has to be at least 2 args, some operations require more */
1153 if (argc < 2)
1154 show_usage();
1156 /* use the ISC commandline parser to get all the program arguments */
1157 while ((ch= isc_commandline_parse(argc, argv, "ldesna:f:k:z:h:c:i:")) != -1) {
1158 switch (ch) {
1159 case 'n':
1160 create_allowed = isc_boolean_true;
1161 break;
1162 case 'l':
1163 checkOp(operation);
1164 operation = list;
1165 break;
1166 case 'd':
1167 checkOp(operation);
1168 operation = dele;
1169 break;
1170 case 'a':
1171 checkOp(operation);
1172 operation = add;
1173 a_data = isc_commandline_argument;
1174 break;
1175 case 'f':
1176 checkOp(operation);
1177 operation = bulk;
1178 bulk_file = isc_commandline_argument;
1179 break;
1180 case 's':
1181 checkOp(operation);
1182 operation = bulk;
1183 break;
1184 case 'k':
1185 checkParam(key, "k");
1186 key = isc_commandline_argument;
1187 key_val = strtoul(key, &endp, 10);
1188 if (*endp != '\0' || key_val < 1) {
1189 fprintf(stderr, "Error converting key to integer");
1191 break;
1192 case 'z':
1193 checkParam(zone, "z");
1194 zone = isc_commandline_argument;
1195 break;
1196 case 'h':
1197 checkParam(host, "h");
1198 host = isc_commandline_argument;
1199 break;
1200 case 'c':
1201 checkParam(c_zone, "c");
1202 c_zone = isc_commandline_argument;
1203 break;
1204 case 'i':
1205 checkParam(c_ip, "i");
1206 c_ip = isc_commandline_argument;
1207 break;
1208 case 'e':
1209 checkOp(operation);
1210 operation = list;
1211 list_everything = isc_boolean_true;
1212 break;
1213 case '?':
1214 show_usage();
1215 break;
1216 default:
1217 /* should never reach this point */
1218 fprintf(stderr, "unexpected error parsing command arguments\n");
1219 quit(1);
1220 break;
1224 argc -= isc_commandline_index;
1225 argv += isc_commandline_index;
1227 /* argc & argv have been modified, so now only "extra" parameters are */
1228 /* left in argc & argv. "Extra" parameters are any parameters that were */
1229 /* not passed using a command line flag. Exactly 2 args should be left. */
1230 /* The first should be the BDB environment path, the second should be the */
1231 /* BDB database. The BDB database path can be either relative to the */
1232 /* BDB environment path, or absolute. */
1233 if (argc < 2) {
1234 fprintf(stderr, "Both a Berkeley DB environment and file "\
1235 "must be specified");
1236 quit(2);
1237 } else if (argc > 2) {
1238 fprintf(stderr, "Too many parameters. Check command line for errors.");
1239 quit(2);
1242 /* get db_file to operate on */
1243 db_envdir = argv[0];
1244 db_file = argv[1];
1246 if (openBDB() != ISC_R_SUCCESS) {
1247 /* openBDB already prints error messages, don't do it here. */
1248 bdb_cleanup();
1249 quit(3);
1252 switch(operation) {
1253 case list:
1254 operation_listOrDelete(isc_boolean_false);
1255 break;
1256 case dele:
1257 operation_listOrDelete(isc_boolean_true);
1258 break;
1259 case add:
1260 operation_add();
1261 break;
1262 case bulk:
1263 operation_bulk();
1264 break;
1265 default:
1266 fprintf(stderr, "\nNo operation was selected. "\
1267 "Select an operation (l d a f)");
1268 quit(2);
1269 break;
1272 quit(0);
1274 #endif