1 /* $NetBSD: dlzbdb.c,v 1.3 2014/12/10 04:37:55 christos Exp $ */
4 * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the
8 * above copyright notice and this permission notice appear in all
11 * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
12 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
13 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
14 * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
15 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
16 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
18 * USE OR PERFORMANCE OF THIS SOFTWARE.
20 * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
21 * conceived and contributed by Rob Butler.
23 * Permission to use, copy, modify, and distribute this software for any
24 * purpose with or without fee is hereby granted, provided that the
25 * above copyright notice and this permission notice appear in all
28 * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
29 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31 * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
32 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
33 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
34 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
35 * USE OR PERFORMANCE OF THIS SOFTWARE.
39 * Copyright (C) 1999-2001 Internet Software Consortium.
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.
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
72 #include <isc/buffer.h>
73 #include <isc/commandline.h>
74 #include <isc/formatcheck.h>
77 #include <isc/result.h>
78 #include <isc/string.h>
83 /* shut up compiler warnings about no previous prototype */
89 getzone(DB
*dbp
, const DBT
*pkey
, const DBT
*pdata
, DBT
*skey
);
92 gethost(DB
*dbp
, const DBT
*pkey
, const DBT
*pdata
, DBT
*skey
);
98 bdb_opendb(DBTYPE db_type
, DB
**db_out
, const char *db_name
, int flags
);
101 put_data(isc_boolean_t dns_data
, char *input_key
, char *input_data
);
116 bulk_write(char type
, DB
*database
, DBC
*dbcursor
, DBT
*bdbkey
, DBT
*bdbdata
);
122 operation_bulk(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 */
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
255 fprintf(stderr
, "\n\n\
256 ---Usage:---------------------------------------------------------------------\
259 dlzbdb -l [-k key] [-z zone] [-h host] [-c client_zone] [-i client_ip]\n\
260 BDB_environment BDB_database\n\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\
269 dlzbdb -a \"dns data to be added\" BDB_environment BDB_database\n\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:------------------------------------------------\
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:------------------------------------------------------------------\
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\
296 /*% BDB callback to create zone secondary index */
299 getzone(DB
*dbp
, const DBT
*pkey
, const DBT
*pdata
, DBT
*skey
) {
308 /* Allocate memory to use in parsing the string */
309 tmp
= right
= malloc(pdata
->size
+ 1);
311 /* verify memory was allocated */
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
;
344 * BDB callback to create host secondary index
348 gethost(DB
*dbp
, const DBT
*pkey
, const DBT
*pdata
, DBT
*skey
) {
357 /* allocate memory to use in parsing the string */
358 tmp
= right
= malloc(pdata
->size
+ 1);
360 /* verify memory was allocated */
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 */
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
;
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.
411 if (db
.cursor4
!= NULL
) {
412 db
.cursor4
->c_close(db
.cursor4
);
416 if (db
.cursor3
!= NULL
) {
417 db
.cursor3
->c_close(db
.cursor3
);
421 if (db
.cursor2
!= NULL
) {
422 db
.cursor2
->c_close(db
.cursor2
);
426 if (db
.cursor
!= NULL
) {
427 db
.cursor
->c_close(db
.cursor
);
431 /* close databases */
432 if (db
.data
!= NULL
) {
433 db
.data
->close(db
.data
, 0);
436 if (db
.host
!= NULL
) {
437 db
.host
->close(db
.host
, 0);
440 if (db
.zone
!= NULL
) {
441 db
.zone
->close(db
.zone
, 0);
444 if (db
.client
!= NULL
) {
445 db
.client
->close(db
.client
, 0);
449 /* close environment */
450 if (db
.dbenv
!= NULL
) {
451 db
.dbenv
->close(db
.dbenv
, 0);
456 /*% Initializes, sets flags and then opens Berkeley databases. */
459 bdb_opendb(DBTYPE db_type
, DB
**db_out
, const char *db_name
, int flags
) {
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
500 put_data(isc_boolean_t dns_data
, char *input_key
, char *input_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
);
515 /* always setup data for insertion */
516 data
.data
= input_data
;
517 data
.size
= strlen(input_data
);
520 /* execute insert against appropriate database. */
522 bdbres
= db
.data
->put(db
.data
, NULL
, &key
, &data
, DB_APPEND
);
524 bdbres
= db
.client
->put(db
.client
, NULL
, &key
, &data
, 0);
527 /* if something went wrong, log error and quit */
529 fprintf(stderr
, "BDB could not insert data. Error: %s",
530 db_strerror(bdbres
));
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 */
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
];
549 char data_arr2
[max_data_len
];
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
);
558 result
= isc_lex_gettoken(lexer
, opt
, &token
);
559 if (result
!= ISC_R_SUCCESS
)
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. */
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);
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
;
586 isc_buffer_putstr(&buf
, token
.value
.as_pointer
);
587 isc_buffer_putstr(&buf
, " ");
590 case isc_tokentype_qstring
:
591 isc_buffer_putstr(&buf
, "\"");
592 isc_buffer_putstr(&buf
, token
.value
.as_pointer
);
593 isc_buffer_putstr(&buf
, "\" ");
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);
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
;
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
));
648 /* create BDB environment */
649 /* Basically BDB allocates and assigns memory to db->dbenv */
650 bdbres
= db_env_create(&db
.dbenv
, 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);
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);
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);
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
;
721 /*% Create & open lexer to parse input data */
727 /* check if we already opened the lexer, if we did, return success */
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");
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
);
753 /*% Close the lexer, and cleanup memory */
758 /* If lexer is still open, close it & destroy it. */
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 */
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
) {
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");
796 /*common logic for "add" & "bulk" operations are handled by insert_data */
800 /*% Perform bulk insert operation */
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
) {
818 if (bulk_file
== NULL
) {
819 if (isc_lex_openstream(lexer
, stdin
) != ISC_R_SUCCESS
) {
820 fprintf(stderr
, "unexpected error opening stdin by lexer.");
823 } else if (isc_lex_openfile(lexer
, bulk_file
) != ISC_R_SUCCESS
) {
824 fprintf(stderr
, "unexpected error opening %s by lexer.", bulk_file
);
828 /* common logic for "add" & "bulk" operations are handled by insert_data */
833 bulk_write(char type
, DB
*database
, DBC
*dbcursor
, DBT
*bdbkey
, DBT
*bdbdata
) {
837 char *retkey
= NULL
, *retdata
;
838 size_t retklen
= 0, retdlen
;
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
) {
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);
857 fprintf(stderr
, "Unexpected error. BDB Error: %s\n",db_strerror(bdbres
));
859 return ISC_R_FAILURE
;
862 /* loop and dump all data */
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. */
871 if (bdbres
!= DB_NOTFOUND
) {
872 fprintf(stderr
, "Unexpected error. BDB Error: %s\n",
873 db_strerror(bdbres
));
875 return ISC_R_FAILURE
;
877 /* Hit DB_NOTFOUND which means end of data. */
879 } /* end of if (bdbres !=0) */
881 for (DB_MULTIPLE_INIT(p
, bdbdata
);;) {
883 DB_MULTIPLE_KEY_NEXT(p
, bdbdata
, retkey
, retklen
, retdata
, retdlen
);
885 DB_MULTIPLE_RECNO_NEXT(p
, bdbdata
, recNum
, retdata
, retdlen
);
890 printf("c %.*s %.*s\n",(int)retklen
, retkey
,(int)retdlen
, retdata
);
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 */
900 return ISC_R_SUCCESS
;
904 * Perform listOrDelete operation
905 * if dlt == true, delete data
910 operation_listOrDelete(isc_boolean_t dlt
) {
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
)
949 memset(&bdbkey
, 0, sizeof(bdbkey
));
950 memset(&bdbdata
, 0, sizeof(bdbdata
));
951 bulk_write('d', db
.data
, db
.cursor2
, &bdbkey
, &bdbdata
);
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
;
961 /* make sure other parameters weren't */
962 checkInvalidParam(zone
, "z", "when k is specified");
963 checkInvalidParam(host
, "h", "when k is specified");
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);
972 bdbdata
.flags
= DB_DBT_REALLOC
;
973 bdbres
= db
.data
->get(db
.data
, NULL
, &bdbkey
, &bdbdata
, 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 */
988 /* create a cursor and make sure it worked */
989 bdbres
= db
.zone
->cursor(db
.zone
, NULL
, &db
.cursor2
, 0);
991 fprintf(stderr
, "Unexpected error. BDB Error: %s\n",
992 db_strerror(bdbres
));
997 bdbkey
.size
= strlen(zone
);
998 bdbres
= db
.cursor2
->c_get(db
.cursor2
, &bdbkey
, &bdbdata
, DB_SET
);
1000 if (bdbres
!= DB_NOTFOUND
) {
1001 fprintf(stderr
, "Unexpected error. BDB Error: %s\n",
1002 db_strerror(bdbres
));
1004 printf("Zone not found in database");
1009 /* add cursor to cursor list for later use in join */
1010 curList
[curIndex
++] = db
.cursor2
;
1013 /* if host is passed */
1016 /* create a cursor and make sure it worked. */
1017 bdbres
= db
.host
->cursor(db
.host
, NULL
, &db
.cursor3
, 0);
1019 fprintf(stderr
, "Unexpected error. BDB Error: %s\n",
1020 db_strerror(bdbres
));
1024 bdbkey
.size
= strlen(host
);
1025 bdbres
= db
.cursor3
->c_get(db
.cursor3
, &bdbkey
, &bdbdata
, DB_SET
);
1027 if (bdbres
!= DB_NOTFOUND
) {
1028 fprintf(stderr
, "Unexpected error. BDB Error: %s\n",
1029 db_strerror(bdbres
));
1031 printf("Host not found in database");
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);
1046 fprintf(stderr
, "Unexpected error. BDB Error: %s\n",
1047 db_strerror(bdbres
));
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) {
1061 bdbres
= db
.cursor4
->c_get(db
.cursor4
, &bdbkey
, &bdbdata
, 0);
1062 /* verify call had no errors */
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");
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
,
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
);
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");
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
);
1113 /* delete record. */
1114 bdbres
= db
.cursor
->c_del(db
.cursor
, 0);
1116 fprintf(stderr
, "Unexpected error. BDB Error: %s\n",
1117 db_strerror(bdbres
));
1124 bdbres
= db
.cursor
->c_get(db
.cursor
, &bdbkey
, &bdbdata
, DB_NEXT_DUP
);
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
) {
1140 if (bdbdata
.flags
== DB_DBT_REALLOC
&& bdbdata
.data
!= NULL
) {
1147 main(int argc
, char **argv
) {
1152 /* there has to be at least 2 args, some operations require more */
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) {
1160 create_allowed
= isc_boolean_true
;
1173 a_data
= isc_commandline_argument
;
1178 bulk_file
= isc_commandline_argument
;
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");
1193 checkParam(zone
, "z");
1194 zone
= isc_commandline_argument
;
1197 checkParam(host
, "h");
1198 host
= isc_commandline_argument
;
1201 checkParam(c_zone
, "c");
1202 c_zone
= isc_commandline_argument
;
1205 checkParam(c_ip
, "i");
1206 c_ip
= isc_commandline_argument
;
1211 list_everything
= isc_boolean_true
;
1217 /* should never reach this point */
1218 fprintf(stderr
, "unexpected error parsing command arguments\n");
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. */
1234 fprintf(stderr
, "Both a Berkeley DB environment and file "\
1235 "must be specified");
1237 } else if (argc
> 2) {
1238 fprintf(stderr
, "Too many parameters. Check command line for errors.");
1242 /* get db_file to operate on */
1243 db_envdir
= argv
[0];
1246 if (openBDB() != ISC_R_SUCCESS
) {
1247 /* openBDB already prints error messages, don't do it here. */
1254 operation_listOrDelete(isc_boolean_false
);
1257 operation_listOrDelete(isc_boolean_true
);
1266 fprintf(stderr
, "\nNo operation was selected. "\
1267 "Select an operation (l d a f)");