summaryrefslogtreecommitdiffstats
path: root/contrib/dlz/bin/dlzbdb/dlzbdb.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 07:24:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 07:24:22 +0000
commit45d6379135504814ab723b57f0eb8be23393a51d (patch)
treed4f2ec4acca824a8446387a758b0ce4238a4dffa /contrib/dlz/bin/dlzbdb/dlzbdb.c
parentInitial commit. (diff)
downloadbind9-45d6379135504814ab723b57f0eb8be23393a51d.tar.xz
bind9-45d6379135504814ab723b57f0eb8be23393a51d.zip
Adding upstream version 1:9.16.44.upstream/1%9.16.44
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/dlz/bin/dlzbdb/dlzbdb.c')
-rw-r--r--contrib/dlz/bin/dlzbdb/dlzbdb.c1277
1 files changed, 1277 insertions, 0 deletions
diff --git a/contrib/dlz/bin/dlzbdb/dlzbdb.c b/contrib/dlz/bin/dlzbdb/dlzbdb.c
new file mode 100644
index 0000000..122d496
--- /dev/null
+++ b/contrib/dlz/bin/dlzbdb/dlzbdb.c
@@ -0,0 +1,1277 @@
+/*
+ * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Copyright (C) 1999-2001, 2016 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifdef DLZ_BDB
+
+/*
+ * exit codes
+ * 0 everything ok
+ * 1 error parsing command line
+ * 2 Missing, too many or invalid combination of command line parameters
+ * 3 Unable to open BDB database.
+ * 4 Unable to allocate memory for, or create lexer.
+ * 5 unable to perform BDB cursor operation
+ */
+#include <db.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <isc/buffer.h>
+#include <isc/commandline.h>
+#include <isc/formatcheck.h>
+#include <isc/lex.h>
+#include <isc/mem.h>
+#include <isc/result.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+/* shut up compiler warnings about no previous prototype */
+
+static void
+show_usage(void);
+
+int
+getzone(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
+
+int
+gethost(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
+
+void
+bdb_cleanup(void);
+
+isc_result_t
+bdb_opendb(DBTYPE db_type, DB **db_out, const char *db_name, int flags);
+
+void
+put_data(bool dns_data, char *input_key, char *input_data);
+
+void
+insert_data(void);
+
+isc_result_t
+openBDB(void);
+
+isc_result_t
+open_lexer(void);
+
+void
+close_lexer(void);
+
+isc_result_t
+bulk_write(char type, DB *database, DBC *dbcursor, DBT *bdbkey, DBT *bdbdata);
+
+void
+operation_add(void);
+
+void
+operation_bulk(void);
+
+void
+operation_listOrDelete(bool dlt);
+
+/*%
+ * Maximum length of a single data line that
+ * may be inserted into database by this program.
+ * If you need to insert a line of data that is more
+ * than 10,000 characters change this definition.
+ */
+
+#define max_data_len 10000
+
+/*%
+ * BDB database names. If you want to use different
+ * database names change them here.
+ */
+
+#define dlz_data "dns_data"
+#define dlz_zone "dns_zone"
+#define dlz_host "dns_host"
+#define dlz_client "dns_client"
+
+/*%
+ * Error code returned by BDB secondary index callback functions.
+ * This error is returned if the callback function could not create
+ * the secondary index for any reason.
+ */
+
+#define BDBparseErr 1
+
+/* A struct to hold all the relevant info about the database */
+
+typedef struct bdb_instance {
+ DB_ENV *dbenv; /* BDB environment */
+ DB *data; /* dns_data database handle */
+ DBC *cursor; /* database cursor */
+ DBC *cursor2; /* second cursor used during list operation. */
+ DBC *cursor3; /* third cursor used during list operation */
+ DBC *cursor4; /* fourth cursor used during list operation */
+ DB *zone; /* zone database handle */
+ DB *host; /* host database handle */
+ DB *client; /* client database handle */
+} bdb_instance_t;
+
+/* Possible operations */
+
+#define list 1 /* list data */
+#define dele 2 /* delete data */
+#define add 3 /* add a single piece of data */
+#define bulk 4 /* bulk load data */
+
+/*%
+ * quit macro is used instead of exit. quit always tries to close the lexer
+ * and the BDB database before exiting.
+ */
+
+#define quit(i) \
+ close_lexer(); \
+ bdb_cleanup(); \
+ exit(i);
+
+/*%
+ * checkOp is used to verify that only one operation (list, del, add,
+ * bulk from file, bulk from stdin) is specified on the command line.
+ * This prevents a user from specifying two operations on the command
+ * line, which would make no sense anyway.
+ */
+
+#define checkOp(x) \
+ if (x != 0) { \
+ fprintf(stderr, "\nonly one operation " \
+ "(l e d a f s) may be specified\n"); \
+ quit(2); \
+ }
+
+/*%
+ * checkParam is used to only allow a parameter to be specified once.
+ * I.E. the parameter key can only be used on the command line once.
+ * any attempt to use it twice causes an error.
+ */
+
+#define checkParam(x, y) \
+ if (x != NULL) { \
+ fprintf(stderr, \
+ "\n%s may only " \
+ "be specified once\n", \
+ y); \
+ quit(2); \
+ }
+
+/*%
+ * checkInvalidParam is used to only allow parameters which make sense for
+ * the operation selected. I.E. passing the key parameter makes no sense
+ * for the add operation, and thus it isn't allowed.
+ */
+
+#define checkInvalidParam(x, y, z) \
+ if (x != NULL) { \
+ fprintf(stderr, \
+ "\n%s " \
+ "may not be specified %s\n", \
+ y, z); \
+ quit(2); \
+ }
+
+/*%
+ * checkInvalidOption is used to only allow parameters which make sense for
+ * the operation selected - but checks boolean options.
+ * I.E. passing the "b" bare_list parameter makes no sense for the add
+ * operation, and thus it isn't allowed.
+ * if w == x then output error message "flag", "message"
+ */
+
+#define checkInvalidOption(w, x, y, z) \
+ if (w == x) { \
+ fprintf(stderr, \
+ "\n%s " \
+ "may not be specified %s\n", \
+ y, z); \
+ quit(2); \
+ }
+
+/* Global Variables */
+
+int operation = 0; /*%< operation to perform. */
+/*% allow new lock files or DB to be created. */
+bool create_allowed = false;
+char *key = NULL; /*%< key to use in list & del operations */
+
+/*% dump DB in DLZBDB bulk format */
+bool list_everything = false;
+unsigned int key_val; /*%< key as unsigned int used in list & del operations */
+char *zone = NULL; /*%< zone to use in list operations */
+char *host = NULL; /*%< host to use in list operations */
+char *c_zone = NULL; /*%< client zone to use in list operations */
+char *c_ip = NULL; /*%< client IP to use in list operations */
+char *a_data = NULL; /*%< data in add operation */
+char *bulk_file = NULL; /*%< bulk data file to load */
+char *db_envdir = NULL; /*%< BDB environment location */
+char *db_file = NULL; /*%< BDB database file location. */
+bdb_instance_t db; /* BDB instance we are operating on */
+isc_lex_t *lexer = NULL; /*%< lexer for use to use in parsing input */
+isc_mem_t *lex_mctx = NULL; /*%< memory context for lexer */
+char lex_data_buf[max_data_len]; /*%< data array to use for lex_buffer below */
+isc_buffer_t lex_buffer; /*%< buffer for lexer during add operation */
+
+/*%
+ * Displays usage message
+ */
+
+static void
+show_usage(void) {
+ fprintf(stderr, "\n\n\
+---Usage:---------------------------------------------------------------------\
+\n\n\
+ List data:\n\
+ dlzbdb -l [-k key] [-z zone] [-h host] [-c client_zone] [-i client_ip]\n\
+ BDB_environment BDB_database\n\n\
+ Delete data:\n\
+ dlzbdb -d [-k key] [-c client_zone] [-i client_ip]\n\
+ BDB_environment BDB_database\n\n\
+ Bulk load data from file:\n\
+ dlzbdb -f file_to_load BDB_environment BDB_database\n\n\
+ Bulk load data from stdin\n\
+ dlzbdb -s BDB_environment BDB_database\n\n\
+ Add data:\n\
+ dlzbdb -a \"dns data to be added\" BDB_environment BDB_database\n\n\
+ Export data:\n\
+ dlzbdb -e BDB_environment BDB_database\n\n\
+ Normally operations can only be performed on an existing database files.\n\
+ Use the -n flag with any operation to allow files to be created.\n\
+ Existing files will NOT be truncated by using the -n flag.\n\
+ The -n flag will allow a new database to be created, or allow new\n\
+ environment files to be created for an existing database.\n\n\
+---Format for -f & -a options:------------------------------------------------\
+\n\n\
+db_type zone host dns_type ttl ip\n\
+db_type zone host dns_type ttl mx_priority mail_host\n\
+db_type zone host dns_type ttl nm_svr resp_psn serial refresh retry expire min\
+\n\
+db_type zone client_ip\n\n\
+---Examples:------------------------------------------------------------------\
+\n\n\
+d mynm.com www A 10 127.0.0.1\n\
+d mynm.com @ MX 10 5 mail\n\
+d mynm.com @ SOA 10 ns1.mynm.com. root.mynm.com. 2 28800 7200 604800 86400\n\
+c mynm.com 127.0.0.1\n\
+c mynm.com 192.168.0.10\n\
+");
+ quit(1);
+}
+
+/*% BDB callback to create zone secondary index */
+
+int
+getzone(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey) {
+ char *token, *last;
+
+ UNUSED(dbp);
+ UNUSED(pkey);
+
+ if ((token = strtok_r(pdata->data, " ", &last)) == NULL) {
+ return (BDBparseErr);
+ }
+
+ /* copy string for "zone" secondary index */
+ if ((skey->data = strdup(token)) == NULL) {
+ return (BDBparseErr);
+ }
+ /* set required values for BDB */
+ skey->size = strlen(skey->data);
+ skey->flags = DB_DBT_APPMALLOC;
+
+ return (0);
+}
+
+/*%
+ * BDB callback to create host secondary index
+ */
+
+int
+gethost(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey) {
+ char *token, *last;
+
+ UNUSED(dbp);
+ UNUSED(pkey);
+
+ /* we don't care about first token. */
+ if ((token = strtok_r(right, " ", &last)) == NULL) {
+ return (BDBparseErr);
+ }
+
+ /* get "host" from data string */
+ if ((token = strtok_r(NULL, " ", &last)) == NULL) {
+ return (BDBparseErr);
+ }
+
+ /* copy string for "host" secondary index */
+ if ((skey->data = strdup(token)) == NULL) {
+ return (BDBparseErr);
+ }
+ /* set required values for BDB */
+ skey->size = strlen(skey->data);
+ skey->flags = DB_DBT_APPMALLOC;
+
+ return (0);
+}
+
+/*%
+ * Performs BDB cleanup. Close each database that we opened.
+ * Close environment. Set each var to NULL so we know they
+ * were closed and don't accidentally try to close them twice.
+ */
+
+void
+bdb_cleanup(void) {
+ /* close cursors */
+ if (db.cursor4 != NULL) {
+ db.cursor4->c_close(db.cursor4);
+ db.cursor4 = NULL;
+ }
+
+ if (db.cursor3 != NULL) {
+ db.cursor3->c_close(db.cursor3);
+ db.cursor3 = NULL;
+ }
+
+ if (db.cursor2 != NULL) {
+ db.cursor2->c_close(db.cursor2);
+ db.cursor2 = NULL;
+ }
+
+ if (db.cursor != NULL) {
+ db.cursor->c_close(db.cursor);
+ db.cursor = NULL;
+ }
+
+ /* close databases */
+ if (db.data != NULL) {
+ db.data->close(db.data, 0);
+ db.data = NULL;
+ }
+ if (db.host != NULL) {
+ db.host->close(db.host, 0);
+ db.host = NULL;
+ }
+ if (db.zone != NULL) {
+ db.zone->close(db.zone, 0);
+ db.zone = NULL;
+ }
+ if (db.client != NULL) {
+ db.client->close(db.client, 0);
+ db.client = NULL;
+ }
+
+ /* close environment */
+ if (db.dbenv != NULL) {
+ db.dbenv->close(db.dbenv, 0);
+ db.dbenv = NULL;
+ }
+}
+
+/*% Initializes, sets flags and then opens Berkeley databases. */
+
+isc_result_t
+bdb_opendb(DBTYPE db_type, DB **db_out, const char *db_name, int flags) {
+ int result;
+ int createFlag = 0;
+
+ /* Initialize the database. */
+ if ((result = db_create(db_out, db.dbenv, 0)) != 0) {
+ fprintf(stderr,
+ "BDB could not initialize %s database. BDB error: %s",
+ db_name, db_strerror(result));
+ return (ISC_R_FAILURE);
+ }
+
+ /* set database flags. */
+ if ((result = (*db_out)->set_flags(*db_out, flags)) != 0) {
+ fprintf(stderr,
+ "BDB could not set flags for %s database. BDB error: "
+ "%s",
+ db_name, db_strerror(result));
+ return (ISC_R_FAILURE);
+ }
+
+ if (create_allowed) {
+ createFlag = DB_CREATE;
+ }
+ /* open the database. */
+ if ((result = (*db_out)->open(*db_out, NULL, db_file, db_name, db_type,
+ createFlag, 0)) != 0)
+ {
+ fprintf(stderr,
+ "BDB could not open %s database in %s. BDB error: %s",
+ db_name, db_file, db_strerror(result));
+ return (ISC_R_FAILURE);
+ }
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * parses input and adds it to the BDB database
+ * Lexer should be instantiated, and either a file or buffer opened for it.
+ * The insert_data function is used by both the add, and bulk insert
+ * operations
+ */
+
+void
+put_data(bool dns_data, char *input_key, char *input_data) {
+ int bdbres;
+ DBT key, data;
+
+ /* make sure key & data are completely empty */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ /* if client data, setup key for insertion */
+ if (!dns_data && input_key != NULL) {
+ key.data = input_key;
+ key.size = strlen(input_key);
+ key.flags = 0;
+ }
+ /* always setup data for insertion */
+ data.data = input_data;
+ data.size = strlen(input_data);
+ data.flags = 0;
+
+ /* execute insert against appropriate database. */
+ if (dns_data) {
+ bdbres = db.data->put(db.data, NULL, &key, &data, DB_APPEND);
+ } else {
+ bdbres = db.client->put(db.client, NULL, &key, &data, 0);
+ }
+
+ /* if something went wrong, log error and quit */
+ if (bdbres != 0) {
+ fprintf(stderr, "BDB could not insert data. Error: %s",
+ db_strerror(bdbres));
+ quit(5);
+ }
+}
+
+void
+insert_data(void) {
+ unsigned int opt = ISC_LEXOPT_EOL | /* Want end-of-line token. */
+ ISC_LEXOPT_EOF | /* Want end-of-file token. */
+ ISC_LEXOPT_QSTRING | /* Recognize qstrings. */
+ ISC_LEXOPT_QSTRINGMULTILINE; /* Allow multiline ""
+ * strings */
+
+ isc_result_t result;
+ isc_token_t token; /* token from lexer */
+ bool loop = true;
+ bool have_czone = false;
+ char data_arr[max_data_len];
+ isc_buffer_t buf;
+ char data_arr2[max_data_len];
+ isc_buffer_t buf2;
+ char data_type = 'u'; /* u =unknown, b =bad token, d/D =DNS, c/C =client
+ * IP */
+
+ /* Initialize buffers */
+ isc_buffer_init(&buf, &data_arr, max_data_len);
+ isc_buffer_init(&buf2, &data_arr2, max_data_len);
+
+ while (loop) {
+ result = isc_lex_gettoken(lexer, opt, &token);
+ if (result != ISC_R_SUCCESS) {
+ goto data_cleanup;
+ }
+
+ switch (token.type) {
+ case isc_tokentype_string:
+ if (data_type == 'u') {
+ /* store data_type */
+ strncpy(&data_type, token.value.as_pointer, 1);
+ /* verify data_type was specified correctly on
+ * input */
+ if (strlen(token.value.as_pointer) > 1 ||
+ (data_type != 'd' && data_type != 'D' &&
+ data_type != 'c' && data_type != 'C'))
+ {
+ /* if not, set to 'b' so this line is
+ * ignored. */
+ data_type = 'b';
+ }
+ } else if (data_type == 'c' || data_type == 'C') {
+ if (have_czone) {
+ isc_buffer_putstr(
+ &buf2, token.value.as_pointer);
+ /* add string terminator to buffer */
+ isc_buffer_putmem(&buf2, "\0", 1);
+ } else {
+ isc_buffer_putstr(
+ &buf, token.value.as_pointer);
+ /* add string terminator to buffer */
+ isc_buffer_putmem(&buf, "\0", 1);
+ have_czone = true;
+ }
+ } else {
+ isc_buffer_putstr(&buf, token.value.as_pointer);
+ isc_buffer_putstr(&buf, " ");
+ }
+ break;
+ case isc_tokentype_qstring:
+ isc_buffer_putstr(&buf, "\"");
+ isc_buffer_putstr(&buf, token.value.as_pointer);
+ isc_buffer_putstr(&buf, "\" ");
+ break;
+ case isc_tokentype_eol:
+ case isc_tokentype_eof:
+
+ if ((data_type != 'u' &&
+ isc_buffer_usedlength(&buf) > 0) ||
+ data_type == 'b')
+ {
+ /* perform insert operation */
+ if (data_type == 'd' || data_type == 'D') {
+ /* add string terminator to buffer */
+ isc_buffer_putmem(&buf, "\0", 1);
+ put_data(true, NULL, (char *)&data_arr);
+ } else if (data_type == 'c' || data_type == 'C')
+ {
+ put_data(false, (char *)&data_arr,
+ (char *)&data_arr2);
+ } else if (data_type == 'b') {
+ fprintf(stderr,
+ "Bad / unknown token "
+ "encountered on line %lu."
+ " Skipping line.",
+ isc_lex_getsourceline(lexer) -
+ 1);
+ } else {
+ fprintf(stderr,
+ "Bad / unknown db data type "
+ "encountered on "
+ "line %lu. Skipping line\n",
+ isc_lex_getsourceline(lexer) -
+ 1);
+ }
+ }
+
+ if (token.type == isc_tokentype_eof) {
+ loop = false;
+ }
+
+ /* reset buffer for next insert */
+ isc_buffer_clear(&buf);
+ isc_buffer_clear(&buf2);
+ have_czone = false;
+ data_type = 'u';
+ break;
+ default:
+ data_type = 'b';
+ break;
+ }
+ }
+
+ return;
+
+data_cleanup:
+ /* let user know we had problems */
+ fprintf(stderr,
+ "Unknown error processing tokens during \"add\" or "
+ "\"bulk\" operation.\nStoped processing on line %lu.",
+ isc_lex_getsourceline(lexer));
+}
+
+isc_result_t
+openBDB(void) {
+ int bdbres;
+ isc_result_t result;
+
+ /* create BDB environment */
+ /* Basically BDB allocates and assigns memory to db->dbenv */
+ bdbres = db_env_create(&db.dbenv, 0);
+ if (bdbres != 0) {
+ fprintf(stderr,
+ "BDB environment could not be created. BDB error: %s",
+ db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto openBDB_cleanup;
+ }
+
+ /* open BDB environment */
+ if (create_allowed) {
+ /* allowed to create new files */
+ bdbres = db.dbenv->open(db.dbenv, db_envdir,
+ DB_INIT_CDB | DB_INIT_MPOOL | DB_CREATE,
+ 0);
+ } else { /* not allowed to create new files. */
+ bdbres = db.dbenv->open(db.dbenv, db_envdir,
+ DB_INIT_CDB | DB_INIT_MPOOL, 0);
+ }
+ if (bdbres != 0) {
+ fprintf(stderr,
+ "BDB environment at '%s' could not be opened. BDB "
+ "error: %s",
+ db_envdir, db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto openBDB_cleanup;
+ }
+
+ /* open dlz_data database. */
+
+ result = bdb_opendb(DB_RECNO, &db.data, dlz_data, 0);
+ if (result != ISC_R_SUCCESS) {
+ goto openBDB_cleanup;
+ }
+
+ /* open dlz_host database */
+ result = bdb_opendb(DB_BTREE, &db.host, dlz_host, DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS) {
+ goto openBDB_cleanup;
+ }
+
+ /* open dlz_zone database. */
+ result = bdb_opendb(DB_BTREE, &db.zone, dlz_zone, DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS) {
+ goto openBDB_cleanup;
+ }
+
+ /* open dlz_client database. */
+ result = bdb_opendb(DB_BTREE, &db.client, dlz_client,
+ DB_DUP | DB_DUPSORT);
+ if (result != ISC_R_SUCCESS) {
+ goto openBDB_cleanup;
+ }
+
+ /* associate the host secondary database with the primary database */
+ bdbres = db.data->associate(db.data, NULL, db.host, gethost, 0);
+ if (bdbres != 0) {
+ fprintf(stderr,
+ "BDB could not associate %s database with %s. BDB "
+ "error: %s",
+ dlz_host, dlz_data, db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto openBDB_cleanup;
+ }
+
+ /* associate the zone secondary database with the primary database */
+ bdbres = db.data->associate(db.data, NULL, db.zone, getzone, 0);
+ if (bdbres != 0) {
+ fprintf(stderr,
+ "BDB could not associate %s database with %s. BDB "
+ "error: %s",
+ dlz_zone, dlz_data, db_strerror(bdbres));
+ result = ISC_R_FAILURE;
+ goto openBDB_cleanup;
+ }
+
+ return (result);
+
+openBDB_cleanup:
+
+ bdb_cleanup();
+ return (result);
+}
+
+/*% Create & open lexer to parse input data */
+
+isc_result_t
+open_lexer(void) {
+ isc_result_t result;
+
+ /* check if we already opened the lexer, if we did, return success */
+ if (lexer != NULL) {
+ return (ISC_R_SUCCESS);
+ }
+
+ /* allocate memory for lexer, and verify it was allocated */
+ isc_mem_create(&lex_mctx);
+
+ /* create lexer */
+ result = isc_lex_create(lex_mctx, 1500, &lexer);
+ if (result != ISC_R_SUCCESS) {
+ fprintf(stderr, "unexpected error creating lexer\n");
+ }
+
+ /* set allowed commenting style */
+ isc_lex_setcomments(lexer,
+ ISC_LEXCOMMENT_C | /* Allow C comments */
+ ISC_LEXCOMMENT_CPLUSPLUS | /* Allow
+ * C++
+ * comments
+ */
+ ISC_LEXCOMMENT_SHELL); /* Allow
+ * shellcomments
+ */
+
+ isc_buffer_init(&lex_buffer, &lex_data_buf, max_data_len);
+
+ return (result);
+}
+
+/*% Close the lexer, and cleanup memory */
+
+void
+close_lexer(void) {
+ /* If lexer is still open, close it & destroy it. */
+ if (lexer != NULL) {
+ isc_lex_close(lexer);
+ isc_lex_destroy(&lexer);
+ }
+
+ /* if lexer memory is still allocated, destroy it. */
+ if (lex_mctx != NULL) {
+ isc_mem_destroy(&lex_mctx);
+ }
+}
+
+/*% Perform add operation */
+
+void
+operation_add(void) {
+ /* check for any parameters that are not allowed during add */
+ checkInvalidParam(key, "k", "for add operation");
+ checkInvalidParam(zone, "z", "for add operation");
+ checkInvalidParam(host, "h", "for add operation");
+ checkInvalidParam(c_zone, "c", "for add operation");
+ checkInvalidParam(c_ip, "i", "for add operation");
+ checkInvalidOption(list_everything, true, "e", "for add operation");
+
+ /* if open lexer fails it already prints error messages. */
+ if (open_lexer() != ISC_R_SUCCESS) {
+ quit(4);
+ }
+
+ /* copy input data to buffer */
+ isc_buffer_putstr(&lex_buffer, a_data);
+
+ /* tell lexer to use buffer as input */
+ if (isc_lex_openbuffer(lexer, &lex_buffer) != ISC_R_SUCCESS) {
+ fprintf(stderr, "unexpected error opening lexer buffer");
+ quit(4);
+ }
+
+ /*common logic for "add" & "bulk" operations are handled by insert_data
+ */
+ insert_data();
+}
+
+/*% Perform bulk insert operation */
+
+void
+operation_bulk(void) {
+ /* check for any parameters that are not allowed during bulk */
+ checkInvalidParam(key, "k", "for bulk load operation");
+ checkInvalidParam(zone, "z", "for bulk load operation");
+ checkInvalidParam(host, "h", "for bulk load operation");
+ checkInvalidParam(c_zone, "c", "for bulk load operation");
+ checkInvalidParam(c_ip, "i", "for bulk load operation");
+ checkInvalidOption(list_everything, true, "e",
+ "for bulk load operation");
+
+ /* if open lexer fails it already prints error messages. */
+ if (open_lexer() != ISC_R_SUCCESS) {
+ quit(4);
+ }
+
+ if (bulk_file == NULL) {
+ if (isc_lex_openstream(lexer, stdin) != ISC_R_SUCCESS) {
+ fprintf(stderr, "unexpected error opening stdin by "
+ "lexer.");
+ quit(4);
+ }
+ } else if (isc_lex_openfile(lexer, bulk_file) != ISC_R_SUCCESS) {
+ fprintf(stderr, "unexpected error opening %s by lexer.",
+ bulk_file);
+ quit(4);
+ }
+
+ /* common logic for "add" & "bulk" operations are handled by insert_data
+ */
+ insert_data();
+}
+
+isc_result_t
+bulk_write(char type, DB *database, DBC *dbcursor, DBT *bdbkey, DBT *bdbdata) {
+ int bdbres;
+ db_recno_t recNum;
+ char *retkey = NULL, *retdata;
+ size_t retklen = 0, retdlen;
+ void *p;
+
+ /* use a 5MB buffer for the bulk dump */
+ int buffer_size = 5 * 1024 * 1024;
+
+ /* try to allocate a 5 MB buffer, if we fail write err msg, die. */
+ bdbdata->data = malloc(buffer_size);
+ if (bdbdata->data == NULL) {
+ fprintf(stderr, "Unable to allocate 5 MB buffer for bulk "
+ "database dump\n");
+ return (ISC_R_FAILURE);
+ }
+ bdbdata->ulen = buffer_size;
+ bdbdata->flags = DB_DBT_USERMEM;
+
+ /* get a cursor, make sure it worked. */
+ bdbres = database->cursor(database, NULL, &dbcursor, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ free(bdbdata->data);
+ return (ISC_R_FAILURE);
+ }
+
+ /* loop and dump all data */
+ for (;;) {
+ /* loop through data until DB_NOTFOUND is returned */
+ bdbres = dbcursor->c_get(dbcursor, bdbkey, bdbdata,
+ DB_MULTIPLE_KEY | DB_NEXT);
+ /* if not successful did we encounter DB_NOTFOUND, or */
+ /* have a different problem. */
+ if (bdbres != 0) {
+ if (bdbres != DB_NOTFOUND) {
+ fprintf(stderr,
+ "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ free(bdbdata->data);
+ return (ISC_R_FAILURE);
+ }
+ /* Hit DB_NOTFOUND which means end of data. */
+ break;
+ } /* end of if (bdbres !=0) */
+
+ for (DB_MULTIPLE_INIT(p, bdbdata);;) {
+ if (type == 'c') {
+ DB_MULTIPLE_KEY_NEXT(p, bdbdata, retkey,
+ retklen, retdata, retdlen);
+ } else {
+ DB_MULTIPLE_RECNO_NEXT(p, bdbdata, recNum,
+ retdata, retdlen);
+ }
+
+ if (p == NULL) {
+ break;
+ }
+ if (type == 'c') {
+ printf("c %.*s %.*s\n", (int)retklen, retkey,
+ (int)retdlen, retdata);
+ } else {
+ printf("d %.*s\n", (int)retdlen, retdata);
+ }
+ } /* end of for (DB_MULTIPLE_INIT....) */
+ } /* end of for (;;) */
+
+ /* free the buffer we created earlier */
+ free(bdbdata->data);
+
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Perform listOrDelete operation
+ * if dlt == true, delete data
+ * else list data
+ */
+
+void
+operation_listOrDelete(bool dlt) {
+ int bdbres = 0;
+ DBC *curList[3];
+ DBT bdbkey, bdbdata;
+ db_recno_t recno;
+ int curIndex = 0;
+
+ /* verify that only allowed parameters were passed. */
+ if (dlt) {
+ checkInvalidParam(zone, "z", "for delete operation");
+ checkInvalidParam(host, "h", "for delete operation");
+ checkInvalidOption(list_everything, true, "e",
+ "for delete operation");
+ checkInvalidOption(create_allowed, true, "n",
+ "for delete operation");
+ } else if (key != NULL || zone != NULL || host != NULL) {
+ checkInvalidParam(c_zone, "c",
+ "for list when k, z or h are specified");
+ checkInvalidParam(c_ip, "i",
+ "for list when k, z, or h are specified");
+ checkInvalidOption(list_everything, true, "e",
+ "for list when k, z, or h are specified");
+ checkInvalidOption(create_allowed, true, "n",
+ "for list operation");
+ } else if (c_ip != NULL || c_zone != NULL) {
+ checkInvalidOption(list_everything, true, "e",
+ "for list when c or i are specified");
+ checkInvalidOption(create_allowed, true, "n",
+ "for list operation");
+ }
+
+ memset(&bdbkey, 0, sizeof(bdbkey));
+ memset(&bdbdata, 0, sizeof(bdbdata));
+
+ /* Dump database in "dlzbdb" bulk format */
+ if (list_everything) {
+ if (bulk_write('c', db.client, db.cursor, &bdbkey, &bdbdata) !=
+ ISC_R_SUCCESS)
+ {
+ return;
+ }
+ memset(&bdbkey, 0, sizeof(bdbkey));
+ memset(&bdbdata, 0, sizeof(bdbdata));
+ bulk_write('d', db.data, db.cursor2, &bdbkey, &bdbdata);
+ return;
+ } /* end if (list_everything) */
+
+ /* set NULL the 2nd and 3rd positions in curList. */
+ /* that way later when add cursors to the join list */
+ /* it is already null terminated. */
+ curList[1] = curList[2] = NULL;
+
+ if (key != NULL) {
+ /* make sure other parameters weren't */
+ checkInvalidParam(zone, "z", "when k is specified");
+ checkInvalidParam(host, "h", "when k is specified");
+
+ recno = key_val;
+ bdbkey.data = &recno;
+ bdbkey.size = sizeof(recno);
+
+ if (dlt) {
+ bdbres = db.data->del(db.data, NULL, &bdbkey, 0);
+ } else {
+ bdbdata.flags = DB_DBT_REALLOC;
+ bdbres = db.data->get(db.data, NULL, &bdbkey, &bdbdata,
+ 0);
+
+ if (bdbres == 0) {
+ printf("KEY | DATA\n");
+ printf("%lu | %.*s\n", *(u_long *)bdbkey.data,
+ (int)bdbdata.size, (char *)bdbdata.data);
+ }
+ } /* closes else of if (dlt == true) */
+ if (bdbres == DB_NOTFOUND) {
+ printf("Key not found in database");
+ }
+ } /* closes if (key != NULL) */
+
+ /* if zone is passed */
+ if (zone != NULL) {
+ /* create a cursor and make sure it worked */
+ bdbres = db.zone->cursor(db.zone, NULL, &db.cursor2, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ return;
+ }
+
+ bdbkey.data = zone;
+ bdbkey.size = strlen(zone);
+ bdbres = db.cursor2->c_get(db.cursor2, &bdbkey, &bdbdata,
+ DB_SET);
+ if (bdbres != 0) {
+ if (bdbres != DB_NOTFOUND) {
+ fprintf(stderr,
+ "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ } else {
+ printf("Zone not found in database");
+ }
+ return;
+ }
+
+ /* add cursor to cursor list for later use in join */
+ curList[curIndex++] = db.cursor2;
+ }
+
+ /* if host is passed */
+ if (host != NULL) {
+ /* create a cursor and make sure it worked. */
+ bdbres = db.host->cursor(db.host, NULL, &db.cursor3, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ return;
+ }
+ bdbkey.data = host;
+ bdbkey.size = strlen(host);
+ bdbres = db.cursor3->c_get(db.cursor3, &bdbkey, &bdbdata,
+ DB_SET);
+ if (bdbres != 0) {
+ if (bdbres != DB_NOTFOUND) {
+ fprintf(stderr,
+ "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ } else {
+ printf("Host not found in database");
+ }
+ return;
+ }
+
+ /* add cursor to cursor list for later use in join */
+ curList[curIndex++] = db.cursor3;
+ }
+
+ if (zone != NULL || host != NULL) {
+ /* join any cursors */
+ bdbres = db.data->join(db.data, curList, &db.cursor4, 0);
+ if (bdbres != 0) {
+ fprintf(stderr, "Unexpected error. BDB Error: %s\n",
+ db_strerror(bdbres));
+ return;
+ }
+
+ memset(&bdbkey, 0, sizeof(bdbkey));
+ bdbkey.flags = DB_DBT_REALLOC;
+ memset(&bdbdata, 0, sizeof(bdbdata));
+ bdbdata.flags = DB_DBT_REALLOC;
+
+ /* print a header to explain the output */
+ printf("KEY | DATA\n");
+ /* loop and list all results. */
+ while (bdbres == 0) {
+ /* get data */
+ bdbres = db.cursor4->c_get(db.cursor4, &bdbkey,
+ &bdbdata, 0);
+ /* verify call had no errors */
+ if (bdbres != 0) {
+ break;
+ }
+ printf("%lu | %.*s\n", *(u_long *)bdbkey.data,
+ (int)bdbdata.size, (char *)bdbdata.data);
+ } /* closes while loop */
+ }
+
+ if (c_ip != NULL && c_zone == NULL) {
+ fprintf(stderr, "i may only be specified when c is also "
+ "specified\n");
+ quit(2);
+ }
+ /* if client_zone was passed */
+ if (c_zone != NULL) {
+ /* create a cursor and make sure it worked. */
+ if (dlt) {
+ /* open read-write cursor */
+ bdbres = db.client->cursor(db.client, NULL, &db.cursor,
+ DB_WRITECURSOR);
+ } else {
+ /* open read only cursor */
+ bdbres = db.client->cursor(db.client, NULL, &db.cursor,
+ 0);
+ /* print a header to explain the output */
+ printf("CLIENT_ZONE | CLIENT_IP\n");
+ }
+
+ bdbkey.data = c_zone;
+ bdbkey.size = strlen(c_zone);
+
+ if (c_ip != NULL) {
+ bdbdata.data = c_ip;
+ bdbdata.size = strlen(c_ip);
+ bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata,
+ DB_GET_BOTH);
+ if (bdbres == DB_NOTFOUND) {
+ printf("Client zone & IP not found in "
+ "database");
+ }
+ } else {
+ bdbdata.flags = DB_DBT_REALLOC;
+ bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata,
+ DB_SET);
+ if (bdbres == DB_NOTFOUND) {
+ printf("Client zone not found in database");
+ }
+ }
+
+ while (bdbres == 0) {
+ if (!dlt) {
+ printf("%.*s | %.*s\n", (int)bdbkey.size,
+ (char *)bdbkey.data, (int)bdbdata.size,
+ (char *)bdbdata.data);
+ } else {
+ /* delete record. */
+ bdbres = db.cursor->c_del(db.cursor, 0);
+ if (bdbres != 0) {
+ fprintf(stderr,
+ "Unexpected error. BDB Error: "
+ "%s\n",
+ db_strerror(bdbres));
+ break;
+ }
+ }
+ if (c_ip != NULL) {
+ break;
+ }
+ bdbres = db.cursor->c_get(db.cursor, &bdbkey, &bdbdata,
+ DB_NEXT_DUP);
+ if (bdbres != 0) {
+ break;
+ }
+ } /* end while loop */
+ }
+
+ if (bdbres != 0 && bdbres != DB_NOTFOUND) {
+ fprintf(stderr,
+ "Unexpected error during list operation "
+ "BDB error: %s",
+ db_strerror(bdbres));
+ }
+
+ if (bdbkey.flags == DB_DBT_REALLOC && bdbkey.data != NULL) {
+ free(bdbkey.data);
+ }
+ if (bdbdata.flags == DB_DBT_REALLOC && bdbdata.data != NULL) {
+ free(bdbdata.data);
+ }
+}
+
+int
+main(int argc, char **argv) {
+ int ch;
+ char *endp;
+
+ /* there has to be at least 2 args, some operations require more */
+ if (argc < 2) {
+ show_usage();
+ }
+
+ /* use the ISC commandline parser to get all the program arguments */
+ while ((ch = isc_commandline_parse(argc, argv,
+ "ldesna:f:k:z:h:c:i:")) != -1)
+ {
+ switch (ch) {
+ case 'n':
+ create_allowed = true;
+ break;
+ case 'l':
+ checkOp(operation);
+ operation = list;
+ break;
+ case 'd':
+ checkOp(operation);
+ operation = dele;
+ break;
+ case 'a':
+ checkOp(operation);
+ operation = add;
+ a_data = isc_commandline_argument;
+ break;
+ case 'f':
+ checkOp(operation);
+ operation = bulk;
+ bulk_file = isc_commandline_argument;
+ break;
+ case 's':
+ checkOp(operation);
+ operation = bulk;
+ break;
+ case 'k':
+ checkParam(key, "k");
+ key = isc_commandline_argument;
+ key_val = strtoul(key, &endp, 10);
+ if (*endp != '\0' || key_val < 1) {
+ fprintf(stderr, "Error converting key to "
+ "integer");
+ }
+ break;
+ case 'z':
+ checkParam(zone, "z");
+ zone = isc_commandline_argument;
+ break;
+ case 'h':
+ checkParam(host, "h");
+ host = isc_commandline_argument;
+ break;
+ case 'c':
+ checkParam(c_zone, "c");
+ c_zone = isc_commandline_argument;
+ break;
+ case 'i':
+ checkParam(c_ip, "i");
+ c_ip = isc_commandline_argument;
+ break;
+ case 'e':
+ checkOp(operation);
+ operation = list;
+ list_everything = true;
+ break;
+ case '?':
+ show_usage();
+ break;
+ default:
+ /* should never reach this point */
+ fprintf(stderr, "unexpected error parsing command "
+ "arguments\n");
+ quit(1);
+ break;
+ }
+ }
+
+ argc -= isc_commandline_index;
+ argv += isc_commandline_index;
+
+ /* argc & argv have been modified, so now only "extra" parameters are */
+ /* left in argc & argv. "Extra" parameters are any parameters that were
+ */
+ /* not passed using a command line flag. Exactly 2 args should be left.
+ */
+ /* The first should be the BDB environment path, the second should be
+ * the */
+ /* BDB database. The BDB database path can be either relative to the */
+ /* BDB environment path, or absolute. */
+ if (argc < 2) {
+ fprintf(stderr, "Both a Berkeley DB environment and file "
+ "must be specified");
+ quit(2);
+ } else if (argc > 2) {
+ fprintf(stderr, "Too many parameters. Check command line for "
+ "errors.");
+ quit(2);
+ }
+
+ /* get db_file to operate on */
+ db_envdir = argv[0];
+ db_file = argv[1];
+
+ if (openBDB() != ISC_R_SUCCESS) {
+ /* openBDB already prints error messages, don't do it here. */
+ bdb_cleanup();
+ quit(3);
+ }
+
+ switch (operation) {
+ case list:
+ operation_listOrDelete(false);
+ break;
+ case dele:
+ operation_listOrDelete(true);
+ break;
+ case add:
+ operation_add();
+ break;
+ case bulk:
+ operation_bulk();
+ break;
+ default:
+ fprintf(stderr, "\nNo operation was selected. "
+ "Select an operation (l d a f)");
+ quit(2);
+ break;
+ }
+
+ quit(0);
+}
+#endif /* ifdef DLZ_BDB */