xref: /minix/external/bsd/bind/dist/bin/tests/rbt_test.c (revision bb9622b5)
1 /*	$NetBSD: rbt_test.c,v 1.6 2014/12/10 04:37:53 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004, 2005, 2007, 2009, 2011, 2012, 2014  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: rbt_test.c,v 1.52 2011/08/28 23:46:41 tbox Exp  */
21 
22 #include <config.h>
23 
24 #include <stdlib.h>
25 
26 #include <isc/commandline.h>
27 #include <isc/mem.h>
28 #include <isc/string.h>
29 #include <isc/util.h>
30 
31 #include <dns/rbt.h>
32 #include <dns/fixedname.h>
33 #include <dns/result.h>
34 
35 char *progname;
36 isc_mem_t *mctx;
37 
38 #define DNSNAMELEN 255
39 
40 static dns_name_t *
41 create_name(char *s) {
42 	int length;
43 	isc_result_t result;
44 	isc_buffer_t source, target;
45 	static dns_name_t *name;
46 
47 	if (s == NULL || *s == '\0') {
48 		printf("missing name argument\n");
49 		return (NULL);
50 	}
51 
52 	length = strlen(s);
53 
54 	isc_buffer_init(&source, s, length);
55 	isc_buffer_add(&source, length);
56 
57 	/*
58 	 * It isn't really necessary in this program to create individual
59 	 * memory spaces for each name structure and its associated character
60 	 * string.  It is done here to provide a relatively easy way to test
61 	 * the callback from dns_rbt_deletename that is supposed to free the
62 	 * data associated with a node.
63 	 *
64 	 * The buffer for the actual name will immediately follow the
65 	 * name structure.
66 	 */
67 	name = isc_mem_get(mctx, sizeof(*name) + DNSNAMELEN);
68 	if (name == NULL) {
69 		printf("out of memory!\n");
70 		return (NULL);
71 	}
72 
73 	dns_name_init(name, NULL);
74 	isc_buffer_init(&target, name + 1, DNSNAMELEN);
75 
76 	result = dns_name_fromtext(name, &source, dns_rootname, 0, &target);
77 
78 	if (result != ISC_R_SUCCESS) {
79 		printf("dns_name_fromtext(%s) failed: %s\n",
80 		       s, dns_result_totext(result));
81 		return (NULL);
82 	}
83 
84 	return (name);
85 }
86 
87 static void
88 delete_name(void *data, void *arg) {
89 	dns_name_t *name;
90 
91 	UNUSED(arg);
92 	name = data;
93 	isc_mem_put(mctx, name, sizeof(*name) + DNSNAMELEN);
94 }
95 
96 static void
97 print_name(dns_name_t *name) {
98 	isc_buffer_t target;
99 	char buffer[1024];
100 
101 	isc_buffer_init(&target, buffer, sizeof(buffer));
102 
103 	/*
104 	 * ISC_FALSE means absolute names have the final dot added.
105 	 */
106 	dns_name_totext(name, ISC_FALSE, &target);
107 
108 	printf("%.*s", (int)target.used, (char *)target.base);
109 }
110 
111 static void
112 detail(dns_rbt_t *rbt, dns_name_t *name) {
113 	dns_name_t *foundname, *origin, *fullname;
114 	dns_fixedname_t fixedfoundname, fixedorigin, fixedfullname;
115 	dns_rbtnode_t *node1, *node2;
116 	dns_rbtnodechain_t chain;
117 	isc_result_t result;
118 	isc_boolean_t nodes_should_match = ISC_FALSE;
119 
120 	dns_rbtnodechain_init(&chain, mctx);
121 
122 	dns_fixedname_init(&fixedorigin);
123 	dns_fixedname_init(&fixedfullname);
124 	dns_fixedname_init(&fixedfoundname);
125 
126 	origin = dns_fixedname_name(&fixedorigin);
127 	fullname = dns_fixedname_name(&fixedfullname);
128 	foundname = dns_fixedname_name(&fixedfoundname);
129 
130 	node1 = node2 = NULL;
131 
132 	printf("checking chain information for ");
133 	print_name(name);
134 	printf("\n");
135 
136 	result = dns_rbt_findnode(rbt, name, foundname, &node1, &chain,
137 				  DNS_RBTFIND_EMPTYDATA, NULL, NULL);
138 
139 	switch (result) {
140 	case ISC_R_SUCCESS:
141 		printf("  found exact.");
142 		nodes_should_match = ISC_TRUE;
143 		break;
144 	case DNS_R_PARTIALMATCH:
145 		printf("  found parent.");
146 		break;
147 	case ISC_R_NOTFOUND:
148 		printf("  name not found.");
149 		break;
150 	default:
151 		printf("  unexpected result: %s\n", dns_result_totext(result));
152 		return;
153 	}
154 
155 	if (node1 != NULL && node1->data != NULL) {
156 		printf("  data at node: ");
157 		print_name(node1->data);
158 	} else
159 		printf("  no data at node.");
160 
161 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
162 		printf("\n  name from dns_rbt_findnode: ");
163 		print_name(foundname);
164 	}
165 
166 	result = dns_rbtnodechain_current(&chain, foundname, origin, &node2);
167 
168 	if (result == ISC_R_SUCCESS) {
169 		printf("\n  name from dns_rbtnodechain_current: ");
170 
171 		result = dns_name_concatenate(foundname, origin,
172 					      fullname, NULL);
173 		if (result == ISC_R_SUCCESS)
174 			print_name(fullname);
175 		else
176 			printf("%s\n", dns_result_totext(result));
177 		printf("\n      (foundname = ");
178 		print_name(foundname);
179 		printf(", origin = ");
180 		print_name(origin);
181 		printf(")\n");
182 		if (nodes_should_match && node1 != node2)
183 			printf("  nodes returned from each function "
184 			       "DO NOT match!\n");
185 
186 	} else
187 		printf("\n  result from dns_rbtnodechain_current: %s\n",
188 		       dns_result_totext(result));
189 
190 	printf("  level_matches = %d, level_count = %d\n",
191 	       chain.level_matches, chain.level_count);
192 }
193 
194 static void
195 iterate(dns_rbt_t *rbt, isc_boolean_t forward) {
196 	dns_name_t foundname, *origin;
197 	dns_rbtnodechain_t chain;
198 	dns_fixedname_t fixedorigin;
199 	isc_result_t result;
200 	isc_result_t (*move)(dns_rbtnodechain_t *chain, dns_name_t *name,
201 			     dns_name_t *origin);
202 
203 	dns_rbtnodechain_init(&chain, mctx);
204 
205 	dns_name_init(&foundname, NULL);
206 	dns_fixedname_init(&fixedorigin);
207 	origin = dns_fixedname_name(&fixedorigin);
208 
209 	if (forward) {
210 		printf("iterating forward\n" );
211 		move = dns_rbtnodechain_next;
212 
213 		result = dns_rbtnodechain_first(&chain, rbt, &foundname,
214 						origin);
215 
216 	} else {
217 		printf("iterating backward\n" );
218 		move = dns_rbtnodechain_prev;
219 
220 		result = dns_rbtnodechain_last(&chain, rbt, &foundname,
221 					       origin);
222 	}
223 
224 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
225 		printf("start not found!\n");
226 
227 	else {
228 		for (;;) {
229 			if (result == DNS_R_NEWORIGIN) {
230 				printf("  new origin: ");
231 				print_name(origin);
232 				printf("\n");
233 			}
234 
235 			if (result == ISC_R_SUCCESS ||
236 			    result == DNS_R_NEWORIGIN) {
237 				print_name(&foundname);
238 				printf("\n");
239 
240 			} else {
241 				if (result != ISC_R_NOMORE)
242 				       printf("UNEXEPCTED ITERATION ERROR: %s",
243 					      dns_result_totext(result));
244 				break;
245 			}
246 
247 			result = move(&chain, &foundname, origin);
248 		}
249 	}
250 }
251 
252 
253 #define CMDCHECK(s)	(strncasecmp(command, (s), length) == 0)
254 #define PRINTERR(r)	if (r != ISC_R_SUCCESS) \
255 				printf("... %s\n", dns_result_totext(r));
256 
257 int
258 main(int argc, char **argv) {
259 	char *command, *arg, buffer[1024];
260 	const char *whitespace;
261 	dns_name_t *name, *foundname;
262 	dns_fixedname_t fixedname;
263 	dns_rbt_t *rbt = NULL;
264 	int length, ch;
265 	isc_boolean_t show_final_mem = ISC_FALSE;
266 	isc_result_t result;
267 	void *data;
268 
269 	progname = strrchr(*argv, '/');
270 	if (progname != NULL)
271 		progname++;
272 	else
273 		progname = *argv;
274 
275 	while ((ch = isc_commandline_parse(argc, argv, "m")) != -1) {
276 		switch (ch) {
277 		case 'm':
278 			show_final_mem = ISC_TRUE;
279 			break;
280 		}
281 	}
282 
283 	argc -= isc_commandline_index;
284 	argv += isc_commandline_index;
285 	POST(argv);
286 
287 	if (argc > 1) {
288 		printf("Usage: %s [-m]\n", progname);
289 		exit(1);
290 	}
291 
292 	setbuf(stdout, NULL);
293 
294 	/*
295 	 * So isc_mem_stats() can report any allocation leaks.
296 	 */
297 	isc_mem_debugging = ISC_MEM_DEBUGRECORD;
298 
299 	result = isc_mem_create(0, 0, &mctx);
300 	if (result != ISC_R_SUCCESS) {
301 		printf("isc_mem_create: %s: exiting\n",
302 		       dns_result_totext(result));
303 		exit(1);
304 	}
305 
306 	result = dns_rbt_create(mctx, delete_name, NULL, &rbt);
307 	if (result != ISC_R_SUCCESS) {
308 		printf("dns_rbt_create: %s: exiting\n",
309 		       dns_result_totext(result));
310 		exit(1);
311 	}
312 
313 	whitespace = " \t";
314 
315 	while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
316 		length = strlen(buffer);
317 
318 		if (buffer[length - 1] != '\n') {
319 			printf("line to long (%lu max), ignored\n",
320 			       (unsigned long)sizeof(buffer) - 2);
321 			continue;
322 		}
323 
324 		buffer[length - 1] = '\0';
325 
326 		command = buffer + strspn(buffer, whitespace);
327 
328 		if (*command == '#')
329 			continue;
330 
331 		arg = strpbrk(command, whitespace);
332 		if (arg != NULL) {
333 			*arg++ = '\0';
334 			arg += strspn(arg, whitespace);
335 		}
336 
337 		length = strlen(command);
338 		if (*command != '\0') {
339 			if (CMDCHECK("add")) {
340 				name = create_name(arg);
341 				if (name != NULL) {
342 					printf("adding name %s\n", arg);
343 					result = dns_rbt_addname(rbt,
344 								 name, name);
345 					PRINTERR(result);
346 				}
347 
348 			} else if (CMDCHECK("delete")) {
349 				name = create_name(arg);
350 				if (name != NULL) {
351 					printf("deleting name %s\n", arg);
352 					result = dns_rbt_deletename(rbt, name,
353 								    ISC_FALSE);
354 					PRINTERR(result);
355 					delete_name(name, NULL);
356 				}
357 
358 			} else if (CMDCHECK("nuke")) {
359 				name = create_name(arg);
360 				if (name != NULL) {
361 					printf("nuking name %s "
362 					       "and its descendants\n", arg);
363 					result = dns_rbt_deletename(rbt, name,
364 								    ISC_TRUE);
365 					PRINTERR(result);
366 					delete_name(name, NULL);
367 				}
368 
369 			} else if (CMDCHECK("search")) {
370 				name = create_name(arg);
371 				if (name != NULL) {
372 					printf("searching for name %s ... ",
373 					       arg);
374 
375 					dns_fixedname_init(&fixedname);
376 					foundname =
377 						dns_fixedname_name(&fixedname);
378 					data = NULL;
379 
380 					result = dns_rbt_findname(rbt, name, 0,
381 								  foundname,
382 								  &data);
383 					switch (result) {
384 					case ISC_R_SUCCESS:
385 						printf("found exact: ");
386 						print_name(data);
387 						putchar('\n');
388 						break;
389 					case DNS_R_PARTIALMATCH:
390 						printf("found parent: ");
391 						print_name(data);
392 						printf("\n\t(foundname: ");
393 						print_name(foundname);
394 						printf(")\n");
395 						break;
396 					case ISC_R_NOTFOUND:
397 						printf("NOT FOUND!\n");
398 						break;
399 					case ISC_R_NOMEMORY:
400 						printf("OUT OF MEMORY!\n");
401 						break;
402 					default:
403 						printf("UNEXPECTED RESULT\n");
404 					}
405 
406 					delete_name(name, NULL);
407 				}
408 
409 			} else if (CMDCHECK("check")) {
410 				/*
411 				 * Or "chain".  I know, I know.  Lame name.
412 				 * I was having a hard time thinking of a
413 				 * name (especially one that did not have
414 				 * a conflicting first letter with another
415 				 * command) that would differentiate this
416 				 * from the search command.
417 				 *
418 				 * But it is just a test program, eh?
419 				 */
420 				name = create_name(arg);
421 				if (name != NULL) {
422 					detail(rbt, name);
423 
424 					delete_name(name, NULL);
425 				}
426 
427 			} else if (CMDCHECK("forward")) {
428 				iterate(rbt, ISC_TRUE);
429 
430 			} else if (CMDCHECK("backward")) {
431 				iterate(rbt, ISC_FALSE);
432 
433 			} else if (CMDCHECK("print")) {
434 				if (arg == NULL || *arg == '\0')
435 					dns_rbt_printtext(rbt, NULL, stdout);
436 				else
437 					printf("usage: print\n");
438 
439 			} else if (CMDCHECK("quit")) {
440 				if (arg == NULL || *arg == '\0')
441 					break;
442 				else
443 					printf("usage: quit\n");
444 			} else {
445 				printf("a(dd) NAME, d(elete) NAME, "
446 				       "s(earch) NAME, p(rint), or q(uit)\n");
447 
448 			}
449 		}
450 
451 	}
452 
453 	dns_rbt_destroy(&rbt);
454 
455 	if (show_final_mem)
456 		isc_mem_stats(mctx, stderr);
457 
458 	return (0);
459 }
460