f86fd6770a00147760abda45431cccae46efad6d
[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.16 (Sleepycat) 9/3/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         DB_LOCK lock;
187         EPG *sp;
188         FILE *fp;
189         RECNO *rp;
190         db_pgno_t i;
191         int ret;
192
193         t = dbp->internal;
194         fp = __db_prinit(NULL);
195
196         (void)fprintf(fp, "%s\nOn-page metadata:\n", DB_LINE);
197         i = PGNO_METADATA;
198         if ((ret = __bam_lget(dbp, 0, PGNO_METADATA, DB_LOCK_READ, &lock)) != 0)
199                 return (ret);
200
201         if ((ret = __bam_pget(dbp, (PAGE **)&mp, &i, 0)) != 0)
202                 return (ret);
203
204         (void)fprintf(fp, "magic %#lx\n", (u_long)mp->magic);
205         (void)fprintf(fp, "version %lu\n", (u_long)mp->version);
206         (void)fprintf(fp, "pagesize %lu\n", (u_long)mp->pagesize);
207         (void)fprintf(fp, "maxkey: %lu minkey: %lu\n",
208             (u_long)mp->maxkey, (u_long)mp->minkey);
209         (void)fprintf(fp, "free %lu\n", (u_long)mp->free);
210         (void)fprintf(fp, "flags %lu", (u_long)mp->flags);
211         __db_prflags(mp->flags, mfn);
212         (void)fprintf(fp, "\n");
213         (void)memp_fput(dbp->mpf, mp, 0);
214         (void)__bam_lput(dbp, lock);
215
216         (void)fprintf(fp, "%s\nDB_INFO:\n", DB_LINE);
217         (void)fprintf(fp, "bt_maxkey: %lu bt_minkey: %lu\n",
218             (u_long)t->bt_maxkey, (u_long)t->bt_minkey);
219         (void)fprintf(fp, "bt_compare: %#lx bt_prefix: %#lx\n",
220             (u_long)t->bt_compare, (u_long)t->bt_prefix);
221         if ((rp = t->bt_recno) != NULL) {
222                 (void)fprintf(fp,
223                     "re_delim: %#lx re_pad: %#lx re_len: %lu re_source: %s\n",
224                     (u_long)rp->re_delim, (u_long)rp->re_pad,
225                     (u_long)rp->re_len,
226                     rp->re_source == NULL ? "" : rp->re_source);
227                 (void)fprintf(fp,
228                     "cmap: %#lx smap: %#lx emap: %#lx msize: %lu\n",
229                     (u_long)rp->re_cmap, (u_long)rp->re_smap,
230                     (u_long)rp->re_emap, (u_long)rp->re_msize);
231         }
232         (void)fprintf(fp, "stack:");
233         for (sp = t->bt_stack; sp < t->bt_sp; ++sp)
234                 (void)fprintf(fp, " %lu", (u_long)sp->page->pgno);
235         (void)fprintf(fp, "\n");
236         (void)fprintf(fp, "ovflsize: %lu\n", (u_long)t->bt_ovflsize);
237         (void)fflush(fp);
238         return (0);
239 }
240
241 /*
242  * __db_prhash --
243  *      Print out the hash internal information.
244  *
245  * PUBLIC: int __db_prhash __P((DB *));
246  */
247 int
248 __db_prhash(dbp)
249         DB *dbp;
250 {
251         FILE *fp;
252         HTAB *t;
253         int i, put_page, ret;
254         db_pgno_t pgno;
255
256         t = dbp->internal;
257
258         fp = __db_prinit(NULL);
259
260         fprintf(fp, "\thash_accesses    %lu\n", (u_long)t->hash_accesses);
261         fprintf(fp, "\thash_collisions  %lu\n", (u_long)t->hash_collisions);
262         fprintf(fp, "\thash_expansions  %lu\n", (u_long)t->hash_expansions);
263         fprintf(fp, "\thash_overflows   %lu\n", (u_long)t->hash_overflows);
264         fprintf(fp, "\thash_bigpages    %lu\n", (u_long)t->hash_bigpages);
265         fprintf(fp, "\n");
266
267         if (t->hdr == NULL) {
268                 pgno = PGNO_METADATA;
269                 if ((ret = memp_fget(dbp->mpf, &pgno, 0, &t->hdr)) != 0)
270                         return (ret);
271                 put_page = 1;
272         } else
273                 put_page = 0;
274
275         fprintf(fp, "\tmagic      %#lx\n", (u_long)t->hdr->magic);
276         fprintf(fp, "\tversion    %lu\n", (u_long)t->hdr->version);
277         fprintf(fp, "\tpagesize   %lu\n", (u_long)t->hdr->pagesize);
278         fprintf(fp, "\tovfl_point %lu\n", (u_long)t->hdr->ovfl_point);
279         fprintf(fp, "\tlast_freed %lu\n", (u_long)t->hdr->last_freed);
280         fprintf(fp, "\tmax_bucket %lu\n", (u_long)t->hdr->max_bucket);
281         fprintf(fp, "\thigh_mask  %#lx\n", (u_long)t->hdr->high_mask);
282         fprintf(fp, "\tlow_mask   %#lx\n", (u_long)t->hdr->low_mask);
283         fprintf(fp, "\tffactor    %lu\n", (u_long)t->hdr->ffactor);
284         fprintf(fp, "\tnelem      %lu\n", (u_long)t->hdr->nelem);
285         fprintf(fp, "\th_charkey  %#lx\n", (u_long)t->hdr->h_charkey);
286
287         for (i = 0; i < NCACHED; i++)
288                 fprintf(fp, "%lu ", (u_long)t->hdr->spares[i]);
289         fprintf(fp, "\n");
290
291         (void)fflush(fp);
292         if (put_page) {
293                 (void)memp_fput(dbp->mpf, (PAGE *)t->hdr, 0);
294                 t->hdr = NULL;
295         }
296         return (0);
297 }
298
299 /*
300  * __db_prtree --
301  *      Print out the entire tree.
302  *
303  * PUBLIC: int __db_prtree __P((DB_MPOOLFILE *, int));
304  */
305 int
306 __db_prtree(mpf, all)
307         DB_MPOOLFILE *mpf;
308         int all;
309 {
310         PAGE *h;
311         db_pgno_t i;
312         int ret, t_ret;
313
314         if (set_psize == PSIZE_BOUNDARY)
315                 __db_psize(mpf);
316
317         ret = 0;
318         for (i = PGNO_ROOT;; ++i) {
319                 if ((ret = memp_fget(mpf, &i, 0, &h)) != 0)
320                         break;
321                 if (TYPE(h) != P_INVALID)
322                         if ((t_ret = __db_prpage(h, all)) != 0 && ret == 0)
323                                 ret = t_ret;
324                 (void)memp_fput(mpf, h, 0);
325         }
326         (void)fflush(__db_prinit(NULL));
327         return (ret);
328 }
329
330 /*
331  * __db_prnpage
332  *      -- Print out a specific page.
333  *
334  * PUBLIC: int __db_prnpage __P((DB_MPOOLFILE *, db_pgno_t));
335  */
336 int
337 __db_prnpage(mpf, pgno)
338         DB_MPOOLFILE *mpf;
339         db_pgno_t pgno;
340 {
341         PAGE *h;
342         int ret;
343
344         if (set_psize == PSIZE_BOUNDARY)
345                 __db_psize(mpf);
346
347         if ((ret = memp_fget(mpf, &pgno, 0, &h)) != 0)
348                 return (ret);
349
350         ret = __db_prpage(h, 1);
351         (void)fflush(__db_prinit(NULL));
352
353         (void)memp_fput(mpf, h, 0);
354         return (ret);
355 }
356
357 /*
358  * __db_prpage
359  *      -- Print out a page.
360  *
361  * PUBLIC: int __db_prpage __P((PAGE *, int));
362  */
363 int
364 __db_prpage(h, all)
365         PAGE *h;
366         int all;
367 {
368         BINTERNAL *bi;
369         BKEYDATA *bk;
370         HKEYDATA *hkd;
371         HOFFPAGE a_hkd;
372         FILE *fp;
373         RINTERNAL *ri;
374         db_indx_t dlen, len, i;
375         db_pgno_t pgno;
376         u_int8_t *p;
377         int deleted, ret;
378         const char *s;
379
380         bi = NULL;                              /* XXX: Shut the compiler up. */
381         bk = NULL;
382         hkd = NULL;
383         ri = NULL;
384
385         fp = __db_prinit(NULL);
386
387         switch (TYPE(h)) {
388         case P_DUPLICATE:
389                 s = "duplicate";
390                 break;
391         case P_HASH:
392                 s = "hash";
393                 break;
394         case P_IBTREE:
395                 s = "btree internal";
396                 break;
397         case P_INVALID:
398                 s = "invalid";
399                 break;
400         case P_IRECNO:
401                 s = "recno internal";
402                 break;
403         case P_LBTREE:
404                 s = "btree leaf";
405                 break;
406         case P_LRECNO:
407                 s = "recno leaf";
408                 break;
409         case P_OVERFLOW:
410                 s = "overflow";
411                 break;
412         default:
413                 fprintf(fp, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n",
414                     (u_long)h->pgno, (u_long)TYPE(h));
415                         return (1);
416         }
417         fprintf(fp, "page %4lu: (%s)\n", (u_long)h->pgno, s);
418         fprintf(fp, "    lsn.file: %lu lsn.offset: %lu",
419             (u_long)LSN(h).file, (u_long)LSN(h).offset);
420         if (TYPE(h) == P_IBTREE || TYPE(h) == P_IRECNO ||
421             (TYPE(h) == P_LRECNO && h->pgno == PGNO_ROOT))
422                 fprintf(fp, " total records: %4lu", (u_long)RE_NREC(h));
423         fprintf(fp, "\n");
424         if (TYPE(h) == P_LBTREE || TYPE(h) == P_LRECNO)
425                 fprintf(fp, "    prev: %4lu next: %4lu",
426                     (u_long)PREV_PGNO(h), (u_long)NEXT_PGNO(h));
427         if (TYPE(h) == P_IBTREE || TYPE(h) == P_LBTREE)
428                 fprintf(fp, " level: %2lu", (u_long)h->level);
429         if (TYPE(h) == P_OVERFLOW) {
430                 fprintf(fp, " ref cnt: %4lu ", (u_long)OV_REF(h));
431                 __db_pr((u_int8_t *)h + P_OVERHEAD, OV_LEN(h));
432                 return (0);
433         }
434         fprintf(fp, " entries: %4lu", (u_long)NUM_ENT(h));
435         fprintf(fp, " offset: %4lu\n", (u_long)HOFFSET(h));
436
437         if (!all || TYPE(h) == P_INVALID)
438                 return (0);
439
440         ret = 0;
441         for (i = 0; i < NUM_ENT(h); i++) {
442                 if (P_ENTRY(h, i) - (u_int8_t *)h < P_OVERHEAD ||
443                     (size_t)(P_ENTRY(h, i) - (u_int8_t *)h) >= set_psize) {
444                         fprintf(fp,
445                             "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n",
446                             (u_long)i, (u_long)h->inp[i]);
447                         ret = EINVAL;
448                         continue;
449                 }
450                 deleted = 0;
451                 switch (TYPE(h)) {
452                 case P_HASH:
453                         hkd = GET_HKEYDATA(h, i);
454                         break;
455                 case P_IBTREE:
456                         bi = GET_BINTERNAL(h, i);
457                         break;
458                 case P_IRECNO:
459                         ri = GET_RINTERNAL(h, i);
460                         break;
461                 case P_LBTREE:
462                         bk = GET_BKEYDATA(h, i);
463                         deleted = i % 2 == 0 &&
464                             B_DISSET(GET_BKEYDATA(h, i + O_INDX)->type);
465                         break;
466                 case P_LRECNO:
467                 case P_DUPLICATE:
468                         bk = GET_BKEYDATA(h, i);
469                         deleted = B_DISSET(GET_BKEYDATA(h, i)->type);
470                         break;
471                 default:
472                         fprintf(fp,
473                             "ILLEGAL PAGE ITEM: %lu\n", (u_long)TYPE(h));
474                         ret = EINVAL;
475                         continue;
476                 }
477                 fprintf(fp, "   %s[%03lu] %4lu ",
478                     deleted ? "D" : " ", (u_long)i, (u_long)h->inp[i]);
479                 switch (TYPE(h)) {
480                 case P_HASH:
481                         switch (hkd->type) {
482                         case H_OFFDUP:
483                                 memcpy(&pgno,
484                                     (u_int8_t *)hkd + SSZ(HOFFDUP, pgno),
485                                     sizeof(db_pgno_t));
486                                 fprintf(fp,
487                                     "%4lu [offpage dups]\n", (u_long)pgno);
488                                 break;
489                         case H_DUPLICATE:
490                                 /*
491                                  * If this is the first item on a page, then
492                                  * we cannot figure out how long it is, so
493                                  * we only print the first one in the duplicate
494                                  * set.
495                                  */
496                                 if (i != 0)
497                                         len = LEN_HKEYDATA(h, 0, i);
498                                 else
499                                         len = 1;
500
501                                 fprintf(fp, "Duplicates:\n");
502                                 for (p = hkd->data; p < hkd->data + len;) {
503                                         memcpy(&dlen, p, sizeof(db_indx_t));
504                                         p += sizeof(db_indx_t);
505                                         fprintf(fp, "\t\t");
506                                         __db_pr(p, dlen);
507                                         p += sizeof(db_indx_t) + dlen;
508                                 }
509                                 break;
510                         case H_KEYDATA:
511                                 if (i != 0)
512                                         __db_pr(hkd->data,
513                                             LEN_HKEYDATA(h, 0, i));
514                                 else
515                                         fprintf(fp, "%s\n", hkd->data);
516                                 break;
517                         case H_OFFPAGE:
518                                 memcpy(&a_hkd, hkd, HOFFPAGE_SIZE);
519                                 fprintf(fp,
520                                     "overflow: total len: %4lu page: %4lu\n",
521                                     (u_long)a_hkd.tlen, (u_long)a_hkd.pgno);
522                                 break;
523                         }
524                         break;
525                 case P_IBTREE:
526                         fprintf(fp, "count: %4lu pgno: %4lu ",
527                             (u_long)bi->nrecs, (u_long)bi->pgno);
528                         switch (B_TYPE(bi->type)) {
529                         case B_KEYDATA:
530                                 __db_pr(bi->data, bi->len);
531                                 break;
532                         case B_DUPLICATE:
533                         case B_OVERFLOW:
534                                 __db_proff(bi->data);
535                                 break;
536                         default:
537                                 fprintf(fp, "ILLEGAL BINTERNAL TYPE: %lu\n",
538                                     (u_long)B_TYPE(bi->type));
539                                 ret = EINVAL;
540                                 break;
541                         }
542                         break;
543                 case P_IRECNO:
544                         fprintf(fp, "entries %4lu pgno %4lu\n",
545                             (u_long)ri->nrecs, (u_long)ri->pgno);
546                         break;
547                 case P_LBTREE:
548                 case P_LRECNO:
549                 case P_DUPLICATE:
550                         switch (B_TYPE(bk->type)) {
551                         case B_KEYDATA:
552                                 __db_pr(bk->data, bk->len);
553                                 break;
554                         case B_DUPLICATE:
555                         case B_OVERFLOW:
556                                 __db_proff(bk);
557                                 break;
558                         default:
559                                 fprintf(fp,
560                             "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n",
561                                     (u_long)B_TYPE(bk->type));
562                                 ret = EINVAL;
563                                 break;
564                         }
565                         break;
566                 }
567         }
568         (void)fflush(fp);
569         return (ret);
570 }
571
572 /*
573  * __db_isbad
574  *      -- Decide if a page is corrupted.
575  *
576  * PUBLIC: int __db_isbad __P((PAGE *, int));
577  */
578 int
579 __db_isbad(h, die)
580         PAGE *h;
581         int die;
582 {
583         BINTERNAL *bi;
584         BKEYDATA *bk;
585         HKEYDATA *hkd;
586         FILE *fp;
587         db_indx_t i;
588
589         bi = NULL;                              /* XXX: Shut the compiler up. */
590         bk = NULL;
591         hkd = NULL;
592
593         fp = __db_prinit(NULL);
594
595         switch (TYPE(h)) {
596         case P_DUPLICATE:
597         case P_HASH:
598         case P_IBTREE:
599         case P_INVALID:
600         case P_IRECNO:
601         case P_LBTREE:
602         case P_LRECNO:
603         case P_OVERFLOW:
604                 break;
605         default:
606                 fprintf(fp, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n",
607                     (u_long)h->pgno, (u_long)TYPE(h));
608                 goto bad;
609         }
610
611         for (i = 0; i < NUM_ENT(h); i++) {
612                 if (P_ENTRY(h, i) - (u_int8_t *)h < P_OVERHEAD ||
613                     (size_t)(P_ENTRY(h, i) - (u_int8_t *)h) >= set_psize) {
614                         fprintf(fp,
615                             "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n",
616                             (u_long)i, (u_long)h->inp[i]);
617                         goto bad;
618                 }
619                 switch (TYPE(h)) {
620                 case P_HASH:
621                         hkd = GET_HKEYDATA(h, i);
622                         if (hkd->type != H_OFFDUP &&
623                             hkd->type != H_DUPLICATE &&
624                             hkd->type != H_KEYDATA &&
625                             hkd->type != H_OFFPAGE) {
626                                 fprintf(fp, "ILLEGAL HASH TYPE: %lu\n",
627                                     (u_long)hkd->type);
628                                 goto bad;
629                         }
630                         break;
631                 case P_IBTREE:
632                         bi = GET_BINTERNAL(h, i);
633                         if (B_TYPE(bi->type) != B_KEYDATA &&
634                             B_TYPE(bi->type) != B_DUPLICATE &&
635                             B_TYPE(bi->type) != B_OVERFLOW) {
636                                 fprintf(fp, "ILLEGAL BINTERNAL TYPE: %lu\n",
637                                     (u_long)B_TYPE(bi->type));
638                                 goto bad;
639                         }
640                         break;
641                 case P_IRECNO:
642                 case P_LBTREE:
643                 case P_LRECNO:
644                         break;
645                 case P_DUPLICATE:
646                         bk = GET_BKEYDATA(h, i);
647                         if (B_TYPE(bk->type) != B_KEYDATA &&
648                             B_TYPE(bk->type) != B_DUPLICATE &&
649                             B_TYPE(bk->type) != B_OVERFLOW) {
650                                 fprintf(fp,
651                             "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n",
652                                     (u_long)B_TYPE(bk->type));
653                                 goto bad;
654                         }
655                         break;
656                 default:
657                         fprintf(fp,
658                             "ILLEGAL PAGE ITEM: %lu\n", (u_long)TYPE(h));
659                         goto bad;
660                 }
661         }
662         return (0);
663
664 bad:    if (die) {
665                 abort();
666                 /* NOTREACHED */
667         }
668         return (1);
669 }
670
671 /*
672  * __db_pr --
673  *      Print out a data element.
674  *
675  * PUBLIC: void __db_pr __P((u_int8_t *, u_int32_t));
676  */
677 void
678 __db_pr(p, len)
679         u_int8_t *p;
680         u_int32_t len;
681 {
682         FILE *fp;
683         int i, lastch;
684
685         fp = __db_prinit(NULL);
686
687         fprintf(fp, "len: %3lu", (u_long)len);
688         lastch = '.';
689         if (len != 0) {
690                 fprintf(fp, " data: ");
691                 for (i = len <= 20 ? len : 20; i > 0; --i, ++p) {
692                         lastch = *p;
693                         if (isprint(*p) || *p == '\n')
694                                 fprintf(fp, "%c", *p);
695                         else
696                                 fprintf(fp, "%#x", (u_int)*p);
697                 }
698                 if (len > 20) {
699                         fprintf(fp, "...");
700                         lastch = '.';
701                 }
702         }
703         if (lastch != '\n')
704                 fprintf(fp, "\n");
705 }
706
707 /*
708  * __db_proff --
709  *      Print out an off-page element.
710  */
711 static void
712 __db_proff(vp)
713         void *vp;
714 {
715         FILE *fp;
716         BOVERFLOW *bo;
717
718         fp = __db_prinit(NULL);
719
720         bo = vp;
721         switch (B_TYPE(bo->type)) {
722         case B_OVERFLOW:
723                 fprintf(fp, "overflow: total len: %4lu page: %4lu\n",
724                     (u_long)bo->tlen, (u_long)bo->pgno);
725                 break;
726         case B_DUPLICATE:
727                 fprintf(fp, "duplicate: page: %4lu\n", (u_long)bo->pgno);
728                 break;
729         }
730 }
731
732 /*
733  * __db_prflags --
734  *      Print out flags values.
735  *
736  * PUBLIC: void __db_prflags __P((u_int32_t, const FN *));
737  */
738 void
739 __db_prflags(flags, fn)
740         u_int32_t flags;
741         FN const *fn;
742 {
743         FILE *fp;
744         const FN *fnp;
745         int found;
746         const char *sep;
747
748         fp = __db_prinit(NULL);
749
750         sep = " (";
751         for (found = 0, fnp = fn; fnp->mask != 0; ++fnp)
752                 if (fnp->mask & flags) {
753                         fprintf(fp, "%s%s", sep, fnp->name);
754                         sep = ", ";
755                         found = 1;
756                 }
757         if (found)
758                 fprintf(fp, ")");
759 }
760
761 /*
762  * __db_psize --
763  *      Get the page size.
764  */
765 static void
766 __db_psize(mpf)
767         DB_MPOOLFILE *mpf;
768 {
769         BTMETA *mp;
770         db_pgno_t pgno;
771
772         set_psize = PSIZE_BOUNDARY - 1;
773
774         pgno = PGNO_METADATA;
775         if (memp_fget(mpf, &pgno, 0, &mp) != 0)
776                 return;
777
778         switch (mp->magic) {
779         case DB_BTREEMAGIC:
780         case DB_HASHMAGIC:
781                 set_psize = mp->pagesize;
782                 break;
783         }
784         (void)memp_fput(mpf, mp, 0);
785 }