00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 1996, 1997, 1998, 1999, 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifndef lint 00011 static const char revid[] = "$Id: db__pr_8c-source.html,v 1.1 2008年06月08日 10:18:09 sebdiaz Exp $"; 00012 #endif /* not lint */ 00013 00014 #ifndef NO_SYSTEM_INCLUDES 00015 #include <sys/types.h> 00016 00017 #include <ctype.h> 00018 #include <errno.h> 00019 #include <stdlib.h> 00020 #include <string.h> 00021 #include <unistd.h> 00022 #endif 00023 00024 #include "db_int.h" 00025 #include "db_page.h" 00026 #include "btree.h" 00027 #include "hash.h" 00028 #include "qam.h" 00029 #include "db_am.h" 00030 #include "db_verify.h" 00031 00032 static int __db_bmeta __P((DB *, FILE *, BTMETA *, u_int32_t)); 00033 static int __db_hmeta __P((DB *, FILE *, HMETA *, u_int32_t)); 00034 static void __db_meta __P((DB *, DBMETA *, FILE *, FN const *, u_int32_t)); 00035 static const char *__db_dbtype_to_string __P((DB *)); 00036 static void __db_prdb __P((DB *, FILE *, u_int32_t)); 00037 static FILE *__db_prinit __P((FILE *)); 00038 static void __db_proff __P((void *)); 00039 static int __db_prtree __P((DB *, u_int32_t)); 00040 static void __db_psize __P((DB *)); 00041 static int __db_qmeta __P((DB *, FILE *, QMETA *, u_int32_t)); 00042 00043 /* 00044 * 64K is the maximum page size, so by default we check for offsets larger 00045 * than that, and, where possible, we refine the test. 00046 */ 00047 #define PSIZE_BOUNDARY (64 * 1024 + 1) 00048 static size_t set_psize = PSIZE_BOUNDARY; 00049 00050 static FILE *set_fp; /* Output file descriptor. */ 00051 00052 /* 00053 * CDB___db_loadme -- 00054 * A nice place to put a breakpoint. 00055 * 00056 * PUBLIC: void CDB___db_loadme __P((void)); 00057 */ 00058 void 00059 CDB___db_loadme() 00060 { 00061 getpid(); 00062 } 00063 00064 /* 00065 * CDB___db_dump -- 00066 * Dump the tree to a file. 00067 * 00068 * PUBLIC: int CDB___db_dump __P((DB *, char *, char *)); 00069 */ 00070 int 00071 CDB___db_dump(dbp, op, name) 00072 DB *dbp; 00073 char *op, *name; 00074 { 00075 FILE *fp, *save_fp; 00076 u_int32_t flags; 00077 00078 COMPQUIET(save_fp, NULL); 00079 00080 if (set_psize == PSIZE_BOUNDARY) 00081 __db_psize(dbp); 00082 00083 if (name != NULL) { 00084 if ((fp = fopen(name, "w")) == NULL) 00085 return (CDB___os_get_errno()); 00086 save_fp = set_fp; 00087 set_fp = fp; 00088 } else 00089 fp = __db_prinit(NULL); 00090 00091 for (flags = 0; *op != '0円'; ++op) 00092 switch (*op) { 00093 case 'a': 00094 LF_SET(DB_PR_PAGE); 00095 break; 00096 case 'h': 00097 break; 00098 case 'r': 00099 LF_SET(DB_PR_RECOVERYTEST); 00100 break; 00101 default: 00102 return (EINVAL); 00103 } 00104 00105 __db_prdb(dbp, fp, flags); 00106 00107 fprintf(fp, "%s\n", DB_LINE); 00108 00109 (void)__db_prtree(dbp, flags); 00110 00111 fflush(fp); 00112 00113 if (name != NULL) { 00114 fclose(fp); 00115 set_fp = save_fp; 00116 } 00117 return (0); 00118 } 00119 00120 /* 00121 * __db_prdb -- 00122 * Print out the DB structure information. 00123 */ 00124 static void 00125 __db_prdb(dbp, fp, flags) 00126 DB *dbp; 00127 FILE *fp; 00128 u_int32_t flags; 00129 { 00130 static const FN fn[] = { 00131 { DB_AM_DISCARD, "discard cached pages" }, 00132 { DB_AM_DUP, "duplicates" }, 00133 { DB_AM_INMEM, "in-memory" }, 00134 { DB_AM_PGDEF, "default page size" }, 00135 { DB_AM_RDONLY, "read-only" }, 00136 { DB_AM_SUBDB, "multiple-databases" }, 00137 { DB_AM_SWAP, "needswap" }, 00138 { DB_BT_RECNUM, "btree:recnum" }, 00139 { DB_BT_REVSPLIT, "btree:no reverse split" }, 00140 { DB_DBM_ERROR, "dbm/ndbm error" }, 00141 { DB_OPEN_CALLED, "DB->open called" }, 00142 { DB_RE_DELIMITER, "recno:delimiter" }, 00143 { DB_RE_FIXEDLEN, "recno:fixed-length" }, 00144 { DB_RE_PAD, "recno:pad" }, 00145 { DB_RE_RENUMBER, "recno:renumber" }, 00146 { DB_RE_SNAPSHOT, "recno:snapshot" }, 00147 { 0, NULL } 00148 }; 00149 static const FN bfn[] = { 00150 { RECNO_MODIFIED, "recno:modified" }, 00151 { RECNO_READFILE, "recno:readfile" }, 00152 { 0, NULL } 00153 }; 00154 BTREE *bt; 00155 HASH *h; 00156 QUEUE *q; 00157 00158 COMPQUIET(flags, 0); 00159 00160 fprintf(fp, 00161 "In-memory DB structure:\n%s: %#lx", 00162 __db_dbtype_to_string(dbp), (u_long)dbp->flags); 00163 CDB___db_prflags(dbp->flags, fn, fp); 00164 fprintf(fp, "\n"); 00165 00166 switch (dbp->type) { 00167 case DB_BTREE: 00168 case DB_RECNO: 00169 bt = dbp->bt_internal; 00170 fprintf(fp, "bt_lpgno: %lu\n", (u_long)bt->bt_lpgno); 00171 fprintf(fp, "bt_meta: %lu: bt_root: %lu\n", 00172 (u_long)bt->bt_meta, (u_long)bt->bt_root); 00173 fprintf(fp, "bt_maxkey: %lu bt_minkey: %lu\n", 00174 (u_long)bt->bt_maxkey, (u_long)bt->bt_minkey); 00175 fprintf(fp, "bt_compare: %#lx bt_prefix: %#lx\n", 00176 (u_long)bt->bt_compare, (u_long)bt->bt_prefix); 00177 if (dbp->type == DB_RECNO) { 00178 fprintf(fp, 00179 "re_pad: %#lx re_delim: %#lx re_len: %lu re_source: %s\n", 00180 (u_long)bt->re_pad, (u_long)bt->re_delim, 00181 (u_long)bt->re_len, 00182 bt->re_source == NULL ? "" : bt->re_source); 00183 fprintf(fp, "re_last: %lu\n", (u_long)bt->re_last); 00184 fprintf(fp, 00185 "cmap: %#lx smap: %#lx emap: %#lx msize: %lu\n", 00186 (u_long)bt->re_cmap, (u_long)bt->re_smap, 00187 (u_long)bt->re_emap, (u_long)bt->re_msize); 00188 fprintf(fp, "re_irec: %#lx\n", (u_long)bt->re_irec); 00189 } 00190 fprintf(fp, "flags: %#lx", (u_long)bt->flags); 00191 CDB___db_prflags(bt->flags, bfn, fp); 00192 fprintf(fp, "\n"); 00193 break; 00194 case DB_HASH: 00195 h = dbp->h_internal; 00196 fprintf(fp, "meta_pgno: %lu\n", (u_long)h->meta_pgno); 00197 fprintf(fp, "h_ffactor: %lu\n", (u_long)h->h_ffactor); 00198 fprintf(fp, "h_nelem: %lu\n", (u_long)h->h_nelem); 00199 fprintf(fp, "h_hash: %#lx\n", (u_long)h->h_hash); 00200 break; 00201 case DB_QUEUE: 00202 q = dbp->q_internal; 00203 fprintf(fp, "q_meta: %lu\n", (u_long)q->q_meta); 00204 fprintf(fp, "q_root: %lu\n", (u_long)q->q_root); 00205 fprintf(fp, "re_pad: %#lx re_len: %lu\n", 00206 (u_long)q->re_pad, (u_long)q->re_len); 00207 fprintf(fp, "rec_page: %lu\n", (u_long)q->rec_page); 00208 break; 00209 default: 00210 break; 00211 } 00212 } 00213 00214 /* 00215 * __db_prtree -- 00216 * Print out the entire tree. 00217 */ 00218 static int 00219 __db_prtree(dbp, flags) 00220 DB *dbp; 00221 u_int32_t flags; 00222 { 00223 PAGE *h; 00224 db_pgno_t i, last; 00225 int ret; 00226 00227 if (set_psize == PSIZE_BOUNDARY) 00228 __db_psize(dbp); 00229 00230 /* Find out the page number of the last page in the database. */ 00231 if ((ret = CDB_memp_fget(dbp->mpf, &last, DB_MPOOL_LAST, &h)) != 0) 00232 return (ret); 00233 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 00234 return (ret); 00235 00236 /* Dump each page. */ 00237 for (i = 0; i <= last; ++i) { 00238 if ((ret = CDB_memp_fget(dbp->mpf, &i, 0, &h)) != 0) 00239 return (ret); 00240 (void)CDB___db_prpage(dbp, h, flags); 00241 if ((ret = CDB_memp_fput(dbp->mpf, h, 0)) != 0) 00242 return (ret); 00243 } 00244 00245 (void)fflush(__db_prinit(NULL)); 00246 return (0); 00247 } 00248 00249 /* 00250 * __db_meta -- 00251 * Print out common metadata information. 00252 */ 00253 static void 00254 __db_meta(dbp, dbmeta, fp, fn, flags) 00255 DB *dbp; 00256 DBMETA *dbmeta; 00257 FILE *fp; 00258 FN const *fn; 00259 u_int32_t flags; 00260 { 00261 PAGE *h; 00262 int cnt; 00263 db_pgno_t pgno; 00264 u_int8_t *p; 00265 int ret; 00266 const char *sep; 00267 00268 fprintf(fp, "\tmagic: %#lx\n", (u_long)dbmeta->magic); 00269 fprintf(fp, "\tversion: %lu\n", (u_long)dbmeta->version); 00270 fprintf(fp, "\tpagesize: %lu\n", (u_long)dbmeta->pagesize); 00271 fprintf(fp, "\ttype: %lu\n", (u_long)dbmeta->type); 00272 fprintf(fp, "\tkeys: %lu\trecords: %lu\n", 00273 (u_long)dbmeta->key_count, (u_long)dbmeta->record_count); 00274 fprintf(fp, "\talloc_lsn(lsn.file: %lu lsn.offset: %lu)\n", 00275 (u_long)dbmeta->alloc_lsn.file, (u_long)dbmeta->alloc_lsn.offset); 00276 00277 if (!LF_ISSET(DB_PR_RECOVERYTEST)) { 00278 /* 00279 * If we're doing recovery testing, don't display the free 00280 * list, it may have changed and that makes the dump diff 00281 * not work. 00282 */ 00283 fprintf(fp, "\tfree list: %lu", (u_long)dbmeta->free); 00284 for (pgno = dbmeta->free, 00285 cnt = 0, sep = ", "; pgno != PGNO_INVALID;) { 00286 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { 00287 fprintf(fp, 00288 "Unable to retrieve free-list page: %lu: %s\n", 00289 (u_long)pgno, CDB_db_strerror(ret)); 00290 break; 00291 } 00292 pgno = h->next_pgno; 00293 (void)CDB_memp_fput(dbp->mpf, h, 0); 00294 fprintf(fp, "%s%lu", sep, (u_long)pgno); 00295 if (++cnt % 10 == 0) { 00296 fprintf(fp, "\n"); 00297 cnt = 0; 00298 sep = "\t"; 00299 } else 00300 sep = ", "; 00301 } 00302 fprintf(fp, "\n"); 00303 } 00304 00305 if (fn != NULL) { 00306 fprintf(fp, "\tflags: %#lx", (u_long)dbmeta->flags); 00307 CDB___db_prflags(dbmeta->flags, fn, fp); 00308 fprintf(fp, "\n"); 00309 } 00310 00311 fprintf(fp, "\tuid: "); 00312 for (p = (u_int8_t *)dbmeta->uid, 00313 cnt = 0; cnt < DB_FILE_ID_LEN; ++cnt) { 00314 fprintf(fp, "%x", *p++); 00315 if (cnt < DB_FILE_ID_LEN - 1) 00316 fprintf(fp, " "); 00317 } 00318 fprintf(fp, "\n"); 00319 } 00320 00321 /* 00322 * __db_bmeta -- 00323 * Print out the btree meta-data page. 00324 */ 00325 static int 00326 __db_bmeta(dbp, fp, h, flags) 00327 DB *dbp; 00328 FILE *fp; 00329 BTMETA *h; 00330 u_int32_t flags; 00331 { 00332 static const FN mfn[] = { 00333 { BTM_DUP, "duplicates" }, 00334 { BTM_RECNO, "recno" }, 00335 { BTM_RECNUM, "btree:recnum" }, 00336 { BTM_FIXEDLEN, "recno:fixed-length" }, 00337 { BTM_RENUMBER, "recno:renumber" }, 00338 { BTM_SUBDB, "multiple-databases" }, 00339 { 0, NULL } 00340 }; 00341 00342 __db_meta(dbp, (DBMETA *)h, fp, mfn, flags); 00343 00344 fprintf(fp, "\tmaxkey: %lu minkey: %lu\n", 00345 (u_long)h->maxkey, (u_long)h->minkey); 00346 if (dbp->type == DB_RECNO) 00347 fprintf(fp, "\tre_len: %#lx re_pad: %lu\n", 00348 (u_long)h->re_len, (u_long)h->re_pad); 00349 fprintf(fp, "\troot: %lu\n", (u_long)h->root); 00350 00351 return (0); 00352 } 00353 00354 /* 00355 * __db_hmeta -- 00356 * Print out the hash meta-data page. 00357 */ 00358 static int 00359 __db_hmeta(dbp, fp, h, flags) 00360 DB *dbp; 00361 FILE *fp; 00362 HMETA *h; 00363 u_int32_t flags; 00364 { 00365 static const FN mfn[] = { 00366 { DB_HASH_DUP, "duplicates" }, 00367 { DB_HASH_SUBDB, "multiple-databases" }, 00368 { 0, NULL } 00369 }; 00370 int i; 00371 00372 __db_meta(dbp, (DBMETA *)h, fp, mfn, flags); 00373 00374 fprintf(fp, "\tmax_bucket: %lu\n", (u_long)h->max_bucket); 00375 fprintf(fp, "\thigh_mask: %#lx\n", (u_long)h->high_mask); 00376 fprintf(fp, "\tlow_mask: %#lx\n", (u_long)h->low_mask); 00377 fprintf(fp, "\tffactor: %lu\n", (u_long)h->ffactor); 00378 fprintf(fp, "\tnelem: %lu\n", (u_long)h->nelem); 00379 fprintf(fp, "\th_charkey: %#lx\n", (u_long)h->h_charkey); 00380 fprintf(fp, "\tspare points: "); 00381 for (i = 0; i < NCACHED; i++) 00382 fprintf(fp, "%lu ", (u_long)h->spares[i]); 00383 fprintf(fp, "\n"); 00384 00385 return (0); 00386 } 00387 00388 /* 00389 * __db_qmeta -- 00390 * Print out the queue meta-data page. 00391 */ 00392 static int 00393 __db_qmeta(dbp, fp, h, flags) 00394 DB *dbp; 00395 FILE *fp; 00396 QMETA *h; 00397 u_int32_t flags; 00398 { 00399 __db_meta(dbp, (DBMETA *)h, fp, NULL, flags); 00400 00401 fprintf(fp, "\tstart: %lu\n", (u_long)h->start); 00402 fprintf(fp, "\tfirst_recno: %lu\n", (u_long)h->first_recno); 00403 fprintf(fp, "\tcur_recno: %lu\n", (u_long)h->cur_recno); 00404 fprintf(fp, "\tre_len: %#lx re_pad: %lu\n", 00405 (u_long)h->re_len, (u_long)h->re_pad); 00406 fprintf(fp, "\trec_page: %lu\n", (u_long)h->rec_page); 00407 00408 return (0); 00409 } 00410 00411 /* 00412 * CDB___db_prnpage 00413 * -- Print out a specific page. 00414 * 00415 * PUBLIC: int CDB___db_prnpage __P((DB *, db_pgno_t)); 00416 */ 00417 int 00418 CDB___db_prnpage(dbp, pgno) 00419 DB *dbp; 00420 db_pgno_t pgno; 00421 { 00422 PAGE *h; 00423 int ret; 00424 00425 if (set_psize == PSIZE_BOUNDARY) 00426 __db_psize(dbp); 00427 00428 if ((ret = CDB_memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) 00429 return (ret); 00430 00431 ret = CDB___db_prpage(dbp, h, DB_PR_PAGE); 00432 (void)fflush(__db_prinit(NULL)); 00433 00434 (void)CDB_memp_fput(dbp->mpf, h, 0); 00435 return (ret); 00436 } 00437 00438 /* 00439 * CDB___db_prpage 00440 * -- Print out a page. 00441 * 00442 * PUBLIC: int CDB___db_prpage __P((DB *, PAGE *, u_int32_t)); 00443 */ 00444 int 00445 CDB___db_prpage(dbp, h, flags) 00446 DB *dbp; 00447 PAGE *h; 00448 u_int32_t flags; 00449 { 00450 BINTERNAL *bi; 00451 BKEYDATA *bk; 00452 BTREE *t; 00453 FILE *fp; 00454 HOFFPAGE a_hkd; 00455 QAMDATA *qp, *qep; 00456 RINTERNAL *ri; 00457 db_indx_t dlen, len, i; 00458 db_pgno_t pgno; 00459 db_recno_t recno; 00460 int deleted, ret; 00461 const char *s; 00462 u_int32_t qlen; 00463 u_int8_t *ep, *hk, *p; 00464 void *sp; 00465 00466 fp = __db_prinit(NULL); 00467 00468 /* 00469 * If we're doing recovery testing and this page is P_INVALID, 00470 * assume it's a page that's on the free list, and don't display it. 00471 */ 00472 if (LF_ISSET(DB_PR_RECOVERYTEST) && TYPE(h) == P_INVALID) 00473 return (0); 00474 00475 s = CDB___db_pagetype_to_string(TYPE(h)); 00476 if (s == NULL) { 00477 fprintf(fp, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n", 00478 (u_long)h->pgno, (u_long)TYPE(h)); 00479 return (1); 00480 } 00481 00482 /* Page number, page type. */ 00483 fprintf(fp, "page %lu: %s level: %lu", 00484 (u_long)h->pgno, s, (u_long)h->level); 00485 00486 /* Record count. */ 00487 if (TYPE(h) == P_IBTREE || 00488 TYPE(h) == P_IRECNO || (TYPE(h) == P_LRECNO && 00489 h->pgno == ((BTREE *)dbp->bt_internal)->bt_root)) 00490 fprintf(fp, " records: %lu", (u_long)RE_NREC(h)); 00491 00492 /* LSN. */ 00493 fprintf(fp, " (lsn.file: %lu lsn.offset: %lu)\n", 00494 (u_long)LSN(h).file, (u_long)LSN(h).offset); 00495 00496 switch (TYPE(h)) { 00497 case P_BTREEMETA: 00498 return (__db_bmeta(dbp, fp, (BTMETA *)h, flags)); 00499 case P_HASHMETA: 00500 return (__db_hmeta(dbp, fp, (HMETA *)h, flags)); 00501 case P_QAMMETA: 00502 return (__db_qmeta(dbp, fp, (QMETA *)h, flags)); 00503 case P_QAMDATA: /* Should be meta->start. */ 00504 if (!LF_ISSET(DB_PR_PAGE)) 00505 return (0); 00506 00507 qlen = ((QUEUE *)dbp->q_internal)->re_len; 00508 recno = (h->pgno - 1) * QAM_RECNO_PER_PAGE(dbp) + 1; 00509 i = 0; 00510 qep = (QAMDATA *)((u_int8_t *)h + set_psize - qlen); 00511 for (qp = QAM_GET_RECORD(dbp, h, i); qp < qep; 00512 recno++, i++, qp = QAM_GET_RECORD(dbp, h, i)) { 00513 if (!F_ISSET(qp, QAM_SET)) 00514 continue; 00515 00516 fprintf(fp, "%s", 00517 F_ISSET(qp, QAM_VALID) ? "\t" : " D"); 00518 fprintf(fp, "[%03lu] %4lu ", 00519 (u_long)recno, (u_long)qp - (u_long)h); 00520 CDB___db_pr(qp->data, qlen); 00521 } 00522 return (0); 00523 } 00524 00525 t = dbp->bt_internal; 00526 00527 s = "\t"; 00528 if (TYPE(h) != P_IBTREE && TYPE(h) != P_IRECNO) { 00529 fprintf(fp, "%sprev: %4lu next: %4lu", 00530 s, (u_long)PREV_PGNO(h), (u_long)NEXT_PGNO(h)); 00531 s = " "; 00532 } 00533 if (TYPE(h) == P_OVERFLOW) { 00534 fprintf(fp, "%sref cnt: %4lu ", s, (u_long)OV_REF(h)); 00535 CDB___db_pr((u_int8_t *)h + P_OVERHEAD, OV_LEN(h)); 00536 return (0); 00537 } 00538 fprintf(fp, "%sentries: %4lu", s, (u_long)NUM_ENT(h)); 00539 fprintf(fp, " offset: %4lu\n", (u_long)HOFFSET(h)); 00540 00541 if (TYPE(h) == P_INVALID || !LF_ISSET(DB_PR_PAGE)) 00542 return (0); 00543 00544 ret = 0; 00545 for (i = 0; i < NUM_ENT(h); i++) { 00546 if (P_ENTRY(h, i) - (u_int8_t *)h < P_OVERHEAD || 00547 (size_t)(P_ENTRY(h, i) - (u_int8_t *)h) >= set_psize) { 00548 fprintf(fp, 00549 "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n", 00550 (u_long)i, (u_long)h->inp[i]); 00551 ret = EINVAL; 00552 continue; 00553 } 00554 deleted = 0; 00555 switch (TYPE(h)) { 00556 case P_HASH: 00557 case P_IBTREE: 00558 case P_IRECNO: 00559 sp = P_ENTRY(h, i); 00560 break; 00561 case P_LBTREE: 00562 sp = P_ENTRY(h, i); 00563 deleted = i % 2 == 0 && 00564 B_DISSET(GET_BKEYDATA(h, i + O_INDX)->type); 00565 break; 00566 case P_LDUP: 00567 case P_LRECNO: 00568 sp = P_ENTRY(h, i); 00569 deleted = B_DISSET(GET_BKEYDATA(h, i)->type); 00570 break; 00571 default: 00572 fprintf(fp, 00573 "ILLEGAL PAGE ITEM: %lu\n", (u_long)TYPE(h)); 00574 ret = EINVAL; 00575 continue; 00576 } 00577 fprintf(fp, "%s", deleted ? " D" : "\t"); 00578 fprintf(fp, "[%03lu] %4lu ", (u_long)i, (u_long)h->inp[i]); 00579 switch (TYPE(h)) { 00580 case P_HASH: 00581 hk = sp; 00582 switch (HPAGE_PTYPE(hk)) { 00583 case H_OFFDUP: 00584 memcpy(&pgno, 00585 HOFFDUP_PGNO(hk), sizeof(db_pgno_t)); 00586 fprintf(fp, 00587 "%4lu [offpage dups]\n", (u_long)pgno); 00588 break; 00589 case H_DUPLICATE: 00590 /* 00591 * If this is the first item on a page, then 00592 * we cannot figure out how long it is, so 00593 * we only print the first one in the duplicate 00594 * set. 00595 */ 00596 if (i != 0) 00597 len = LEN_HKEYDATA(h, 0, i); 00598 else 00599 len = 1; 00600 00601 fprintf(fp, "Duplicates:\n"); 00602 for (p = HKEYDATA_DATA(hk), 00603 ep = p + len; p < ep;) { 00604 memcpy(&dlen, p, sizeof(db_indx_t)); 00605 p += sizeof(db_indx_t); 00606 fprintf(fp, "\t\t"); 00607 CDB___db_pr(p, dlen); 00608 p += sizeof(db_indx_t) + dlen; 00609 } 00610 break; 00611 case H_KEYDATA: 00612 CDB___db_pr(HKEYDATA_DATA(hk), 00613 LEN_HKEYDATA(h, i == 0 ? set_psize : 0, i)); 00614 break; 00615 case H_OFFPAGE: 00616 memcpy(&a_hkd, hk, HOFFPAGE_SIZE); 00617 fprintf(fp, 00618 "overflow: total len: %4lu page: %4lu\n", 00619 (u_long)a_hkd.tlen, (u_long)a_hkd.pgno); 00620 break; 00621 } 00622 break; 00623 case P_IBTREE: 00624 bi = sp; 00625 fprintf(fp, "count: %4lu pgno: %4lu type: %4lu", 00626 (u_long)bi->nrecs, (u_long)bi->pgno, (u_long)bi->type); 00627 switch (B_TYPE(bi->type)) { 00628 case B_KEYDATA: 00629 CDB___db_pr(bi->data, bi->len); 00630 break; 00631 case B_DUPLICATE: 00632 case B_OVERFLOW: 00633 __db_proff(bi->data); 00634 break; 00635 default: 00636 fprintf(fp, "ILLEGAL BINTERNAL TYPE: %lu\n", 00637 (u_long)B_TYPE(bi->type)); 00638 ret = EINVAL; 00639 break; 00640 } 00641 break; 00642 case P_IRECNO: 00643 ri = sp; 00644 fprintf(fp, "entries %4lu pgno %4lu\n", 00645 (u_long)ri->nrecs, (u_long)ri->pgno); 00646 break; 00647 case P_LBTREE: 00648 case P_LDUP: 00649 case P_LRECNO: 00650 bk = sp; 00651 switch (B_TYPE(bk->type)) { 00652 case B_KEYDATA: 00653 CDB___db_pr(bk->data, bk->len); 00654 break; 00655 case B_DUPLICATE: 00656 case B_OVERFLOW: 00657 __db_proff(bk); 00658 break; 00659 default: 00660 fprintf(fp, 00661 "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n", 00662 (u_long)B_TYPE(bk->type)); 00663 ret = EINVAL; 00664 break; 00665 } 00666 break; 00667 } 00668 } 00669 (void)fflush(fp); 00670 return (ret); 00671 } 00672 00673 /* 00674 * CDB___db_pr -- 00675 * Print out a data element. 00676 * 00677 * PUBLIC: void CDB___db_pr __P((u_int8_t *, u_int32_t)); 00678 */ 00679 void 00680 CDB___db_pr(p, len) 00681 u_int8_t *p; 00682 u_int32_t len; 00683 { 00684 FILE *fp; 00685 u_int lastch; 00686 int i; 00687 00688 fp = __db_prinit(NULL); 00689 00690 fprintf(fp, "len: %3lu", (u_long)len); 00691 lastch = '.'; 00692 if (len != 0) { 00693 fprintf(fp, " data: "); 00694 for (i = len <= 20 ? len : 20; i > 0; --i, ++p) { 00695 lastch = *p; 00696 if (isprint(*p) || *p == '\n') 00697 fprintf(fp, "%c", *p); 00698 else 00699 fprintf(fp, "0x%.2x", (u_int)*p); 00700 } 00701 if (len > 20) { 00702 fprintf(fp, "..."); 00703 lastch = '.'; 00704 } 00705 } 00706 if (lastch != '\n') 00707 fprintf(fp, "\n"); 00708 } 00709 00710 /* 00711 * CDB___db_prdbt -- 00712 * Print out a DBT data element. 00713 * 00714 * PUBLIC: int CDB___db_prdbt __P((DBT *, int, const char *, void *, 00715 * PUBLIC: int (*)(void *, const void *), int, VRFY_DBINFO *)); 00716 */ 00717 int 00718 CDB___db_prdbt(dbtp, checkprint, prefix, handle, callback, is_recno, vdp) 00719 DBT *dbtp; 00720 int checkprint; 00721 const char *prefix; 00722 void *handle; 00723 int (*callback) __P((void *, const void *)); 00724 int is_recno; 00725 VRFY_DBINFO *vdp; 00726 { 00727 static const char hex[] = "0123456789abcdef"; 00728 #define DBTBUFLEN 100 00729 char buf[DBTBUFLEN]; 00730 db_recno_t recno; 00731 int ret; 00732 u_int32_t len; 00733 u_int8_t *p; 00734 00735 if (vdp != NULL) { 00736 /* 00737 * If vdp is non-NULL, we might be the first key in the 00738 * "fake" subdatabase used for key/data pairs we can't 00739 * associate with a known subdb. 00740 * 00741 * Check and clear the SALVAGE_PRINTHEADER flag; if 00742 * it was set, print a subdatabase header. 00743 */ 00744 if (F_ISSET(vdp, SALVAGE_PRINTHEADER)) 00745 (void)CDB___db_prheader(NULL, "__OTHER__", 0, 0, 00746 handle, callback, vdp, 0); 00747 F_CLR(vdp, SALVAGE_PRINTHEADER); 00748 F_SET(vdp, SALVAGE_PRINTFOOTER); 00749 } 00750 00751 /* 00752 * !!! 00753 * This routine is the routine that dumps out items in the format 00754 * used by db_dump(1) and db_load(1). This means that the format 00755 * cannot change. 00756 */ 00757 if (prefix != NULL && (ret = callback(handle, prefix)) != 0) 00758 return (ret); 00759 if (is_recno) { 00760 /* 00761 * We're printing a record number, and this has to be done 00762 * in a platform-independent way. So we use the numeral in 00763 * straight ASCII. 00764 */ 00765 CDB___ua_memcpy(&recno, dbtp->data, sizeof(recno)); 00766 snprintf(buf, DBTBUFLEN, "%lu", (u_long)recno); 00767 if ((ret = callback(handle, buf)) != 0) 00768 return (ret); 00769 } else if (checkprint) { 00770 for (len = dbtp->size, p = dbtp->data; len--; ++p) 00771 if (isprint(*p)) { 00772 if (*p == '\\' && 00773 (ret = callback(handle, "\\")) != 0) 00774 return (ret); 00775 snprintf(buf, DBTBUFLEN, "%c", *p); 00776 if ((ret = callback(handle, buf)) != 0) 00777 return (ret); 00778 } else { 00779 snprintf(buf, DBTBUFLEN, "\\%c%c", 00780 hex[(u_int8_t)(*p & 0xf0) >> 4], 00781 hex[*p & 0x0f]); 00782 if ((ret = callback(handle, buf)) != 0) 00783 return (ret); 00784 } 00785 } else 00786 for (len = dbtp->size, p = dbtp->data; len--; ++p) { 00787 snprintf(buf, DBTBUFLEN, "%c%c", 00788 hex[(u_int8_t)(*p & 0xf0) >> 4], 00789 hex[*p & 0x0f]); 00790 if ((ret = callback(handle, buf)) != 0) 00791 return (ret); 00792 } 00793 00794 return (callback(handle, "\n")); 00795 } 00796 00797 /* 00798 * __db_proff -- 00799 * Print out an off-page element. 00800 */ 00801 static void 00802 __db_proff(vp) 00803 void *vp; 00804 { 00805 FILE *fp; 00806 BOVERFLOW *bo; 00807 00808 fp = __db_prinit(NULL); 00809 00810 bo = vp; 00811 switch (B_TYPE(bo->type)) { 00812 case B_OVERFLOW: 00813 fprintf(fp, "overflow: total len: %4lu page: %4lu\n", 00814 (u_long)bo->tlen, (u_long)bo->pgno); 00815 break; 00816 case B_DUPLICATE: 00817 fprintf(fp, "duplicate: page: %4lu\n", (u_long)bo->pgno); 00818 break; 00819 } 00820 } 00821 00822 /* 00823 * CDB___db_prflags -- 00824 * Print out flags values. 00825 * 00826 * PUBLIC: void CDB___db_prflags __P((u_int32_t, const FN *, FILE *)); 00827 */ 00828 void 00829 CDB___db_prflags(flags, fn, fp) 00830 u_int32_t flags; 00831 FN const *fn; 00832 FILE *fp; 00833 { 00834 const FN *fnp; 00835 int found; 00836 const char *sep; 00837 00838 sep = " ("; 00839 for (found = 0, fnp = fn; fnp->mask != 0; ++fnp) 00840 if (LF_ISSET(fnp->mask)) { 00841 fprintf(fp, "%s%s", sep, fnp->name); 00842 sep = ", "; 00843 found = 1; 00844 } 00845 if (found) 00846 fprintf(fp, ")"); 00847 } 00848 00849 /* 00850 * __db_prinit -- 00851 * Initialize tree printing routines. 00852 */ 00853 static FILE * 00854 __db_prinit(fp) 00855 FILE *fp; 00856 { 00857 if (set_fp == NULL) 00858 set_fp = fp == NULL ? stdout : fp; 00859 return (set_fp); 00860 } 00861 00862 /* 00863 * __db_psize -- 00864 * Get the page size. 00865 */ 00866 static void 00867 __db_psize(dbp) 00868 DB *dbp; 00869 { 00870 DBMETA *mp; 00871 db_pgno_t pgno; 00872 00873 set_psize = PSIZE_BOUNDARY - 1; 00874 00875 pgno = PGNO_BASE_MD; 00876 if (CDB_memp_fget(dbp->mpf, &pgno, 0, &mp) != 0) 00877 return; 00878 00879 switch (mp->magic) { 00880 case DB_BTREEMAGIC: 00881 case DB_HASHMAGIC: 00882 case DB_QAMMAGIC: 00883 set_psize = mp->pagesize; 00884 break; 00885 } 00886 (void)CDB_memp_fput(dbp->mpf, mp, 0); 00887 } 00888 00889 /* 00890 * __db_dbtype_to_string -- 00891 * Return the name of the database type. 00892 */ 00893 static const char * 00894 __db_dbtype_to_string(dbp) 00895 DB *dbp; 00896 { 00897 switch (dbp->type) { 00898 case DB_BTREE: 00899 return ("btree"); 00900 case DB_HASH: 00901 return ("hash"); 00902 break; 00903 case DB_RECNO: 00904 return ("recno"); 00905 break; 00906 case DB_QUEUE: 00907 return ("queue"); 00908 default: 00909 return ("UNKNOWN TYPE"); 00910 } 00911 /* NOTREACHED */ 00912 } 00913 00914 /* 00915 * CDB___db_pagetype_to_string -- 00916 * Return the name of the specified page type. 00917 * 00918 * PUBLIC: const char *CDB___db_pagetype_to_string __P((u_int32_t)); 00919 */ 00920 const char * 00921 CDB___db_pagetype_to_string(type) 00922 u_int32_t type; 00923 { 00924 char *s; 00925 00926 s = NULL; 00927 switch (type) { 00928 case P_BTREEMETA: 00929 s = "btree metadata"; 00930 break; 00931 case P_LDUP: 00932 s = "duplicate"; 00933 break; 00934 case P_HASH: 00935 s = "hash"; 00936 break; 00937 case P_HASHMETA: 00938 s = "hash metadata"; 00939 break; 00940 case P_IBTREE: 00941 s = "btree internal"; 00942 break; 00943 case P_INVALID: 00944 s = "invalid"; 00945 break; 00946 case P_IRECNO: 00947 s = "recno internal"; 00948 break; 00949 case P_LBTREE: 00950 s = "btree leaf"; 00951 break; 00952 case P_LRECNO: 00953 s = "recno leaf"; 00954 break; 00955 case P_OVERFLOW: 00956 s = "overflow"; 00957 break; 00958 case P_QAMMETA: 00959 s = "queue metadata"; 00960 break; 00961 case P_QAMDATA: 00962 s = "queue"; 00963 break; 00964 default: 00965 /* Just return a NULL. */ 00966 break; 00967 } 00968 return (s); 00969 } 00970 00971 /* 00972 * CDB___db_prheader -- 00973 * Write out header information in the format expected by db_load. 00974 * 00975 * PUBLIC: int CDB___db_prheader __P((DB *, char *, int, int, void *, 00976 * PUBLIC: int (*)(void *, const void *), VRFY_DBINFO *, db_pgno_t)); 00977 */ 00978 int 00979 CDB___db_prheader(dbp, subname, pflag, keyflag, handle, callback, vdp, meta_pgno) 00980 DB *dbp; 00981 char *subname; 00982 int pflag, keyflag; 00983 void *handle; 00984 int (*callback) __P((void *, const void *)); 00985 VRFY_DBINFO *vdp; 00986 db_pgno_t meta_pgno; 00987 { 00988 DB_BTREE_STAT *btsp; 00989 DB_ENV *dbenv; 00990 DB_HASH_STAT *hsp; 00991 DB_QUEUE_STAT *qsp; 00992 VRFY_PAGEINFO *pip; 00993 char *buf; 00994 int ret, t_ret, buflen; 00995 u_int32_t dbtype; 00996 00997 btsp = NULL; 00998 hsp = NULL; 00999 qsp = NULL; 01000 ret = 0; 01001 buf = NULL; 01002 COMPQUIET(buflen, 0); 01003 01004 if (dbp == NULL) 01005 dbenv = NULL; 01006 else 01007 dbenv = dbp->dbenv; 01008 01009 /* 01010 * If we've been passed a verifier statistics object, use 01011 * that; we're being called in a context where dbp->stat 01012 * is unsafe. 01013 */ 01014 if (vdp != NULL) { 01015 if ((ret = CDB___db_vrfy_getpageinfo(vdp, meta_pgno, &pip)) != 0) 01016 return (ret); 01017 } else 01018 pip = NULL; 01019 01020 /* 01021 * If dbp is NULL, we're being called from inside CDB___db_prdbt, 01022 * and this is a special subdatabase for "lost" items. Make it a btree. 01023 * Otherwise, set dbtype to the appropriate type for the specified 01024 * meta page, or the type of the dbp. 01025 */ 01026 if (dbp == NULL) 01027 dbtype = DB_BTREE; 01028 else if (pip != NULL) 01029 switch (pip->type) { 01030 case P_BTREEMETA: 01031 if (F_ISSET(pip, VRFY_IS_RECNO)) 01032 dbtype = DB_RECNO; 01033 else 01034 dbtype = DB_BTREE; 01035 break; 01036 case P_HASHMETA: 01037 dbtype = DB_HASH; 01038 break; 01039 default: 01040 /* Shouldn't happen. */ 01041 DB_ASSERT(0); 01042 ret = EINVAL; 01043 goto err; 01044 } 01045 else 01046 dbtype = dbp->type; 01047 01048 if ((ret = callback(handle, "VERSION=2\n")) != 0) 01049 goto err; 01050 if (pflag) { 01051 if ((ret = callback(handle, "format=print\n")) != 0) 01052 goto err; 01053 } else if ((ret = callback(handle, "format=bytevalue\n")) != 0) 01054 goto err; 01055 01056 /* 01057 * 64 bytes is long enough, as a minimum bound, for any of the 01058 * fields besides subname. Subname can be anything, and so 01059 * 64 + subname is big enough for all the things we need to print here. 01060 */ 01061 buflen = 64 + ((subname != NULL) ? strlen(subname) : 0); 01062 if ((ret = CDB___os_malloc(dbenv, buflen, NULL, &buf)) != 0) 01063 goto err; 01064 if (subname != NULL) { 01065 snprintf(buf, buflen, "database=%s\n", subname); 01066 if ((ret = callback(handle, buf)) != 0) 01067 goto err; 01068 } 01069 switch (dbtype) { 01070 case DB_BTREE: 01071 if ((ret = callback(handle, "type=btree\n")) != 0) 01072 goto err; 01073 if (pip != NULL) { 01074 if (F_ISSET(pip, VRFY_HAS_RECNUMS)) 01075 if ((ret = 01076 callback(handle, "recnum=1\n")) != 0) 01077 goto err; 01078 if (pip->bt_maxkey != 0) { 01079 snprintf(buf, buflen, "bt_maxkey=%lu\n", 01080 (u_long)pip->bt_maxkey); 01081 if ((ret = callback(handle, buf)) != 0) 01082 goto err; 01083 } 01084 if (pip->bt_minkey != 0 && 01085 pip->bt_minkey != DEFMINKEYPAGE) { 01086 snprintf(buf, buflen, "bt_minkey=%lu\n", 01087 (u_long)pip->bt_minkey); 01088 if ((ret = callback(handle, buf)) != 0) 01089 goto err; 01090 } 01091 break; 01092 } 01093 if ((ret = dbp->stat(dbp, &btsp, NULL, 0)) != 0) { 01094 dbp->err(dbp, ret, "DB->stat"); 01095 goto err; 01096 } 01097 if (F_ISSET(dbp, DB_BT_RECNUM)) 01098 if ((ret = callback(handle, "recnum=1\n")) != 0) 01099 goto err; 01100 if (btsp->bt_maxkey != 0) { 01101 snprintf(buf, buflen, 01102 "bt_maxkey=%lu\n", (u_long)btsp->bt_maxkey); 01103 if ((ret = callback(handle, buf)) != 0) 01104 goto err; 01105 } 01106 if (btsp->bt_minkey != 0 && btsp->bt_minkey != DEFMINKEYPAGE) { 01107 snprintf(buf, buflen, 01108 "bt_minkey=%lu\n", (u_long)btsp->bt_minkey); 01109 if ((ret = callback(handle, buf)) != 0) 01110 goto err; 01111 } 01112 break; 01113 case DB_HASH: 01114 if ((ret = callback(handle, "type=hash\n")) != 0) 01115 goto err; 01116 if (pip != NULL) { 01117 if (pip->h_ffactor != 0) { 01118 snprintf(buf, buflen, "h_ffactor=%lu\n", 01119 (u_long)pip->h_ffactor); 01120 if ((ret = callback(handle, buf)) != 0) 01121 goto err; 01122 } 01123 if (pip->h_nelem != 0) { 01124 snprintf(buf, buflen, "h_nelem=%lu\n", 01125 (u_long)pip->h_nelem); 01126 if ((ret = callback(handle, buf)) != 0) 01127 goto err; 01128 } 01129 break; 01130 } 01131 if ((ret = dbp->stat(dbp, &hsp, NULL, 0)) != 0) { 01132 dbp->err(dbp, ret, "DB->stat"); 01133 goto err; 01134 } 01135 if (hsp->hash_ffactor != 0) { 01136 snprintf(buf, buflen, 01137 "h_ffactor=%lu\n", (u_long)hsp->hash_ffactor); 01138 if ((ret = callback(handle, buf)) != 0) 01139 goto err; 01140 } 01141 if (hsp->hash_nelem != 0 || hsp->hash_nkeys != 0) { 01142 snprintf(buf, buflen, "h_nelem=%lu\n", 01143 hsp->hash_nelem > hsp->hash_nkeys ? 01144 (u_long)hsp->hash_nelem : (u_long)hsp->hash_nkeys); 01145 if ((ret = callback(handle, buf)) != 0) 01146 goto err; 01147 } 01148 break; 01149 case DB_QUEUE: 01150 if ((ret = callback(handle, "type=queue\n")) != 0) 01151 goto err; 01152 if (vdp != NULL) { 01153 snprintf(buf, 01154 buflen, "re_len=%lu\n", (u_long)vdp->re_len); 01155 if ((ret = callback(handle, buf)) != 0) 01156 goto err; 01157 break; 01158 } 01159 if ((ret = dbp->stat(dbp, &qsp, NULL, 0)) != 0) { 01160 dbp->err(dbp, ret, "DB->stat"); 01161 goto err; 01162 } 01163 snprintf(buf, buflen, "re_len=%lu\n", (u_long)qsp->qs_re_len); 01164 if (qsp->qs_re_pad != 0 && qsp->qs_re_pad != ' ') 01165 snprintf(buf, buflen, "re_pad=%#x\n", qsp->qs_re_pad); 01166 if ((ret = callback(handle, buf)) != 0) 01167 goto err; 01168 break; 01169 case DB_RECNO: 01170 if ((ret = callback(handle, "type=recno\n")) != 0) 01171 goto err; 01172 if (pip != NULL) { 01173 if (F_ISSET(pip, VRFY_IS_RRECNO)) 01174 if ((ret = 01175 callback(handle, "renumber=1\n")) != 0) 01176 goto err; 01177 if (pip->re_len > 0) { 01178 snprintf(buf, buflen, "re_len=%lu\n", 01179 (u_long)pip->re_len); 01180 if ((ret = callback(handle, buf)) != 0) 01181 goto err; 01182 } 01183 break; 01184 } 01185 if ((ret = dbp->stat(dbp, &btsp, NULL, 0)) != 0) { 01186 dbp->err(dbp, ret, "DB->stat"); 01187 goto err; 01188 } 01189 if (F_ISSET(dbp, DB_RE_RENUMBER)) 01190 if ((ret = callback(handle, "renumber=1\n")) != 0) 01191 goto err; 01192 if (F_ISSET(dbp, DB_RE_FIXEDLEN)) { 01193 snprintf(buf, buflen, 01194 "re_len=%lu\n", (u_long)btsp->bt_re_len); 01195 if ((ret = callback(handle, buf)) != 0) 01196 goto err; 01197 } 01198 if (btsp->bt_re_pad != 0 && btsp->bt_re_pad != ' ') { 01199 snprintf(buf, buflen, "re_pad=%#x\n", btsp->bt_re_pad); 01200 if ((ret = callback(handle, buf)) != 0) 01201 goto err; 01202 } 01203 break; 01204 case DB_UNKNOWN: 01205 DB_ASSERT(0); /* Impossible. */ 01206 CDB___db_err(dbp->dbenv, "Impossible DB type in CDB___db_prheader"); 01207 ret = EINVAL; 01208 goto err; 01209 } 01210 01211 if (pip != NULL) { 01212 if (F_ISSET(pip, VRFY_HAS_DUPS)) 01213 if ((ret = callback(handle, "duplicates=1\n")) != 0) 01214 goto err; 01215 if (F_ISSET(pip, VRFY_HAS_DUPSORT)) 01216 if ((ret = callback(handle, "dupsort=1\n")) != 0) 01217 goto err; 01218 /* We should handle page size. XXX */ 01219 } else { 01220 if (F_ISSET(dbp, DB_AM_DUP)) 01221 if ((ret = callback(handle, "duplicates=1\n")) != 0) 01222 goto err; 01223 if (F_ISSET(dbp, DB_AM_DUPSORT)) 01224 if ((ret = callback(handle, "dupsort=1\n")) != 0) 01225 goto err; 01226 if (!F_ISSET(dbp, DB_AM_PGDEF)) { 01227 snprintf(buf, buflen, "db_pagesize=%lu\n", 01228 (u_long)dbp->pgsize); 01229 if ((ret = callback(handle, buf)) != 0) 01230 goto err; 01231 } 01232 } 01233 01234 if (keyflag) 01235 if ((ret = callback(handle, "keys=1\n")) != 0) 01236 goto err; 01237 01238 ret = callback(handle, "HEADER=END\n"); 01239 01240 err: if (pip != NULL && 01241 (t_ret = CDB___db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0) 01242 ret = t_ret; 01243 if (btsp != NULL) 01244 CDB___os_free(btsp, 0); 01245 if (hsp != NULL) 01246 CDB___os_free(hsp, 0); 01247 if (qsp != NULL) 01248 CDB___os_free(qsp, 0); 01249 if (buf != NULL) 01250 CDB___os_free(buf, buflen); 01251 01252 return (ret); 01253 } 01254 01255 /* 01256 * CDB___db_prfooter -- 01257 * Print the footer that marks the end of a DB dump. This is trivial, 01258 * but for consistency's sake we don't want to put its literal contents 01259 * in multiple places. 01260 * 01261 * PUBLIC: int CDB___db_prfooter __P((void *, int (*)(void *, const void *))); 01262 */ 01263 int 01264 CDB___db_prfooter(handle, callback) 01265 void *handle; 01266 int (*callback) __P((void *, const void *)); 01267 { 01268 return (callback(handle, "DATA=END\n")); 01269 }