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
__db_loadme()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 *
__db_prinit(fp)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
__db_dump(dbp,name,all)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
__db_prdb(dbp)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
__db_prbtree(dbp)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
__db_prhash(dbp)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
__db_prtree(mpf,all)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
__db_prnpage(mpf,pgno)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
__db_prpage(h,all)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
__db_isbad(h,die)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
__db_pr(p,len)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
__db_prdbt(dbtp,checkprint,fp)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
__db_proff(vp)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
__db_prflags(flags,fn,fp)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
__db_psize(mpf)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