rbt_test.c revision 4997d113e1b0362e25f0a682bb7c7c7ef03b9440
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt/*
be755f4725e6579ffe725b3ead9ccfbd108f55ddTinderbox User * Copyright (C) 1999 Internet Software Consortium.
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt *
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * Permission to use, copy, modify, and distribute this software for any
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * purpose with or without fee is hereby granted, provided that the above
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * copyright notice and this permission notice appear in all copies.
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt *
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * SOFTWARE.
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt */
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt#include <config.h>
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt#include <stdlib.h>
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt#include <stdio.h>
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt#include <string.h>
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt#include <unistd.h>
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt#include <isc/boolean.h>
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt#include <dns/rbt.h>
3759f10fc543747668b1ca4b4671f35b0dea8445Francis Dupont#include <dns/fixedname.h>
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntchar *progname;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntisc_mem_t *mctx;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt#define DNSNAMELEN 255
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntstatic dns_name_t *
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntcreate_name(char *s) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt int length;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_result_t result;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_buffer_t source, target;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt static dns_name_t *name;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt if (s == NULL || *s == '\0') {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf("missing name argument\n");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt return (NULL);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt }
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt length = strlen(s);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_buffer_init(&source, s, length, ISC_BUFFERTYPE_TEXT);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_buffer_add(&source, length);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt /*
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * It isn't really necessary in this program to create individual
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * memory spaces for each name structure and its associate character
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * string. It is done here to provide a relatively easy way to test
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * the callback from dns_rbt_deletename that is supposed to free the
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * data associated with a node.
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt *
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * The buffer for the actual name will immediately follow the
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt * name structure.
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt */
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt name = isc_mem_get(mctx, sizeof(*name) + DNSNAMELEN);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt if (name == NULL) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf("out of memory!\n");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt return (NULL);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt }
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_name_init(name, NULL);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_buffer_init(&target, name + 1, DNSNAMELEN, ISC_BUFFERTYPE_BINARY);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt result = dns_name_fromtext(name, &source, dns_rootname,
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt ISC_FALSE, &target);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt if (result != DNS_R_SUCCESS) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf("dns_name_fromtext(%s) failed: %s\n",
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt s, dns_result_totext(result));
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt return (NULL);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt }
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
d2a50c9ba87a6c57cb310308dfe95fff2f2836e2Mark Andrews return (name);
d2a50c9ba87a6c57cb310308dfe95fff2f2836e2Mark Andrews}
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntstatic void
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntdelete_name(void *data, void *arg) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_name_t *name;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt (void)arg;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt name = data;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_mem_put(mctx, data, sizeof(dns_name_t) + DNSNAMELEN);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt}
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntstatic void
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntprint_name(dns_name_t *name) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_buffer_t target;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt char *buffer[256];
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_buffer_init(&target, buffer, sizeof(buffer), ISC_BUFFERTYPE_TEXT);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt /*
d2a50c9ba87a6c57cb310308dfe95fff2f2836e2Mark Andrews * ISC_FALSE means absolute names have the final dot added.
d2a50c9ba87a6c57cb310308dfe95fff2f2836e2Mark Andrews */
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_name_totext(name, ISC_FALSE, &target);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf("%.*s", (int)target.used, (char *)target.base);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt}
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntstatic void
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Huntdetail(dns_rbt_t *rbt, dns_name_t *name) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_name_t *foundname, *origin, *fullname;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_rbtnode_t *node1, *node2;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_rbtnodechain_t chain;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_result_t result;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt isc_boolean_t nodes_should_match = ISC_FALSE;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_rbtnodechain_init(&chain, mctx);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_fixedname_init(&fixedorigin);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_fixedname_init(&fixedfullname);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt dns_fixedname_init(&fixedfoundname);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt origin = dns_fixedname_name(&fixedorigin);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt fullname = dns_fixedname_name(&fixedfullname);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt foundname = dns_fixedname_name(&fixedfoundname);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt node1 = node2 = NULL;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf("checking chain information for ");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt print_name(name);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf("\n");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt result = dns_rbt_findnode(rbt, name, foundname, &node1, &chain,
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt ISC_TRUE, NULL, NULL);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt switch (result) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt case DNS_R_SUCCESS:
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf(" found exact.");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt nodes_should_match = ISC_TRUE;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt break;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt case DNS_R_PARTIALMATCH:
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf(" found parent.");
d2a50c9ba87a6c57cb310308dfe95fff2f2836e2Mark Andrews break;
d2a50c9ba87a6c57cb310308dfe95fff2f2836e2Mark Andrews case DNS_R_NOTFOUND:
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf(" name not found.");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt break;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt default:
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf(" unexpected result: %s\n", dns_result_totext(result));
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt return;
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt }
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt if (node1 != NULL && node1->data != NULL) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf(" data at node: ");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt print_name(node1->data);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt } else
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf(" no data at node.");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt if (result == DNS_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt printf("\n name from dns_rbt_findnode: ");
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt print_name(foundname);
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt }
84ee90b52d4fb443c796f4e1481f98d5a95b5614Evan Hunt
result = dns_rbtnodechain_current(&chain, foundname, origin, &node2);
if (result == DNS_R_SUCCESS) {
printf("\n name from dns_rbtnodechain_current: ");
/*
* If foundname is absolute, it includes the origin (which
* is intrinsically known here to be just ".").
*/
result = dns_name_concatenate(foundname,
dns_name_isabsolute(foundname) ?
NULL : origin,
fullname, NULL);
if (result == DNS_R_SUCCESS)
print_name(fullname);
else
printf("%s\n", dns_result_totext(result));
printf("\n (foundname = ");
print_name(foundname);
printf(", origin = ");
print_name(origin);
printf(")\n");
if (nodes_should_match && node1 != node2)
printf(" nodes returned from each function "
"DO NOT match!\n");
} else
printf("\n result from dns_rbtnodechain_current: %s\n",
dns_result_totext(result));
}
static void
iterate(dns_rbt_t *rbt, isc_boolean_t forward) {
dns_name_t foundname, *origin;
dns_rbtnodechain_t chain;
dns_fixedname_t fixedorigin;
dns_result_t result;
dns_result_t (*move)(dns_rbtnodechain_t *chain, dns_name_t *name,
dns_name_t *origin);
dns_rbtnodechain_init(&chain, mctx);
dns_name_init(&foundname, NULL);
dns_fixedname_init(&fixedorigin);
origin = dns_fixedname_name(&fixedorigin);
if (forward) {
printf("iterating forward\n" );
move = dns_rbtnodechain_next;
result = dns_rbtnodechain_first(&chain, rbt, &foundname,
origin);
} else {
printf("iterating backward\n" );
move = dns_rbtnodechain_prev;
result = dns_rbtnodechain_last(&chain, rbt, &foundname,
origin);
}
if (result != DNS_R_SUCCESS && result != DNS_R_NEWORIGIN)
printf("start not found!\n");
else {
while (1) {
if (result == DNS_R_NEWORIGIN) {
printf(" new origin: ");
print_name(origin);
printf("\n");
}
if (result == DNS_R_SUCCESS ||
result == DNS_R_NEWORIGIN) {
print_name(&foundname);
printf("\n");
} else {
if (result != DNS_R_NOMORE)
printf("UNEXEPCTED ITERATION ERROR: %s",
dns_result_totext(result));
break;
}
result = move(&chain, &foundname, origin);
}
}
}
#define CMDCHECK(s) (strncasecmp(command, (s), length) == 0)
#define PRINTERR(r) if (r != DNS_R_SUCCESS) \
printf("... %s\n", dns_result_totext(r));
void
main (int argc, char **argv) {
char *command, *arg, *whitespace, buffer[1024];
dns_name_t *name, *foundname;
dns_fixedname_t fixedname;
dns_rbt_t *rbt;
int length, ch;
isc_boolean_t show_final_mem = ISC_FALSE;
isc_result_t result;
void *data;
progname = strrchr(*argv, '/');
if (progname != NULL)
progname++;
else
progname = *argv;
while ((ch = getopt(argc, argv, "m")) != -1) {
switch (ch) {
case 'm':
show_final_mem = ISC_TRUE;
break;
}
}
argc -= optind;
argv += optind;
if (argc > 1) {
printf("Usage: %s [-m]\n", progname);
exit(1);
}
setbuf(stdout, NULL);
result = isc_mem_create(0, 0, &mctx);
if (result != ISC_R_SUCCESS) {
printf("isc_mem_create: %s: exiting\n",
dns_result_totext(result));
exit(1);
}
result = dns_rbt_create(mctx, delete_name, NULL, &rbt);
if (result != DNS_R_SUCCESS) {
printf("dns_rbt_create: %s: exiting\n",
dns_result_totext(result));
exit(1);
}
whitespace = " \t";
while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
length = strlen(buffer);
if (buffer[length - 1] != '\n') {
printf("line to long (%d max), ignored\n",
sizeof(buffer) - 2);
continue;
}
buffer[length - 1] = '\0';
command = buffer + strspn(buffer, whitespace);
if (*command == '#')
continue;
arg = strpbrk(command, whitespace);
if (arg != NULL) {
*arg++ = '\0';
arg += strspn(arg, whitespace);
}
length = strlen(command);
if (*command != '\0') {
if (CMDCHECK("add")) {
name = create_name(arg);
if (name != NULL) {
printf("adding name %s\n", arg);
result = dns_rbt_addname(rbt,
name, name);
PRINTERR(result);
}
} else if (CMDCHECK("delete")) {
name = create_name(arg);
if (name != NULL) {
printf("deleting name %s\n", arg);
result = dns_rbt_deletename(rbt, name,
ISC_FALSE);
PRINTERR(result);
delete_name(name, NULL);
}
} else if (CMDCHECK("nuke")) {
name = create_name(arg);
if (name != NULL) {
printf("deleting name %s\n", arg);
result = dns_rbt_deletename(rbt, name,
ISC_TRUE);
PRINTERR(result);
delete_name(name, NULL);
}
} else if (CMDCHECK("search")) {
name = create_name(arg);
if (name != NULL) {
printf("searching for name %s ... ",
arg);
dns_fixedname_init(&fixedname);
foundname =
dns_fixedname_name(&fixedname);
data = NULL;
result = dns_rbt_findname(rbt, name,
foundname,
&data);
switch (result) {
case DNS_R_SUCCESS:
printf("found exact: ");
print_name(data);
putchar('\n');
break;
case DNS_R_PARTIALMATCH:
printf("found parent: ");
print_name(data);
printf("\n\t(foundname: ");
print_name(foundname);
printf(")\n");
break;
case DNS_R_NOTFOUND:
printf("NOT FOUND!\n");
break;
case DNS_R_NOMEMORY:
printf("OUT OF MEMORY!\n");
break;
default:
printf("UNEXPECTED RESULT\n");
}
delete_name(name, NULL);
}
} else if (CMDCHECK("check")) {
/*
* Or "chain". I know, I know. Lame name.
* I was having a hard time thinking of a
* name (especially one that did not have
* a conflicting first letter with another
* command) that would differentiate this
* from the search command.
*
* But it is just a test program, eh?
*/
name = create_name(arg);
if (name != NULL) {
detail(rbt, name);
delete_name(name, NULL);
}
} else if (CMDCHECK("forward")) {
iterate(rbt, ISC_TRUE);
} else if (CMDCHECK("backward")) {
iterate(rbt, ISC_FALSE);
} else if (CMDCHECK("print")) {
if (arg == NULL || *arg == '\0')
dns_rbt_printall(rbt);
else
printf("usage: print\n");
} else if (CMDCHECK("quit")) {
if (arg == NULL || *arg == '\0')
break;
else
printf("usage: quit\n");
} else {
printf("a(dd) NAME, d(elete) NAME, "
"s(earch) NAME, p(rint), or q(uit)\n");
}
}
}
dns_rbt_destroy(&rbt);
if (show_final_mem)
isc_mem_stats(mctx, stderr);
exit(0);
}