xref: /minix/external/bsd/bind/dist/bin/tests/db_test.c (revision bb9622b5)
1 /*	$NetBSD: db_test.c,v 1.7 2014/12/10 04:37:53 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004, 2005, 2007-2009, 2011-2013  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2001  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id: db_test.c,v 1.70 2011/08/29 23:46:44 tbox Exp  */
21 
22 /*! \file
23  * \author
24  * Principal Author: Bob Halley
25  */
26 
27 #include <config.h>
28 
29 #include <stdlib.h>
30 
31 #include <isc/commandline.h>
32 #include <isc/log.h>
33 #include <isc/mem.h>
34 #include <isc/time.h>
35 #include <isc/string.h>
36 #include <isc/util.h>
37 
38 #include <dns/db.h>
39 #include <dns/dbiterator.h>
40 #include <dns/dbtable.h>
41 #include <dns/fixedname.h>
42 #include <dns/log.h>
43 #include <dns/rdataset.h>
44 #include <dns/rdatasetiter.h>
45 #include <dns/result.h>
46 
47 #define MAXHOLD			100
48 #define MAXVERSIONS		100
49 
50 typedef struct dbinfo {
51 	dns_db_t *		db;
52 	dns_dbversion_t *	version;
53 	dns_dbversion_t *	wversion;
54 	dns_dbversion_t *	rversions[MAXVERSIONS];
55 	int			rcount;
56 	dns_dbnode_t *		hold_nodes[MAXHOLD];
57 	int			hold_count;
58 	dns_dbiterator_t *	dbiterator;
59 	dns_dbversion_t *	iversion;
60 	int			pause_every;
61 	isc_boolean_t		ascending;
62 	ISC_LINK(struct dbinfo)	link;
63 } dbinfo;
64 
65 static isc_mem_t *		mctx = NULL;
66 static char			dbtype[128];
67 static dns_dbtable_t *		dbtable;
68 static ISC_LIST(dbinfo)		dbs;
69 static dbinfo *			cache_dbi = NULL;
70 static int			pause_every = 0;
71 static isc_boolean_t		ascending = ISC_TRUE;
72 
73 static void
74 print_result(const char *message, isc_result_t result) {
75 
76 	if (message == NULL)
77 		message = "";
78 	printf("%s%sresult %08x: %s\n", message, (*message == '\0') ? "" : " ",
79 	       result, isc_result_totext(result));
80 }
81 
82 static void
83 print_rdataset(dns_name_t *name, dns_rdataset_t *rdataset) {
84 	isc_buffer_t text;
85 	char t[1000];
86 	isc_result_t result;
87 	isc_region_t r;
88 
89 	isc_buffer_init(&text, t, sizeof(t));
90 	result = dns_rdataset_totext(rdataset, name, ISC_FALSE, ISC_FALSE,
91 				     &text);
92 	isc_buffer_usedregion(&text, &r);
93 	if (result == ISC_R_SUCCESS)
94 		printf("%.*s", (int)r.length, (char *)r.base);
95 	else
96 		print_result("", result);
97 }
98 
99 static void
100 print_rdatasets(dns_name_t *name, dns_rdatasetiter_t *rdsiter) {
101 	isc_result_t result;
102 	dns_rdataset_t rdataset;
103 
104 	dns_rdataset_init(&rdataset);
105 	result = dns_rdatasetiter_first(rdsiter);
106 	while (result == ISC_R_SUCCESS) {
107 		dns_rdatasetiter_current(rdsiter, &rdataset);
108 		print_rdataset(name, &rdataset);
109 		dns_rdataset_disassociate(&rdataset);
110 		result = dns_rdatasetiter_next(rdsiter);
111 	}
112 	if (result != ISC_R_NOMORE)
113 		print_result("", result);
114 }
115 
116 static dbinfo *
117 select_db(char *origintext) {
118 	dns_fixedname_t forigin;
119 	dns_name_t *origin;
120 	isc_buffer_t source;
121 	size_t len;
122 	dbinfo *dbi;
123 	isc_result_t result;
124 
125 	if (strcasecmp(origintext, "cache") == 0) {
126 		if (cache_dbi == NULL)
127 			printf("the cache does not exist\n");
128 		return (cache_dbi);
129 	}
130 	len = strlen(origintext);
131 	isc_buffer_init(&source, origintext, len);
132 	isc_buffer_add(&source, len);
133 	dns_fixedname_init(&forigin);
134 	origin = dns_fixedname_name(&forigin);
135 	result = dns_name_fromtext(origin, &source, dns_rootname, 0, NULL);
136 	if (result != ISC_R_SUCCESS) {
137 		print_result("bad name", result);
138 		return (NULL);
139 	}
140 
141 	for (dbi = ISC_LIST_HEAD(dbs);
142 	     dbi != NULL;
143 	     dbi = ISC_LIST_NEXT(dbi, link)) {
144 		if (dns_name_compare(dns_db_origin(dbi->db), origin) == 0)
145 			break;
146 	}
147 
148 	return (dbi);
149 }
150 
151 static void
152 list(dbinfo *dbi, char *seektext) {
153 	dns_fixedname_t fname;
154 	dns_name_t *name;
155 	dns_dbnode_t *node;
156 	dns_rdatasetiter_t *rdsiter;
157 	isc_result_t result;
158 	int i;
159 	size_t len;
160 	dns_fixedname_t fseekname;
161 	dns_name_t *seekname;
162 	isc_buffer_t source;
163 
164 	dns_fixedname_init(&fname);
165 	name = dns_fixedname_name(&fname);
166 
167 	if (dbi->dbiterator == NULL) {
168 		INSIST(dbi->iversion == NULL);
169 		if (dns_db_iszone(dbi->db)) {
170 			if (dbi->version != NULL)
171 				dns_db_attachversion(dbi->db, dbi->version,
172 						     &dbi->iversion);
173 			else
174 				dns_db_currentversion(dbi->db, &dbi->iversion);
175 		}
176 
177 		result = dns_db_createiterator(dbi->db, 0, &dbi->dbiterator);
178 		if (result == ISC_R_SUCCESS) {
179 			if (seektext != NULL) {
180 				len = strlen(seektext);
181 				isc_buffer_init(&source, seektext, len);
182 				isc_buffer_add(&source, len);
183 				dns_fixedname_init(&fseekname);
184 				seekname = dns_fixedname_name(&fseekname);
185 				result = dns_name_fromtext(seekname, &source,
186 							   dns_db_origin(
187 								 dbi->db),
188 							   0, NULL);
189 				if (result == ISC_R_SUCCESS)
190 					result = dns_dbiterator_seek(
191 							     dbi->dbiterator,
192 							     seekname);
193 			} else if (dbi->ascending)
194 				result = dns_dbiterator_first(dbi->dbiterator);
195 			else
196 				result = dns_dbiterator_last(dbi->dbiterator);
197 		}
198 	} else
199 		result = ISC_R_SUCCESS;
200 
201 	node = NULL;
202 	rdsiter = NULL;
203 	i = 0;
204 	while (result == ISC_R_SUCCESS) {
205 		result = dns_dbiterator_current(dbi->dbiterator, &node, name);
206 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
207 			break;
208 		result = dns_db_allrdatasets(dbi->db, node, dbi->iversion, 0,
209 					     &rdsiter);
210 		if (result != ISC_R_SUCCESS) {
211 			dns_db_detachnode(dbi->db, &node);
212 			break;
213 		}
214 		print_rdatasets(name, rdsiter);
215 		dns_rdatasetiter_destroy(&rdsiter);
216 		dns_db_detachnode(dbi->db, &node);
217 		if (dbi->ascending)
218 			result = dns_dbiterator_next(dbi->dbiterator);
219 		else
220 			result = dns_dbiterator_prev(dbi->dbiterator);
221 		i++;
222 		if (result == ISC_R_SUCCESS && i == dbi->pause_every) {
223 			printf("[more...]\n");
224 			result = dns_dbiterator_pause(dbi->dbiterator);
225 			if (result == ISC_R_SUCCESS)
226 				return;
227 		}
228 	}
229 	if (result != ISC_R_NOMORE)
230 		print_result("", result);
231 
232 	dns_dbiterator_destroy(&dbi->dbiterator);
233 	if (dbi->iversion != NULL)
234 		dns_db_closeversion(dbi->db, &dbi->iversion, ISC_FALSE);
235 }
236 
237 static isc_result_t
238 load(const char *filename, const char *origintext, isc_boolean_t cache) {
239 	dns_fixedname_t forigin;
240 	dns_name_t *origin;
241 	isc_result_t result;
242 	isc_buffer_t source;
243 	size_t len;
244 	dbinfo *dbi;
245 	unsigned int i;
246 
247 	dbi = isc_mem_get(mctx, sizeof(*dbi));
248 	if (dbi == NULL)
249 		return (ISC_R_NOMEMORY);
250 
251 	dbi->db = NULL;
252 	dbi->version = NULL;
253 	dbi->wversion = NULL;
254 	for (i = 0; i < MAXVERSIONS; i++)
255 		dbi->rversions[i] = NULL;
256 	dbi->hold_count = 0;
257 	for (i = 0; i < MAXHOLD; i++)
258 		dbi->hold_nodes[i] = NULL;
259 	dbi->dbiterator = NULL;
260 	dbi->iversion = NULL;
261 	dbi->pause_every = pause_every;
262 	dbi->ascending = ascending;
263 	ISC_LINK_INIT(dbi, link);
264 
265 	len = strlen(origintext);
266 	isc_buffer_constinit(&source, origintext, len);
267 	isc_buffer_add(&source, len);
268 	dns_fixedname_init(&forigin);
269 	origin = dns_fixedname_name(&forigin);
270 	result = dns_name_fromtext(origin, &source, dns_rootname, 0, NULL);
271 	if (result != ISC_R_SUCCESS)
272 		return (result);
273 
274 	result = dns_db_create(mctx, dbtype, origin,
275 			       cache ? dns_dbtype_cache : dns_dbtype_zone,
276 			       dns_rdataclass_in,
277 			       0, NULL, &dbi->db);
278 	if (result != ISC_R_SUCCESS) {
279 		isc_mem_put(mctx, dbi, sizeof(*dbi));
280 		return (result);
281 	}
282 
283 	printf("loading %s (%s)\n", filename, origintext);
284 	result = dns_db_load(dbi->db, filename);
285 	if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) {
286 		dns_db_detach(&dbi->db);
287 		isc_mem_put(mctx, dbi, sizeof(*dbi));
288 		return (result);
289 	}
290 	printf("loaded\n");
291 
292 	if (cache) {
293 		INSIST(cache_dbi == NULL);
294 		dns_dbtable_adddefault(dbtable, dbi->db);
295 		cache_dbi = dbi;
296 	} else {
297 		if (dns_dbtable_add(dbtable, dbi->db) != ISC_R_SUCCESS) {
298 			dns_db_detach(&dbi->db);
299 			isc_mem_put(mctx, dbi, sizeof(*dbi));
300 			return (result);
301 		}
302 	}
303 	ISC_LIST_APPEND(dbs, dbi, link);
304 
305 	return (ISC_R_SUCCESS);
306 }
307 
308 static void
309 unload_all(void) {
310 	dbinfo *dbi, *dbi_next;
311 
312 	for (dbi = ISC_LIST_HEAD(dbs); dbi != NULL; dbi = dbi_next) {
313 		dbi_next = ISC_LIST_NEXT(dbi, link);
314 		if (dns_db_iszone(dbi->db))
315 			dns_dbtable_remove(dbtable, dbi->db);
316 		else {
317 			INSIST(dbi == cache_dbi);
318 			dns_dbtable_removedefault(dbtable);
319 			cache_dbi = NULL;
320 		}
321 		dns_db_detach(&dbi->db);
322 		ISC_LIST_UNLINK(dbs, dbi, link);
323 		isc_mem_put(mctx, dbi, sizeof(*dbi));
324 	}
325 }
326 
327 #define DBI_CHECK(dbi) \
328 if ((dbi) == NULL) { \
329 	printf("You must first select a database with !DB\n"); \
330 	continue; \
331 }
332 
333 int
334 main(int argc, char *argv[]) {
335 	dns_db_t *db;
336 	dns_dbnode_t *node;
337 	isc_result_t result;
338 	dns_name_t name;
339 	dns_offsets_t offsets;
340 	size_t len;
341 	isc_buffer_t source, target;
342 	char s[1000];
343 	char b[255];
344 	dns_rdataset_t rdataset, sigrdataset;
345 	int ch;
346 	dns_rdatatype_t type = 1;
347 	isc_boolean_t printnode = ISC_FALSE;
348 	isc_boolean_t addmode = ISC_FALSE;
349 	isc_boolean_t delmode = ISC_FALSE;
350 	isc_boolean_t holdmode = ISC_FALSE;
351 	isc_boolean_t verbose = ISC_FALSE;
352 	isc_boolean_t done = ISC_FALSE;
353 	isc_boolean_t quiet = ISC_FALSE;
354 	isc_boolean_t time_lookups = ISC_FALSE;
355 	isc_boolean_t found_as;
356 	isc_boolean_t find_zonecut = ISC_FALSE;
357 	isc_boolean_t noexact_zonecut = ISC_FALSE;
358 	int i, v;
359 	dns_rdatasetiter_t *rdsiter;
360 	char t1[256];
361 	char t2[256];
362 	isc_buffer_t tb1, tb2;
363 	isc_region_t r1, r2;
364 	dns_fixedname_t foundname;
365 	dns_name_t *fname;
366 	unsigned int options = 0, zcoptions;
367 	isc_time_t start, finish;
368 	char *origintext;
369 	dbinfo *dbi;
370 	dns_dbversion_t *version;
371 	dns_name_t *origin;
372 	size_t memory_quota = 0;
373 	dns_trust_t trust = 0;
374 	unsigned int addopts;
375 	isc_log_t *lctx = NULL;
376 	size_t n;
377 
378 	dns_result_register();
379 
380 	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
381 	RUNTIME_CHECK(dns_dbtable_create(mctx, dns_rdataclass_in, &dbtable) ==
382 		      ISC_R_SUCCESS);
383 
384 
385 
386 	strcpy(dbtype, "rbt");
387 	while ((ch = isc_commandline_parse(argc, argv, "c:d:t:z:P:Q:glpqvT"))
388 	       != -1) {
389 		switch (ch) {
390 		case 'c':
391 			result = load(isc_commandline_argument, ".", ISC_TRUE);
392 			if (result != ISC_R_SUCCESS)
393 				printf("cache load(%s) %08x: %s\n",
394 				       isc_commandline_argument, result,
395 				       isc_result_totext(result));
396 			break;
397 		case 'd':
398 			n = strlcpy(dbtype, isc_commandline_argument,
399 				    sizeof(dbtype));
400 			if (n >= sizeof(dbtype)) {
401 				fprintf(stderr, "bad db type '%s'\n",
402 					isc_commandline_argument);
403 				exit(1);
404 			}
405 			break;
406 		case 'g':
407 			options |= (DNS_DBFIND_GLUEOK|DNS_DBFIND_VALIDATEGLUE);
408 			break;
409 		case 'l':
410 			RUNTIME_CHECK(isc_log_create(mctx, &lctx,
411 						     NULL) == ISC_R_SUCCESS);
412 			isc_log_setcontext(lctx);
413 			dns_log_init(lctx);
414 			dns_log_setcontext(lctx);
415 			break;
416 		case 'q':
417 			quiet = ISC_TRUE;
418 			verbose = ISC_FALSE;
419 			break;
420 		case 'p':
421 			printnode = ISC_TRUE;
422 			break;
423 		case 'P':
424 			pause_every = atoi(isc_commandline_argument);
425 			break;
426 		case 'Q':
427 			memory_quota = atoi(isc_commandline_argument);
428 			isc_mem_setquota(mctx, memory_quota);
429 			break;
430 		case 't':
431 			type = atoi(isc_commandline_argument);
432 			break;
433 		case 'T':
434 			time_lookups = ISC_TRUE;
435 			break;
436 		case 'v':
437 			verbose = ISC_TRUE;
438 			break;
439 		case 'z':
440 			origintext = strrchr(isc_commandline_argument, '/');
441 			if (origintext == NULL)
442 				origintext = isc_commandline_argument;
443 			else
444 				origintext++;	/* Skip '/'. */
445 			result = load(isc_commandline_argument, origintext,
446 				      ISC_FALSE);
447 			if (result != ISC_R_SUCCESS)
448 				printf("zone load(%s) %08x: %s\n",
449 				       isc_commandline_argument, result,
450 				       isc_result_totext(result));
451 			break;
452 		}
453 	}
454 
455 	argc -= isc_commandline_index;
456 	argv += isc_commandline_index;
457 	POST(argv);
458 
459 	if (argc != 0)
460 		printf("ignoring trailing arguments\n");
461 
462 	/*
463 	 * Some final initialization...
464 	 */
465 	dns_fixedname_init(&foundname);
466 	fname = dns_fixedname_name(&foundname);
467 	dbi = NULL;
468 	origin = dns_rootname;
469 	version = NULL;
470 
471 	if (time_lookups) {
472 		TIME_NOW(&start);
473 	}
474 
475 	while (!done) {
476 		if (!quiet)
477 			printf("\n");
478 		if (fgets(s, sizeof(s), stdin) == NULL) {
479 			done = ISC_TRUE;
480 			continue;
481 		}
482 		len = strlen(s);
483 		if (len > 0U && s[len - 1] == '\n') {
484 			s[len - 1] = '\0';
485 			len--;
486 		}
487 		if (verbose && dbi != NULL) {
488 			if (dbi->wversion != NULL)
489 				printf("future version (%p)\n", dbi->wversion);
490 			for (i = 0; i < dbi->rcount; i++)
491 				if (dbi->rversions[i] != NULL)
492 					printf("open version %d (%p)\n", i,
493 					       dbi->rversions[i]);
494 		}
495 		dns_name_init(&name, offsets);
496 		if (strcmp(s, "!R") == 0) {
497 			DBI_CHECK(dbi);
498 			if (dbi->rcount == MAXVERSIONS) {
499 				printf("too many open versions\n");
500 				continue;
501 			}
502 			dns_db_currentversion(dbi->db,
503 					      &dbi->rversions[dbi->rcount]);
504 			printf("opened version %d\n", dbi->rcount);
505 			dbi->version = dbi->rversions[dbi->rcount];
506 			version = dbi->version;
507 			dbi->rcount++;
508 			continue;
509 		} else if (strcmp(s, "!W") == 0) {
510 			DBI_CHECK(dbi);
511 			if (dbi->wversion != NULL) {
512 				printf("using existing future version\n");
513 				dbi->version = dbi->wversion;
514 				version = dbi->version;
515 				continue;
516 			}
517 			result = dns_db_newversion(dbi->db, &dbi->wversion);
518 			if (result != ISC_R_SUCCESS)
519 				print_result("", result);
520 			else
521 				printf("newversion\n");
522 			dbi->version = dbi->wversion;
523 			version = dbi->version;
524 			continue;
525 		} else if (strcmp(s, "!C") == 0) {
526 			DBI_CHECK(dbi);
527 			addmode = ISC_FALSE;
528 			delmode = ISC_FALSE;
529 			if (dbi->version == NULL)
530 				continue;
531 			if (dbi->version == dbi->wversion) {
532 				printf("closing future version\n");
533 				dbi->wversion = NULL;
534 			} else {
535 				for (i = 0; i < dbi->rcount; i++) {
536 					if (dbi->version ==
537 					    dbi->rversions[i]) {
538 						dbi->rversions[i] = NULL;
539 					  printf("closing open version %d\n",
540 						 i);
541 						break;
542 					}
543 				}
544 			}
545 			dns_db_closeversion(dbi->db, &dbi->version, ISC_TRUE);
546 			version = NULL;
547 			continue;
548 		} else if (strcmp(s, "!X") == 0) {
549 			DBI_CHECK(dbi);
550 			addmode = ISC_FALSE;
551 			delmode = ISC_FALSE;
552 			if (dbi->version == NULL)
553 				continue;
554 			if (dbi->version == dbi->wversion) {
555 				printf("aborting future version\n");
556 				dbi->wversion = NULL;
557 			} else {
558 				for (i = 0; i < dbi->rcount; i++) {
559 					if (dbi->version ==
560 					    dbi->rversions[i]) {
561 						dbi->rversions[i] = NULL;
562 					  printf("closing open version %d\n",
563 						 i);
564 						break;
565 					}
566 				}
567 			}
568 			dns_db_closeversion(dbi->db, &dbi->version, ISC_FALSE);
569 			version = NULL;
570 			continue;
571 		} else if (strcmp(s, "!A") == 0) {
572 			DBI_CHECK(dbi);
573 			delmode = ISC_FALSE;
574 			if (addmode)
575 				addmode = ISC_FALSE;
576 			else
577 				addmode = ISC_TRUE;
578 			printf("addmode = %s\n", addmode ? "TRUE" : "FALSE");
579 			continue;
580 		} else if (strcmp(s, "!D") == 0) {
581 			DBI_CHECK(dbi);
582 			addmode = ISC_FALSE;
583 			if (delmode)
584 				delmode = ISC_FALSE;
585 			else
586 				delmode = ISC_TRUE;
587 			printf("delmode = %s\n", delmode ? "TRUE" : "FALSE");
588 			continue;
589 		} else if (strcmp(s, "!H") == 0) {
590 			DBI_CHECK(dbi);
591 			if (holdmode)
592 				holdmode = ISC_FALSE;
593 			else
594 				holdmode = ISC_TRUE;
595 			printf("holdmode = %s\n", holdmode ? "TRUE" : "FALSE");
596 			continue;
597 		} else if (strcmp(s, "!HR") == 0) {
598 			DBI_CHECK(dbi);
599 			for (i = 0; i < dbi->hold_count; i++)
600 				dns_db_detachnode(dbi->db,
601 						  &dbi->hold_nodes[i]);
602 			dbi->hold_count = 0;
603 			holdmode = ISC_FALSE;
604 			printf("held nodes have been detached\n");
605 			continue;
606 		} else if (strcmp(s, "!VC") == 0) {
607 			DBI_CHECK(dbi);
608 			printf("switching to current version\n");
609 			dbi->version = NULL;
610 			version = NULL;
611 			continue;
612 		} else if (strstr(s, "!V") == s) {
613 			DBI_CHECK(dbi);
614 			v = atoi(&s[2]);
615 			if (v >= dbi->rcount || v < 0) {
616 				printf("unknown open version %d\n", v);
617 				continue;
618 			}
619 			if (dbi->rversions[v] == NULL) {
620 				printf("version %d is not open\n", v);
621 				continue;
622 			}
623 			printf("switching to open version %d\n", v);
624 			dbi->version = dbi->rversions[v];
625 			version = dbi->version;
626 			continue;
627 		} else if (strstr(s, "!TR") == s) {
628 			trust = (unsigned int)atoi(&s[3]);
629 			printf("trust level is now %u\n", (unsigned int)trust);
630 			continue;
631 		} else if (strstr(s, "!T") == s) {
632 			type = (unsigned int)atoi(&s[2]);
633 			printf("now searching for type %u\n", type);
634 			continue;
635 		} else if (strcmp(s, "!G") == 0) {
636 			if ((options & DNS_DBFIND_GLUEOK) != 0)
637 				options &= ~DNS_DBFIND_GLUEOK;
638 			else
639 				options |= DNS_DBFIND_GLUEOK;
640 			printf("glue ok = %s\n",
641 			       ((options & DNS_DBFIND_GLUEOK) != 0) ?
642 			       "TRUE" : "FALSE");
643 			continue;
644 		} else if (strcmp(s, "!GV") == 0) {
645 			if ((options & DNS_DBFIND_VALIDATEGLUE) != 0)
646 				options &= ~DNS_DBFIND_VALIDATEGLUE;
647 			else
648 				options |= DNS_DBFIND_VALIDATEGLUE;
649 			printf("validate glue = %s\n",
650 			       ((options & DNS_DBFIND_VALIDATEGLUE) != 0) ?
651 			       "TRUE" : "FALSE");
652 			continue;
653 		} else if (strcmp(s, "!WC") == 0) {
654 			if ((options & DNS_DBFIND_NOWILD) != 0)
655 				options &= ~DNS_DBFIND_NOWILD;
656 			else
657 				options |= DNS_DBFIND_NOWILD;
658 			printf("wildcard matching = %s\n",
659 			       ((options & DNS_DBFIND_NOWILD) == 0) ?
660 			       "TRUE" : "FALSE");
661 			continue;
662 		} else if (strstr(s, "!LS ") == s) {
663 			DBI_CHECK(dbi);
664 			list(dbi, &s[4]);
665 			continue;
666 		} else if (strcmp(s, "!LS") == 0) {
667 			DBI_CHECK(dbi);
668 			list(dbi, NULL);
669 			continue;
670 		} else if (strstr(s, "!DU ") == s) {
671 			DBI_CHECK(dbi);
672 			result = dns_db_dump(dbi->db, dbi->version, s+4);
673 			if (result != ISC_R_SUCCESS) {
674 				printf("\n");
675 				print_result("", result);
676 			}
677 			continue;
678 		} else if (strcmp(s, "!PN") == 0) {
679 			if (printnode)
680 				printnode = ISC_FALSE;
681 			else
682 				printnode = ISC_TRUE;
683 			printf("printnode = %s\n",
684 			       printnode ? "TRUE" : "FALSE");
685 			continue;
686 		} else if (strstr(s, "!P") == s) {
687 			DBI_CHECK(dbi);
688 			v = atoi(&s[2]);
689 			dbi->pause_every = v;
690 			continue;
691 		} else if (strcmp(s, "!+") == 0) {
692 			DBI_CHECK(dbi);
693 			dbi->ascending = ISC_TRUE;
694 			continue;
695 		} else if (strcmp(s, "!-") == 0) {
696 			DBI_CHECK(dbi);
697 			dbi->ascending = ISC_FALSE;
698 			continue;
699 		} else if (strcmp(s, "!DB") == 0) {
700 			dbi = NULL;
701 			origin = dns_rootname;
702 			version = NULL;
703 			printf("now searching all databases\n");
704 			continue;
705 		} else if (strncmp(s, "!DB ", 4) == 0) {
706 			dbi = select_db(s+4);
707 			if (dbi != NULL) {
708 				db = dbi->db;
709 				origin = dns_db_origin(dbi->db);
710 				version = dbi->version;
711 				addmode = ISC_FALSE;
712 				delmode = ISC_FALSE;
713 				holdmode = ISC_FALSE;
714 			} else {
715 				db = NULL;
716 				version = NULL;
717 				origin = dns_rootname;
718 				printf("database not found; "
719 				       "now searching all databases\n");
720 			}
721 			continue;
722 		} else if (strcmp(s, "!ZC") == 0) {
723 			if (find_zonecut)
724 				find_zonecut = ISC_FALSE;
725 			else
726 				find_zonecut = ISC_TRUE;
727 			printf("find_zonecut = %s\n",
728 			       find_zonecut ? "TRUE" : "FALSE");
729 			continue;
730 		} else if (strcmp(s, "!NZ") == 0) {
731 			if (noexact_zonecut)
732 				noexact_zonecut = ISC_FALSE;
733 			else
734 				noexact_zonecut = ISC_TRUE;
735 			printf("noexact_zonecut = %s\n",
736 			       noexact_zonecut ? "TRUE" : "FALSE");
737 			continue;
738 		}
739 
740 		isc_buffer_init(&source, s, len);
741 		isc_buffer_add(&source, len);
742 		isc_buffer_init(&target, b, sizeof(b));
743 		result = dns_name_fromtext(&name, &source, origin, 0, &target);
744 		if (result != ISC_R_SUCCESS) {
745 			print_result("bad name: ", result);
746 			continue;
747 		}
748 
749 		if (dbi == NULL) {
750 			zcoptions = 0;
751 			if (noexact_zonecut)
752 				zcoptions |= DNS_DBTABLEFIND_NOEXACT;
753 			db = NULL;
754 			result = dns_dbtable_find(dbtable, &name, zcoptions,
755 						  &db);
756 			if (result != ISC_R_SUCCESS &&
757 			    result != DNS_R_PARTIALMATCH) {
758 				if (!quiet) {
759 					printf("\n");
760 					print_result("", result);
761 				}
762 				continue;
763 			}
764 			isc_buffer_init(&tb1, t1, sizeof(t1));
765 			result = dns_name_totext(dns_db_origin(db), ISC_FALSE,
766 						 &tb1);
767 			if (result != ISC_R_SUCCESS) {
768 				printf("\n");
769 				print_result("", result);
770 				dns_db_detach(&db);
771 				continue;
772 			}
773 			isc_buffer_usedregion(&tb1, &r1);
774 			printf("\ndatabase = %.*s (%s)\n",
775 			       (int)r1.length, r1.base,
776 			       (dns_db_iszone(db)) ? "zone" : "cache");
777 		}
778 		node = NULL;
779 		dns_rdataset_init(&rdataset);
780 		dns_rdataset_init(&sigrdataset);
781 
782 		if (find_zonecut && dns_db_iscache(db)) {
783 			zcoptions = options;
784 			if (noexact_zonecut)
785 				zcoptions |= DNS_DBFIND_NOEXACT;
786 			result = dns_db_findzonecut(db, &name, zcoptions,
787 						    0, &node, fname,
788 						    &rdataset, &sigrdataset);
789 		} else {
790 			result = dns_db_find(db, &name, version, type,
791 					     options, 0, &node, fname,
792 					     &rdataset, &sigrdataset);
793 		}
794 
795 		if (!quiet) {
796 			if (dbi != NULL)
797 				printf("\n");
798 			print_result("", result);
799 		}
800 
801 		found_as = ISC_FALSE;
802 		switch (result) {
803 		case ISC_R_SUCCESS:
804 		case DNS_R_GLUE:
805 		case DNS_R_CNAME:
806 		case DNS_R_ZONECUT:
807 			break;
808 		case DNS_R_DNAME:
809 		case DNS_R_DELEGATION:
810 			found_as = ISC_TRUE;
811 			break;
812 		case DNS_R_NXRRSET:
813 			if (dns_rdataset_isassociated(&rdataset))
814 				break;
815 			if (dbi != NULL) {
816 				if (holdmode) {
817 					RUNTIME_CHECK(dbi->hold_count <
818 						      MAXHOLD);
819 					dbi->hold_nodes[dbi->hold_count++] =
820 						node;
821 					node = NULL;
822 				} else
823 					dns_db_detachnode(db, &node);
824 			} else {
825 				dns_db_detachnode(db, &node);
826 				dns_db_detach(&db);
827 			}
828 			continue;
829 		case DNS_R_NXDOMAIN:
830 			if (dns_rdataset_isassociated(&rdataset))
831 				break;
832 			/* FALLTHROUGH */
833 		default:
834 			if (dbi == NULL)
835 				dns_db_detach(&db);
836 			if (quiet)
837 				print_result("", result);
838 			continue;
839 		}
840 		if (found_as && !quiet) {
841 			isc_buffer_init(&tb1, t1, sizeof(t1));
842 			isc_buffer_init(&tb2, t2, sizeof(t2));
843 			result = dns_name_totext(&name, ISC_FALSE, &tb1);
844 			if (result != ISC_R_SUCCESS) {
845 				print_result("", result);
846 				dns_db_detachnode(db, &node);
847 				if (dbi == NULL)
848 					dns_db_detach(&db);
849 				continue;
850 			}
851 			result = dns_name_totext(fname, ISC_FALSE, &tb2);
852 			if (result != ISC_R_SUCCESS) {
853 				print_result("", result);
854 				dns_db_detachnode(db, &node);
855 				if (dbi == NULL)
856 					dns_db_detach(&db);
857 				continue;
858 			}
859 			isc_buffer_usedregion(&tb1, &r1);
860 			isc_buffer_usedregion(&tb2, &r2);
861 			printf("found %.*s as %.*s\n",
862 			       (int)r1.length, r1.base,
863 			       (int)r2.length, r2.base);
864 		}
865 
866 		if (printnode)
867 			dns_db_printnode(db, node, stdout);
868 
869 		if (!found_as && type == dns_rdatatype_any) {
870 			rdsiter = NULL;
871 			result = dns_db_allrdatasets(db, node, version, 0,
872 						     &rdsiter);
873 			if (result == ISC_R_SUCCESS) {
874 				if (!quiet)
875 					print_rdatasets(fname, rdsiter);
876 				dns_rdatasetiter_destroy(&rdsiter);
877 			} else
878 				print_result("", result);
879 		} else {
880 			if (!quiet)
881 				print_rdataset(fname, &rdataset);
882 			if (dns_rdataset_isassociated(&sigrdataset)) {
883 				if (!quiet)
884 					print_rdataset(fname, &sigrdataset);
885 				dns_rdataset_disassociate(&sigrdataset);
886 			}
887 			if (dbi != NULL && addmode && !found_as) {
888 				rdataset.ttl++;
889 				rdataset.trust = trust;
890 				if (dns_db_iszone(db))
891 					addopts = DNS_DBADD_MERGE;
892 				else
893 					addopts = 0;
894 				result = dns_db_addrdataset(db, node, version,
895 							    0, &rdataset,
896 							    addopts, NULL);
897 				if (result != ISC_R_SUCCESS)
898 					print_result("", result);
899 				if (printnode)
900 					dns_db_printnode(db, node, stdout);
901 			} else if (dbi != NULL && delmode && !found_as) {
902 				result = dns_db_deleterdataset(db, node,
903 							       version, type,
904 							       0);
905 				if (result != ISC_R_SUCCESS)
906 					print_result("", result);
907 				if (printnode)
908 					dns_db_printnode(db, node, stdout);
909 			}
910 			dns_rdataset_disassociate(&rdataset);
911 		}
912 
913 		if (dbi != NULL) {
914 			if (holdmode) {
915 				RUNTIME_CHECK(dbi->hold_count < MAXHOLD);
916 				dbi->hold_nodes[dbi->hold_count++] = node;
917 				node = NULL;
918 			} else
919 				dns_db_detachnode(db, &node);
920 		} else {
921 			dns_db_detachnode(db, &node);
922 			dns_db_detach(&db);
923 		}
924 	}
925 
926 	if (time_lookups) {
927 		isc_uint64_t usec;
928 
929 		TIME_NOW(&finish);
930 
931 		usec = isc_time_microdiff(&finish, &start);
932 
933 		printf("elapsed time: %lu.%06lu seconds\n",
934 		       (unsigned long)(usec / 1000000),
935 		       (unsigned long)(usec % 1000000));
936 	}
937 
938 	unload_all();
939 
940 	dns_dbtable_detach(&dbtable);
941 
942 	if (lctx != NULL)
943 		isc_log_destroy(&lctx);
944 
945 	if (!quiet)
946 		isc_mem_stats(mctx, stdout);
947 
948 	return (0);
949 }
950