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