xref: /illumos-gate/usr/src/cmd/sendmail/db/db/db_pr.c (revision f67950b21e185934ccabe311516f4dcbdb00ef79)
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997, 1998
5  *	Sleepycat Software.  All rights reserved.
6  */
7 
8 #include "config.h"
9 
10 #ifndef lint
11 static const char sccsid[] = "@(#)db_pr.c	10.40 (Sleepycat) 11/22/98";
12 #endif /* not lint */
13 
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
16 
17 #include <ctype.h>
18 #include <errno.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #endif
23 
24 #include "db_int.h"
25 #include "db_page.h"
26 #include "btree.h"
27 #include "hash.h"
28 #include "db_am.h"
29 
30 static void __db_proff __P((void *));
31 static void __db_psize __P((DB_MPOOLFILE *));
32 
33 /*
34  * __db_loadme --
35  *	Force loading of this file.
36  *
37  * PUBLIC: void __db_loadme __P((void));
38  */
39 void
40 __db_loadme()
41 {
42 	getpid();
43 }
44 
45 static FILE *set_fp;
46 
47 /*
48  * 64K is the maximum page size, so by default we check for offsets
49  * larger than that, and, where possible, we refine the test.
50  */
51 #define	PSIZE_BOUNDARY	(64 * 1024 + 1)
52 static size_t set_psize = PSIZE_BOUNDARY;
53 
54 /*
55  * __db_prinit --
56  *	Initialize tree printing routines.
57  *
58  * PUBLIC: FILE *__db_prinit __P((FILE *));
59  */
60 FILE *
61 __db_prinit(fp)
62 	FILE *fp;
63 {
64 	if (set_fp == NULL)
65 		set_fp = fp == NULL ? stdout : fp;
66 	return (set_fp);
67 }
68 
69 /*
70  * __db_dump --
71  *	Dump the tree to a file.
72  *
73  * PUBLIC: int __db_dump __P((DB *, char *, int));
74  */
75 int
76 __db_dump(dbp, name, all)
77 	DB *dbp;
78 	char *name;
79 	int all;
80 {
81 	FILE *fp, *save_fp;
82 
83 	COMPQUIET(save_fp, NULL);
84 
85 	if (set_psize == PSIZE_BOUNDARY)
86 		__db_psize(dbp->mpf);
87 
88 	if (name != NULL) {
89 		if ((fp = fopen(name, "w")) == NULL)
90 			return (errno);
91 		save_fp = set_fp;
92 		set_fp = fp;
93 	} else
94 		fp = __db_prinit(NULL);
95 
96 	(void)__db_prdb(dbp);
97 	if (dbp->type == DB_HASH)
98 		(void)__db_prhash(dbp);
99 	else
100 		(void)__db_prbtree(dbp);
101 	fprintf(fp, "%s\n", DB_LINE);
102 	__db_prtree(dbp->mpf, all);
103 
104 	if (name != NULL) {
105 		(void)fclose(fp);
106 		set_fp = save_fp;
107 	}
108 	return (0);
109 }
110 
111 /*
112  * __db_prdb --
113  *	Print out the DB structure information.
114  *
115  * PUBLIC: int __db_prdb __P((DB *));
116  */
117 int
118 __db_prdb(dbp)
119 	DB *dbp;
120 {
121 	static const FN fn[] = {
122 		{ DB_AM_DUP,		"duplicates" },
123 		{ DB_AM_INMEM,		"in-memory" },
124 		{ DB_AM_LOCKING,	"locking" },
125 		{ DB_AM_LOGGING,	"logging" },
126 		{ DB_AM_MLOCAL,		"local mpool" },
127 		{ DB_AM_PGDEF,		"default page size" },
128 		{ DB_AM_RDONLY,		"read-only" },
129 		{ DB_AM_SWAP,		"needswap" },
130 		{ DB_AM_THREAD,		"thread" },
131 		{ DB_BT_RECNUM,		"btree:recnum" },
132 		{ DB_DBM_ERROR,		"dbm/ndbm error" },
133 		{ DB_RE_DELIMITER,	"recno:delimiter" },
134 		{ DB_RE_FIXEDLEN,	"recno:fixed-length" },
135 		{ DB_RE_PAD,		"recno:pad" },
136 		{ DB_RE_RENUMBER,	"recno:renumber" },
137 		{ DB_RE_SNAPSHOT,	"recno:snapshot" },
138 		{ 0 },
139 	};
140 	FILE *fp;
141 	const char *t;
142 
143 	fp = __db_prinit(NULL);
144 
145 	switch (dbp->type) {
146 	case DB_BTREE:
147 		t = "btree";
148 		break;
149 	case DB_HASH:
150 		t = "hash";
151 		break;
152 	case DB_RECNO:
153 		t = "recno";
154 		break;
155 	default:
156 		t = "UNKNOWN";
157 		break;
158 	}
159 
160 	fprintf(fp, "%s ", t);
161 	__db_prflags(dbp->flags, fn, fp);
162 	fprintf(fp, "\n");
163 
164 	return (0);
165 }
166 
167 /*
168  * __db_prbtree --
169  *	Print out the btree internal information.
170  *
171  * PUBLIC: int __db_prbtree __P((DB *));
172  */
173 int
174 __db_prbtree(dbp)
175 	DB *dbp;
176 {
177 	static const FN mfn[] = {
178 		{ BTM_DUP,	"duplicates" },
179 		{ BTM_RECNO,	"recno" },
180 		{ BTM_RECNUM,	"btree:recnum" },
181 		{ BTM_FIXEDLEN,	"recno:fixed-length" },
182 		{ BTM_RENUMBER,	"recno:renumber" },
183 		{ 0 },
184 	};
185 	DBC *dbc;
186 	BTMETA *mp;
187 	BTREE *t;
188 	FILE *fp;
189 	PAGE *h;
190 	RECNO *rp;
191 	db_pgno_t i;
192 	int cnt, ret;
193 	const char *sep;
194 
195 	t = dbp->internal;
196 	fp = __db_prinit(NULL);
197 	if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
198 		return (ret);
199 
200 	(void)fprintf(fp, "%s\nOn-page metadata:\n", DB_LINE);
201 
202 	i = PGNO_METADATA;
203 	if ((ret = memp_fget(dbp->mpf, &i, 0, (PAGE **)&mp)) != 0) {
204 		(void)dbc->c_close(dbc);
205 		return (ret);
206 	}
207 
208 	fprintf(fp, "lsn.file: %lu lsn.offset: %lu\n",
209 	    (u_long)LSN(mp).file, (u_long)LSN(mp).offset);
210 	(void)fprintf(fp, "magic %#lx\n", (u_long)mp->magic);
211 	(void)fprintf(fp, "version %#lx\n", (u_long)mp->version);
212 	(void)fprintf(fp, "pagesize %lu\n", (u_long)mp->pagesize);
213 	(void)fprintf(fp, "maxkey: %lu minkey: %lu\n",
214 	    (u_long)mp->maxkey, (u_long)mp->minkey);
215 
216 	(void)fprintf(fp, "free list: %lu", (u_long)mp->free);
217 	for (i = mp->free, cnt = 0, sep = ", "; i != PGNO_INVALID;) {
218 		if ((ret = memp_fget(dbp->mpf, &i, 0, &h)) != 0)
219 			return (ret);
220 		i = h->next_pgno;
221 		(void)memp_fput(dbp->mpf, h, 0);
222 		(void)fprintf(fp, "%s%lu", sep, (u_long)i);
223 		if (++cnt % 10 == 0) {
224 			(void)fprintf(fp, "\n");
225 			cnt = 0;
226 			sep = "";
227 		} else
228 			sep = ", ";
229 	}
230 	(void)fprintf(fp, "\n");
231 
232 	(void)fprintf(fp, "flags %#lx", (u_long)mp->flags);
233 	__db_prflags(mp->flags, mfn, fp);
234 	(void)fprintf(fp, "\n");
235 	(void)memp_fput(dbp->mpf, mp, 0);
236 
237 	(void)fprintf(fp, "%s\nDB_INFO:\n", DB_LINE);
238 	(void)fprintf(fp, "bt_maxkey: %lu bt_minkey: %lu\n",
239 	    (u_long)t->bt_maxkey, (u_long)t->bt_minkey);
240 	(void)fprintf(fp, "bt_compare: %#lx bt_prefix: %#lx\n",
241 	    (u_long)t->bt_compare, (u_long)t->bt_prefix);
242 	if ((rp = t->recno) != NULL) {
243 		(void)fprintf(fp,
244 		    "re_delim: %#lx re_pad: %#lx re_len: %lu re_source: %s\n",
245 		    (u_long)rp->re_delim, (u_long)rp->re_pad,
246 		    (u_long)rp->re_len,
247 		    rp->re_source == NULL ? "" : rp->re_source);
248 		(void)fprintf(fp,
249 		    "cmap: %#lx smap: %#lx emap: %#lx msize: %lu\n",
250 		    (u_long)rp->re_cmap, (u_long)rp->re_smap,
251 		    (u_long)rp->re_emap, (u_long)rp->re_msize);
252 	}
253 	(void)fprintf(fp, "ovflsize: %lu\n", (u_long)t->bt_ovflsize);
254 	(void)fflush(fp);
255 	return (dbc->c_close(dbc));
256 }
257 
258 /*
259  * __db_prhash --
260  *	Print out the hash internal information.
261  *
262  * PUBLIC: int __db_prhash __P((DB *));
263  */
264 int
265 __db_prhash(dbp)
266 	DB *dbp;
267 {
268 	FILE *fp;
269 	DBC *dbc;
270 	HASH_CURSOR *hcp;
271 	int i, put_page, ret;
272 	db_pgno_t pgno;
273 
274 	fp = __db_prinit(NULL);
275 	if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
276 		return (ret);
277 	hcp = (HASH_CURSOR *)dbc->internal;
278 
279 	/*
280 	 * In this case,  hcp->hdr will never be null, if we decide
281 	 * to pass dbc's to this routine instead, then it could be.
282 	 */
283 	if (hcp->hdr == NULL) {
284 		pgno = PGNO_METADATA;
285 		if ((ret = memp_fget(dbp->mpf, &pgno, 0, &hcp->hdr)) != 0)
286 			return (ret);
287 		put_page = 1;
288 	} else
289 		put_page = 0;
290 
291 	fprintf(fp, "\tmagic      %#lx\n", (u_long)hcp->hdr->magic);
292 	fprintf(fp, "\tversion    %lu\n", (u_long)hcp->hdr->version);
293 	fprintf(fp, "\tpagesize   %lu\n", (u_long)hcp->hdr->pagesize);
294 	fprintf(fp, "\tovfl_point %lu\n", (u_long)hcp->hdr->ovfl_point);
295 	fprintf(fp, "\tlast_freed %lu\n", (u_long)hcp->hdr->last_freed);
296 	fprintf(fp, "\tmax_bucket %lu\n", (u_long)hcp->hdr->max_bucket);
297 	fprintf(fp, "\thigh_mask  %#lx\n", (u_long)hcp->hdr->high_mask);
298 	fprintf(fp, "\tlow_mask   %#lx\n", (u_long)hcp->hdr->low_mask);
299 	fprintf(fp, "\tffactor    %lu\n", (u_long)hcp->hdr->ffactor);
300 	fprintf(fp, "\tnelem      %lu\n", (u_long)hcp->hdr->nelem);
301 	fprintf(fp, "\th_charkey  %#lx\n", (u_long)hcp->hdr->h_charkey);
302 
303 	for (i = 0; i < NCACHED; i++)
304 		fprintf(fp, "%lu ", (u_long)hcp->hdr->spares[i]);
305 	fprintf(fp, "\n");
306 
307 	(void)fflush(fp);
308 	if (put_page) {
309 		(void)memp_fput(dbp->mpf, (PAGE *)hcp->hdr, 0);
310 		hcp->hdr = NULL;
311 	}
312 	return (dbc->c_close(dbc));
313 }
314 
315 /*
316  * __db_prtree --
317  *	Print out the entire tree.
318  *
319  * PUBLIC: int __db_prtree __P((DB_MPOOLFILE *, int));
320  */
321 int
322 __db_prtree(mpf, all)
323 	DB_MPOOLFILE *mpf;
324 	int all;
325 {
326 	PAGE *h;
327 	db_pgno_t i;
328 
329 	if (set_psize == PSIZE_BOUNDARY)
330 		__db_psize(mpf);
331 
332 	for (i = PGNO_ROOT;; ++i) {
333 		if (memp_fget(mpf, &i, 0, &h) != 0)
334 			break;
335 		(void)__db_prpage(h, all);
336 		(void)memp_fput(mpf, h, 0);
337 	}
338 	(void)fflush(__db_prinit(NULL));
339 	return (0);
340 }
341 
342 /*
343  * __db_prnpage
344  *	-- Print out a specific page.
345  *
346  * PUBLIC: int __db_prnpage __P((DB_MPOOLFILE *, db_pgno_t));
347  */
348 int
349 __db_prnpage(mpf, pgno)
350 	DB_MPOOLFILE *mpf;
351 	db_pgno_t pgno;
352 {
353 	PAGE *h;
354 	int ret;
355 
356 	if (set_psize == PSIZE_BOUNDARY)
357 		__db_psize(mpf);
358 
359 	if ((ret = memp_fget(mpf, &pgno, 0, &h)) != 0)
360 		return (ret);
361 
362 	ret = __db_prpage(h, 1);
363 	(void)fflush(__db_prinit(NULL));
364 
365 	(void)memp_fput(mpf, h, 0);
366 	return (ret);
367 }
368 
369 /*
370  * __db_prpage
371  *	-- Print out a page.
372  *
373  * PUBLIC: int __db_prpage __P((PAGE *, int));
374  */
375 int
376 __db_prpage(h, all)
377 	PAGE *h;
378 	int all;
379 {
380 	BINTERNAL *bi;
381 	BKEYDATA *bk;
382 	HOFFPAGE a_hkd;
383 	FILE *fp;
384 	RINTERNAL *ri;
385 	db_indx_t dlen, len, i;
386 	db_pgno_t pgno;
387 	int deleted, ret;
388 	const char *s;
389 	u_int8_t *ep, *hk, *p;
390 	void *sp;
391 
392 	fp = __db_prinit(NULL);
393 
394 	switch (TYPE(h)) {
395 	case P_DUPLICATE:
396 		s = "duplicate";
397 		break;
398 	case P_HASH:
399 		s = "hash";
400 		break;
401 	case P_IBTREE:
402 		s = "btree internal";
403 		break;
404 	case P_INVALID:
405 		s = "invalid";
406 		break;
407 	case P_IRECNO:
408 		s = "recno internal";
409 		break;
410 	case P_LBTREE:
411 		s = "btree leaf";
412 		break;
413 	case P_LRECNO:
414 		s = "recno leaf";
415 		break;
416 	case P_OVERFLOW:
417 		s = "overflow";
418 		break;
419 	default:
420 		fprintf(fp, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n",
421 		    (u_long)h->pgno, (u_long)TYPE(h));
422 			return (1);
423 	}
424 	fprintf(fp, "page %4lu: (%s)\n", (u_long)h->pgno, s);
425 	fprintf(fp, "    lsn.file: %lu lsn.offset: %lu",
426 	    (u_long)LSN(h).file, (u_long)LSN(h).offset);
427 	if (TYPE(h) == P_IBTREE || TYPE(h) == P_IRECNO ||
428 	    (TYPE(h) == P_LRECNO && h->pgno == PGNO_ROOT))
429 		fprintf(fp, " total records: %4lu", (u_long)RE_NREC(h));
430 	fprintf(fp, "\n");
431 	if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO)
432 		fprintf(fp, "    prev: %4lu next: %4lu",
433 		    (u_long)PREV_PGNO(h), (u_long)NEXT_PGNO(h));
434 	if (TYPE(h) == P_IBTREE || TYPE(h) == P_LBTREE)
435 		fprintf(fp, " level: %2lu", (u_long)h->level);
436 	if (TYPE(h) == P_OVERFLOW) {
437 		fprintf(fp, " ref cnt: %4lu ", (u_long)OV_REF(h));
438 		__db_pr((u_int8_t *)h + P_OVERHEAD, OV_LEN(h));
439 		return (0);
440 	}
441 	fprintf(fp, " entries: %4lu", (u_long)NUM_ENT(h));
442 	fprintf(fp, " offset: %4lu\n", (u_long)HOFFSET(h));
443 
444 	if (!all || TYPE(h) == P_INVALID)
445 		return (0);
446 
447 	ret = 0;
448 	for (i = 0; i < NUM_ENT(h); i++) {
449 		if (P_ENTRY(h, i) - (u_int8_t *)h < P_OVERHEAD ||
450 		    (size_t)(P_ENTRY(h, i) - (u_int8_t *)h) >= set_psize) {
451 			fprintf(fp,
452 			    "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n",
453 			    (u_long)i, (u_long)h->inp[i]);
454 			ret = EINVAL;
455 			continue;
456 		}
457 		deleted = 0;
458 		switch (TYPE(h)) {
459 		case P_HASH:
460 		case P_IBTREE:
461 		case P_IRECNO:
462 			sp = P_ENTRY(h, i);
463 			break;
464 		case P_LBTREE:
465 			sp = P_ENTRY(h, i);
466 			deleted = i % 2 == 0 &&
467 			    B_DISSET(GET_BKEYDATA(h, i + O_INDX)->type);
468 			break;
469 		case P_LRECNO:
470 		case P_DUPLICATE:
471 			sp = P_ENTRY(h, i);
472 			deleted = B_DISSET(GET_BKEYDATA(h, i)->type);
473 			break;
474 		default:
475 			fprintf(fp,
476 			    "ILLEGAL PAGE ITEM: %lu\n", (u_long)TYPE(h));
477 			ret = EINVAL;
478 			continue;
479 		}
480 		fprintf(fp, "   %s[%03lu] %4lu ",
481 		    deleted ? "D" : " ", (u_long)i, (u_long)h->inp[i]);
482 		switch (TYPE(h)) {
483 		case P_HASH:
484 			hk = sp;
485 			switch (HPAGE_PTYPE(hk)) {
486 			case H_OFFDUP:
487 				memcpy(&pgno,
488 				    HOFFDUP_PGNO(hk), sizeof(db_pgno_t));
489 				fprintf(fp,
490 				    "%4lu [offpage dups]\n", (u_long)pgno);
491 				break;
492 			case H_DUPLICATE:
493 				/*
494 				 * If this is the first item on a page, then
495 				 * we cannot figure out how long it is, so
496 				 * we only print the first one in the duplicate
497 				 * set.
498 				 */
499 				if (i != 0)
500 					len = LEN_HKEYDATA(h, 0, i);
501 				else
502 					len = 1;
503 
504 				fprintf(fp, "Duplicates:\n");
505 				for (p = HKEYDATA_DATA(hk),
506 				    ep = p + len; p < ep;) {
507 					memcpy(&dlen, p, sizeof(db_indx_t));
508 					p += sizeof(db_indx_t);
509 					fprintf(fp, "\t\t");
510 					__db_pr(p, dlen);
511 					p += sizeof(db_indx_t) + dlen;
512 				}
513 				break;
514 			case H_KEYDATA:
515 				if (i != 0)
516 					__db_pr(HKEYDATA_DATA(hk),
517 					    LEN_HKEYDATA(h, 0, i));
518 				else
519 					fprintf(fp, "%s\n", HKEYDATA_DATA(hk));
520 				break;
521 			case H_OFFPAGE:
522 				memcpy(&a_hkd, hk, HOFFPAGE_SIZE);
523 				fprintf(fp,
524 				    "overflow: total len: %4lu page: %4lu\n",
525 				    (u_long)a_hkd.tlen, (u_long)a_hkd.pgno);
526 				break;
527 			}
528 			break;
529 		case P_IBTREE:
530 			bi = sp;
531 			fprintf(fp, "count: %4lu pgno: %4lu ",
532 			    (u_long)bi->nrecs, (u_long)bi->pgno);
533 			switch (B_TYPE(bi->type)) {
534 			case B_KEYDATA:
535 				__db_pr(bi->data, bi->len);
536 				break;
537 			case B_DUPLICATE:
538 			case B_OVERFLOW:
539 				__db_proff(bi->data);
540 				break;
541 			default:
542 				fprintf(fp, "ILLEGAL BINTERNAL TYPE: %lu\n",
543 				    (u_long)B_TYPE(bi->type));
544 				ret = EINVAL;
545 				break;
546 			}
547 			break;
548 		case P_IRECNO:
549 			ri = sp;
550 			fprintf(fp, "entries %4lu pgno %4lu\n",
551 			    (u_long)ri->nrecs, (u_long)ri->pgno);
552 			break;
553 		case P_LBTREE:
554 		case P_LRECNO:
555 		case P_DUPLICATE:
556 			bk = sp;
557 			switch (B_TYPE(bk->type)) {
558 			case B_KEYDATA:
559 				__db_pr(bk->data, bk->len);
560 				break;
561 			case B_DUPLICATE:
562 			case B_OVERFLOW:
563 				__db_proff(bk);
564 				break;
565 			default:
566 				fprintf(fp,
567 			    "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n",
568 				    (u_long)B_TYPE(bk->type));
569 				ret = EINVAL;
570 				break;
571 			}
572 			break;
573 		}
574 	}
575 	(void)fflush(fp);
576 	return (ret);
577 }
578 
579 /*
580  * __db_isbad
581  *	-- Decide if a page is corrupted.
582  *
583  * PUBLIC: int __db_isbad __P((PAGE *, int));
584  */
585 int
586 __db_isbad(h, die)
587 	PAGE *h;
588 	int die;
589 {
590 	BINTERNAL *bi;
591 	BKEYDATA *bk;
592 	FILE *fp;
593 	db_indx_t i;
594 	u_int type;
595 
596 	fp = __db_prinit(NULL);
597 
598 	switch (TYPE(h)) {
599 	case P_DUPLICATE:
600 	case P_HASH:
601 	case P_IBTREE:
602 	case P_INVALID:
603 	case P_IRECNO:
604 	case P_LBTREE:
605 	case P_LRECNO:
606 	case P_OVERFLOW:
607 		break;
608 	default:
609 		fprintf(fp, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n",
610 		    (u_long)h->pgno, (u_long)TYPE(h));
611 		goto bad;
612 	}
613 
614 	for (i = 0; i < NUM_ENT(h); i++) {
615 		if (P_ENTRY(h, i) - (u_int8_t *)h < P_OVERHEAD ||
616 		    (size_t)(P_ENTRY(h, i) - (u_int8_t *)h) >= set_psize) {
617 			fprintf(fp,
618 			    "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n",
619 			    (u_long)i, (u_long)h->inp[i]);
620 			goto bad;
621 		}
622 		switch (TYPE(h)) {
623 		case P_HASH:
624 			type = HPAGE_TYPE(h, i);
625 			if (type != H_OFFDUP &&
626 			    type != H_DUPLICATE &&
627 			    type != H_KEYDATA &&
628 			    type != H_OFFPAGE) {
629 				fprintf(fp, "ILLEGAL HASH TYPE: %lu\n",
630 				    (u_long)type);
631 				goto bad;
632 			}
633 			break;
634 		case P_IBTREE:
635 			bi = GET_BINTERNAL(h, i);
636 			if (B_TYPE(bi->type) != B_KEYDATA &&
637 			    B_TYPE(bi->type) != B_DUPLICATE &&
638 			    B_TYPE(bi->type) != B_OVERFLOW) {
639 				fprintf(fp, "ILLEGAL BINTERNAL TYPE: %lu\n",
640 				    (u_long)B_TYPE(bi->type));
641 				goto bad;
642 			}
643 			break;
644 		case P_IRECNO:
645 		case P_LBTREE:
646 		case P_LRECNO:
647 			break;
648 		case P_DUPLICATE:
649 			bk = GET_BKEYDATA(h, i);
650 			if (B_TYPE(bk->type) != B_KEYDATA &&
651 			    B_TYPE(bk->type) != B_DUPLICATE &&
652 			    B_TYPE(bk->type) != B_OVERFLOW) {
653 				fprintf(fp,
654 			    "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n",
655 				    (u_long)B_TYPE(bk->type));
656 				goto bad;
657 			}
658 			break;
659 		default:
660 			fprintf(fp,
661 			    "ILLEGAL PAGE ITEM: %lu\n", (u_long)TYPE(h));
662 			goto bad;
663 		}
664 	}
665 	return (0);
666 
667 bad:	if (die) {
668 		abort();
669 		/* NOTREACHED */
670 	}
671 	return (1);
672 }
673 
674 /*
675  * __db_pr --
676  *	Print out a data element.
677  *
678  * PUBLIC: void __db_pr __P((u_int8_t *, u_int32_t));
679  */
680 void
681 __db_pr(p, len)
682 	u_int8_t *p;
683 	u_int32_t len;
684 {
685 	FILE *fp;
686 	u_int lastch;
687 	int i;
688 
689 	fp = __db_prinit(NULL);
690 
691 	fprintf(fp, "len: %3lu", (u_long)len);
692 	lastch = '.';
693 	if (len != 0) {
694 		fprintf(fp, " data: ");
695 		for (i = len <= 20 ? len : 20; i > 0; --i, ++p) {
696 			lastch = *p;
697 			if (isprint(*p) || *p == '\n')
698 				fprintf(fp, "%c", *p);
699 			else
700 				fprintf(fp, "0x%.2x", (u_int)*p);
701 		}
702 		if (len > 20) {
703 			fprintf(fp, "...");
704 			lastch = '.';
705 		}
706 	}
707 	if (lastch != '\n')
708 		fprintf(fp, "\n");
709 }
710 
711 /*
712  * __db_prdbt --
713  *	Print out a DBT data element.
714  *
715  * PUBLIC: int __db_prdbt __P((DBT *, int, FILE *));
716  */
717 int
718 __db_prdbt(dbtp, checkprint, fp)
719 	DBT *dbtp;
720 	int checkprint;
721 	FILE *fp;
722 {
723 	static const char hex[] = "0123456789abcdef";
724 	u_int8_t *p;
725 	u_int32_t len;
726 
727 	/*
728 	 * !!!
729 	 * This routine is the routine that dumps out items in the format
730 	 * used by db_dump(1) and db_load(1).  This means that the format
731 	 * cannot change.
732 	 */
733 	if (checkprint) {
734 		for (len = dbtp->size, p = dbtp->data; len--; ++p)
735 			if (isprint(*p)) {
736 				if (*p == '\\' && fprintf(fp, "\\") != 1)
737 					return (EIO);
738 				if (fprintf(fp, "%c", *p) != 1)
739 					return (EIO);
740 			} else
741 				if (fprintf(fp, "\\%c%c",
742 				    hex[(u_int8_t)(*p & 0xf0) >> 4],
743 				    hex[*p & 0x0f]) != 3)
744 					return (EIO);
745 	} else
746 		for (len = dbtp->size, p = dbtp->data; len--; ++p)
747 			if (fprintf(fp, "%c%c",
748 			    hex[(u_int8_t)(*p & 0xf0) >> 4],
749 			    hex[*p & 0x0f]) != 2)
750 				return (EIO);
751 
752 	return (fprintf(fp, "\n") == 1 ? 0 : EIO);
753 }
754 
755 /*
756  * __db_proff --
757  *	Print out an off-page element.
758  */
759 static void
760 __db_proff(vp)
761 	void *vp;
762 {
763 	FILE *fp;
764 	BOVERFLOW *bo;
765 
766 	fp = __db_prinit(NULL);
767 
768 	bo = vp;
769 	switch (B_TYPE(bo->type)) {
770 	case B_OVERFLOW:
771 		fprintf(fp, "overflow: total len: %4lu page: %4lu\n",
772 		    (u_long)bo->tlen, (u_long)bo->pgno);
773 		break;
774 	case B_DUPLICATE:
775 		fprintf(fp, "duplicate: page: %4lu\n", (u_long)bo->pgno);
776 		break;
777 	}
778 }
779 
780 /*
781  * __db_prflags --
782  *	Print out flags values.
783  *
784  * PUBLIC: void __db_prflags __P((u_int32_t, const FN *, FILE *));
785  */
786 void
787 __db_prflags(flags, fn, fp)
788 	u_int32_t flags;
789 	FN const *fn;
790 	FILE *fp;
791 {
792 	const FN *fnp;
793 	int found;
794 	const char *sep;
795 
796 	sep = " (";
797 	for (found = 0, fnp = fn; fnp->mask != 0; ++fnp)
798 		if (LF_ISSET(fnp->mask)) {
799 			fprintf(fp, "%s%s", sep, fnp->name);
800 			sep = ", ";
801 			found = 1;
802 		}
803 	if (found)
804 		fprintf(fp, ")");
805 }
806 
807 /*
808  * __db_psize --
809  *	Get the page size.
810  */
811 static void
812 __db_psize(mpf)
813 	DB_MPOOLFILE *mpf;
814 {
815 	BTMETA *mp;
816 	db_pgno_t pgno;
817 
818 	set_psize = PSIZE_BOUNDARY - 1;
819 
820 	pgno = PGNO_METADATA;
821 	if (memp_fget(mpf, &pgno, 0, &mp) != 0)
822 		return;
823 
824 	switch (mp->magic) {
825 	case DB_BTREEMAGIC:
826 	case DB_HASHMAGIC:
827 		set_psize = mp->pagesize;
828 		break;
829 	}
830 	(void)memp_fput(mpf, mp, 0);
831 }
832